summaryrefslogtreecommitdiff
path: root/drivers/net/wireless/intel/iwlwifi/mvm
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2023-06-29 02:43:10 +0300
committerLinus Torvalds <torvalds@linux-foundation.org>2023-06-29 02:43:10 +0300
commit3a8a670eeeaa40d87bd38a587438952741980c18 (patch)
treed5546d311271503eadf75b45d87e12720e72899f /drivers/net/wireless/intel/iwlwifi/mvm
parent6a8cbd9253abc1bd0df4d60c4c24fa555190376d (diff)
parentae230642190a51b85656d6da2df744d534d59544 (diff)
downloadlinux-3a8a670eeeaa40d87bd38a587438952741980c18.tar.xz
Merge tag 'net-next-6.5' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next
Pull networking changes from Jakub Kicinski: "WiFi 7 and sendpage changes are the biggest pieces of work for this release. The latter will definitely require fixes but I think that we got it to a reasonable point. Core: - Rework the sendpage & splice implementations Instead of feeding data into sockets page by page extend sendmsg handlers to support taking a reference on the data, controlled by a new flag called MSG_SPLICE_PAGES Rework the handling of unexpected-end-of-file to invoke an additional callback instead of trying to predict what the right combination of MORE/NOTLAST flags is Remove the MSG_SENDPAGE_NOTLAST flag completely - Implement SCM_PIDFD, a new type of CMSG type analogous to SCM_CREDENTIALS, but it contains pidfd instead of plain pid - Enable socket busy polling with CONFIG_RT - Improve reliability and efficiency of reporting for ref_tracker - Auto-generate a user space C library for various Netlink families Protocols: - Allow TCP to shrink the advertised window when necessary, prevent sk_rcvbuf auto-tuning from growing the window all the way up to tcp_rmem[2] - Use per-VMA locking for "page-flipping" TCP receive zerocopy - Prepare TCP for device-to-device data transfers, by making sure that payloads are always attached to skbs as page frags - Make the backoff time for the first N TCP SYN retransmissions linear. Exponential backoff is unnecessarily conservative - Create a new MPTCP getsockopt to retrieve all info (MPTCP_FULL_INFO) - Avoid waking up applications using TLS sockets until we have a full record - Allow using kernel memory for protocol ioctl callbacks, paving the way to issuing ioctls over io_uring - Add nolocalbypass option to VxLAN, forcing packets to be fully encapsulated even if they are destined for a local IP address - Make TCPv4 use consistent hash in TIME_WAIT and SYN_RECV. Ensure in-kernel ECMP implementation (e.g. Open vSwitch) select the same link for all packets. Support L4 symmetric hashing in Open vSwitch - PPPoE: make number of hash bits configurable - Allow DNS to be overwritten by DHCPACK in the in-kernel DHCP client (ipconfig) - Add layer 2 miss indication and filtering, allowing higher layers (e.g. ACL filters) to make forwarding decisions based on whether packet matched forwarding state in lower devices (bridge) - Support matching on Connectivity Fault Management (CFM) packets - Hide the "link becomes ready" IPv6 messages by demoting their printk level to debug - HSR: don't enable promiscuous mode if device offloads the proto - Support active scanning in IEEE 802.15.4 - Continue work on Multi-Link Operation for WiFi 7 BPF: - Add precision propagation for subprogs and callbacks. This allows maintaining verification efficiency when subprograms are used, or in fact passing the verifier at all for complex programs, especially those using open-coded iterators - Improve BPF's {g,s}setsockopt() length handling. Previously BPF assumed the length is always equal to the amount of written data. But some protos allow passing a NULL buffer to discover what the output buffer *should* be, without writing anything - Accept dynptr memory as memory arguments passed to helpers - Add routing table ID to bpf_fib_lookup BPF helper - Support O_PATH FDs in BPF_OBJ_PIN and BPF_OBJ_GET commands - Drop bpf_capable() check in BPF_MAP_FREEZE command (used to mark maps as read-only) - Show target_{obj,btf}_id in tracing link fdinfo - Addition of several new kfuncs (most of the names are self-explanatory): - Add a set of new dynptr kfuncs: bpf_dynptr_adjust(), bpf_dynptr_is_null(), bpf_dynptr_is_rdonly(), bpf_dynptr_size() and bpf_dynptr_clone(). - bpf_task_under_cgroup() - bpf_sock_destroy() - force closing sockets - bpf_cpumask_first_and(), rework bpf_cpumask_any*() kfuncs Netfilter: - Relax set/map validation checks in nf_tables. Allow checking presence of an entry in a map without using the value - Increase ip_vs_conn_tab_bits range for 64BIT builds - Allow updating size of a set - Improve NAT tuple selection when connection is closing Driver API: - Integrate netdev with LED subsystem, to allow configuring HW "offloaded" blinking of LEDs based on link state and activity (i.e. packets coming in and out) - Support configuring rate selection pins of SFP modules - Factor Clause 73 auto-negotiation code out of the drivers, provide common helper routines - Add more fool-proof helpers for managing lifetime of MDIO devices associated with the PCS layer - Allow drivers to report advanced statistics related to Time Aware scheduler offload (taprio) - Allow opting out of VF statistics in link dump, to allow more VFs to fit into the message - Split devlink instance and devlink port operations New hardware / drivers: - Ethernet: - Synopsys EMAC4 IP support (stmmac) - Marvell 88E6361 8 port (5x1GE + 3x2.5GE) switches - Marvell 88E6250 7 port switches - Microchip LAN8650/1 Rev.B0 PHYs - MediaTek MT7981/MT7988 built-in 1GE PHY driver - WiFi: - Realtek RTL8192FU, 2.4 GHz, b/g/n mode, 2T2R, 300 Mbps - Realtek RTL8723DS (SDIO variant) - Realtek RTL8851BE - CAN: - Fintek F81604 Drivers: - Ethernet NICs: - Intel (100G, ice): - support dynamic interrupt allocation - use meta data match instead of VF MAC addr on slow-path - nVidia/Mellanox: - extend link aggregation to handle 4, rather than just 2 ports - spawn sub-functions without any features by default - OcteonTX2: - support HTB (Tx scheduling/QoS) offload - make RSS hash generation configurable - support selecting Rx queue using TC filters - Wangxun (ngbe/txgbe): - add basic Tx/Rx packet offloads - add phylink support (SFP/PCS control) - Freescale/NXP (enetc): - report TAPRIO packet statistics - Solarflare/AMD: - support matching on IP ToS and UDP source port of outer header - VxLAN and GENEVE tunnel encapsulation over IPv4 or IPv6 - add devlink dev info support for EF10 - Virtual NICs: - Microsoft vNIC: - size the Rx indirection table based on requested configuration - support VLAN tagging - Amazon vNIC: - try to reuse Rx buffers if not fully consumed, useful for ARM servers running with 16kB pages - Google vNIC: - support TCP segmentation of >64kB frames - Ethernet embedded switches: - Marvell (mv88e6xxx): - enable USXGMII (88E6191X) - Microchip: - lan966x: add support for Egress Stage 0 ACL engine - lan966x: support mapping packet priority to internal switch priority (based on PCP or DSCP) - Ethernet PHYs: - Broadcom PHYs: - support for Wake-on-LAN for BCM54210E/B50212E - report LPI counter - Microsemi PHYs: support RGMII delay configuration (VSC85xx) - Micrel PHYs: receive timestamp in the frame (LAN8841) - Realtek PHYs: support optional external PHY clock - Altera TSE PCS: merge the driver into Lynx PCS which it is a variant of - CAN: Kvaser PCIEcan: - support packet timestamping - WiFi: - Intel (iwlwifi): - major update for new firmware and Multi-Link Operation (MLO) - configuration rework to drop test devices and split the different families - support for segmented PNVM images and power tables - new vendor entries for PPAG (platform antenna gain) feature - Qualcomm 802.11ax (ath11k): - Multiple Basic Service Set Identifier (MBSSID) and Enhanced MBSSID Advertisement (EMA) support in AP mode - support factory test mode - RealTek (rtw89): - add RSSI based antenna diversity - support U-NII-4 channels on 5 GHz band - RealTek (rtl8xxxu): - AP mode support for 8188f - support USB RX aggregation for the newer chips" * tag 'net-next-6.5' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next: (1602 commits) net: scm: introduce and use scm_recv_unix helper af_unix: Skip SCM_PIDFD if scm->pid is NULL. net: lan743x: Simplify comparison netlink: Add __sock_i_ino() for __netlink_diag_dump(). net: dsa: avoid suspicious RCU usage for synced VLAN-aware MAC addresses Revert "af_unix: Call scm_recv() only after scm_set_cred()." phylink: ReST-ify the phylink_pcs_neg_mode() kdoc libceph: Partially revert changes to support MSG_SPLICE_PAGES net: phy: mscc: fix packet loss due to RGMII delays net: mana: use vmalloc_array and vcalloc net: enetc: use vmalloc_array and vcalloc ionic: use vmalloc_array and vcalloc pds_core: use vmalloc_array and vcalloc gve: use vmalloc_array and vcalloc octeon_ep: use vmalloc_array and vcalloc net: usb: qmi_wwan: add u-blox 0x1312 composition perf trace: fix MSG_SPLICE_PAGES build error ipvlan: Fix return value of ipvlan_queue_xmit() netfilter: nf_tables: fix underflow in chain reference counter netfilter: nf_tables: unbind non-anonymous set if rule construction fails ...
Diffstat (limited to 'drivers/net/wireless/intel/iwlwifi/mvm')
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/binding.c10
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/constants.h6
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/d3.c420
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c6
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c202
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c48
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c23
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/fw.c93
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/link.c37
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c122
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c200
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c99
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/mld-mac.c26
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c177
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c28
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/mvm.h105
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/nvm.c63
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/offloading.c4
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/ops.c16
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c15
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/power.c56
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c77
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/rs.c11
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/rx.c10
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c46
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/scan.c163
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/sf.c5
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/sta.c90
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/sta.h20
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/time-event.c4
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/tx.c150
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/utils.c26
32 files changed, 1612 insertions, 746 deletions
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/binding.c b/drivers/net/wireless/intel/iwlwifi/mvm/binding.c
index ef50ccabcc73..458b97930059 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/binding.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/binding.c
@@ -32,7 +32,7 @@ static int iwl_mvm_binding_cmd(struct iwl_mvm *mvm, u32 action,
if (fw_has_capa(&mvm->fw->ucode_capa,
IWL_UCODE_TLV_CAPA_BINDING_CDB_SUPPORT)) {
size = sizeof(cmd);
- cmd.lmac_id = cpu_to_le32(iwl_mvm_get_lmac_id(mvm->fw,
+ cmd.lmac_id = cpu_to_le32(iwl_mvm_get_lmac_id(mvm,
phyctxt->channel->band));
} else {
size = IWL_BINDING_CMD_SIZE_V1;
@@ -164,3 +164,11 @@ int iwl_mvm_binding_remove_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
return ret;
}
+
+u32 iwl_mvm_get_lmac_id(struct iwl_mvm *mvm, enum nl80211_band band)
+{
+ if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_CDB_SUPPORT) ||
+ band == NL80211_BAND_2GHZ)
+ return IWL_LMAC_24G_INDEX;
+ return IWL_LMAC_5G_INDEX;
+}
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/constants.h b/drivers/net/wireless/intel/iwlwifi/mvm/constants.h
index c604f9f39b24..243eccc68cb0 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/constants.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/constants.h
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/*
* Copyright (C) 2013-2015 Intel Mobile Communications GmbH
- * Copyright (C) 2013-2014, 2018-2021 Intel Corporation
+ * Copyright (C) 2013-2014, 2018-2023 Intel Corporation
* Copyright (C) 2015 Intel Deutschland GmbH
*/
#ifndef __MVM_CONSTANTS_H
@@ -109,10 +109,6 @@
#define IWL_MVM_USE_TWT true
#define IWL_MVM_AMPDU_CONSEC_DROPS_DELBA 20
#define IWL_MVM_USE_NSSN_SYNC 0
-#define IWL_MVM_PHY_FILTER_CHAIN_A 0
-#define IWL_MVM_PHY_FILTER_CHAIN_B 0
-#define IWL_MVM_PHY_FILTER_CHAIN_C 0
-#define IWL_MVM_PHY_FILTER_CHAIN_D 0
#define IWL_MVM_FTM_INITIATOR_ENABLE_SMOOTH false
#define IWL_MVM_FTM_INITIATOR_SMOOTH_ALPHA 40
/* 20016 pSec is 6 meter RTT, meaning 3 meter range */
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
index 6d1007f24b4a..f6488b4bbe68 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
- * Copyright (C) 2012-2014, 2018-2022 Intel Corporation
+ * Copyright (C) 2012-2014, 2018-2023 Intel Corporation
* Copyright (C) 2013-2015 Intel Mobile Communications GmbH
* Copyright (C) 2016-2017 Intel Deutschland GmbH
*/
@@ -1380,6 +1380,14 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
return __iwl_mvm_suspend(hw, wowlan, false);
}
+struct iwl_multicast_key_data {
+ u8 key[WOWLAN_KEY_MAX_SIZE];
+ u8 len;
+ u8 flags;
+ u8 id;
+ u8 ipn[6];
+};
+
/* converted data from the different status responses */
struct iwl_wowlan_status_data {
u64 replay_ctr;
@@ -1398,7 +1406,8 @@ struct iwl_wowlan_status_data {
u8 key[WOWLAN_KEY_MAX_SIZE];
u8 len;
u8 flags;
- } gtk;
+ u8 id;
+ } gtk[WOWLAN_GTK_KEYS_NUM];
struct {
/*
@@ -1428,12 +1437,7 @@ struct iwl_wowlan_status_data {
} tkip, aes;
} ptk;
- struct {
- u64 ipn;
- u8 key[WOWLAN_KEY_MAX_SIZE];
- u8 len;
- u8 flags;
- } igtk;
+ struct iwl_multicast_key_data igtk;
u8 *wake_packet;
};
@@ -1758,7 +1762,7 @@ static void iwl_mvm_set_key_rx_seq(struct ieee80211_key_conf *key,
s8 new_key_id = -1;
if (status->num_of_gtk_rekeys)
- new_key_id = status->gtk.flags &
+ new_key_id = status->gtk[0].flags &
IWL_WOWLAN_GTK_IDX_MASK;
/* Don't install a new key's value to an old key */
@@ -1777,20 +1781,18 @@ static void iwl_mvm_set_key_rx_seq(struct ieee80211_key_conf *key,
struct iwl_mvm_d3_gtk_iter_data {
struct iwl_mvm *mvm;
struct iwl_wowlan_status_data *status;
- void *last_gtk;
- u32 cipher;
- bool find_phase, unhandled_cipher;
+ u32 gtk_cipher, igtk_cipher;
+ bool unhandled_cipher, igtk_support;
int num_keys;
};
-static void iwl_mvm_d3_update_keys(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta,
- struct ieee80211_key_conf *key,
- void *_data)
+static void iwl_mvm_d3_find_last_keys(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
+ struct ieee80211_key_conf *key,
+ void *_data)
{
struct iwl_mvm_d3_gtk_iter_data *data = _data;
- struct iwl_wowlan_status_data *status = data->status;
if (data->unhandled_cipher)
return;
@@ -1805,51 +1807,230 @@ static void iwl_mvm_d3_update_keys(struct ieee80211_hw *hw,
case WLAN_CIPHER_SUITE_GCMP_256:
case WLAN_CIPHER_SUITE_TKIP:
/* we support these */
+ data->gtk_cipher = key->cipher;
+ break;
+ case WLAN_CIPHER_SUITE_BIP_GMAC_128:
+ case WLAN_CIPHER_SUITE_BIP_GMAC_256:
+ case WLAN_CIPHER_SUITE_BIP_CMAC_256:
+ case WLAN_CIPHER_SUITE_AES_CMAC:
+ /* we support these */
+ if (data->igtk_support &&
+ (key->keyidx == 4 || key->keyidx == 5)) {
+ data->igtk_cipher = key->cipher;
+ } else {
+ data->unhandled_cipher = true;
+ return;
+ }
break;
default:
- /* everything else (even CMAC for MFP) - disconnect from AP */
+ /* everything else - disconnect from AP */
data->unhandled_cipher = true;
return;
}
data->num_keys++;
+}
- /*
- * pairwise key - update sequence counters only;
- * note that this assumes no TDLS sessions are active
- */
- if (sta) {
- if (data->find_phase)
- return;
+static void
+iwl_mvm_d3_set_igtk_bigtk_ipn(const struct iwl_multicast_key_data *key,
+ struct ieee80211_key_seq *seq, u32 cipher)
+{
+ switch (cipher) {
+ case WLAN_CIPHER_SUITE_BIP_GMAC_128:
+ case WLAN_CIPHER_SUITE_BIP_GMAC_256:
+ BUILD_BUG_ON(sizeof(seq->aes_gmac.pn) != sizeof(key->ipn));
+ memcpy(seq->aes_gmac.pn, key->ipn, sizeof(seq->aes_gmac.pn));
+ break;
+ case WLAN_CIPHER_SUITE_BIP_CMAC_256:
+ BUILD_BUG_ON(sizeof(seq->aes_cmac.pn) != sizeof(key->ipn));
+ memcpy(seq->aes_cmac.pn, key->ipn, sizeof(seq->aes_cmac.pn));
+ break;
+ }
+}
+
+static void iwl_mvm_d3_update_keys(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
+ struct ieee80211_key_conf *key,
+ void *_data)
+{
+ struct iwl_mvm_d3_gtk_iter_data *data = _data;
+ struct iwl_wowlan_status_data *status = data->status;
+ s8 keyidx;
+
+ if (data->unhandled_cipher)
+ return;
- switch (key->cipher) {
- case WLAN_CIPHER_SUITE_CCMP:
- case WLAN_CIPHER_SUITE_GCMP:
- case WLAN_CIPHER_SUITE_GCMP_256:
+ switch (key->cipher) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ case WLAN_CIPHER_SUITE_WEP104:
+ /* ignore WEP completely, nothing to do */
+ return;
+ case WLAN_CIPHER_SUITE_CCMP:
+ case WLAN_CIPHER_SUITE_GCMP:
+ case WLAN_CIPHER_SUITE_GCMP_256:
+ if (sta) {
atomic64_set(&key->tx_pn, status->ptk.aes.tx_pn);
iwl_mvm_set_aes_ptk_rx_seq(data->mvm, status, sta, key);
- break;
- case WLAN_CIPHER_SUITE_TKIP:
+ return;
+ }
+ fallthrough;
+ case WLAN_CIPHER_SUITE_TKIP:
+ if (sta) {
atomic64_set(&key->tx_pn, status->ptk.tkip.tx_pn);
iwl_mvm_set_key_rx_seq_tids(key, status->ptk.tkip.seq);
- break;
+ return;
}
+ keyidx = key->keyidx;
+ /* The current key is always sent by the FW, even if it wasn't
+ * rekeyed during D3.
+ * We remove an existing key if it has the same index as
+ * a new key
+ */
+ if (status->num_of_gtk_rekeys &&
+ ((status->gtk[0].len && keyidx == status->gtk[0].id) ||
+ (status->gtk[1].len && keyidx == status->gtk[1].id))) {
+ ieee80211_remove_key(key);
+ } else {
+ iwl_mvm_set_key_rx_seq(key, data->status, false);
+ }
+ break;
+ case WLAN_CIPHER_SUITE_BIP_GMAC_128:
+ case WLAN_CIPHER_SUITE_BIP_GMAC_256:
+ case WLAN_CIPHER_SUITE_BIP_CMAC_256:
+ case WLAN_CIPHER_SUITE_AES_CMAC:
+ if (key->keyidx == 4 || key->keyidx == 5) {
+ /* remove rekeyed key */
+ if (status->num_of_gtk_rekeys) {
+ ieee80211_remove_key(key);
+ } else {
+ struct ieee80211_key_seq seq;
- /* that's it for this key */
- return;
+ iwl_mvm_d3_set_igtk_bigtk_ipn(&status->igtk,
+ &seq,
+ key->cipher);
+ ieee80211_set_key_rx_seq(key, 0, &seq);
+ }
+ }
}
+}
- if (data->find_phase) {
- data->last_gtk = key;
- data->cipher = key->cipher;
- return;
+static bool iwl_mvm_gtk_rekey(struct iwl_wowlan_status_data *status,
+ struct ieee80211_vif *vif,
+ struct iwl_mvm *mvm, u32 gtk_cipher)
+{
+ int i;
+ struct ieee80211_key_conf *key;
+ struct {
+ struct ieee80211_key_conf conf;
+ u8 key[32];
+ } conf = {
+ .conf.cipher = gtk_cipher,
+ };
+
+ BUILD_BUG_ON(WLAN_KEY_LEN_CCMP != WLAN_KEY_LEN_GCMP);
+ BUILD_BUG_ON(sizeof(conf.key) < WLAN_KEY_LEN_CCMP);
+ BUILD_BUG_ON(sizeof(conf.key) < WLAN_KEY_LEN_GCMP_256);
+ BUILD_BUG_ON(sizeof(conf.key) < WLAN_KEY_LEN_TKIP);
+ BUILD_BUG_ON(sizeof(conf.key) < sizeof(status->gtk[0].key));
+
+ switch (gtk_cipher) {
+ case WLAN_CIPHER_SUITE_CCMP:
+ case WLAN_CIPHER_SUITE_GCMP:
+ conf.conf.keylen = WLAN_KEY_LEN_CCMP;
+ break;
+ case WLAN_CIPHER_SUITE_GCMP_256:
+ conf.conf.keylen = WLAN_KEY_LEN_GCMP_256;
+ break;
+ case WLAN_CIPHER_SUITE_TKIP:
+ conf.conf.keylen = WLAN_KEY_LEN_TKIP;
+ break;
+ default:
+ WARN_ON(1);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(status->gtk); i++) {
+ if (!status->gtk[i].len)
+ continue;
+
+ conf.conf.keyidx = status->gtk[i].id;
+ IWL_DEBUG_WOWLAN(mvm,
+ "Received from FW GTK cipher %d, key index %d\n",
+ conf.conf.cipher, conf.conf.keyidx);
+ memcpy(conf.conf.key, status->gtk[i].key,
+ sizeof(status->gtk[i].key));
+
+ key = ieee80211_gtk_rekey_add(vif, &conf.conf);
+ if (IS_ERR(key))
+ return false;
+ iwl_mvm_set_key_rx_seq_idx(key, status, i);
}
- if (data->status->num_of_gtk_rekeys)
- ieee80211_remove_key(key);
+ return true;
+}
+
+static bool
+iwl_mvm_d3_igtk_bigtk_rekey_add(struct iwl_wowlan_status_data *status,
+ struct ieee80211_vif *vif, u32 cipher,
+ struct iwl_multicast_key_data *key_data)
+{
+ struct ieee80211_key_conf *key_config;
+ struct {
+ struct ieee80211_key_conf conf;
+ u8 key[WOWLAN_KEY_MAX_SIZE];
+ } conf = {
+ .conf.cipher = cipher,
+ .conf.keyidx = key_data->id,
+ };
+ struct ieee80211_key_seq seq;
+
+ if (!key_data->len)
+ return true;
+
+ iwl_mvm_d3_set_igtk_bigtk_ipn(key_data, &seq, conf.conf.cipher);
+
+ switch (cipher) {
+ case WLAN_CIPHER_SUITE_BIP_GMAC_128:
+ conf.conf.keylen = WLAN_KEY_LEN_BIP_GMAC_128;
+ break;
+ case WLAN_CIPHER_SUITE_BIP_GMAC_256:
+ conf.conf.keylen = WLAN_KEY_LEN_BIP_GMAC_256;
+ break;
+ case WLAN_CIPHER_SUITE_AES_CMAC:
+ conf.conf.keylen = WLAN_KEY_LEN_AES_CMAC;
+ break;
+ case WLAN_CIPHER_SUITE_BIP_CMAC_256:
+ conf.conf.keylen = WLAN_KEY_LEN_BIP_CMAC_256;
+ break;
+ default:
+ WARN_ON(1);
+ }
+ BUILD_BUG_ON(sizeof(conf.key) < sizeof(key_data->key));
+ memcpy(conf.conf.key, key_data->key, conf.conf.keylen);
+
+ key_config = ieee80211_gtk_rekey_add(vif, &conf.conf);
+ if (IS_ERR(key_config))
+ return false;
+ ieee80211_set_key_rx_seq(key_config, 0, &seq);
+ return true;
+}
+
+static int iwl_mvm_lookup_wowlan_status_ver(struct iwl_mvm *mvm)
+{
+ u8 notif_ver;
+
+ if (!fw_has_api(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_API_WOWLAN_KEY_MATERIAL))
+ return 6;
+
+ /* default to 7 (when we have IWL_UCODE_TLV_API_WOWLAN_KEY_MATERIAL) */
+ notif_ver = iwl_fw_lookup_notif_ver(mvm->fw, LONG_GROUP,
+ WOWLAN_GET_STATUSES, 0);
+ if (!notif_ver)
+ notif_ver = iwl_fw_lookup_notif_ver(mvm->fw, LEGACY_GROUP,
+ WOWLAN_GET_STATUSES, 7);
- if (data->last_gtk == key)
- iwl_mvm_set_key_rx_seq(key, data->status, false);
+ return notif_ver;
}
static bool iwl_mvm_setup_connection_keep(struct iwl_mvm *mvm,
@@ -1871,71 +2052,41 @@ static bool iwl_mvm_setup_connection_keep(struct iwl_mvm *mvm,
if (status->wakeup_reasons & disconnection_reasons)
return false;
+ if (iwl_mvm_lookup_wowlan_status_ver(mvm) > 6 ||
+ iwl_fw_lookup_notif_ver(mvm->fw, PROT_OFFLOAD_GROUP,
+ WOWLAN_INFO_NOTIFICATION,
+ 0))
+ gtkdata.igtk_support = true;
+
/* find last GTK that we used initially, if any */
- gtkdata.find_phase = true;
ieee80211_iter_keys(mvm->hw, vif,
- iwl_mvm_d3_update_keys, &gtkdata);
+ iwl_mvm_d3_find_last_keys, &gtkdata);
/* not trying to keep connections with MFP/unhandled ciphers */
if (gtkdata.unhandled_cipher)
return false;
if (!gtkdata.num_keys)
goto out;
- if (!gtkdata.last_gtk)
- return false;
/*
* invalidate all other GTKs that might still exist and update
* the one that we used
*/
- gtkdata.find_phase = false;
ieee80211_iter_keys(mvm->hw, vif,
iwl_mvm_d3_update_keys, &gtkdata);
- IWL_DEBUG_WOWLAN(mvm, "num of GTK rekeying %d\n",
- status->num_of_gtk_rekeys);
if (status->num_of_gtk_rekeys) {
- struct ieee80211_key_conf *key;
- struct {
- struct ieee80211_key_conf conf;
- u8 key[32];
- } conf = {
- .conf.cipher = gtkdata.cipher,
- .conf.keyidx =
- status->gtk.flags & IWL_WOWLAN_GTK_IDX_MASK,
- };
- __be64 replay_ctr;
+ __be64 replay_ctr = cpu_to_be64(status->replay_ctr);
- IWL_DEBUG_WOWLAN(mvm,
- "Received from FW GTK cipher %d, key index %d\n",
- conf.conf.cipher, conf.conf.keyidx);
-
- BUILD_BUG_ON(WLAN_KEY_LEN_CCMP != WLAN_KEY_LEN_GCMP);
- BUILD_BUG_ON(sizeof(conf.key) < WLAN_KEY_LEN_CCMP);
- BUILD_BUG_ON(sizeof(conf.key) < WLAN_KEY_LEN_GCMP_256);
- BUILD_BUG_ON(sizeof(conf.key) < WLAN_KEY_LEN_TKIP);
- BUILD_BUG_ON(sizeof(conf.key) < sizeof(status->gtk.key));
+ IWL_DEBUG_WOWLAN(mvm, "num of GTK rekeying %d\n",
+ status->num_of_gtk_rekeys);
- memcpy(conf.conf.key, status->gtk.key, sizeof(status->gtk.key));
-
- switch (gtkdata.cipher) {
- case WLAN_CIPHER_SUITE_CCMP:
- case WLAN_CIPHER_SUITE_GCMP:
- conf.conf.keylen = WLAN_KEY_LEN_CCMP;
- break;
- case WLAN_CIPHER_SUITE_GCMP_256:
- conf.conf.keylen = WLAN_KEY_LEN_GCMP_256;
- break;
- case WLAN_CIPHER_SUITE_TKIP:
- conf.conf.keylen = WLAN_KEY_LEN_TKIP;
- break;
- }
-
- key = ieee80211_gtk_rekey_add(vif, &conf.conf);
- if (IS_ERR(key))
+ if (!iwl_mvm_gtk_rekey(status, vif, mvm, gtkdata.gtk_cipher))
return false;
- iwl_mvm_set_key_rx_seq(key, status, true);
- replay_ctr = cpu_to_be64(status->replay_ctr);
+ if (!iwl_mvm_d3_igtk_bigtk_rekey_add(status, vif,
+ gtkdata.igtk_cipher,
+ &status->igtk))
+ return false;
ieee80211_gtk_rekey_notify(vif, vif->bss_conf.bssid,
(void *)&replay_ctr, GFP_KERNEL);
@@ -1955,60 +2106,70 @@ out:
static void iwl_mvm_convert_gtk_v2(struct iwl_wowlan_status_data *status,
struct iwl_wowlan_gtk_status_v2 *data)
{
- BUILD_BUG_ON(sizeof(status->gtk.key) < sizeof(data->key));
+ BUILD_BUG_ON(sizeof(status->gtk[0].key) < sizeof(data->key));
BUILD_BUG_ON(NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY +
sizeof(data->tkip_mic_key) >
- sizeof(status->gtk.key));
+ sizeof(status->gtk[0].key));
- status->gtk.len = data->key_len;
- status->gtk.flags = data->key_flags;
+ status->gtk[0].len = data->key_len;
+ status->gtk[0].flags = data->key_flags;
- memcpy(status->gtk.key, data->key, sizeof(data->key));
+ memcpy(status->gtk[0].key, data->key, sizeof(data->key));
/* if it's as long as the TKIP encryption key, copy MIC key */
- if (status->gtk.len == NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY)
- memcpy(status->gtk.key + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY,
+ if (status->gtk[0].len == NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY)
+ memcpy(status->gtk[0].key + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY,
data->tkip_mic_key, sizeof(data->tkip_mic_key));
}
static void iwl_mvm_convert_gtk_v3(struct iwl_wowlan_status_data *status,
struct iwl_wowlan_gtk_status_v3 *data)
{
- /* The parts we need are identical in v2 and v3 */
-#define CHECK(_f) do { \
- BUILD_BUG_ON(offsetof(struct iwl_wowlan_gtk_status_v2, _f) != \
- offsetof(struct iwl_wowlan_gtk_status_v3, _f)); \
- BUILD_BUG_ON(offsetofend(struct iwl_wowlan_gtk_status_v2, _f) !=\
- offsetofend(struct iwl_wowlan_gtk_status_v3, _f)); \
-} while (0)
+ int data_idx, status_idx = 0;
- CHECK(key);
- CHECK(key_len);
- CHECK(key_flags);
- CHECK(tkip_mic_key);
-#undef CHECK
+ BUILD_BUG_ON(sizeof(status->gtk[0].key) < sizeof(data[0].key));
+ BUILD_BUG_ON(NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY +
+ sizeof(data[0].tkip_mic_key) >
+ sizeof(status->gtk[0].key));
+ BUILD_BUG_ON(ARRAY_SIZE(status->gtk) < WOWLAN_GTK_KEYS_NUM);
+ for (data_idx = 0; data_idx < ARRAY_SIZE(status->gtk); data_idx++) {
+ if (!(data[data_idx].key_len))
+ continue;
+ status->gtk[status_idx].len = data[data_idx].key_len;
+ status->gtk[status_idx].flags = data[data_idx].key_flags;
+ status->gtk[status_idx].id = status->gtk[status_idx].flags &
+ IWL_WOWLAN_GTK_IDX_MASK;
- iwl_mvm_convert_gtk_v2(status, (void *)data);
+ memcpy(status->gtk[status_idx].key, data[data_idx].key,
+ sizeof(data[data_idx].key));
+
+ /* if it's as long as the TKIP encryption key, copy MIC key */
+ if (status->gtk[status_idx].len ==
+ NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY)
+ memcpy(status->gtk[status_idx].key +
+ NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY,
+ data[data_idx].tkip_mic_key,
+ sizeof(data[data_idx].tkip_mic_key));
+ status_idx++;
+ }
}
static void iwl_mvm_convert_igtk(struct iwl_wowlan_status_data *status,
struct iwl_wowlan_igtk_status *data)
{
- const u8 *ipn = data->ipn;
-
BUILD_BUG_ON(sizeof(status->igtk.key) < sizeof(data->key));
+ if (!data->key_len)
+ return;
+
status->igtk.len = data->key_len;
status->igtk.flags = data->key_flags;
+ status->igtk.id = u32_get_bits(data->key_flags,
+ IWL_WOWLAN_IGTK_BIGTK_IDX_MASK)
+ + WOWLAN_IGTK_MIN_INDEX;
memcpy(status->igtk.key, data->key, sizeof(data->key));
-
- status->igtk.ipn = ((u64)ipn[5] << 0) |
- ((u64)ipn[4] << 8) |
- ((u64)ipn[3] << 16) |
- ((u64)ipn[2] << 24) |
- ((u64)ipn[1] << 32) |
- ((u64)ipn[0] << 40);
+ memcpy(status->igtk.ipn, data->ipn, sizeof(data->ipn));
}
static void iwl_mvm_parse_wowlan_info_notif(struct iwl_mvm *mvm,
@@ -2031,7 +2192,7 @@ static void iwl_mvm_parse_wowlan_info_notif(struct iwl_mvm *mvm,
}
iwl_mvm_convert_key_counters_v5(status, &data->gtk[0].sc);
- iwl_mvm_convert_gtk_v3(status, &data->gtk[0]);
+ iwl_mvm_convert_gtk_v3(status, data->gtk);
iwl_mvm_convert_igtk(status, &data->igtk[0]);
status->replay_ctr = le64_to_cpu(data->replay_ctr);
@@ -2139,14 +2300,9 @@ iwl_mvm_send_wowlan_get_status(struct iwl_mvm *mvm, u8 sta_id)
len = iwl_rx_packet_payload_len(cmd.resp_pkt);
/* default to 7 (when we have IWL_UCODE_TLV_API_WOWLAN_KEY_MATERIAL) */
- notif_ver = iwl_fw_lookup_notif_ver(mvm->fw, LONG_GROUP,
- WOWLAN_GET_STATUSES, 0);
- if (!notif_ver)
- notif_ver = iwl_fw_lookup_notif_ver(mvm->fw, LEGACY_GROUP,
- WOWLAN_GET_STATUSES, 7);
+ notif_ver = iwl_mvm_lookup_wowlan_status_ver(mvm);
- if (!fw_has_api(&mvm->fw->ucode_capa,
- IWL_UCODE_TLV_API_WOWLAN_KEY_MATERIAL)) {
+ if (notif_ver < 7) {
struct iwl_wowlan_status_v6 *v6 = (void *)cmd.resp_pkt->data;
status = iwl_mvm_parse_wowlan_status_common_v6(mvm, v6, len);
@@ -2154,29 +2310,29 @@ iwl_mvm_send_wowlan_get_status(struct iwl_mvm *mvm, u8 sta_id)
goto out_free_resp;
BUILD_BUG_ON(sizeof(v6->gtk.decrypt_key) >
- sizeof(status->gtk.key));
+ sizeof(status->gtk[0].key));
BUILD_BUG_ON(NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY +
sizeof(v6->gtk.tkip_mic_key) >
- sizeof(status->gtk.key));
+ sizeof(status->gtk[0].key));
/* copy GTK info to the right place */
- memcpy(status->gtk.key, v6->gtk.decrypt_key,
+ memcpy(status->gtk[0].key, v6->gtk.decrypt_key,
sizeof(v6->gtk.decrypt_key));
- memcpy(status->gtk.key + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY,
+ memcpy(status->gtk[0].key + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY,
v6->gtk.tkip_mic_key,
sizeof(v6->gtk.tkip_mic_key));
iwl_mvm_convert_key_counters(status, &v6->gtk.rsc.all_tsc_rsc);
/* hardcode the key length to 16 since v6 only supports 16 */
- status->gtk.len = 16;
+ status->gtk[0].len = 16;
/*
* The key index only uses 2 bits (values 0 to 3) and
* we always set bit 7 which means this is the
* currently used key.
*/
- status->gtk.flags = v6->gtk.key_index | BIT(7);
+ status->gtk[0].flags = v6->gtk.key_index | BIT(7);
} else if (notif_ver == 7) {
struct iwl_wowlan_status_v7 *v7 = (void *)cmd.resp_pkt->data;
@@ -2210,7 +2366,7 @@ iwl_mvm_send_wowlan_get_status(struct iwl_mvm *mvm, u8 sta_id)
goto out_free_resp;
iwl_mvm_convert_key_counters_v5(status, &v12->gtk[0].sc);
- iwl_mvm_convert_gtk_v3(status, &v12->gtk[0]);
+ iwl_mvm_convert_gtk_v3(status, v12->gtk);
iwl_mvm_convert_igtk(status, &v12->igtk[0]);
status->tid_tear_down = v12->tid_tear_down;
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c
index 3613b1fdc5d9..cb4ecad6103f 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
- * Copyright (C) 2012-2014, 2018-2021 Intel Corporation
+ * Copyright (C) 2012-2014, 2018-2023 Intel Corporation
* Copyright (C) 2013-2015 Intel Mobile Communications GmbH
* Copyright (C) 2016-2017 Intel Deutschland GmbH
*/
@@ -554,7 +554,7 @@ static ssize_t iwl_dbgfs_uapsd_misbehaving_read(struct file *file,
char buf[20];
int len;
- len = sprintf(buf, "%pM\n", mvmvif->uapsd_misbehaving_bssid);
+ len = sprintf(buf, "%pM\n", mvmvif->uapsd_misbehaving_ap_addr);
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
@@ -567,7 +567,7 @@ static ssize_t iwl_dbgfs_uapsd_misbehaving_write(struct ieee80211_vif *vif,
bool ret;
mutex_lock(&mvm->mutex);
- ret = mac_pton(buf, mvmvif->uapsd_misbehaving_bssid);
+ ret = mac_pton(buf, mvmvif->uapsd_misbehaving_ap_addr);
mutex_unlock(&mvm->mutex);
return ret ? count : -EINVAL;
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c
index 84a488538427..cf27f106d4d5 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c
@@ -15,6 +15,7 @@
#include "iwl-io.h"
#include "debugfs.h"
#include "iwl-modparams.h"
+#include "iwl-drv.h"
#include "fw/error-dump.h"
#include "fw/api/phy-ctxt.h"
@@ -391,13 +392,14 @@ static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf,
return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
}
-static ssize_t iwl_dbgfs_rs_data_read(struct file *file, char __user *user_buf,
+static ssize_t iwl_dbgfs_rs_data_read(struct ieee80211_link_sta *link_sta,
+ struct iwl_mvm_sta *mvmsta,
+ struct iwl_mvm *mvm,
+ struct iwl_mvm_link_sta *mvm_link_sta,
+ char __user *user_buf,
size_t count, loff_t *ppos)
{
- struct ieee80211_sta *sta = file->private_data;
- struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
- struct iwl_lq_sta_rs_fw *lq_sta = &mvmsta->deflink.lq_sta.rs_fw;
- struct iwl_mvm *mvm = lq_sta->pers.drv;
+ struct iwl_lq_sta_rs_fw *lq_sta = &mvm_link_sta->lq_sta.rs_fw;
static const size_t bufsz = 2048;
char *buff;
int desc = 0;
@@ -407,8 +409,6 @@ static ssize_t iwl_dbgfs_rs_data_read(struct file *file, char __user *user_buf,
if (!buff)
return -ENOMEM;
- mutex_lock(&mvm->mutex);
-
desc += scnprintf(buff + desc, bufsz - desc, "sta_id %d\n",
lq_sta->pers.sta_id);
desc += scnprintf(buff + desc, bufsz - desc,
@@ -429,18 +429,19 @@ static ssize_t iwl_dbgfs_rs_data_read(struct file *file, char __user *user_buf,
lq_sta->last_rate_n_flags);
if (desc < bufsz - 1)
buff[desc++] = '\n';
- mutex_unlock(&mvm->mutex);
ret = simple_read_from_buffer(user_buf, count, ppos, buff, desc);
kfree(buff);
return ret;
}
-static ssize_t iwl_dbgfs_amsdu_len_write(struct ieee80211_sta *sta,
+static ssize_t iwl_dbgfs_amsdu_len_write(struct ieee80211_link_sta *link_sta,
+ struct iwl_mvm_sta *mvmsta,
+ struct iwl_mvm *mvm,
+ struct iwl_mvm_link_sta *mvm_link_sta,
char *buf, size_t count,
loff_t *ppos)
{
- struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
int i;
u16 amsdu_len;
@@ -448,36 +449,39 @@ static ssize_t iwl_dbgfs_amsdu_len_write(struct ieee80211_sta *sta,
return -EINVAL;
/* only change from debug set <-> debug unset */
- if (amsdu_len && mvmsta->orig_amsdu_len)
+ if (amsdu_len && mvm_link_sta->orig_amsdu_len)
return -EBUSY;
if (amsdu_len) {
- mvmsta->orig_amsdu_len = sta->cur->max_amsdu_len;
- sta->deflink.agg.max_amsdu_len = amsdu_len;
- sta->deflink.agg.max_amsdu_len = amsdu_len;
- for (i = 0; i < ARRAY_SIZE(sta->deflink.agg.max_tid_amsdu_len); i++)
- sta->deflink.agg.max_tid_amsdu_len[i] = amsdu_len;
+ mvm_link_sta->orig_amsdu_len = link_sta->agg.max_amsdu_len;
+ link_sta->agg.max_amsdu_len = amsdu_len;
+ link_sta->agg.max_amsdu_len = amsdu_len;
+ for (i = 0; i < ARRAY_SIZE(link_sta->agg.max_tid_amsdu_len); i++)
+ link_sta->agg.max_tid_amsdu_len[i] = amsdu_len;
} else {
- sta->deflink.agg.max_amsdu_len = mvmsta->orig_amsdu_len;
- mvmsta->orig_amsdu_len = 0;
+ link_sta->agg.max_amsdu_len = mvm_link_sta->orig_amsdu_len;
+ mvm_link_sta->orig_amsdu_len = 0;
}
+ ieee80211_sta_recalc_aggregates(link_sta->sta);
+
return count;
}
-static ssize_t iwl_dbgfs_amsdu_len_read(struct file *file,
+static ssize_t iwl_dbgfs_amsdu_len_read(struct ieee80211_link_sta *link_sta,
+ struct iwl_mvm_sta *mvmsta,
+ struct iwl_mvm *mvm,
+ struct iwl_mvm_link_sta *mvm_link_sta,
char __user *user_buf,
size_t count, loff_t *ppos)
{
- struct ieee80211_sta *sta = file->private_data;
- struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
-
char buf[32];
int pos;
- pos = scnprintf(buf, sizeof(buf), "current %d ", sta->cur->max_amsdu_len);
+ pos = scnprintf(buf, sizeof(buf), "current %d ",
+ link_sta->agg.max_amsdu_len);
pos += scnprintf(buf + pos, sizeof(buf) - pos, "stored %d\n",
- mvmsta->orig_amsdu_len);
+ mvm_link_sta->orig_amsdu_len);
return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
}
@@ -712,6 +716,7 @@ static ssize_t iwl_dbgfs_fw_ver_read(struct file *file, char __user *user_buf,
struct iwl_mvm *mvm = file->private_data;
char *buff, *pos, *endpos;
static const size_t bufsz = 1024;
+ char _fw_name_pre[FW_NAME_PRE_BUFSIZE];
int ret;
buff = kmalloc(bufsz, GFP_KERNEL);
@@ -722,7 +727,7 @@ static ssize_t iwl_dbgfs_fw_ver_read(struct file *file, char __user *user_buf,
endpos = pos + bufsz;
pos += scnprintf(pos, endpos - pos, "FW prefix: %s\n",
- mvm->trans->cfg->fw_name_pre);
+ iwl_drv_get_fwname_pre(mvm->trans, _fw_name_pre));
pos += scnprintf(pos, endpos - pos, "FW: %s\n",
mvm->fwrt.fw->human_readable);
pos += scnprintf(pos, endpos - pos, "Device: %s\n",
@@ -1596,17 +1601,127 @@ static ssize_t iwl_dbgfs_dbg_time_point_write(struct iwl_mvm *mvm,
#define MVM_DEBUGFS_ADD_FILE(name, parent, mode) \
MVM_DEBUGFS_ADD_FILE_ALIAS(#name, name, parent, mode)
-#define MVM_DEBUGFS_WRITE_STA_FILE_OPS(name, bufsz) \
- _MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz, struct ieee80211_sta)
-#define MVM_DEBUGFS_READ_WRITE_STA_FILE_OPS(name, bufsz) \
- _MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz, struct ieee80211_sta)
+static ssize_t
+_iwl_dbgfs_link_sta_wrap_write(ssize_t (*real)(struct ieee80211_link_sta *,
+ struct iwl_mvm_sta *,
+ struct iwl_mvm *,
+ struct iwl_mvm_link_sta *,
+ char *,
+ size_t, loff_t *),
+ struct file *file,
+ char *buf, size_t buf_size, loff_t *ppos)
+{
+ struct ieee80211_link_sta *link_sta = file->private_data;
+ struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(link_sta->sta);
+ struct iwl_mvm *mvm = iwl_mvm_vif_from_mac80211(mvmsta->vif)->mvm;
+ struct iwl_mvm_link_sta *mvm_link_sta;
+ ssize_t ret;
-#define MVM_DEBUGFS_ADD_STA_FILE_ALIAS(alias, name, parent, mode) do { \
- debugfs_create_file(alias, mode, parent, sta, \
- &iwl_dbgfs_##name##_ops); \
- } while (0)
-#define MVM_DEBUGFS_ADD_STA_FILE(name, parent, mode) \
- MVM_DEBUGFS_ADD_STA_FILE_ALIAS(#name, name, parent, mode)
+ mutex_lock(&mvm->mutex);
+
+ mvm_link_sta = rcu_dereference_protected(mvmsta->link[link_sta->link_id],
+ lockdep_is_held(&mvm->mutex));
+ if (WARN_ON(!mvm_link_sta)) {
+ mutex_unlock(&mvm->mutex);
+ return -ENODEV;
+ }
+
+ ret = real(link_sta, mvmsta, mvm, mvm_link_sta, buf, buf_size, ppos);
+
+ mutex_unlock(&mvm->mutex);
+
+ return ret;
+}
+
+static ssize_t
+_iwl_dbgfs_link_sta_wrap_read(ssize_t (*real)(struct ieee80211_link_sta *,
+ struct iwl_mvm_sta *,
+ struct iwl_mvm *,
+ struct iwl_mvm_link_sta *,
+ char __user *,
+ size_t, loff_t *),
+ struct file *file,
+ char __user *user_buf, size_t count, loff_t *ppos)
+{
+ struct ieee80211_link_sta *link_sta = file->private_data;
+ struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(link_sta->sta);
+ struct iwl_mvm *mvm = iwl_mvm_vif_from_mac80211(mvmsta->vif)->mvm;
+ struct iwl_mvm_link_sta *mvm_link_sta;
+ ssize_t ret;
+
+ mutex_lock(&mvm->mutex);
+
+ mvm_link_sta = rcu_dereference_protected(mvmsta->link[link_sta->link_id],
+ lockdep_is_held(&mvm->mutex));
+ if (WARN_ON(!mvm_link_sta)) {
+ mutex_unlock(&mvm->mutex);
+ return -ENODEV;
+ }
+
+ ret = real(link_sta, mvmsta, mvm, mvm_link_sta, user_buf, count, ppos);
+
+ mutex_unlock(&mvm->mutex);
+
+ return ret;
+}
+
+#define MVM_DEBUGFS_LINK_STA_WRITE_WRAPPER(name, buflen) \
+static ssize_t _iwl_dbgfs_link_sta_##name##_write(struct file *file, \
+ const char __user *user_buf, \
+ size_t count, loff_t *ppos) \
+{ \
+ char buf[buflen] = {}; \
+ size_t buf_size = min(count, sizeof(buf) - 1); \
+ \
+ if (copy_from_user(buf, user_buf, sizeof(buf))) \
+ return -EFAULT; \
+ \
+ return _iwl_dbgfs_link_sta_wrap_write(iwl_dbgfs_##name##_write, \
+ file, \
+ buf, buf_size, ppos); \
+} \
+
+#define MVM_DEBUGFS_LINK_STA_READ_WRAPPER(name) \
+static ssize_t _iwl_dbgfs_link_sta_##name##_read(struct file *file, \
+ char __user *user_buf, \
+ size_t count, loff_t *ppos) \
+{ \
+ return _iwl_dbgfs_link_sta_wrap_read(iwl_dbgfs_##name##_read, \
+ file, \
+ user_buf, count, ppos); \
+} \
+
+#define MVM_DEBUGFS_WRITE_LINK_STA_FILE_OPS(name, bufsz) \
+MVM_DEBUGFS_LINK_STA_WRITE_WRAPPER(name, bufsz) \
+static const struct file_operations iwl_dbgfs_link_sta_##name##_ops = { \
+ .write = _iwl_dbgfs_link_sta_##name##_write, \
+ .open = simple_open, \
+ .llseek = generic_file_llseek, \
+}
+
+#define MVM_DEBUGFS_READ_LINK_STA_FILE_OPS(name) \
+MVM_DEBUGFS_LINK_STA_READ_WRAPPER(name) \
+static const struct file_operations iwl_dbgfs_link_sta_##name##_ops = { \
+ .read = _iwl_dbgfs_link_sta_##name##_read, \
+ .open = simple_open, \
+ .llseek = generic_file_llseek, \
+}
+
+#define MVM_DEBUGFS_READ_WRITE_LINK_STA_FILE_OPS(name, bufsz) \
+MVM_DEBUGFS_LINK_STA_READ_WRAPPER(name) \
+MVM_DEBUGFS_LINK_STA_WRITE_WRAPPER(name, bufsz) \
+static const struct file_operations iwl_dbgfs_link_sta_##name##_ops = { \
+ .read = _iwl_dbgfs_link_sta_##name##_read, \
+ .write = _iwl_dbgfs_link_sta_##name##_write, \
+ .open = simple_open, \
+ .llseek = generic_file_llseek, \
+}
+
+#define MVM_DEBUGFS_ADD_LINK_STA_FILE_ALIAS(alias, name, parent, mode) \
+ debugfs_create_file(alias, mode, parent, link_sta, \
+ &iwl_dbgfs_link_sta_##name##_ops)
+#define MVM_DEBUGFS_ADD_LINK_STA_FILE(name, parent, mode) \
+ MVM_DEBUGFS_ADD_LINK_STA_FILE_ALIAS(#name, name, parent, mode)
static ssize_t
iwl_dbgfs_prph_reg_read(struct file *file,
@@ -1891,7 +2006,7 @@ MVM_DEBUGFS_READ_WRITE_FILE_OPS(sram, 64);
MVM_DEBUGFS_READ_WRITE_FILE_OPS(set_nic_temperature, 64);
MVM_DEBUGFS_READ_FILE_OPS(nic_temp);
MVM_DEBUGFS_READ_FILE_OPS(stations);
-MVM_DEBUGFS_READ_FILE_OPS(rs_data);
+MVM_DEBUGFS_READ_LINK_STA_FILE_OPS(rs_data);
MVM_DEBUGFS_READ_FILE_OPS(bt_notif);
MVM_DEBUGFS_READ_FILE_OPS(bt_cmd);
MVM_DEBUGFS_READ_WRITE_FILE_OPS(disable_power_off, 64);
@@ -1921,7 +2036,7 @@ MVM_DEBUGFS_READ_FILE_OPS(sar_geo_profile);
MVM_DEBUGFS_READ_FILE_OPS(wifi_6e_enable);
#endif
-MVM_DEBUGFS_READ_WRITE_STA_FILE_OPS(amsdu_len, 16);
+MVM_DEBUGFS_READ_WRITE_LINK_STA_FILE_OPS(amsdu_len, 16);
MVM_DEBUGFS_READ_WRITE_FILE_OPS(he_sniffer_params, 32);
@@ -2068,17 +2183,18 @@ static const struct file_operations iwl_dbgfs_mem_ops = {
.llseek = default_llseek,
};
-void iwl_mvm_sta_add_debugfs(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta,
- struct dentry *dir)
+void iwl_mvm_link_sta_add_debugfs(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_link_sta *link_sta,
+ struct dentry *dir)
{
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
if (iwl_mvm_has_tlc_offload(mvm)) {
- MVM_DEBUGFS_ADD_STA_FILE(rs_data, dir, 0400);
+ MVM_DEBUGFS_ADD_LINK_STA_FILE(rs_data, dir, 0400);
}
- MVM_DEBUGFS_ADD_STA_FILE(amsdu_len, dir, 0600);
+
+ MVM_DEBUGFS_ADD_LINK_STA_FILE(amsdu_len, dir, 0600);
}
void iwl_mvm_dbgfs_register(struct iwl_mvm *mvm)
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c
index 652a603c4500..233ae81884a0 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c
@@ -72,15 +72,24 @@ int iwl_mvm_ftm_add_pasn_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
* the TK is already configured for this station, so it
* shouldn't be set again here.
*/
- if (vif->cfg.assoc &&
- !memcmp(addr, vif->bss_conf.bssid, ETH_ALEN)) {
+ if (vif->cfg.assoc) {
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ struct ieee80211_bss_conf *link_conf;
+ unsigned int link_id;
struct ieee80211_sta *sta;
+ u8 sta_id;
rcu_read_lock();
- sta = rcu_dereference(mvm->fw_id_to_mac_id[mvmvif->deflink.ap_sta_id]);
- if (!IS_ERR_OR_NULL(sta) && sta->mfp)
- expected_tk_len = 0;
+ for_each_vif_active_link(vif, link_conf, link_id) {
+ if (memcmp(addr, link_conf->bssid, ETH_ALEN))
+ continue;
+
+ sta_id = mvmvif->link[link_id]->ap_sta_id;
+ sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]);
+ if (!IS_ERR_OR_NULL(sta) && sta->mfp)
+ expected_tk_len = 0;
+ break;
+ }
rcu_read_unlock();
}
@@ -518,25 +527,30 @@ iwl_mvm_ftm_put_target(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
iwl_mvm_ftm_put_target_common(mvm, peer, target);
- if (vif->cfg.assoc &&
- !memcmp(peer->addr, vif->bss_conf.bssid, ETH_ALEN)) {
+ if (vif->cfg.assoc) {
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct ieee80211_sta *sta;
+ struct ieee80211_bss_conf *link_conf;
+ unsigned int link_id;
rcu_read_lock();
+ for_each_vif_active_link(vif, link_conf, link_id) {
+ if (memcmp(peer->addr, link_conf->bssid, ETH_ALEN))
+ continue;
+
+ target->sta_id = mvmvif->link[link_id]->ap_sta_id;
+ sta = rcu_dereference(mvm->fw_id_to_mac_id[target->sta_id]);
+ if (WARN_ON_ONCE(IS_ERR_OR_NULL(sta))) {
+ rcu_read_unlock();
+ return PTR_ERR_OR_ZERO(sta);
+ }
- sta = rcu_dereference(mvm->fw_id_to_mac_id[mvmvif->deflink.ap_sta_id]);
- if (WARN_ON_ONCE(IS_ERR_OR_NULL(sta))) {
- rcu_read_unlock();
- return PTR_ERR_OR_ZERO(sta);
+ if (sta->mfp && (peer->ftm.trigger_based ||
+ peer->ftm.non_trigger_based))
+ FTM_PUT_FLAG(PMF);
+ break;
}
-
- if (sta->mfp && (peer->ftm.trigger_based || peer->ftm.non_trigger_based))
- FTM_PUT_FLAG(PMF);
-
rcu_read_unlock();
-
- target->sta_id = mvmvif->deflink.ap_sta_id;
} else {
target->sta_id = IWL_MVM_INVALID_STA;
}
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c
index 1b6fb73ddfc7..b49781d1a07a 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c
@@ -104,7 +104,8 @@ iwl_mvm_ftm_responder_set_ndp(struct iwl_mvm *mvm,
static int
iwl_mvm_ftm_responder_cmd(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
- struct cfg80211_chan_def *chandef)
+ struct cfg80211_chan_def *chandef,
+ struct ieee80211_bss_conf *link_conf)
{
u32 cmd_id = WIDE_ID(LOCATION_GROUP, TOF_RESPONDER_CONFIG_CMD);
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
@@ -119,7 +120,7 @@ iwl_mvm_ftm_responder_cmd(struct iwl_mvm *mvm,
cpu_to_le32(IWL_TOF_RESPONDER_CMD_VALID_CHAN_INFO |
IWL_TOF_RESPONDER_CMD_VALID_BSSID |
IWL_TOF_RESPONDER_CMD_VALID_STA_ID),
- .sta_id = mvmvif->deflink.bcast_sta.sta_id,
+ .sta_id = mvmvif->link[link_conf->link_id]->bcast_sta.sta_id,
};
u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, cmd_id, 6);
int err;
@@ -386,7 +387,8 @@ int iwl_mvm_ftm_resp_remove_pasn_sta(struct iwl_mvm *mvm,
return -EINVAL;
}
-int iwl_mvm_ftm_start_responder(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
+int iwl_mvm_ftm_start_responder(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+ struct ieee80211_bss_conf *bss_conf)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct ieee80211_ftm_responder_params *params;
@@ -395,11 +397,11 @@ int iwl_mvm_ftm_start_responder(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
struct iwl_mvm_phy_ctxt *phy_ctxt;
int ret;
- params = vif->bss_conf.ftmr_params;
+ params = bss_conf->ftmr_params;
lockdep_assert_held(&mvm->mutex);
- if (WARN_ON_ONCE(!vif->bss_conf.ftm_responder))
+ if (WARN_ON_ONCE(!bss_conf->ftm_responder))
return -EINVAL;
if (vif->p2p || vif->type != NL80211_IFTYPE_AP ||
@@ -409,7 +411,7 @@ int iwl_mvm_ftm_start_responder(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
}
rcu_read_lock();
- pctx = rcu_dereference(vif->bss_conf.chanctx_conf);
+ pctx = rcu_dereference(bss_conf->chanctx_conf);
/* Copy the ctx to unlock the rcu and send the phy ctxt. We don't care
* about changes in the ctx after releasing the lock because the driver
* is still protected by the mutex. */
@@ -424,7 +426,7 @@ int iwl_mvm_ftm_start_responder(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
if (ret)
return ret;
- ret = iwl_mvm_ftm_responder_cmd(mvm, vif, &ctx.def);
+ ret = iwl_mvm_ftm_responder_cmd(mvm, vif, &ctx.def, bss_conf);
if (ret)
return ret;
@@ -446,13 +448,14 @@ void iwl_mvm_ftm_responder_clear(struct iwl_mvm *mvm,
}
void iwl_mvm_ftm_restart_responder(struct iwl_mvm *mvm,
- struct ieee80211_vif *vif)
+ struct ieee80211_vif *vif,
+ struct ieee80211_bss_conf *bss_conf)
{
- if (!vif->bss_conf.ftm_responder)
+ if (!bss_conf->ftm_responder)
return;
iwl_mvm_ftm_responder_clear(mvm, vif);
- iwl_mvm_ftm_start_responder(mvm, vif);
+ iwl_mvm_ftm_start_responder(mvm, vif, bss_conf);
}
void iwl_mvm_ftm_responder_stats(struct iwl_mvm *mvm,
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
index 205c09bc9863..1f5db65a088d 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
- * Copyright (C) 2012-2014, 2018-2022 Intel Corporation
+ * Copyright (C) 2012-2014, 2018-2023 Intel Corporation
* Copyright (C) 2013-2015 Intel Mobile Communications GmbH
* Copyright (C) 2016-2017 Intel Deutschland GmbH
*/
@@ -433,7 +433,8 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm,
/* if reached this point, Alive notification was received */
iwl_mei_alive_notif(true);
- ret = iwl_pnvm_load(mvm->trans, &mvm->notif_wait);
+ ret = iwl_pnvm_load(mvm->trans, &mvm->notif_wait,
+ &mvm->fw->ucode_capa);
if (ret) {
IWL_ERR(mvm, "Timeout waiting for PNVM load!\n");
iwl_fw_set_current_image(&mvm->fwrt, old_type);
@@ -477,40 +478,13 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm,
return 0;
}
-#ifdef CONFIG_ACPI
-static void iwl_mvm_phy_filter_init(struct iwl_mvm *mvm,
- struct iwl_phy_specific_cfg *phy_filters)
-{
- /*
- * TODO: read specific phy config from BIOS
- * ACPI table for this feature has not been defined yet,
- * so for now we use hardcoded values.
- */
-
- if (IWL_MVM_PHY_FILTER_CHAIN_A) {
- phy_filters->filter_cfg_chain_a =
- cpu_to_le32(IWL_MVM_PHY_FILTER_CHAIN_A);
- }
- if (IWL_MVM_PHY_FILTER_CHAIN_B) {
- phy_filters->filter_cfg_chain_b =
- cpu_to_le32(IWL_MVM_PHY_FILTER_CHAIN_B);
- }
- if (IWL_MVM_PHY_FILTER_CHAIN_C) {
- phy_filters->filter_cfg_chain_c =
- cpu_to_le32(IWL_MVM_PHY_FILTER_CHAIN_C);
- }
- if (IWL_MVM_PHY_FILTER_CHAIN_D) {
- phy_filters->filter_cfg_chain_d =
- cpu_to_le32(IWL_MVM_PHY_FILTER_CHAIN_D);
- }
-}
-#else /* CONFIG_ACPI */
-
static void iwl_mvm_phy_filter_init(struct iwl_mvm *mvm,
struct iwl_phy_specific_cfg *phy_filters)
{
-}
+#ifdef CONFIG_ACPI
+ *phy_filters = mvm->phy_filters;
#endif /* CONFIG_ACPI */
+}
#if defined(CONFIG_ACPI) && defined(CONFIG_EFI)
static int iwl_mvm_sgom_init(struct iwl_mvm *mvm)
@@ -559,7 +533,6 @@ static int iwl_send_phy_cfg_cmd(struct iwl_mvm *mvm)
u32 cmd_id = PHY_CONFIGURATION_CMD;
struct iwl_phy_cfg_cmd_v3 phy_cfg_cmd;
enum iwl_ucode_type ucode_type = mvm->fwrt.cur_fw_img;
- struct iwl_phy_specific_cfg phy_filters = {};
u8 cmd_ver;
size_t cmd_size;
@@ -590,11 +563,8 @@ static int iwl_send_phy_cfg_cmd(struct iwl_mvm *mvm)
cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, cmd_id,
IWL_FW_CMD_VER_UNKNOWN);
- if (cmd_ver == 3) {
- iwl_mvm_phy_filter_init(mvm, &phy_filters);
- memcpy(&phy_cfg_cmd.phy_specific_cfg, &phy_filters,
- sizeof(struct iwl_phy_specific_cfg));
- }
+ if (cmd_ver >= 3)
+ iwl_mvm_phy_filter_init(mvm, &phy_cfg_cmd.phy_specific_cfg);
IWL_DEBUG_INFO(mvm, "Sending Phy CFG command: 0x%x\n",
phy_cfg_cmd.phy_cfg);
@@ -1104,7 +1074,26 @@ static const struct dmi_system_id dmi_tas_approved_list[] = {
DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
},
},
-
+ { .ident = "Acer",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+ },
+ },
+ { .ident = "ASUS",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+ },
+ },
+ { .ident = "MSI",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International Co., Ltd."),
+ },
+ },
+ { .ident = "Honor",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "HONOR"),
+ },
+ },
/* keep last */
{}
};
@@ -1162,7 +1151,7 @@ static void iwl_mvm_tas_init(struct iwl_mvm *mvm)
if (ret == 0)
return;
- if (!dmi_check_system(dmi_tas_approved_list)) {
+ if (!iwl_mvm_is_vendor_in_approved_list()) {
IWL_DEBUG_RADIO(mvm,
"System vendor '%s' is not in the approved list, disabling TAS in US and Canada.\n",
dmi_get_system_info(DMI_SYS_VENDOR));
@@ -1176,6 +1165,10 @@ static void iwl_mvm_tas_init(struct iwl_mvm *mvm)
"Unable to add US/Canada to TAS block list, disabling TAS\n");
return;
}
+ } else {
+ IWL_DEBUG_RADIO(mvm,
+ "System vendor '%s' is in the approved list.\n",
+ dmi_get_system_info(DMI_SYS_VENDOR));
}
/* v4 is the same size as v3, so no need to differentiate here */
@@ -1356,6 +1349,8 @@ void iwl_mvm_get_acpi_tables(struct iwl_mvm *mvm)
/* we don't fail if the table is not available */
}
}
+
+ iwl_acpi_get_phy_filters(&mvm->fwrt, &mvm->phy_filters);
}
#else /* CONFIG_ACPI */
@@ -1571,6 +1566,8 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
goto error;
}
+ iwl_mvm_lari_cfg(mvm);
+
/* Init RSS configuration */
ret = iwl_configure_rxq(&mvm->fwrt);
if (ret)
@@ -1591,6 +1588,9 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
RCU_INIT_POINTER(mvm->fw_id_to_link_sta[i], NULL);
}
+ for (i = 0; i < IWL_MVM_FW_MAX_LINK_ID + 1; i++)
+ RCU_INIT_POINTER(mvm->link_id_to_link_conf[i], NULL);
+
memset(&mvm->fw_link_ids_map, 0, sizeof(mvm->fw_link_ids_map));
mvm->tdls_cs.peer.sta_id = IWL_MVM_INVALID_STA;
@@ -1610,7 +1610,7 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
* internal aux station for all aux activities that don't
* requires a dedicated data queue.
*/
- if (iwl_fw_lookup_cmd_ver(mvm->fw, ADD_STA, 0) < 12) {
+ if (!iwl_mvm_has_new_station_api(mvm->fw)) {
/*
* In old version the aux station uses mac id like other
* station and not lmac id
@@ -1678,7 +1678,6 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
if (ret)
goto error;
- iwl_mvm_lari_cfg(mvm);
/*
* RTNL is not taken during Ct-kill, but we don't need to scan/Tx
* anyway, so don't init MCC.
@@ -1699,9 +1698,11 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) {
iwl_mvm_send_recovery_cmd(mvm, ERROR_RECOVERY_UPDATE_DB);
- iwl_mvm_time_sync_config(mvm, mvm->time_sync.peer_addr,
- IWL_TIME_SYNC_PROTOCOL_TM |
- IWL_TIME_SYNC_PROTOCOL_FTM);
+
+ if (mvm->time_sync.active)
+ iwl_mvm_time_sync_config(mvm, mvm->time_sync.peer_addr,
+ IWL_TIME_SYNC_PROTOCOL_TM |
+ IWL_TIME_SYNC_PROTOCOL_FTM);
}
if (!mvm->ptp_data.ptp_clock)
@@ -1777,7 +1778,7 @@ int iwl_mvm_load_d3_fw(struct iwl_mvm *mvm)
RCU_INIT_POINTER(mvm->fw_id_to_link_sta[i], NULL);
}
- if (iwl_fw_lookup_cmd_ver(mvm->fw, ADD_STA, 0) < 12) {
+ if (!iwl_mvm_has_new_station_api(mvm->fw)) {
/*
* Add auxiliary station for scanning.
* Newer versions of this command implies that the fw uses
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/link.c b/drivers/net/wireless/intel/iwlwifi/mvm/link.c
index 3814915cb1a6..ace82e2c5bd9 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/link.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/link.c
@@ -63,6 +63,9 @@ int iwl_mvm_add_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
mvmvif);
if (link_info->fw_link_id == IWL_MVM_FW_LINK_ID_INVALID)
return -EINVAL;
+
+ rcu_assign_pointer(mvm->link_id_to_link_conf[link_info->fw_link_id],
+ link_conf);
}
/* Update SF - Disable if needed. if this fails, SF might still be on
@@ -73,6 +76,7 @@ int iwl_mvm_add_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
cmd.link_id = cpu_to_le32(link_info->fw_link_id);
cmd.mac_id = cpu_to_le32(mvmvif->id);
+ cmd.spec_link_id = link_conf->link_id;
/* P2P-Device already has a valid PHY context during add */
phyctxt = link_info->phy_ctxt;
if (phyctxt)
@@ -85,6 +89,8 @@ int iwl_mvm_add_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
if (vif->type == NL80211_IFTYPE_ADHOC && link_conf->bssid)
memcpy(cmd.ibss_bssid_addr, link_conf->bssid, ETH_ALEN);
+ cmd.listen_lmac = cpu_to_le32(link_info->listen_lmac);
+
return iwl_mvm_link_cmd_send(mvm, &cmd, FW_CTXT_ACTION_ADD);
}
@@ -114,24 +120,6 @@ int iwl_mvm_link_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
if (!link_info->phy_ctxt)
return 0;
- /* check there aren't too many active links */
- if (!link_info->active && active) {
- int i, count = 0;
-
- /* link with phy_ctxt is active in FW */
- for_each_mvm_vif_valid_link(mvmvif, i)
- if (mvmvif->link[i]->phy_ctxt)
- count++;
-
- if (vif->type == NL80211_IFTYPE_AP) {
- if (count > mvm->fw->ucode_capa.num_beacons)
- return -EOPNOTSUPP;
- /* this should be per HW or such */
- } else if (count >= IWL_MVM_FW_MAX_ACTIVE_LINKS_NUM) {
- return -EOPNOTSUPP;
- }
- }
-
/* Catch early if driver tries to activate or deactivate a link
* twice.
*/
@@ -163,10 +151,6 @@ int iwl_mvm_link_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
if (vif->type == NL80211_IFTYPE_ADHOC && link_conf->bssid)
memcpy(cmd.ibss_bssid_addr, link_conf->bssid, ETH_ALEN);
- /* TODO: set a value to cmd.listen_lmac when system requiremens
- * will define it
- */
-
iwl_mvm_set_fw_basic_rates(mvm, vif, link_conf,
&cmd.cck_rates, &cmd.ofdm_rates);
@@ -179,7 +163,7 @@ int iwl_mvm_link_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
&cmd.protection_flags,
ht_flag, LINK_PROT_FLG_TGG_PROTECT);
- iwl_mvm_set_fw_qos_params(mvm, vif, link_conf, &cmd.ac[0],
+ iwl_mvm_set_fw_qos_params(mvm, vif, link_conf, cmd.ac,
&cmd.qos_flags);
@@ -204,7 +188,7 @@ int iwl_mvm_link_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
/* TODO how to set ndp_fdbk_buff_th_exp? */
- if (iwl_mvm_set_fw_mu_edca_params(mvm, mvmvif,
+ if (iwl_mvm_set_fw_mu_edca_params(mvm, mvmvif->link[link_id],
&cmd.trig_based_txf[0])) {
flags |= LINK_FLG_MU_EDCA_CW;
flags_mask |= LINK_FLG_MU_EDCA_CW;
@@ -241,6 +225,8 @@ send_cmd:
cmd.modify_mask = cpu_to_le32(changes);
cmd.flags = cpu_to_le32(flags);
cmd.flags_mask = cpu_to_le32(flags_mask);
+ cmd.spec_link_id = link_conf->link_id;
+ cmd.listen_lmac = cpu_to_le32(link_info->listen_lmac);
ret = iwl_mvm_link_cmd_send(mvm, &cmd, FW_CTXT_ACTION_MODIFY);
if (!ret && (changes & LINK_CONTEXT_MODIFY_ACTIVE))
@@ -262,9 +248,12 @@ int iwl_mvm_remove_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
link_info->fw_link_id == IWL_MVM_FW_LINK_ID_INVALID))
return -EINVAL;
+ RCU_INIT_POINTER(mvm->link_id_to_link_conf[link_info->fw_link_id],
+ NULL);
cmd.link_id = cpu_to_le32(link_info->fw_link_id);
iwl_mvm_release_fw_link_id(mvm, link_info->fw_link_id);
link_info->fw_link_id = IWL_MVM_FW_LINK_ID_INVALID;
+ cmd.spec_link_id = link_conf->link_id;
ret = iwl_mvm_link_cmd_send(mvm, &cmd, FW_CTXT_ACTION_REMOVE);
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c
index cc90f2884cff..7369a45f7f2b 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
- * Copyright (C) 2012-2014, 2018-2022 Intel Corporation
+ * Copyright (C) 2012-2014, 2018-2023 Intel Corporation
* Copyright (C) 2013-2014 Intel Mobile Communications GmbH
* Copyright (C) 2015-2017 Intel Deutschland GmbH
*/
@@ -470,19 +470,24 @@ void iwl_mvm_set_fw_qos_params(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
struct iwl_ac_qos *ac, __le32 *qos_flags)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ struct iwl_mvm_vif_link_info *mvm_link =
+ mvmvif->link[link_conf->link_id];
int i;
+ if (!mvm_link)
+ return;
+
for (i = 0; i < IEEE80211_NUM_ACS; i++) {
u8 txf = iwl_mvm_mac_ac_to_tx_fifo(mvm, i);
u8 ucode_ac = iwl_mvm_mac80211_ac_to_ucode_ac(i);
ac[ucode_ac].cw_min =
- cpu_to_le16(mvmvif->deflink.queue_params[i].cw_min);
+ cpu_to_le16(mvm_link->queue_params[i].cw_min);
ac[ucode_ac].cw_max =
- cpu_to_le16(mvmvif->deflink.queue_params[i].cw_max);
+ cpu_to_le16(mvm_link->queue_params[i].cw_max);
ac[ucode_ac].edca_txop =
- cpu_to_le16(mvmvif->deflink.queue_params[i].txop * 32);
- ac[ucode_ac].aifsn = mvmvif->deflink.queue_params[i].aifs;
+ cpu_to_le16(mvm_link->queue_params[i].txop * 32);
+ ac[ucode_ac].aifsn = mvm_link->queue_params[i].aifs;
ac[ucode_ac].fifos_mask = BIT(txf);
}
@@ -558,7 +563,7 @@ static void iwl_mvm_mac_ctxt_cmd_common(struct iwl_mvm *mvm,
cmd->filter_flags = 0;
- iwl_mvm_set_fw_qos_params(mvm, vif, &vif->bss_conf, &cmd->ac[0],
+ iwl_mvm_set_fw_qos_params(mvm, vif, &vif->bss_conf, cmd->ac,
&cmd->qos_flags);
/* The fw does not distinguish between ht and fat */
@@ -629,17 +634,17 @@ __le32 iwl_mvm_mac_ctxt_cmd_p2p_sta_get_oppps_ctwin(struct iwl_mvm *mvm,
IEEE80211_P2P_OPPPS_CTWINDOW_MASK);
}
-__le32 iwl_mvm_mac_ctxt_cmd_sta_get_twt_policy(struct iwl_mvm *mvm,
- struct ieee80211_vif *vif)
+u32 iwl_mvm_mac_ctxt_cmd_sta_get_twt_policy(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif)
{
- __le32 twt_policy = cpu_to_le32(0);
+ u32 twt_policy = 0;
if (vif->bss_conf.twt_requester && IWL_MVM_USE_TWT)
- twt_policy |= cpu_to_le32(TWT_SUPPORTED);
+ twt_policy |= TWT_SUPPORTED;
if (vif->bss_conf.twt_protected)
- twt_policy |= cpu_to_le32(PROTECTED_TWT_SUPPORTED);
+ twt_policy |= PROTECTED_TWT_SUPPORTED;
if (vif->bss_conf.twt_broadcast)
- twt_policy |= cpu_to_le32(BROADCAST_TWT_SUPPORTED);
+ twt_policy |= BROADCAST_TWT_SUPPORTED;
return twt_policy;
}
@@ -711,7 +716,7 @@ static int iwl_mvm_mac_ctxt_cmd_sta(struct iwl_mvm *mvm,
if (vif->bss_conf.he_support && !iwlwifi_mod_params.disable_11ax) {
cmd.filter_flags |= cpu_to_le32(MAC_FILTER_IN_11AX);
ctxt_sta->data_policy |=
- iwl_mvm_mac_ctxt_cmd_sta_get_twt_policy(mvm, vif);
+ cpu_to_le32(iwl_mvm_mac_ctxt_cmd_sta_get_twt_policy(mvm, vif));
}
@@ -888,7 +893,7 @@ u8 iwl_mvm_mac_ctxt_get_lowest_rate(struct iwl_mvm *mvm,
u8 rate;
u32 i;
- if (link_id == IEEE80211_LINK_UNSPECIFIED && vif->valid_links) {
+ if (link_id == IEEE80211_LINK_UNSPECIFIED && ieee80211_vif_is_mld(vif)) {
for (i = 0; i < ARRAY_SIZE(mvmvif->link); i++) {
if (!mvmvif->link[i])
continue;
@@ -1111,6 +1116,10 @@ static int iwl_mvm_mac_ctxt_send_beacon_v9(struct iwl_mvm *mvm,
beacon_cmd.flags = cpu_to_le16(flags);
beacon_cmd.byte_cnt = cpu_to_le16((u16)beacon->len);
+
+ if (WARN_ON(!mvmvif->link[link_conf->link_id]))
+ return -EINVAL;
+
if (iwl_fw_lookup_cmd_ver(mvm->fw, BEACON_TEMPLATE_CMD, 0) > 12)
beacon_cmd.link_id =
cpu_to_le32(mvmvif->link[link_conf->link_id]->fw_link_id);
@@ -1555,21 +1564,38 @@ void iwl_mvm_rx_missed_beacons_notif(struct iwl_mvm *mvm,
u32 stop_trig_missed_bcon, stop_trig_missed_bcon_since_rx;
u32 rx_missed_bcon, rx_missed_bcon_since_rx;
struct ieee80211_vif *vif;
- u32 id = le32_to_cpu(mb->mac_id);
+ /* Id can be mac/link id depending on the notification version */
+ u32 id = le32_to_cpu(mb->link_id);
union iwl_dbg_tlv_tp_data tp_data = { .fw_pkt = pkt };
u32 mac_type;
+ u8 notif_ver = iwl_fw_lookup_notif_ver(mvm->fw, LEGACY_GROUP,
+ MISSED_BEACONS_NOTIFICATION,
+ 0);
+
+ rcu_read_lock();
+
+ /* before version four the ID in the notification refers to mac ID */
+ if (notif_ver < 4) {
+ vif = iwl_mvm_rcu_dereference_vif_id(mvm, id, true);
+ } else {
+ struct ieee80211_bss_conf *bss_conf =
+ iwl_mvm_rcu_fw_link_id_to_link_conf(mvm, id, true);
+
+ if (!bss_conf)
+ goto out;
+
+ vif = bss_conf->vif;
+ }
IWL_DEBUG_INFO(mvm,
- "missed bcn mac_id=%u, consecutive=%u (%u, %u, %u)\n",
- le32_to_cpu(mb->mac_id),
+ "missed bcn %s_id=%u, consecutive=%u (%u, %u, %u)\n",
+ notif_ver < 4 ? "mac" : "link",
+ id,
le32_to_cpu(mb->consec_missed_beacons),
le32_to_cpu(mb->consec_missed_beacons_since_last_rx),
le32_to_cpu(mb->num_recvd_beacons),
le32_to_cpu(mb->num_expected_beacons));
- rcu_read_lock();
-
- vif = iwl_mvm_rcu_dereference_vif_id(mvm, id, true);
if (!vif)
goto out;
@@ -1730,20 +1756,47 @@ void iwl_mvm_channel_switch_start_notif(struct iwl_mvm *mvm,
struct iwl_rx_cmd_buffer *rxb)
{
struct iwl_rx_packet *pkt = rxb_addr(rxb);
- struct iwl_channel_switch_start_notif *notif = (void *)pkt->data;
struct ieee80211_vif *csa_vif, *vif;
- struct iwl_mvm_vif *mvmvif;
- u32 id_n_color, csa_id, mac_id;
+ struct iwl_mvm_vif *mvmvif, *csa_mvmvif;
+ u32 id_n_color, csa_id;
+ /* save mac_id or link_id to use later to cancel csa if needed */
+ u32 id;
+ u8 notif_ver = iwl_fw_lookup_notif_ver(mvm->fw, MAC_CONF_GROUP,
+ CHANNEL_SWITCH_START_NOTIF, 0);
+ bool csa_active;
- id_n_color = le32_to_cpu(notif->id_and_color);
- mac_id = id_n_color & FW_CTXT_ID_MSK;
+ rcu_read_lock();
- if (WARN_ON_ONCE(mac_id >= NUM_MAC_INDEX_DRIVER))
- return;
+ if (notif_ver < 3) {
+ struct iwl_channel_switch_start_notif_v1 *notif = (void *)pkt->data;
+ u32 mac_id;
+
+ id_n_color = le32_to_cpu(notif->id_and_color);
+ mac_id = id_n_color & FW_CTXT_ID_MSK;
+
+ vif = iwl_mvm_rcu_dereference_vif_id(mvm, mac_id, true);
+ if (!vif)
+ goto out_unlock;
+
+ id = mac_id;
+ csa_active = vif->bss_conf.csa_active;
+ } else {
+ struct iwl_channel_switch_start_notif *notif = (void *)pkt->data;
+ u32 link_id = le32_to_cpu(notif->link_id);
+ struct ieee80211_bss_conf *bss_conf =
+ iwl_mvm_rcu_fw_link_id_to_link_conf(mvm, link_id, true);
+
+ if (!bss_conf)
+ goto out_unlock;
+
+ id = link_id;
+ vif = bss_conf->vif;
+ csa_active = bss_conf->csa_active;
+ }
- rcu_read_lock();
- vif = rcu_dereference(mvm->vif_id_to_mac[mac_id]);
mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ if (notif_ver >= 3)
+ id_n_color = FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color);
switch (vif->type) {
case NL80211_IFTYPE_AP:
@@ -1752,7 +1805,8 @@ void iwl_mvm_channel_switch_start_notif(struct iwl_mvm *mvm,
csa_vif != vif))
goto out_unlock;
- csa_id = FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color);
+ csa_mvmvif = iwl_mvm_vif_from_mac80211(csa_vif);
+ csa_id = FW_CMD_ID_AND_COLOR(csa_mvmvif->id, csa_mvmvif->color);
if (WARN(csa_id != id_n_color,
"channel switch noa notification on unexpected vif (csa_vif=%d, notif=%d)",
csa_id, id_n_color))
@@ -1777,9 +1831,9 @@ void iwl_mvm_channel_switch_start_notif(struct iwl_mvm *mvm,
*/
if (iwl_fw_lookup_notif_ver(mvm->fw, MAC_CONF_GROUP,
CHANNEL_SWITCH_ERROR_NOTIF,
- 0) && !vif->bss_conf.csa_active) {
+ 0) && !csa_active) {
IWL_DEBUG_INFO(mvm, "Channel Switch was canceled\n");
- iwl_mvm_cancel_channel_switch(mvm, vif, mac_id);
+ iwl_mvm_cancel_channel_switch(mvm, vif, id);
break;
}
@@ -1802,7 +1856,7 @@ void iwl_mvm_channel_switch_error_notif(struct iwl_mvm *mvm,
struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl_channel_switch_error_notif *notif = (void *)pkt->data;
struct ieee80211_vif *vif;
- u32 id = le32_to_cpu(notif->mac_id);
+ u32 id = le32_to_cpu(notif->link_id);
u32 csa_err_mask = le32_to_cpu(notif->csa_err_mask);
rcu_read_lock();
@@ -1812,7 +1866,7 @@ void iwl_mvm_channel_switch_error_notif(struct iwl_mvm *mvm,
return;
}
- IWL_DEBUG_INFO(mvm, "FW reports CSA error: mac_id=%u, csa_err_mask=%u\n",
+ IWL_DEBUG_INFO(mvm, "FW reports CSA error: id=%u, csa_err_mask=%u\n",
id, csa_err_mask);
if (csa_err_mask & (CS_ERR_COUNT_ERROR |
CS_ERR_LONG_DELAY_AFTER_CS |
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
index 17f788a5ff6b..ce7905faa08f 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
@@ -108,7 +108,7 @@ struct ieee80211_regdomain *iwl_mvm_get_regdomain(struct wiphy *wiphy,
struct ieee80211_regdomain *regd = NULL;
struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
- struct iwl_mcc_update_resp *resp;
+ struct iwl_mcc_update_resp_v8 *resp;
u8 resp_ver;
IWL_DEBUG_LAR(mvm, "Getting regdomain data for %s from FW\n", alpha2);
@@ -138,7 +138,7 @@ struct ieee80211_regdomain *iwl_mvm_get_regdomain(struct wiphy *wiphy,
resp->channels,
__le16_to_cpu(resp->mcc),
__le16_to_cpu(resp->geo_info),
- __le16_to_cpu(resp->cap), resp_ver);
+ le32_to_cpu(resp->cap), resp_ver);
/* Store the return source id */
src_id = resp->source_id;
if (IS_ERR_OR_NULL(regd)) {
@@ -245,12 +245,21 @@ static const u8 tm_if_types_ext_capa_sta[] = {
/* Additional interface types for which extended capabilities are
* specified separately
*/
+
+#define IWL_MVM_EMLSR_CAPA (IEEE80211_EML_CAP_EMLSR_SUPP | \
+ IEEE80211_EML_CAP_EMLSR_PADDING_DELAY_32US << \
+ __bf_shf(IEEE80211_EML_CAP_EMLSR_PADDING_DELAY) | \
+ IEEE80211_EML_CAP_EMLSR_TRANSITION_DELAY_64US << \
+ __bf_shf(IEEE80211_EML_CAP_EMLSR_TRANSITION_DELAY))
+
static const struct wiphy_iftype_ext_capab add_iftypes_ext_capa[] = {
{
.iftype = NL80211_IFTYPE_STATION,
.extended_capabilities = he_if_types_ext_capa_sta,
.extended_capabilities_mask = he_if_types_ext_capa_sta,
.extended_capabilities_len = sizeof(he_if_types_ext_capa_sta),
+ /* relevant only if EHT is supported */
+ .eml_capabilities = IWL_MVM_EMLSR_CAPA,
},
{
.iftype = NL80211_IFTYPE_STATION,
@@ -258,7 +267,7 @@ static const struct wiphy_iftype_ext_capab add_iftypes_ext_capa[] = {
.extended_capabilities_mask = tm_if_types_ext_capa_sta,
.extended_capabilities_len = sizeof(tm_if_types_ext_capa_sta),
/* relevant only if EHT is supported */
- .eml_capabilities = IEEE80211_EML_CAP_EMLSR_SUPP,
+ .eml_capabilities = IWL_MVM_EMLSR_CAPA,
},
};
@@ -1029,6 +1038,7 @@ static void iwl_mvm_cleanup_iterator(void *data, u8 *mac,
mvmvif->link[link_id]->fw_link_id = IWL_MVM_FW_LINK_ID_INVALID;
mvmvif->link[link_id]->phy_ctxt = NULL;
mvmvif->link[link_id]->active = 0;
+ mvmvif->link[link_id]->igtk = NULL;
}
probe_data = rcu_dereference_protected(mvmvif->deflink.probe_resp_data,
@@ -1233,7 +1243,7 @@ void __iwl_mvm_mac_stop(struct iwl_mvm *mvm)
/* async_handlers_wk is now blocked */
- if (iwl_fw_lookup_cmd_ver(mvm->fw, ADD_STA, 0) < 12)
+ if (!iwl_mvm_has_new_station_api(mvm->fw))
iwl_mvm_rm_aux_sta(mvm);
iwl_mvm_stop_device(mvm);
@@ -1478,21 +1488,37 @@ iwl_mvm_chandef_get_primary_80(struct cfg80211_chan_def *chandef)
return (control_start - data_start) / 80;
}
-/*
- * Returns true if addding the interface is done
- * (either with success or failure)
- *
- * FIXME: remove this again and merge it in
- */
-static bool iwl_mvm_mac_add_interface_common(struct iwl_mvm *mvm,
- struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- int *ret)
+static int iwl_mvm_alloc_bcast_mcast_sta(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ int ret;
lockdep_assert_held(&mvm->mutex);
+ ret = iwl_mvm_alloc_bcast_sta(mvm, vif);
+ if (ret) {
+ IWL_ERR(mvm, "Failed to allocate bcast sta\n");
+ return ret;
+ }
+
+ /* Only queue for this station is the mcast queue,
+ * which shouldn't be in TFD mask anyway
+ */
+ return iwl_mvm_allocate_int_sta(mvm, &mvmvif->deflink.mcast_sta, 0,
+ vif->type,
+ IWL_STA_MULTICAST);
+}
+
+static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif)
+{
+ struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ int ret;
+
+ mutex_lock(&mvm->mutex);
+
mvmvif->mvm = mvm;
/* the first link always points to the default one */
@@ -1510,12 +1536,18 @@ static bool iwl_mvm_mac_add_interface_common(struct iwl_mvm *mvm,
mvmvif->deflink.beacon_stats.num_beacons;
/* Allocate resources for the MAC context, and add it to the fw */
- *ret = iwl_mvm_mac_ctxt_init(mvm, vif);
- if (*ret)
- return true;
+ ret = iwl_mvm_mac_ctxt_init(mvm, vif);
+ if (ret)
+ goto out;
rcu_assign_pointer(mvm->vif_id_to_mac[mvmvif->id], vif);
+ /* Currently not much to do for NAN */
+ if (vif->type == NL80211_IFTYPE_NAN) {
+ ret = 0;
+ goto out;
+ }
+
/*
* The AP binding flow can be done only after the beacon
* template is configured (which happens only in the mac80211
@@ -1530,50 +1562,12 @@ static bool iwl_mvm_mac_add_interface_common(struct iwl_mvm *mvm,
if (vif->type == NL80211_IFTYPE_AP ||
vif->type == NL80211_IFTYPE_ADHOC) {
iwl_mvm_vif_dbgfs_register(mvm, vif);
- return true;
+ ret = 0;
+ goto out;
}
mvmvif->features |= hw->netdev_features;
- return false;
-}
-
-static int iwl_mvm_alloc_bcast_mcast_sta(struct iwl_mvm *mvm,
- struct ieee80211_vif *vif)
-{
- struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
- int ret;
-
- lockdep_assert_held(&mvm->mutex);
-
- ret = iwl_mvm_alloc_bcast_sta(mvm, vif);
- if (ret) {
- IWL_ERR(mvm, "Failed to allocate bcast sta\n");
- return ret;
- }
-
- /*
- * Only queue for this station is the mcast queue,
- * which shouldn't be in TFD mask anyway
- */
- return iwl_mvm_allocate_int_sta(mvm, &mvmvif->deflink.mcast_sta, 0,
- vif->type,
- IWL_STA_MULTICAST);
-}
-
-static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif)
-{
- struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
- struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
- int ret;
-
- mutex_lock(&mvm->mutex);
-
- /* Common for MLD and non-MLD API */
- if (iwl_mvm_mac_add_interface_common(mvm, hw, vif, &ret))
- goto out;
-
ret = iwl_mvm_mac_ctxt_add(mvm, vif);
if (ret)
goto out_unlock;
@@ -2246,7 +2240,7 @@ int iwl_mvm_set_sta_pkt_ext(struct iwl_mvm *mvm,
* is enabled or not
*/
bool iwl_mvm_set_fw_mu_edca_params(struct iwl_mvm *mvm,
- struct iwl_mvm_vif *mvmvif,
+ const struct iwl_mvm_vif_link_info *link_info,
struct iwl_he_backoff_conf *trig_based_txf)
{
int i;
@@ -2254,11 +2248,11 @@ bool iwl_mvm_set_fw_mu_edca_params(struct iwl_mvm *mvm,
bool mu_edca_enabled = true;
for (i = 0; i < IEEE80211_NUM_ACS; i++) {
- struct ieee80211_he_mu_edca_param_ac_rec *mu_edca =
- &mvmvif->deflink.queue_params[i].mu_edca_param_rec;
+ const struct ieee80211_he_mu_edca_param_ac_rec *mu_edca =
+ &link_info->queue_params[i].mu_edca_param_rec;
u8 ac = iwl_mvm_mac80211_ac_to_ucode_ac(i);
- if (!mvmvif->deflink.queue_params[i].mu_edca) {
+ if (!link_info->queue_params[i].mu_edca) {
mu_edca_enabled = false;
break;
}
@@ -2285,8 +2279,7 @@ bool iwl_mvm_is_nic_ack_enabled(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
* so take it from one of them.
*/
sband = mvm->hw->wiphy->bands[NL80211_BAND_2GHZ];
- own_he_cap = ieee80211_get_he_iftype_cap(sband,
- ieee80211_vif_type_p2p(vif));
+ own_he_cap = ieee80211_get_he_iftype_cap_vif(sband, vif);
return (own_he_cap && (own_he_cap->he_cap_elem.mac_cap_info[2] &
IEEE80211_HE_MAC_CAP2_ACK_EN));
@@ -2405,7 +2398,7 @@ static void iwl_mvm_cfg_he_sta(struct iwl_mvm *mvm,
rcu_read_unlock();
- if (iwl_mvm_set_fw_mu_edca_params(mvm, mvmvif,
+ if (iwl_mvm_set_fw_mu_edca_params(mvm, &mvmvif->deflink,
&sta_ctxt_cmd.trig_based_txf[0]))
flags |= STA_CTXT_HE_MU_EDCA_CW;
@@ -2898,7 +2891,7 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw,
if (iwl_mvm_phy_ctx_count(mvm) > 1)
iwl_mvm_teardown_tdls_peers(mvm);
- iwl_mvm_ftm_restart_responder(mvm, vif);
+ iwl_mvm_ftm_restart_responder(mvm, vif, &vif->bss_conf);
goto out_unlock;
@@ -3040,7 +3033,7 @@ iwl_mvm_bss_info_changed_ap_ibss(struct iwl_mvm *mvm,
IWL_WARN(mvm, "Failed updating beacon data\n");
if (changes & BSS_CHANGED_FTM_RESPONDER) {
- int ret = iwl_mvm_ftm_start_responder(mvm, vif);
+ int ret = iwl_mvm_ftm_start_responder(mvm, vif, &vif->bss_conf);
if (ret)
IWL_WARN(mvm, "Failed to enable FTM responder (%d)\n",
@@ -3054,7 +3047,7 @@ static void iwl_mvm_bss_info_changed(struct ieee80211_hw *hw,
struct ieee80211_bss_conf *bss_conf,
u64 changes)
{
- struct iwl_mvm_bss_info_changed_ops callbacks = {
+ static const struct iwl_mvm_bss_info_changed_ops callbacks = {
.bss_info_changed_sta = iwl_mvm_bss_info_changed_station,
.bss_info_changed_ap_ibss = iwl_mvm_bss_info_changed_ap_ibss,
};
@@ -3067,7 +3060,7 @@ void
iwl_mvm_bss_info_changed_common(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *bss_conf,
- struct iwl_mvm_bss_info_changed_ops *callbacks,
+ const struct iwl_mvm_bss_info_changed_ops *callbacks,
u64 changes)
{
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
@@ -3468,8 +3461,7 @@ static void iwl_mvm_reset_cca_40mhz_workaround(struct iwl_mvm *mvm,
sband->ht_cap.cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
- he_cap = ieee80211_get_he_iftype_cap(sband,
- ieee80211_vif_type_p2p(vif));
+ he_cap = ieee80211_get_he_iftype_cap_vif(sband, vif);
if (he_cap) {
/* we know that ours is writable */
@@ -3564,7 +3556,7 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw,
enum ieee80211_sta_state old_state,
enum ieee80211_sta_state new_state)
{
- struct iwl_mvm_sta_state_ops callbacks = {
+ static const struct iwl_mvm_sta_state_ops callbacks = {
.add_sta = iwl_mvm_add_sta,
.update_sta = iwl_mvm_update_sta,
.rm_sta = iwl_mvm_rm_sta,
@@ -3669,7 +3661,7 @@ static int
iwl_mvm_sta_state_notexist_to_none(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
- struct iwl_mvm_sta_state_ops *callbacks)
+ const struct iwl_mvm_sta_state_ops *callbacks)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct ieee80211_link_sta *link_sta;
@@ -3713,7 +3705,7 @@ iwl_mvm_sta_state_auth_to_assoc(struct ieee80211_hw *hw,
struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
- struct iwl_mvm_sta_state_ops *callbacks)
+ const struct iwl_mvm_sta_state_ops *callbacks)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);
@@ -3770,7 +3762,7 @@ static int
iwl_mvm_sta_state_assoc_to_authorized(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
- struct iwl_mvm_sta_state_ops *callbacks)
+ const struct iwl_mvm_sta_state_ops *callbacks)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);
@@ -3805,11 +3797,10 @@ static int
iwl_mvm_sta_state_authorized_to_assoc(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
- struct iwl_mvm_sta_state_ops *callbacks)
+ const struct iwl_mvm_sta_state_ops *callbacks)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
- int ret;
lockdep_assert_held(&mvm->mutex);
@@ -3828,10 +3819,7 @@ iwl_mvm_sta_state_authorized_to_assoc(struct iwl_mvm *mvm,
mvmvif->authorized = 0;
/* disable beacon filtering */
- ret = iwl_mvm_disable_beacon_filter(mvm, vif, 0);
- WARN_ON(ret &&
- !test_bit(IWL_MVM_STATUS_HW_RESTART_REQUESTED,
- &mvm->status));
+ iwl_mvm_disable_beacon_filter(mvm, vif, 0);
}
return 0;
@@ -3843,11 +3831,12 @@ int iwl_mvm_mac_sta_state_common(struct ieee80211_hw *hw,
struct ieee80211_sta *sta,
enum ieee80211_sta_state old_state,
enum ieee80211_sta_state new_state,
- struct iwl_mvm_sta_state_ops *callbacks)
+ const struct iwl_mvm_sta_state_ops *callbacks)
{
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);
+ struct ieee80211_link_sta *link_sta;
unsigned int link_id;
int ret;
@@ -3889,7 +3878,7 @@ int iwl_mvm_mac_sta_state_common(struct ieee80211_hw *hw,
mutex_lock(&mvm->mutex);
/* this would be a mac80211 bug ... but don't crash */
- for_each_mvm_vif_valid_link(mvmvif, link_id) {
+ for_each_sta_active_link(vif, sta, link_sta, link_id) {
if (WARN_ON_ONCE(!mvmvif->link[link_id]->phy_ctxt)) {
mutex_unlock(&mvm->mutex);
return test_bit(IWL_MVM_STATUS_HW_RESTART_REQUESTED,
@@ -4533,7 +4522,7 @@ static int iwl_mvm_add_aux_sta_for_hs20(struct iwl_mvm *mvm, u32 lmac_id)
return -EINVAL;
}
- if (iwl_fw_lookup_cmd_ver(mvm->fw, ADD_STA, 0) >= 12) {
+ if (iwl_mvm_has_new_station_api(mvm->fw)) {
ret = iwl_mvm_add_aux_sta(mvm, lmac_id);
WARN(ret, "Failed to allocate aux station");
}
@@ -4573,7 +4562,7 @@ static int iwl_mvm_roc(struct ieee80211_hw *hw,
int duration,
enum ieee80211_roc_type type)
{
- struct iwl_mvm_roc_ops ops = {
+ static const struct iwl_mvm_roc_ops ops = {
.add_aux_sta_for_hs20 = iwl_mvm_add_aux_sta_for_hs20,
.switch_phy_ctxt = iwl_mvm_roc_switch_binding,
};
@@ -4585,7 +4574,7 @@ static int iwl_mvm_roc(struct ieee80211_hw *hw,
int iwl_mvm_roc_common(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_channel *channel, int duration,
enum ieee80211_roc_type type,
- struct iwl_mvm_roc_ops *ops)
+ const struct iwl_mvm_roc_ops *ops)
{
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
@@ -4608,7 +4597,7 @@ int iwl_mvm_roc_common(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
switch (vif->type) {
case NL80211_IFTYPE_STATION:
- lmac_id = iwl_mvm_get_lmac_id(mvm->fw, channel->band);
+ lmac_id = iwl_mvm_get_lmac_id(mvm, channel->band);
/* Use aux roc framework (HS20) */
ret = ops->add_aux_sta_for_hs20(mvm, lmac_id);
@@ -5092,7 +5081,7 @@ static void iwl_mvm_unassign_vif_chanctx(struct ieee80211_hw *hw,
static int
iwl_mvm_switch_vif_chanctx_swap(struct iwl_mvm *mvm,
struct ieee80211_vif_chanctx_switch *vifs,
- struct iwl_mvm_switch_vif_chanctx_ops *ops)
+ const struct iwl_mvm_switch_vif_chanctx_ops *ops)
{
int ret;
@@ -5151,7 +5140,7 @@ out:
static int
iwl_mvm_switch_vif_chanctx_reassign(struct iwl_mvm *mvm,
struct ieee80211_vif_chanctx_switch *vifs,
- struct iwl_mvm_switch_vif_chanctx_ops *ops)
+ const struct iwl_mvm_switch_vif_chanctx_ops *ops)
{
int ret;
@@ -5194,7 +5183,7 @@ iwl_mvm_switch_vif_chanctx_common(struct ieee80211_hw *hw,
struct ieee80211_vif_chanctx_switch *vifs,
int n_vifs,
enum ieee80211_chanctx_switch_mode mode,
- struct iwl_mvm_switch_vif_chanctx_ops *ops)
+ const struct iwl_mvm_switch_vif_chanctx_ops *ops)
{
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
int ret;
@@ -5223,7 +5212,7 @@ static int iwl_mvm_switch_vif_chanctx(struct ieee80211_hw *hw,
int n_vifs,
enum ieee80211_chanctx_switch_mode mode)
{
- struct iwl_mvm_switch_vif_chanctx_ops ops = {
+ static const struct iwl_mvm_switch_vif_chanctx_ops ops = {
.__assign_vif_chanctx = __iwl_mvm_assign_vif_chanctx,
.__unassign_vif_chanctx = __iwl_mvm_unassign_vif_chanctx,
};
@@ -5664,6 +5653,30 @@ void iwl_mvm_mac_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
iwl_trans_wait_tx_queues_empty(mvm->trans, msk);
}
+void iwl_mvm_mac_flush_sta(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta)
+{
+ struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+ int i;
+
+ mutex_lock(&mvm->mutex);
+ for (i = 0; i < mvm->fw->ucode_capa.num_stations; i++) {
+ struct iwl_mvm_sta *mvmsta;
+ struct ieee80211_sta *tmp;
+
+ tmp = rcu_dereference_protected(mvm->fw_id_to_mac_id[i],
+ lockdep_is_held(&mvm->mutex));
+ if (tmp != sta)
+ continue;
+
+ mvmsta = iwl_mvm_sta_from_mac80211(sta);
+
+ if (iwl_mvm_flush_sta(mvm, mvmsta, false))
+ IWL_ERR(mvm, "flush request fail\n");
+ }
+ mutex_unlock(&mvm->mutex);
+}
+
int iwl_mvm_mac_get_survey(struct ieee80211_hw *hw, int idx,
struct survey_info *survey)
{
@@ -6154,10 +6167,6 @@ static bool iwl_mvm_mac_can_aggregate(struct ieee80211_hw *hw,
{
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
- if (iwl_mvm_has_new_tx_csum(mvm))
- return iwl_mvm_tx_csum_bz(mvm, head, true) ==
- iwl_mvm_tx_csum_bz(mvm, skb, true);
-
/* For now don't aggregate IPv6 in AMSDU */
if (skb->protocol != htons(ETH_P_IP))
return false;
@@ -6220,6 +6229,7 @@ const struct ieee80211_ops iwl_mvm_hw_ops = {
.mgd_complete_tx = iwl_mvm_mac_mgd_complete_tx,
.mgd_protect_tdls_discover = iwl_mvm_mac_mgd_protect_tdls_discover,
.flush = iwl_mvm_mac_flush,
+ .flush_sta = iwl_mvm_mac_flush_sta,
.sched_scan_start = iwl_mvm_mac_sched_scan_start,
.sched_scan_stop = iwl_mvm_mac_sched_scan_stop,
.set_key = iwl_mvm_mac_set_key,
@@ -6277,7 +6287,7 @@ const struct ieee80211_ops iwl_mvm_hw_ops = {
.can_aggregate_in_amsdu = iwl_mvm_mac_can_aggregate,
#ifdef CONFIG_IWLWIFI_DEBUGFS
- .sta_add_debugfs = iwl_mvm_sta_add_debugfs,
+ .link_sta_add_debugfs = iwl_mvm_link_sta_add_debugfs,
#endif
.set_hw_timestamp = iwl_mvm_set_hw_timestamp,
};
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c
index 8853821b3716..2c9f2f71b083 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
- * Copyright (C) 2022 Intel Corporation
+ * Copyright (C) 2022 - 2023 Intel Corporation
*/
#include <linux/kernel.h>
#include <net/mac80211.h>
@@ -42,7 +42,7 @@ static u32 iwl_mvm_get_sec_sta_mask(struct iwl_mvm *mvm,
* Of course the same can be done during add as well, but we must do
* it during remove, since we don't have the mvmvif->ap_sta pointer.
*/
- if (!sta && (keyconf->link_id >= 0 || !vif->valid_links))
+ if (!sta && (keyconf->link_id >= 0 || !ieee80211_vif_is_mld(vif)))
return BIT(link_info->ap_sta_id);
/* STA should be non-NULL now, but iwl_mvm_sta_fw_id_mask() checks */
@@ -51,10 +51,10 @@ static u32 iwl_mvm_get_sec_sta_mask(struct iwl_mvm *mvm,
return iwl_mvm_sta_fw_id_mask(mvm, sta, keyconf->link_id);
}
-static u32 iwl_mvm_get_sec_flags(struct iwl_mvm *mvm,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta,
- struct ieee80211_key_conf *keyconf)
+u32 iwl_mvm_get_sec_flags(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
+ struct ieee80211_key_conf *keyconf)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
u32 flags = 0;
@@ -164,13 +164,9 @@ static int __iwl_mvm_sec_key_del(struct iwl_mvm *mvm, u32 sta_mask,
return iwl_mvm_send_cmd_pdu(mvm, cmd_id, flags, sizeof(cmd), &cmd);
}
-int iwl_mvm_sec_key_add(struct iwl_mvm *mvm,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta,
- struct ieee80211_key_conf *keyconf)
+int iwl_mvm_mld_send_key(struct iwl_mvm *mvm, u32 sta_mask, u32 key_flags,
+ struct ieee80211_key_conf *keyconf)
{
- u32 sta_mask = iwl_mvm_get_sec_sta_mask(mvm, vif, sta, keyconf);
- u32 key_flags = iwl_mvm_get_sec_flags(mvm, vif, sta, keyconf);
u32 cmd_id = WIDE_ID(DATA_PATH_GROUP, SEC_KEY_CMD);
struct iwl_sec_key_cmd cmd = {
.action = cpu_to_le32(FW_CTXT_ACTION_ADD),
@@ -179,9 +175,14 @@ int iwl_mvm_sec_key_add(struct iwl_mvm *mvm,
.u.add.key_flags = cpu_to_le32(key_flags),
.u.add.tx_seq = cpu_to_le64(atomic64_read(&keyconf->tx_pn)),
};
+ int max_key_len = sizeof(cmd.u.add.key);
int ret;
- if (WARN_ON(keyconf->keylen > sizeof(cmd.u.add.key)))
+ if (keyconf->cipher == WLAN_CIPHER_SUITE_WEP40 ||
+ keyconf->cipher == WLAN_CIPHER_SUITE_WEP104)
+ max_key_len -= IWL_SEC_WEP_KEY_OFFSET;
+
+ if (WARN_ON(keyconf->keylen > max_key_len))
return -EINVAL;
if (WARN_ON(!sta_mask))
@@ -223,6 +224,58 @@ int iwl_mvm_sec_key_add(struct iwl_mvm *mvm,
return ret;
}
+int iwl_mvm_sec_key_add(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
+ struct ieee80211_key_conf *keyconf)
+{
+ u32 sta_mask = iwl_mvm_get_sec_sta_mask(mvm, vif, sta, keyconf);
+ u32 key_flags = iwl_mvm_get_sec_flags(mvm, vif, sta, keyconf);
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ struct iwl_mvm_vif_link_info *mvm_link = NULL;
+ int ret;
+
+ if (keyconf->keyidx == 4 || keyconf->keyidx == 5) {
+ unsigned int link_id = 0;
+
+ /* set to -1 for non-MLO right now */
+ if (keyconf->link_id >= 0)
+ link_id = keyconf->link_id;
+
+ mvm_link = mvmvif->link[link_id];
+ if (WARN_ON(!mvm_link))
+ return -EINVAL;
+
+ if (mvm_link->igtk) {
+ IWL_DEBUG_MAC80211(mvm, "remove old IGTK %d\n",
+ mvm_link->igtk->keyidx);
+ ret = iwl_mvm_sec_key_del(mvm, vif, sta,
+ mvm_link->igtk);
+ if (ret)
+ IWL_ERR(mvm,
+ "failed to remove old IGTK (ret=%d)\n",
+ ret);
+ }
+
+ WARN_ON(mvm_link->igtk);
+ }
+
+ ret = iwl_mvm_mld_send_key(mvm, sta_mask, key_flags, keyconf);
+ if (ret)
+ return ret;
+
+ if (mvm_link)
+ mvm_link->igtk = keyconf;
+
+ /* We don't really need this, but need it to be not invalid,
+ * and if we switch links multiple times it might go to be
+ * invalid when removed.
+ */
+ keyconf->hw_key_idx = 0;
+
+ return 0;
+}
+
static int _iwl_mvm_sec_key_del(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
@@ -231,11 +284,31 @@ static int _iwl_mvm_sec_key_del(struct iwl_mvm *mvm,
{
u32 sta_mask = iwl_mvm_get_sec_sta_mask(mvm, vif, sta, keyconf);
u32 key_flags = iwl_mvm_get_sec_flags(mvm, vif, sta, keyconf);
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
int ret;
if (WARN_ON(!sta_mask))
return -EINVAL;
+ if (keyconf->keyidx == 4 || keyconf->keyidx == 5) {
+ struct iwl_mvm_vif_link_info *mvm_link;
+ unsigned int link_id = 0;
+
+ /* set to -1 for non-MLO right now */
+ if (keyconf->link_id >= 0)
+ link_id = keyconf->link_id;
+
+ mvm_link = mvmvif->link[link_id];
+ if (WARN_ON(!mvm_link))
+ return -EINVAL;
+
+ if (mvm_link->igtk == keyconf) {
+ /* no longer in HW - mark for later */
+ mvm_link->igtk->hw_key_idx = STA_KEY_IDX_INVALID;
+ mvm_link->igtk = NULL;
+ }
+ }
+
ret = __iwl_mvm_sec_key_del(mvm, sta_mask, key_flags, keyconf->keyidx,
flags);
if (ret)
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac.c
index 1717fb52dc12..f313a8d771e4 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
- * Copyright (C) 2022 Intel Corporation
+ * Copyright (C) 2022 - 2023 Intel Corporation
*/
#include "mvm.h"
@@ -50,7 +50,7 @@ static void iwl_mvm_mld_mac_ctxt_cmd_common(struct iwl_mvm *mvm,
* the association response successfully, so just skip all that
* and enable both when we have MLO.
*/
- if (vif->valid_links) {
+ if (ieee80211_vif_is_mld(vif)) {
iwl_mvm_mld_set_he_support(mvm, vif, cmd);
cmd->eht_support = cpu_to_le32(1);
return;
@@ -96,6 +96,7 @@ static int iwl_mvm_mld_mac_ctxt_cmd_sta(struct iwl_mvm *mvm,
u32 action, bool force_assoc_off)
{
struct iwl_mac_config_cmd cmd = {};
+ u16 esr_transition_timeout;
WARN_ON(vif->type != NL80211_IFTYPE_STATION);
@@ -115,16 +116,16 @@ static int iwl_mvm_mld_mac_ctxt_cmd_sta(struct iwl_mvm *mvm,
if (vif->cfg.assoc && !force_assoc_off) {
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
- cmd.client.is_assoc = cpu_to_le32(1);
+ cmd.client.is_assoc = 1;
if (!mvmvif->authorized &&
fw_has_capa(&mvm->fw->ucode_capa,
IWL_UCODE_TLV_CAPA_COEX_HIGH_PRIO))
cmd.client.data_policy |=
- cpu_to_le32(COEX_HIGH_PRIORITY_ENABLE);
+ cpu_to_le16(COEX_HIGH_PRIORITY_ENABLE);
} else {
- cmd.client.is_assoc = cpu_to_le32(0);
+ cmd.client.is_assoc = 0;
/* Allow beacons to pass through as long as we are not
* associated, or we do not have dtim period information.
@@ -132,14 +133,25 @@ static int iwl_mvm_mld_mac_ctxt_cmd_sta(struct iwl_mvm *mvm,
cmd.filter_flags |= cpu_to_le32(MAC_CFG_FILTER_ACCEPT_BEACON);
}
- cmd.client.assoc_id = cpu_to_le32(vif->cfg.aid);
+ cmd.client.assoc_id = cpu_to_le16(vif->cfg.aid);
+ if (ieee80211_vif_is_mld(vif)) {
+ esr_transition_timeout =
+ u16_get_bits(vif->cfg.eml_cap,
+ IEEE80211_EML_CAP_TRANSITION_TIMEOUT);
+
+ cmd.client.esr_transition_timeout =
+ min_t(u16, IEEE80211_EML_CAP_TRANSITION_TIMEOUT_128TU,
+ esr_transition_timeout);
+ cmd.client.medium_sync_delay =
+ cpu_to_le16(vif->cfg.eml_med_sync_delay);
+ }
if (vif->probe_req_reg && vif->cfg.assoc && vif->p2p)
cmd.filter_flags |= cpu_to_le32(MAC_CFG_FILTER_ACCEPT_PROBE_REQ);
if (vif->bss_conf.he_support && !iwlwifi_mod_params.disable_11ax)
cmd.client.data_policy |=
- iwl_mvm_mac_ctxt_cmd_sta_get_twt_policy(mvm, vif);
+ cpu_to_le16(iwl_mvm_mac_ctxt_cmd_sta_get_twt_policy(mvm, vif));
return iwl_mvm_mld_mac_ctxt_send_cmd(mvm, &cmd);
}
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c
index 7fb66c570959..8b6c641772ee 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
- * Copyright (C) 2022 Intel Corporation
+ * Copyright (C) 2022-2023 Intel Corporation
*/
#include "mvm.h"
@@ -215,6 +215,53 @@ static void iwl_mvm_mld_mac_remove_interface(struct ieee80211_hw *hw,
mutex_unlock(&mvm->mutex);
}
+static unsigned int iwl_mvm_mld_count_active_links(struct ieee80211_vif *vif)
+{
+ unsigned int n_active = 0;
+ int i;
+
+ for (i = 0; i < IEEE80211_MLD_MAX_NUM_LINKS; i++) {
+ struct ieee80211_bss_conf *link_conf;
+
+ link_conf = link_conf_dereference_protected(vif, i);
+ if (link_conf &&
+ rcu_access_pointer(link_conf->chanctx_conf))
+ n_active++;
+ }
+
+ return n_active;
+}
+
+static int iwl_mvm_esr_mode_active(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif)
+{
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ int link_id, ret = 0;
+
+ mvmvif->esr_active = true;
+
+ /* Disable SMPS overrideing by user */
+ vif->driver_flags |= IEEE80211_VIF_DISABLE_SMPS_OVERRIDE;
+
+ iwl_mvm_update_smps_on_active_links(mvm, vif, IWL_MVM_SMPS_REQ_FW,
+ IEEE80211_SMPS_OFF);
+
+ for_each_mvm_vif_valid_link(mvmvif, link_id) {
+ struct iwl_mvm_vif_link_info *link = mvmvif->link[link_id];
+
+ if (!link->phy_ctxt)
+ continue;
+
+ ret = iwl_mvm_phy_send_rlc(mvm, link->phy_ctxt, 2, 2);
+ if (ret)
+ break;
+
+ link->phy_ctxt->rlc_disabled = true;
+ }
+
+ return ret;
+}
+
static int
__iwl_mvm_mld_assign_vif_chanctx(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
@@ -224,10 +271,18 @@ __iwl_mvm_mld_assign_vif_chanctx(struct iwl_mvm *mvm,
{
u16 *phy_ctxt_id = (u16 *)ctx->drv_priv;
struct iwl_mvm_phy_ctxt *phy_ctxt = &mvm->phy_ctxts[*phy_ctxt_id];
+ unsigned int n_active = iwl_mvm_mld_count_active_links(vif);
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
unsigned int link_id = link_conf->link_id;
int ret;
+ /* if the assigned one was not counted yet, count it now */
+ if (!rcu_access_pointer(link_conf->chanctx_conf))
+ n_active++;
+
+ if (n_active > iwl_mvm_max_active_links(mvm, vif))
+ return -EOPNOTSUPP;
+
if (WARN_ON_ONCE(!mvmvif->link[link_id]))
return -EINVAL;
@@ -243,6 +298,15 @@ __iwl_mvm_mld_assign_vif_chanctx(struct iwl_mvm *mvm,
}
}
+ if (iwl_mvm_is_esr_supported(mvm->fwrt.trans) && n_active > 1) {
+ mvmvif->link[link_id]->listen_lmac = true;
+ ret = iwl_mvm_esr_mode_active(mvm, vif);
+ if (ret) {
+ IWL_ERR(mvm, "failed to activate ESR mode (%d)\n", ret);
+ return ret;
+ }
+ }
+
mvmvif->link[link_id]->phy_ctxt = phy_ctxt;
if (switching_chanctx) {
@@ -326,14 +390,62 @@ static int iwl_mvm_mld_assign_vif_chanctx(struct ieee80211_hw *hw,
return ret;
}
+static int iwl_mvm_esr_mode_inactive(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif)
+{
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ struct ieee80211_bss_conf *link_conf;
+ int link_id, ret = 0;
+
+ mvmvif->esr_active = false;
+
+ vif->driver_flags &= ~IEEE80211_VIF_DISABLE_SMPS_OVERRIDE;
+
+ iwl_mvm_update_smps_on_active_links(mvm, vif, IWL_MVM_SMPS_REQ_FW,
+ IEEE80211_SMPS_AUTOMATIC);
+
+ for_each_vif_active_link(vif, link_conf, link_id) {
+ struct ieee80211_chanctx_conf *chanctx_conf;
+ struct iwl_mvm_phy_ctxt *phy_ctxt;
+ u8 static_chains, dynamic_chains;
+
+ mvmvif->link[link_id]->listen_lmac = false;
+
+ rcu_read_lock();
+
+ chanctx_conf = rcu_dereference(link_conf->chanctx_conf);
+ phy_ctxt = mvmvif->link[link_id]->phy_ctxt;
+
+ if (!chanctx_conf || !phy_ctxt) {
+ rcu_read_unlock();
+ continue;
+ }
+
+ phy_ctxt->rlc_disabled = false;
+ static_chains = chanctx_conf->rx_chains_static;
+ dynamic_chains = chanctx_conf->rx_chains_dynamic;
+
+ rcu_read_unlock();
+
+ ret = iwl_mvm_phy_send_rlc(mvm, phy_ctxt, static_chains,
+ dynamic_chains);
+ if (ret)
+ break;
+ }
+
+ return ret;
+}
+
static void
__iwl_mvm_mld_unassign_vif_chanctx(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *link_conf,
struct ieee80211_chanctx_conf *ctx,
bool switching_chanctx)
+
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ unsigned int n_active = iwl_mvm_mld_count_active_links(vif);
unsigned int link_id = link_conf->link_id;
/* shouldn't happen, but verify link_id is valid before accessing */
@@ -352,6 +464,14 @@ __iwl_mvm_mld_unassign_vif_chanctx(struct iwl_mvm *mvm,
mvmvif->ap_ibss_active = false;
}
+ if (iwl_mvm_is_esr_supported(mvm->fwrt.trans) && n_active > 1) {
+ int ret = iwl_mvm_esr_mode_inactive(mvm, vif);
+
+ if (ret)
+ IWL_ERR(mvm, "failed to deactivate ESR mode (%d)\n",
+ ret);
+ }
+
if (vif->type == NL80211_IFTYPE_MONITOR)
iwl_mvm_mld_rm_snif_sta(mvm, vif);
@@ -422,7 +542,7 @@ static int iwl_mvm_mld_start_ap_ibss(struct ieee80211_hw *hw,
if (iwl_mvm_phy_ctx_count(mvm) > 1)
iwl_mvm_teardown_tdls_peers(mvm);
- iwl_mvm_ftm_restart_responder(mvm, vif);
+ iwl_mvm_ftm_restart_responder(mvm, vif, link_conf);
goto out_unlock;
@@ -492,7 +612,7 @@ static int iwl_mvm_mld_mac_sta_state(struct ieee80211_hw *hw,
enum ieee80211_sta_state old_state,
enum ieee80211_sta_state new_state)
{
- struct iwl_mvm_sta_state_ops callbacks = {
+ static const struct iwl_mvm_sta_state_ops callbacks = {
.add_sta = iwl_mvm_mld_add_sta,
.update_sta = iwl_mvm_mld_update_sta,
.rm_sta = iwl_mvm_mld_rm_sta,
@@ -697,7 +817,11 @@ iwl_mvm_mld_link_info_changed_ap_ibss(struct iwl_mvm *mvm,
if (link_conf->he_support)
link_changes |= LINK_CONTEXT_MODIFY_HE_PARAMS;
- if (changes & (BSS_CHANGED_ERP_CTS_PROT | BSS_CHANGED_HT |
+ if (changes & BSS_CHANGED_ERP_SLOT)
+ link_changes |= LINK_CONTEXT_MODIFY_RATES_INFO;
+
+ if (changes & (BSS_CHANGED_ERP_CTS_PROT | BSS_CHANGED_ERP_SLOT |
+ BSS_CHANGED_HT |
BSS_CHANGED_BANDWIDTH | BSS_CHANGED_QOS |
BSS_CHANGED_HE_BSS_COLOR) &&
iwl_mvm_link_changed(mvm, vif, link_conf,
@@ -711,7 +835,7 @@ iwl_mvm_mld_link_info_changed_ap_ibss(struct iwl_mvm *mvm,
/* FIXME: need to decide if we need FTM responder per link */
if (changes & BSS_CHANGED_FTM_RESPONDER) {
- int ret = iwl_mvm_ftm_start_responder(mvm, vif);
+ int ret = iwl_mvm_ftm_start_responder(mvm, vif, link_conf);
if (ret)
IWL_WARN(mvm, "Failed to enable FTM responder (%d)\n",
@@ -779,7 +903,7 @@ iwl_mvm_mld_switch_vif_chanctx(struct ieee80211_hw *hw,
int n_vifs,
enum ieee80211_chanctx_switch_mode mode)
{
- struct iwl_mvm_switch_vif_chanctx_ops ops = {
+ static const struct iwl_mvm_switch_vif_chanctx_ops ops = {
.__assign_vif_chanctx = __iwl_mvm_mld_assign_vif_chanctx,
.__unassign_vif_chanctx = __iwl_mvm_mld_unassign_vif_chanctx,
};
@@ -816,8 +940,12 @@ iwl_mvm_mld_mac_conf_tx(struct ieee80211_hw *hw,
{
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ struct iwl_mvm_vif_link_info *mvm_link = mvmvif->link[link_id];
- mvmvif->deflink.queue_params[ac] = *params;
+ if (!mvm_link)
+ return -EINVAL;
+
+ mvm_link->queue_params[ac] = *params;
/* No need to update right away, we'll get BSS_CHANGED_QOS
* The exception is P2P_DEVICE interface which needs immediate update.
@@ -871,7 +999,7 @@ static int iwl_mvm_mld_roc(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_channel *channel, int duration,
enum ieee80211_roc_type type)
{
- struct iwl_mvm_roc_ops ops = {
+ static const struct iwl_mvm_roc_ops ops = {
.add_aux_sta_for_hs20 = iwl_mvm_mld_add_aux_sta,
.switch_phy_ctxt = iwl_mvm_link_switch_phy_ctx,
};
@@ -886,33 +1014,16 @@ iwl_mvm_mld_change_vif_links(struct ieee80211_hw *hw,
struct ieee80211_bss_conf *old[IEEE80211_MLD_MAX_NUM_LINKS])
{
struct iwl_mvm_vif_link_info *new_link[IEEE80211_MLD_MAX_NUM_LINKS] = {};
+ unsigned int n_active = iwl_mvm_mld_count_active_links(vif);
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
u16 removed = old_links & ~new_links;
u16 added = new_links & ~old_links;
int err, i;
- if (hweight16(new_links) > 2) {
+ if (hweight16(new_links) > 1 &&
+ n_active > iwl_mvm_max_active_links(mvm, vif))
return -EOPNOTSUPP;
- } else if (hweight16(new_links) > 1) {
- unsigned int n_active = 0;
-
- for (i = 0; i < IEEE80211_MLD_MAX_NUM_LINKS; i++) {
- struct ieee80211_bss_conf *link_conf;
-
- link_conf = link_conf_dereference_protected(vif, i);
- if (link_conf &&
- rcu_access_pointer(link_conf->chanctx_conf))
- n_active++;
- }
-
- if (vif->type == NL80211_IFTYPE_AP) {
- if (n_active > mvm->fw->ucode_capa.num_beacons)
- return -EOPNOTSUPP;
- } else if (n_active > 1) {
- return -EOPNOTSUPP;
- }
- }
for (i = 0; i < IEEE80211_MLD_MAX_NUM_LINKS; i++) {
int r;
@@ -956,9 +1067,7 @@ iwl_mvm_mld_change_vif_links(struct ieee80211_hw *hw,
goto out_err;
kfree(mvmvif->link[i]);
mvmvif->link[i] = NULL;
- }
-
- if (added & BIT(i)) {
+ } else if (added & BIT(i)) {
struct ieee80211_bss_conf *link_conf;
link_conf = link_conf_dereference_protected(vif, i);
@@ -975,6 +1084,9 @@ iwl_mvm_mld_change_vif_links(struct ieee80211_hw *hw,
}
}
+ if (err)
+ goto out_err;
+
err = 0;
if (new_links == 0) {
mvmvif->link[0] = &mvmvif->deflink;
@@ -1037,6 +1149,7 @@ const struct ieee80211_ops iwl_mvm_mld_hw_ops = {
.mgd_complete_tx = iwl_mvm_mac_mgd_complete_tx,
.mgd_protect_tdls_discover = iwl_mvm_mac_mgd_protect_tdls_discover,
.flush = iwl_mvm_mac_flush,
+ .flush_sta = iwl_mvm_mac_flush_sta,
.sched_scan_start = iwl_mvm_mac_sched_scan_start,
.sched_scan_stop = iwl_mvm_mac_sched_scan_stop,
.set_key = iwl_mvm_mac_set_key,
@@ -1093,7 +1206,7 @@ const struct ieee80211_ops iwl_mvm_mld_hw_ops = {
.abort_pmsr = iwl_mvm_abort_pmsr,
#ifdef CONFIG_IWLWIFI_DEBUGFS
- .sta_add_debugfs = iwl_mvm_sta_add_debugfs,
+ .link_sta_add_debugfs = iwl_mvm_link_sta_add_debugfs,
#endif
.set_hw_timestamp = iwl_mvm_set_hw_timestamp,
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c
index 85a4ce8449ad..524852cf5cd2 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
- * Copyright (C) 2022 Intel Corporation
+ * Copyright (C) 2022-2023 Intel Corporation
*/
#include "mvm.h"
#include "time-sync.h"
@@ -71,6 +71,11 @@ static int iwl_mvm_mld_add_int_sta_to_fw(struct iwl_mvm *mvm,
cmd.station_type = cpu_to_le32(sta->type);
+ if (fw_has_capa(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_CAPA_STA_EXP_MFP_SUPPORT) &&
+ sta->type == STATION_TYPE_BCAST_MGMT)
+ cmd.mfp = cpu_to_le32(1);
+
if (addr) {
memcpy(cmd.peer_mld_address, addr, ETH_ALEN);
memcpy(cmd.peer_link_address, addr, ETH_ALEN);
@@ -128,11 +133,11 @@ static int iwl_mvm_add_aux_sta_to_fw(struct iwl_mvm *mvm,
/*
* Adds an internal sta to the FW table with its queues
*/
-static int iwl_mvm_mld_add_int_sta_with_queue(struct iwl_mvm *mvm,
- struct iwl_mvm_int_sta *sta,
- const u8 *addr, int link_id,
- u16 *queue, u8 tid,
- unsigned int *_wdg_timeout)
+int iwl_mvm_mld_add_int_sta_with_queue(struct iwl_mvm *mvm,
+ struct iwl_mvm_int_sta *sta,
+ const u8 *addr, int link_id,
+ u16 *queue, u8 tid,
+ unsigned int *_wdg_timeout)
{
int ret, txq;
unsigned int wdg_timeout = _wdg_timeout ? *_wdg_timeout :
@@ -364,6 +369,9 @@ int iwl_mvm_mld_rm_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
lockdep_assert_held(&mvm->mutex);
+ if (WARN_ON(!link))
+ return -EIO;
+
switch (vif->type) {
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_ADHOC:
@@ -393,6 +401,9 @@ int iwl_mvm_mld_rm_mcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
lockdep_assert_held(&mvm->mutex);
+ if (WARN_ON(!link))
+ return -EIO;
+
return iwl_mvm_mld_rm_int_sta(mvm, &link->mcast_sta, true, 0,
&link->cab_queue);
}
@@ -442,6 +453,11 @@ static int iwl_mvm_mld_cfg_sta(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
if (mvm_sta->sta_state >= IEEE80211_STA_ASSOC)
cmd.assoc_id = cpu_to_le32(sta->aid);
+ if (fw_has_capa(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_CAPA_STA_EXP_MFP_SUPPORT) &&
+ (sta->mfp || mvm_sta->sta_state < IEEE80211_STA_AUTHORIZED))
+ cmd.mfp = cpu_to_le32(1);
+
switch (link_sta->rx_nss) {
case 1:
cmd.mimo = cpu_to_le32(0);
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
index 9e5008e0e47f..b83df0631279 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/*
- * Copyright (C) 2012-2014, 2018-2022 Intel Corporation
+ * Copyright (C) 2012-2014, 2018-2023 Intel Corporation
* Copyright (C) 2013-2015 Intel Mobile Communications GmbH
* Copyright (C) 2016-2017 Intel Deutschland GmbH
*/
@@ -104,6 +104,7 @@ struct iwl_mvm_phy_ctxt {
/* track for RLC config command */
u32 center_freq1;
+ bool rlc_disabled;
};
struct iwl_mvm_time_event_data {
@@ -300,6 +301,8 @@ struct iwl_probe_resp_data {
* @he_ru_2mhz_block: 26-tone RU OFDMA transmissions should be blocked
* @queue_params: QoS params for this MAC
* @mgmt_queue: queue number for unbufferable management frames
+ * @igtk: the current IGTK programmed into the firmware
+ * @listen_lmac: indicates this link is allocated to the listen LMAC
*/
struct iwl_mvm_vif_link_info {
u8 bssid[ETH_ALEN];
@@ -317,8 +320,11 @@ struct iwl_mvm_vif_link_info {
enum ieee80211_smps_mode smps_requests[NUM_IWL_MVM_SMPS_REQ];
struct iwl_probe_resp_data __rcu *probe_resp_data;
+ struct ieee80211_key_conf *igtk;
+
bool he_ru_2mhz_block;
bool active;
+ bool listen_lmac;
u16 cab_queue;
/* Assigned while mac80211 has the link in a channel context,
@@ -370,6 +376,7 @@ struct iwl_mvm_vif {
bool ap_ibss_active;
bool pm_enabled;
bool monitor_active;
+ bool esr_active;
u8 low_latency: 6;
u8 low_latency_actual: 1;
@@ -415,7 +422,7 @@ struct iwl_mvm_vif {
#endif
/* FW identified misbehaving AP */
- u8 uapsd_misbehaving_bssid[ETH_ALEN];
+ u8 uapsd_misbehaving_ap_addr[ETH_ALEN] __aligned(2);
struct delayed_work uapsd_nonagg_detected_wk;
bool csa_countdown;
@@ -1003,6 +1010,8 @@ struct iwl_mvm {
struct ieee80211_vif __rcu *vif_id_to_mac[NUM_MAC_INDEX_DRIVER];
+ struct ieee80211_bss_conf __rcu *link_id_to_link_conf[IWL_MVM_FW_MAX_LINK_ID + 1];
+
/* -1 for always, 0 for never, >0 for that many times */
s8 fw_restart;
u8 *error_recovery_buf;
@@ -1174,6 +1183,10 @@ struct iwl_mvm {
__le16 cur_aid;
u8 cur_bssid[ETH_ALEN];
+#ifdef CONFIG_ACPI
+ struct iwl_phy_specific_cfg phy_filters;
+#endif
+
unsigned long last_6ghz_passive_scan_jiffies;
unsigned long last_reset_or_resume_time_jiffies;
@@ -1302,6 +1315,19 @@ iwl_mvm_rcu_dereference_vif_id(struct iwl_mvm *mvm, u8 vif_id, bool rcu)
lockdep_is_held(&mvm->mutex));
}
+static inline struct ieee80211_bss_conf *
+iwl_mvm_rcu_fw_link_id_to_link_conf(struct iwl_mvm *mvm, u8 link_id, bool rcu)
+{
+ if (WARN_ON(link_id >= ARRAY_SIZE(mvm->link_id_to_link_conf)))
+ return NULL;
+
+ if (rcu)
+ return rcu_dereference(mvm->link_id_to_link_conf[link_id]);
+
+ return rcu_dereference_protected(mvm->link_id_to_link_conf[link_id],
+ lockdep_is_held(&mvm->mutex));
+}
+
static inline bool iwl_mvm_is_adaptive_dwell_supported(struct iwl_mvm *mvm)
{
return fw_has_api(&mvm->fw->ucode_capa,
@@ -1415,6 +1441,12 @@ static inline bool iwl_mvm_has_mld_api(const struct iwl_fw *fw)
IWL_UCODE_TLV_CAPA_MLD_API_SUPPORT);
}
+static inline bool iwl_mvm_has_new_station_api(const struct iwl_fw *fw)
+{
+ return iwl_mvm_has_mld_api(fw) ||
+ iwl_fw_lookup_cmd_ver(fw, ADD_STA, 0) >= 12;
+}
+
static inline bool iwl_mvm_has_new_tx_api(struct iwl_mvm *mvm)
{
/* TODO - replace with TLV once defined */
@@ -1516,17 +1548,30 @@ static inline bool iwl_mvm_is_ctdp_supported(struct iwl_mvm *mvm)
IWL_UCODE_TLV_CAPA_CTDP_SUPPORT);
}
-static inline bool iwl_mvm_has_new_tx_csum(struct iwl_mvm *mvm)
+static inline bool iwl_mvm_is_esr_supported(struct iwl_trans *trans)
+{
+ if ((CSR_HW_RFID_TYPE(trans->hw_rf_id) == IWL_CFG_RF_TYPE_FM) &&
+ !CSR_HW_RFID_IS_CDB(trans->hw_rf_id))
+ /* Step A doesn't support eSR */
+ return CSR_HW_RFID_STEP(trans->hw_rf_id);
+
+ return false;
+}
+
+static inline int iwl_mvm_max_active_links(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif)
{
- if (mvm->trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_BZ)
- return false;
+ struct iwl_trans *trans = mvm->fwrt.trans;
+
+ if (vif->type == NL80211_IFTYPE_AP)
+ return mvm->fw->ucode_capa.num_beacons;
- if (mvm->trans->trans_cfg->device_family == IWL_DEVICE_FAMILY_BZ &&
- CSR_HW_REV_TYPE(mvm->trans->hw_rev) == IWL_CFG_MAC_TYPE_GL &&
- mvm->trans->hw_rev_step <= SILICON_B_STEP)
- return false;
+ if (iwl_mvm_is_esr_supported(trans) ||
+ (CSR_HW_RFID_TYPE(trans->hw_rf_id) == IWL_CFG_RF_TYPE_FM &&
+ CSR_HW_RFID_IS_CDB(trans->hw_rf_id)))
+ return IWL_MVM_FW_MAX_ACTIVE_LINKS_NUM;
- return true;
+ return 1;
}
extern const u8 iwl_mvm_ac_to_tx_fifo[];
@@ -1606,7 +1651,6 @@ void iwl_mvm_mac_itxq_xmit(struct ieee80211_hw *hw, struct ieee80211_txq *txq);
unsigned int iwl_mvm_max_amsdu_size(struct iwl_mvm *mvm,
struct ieee80211_sta *sta,
unsigned int tid);
-u32 iwl_mvm_tx_csum_bz(struct iwl_mvm *mvm, struct sk_buff *skb, bool amsdu);
#ifdef CONFIG_IWLWIFI_DEBUG
const char *iwl_mvm_get_tx_fail_reason(u32 status);
@@ -1741,6 +1785,8 @@ void iwl_mvm_phy_ctxt_unref(struct iwl_mvm *mvm,
int iwl_mvm_phy_ctx_count(struct iwl_mvm *mvm);
u8 iwl_mvm_get_channel_width(struct cfg80211_chan_def *chandef);
u8 iwl_mvm_get_ctrl_pos(struct cfg80211_chan_def *chandef);
+int iwl_mvm_phy_send_rlc(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt,
+ u8 chains_static, u8 chains_dynamic);
/* MAC (virtual interface) programming */
@@ -1758,7 +1804,7 @@ void iwl_mvm_set_fw_qos_params(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
struct ieee80211_bss_conf *link_conf,
struct iwl_ac_qos *ac, __le32 *qos_flags);
bool iwl_mvm_set_fw_mu_edca_params(struct iwl_mvm *mvm,
- struct iwl_mvm_vif *mvmvif,
+ const struct iwl_mvm_vif_link_info *link_info,
struct iwl_he_backoff_conf *trig_based_txf);
void iwl_mvm_set_fw_dtim_tbtt(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
struct ieee80211_bss_conf *link_conf,
@@ -1774,8 +1820,8 @@ void iwl_mvm_mac_ctxt_cmd_ap_set_filter_flags(struct iwl_mvm *mvm,
int iwl_mvm_get_mac_type(struct ieee80211_vif *vif);
__le32 iwl_mvm_mac_ctxt_cmd_p2p_sta_get_oppps_ctwin(struct iwl_mvm *mvm,
struct ieee80211_vif *vif);
-__le32 iwl_mvm_mac_ctxt_cmd_sta_get_twt_policy(struct iwl_mvm *mvm,
- struct ieee80211_vif *vif);
+u32 iwl_mvm_mac_ctxt_cmd_sta_get_twt_policy(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif);
int iwl_mvm_mld_mac_ctxt_add(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
int iwl_mvm_mld_mac_ctxt_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
bool force_assoc_off);
@@ -1826,6 +1872,7 @@ void iwl_mvm_channel_switch_error_notif(struct iwl_mvm *mvm,
/* Bindings */
int iwl_mvm_binding_add_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
int iwl_mvm_binding_remove_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
+u32 iwl_mvm_get_lmac_id(struct iwl_mvm *mvm, enum nl80211_band band);
/* Links */
int iwl_mvm_add_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
@@ -1873,7 +1920,7 @@ void
iwl_mvm_bss_info_changed_common(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *bss_conf,
- struct iwl_mvm_bss_info_changed_ops *callbacks,
+ const struct iwl_mvm_bss_info_changed_ops *callbacks,
u64 changes);
void
iwl_mvm_bss_info_changed_station_common(struct iwl_mvm *mvm,
@@ -1907,7 +1954,7 @@ struct iwl_mvm_roc_ops {
int iwl_mvm_roc_common(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_channel *channel, int duration,
enum ieee80211_roc_type type,
- struct iwl_mvm_roc_ops *ops);
+ const struct iwl_mvm_roc_ops *ops);
int iwl_mvm_cancel_roc(struct ieee80211_hw *hw,
struct ieee80211_vif *vif);
/*Session Protection */
@@ -2204,7 +2251,7 @@ static inline void iwl_mvm_vendor_cmds_register(struct iwl_mvm *mvm) {}
#endif
/* Location Aware Regulatory */
-struct iwl_mcc_update_resp *
+struct iwl_mcc_update_resp_v8 *
iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2,
enum iwl_mcc_source src_id);
int iwl_mvm_init_mcc(struct iwl_mvm *mvm);
@@ -2224,9 +2271,11 @@ int iwl_mvm_sf_update(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
bool added_vif);
/* FTM responder */
-int iwl_mvm_ftm_start_responder(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
+int iwl_mvm_ftm_start_responder(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+ struct ieee80211_bss_conf *bss_conf);
void iwl_mvm_ftm_restart_responder(struct iwl_mvm *mvm,
- struct ieee80211_vif *vif);
+ struct ieee80211_vif *vif,
+ struct ieee80211_bss_conf *bss_conf);
void iwl_mvm_ftm_responder_stats(struct iwl_mvm *mvm,
struct iwl_rx_cmd_buffer *rxb);
int iwl_mvm_ftm_resp_remove_pasn_sta(struct iwl_mvm *mvm,
@@ -2322,10 +2371,10 @@ int iwl_mvm_get_sar_geo_profile(struct iwl_mvm *mvm);
int iwl_mvm_ppag_send_cmd(struct iwl_mvm *mvm);
void iwl_mvm_get_acpi_tables(struct iwl_mvm *mvm);
#ifdef CONFIG_IWLWIFI_DEBUGFS
-void iwl_mvm_sta_add_debugfs(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta,
- struct dentry *dir);
+void iwl_mvm_link_sta_add_debugfs(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_link_sta *link_sta,
+ struct dentry *dir);
#endif
/* new MLD related APIs */
@@ -2346,6 +2395,12 @@ int iwl_mvm_mld_update_sta_keys(struct iwl_mvm *mvm,
struct ieee80211_sta *sta,
u32 old_sta_mask,
u32 new_sta_mask);
+int iwl_mvm_mld_send_key(struct iwl_mvm *mvm, u32 sta_mask, u32 key_flags,
+ struct ieee80211_key_conf *keyconf);
+u32 iwl_mvm_get_sec_flags(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
+ struct ieee80211_key_conf *keyconf);
bool iwl_rfi_supported(struct iwl_mvm *mvm);
int iwl_rfi_send_config_cmd(struct iwl_mvm *mvm,
@@ -2406,7 +2461,7 @@ iwl_mvm_switch_vif_chanctx_common(struct ieee80211_hw *hw,
struct ieee80211_vif_chanctx_switch *vifs,
int n_vifs,
enum ieee80211_chanctx_switch_mode mode,
- struct iwl_mvm_switch_vif_chanctx_ops *ops);
+ const struct iwl_mvm_switch_vif_chanctx_ops *ops);
/* Channel info utils */
static inline bool iwl_mvm_has_ultra_hb_channel(struct iwl_mvm *mvm)
@@ -2604,6 +2659,8 @@ void iwl_mvm_mac_mgd_complete_tx(struct ieee80211_hw *hw,
struct ieee80211_prep_tx_info *info);
void iwl_mvm_mac_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
u32 queues, bool drop);
+void iwl_mvm_mac_flush_sta(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta);
int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct cfg80211_sched_scan_request *req,
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c
index fdf60afb0f3f..f67ab8ee18c2 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c
@@ -404,7 +404,7 @@ int iwl_nvm_init(struct iwl_mvm *mvm)
return ret < 0 ? ret : 0;
}
-struct iwl_mcc_update_resp *
+struct iwl_mcc_update_resp_v8 *
iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2,
enum iwl_mcc_source src_id)
{
@@ -412,7 +412,7 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2,
.mcc = cpu_to_le16(alpha2[0] << 8 | alpha2[1]),
.source_id = (u8)src_id,
};
- struct iwl_mcc_update_resp *resp_cp;
+ struct iwl_mcc_update_resp_v8 *resp_cp;
struct iwl_rx_packet *pkt;
struct iwl_host_cmd cmd = {
.id = MCC_UPDATE_CMD,
@@ -420,7 +420,7 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2,
.data = { &mcc_update_cmd },
};
- int ret;
+ int ret, resp_ver;
u32 status;
int resp_len, n_channels;
u16 mcc;
@@ -439,24 +439,60 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2,
pkt = cmd.resp_pkt;
+ resp_ver = iwl_fw_lookup_notif_ver(mvm->fw, IWL_ALWAYS_LONG_GROUP,
+ MCC_UPDATE_CMD, 0);
+
/* Extract MCC response */
- if (fw_has_capa(&mvm->fw->ucode_capa,
- IWL_UCODE_TLV_CAPA_MCC_UPDATE_11AX_SUPPORT)) {
- struct iwl_mcc_update_resp *mcc_resp = (void *)pkt->data;
+ if (resp_ver >= 8) {
+ struct iwl_mcc_update_resp_v8 *mcc_resp_v8 = (void *)pkt->data;
+
+ n_channels = __le32_to_cpu(mcc_resp_v8->n_channels);
+ if (iwl_rx_packet_payload_len(pkt) !=
+ struct_size(mcc_resp_v8, channels, n_channels)) {
+ resp_cp = ERR_PTR(-EINVAL);
+ goto exit;
+ }
+ resp_len = struct_size(resp_cp, channels, n_channels);
+ resp_cp = kzalloc(resp_len, GFP_KERNEL);
+ if (!resp_cp) {
+ resp_cp = ERR_PTR(-ENOMEM);
+ goto exit;
+ }
+ resp_cp->status = mcc_resp_v8->status;
+ resp_cp->mcc = mcc_resp_v8->mcc;
+ resp_cp->cap = mcc_resp_v8->cap;
+ resp_cp->source_id = mcc_resp_v8->source_id;
+ resp_cp->time = mcc_resp_v8->time;
+ resp_cp->geo_info = mcc_resp_v8->geo_info;
+ resp_cp->n_channels = mcc_resp_v8->n_channels;
+ memcpy(resp_cp->channels, mcc_resp_v8->channels,
+ n_channels * sizeof(__le32));
+ } else if (fw_has_capa(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_CAPA_MCC_UPDATE_11AX_SUPPORT)) {
+ struct iwl_mcc_update_resp_v4 *mcc_resp_v4 = (void *)pkt->data;
- n_channels = __le32_to_cpu(mcc_resp->n_channels);
+ n_channels = __le32_to_cpu(mcc_resp_v4->n_channels);
if (iwl_rx_packet_payload_len(pkt) !=
- struct_size(mcc_resp, channels, n_channels)) {
+ struct_size(mcc_resp_v4, channels, n_channels)) {
resp_cp = ERR_PTR(-EINVAL);
goto exit;
}
- resp_len = sizeof(struct iwl_mcc_update_resp) +
- n_channels * sizeof(__le32);
- resp_cp = kmemdup(mcc_resp, resp_len, GFP_KERNEL);
+ resp_len = struct_size(resp_cp, channels, n_channels);
+ resp_cp = kzalloc(resp_len, GFP_KERNEL);
if (!resp_cp) {
resp_cp = ERR_PTR(-ENOMEM);
goto exit;
}
+
+ resp_cp->status = mcc_resp_v4->status;
+ resp_cp->mcc = mcc_resp_v4->mcc;
+ resp_cp->cap = cpu_to_le32(le16_to_cpu(mcc_resp_v4->cap));
+ resp_cp->source_id = mcc_resp_v4->source_id;
+ resp_cp->time = mcc_resp_v4->time;
+ resp_cp->geo_info = mcc_resp_v4->geo_info;
+ resp_cp->n_channels = mcc_resp_v4->n_channels;
+ memcpy(resp_cp->channels, mcc_resp_v4->channels,
+ n_channels * sizeof(__le32));
} else {
struct iwl_mcc_update_resp_v3 *mcc_resp_v3 = (void *)pkt->data;
@@ -466,8 +502,7 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2,
resp_cp = ERR_PTR(-EINVAL);
goto exit;
}
- resp_len = sizeof(struct iwl_mcc_update_resp) +
- n_channels * sizeof(__le32);
+ resp_len = struct_size(resp_cp, channels, n_channels);
resp_cp = kzalloc(resp_len, GFP_KERNEL);
if (!resp_cp) {
resp_cp = ERR_PTR(-ENOMEM);
@@ -476,7 +511,7 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2,
resp_cp->status = mcc_resp_v3->status;
resp_cp->mcc = mcc_resp_v3->mcc;
- resp_cp->cap = cpu_to_le16(mcc_resp_v3->cap);
+ resp_cp->cap = cpu_to_le32(mcc_resp_v3->cap);
resp_cp->source_id = mcc_resp_v3->source_id;
resp_cp->time = mcc_resp_v3->time;
resp_cp->geo_info = mcc_resp_v3->geo_info;
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/offloading.c b/drivers/net/wireless/intel/iwlwifi/mvm/offloading.c
index a8bd0f5f795c..dfb16ca5b438 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/offloading.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/offloading.c
@@ -198,6 +198,10 @@ int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm,
memcpy(common->arp_mac_addr, vif->addr, ETH_ALEN);
}
+ if (fw_has_capa(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_CAPA_OFFLOAD_BTM_SUPPORT))
+ enabled |= IWL_D3_PROTO_OFFLOAD_BTM;
+
if (!disable_offloading)
common->enabled = cpu_to_le32(enabled);
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c
index 32625bfacaae..5336a4afde4d 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
- * Copyright (C) 2012-2014, 2018-2020 Intel Corporation
+ * Copyright (C) 2012-2014, 2018-2023 Intel Corporation
* Copyright (C) 2013-2015 Intel Mobile Communications GmbH
* Copyright (C) 2016-2017 Intel Deutschland GmbH
*/
@@ -192,8 +192,7 @@ static void iwl_mvm_rx_monitor_notif(struct iwl_mvm *mvm,
WARN_ON(!(sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40));
sband->ht_cap.cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
- he_cap = ieee80211_get_he_iftype_cap(sband,
- ieee80211_vif_type_p2p(vif));
+ he_cap = ieee80211_get_he_iftype_cap_vif(sband, vif);
if (he_cap) {
/* we know that ours is writable */
@@ -449,7 +448,6 @@ static const struct iwl_hcmd_names iwl_mvm_legacy_names[] = {
HCMD_NAME(ADD_STA_KEY),
HCMD_NAME(ADD_STA),
HCMD_NAME(REMOVE_STA),
- HCMD_NAME(FW_GET_ITEM_CMD),
HCMD_NAME(TX_CMD),
HCMD_NAME(SCD_QUEUE_CFG),
HCMD_NAME(TXPATH_FLUSH),
@@ -512,7 +510,6 @@ static const struct iwl_hcmd_names iwl_mvm_legacy_names[] = {
HCMD_NAME(REPLY_BEACON_FILTERING_CMD),
HCMD_NAME(D3_CONFIG_CMD),
HCMD_NAME(PROT_OFFLOAD_CONFIG_CMD),
- HCMD_NAME(OFFLOADS_QUERY_CMD),
HCMD_NAME(MATCH_FOUND_NOTIFICATION),
HCMD_NAME(DTS_MEASUREMENT_NOTIFICATION),
HCMD_NAME(WOWLAN_PATTERNS),
@@ -1604,7 +1601,9 @@ static void iwl_mvm_rx_common(struct iwl_mvm *mvm,
if (rx_h->cmd_id != WIDE_ID(pkt->hdr.group_id, pkt->hdr.cmd))
continue;
- if (unlikely(pkt_len < rx_h->min_size))
+ if (IWL_FW_CHECK(mvm, pkt_len < rx_h->min_size,
+ "unexpected notification 0x%04x size %d, need %d\n",
+ rx_h->cmd_id, pkt_len, rx_h->min_size))
return;
if (rx_h->context == RX_HANDLER_SYNC) {
@@ -1743,8 +1742,11 @@ static void iwl_mvm_queue_state_change(struct iwl_op_mode *op_mode,
else
set_bit(IWL_MVM_TXQ_STATE_STOP_FULL, &mvmtxq->state);
- if (start && mvmsta->sta_state != IEEE80211_STA_NOTEXIST)
+ if (start && mvmsta->sta_state != IEEE80211_STA_NOTEXIST) {
+ local_bh_disable();
iwl_mvm_mac_itxq_xmit(mvm->hw, txq);
+ local_bh_enable();
+ }
}
out:
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c
index 3ab6fb83a175..a5b432bc9e2f 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
- * Copyright (C) 2012-2014, 2018-2022 Intel Corporation
+ * Copyright (C) 2012-2014, 2018-2023 Intel Corporation
* Copyright (C) 2013-2014 Intel Mobile Communications GmbH
* Copyright (C) 2017 Intel Deutschland GmbH
*/
@@ -151,7 +151,7 @@ static void iwl_mvm_phy_ctxt_cmd_data(struct iwl_mvm *mvm,
struct cfg80211_chan_def *chandef,
u8 chains_static, u8 chains_dynamic)
{
- cmd->lmac_id = cpu_to_le32(iwl_mvm_get_lmac_id(mvm->fw,
+ cmd->lmac_id = cpu_to_le32(iwl_mvm_get_lmac_id(mvm,
chandef->chan->band));
/* Set the channel info data */
@@ -163,15 +163,18 @@ static void iwl_mvm_phy_ctxt_cmd_data(struct iwl_mvm *mvm,
chains_static, chains_dynamic);
}
-static int iwl_mvm_phy_send_rlc(struct iwl_mvm *mvm,
- struct iwl_mvm_phy_ctxt *ctxt,
- u8 chains_static, u8 chains_dynamic)
+int iwl_mvm_phy_send_rlc(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt,
+ u8 chains_static, u8 chains_dynamic)
{
struct iwl_rlc_config_cmd cmd = {
.phy_id = cpu_to_le32(ctxt->id),
};
- if (iwl_fw_lookup_cmd_ver(mvm->fw, WIDE_ID(DATA_PATH_GROUP, RLC_CONFIG_CMD), 0) < 2)
+ if (ctxt->rlc_disabled)
+ return 0;
+
+ if (iwl_fw_lookup_cmd_ver(mvm->fw, WIDE_ID(DATA_PATH_GROUP,
+ RLC_CONFIG_CMD), 0) < 2)
return 0;
BUILD_BUG_ON(IWL_RLC_CHAIN_INFO_DRIVER_FORCE !=
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/power.c b/drivers/net/wireless/intel/iwlwifi/mvm/power.c
index ac1dae52556f..9131b5f1bc76 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/power.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/power.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
- * Copyright (C) 2012-2014, 2018-2019, 2021 Intel Corporation
+ * Copyright (C) 2012-2014, 2018-2019, 2021-2023 Intel Corporation
* Copyright (C) 2013-2014 Intel Mobile Communications GmbH
* Copyright (C) 2015-2017 Intel Deutschland GmbH
*/
@@ -237,8 +237,8 @@ static bool iwl_mvm_power_allow_uapsd(struct iwl_mvm *mvm,
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
- if (!memcmp(mvmvif->uapsd_misbehaving_bssid, vif->bss_conf.bssid,
- ETH_ALEN))
+ if (ether_addr_equal(mvmvif->uapsd_misbehaving_ap_addr,
+ vif->cfg.ap_addr))
return false;
/*
@@ -327,12 +327,11 @@ static void iwl_mvm_power_config_skip_dtim(struct iwl_mvm *mvm,
if (WARN_ON(!dtimper_tu))
return;
- /* configure skip over dtim up to 306TU - 314 msec */
- skip = max_t(u8, 1, 306 / dtimper_tu);
+ /* configure skip over dtim up to 900 TU DTIM interval */
+ skip = max_t(u8, 1, 900 / dtimper_tu);
}
- /* the firmware really expects "look at every X DTIMs", so add 1 */
- cmd->skip_dtim_periods = 1 + skip;
+ cmd->skip_dtim_periods = skip;
cmd->flags |= cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK);
}
@@ -502,9 +501,9 @@ void iwl_mvm_power_vif_assoc(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
- if (memcmp(vif->bss_conf.bssid, mvmvif->uapsd_misbehaving_bssid,
- ETH_ALEN))
- eth_zero_addr(mvmvif->uapsd_misbehaving_bssid);
+ if (!ether_addr_equal(mvmvif->uapsd_misbehaving_ap_addr,
+ vif->cfg.ap_addr))
+ eth_zero_addr(mvmvif->uapsd_misbehaving_ap_addr);
}
static void iwl_mvm_power_uapsd_misbehav_ap_iterator(void *_data, u8 *mac,
@@ -512,14 +511,23 @@ static void iwl_mvm_power_uapsd_misbehav_ap_iterator(void *_data, u8 *mac,
{
u8 *ap_sta_id = _data;
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ struct ieee80211_bss_conf *link_conf;
+ unsigned int link_id;
- /* The ap_sta_id is not expected to change during current association
- * so no explicit protection is needed
- */
- if (mvmvif->deflink.ap_sta_id == *ap_sta_id)
- memcpy(mvmvif->uapsd_misbehaving_bssid,
- vif->bss_conf.bssid,
- ETH_ALEN);
+ rcu_read_lock();
+ for_each_vif_active_link(vif, link_conf, link_id) {
+ struct iwl_mvm_vif_link_info *link_info = mvmvif->link[link_id];
+
+ /* The ap_sta_id is not expected to change during current
+ * association so no explicit protection is needed
+ */
+ if (link_info->ap_sta_id == *ap_sta_id) {
+ ether_addr_copy(mvmvif->uapsd_misbehaving_ap_addr,
+ vif->cfg.ap_addr);
+ break;
+ }
+ }
+ rcu_read_unlock();
}
void iwl_mvm_power_uapsd_misbehaving_ap_notif(struct iwl_mvm *mvm,
@@ -647,30 +655,32 @@ static void iwl_mvm_power_set_pm(struct iwl_mvm *mvm,
return;
/* enable PM on bss if bss stand alone */
- if (vifs->bss_active && !vifs->p2p_active && !vifs->ap_active) {
+ if (bss_mvmvif && vifs->bss_active && !vifs->p2p_active &&
+ !vifs->ap_active) {
bss_mvmvif->pm_enabled = true;
return;
}
/* enable PM on p2p if p2p stand alone */
- if (vifs->p2p_active && !vifs->bss_active && !vifs->ap_active) {
+ if (p2p_mvmvif && vifs->p2p_active && !vifs->bss_active &&
+ !vifs->ap_active) {
p2p_mvmvif->pm_enabled = true;
return;
}
- if (vifs->bss_active && vifs->p2p_active)
+ if (p2p_mvmvif && bss_mvmvif && vifs->bss_active && vifs->p2p_active)
client_same_channel =
iwl_mvm_have_links_same_channel(bss_mvmvif, p2p_mvmvif);
- if (vifs->bss_active && vifs->ap_active)
+ if (bss_mvmvif && ap_mvmvif && vifs->bss_active && vifs->ap_active)
ap_same_channel =
iwl_mvm_have_links_same_channel(bss_mvmvif, ap_mvmvif);
/* clients are not stand alone: enable PM if DCM */
if (!(client_same_channel || ap_same_channel)) {
- if (vifs->bss_active)
+ if (bss_mvmvif && vifs->bss_active)
bss_mvmvif->pm_enabled = true;
- if (vifs->p2p_active)
+ if (p2p_mvmvif && vifs->p2p_active)
p2p_mvmvif->pm_enabled = true;
return;
}
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c
index c3a00bfbeef2..6cba8a353b53 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
* Copyright (C) 2017 Intel Deutschland GmbH
- * Copyright (C) 2018-2022 Intel Corporation
+ * Copyright (C) 2018-2023 Intel Corporation
*/
#include "rs.h"
#include "fw-api.h"
@@ -63,12 +63,11 @@ static u8 rs_fw_sgi_cw_support(struct ieee80211_link_sta *link_sta)
static u16 rs_fw_get_config_flags(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
struct ieee80211_link_sta *link_sta,
- struct ieee80211_supported_band *sband)
+ const struct ieee80211_sta_he_cap *sband_he_cap)
{
struct ieee80211_sta_ht_cap *ht_cap = &link_sta->ht_cap;
struct ieee80211_sta_vht_cap *vht_cap = &link_sta->vht_cap;
struct ieee80211_sta_he_cap *he_cap = &link_sta->he_cap;
- const struct ieee80211_sta_he_cap *sband_he_cap;
bool vht_ena = vht_cap->vht_supported;
u16 flags = 0;
@@ -94,8 +93,6 @@ static u16 rs_fw_get_config_flags(struct iwl_mvm *mvm,
IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD))
flags |= IWL_TLC_MNG_CFG_FLAGS_LDPC_MSK;
- sband_he_cap = ieee80211_get_he_iftype_cap(sband,
- ieee80211_vif_type_p2p(vif));
if (sband_he_cap &&
!(sband_he_cap->he_cap_elem.phy_cap_info[1] &
IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD))
@@ -197,16 +194,14 @@ static u16 rs_fw_he_ieee80211_mcs_to_rs_mcs(u16 mcs)
static void
rs_fw_he_set_enabled_rates(const struct ieee80211_link_sta *link_sta,
- struct ieee80211_supported_band *sband,
+ const struct ieee80211_sta_he_cap *sband_he_cap,
struct iwl_tlc_config_cmd_v4 *cmd)
{
const struct ieee80211_sta_he_cap *he_cap = &link_sta->he_cap;
u16 mcs_160 = le16_to_cpu(he_cap->he_mcs_nss_supp.rx_mcs_160);
u16 mcs_80 = le16_to_cpu(he_cap->he_mcs_nss_supp.rx_mcs_80);
- u16 tx_mcs_80 =
- le16_to_cpu(sband->iftype_data->he_cap.he_mcs_nss_supp.tx_mcs_80);
- u16 tx_mcs_160 =
- le16_to_cpu(sband->iftype_data->he_cap.he_mcs_nss_supp.tx_mcs_160);
+ u16 tx_mcs_80 = le16_to_cpu(sband_he_cap->he_mcs_nss_supp.tx_mcs_80);
+ u16 tx_mcs_160 = le16_to_cpu(sband_he_cap->he_mcs_nss_supp.tx_mcs_160);
int i;
u8 nss = link_sta->rx_nss;
@@ -289,7 +284,8 @@ rs_fw_rs_mcs2eht_mcs(enum IWL_TLC_MCS_PER_BW bw,
static void
rs_fw_eht_set_enabled_rates(struct ieee80211_vif *vif,
const struct ieee80211_link_sta *link_sta,
- struct ieee80211_supported_band *sband,
+ const struct ieee80211_sta_he_cap *sband_he_cap,
+ const struct ieee80211_sta_eht_cap *sband_eht_cap,
struct iwl_tlc_config_cmd_v4 *cmd)
{
/* peer RX mcs capa */
@@ -297,7 +293,7 @@ rs_fw_eht_set_enabled_rates(struct ieee80211_vif *vif,
&link_sta->eht_cap.eht_mcs_nss_supp;
/* our TX mcs capa */
const struct ieee80211_eht_mcs_nss_supp *eht_tx_mcs =
- &sband->iftype_data->eht_cap.eht_mcs_nss_supp;
+ &sband_eht_cap->eht_mcs_nss_supp;
enum IWL_TLC_MCS_PER_BW bw;
struct ieee80211_eht_mcs_nss_supp_20mhz_only mcs_rx_20;
@@ -316,7 +312,7 @@ rs_fw_eht_set_enabled_rates(struct ieee80211_vif *vif,
}
/* nic is 20Mhz only */
- if (!(sband->iftype_data->he_cap.he_cap_elem.phy_cap_info[0] &
+ if (!(sband_he_cap->he_cap_elem.phy_cap_info[0] &
IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_MASK_ALL)) {
mcs_tx_20 = eht_tx_mcs->only_20mhz;
} else {
@@ -370,6 +366,8 @@ rs_fw_eht_set_enabled_rates(struct ieee80211_vif *vif,
static void rs_fw_set_supp_rates(struct ieee80211_vif *vif,
struct ieee80211_link_sta *link_sta,
struct ieee80211_supported_band *sband,
+ const struct ieee80211_sta_he_cap *sband_he_cap,
+ const struct ieee80211_sta_eht_cap *sband_eht_cap,
struct iwl_tlc_config_cmd_v4 *cmd)
{
int i;
@@ -388,12 +386,13 @@ static void rs_fw_set_supp_rates(struct ieee80211_vif *vif,
cmd->mode = IWL_TLC_MNG_MODE_NON_HT;
/* HT/VHT rates */
- if (link_sta->eht_cap.has_eht) {
+ if (link_sta->eht_cap.has_eht && sband_he_cap && sband_eht_cap) {
cmd->mode = IWL_TLC_MNG_MODE_EHT;
- rs_fw_eht_set_enabled_rates(vif, link_sta, sband, cmd);
- } else if (he_cap->has_he) {
+ rs_fw_eht_set_enabled_rates(vif, link_sta, sband_he_cap,
+ sband_eht_cap, cmd);
+ } else if (he_cap->has_he && sband_he_cap) {
cmd->mode = IWL_TLC_MNG_MODE_HE;
- rs_fw_he_set_enabled_rates(link_sta, sband, cmd);
+ rs_fw_he_set_enabled_rates(link_sta, sband_he_cap, cmd);
} else if (vht_cap->vht_supported) {
cmd->mode = IWL_TLC_MNG_MODE_VHT;
rs_fw_vht_set_enabled_rates(link_sta, vht_cap, cmd);
@@ -479,7 +478,7 @@ void iwl_mvm_tlc_update_notif(struct iwl_mvm *mvm,
IWL_DEBUG_RATE(mvm, "new rate: %s\n", pretty_rate);
}
- if (flags & IWL_TLC_NOTIF_FLAG_AMSDU && !mvmsta->orig_amsdu_len) {
+ if (flags & IWL_TLC_NOTIF_FLAG_AMSDU && !mvm_link_sta->orig_amsdu_len) {
u16 size = le32_to_cpu(notif->amsdu_size);
int i;
@@ -489,7 +488,7 @@ void iwl_mvm_tlc_update_notif(struct iwl_mvm *mvm,
* so also check with orig_amsdu_len which holds the
* original data before debugfs changed the value
*/
- WARN_ON(mvmsta->orig_amsdu_len < size);
+ WARN_ON(mvm_link_sta->orig_amsdu_len < size);
goto out;
}
@@ -524,6 +523,7 @@ u16 rs_fw_get_max_amsdu_len(struct ieee80211_sta *sta,
{
const struct ieee80211_sta_vht_cap *vht_cap = &link_sta->vht_cap;
const struct ieee80211_sta_ht_cap *ht_cap = &link_sta->ht_cap;
+ const struct ieee80211_sta_eht_cap *eht_cap = &link_sta->eht_cap;
if (WARN_ON_ONCE(!link_conf->chandef.chan))
return IEEE80211_MAX_MPDU_LEN_VHT_3895;
@@ -538,8 +538,18 @@ u16 rs_fw_get_max_amsdu_len(struct ieee80211_sta *sta,
default:
return IEEE80211_MAX_MPDU_LEN_VHT_3895;
}
- } else
- if (vht_cap->vht_supported) {
+ } else if (link_conf->chandef.chan->band == NL80211_BAND_2GHZ &&
+ eht_cap->has_eht) {
+ switch (u8_get_bits(eht_cap->eht_cap_elem.mac_cap_info[0],
+ IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN_MASK)) {
+ case IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN_11454:
+ return IEEE80211_MAX_MPDU_LEN_VHT_11454;
+ case IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN_7991:
+ return IEEE80211_MAX_MPDU_LEN_VHT_7991;
+ default:
+ return IEEE80211_MAX_MPDU_LEN_VHT_3895;
+ }
+ } else if (vht_cap->vht_supported) {
switch (vht_cap->cap & IEEE80211_VHT_CAP_MAX_MPDU_MASK) {
case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454:
return IEEE80211_MAX_MPDU_LEN_VHT_11454;
@@ -576,13 +586,17 @@ void iwl_mvm_rs_fw_rate_init(struct iwl_mvm *mvm,
u32 cmd_id = WIDE_ID(DATA_PATH_GROUP, TLC_MNG_CONFIG_CMD);
struct ieee80211_supported_band *sband = hw->wiphy->bands[band];
u16 max_amsdu_len = rs_fw_get_max_amsdu_len(sta, link_conf, link_sta);
+ const struct ieee80211_sta_he_cap *sband_he_cap =
+ ieee80211_get_he_iftype_cap_vif(sband, vif);
+ const struct ieee80211_sta_eht_cap *sband_eht_cap =
+ ieee80211_get_eht_iftype_cap_vif(sband, vif);
struct iwl_mvm_link_sta *mvm_link_sta;
struct iwl_lq_sta_rs_fw *lq_sta;
struct iwl_tlc_config_cmd_v4 cfg_cmd = {
.max_ch_width = mvmsta->authorized ?
rs_fw_bw_from_sta_bw(link_sta) : IWL_TLC_MNG_CH_WIDTH_20MHZ,
.flags = cpu_to_le16(rs_fw_get_config_flags(mvm, vif, link_sta,
- sband)),
+ sband_he_cap)),
.chains = rs_fw_set_active_chains(iwl_mvm_get_valid_tx_ant(mvm)),
.sgi_ch_width_supp = rs_fw_sgi_cw_support(link_sta),
.max_mpdu_len = iwl_mvm_is_csum_supported(mvm) ?
@@ -592,6 +606,21 @@ void iwl_mvm_rs_fw_rate_init(struct iwl_mvm *mvm,
int cmd_ver;
int ret;
+ /* Enable external EHT LTF only for GL device and if there's
+ * mutual support by AP and client
+ */
+ if (CSR_HW_REV_TYPE(mvm->trans->hw_rev) == IWL_CFG_MAC_TYPE_GL &&
+ sband_eht_cap &&
+ sband_eht_cap->eht_cap_elem.phy_cap_info[5] &
+ IEEE80211_EHT_PHY_CAP5_SUPP_EXTRA_EHT_LTF &&
+ link_sta->eht_cap.has_eht &&
+ link_sta->eht_cap.eht_cap_elem.phy_cap_info[5] &
+ IEEE80211_EHT_PHY_CAP5_SUPP_EXTRA_EHT_LTF) {
+ IWL_DEBUG_RATE(mvm, "Set support for Extra EHT LTF\n");
+ cfg_cmd.flags |=
+ cpu_to_le16(IWL_TLC_MNG_CFG_FLAGS_EHT_EXTRA_LTF_MSK);
+ }
+
rcu_read_lock();
mvm_link_sta = rcu_dereference(mvmsta->link[link_id]);
if (WARN_ON_ONCE(!mvm_link_sta)) {
@@ -609,7 +638,9 @@ void iwl_mvm_rs_fw_rate_init(struct iwl_mvm *mvm,
#ifdef CONFIG_IWLWIFI_DEBUGFS
iwl_mvm_reset_frame_stats(mvm);
#endif
- rs_fw_set_supp_rates(vif, link_sta, sband, &cfg_cmd);
+ rs_fw_set_supp_rates(vif, link_sta, sband,
+ sband_he_cap, sband_eht_cap,
+ &cfg_cmd);
/*
* since TLC offload works with one mode we can assume
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c
index 9a20468345e4..481d68cbbbd8 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
/******************************************************************************
*
- * Copyright(c) 2005 - 2014, 2018 - 2022 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2014, 2018 - 2023 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* Copyright(c) 2016 - 2017 Intel Deutschland GmbH
*****************************************************************************/
@@ -1070,10 +1070,13 @@ static void rs_get_lower_rate_down_column(struct iwl_lq_sta *lq_sta,
rate->bw = RATE_MCS_CHAN_WIDTH_20;
- WARN_ON_ONCE(rate->index < IWL_RATE_MCS_0_INDEX ||
- rate->index > IWL_RATE_MCS_9_INDEX);
+ if (WARN_ON_ONCE(rate->index < IWL_RATE_MCS_0_INDEX))
+ rate->index = rs_ht_to_legacy[IWL_RATE_MCS_0_INDEX];
+ else if (WARN_ON_ONCE(rate->index > IWL_RATE_MCS_9_INDEX))
+ rate->index = rs_ht_to_legacy[IWL_RATE_MCS_9_INDEX];
+ else
+ rate->index = rs_ht_to_legacy[rate->index];
- rate->index = rs_ht_to_legacy[rate->index];
rate->ldpc = false;
} else {
/* Downgrade to SISO with same MCS if in MIMO */
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c
index b38b24246675..542c192698a4 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
- * Copyright (C) 2012-2014, 2018-2022 Intel Corporation
+ * Copyright (C) 2012-2014, 2018-2023 Intel Corporation
* Copyright (C) 2013-2015 Intel Mobile Communications GmbH
* Copyright (C) 2016-2017 Intel Deutschland GmbH
*/
@@ -213,8 +213,12 @@ static void iwl_mvm_rx_handle_tcm(struct iwl_mvm *mvm,
};
u16 thr;
- if (ieee80211_is_data_qos(hdr->frame_control))
- ac = tid_to_mac80211_ac[ieee80211_get_tid(hdr)];
+ if (ieee80211_is_data_qos(hdr->frame_control)) {
+ u8 tid = ieee80211_get_tid(hdr);
+
+ if (tid < IWL_MAX_TID_COUNT)
+ ac = tid_to_mac80211_ac[tid];
+ }
mvmsta = iwl_mvm_sta_from_mac80211(sta);
mac = mvmsta->mac_id_n_color & FW_CTXT_ID_MSK;
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c
index 6226e4e54a51..8d1e44fd9de7 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c
@@ -279,7 +279,8 @@ static void iwl_mvm_get_signal_strength(struct iwl_mvm *mvm,
static int iwl_mvm_rx_mgmt_prot(struct ieee80211_sta *sta,
struct ieee80211_hdr *hdr,
struct iwl_rx_mpdu_desc *desc,
- u32 status)
+ u32 status,
+ struct ieee80211_rx_status *stats)
{
struct iwl_mvm_sta *mvmsta;
struct iwl_mvm_vif *mvmvif;
@@ -308,8 +309,10 @@ static int iwl_mvm_rx_mgmt_prot(struct ieee80211_sta *sta,
/* good cases */
if (likely(status & IWL_RX_MPDU_STATUS_MIC_OK &&
- !(status & IWL_RX_MPDU_STATUS_REPLAY_ERROR)))
+ !(status & IWL_RX_MPDU_STATUS_REPLAY_ERROR))) {
+ stats->flag |= RX_FLAG_DECRYPTED;
return 0;
+ }
if (!sta)
return -1;
@@ -378,7 +381,7 @@ static int iwl_mvm_rx_crypto(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
if (unlikely(ieee80211_is_mgmt(hdr->frame_control) &&
!ieee80211_has_protected(hdr->frame_control)))
- return iwl_mvm_rx_mgmt_prot(sta, hdr, desc, status);
+ return iwl_mvm_rx_mgmt_prot(sta, hdr, desc, status, stats);
if (!ieee80211_has_protected(hdr->frame_control) ||
(status & IWL_RX_MPDU_STATUS_SEC_MASK) ==
@@ -484,7 +487,7 @@ static void iwl_mvm_rx_csum(struct iwl_mvm *mvm,
}
/*
- * returns true if a packet is a duplicate and should be dropped.
+ * returns true if a packet is a duplicate or invalid tid and should be dropped.
* Updates AMSDU PN tracking info
*/
static bool iwl_mvm_is_dup(struct ieee80211_sta *sta, int queue,
@@ -513,11 +516,14 @@ static bool iwl_mvm_is_dup(struct ieee80211_sta *sta, int queue,
return false;
}
- if (ieee80211_is_data_qos(hdr->frame_control))
+ if (ieee80211_is_data_qos(hdr->frame_control)) {
/* frame has qos control */
tid = ieee80211_get_tid(hdr);
- else
+ if (tid >= IWL_MAX_TID_COUNT)
+ return true;
+ } else {
tid = IWL_MAX_TID_COUNT;
+ }
/* If this wasn't a part of an A-MSDU the sub-frame index will be 0 */
sub_frame_idx = desc->amsdu_info &
@@ -985,10 +991,12 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm,
sta_mask = iwl_mvm_sta_fw_id_mask(mvm, sta, -1);
rcu_read_unlock();
- if (WARN(tid != baid_data->tid ||
- !(sta_mask & baid_data->sta_mask),
- "baid 0x%x is mapped to sta_mask:0x%x tid:%d, but was received for sta_mask:0x%x tid:%d\n",
- baid, baid_data->sta_mask, baid_data->tid, sta_mask, tid))
+ if (IWL_FW_CHECK(mvm,
+ tid != baid_data->tid ||
+ !(sta_mask & baid_data->sta_mask),
+ "baid 0x%x is mapped to sta_mask:0x%x tid:%d, but was received for sta_mask:0x%x tid:%d\n",
+ baid, baid_data->sta_mask, baid_data->tid,
+ sta_mask, tid))
return false;
nssn = reorder & IWL_RX_MPDU_REORDER_NSSN_MASK;
@@ -1773,6 +1781,15 @@ static void iwl_mvm_decode_eht_phy_data(struct iwl_mvm *mvm,
IEEE80211_RADIOTAP_EHT_USIG_COMMON_BSS_COLOR);
}
+ if (fw_has_capa(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_CAPA_SNIFF_VALIDATE_SUPPORT)) {
+ usig->common |=
+ cpu_to_le32(IEEE80211_RADIOTAP_EHT_USIG_COMMON_VALIDATE_BITS_CHECKED);
+ usig->common |=
+ LE32_DEC_ENC(data0, IWL_RX_PHY_DATA0_EHT_VALIDATE,
+ IEEE80211_RADIOTAP_EHT_USIG_COMMON_VALIDATE_BITS_OK);
+ }
+
eht->known |= cpu_to_le32(IEEE80211_RADIOTAP_EHT_KNOWN_SPATIAL_REUSE);
eht->data[0] |= LE32_DEC_ENC(data0,
IWL_RX_PHY_DATA0_ETH_SPATIAL_REUSE_MASK,
@@ -1782,9 +1799,9 @@ static void iwl_mvm_decode_eht_phy_data(struct iwl_mvm *mvm,
eht->known |= cpu_to_le32(IEEE80211_RADIOTAP_EHT_KNOWN_RU_ALLOC_TB_FMT);
eht->data[8] |= LE32_DEC_ENC(data0, IWL_RX_PHY_DATA0_EHT_PS160,
IEEE80211_RADIOTAP_EHT_DATA8_RU_ALLOC_TB_FMT_PS_160);
- eht->data[8] |= LE32_DEC_ENC(data1, IWL_RX_PHY_DATA1_EHT_B0,
+ eht->data[8] |= LE32_DEC_ENC(data1, IWL_RX_PHY_DATA1_EHT_RU_ALLOC_B0,
IEEE80211_RADIOTAP_EHT_DATA8_RU_ALLOC_TB_FMT_B0);
- eht->data[8] |= LE32_DEC_ENC(data1, IWL_RX_PHY_DATA1_EHT_RU_B1_B7_ALLOC,
+ eht->data[8] |= LE32_DEC_ENC(data1, IWL_RX_PHY_DATA1_EHT_RU_ALLOC_B1_B7,
IEEE80211_RADIOTAP_EHT_DATA8_RU_ALLOC_TB_FMT_B7_B1);
iwl_mvm_decode_eht_ru(mvm, rx_status, eht);
@@ -2633,6 +2650,8 @@ void iwl_mvm_rx_monitor_no_data(struct iwl_mvm *mvm, struct napi_struct *napi,
phy_data.energy_b = u32_get_bits(rssi, RX_NO_DATA_CHAIN_B_MSK);
phy_data.channel = u32_get_bits(rssi, RX_NO_DATA_CHANNEL_MSK);
phy_data.with_data = false;
+ phy_data.rx_vec[0] = desc->rx_vec[0];
+ phy_data.rx_vec[1] = desc->rx_vec[1];
if (iwl_fw_lookup_notif_ver(mvm->fw, DATA_PATH_GROUP,
RX_NO_DATA_NOTIF, 0) < 2) {
@@ -2651,7 +2670,8 @@ void iwl_mvm_rx_monitor_no_data(struct iwl_mvm *mvm, struct napi_struct *napi,
sizeof(struct iwl_rx_no_data_ver_3)))
/* invalid len for ver 3 */
return;
- memcpy(phy_data.rx_vec, desc->rx_vec, sizeof(phy_data.rx_vec));
+ phy_data.rx_vec[2] = desc->rx_vec[2];
+ phy_data.rx_vec[3] = desc->rx_vec[3];
} else {
if (format == RATE_MCS_EHT_MSK)
/* no support for EHT before version 3 API */
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c
index 175615755d9d..c1d9ce753468 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
- * Copyright (C) 2012-2014, 2018-2021 Intel Corporation
+ * Copyright (C) 2012-2014, 2018-2023 Intel Corporation
* Copyright (C) 2013-2015 Intel Mobile Communications GmbH
* Copyright (C) 2016-2017 Intel Deutschland GmbH
*/
@@ -647,7 +647,7 @@ static void iwl_mvm_scan_fill_tx_cmd(struct iwl_mvm *mvm,
NL80211_BAND_2GHZ,
no_cck);
- if (iwl_fw_lookup_cmd_ver(mvm->fw, ADD_STA, 0) < 12) {
+ if (!iwl_mvm_has_new_station_api(mvm->fw)) {
tx_cmd[0].sta_id = mvm->aux_sta.sta_id;
tx_cmd[1].sta_id = mvm->aux_sta.sta_id;
@@ -1084,7 +1084,7 @@ static void iwl_mvm_fill_scan_config_v1(struct iwl_mvm *mvm, void *config,
memcpy(&cfg->mac_addr, &mvm->addresses[0].addr, ETH_ALEN);
/* This function should not be called when using ADD_STA ver >=12 */
- WARN_ON_ONCE(iwl_fw_lookup_cmd_ver(mvm->fw, ADD_STA, 0) >= 12);
+ WARN_ON_ONCE(iwl_mvm_has_new_station_api(mvm->fw));
cfg->bcast_sta_id = mvm->aux_sta.sta_id;
cfg->channel_flags = channel_flags;
@@ -1135,7 +1135,7 @@ static void iwl_mvm_fill_scan_config_v2(struct iwl_mvm *mvm, void *config,
memcpy(&cfg->mac_addr, &mvm->addresses[0].addr, ETH_ALEN);
/* This function should not be called when using ADD_STA ver >=12 */
- WARN_ON_ONCE(iwl_fw_lookup_cmd_ver(mvm->fw, ADD_STA, 0) >= 12);
+ WARN_ON_ONCE(iwl_mvm_has_new_station_api(mvm->fw));
cfg->bcast_sta_id = mvm->aux_sta.sta_id;
cfg->channel_flags = channel_flags;
@@ -1250,7 +1250,7 @@ int iwl_mvm_config_scan(struct iwl_mvm *mvm)
memset(&cfg, 0, sizeof(cfg));
- if (iwl_fw_lookup_cmd_ver(mvm->fw, ADD_STA, 0) < 12) {
+ if (!iwl_mvm_has_new_station_api(mvm->fw)) {
cfg.bcast_sta_id = mvm->aux_sta.sta_id;
} else if (iwl_fw_lookup_cmd_ver(mvm->fw, SCAN_CFG_CMD, 0) < 5) {
/*
@@ -1627,11 +1627,11 @@ iwl_mvm_umac_scan_cfg_channels_v4(struct iwl_mvm *mvm,
}
static void
-iwl_mvm_umac_scan_cfg_channels_v6(struct iwl_mvm *mvm,
+iwl_mvm_umac_scan_cfg_channels_v7(struct iwl_mvm *mvm,
struct ieee80211_channel **channels,
- struct iwl_scan_channel_params_v6 *cp,
+ struct iwl_scan_channel_params_v7 *cp,
int n_channels, u32 flags,
- enum nl80211_iftype vif_type)
+ enum nl80211_iftype vif_type, u32 version)
{
int i;
@@ -1641,14 +1641,19 @@ iwl_mvm_umac_scan_cfg_channels_v6(struct iwl_mvm *mvm,
u32 n_aps_flag =
iwl_mvm_scan_ch_n_aps_flag(vif_type,
channels[i]->hw_value);
+ u8 iwl_band = iwl_mvm_phy_band_from_nl80211(band);
cfg->flags = cpu_to_le32(flags | n_aps_flag);
cfg->v2.channel_num = channels[i]->hw_value;
- cfg->v2.band = iwl_mvm_phy_band_from_nl80211(band);
if (cfg80211_channel_is_psc(channels[i]))
cfg->flags = 0;
cfg->v2.iter_count = 1;
cfg->v2.iter_interval = 0;
+ if (version < 17)
+ cfg->v2.band = iwl_band;
+ else
+ cfg->flags |= cpu_to_le32((iwl_band <<
+ IWL_CHAN_CFG_FLAGS_BAND_POS));
}
}
@@ -1723,14 +1728,15 @@ iwl_mvm_umac_scan_fill_6g_chan_list(struct iwl_mvm *mvm,
pp->bssid_num = idex_b;
}
-/* TODO: this function can be merged with iwl_mvm_scan_umac_fill_ch_p_v6 */
+/* TODO: this function can be merged with iwl_mvm_scan_umac_fill_ch_p_v7 */
static u32
-iwl_mvm_umac_scan_cfg_channels_v6_6g(struct iwl_mvm *mvm,
+iwl_mvm_umac_scan_cfg_channels_v7_6g(struct iwl_mvm *mvm,
struct iwl_mvm_scan_params *params,
u32 n_channels,
struct iwl_scan_probe_params_v4 *pp,
- struct iwl_scan_channel_params_v6 *cp,
- enum nl80211_iftype vif_type)
+ struct iwl_scan_channel_params_v7 *cp,
+ enum nl80211_iftype vif_type,
+ u32 version)
{
int i;
struct cfg80211_scan_6ghz_params *scan_6ghz_params =
@@ -1745,6 +1751,7 @@ iwl_mvm_umac_scan_cfg_channels_v6_6g(struct iwl_mvm *mvm,
u8 j, k, s_max = 0, b_max = 0, n_used_bssid_entries;
bool force_passive, found = false, allow_passive = true,
unsolicited_probe_on_chan = false, psc_no_listen = false;
+ s8 psd_20 = IEEE80211_RNR_TBTT_PARAMS_PSD_RESERVED;
/*
* Avoid performing passive scan on non PSC channels unless the
@@ -1756,9 +1763,14 @@ iwl_mvm_umac_scan_cfg_channels_v6_6g(struct iwl_mvm *mvm,
continue;
cfg->v1.channel_num = params->channels[i]->hw_value;
- cfg->v2.band = 2;
- cfg->v2.iter_count = 1;
- cfg->v2.iter_interval = 0;
+ if (version < 17)
+ cfg->v2.band = PHY_BAND_6;
+ else
+ cfg->flags |= cpu_to_le32(PHY_BAND_6 <<
+ IWL_CHAN_CFG_FLAGS_BAND_POS);
+
+ cfg->v5.iter_count = 1;
+ cfg->v5.iter_interval = 0;
/*
* The optimize the scan time, i.e., reduce the scan dwell time
@@ -1769,9 +1781,22 @@ iwl_mvm_umac_scan_cfg_channels_v6_6g(struct iwl_mvm *mvm,
*/
n_used_bssid_entries = 3;
for (j = 0; j < params->n_6ghz_params; j++) {
+ s8 tmp_psd_20;
+
if (!(scan_6ghz_params[j].channel_idx == i))
continue;
+ /* Use the highest PSD value allowed as advertised by
+ * APs for this channel
+ */
+ tmp_psd_20 = scan_6ghz_params[j].psd_20;
+ if (tmp_psd_20 !=
+ IEEE80211_RNR_TBTT_PARAMS_PSD_RESERVED &&
+ (psd_20 ==
+ IEEE80211_RNR_TBTT_PARAMS_PSD_RESERVED ||
+ psd_20 < tmp_psd_20))
+ psd_20 = tmp_psd_20;
+
found = false;
unsolicited_probe_on_chan |=
scan_6ghz_params[j].unsolicited_probe;
@@ -1875,6 +1900,9 @@ iwl_mvm_umac_scan_cfg_channels_v6_6g(struct iwl_mvm *mvm,
flags |= bssid_bitmap | (s_ssid_bitmap << 16);
cfg->flags |= cpu_to_le32(flags);
+ if (version >= 17)
+ cfg->v5.psd_20 = psd_20;
+
ch_cnt++;
}
@@ -2292,11 +2320,12 @@ static int iwl_mvm_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
}
static void
-iwl_mvm_scan_umac_fill_general_p_v11(struct iwl_mvm *mvm,
+iwl_mvm_scan_umac_fill_general_p_v12(struct iwl_mvm *mvm,
struct iwl_mvm_scan_params *params,
struct ieee80211_vif *vif,
struct iwl_scan_general_params_v11 *gp,
- u16 gen_flags, u8 gen_flags2)
+ u16 gen_flags, u8 gen_flags2,
+ u32 version)
{
struct iwl_mvm_vif *scan_vif = iwl_mvm_vif_from_mac80211(vif);
@@ -2313,7 +2342,23 @@ iwl_mvm_scan_umac_fill_general_p_v11(struct iwl_mvm *mvm,
if (gen_flags & IWL_UMAC_SCAN_GEN_FLAGS_V2_FRAGMENTED_LMAC2)
gp->num_of_fragments[SCAN_HB_LMAC_IDX] = IWL_SCAN_NUM_OF_FRAGS;
- gp->scan_start_mac_id = scan_vif->id;
+ if (version < 12) {
+ gp->scan_start_mac_or_link_id = scan_vif->id;
+ } else {
+ struct iwl_mvm_vif_link_info *link_info;
+ u8 link_id = 0;
+
+ /* Use one of the active link (if any). In the future it would
+ * be possible that the link ID would be part of the scan
+ * request coming from upper layers so we would need to use it.
+ */
+ if (vif->active_links)
+ link_id = ffs(vif->active_links) - 1;
+
+ link_info = scan_vif->link[link_id];
+ if (!WARN_ON(!link_info))
+ gp->scan_start_mac_or_link_id = link_info->fw_link_id;
+ }
}
static void
@@ -2352,21 +2397,22 @@ iwl_mvm_scan_umac_fill_ch_p_v4(struct iwl_mvm *mvm,
}
static void
-iwl_mvm_scan_umac_fill_ch_p_v6(struct iwl_mvm *mvm,
+iwl_mvm_scan_umac_fill_ch_p_v7(struct iwl_mvm *mvm,
struct iwl_mvm_scan_params *params,
struct ieee80211_vif *vif,
- struct iwl_scan_channel_params_v6 *cp,
- u32 channel_cfg_flags)
+ struct iwl_scan_channel_params_v7 *cp,
+ u32 channel_cfg_flags,
+ u32 version)
{
cp->flags = iwl_mvm_scan_umac_chan_flags_v2(mvm, params, vif);
cp->count = params->n_channels;
cp->n_aps_override[0] = IWL_SCAN_ADWELL_N_APS_GO_FRIENDLY;
cp->n_aps_override[1] = IWL_SCAN_ADWELL_N_APS_SOCIAL_CHS;
- iwl_mvm_umac_scan_cfg_channels_v6(mvm, params->channels, cp,
+ iwl_mvm_umac_scan_cfg_channels_v7(mvm, params->channels, cp,
params->n_channels,
channel_cfg_flags,
- vif->type);
+ vif->type, version);
if (params->enable_6ghz_passive) {
struct ieee80211_supported_band *sband =
@@ -2383,11 +2429,19 @@ iwl_mvm_scan_umac_fill_ch_p_v6(struct iwl_mvm *mvm,
if (!cfg80211_channel_is_psc(channel))
continue;
- cfg->flags = 0;
- cfg->v2.channel_num = channel->hw_value;
- cfg->v2.band = PHY_BAND_6;
- cfg->v2.iter_count = 1;
- cfg->v2.iter_interval = 0;
+ cfg->v5.channel_num = channel->hw_value;
+ cfg->v5.iter_count = 1;
+ cfg->v5.iter_interval = 0;
+
+ if (version < 17) {
+ cfg->flags = 0;
+ cfg->v2.band = PHY_BAND_6;
+ } else {
+ cfg->flags = cpu_to_le32(PHY_BAND_6 <<
+ IWL_CHAN_CFG_FLAGS_BAND_POS);
+ cfg->v5.psd_20 =
+ IEEE80211_RNR_TBTT_PARAMS_PSD_RESERVED;
+ }
cp->count++;
}
}
@@ -2408,9 +2462,9 @@ static int iwl_mvm_scan_umac_v12(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
cmd->uid = cpu_to_le32(uid);
gen_flags = iwl_mvm_scan_umac_flags_v2(mvm, params, vif, type);
- iwl_mvm_scan_umac_fill_general_p_v11(mvm, params, vif,
+ iwl_mvm_scan_umac_fill_general_p_v12(mvm, params, vif,
&scan_p->general_params,
- gen_flags, 0);
+ gen_flags, 0, 12);
ret = iwl_mvm_fill_scan_sched_params(params,
scan_p->periodic_params.schedule,
@@ -2430,9 +2484,9 @@ static int iwl_mvm_scan_umac_v14_and_above(struct iwl_mvm *mvm,
struct iwl_mvm_scan_params *params,
int type, int uid, u32 version)
{
- struct iwl_scan_req_umac_v15 *cmd = mvm->scan_cmd;
- struct iwl_scan_req_params_v15 *scan_p = &cmd->scan_params;
- struct iwl_scan_channel_params_v6 *cp = &scan_p->channel_params;
+ struct iwl_scan_req_umac_v17 *cmd = mvm->scan_cmd;
+ struct iwl_scan_req_params_v17 *scan_p = &cmd->scan_params;
+ struct iwl_scan_channel_params_v7 *cp = &scan_p->channel_params;
struct iwl_scan_probe_params_v4 *pb = &scan_p->probe_params;
int ret;
u16 gen_flags;
@@ -2451,9 +2505,9 @@ static int iwl_mvm_scan_umac_v14_and_above(struct iwl_mvm *mvm,
else
gen_flags2 = 0;
- iwl_mvm_scan_umac_fill_general_p_v11(mvm, params, vif,
+ iwl_mvm_scan_umac_fill_general_p_v12(mvm, params, vif,
&scan_p->general_params,
- gen_flags, gen_flags2);
+ gen_flags, gen_flags2, version);
ret = iwl_mvm_fill_scan_sched_params(params,
scan_p->periodic_params.schedule,
@@ -2462,11 +2516,13 @@ static int iwl_mvm_scan_umac_v14_and_above(struct iwl_mvm *mvm,
return ret;
if (!params->scan_6ghz) {
- iwl_mvm_scan_umac_fill_probe_p_v4(params, &scan_p->probe_params,
- &bitmap_ssid);
- iwl_mvm_scan_umac_fill_ch_p_v6(mvm, params, vif,
- &scan_p->channel_params, bitmap_ssid);
-
+ iwl_mvm_scan_umac_fill_probe_p_v4(params,
+ &scan_p->probe_params,
+ &bitmap_ssid);
+ iwl_mvm_scan_umac_fill_ch_p_v7(mvm, params, vif,
+ &scan_p->channel_params,
+ bitmap_ssid,
+ version);
return 0;
} else {
pb->preq = params->preq;
@@ -2478,9 +2534,10 @@ static int iwl_mvm_scan_umac_v14_and_above(struct iwl_mvm *mvm,
iwl_mvm_umac_scan_fill_6g_chan_list(mvm, params, pb);
- cp->count = iwl_mvm_umac_scan_cfg_channels_v6_6g(mvm, params,
+ cp->count = iwl_mvm_umac_scan_cfg_channels_v7_6g(mvm, params,
params->n_channels,
- pb, cp, vif->type);
+ pb, cp, vif->type,
+ version);
if (!cp->count) {
mvm->scan_uid_status[uid] = 0;
return -EINVAL;
@@ -2507,6 +2564,20 @@ static int iwl_mvm_scan_umac_v15(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
return iwl_mvm_scan_umac_v14_and_above(mvm, vif, params, type, uid, 15);
}
+static int iwl_mvm_scan_umac_v16(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+ struct iwl_mvm_scan_params *params, int type,
+ int uid)
+{
+ return iwl_mvm_scan_umac_v14_and_above(mvm, vif, params, type, uid, 16);
+}
+
+static int iwl_mvm_scan_umac_v17(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+ struct iwl_mvm_scan_params *params, int type,
+ int uid)
+{
+ return iwl_mvm_scan_umac_v14_and_above(mvm, vif, params, type, uid, 17);
+}
+
static int iwl_mvm_num_scans(struct iwl_mvm *mvm)
{
return hweight32(mvm->scan_status & IWL_MVM_SCAN_MASK);
@@ -2622,6 +2693,8 @@ struct iwl_scan_umac_handler {
static const struct iwl_scan_umac_handler iwl_scan_umac_handlers[] = {
/* set the newest version first to shorten the list traverse time */
+ IWL_SCAN_UMAC_HANDLER(17),
+ IWL_SCAN_UMAC_HANDLER(16),
IWL_SCAN_UMAC_HANDLER(15),
IWL_SCAN_UMAC_HANDLER(14),
IWL_SCAN_UMAC_HANDLER(12),
@@ -3210,7 +3283,9 @@ static size_t iwl_scan_req_umac_get_size(u8 scan_ver)
return sizeof(struct iwl_scan_req_umac_v12);
case 14:
case 15:
- return sizeof(struct iwl_scan_req_umac_v15);
+ case 16:
+ case 17:
+ return sizeof(struct iwl_scan_req_umac_v17);
}
return 0;
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sf.c b/drivers/net/wireless/intel/iwlwifi/mvm/sf.c
index 98f330fcf678..30d4233595e8 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/sf.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/sf.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
- * Copyright (C) 2013-2014, 2018-2019, 2022 Intel Corporation
+ * Copyright (C) 2013-2014, 2018-2019, 2022-2023 Intel Corporation
* Copyright (C) 2013-2014 Intel Mobile Communications GmbH
*/
#include "mvm.h"
@@ -180,9 +180,6 @@ static int iwl_mvm_sf_config(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
};
int ret = 0;
- if (mvm->cfg->disable_dummy_notification)
- sf_cmd.state |= cpu_to_le32(SF_CFG_DUMMY_NOTIF_OFF);
-
/*
* If an associated AP sta changed its antenna configuration, the state
* will remain FULL_ON but SF parameters need to be reconsidered.
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
index 05a54a69c135..3b9a343d4f67 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
- * Copyright (C) 2012-2015, 2018-2022 Intel Corporation
+ * Copyright (C) 2012-2015, 2018-2023 Intel Corporation
* Copyright (C) 2013-2015 Intel Mobile Communications GmbH
* Copyright (C) 2016-2017 Intel Deutschland GmbH
*/
@@ -60,22 +60,27 @@ u32 iwl_mvm_get_sta_ampdu_dens(struct ieee80211_link_sta *link_sta,
if (WARN_ON(!link_sta))
return 0;
- if (link_sta->ht_cap.ht_supported)
+ /* Note that we always use only legacy & highest supported PPDUs, so
+ * of Draft P802.11be D.30 Table 10-12a--Fields used for calculating
+ * the maximum A-MPDU size of various PPDU types in different bands,
+ * we only need to worry about the highest supported PPDU type here.
+ */
+
+ if (link_sta->ht_cap.ht_supported) {
+ agg_size = link_sta->ht_cap.ampdu_factor;
mpdu_dens = link_sta->ht_cap.ampdu_density;
+ }
- if (link_conf->chandef.chan->band ==
- NL80211_BAND_6GHZ) {
+ if (link_conf->chandef.chan->band == NL80211_BAND_6GHZ) {
+ /* overwrite HT values on 6 GHz */
mpdu_dens = le16_get_bits(link_sta->he_6ghz_capa.capa,
IEEE80211_HE_6GHZ_CAP_MIN_MPDU_START);
agg_size = le16_get_bits(link_sta->he_6ghz_capa.capa,
IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP);
} else if (link_sta->vht_cap.vht_supported) {
- agg_size = link_sta->vht_cap.cap &
- IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK;
- agg_size >>=
- IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT;
- } else if (link_sta->ht_cap.ht_supported) {
- agg_size = link_sta->ht_cap.ampdu_factor;
+ /* if VHT supported overwrite HT value */
+ agg_size = u32_get_bits(link_sta->vht_cap.cap,
+ IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK);
}
/* D6.0 10.12.2 A-MPDU length limit rules
@@ -91,10 +96,13 @@ u32 iwl_mvm_get_sta_ampdu_dens(struct ieee80211_link_sta *link_sta,
u8_get_bits(link_sta->he_cap.he_cap_elem.mac_cap_info[3],
IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_MASK);
+ if (link_sta->eht_cap.has_eht)
+ agg_size += u8_get_bits(link_sta->eht_cap.eht_cap_elem.mac_cap_info[1],
+ IEEE80211_EHT_MAC_CAP1_MAX_AMPDU_LEN_MASK);
+
/* Limit to max A-MPDU supported by FW */
- if (agg_size > (STA_FLG_MAX_AGG_SIZE_4M >> STA_FLG_MAX_AGG_SIZE_SHIFT))
- agg_size = (STA_FLG_MAX_AGG_SIZE_4M >>
- STA_FLG_MAX_AGG_SIZE_SHIFT);
+ agg_size = min_t(u32, agg_size,
+ STA_FLG_MAX_AGG_SIZE_4M >> STA_FLG_MAX_AGG_SIZE_SHIFT);
*_agg_size = agg_size;
return mpdu_dens;
@@ -1679,7 +1687,7 @@ static int iwl_mvm_add_int_sta_common(struct iwl_mvm *mvm,
memset(&cmd, 0, sizeof(cmd));
cmd.sta_id = sta->sta_id;
- if (iwl_fw_lookup_cmd_ver(mvm->fw, ADD_STA, 0) >= 12 &&
+ if (iwl_mvm_has_new_station_api(mvm->fw) &&
sta->type == IWL_STA_AUX_ACTIVITY)
cmd.mac_id_n_color = cpu_to_le32(mac_id);
else
@@ -1859,6 +1867,8 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm,
ret = iwl_mvm_sta_init(mvm, vif, sta, sta_id,
sta->tdls ? IWL_STA_TDLS_LINK : IWL_STA_LINK);
+ if (ret)
+ goto err;
update_fw:
ret = iwl_mvm_sta_send_to_fw(mvm, sta, sta_update, sta_flags);
@@ -2070,13 +2080,6 @@ bool iwl_mvm_sta_del(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
cancel_delayed_work(&mvm->tdls_cs.dwork);
}
- /*
- * Make sure that the tx response code sees the station as -EBUSY and
- * calls the drain worker.
- */
- spin_lock_bh(&mvm_sta->lock);
- spin_unlock_bh(&mvm_sta->lock);
-
return false;
}
@@ -2882,7 +2885,7 @@ int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
}
if (iwl_mvm_has_new_rx_api(mvm) && start) {
- u16 reorder_buf_size = buf_size * sizeof(baid_data->entries[0]);
+ u32 reorder_buf_size = buf_size * sizeof(baid_data->entries[0]);
/* sparse doesn't like the __align() so don't check */
#ifndef __CHECKER__
@@ -4306,16 +4309,27 @@ int iwl_mvm_add_pasn_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
u16 queue;
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct ieee80211_key_conf *keyconf;
+ unsigned int wdg_timeout =
+ iwl_mvm_get_wd_timeout(mvm, vif, false, false);
+ bool mld = iwl_mvm_has_mld_api(mvm->fw);
+ u32 type = mld ? STATION_TYPE_PEER : IWL_STA_LINK;
ret = iwl_mvm_allocate_int_sta(mvm, sta, 0,
- NL80211_IFTYPE_UNSPECIFIED,
- IWL_STA_LINK);
+ NL80211_IFTYPE_UNSPECIFIED, type);
if (ret)
return ret;
- ret = iwl_mvm_add_int_sta_with_queue(mvm, mvmvif->id, mvmvif->color,
- addr, sta, &queue,
- IWL_MVM_TX_FIFO_BE);
+ if (mld)
+ ret = iwl_mvm_mld_add_int_sta_with_queue(mvm, sta, addr,
+ mvmvif->deflink.fw_link_id,
+ &queue,
+ IWL_MAX_TID_COUNT,
+ &wdg_timeout);
+ else
+ ret = iwl_mvm_add_int_sta_with_queue(mvm, mvmvif->id,
+ mvmvif->color, addr, sta,
+ &queue,
+ IWL_MVM_TX_FIFO_BE);
if (ret)
goto out;
@@ -4328,9 +4342,23 @@ int iwl_mvm_add_pasn_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
keyconf->cipher = cipher;
memcpy(keyconf->key, key, key_len);
keyconf->keylen = key_len;
+ keyconf->flags = IEEE80211_KEY_FLAG_PAIRWISE;
+
+ if (mld) {
+ /* The MFP flag is set according to the station mfp field. Since
+ * we don't have a station, set it manually.
+ */
+ u32 key_flags =
+ iwl_mvm_get_sec_flags(mvm, vif, NULL, keyconf) |
+ IWL_SEC_KEY_FLAG_MFP;
+ u32 sta_mask = BIT(sta->sta_id);
+
+ ret = iwl_mvm_mld_send_key(mvm, sta_mask, key_flags, keyconf);
+ } else {
+ ret = iwl_mvm_send_sta_key(mvm, sta->sta_id, keyconf, false,
+ 0, NULL, 0, 0, true);
+ }
- ret = iwl_mvm_send_sta_key(mvm, sta->sta_id, keyconf, false,
- 0, NULL, 0, 0, true);
kfree(keyconf);
return 0;
out:
@@ -4340,10 +4368,10 @@ out:
void iwl_mvm_cancel_channel_switch(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
- u32 mac_id)
+ u32 id)
{
struct iwl_cancel_channel_switch_cmd cancel_channel_switch_cmd = {
- .mac_id = cpu_to_le32(mac_id),
+ .id = cpu_to_le32(id),
};
int ret;
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h
index a61d4f88125f..7364346a1209 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h
@@ -336,6 +336,9 @@ struct iwl_mvm_rxq_dup_data {
* @sta_id: the index of the station in the fw
* @lq_sta: holds rate scaling data, either for the case when RS is done in
* the driver - %rs_drv or in the FW - %rs_fw.
+ * @orig_amsdu_len: used to save the original amsdu_len when it is changed via
+ * debugfs. If it's set to 0, it means that it is it's not set via
+ * debugfs.
* @avg_energy: energy as reported by FW statistics notification
*/
struct iwl_mvm_link_sta {
@@ -346,6 +349,8 @@ struct iwl_mvm_link_sta {
struct iwl_lq_sta rs_drv;
} lq_sta;
+ u16 orig_amsdu_len;
+
u8 avg_energy;
};
@@ -365,6 +370,7 @@ struct iwl_mvm_link_sta {
* and from Tx response flow, it needs a spinlock.
* @tid_data: per tid data + mgmt. Look at %iwl_mvm_tid_data.
* @tid_to_baid: a simple map of TID to baid
+ * @vif: a vif pointer
* @reserved_queue: the queue reserved for this STA for DQA purposes
* Every STA has is given one reserved queue to allow it to operate. If no
* such queue can be guaranteed, the STA addition will fail.
@@ -374,10 +380,8 @@ struct iwl_mvm_link_sta {
* @amsdu_enabled: bitmap of TX AMSDU allowed TIDs.
* In case TLC offload is not active it is either 0xFFFF or 0.
* @max_amsdu_len: max AMSDU length
- * @orig_amsdu_len: used to save the original amsdu_len when it is changed via
- * debugfs. If it's set to 0, it means that it is it's not set via
- * debugfs.
* @agg_tids: bitmap of tids whose status is operational aggregated (IWL_AGG_ON)
+ * @sleeping: sta sleep transitions in power management
* @sleep_tx_count: the number of frames that we told the firmware to let out
* even when that station is asleep. This is useful in case the queue
* gets empty before all the frames were sent, which can happen when
@@ -427,7 +431,6 @@ struct iwl_mvm_sta {
bool disable_tx;
u16 amsdu_enabled;
u16 max_amsdu_len;
- u16 orig_amsdu_len;
bool sleeping;
u8 agg_tids;
u8 sleep_tx_count;
@@ -580,7 +583,7 @@ int iwl_mvm_add_pasn_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
u8 *key, u32 key_len);
void iwl_mvm_cancel_channel_switch(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
- u32 mac_id);
+ u32 id);
/* Queues */
int iwl_mvm_tvqm_enable_txq(struct iwl_mvm *mvm,
struct ieee80211_sta *sta,
@@ -616,7 +619,7 @@ int iwl_mvm_mac_sta_state_common(struct ieee80211_hw *hw,
struct ieee80211_sta *sta,
enum ieee80211_sta_state old_state,
enum ieee80211_sta_state new_state,
- struct iwl_mvm_sta_state_ops *callbacks);
+ const struct iwl_mvm_sta_state_ops *callbacks);
/* New MLD STA related APIs */
/* STA */
@@ -646,6 +649,11 @@ int iwl_mvm_mld_update_sta_links(struct iwl_mvm *mvm,
u16 old_links, u16 new_links);
u32 iwl_mvm_sta_fw_id_mask(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
int filter_link_id);
+int iwl_mvm_mld_add_int_sta_with_queue(struct iwl_mvm *mvm,
+ struct iwl_mvm_int_sta *sta,
+ const u8 *addr, int link_id,
+ u16 *queue, u8 tid,
+ unsigned int *_wdg_timeout);
/* Queues */
void iwl_mvm_mld_modify_all_sta_disable_tx(struct iwl_mvm *mvm,
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c
index 6b7b6250f1bb..5f0e7144a951 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
- * Copyright (C) 2012-2014, 2018-2022 Intel Corporation
+ * Copyright (C) 2012-2014, 2018-2023 Intel Corporation
* Copyright (C) 2013-2015 Intel Mobile Communications GmbH
* Copyright (C) 2017 Intel Deutschland GmbH
*/
@@ -103,7 +103,7 @@ void iwl_mvm_roc_done_wk(struct work_struct *wk)
/* In newer version of this command an aux station is added only
* in cases of dedicated tx queue and need to be removed in end
* of use */
- if (iwl_fw_lookup_cmd_ver(mvm->fw, ADD_STA, 0) >= 12)
+ if (iwl_mvm_has_new_station_api(mvm->fw))
iwl_mvm_rm_aux_sta(mvm);
}
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
index 00719e130438..36d70d589aed 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
@@ -1,12 +1,13 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
- * Copyright (C) 2012-2014, 2018-2022 Intel Corporation
+ * Copyright (C) 2012-2014, 2018-2023 Intel Corporation
* Copyright (C) 2013-2015 Intel Mobile Communications GmbH
* Copyright (C) 2016-2017 Intel Deutschland GmbH
*/
#include <linux/ieee80211.h>
#include <linux/etherdevice.h>
#include <linux/tcp.h>
+#include <net/gso.h>
#include <net/ip.h>
#include <net/ipv6.h>
@@ -40,13 +41,14 @@ iwl_mvm_bar_check_trigger(struct iwl_mvm *mvm, const u8 *addr,
#define OPT_HDR(type, skb, off) \
(type *)(skb_network_header(skb) + (off))
-static u16 iwl_mvm_tx_csum_pre_bz(struct iwl_mvm *mvm, struct sk_buff *skb,
- struct ieee80211_tx_info *info, bool amsdu)
+static u32 iwl_mvm_tx_csum(struct iwl_mvm *mvm, struct sk_buff *skb,
+ struct ieee80211_tx_info *info,
+ bool amsdu)
{
struct ieee80211_hdr *hdr = (void *)skb->data;
+ u16 mh_len = ieee80211_hdrlen(hdr->frame_control);
u16 offload_assist = 0;
#if IS_ENABLED(CONFIG_INET)
- u16 mh_len = ieee80211_hdrlen(hdr->frame_control);
u8 protocol = 0;
/* Do not compute checksum if already computed */
@@ -118,6 +120,8 @@ static u16 iwl_mvm_tx_csum_pre_bz(struct iwl_mvm *mvm, struct sk_buff *skb,
else
udp_hdr(skb)->check = 0;
+out:
+#endif
/*
* mac header len should include IV, size is in words unless
* the IV is added by the firmware like in WEP.
@@ -130,8 +134,6 @@ static u16 iwl_mvm_tx_csum_pre_bz(struct iwl_mvm *mvm, struct sk_buff *skb,
mh_len /= 2;
offload_assist |= mh_len << TX_CMD_OFFLD_MH_SIZE;
-out:
-#endif
if (amsdu)
offload_assist |= BIT(TX_CMD_OFFLD_AMSDU);
else if (ieee80211_hdrlen(hdr->frame_control) % 4)
@@ -141,54 +143,6 @@ out:
return offload_assist;
}
-u32 iwl_mvm_tx_csum_bz(struct iwl_mvm *mvm, struct sk_buff *skb, bool amsdu)
-{
- struct ieee80211_hdr *hdr = (void *)skb->data;
- u32 offload_assist = IWL_TX_CMD_OFFLD_BZ_PARTIAL_CSUM;
- unsigned int hdrlen = ieee80211_hdrlen(hdr->frame_control);
- unsigned int csum_start = skb_checksum_start_offset(skb);
-
- offload_assist |= u32_encode_bits(hdrlen / 2,
- IWL_TX_CMD_OFFLD_BZ_MH_LEN);
- if (amsdu)
- offload_assist |= IWL_TX_CMD_OFFLD_BZ_AMSDU;
- else if (hdrlen % 4)
- /* padding is inserted later in transport */
- offload_assist |= IWL_TX_CMD_OFFLD_BZ_MH_PAD;
-
- if (skb->ip_summed != CHECKSUM_PARTIAL)
- return offload_assist;
-
- offload_assist |= IWL_TX_CMD_OFFLD_BZ_ENABLE_CSUM |
- IWL_TX_CMD_OFFLD_BZ_ZERO2ONES;
-
- /*
- * mac80211 will always calculate checksum in software for
- * non-fast-xmit, and so we can only do offloaded checksum
- * for fast-xmit frames. In this case, we always have the
- * RFC 1042 header present. skb_checksum_start_offset()
- * returns the offset from the beginning, but the hardware
- * needs it from after the header & SNAP header.
- */
- csum_start -= hdrlen + 8;
-
- offload_assist |= u32_encode_bits(csum_start,
- IWL_TX_CMD_OFFLD_BZ_START_OFFS);
- offload_assist |= u32_encode_bits(csum_start + skb->csum_offset,
- IWL_TX_CMD_OFFLD_BZ_RESULT_OFFS);
-
- return offload_assist;
-}
-
-static u32 iwl_mvm_tx_csum(struct iwl_mvm *mvm, struct sk_buff *skb,
- struct ieee80211_tx_info *info,
- bool amsdu)
-{
- if (!iwl_mvm_has_new_tx_csum(mvm))
- return iwl_mvm_tx_csum_pre_bz(mvm, skb, info, amsdu);
- return iwl_mvm_tx_csum_bz(mvm, skb, amsdu);
-}
-
/*
* Sets most of the Tx cmd's fields
*/
@@ -288,7 +242,7 @@ void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb,
tx_cmd->sta_id = sta_id;
tx_cmd->offload_assist =
- cpu_to_le16(iwl_mvm_tx_csum_pre_bz(mvm, skb, info, amsdu));
+ cpu_to_le16(iwl_mvm_tx_csum(mvm, skb, info, amsdu));
}
static u32 iwl_mvm_get_tx_ant(struct iwl_mvm *mvm,
@@ -308,6 +262,54 @@ static u32 iwl_mvm_get_tx_ant(struct iwl_mvm *mvm,
return BIT(mvm->mgmt_last_antenna_idx) << RATE_MCS_ANT_POS;
}
+static u32 iwl_mvm_get_inject_tx_rate(struct iwl_mvm *mvm,
+ struct ieee80211_tx_info *info)
+{
+ struct ieee80211_tx_rate *rate = &info->control.rates[0];
+ u32 result;
+
+ /*
+ * we only care about legacy/HT/VHT so far, so we can
+ * build in v1 and use iwl_new_rate_from_v1()
+ */
+
+ if (rate->flags & IEEE80211_TX_RC_VHT_MCS) {
+ u8 mcs = ieee80211_rate_get_vht_mcs(rate);
+ u8 nss = ieee80211_rate_get_vht_nss(rate);
+
+ result = RATE_MCS_VHT_MSK_V1;
+ result |= u32_encode_bits(mcs, RATE_VHT_MCS_RATE_CODE_MSK);
+ result |= u32_encode_bits(nss, RATE_MCS_NSS_MSK);
+ if (rate->flags & IEEE80211_TX_RC_SHORT_GI)
+ result |= RATE_MCS_SGI_MSK_V1;
+ if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
+ result |= u32_encode_bits(1, RATE_MCS_CHAN_WIDTH_MSK_V1);
+ else if (rate->flags & IEEE80211_TX_RC_80_MHZ_WIDTH)
+ result |= u32_encode_bits(2, RATE_MCS_CHAN_WIDTH_MSK_V1);
+ else if (rate->flags & IEEE80211_TX_RC_160_MHZ_WIDTH)
+ result |= u32_encode_bits(3, RATE_MCS_CHAN_WIDTH_MSK_V1);
+ } else if (rate->flags & IEEE80211_TX_RC_MCS) {
+ result = RATE_MCS_HT_MSK_V1;
+ result |= u32_encode_bits(rate->idx,
+ RATE_HT_MCS_RATE_CODE_MSK_V1 |
+ RATE_HT_MCS_NSS_MSK_V1);
+ if (rate->flags & IEEE80211_TX_RC_SHORT_GI)
+ result |= RATE_MCS_SGI_MSK_V1;
+ if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
+ result |= u32_encode_bits(1, RATE_MCS_CHAN_WIDTH_MSK_V1);
+ if (info->flags & IEEE80211_TX_CTL_LDPC)
+ result |= RATE_MCS_LDPC_MSK_V1;
+ if (u32_get_bits(info->flags, IEEE80211_TX_CTL_STBC))
+ result |= RATE_MCS_STBC_MSK;
+ } else {
+ return 0;
+ }
+
+ if (iwl_fw_lookup_notif_ver(mvm->fw, LONG_GROUP, TX_CMD, 0) > 6)
+ return iwl_new_rate_from_v1(result);
+ return result;
+}
+
static u32 iwl_mvm_get_tx_rate(struct iwl_mvm *mvm,
struct ieee80211_tx_info *info,
struct ieee80211_sta *sta, __le16 fc)
@@ -317,8 +319,15 @@ static u32 iwl_mvm_get_tx_rate(struct iwl_mvm *mvm,
u32 rate_flags = 0;
bool is_cck;
- /* info->control is only relevant for non HW rate control */
- if (!ieee80211_hw_check(mvm->hw, HAS_RATE_CONTROL)) {
+ if (unlikely(info->control.flags & IEEE80211_TX_CTRL_RATE_INJECT)) {
+ u32 result = iwl_mvm_get_inject_tx_rate(mvm, info);
+
+ if (result)
+ return result;
+ rate_idx = info->control.rates[0].idx;
+ } else if (!ieee80211_hw_check(mvm->hw, HAS_RATE_CONTROL)) {
+ /* info->control is only relevant for non HW rate control */
+
/* HT rate doesn't make sense for a non data frame */
WARN_ONCE(info->control.rates[0].flags & IEEE80211_TX_RC_MCS &&
!ieee80211_is_data(fc),
@@ -398,7 +407,8 @@ void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm, struct iwl_tx_cmd *tx_cmd,
* table is controlled by LINK_QUALITY commands
*/
- if (ieee80211_is_data(fc) && sta) {
+ if (likely(ieee80211_is_data(fc) && sta &&
+ !(info->control.flags & IEEE80211_TX_CTRL_RATE_INJECT))) {
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
if (mvmsta->sta_state >= IEEE80211_STA_AUTHORIZED) {
@@ -556,9 +566,8 @@ iwl_mvm_set_tx_params(struct iwl_mvm *mvm, struct sk_buff *skb,
cmd->rate_n_flags = cpu_to_le32(rate_n_flags);
} else {
struct iwl_tx_cmd_gen2 *cmd = (void *)dev_cmd->payload;
- u16 offload_assist = iwl_mvm_tx_csum_pre_bz(mvm, skb,
- info,
- amsdu);
+ u16 offload_assist = iwl_mvm_tx_csum(mvm, skb,
+ info, amsdu);
cmd->offload_assist = cpu_to_le16(offload_assist);
@@ -749,6 +758,8 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb)
}
link = mvmvif->link[link_id];
+ if (WARN_ON(!link))
+ return -1;
if (!ieee80211_is_data(hdr->frame_control))
sta_id = link->bcast_sta.sta_id;
@@ -840,7 +851,7 @@ unsigned int iwl_mvm_max_amsdu_size(struct iwl_mvm *mvm,
band = mvmsta->vif->bss_conf.chandef.chan->band;
}
- lmac = iwl_mvm_get_lmac_id(mvm->fw, band);
+ lmac = iwl_mvm_get_lmac_id(mvm, band);
} else if (fw_has_capa(&mvm->fw->ucode_capa,
IWL_UCODE_TLV_CAPA_CDB_SUPPORT)) {
/* for real MLO restrict to both LMACs if they exist */
@@ -2065,7 +2076,8 @@ void iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb)
u16 tfd_cnt;
int i;
- if (unlikely(sizeof(*ba_res) > pkt_len))
+ if (IWL_FW_CHECK(mvm, sizeof(*ba_res) > pkt_len,
+ "short BA notification (%d)\n", pkt_len))
return;
sta_id = ba_res->sta_id;
@@ -2077,7 +2089,13 @@ void iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb)
(void *)(uintptr_t)ba_res->reduced_txp;
tfd_cnt = le16_to_cpu(ba_res->tfd_cnt);
- if (!tfd_cnt || struct_size(ba_res, tfd, tfd_cnt) > pkt_len)
+ if (!tfd_cnt)
+ return;
+
+ if (IWL_FW_CHECK(mvm,
+ struct_size(ba_res, tfd, tfd_cnt) > pkt_len,
+ "short BA notification (tfds:%d, size:%d)\n",
+ tfd_cnt, pkt_len))
return;
rcu_read_lock();
@@ -2135,7 +2153,9 @@ void iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb)
rcu_read_lock();
mvmsta = iwl_mvm_sta_from_staid_rcu(mvm, sta_id);
- if (WARN_ON_ONCE(!mvmsta)) {
+ if (IWL_FW_CHECK(mvm, !mvmsta,
+ "invalid STA ID %d in BA notif\n",
+ sta_id)) {
rcu_read_unlock();
return;
}
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c
index af31b09c3966..48016b4343d2 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
- * Copyright (C) 2012-2014, 2018-2022 Intel Corporation
+ * Copyright (C) 2012-2014, 2018-2023 Intel Corporation
* Copyright (C) 2013-2014 Intel Mobile Communications GmbH
* Copyright (C) 2015-2017 Intel Deutschland GmbH
*/
@@ -312,6 +312,10 @@ void iwl_mvm_update_smps(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
smps_mode = IEEE80211_SMPS_DYNAMIC;
}
+ /* SMPS is disabled in eSR */
+ if (mvmvif->esr_active)
+ smps_mode = IEEE80211_SMPS_OFF;
+
ieee80211_request_smps(vif, link_id, smps_mode);
}
@@ -413,16 +417,20 @@ static void iwl_mvm_diversity_iter(void *_data, u8 *mac,
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_mvm_diversity_iter_data *data = _data;
- int i;
+ int i, link_id;
- if (mvmvif->deflink.phy_ctxt != data->ctxt)
- return;
+ for_each_mvm_vif_valid_link(mvmvif, link_id) {
+ struct iwl_mvm_vif_link_info *link_info = mvmvif->link[link_id];
- for (i = 0; i < NUM_IWL_MVM_SMPS_REQ; i++) {
- if (mvmvif->deflink.smps_requests[i] == IEEE80211_SMPS_STATIC ||
- mvmvif->deflink.smps_requests[i] == IEEE80211_SMPS_DYNAMIC) {
- data->result = false;
- break;
+ if (link_info->phy_ctxt != data->ctxt)
+ continue;
+
+ for (i = 0; i < NUM_IWL_MVM_SMPS_REQ; i++) {
+ if (link_info->smps_requests[i] == IEEE80211_SMPS_STATIC ||
+ link_info->smps_requests[i] == IEEE80211_SMPS_DYNAMIC) {
+ data->result = false;
+ break;
+ }
}
}
}