1 /******************************************************************************
2 *
3 * Copyright(c) 2007 - 2017 Realtek Corporation.
4 *
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.
8 *
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
12 * more details.
13 *
14 *****************************************************************************/
15 #define _RTL8723DS_XMIT_C_
16
17 #include <rtl8723d_hal.h>
18
rtw_sdio_wait_enough_TxOQT_space(PADAPTER padapter,u8 agg_num)19 static u8 rtw_sdio_wait_enough_TxOQT_space(PADAPTER padapter, u8 agg_num)
20 {
21 u32 n = 0;
22 HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter);
23
24 while (pHalData->SdioTxOQTFreeSpace < agg_num) {
25 if (RTW_CANNOT_RUN(padapter)) {
26 RTW_INFO("%s: bSurpriseRemoved or bDriverStopped (wait TxOQT)\n", __func__);
27 return _FALSE;
28 }
29
30 HalQueryTxOQTBufferStatus8723DSdio(padapter);
31
32 if ((++n % 60) == 0) {
33 if ((n % 300) == 0) {
34 RTW_INFO("%s(%d): QOT free space(%d), agg_num: %d\n",
35 __func__, n, pHalData->SdioTxOQTFreeSpace, agg_num);
36 }
37 rtw_msleep_os(1);
38 /* yield(); */
39 }
40 }
41
42 pHalData->SdioTxOQTFreeSpace -= agg_num;
43
44 /* if (n > 1) */
45 /* ++priv->pshare->nr_out_of_txoqt_space; */
46
47 return _TRUE;
48 }
49
_dequeue_writeport(PADAPTER padapter)50 s32 _dequeue_writeport(PADAPTER padapter)
51 {
52 #if defined(DBG_TX_FREE_PAGE) || defined(CONFIG_SDIO_TX_ENABLE_AVAL_INT)
53 HAL_DATA_TYPE *hal_data = GET_HAL_DATA(padapter);
54 #endif
55 struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
56 struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
57 struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter);
58 struct xmit_buf *pxmitbuf;
59 u8 PageIdx = 0;
60 u32 deviceId;
61 #ifdef CONFIG_SDIO_TX_ENABLE_AVAL_INT
62 u8 bUpdatePageNum = _FALSE;
63 #else
64 u32 polling_num = 0;
65 #endif
66
67 pxmitbuf = select_and_dequeue_pending_xmitbuf(padapter);
68
69 if (pxmitbuf == NULL)
70 return _TRUE;
71
72 deviceId = ffaddr2deviceId(pdvobjpriv, pxmitbuf->ff_hwaddr);
73
74 /* translate fifo addr to queue index */
75 switch (deviceId) {
76 case WLAN_TX_HIQ_DEVICE_ID:
77 PageIdx = HI_QUEUE_IDX;
78 break;
79
80 case WLAN_TX_MIQ_DEVICE_ID:
81 PageIdx = MID_QUEUE_IDX;
82 break;
83
84 case WLAN_TX_LOQ_DEVICE_ID:
85 PageIdx = LOW_QUEUE_IDX;
86 break;
87 }
88
89 query_free_page:
90 /* check if hardware tx fifo page is enough */
91 if (_FALSE == rtw_hal_sdio_query_tx_freepage(padapter, PageIdx, pxmitbuf->pg_num)) {
92 if (RTW_CANNOT_RUN(padapter))
93 goto free_xmitbuf;
94 #ifdef CONFIG_SDIO_TX_ENABLE_AVAL_INT
95 if (!bUpdatePageNum) {
96 rtw_hal_sdio_avail_page_threshold_en(padapter, PageIdx, pxmitbuf->pg_num);
97 /* Total number of page is NOT available, so update current FIFO status */
98 HalQueryTxBufferStatus8723DSdio(padapter);
99 bUpdatePageNum = _TRUE;
100 goto query_free_page;
101 } else {
102 bUpdatePageNum = _FALSE;
103 enqueue_pending_xmitbuf_to_head(pxmitpriv, pxmitbuf);
104 #ifdef DBG_TX_FREE_PAGE
105 RTW_INFO("DQWP page not enough, len:%d, agg:%d, req %s:%u, cur H:%u, M:%u, L:%u, P:%u\n"
106 , pxmitbuf->len, pxmitbuf->agg_num
107 , sdio_tx_queue_str(PageIdx), pxmitbuf->pg_num
108 , hal_data->SdioTxFIFOFreePage[HI_QUEUE_IDX]
109 , hal_data->SdioTxFIFOFreePage[MID_QUEUE_IDX]
110 , hal_data->SdioTxFIFOFreePage[LOW_QUEUE_IDX]
111 , hal_data->SdioTxFIFOFreePage[PUBLIC_QUEUE_IDX]
112 );
113 #endif
114 return _TRUE;
115 }
116 #else /* CONFIG_SDIO_TX_ENABLE_AVAL_INT */
117 polling_num++;
118 if ((polling_num % 0x10) == 0) {
119 enqueue_pending_xmitbuf_to_head(pxmitpriv, pxmitbuf);
120 #ifdef DBG_TX_FREE_PAGE
121 RTW_INFO("DQWP FIFO starvation!(%d), len:%u, agg:%u, req %s:%u, cur H:%u, M:%u, L:%u, P:%u\n"
122 , polling_num, pxmitbuf->len, pxmitbuf->agg_num
123 , sdio_tx_queue_str(PageIdx), pxmitbuf->pg_num
124 , hal_data->SdioTxFIFOFreePage[HI_QUEUE_IDX]
125 , hal_data->SdioTxFIFOFreePage[MID_QUEUE_IDX]
126 , hal_data->SdioTxFIFOFreePage[LOW_QUEUE_IDX]
127 , hal_data->SdioTxFIFOFreePage[PUBLIC_QUEUE_IDX]
128 );
129 #endif
130 rtw_usleep_os(50);
131 return _FALSE;
132 }
133
134 /* Total number of page is NOT available, so update current FIFO status */
135 HalQueryTxBufferStatus8723DSdio(padapter);
136 goto query_free_page;
137 #endif /* CONFIG_SDIO_TX_ENABLE_AVAL_INT */
138 }
139
140 #ifdef CONFIG_LPS_POFF
141 if (rtl8723d_lps_poff_get_txbndy_status(padapter) == _TRUE) {
142 RTW_INFO("%s: enqueue xmitbuf to pending queue head~~~\n",
143 __func__);
144 enqueue_pending_xmitbuf_to_head(pxmitpriv, pxmitbuf);
145 return _TRUE;
146 }
147 #endif
148
149 if (rtw_sdio_wait_enough_TxOQT_space(padapter, pxmitbuf->agg_num) == _FALSE)
150 goto free_xmitbuf;
151
152 #ifdef CONFIG_CHECK_LEAVE_LPS
153 #ifdef CONFIG_LPS_CHK_BY_TP
154 if (!adapter_to_pwrctl(padapter)->lps_chk_by_tp)
155 #endif
156 traffic_check_for_leave_lps(padapter, _TRUE, pxmitbuf->agg_num);
157 #endif
158 #ifdef DBG_TX_FREE_PAGE
159 RTW_INFO("DQWP write, %s:%u\n", sdio_tx_queue_str(PageIdx), pxmitbuf->pg_num);
160 #endif
161
162 rtw_write_port(padapter, deviceId, pxmitbuf->len, (u8 *)pxmitbuf);
163
164 rtw_hal_sdio_update_tx_freepage(padapter, PageIdx, pxmitbuf->pg_num);
165 #ifdef DBG_TX_FREE_PAGE
166 RTW_INFO("DQWP write done, cur H:%u, M:%u, L:%u, P:%u\n"
167 , hal_data->SdioTxFIFOFreePage[HI_QUEUE_IDX]
168 , hal_data->SdioTxFIFOFreePage[MID_QUEUE_IDX]
169 , hal_data->SdioTxFIFOFreePage[LOW_QUEUE_IDX]
170 , hal_data->SdioTxFIFOFreePage[PUBLIC_QUEUE_IDX]
171 );
172 #endif
173
174 free_xmitbuf:
175 /* rtw_free_xmitframe(pxmitpriv, pframe); */
176 /* pxmitbuf->priv_data = NULL; */
177 rtw_free_xmitbuf(pxmitpriv, pxmitbuf);
178 #ifdef SDIO_FREE_XMIT_BUF_SEMA
179 if (pxmitbuf->buf_tag == XMITBUF_DATA)
180 rtw_sdio_free_xmitbuf_sema_up(pxmitpriv);
181 #endif
182 #if 0 /* improve TX/RX throughput balance */
183 {
184 PSDIO_DATA psdio;
185 struct sdio_func *func;
186 static u8 i = 0;
187 u32 sdio_hisr;
188 u8 j;
189
190 psdio = &adapter_to_dvobj(padapter)->intf_data;
191 func = psdio->func;
192
193 if (i == 2) {
194 j = 0;
195 while (j < 10) {
196 sdio_hisr = SdioLocalCmd52Read1Byte(padapter, SDIO_REG_HISR);
197 sdio_hisr &= GET_HAL_DATA(padapter)->sdio_himr;
198 if (sdio_hisr & SDIO_HISR_RX_REQUEST) {
199 sdio_claim_host(func);
200 sd_int_hdl(GET_PRIMARY_ADAPTER(padapter));
201 sdio_release_host(func);
202 } else
203 break;
204 j++;
205 }
206 i = 0;
207 } else
208 i++;
209 }
210 #endif
211
212 #ifdef CONFIG_SDIO_TX_TASKLET
213 tasklet_hi_schedule(&pxmitpriv->xmit_tasklet);
214 #endif
215
216 return _FALSE;
217 }
218
219 /*
220 * Description
221 * Transmit xmitbuf to hardware tx fifo
222 *
223 * Return
224 * _SUCCESS ok
225 * _FAIL something error
226 */
rtl8723ds_xmit_buf_handler(PADAPTER padapter)227 s32 rtl8723ds_xmit_buf_handler(PADAPTER padapter)
228 {
229 struct xmit_priv *pxmitpriv;
230 u8 queue_empty;
231 s32 ret;
232
233
234 pxmitpriv = &padapter->xmitpriv;
235
236 ret = _rtw_down_sema(&pxmitpriv->xmit_sema);
237 if (_FAIL == ret) {
238 RTW_ERR("%s: down SdioXmitBufSema fail!\n", __func__);
239 return _FAIL;
240 }
241
242 if (RTW_CANNOT_RUN(padapter)) {
243 RTW_DBG(FUNC_ADPT_FMT "- bDriverStopped(%s) bSurpriseRemoved(%s)\n",
244 FUNC_ADPT_ARG(padapter),
245 rtw_is_drv_stopped(padapter) ? "True" : "False",
246 rtw_is_surprise_removed(padapter) ? "True" : "False");
247 return _FAIL;
248 }
249
250 if (rtw_mi_check_pending_xmitbuf(padapter) == 0)
251 return _SUCCESS;
252
253 #ifdef CONFIG_LPS_LCLK
254 ret = rtw_register_tx_alive(padapter);
255 if (ret != _SUCCESS)
256 return _SUCCESS;
257 #endif
258 do {
259 queue_empty = rtw_mi_dequeue_writeport(padapter);
260 } while (!queue_empty);
261 #ifdef CONFIG_LPS_LCLK
262 rtw_unregister_tx_alive(padapter);
263 #endif
264
265 return _SUCCESS;
266 }
267
268 /*
269 * Description:
270 * Aggregation packets and send to hardware
271 *
272 * Return:
273 * 0 Success
274 * -1 Hardware resource(TX FIFO) not ready
275 * -2 Software resource(xmitbuf) not ready
276 */
xmit_xmitframes(PADAPTER padapter,struct xmit_priv * pxmitpriv)277 static s32 xmit_xmitframes(PADAPTER padapter, struct xmit_priv *pxmitpriv)
278 {
279 s32 err, ret;
280 u32 k = 0;
281 struct hw_xmit *hwxmits, *phwxmit;
282 u8 no_res, idx, hwentry;
283 _irqL irql;
284 struct tx_servq *ptxservq;
285 _list *sta_plist, *sta_phead, *frame_plist, *frame_phead;
286 struct xmit_frame *pxmitframe;
287 _queue *pframe_queue;
288 struct xmit_buf *pxmitbuf;
289 u32 txlen, max_xmit_len, page_size;
290 u8 txdesc_size = TXDESC_SIZE;
291 int inx[4];
292 u8 pre_qsel = 0xFF, next_qsel = 0xFF;
293 u8 single_sta_in_queue = _FALSE;
294 #ifdef SDIO_FREE_XMIT_BUF_SEMA
295 u32 consume;
296 #endif
297 err = 0;
298 no_res = _FALSE;
299 hwxmits = pxmitpriv->hwxmits;
300 hwentry = pxmitpriv->hwxmit_entry;
301 ptxservq = NULL;
302 pxmitframe = NULL;
303 pframe_queue = NULL;
304 pxmitbuf = NULL;
305
306 rtw_hal_get_def_var(padapter, HAL_DEF_TX_PAGE_SIZE, &page_size);
307
308 #ifdef CONFIG_RTW_MGMT_QUEUE
309 /* dump management frame directly */
310 do {
311 pxmitframe = rtw_dequeue_mgmt_xframe(pxmitpriv);
312 if (pxmitframe)
313 padapter->hal_func.mgnt_xmit(padapter, pxmitframe);
314 } while (pxmitframe != NULL);
315
316 hwentry--;
317 #endif
318
319 if (padapter->registrypriv.wifi_spec == 1) {
320 for (idx = 0; idx < 4; idx++)
321 inx[idx] = pxmitpriv->wmm_para_seq[idx];
322 } else {
323 inx[0] = 0;
324 inx[1] = 1;
325 inx[2] = 2;
326 inx[3] = 3;
327 }
328
329 /* 0(VO), 1(VI), 2(BE), 3(BK) */
330 for (idx = 0; idx < hwentry; idx++) {
331 phwxmit = hwxmits + inx[idx];
332 #ifdef SDIO_FREE_XMIT_BUF_SEMA
333 consume = 0;
334 #endif
335 if ((check_pending_xmitbuf(pxmitpriv) == _TRUE) && (padapter->mlmepriv.LinkDetectInfo.bHigherBusyTxTraffic == _TRUE)) {
336 if ((phwxmit->accnt > 0) && (phwxmit->accnt < 5)) {
337 err = RTW_TX_WAIT_MORE_FRAME;
338 break;
339 }
340 }
341
342 max_xmit_len = rtw_hal_get_sdio_tx_max_length(padapter, inx[idx]);
343
344 _enter_critical_bh(&pxmitpriv->lock, &irql);
345
346 sta_phead = get_list_head(phwxmit->sta_queue);
347 sta_plist = get_next(sta_phead);
348 /* because stop_sta_xmit may delete sta_plist at any time */
349 /* so we should add lock here, or while loop can not exit */
350
351 single_sta_in_queue = rtw_end_of_queue_search(sta_phead, get_next(sta_plist));
352
353 while (rtw_end_of_queue_search(sta_phead, sta_plist) == _FALSE) {
354 ptxservq = LIST_CONTAINOR(sta_plist, struct tx_servq, tx_pending);
355 sta_plist = get_next(sta_plist);
356
357 #ifdef DBG_XMIT_BUF
358 RTW_INFO("%s idx:%d hwxmit_pkt_num:%d ptxservq_pkt_num:%d\n", __func__, idx, phwxmit->accnt, ptxservq->qcnt);
359 RTW_INFO("%s free_xmit_extbuf_cnt=%d free_xmitbuf_cnt=%d free_xmitframe_cnt=%d\n",
360 __func__, pxmitpriv->free_xmit_extbuf_cnt, pxmitpriv->free_xmitbuf_cnt,
361 pxmitpriv->free_xmitframe_cnt);
362 #endif
363 pframe_queue = &ptxservq->sta_pending;
364
365 frame_phead = get_list_head(pframe_queue);
366
367 while (rtw_is_list_empty(frame_phead) == _FALSE) {
368 frame_plist = get_next(frame_phead);
369 pxmitframe = LIST_CONTAINOR(frame_plist, struct xmit_frame, list);
370
371 /* check xmit_buf size enough or not */
372 txlen = txdesc_size + rtw_wlan_pkt_size(pxmitframe);
373 next_qsel = pxmitframe->attrib.qsel;
374 if ((NULL == pxmitbuf) ||
375 (pxmitbuf->pg_num + PageNum(txlen, page_size) > PageNum(max_xmit_len, page_size))
376 || (k >= (rtw_hal_sdio_max_txoqt_free_space(padapter) - 1))
377 || ((k != 0) && (_FAIL == rtw_hal_busagg_qsel_check(padapter, pre_qsel, next_qsel)))
378 ) {
379 if (pxmitbuf) {
380 /* pxmitbuf->priv_data will be NULL, and will crash here */
381 if (pxmitbuf->len > 0 && pxmitbuf->priv_data) {
382 struct xmit_frame *pframe;
383
384 pframe = (struct xmit_frame *)pxmitbuf->priv_data;
385 pframe->agg_num = k;
386 pxmitbuf->agg_num = k;
387 rtl8723d_update_txdesc(pframe, pframe->buf_addr);
388 rtw_free_xmitframe(pxmitpriv, pframe);
389 pxmitbuf->priv_data = NULL;
390 enqueue_pending_xmitbuf(pxmitpriv, pxmitbuf);
391 /* can not yield under lock */
392
393 /* rtw_yield_os(); */
394 if (single_sta_in_queue == _FALSE) {
395 /* break the loop in case there is more than one sta in this ac queue */
396 pxmitbuf = NULL;
397 err = RTW_TX_BALANCE;
398 break;
399 }
400 } else
401 {
402 rtw_free_xmitbuf(pxmitpriv, pxmitbuf);
403 #ifdef SDIO_FREE_XMIT_BUF_SEMA
404 consume--;
405 #endif
406 }
407 }
408
409 pxmitbuf = rtw_alloc_xmitbuf(pxmitpriv);
410 if (pxmitbuf == NULL) {
411 #ifdef DBG_XMIT_BUF
412 RTW_ERR("%s: xmit_buf is not enough!\n", __func__);
413 #endif
414 err = RTW_XBUF_UNAVAIL;
415 break;
416 }
417 #ifdef SDIO_FREE_XMIT_BUF_SEMA
418 consume++;
419 #endif
420 k = 0;
421 }
422
423 /* ok to send, remove frame from queue */
424 #ifdef CONFIG_AP_MODE
425 if (MLME_IS_AP(padapter) || MLME_IS_MESH(padapter)) {
426 if ((pxmitframe->attrib.psta->state & WIFI_SLEEP_STATE) &&
427 (pxmitframe->attrib.triggered == 0)) {
428 RTW_INFO("%s: one not triggered pkt in queue when this STA sleep, break and goto next sta\n", __func__);
429 break;
430 }
431 }
432 #endif
433 rtw_list_delete(&pxmitframe->list);
434 ptxservq->qcnt--;
435 phwxmit->accnt--;
436
437 if (k == 0) {
438 pxmitbuf->ff_hwaddr = rtw_get_ff_hwaddr(pxmitframe);
439 pxmitbuf->priv_data = (u8 *)pxmitframe;
440 }
441
442 /* coalesce the xmitframe to xmitbuf */
443 pxmitframe->pxmitbuf = pxmitbuf;
444 pxmitframe->buf_addr = pxmitbuf->ptail;
445
446 ret = rtw_xmitframe_coalesce(padapter, pxmitframe->pkt, pxmitframe);
447 if (ret == _FAIL) {
448 RTW_ERR("%s: coalesce FAIL!", __func__);
449 /* Todo: error handler */
450 } else {
451 k++;
452 if (k != 1)
453 rtl8723d_update_txdesc(pxmitframe, pxmitframe->buf_addr);
454 rtw_count_tx_stats(padapter, pxmitframe, pxmitframe->attrib.last_txcmdsz);
455 pre_qsel = pxmitframe->attrib.qsel;
456 txlen = txdesc_size + pxmitframe->attrib.last_txcmdsz;
457 pxmitframe->pg_num = (txlen + 127) / 128;
458 pxmitbuf->pg_num += (txlen + 127) / 128;
459 /* if (k != 1) */
460 /* ((struct xmit_frame*)pxmitbuf->priv_data)->pg_num += pxmitframe->pg_num; */
461 pxmitbuf->ptail += _RND(txlen, 8); /* round to 8 bytes alignment */
462 pxmitbuf->len = _RND(pxmitbuf->len, 8) + txlen;
463 }
464
465 if (k != 1)
466 rtw_free_xmitframe(pxmitpriv, pxmitframe);
467 pxmitframe = NULL;
468 }
469
470 if (_rtw_queue_empty(pframe_queue) == _TRUE)
471 rtw_list_delete(&ptxservq->tx_pending);
472 else if (err == RTW_TX_BALANCE) {
473 /* Re-arrange the order of stations in this ac queue to balance the service for these stations */
474 rtw_list_delete(&ptxservq->tx_pending);
475 rtw_list_insert_tail(&ptxservq->tx_pending, get_list_head(phwxmit->sta_queue));
476 }
477
478 if (err)
479 break;
480 }
481 _exit_critical_bh(&pxmitpriv->lock, &irql);
482 #ifdef SDIO_FREE_XMIT_BUF_SEMA
483 #ifdef DBG_SDIO_FREE_XMIT_BUF_SEMA
484 if (consume)
485 RTW_INFO(FUNC_ADPT_FMT" acq[%u], consume:%u\n", FUNC_ADPT_ARG(padapter), inx[idx], consume);
486 #endif
487 while (consume--)
488 rtw_sdio_free_xmitbuf_sema_down(pxmitpriv);
489 #endif
490 /* dump xmit_buf to hw tx fifo */
491 if (pxmitbuf) {
492
493 if (pxmitbuf->len > 0) {
494 struct xmit_frame *pframe;
495
496 pframe = (struct xmit_frame *)pxmitbuf->priv_data;
497 pframe->agg_num = k;
498 pxmitbuf->agg_num = k;
499 rtl8723d_update_txdesc(pframe, pframe->buf_addr);
500 rtw_free_xmitframe(pxmitpriv, pframe);
501 pxmitbuf->priv_data = NULL;
502 enqueue_pending_xmitbuf(pxmitpriv, pxmitbuf);
503 rtw_yield_os();
504 } else{
505 rtw_free_xmitbuf(pxmitpriv, pxmitbuf);
506 #ifdef SDIO_FREE_XMIT_BUF_SEMA
507 rtw_sdio_free_xmitbuf_sema_up(pxmitpriv);
508 #endif
509 }
510 pxmitbuf = NULL;
511 }
512
513 if (err == RTW_XBUF_UNAVAIL)
514 break;
515 }
516
517 return err;
518 }
519
520 /*
521 * Description
522 * Transmit xmitframe from queue
523 *
524 * Return
525 * _SUCCESS ok
526 * _FAIL something error
527 */
rtl8723ds_xmit_handler(PADAPTER padapter)528 s32 rtl8723ds_xmit_handler(PADAPTER padapter)
529 {
530 struct xmit_priv *pxmitpriv;
531 s32 ret;
532 _irqL irql;
533
534
535 pxmitpriv = &padapter->xmitpriv;
536
537 ret = _rtw_down_sema(&pxmitpriv->SdioXmitSema);
538 if (_FAIL == ret) {
539 RTW_ERR("%s: down sema fail!\n", __func__);
540 return _FAIL;
541 }
542
543 next:
544 if (RTW_CANNOT_RUN(padapter)) {
545 RTW_DBG(FUNC_ADPT_FMT "- bDriverStopped(%s) bSurpriseRemoved(%s)\n",
546 FUNC_ADPT_ARG(padapter),
547 rtw_is_drv_stopped(padapter) ? "True" : "False",
548 rtw_is_surprise_removed(padapter) ? "True" : "False");
549 return _FAIL;
550 }
551
552 _enter_critical_bh(&pxmitpriv->lock, &irql);
553 ret = rtw_txframes_pending(padapter);
554 _exit_critical_bh(&pxmitpriv->lock, &irql);
555 if (ret == 0)
556 return _SUCCESS;
557
558 /* dequeue frame and write to hardware */
559
560 ret = xmit_xmitframes(padapter, pxmitpriv);
561 if (ret == RTW_XBUF_UNAVAIL
562 || ret == RTW_TX_WAIT_MORE_FRAME
563 ) {
564 #ifdef SDIO_FREE_XMIT_BUF_SEMA
565 if (ret == RTW_XBUF_UNAVAIL) {
566 rtw_sdio_free_xmitbuf_sema_down(pxmitpriv);
567 rtw_sdio_free_xmitbuf_sema_up(pxmitpriv);
568 goto next;
569 }
570 #endif
571
572 if (padapter->registrypriv.wifi_spec)
573 rtw_msleep_os(1);
574 else {
575 #ifdef CONFIG_REDUCE_TX_CPU_LOADING
576 rtw_msleep_os(1);
577 #else
578 rtw_yield_os();
579 #endif
580 }
581 goto next;
582 }
583 _enter_critical_bh(&pxmitpriv->lock, &irql);
584 ret = rtw_txframes_pending(padapter);
585 _exit_critical_bh(&pxmitpriv->lock, &irql);
586 if (ret == 1) {
587 #ifdef CONFIG_REDUCE_TX_CPU_LOADING
588 rtw_msleep_os(1);
589 #endif
590 goto next;
591 }
592
593 return _SUCCESS;
594 }
595
rtl8723ds_xmit_thread(thread_context context)596 thread_return rtl8723ds_xmit_thread(thread_context context)
597 {
598 s32 ret;
599 PADAPTER padapter;
600 struct xmit_priv *pxmitpriv;
601 u8 thread_name[20] = {0};
602 #ifdef RTW_XMIT_THREAD_HIGH_PRIORITY_AGG
603 #ifdef PLATFORM_LINUX
604 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 9, 0))
605 sched_set_fifo_low(current);
606 #else
607 struct sched_param param = { .sched_priority = 1 };
608
609 sched_setscheduler(current, SCHED_FIFO, ¶m);
610 #endif
611 #endif /* PLATFORM_LINUX */
612 #endif /* RTW_XMIT_THREAD_HIGH_PRIORITY_AGG */
613
614 ret = _SUCCESS;
615 padapter = (PADAPTER)context;
616 pxmitpriv = &padapter->xmitpriv;
617
618 rtw_sprintf(thread_name, 20, "RTWHALXT-"ADPT_FMT, ADPT_ARG(padapter));
619 thread_enter(thread_name);
620
621 RTW_INFO("start "FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(padapter));
622
623 do {
624 ret = rtl8723ds_xmit_handler(padapter);
625 flush_signals_thread();
626 } while (_SUCCESS == ret);
627
628 RTW_INFO(FUNC_ADPT_FMT " Exit\n", FUNC_ADPT_ARG(padapter));
629
630 rtw_thread_wait_stop();
631
632 return 0;
633 }
634
rtl8723ds_mgnt_xmit(PADAPTER padapter,struct xmit_frame * pmgntframe)635 s32 rtl8723ds_mgnt_xmit(PADAPTER padapter, struct xmit_frame *pmgntframe)
636 {
637 s32 ret = _SUCCESS;
638 struct pkt_attrib *pattrib;
639 struct xmit_buf *pxmitbuf;
640 struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
641 struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter);
642 u8 *pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
643 u8 txdesc_size = TXDESC_SIZE;
644
645
646 pattrib = &pmgntframe->attrib;
647 pxmitbuf = pmgntframe->pxmitbuf;
648
649 rtl8723d_update_txdesc(pmgntframe, pmgntframe->buf_addr);
650
651 pxmitbuf->len = txdesc_size + pattrib->last_txcmdsz;
652 /* pmgntframe->pg_num = (pxmitbuf->len + 127)/128; // 128 is tx page size */
653 pxmitbuf->pg_num = (pxmitbuf->len + 127) / 128; /* 128 is tx page size */
654 pxmitbuf->ptail = pmgntframe->buf_addr + pxmitbuf->len;
655 pxmitbuf->ff_hwaddr = rtw_get_ff_hwaddr(pmgntframe);
656
657 rtw_count_tx_stats(padapter, pmgntframe, pattrib->last_txcmdsz);
658
659 rtw_free_xmitframe(pxmitpriv, pmgntframe);
660
661 pxmitbuf->priv_data = NULL;
662
663 if (get_frame_sub_type(pframe) == WIFI_BEACON ||
664 pxmitbuf->buf_tag == XMITBUF_CMD) {
665
666 #ifdef CONFIG_LPS_POFF
667 if (rtl8723d_lps_poff_get_txbndy_status(padapter) == _TRUE) {
668 RTW_INFO("%s: enqueue xmitbuf to pending queue ~~~\n",
669 __func__);
670 enqueue_pending_xmitbuf(pxmitpriv, pxmitbuf);
671 return ret;
672 }
673 #endif
674 ret = rtw_write_port(padapter, pdvobjpriv->Queue2Pipe[pxmitbuf->ff_hwaddr], pxmitbuf->len, (u8 *)pxmitbuf);
675 if (ret != _SUCCESS)
676 rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_WRITE_PORT_ERR);
677
678 rtw_free_xmitbuf(pxmitpriv, pxmitbuf);
679 } else
680 enqueue_pending_xmitbuf(pxmitpriv, pxmitbuf);
681
682 return ret;
683 }
684
685 /*
686 * Description:
687 * Handle xmitframe(packet) come from rtw_xmit()
688 *
689 * Return:
690 * _TRUE dump packet directly ok
691 * _FALSE enqueue, temporary can't transmit packets to hardware
692 */
rtl8723ds_hal_xmit(PADAPTER padapter,struct xmit_frame * pxmitframe)693 s32 rtl8723ds_hal_xmit(PADAPTER padapter, struct xmit_frame *pxmitframe)
694 {
695 struct xmit_priv *pxmitpriv;
696 _irqL irql;
697 s32 err;
698
699
700 pxmitframe->attrib.qsel = pxmitframe->attrib.priority;
701 pxmitpriv = &padapter->xmitpriv;
702
703 #ifdef CONFIG_80211N_HT
704 if ((pxmitframe->frame_tag == DATA_FRAMETAG) &&
705 (pxmitframe->attrib.ether_type != 0x0806) &&
706 (pxmitframe->attrib.ether_type != 0x888e) &&
707 (pxmitframe->attrib.dhcp_pkt != 1)) {
708 rtw_issue_addbareq_cmd(padapter, pxmitframe, _TRUE);
709 }
710 #endif
711
712 _enter_critical_bh(&pxmitpriv->lock, &irql);
713 err = rtw_xmitframe_enqueue(padapter, pxmitframe);
714 _exit_critical_bh(&pxmitpriv->lock, &irql);
715 if (err != _SUCCESS) {
716 rtw_free_xmitframe(pxmitpriv, pxmitframe);
717
718 pxmitpriv->tx_drop++;
719 return _TRUE;
720 }
721
722 _rtw_up_sema(&pxmitpriv->SdioXmitSema);
723
724 return _FALSE;
725 }
726
727 #ifdef CONFIG_RTW_MGMT_QUEUE
rtl8723ds_hal_mgmt_xmitframe_enqueue(PADAPTER adapter,struct xmit_frame * pxmitframe)728 s32 rtl8723ds_hal_mgmt_xmitframe_enqueue(PADAPTER adapter, struct xmit_frame *pxmitframe)
729 {
730 struct xmit_priv *pxmitpriv;
731 s32 ret;
732
733 pxmitpriv = &adapter->xmitpriv;
734
735 ret = rtw_mgmt_xmitframe_enqueue(adapter, pxmitframe);
736 if (ret != _SUCCESS) {
737 rtw_free_xmitframe(pxmitpriv, pxmitframe);
738 pxmitpriv->tx_drop++;
739 return _FALSE;
740 }
741
742 #ifdef CONFIG_SDIO_TX_TASKLET
743 tasklet_hi_schedule(&pxmitpriv->xmit_tasklet);
744 #else
745 _rtw_up_sema(&pxmitpriv->SdioXmitSema);
746 #endif
747
748 return _TRUE;
749 }
750 #endif
751
rtl8723ds_hal_xmitframe_enqueue(_adapter * padapter,struct xmit_frame * pxmitframe)752 s32 rtl8723ds_hal_xmitframe_enqueue(_adapter *padapter, struct xmit_frame *pxmitframe)
753 {
754 struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
755 s32 err;
756
757 err = rtw_xmitframe_enqueue(padapter, pxmitframe);
758 if (err != _SUCCESS) {
759 rtw_free_xmitframe(pxmitpriv, pxmitframe);
760
761 pxmitpriv->tx_drop++;
762 } else {
763 #ifdef CONFIG_SDIO_TX_TASKLET
764 tasklet_hi_schedule(&pxmitpriv->xmit_tasklet);
765 #else
766 _rtw_up_sema(&pxmitpriv->SdioXmitSema);
767 #endif
768 }
769
770 return err;
771
772 }
773
774 /*
775 * Return
776 * _SUCCESS start thread ok
777 * _FAIL start thread fail
778 *
779 */
rtl8723ds_init_xmit_priv(PADAPTER padapter)780 s32 rtl8723ds_init_xmit_priv(PADAPTER padapter)
781 {
782 struct xmit_priv *xmitpriv = &padapter->xmitpriv;
783 PHAL_DATA_TYPE phal;
784
785
786 phal = GET_HAL_DATA(padapter);
787
788 _rtw_spinlock_init(&phal->SdioTxFIFOFreePageLock);
789 _rtw_init_sema(&xmitpriv->SdioXmitSema, 0);
790 #ifdef SDIO_FREE_XMIT_BUF_SEMA
791 _rtw_init_sema(&xmitpriv->sdio_free_xmitbuf_sema, xmitpriv->free_xmitbuf_cnt);
792 #endif
793 return _SUCCESS;
794 }
795
rtl8723ds_free_xmit_priv(PADAPTER padapter)796 void rtl8723ds_free_xmit_priv(PADAPTER padapter)
797 {
798 PHAL_DATA_TYPE phal;
799 struct xmit_priv *pxmitpriv;
800 struct xmit_buf *pxmitbuf;
801 _queue *pqueue;
802 _list *plist, *phead;
803 _list tmplist;
804 _irqL irql;
805
806
807 phal = GET_HAL_DATA(padapter);
808 pxmitpriv = &padapter->xmitpriv;
809 pqueue = &pxmitpriv->pending_xmitbuf_queue;
810 phead = get_list_head(pqueue);
811 _rtw_init_listhead(&tmplist);
812
813 _enter_critical_bh(&pqueue->lock, &irql);
814 if (_rtw_queue_empty(pqueue) == _FALSE) {
815 /* Insert tmplist to end of queue, and delete phead */
816 /* then tmplist become head of queue. */
817 rtw_list_insert_tail(&tmplist, phead);
818 rtw_list_delete(phead);
819 }
820 _exit_critical_bh(&pqueue->lock, &irql);
821
822 phead = &tmplist;
823 while (rtw_is_list_empty(phead) == _FALSE) {
824 plist = get_next(phead);
825 rtw_list_delete(plist);
826
827 pxmitbuf = LIST_CONTAINOR(plist, struct xmit_buf, list);
828 rtw_free_xmitframe(pxmitpriv, (struct xmit_frame *)pxmitbuf->priv_data);
829 pxmitbuf->priv_data = NULL;
830 rtw_free_xmitbuf(pxmitpriv, pxmitbuf);
831 #ifdef SDIO_FREE_XMIT_BUF_SEMA
832 if (pxmitbuf->buf_tag == XMITBUF_DATA)
833 rtw_sdio_free_xmitbuf_sema_up(pxmitpriv);
834 #endif
835 }
836 _rtw_spinlock_free(&phal->SdioTxFIFOFreePageLock);
837 }
838