GNU Linux-libre 4.19.264-gnu1
[releases.git] / drivers / staging / rtl8723bs / hal / rtl8723bs_xmit.c
1 // SPDX-License-Identifier: GPL-2.0
2 /******************************************************************************
3  *
4  * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
5  *
6  ******************************************************************************/
7 #define _RTL8723BS_XMIT_C_
8
9 #include <drv_types.h>
10 #include <rtw_debug.h>
11 #include <rtl8723b_hal.h>
12
13 static u8 rtw_sdio_wait_enough_TxOQT_space(struct adapter *padapter, u8 agg_num)
14 {
15         u32 n = 0;
16         struct hal_com_data *pHalData = GET_HAL_DATA(padapter);
17
18         while (pHalData->SdioTxOQTFreeSpace < agg_num) {
19                 if (
20                         (padapter->bSurpriseRemoved == true) ||
21                         (padapter->bDriverStopped == true)
22                 ) {
23                         DBG_871X("%s: bSurpriseRemoved or bDriverStopped (wait TxOQT)\n", __func__);
24                         return false;
25                 }
26
27                 HalQueryTxOQTBufferStatus8723BSdio(padapter);
28
29                 if ((++n % 60) == 0) {
30                         if ((n % 300) == 0) {
31                                 DBG_871X("%s(%d): QOT free space(%d), agg_num: %d\n",
32                                 __func__, n, pHalData->SdioTxOQTFreeSpace, agg_num);
33                         }
34                         msleep(1);
35                         /* yield(); */
36                 }
37         }
38
39         pHalData->SdioTxOQTFreeSpace -= agg_num;
40
41         /* if (n > 1) */
42         /*      ++priv->pshare->nr_out_of_txoqt_space; */
43
44         return true;
45 }
46
47 static s32 rtl8723_dequeue_writeport(struct adapter *padapter)
48 {
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;
54         s32 ret = 0;
55         u8 PageIdx = 0;
56         u32 deviceId;
57         u8 bUpdatePageNum = false;
58
59         ret = ret || check_fwstate(pmlmepriv, _FW_UNDER_SURVEY);
60
61         if (true == ret)
62                 pxmitbuf = dequeue_pending_xmitbuf_under_survey(pxmitpriv);
63         else
64                 pxmitbuf = dequeue_pending_xmitbuf(pxmitpriv);
65
66         if (pxmitbuf == NULL)
67                 return true;
68
69         deviceId = ffaddr2deviceId(pdvobjpriv, pxmitbuf->ff_hwaddr);
70
71         /*  translate fifo addr to queue index */
72         switch (deviceId) {
73         case WLAN_TX_HIQ_DEVICE_ID:
74                 PageIdx = HI_QUEUE_IDX;
75                 break;
76
77         case WLAN_TX_MIQ_DEVICE_ID:
78                 PageIdx = MID_QUEUE_IDX;
79                 break;
80
81         case WLAN_TX_LOQ_DEVICE_ID:
82                 PageIdx = LOW_QUEUE_IDX;
83                 break;
84         }
85
86 query_free_page:
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;
93                         goto query_free_page;
94                 } else {
95                         bUpdatePageNum = false;
96                         enqueue_pending_xmitbuf_to_head(pxmitpriv, pxmitbuf);
97                         return true;
98                 }
99         }
100
101         if (
102                 (padapter->bSurpriseRemoved == true) ||
103                 (padapter->bDriverStopped == true)
104         ) {
105                 RT_TRACE(
106                         _module_hal_xmit_c_,
107                         _drv_notice_,
108                         ("%s: bSurpriseRemoved(write port)\n", __func__)
109                 );
110                 goto free_xmitbuf;
111         }
112
113         if (rtw_sdio_wait_enough_TxOQT_space(padapter, pxmitbuf->agg_num) == false)
114                 goto free_xmitbuf;
115
116         traffic_check_for_leave_lps(padapter, true, pxmitbuf->agg_num);
117
118         rtw_write_port(padapter, deviceId, pxmitbuf->len, (u8 *)pxmitbuf);
119
120         rtw_hal_sdio_update_tx_freepage(pri_padapter, PageIdx, pxmitbuf->pg_num);
121
122 free_xmitbuf:
123         /* rtw_free_xmitframe(pxmitpriv, pframe); */
124         /* pxmitbuf->priv_data = NULL; */
125         rtw_free_xmitbuf(pxmitpriv, pxmitbuf);
126
127 #ifdef CONFIG_SDIO_TX_TASKLET
128         tasklet_hi_schedule(&pxmitpriv->xmit_tasklet);
129 #endif
130
131         return _FAIL;
132 }
133
134 /*
135  * Description
136  *Transmit xmitbuf to hardware tx fifo
137  *
138  * Return
139  *_SUCCESS      ok
140  *_FAIL         something error
141  */
142 s32 rtl8723bs_xmit_buf_handler(struct adapter *padapter)
143 {
144         struct xmit_priv *pxmitpriv;
145         u8 queue_empty, queue_pending;
146         s32 ret;
147
148
149         pxmitpriv = &padapter->xmitpriv;
150
151         if (down_interruptible(&pxmitpriv->xmit_sema)) {
152                 DBG_871X_LEVEL(_drv_emerg_, "%s: down SdioXmitBufSema fail!\n", __func__);
153                 return _FAIL;
154         }
155
156         ret = (padapter->bDriverStopped == true) || (padapter->bSurpriseRemoved == true);
157         if (ret) {
158                 RT_TRACE(
159                         _module_hal_xmit_c_,
160                         _drv_err_,
161                         (
162                                 "%s: bDriverStopped(%d) bSurpriseRemoved(%d)!\n",
163                                 __func__,
164                                 padapter->bDriverStopped,
165                                 padapter->bSurpriseRemoved
166                         )
167                 );
168                 return _FAIL;
169         }
170
171         queue_pending = check_pending_xmitbuf(pxmitpriv);
172
173         if (queue_pending == false)
174                 return _SUCCESS;
175
176         ret = rtw_register_tx_alive(padapter);
177         if (ret != _SUCCESS) {
178                 return _SUCCESS;
179         }
180
181         do {
182                 queue_empty = rtl8723_dequeue_writeport(padapter);
183 /*      dump secondary adapter xmitbuf */
184         } while (!queue_empty);
185
186         rtw_unregister_tx_alive(padapter);
187
188         return _SUCCESS;
189 }
190
191 /*
192  * Description:
193  *Aggregation packets and send to hardware
194  *
195  * Return:
196  *0     Success
197  *-1    Hardware resource(TX FIFO) not ready
198  *-2    Software resource(xmitbuf) not ready
199  */
200 static s32 xmit_xmitframes(struct adapter *padapter, struct xmit_priv *pxmitpriv)
201 {
202         s32 err, ret;
203         u32 k = 0;
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;
213         int inx[4];
214
215         err = 0;
216         no_res = false;
217         hwxmits = pxmitpriv->hwxmits;
218         hwentry = pxmitpriv->hwxmit_entry;
219         ptxservq = NULL;
220         pxmitframe = NULL;
221         pframe_queue = NULL;
222         pxmitbuf = NULL;
223
224         if (padapter->registrypriv.wifi_spec == 1) {
225                 for (idx = 0; idx < 4; idx++)
226                         inx[idx] = pxmitpriv->wmm_para_seq[idx];
227         } else {
228                 inx[0] = 0;
229                 inx[1] = 1;
230                 inx[2] = 2;
231                 inx[3] = 3;
232         }
233
234         /*  0(VO), 1(VI), 2(BE), 3(BK) */
235         for (idx = 0; idx < hwentry; idx++) {
236                 phwxmit = hwxmits + inx[idx];
237
238                 if (
239                         (check_pending_xmitbuf(pxmitpriv) == true) &&
240                         (padapter->mlmepriv.LinkDetectInfo.bHigherBusyTxTraffic == true)
241                 ) {
242                         if ((phwxmit->accnt > 0) && (phwxmit->accnt < 5)) {
243                                 err = -2;
244                                 break;
245                         }
246                 }
247
248                 max_xmit_len = rtw_hal_get_sdio_tx_max_length(padapter, inx[idx]);
249
250                 spin_lock_bh(&pxmitpriv->lock);
251
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);
259
260 #ifdef DBG_XMIT_BUF
261                         DBG_871X(
262                                 "%s idx:%d hwxmit_pkt_num:%d ptxservq_pkt_num:%d\n",
263                                 __func__,
264                                 idx,
265                                 phwxmit->accnt,
266                                 ptxservq->qcnt
267                         );
268                         DBG_871X(
269                                 "%s free_xmit_extbuf_cnt =%d free_xmitbuf_cnt =%d free_xmitframe_cnt =%d\n",
270                                 __func__,
271                                 pxmitpriv->free_xmit_extbuf_cnt,
272                                 pxmitpriv->free_xmitbuf_cnt,
273                                 pxmitpriv->free_xmitframe_cnt
274                         );
275 #endif
276                         pframe_queue = &ptxservq->sta_pending;
277
278                         frame_phead = get_list_head(pframe_queue);
279
280                         while (list_empty(frame_phead) == false) {
281                                 frame_plist = get_next(frame_phead);
282                                 pxmitframe = LIST_CONTAINOR(frame_plist, struct xmit_frame, list);
283
284                                 /*  check xmit_buf size enough or not */
285                                 txlen = txdesc_size + rtw_wlan_pkt_size(pxmitframe);
286                                 if (
287                                         (NULL == pxmitbuf) ||
288                                         ((_RND(pxmitbuf->len, 8) + txlen) > max_xmit_len) ||
289                                         (k >= (rtw_hal_sdio_max_txoqt_free_space(padapter)-1))
290                                 ) {
291                                         if (pxmitbuf) {
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;
297                                                         pframe->agg_num = k;
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 */
304                                                         /* yield(); */
305                                                 } else
306                                                         rtw_free_xmitbuf(pxmitpriv, pxmitbuf);
307                                         }
308
309                                         pxmitbuf = rtw_alloc_xmitbuf(pxmitpriv);
310                                         if (pxmitbuf == NULL) {
311 #ifdef DBG_XMIT_BUF
312                                                 DBG_871X_LEVEL(_drv_err_, "%s: xmit_buf is not enough!\n", __func__);
313 #endif
314                                                 err = -2;
315                                                 up(&(pxmitpriv->xmit_sema));
316                                                 break;
317                                         }
318                                         k = 0;
319                                 }
320
321                                 /*  ok to send, remove frame from queue */
322                                 if (check_fwstate(&padapter->mlmepriv, WIFI_AP_STATE) == true) {
323                                         if (
324                                                 (pxmitframe->attrib.psta->state & WIFI_SLEEP_STATE) &&
325                                                 (pxmitframe->attrib.triggered == 0)
326                                         ) {
327                                                 DBG_871X(
328                                                         "%s: one not triggered pkt in queue when this STA sleep,"
329                                                         " break and goto next sta\n",
330                                                         __func__
331                                                 );
332                                                 break;
333                                         }
334                                 }
335
336                                 list_del_init(&pxmitframe->list);
337                                 ptxservq->qcnt--;
338                                 phwxmit->accnt--;
339
340                                 if (k == 0) {
341                                         pxmitbuf->ff_hwaddr = rtw_get_ff_hwaddr(pxmitframe);
342                                         pxmitbuf->priv_data = (u8 *)pxmitframe;
343                                 }
344
345                                 /*  coalesce the xmitframe to xmitbuf */
346                                 pxmitframe->pxmitbuf = pxmitbuf;
347                                 pxmitframe->buf_addr = pxmitbuf->ptail;
348
349                                 ret = rtw_xmitframe_coalesce(padapter, pxmitframe->pkt, pxmitframe);
350                                 if (ret == _FAIL) {
351                                         DBG_871X_LEVEL(_drv_err_, "%s: coalesce FAIL!", __func__);
352                                         /*  Todo: error handler */
353                                 } else {
354                                         k++;
355                                         if (k != 1)
356                                                 rtl8723b_update_txdesc(pxmitframe, pxmitframe->buf_addr);
357                                         rtw_count_tx_stats(padapter, pxmitframe, pxmitframe->attrib.last_txcmdsz);
358
359                                         txlen = txdesc_size + pxmitframe->attrib.last_txcmdsz;
360                                         pxmitframe->pg_num = (txlen + 127)/128;
361                                         pxmitbuf->pg_num += (txlen + 127)/128;
362                                     /* if (k != 1) */
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;
366                                 }
367
368                                 if (k != 1)
369                                         rtw_free_xmitframe(pxmitpriv, pxmitframe);
370                                 pxmitframe = NULL;
371                         }
372
373                         if (list_empty(&pframe_queue->queue))
374                                 list_del_init(&ptxservq->tx_pending);
375
376                         if (err)
377                                 break;
378                 }
379                 spin_unlock_bh(&pxmitpriv->lock);
380
381                 /*  dump xmit_buf to hw tx fifo */
382                 if (pxmitbuf) {
383                         RT_TRACE(_module_hal_xmit_c_, _drv_info_, ("pxmitbuf->len =%d enqueue\n", pxmitbuf->len));
384
385                         if (pxmitbuf->len > 0) {
386                                 struct xmit_frame *pframe;
387                                 pframe = (struct xmit_frame *)pxmitbuf->priv_data;
388                                 pframe->agg_num = k;
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);
394                                 yield();
395                         } else
396                                 rtw_free_xmitbuf(pxmitpriv, pxmitbuf);
397                         pxmitbuf = NULL;
398                 }
399
400                 if (err)
401                         break;
402         }
403
404         return err;
405 }
406
407 /*
408  * Description
409  *Transmit xmitframe from queue
410  *
411  * Return
412  *_SUCCESS      ok
413  *_FAIL         something error
414  */
415 static s32 rtl8723bs_xmit_handler(struct adapter *padapter)
416 {
417         struct xmit_priv *pxmitpriv;
418         s32 ret;
419
420
421         pxmitpriv = &padapter->xmitpriv;
422
423         if (down_interruptible(&pxmitpriv->SdioXmitSema)) {
424                 DBG_871X_LEVEL(_drv_emerg_, "%s: down sema fail!\n", __func__);
425                 return _FAIL;
426         }
427
428 next:
429         if (
430                 (padapter->bDriverStopped == true) ||
431                 (padapter->bSurpriseRemoved == true)
432         ) {
433                 RT_TRACE(
434                         _module_hal_xmit_c_,
435                         _drv_notice_,
436                         (
437                                 "%s: bDriverStopped(%d) bSurpriseRemoved(%d)\n",
438                                 __func__,
439                                 padapter->bDriverStopped,
440                                 padapter->bSurpriseRemoved
441                         )
442                 );
443                 return _FAIL;
444         }
445
446         spin_lock_bh(&pxmitpriv->lock);
447         ret = rtw_txframes_pending(padapter);
448         spin_unlock_bh(&pxmitpriv->lock);
449         if (ret == 0) {
450                 return _SUCCESS;
451         }
452
453         /*  dequeue frame and write to hardware */
454
455         ret = xmit_xmitframes(padapter, pxmitpriv);
456         if (ret == -2) {
457                 /* here sleep 1ms will cause big TP loss of TX */
458                 /* from 50+ to 40+ */
459                 if (padapter->registrypriv.wifi_spec)
460                         msleep(1);
461                 else
462                         yield();
463                 goto next;
464         }
465
466         spin_lock_bh(&pxmitpriv->lock);
467         ret = rtw_txframes_pending(padapter);
468         spin_unlock_bh(&pxmitpriv->lock);
469         if (ret == 1) {
470                 goto next;
471         }
472
473         return _SUCCESS;
474 }
475
476 int rtl8723bs_xmit_thread(void *context)
477 {
478         s32 ret;
479         struct adapter *padapter;
480         struct xmit_priv *pxmitpriv;
481         u8 thread_name[20];
482
483         ret = _SUCCESS;
484         padapter = context;
485         pxmitpriv = &padapter->xmitpriv;
486
487         rtw_sprintf(thread_name, 20, "RTWHALXT-" ADPT_FMT, ADPT_ARG(padapter));
488         thread_enter(thread_name);
489
490         DBG_871X("start "FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(padapter));
491
492         /*  For now, no one would down sema to check thread is running, */
493         /*  so mark this temporary, Lucas@20130820 */
494 /*      up(&pxmitpriv->SdioXmitTerminateSema); */
495
496         do {
497                 ret = rtl8723bs_xmit_handler(padapter);
498                 if (signal_pending(current)) {
499                         flush_signals(current);
500                 }
501         } while (_SUCCESS == ret);
502
503         up(&pxmitpriv->SdioXmitTerminateSema);
504
505         RT_TRACE(_module_hal_xmit_c_, _drv_notice_, ("-%s\n", __func__));
506
507         thread_exit();
508 }
509
510 s32 rtl8723bs_mgnt_xmit(
511         struct adapter *padapter, struct xmit_frame *pmgntframe
512 )
513 {
514         s32 ret = _SUCCESS;
515         struct pkt_attrib *pattrib;
516         struct xmit_buf *pxmitbuf;
517         struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
518         struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter);
519         u8 *pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
520         u8 txdesc_size = TXDESC_SIZE;
521
522         RT_TRACE(_module_hal_xmit_c_, _drv_info_, ("+%s\n", __func__));
523
524         pattrib = &pmgntframe->attrib;
525         pxmitbuf = pmgntframe->pxmitbuf;
526
527         rtl8723b_update_txdesc(pmgntframe, pmgntframe->buf_addr);
528
529         pxmitbuf->len = txdesc_size + pattrib->last_txcmdsz;
530         pxmitbuf->pg_num = (pxmitbuf->len + 127)/128; /*  128 is tx page size */
531         pxmitbuf->ptail = pmgntframe->buf_addr + pxmitbuf->len;
532         pxmitbuf->ff_hwaddr = rtw_get_ff_hwaddr(pmgntframe);
533
534         rtw_count_tx_stats(padapter, pmgntframe, pattrib->last_txcmdsz);
535
536         rtw_free_xmitframe(pxmitpriv, pmgntframe);
537
538         pxmitbuf->priv_data = NULL;
539
540         if (GetFrameSubType(pframe) == WIFI_BEACON) { /* dump beacon directly */
541                 ret = rtw_write_port(padapter, pdvobjpriv->Queue2Pipe[pxmitbuf->ff_hwaddr], pxmitbuf->len, (u8 *)pxmitbuf);
542                 if (ret != _SUCCESS)
543                         rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_WRITE_PORT_ERR);
544
545                 rtw_free_xmitbuf(pxmitpriv, pxmitbuf);
546         } else
547                 enqueue_pending_xmitbuf(pxmitpriv, pxmitbuf);
548
549         return ret;
550 }
551
552 /*
553  * Description:
554  *Handle xmitframe(packet) come from rtw_xmit()
555  *
556  * Return:
557  *true  dump packet directly ok
558  *false enqueue, temporary can't transmit packets to hardware
559  */
560 s32 rtl8723bs_hal_xmit(
561         struct adapter *padapter, struct xmit_frame *pxmitframe
562 )
563 {
564         struct xmit_priv *pxmitpriv;
565         s32 err;
566
567
568         pxmitframe->attrib.qsel = pxmitframe->attrib.priority;
569         pxmitpriv = &padapter->xmitpriv;
570
571         if (
572                 (pxmitframe->frame_tag == DATA_FRAMETAG) &&
573                 (pxmitframe->attrib.ether_type != 0x0806) &&
574                 (pxmitframe->attrib.ether_type != 0x888e) &&
575                 (pxmitframe->attrib.dhcp_pkt != 1)
576         ) {
577                 if (padapter->mlmepriv.LinkDetectInfo.bBusyTraffic == true)
578                         rtw_issue_addbareq_cmd(padapter, pxmitframe);
579         }
580
581         spin_lock_bh(&pxmitpriv->lock);
582         err = rtw_xmitframe_enqueue(padapter, pxmitframe);
583         spin_unlock_bh(&pxmitpriv->lock);
584         if (err != _SUCCESS) {
585                 RT_TRACE(_module_hal_xmit_c_, _drv_err_, ("rtl8723bs_hal_xmit: enqueue xmitframe fail\n"));
586                 rtw_free_xmitframe(pxmitpriv, pxmitframe);
587
588                 pxmitpriv->tx_drop++;
589                 return true;
590         }
591
592         up(&pxmitpriv->SdioXmitSema);
593
594         return false;
595 }
596
597 s32     rtl8723bs_hal_xmitframe_enqueue(
598         struct adapter *padapter, struct xmit_frame *pxmitframe
599 )
600 {
601         struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
602         s32 err;
603
604         err = rtw_xmitframe_enqueue(padapter, pxmitframe);
605         if (err != _SUCCESS) {
606                 rtw_free_xmitframe(pxmitpriv, pxmitframe);
607
608                 pxmitpriv->tx_drop++;
609         } else {
610 #ifdef CONFIG_SDIO_TX_TASKLET
611                 tasklet_hi_schedule(&pxmitpriv->xmit_tasklet);
612 #else
613                 up(&pxmitpriv->SdioXmitSema);
614 #endif
615         }
616
617         return err;
618
619 }
620
621 /*
622  * Return
623  *_SUCCESS      start thread ok
624  *_FAIL         start thread fail
625  *
626  */
627 s32 rtl8723bs_init_xmit_priv(struct adapter *padapter)
628 {
629         struct xmit_priv *xmitpriv = &padapter->xmitpriv;
630         struct hal_com_data *phal;
631
632
633         phal = GET_HAL_DATA(padapter);
634
635         spin_lock_init(&phal->SdioTxFIFOFreePageLock);
636         sema_init(&xmitpriv->SdioXmitSema, 0);
637         sema_init(&xmitpriv->SdioXmitTerminateSema, 0);
638
639         return _SUCCESS;
640 }
641
642 void rtl8723bs_free_xmit_priv(struct adapter *padapter)
643 {
644         struct hal_com_data *phal;
645         struct xmit_priv *pxmitpriv;
646         struct xmit_buf *pxmitbuf;
647         struct __queue *pqueue;
648         struct list_head *plist, *phead;
649         struct list_head tmplist;
650
651
652         phal = GET_HAL_DATA(padapter);
653         pxmitpriv = &padapter->xmitpriv;
654         pqueue = &pxmitpriv->pending_xmitbuf_queue;
655         phead = get_list_head(pqueue);
656         INIT_LIST_HEAD(&tmplist);
657
658         spin_lock_bh(&pqueue->lock);
659         if (!list_empty(&pqueue->queue)) {
660                 /*  Insert tmplist to end of queue, and delete phead */
661                 /*  then tmplist become head of queue. */
662                 list_add_tail(&tmplist, phead);
663                 list_del_init(phead);
664         }
665         spin_unlock_bh(&pqueue->lock);
666
667         phead = &tmplist;
668         while (list_empty(phead) == false) {
669                 plist = get_next(phead);
670                 list_del_init(plist);
671
672                 pxmitbuf = LIST_CONTAINOR(plist, struct xmit_buf, list);
673                 rtw_free_xmitframe(pxmitpriv, (struct xmit_frame *)pxmitbuf->priv_data);
674                 pxmitbuf->priv_data = NULL;
675                 rtw_free_xmitbuf(pxmitpriv, pxmitbuf);
676         }
677 }