struct xmit_frame *rtw_IOL_accquire_xmit_frame(struct adapter *adapter) { struct xmit_frame *xmit_frame; struct xmit_buf *xmitbuf; struct pkt_attrib *pattrib; struct xmit_priv *pxmitpriv = &(adapter->xmitpriv); xmit_frame = rtw_alloc_xmitframe(pxmitpriv); if (xmit_frame == NULL) { DBG_88E("%s rtw_alloc_xmitframe return null\n", __func__); goto exit; } xmitbuf = rtw_alloc_xmitbuf(pxmitpriv); if (xmitbuf == NULL) { DBG_88E("%s rtw_alloc_xmitbuf return null\n", __func__); rtw_free_xmitframe(pxmitpriv, xmit_frame); xmit_frame = NULL; goto exit; } xmit_frame->frame_tag = MGNT_FRAMETAG; xmit_frame->pxmitbuf = xmitbuf; xmit_frame->buf_addr = xmitbuf->pbuf; xmitbuf->priv_data = xmit_frame; pattrib = &xmit_frame->attrib; update_mgntframe_attrib(adapter, pattrib); pattrib->qsel = 0x10;/* Beacon */ pattrib->subtype = WIFI_BEACON; pattrib->pktlen = 0; pattrib->last_txcmdsz = 0; exit: return xmit_frame; }
/* * 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; }
/* * 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; }
struct xmit_frame *rtw_IOL_accquire_xmit_frame(ADAPTER *adapter) { struct xmit_frame *xmit_frame; struct xmit_buf *xmitbuf; struct pkt_attrib *pattrib; struct xmit_priv *pxmitpriv = &(adapter->xmitpriv); #if 1 if ((xmit_frame = rtw_alloc_xmitframe(pxmitpriv)) == NULL) { DBG_871X("%s rtw_alloc_xmitframe return null\n", __FUNCTION__); goto exit; } if ((xmitbuf = rtw_alloc_xmitbuf(pxmitpriv)) == NULL) { DBG_871X("%s rtw_alloc_xmitbuf return null\n", __FUNCTION__); rtw_free_xmitframe(pxmitpriv, xmit_frame); xmit_frame=NULL; goto exit; } xmit_frame->frame_tag = MGNT_FRAMETAG; xmit_frame->pxmitbuf = xmitbuf; xmit_frame->buf_addr = xmitbuf->pbuf; xmitbuf->priv_data = xmit_frame; pattrib = &xmit_frame->attrib; update_mgntframe_attrib(adapter, pattrib); pattrib->qsel = 0x10;//Beacon pattrib->subtype = WIFI_BEACON; pattrib->pktlen = pattrib->last_txcmdsz = 0; #else if ((xmit_frame = alloc_mgtxmitframe(pxmitpriv)) == NULL) { DBG_871X("%s alloc_mgtxmitframe return null\n", __FUNCTION__); } else { pattrib = &xmit_frame->attrib; update_mgntframe_attrib(adapter, pattrib); pattrib->qsel = 0x10; pattrib->pktlen = pattrib->last_txcmdsz = 0; } #endif exit: return xmit_frame; }
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; }
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; }
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 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; }
/* * 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; }
/* * 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; }
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; }
s32 rtl8192du_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 = pxmitpriv->hwxmits; struct tx_servq *ptxservq = NULL; _irqL irqL; _list *xmitframe_plist = NULL, *xmitframe_phead = NULL; u32 pbuf=0; // next pkt address u32 pbuf_tail; // last pkt tail u32 len=0; //packet length, except TXDESC_SIZE and PKT_OFFSET u32 aggMaxLength = MAX_XMITBUF_SZ; u32 bulkSize = pHalData->UsbBulkOutSize; u32 bulkPtr=0; u8 descCount=0; u8 ac_index; u8 bfirst = _TRUE;//first aggregation xmitframe u8 bulkstart = _FALSE; // 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; } if(pHalData->MacPhyMode92D==SINGLEMAC_SINGLEPHY) aggMaxLength = MAX_XMITBUF_SZ; else aggMaxLength = 0x3D00; do { //3 1. pick up first frame if(bfirst) { 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 = USB_92D_DUMMY_OFFSET; // first frame of aggregation, reserve 2 offset for 512 alignment and early mode pfirstframe = pxmitframe; _enter_critical_bh(&pxmitpriv->lock, &irqL); ptxservq = rtw_get_sta_pending(padapter, pfirstframe->attrib.psta, pfirstframe->attrib.priority, (u8 *)(&ac_index)); _exit_critical_bh(&pxmitpriv->lock, &irqL); } //3 2. aggregate same priority and same DA(AP or STA) frames else { // dequeue same priority packet from station tx queue _enter_critical_bh(&pxmitpriv->lock, &irqL); if (_rtw_queue_empty(&ptxservq->sta_pending) == _FALSE) { xmitframe_phead = get_list_head(&ptxservq->sta_pending); xmitframe_plist = get_next(xmitframe_phead); pxmitframe = LIST_CONTAINOR(xmitframe_plist, struct xmit_frame, list); len = xmitframe_need_length(pxmitframe) + TXDESC_SIZE + ((USB_92D_DUMMY_OFFSET - 1) * PACKET_OFFSET_SZ); if (pbuf + _RND8(len) > aggMaxLength) { bulkstart = _TRUE; } else { rtw_list_delete(&pxmitframe->list); ptxservq->qcnt--; phwxmit[ac_index].accnt--; //Remove sta node when there is no pending packets. if (_rtw_queue_empty(&ptxservq->sta_pending) == _TRUE) rtw_list_delete(&ptxservq->tx_pending); } } else { bulkstart = _TRUE; } _exit_critical_bh(&pxmitpriv->lock, &irqL); if(bulkstart) { break; } pxmitframe->buf_addr = pxmitbuf->pbuf + pbuf; pxmitframe->agg_num = 0; // not first frame of aggregation pxmitframe->pkt_offset = USB_92D_DUMMY_OFFSET - 1; // not first frame of aggregation, reserve 1 offset for early mode }
/* * 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(struct adapter *padapter, struct xmit_priv *pxmitpriv) { s32 err, ret; u32 k = 0; struct hw_xmit *hwxmits, *phwxmit; u8 no_res, idx, hwentry; struct tx_servq *ptxservq; struct list_head *sta_plist, *sta_phead, *frame_plist, *frame_phead; struct xmit_frame *pxmitframe; struct __queue *pframe_queue; struct xmit_buf *pxmitbuf; u32 txlen, max_xmit_len; 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; } } max_xmit_len = rtw_hal_get_sdio_tx_max_length(padapter, inx[idx]); spin_lock_bh(&pxmitpriv->lock); 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 (sta_phead != sta_plist) { 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 (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) || ((_RND(pxmitbuf->len, 8) + txlen) > max_xmit_len) || (k >= (rtw_hal_sdio_max_txoqt_free_space(padapter)-1)) ) { 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 */ /* yield(); */ } 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", __func__); #endif err = -2; up(&(pxmitpriv->xmit_sema)); break; } k = 0; } /* ok to send, remove frame from queue */ 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; } } list_del_init(&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!", __func__); /* 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 (list_empty(&pframe_queue->queue)) list_del_init(&ptxservq->tx_pending); if (err) break; } spin_unlock_bh(&pxmitpriv->lock); /* 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); yield(); } else rtw_free_xmitbuf(pxmitpriv, pxmitbuf); pxmitbuf = NULL; } if (err) break; } return err; }