1 /******************************************************************************
3 * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * You should have received a copy of the GNU General Public License along with
15 * this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
19 ******************************************************************************/
20 #define _RTL8723AS_XMIT_C_
23 #include <osdep_service.h>
24 #include <drv_types.h>
26 #include <rtl8723a_hal.h>
28 #define SDIO_TX_AGG_MAX 5
31 s32 rtl8723_dequeue_writeport(PADAPTER padapter, u8 *freePage)
33 struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
34 struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
35 struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter);
36 struct xmit_buf *pxmitbuf;
37 //struct xmit_frame *pframe;
38 PADAPTER pri_padapter = padapter;
45 //HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter);
46 #ifdef CONFIG_CONCURRENT_MODE
47 s32 buddy_rm_stop = _FAIL;
50 #ifdef CONFIG_CONCURRENT_MODE
51 if(rtw_buddy_adapter_up(padapter))
52 ret = check_buddy_fwstate( padapter, _FW_UNDER_SURVEY);
55 ret = ret || check_fwstate(pmlmepriv, _FW_UNDER_SURVEY);
58 pxmitbuf = dequeue_pending_xmitbuf_under_survey(pxmitpriv);
60 pxmitbuf = dequeue_pending_xmitbuf(pxmitpriv);
65 //pframe = (struct xmit_frame*)pxmitbuf->priv_data;
66 //requiredPage = pframe->pg_num;
67 requiredPage = pxmitbuf->pg_num;
69 //translate queue index to sdio fifo addr
70 deviceId = pdvobjpriv->Queue2Pipe[pxmitbuf->ff_hwaddr];
72 // translate sdio fifo addr to tx fifo page index
75 case WLAN_TX_HIQ_DEVICE_ID:
76 PageIdx = HI_QUEUE_IDX;
79 case WLAN_TX_MIQ_DEVICE_ID:
80 PageIdx = MID_QUEUE_IDX;
83 case WLAN_TX_LOQ_DEVICE_ID:
84 PageIdx = LOW_QUEUE_IDX;
88 // check if hardware tx fifo page is enough
90 // _enter_critical_bh(&phal->SdioTxFIFOFreePageLock, &irql);
92 if (requiredPage <= freePage[PageIdx]) {
93 freePage[PageIdx] -= requiredPage;
96 // The number of page which public page included is available.
97 if ((freePage[PageIdx] + freePage[PUBLIC_QUEUE_IDX]) > (requiredPage + 1))
99 u8 requiredPublicPage;
101 requiredPublicPage = requiredPage - freePage[PageIdx];
102 freePage[PageIdx] = 0;
103 freePage[PUBLIC_QUEUE_IDX] -= requiredPublicPage;
106 // _exit_critical_bh(&phal->SdioTxFIFOFreePageLock, &irql);
108 ret = (padapter->bDriverStopped == _TRUE) || (padapter->bSurpriseRemoved == _TRUE)
109 #ifdef CONFIG_CONCURRENT_MODE
110 ||((padapter->pbuddy_adapter)
111 && ((padapter->pbuddy_adapter->bSurpriseRemoved) ||(padapter->pbuddy_adapter->bDriverStopped)))
116 RT_TRACE(_module_hal_xmit_c_, _drv_notice_,
117 ("%s: bSurpriseRemoved(update TX FIFO page)\n", __func__));
122 //if ((n & 0x3FF) == 0)
130 DBG_8192C(KERN_NOTICE "%s: FIFO starvation!(%d) len=%d agg=%d page=(R)%d(A)%d\n",
131 __func__, n, pxmitbuf->len, pxmitbuf->agg_num, pxmitbuf->pg_num, freePage[PageIdx] + freePage[PUBLIC_QUEUE_IDX]);
133 //try to recover the transmission
134 reg_value_1 = rtw_read8(padapter, REG_SYS_FUNC_EN);
135 reg_value_2 = rtw_read8(padapter, REG_CR);
136 reg_value_3 = rtw_read8(padapter, REG_TXPAUSE);
137 DBG_871X("Before recovery: REG_SYS_FUNC_EN = 0x%X, REG_CR = 0x%X, REG_TXPAUSE = 0x%X\n", reg_value_1, reg_value_2, reg_value_3);
139 rtw_write8(padapter, REG_SYS_FUNC_EN, reg_value_1 | 0x01);
140 rtw_write8(padapter, REG_CR, reg_value_2 | 0xC0);
141 rtw_write8(padapter, REG_TXPAUSE, 0);
142 DBG_871X("After recovery: REG_SYS_FUNC_EN = 0x%X, REG_CR = 0x%X, REG_TXPAUSE = 0x%X\n",
143 rtw_read8(padapter, REG_SYS_FUNC_EN), rtw_read8(padapter, REG_CR), rtw_read8(padapter, REG_TXPAUSE));
145 //RT_TRACE(_module_hal_xmit_c_, _drv_notice_,
146 // ("%s: FIFO starvation!(%d) len=%d agg=%d page=(R)%d(A)%d\n",
147 // __FUNCTION__, n, pxmitbuf->len, pxmitbuf->agg_num, pxmitbuf->pg_num, freePage[PageIdx] + freePage[PUBLIC_QUEUE_IDX]));
153 // Total number of page is NOT available, so update current FIFO status
154 #ifdef CONFIG_CONCURRENT_MODE
155 if (padapter->adapter_type > 0)
156 pri_padapter = padapter->pbuddy_adapter;
158 HalQueryTxBufferStatus8723ASdio(pri_padapter);
162 if ((padapter->bSurpriseRemoved == _TRUE)
163 #ifdef CONFIG_CONCURRENT_MODE
164 ||((padapter->pbuddy_adapter)&& (padapter->pbuddy_adapter->bSurpriseRemoved))
167 RT_TRACE(_module_hal_xmit_c_, _drv_notice_,
168 ("%s: bSurpriseRemoved(wirte port)\n", __FUNCTION__));
171 rtw_write_port(padapter, deviceId, pxmitbuf->len, (u8 *)pxmitbuf);
174 //rtw_free_xmitframe(pxmitpriv, pframe);
175 //pxmitbuf->priv_data = NULL;
176 rtw_free_xmitbuf(pxmitpriv, pxmitbuf);
183 * Transmit xmitbuf to hardware tx fifo
187 * _FAIL something error
189 s32 rtl8723as_xmit_buf_handler(PADAPTER padapter)
192 struct mlme_priv *pmlmepriv;
193 struct xmit_priv *pxmitpriv;
194 struct dvobj_priv *pdvobjpriv;
195 struct xmit_buf *pxmitbuf;
196 struct xmit_frame *pframe;
200 u8 PageIdx, queue_empty;
206 phal = GET_HAL_DATA(padapter);
207 pmlmepriv = &padapter->mlmepriv;
208 pxmitpriv = &padapter->xmitpriv;
209 pdvobjpriv = adapter_to_dvobj(padapter);
210 freePage = phal->SdioTxFIFOFreePage;
212 ret = _rtw_down_sema(&pxmitpriv->xmit_sema);
214 RT_TRACE(_module_hal_xmit_c_, _drv_emerg_,
215 ("%s: down SdioXmitBufSema fail!\n", __FUNCTION__));
219 ret = (padapter->bDriverStopped == _TRUE) || (padapter->bSurpriseRemoved == _TRUE);
221 RT_TRACE(_module_hal_xmit_c_, _drv_err_,
222 ("%s: bDriverStopped(%d) bSurpriseRemoved(%d)!\n",
223 __FUNCTION__, padapter->bDriverStopped, padapter->bSurpriseRemoved));
227 #ifdef CONFIG_LPS_LCLK
228 ret = rtw_register_tx_alive(padapter);
229 if (ret != _SUCCESS) {
235 queue_empty = rtl8723_dequeue_writeport(padapter, freePage);
236 // dump secondary adapter xmitbuf
237 #ifdef CONFIG_CONCURRENT_MODE
238 if(rtw_buddy_adapter_up(padapter))
239 queue_empty &= rtl8723_dequeue_writeport(padapter->pbuddy_adapter, freePage);
241 } while ( !queue_empty);
243 #ifdef CONFIG_LPS_LCLK
244 rtw_unregister_tx_alive(padapter);
252 * Aggregation packets and send to hardware
256 * -1 Hardware resource(TX FIFO) not ready
257 * -2 Software resource(xmitbuf) not ready
259 static s32 xmit_xmitframes(PADAPTER padapter, struct xmit_priv *pxmitpriv)
263 struct hw_xmit *hwxmits;
264 u8 no_res, idx, hwentry;
266 // _irqL irqL0, irqL1;
267 struct tx_servq *ptxservq;
268 _list *sta_plist, *sta_phead, *frame_plist, *frame_phead;
269 struct xmit_frame *pxmitframe;
270 _queue *pframe_queue;
271 struct xmit_buf *pxmitbuf;
277 hwxmits = pxmitpriv->hwxmits;
278 hwentry = pxmitpriv->hwxmit_entry;
284 // 0(VO), 1(VI), 2(BE), 3(BK)
285 for (idx = 0; idx < hwentry; idx++, hwxmits++)
287 // _enter_critical(&hwxmits->sta_queue->lock, &irqL0);
288 _enter_critical_bh(&pxmitpriv->lock, &irql);
290 sta_phead = get_list_head(hwxmits->sta_queue);
291 sta_plist = get_next(sta_phead);
293 while (rtw_end_of_queue_search(sta_phead, sta_plist) == _FALSE)
295 ptxservq = LIST_CONTAINOR(sta_plist, struct tx_servq, tx_pending);
296 sta_plist = get_next(sta_plist);
298 pframe_queue = &ptxservq->sta_pending;
300 // _enter_critical(&pframe_queue->lock, &irqL1);
301 //_enter_critical_bh(&pxmitpriv->lock, &irql);
303 frame_phead = get_list_head(pframe_queue);
305 while (rtw_is_list_empty(frame_phead) == _FALSE)
307 frame_plist = get_next(frame_phead);
308 pxmitframe = LIST_CONTAINOR(frame_plist, struct xmit_frame, list);
310 // check xmit_buf size enough or not
311 txlen = TXDESC_SIZE + rtw_wlan_pkt_size(pxmitframe);
312 if ((NULL == pxmitbuf) ||
313 ((pxmitbuf->ptail + txlen) > pxmitbuf->pend)
314 #ifdef SDIO_TX_AGG_MAX
315 || (k >= SDIO_TX_AGG_MAX)
320 struct xmit_frame *pframe;
321 pframe = (struct xmit_frame*)pxmitbuf->priv_data;
323 pxmitbuf->agg_num = k;
324 rtl8723a_update_txdesc(pframe, pframe->buf_addr);
325 rtw_free_xmitframe(pxmitpriv, pframe);
326 pxmitbuf->priv_data = NULL;
327 enqueue_pending_xmitbuf(pxmitpriv, pxmitbuf);
331 pxmitbuf = rtw_alloc_xmitbuf(pxmitpriv);
332 if (pxmitbuf == NULL) {
333 RT_TRACE(_module_hal_xmit_c_, _drv_err_, ("%s: xmit_buf is not enough!\n", __FUNCTION__));
340 // ok to send, remove frame from queue
341 //_enter_critical_bh(&pxmitpriv->lock, &irql);
342 #ifdef CONFIG_AP_MODE
343 if (check_fwstate(&padapter->mlmepriv, WIFI_AP_STATE) == _TRUE)
345 if ((pxmitframe->attrib.psta->state & WIFI_SLEEP_STATE) &&
346 (pxmitframe->attrib.triggered == 0))
348 //_exit_critical_bh(&pxmitpriv->lock, &irql);
350 DBG_8192C("%s: one not triggered pkt in queue when STA sleep\n", __func__);
355 rtw_list_delete(&pxmitframe->list);
361 pxmitbuf->ff_hwaddr = rtw_get_ff_hwaddr(pxmitframe);
362 pxmitbuf->priv_data = (u8*)pxmitframe;
365 // coalesce the xmitframe to xmitbuf
366 pxmitframe->pxmitbuf = pxmitbuf;
367 pxmitframe->buf_addr = pxmitbuf->ptail;
369 ret = rtw_xmitframe_coalesce(padapter, pxmitframe->pkt, pxmitframe);
371 RT_TRACE(_module_hal_xmit_c_, _drv_err_, ("%s: coalesce FAIL!", __FUNCTION__));
372 // Todo: error handler
373 DBG_871X("%s: coalesce FAIL!", __FUNCTION__);
377 rtl8723a_update_txdesc(pxmitframe, pxmitframe->buf_addr);
378 rtw_count_tx_stats(padapter, pxmitframe, pxmitframe->attrib.last_txcmdsz);
380 txlen = TXDESC_SIZE + pxmitframe->attrib.last_txcmdsz;
381 pxmitframe->pg_num = (txlen + 127)/128;
382 pxmitbuf->pg_num += (txlen + 127)/128;
384 // ((struct xmit_frame*)pxmitbuf->priv_data)->pg_num += pxmitframe->pg_num;
385 pxmitbuf->ptail += _RND(txlen, 8); // round to 8 bytes alignment
386 pxmitbuf->len = _RND(pxmitbuf->len, 8) + txlen;
390 rtw_free_xmitframe(pxmitpriv, pxmitframe);
394 //_enter_critical_bh(&pxmitpriv->lock, &irql);
395 if (_rtw_queue_empty(pframe_queue) == _TRUE)
396 rtw_list_delete(&ptxservq->tx_pending);
397 //_exit_critical_bh(&pxmitpriv->lock, &irql);
399 // _exit_critical(&pframe_queue->lock, &irqL1);
400 //_exit_critical_bh(&pxmitpriv->lock, &irql);
405 // _exit_critical(&hwxmits->sta_queue->lock, &irqL0);
406 _exit_critical_bh(&pxmitpriv->lock, &irql);
408 // dump xmit_buf to hw tx fifo
411 RT_TRACE(_module_hal_xmit_c_, _drv_notice_, ("pxmitbuf->len=%d enqueue\n",pxmitbuf->len));
413 if (pxmitbuf->len > 0) {
414 struct xmit_frame *pframe;
415 pframe = (struct xmit_frame*)pxmitbuf->priv_data;
417 pxmitbuf->agg_num = k;
418 rtl8723a_update_txdesc(pframe, pframe->buf_addr);
419 rtw_free_xmitframe(pxmitpriv, pframe);
420 pxmitbuf->priv_data = NULL;
421 enqueue_pending_xmitbuf(pxmitpriv, pxmitbuf);
425 rtw_free_xmitbuf(pxmitpriv, pxmitbuf);
438 * Transmit xmitframe from queue
442 * _FAIL something error
444 s32 rtl8723as_xmit_handler(PADAPTER padapter)
446 struct xmit_priv *pxmitpriv;
451 pxmitpriv = &padapter->xmitpriv;
454 ret = _rtw_down_sema(&pxmitpriv->SdioXmitSema);
456 RT_TRACE(_module_hal_xmit_c_, _drv_emerg_, ("%s: down sema fail!\n", __FUNCTION__));
461 if ((padapter->bDriverStopped == _TRUE) ||
462 (padapter->bSurpriseRemoved == _TRUE)) {
463 RT_TRACE(_module_hal_xmit_c_, _drv_notice_,
464 ("%s: bDriverStopped(%d) bSurpriseRemoved(%d)\n",
465 __FUNCTION__, padapter->bDriverStopped, padapter->bSurpriseRemoved));
469 _enter_critical_bh(&pxmitpriv->lock, &irql);
470 ret = rtw_txframes_pending(padapter);
471 _exit_critical_bh(&pxmitpriv->lock, &irql);
476 // dequeue frame and write to hardware
478 ret = xmit_xmitframes(padapter, pxmitpriv);
484 _enter_critical_bh(&pxmitpriv->lock, &irql);
485 ret = rtw_txframes_pending(padapter);
486 _exit_critical_bh(&pxmitpriv->lock, &irql);
495 thread_return rtl8723as_xmit_thread(thread_context context)
498 struct xmit_priv *pxmitpriv;
502 padapter = (PADAPTER)context;
503 pxmitpriv = &padapter->xmitpriv;
506 thread_enter("RTWHALXT");
509 ret = rtl8723as_xmit_handler(padapter);
510 if (signal_pending(current)) {
511 flush_signals(current);
513 } while (_SUCCESS == ret);
515 _rtw_up_sema(&pxmitpriv->SdioXmitTerminateSema);
517 RT_TRACE(_module_hal_xmit_c_, _drv_notice_, ("-%s\n", __FUNCTION__));
522 s32 rtl8723as_mgnt_xmit(PADAPTER padapter, struct xmit_frame *pmgntframe)
525 struct pkt_attrib *pattrib;
526 struct xmit_buf *pxmitbuf;
527 struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
528 struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter);
529 u8 *pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
531 RT_TRACE(_module_hal_xmit_c_, _drv_info_, ("+%s\n", __FUNCTION__));
533 pattrib = &pmgntframe->attrib;
534 pxmitbuf = pmgntframe->pxmitbuf;
536 rtl8723a_update_txdesc(pmgntframe, pmgntframe->buf_addr);
538 pxmitbuf->len = TXDESC_SIZE + pattrib->last_txcmdsz;
539 //pmgntframe->pg_num = (pxmitbuf->len + 127)/128; // 128 is tx page size
540 pxmitbuf->pg_num = (pxmitbuf->len + 127)/128; // 128 is tx page size
541 pxmitbuf->ptail = pmgntframe->buf_addr + pxmitbuf->len;
542 pxmitbuf->ff_hwaddr = rtw_get_ff_hwaddr(pmgntframe);
544 rtw_count_tx_stats(padapter, pmgntframe, pattrib->last_txcmdsz);
546 rtw_free_xmitframe(pxmitpriv, pmgntframe);
548 pxmitbuf->priv_data = NULL;
550 if(GetFrameSubType(pframe)==WIFI_BEACON) //dump beacon directly
552 rtw_write_port(padapter, pdvobjpriv->Queue2Pipe[pxmitbuf->ff_hwaddr], pxmitbuf->len, (u8 *)pxmitbuf);
554 rtw_free_xmitbuf(pxmitpriv, pxmitbuf);
558 enqueue_pending_xmitbuf(pxmitpriv, pxmitbuf);
562 rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_UNKNOWN);
569 * Handle xmitframe(packet) come from rtw_xmit()
572 * _TRUE dump packet directly ok
573 * _FALSE enqueue, temporary can't transmit packets to hardware
575 s32 rtl8723as_hal_xmit(PADAPTER padapter, struct xmit_frame *pxmitframe)
577 struct xmit_priv *pxmitpriv;
582 pxmitframe->attrib.qsel = pxmitframe->attrib.priority;
583 pxmitpriv = &padapter->xmitpriv;
585 #ifdef CONFIG_80211N_HT
586 if ((pxmitframe->frame_tag == DATA_FRAMETAG) &&
587 (pxmitframe->attrib.ether_type != 0x0806) &&
588 (pxmitframe->attrib.ether_type != 0x888e) &&
589 (pxmitframe->attrib.dhcp_pkt != 1))
591 if (padapter->mlmepriv.LinkDetectInfo.bBusyTraffic == _TRUE)
592 rtw_issue_addbareq_cmd(padapter, pxmitframe);
596 _enter_critical_bh(&pxmitpriv->lock, &irql);
597 err = rtw_xmitframe_enqueue(padapter, pxmitframe);
598 _exit_critical_bh(&pxmitpriv->lock, &irql);
599 if (err != _SUCCESS) {
600 RT_TRACE(_module_hal_xmit_c_, _drv_err_, ("rtl8723as_hal_xmit: enqueue xmitframe fail\n"));
601 rtw_free_xmitframe(pxmitpriv, pxmitframe);
603 // Trick, make the statistics correct
604 pxmitpriv->tx_pkts--;
605 pxmitpriv->tx_drop++;
609 _rtw_up_sema(&pxmitpriv->SdioXmitSema);
614 s32 rtl8723as_hal_xmitframe_enqueue(_adapter *padapter, struct xmit_frame *pxmitframe)
616 struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
619 if ((err=rtw_xmitframe_enqueue(padapter, pxmitframe)) != _SUCCESS)
621 rtw_free_xmitframe(pxmitpriv, pxmitframe);
623 // Trick, make the statistics correct
624 pxmitpriv->tx_pkts--;
625 pxmitpriv->tx_drop++;
629 #ifdef CONFIG_SDIO_TX_TASKLET
630 tasklet_hi_schedule(&pxmitpriv->xmit_tasklet);
632 _rtw_up_sema(&pxmitpriv->SdioXmitSema);
642 * _SUCCESS start thread ok
643 * _FAIL start thread fail
646 s32 rtl8723as_init_xmit_priv(PADAPTER padapter)
648 struct xmit_priv *xmitpriv = &padapter->xmitpriv;
652 phal = GET_HAL_DATA(padapter);
654 _rtw_spinlock_init(&phal->SdioTxFIFOFreePageLock);
655 _rtw_init_sema(&xmitpriv->SdioXmitSema, 0);
656 _rtw_init_sema(&xmitpriv->SdioXmitTerminateSema, 0);
661 void rtl8723as_free_xmit_priv(PADAPTER padapter)
664 struct xmit_priv *pxmitpriv;
665 struct xmit_buf *pxmitbuf;
667 _list *plist, *phead;
672 phal = GET_HAL_DATA(padapter);
673 pxmitpriv = &padapter->xmitpriv;
674 pqueue = &pxmitpriv->pending_xmitbuf_queue;
675 phead = get_list_head(pqueue);
676 _rtw_init_listhead(&tmplist);
678 _enter_critical_bh(&pqueue->lock, &irql);
679 if (_rtw_queue_empty(pqueue) == _FALSE)
681 // Insert tmplist to end of queue, and delete phead
682 // then tmplist become head of queue.
683 rtw_list_insert_tail(&tmplist, phead);
684 rtw_list_delete(phead);
686 _exit_critical_bh(&pqueue->lock, &irql);
689 while (rtw_is_list_empty(phead) == _FALSE)
691 plist = get_next(phead);
692 rtw_list_delete(plist);
694 pxmitbuf = LIST_CONTAINOR(plist, struct xmit_buf, list);
695 rtw_free_xmitframe(pxmitpriv, (struct xmit_frame*)pxmitbuf->priv_data);
696 pxmitbuf->priv_data = NULL;
697 rtw_free_xmitbuf(pxmitpriv, pxmitbuf);
700 _rtw_spinlock_free(&phal->SdioTxFIFOFreePageLock);