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