xref: /linux/drivers/net/wireless/nxp/nxpwifi/11n_aggr.c (revision 91ec2035134982b98fab0609a9fd8480e8217dc1)
1*73b01e57SJeff Chen // SPDX-License-Identifier: GPL-2.0-only
2*73b01e57SJeff Chen /*
3*73b01e57SJeff Chen  * nxpwifi: 802.11n Aggregation
4*73b01e57SJeff Chen  *
5*73b01e57SJeff Chen  * Copyright 2011-2024 NXP
6*73b01e57SJeff Chen  */
7*73b01e57SJeff Chen 
8*73b01e57SJeff Chen #include "cfg.h"
9*73b01e57SJeff Chen #include "util.h"
10*73b01e57SJeff Chen #include "fw.h"
11*73b01e57SJeff Chen #include "main.h"
12*73b01e57SJeff Chen #include "wmm.h"
13*73b01e57SJeff Chen #include "11n.h"
14*73b01e57SJeff Chen #include "11n_aggr.h"
15*73b01e57SJeff Chen 
16*73b01e57SJeff Chen /*
17*73b01e57SJeff Chen  * Build an AMSDU subframe for aggregation, with fields
18*73b01e57SJeff Chen  * (DA | SA | Length | SNAP header | MSDU), and compute padding
19*73b01e57SJeff Chen  * to align the subframe to a 4-byte boundary.
20*73b01e57SJeff Chen  */
nxpwifi_11n_form_amsdu_pkt(struct sk_buff * skb_aggr,struct sk_buff * skb_src,int * pad)21*73b01e57SJeff Chen static int nxpwifi_11n_form_amsdu_pkt(struct sk_buff *skb_aggr,
22*73b01e57SJeff Chen 				      struct sk_buff *skb_src, int *pad)
23*73b01e57SJeff Chen 
24*73b01e57SJeff Chen {
25*73b01e57SJeff Chen 	int dt_offset;
26*73b01e57SJeff Chen 	struct rfc_1042_hdr snap = {
27*73b01e57SJeff Chen 		0xaa,		/* LLC DSAP */
28*73b01e57SJeff Chen 		0xaa,		/* LLC SSAP */
29*73b01e57SJeff Chen 		0x03,		/* LLC CTRL */
30*73b01e57SJeff Chen 		{0x00, 0x00, 0x00},	/* SNAP OUI */
31*73b01e57SJeff Chen 		0x0000		/* SNAP type */
32*73b01e57SJeff Chen 		/* This field will be overwritten later with ethertype */
33*73b01e57SJeff Chen 	};
34*73b01e57SJeff Chen 	struct tx_packet_hdr *tx_header;
35*73b01e57SJeff Chen 
36*73b01e57SJeff Chen 	tx_header = skb_put(skb_aggr, sizeof(*tx_header));
37*73b01e57SJeff Chen 
38*73b01e57SJeff Chen 	/* Copy DA and SA */
39*73b01e57SJeff Chen 	dt_offset = 2 * ETH_ALEN;
40*73b01e57SJeff Chen 	memcpy(&tx_header->eth803_hdr, skb_src->data, dt_offset);
41*73b01e57SJeff Chen 
42*73b01e57SJeff Chen 	/* Copy SNAP header */
43*73b01e57SJeff Chen 	snap.snap_type = ((struct ethhdr *)skb_src->data)->h_proto;
44*73b01e57SJeff Chen 
45*73b01e57SJeff Chen 	dt_offset += sizeof(__be16);
46*73b01e57SJeff Chen 
47*73b01e57SJeff Chen 	memcpy(&tx_header->rfc1042_hdr, &snap, sizeof(struct rfc_1042_hdr));
48*73b01e57SJeff Chen 
49*73b01e57SJeff Chen 	skb_pull(skb_src, dt_offset);
50*73b01e57SJeff Chen 
51*73b01e57SJeff Chen 	/* Update Length field */
52*73b01e57SJeff Chen 	tx_header->eth803_hdr.h_proto = htons(skb_src->len + LLC_SNAP_LEN);
53*73b01e57SJeff Chen 
54*73b01e57SJeff Chen 	/* Add payload */
55*73b01e57SJeff Chen 	skb_put_data(skb_aggr, skb_src->data, skb_src->len);
56*73b01e57SJeff Chen 
57*73b01e57SJeff Chen 	/* Add padding for new MSDU to start from 4 byte boundary */
58*73b01e57SJeff Chen 	*pad = (4 - ((unsigned long)skb_aggr->tail & 0x3)) % 4;
59*73b01e57SJeff Chen 
60*73b01e57SJeff Chen 	return skb_aggr->len + *pad;
61*73b01e57SJeff Chen }
62*73b01e57SJeff Chen 
63*73b01e57SJeff Chen /*
64*73b01e57SJeff Chen  * Adds TxPD to AMSDU header. Each AMSDU packet will contain one TxPD at the
65*73b01e57SJeff Chen  * beginning, followed by multiple AMSDU subframes
66*73b01e57SJeff Chen  */
67*73b01e57SJeff Chen static void
nxpwifi_11n_form_amsdu_txpd(struct nxpwifi_private * priv,struct sk_buff * skb)68*73b01e57SJeff Chen nxpwifi_11n_form_amsdu_txpd(struct nxpwifi_private *priv,
69*73b01e57SJeff Chen 			    struct sk_buff *skb)
70*73b01e57SJeff Chen {
71*73b01e57SJeff Chen 	struct txpd *local_tx_pd;
72*73b01e57SJeff Chen 
73*73b01e57SJeff Chen 	skb_push(skb, sizeof(*local_tx_pd));
74*73b01e57SJeff Chen 
75*73b01e57SJeff Chen 	local_tx_pd = (struct txpd *)skb->data;
76*73b01e57SJeff Chen 	memset(local_tx_pd, 0, sizeof(struct txpd));
77*73b01e57SJeff Chen 
78*73b01e57SJeff Chen 	/* Original priority has been overwritten */
79*73b01e57SJeff Chen 	local_tx_pd->priority = (u8)skb->priority;
80*73b01e57SJeff Chen 	local_tx_pd->pkt_delay_2ms =
81*73b01e57SJeff Chen 		nxpwifi_wmm_compute_drv_pkt_delay(priv, skb);
82*73b01e57SJeff Chen 	local_tx_pd->bss_num = priv->bss_num;
83*73b01e57SJeff Chen 	local_tx_pd->bss_type = priv->bss_type;
84*73b01e57SJeff Chen 	/* Always zero as the data is followed by struct txpd */
85*73b01e57SJeff Chen 	local_tx_pd->tx_pkt_offset = cpu_to_le16(sizeof(struct txpd));
86*73b01e57SJeff Chen 	local_tx_pd->tx_pkt_type = cpu_to_le16(PKT_TYPE_AMSDU);
87*73b01e57SJeff Chen 	local_tx_pd->tx_pkt_length = cpu_to_le16(skb->len -
88*73b01e57SJeff Chen 						 sizeof(*local_tx_pd));
89*73b01e57SJeff Chen 
90*73b01e57SJeff Chen 	if (local_tx_pd->tx_control == 0)
91*73b01e57SJeff Chen 		/* TxCtrl set by user or default */
92*73b01e57SJeff Chen 		local_tx_pd->tx_control = cpu_to_le32(priv->pkt_tx_ctrl);
93*73b01e57SJeff Chen 
94*73b01e57SJeff Chen 	if (GET_BSS_ROLE(priv) == NXPWIFI_BSS_ROLE_STA &&
95*73b01e57SJeff Chen 	    priv->adapter->pps_uapsd_mode) {
96*73b01e57SJeff Chen 		if (nxpwifi_check_last_packet_indication(priv)) {
97*73b01e57SJeff Chen 			priv->adapter->tx_lock_flag = true;
98*73b01e57SJeff Chen 			local_tx_pd->flags =
99*73b01e57SJeff Chen 				NXPWIFI_TxPD_POWER_MGMT_LAST_PACKET;
100*73b01e57SJeff Chen 		}
101*73b01e57SJeff Chen 	}
102*73b01e57SJeff Chen }
103*73b01e57SJeff Chen 
104*73b01e57SJeff Chen /*
105*73b01e57SJeff Chen  * Build an aggregated MSDU packet by encapsulating buffers from the RA
106*73b01e57SJeff Chen  * list as AMSDU subframes and concatenating them. A TxPD is prepended
107*73b01e57SJeff Chen  * before transmission to form the final AMSDU packet.
108*73b01e57SJeff Chen  */
109*73b01e57SJeff Chen int
nxpwifi_11n_aggregate_pkt(struct nxpwifi_private * priv,struct nxpwifi_ra_list_tbl * pra_list,int ptrindex)110*73b01e57SJeff Chen nxpwifi_11n_aggregate_pkt(struct nxpwifi_private *priv,
111*73b01e57SJeff Chen 			  struct nxpwifi_ra_list_tbl *pra_list,
112*73b01e57SJeff Chen 			  int ptrindex)
113*73b01e57SJeff Chen 			  __releases(&priv->wmm.ra_list_spinlock)
114*73b01e57SJeff Chen {
115*73b01e57SJeff Chen 	struct nxpwifi_adapter *adapter = priv->adapter;
116*73b01e57SJeff Chen 	struct sk_buff *skb_aggr, *skb_src;
117*73b01e57SJeff Chen 	struct nxpwifi_txinfo *tx_info_aggr, *tx_info_src;
118*73b01e57SJeff Chen 	int pad = 0, aggr_num = 0, ret;
119*73b01e57SJeff Chen 	struct nxpwifi_tx_param tx_param;
120*73b01e57SJeff Chen 	struct txpd *ptx_pd = NULL;
121*73b01e57SJeff Chen 	int headroom = adapter->intf_hdr_len;
122*73b01e57SJeff Chen 
123*73b01e57SJeff Chen 	skb_src = skb_peek(&pra_list->skb_head);
124*73b01e57SJeff Chen 	if (!skb_src) {
125*73b01e57SJeff Chen 		spin_unlock_bh(&priv->wmm.ra_list_spinlock);
126*73b01e57SJeff Chen 		return 0;
127*73b01e57SJeff Chen 	}
128*73b01e57SJeff Chen 
129*73b01e57SJeff Chen 	tx_info_src = NXPWIFI_SKB_TXCB(skb_src);
130*73b01e57SJeff Chen 	skb_aggr = nxpwifi_alloc_dma_align_buf(adapter->tx_buf_size,
131*73b01e57SJeff Chen 					       GFP_ATOMIC);
132*73b01e57SJeff Chen 	if (!skb_aggr) {
133*73b01e57SJeff Chen 		spin_unlock_bh(&priv->wmm.ra_list_spinlock);
134*73b01e57SJeff Chen 		return -ENOMEM;
135*73b01e57SJeff Chen 	}
136*73b01e57SJeff Chen 
137*73b01e57SJeff Chen 	/*
138*73b01e57SJeff Chen 	 * skb_aggr->data already 64 byte align, just reserve bus interface
139*73b01e57SJeff Chen 	 * header and txpd.
140*73b01e57SJeff Chen 	 */
141*73b01e57SJeff Chen 	skb_reserve(skb_aggr, headroom + sizeof(struct txpd));
142*73b01e57SJeff Chen 	tx_info_aggr =  NXPWIFI_SKB_TXCB(skb_aggr);
143*73b01e57SJeff Chen 
144*73b01e57SJeff Chen 	memset(tx_info_aggr, 0, sizeof(*tx_info_aggr));
145*73b01e57SJeff Chen 	tx_info_aggr->bss_type = tx_info_src->bss_type;
146*73b01e57SJeff Chen 	tx_info_aggr->bss_num = tx_info_src->bss_num;
147*73b01e57SJeff Chen 
148*73b01e57SJeff Chen 	tx_info_aggr->flags |= NXPWIFI_BUF_FLAG_AGGR_PKT;
149*73b01e57SJeff Chen 	skb_aggr->priority = skb_src->priority;
150*73b01e57SJeff Chen 	skb_aggr->tstamp = skb_src->tstamp;
151*73b01e57SJeff Chen 
152*73b01e57SJeff Chen 	do {
153*73b01e57SJeff Chen 		/* Check if AMSDU can accommodate this MSDU */
154*73b01e57SJeff Chen 		if ((skb_aggr->len + skb_src->len + LLC_SNAP_LEN) >
155*73b01e57SJeff Chen 		    adapter->tx_buf_size)
156*73b01e57SJeff Chen 			break;
157*73b01e57SJeff Chen 
158*73b01e57SJeff Chen 		skb_src = skb_dequeue(&pra_list->skb_head);
159*73b01e57SJeff Chen 		pra_list->total_pkt_count--;
160*73b01e57SJeff Chen 		atomic_dec(&priv->wmm.tx_pkts_queued);
161*73b01e57SJeff Chen 		aggr_num++;
162*73b01e57SJeff Chen 		spin_unlock_bh(&priv->wmm.ra_list_spinlock);
163*73b01e57SJeff Chen 		nxpwifi_11n_form_amsdu_pkt(skb_aggr, skb_src, &pad);
164*73b01e57SJeff Chen 
165*73b01e57SJeff Chen 		nxpwifi_write_data_complete(adapter, skb_src, 0, 0);
166*73b01e57SJeff Chen 
167*73b01e57SJeff Chen 		spin_lock_bh(&priv->wmm.ra_list_spinlock);
168*73b01e57SJeff Chen 
169*73b01e57SJeff Chen 		if (!nxpwifi_is_ralist_valid(priv, pra_list, ptrindex)) {
170*73b01e57SJeff Chen 			spin_unlock_bh(&priv->wmm.ra_list_spinlock);
171*73b01e57SJeff Chen 			return -ENOENT;
172*73b01e57SJeff Chen 		}
173*73b01e57SJeff Chen 
174*73b01e57SJeff Chen 		if (skb_tailroom(skb_aggr) < pad) {
175*73b01e57SJeff Chen 			pad = 0;
176*73b01e57SJeff Chen 			break;
177*73b01e57SJeff Chen 		}
178*73b01e57SJeff Chen 		skb_put(skb_aggr, pad);
179*73b01e57SJeff Chen 
180*73b01e57SJeff Chen 		skb_src = skb_peek(&pra_list->skb_head);
181*73b01e57SJeff Chen 
182*73b01e57SJeff Chen 	} while (skb_src);
183*73b01e57SJeff Chen 
184*73b01e57SJeff Chen 	spin_unlock_bh(&priv->wmm.ra_list_spinlock);
185*73b01e57SJeff Chen 
186*73b01e57SJeff Chen 	/* Last AMSDU packet does not need padding */
187*73b01e57SJeff Chen 	skb_trim(skb_aggr, skb_aggr->len - pad);
188*73b01e57SJeff Chen 
189*73b01e57SJeff Chen 	/* Form AMSDU */
190*73b01e57SJeff Chen 	nxpwifi_11n_form_amsdu_txpd(priv, skb_aggr);
191*73b01e57SJeff Chen 	if (GET_BSS_ROLE(priv) == NXPWIFI_BSS_ROLE_STA)
192*73b01e57SJeff Chen 		ptx_pd = (struct txpd *)skb_aggr->data;
193*73b01e57SJeff Chen 
194*73b01e57SJeff Chen 	skb_push(skb_aggr, headroom);
195*73b01e57SJeff Chen 	tx_info_aggr->aggr_num = aggr_num * 2;
196*73b01e57SJeff Chen 	if (adapter->data_sent || adapter->tx_lock_flag) {
197*73b01e57SJeff Chen 		atomic_add(aggr_num * 2, &adapter->tx_queued);
198*73b01e57SJeff Chen 		skb_queue_tail(&adapter->tx_data_q, skb_aggr);
199*73b01e57SJeff Chen 		return 0;
200*73b01e57SJeff Chen 	}
201*73b01e57SJeff Chen 
202*73b01e57SJeff Chen 	if (skb_src)
203*73b01e57SJeff Chen 		tx_param.next_pkt_len = skb_src->len + sizeof(struct txpd);
204*73b01e57SJeff Chen 	else
205*73b01e57SJeff Chen 		tx_param.next_pkt_len = 0;
206*73b01e57SJeff Chen 
207*73b01e57SJeff Chen 	ret = adapter->if_ops.host_to_card(adapter, NXPWIFI_TYPE_DATA,
208*73b01e57SJeff Chen 					   skb_aggr, &tx_param);
209*73b01e57SJeff Chen 
210*73b01e57SJeff Chen 	switch (ret) {
211*73b01e57SJeff Chen 	case -EBUSY:
212*73b01e57SJeff Chen 		spin_lock_bh(&priv->wmm.ra_list_spinlock);
213*73b01e57SJeff Chen 		if (!nxpwifi_is_ralist_valid(priv, pra_list, ptrindex)) {
214*73b01e57SJeff Chen 			spin_unlock_bh(&priv->wmm.ra_list_spinlock);
215*73b01e57SJeff Chen 			nxpwifi_write_data_complete(adapter, skb_aggr, 1, -1);
216*73b01e57SJeff Chen 			return -EINVAL;
217*73b01e57SJeff Chen 		}
218*73b01e57SJeff Chen 		if (GET_BSS_ROLE(priv) == NXPWIFI_BSS_ROLE_STA &&
219*73b01e57SJeff Chen 		    adapter->pps_uapsd_mode && adapter->tx_lock_flag) {
220*73b01e57SJeff Chen 			priv->adapter->tx_lock_flag = false;
221*73b01e57SJeff Chen 			if (ptx_pd)
222*73b01e57SJeff Chen 				ptx_pd->flags = 0;
223*73b01e57SJeff Chen 		}
224*73b01e57SJeff Chen 
225*73b01e57SJeff Chen 		skb_queue_tail(&pra_list->skb_head, skb_aggr);
226*73b01e57SJeff Chen 
227*73b01e57SJeff Chen 		pra_list->total_pkt_count++;
228*73b01e57SJeff Chen 
229*73b01e57SJeff Chen 		atomic_inc(&priv->wmm.tx_pkts_queued);
230*73b01e57SJeff Chen 
231*73b01e57SJeff Chen 		tx_info_aggr->flags |= NXPWIFI_BUF_FLAG_REQUEUED_PKT;
232*73b01e57SJeff Chen 		spin_unlock_bh(&priv->wmm.ra_list_spinlock);
233*73b01e57SJeff Chen 		nxpwifi_dbg(adapter, ERROR, "data: -EBUSY is returned\n");
234*73b01e57SJeff Chen 		break;
235*73b01e57SJeff Chen 	case -EINPROGRESS:
236*73b01e57SJeff Chen 		break;
237*73b01e57SJeff Chen 	case 0:
238*73b01e57SJeff Chen 		nxpwifi_write_data_complete(adapter, skb_aggr, 1, ret);
239*73b01e57SJeff Chen 		break;
240*73b01e57SJeff Chen 	default:
241*73b01e57SJeff Chen 		nxpwifi_dbg(adapter, ERROR, "%s: host_to_card failed: %#x\n",
242*73b01e57SJeff Chen 			    __func__, ret);
243*73b01e57SJeff Chen 		adapter->dbg.num_tx_host_to_card_failure++;
244*73b01e57SJeff Chen 		nxpwifi_write_data_complete(adapter, skb_aggr, 1, ret);
245*73b01e57SJeff Chen 		break;
246*73b01e57SJeff Chen 	}
247*73b01e57SJeff Chen 	if (ret != -EBUSY)
248*73b01e57SJeff Chen 		nxpwifi_rotate_priolists(priv, pra_list, ptrindex);
249*73b01e57SJeff Chen 
250*73b01e57SJeff Chen 	return 0;
251*73b01e57SJeff Chen }
252