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