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