Merge tag 'docs-5.6-fixes' of git://git.lwn.net/linux
[linux-2.6-microblaze.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) ||
21                         (padapter->bDriverStopped)
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 (ret)
62                 pxmitbuf = dequeue_pending_xmitbuf_under_survey(pxmitpriv);
63         else
64                 pxmitbuf = dequeue_pending_xmitbuf(pxmitpriv);
65
66         if (!pxmitbuf)
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 (!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) ||
103                 (padapter->bDriverStopped)
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 (wait_for_completion_interruptible(&pxmitpriv->xmit_comp)) {
152                 DBG_871X_LEVEL(_drv_emerg_, "%s: down SdioXmitBufSema fail!\n", __func__);
153                 return _FAIL;
154         }
155
156         ret = (padapter->bDriverStopped) || (padapter->bSurpriseRemoved);
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)
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 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         hwxmits = pxmitpriv->hwxmits;
217         hwentry = pxmitpriv->hwxmit_entry;
218         ptxservq = NULL;
219         pxmitframe = NULL;
220         pframe_queue = NULL;
221         pxmitbuf = NULL;
222
223         if (padapter->registrypriv.wifi_spec == 1) {
224                 for (idx = 0; idx < 4; idx++)
225                         inx[idx] = pxmitpriv->wmm_para_seq[idx];
226         } else {
227                 inx[0] = 0;
228                 inx[1] = 1;
229                 inx[2] = 2;
230                 inx[3] = 3;
231         }
232
233         /*  0(VO), 1(VI), 2(BE), 3(BK) */
234         for (idx = 0; idx < hwentry; idx++) {
235                 phwxmit = hwxmits + inx[idx];
236
237                 if (
238                         (check_pending_xmitbuf(pxmitpriv)) &&
239                         (padapter->mlmepriv.LinkDetectInfo.bHigherBusyTxTraffic)
240                 ) {
241                         if ((phwxmit->accnt > 0) && (phwxmit->accnt < 5)) {
242                                 err = -2;
243                                 break;
244                         }
245                 }
246
247                 max_xmit_len = rtw_hal_get_sdio_tx_max_length(padapter, inx[idx]);
248
249                 spin_lock_bh(&pxmitpriv->lock);
250
251                 sta_phead = get_list_head(phwxmit->sta_queue);
252                 sta_plist = get_next(sta_phead);
253                 /* because stop_sta_xmit may delete sta_plist at any time */
254                 /* so we should add lock here, or while loop can not exit */
255                 while (sta_phead != sta_plist) {
256                         ptxservq = LIST_CONTAINOR(sta_plist, struct tx_servq, tx_pending);
257                         sta_plist = get_next(sta_plist);
258
259 #ifdef DBG_XMIT_BUF
260                         DBG_871X(
261                                 "%s idx:%d hwxmit_pkt_num:%d ptxservq_pkt_num:%d\n",
262                                 __func__,
263                                 idx,
264                                 phwxmit->accnt,
265                                 ptxservq->qcnt
266                         );
267                         DBG_871X(
268                                 "%s free_xmit_extbuf_cnt =%d free_xmitbuf_cnt =%d free_xmitframe_cnt =%d\n",
269                                 __func__,
270                                 pxmitpriv->free_xmit_extbuf_cnt,
271                                 pxmitpriv->free_xmitbuf_cnt,
272                                 pxmitpriv->free_xmitframe_cnt
273                         );
274 #endif
275                         pframe_queue = &ptxservq->sta_pending;
276
277                         frame_phead = get_list_head(pframe_queue);
278
279                         while (list_empty(frame_phead) == false) {
280                                 frame_plist = get_next(frame_phead);
281                                 pxmitframe = LIST_CONTAINOR(frame_plist, struct xmit_frame, list);
282
283                                 /*  check xmit_buf size enough or not */
284                                 txlen = txdesc_size + rtw_wlan_pkt_size(pxmitframe);
285                                 if(     !pxmitbuf ||
286                                         ((_RND(pxmitbuf->len, 8) + txlen) > max_xmit_len) ||
287                                         (k >= (rtw_hal_sdio_max_txoqt_free_space(padapter) - 1))
288                                 ) {
289                                         if (pxmitbuf) {
290                                                 /* pxmitbuf->priv_data will be NULL, and will crash here */
291                                                 if (pxmitbuf->len > 0 &&
292                                                     pxmitbuf->priv_data) {
293                                                         struct xmit_frame *pframe;
294                                                         pframe = (struct xmit_frame *)pxmitbuf->priv_data;
295                                                         pframe->agg_num = k;
296                                                         pxmitbuf->agg_num = k;
297                                                         rtl8723b_update_txdesc(pframe, pframe->buf_addr);
298                                                         rtw_free_xmitframe(pxmitpriv, pframe);
299                                                         pxmitbuf->priv_data = NULL;
300                                                         enqueue_pending_xmitbuf(pxmitpriv, pxmitbuf);
301                                                         /* can not yield under lock */
302                                                         /* yield(); */
303                                                 } else
304                                                         rtw_free_xmitbuf(pxmitpriv, pxmitbuf);
305                                         }
306
307                                         pxmitbuf = rtw_alloc_xmitbuf(pxmitpriv);
308                                         if (!pxmitbuf) {
309 #ifdef DBG_XMIT_BUF
310                                                 DBG_871X_LEVEL(_drv_err_, "%s: xmit_buf is not enough!\n", __func__);
311 #endif
312                                                 err = -2;
313                                                 complete(&(pxmitpriv->xmit_comp));
314                                                 break;
315                                         }
316                                         k = 0;
317                                 }
318
319                                 /*  ok to send, remove frame from queue */
320                                 if (check_fwstate(&padapter->mlmepriv, WIFI_AP_STATE) == true) {
321                                         if (
322                                                 (pxmitframe->attrib.psta->state & WIFI_SLEEP_STATE) &&
323                                                 (pxmitframe->attrib.triggered == 0)
324                                         ) {
325                                                 DBG_871X(
326                                                         "%s: one not triggered pkt in queue when this STA sleep,"
327                                                         " break and goto next sta\n",
328                                                         __func__
329                                                 );
330                                                 break;
331                                         }
332                                 }
333
334                                 list_del_init(&pxmitframe->list);
335                                 ptxservq->qcnt--;
336                                 phwxmit->accnt--;
337
338                                 if (k == 0) {
339                                         pxmitbuf->ff_hwaddr = rtw_get_ff_hwaddr(pxmitframe);
340                                         pxmitbuf->priv_data = (u8 *)pxmitframe;
341                                 }
342
343                                 /*  coalesce the xmitframe to xmitbuf */
344                                 pxmitframe->pxmitbuf = pxmitbuf;
345                                 pxmitframe->buf_addr = pxmitbuf->ptail;
346
347                                 ret = rtw_xmitframe_coalesce(padapter, pxmitframe->pkt, pxmitframe);
348                                 if (ret == _FAIL) {
349                                         DBG_871X_LEVEL(_drv_err_, "%s: coalesce FAIL!", __func__);
350                                         /*  Todo: error handler */
351                                 } else {
352                                         k++;
353                                         if (k != 1)
354                                                 rtl8723b_update_txdesc(pxmitframe, pxmitframe->buf_addr);
355                                         rtw_count_tx_stats(padapter, pxmitframe, pxmitframe->attrib.last_txcmdsz);
356
357                                         txlen = txdesc_size + pxmitframe->attrib.last_txcmdsz;
358                                         pxmitframe->pg_num = (txlen + 127) / 128;
359                                         pxmitbuf->pg_num += (txlen + 127) / 128;
360                                     /* if (k != 1) */
361                                         /*      ((struct xmit_frame*)pxmitbuf->priv_data)->pg_num += pxmitframe->pg_num; */
362                                         pxmitbuf->ptail += _RND(txlen, 8); /*  round to 8 bytes alignment */
363                                         pxmitbuf->len = _RND(pxmitbuf->len, 8) + txlen;
364                                 }
365
366                                 if (k != 1)
367                                         rtw_free_xmitframe(pxmitpriv, pxmitframe);
368                                 pxmitframe = NULL;
369                         }
370
371                         if (list_empty(&pframe_queue->queue))
372                                 list_del_init(&ptxservq->tx_pending);
373
374                         if (err)
375                                 break;
376                 }
377                 spin_unlock_bh(&pxmitpriv->lock);
378
379                 /*  dump xmit_buf to hw tx fifo */
380                 if (pxmitbuf) {
381                         RT_TRACE(_module_hal_xmit_c_, _drv_info_, ("pxmitbuf->len =%d enqueue\n", pxmitbuf->len));
382
383                         if (pxmitbuf->len > 0) {
384                                 struct xmit_frame *pframe;
385                                 pframe = (struct xmit_frame *)pxmitbuf->priv_data;
386                                 pframe->agg_num = k;
387                                 pxmitbuf->agg_num = k;
388                                 rtl8723b_update_txdesc(pframe, pframe->buf_addr);
389                                 rtw_free_xmitframe(pxmitpriv, pframe);
390                                 pxmitbuf->priv_data = NULL;
391                                 enqueue_pending_xmitbuf(pxmitpriv, pxmitbuf);
392                                 yield();
393                         } else
394                                 rtw_free_xmitbuf(pxmitpriv, pxmitbuf);
395                         pxmitbuf = NULL;
396                 }
397
398                 if (err)
399                         break;
400         }
401
402         return err;
403 }
404
405 /*
406  * Description
407  *Transmit xmitframe from queue
408  *
409  * Return
410  *_SUCCESS      ok
411  *_FAIL         something error
412  */
413 static s32 rtl8723bs_xmit_handler(struct adapter *padapter)
414 {
415         struct xmit_priv *pxmitpriv;
416         s32 ret;
417
418
419         pxmitpriv = &padapter->xmitpriv;
420
421         if (wait_for_completion_interruptible(&pxmitpriv->SdioXmitStart)) {
422                 DBG_871X_LEVEL(_drv_emerg_, "%s: SdioXmitStart fail!\n", __func__);
423                 return _FAIL;
424         }
425
426 next:
427         if (
428                 (padapter->bDriverStopped) ||
429                 (padapter->bSurpriseRemoved)
430         ) {
431                 RT_TRACE(
432                         _module_hal_xmit_c_,
433                         _drv_notice_,
434                         (
435                                 "%s: bDriverStopped(%d) bSurpriseRemoved(%d)\n",
436                                 __func__,
437                                 padapter->bDriverStopped,
438                                 padapter->bSurpriseRemoved
439                         )
440                 );
441                 return _FAIL;
442         }
443
444         spin_lock_bh(&pxmitpriv->lock);
445         ret = rtw_txframes_pending(padapter);
446         spin_unlock_bh(&pxmitpriv->lock);
447         if (ret == 0) {
448                 return _SUCCESS;
449         }
450
451         /*  dequeue frame and write to hardware */
452
453         ret = xmit_xmitframes(padapter, pxmitpriv);
454         if (ret == -2) {
455                 /* here sleep 1ms will cause big TP loss of TX */
456                 /* from 50+ to 40+ */
457                 if (padapter->registrypriv.wifi_spec)
458                         msleep(1);
459                 else
460                         yield();
461                 goto next;
462         }
463
464         spin_lock_bh(&pxmitpriv->lock);
465         ret = rtw_txframes_pending(padapter);
466         spin_unlock_bh(&pxmitpriv->lock);
467         if (ret == 1) {
468                 goto next;
469         }
470
471         return _SUCCESS;
472 }
473
474 int rtl8723bs_xmit_thread(void *context)
475 {
476         s32 ret;
477         struct adapter *padapter;
478         struct xmit_priv *pxmitpriv;
479         u8 thread_name[20];
480
481         ret = _SUCCESS;
482         padapter = context;
483         pxmitpriv = &padapter->xmitpriv;
484
485         rtw_sprintf(thread_name, 20, "RTWHALXT-" ADPT_FMT, ADPT_ARG(padapter));
486         thread_enter(thread_name);
487
488         DBG_871X("start "FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(padapter));
489
490         do {
491                 ret = rtl8723bs_xmit_handler(padapter);
492                 if (signal_pending(current)) {
493                         flush_signals(current);
494                 }
495         } while (_SUCCESS == ret);
496
497         complete(&pxmitpriv->SdioXmitTerminate);
498
499         RT_TRACE(_module_hal_xmit_c_, _drv_notice_, ("-%s\n", __func__));
500
501         thread_exit();
502 }
503
504 s32 rtl8723bs_mgnt_xmit(
505         struct adapter *padapter, struct xmit_frame *pmgntframe
506 )
507 {
508         s32 ret = _SUCCESS;
509         struct pkt_attrib *pattrib;
510         struct xmit_buf *pxmitbuf;
511         struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
512         struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter);
513         u8 *pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
514         u8 txdesc_size = TXDESC_SIZE;
515
516         RT_TRACE(_module_hal_xmit_c_, _drv_info_, ("+%s\n", __func__));
517
518         pattrib = &pmgntframe->attrib;
519         pxmitbuf = pmgntframe->pxmitbuf;
520
521         rtl8723b_update_txdesc(pmgntframe, pmgntframe->buf_addr);
522
523         pxmitbuf->len = txdesc_size + pattrib->last_txcmdsz;
524         pxmitbuf->pg_num = (pxmitbuf->len + 127) / 128; /*  128 is tx page size */
525         pxmitbuf->ptail = pmgntframe->buf_addr + pxmitbuf->len;
526         pxmitbuf->ff_hwaddr = rtw_get_ff_hwaddr(pmgntframe);
527
528         rtw_count_tx_stats(padapter, pmgntframe, pattrib->last_txcmdsz);
529
530         rtw_free_xmitframe(pxmitpriv, pmgntframe);
531
532         pxmitbuf->priv_data = NULL;
533
534         if (GetFrameSubType(pframe) == WIFI_BEACON) { /* dump beacon directly */
535                 ret = rtw_write_port(padapter, pdvobjpriv->Queue2Pipe[pxmitbuf->ff_hwaddr], pxmitbuf->len, (u8 *)pxmitbuf);
536                 if (ret != _SUCCESS)
537                         rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_WRITE_PORT_ERR);
538
539                 rtw_free_xmitbuf(pxmitpriv, pxmitbuf);
540         } else
541                 enqueue_pending_xmitbuf(pxmitpriv, pxmitbuf);
542
543         return ret;
544 }
545
546 /*
547  * Description:
548  *Handle xmitframe(packet) come from rtw_xmit()
549  *
550  * Return:
551  *true  dump packet directly ok
552  *false enqueue, temporary can't transmit packets to hardware
553  */
554 s32 rtl8723bs_hal_xmit(
555         struct adapter *padapter, struct xmit_frame *pxmitframe
556 )
557 {
558         struct xmit_priv *pxmitpriv;
559         s32 err;
560
561
562         pxmitframe->attrib.qsel = pxmitframe->attrib.priority;
563         pxmitpriv = &padapter->xmitpriv;
564
565         if (
566                 (pxmitframe->frame_tag == DATA_FRAMETAG) &&
567                 (pxmitframe->attrib.ether_type != 0x0806) &&
568                 (pxmitframe->attrib.ether_type != 0x888e) &&
569                 (pxmitframe->attrib.dhcp_pkt != 1)
570         ) {
571                 if (padapter->mlmepriv.LinkDetectInfo.bBusyTraffic)
572                         rtw_issue_addbareq_cmd(padapter, pxmitframe);
573         }
574
575         spin_lock_bh(&pxmitpriv->lock);
576         err = rtw_xmitframe_enqueue(padapter, pxmitframe);
577         spin_unlock_bh(&pxmitpriv->lock);
578         if (err != _SUCCESS) {
579                 RT_TRACE(_module_hal_xmit_c_, _drv_err_, ("rtl8723bs_hal_xmit: enqueue xmitframe fail\n"));
580                 rtw_free_xmitframe(pxmitpriv, pxmitframe);
581
582                 pxmitpriv->tx_drop++;
583                 return true;
584         }
585
586         complete(&pxmitpriv->SdioXmitStart);
587
588         return false;
589 }
590
591 s32     rtl8723bs_hal_xmitframe_enqueue(
592         struct adapter *padapter, struct xmit_frame *pxmitframe
593 )
594 {
595         struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
596         s32 err;
597
598         err = rtw_xmitframe_enqueue(padapter, pxmitframe);
599         if (err != _SUCCESS) {
600                 rtw_free_xmitframe(pxmitpriv, pxmitframe);
601
602                 pxmitpriv->tx_drop++;
603         } else {
604 #ifdef CONFIG_SDIO_TX_TASKLET
605                 tasklet_hi_schedule(&pxmitpriv->xmit_tasklet);
606 #else
607                 complete(&pxmitpriv->SdioXmitStart);
608 #endif
609         }
610
611         return err;
612
613 }
614
615 /*
616  * Return
617  *_SUCCESS      start thread ok
618  *_FAIL         start thread fail
619  *
620  */
621 s32 rtl8723bs_init_xmit_priv(struct adapter *padapter)
622 {
623         struct xmit_priv *xmitpriv = &padapter->xmitpriv;
624         struct hal_com_data *phal;
625
626
627         phal = GET_HAL_DATA(padapter);
628
629         spin_lock_init(&phal->SdioTxFIFOFreePageLock);
630         init_completion(&xmitpriv->SdioXmitStart);
631         init_completion(&xmitpriv->SdioXmitTerminate);
632
633         return _SUCCESS;
634 }
635
636 void rtl8723bs_free_xmit_priv(struct adapter *padapter)
637 {
638         struct xmit_priv *pxmitpriv;
639         struct xmit_buf *pxmitbuf;
640         struct __queue *pqueue;
641         struct list_head *plist, *phead;
642         struct list_head tmplist;
643
644
645         pxmitpriv = &padapter->xmitpriv;
646         pqueue = &pxmitpriv->pending_xmitbuf_queue;
647         phead = get_list_head(pqueue);
648         INIT_LIST_HEAD(&tmplist);
649
650         spin_lock_bh(&pqueue->lock);
651         if (!list_empty(&pqueue->queue)) {
652                 /*  Insert tmplist to end of queue, and delete phead */
653                 /*  then tmplist become head of queue. */
654                 list_add_tail(&tmplist, phead);
655                 list_del_init(phead);
656         }
657         spin_unlock_bh(&pqueue->lock);
658
659         phead = &tmplist;
660         while (list_empty(phead) == false) {
661                 plist = get_next(phead);
662                 list_del_init(plist);
663
664                 pxmitbuf = LIST_CONTAINOR(plist, struct xmit_buf, list);
665                 rtw_free_xmitframe(pxmitpriv, (struct xmit_frame *)pxmitbuf->priv_data);
666                 pxmitbuf->priv_data = NULL;
667                 rtw_free_xmitbuf(pxmitpriv, pxmitbuf);
668         }
669 }