5ba84eaa31ab5f8326d8f4d529cd33741a2b4ccc
[firefly-linux-kernel-4.4.55.git] / drivers / net / wireless / rockchip_wlan / rtl8723bs / hal / rtl8723b / sdio / rtl8723bs_xmit.c
1 /******************************************************************************
2  *
3  * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
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  * You should have received a copy of the GNU General Public License along with
15  * this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
17  *
18  *
19  ******************************************************************************/
20 #define _RTL8723BS_XMIT_C_
21
22 #include <rtl8723b_hal.h>
23
24 static u8 rtw_sdio_wait_enough_TxOQT_space(PADAPTER padapter, u8 agg_num)
25 {
26         u32 n = 0;
27         HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter);
28
29         while (pHalData->SdioTxOQTFreeSpace < agg_num) 
30         {
31                 if ((padapter->bSurpriseRemoved == _TRUE) 
32                         || (padapter->bDriverStopped == _TRUE)
33 #ifdef CONFIG_CONCURRENT_MODE
34                         ||((padapter->pbuddy_adapter) 
35                 && ((padapter->pbuddy_adapter->bSurpriseRemoved) ||(padapter->pbuddy_adapter->bDriverStopped)))
36 #endif          
37                 ){
38                         DBG_871X("%s: bSurpriseRemoved or bDriverStopped (wait TxOQT)\n", __func__);
39                         return _FALSE;
40                 }
41
42                 HalQueryTxOQTBufferStatus8723BSdio(padapter);
43                 
44                 if ((++n % 60) == 0) {
45                         if ((n % 300) == 0) {                   
46                                 DBG_871X("%s(%d): QOT free space(%d), agg_num: %d\n",
47                                 __func__, n, pHalData->SdioTxOQTFreeSpace, agg_num);
48                         }       
49                         rtw_msleep_os(1);
50                         //yield();
51                 }
52         }
53
54         pHalData->SdioTxOQTFreeSpace -= agg_num;
55         
56         //if (n > 1)
57         //      ++priv->pshare->nr_out_of_txoqt_space;
58
59         return _TRUE;
60 }
61
62 static s32 rtl8723_dequeue_writeport(PADAPTER padapter)
63 {
64         struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
65         struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
66         struct dvobj_priv       *pdvobjpriv = adapter_to_dvobj(padapter);
67         struct xmit_buf *pxmitbuf;
68         PADAPTER pri_padapter = padapter;
69         s32 ret = 0;
70         u8      PageIdx = 0;
71         u32     deviceId;
72 #ifdef CONFIG_SDIO_TX_ENABLE_AVAL_INT
73         u8      bUpdatePageNum = _FALSE;
74 #else
75         u32     polling_num = 0;
76 #endif
77
78
79 #ifdef CONFIG_CONCURRENT_MODE
80         if (padapter->adapter_type > 0)
81                 pri_padapter = padapter->pbuddy_adapter;
82
83         if (rtw_buddy_adapter_up(padapter))
84                 ret = check_buddy_fwstate(padapter, _FW_UNDER_SURVEY);
85 #endif
86
87         ret = ret || check_fwstate(pmlmepriv, _FW_UNDER_SURVEY);
88
89         if (_TRUE == ret)
90                 pxmitbuf = dequeue_pending_xmitbuf_under_survey(pxmitpriv);
91         else
92                 pxmitbuf = dequeue_pending_xmitbuf(pxmitpriv);
93
94         if (pxmitbuf == NULL)
95                 return _TRUE;
96
97         deviceId = ffaddr2deviceId(pdvobjpriv, pxmitbuf->ff_hwaddr);
98
99         // translate fifo addr to queue index
100         switch (deviceId) {
101                 case WLAN_TX_HIQ_DEVICE_ID:
102                                 PageIdx = HI_QUEUE_IDX;
103                                 break;
104
105                 case WLAN_TX_MIQ_DEVICE_ID:
106                                 PageIdx = MID_QUEUE_IDX;
107                                 break;
108
109                 case WLAN_TX_LOQ_DEVICE_ID:
110                                 PageIdx = LOW_QUEUE_IDX;
111                                 break;
112         }
113
114 query_free_page:
115         // check if hardware tx fifo page is enough
116         if( _FALSE == rtw_hal_sdio_query_tx_freepage(pri_padapter, PageIdx, pxmitbuf->pg_num))
117         {
118 #ifdef CONFIG_SDIO_TX_ENABLE_AVAL_INT
119                 if (!bUpdatePageNum) {
120                         // Total number of page is NOT available, so update current FIFO status
121                         HalQueryTxBufferStatus8723BSdio(padapter);
122                         bUpdatePageNum = _TRUE;
123                         goto query_free_page;
124                 } else {
125                         bUpdatePageNum = _FALSE;
126                         enqueue_pending_xmitbuf_to_head(pxmitpriv, pxmitbuf);
127                         return _TRUE;
128                 }
129 #else //CONFIG_SDIO_TX_ENABLE_AVAL_INT
130                 polling_num++;
131                 if ((polling_num % 0x7F) == 0) {//or 80
132                         //DBG_871X("%s: FIFO starvation!(%d) len=%d agg=%d page=(R)%d(A)%d\n",
133                         //      __func__, polling_num, pxmitbuf->len, pxmitbuf->agg_num, pframe->pg_num, freePage[PageIdx] + freePage[PUBLIC_QUEUE_IDX]);
134                         rtw_msleep_os(1);
135                 }
136
137                 // Total number of page is NOT available, so update current FIFO status
138                 HalQueryTxBufferStatus8723BSdio(padapter);
139                 goto query_free_page;
140 #endif //CONFIG_SDIO_TX_ENABLE_AVAL_INT
141         }
142
143         if ((padapter->bSurpriseRemoved == _TRUE) 
144                 || (padapter->bDriverStopped == _TRUE)
145 #ifdef CONFIG_CONCURRENT_MODE
146                 ||((padapter->pbuddy_adapter) 
147                 && ((padapter->pbuddy_adapter->bSurpriseRemoved) ||(padapter->pbuddy_adapter->bDriverStopped)))
148 #endif
149         ){
150                 RT_TRACE(_module_hal_xmit_c_, _drv_notice_,
151                          ("%s: bSurpriseRemoved(wirte port)\n", __FUNCTION__));
152                 goto free_xmitbuf;
153         }
154
155         if (rtw_sdio_wait_enough_TxOQT_space(padapter, pxmitbuf->agg_num) == _FALSE) 
156         {
157                 goto free_xmitbuf;
158         }
159
160 #ifdef CONFIG_CHECK_LEAVE_LPS
161         traffic_check_for_leave_lps(padapter, _TRUE, pxmitbuf->agg_num);
162 #endif 
163
164         rtw_write_port(padapter, deviceId, pxmitbuf->len, (u8 *)pxmitbuf);
165
166         rtw_hal_sdio_update_tx_freepage(pri_padapter, PageIdx, pxmitbuf->pg_num);
167
168 free_xmitbuf:
169         //rtw_free_xmitframe(pxmitpriv, pframe);
170         //pxmitbuf->priv_data = NULL;
171         rtw_free_xmitbuf(pxmitpriv, pxmitbuf);
172
173 #if 0 // improve TX/RX throughput balance
174 {
175         PSDIO_DATA psdio;
176         struct sdio_func *func;
177         static u8 i = 0;
178         u32 sdio_hisr;
179         u8 j;
180
181         psdio = &adapter_to_dvobj(padapter)->intf_data;
182         func = psdio->func;
183
184         if (i == 2)
185         {
186                 j = 0;
187                 while (j < 10)
188                 {
189                         sdio_hisr = SdioLocalCmd52Read1Byte(padapter, SDIO_REG_HISR);
190                         sdio_hisr &= GET_HAL_DATA(padapter)->sdio_himr;
191                         if (sdio_hisr & SDIO_HISR_RX_REQUEST)
192                         {
193                                 sdio_claim_host(func);
194                                 sd_int_hdl(pri_padapter);
195                                 sdio_release_host(func);
196                         }
197                         else
198                         {
199                                 break;
200                         }
201                         j++;
202                 }
203                 i = 0;
204         }
205         else
206         {
207                 i++;
208         }
209 }
210 #endif
211
212 #ifdef CONFIG_SDIO_TX_TASKLET
213         tasklet_hi_schedule(&pxmitpriv->xmit_tasklet);
214 #endif
215
216         return _FAIL;
217 }
218
219 /*
220  * Description
221  *      Transmit xmitbuf to hardware tx fifo
222  *
223  * Return
224  *      _SUCCESS        ok
225  *      _FAIL           something error
226  */
227 s32 rtl8723bs_xmit_buf_handler(PADAPTER padapter)
228 {
229         struct xmit_priv *pxmitpriv;
230         u8      queue_empty, queue_pending;
231         s32     ret;
232
233
234         pxmitpriv = &padapter->xmitpriv;
235
236         ret = _rtw_down_sema(&pxmitpriv->xmit_sema);
237         if (_FAIL == ret) {
238                 DBG_871X_LEVEL(_drv_emerg_, "%s: down SdioXmitBufSema fail!\n", __FUNCTION__);
239                 return _FAIL;
240         }
241
242         ret = (padapter->bDriverStopped == _TRUE) || (padapter->bSurpriseRemoved == _TRUE);
243         if (ret) {
244                 RT_TRACE(_module_hal_xmit_c_, _drv_err_,
245                                  ("%s: bDriverStopped(%d) bSurpriseRemoved(%d)!\n",
246                                   __FUNCTION__, padapter->bDriverStopped, padapter->bSurpriseRemoved));
247                 return _FAIL;
248         }
249
250         queue_pending = check_pending_xmitbuf(pxmitpriv);
251
252 #ifdef CONFIG_CONCURRENT_MODE
253         if(rtw_buddy_adapter_up(padapter))
254                 queue_pending |= check_pending_xmitbuf(&padapter->pbuddy_adapter->xmitpriv);
255 #endif
256
257         if(queue_pending == _FALSE)
258                 return _SUCCESS;
259
260 #ifdef CONFIG_LPS_LCLK
261         ret = rtw_register_tx_alive(padapter);
262         if (ret != _SUCCESS) {
263                 return _SUCCESS;
264         }
265 #endif
266
267         do {
268                 queue_empty = rtl8723_dequeue_writeport(padapter);
269 //      dump secondary adapter xmitbuf
270 #ifdef CONFIG_CONCURRENT_MODE
271                 if(rtw_buddy_adapter_up(padapter))
272                         queue_empty &= rtl8723_dequeue_writeport(padapter->pbuddy_adapter);
273 #endif
274         } while ( !queue_empty);
275
276 #ifdef CONFIG_LPS_LCLK
277         rtw_unregister_tx_alive(padapter);
278 #endif
279
280         return _SUCCESS;
281 }
282
283 /*
284  * Description:
285  *      Aggregation packets and send to hardware
286  *
287  * Return:
288  *      0       Success
289  *      -1      Hardware resource(TX FIFO) not ready
290  *      -2      Software resource(xmitbuf) not ready
291  */
292 static s32 xmit_xmitframes(PADAPTER padapter, struct xmit_priv *pxmitpriv)
293 {
294         s32 err, ret;
295         u32 k=0;
296         struct hw_xmit *hwxmits, *phwxmit;
297         u8 no_res, idx, hwentry;
298         _irqL irql;
299         struct tx_servq *ptxservq;
300         _list *sta_plist, *sta_phead, *frame_plist, *frame_phead;
301         struct xmit_frame *pxmitframe;
302         _queue *pframe_queue;
303         struct xmit_buf *pxmitbuf;
304         u32 txlen, max_xmit_len;
305         u8 txdesc_size = TXDESC_SIZE;
306         int inx[4];
307         u8 pre_qsel=0xFF,next_qsel=0xFF;
308         err = 0;
309         no_res = _FALSE;
310         hwxmits = pxmitpriv->hwxmits;
311         hwentry = pxmitpriv->hwxmit_entry;
312         ptxservq = NULL;
313         pxmitframe = NULL;
314         pframe_queue = NULL;
315         pxmitbuf = NULL;
316
317         if (padapter->registrypriv.wifi_spec == 1) {
318                 for(idx=0; idx<4; idx++)
319                         inx[idx] = pxmitpriv->wmm_para_seq[idx];
320         } else {
321                 inx[0] = 0; inx[1] = 1; inx[2] = 2; inx[3] = 3;
322         }
323
324         // 0(VO), 1(VI), 2(BE), 3(BK)
325         for (idx = 0; idx < hwentry; idx++)
326         {
327                 phwxmit = hwxmits + inx[idx];
328         
329                 if((check_pending_xmitbuf(pxmitpriv) == _TRUE) && (padapter->mlmepriv.LinkDetectInfo.bHigherBusyTxTraffic == _TRUE)) {
330                         if ((phwxmit->accnt > 0) && (phwxmit->accnt < 5)) {
331                                 err = -2;
332                                 break;
333                         }
334                 }
335
336                 max_xmit_len = rtw_hal_get_sdio_tx_max_length(padapter, inx[idx]);
337
338                 _enter_critical_bh(&pxmitpriv->lock, &irql);
339                 
340                 sta_phead = get_list_head(phwxmit->sta_queue);
341                 sta_plist = get_next(sta_phead);
342                 //because stop_sta_xmit may delete sta_plist at any time
343                 //so we should add lock here, or while loop can not exit
344                 while (rtw_end_of_queue_search(sta_phead, sta_plist) == _FALSE)
345                 {
346                         ptxservq = LIST_CONTAINOR(sta_plist, struct tx_servq, tx_pending);
347                         sta_plist = get_next(sta_plist);
348
349 #ifdef DBG_XMIT_BUF
350                         DBG_871X("%s idx:%d hwxmit_pkt_num:%d ptxservq_pkt_num:%d\n", __func__, idx, phwxmit->accnt, ptxservq->qcnt);
351                         DBG_871X("%s free_xmit_extbuf_cnt=%d free_xmitbuf_cnt=%d free_xmitframe_cnt=%d \n",
352                                         __func__, pxmitpriv->free_xmit_extbuf_cnt, pxmitpriv->free_xmitbuf_cnt,
353                                         pxmitpriv->free_xmitframe_cnt);
354 #endif
355                         pframe_queue = &ptxservq->sta_pending;
356
357                         frame_phead = get_list_head(pframe_queue);
358
359                         while (rtw_is_list_empty(frame_phead) == _FALSE)
360                         {
361                                 frame_plist = get_next(frame_phead);
362                                 pxmitframe = LIST_CONTAINOR(frame_plist, struct xmit_frame, list);
363                                 
364                                 // check xmit_buf size enough or not
365                                 txlen = txdesc_size + rtw_wlan_pkt_size(pxmitframe);
366                                 next_qsel = pxmitframe->attrib.qsel;
367                                 if ((NULL == pxmitbuf) ||
368                                         ((_RND(pxmitbuf->len, 8) + txlen) > max_xmit_len)
369                                         || (k >= (rtw_hal_sdio_max_txoqt_free_space(padapter)-1))
370                                         || ((k!=0) && (_FAIL == rtw_hal_busagg_qsel_check(padapter,pre_qsel,next_qsel)))
371                                 )
372                                 {
373                                         if (pxmitbuf)
374                                         {
375                                                 //pxmitbuf->priv_data will be NULL, and will crash here
376                                                 if (pxmitbuf->len > 0 && pxmitbuf->priv_data)
377                                                 {
378                                                         struct xmit_frame *pframe;
379                                                         pframe = (struct xmit_frame*)pxmitbuf->priv_data;
380                                                         pframe->agg_num = k;
381                                                         pxmitbuf->agg_num = k;
382                                                         rtl8723b_update_txdesc(pframe, pframe->buf_addr);
383                                                         rtw_free_xmitframe(pxmitpriv, pframe);
384                                                         pxmitbuf->priv_data = NULL;
385                                                         enqueue_pending_xmitbuf(pxmitpriv, pxmitbuf);
386                                                         //can not yield under lock
387                                                         //rtw_yield_os();
388                                                 } else {
389                                                         rtw_free_xmitbuf(pxmitpriv, pxmitbuf);
390                                                 }
391                                         }
392
393                                         pxmitbuf = rtw_alloc_xmitbuf(pxmitpriv);
394                                         if (pxmitbuf == NULL) {
395 #ifdef DBG_XMIT_BUF
396                                                 DBG_871X_LEVEL(_drv_err_, "%s: xmit_buf is not enough!\n", __FUNCTION__);
397 #endif
398                                                 err = -2;
399 #ifdef CONFIG_SDIO_TX_ENABLE_AVAL_INT
400         #ifdef CONFIG_CONCURRENT_MODE
401                                                 if (padapter->adapter_type > PRIMARY_ADAPTER)
402                                                         _rtw_up_sema(&(padapter->pbuddy_adapter->xmitpriv.xmit_sema));
403                                                 else
404         #endif
405                                                         _rtw_up_sema(&(pxmitpriv->xmit_sema));
406 #endif
407                                                 break;
408                                         }
409                                         k = 0;
410                                 }
411
412                                 // ok to send, remove frame from queue
413 #ifdef CONFIG_AP_MODE
414                                 if (check_fwstate(&padapter->mlmepriv, WIFI_AP_STATE) == _TRUE) {
415                                         if ((pxmitframe->attrib.psta->state & WIFI_SLEEP_STATE) &&
416                                                 (pxmitframe->attrib.triggered == 0)) {
417                                                 DBG_871X("%s: one not triggered pkt in queue when this STA sleep,"
418                                                                 " break and goto next sta\n", __func__);
419                                                 break;
420                                         }
421                                 }
422 #endif
423                                 rtw_list_delete(&pxmitframe->list);
424                                 ptxservq->qcnt--;
425                                 phwxmit->accnt--;
426
427                                 if (k == 0) {
428                                         pxmitbuf->ff_hwaddr = rtw_get_ff_hwaddr(pxmitframe);
429                                         pxmitbuf->priv_data = (u8*)pxmitframe;
430                                 }
431
432                                 // coalesce the xmitframe to xmitbuf
433                                 pxmitframe->pxmitbuf = pxmitbuf;
434                                 pxmitframe->buf_addr = pxmitbuf->ptail;
435
436                                 ret = rtw_xmitframe_coalesce(padapter, pxmitframe->pkt, pxmitframe);
437                                 if (ret == _FAIL) {
438                                         DBG_871X_LEVEL(_drv_err_, "%s: coalesce FAIL!", __FUNCTION__);
439                                         // Todo: error handler
440                                 } else {
441                                         k++;
442                                         if (k != 1)
443                                                 rtl8723b_update_txdesc(pxmitframe, pxmitframe->buf_addr);
444                                         rtw_count_tx_stats(padapter, pxmitframe, pxmitframe->attrib.last_txcmdsz);
445                                         pre_qsel = pxmitframe->attrib.qsel;
446                                         txlen = txdesc_size + pxmitframe->attrib.last_txcmdsz;
447                                         pxmitframe->pg_num = (txlen + 127)/128;
448                                         pxmitbuf->pg_num += (txlen + 127)/128;
449                                     //if (k != 1)
450                                         //      ((struct xmit_frame*)pxmitbuf->priv_data)->pg_num += pxmitframe->pg_num;
451                                         pxmitbuf->ptail += _RND(txlen, 8); // round to 8 bytes alignment
452                                         pxmitbuf->len = _RND(pxmitbuf->len, 8) + txlen;
453                                 }
454
455                                 if (k != 1)
456                                         rtw_free_xmitframe(pxmitpriv, pxmitframe);
457                                 pxmitframe = NULL;
458                         }
459
460                         if (_rtw_queue_empty(pframe_queue) == _TRUE)
461                                 rtw_list_delete(&ptxservq->tx_pending);
462
463                         if (err) break;
464                 }
465                 _exit_critical_bh(&pxmitpriv->lock, &irql);
466                 
467                 // dump xmit_buf to hw tx fifo
468                 if (pxmitbuf)
469                 {
470                         RT_TRACE(_module_hal_xmit_c_, _drv_info_, ("pxmitbuf->len=%d enqueue\n",pxmitbuf->len));
471
472                         if (pxmitbuf->len > 0) {
473                                 struct xmit_frame *pframe;
474                                 pframe = (struct xmit_frame*)pxmitbuf->priv_data;
475                                 pframe->agg_num = k;
476                                 pxmitbuf->agg_num = k;
477                                 rtl8723b_update_txdesc(pframe, pframe->buf_addr);
478                                 rtw_free_xmitframe(pxmitpriv, pframe);
479                                 pxmitbuf->priv_data = NULL;
480                                 enqueue_pending_xmitbuf(pxmitpriv, pxmitbuf);
481                                 rtw_yield_os();
482                         }
483                         else
484                                 rtw_free_xmitbuf(pxmitpriv, pxmitbuf);
485                         pxmitbuf = NULL;
486                 }
487                 
488                 if (err) break;
489         }
490
491         return err;
492 }
493
494 /*
495  * Description
496  *      Transmit xmitframe from queue
497  *
498  * Return
499  *      _SUCCESS        ok
500  *      _FAIL           something error
501  */
502 s32 rtl8723bs_xmit_handler(PADAPTER padapter)
503 {
504         struct xmit_priv *pxmitpriv;
505         s32 ret;
506         _irqL irql;
507
508
509         pxmitpriv = &padapter->xmitpriv;
510
511 wait:
512         ret = _rtw_down_sema(&pxmitpriv->SdioXmitSema);
513         if (_FAIL == ret) {
514                 DBG_871X_LEVEL(_drv_emerg_, "%s: down sema fail!\n", __FUNCTION__);
515                 return _FAIL;
516         }
517
518 next:
519         if ((padapter->bDriverStopped == _TRUE) ||
520                 (padapter->bSurpriseRemoved == _TRUE)) {
521                 RT_TRACE(_module_hal_xmit_c_, _drv_notice_,
522                                  ("%s: bDriverStopped(%d) bSurpriseRemoved(%d)\n",
523                                   __FUNCTION__, padapter->bDriverStopped, padapter->bSurpriseRemoved));
524                 return _FAIL;
525         }
526
527         _enter_critical_bh(&pxmitpriv->lock, &irql);
528         ret = rtw_txframes_pending(padapter);
529         _exit_critical_bh(&pxmitpriv->lock, &irql);
530         if (ret == 0) {
531                 return _SUCCESS;
532         }
533
534         // dequeue frame and write to hardware
535
536         ret = xmit_xmitframes(padapter, pxmitpriv);
537         if (ret == -2) {
538                 //here sleep 1ms will cause big TP loss of TX
539                 //from 50+ to 40+
540                 if(padapter->registrypriv.wifi_spec)
541                         rtw_msleep_os(1);
542                 else
543 #ifdef CONFIG_REDUCE_TX_CPU_LOADING 
544                         rtw_msleep_os(1);
545 #else
546                         rtw_yield_os();
547 #endif
548                 goto next;
549         }
550
551         _enter_critical_bh(&pxmitpriv->lock, &irql);
552         ret = rtw_txframes_pending(padapter);
553         _exit_critical_bh(&pxmitpriv->lock, &irql);
554         if (ret == 1) {
555 #ifdef CONFIG_REDUCE_TX_CPU_LOADING 
556                 rtw_msleep_os(1);
557 #endif
558                 goto next;
559         }
560
561         return _SUCCESS;
562 }
563
564 thread_return rtl8723bs_xmit_thread(thread_context context)
565 {
566         s32 ret;
567         PADAPTER padapter;
568         struct xmit_priv *pxmitpriv;
569         u8 thread_name[20] = "RTWHALXT";
570
571
572         ret = _SUCCESS;
573         padapter = (PADAPTER)context;
574         pxmitpriv = &padapter->xmitpriv;
575
576         rtw_sprintf(thread_name, 20, "%s-"ADPT_FMT, thread_name, ADPT_ARG(padapter));
577         thread_enter(thread_name);
578
579         DBG_871X("start "FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(padapter));
580
581         // For now, no one would down sema to check thread is running,
582         // so mark this temporary, Lucas@20130820
583 //      _rtw_up_sema(&pxmitpriv->SdioXmitTerminateSema);
584
585         do {
586                 ret = rtl8723bs_xmit_handler(padapter);
587                 if (signal_pending(current)) {
588                         flush_signals(current);
589                 }
590         } while (_SUCCESS == ret);
591
592         _rtw_up_sema(&pxmitpriv->SdioXmitTerminateSema);
593
594         RT_TRACE(_module_hal_xmit_c_, _drv_notice_, ("-%s\n", __FUNCTION__));
595
596         thread_exit();
597 }
598
599 s32 rtl8723bs_mgnt_xmit(PADAPTER padapter, struct xmit_frame *pmgntframe)
600 {
601         s32 ret = _SUCCESS;
602         struct pkt_attrib *pattrib;
603         struct xmit_buf *pxmitbuf;
604         struct xmit_priv        *pxmitpriv = &padapter->xmitpriv;
605         struct dvobj_priv       *pdvobjpriv = adapter_to_dvobj(padapter);
606         u8 *pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
607         u8 txdesc_size = TXDESC_SIZE;
608
609         RT_TRACE(_module_hal_xmit_c_, _drv_info_, ("+%s\n", __FUNCTION__));
610
611         pattrib = &pmgntframe->attrib;
612         pxmitbuf = pmgntframe->pxmitbuf;
613
614         rtl8723b_update_txdesc(pmgntframe, pmgntframe->buf_addr);
615
616         pxmitbuf->len = txdesc_size + pattrib->last_txcmdsz;
617         //pmgntframe->pg_num = (pxmitbuf->len + 127)/128; // 128 is tx page size
618         pxmitbuf->pg_num = (pxmitbuf->len + 127)/128; // 128 is tx page size
619         pxmitbuf->ptail = pmgntframe->buf_addr + pxmitbuf->len;
620         pxmitbuf->ff_hwaddr = rtw_get_ff_hwaddr(pmgntframe);
621
622         rtw_count_tx_stats(padapter, pmgntframe, pattrib->last_txcmdsz);
623
624         rtw_free_xmitframe(pxmitpriv, pmgntframe);
625
626         pxmitbuf->priv_data = NULL;
627
628         if(GetFrameSubType(pframe)==WIFI_BEACON) //dump beacon directly
629         {
630                 ret = rtw_write_port(padapter, pdvobjpriv->Queue2Pipe[pxmitbuf->ff_hwaddr], pxmitbuf->len, (u8 *)pxmitbuf);
631                 if (ret != _SUCCESS)
632                         rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_WRITE_PORT_ERR);
633
634                 rtw_free_xmitbuf(pxmitpriv, pxmitbuf);
635         }
636         else
637         {
638                 enqueue_pending_xmitbuf(pxmitpriv, pxmitbuf);
639         }
640
641         return ret;
642 }
643
644 /*
645  * Description:
646  *      Handle xmitframe(packet) come from rtw_xmit()
647  *
648  * Return:
649  *      _TRUE   dump packet directly ok
650  *      _FALSE  enqueue, temporary can't transmit packets to hardware
651  */
652 s32 rtl8723bs_hal_xmit(PADAPTER padapter, struct xmit_frame *pxmitframe)
653 {
654         struct xmit_priv *pxmitpriv;
655         _irqL irql;
656         s32 err;
657
658
659         pxmitframe->attrib.qsel = pxmitframe->attrib.priority;
660         pxmitpriv = &padapter->xmitpriv;
661
662 #ifdef CONFIG_80211N_HT
663         if ((pxmitframe->frame_tag == DATA_FRAMETAG) &&
664                 (pxmitframe->attrib.ether_type != 0x0806) &&
665                 (pxmitframe->attrib.ether_type != 0x888e) &&
666                 (pxmitframe->attrib.dhcp_pkt != 1))
667         {
668                 if (padapter->mlmepriv.LinkDetectInfo.bBusyTraffic == _TRUE)
669                         rtw_issue_addbareq_cmd(padapter, pxmitframe);
670         }
671 #endif
672
673         _enter_critical_bh(&pxmitpriv->lock, &irql);
674         err = rtw_xmitframe_enqueue(padapter, pxmitframe);
675         _exit_critical_bh(&pxmitpriv->lock, &irql);
676         if (err != _SUCCESS) {
677                 RT_TRACE(_module_hal_xmit_c_, _drv_err_, ("rtl8723bs_hal_xmit: enqueue xmitframe fail\n"));
678                 rtw_free_xmitframe(pxmitpriv, pxmitframe);
679
680                 pxmitpriv->tx_drop++;
681                 return _TRUE;
682         }
683
684         _rtw_up_sema(&pxmitpriv->SdioXmitSema);
685
686         return _FALSE;
687 }
688
689 s32     rtl8723bs_hal_xmitframe_enqueue(_adapter *padapter, struct xmit_frame *pxmitframe)
690 {
691         struct xmit_priv        *pxmitpriv = &padapter->xmitpriv;
692         s32 err;
693         
694         if ((err=rtw_xmitframe_enqueue(padapter, pxmitframe)) != _SUCCESS) 
695         {
696                 rtw_free_xmitframe(pxmitpriv, pxmitframe);
697
698                 pxmitpriv->tx_drop++;                                   
699         }
700         else
701         {
702 #ifdef CONFIG_SDIO_TX_TASKLET
703                 tasklet_hi_schedule(&pxmitpriv->xmit_tasklet);                                  
704 #else
705                 _rtw_up_sema(&pxmitpriv->SdioXmitSema);
706 #endif
707         }
708         
709         return err;
710         
711 }
712
713 /*
714  * Return
715  *      _SUCCESS        start thread ok
716  *      _FAIL           start thread fail
717  *
718  */
719 s32 rtl8723bs_init_xmit_priv(PADAPTER padapter)
720 {
721         struct xmit_priv *xmitpriv = &padapter->xmitpriv;
722         PHAL_DATA_TYPE phal;
723
724
725         phal = GET_HAL_DATA(padapter);
726
727         _rtw_spinlock_init(&phal->SdioTxFIFOFreePageLock);
728         _rtw_init_sema(&xmitpriv->SdioXmitSema, 0);
729         _rtw_init_sema(&xmitpriv->SdioXmitTerminateSema, 0);
730
731         return _SUCCESS;
732 }
733
734 void rtl8723bs_free_xmit_priv(PADAPTER padapter)
735 {
736         PHAL_DATA_TYPE phal;
737         struct xmit_priv *pxmitpriv;
738         struct xmit_buf *pxmitbuf;
739         _queue *pqueue;
740         _list *plist, *phead;
741         _list tmplist;
742         _irqL irql;
743
744
745         phal = GET_HAL_DATA(padapter);
746         pxmitpriv = &padapter->xmitpriv;
747         pqueue = &pxmitpriv->pending_xmitbuf_queue;
748         phead = get_list_head(pqueue);
749         _rtw_init_listhead(&tmplist);
750
751         _enter_critical_bh(&pqueue->lock, &irql);
752         if (_rtw_queue_empty(pqueue) == _FALSE)
753         {
754                 // Insert tmplist to end of queue, and delete phead
755                 // then tmplist become head of queue.
756                 rtw_list_insert_tail(&tmplist, phead);
757                 rtw_list_delete(phead);
758         }
759         _exit_critical_bh(&pqueue->lock, &irql);
760
761         phead = &tmplist;
762         while (rtw_is_list_empty(phead) == _FALSE)
763         {
764                 plist = get_next(phead);
765                 rtw_list_delete(plist);
766
767                 pxmitbuf = LIST_CONTAINOR(plist, struct xmit_buf, list);
768                 rtw_free_xmitframe(pxmitpriv, (struct xmit_frame*)pxmitbuf->priv_data);
769                 pxmitbuf->priv_data = NULL;
770                 rtw_free_xmitbuf(pxmitpriv, pxmitbuf);
771         }
772
773         _rtw_spinlock_free(&phal->SdioTxFIFOFreePageLock);
774 }
775