/* * Description: * Write to TX FIFO * Align write size block size, * and make sure data could be written in one command. * * Parameters: * pintfhdl a pointer of intf_hdl * addr port ID * cnt size to write * wmem data pointer to write * * Return: * _SUCCESS(1) Success * _FAIL(0) Fail */ static u32 sdio_write_port( struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *mem) { PADAPTER padapter; PSDIO_DATA psdio; s32 err; struct xmit_buf *xmitbuf = (struct xmit_buf *)mem; padapter = pintfhdl->padapter; psdio = &adapter_to_dvobj(padapter)->intf_data; if (padapter->hw_init_completed == _FALSE) { DBG_871X("%s [addr=0x%x cnt=%d] padapter->hw_init_completed == _FALSE\n",__func__,addr,cnt); return _FAIL; } cnt = _RND4(cnt); HalSdioGetCmdAddr8723BSdio(padapter, addr, cnt >> 2, &addr); if (cnt > psdio->block_transfer_len) cnt = _RND(cnt, psdio->block_transfer_len); // cnt = sdio_align_size(cnt); err = sd_write(pintfhdl, addr, cnt, xmitbuf->pdata); rtw_sctx_done_err(&xmitbuf->sctx, err ? RTW_SCTX_DONE_WRITE_PORT_ERR : RTW_SCTX_DONE_SUCCESS); if (err) return _FAIL; return _SUCCESS; }
/* * Description: * Write to TX FIFO * Align write size block size, * and make sure data could be written in one command. * * Parameters: * pintfhdl a pointer of intf_hdl * addr port ID * cnt size to write * wmem data pointer to write * * Return: * _SUCCESS(1) Success * _FAIL(0) Fail */ static u32 sdio_write_port( struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *mem) { PADAPTER padapter; PSDIO_DATA psdio; s32 err; padapter = pintfhdl->padapter; psdio = &padapter->dvobjpriv.intf_data; cnt = _RND4(cnt); HalSdioGetCmdAddr8723ASdio(padapter, addr, cnt >> 2, &addr); if (cnt > psdio->block_transfer_len) cnt = _RND(cnt, psdio->block_transfer_len); // cnt = sdio_align_size(cnt); err = sd_write(psdio, addr, cnt, mem); if (err) return _FAIL; return _SUCCESS; }
/* * Description: * Read from RX FIFO * Round read size to block size, * and make sure data transfer will be done in one command. * * Parameters: * pintfhdl a pointer of intf_hdl * addr port ID * cnt size to read * rmem address to put data * * Return: * _SUCCESS(1) Success * _FAIL(0) Fail */ static u32 sdio_read_port( struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *mem) { PADAPTER padapter = pintfhdl->padapter; PSDIO_DATA psdio= &adapter_to_dvobj(padapter)->intf_data; HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); s32 err; HalSdioGetCmdAddr8723ASdio(padapter, addr, pHalData->SdioRxFIFOCnt++, &addr); cnt = _RND4(cnt); if (cnt > psdio->block_transfer_len) cnt = _RND(cnt, psdio->block_transfer_len); // cnt = sdio_align_size(cnt); err = _sd_read(pintfhdl, addr, cnt, mem); //err = sd_read(pintfhdl, addr, cnt, mem); if (err) return _FAIL; return _SUCCESS; }
static struct recv_buf* sd_recv_rxfifo(PADAPTER padapter, u32 size) { u32 readsize, allocsize, ret; u8 *preadbuf; _pkt *ppkt; struct recv_priv *precvpriv; struct recv_buf *precvbuf; readsize = size; //3 1. alloc skb // align to block size allocsize = _RND(readsize, padapter->dvobjpriv.intf_data.block_transfer_len); #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)) // http://www.mail-archive.com/[email protected]/msg17214.html ppkt = dev_alloc_skb(allocsize); #else ppkt = netdev_alloc_skb(padapter->pnetdev, allocsize); #endif if (ppkt == NULL) { RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("%s: alloc_skb fail! alloc=%d read=%d\n", __FUNCTION__, allocsize, readsize)); return NULL; } //3 2. read data from rxfifo preadbuf = skb_put(ppkt, readsize); // rtw_read_port(padapter, WLAN_RX0FF_DEVICE_ID, readsize, preadbuf); ret = sdio_read_port(&padapter->iopriv.intf, WLAN_RX0FF_DEVICE_ID, readsize, preadbuf); if (ret == _FAIL) { dev_kfree_skb_any(ppkt); RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("%s: read port FAIL!\n", __FUNCTION__)); return NULL; } //3 3. alloc recvbuf precvpriv = &padapter->recvpriv; precvbuf = rtw_dequeue_recvbuf(&precvpriv->free_recv_buf_queue); if (precvbuf == NULL) { dev_kfree_skb_any(ppkt); RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("%s: alloc recvbuf FAIL!\n", __FUNCTION__)); return NULL; } //3 4. init recvbuf precvbuf->pskb = ppkt; precvbuf->len = ppkt->len; precvbuf->phead = ppkt->head; precvbuf->pdata = ppkt->data; #ifdef NET_SKBUFF_DATA_USES_OFFSET precvbuf->ptail = ppkt->head + ppkt->tail; precvbuf->pend = ppkt->head + ppkt->end; #else precvbuf->ptail = ppkt->tail; precvbuf->pend = ppkt->end; #endif return precvbuf; }
/* * Description: * Read from RX FIFO * Round read size to block size, * and make sure data transfer will be done in one command. * * Parameters: * pintfhdl a pointer of intf_hdl * addr port ID * cnt size to read * rmem address to put data * * Return: * _SUCCESS(1) Success * _FAIL(0) Fail */ static u32 sdio_read_port( struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *mem) { PADAPTER padapter; PSDIO_DATA psdio; PHAL_DATA_TYPE phal; u32 oldcnt; #ifdef SDIO_DYNAMIC_ALLOC_MEM u8 *oldmem; #endif s32 err; padapter = pintfhdl->padapter; psdio = &adapter_to_dvobj(padapter)->intf_data; phal = GET_HAL_DATA(padapter); HalSdioGetCmdAddr8723BSdio(padapter, addr, phal->SdioRxFIFOCnt++, &addr); oldcnt = cnt; if (cnt > psdio->block_transfer_len) cnt = _RND(cnt, psdio->block_transfer_len); // cnt = sdio_align_size(cnt); if (oldcnt != cnt) { #ifdef SDIO_DYNAMIC_ALLOC_MEM oldmem = mem; mem = rtw_malloc(cnt); if (mem == NULL) { DBG_8192C(KERN_WARNING "%s: allocate memory %d bytes fail!\n", __func__, cnt); mem = oldmem; oldmem == NULL; } #else // in this case, caller should gurante the buffer is big enough // to receive data after alignment #endif } err = _sd_read(pintfhdl, addr, cnt, mem); #ifdef SDIO_DYNAMIC_ALLOC_MEM if ((oldcnt != cnt) && (oldmem)) { _rtw_memcpy(oldmem, mem, oldcnt); rtw_mfree(mem, cnt); } #endif if (err) return _FAIL; return _SUCCESS; }
static struct recv_buf* sd_recv_rxfifo(PADAPTER padapter, u32 size) { u32 readsize, allocsize, ret; u8 *preadbuf; _pkt *ppkt; struct recv_priv *precvpriv; struct recv_buf *precvbuf; readsize = size; //3 1. alloc skb // align to block size allocsize = _RND(readsize, adapter_to_dvobj(padapter)->intf_data.block_transfer_len); ppkt = rtw_skb_alloc(allocsize); if (ppkt == NULL) { RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("%s: alloc_skb fail! alloc=%d read=%d\n", __FUNCTION__, allocsize, readsize)); return NULL; } //3 2. read data from rxfifo preadbuf = skb_put(ppkt, readsize); // rtw_read_port(padapter, WLAN_RX0FF_DEVICE_ID, readsize, preadbuf); ret = sdio_read_port(&padapter->iopriv.intf, WLAN_RX0FF_DEVICE_ID, readsize, preadbuf); if (ret == _FAIL) { rtw_skb_free(ppkt); RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("%s: read port FAIL!\n", __FUNCTION__)); return NULL; } //3 3. alloc recvbuf precvpriv = &padapter->recvpriv; precvbuf = rtw_dequeue_recvbuf(&precvpriv->free_recv_buf_queue); if (precvbuf == NULL) { rtw_skb_free(ppkt); RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("%s: alloc recvbuf FAIL!\n", __FUNCTION__)); return NULL; } //3 4. init recvbuf precvbuf->pskb = ppkt; precvbuf->len = ppkt->len; precvbuf->phead = ppkt->head; precvbuf->pdata = ppkt->data; precvbuf->ptail = skb_tail_pointer(precvbuf->pskb); precvbuf->pend = skb_end_pointer(precvbuf->pskb); return precvbuf; }
static void sd_recv_loopback(PADAPTER padapter, u32 size) { PLOOPBACKDATA ploopback; u32 readsize, allocsize; u8 *preadbuf; readsize = size; DBG_8192C("%s: read size=%d\n", __func__, readsize); allocsize = _RND(readsize, adapter_to_dvobj(padapter)->intf_data.block_transfer_len); ploopback = padapter->ploopback; if (ploopback) { ploopback->rxsize = readsize; preadbuf = ploopback->rxbuf; } else { preadbuf = rtw_malloc(allocsize); if (preadbuf == NULL) { DBG_8192C("%s: malloc fail size=%d\n", __func__, allocsize); return; } } // rtw_read_port(padapter, WLAN_RX0FF_DEVICE_ID, readsize, preadbuf); sdio_read_port(&padapter->iopriv.intf, WLAN_RX0FF_DEVICE_ID, readsize, preadbuf); if (ploopback) _rtw_up_sema(&ploopback->sema); else { u32 i; DBG_8192C("%s: drop pkt\n", __func__); for (i = 0; i < readsize; i+=4) { DBG_8192C("%08X", *(u32*)(preadbuf + i)); if ((i+4) & 0x1F) printk(" "); else printk("\n"); } printk("\n"); rtw_mfree(preadbuf, allocsize); } }
/* * Description: *Read from RX FIFO *Round read size to block size, *and make sure data transfer will be done in one command. * * Parameters: *intfhdl a pointer of intf_hdl *addr port ID *cnt size to read *rmem address to put data * * Return: *_SUCCESS(1) Success *_FAIL(0) Fail */ static u32 sdio_read_port( struct intf_hdl *intfhdl, u32 addr, u32 cnt, u8 *mem ) { struct adapter *adapter; PSDIO_DATA psdio; struct hal_com_data *hal; u32 oldcnt; #ifdef SDIO_DYNAMIC_ALLOC_MEM u8 *oldmem; #endif s32 err; adapter = intfhdl->padapter; psdio = &adapter_to_dvobj(adapter)->intf_data; hal = GET_HAL_DATA(adapter); HalSdioGetCmdAddr8723BSdio(adapter, addr, hal->SdioRxFIFOCnt++, &addr); oldcnt = cnt; if (cnt > psdio->block_transfer_len) cnt = _RND(cnt, psdio->block_transfer_len); /* cnt = sdio_align_size(cnt); */ err = _sd_read(intfhdl, addr, cnt, mem); #ifdef SDIO_DYNAMIC_ALLOC_MEM if ((oldcnt != cnt) && (oldmem)) { memcpy(oldmem, mem, oldcnt); kfree(mem); } #endif if (err) return _FAIL; return _SUCCESS; }
/* * Description: * Write to TX FIFO * Align write size block size, * and make sure data could be written in one command. * * Parameters: * pintfhdl a pointer of intf_hdl * addr port ID * cnt size to write * wmem data pointer to write * * Return: * _SUCCESS(1) Success * _FAIL(0) Fail */ u32 chris_sdio_write_port( struct sdio_func *func, u32 addr, u32 cnt, u8 *mem) { s32 err; struct sdio_func *pfunc = func; int i; // struct xmit_buf *xmitbuf = (struct xmit_buf *)mem; printk("%s(): addr is %d\n", __func__, addr); for(i=0;i<(cnt);i++) printk("mem[%d] = 0x%02x\n", i, *(mem+i)); err = chris_sd_write(pfunc, addr, cnt, mem); cnt = _RND4(cnt); printk("%s(): cnt is %d\n", __func__, cnt); chris_HalSdioGetCmdAddr8195ASdio(pfunc, addr, cnt >> 2, &addr); printk("%s(): Get Cmd Addr is 0x%x\n", __func__, addr); if (cnt > pfunc->cur_blksize) cnt = _RND(cnt, pfunc->cur_blksize); // cnt = sdio_align_size(cnt); err = chris_sd_write(pfunc, addr, cnt, mem); // rtw_sctx_done_err(&xmitbuf->sctx, // err ? RTW_SCTX_DONE_WRITE_PORT_ERR : RTW_SCTX_DONE_SUCCESS); if (err) { printk("%s, error=%d\n", __func__, err); return _FAIL; } return _SUCCESS; }
/* * 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; }
static struct recv_buf* spi_recv_rxfifo(PADAPTER padapter, u32 size, struct spi_more_data* more_data) { u32 readsize, allocsize, ret; u8 *preadbuf; _pkt *ppkt; struct recv_priv *precvpriv; struct recv_buf *precvbuf; u8 remain_len = 0; readsize = size; remain_len = size%4; if (remain_len != 0) readsize += 4 -remain_len; //3 1. alloc skb // align to block size allocsize = _RND(readsize, adapter_to_dvobj(padapter)->intf_data.block_transfer_len); #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)) // http://www.mail-archive.com/[email protected]/msg17214.html ppkt = __dev_alloc_skb(allocsize, GFP_KERNEL); #else ppkt = __netdev_alloc_skb(padapter->pnetdev, allocsize, GFP_KERNEL); #endif if (ppkt == NULL) { RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("%s: alloc_skb fail! alloc=%d read=%d\n", __FUNCTION__, allocsize, readsize)); #ifdef TODO spi_clean_rxfifo(padapter, size); #endif return NULL; } //3 2. read data from rxfifo preadbuf = skb_put(ppkt, readsize); // rtw_read_port(padapter, WLAN_RX0FF_DEVICE_ID, readsize, preadbuf); //DBG_8192C("%s readsize:%d\n", __func__, readsize); ret = spi_read_rx_fifo(padapter, preadbuf, readsize, more_data); if (ret == _FAIL) { dev_kfree_skb_any(ppkt); RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("%s: read port FAIL!\n", __FUNCTION__)); return NULL; } //3 3. alloc recvbuf precvpriv = &padapter->recvpriv; precvbuf = rtw_dequeue_recvbuf(&precvpriv->free_recv_buf_queue); if (precvbuf == NULL) { dev_kfree_skb_any(ppkt); RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("%s: alloc recvbuf FAIL!\n", __FUNCTION__)); return NULL; } if (0) { u32 i = 0; DBG_8192C("%s dump pkt: len:%d\n", __func__, readsize); for (i = 0; i < readsize; i = i + 4) { DBG_8192C("%8.8x \n", *((u32*)(ppkt->data + i))); } } //3 4. init recvbuf precvbuf->pskb = ppkt; precvbuf->len = ppkt->len; precvbuf->phead = ppkt->head; precvbuf->pdata = ppkt->data; #ifdef NET_SKBUFF_DATA_USES_OFFSET precvbuf->ptail = ppkt->head + ppkt->tail; precvbuf->pend = ppkt->head + ppkt->end; #else precvbuf->ptail = ppkt->tail; precvbuf->pend = ppkt->end; #endif return precvbuf; }
/* * 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; }