From 9e978d8ebbe96e6abff33f2cc886b2fca1825d4f Mon Sep 17 00:00:00 2001 From: Ilan Peer Date: Mon, 10 Nov 2025 18:08:45 +0200 Subject: wifi: iwlwifi: mld: Add support for NAN - Add firmware API definitions related to NAN. - Indicate support for NAN Device interface operation, if supported by the firmware. - Add support for starting and stopping NAN cluster functionality. The NAN cluster operation is offloaded to the FW, which notifies the driver on: - cluster events: Start/Join cluster. - Discovery Window (DW) end, which allows the driver to flush the HW queues and update the higher layers Signed-off-by: Ilan Peer Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20251110180612.76dd4d45b91e.I5abfab64b4f27bed442aeca6231ffebad979cad6@changeid --- .../net/wireless/intel/iwlwifi/fw/api/mac-cfg.h | 129 ++++++++++++++++ drivers/net/wireless/intel/iwlwifi/fw/file.h | 2 + drivers/net/wireless/intel/iwlwifi/mld/Makefile | 2 +- drivers/net/wireless/intel/iwlwifi/mld/iface.c | 21 +-- drivers/net/wireless/intel/iwlwifi/mld/mac80211.c | 69 ++++++++- drivers/net/wireless/intel/iwlwifi/mld/mld.c | 3 + drivers/net/wireless/intel/iwlwifi/mld/mld.h | 3 + drivers/net/wireless/intel/iwlwifi/mld/nan.c | 167 +++++++++++++++++++++ drivers/net/wireless/intel/iwlwifi/mld/nan.h | 18 +++ drivers/net/wireless/intel/iwlwifi/mld/notif.c | 6 + drivers/net/wireless/intel/iwlwifi/mld/sta.c | 3 +- drivers/net/wireless/intel/iwlwifi/mld/tx.c | 6 + 12 files changed, 411 insertions(+), 18 deletions(-) create mode 100644 drivers/net/wireless/intel/iwlwifi/mld/nan.c create mode 100644 drivers/net/wireless/intel/iwlwifi/mld/nan.h diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h b/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h index f76cea6e9ec8..628f39917a6f 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h @@ -65,6 +65,18 @@ enum iwl_mac_conf_subcmd_ids { * @TWT_OPERATION_CMD: &struct iwl_twt_operation_cmd */ TWT_OPERATION_CMD = 0x10, + /** + * @NAN_CFG_CMD: &struct iwl_nan_config_cmd + */ + NAN_CFG_CMD = 0x12, + /** + * @NAN_DW_END_NOTIF: &struct iwl_nan_dw_end_notif + */ + NAN_DW_END_NOTIF = 0xf4, + /** + * @NAN_JOINED_CLUSTER_NOTIF: &struct iwl_nan_cluster_notif + */ + NAN_JOINED_CLUSTER_NOTIF = 0xf5, /** * @MISSED_BEACONS_NOTIF: &struct iwl_missed_beacons_notif */ @@ -990,4 +1002,121 @@ struct iwl_twt_operation_cmd { u8 ul_tid_bitmap; } __packed; /* TWT_OPERATION_API_S_VER_1 */ +enum iwl_nan_band { + IWL_NAN_BAND_5GHZ = 0, + IWL_NAN_BAND_2GHZ = 1, + IWL_NUM_NAN_BANDS, +}; + +/** + * struct iwl_nan_band_config - NAN band configuration + * + * @rssi_close: RSSI threshold for close proximity in dBm + * @rssi_middle: RSSI threshold for middle proximity in dBm + * @dw_interval: Discovery Window (DW) interval for synchronization beacons and + * SDFs. Valid values of DW interval are: 1, 2, 3, 4 and 5 corresponding to + * 1, 2, 4, 8, and 16 DWs. + * @reserved: reserved + */ +struct iwl_nan_band_config { + u8 rssi_close; + u8 rssi_middle; + u8 dw_interval; + u8 reserved; +}; /* NAN_BAND_SPECIFIC_CONFIG_API_S_VER_1 */ + +/** + * enum iwl_nan_flags - flags for NAN configuration + * + * @IWL_NAN_FLAG_DW_END_NOTIF_ENABLED: indicates that the host wants to receive + * notifications when a DW ends. + */ +enum iwl_nan_flags { + IWL_NAN_FLAG_DW_END_NOTIF_ENABLED = BIT(0), +}; + +/** + * struct iwl_nan_config_cmd - NAN configuration command + * + * @action: action to perform, see &enum iwl_ctxt_action + * @nmi_addr: NAN Management Interface (NMI) address + * @reserved_for_nmi_addr: reserved + * @discovery_beacon_interval: discovery beacon interval in TUs + * @cluster_id: local cluster ID, in case the local device starts a cluster + * @sta_id: station ID of the NAN station + * @hb_channel: channel for 5 GHz if the device supports operation on 5 GHz. + * Valid values are 44 and 149, which correspond to the 5 GHz channel, and + * 0 which means that NAN operation on the 5 GHz band is disabled. + * @master_pref: master preference + * @dwell_time: dwell time on the discovery channel during scan (milliseconds). + * If set to 0, the dwell time is determined by the firmware. + * @scan_period: scan period in seconds. If set to 0, the scan period is + * determined by the firmware. + * @flags: flags for NAN configuration, see &enum iwl_nan_flags + * @band_config: band configuration for NAN, one for each band + * @nan_attr_len: length of the NAN attributes to be added to the beacon (bytes) + * @nan_vendor_elems_len: length of the NAN vendor elements to be added to the + * beacon (bytes) + * @beacon_data: variable length data that contains the NAN attributes + * (&nan_attr_len) followed by the NAN vendor elements + * (&nan_vendor_elems_len). + */ +struct iwl_nan_config_cmd { + __le32 action; + u8 nmi_addr[6]; + __le16 reserved_for_nmi_addr; + __le32 discovery_beacon_interval; + + __le16 cluster_id; + u8 sta_id; + u8 hb_channel; + + u8 master_pref; + u8 dwell_time; + u8 scan_period; + u8 flags; + + struct iwl_nan_band_config band_config[IWL_NUM_NAN_BANDS]; + + __le32 nan_attr_len; + __le32 nan_vendor_elems_len; + u8 beacon_data[]; +} __packed; /* NAN_CONFIG_CMD_API_S_VER_1 */ + +/** + * enum iwl_nan_cluster_notif_flags - flags for the cluster notification + * + * @IWL_NAN_CLUSTER_NOTIF_FLAG_NEW_CLUSTER: indicates that the device has + * started a new cluster. If not set, the device has joined an existing + * cluster. + */ +enum iwl_nan_cluster_notif_flags { + IWL_NAN_CLUSTER_NOTIF_FLAG_NEW_CLUSTER = BIT(0), +}; /* NAN_JOINED_CLUSTER_FLAG_E_VER_1 */ + +/** + * struct iwl_nan_cluster_notif - event sent when the device starts or joins a + * NAN cluster. + * + * @cluster_id: cluster ID + * @flags: combination of &enum iwl_nan_cluster_notif_flags + * @reserved: reserved + */ +struct iwl_nan_cluster_notif { + __le16 cluster_id; + u8 flags; + u8 reserved; +}; /* NAN_JOINED_CLUSTER_NTF_API_S_VER_1 */ + +/** + * struct iwl_nan_dw_end_notif - sent to notify the host the end of a DW. + * + * @band: band on which the DW ended. See &enum iwl_nan_band. + * @reserved: reserved + */ +struct iwl_nan_dw_end_notif { + u8 band; + u8 reserved[3]; +} __packed; /* NAN_DW_END_NTF_API_S_VER_1 */ + #endif /* __iwl_fw_api_mac_cfg_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/file.h b/drivers/net/wireless/intel/iwlwifi/fw/file.h index b9e0b69c6680..378788de1d74 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/file.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/file.h @@ -447,6 +447,7 @@ typedef unsigned int __bitwise iwl_ucode_tlv_capa_t; * during assert handling even if the dump isn't split * @IWL_UCODE_TLV_CAPA_FW_ACCEPTS_RAW_DSM_TABLE: Firmware has capability of * handling raw DSM table data. + * @IWL_UCODE_TLV_CAPA_NAN_SYNC_SUPPORT: Supports NAN synchronization * * @NUM_IWL_UCODE_TLV_CAPA: number of bits used */ @@ -550,6 +551,7 @@ enum iwl_ucode_tlv_capa { IWL_UCODE_TLV_CAPA_RESET_DURING_ASSERT = (__force iwl_ucode_tlv_capa_t)(4 * 32 + 0), IWL_UCODE_TLV_CAPA_FW_ACCEPTS_RAW_DSM_TABLE = (__force iwl_ucode_tlv_capa_t)(4 * 32 + 1), + IWL_UCODE_TLV_CAPA_NAN_SYNC_SUPPORT = (__force iwl_ucode_tlv_capa_t)(4 * 32 + 2), NUM_IWL_UCODE_TLV_CAPA /* * This construction make both sparse (which cannot increment the previous diff --git a/drivers/net/wireless/intel/iwlwifi/mld/Makefile b/drivers/net/wireless/intel/iwlwifi/mld/Makefile index c966e573f430..5740c0510b61 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/Makefile +++ b/drivers/net/wireless/intel/iwlwifi/mld/Makefile @@ -4,7 +4,7 @@ obj-$(CONFIG_IWLWIFI_KUNIT_TESTS) += tests/ iwlmld-y += mld.o notif.o mac80211.o fw.o power.o iface.o link.o rx.o mcc.o session-protect.o phy.o iwlmld-y += scan.o sta.o tx.o coex.o tlc.o agg.o key.o regulatory.o ap.o thermal.o roc.o stats.o -iwlmld-y += low_latency.o mlo.o ptp.o time_sync.o ftm-initiator.o +iwlmld-y += low_latency.o mlo.o ptp.o time_sync.o ftm-initiator.o nan.o iwlmld-$(CONFIG_IWLWIFI_DEBUGFS) += debugfs.o iwlmld-$(CONFIG_IWLWIFI_LEDS) += led.o iwlmld-$(CONFIG_PM_SLEEP) += d3.o diff --git a/drivers/net/wireless/intel/iwlwifi/mld/iface.c b/drivers/net/wireless/intel/iwlwifi/mld/iface.c index a5ececfc13e4..3ca3e169738e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/iface.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/iface.c @@ -339,6 +339,10 @@ int iwl_mld_mac_fw_action(struct iwl_mld *mld, struct ieee80211_vif *vif, lockdep_assert_wiphy(mld->wiphy); + /* NAN interface type is not known to FW */ + if (vif->type == NL80211_IFTYPE_NAN) + return 0; + if (action == FW_CTXT_ACTION_REMOVE) return iwl_mld_rm_mac_from_fw(mld, vif); @@ -387,21 +391,16 @@ static void iwl_mld_mlo_scan_start_wk(struct wiphy *wiphy, IWL_MLD_ALLOC_FN(vif, vif) /* Constructor function for struct iwl_mld_vif */ -static int +static void iwl_mld_init_vif(struct iwl_mld *mld, struct ieee80211_vif *vif) { struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif); - int ret; lockdep_assert_wiphy(mld->wiphy); mld_vif->mld = mld; mld_vif->roc_activity = ROC_NUM_ACTIVITIES; - ret = iwl_mld_allocate_vif_fw_id(mld, &mld_vif->fw_id, vif); - if (ret) - return ret; - if (!mld->fw_status.in_hw_restart) { wiphy_work_init(&mld_vif->emlsr.unblock_tpt_wk, iwl_mld_emlsr_unblock_tpt_wk); @@ -415,8 +414,6 @@ iwl_mld_init_vif(struct iwl_mld *mld, struct ieee80211_vif *vif) iwl_mld_mlo_scan_start_wk); } iwl_mld_init_internal_sta(&mld_vif->aux_sta); - - return 0; } int iwl_mld_add_vif(struct iwl_mld *mld, struct ieee80211_vif *vif) @@ -426,7 +423,13 @@ int iwl_mld_add_vif(struct iwl_mld *mld, struct ieee80211_vif *vif) lockdep_assert_wiphy(mld->wiphy); - ret = iwl_mld_init_vif(mld, vif); + iwl_mld_init_vif(mld, vif); + + /* NAN interface type is not known to FW */ + if (vif->type == NL80211_IFTYPE_NAN) + return 0; + + ret = iwl_mld_allocate_vif_fw_id(mld, &mld_vif->fw_id, vif); if (ret) return ret; diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c index 55b484c16280..357e1e80bdc5 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c @@ -50,7 +50,7 @@ { \ .max = 1, \ .types = BIT(NL80211_IFTYPE_P2P_DEVICE), \ - } + }, static const struct ieee80211_iface_limit iwl_mld_limits[] = { IWL_MLD_LIMITS(0) @@ -60,6 +60,22 @@ static const struct ieee80211_iface_limit iwl_mld_limits_ap[] = { IWL_MLD_LIMITS(BIT(NL80211_IFTYPE_AP)) }; +static const struct ieee80211_iface_limit iwl_mld_limits_nan[] = { + { + .max = 2, + .types = BIT(NL80211_IFTYPE_STATION), + }, + { + .max = 1, + .types = BIT(NL80211_IFTYPE_NAN), + }, + /* Removed when two channels are permitted */ + { + .max = 1, + .types = BIT(NL80211_IFTYPE_AP), + }, +}; + static const struct ieee80211_iface_combination iwl_mld_iface_combinations[] = { { @@ -74,6 +90,19 @@ iwl_mld_iface_combinations[] = { .limits = iwl_mld_limits_ap, .n_limits = ARRAY_SIZE(iwl_mld_limits_ap), }, + /* NAN combinations follow, these exclude P2P */ + { + .num_different_channels = 2, + .max_interfaces = 3, + .limits = iwl_mld_limits_nan, + .n_limits = ARRAY_SIZE(iwl_mld_limits_nan) - 1, + }, + { + .num_different_channels = 1, + .max_interfaces = 4, + .limits = iwl_mld_limits_nan, + .n_limits = ARRAY_SIZE(iwl_mld_limits_nan), + } }; static const u8 ext_capa_base[IWL_MLD_STA_EXT_CAPA_SIZE] = { @@ -305,8 +334,22 @@ static void iwl_mac_hw_set_wiphy(struct iwl_mld *mld) wiphy->hw_timestamp_max_peers = 1; - wiphy->iface_combinations = iwl_mld_iface_combinations; - wiphy->n_iface_combinations = ARRAY_SIZE(iwl_mld_iface_combinations); + if (iwl_mld_nan_supported(mld)) { + hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_NAN); + hw->wiphy->iface_combinations = iwl_mld_iface_combinations; + hw->wiphy->n_iface_combinations = + ARRAY_SIZE(iwl_mld_iface_combinations); + + hw->wiphy->nan_supported_bands = BIT(NL80211_BAND_2GHZ); + if (mld->nvm_data->bands[NL80211_BAND_5GHZ].n_channels) + hw->wiphy->nan_supported_bands |= + BIT(NL80211_BAND_5GHZ); + } else { + wiphy->iface_combinations = iwl_mld_iface_combinations; + /* Do not include NAN combinations */ + wiphy->n_iface_combinations = + ARRAY_SIZE(iwl_mld_iface_combinations) - 2; + } wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_VHT_IBSS); wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_DFS_CONCURRENT); @@ -616,10 +659,11 @@ int iwl_mld_mac80211_add_interface(struct ieee80211_hw *hw, * Add the default link, but not if this is an MLD vif as that implies * the HW is restarting and it will be configured by change_vif_links. */ - if (!ieee80211_vif_is_mld(vif)) + if (vif->type != NL80211_IFTYPE_NAN && !ieee80211_vif_is_mld(vif)) { ret = iwl_mld_add_link(mld, &vif->bss_conf); - if (ret) - goto err; + if (ret) + goto err; + } if (vif->type == NL80211_IFTYPE_STATION) { vif->driver_flags |= IEEE80211_VIF_REMOVE_AP_AFTER_DISASSOC; @@ -647,6 +691,9 @@ int iwl_mld_mac80211_add_interface(struct ieee80211_hw *hw, if (vif->type == NL80211_IFTYPE_P2P_DEVICE) mld->p2p_device_vif = vif; + if (vif->type == NL80211_IFTYPE_NAN) + mld->nan_device_vif = vif; + return 0; err: @@ -674,7 +721,10 @@ void iwl_mld_mac80211_remove_interface(struct ieee80211_hw *hw, if (vif->type == NL80211_IFTYPE_P2P_DEVICE) mld->p2p_device_vif = NULL; - iwl_mld_remove_link(mld, &vif->bss_conf); + if (vif->type == NL80211_IFTYPE_NAN) + mld->nan_device_vif = NULL; + else + iwl_mld_remove_link(mld, &vif->bss_conf); #ifdef CONFIG_IWLWIFI_DEBUGFS debugfs_remove(iwl_mld_vif_from_mac80211(vif)->dbgfs_slink); @@ -1506,6 +1556,9 @@ iwl_mld_mac80211_conf_tx(struct ieee80211_hw *hw, lockdep_assert_wiphy(mld->wiphy); + if (vif->type == NL80211_IFTYPE_NAN) + return 0; + link = iwl_mld_link_dereference_check(mld_vif, link_id); if (!link) return -EINVAL; @@ -2699,4 +2752,6 @@ const struct ieee80211_ops iwl_mld_hw_ops = { .set_hw_timestamp = iwl_mld_set_hw_timestamp, .start_pmsr = iwl_mld_start_pmsr, .can_neg_ttlm = iwl_mld_can_neg_ttlm, + .start_nan = iwl_mld_start_nan, + .stop_nan = iwl_mld_stop_nan, }; diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mld.c b/drivers/net/wireless/intel/iwlwifi/mld/mld.c index 8a4c96385640..495e9d8f3af6 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/mld.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/mld.c @@ -234,6 +234,9 @@ static const struct iwl_hcmd_names iwl_mld_mac_conf_names[] = { HCMD_NAME(AUX_STA_CMD), HCMD_NAME(STA_REMOVE_CMD), HCMD_NAME(ROC_CMD), + HCMD_NAME(NAN_CFG_CMD), + HCMD_NAME(NAN_DW_END_NOTIF), + HCMD_NAME(NAN_JOINED_CLUSTER_NOTIF), HCMD_NAME(MISSED_BEACONS_NOTIF), HCMD_NAME(EMLSR_TRANS_FAIL_NOTIF), HCMD_NAME(ROC_NOTIF), diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mld.h b/drivers/net/wireless/intel/iwlwifi/mld/mld.h index 22efe8e10f53..66c7a7d31409 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/mld.h +++ b/drivers/net/wireless/intel/iwlwifi/mld/mld.h @@ -35,6 +35,7 @@ #include "ptp.h" #include "time_sync.h" #include "ftm-initiator.h" +#include "nan.h" /** * DOC: Introduction @@ -199,6 +200,7 @@ * @ptp_data: data of the PTP clock * @time_sync: time sync data. * @ftm_initiator: FTM initiator data + * @nan_device_vif: points to the NAN device vif if exists */ struct iwl_mld { /* Add here fields that need clean up on restart */ @@ -228,6 +230,7 @@ struct iwl_mld { #endif /* CONFIG_PM_SLEEP */ struct ieee80211_vif *p2p_device_vif; bool bt_is_active; + struct ieee80211_vif *nan_device_vif; ); struct ieee80211_link_sta __rcu *fw_id_to_link_sta[IWL_STATION_COUNT_MAX]; /* And here fields that survive a fw restart */ diff --git a/drivers/net/wireless/intel/iwlwifi/mld/nan.c b/drivers/net/wireless/intel/iwlwifi/mld/nan.c new file mode 100644 index 000000000000..0bce7a48ab2c --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/mld/nan.c @@ -0,0 +1,167 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* + * Copyright (C) 2025 Intel Corporation + */ + +#include "mld.h" +#include "iface.h" +#include "fw/api/mac-cfg.h" + +#define IWL_NAN_DISOVERY_BEACON_INTERNVAL_TU 512 +#define IWL_NAN_RSSI_CLOSE 55 +#define IWL_NAN_RSSI_MIDDLE 70 + +/* possible discovery channels for the 5 GHz band*/ +#define IWL_NAN_CHANNEL_UNII1 44 +#define IWL_NAN_CHANNEL_UNII3 149 + +bool iwl_mld_nan_supported(struct iwl_mld *mld) +{ + return fw_has_capa(&mld->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_NAN_SYNC_SUPPORT); +} + +static bool iwl_mld_nan_can_beacon(struct ieee80211_vif *vif, + enum nl80211_band band, u8 channel) +{ + struct wiphy *wiphy = ieee80211_vif_to_wdev(vif)->wiphy; + int freq = ieee80211_channel_to_frequency(channel, band); + struct ieee80211_channel *chan = ieee80211_get_channel(wiphy, + freq); + struct cfg80211_chan_def def; + + if (!chan) + return false; + + cfg80211_chandef_create(&def, chan, NL80211_CHAN_NO_HT); + return cfg80211_reg_can_beacon(wiphy, &def, vif->type); +} + +int iwl_mld_start_nan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct cfg80211_nan_conf *conf) +{ + struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw); + struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif); + struct iwl_mld_int_sta *aux_sta = &mld_vif->aux_sta; + struct iwl_nan_config_cmd cmd = { + .action = cpu_to_le32(FW_CTXT_ACTION_ADD), + .discovery_beacon_interval = + cpu_to_le32(IWL_NAN_DISOVERY_BEACON_INTERNVAL_TU), + .band_config = { + { + .rssi_close = IWL_NAN_RSSI_CLOSE, + .rssi_middle = IWL_NAN_RSSI_MIDDLE, + .dw_interval = 1, + }, + { + .rssi_close = IWL_NAN_RSSI_CLOSE, + .rssi_middle = IWL_NAN_RSSI_MIDDLE, + .dw_interval = 1, + }, + }, + }; + int ret; + + lockdep_assert_wiphy(mld->wiphy); + + IWL_DEBUG_MAC80211(mld, "Start NAN: bands=0x%x\n", conf->bands); + + ether_addr_copy(cmd.nmi_addr, vif->addr); + cmd.master_pref = conf->master_pref; + cmd.flags = IWL_NAN_FLAG_DW_END_NOTIF_ENABLED; + + if (WARN_ON(!(conf->bands & BIT(NL80211_BAND_2GHZ)))) + return -EINVAL; + + if (conf->bands & BIT(NL80211_BAND_5GHZ)) { + if (iwl_mld_nan_can_beacon(vif, NL80211_BAND_5GHZ, + IWL_NAN_CHANNEL_UNII1)) { + cmd.hb_channel = IWL_NAN_CHANNEL_UNII1; + } else if (iwl_mld_nan_can_beacon(vif, NL80211_BAND_5GHZ, + IWL_NAN_CHANNEL_UNII3)) { + cmd.hb_channel = IWL_NAN_CHANNEL_UNII3; + } else { + IWL_ERR(mld, "NAN: Can't beacon on 5 GHz band\n"); + ret = -EINVAL; + } + } else { + memset(&cmd.band_config[IWL_NAN_BAND_5GHZ], 0, + sizeof(cmd.band_config[0])); + } + + ret = iwl_mld_add_aux_sta(mld, aux_sta); + if (ret) + return ret; + + cmd.sta_id = aux_sta->sta_id; + + ret = iwl_mld_send_cmd_pdu(mld, + WIDE_ID(MAC_CONF_GROUP, NAN_CFG_CMD), + &cmd); + + if (ret) { + IWL_ERR(mld, "Failed to start NAN. ret=%d\n", ret); + iwl_mld_remove_aux_sta(mld, vif); + } + + return ret; +} + +int iwl_mld_stop_nan(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw); + struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif); + struct iwl_nan_config_cmd cmd = { + .action = cpu_to_le32(FW_CTXT_ACTION_REMOVE), + }; + int ret; + + lockdep_assert_wiphy(mld->wiphy); + + ret = iwl_mld_send_cmd_pdu(mld, + WIDE_ID(MAC_CONF_GROUP, NAN_CFG_CMD), + &cmd); + if (ret) + IWL_ERR(mld, "NAN: Failed to stop NAN. ret=%d\n", ret); + + /* assume that higher layer guarantees that no additional frames are + * added before calling this callback + */ + iwl_mld_flush_link_sta_txqs(mld, mld_vif->aux_sta.sta_id); + iwl_mld_remove_aux_sta(mld, vif); + + return 0; +} + +void iwl_mld_handle_nan_cluster_notif(struct iwl_mld *mld, + struct iwl_rx_packet *pkt) +{ + struct iwl_nan_cluster_notif *notif = (void *)pkt->data; + + IWL_DEBUG_INFO(mld, + "NAN: cluster event: cluster_id=0x%x, flags=0x%x\n", + le16_to_cpu(notif->cluster_id), notif->flags); +} + +void iwl_mld_handle_nan_dw_end_notif(struct iwl_mld *mld, + struct iwl_rx_packet *pkt) +{ + struct iwl_nan_dw_end_notif *notif = (void *)pkt->data; + struct iwl_mld_vif *mld_vif = mld->nan_device_vif ? + iwl_mld_vif_from_mac80211(mld->nan_device_vif) : + NULL; + + IWL_INFO(mld, "NAN: DW end: band=%u\n", notif->band); + + if (!mld_vif) + return; + + if (WARN_ON(mld_vif->aux_sta.sta_id == IWL_INVALID_STA)) + return; + + IWL_DEBUG_INFO(mld, "NAN: flush queues for aux sta=%u\n", + mld_vif->aux_sta.sta_id); + + iwl_mld_flush_link_sta_txqs(mld, mld_vif->aux_sta.sta_id); +} diff --git a/drivers/net/wireless/intel/iwlwifi/mld/nan.h b/drivers/net/wireless/intel/iwlwifi/mld/nan.h new file mode 100644 index 000000000000..c7b621393655 --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/mld/nan.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ +/* + * Copyright (C) 2025 Intel Corporation + */ + +#include +#include + +bool iwl_mld_nan_supported(struct iwl_mld *mld); +int iwl_mld_start_nan(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct cfg80211_nan_conf *conf); +int iwl_mld_stop_nan(struct ieee80211_hw *hw, + struct ieee80211_vif *vif); +void iwl_mld_handle_nan_cluster_notif(struct iwl_mld *mld, + struct iwl_rx_packet *pkt); +void iwl_mld_handle_nan_dw_end_notif(struct iwl_mld *mld, + struct iwl_rx_packet *pkt); diff --git a/drivers/net/wireless/intel/iwlwifi/mld/notif.c b/drivers/net/wireless/intel/iwlwifi/mld/notif.c index 4cf3920b005f..eedb4818c647 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/notif.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/notif.c @@ -344,6 +344,8 @@ CMD_VERSIONS(time_sync_confirm_notif, CMD_VER_ENTRY(1, iwl_time_msmt_cfm_notify)) CMD_VERSIONS(ftm_resp_notif, CMD_VER_ENTRY(10, iwl_tof_range_rsp_ntfy)) CMD_VERSIONS(beacon_filter_notif, CMD_VER_ENTRY(2, iwl_beacon_filter_notif)) +CMD_VERSIONS(nan_cluster_notif, CMD_VER_ENTRY(1, iwl_nan_cluster_notif)) +CMD_VERSIONS(nan_dw_end_notif, CMD_VER_ENTRY(1, iwl_nan_dw_end_notif)) DEFINE_SIMPLE_CANCELLATION(session_prot, iwl_session_prot_notif, mac_link_id) DEFINE_SIMPLE_CANCELLATION(tlc, iwl_tlc_update_notif, sta_id) @@ -459,6 +461,10 @@ const struct iwl_rx_handler iwl_mld_rx_handlers[] = { beacon_filter_notif) RX_HANDLER_OF_FTM_REQ(LOCATION_GROUP, TOF_RANGE_RESPONSE_NOTIF, ftm_resp_notif) + RX_HANDLER_NO_OBJECT(MAC_CONF_GROUP, NAN_JOINED_CLUSTER_NOTIF, + nan_cluster_notif, RX_HANDLER_ASYNC) + RX_HANDLER_NO_OBJECT(MAC_CONF_GROUP, NAN_DW_END_NOTIF, + nan_dw_end_notif, RX_HANDLER_ASYNC) }; EXPORT_SYMBOL_IF_IWLWIFI_KUNIT(iwl_mld_rx_handlers); diff --git a/drivers/net/wireless/intel/iwlwifi/mld/sta.c b/drivers/net/wireless/intel/iwlwifi/mld/sta.c index 61ecc33116cf..6056a306f7cb 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/sta.c @@ -1163,7 +1163,8 @@ void iwl_mld_remove_aux_sta(struct iwl_mld *mld, struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif); if (WARN_ON(vif->type != NL80211_IFTYPE_P2P_DEVICE && - vif->type != NL80211_IFTYPE_STATION)) + vif->type != NL80211_IFTYPE_STATION && + vif->type != NL80211_IFTYPE_NAN)) return; iwl_mld_remove_internal_sta(mld, &mld_vif->aux_sta, false, diff --git a/drivers/net/wireless/intel/iwlwifi/mld/tx.c b/drivers/net/wireless/intel/iwlwifi/mld/tx.c index 3b4b575aadaa..9af4d73e3444 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/tx.c @@ -666,6 +666,12 @@ iwl_mld_get_tx_queue_id(struct iwl_mld *mld, struct ieee80211_txq *txq, } WARN_ON(!ieee80211_is_mgmt(fc)); + return mld_vif->aux_sta.queue_id; + case NL80211_IFTYPE_NAN: + mld_vif = iwl_mld_vif_from_mac80211(info->control.vif); + + WARN_ON(!ieee80211_is_mgmt(fc)); + return mld_vif->aux_sta.queue_id; default: WARN_ONCE(1, "Unsupported vif type\n"); -- cgit v1.2.3 From dbbeebece03050cd510073ce89fee83844e06b00 Mon Sep 17 00:00:00 2001 From: Ilan Peer Date: Mon, 10 Nov 2025 18:08:46 +0200 Subject: wifi: iwlwifi: mld: Handle rate selection for NAN interface Frames transmitted over a NAN interface might not have channel information assigned to them. In such cases assign the lowest OFDM to the frame. Signed-off-by: Ilan Peer Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20251110180612.72046f98f878.Ib784931fffd0747acd9d7bb22eabbbec5282733e@changeid --- drivers/net/wireless/intel/iwlwifi/mld/tx.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/wireless/intel/iwlwifi/mld/tx.c b/drivers/net/wireless/intel/iwlwifi/mld/tx.c index 9af4d73e3444..546d09a38dab 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/tx.c @@ -345,6 +345,11 @@ u8 iwl_mld_get_lowest_rate(struct iwl_mld *mld, iwl_mld_get_basic_rates_and_band(mld, vif, info, &basic_rates, &band); + if (band >= NUM_NL80211_BANDS) { + WARN_ON(vif->type != NL80211_IFTYPE_NAN); + return IWL_FIRST_OFDM_RATE; + } + sband = mld->hw->wiphy->bands[band]; for_each_set_bit(i, &basic_rates, BITS_PER_LONG) { u16 hw = sband->bitrates[i].hw_value; -- cgit v1.2.3 From 6009414649910210ae3c18a96747e9a5e5224306 Mon Sep 17 00:00:00 2001 From: Ilan Peer Date: Mon, 10 Nov 2025 18:08:47 +0200 Subject: wifi: iwlwifi: mld: Declare support for NAN capabilities And notify cfg80211 about NAN cluster events and DW end events. Signed-off-by: Ilan Peer Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20251110180612.eb49cb2172ce.Iaf59884242cb52351e24cb0711875851b5c863f8@changeid --- drivers/net/wireless/intel/iwlwifi/mld/mac80211.c | 16 +++++ drivers/net/wireless/intel/iwlwifi/mld/nan.c | 71 ++++++++++++++++++++++- drivers/net/wireless/intel/iwlwifi/mld/nan.h | 6 ++ drivers/net/wireless/intel/iwlwifi/mld/notif.c | 11 ++-- drivers/net/wireless/intel/iwlwifi/mld/notif.h | 1 + 5 files changed, 99 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c index 357e1e80bdc5..9a58f2751d4e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c @@ -344,6 +344,22 @@ static void iwl_mac_hw_set_wiphy(struct iwl_mld *mld) if (mld->nvm_data->bands[NL80211_BAND_5GHZ].n_channels) hw->wiphy->nan_supported_bands |= BIT(NL80211_BAND_5GHZ); + + hw->wiphy->nan_capa.flags = WIPHY_NAN_FLAGS_CONFIGURABLE_SYNC | + WIPHY_NAN_FLAGS_USERSPACE_DE; + + hw->wiphy->nan_capa.op_mode = NAN_OP_MODE_PHY_MODE_MASK | + NAN_OP_MODE_80P80MHZ | + NAN_OP_MODE_160MHZ; + + /* Support 2 antenna's for Tx and Rx */ + hw->wiphy->nan_capa.n_antennas = 0x22; + + /* Maximal channel switch time is 4 msec */ + hw->wiphy->nan_capa.max_channel_switch_time = 4; + hw->wiphy->nan_capa.dev_capabilities = + NAN_DEV_CAPA_EXT_KEY_ID_SUPPORTED | + NAN_DEV_CAPA_NDPE_SUPPORTED; } else { wiphy->iface_combinations = iwl_mld_iface_combinations; /* Do not include NAN combinations */ diff --git a/drivers/net/wireless/intel/iwlwifi/mld/nan.c b/drivers/net/wireless/intel/iwlwifi/mld/nan.c index 0bce7a48ab2c..5104ba75b38c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/nan.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/nan.c @@ -131,6 +131,12 @@ int iwl_mld_stop_nan(struct ieee80211_hw *hw, iwl_mld_flush_link_sta_txqs(mld, mld_vif->aux_sta.sta_id); iwl_mld_remove_aux_sta(mld, vif); + /* cancel based on object type being NAN, as the NAN objects do + * not have a unique identifier associated with them + */ + iwl_mld_cancel_notifications_of_object(mld, + IWL_MLD_OBJECT_TYPE_NAN, + 0); return 0; } @@ -138,10 +144,43 @@ void iwl_mld_handle_nan_cluster_notif(struct iwl_mld *mld, struct iwl_rx_packet *pkt) { struct iwl_nan_cluster_notif *notif = (void *)pkt->data; + struct wireless_dev *wdev = mld->nan_device_vif ? + ieee80211_vif_to_wdev(mld->nan_device_vif) : NULL; + bool new_cluster = !!(notif->flags & + IWL_NAN_CLUSTER_NOTIF_FLAG_NEW_CLUSTER); + u8 cluster_id[ETH_ALEN] __aligned(2) = { + 0x50, 0x6f, 0x9a, 0x01, 0x00, 0x00 + }; + u16 id = le16_to_cpu(notif->cluster_id); IWL_DEBUG_INFO(mld, "NAN: cluster event: cluster_id=0x%x, flags=0x%x\n", - le16_to_cpu(notif->cluster_id), notif->flags); + id, notif->flags); + + if (IWL_FW_CHECK(mld, !wdev, "NAN: cluster event without wdev\n")) + return; + + if (IWL_FW_CHECK(mld, !ieee80211_vif_nan_started(mld->nan_device_vif), + "NAN: cluster event without NAN started\n")) + return; + + *((u16 *)(cluster_id + 4)) = id; + + cfg80211_nan_cluster_joined(wdev, cluster_id, new_cluster, GFP_KERNEL); +} + +bool iwl_mld_cancel_nan_cluster_notif(struct iwl_mld *mld, + struct iwl_rx_packet *pkt, + u32 obj_id) +{ + return true; +} + +bool iwl_mld_cancel_nan_dw_end_notif(struct iwl_mld *mld, + struct iwl_rx_packet *pkt, + u32 obj_id) +{ + return true; } void iwl_mld_handle_nan_dw_end_notif(struct iwl_mld *mld, @@ -151,10 +190,16 @@ void iwl_mld_handle_nan_dw_end_notif(struct iwl_mld *mld, struct iwl_mld_vif *mld_vif = mld->nan_device_vif ? iwl_mld_vif_from_mac80211(mld->nan_device_vif) : NULL; + struct wireless_dev *wdev; + struct ieee80211_channel *chan; IWL_INFO(mld, "NAN: DW end: band=%u\n", notif->band); - if (!mld_vif) + if (IWL_FW_CHECK(mld, !mld_vif, "NAN: DW end without mld_vif\n")) + return; + + if (IWL_FW_CHECK(mld, !ieee80211_vif_nan_started(mld->nan_device_vif), + "NAN: DW end without NAN started\n")) return; if (WARN_ON(mld_vif->aux_sta.sta_id == IWL_INVALID_STA)) @@ -164,4 +209,26 @@ void iwl_mld_handle_nan_dw_end_notif(struct iwl_mld *mld, mld_vif->aux_sta.sta_id); iwl_mld_flush_link_sta_txqs(mld, mld_vif->aux_sta.sta_id); + + /* TODO: currently the notification specified the band on which the DW + * ended. Need to change that to the actual channel on which the next DW + * will be started. + */ + switch (notif->band) { + case IWL_NAN_BAND_2GHZ: + chan = ieee80211_get_channel(mld->wiphy, 2437); + break; + case IWL_NAN_BAND_5GHZ: + /* TODO: use the actual channel */ + chan = ieee80211_get_channel(mld->wiphy, 5745); + break; + default: + IWL_FW_CHECK(mld, false, + "NAN: Invalid band %u in DW end notif\n", + notif->band); + return; + } + + wdev = ieee80211_vif_to_wdev(mld->nan_device_vif); + cfg80211_next_nan_dw_notif(wdev, chan, GFP_KERNEL); } diff --git a/drivers/net/wireless/intel/iwlwifi/mld/nan.h b/drivers/net/wireless/intel/iwlwifi/mld/nan.h index c7b621393655..97607b74a177 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/nan.h +++ b/drivers/net/wireless/intel/iwlwifi/mld/nan.h @@ -16,3 +16,9 @@ void iwl_mld_handle_nan_cluster_notif(struct iwl_mld *mld, struct iwl_rx_packet *pkt); void iwl_mld_handle_nan_dw_end_notif(struct iwl_mld *mld, struct iwl_rx_packet *pkt); +bool iwl_mld_cancel_nan_cluster_notif(struct iwl_mld *mld, + struct iwl_rx_packet *pkt, + u32 obj_id); +bool iwl_mld_cancel_nan_dw_end_notif(struct iwl_mld *mld, + struct iwl_rx_packet *pkt, + u32 obj_id); diff --git a/drivers/net/wireless/intel/iwlwifi/mld/notif.c b/drivers/net/wireless/intel/iwlwifi/mld/notif.c index eedb4818c647..555542dc5e37 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/notif.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/notif.c @@ -111,6 +111,9 @@ static bool iwl_mld_cancel_##name##_notif(struct iwl_mld *mld, \ #define RX_HANDLER_OF_FTM_REQ(_grp, _cmd, _name) \ RX_HANDLER_OF_OBJ(_grp, _cmd, _name, FTM_REQ) +#define RX_HANDLER_OF_NAN(_grp, _cmd, _name) \ + RX_HANDLER_OF_OBJ(_grp, _cmd, _name, NAN) + static void iwl_mld_handle_mfuart_notif(struct iwl_mld *mld, struct iwl_rx_packet *pkt) { @@ -461,10 +464,10 @@ const struct iwl_rx_handler iwl_mld_rx_handlers[] = { beacon_filter_notif) RX_HANDLER_OF_FTM_REQ(LOCATION_GROUP, TOF_RANGE_RESPONSE_NOTIF, ftm_resp_notif) - RX_HANDLER_NO_OBJECT(MAC_CONF_GROUP, NAN_JOINED_CLUSTER_NOTIF, - nan_cluster_notif, RX_HANDLER_ASYNC) - RX_HANDLER_NO_OBJECT(MAC_CONF_GROUP, NAN_DW_END_NOTIF, - nan_dw_end_notif, RX_HANDLER_ASYNC) + RX_HANDLER_OF_NAN(MAC_CONF_GROUP, NAN_JOINED_CLUSTER_NOTIF, + nan_cluster_notif) + RX_HANDLER_OF_NAN(MAC_CONF_GROUP, NAN_DW_END_NOTIF, + nan_dw_end_notif) }; EXPORT_SYMBOL_IF_IWLWIFI_KUNIT(iwl_mld_rx_handlers); diff --git a/drivers/net/wireless/intel/iwlwifi/mld/notif.h b/drivers/net/wireless/intel/iwlwifi/mld/notif.h index adcdd9dec192..373c1a90d98e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/notif.h +++ b/drivers/net/wireless/intel/iwlwifi/mld/notif.h @@ -25,6 +25,7 @@ enum iwl_mld_object_type { IWL_MLD_OBJECT_TYPE_ROC, IWL_MLD_OBJECT_TYPE_SCAN, IWL_MLD_OBJECT_TYPE_FTM_REQ, + IWL_MLD_OBJECT_TYPE_NAN, }; void iwl_mld_cancel_notifications_of_object(struct iwl_mld *mld, -- cgit v1.2.3 From 89000fe4b1dca198ade6ba9f8edd61fa6b9596dc Mon Sep 17 00:00:00 2001 From: Ilan Peer Date: Mon, 10 Nov 2025 18:08:48 +0200 Subject: wifi: iwlwifi: mld: Extend the NAN configuration Configure the FW based on the NAN cluster configuration provided by higher layers. Signed-off-by: Ilan Peer Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20251110180612.5353d9520f0f.Ie41dcea815afbb5da6cc870ea50a271c18f66639@changeid --- drivers/net/wireless/intel/iwlwifi/mld/nan.c | 131 ++++++++++++++++----------- 1 file changed, 79 insertions(+), 52 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mld/nan.c b/drivers/net/wireless/intel/iwlwifi/mld/nan.c index 5104ba75b38c..6cdee2aa0f50 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/nan.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/nan.c @@ -11,30 +11,30 @@ #define IWL_NAN_RSSI_CLOSE 55 #define IWL_NAN_RSSI_MIDDLE 70 -/* possible discovery channels for the 5 GHz band*/ -#define IWL_NAN_CHANNEL_UNII1 44 -#define IWL_NAN_CHANNEL_UNII3 149 - bool iwl_mld_nan_supported(struct iwl_mld *mld) { return fw_has_capa(&mld->fw->ucode_capa, IWL_UCODE_TLV_CAPA_NAN_SYNC_SUPPORT); } -static bool iwl_mld_nan_can_beacon(struct ieee80211_vif *vif, - enum nl80211_band band, u8 channel) +static int iwl_mld_nan_send_config_cmd(struct iwl_mld *mld, + struct iwl_nan_config_cmd *cmd, + u8 *beacon_data, size_t beacon_data_len) { - struct wiphy *wiphy = ieee80211_vif_to_wdev(vif)->wiphy; - int freq = ieee80211_channel_to_frequency(channel, band); - struct ieee80211_channel *chan = ieee80211_get_channel(wiphy, - freq); - struct cfg80211_chan_def def; + struct iwl_host_cmd hcmd = { + .id = WIDE_ID(MAC_CONF_GROUP, NAN_CFG_CMD), + }; - if (!chan) - return false; + hcmd.len[0] = sizeof(*cmd); + hcmd.data[0] = cmd; + + if (beacon_data_len) { + hcmd.len[1] = beacon_data_len; + hcmd.data[1] = beacon_data; + hcmd.dataflags[1] = IWL_HCMD_DFL_DUP; + } - cfg80211_chandef_create(&def, chan, NL80211_CHAN_NO_HT); - return cfg80211_reg_can_beacon(wiphy, &def, vif->type); + return iwl_mld_send_cmd(mld, &hcmd); } int iwl_mld_start_nan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, @@ -45,21 +45,8 @@ int iwl_mld_start_nan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct iwl_mld_int_sta *aux_sta = &mld_vif->aux_sta; struct iwl_nan_config_cmd cmd = { .action = cpu_to_le32(FW_CTXT_ACTION_ADD), - .discovery_beacon_interval = - cpu_to_le32(IWL_NAN_DISOVERY_BEACON_INTERNVAL_TU), - .band_config = { - { - .rssi_close = IWL_NAN_RSSI_CLOSE, - .rssi_middle = IWL_NAN_RSSI_MIDDLE, - .dw_interval = 1, - }, - { - .rssi_close = IWL_NAN_RSSI_CLOSE, - .rssi_middle = IWL_NAN_RSSI_MIDDLE, - .dw_interval = 1, - }, - }, }; + u8 *data __free(kfree) = NULL; int ret; lockdep_assert_wiphy(mld->wiphy); @@ -68,25 +55,66 @@ int iwl_mld_start_nan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, ether_addr_copy(cmd.nmi_addr, vif->addr); cmd.master_pref = conf->master_pref; - cmd.flags = IWL_NAN_FLAG_DW_END_NOTIF_ENABLED; - - if (WARN_ON(!(conf->bands & BIT(NL80211_BAND_2GHZ)))) - return -EINVAL; - - if (conf->bands & BIT(NL80211_BAND_5GHZ)) { - if (iwl_mld_nan_can_beacon(vif, NL80211_BAND_5GHZ, - IWL_NAN_CHANNEL_UNII1)) { - cmd.hb_channel = IWL_NAN_CHANNEL_UNII1; - } else if (iwl_mld_nan_can_beacon(vif, NL80211_BAND_5GHZ, - IWL_NAN_CHANNEL_UNII3)) { - cmd.hb_channel = IWL_NAN_CHANNEL_UNII3; - } else { - IWL_ERR(mld, "NAN: Can't beacon on 5 GHz band\n"); - ret = -EINVAL; - } - } else { - memset(&cmd.band_config[IWL_NAN_BAND_5GHZ], 0, - sizeof(cmd.band_config[0])); + + if (conf->cluster_id) + cmd.cluster_id = + cpu_to_le16(*(const u16 *)(conf->cluster_id + 4)); + + cmd.scan_period = conf->scan_period < 255 ? conf->scan_period : 255; + cmd.dwell_time = + conf->scan_dwell_time < 255 ? conf->scan_dwell_time : 255; + + if (conf->discovery_beacon_interval) + cmd.discovery_beacon_interval = + cpu_to_le32(conf->discovery_beacon_interval); + else + cmd.discovery_beacon_interval = + cpu_to_le32(IWL_NAN_DISOVERY_BEACON_INTERNVAL_TU); + + if (conf->enable_dw_notification) + cmd.flags = IWL_NAN_FLAG_DW_END_NOTIF_ENABLED; + + /* 2 GHz band must be supported */ + cmd.band_config[IWL_NAN_BAND_2GHZ].rssi_close = + abs(conf->band_cfgs[NL80211_BAND_2GHZ].rssi_close); + cmd.band_config[IWL_NAN_BAND_2GHZ].rssi_middle = + abs(conf->band_cfgs[NL80211_BAND_2GHZ].rssi_middle); + cmd.band_config[IWL_NAN_BAND_2GHZ].dw_interval = + conf->band_cfgs[NL80211_BAND_2GHZ].awake_dw_interval; + + /* 5 GHz band operation is optional. Configure its operation if + * supported. Note that conf->bands might be zero, so we need to check + * the channel pointer, not the band mask. + */ + if (conf->band_cfgs[NL80211_BAND_5GHZ].chan) { + cmd.hb_channel = + conf->band_cfgs[NL80211_BAND_5GHZ].chan->hw_value; + + cmd.band_config[IWL_NAN_BAND_5GHZ].rssi_close = + abs(conf->band_cfgs[NL80211_BAND_5GHZ].rssi_close); + cmd.band_config[IWL_NAN_BAND_5GHZ].rssi_middle = + abs(conf->band_cfgs[NL80211_BAND_5GHZ].rssi_middle); + cmd.band_config[IWL_NAN_BAND_5GHZ].dw_interval = + conf->band_cfgs[NL80211_BAND_5GHZ].awake_dw_interval; + } + + if (conf->extra_nan_attrs_len || conf->vendor_elems_len) { + data = kmalloc(conf->extra_nan_attrs_len + + conf->vendor_elems_len, GFP_KERNEL); + if (!data) + return -ENOMEM; + + cmd.nan_attr_len = cpu_to_le32(conf->extra_nan_attrs_len); + cmd.nan_vendor_elems_len = cpu_to_le32(conf->vendor_elems_len); + + if (conf->extra_nan_attrs_len) + memcpy(data, conf->extra_nan_attrs, + conf->extra_nan_attrs_len); + + if (conf->vendor_elems_len) + memcpy(data + conf->extra_nan_attrs_len, + conf->vendor_elems, + conf->vendor_elems_len); } ret = iwl_mld_add_aux_sta(mld, aux_sta); @@ -95,10 +123,9 @@ int iwl_mld_start_nan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, cmd.sta_id = aux_sta->sta_id; - ret = iwl_mld_send_cmd_pdu(mld, - WIDE_ID(MAC_CONF_GROUP, NAN_CFG_CMD), - &cmd); - + ret = iwl_mld_nan_send_config_cmd(mld, &cmd, data, + conf->extra_nan_attrs_len + + conf->vendor_elems_len); if (ret) { IWL_ERR(mld, "Failed to start NAN. ret=%d\n", ret); iwl_mld_remove_aux_sta(mld, vif); -- cgit v1.2.3 From ab4107583b0a42868a1638603d449e64121f5640 Mon Sep 17 00:00:00 2001 From: Ilan Peer Date: Mon, 10 Nov 2025 18:08:49 +0200 Subject: wifi: iwlwifi: mld: Support changing NAN configuration Add support for changing the NAN configuration. Signed-off-by: Ilan Peer Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20251110180612.82dcdfeb9533.Ib8576873c92f68f1bcafbda409d45ef2b4133e9f@changeid --- drivers/net/wireless/intel/iwlwifi/mld/mac80211.c | 1 + drivers/net/wireless/intel/iwlwifi/mld/nan.c | 52 +++++++++++++++++------ drivers/net/wireless/intel/iwlwifi/mld/nan.h | 4 ++ 3 files changed, 44 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c index 9a58f2751d4e..05ab6246eb17 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c @@ -2770,4 +2770,5 @@ const struct ieee80211_ops iwl_mld_hw_ops = { .can_neg_ttlm = iwl_mld_can_neg_ttlm, .start_nan = iwl_mld_start_nan, .stop_nan = iwl_mld_stop_nan, + .nan_change_conf = iwl_mld_nan_change_config, }; diff --git a/drivers/net/wireless/intel/iwlwifi/mld/nan.c b/drivers/net/wireless/intel/iwlwifi/mld/nan.c index 6cdee2aa0f50..e7a2c1ec7494 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/nan.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/nan.c @@ -37,22 +37,19 @@ static int iwl_mld_nan_send_config_cmd(struct iwl_mld *mld, return iwl_mld_send_cmd(mld, &hcmd); } -int iwl_mld_start_nan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct cfg80211_nan_conf *conf) +static int iwl_mld_nan_config(struct iwl_mld *mld, + struct ieee80211_vif *vif, + struct cfg80211_nan_conf *conf, + enum iwl_ctxt_action action) { - struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw); struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif); - struct iwl_mld_int_sta *aux_sta = &mld_vif->aux_sta; struct iwl_nan_config_cmd cmd = { - .action = cpu_to_le32(FW_CTXT_ACTION_ADD), + .action = cpu_to_le32(action), }; u8 *data __free(kfree) = NULL; - int ret; lockdep_assert_wiphy(mld->wiphy); - IWL_DEBUG_MAC80211(mld, "Start NAN: bands=0x%x\n", conf->bands); - ether_addr_copy(cmd.nmi_addr, vif->addr); cmd.master_pref = conf->master_pref; @@ -117,15 +114,27 @@ int iwl_mld_start_nan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, conf->vendor_elems_len); } + cmd.sta_id = mld_vif->aux_sta.sta_id; + return iwl_mld_nan_send_config_cmd(mld, &cmd, data, + conf->extra_nan_attrs_len + + conf->vendor_elems_len); +} + +int iwl_mld_start_nan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct cfg80211_nan_conf *conf) +{ + struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw); + struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif); + struct iwl_mld_int_sta *aux_sta = &mld_vif->aux_sta; + int ret; + + IWL_DEBUG_MAC80211(mld, "NAN: start: bands=0x%x\n", conf->bands); + ret = iwl_mld_add_aux_sta(mld, aux_sta); if (ret) return ret; - cmd.sta_id = aux_sta->sta_id; - - ret = iwl_mld_nan_send_config_cmd(mld, &cmd, data, - conf->extra_nan_attrs_len + - conf->vendor_elems_len); + ret = iwl_mld_nan_config(mld, vif, conf, FW_CTXT_ACTION_ADD); if (ret) { IWL_ERR(mld, "Failed to start NAN. ret=%d\n", ret); iwl_mld_remove_aux_sta(mld, vif); @@ -134,6 +143,23 @@ int iwl_mld_start_nan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, return ret; } +int iwl_mld_nan_change_config(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct cfg80211_nan_conf *conf, + u32 changes) +{ + struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw); + + IWL_DEBUG_MAC80211(mld, "NAN: change: changes=0x%x, bands=0x%x\n", + changes, conf->bands); + + /* Note that we do not use 'changes' as the FW always expects the + * complete configuration, and mac80211 always provides the complete + * configuration. + */ + return iwl_mld_nan_config(mld, vif, conf, FW_CTXT_ACTION_MODIFY); +} + int iwl_mld_stop_nan(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { diff --git a/drivers/net/wireless/intel/iwlwifi/mld/nan.h b/drivers/net/wireless/intel/iwlwifi/mld/nan.h index 97607b74a177..c9c83d1012f0 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/nan.h +++ b/drivers/net/wireless/intel/iwlwifi/mld/nan.h @@ -10,6 +10,10 @@ bool iwl_mld_nan_supported(struct iwl_mld *mld); int iwl_mld_start_nan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct cfg80211_nan_conf *conf); +int iwl_mld_nan_change_config(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct cfg80211_nan_conf *conf, + u32 changes); int iwl_mld_stop_nan(struct ieee80211_hw *hw, struct ieee80211_vif *vif); void iwl_mld_handle_nan_cluster_notif(struct iwl_mld *mld, -- cgit v1.2.3 From b47b3d0d8be376d0baf83bc14933377216417504 Mon Sep 17 00:00:00 2001 From: Ilan Peer Date: Mon, 10 Nov 2025 18:08:50 +0200 Subject: wifi: iwlwifi: mld: Advertise support for multicast RX registration While this is not needed for configuring Rx filters, without setting it some multicast action frame registrations from user space would fail, specifically, NAN multicast action frame registration (SDFs). Signed-off-by: Ilan Peer Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20251110180612.640fb5a99470.If6f423bcf0a426e662041a4b310ce81485f1af03@changeid --- drivers/net/wireless/intel/iwlwifi/mld/mac80211.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c index 05ab6246eb17..8466345d7f21 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c @@ -377,6 +377,8 @@ static void iwl_mac_hw_set_wiphy(struct iwl_mld *mld) wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_FILS_MAX_CHANNEL_TIME); wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_OCE_PROBE_REQ_HIGH_TX_RATE); wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_MU_MIMO_AIR_SNIFFER); + wiphy_ext_feature_set(wiphy, + NL80211_EXT_FEATURE_MULTICAST_REGISTRATIONS); wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_SPP_AMSDU_SUPPORT); if (fw_has_capa(ucode_capa, IWL_UCODE_TLV_CAPA_PROTECTED_TWT)) -- cgit v1.2.3 From 4bfdbd5d1ea9d6f04975e9ebaf830b75e5fb960b Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Mon, 10 Nov 2025 15:02:12 +0200 Subject: wifi: iwlwifi: mld: decode VHT information for sniffer The available VHT information may be useful, so decode it and include it in the generated radiotap headers. Signed-off-by: Benjamin Berg Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20251110150012.6751d1d0b31d.I927cb0767667f2c03ee41f2ba417f3b94bba6d91@changeid --- drivers/net/wireless/intel/iwlwifi/fw/api/rx.h | 24 ++++- drivers/net/wireless/intel/iwlwifi/mld/rx.c | 132 +++++++++++++++++++++++++ 2 files changed, 155 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h b/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h index 3ed7e0807b90..6d0523497663 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h @@ -1062,7 +1062,29 @@ struct iwl_vht_sigs { #define OFDM_RX_FRAME_VHT_NUM_OF_DATA_SYM 0x000007ff #define OFDM_RX_FRAME_VHT_NUM_OF_DATA_SYM_VALID 0x80000000 __le32 a0; - __le32 a1, a2; +#define OFDM_RX_FRAME_VHT_BANDWIDTH 0x00000003 +#define OFDM_RX_FRAME_VHT_STBC 0x00000008 +#define OFDM_RX_FRAME_VHT_GRP_ID 0x000003f0 +#define OFDM_RX_FRAME_VHT_STS_USER0 0x00001c00 +#define OFDM_RX_FRAME_VHT_MU_STS_USER1 0x0000e000 +#define OFDM_RX_FRAME_VHT_MU_STS_USER2 0x00070000 +#define OFDM_RX_FRAME_VHT_MU_STS_USER3 0x00380000 +#define OFDM_RX_FRAME_VHT_PARTIAL_AID_OR_MU_STS 0x003fe000 +#define OFDM_RX_FRAME_VHT_MU_MIMO_USER_POSITION 0x03000000 +#define OFDM_RX_FRAME_VHT_NO_STREAMS 0x04000000 +#define OFDM_RX_FRAME_VHT_STS 0x38000000 + __le32 a1; +#define OFDM_RX_FRAME_VHT_SHORT_GI 0x00000001 +#define OFDM_RX_FRAME_VHT_SHORT_GI_AMBIG 0x00000002 +#define OFDM_RX_FRAME_VHT_CODING 0x00000004 +#define OFDM_RX_FRAME_VHT_CODING_EXTRA_SYM 0x00000008 +#define OFDM_RX_FRAME_VHT_MCS_OR_MU_CODING 0x000000f0 +#define OFDM_RX_FRAME_VHT_BF_OR_MU_RESERVED 0x00000100 +#define OFDM_RX_FRAME_VHT_CRC 0x0003fc00 +#define OFDM_RX_FRAME_VHT_CRC_OK_BIT 0x00040000 +#define OFDM_RX_FRAME_VHT_CUR_USER_CODING 0x00080000 +#define OFDM_RX_FRAME_VHT_CUR_USER_STS 0x00700000 + __le32 a2; }; struct iwl_he_sigs { diff --git a/drivers/net/wireless/intel/iwlwifi/mld/rx.c b/drivers/net/wireless/intel/iwlwifi/mld/rx.c index 6a76e3fcb581..4386e6b5c37c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/rx.c @@ -207,6 +207,134 @@ static void iwl_mld_fill_signal(struct iwl_mld *mld, int link_id, rx_status->chain_signal[1] = energy_b; } +static void +iwl_mld_decode_vht_phy_data(struct iwl_mld_rx_phy_data *phy_data, + struct ieee80211_radiotap_vht *vht, + struct ieee80211_rx_status *rx_status) +{ + bool stbc; + + vht->known = cpu_to_le16(IEEE80211_RADIOTAP_VHT_KNOWN_BANDWIDTH | + IEEE80211_RADIOTAP_VHT_KNOWN_GROUP_ID | + IEEE80211_RADIOTAP_VHT_KNOWN_STBC | + IEEE80211_RADIOTAP_VHT_KNOWN_GI | + IEEE80211_RADIOTAP_VHT_KNOWN_SGI_NSYM_DIS | + IEEE80211_RADIOTAP_VHT_KNOWN_LDPC_EXTRA_OFDM_SYM | + IEEE80211_RADIOTAP_VHT_KNOWN_BEAMFORMED); + + switch (le32_get_bits(phy_data->ntfy->sigs.vht.a1, + OFDM_RX_FRAME_VHT_BANDWIDTH)) { + case 0: + vht->bandwidth = IEEE80211_RADIOTAP_VHT_BW_20; + break; + case 1: + vht->bandwidth = IEEE80211_RADIOTAP_VHT_BW_40; + break; + case 2: + vht->bandwidth = IEEE80211_RADIOTAP_VHT_BW_80; + break; + case 3: + vht->bandwidth = IEEE80211_RADIOTAP_VHT_BW_160; + break; + } + + vht->group_id = le32_get_bits(phy_data->ntfy->sigs.vht.a1, + OFDM_RX_FRAME_VHT_GRP_ID); + + stbc = le32_get_bits(phy_data->ntfy->sigs.vht.a1, + OFDM_RX_FRAME_VHT_STBC); + if (stbc) + vht->flags |= IEEE80211_RADIOTAP_VHT_FLAG_STBC; + + if (le32_get_bits(phy_data->ntfy->sigs.vht.a2, + OFDM_RX_FRAME_VHT_SHORT_GI)) + vht->flags |= IEEE80211_RADIOTAP_VHT_FLAG_SGI; + + if (le32_get_bits(phy_data->ntfy->sigs.vht.a2, + OFDM_RX_FRAME_VHT_SHORT_GI_AMBIG)) + vht->flags |= IEEE80211_RADIOTAP_VHT_FLAG_SGI_NSYM_M10_9; + + if (le32_get_bits(phy_data->ntfy->sigs.vht.a2, + OFDM_RX_FRAME_VHT_CODING_EXTRA_SYM)) + vht->flags |= IEEE80211_RADIOTAP_VHT_FLAG_LDPC_EXTRA_OFDM_SYM; + + if (vht->group_id != 0 && vht->group_id != 63) { + /* MU frame */ + int user = le32_get_bits(phy_data->ntfy->sigs.vht.a1, + OFDM_RX_FRAME_VHT_MU_MIMO_USER_POSITION); + int nsts; + + /* Always beamformed */ + vht->flags |= IEEE80211_RADIOTAP_VHT_FLAG_BEAMFORMED; + + /* No MCS information in the a1/a2 data for MU frames */ + nsts = le32_get_bits(phy_data->ntfy->sigs.vht.a1, + OFDM_RX_FRAME_VHT_STS_USER0); + vht->mcs_nss[0] = (stbc ? nsts / 2 : nsts) | 0xf0; + + nsts = le32_get_bits(phy_data->ntfy->sigs.vht.a1, + OFDM_RX_FRAME_VHT_MU_STS_USER1); + vht->mcs_nss[1] = (stbc ? nsts / 2 : nsts) | 0xf0; + + nsts = le32_get_bits(phy_data->ntfy->sigs.vht.a1, + OFDM_RX_FRAME_VHT_MU_STS_USER2); + vht->mcs_nss[2] = (stbc ? nsts / 2 : nsts) | 0xf0; + + nsts = le32_get_bits(phy_data->ntfy->sigs.vht.a1, + OFDM_RX_FRAME_VHT_MU_STS_USER3); + vht->mcs_nss[3] = (stbc ? nsts / 2 : nsts) | 0xf0; + + /* Report current user MCS from rate_n_flags via rx_status */ + vht->mcs_nss[user] &= 0x0f; + vht->mcs_nss[user] |= rx_status->rate_idx << 4; + + /* Report LDPC for current user */ + if (rx_status->enc_flags & RX_ENC_FLAG_LDPC) + vht->coding = 0x1 << user; + } else { + int nsts; + + /* SU frame */ + vht->known |= cpu_to_le16(IEEE80211_RADIOTAP_VHT_KNOWN_PARTIAL_AID); + + if (le32_get_bits(phy_data->ntfy->sigs.vht.a2, + OFDM_RX_FRAME_VHT_BF_OR_MU_RESERVED)) + vht->flags |= IEEE80211_RADIOTAP_VHT_FLAG_BEAMFORMED; + + vht->partial_aid = + cpu_to_le16(le32_get_bits(phy_data->ntfy->sigs.vht.a1, + OFDM_RX_FRAME_VHT_PARTIAL_AID_OR_MU_STS)); + + nsts = le32_get_bits(phy_data->ntfy->sigs.vht.a1, + OFDM_RX_FRAME_VHT_STS) + 1; + vht->mcs_nss[0] = + (stbc ? nsts / 2 : nsts) | + le32_get_bits(phy_data->ntfy->sigs.vht.a2, + OFDM_RX_FRAME_VHT_MCS_OR_MU_CODING) << 4; + vht->mcs_nss[1] = 0; + vht->mcs_nss[2] = 0; + vht->mcs_nss[3] = 0; + + if (rx_status->enc_flags & RX_ENC_FLAG_LDPC) + vht->coding = 0x1; + } +} + +static void iwl_mld_rx_vht(struct sk_buff *skb, + struct iwl_mld_rx_phy_data *phy_data) +{ + struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb); + struct ieee80211_radiotap_vht *vht; + + if (likely(!phy_data->ntfy)) + return; + + vht = skb_put_zero(skb, sizeof(*vht)); + rx_status->flag |= RX_FLAG_RADIOTAP_VHT; + + iwl_mld_decode_vht_phy_data(phy_data, vht, rx_status); +} + static void iwl_mld_he_set_ru_alloc(struct ieee80211_rx_status *rx_status, struct ieee80211_radiotap_he *he, @@ -1377,6 +1505,10 @@ static void iwl_mld_rx_fill_status(struct iwl_mld *mld, int link_id, iwl_mld_set_rx_rate(mld, phy_data, rx_status); + /* must be before HE data (radiotap field order) */ + if (format == RATE_MCS_MOD_TYPE_VHT) + iwl_mld_rx_vht(skb, phy_data); + /* must be before L-SIG data (radiotap field order) */ if (format == RATE_MCS_MOD_TYPE_HE) iwl_mld_rx_he(skb, phy_data); -- cgit v1.2.3 From c5ee8b255451611590b10b5df18625f02b3741c7 Mon Sep 17 00:00:00 2001 From: Daniel Gabay Date: Mon, 10 Nov 2025 15:02:13 +0200 Subject: wifi: iwlwifi: mld: Remove wrong channel flags in scan cmd Erroneously, the channel flags in the scan command for 6 GHz scan were mistakenly set using iwl_mld_scan_get_cmd_gen_flags, which actually calculates a different field (the general flags) in the command. However, these flags are not relevant for 6 GHz scan part, except for IWL_SCAN_CHANNEL_FLAG_6G_PSC_NO_FILTER, which is already set correctly. Since the incorrect flags are only applied in the 6 GHz scan part and are ignored by the firmware, this has no adverse effect. Therefore, we can simply remove this helper function call and explicitly clear the flags. Signed-off-by: Daniel Gabay Reviewed-by: Ilan Peer Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20251110150012.a8a931e1abef.I8f7dc66b23198b83083685ef76dec59cfb407f57@changeid --- drivers/net/wireless/intel/iwlwifi/mld/scan.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mld/scan.c b/drivers/net/wireless/intel/iwlwifi/mld/scan.c index fd1022ddc912..16f48087a888 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/scan.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/scan.c @@ -1063,14 +1063,15 @@ static int iwl_mld_scan_cmd_set_6ghz_chan_params(struct iwl_mld *mld, struct iwl_mld_scan_params *params, struct ieee80211_vif *vif, - struct iwl_scan_req_params_v17 *scan_p, - enum iwl_mld_scan_status scan_status) + struct iwl_scan_req_params_v17 *scan_p) { struct iwl_scan_channel_params_v7 *chan_p = &scan_p->channel_params; struct iwl_scan_probe_params_v4 *probe_p = &scan_p->probe_params; - chan_p->flags = iwl_mld_scan_get_cmd_gen_flags(mld, params, vif, - scan_status); + /* Explicitly clear the flags since most of them are not + * relevant for 6 GHz scan. + */ + chan_p->flags = 0; chan_p->count = iwl_mld_scan_cfg_channels_6g(mld, params, params->n_channels, probe_p, chan_p, @@ -1106,8 +1107,7 @@ iwl_mld_scan_cmd_set_chan_params(struct iwl_mld *mld, if (params->scan_6ghz) return iwl_mld_scan_cmd_set_6ghz_chan_params(mld, params, - vif, scan_p, - scan_status); + vif, scan_p); /* relevant only for 2.4 GHz/5 GHz scan */ cp->flags = iwl_mld_scan_cmd_set_chan_flags(mld, params, vif, -- cgit v1.2.3 From 60abc027701dbb0c5d1d3712a5336d5977562071 Mon Sep 17 00:00:00 2001 From: Daniel Gabay Date: Mon, 10 Nov 2025 15:02:14 +0200 Subject: wifi: iwlwifi: mvm: Remove few redundant 6 GHz scan chan params - iwl_mvm_scan_umac_chan_flags_v2() computes channel params flags that are only relevant for 2.4/5 GHz scan, explicitly clear the flags for 6 GHz scan. - n_aps_override[0] and n_aps_override[1] are not relevant for 6 GHz scan, remove them. Signed-off-by: Daniel Gabay Reviewed-by: Ilan Peer Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20251110150012.3b4f8ed30498.I014c098e64118fe3adaf6db07816e7df8ea4f79e@changeid --- drivers/net/wireless/intel/iwlwifi/mvm/scan.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c index b588f1dcf20d..59331f1d144b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c @@ -2568,16 +2568,16 @@ static int iwl_mvm_scan_umac_v14_and_above(struct iwl_mvm *mvm, bitmap_ssid, version); return 0; - } else { - pb->preq = params->preq; } - cp->flags = iwl_mvm_scan_umac_chan_flags_v2(mvm, params, vif); - cp->n_aps_override[0] = IWL_SCAN_ADWELL_N_APS_GO_FRIENDLY; - cp->n_aps_override[1] = IWL_SCAN_ADWELL_N_APS_SOCIAL_CHS; + pb->preq = params->preq; iwl_mvm_umac_scan_fill_6g_chan_list(mvm, params, pb); + /* Explicitly clear the flags since most of them are not + * relevant for 6 GHz scan. + */ + cp->flags = 0; cp->count = iwl_mvm_umac_scan_cfg_channels_v7_6g(mvm, params, params->n_channels, pb, cp, vif->type, -- cgit v1.2.3 From 1e3fb3c4a8e6c581d0f4533dba887fabf53d607d Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Mon, 10 Nov 2025 15:02:15 +0200 Subject: wifi: iwlwifi: mvm: check the validity of noa_len Validate iwl_probe_resp_data_notif::noa_attr::len_low since we are using its value to determine the noa_len, which is later used for the NoA attribute. Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20251110150012.99b663d9b424.I206fd54c990ca9e1160b9b94fa8be44e67bcc1b9@changeid --- drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c index 867807abde66..49ffc4ecee85 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c @@ -1761,6 +1761,20 @@ void iwl_mvm_probe_resp_data_notif(struct iwl_mvm *mvm, mvmvif = iwl_mvm_vif_from_mac80211(vif); + /* + * len_low should be 2 + n*13 (where n is the number of descriptors. + * 13 is the size of a NoA descriptor). We can have either one or two + * descriptors. + */ + if (IWL_FW_CHECK(mvm, notif->noa_active && + notif->noa_attr.len_low != 2 + + sizeof(struct ieee80211_p2p_noa_desc) && + notif->noa_attr.len_low != 2 + + sizeof(struct ieee80211_p2p_noa_desc) * 2, + "Invalid noa_attr.len_low (%d)\n", + notif->noa_attr.len_low)) + return; + new_data = kzalloc(sizeof(*new_data), GFP_KERNEL); if (!new_data) return; -- cgit v1.2.3 From 86a6faaf05a4c852ae5550e0ea86056eb4b83154 Mon Sep 17 00:00:00 2001 From: Pagadala Yesu Anjaneyulu Date: Mon, 10 Nov 2025 15:02:16 +0200 Subject: wifi: iwlwifi: fw: fix documentation reference for ap_type field Fix the documentation comment for the ap_type field in AP_TX_POWER_CONSTRAINTS_CMD to reference the correct enum iwl_6ghz_ap_type. Signed-off-by: Pagadala Yesu Anjaneyulu Reviewed-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20251110150012.d70f56dd24b0.I82956bd93a36c7fa5585f014c197afea0610a076@changeid --- drivers/net/wireless/intel/iwlwifi/fw/api/power.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/power.h b/drivers/net/wireless/intel/iwlwifi/fw/api/power.h index 535864e22626..0cd8a12e0f7c 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/power.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/power.h @@ -766,7 +766,7 @@ enum iwl_6ghz_ap_type { * AP_TX_POWER_CONSTRAINTS_CMD * Used for VLP/LPI/AFC Access Point power constraints for 6GHz channels * @link_id: linkId - * @ap_type: see &enum iwl_ap_type + * @ap_type: see &enum iwl_6ghz_ap_type * @eirp_pwr: 8-bit 2s complement signed integer in the range * -64 dBm to 63 dBm with a 0.5 dB step * default &DEFAULT_TPE_TX_POWER (no maximum limit) -- cgit v1.2.3 From 0b9e07b76537f5b22f980974423778509c38a390 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Mon, 10 Nov 2025 15:02:17 +0200 Subject: wifi: iwlwifi: mld: trigger a dump upon notification if needed The firmware can request us to trigger a dump upon specific notifications. In order for that flow to work, we need to call the firmware debug infra when we get a notification from the firmware. This was missing. Signed-off-by: Emmanuel Grumbach Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20251110150012.d6d7e69c7da6.I40f891ece6f98983e0fd2cd0c6863f8620ca08aa@changeid --- drivers/net/wireless/intel/iwlwifi/mld/notif.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/wireless/intel/iwlwifi/mld/notif.c b/drivers/net/wireless/intel/iwlwifi/mld/notif.c index 555542dc5e37..35356b244c0a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/notif.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/notif.c @@ -540,6 +540,8 @@ static void iwl_mld_rx_notif(struct iwl_mld *mld, struct iwl_rx_cmd_buffer *rxb, struct iwl_rx_packet *pkt) { + union iwl_dbg_tlv_tp_data tp_data = { .fw_pkt = pkt }; + for (int i = 0; i < ARRAY_SIZE(iwl_mld_rx_handlers); i++) { const struct iwl_rx_handler *rx_h = &iwl_mld_rx_handlers[i]; struct iwl_async_handler_entry *entry; @@ -580,6 +582,8 @@ static void iwl_mld_rx_notif(struct iwl_mld *mld, } iwl_notification_wait_notify(&mld->notif_wait, pkt); + iwl_dbg_tlv_time_point(&mld->fwrt, + IWL_FW_INI_TIME_POINT_FW_RSP_OR_NOTIF, &tp_data); } void iwl_mld_rx(struct iwl_op_mode *op_mode, struct napi_struct *napi, -- cgit v1.2.3 From 5f05d20180059f00e17b514c1022963034756cfd Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Mon, 10 Nov 2025 15:02:18 +0200 Subject: wifi: iwlwifi: mld: support TLC command version 6 In version 6, a phy id is added to the tlc command and the sta_id becomes a sta_mask. This change is required for NAN: - in NAN we can have 2 logical stations of the same physical station and with the same channel/band (2 NDIs with the same peer) - hence the sta_mask. - In NAN we can have more than one TLC configuration for a single station (for example if it operates on more than one channel) - so the FW needs to be able to find the right TLC context, based on the phy id. Populate the new version (for now with a single station id only. The other ones will be added later when NAN is implemented). In case the FW has a lower version than that - convert it to the FW version. Note that there is some code duplicantion in the conversions to v5 and to v4, but this is intentional since v5 will be removed as soon as v6 is supported. Reviewed-by: Emmanuel Grumbach Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20251110150012.64220c6b292b.I2f5d195ce2bf9d35398f0f6f2d5faf9e90ae45a4@changeid --- drivers/net/wireless/intel/iwlwifi/fw/api/rs.h | 36 ++++++++++- drivers/net/wireless/intel/iwlwifi/mld/tlc.c | 85 ++++++++++++++++++++++---- 2 files changed, 106 insertions(+), 15 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/rs.h b/drivers/net/wireless/intel/iwlwifi/fw/api/rs.h index 9c464e7aba10..8a998747dd95 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/rs.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/rs.h @@ -205,7 +205,7 @@ struct iwl_tlc_config_cmd_v4 { } __packed; /* TLC_MNG_CONFIG_CMD_API_S_VER_4 */ /** - * struct iwl_tlc_config_cmd - TLC configuration + * struct iwl_tlc_config_cmd_v5 - TLC configuration * @sta_id: station id * @reserved1: reserved * @max_ch_width: max supported channel width from &enum iwl_tlc_mng_cfg_cw @@ -221,7 +221,7 @@ struct iwl_tlc_config_cmd_v4 { * @max_tx_op: max TXOP in uSecs for all AC (BK, BE, VO, VI), * set zero for no limit. */ -struct iwl_tlc_config_cmd { +struct iwl_tlc_config_cmd_v5 { u8 sta_id; u8 reserved1[3]; u8 max_ch_width; @@ -235,6 +235,38 @@ struct iwl_tlc_config_cmd { __le16 max_tx_op; } __packed; /* TLC_MNG_CONFIG_CMD_API_S_VER_5 */ +/** + * struct iwl_tlc_config_cmd - TLC configuration + * @sta_mask: station mask (in NAN we can have multiple logical stations of + * the same peer (with the same TLC configuration)). + * @phy_id: the phy id to used for this TLC configuration + * @max_ch_width: max supported channel width from &enum iwl_tlc_mng_cfg_cw + * @mode: &enum iwl_tlc_mng_cfg_mode + * @chains: bitmask of &enum iwl_tlc_mng_cfg_chains + * @sgi_ch_width_supp: bitmap of SGI support per channel width + * use BIT(&enum iwl_tlc_mng_cfg_cw) + * @flags: bitmask of &enum iwl_tlc_mng_cfg_flags + * @non_ht_rates: bitmap of supported legacy rates + * @ht_rates: bitmap of &enum iwl_tlc_mng_ht_rates, per + * pair (0 - 80mhz width and below, 1 - 160mhz, 2 - 320mhz). + * @max_mpdu_len: max MPDU length, in bytes + * @max_tx_op: max TXOP in uSecs for all AC (BK, BE, VO, VI), + * set zero for no limit. + */ +struct iwl_tlc_config_cmd { + __le32 sta_mask; + __le32 phy_id; + u8 max_ch_width; + u8 mode; + u8 chains; + u8 sgi_ch_width_supp; + __le16 flags; + __le16 non_ht_rates; + __le32 ht_rates[IWL_TLC_NSS_MAX][IWL_TLC_MCS_PER_BW_NUM_V4]; + __le16 max_mpdu_len; + __le16 max_tx_op; +} __packed; /* TLC_MNG_CONFIG_CMD_API_S_VER_6 */ + /** * enum iwl_tlc_update_flags - updated fields * @IWL_TLC_NOTIF_FLAG_RATE: last initial rate update diff --git a/drivers/net/wireless/intel/iwlwifi/mld/tlc.c b/drivers/net/wireless/intel/iwlwifi/mld/tlc.c index 0e172281b0c8..62a54c37a98c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/tlc.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/tlc.c @@ -8,6 +8,7 @@ #include "tlc.h" #include "hcmd.h" #include "sta.h" +#include "phy.h" #include "fw/api/rs.h" #include "fw/api/context.h" @@ -447,11 +448,48 @@ iwl_mld_fill_supp_rates(struct iwl_mld *mld, struct ieee80211_vif *vif, } } -static void iwl_mld_convert_tlc_cmd_to_v4(struct iwl_tlc_config_cmd *cmd, - struct iwl_tlc_config_cmd_v4 *cmd_v4) +static int iwl_mld_convert_tlc_cmd_to_v5(struct iwl_tlc_config_cmd *cmd, + struct iwl_tlc_config_cmd_v5 *cmd_v5) { + if (WARN_ON_ONCE(hweight32(le32_to_cpu(cmd->sta_mask)) != 1)) + return -EINVAL; + + /* Convert sta_mask to sta_id */ + cmd_v5->sta_id = __ffs(le32_to_cpu(cmd->sta_mask)); + + /* Copy all the rest */ + cmd_v5->max_ch_width = cmd->max_ch_width; + cmd_v5->mode = cmd->mode; + cmd_v5->chains = cmd->chains; + cmd_v5->sgi_ch_width_supp = cmd->sgi_ch_width_supp; + cmd_v5->flags = cmd->flags; + cmd_v5->non_ht_rates = cmd->non_ht_rates; + + BUILD_BUG_ON(sizeof(cmd_v5->ht_rates) != sizeof(cmd->ht_rates)); + memcpy(cmd_v5->ht_rates, cmd->ht_rates, sizeof(cmd->ht_rates)); + + cmd_v5->max_mpdu_len = cmd->max_mpdu_len; + cmd_v5->max_tx_op = cmd->max_tx_op; + + return 0; +} + +static int iwl_mld_convert_tlc_cmd_to_v4(struct iwl_tlc_config_cmd *cmd, + struct iwl_tlc_config_cmd_v4 *cmd_v4) +{ + if (WARN_ON_ONCE(hweight32(le32_to_cpu(cmd->sta_mask)) != 1)) + return -EINVAL; + + /* Convert sta_mask to sta_id */ + cmd_v4->sta_id = __ffs(le32_to_cpu(cmd->sta_mask)); + /* Copy everything until ht_rates */ - memcpy(cmd_v4, cmd, offsetof(struct iwl_tlc_config_cmd, ht_rates)); + cmd_v4->max_ch_width = cmd->max_ch_width; + cmd_v4->mode = cmd->mode; + cmd_v4->chains = cmd->chains; + cmd_v4->sgi_ch_width_supp = cmd->sgi_ch_width_supp; + cmd_v4->flags = cmd->flags; + cmd_v4->non_ht_rates = cmd->non_ht_rates; /* Convert ht_rates from __le32 to __le16 */ BUILD_BUG_ON(ARRAY_SIZE(cmd_v4->ht_rates) != ARRAY_SIZE(cmd->ht_rates)); @@ -465,14 +503,17 @@ static void iwl_mld_convert_tlc_cmd_to_v4(struct iwl_tlc_config_cmd *cmd, /* Copy the rest */ cmd_v4->max_mpdu_len = cmd->max_mpdu_len; cmd_v4->max_tx_op = cmd->max_tx_op; + + return 0; } static void iwl_mld_send_tlc_cmd(struct iwl_mld *mld, struct ieee80211_vif *vif, struct ieee80211_link_sta *link_sta, - enum nl80211_band band) + struct ieee80211_bss_conf *link) { struct iwl_mld_sta *mld_sta = iwl_mld_sta_from_mac80211(link_sta->sta); + enum nl80211_band band = link->chanreq.oper.chan->band; struct ieee80211_supported_band *sband = mld->hw->wiphy->bands[band]; const struct ieee80211_sta_he_cap *own_he_cap = ieee80211_get_he_iftype_cap_vif(sband, vif); @@ -492,25 +533,44 @@ static void iwl_mld_send_tlc_cmd(struct iwl_mld *mld, int fw_sta_id = iwl_mld_fw_sta_id_from_link_sta(mld, link_sta); u32 cmd_id = WIDE_ID(DATA_PATH_GROUP, TLC_MNG_CONFIG_CMD); u8 cmd_ver = iwl_fw_lookup_cmd_ver(mld->fw, cmd_id, 0); - struct iwl_tlc_config_cmd_v4 cmd_v4; + struct ieee80211_chanctx_conf *chan_ctx; + struct iwl_tlc_config_cmd_v5 cmd_v5 = {}; + struct iwl_tlc_config_cmd_v4 cmd_v4 = {}; void *cmd_ptr; u8 cmd_size; + u32 phy_id; int ret; if (fw_sta_id < 0) return; - cmd.sta_id = fw_sta_id; + cmd.sta_mask = cpu_to_le32(BIT(fw_sta_id)); + + chan_ctx = rcu_dereference_wiphy(mld->wiphy, link->chanctx_conf); + if (WARN_ON(!chan_ctx)) + return; + + phy_id = iwl_mld_phy_from_mac80211(chan_ctx)->fw_id; + cmd.phy_id = cpu_to_le32(phy_id); iwl_mld_fill_supp_rates(mld, vif, link_sta, sband, own_he_cap, own_eht_cap, &cmd); - if (cmd_ver == 5) { + if (cmd_ver == 6) { cmd_ptr = &cmd; cmd_size = sizeof(cmd); + } else if (cmd_ver == 5) { + /* TODO: remove support once FW moves to version 6 */ + ret = iwl_mld_convert_tlc_cmd_to_v5(&cmd, &cmd_v5); + if (ret) + return; + cmd_ptr = &cmd_v5; + cmd_size = sizeof(cmd_v5); } else if (cmd_ver == 4) { - iwl_mld_convert_tlc_cmd_to_v4(&cmd, &cmd_v4); + ret = iwl_mld_convert_tlc_cmd_to_v4(&cmd, &cmd_v4); + if (ret) + return; cmd_ptr = &cmd_v4; cmd_size = sizeof(cmd_v4); } else { @@ -520,8 +580,9 @@ static void iwl_mld_send_tlc_cmd(struct iwl_mld *mld, } IWL_DEBUG_RATE(mld, - "TLC CONFIG CMD, sta_id=%d, max_ch_width=%d, mode=%d\n", - cmd.sta_id, cmd.max_ch_width, cmd.mode); + "TLC CONFIG CMD, sta_mask=0x%x, max_ch_width=%d, mode=%d, phy_id=%d\n", + le32_to_cpu(cmd.sta_mask), cmd.max_ch_width, cmd.mode, + le32_to_cpu(cmd.phy_id)); /* Send async since this can be called within a RCU-read section */ ret = iwl_mld_send_cmd_with_flags_pdu(mld, cmd_id, CMD_ASYNC, cmd_ptr, @@ -561,7 +622,6 @@ void iwl_mld_config_tlc_link(struct iwl_mld *mld, struct ieee80211_link_sta *link_sta) { struct iwl_mld_sta *mld_sta = iwl_mld_sta_from_mac80211(link_sta->sta); - enum nl80211_band band; if (WARN_ON_ONCE(!link_conf->chanreq.oper.chan)) return; @@ -575,8 +635,7 @@ void iwl_mld_config_tlc_link(struct iwl_mld *mld, ieee80211_sta_recalc_aggregates(link_sta->sta); } - band = link_conf->chanreq.oper.chan->band; - iwl_mld_send_tlc_cmd(mld, vif, link_sta, band); + iwl_mld_send_tlc_cmd(mld, vif, link_sta, link_conf); } void iwl_mld_config_tlc(struct iwl_mld *mld, struct ieee80211_vif *vif, -- cgit v1.2.3 From 58192b9ce09b0f0f86e2036683bd542130b91a98 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 10 Nov 2025 15:02:19 +0200 Subject: wifi: iwlwifi: fix 22000 series SMEM parsing If the firmware were to report three LMACs (which doesn't exist in hardware) then using "fwrt->smem_cfg.lmac[2]" is an overrun of the array. Reject such and use IWL_FW_CHECK instead of WARN_ON in this function. Signed-off-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20251110150012.16e8c2d70c26.Iadfcc1aedf43c5175b3f0757bea5aa232454f1ac@changeid --- drivers/net/wireless/intel/iwlwifi/fw/smem.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/smem.c b/drivers/net/wireless/intel/iwlwifi/fw/smem.c index 90fd69b4860c..344ddde85b18 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/smem.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/smem.c @@ -6,6 +6,7 @@ */ #include "iwl-drv.h" #include "runtime.h" +#include "dbg.h" #include "fw/api/commands.h" static void iwl_parse_shared_mem_22000(struct iwl_fw_runtime *fwrt, @@ -17,7 +18,9 @@ static void iwl_parse_shared_mem_22000(struct iwl_fw_runtime *fwrt, u8 api_ver = iwl_fw_lookup_notif_ver(fwrt->fw, SYSTEM_GROUP, SHARED_MEM_CFG_CMD, 0); - if (WARN_ON(lmac_num > ARRAY_SIZE(mem_cfg->lmac_smem))) + /* Note: notification has 3 entries, but we only expect 2 */ + if (IWL_FW_CHECK(fwrt, lmac_num > ARRAY_SIZE(fwrt->smem_cfg.lmac), + "FW advertises %d LMACs\n", lmac_num)) return; fwrt->smem_cfg.num_lmacs = lmac_num; @@ -26,7 +29,8 @@ static void iwl_parse_shared_mem_22000(struct iwl_fw_runtime *fwrt, fwrt->smem_cfg.rxfifo2_size = le32_to_cpu(mem_cfg->rxfifo2_size); if (api_ver >= 4 && - !WARN_ON_ONCE(iwl_rx_packet_payload_len(pkt) < sizeof(*mem_cfg))) { + !IWL_FW_CHECK(fwrt, iwl_rx_packet_payload_len(pkt) < sizeof(*mem_cfg), + "bad shared mem notification size\n")) { fwrt->smem_cfg.rxfifo2_control_size = le32_to_cpu(mem_cfg->rxfifo2_control_size); } -- cgit v1.2.3 From cc10aa812472535a004b8ff8b6177912169fac0b Mon Sep 17 00:00:00 2001 From: Pagadala Yesu Anjaneyulu Date: Mon, 10 Nov 2025 15:02:20 +0200 Subject: wifi: iwlwifi: mld: refactor AP power type setting Fix unsafe power type mapping for iwl_txpower_constraints_cmd that breaks if enum values change. Replace "power_type - 1" with explicit case handling for each power type. While on it, Add debug logging to show configured power type. Signed-off-by: Pagadala Yesu Anjaneyulu Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20251110150012.f3b15566dac8.I31b900ab161fb627158dc1b3e2fc4ab35d84fddf@changeid --- drivers/net/wireless/intel/iwlwifi/mld/power.c | 37 +++++++++++++++++++++----- 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mld/power.c b/drivers/net/wireless/intel/iwlwifi/mld/power.c index f664b277adf7..c3318e84f4a2 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/power.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/power.c @@ -328,6 +328,33 @@ iwl_mld_tpe_sta_cmd_data(struct iwl_txpower_constraints_cmd *cmd, link->tpe.max_reg_client[0].power[i]); } +static int +iwl_mld_set_ap_power_type(struct iwl_txpower_constraints_cmd *cmd, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link) +{ + if (vif->type == NL80211_IFTYPE_AP) { + cmd->ap_type = cpu_to_le16(IWL_6GHZ_AP_TYPE_VLP); + return 0; + } + + switch (link->power_type) { + case IEEE80211_REG_LPI_AP: + cmd->ap_type = cpu_to_le16(IWL_6GHZ_AP_TYPE_LPI); + break; + case IEEE80211_REG_SP_AP: + cmd->ap_type = cpu_to_le16(IWL_6GHZ_AP_TYPE_SP); + break; + case IEEE80211_REG_VLP_AP: + cmd->ap_type = cpu_to_le16(IWL_6GHZ_AP_TYPE_VLP); + break; + default: + return -EINVAL; + } + + return 0; +} + void iwl_mld_send_ap_tx_power_constraint_cmd(struct iwl_mld *mld, struct ieee80211_vif *vif, @@ -349,15 +376,13 @@ iwl_mld_send_ap_tx_power_constraint_cmd(struct iwl_mld *mld, memset(cmd.psd_pwr, DEFAULT_TPE_TX_POWER, sizeof(cmd.psd_pwr)); memset(cmd.eirp_pwr, DEFAULT_TPE_TX_POWER, sizeof(cmd.eirp_pwr)); - if (vif->type == NL80211_IFTYPE_AP) { - cmd.ap_type = cpu_to_le16(IWL_6GHZ_AP_TYPE_VLP); - } else if (link->power_type == IEEE80211_REG_UNSET_AP) { + if (iwl_mld_set_ap_power_type(&cmd, vif, link)) return; - } else { - cmd.ap_type = cpu_to_le16(link->power_type - 1); + + if (vif->type != NL80211_IFTYPE_AP) iwl_mld_tpe_sta_cmd_data(&cmd, link); - } + IWL_DEBUG_POWER(mld, "AP power type: %d\n", le16_to_cpu(cmd.ap_type)); ret = iwl_mld_send_cmd_pdu(mld, WIDE_ID(PHY_OPS_GROUP, AP_TX_POWER_CONSTRAINTS_CMD), -- cgit v1.2.3 From d9ca724db72880d2f1a1ab2e5bb57e271f8569e5 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 10 Nov 2025 15:02:21 +0200 Subject: wifi: iwlwifi: adjust LINK context NPCA API The link context NPCA API was changed in the firmware, adjust the driver accordingly. Signed-off-by: Johannes Berg Reviewed-by: Emmanuel Grumbach Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20251110150012.93bd7a454eef.I3d2ce1a363b0d8c3809ec8e729b7acf94efca25b@changeid --- .../net/wireless/intel/iwlwifi/fw/api/mac-cfg.h | 29 ++++++++++++++++------ 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h b/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h index 628f39917a6f..f260115abc5a 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h @@ -503,23 +503,37 @@ enum iwl_link_modify_bandwidth { IWL_LINK_MODIFY_BW_320, }; +/** + * enum iwl_npca_flags - NPCA flags + * @IWL_NPCA_FLAG_MAC_HDR_BASED: MAC header based NPCA operation + * permitted in the BSS (MOPLEN) + */ +enum iwl_npca_flags { + IWL_NPCA_FLAG_MAC_HDR_BASED = BIT(0), +}; /* NPCA_FLAG_E */ + /** * struct iwl_npca_params - NPCA parameters (non-primary channel access) * + * @dis_subch_bmap: disabled subchannel bitmap for NPCA * @switch_delay: after switch, delay TX according to destination AP * @switch_back_delay: switch back to control channel before OBSS frame end + * @initial_qsrc: Indicates the value that is used to initialize the + * EDCAF QSRC[AC] variables * @min_dur_threshold: minimum PPDU time to switch to the non-primary - * NPCA channel - * @flags: NPCA flags - bit 0: puncturing allowed, bit 1: new TX allowed + * NPCA channel (usec) + * @flags: NPCA flags, see &enum iwl_npca_flags * @reserved: reserved for alignment purposes */ struct iwl_npca_params { + __le16 dis_subch_bmap; u8 switch_delay; u8 switch_back_delay; - __le16 min_dur_threshold; - __le16 flags; - __le16 reserved; -} __packed; /* NPCA_PARAM_API_S_VER_1 */ + u8 initial_qsrc; + u8 min_dur_threshold; + u8 flags; + u8 reserved; +} __packed; /* NPCA_PARAM_API_S_VER_2 */ /** * struct iwl_link_config_cmd - command structure to configure the LINK context @@ -630,7 +644,8 @@ struct iwl_link_config_cmd { struct iwl_npca_params npca_params; /* since _VER_7 */ struct iwl_ac_qos prio_edca_params; /* since _VER_7 */ __le32 reserved3[4]; -} __packed; /* LINK_CONTEXT_CONFIG_CMD_API_S_VER_1, _VER_2, _VER_3, _VER_4, _VER_5, _VER_6, _VER_7 */ +} __packed; /* LINK_CONTEXT_CONFIG_CMD_API_S_VER_1, _VER_2, _VER_3, _VER_4, + * _VER_5, _VER_6, _VER_7, _VER_8 */ /* Currently FW supports link ids in the range 0-3 and can have * at most two active links for each vif. -- cgit v1.2.3 From ac47aa8bc906e1c42dd8b7caf96c180680bddda5 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 10 Nov 2025 15:02:22 +0200 Subject: wifi: iwlwifi: add UHR TLC mode This is part of the new TLC API for UHR, was just missed in the earlier update. Signed-off-by: Johannes Berg Reviewed-by: Emmanuel Grumbach Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20251110150012.aba5036fcee0.Ifba8e366a3ad794a384ced1ebe39fccfc0ec5198@changeid --- drivers/net/wireless/intel/iwlwifi/fw/api/rs.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/rs.h b/drivers/net/wireless/intel/iwlwifi/fw/api/rs.h index 8a998747dd95..e073e1963742 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/rs.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/rs.h @@ -73,6 +73,7 @@ enum iwl_tlc_mng_cfg_chains { * @IWL_TLC_MNG_MODE_VHT: enable VHT * @IWL_TLC_MNG_MODE_HE: enable HE * @IWL_TLC_MNG_MODE_EHT: enable EHT + * @IWL_TLC_MNG_MODE_UHR: enable UHR */ enum iwl_tlc_mng_cfg_mode { IWL_TLC_MNG_MODE_CCK = 0, @@ -82,6 +83,7 @@ enum iwl_tlc_mng_cfg_mode { IWL_TLC_MNG_MODE_VHT, IWL_TLC_MNG_MODE_HE, IWL_TLC_MNG_MODE_EHT, + IWL_TLC_MNG_MODE_UHR, }; /** -- cgit v1.2.3 From 3b6e7afaf7c35c9840f34dc7550ed95d875741ec Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 10 Nov 2025 15:02:23 +0200 Subject: wifi: iwlwifi: fw: api: add UHR data definitions Add the necessary data definitions for the sniffer-related fields reported for the various UHR frame formats by the firmware/hardware to be able to later add the necessary sniffer code. Signed-off-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20251110150012.358b51dd8cb2.I16178416dd7019cb88a45e55f81eb28510982028@changeid --- drivers/net/wireless/intel/iwlwifi/fw/api/rx.h | 69 ++++++++++++++++++++++++-- 1 file changed, 66 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h b/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h index 6d0523497663..beb20eadf6d6 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h @@ -1269,19 +1269,82 @@ struct iwl_eht_tb_sigs { }; struct iwl_uhr_sigs { - __le32 usig_a1, usig_a1_uhr, usig_a2_uhr, b1, b2; + /* same as EHT above */ + __le32 usig_a1; +#define OFDM_RX_FRAME_UHR_BSS_COLOR2 0x0000003f + __le32 usig_a1_uhr; +#define OFDM_RX_FRAME_UHR_PPDU_TYPE 0x00000003 +#define OFDM_RX_FRAME_UHR_COBF_CSR_DISABLE 0x00000004 +#define OFDM_RX_FRAME_UHR_PUNC_CHANNEL 0x000000f8 +#define OFDM_RX_FRAME_UHR_USIG2_VALIDATE_B8 0x00000100 +#define OFDM_RX_FRAME_UHR_SIG_MCS 0x00000600 +#define OFDM_RX_FRAME_UHR_SIG_SYM_NUM 0x0000f800 +#define OFDM_RX_FRAME_UHR_TRIG_SPATIAL_REUSE_1 0x000f0000 +#define OFDM_RX_FRAME_UHR_TRIG_SPATIAL_REUSE_2 0x00f00000 +#define OFDM_RX_FRAME_UHR_TRIG_USIG2_DISREGARD 0x1f000000 + __le32 usig_a2_uhr; +#define OFDM_RX_FRAME_UHR_SPATIAL_REUSE 0x0000000f +#define OFDM_RX_FRAME_UHR_GI_LTF_TYPE 0x00000030 +#define OFDM_RX_FRAME_UHR_NUM_OF_LTF_SYM 0x000001c0 +#define OFDM_RX_FRAME_UHR_CODING_EXTRA_SYM 0x00000200 +#define OFDM_RX_FRAME_UHR_PE_A_FACTOR 0x00000c00 +#define OFDM_RX_FRAME_UHR_PE_DISAMBIGUITY 0x00001000 +#define OFDM_RX_FRAME_UHR_IM_DISABLE 0x00002000 +#define OFDM_RX_FRAME_UHR_USIG_OVF_DISREGARD 0x0000c000 +#define OFDM_RX_FRAME_UHR_NUM_OF_USERS 0x00070000 +#define OFDM_RX_FRAME_UHR_NSTS 0x00f00000 +#define OFDM_RX_FRAME_UHR_BF 0x01000000 +#define OFDM_RX_FRAME_UHR_USIG_OVF_NDP_DISREGARD 0x06000000 +#define OFDM_RX_FRAME_UHR_COMM_CC1_CRC_OK 0x08000000 +#define OFDM_RX_FRAME_UHR_COMM_CC2_CRC_OK 0x10000000 +#define OFDM_RX_FRAME_UHR_NON_VALID_RU_ALLOC 0x20000000 + __le32 b1; +#define OFDM_RX_FRAME_UHR_MCS 0x000001f0 +#define OFDM_RX_FRAME_UHR_CODING 0x00000200 +#define OFDM_RX_FRAME_UHR_SPATIAL_CONFIG 0x00003c00 +#define OFDM_RX_FRAME_UHR_STA_RU 0x003fc000 +#define OFDM_RX_FRAME_UHR_STA_RU_PS160 0x00400000 +#define OFDM_RX_FRAME_UHR_UEQM 0x00800000 +#define OFDM_RX_FRAME_UHR_2XLDPC 0x01000000 +#define OFDM_RX_FRAME_UHR_UEQM_PATTERN 0x06000000 +#define OFDM_RX_FRAME_UHR_IS_MU_MIMO_USER_FIELD 0x08000000 +#define OFDM_RX_FRAME_UHR_USER_FIELD_CRC_OK 0x40000000 + __le32 b2; +#define OFDM_RX_UHR_NUM_OF_DATA_SYM 0x000007ff +#define OFDM_RX_UHR_PE_DURATION 0x00003800 __le32 sig2; + /* same as EHT above: OFDM_RX_FRAME_EHT_RU_ALLOC_* */ __le32 cmn[6]; +#define OFDM_RX_FRAME_UHR_USER_FIELD_ID 0x000007ff __le32 user_id; }; struct iwl_uhr_tb_sigs { - __le32 usig_a1, usig_a2_uhr, tb_rx0, tb_rx1; + /* same as UHR above */ + __le32 usig_a1, usig_a2_uhr; + /* same as HE above */ + __le32 tb_rx0, tb_rx1; }; struct iwl_uhr_elr_sigs { + /* same as UHR above */ __le32 usig_a1, usig_a2_uhr; - __le32 uhr_sig_elr1, uhr_sig_elr2; +#define OFDM_RX_VECTOR_UHR_ELR_VER_ID 0x00000007 +#define OFDM_RX_VECTOR_UHR_ELR_UPLINK_FLAG 0x00000008 +#define OFDM_RX_VECTOR_UHR_ELR_MCS 0x00000010 +#define OFDM_RX_VECTOR_UHR_ELR_CODING 0x00000020 +#define OFDM_RX_VECTOR_UHR_ELR_LENGTH_IN_SYM 0x00007fc0 +#define OFDM_RX_VECTOR_UHR_ELR_CODING_EXTRA_SYM 0x00008000 +#define OFDM_RX_VECTOR_UHR_ELR_SIG1_CRC_OK 0x00010000 +#define OFDM_RX_VECTOR_UHR_ELR_STA_ID 0x0ffe0000 +#define OFDM_RX_VECTOR_UHR_ELR_DISREGARD 0x70000000 + __le32 uhr_sig_elr1; +#define OFDM_RX_VECTOR_UHR_ELR_MARK_BSS_COLOR 0x0000003f +#define OFDM_RX_VECTOR_UHR_ELR_SIG_ID_INDX 0x00000e00 +#define OFDM_RX_VECTOR_UHR_ELR_STA_RU 0x000ff000 +#define OFDM_RX_VECTOR_UHR_ELR_STA_RU_PS160 0x00100000 +#define OFDM_RX_VECTOR_UHR_ELR_SIG2_CRC_OK 0x00200000 + __le32 uhr_sig_elr2; }; union iwl_sigs { -- cgit v1.2.3 From 772fe513e198b83324b8c0f93a886d6c24667832 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 10 Nov 2025 15:02:24 +0200 Subject: wifi: iwlwifi: mld: fix HE SIG-B MCS/DCM/compression These values should be taken from SIG-A, indicating how SIG-B is encoded. The values taken from SIG-B (the corresponding register) indicate how the data portion (for that user) is encoded. For the SIG-B compression value the correct mask was applied to the wrong value. Signed-off-by: Johannes Berg Reviewed-by: Benjamin Berg Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20251110150012.4d625e05dece.If295eb9382fc681d63b0853261d884cd1a833ba5@changeid --- drivers/net/wireless/intel/iwlwifi/fw/api/rx.h | 2 ++ drivers/net/wireless/intel/iwlwifi/mld/rx.c | 10 +++++----- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h b/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h index beb20eadf6d6..ac6c1ef2cbcd 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h @@ -1090,7 +1090,9 @@ struct iwl_vht_sigs { struct iwl_he_sigs { #define OFDM_RX_FRAME_HE_BEAM_CHANGE 0x00000001 #define OFDM_RX_FRAME_HE_UL_FLAG 0x00000002 +/* SU/ER-SU: MCS, MU: SIG-B MCS */ #define OFDM_RX_FRAME_HE_MCS 0x0000003c +/* SU/ER-SU: DCM, MU: SIG-B DCM */ #define OFDM_RX_FRAME_HE_DCM 0x00000040 #define OFDM_RX_FRAME_HE_BSS_COLOR 0x00001f80 #define OFDM_RX_FRAME_HE_SPATIAL_REUSE 0x0001e000 diff --git a/drivers/net/wireless/intel/iwlwifi/mld/rx.c b/drivers/net/wireless/intel/iwlwifi/mld/rx.c index 4386e6b5c37c..214dcfde2fb4 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/rx.c @@ -396,11 +396,11 @@ iwl_mld_decode_he_mu(struct iwl_mld_rx_phy_data *phy_data, { u32 rate_n_flags = phy_data->rate_n_flags; - he_mu->flags1 |= RTAP_ENC_HE(phy_data->ntfy->sigs.he.b, - OFDM_RX_FRAME_HE_SIGB_DCM, + he_mu->flags1 |= RTAP_ENC_HE(phy_data->ntfy->sigs.he.a1, + OFDM_RX_FRAME_HE_DCM, IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_DCM); - he_mu->flags1 |= RTAP_ENC_HE(phy_data->ntfy->sigs.he.b, - OFDM_RX_FRAME_HE_SIGB_MCS, + he_mu->flags1 |= RTAP_ENC_HE(phy_data->ntfy->sigs.he.a1, + OFDM_RX_FRAME_HE_MCS, IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_MCS); he_mu->flags2 |= RTAP_ENC_HE(phy_data->ntfy->sigs.he.a1, OFDM_RX_FRAME_HE_PRMBL_PUNC_TYPE, @@ -408,7 +408,7 @@ iwl_mld_decode_he_mu(struct iwl_mld_rx_phy_data *phy_data, he_mu->flags2 |= RTAP_ENC_HE(phy_data->ntfy->sigs.he.a2, OFDM_RX_FRAME_HE_MU_NUM_OF_SIGB_SYM_OR_USER_NUM, IEEE80211_RADIOTAP_HE_MU_FLAGS2_SIG_B_SYMS_USERS); - he_mu->flags2 |= RTAP_ENC_HE(phy_data->ntfy->sigs.he.b, + he_mu->flags2 |= RTAP_ENC_HE(phy_data->ntfy->sigs.he.a2, OFDM_RX_FRAME_HE_MU_SIGB_COMP, IEEE80211_RADIOTAP_HE_MU_FLAGS2_SIG_B_COMP); -- cgit v1.2.3 From e4d47493c6be00939eecaf03713789766faf10f7 Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Mon, 10 Nov 2025 15:02:25 +0200 Subject: wifi: iwlwifi: cfg: move the MODULE_FIRMWARE to the per-rf file The MODULE_FIRMWARE are now located in the rf-*.h file and not in the mac (bz.h in our case) files. Move them around for consistency. Reviewed-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20251110150012.9749e9514e8c.Ib6f15663c875cf231e97cb4b37adaf21fa616a77@changeid --- drivers/net/wireless/intel/iwlwifi/cfg/bz.c | 12 ------------ drivers/net/wireless/intel/iwlwifi/cfg/rf-fm.c | 12 ++++++++++++ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/bz.c b/drivers/net/wireless/intel/iwlwifi/cfg/bz.c index d25445bd1e5c..77db8c75e6e2 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/bz.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/bz.c @@ -19,12 +19,6 @@ #define IWL_BZ_SMEM_OFFSET 0x400000 #define IWL_BZ_SMEM_LEN 0xD0000 -#define IWL_BZ_A_FM_B_FW_PRE "iwlwifi-bz-a0-fm-b0" -#define IWL_BZ_A_FM_C_FW_PRE "iwlwifi-bz-a0-fm-c0" -#define IWL_BZ_A_FM4_B_FW_PRE "iwlwifi-bz-a0-fm4-b0" -#define IWL_GL_B_FM_B_FW_PRE "iwlwifi-gl-b0-fm-b0" -#define IWL_GL_C_FM_C_FW_PRE "iwlwifi-gl-c0-fm-c0" - static const struct iwl_family_base_params iwl_bz_base = { .num_of_queues = 512, .max_tfd_queue_size = 65536, @@ -100,9 +94,3 @@ const struct iwl_mac_cfg iwl_gl_mac_cfg = { .xtal_latency = 12000, .low_latency_xtal = true, }; - -IWL_CORE_FW(IWL_BZ_A_FM_B_FW_PRE, IWL_BZ_UCODE_CORE_MAX); -IWL_CORE_FW(IWL_BZ_A_FM_C_FW_PRE, IWL_BZ_UCODE_CORE_MAX); -IWL_CORE_FW(IWL_BZ_A_FM4_B_FW_PRE, IWL_BZ_UCODE_CORE_MAX); -IWL_CORE_FW(IWL_GL_B_FM_B_FW_PRE, IWL_BZ_UCODE_CORE_MAX); -IWL_CORE_FW(IWL_GL_C_FM_C_FW_PRE, IWL_BZ_UCODE_CORE_MAX); diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/rf-fm.c b/drivers/net/wireless/intel/iwlwifi/cfg/rf-fm.c index fd82050e33a3..ad2536f53084 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/rf-fm.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/rf-fm.c @@ -5,6 +5,12 @@ */ #include "iwl-config.h" +#define IWL_BZ_A_FM_B_FW_PRE "iwlwifi-bz-a0-fm-b0" +#define IWL_BZ_A_FM_C_FW_PRE "iwlwifi-bz-a0-fm-c0" +#define IWL_BZ_A_FM4_B_FW_PRE "iwlwifi-bz-a0-fm4-b0" +#define IWL_GL_B_FM_B_FW_PRE "iwlwifi-gl-b0-fm-b0" +#define IWL_GL_C_FM_C_FW_PRE "iwlwifi-gl-c0-fm-c0" + /* NVM versions */ #define IWL_FM_NVM_VERSION 0x0a1d @@ -50,3 +56,9 @@ const char iwl_be201_name[] = "Intel(R) Wi-Fi 7 BE201 320MHz"; const char iwl_be200_name[] = "Intel(R) Wi-Fi 7 BE200 320MHz"; const char iwl_be202_name[] = "Intel(R) Wi-Fi 7 BE202 160MHz"; const char iwl_be401_name[] = "Intel(R) Wi-Fi 7 BE401 320MHz"; + +IWL_CORE_FW(IWL_BZ_A_FM_B_FW_PRE, IWL_BZ_UCODE_CORE_MAX); +IWL_CORE_FW(IWL_BZ_A_FM_C_FW_PRE, IWL_BZ_UCODE_CORE_MAX); +IWL_CORE_FW(IWL_BZ_A_FM4_B_FW_PRE, IWL_BZ_UCODE_CORE_MAX); +IWL_CORE_FW(IWL_GL_B_FM_B_FW_PRE, IWL_BZ_UCODE_CORE_MAX); +IWL_CORE_FW(IWL_GL_C_FM_C_FW_PRE, IWL_BZ_UCODE_CORE_MAX); -- cgit v1.2.3 From 85fad59d21ae958e42993179ad205acbb84945de Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 10 Nov 2025 15:02:26 +0200 Subject: wifi: iwlwifi: fw: api: add HE type for UHR ELR For UHR ELR, the EXT_SU type is reused, so it depends on the modulation. Add a define so the code will be clearer. Signed-off-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20251110150012.3dabe4690805.I93dfb6b41ace7844e462e8649253c20f2712b382@changeid --- drivers/net/wireless/intel/iwlwifi/fw/api/rs.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/rs.h b/drivers/net/wireless/intel/iwlwifi/fw/api/rs.h index e073e1963742..ae6be3ed32f8 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/rs.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/rs.h @@ -740,10 +740,11 @@ enum { #define RATE_MCS_HE_SU_4_LTF 3 #define RATE_MCS_HE_SU_4_LTF_08_GI 4 -/* Bit 24-23: HE type. (0) SU, (1) SU_EXT, (2) MU, (3) trigger based */ +/* Bit 24-23: HE type. (0) SU, (1) HE SU_EXT/UHR ELR, (2) MU, (3) trigger based */ #define RATE_MCS_HE_TYPE_POS 23 #define RATE_MCS_HE_TYPE_SU (0 << RATE_MCS_HE_TYPE_POS) #define RATE_MCS_HE_TYPE_EXT_SU (1 << RATE_MCS_HE_TYPE_POS) +#define RATE_MCS_HE_TYPE_UHR_ELR (1 << RATE_MCS_HE_TYPE_POS) #define RATE_MCS_HE_TYPE_MU (2 << RATE_MCS_HE_TYPE_POS) #define RATE_MCS_HE_TYPE_TRIG (3 << RATE_MCS_HE_TYPE_POS) #define RATE_MCS_HE_TYPE_MSK (3 << RATE_MCS_HE_TYPE_POS) -- cgit v1.2.3 From d0f573f3bf96d6441caf32202644f3b16a3afca3 Mon Sep 17 00:00:00 2001 From: Ally Heev Date: Tue, 11 Nov 2025 13:53:51 +0530 Subject: wifi: iwlwifi: mld: remove unused variable in d3.c remove unused variable `old_keys` Signed-off-by: Ally Heev Link: https://patch.msgid.link/20251111-aheev-remove-unused-var-old-keys-v1-1-988de3a91b1c@gmail.com Signed-off-by: Miri Korenblit --- drivers/net/wireless/intel/iwlwifi/mld/d3.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mld/d3.c b/drivers/net/wireless/intel/iwlwifi/mld/d3.c index dd85be94433c..6595542e95cf 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/d3.c @@ -996,8 +996,6 @@ static void iwl_mld_mlo_rekey(struct iwl_mld *mld, struct iwl_mld_wowlan_status *wowlan_status, struct ieee80211_vif *vif) { - struct iwl_mld_old_mlo_keys *old_keys __free(kfree) = NULL; - IWL_DEBUG_WOWLAN(mld, "Num of MLO Keys: %d\n", wowlan_status->num_mlo_keys); if (!wowlan_status->num_mlo_keys) -- cgit v1.2.3 From d2fcdf36554316cc51f7928b777944738d06e332 Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Sun, 11 Jan 2026 19:39:12 +0200 Subject: wifi: iwlwifi: mld: fix chandef start calculation A link pair in which both links are in 5 GHz can be used for EMLSR only if they are separated enough. To check this condition we calculate the start and the end of the chandefs of both links in the pair and do some checks. But the calculation of the start/end of the chandef is currently done by subtracting/adding half the bandwidth from/to the control channel's center frequency, when it should really be subtracted/added from/to the center frequency of the entire chandef. Fix the wrong calculation. Reviewed-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20260111193638.2138fdb99bd5.I4d2e5957b22482a57b1d6ca444e90fcf73bf2cab@changeid --- drivers/net/wireless/intel/iwlwifi/mld/mlo.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mlo.c b/drivers/net/wireless/intel/iwlwifi/mld/mlo.c index c6b151f26921..1efefc737248 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/mlo.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/mlo.c @@ -844,9 +844,9 @@ iwl_mld_emlsr_pair_state(struct ieee80211_vif *vif, if (c_low->chan->center_freq > c_high->chan->center_freq) swap(c_low, c_high); - c_low_upper_edge = c_low->chan->center_freq + + c_low_upper_edge = c_low->center_freq1 + cfg80211_chandef_get_width(c_low) / 2; - c_high_lower_edge = c_high->chan->center_freq - + c_high_lower_edge = c_high->center_freq1 - cfg80211_chandef_get_width(c_high) / 2; if (a->chandef->chan->band == NL80211_BAND_5GHZ && -- cgit v1.2.3 From 4f042e3bb907fc33c1a42676fbbf15ae679f87e8 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 11 Jan 2026 19:39:13 +0200 Subject: wifi: iwlwifi: cfg: remove iwl_be221_name This is unused, no devices with such a name exist, so remove it. Signed-off-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20260111193638.360ca699c9d6.I26ceddc2916e134ff50ea8550e44935f287b063c@changeid --- drivers/net/wireless/intel/iwlwifi/cfg/rf-pe.c | 1 - drivers/net/wireless/intel/iwlwifi/iwl-config.h | 1 - 2 files changed, 2 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/rf-pe.c b/drivers/net/wireless/intel/iwlwifi/cfg/rf-pe.c index 408b9850bd10..2c29054ce7b8 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/rf-pe.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/rf-pe.c @@ -13,5 +13,4 @@ const char iwl_killer_bn1850i_name[] = const char iwl_bn201_name[] = "Intel(R) Wi-Fi 8 BN201"; const char iwl_bn203_name[] = "Intel(R) Wi-Fi 8 BN203"; -const char iwl_be221_name[] = "Intel(R) Wi-Fi 7 BE221"; const char iwl_be223_name[] = "Intel(R) Wi-Fi 7 BE223"; diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h index 076810ee5d34..45cf2bc68e41 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h @@ -687,7 +687,6 @@ extern const char iwl_killer_bn1850w2_name[]; extern const char iwl_killer_bn1850i_name[]; extern const char iwl_bn201_name[]; extern const char iwl_bn203_name[]; -extern const char iwl_be221_name[]; extern const char iwl_be223_name[]; extern const char iwl_ax221_name[]; #if IS_ENABLED(CONFIG_IWLDVM) -- cgit v1.2.3 From 7a749db26cab2334d5b356ac31e6f1147c7682da Mon Sep 17 00:00:00 2001 From: Nidhish A N Date: Sun, 11 Jan 2026 19:39:14 +0200 Subject: wifi: iwlwifi: mld: Fix primary link selection logic When assigning emlsr.primary with emlsr.selected_primary we are checking if BIT(mld_vif->emlsr.selected_links) are a part of vif->active_links. This is incorrect as emlsr.selected_links is a bitmap of possibly two selected links. Therefore, performing the BIT() operation on it does not yield any meaningful result and almost always leads to incorrect primary link selection. Additionally, we cannot rely on vif->active_links at this stage of the link switch flow because it contains both the removed links and also the newly added links. For example, if we had selected links in the past (0x11) and we now select links because of TTLM/debugfs (0x100), vif->active_links will now be (0x111) and primary link will be 0, while 0 is not even an active link. Thus, we create our own bitmap of final active links. Signed-off-by: Nidhish A N Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20260111193638.38b2e14e3a20.Ie81a88dfff0c5d2becedabab8398702808f6b1bf@changeid --- drivers/net/wireless/intel/iwlwifi/mld/mac80211.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c index 8466345d7f21..411a2d56e5f0 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c @@ -1052,7 +1052,9 @@ int iwl_mld_assign_vif_chanctx(struct ieee80211_hw *hw, { struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw); struct iwl_mld_link *mld_link = iwl_mld_link_from_mac80211(link); - unsigned int n_active = iwl_mld_count_active_links(mld, vif); + struct iwl_mld_link *temp_mld_link; + struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif); + u16 final_active_links = 0; int ret; lockdep_assert_wiphy(mld->wiphy); @@ -1060,10 +1062,7 @@ int iwl_mld_assign_vif_chanctx(struct ieee80211_hw *hw, if (WARN_ON(!mld_link)) return -EINVAL; - /* if the assigned one was not counted yet, count it now */ if (!rcu_access_pointer(mld_link->chan_ctx)) { - n_active++; - /* Track addition of non-BSS link */ if (ieee80211_vif_type_p2p(vif) != NL80211_IFTYPE_STATION) { ret = iwl_mld_emlsr_check_non_bss_block(mld, 1); @@ -1084,17 +1083,25 @@ int iwl_mld_assign_vif_chanctx(struct ieee80211_hw *hw, rcu_assign_pointer(mld_link->chan_ctx, ctx); - if (n_active > 1) { - struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif); + /* We cannot rely on vif->active_links at this stage as it contains + * both the removed links and the newly added links. + * Therefore, we create our own bitmap of the final active links, + * which does not include the removed links. + */ + for_each_mld_vif_valid_link(mld_vif, temp_mld_link) { + if (rcu_access_pointer(temp_mld_link->chan_ctx)) + final_active_links |= BIT(link_id); + } + if (hweight16(final_active_links) > 1) { /* Indicate to mac80211 that EML is enabled */ vif->driver_flags |= IEEE80211_VIF_EML_ACTIVE; mld_vif->emlsr.last_entry_ts = jiffies; - if (vif->active_links & BIT(mld_vif->emlsr.selected_links)) + if (final_active_links == mld_vif->emlsr.selected_links) mld_vif->emlsr.primary = mld_vif->emlsr.selected_primary; else - mld_vif->emlsr.primary = __ffs(vif->active_links); + mld_vif->emlsr.primary = __ffs(final_active_links); iwl_dbg_tlv_time_point(&mld->fwrt, IWL_FW_INI_TIME_ESR_LINK_UP, NULL); -- cgit v1.2.3 From 81a33d0f3c69289c7555c4a40af1ce74e130e30e Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Sun, 11 Jan 2026 19:39:15 +0200 Subject: wifi: iwlwifi: mld: add an helper to update an EMLSR blocker Add an helper function that iterates over all (relevant) interfaces and sets/unsets a given EMLSR blocker. For now use it only for IWL_MLD_EMLSR_BLOCKED_NON_BSS. Reviewed-by: Ilan Peer Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20260111193638.f87b347a5cf0.I6836ba40d21cca49401d1f88e03a37b00dd9f5c2@changeid --- drivers/net/wireless/intel/iwlwifi/mld/mlo.c | 39 ++++++++++++++++++---------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mlo.c b/drivers/net/wireless/intel/iwlwifi/mld/mlo.c index 1efefc737248..87f67ddfced4 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/mlo.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/mlo.c @@ -451,29 +451,49 @@ static void iwl_mld_count_non_bss_links(void *_data, u8 *mac, struct iwl_mld_update_emlsr_block_data { bool block; + enum iwl_mld_emlsr_blocked reason; int result; }; static void -iwl_mld_vif_iter_update_emlsr_non_bss_block(void *_data, u8 *mac, - struct ieee80211_vif *vif) +iwl_mld_vif_iter_update_emlsr_block(void *_data, u8 *mac, + struct ieee80211_vif *vif) { struct iwl_mld_update_emlsr_block_data *data = _data; struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif); int ret; + if (!iwl_mld_vif_has_emlsr_cap(vif)) + return; + if (data->block) { ret = iwl_mld_block_emlsr_sync(mld_vif->mld, vif, - IWL_MLD_EMLSR_BLOCKED_NON_BSS, + data->reason, iwl_mld_get_primary_link(vif)); if (ret) data->result = ret; } else { iwl_mld_unblock_emlsr(mld_vif->mld, vif, - IWL_MLD_EMLSR_BLOCKED_NON_BSS); + data->reason); } } +static int iwl_mld_update_emlsr_block(struct iwl_mld *mld, bool block, + enum iwl_mld_emlsr_blocked reason) +{ + struct iwl_mld_update_emlsr_block_data block_data = { + .block = block, + .reason = reason, + }; + + ieee80211_iterate_active_interfaces_mtx(mld->hw, + IEEE80211_IFACE_ITER_NORMAL, + iwl_mld_vif_iter_update_emlsr_block, + &block_data); + + return block_data.result; +} + int iwl_mld_emlsr_check_non_bss_block(struct iwl_mld *mld, int pending_link_changes) { @@ -481,7 +501,6 @@ int iwl_mld_emlsr_check_non_bss_block(struct iwl_mld *mld, * block EMLSR on the bss vif. Upon deactivation, check if this link * was the last non-station link active, and if so unblock the bss vif */ - struct iwl_mld_update_emlsr_block_data block_data = {}; int count = pending_link_changes; /* No need to count if we are activating a non-BSS link */ @@ -495,14 +514,8 @@ int iwl_mld_emlsr_check_non_bss_block(struct iwl_mld *mld, * We could skip updating it if the block change did not change (and * pending_link_changes is non-zero). */ - block_data.block = !!count; - - ieee80211_iterate_active_interfaces_mtx(mld->hw, - IEEE80211_IFACE_ITER_NORMAL, - iwl_mld_vif_iter_update_emlsr_non_bss_block, - &block_data); - - return block_data.result; + return iwl_mld_update_emlsr_block(mld, !!count, + IWL_MLD_EMLSR_BLOCKED_NON_BSS); } #define EMLSR_SEC_LINK_MIN_PERC 10 -- cgit v1.2.3 From 53d649ae79a760785d7f74ccf9830f3fe0e82380 Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Sun, 11 Jan 2026 19:39:16 +0200 Subject: wifi: iwlwifi: mld: prevent EMLSR when NAN is active EMLSR is not allowed when NAN is active. Block EMLSR when starting NAN, and unblock EMLSR when NAN is stopped. Reviewed-by: Ilan Peer Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20260111193638.8baef343023a.Ie94e5f32db003ebce33bde65e0ed8c6d98673b5a@changeid --- drivers/net/wireless/intel/iwlwifi/mld/iface.h | 2 ++ drivers/net/wireless/intel/iwlwifi/mld/mac80211.c | 3 +++ drivers/net/wireless/intel/iwlwifi/mld/mlo.c | 20 +++++++++++++++++--- drivers/net/wireless/intel/iwlwifi/mld/mlo.h | 5 +++++ drivers/net/wireless/intel/iwlwifi/mld/nan.c | 18 ++++++++++++++++-- 5 files changed, 43 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mld/iface.h b/drivers/net/wireless/intel/iwlwifi/mld/iface.h index a3573d20f214..62fca166afd1 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/iface.h +++ b/drivers/net/wireless/intel/iwlwifi/mld/iface.h @@ -32,6 +32,7 @@ enum iwl_mld_cca_40mhz_wa_status { * link is preventing EMLSR. This is a temporary blocking that is set when * there is an indication that a non-BSS interface is to be added. * @IWL_MLD_EMLSR_BLOCKED_TPT: throughput is too low to make EMLSR worthwhile + * @IWL_MLD_EMLSR_BLOCKED_NAN: NAN is preventing EMLSR. */ enum iwl_mld_emlsr_blocked { IWL_MLD_EMLSR_BLOCKED_PREVENTION = 0x1, @@ -40,6 +41,7 @@ enum iwl_mld_emlsr_blocked { IWL_MLD_EMLSR_BLOCKED_NON_BSS = 0x8, IWL_MLD_EMLSR_BLOCKED_TMP_NON_BSS = 0x10, IWL_MLD_EMLSR_BLOCKED_TPT = 0x20, + IWL_MLD_EMLSR_BLOCKED_NAN = 0x40, }; /** diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c index 411a2d56e5f0..df8221277d51 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c @@ -1784,6 +1784,9 @@ static int iwl_mld_move_sta_state_up(struct iwl_mld *mld, /* Ensure any block due to a non-BSS link is synced */ iwl_mld_emlsr_check_non_bss_block(mld, 0); + /* Ensure NAN block is synced */ + iwl_mld_emlsr_check_nan_block(mld, vif); + /* Block EMLSR until a certain throughput it reached */ if (!mld->fw_status.in_hw_restart && IWL_MLD_ENTER_EMLSR_TPT_THRESH > 0) diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mlo.c b/drivers/net/wireless/intel/iwlwifi/mld/mlo.c index 87f67ddfced4..f842f5183223 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/mlo.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/mlo.c @@ -12,7 +12,8 @@ HOW(ROC) \ HOW(NON_BSS) \ HOW(TMP_NON_BSS) \ - HOW(TPT) + HOW(TPT) \ + HOW(NAN) static const char * iwl_mld_get_emlsr_blocked_string(enum iwl_mld_emlsr_blocked blocked) @@ -478,8 +479,8 @@ iwl_mld_vif_iter_update_emlsr_block(void *_data, u8 *mac, } } -static int iwl_mld_update_emlsr_block(struct iwl_mld *mld, bool block, - enum iwl_mld_emlsr_blocked reason) +int iwl_mld_update_emlsr_block(struct iwl_mld *mld, bool block, + enum iwl_mld_emlsr_blocked reason) { struct iwl_mld_update_emlsr_block_data block_data = { .block = block, @@ -1210,3 +1211,16 @@ void iwl_mld_stop_ignoring_tpt_updates(struct iwl_mld *mld) iwl_mld_ignore_tpt_iter, &start); } + +int iwl_mld_emlsr_check_nan_block(struct iwl_mld *mld, struct ieee80211_vif *vif) +{ + if (mld->nan_device_vif && + ieee80211_vif_nan_started(mld->nan_device_vif)) + return iwl_mld_block_emlsr_sync(mld, vif, + IWL_MLD_EMLSR_BLOCKED_NAN, + iwl_mld_get_primary_link(vif)); + + iwl_mld_unblock_emlsr(mld, vif, IWL_MLD_EMLSR_BLOCKED_NAN); + + return 0; +} diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mlo.h b/drivers/net/wireless/intel/iwlwifi/mld/mlo.h index d936589fe39d..ccc3a7afa095 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/mlo.h +++ b/drivers/net/wireless/intel/iwlwifi/mld/mlo.h @@ -150,6 +150,11 @@ void iwl_mld_emlsr_check_chan_load(struct ieee80211_hw *hw, */ void iwl_mld_retry_emlsr(struct iwl_mld *mld, struct ieee80211_vif *vif); +int iwl_mld_emlsr_check_nan_block(struct iwl_mld *mld, struct ieee80211_vif *vif); + +int iwl_mld_update_emlsr_block(struct iwl_mld *mld, bool block, + enum iwl_mld_emlsr_blocked reason); + struct iwl_mld_link_sel_data { u8 link_id; const struct cfg80211_chan_def *chandef; diff --git a/drivers/net/wireless/intel/iwlwifi/mld/nan.c b/drivers/net/wireless/intel/iwlwifi/mld/nan.c index e7a2c1ec7494..d4298f44baf7 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/nan.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/nan.c @@ -5,6 +5,7 @@ #include "mld.h" #include "iface.h" +#include "mlo.h" #include "fw/api/mac-cfg.h" #define IWL_NAN_DISOVERY_BEACON_INTERNVAL_TU 512 @@ -130,15 +131,25 @@ int iwl_mld_start_nan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, IWL_DEBUG_MAC80211(mld, "NAN: start: bands=0x%x\n", conf->bands); - ret = iwl_mld_add_aux_sta(mld, aux_sta); + ret = iwl_mld_update_emlsr_block(mld, true, IWL_MLD_EMLSR_BLOCKED_NAN); if (ret) return ret; + ret = iwl_mld_add_aux_sta(mld, aux_sta); + if (ret) + goto unblock_emlsr; + ret = iwl_mld_nan_config(mld, vif, conf, FW_CTXT_ACTION_ADD); if (ret) { IWL_ERR(mld, "Failed to start NAN. ret=%d\n", ret); - iwl_mld_remove_aux_sta(mld, vif); + goto remove_aux; } + return 0; + +remove_aux: + iwl_mld_remove_aux_sta(mld, vif); +unblock_emlsr: + iwl_mld_update_emlsr_block(mld, false, IWL_MLD_EMLSR_BLOCKED_NAN); return ret; } @@ -190,6 +201,9 @@ int iwl_mld_stop_nan(struct ieee80211_hw *hw, iwl_mld_cancel_notifications_of_object(mld, IWL_MLD_OBJECT_TYPE_NAN, 0); + + iwl_mld_update_emlsr_block(mld, false, IWL_MLD_EMLSR_BLOCKED_NAN); + return 0; } -- cgit v1.2.3 From 839d9176176da9f5fe4ba7b988c570d3b6174e70 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Sun, 11 Jan 2026 19:39:17 +0200 Subject: wifi: iwlwifi: move lari helper functions to the op_mode iwlmvm is the only op_mode that uses the lari helper functions. iwlmld has its own version to avoid introducing regressions. Move all those functions to iwlmvm, as they are more related to the op_mode. iwl_get_lari_config_bitmap will move in the next patch. Signed-off-by: Emmanuel Grumbach Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20260111193638.4bb241e436cb.I3d80796d4722376ce24a847419d34723083baaa8@changeid --- drivers/net/wireless/intel/iwlwifi/fw/regulatory.c | 151 --------------------- drivers/net/wireless/intel/iwlwifi/fw/regulatory.h | 3 - drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 148 +++++++++++++++++++- 3 files changed, 147 insertions(+), 155 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c index d2ad169ae880..7e7af2b81181 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c @@ -537,157 +537,6 @@ __le32 iwl_get_lari_config_bitmap(struct iwl_fw_runtime *fwrt) } IWL_EXPORT_SYMBOL(iwl_get_lari_config_bitmap); -static size_t iwl_get_lari_config_cmd_size(u8 cmd_ver) -{ - size_t cmd_size; - - switch (cmd_ver) { - case 12: - cmd_size = sizeof(struct iwl_lari_config_change_cmd); - break; - case 8: - cmd_size = sizeof(struct iwl_lari_config_change_cmd_v8); - break; - case 6: - cmd_size = sizeof(struct iwl_lari_config_change_cmd_v6); - break; - default: - cmd_size = sizeof(struct iwl_lari_config_change_cmd_v1); - break; - } - return cmd_size; -} - -int iwl_fill_lari_config(struct iwl_fw_runtime *fwrt, - struct iwl_lari_config_change_cmd *cmd, - size_t *cmd_size) -{ - int ret; - u32 value; - bool has_raw_dsm_capa = fw_has_capa(&fwrt->fw->ucode_capa, - IWL_UCODE_TLV_CAPA_FW_ACCEPTS_RAW_DSM_TABLE); - u8 cmd_ver = iwl_fw_lookup_cmd_ver(fwrt->fw, - WIDE_ID(REGULATORY_AND_NVM_GROUP, - LARI_CONFIG_CHANGE), 1); - - if (WARN_ONCE(cmd_ver > 12, - "Don't add newer versions to this function\n")) - return -EINVAL; - - memset(cmd, 0, sizeof(*cmd)); - *cmd_size = iwl_get_lari_config_cmd_size(cmd_ver); - - cmd->config_bitmap = iwl_get_lari_config_bitmap(fwrt); - - ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_11AX_ENABLEMENT, &value); - if (!ret) { - if (!has_raw_dsm_capa) - value &= DSM_11AX_ALLOW_BITMAP; - cmd->oem_11ax_allow_bitmap = cpu_to_le32(value); - } - - ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ENABLE_UNII4_CHAN, &value); - if (!ret) { - if (!has_raw_dsm_capa) - value &= DSM_UNII4_ALLOW_BITMAP; - - /* Since version 12, bits 4 and 5 are supported - * regardless of this capability, By pass this masking - * if firmware has capability of accepting raw DSM table. - */ - if (!has_raw_dsm_capa && cmd_ver < 12 && - !fw_has_capa(&fwrt->fw->ucode_capa, - IWL_UCODE_TLV_CAPA_BIOS_OVERRIDE_5G9_FOR_CA)) - value &= ~(DSM_VALUE_UNII4_CANADA_OVERRIDE_MSK | - DSM_VALUE_UNII4_CANADA_EN_MSK); - - cmd->oem_unii4_allow_bitmap = cpu_to_le32(value); - } - - ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ACTIVATE_CHANNEL, &value); - if (!ret) { - if (!has_raw_dsm_capa) - value &= CHAN_STATE_ACTIVE_BITMAP_CMD_V12; - - if (!has_raw_dsm_capa && cmd_ver < 8) - value &= ~ACTIVATE_5G2_IN_WW_MASK; - - /* Since version 12, bits 5 and 6 are supported - * regardless of this capability, By pass this masking - * if firmware has capability of accepting raw DSM table. - */ - if (!has_raw_dsm_capa && cmd_ver < 12 && - !fw_has_capa(&fwrt->fw->ucode_capa, - IWL_UCODE_TLV_CAPA_BIOS_OVERRIDE_UNII4_US_CA)) - value &= CHAN_STATE_ACTIVE_BITMAP_CMD_V8; - - cmd->chan_state_active_bitmap = cpu_to_le32(value); - } - - ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ENABLE_6E, &value); - if (!ret) - cmd->oem_uhb_allow_bitmap = cpu_to_le32(value); - - ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_FORCE_DISABLE_CHANNELS, &value); - if (!ret) { - if (!has_raw_dsm_capa) - value &= DSM_FORCE_DISABLE_CHANNELS_ALLOWED_BITMAP; - cmd->force_disable_channels_bitmap = cpu_to_le32(value); - } - - ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ENERGY_DETECTION_THRESHOLD, - &value); - if (!ret) { - if (!has_raw_dsm_capa) - value &= DSM_EDT_ALLOWED_BITMAP; - cmd->edt_bitmap = cpu_to_le32(value); - } - - ret = iwl_bios_get_wbem(fwrt, &value); - if (!ret) - cmd->oem_320mhz_allow_bitmap = cpu_to_le32(value); - - ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ENABLE_11BE, &value); - if (!ret) - cmd->oem_11be_allow_bitmap = cpu_to_le32(value); - - if (cmd->config_bitmap || - cmd->oem_uhb_allow_bitmap || - cmd->oem_11ax_allow_bitmap || - cmd->oem_unii4_allow_bitmap || - cmd->chan_state_active_bitmap || - cmd->force_disable_channels_bitmap || - cmd->edt_bitmap || - cmd->oem_320mhz_allow_bitmap || - cmd->oem_11be_allow_bitmap) { - IWL_DEBUG_RADIO(fwrt, - "sending LARI_CONFIG_CHANGE, config_bitmap=0x%x, oem_11ax_allow_bitmap=0x%x\n", - le32_to_cpu(cmd->config_bitmap), - le32_to_cpu(cmd->oem_11ax_allow_bitmap)); - IWL_DEBUG_RADIO(fwrt, - "sending LARI_CONFIG_CHANGE, oem_unii4_allow_bitmap=0x%x, chan_state_active_bitmap=0x%x, cmd_ver=%d\n", - le32_to_cpu(cmd->oem_unii4_allow_bitmap), - le32_to_cpu(cmd->chan_state_active_bitmap), - cmd_ver); - IWL_DEBUG_RADIO(fwrt, - "sending LARI_CONFIG_CHANGE, oem_uhb_allow_bitmap=0x%x, force_disable_channels_bitmap=0x%x\n", - le32_to_cpu(cmd->oem_uhb_allow_bitmap), - le32_to_cpu(cmd->force_disable_channels_bitmap)); - IWL_DEBUG_RADIO(fwrt, - "sending LARI_CONFIG_CHANGE, edt_bitmap=0x%x, oem_320mhz_allow_bitmap=0x%x\n", - le32_to_cpu(cmd->edt_bitmap), - le32_to_cpu(cmd->oem_320mhz_allow_bitmap)); - IWL_DEBUG_RADIO(fwrt, - "sending LARI_CONFIG_CHANGE, oem_11be_allow_bitmap=0x%x\n", - le32_to_cpu(cmd->oem_11be_allow_bitmap)); - } else { - return 1; - } - - return 0; -} -IWL_EXPORT_SYMBOL(iwl_fill_lari_config); - int iwl_bios_get_dsm(struct iwl_fw_runtime *fwrt, enum iwl_dsm_funcs func, u32 *value) { diff --git a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h index 735482e7adf5..859cb303f813 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h @@ -219,9 +219,6 @@ int iwl_bios_get_eckv(struct iwl_fw_runtime *fwrt, u32 *ext_clk); int iwl_bios_get_wbem(struct iwl_fw_runtime *fwrt, u32 *value); __le32 iwl_get_lari_config_bitmap(struct iwl_fw_runtime *fwrt); -int iwl_fill_lari_config(struct iwl_fw_runtime *fwrt, - struct iwl_lari_config_change_cmd *cmd, - size_t *cmd_size); int iwl_bios_get_dsm(struct iwl_fw_runtime *fwrt, enum iwl_dsm_funcs func, u32 *value); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index edae13755ee6..d04f5d408ec3 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -1165,13 +1165,159 @@ static void iwl_mvm_tas_init(struct iwl_mvm *mvm) IWL_DEBUG_RADIO(mvm, "failed to send TAS_CONFIG (%d)\n", ret); } +static size_t iwl_mvm_get_lari_config_cmd_size(u8 cmd_ver) +{ + size_t cmd_size; + + switch (cmd_ver) { + case 12: + cmd_size = sizeof(struct iwl_lari_config_change_cmd); + break; + case 8: + cmd_size = sizeof(struct iwl_lari_config_change_cmd_v8); + break; + case 6: + cmd_size = sizeof(struct iwl_lari_config_change_cmd_v6); + break; + default: + cmd_size = sizeof(struct iwl_lari_config_change_cmd_v1); + break; + } + return cmd_size; +} + +static int iwl_mvm_fill_lari_config(struct iwl_fw_runtime *fwrt, + struct iwl_lari_config_change_cmd *cmd, + size_t *cmd_size) +{ + int ret; + u32 value; + bool has_raw_dsm_capa = fw_has_capa(&fwrt->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_FW_ACCEPTS_RAW_DSM_TABLE); + u8 cmd_ver = iwl_fw_lookup_cmd_ver(fwrt->fw, + WIDE_ID(REGULATORY_AND_NVM_GROUP, + LARI_CONFIG_CHANGE), 1); + + memset(cmd, 0, sizeof(*cmd)); + *cmd_size = iwl_mvm_get_lari_config_cmd_size(cmd_ver); + + cmd->config_bitmap = iwl_get_lari_config_bitmap(fwrt); + + ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_11AX_ENABLEMENT, &value); + if (!ret) { + if (!has_raw_dsm_capa) + value &= DSM_11AX_ALLOW_BITMAP; + cmd->oem_11ax_allow_bitmap = cpu_to_le32(value); + } + + ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ENABLE_UNII4_CHAN, &value); + if (!ret) { + if (!has_raw_dsm_capa) + value &= DSM_UNII4_ALLOW_BITMAP; + + /* Since version 12, bits 4 and 5 are supported + * regardless of this capability, By pass this masking + * if firmware has capability of accepting raw DSM table. + */ + if (!has_raw_dsm_capa && cmd_ver < 12 && + !fw_has_capa(&fwrt->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_BIOS_OVERRIDE_5G9_FOR_CA)) + value &= ~(DSM_VALUE_UNII4_CANADA_OVERRIDE_MSK | + DSM_VALUE_UNII4_CANADA_EN_MSK); + + cmd->oem_unii4_allow_bitmap = cpu_to_le32(value); + } + + ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ACTIVATE_CHANNEL, &value); + if (!ret) { + if (!has_raw_dsm_capa) + value &= CHAN_STATE_ACTIVE_BITMAP_CMD_V12; + + if (!has_raw_dsm_capa && cmd_ver < 8) + value &= ~ACTIVATE_5G2_IN_WW_MASK; + + /* Since version 12, bits 5 and 6 are supported + * regardless of this capability, By pass this masking + * if firmware has capability of accepting raw DSM table. + */ + if (!has_raw_dsm_capa && cmd_ver < 12 && + !fw_has_capa(&fwrt->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_BIOS_OVERRIDE_UNII4_US_CA)) + value &= CHAN_STATE_ACTIVE_BITMAP_CMD_V8; + + cmd->chan_state_active_bitmap = cpu_to_le32(value); + } + + ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ENABLE_6E, &value); + if (!ret) + cmd->oem_uhb_allow_bitmap = cpu_to_le32(value); + + ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_FORCE_DISABLE_CHANNELS, &value); + if (!ret) { + if (!has_raw_dsm_capa) + value &= DSM_FORCE_DISABLE_CHANNELS_ALLOWED_BITMAP; + cmd->force_disable_channels_bitmap = cpu_to_le32(value); + } + + ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ENERGY_DETECTION_THRESHOLD, + &value); + if (!ret) { + if (!has_raw_dsm_capa) + value &= DSM_EDT_ALLOWED_BITMAP; + cmd->edt_bitmap = cpu_to_le32(value); + } + + ret = iwl_bios_get_wbem(fwrt, &value); + if (!ret) + cmd->oem_320mhz_allow_bitmap = cpu_to_le32(value); + + ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ENABLE_11BE, &value); + if (!ret) + cmd->oem_11be_allow_bitmap = cpu_to_le32(value); + + if (cmd->config_bitmap || + cmd->oem_uhb_allow_bitmap || + cmd->oem_11ax_allow_bitmap || + cmd->oem_unii4_allow_bitmap || + cmd->chan_state_active_bitmap || + cmd->force_disable_channels_bitmap || + cmd->edt_bitmap || + cmd->oem_320mhz_allow_bitmap || + cmd->oem_11be_allow_bitmap) { + IWL_DEBUG_RADIO(fwrt, + "sending LARI_CONFIG_CHANGE, config_bitmap=0x%x, oem_11ax_allow_bitmap=0x%x\n", + le32_to_cpu(cmd->config_bitmap), + le32_to_cpu(cmd->oem_11ax_allow_bitmap)); + IWL_DEBUG_RADIO(fwrt, + "sending LARI_CONFIG_CHANGE, oem_unii4_allow_bitmap=0x%x, chan_state_active_bitmap=0x%x, cmd_ver=%d\n", + le32_to_cpu(cmd->oem_unii4_allow_bitmap), + le32_to_cpu(cmd->chan_state_active_bitmap), + cmd_ver); + IWL_DEBUG_RADIO(fwrt, + "sending LARI_CONFIG_CHANGE, oem_uhb_allow_bitmap=0x%x, force_disable_channels_bitmap=0x%x\n", + le32_to_cpu(cmd->oem_uhb_allow_bitmap), + le32_to_cpu(cmd->force_disable_channels_bitmap)); + IWL_DEBUG_RADIO(fwrt, + "sending LARI_CONFIG_CHANGE, edt_bitmap=0x%x, oem_320mhz_allow_bitmap=0x%x\n", + le32_to_cpu(cmd->edt_bitmap), + le32_to_cpu(cmd->oem_320mhz_allow_bitmap)); + IWL_DEBUG_RADIO(fwrt, + "sending LARI_CONFIG_CHANGE, oem_11be_allow_bitmap=0x%x\n", + le32_to_cpu(cmd->oem_11be_allow_bitmap)); + } else { + return 1; + } + + return 0; +} + static void iwl_mvm_lari_cfg(struct iwl_mvm *mvm) { struct iwl_lari_config_change_cmd cmd; size_t cmd_size; int ret; - ret = iwl_fill_lari_config(&mvm->fwrt, &cmd, &cmd_size); + ret = iwl_mvm_fill_lari_config(&mvm->fwrt, &cmd, &cmd_size); if (!ret) { ret = iwl_mvm_send_cmd_pdu(mvm, WIDE_ID(REGULATORY_AND_NVM_GROUP, -- cgit v1.2.3 From d5b2927a3387e536c560a49b0753f127d823ac8e Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Sun, 11 Jan 2026 19:39:18 +0200 Subject: wifi: iwlwifi: move iwl_get_lari_config_bitmap to the op_mode This is used solely there. The implementation can differe between different op_modes that support different firmware versions Signed-off-by: Emmanuel Grumbach Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20260111193638.099e733b1ece.Icac5b8eb5d8260e35df89622443d68a6beacedbb@changeid --- drivers/net/wireless/intel/iwlwifi/fw/regulatory.c | 49 --------------------- drivers/net/wireless/intel/iwlwifi/fw/regulatory.h | 2 - .../net/wireless/intel/iwlwifi/mld/regulatory.c | 18 +++++++- drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 50 +++++++++++++++++++++- 4 files changed, 66 insertions(+), 53 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c index 7e7af2b81181..00f1c20a5a37 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c @@ -488,55 +488,6 @@ bool iwl_add_mcc_to_tas_block_list(u16 *list, u8 *size, u16 mcc) } IWL_EXPORT_SYMBOL(iwl_add_mcc_to_tas_block_list); -__le32 iwl_get_lari_config_bitmap(struct iwl_fw_runtime *fwrt) -{ - int ret; - u32 val; - __le32 config_bitmap = 0; - - switch (CSR_HW_RFID_TYPE(fwrt->trans->info.hw_rf_id)) { - case IWL_CFG_RF_TYPE_HR1: - case IWL_CFG_RF_TYPE_HR2: - case IWL_CFG_RF_TYPE_JF1: - case IWL_CFG_RF_TYPE_JF2: - ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ENABLE_INDONESIA_5G2, - &val); - - if (!ret && val == DSM_VALUE_INDONESIA_ENABLE) - config_bitmap |= - cpu_to_le32(LARI_CONFIG_ENABLE_5G2_IN_INDONESIA_MSK); - break; - default: - break; - } - - ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_DISABLE_SRD, &val); - if (!ret) { - if (val == DSM_VALUE_SRD_PASSIVE) - config_bitmap |= - cpu_to_le32(LARI_CONFIG_CHANGE_ETSI_TO_PASSIVE_MSK); - else if (val == DSM_VALUE_SRD_DISABLE) - config_bitmap |= - cpu_to_le32(LARI_CONFIG_CHANGE_ETSI_TO_DISABLED_MSK); - } - - if (fw_has_capa(&fwrt->fw->ucode_capa, - IWL_UCODE_TLV_CAPA_CHINA_22_REG_SUPPORT)) { - ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_REGULATORY_CONFIG, - &val); - /* - * China 2022 enable if the BIOS object does not exist or - * if it is enabled in BIOS. - */ - if (ret < 0 || val & DSM_MASK_CHINA_22_REG) - config_bitmap |= - cpu_to_le32(LARI_CONFIG_ENABLE_CHINA_22_REG_SUPPORT_MSK); - } - - return config_bitmap; -} -IWL_EXPORT_SYMBOL(iwl_get_lari_config_bitmap); - int iwl_bios_get_dsm(struct iwl_fw_runtime *fwrt, enum iwl_dsm_funcs func, u32 *value) { diff --git a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h index 859cb303f813..26c1d3fad4df 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h @@ -218,8 +218,6 @@ int iwl_bios_get_mcc(struct iwl_fw_runtime *fwrt, char *mcc); int iwl_bios_get_eckv(struct iwl_fw_runtime *fwrt, u32 *ext_clk); int iwl_bios_get_wbem(struct iwl_fw_runtime *fwrt, u32 *value); -__le32 iwl_get_lari_config_bitmap(struct iwl_fw_runtime *fwrt); - int iwl_bios_get_dsm(struct iwl_fw_runtime *fwrt, enum iwl_dsm_funcs func, u32 *value); diff --git a/drivers/net/wireless/intel/iwlwifi/mld/regulatory.c b/drivers/net/wireless/intel/iwlwifi/mld/regulatory.c index 40571125b3ab..92e6c0535501 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/regulatory.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/regulatory.c @@ -206,11 +206,27 @@ int iwl_mld_init_ppag(struct iwl_mld *mld) return iwl_mld_ppag_send_cmd(mld); } +static __le32 iwl_mld_get_lari_config_bitmap(struct iwl_fw_runtime *fwrt) +{ + int ret; + u32 val; + + ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_DISABLE_SRD, &val); + if (!ret) { + if (val == DSM_VALUE_SRD_PASSIVE) + return cpu_to_le32(LARI_CONFIG_CHANGE_ETSI_TO_PASSIVE_MSK); + else if (val == DSM_VALUE_SRD_DISABLE) + return cpu_to_le32(LARI_CONFIG_CHANGE_ETSI_TO_DISABLED_MSK); + } + + return 0; +} + void iwl_mld_configure_lari(struct iwl_mld *mld) { struct iwl_fw_runtime *fwrt = &mld->fwrt; struct iwl_lari_config_change_cmd cmd = { - .config_bitmap = iwl_get_lari_config_bitmap(fwrt), + .config_bitmap = iwl_mld_get_lari_config_bitmap(fwrt), }; bool has_raw_dsm_capa = fw_has_capa(&fwrt->fw->ucode_capa, IWL_UCODE_TLV_CAPA_FW_ACCEPTS_RAW_DSM_TABLE); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index d04f5d408ec3..018f3396e955 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -1165,6 +1165,54 @@ static void iwl_mvm_tas_init(struct iwl_mvm *mvm) IWL_DEBUG_RADIO(mvm, "failed to send TAS_CONFIG (%d)\n", ret); } +static __le32 iwl_mvm_get_lari_config_bitmap(struct iwl_fw_runtime *fwrt) +{ + int ret; + u32 val; + __le32 config_bitmap = 0; + + switch (CSR_HW_RFID_TYPE(fwrt->trans->info.hw_rf_id)) { + case IWL_CFG_RF_TYPE_HR1: + case IWL_CFG_RF_TYPE_HR2: + case IWL_CFG_RF_TYPE_JF1: + case IWL_CFG_RF_TYPE_JF2: + ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ENABLE_INDONESIA_5G2, + &val); + + if (!ret && val == DSM_VALUE_INDONESIA_ENABLE) + config_bitmap |= + cpu_to_le32(LARI_CONFIG_ENABLE_5G2_IN_INDONESIA_MSK); + break; + default: + break; + } + + ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_DISABLE_SRD, &val); + if (!ret) { + if (val == DSM_VALUE_SRD_PASSIVE) + config_bitmap |= + cpu_to_le32(LARI_CONFIG_CHANGE_ETSI_TO_PASSIVE_MSK); + else if (val == DSM_VALUE_SRD_DISABLE) + config_bitmap |= + cpu_to_le32(LARI_CONFIG_CHANGE_ETSI_TO_DISABLED_MSK); + } + + if (fw_has_capa(&fwrt->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_CHINA_22_REG_SUPPORT)) { + ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_REGULATORY_CONFIG, + &val); + /* + * China 2022 enable if the BIOS object does not exist or + * if it is enabled in BIOS. + */ + if (ret < 0 || val & DSM_MASK_CHINA_22_REG) + config_bitmap |= + cpu_to_le32(LARI_CONFIG_ENABLE_CHINA_22_REG_SUPPORT_MSK); + } + + return config_bitmap; +} + static size_t iwl_mvm_get_lari_config_cmd_size(u8 cmd_ver) { size_t cmd_size; @@ -1201,7 +1249,7 @@ static int iwl_mvm_fill_lari_config(struct iwl_fw_runtime *fwrt, memset(cmd, 0, sizeof(*cmd)); *cmd_size = iwl_mvm_get_lari_config_cmd_size(cmd_ver); - cmd->config_bitmap = iwl_get_lari_config_bitmap(fwrt); + cmd->config_bitmap = iwl_mvm_get_lari_config_bitmap(fwrt); ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_11AX_ENABLEMENT, &value); if (!ret) { -- cgit v1.2.3 From b9d19dd12c1ba318e3449487e430a3859421d740 Mon Sep 17 00:00:00 2001 From: Nidhish A N Date: Sun, 11 Jan 2026 19:39:19 +0200 Subject: wifi: iwlwifi: mvm: Cleanup MLO code iwlmld is now the op mode that is used for EHT devices, so iwlmvm code can never run in MLO. Cleanup some of the MLO code. Signed-off-by: Nidhish A N Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20260111193638.214157366bc7.I324778c008058c5d894328aab8e473304f657b69@changeid --- drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 51 ++---- drivers/net/wireless/intel/iwlwifi/mvm/link.c | 22 --- drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c | 11 -- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 59 +------ drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c | 6 +- drivers/net/wireless/intel/iwlwifi/mvm/mld-mac.c | 29 ---- .../net/wireless/intel/iwlwifi/mvm/mld-mac80211.c | 193 ++------------------- drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c | 28 +-- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 57 ------ drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 8 - drivers/net/wireless/intel/iwlwifi/mvm/scan.c | 8 +- drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 51 +----- drivers/net/wireless/intel/iwlwifi/mvm/utils.c | 4 - 13 files changed, 39 insertions(+), 488 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index 07f1a84c274e..2375fc76039f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -726,8 +726,7 @@ static int iwl_mvm_d3_reprogram(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct iwl_time_quota_data *quota; u32 status; - if (WARN_ON_ONCE(iwl_mvm_is_cdb_supported(mvm) || - ieee80211_vif_is_mld(vif))) + if (WARN_ON_ONCE(iwl_mvm_is_cdb_supported(mvm))) return -EINVAL; /* add back the PHY */ @@ -1248,7 +1247,6 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, struct ieee80211_vif *vif = NULL; struct iwl_mvm_vif *mvmvif = NULL; struct ieee80211_sta *ap_sta = NULL; - struct iwl_mvm_vif_link_info *mvm_link; struct iwl_d3_manager_config d3_cfg_cmd = { /* * Program the minimum sleep time to 10 seconds, as many @@ -1280,13 +1278,7 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, mvmvif = iwl_mvm_vif_from_mac80211(vif); - mvm_link = mvmvif->link[iwl_mvm_get_primary_link(vif)]; - if (WARN_ON_ONCE(!mvm_link)) { - ret = -EINVAL; - goto out_noreset; - } - - if (mvm_link->ap_sta_id == IWL_INVALID_STA) { + if (mvmvif->deflink.ap_sta_id == IWL_INVALID_STA) { /* if we're not associated, this must be netdetect */ if (!wowlan->nd_config) { ret = 1; @@ -1304,10 +1296,10 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, .offloading_tid = 0, }; - wowlan_config_cmd.sta_id = mvm_link->ap_sta_id; + wowlan_config_cmd.sta_id = mvmvif->deflink.ap_sta_id; ap_sta = rcu_dereference_protected( - mvm->fw_id_to_mac_id[mvm_link->ap_sta_id], + mvm->fw_id_to_mac_id[mvmvif->deflink.ap_sta_id], lockdep_is_held(&mvm->mutex)); if (IS_ERR_OR_NULL(ap_sta)) { ret = -EINVAL; @@ -1324,7 +1316,8 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, if (ret) goto out_noreset; ret = iwl_mvm_wowlan_config(mvm, wowlan, &wowlan_config_cmd, - vif, mvmvif, mvm_link, ap_sta); + vif, mvmvif, &mvmvif->deflink, + ap_sta); if (ret) goto out; @@ -1819,10 +1812,6 @@ static void iwl_mvm_d3_update_keys(struct ieee80211_hw *hw, struct iwl_mvm_d3_gtk_iter_data *data = _data; struct iwl_wowlan_status_data *status = data->status; s8 keyidx; - int link_id = vif->active_links ? __ffs(vif->active_links) : -1; - - if (link_id >= 0 && key->link_id >= 0 && link_id != key->link_id) - return; switch (key->cipher) { case WLAN_CIPHER_SUITE_WEP40: @@ -1876,7 +1865,6 @@ static bool iwl_mvm_gtk_rekey(struct iwl_wowlan_status_data *status, { int i, j; struct ieee80211_key_conf *key; - int link_id = vif->active_links ? __ffs(vif->active_links) : -1; for (i = 0; i < ARRAY_SIZE(status->gtk); i++) { if (!status->gtk[i].len) @@ -1888,8 +1876,7 @@ static bool iwl_mvm_gtk_rekey(struct iwl_wowlan_status_data *status, key = ieee80211_gtk_rekey_add(vif, status->gtk[i].id, status->gtk[i].key, - sizeof(status->gtk[i].key), - link_id); + sizeof(status->gtk[i].key), -1); if (IS_ERR(key)) { /* FW may send also the old keys */ if (PTR_ERR(key) == -EALREADY) @@ -1918,14 +1905,13 @@ iwl_mvm_d3_igtk_bigtk_rekey_add(struct iwl_wowlan_status_data *status, struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct ieee80211_key_conf *key_config; struct ieee80211_key_seq seq; - int link_id = vif->active_links ? __ffs(vif->active_links) : -1; s8 keyidx = key_data->id; if (!key_data->len) return true; key_config = ieee80211_gtk_rekey_add(vif, keyidx, key_data->key, - sizeof(key_data->key), link_id); + sizeof(key_data->key), -1); if (IS_ERR(key_config)) { /* FW may send also the old keys */ return PTR_ERR(key_config) == -EALREADY; @@ -1935,13 +1921,9 @@ iwl_mvm_d3_igtk_bigtk_rekey_add(struct iwl_wowlan_status_data *status, ieee80211_set_key_rx_seq(key_config, 0, &seq); if (keyidx == 4 || keyidx == 5) { - struct iwl_mvm_vif_link_info *mvm_link; - - link_id = link_id < 0 ? 0 : link_id; - mvm_link = mvmvif->link[link_id]; - if (mvm_link->igtk) - mvm_link->igtk->hw_key_idx = STA_KEY_IDX_INVALID; - mvm_link->igtk = key_config; + if (mvmvif->deflink.igtk) + mvmvif->deflink.igtk->hw_key_idx = STA_KEY_IDX_INVALID; + mvmvif->deflink.igtk = key_config; } if (vif->type == NL80211_IFTYPE_STATION && (keyidx == 6 || keyidx == 7)) @@ -2396,23 +2378,19 @@ static bool iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm, bool keep = false; struct iwl_mvm_sta *mvm_ap_sta; struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - int link_id = vif->active_links ? __ffs(vif->active_links) : 0; - struct iwl_mvm_vif_link_info *mvm_link = mvmvif->link[link_id]; int wowlan_info_ver = iwl_fw_lookup_notif_ver(mvm->fw, PROT_OFFLOAD_GROUP, WOWLAN_INFO_NOTIFICATION, IWL_FW_CMD_VER_UNKNOWN); - if (WARN_ON(!mvm_link)) - goto out_unlock; - if (!status) goto out_unlock; IWL_DEBUG_WOWLAN(mvm, "wakeup reason 0x%x\n", status->wakeup_reasons); - mvm_ap_sta = iwl_mvm_sta_from_staid_protected(mvm, mvm_link->ap_sta_id); + mvm_ap_sta = iwl_mvm_sta_from_staid_protected(mvm, + mvmvif->deflink.ap_sta_id); if (!mvm_ap_sta) goto out_unlock; @@ -2756,9 +2734,6 @@ iwl_mvm_choose_query_wakeup_reasons(struct iwl_mvm *mvm, u8 sta_id = mvm->net_detect ? IWL_INVALID_STA : mvmvif->deflink.ap_sta_id; - /* bug - FW with MLO has status notification */ - WARN_ON(ieee80211_vif_is_mld(vif)); - d3_data->status = iwl_mvm_send_wowlan_get_status(mvm, sta_id); } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/link.c b/drivers/net/wireless/intel/iwlwifi/mvm/link.c index 738facceb240..b5d252ece2d9 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/link.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/link.c @@ -285,28 +285,6 @@ int iwl_mvm_disable_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif, return ret; } -u8 iwl_mvm_get_primary_link(struct ieee80211_vif *vif) -{ - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - - /* relevant data is written with both locks held, so read with either */ - lockdep_assert(lockdep_is_held(&mvmvif->mvm->mutex) || - lockdep_is_held(&mvmvif->mvm->hw->wiphy->mtx)); - - if (!ieee80211_vif_is_mld(vif)) - return 0; - - /* In AP mode, there is no primary link */ - if (vif->type == NL80211_IFTYPE_AP) - return __ffs(vif->active_links); - - if (mvmvif->esr_active && - !WARN_ON(!(BIT(mvmvif->primary_link) & vif->active_links))) - return mvmvif->primary_link; - - return __ffs(vif->active_links); -} - void iwl_mvm_init_link(struct iwl_mvm_vif_link_info *link) { link->bcast_sta.sta_id = IWL_INVALID_STA; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c index 49ffc4ecee85..0e5820c13523 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c @@ -873,7 +873,6 @@ u8 iwl_mvm_mac_ctxt_get_lowest_rate(struct iwl_mvm *mvm, struct ieee80211_tx_info *info, struct ieee80211_vif *vif) { - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct ieee80211_supported_band *sband; unsigned long basic = vif->bss_conf.basic_rates; u16 lowest_cck = IWL_RATE_COUNT, lowest_ofdm = IWL_RATE_COUNT; @@ -883,16 +882,6 @@ u8 iwl_mvm_mac_ctxt_get_lowest_rate(struct iwl_mvm *mvm, u8 rate; u32 i; - 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; - /* shouldn't do this when >1 link is active */ - WARN_ON_ONCE(link_id != IEEE80211_LINK_UNSPECIFIED); - link_id = i; - } - } - if (link_id < IEEE80211_LINK_UNSPECIFIED) { struct ieee80211_bss_conf *link_conf; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 44029ceb8f77..a9022ae4504f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -1109,7 +1109,6 @@ static void iwl_mvm_cleanup_iterator(void *data, u8 *mac, mvmvif->ba_enabled = false; mvmvif->ap_sta = NULL; - mvmvif->esr_active = false; vif->driver_flags &= ~IEEE80211_VIF_EML_ACTIVE; for_each_mvm_vif_valid_link(mvmvif, link_id) { @@ -1129,39 +1128,6 @@ static void iwl_mvm_cleanup_iterator(void *data, u8 *mac, RCU_INIT_POINTER(mvmvif->deflink.probe_resp_data, NULL); } -static void iwl_mvm_cleanup_sta_iterator(void *data, struct ieee80211_sta *sta) -{ - struct iwl_mvm *mvm = data; - struct iwl_mvm_sta *mvm_sta; - struct ieee80211_vif *vif; - int link_id; - - mvm_sta = iwl_mvm_sta_from_mac80211(sta); - vif = mvm_sta->vif; - - if (!sta->valid_links) - return; - - for (link_id = 0; link_id < ARRAY_SIZE((sta)->link); link_id++) { - struct iwl_mvm_link_sta *mvm_link_sta; - - mvm_link_sta = - rcu_dereference_check(mvm_sta->link[link_id], - lockdep_is_held(&mvm->mutex)); - if (mvm_link_sta && !(vif->active_links & BIT(link_id))) { - /* - * We have a link STA but the link is inactive in - * mac80211. This will happen if we failed to - * deactivate the link but mac80211 roll back the - * deactivation of the link. - * Delete the stale data to avoid issues later on. - */ - iwl_mvm_mld_free_sta_link(mvm, mvm_sta, mvm_link_sta, - link_id); - } - } -} - static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm) { iwl_mvm_stop_device(mvm); @@ -1184,10 +1150,6 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm) */ ieee80211_iterate_interfaces(mvm->hw, 0, iwl_mvm_cleanup_iterator, mvm); - /* cleanup stations as links may be gone after restart */ - ieee80211_iterate_stations_atomic(mvm->hw, - iwl_mvm_cleanup_sta_iterator, mvm); - mvm->p2p_device_vif = NULL; iwl_mvm_reset_phy_ctxts(mvm); @@ -3921,12 +3883,6 @@ iwl_mvm_sta_state_assoc_to_authorized(struct iwl_mvm *mvm, mvmvif->authorized = 1; - if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) { - mvmvif->link_selection_res = vif->active_links; - mvmvif->link_selection_primary = - vif->active_links ? __ffs(vif->active_links) : 0; - } - callbacks->mac_ctxt_changed(mvm, vif, false); iwl_mvm_mei_host_associated(mvm, vif, mvm_sta); } @@ -3972,7 +3928,6 @@ iwl_mvm_sta_state_authorized_to_assoc(struct iwl_mvm *mvm, * time. */ mvmvif->authorized = 0; - mvmvif->link_selection_res = 0; /* disable beacon filtering */ iwl_mvm_disable_beacon_filter(mvm, vif); @@ -5568,8 +5523,7 @@ static int iwl_mvm_pre_channel_switch(struct iwl_mvm *mvm, if (!vif->cfg.assoc || !vif->bss_conf.dtim_period) return -EBUSY; - if (chsw->delay > IWL_MAX_CSA_BLOCK_TX && - hweight16(vif->valid_links) <= 1) + if (chsw->delay > IWL_MAX_CSA_BLOCK_TX) schedule_delayed_work(&mvmvif->csa_work, 0); if (chsw->block_tx) { @@ -5733,15 +5687,8 @@ void iwl_mvm_mac_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, return; } - if (!drop && hweight16(vif->active_links) <= 1) { - int link_id = vif->active_links ? __ffs(vif->active_links) : 0; - struct ieee80211_bss_conf *link_conf; - - link_conf = wiphy_dereference(hw->wiphy, - vif->link_conf[link_id]); - if (WARN_ON(!link_conf)) - return; - if (link_conf->csa_active && mvmvif->csa_blocks_tx) + if (!drop) { + if (vif->bss_conf.csa_active && mvmvif->csa_blocks_tx) drop = true; } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c index ef0be44207e1..9bb253dcf4a7 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 - 2024 Intel Corporation + * Copyright (C) 2022 - 2025 Intel Corporation */ #include #include @@ -43,11 +43,11 @@ static u32 iwl_mvm_get_sec_sta_mask(struct iwl_mvm *mvm, * group keys have no sta pointer), so we don't have a STA now. * Since this happens for group keys only, just use the link_info as * the group keys are per link; make sure that is the case by checking - * we do have a link_id or are not doing MLO. + * we do have a link_id. * 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 || !ieee80211_vif_is_mld(vif))) + if (!sta && keyconf->link_id >= 0) return BIT(link_info->ap_sta_id); /* STA should be non-NULL now, but iwl_mvm_sta_fw_id_mask() checks */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac.c index 2d116a41913c..bf54b90a7c51 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac.c @@ -56,23 +56,6 @@ static void iwl_mvm_mld_mac_ctxt_cmd_common(struct iwl_mvm *mvm, if (iwlwifi_mod_params.disable_11ax) return; - /* If we have MLO enabled, then the firmware needs to enable - * address translation for the station(s) we add. That depends - * on having EHT enabled in firmware, which in turn depends on - * mac80211 in the code below. - * However, mac80211 doesn't enable HE/EHT until it has parsed - * the association response successfully, so just skip all that - * and enable both when we have MLO. - */ - if (ieee80211_vif_is_mld(vif)) { - iwl_mvm_mld_set_he_support(mvm, vif, cmd, cmd_ver); - if (cmd_ver == 2) - cmd->wifi_gen_v2.eht_support = cpu_to_le32(1); - else - cmd->wifi_gen.eht_support = 1; - return; - } - rcu_read_lock(); for (link_id = 0; link_id < ARRAY_SIZE((vif)->link_conf); link_id++) { link_conf = rcu_dereference(vif->link_conf[link_id]); @@ -116,7 +99,6 @@ 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); @@ -154,17 +136,6 @@ static int iwl_mvm_mld_mac_ctxt_cmd_sta(struct iwl_mvm *mvm, } 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); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c index 380b6f8a53fd..5829a8b45a89 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c @@ -60,19 +60,12 @@ static int iwl_mvm_mld_mac_add_interface(struct ieee80211_hw *hw, IEEE80211_VIF_SUPPORTS_CQM_RSSI; } - /* We want link[0] to point to the default link, unless we have MLO and - * in this case this will be modified later by .change_vif_links() - * If we are in the restart flow with an MLD connection, we will wait - * to .change_vif_links() to setup the links. - */ - if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) || - !ieee80211_vif_is_mld(vif)) { - mvmvif->link[0] = &mvmvif->deflink; + /* We want link[0] to point to the default link. */ + mvmvif->link[0] = &mvmvif->deflink; - ret = iwl_mvm_add_link(mvm, vif, &vif->bss_conf); - if (ret) - goto out_free_bf; - } + ret = iwl_mvm_add_link(mvm, vif, &vif->bss_conf); + if (ret) + goto out_free_bf; /* Save a pointer to p2p device vif, so it can later be used to * update the p2p device MAC when a GO is started/stopped @@ -181,58 +174,6 @@ static void iwl_mvm_mld_mac_remove_interface(struct ieee80211_hw *hw, } } -static unsigned int iwl_mvm_mld_count_active_links(struct iwl_mvm_vif *mvmvif) -{ - unsigned int n_active = 0; - int i; - - for (i = 0; i < IEEE80211_MLD_MAX_NUM_LINKS; i++) { - if (mvmvif->link[i] && mvmvif->link[i]->phy_ctxt) - 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; - - /* Indicate to mac80211 that EML is enabled */ - vif->driver_flags |= IEEE80211_VIF_EML_ACTIVE; - - 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; - } - - if (vif->active_links == mvmvif->link_selection_res && - !WARN_ON(!(vif->active_links & BIT(mvmvif->link_selection_primary)))) - mvmvif->primary_link = mvmvif->link_selection_primary; - else - mvmvif->primary_link = __ffs(vif->active_links); - - iwl_dbg_tlv_time_point(&mvm->fwrt, IWL_FW_INI_TIME_ESR_LINK_UP, - NULL); - - return ret; -} - static int __iwl_mvm_mld_assign_vif_chanctx(struct iwl_mvm *mvm, struct ieee80211_vif *vif, @@ -243,17 +184,12 @@ __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]; struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - unsigned int n_active = iwl_mvm_mld_count_active_links(mvmvif); unsigned int link_id = link_conf->link_id; int ret; if (WARN_ON_ONCE(!mvmvif->link[link_id])) return -EINVAL; - /* if the assigned one was not counted yet, count it now */ - if (!mvmvif->link[link_id]->phy_ctxt) - n_active++; - /* mac parameters such as HE support can change at this stage * For sta, need first to configure correct state from drv_sta_state * and only after that update mac config. @@ -268,15 +204,6 @@ __iwl_mvm_mld_assign_vif_chanctx(struct iwl_mvm *mvm, mvmvif->link[link_id]->phy_ctxt = phy_ctxt; - 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); - goto out; - } - } - if (switching_chanctx) { /* reactivate if we turned this off during channel switch */ if (vif->type == NL80211_IFTYPE_AP) @@ -341,55 +268,6 @@ static int iwl_mvm_mld_assign_vif_chanctx(struct ieee80211_hw *hw, return __iwl_mvm_mld_assign_vif_chanctx(mvm, vif, link_conf, ctx, false); } -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_EML_ACTIVE; - - 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; - } - - iwl_dbg_tlv_time_point(&mvm->fwrt, IWL_FW_INI_TIME_ESR_LINK_DOWN, - NULL); - - return ret; -} - static void __iwl_mvm_mld_unassign_vif_chanctx(struct iwl_mvm *mvm, struct ieee80211_vif *vif, @@ -399,7 +277,6 @@ __iwl_mvm_mld_unassign_vif_chanctx(struct iwl_mvm *mvm, { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - unsigned int n_active = iwl_mvm_mld_count_active_links(mvmvif); unsigned int link_id = link_conf->link_id; /* shouldn't happen, but verify link_id is valid before accessing */ @@ -421,14 +298,6 @@ __iwl_mvm_mld_unassign_vif_chanctx(struct iwl_mvm *mvm, iwl_mvm_link_changed(mvm, vif, link_conf, LINK_CONTEXT_MODIFY_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); @@ -448,9 +317,8 @@ static void iwl_mvm_mld_unassign_vif_chanctx(struct ieee80211_hw *hw, mutex_lock(&mvm->mutex); __iwl_mvm_mld_unassign_vif_chanctx(mvm, vif, link_conf, ctx, false); - /* in the non-MLD case, remove/re-add the link to clean up FW state */ - if (!ieee80211_vif_is_mld(vif) && !mvmvif->ap_sta && - !WARN_ON_ONCE(vif->cfg.assoc)) { + /* Remove/re-add the link to clean up FW state */ + if (!mvmvif->ap_sta && !WARN_ON_ONCE(vif->cfg.assoc)) { iwl_mvm_remove_link(mvm, vif, link_conf); iwl_mvm_add_link(mvm, vif, link_conf); } @@ -785,12 +653,6 @@ static void iwl_mvm_mld_vif_cfg_changed_station(struct iwl_mvm *mvm, if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) && protect) { - /* We are in assoc so only one link is active- - * The association link - */ - unsigned int link_id = - ffs(vif->active_links) - 1; - /* If we're not restarting and still haven't * heard a beacon (dtim period unknown) then * make sure we still have enough minimum time @@ -800,7 +662,7 @@ static void iwl_mvm_mld_vif_cfg_changed_station(struct iwl_mvm *mvm, * time could be small without us having heard * a beacon yet. */ - iwl_mvm_protect_assoc(mvm, vif, 0, link_id); + iwl_mvm_protect_assoc(mvm, vif, 0, -1); } iwl_mvm_sf_update(mvm, vif, false); @@ -1096,14 +958,6 @@ iwl_mvm_mld_change_vif_links(struct ieee80211_hw *hw, if (new_links == 0) { mvmvif->link[0] = &mvmvif->deflink; err = iwl_mvm_add_link(mvm, vif, &vif->bss_conf); - if (err == 0) - mvmvif->primary_link = 0; - } else if (!(new_links & BIT(mvmvif->primary_link))) { - /* - * Ensure we always have a valid primary_link, the real - * decision happens later when PHY is activated. - */ - mvmvif->primary_link = __ffs(new_links); } out_err: @@ -1128,44 +982,17 @@ iwl_mvm_mld_change_sta_links(struct ieee80211_hw *hw, return iwl_mvm_mld_update_sta_links(mvm, vif, sta, old_links, new_links); } -bool iwl_mvm_vif_has_esr_cap(struct iwl_mvm *mvm, struct ieee80211_vif *vif) -{ - const struct wiphy_iftype_ext_capab *ext_capa; - - lockdep_assert_held(&mvm->mutex); - - if (!ieee80211_vif_is_mld(vif) || !vif->cfg.assoc || - hweight16(ieee80211_vif_usable_links(vif)) == 1) - return false; - - if (!(vif->cfg.eml_cap & IEEE80211_EML_CAP_EMLSR_SUPP)) - return false; - - ext_capa = cfg80211_get_iftype_ext_capa(mvm->hw->wiphy, - ieee80211_vif_type_p2p(vif)); - return (ext_capa && - (ext_capa->eml_capabilities & IEEE80211_EML_CAP_EMLSR_SUPP)); -} - static bool iwl_mvm_mld_can_activate_links(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 desired_links) { - struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); int n_links = hweight16(desired_links); if (n_links <= 1) return true; - guard(mvm)(mvm); - - /* Check if HW supports the wanted number of links */ - if (n_links > iwl_mvm_max_active_links(mvm, vif)) - return false; - - /* If it is an eSR device, check that we can enter eSR */ - return iwl_mvm_is_esr_supported(mvm->fwrt.trans) && - iwl_mvm_vif_has_esr_cap(mvm, vif); + WARN_ON(1); + return false; } static enum ieee80211_neg_ttlm_res diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c index d9a2801636cf..1100d763ceb6 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c @@ -9,40 +9,14 @@ u32 iwl_mvm_sta_fw_id_mask(struct iwl_mvm *mvm, struct ieee80211_sta *sta, int filter_link_id) { - struct ieee80211_link_sta *link_sta; struct iwl_mvm_sta *mvmsta; - struct ieee80211_vif *vif; - unsigned int link_id; - u32 result = 0; if (!sta) return 0; mvmsta = iwl_mvm_sta_from_mac80211(sta); - vif = mvmsta->vif; - - /* it's easy when the STA is not an MLD */ - if (!sta->valid_links) - return BIT(mvmsta->deflink.sta_id); - - /* but if it is an MLD, get the mask of all the FW STAs it has ... */ - for_each_sta_active_link(vif, sta, link_sta, link_id) { - struct iwl_mvm_link_sta *mvm_link_sta; - - /* unless we have a specific link in mind */ - if (filter_link_id >= 0 && link_id != filter_link_id) - continue; - - mvm_link_sta = - rcu_dereference_check(mvmsta->link[link_id], - lockdep_is_held(&mvm->mutex)); - if (!mvm_link_sta) - continue; - - result |= BIT(mvm_link_sta->sta_id); - } - return result; + return BIT(mvmsta->deflink.sta_id); } static int iwl_mvm_mld_send_sta_cmd(struct iwl_mvm *mvm, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 301d590fe0bd..f3685292b834 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -380,14 +380,7 @@ struct iwl_mvm_vif_link_info { * @bcn_prot: beacon protection data (keys; FIXME: needs to be per link) * @deflink: default link data for use in non-MLO * @link: link data for each link in MLO - * @esr_active: indicates eSR mode is active * @pm_enabled: indicates powersave is enabled - * @link_selection_res: bitmap of active links as it was decided in the last - * link selection. Valid only for a MLO vif after assoc. 0 if there wasn't - * any link selection yet. - * @link_selection_primary: primary link selected by link selection - * @primary_link: primary link in eSR. Valid only for an associated MLD vif, - * and in eSR mode. Valid only for a STA. * @roc_activity: currently running ROC activity for this vif (or * ROC_NUM_ACTIVITIES if no activity is running). * @session_prot_connection_loss: the connection was lost due to session @@ -434,7 +427,6 @@ struct iwl_mvm_vif { bool ap_ibss_active; bool pm_enabled; bool monitor_active; - bool esr_active; bool session_prot_connection_loss; u8 low_latency: 6; @@ -515,10 +507,6 @@ struct iwl_mvm_vif { u16 max_tx_op; - u16 link_selection_res; - u8 link_selection_primary; - u8 primary_link; - struct iwl_mvm_vif_link_info deflink; struct iwl_mvm_vif_link_info *link[IEEE80211_MLD_MAX_NUM_LINKS]; }; @@ -1619,40 +1607,6 @@ static inline bool iwl_mvm_is_ctdp_supported(struct iwl_mvm *mvm) IWL_UCODE_TLV_CAPA_CTDP_SUPPORT); } -static inline bool iwl_mvm_is_esr_supported(struct iwl_trans *trans) -{ - if (CSR_HW_RFID_IS_CDB(trans->info.hw_rf_id)) - return false; - - switch (CSR_HW_RFID_TYPE(trans->info.hw_rf_id)) { - case IWL_CFG_RF_TYPE_FM: - /* Step A doesn't support eSR */ - return CSR_HW_RFID_STEP(trans->info.hw_rf_id); - case IWL_CFG_RF_TYPE_WH: - case IWL_CFG_RF_TYPE_PE: - return true; - default: - return false; - } -} - -static inline int iwl_mvm_max_active_links(struct iwl_mvm *mvm, - struct ieee80211_vif *vif) -{ - struct iwl_trans *trans = mvm->fwrt.trans; - - if (vif->type == NL80211_IFTYPE_AP) - return mvm->fw->ucode_capa.num_beacons; - - /* Check if HW supports eSR or STR */ - if (iwl_mvm_is_esr_supported(trans) || - (CSR_HW_RFID_TYPE(trans->info.hw_rf_id) == IWL_CFG_RF_TYPE_FM && - CSR_HW_RFID_IS_CDB(trans->info.hw_rf_id))) - return IWL_FW_MAX_ACTIVE_LINKS_NUM; - - return 1; -} - extern const u8 iwl_mvm_ac_to_tx_fifo[]; extern const u8 iwl_mvm_ac_to_gen2_tx_fifo[]; extern const u8 iwl_mvm_ac_to_bz_tx_fifo[]; @@ -2008,15 +1962,6 @@ int iwl_mvm_remove_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif, int iwl_mvm_disable_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct ieee80211_bss_conf *link_conf); -u8 iwl_mvm_get_primary_link(struct ieee80211_vif *vif); - -struct iwl_mvm_link_sel_data { - u8 link_id; - const struct cfg80211_chan_def *chandef; - s32 signal; - u16 grade; -}; - #if IS_ENABLED(CONFIG_IWLWIFI_KUNIT_TESTS) extern const struct iwl_hcmd_arr iwl_mvm_groups[]; extern const unsigned int iwl_mvm_groups_size; @@ -2884,8 +2829,6 @@ int iwl_mvm_roc_add_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif, int duration, enum iwl_roc_activity activity); -/* EMLSR */ -bool iwl_mvm_vif_has_esr_cap(struct iwl_mvm *mvm, struct ieee80211_vif *vif); void iwl_mvm_send_ap_tx_power_constraint_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index d35c63a673b6..7f0b4f5daa21 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -2254,17 +2254,9 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, IWL_RX_MPDU_STATUS_STA_ID); if (!WARN_ON_ONCE(sta_id >= mvm->fw->ucode_capa.num_stations)) { - struct ieee80211_link_sta *link_sta; - sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]); if (IS_ERR(sta)) sta = NULL; - link_sta = rcu_dereference(mvm->fw_id_to_link_sta[sta_id]); - - if (sta && sta->valid_links && link_sta) { - rx_status->link_valid = 1; - rx_status->link_id = link_sta->link_id; - } } } else if (!is_multicast_ether_addr(hdr->addr2)) { /* diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c index 59331f1d144b..9c51953d255d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c @@ -3023,12 +3023,8 @@ static int _iwl_mvm_single_scan_start(struct iwl_mvm *mvm, params.iter_notif = true; params.tsf_report_link_id = req->tsf_report_link_id; - if (params.tsf_report_link_id < 0) { - if (vif->active_links) - params.tsf_report_link_id = __ffs(vif->active_links); - else - params.tsf_report_link_id = 0; - } + if (params.tsf_report_link_id < 0) + params.tsf_report_link_id = 0; iwl_mvm_build_scan_probe(mvm, vif, ies, ¶ms); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index bb97837baeda..bca13417e82c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -817,28 +817,15 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb) NL80211_IFTYPE_P2P_DEVICE || info.control.vif->type == NL80211_IFTYPE_AP || info.control.vif->type == NL80211_IFTYPE_ADHOC) { - u32 link_id = u32_get_bits(info.control.flags, - IEEE80211_TX_CTRL_MLO_LINK); - struct iwl_mvm_vif_link_info *link; - - if (link_id == IEEE80211_LINK_UNSPECIFIED) { - if (info.control.vif->active_links) - link_id = ffs(info.control.vif->active_links) - 1; - else - link_id = 0; - } - - 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; + sta_id = mvmvif->deflink.bcast_sta.sta_id; else - sta_id = link->mcast_sta.sta_id; + sta_id = mvmvif->deflink.mcast_sta.sta_id; - queue = iwl_mvm_get_ctrl_vif_queue(mvm, link, &info, - skb); + queue = iwl_mvm_get_ctrl_vif_queue(mvm, + &mvmvif->deflink, + &info, skb); } else if (info.control.vif->type == NL80211_IFTYPE_MONITOR) { queue = mvm->snif_queue; sta_id = mvm->snif_sta.sta_id; @@ -895,33 +882,9 @@ unsigned int iwl_mvm_max_amsdu_size(struct iwl_mvm *mvm, */ val = mvmsta->max_amsdu_len; - if (hweight16(sta->valid_links) <= 1) { - if (sta->valid_links) { - struct ieee80211_bss_conf *link_conf; - unsigned int link = ffs(sta->valid_links) - 1; + band = mvmsta->vif->bss_conf.chanreq.oper.chan->band; - rcu_read_lock(); - link_conf = rcu_dereference(mvmsta->vif->link_conf[link]); - if (WARN_ON(!link_conf)) - band = NL80211_BAND_2GHZ; - else - band = link_conf->chanreq.oper.chan->band; - rcu_read_unlock(); - } else { - band = mvmsta->vif->bss_conf.chanreq.oper.chan->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 */ - lmac = IWL_LMAC_5G_INDEX; - val = min_t(unsigned int, val, - mvm->fwrt.smem_cfg.lmac[lmac].txfifo_size[txf] - 256); - lmac = IWL_LMAC_24G_INDEX; - } else { - lmac = IWL_LMAC_24G_INDEX; - } + lmac = iwl_mvm_get_lmac_id(mvm, band); return min_t(unsigned int, val, mvm->fwrt.smem_cfg.lmac[lmac].txfifo_size[txf] - 256); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c index 1a6c1f8706e1..4a33a032c2a7 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c @@ -308,10 +308,6 @@ 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); } -- cgit v1.2.3 From af60fe4b1236d7f355afc52a57b9b0b7a42792ac Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Sun, 11 Jan 2026 19:39:20 +0200 Subject: wifi: iwlwifi: acpi: cache the DSM functions Instead of reading the DSM functions on demand, just read them all when the first DSM function is called and cache the values for all the other DSM functions. This simplifies the flow. Since the same will be done for UEFI in the next patch, remove the ifdef CONFIG_ACPI around the relevant variables. Once UEFI's cache will be implemented, we'll be able to change iwl_bios_get_dsm to access the cache directly. Signed-off-by: Emmanuel Grumbach Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20260111193638.732ff6856796.Iff844bfbb0fea3c3d9654a53254a5b14dbaec8c1@changeid --- drivers/net/wireless/intel/iwlwifi/fw/acpi.c | 112 ++++++++++++++++-------- drivers/net/wireless/intel/iwlwifi/fw/runtime.h | 11 ++- 2 files changed, 84 insertions(+), 39 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c index 52edc19d8cdd..3899dc3915bf 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c @@ -156,61 +156,101 @@ out: } /* - * This function receives a DSM function number, calculates its expected size - * according to Intel BIOS spec, and fills in the value in a 32-bit field. + * This function loads all the DSM functions, it checks the size and populates + * the cache with the values in a 32-bit field. * In case the expected size is smaller than 32-bit, padding will be added. */ -int iwl_acpi_get_dsm(struct iwl_fw_runtime *fwrt, - enum iwl_dsm_funcs func, u32 *value) +static int iwl_acpi_load_dsm_values(struct iwl_fw_runtime *fwrt) { - size_t expected_size; - u64 tmp; + u64 query_func_val; int ret; BUILD_BUG_ON(ARRAY_SIZE(acpi_dsm_size) != DSM_FUNC_NUM_FUNCS); - if (WARN_ON(func >= ARRAY_SIZE(acpi_dsm_size) || !func)) - return -EINVAL; + ret = iwl_acpi_get_dsm_integer(fwrt->dev, ACPI_DSM_REV, + DSM_FUNC_QUERY, + &iwl_guid, &query_func_val, + acpi_dsm_size[DSM_FUNC_QUERY]); - expected_size = acpi_dsm_size[func]; + if (ret) { + IWL_DEBUG_RADIO(fwrt, "ACPI QUERY FUNC not valid: %d\n", ret); + return ret; + } - /* Currently all ACPI DSMs are either 8-bit or 32-bit */ - if (expected_size != sizeof(u8) && expected_size != sizeof(u32)) - return -EOPNOTSUPP; + IWL_DEBUG_RADIO(fwrt, "ACPI DSM validity bitmap 0x%x\n", + (u32)query_func_val); - if (!fwrt->acpi_dsm_funcs_valid) { - ret = iwl_acpi_get_dsm_integer(fwrt->dev, ACPI_DSM_REV, - DSM_FUNC_QUERY, - &iwl_guid, &tmp, - acpi_dsm_size[DSM_FUNC_QUERY]); - if (ret) { - /* always indicate BIT(0) to avoid re-reading */ - fwrt->acpi_dsm_funcs_valid = BIT(0); - return ret; + /* DSM_FUNC_QUERY is 0, start from 1 */ + for (int func = 1; func < ARRAY_SIZE(fwrt->dsm_values); func++) { + size_t expected_size = acpi_dsm_size[func]; + u64 tmp; + + if (!(query_func_val & BIT(func))) { + IWL_DEBUG_RADIO(fwrt, + "ACPI DSM %d not indicated as valid\n", + func); + continue; } - IWL_DEBUG_RADIO(fwrt, "ACPI DSM validity bitmap 0x%x\n", - (u32)tmp); - /* always indicate BIT(0) to avoid re-reading */ - fwrt->acpi_dsm_funcs_valid = tmp | BIT(0); + /* This is an invalid function (5 for example) */ + if (!expected_size) + continue; + + /* Currently all ACPI DSMs are either 8-bit or 32-bit */ + if (expected_size != sizeof(u8) && expected_size != sizeof(u32)) + continue; + + ret = iwl_acpi_get_dsm_integer(fwrt->dev, ACPI_DSM_REV, func, + &iwl_guid, &tmp, expected_size); + if (ret) + continue; + + if ((expected_size == sizeof(u8) && tmp != (u8)tmp) || + (expected_size == sizeof(u32) && tmp != (u32)tmp)) + IWL_DEBUG_RADIO(fwrt, + "DSM value overflows the expected size, truncating\n"); + fwrt->dsm_values[func] = (u32)tmp; + fwrt->dsm_funcs_valid |= BIT(func); } - if (!(fwrt->acpi_dsm_funcs_valid & BIT(func))) { + return 0; +} + +/* + * This function receives a DSM function number, calculates its expected size + * according to Intel BIOS spec, and fills in the value in a 32-bit field. + * In case the expected size is smaller than 32-bit, padding will be added. + */ +int iwl_acpi_get_dsm(struct iwl_fw_runtime *fwrt, + enum iwl_dsm_funcs func, u32 *value) +{ + if (!fwrt->dsm_funcs_valid) { + int ret = iwl_acpi_load_dsm_values(fwrt); + + /* + * Always set the valid bit for DSM_FUNC_QUERY so that even if + * DSM_FUNC_QUERY returns 0 (no DSM function is valid), we will + * still consider the cache as valid. + */ + fwrt->dsm_funcs_valid |= BIT(DSM_FUNC_QUERY); + + if (ret) + return ret; + } + + BUILD_BUG_ON(ARRAY_SIZE(fwrt->dsm_values) != DSM_FUNC_NUM_FUNCS); + BUILD_BUG_ON(BITS_PER_TYPE(fwrt->dsm_funcs_valid) < DSM_FUNC_NUM_FUNCS); + + if (WARN_ON(func >= ARRAY_SIZE(fwrt->dsm_values) || !func)) + return -EINVAL; + + if (!(fwrt->dsm_funcs_valid & BIT(func))) { IWL_DEBUG_RADIO(fwrt, "ACPI DSM %d not indicated as valid\n", func); return -ENODATA; } - ret = iwl_acpi_get_dsm_integer(fwrt->dev, ACPI_DSM_REV, func, - &iwl_guid, &tmp, expected_size); - if (ret) - return ret; - - if ((expected_size == sizeof(u8) && tmp != (u8)tmp) || - (expected_size == sizeof(u32) && tmp != (u32)tmp)) - IWL_DEBUG_RADIO(fwrt, - "DSM value overflows the expected size, truncating\n"); - *value = (u32)tmp; + *value = fwrt->dsm_values[func]; return 0; } diff --git a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h index 57570ff15622..b9e5f8ea8f94 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h @@ -116,10 +116,14 @@ struct iwl_txf_iter_data { * @phy_filters: specific phy filters as read from WPFC BIOS table * @ppag_bios_rev: PPAG BIOS revision * @ppag_bios_source: see &enum bios_source - * @acpi_dsm_funcs_valid: bitmap indicating which DSM values are valid, + * @dsm_funcs_valid: bitmap indicating which DSM values are valid, * zero (default initialization) means it hasn't been read yet, * and BIT(0) is set when it has since function 0 also has this - * bitmap and is always supported + * bitmap and is always supported. + * If the bit is set for a specific function, then the corresponding + * entry in &dsm_values is valid. + * @dsm_values: cache of the DSM values. The validity of each entry is + * determined by &dsm_funcs_valid. * @geo_enabled: WGDS table is present * @geo_num_profiles: number of geo profiles * @geo_rev: geo profiles table revision @@ -213,7 +217,8 @@ struct iwl_fw_runtime { struct iwl_phy_specific_cfg phy_filters; #ifdef CONFIG_ACPI - u32 acpi_dsm_funcs_valid; + u32 dsm_funcs_valid; + u32 dsm_values[DSM_FUNC_NUM_FUNCS]; #endif }; -- cgit v1.2.3 From 4172db83b0af647c75431e2ceb56ef46d5c8c6d9 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Sun, 11 Jan 2026 19:39:21 +0200 Subject: wifi: iwlwifi: uefi: cache the DSM functions Just like we did for ACPI, cache the UEFI values to avoid reading the tables over and over again. Signed-off-by: Emmanuel Grumbach Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20260111193638.15871db3cfab.Ib39db197646cc303d60bb12448794d20f6ccbd15@changeid --- drivers/net/wireless/intel/iwlwifi/fw/runtime.h | 2 +- drivers/net/wireless/intel/iwlwifi/fw/uefi.c | 65 +++++++++++++++++++------ 2 files changed, 51 insertions(+), 16 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h index b9e5f8ea8f94..a655bca75301 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h @@ -216,7 +216,7 @@ struct iwl_fw_runtime { u8 uefi_tables_lock_status; struct iwl_phy_specific_cfg phy_filters; -#ifdef CONFIG_ACPI +#if defined(CONFIG_ACPI) || defined(CONFIG_EFI) u32 dsm_funcs_valid; u32 dsm_values[DSM_FUNC_NUM_FUNCS]; #endif diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c index 4ae4d215e633..acccb22a833c 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c @@ -721,17 +721,12 @@ out: return ret; } -int iwl_uefi_get_dsm(struct iwl_fw_runtime *fwrt, enum iwl_dsm_funcs func, - u32 *value) +static int iwl_uefi_load_dsm_values(struct iwl_fw_runtime *fwrt) { struct uefi_cnv_var_general_cfg *data; int ret = -EINVAL; - BUILD_BUG_ON(ARRAY_SIZE(data->functions) < DSM_FUNC_NUM_FUNCS); - - /* Not supported function index */ - if (func >= DSM_FUNC_NUM_FUNCS || func == 5) - return -EOPNOTSUPP; + BUILD_BUG_ON(ARRAY_SIZE(data->functions) < ARRAY_SIZE(fwrt->dsm_values)); data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_DSM_NAME, "DSM", sizeof(*data), NULL); @@ -744,23 +739,63 @@ int iwl_uefi_get_dsm(struct iwl_fw_runtime *fwrt, enum iwl_dsm_funcs func, goto out; } - if (!(data->functions[DSM_FUNC_QUERY] & BIT(func))) { - IWL_DEBUG_RADIO(fwrt, "DSM func %d not in 0x%x\n", - func, data->functions[DSM_FUNC_QUERY]); - goto out; - } + fwrt->dsm_funcs_valid = data->functions[DSM_FUNC_QUERY]; - *value = data->functions[func]; + /* + * Make sure we don't load the DSM values twice. Set this only after we + * validated the DSM table so that if the table in UEFI is not valid, + * we will fallback to ACPI. + */ + fwrt->dsm_funcs_valid |= BIT(DSM_FUNC_QUERY); - IWL_DEBUG_RADIO(fwrt, - "UEFI: DSM func=%d: value=%d\n", func, *value); + for (int func = 1; func < ARRAY_SIZE(fwrt->dsm_values); func++) { + if (!(fwrt->dsm_funcs_valid & BIT(func))) { + IWL_DEBUG_RADIO(fwrt, "DSM func %d not in 0x%x\n", + func, fwrt->dsm_funcs_valid); + continue; + } + fwrt->dsm_values[func] = data->functions[func]; + + IWL_DEBUG_RADIO(fwrt, + "UEFI: DSM func=%d: value=%d\n", func, + fwrt->dsm_values[func]); + } ret = 0; + out: kfree(data); return ret; } +int iwl_uefi_get_dsm(struct iwl_fw_runtime *fwrt, enum iwl_dsm_funcs func, + u32 *value) +{ + /* Not supported function index */ + if (func >= DSM_FUNC_NUM_FUNCS || func == 5) + return -EOPNOTSUPP; + + if (!fwrt->dsm_funcs_valid) { + int ret = iwl_uefi_load_dsm_values(fwrt); + + if (ret) + return ret; + } + + if (!(fwrt->dsm_funcs_valid & BIT(func))) { + IWL_DEBUG_RADIO(fwrt, "DSM func %d not in 0x%x\n", + func, fwrt->dsm_funcs_valid); + return -EINVAL; + } + + *value = fwrt->dsm_values[func]; + + IWL_DEBUG_RADIO(fwrt, + "UEFI: DSM func=%d: value=%d\n", func, *value); + + return 0; +} + int iwl_uefi_get_puncturing(struct iwl_fw_runtime *fwrt) { struct uefi_cnv_var_puncturing_data *data; -- cgit v1.2.3 From 1e00423de0f8a9bf1a669a6e427fe32202403b35 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Sun, 11 Jan 2026 19:39:22 +0200 Subject: wifi: iwlwifi: split bios_value_u32 to separate the header This header will be reused in other firmware API structures Signed-off-by: Emmanuel Grumbach Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20260111193638.2f191a5f33fe.I7797134967b980bbda9ba29daa360e50a2196d7d@changeid --- drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h | 16 ++++++++++++---- drivers/net/wireless/intel/iwlwifi/fw/regulatory.c | 6 ++++-- drivers/net/wireless/intel/iwlwifi/mld/debugfs.c | 6 +++--- drivers/net/wireless/intel/iwlwifi/mld/regulatory.c | 8 ++++---- drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 5 +++-- 5 files changed, 26 insertions(+), 15 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h b/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h index 4644fc1aa1ec..48f407baed39 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h @@ -503,18 +503,26 @@ enum bios_source { }; /** - * struct bios_value_u32 - BIOS configuration. + * struct iwl_bios_config_hdr - BIOS configuration header * @table_source: see &enum bios_source * @table_revision: table revision. * @reserved: reserved - * @value: value in bios. */ -struct bios_value_u32 { +struct iwl_bios_config_hdr { u8 table_source; u8 table_revision; u8 reserved[2]; +} __packed; /* BIOS_CONFIG_HDR_API_S_VER_1 */ + +/** + * struct bios_value_u32 - BIOS configuration. + * @hdr: bios config header + * @value: value in bios. + */ +struct bios_value_u32 { + struct iwl_bios_config_hdr hdr; __le32 value; -} __packed; /* BIOS_TABLE_SOURCE_U32_S_VER_1 */ +} __packed; /* BIOS_CONFIG_DATA_U32_API_S_VER_1 */ /** * struct iwl_tas_config_cmd - configures the TAS. diff --git a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c index 00f1c20a5a37..958e71a3c958 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c @@ -376,8 +376,10 @@ int iwl_fill_ppag_table(struct iwl_fw_runtime *fwrt, num_sub_bands = IWL_NUM_SUB_BANDS_V2; gain = cmd->v7.gain[0]; *cmd_size = sizeof(cmd->v7); - cmd->v7.ppag_config_info.table_source = fwrt->ppag_bios_source; - cmd->v7.ppag_config_info.table_revision = fwrt->ppag_bios_rev; + cmd->v7.ppag_config_info.hdr.table_source = + fwrt->ppag_bios_source; + cmd->v7.ppag_config_info.hdr.table_revision = + fwrt->ppag_bios_rev; cmd->v7.ppag_config_info.value = cpu_to_le32(fwrt->ppag_flags); } else { IWL_DEBUG_RADIO(fwrt, "Unsupported PPAG command version\n"); diff --git a/drivers/net/wireless/intel/iwlwifi/mld/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mld/debugfs.c index b9c9cd3f44e4..5c2a2033b3fd 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/debugfs.c @@ -244,7 +244,7 @@ static size_t iwl_mld_dump_tas_resp(struct iwl_dhc_tas_status_resp *resp, } pos += scnprintf(buf + pos, count - pos, "TAS Report\n"); - switch (resp->tas_config_info.table_source) { + switch (resp->tas_config_info.hdr.table_source) { case BIOS_SOURCE_NONE: pos += scnprintf(buf + pos, count - pos, "BIOS SOURCE NONE "); @@ -260,13 +260,13 @@ static size_t iwl_mld_dump_tas_resp(struct iwl_dhc_tas_status_resp *resp, default: pos += scnprintf(buf + pos, count - pos, "BIOS SOURCE UNKNOWN (%d) ", - resp->tas_config_info.table_source); + resp->tas_config_info.hdr.table_source); break; } pos += scnprintf(buf + pos, count - pos, "revision is: %d data is: 0x%08x\n", - resp->tas_config_info.table_revision, + resp->tas_config_info.hdr.table_revision, resp->tas_config_info.value); pos += scnprintf(buf + pos, count - pos, "Current MCC: 0x%x\n", le16_to_cpu(resp->curr_mcc)); diff --git a/drivers/net/wireless/intel/iwlwifi/mld/regulatory.c b/drivers/net/wireless/intel/iwlwifi/mld/regulatory.c index 92e6c0535501..7d11036f9e04 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/regulatory.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/regulatory.c @@ -165,8 +165,8 @@ static int iwl_mld_ppag_send_cmd(struct iwl_mld *mld) { struct iwl_fw_runtime *fwrt = &mld->fwrt; union iwl_ppag_table_cmd cmd = { - .v7.ppag_config_info.table_source = fwrt->ppag_bios_source, - .v7.ppag_config_info.table_revision = fwrt->ppag_bios_rev, + .v7.ppag_config_info.hdr.table_source = fwrt->ppag_bios_source, + .v7.ppag_config_info.hdr.table_revision = fwrt->ppag_bios_rev, .v7.ppag_config_info.value = cpu_to_le32(fwrt->ppag_flags), }; int ret; @@ -389,8 +389,8 @@ void iwl_mld_init_tas(struct iwl_mld *mld) for (u8 i = 0; i < data.block_list_size; i++) cmd.block_list_array[i] = cpu_to_le16(data.block_list_array[i]); - cmd.tas_config_info.table_source = data.table_source; - cmd.tas_config_info.table_revision = data.table_revision; + cmd.tas_config_info.hdr.table_source = data.table_source; + cmd.tas_config_info.hdr.table_revision = data.table_revision; cmd.tas_config_info.value = cpu_to_le32(data.tas_selection); ret = iwl_mld_send_cmd_pdu(mld, cmd_id, &cmd); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index 018f3396e955..a34ca8073ca8 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -1135,8 +1135,9 @@ static void iwl_mvm_tas_init(struct iwl_mvm *mvm) for (u16 i = 0; i < data.block_list_size; i++) cmd_v5.block_list_array[i] = cpu_to_le16(data.block_list_array[i]); - cmd_v5.tas_config_info.table_source = data.table_source; - cmd_v5.tas_config_info.table_revision = data.table_revision; + cmd_v5.tas_config_info.hdr.table_source = data.table_source; + cmd_v5.tas_config_info.hdr.table_revision = + data.table_revision; cmd_v5.tas_config_info.value = cpu_to_le32(data.tas_selection); } else if (fw_ver == 4) { cmd_size = sizeof(cmd_v2_v4.common) + sizeof(cmd_v2_v4.v4); -- cgit v1.2.3 From abce13f5607efcf423cdec31ee36adfb92bb94d6 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Sun, 11 Jan 2026 19:39:23 +0200 Subject: wifi: iwlwifi: support V13 of iwl_lari_config_change_cmd This command is getting a new field for UNII-9 and ieee80211bn enablement. We must read the relevant DSM values and pass them to the firmware, Remember whether we have ACPI or UEFI available in the firmware runtime object and remember the DSM function revision. Signed-off-by: Emmanuel Grumbach Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20260111193638.9577f0cade21.I82b26f082f152a83eb9990dddf68d7dcc549f227@changeid --- drivers/net/wireless/intel/iwlwifi/fw/acpi.c | 5 +++ .../net/wireless/intel/iwlwifi/fw/api/nvm-reg.h | 14 +++++++- drivers/net/wireless/intel/iwlwifi/fw/regulatory.h | 4 ++- drivers/net/wireless/intel/iwlwifi/fw/runtime.h | 4 +++ drivers/net/wireless/intel/iwlwifi/fw/uefi.c | 2 ++ .../net/wireless/intel/iwlwifi/mld/regulatory.c | 40 +++++++++++++++++++--- drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 3 +- 7 files changed, 65 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c index 3899dc3915bf..de9aef0d924c 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c @@ -28,6 +28,8 @@ static const size_t acpi_dsm_size[DSM_FUNC_NUM_FUNCS] = { [DSM_FUNC_ENERGY_DETECTION_THRESHOLD] = sizeof(u32), [DSM_FUNC_RFI_CONFIG] = sizeof(u32), [DSM_FUNC_ENABLE_11BE] = sizeof(u32), + [DSM_FUNC_ENABLE_UNII_9] = sizeof(u32), + [DSM_FUNC_ENABLE_11BN] = sizeof(u32), }; static int iwl_acpi_get_handle(struct device *dev, acpi_string method, @@ -177,6 +179,9 @@ static int iwl_acpi_load_dsm_values(struct iwl_fw_runtime *fwrt) return ret; } + fwrt->dsm_revision = ACPI_DSM_REV; + fwrt->dsm_source = BIOS_SOURCE_ACPI; + IWL_DEBUG_RADIO(fwrt, "ACPI DSM validity bitmap 0x%x\n", (u32)query_func_val); diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h b/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h index 48f407baed39..f6b59e009036 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h @@ -658,6 +658,10 @@ struct iwl_lari_config_change_cmd_v8 { * bit0: enable 11be in China(CB/CN). * bit1: enable 11be in South Korea. * bit 2 - 31: reserved. + * @oem_11bn_allow_bitmap: Bitmap of 11bn allowed MCCs. The firmware expects to + * get the data from the BIOS. + * @oem_unii9_enable: UNII-9 enablement as read from the BIOS + * @bios_hdr: bios config header */ struct iwl_lari_config_change_cmd { __le32 config_bitmap; @@ -669,8 +673,16 @@ struct iwl_lari_config_change_cmd { __le32 edt_bitmap; __le32 oem_320mhz_allow_bitmap; __le32 oem_11be_allow_bitmap; + /* since version 13 */ + __le32 oem_11bn_allow_bitmap; + /* since version 13 */ + __le32 oem_unii9_enable; + /* since version 13 */ + struct iwl_bios_config_hdr bios_hdr; } __packed; -/* LARI_CHANGE_CONF_CMD_S_VER_12 */ +/* LARI_CHANGE_CONF_CMD_S_VER_12 + * LARI_CHANGE_CONF_CMD_S_VER_13 + */ /* Activate UNII-1 (5.2GHz) for World Wide */ #define ACTIVATE_5G2_IN_WW_MASK BIT(4) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h index 26c1d3fad4df..1489031687b7 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h @@ -125,7 +125,9 @@ enum iwl_dsm_funcs { DSM_FUNC_ENERGY_DETECTION_THRESHOLD = 10, DSM_FUNC_RFI_CONFIG = 11, DSM_FUNC_ENABLE_11BE = 12, - DSM_FUNC_NUM_FUNCS = 13, + DSM_FUNC_ENABLE_11BN = 13, + DSM_FUNC_ENABLE_UNII_9 = 14, + DSM_FUNC_NUM_FUNCS, }; enum iwl_dsm_values_srd { diff --git a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h index a655bca75301..ff186fb2e0da 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h @@ -141,6 +141,8 @@ struct iwl_txf_iter_data { * @timestamp.seq: timestamp marking sequence * @timestamp.delay: timestamp marking worker delay * @tpc_enabled: TPC enabled + * @dsm_source: one of &enum bios_source. UEFI, ACPI or NONE + * @dsm_revision: the revision of the DSM table */ struct iwl_fw_runtime { struct iwl_trans *trans; @@ -215,6 +217,8 @@ struct iwl_fw_runtime { bool uats_valid; u8 uefi_tables_lock_status; struct iwl_phy_specific_cfg phy_filters; + enum bios_source dsm_source; + u8 dsm_revision; #if defined(CONFIG_ACPI) || defined(CONFIG_EFI) u32 dsm_funcs_valid; diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c index acccb22a833c..b7532494d4e0 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c @@ -738,6 +738,8 @@ static int iwl_uefi_load_dsm_values(struct iwl_fw_runtime *fwrt) data->revision); goto out; } + fwrt->dsm_revision = data->revision; + fwrt->dsm_source = BIOS_SOURCE_UEFI; fwrt->dsm_funcs_valid = data->functions[DSM_FUNC_QUERY]; diff --git a/drivers/net/wireless/intel/iwlwifi/mld/regulatory.c b/drivers/net/wireless/intel/iwlwifi/mld/regulatory.c index 7d11036f9e04..6ab5a3410353 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/regulatory.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/regulatory.c @@ -281,6 +281,14 @@ void iwl_mld_configure_lari(struct iwl_mld *mld) if (!ret) cmd.oem_11be_allow_bitmap = cpu_to_le32(value); + ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ENABLE_11BN, &value); + if (!ret) + cmd.oem_11bn_allow_bitmap = cpu_to_le32(value); + + ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ENABLE_UNII_9, &value); + if (!ret) + cmd.oem_unii9_enable = cpu_to_le32(value); + if (!cmd.config_bitmap && !cmd.oem_uhb_allow_bitmap && !cmd.oem_11ax_allow_bitmap && @@ -289,9 +297,14 @@ void iwl_mld_configure_lari(struct iwl_mld *mld) !cmd.force_disable_channels_bitmap && !cmd.edt_bitmap && !cmd.oem_320mhz_allow_bitmap && - !cmd.oem_11be_allow_bitmap) + !cmd.oem_11be_allow_bitmap && + !cmd.oem_11bn_allow_bitmap && + !cmd.oem_unii9_enable) return; + cmd.bios_hdr.table_source = fwrt->dsm_source; + cmd.bios_hdr.table_revision = fwrt->dsm_revision; + IWL_DEBUG_RADIO(mld, "sending LARI_CONFIG_CHANGE, config_bitmap=0x%x, oem_11ax_allow_bitmap=0x%x\n", le32_to_cpu(cmd.config_bitmap), @@ -311,9 +324,28 @@ void iwl_mld_configure_lari(struct iwl_mld *mld) IWL_DEBUG_RADIO(mld, "sending LARI_CONFIG_CHANGE, oem_11be_allow_bitmap=0x%x\n", le32_to_cpu(cmd.oem_11be_allow_bitmap)); - - ret = iwl_mld_send_cmd_pdu(mld, WIDE_ID(REGULATORY_AND_NVM_GROUP, - LARI_CONFIG_CHANGE), &cmd); + IWL_DEBUG_RADIO(mld, + "sending LARI_CONFIG_CHANGE, oem_11bn_allow_bitmap=0x%x\n", + le32_to_cpu(cmd.oem_11bn_allow_bitmap)); + IWL_DEBUG_RADIO(mld, + "sending LARI_CONFIG_CHANGE, oem_unii9_enable=0x%x\n", + le32_to_cpu(cmd.oem_unii9_enable)); + + if (iwl_fw_lookup_cmd_ver(mld->fw, + WIDE_ID(REGULATORY_AND_NVM_GROUP, + LARI_CONFIG_CHANGE), 12) == 12) { + int cmd_size = offsetof(typeof(cmd), oem_11bn_allow_bitmap); + + ret = iwl_mld_send_cmd_pdu(mld, + WIDE_ID(REGULATORY_AND_NVM_GROUP, + LARI_CONFIG_CHANGE), + &cmd, cmd_size); + } else { + ret = iwl_mld_send_cmd_pdu(mld, + WIDE_ID(REGULATORY_AND_NVM_GROUP, + LARI_CONFIG_CHANGE), + &cmd); + } if (ret) IWL_DEBUG_RADIO(mld, "Failed to send LARI_CONFIG_CHANGE (%d)\n", diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index a34ca8073ca8..43cf94c9a36b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -1220,7 +1220,8 @@ static size_t iwl_mvm_get_lari_config_cmd_size(u8 cmd_ver) switch (cmd_ver) { case 12: - cmd_size = sizeof(struct iwl_lari_config_change_cmd); + cmd_size = offsetof(struct iwl_lari_config_change_cmd, + oem_11bn_allow_bitmap); break; case 8: cmd_size = sizeof(struct iwl_lari_config_change_cmd_v8); -- cgit v1.2.3 From 5b31cf3f487a4c7f21cb264a3501fb4a4a06b067 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Sun, 11 Jan 2026 19:39:24 +0200 Subject: wifi: iwlwifi: mld: change cluster_id type to u8 array While the cluster_id is two bytes long, it is just the last two bytes of the cluster ID MAC address. This does not really map to a big or little endian data type. Switch it to use an array to avoid confusion and adjust all users so that they do the right thing independent of endianness. Signed-off-by: Benjamin Berg Reviewed-by: Ilan Peer Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20260111193638.80921dc7d305.I56c2bbe0bfc6ee02782bc5d69fda2ac77f3502c4@changeid --- drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h | 9 +++++---- drivers/net/wireless/intel/iwlwifi/mld/nan.c | 16 +++++++--------- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h b/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h index f260115abc5a..c7a833f8041a 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h @@ -1057,7 +1057,8 @@ enum iwl_nan_flags { * @nmi_addr: NAN Management Interface (NMI) address * @reserved_for_nmi_addr: reserved * @discovery_beacon_interval: discovery beacon interval in TUs - * @cluster_id: local cluster ID, in case the local device starts a cluster + * @cluster_id: lower last two bytes of the cluster ID, in case the local + * device starts a cluster * @sta_id: station ID of the NAN station * @hb_channel: channel for 5 GHz if the device supports operation on 5 GHz. * Valid values are 44 and 149, which correspond to the 5 GHz channel, and @@ -1082,7 +1083,7 @@ struct iwl_nan_config_cmd { __le16 reserved_for_nmi_addr; __le32 discovery_beacon_interval; - __le16 cluster_id; + u8 cluster_id[2]; u8 sta_id; u8 hb_channel; @@ -1113,12 +1114,12 @@ enum iwl_nan_cluster_notif_flags { * struct iwl_nan_cluster_notif - event sent when the device starts or joins a * NAN cluster. * - * @cluster_id: cluster ID + * @cluster_id: the last two bytes of the cluster ID * @flags: combination of &enum iwl_nan_cluster_notif_flags * @reserved: reserved */ struct iwl_nan_cluster_notif { - __le16 cluster_id; + u8 cluster_id[2]; u8 flags; u8 reserved; }; /* NAN_JOINED_CLUSTER_NTF_API_S_VER_1 */ diff --git a/drivers/net/wireless/intel/iwlwifi/mld/nan.c b/drivers/net/wireless/intel/iwlwifi/mld/nan.c index d4298f44baf7..2dbd3d58b0c6 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/nan.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/nan.c @@ -55,8 +55,8 @@ static int iwl_mld_nan_config(struct iwl_mld *mld, cmd.master_pref = conf->master_pref; if (conf->cluster_id) - cmd.cluster_id = - cpu_to_le16(*(const u16 *)(conf->cluster_id + 4)); + memcpy(cmd.cluster_id, conf->cluster_id + 4, + sizeof(cmd.cluster_id)); cmd.scan_period = conf->scan_period < 255 ? conf->scan_period : 255; cmd.dwell_time = @@ -215,14 +215,14 @@ void iwl_mld_handle_nan_cluster_notif(struct iwl_mld *mld, ieee80211_vif_to_wdev(mld->nan_device_vif) : NULL; bool new_cluster = !!(notif->flags & IWL_NAN_CLUSTER_NOTIF_FLAG_NEW_CLUSTER); - u8 cluster_id[ETH_ALEN] __aligned(2) = { - 0x50, 0x6f, 0x9a, 0x01, 0x00, 0x00 + u8 cluster_id[ETH_ALEN] = { + 0x50, 0x6f, 0x9a, 0x01, + notif->cluster_id[0], notif->cluster_id[1] }; - u16 id = le16_to_cpu(notif->cluster_id); IWL_DEBUG_INFO(mld, - "NAN: cluster event: cluster_id=0x%x, flags=0x%x\n", - id, notif->flags); + "NAN: cluster event: cluster_id=%pM, flags=0x%x\n", + cluster_id, notif->flags); if (IWL_FW_CHECK(mld, !wdev, "NAN: cluster event without wdev\n")) return; @@ -231,8 +231,6 @@ void iwl_mld_handle_nan_cluster_notif(struct iwl_mld *mld, "NAN: cluster event without NAN started\n")) return; - *((u16 *)(cluster_id + 4)) = id; - cfg80211_nan_cluster_joined(wdev, cluster_id, new_cluster, GFP_KERNEL); } -- cgit v1.2.3 From b46616bb54f71f28bb35c761d3fc77babdd8f5c3 Mon Sep 17 00:00:00 2001 From: Nidhish A N Date: Sun, 11 Jan 2026 19:39:25 +0200 Subject: wifi: iwlwifi: mvm: Remove link_id from time_events As part of removal of EMLSR support from mvm, remove link_id parameter from time_events. Additionally, remove link_id parameter from iwl_mvm_protect_assoc as we can now directly use deflink. Signed-off-by: Nidhish A N Reviewed-by: Pagadala Yesu Anjaneyulu Reviewed-by: Emmanuel Grumbach Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20260111193638.9475bb832db6.I5829b0a2a9a5b56fe885eb0f1e1ad8cd70bc69ff@changeid --- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 9 +++-- .../net/wireless/intel/iwlwifi/mvm/mld-mac80211.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 3 +- drivers/net/wireless/intel/iwlwifi/mvm/tdls.c | 4 +-- .../net/wireless/intel/iwlwifi/mvm/time-event.c | 39 +++++++--------------- .../net/wireless/intel/iwlwifi/mvm/time-event.h | 4 +-- 6 files changed, 21 insertions(+), 40 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index a9022ae4504f..169c87588938 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -2601,7 +2601,7 @@ static void iwl_mvm_cfg_he_sta(struct iwl_mvm *mvm, } void iwl_mvm_protect_assoc(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - u32 duration_override, unsigned int link_id) + u32 duration_override) { u32 duration = IWL_MVM_TE_SESSION_PROTECTION_MAX_TIME_MS; u32 min_duration = IWL_MVM_TE_SESSION_PROTECTION_MIN_TIME_MS; @@ -2621,8 +2621,7 @@ void iwl_mvm_protect_assoc(struct iwl_mvm *mvm, struct ieee80211_vif *vif, if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_SESSION_PROT_CMD)) iwl_mvm_schedule_session_protection(mvm, vif, 900, - min_duration, false, - link_id); + min_duration, false); else iwl_mvm_protect_session(mvm, vif, duration, min_duration, 500, false); @@ -2822,7 +2821,7 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, * time could be small without us having heard * a beacon yet. */ - iwl_mvm_protect_assoc(mvm, vif, 0, 0); + iwl_mvm_protect_assoc(mvm, vif, 0); } iwl_mvm_sf_update(mvm, vif, false); @@ -4152,7 +4151,7 @@ void iwl_mvm_mac_mgd_prepare_tx(struct ieee80211_hw *hw, return; guard(mvm)(mvm); - iwl_mvm_protect_assoc(mvm, vif, info->duration, info->link_id); + iwl_mvm_protect_assoc(mvm, vif, info->duration); } void iwl_mvm_mac_mgd_complete_tx(struct ieee80211_hw *hw, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c index 5829a8b45a89..075ff09e93cc 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c @@ -662,7 +662,7 @@ static void iwl_mvm_mld_vif_cfg_changed_station(struct iwl_mvm *mvm, * time could be small without us having heard * a beacon yet. */ - iwl_mvm_protect_assoc(mvm, vif, 0, -1); + iwl_mvm_protect_assoc(mvm, vif, 0); } iwl_mvm_sf_update(mvm, vif, false); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index f3685292b834..db5f9804b529 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -120,7 +120,6 @@ struct iwl_mvm_time_event_data { * if the te is in the time event list or not (when id == TE_MAX) */ u32 id; - s8 link_id; }; /* Power management */ @@ -2009,7 +2008,7 @@ int iwl_mvm_cancel_roc(struct ieee80211_hw *hw, struct ieee80211_vif *vif); /*Session Protection */ void iwl_mvm_protect_assoc(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - u32 duration_override, unsigned int link_id); + u32 duration_override); /* Quota management */ static inline size_t iwl_mvm_quota_cmd_size(struct iwl_mvm *mvm) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tdls.c b/drivers/net/wireless/intel/iwlwifi/mvm/tdls.c index 36379b738de1..4945ebf19f6b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tdls.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tdls.c @@ -2,7 +2,7 @@ /* * Copyright (C) 2014 Intel Mobile Communications GmbH * Copyright (C) 2017 Intel Deutschland GmbH - * Copyright (C) 2018-2020, 2022-2024 Intel Corporation + * Copyright (C) 2018-2020, 2022-2025 Intel Corporation */ #include #include "mvm.h" @@ -155,7 +155,7 @@ void iwl_mvm_mac_mgd_protect_tdls_discover(struct ieee80211_hw *hw, if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_SESSION_PROT_CMD)) iwl_mvm_schedule_session_protection(mvm, vif, duration, - duration, true, link_id); + duration, true); else iwl_mvm_protect_session(mvm, vif, duration, duration, 100, true); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c index 0b12ee8ad618..2b52a4f3bff9 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c @@ -42,7 +42,6 @@ void iwl_mvm_te_clear_data(struct iwl_mvm *mvm, te_data->uid = 0; te_data->id = TE_MAX; te_data->vif = NULL; - te_data->link_id = -1; } static void iwl_mvm_cleanup_roc(struct iwl_mvm *mvm) @@ -721,8 +720,7 @@ void iwl_mvm_protect_session(struct iwl_mvm *mvm, /* Determine whether mac or link id should be used, and validate the link id */ static int iwl_mvm_get_session_prot_id(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - s8 link_id) + struct ieee80211_vif *vif) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); int ver = iwl_fw_lookup_cmd_ver(mvm->fw, @@ -732,22 +730,18 @@ static int iwl_mvm_get_session_prot_id(struct iwl_mvm *mvm, if (ver < 2) return mvmvif->id; - if (WARN(link_id < 0 || !mvmvif->link[link_id], - "Invalid link ID for session protection: %u\n", link_id)) - return -EINVAL; - - if (WARN(!mvmvif->link[link_id]->active, - "Session Protection on an inactive link: %u\n", link_id)) + if (WARN(!mvmvif->deflink.active, + "Session Protection on an inactive link\n")) return -EINVAL; - return mvmvif->link[link_id]->fw_link_id; + return mvmvif->deflink.fw_link_id; } static void iwl_mvm_cancel_session_protection(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - u32 id, s8 link_id) + u32 id) { - int mac_link_id = iwl_mvm_get_session_prot_id(mvm, vif, link_id); + int mac_link_id = iwl_mvm_get_session_prot_id(mvm, vif); struct iwl_session_prot_cmd cmd = { .id_and_color = cpu_to_le32(mac_link_id), .action = cpu_to_le32(FW_CTXT_ACTION_REMOVE), @@ -791,7 +785,6 @@ static bool __iwl_mvm_remove_time_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif = te_data->vif; struct iwl_mvm_vif *mvmvif; enum nl80211_iftype iftype; - s8 link_id; bool p2p_aux = iwl_mvm_has_p2p_over_aux(mvm); u8 roc_ver = iwl_fw_lookup_cmd_ver(mvm->fw, WIDE_ID(MAC_CONF_GROUP, ROC_CMD), 0); @@ -811,7 +804,6 @@ static bool __iwl_mvm_remove_time_event(struct iwl_mvm *mvm, /* Save time event uid before clearing its data */ *uid = te_data->uid; id = te_data->id; - link_id = te_data->link_id; /* * The clear_data function handles time events that were already removed @@ -837,8 +829,7 @@ static bool __iwl_mvm_remove_time_event(struct iwl_mvm *mvm, */ if (mvmvif && id < SESSION_PROTECT_CONF_MAX_ID) { /* Session protection is still ongoing. Cancel it */ - iwl_mvm_cancel_session_protection(mvm, vif, id, - link_id); + iwl_mvm_cancel_session_protection(mvm, vif, id); if (iftype == NL80211_IFTYPE_P2P_DEVICE) { iwl_mvm_roc_finished(mvm); } @@ -1007,7 +998,6 @@ void iwl_mvm_rx_session_protect_notif(struct iwl_mvm *mvm, if (!le32_to_cpu(notif->status) || !le32_to_cpu(notif->start)) { /* End TE, notify mac80211 */ mvmvif->time_event_data.id = SESSION_PROTECT_CONF_MAX_ID; - mvmvif->time_event_data.link_id = -1; /* set the bit so the ROC cleanup will actually clean up */ set_bit(IWL_MVM_STATUS_ROC_P2P_RUNNING, &mvm->status); iwl_mvm_roc_finished(mvm); @@ -1132,7 +1122,7 @@ iwl_mvm_start_p2p_roc_session_protection(struct iwl_mvm *mvm, struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_session_prot_cmd cmd = { .id_and_color = - cpu_to_le32(iwl_mvm_get_session_prot_id(mvm, vif, 0)), + cpu_to_le32(iwl_mvm_get_session_prot_id(mvm, vif)), .action = cpu_to_le32(FW_CTXT_ACTION_ADD), .duration_tu = cpu_to_le32(MSEC_TO_TU(duration)), }; @@ -1143,8 +1133,6 @@ iwl_mvm_start_p2p_roc_session_protection(struct iwl_mvm *mvm, * protection's configuration. */ - mvmvif->time_event_data.link_id = 0; - switch (type) { case IEEE80211_ROC_TYPE_NORMAL: mvmvif->time_event_data.id = @@ -1290,8 +1278,7 @@ void iwl_mvm_stop_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif) return; } iwl_mvm_cancel_session_protection(mvm, vif, - te_data->id, - te_data->link_id); + te_data->id); } else { iwl_mvm_remove_aux_roc_te(mvm, mvmvif, &mvmvif->hs_time_event_data); @@ -1423,14 +1410,13 @@ static bool iwl_mvm_session_prot_notif(struct iwl_notif_wait_data *notif_wait, void iwl_mvm_schedule_session_protection(struct iwl_mvm *mvm, struct ieee80211_vif *vif, u32 duration, u32 min_duration, - bool wait_for_notif, - unsigned int link_id) + bool wait_for_notif) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data; const u16 notif[] = { WIDE_ID(MAC_CONF_GROUP, SESSION_PROTECTION_NOTIF) }; struct iwl_notification_wait wait_notif; - int mac_link_id = iwl_mvm_get_session_prot_id(mvm, vif, (s8)link_id); + int mac_link_id = iwl_mvm_get_session_prot_id(mvm, vif); struct iwl_session_prot_cmd cmd = { .id_and_color = cpu_to_le32(mac_link_id), .action = cpu_to_le32(FW_CTXT_ACTION_ADD), @@ -1444,7 +1430,7 @@ void iwl_mvm_schedule_session_protection(struct iwl_mvm *mvm, lockdep_assert_held(&mvm->mutex); spin_lock_bh(&mvm->time_event_lock); - if (te_data->running && te_data->link_id == link_id && + if (te_data->running && time_after(te_data->end_jiffies, TU_TO_EXP_TIME(min_duration))) { IWL_DEBUG_TE(mvm, "We have enough time in the current TE: %u\n", jiffies_to_msecs(te_data->end_jiffies - jiffies)); @@ -1461,7 +1447,6 @@ void iwl_mvm_schedule_session_protection(struct iwl_mvm *mvm, te_data->id = le32_to_cpu(cmd.conf_id); te_data->duration = le32_to_cpu(cmd.duration_tu); te_data->vif = vif; - te_data->link_id = link_id; spin_unlock_bh(&mvm->time_event_lock); IWL_DEBUG_TE(mvm, "Add new session protection, duration %d TU\n", diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.h b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.h index 1ef8768756db..3f8628cbd480 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.h @@ -210,13 +210,11 @@ iwl_mvm_te_scheduled(struct iwl_mvm_time_event_data *te_data) * @duration: the requested duration of the protection * @min_duration: the minimum duration of the protection * @wait_for_notif: if true, will block until the start of the protection - * @link_id: The link to schedule a session protection for */ void iwl_mvm_schedule_session_protection(struct iwl_mvm *mvm, struct ieee80211_vif *vif, u32 duration, u32 min_duration, - bool wait_for_notif, - unsigned int link_id); + bool wait_for_notif); /** * iwl_mvm_rx_session_protect_notif - handles %SESSION_PROTECTION_NOTIF -- cgit v1.2.3 From 66af8ac52d10ea229d5755b8700e2fe86fc037f7 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Sun, 11 Jan 2026 19:39:26 +0200 Subject: wifi: iwlwifi: rename struct iwl_mcc_allowed_ap_type_cmd::offset_map This was poorly named, probably a copy paste mistake. The real meaning of this field is a map of the MCCs to describe the AP type allowed for each country. Signed-off-by: Emmanuel Grumbach Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20260111193638.6ed558b09581.I6560b8cfb36b68cea1afe8f89f87dded99d2caf7@changeid --- drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h | 4 ++-- drivers/net/wireless/intel/iwlwifi/fw/uefi.c | 5 +++-- drivers/net/wireless/intel/iwlwifi/fw/uefi.h | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h b/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h index f6b59e009036..bd6bf931866f 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h @@ -702,11 +702,11 @@ struct iwl_pnvm_init_complete_ntfy { /** * struct iwl_mcc_allowed_ap_type_cmd - struct for MCC_ALLOWED_AP_TYPE_CMD - * @offset_map: mapping a mcc to UHB AP type support (UATS) allowed + * @mcc_to_ap_type_map: mapping an MCC to 6 GHz AP type support (UATS) * @reserved: reserved */ struct iwl_mcc_allowed_ap_type_cmd { - u8 offset_map[UATS_TABLE_ROW_SIZE][UATS_TABLE_COL_SIZE]; + u8 mcc_to_ap_type_map[UATS_TABLE_ROW_SIZE][UATS_TABLE_COL_SIZE]; __le16 reserved; } __packed; /* MCC_ALLOWED_AP_TYPE_CMD_API_S_VER_1 */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c index b7532494d4e0..a7ba86e06c09 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c @@ -402,8 +402,9 @@ static int iwl_uefi_uats_parse(struct uefi_cnv_wlan_uats_data *uats_data, if (uats_data->revision != 1) return -EINVAL; - memcpy(fwrt->uats_table.offset_map, uats_data->offset_map, - sizeof(fwrt->uats_table.offset_map)); + memcpy(fwrt->uats_table.mcc_to_ap_type_map, + uats_data->mcc_to_ap_type_map, + sizeof(fwrt->uats_table.mcc_to_ap_type_map)); fwrt->uats_valid = true; diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.h b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h index 5a4c557e47c7..349ac1505ad7 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h @@ -60,7 +60,7 @@ struct uefi_cnv_wlan_sgom_data { struct uefi_cnv_wlan_uats_data { u8 revision; - u8 offset_map[IWL_UATS_MAP_SIZE - 1]; + u8 mcc_to_ap_type_map[IWL_UATS_MAP_SIZE - 1]; } __packed; struct uefi_cnv_common_step_data { -- cgit v1.2.3