xref: /OK3568_Linux_fs/kernel/drivers/net/wireless/nxp/mlan/mlan_txrx.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /**
2  * @file mlan_txrx.c
3  *
4  *  @brief This file contains the handling of TX/RX in MLAN
5  *
6  *
7  *  Copyright 2009-2021 NXP
8  *
9  *  This software file (the File) is distributed by NXP
10  *  under the terms of the GNU General Public License Version 2, June 1991
11  *  (the License).  You may use, redistribute and/or modify the File in
12  *  accordance with the terms and conditions of the License, a copy of which
13  *  is available by writing to the Free Software Foundation, Inc.,
14  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
15  *  worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
16  *
17  *  THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
18  *  IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
19  *  ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
20  *  this warranty disclaimer.
21  *
22  */
23 
24 /*************************************************************
25 Change Log:
26     05/11/2009: initial version
27 ************************************************************/
28 
29 #include "mlan.h"
30 #ifdef STA_SUPPORT
31 #include "mlan_join.h"
32 #endif
33 #include "mlan_util.h"
34 #include "mlan_fw.h"
35 #include "mlan_main.h"
36 #include "mlan_wmm.h"
37 
38 /********************************************************
39 			Local Variables
40 ********************************************************/
41 
42 /********************************************************
43 			Global Variables
44 ********************************************************/
45 
46 /********************************************************
47 			Local Functions
48 ********************************************************/
49 
50 /********************************************************
51 			Global Functions
52 ********************************************************/
53 /**
54  *   @brief This function processes the received buffer
55  *
56  *   @param pmadapter A pointer to mlan_adapter
57  *   @param pmbuf     A pointer to the received buffer
58  *
59  *   @return        MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
60  */
wlan_handle_rx_packet(pmlan_adapter pmadapter,pmlan_buffer pmbuf)61 mlan_status wlan_handle_rx_packet(pmlan_adapter pmadapter, pmlan_buffer pmbuf)
62 {
63 	mlan_status ret = MLAN_STATUS_SUCCESS;
64 	pmlan_private priv = MNULL;
65 	RxPD *prx_pd;
66 #ifdef DEBUG_LEVEL1
67 	t_u32 sec = 0, usec = 0;
68 #endif
69 
70 	ENTER();
71 
72 	prx_pd = (RxPD *)(pmbuf->pbuf + pmbuf->data_offset);
73 	/* Get the BSS number from RxPD, get corresponding priv */
74 	priv = wlan_get_priv_by_id(pmadapter, prx_pd->bss_num & BSS_NUM_MASK,
75 				   prx_pd->bss_type);
76 	if (!priv)
77 		priv = wlan_get_priv(pmadapter, MLAN_BSS_ROLE_ANY);
78 	if (!priv) {
79 		ret = MLAN_STATUS_FAILURE;
80 		goto done;
81 	}
82 	pmbuf->bss_index = priv->bss_index;
83 	PRINTM_GET_SYS_TIME(MDATA, &sec, &usec);
84 	PRINTM_NETINTF(MDATA, priv);
85 	PRINTM(MDATA, "%lu.%06lu : Data <= FW\n", sec, usec);
86 	ret = priv->ops.process_rx_packet(pmadapter, pmbuf);
87 
88 done:
89 	LEAVE();
90 	return ret;
91 }
92 
93 /**
94  *  @brief This function checks the conditions and sends packet to device
95  *
96  *  @param priv	   A pointer to mlan_private structure
97  *  @param pmbuf   A pointer to the mlan_buffer for process
98  *  @param tx_param A pointer to mlan_tx_param structure
99  *
100  *  @return         MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success, otherwise
101  * failure
102  */
wlan_process_tx(pmlan_private priv,pmlan_buffer pmbuf,mlan_tx_param * tx_param)103 mlan_status wlan_process_tx(pmlan_private priv, pmlan_buffer pmbuf,
104 			    mlan_tx_param *tx_param)
105 {
106 	mlan_status ret = MLAN_STATUS_SUCCESS;
107 	pmlan_adapter pmadapter = priv->adapter;
108 	t_u8 *head_ptr = MNULL;
109 #ifdef DEBUG_LEVEL1
110 	t_u32 sec = 0, usec = 0;
111 #endif
112 #ifdef STA_SUPPORT
113 	PTxPD plocal_tx_pd = MNULL;
114 #endif
115 
116 	ENTER();
117 	head_ptr = (t_u8 *)priv->ops.process_txpd(priv, pmbuf);
118 	if (!head_ptr) {
119 		pmbuf->status_code = MLAN_ERROR_PKT_INVALID;
120 		ret = MLAN_STATUS_FAILURE;
121 		goto done;
122 	}
123 #ifdef STA_SUPPORT
124 	if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA)
125 		plocal_tx_pd = (TxPD *)(head_ptr + priv->intf_hr_len);
126 #endif
127 	if (pmadapter->tp_state_on)
128 		pmadapter->callbacks.moal_tp_accounting(pmadapter->pmoal_handle,
129 							pmbuf, 4);
130 	if (pmadapter->tp_state_drop_point == 4)
131 		goto done;
132 	else {
133 		ret = pmadapter->ops.host_to_card(priv, MLAN_TYPE_DATA, pmbuf,
134 						  tx_param);
135 	}
136 done:
137 	switch (ret) {
138 #ifdef USB
139 	case MLAN_STATUS_PRESOURCE:
140 		PRINTM(MINFO, "MLAN_STATUS_PRESOURCE is returned\n");
141 		DBG_HEXDUMP(MDAT_D, "Tx", head_ptr + priv->intf_hr_len,
142 			    MIN(pmbuf->data_len + sizeof(TxPD),
143 				MAX_DATA_DUMP_LEN));
144 		break;
145 #endif
146 	case MLAN_STATUS_RESOURCE:
147 #ifdef STA_SUPPORT
148 		if ((GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) &&
149 		    pmadapter->pps_uapsd_mode &&
150 		    (pmadapter->tx_lock_flag == MTRUE)) {
151 			pmadapter->tx_lock_flag = MFALSE;
152 			if (plocal_tx_pd != MNULL)
153 				plocal_tx_pd->flags = 0;
154 		}
155 #endif
156 		PRINTM(MINFO, "MLAN_STATUS_RESOURCE is returned\n");
157 		break;
158 	case MLAN_STATUS_FAILURE:
159 		pmadapter->dbg.num_tx_host_to_card_failure++;
160 		pmbuf->status_code = MLAN_ERROR_DATA_TX_FAIL;
161 		wlan_write_data_complete(pmadapter, pmbuf, ret);
162 		break;
163 	case MLAN_STATUS_PENDING:
164 		DBG_HEXDUMP(MDAT_D, "Tx", head_ptr + priv->intf_hr_len,
165 			    MIN(pmbuf->data_len + sizeof(TxPD),
166 				MAX_DATA_DUMP_LEN));
167 		break;
168 	case MLAN_STATUS_SUCCESS:
169 		DBG_HEXDUMP(MDAT_D, "Tx", head_ptr + priv->intf_hr_len,
170 			    MIN(pmbuf->data_len + sizeof(TxPD),
171 				MAX_DATA_DUMP_LEN));
172 		wlan_write_data_complete(pmadapter, pmbuf, ret);
173 		break;
174 	default:
175 		break;
176 	}
177 
178 	if ((ret == MLAN_STATUS_SUCCESS) || (ret == MLAN_STATUS_PENDING)) {
179 		PRINTM_GET_SYS_TIME(MDATA, &sec, &usec);
180 		PRINTM_NETINTF(MDATA, priv);
181 		PRINTM(MDATA, "%lu.%06lu : Data => FW\n", sec, usec);
182 	}
183 	LEAVE();
184 	return ret;
185 }
186 
187 /**
188  *  @brief Packet send completion handling
189  *
190  *  @param pmadapter		A pointer to mlan_adapter structure
191  *  @param pmbuf		A pointer to mlan_buffer structure
192  *  @param status		Callback status
193  *
194  *  @return			MLAN_STATUS_SUCCESS
195  */
wlan_write_data_complete(pmlan_adapter pmadapter,pmlan_buffer pmbuf,mlan_status status)196 mlan_status wlan_write_data_complete(pmlan_adapter pmadapter,
197 				     pmlan_buffer pmbuf, mlan_status status)
198 {
199 	mlan_status ret = MLAN_STATUS_SUCCESS;
200 	pmlan_callbacks pcb;
201 
202 	ENTER();
203 
204 	MASSERT(pmadapter && pmbuf);
205 	if (!pmadapter || !pmbuf) {
206 		LEAVE();
207 		return MLAN_STATUS_FAILURE;
208 	}
209 
210 	pcb = &pmadapter->callbacks;
211 
212 	if ((pmbuf->buf_type == MLAN_BUF_TYPE_DATA) ||
213 	    (pmbuf->buf_type == MLAN_BUF_TYPE_RAW_DATA)) {
214 		PRINTM(MINFO, "wlan_write_data_complete: DATA %p\n", pmbuf);
215 #if defined(USB)
216 		if ((pmbuf->flags & MLAN_BUF_FLAG_USB_TX_AGGR) &&
217 		    pmbuf->use_count) {
218 			pmlan_buffer pmbuf_next;
219 			t_u32 i, use_count = pmbuf->use_count;
220 			for (i = 0; i <= use_count; i++) {
221 				pmbuf_next = pmbuf->pnext;
222 				if (pmbuf->flags & MLAN_BUF_FLAG_MOAL_TX_BUF)
223 					pcb->moal_send_packet_complete(
224 						pmadapter->pmoal_handle, pmbuf,
225 						status);
226 				else
227 					wlan_free_mlan_buffer(pmadapter, pmbuf);
228 				pmbuf = pmbuf_next;
229 			}
230 		} else {
231 #endif
232 			if (pmbuf->flags & MLAN_BUF_FLAG_MOAL_TX_BUF) {
233 				/* pmbuf was allocated by MOAL */
234 				pcb->moal_send_packet_complete(
235 					pmadapter->pmoal_handle, pmbuf, status);
236 			} else {
237 				/* pmbuf was allocated by MLAN */
238 				wlan_free_mlan_buffer(pmadapter, pmbuf);
239 			}
240 #if defined(USB)
241 		}
242 #endif
243 	}
244 
245 	LEAVE();
246 	return ret;
247 }
248 
249 /**
250  *  @brief Packet receive completion callback handler
251  *
252  *  @param pmadapter		A pointer to mlan_adapter structure
253  *  @param pmbuf		A pointer to mlan_buffer structure
254  *  @param status		Callback status
255  *
256  *  @return			MLAN_STATUS_SUCCESS
257  */
wlan_recv_packet_complete(pmlan_adapter pmadapter,pmlan_buffer pmbuf,mlan_status status)258 mlan_status wlan_recv_packet_complete(pmlan_adapter pmadapter,
259 				      pmlan_buffer pmbuf, mlan_status status)
260 {
261 	mlan_status ret = MLAN_STATUS_SUCCESS;
262 
263 	ENTER();
264 
265 	MASSERT(pmadapter && pmbuf);
266 	if (!pmadapter || !pmbuf) {
267 		LEAVE();
268 		return MLAN_STATUS_FAILURE;
269 	}
270 
271 	MASSERT(pmbuf->bss_index < pmadapter->priv_num);
272 
273 	if (pmbuf->pparent) {
274 		/** we will free the pparaent at the end of deaggr */
275 		wlan_free_mlan_buffer(pmadapter, pmbuf);
276 	} else {
277 		pmadapter->ops.data_complete(pmadapter, pmbuf, status);
278 	}
279 
280 	LEAVE();
281 	return ret;
282 }
283 
284 /**
285  *  @brief Add packet to Bypass TX queue
286  *
287  *  @param pmadapter  Pointer to the mlan_adapter driver data struct
288  *  @param pmbuf      Pointer to the mlan_buffer data struct
289  *
290  *  @return         N/A
291  */
wlan_add_buf_bypass_txqueue(mlan_adapter * pmadapter,pmlan_buffer pmbuf)292 t_void wlan_add_buf_bypass_txqueue(mlan_adapter *pmadapter, pmlan_buffer pmbuf)
293 {
294 	pmlan_private priv = pmadapter->priv[pmbuf->bss_index];
295 	ENTER();
296 
297 	if (pmbuf->buf_type != MLAN_BUF_TYPE_RAW_DATA)
298 		pmbuf->buf_type = MLAN_BUF_TYPE_DATA;
299 	pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
300 					    priv->bypass_txq.plock);
301 	pmadapter->bypass_pkt_count++;
302 	util_enqueue_list_tail(pmadapter->pmoal_handle, &priv->bypass_txq,
303 			       (pmlan_linked_list)pmbuf, MNULL, MNULL);
304 	pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
305 					      priv->bypass_txq.plock);
306 	LEAVE();
307 }
308 
309 /**
310  *  @brief Check if packets are available in Bypass TX queue
311  *
312  *  @param pmadapter  Pointer to the mlan_adapter driver data struct
313  *
314  *  @return         MFALSE if not empty; MTRUE if empty
315  */
wlan_bypass_tx_list_empty(mlan_adapter * pmadapter)316 INLINE t_u8 wlan_bypass_tx_list_empty(mlan_adapter *pmadapter)
317 {
318 	return (pmadapter->bypass_pkt_count) ? MFALSE : MTRUE;
319 }
320 
321 /**
322  *  @brief Clean up the By-pass TX queue
323  *
324  *  @param priv     Pointer to the mlan_private data struct
325  *
326  *  @return      N/A
327  */
wlan_cleanup_bypass_txq(mlan_private * priv)328 t_void wlan_cleanup_bypass_txq(mlan_private *priv)
329 {
330 	pmlan_buffer pmbuf;
331 	mlan_adapter *pmadapter = priv->adapter;
332 	ENTER();
333 	pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
334 					    priv->bypass_txq.plock);
335 	while ((pmbuf = (pmlan_buffer)util_peek_list(pmadapter->pmoal_handle,
336 						     &priv->bypass_txq, MNULL,
337 						     MNULL))) {
338 		util_unlink_list(pmadapter->pmoal_handle, &priv->bypass_txq,
339 				 (pmlan_linked_list)pmbuf, MNULL, MNULL);
340 		wlan_write_data_complete(pmadapter, pmbuf, MLAN_STATUS_FAILURE);
341 		pmadapter->bypass_pkt_count--;
342 	}
343 	pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
344 					      priv->bypass_txq.plock);
345 	LEAVE();
346 }
347 
348 /**
349  *  @brief Transmit the By-passed packet awaiting in by-pass queue
350  *
351  *  @param pmadapter Pointer to the mlan_adapter driver data struct
352  *
353  *  @return        N/A
354  */
wlan_process_bypass_tx(pmlan_adapter pmadapter)355 t_void wlan_process_bypass_tx(pmlan_adapter pmadapter)
356 {
357 	pmlan_buffer pmbuf;
358 	mlan_tx_param tx_param;
359 	mlan_status status = MLAN_STATUS_SUCCESS;
360 	pmlan_private priv;
361 	int j = 0;
362 	ENTER();
363 	do {
364 		for (j = 0; j < pmadapter->priv_num; ++j) {
365 			priv = pmadapter->priv[j];
366 			if (priv) {
367 				pmbuf = (pmlan_buffer)util_dequeue_list(
368 					pmadapter->pmoal_handle,
369 					&priv->bypass_txq,
370 					pmadapter->callbacks.moal_spin_lock,
371 					pmadapter->callbacks.moal_spin_unlock);
372 				if (pmbuf) {
373 					pmadapter->callbacks.moal_spin_lock(
374 						pmadapter->pmoal_handle,
375 						priv->bypass_txq.plock);
376 					pmadapter->bypass_pkt_count--;
377 					pmadapter->callbacks.moal_spin_unlock(
378 						pmadapter->pmoal_handle,
379 						priv->bypass_txq.plock);
380 					PRINTM(MINFO,
381 					       "Dequeuing bypassed packet %p\n",
382 					       pmbuf);
383 					if (wlan_bypass_tx_list_empty(
384 						    pmadapter))
385 						tx_param.next_pkt_len = 0;
386 					else
387 						tx_param.next_pkt_len =
388 							pmbuf->data_len;
389 					status = wlan_process_tx(
390 						pmadapter->priv[pmbuf->bss_index],
391 						pmbuf, &tx_param);
392 
393 					if (status == MLAN_STATUS_RESOURCE) {
394 						/* Queue the packet again so
395 						 * that it will be TX'ed later
396 						 */
397 						pmadapter->callbacks.moal_spin_lock(
398 							pmadapter->pmoal_handle,
399 							priv->bypass_txq.plock);
400 						pmadapter->bypass_pkt_count++;
401 						util_enqueue_list_head(
402 							pmadapter->pmoal_handle,
403 							&priv->bypass_txq,
404 							(pmlan_linked_list)pmbuf,
405 							pmadapter->callbacks
406 								.moal_spin_lock,
407 							pmadapter->callbacks
408 								.moal_spin_unlock);
409 						pmadapter->callbacks.moal_spin_unlock(
410 							pmadapter->pmoal_handle,
411 							priv->bypass_txq.plock);
412 					}
413 					break;
414 				} else {
415 					PRINTM(MINFO, "Nothing to send\n");
416 				}
417 			}
418 		}
419 	} while (!pmadapter->data_sent && !pmadapter->tx_lock_flag &&
420 		 !wlan_bypass_tx_list_empty(pmadapter));
421 	LEAVE();
422 }
423