xref: /OK3568_Linux_fs/kernel/drivers/net/wireless/nxp/mlan/mlan_sta_tx.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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