File Index
Files and directories
Sign in
FILE

rtl8723bs_xmit.c

File preview with syntax highlighting.

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