xref: /openbmc/linux/drivers/net/wireless/intel/iwlwifi/mvm/tx.c (revision fac59652993f075d57860769c99045b3ca18780d)
18e99ea8dSJohannes Berg // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
28e99ea8dSJohannes Berg /*
367e7b24aSJohannes Berg  * Copyright (C) 2012-2014, 2018-2024 Intel Corporation
48e99ea8dSJohannes Berg  * Copyright (C) 2013-2015 Intel Mobile Communications GmbH
58e99ea8dSJohannes Berg  * Copyright (C) 2016-2017 Intel Deutschland GmbH
68e99ea8dSJohannes Berg  */
7e705c121SKalle Valo #include <linux/ieee80211.h>
8e705c121SKalle Valo #include <linux/etherdevice.h>
9a3713f8bSEmmanuel Grumbach #include <linux/tcp.h>
10d457a0e3SEric Dumazet #include <net/gso.h>
11a6d5e32fSEmmanuel Grumbach #include <net/ip.h>
125e6a98dcSSara Sharon #include <net/ipv6.h>
13e705c121SKalle Valo 
14e705c121SKalle Valo #include "iwl-trans.h"
15e705c121SKalle Valo #include "iwl-eeprom-parse.h"
16e705c121SKalle Valo #include "mvm.h"
17e705c121SKalle Valo #include "sta.h"
18c7eca79dSAvraham Stern #include "time-sync.h"
19e705c121SKalle Valo 
20e705c121SKalle Valo static void
iwl_mvm_bar_check_trigger(struct iwl_mvm * mvm,const u8 * addr,u16 tid,u16 ssn)21e705c121SKalle Valo iwl_mvm_bar_check_trigger(struct iwl_mvm *mvm, const u8 *addr,
22e705c121SKalle Valo 			  u16 tid, u16 ssn)
23e705c121SKalle Valo {
24e705c121SKalle Valo 	struct iwl_fw_dbg_trigger_tlv *trig;
25e705c121SKalle Valo 	struct iwl_fw_dbg_trigger_ba *ba_trig;
26e705c121SKalle Valo 
276c042d75SSara Sharon 	trig = iwl_fw_dbg_trigger_on(&mvm->fwrt, NULL, FW_DBG_TRIGGER_BA);
286c042d75SSara Sharon 	if (!trig)
29e705c121SKalle Valo 		return;
30e705c121SKalle Valo 
31e705c121SKalle Valo 	ba_trig = (void *)trig->data;
32e705c121SKalle Valo 
33e705c121SKalle Valo 	if (!(le16_to_cpu(ba_trig->tx_bar) & BIT(tid)))
34e705c121SKalle Valo 		return;
35e705c121SKalle Valo 
367174beb6SJohannes Berg 	iwl_fw_dbg_collect_trig(&mvm->fwrt, trig,
37e705c121SKalle Valo 				"BAR sent to %pM, tid %d, ssn %d",
38e705c121SKalle Valo 				addr, tid, ssn);
39e705c121SKalle Valo }
40e705c121SKalle Valo 
415e6a98dcSSara Sharon #define OPT_HDR(type, skb, off) \
425e6a98dcSSara Sharon 	(type *)(skb_network_header(skb) + (off))
435e6a98dcSSara Sharon 
iwl_mvm_tx_csum(struct iwl_mvm * mvm,struct sk_buff * skb,struct ieee80211_tx_info * info,bool amsdu)44edcda51dSJohannes Berg static u32 iwl_mvm_tx_csum(struct iwl_mvm *mvm, struct sk_buff *skb,
45edcda51dSJohannes Berg 			   struct ieee80211_tx_info *info,
46edcda51dSJohannes Berg 			   bool amsdu)
475e6a98dcSSara Sharon {
480792df68SJohannes Berg 	struct ieee80211_hdr *hdr = (void *)skb->data;
49af8bfc7eSJohannes Berg 	u16 mh_len = ieee80211_hdrlen(hdr->frame_control);
50fbdacb30SJohannes Berg 	u16 offload_assist = 0;
515e6a98dcSSara Sharon #if IS_ENABLED(CONFIG_INET)
525e6a98dcSSara Sharon 	u8 protocol = 0;
535e6a98dcSSara Sharon 
5459fa61f3SEmmanuel Grumbach 	/* Do not compute checksum if already computed */
5559fa61f3SEmmanuel Grumbach 	if (skb->ip_summed != CHECKSUM_PARTIAL)
56b86dd74fSSara Sharon 		goto out;
575e6a98dcSSara Sharon 
585e6a98dcSSara Sharon 	/* We do not expect to be requested to csum stuff we do not support */
595e6a98dcSSara Sharon 	if (WARN_ONCE(!(mvm->hw->netdev_features & IWL_TX_CSUM_NETIF_FLAGS) ||
605e6a98dcSSara Sharon 		      (skb->protocol != htons(ETH_P_IP) &&
615e6a98dcSSara Sharon 		       skb->protocol != htons(ETH_P_IPV6)),
625e6a98dcSSara Sharon 		      "No support for requested checksum\n")) {
635e6a98dcSSara Sharon 		skb_checksum_help(skb);
64b86dd74fSSara Sharon 		goto out;
655e6a98dcSSara Sharon 	}
665e6a98dcSSara Sharon 
675e6a98dcSSara Sharon 	if (skb->protocol == htons(ETH_P_IP)) {
685e6a98dcSSara Sharon 		protocol = ip_hdr(skb)->protocol;
695e6a98dcSSara Sharon 	} else {
705e6a98dcSSara Sharon #if IS_ENABLED(CONFIG_IPV6)
715e6a98dcSSara Sharon 		struct ipv6hdr *ipv6h =
725e6a98dcSSara Sharon 			(struct ipv6hdr *)skb_network_header(skb);
735e6a98dcSSara Sharon 		unsigned int off = sizeof(*ipv6h);
745e6a98dcSSara Sharon 
755e6a98dcSSara Sharon 		protocol = ipv6h->nexthdr;
765e6a98dcSSara Sharon 		while (protocol != NEXTHDR_NONE && ipv6_ext_hdr(protocol)) {
77ecf51424SSara Sharon 			struct ipv6_opt_hdr *hp;
78ecf51424SSara Sharon 
795e6a98dcSSara Sharon 			/* only supported extension headers */
805e6a98dcSSara Sharon 			if (protocol != NEXTHDR_ROUTING &&
815e6a98dcSSara Sharon 			    protocol != NEXTHDR_HOP &&
82ecf51424SSara Sharon 			    protocol != NEXTHDR_DEST) {
835e6a98dcSSara Sharon 				skb_checksum_help(skb);
84b86dd74fSSara Sharon 				goto out;
855e6a98dcSSara Sharon 			}
865e6a98dcSSara Sharon 
87ecf51424SSara Sharon 			hp = OPT_HDR(struct ipv6_opt_hdr, skb, off);
885e6a98dcSSara Sharon 			protocol = hp->nexthdr;
895e6a98dcSSara Sharon 			off += ipv6_optlen(hp);
905e6a98dcSSara Sharon 		}
915e6a98dcSSara Sharon 		/* if we get here - protocol now should be TCP/UDP */
925e6a98dcSSara Sharon #endif
935e6a98dcSSara Sharon 	}
945e6a98dcSSara Sharon 
955e6a98dcSSara Sharon 	if (protocol != IPPROTO_TCP && protocol != IPPROTO_UDP) {
965e6a98dcSSara Sharon 		WARN_ON_ONCE(1);
975e6a98dcSSara Sharon 		skb_checksum_help(skb);
98b86dd74fSSara Sharon 		goto out;
995e6a98dcSSara Sharon 	}
1005e6a98dcSSara Sharon 
1015e6a98dcSSara Sharon 	/* enable L4 csum */
1025e6a98dcSSara Sharon 	offload_assist |= BIT(TX_CMD_OFFLD_L4_EN);
1035e6a98dcSSara Sharon 
1045e6a98dcSSara Sharon 	/*
1055e6a98dcSSara Sharon 	 * Set offset to IP header (snap).
1065e6a98dcSSara Sharon 	 * We don't support tunneling so no need to take care of inner header.
1075e6a98dcSSara Sharon 	 * Size is in words.
1085e6a98dcSSara Sharon 	 */
1095e6a98dcSSara Sharon 	offload_assist |= (4 << TX_CMD_OFFLD_IP_HDR);
1105e6a98dcSSara Sharon 
1115e6a98dcSSara Sharon 	/* Do IPv4 csum for AMSDU only (no IP csum for Ipv6) */
112fbdacb30SJohannes Berg 	if (skb->protocol == htons(ETH_P_IP) && amsdu) {
1135e6a98dcSSara Sharon 		ip_hdr(skb)->check = 0;
1145e6a98dcSSara Sharon 		offload_assist |= BIT(TX_CMD_OFFLD_L3_EN);
1155e6a98dcSSara Sharon 	}
1165e6a98dcSSara Sharon 
1175e6a98dcSSara Sharon 	/* reset UDP/TCP header csum */
1185e6a98dcSSara Sharon 	if (protocol == IPPROTO_TCP)
1195e6a98dcSSara Sharon 		tcp_hdr(skb)->check = 0;
1205e6a98dcSSara Sharon 	else
1215e6a98dcSSara Sharon 		udp_hdr(skb)->check = 0;
1225e6a98dcSSara Sharon 
123af8bfc7eSJohannes Berg out:
124af8bfc7eSJohannes Berg #endif
1253f25bb4bSEmmanuel Grumbach 	/*
1263f25bb4bSEmmanuel Grumbach 	 * mac header len should include IV, size is in words unless
1273f25bb4bSEmmanuel Grumbach 	 * the IV is added by the firmware like in WEP.
1283f25bb4bSEmmanuel Grumbach 	 * In new Tx API, the IV is always added by the firmware.
1293f25bb4bSEmmanuel Grumbach 	 */
1303f25bb4bSEmmanuel Grumbach 	if (!iwl_mvm_has_new_tx_api(mvm) && info->control.hw_key &&
1313f25bb4bSEmmanuel Grumbach 	    info->control.hw_key->cipher != WLAN_CIPHER_SUITE_WEP40 &&
1323f25bb4bSEmmanuel Grumbach 	    info->control.hw_key->cipher != WLAN_CIPHER_SUITE_WEP104)
1335e6a98dcSSara Sharon 		mh_len += info->control.hw_key->iv_len;
1345e6a98dcSSara Sharon 	mh_len /= 2;
1355e6a98dcSSara Sharon 	offload_assist |= mh_len << TX_CMD_OFFLD_MH_SIZE;
1365e6a98dcSSara Sharon 
137fbdacb30SJohannes Berg 	if (amsdu)
138fbdacb30SJohannes Berg 		offload_assist |= BIT(TX_CMD_OFFLD_AMSDU);
139fbdacb30SJohannes Berg 	else if (ieee80211_hdrlen(hdr->frame_control) % 4)
140fbdacb30SJohannes Berg 		/* padding is inserted later in transport */
141fbdacb30SJohannes Berg 		offload_assist |= BIT(TX_CMD_OFFLD_PAD);
142fbdacb30SJohannes Berg 
143b86dd74fSSara Sharon 	return offload_assist;
1445e6a98dcSSara Sharon }
1455e6a98dcSSara Sharon 
146e705c121SKalle Valo /*
147e705c121SKalle Valo  * Sets most of the Tx cmd's fields
148e705c121SKalle Valo  */
iwl_mvm_set_tx_cmd(struct iwl_mvm * mvm,struct sk_buff * skb,struct iwl_tx_cmd * tx_cmd,struct ieee80211_tx_info * info,u8 sta_id)149e705c121SKalle Valo void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb,
150e705c121SKalle Valo 			struct iwl_tx_cmd *tx_cmd,
151e705c121SKalle Valo 			struct ieee80211_tx_info *info, u8 sta_id)
152e705c121SKalle Valo {
153e705c121SKalle Valo 	struct ieee80211_hdr *hdr = (void *)skb->data;
154e705c121SKalle Valo 	__le16 fc = hdr->frame_control;
155e705c121SKalle Valo 	u32 tx_flags = le32_to_cpu(tx_cmd->tx_flags);
156e705c121SKalle Valo 	u32 len = skb->len + FCS_LEN;
157fbdacb30SJohannes Berg 	bool amsdu = false;
158e705c121SKalle Valo 	u8 ac;
159e705c121SKalle Valo 
1608c739d8dSIlan Peer 	if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) ||
1618c739d8dSIlan Peer 	    (ieee80211_is_probe_resp(fc) &&
1628c739d8dSIlan Peer 	     !is_multicast_ether_addr(hdr->addr1)))
163e705c121SKalle Valo 		tx_flags |= TX_CMD_FLG_ACK;
164e705c121SKalle Valo 	else
165e705c121SKalle Valo 		tx_flags &= ~TX_CMD_FLG_ACK;
166e705c121SKalle Valo 
167e705c121SKalle Valo 	if (ieee80211_is_probe_resp(fc))
168e705c121SKalle Valo 		tx_flags |= TX_CMD_FLG_TSF;
169e705c121SKalle Valo 
170e705c121SKalle Valo 	if (ieee80211_has_morefrags(fc))
171e705c121SKalle Valo 		tx_flags |= TX_CMD_FLG_MORE_FRAG;
172e705c121SKalle Valo 
173e705c121SKalle Valo 	if (ieee80211_is_data_qos(fc)) {
174e705c121SKalle Valo 		u8 *qc = ieee80211_get_qos_ctl(hdr);
175e705c121SKalle Valo 		tx_cmd->tid_tspec = qc[0] & 0xf;
176e705c121SKalle Valo 		tx_flags &= ~TX_CMD_FLG_SEQ_CTL;
177fbdacb30SJohannes Berg 		amsdu = *qc & IEEE80211_QOS_CTL_A_MSDU_PRESENT;
178e705c121SKalle Valo 	} else if (ieee80211_is_back_req(fc)) {
179e705c121SKalle Valo 		struct ieee80211_bar *bar = (void *)skb->data;
180e705c121SKalle Valo 		u16 control = le16_to_cpu(bar->control);
181e705c121SKalle Valo 		u16 ssn = le16_to_cpu(bar->start_seq_num);
182e705c121SKalle Valo 
183e705c121SKalle Valo 		tx_flags |= TX_CMD_FLG_ACK | TX_CMD_FLG_BAR;
184e705c121SKalle Valo 		tx_cmd->tid_tspec = (control &
185e705c121SKalle Valo 				     IEEE80211_BAR_CTRL_TID_INFO_MASK) >>
186e705c121SKalle Valo 			IEEE80211_BAR_CTRL_TID_INFO_SHIFT;
187e705c121SKalle Valo 		WARN_ON_ONCE(tx_cmd->tid_tspec >= IWL_MAX_TID_COUNT);
188e705c121SKalle Valo 		iwl_mvm_bar_check_trigger(mvm, bar->ra, tx_cmd->tid_tspec,
189e705c121SKalle Valo 					  ssn);
190e705c121SKalle Valo 	} else {
1912210f695SAvraham Stern 		if (ieee80211_is_data(fc))
192e705c121SKalle Valo 			tx_cmd->tid_tspec = IWL_TID_NON_QOS;
1932210f695SAvraham Stern 		else
1942210f695SAvraham Stern 			tx_cmd->tid_tspec = IWL_MAX_TID_COUNT;
1952210f695SAvraham Stern 
196e705c121SKalle Valo 		if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ)
197e705c121SKalle Valo 			tx_flags |= TX_CMD_FLG_SEQ_CTL;
198e705c121SKalle Valo 		else
199e705c121SKalle Valo 			tx_flags &= ~TX_CMD_FLG_SEQ_CTL;
200e705c121SKalle Valo 	}
201e705c121SKalle Valo 
2022210f695SAvraham Stern 	/* Default to 0 (BE) when tid_spec is set to IWL_MAX_TID_COUNT */
203e705c121SKalle Valo 	if (tx_cmd->tid_tspec < IWL_MAX_TID_COUNT)
204e705c121SKalle Valo 		ac = tid_to_mac80211_ac[tx_cmd->tid_tspec];
205e705c121SKalle Valo 	else
206e705c121SKalle Valo 		ac = tid_to_mac80211_ac[0];
207e705c121SKalle Valo 
208e705c121SKalle Valo 	tx_flags |= iwl_mvm_bt_coex_tx_prio(mvm, hdr, info, ac) <<
209e705c121SKalle Valo 			TX_CMD_FLG_BT_PRIO_POS;
210e705c121SKalle Valo 
211e705c121SKalle Valo 	if (ieee80211_is_mgmt(fc)) {
212e705c121SKalle Valo 		if (ieee80211_is_assoc_req(fc) || ieee80211_is_reassoc_req(fc))
213e705c121SKalle Valo 			tx_cmd->pm_frame_timeout = cpu_to_le16(PM_FRAME_ASSOC);
214e705c121SKalle Valo 		else if (ieee80211_is_action(fc))
215e705c121SKalle Valo 			tx_cmd->pm_frame_timeout = cpu_to_le16(PM_FRAME_NONE);
216e705c121SKalle Valo 		else
217e705c121SKalle Valo 			tx_cmd->pm_frame_timeout = cpu_to_le16(PM_FRAME_MGMT);
218e705c121SKalle Valo 
219e705c121SKalle Valo 		/* The spec allows Action frames in A-MPDU, we don't support
220e705c121SKalle Valo 		 * it
221e705c121SKalle Valo 		 */
222e705c121SKalle Valo 		WARN_ON_ONCE(info->flags & IEEE80211_TX_CTL_AMPDU);
223e705c121SKalle Valo 	} else if (info->control.flags & IEEE80211_TX_CTRL_PORT_CTRL_PROTO) {
224e705c121SKalle Valo 		tx_cmd->pm_frame_timeout = cpu_to_le16(PM_FRAME_MGMT);
225e705c121SKalle Valo 	} else {
226e705c121SKalle Valo 		tx_cmd->pm_frame_timeout = cpu_to_le16(PM_FRAME_NONE);
227e705c121SKalle Valo 	}
228e705c121SKalle Valo 
229e705c121SKalle Valo 	if (ieee80211_is_data(fc) && len > mvm->rts_threshold &&
230a371bb64SAndrei Otcheretianski 	    !is_multicast_ether_addr(hdr->addr1))
231e705c121SKalle Valo 		tx_flags |= TX_CMD_FLG_PROT_REQUIRE;
232e705c121SKalle Valo 
233e705c121SKalle Valo 	if (fw_has_capa(&mvm->fw->ucode_capa,
234e705c121SKalle Valo 			IWL_UCODE_TLV_CAPA_TXPOWER_INSERTION_SUPPORT) &&
235e705c121SKalle Valo 	    ieee80211_action_contains_tpc(skb))
236e705c121SKalle Valo 		tx_flags |= TX_CMD_FLG_WRITE_TX_POWER;
237e705c121SKalle Valo 
238e705c121SKalle Valo 	tx_cmd->tx_flags = cpu_to_le32(tx_flags);
23905e5a7e5SJohannes Berg 	/* Total # bytes to be transmitted - PCIe code will adjust for A-MSDU */
24005e5a7e5SJohannes Berg 	tx_cmd->len = cpu_to_le16((u16)skb->len);
241e705c121SKalle Valo 	tx_cmd->life_time = cpu_to_le32(TX_CMD_LIFE_TIME_INFINITE);
242e705c121SKalle Valo 	tx_cmd->sta_id = sta_id;
243d8fe4844SSara Sharon 
244fbdacb30SJohannes Berg 	tx_cmd->offload_assist =
245edcda51dSJohannes Berg 		cpu_to_le16(iwl_mvm_tx_csum(mvm, skb, info, amsdu));
246e705c121SKalle Valo }
247e705c121SKalle Valo 
iwl_mvm_get_tx_ant(struct iwl_mvm * mvm,struct ieee80211_tx_info * info,struct ieee80211_sta * sta,__le16 fc)2480dde2440SAvraham Stern static u32 iwl_mvm_get_tx_ant(struct iwl_mvm *mvm,
2490dde2440SAvraham Stern 			      struct ieee80211_tx_info *info,
2500dde2440SAvraham Stern 			      struct ieee80211_sta *sta, __le16 fc)
2510dde2440SAvraham Stern {
2520dde2440SAvraham Stern 	if (info->band == NL80211_BAND_2GHZ &&
2530dde2440SAvraham Stern 	    !iwl_mvm_bt_coex_is_shared_ant_avail(mvm))
2540dde2440SAvraham Stern 		return mvm->cfg->non_shared_ant << RATE_MCS_ANT_POS;
2550dde2440SAvraham Stern 
2560dde2440SAvraham Stern 	if (sta && ieee80211_is_data(fc)) {
2570dde2440SAvraham Stern 		struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
2580dde2440SAvraham Stern 
2590dde2440SAvraham Stern 		return BIT(mvmsta->tx_ant) << RATE_MCS_ANT_POS;
2600dde2440SAvraham Stern 	}
2610dde2440SAvraham Stern 
2620dde2440SAvraham Stern 	return BIT(mvm->mgmt_last_antenna_idx) << RATE_MCS_ANT_POS;
2630dde2440SAvraham Stern }
2640dde2440SAvraham Stern 
iwl_mvm_get_inject_tx_rate(struct iwl_mvm * mvm,struct ieee80211_tx_info * info)265f9f5cc86SJohannes Berg static u32 iwl_mvm_get_inject_tx_rate(struct iwl_mvm *mvm,
266f9f5cc86SJohannes Berg 				      struct ieee80211_tx_info *info)
267f9f5cc86SJohannes Berg {
268f9f5cc86SJohannes Berg 	struct ieee80211_tx_rate *rate = &info->control.rates[0];
269f9f5cc86SJohannes Berg 	u32 result;
270f9f5cc86SJohannes Berg 
271f9f5cc86SJohannes Berg 	/*
272f9f5cc86SJohannes Berg 	 * we only care about legacy/HT/VHT so far, so we can
273f9f5cc86SJohannes Berg 	 * build in v1 and use iwl_new_rate_from_v1()
274f9f5cc86SJohannes Berg 	 */
275f9f5cc86SJohannes Berg 
276f9f5cc86SJohannes Berg 	if (rate->flags & IEEE80211_TX_RC_VHT_MCS) {
277f9f5cc86SJohannes Berg 		u8 mcs = ieee80211_rate_get_vht_mcs(rate);
278f9f5cc86SJohannes Berg 		u8 nss = ieee80211_rate_get_vht_nss(rate);
279f9f5cc86SJohannes Berg 
280f9f5cc86SJohannes Berg 		result = RATE_MCS_VHT_MSK_V1;
281f9f5cc86SJohannes Berg 		result |= u32_encode_bits(mcs, RATE_VHT_MCS_RATE_CODE_MSK);
282f9f5cc86SJohannes Berg 		result |= u32_encode_bits(nss, RATE_MCS_NSS_MSK);
283f9f5cc86SJohannes Berg 		if (rate->flags & IEEE80211_TX_RC_SHORT_GI)
284f9f5cc86SJohannes Berg 			result |= RATE_MCS_SGI_MSK_V1;
285f9f5cc86SJohannes Berg 		if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
286f9f5cc86SJohannes Berg 			result |= u32_encode_bits(1, RATE_MCS_CHAN_WIDTH_MSK_V1);
287f9f5cc86SJohannes Berg 		else if (rate->flags & IEEE80211_TX_RC_80_MHZ_WIDTH)
288f9f5cc86SJohannes Berg 			result |= u32_encode_bits(2, RATE_MCS_CHAN_WIDTH_MSK_V1);
289f9f5cc86SJohannes Berg 		else if (rate->flags & IEEE80211_TX_RC_160_MHZ_WIDTH)
290f9f5cc86SJohannes Berg 			result |= u32_encode_bits(3, RATE_MCS_CHAN_WIDTH_MSK_V1);
291f9f5cc86SJohannes Berg 	} else if (rate->flags & IEEE80211_TX_RC_MCS) {
292f9f5cc86SJohannes Berg 		result = RATE_MCS_HT_MSK_V1;
293f9f5cc86SJohannes Berg 		result |= u32_encode_bits(rate->idx,
294f9f5cc86SJohannes Berg 					  RATE_HT_MCS_RATE_CODE_MSK_V1 |
295f9f5cc86SJohannes Berg 					  RATE_HT_MCS_NSS_MSK_V1);
296f9f5cc86SJohannes Berg 		if (rate->flags & IEEE80211_TX_RC_SHORT_GI)
297f9f5cc86SJohannes Berg 			result |= RATE_MCS_SGI_MSK_V1;
298f9f5cc86SJohannes Berg 		if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
299f9f5cc86SJohannes Berg 			result |= u32_encode_bits(1, RATE_MCS_CHAN_WIDTH_MSK_V1);
300cda2e9d7SMukesh Sisodiya 		if (info->flags & IEEE80211_TX_CTL_LDPC)
301f9f5cc86SJohannes Berg 			result |= RATE_MCS_LDPC_MSK_V1;
302cda2e9d7SMukesh Sisodiya 		if (u32_get_bits(info->flags, IEEE80211_TX_CTL_STBC))
303f9f5cc86SJohannes Berg 			result |= RATE_MCS_STBC_MSK;
304f9f5cc86SJohannes Berg 	} else {
305f9f5cc86SJohannes Berg 		return 0;
306f9f5cc86SJohannes Berg 	}
307f9f5cc86SJohannes Berg 
308f9f5cc86SJohannes Berg 	if (iwl_fw_lookup_notif_ver(mvm->fw, LONG_GROUP, TX_CMD, 0) > 6)
309f9f5cc86SJohannes Berg 		return iwl_new_rate_from_v1(result);
310f9f5cc86SJohannes Berg 	return result;
311f9f5cc86SJohannes Berg }
312f9f5cc86SJohannes Berg 
iwl_mvm_get_tx_rate(struct iwl_mvm * mvm,struct ieee80211_tx_info * info,struct ieee80211_sta * sta,__le16 fc)3135ec295dbSSara Sharon static u32 iwl_mvm_get_tx_rate(struct iwl_mvm *mvm,
3145ec295dbSSara Sharon 			       struct ieee80211_tx_info *info,
3156761a718SKrishnanand Prabhu 			       struct ieee80211_sta *sta, __le16 fc)
3165ec295dbSSara Sharon {
317004272bcSMordechay Goodstein 	int rate_idx = -1;
3185ec295dbSSara Sharon 	u8 rate_plcp;
3190dde2440SAvraham Stern 	u32 rate_flags = 0;
320d35d95ceSMiri Korenblit 	bool is_cck;
3215ec295dbSSara Sharon 
322f9f5cc86SJohannes Berg 	if (unlikely(info->control.flags & IEEE80211_TX_CTRL_RATE_INJECT)) {
323f9f5cc86SJohannes Berg 		u32 result = iwl_mvm_get_inject_tx_rate(mvm, info);
324f9f5cc86SJohannes Berg 
325f9f5cc86SJohannes Berg 		if (result)
326f9f5cc86SJohannes Berg 			return result;
327f9f5cc86SJohannes Berg 		rate_idx = info->control.rates[0].idx;
328f9f5cc86SJohannes Berg 	} else if (!ieee80211_hw_check(mvm->hw, HAS_RATE_CONTROL)) {
329004272bcSMordechay Goodstein 		/* info->control is only relevant for non HW rate control */
330f9f5cc86SJohannes Berg 
3315ec295dbSSara Sharon 		/* HT rate doesn't make sense for a non data frame */
3326761a718SKrishnanand Prabhu 		WARN_ONCE(info->control.rates[0].flags & IEEE80211_TX_RC_MCS &&
3336761a718SKrishnanand Prabhu 			  !ieee80211_is_data(fc),
3346761a718SKrishnanand Prabhu 			  "Got a HT rate (flags:0x%x/mcs:%d/fc:0x%x/state:%d) for a non data frame\n",
3355ec295dbSSara Sharon 			  info->control.rates[0].flags,
3366761a718SKrishnanand Prabhu 			  info->control.rates[0].idx,
33730d17c12STakashi Iwai 			  le16_to_cpu(fc),
33830d17c12STakashi Iwai 			  sta ? iwl_mvm_sta_from_mac80211(sta)->sta_state : -1);
3395ec295dbSSara Sharon 
3405ec295dbSSara Sharon 		rate_idx = info->control.rates[0].idx;
341004272bcSMordechay Goodstein 
3427f11d17fSIlan Peer 		/* For non 2 GHZ band, remap mac80211 rate indices into driver
3437f11d17fSIlan Peer 		 * indices.
344d558b7f8STova Mussai 		 */
3454e17e156SAvraham Stern 		if (info->band != NL80211_BAND_2GHZ ||
3464e17e156SAvraham Stern 		    (info->flags & IEEE80211_TX_CTL_NO_CCK_RATE))
3475ec295dbSSara Sharon 			rate_idx += IWL_FIRST_OFDM_RATE;
3485ec295dbSSara Sharon 
3495ec295dbSSara Sharon 		/* For 2.4 GHZ band, check that there is no need to remap */
3505ec295dbSSara Sharon 		BUILD_BUG_ON(IWL_FIRST_CCK_RATE != 0);
3517f11d17fSIlan Peer 	}
3527f11d17fSIlan Peer 
3537f11d17fSIlan Peer 	/* if the rate isn't a well known legacy rate, take the lowest one */
3547f11d17fSIlan Peer 	if (rate_idx < 0 || rate_idx >= IWL_RATE_COUNT_LEGACY)
3557f11d17fSIlan Peer 		rate_idx = iwl_mvm_mac_ctxt_get_lowest_rate(mvm,
3567f11d17fSIlan Peer 							    info,
3577f11d17fSIlan Peer 							    info->control.vif);
3585ec295dbSSara Sharon 
3595ec295dbSSara Sharon 	/* Get PLCP rate for tx_cmd->rate_n_flags */
360d35d95ceSMiri Korenblit 	rate_plcp = iwl_mvm_mac80211_idx_to_hwrate(mvm->fw, rate_idx);
361d35d95ceSMiri Korenblit 	is_cck = (rate_idx >= IWL_FIRST_CCK_RATE) && (rate_idx <= IWL_LAST_CCK_RATE);
3625ec295dbSSara Sharon 
363d35d95ceSMiri Korenblit 	/* Set CCK or OFDM flag */
364971cbe50SJohannes Berg 	if (iwl_fw_lookup_cmd_ver(mvm->fw, TX_CMD, 0) > 8) {
365d35d95ceSMiri Korenblit 		if (!is_cck)
366d35d95ceSMiri Korenblit 			rate_flags |= RATE_MCS_LEGACY_OFDM_MSK;
367d35d95ceSMiri Korenblit 		else
368d35d95ceSMiri Korenblit 			rate_flags |= RATE_MCS_CCK_MSK;
369d35d95ceSMiri Korenblit 	} else if (is_cck) {
37048c6ebc1SMiri Korenblit 		rate_flags |= RATE_MCS_CCK_MSK_V1;
371d35d95ceSMiri Korenblit 	}
3725ec295dbSSara Sharon 
3735ec295dbSSara Sharon 	return (u32)rate_plcp | rate_flags;
3745ec295dbSSara Sharon }
3755ec295dbSSara Sharon 
iwl_mvm_get_tx_rate_n_flags(struct iwl_mvm * mvm,struct ieee80211_tx_info * info,struct ieee80211_sta * sta,__le16 fc)3760dde2440SAvraham Stern static u32 iwl_mvm_get_tx_rate_n_flags(struct iwl_mvm *mvm,
3770dde2440SAvraham Stern 				       struct ieee80211_tx_info *info,
3780dde2440SAvraham Stern 				       struct ieee80211_sta *sta, __le16 fc)
3790dde2440SAvraham Stern {
3806761a718SKrishnanand Prabhu 	return iwl_mvm_get_tx_rate(mvm, info, sta, fc) |
3810dde2440SAvraham Stern 		iwl_mvm_get_tx_ant(mvm, info, sta, fc);
3820dde2440SAvraham Stern }
3830dde2440SAvraham Stern 
384e705c121SKalle Valo /*
385e705c121SKalle Valo  * Sets the fields in the Tx cmd that are rate related
386e705c121SKalle Valo  */
iwl_mvm_set_tx_cmd_rate(struct iwl_mvm * mvm,struct iwl_tx_cmd * tx_cmd,struct ieee80211_tx_info * info,struct ieee80211_sta * sta,__le16 fc)387e705c121SKalle Valo void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm, struct iwl_tx_cmd *tx_cmd,
388e705c121SKalle Valo 			    struct ieee80211_tx_info *info,
389e705c121SKalle Valo 			    struct ieee80211_sta *sta, __le16 fc)
390e705c121SKalle Valo {
391e705c121SKalle Valo 	/* Set retry limit on RTS packets */
392e705c121SKalle Valo 	tx_cmd->rts_retry_limit = IWL_RTS_DFAULT_RETRY_LIMIT;
393e705c121SKalle Valo 
394e705c121SKalle Valo 	/* Set retry limit on DATA packets and Probe Responses*/
395e705c121SKalle Valo 	if (ieee80211_is_probe_resp(fc)) {
396e705c121SKalle Valo 		tx_cmd->data_retry_limit = IWL_MGMT_DFAULT_RETRY_LIMIT;
397e705c121SKalle Valo 		tx_cmd->rts_retry_limit =
398e705c121SKalle Valo 			min(tx_cmd->data_retry_limit, tx_cmd->rts_retry_limit);
399e705c121SKalle Valo 	} else if (ieee80211_is_back_req(fc)) {
400e705c121SKalle Valo 		tx_cmd->data_retry_limit = IWL_BAR_DFAULT_RETRY_LIMIT;
401e705c121SKalle Valo 	} else {
402e705c121SKalle Valo 		tx_cmd->data_retry_limit = IWL_DEFAULT_TX_RETRY;
403e705c121SKalle Valo 	}
404e705c121SKalle Valo 
405e705c121SKalle Valo 	/*
406e705c121SKalle Valo 	 * for data packets, rate info comes from the table inside the fw. This
407e705c121SKalle Valo 	 * table is controlled by LINK_QUALITY commands
408e705c121SKalle Valo 	 */
409e705c121SKalle Valo 
410f9f5cc86SJohannes Berg 	if (likely(ieee80211_is_data(fc) && sta &&
411f9f5cc86SJohannes Berg 		   !(info->control.flags & IEEE80211_TX_CTRL_RATE_INJECT))) {
4120dde2440SAvraham Stern 		struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
4130dde2440SAvraham Stern 
4140dde2440SAvraham Stern 		if (mvmsta->sta_state >= IEEE80211_STA_AUTHORIZED) {
415e705c121SKalle Valo 			tx_cmd->initial_rate_index = 0;
416e705c121SKalle Valo 			tx_cmd->tx_flags |= cpu_to_le32(TX_CMD_FLG_STA_RATE);
417e705c121SKalle Valo 			return;
4180dde2440SAvraham Stern 		}
419e705c121SKalle Valo 	} else if (ieee80211_is_back_req(fc)) {
420e705c121SKalle Valo 		tx_cmd->tx_flags |=
421e705c121SKalle Valo 			cpu_to_le32(TX_CMD_FLG_ACK | TX_CMD_FLG_BAR);
422e705c121SKalle Valo 	}
423e705c121SKalle Valo 
424e705c121SKalle Valo 	/* Set the rate in the TX cmd */
4250dde2440SAvraham Stern 	tx_cmd->rate_n_flags =
4260dde2440SAvraham Stern 		cpu_to_le32(iwl_mvm_get_tx_rate_n_flags(mvm, info, sta, fc));
427e705c121SKalle Valo }
428e705c121SKalle Valo 
iwl_mvm_set_tx_cmd_pn(struct ieee80211_tx_info * info,u8 * crypto_hdr)4292a53d166SAyala Beker static inline void iwl_mvm_set_tx_cmd_pn(struct ieee80211_tx_info *info,
4302a53d166SAyala Beker 					 u8 *crypto_hdr)
4312a53d166SAyala Beker {
4322a53d166SAyala Beker 	struct ieee80211_key_conf *keyconf = info->control.hw_key;
4332a53d166SAyala Beker 	u64 pn;
4342a53d166SAyala Beker 
4352a53d166SAyala Beker 	pn = atomic64_inc_return(&keyconf->tx_pn);
4362a53d166SAyala Beker 	crypto_hdr[0] = pn;
4372a53d166SAyala Beker 	crypto_hdr[2] = 0;
4382a53d166SAyala Beker 	crypto_hdr[3] = 0x20 | (keyconf->keyidx << 6);
4392a53d166SAyala Beker 	crypto_hdr[1] = pn >> 8;
4402a53d166SAyala Beker 	crypto_hdr[4] = pn >> 16;
4412a53d166SAyala Beker 	crypto_hdr[5] = pn >> 24;
4422a53d166SAyala Beker 	crypto_hdr[6] = pn >> 32;
4432a53d166SAyala Beker 	crypto_hdr[7] = pn >> 40;
4442a53d166SAyala Beker }
4452a53d166SAyala Beker 
446e705c121SKalle Valo /*
447e705c121SKalle Valo  * Sets the fields in the Tx cmd that are crypto related
448e705c121SKalle Valo  */
iwl_mvm_set_tx_cmd_crypto(struct iwl_mvm * mvm,struct ieee80211_tx_info * info,struct iwl_tx_cmd * tx_cmd,struct sk_buff * skb_frag,int hdrlen)449e705c121SKalle Valo static void iwl_mvm_set_tx_cmd_crypto(struct iwl_mvm *mvm,
450e705c121SKalle Valo 				      struct ieee80211_tx_info *info,
451e705c121SKalle Valo 				      struct iwl_tx_cmd *tx_cmd,
452e705c121SKalle Valo 				      struct sk_buff *skb_frag,
453e705c121SKalle Valo 				      int hdrlen)
454e705c121SKalle Valo {
455e705c121SKalle Valo 	struct ieee80211_key_conf *keyconf = info->control.hw_key;
456e705c121SKalle Valo 	u8 *crypto_hdr = skb_frag->data + hdrlen;
457de04d4fbSSara Sharon 	enum iwl_tx_cmd_sec_ctrl type = TX_CMD_SEC_CCM;
458e705c121SKalle Valo 	u64 pn;
459e705c121SKalle Valo 
460e705c121SKalle Valo 	switch (keyconf->cipher) {
461e705c121SKalle Valo 	case WLAN_CIPHER_SUITE_CCMP:
462e705c121SKalle Valo 		iwl_mvm_set_tx_cmd_ccmp(info, tx_cmd);
4632a53d166SAyala Beker 		iwl_mvm_set_tx_cmd_pn(info, crypto_hdr);
464e705c121SKalle Valo 		break;
465e705c121SKalle Valo 
466e705c121SKalle Valo 	case WLAN_CIPHER_SUITE_TKIP:
467e705c121SKalle Valo 		tx_cmd->sec_ctl = TX_CMD_SEC_TKIP;
4681ad4f639SEliad Peller 		pn = atomic64_inc_return(&keyconf->tx_pn);
4691ad4f639SEliad Peller 		ieee80211_tkip_add_iv(crypto_hdr, keyconf, pn);
470e705c121SKalle Valo 		ieee80211_get_tkip_p2k(keyconf, skb_frag, tx_cmd->key);
471e705c121SKalle Valo 		break;
472e705c121SKalle Valo 
473e705c121SKalle Valo 	case WLAN_CIPHER_SUITE_WEP104:
474e705c121SKalle Valo 		tx_cmd->sec_ctl |= TX_CMD_SEC_KEY128;
4755a2abdcaSGustavo A. R. Silva 		fallthrough;
476e705c121SKalle Valo 	case WLAN_CIPHER_SUITE_WEP40:
477e705c121SKalle Valo 		tx_cmd->sec_ctl |= TX_CMD_SEC_WEP |
478e705c121SKalle Valo 			((keyconf->keyidx << TX_CMD_SEC_WEP_KEY_IDX_POS) &
479e705c121SKalle Valo 			  TX_CMD_SEC_WEP_KEY_IDX_MSK);
480e705c121SKalle Valo 
481e705c121SKalle Valo 		memcpy(&tx_cmd->key[3], keyconf->key, keyconf->keylen);
482e705c121SKalle Valo 		break;
4832a53d166SAyala Beker 	case WLAN_CIPHER_SUITE_GCMP:
4842a53d166SAyala Beker 	case WLAN_CIPHER_SUITE_GCMP_256:
485de04d4fbSSara Sharon 		type = TX_CMD_SEC_GCMP;
4865a2abdcaSGustavo A. R. Silva 		fallthrough;
487de04d4fbSSara Sharon 	case WLAN_CIPHER_SUITE_CCMP_256:
4882a53d166SAyala Beker 		/* TODO: Taking the key from the table might introduce a race
4892a53d166SAyala Beker 		 * when PTK rekeying is done, having an old packets with a PN
4902a53d166SAyala Beker 		 * based on the old key but the message encrypted with a new
4912a53d166SAyala Beker 		 * one.
4922a53d166SAyala Beker 		 * Need to handle this.
4932a53d166SAyala Beker 		 */
494de04d4fbSSara Sharon 		tx_cmd->sec_ctl |= type | TX_CMD_SEC_KEY_FROM_TABLE;
4952a53d166SAyala Beker 		tx_cmd->key[0] = keyconf->hw_key_idx;
4962a53d166SAyala Beker 		iwl_mvm_set_tx_cmd_pn(info, crypto_hdr);
4972a53d166SAyala Beker 		break;
498e705c121SKalle Valo 	default:
499e705c121SKalle Valo 		tx_cmd->sec_ctl |= TX_CMD_SEC_EXT;
500e705c121SKalle Valo 	}
501e705c121SKalle Valo }
502e705c121SKalle Valo 
iwl_mvm_copy_hdr(void * cmd,const void * hdr,int hdrlen,const u8 * addr3_override)503ae668e2eSDaniel Gabay static void iwl_mvm_copy_hdr(void *cmd, const void *hdr, int hdrlen,
504ae668e2eSDaniel Gabay 			     const u8 *addr3_override)
505ae668e2eSDaniel Gabay {
506ae668e2eSDaniel Gabay 	struct ieee80211_hdr *out_hdr = cmd;
507ae668e2eSDaniel Gabay 
508ae668e2eSDaniel Gabay 	memcpy(cmd, hdr, hdrlen);
509ae668e2eSDaniel Gabay 	if (addr3_override)
510ae668e2eSDaniel Gabay 		memcpy(out_hdr->addr3, addr3_override, ETH_ALEN);
511ae668e2eSDaniel Gabay }
512ae668e2eSDaniel Gabay 
513e705c121SKalle Valo /*
514e705c121SKalle Valo  * Allocates and sets the Tx cmd the driver data pointers in the skb
515e705c121SKalle Valo  */
516a89c72ffSJohannes Berg static struct iwl_device_tx_cmd *
iwl_mvm_set_tx_params(struct iwl_mvm * mvm,struct sk_buff * skb,struct ieee80211_tx_info * info,int hdrlen,struct ieee80211_sta * sta,u8 sta_id,const u8 * addr3_override)517e705c121SKalle Valo iwl_mvm_set_tx_params(struct iwl_mvm *mvm, struct sk_buff *skb,
5185c08b0f5SEmmanuel Grumbach 		      struct ieee80211_tx_info *info, int hdrlen,
519ae668e2eSDaniel Gabay 		      struct ieee80211_sta *sta, u8 sta_id,
520ae668e2eSDaniel Gabay 		      const u8 *addr3_override)
521e705c121SKalle Valo {
522e705c121SKalle Valo 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
523a89c72ffSJohannes Berg 	struct iwl_device_tx_cmd *dev_cmd;
524e705c121SKalle Valo 	struct iwl_tx_cmd *tx_cmd;
525e705c121SKalle Valo 
526e705c121SKalle Valo 	dev_cmd = iwl_trans_alloc_tx_cmd(mvm->trans);
527e705c121SKalle Valo 
528e705c121SKalle Valo 	if (unlikely(!dev_cmd))
529e705c121SKalle Valo 		return NULL;
530e705c121SKalle Valo 
531e705c121SKalle Valo 	dev_cmd->hdr.cmd = TX_CMD;
532c47de665SSara Sharon 
533c47de665SSara Sharon 	if (iwl_mvm_has_new_tx_api(mvm)) {
534a0ec0169SGolan Ben Ami 		u32 rate_n_flags = 0;
535a0ec0169SGolan Ben Ami 		u16 flags = 0;
5360dde2440SAvraham Stern 		struct iwl_mvm_sta *mvmsta = sta ?
5370dde2440SAvraham Stern 			iwl_mvm_sta_from_mac80211(sta) : NULL;
538fbdacb30SJohannes Berg 		bool amsdu = false;
539c47de665SSara Sharon 
540f5bd90b7SSara Sharon 		if (ieee80211_is_data_qos(hdr->frame_control)) {
541f5bd90b7SSara Sharon 			u8 *qc = ieee80211_get_qos_ctl(hdr);
542f5bd90b7SSara Sharon 
543fbdacb30SJohannes Berg 			amsdu = *qc & IEEE80211_QOS_CTL_A_MSDU_PRESENT;
544f5bd90b7SSara Sharon 		}
545f5bd90b7SSara Sharon 
546a0ec0169SGolan Ben Ami 		if (!info->control.hw_key)
547a0ec0169SGolan Ben Ami 			flags |= IWL_TX_FLAGS_ENCRYPT_DIS;
548a0ec0169SGolan Ben Ami 
5490dde2440SAvraham Stern 		/*
550a96ef1ffSMiri Korenblit 		 * For data and mgmt packets rate info comes from the fw. Only
551a96ef1ffSMiri Korenblit 		 * set rate/antenna for injected frames with fixed rate, or
552a96ef1ffSMiri Korenblit 		 * when no sta is given.
5530dde2440SAvraham Stern 		 */
554a96ef1ffSMiri Korenblit 		if (unlikely(!sta ||
555a96ef1ffSMiri Korenblit 			     info->control.flags & IEEE80211_TX_CTRL_RATE_INJECT)) {
556a0ec0169SGolan Ben Ami 			flags |= IWL_TX_FLAGS_CMD_RATE;
5570dde2440SAvraham Stern 			rate_n_flags =
5580dde2440SAvraham Stern 				iwl_mvm_get_tx_rate_n_flags(mvm, info, sta,
5590dde2440SAvraham Stern 							    hdr->frame_control);
560a96ef1ffSMiri Korenblit 		} else if (!ieee80211_is_data(hdr->frame_control) ||
561a96ef1ffSMiri Korenblit 			   mvmsta->sta_state < IEEE80211_STA_AUTHORIZED) {
562a96ef1ffSMiri Korenblit 			/* These are important frames */
563a96ef1ffSMiri Korenblit 			flags |= IWL_TX_FLAGS_HIGH_PRI;
564a0ec0169SGolan Ben Ami 		}
565a0ec0169SGolan Ben Ami 
566286ca8ebSLuca Coelho 		if (mvm->trans->trans_cfg->device_family >=
5673681021fSJohannes Berg 		    IWL_DEVICE_FAMILY_AX210) {
568a0ec0169SGolan Ben Ami 			struct iwl_tx_cmd_gen3 *cmd = (void *)dev_cmd->payload;
5690792df68SJohannes Berg 			u32 offload_assist = iwl_mvm_tx_csum(mvm, skb,
5700792df68SJohannes Berg 							     info, amsdu);
571a0ec0169SGolan Ben Ami 
572fbdacb30SJohannes Berg 			cmd->offload_assist = cpu_to_le32(offload_assist);
573a0ec0169SGolan Ben Ami 
574a0ec0169SGolan Ben Ami 			/* Total # bytes to be transmitted */
575a0ec0169SGolan Ben Ami 			cmd->len = cpu_to_le16((u16)skb->len);
576a0ec0169SGolan Ben Ami 
577a0ec0169SGolan Ben Ami 			/* Copy MAC header from skb into command buffer */
578ae668e2eSDaniel Gabay 			iwl_mvm_copy_hdr(cmd->hdr, hdr, hdrlen, addr3_override);
579a0ec0169SGolan Ben Ami 
580a0ec0169SGolan Ben Ami 			cmd->flags = cpu_to_le16(flags);
581a0ec0169SGolan Ben Ami 			cmd->rate_n_flags = cpu_to_le32(rate_n_flags);
582a0ec0169SGolan Ben Ami 		} else {
583a0ec0169SGolan Ben Ami 			struct iwl_tx_cmd_gen2 *cmd = (void *)dev_cmd->payload;
584edcda51dSJohannes Berg 			u16 offload_assist = iwl_mvm_tx_csum(mvm, skb,
585edcda51dSJohannes Berg 							     info, amsdu);
586a0ec0169SGolan Ben Ami 
587fbdacb30SJohannes Berg 			cmd->offload_assist = cpu_to_le16(offload_assist);
588c47de665SSara Sharon 
589c47de665SSara Sharon 			/* Total # bytes to be transmitted */
590c47de665SSara Sharon 			cmd->len = cpu_to_le16((u16)skb->len);
591c47de665SSara Sharon 
592c47de665SSara Sharon 			/* Copy MAC header from skb into command buffer */
593ae668e2eSDaniel Gabay 			iwl_mvm_copy_hdr(cmd->hdr, hdr, hdrlen, addr3_override);
594c47de665SSara Sharon 
595a0ec0169SGolan Ben Ami 			cmd->flags = cpu_to_le32(flags);
596a0ec0169SGolan Ben Ami 			cmd->rate_n_flags = cpu_to_le32(rate_n_flags);
597a0ec0169SGolan Ben Ami 		}
598c47de665SSara Sharon 		goto out;
599c47de665SSara Sharon 	}
600c47de665SSara Sharon 
601e705c121SKalle Valo 	tx_cmd = (struct iwl_tx_cmd *)dev_cmd->payload;
602e705c121SKalle Valo 
603e705c121SKalle Valo 	if (info->control.hw_key)
604e705c121SKalle Valo 		iwl_mvm_set_tx_cmd_crypto(mvm, info, tx_cmd, skb, hdrlen);
605e705c121SKalle Valo 
606e705c121SKalle Valo 	iwl_mvm_set_tx_cmd(mvm, skb, tx_cmd, info, sta_id);
607e705c121SKalle Valo 
608e705c121SKalle Valo 	iwl_mvm_set_tx_cmd_rate(mvm, tx_cmd, info, sta, hdr->frame_control);
609e705c121SKalle Valo 
610c47de665SSara Sharon 	/* Copy MAC header from skb into command buffer */
611ae668e2eSDaniel Gabay 	iwl_mvm_copy_hdr(tx_cmd->hdr, hdr, hdrlen, addr3_override);
612c47de665SSara Sharon 
613c47de665SSara Sharon out:
614bd05a5bdSJohannes Berg 	return dev_cmd;
615bd05a5bdSJohannes Berg }
616bd05a5bdSJohannes Berg 
iwl_mvm_skb_prepare_status(struct sk_buff * skb,struct iwl_device_tx_cmd * cmd)617bd05a5bdSJohannes Berg static void iwl_mvm_skb_prepare_status(struct sk_buff *skb,
618a89c72ffSJohannes Berg 				       struct iwl_device_tx_cmd *cmd)
619bd05a5bdSJohannes Berg {
620bd05a5bdSJohannes Berg 	struct ieee80211_tx_info *skb_info = IEEE80211_SKB_CB(skb);
621bd05a5bdSJohannes Berg 
6225c08b0f5SEmmanuel Grumbach 	memset(&skb_info->status, 0, sizeof(skb_info->status));
6235c08b0f5SEmmanuel Grumbach 	memset(skb_info->driver_data, 0, sizeof(skb_info->driver_data));
624e705c121SKalle Valo 
625bd05a5bdSJohannes Berg 	skb_info->driver_data[1] = cmd;
626e705c121SKalle Valo }
627e705c121SKalle Valo 
iwl_mvm_get_ctrl_vif_queue(struct iwl_mvm * mvm,struct iwl_mvm_vif_link_info * link,struct ieee80211_tx_info * info,struct sk_buff * skb)628de24f638SLiad Kaufman static int iwl_mvm_get_ctrl_vif_queue(struct iwl_mvm *mvm,
629f699f039SShaul Triebitz 				      struct iwl_mvm_vif_link_info *link,
630cfbc6c4cSSara Sharon 				      struct ieee80211_tx_info *info,
6312c9abe65SJohannes Berg 				      struct sk_buff *skb)
632de24f638SLiad Kaufman {
6332c9abe65SJohannes Berg 	struct ieee80211_hdr *hdr = (void *)skb->data;
634cfbc6c4cSSara Sharon 	__le16 fc = hdr->frame_control;
635b0129db4SJohannes Berg 
6363ee0f0e2SSara Sharon 	switch (info->control.vif->type) {
6373ee0f0e2SSara Sharon 	case NL80211_IFTYPE_AP:
6384d339989SLiad Kaufman 	case NL80211_IFTYPE_ADHOC:
6393ee0f0e2SSara Sharon 		/*
6400fe8bed6SAvraham Stern 		 * Non-bufferable frames use the broadcast station, thus they
6410fe8bed6SAvraham Stern 		 * use the probe queue.
642e6835942SJohannes Berg 		 * Also take care of the case where we send a deauth to a
643e6835942SJohannes Berg 		 * station that we don't have, or similarly an association
644e6835942SJohannes Berg 		 * response (with non-success status) for a station we can't
645e6835942SJohannes Berg 		 * accept.
64651da3d8bSJohannes Berg 		 * Also, disassociate frames might happen, particular with
64751da3d8bSJohannes Berg 		 * reason 7 ("Class 3 frame received from nonassociated STA").
6483ee0f0e2SSara Sharon 		 */
6490fe8bed6SAvraham Stern 		if (ieee80211_is_mgmt(fc) &&
6502c9abe65SJohannes Berg 		    (!ieee80211_is_bufferable_mmpdu(skb) ||
6510fe8bed6SAvraham Stern 		     ieee80211_is_deauth(fc) || ieee80211_is_disassoc(fc)))
652de50140bSJohannes Berg 			return link->mgmt_queue;
653cfbc6c4cSSara Sharon 
654cfbc6c4cSSara Sharon 		if (!ieee80211_has_order(fc) && !ieee80211_is_probe_req(fc) &&
655cfbc6c4cSSara Sharon 		    is_multicast_ether_addr(hdr->addr1))
656f699f039SShaul Triebitz 			return link->cab_queue;
6573ee0f0e2SSara Sharon 
6584d339989SLiad Kaufman 		WARN_ONCE(info->control.vif->type != NL80211_IFTYPE_ADHOC,
6594d339989SLiad Kaufman 			  "fc=0x%02x", le16_to_cpu(fc));
660de50140bSJohannes Berg 		return link->mgmt_queue;
6613ee0f0e2SSara Sharon 	case NL80211_IFTYPE_P2P_DEVICE:
6623ee0f0e2SSara Sharon 		if (ieee80211_is_mgmt(fc))
66349f71713SSara Sharon 			return mvm->p2p_dev_queue;
6643ee0f0e2SSara Sharon 
6653ee0f0e2SSara Sharon 		WARN_ON_ONCE(1);
66649f71713SSara Sharon 		return mvm->p2p_dev_queue;
6673ee0f0e2SSara Sharon 	default:
6683ee0f0e2SSara Sharon 		WARN_ONCE(1, "Not a ctrl vif, no available queue\n");
6693ee0f0e2SSara Sharon 		return -1;
6703ee0f0e2SSara Sharon 	}
671de24f638SLiad Kaufman }
672de24f638SLiad Kaufman 
iwl_mvm_probe_resp_set_noa(struct iwl_mvm * mvm,struct sk_buff * skb)67386e177d8SGregory Greenman static void iwl_mvm_probe_resp_set_noa(struct iwl_mvm *mvm,
67486e177d8SGregory Greenman 				       struct sk_buff *skb)
67586e177d8SGregory Greenman {
67686e177d8SGregory Greenman 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
67786e177d8SGregory Greenman 	struct iwl_mvm_vif *mvmvif =
67886e177d8SGregory Greenman 		iwl_mvm_vif_from_mac80211(info->control.vif);
67986e177d8SGregory Greenman 	struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
68086e177d8SGregory Greenman 	int base_len = (u8 *)mgmt->u.probe_resp.variable - (u8 *)mgmt;
68186e177d8SGregory Greenman 	struct iwl_probe_resp_data *resp_data;
68273c289baSBjoern A. Zeeb 	const u8 *ie;
68373c289baSBjoern A. Zeeb 	u8 *pos;
68486e177d8SGregory Greenman 	u8 match[] = {
68586e177d8SGregory Greenman 		(WLAN_OUI_WFA >> 16) & 0xff,
68686e177d8SGregory Greenman 		(WLAN_OUI_WFA >> 8) & 0xff,
68786e177d8SGregory Greenman 		WLAN_OUI_WFA & 0xff,
68886e177d8SGregory Greenman 		WLAN_OUI_TYPE_WFA_P2P,
68986e177d8SGregory Greenman 	};
69086e177d8SGregory Greenman 
69186e177d8SGregory Greenman 	rcu_read_lock();
69286e177d8SGregory Greenman 
693650cadb7SGregory Greenman 	resp_data = rcu_dereference(mvmvif->deflink.probe_resp_data);
69486e177d8SGregory Greenman 	if (!resp_data)
69586e177d8SGregory Greenman 		goto out;
69686e177d8SGregory Greenman 
69786e177d8SGregory Greenman 	if (!resp_data->notif.noa_active)
69886e177d8SGregory Greenman 		goto out;
69986e177d8SGregory Greenman 
70073c289baSBjoern A. Zeeb 	ie = cfg80211_find_ie_match(WLAN_EID_VENDOR_SPECIFIC,
70186e177d8SGregory Greenman 				    mgmt->u.probe_resp.variable,
70286e177d8SGregory Greenman 				    skb->len - base_len,
70386e177d8SGregory Greenman 				    match, 4, 2);
70486e177d8SGregory Greenman 	if (!ie) {
70586e177d8SGregory Greenman 		IWL_DEBUG_TX(mvm, "probe resp doesn't have P2P IE\n");
70686e177d8SGregory Greenman 		goto out;
70786e177d8SGregory Greenman 	}
70886e177d8SGregory Greenman 
70986e177d8SGregory Greenman 	if (skb_tailroom(skb) < resp_data->noa_len) {
71086e177d8SGregory Greenman 		if (pskb_expand_head(skb, 0, resp_data->noa_len, GFP_ATOMIC)) {
71186e177d8SGregory Greenman 			IWL_ERR(mvm,
71286e177d8SGregory Greenman 				"Failed to reallocate probe resp\n");
71386e177d8SGregory Greenman 			goto out;
71486e177d8SGregory Greenman 		}
71586e177d8SGregory Greenman 	}
71686e177d8SGregory Greenman 
71786e177d8SGregory Greenman 	pos = skb_put(skb, resp_data->noa_len);
71886e177d8SGregory Greenman 
71986e177d8SGregory Greenman 	*pos++ = WLAN_EID_VENDOR_SPECIFIC;
72086e177d8SGregory Greenman 	/* Set length of IE body (not including ID and length itself) */
72186e177d8SGregory Greenman 	*pos++ = resp_data->noa_len - 2;
72286e177d8SGregory Greenman 	*pos++ = (WLAN_OUI_WFA >> 16) & 0xff;
72386e177d8SGregory Greenman 	*pos++ = (WLAN_OUI_WFA >> 8) & 0xff;
72486e177d8SGregory Greenman 	*pos++ = WLAN_OUI_WFA & 0xff;
72586e177d8SGregory Greenman 	*pos++ = WLAN_OUI_TYPE_WFA_P2P;
72686e177d8SGregory Greenman 
72786e177d8SGregory Greenman 	memcpy(pos, &resp_data->notif.noa_attr,
72886e177d8SGregory Greenman 	       resp_data->noa_len - sizeof(struct ieee80211_vendor_ie));
72986e177d8SGregory Greenman 
73086e177d8SGregory Greenman out:
73186e177d8SGregory Greenman 	rcu_read_unlock();
73286e177d8SGregory Greenman }
73386e177d8SGregory Greenman 
iwl_mvm_tx_skb_non_sta(struct iwl_mvm * mvm,struct sk_buff * skb)734e705c121SKalle Valo int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb)
735e705c121SKalle Valo {
736e705c121SKalle Valo 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
7375c08b0f5SEmmanuel Grumbach 	struct ieee80211_tx_info info;
738a89c72ffSJohannes Berg 	struct iwl_device_tx_cmd *dev_cmd;
739e705c121SKalle Valo 	u8 sta_id;
740e705c121SKalle Valo 	int hdrlen = ieee80211_hdrlen(hdr->frame_control);
74186e177d8SGregory Greenman 	__le16 fc = hdr->frame_control;
742cfbc6c4cSSara Sharon 	bool offchannel = IEEE80211_SKB_CB(skb)->flags &
743cfbc6c4cSSara Sharon 		IEEE80211_TX_CTL_TX_OFFCHAN;
7444120e4a1SSara Sharon 	int queue = -1;
74554c5ef2eSBeni Lev 
74650386305SSara Sharon 	if (IWL_MVM_NON_TRANSMITTING_AP && ieee80211_is_probe_resp(fc))
74750386305SSara Sharon 		return -1;
74850386305SSara Sharon 
7495c08b0f5SEmmanuel Grumbach 	memcpy(&info, skb->cb, sizeof(info));
7505c08b0f5SEmmanuel Grumbach 
751ac70499eSAndrei Otcheretianski 	if (WARN_ON_ONCE(skb->len > IEEE80211_MAX_DATA_LEN + hdrlen))
752ac70499eSAndrei Otcheretianski 		return -1;
753ac70499eSAndrei Otcheretianski 
7545c08b0f5SEmmanuel Grumbach 	if (WARN_ON_ONCE(info.flags & IEEE80211_TX_CTL_AMPDU))
755e705c121SKalle Valo 		return -1;
756e705c121SKalle Valo 
7575c08b0f5SEmmanuel Grumbach 	if (info.control.vif) {
758e705c121SKalle Valo 		struct iwl_mvm_vif *mvmvif =
7595c08b0f5SEmmanuel Grumbach 			iwl_mvm_vif_from_mac80211(info.control.vif);
760e705c121SKalle Valo 
7615c08b0f5SEmmanuel Grumbach 		if (info.control.vif->type == NL80211_IFTYPE_P2P_DEVICE ||
7624d339989SLiad Kaufman 		    info.control.vif->type == NL80211_IFTYPE_AP ||
7634d339989SLiad Kaufman 		    info.control.vif->type == NL80211_IFTYPE_ADHOC) {
7646e3ac426SShaul Triebitz 			u32 link_id = u32_get_bits(info.control.flags,
7656e3ac426SShaul Triebitz 						   IEEE80211_TX_CTRL_MLO_LINK);
7666e3ac426SShaul Triebitz 			struct iwl_mvm_vif_link_info *link;
7676e3ac426SShaul Triebitz 
7686e3ac426SShaul Triebitz 			if (link_id == IEEE80211_LINK_UNSPECIFIED) {
7696e3ac426SShaul Triebitz 				if (info.control.vif->active_links)
7706e3ac426SShaul Triebitz 					link_id = ffs(info.control.vif->active_links) - 1;
7717c305de2SIlan Peer 				else
7726e3ac426SShaul Triebitz 					link_id = 0;
7736e3ac426SShaul Triebitz 			}
7746e3ac426SShaul Triebitz 
7756e3ac426SShaul Triebitz 			link = mvmvif->link[link_id];
776df6791e7SJohannes Berg 			if (WARN_ON(!link))
777df6791e7SJohannes Berg 				return -1;
7786e3ac426SShaul Triebitz 
7796e3ac426SShaul Triebitz 			if (!ieee80211_is_data(hdr->frame_control))
7806e3ac426SShaul Triebitz 				sta_id = link->bcast_sta.sta_id;
7816e3ac426SShaul Triebitz 			else
7826e3ac426SShaul Triebitz 				sta_id = link->mcast_sta.sta_id;
7837c305de2SIlan Peer 
784f699f039SShaul Triebitz 			queue = iwl_mvm_get_ctrl_vif_queue(mvm, link, &info,
7852c9abe65SJohannes Berg 							   skb);
786c8f54701SJohannes Berg 		} else if (info.control.vif->type == NL80211_IFTYPE_MONITOR) {
787b13f43a4SEmmanuel Grumbach 			queue = mvm->snif_queue;
788b13f43a4SEmmanuel Grumbach 			sta_id = mvm->snif_sta.sta_id;
7894120e4a1SSara Sharon 		} else if (info.control.vif->type == NL80211_IFTYPE_STATION &&
790cfbc6c4cSSara Sharon 			   offchannel) {
7914120e4a1SSara Sharon 			/*
7924120e4a1SSara Sharon 			 * IWL_MVM_OFFCHANNEL_QUEUE is used for ROC packets
7934120e4a1SSara Sharon 			 * that can be used in 2 different types of vifs, P2P &
7944120e4a1SSara Sharon 			 * STATION.
7954120e4a1SSara Sharon 			 * P2P uses the offchannel queue.
7964120e4a1SSara Sharon 			 * STATION (HS2.0) uses the auxiliary context of the FW,
7974120e4a1SSara Sharon 			 * and hence needs to be sent on the aux queue.
7984120e4a1SSara Sharon 			 */
7994120e4a1SSara Sharon 			sta_id = mvm->aux_sta.sta_id;
8004120e4a1SSara Sharon 			queue = mvm->aux_queue;
801e705c121SKalle Valo 		}
802e705c121SKalle Valo 	}
803e705c121SKalle Valo 
804cfbc6c4cSSara Sharon 	if (queue < 0) {
805cfbc6c4cSSara Sharon 		IWL_ERR(mvm, "No queue was found. Dropping TX\n");
8064120e4a1SSara Sharon 		return -1;
807cfbc6c4cSSara Sharon 	}
8084120e4a1SSara Sharon 
80986e177d8SGregory Greenman 	if (unlikely(ieee80211_is_probe_resp(fc)))
81086e177d8SGregory Greenman 		iwl_mvm_probe_resp_set_noa(mvm, skb);
81186e177d8SGregory Greenman 
812de24f638SLiad Kaufman 	IWL_DEBUG_TX(mvm, "station Id %d, queue=%d\n", sta_id, queue);
813e705c121SKalle Valo 
814ae668e2eSDaniel Gabay 	dev_cmd = iwl_mvm_set_tx_params(mvm, skb, &info, hdrlen, NULL, sta_id,
815ae668e2eSDaniel Gabay 					NULL);
816e705c121SKalle Valo 	if (!dev_cmd)
817e705c121SKalle Valo 		return -1;
818e705c121SKalle Valo 
819bd05a5bdSJohannes Berg 	/* From now on, we cannot access info->control */
820bd05a5bdSJohannes Berg 	iwl_mvm_skb_prepare_status(skb, dev_cmd);
821bd05a5bdSJohannes Berg 
822de24f638SLiad Kaufman 	if (iwl_trans_tx(mvm->trans, skb, dev_cmd, queue)) {
823e705c121SKalle Valo 		iwl_trans_free_tx_cmd(mvm->trans, dev_cmd);
824e705c121SKalle Valo 		return -1;
825e705c121SKalle Valo 	}
826e705c121SKalle Valo 
827e705c121SKalle Valo 	return 0;
828e705c121SKalle Valo }
829e705c121SKalle Valo 
iwl_mvm_max_amsdu_size(struct iwl_mvm * mvm,struct ieee80211_sta * sta,unsigned int tid)830438af969SSara Sharon unsigned int iwl_mvm_max_amsdu_size(struct iwl_mvm *mvm,
831438af969SSara Sharon 				    struct ieee80211_sta *sta, unsigned int tid)
8327126b6f2SSara Sharon {
8337126b6f2SSara Sharon 	struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
8347126b6f2SSara Sharon 	u8 ac = tid_to_mac80211_ac[tid];
835b2bc600cSJohannes Berg 	enum nl80211_band band;
8367126b6f2SSara Sharon 	unsigned int txf;
837b2bc600cSJohannes Berg 	unsigned int val;
838b2bc600cSJohannes Berg 	int lmac;
8397126b6f2SSara Sharon 
8407126b6f2SSara Sharon 	/* For HE redirect to trigger based fifos */
841046d2e7cSSriram R 	if (sta->deflink.he_cap.has_he && !WARN_ON(!iwl_mvm_has_new_tx_api(mvm)))
8427126b6f2SSara Sharon 		ac += 4;
8437126b6f2SSara Sharon 
8447126b6f2SSara Sharon 	txf = iwl_mvm_mac_ac_to_tx_fifo(mvm, ac);
8457126b6f2SSara Sharon 
8467126b6f2SSara Sharon 	/*
8477126b6f2SSara Sharon 	 * Don't send an AMSDU that will be longer than the TXF.
8487126b6f2SSara Sharon 	 * Add a security margin of 256 for the TX command + headers.
8497126b6f2SSara Sharon 	 * We also want to have the start of the next packet inside the
8507126b6f2SSara Sharon 	 * fifo to be able to send bursts.
8517126b6f2SSara Sharon 	 */
852b2bc600cSJohannes Berg 	val = mvmsta->max_amsdu_len;
853b2bc600cSJohannes Berg 
854b2bc600cSJohannes Berg 	if (hweight16(sta->valid_links) <= 1) {
855b2bc600cSJohannes Berg 		if (sta->valid_links) {
856b2bc600cSJohannes Berg 			struct ieee80211_bss_conf *link_conf;
857b2bc600cSJohannes Berg 			unsigned int link = ffs(sta->valid_links) - 1;
858b2bc600cSJohannes Berg 
859b2bc600cSJohannes Berg 			rcu_read_lock();
860b2bc600cSJohannes Berg 			link_conf = rcu_dereference(mvmsta->vif->link_conf[link]);
861b2bc600cSJohannes Berg 			if (WARN_ON(!link_conf))
862b2bc600cSJohannes Berg 				band = NL80211_BAND_2GHZ;
863b2bc600cSJohannes Berg 			else
864b2bc600cSJohannes Berg 				band = link_conf->chandef.chan->band;
865b2bc600cSJohannes Berg 			rcu_read_unlock();
866b2bc600cSJohannes Berg 		} else {
867b2bc600cSJohannes Berg 			band = mvmsta->vif->bss_conf.chandef.chan->band;
868b2bc600cSJohannes Berg 		}
869b2bc600cSJohannes Berg 
870d51439a6SAriel Malamud 		lmac = iwl_mvm_get_lmac_id(mvm, band);
871b2bc600cSJohannes Berg 	} else if (fw_has_capa(&mvm->fw->ucode_capa,
872b2bc600cSJohannes Berg 			       IWL_UCODE_TLV_CAPA_CDB_SUPPORT)) {
873b2bc600cSJohannes Berg 		/* for real MLO restrict to both LMACs if they exist */
874b2bc600cSJohannes Berg 		lmac = IWL_LMAC_5G_INDEX;
875b2bc600cSJohannes Berg 		val = min_t(unsigned int, val,
876b2bc600cSJohannes Berg 			    mvm->fwrt.smem_cfg.lmac[lmac].txfifo_size[txf] - 256);
877b2bc600cSJohannes Berg 		lmac = IWL_LMAC_24G_INDEX;
878b2bc600cSJohannes Berg 	} else {
879b2bc600cSJohannes Berg 		lmac = IWL_LMAC_24G_INDEX;
880b2bc600cSJohannes Berg 	}
881b2bc600cSJohannes Berg 
882b2bc600cSJohannes Berg 	return min_t(unsigned int, val,
8837126b6f2SSara Sharon 		     mvm->fwrt.smem_cfg.lmac[lmac].txfifo_size[txf] - 256);
8847126b6f2SSara Sharon }
8857126b6f2SSara Sharon 
88608f7d8b6SSara Sharon #ifdef CONFIG_INET
88708f7d8b6SSara Sharon 
88808f7d8b6SSara Sharon static int
iwl_mvm_tx_tso_segment(struct sk_buff * skb,unsigned int num_subframes,netdev_features_t netdev_flags,struct sk_buff_head * mpdus_skb)88908f7d8b6SSara Sharon iwl_mvm_tx_tso_segment(struct sk_buff *skb, unsigned int num_subframes,
89008f7d8b6SSara Sharon 		       netdev_features_t netdev_flags,
89108f7d8b6SSara Sharon 		       struct sk_buff_head *mpdus_skb)
89208f7d8b6SSara Sharon {
89308f7d8b6SSara Sharon 	struct sk_buff *tmp, *next;
89408f7d8b6SSara Sharon 	struct ieee80211_hdr *hdr = (void *)skb->data;
89508f7d8b6SSara Sharon 	char cb[sizeof(skb->cb)];
89608f7d8b6SSara Sharon 	u16 i = 0;
89708f7d8b6SSara Sharon 	unsigned int tcp_payload_len;
89808f7d8b6SSara Sharon 	unsigned int mss = skb_shinfo(skb)->gso_size;
89908f7d8b6SSara Sharon 	bool ipv4 = (skb->protocol == htons(ETH_P_IP));
90071b256f8SEmmanuel Grumbach 	bool qos = ieee80211_is_data_qos(hdr->frame_control);
90108f7d8b6SSara Sharon 	u16 ip_base_id = ipv4 ? ntohs(ip_hdr(skb)->id) : 0;
90208f7d8b6SSara Sharon 
90308f7d8b6SSara Sharon 	skb_shinfo(skb)->gso_size = num_subframes * mss;
90408f7d8b6SSara Sharon 	memcpy(cb, skb->cb, sizeof(cb));
90508f7d8b6SSara Sharon 
90608f7d8b6SSara Sharon 	next = skb_gso_segment(skb, netdev_flags);
90708f7d8b6SSara Sharon 	skb_shinfo(skb)->gso_size = mss;
90881a86e1bSEric Dumazet 	skb_shinfo(skb)->gso_type = ipv4 ? SKB_GSO_TCPV4 : SKB_GSO_TCPV6;
90908f7d8b6SSara Sharon 	if (WARN_ON_ONCE(IS_ERR(next)))
91008f7d8b6SSara Sharon 		return -EINVAL;
91108f7d8b6SSara Sharon 	else if (next)
91208f7d8b6SSara Sharon 		consume_skb(skb);
91308f7d8b6SSara Sharon 
91466de4b17SJason A. Donenfeld 	skb_list_walk_safe(next, tmp, next) {
91508f7d8b6SSara Sharon 		memcpy(tmp->cb, cb, sizeof(tmp->cb));
91608f7d8b6SSara Sharon 		/*
91708f7d8b6SSara Sharon 		 * Compute the length of all the data added for the A-MSDU.
91808f7d8b6SSara Sharon 		 * This will be used to compute the length to write in the TX
91908f7d8b6SSara Sharon 		 * command. We have: SNAP + IP + TCP for n -1 subframes and
92008f7d8b6SSara Sharon 		 * ETH header for n subframes.
92108f7d8b6SSara Sharon 		 */
92208f7d8b6SSara Sharon 		tcp_payload_len = skb_tail_pointer(tmp) -
92308f7d8b6SSara Sharon 			skb_transport_header(tmp) -
92408f7d8b6SSara Sharon 			tcp_hdrlen(tmp) + tmp->data_len;
92508f7d8b6SSara Sharon 
92608f7d8b6SSara Sharon 		if (ipv4)
92708f7d8b6SSara Sharon 			ip_hdr(tmp)->id = htons(ip_base_id + i * num_subframes);
92808f7d8b6SSara Sharon 
92908f7d8b6SSara Sharon 		if (tcp_payload_len > mss) {
93008f7d8b6SSara Sharon 			skb_shinfo(tmp)->gso_size = mss;
93181a86e1bSEric Dumazet 			skb_shinfo(tmp)->gso_type = ipv4 ? SKB_GSO_TCPV4 :
93281a86e1bSEric Dumazet 							   SKB_GSO_TCPV6;
93308f7d8b6SSara Sharon 		} else {
93471b256f8SEmmanuel Grumbach 			if (qos) {
93508f7d8b6SSara Sharon 				u8 *qc;
93608f7d8b6SSara Sharon 
93708f7d8b6SSara Sharon 				if (ipv4)
93808f7d8b6SSara Sharon 					ip_send_check(ip_hdr(tmp));
93908f7d8b6SSara Sharon 
94008f7d8b6SSara Sharon 				qc = ieee80211_get_qos_ctl((void *)tmp->data);
94108f7d8b6SSara Sharon 				*qc &= ~IEEE80211_QOS_CTL_A_MSDU_PRESENT;
94208f7d8b6SSara Sharon 			}
94308f7d8b6SSara Sharon 			skb_shinfo(tmp)->gso_size = 0;
94408f7d8b6SSara Sharon 		}
94508f7d8b6SSara Sharon 
94666de4b17SJason A. Donenfeld 		skb_mark_not_on_list(tmp);
94708f7d8b6SSara Sharon 		__skb_queue_tail(mpdus_skb, tmp);
94808f7d8b6SSara Sharon 		i++;
94908f7d8b6SSara Sharon 	}
95008f7d8b6SSara Sharon 
95108f7d8b6SSara Sharon 	return 0;
95208f7d8b6SSara Sharon }
95308f7d8b6SSara Sharon 
iwl_mvm_tx_tso(struct iwl_mvm * mvm,struct sk_buff * skb,struct ieee80211_tx_info * info,struct ieee80211_sta * sta,struct sk_buff_head * mpdus_skb)95408f7d8b6SSara Sharon static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb,
95508f7d8b6SSara Sharon 			  struct ieee80211_tx_info *info,
95608f7d8b6SSara Sharon 			  struct ieee80211_sta *sta,
95708f7d8b6SSara Sharon 			  struct sk_buff_head *mpdus_skb)
95808f7d8b6SSara Sharon {
95908f7d8b6SSara Sharon 	struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
96008f7d8b6SSara Sharon 	struct ieee80211_hdr *hdr = (void *)skb->data;
96108f7d8b6SSara Sharon 	unsigned int mss = skb_shinfo(skb)->gso_size;
96208f7d8b6SSara Sharon 	unsigned int num_subframes, tcp_payload_len, subf_len, max_amsdu_len;
96308f7d8b6SSara Sharon 	u16 snap_ip_tcp, pad;
96408f7d8b6SSara Sharon 	netdev_features_t netdev_flags = NETIF_F_CSUM_MASK | NETIF_F_SG;
96508f7d8b6SSara Sharon 	u8 tid;
96608f7d8b6SSara Sharon 
96708f7d8b6SSara Sharon 	snap_ip_tcp = 8 + skb_transport_header(skb) - skb_network_header(skb) +
96808f7d8b6SSara Sharon 		tcp_hdrlen(skb);
96908f7d8b6SSara Sharon 
97008f7d8b6SSara Sharon 	if (!mvmsta->max_amsdu_len ||
97108f7d8b6SSara Sharon 	    !ieee80211_is_data_qos(hdr->frame_control) ||
972d6882e58SMordechay Goodstein 	    !mvmsta->amsdu_enabled)
97308f7d8b6SSara Sharon 		return iwl_mvm_tx_tso_segment(skb, 1, netdev_flags, mpdus_skb);
97408f7d8b6SSara Sharon 
97508f7d8b6SSara Sharon 	/*
97608f7d8b6SSara Sharon 	 * Do not build AMSDU for IPv6 with extension headers.
97708f7d8b6SSara Sharon 	 * ask stack to segment and checkum the generated MPDUs for us.
97808f7d8b6SSara Sharon 	 */
97908f7d8b6SSara Sharon 	if (skb->protocol == htons(ETH_P_IPV6) &&
98008f7d8b6SSara Sharon 	    ((struct ipv6hdr *)skb_network_header(skb))->nexthdr !=
98108f7d8b6SSara Sharon 	    IPPROTO_TCP) {
98208f7d8b6SSara Sharon 		netdev_flags &= ~NETIF_F_CSUM_MASK;
98308f7d8b6SSara Sharon 		return iwl_mvm_tx_tso_segment(skb, 1, netdev_flags, mpdus_skb);
98408f7d8b6SSara Sharon 	}
98508f7d8b6SSara Sharon 
98608f7d8b6SSara Sharon 	tid = ieee80211_get_tid(hdr);
98708f7d8b6SSara Sharon 	if (WARN_ON_ONCE(tid >= IWL_MAX_TID_COUNT))
98808f7d8b6SSara Sharon 		return -EINVAL;
98908f7d8b6SSara Sharon 
99008f7d8b6SSara Sharon 	/*
99108f7d8b6SSara Sharon 	 * No need to lock amsdu_in_ampdu_allowed since it can't be modified
99208f7d8b6SSara Sharon 	 * during an BA session.
99308f7d8b6SSara Sharon 	 */
994e88e2cd0SMordechay Goodstein 	if ((info->flags & IEEE80211_TX_CTL_AMPDU &&
995e88e2cd0SMordechay Goodstein 	     !mvmsta->tid_data[tid].amsdu_in_ampdu_allowed) ||
99608f7d8b6SSara Sharon 	    !(mvmsta->amsdu_enabled & BIT(tid)))
99708f7d8b6SSara Sharon 		return iwl_mvm_tx_tso_segment(skb, 1, netdev_flags, mpdus_skb);
99808f7d8b6SSara Sharon 
999ee4cce9bSMordechay Goodstein 	/*
1000ee4cce9bSMordechay Goodstein 	 * Take the min of ieee80211 station and mvm station
1001ee4cce9bSMordechay Goodstein 	 */
1002ee4cce9bSMordechay Goodstein 	max_amsdu_len =
10034c51541dSBenjamin Berg 		min_t(unsigned int, sta->cur->max_amsdu_len,
1004ee4cce9bSMordechay Goodstein 		      iwl_mvm_max_amsdu_size(mvm, sta, tid));
100508f7d8b6SSara Sharon 
100608f7d8b6SSara Sharon 	/*
100708f7d8b6SSara Sharon 	 * Limit A-MSDU in A-MPDU to 4095 bytes when VHT is not
100808f7d8b6SSara Sharon 	 * supported. This is a spec requirement (IEEE 802.11-2015
100908f7d8b6SSara Sharon 	 * section 8.7.3 NOTE 3).
101008f7d8b6SSara Sharon 	 */
101108f7d8b6SSara Sharon 	if (info->flags & IEEE80211_TX_CTL_AMPDU &&
1012046d2e7cSSriram R 	    !sta->deflink.vht_cap.vht_supported)
101308f7d8b6SSara Sharon 		max_amsdu_len = min_t(unsigned int, max_amsdu_len, 4095);
101408f7d8b6SSara Sharon 
101508f7d8b6SSara Sharon 	/* Sub frame header + SNAP + IP header + TCP header + MSS */
101608f7d8b6SSara Sharon 	subf_len = sizeof(struct ethhdr) + snap_ip_tcp + mss;
101708f7d8b6SSara Sharon 	pad = (4 - subf_len) & 0x3;
101808f7d8b6SSara Sharon 
101908f7d8b6SSara Sharon 	/*
102008f7d8b6SSara Sharon 	 * If we have N subframes in the A-MSDU, then the A-MSDU's size is
102108f7d8b6SSara Sharon 	 * N * subf_len + (N - 1) * pad.
102208f7d8b6SSara Sharon 	 */
102308f7d8b6SSara Sharon 	num_subframes = (max_amsdu_len + pad) / (subf_len + pad);
102408f7d8b6SSara Sharon 
102508f7d8b6SSara Sharon 	if (sta->max_amsdu_subframes &&
102608f7d8b6SSara Sharon 	    num_subframes > sta->max_amsdu_subframes)
102708f7d8b6SSara Sharon 		num_subframes = sta->max_amsdu_subframes;
102808f7d8b6SSara Sharon 
102908f7d8b6SSara Sharon 	tcp_payload_len = skb_tail_pointer(skb) - skb_transport_header(skb) -
103008f7d8b6SSara Sharon 		tcp_hdrlen(skb) + skb->data_len;
103108f7d8b6SSara Sharon 
103208f7d8b6SSara Sharon 	/*
103308f7d8b6SSara Sharon 	 * Make sure we have enough TBs for the A-MSDU:
103408f7d8b6SSara Sharon 	 *	2 for each subframe
103508f7d8b6SSara Sharon 	 *	1 more for each fragment
103608f7d8b6SSara Sharon 	 *	1 more for the potential data in the header
103708f7d8b6SSara Sharon 	 */
103808f7d8b6SSara Sharon 	if ((num_subframes * 2 + skb_shinfo(skb)->nr_frags + 1) >
103908f7d8b6SSara Sharon 	    mvm->trans->max_skb_frags)
104008f7d8b6SSara Sharon 		num_subframes = 1;
104108f7d8b6SSara Sharon 
104208f7d8b6SSara Sharon 	if (num_subframes > 1)
104308f7d8b6SSara Sharon 		*ieee80211_get_qos_ctl(hdr) |= IEEE80211_QOS_CTL_A_MSDU_PRESENT;
104408f7d8b6SSara Sharon 
104508f7d8b6SSara Sharon 	/* This skb fits in one single A-MSDU */
104608f7d8b6SSara Sharon 	if (num_subframes * mss >= tcp_payload_len) {
104708f7d8b6SSara Sharon 		__skb_queue_tail(mpdus_skb, skb);
104808f7d8b6SSara Sharon 		return 0;
104908f7d8b6SSara Sharon 	}
105008f7d8b6SSara Sharon 
105108f7d8b6SSara Sharon 	/*
105208f7d8b6SSara Sharon 	 * Trick the segmentation function to make it
105308f7d8b6SSara Sharon 	 * create SKBs that can fit into one A-MSDU.
105408f7d8b6SSara Sharon 	 */
105508f7d8b6SSara Sharon 	return iwl_mvm_tx_tso_segment(skb, num_subframes, netdev_flags,
105608f7d8b6SSara Sharon 				      mpdus_skb);
105708f7d8b6SSara Sharon }
105808f7d8b6SSara Sharon #else /* CONFIG_INET */
iwl_mvm_tx_tso(struct iwl_mvm * mvm,struct sk_buff * skb,struct ieee80211_tx_info * info,struct ieee80211_sta * sta,struct sk_buff_head * mpdus_skb)105908f7d8b6SSara Sharon static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb,
106008f7d8b6SSara Sharon 			  struct ieee80211_tx_info *info,
106108f7d8b6SSara Sharon 			  struct ieee80211_sta *sta,
106208f7d8b6SSara Sharon 			  struct sk_buff_head *mpdus_skb)
106308f7d8b6SSara Sharon {
106408f7d8b6SSara Sharon 	/* Impossible to get TSO with CONFIG_INET */
106508f7d8b6SSara Sharon 	WARN_ON(1);
106608f7d8b6SSara Sharon 
106708f7d8b6SSara Sharon 	return -1;
106808f7d8b6SSara Sharon }
106908f7d8b6SSara Sharon #endif
107008f7d8b6SSara Sharon 
10719f9af3d7SLiad Kaufman /* Check if there are any timed-out TIDs on a given shared TXQ */
iwl_mvm_txq_should_update(struct iwl_mvm * mvm,int txq_id)10729f9af3d7SLiad Kaufman static bool iwl_mvm_txq_should_update(struct iwl_mvm *mvm, int txq_id)
10739f9af3d7SLiad Kaufman {
10749f9af3d7SLiad Kaufman 	unsigned long queue_tid_bitmap = mvm->queue_info[txq_id].tid_bitmap;
10759f9af3d7SLiad Kaufman 	unsigned long now = jiffies;
10769f9af3d7SLiad Kaufman 	int tid;
10779f9af3d7SLiad Kaufman 
1078bb49701bSSara Sharon 	if (WARN_ON(iwl_mvm_has_new_tx_api(mvm)))
1079bb49701bSSara Sharon 		return false;
1080bb49701bSSara Sharon 
10819f9af3d7SLiad Kaufman 	for_each_set_bit(tid, &queue_tid_bitmap, IWL_MAX_TID_COUNT + 1) {
10829f9af3d7SLiad Kaufman 		if (time_before(mvm->queue_info[txq_id].last_frame_time[tid] +
10839f9af3d7SLiad Kaufman 				IWL_MVM_DQA_QUEUE_TIMEOUT, now))
10849f9af3d7SLiad Kaufman 			return true;
10859f9af3d7SLiad Kaufman 	}
10869f9af3d7SLiad Kaufman 
10879f9af3d7SLiad Kaufman 	return false;
10889f9af3d7SLiad Kaufman }
10899f9af3d7SLiad Kaufman 
iwl_mvm_tx_airtime(struct iwl_mvm * mvm,struct iwl_mvm_sta * mvmsta,int airtime)10907d9d0d56SLuca Coelho static void iwl_mvm_tx_airtime(struct iwl_mvm *mvm,
10917d9d0d56SLuca Coelho 			       struct iwl_mvm_sta *mvmsta,
10927d9d0d56SLuca Coelho 			       int airtime)
10937d9d0d56SLuca Coelho {
10947d9d0d56SLuca Coelho 	int mac = mvmsta->mac_id_n_color & FW_CTXT_ID_MSK;
1095162b22c9SLiad Kaufman 	struct iwl_mvm_tcm_mac *mdata;
1096162b22c9SLiad Kaufman 
1097162b22c9SLiad Kaufman 	if (mac >= NUM_MAC_INDEX_DRIVER)
1098162b22c9SLiad Kaufman 		return;
1099162b22c9SLiad Kaufman 
1100162b22c9SLiad Kaufman 	mdata = &mvm->tcm.data[mac];
11017d9d0d56SLuca Coelho 
11027d9d0d56SLuca Coelho 	if (mvm->tcm.paused)
11037d9d0d56SLuca Coelho 		return;
11047d9d0d56SLuca Coelho 
11057d9d0d56SLuca Coelho 	if (time_after(jiffies, mvm->tcm.ts + MVM_TCM_PERIOD))
11067d9d0d56SLuca Coelho 		schedule_delayed_work(&mvm->tcm.work, 0);
11077d9d0d56SLuca Coelho 
11087d9d0d56SLuca Coelho 	mdata->tx.airtime += airtime;
11097d9d0d56SLuca Coelho }
11107d9d0d56SLuca Coelho 
iwl_mvm_tx_pkt_queued(struct iwl_mvm * mvm,struct iwl_mvm_sta * mvmsta,int tid)1111162b22c9SLiad Kaufman static int iwl_mvm_tx_pkt_queued(struct iwl_mvm *mvm,
11127d9d0d56SLuca Coelho 				 struct iwl_mvm_sta *mvmsta, int tid)
11137d9d0d56SLuca Coelho {
11147d9d0d56SLuca Coelho 	u32 ac = tid_to_mac80211_ac[tid];
11157d9d0d56SLuca Coelho 	int mac = mvmsta->mac_id_n_color & FW_CTXT_ID_MSK;
1116162b22c9SLiad Kaufman 	struct iwl_mvm_tcm_mac *mdata;
1117162b22c9SLiad Kaufman 
1118162b22c9SLiad Kaufman 	if (mac >= NUM_MAC_INDEX_DRIVER)
1119162b22c9SLiad Kaufman 		return -EINVAL;
1120162b22c9SLiad Kaufman 
1121162b22c9SLiad Kaufman 	mdata = &mvm->tcm.data[mac];
11227d9d0d56SLuca Coelho 
11237d9d0d56SLuca Coelho 	mdata->tx.pkts[ac]++;
1124162b22c9SLiad Kaufman 
1125162b22c9SLiad Kaufman 	return 0;
11267d9d0d56SLuca Coelho }
11277d9d0d56SLuca Coelho 
1128e705c121SKalle Valo /*
11299ae3b870SJiri Kosina  * Sets the fields in the Tx cmd that are crypto related.
11309ae3b870SJiri Kosina  *
11319ae3b870SJiri Kosina  * This function must be called with BHs disabled.
1132e705c121SKalle Valo  */
iwl_mvm_tx_mpdu(struct iwl_mvm * mvm,struct sk_buff * skb,struct ieee80211_tx_info * info,struct ieee80211_sta * sta,const u8 * addr3_override)1133a3713f8bSEmmanuel Grumbach static int iwl_mvm_tx_mpdu(struct iwl_mvm *mvm, struct sk_buff *skb,
11345c08b0f5SEmmanuel Grumbach 			   struct ieee80211_tx_info *info,
1135ae668e2eSDaniel Gabay 			   struct ieee80211_sta *sta,
1136ae668e2eSDaniel Gabay 			   const u8 *addr3_override)
1137e705c121SKalle Valo {
1138e705c121SKalle Valo 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
1139e705c121SKalle Valo 	struct iwl_mvm_sta *mvmsta;
1140a89c72ffSJohannes Berg 	struct iwl_device_tx_cmd *dev_cmd;
1141e705c121SKalle Valo 	__le16 fc;
1142e705c121SKalle Valo 	u16 seq_number = 0;
1143e705c121SKalle Valo 	u8 tid = IWL_MAX_TID_COUNT;
1144cfbc6c4cSSara Sharon 	u16 txq_id;
11457ec54716SJohannes Berg 	bool is_ampdu = false;
1146e705c121SKalle Valo 	int hdrlen;
1147e705c121SKalle Valo 
1148*6dcadb2eSMiri Korenblit 	if (WARN_ON_ONCE(!sta))
1149*6dcadb2eSMiri Korenblit 		return -1;
1150*6dcadb2eSMiri Korenblit 
1151e705c121SKalle Valo 	mvmsta = iwl_mvm_sta_from_mac80211(sta);
1152e705c121SKalle Valo 	fc = hdr->frame_control;
1153e705c121SKalle Valo 	hdrlen = ieee80211_hdrlen(fc);
1154e705c121SKalle Valo 
115550386305SSara Sharon 	if (IWL_MVM_NON_TRANSMITTING_AP && ieee80211_is_probe_resp(fc))
115650386305SSara Sharon 		return -1;
115750386305SSara Sharon 
1158c8ee33e1SGregory Greenman 	if (WARN_ON_ONCE(mvmsta->deflink.sta_id == IWL_MVM_INVALID_STA))
1159e705c121SKalle Valo 		return -1;
1160e705c121SKalle Valo 
1161046d2e7cSSriram R 	if (unlikely(ieee80211_is_any_nullfunc(fc)) && sta->deflink.he_cap.has_he)
1162e41eb3e4SFelix Fietkau 		return -1;
1163e41eb3e4SFelix Fietkau 
116486e177d8SGregory Greenman 	if (unlikely(ieee80211_is_probe_resp(fc)))
116586e177d8SGregory Greenman 		iwl_mvm_probe_resp_set_noa(mvm, skb);
116686e177d8SGregory Greenman 
11675c08b0f5SEmmanuel Grumbach 	dev_cmd = iwl_mvm_set_tx_params(mvm, skb, info, hdrlen,
1168ae668e2eSDaniel Gabay 					sta, mvmsta->deflink.sta_id,
1169ae668e2eSDaniel Gabay 					addr3_override);
1170e705c121SKalle Valo 	if (!dev_cmd)
1171e705c121SKalle Valo 		goto drop;
1172e705c121SKalle Valo 
1173e705c121SKalle Valo 	/*
1174e705c121SKalle Valo 	 * we handle that entirely ourselves -- for uAPSD the firmware
1175e705c121SKalle Valo 	 * will always send a notification, and for PS-Poll responses
1176e705c121SKalle Valo 	 * we'll notify mac80211 when getting frame status
1177e705c121SKalle Valo 	 */
1178e705c121SKalle Valo 	info->flags &= ~IEEE80211_TX_STATUS_EOSP;
1179e705c121SKalle Valo 
1180e705c121SKalle Valo 	spin_lock(&mvmsta->lock);
1181e705c121SKalle Valo 
11820d7f1b99SSara Sharon 	/* nullfunc frames should go to the MGMT queue regardless of QOS,
11837d577d76SGregory Greenman 	 * the conditions of !ieee80211_is_qos_nullfunc(fc) and
11847d577d76SGregory Greenman 	 * !ieee80211_is_data_qos(fc) keep the default assignment of MGMT TID
11850d7f1b99SSara Sharon 	 */
1186e705c121SKalle Valo 	if (ieee80211_is_data_qos(fc) && !ieee80211_is_qos_nullfunc(fc)) {
11878f66e064SSara Sharon 		tid = ieee80211_get_tid(hdr);
1188f50d693bSSara Sharon 		if (WARN_ONCE(tid >= IWL_MAX_TID_COUNT, "Invalid TID %d", tid))
1189e705c121SKalle Valo 			goto drop_unlock_sta;
1190e705c121SKalle Valo 
1191e705c121SKalle Valo 		is_ampdu = info->flags & IEEE80211_TX_CTL_AMPDU;
1192f50d693bSSara Sharon 		if (WARN_ONCE(is_ampdu &&
1193f50d693bSSara Sharon 			      mvmsta->tid_data[tid].state != IWL_AGG_ON,
1194f50d693bSSara Sharon 			      "Invalid internal agg state %d for TID %d",
1195f50d693bSSara Sharon 			       mvmsta->tid_data[tid].state, tid))
11960d7f1b99SSara Sharon 			goto drop_unlock_sta;
1197c47de665SSara Sharon 
1198c47de665SSara Sharon 		seq_number = mvmsta->tid_data[tid].seq_number;
1199c47de665SSara Sharon 		seq_number &= IEEE80211_SCTL_SEQ;
1200c47de665SSara Sharon 
1201c47de665SSara Sharon 		if (!iwl_mvm_has_new_tx_api(mvm)) {
1202c47de665SSara Sharon 			struct iwl_tx_cmd *tx_cmd = (void *)dev_cmd->payload;
1203c47de665SSara Sharon 
1204c47de665SSara Sharon 			hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
1205c47de665SSara Sharon 			hdr->seq_ctrl |= cpu_to_le16(seq_number);
1206c47de665SSara Sharon 			/* update the tx_cmd hdr as it was already copied */
1207c47de665SSara Sharon 			tx_cmd->hdr->seq_ctrl = hdr->seq_ctrl;
1208c47de665SSara Sharon 		}
12097d577d76SGregory Greenman 	} else if (ieee80211_is_data(fc) && !ieee80211_is_data_qos(fc) &&
12107d577d76SGregory Greenman 		   !ieee80211_is_nullfunc(fc)) {
12112210f695SAvraham Stern 		tid = IWL_TID_NON_QOS;
1212e705c121SKalle Valo 	}
1213e705c121SKalle Valo 
12149794c64fSLiad Kaufman 	txq_id = mvmsta->tid_data[tid].txq_id;
1215c47de665SSara Sharon 
12160d7f1b99SSara Sharon 	WARN_ON_ONCE(info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM);
1217e705c121SKalle Valo 
1218f50d693bSSara Sharon 	if (WARN_ONCE(txq_id == IWL_MVM_INVALID_QUEUE, "Invalid TXQ id")) {
121924afba76SLiad Kaufman 		iwl_trans_free_tx_cmd(mvm->trans, dev_cmd);
122024afba76SLiad Kaufman 		spin_unlock(&mvmsta->lock);
1221b9f726c9SJohannes Berg 		return -1;
122224afba76SLiad Kaufman 	}
122324afba76SLiad Kaufman 
1224c8f54701SJohannes Berg 	if (!iwl_mvm_has_new_tx_api(mvm)) {
12259794c64fSLiad Kaufman 		/* Keep track of the time of the last frame for this RA/TID */
12269794c64fSLiad Kaufman 		mvm->queue_info[txq_id].last_frame_time[tid] = jiffies;
12279794c64fSLiad Kaufman 
12289f9af3d7SLiad Kaufman 		/*
12299f9af3d7SLiad Kaufman 		 * If we have timed-out TIDs - schedule the worker that will
12309f9af3d7SLiad Kaufman 		 * reconfig the queues and update them
12319f9af3d7SLiad Kaufman 		 *
1232f3f240f9SJohannes Berg 		 * Note that the no lock is taken here in order to not serialize
1233f3f240f9SJohannes Berg 		 * the TX flow. This isn't dangerous because scheduling
1234f3f240f9SJohannes Berg 		 * mvm->add_stream_wk can't ruin the state, and if we DON'T
1235f3f240f9SJohannes Berg 		 * schedule it due to some race condition then next TX we get
1236f3f240f9SJohannes Berg 		 * here we will.
12379f9af3d7SLiad Kaufman 		 */
12389f9af3d7SLiad Kaufman 		if (unlikely(mvm->queue_info[txq_id].status ==
12399f9af3d7SLiad Kaufman 			     IWL_MVM_QUEUE_SHARED &&
12409f9af3d7SLiad Kaufman 			     iwl_mvm_txq_should_update(mvm, txq_id)))
12419f9af3d7SLiad Kaufman 			schedule_work(&mvm->add_stream_wk);
12429f9af3d7SLiad Kaufman 	}
12439f9af3d7SLiad Kaufman 
1244f38acea6SShaul Triebitz 	IWL_DEBUG_TX(mvm, "TX to [%d|%d] Q:%d - seq: 0x%x len %d\n",
1245c8ee33e1SGregory Greenman 		     mvmsta->deflink.sta_id, tid, txq_id,
1246f38acea6SShaul Triebitz 		     IEEE80211_SEQ_TO_SN(seq_number), skb->len);
1247e705c121SKalle Valo 
1248bd05a5bdSJohannes Berg 	/* From now on, we cannot access info->control */
1249bd05a5bdSJohannes Berg 	iwl_mvm_skb_prepare_status(skb, dev_cmd);
1250bd05a5bdSJohannes Berg 
1251bcd68b3dSEmmanuel Grumbach 	/*
1252bcd68b3dSEmmanuel Grumbach 	 * The IV is introduced by the HW for new tx api, and it is not present
1253bcd68b3dSEmmanuel Grumbach 	 * in the skb, hence, don't tell iwl_mvm_mei_tx_copy_to_csme about the
1254bcd68b3dSEmmanuel Grumbach 	 * IV for those devices.
1255bcd68b3dSEmmanuel Grumbach 	 */
12566d19a5ebSEmmanuel Grumbach 	if (ieee80211_is_data(fc))
12576d19a5ebSEmmanuel Grumbach 		iwl_mvm_mei_tx_copy_to_csme(mvm, skb,
1258bcd68b3dSEmmanuel Grumbach 					    info->control.hw_key &&
1259bcd68b3dSEmmanuel Grumbach 					    !iwl_mvm_has_new_tx_api(mvm) ?
12606d19a5ebSEmmanuel Grumbach 					    info->control.hw_key->iv_len : 0);
12616d19a5ebSEmmanuel Grumbach 
1262e705c121SKalle Valo 	if (iwl_trans_tx(mvm->trans, skb, dev_cmd, txq_id))
1263e705c121SKalle Valo 		goto drop_unlock_sta;
1264e705c121SKalle Valo 
12657ec54716SJohannes Berg 	if (tid < IWL_MAX_TID_COUNT && !ieee80211_has_morefrags(fc))
1266e705c121SKalle Valo 		mvmsta->tid_data[tid].seq_number = seq_number + 0x10;
1267e705c121SKalle Valo 
1268e705c121SKalle Valo 	spin_unlock(&mvmsta->lock);
1269e705c121SKalle Valo 
1270162b22c9SLiad Kaufman 	if (iwl_mvm_tx_pkt_queued(mvm, mvmsta,
1271162b22c9SLiad Kaufman 				  tid == IWL_MAX_TID_COUNT ? 0 : tid))
1272162b22c9SLiad Kaufman 		goto drop;
12737d9d0d56SLuca Coelho 
1274e705c121SKalle Valo 	return 0;
1275e705c121SKalle Valo 
1276e705c121SKalle Valo drop_unlock_sta:
1277e705c121SKalle Valo 	iwl_trans_free_tx_cmd(mvm->trans, dev_cmd);
1278e705c121SKalle Valo 	spin_unlock(&mvmsta->lock);
1279e705c121SKalle Valo drop:
1280c8ee33e1SGregory Greenman 	IWL_DEBUG_TX(mvm, "TX to [%d|%d] dropped\n", mvmsta->deflink.sta_id,
1281c8ee33e1SGregory Greenman 		     tid);
1282e705c121SKalle Valo 	return -1;
1283e705c121SKalle Valo }
1284e705c121SKalle Valo 
iwl_mvm_tx_skb_sta(struct iwl_mvm * mvm,struct sk_buff * skb,struct ieee80211_sta * sta)1285df2378abSJohannes Berg int iwl_mvm_tx_skb_sta(struct iwl_mvm *mvm, struct sk_buff *skb,
1286a3713f8bSEmmanuel Grumbach 		       struct ieee80211_sta *sta)
1287a3713f8bSEmmanuel Grumbach {
1288*6dcadb2eSMiri Korenblit 	struct iwl_mvm_sta *mvmsta;
12895c08b0f5SEmmanuel Grumbach 	struct ieee80211_tx_info info;
129008f7d8b6SSara Sharon 	struct sk_buff_head mpdus_skbs;
1291ae668e2eSDaniel Gabay 	struct ieee80211_vif *vif;
129208f7d8b6SSara Sharon 	unsigned int payload_len;
129308f7d8b6SSara Sharon 	int ret;
12940473cbaeSBen Greear 	struct sk_buff *orig_skb = skb;
1295ae668e2eSDaniel Gabay 	const u8 *addr3;
1296a3713f8bSEmmanuel Grumbach 
1297*6dcadb2eSMiri Korenblit 	if (WARN_ON_ONCE(!sta))
1298a3713f8bSEmmanuel Grumbach 		return -1;
1299a3713f8bSEmmanuel Grumbach 
1300*6dcadb2eSMiri Korenblit 	mvmsta = iwl_mvm_sta_from_mac80211(sta);
1301*6dcadb2eSMiri Korenblit 
1302c8ee33e1SGregory Greenman 	if (WARN_ON_ONCE(mvmsta->deflink.sta_id == IWL_MVM_INVALID_STA))
1303a3713f8bSEmmanuel Grumbach 		return -1;
1304a3713f8bSEmmanuel Grumbach 
13055c08b0f5SEmmanuel Grumbach 	memcpy(&info, skb->cb, sizeof(info));
13065c08b0f5SEmmanuel Grumbach 
130708f7d8b6SSara Sharon 	if (!skb_is_gso(skb))
1308ae668e2eSDaniel Gabay 		return iwl_mvm_tx_mpdu(mvm, skb, &info, sta, NULL);
130908f7d8b6SSara Sharon 
131008f7d8b6SSara Sharon 	payload_len = skb_tail_pointer(skb) - skb_transport_header(skb) -
131108f7d8b6SSara Sharon 		tcp_hdrlen(skb) + skb->data_len;
131208f7d8b6SSara Sharon 
131308f7d8b6SSara Sharon 	if (payload_len <= skb_shinfo(skb)->gso_size)
1314ae668e2eSDaniel Gabay 		return iwl_mvm_tx_mpdu(mvm, skb, &info, sta, NULL);
131508f7d8b6SSara Sharon 
131608f7d8b6SSara Sharon 	__skb_queue_head_init(&mpdus_skbs);
131708f7d8b6SSara Sharon 
1318ae668e2eSDaniel Gabay 	vif = info.control.vif;
1319ae668e2eSDaniel Gabay 	if (!vif)
1320ae668e2eSDaniel Gabay 		return -1;
1321ae668e2eSDaniel Gabay 
132208f7d8b6SSara Sharon 	ret = iwl_mvm_tx_tso(mvm, skb, &info, sta, &mpdus_skbs);
132308f7d8b6SSara Sharon 	if (ret)
132408f7d8b6SSara Sharon 		return ret;
132508f7d8b6SSara Sharon 
1326cdc419e9SJohannes Berg 	WARN_ON(skb_queue_empty(&mpdus_skbs));
132708f7d8b6SSara Sharon 
1328ae668e2eSDaniel Gabay 	/*
1329ae668e2eSDaniel Gabay 	 * As described in IEEE sta 802.11-2020, table 9-30 (Address
1330ae668e2eSDaniel Gabay 	 * field contents), A-MSDU address 3 should contain the BSSID
1331ae668e2eSDaniel Gabay 	 * address.
1332ae668e2eSDaniel Gabay 	 * Pass address 3 down to iwl_mvm_tx_mpdu() and further to set it
1333ae668e2eSDaniel Gabay 	 * in the command header. We need to preserve the original
1334ae668e2eSDaniel Gabay 	 * address 3 in the skb header to correctly create all the
1335ae668e2eSDaniel Gabay 	 * A-MSDU subframe headers from it.
1336ae668e2eSDaniel Gabay 	 */
1337ae668e2eSDaniel Gabay 	switch (vif->type) {
1338ae668e2eSDaniel Gabay 	case NL80211_IFTYPE_STATION:
1339ae668e2eSDaniel Gabay 		addr3 = vif->cfg.ap_addr;
1340ae668e2eSDaniel Gabay 		break;
1341ae668e2eSDaniel Gabay 	case NL80211_IFTYPE_AP:
1342ae668e2eSDaniel Gabay 		addr3 = vif->addr;
1343ae668e2eSDaniel Gabay 		break;
1344ae668e2eSDaniel Gabay 	default:
1345ae668e2eSDaniel Gabay 		addr3 = NULL;
1346ae668e2eSDaniel Gabay 		break;
1347ae668e2eSDaniel Gabay 	}
134808f7d8b6SSara Sharon 
1349ae668e2eSDaniel Gabay 	while (!skb_queue_empty(&mpdus_skbs)) {
1350ae668e2eSDaniel Gabay 		struct ieee80211_hdr *hdr;
1351ae668e2eSDaniel Gabay 		bool amsdu;
1352ae668e2eSDaniel Gabay 
1353ae668e2eSDaniel Gabay 		skb = __skb_dequeue(&mpdus_skbs);
1354ae668e2eSDaniel Gabay 		hdr = (void *)skb->data;
1355ae668e2eSDaniel Gabay 		amsdu = ieee80211_is_data_qos(hdr->frame_control) &&
1356ae668e2eSDaniel Gabay 			(*ieee80211_get_qos_ctl(hdr) &
1357ae668e2eSDaniel Gabay 			 IEEE80211_QOS_CTL_A_MSDU_PRESENT);
1358ae668e2eSDaniel Gabay 
1359ae668e2eSDaniel Gabay 		ret = iwl_mvm_tx_mpdu(mvm, skb, &info, sta,
1360ae668e2eSDaniel Gabay 				      amsdu ? addr3 : NULL);
136108f7d8b6SSara Sharon 		if (ret) {
13620473cbaeSBen Greear 			/* Free skbs created as part of TSO logic that have not yet been dequeued */
136308f7d8b6SSara Sharon 			__skb_queue_purge(&mpdus_skbs);
13640473cbaeSBen Greear 			/* skb here is not necessarily same as skb that entered this method,
13650473cbaeSBen Greear 			 * so free it explicitly.
13660473cbaeSBen Greear 			 */
13670473cbaeSBen Greear 			if (skb == orig_skb)
13680473cbaeSBen Greear 				ieee80211_free_txskb(mvm->hw, skb);
13690473cbaeSBen Greear 			else
13700473cbaeSBen Greear 				kfree_skb(skb);
13710473cbaeSBen Greear 			/* there was error, but we consumed skb one way or another, so return 0 */
13720473cbaeSBen Greear 			return 0;
137308f7d8b6SSara Sharon 		}
137408f7d8b6SSara Sharon 	}
137508f7d8b6SSara Sharon 
137608f7d8b6SSara Sharon 	return 0;
1377a3713f8bSEmmanuel Grumbach }
1378a3713f8bSEmmanuel Grumbach 
iwl_mvm_check_ratid_empty(struct iwl_mvm * mvm,struct ieee80211_sta * sta,u8 tid)1379e705c121SKalle Valo static void iwl_mvm_check_ratid_empty(struct iwl_mvm *mvm,
1380e705c121SKalle Valo 				      struct ieee80211_sta *sta, u8 tid)
1381e705c121SKalle Valo {
1382e705c121SKalle Valo 	struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
1383e705c121SKalle Valo 	struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid];
1384e705c121SKalle Valo 	struct ieee80211_vif *vif = mvmsta->vif;
1385dd32162dSLiad Kaufman 	u16 normalized_ssn;
1386e705c121SKalle Valo 
1387e705c121SKalle Valo 	lockdep_assert_held(&mvmsta->lock);
1388e705c121SKalle Valo 
1389e705c121SKalle Valo 	if ((tid_data->state == IWL_AGG_ON ||
1390c8f54701SJohannes Berg 	     tid_data->state == IWL_EMPTYING_HW_QUEUE_DELBA) &&
1391dd32162dSLiad Kaufman 	    iwl_mvm_tid_queued(mvm, tid_data) == 0) {
1392e705c121SKalle Valo 		/*
13939a3fcf91SSara Sharon 		 * Now that this aggregation or DQA queue is empty tell
13949a3fcf91SSara Sharon 		 * mac80211 so it knows we no longer have frames buffered for
13959a3fcf91SSara Sharon 		 * the station on this TID (for the TIM bitmap calculation.)
1396e705c121SKalle Valo 		 */
1397e705c121SKalle Valo 		ieee80211_sta_set_buffered(sta, tid, false);
1398e705c121SKalle Valo 	}
1399e705c121SKalle Valo 
1400dd32162dSLiad Kaufman 	/*
14012f7a3863SLuca Coelho 	 * In 22000 HW, the next_reclaimed index is only 8 bit, so we'll need
1402dd32162dSLiad Kaufman 	 * to align the wrap around of ssn so we compare relevant values.
1403dd32162dSLiad Kaufman 	 */
1404dd32162dSLiad Kaufman 	normalized_ssn = tid_data->ssn;
1405286ca8ebSLuca Coelho 	if (mvm->trans->trans_cfg->gen2)
1406dd32162dSLiad Kaufman 		normalized_ssn &= 0xff;
1407dd32162dSLiad Kaufman 
1408dd32162dSLiad Kaufman 	if (normalized_ssn != tid_data->next_reclaimed)
1409e705c121SKalle Valo 		return;
1410e705c121SKalle Valo 
1411e705c121SKalle Valo 	switch (tid_data->state) {
1412e705c121SKalle Valo 	case IWL_EMPTYING_HW_QUEUE_ADDBA:
1413e705c121SKalle Valo 		IWL_DEBUG_TX_QUEUES(mvm,
1414e705c121SKalle Valo 				    "Can continue addBA flow ssn = next_recl = %d\n",
1415e705c121SKalle Valo 				    tid_data->next_reclaimed);
1416e705c121SKalle Valo 		tid_data->state = IWL_AGG_STARTING;
1417e705c121SKalle Valo 		ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
1418e705c121SKalle Valo 		break;
1419e705c121SKalle Valo 
1420e705c121SKalle Valo 	case IWL_EMPTYING_HW_QUEUE_DELBA:
1421e705c121SKalle Valo 		IWL_DEBUG_TX_QUEUES(mvm,
1422e705c121SKalle Valo 				    "Can continue DELBA flow ssn = next_recl = %d\n",
1423e705c121SKalle Valo 				    tid_data->next_reclaimed);
1424e705c121SKalle Valo 		tid_data->state = IWL_AGG_OFF;
1425e705c121SKalle Valo 		ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
1426e705c121SKalle Valo 		break;
1427e705c121SKalle Valo 
1428e705c121SKalle Valo 	default:
1429e705c121SKalle Valo 		break;
1430e705c121SKalle Valo 	}
1431e705c121SKalle Valo }
1432e705c121SKalle Valo 
1433e705c121SKalle Valo #ifdef CONFIG_IWLWIFI_DEBUG
iwl_mvm_get_tx_fail_reason(u32 status)1434e705c121SKalle Valo const char *iwl_mvm_get_tx_fail_reason(u32 status)
1435e705c121SKalle Valo {
1436e705c121SKalle Valo #define TX_STATUS_FAIL(x) case TX_STATUS_FAIL_ ## x: return #x
1437e705c121SKalle Valo #define TX_STATUS_POSTPONE(x) case TX_STATUS_POSTPONE_ ## x: return #x
1438e705c121SKalle Valo 
1439e705c121SKalle Valo 	switch (status & TX_STATUS_MSK) {
1440e705c121SKalle Valo 	case TX_STATUS_SUCCESS:
1441e705c121SKalle Valo 		return "SUCCESS";
1442e705c121SKalle Valo 	TX_STATUS_POSTPONE(DELAY);
1443e705c121SKalle Valo 	TX_STATUS_POSTPONE(FEW_BYTES);
1444e705c121SKalle Valo 	TX_STATUS_POSTPONE(BT_PRIO);
1445e705c121SKalle Valo 	TX_STATUS_POSTPONE(QUIET_PERIOD);
1446e705c121SKalle Valo 	TX_STATUS_POSTPONE(CALC_TTAK);
1447e705c121SKalle Valo 	TX_STATUS_FAIL(INTERNAL_CROSSED_RETRY);
1448e705c121SKalle Valo 	TX_STATUS_FAIL(SHORT_LIMIT);
1449e705c121SKalle Valo 	TX_STATUS_FAIL(LONG_LIMIT);
1450e705c121SKalle Valo 	TX_STATUS_FAIL(UNDERRUN);
1451e705c121SKalle Valo 	TX_STATUS_FAIL(DRAIN_FLOW);
1452e705c121SKalle Valo 	TX_STATUS_FAIL(RFKILL_FLUSH);
1453e705c121SKalle Valo 	TX_STATUS_FAIL(LIFE_EXPIRE);
1454e705c121SKalle Valo 	TX_STATUS_FAIL(DEST_PS);
1455e705c121SKalle Valo 	TX_STATUS_FAIL(HOST_ABORTED);
1456e705c121SKalle Valo 	TX_STATUS_FAIL(BT_RETRY);
1457e705c121SKalle Valo 	TX_STATUS_FAIL(STA_INVALID);
1458e705c121SKalle Valo 	TX_STATUS_FAIL(FRAG_DROPPED);
1459e705c121SKalle Valo 	TX_STATUS_FAIL(TID_DISABLE);
1460e705c121SKalle Valo 	TX_STATUS_FAIL(FIFO_FLUSHED);
1461e705c121SKalle Valo 	TX_STATUS_FAIL(SMALL_CF_POLL);
1462e705c121SKalle Valo 	TX_STATUS_FAIL(FW_DROP);
1463e705c121SKalle Valo 	TX_STATUS_FAIL(STA_COLOR_MISMATCH);
1464e705c121SKalle Valo 	}
1465e705c121SKalle Valo 
1466e705c121SKalle Valo 	return "UNKNOWN";
1467e705c121SKalle Valo 
1468e705c121SKalle Valo #undef TX_STATUS_FAIL
1469e705c121SKalle Valo #undef TX_STATUS_POSTPONE
1470e705c121SKalle Valo }
1471e705c121SKalle Valo #endif /* CONFIG_IWLWIFI_DEBUG */
1472e705c121SKalle Valo 
iwl_mvm_get_hwrate_chan_width(u32 chan_width)1473dc52fac3SMiri Korenblit static int iwl_mvm_get_hwrate_chan_width(u32 chan_width)
1474dc52fac3SMiri Korenblit {
1475dc52fac3SMiri Korenblit 	switch (chan_width) {
1476dc52fac3SMiri Korenblit 	case RATE_MCS_CHAN_WIDTH_20:
1477dc52fac3SMiri Korenblit 		return 0;
1478dc52fac3SMiri Korenblit 	case RATE_MCS_CHAN_WIDTH_40:
1479dc52fac3SMiri Korenblit 		return IEEE80211_TX_RC_40_MHZ_WIDTH;
1480dc52fac3SMiri Korenblit 	case RATE_MCS_CHAN_WIDTH_80:
1481dc52fac3SMiri Korenblit 		return IEEE80211_TX_RC_80_MHZ_WIDTH;
1482dc52fac3SMiri Korenblit 	case RATE_MCS_CHAN_WIDTH_160:
1483dc52fac3SMiri Korenblit 		return IEEE80211_TX_RC_160_MHZ_WIDTH;
1484dc52fac3SMiri Korenblit 	default:
1485dc52fac3SMiri Korenblit 		return 0;
1486dc52fac3SMiri Korenblit 	}
1487dc52fac3SMiri Korenblit }
1488dc52fac3SMiri Korenblit 
iwl_mvm_hwrate_to_tx_rate(u32 rate_n_flags,enum nl80211_band band,struct ieee80211_tx_rate * r)1489e705c121SKalle Valo void iwl_mvm_hwrate_to_tx_rate(u32 rate_n_flags,
149057fbcce3SJohannes Berg 			       enum nl80211_band band,
1491e705c121SKalle Valo 			       struct ieee80211_tx_rate *r)
1492e705c121SKalle Valo {
1493dc52fac3SMiri Korenblit 	u32 format = rate_n_flags & RATE_MCS_MOD_TYPE_MSK;
1494dc52fac3SMiri Korenblit 	u32 rate = format == RATE_MCS_HT_MSK ?
1495dc52fac3SMiri Korenblit 		RATE_HT_MCS_INDEX(rate_n_flags) :
1496dc52fac3SMiri Korenblit 		rate_n_flags & RATE_MCS_CODE_MSK;
1497dc52fac3SMiri Korenblit 
1498dc52fac3SMiri Korenblit 	r->flags |=
1499dc52fac3SMiri Korenblit 		iwl_mvm_get_hwrate_chan_width(rate_n_flags &
1500dc52fac3SMiri Korenblit 					      RATE_MCS_CHAN_WIDTH_MSK);
1501dc52fac3SMiri Korenblit 
1502dc52fac3SMiri Korenblit 	if (rate_n_flags & RATE_MCS_SGI_MSK)
1503dc52fac3SMiri Korenblit 		r->flags |= IEEE80211_TX_RC_SHORT_GI;
1504dc52fac3SMiri Korenblit 	if (format ==  RATE_MCS_HT_MSK) {
1505dc52fac3SMiri Korenblit 		r->flags |= IEEE80211_TX_RC_MCS;
1506dc52fac3SMiri Korenblit 		r->idx = rate;
1507dc52fac3SMiri Korenblit 	} else if (format ==  RATE_MCS_VHT_MSK) {
1508dc52fac3SMiri Korenblit 		ieee80211_rate_set_vht(r, rate,
1509774302d2SMordechay Goodstein 				       FIELD_GET(RATE_MCS_NSS_MSK,
1510774302d2SMordechay Goodstein 						 rate_n_flags) + 1);
1511dc52fac3SMiri Korenblit 		r->flags |= IEEE80211_TX_RC_VHT_MCS;
1512dc52fac3SMiri Korenblit 	} else if (format == RATE_MCS_HE_MSK) {
1513dc52fac3SMiri Korenblit 		/* mac80211 cannot do this without ieee80211_tx_status_ext()
1514dc52fac3SMiri Korenblit 		 * but it only matters for radiotap */
1515dc52fac3SMiri Korenblit 		r->idx = 0;
1516dc52fac3SMiri Korenblit 	} else {
1517dc52fac3SMiri Korenblit 		r->idx = iwl_mvm_legacy_hw_idx_to_mac80211_idx(rate_n_flags,
1518dc52fac3SMiri Korenblit 							       band);
1519dc52fac3SMiri Korenblit 	}
1520dc52fac3SMiri Korenblit }
1521dc52fac3SMiri Korenblit 
iwl_mvm_hwrate_to_tx_rate_v1(u32 rate_n_flags,enum nl80211_band band,struct ieee80211_tx_rate * r)1522dc52fac3SMiri Korenblit void iwl_mvm_hwrate_to_tx_rate_v1(u32 rate_n_flags,
1523dc52fac3SMiri Korenblit 				  enum nl80211_band band,
1524dc52fac3SMiri Korenblit 				  struct ieee80211_tx_rate *r)
1525dc52fac3SMiri Korenblit {
1526e705c121SKalle Valo 	if (rate_n_flags & RATE_HT_MCS_GF_MSK)
1527e705c121SKalle Valo 		r->flags |= IEEE80211_TX_RC_GREEN_FIELD;
1528dc52fac3SMiri Korenblit 
1529dc52fac3SMiri Korenblit 	r->flags |=
1530dc52fac3SMiri Korenblit 		iwl_mvm_get_hwrate_chan_width(rate_n_flags &
1531dc52fac3SMiri Korenblit 					      RATE_MCS_CHAN_WIDTH_MSK_V1);
1532dc52fac3SMiri Korenblit 
153348c6ebc1SMiri Korenblit 	if (rate_n_flags & RATE_MCS_SGI_MSK_V1)
1534e705c121SKalle Valo 		r->flags |= IEEE80211_TX_RC_SHORT_GI;
153548c6ebc1SMiri Korenblit 	if (rate_n_flags & RATE_MCS_HT_MSK_V1) {
1536e705c121SKalle Valo 		r->flags |= IEEE80211_TX_RC_MCS;
153748c6ebc1SMiri Korenblit 		r->idx = rate_n_flags & RATE_HT_MCS_INDEX_MSK_V1;
153848c6ebc1SMiri Korenblit 	} else if (rate_n_flags & RATE_MCS_VHT_MSK_V1) {
1539e705c121SKalle Valo 		ieee80211_rate_set_vht(
1540e705c121SKalle Valo 			r, rate_n_flags & RATE_VHT_MCS_RATE_CODE_MSK,
1541774302d2SMordechay Goodstein 			FIELD_GET(RATE_MCS_NSS_MSK, rate_n_flags) + 1);
1542e705c121SKalle Valo 		r->flags |= IEEE80211_TX_RC_VHT_MCS;
1543e705c121SKalle Valo 	} else {
1544e705c121SKalle Valo 		r->idx = iwl_mvm_legacy_rate_to_mac80211_idx(rate_n_flags,
1545e705c121SKalle Valo 							     band);
1546e705c121SKalle Valo 	}
1547e705c121SKalle Valo }
1548e705c121SKalle Valo 
154991b4780fSLee Jones /*
1550e705c121SKalle Valo  * translate ucode response to mac80211 tx status control values
1551e705c121SKalle Valo  */
iwl_mvm_hwrate_to_tx_status(const struct iwl_fw * fw,u32 rate_n_flags,struct ieee80211_tx_info * info)1552dc52fac3SMiri Korenblit static void iwl_mvm_hwrate_to_tx_status(const struct iwl_fw *fw,
1553dc52fac3SMiri Korenblit 					u32 rate_n_flags,
1554e705c121SKalle Valo 					struct ieee80211_tx_info *info)
1555e705c121SKalle Valo {
1556e705c121SKalle Valo 	struct ieee80211_tx_rate *r = &info->status.rates[0];
1557e705c121SKalle Valo 
1558dc52fac3SMiri Korenblit 	if (iwl_fw_lookup_notif_ver(fw, LONG_GROUP,
1559be8287c9SMiri Korenblit 				    TX_CMD, 0) <= 6)
1560dc52fac3SMiri Korenblit 		rate_n_flags = iwl_new_rate_from_v1(rate_n_flags);
1561dc52fac3SMiri Korenblit 
1562e705c121SKalle Valo 	info->status.antenna =
156357b7b345SMiri Korenblit 		((rate_n_flags & RATE_MCS_ANT_AB_MSK) >> RATE_MCS_ANT_POS);
1564dc52fac3SMiri Korenblit 	iwl_mvm_hwrate_to_tx_rate(rate_n_flags,
1565dc52fac3SMiri Korenblit 				  info->band, r);
1566e705c121SKalle Valo }
1567e705c121SKalle Valo 
iwl_mvm_tx_status_check_trigger(struct iwl_mvm * mvm,u32 status,__le16 frame_control)156825657fecSGolan Ben-Ami static void iwl_mvm_tx_status_check_trigger(struct iwl_mvm *mvm,
15690d65ce90SMordechay Goodstein 					    u32 status, __le16 frame_control)
157025657fecSGolan Ben-Ami {
157125657fecSGolan Ben-Ami 	struct iwl_fw_dbg_trigger_tlv *trig;
157225657fecSGolan Ben-Ami 	struct iwl_fw_dbg_trigger_tx_status *status_trig;
157325657fecSGolan Ben-Ami 	int i;
157425657fecSGolan Ben-Ami 
15750d65ce90SMordechay Goodstein 	if ((status & TX_STATUS_MSK) != TX_STATUS_SUCCESS) {
15760d65ce90SMordechay Goodstein 		enum iwl_fw_ini_time_point tp =
15770d65ce90SMordechay Goodstein 			IWL_FW_INI_TIME_POINT_TX_FAILED;
15780d65ce90SMordechay Goodstein 
15790d65ce90SMordechay Goodstein 		if (ieee80211_is_action(frame_control))
15800d65ce90SMordechay Goodstein 			tp = IWL_FW_INI_TIME_POINT_TX_WFD_ACTION_FRAME_FAILED;
15810d65ce90SMordechay Goodstein 
15820d65ce90SMordechay Goodstein 		iwl_dbg_tlv_time_point(&mvm->fwrt,
15830d65ce90SMordechay Goodstein 				       tp, NULL);
15840d65ce90SMordechay Goodstein 		return;
15850d65ce90SMordechay Goodstein 	}
15860d65ce90SMordechay Goodstein 
15876c042d75SSara Sharon 	trig = iwl_fw_dbg_trigger_on(&mvm->fwrt, NULL,
15886c042d75SSara Sharon 				     FW_DBG_TRIGGER_TX_STATUS);
15896c042d75SSara Sharon 	if (!trig)
159025657fecSGolan Ben-Ami 		return;
159125657fecSGolan Ben-Ami 
159225657fecSGolan Ben-Ami 	status_trig = (void *)trig->data;
159325657fecSGolan Ben-Ami 
159425657fecSGolan Ben-Ami 	for (i = 0; i < ARRAY_SIZE(status_trig->statuses); i++) {
159525657fecSGolan Ben-Ami 		/* don't collect on status 0 */
159625657fecSGolan Ben-Ami 		if (!status_trig->statuses[i].status)
159725657fecSGolan Ben-Ami 			break;
159825657fecSGolan Ben-Ami 
159925657fecSGolan Ben-Ami 		if (status_trig->statuses[i].status != (status & TX_STATUS_MSK))
160025657fecSGolan Ben-Ami 			continue;
160125657fecSGolan Ben-Ami 
16027174beb6SJohannes Berg 		iwl_fw_dbg_collect_trig(&mvm->fwrt, trig,
160325657fecSGolan Ben-Ami 					"Tx status %d was received",
160425657fecSGolan Ben-Ami 					status & TX_STATUS_MSK);
160525657fecSGolan Ben-Ami 		break;
160625657fecSGolan Ben-Ami 	}
160725657fecSGolan Ben-Ami }
160825657fecSGolan Ben-Ami 
160991b4780fSLee Jones /*
161012db294cSSara Sharon  * iwl_mvm_get_scd_ssn - returns the SSN of the SCD
161112db294cSSara Sharon  * @tx_resp: the Tx response from the fw (agg or non-agg)
161212db294cSSara Sharon  *
161312db294cSSara Sharon  * When the fw sends an AMPDU, it fetches the MPDUs one after the other. Since
161412db294cSSara Sharon  * it can't know that everything will go well until the end of the AMPDU, it
161512db294cSSara Sharon  * can't know in advance the number of MPDUs that will be sent in the current
161612db294cSSara Sharon  * batch. This is why it writes the agg Tx response while it fetches the MPDUs.
161712db294cSSara Sharon  * Hence, it can't know in advance what the SSN of the SCD will be at the end
161812db294cSSara Sharon  * of the batch. This is why the SSN of the SCD is written at the end of the
161912db294cSSara Sharon  * whole struct at a variable offset. This function knows how to cope with the
162012db294cSSara Sharon  * variable offset and returns the SSN of the SCD.
162167e7b24aSJohannes Berg  *
162267e7b24aSJohannes Berg  * For 22000-series and lower, this is just 12 bits. For later, 16 bits.
162312db294cSSara Sharon  */
iwl_mvm_get_scd_ssn(struct iwl_mvm * mvm,struct iwl_mvm_tx_resp * tx_resp)162412db294cSSara Sharon static inline u32 iwl_mvm_get_scd_ssn(struct iwl_mvm *mvm,
162512db294cSSara Sharon 				      struct iwl_mvm_tx_resp *tx_resp)
162612db294cSSara Sharon {
162767e7b24aSJohannes Berg 	u32 val = le32_to_cpup((__le32 *)iwl_mvm_get_agg_status(mvm, tx_resp) +
162867e7b24aSJohannes Berg 			       tx_resp->frame_count);
162967e7b24aSJohannes Berg 
163067e7b24aSJohannes Berg 	if (mvm->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210)
163167e7b24aSJohannes Berg 		return val & 0xFFFF;
163267e7b24aSJohannes Berg 	return val & 0xFFF;
163312db294cSSara Sharon }
163412db294cSSara Sharon 
iwl_mvm_rx_tx_cmd_single(struct iwl_mvm * mvm,struct iwl_rx_packet * pkt)1635e705c121SKalle Valo static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
1636e705c121SKalle Valo 				     struct iwl_rx_packet *pkt)
1637e705c121SKalle Valo {
1638e705c121SKalle Valo 	struct ieee80211_sta *sta;
1639e705c121SKalle Valo 	u16 sequence = le16_to_cpu(pkt->hdr.sequence);
1640e705c121SKalle Valo 	int txq_id = SEQ_TO_QUEUE(sequence);
1641a6a62193SJohannes Berg 	/* struct iwl_mvm_tx_resp_v3 is almost the same */
1642e705c121SKalle Valo 	struct iwl_mvm_tx_resp *tx_resp = (void *)pkt->data;
1643e705c121SKalle Valo 	int sta_id = IWL_MVM_TX_RES_GET_RA(tx_resp->ra_tid);
1644e705c121SKalle Valo 	int tid = IWL_MVM_TX_RES_GET_TID(tx_resp->ra_tid);
164512db294cSSara Sharon 	struct agg_tx_status *agg_status =
164612db294cSSara Sharon 		iwl_mvm_get_agg_status(mvm, tx_resp);
164712db294cSSara Sharon 	u32 status = le16_to_cpu(agg_status->status);
164812db294cSSara Sharon 	u16 ssn = iwl_mvm_get_scd_ssn(mvm, tx_resp);
1649e705c121SKalle Valo 	struct sk_buff_head skbs;
1650e705c121SKalle Valo 	u8 skb_freed = 0;
1651ea42d1cbSGregory Greenman 	u8 lq_color;
1652e705c121SKalle Valo 	u16 next_reclaimed, seq_ctl;
1653532beba3SEmmanuel Grumbach 	bool is_ndp = false;
1654e705c121SKalle Valo 
1655e705c121SKalle Valo 	__skb_queue_head_init(&skbs);
1656e705c121SKalle Valo 
165712db294cSSara Sharon 	if (iwl_mvm_has_new_tx_api(mvm))
1658a6a62193SJohannes Berg 		txq_id = le16_to_cpu(tx_resp->tx_queue);
165912db294cSSara Sharon 
1660e705c121SKalle Valo 	seq_ctl = le16_to_cpu(tx_resp->seq_ctl);
1661e705c121SKalle Valo 
1662e705c121SKalle Valo 	/* we can free until ssn % q.n_bd not inclusive */
1663fc163831SMiri Korenblit 	iwl_trans_reclaim(mvm->trans, txq_id, ssn, &skbs, false);
1664e705c121SKalle Valo 
1665e705c121SKalle Valo 	while (!skb_queue_empty(&skbs)) {
1666e705c121SKalle Valo 		struct sk_buff *skb = __skb_dequeue(&skbs);
1667e705c121SKalle Valo 		struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
1668941ab4ebSSara Sharon 		struct ieee80211_hdr *hdr = (void *)skb->data;
1669114db230SEmmanuel Grumbach 		bool flushed = false;
1670e705c121SKalle Valo 
1671e705c121SKalle Valo 		skb_freed++;
1672e705c121SKalle Valo 
1673e705c121SKalle Valo 		iwl_trans_free_tx_cmd(mvm->trans, info->driver_data[1]);
1674e705c121SKalle Valo 
1675e705c121SKalle Valo 		memset(&info->status, 0, sizeof(info->status));
1676e8fbe99eSBen Greear 		info->flags &= ~(IEEE80211_TX_STAT_ACK | IEEE80211_TX_STAT_TX_FILTERED);
1677e705c121SKalle Valo 
1678e705c121SKalle Valo 		/* inform mac80211 about what happened with the frame */
1679e705c121SKalle Valo 		switch (status & TX_STATUS_MSK) {
1680e705c121SKalle Valo 		case TX_STATUS_SUCCESS:
1681e705c121SKalle Valo 		case TX_STATUS_DIRECT_DONE:
1682e705c121SKalle Valo 			info->flags |= IEEE80211_TX_STAT_ACK;
1683e705c121SKalle Valo 			break;
1684114db230SEmmanuel Grumbach 		case TX_STATUS_FAIL_FIFO_FLUSHED:
1685114db230SEmmanuel Grumbach 		case TX_STATUS_FAIL_DRAIN_FLOW:
1686114db230SEmmanuel Grumbach 			flushed = true;
1687114db230SEmmanuel Grumbach 			break;
1688e705c121SKalle Valo 		case TX_STATUS_FAIL_DEST_PS:
1689c8f54701SJohannes Berg 			/* the FW should have stopped the queue and not
16909a3fcf91SSara Sharon 			 * return this status
16919a3fcf91SSara Sharon 			 */
169275da590fSJohannes Berg 			IWL_ERR_LIMIT(mvm,
169375da590fSJohannes Berg 				      "FW reported TX filtered, status=0x%x, FC=0x%x\n",
169475da590fSJohannes Berg 				      status, le16_to_cpu(hdr->frame_control));
1695e705c121SKalle Valo 			info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
1696e705c121SKalle Valo 			break;
1697e705c121SKalle Valo 		default:
1698e705c121SKalle Valo 			break;
1699e705c121SKalle Valo 		}
1700e705c121SKalle Valo 
1701656fca00SAvraham Stern 		if ((status & TX_STATUS_MSK) != TX_STATUS_SUCCESS &&
1702656fca00SAvraham Stern 		    ieee80211_is_mgmt(hdr->frame_control))
1703656fca00SAvraham Stern 			iwl_mvm_toggle_tx_ant(mvm, &mvm->mgmt_last_antenna_idx);
1704656fca00SAvraham Stern 
17051a19c139SSara Sharon 		/*
17061a19c139SSara Sharon 		 * If we are freeing multiple frames, mark all the frames
17071a19c139SSara Sharon 		 * but the first one as acked, since they were acknowledged
17081a19c139SSara Sharon 		 * before
17091a19c139SSara Sharon 		 * */
17101a19c139SSara Sharon 		if (skb_freed > 1)
17111a19c139SSara Sharon 			info->flags |= IEEE80211_TX_STAT_ACK;
17121a19c139SSara Sharon 
17130d65ce90SMordechay Goodstein 		iwl_mvm_tx_status_check_trigger(mvm, status, hdr->frame_control);
171425657fecSGolan Ben-Ami 
1715e705c121SKalle Valo 		info->status.rates[0].count = tx_resp->failure_frame + 1;
1716dc52fac3SMiri Korenblit 
1717dc52fac3SMiri Korenblit 		iwl_mvm_hwrate_to_tx_status(mvm->fw,
1718dc52fac3SMiri Korenblit 					    le32_to_cpu(tx_resp->initial_rate),
1719e705c121SKalle Valo 					    info);
1720dc52fac3SMiri Korenblit 
1721dc52fac3SMiri Korenblit 		/* Don't assign the converted initial_rate, because driver
1722dc52fac3SMiri Korenblit 		 * TLC uses this and doesn't support the new FW rate
1723dc52fac3SMiri Korenblit 		 */
1724e705c121SKalle Valo 		info->status.status_driver_data[1] =
1725e705c121SKalle Valo 			(void *)(uintptr_t)le32_to_cpu(tx_resp->initial_rate);
1726e705c121SKalle Valo 
1727e705c121SKalle Valo 		/* Single frame failure in an AMPDU queue => send BAR */
1728c56108b5SSara Sharon 		if (info->flags & IEEE80211_TX_CTL_AMPDU &&
1729e705c121SKalle Valo 		    !(info->flags & IEEE80211_TX_STAT_ACK) &&
1730114db230SEmmanuel Grumbach 		    !(info->flags & IEEE80211_TX_STAT_TX_FILTERED) && !flushed)
1731e705c121SKalle Valo 			info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;
1732c56108b5SSara Sharon 		info->flags &= ~IEEE80211_TX_CTL_AMPDU;
1733e705c121SKalle Valo 
1734941ab4ebSSara Sharon 		/* W/A FW bug: seq_ctl is wrong upon failure / BAR frame */
1735941ab4ebSSara Sharon 		if (ieee80211_is_back_req(hdr->frame_control))
1736941ab4ebSSara Sharon 			seq_ctl = 0;
1737941ab4ebSSara Sharon 		else if (status != TX_STATUS_SUCCESS)
1738e705c121SKalle Valo 			seq_ctl = le16_to_cpu(hdr->seq_ctrl);
1739e705c121SKalle Valo 
1740532beba3SEmmanuel Grumbach 		if (unlikely(!seq_ctl)) {
1741532beba3SEmmanuel Grumbach 			/*
1742532beba3SEmmanuel Grumbach 			 * If it is an NDP, we can't update next_reclaim since
1743532beba3SEmmanuel Grumbach 			 * its sequence control is 0. Note that for that same
1744532beba3SEmmanuel Grumbach 			 * reason, NDPs are never sent to A-MPDU'able queues
1745532beba3SEmmanuel Grumbach 			 * so that we can never have more than one freed frame
1746532beba3SEmmanuel Grumbach 			 * for a single Tx resonse (see WARN_ON below).
1747532beba3SEmmanuel Grumbach 			 */
1748532beba3SEmmanuel Grumbach 			if (ieee80211_is_qos_nullfunc(hdr->frame_control))
1749532beba3SEmmanuel Grumbach 				is_ndp = true;
1750532beba3SEmmanuel Grumbach 		}
1751532beba3SEmmanuel Grumbach 
1752e705c121SKalle Valo 		/*
1753e705c121SKalle Valo 		 * TODO: this is not accurate if we are freeing more than one
1754e705c121SKalle Valo 		 * packet.
1755e705c121SKalle Valo 		 */
1756e705c121SKalle Valo 		info->status.tx_time =
1757e705c121SKalle Valo 			le16_to_cpu(tx_resp->wireless_media_time);
1758e705c121SKalle Valo 		BUILD_BUG_ON(ARRAY_SIZE(info->status.status_driver_data) < 1);
1759ea42d1cbSGregory Greenman 		lq_color = TX_RES_RATE_TABLE_COL_GET(tx_resp->tlc_info);
1760e705c121SKalle Valo 		info->status.status_driver_data[0] =
1761ea42d1cbSGregory Greenman 			RS_DRV_DATA_PACK(lq_color, tx_resp->reduced_tpc);
1762e705c121SKalle Valo 
1763c7eca79dSAvraham Stern 		if (likely(!iwl_mvm_time_sync_frame(mvm, skb, hdr->addr1)))
1764e705c121SKalle Valo 			ieee80211_tx_status(mvm->hw, skb);
1765e705c121SKalle Valo 	}
1766e705c121SKalle Valo 
1767c8f54701SJohannes Berg 	/* This is an aggregation queue or might become one, so we use
1768c8f54701SJohannes Berg 	 * the ssn since: ssn = wifi seq_num % 256.
1769e705c121SKalle Valo 	 * The seq_ctl is the sequence control of the packet to which
1770e705c121SKalle Valo 	 * this Tx response relates. But if there is a hole in the
1771e705c121SKalle Valo 	 * bitmap of the BA we received, this Tx response may allow to
1772e705c121SKalle Valo 	 * reclaim the hole and all the subsequent packets that were
1773e705c121SKalle Valo 	 * already acked. In that case, seq_ctl != ssn, and the next
1774e705c121SKalle Valo 	 * packet to be reclaimed will be ssn and not seq_ctl. In that
1775e705c121SKalle Valo 	 * case, several packets will be reclaimed even if
1776e705c121SKalle Valo 	 * frame_count = 1.
1777e705c121SKalle Valo 	 *
1778e705c121SKalle Valo 	 * The ssn is the index (% 256) of the latest packet that has
1779e705c121SKalle Valo 	 * treated (acked / dropped) + 1.
1780e705c121SKalle Valo 	 */
1781e705c121SKalle Valo 	next_reclaimed = ssn;
1782e705c121SKalle Valo 
1783e705c121SKalle Valo 	IWL_DEBUG_TX_REPLY(mvm,
1784e705c121SKalle Valo 			   "TXQ %d status %s (0x%08x)\n",
1785e705c121SKalle Valo 			   txq_id, iwl_mvm_get_tx_fail_reason(status), status);
1786e705c121SKalle Valo 
1787e705c121SKalle Valo 	IWL_DEBUG_TX_REPLY(mvm,
1788e705c121SKalle Valo 			   "\t\t\t\tinitial_rate 0x%x retries %d, idx=%d ssn=%d next_reclaimed=0x%x seq_ctl=0x%x\n",
1789e705c121SKalle Valo 			   le32_to_cpu(tx_resp->initial_rate),
1790e705c121SKalle Valo 			   tx_resp->failure_frame, SEQ_TO_INDEX(sequence),
1791e705c121SKalle Valo 			   ssn, next_reclaimed, seq_ctl);
1792e705c121SKalle Valo 
1793e705c121SKalle Valo 	rcu_read_lock();
1794e705c121SKalle Valo 
1795e705c121SKalle Valo 	sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]);
1796e705c121SKalle Valo 	/*
1797e705c121SKalle Valo 	 * sta can't be NULL otherwise it'd mean that the sta has been freed in
1798e705c121SKalle Valo 	 * the firmware while we still have packets for it in the Tx queues.
1799e705c121SKalle Valo 	 */
1800e705c121SKalle Valo 	if (WARN_ON_ONCE(!sta))
1801e705c121SKalle Valo 		goto out;
1802e705c121SKalle Valo 
1803e705c121SKalle Valo 	if (!IS_ERR(sta)) {
1804a124caf8SSara Sharon 		struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
1805e705c121SKalle Valo 
18067d9d0d56SLuca Coelho 		iwl_mvm_tx_airtime(mvm, mvmsta,
18077d9d0d56SLuca Coelho 				   le16_to_cpu(tx_resp->wireless_media_time));
18087d9d0d56SLuca Coelho 
18090dde2440SAvraham Stern 		if ((status & TX_STATUS_MSK) != TX_STATUS_SUCCESS &&
18100dde2440SAvraham Stern 		    mvmsta->sta_state < IEEE80211_STA_AUTHORIZED)
18110dde2440SAvraham Stern 			iwl_mvm_toggle_tx_ant(mvm, &mvmsta->tx_ant);
18120dde2440SAvraham Stern 
18132210f695SAvraham Stern 		if (sta->wme && tid != IWL_MGMT_TID) {
1814e705c121SKalle Valo 			struct iwl_mvm_tid_data *tid_data =
1815e705c121SKalle Valo 				&mvmsta->tid_data[tid];
181636be0eb6SEmmanuel Grumbach 			bool send_eosp_ndp = false;
1817e705c121SKalle Valo 
1818e705c121SKalle Valo 			spin_lock_bh(&mvmsta->lock);
1819cf961e16SLiad Kaufman 
1820532beba3SEmmanuel Grumbach 			if (!is_ndp) {
1821e705c121SKalle Valo 				tid_data->next_reclaimed = next_reclaimed;
1822532beba3SEmmanuel Grumbach 				IWL_DEBUG_TX_REPLY(mvm,
1823532beba3SEmmanuel Grumbach 						   "Next reclaimed packet:%d\n",
1824e705c121SKalle Valo 						   next_reclaimed);
1825532beba3SEmmanuel Grumbach 			} else {
1826532beba3SEmmanuel Grumbach 				IWL_DEBUG_TX_REPLY(mvm,
1827532beba3SEmmanuel Grumbach 						   "NDP - don't update next_reclaimed\n");
1828532beba3SEmmanuel Grumbach 			}
1829532beba3SEmmanuel Grumbach 
1830e705c121SKalle Valo 			iwl_mvm_check_ratid_empty(mvm, sta, tid);
183136be0eb6SEmmanuel Grumbach 
183236be0eb6SEmmanuel Grumbach 			if (mvmsta->sleep_tx_count) {
183336be0eb6SEmmanuel Grumbach 				mvmsta->sleep_tx_count--;
183436be0eb6SEmmanuel Grumbach 				if (mvmsta->sleep_tx_count &&
1835dd32162dSLiad Kaufman 				    !iwl_mvm_tid_queued(mvm, tid_data)) {
183636be0eb6SEmmanuel Grumbach 					/*
183736be0eb6SEmmanuel Grumbach 					 * The number of frames in the queue
183836be0eb6SEmmanuel Grumbach 					 * dropped to 0 even if we sent less
183936be0eb6SEmmanuel Grumbach 					 * frames than we thought we had on the
184036be0eb6SEmmanuel Grumbach 					 * Tx queue.
184136be0eb6SEmmanuel Grumbach 					 * This means we had holes in the BA
184236be0eb6SEmmanuel Grumbach 					 * window that we just filled, ask
184336be0eb6SEmmanuel Grumbach 					 * mac80211 to send EOSP since the
184436be0eb6SEmmanuel Grumbach 					 * firmware won't know how to do that.
184536be0eb6SEmmanuel Grumbach 					 * Send NDP and the firmware will send
184636be0eb6SEmmanuel Grumbach 					 * EOSP notification that will trigger
184736be0eb6SEmmanuel Grumbach 					 * a call to ieee80211_sta_eosp().
184836be0eb6SEmmanuel Grumbach 					 */
184936be0eb6SEmmanuel Grumbach 					send_eosp_ndp = true;
185036be0eb6SEmmanuel Grumbach 				}
185136be0eb6SEmmanuel Grumbach 			}
185236be0eb6SEmmanuel Grumbach 
1853e705c121SKalle Valo 			spin_unlock_bh(&mvmsta->lock);
185436be0eb6SEmmanuel Grumbach 			if (send_eosp_ndp) {
185536be0eb6SEmmanuel Grumbach 				iwl_mvm_sta_modify_sleep_tx_count(mvm, sta,
185636be0eb6SEmmanuel Grumbach 					IEEE80211_FRAME_RELEASE_UAPSD,
185736be0eb6SEmmanuel Grumbach 					1, tid, false, false);
185836be0eb6SEmmanuel Grumbach 				mvmsta->sleep_tx_count = 0;
185936be0eb6SEmmanuel Grumbach 				ieee80211_send_eosp_nullfunc(sta, tid);
186036be0eb6SEmmanuel Grumbach 			}
1861e705c121SKalle Valo 		}
1862e705c121SKalle Valo 
1863e705c121SKalle Valo 		if (mvmsta->next_status_eosp) {
1864e705c121SKalle Valo 			mvmsta->next_status_eosp = false;
1865e705c121SKalle Valo 			ieee80211_sta_eosp(sta);
1866e705c121SKalle Valo 		}
1867e705c121SKalle Valo 	}
1868e705c121SKalle Valo out:
1869e705c121SKalle Valo 	rcu_read_unlock();
1870e705c121SKalle Valo }
1871e705c121SKalle Valo 
1872e705c121SKalle Valo #ifdef CONFIG_IWLWIFI_DEBUG
1873e705c121SKalle Valo #define AGG_TX_STATE_(x) case AGG_TX_STATE_ ## x: return #x
iwl_get_agg_tx_status(u16 status)1874e705c121SKalle Valo static const char *iwl_get_agg_tx_status(u16 status)
1875e705c121SKalle Valo {
1876e705c121SKalle Valo 	switch (status & AGG_TX_STATE_STATUS_MSK) {
1877e705c121SKalle Valo 	AGG_TX_STATE_(TRANSMITTED);
1878e705c121SKalle Valo 	AGG_TX_STATE_(UNDERRUN);
1879e705c121SKalle Valo 	AGG_TX_STATE_(BT_PRIO);
1880e705c121SKalle Valo 	AGG_TX_STATE_(FEW_BYTES);
1881e705c121SKalle Valo 	AGG_TX_STATE_(ABORT);
1882f9cd3e08SEmmanuel Grumbach 	AGG_TX_STATE_(TX_ON_AIR_DROP);
1883e705c121SKalle Valo 	AGG_TX_STATE_(LAST_SENT_TRY_CNT);
1884e705c121SKalle Valo 	AGG_TX_STATE_(LAST_SENT_BT_KILL);
1885e705c121SKalle Valo 	AGG_TX_STATE_(SCD_QUERY);
1886e705c121SKalle Valo 	AGG_TX_STATE_(TEST_BAD_CRC32);
1887e705c121SKalle Valo 	AGG_TX_STATE_(RESPONSE);
1888e705c121SKalle Valo 	AGG_TX_STATE_(DUMP_TX);
1889e705c121SKalle Valo 	AGG_TX_STATE_(DELAY_TX);
1890e705c121SKalle Valo 	}
1891e705c121SKalle Valo 
1892e705c121SKalle Valo 	return "UNKNOWN";
1893e705c121SKalle Valo }
1894e705c121SKalle Valo 
iwl_mvm_rx_tx_cmd_agg_dbg(struct iwl_mvm * mvm,struct iwl_rx_packet * pkt)1895e705c121SKalle Valo static void iwl_mvm_rx_tx_cmd_agg_dbg(struct iwl_mvm *mvm,
1896e705c121SKalle Valo 				      struct iwl_rx_packet *pkt)
1897e705c121SKalle Valo {
1898e705c121SKalle Valo 	struct iwl_mvm_tx_resp *tx_resp = (void *)pkt->data;
189912db294cSSara Sharon 	struct agg_tx_status *frame_status =
190012db294cSSara Sharon 		iwl_mvm_get_agg_status(mvm, tx_resp);
1901e705c121SKalle Valo 	int i;
19020d65ce90SMordechay Goodstein 	bool tirgger_timepoint = false;
1903e705c121SKalle Valo 
1904e705c121SKalle Valo 	for (i = 0; i < tx_resp->frame_count; i++) {
1905e705c121SKalle Valo 		u16 fstatus = le16_to_cpu(frame_status[i].status);
19060d65ce90SMordechay Goodstein 		/* In case one frame wasn't transmitted trigger time point */
19070d65ce90SMordechay Goodstein 		tirgger_timepoint |= ((fstatus & AGG_TX_STATE_STATUS_MSK) !=
19080d65ce90SMordechay Goodstein 				      AGG_TX_STATE_TRANSMITTED);
1909e705c121SKalle Valo 		IWL_DEBUG_TX_REPLY(mvm,
1910e705c121SKalle Valo 				   "status %s (0x%04x), try-count (%d) seq (0x%x)\n",
1911e705c121SKalle Valo 				   iwl_get_agg_tx_status(fstatus),
1912e705c121SKalle Valo 				   fstatus & AGG_TX_STATE_STATUS_MSK,
1913e705c121SKalle Valo 				   (fstatus & AGG_TX_STATE_TRY_CNT_MSK) >>
1914e705c121SKalle Valo 					AGG_TX_STATE_TRY_CNT_POS,
1915e705c121SKalle Valo 				   le16_to_cpu(frame_status[i].sequence));
1916e705c121SKalle Valo 	}
19170d65ce90SMordechay Goodstein 
19180d65ce90SMordechay Goodstein 	if (tirgger_timepoint)
19190d65ce90SMordechay Goodstein 		iwl_dbg_tlv_time_point(&mvm->fwrt,
19200d65ce90SMordechay Goodstein 				       IWL_FW_INI_TIME_POINT_TX_FAILED, NULL);
19210d65ce90SMordechay Goodstein 
1922e705c121SKalle Valo }
1923e705c121SKalle Valo #else
iwl_mvm_rx_tx_cmd_agg_dbg(struct iwl_mvm * mvm,struct iwl_rx_packet * pkt)1924e705c121SKalle Valo static void iwl_mvm_rx_tx_cmd_agg_dbg(struct iwl_mvm *mvm,
1925e705c121SKalle Valo 				      struct iwl_rx_packet *pkt)
1926e705c121SKalle Valo {}
1927e705c121SKalle Valo #endif /* CONFIG_IWLWIFI_DEBUG */
1928e705c121SKalle Valo 
iwl_mvm_rx_tx_cmd_agg(struct iwl_mvm * mvm,struct iwl_rx_packet * pkt)1929e705c121SKalle Valo static void iwl_mvm_rx_tx_cmd_agg(struct iwl_mvm *mvm,
1930e705c121SKalle Valo 				  struct iwl_rx_packet *pkt)
1931e705c121SKalle Valo {
1932e705c121SKalle Valo 	struct iwl_mvm_tx_resp *tx_resp = (void *)pkt->data;
1933e705c121SKalle Valo 	int sta_id = IWL_MVM_TX_RES_GET_RA(tx_resp->ra_tid);
1934e705c121SKalle Valo 	int tid = IWL_MVM_TX_RES_GET_TID(tx_resp->ra_tid);
1935e705c121SKalle Valo 	u16 sequence = le16_to_cpu(pkt->hdr.sequence);
193613303c0fSSara Sharon 	struct iwl_mvm_sta *mvmsta;
1937cf961e16SLiad Kaufman 	int queue = SEQ_TO_QUEUE(sequence);
19382210f695SAvraham Stern 	struct ieee80211_sta *sta;
1939e705c121SKalle Valo 
1940c8f54701SJohannes Berg 	if (WARN_ON_ONCE(queue < IWL_MVM_DQA_MIN_DATA_QUEUE &&
1941c8f54701SJohannes Berg 			 (queue != IWL_MVM_DQA_BSS_CLIENT_QUEUE)))
1942e705c121SKalle Valo 		return;
1943e705c121SKalle Valo 
1944e705c121SKalle Valo 	iwl_mvm_rx_tx_cmd_agg_dbg(mvm, pkt);
1945e705c121SKalle Valo 
1946e705c121SKalle Valo 	rcu_read_lock();
1947e705c121SKalle Valo 
194813303c0fSSara Sharon 	mvmsta = iwl_mvm_sta_from_staid_rcu(mvm, sta_id);
1949e705c121SKalle Valo 
19502210f695SAvraham Stern 	sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]);
195168182662SGregory Greenman 	if (WARN_ON_ONCE(IS_ERR_OR_NULL(sta) || !sta->wme)) {
19522210f695SAvraham Stern 		rcu_read_unlock();
19532210f695SAvraham Stern 		return;
19542210f695SAvraham Stern 	}
19552210f695SAvraham Stern 
195613303c0fSSara Sharon 	if (!WARN_ON_ONCE(!mvmsta)) {
1957e705c121SKalle Valo 		mvmsta->tid_data[tid].rate_n_flags =
1958e705c121SKalle Valo 			le32_to_cpu(tx_resp->initial_rate);
1959e705c121SKalle Valo 		mvmsta->tid_data[tid].tx_time =
1960e705c121SKalle Valo 			le16_to_cpu(tx_resp->wireless_media_time);
1961ea42d1cbSGregory Greenman 		mvmsta->tid_data[tid].lq_color =
1962b67ce55dSSara Sharon 			TX_RES_RATE_TABLE_COL_GET(tx_resp->tlc_info);
19637d9d0d56SLuca Coelho 		iwl_mvm_tx_airtime(mvm, mvmsta,
19647d9d0d56SLuca Coelho 				   le16_to_cpu(tx_resp->wireless_media_time));
1965e705c121SKalle Valo 	}
1966e705c121SKalle Valo 
1967e705c121SKalle Valo 	rcu_read_unlock();
1968e705c121SKalle Valo }
1969e705c121SKalle Valo 
iwl_mvm_rx_tx_cmd(struct iwl_mvm * mvm,struct iwl_rx_cmd_buffer * rxb)1970e705c121SKalle Valo void iwl_mvm_rx_tx_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb)
1971e705c121SKalle Valo {
1972e705c121SKalle Valo 	struct iwl_rx_packet *pkt = rxb_addr(rxb);
1973e705c121SKalle Valo 	struct iwl_mvm_tx_resp *tx_resp = (void *)pkt->data;
1974e705c121SKalle Valo 
1975e705c121SKalle Valo 	if (tx_resp->frame_count == 1)
1976e705c121SKalle Valo 		iwl_mvm_rx_tx_cmd_single(mvm, pkt);
1977e705c121SKalle Valo 	else
1978e705c121SKalle Valo 		iwl_mvm_rx_tx_cmd_agg(mvm, pkt);
1979e705c121SKalle Valo }
1980e705c121SKalle Valo 
iwl_mvm_tx_reclaim(struct iwl_mvm * mvm,int sta_id,int tid,int txq,int index,struct ieee80211_tx_info * tx_info,u32 rate,bool is_flush)1981c46e7724SSara Sharon static void iwl_mvm_tx_reclaim(struct iwl_mvm *mvm, int sta_id, int tid,
1982c46e7724SSara Sharon 			       int txq, int index,
1983d4e3a341SMordechay Goodstein 			       struct ieee80211_tx_info *tx_info, u32 rate,
1984d4e3a341SMordechay Goodstein 			       bool is_flush)
1985e705c121SKalle Valo {
1986e705c121SKalle Valo 	struct sk_buff_head reclaimed_skbs;
19872b3eb122SNaftali Goldstein 	struct iwl_mvm_tid_data *tid_data = NULL;
1988e705c121SKalle Valo 	struct ieee80211_sta *sta;
19892b3eb122SNaftali Goldstein 	struct iwl_mvm_sta *mvmsta = NULL;
1990e705c121SKalle Valo 	struct sk_buff *skb;
1991c46e7724SSara Sharon 	int freed;
1992e705c121SKalle Valo 
1993be9ae34eSNathan Errera 	if (WARN_ONCE(sta_id >= mvm->fw->ucode_capa.num_stations ||
1994087428d3SLiad Kaufman 		      tid > IWL_MAX_TID_COUNT,
1995e705c121SKalle Valo 		      "sta_id %d tid %d", sta_id, tid))
1996e705c121SKalle Valo 		return;
1997e705c121SKalle Valo 
1998e705c121SKalle Valo 	rcu_read_lock();
1999e705c121SKalle Valo 
2000e705c121SKalle Valo 	sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]);
2001e705c121SKalle Valo 
2002e705c121SKalle Valo 	/* Reclaiming frames for a station that has been deleted ? */
20032b3eb122SNaftali Goldstein 	if (WARN_ON_ONCE(!sta)) {
2004e705c121SKalle Valo 		rcu_read_unlock();
2005e705c121SKalle Valo 		return;
2006e705c121SKalle Valo 	}
2007e705c121SKalle Valo 
2008e705c121SKalle Valo 	__skb_queue_head_init(&reclaimed_skbs);
2009e705c121SKalle Valo 
2010e705c121SKalle Valo 	/*
2011e705c121SKalle Valo 	 * Release all TFDs before the SSN, i.e. all TFDs in front of
2012e705c121SKalle Valo 	 * block-ack window (we assume that they've been successfully
2013e705c121SKalle Valo 	 * transmitted ... if not, it's too late anyway).
2014e705c121SKalle Valo 	 */
2015fc163831SMiri Korenblit 	iwl_trans_reclaim(mvm->trans, txq, index, &reclaimed_skbs, is_flush);
2016e705c121SKalle Valo 
20172b3eb122SNaftali Goldstein 	skb_queue_walk(&reclaimed_skbs, skb) {
20182b3eb122SNaftali Goldstein 		struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
20192b3eb122SNaftali Goldstein 
20202b3eb122SNaftali Goldstein 		iwl_trans_free_tx_cmd(mvm->trans, info->driver_data[1]);
20212b3eb122SNaftali Goldstein 
20222b3eb122SNaftali Goldstein 		memset(&info->status, 0, sizeof(info->status));
20232b3eb122SNaftali Goldstein 		/* Packet was transmitted successfully, failures come as single
20242b3eb122SNaftali Goldstein 		 * frames because before failing a frame the firmware transmits
20252b3eb122SNaftali Goldstein 		 * it without aggregation at least once.
20262b3eb122SNaftali Goldstein 		 */
2027d4e3a341SMordechay Goodstein 		if (!is_flush)
20282b3eb122SNaftali Goldstein 			info->flags |= IEEE80211_TX_STAT_ACK;
2029e8fbe99eSBen Greear 		else
2030e8fbe99eSBen Greear 			info->flags &= ~IEEE80211_TX_STAT_ACK;
20312b3eb122SNaftali Goldstein 	}
20322b3eb122SNaftali Goldstein 
20332b3eb122SNaftali Goldstein 	/*
20342b3eb122SNaftali Goldstein 	 * It's possible to get a BA response after invalidating the rcu (rcu is
20352b3eb122SNaftali Goldstein 	 * invalidated in order to prevent new Tx from being sent, but there may
20362b3eb122SNaftali Goldstein 	 * be some frames already in-flight).
20372b3eb122SNaftali Goldstein 	 * In this case we just want to reclaim, and could skip all the
20382b3eb122SNaftali Goldstein 	 * sta-dependent stuff since it's in the middle of being removed
20392b3eb122SNaftali Goldstein 	 * anyways.
20402b3eb122SNaftali Goldstein 	 */
20412b3eb122SNaftali Goldstein 	if (IS_ERR(sta))
20422b3eb122SNaftali Goldstein 		goto out;
20432b3eb122SNaftali Goldstein 
20442b3eb122SNaftali Goldstein 	mvmsta = iwl_mvm_sta_from_mac80211(sta);
20452b3eb122SNaftali Goldstein 	tid_data = &mvmsta->tid_data[tid];
20462b3eb122SNaftali Goldstein 
20472b3eb122SNaftali Goldstein 	if (tid_data->txq_id != txq) {
20482b3eb122SNaftali Goldstein 		IWL_ERR(mvm,
2049d4e3a341SMordechay Goodstein 			"invalid reclaim request: Q %d, tid %d\n",
20502b3eb122SNaftali Goldstein 			tid_data->txq_id, tid);
20512b3eb122SNaftali Goldstein 		rcu_read_unlock();
20522b3eb122SNaftali Goldstein 		return;
20532b3eb122SNaftali Goldstein 	}
20542b3eb122SNaftali Goldstein 
205583eabf1eSSara Sharon 	spin_lock_bh(&mvmsta->lock);
205683eabf1eSSara Sharon 
2057c46e7724SSara Sharon 	tid_data->next_reclaimed = index;
2058e705c121SKalle Valo 
2059e705c121SKalle Valo 	iwl_mvm_check_ratid_empty(mvm, sta, tid);
2060e705c121SKalle Valo 
2061e705c121SKalle Valo 	freed = 0;
2062ea42d1cbSGregory Greenman 
2063ea42d1cbSGregory Greenman 	/* pack lq color from tid_data along the reduced txp */
2064d4e3a341SMordechay Goodstein 	tx_info->status.status_driver_data[0] =
2065ea42d1cbSGregory Greenman 		RS_DRV_DATA_PACK(tid_data->lq_color,
2066d4e3a341SMordechay Goodstein 				 tx_info->status.status_driver_data[0]);
2067d4e3a341SMordechay Goodstein 	tx_info->status.status_driver_data[1] = (void *)(uintptr_t)rate;
2068e705c121SKalle Valo 
2069e705c121SKalle Valo 	skb_queue_walk(&reclaimed_skbs, skb) {
2070e705c121SKalle Valo 		struct ieee80211_hdr *hdr = (void *)skb->data;
2071e705c121SKalle Valo 		struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
2072e705c121SKalle Valo 
2073d4e3a341SMordechay Goodstein 		if (!is_flush) {
2074e705c121SKalle Valo 			if (ieee80211_is_data_qos(hdr->frame_control))
2075e705c121SKalle Valo 				freed++;
2076e705c121SKalle Valo 			else
2077087428d3SLiad Kaufman 				WARN_ON_ONCE(tid != IWL_MAX_TID_COUNT);
2078d4e3a341SMordechay Goodstein 		}
2079e705c121SKalle Valo 
2080e705c121SKalle Valo 		/* this is the first skb we deliver in this batch */
2081e705c121SKalle Valo 		/* put the rate scaling data there */
2082c46e7724SSara Sharon 		if (freed == 1) {
2083c46e7724SSara Sharon 			info->flags |= IEEE80211_TX_STAT_AMPDU;
2084d4e3a341SMordechay Goodstein 			memcpy(&info->status, &tx_info->status,
2085d4e3a341SMordechay Goodstein 			       sizeof(tx_info->status));
2086dc52fac3SMiri Korenblit 			iwl_mvm_hwrate_to_tx_status(mvm->fw, rate, info);
2087c46e7724SSara Sharon 		}
2088e705c121SKalle Valo 	}
2089e705c121SKalle Valo 
2090e705c121SKalle Valo 	spin_unlock_bh(&mvmsta->lock);
2091e705c121SKalle Valo 
2092e705c121SKalle Valo 	/* We got a BA notif with 0 acked or scd_ssn didn't progress which is
2093e705c121SKalle Valo 	 * possible (i.e. first MPDU in the aggregation wasn't acked)
2094e705c121SKalle Valo 	 * Still it's important to update RS about sent vs. acked.
2095e705c121SKalle Valo 	 */
20962c9b9220SGregory Greenman 	if (!is_flush && skb_queue_empty(&reclaimed_skbs) &&
20972c9b9220SGregory Greenman 	    !iwl_mvm_has_tlc_offload(mvm)) {
2098e705c121SKalle Valo 		struct ieee80211_chanctx_conf *chanctx_conf = NULL;
2099e705c121SKalle Valo 
21002c9b9220SGregory Greenman 		/* no TLC offload, so non-MLD mode */
2101e705c121SKalle Valo 		if (mvmsta->vif)
2102e705c121SKalle Valo 			chanctx_conf =
2103d0a9123eSJohannes Berg 				rcu_dereference(mvmsta->vif->bss_conf.chanctx_conf);
2104e705c121SKalle Valo 
2105e705c121SKalle Valo 		if (WARN_ON_ONCE(!chanctx_conf))
2106e705c121SKalle Valo 			goto out;
2107e705c121SKalle Valo 
2108d4e3a341SMordechay Goodstein 		tx_info->band = chanctx_conf->def.chan->band;
2109dc52fac3SMiri Korenblit 		iwl_mvm_hwrate_to_tx_status(mvm->fw, rate, tx_info);
2110e705c121SKalle Valo 
21112c9b9220SGregory Greenman 		IWL_DEBUG_TX_REPLY(mvm, "No reclaim. Update rs directly\n");
2112d4e3a341SMordechay Goodstein 		iwl_mvm_rs_tx_status(mvm, sta, tid, tx_info, false);
2113e705c121SKalle Valo 	}
2114e705c121SKalle Valo 
2115e705c121SKalle Valo out:
2116e705c121SKalle Valo 	rcu_read_unlock();
2117e705c121SKalle Valo 
2118e705c121SKalle Valo 	while (!skb_queue_empty(&reclaimed_skbs)) {
2119e705c121SKalle Valo 		skb = __skb_dequeue(&reclaimed_skbs);
2120e705c121SKalle Valo 		ieee80211_tx_status(mvm->hw, skb);
2121e705c121SKalle Valo 	}
2122e705c121SKalle Valo }
2123e705c121SKalle Valo 
iwl_mvm_rx_ba_notif(struct iwl_mvm * mvm,struct iwl_rx_cmd_buffer * rxb)2124c46e7724SSara Sharon void iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb)
2125c46e7724SSara Sharon {
2126c46e7724SSara Sharon 	struct iwl_rx_packet *pkt = rxb_addr(rxb);
2127afc857bcSJohannes Berg 	unsigned int pkt_len = iwl_rx_packet_payload_len(pkt);
2128c46e7724SSara Sharon 	int sta_id, tid, txq, index;
2129c46e7724SSara Sharon 	struct ieee80211_tx_info ba_info = {};
2130c46e7724SSara Sharon 	struct iwl_mvm_ba_notif *ba_notif;
2131c46e7724SSara Sharon 	struct iwl_mvm_tid_data *tid_data;
2132c46e7724SSara Sharon 	struct iwl_mvm_sta *mvmsta;
2133c46e7724SSara Sharon 
21349465c3f8SGregory Greenman 	ba_info.flags = IEEE80211_TX_STAT_AMPDU;
21359465c3f8SGregory Greenman 
2136c46e7724SSara Sharon 	if (iwl_mvm_has_new_tx_api(mvm)) {
2137c46e7724SSara Sharon 		struct iwl_mvm_compressed_ba_notif *ba_res =
2138c46e7724SSara Sharon 			(void *)pkt->data;
213941fd2fecSLiad Kaufman 		u8 lq_color = TX_RES_RATE_TABLE_COL_GET(ba_res->tlc_rate_info);
2140afc857bcSJohannes Berg 		u16 tfd_cnt;
2141cba46988SLiad Kaufman 		int i;
2142c46e7724SSara Sharon 
2143568db7fdSJohannes Berg 		if (IWL_FW_CHECK(mvm, sizeof(*ba_res) > pkt_len,
2144568db7fdSJohannes Berg 				 "short BA notification (%d)\n", pkt_len))
2145afc857bcSJohannes Berg 			return;
2146afc857bcSJohannes Berg 
2147c46e7724SSara Sharon 		sta_id = ba_res->sta_id;
2148c46e7724SSara Sharon 		ba_info.status.ampdu_ack_len = (u8)le16_to_cpu(ba_res->done);
2149c46e7724SSara Sharon 		ba_info.status.ampdu_len = (u8)le16_to_cpu(ba_res->txed);
2150c46e7724SSara Sharon 		ba_info.status.tx_time =
2151c46e7724SSara Sharon 			(u16)le32_to_cpu(ba_res->wireless_time);
2152c46e7724SSara Sharon 		ba_info.status.status_driver_data[0] =
2153c46e7724SSara Sharon 			(void *)(uintptr_t)ba_res->reduced_txp;
2154c46e7724SSara Sharon 
2155afc857bcSJohannes Berg 		tfd_cnt = le16_to_cpu(ba_res->tfd_cnt);
2156568db7fdSJohannes Berg 		if (!tfd_cnt)
2157568db7fdSJohannes Berg 			return;
2158568db7fdSJohannes Berg 
2159568db7fdSJohannes Berg 		if (IWL_FW_CHECK(mvm,
2160568db7fdSJohannes Berg 				 struct_size(ba_res, tfd, tfd_cnt) > pkt_len,
2161568db7fdSJohannes Berg 				 "short BA notification (tfds:%d, size:%d)\n",
2162568db7fdSJohannes Berg 				 tfd_cnt, pkt_len))
2163afc857bcSJohannes Berg 			return;
21649b1ea167SSara Sharon 
216541fd2fecSLiad Kaufman 		rcu_read_lock();
216641fd2fecSLiad Kaufman 
216741fd2fecSLiad Kaufman 		mvmsta = iwl_mvm_sta_from_staid_rcu(mvm, sta_id);
21682b3eb122SNaftali Goldstein 		/*
21692b3eb122SNaftali Goldstein 		 * It's possible to get a BA response after invalidating the rcu
21702b3eb122SNaftali Goldstein 		 * (rcu is invalidated in order to prevent new Tx from being
21712b3eb122SNaftali Goldstein 		 * sent, but there may be some frames already in-flight).
21722b3eb122SNaftali Goldstein 		 * In this case we just want to reclaim, and could skip all the
21732b3eb122SNaftali Goldstein 		 * sta-dependent stuff since it's in the middle of being removed
21742b3eb122SNaftali Goldstein 		 * anyways.
21752b3eb122SNaftali Goldstein 		 */
217641fd2fecSLiad Kaufman 
2177cba46988SLiad Kaufman 		/* Free per TID */
2178afc857bcSJohannes Berg 		for (i = 0; i < tfd_cnt; i++) {
2179cba46988SLiad Kaufman 			struct iwl_mvm_compressed_ba_tfd *ba_tfd =
2180cba46988SLiad Kaufman 				&ba_res->tfd[i];
2181cba46988SLiad Kaufman 
2182087428d3SLiad Kaufman 			tid = ba_tfd->tid;
2183087428d3SLiad Kaufman 			if (tid == IWL_MGMT_TID)
2184087428d3SLiad Kaufman 				tid = IWL_MAX_TID_COUNT;
2185087428d3SLiad Kaufman 
21862b3eb122SNaftali Goldstein 			if (mvmsta)
218741fd2fecSLiad Kaufman 				mvmsta->tid_data[i].lq_color = lq_color;
21882b3eb122SNaftali Goldstein 
2189087428d3SLiad Kaufman 			iwl_mvm_tx_reclaim(mvm, sta_id, tid,
2190cba46988SLiad Kaufman 					   (int)(le16_to_cpu(ba_tfd->q_num)),
2191cba46988SLiad Kaufman 					   le16_to_cpu(ba_tfd->tfd_index),
2192cba46988SLiad Kaufman 					   &ba_info,
2193d4e3a341SMordechay Goodstein 					   le32_to_cpu(ba_res->tx_rate), false);
2194cba46988SLiad Kaufman 		}
2195c46e7724SSara Sharon 
21962b3eb122SNaftali Goldstein 		if (mvmsta)
21977d9d0d56SLuca Coelho 			iwl_mvm_tx_airtime(mvm, mvmsta,
21987d9d0d56SLuca Coelho 					   le32_to_cpu(ba_res->wireless_time));
219941fd2fecSLiad Kaufman 		rcu_read_unlock();
2200afc857bcSJohannes Berg 
2201c46e7724SSara Sharon 		IWL_DEBUG_TX_REPLY(mvm,
2202c46e7724SSara Sharon 				   "BA_NOTIFICATION Received from sta_id = %d, flags %x, sent:%d, acked:%d\n",
2203c46e7724SSara Sharon 				   sta_id, le32_to_cpu(ba_res->flags),
2204c46e7724SSara Sharon 				   le16_to_cpu(ba_res->txed),
2205c46e7724SSara Sharon 				   le16_to_cpu(ba_res->done));
2206c46e7724SSara Sharon 		return;
2207c46e7724SSara Sharon 	}
2208c46e7724SSara Sharon 
2209c46e7724SSara Sharon 	ba_notif = (void *)pkt->data;
2210c46e7724SSara Sharon 	sta_id = ba_notif->sta_id;
2211c46e7724SSara Sharon 	tid = ba_notif->tid;
2212c46e7724SSara Sharon 	/* "flow" corresponds to Tx queue */
2213c46e7724SSara Sharon 	txq = le16_to_cpu(ba_notif->scd_flow);
2214c46e7724SSara Sharon 	/* "ssn" is start of block-ack Tx window, corresponds to index
2215c46e7724SSara Sharon 	 * (in Tx queue's circular buffer) of first TFD/frame in window */
2216c46e7724SSara Sharon 	index = le16_to_cpu(ba_notif->scd_ssn);
2217c46e7724SSara Sharon 
2218c46e7724SSara Sharon 	rcu_read_lock();
2219c46e7724SSara Sharon 	mvmsta = iwl_mvm_sta_from_staid_rcu(mvm, sta_id);
2220568db7fdSJohannes Berg 	if (IWL_FW_CHECK(mvm, !mvmsta,
2221568db7fdSJohannes Berg 			 "invalid STA ID %d in BA notif\n",
2222568db7fdSJohannes Berg 			 sta_id)) {
2223c46e7724SSara Sharon 		rcu_read_unlock();
2224c46e7724SSara Sharon 		return;
2225c46e7724SSara Sharon 	}
2226c46e7724SSara Sharon 
2227c46e7724SSara Sharon 	tid_data = &mvmsta->tid_data[tid];
2228c46e7724SSara Sharon 
2229c46e7724SSara Sharon 	ba_info.status.ampdu_ack_len = ba_notif->txed_2_done;
2230c46e7724SSara Sharon 	ba_info.status.ampdu_len = ba_notif->txed;
2231c46e7724SSara Sharon 	ba_info.status.tx_time = tid_data->tx_time;
2232c46e7724SSara Sharon 	ba_info.status.status_driver_data[0] =
2233c46e7724SSara Sharon 		(void *)(uintptr_t)ba_notif->reduced_txp;
2234c46e7724SSara Sharon 
2235c46e7724SSara Sharon 	rcu_read_unlock();
2236c46e7724SSara Sharon 
2237c46e7724SSara Sharon 	iwl_mvm_tx_reclaim(mvm, sta_id, tid, txq, index, &ba_info,
2238d4e3a341SMordechay Goodstein 			   tid_data->rate_n_flags, false);
2239c46e7724SSara Sharon 
2240c46e7724SSara Sharon 	IWL_DEBUG_TX_REPLY(mvm,
2241c46e7724SSara Sharon 			   "BA_NOTIFICATION Received from %pM, sta_id = %d\n",
22423dc6dd96SJohannes Berg 			   ba_notif->sta_addr, ba_notif->sta_id);
2243c46e7724SSara Sharon 
2244c46e7724SSara Sharon 	IWL_DEBUG_TX_REPLY(mvm,
2245c46e7724SSara Sharon 			   "TID = %d, SeqCtl = %d, bitmap = 0x%llx, scd_flow = %d, scd_ssn = %d sent:%d, acked:%d\n",
2246c46e7724SSara Sharon 			   ba_notif->tid, le16_to_cpu(ba_notif->seq_ctl),
2247c46e7724SSara Sharon 			   le64_to_cpu(ba_notif->bitmap), txq, index,
2248c46e7724SSara Sharon 			   ba_notif->txed, ba_notif->txed_2_done);
2249c46e7724SSara Sharon 
2250c46e7724SSara Sharon 	IWL_DEBUG_TX_REPLY(mvm, "reduced txp from ba notif %d\n",
2251c46e7724SSara Sharon 			   ba_notif->reduced_txp);
2252c46e7724SSara Sharon }
2253c46e7724SSara Sharon 
2254e705c121SKalle Valo /*
2255e705c121SKalle Valo  * Note that there are transports that buffer frames before they reach
2256e705c121SKalle Valo  * the firmware. This means that after flush_tx_path is called, the
2257e705c121SKalle Valo  * queue might not be empty. The race-free way to handle this is to:
2258e705c121SKalle Valo  * 1) set the station as draining
2259e705c121SKalle Valo  * 2) flush the Tx path
2260e705c121SKalle Valo  * 3) wait for the transport queues to be empty
2261e705c121SKalle Valo  */
iwl_mvm_flush_tx_path(struct iwl_mvm * mvm,u32 tfd_msk)2262d4e3a341SMordechay Goodstein int iwl_mvm_flush_tx_path(struct iwl_mvm *mvm, u32 tfd_msk)
2263e705c121SKalle Valo {
2264e705c121SKalle Valo 	int ret;
2265d167e81aSMordechai Goodstein 	struct iwl_tx_path_flush_cmd_v1 flush_cmd = {
2266e705c121SKalle Valo 		.queues_ctl = cpu_to_le32(tfd_msk),
2267e705c121SKalle Valo 		.flush_ctl = cpu_to_le16(DUMP_TX_FIFO_FLUSH),
2268e705c121SKalle Valo 	};
2269e705c121SKalle Valo 
2270d167e81aSMordechai Goodstein 	WARN_ON(iwl_mvm_has_new_tx_api(mvm));
2271d4e3a341SMordechay Goodstein 	ret = iwl_mvm_send_cmd_pdu(mvm, TXPATH_FLUSH, 0,
2272d167e81aSMordechai Goodstein 				   sizeof(flush_cmd), &flush_cmd);
2273d167e81aSMordechai Goodstein 	if (ret)
2274d167e81aSMordechai Goodstein 		IWL_ERR(mvm, "Failed to send flush command (%d)\n", ret);
2275d167e81aSMordechai Goodstein 	return ret;
2276d167e81aSMordechai Goodstein }
2277d167e81aSMordechai Goodstein 
iwl_mvm_flush_sta_tids(struct iwl_mvm * mvm,u32 sta_id,u16 tids)2278d4e3a341SMordechay Goodstein int iwl_mvm_flush_sta_tids(struct iwl_mvm *mvm, u32 sta_id, u16 tids)
2279d167e81aSMordechai Goodstein {
2280d167e81aSMordechai Goodstein 	int ret;
2281d4e3a341SMordechay Goodstein 	struct iwl_tx_path_flush_cmd_rsp *rsp;
2282d167e81aSMordechai Goodstein 	struct iwl_tx_path_flush_cmd flush_cmd = {
2283d167e81aSMordechai Goodstein 		.sta_id = cpu_to_le32(sta_id),
2284d167e81aSMordechai Goodstein 		.tid_mask = cpu_to_le16(tids),
2285d167e81aSMordechai Goodstein 	};
2286d167e81aSMordechai Goodstein 
2287d4e3a341SMordechay Goodstein 	struct iwl_host_cmd cmd = {
2288d4e3a341SMordechay Goodstein 		.id = TXPATH_FLUSH,
2289d4e3a341SMordechay Goodstein 		.len = { sizeof(flush_cmd), },
2290d4e3a341SMordechay Goodstein 		.data = { &flush_cmd, },
2291d4e3a341SMordechay Goodstein 	};
2292d4e3a341SMordechay Goodstein 
2293d167e81aSMordechai Goodstein 	WARN_ON(!iwl_mvm_has_new_tx_api(mvm));
2294d167e81aSMordechai Goodstein 
2295d4e3a341SMordechay Goodstein 	if (iwl_fw_lookup_notif_ver(mvm->fw, LONG_GROUP, TXPATH_FLUSH, 0) > 0)
2296076ca742SJohannes Berg 		cmd.flags |= CMD_WANT_SKB | CMD_SEND_IN_RFKILL;
2297d4e3a341SMordechay Goodstein 
2298d4e3a341SMordechay Goodstein 	IWL_DEBUG_TX_QUEUES(mvm, "flush for sta id %d tid mask 0x%x\n",
2299d4e3a341SMordechay Goodstein 			    sta_id, tids);
2300d4e3a341SMordechay Goodstein 
2301d4e3a341SMordechay Goodstein 	ret = iwl_mvm_send_cmd(mvm, &cmd);
2302d4e3a341SMordechay Goodstein 
2303d4e3a341SMordechay Goodstein 	if (ret) {
2304e705c121SKalle Valo 		IWL_ERR(mvm, "Failed to send flush command (%d)\n", ret);
2305e705c121SKalle Valo 		return ret;
2306e705c121SKalle Valo 	}
2307d49394a1SSara Sharon 
2308d4e3a341SMordechay Goodstein 	if (cmd.flags & CMD_WANT_SKB) {
2309d4e3a341SMordechay Goodstein 		int i;
2310d4e3a341SMordechay Goodstein 		int num_flushed_queues;
2311d4e3a341SMordechay Goodstein 
2312d4e3a341SMordechay Goodstein 		if (WARN_ON_ONCE(iwl_rx_packet_payload_len(cmd.resp_pkt) != sizeof(*rsp))) {
2313d4e3a341SMordechay Goodstein 			ret = -EIO;
2314d4e3a341SMordechay Goodstein 			goto free_rsp;
2315d4e3a341SMordechay Goodstein 		}
2316d4e3a341SMordechay Goodstein 
2317d4e3a341SMordechay Goodstein 		rsp = (void *)cmd.resp_pkt->data;
2318d4e3a341SMordechay Goodstein 
2319d4e3a341SMordechay Goodstein 		if (WARN_ONCE(le16_to_cpu(rsp->sta_id) != sta_id,
2320d4e3a341SMordechay Goodstein 			      "sta_id %d != rsp_sta_id %d",
2321d4e3a341SMordechay Goodstein 			      sta_id, le16_to_cpu(rsp->sta_id))) {
2322d4e3a341SMordechay Goodstein 			ret = -EIO;
2323d4e3a341SMordechay Goodstein 			goto free_rsp;
2324d4e3a341SMordechay Goodstein 		}
2325d4e3a341SMordechay Goodstein 
2326d4e3a341SMordechay Goodstein 		num_flushed_queues = le16_to_cpu(rsp->num_flushed_queues);
2327d4e3a341SMordechay Goodstein 		if (WARN_ONCE(num_flushed_queues > IWL_TX_FLUSH_QUEUE_RSP,
2328d4e3a341SMordechay Goodstein 			      "num_flushed_queues %d", num_flushed_queues)) {
2329d4e3a341SMordechay Goodstein 			ret = -EIO;
2330d4e3a341SMordechay Goodstein 			goto free_rsp;
2331d4e3a341SMordechay Goodstein 		}
2332d4e3a341SMordechay Goodstein 
2333d4e3a341SMordechay Goodstein 		for (i = 0; i < num_flushed_queues; i++) {
2334d4e3a341SMordechay Goodstein 			struct ieee80211_tx_info tx_info = {};
2335d4e3a341SMordechay Goodstein 			struct iwl_flush_queue_info *queue_info = &rsp->queues[i];
2336d4e3a341SMordechay Goodstein 			int tid = le16_to_cpu(queue_info->tid);
2337d4e3a341SMordechay Goodstein 			int read_before = le16_to_cpu(queue_info->read_before_flush);
2338d4e3a341SMordechay Goodstein 			int read_after = le16_to_cpu(queue_info->read_after_flush);
2339d4e3a341SMordechay Goodstein 			int queue_num = le16_to_cpu(queue_info->queue_num);
2340d4e3a341SMordechay Goodstein 
2341d4e3a341SMordechay Goodstein 			if (tid == IWL_MGMT_TID)
2342d4e3a341SMordechay Goodstein 				tid = IWL_MAX_TID_COUNT;
2343d4e3a341SMordechay Goodstein 
2344d4e3a341SMordechay Goodstein 			IWL_DEBUG_TX_QUEUES(mvm,
2345d4e3a341SMordechay Goodstein 					    "tid %d queue_id %d read-before %d read-after %d\n",
2346d4e3a341SMordechay Goodstein 					    tid, queue_num, read_before, read_after);
2347d4e3a341SMordechay Goodstein 
2348d4e3a341SMordechay Goodstein 			iwl_mvm_tx_reclaim(mvm, sta_id, tid, queue_num, read_after,
2349d4e3a341SMordechay Goodstein 					   &tx_info, 0, true);
2350d4e3a341SMordechay Goodstein 		}
2351d4e3a341SMordechay Goodstein free_rsp:
2352d4e3a341SMordechay Goodstein 		iwl_free_resp(&cmd);
2353d4e3a341SMordechay Goodstein 	}
2354d4e3a341SMordechay Goodstein 	return ret;
2355d4e3a341SMordechay Goodstein }
2356d4e3a341SMordechay Goodstein 
iwl_mvm_flush_sta(struct iwl_mvm * mvm,u32 sta_id,u32 tfd_queue_mask)2357d43701c5SJohannes Berg int iwl_mvm_flush_sta(struct iwl_mvm *mvm, u32 sta_id, u32 tfd_queue_mask)
2358d49394a1SSara Sharon {
2359334167deSEmmanuel Grumbach 	if (iwl_mvm_has_new_tx_api(mvm))
2360c8ee33e1SGregory Greenman 		return iwl_mvm_flush_sta_tids(mvm, sta_id, 0xffff);
2361d49394a1SSara Sharon 
2362d43701c5SJohannes Berg 	return iwl_mvm_flush_tx_path(mvm, tfd_queue_mask);
2363d49394a1SSara Sharon }
2364