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