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