/** * aicwf_usb.c * * USB function declarations * * Copyright (C) AICSemi 2018-2020 */ #include #include #include #include "aicwf_txrxif.h" #include "aicwf_usb.h" #include "rwnx_tx.h" #include "rwnx_defs.h" #include "usb_host.h" #include "rwnx_platform.h" #include "rwnx_msg_tx.h" #ifdef CONFIG_GPIO_WAKEUP #ifdef CONFIG_PLATFORM_ROCKCHIP #include #endif static int wakeup_enable; static u32 hostwake_irq_num; atomic_t irq_count; spinlock_t irq_lock; #endif #include extern struct semaphore aicwf_deinit_sem; extern atomic_t aicwf_deinit_atomic; #define SEM_TIMOUT 2000 #ifdef CONFIG_TXRX_THREAD_PRIO #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0)) #include "uapi/linux/sched/types.h" #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)) #include "linux/sched/types.h" #else #include "linux/sched/rt.h" #endif int bustx_thread_prio = 1; module_param(bustx_thread_prio, int, 0); int busrx_thread_prio = 1; module_param(busrx_thread_prio, int, 0); #endif #ifdef CONFIG_USB_RX_AGGR bool aicwf_usb_rx_aggr = true; #else bool aicwf_usb_rx_aggr = false; #endif atomic_t rx_urb_cnt; bool rx_urb_sched = false; u32 aicwf_usb_max_pkt_size = AICWF_USB_MAX_PKT_SIZE; void aicwf_usb_tx_flowctrl(struct rwnx_hw *rwnx_hw, bool state) { struct rwnx_vif *rwnx_vif; list_for_each_entry(rwnx_vif, &rwnx_hw->vifs, list) { if (!rwnx_vif || !rwnx_vif->ndev || !rwnx_vif->up) continue; if (state) netif_tx_stop_all_queues(rwnx_vif->ndev);//netif_stop_queue(rwnx_vif->ndev); else netif_tx_wake_all_queues(rwnx_vif->ndev);//netif_wake_queue(rwnx_vif->ndev); } } static struct aicwf_usb_buf *aicwf_usb_tx_dequeue(struct aic_usb_dev *usb_dev, struct list_head *q, int *counter, spinlock_t *qlock) { unsigned long flags; struct aicwf_usb_buf *usb_buf; spin_lock_irqsave(qlock, flags); if (list_empty(q)) { usb_buf = NULL; } else { usb_buf = list_first_entry(q, struct aicwf_usb_buf, list); list_del_init(&usb_buf->list); if (counter) (*counter)--; } spin_unlock_irqrestore(qlock, flags); return usb_buf; } static void aicwf_usb_tx_queue(struct aic_usb_dev *usb_dev, struct list_head *q, struct aicwf_usb_buf *usb_buf, int *counter, spinlock_t *qlock) { unsigned long flags; spin_lock_irqsave(qlock, flags); list_add_tail(&usb_buf->list, q); (*counter)++; spin_unlock_irqrestore(qlock, flags); } static struct aicwf_usb_buf *aicwf_usb_rx_buf_get(struct aic_usb_dev *usb_dev) { unsigned long flags; struct aicwf_usb_buf *usb_buf; spin_lock_irqsave(&usb_dev->rx_free_lock, flags); if (list_empty(&usb_dev->rx_free_list)) { usb_buf = NULL; } else { usb_buf = list_first_entry(&usb_dev->rx_free_list, struct aicwf_usb_buf, list); list_del_init(&usb_buf->list); } spin_unlock_irqrestore(&usb_dev->rx_free_lock, flags); return usb_buf; } static void aicwf_usb_rx_buf_put(struct aic_usb_dev *usb_dev, struct aicwf_usb_buf *usb_buf) { unsigned long flags; spin_lock_irqsave(&usb_dev->rx_free_lock, flags); list_add_tail(&usb_buf->list, &usb_dev->rx_free_list); spin_unlock_irqrestore(&usb_dev->rx_free_lock, flags); } #ifdef CONFIG_USB_MSG_IN_EP static struct aicwf_usb_buf *aicwf_usb_msg_rx_buf_get(struct aic_usb_dev *usb_dev) { unsigned long flags; struct aicwf_usb_buf *usb_buf; spin_lock_irqsave(&usb_dev->msg_rx_free_lock, flags); if (list_empty(&usb_dev->msg_rx_free_list)) { usb_buf = NULL; } else { usb_buf = list_first_entry(&usb_dev->msg_rx_free_list, struct aicwf_usb_buf, list); list_del_init(&usb_buf->list); } spin_unlock_irqrestore(&usb_dev->msg_rx_free_lock, flags); return usb_buf; } static void aicwf_usb_msg_rx_buf_put(struct aic_usb_dev *usb_dev, struct aicwf_usb_buf *usb_buf) { unsigned long flags; spin_lock_irqsave(&usb_dev->msg_rx_free_lock, flags); list_add_tail(&usb_buf->list, &usb_dev->msg_rx_free_list); spin_unlock_irqrestore(&usb_dev->msg_rx_free_lock, flags); } #endif void rwnx_stop_sta_all_queues(void *sta, struct rwnx_hw *rwnx_hw) { u8 tid; struct rwnx_txq *txq; struct rwnx_sta *sta_tmp = (struct rwnx_sta *)sta; for(tid=0; tid<8; tid++) { txq = rwnx_txq_sta_get(sta_tmp, tid, rwnx_hw); netif_stop_subqueue(txq->ndev, txq->ndev_idx); } } void rwnx_wake_sta_all_queues(void *sta, struct rwnx_hw *rwnx_hw) { u8 tid; struct rwnx_txq *txq; struct rwnx_sta *sta_tmp = (struct rwnx_sta *)sta; for(tid=0; tid<8; tid++) { txq = rwnx_txq_sta_get(sta_tmp, tid, rwnx_hw); netif_wake_subqueue(txq->ndev, txq->ndev_idx); } } static void usb_txc_sta_flowctrl(struct aicwf_usb_buf *usb_buf, struct aic_usb_dev *usb_dev) { #ifdef CONFIG_PER_STA_FC unsigned long flags; struct rwnx_sta *sta; struct txdesc_api *hostdesc; u8 sta_idx; if(usb_buf->cfm) hostdesc = (struct txdesc_api *)((u8 *)usb_buf->skb + 4); else hostdesc = (struct txdesc_api *)((u8 *)usb_buf->skb->data + 4); //printk("txcpl: sta %d\n", hostdesc->host.staid); sta_idx = hostdesc->host.staid; if(sta_idx < NX_REMOTE_STA_MAX && !(hostdesc->host.flags & TXU_CNTRL_MGMT)) { struct rwnx_vif *vif = NULL; sta = &usb_dev->rwnx_hw->sta_table[sta_idx]; vif = usb_dev->rwnx_hw->vif_table[sta->vif_idx]; spin_lock_irqsave(&usb_dev->tx_flow_lock, flags); atomic_dec(&usb_dev->rwnx_hw->sta_flowctrl[sta_idx].tx_pending_cnt); //printk("sta:%d, pending:%d, flowctrl=%d\n", sta->sta_idx, sta->tx_pending_cnt, sta->flowctrl); if(RWNX_VIF_TYPE(vif) == NL80211_IFTYPE_AP) { if(atomic_read(&usb_dev->rwnx_hw->sta_flowctrl[sta_idx].tx_pending_cnt) < AICWF_USB_FC_PERSTA_LOW_WATER && usb_dev->rwnx_hw->sta_flowctrl[sta_idx].flowctrl) { //AICWFDBG(LOGDEBUG, "sta 0x%x:0x%x, %d pending %d, wake\n", sta->mac_addr[4], sta->mac_addr[5], sta->sta_idx, atomic_read(&usb_dev->rwnx_hw->sta_flowctrl[sta_idx].tx_pending_cnt)); if(!usb_dev->tbusy) rwnx_wake_sta_all_queues((void *)sta, usb_dev->rwnx_hw); usb_dev->rwnx_hw->sta_flowctrl[sta_idx].flowctrl = 0; } } spin_unlock_irqrestore(&usb_dev->tx_flow_lock, flags); } #endif } static void aicwf_usb_tx_complete(struct urb *urb) { unsigned long flags; struct aicwf_usb_buf *usb_buf = (struct aicwf_usb_buf *) urb->context; struct aic_usb_dev *usb_dev = usb_buf->usbdev; #ifndef CONFIG_USB_TX_AGGR struct sk_buff *skb; #endif usb_txc_sta_flowctrl(usb_buf, usb_dev); #ifdef CONFIG_USB_ALIGN_DATA if(usb_buf->usb_align_data) { kfree(usb_buf->usb_align_data); usb_buf->usb_align_data = NULL; } #endif #ifndef CONFIG_USB_TX_AGGR if (usb_buf->cfm == false) { skb = usb_buf->skb; dev_kfree_skb_any(skb); } #if !defined CONFIG_USB_NO_TRANS_DMA_MAP else { u8 *buf; buf = (u8 *)usb_buf->skb; kfree(buf); } #endif usb_buf->skb = NULL; #else AICWFDBG(LOGDEBUG,"tx com %d\n", usb_buf->aggr_cnt); usb_buf->aggr_cnt = 0; #endif//CONFIG_USB_TX_AGGR aicwf_usb_tx_queue(usb_dev, &usb_dev->tx_free_list, usb_buf, &usb_dev->tx_free_count, &usb_dev->tx_free_lock); spin_lock_irqsave(&usb_dev->tx_flow_lock, flags); if (usb_dev->tx_free_count > AICWF_USB_TX_HIGH_WATER) { if (usb_dev->tbusy) { usb_dev->tbusy = false; aicwf_usb_tx_flowctrl(usb_dev->rwnx_hw, false); } } spin_unlock_irqrestore(&usb_dev->tx_flow_lock, flags); } void aicwf_usb_rx_submit_all_urb_(struct aic_usb_dev *usb_dev); #ifdef CONFIG_PREALLOC_RX_SKB static void aicwf_usb_rx_complete(struct urb *urb) { struct aicwf_usb_buf *usb_buf = (struct aicwf_usb_buf *) urb->context; struct aic_usb_dev *usb_dev = usb_buf->usbdev; struct aicwf_rx_priv* rx_priv = usb_dev->rx_priv; struct rx_buff *rx_buff = NULL; unsigned long flags = 0; rx_buff = usb_buf->rx_buff; usb_buf->rx_buff = NULL; atomic_dec(&rx_urb_cnt); if(atomic_read(&rx_urb_cnt) < 10){ AICWFDBG(LOGDEBUG, "%s %d \r\n", __func__, atomic_read(&rx_urb_cnt)); //printk("%s %d \r\n", __func__, atomic_read(&rx_urb_cnt)); } if(!usb_dev->rwnx_hw){ aicwf_prealloc_rxbuff_free(rx_buff, &rx_priv->rxbuff_lock); aicwf_usb_rx_buf_put(usb_dev, usb_buf); AICWFDBG(LOGERROR, "usb_dev->rwnx_hw is not ready \r\n"); return; } if (urb->actual_length > urb->transfer_buffer_length) { aicwf_prealloc_rxbuff_free(rx_buff, &rx_priv->rxbuff_lock); aicwf_usb_rx_buf_put(usb_dev, usb_buf); aicwf_usb_rx_submit_all_urb_(usb_dev); return; } if (urb->status != 0 || !urb->actual_length) { aicwf_prealloc_rxbuff_free(rx_buff, &rx_priv->rxbuff_lock); aicwf_usb_rx_buf_put(usb_dev, usb_buf); if(urb->status < 0){ AICWFDBG(LOGDEBUG, "%s urb->status:%d \r\n", __func__, urb->status); if(g_rwnx_plat->wait_disconnect_cb == false){ g_rwnx_plat->wait_disconnect_cb = true; if(atomic_read(&aicwf_deinit_atomic) > 0){ atomic_set(&aicwf_deinit_atomic, 0); down(&aicwf_deinit_sem); AICWFDBG(LOGINFO, "%s need to wait for disconnect callback \r\n", __func__); }else{ g_rwnx_plat->wait_disconnect_cb = false; } } return; }else{ //schedule_work(&usb_dev->rx_urb_work); aicwf_usb_rx_submit_all_urb_(usb_dev); return; } } if (usb_dev->state == USB_UP_ST) { spin_lock_irqsave(&rx_priv->rxqlock, flags); //if (aicwf_usb_rx_aggr) { rx_buff->len = urb->actual_length; //printk("%s rx_buff->len:%d \r\n", __func__, rx_buff->len); //} if(!aicwf_rxbuff_enqueue(usb_dev->dev, &rx_priv->rxq, rx_buff)){ spin_unlock_irqrestore(&rx_priv->rxqlock, flags); usb_err("rx_priv->rxq is over flow!!!\n"); aicwf_prealloc_rxbuff_free(rx_buff, &rx_priv->rxbuff_lock); aicwf_usb_rx_buf_put(usb_dev, usb_buf); aicwf_usb_rx_submit_all_urb_(usb_dev); return; } spin_unlock_irqrestore(&rx_priv->rxqlock, flags); atomic_inc(&rx_priv->rx_cnt); if(atomic_read(&rx_priv->rx_cnt) == 1){ complete(&rx_priv->usbdev->bus_if->busrx_trgg); } aicwf_usb_rx_buf_put(usb_dev, usb_buf); aicwf_usb_rx_submit_all_urb_(usb_dev); } else { aicwf_prealloc_rxbuff_free(rx_buff, &rx_priv->rxbuff_lock); aicwf_usb_rx_buf_put(usb_dev, usb_buf); } } #else static void aicwf_usb_rx_complete(struct urb *urb) { struct aicwf_usb_buf *usb_buf = (struct aicwf_usb_buf *) urb->context; struct aic_usb_dev *usb_dev = usb_buf->usbdev; struct aicwf_rx_priv* rx_priv = usb_dev->rx_priv; struct sk_buff *skb = NULL; unsigned long flags = 0; skb = usb_buf->skb; usb_buf->skb = NULL; atomic_dec(&rx_urb_cnt); if(atomic_read(&rx_urb_cnt) < 10){ AICWFDBG(LOGDEBUG, "%s %d \r\n", __func__, atomic_read(&rx_urb_cnt)); //printk("%s %d \r\n", __func__, atomic_read(&rx_urb_cnt)); } if(!usb_dev->rwnx_hw){ aicwf_dev_skb_free(skb); aicwf_usb_rx_buf_put(usb_dev, usb_buf); AICWFDBG(LOGERROR, "usb_dev->rwnx_hw is not ready \r\n"); return; } if (urb->actual_length > urb->transfer_buffer_length) { usb_err("urb_rx len error %u/%u\n", urb->actual_length, urb->transfer_buffer_length); aicwf_dev_skb_free(skb); aicwf_usb_rx_buf_put(usb_dev, usb_buf); aicwf_usb_rx_submit_all_urb_(usb_dev); return; } if (urb->status != 0 || !urb->actual_length) { aicwf_dev_skb_free(skb); aicwf_usb_rx_buf_put(usb_dev, usb_buf); if(urb->status < 0){ AICWFDBG(LOGDEBUG, "%s urb->status:%d \r\n", __func__, urb->status); if(g_rwnx_plat->wait_disconnect_cb == false){ g_rwnx_plat->wait_disconnect_cb = true; if(atomic_read(&aicwf_deinit_atomic) > 0){ atomic_set(&aicwf_deinit_atomic, 0); down(&aicwf_deinit_sem); AICWFDBG(LOGINFO, "%s need to wait for disconnect callback \r\n", __func__); }else{ g_rwnx_plat->wait_disconnect_cb = false; } } return; }else{ //schedule_work(&usb_dev->rx_urb_work); aicwf_usb_rx_submit_all_urb_(usb_dev); return; } } #if 0 if ((urb->actual_length > 1600 * 30) && (aicwf_usb_rx_aggr)) { printk("r%d\n", urb->actual_length); } #endif if (usb_dev->state == USB_UP_ST) { skb_put(skb, urb->actual_length); if (aicwf_usb_rx_aggr) { skb->len = urb->actual_length; } else { #ifdef CONFIG_USB_RX_REASSEMBLE bool pkt_check = false; if (rx_priv->rx_reassemble_skb) { u32 frag_len = skb->len; struct sk_buff *reassemble_skb = rx_priv->rx_reassemble_skb; bool reassemble_valid = false; bool reassemble_done = false; if ((rx_priv->rx_reassemble_cur_frags + 1) == rx_priv->rx_reassemble_total_frags) { if ((rx_priv->rx_reassemble_cur_len + frag_len) == rx_priv->rx_reassemble_total_len) { reassemble_valid = true; reassemble_done = true; } } else { if (frag_len == aicwf_usb_max_pkt_size) { reassemble_valid = true; } } if (reassemble_valid) { memcpy((reassemble_skb->data + reassemble_skb->len), skb->data, frag_len); skb_put(reassemble_skb, skb->len); rx_priv->rx_reassemble_cur_len += frag_len; rx_priv->rx_reassemble_cur_frags++; aicwf_dev_skb_free(skb); if (reassemble_done) { skb = reassemble_skb; rx_priv->rx_reassemble_skb = NULL; rx_priv->rx_reassemble_total_len = 0; rx_priv->rx_reassemble_cur_len = 0; rx_priv->rx_reassemble_total_frags = 0; rx_priv->rx_reassemble_cur_frags = 0; } else { aicwf_usb_rx_buf_put(usb_dev, usb_buf); aicwf_usb_rx_submit_all_urb_(usb_dev); return; } } else { usb_err("invalid frag pkt, len=%u/%u/%u, frags=%u/%u\n", frag_len, rx_priv->rx_reassemble_cur_len, rx_priv->rx_reassemble_cur_len, rx_priv->rx_reassemble_cur_frags, rx_priv->rx_reassemble_total_frags); aicwf_dev_skb_free(reassemble_skb); rx_priv->rx_reassemble_skb = NULL; rx_priv->rx_reassemble_total_len = 0; rx_priv->rx_reassemble_cur_len = 0; rx_priv->rx_reassemble_total_frags = 0; rx_priv->rx_reassemble_cur_frags = 0; pkt_check = true; } } else { pkt_check = true; } if (pkt_check) { bool pkt_drop = false; u8 type = skb->data[2]; u32 pkt_len = skb->data[0] | (skb->data[1] << 8); if ((type & USB_TYPE_CFG) != USB_TYPE_CFG) { u32 pkt_total_len = pkt_len + RX_HWHRD_LEN; if ((pkt_total_len > aicwf_usb_max_pkt_size) && (skb->len == aicwf_usb_max_pkt_size)) { AICWFDBG(LOGINFO, "reassemble pkt, len=%u\n", pkt_total_len); struct sk_buff *reassemble_skb = __dev_alloc_skb(pkt_total_len, GFP_ATOMIC/*GFP_KERNEL*/); if (reassemble_skb) { memcpy(reassemble_skb->data, skb->data, skb->len); skb_put(reassemble_skb, skb->len); rx_priv->rx_reassemble_skb = reassemble_skb; rx_priv->rx_reassemble_total_len = pkt_total_len; rx_priv->rx_reassemble_cur_len = skb->len; rx_priv->rx_reassemble_total_frags = ALIGN(pkt_total_len, aicwf_usb_max_pkt_size) / aicwf_usb_max_pkt_size; rx_priv->rx_reassemble_cur_frags = 1; } else { usb_err("reassemble pkt alloc fail, len=%u\n", pkt_total_len); } aicwf_dev_skb_free(skb); aicwf_usb_rx_buf_put(usb_dev, usb_buf); aicwf_usb_rx_submit_all_urb_(usb_dev); return; } else if (pkt_total_len != skb->len) { usb_err("invalid DATA, len=%u/%u\n", pkt_len, skb->len); pkt_drop = true; } } else { if (type == USB_TYPE_CFG_CMD_RSP) { u32 pkt_total_len = ALIGN((pkt_len + 4), 4); if ((pkt_total_len > aicwf_usb_max_pkt_size) && (skb->len == aicwf_usb_max_pkt_size)) { AICWFDBG(LOGINFO, "reassemble pkt, len=%u\n", pkt_total_len); struct sk_buff *reassemble_skb = __dev_alloc_skb(pkt_total_len, GFP_ATOMIC/*GFP_KERNEL*/); if (reassemble_skb) { memcpy(reassemble_skb->data, skb->data, skb->len); skb_put(reassemble_skb, skb->len); rx_priv->rx_reassemble_skb = reassemble_skb; rx_priv->rx_reassemble_total_len = pkt_total_len; rx_priv->rx_reassemble_cur_len = skb->len; rx_priv->rx_reassemble_total_frags = ALIGN(pkt_total_len, aicwf_usb_max_pkt_size) / aicwf_usb_max_pkt_size; rx_priv->rx_reassemble_cur_frags = 1; } else { usb_err("reassemble pkt alloc fail, len=%u\n", pkt_total_len); } aicwf_dev_skb_free(skb); aicwf_usb_rx_buf_put(usb_dev, usb_buf); aicwf_usb_rx_submit_all_urb_(usb_dev); return; } else if (pkt_total_len != skb->len) { usb_err("invalid CMD_RSP, len=%u/%u\n", pkt_len, skb->len); pkt_drop = true; } } else if (type == USB_TYPE_CFG_DATA_CFM) { if (!((pkt_len == 8) && (skb->len == 12))) { usb_err("invalid DATA_CFM, len=%u/%u\n", pkt_len, skb->len); pkt_drop = true; } } else { usb_err("invalid pkt, type=0x%x, len=%u/%u\n", type, pkt_len, skb->len); pkt_drop = true; } } if (pkt_drop) { aicwf_dev_skb_free(skb); aicwf_usb_rx_buf_put(usb_dev, usb_buf); aicwf_usb_rx_submit_all_urb_(usb_dev); return; } } #endif } spin_lock_irqsave(&rx_priv->rxqlock, flags); if(!aicwf_rxframe_enqueue(usb_dev->dev, &rx_priv->rxq, skb)){ spin_unlock_irqrestore(&rx_priv->rxqlock, flags); usb_err("rx_priv->rxq is over flow!!!\n"); aicwf_dev_skb_free(skb); aicwf_usb_rx_buf_put(usb_dev, usb_buf); aicwf_usb_rx_submit_all_urb_(usb_dev); return; } spin_unlock_irqrestore(&rx_priv->rxqlock, flags); atomic_inc(&rx_priv->rx_cnt); #ifndef CONFIG_RX_TASKLET //if(!rx_priv->rx_thread_working && (atomic_read(&rx_priv->rx_cnt)>0)){ if(atomic_read(&rx_priv->rx_cnt) == 1){ complete(&rx_priv->usbdev->bus_if->busrx_trgg); } #else tasklet_schedule(&rx_priv->usbdev->recv_tasklet); #endif aicwf_usb_rx_buf_put(usb_dev, usb_buf); aicwf_usb_rx_submit_all_urb_(usb_dev); //schedule_work(&usb_dev->rx_urb_work); } else { aicwf_dev_skb_free(skb); aicwf_usb_rx_buf_put(usb_dev, usb_buf); } } #endif #ifdef CONFIG_USB_MSG_IN_EP void aicwf_usb_msg_rx_submit_all_urb_(struct aic_usb_dev *usb_dev); static void aicwf_usb_msg_rx_complete(struct urb *urb) { struct aicwf_usb_buf *usb_buf = (struct aicwf_usb_buf *) urb->context; struct aic_usb_dev *usb_dev = usb_buf->usbdev; struct aicwf_rx_priv* rx_priv = usb_dev->rx_priv; struct sk_buff *skb = NULL; unsigned long flags = 0; skb = usb_buf->skb; usb_buf->skb = NULL; if (urb->actual_length > urb->transfer_buffer_length) { usb_err("usb_msg_rx len error %u/%u\n", urb->actual_length, urb->transfer_buffer_length); aicwf_dev_skb_free(skb); aicwf_usb_msg_rx_buf_put(usb_dev, usb_buf); aicwf_usb_msg_rx_submit_all_urb_(usb_dev); //schedule_work(&usb_dev->msg_rx_urb_work); return; } if (urb->status != 0 || !urb->actual_length) { aicwf_dev_skb_free(skb); aicwf_usb_msg_rx_buf_put(usb_dev, usb_buf); if(urb->status < 0){ AICWFDBG(LOGDEBUG, "%s urb->status:%d \r\n", __func__, urb->status); return; }else{ aicwf_usb_msg_rx_submit_all_urb_(usb_dev); //schedule_work(&usb_dev->msg_rx_urb_work); return; } } if (usb_dev->state == USB_UP_ST) { skb_put(skb, urb->actual_length); #ifdef CONFIG_USB_RX_REASSEMBLE bool pkt_check = false; if (rx_priv->rx_msg_reassemble_skb) { u32 frag_len = skb->len; struct sk_buff *reassemble_skb = rx_priv->rx_msg_reassemble_skb; bool reassemble_valid = false; bool reassemble_done = false; if ((rx_priv->rx_msg_reassemble_cur_frags + 1) == rx_priv->rx_msg_reassemble_total_frags) { if ((rx_priv->rx_msg_reassemble_cur_len + frag_len) == rx_priv->rx_msg_reassemble_total_len) { reassemble_valid = true; reassemble_done = true; } } else { if (frag_len == AICWF_USB_MSG_MAX_PKT_SIZE) { reassemble_valid = true; } } if (reassemble_valid) { memcpy((reassemble_skb->data + reassemble_skb->len), skb->data, frag_len); skb_put(reassemble_skb, skb->len); rx_priv->rx_msg_reassemble_cur_len += frag_len; rx_priv->rx_msg_reassemble_cur_frags++; aicwf_dev_skb_free(skb); if (reassemble_done) { skb = reassemble_skb; rx_priv->rx_msg_reassemble_skb = NULL; rx_priv->rx_msg_reassemble_total_len = 0; rx_priv->rx_msg_reassemble_cur_len = 0; rx_priv->rx_msg_reassemble_total_frags = 0; rx_priv->rx_msg_reassemble_cur_frags = 0; } else { aicwf_usb_msg_rx_buf_put(usb_dev, usb_buf); aicwf_usb_msg_rx_submit_all_urb_(usb_dev); return; } } else { usb_err("invalid frag msg pkt, len=%u/%u/%u, frags=%u/%u\n", frag_len, rx_priv->rx_msg_reassemble_cur_len, rx_priv->rx_msg_reassemble_cur_len, rx_priv->rx_msg_reassemble_cur_frags, rx_priv->rx_msg_reassemble_total_frags); aicwf_dev_skb_free(reassemble_skb); rx_priv->rx_msg_reassemble_skb = NULL; rx_priv->rx_msg_reassemble_total_len = 0; rx_priv->rx_msg_reassemble_cur_len = 0; rx_priv->rx_msg_reassemble_total_frags = 0; rx_priv->rx_msg_reassemble_cur_frags = 0; pkt_check = true; } } else { pkt_check = true; } if (pkt_check) { bool pkt_drop = false; u8 type = skb->data[2]; u32 pkt_len = skb->data[0] | (skb->data[1] << 8); if ((type & USB_TYPE_CFG) != USB_TYPE_CFG) { usb_err("invalid msg pkt, type=0x%x, len=%u/%u\n", type, pkt_len, skb->len);; pkt_drop = true; } else { if (type == USB_TYPE_CFG_CMD_RSP) { u32 pkt_total_len = ALIGN((pkt_len + 4), 4); if ((pkt_total_len > AICWF_USB_MSG_MAX_PKT_SIZE) && (skb->len == AICWF_USB_MSG_MAX_PKT_SIZE)) { AICWFDBG(LOGINFO, "reassemble msg pkt, len=%u\n", pkt_total_len); struct sk_buff *reassemble_skb = __dev_alloc_skb(pkt_total_len, GFP_ATOMIC/*GFP_KERNEL*/); if (reassemble_skb) { memcpy(reassemble_skb->data, skb->data, skb->len); skb_put(reassemble_skb, skb->len); rx_priv->rx_msg_reassemble_skb = reassemble_skb; rx_priv->rx_msg_reassemble_total_len = pkt_total_len; rx_priv->rx_msg_reassemble_cur_len = skb->len; rx_priv->rx_msg_reassemble_total_frags = ALIGN(pkt_total_len, AICWF_USB_MSG_MAX_PKT_SIZE) / AICWF_USB_MSG_MAX_PKT_SIZE; rx_priv->rx_msg_reassemble_cur_frags = 1; } else { usb_err("reassemble msg pkt alloc fail, len=%u\n", pkt_total_len); } aicwf_dev_skb_free(skb); aicwf_usb_msg_rx_buf_put(usb_dev, usb_buf); aicwf_usb_msg_rx_submit_all_urb_(usb_dev); return; } else if (pkt_total_len != skb->len) { usb_err("invalid CMD_RSP, len=%u/%u\n", pkt_len, skb->len); pkt_drop = true; } } else if (type == USB_TYPE_CFG_DATA_CFM) { if (!((pkt_len == 8) && (skb->len == 12))) { usb_err("invalid DATA_CFM, len=%u/%u\n", pkt_len, skb->len); pkt_drop = true; } } else { usb_err("invalid msg pkt, type=0x%x, len=%u/%u\n", type, pkt_len, skb->len); pkt_drop = true; } } if (pkt_drop) { aicwf_dev_skb_free(skb); aicwf_usb_msg_rx_buf_put(usb_dev, usb_buf); aicwf_usb_msg_rx_submit_all_urb_(usb_dev); return; } } #endif spin_lock_irqsave(&rx_priv->msg_rxqlock, flags); if(!aicwf_rxframe_enqueue(usb_dev->dev, &rx_priv->msg_rxq, skb)){ spin_unlock_irqrestore(&rx_priv->msg_rxqlock, flags); usb_err("rx_priv->rxq is over flow!!!\n"); aicwf_dev_skb_free(skb); return; } spin_unlock_irqrestore(&rx_priv->msg_rxqlock, flags); atomic_inc(&rx_priv->msg_rx_cnt); complete(&rx_priv->usbdev->bus_if->msg_busrx_trgg); aicwf_usb_msg_rx_buf_put(usb_dev, usb_buf); aicwf_usb_msg_rx_submit_all_urb_(usb_dev); //schedule_work(&usb_dev->msg_rx_urb_work); } else { aicwf_dev_skb_free(skb); aicwf_usb_msg_rx_buf_put(usb_dev, usb_buf); } } #endif #ifdef CONFIG_PREALLOC_RX_SKB //extern int aic_rxbuff_size; static int aicwf_usb_submit_rx_urb(struct aic_usb_dev *usb_dev, struct aicwf_usb_buf *usb_buf) { int ret; struct rx_buff *rx_buff; if (!usb_buf || !usb_dev) return -1; if (usb_dev->state != USB_UP_ST) { usb_err("usb state is not up!\r\n"); aicwf_usb_rx_buf_put(usb_dev, usb_buf); return -1; } rx_buff = aicwf_prealloc_rxbuff_alloc(&usb_dev->rx_priv->rxbuff_lock); if (rx_buff == NULL) { AICWFDBG(LOGERROR, "failed to alloc rxbuff\r\n"); aicwf_usb_rx_buf_put(usb_dev, usb_buf); rx_urb_sched = true; return -1; } rx_buff->len = 0; rx_buff->start = rx_buff->data; rx_buff->read = rx_buff->start; rx_buff->end = rx_buff->data + aicwf_rxbuff_size_get(); usb_buf->rx_buff = rx_buff; usb_fill_bulk_urb(usb_buf->urb, usb_dev->udev, usb_dev->bulk_in_pipe, rx_buff->data, aicwf_rxbuff_size_get(), aicwf_usb_rx_complete, usb_buf); usb_buf->usbdev = usb_dev; usb_anchor_urb(usb_buf->urb, &usb_dev->rx_submitted); ret = usb_submit_urb(usb_buf->urb, GFP_ATOMIC); if (ret) { usb_err("usb submit rx urb fail:%d\n", ret); usb_unanchor_urb(usb_buf->urb); aicwf_prealloc_rxbuff_free(rx_buff, &usb_dev->rx_priv->rxbuff_lock); aicwf_usb_rx_buf_put(usb_dev, usb_buf); mdelay(100); return -1; }else{ atomic_inc(&rx_urb_cnt); } return 0; } #else static int aicwf_usb_submit_rx_urb(struct aic_usb_dev *usb_dev, struct aicwf_usb_buf *usb_buf) { struct sk_buff *skb; int ret; if (!usb_buf || !usb_dev) return -1; if (usb_dev->state != USB_UP_ST) { usb_err("usb state is not up!\n"); aicwf_usb_rx_buf_put(usb_dev, usb_buf); return -1; } if(aicwf_usb_rx_aggr){ skb = __dev_alloc_skb(AICWF_USB_AGGR_MAX_PKT_SIZE, GFP_ATOMIC/*GFP_KERNEL*/); } else { skb = __dev_alloc_skb(aicwf_usb_max_pkt_size, GFP_ATOMIC/*GFP_KERNEL*/); } if (!skb) { aicwf_usb_rx_buf_put(usb_dev, usb_buf); return -1; } usb_buf->skb = skb; if (aicwf_usb_rx_aggr) { usb_fill_bulk_urb(usb_buf->urb, usb_dev->udev, usb_dev->bulk_in_pipe, skb->data, AICWF_USB_AGGR_MAX_PKT_SIZE, aicwf_usb_rx_complete, usb_buf); } else { usb_fill_bulk_urb(usb_buf->urb, usb_dev->udev, usb_dev->bulk_in_pipe, skb->data, aicwf_usb_max_pkt_size, aicwf_usb_rx_complete, usb_buf); } usb_buf->usbdev = usb_dev; usb_anchor_urb(usb_buf->urb, &usb_dev->rx_submitted); ret = usb_submit_urb(usb_buf->urb, GFP_ATOMIC); if (ret) { usb_err("usb submit rx urb fail:%d\n", ret); usb_unanchor_urb(usb_buf->urb); aicwf_dev_skb_free(usb_buf->skb); usb_buf->skb = NULL; aicwf_usb_rx_buf_put(usb_dev, usb_buf); mdelay(100); return -1; }else{ atomic_inc(&rx_urb_cnt); } return 0; } #endif static void aicwf_usb_rx_submit_all_urb(struct aic_usb_dev *usb_dev) { struct aicwf_usb_buf *usb_buf; // int i = 0; if (usb_dev->state != USB_UP_ST) { AICWFDBG(LOGERROR, "bus is not up=%d\n", usb_dev->state); return; } while((usb_buf = aicwf_usb_rx_buf_get(usb_dev)) != NULL) { if (aicwf_usb_submit_rx_urb(usb_dev, usb_buf)) { AICWFDBG(LOGERROR, "sub rx fail\n"); return; #if 0 AICWFDBG(LOGERROR, "usb rx refill fail\n"); if (usb_dev->state != USB_UP_ST) return; #endif } } usb_dev->rx_prepare_ready = true; } #ifdef CONFIG_USB_MSG_IN_EP static int aicwf_usb_submit_msg_rx_urb(struct aic_usb_dev *usb_dev, struct aicwf_usb_buf *usb_buf) { struct sk_buff *skb; int ret; if (!usb_buf || !usb_dev) return -1; if (usb_dev->state != USB_UP_ST) { AICWFDBG(LOGERROR, "usb state is not up!\n"); aicwf_usb_msg_rx_buf_put(usb_dev, usb_buf); return -1; } skb = __dev_alloc_skb(AICWF_USB_MSG_MAX_PKT_SIZE, GFP_ATOMIC); if (!skb) { aicwf_usb_msg_rx_buf_put(usb_dev, usb_buf); return -1; } usb_buf->skb = skb; usb_fill_bulk_urb(usb_buf->urb, usb_dev->udev, usb_dev->msg_in_pipe, skb->data, AICWF_USB_MSG_MAX_PKT_SIZE, aicwf_usb_msg_rx_complete, usb_buf); usb_buf->usbdev = usb_dev; usb_anchor_urb(usb_buf->urb, &usb_dev->msg_rx_submitted); ret = usb_submit_urb(usb_buf->urb, GFP_ATOMIC); if (ret) { AICWFDBG(LOGERROR, "usb submit msg rx urb fail:%d\n", ret); usb_unanchor_urb(usb_buf->urb); aicwf_dev_skb_free(usb_buf->skb); usb_buf->skb = NULL; aicwf_usb_msg_rx_buf_put(usb_dev, usb_buf); mdelay(100); } return 0; } static void aicwf_usb_msg_rx_submit_all_urb(struct aic_usb_dev *usb_dev) { struct aicwf_usb_buf *usb_buf; if (usb_dev->state != USB_UP_ST) { AICWFDBG(LOGERROR, "bus is not up=%d\n", usb_dev->state); return; } while((usb_buf = aicwf_usb_msg_rx_buf_get(usb_dev)) != NULL) { if (aicwf_usb_submit_msg_rx_urb(usb_dev, usb_buf)) { AICWFDBG(LOGERROR, "usb msg rx refill fail\n"); if (usb_dev->state != USB_UP_ST) return; } } } #endif #ifdef CONFIG_USB_MSG_IN_EP void aicwf_usb_msg_rx_submit_all_urb_(struct aic_usb_dev *usb_dev){ aicwf_usb_msg_rx_submit_all_urb(usb_dev); } #endif void aicwf_usb_rx_submit_all_urb_(struct aic_usb_dev *usb_dev){ aicwf_usb_rx_submit_all_urb(usb_dev); } static void aicwf_usb_rx_prepare(struct aic_usb_dev *usb_dev) { aicwf_usb_rx_submit_all_urb(usb_dev); } #ifdef CONFIG_USB_MSG_IN_EP static void aicwf_usb_msg_rx_prepare(struct aic_usb_dev *usb_dev) { aicwf_usb_msg_rx_submit_all_urb(usb_dev); } #endif static void aicwf_usb_tx_prepare(struct aic_usb_dev *usb_dev) { struct aicwf_usb_buf *usb_buf; while(!list_empty(&usb_dev->tx_post_list)){ usb_buf = aicwf_usb_tx_dequeue(usb_dev, &usb_dev->tx_post_list, &usb_dev->tx_post_count, &usb_dev->tx_post_lock); #ifndef CONFIG_USB_TX_AGGR if(usb_buf->skb) { dev_kfree_skb(usb_buf->skb); usb_buf->skb = NULL; } #endif aicwf_usb_tx_queue(usb_dev, &usb_dev->tx_free_list, usb_buf, &usb_dev->tx_free_count, &usb_dev->tx_free_lock); } } #ifdef CONFIG_USB_TX_AGGR int aicwf_usb_send_pkt(struct aic_usb_dev *usb_dev, u8 *buf, uint buf_len) { int ret = 0; struct aicwf_usb_buf *usb_buf; unsigned long flags; bool need_cfm = false; if (usb_dev->state != USB_UP_ST) { AICWFDBG(LOGERROR, "usb state is not up!\n"); return -EIO; } usb_buf = aicwf_usb_tx_dequeue(usb_dev, &usb_dev->tx_free_list, &usb_dev->tx_free_count, &usb_dev->tx_free_lock); if (!usb_buf) { AICWFDBG(LOGERROR, "free:%d, post:%d\n", usb_dev->tx_free_count, usb_dev->tx_post_count); ret = -ENOMEM; goto flow_ctrl; } usb_buf->skb = (struct sk_buff *)buf; usb_buf->usbdev = usb_dev; if (need_cfm) usb_buf->cfm = true; else usb_buf->cfm = false; AICWFDBG(LOGERROR, "%s len %d\n", __func__, buf_len); print_hex_dump(KERN_ERR, "buf ", DUMP_PREFIX_NONE, 16, 1, &buf[0], 32, false); usb_fill_bulk_urb(usb_buf->urb, usb_dev->udev, usb_dev->bulk_out_pipe, buf, buf_len, aicwf_usb_tx_complete, usb_buf); usb_buf->urb->transfer_flags |= URB_ZERO_PACKET; aicwf_usb_tx_queue(usb_dev, &usb_dev->tx_post_list, usb_buf, &usb_dev->tx_post_count, &usb_dev->tx_post_lock); ret = 0; flow_ctrl: spin_lock_irqsave(&usb_dev->tx_flow_lock, flags); if (usb_dev->tx_free_count < AICWF_USB_TX_LOW_WATER) { usb_dev->tbusy = true; aicwf_usb_tx_flowctrl(usb_dev->rwnx_hw, true); } spin_unlock_irqrestore(&usb_dev->tx_flow_lock, flags); return ret; } int aicwf_usb_aggr(struct aicwf_tx_priv *tx_priv, struct sk_buff *pkt) { struct rwnx_txhdr *txhdr = (struct rwnx_txhdr *)pkt->data; u8 usb_header[8]; u8 adjust_str[4] = {0, 0, 0, 0}; u32 curr_len = 0; int allign_len = 0; u32 data_len = (pkt->len - sizeof(struct rwnx_txhdr) + sizeof(struct txdesc_api)) + 4; usb_header[0] =(data_len & 0xff); usb_header[1] =((data_len >> 8)&0x0f); usb_header[2] =(data_len & 0xff); usb_header[3] =((data_len >> 8)&0x0f); usb_header[4] =(data_len & 0xff); usb_header[5] =((data_len >> 8)&0x0f); usb_header[6] = 0x01; //data usb_header[7] = 0; //reserved memcpy(tx_priv->tail, (u8 *)&usb_header, sizeof(usb_header)); tx_priv->tail += sizeof(usb_header); //payload memcpy(tx_priv->tail, (u8 *)(long)&txhdr->sw_hdr->desc, sizeof(struct txdesc_api)); tx_priv->tail += sizeof(struct txdesc_api); //hostdesc memcpy(tx_priv->tail, (u8 *)((u8 *)txhdr + txhdr->sw_hdr->headroom), pkt->len-txhdr->sw_hdr->headroom); tx_priv->tail += (pkt->len - txhdr->sw_hdr->headroom); //word alignment curr_len = tx_priv->tail - tx_priv->head; if (curr_len & (TX_ALIGNMENT - 1)) { allign_len = roundup(curr_len, TX_ALIGNMENT)-curr_len; memcpy(tx_priv->tail, adjust_str, allign_len); tx_priv->tail += allign_len; } tx_priv->aggr_buf->dev = pkt->dev; if(!txhdr->sw_hdr->need_cfm) { kmem_cache_free(txhdr->sw_hdr->rwnx_vif->rwnx_hw->sw_txhdr_cache, txhdr->sw_hdr); skb_pull(pkt, txhdr->sw_hdr->headroom); consume_skb(pkt); } atomic_inc(&tx_priv->aggr_count); return 0; } int aicwf_usb_send(struct aicwf_tx_priv *tx_priv) { struct sk_buff *pkt; struct sk_buff *tx_buf; struct aic_usb_dev *usbdev = tx_priv->usbdev; struct aicwf_usb_buf *usb_buf; u8* buf; int ret = 0; int curr_len = 0; unsigned long flags; if (aicwf_is_framequeue_empty(&tx_priv->txq)) { ret = -1; AICWFDBG(LOGERROR, "no buf to send\n"); return ret; } if (usbdev->state != USB_UP_ST) { AICWFDBG(LOGERROR, "usb state is not up!\n"); ret = -ENODEV; return ret; } usb_buf = aicwf_usb_tx_dequeue(usbdev, &usbdev->tx_free_list, &usbdev->tx_free_count, &usbdev->tx_free_lock); if (!usb_buf) { AICWFDBG(LOGERROR, "free:%d, post:%d\n", usbdev->tx_free_count, usbdev->tx_post_count); ret = -ENOMEM; return ret; } usb_buf->aggr_cnt = 0; spin_lock_bh(&usbdev->tx_priv->txdlock); tx_priv->head = usb_buf->skb->data; tx_priv->tail = usb_buf->skb->data; while (!aicwf_is_framequeue_empty(&usbdev->tx_priv->txq)) { if (usbdev->state != USB_UP_ST) { AICWFDBG(LOGERROR, "usb state is not up, break!\n"); ret = -ENODEV; break; } if (usb_buf->aggr_cnt == 10) { break; } spin_lock_bh(&usbdev->tx_priv->txqlock); pkt = aicwf_frame_dequeue(&usbdev->tx_priv->txq); if (pkt == NULL) { AICWFDBG(LOGERROR, "txq no pkt\n"); spin_unlock_bh(&usbdev->tx_priv->txqlock); ret = -1; return ret; } atomic_dec(&usbdev->tx_priv->tx_pktcnt); spin_unlock_bh(&usbdev->tx_priv->txqlock); if(tx_priv==NULL || tx_priv->tail==NULL || pkt==NULL) { AICWFDBG(LOGERROR, "null error\n"); } aicwf_usb_aggr(tx_priv, pkt); usb_buf->aggr_cnt++; } tx_buf = usb_buf->skb; buf = tx_buf->data; curr_len = tx_priv->tail - tx_priv->head; AICWFDBG(LOGTRACE, "%s len %d, cnt %d\n", __func__,curr_len, usb_buf->aggr_cnt); tx_buf->len = tx_priv->tail - tx_priv->head; spin_unlock_bh(&usbdev->tx_priv->txdlock); usb_fill_bulk_urb(usb_buf->urb, usbdev->udev, usbdev->bulk_out_pipe, buf, curr_len, aicwf_usb_tx_complete, usb_buf); usb_buf->urb->transfer_flags |= URB_ZERO_PACKET; aicwf_usb_tx_queue(usbdev, &usbdev->tx_post_list, usb_buf, &usbdev->tx_post_count, &usbdev->tx_post_lock); flow_ctrl: spin_lock_irqsave(&usbdev->tx_flow_lock, flags); if (usbdev->tx_free_count < AICWF_USB_TX_LOW_WATER) { usbdev->tbusy = true; aicwf_usb_tx_flowctrl(usbdev->rwnx_hw, true); } spin_unlock_irqrestore(&usbdev->tx_flow_lock, flags); return ret; } #endif static void aicwf_usb_tx_process(struct aic_usb_dev *usb_dev) { struct aicwf_usb_buf *usb_buf; int ret = 0; u8* data = NULL; #ifdef CONFIG_USB_TX_AGGR if (!aicwf_is_framequeue_empty(&usb_dev->tx_priv->txq)) { if (aicwf_usb_send(usb_dev->tx_priv)) { AICWFDBG(LOGERROR, "%s no buf send\n", __func__); } } #endif while(!list_empty(&usb_dev->tx_post_list)) { if (usb_dev->state != USB_UP_ST) { usb_err("usb state is not up!\n"); return; } usb_buf = aicwf_usb_tx_dequeue(usb_dev, &usb_dev->tx_post_list, &usb_dev->tx_post_count, &usb_dev->tx_post_lock); if(!usb_buf) { usb_err("can not get usb_buf from tx_post_list!\n"); return; } data = usb_buf->skb->data; ret = usb_submit_urb(usb_buf->urb, GFP_KERNEL); if (ret) { AICWFDBG(LOGERROR, "aicwf_usb_bus_tx usb_submit_urb FAILED err:%d\n", ret); #ifdef CONFIG_USB_TX_AGGR aicwf_usb_tx_queue(usb_dev, &usb_dev->tx_post_list, usb_buf, &usb_dev->tx_post_count, &usb_dev->tx_post_lock); break; #else goto fail; #endif } continue; #ifndef CONFIG_USB_TX_AGGR fail: usb_txc_sta_flowctrl(usb_buf, usb_dev); dev_kfree_skb(usb_buf->skb); usb_buf->skb = NULL; aicwf_usb_tx_queue(usb_dev, &usb_dev->tx_free_list, usb_buf, &usb_dev->tx_free_count, &usb_dev->tx_free_lock); #endif } } #ifdef CONFIG_TX_TASKLET void aicwf_tasklet_tx_process(struct aic_usb_dev *usb_dev){ aicwf_usb_tx_process(usb_dev); } #endif static inline void aic_thread_wait_stop(void) { #if 1// PLATFORM_LINUX #if 0 while (!kthread_should_stop()) rtw_msleep_os(10); #else set_current_state(TASK_INTERRUPTIBLE); while (!kthread_should_stop()) { schedule(); set_current_state(TASK_INTERRUPTIBLE); } __set_current_state(TASK_RUNNING); #endif #endif } int usb_bustx_thread(void *data) { struct aicwf_bus *bus = (struct aicwf_bus *)data; struct aic_usb_dev *usbdev = bus->bus_priv.usb; int set_cpu_ret = 0; #ifdef CONFIG_THREAD_INFO_IN_TASK #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 16, 0)) AICWFDBG(LOGINFO, "%s the cpu is:%d\n", __func__, current->thread_info.cpu); #else AICWFDBG(LOGINFO, "%s the cpu is:%d\n", __func__, current->cpu); #endif #endif set_cpu_ret = set_cpus_allowed_ptr(current, cpumask_of(1)); #ifdef CONFIG_THREAD_INFO_IN_TASK AICWFDBG(LOGINFO, "%s set_cpu_ret is:%d\n", __func__, set_cpu_ret); #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 16, 0)) AICWFDBG(LOGINFO, "%s change cpu to:%d\n", __func__, current->thread_info.cpu); #else AICWFDBG(LOGINFO, "%s change cpu to:%d\n", __func__, current->cpu); #endif #endif #ifdef CONFIG_TXRX_THREAD_PRIO if (bustx_thread_prio > 0) { #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 9, 0)) sched_set_fifo_low(current); #else struct sched_param param; param.sched_priority = (bustx_thread_prio < MAX_RT_PRIO)?bustx_thread_prio:(MAX_RT_PRIO-1); sched_setscheduler(current, SCHED_FIFO, ¶m); #endif } #endif AICWFDBG(LOGINFO, "%s the policy of current thread is:%d\n", __func__, current->policy); AICWFDBG(LOGINFO, "%s the rt_priority of current thread is:%d\n", __func__, current->rt_priority); AICWFDBG(LOGINFO, "%s the current pid is:%d\n", __func__, current->pid); while (1) { #if 0 if(kthread_should_stop()) { usb_err("usb bustx thread stop 2\n"); break; } #endif if (!wait_for_completion_interruptible(&bus->bustx_trgg)) { if(usbdev->bus_if->state == BUS_DOWN_ST){ AICWFDBG(LOGINFO, "usb bustx thread will to stop\n"); break; } #ifdef CONFIG_USB_TX_AGGR if ((usbdev->tx_post_count > 0) || !aicwf_is_framequeue_empty(&usbdev->tx_priv->txq)) #else if (usbdev->tx_post_count > 0) #endif aicwf_usb_tx_process(usbdev); } } aic_thread_wait_stop(); AICWFDBG(LOGINFO, "usb bustx thread stop\n"); return 0; } int usb_busrx_thread(void *data) { struct aicwf_rx_priv *rx_priv = (struct aicwf_rx_priv *)data; struct aicwf_bus *bus_if = rx_priv->usbdev->bus_if; int set_cpu_ret = 0; #ifdef CONFIG_THREAD_INFO_IN_TASK #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 16, 0)) AICWFDBG(LOGINFO, "%s the cpu is:%d\n", __func__, current->thread_info.cpu); #else AICWFDBG(LOGINFO, "%s the cpu is:%d\n", __func__, current->cpu); #endif #endif set_cpu_ret = set_cpus_allowed_ptr(current, cpumask_of(1)); #ifdef CONFIG_THREAD_INFO_IN_TASK AICWFDBG(LOGINFO, "%s set_cpu_ret is:%d\n", __func__, set_cpu_ret); #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 16, 0)) AICWFDBG(LOGINFO, "%s change cpu to:%d\n", __func__, current->thread_info.cpu); #else AICWFDBG(LOGINFO, "%s change cpu to:%d\n", __func__, current->cpu); #endif #endif #ifdef CONFIG_TXRX_THREAD_PRIO if (busrx_thread_prio > 0) { #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 9, 0)) sched_set_fifo_low(current); #else struct sched_param param; param.sched_priority = (busrx_thread_prio < MAX_RT_PRIO)?busrx_thread_prio:(MAX_RT_PRIO-1); sched_setscheduler(current, SCHED_FIFO, ¶m); #endif } #endif AICWFDBG(LOGINFO, "%s the policy of current thread is:%d\n", __func__, current->policy); AICWFDBG(LOGINFO, "%s the rt_priority of current thread is:%d\n", __func__, current->rt_priority); AICWFDBG(LOGINFO, "%s the current pid is:%d\n", __func__, current->pid); while (1) { #if 0 if(kthread_should_stop()) { usb_err("usb busrx thread stop 2\n"); break; } #endif //rx_priv->rx_thread_working = 0;//AIDEN if (!wait_for_completion_interruptible(&bus_if->busrx_trgg)) { if(bus_if->state == BUS_DOWN_ST){ AICWFDBG(LOGINFO, "usb busrx thread will to stop\n"); break; } //rx_priv->rx_thread_working = 1;//AIDEN aicwf_process_rxframes(rx_priv); } } aic_thread_wait_stop(); AICWFDBG(LOGINFO, "usb busrx thread stop\n"); return 0; } #ifdef CONFIG_USB_MSG_IN_EP int usb_msg_busrx_thread(void *data) { struct aicwf_rx_priv *rx_priv = (struct aicwf_rx_priv *)data; struct aicwf_bus *bus_if = rx_priv->usbdev->bus_if; #ifdef CONFIG_TXRX_THREAD_PRIO if (busrx_thread_prio > 0) { #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 9, 0)) sched_set_fifo_low(current); #else struct sched_param param; param.sched_priority = (busrx_thread_prio < MAX_RT_PRIO)?busrx_thread_prio:(MAX_RT_PRIO-1); sched_setscheduler(current, SCHED_FIFO, ¶m); #endif } #endif AICWFDBG(LOGINFO, "%s the policy of current thread is:%d\n", __func__, current->policy); AICWFDBG(LOGINFO, "%s the rt_priority of current thread is:%d\n", __func__, current->rt_priority); AICWFDBG(LOGINFO, "%s the current pid is:%d\n", __func__, current->pid); while (1) { #if 0 if(kthread_should_stop()) { usb_err("usb msg busrx thread stop\n"); break; } #endif if (!wait_for_completion_interruptible(&bus_if->msg_busrx_trgg)) { if(bus_if->state == BUS_DOWN_ST){ AICWFDBG(LOGINFO, "usb msg busrx thread will to stop\n"); break; } aicwf_process_msg_rxframes(rx_priv); } } aic_thread_wait_stop(); AICWFDBG(LOGINFO, "usb msg busrx thread stop\n"); return 0; } #endif static void aicwf_usb_send_msg_complete(struct urb *urb) { struct aic_usb_dev *usb_dev = (struct aic_usb_dev *) urb->context; usb_dev->msg_finished = true; if (waitqueue_active(&usb_dev->msg_wait)) wake_up(&usb_dev->msg_wait); } static int aicwf_usb_bus_txmsg(struct device *dev, u8 *buf, u32 len) { int ret = 0; struct aicwf_bus *bus_if = dev_get_drvdata(dev); struct aic_usb_dev *usb_dev = bus_if->bus_priv.usb; if (usb_dev->state != USB_UP_ST) return -EIO; if (buf == NULL || len == 0 || usb_dev->msg_out_urb == NULL) return -EINVAL; #if 0 if (test_and_set_bit(0, &usb_dev->msg_busy)) { usb_err("In a control frame option, can't tx!\n"); return -EIO; } #endif usb_dev->msg_finished = false; #ifdef CONFIG_USB_MSG_OUT_EP if (usb_dev->msg_out_pipe) { usb_fill_bulk_urb(usb_dev->msg_out_urb, usb_dev->udev, usb_dev->msg_out_pipe, buf, len, (usb_complete_t) aicwf_usb_send_msg_complete, usb_dev); } else { usb_fill_bulk_urb(usb_dev->msg_out_urb, usb_dev->udev, usb_dev->bulk_out_pipe, buf, len, (usb_complete_t) aicwf_usb_send_msg_complete, usb_dev); } #else usb_fill_bulk_urb(usb_dev->msg_out_urb, usb_dev->udev, usb_dev->bulk_out_pipe, buf, len, (usb_complete_t) aicwf_usb_send_msg_complete, usb_dev); #endif #if defined CONFIG_USB_NO_TRANS_DMA_MAP usb_dev->msg_out_urb->transfer_dma = usb_dev->cmd_dma_trans_addr; usb_dev->msg_out_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; #endif #ifdef CONFIG_USE_USB_ZERO_PACKET usb_dev->msg_out_urb->transfer_flags |= URB_ZERO_PACKET; #endif ret = usb_submit_urb(usb_dev->msg_out_urb, GFP_ATOMIC); if (ret) { usb_err("usb_submit_urb failed %d\n", ret); goto exit; } ret = wait_event_timeout(usb_dev->msg_wait, usb_dev->msg_finished, msecs_to_jiffies(CMD_TX_TIMEOUT)); if (!ret) { if (usb_dev->msg_out_urb) usb_kill_urb(usb_dev->msg_out_urb); usb_err("Txmsg wait timed out\n"); ret = -EIO; goto exit; } if (usb_dev->msg_finished == false) { usb_err("Txmsg timed out\n"); ret = -ETIMEDOUT; goto exit; } exit: #if 0 clear_bit(0, &usb_dev->msg_busy); #endif return ret; } static void aicwf_usb_free_urb(struct list_head *q, spinlock_t *qlock) { struct aicwf_usb_buf *usb_buf, *tmp; unsigned long flags; spin_lock_irqsave(qlock, flags); list_for_each_entry_safe(usb_buf, tmp, q, list) { spin_unlock_irqrestore(qlock, flags); if (!usb_buf->urb) { usb_err("bad usb_buf\n"); spin_lock_irqsave(qlock, flags); break; } #ifdef CONFIG_USB_TX_AGGR if (usb_buf->skb) { dev_kfree_skb(usb_buf->skb); } #endif usb_free_urb(usb_buf->urb); #if defined CONFIG_USB_NO_TRANS_DMA_MAP // free dma buf if needed if (usb_buf->data_buf) { #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)) usb_free_coherent(usb_buf->usbdev->udev, DATA_BUF_MAX, usb_buf->data_buf, usb_buf->data_dma_trans_addr); #else usb_buffer_free(usb_buf->usbdev->udev, DATA_BUF_MAX, usb_buf->data_buf, usb_buf->data_dma_trans_addr); #endif usb_buf->data_buf = NULL; usb_buf->data_dma_trans_addr = 0x0; } #endif list_del_init(&usb_buf->list); spin_lock_irqsave(qlock, flags); } spin_unlock_irqrestore(qlock, flags); } static int aicwf_usb_alloc_rx_urb(struct aic_usb_dev *usb_dev) { int i; AICWFDBG(LOGINFO, "%s AICWF_USB_RX_URBS:%d \r\n", __func__, AICWF_USB_RX_URBS); for (i = 0; i < AICWF_USB_RX_URBS; i++) { struct aicwf_usb_buf *usb_buf = &usb_dev->usb_rx_buf[i]; usb_buf->usbdev = usb_dev; usb_buf->urb = usb_alloc_urb(0, GFP_KERNEL); if (!usb_buf->urb) { usb_err("could not allocate rx data urb\n"); goto err; } #if defined CONFIG_USB_NO_TRANS_DMA_MAP // dma buf unused usb_buf->data_buf = NULL; usb_buf->data_dma_trans_addr = 0x0; #endif list_add_tail(&usb_buf->list, &usb_dev->rx_free_list); } return 0; err: aicwf_usb_free_urb(&usb_dev->rx_free_list, &usb_dev->rx_free_lock); return -ENOMEM; } static int aicwf_usb_alloc_tx_urb(struct aic_usb_dev *usb_dev) { int i; AICWFDBG(LOGINFO, "%s AICWF_USB_TX_URBS:%d \r\n", __func__, AICWF_USB_TX_URBS); for (i = 0; i < AICWF_USB_TX_URBS; i++) { struct aicwf_usb_buf *usb_buf = &usb_dev->usb_tx_buf[i]; usb_buf->usbdev = usb_dev; usb_buf->urb = usb_alloc_urb(0, GFP_KERNEL); if (!usb_buf->urb) { usb_err("could not allocate tx data urb\n"); goto err; } #ifdef CONFIG_USB_TX_AGGR usb_buf->skb = dev_alloc_skb(MAX_USB_AGGR_TXPKT_LEN); #endif #if defined CONFIG_USB_NO_TRANS_DMA_MAP // alloc dma buf #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)) usb_buf->data_buf = usb_alloc_coherent(usb_dev->udev, DATA_BUF_MAX, (in_interrupt() ? GFP_ATOMIC : GFP_KERNEL), &usb_buf->data_dma_trans_addr); #else usb_buf->data_buf = usb_buffer_alloc(usb_dev->udev, DATA_BUF_MAX, (in_interrupt() ? GFP_ATOMIC : GFP_KERNEL), &usb_buf->data_dma_trans_addr); #endif if (usb_buf->data_buf == NULL) { usb_err("could not allocate tx data dma buf\n"); goto err; } #endif list_add_tail(&usb_buf->list, &usb_dev->tx_free_list); (usb_dev->tx_free_count)++; } return 0; err: aicwf_usb_free_urb(&usb_dev->tx_free_list, &usb_dev->tx_free_lock); return -ENOMEM; } #ifdef CONFIG_USB_MSG_IN_EP static int aicwf_usb_alloc_msg_rx_urb(struct aic_usb_dev *usb_dev) { int i; AICWFDBG(LOGINFO, "%s AICWF_USB_MSG_RX_URBS:%d \r\n", __func__, AICWF_USB_MSG_RX_URBS); for (i = 0; i < AICWF_USB_MSG_RX_URBS; i++) { struct aicwf_usb_buf *usb_buf = &usb_dev->usb_msg_rx_buf[i]; usb_buf->usbdev = usb_dev; usb_buf->urb = usb_alloc_urb(0, GFP_KERNEL); if (!usb_buf->urb) { usb_err("could not allocate rx data urb\n"); goto err; } list_add_tail(&usb_buf->list, &usb_dev->msg_rx_free_list); } return 0; err: aicwf_usb_free_urb(&usb_dev->msg_rx_free_list, &usb_dev->msg_rx_free_lock); return -ENOMEM; } #endif static void aicwf_usb_state_change(struct aic_usb_dev *usb_dev, int state) { int old_state; if (usb_dev->state == state) return; old_state = usb_dev->state; usb_dev->state = state; if (state == USB_DOWN_ST) { usb_dev->bus_if->state = BUS_DOWN_ST; } if (state == USB_UP_ST) { usb_dev->bus_if->state = BUS_UP_ST; } } int align_param = 8; module_param(align_param, int, 0660); static void usb_tx_flow_ctrl(struct rwnx_txhdr *txhdr, struct aic_usb_dev *usb_dev, struct rwnx_hw *rwnx_hw) { #ifdef CONFIG_PER_STA_FC struct rwnx_sta *sta; u8 sta_idx; unsigned long flags; //printk("txdata: sta %d\n", txhdr->sw_hdr->desc.host.staid); sta_idx = txhdr->sw_hdr->desc.host.staid; if(sta_idx < NX_REMOTE_STA_MAX && !(txhdr->sw_hdr->desc.host.flags & TXU_CNTRL_MGMT)) { struct rwnx_vif *vif = NULL; sta = &rwnx_hw->sta_table[sta_idx]; vif = rwnx_hw->vif_table[sta->vif_idx]; spin_lock_irqsave(&usb_dev->tx_flow_lock, flags); atomic_inc(&rwnx_hw->sta_flowctrl[sta_idx].tx_pending_cnt); //printk("sta %d pending %d >= 64, flowctrl=%d\n", sta->sta_idx, sta->tx_pending_cnt, sta->flowctrl); if(RWNX_VIF_TYPE(vif) == NL80211_IFTYPE_AP) { if((atomic_read(&rwnx_hw->sta_flowctrl[sta_idx].tx_pending_cnt) >= AICWF_USB_FC_PERSTA_HIGH_WATER && rwnx_hw->sta_flowctrl[sta_idx].flowctrl == 0) || rwnx_hw->sta_flowctrl[sta_idx].flowctrl) { //AICWFDBG(LOGDEBUG, "sta 0x%x:0x%x, %d pending %d, stop\n", sta->mac_addr[4], sta->mac_addr[5], sta->sta_idx, atomic_read(&rwnx_hw->sta_flowctrl[sta_idx].tx_pending_cnt)); if(!usb_dev->tbusy) rwnx_stop_sta_all_queues((void *)sta, usb_dev->rwnx_hw); rwnx_hw->sta_flowctrl[sta_idx].flowctrl = 1; } } spin_unlock_irqrestore(&usb_dev->tx_flow_lock, flags); } #endif } #ifdef CONFIG_USB_TX_AGGR static int aicwf_usb_bus_txdata(struct device *dev, struct sk_buff *pkt) { uint prio; int ret = -EBADE; struct aicwf_bus *bus_if = dev_get_drvdata(dev); struct aic_usb_dev *usbdev = bus_if->bus_priv.usb; //printk("%s\n", __func__); prio = (pkt->priority & 0x7); spin_lock_bh(&usbdev->tx_priv->txqlock); if (!aicwf_frame_enq(usbdev->dev, &usbdev->tx_priv->txq, pkt, prio)) { aicwf_dev_skb_free(pkt); spin_unlock_bh(&usbdev->tx_priv->txqlock); return -ENOSR; } else { ret = 0; } if (bus_if->state != BUS_UP_ST) { usb_err("bus_if stopped\n"); spin_unlock_bh(&usbdev->tx_priv->txqlock); return -1; } atomic_inc(&usbdev->tx_priv->tx_pktcnt); spin_unlock_bh(&usbdev->tx_priv->txqlock); complete(&bus_if->bustx_trgg); return ret; } #else static int aicwf_usb_bus_txdata(struct device *dev, struct sk_buff *skb) { u8 *buf; u16 buf_len = 0; u16 adjust_len = 0; struct aicwf_usb_buf *usb_buf; int ret = 0; unsigned long flags; struct aicwf_bus *bus_if = dev_get_drvdata(dev); struct aic_usb_dev *usb_dev = bus_if->bus_priv.usb; struct rwnx_txhdr *txhdr = (struct rwnx_txhdr *)skb->data; struct rwnx_hw *rwnx_hw = usb_dev->rwnx_hw; u8 usb_header[4]; u8 adj_buf[4] = {0}; u16 index = 0; bool need_cfm = false; #ifdef CONFIG_USB_ALIGN_DATA//AIDEN u8 *buf_align; int align; #endif if (usb_dev->state != USB_UP_ST) { usb_err("usb state is not up!\n"); kmem_cache_free(rwnx_hw->sw_txhdr_cache, txhdr->sw_hdr); dev_kfree_skb_any(skb); return -EIO; } usb_buf = aicwf_usb_tx_dequeue(usb_dev, &usb_dev->tx_free_list, &usb_dev->tx_free_count, &usb_dev->tx_free_lock); if (!usb_buf) { usb_err("free:%d, post:%d\n", usb_dev->tx_free_count, usb_dev->tx_post_count); kmem_cache_free(rwnx_hw->sw_txhdr_cache, txhdr->sw_hdr); dev_kfree_skb_any(skb); ret = -ENOMEM; goto flow_ctrl; } usb_tx_flow_ctrl(txhdr, usb_dev, rwnx_hw); if (txhdr->sw_hdr->need_cfm) { need_cfm = true; #if defined CONFIG_USB_NO_TRANS_DMA_MAP buf = usb_buf->data_buf; #else buf = kmalloc(skb->len + 1, GFP_ATOMIC/*GFP_KERNEL*/); #endif index += sizeof(usb_header); memcpy(&buf[index], (u8 *)(long)&txhdr->sw_hdr->desc, sizeof(struct txdesc_api)); index += sizeof(struct txdesc_api); memcpy(&buf[index], &skb->data[txhdr->sw_hdr->headroom], skb->len - txhdr->sw_hdr->headroom); index += skb->len - txhdr->sw_hdr->headroom; buf_len = index; if (buf_len & (TX_ALIGNMENT - 1)) { adjust_len = roundup(buf_len, TX_ALIGNMENT)-buf_len; memcpy(&buf[buf_len], adj_buf, adjust_len); buf_len += adjust_len; } usb_header[0] =((buf_len) & 0xff); usb_header[1] =(((buf_len) >> 8)&0x0f); usb_header[2] = 0x01; //data usb_header[3] = 0; //reserved memcpy(&buf[0], usb_header, sizeof(usb_header)); usb_buf->skb = (struct sk_buff *)buf; } else { skb_pull(skb, txhdr->sw_hdr->headroom); skb_push(skb, sizeof(struct txdesc_api)); memcpy(&skb->data[0], (u8 *)(long)&txhdr->sw_hdr->desc, sizeof(struct txdesc_api)); kmem_cache_free(rwnx_hw->sw_txhdr_cache, txhdr->sw_hdr); skb_push(skb, sizeof(usb_header)); usb_header[0] =((skb->len) & 0xff); usb_header[1] =(((skb->len) >> 8)&0x0f); usb_header[2] = 0x01; //data usb_header[3] = 0; //reserved memcpy(&skb->data[0], usb_header, sizeof(usb_header)); #if defined CONFIG_USB_NO_TRANS_DMA_MAP buf = usb_buf->data_buf; memcpy(&buf[0], skb->data, skb->len); #else buf = skb->data; #endif buf_len = skb->len; usb_buf->skb = skb; } usb_buf->usbdev = usb_dev; if (need_cfm) usb_buf->cfm = true; else usb_buf->cfm = false; #ifndef CONFIG_USE_USB_ZERO_PACKET if((buf_len % 512) == 0){ printk("%s send zero package buf_len: %d\r\n", __func__, buf_len); if(txhdr->sw_hdr->need_cfm){ buf[buf_len] = 0x00; buf_len = buf_len + 1; }else{ skb_put(skb, 1); skb->data[buf_len] = 0x00; buf = skb->data; buf_len = skb->len; } } #endif #ifdef CONFIG_USB_ALIGN_DATA #if defined CONFIG_USB_NO_TRANS_DMA_MAP #error "CONFIG_USB_NO_TRANS_DMA_MAP not supported" #endif #if 0 usb_buf->usb_align_data = (u8*)kmalloc(sizeof(u8) * buf_len + align_param, GFP_ATOMIC); align = ((unsigned long)(usb_buf->usb_align_data)) & (align_param - 1); memcpy(usb_buf->usb_align_data + (align_param - align), buf, buf_len); usb_fill_bulk_urb(usb_buf->urb, usb_dev->udev, usb_dev->bulk_out_pipe, usb_buf->usb_align_data + (align_param - align), buf_len, aicwf_usb_tx_complete, usb_buf); #else if (!IS_ALIGNED((unsigned long)buf, align_param)) { usb_buf->usb_align_data = (u8*)kmalloc(sizeof(u8) * buf_len + align_param, GFP_ATOMIC); if (usb_buf->usb_align_data) { align = ((unsigned long)(usb_buf->usb_align_data)) & (align_param - 1); buf_align = usb_buf->usb_align_data + (align_param - align); memcpy(buf_align, buf, buf_len); } } else { buf_align = buf; } usb_fill_bulk_urb(usb_buf->urb, usb_dev->udev, usb_dev->bulk_out_pipe, buf_align, buf_len, aicwf_usb_tx_complete, usb_buf); #endif #else usb_fill_bulk_urb(usb_buf->urb, usb_dev->udev, usb_dev->bulk_out_pipe, buf, buf_len, aicwf_usb_tx_complete, usb_buf); #endif #if defined CONFIG_USB_NO_TRANS_DMA_MAP usb_buf->urb->transfer_dma = usb_buf->data_dma_trans_addr; usb_buf->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; #endif #ifdef CONFIG_USE_USB_ZERO_PACKET usb_buf->urb->transfer_flags |= URB_ZERO_PACKET; #endif aicwf_usb_tx_queue(usb_dev, &usb_dev->tx_post_list, usb_buf, &usb_dev->tx_post_count, &usb_dev->tx_post_lock); #ifdef CONFIG_TX_TASKLET tasklet_schedule(&usb_dev->xmit_tasklet); #else complete(&bus_if->bustx_trgg); #endif ret = 0; flow_ctrl: spin_lock_irqsave(&usb_dev->tx_flow_lock, flags); if (usb_dev->tx_free_count < AICWF_USB_TX_LOW_WATER) { AICWFDBG(LOGDEBUG, "usb_dev->tx_free_count < AICWF_USB_TX_LOW_WATER:%d\r\n", usb_dev->tx_free_count); usb_dev->tbusy = true; aicwf_usb_tx_flowctrl(usb_dev->rwnx_hw, true); } spin_unlock_irqrestore(&usb_dev->tx_flow_lock, flags); return ret; } #endif static int aicwf_usb_bus_start(struct device *dev) { struct aicwf_bus *bus_if = dev_get_drvdata(dev); struct aic_usb_dev *usb_dev = bus_if->bus_priv.usb; if (usb_dev->state == USB_UP_ST) return 0; aicwf_usb_state_change(usb_dev, USB_UP_ST); usb_dev->rx_prepare_ready = false; aicwf_usb_rx_prepare(usb_dev); aicwf_usb_tx_prepare(usb_dev); #ifdef CONFIG_USB_MSG_IN_EP if(usb_dev->msg_in_pipe){ aicwf_usb_msg_rx_prepare(usb_dev); } #endif if(!usb_dev->rx_prepare_ready){ AICWFDBG(LOGERROR, "%s rx prepare fail\r\n", __func__); return -1; }else{ return 0; } } static void aicwf_usb_cancel_all_urbs_(struct aic_usb_dev *usb_dev) { struct aicwf_usb_buf *usb_buf, *tmp; unsigned long flags; if (usb_dev->msg_out_urb) usb_kill_urb(usb_dev->msg_out_urb); spin_lock_irqsave(&usb_dev->tx_post_lock, flags); list_for_each_entry_safe(usb_buf, tmp, &usb_dev->tx_post_list, list) { spin_unlock_irqrestore(&usb_dev->tx_post_lock, flags); if (!usb_buf->urb) { usb_err("bad usb_buf\n"); spin_lock_irqsave(&usb_dev->tx_post_lock, flags); break; } usb_kill_urb(usb_buf->urb); #if defined CONFIG_USB_NO_TRANS_DMA_MAP // free dma buf if needed if (usb_buf->data_buf) { #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)) usb_free_coherent(usb_buf->usbdev->udev, DATA_BUF_MAX, usb_buf->data_buf, usb_buf->data_dma_trans_addr); #else usb_buffer_free(usb_buf->usbdev->udev, DATA_BUF_MAX, usb_buf->data_buf, usb_buf->data_dma_trans_addr); #endif usb_buf->data_buf = NULL; usb_buf->data_dma_trans_addr = 0x0; } else { usb_err("bad usb dma buf\n"); spin_lock_irqsave(&usb_dev->tx_post_lock, flags); break; } #endif spin_lock_irqsave(&usb_dev->tx_post_lock, flags); } spin_unlock_irqrestore(&usb_dev->tx_post_lock, flags); usb_kill_anchored_urbs(&usb_dev->rx_submitted); #ifdef CONFIG_USB_MSG_IN_EP if(usb_dev->msg_in_pipe){ usb_kill_anchored_urbs(&usb_dev->msg_rx_submitted); } #endif } void aicwf_usb_cancel_all_urbs(struct aic_usb_dev *usb_dev){ aicwf_usb_cancel_all_urbs_(usb_dev); } static void aicwf_usb_bus_stop(struct device *dev) { struct aicwf_bus *bus_if = dev_get_drvdata(dev); struct aic_usb_dev *usb_dev = bus_if->bus_priv.usb; AICWFDBG(LOGINFO, "%s\r\n", __func__); if (usb_dev == NULL) return; if (usb_dev->state == USB_DOWN_ST) return; if(g_rwnx_plat && g_rwnx_plat->wait_disconnect_cb == true){ atomic_set(&aicwf_deinit_atomic, 1); up(&aicwf_deinit_sem); } aicwf_usb_state_change(usb_dev, USB_DOWN_ST); //aicwf_usb_cancel_all_urbs(usb_dev);//AIDEN } static void aicwf_usb_deinit(struct aic_usb_dev *usbdev) { cancel_work_sync(&usbdev->rx_urb_work); aicwf_usb_free_urb(&usbdev->rx_free_list, &usbdev->rx_free_lock); aicwf_usb_free_urb(&usbdev->tx_free_list, &usbdev->tx_free_lock); #ifdef CONFIG_USB_MSG_IN_EP if(usbdev->msg_in_pipe){ cancel_work_sync(&usbdev->msg_rx_urb_work); aicwf_usb_free_urb(&usbdev->msg_rx_free_list, &usbdev->msg_rx_free_lock); } #endif usb_free_urb(usbdev->msg_out_urb); } static void aicwf_usb_rx_urb_work(struct work_struct *work) { struct aic_usb_dev *usb_dev = container_of(work, struct aic_usb_dev, rx_urb_work); aicwf_usb_rx_submit_all_urb(usb_dev); } #ifdef CONFIG_USB_MSG_IN_EP static void aicwf_usb_msg_rx_urb_work(struct work_struct *work) { struct aic_usb_dev *usb_dev = container_of(work, struct aic_usb_dev, msg_rx_urb_work); aicwf_usb_msg_rx_submit_all_urb(usb_dev); } #endif static int aicwf_usb_init(struct aic_usb_dev *usb_dev) { int ret = 0; usb_dev->tbusy = false; usb_dev->state = USB_DOWN_ST; init_waitqueue_head(&usb_dev->msg_wait); init_usb_anchor(&usb_dev->rx_submitted); #ifdef CONFIG_USB_MSG_IN_EP if(usb_dev->msg_in_pipe){ init_usb_anchor(&usb_dev->msg_rx_submitted); } #endif spin_lock_init(&usb_dev->tx_free_lock); spin_lock_init(&usb_dev->tx_post_lock); spin_lock_init(&usb_dev->rx_free_lock); spin_lock_init(&usb_dev->tx_flow_lock); #ifdef CONFIG_USB_MSG_IN_EP if(usb_dev->msg_in_pipe){ spin_lock_init(&usb_dev->msg_rx_free_lock); } #endif INIT_LIST_HEAD(&usb_dev->rx_free_list); INIT_LIST_HEAD(&usb_dev->tx_free_list); INIT_LIST_HEAD(&usb_dev->tx_post_list); #ifdef CONFIG_USB_MSG_IN_EP if(usb_dev->msg_in_pipe){ INIT_LIST_HEAD(&usb_dev->msg_rx_free_list); } #endif atomic_set(&rx_urb_cnt, 0); usb_dev->tx_free_count = 0; usb_dev->tx_post_count = 0; ret = aicwf_usb_alloc_rx_urb(usb_dev); if (ret) { goto error; } ret = aicwf_usb_alloc_tx_urb(usb_dev); if (ret) { goto error; } #ifdef CONFIG_USB_MSG_IN_EP if(usb_dev->msg_in_pipe){ ret = aicwf_usb_alloc_msg_rx_urb(usb_dev); if (ret) { goto error; } } #endif usb_dev->msg_out_urb = usb_alloc_urb(0, GFP_ATOMIC); if (!usb_dev->msg_out_urb) { usb_err("usb_alloc_urb (msg out) failed\n"); ret = ENOMEM; goto error; } INIT_WORK(&usb_dev->rx_urb_work, aicwf_usb_rx_urb_work); #ifdef CONFIG_USB_MSG_IN_EP if(usb_dev->msg_in_pipe){ INIT_WORK(&usb_dev->msg_rx_urb_work, aicwf_usb_msg_rx_urb_work); } #endif return ret; error: usb_err("failed!\n"); aicwf_usb_deinit(usb_dev); return ret; } static int aicwf_parse_usb(struct aic_usb_dev *usb_dev, struct usb_interface *interface) { struct usb_interface_descriptor *interface_desc; struct usb_host_interface *host_interface; struct usb_endpoint_descriptor *endpoint; struct usb_device *usb = usb_dev->udev; int i, endpoints; u8 endpoint_num; int ret = 0; usb_dev->bulk_in_pipe = 0; usb_dev->bulk_out_pipe = 0; #ifdef CONFIG_USB_MSG_OUT_EP usb_dev->msg_out_pipe = 0; #endif #ifdef CONFIG_USB_MSG_IN_EP usb_dev->msg_in_pipe = 0; #endif host_interface = &interface->altsetting[0]; interface_desc = &host_interface->desc; endpoints = interface_desc->bNumEndpoints; AICWFDBG(LOGINFO, "%s endpoints = %d\n", __func__, endpoints); /* Check device configuration */ if (usb->descriptor.bNumConfigurations != 1) { usb_err("Number of configurations: %d not supported\n", usb->descriptor.bNumConfigurations); ret = -ENODEV; goto exit; } /* Check deviceclass */ #ifndef CONFIG_USB_BT if (usb->descriptor.bDeviceClass != 0x00) { usb_err("DeviceClass %d not supported\n", usb->descriptor.bDeviceClass); ret = -ENODEV; goto exit; } #endif /* Check interface number */ #ifdef CONFIG_USB_BT if (usb->actconfig->desc.bNumInterfaces != 1 && usb->actconfig->desc.bNumInterfaces != 3) #else if (usb->actconfig->desc.bNumInterfaces != 1) #endif { AICWFDBG(LOGERROR, "Number of interfaces: %d not supported\n", usb->actconfig->desc.bNumInterfaces); if(usb_dev->chipid == PRODUCT_ID_AIC8800DC){ AICWFDBG(LOGERROR, "AIC8800DC change to AIC8800DW\n"); usb_dev->chipid = PRODUCT_ID_AIC8800DW; }else if (usb_dev->chipid == PRODUCT_ID_AIC8800DW) { AICWFDBG(LOGINFO, "AIC8800DW\n"); } else if (usb_dev->chipid == PRODUCT_ID_AIC8800D80N) { AICWFDBG(LOGERROR, "AIC8800D80N change to AIC8800D80WN\n"); } else if (usb_dev->chipid == PRODUCT_ID_AIC8800DLN) { AICWFDBG(LOGERROR, "AIC8800DLN change to AIC8800DWN\n"); }else if(usb_dev->chipid == PRODUCT_ID_AIC8800D81X2 || usb_dev->chipid == PRODUCT_ID_AIC8800D89X2){ //TODO }else{ ret = -ENODEV; goto exit; } } if ((interface_desc->bInterfaceClass != USB_CLASS_VENDOR_SPEC) || (interface_desc->bInterfaceSubClass != 0xff) || (interface_desc->bInterfaceProtocol != 0xff)) { usb_err("non WLAN interface %d: 0x%x:0x%x:0x%x\n", interface_desc->bInterfaceNumber, interface_desc->bInterfaceClass, interface_desc->bInterfaceSubClass, interface_desc->bInterfaceProtocol); ret = -ENODEV; goto exit; } for (i = 0; i < endpoints; i++) { endpoint = &host_interface->endpoint[i].desc; endpoint_num = usb_endpoint_num(endpoint); if (usb_endpoint_dir_in(endpoint) && usb_endpoint_xfer_bulk(endpoint)) { if (!usb_dev->bulk_in_pipe) { usb_dev->bulk_in_pipe = usb_rcvbulkpipe(usb, endpoint_num); } #ifdef CONFIG_USB_MSG_IN_EP else if (!usb_dev->msg_in_pipe) { if(usb_dev->chipid != PRODUCT_ID_AIC8801){ usb_dev->msg_in_pipe = usb_rcvbulkpipe(usb, endpoint_num); } } #endif } if (usb_endpoint_dir_out(endpoint) && usb_endpoint_xfer_bulk(endpoint)) { if (!usb_dev->bulk_out_pipe) { usb_dev->bulk_out_pipe = usb_sndbulkpipe(usb, endpoint_num); } #ifdef CONFIG_USB_MSG_OUT_EP else if (!usb_dev->msg_out_pipe) { usb_dev->msg_out_pipe = usb_sndbulkpipe(usb, endpoint_num); } #endif } } if (usb_dev->bulk_in_pipe == 0) { usb_err("No RX (in) Bulk EP found\n"); ret = -ENODEV; goto exit; } if (usb_dev->bulk_out_pipe == 0) { usb_err("No TX (out) Bulk EP found\n"); ret = -ENODEV; goto exit; } #ifdef CONFIG_USB_MSG_OUT_EP if (usb_dev->msg_out_pipe == 0) { usb_err("No TX Msg (out) Bulk EP found\n"); } #endif #ifdef CONFIG_USB_MSG_IN_EP if(usb_dev->chipid != PRODUCT_ID_AIC8801){ if (usb_dev->msg_in_pipe == 0) { AICWFDBG(LOGINFO, "No RX Msg (in) Bulk EP found\n"); } } #endif switch (usb->speed) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 6, 0) case USB_SPEED_SUPER_PLUS: AICWFDBG(LOGINFO, "Aic super plus speed USB device detected\n"); break; #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0) case USB_SPEED_SUPER: AICWFDBG(LOGINFO, "Aic super speed USB device detected\n"); break; #endif case USB_SPEED_HIGH: AICWFDBG(LOGINFO, "Aic high speed USB device detected\n"); break; case USB_SPEED_FULL: AICWFDBG(LOGINFO, "Aic full speed USB device detected\n"); break; default: AICWFDBG(LOGINFO, "Aic unknown speed(%d) USB device detected\n", usb->speed); break; } exit: return ret; } static struct aicwf_bus_ops aicwf_usb_bus_ops = { .start = aicwf_usb_bus_start, .stop = aicwf_usb_bus_stop, .txdata = aicwf_usb_bus_txdata, .txmsg = aicwf_usb_bus_txmsg, }; #ifdef CONFIG_GPIO_WAKEUP static irqreturn_t rwnx_irq_handler(int irq, void *para) { unsigned long irqflags; spin_lock_irqsave(&irq_lock, irqflags); disable_irq_nosync(hostwake_irq_num); //do something printk("%s gpio irq trigger\r\n", __func__); spin_unlock_irqrestore(&irq_lock, irqflags); atomic_dec(&irq_count); return IRQ_HANDLED; } static int rwnx_register_hostwake_irq(struct device *dev) { int ret = 0; uint irq_flags = 0; spin_lock_init(&irq_lock); //Setting hostwake gpio for platform //For Rockchip #ifdef CONFIG_PLATFORM_ROCKCHIP hostwake_irq_num = rockchip_wifi_get_oob_irq(); printk("%s hostwake_irq_num:%d \r\n", __func__, hostwake_irq_num); irq_flags = (IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL | IORESOURCE_IRQ_SHAREABLE) & IRQF_TRIGGER_MASK; printk("%s irq_flags:%d \r\n", __func__, irq_flags); wakeup_enable = 1; #endif //CONFIG_PLATFORM_ROCKCHIP //For Allwinner #ifdef CONFIG_PLATFORM_ALLWINNER int irq_flags; #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0) hostwake_irq_num = sunxi_wlan_get_oob_irq(&irq_flags, &wakeup_enable); #else hostwake_irq_num = sunxi_wlan_get_oob_irq(); irq_flags = sunxi_wlan_get_oob_irq_flags(); wakeup_enable = 1; #endif #endif //CONFIG_PLATFORM_ALLWINNER ret = request_irq(hostwake_irq_num, rwnx_irq_handler, IRQF_TRIGGER_RISING | IRQF_NO_SUSPEND, "rwnx_irq_handler", NULL); enable_irq_wake(hostwake_irq_num); return ret; } static int rwnx_unregister_hostwake_irq(struct device *dev) { wakeup_enable = 0; printk("%s hostwake_irq_num:%d \r\n", __func__, hostwake_irq_num); disable_irq_wake(hostwake_irq_num); free_irq(hostwake_irq_num, NULL); return 0; } #endif //CONFIG_GPIO_WAKEUP static int aicwf_usb_chipmatch(struct aic_usb_dev *usb_dev, u16_l vid, u16_l pid){ if(pid == USB_PRODUCT_ID_AIC8801){ usb_dev->chipid = PRODUCT_ID_AIC8801; AICWFDBG(LOGINFO, "%s USE AIC8801\r\n", __func__); return 0; }else if(pid == USB_PRODUCT_ID_AIC8800DC || pid == USB_PRODUCT_ID_TENDA || pid == USB_PRODUCT_ID_TENDA_U2 || pid == USB_PRODUCT_ID_AIC8800FC_CUS1 || pid == USB_PRODUCT_ID_AIC8800FC_CUS2 || pid == USB_PRODUCT_ID_AIC8800FC_CUS3 || pid == USB_PRODUCT_ID_AIC8800FC_CUS4 || pid == USB_PRODUCT_ID_AIC8800FC_CUS5 || pid == USB_PRODUCT_ID_AIC8800FC_CUS6){ usb_dev->chipid = PRODUCT_ID_AIC8800DC; AICWFDBG(LOGINFO, "%s USE AIC8800DC\r\n", __func__); return 0; }else if(pid == USB_PRODUCT_ID_AIC8800DW || pid == USB_PRODUCT_ID_TENDA_TX1U_NANO){ usb_dev->chipid = PRODUCT_ID_AIC8800DW; AICWFDBG(LOGINFO, "%s USE AIC8800DW\r\n", __func__); return 0; }else if(pid == USB_PRODUCT_ID_AIC8800D81 || pid == USB_PRODUCT_ID_AIC8800D41 || pid == USB_PRODUCT_ID_TENDA_U11 || pid == USB_PRODUCT_ID_TENDA_U11_PRO || pid == USB_PRODUCT_ID_AIC8800M80_CUS0 || pid == USB_PRODUCT_ID_AIC8800M80_CUS1 || pid == USB_PRODUCT_ID_AIC8800M80_CUS2 || pid == USB_PRODUCT_ID_AIC8800M80_CUS3 || pid == USB_PRODUCT_ID_AIC8800M80_CUS4 || pid == USB_PRODUCT_ID_AIC8800M80_CUS5 || pid == USB_PRODUCT_ID_AIC8800M80_CUS6 || pid == USB_PRODUCT_ID_AIC8800M80_CUS7 || pid == USB_PRODUCT_ID_AIC8800M80_CUS8 || pid == USB_PRODUCT_ID_AIC8800D80_UGREEN || pid == USB_PRODUCT_ID_MERCURY){ usb_dev->chipid = PRODUCT_ID_AIC8800D81; aicwf_usb_rx_aggr = true; AICWFDBG(LOGINFO, "%s USE AIC8800D81\r\n", __func__); return 0; }else if(pid == USB_PRODUCT_ID_AIC8800D81X2){ usb_dev->chipid = PRODUCT_ID_AIC8800D81X2; aicwf_usb_max_pkt_size = AICWF_USB_MAX_AMSDU_PKT_SIZE; if (usb_dev->udev->speed <= USB_SPEED_HIGH) { aicwf_usb_rx_aggr = true; } else { #ifdef CONFIG_PLATFORM_HI aicwf_usb_rx_aggr = true; #else aicwf_usb_rx_aggr = false; #endif } AICWFDBG(LOGINFO, "%s USE AIC8800D81X2\r\n", __func__); return 0; }else if(pid == USB_PRODUCT_ID_AIC8800D89X2){ usb_dev->chipid = PRODUCT_ID_AIC8800D89X2; aicwf_usb_max_pkt_size = AICWF_USB_MAX_AMSDU_PKT_SIZE; if (usb_dev->udev->speed <= USB_SPEED_HIGH) { aicwf_usb_rx_aggr = true; } else { #ifdef CONFIG_PLATFORM_HI aicwf_usb_rx_aggr = true; #else aicwf_usb_rx_aggr = false; #endif } AICWFDBG(LOGINFO, "%s USE AIC8800D89X2\r\n", __func__); return 0; } else if ((pid == USB_PRODUCT_ID_AIC8800D80N) || (pid == USB_PRODUCT_ID_AIC8800D80LN) || (pid == USB_PRODUCT_ID_AIC8800D80WN) || (pid == USB_PRODUCT_ID_AIC8800D40N) || (pid == USB_PRODUCT_ID_AIC8800D40LN) || (pid == USB_PRODUCT_ID_AIC8800D40WN)) { usb_dev->chipid = PRODUCT_ID_AIC8800D80N; aicwf_usb_rx_aggr = true; AICWFDBG(LOGINFO, "%s USE AIC8800D80N\r\n", __func__); return 0; } else if ((pid == USB_PRODUCT_ID_AIC8800DLN) || (pid == USB_PRODUCT_ID_AIC8800DWN)) { usb_dev->chipid = PRODUCT_ID_AIC8800DLN; aicwf_usb_rx_aggr = true; AICWFDBG(LOGINFO, "%s USE AIC8800DLN\r\n", __func__); return 0; } else{ return -1; } } static int aicwf_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) { int ret = 0; struct usb_device *usb = interface_to_usbdev(intf); struct aicwf_bus *bus_if = NULL; struct device *dev = NULL; struct aicwf_rx_priv* rx_priv = NULL; struct aic_usb_dev *usb_dev = NULL; #ifdef CONFIG_USB_TX_AGGR struct aicwf_tx_priv *tx_priv = NULL; #endif usb_dev = kzalloc(sizeof(struct aic_usb_dev), GFP_ATOMIC); AICWFDBG(LOGDEBUG, "%s usb_dev:%d usb_tx_buf:%d usb_rx_buf:%d\r\n", __func__, (int)sizeof(struct aic_usb_dev), (int)sizeof(struct aicwf_usb_buf) * AICWF_USB_TX_URBS, (int)sizeof(struct aicwf_usb_buf) * AICWF_USB_RX_URBS); if (!usb_dev) { AICWFDBG(LOGERROR, "%s usb_dev kzalloc fail\r\n", __func__); return -ENOMEM; } usb_dev->usb_tx_buf = vmalloc(sizeof(struct aicwf_usb_buf) * AICWF_USB_TX_URBS); usb_dev->usb_rx_buf = vmalloc(sizeof(struct aicwf_usb_buf) * AICWF_USB_RX_URBS); if(!usb_dev->usb_tx_buf || !usb_dev->usb_rx_buf){ if(usb_dev->usb_tx_buf){ vfree(usb_dev); } if(usb_dev->usb_tx_buf){ vfree(usb_dev); } if(usb_dev){ kfree(usb_dev); } AICWFDBG(LOGERROR, "%s usb_tx_buf or usb_rx_buf vmalloc fail\r\n", __func__); return -ENOMEM; } memset(usb_dev->usb_tx_buf, 0, (int)(sizeof(struct aicwf_usb_buf) * AICWF_USB_TX_URBS)); memset(usb_dev->usb_rx_buf, 0, (int)(sizeof(struct aicwf_usb_buf) * AICWF_USB_RX_URBS)); usb_dev->udev = usb; usb_dev->dev = &usb->dev; usb_set_intfdata(intf, usb_dev); ret = aicwf_usb_chipmatch(usb_dev, id->idVendor, id->idProduct); if (ret < 0) { AICWFDBG(LOGERROR, "%s pid:0x%04X vid:0x%04X unsupport\n", __func__, id->idVendor, id->idProduct); goto out_free_bus; } ret = aicwf_parse_usb(usb_dev, intf); if (ret) { AICWFDBG(LOGERROR, "aicwf_parse_usb err %d\n", ret); goto out_free; } ret = aicwf_usb_init(usb_dev); if (ret) { AICWFDBG(LOGERROR, "aicwf_usb_init err %d\n", ret); goto out_free; } bus_if = kzalloc(sizeof(struct aicwf_bus), GFP_ATOMIC); if (!bus_if) { ret = -ENOMEM; goto out_free_usb; } dev = usb_dev->dev; bus_if->dev = dev; usb_dev->bus_if = bus_if; bus_if->bus_priv.usb = usb_dev; dev_set_drvdata(dev, bus_if); bus_if->ops = &aicwf_usb_bus_ops; rx_priv = aicwf_rx_init(usb_dev); if(!rx_priv) { AICWFDBG(LOGERROR, "rx init failed\n"); ret = -1; goto out_free_bus; } usb_dev->rx_priv = rx_priv; #ifdef CONFIG_USB_TX_AGGR tx_priv = aicwf_tx_init(usb_dev); if(!tx_priv) { usb_err("tx init fail\n"); goto out_free_bus; } usb_dev->tx_priv = tx_priv; aicwf_frame_queue_init(&tx_priv->txq, 8, TXQLEN); spin_lock_init(&tx_priv->txqlock); spin_lock_init(&tx_priv->txdlock); #endif ret = aicwf_bus_init(0, dev); if (ret < 0) { AICWFDBG(LOGERROR, "aicwf_bus_init err %d\n", ret); goto out_free_bus; } ret = aicwf_bus_start(bus_if); if (ret < 0) { AICWFDBG(LOGERROR, "aicwf_bus_start err %d\n", ret); goto out_free_bus; } ret = aicwf_rwnx_usb_platform_init(usb_dev); if (ret < 0) { AICWFDBG(LOGERROR, "aicwf_rwnx_usb_platform_init err %d\n", ret); goto out_free_bus; } aicwf_hostif_ready(); #ifdef CONFIG_GPIO_WAKEUP rwnx_register_hostwake_irq(usb_dev->dev); #endif return 0; out_free_bus: aicwf_bus_deinit(dev); kfree(bus_if); out_free_usb: aicwf_usb_deinit(usb_dev); out_free: usb_err("failed with errno %d\n", ret); vfree(usb_dev->usb_tx_buf); vfree(usb_dev->usb_rx_buf); kfree(usb_dev); usb_set_intfdata(intf, NULL); return ret; } static void aicwf_usb_disconnect(struct usb_interface *intf) { struct aic_usb_dev *usb_dev = (struct aic_usb_dev *) usb_get_intfdata(intf); AICWFDBG(LOGINFO, "%s Enter\r\n", __func__); if(g_rwnx_plat->wait_disconnect_cb == false){ atomic_set(&aicwf_deinit_atomic, 0); down(&aicwf_deinit_sem); } if (!usb_dev){ AICWFDBG(LOGERROR, "%s usb_dev is null \r\n", __func__); return; } #if 0 if(timer_pending(&usb_dev->rwnx_hw->p2p_alive_timer) && usb_dev->rwnx_hw->is_p2p_alive == 1){ printk("%s del timer rwnx_hw->p2p_alive_timer \r\n", __func__); rwnx_del_timer(&usb_dev->rwnx_hw->p2p_alive_timer); } #endif aicwf_bus_deinit(usb_dev->dev); aicwf_usb_deinit(usb_dev); #ifdef CONFIG_GPIO_WAKEUP rwnx_unregister_hostwake_irq(usb_dev->dev); #endif kfree(usb_dev->bus_if); vfree(usb_dev->usb_tx_buf); vfree(usb_dev->usb_rx_buf); kfree(usb_dev); AICWFDBG(LOGINFO, "%s exit\r\n", __func__); up(&aicwf_deinit_sem); atomic_set(&aicwf_deinit_atomic, 1); } static int aicwf_usb_suspend(struct usb_interface *intf, pm_message_t state) { struct aic_usb_dev *usb_dev = (struct aic_usb_dev *) usb_get_intfdata(intf); struct rwnx_vif *rwnx_vif, *tmp; AICWFDBG(LOGINFO, "%s enter\r\n", __func__); #ifdef CONFIG_WOWLAN #ifndef ANDROID_PLATFORM rwnx_send_dummy_reboot(usb_dev->rwnx_hw); #endif #endif list_for_each_entry_safe(rwnx_vif, tmp, &usb_dev->rwnx_hw->vifs, list) { if (rwnx_vif->ndev){ netif_tx_stop_all_queues(rwnx_vif->ndev); mdelay(1000); } } aicwf_usb_state_change(usb_dev, USB_SLEEP_ST); aicwf_bus_stop(usb_dev->bus_if); list_for_each_entry_safe(rwnx_vif, tmp, &usb_dev->rwnx_hw->vifs, list) { if (rwnx_vif->ndev) netif_device_detach(rwnx_vif->ndev); } return 0; } static int aicwf_usb_resume(struct usb_interface *intf) { struct aic_usb_dev *usb_dev = (struct aic_usb_dev *) usb_get_intfdata(intf); struct rwnx_vif *rwnx_vif, *tmp; AICWFDBG(LOGINFO, "%s enter\r\n", __func__); list_for_each_entry_safe(rwnx_vif, tmp, &usb_dev->rwnx_hw->vifs, list) { if (rwnx_vif->ndev) netif_device_attach(rwnx_vif->ndev); } if (usb_dev->state != USB_UP_ST){ aicwf_bus_start(usb_dev->bus_if); g_rwnx_plat->wait_disconnect_cb = false; } list_for_each_entry_safe(rwnx_vif, tmp, &usb_dev->rwnx_hw->vifs, list) { if (rwnx_vif->ndev){ netif_tx_wake_all_queues(rwnx_vif->ndev); } } return 0; } static int aicwf_usb_reset_resume(struct usb_interface *intf) { return aicwf_usb_resume(intf); } static struct usb_device_id aicwf_usb_id_table[] = { #ifndef CONFIG_USB_BT {USB_DEVICE(USB_VENDOR_ID_AIC, USB_PRODUCT_ID_AIC8800)}, #else {USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_AIC, USB_PRODUCT_ID_AIC8801, 0xff, 0xff, 0xff)}, {USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_AIC, USB_PRODUCT_ID_AIC8800D81, 0xff, 0xff, 0xff)}, {USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_AIC, USB_PRODUCT_ID_AIC8800D41, 0xff, 0xff, 0xff)}, {USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_AIC, USB_PRODUCT_ID_AIC8800DC, 0xff, 0xff, 0xff)}, {USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_TENDA_V2, USB_PRODUCT_ID_TENDA_TX1U_NANO, 0xff, 0xff, 0xff)}, {USB_DEVICE(USB_VENDOR_ID_AIC, USB_PRODUCT_ID_AIC8800DW)}, {USB_DEVICE(USB_VENDOR_ID_AIC, USB_PRODUCT_ID_AIC8800M80_CUS1)}, {USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_AIC_V2, USB_PRODUCT_ID_AIC8800D81X2, 0xff, 0xff, 0xff)}, {USB_DEVICE(USB_VENDOR_ID_AIC_V2, USB_PRODUCT_ID_AIC8800D89X2)}, {USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_AIC_V2, USB_PRODUCT_ID_AIC8800D80N, 0xff, 0xff, 0xff)}, {USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_AIC_V2, USB_PRODUCT_ID_AIC8800D80LN, 0xff, 0xff, 0xff)}, {USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_AIC_V2, USB_PRODUCT_ID_AIC8800D80WN, 0xff, 0xff, 0xff)}, {USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_AIC_V2, USB_PRODUCT_ID_AIC8800D40N, 0xff, 0xff, 0xff)}, {USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_AIC_V2, USB_PRODUCT_ID_AIC8800D40LN, 0xff, 0xff, 0xff)}, {USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_AIC_V2, USB_PRODUCT_ID_AIC8800D40WN, 0xff, 0xff, 0xff)}, {USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_AIC_V2, USB_PRODUCT_ID_AIC8800DLN, 0xff, 0xff, 0xff)}, {USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_AIC_V2, USB_PRODUCT_ID_AIC8800DWN, 0xff, 0xff, 0xff)}, {USB_DEVICE(USB_VENDOR_ID_TENDA, USB_PRODUCT_ID_TENDA)}, {USB_DEVICE(USB_VENDOR_ID_TENDA, USB_PRODUCT_ID_TENDA_U2)}, {USB_DEVICE(USB_VENDOR_ID_TENDA, USB_PRODUCT_ID_TENDA_U11)}, {USB_DEVICE(USB_VENDOR_ID_TENDA, USB_PRODUCT_ID_TENDA_U11_PRO)}, {USB_DEVICE(USB_VENDOR_ID_AIC_V2, USB_PRODUCT_ID_AIC8800D81)}, {USB_DEVICE(USB_VENDOR_ID_AIC_V2, USB_PRODUCT_ID_AIC8800FC_CUS1)}, {USB_DEVICE(USB_VENDOR_ID_AIC_V2, USB_PRODUCT_ID_AIC8800FC_CUS2)}, {USB_DEVICE(USB_VENDOR_ID_AIC_V2, USB_PRODUCT_ID_AIC8800FC_CUS3)}, {USB_DEVICE(USB_VENDOR_ID_AIC_V2, USB_PRODUCT_ID_AIC8800FC_CUS4)}, {USB_DEVICE(USB_VENDOR_ID_AIC_V2, USB_PRODUCT_ID_AIC8800FC_CUS5)}, {USB_DEVICE(USB_VENDOR_ID_AIC_V2, USB_PRODUCT_ID_AIC8800FC_CUS6)}, {USB_DEVICE(USB_VENDOR_ID_AIC_V2, USB_PRODUCT_ID_AIC8800M80_CUS0)}, {USB_DEVICE(USB_VENDOR_ID_AIC_V2, USB_PRODUCT_ID_AIC8800M80_CUS1)}, {USB_DEVICE(USB_VENDOR_ID_AIC_V2, USB_PRODUCT_ID_AIC8800M80_CUS2)}, {USB_DEVICE(USB_VENDOR_ID_AIC_V2, USB_PRODUCT_ID_AIC8800M80_CUS3)}, {USB_DEVICE(USB_VENDOR_ID_AIC_V2, USB_PRODUCT_ID_AIC8800M80_CUS4)}, {USB_DEVICE(USB_VENDOR_ID_AIC_V2, USB_PRODUCT_ID_AIC8800M80_CUS5)}, {USB_DEVICE(USB_VENDOR_ID_AIC_V2, USB_PRODUCT_ID_AIC8800M80_CUS6)}, {USB_DEVICE(USB_VENDOR_ID_AIC_V2, USB_PRODUCT_ID_AIC8800M80_CUS7)}, {USB_DEVICE(USB_VENDOR_ID_AIC_V2, USB_PRODUCT_ID_AIC8800M80_CUS8)}, {USB_DEVICE(USB_VENDOR_ID_AIC_V2, USB_PRODUCT_ID_AIC8800D80_UGREEN)}, {USB_DEVICE(USB_VENDOR_ID_TP, USB_PRODUCT_ID_MERCURY)}, #endif {} }; MODULE_DEVICE_TABLE(usb, aicwf_usb_id_table); static struct usb_driver aicwf_usbdrvr = { .name = KBUILD_MODNAME, .probe = aicwf_usb_probe, .disconnect = aicwf_usb_disconnect, .id_table = aicwf_usb_id_table, .suspend = aicwf_usb_suspend, .resume = aicwf_usb_resume, .reset_resume = aicwf_usb_reset_resume, #ifdef ANDROID_PLATFORM .supports_autosuspend = 1, #else .supports_autosuspend = 0, #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0) .disable_hub_initiated_lpm = 1, #endif }; void aicwf_usb_register(void) { if (usb_register(&aicwf_usbdrvr) < 0) { usb_err("usb_register failed\n"); } } void aicwf_usb_exit(void) { int retry = 5; AICWFDBG(LOGINFO, "%s Enter\r\n", __func__); AICWFDBG(LOGDEBUG, "%s in_interrupt:%d in_softirq:%d in_atomic:%d\r\n", __func__, (int)in_interrupt(), (int)in_softirq(), (int)in_atomic()); do{ AICWFDBG(LOGINFO, "aicwf_deinit_atomic is busy. waiting for 500ms retry:%d \r\n", retry); mdelay(500); retry--; if(retry == 0){ break; } }while(atomic_read(&aicwf_deinit_atomic) == 0); atomic_set(&aicwf_deinit_atomic, 0); if(down_timeout(&aicwf_deinit_sem, msecs_to_jiffies(SEM_TIMOUT)) != 0){ AICWFDBG(LOGERROR, "%s semaphore waiting timeout\r\n", __func__); } if(g_rwnx_plat){ g_rwnx_plat->wait_disconnect_cb = false; } if(!g_rwnx_plat || !g_rwnx_plat->enabled){ AICWFDBG(LOGINFO, "g_rwnx_plat is not ready. waiting for 500ms\r\n"); mdelay(500); } #if 1 if(g_rwnx_plat && g_rwnx_plat->enabled){ rwnx_platform_deinit(g_rwnx_plat->usbdev->rwnx_hw); } #endif up(&aicwf_deinit_sem); atomic_set(&aicwf_deinit_atomic, 1); AICWFDBG(LOGINFO, "%s usb_deregister \r\n", __func__); usb_deregister(&aicwf_usbdrvr); //mdelay(500); if(g_rwnx_plat){ kfree(g_rwnx_plat); } AICWFDBG(LOGINFO, "%s exit\r\n", __func__); }