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 #ifdef CONFIG_TX_AGGREGATION
29 #define SDIO_TX_AGG_MAX 5
31 #define SDIO_TX_AGG_MAX 1
34 s32 rtl8723_dequeue_writeport(PADAPTER padapter, u8 *freePage)
36 struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
37 struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
38 struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter);
39 struct xmit_buf *pxmitbuf;
40 //struct xmit_frame *pframe;
41 PADAPTER pri_padapter = padapter;
48 //HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter);
49 #ifdef CONFIG_CONCURRENT_MODE
50 s32 buddy_rm_stop = _FAIL;
53 #ifdef CONFIG_CONCURRENT_MODE
54 if(rtw_buddy_adapter_up(padapter))
55 ret = check_buddy_fwstate( padapter, _FW_UNDER_SURVEY);
58 ret = ret || check_fwstate(pmlmepriv, _FW_UNDER_SURVEY);
61 pxmitbuf = dequeue_pending_xmitbuf_under_survey(pxmitpriv);
63 pxmitbuf = dequeue_pending_xmitbuf(pxmitpriv);
68 //pframe = (struct xmit_frame*)pxmitbuf->priv_data;
69 //requiredPage = pframe->pg_num;
70 requiredPage = pxmitbuf->pg_num;
72 //translate queue index to sdio fifo addr
73 deviceId = pdvobjpriv->Queue2Pipe[pxmitbuf->ff_hwaddr];
75 // translate sdio fifo addr to tx fifo page index
78 case WLAN_TX_HIQ_DEVICE_ID:
79 PageIdx = HI_QUEUE_IDX;
82 case WLAN_TX_MIQ_DEVICE_ID:
83 PageIdx = MID_QUEUE_IDX;
86 case WLAN_TX_LOQ_DEVICE_ID:
87 PageIdx = LOW_QUEUE_IDX;
91 // check if hardware tx fifo page is enough
93 // _enter_critical_bh(&phal->SdioTxFIFOFreePageLock, &irql);
95 if (requiredPage <= freePage[PageIdx]) {
96 freePage[PageIdx] -= requiredPage;
99 // The number of page which public page included is available.
100 if ((freePage[PageIdx] + freePage[PUBLIC_QUEUE_IDX]) > (requiredPage + 1))
102 u8 requiredPublicPage;
104 requiredPublicPage = requiredPage - freePage[PageIdx];
105 freePage[PageIdx] = 0;
106 freePage[PUBLIC_QUEUE_IDX] -= requiredPublicPage;
109 // _exit_critical_bh(&phal->SdioTxFIFOFreePageLock, &irql);
111 ret = (padapter->bDriverStopped == _TRUE) || (padapter->bSurpriseRemoved == _TRUE)
112 #ifdef CONFIG_CONCURRENT_MODE
113 ||((padapter->pbuddy_adapter)
114 && ((padapter->pbuddy_adapter->bSurpriseRemoved) ||(padapter->pbuddy_adapter->bDriverStopped)))
119 RT_TRACE(_module_hal_xmit_c_, _drv_notice_,
120 ("%s: bSurpriseRemoved(update TX FIFO page)\n", __func__));
125 //if ((n & 0x3FF) == 0)
133 DBG_8192C(KERN_NOTICE "%s: FIFO starvation!(%d) len=%d agg=%d page=(R)%d(A)%d\n",
134 __func__, n, pxmitbuf->len, pxmitbuf->agg_num, pxmitbuf->pg_num, freePage[PageIdx] + freePage[PUBLIC_QUEUE_IDX]);
136 //try to recover the transmission
137 reg_value_1 = rtw_read8(padapter, REG_SYS_FUNC_EN);
138 reg_value_2 = rtw_read8(padapter, REG_CR);
139 reg_value_3 = rtw_read8(padapter, REG_TXPAUSE);
140 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);
142 rtw_write8(padapter, REG_SYS_FUNC_EN, reg_value_1 | 0x01);
143 rtw_write8(padapter, REG_CR, reg_value_2 | 0xC0);
144 rtw_write8(padapter, REG_TXPAUSE, 0);
145 DBG_871X("After recovery: REG_SYS_FUNC_EN = 0x%X, REG_CR = 0x%X, REG_TXPAUSE = 0x%X\n",
146 rtw_read8(padapter, REG_SYS_FUNC_EN), rtw_read8(padapter, REG_CR), rtw_read8(padapter, REG_TXPAUSE));
148 //RT_TRACE(_module_hal_xmit_c_, _drv_notice_,
149 // ("%s: FIFO starvation!(%d) len=%d agg=%d page=(R)%d(A)%d\n",
150 // __FUNCTION__, n, pxmitbuf->len, pxmitbuf->agg_num, pxmitbuf->pg_num, freePage[PageIdx] + freePage[PUBLIC_QUEUE_IDX]));
156 // Total number of page is NOT available, so update current FIFO status
157 #ifdef CONFIG_CONCURRENT_MODE
158 if (padapter->adapter_type > 0)
159 pri_padapter = padapter->pbuddy_adapter;
161 HalQueryTxBufferStatus8723ASdio(pri_padapter);
165 if ((padapter->bSurpriseRemoved == _TRUE)
166 #ifdef CONFIG_CONCURRENT_MODE
167 ||((padapter->pbuddy_adapter)&& (padapter->pbuddy_adapter->bSurpriseRemoved))
170 RT_TRACE(_module_hal_xmit_c_, _drv_notice_,
171 ("%s: bSurpriseRemoved(wirte port)\n", __FUNCTION__));
174 rtw_write_port(padapter, deviceId, pxmitbuf->len, (u8 *)pxmitbuf);
177 //rtw_free_xmitframe(pxmitpriv, pframe);
178 //pxmitbuf->priv_data = NULL;
179 rtw_free_xmitbuf(pxmitpriv, pxmitbuf);
186 * Transmit xmitbuf to hardware tx fifo
190 * _FAIL something error
192 s32 rtl8723as_xmit_buf_handler(PADAPTER padapter)
195 struct mlme_priv *pmlmepriv;
196 struct xmit_priv *pxmitpriv;
197 struct dvobj_priv *pdvobjpriv;
198 struct xmit_buf *pxmitbuf;
199 struct xmit_frame *pframe;
203 u8 PageIdx, queue_empty;
209 phal = GET_HAL_DATA(padapter);
210 pmlmepriv = &padapter->mlmepriv;
211 pxmitpriv = &padapter->xmitpriv;
212 pdvobjpriv = adapter_to_dvobj(padapter);
213 freePage = phal->SdioTxFIFOFreePage;
215 ret = _rtw_down_sema(&pxmitpriv->xmit_sema);
217 RT_TRACE(_module_hal_xmit_c_, _drv_emerg_,
218 ("%s: down SdioXmitBufSema fail!\n", __FUNCTION__));
222 ret = (padapter->bDriverStopped == _TRUE) || (padapter->bSurpriseRemoved == _TRUE);
224 RT_TRACE(_module_hal_xmit_c_, _drv_err_,
225 ("%s: bDriverStopped(%d) bSurpriseRemoved(%d)!\n",
226 __FUNCTION__, padapter->bDriverStopped, padapter->bSurpriseRemoved));
230 #ifdef CONFIG_LPS_LCLK
231 ret = rtw_register_tx_alive(padapter);
232 if (ret != _SUCCESS) {
238 queue_empty = rtl8723_dequeue_writeport(padapter, freePage);
239 // dump secondary adapter xmitbuf
240 #ifdef CONFIG_CONCURRENT_MODE
241 if(rtw_buddy_adapter_up(padapter))
242 queue_empty &= rtl8723_dequeue_writeport(padapter->pbuddy_adapter, freePage);
244 } while ( !queue_empty);
246 #ifdef CONFIG_LPS_LCLK
247 rtw_unregister_tx_alive(padapter);
255 * Aggregation packets and send to hardware
259 * -1 Hardware resource(TX FIFO) not ready
260 * -2 Software resource(xmitbuf) not ready
262 static s32 xmit_xmitframes(PADAPTER padapter, struct xmit_priv *pxmitpriv)
266 struct hw_xmit *hwxmits;
267 u8 no_res, idx, hwentry;
269 // _irqL irqL0, irqL1;
270 struct tx_servq *ptxservq;
271 _list *sta_plist, *sta_phead, *frame_plist, *frame_phead;
272 struct xmit_frame *pxmitframe;
273 _queue *pframe_queue;
274 struct xmit_buf *pxmitbuf;
280 hwxmits = pxmitpriv->hwxmits;
281 hwentry = pxmitpriv->hwxmit_entry;
287 // 0(VO), 1(VI), 2(BE), 3(BK)
288 for (idx = 0; idx < hwentry; idx++, hwxmits++)
290 // _enter_critical(&hwxmits->sta_queue->lock, &irqL0);
291 _enter_critical_bh(&pxmitpriv->lock, &irql);
293 sta_phead = get_list_head(hwxmits->sta_queue);
294 sta_plist = get_next(sta_phead);
296 while (rtw_end_of_queue_search(sta_phead, sta_plist) == _FALSE)
298 ptxservq = LIST_CONTAINOR(sta_plist, struct tx_servq, tx_pending);
299 sta_plist = get_next(sta_plist);
301 pframe_queue = &ptxservq->sta_pending;
303 // _enter_critical(&pframe_queue->lock, &irqL1);
304 //_enter_critical_bh(&pxmitpriv->lock, &irql);
306 frame_phead = get_list_head(pframe_queue);
308 while (rtw_is_list_empty(frame_phead) == _FALSE)
310 frame_plist = get_next(frame_phead);
311 pxmitframe = LIST_CONTAINOR(frame_plist, struct xmit_frame, list);
313 // check xmit_buf size enough or not
314 txlen = TXDESC_SIZE + rtw_wlan_pkt_size(pxmitframe);
315 if ((NULL == pxmitbuf) ||
316 ((pxmitbuf->ptail + txlen) > pxmitbuf->pend)
317 #ifdef SDIO_TX_AGG_MAX
318 || (k >= SDIO_TX_AGG_MAX)
323 struct xmit_frame *pframe;
324 pframe = (struct xmit_frame*)pxmitbuf->priv_data;
326 pxmitbuf->agg_num = k;
327 rtl8723a_update_txdesc(pframe, pframe->buf_addr);
328 rtw_free_xmitframe(pxmitpriv, pframe);
329 pxmitbuf->priv_data = NULL;
330 enqueue_pending_xmitbuf(pxmitpriv, pxmitbuf);
334 pxmitbuf = rtw_alloc_xmitbuf(pxmitpriv);
335 if (pxmitbuf == NULL) {
336 RT_TRACE(_module_hal_xmit_c_, _drv_err_, ("%s: xmit_buf is not enough!\n", __FUNCTION__));
343 // ok to send, remove frame from queue
344 //_enter_critical_bh(&pxmitpriv->lock, &irql);
345 #ifdef CONFIG_AP_MODE
346 if (check_fwstate(&padapter->mlmepriv, WIFI_AP_STATE) == _TRUE)
348 if ((pxmitframe->attrib.psta->state & WIFI_SLEEP_STATE) &&
349 (pxmitframe->attrib.triggered == 0))
351 //_exit_critical_bh(&pxmitpriv->lock, &irql);
353 DBG_8192C("%s: one not triggered pkt in queue when STA sleep\n", __func__);
358 rtw_list_delete(&pxmitframe->list);
364 pxmitbuf->ff_hwaddr = rtw_get_ff_hwaddr(pxmitframe);
365 pxmitbuf->priv_data = (u8*)pxmitframe;
368 // coalesce the xmitframe to xmitbuf
369 pxmitframe->pxmitbuf = pxmitbuf;
370 pxmitframe->buf_addr = pxmitbuf->ptail;
372 ret = rtw_xmitframe_coalesce(padapter, pxmitframe->pkt, pxmitframe);
374 RT_TRACE(_module_hal_xmit_c_, _drv_err_, ("%s: coalesce FAIL!", __FUNCTION__));
375 // Todo: error handler
376 DBG_871X("%s: coalesce FAIL!", __FUNCTION__);
380 rtl8723a_update_txdesc(pxmitframe, pxmitframe->buf_addr);
381 rtw_count_tx_stats(padapter, pxmitframe, pxmitframe->attrib.last_txcmdsz);
383 txlen = TXDESC_SIZE + pxmitframe->attrib.last_txcmdsz;
384 pxmitframe->pg_num = (txlen + 127)/128;
385 pxmitbuf->pg_num += (txlen + 127)/128;
387 // ((struct xmit_frame*)pxmitbuf->priv_data)->pg_num += pxmitframe->pg_num;
388 pxmitbuf->ptail += _RND(txlen, 8); // round to 8 bytes alignment
389 pxmitbuf->len = _RND(pxmitbuf->len, 8) + txlen;
393 rtw_free_xmitframe(pxmitpriv, pxmitframe);
397 //_enter_critical_bh(&pxmitpriv->lock, &irql);
398 if (_rtw_queue_empty(pframe_queue) == _TRUE)
399 rtw_list_delete(&ptxservq->tx_pending);
400 //_exit_critical_bh(&pxmitpriv->lock, &irql);
402 // _exit_critical(&pframe_queue->lock, &irqL1);
403 //_exit_critical_bh(&pxmitpriv->lock, &irql);
408 // _exit_critical(&hwxmits->sta_queue->lock, &irqL0);
409 _exit_critical_bh(&pxmitpriv->lock, &irql);
411 // dump xmit_buf to hw tx fifo
414 RT_TRACE(_module_hal_xmit_c_, _drv_notice_, ("pxmitbuf->len=%d enqueue\n",pxmitbuf->len));
416 if (pxmitbuf->len > 0) {
417 struct xmit_frame *pframe;
418 pframe = (struct xmit_frame*)pxmitbuf->priv_data;
420 pxmitbuf->agg_num = k;
421 rtl8723a_update_txdesc(pframe, pframe->buf_addr);
422 rtw_free_xmitframe(pxmitpriv, pframe);
423 pxmitbuf->priv_data = NULL;
424 enqueue_pending_xmitbuf(pxmitpriv, pxmitbuf);
428 rtw_free_xmitbuf(pxmitpriv, pxmitbuf);
441 * Transmit xmitframe from queue
445 * _FAIL something error
447 s32 rtl8723as_xmit_handler(PADAPTER padapter)
449 struct xmit_priv *pxmitpriv;
454 pxmitpriv = &padapter->xmitpriv;
457 ret = _rtw_down_sema(&pxmitpriv->SdioXmitSema);
459 RT_TRACE(_module_hal_xmit_c_, _drv_emerg_, ("%s: down sema fail!\n", __FUNCTION__));
464 if ((padapter->bDriverStopped == _TRUE) ||
465 (padapter->bSurpriseRemoved == _TRUE)) {
466 RT_TRACE(_module_hal_xmit_c_, _drv_notice_,
467 ("%s: bDriverStopped(%d) bSurpriseRemoved(%d)\n",
468 __FUNCTION__, padapter->bDriverStopped, padapter->bSurpriseRemoved));
472 _enter_critical_bh(&pxmitpriv->lock, &irql);
473 ret = rtw_txframes_pending(padapter);
474 _exit_critical_bh(&pxmitpriv->lock, &irql);
479 // dequeue frame and write to hardware
481 ret = xmit_xmitframes(padapter, pxmitpriv);
487 _enter_critical_bh(&pxmitpriv->lock, &irql);
488 ret = rtw_txframes_pending(padapter);
489 _exit_critical_bh(&pxmitpriv->lock, &irql);
498 thread_return rtl8723as_xmit_thread(thread_context context)
501 struct xmit_priv *pxmitpriv;
505 padapter = (PADAPTER)context;
506 pxmitpriv = &padapter->xmitpriv;
509 thread_enter("RTWHALXT");
512 ret = rtl8723as_xmit_handler(padapter);
513 if (signal_pending(current)) {
514 flush_signals(current);
516 } while (_SUCCESS == ret);
518 _rtw_up_sema(&pxmitpriv->SdioXmitTerminateSema);
520 RT_TRACE(_module_hal_xmit_c_, _drv_notice_, ("-%s\n", __FUNCTION__));
525 s32 rtl8723as_mgnt_xmit(PADAPTER padapter, struct xmit_frame *pmgntframe)
528 struct pkt_attrib *pattrib;
529 struct xmit_buf *pxmitbuf;
530 struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
531 struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter);
532 u8 *pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
534 RT_TRACE(_module_hal_xmit_c_, _drv_info_, ("+%s\n", __FUNCTION__));
536 pattrib = &pmgntframe->attrib;
537 pxmitbuf = pmgntframe->pxmitbuf;
539 rtl8723a_update_txdesc(pmgntframe, pmgntframe->buf_addr);
541 pxmitbuf->len = TXDESC_SIZE + pattrib->last_txcmdsz;
542 //pmgntframe->pg_num = (pxmitbuf->len + 127)/128; // 128 is tx page size
543 pxmitbuf->pg_num = (pxmitbuf->len + 127)/128; // 128 is tx page size
544 pxmitbuf->ptail = pmgntframe->buf_addr + pxmitbuf->len;
545 pxmitbuf->ff_hwaddr = rtw_get_ff_hwaddr(pmgntframe);
547 rtw_count_tx_stats(padapter, pmgntframe, pattrib->last_txcmdsz);
549 rtw_free_xmitframe(pxmitpriv, pmgntframe);
551 pxmitbuf->priv_data = NULL;
553 if(GetFrameSubType(pframe)==WIFI_BEACON) //dump beacon directly
555 rtw_write_port(padapter, pdvobjpriv->Queue2Pipe[pxmitbuf->ff_hwaddr], pxmitbuf->len, (u8 *)pxmitbuf);
557 rtw_free_xmitbuf(pxmitpriv, pxmitbuf);
561 enqueue_pending_xmitbuf(pxmitpriv, pxmitbuf);
565 rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_UNKNOWN);
572 * Handle xmitframe(packet) come from rtw_xmit()
575 * _TRUE dump packet directly ok
576 * _FALSE enqueue, temporary can't transmit packets to hardware
578 s32 rtl8723as_hal_xmit(PADAPTER padapter, struct xmit_frame *pxmitframe)
580 struct xmit_priv *pxmitpriv;
585 pxmitframe->attrib.qsel = pxmitframe->attrib.priority;
586 pxmitpriv = &padapter->xmitpriv;
588 #ifdef CONFIG_80211N_HT
589 if ((pxmitframe->frame_tag == DATA_FRAMETAG) &&
590 (pxmitframe->attrib.ether_type != 0x0806) &&
591 (pxmitframe->attrib.ether_type != 0x888e) &&
592 (pxmitframe->attrib.dhcp_pkt != 1))
594 if (padapter->mlmepriv.LinkDetectInfo.bBusyTraffic == _TRUE)
595 rtw_issue_addbareq_cmd(padapter, pxmitframe);
599 _enter_critical_bh(&pxmitpriv->lock, &irql);
600 err = rtw_xmitframe_enqueue(padapter, pxmitframe);
601 _exit_critical_bh(&pxmitpriv->lock, &irql);
602 if (err != _SUCCESS) {
603 RT_TRACE(_module_hal_xmit_c_, _drv_err_, ("rtl8723as_hal_xmit: enqueue xmitframe fail\n"));
604 rtw_free_xmitframe(pxmitpriv, pxmitframe);
606 // Trick, make the statistics correct
607 pxmitpriv->tx_pkts--;
608 pxmitpriv->tx_drop++;
612 _rtw_up_sema(&pxmitpriv->SdioXmitSema);
617 s32 rtl8723as_hal_xmitframe_enqueue(_adapter *padapter, struct xmit_frame *pxmitframe)
619 struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
622 if ((err=rtw_xmitframe_enqueue(padapter, pxmitframe)) != _SUCCESS)
624 rtw_free_xmitframe(pxmitpriv, pxmitframe);
626 // Trick, make the statistics correct
627 pxmitpriv->tx_pkts--;
628 pxmitpriv->tx_drop++;
632 #ifdef CONFIG_SDIO_TX_TASKLET
633 tasklet_hi_schedule(&pxmitpriv->xmit_tasklet);
635 _rtw_up_sema(&pxmitpriv->SdioXmitSema);
645 * _SUCCESS start thread ok
646 * _FAIL start thread fail
649 s32 rtl8723as_init_xmit_priv(PADAPTER padapter)
651 struct xmit_priv *xmitpriv = &padapter->xmitpriv;
655 phal = GET_HAL_DATA(padapter);
657 _rtw_spinlock_init(&phal->SdioTxFIFOFreePageLock);
658 _rtw_init_sema(&xmitpriv->SdioXmitSema, 0);
659 _rtw_init_sema(&xmitpriv->SdioXmitTerminateSema, 0);
664 void rtl8723as_free_xmit_priv(PADAPTER padapter)
667 struct xmit_priv *pxmitpriv;
668 struct xmit_buf *pxmitbuf;
670 _list *plist, *phead;
675 phal = GET_HAL_DATA(padapter);
676 pxmitpriv = &padapter->xmitpriv;
677 pqueue = &pxmitpriv->pending_xmitbuf_queue;
678 phead = get_list_head(pqueue);
679 _rtw_init_listhead(&tmplist);
681 _enter_critical_bh(&pqueue->lock, &irql);
682 if (_rtw_queue_empty(pqueue) == _FALSE)
684 // Insert tmplist to end of queue, and delete phead
685 // then tmplist become head of queue.
686 rtw_list_insert_tail(&tmplist, phead);
687 rtw_list_delete(phead);
689 _exit_critical_bh(&pqueue->lock, &irql);
692 while (rtw_is_list_empty(phead) == _FALSE)
694 plist = get_next(phead);
695 rtw_list_delete(plist);
697 pxmitbuf = LIST_CONTAINOR(plist, struct xmit_buf, list);
698 rtw_free_xmitframe(pxmitpriv, (struct xmit_frame*)pxmitbuf->priv_data);
699 pxmitbuf->priv_data = NULL;
700 rtw_free_xmitbuf(pxmitpriv, pxmitbuf);
703 _rtw_spinlock_free(&phal->SdioTxFIFOFreePageLock);