linux/drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c
<<
>>
Prefs
   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
  13static 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
  47static 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
  86query_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
 122free_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 */
 142s32 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 */
 200static 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 */
 415static 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
 428next:
 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
 476int rtl8723bs_xmit_thread(void *context)
 477{
 478        s32 ret;
 479        struct adapter *padapter;
 480        struct xmit_priv *pxmitpriv;
 481        u8 thread_name[20] = "RTWHALXT";
 482
 483
 484        ret = _SUCCESS;
 485        padapter = context;
 486        pxmitpriv = &padapter->xmitpriv;
 487
 488        rtw_sprintf(thread_name, 20, "%s-"ADPT_FMT, thread_name, ADPT_ARG(padapter));
 489        thread_enter(thread_name);
 490
 491        DBG_871X("start "FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(padapter));
 492
 493        /*  For now, no one would down sema to check thread is running, */
 494        /*  so mark this temporary, Lucas@20130820 */
 495/*      up(&pxmitpriv->SdioXmitTerminateSema); */
 496
 497        do {
 498                ret = rtl8723bs_xmit_handler(padapter);
 499                if (signal_pending(current)) {
 500                        flush_signals(current);
 501                }
 502        } while (_SUCCESS == ret);
 503
 504        up(&pxmitpriv->SdioXmitTerminateSema);
 505
 506        RT_TRACE(_module_hal_xmit_c_, _drv_notice_, ("-%s\n", __func__));
 507
 508        thread_exit();
 509}
 510
 511s32 rtl8723bs_mgnt_xmit(
 512        struct adapter *padapter, struct xmit_frame *pmgntframe
 513)
 514{
 515        s32 ret = _SUCCESS;
 516        struct pkt_attrib *pattrib;
 517        struct xmit_buf *pxmitbuf;
 518        struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
 519        struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter);
 520        u8 *pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
 521        u8 txdesc_size = TXDESC_SIZE;
 522
 523        RT_TRACE(_module_hal_xmit_c_, _drv_info_, ("+%s\n", __func__));
 524
 525        pattrib = &pmgntframe->attrib;
 526        pxmitbuf = pmgntframe->pxmitbuf;
 527
 528        rtl8723b_update_txdesc(pmgntframe, pmgntframe->buf_addr);
 529
 530        pxmitbuf->len = txdesc_size + pattrib->last_txcmdsz;
 531        pxmitbuf->pg_num = (pxmitbuf->len + 127)/128; /*  128 is tx page size */
 532        pxmitbuf->ptail = pmgntframe->buf_addr + pxmitbuf->len;
 533        pxmitbuf->ff_hwaddr = rtw_get_ff_hwaddr(pmgntframe);
 534
 535        rtw_count_tx_stats(padapter, pmgntframe, pattrib->last_txcmdsz);
 536
 537        rtw_free_xmitframe(pxmitpriv, pmgntframe);
 538
 539        pxmitbuf->priv_data = NULL;
 540
 541        if (GetFrameSubType(pframe) == WIFI_BEACON) { /* dump beacon directly */
 542                ret = rtw_write_port(padapter, pdvobjpriv->Queue2Pipe[pxmitbuf->ff_hwaddr], pxmitbuf->len, (u8 *)pxmitbuf);
 543                if (ret != _SUCCESS)
 544                        rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_WRITE_PORT_ERR);
 545
 546                rtw_free_xmitbuf(pxmitpriv, pxmitbuf);
 547        } else
 548                enqueue_pending_xmitbuf(pxmitpriv, pxmitbuf);
 549
 550        return ret;
 551}
 552
 553/*
 554 * Description:
 555 *Handle xmitframe(packet) come from rtw_xmit()
 556 *
 557 * Return:
 558 *true  dump packet directly ok
 559 *false enqueue, temporary can't transmit packets to hardware
 560 */
 561s32 rtl8723bs_hal_xmit(
 562        struct adapter *padapter, struct xmit_frame *pxmitframe
 563)
 564{
 565        struct xmit_priv *pxmitpriv;
 566        s32 err;
 567
 568
 569        pxmitframe->attrib.qsel = pxmitframe->attrib.priority;
 570        pxmitpriv = &padapter->xmitpriv;
 571
 572        if (
 573                (pxmitframe->frame_tag == DATA_FRAMETAG) &&
 574                (pxmitframe->attrib.ether_type != 0x0806) &&
 575                (pxmitframe->attrib.ether_type != 0x888e) &&
 576                (pxmitframe->attrib.dhcp_pkt != 1)
 577        ) {
 578                if (padapter->mlmepriv.LinkDetectInfo.bBusyTraffic == true)
 579                        rtw_issue_addbareq_cmd(padapter, pxmitframe);
 580        }
 581
 582        spin_lock_bh(&pxmitpriv->lock);
 583        err = rtw_xmitframe_enqueue(padapter, pxmitframe);
 584        spin_unlock_bh(&pxmitpriv->lock);
 585        if (err != _SUCCESS) {
 586                RT_TRACE(_module_hal_xmit_c_, _drv_err_, ("rtl8723bs_hal_xmit: enqueue xmitframe fail\n"));
 587                rtw_free_xmitframe(pxmitpriv, pxmitframe);
 588
 589                pxmitpriv->tx_drop++;
 590                return true;
 591        }
 592
 593        up(&pxmitpriv->SdioXmitSema);
 594
 595        return false;
 596}
 597
 598s32     rtl8723bs_hal_xmitframe_enqueue(
 599        struct adapter *padapter, struct xmit_frame *pxmitframe
 600)
 601{
 602        struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
 603        s32 err;
 604
 605        err = rtw_xmitframe_enqueue(padapter, pxmitframe);
 606        if (err != _SUCCESS) {
 607                rtw_free_xmitframe(pxmitpriv, pxmitframe);
 608
 609                pxmitpriv->tx_drop++;
 610        } else {
 611#ifdef CONFIG_SDIO_TX_TASKLET
 612                tasklet_hi_schedule(&pxmitpriv->xmit_tasklet);
 613#else
 614                up(&pxmitpriv->SdioXmitSema);
 615#endif
 616        }
 617
 618        return err;
 619
 620}
 621
 622/*
 623 * Return
 624 *_SUCCESS      start thread ok
 625 *_FAIL         start thread fail
 626 *
 627 */
 628s32 rtl8723bs_init_xmit_priv(struct adapter *padapter)
 629{
 630        struct xmit_priv *xmitpriv = &padapter->xmitpriv;
 631        struct hal_com_data *phal;
 632
 633
 634        phal = GET_HAL_DATA(padapter);
 635
 636        spin_lock_init(&phal->SdioTxFIFOFreePageLock);
 637        sema_init(&xmitpriv->SdioXmitSema, 0);
 638        sema_init(&xmitpriv->SdioXmitTerminateSema, 0);
 639
 640        return _SUCCESS;
 641}
 642
 643void rtl8723bs_free_xmit_priv(struct adapter *padapter)
 644{
 645        struct hal_com_data *phal;
 646        struct xmit_priv *pxmitpriv;
 647        struct xmit_buf *pxmitbuf;
 648        struct __queue *pqueue;
 649        struct list_head *plist, *phead;
 650        struct list_head tmplist;
 651
 652
 653        phal = GET_HAL_DATA(padapter);
 654        pxmitpriv = &padapter->xmitpriv;
 655        pqueue = &pxmitpriv->pending_xmitbuf_queue;
 656        phead = get_list_head(pqueue);
 657        INIT_LIST_HEAD(&tmplist);
 658
 659        spin_lock_bh(&pqueue->lock);
 660        if (!list_empty(&pqueue->queue)) {
 661                /*  Insert tmplist to end of queue, and delete phead */
 662                /*  then tmplist become head of queue. */
 663                list_add_tail(&tmplist, phead);
 664                list_del_init(phead);
 665        }
 666        spin_unlock_bh(&pqueue->lock);
 667
 668        phead = &tmplist;
 669        while (list_empty(phead) == false) {
 670                plist = get_next(phead);
 671                list_del_init(plist);
 672
 673                pxmitbuf = LIST_CONTAINOR(plist, struct xmit_buf, list);
 674                rtw_free_xmitframe(pxmitpriv, (struct xmit_frame *)pxmitbuf->priv_data);
 675                pxmitbuf->priv_data = NULL;
 676                rtw_free_xmitbuf(pxmitpriv, pxmitbuf);
 677        }
 678}
 679