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