//todo: static s32 rtl8188es_dequeue_writeport(PADAPTER padapter, u8 *freePage) { struct mlme_priv *pmlmepriv = &padapter->mlmepriv; struct xmit_priv *pxmitpriv = &padapter->xmitpriv; struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter); struct xmit_buf *pxmitbuf; PADAPTER pri_padapter = padapter; s32 ret = 0; #ifdef CONFIG_CONCURRENT_MODE if (padapter->adapter_type > 0) pri_padapter = padapter->pbuddy_adapter; if(rtw_buddy_adapter_up(padapter)) ret = check_buddy_fwstate( padapter, _FW_UNDER_SURVEY); #endif ret = ret || check_fwstate(pmlmepriv, _FW_UNDER_SURVEY); if (_TRUE == ret) pxmitbuf = dequeue_pending_xmitbuf_under_survey(pxmitpriv); else pxmitbuf = dequeue_pending_xmitbuf(pxmitpriv); if (pxmitbuf == NULL) return _TRUE; query_free_page: // check if hardware tx fifo page is enough if( _FALSE == rtl8188es_query_tx_freepage(pri_padapter, pxmitbuf)) { rtw_msleep_os(1); goto query_free_page; } if ((padapter->bSurpriseRemoved == _TRUE) || (padapter->bDriverStopped == _TRUE) #ifdef CONFIG_CONCURRENT_MODE ||((padapter->pbuddy_adapter) && ((padapter->pbuddy_adapter->bSurpriseRemoved) ||(padapter->pbuddy_adapter->bDriverStopped))) #endif ){ RT_TRACE(_module_hal_xmit_c_, _drv_notice_, ("%s: bSurpriseRemoved(wirte port)\n", __FUNCTION__)); goto free_xmitbuf; } rtw_write_port(padapter, ffaddr2deviceId(pdvobjpriv, pxmitbuf->ff_hwaddr), pxmitbuf->len, (u8 *)pxmitbuf); free_xmitbuf: //rtw_free_xmitframe(pxmitpriv, pframe); //pxmitbuf->priv_data = NULL; rtw_free_xmitbuf(pxmitpriv, pxmitbuf); #ifdef CONFIG_SDIO_TX_TASKLET tasklet_hi_schedule(&pxmitpriv->xmit_tasklet); #endif return _FAIL; }
/* * Return * _TRUE dump packet directly * _FALSE enqueue packet */ static s32 pre_xmitframe(_adapter *padapter, struct xmit_frame *pxmitframe) { _irqL irqL; s32 res; struct xmit_buf *pxmitbuf = NULL; struct xmit_priv *pxmitpriv = &padapter->xmitpriv; struct pkt_attrib *pattrib = &pxmitframe->attrib; struct mlme_priv *pmlmepriv = &padapter->mlmepriv; _enter_critical_bh(&pxmitpriv->lock, &irqL); //DBG_8192C("==> %s \n",__FUNCTION__); if (rtw_txframes_sta_ac_pending(padapter, pattrib) > 0) { //DBG_8192C("enqueue AC(%d)\n",pattrib->priority); goto enqueue; } if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY|_FW_UNDER_LINKING) == _TRUE) goto enqueue; #ifdef CONFIG_CONCURRENT_MODE if (check_buddy_fwstate(padapter, _FW_UNDER_SURVEY|_FW_UNDER_LINKING) == _TRUE) goto enqueue; #endif pxmitbuf = rtw_alloc_xmitbuf(pxmitpriv); if (pxmitbuf == NULL) goto enqueue; _exit_critical_bh(&pxmitpriv->lock, &irqL); pxmitframe->pxmitbuf = pxmitbuf; pxmitframe->buf_addr = pxmitbuf->pbuf; pxmitbuf->priv_data = pxmitframe; if (xmitframe_direct(padapter, pxmitframe) != _SUCCESS) { rtw_free_xmitbuf(pxmitpriv, pxmitbuf); rtw_free_xmitframe(pxmitpriv, pxmitframe); } return _TRUE; enqueue: res = rtw_xmitframe_enqueue(padapter, pxmitframe); _exit_critical_bh(&pxmitpriv->lock, &irqL); if (res != _SUCCESS) { RT_TRACE(_module_xmit_osdep_c_, _drv_err_, ("pre_xmitframe: enqueue xmitframe fail\n")); rtw_free_xmitframe(pxmitpriv, pxmitframe); pxmitpriv->tx_drop++; return _TRUE; } return _FALSE; }
/* * Return * true dump packet directly * false enqueue packet */ s32 rtw_hal_xmit(struct adapter *adapt, struct xmit_frame *pxmitframe) { s32 res; struct xmit_buf *pxmitbuf = NULL; struct xmit_priv *pxmitpriv = &adapt->xmitpriv; struct pkt_attrib *pattrib = &pxmitframe->attrib; struct mlme_priv *pmlmepriv = &adapt->mlmepriv; spin_lock_bh(&pxmitpriv->lock); if (rtw_txframes_sta_ac_pending(adapt, pattrib) > 0) goto enqueue; if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY|_FW_UNDER_LINKING) == true) goto enqueue; pxmitbuf = rtw_alloc_xmitbuf(pxmitpriv); if (!pxmitbuf) goto enqueue; spin_unlock_bh(&pxmitpriv->lock); pxmitframe->pxmitbuf = pxmitbuf; pxmitframe->buf_addr = pxmitbuf->pbuf; pxmitbuf->priv_data = pxmitframe; res = rtw_xmitframe_coalesce(adapt, pxmitframe->pkt, pxmitframe); if (res == _SUCCESS) { rtw_dump_xframe(adapt, pxmitframe); } else { DBG_88E("==> %s xmitframe_coalsece failed\n", __func__); rtw_free_xmitbuf(pxmitpriv, pxmitbuf); rtw_free_xmitframe(pxmitpriv, pxmitframe); } return true; enqueue: res = rtw_xmitframe_enqueue(adapt, pxmitframe); spin_unlock_bh(&pxmitpriv->lock); if (res != _SUCCESS) { RT_TRACE(_module_xmit_osdep_c_, _drv_err_, ("pre_xmitframe: enqueue xmitframe fail\n")); rtw_free_xmitframe(pxmitpriv, pxmitframe); /* Trick, make the statistics correct */ pxmitpriv->tx_pkts--; pxmitpriv->tx_drop++; return true; } return false; }
/* * Return * true dump packet directly * false enqueue packet */ static s32 pre_xmitframe(struct adapter *padapter, struct xmit_frame *pxmitframe) { unsigned long irqL; s32 res; struct xmit_buf *pxmitbuf = NULL; struct xmit_priv *pxmitpriv = &padapter->xmitpriv; struct pkt_attrib *pattrib = &pxmitframe->attrib; struct mlme_priv *pmlmepriv = &padapter->mlmepriv; _enter_critical_bh(&pxmitpriv->lock, &irqL); if (rtw_txframes_sta_ac_pending(padapter, pattrib) > 0) { goto enqueue; } if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY|_FW_UNDER_LINKING) == true) goto enqueue; pxmitbuf = rtw_alloc_xmitbuf(pxmitpriv); if (pxmitbuf == NULL) goto enqueue; _exit_critical_bh(&pxmitpriv->lock, &irqL); pxmitframe->pxmitbuf = pxmitbuf; pxmitframe->buf_addr = pxmitbuf->pbuf; pxmitbuf->priv_data = pxmitframe; if (xmitframe_direct(padapter, pxmitframe) != _SUCCESS) { rtw_free_xmitbuf(pxmitpriv, pxmitbuf); rtw_free_xmitframe(pxmitpriv, pxmitframe); } return true; enqueue: res = rtw_xmitframe_enqueue(padapter, pxmitframe); _exit_critical_bh(&pxmitpriv->lock, &irqL); if (res != _SUCCESS) { RT_TRACE(_module_xmit_osdep_c_, _drv_err_, ("pre_xmitframe: enqueue xmitframe fail\n")); rtw_free_xmitframe(pxmitpriv, pxmitframe); /* Trick, make the statistics correct */ pxmitpriv->tx_pkts--; pxmitpriv->tx_drop++; return true; } return false; }
s32 rtl8195as_dequeue_writeport(PADAPTER padapter) { struct xmit_buf *pxmitbuf; _func_enter_; pxmitbuf = rtw_dequeue_xmitbuf(padapter); if(pxmitbuf == NULL) return _TRUE; rtw_write_port(padapter, WLAN_TX_FIFO_DEVICE_ID, pxmitbuf->pkt_len, pxmitbuf->pdata); rtw_free_xmitbuf(padapter, pxmitbuf); _func_exit_; return _FAIL; }
/* * Return * _TRUE dump packet directly * _FALSE enqueue packet */ static s32 pre_xmitframe(_adapter *padapter, struct xmit_frame *pxmitframe) { _irqL irqL; s32 res; struct xmit_buf *pxmitbuf = NULL; struct xmit_priv *pxmitpriv = &padapter->xmitpriv; struct pkt_attrib *pattrib = &pxmitframe->attrib; struct mlme_priv *pmlmepriv = &padapter->mlmepriv; _enter_critical_bh(&pxmitpriv->lock, &irqL); if ( (rtw_txframes_sta_ac_pending(padapter, pattrib) > 0) || (check_nic_enough_desc(padapter, pattrib) == _FALSE)) goto enqueue; if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) == _TRUE) goto enqueue; pxmitbuf = rtw_alloc_xmitbuf(pxmitpriv); if (pxmitbuf == NULL) goto enqueue; _exit_critical_bh(&pxmitpriv->lock, &irqL); pxmitframe->pxmitbuf = pxmitbuf; pxmitframe->buf_addr = pxmitbuf->pbuf; pxmitbuf->priv_data = pxmitframe; if (xmitframe_direct(padapter, pxmitframe) != _SUCCESS) { rtw_free_xmitbuf(pxmitpriv, pxmitbuf); rtw_free_xmitframe(pxmitpriv, pxmitframe); } return _TRUE; enqueue: res = rtw_xmitframe_enqueue(padapter, pxmitframe); _exit_critical_bh(&pxmitpriv->lock, &irqL); if (res != _SUCCESS) { RT_TRACE(_module_xmit_osdep_c_, _drv_err_, ("pre_xmitframe: enqueue xmitframe fail\n")); rtw_free_xmitframe(pxmitpriv, pxmitframe); // Trick, make the statistics correct pxmitpriv->tx_pkts--; pxmitpriv->tx_drop++; return _TRUE; } return _FALSE; }
s32 rtl8723bs_mgnt_xmit(PADAPTER padapter, struct xmit_frame *pmgntframe) { s32 ret = _SUCCESS; struct pkt_attrib *pattrib; struct xmit_buf *pxmitbuf; struct xmit_priv *pxmitpriv = &padapter->xmitpriv; struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter); u8 *pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; u8 txdesc_size = TXDESC_SIZE; RT_TRACE(_module_hal_xmit_c_, _drv_info_, ("+%s\n", __FUNCTION__)); pattrib = &pmgntframe->attrib; pxmitbuf = pmgntframe->pxmitbuf; rtl8723b_update_txdesc(pmgntframe, pmgntframe->buf_addr); pxmitbuf->len = txdesc_size + pattrib->last_txcmdsz; //pmgntframe->pg_num = (pxmitbuf->len + 127)/128; // 128 is tx page size pxmitbuf->pg_num = (pxmitbuf->len + 127)/128; // 128 is tx page size pxmitbuf->ptail = pmgntframe->buf_addr + pxmitbuf->len; pxmitbuf->ff_hwaddr = rtw_get_ff_hwaddr(pmgntframe); rtw_count_tx_stats(padapter, pmgntframe, pattrib->last_txcmdsz); rtw_free_xmitframe(pxmitpriv, pmgntframe); pxmitbuf->priv_data = NULL; if(GetFrameSubType(pframe)==WIFI_BEACON) //dump beacon directly { rtw_write_port(padapter, pdvobjpriv->Queue2Pipe[pxmitbuf->ff_hwaddr], pxmitbuf->len, (u8 *)pxmitbuf); rtw_free_xmitbuf(pxmitpriv, pxmitbuf); } else { enqueue_pending_xmitbuf(pxmitpriv, pxmitbuf); } if (ret != _SUCCESS) rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_UNKNOWN); return ret; }
void rtl8723bs_free_xmit_priv(PADAPTER padapter) { PHAL_DATA_TYPE phal; struct xmit_priv *pxmitpriv; struct xmit_buf *pxmitbuf; _queue *pqueue; _list *plist, *phead; _list tmplist; _irqL irql; phal = GET_HAL_DATA(padapter); pxmitpriv = &padapter->xmitpriv; pqueue = &pxmitpriv->pending_xmitbuf_queue; phead = get_list_head(pqueue); _rtw_init_listhead(&tmplist); _enter_critical_bh(&pqueue->lock, &irql); if (_rtw_queue_empty(pqueue) == _FALSE) { // Insert tmplist to end of queue, and delete phead // then tmplist become head of queue. rtw_list_insert_tail(&tmplist, phead); rtw_list_delete(phead); } _exit_critical_bh(&pqueue->lock, &irql); phead = &tmplist; while (rtw_is_list_empty(phead) == _FALSE) { plist = get_next(phead); rtw_list_delete(plist); pxmitbuf = LIST_CONTAINOR(plist, struct xmit_buf, list); rtw_free_xmitframe(pxmitpriv, (struct xmit_frame*)pxmitbuf->priv_data); pxmitbuf->priv_data = NULL; rtw_free_xmitbuf(pxmitpriv, pxmitbuf); } _rtw_spinlock_free(&phal->SdioTxFIFOFreePageLock); }
void rtl8723bs_free_xmit_priv(PADAPTER padapter) { PHAL_DATA_TYPE phal; struct xmit_priv *pxmitpriv; struct xmit_buf *pxmitbuf; _queue *pqueue; _list *plist, *phead; _list tmplist; _irqL irql; phal = GET_HAL_DATA(padapter); pxmitpriv = &padapter->xmitpriv; pqueue = &pxmitpriv->pending_xmitbuf_queue; phead = get_list_head(pqueue); INIT_LIST_HEAD(&tmplist); spin_lock_bh(&pqueue->lock); if (!list_empty(&pqueue->queue)) { // Insert tmplist to end of queue, and delete phead // then tmplist become head of queue. list_add_tail(&tmplist, phead); list_del_init(phead); } spin_unlock_bh(&pqueue->lock); phead = &tmplist; while (list_empty(phead) == false) { plist = get_next(phead); list_del_init(plist); pxmitbuf = LIST_CONTAINOR(plist, struct xmit_buf, list); rtw_free_xmitframe(pxmitpriv, (struct xmit_frame*)pxmitbuf->priv_data); pxmitbuf->priv_data = NULL; rtw_free_xmitbuf(pxmitpriv, pxmitbuf); } }
void rtl8723bs_free_xmit_priv(struct adapter *padapter) { struct hal_com_data *phal; struct xmit_priv *pxmitpriv; struct xmit_buf *pxmitbuf; struct __queue *pqueue; struct list_head *plist, *phead; struct list_head tmplist; phal = GET_HAL_DATA(padapter); pxmitpriv = &padapter->xmitpriv; pqueue = &pxmitpriv->pending_xmitbuf_queue; phead = get_list_head(pqueue); INIT_LIST_HEAD(&tmplist); critical_enter_bh(&pqueue->lock); if (!list_empty(&pqueue->queue)) { /* Insert tmplist to end of queue, and delete phead */ /* then tmplist become head of queue. */ list_add_tail(&tmplist, phead); list_del_init(phead); } critical_exit_bh(&pqueue->lock); phead = &tmplist; while (list_empty(phead) == false) { plist = get_next(phead); list_del_init(plist); pxmitbuf = LIST_CONTAINOR(plist, struct xmit_buf, list); rtw_free_xmitframe(pxmitpriv, (struct xmit_frame*)pxmitbuf->priv_data); pxmitbuf->priv_data = NULL; rtw_free_xmitbuf(pxmitpriv, pxmitbuf); } }
void rtw_dump_xframe(_adapter *padapter, struct xmit_frame *pxmitframe) { _irqL irqL; int t, sz, w_sz, pull=0; //u8 *mem_addr; u32 ff_hwaddr; struct xmit_buf *pxmitbuf = pxmitframe->pxmitbuf; struct pkt_attrib *pattrib = &pxmitframe->attrib; struct xmit_priv *pxmitpriv = &padapter->xmitpriv; struct dvobj_priv *pdvobjpriv = &padapter->dvobjpriv; struct security_priv *psecuritypriv = &padapter->securitypriv; struct tx_desc *ptxdesc; if ((pxmitframe->frame_tag == DATA_FRAMETAG) && (pxmitframe->attrib.ether_type != 0x0806) && (pxmitframe->attrib.ether_type != 0x888e) && (pxmitframe->attrib.dhcp_pkt != 1)) { rtw_issue_addbareq_cmd(padapter, pxmitframe); } //mem_addr = pxmitframe->buf_addr; RT_TRACE(_module_rtl871x_xmit_c_,_drv_info_,("rtw_dump_xframe()\n")); for (t = 0; t < pattrib->nr_frags; t++) { if (t != (pattrib->nr_frags - 1)) { RT_TRACE(_module_rtl871x_xmit_c_,_drv_err_,("pattrib->nr_frags=%d\n", pattrib->nr_frags)); sz = pxmitpriv->frag_len; sz = sz - 4 - (psecuritypriv->sw_encrypt ? 0 : pattrib->icv_len); } else //no frag { sz = pattrib->last_txcmdsz; } ff_hwaddr = rtw_get_ff_hwaddr(pxmitframe); #ifdef CONFIG_CONCURRENT_MODE if(!rtw_buddy_adapter_up(padapter)) goto skip_if2_tx; if(padapter->adapter_type > PRIMARY_ADAPTER) { _adapter *pri_adapter = padapter->pbuddy_adapter; struct dvobj_priv *pri_dvobjpriv = &pri_adapter->dvobjpriv; _enter_critical(&(pri_dvobjpriv->irq_th_lock), &irqL); ptxdesc = get_txdesc(pri_adapter, ff_hwaddr); if(ptxdesc == NULL) { _exit_critical(&pri_dvobjpriv->irq_th_lock, &irqL); rtw_free_xmitbuf(pxmitpriv, pxmitbuf); DBG_8192C("##### Tx desc unavailable !#####\n"); break; } update_txdesc(pxmitframe, (uint*)ptxdesc, sz); rtl8192ce_enqueue_xmitbuf(&(pri_adapter->xmitpriv.tx_ring[ff_hwaddr]), pxmitbuf); pxmitbuf->len = sz; w_sz = sz; wmb(); ptxdesc->txdw0 |= cpu_to_le32(OWN); _exit_critical(&pri_dvobjpriv->irq_th_lock, &irqL); rtw_write16(pri_adapter, REG_PCIE_CTRL_REG, ffaddr2dma(ff_hwaddr)); rtw_write_port(padapter, ff_hwaddr, w_sz, (unsigned char*)pxmitbuf); } else skip_if2_tx: #endif { _enter_critical(&pdvobjpriv->irq_th_lock, &irqL); ptxdesc = get_txdesc(pxmitframe->padapter, ff_hwaddr); if(ptxdesc == NULL) { _exit_critical(&pdvobjpriv->irq_th_lock, &irqL); rtw_free_xmitbuf(pxmitpriv, pxmitbuf); DBG_8192C("##### Tx desc unavailable !#####\n"); break; } update_txdesc(pxmitframe, (uint*)ptxdesc, sz); rtl8192ce_enqueue_xmitbuf(&pxmitpriv->tx_ring[ff_hwaddr], pxmitbuf); pxmitbuf->len = sz; w_sz = sz; wmb(); ptxdesc->txdw0 |= cpu_to_le32(OWN); _exit_critical(&pdvobjpriv->irq_th_lock, &irqL); rtw_write16(padapter, REG_PCIE_CTRL_REG, ffaddr2dma(ff_hwaddr)); rtw_write_port(padapter, ff_hwaddr, w_sz, (unsigned char*)pxmitbuf); } rtw_count_tx_stats(padapter, pxmitframe, sz); RT_TRACE(_module_rtl871x_xmit_c_,_drv_info_,("rtw_write_port, w_sz=%d\n", w_sz)); //DBG_8192C("rtw_write_port, w_sz=%d, sz=%d, txdesc_sz=%d, tid=%d\n", w_sz, sz, w_sz-sz, pattrib->priority); //mem_addr += w_sz; //mem_addr = (u8 *)RND4(((SIZE_PTR)(mem_addr))); } rtw_free_xmitframe_ex(pxmitpriv, pxmitframe); }
//todo: static s32 rtl8188es_dequeue_writeport(PADAPTER padapter) { struct mlme_priv *pmlmepriv = &padapter->mlmepriv; struct xmit_priv *pxmitpriv = &padapter->xmitpriv; struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter); struct xmit_buf *pxmitbuf; PADAPTER pri_padapter = padapter; s32 ret = 0; u8 PageIdx = 0; u32 deviceId; #ifdef CONFIG_SDIO_TX_ENABLE_AVAL_INT u8 bUpdatePageNum = _FALSE; #else u32 polling_num = 0; #endif #ifdef CONFIG_CONCURRENT_MODE if (padapter->adapter_type > 0) pri_padapter = padapter->pbuddy_adapter; if(rtw_buddy_adapter_up(padapter)) ret = check_buddy_fwstate( padapter, _FW_UNDER_SURVEY); #endif ret = ret || check_fwstate(pmlmepriv, _FW_UNDER_SURVEY); if (_TRUE == ret) pxmitbuf = dequeue_pending_xmitbuf_under_survey(pxmitpriv); else pxmitbuf = dequeue_pending_xmitbuf(pxmitpriv); if (pxmitbuf == NULL) { return _TRUE; } deviceId = ffaddr2deviceId(pdvobjpriv, pxmitbuf->ff_hwaddr); // translate fifo addr to queue index switch (deviceId) { case WLAN_TX_HIQ_DEVICE_ID: PageIdx = HI_QUEUE_IDX; break; case WLAN_TX_MIQ_DEVICE_ID: PageIdx = MID_QUEUE_IDX; break; case WLAN_TX_LOQ_DEVICE_ID: PageIdx = LOW_QUEUE_IDX; break; } query_free_page: // check if hardware tx fifo page is enough if( _FALSE == rtw_hal_sdio_query_tx_freepage(pri_padapter, PageIdx, pxmitbuf->pg_num)) { #ifdef CONFIG_SDIO_TX_ENABLE_AVAL_INT if (!bUpdatePageNum) { // Total number of page is NOT available, so update current FIFO status HalQueryTxBufferStatus8189ESdio(padapter); bUpdatePageNum = _TRUE; goto query_free_page; } else { bUpdatePageNum = _FALSE; enqueue_pending_xmitbuf_to_head(pxmitpriv, pxmitbuf); return _TRUE; } #else //CONFIG_SDIO_TX_ENABLE_AVAL_INT polling_num++; if ((polling_num % 60) == 0) {//or 80 //DBG_871X("%s: FIFO starvation!(%d) len=%d agg=%d page=(R)%d(A)%d\n", // __func__, n, pxmitbuf->len, pxmitbuf->agg_num, pframe->pg_num, freePage[PageIdx] + freePage[PUBLIC_QUEUE_IDX]); rtw_msleep_os(1); } // Total number of page is NOT available, so update current FIFO status HalQueryTxBufferStatus8189ESdio(padapter); goto query_free_page; #endif //CONFIG_SDIO_TX_ENABLE_AVAL_INT } if ((padapter->bSurpriseRemoved == _TRUE) || (padapter->bDriverStopped == _TRUE) #ifdef CONFIG_CONCURRENT_MODE ||((padapter->pbuddy_adapter) && ((padapter->pbuddy_adapter->bSurpriseRemoved) ||(padapter->pbuddy_adapter->bDriverStopped))) #endif ){ RT_TRACE(_module_hal_xmit_c_, _drv_notice_, ("%s: bSurpriseRemoved(wirte port)\n", __FUNCTION__)); goto free_xmitbuf; } if (rtw_sdio_wait_enough_TxOQT_space(padapter, pxmitbuf->agg_num) == _FALSE) { goto free_xmitbuf; } rtw_write_port(padapter, deviceId, pxmitbuf->len, (u8 *)pxmitbuf); rtw_hal_sdio_update_tx_freepage(pri_padapter, PageIdx, pxmitbuf->pg_num); free_xmitbuf: //rtw_free_xmitframe(pxmitpriv, pframe); //pxmitbuf->priv_data = NULL; rtw_free_xmitbuf(pxmitpriv, pxmitbuf); #ifdef CONFIG_SDIO_TX_TASKLET tasklet_hi_schedule(&pxmitpriv->xmit_tasklet); #endif return _FAIL; }
s32 rtl8188eu_xmitframe_complete(struct adapter *adapt, struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf) { struct hal_data_8188e *haldata = GET_HAL_DATA(adapt); struct xmit_frame *pxmitframe = NULL; struct xmit_frame *pfirstframe = NULL; /* aggregate variable */ struct hw_xmit *phwxmit; struct sta_info *psta = NULL; struct tx_servq *ptxservq = NULL; struct list_head *xmitframe_plist = NULL, *xmitframe_phead = NULL; u32 pbuf; /* next pkt address */ u32 pbuf_tail; /* last pkt tail */ u32 len; /* packet length, except TXDESC_SIZE and PKT_OFFSET */ u32 bulksize = haldata->UsbBulkOutSize; u8 desc_cnt; u32 bulkptr; /* dump frame variable */ u32 ff_hwaddr; RT_TRACE(_module_rtl8192c_xmit_c_, _drv_info_, ("+xmitframe_complete\n")); /* check xmitbuffer is ok */ if (pxmitbuf == NULL) { pxmitbuf = rtw_alloc_xmitbuf(pxmitpriv); if (pxmitbuf == NULL) return false; } /* 3 1. pick up first frame */ do { rtw_free_xmitframe(pxmitpriv, pxmitframe); pxmitframe = rtw_dequeue_xframe(pxmitpriv, pxmitpriv->hwxmits, pxmitpriv->hwxmit_entry); if (pxmitframe == NULL) { /* no more xmit frame, release xmit buffer */ rtw_free_xmitbuf(pxmitpriv, pxmitbuf); return false; } pxmitframe->pxmitbuf = pxmitbuf; pxmitframe->buf_addr = pxmitbuf->pbuf; pxmitbuf->priv_data = pxmitframe; pxmitframe->agg_num = 1; /* alloc xmitframe should assign to 1. */ pxmitframe->pkt_offset = 1; /* first frame of aggregation, reserve offset */ rtw_xmitframe_coalesce(adapt, pxmitframe->pkt, pxmitframe); /* always return ndis_packet after rtw_xmitframe_coalesce */ rtw_os_xmit_complete(adapt, pxmitframe); break; } while (1); /* 3 2. aggregate same priority and same DA(AP or STA) frames */ pfirstframe = pxmitframe; len = xmitframe_need_length(pfirstframe) + TXDESC_SIZE + (pfirstframe->pkt_offset*PACKET_OFFSET_SZ); pbuf_tail = len; pbuf = round_up(pbuf_tail, 8); /* check pkt amount in one bulk */ desc_cnt = 0; bulkptr = bulksize; if (pbuf < bulkptr) { desc_cnt++; } else { desc_cnt = 0; bulkptr = ((pbuf / bulksize) + 1) * bulksize; /* round to next bulksize */ } /* dequeue same priority packet from station tx queue */ psta = pfirstframe->attrib.psta; switch (pfirstframe->attrib.priority) { case 1: case 2: ptxservq = &(psta->sta_xmitpriv.bk_q); phwxmit = pxmitpriv->hwxmits + 3; break; case 4: case 5: ptxservq = &(psta->sta_xmitpriv.vi_q); phwxmit = pxmitpriv->hwxmits + 1; break; case 6: case 7: ptxservq = &(psta->sta_xmitpriv.vo_q); phwxmit = pxmitpriv->hwxmits; break; case 0: case 3: default: ptxservq = &(psta->sta_xmitpriv.be_q); phwxmit = pxmitpriv->hwxmits + 2; break; } spin_lock_bh(&pxmitpriv->lock); xmitframe_phead = get_list_head(&ptxservq->sta_pending); xmitframe_plist = xmitframe_phead->next; while (xmitframe_phead != xmitframe_plist) { pxmitframe = container_of(xmitframe_plist, struct xmit_frame, list); xmitframe_plist = xmitframe_plist->next; pxmitframe->agg_num = 0; /* not first frame of aggregation */ pxmitframe->pkt_offset = 0; /* not first frame of aggregation, no need to reserve offset */ len = xmitframe_need_length(pxmitframe) + TXDESC_SIZE + (pxmitframe->pkt_offset*PACKET_OFFSET_SZ); if (round_up(pbuf + len, 8) > MAX_XMITBUF_SZ) { pxmitframe->agg_num = 1; pxmitframe->pkt_offset = 1; break; } list_del_init(&pxmitframe->list); ptxservq->qcnt--; phwxmit->accnt--; pxmitframe->buf_addr = pxmitbuf->pbuf + pbuf; rtw_xmitframe_coalesce(adapt, pxmitframe->pkt, pxmitframe); /* always return ndis_packet after rtw_xmitframe_coalesce */ rtw_os_xmit_complete(adapt, pxmitframe); /* (len - TXDESC_SIZE) == pxmitframe->attrib.last_txcmdsz */ update_txdesc(pxmitframe, pxmitframe->buf_addr, pxmitframe->attrib.last_txcmdsz, true); /* don't need xmitframe any more */ rtw_free_xmitframe(pxmitpriv, pxmitframe); /* handle pointer and stop condition */ pbuf_tail = pbuf + len; pbuf = round_up(pbuf_tail, 8); pfirstframe->agg_num++; if (MAX_TX_AGG_PACKET_NUMBER == pfirstframe->agg_num) break; if (pbuf < bulkptr) { desc_cnt++; if (desc_cnt == haldata->UsbTxAggDescNum) break; } else { desc_cnt = 0; bulkptr = ((pbuf / bulksize) + 1) * bulksize; } } /* end while (aggregate same priority and same DA(AP or STA) frames) */ if (list_empty(&ptxservq->sta_pending.queue)) list_del_init(&ptxservq->tx_pending); spin_unlock_bh(&pxmitpriv->lock); if ((pfirstframe->attrib.ether_type != 0x0806) && (pfirstframe->attrib.ether_type != 0x888e) && (pfirstframe->attrib.ether_type != 0x88b4) && (pfirstframe->attrib.dhcp_pkt != 1)) rtw_issue_addbareq_cmd(adapt, pfirstframe); /* 3 3. update first frame txdesc */ if ((pbuf_tail % bulksize) == 0) { /* remove pkt_offset */ pbuf_tail -= PACKET_OFFSET_SZ; pfirstframe->buf_addr += PACKET_OFFSET_SZ; pfirstframe->pkt_offset--; } update_txdesc(pfirstframe, pfirstframe->buf_addr, pfirstframe->attrib.last_txcmdsz, true); /* 3 4. write xmit buffer to USB FIFO */ ff_hwaddr = rtw_get_ff_hwaddr(pfirstframe); usb_write_port(adapt, ff_hwaddr, pbuf_tail, (u8 *)pxmitbuf); /* 3 5. update statisitc */ pbuf_tail -= (pfirstframe->agg_num * TXDESC_SIZE); pbuf_tail -= (pfirstframe->pkt_offset * PACKET_OFFSET_SZ); rtw_count_tx_stats(adapt, pfirstframe, pbuf_tail); rtw_free_xmitframe(pxmitpriv, pfirstframe); return true; }
s32 rtl8192cu_xmitframe_complete(_adapter *padapter, struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf) { HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); struct xmit_frame *pxmitframe = NULL; struct xmit_frame *pfirstframe = NULL; // aggregate variable struct hw_xmit *phwxmit; struct sta_info *psta = NULL; struct tx_servq *ptxservq = NULL; _irqL irqL; _list *xmitframe_plist = NULL, *xmitframe_phead = NULL; u32 pbuf; // next pkt address u32 pbuf_tail; // last pkt tail u32 len; // packet length, except TXDESC_SIZE and PKT_OFFSET u32 bulkSize = pHalData->UsbBulkOutSize; u8 descCount; u32 bulkPtr; // dump frame variable u32 ff_hwaddr; #ifndef IDEA_CONDITION int res = _SUCCESS; #endif RT_TRACE(_module_rtl8192c_xmit_c_, _drv_info_, ("+xmitframe_complete\n")); // check xmitbuffer is ok if (pxmitbuf == NULL) { pxmitbuf = rtw_alloc_xmitbuf(pxmitpriv); if (pxmitbuf == NULL) return _FALSE; } //3 1. pick up first frame do { rtw_free_xmitframe(pxmitpriv, pxmitframe); pxmitframe = rtw_dequeue_xframe(pxmitpriv, pxmitpriv->hwxmits, pxmitpriv->hwxmit_entry); if (pxmitframe == NULL) { // no more xmit frame, release xmit buffer rtw_free_xmitbuf(pxmitpriv, pxmitbuf); return _FALSE; } #ifndef IDEA_CONDITION if (pxmitframe->frame_tag != DATA_FRAMETAG) { RT_TRACE(_module_rtl8192c_xmit_c_, _drv_err_, ("xmitframe_complete: frame tag(%d) is not DATA_FRAMETAG(%d)!\n", pxmitframe->frame_tag, DATA_FRAMETAG)); // rtw_free_xmitframe(pxmitpriv, pxmitframe); continue; } // TID 0~15 if ((pxmitframe->attrib.priority < 0) || (pxmitframe->attrib.priority > 15)) { RT_TRACE(_module_rtl8192c_xmit_c_, _drv_err_, ("xmitframe_complete: TID(%d) should be 0~15!\n", pxmitframe->attrib.priority)); // rtw_free_xmitframe(pxmitpriv, pxmitframe); continue; } #endif pxmitframe->pxmitbuf = pxmitbuf; pxmitframe->buf_addr = pxmitbuf->pbuf; pxmitbuf->priv_data = pxmitframe; //pxmitframe->agg_num = 1; // alloc xmitframe should assign to 1. pxmitframe->pkt_offset = 1; // first frame of aggregation, reserve offset #ifdef IDEA_CONDITION rtw_xmitframe_coalesce(padapter, pxmitframe->pkt, pxmitframe); #else res = rtw_xmitframe_coalesce(padapter, pxmitframe->pkt, pxmitframe); if (res == _FALSE) { // rtw_free_xmitframe(pxmitpriv, pxmitframe); continue; } #endif // always return ndis_packet after rtw_xmitframe_coalesce rtw_os_xmit_complete(padapter, pxmitframe); break; } while (1); //3 2. aggregate same priority and same DA(AP or STA) frames pfirstframe = pxmitframe; len = xmitframe_need_length(pfirstframe) + TXDESC_OFFSET; pbuf_tail = len; pbuf = _RND8(pbuf_tail); // check pkt amount in one bluk descCount = 0; bulkPtr = bulkSize; if (pbuf < bulkPtr) descCount++; else { descCount = 0; bulkPtr = ((pbuf / bulkSize) + 1) * bulkSize; // round to next bulkSize } // dequeue same priority packet from station tx queue psta = pfirstframe->attrib.psta; switch (pfirstframe->attrib.priority) { case 1: case 2: ptxservq = &(psta->sta_xmitpriv.bk_q); phwxmit = pxmitpriv->hwxmits + 3; break; case 4: case 5: ptxservq = &(psta->sta_xmitpriv.vi_q); phwxmit = pxmitpriv->hwxmits + 1; break; case 6: case 7: ptxservq = &(psta->sta_xmitpriv.vo_q); phwxmit = pxmitpriv->hwxmits; break; case 0: case 3: default: ptxservq = &(psta->sta_xmitpriv.be_q); phwxmit = pxmitpriv->hwxmits + 2; break; } _enter_critical_bh(&pxmitpriv->lock, &irqL); xmitframe_phead = get_list_head(&ptxservq->sta_pending); xmitframe_plist = get_next(xmitframe_phead); while (rtw_end_of_queue_search(xmitframe_phead, xmitframe_plist) == _FALSE) { pxmitframe = LIST_CONTAINOR(xmitframe_plist, struct xmit_frame, list); xmitframe_plist = get_next(xmitframe_plist); len = xmitframe_need_length(pxmitframe) + TXDESC_SIZE; // no offset if (pbuf + len > MAX_XMITBUF_SZ) break; rtw_list_delete(&pxmitframe->list); ptxservq->qcnt--; phwxmit->accnt--; #ifndef IDEA_CONDITION // suppose only data frames would be in queue if (pxmitframe->frame_tag != DATA_FRAMETAG) { RT_TRACE(_module_rtl8192c_xmit_c_, _drv_err_, ("xmitframe_complete: frame tag(%d) is not DATA_FRAMETAG(%d)!\n", pxmitframe->frame_tag, DATA_FRAMETAG)); rtw_free_xmitframe(pxmitpriv, pxmitframe); continue; } // TID 0~15 if ((pxmitframe->attrib.priority < 0) || (pxmitframe->attrib.priority > 15)) { RT_TRACE(_module_rtl8192c_xmit_c_, _drv_err_, ("xmitframe_complete: TID(%d) should be 0~15!\n", pxmitframe->attrib.priority)); rtw_free_xmitframe(pxmitpriv, pxmitframe); continue; } #endif // pxmitframe->pxmitbuf = pxmitbuf; pxmitframe->buf_addr = pxmitbuf->pbuf + pbuf; pxmitframe->agg_num = 0; // not first frame of aggregation pxmitframe->pkt_offset = 0; // not first frame of aggregation, no need to reserve offset #ifdef IDEA_CONDITION rtw_xmitframe_coalesce(padapter, pxmitframe->pkt, pxmitframe); #else res = rtw_xmitframe_coalesce(padapter, pxmitframe->pkt, pxmitframe); if (res == _FALSE) { rtw_free_xmitframe(pxmitpriv, pxmitframe); continue; } #endif // always return ndis_packet after rtw_xmitframe_coalesce rtw_os_xmit_complete(padapter, pxmitframe); // (len - TXDESC_SIZE) == pxmitframe->attrib.last_txcmdsz update_txdesc(pxmitframe, pxmitframe->buf_addr, pxmitframe->attrib.last_txcmdsz, _TRUE); // don't need xmitframe any more rtw_free_xmitframe(pxmitpriv, pxmitframe); // handle pointer and stop condition pbuf_tail = pbuf + len; pbuf = _RND8(pbuf_tail); pfirstframe->agg_num++; if (MAX_TX_AGG_PACKET_NUMBER == pfirstframe->agg_num) break; if (pbuf < bulkPtr) { descCount++; if (descCount == pHalData->UsbTxAggDescNum) break; } else { descCount = 0; bulkPtr = ((pbuf / bulkSize) + 1) * bulkSize; } } if (_rtw_queue_empty(&ptxservq->sta_pending) == _TRUE) rtw_list_delete(&ptxservq->tx_pending); _exit_critical_bh(&pxmitpriv->lock, &irqL); if ((pfirstframe->attrib.ether_type != 0x0806) && (pfirstframe->attrib.ether_type != 0x888e) && (pfirstframe->attrib.dhcp_pkt != 1)) { rtw_issue_addbareq_cmd(padapter, pfirstframe); } #ifndef CONFIG_USE_USB_BUFFER_ALLOC_TX //3 3. update first frame txdesc if ((pbuf_tail % bulkSize) == 0) { // remove pkt_offset pbuf_tail -= PACKET_OFFSET_SZ; pfirstframe->buf_addr += PACKET_OFFSET_SZ; pfirstframe->pkt_offset = 0; } #endif // CONFIG_USE_USB_BUFFER_ALLOC_TX update_txdesc(pfirstframe, pfirstframe->buf_addr, pfirstframe->attrib.last_txcmdsz, _TRUE); //3 4. write xmit buffer to USB FIFO ff_hwaddr = rtw_get_ff_hwaddr(pfirstframe); // xmit address == ((xmit_frame*)pxmitbuf->priv_data)->buf_addr rtw_write_port(padapter, ff_hwaddr, pbuf_tail, (u8*)pxmitbuf); //3 5. update statisitc pbuf_tail -= (pfirstframe->agg_num * TXDESC_SIZE); if (pfirstframe->pkt_offset == 1) pbuf_tail -= PACKET_OFFSET_SZ; rtw_count_tx_stats(padapter, pfirstframe, pbuf_tail); rtw_free_xmitframe(pxmitpriv, pfirstframe); return _TRUE; }
u32 usb_write_port(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *wmem) { _irqL irqL; unsigned int pipe; int status; u32 ret = _FAIL, bwritezero = _FALSE; PURB purb = NULL; _adapter *padapter = (_adapter *)pintfhdl->padapter; struct dvobj_priv *pdvobj = adapter_to_dvobj(padapter); struct pwrctrl_priv *pwrctl = dvobj_to_pwrctl(pdvobj); struct xmit_priv *pxmitpriv = &padapter->xmitpriv; struct xmit_buf *pxmitbuf = (struct xmit_buf *)wmem; struct xmit_frame *pxmitframe = (struct xmit_frame *)pxmitbuf->priv_data; struct usb_device *pusbd = pdvobj->pusbdev; struct pkt_attrib *pattrib = &pxmitframe->attrib; RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("+usb_write_port\n")); if (RTW_CANNOT_TX(padapter)) { #ifdef DBG_TX DBG_871X(" DBG_TX %s:%d bDriverStopped%d, bSurpriseRemoved:%d\n",__FUNCTION__, __LINE__ ,padapter->bDriverStopped, padapter->bSurpriseRemoved); #endif RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("usb_write_port:( padapter->bDriverStopped ||padapter->bSurpriseRemoved )!!!\n")); rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_TX_DENY); goto exit; } SPIN_LOCK_IRQ(pxmitpriv->lock, &irqL); switch(addr) { case VO_QUEUE_INX: pxmitpriv->voq_cnt++; pxmitbuf->flags = VO_QUEUE_INX; break; case VI_QUEUE_INX: pxmitpriv->viq_cnt++; pxmitbuf->flags = VI_QUEUE_INX; break; case BE_QUEUE_INX: pxmitpriv->beq_cnt++; pxmitbuf->flags = BE_QUEUE_INX; break; case BK_QUEUE_INX: pxmitpriv->bkq_cnt++; pxmitbuf->flags = BK_QUEUE_INX; break; case HIGH_QUEUE_INX: pxmitbuf->flags = HIGH_QUEUE_INX; break; default: pxmitbuf->flags = MGT_QUEUE_INX; break; } SPIN_UNLOCK_IRQ(pxmitpriv->lock, &irqL); purb = pxmitbuf->pxmit_urb[0]; //translate DMA FIFO addr to pipehandle pipe = ffaddr2pipehdl(pdvobj, addr); #ifdef CONFIG_REDUCE_USB_TX_INT if ( (pxmitpriv->free_xmitbuf_cnt%NR_XMITBUFF == 0) || (pxmitbuf->buf_tag > XMITBUF_DATA) ) { purb->transfer_flags &= (~URB_NO_INTERRUPT); } else { purb->transfer_flags |= URB_NO_INTERRUPT; //DBG_8192C("URB_NO_INTERRUPT "); } #endif usb_fill_bulk_urb(purb, pusbd, pipe, pxmitframe->buf_addr, //= pxmitbuf->pbuf cnt, usb_write_port_complete, pxmitbuf);//context is pxmitbuf #ifdef CONFIG_USE_USB_BUFFER_ALLOC_TX purb->transfer_dma = pxmitbuf->dma_transfer_addr; purb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; purb->transfer_flags |= URB_ZERO_PACKET; #endif // CONFIG_USE_USB_BUFFER_ALLOC_TX #ifdef USB_PACKET_OFFSET_SZ #if (USB_PACKET_OFFSET_SZ == 0) purb->transfer_flags |= URB_ZERO_PACKET; #endif #endif status = usb_submit_urb(purb, GFP_ATOMIC); if (!status) { #ifdef DBG_CONFIG_ERROR_DETECT { HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); pHalData->srestpriv.last_tx_time = rtw_get_current_time(); } #endif } else { rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_WRITE_PORT_ERR); DBG_871X("usb_write_port, status=%d\n", status); RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("usb_write_port(): usb_submit_urb, status=%x\n", status)); switch (status) { case -ENODEV: padapter->bDriverStopped=_TRUE; break; default: break; } goto exit; } ret= _SUCCESS; RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("-usb_write_port\n")); exit: if (ret != _SUCCESS) rtw_free_xmitbuf(pxmitpriv, pxmitbuf); return ret; }
static s32 rtl8723_dequeue_writeport(PADAPTER padapter) { struct mlme_priv *pmlmepriv = &padapter->mlmepriv; struct xmit_priv *pxmitpriv = &padapter->xmitpriv; struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter); struct xmit_buf *pxmitbuf; PADAPTER pri_padapter = padapter; u32 deviceId; u32 requiredPage; u8 PageIdx=0; u8 *freePage; _irqL irql; u32 n; s32 ret = 0; #ifdef CONFIG_CONCURRENT_MODE if (padapter->adapter_type > 0) pri_padapter = padapter->pbuddy_adapter; if (rtw_buddy_adapter_up(padapter)) ret = check_buddy_fwstate(padapter, _FW_UNDER_SURVEY); #endif ret = ret || check_fwstate(pmlmepriv, _FW_UNDER_SURVEY); if (_TRUE == ret) pxmitbuf = dequeue_pending_xmitbuf_under_survey(pxmitpriv); else pxmitbuf = dequeue_pending_xmitbuf(pxmitpriv); if (pxmitbuf == NULL) return _TRUE; query_free_page: // check if hardware tx fifo page is enough if( _FALSE == rtl8723bs_query_tx_freepage(pri_padapter, pxmitbuf)) { rtw_msleep_os(1); goto query_free_page; } if ((padapter->bSurpriseRemoved == _TRUE) || (padapter->bDriverStopped == _TRUE) #ifdef CONFIG_CONCURRENT_MODE ||((padapter->pbuddy_adapter) && ((padapter->pbuddy_adapter->bSurpriseRemoved) ||(padapter->pbuddy_adapter->bDriverStopped))) #endif ) { RT_TRACE(_module_hal_xmit_c_, _drv_notice_, ("%s: bSurpriseRemoved(wirte port)\n", __FUNCTION__)); goto free_xmitbuf; } #ifdef CONFIG_CHECK_LEAVE_LPS traffic_check_for_leave_lps(padapter, _TRUE, pxmitbuf->agg_num); #endif rtw_write_port(padapter, ffaddr2deviceId(pdvobjpriv, pxmitbuf->ff_hwaddr), pxmitbuf->len, (u8 *)pxmitbuf); free_xmitbuf: //rtw_free_xmitframe(pxmitpriv, pframe); //pxmitbuf->priv_data = NULL; rtw_free_xmitbuf(pxmitpriv, pxmitbuf); #if 0 // improve TX/RX throughput balance { PSDIO_DATA psdio; struct sdio_func *func; static u8 i = 0; u32 sdio_hisr; u8 j; psdio = &adapter_to_dvobj(padapter)->intf_data; func = psdio->func; if (i == 2) { j = 0; while (j < 10) { sdio_hisr = SdioLocalCmd52Read1Byte(padapter, SDIO_REG_HISR); sdio_hisr &= GET_HAL_DATA(padapter)->sdio_himr; if (sdio_hisr & SDIO_HISR_RX_REQUEST) { sdio_claim_host(func); sd_int_hdl(pri_padapter); sdio_release_host(func); } else { break; } j++; } i = 0; } else { i++; } } #endif #ifdef CONFIG_SDIO_TX_TASKLET tasklet_hi_schedule(&pxmitpriv->xmit_tasklet); #endif return _FAIL; }
/* * Description: * Aggregation packets and send to hardware * * Return: * 0 Success * -1 Hardware resource(TX FIFO) not ready * -2 Software resource(xmitbuf) not ready */ static s32 xmit_xmitframes(PADAPTER padapter, struct xmit_priv *pxmitpriv) { s32 err, ret; u32 k=0; struct hw_xmit *hwxmits, *phwxmit; u8 no_res, idx, hwentry; _irqL irql; struct tx_servq *ptxservq; _list *sta_plist, *sta_phead, *frame_plist, *frame_phead; struct xmit_frame *pxmitframe; _queue *pframe_queue; struct xmit_buf *pxmitbuf; u32 txlen; u8 txdesc_size = TXDESC_SIZE; int inx[4]; err = 0; no_res = _FALSE; hwxmits = pxmitpriv->hwxmits; hwentry = pxmitpriv->hwxmit_entry; ptxservq = NULL; pxmitframe = NULL; pframe_queue = NULL; pxmitbuf = NULL; if (padapter->registrypriv.wifi_spec == 1) { for(idx=0; idx<4; idx++) inx[idx] = pxmitpriv->wmm_para_seq[idx]; } else { inx[0] = 0; inx[1] = 1; inx[2] = 2; inx[3] = 3; } // 0(VO), 1(VI), 2(BE), 3(BK) for (idx = 0; idx < hwentry; idx++) { phwxmit = hwxmits + inx[idx]; if((check_pending_xmitbuf(pxmitpriv) == _TRUE) && (padapter->mlmepriv.LinkDetectInfo.bHigherBusyTxTraffic == _TRUE)) { if ((phwxmit->accnt > 0) && (phwxmit->accnt < 5)) { err = -2; break; } } _enter_critical_bh(&pxmitpriv->lock, &irql); sta_phead = get_list_head(phwxmit->sta_queue); sta_plist = get_next(sta_phead); //because stop_sta_xmit may delete sta_plist at any time //so we should add lock here, or while loop can not exit while (rtw_end_of_queue_search(sta_phead, sta_plist) == _FALSE) { ptxservq = LIST_CONTAINOR(sta_plist, struct tx_servq, tx_pending); sta_plist = get_next(sta_plist); #ifdef DBG_XMIT_BUF DBG_871X("%s idx:%d hwxmit_pkt_num:%d ptxservq_pkt_num:%d\n", __func__, idx, phwxmit->accnt, ptxservq->qcnt); DBG_871X("%s free_xmit_extbuf_cnt=%d free_xmitbuf_cnt=%d free_xmitframe_cnt=%d \n", __func__, pxmitpriv->free_xmit_extbuf_cnt, pxmitpriv->free_xmitbuf_cnt, pxmitpriv->free_xmitframe_cnt); #endif pframe_queue = &ptxservq->sta_pending; frame_phead = get_list_head(pframe_queue); while (rtw_is_list_empty(frame_phead) == _FALSE) { frame_plist = get_next(frame_phead); pxmitframe = LIST_CONTAINOR(frame_plist, struct xmit_frame, list); // check xmit_buf size enough or not txlen = txdesc_size + rtw_wlan_pkt_size(pxmitframe); if ((NULL == pxmitbuf) || ((pxmitbuf->ptail + txlen) > pxmitbuf->pend) #ifdef SDIO_TX_AGG_MAX || (k >= SDIO_TX_AGG_MAX) #endif ) { if (pxmitbuf) { //pxmitbuf->priv_data will be NULL, and will crash here if (pxmitbuf->len > 0 && pxmitbuf->priv_data) { struct xmit_frame *pframe; pframe = (struct xmit_frame*)pxmitbuf->priv_data; pframe->agg_num = k; pxmitbuf->agg_num = k; rtl8723b_update_txdesc(pframe, pframe->buf_addr); rtw_free_xmitframe(pxmitpriv, pframe); pxmitbuf->priv_data = NULL; enqueue_pending_xmitbuf(pxmitpriv, pxmitbuf); //can not yield under lock //rtw_yield_os(); } else { rtw_free_xmitbuf(pxmitpriv, pxmitbuf); } } pxmitbuf = rtw_alloc_xmitbuf(pxmitpriv); if (pxmitbuf == NULL) { #ifdef DBG_XMIT_BUF DBG_871X_LEVEL(_drv_err_, "%s: xmit_buf is not enough!\n", __FUNCTION__); #endif err = -2; break; } k = 0; } // ok to send, remove frame from queue #ifdef CONFIG_AP_MODE if (check_fwstate(&padapter->mlmepriv, WIFI_AP_STATE) == _TRUE) { if ((pxmitframe->attrib.psta->state & WIFI_SLEEP_STATE) && (pxmitframe->attrib.triggered == 0)) { DBG_871X("%s: one not triggered pkt in queue when this STA sleep," " break and goto next sta\n", __func__); break; } } #endif rtw_list_delete(&pxmitframe->list); ptxservq->qcnt--; phwxmit->accnt--; if (k == 0) { pxmitbuf->ff_hwaddr = rtw_get_ff_hwaddr(pxmitframe); pxmitbuf->priv_data = (u8*)pxmitframe; } // coalesce the xmitframe to xmitbuf pxmitframe->pxmitbuf = pxmitbuf; pxmitframe->buf_addr = pxmitbuf->ptail; ret = rtw_xmitframe_coalesce(padapter, pxmitframe->pkt, pxmitframe); if (ret == _FAIL) { DBG_871X_LEVEL(_drv_err_, "%s: coalesce FAIL!", __FUNCTION__); // Todo: error handler } else { k++; if (k != 1) rtl8723b_update_txdesc(pxmitframe, pxmitframe->buf_addr); rtw_count_tx_stats(padapter, pxmitframe, pxmitframe->attrib.last_txcmdsz); txlen = txdesc_size + pxmitframe->attrib.last_txcmdsz; pxmitframe->pg_num = (txlen + 127)/128; pxmitbuf->pg_num += (txlen + 127)/128; //if (k != 1) // ((struct xmit_frame*)pxmitbuf->priv_data)->pg_num += pxmitframe->pg_num; pxmitbuf->ptail += _RND(txlen, 8); // round to 8 bytes alignment pxmitbuf->len = _RND(pxmitbuf->len, 8) + txlen; } if (k != 1) rtw_free_xmitframe(pxmitpriv, pxmitframe); pxmitframe = NULL; } if (_rtw_queue_empty(pframe_queue) == _TRUE) rtw_list_delete(&ptxservq->tx_pending); if (err) break; } _exit_critical_bh(&pxmitpriv->lock, &irql); // dump xmit_buf to hw tx fifo if (pxmitbuf) { RT_TRACE(_module_hal_xmit_c_, _drv_info_, ("pxmitbuf->len=%d enqueue\n",pxmitbuf->len)); if (pxmitbuf->len > 0) { struct xmit_frame *pframe; pframe = (struct xmit_frame*)pxmitbuf->priv_data; pframe->agg_num = k; pxmitbuf->agg_num = k; rtl8723b_update_txdesc(pframe, pframe->buf_addr); rtw_free_xmitframe(pxmitpriv, pframe); pxmitbuf->priv_data = NULL; enqueue_pending_xmitbuf(pxmitpriv, pxmitbuf); rtw_yield_os(); } else rtw_free_xmitbuf(pxmitpriv, pxmitbuf); pxmitbuf = NULL; } if (err) break; } return err; }
static void usb_write_port_complete(struct urb *purb, struct pt_regs *regs) { _irqL irqL; int i; struct xmit_buf *pxmitbuf = (struct xmit_buf *)purb->context; _adapter *padapter = pxmitbuf->padapter; struct xmit_priv *pxmitpriv = &padapter->xmitpriv; switch(pxmitbuf->flags) { case VO_QUEUE_INX: pxmitpriv->voq_cnt--; break; case VI_QUEUE_INX: pxmitpriv->viq_cnt--; break; case BE_QUEUE_INX: pxmitpriv->beq_cnt--; break; case BK_QUEUE_INX: pxmitpriv->bkq_cnt--; break; default: break; } if (RTW_CANNOT_TX(padapter)) { RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("usb_write_port_complete:bDriverStopped(%d) OR bSurpriseRemoved(%d)", padapter->bDriverStopped, padapter->bSurpriseRemoved)); DBG_8192C("%s(): TX Warning! bDriverStopped(%d) OR bSurpriseRemoved(%d) pxmitbuf->buf_tag(%x) \n", __FUNCTION__,padapter->bDriverStopped, padapter->bSurpriseRemoved,pxmitbuf->buf_tag); goto check_completion; } if (purb->status==0) { } else { RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("usb_write_port_complete : purb->status(%d) != 0 \n", purb->status)); DBG_871X("###=> urb_write_port_complete status(%d)\n",purb->status); if((purb->status==-EPIPE)||(purb->status==-EPROTO)) { sreset_set_wifi_error_status(padapter, USB_WRITE_PORT_FAIL); } else if (purb->status == -EINPROGRESS) { RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("usb_write_port_complete: EINPROGESS\n")); goto check_completion; } else if (purb->status == -ENOENT) { DBG_871X("%s: -ENOENT\n", __func__); goto check_completion; } else if (purb->status == -ECONNRESET) { DBG_871X("%s: -ECONNRESET\n", __func__); goto check_completion; } else if (purb->status == -ESHUTDOWN) { RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("usb_write_port_complete: ESHUTDOWN\n")); padapter->bDriverStopped=_TRUE; RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("usb_write_port_complete:bDriverStopped=TRUE\n")); goto check_completion; } else { padapter->bSurpriseRemoved=_TRUE; DBG_8192C("bSurpriseRemoved=TRUE\n"); RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("usb_write_port_complete:bSurpriseRemoved=TRUE\n")); goto check_completion; } } #ifdef DBG_CONFIG_ERROR_DETECT { HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); pHalData->srestpriv.last_tx_complete_time = rtw_get_current_time(); } #endif check_completion: SPIN_LOCK_IRQ(pxmitpriv->lock_sctx, &irqL); rtw_sctx_done_err(&pxmitbuf->sctx, purb->status ? RTW_SCTX_DONE_WRITE_PORT_ERR : RTW_SCTX_DONE_SUCCESS); SPIN_UNLOCK_IRQ(pxmitpriv->lock_sctx, &irqL); rtw_free_xmitbuf(pxmitpriv, pxmitbuf); tasklet_hi_schedule(&pxmitpriv->xmit_tasklet); }
static void usb_write_port_complete(struct urb *purb, struct pt_regs *regs) { _irqL irqL; int i; struct xmit_buf *pxmitbuf = (struct xmit_buf *)purb->context; /* struct xmit_frame *pxmitframe = (struct xmit_frame *)pxmitbuf->priv_data; */ /* _adapter *padapter = pxmitframe->padapter; */ _adapter *padapter = pxmitbuf->padapter; struct xmit_priv *pxmitpriv = &padapter->xmitpriv; /* struct pkt_attrib *pattrib = &pxmitframe->attrib; */ switch (pxmitbuf->flags) { case VO_QUEUE_INX: pxmitpriv->voq_cnt--; break; case VI_QUEUE_INX: pxmitpriv->viq_cnt--; break; case BE_QUEUE_INX: pxmitpriv->beq_cnt--; break; case BK_QUEUE_INX: pxmitpriv->bkq_cnt--; break; default: break; } /* _enter_critical(&pxmitpriv->lock, &irqL); pxmitpriv->txirp_cnt--; switch(pattrib->priority) { case 1: case 2: pxmitpriv->bkq_cnt--; break; case 4: case 5: pxmitpriv->viq_cnt--; break; case 6: case 7: pxmitpriv->voq_cnt--; break; case 0: case 3: default: pxmitpriv->beq_cnt--; break; } _exit_critical(&pxmitpriv->lock, &irqL); if(pxmitpriv->txirp_cnt==0) { _rtw_up_sema(&(pxmitpriv->tx_retevt)); } */ /* rtw_free_xmitframe(pxmitpriv, pxmitframe); */ if (RTW_CANNOT_TX(padapter)) { RTW_INFO("%s(): TX Warning! bDriverStopped(%s) OR bSurpriseRemoved(%s) pxmitbuf->buf_tag(%x)\n" , __func__ , rtw_is_drv_stopped(padapter) ? "True" : "False" , rtw_is_surprise_removed(padapter) ? "True" : "False" , pxmitbuf->buf_tag); goto check_completion; } if (purb->status == 0) { } else { RTW_INFO("###=> urb_write_port_complete status(%d)\n", purb->status); if ((purb->status == -EPIPE) || (purb->status == -EPROTO)) { /* usb_clear_halt(pusbdev, purb->pipe); */ /* msleep(10); */ sreset_set_wifi_error_status(padapter, USB_WRITE_PORT_FAIL); } else if (purb->status == -EINPROGRESS) { goto check_completion; } else if (purb->status == -ENOENT) { RTW_INFO("%s: -ENOENT\n", __func__); goto check_completion; } else if (purb->status == -ECONNRESET) { RTW_INFO("%s: -ECONNRESET\n", __func__); goto check_completion; } else if (purb->status == -ESHUTDOWN) { rtw_set_drv_stopped(padapter); goto check_completion; } else { rtw_set_surprise_removed(padapter); RTW_INFO("bSurpriseRemoved=TRUE\n"); goto check_completion; } } #ifdef DBG_CONFIG_ERROR_DETECT { HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); pHalData->srestpriv.last_tx_complete_time = rtw_get_current_time(); } #endif check_completion: _enter_critical(&pxmitpriv->lock_sctx, &irqL); rtw_sctx_done_err(&pxmitbuf->sctx, purb->status ? RTW_SCTX_DONE_WRITE_PORT_ERR : RTW_SCTX_DONE_SUCCESS); _exit_critical(&pxmitpriv->lock_sctx, &irqL); rtw_free_xmitbuf(pxmitpriv, pxmitbuf); /* if(rtw_txframes_pending(padapter)) */ { tasklet_hi_schedule(&pxmitpriv->xmit_tasklet); } }
void rtl8192ce_xmitframe_resume(_adapter *padapter) { struct xmit_priv *pxmitpriv = &padapter->xmitpriv; struct xmit_frame *pxmitframe = NULL; struct xmit_buf *pxmitbuf = NULL; int res=_SUCCESS, xcnt = 0; RT_TRACE(_module_rtl871x_xmit_c_,_drv_info_,("rtl8192ce_xmitframe_resume()\n")); while(1) { if ((padapter->bDriverStopped == _TRUE)||(padapter->bSurpriseRemoved== _TRUE)) { DBG_8192C("rtl8192ce_xmitframe_resume => bDriverStopped or bSurpriseRemoved \n"); break; } pxmitbuf = rtw_alloc_xmitbuf(pxmitpriv); if(!pxmitbuf) { break; } pxmitframe = rtw_dequeue_xframe(pxmitpriv, pxmitpriv->hwxmits, pxmitpriv->hwxmit_entry); if(pxmitframe) { pxmitframe->pxmitbuf = pxmitbuf; pxmitframe->buf_addr = pxmitbuf->pbuf; pxmitbuf->priv_data = pxmitframe; if((pxmitframe->frame_tag&0x0f) == DATA_FRAMETAG) { if(pxmitframe->attrib.priority<=15)//TID0~15 { res = rtw_xmitframe_coalesce(padapter, pxmitframe->pkt, pxmitframe); } rtw_os_xmit_complete(padapter, pxmitframe);//always return ndis_packet after rtw_xmitframe_coalesce } RT_TRACE(_module_rtl871x_xmit_c_,_drv_info_,("rtl8192ce_xmitframe_resume(): rtw_dump_xframe\n")); if(res == _SUCCESS) { rtw_dump_xframe(padapter, pxmitframe); } else { rtw_free_xmitbuf(pxmitpriv, pxmitbuf); rtw_free_xmitframe_ex(pxmitpriv, pxmitframe); } xcnt++; } else { rtw_free_xmitbuf(pxmitpriv, pxmitbuf); break; } } }
s32 rtl8812au_xmitframe_complete(_adapter *padapter, struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf) { struct hw_xmit *phwxmits; sint hwentry; struct xmit_frame *pxmitframe=NULL; int res=_SUCCESS, xcnt = 0; phwxmits = pxmitpriv->hwxmits; hwentry = pxmitpriv->hwxmit_entry; RT_TRACE(_module_rtl871x_xmit_c_,_drv_info_,("xmitframe_complete()\n")); if(pxmitbuf==NULL) { pxmitbuf = rtw_alloc_xmitbuf(pxmitpriv); if(!pxmitbuf) { return _FALSE; } } do { pxmitframe = rtw_dequeue_xframe(pxmitpriv, phwxmits, hwentry); if(pxmitframe) { pxmitframe->pxmitbuf = pxmitbuf; pxmitframe->buf_addr = pxmitbuf->pbuf; pxmitbuf->priv_data = pxmitframe; if((pxmitframe->frame_tag&0x0f) == DATA_FRAMETAG) { if(pxmitframe->attrib.priority<=15)//TID0~15 { res = rtw_xmitframe_coalesce(padapter, pxmitframe->pkt, pxmitframe); } //DBG_8192C("==> pxmitframe->attrib.priority:%d\n",pxmitframe->attrib.priority); rtw_os_xmit_complete(padapter, pxmitframe);//always return ndis_packet after rtw_xmitframe_coalesce } RT_TRACE(_module_rtl871x_xmit_c_,_drv_info_,("xmitframe_complete(): rtw_dump_xframe\n")); if(res == _SUCCESS) { rtw_dump_xframe(padapter, pxmitframe); } else { rtw_free_xmitbuf(pxmitpriv, pxmitbuf); rtw_free_xmitframe(pxmitpriv, pxmitframe); } xcnt++; } else { rtw_free_xmitbuf(pxmitpriv, pxmitbuf); return _FALSE; } break; }while(0/*xcnt < (NR_XMITFRAME >> 3)*/); return _TRUE; }
static void usb_write_port_complete(struct urb *purb, struct pt_regs *regs) { struct xmit_buf *pxmitbuf = (struct xmit_buf *)purb->context; struct adapter *padapter = pxmitbuf->padapter; struct xmit_priv *pxmitpriv = &padapter->xmitpriv; struct hal_data_8188e *haldata; switch (pxmitbuf->flags) { case VO_QUEUE_INX: pxmitpriv->voq_cnt--; break; case VI_QUEUE_INX: pxmitpriv->viq_cnt--; break; case BE_QUEUE_INX: pxmitpriv->beq_cnt--; break; case BK_QUEUE_INX: pxmitpriv->bkq_cnt--; break; case HIGH_QUEUE_INX: #ifdef CONFIG_88EU_AP_MODE rtw_chk_hi_queue_cmd(padapter); #endif break; default: break; } if (padapter->bSurpriseRemoved || padapter->bDriverStopped || padapter->bWritePortCancel) { RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("usb_write_port_complete:bDriverStopped(%d) OR bSurpriseRemoved(%d)", padapter->bDriverStopped, padapter->bSurpriseRemoved)); DBG_88E("%s(): TX Warning! bDriverStopped(%d) OR bSurpriseRemoved(%d) bWritePortCancel(%d) pxmitbuf->ext_tag(%x)\n", __func__, padapter->bDriverStopped, padapter->bSurpriseRemoved, padapter->bReadPortCancel, pxmitbuf->ext_tag); goto check_completion; } if (purb->status) { RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("usb_write_port_complete : purb->status(%d) != 0\n", purb->status)); DBG_88E("###=> urb_write_port_complete status(%d)\n", purb->status); if ((purb->status == -EPIPE) || (purb->status == -EPROTO)) { sreset_set_wifi_error_status(padapter, USB_WRITE_PORT_FAIL); } else if (purb->status == -EINPROGRESS) { RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("usb_write_port_complete: EINPROGESS\n")); goto check_completion; } else if (purb->status == -ENOENT) { DBG_88E("%s: -ENOENT\n", __func__); goto check_completion; } else if (purb->status == -ECONNRESET) { DBG_88E("%s: -ECONNRESET\n", __func__); goto check_completion; } else if (purb->status == -ESHUTDOWN) { RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("usb_write_port_complete: ESHUTDOWN\n")); padapter->bDriverStopped = true; RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("usb_write_port_complete:bDriverStopped = true\n")); goto check_completion; } else { padapter->bSurpriseRemoved = true; DBG_88E("bSurpriseRemoved = true\n"); RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("usb_write_port_complete:bSurpriseRemoved = true\n")); goto check_completion; } } haldata = GET_HAL_DATA(padapter); haldata->srestpriv.last_tx_complete_time = jiffies; check_completion: rtw_sctx_done_err(&pxmitbuf->sctx, purb->status ? RTW_SCTX_DONE_WRITE_PORT_ERR : RTW_SCTX_DONE_SUCCESS); rtw_free_xmitbuf(pxmitpriv, pxmitbuf); tasklet_hi_schedule(&pxmitpriv->xmit_tasklet); }
u32 usb_write_port(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *wmem) { unsigned long irqL; unsigned int pipe; int status; u32 ret = _FAIL; struct urb *purb = NULL; struct adapter *padapter = (struct adapter *)pintfhdl->padapter; struct dvobj_priv *pdvobj = adapter_to_dvobj(padapter); struct xmit_priv *pxmitpriv = &padapter->xmitpriv; struct xmit_buf *pxmitbuf = (struct xmit_buf *)wmem; struct xmit_frame *pxmitframe = (struct xmit_frame *)pxmitbuf->priv_data; struct usb_device *pusbd = pdvobj->pusbdev; RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("+usb_write_port\n")); if ((padapter->bDriverStopped) || (padapter->bSurpriseRemoved) || (padapter->pwrctrlpriv.pnp_bstop_trx)) { RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("usb_write_port:( padapter->bDriverStopped ||padapter->bSurpriseRemoved ||adapter->pwrctrlpriv.pnp_bstop_trx)!!!\n")); rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_TX_DENY); goto exit; } spin_lock_irqsave(&pxmitpriv->lock, irqL); switch (addr) { case VO_QUEUE_INX: pxmitpriv->voq_cnt++; pxmitbuf->flags = VO_QUEUE_INX; break; case VI_QUEUE_INX: pxmitpriv->viq_cnt++; pxmitbuf->flags = VI_QUEUE_INX; break; case BE_QUEUE_INX: pxmitpriv->beq_cnt++; pxmitbuf->flags = BE_QUEUE_INX; break; case BK_QUEUE_INX: pxmitpriv->bkq_cnt++; pxmitbuf->flags = BK_QUEUE_INX; break; case HIGH_QUEUE_INX: pxmitbuf->flags = HIGH_QUEUE_INX; break; default: pxmitbuf->flags = MGT_QUEUE_INX; break; } spin_unlock_irqrestore(&pxmitpriv->lock, irqL); purb = pxmitbuf->pxmit_urb[0]; /* translate DMA FIFO addr to pipehandle */ pipe = ffaddr2pipehdl(pdvobj, addr); usb_fill_bulk_urb(purb, pusbd, pipe, pxmitframe->buf_addr, /* pxmitbuf->pbuf */ cnt, usb_write_port_complete, pxmitbuf);/* context is pxmitbuf */ status = usb_submit_urb(purb, GFP_ATOMIC); if (!status) { struct hal_data_8188e *haldata = GET_HAL_DATA(padapter); haldata->srestpriv.last_tx_time = jiffies; } else { rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_WRITE_PORT_ERR); DBG_88E("usb_write_port, status =%d\n", status); RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("usb_write_port(): usb_submit_urb, status =%x\n", status)); switch (status) { case -ENODEV: padapter->bDriverStopped = true; break; default: break; } goto exit; } ret = _SUCCESS; /* We add the URB_ZERO_PACKET flag to urb so that the host will send the zero packet automatically. */ RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("-usb_write_port\n")); exit: if (ret != _SUCCESS) rtw_free_xmitbuf(pxmitpriv, pxmitbuf); return ret; }
u32 usb_write_port(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *wmem) { _irqL irqL; unsigned int pipe; int status; u32 ret = _FAIL, bwritezero = _FALSE; PURB purb = NULL; _adapter *padapter = (_adapter *)pintfhdl->padapter; struct dvobj_priv *pdvobj = adapter_to_dvobj(padapter); struct xmit_priv *pxmitpriv = &padapter->xmitpriv; struct xmit_buf *pxmitbuf = (struct xmit_buf *)wmem; struct xmit_frame *pxmitframe = (struct xmit_frame *)pxmitbuf->priv_data; struct usb_device *pusbd = pdvobj->pusbdev; struct pkt_attrib *pattrib = &pxmitframe->attrib; _func_enter_; RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("+usb_write_port\n")); if ((padapter->bDriverStopped) || (padapter->bSurpriseRemoved) ||(padapter->pwrctrlpriv.pnp_bstop_trx)) { #ifdef DBG_TX DBG_871X(" DBG_TX %s:%d bDriverStopped%d, bSurpriseRemoved:%d, pnp_bstop_trx:%d\n",__FUNCTION__, __LINE__ ,padapter->bDriverStopped, padapter->bSurpriseRemoved, padapter->pwrctrlpriv.pnp_bstop_trx ); #endif RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("usb_write_port:( padapter->bDriverStopped ||padapter->bSurpriseRemoved ||adapter->pwrctrlpriv.pnp_bstop_trx)!!!\n")); rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_TX_DENY); goto exit; } _enter_critical(&pxmitpriv->lock, &irqL); switch(addr) { case VO_QUEUE_INX: pxmitpriv->voq_cnt++; pxmitbuf->flags = VO_QUEUE_INX; break; case VI_QUEUE_INX: pxmitpriv->viq_cnt++; pxmitbuf->flags = VI_QUEUE_INX; break; case BE_QUEUE_INX: pxmitpriv->beq_cnt++; pxmitbuf->flags = BE_QUEUE_INX; break; case BK_QUEUE_INX: pxmitpriv->bkq_cnt++; pxmitbuf->flags = BK_QUEUE_INX; break; case HIGH_QUEUE_INX: pxmitbuf->flags = HIGH_QUEUE_INX; break; default: pxmitbuf->flags = MGT_QUEUE_INX; break; } _exit_critical(&pxmitpriv->lock, &irqL); purb = pxmitbuf->pxmit_urb[0]; #if 0 if(pdvobj->ishighspeed) { if(cnt> 0 && cnt%512 == 0) { //DBG_8192C("ishighspeed, cnt=%d\n", cnt); bwritezero = _TRUE; } } else { if(cnt > 0 && cnt%64 == 0) { //DBG_8192C("cnt=%d\n", cnt); bwritezero = _TRUE; } } #endif //translate DMA FIFO addr to pipehandle pipe = ffaddr2pipehdl(pdvobj, addr); #ifdef CONFIG_REDUCE_USB_TX_INT if ( (pxmitpriv->free_xmitbuf_cnt%NR_XMITBUFF == 0) || (pxmitbuf->ext_tag == _TRUE) ) { purb->transfer_flags &= (~URB_NO_INTERRUPT); } else { purb->transfer_flags |= URB_NO_INTERRUPT; //DBG_8192C("URB_NO_INTERRUPT "); } #endif usb_fill_bulk_urb(purb, pusbd, pipe, pxmitframe->buf_addr, //= pxmitbuf->pbuf cnt, usb_write_port_complete, pxmitbuf);//context is pxmitbuf #ifdef CONFIG_USE_USB_BUFFER_ALLOC_TX purb->transfer_dma = pxmitbuf->dma_transfer_addr; purb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; purb->transfer_flags |= URB_ZERO_PACKET; #endif // CONFIG_USE_USB_BUFFER_ALLOC_TX #if 0 if (bwritezero) { purb->transfer_flags |= URB_ZERO_PACKET; } #endif status = usb_submit_urb(purb, GFP_ATOMIC); if (!status) { #ifdef DBG_CONFIG_ERROR_DETECT { HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); pHalData->srestpriv.last_tx_time = rtw_get_current_time(); } #endif } else { rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_WRITE_PORT_ERR); DBG_871X("usb_write_port, status=%d\n", status); RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("usb_write_port(): usb_submit_urb, status=%x\n", status)); switch (status) { case -ENODEV: padapter->bDriverStopped=_TRUE; break; default: break; } goto exit; } ret= _SUCCESS; // Commented by Albert 2009/10/13 // We add the URB_ZERO_PACKET flag to urb so that the host will send the zero packet automatically. /* if(bwritezero == _TRUE) { usb_bulkout_zero(pintfhdl, addr); } */ RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("-usb_write_port\n")); exit: if (ret != _SUCCESS) rtw_free_xmitbuf(pxmitpriv, pxmitbuf); _func_exit_; return ret; }
static void usb_write_port_complete(struct urb *purb, struct pt_regs *regs) { _irqL irqL; int i; struct xmit_buf *pxmitbuf = (struct xmit_buf *)purb->context; //struct xmit_frame *pxmitframe = (struct xmit_frame *)pxmitbuf->priv_data; //_adapter *padapter = pxmitframe->padapter; _adapter *padapter = pxmitbuf->padapter; struct xmit_priv *pxmitpriv = &padapter->xmitpriv; //struct pkt_attrib *pattrib = &pxmitframe->attrib; _func_enter_; switch(pxmitbuf->flags) { case VO_QUEUE_INX: pxmitpriv->voq_cnt--; break; case VI_QUEUE_INX: pxmitpriv->viq_cnt--; break; case BE_QUEUE_INX: pxmitpriv->beq_cnt--; break; case BK_QUEUE_INX: pxmitpriv->bkq_cnt--; break; case HIGH_QUEUE_INX: #ifdef CONFIG_AP_MODE rtw_chk_hi_queue_cmd(padapter); #endif break; default: break; } /* _enter_critical(&pxmitpriv->lock, &irqL); pxmitpriv->txirp_cnt--; switch(pattrib->priority) { case 1: case 2: pxmitpriv->bkq_cnt--; //DBG_8192C("pxmitpriv->bkq_cnt=%d\n", pxmitpriv->bkq_cnt); break; case 4: case 5: pxmitpriv->viq_cnt--; //DBG_8192C("pxmitpriv->viq_cnt=%d\n", pxmitpriv->viq_cnt); break; case 6: case 7: pxmitpriv->voq_cnt--; //DBG_8192C("pxmitpriv->voq_cnt=%d\n", pxmitpriv->voq_cnt); break; case 0: case 3: default: pxmitpriv->beq_cnt--; //DBG_8192C("pxmitpriv->beq_cnt=%d\n", pxmitpriv->beq_cnt); break; } _exit_critical(&pxmitpriv->lock, &irqL); if(pxmitpriv->txirp_cnt==0) { RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("usb_write_port_complete: txirp_cnt== 0, set allrxreturnevt!\n")); _rtw_up_sema(&(pxmitpriv->tx_retevt)); } */ //rtw_free_xmitframe(pxmitpriv, pxmitframe); if(padapter->bSurpriseRemoved || padapter->bDriverStopped ||padapter->bWritePortCancel) { RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("usb_write_port_complete:bDriverStopped(%d) OR bSurpriseRemoved(%d)", padapter->bDriverStopped, padapter->bSurpriseRemoved)); DBG_8192C("%s(): TX Warning! bDriverStopped(%d) OR bSurpriseRemoved(%d) bWritePortCancel(%d) pxmitbuf->ext_tag(%x) \n", __FUNCTION__,padapter->bDriverStopped, padapter->bSurpriseRemoved,padapter->bReadPortCancel,pxmitbuf->ext_tag); goto check_completion; } if (purb->status==0) { } else { RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("usb_write_port_complete : purb->status(%d) != 0 \n", purb->status)); DBG_871X("###=> urb_write_port_complete status(%d)\n",purb->status); if((purb->status==-EPIPE)||(purb->status==-EPROTO)) { //usb_clear_halt(pusbdev, purb->pipe); //msleep(10); sreset_set_wifi_error_status(padapter, USB_WRITE_PORT_FAIL); } else if (purb->status == -EINPROGRESS) { RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("usb_write_port_complete: EINPROGESS\n")); goto check_completion; } else if (purb->status == -ENOENT) { DBG_871X("%s: -ENOENT\n", __func__); goto check_completion; } else if (purb->status == -ECONNRESET) { DBG_871X("%s: -ECONNRESET\n", __func__); goto check_completion; } else if (purb->status == -ESHUTDOWN) { RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("usb_write_port_complete: ESHUTDOWN\n")); padapter->bDriverStopped=_TRUE; RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("usb_write_port_complete:bDriverStopped=TRUE\n")); goto check_completion; } else { padapter->bSurpriseRemoved=_TRUE; DBG_8192C("bSurpriseRemoved=TRUE\n"); //rtl8192cu_trigger_gpio_0(padapter); RT_TRACE(_module_hci_ops_os_c_,_drv_err_,("usb_write_port_complete:bSurpriseRemoved=TRUE\n")); goto check_completion; } } #ifdef DBG_CONFIG_ERROR_DETECT { HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); pHalData->srestpriv.last_tx_complete_time = rtw_get_current_time(); } #endif check_completion: _enter_critical(&pxmitpriv->lock_sctx, &irqL); rtw_sctx_done_err(&pxmitbuf->sctx, purb->status ? RTW_SCTX_DONE_WRITE_PORT_ERR : RTW_SCTX_DONE_SUCCESS); _exit_critical(&pxmitpriv->lock_sctx, &irqL); rtw_free_xmitbuf(pxmitpriv, pxmitbuf); //if(rtw_txframes_pending(padapter)) { tasklet_hi_schedule(&pxmitpriv->xmit_tasklet); } _func_exit_; }
u32 usb_write_port(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *wmem) { _irqL irqL; unsigned int pipe; int status; u32 ret = _FAIL, bwritezero = _FALSE; PURB purb = NULL; _adapter *padapter = (_adapter *)pintfhdl->padapter; struct dvobj_priv *pdvobj = adapter_to_dvobj(padapter); struct pwrctrl_priv *pwrctl = dvobj_to_pwrctl(pdvobj); struct xmit_priv *pxmitpriv = &padapter->xmitpriv; struct xmit_buf *pxmitbuf = (struct xmit_buf *)wmem; struct xmit_frame *pxmitframe = (struct xmit_frame *)pxmitbuf->priv_data; struct usb_device *pusbd = pdvobj->pusbdev; struct pkt_attrib *pattrib = &pxmitframe->attrib; if (RTW_CANNOT_TX(padapter)) { #ifdef DBG_TX RTW_INFO(" DBG_TX %s:%d bDriverStopped%s, bSurpriseRemoved:%s\n", __func__, __LINE__ , rtw_is_drv_stopped(padapter) ? "True" : "False" , rtw_is_surprise_removed(padapter) ? "True" : "False"); #endif rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_TX_DENY); goto exit; } _enter_critical(&pxmitpriv->lock, &irqL); switch (addr) { case VO_QUEUE_INX: pxmitpriv->voq_cnt++; pxmitbuf->flags = VO_QUEUE_INX; break; case VI_QUEUE_INX: pxmitpriv->viq_cnt++; pxmitbuf->flags = VI_QUEUE_INX; break; case BE_QUEUE_INX: pxmitpriv->beq_cnt++; pxmitbuf->flags = BE_QUEUE_INX; break; case BK_QUEUE_INX: pxmitpriv->bkq_cnt++; pxmitbuf->flags = BK_QUEUE_INX; break; case HIGH_QUEUE_INX: pxmitbuf->flags = HIGH_QUEUE_INX; break; default: pxmitbuf->flags = MGT_QUEUE_INX; break; } _exit_critical(&pxmitpriv->lock, &irqL); purb = pxmitbuf->pxmit_urb[0]; /* translate DMA FIFO addr to pipehandle */ #ifdef RTW_HALMAC pipe = ffaddr2pipehdl(pdvobj, pxmitbuf->bulkout_id); #else pipe = ffaddr2pipehdl(pdvobj, addr); #endif #ifdef CONFIG_REDUCE_USB_TX_INT if ((pxmitpriv->free_xmitbuf_cnt % NR_XMITBUFF == 0) || (pxmitbuf->buf_tag > XMITBUF_DATA)) purb->transfer_flags &= (~URB_NO_INTERRUPT); else { purb->transfer_flags |= URB_NO_INTERRUPT; /* RTW_INFO("URB_NO_INTERRUPT "); */ } #endif usb_fill_bulk_urb(purb, pusbd, pipe, pxmitframe->buf_addr, /* = pxmitbuf->pbuf */ cnt, usb_write_port_complete, pxmitbuf);/* context is pxmitbuf */ #ifdef CONFIG_USE_USB_BUFFER_ALLOC_TX purb->transfer_dma = pxmitbuf->dma_transfer_addr; purb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; purb->transfer_flags |= URB_ZERO_PACKET; #endif /* CONFIG_USE_USB_BUFFER_ALLOC_TX */ #ifdef USB_PACKET_OFFSET_SZ #if (USB_PACKET_OFFSET_SZ == 0) purb->transfer_flags |= URB_ZERO_PACKET; #endif #endif #if 0 if (bwritezero) purb->transfer_flags |= URB_ZERO_PACKET; #endif status = usb_submit_urb(purb, GFP_ATOMIC); if (!status) { #ifdef DBG_CONFIG_ERROR_DETECT { HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); pHalData->srestpriv.last_tx_time = rtw_get_current_time(); } #endif } else { rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_WRITE_PORT_ERR); RTW_INFO("usb_write_port, status=%d\n", status); switch (status) { case -ENODEV: rtw_set_drv_stopped(padapter); break; default: break; } goto exit; } ret = _SUCCESS; /* Commented by Albert 2009/10/13 * We add the URB_ZERO_PACKET flag to urb so that the host will send the zero packet automatically. */ /* if(bwritezero == _TRUE) { usb_bulkout_zero(pintfhdl, addr); } */ exit: if (ret != _SUCCESS) rtw_free_xmitbuf(pxmitpriv, pxmitbuf); return ret; }
s32 rtl8812au_xmitframe_complete(_adapter *padapter, struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf) { HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); struct xmit_frame *pxmitframe = NULL; struct xmit_frame *pfirstframe = NULL; // aggregate variable struct hw_xmit *phwxmit; struct sta_info *psta = NULL; struct tx_servq *ptxservq = NULL; _irqL irqL; _list *xmitframe_plist = NULL, *xmitframe_phead = NULL; u32 pbuf; // next pkt address u32 pbuf_tail; // last pkt tail u32 len; // packet length, except TXDESC_SIZE and PKT_OFFSET u32 bulkSize = pHalData->UsbBulkOutSize; u8 descCount; u32 bulkPtr; // dump frame variable u32 ff_hwaddr; #ifndef IDEA_CONDITION int res = _SUCCESS; #endif RT_TRACE(_module_rtl8192c_xmit_c_, _drv_info_, ("+xmitframe_complete\n")); // check xmitbuffer is ok if (pxmitbuf == NULL) { pxmitbuf = rtw_alloc_xmitbuf(pxmitpriv); if (pxmitbuf == NULL){ //DBG_871X("%s #1, connot alloc xmitbuf!!!! \n",__FUNCTION__); return _FALSE; } } //DBG_8192C("%s ===================================== \n",__FUNCTION__); //3 1. pick up first frame do { rtw_free_xmitframe(pxmitpriv, pxmitframe); pxmitframe = rtw_dequeue_xframe(pxmitpriv, pxmitpriv->hwxmits, pxmitpriv->hwxmit_entry); if (pxmitframe == NULL) { // no more xmit frame, release xmit buffer //DBG_8192C("no more xmit frame ,return\n"); rtw_free_xmitbuf(pxmitpriv, pxmitbuf); return _FALSE; } #ifndef IDEA_CONDITION if (pxmitframe->frame_tag != DATA_FRAMETAG) { RT_TRACE(_module_rtl8192c_xmit_c_, _drv_err_, ("xmitframe_complete: frame tag(%d) is not DATA_FRAMETAG(%d)!\n", pxmitframe->frame_tag, DATA_FRAMETAG)); // rtw_free_xmitframe(pxmitpriv, pxmitframe); continue; } // TID 0~15 if ((pxmitframe->attrib.priority < 0) || (pxmitframe->attrib.priority > 15)) { RT_TRACE(_module_rtl8192c_xmit_c_, _drv_err_, ("xmitframe_complete: TID(%d) should be 0~15!\n", pxmitframe->attrib.priority)); // rtw_free_xmitframe(pxmitpriv, pxmitframe); continue; } #endif //DBG_8192C("==> pxmitframe->attrib.priority:%d\n",pxmitframe->attrib.priority); pxmitframe->pxmitbuf = pxmitbuf; pxmitframe->buf_addr = pxmitbuf->pbuf; pxmitbuf->priv_data = pxmitframe; pxmitframe->agg_num = 1; // alloc xmitframe should assign to 1. #ifdef CONFIG_TX_EARLY_MODE pxmitframe->pkt_offset = (PACKET_OFFSET_SZ/8)+1; // 2; // first frame of aggregation, reserve one offset for EM info ,another for usb bulk-out block check #else pxmitframe->pkt_offset = (PACKET_OFFSET_SZ/8); // 1; // first frame of aggregation, reserve offset #endif if (rtw_xmitframe_coalesce(padapter, pxmitframe->pkt, pxmitframe) == _FALSE) { DBG_871X("%s coalesce 1st xmitframe failed \n",__FUNCTION__); continue; } // always return ndis_packet after rtw_xmitframe_coalesce rtw_os_xmit_complete(padapter, pxmitframe); break; } while (1); //3 2. aggregate same priority and same DA(AP or STA) frames pfirstframe = pxmitframe; len = xmitframe_need_length(pfirstframe) + TXDESC_SIZE+(pfirstframe->pkt_offset*PACKET_OFFSET_SZ); pbuf_tail = len; pbuf = _RND8(pbuf_tail); // check pkt amount in one bulk descCount = 0; bulkPtr = bulkSize; if (pbuf < bulkPtr) descCount++; if (descCount == pHalData->UsbTxAggDescNum) goto agg_end; else { descCount = 0; bulkPtr = ((pbuf / bulkSize) + 1) * bulkSize; // round to next bulkSize } // dequeue same priority packet from station tx queue psta = pfirstframe->attrib.psta; switch (pfirstframe->attrib.priority) { case 1: case 2: ptxservq = &(psta->sta_xmitpriv.bk_q); phwxmit = pxmitpriv->hwxmits + 3; break; case 4: case 5: ptxservq = &(psta->sta_xmitpriv.vi_q); phwxmit = pxmitpriv->hwxmits + 1; break; case 6: case 7: ptxservq = &(psta->sta_xmitpriv.vo_q); phwxmit = pxmitpriv->hwxmits; break; case 0: case 3: default: ptxservq = &(psta->sta_xmitpriv.be_q); phwxmit = pxmitpriv->hwxmits + 2; break; } //DBG_8192C("==> pkt_no=%d,pkt_len=%d,len=%d,RND8_LEN=%d,pkt_offset=0x%02x\n", //pxmitframe->agg_num,pxmitframe->attrib.last_txcmdsz,len,pbuf,pxmitframe->pkt_offset ); _enter_critical_bh(&pxmitpriv->lock, &irqL); xmitframe_phead = get_list_head(&ptxservq->sta_pending); xmitframe_plist = get_next(xmitframe_phead); while (rtw_end_of_queue_search(xmitframe_phead, xmitframe_plist) == _FALSE) { pxmitframe = LIST_CONTAINOR(xmitframe_plist, struct xmit_frame, list); xmitframe_plist = get_next(xmitframe_plist); if(_FAIL == rtw_hal_busagg_qsel_check(padapter,pfirstframe->attrib.qsel,pxmitframe->attrib.qsel)) break; pxmitframe->agg_num = 0; // not first frame of aggregation #ifdef CONFIG_TX_EARLY_MODE pxmitframe->pkt_offset = 1;// not first frame of aggregation,reserve offset for EM Info #else pxmitframe->pkt_offset = 0; // not first frame of aggregation, no need to reserve offset #endif len = xmitframe_need_length(pxmitframe) + TXDESC_SIZE +(pxmitframe->pkt_offset*PACKET_OFFSET_SZ); if (_RND8(pbuf + len) > MAX_XMITBUF_SZ) //if (_RND8(pbuf + len) > (MAX_XMITBUF_SZ/2))//to do : for TX TP finial tune , Georgia 2012-0323 { //DBG_8192C("%s....len> MAX_XMITBUF_SZ\n",__FUNCTION__); pxmitframe->agg_num = 1; pxmitframe->pkt_offset = 1; break; } rtw_list_delete(&pxmitframe->list); ptxservq->qcnt--; phwxmit->accnt--; #ifndef IDEA_CONDITION // suppose only data frames would be in queue if (pxmitframe->frame_tag != DATA_FRAMETAG) { RT_TRACE(_module_rtl8192c_xmit_c_, _drv_err_, ("xmitframe_complete: frame tag(%d) is not DATA_FRAMETAG(%d)!\n", pxmitframe->frame_tag, DATA_FRAMETAG)); rtw_free_xmitframe(pxmitpriv, pxmitframe); continue; } // TID 0~15 if ((pxmitframe->attrib.priority < 0) || (pxmitframe->attrib.priority > 15)) { RT_TRACE(_module_rtl8192c_xmit_c_, _drv_err_, ("xmitframe_complete: TID(%d) should be 0~15!\n", pxmitframe->attrib.priority)); rtw_free_xmitframe(pxmitpriv, pxmitframe); continue; } #endif // pxmitframe->pxmitbuf = pxmitbuf; pxmitframe->buf_addr = pxmitbuf->pbuf + pbuf; if (rtw_xmitframe_coalesce(padapter, pxmitframe->pkt, pxmitframe) == _FALSE) { DBG_871X("%s coalesce failed \n",__FUNCTION__); rtw_free_xmitframe(pxmitpriv, pxmitframe); continue; } //DBG_8192C("==> pxmitframe->attrib.priority:%d\n",pxmitframe->attrib.priority); // always return ndis_packet after rtw_xmitframe_coalesce rtw_os_xmit_complete(padapter, pxmitframe); // (len - TXDESC_SIZE) == pxmitframe->attrib.last_txcmdsz update_txdesc(pxmitframe, pxmitframe->buf_addr, pxmitframe->attrib.last_txcmdsz,_TRUE); // don't need xmitframe any more rtw_free_xmitframe(pxmitpriv, pxmitframe); // handle pointer and stop condition pbuf_tail = pbuf + len; pbuf = _RND8(pbuf_tail); pfirstframe->agg_num++; #ifdef CONFIG_TX_EARLY_MODE pxmitpriv->agg_pkt[pfirstframe->agg_num-1].offset = _RND8(len); pxmitpriv->agg_pkt[pfirstframe->agg_num-1].pkt_len = pxmitframe->attrib.last_txcmdsz; #endif if (MAX_TX_AGG_PACKET_NUMBER == pfirstframe->agg_num) break; if (pbuf < bulkPtr) { descCount++; if (descCount == pHalData->UsbTxAggDescNum) break; } else { descCount = 0; bulkPtr = ((pbuf / bulkSize) + 1) * bulkSize; } }//end while( aggregate same priority and same DA(AP or STA) frames) if (_rtw_queue_empty(&ptxservq->sta_pending) == _TRUE) rtw_list_delete(&ptxservq->tx_pending); _exit_critical_bh(&pxmitpriv->lock, &irqL); agg_end: #ifdef CONFIG_80211N_HT if ((pfirstframe->attrib.ether_type != 0x0806) && (pfirstframe->attrib.ether_type != 0x888e) && (pfirstframe->attrib.ether_type != 0x88b4) && (pfirstframe->attrib.dhcp_pkt != 1)) { rtw_issue_addbareq_cmd(padapter, pfirstframe); } #endif //CONFIG_80211N_HT #ifndef CONFIG_USE_USB_BUFFER_ALLOC_TX //3 3. update first frame txdesc if ((PACKET_OFFSET_SZ != 0) && ((pbuf_tail % bulkSize) == 0)) { // remove pkt_offset pbuf_tail -= PACKET_OFFSET_SZ; pfirstframe->buf_addr += PACKET_OFFSET_SZ; pfirstframe->pkt_offset--; //DBG_8192C("$$$$$ buf size equal to USB block size $$$$$$\n"); } #endif // CONFIG_USE_USB_BUFFER_ALLOC_TX update_txdesc(pfirstframe, pfirstframe->buf_addr, pfirstframe->attrib.last_txcmdsz,_TRUE); #ifdef CONFIG_TX_EARLY_MODE //prepare EM info for first frame, agg_num value start from 1 pxmitpriv->agg_pkt[0].offset = _RND8(pfirstframe->attrib.last_txcmdsz +TXDESC_SIZE +(pfirstframe->pkt_offset*PACKET_OFFSET_SZ)); pxmitpriv->agg_pkt[0].pkt_len = pfirstframe->attrib.last_txcmdsz;//get from rtw_xmitframe_coalesce UpdateEarlyModeInfo8812(pxmitpriv,pxmitbuf ); #endif //3 4. write xmit buffer to USB FIFO ff_hwaddr = rtw_get_ff_hwaddr(pfirstframe); //DBG_8192C("%s ===================================== write port,buf_size(%d) \n",__FUNCTION__,pbuf_tail); // xmit address == ((xmit_frame*)pxmitbuf->priv_data)->buf_addr rtw_write_port(padapter, ff_hwaddr, pbuf_tail, (u8*)pxmitbuf); //3 5. update statisitc pbuf_tail -= (pfirstframe->agg_num * TXDESC_SIZE); pbuf_tail -= (pfirstframe->pkt_offset * PACKET_OFFSET_SZ); rtw_count_tx_stats(padapter, pfirstframe, pbuf_tail); rtw_free_xmitframe(pxmitpriv, pfirstframe); return _TRUE; }
s32 rtl8723_dequeue_writeport(PADAPTER padapter, u8 *freePage) { struct mlme_priv *pmlmepriv = &padapter->mlmepriv; struct xmit_priv *pxmitpriv = &padapter->xmitpriv; struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter); struct xmit_buf *pxmitbuf; //struct xmit_frame *pframe; PADAPTER pri_padapter = padapter; u32 deviceId; u32 requiredPage; u8 PageIdx; _irqL irql; u32 n; s32 ret = 0; //HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); #ifdef CONFIG_CONCURRENT_MODE s32 buddy_rm_stop = _FAIL; #endif #ifdef CONFIG_CONCURRENT_MODE if(rtw_buddy_adapter_up(padapter)) ret = check_buddy_fwstate( padapter, _FW_UNDER_SURVEY); #endif ret = ret || check_fwstate(pmlmepriv, _FW_UNDER_SURVEY); if (_TRUE == ret) pxmitbuf = dequeue_pending_xmitbuf_under_survey(pxmitpriv); else pxmitbuf = dequeue_pending_xmitbuf(pxmitpriv); if (pxmitbuf == NULL) return _TRUE; //pframe = (struct xmit_frame*)pxmitbuf->priv_data; //requiredPage = pframe->pg_num; requiredPage = pxmitbuf->pg_num; //translate queue index to sdio fifo addr deviceId = pdvobjpriv->Queue2Pipe[pxmitbuf->ff_hwaddr]; // translate sdio fifo addr to tx fifo page index switch (deviceId) { case WLAN_TX_HIQ_DEVICE_ID: PageIdx = HI_QUEUE_IDX; break; case WLAN_TX_MIQ_DEVICE_ID: PageIdx = MID_QUEUE_IDX; break; case WLAN_TX_LOQ_DEVICE_ID: PageIdx = LOW_QUEUE_IDX; break; } // check if hardware tx fifo page is enough n = 0; // _enter_critical_bh(&phal->SdioTxFIFOFreePageLock, &irql); do { if (requiredPage <= freePage[PageIdx]) { freePage[PageIdx] -= requiredPage; break; } // The number of page which public page included is available. if ((freePage[PageIdx] + freePage[PUBLIC_QUEUE_IDX]) > (requiredPage + 1)) { u8 requiredPublicPage; requiredPublicPage = requiredPage - freePage[PageIdx]; freePage[PageIdx] = 0; freePage[PUBLIC_QUEUE_IDX] -= requiredPublicPage; break; } // _exit_critical_bh(&phal->SdioTxFIFOFreePageLock, &irql); ret = (padapter->bDriverStopped == _TRUE) || (padapter->bSurpriseRemoved == _TRUE); if (ret) { RT_TRACE(_module_hal_xmit_c_, _drv_notice_, ("%s: bSurpriseRemoved(update TX FIFO page)\n", __func__)); goto free_xmitbuf; } n++; //if ((n & 0x3FF) == 0) if ((n % 2) == 0) { if (n > 5000) { DBG_8192C(KERN_NOTICE "%s: FIFO starvation!(%d) len=%d agg=%d page=(R)%d(A)%d\n", __func__, n, pxmitbuf->len, pxmitbuf->agg_num, pxmitbuf->pg_num, freePage[PageIdx] + freePage[PUBLIC_QUEUE_IDX]); } else { //RT_TRACE(_module_hal_xmit_c_, _drv_notice_, // ("%s: FIFO starvation!(%d) len=%d agg=%d page=(R)%d(A)%d\n", // __FUNCTION__, n, pxmitbuf->len, pxmitbuf->agg_num, pxmitbuf->pg_num, freePage[PageIdx] + freePage[PUBLIC_QUEUE_IDX])); } //rtw_yield_os(); rtw_msleep_os(1); } // Total number of page is NOT available, so update current FIFO status #ifdef CONFIG_CONCURRENT_MODE if (padapter->adapter_type > 0) pri_padapter = padapter->pbuddy_adapter; #endif HalQueryTxBufferStatus8723ASdio(pri_padapter); } while (1); if ((padapter->bSurpriseRemoved == _TRUE) #ifdef CONFIG_CONCURRENT_MODE ||((padapter->pbuddy_adapter)&& (padapter->pbuddy_adapter->bSurpriseRemoved)) #endif ){ RT_TRACE(_module_hal_xmit_c_, _drv_notice_, ("%s: bSurpriseRemoved(wirte port)\n", __FUNCTION__)); goto free_xmitbuf; } rtw_write_port(padapter, deviceId, pxmitbuf->len, (u8 *)pxmitbuf); free_xmitbuf: //rtw_free_xmitframe(pxmitpriv, pframe); //pxmitbuf->priv_data = NULL; rtw_free_xmitbuf(pxmitpriv, pxmitbuf); return _FAIL; }
/* * Description: * Aggregation packets and send to hardware * * Return: * 0 Success * -1 Hardware resource(TX FIFO) not ready * -2 Software resource(xmitbuf) not ready */ static s32 xmit_xmitframes(PADAPTER padapter, struct xmit_priv *pxmitpriv) { s32 err, ret; u32 k; struct hw_xmit *hwxmits; u8 no_res, idx, hwentry; _irqL irql; // _irqL irqL0, irqL1; struct tx_servq *ptxservq; _list *sta_plist, *sta_phead, *frame_plist, *frame_phead; struct xmit_frame *pxmitframe; _queue *pframe_queue; struct xmit_buf *pxmitbuf; u32 txlen; err = 0; no_res = _FALSE; hwxmits = pxmitpriv->hwxmits; hwentry = pxmitpriv->hwxmit_entry; ptxservq = NULL; pxmitframe = NULL; pframe_queue = NULL; pxmitbuf = NULL; // 0(VO), 1(VI), 2(BE), 3(BK) for (idx = 0; idx < hwentry; idx++, hwxmits++) { // _enter_critical(&hwxmits->sta_queue->lock, &irqL0); _enter_critical_bh(&pxmitpriv->lock, &irql); sta_phead = get_list_head(hwxmits->sta_queue); sta_plist = get_next(sta_phead); while (rtw_end_of_queue_search(sta_phead, sta_plist) == _FALSE) { ptxservq = LIST_CONTAINOR(sta_plist, struct tx_servq, tx_pending); sta_plist = get_next(sta_plist); pframe_queue = &ptxservq->sta_pending; // _enter_critical(&pframe_queue->lock, &irqL1); //_enter_critical_bh(&pxmitpriv->lock, &irql); frame_phead = get_list_head(pframe_queue); while (rtw_is_list_empty(frame_phead) == _FALSE) { frame_plist = get_next(frame_phead); pxmitframe = LIST_CONTAINOR(frame_plist, struct xmit_frame, list); // check xmit_buf size enough or not txlen = TXDESC_SIZE + rtw_wlan_pkt_size(pxmitframe); if ((NULL == pxmitbuf) || ((pxmitbuf->ptail + txlen) > pxmitbuf->pend) #ifdef SDIO_TX_AGG_MAX || (k >= SDIO_TX_AGG_MAX) #endif ) { if (pxmitbuf) { struct xmit_frame *pframe; pframe = (struct xmit_frame*)pxmitbuf->priv_data; pframe->agg_num = k; pxmitbuf->agg_num = k; rtl8723a_update_txdesc(pframe, pframe->buf_addr); rtw_free_xmitframe(pxmitpriv, pframe); pxmitbuf->priv_data = NULL; enqueue_pending_xmitbuf(pxmitpriv, pxmitbuf); //rtw_yield_os(); } pxmitbuf = rtw_alloc_xmitbuf(pxmitpriv); if (pxmitbuf == NULL) { RT_TRACE(_module_hal_xmit_c_, _drv_err_, ("%s: xmit_buf is not enough!\n", __FUNCTION__)); err = -2; break; } k = 0; } // ok to send, remove frame from queue //_enter_critical_bh(&pxmitpriv->lock, &irql); #ifdef CONFIG_AP_MODE if (check_fwstate(&padapter->mlmepriv, WIFI_AP_STATE) == _TRUE) { if ((pxmitframe->attrib.psta->state & WIFI_SLEEP_STATE) && (pxmitframe->attrib.triggered == 0)) { //_exit_critical_bh(&pxmitpriv->lock, &irql); DBG_8192C("%s: one not triggered pkt in queue when STA sleep\n", __func__); break; } } #endif rtw_list_delete(&pxmitframe->list); ptxservq->qcnt--; hwxmits->accnt--; if (k == 0) { pxmitbuf->ff_hwaddr = rtw_get_ff_hwaddr(pxmitframe); pxmitbuf->priv_data = (u8*)pxmitframe; } // coalesce the xmitframe to xmitbuf pxmitframe->pxmitbuf = pxmitbuf; pxmitframe->buf_addr = pxmitbuf->ptail; ret = rtw_xmitframe_coalesce(padapter, pxmitframe->pkt, pxmitframe); if (ret == _FAIL) { RT_TRACE(_module_hal_xmit_c_, _drv_err_, ("%s: coalesce FAIL!", __FUNCTION__)); // Todo: error handler DBG_871X("%s: coalesce FAIL!", __FUNCTION__); } else { k++; if (k != 1) rtl8723a_update_txdesc(pxmitframe, pxmitframe->buf_addr); rtw_count_tx_stats(padapter, pxmitframe, pxmitframe->attrib.last_txcmdsz); txlen = TXDESC_SIZE + pxmitframe->attrib.last_txcmdsz; pxmitframe->pg_num = (txlen + 127)/128; pxmitbuf->pg_num += (txlen + 127)/128; //if (k != 1) // ((struct xmit_frame*)pxmitbuf->priv_data)->pg_num += pxmitframe->pg_num; pxmitbuf->ptail += _RND(txlen, 8); // round to 8 bytes alignment pxmitbuf->len = _RND(pxmitbuf->len, 8) + txlen; } if (k != 1) rtw_free_xmitframe(pxmitpriv, pxmitframe); pxmitframe = NULL; } //_enter_critical_bh(&pxmitpriv->lock, &irql); if (_rtw_queue_empty(pframe_queue) == _TRUE) rtw_list_delete(&ptxservq->tx_pending); //_exit_critical_bh(&pxmitpriv->lock, &irql); // _exit_critical(&pframe_queue->lock, &irqL1); //_exit_critical_bh(&pxmitpriv->lock, &irql); if (err) break; } // _exit_critical(&hwxmits->sta_queue->lock, &irqL0); _exit_critical_bh(&pxmitpriv->lock, &irql); // dump xmit_buf to hw tx fifo if (pxmitbuf) { RT_TRACE(_module_hal_xmit_c_, _drv_notice_, ("pxmitbuf->len=%d enqueue\n",pxmitbuf->len)); if (pxmitbuf->len > 0) { struct xmit_frame *pframe; pframe = (struct xmit_frame*)pxmitbuf->priv_data; pframe->agg_num = k; pxmitbuf->agg_num = k; rtl8723a_update_txdesc(pframe, pframe->buf_addr); rtw_free_xmitframe(pxmitpriv, pframe); pxmitbuf->priv_data = NULL; enqueue_pending_xmitbuf(pxmitpriv, pxmitbuf); rtw_yield_os(); } else rtw_free_xmitbuf(pxmitpriv, pxmitbuf); pxmitbuf = NULL; } if (err) break; } return err; }
static s32 rtl8723_dequeue_writeport(PADAPTER padapter) { struct mlme_priv *pmlmepriv = &padapter->mlmepriv; struct xmit_priv *pxmitpriv = &padapter->xmitpriv; struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter); struct xmit_buf *pxmitbuf; PADAPTER pri_padapter = padapter; s32 ret = 0; u8 PageIdx = 0; u32 deviceId; u8 bUpdatePageNum = false; ret = ret || check_fwstate(pmlmepriv, _FW_UNDER_SURVEY); if (true == ret) pxmitbuf = dequeue_pending_xmitbuf_under_survey(pxmitpriv); else pxmitbuf = dequeue_pending_xmitbuf(pxmitpriv); if (pxmitbuf == NULL) return true; deviceId = ffaddr2deviceId(pdvobjpriv, pxmitbuf->ff_hwaddr); // translate fifo addr to queue index switch (deviceId) { case WLAN_TX_HIQ_DEVICE_ID: PageIdx = HI_QUEUE_IDX; break; case WLAN_TX_MIQ_DEVICE_ID: PageIdx = MID_QUEUE_IDX; break; case WLAN_TX_LOQ_DEVICE_ID: PageIdx = LOW_QUEUE_IDX; break; } query_free_page: // check if hardware tx fifo page is enough if( false == rtw_hal_sdio_query_tx_freepage(pri_padapter, PageIdx, pxmitbuf->pg_num)) { if (!bUpdatePageNum) { // Total number of page is NOT available, so update current FIFO status HalQueryTxBufferStatus8723BSdio(padapter); bUpdatePageNum = true; goto query_free_page; } else { bUpdatePageNum = false; enqueue_pending_xmitbuf_to_head(pxmitpriv, pxmitbuf); return true; } } if ((padapter->bSurpriseRemoved == true) || (padapter->bDriverStopped == true)){ RT_TRACE(_module_hal_xmit_c_, _drv_notice_, ("%s: bSurpriseRemoved(wirte port)\n", __FUNCTION__)); goto free_xmitbuf; } if (rtw_sdio_wait_enough_TxOQT_space(padapter, pxmitbuf->agg_num) == false) { goto free_xmitbuf; } traffic_check_for_leave_lps(padapter, true, pxmitbuf->agg_num); rtw_write_port(padapter, deviceId, pxmitbuf->len, (u8 *)pxmitbuf); rtw_hal_sdio_update_tx_freepage(pri_padapter, PageIdx, pxmitbuf->pg_num); free_xmitbuf: //rtw_free_xmitframe(pxmitpriv, pframe); //pxmitbuf->priv_data = NULL; rtw_free_xmitbuf(pxmitpriv, pxmitbuf); #ifdef CONFIG_SDIO_TX_TASKLET tasklet_hi_schedule(&pxmitpriv->xmit_tasklet); #endif return _FAIL; }