1 /** @file mlan_sta_tx.c
2 *
3 * @brief This file contains the handling of data packet
4 * transmission in MLAN module.
5 *
6 *
7 * Copyright 2008-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 10/21/2008: initial version
27 ********************************************************/
28
29 #include "mlan.h"
30 #include "mlan_join.h"
31 #include "mlan_util.h"
32 #include "mlan_fw.h"
33 #include "mlan_main.h"
34 #include "mlan_wmm.h"
35
36 /********************************************************
37 Local Variables
38 ********************************************************/
39
40 /********************************************************
41 Global Variables
42 ********************************************************/
43
44 /********************************************************
45 Local Functions
46 ********************************************************/
47
48 /********************************************************
49 Global functions
50 ********************************************************/
51 /**
52 * @brief This function fill the txpd for tx packet
53 *
54 * @param priv A pointer to mlan_private structure
55 * @param pmbuf A pointer to the mlan_buffer for process
56 *
57 * @return headptr or MNULL
58 */
wlan_ops_sta_process_txpd(t_void * priv,pmlan_buffer pmbuf)59 t_void *wlan_ops_sta_process_txpd(t_void *priv, pmlan_buffer pmbuf)
60 {
61 mlan_private *pmpriv = (mlan_private *)priv;
62 pmlan_adapter pmadapter = pmpriv->adapter;
63 TxPD *plocal_tx_pd;
64 t_u8 *head_ptr = MNULL;
65 t_u32 pkt_type;
66 t_u32 tx_control;
67
68 ENTER();
69
70 if (!pmbuf->data_len) {
71 PRINTM(MERROR, "STA Tx Error: Invalid packet length: %d\n",
72 pmbuf->data_len);
73 pmbuf->status_code = MLAN_ERROR_PKT_SIZE_INVALID;
74 goto done;
75 }
76 if (pmbuf->buf_type == MLAN_BUF_TYPE_RAW_DATA) {
77 memcpy_ext(pmpriv->adapter, &pkt_type,
78 pmbuf->pbuf + pmbuf->data_offset, sizeof(pkt_type),
79 sizeof(pkt_type));
80 memcpy_ext(pmpriv->adapter, &tx_control,
81 pmbuf->pbuf + pmbuf->data_offset + sizeof(pkt_type),
82 sizeof(tx_control), sizeof(tx_control));
83 pmbuf->data_offset += sizeof(pkt_type) + sizeof(tx_control);
84 pmbuf->data_len -= sizeof(pkt_type) + sizeof(tx_control);
85 }
86
87 if (pmbuf->data_offset <
88 (sizeof(TxPD) + pmpriv->intf_hr_len + DMA_ALIGNMENT)) {
89 PRINTM(MERROR,
90 "not enough space for TxPD: headroom=%d pkt_len=%d, required=%d\n",
91 pmbuf->data_offset, pmbuf->data_len,
92 sizeof(TxPD) + pmpriv->intf_hr_len + DMA_ALIGNMENT);
93 pmbuf->status_code = MLAN_ERROR_PKT_SIZE_INVALID;
94 goto done;
95 }
96
97 /* head_ptr should be aligned */
98 head_ptr = pmbuf->pbuf + pmbuf->data_offset - sizeof(TxPD) -
99 pmpriv->intf_hr_len;
100 head_ptr = (t_u8 *)((t_ptr)head_ptr & ~((t_ptr)(DMA_ALIGNMENT - 1)));
101
102 plocal_tx_pd = (TxPD *)(head_ptr + pmpriv->intf_hr_len);
103 memset(pmadapter, plocal_tx_pd, 0, sizeof(TxPD));
104 /* Set the BSS number to TxPD */
105 plocal_tx_pd->bss_num = GET_BSS_NUM(pmpriv);
106 plocal_tx_pd->bss_type = pmpriv->bss_type;
107 plocal_tx_pd->tx_pkt_length = (t_u16)pmbuf->data_len;
108
109 plocal_tx_pd->priority = (t_u8)pmbuf->priority;
110 plocal_tx_pd->pkt_delay_2ms =
111 wlan_wmm_compute_driver_packet_delay(pmpriv, pmbuf);
112
113 if (plocal_tx_pd->priority <
114 NELEMENTS(pmpriv->wmm.user_pri_pkt_tx_ctrl))
115 /*
116 * Set the priority specific tx_control field, setting of 0 will
117 * cause the default value to be used later in this function
118 */
119 plocal_tx_pd->tx_control =
120 pmpriv->wmm.user_pri_pkt_tx_ctrl[plocal_tx_pd->priority];
121 if (pmadapter->pps_uapsd_mode) {
122 if (MTRUE == wlan_check_last_packet_indication(pmpriv)) {
123 pmadapter->tx_lock_flag = MTRUE;
124 plocal_tx_pd->flags =
125 MRVDRV_TxPD_POWER_MGMT_LAST_PACKET;
126 }
127 }
128 if (pmbuf->flags & MLAN_BUF_FLAG_TDLS)
129 plocal_tx_pd->flags |= MRVDRV_TxPD_FLAGS_TDLS_PACKET;
130 /* Offset of actual data */
131 plocal_tx_pd->tx_pkt_offset = (t_u16)(
132 (t_ptr)pmbuf->pbuf + pmbuf->data_offset - (t_ptr)plocal_tx_pd);
133
134 if (!plocal_tx_pd->tx_control) {
135 /* TxCtrl set by user or default */
136 plocal_tx_pd->tx_control = pmpriv->pkt_tx_ctrl;
137 }
138
139 if (pmbuf->buf_type == MLAN_BUF_TYPE_RAW_DATA) {
140 plocal_tx_pd->tx_pkt_type = (t_u16)pkt_type;
141 plocal_tx_pd->tx_control = tx_control;
142 }
143
144 if (pmbuf->flags & MLAN_BUF_FLAG_TX_STATUS) {
145 plocal_tx_pd->tx_control_1 |= pmbuf->tx_seq_num << 8;
146 plocal_tx_pd->flags |= MRVDRV_TxPD_FLAGS_TX_PACKET_STATUS;
147 }
148 if (pmbuf->flags & MLAN_BUF_FLAG_TX_CTRL) {
149 if (pmbuf->u.tx_info.data_rate) {
150 plocal_tx_pd->tx_control |=
151 (wlan_ieee_rateid_to_mrvl_rateid(
152 pmpriv, pmbuf->u.tx_info.data_rate,
153 MNULL)
154 << 16);
155 plocal_tx_pd->tx_control |= TXPD_TXRATE_ENABLE;
156 }
157 plocal_tx_pd->tx_control_1 |= pmbuf->u.tx_info.channel << 21;
158 if (pmbuf->u.tx_info.bw) {
159 plocal_tx_pd->tx_control_1 |= pmbuf->u.tx_info.bw << 16;
160 plocal_tx_pd->tx_control_1 |= TXPD_BW_ENABLE;
161 }
162 if (pmbuf->u.tx_info.tx_power.tp.hostctl)
163 plocal_tx_pd->tx_control |=
164 (t_u32)pmbuf->u.tx_info.tx_power.val;
165 if (pmbuf->u.tx_info.retry_limit) {
166 plocal_tx_pd->tx_control |= pmbuf->u.tx_info.retry_limit
167 << 8;
168 plocal_tx_pd->tx_control |= TXPD_RETRY_ENABLE;
169 }
170 }
171 if (pmbuf->flags & MLAN_BUF_FLAG_MC_AGGR_PKT) {
172 tx_ctrl *ctrl = (tx_ctrl *)&plocal_tx_pd->tx_control;
173 mc_tx_ctrl *mc_ctrl =
174 (mc_tx_ctrl *)&plocal_tx_pd->pkt_delay_2ms;
175 plocal_tx_pd->tx_pkt_type = PKT_TYPE_802DOT11_MC_AGGR;
176 if (pmbuf->u.mc_tx_info.mc_pkt_flags & MC_FLAG_START_CYCLE)
177 ctrl->mc_cycle_start = MTRUE;
178 else
179 ctrl->mc_cycle_start = MFALSE;
180 if (pmbuf->u.mc_tx_info.mc_pkt_flags & MC_FLAG_END_CYCLE)
181 ctrl->mc_cycle_end = MTRUE;
182 else
183 ctrl->mc_cycle_end = MFALSE;
184 if (pmbuf->u.mc_tx_info.mc_pkt_flags & MC_FLAG_START_AMPDU)
185 ctrl->mc_ampdu_start = MTRUE;
186 else
187 ctrl->mc_ampdu_start = MFALSE;
188 if (pmbuf->u.mc_tx_info.mc_pkt_flags & MC_FLAG_END_AMPDU)
189 ctrl->mc_ampdu_end = MTRUE;
190 else
191 ctrl->mc_ampdu_end = MFALSE;
192 if (pmbuf->u.mc_tx_info.mc_pkt_flags & MC_FLAG_RETRY)
193 ctrl->mc_pkt_retry = MTRUE;
194 else
195 ctrl->mc_pkt_retry = MFALSE;
196 ctrl->bw = pmbuf->u.mc_tx_info.bandwidth & 0x7;
197 ctrl->tx_rate = pmbuf->u.mc_tx_info.mcs_index & 0x1f;
198 mc_ctrl->abs_tsf_expirytime =
199 wlan_cpu_to_le32(pmbuf->u.mc_tx_info.pkt_expiry);
200 mc_ctrl->mc_seq = wlan_cpu_to_le16(pmbuf->u.mc_tx_info.seq_num);
201 }
202 endian_convert_TxPD(plocal_tx_pd);
203
204 /* Adjust the data offset and length to include TxPD in pmbuf */
205 pmbuf->data_len += pmbuf->data_offset;
206 pmbuf->data_offset = (t_u32)(head_ptr - pmbuf->pbuf);
207 pmbuf->data_len -= pmbuf->data_offset;
208
209 done:
210 LEAVE();
211 return head_ptr;
212 }
213
214 /**
215 * @brief This function tells firmware to send a NULL data packet.
216 *
217 * @param priv A pointer to mlan_private structure
218 * @param flags Transmit Pkt Flags
219 *
220 * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success, otherwise
221 * failure
222 */
wlan_send_null_packet(pmlan_private priv,t_u8 flags)223 mlan_status wlan_send_null_packet(pmlan_private priv, t_u8 flags)
224 {
225 pmlan_adapter pmadapter = MNULL;
226 TxPD *ptx_pd;
227 /* sizeof(TxPD) + Interface specific header */
228 #define NULL_PACKET_HDR 256
229 t_u32 data_len = NULL_PACKET_HDR;
230 pmlan_buffer pmbuf = MNULL;
231 t_u8 *ptr;
232 mlan_status ret = MLAN_STATUS_SUCCESS;
233 #ifdef DEBUG_LEVEL1
234 t_u32 sec = 0, usec = 0;
235 #endif
236
237 ENTER();
238
239 if (!priv) {
240 LEAVE();
241 return MLAN_STATUS_FAILURE;
242 }
243 pmadapter = priv->adapter;
244
245 if (pmadapter->surprise_removed == MTRUE) {
246 ret = MLAN_STATUS_FAILURE;
247 goto done;
248 }
249
250 if (priv->media_connected == MFALSE) {
251 ret = MLAN_STATUS_FAILURE;
252 goto done;
253 }
254
255 if (pmadapter->data_sent == MTRUE) {
256 ret = MLAN_STATUS_FAILURE;
257 goto done;
258 }
259
260 pmbuf = wlan_alloc_mlan_buffer(pmadapter, data_len, 0,
261 MOAL_MALLOC_BUFFER);
262 if (!pmbuf) {
263 ret = MLAN_STATUS_FAILURE;
264 goto done;
265 }
266 memset(pmadapter, pmbuf->pbuf, 0, data_len);
267 pmbuf->bss_index = priv->bss_index;
268 pmbuf->buf_type = MLAN_BUF_TYPE_DATA;
269 pmbuf->flags |= MLAN_BUF_FLAG_NULL_PKT;
270 ptr = pmbuf->pbuf + pmbuf->data_offset;
271 pmbuf->data_len = sizeof(TxPD) + priv->intf_hr_len;
272 ptx_pd = (TxPD *)(ptr + priv->intf_hr_len);
273 ptx_pd->tx_control = priv->pkt_tx_ctrl;
274 ptx_pd->flags = flags;
275 ptx_pd->priority = WMM_HIGHEST_PRIORITY;
276 ptx_pd->tx_pkt_offset = sizeof(TxPD);
277 /* Set the BSS number to TxPD */
278 ptx_pd->bss_num = GET_BSS_NUM(priv);
279 ptx_pd->bss_type = priv->bss_type;
280
281 endian_convert_TxPD(ptx_pd);
282
283 ret = pmadapter->ops.host_to_card(priv, MLAN_TYPE_DATA, pmbuf, MNULL);
284
285 switch (ret) {
286 #ifdef USB
287 case MLAN_STATUS_PRESOURCE:
288 PRINTM(MINFO, "MLAN_STATUS_PRESOURCE is returned\n");
289 break;
290 #endif
291 case MLAN_STATUS_RESOURCE:
292 wlan_free_mlan_buffer(pmadapter, pmbuf);
293 PRINTM(MERROR, "STA Tx Error: Failed to send NULL packet!\n");
294 pmadapter->dbg.num_tx_host_to_card_failure++;
295 goto done;
296 case MLAN_STATUS_FAILURE:
297 wlan_free_mlan_buffer(pmadapter, pmbuf);
298 PRINTM(MERROR, "STA Tx Error: Failed to send NULL packet!\n");
299 pmadapter->dbg.num_tx_host_to_card_failure++;
300 goto done;
301 case MLAN_STATUS_SUCCESS:
302 wlan_free_mlan_buffer(pmadapter, pmbuf);
303 PRINTM(MINFO, "STA Tx: Successfully send the NULL packet\n");
304 pmadapter->tx_lock_flag = MTRUE;
305 break;
306 case MLAN_STATUS_PENDING:
307 pmadapter->tx_lock_flag = MTRUE;
308 break;
309 default:
310 break;
311 }
312
313 PRINTM_GET_SYS_TIME(MDATA, &sec, &usec);
314 PRINTM_NETINTF(MDATA, priv);
315 PRINTM(MDATA, "%lu.%06lu : Null data => FW\n", sec, usec);
316 DBG_HEXDUMP(MDAT_D, "Null data", ptr, sizeof(TxPD) + priv->intf_hr_len);
317 done:
318 LEAVE();
319 return ret;
320 }
321
322 /**
323 * @brief This function checks if we need to send last packet indication.
324 *
325 * @param priv A pointer to mlan_private structure
326 *
327 * @return MTRUE or MFALSE
328 */
wlan_check_last_packet_indication(pmlan_private priv)329 t_u8 wlan_check_last_packet_indication(pmlan_private priv)
330 {
331 pmlan_adapter pmadapter = priv->adapter;
332 t_u8 ret = MFALSE;
333 t_u8 prop_ps = MTRUE;
334
335 ENTER();
336
337 if (!pmadapter->sleep_period.period) {
338 LEAVE();
339 return ret;
340 }
341 if (wlan_bypass_tx_list_empty(pmadapter) &&
342 wlan_wmm_lists_empty(pmadapter)) {
343 if (((priv->curr_bss_params.wmm_uapsd_enabled == MTRUE) &&
344 priv->wmm_qosinfo) ||
345 prop_ps)
346
347 ret = MTRUE;
348 }
349 if (ret && !pmadapter->cmd_sent && !pmadapter->curr_cmd &&
350 !wlan_is_cmd_pending(pmadapter)) {
351 pmadapter->delay_null_pkt = MFALSE;
352 ret = MTRUE;
353 } else {
354 ret = MFALSE;
355 pmadapter->delay_null_pkt = MTRUE;
356 }
357 LEAVE();
358 return ret;
359 }
360