1 // SPDX-License-Identifier: GPL-2.0
2 /******************************************************************************
4 * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
6 ******************************************************************************/
7 #define _RTL8723BS_XMIT_C_
10 #include <rtw_debug.h>
11 #include <rtl8723b_hal.h>
13 static u8 rtw_sdio_wait_enough_TxOQT_space(struct adapter *padapter, u8 agg_num)
16 struct hal_com_data *pHalData = GET_HAL_DATA(padapter);
18 while (pHalData->SdioTxOQTFreeSpace < agg_num) {
20 (padapter->bSurpriseRemoved == true) ||
21 (padapter->bDriverStopped == true)
23 DBG_871X("%s: bSurpriseRemoved or bDriverStopped (wait TxOQT)\n", __func__);
27 HalQueryTxOQTBufferStatus8723BSdio(padapter);
29 if ((++n % 60) == 0) {
31 DBG_871X("%s(%d): QOT free space(%d), agg_num: %d\n",
32 __func__, n, pHalData->SdioTxOQTFreeSpace, agg_num);
39 pHalData->SdioTxOQTFreeSpace -= agg_num;
42 /* ++priv->pshare->nr_out_of_txoqt_space; */
47 static s32 rtl8723_dequeue_writeport(struct adapter *padapter)
49 struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
50 struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
51 struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter);
52 struct xmit_buf *pxmitbuf;
53 struct adapter *pri_padapter = padapter;
57 u8 bUpdatePageNum = false;
59 ret = ret || check_fwstate(pmlmepriv, _FW_UNDER_SURVEY);
62 pxmitbuf = dequeue_pending_xmitbuf_under_survey(pxmitpriv);
64 pxmitbuf = dequeue_pending_xmitbuf(pxmitpriv);
69 deviceId = ffaddr2deviceId(pdvobjpriv, pxmitbuf->ff_hwaddr);
71 /* translate fifo addr to queue index */
73 case WLAN_TX_HIQ_DEVICE_ID:
74 PageIdx = HI_QUEUE_IDX;
77 case WLAN_TX_MIQ_DEVICE_ID:
78 PageIdx = MID_QUEUE_IDX;
81 case WLAN_TX_LOQ_DEVICE_ID:
82 PageIdx = LOW_QUEUE_IDX;
87 /* check if hardware tx fifo page is enough */
88 if (false == rtw_hal_sdio_query_tx_freepage(pri_padapter, PageIdx, pxmitbuf->pg_num)) {
89 if (!bUpdatePageNum) {
90 /* Total number of page is NOT available, so update current FIFO status */
91 HalQueryTxBufferStatus8723BSdio(padapter);
92 bUpdatePageNum = true;
95 bUpdatePageNum = false;
96 enqueue_pending_xmitbuf_to_head(pxmitpriv, pxmitbuf);
102 (padapter->bSurpriseRemoved == true) ||
103 (padapter->bDriverStopped == true)
108 ("%s: bSurpriseRemoved(write port)\n", __func__)
113 if (rtw_sdio_wait_enough_TxOQT_space(padapter, pxmitbuf->agg_num) == false)
116 traffic_check_for_leave_lps(padapter, true, pxmitbuf->agg_num);
118 rtw_write_port(padapter, deviceId, pxmitbuf->len, (u8 *)pxmitbuf);
120 rtw_hal_sdio_update_tx_freepage(pri_padapter, PageIdx, pxmitbuf->pg_num);
123 /* rtw_free_xmitframe(pxmitpriv, pframe); */
124 /* pxmitbuf->priv_data = NULL; */
125 rtw_free_xmitbuf(pxmitpriv, pxmitbuf);
127 #ifdef CONFIG_SDIO_TX_TASKLET
128 tasklet_hi_schedule(&pxmitpriv->xmit_tasklet);
136 *Transmit xmitbuf to hardware tx fifo
140 *_FAIL something error
142 s32 rtl8723bs_xmit_buf_handler(struct adapter *padapter)
144 struct xmit_priv *pxmitpriv;
145 u8 queue_empty, queue_pending;
149 pxmitpriv = &padapter->xmitpriv;
151 if (wait_for_completion_interruptible(&pxmitpriv->xmit_comp)) {
152 DBG_871X_LEVEL(_drv_emerg_, "%s: down SdioXmitBufSema fail!\n", __func__);
156 ret = (padapter->bDriverStopped == true) || (padapter->bSurpriseRemoved == true);
162 "%s: bDriverStopped(%d) bSurpriseRemoved(%d)!\n",
164 padapter->bDriverStopped,
165 padapter->bSurpriseRemoved
171 queue_pending = check_pending_xmitbuf(pxmitpriv);
173 if (queue_pending == false)
176 ret = rtw_register_tx_alive(padapter);
177 if (ret != _SUCCESS) {
182 queue_empty = rtl8723_dequeue_writeport(padapter);
183 /* dump secondary adapter xmitbuf */
184 } while (!queue_empty);
186 rtw_unregister_tx_alive(padapter);
193 *Aggregation packets and send to hardware
197 *-1 Hardware resource(TX FIFO) not ready
198 *-2 Software resource(xmitbuf) not ready
200 static s32 xmit_xmitframes(struct adapter *padapter, struct xmit_priv *pxmitpriv)
204 struct hw_xmit *hwxmits, *phwxmit;
205 u8 no_res, idx, hwentry;
206 struct tx_servq *ptxservq;
207 struct list_head *sta_plist, *sta_phead, *frame_plist, *frame_phead;
208 struct xmit_frame *pxmitframe;
209 struct __queue *pframe_queue;
210 struct xmit_buf *pxmitbuf;
211 u32 txlen, max_xmit_len;
212 u8 txdesc_size = TXDESC_SIZE;
217 hwxmits = pxmitpriv->hwxmits;
218 hwentry = pxmitpriv->hwxmit_entry;
224 if (padapter->registrypriv.wifi_spec == 1) {
225 for (idx = 0; idx < 4; idx++)
226 inx[idx] = pxmitpriv->wmm_para_seq[idx];
234 /* 0(VO), 1(VI), 2(BE), 3(BK) */
235 for (idx = 0; idx < hwentry; idx++) {
236 phwxmit = hwxmits + inx[idx];
239 (check_pending_xmitbuf(pxmitpriv) == true) &&
240 (padapter->mlmepriv.LinkDetectInfo.bHigherBusyTxTraffic == true)
242 if ((phwxmit->accnt > 0) && (phwxmit->accnt < 5)) {
248 max_xmit_len = rtw_hal_get_sdio_tx_max_length(padapter, inx[idx]);
250 spin_lock_bh(&pxmitpriv->lock);
252 sta_phead = get_list_head(phwxmit->sta_queue);
253 sta_plist = get_next(sta_phead);
254 /* because stop_sta_xmit may delete sta_plist at any time */
255 /* so we should add lock here, or while loop can not exit */
256 while (sta_phead != sta_plist) {
257 ptxservq = LIST_CONTAINOR(sta_plist, struct tx_servq, tx_pending);
258 sta_plist = get_next(sta_plist);
262 "%s idx:%d hwxmit_pkt_num:%d ptxservq_pkt_num:%d\n",
269 "%s free_xmit_extbuf_cnt =%d free_xmitbuf_cnt =%d free_xmitframe_cnt =%d\n",
271 pxmitpriv->free_xmit_extbuf_cnt,
272 pxmitpriv->free_xmitbuf_cnt,
273 pxmitpriv->free_xmitframe_cnt
276 pframe_queue = &ptxservq->sta_pending;
278 frame_phead = get_list_head(pframe_queue);
280 while (list_empty(frame_phead) == false) {
281 frame_plist = get_next(frame_phead);
282 pxmitframe = LIST_CONTAINOR(frame_plist, struct xmit_frame, list);
284 /* check xmit_buf size enough or not */
285 txlen = txdesc_size + rtw_wlan_pkt_size(pxmitframe);
287 (NULL == pxmitbuf) ||
288 ((_RND(pxmitbuf->len, 8) + txlen) > max_xmit_len) ||
289 (k >= (rtw_hal_sdio_max_txoqt_free_space(padapter)-1))
292 /* pxmitbuf->priv_data will be NULL, and will crash here */
293 if (pxmitbuf->len > 0 &&
294 pxmitbuf->priv_data) {
295 struct xmit_frame *pframe;
296 pframe = (struct xmit_frame *)pxmitbuf->priv_data;
298 pxmitbuf->agg_num = k;
299 rtl8723b_update_txdesc(pframe, pframe->buf_addr);
300 rtw_free_xmitframe(pxmitpriv, pframe);
301 pxmitbuf->priv_data = NULL;
302 enqueue_pending_xmitbuf(pxmitpriv, pxmitbuf);
303 /* can not yield under lock */
306 rtw_free_xmitbuf(pxmitpriv, pxmitbuf);
309 pxmitbuf = rtw_alloc_xmitbuf(pxmitpriv);
310 if (pxmitbuf == NULL) {
312 DBG_871X_LEVEL(_drv_err_, "%s: xmit_buf is not enough!\n", __func__);
315 complete(&(pxmitpriv->xmit_comp));
321 /* ok to send, remove frame from queue */
322 if (check_fwstate(&padapter->mlmepriv, WIFI_AP_STATE) == true) {
324 (pxmitframe->attrib.psta->state & WIFI_SLEEP_STATE) &&
325 (pxmitframe->attrib.triggered == 0)
328 "%s: one not triggered pkt in queue when this STA sleep,"
329 " break and goto next sta\n",
336 list_del_init(&pxmitframe->list);
341 pxmitbuf->ff_hwaddr = rtw_get_ff_hwaddr(pxmitframe);
342 pxmitbuf->priv_data = (u8 *)pxmitframe;
345 /* coalesce the xmitframe to xmitbuf */
346 pxmitframe->pxmitbuf = pxmitbuf;
347 pxmitframe->buf_addr = pxmitbuf->ptail;
349 ret = rtw_xmitframe_coalesce(padapter, pxmitframe->pkt, pxmitframe);
351 DBG_871X_LEVEL(_drv_err_, "%s: coalesce FAIL!", __func__);
352 /* Todo: error handler */
356 rtl8723b_update_txdesc(pxmitframe, pxmitframe->buf_addr);
357 rtw_count_tx_stats(padapter, pxmitframe, pxmitframe->attrib.last_txcmdsz);
359 txlen = txdesc_size + pxmitframe->attrib.last_txcmdsz;
360 pxmitframe->pg_num = (txlen + 127)/128;
361 pxmitbuf->pg_num += (txlen + 127)/128;
363 /* ((struct xmit_frame*)pxmitbuf->priv_data)->pg_num += pxmitframe->pg_num; */
364 pxmitbuf->ptail += _RND(txlen, 8); /* round to 8 bytes alignment */
365 pxmitbuf->len = _RND(pxmitbuf->len, 8) + txlen;
369 rtw_free_xmitframe(pxmitpriv, pxmitframe);
373 if (list_empty(&pframe_queue->queue))
374 list_del_init(&ptxservq->tx_pending);
379 spin_unlock_bh(&pxmitpriv->lock);
381 /* dump xmit_buf to hw tx fifo */
383 RT_TRACE(_module_hal_xmit_c_, _drv_info_, ("pxmitbuf->len =%d enqueue\n", pxmitbuf->len));
385 if (pxmitbuf->len > 0) {
386 struct xmit_frame *pframe;
387 pframe = (struct xmit_frame *)pxmitbuf->priv_data;
389 pxmitbuf->agg_num = k;
390 rtl8723b_update_txdesc(pframe, pframe->buf_addr);
391 rtw_free_xmitframe(pxmitpriv, pframe);
392 pxmitbuf->priv_data = NULL;
393 enqueue_pending_xmitbuf(pxmitpriv, pxmitbuf);
396 rtw_free_xmitbuf(pxmitpriv, pxmitbuf);
409 *Transmit xmitframe from queue
413 *_FAIL something error
415 static s32 rtl8723bs_xmit_handler(struct adapter *padapter)
417 struct xmit_priv *pxmitpriv;
421 pxmitpriv = &padapter->xmitpriv;
423 if (wait_for_completion_interruptible(&pxmitpriv->SdioXmitStart)) {
424 DBG_871X_LEVEL(_drv_emerg_, "%s: SdioXmitStart fail!\n", __func__);
430 (padapter->bDriverStopped == true) ||
431 (padapter->bSurpriseRemoved == true)
437 "%s: bDriverStopped(%d) bSurpriseRemoved(%d)\n",
439 padapter->bDriverStopped,
440 padapter->bSurpriseRemoved
446 spin_lock_bh(&pxmitpriv->lock);
447 ret = rtw_txframes_pending(padapter);
448 spin_unlock_bh(&pxmitpriv->lock);
453 /* dequeue frame and write to hardware */
455 ret = xmit_xmitframes(padapter, pxmitpriv);
457 /* here sleep 1ms will cause big TP loss of TX */
458 /* from 50+ to 40+ */
459 if (padapter->registrypriv.wifi_spec)
466 spin_lock_bh(&pxmitpriv->lock);
467 ret = rtw_txframes_pending(padapter);
468 spin_unlock_bh(&pxmitpriv->lock);
476 int rtl8723bs_xmit_thread(void *context)
479 struct adapter *padapter;
480 struct xmit_priv *pxmitpriv;
481 u8 thread_name[20] = "RTWHALXT";
486 pxmitpriv = &padapter->xmitpriv;
488 rtw_sprintf(thread_name, 20, "%s-"ADPT_FMT, thread_name, ADPT_ARG(padapter));
489 thread_enter(thread_name);
491 DBG_871X("start "FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(padapter));
494 ret = rtl8723bs_xmit_handler(padapter);
495 if (signal_pending(current)) {
496 flush_signals(current);
498 } while (_SUCCESS == ret);
500 complete(&pxmitpriv->SdioXmitTerminate);
502 RT_TRACE(_module_hal_xmit_c_, _drv_notice_, ("-%s\n", __func__));
507 s32 rtl8723bs_mgnt_xmit(
508 struct adapter *padapter, struct xmit_frame *pmgntframe
512 struct pkt_attrib *pattrib;
513 struct xmit_buf *pxmitbuf;
514 struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
515 struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter);
516 u8 *pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
517 u8 txdesc_size = TXDESC_SIZE;
519 RT_TRACE(_module_hal_xmit_c_, _drv_info_, ("+%s\n", __func__));
521 pattrib = &pmgntframe->attrib;
522 pxmitbuf = pmgntframe->pxmitbuf;
524 rtl8723b_update_txdesc(pmgntframe, pmgntframe->buf_addr);
526 pxmitbuf->len = txdesc_size + pattrib->last_txcmdsz;
527 pxmitbuf->pg_num = (pxmitbuf->len + 127)/128; /* 128 is tx page size */
528 pxmitbuf->ptail = pmgntframe->buf_addr + pxmitbuf->len;
529 pxmitbuf->ff_hwaddr = rtw_get_ff_hwaddr(pmgntframe);
531 rtw_count_tx_stats(padapter, pmgntframe, pattrib->last_txcmdsz);
533 rtw_free_xmitframe(pxmitpriv, pmgntframe);
535 pxmitbuf->priv_data = NULL;
537 if (GetFrameSubType(pframe) == WIFI_BEACON) { /* dump beacon directly */
538 ret = rtw_write_port(padapter, pdvobjpriv->Queue2Pipe[pxmitbuf->ff_hwaddr], pxmitbuf->len, (u8 *)pxmitbuf);
540 rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_WRITE_PORT_ERR);
542 rtw_free_xmitbuf(pxmitpriv, pxmitbuf);
544 enqueue_pending_xmitbuf(pxmitpriv, pxmitbuf);
551 *Handle xmitframe(packet) come from rtw_xmit()
554 *true dump packet directly ok
555 *false enqueue, temporary can't transmit packets to hardware
557 s32 rtl8723bs_hal_xmit(
558 struct adapter *padapter, struct xmit_frame *pxmitframe
561 struct xmit_priv *pxmitpriv;
565 pxmitframe->attrib.qsel = pxmitframe->attrib.priority;
566 pxmitpriv = &padapter->xmitpriv;
569 (pxmitframe->frame_tag == DATA_FRAMETAG) &&
570 (pxmitframe->attrib.ether_type != 0x0806) &&
571 (pxmitframe->attrib.ether_type != 0x888e) &&
572 (pxmitframe->attrib.dhcp_pkt != 1)
574 if (padapter->mlmepriv.LinkDetectInfo.bBusyTraffic == true)
575 rtw_issue_addbareq_cmd(padapter, pxmitframe);
578 spin_lock_bh(&pxmitpriv->lock);
579 err = rtw_xmitframe_enqueue(padapter, pxmitframe);
580 spin_unlock_bh(&pxmitpriv->lock);
581 if (err != _SUCCESS) {
582 RT_TRACE(_module_hal_xmit_c_, _drv_err_, ("rtl8723bs_hal_xmit: enqueue xmitframe fail\n"));
583 rtw_free_xmitframe(pxmitpriv, pxmitframe);
585 pxmitpriv->tx_drop++;
589 complete(&pxmitpriv->SdioXmitStart);
594 s32 rtl8723bs_hal_xmitframe_enqueue(
595 struct adapter *padapter, struct xmit_frame *pxmitframe
598 struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
601 err = rtw_xmitframe_enqueue(padapter, pxmitframe);
602 if (err != _SUCCESS) {
603 rtw_free_xmitframe(pxmitpriv, pxmitframe);
605 pxmitpriv->tx_drop++;
607 #ifdef CONFIG_SDIO_TX_TASKLET
608 tasklet_hi_schedule(&pxmitpriv->xmit_tasklet);
610 complete(&pxmitpriv->SdioXmitStart);
620 *_SUCCESS start thread ok
621 *_FAIL start thread fail
624 s32 rtl8723bs_init_xmit_priv(struct adapter *padapter)
626 struct xmit_priv *xmitpriv = &padapter->xmitpriv;
627 struct hal_com_data *phal;
630 phal = GET_HAL_DATA(padapter);
632 spin_lock_init(&phal->SdioTxFIFOFreePageLock);
633 init_completion(&xmitpriv->SdioXmitStart);
634 init_completion(&xmitpriv->SdioXmitTerminate);
639 void rtl8723bs_free_xmit_priv(struct adapter *padapter)
641 struct hal_com_data *phal;
642 struct xmit_priv *pxmitpriv;
643 struct xmit_buf *pxmitbuf;
644 struct __queue *pqueue;
645 struct list_head *plist, *phead;
646 struct list_head tmplist;
649 phal = GET_HAL_DATA(padapter);
650 pxmitpriv = &padapter->xmitpriv;
651 pqueue = &pxmitpriv->pending_xmitbuf_queue;
652 phead = get_list_head(pqueue);
653 INIT_LIST_HEAD(&tmplist);
655 spin_lock_bh(&pqueue->lock);
656 if (!list_empty(&pqueue->queue)) {
657 /* Insert tmplist to end of queue, and delete phead */
658 /* then tmplist become head of queue. */
659 list_add_tail(&tmplist, phead);
660 list_del_init(phead);
662 spin_unlock_bh(&pqueue->lock);
665 while (list_empty(phead) == false) {
666 plist = get_next(phead);
667 list_del_init(plist);
669 pxmitbuf = LIST_CONTAINOR(plist, struct xmit_buf, list);
670 rtw_free_xmitframe(pxmitpriv, (struct xmit_frame *)pxmitbuf->priv_data);
671 pxmitbuf->priv_data = NULL;
672 rtw_free_xmitbuf(pxmitpriv, pxmitbuf);