1// SPDX-License-Identifier: GPL-2.0
2/******************************************************************************
3 *
4 * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
5 *
6 ******************************************************************************/
7
8#include <drv_types.h>
9#include <rtw_debug.h>
10#include <rtl8723b_hal.h>
11
12static u8 rtw_sdio_wait_enough_TxOQT_space(struct adapter *padapter, u8 agg_num)
13{
14 u32 n = 0;
15 struct hal_com_data *pHalData = GET_HAL_DATA(padapter);
16
17 while (pHalData->SdioTxOQTFreeSpace < agg_num) {
18 if (
19 (padapter->bSurpriseRemoved) ||
20 (padapter->bDriverStopped)
21 )
22 return false;
23
24 HalQueryTxOQTBufferStatus8723BSdio(padapter);
25
26 if ((++n % 60) == 0) {
27 msleep(msecs: 1);
28 /* yield(); */
29 }
30 }
31
32 pHalData->SdioTxOQTFreeSpace -= agg_num;
33
34 return true;
35}
36
37static s32 rtl8723_dequeue_writeport(struct adapter *padapter)
38{
39 struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
40 struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
41 struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter);
42 struct xmit_buf *pxmitbuf;
43 struct adapter *pri_padapter = padapter;
44 s32 ret = 0;
45 u8 PageIdx = 0;
46 u32 deviceId;
47 u8 bUpdatePageNum = false;
48
49 ret = ret || check_fwstate(pmlmepriv, _FW_UNDER_SURVEY);
50
51 if (ret)
52 pxmitbuf = dequeue_pending_xmitbuf_under_survey(pxmitpriv);
53 else
54 pxmitbuf = dequeue_pending_xmitbuf(pxmitpriv);
55
56 if (!pxmitbuf)
57 return true;
58
59 deviceId = ffaddr2deviceId(pdvobjpriv, pxmitbuf->ff_hwaddr);
60
61 /* translate fifo addr to queue index */
62 switch (deviceId) {
63 case WLAN_TX_HIQ_DEVICE_ID:
64 PageIdx = HI_QUEUE_IDX;
65 break;
66
67 case WLAN_TX_MIQ_DEVICE_ID:
68 PageIdx = MID_QUEUE_IDX;
69 break;
70
71 case WLAN_TX_LOQ_DEVICE_ID:
72 PageIdx = LOW_QUEUE_IDX;
73 break;
74 }
75
76query_free_page:
77 /* check if hardware tx fifo page is enough */
78 if (!rtw_hal_sdio_query_tx_freepage(padapter: pri_padapter, PageIdx, RequiredPageNum: pxmitbuf->pg_num)) {
79 if (!bUpdatePageNum) {
80 /* Total number of page is NOT available, so update current FIFO status */
81 HalQueryTxBufferStatus8723BSdio(padapter);
82 bUpdatePageNum = true;
83 goto query_free_page;
84 } else {
85 bUpdatePageNum = false;
86 enqueue_pending_xmitbuf_to_head(pxmitpriv, pxmitbuf);
87 return true;
88 }
89 }
90
91 if (
92 (padapter->bSurpriseRemoved) ||
93 (padapter->bDriverStopped)
94 )
95 goto free_xmitbuf;
96
97 if (rtw_sdio_wait_enough_TxOQT_space(padapter, agg_num: pxmitbuf->agg_num) == false)
98 goto free_xmitbuf;
99
100 traffic_check_for_leave_lps(padapter, tx: true, tx_packets: pxmitbuf->agg_num);
101
102 rtw_write_port(adapter: padapter, addr: deviceId, cnt: pxmitbuf->len, pmem: (u8 *)pxmitbuf);
103
104 rtw_hal_sdio_update_tx_freepage(padapter: pri_padapter, PageIdx, RequiredPageNum: pxmitbuf->pg_num);
105
106free_xmitbuf:
107 /* rtw_free_xmitframe(pxmitpriv, pframe); */
108 /* pxmitbuf->priv_data = NULL; */
109 rtw_free_xmitbuf(pxmitpriv, pxmitbuf);
110
111 return _FAIL;
112}
113
114/*
115 * Description
116 *Transmit xmitbuf to hardware tx fifo
117 *
118 * Return
119 *_SUCCESS ok
120 *_FAIL something error
121 */
122s32 rtl8723bs_xmit_buf_handler(struct adapter *padapter)
123{
124 struct xmit_priv *pxmitpriv;
125 u8 queue_empty, queue_pending;
126 s32 ret;
127
128
129 pxmitpriv = &padapter->xmitpriv;
130
131 if (wait_for_completion_interruptible(x: &pxmitpriv->xmit_comp)) {
132 netdev_emerg(dev: padapter->pnetdev,
133 format: "%s: down SdioXmitBufSema fail!\n", __func__);
134 return _FAIL;
135 }
136
137 ret = (padapter->bDriverStopped) || (padapter->bSurpriseRemoved);
138 if (ret)
139 return _FAIL;
140
141 queue_pending = check_pending_xmitbuf(pxmitpriv);
142
143 if (!queue_pending)
144 return _SUCCESS;
145
146 ret = rtw_register_tx_alive(padapter);
147 if (ret != _SUCCESS) {
148 return _SUCCESS;
149 }
150
151 do {
152 queue_empty = rtl8723_dequeue_writeport(padapter);
153/* dump secondary adapter xmitbuf */
154 } while (!queue_empty);
155
156 rtw_unregister_tx_alive(padapter);
157
158 return _SUCCESS;
159}
160
161/*
162 * Description:
163 *Aggregation packets and send to hardware
164 *
165 * Return:
166 *0 Success
167 *-1 Hardware resource(TX FIFO) not ready
168 *-2 Software resource(xmitbuf) not ready
169 */
170static s32 xmit_xmitframes(struct adapter *padapter, struct xmit_priv *pxmitpriv)
171{
172 s32 err, ret;
173 u32 k = 0;
174 struct hw_xmit *hwxmits, *phwxmit;
175 u8 idx, hwentry;
176 struct tx_servq *ptxservq;
177 struct list_head *sta_plist, *sta_phead, *frame_plist, *frame_phead, *tmp;
178 struct xmit_frame *pxmitframe;
179 struct __queue *pframe_queue;
180 struct xmit_buf *pxmitbuf;
181 u32 txlen, max_xmit_len;
182 u8 txdesc_size = TXDESC_SIZE;
183 int inx[4];
184
185 err = 0;
186 hwxmits = pxmitpriv->hwxmits;
187 hwentry = pxmitpriv->hwxmit_entry;
188 ptxservq = NULL;
189 pxmitframe = NULL;
190 pframe_queue = NULL;
191 pxmitbuf = NULL;
192
193 if (padapter->registrypriv.wifi_spec == 1) {
194 for (idx = 0; idx < 4; idx++)
195 inx[idx] = pxmitpriv->wmm_para_seq[idx];
196 } else {
197 inx[0] = 0;
198 inx[1] = 1;
199 inx[2] = 2;
200 inx[3] = 3;
201 }
202
203 /* 0(VO), 1(VI), 2(BE), 3(BK) */
204 for (idx = 0; idx < hwentry; idx++) {
205 phwxmit = hwxmits + inx[idx];
206
207 if (
208 (check_pending_xmitbuf(pxmitpriv)) &&
209 (padapter->mlmepriv.LinkDetectInfo.bHigherBusyTxTraffic)
210 ) {
211 if ((phwxmit->accnt > 0) && (phwxmit->accnt < 5)) {
212 err = -2;
213 break;
214 }
215 }
216
217 max_xmit_len = rtw_hal_get_sdio_tx_max_length(padapter, queue_idx: inx[idx]);
218
219 spin_lock_bh(lock: &pxmitpriv->lock);
220
221 sta_phead = get_list_head(queue: phwxmit->sta_queue);
222 /* because stop_sta_xmit may delete sta_plist at any time */
223 /* so we should add lock here, or while loop can not exit */
224 list_for_each_safe(sta_plist, tmp, sta_phead) {
225 ptxservq = list_entry(sta_plist, struct tx_servq,
226 tx_pending);
227
228 pframe_queue = &ptxservq->sta_pending;
229
230 frame_phead = get_list_head(queue: pframe_queue);
231
232 while (list_empty(head: frame_phead) == false) {
233 frame_plist = get_next(list: frame_phead);
234 pxmitframe = container_of(frame_plist, struct xmit_frame, list);
235
236 /* check xmit_buf size enough or not */
237 txlen = txdesc_size + rtw_wlan_pkt_size(pxmitframe);
238 if (!pxmitbuf ||
239 ((_RND(pxmitbuf->len, 8) + txlen) > max_xmit_len) ||
240 (k >= (rtw_hal_sdio_max_txoqt_free_space(padapter) - 1))
241 ) {
242 if (pxmitbuf) {
243 /* pxmitbuf->priv_data will be NULL, and will crash here */
244 if (pxmitbuf->len > 0 &&
245 pxmitbuf->priv_data) {
246 struct xmit_frame *pframe;
247 pframe = (struct xmit_frame *)pxmitbuf->priv_data;
248 pframe->agg_num = k;
249 pxmitbuf->agg_num = k;
250 rtl8723b_update_txdesc(pxmitframe: pframe, pmem: pframe->buf_addr);
251 rtw_free_xmitframe(pxmitpriv, pxmitframe: pframe);
252 pxmitbuf->priv_data = NULL;
253 enqueue_pending_xmitbuf(pxmitpriv, pxmitbuf);
254 /* can not yield under lock */
255 /* yield(); */
256 } else
257 rtw_free_xmitbuf(pxmitpriv, pxmitbuf);
258 }
259
260 pxmitbuf = rtw_alloc_xmitbuf(pxmitpriv);
261 if (!pxmitbuf) {
262#ifdef DBG_XMIT_BUF
263 netdev_err(padapter->pnetdev,
264 "%s: xmit_buf is not enough!\n",
265 __func__);
266#endif
267 err = -2;
268 complete(&(pxmitpriv->xmit_comp));
269 break;
270 }
271 k = 0;
272 }
273
274 /* ok to send, remove frame from queue */
275 if (check_fwstate(pmlmepriv: &padapter->mlmepriv, WIFI_AP_STATE) == true)
276 if (
277 (pxmitframe->attrib.psta->state & WIFI_SLEEP_STATE) &&
278 (pxmitframe->attrib.triggered == 0)
279 )
280 break;
281
282 list_del_init(entry: &pxmitframe->list);
283 ptxservq->qcnt--;
284 phwxmit->accnt--;
285
286 if (k == 0) {
287 pxmitbuf->ff_hwaddr = rtw_get_ff_hwaddr(pxmitframe);
288 pxmitbuf->priv_data = (u8 *)pxmitframe;
289 }
290
291 /* coalesce the xmitframe to xmitbuf */
292 pxmitframe->pxmitbuf = pxmitbuf;
293 pxmitframe->buf_addr = pxmitbuf->ptail;
294
295 ret = rtw_xmitframe_coalesce(padapter, pkt: pxmitframe->pkt, pxmitframe);
296 if (ret == _FAIL) {
297 netdev_err(dev: padapter->pnetdev,
298 format: "%s: coalesce FAIL!",
299 __func__);
300 /* Todo: error handler */
301 } else {
302 k++;
303 if (k != 1)
304 rtl8723b_update_txdesc(pxmitframe, pmem: pxmitframe->buf_addr);
305 rtw_count_tx_stats(padapter, pxmitframe, sz: pxmitframe->attrib.last_txcmdsz);
306
307 txlen = txdesc_size + pxmitframe->attrib.last_txcmdsz;
308 pxmitframe->pg_num = (txlen + 127) / 128;
309 pxmitbuf->pg_num += (txlen + 127) / 128;
310 pxmitbuf->ptail += _RND(txlen, 8); /* round to 8 bytes alignment */
311 pxmitbuf->len = _RND(pxmitbuf->len, 8) + txlen;
312 }
313
314 if (k != 1)
315 rtw_free_xmitframe(pxmitpriv, pxmitframe);
316 pxmitframe = NULL;
317 }
318
319 if (list_empty(head: &pframe_queue->queue))
320 list_del_init(entry: &ptxservq->tx_pending);
321
322 if (err)
323 break;
324 }
325 spin_unlock_bh(lock: &pxmitpriv->lock);
326
327 /* dump xmit_buf to hw tx fifo */
328 if (pxmitbuf) {
329 if (pxmitbuf->len > 0) {
330 struct xmit_frame *pframe;
331 pframe = (struct xmit_frame *)pxmitbuf->priv_data;
332 pframe->agg_num = k;
333 pxmitbuf->agg_num = k;
334 rtl8723b_update_txdesc(pxmitframe: pframe, pmem: pframe->buf_addr);
335 rtw_free_xmitframe(pxmitpriv, pxmitframe: pframe);
336 pxmitbuf->priv_data = NULL;
337 enqueue_pending_xmitbuf(pxmitpriv, pxmitbuf);
338 yield();
339 } else
340 rtw_free_xmitbuf(pxmitpriv, pxmitbuf);
341 pxmitbuf = NULL;
342 }
343
344 if (err)
345 break;
346 }
347
348 return err;
349}
350
351/*
352 * Description
353 *Transmit xmitframe from queue
354 *
355 * Return
356 *_SUCCESS ok
357 *_FAIL something error
358 */
359static s32 rtl8723bs_xmit_handler(struct adapter *padapter)
360{
361 struct xmit_priv *pxmitpriv;
362 s32 ret;
363
364
365 pxmitpriv = &padapter->xmitpriv;
366
367 if (wait_for_completion_interruptible(x: &pxmitpriv->SdioXmitStart)) {
368 netdev_emerg(dev: padapter->pnetdev, format: "%s: SdioXmitStart fail!\n",
369 __func__);
370 return _FAIL;
371 }
372
373next:
374 if (
375 (padapter->bDriverStopped) ||
376 (padapter->bSurpriseRemoved)
377 )
378 return _FAIL;
379
380 spin_lock_bh(lock: &pxmitpriv->lock);
381 ret = rtw_txframes_pending(padapter);
382 spin_unlock_bh(lock: &pxmitpriv->lock);
383 if (ret == 0) {
384 return _SUCCESS;
385 }
386
387 /* dequeue frame and write to hardware */
388
389 ret = xmit_xmitframes(padapter, pxmitpriv);
390 if (ret == -2) {
391 /* here sleep 1ms will cause big TP loss of TX */
392 /* from 50+ to 40+ */
393 if (padapter->registrypriv.wifi_spec)
394 msleep(msecs: 1);
395 else
396 yield();
397 goto next;
398 }
399
400 spin_lock_bh(lock: &pxmitpriv->lock);
401 ret = rtw_txframes_pending(padapter);
402 spin_unlock_bh(lock: &pxmitpriv->lock);
403 if (ret == 1) {
404 goto next;
405 }
406
407 return _SUCCESS;
408}
409
410int rtl8723bs_xmit_thread(void *context)
411{
412 s32 ret;
413 struct adapter *padapter;
414 struct xmit_priv *pxmitpriv;
415 u8 thread_name[20];
416
417 ret = _SUCCESS;
418 padapter = context;
419 pxmitpriv = &padapter->xmitpriv;
420
421 rtw_sprintf(thread_name, 20, "RTWHALXT-%s", ADPT_ARG(padapter));
422 thread_enter(name: thread_name);
423
424 do {
425 ret = rtl8723bs_xmit_handler(padapter);
426 if (signal_pending(current)) {
427 flush_signals(current);
428 }
429 } while (_SUCCESS == ret);
430
431 complete(&pxmitpriv->SdioXmitTerminate);
432
433 return 0;
434}
435
436s32 rtl8723bs_mgnt_xmit(
437 struct adapter *padapter, struct xmit_frame *pmgntframe
438)
439{
440 s32 ret = _SUCCESS;
441 struct pkt_attrib *pattrib;
442 struct xmit_buf *pxmitbuf;
443 struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
444 struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter);
445 u8 *pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
446 u8 txdesc_size = TXDESC_SIZE;
447
448 pattrib = &pmgntframe->attrib;
449 pxmitbuf = pmgntframe->pxmitbuf;
450
451 rtl8723b_update_txdesc(pxmitframe: pmgntframe, pmem: pmgntframe->buf_addr);
452
453 pxmitbuf->len = txdesc_size + pattrib->last_txcmdsz;
454 pxmitbuf->pg_num = (pxmitbuf->len + 127) / 128; /* 128 is tx page size */
455 pxmitbuf->ptail = pmgntframe->buf_addr + pxmitbuf->len;
456 pxmitbuf->ff_hwaddr = rtw_get_ff_hwaddr(pxmitframe: pmgntframe);
457
458 rtw_count_tx_stats(padapter, pxmitframe: pmgntframe, sz: pattrib->last_txcmdsz);
459
460 rtw_free_xmitframe(pxmitpriv, pxmitframe: pmgntframe);
461
462 pxmitbuf->priv_data = NULL;
463
464 if (GetFrameSubType(pframe) == WIFI_BEACON) { /* dump beacon directly */
465 ret = rtw_write_port(adapter: padapter, addr: pdvobjpriv->Queue2Pipe[pxmitbuf->ff_hwaddr], cnt: pxmitbuf->len, pmem: (u8 *)pxmitbuf);
466 if (ret != _SUCCESS)
467 rtw_sctx_done_err(sctx: &pxmitbuf->sctx, status: RTW_SCTX_DONE_WRITE_PORT_ERR);
468
469 rtw_free_xmitbuf(pxmitpriv, pxmitbuf);
470 } else
471 enqueue_pending_xmitbuf(pxmitpriv, pxmitbuf);
472
473 return ret;
474}
475
476/*
477 * Description:
478 *Handle xmitframe(packet) come from rtw_xmit()
479 *
480 * Return:
481 *true dump packet directly ok
482 *false enqueue, temporary can't transmit packets to hardware
483 */
484s32 rtl8723bs_hal_xmit(
485 struct adapter *padapter, struct xmit_frame *pxmitframe
486)
487{
488 struct xmit_priv *pxmitpriv;
489 s32 err;
490
491
492 pxmitframe->attrib.qsel = pxmitframe->attrib.priority;
493 pxmitpriv = &padapter->xmitpriv;
494
495 if (
496 (pxmitframe->frame_tag == DATA_FRAMETAG) &&
497 (pxmitframe->attrib.ether_type != 0x0806) &&
498 (pxmitframe->attrib.ether_type != 0x888e) &&
499 (pxmitframe->attrib.dhcp_pkt != 1)
500 ) {
501 if (padapter->mlmepriv.LinkDetectInfo.bBusyTraffic)
502 rtw_issue_addbareq_cmd(padapter, pxmitframe);
503 }
504
505 spin_lock_bh(lock: &pxmitpriv->lock);
506 err = rtw_xmitframe_enqueue(padapter, pxmitframe);
507 spin_unlock_bh(lock: &pxmitpriv->lock);
508 if (err != _SUCCESS) {
509 rtw_free_xmitframe(pxmitpriv, pxmitframe);
510
511 pxmitpriv->tx_drop++;
512 return true;
513 }
514
515 complete(&pxmitpriv->SdioXmitStart);
516
517 return false;
518}
519
520s32 rtl8723bs_hal_xmitframe_enqueue(
521 struct adapter *padapter, struct xmit_frame *pxmitframe
522)
523{
524 struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
525 s32 err;
526
527 err = rtw_xmitframe_enqueue(padapter, pxmitframe);
528 if (err != _SUCCESS) {
529 rtw_free_xmitframe(pxmitpriv, pxmitframe);
530
531 pxmitpriv->tx_drop++;
532 } else {
533 complete(&pxmitpriv->SdioXmitStart);
534 }
535
536 return err;
537
538}
539
540/*
541 * Return
542 *_SUCCESS start thread ok
543 *_FAIL start thread fail
544 *
545 */
546s32 rtl8723bs_init_xmit_priv(struct adapter *padapter)
547{
548 struct xmit_priv *xmitpriv = &padapter->xmitpriv;
549 struct hal_com_data *phal;
550
551
552 phal = GET_HAL_DATA(padapter);
553
554 spin_lock_init(&phal->SdioTxFIFOFreePageLock);
555 init_completion(x: &xmitpriv->SdioXmitStart);
556 init_completion(x: &xmitpriv->SdioXmitTerminate);
557
558 return _SUCCESS;
559}
560
561void rtl8723bs_free_xmit_priv(struct adapter *padapter)
562{
563 struct xmit_priv *pxmitpriv;
564 struct xmit_buf *pxmitbuf;
565 struct __queue *pqueue;
566 struct list_head *plist, *phead;
567 struct list_head tmplist;
568
569
570 pxmitpriv = &padapter->xmitpriv;
571 pqueue = &pxmitpriv->pending_xmitbuf_queue;
572 phead = get_list_head(queue: pqueue);
573 INIT_LIST_HEAD(list: &tmplist);
574
575 spin_lock_bh(lock: &pqueue->lock);
576 if (!list_empty(head: &pqueue->queue)) {
577 /* Insert tmplist to end of queue, and delete phead */
578 /* then tmplist become head of queue. */
579 list_add_tail(new: &tmplist, head: phead);
580 list_del_init(entry: phead);
581 }
582 spin_unlock_bh(lock: &pqueue->lock);
583
584 phead = &tmplist;
585 while (list_empty(head: phead) == false) {
586 plist = get_next(list: phead);
587 list_del_init(entry: plist);
588
589 pxmitbuf = container_of(plist, struct xmit_buf, list);
590 rtw_free_xmitframe(pxmitpriv, pxmitframe: (struct xmit_frame *)pxmitbuf->priv_data);
591 pxmitbuf->priv_data = NULL;
592 rtw_free_xmitbuf(pxmitpriv, pxmitbuf);
593 }
594}
595

source code of linux/drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c