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