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