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