diff options
| author | Johannes Berg <johannes.berg@intel.com> | 2026-01-27 13:53:53 +0100 |
|---|---|---|
| committer | Johannes Berg <johannes.berg@intel.com> | 2026-01-27 13:54:12 +0100 |
| commit | c30e188bd2a886258be5facb970a804d8ef549b5 (patch) | |
| tree | a0e4a222753b9a354ad7b60dd372c75f4b9a677d | |
| parent | a410d3fb30d920f26b1fd1604db13f4213144bc1 (diff) | |
| parent | 66af8ac52d10ea229d5755b8700e2fe86fc037f7 (diff) | |
Merge tag 'iwlwifi-next-2026-01-21' of https://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi-next
Miri Korenblit says:
====================
iwlwifi features. Notably:
- Partial NAN support - without DATA
- Initial UHR support
- UNII-9 support
- EHT code cleanup in iwlmvm
====================
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
55 files changed, 1591 insertions, 925 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); 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/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c index 52edc19d8cdd..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, @@ -156,61 +158,104 @@ 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; + fwrt->dsm_revision = ACPI_DSM_REV; + fwrt->dsm_source = BIOS_SOURCE_ACPI; - 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; + IWL_DEBUG_RADIO(fwrt, "ACPI DSM validity bitmap 0x%x\n", + (u32)query_func_val); + + /* 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); + } + + 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; } - if (!(fwrt->acpi_dsm_funcs_valid & BIT(func))) { + 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/api/mac-cfg.h b/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h index f76cea6e9ec8..c7a833f8041a 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h @@ -66,6 +66,18 @@ enum iwl_mac_conf_subcmd_ids { */ 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 */ MISSED_BEACONS_NOTIF = 0xF6, @@ -492,22 +504,36 @@ enum iwl_link_modify_bandwidth { }; /** + * 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 @@ -618,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. @@ -990,4 +1017,122 @@ 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: 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 + * 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; + + u8 cluster_id[2]; + 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: the last two bytes of the cluster ID + * @flags: combination of &enum iwl_nan_cluster_notif_flags + * @reserved: reserved + */ +struct iwl_nan_cluster_notif { + u8 cluster_id[2]; + 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/api/nvm-reg.h b/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h index 4644fc1aa1ec..bd6bf931866f 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. @@ -650,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; @@ -661,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) @@ -682,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/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) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/rs.h b/drivers/net/wireless/intel/iwlwifi/fw/api/rs.h index 9c464e7aba10..ae6be3ed32f8 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, }; /** @@ -205,7 +207,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 +223,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; @@ -236,6 +238,38 @@ struct iwl_tlc_config_cmd { } __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 <nss, channel-width> + * 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 * @IWL_TLC_NOTIF_FLAG_AMSDU: umsdu parameters update @@ -706,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) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h b/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h index 3ed7e0807b90..ac6c1ef2cbcd 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h @@ -1062,13 +1062,37 @@ 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 { #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 @@ -1247,19 +1271,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 { 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/fw/regulatory.c b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c index d2ad169ae880..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"); @@ -488,206 +490,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); - -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..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 { @@ -218,11 +220,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_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/fw/runtime.h b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h index 57570ff15622..ff186fb2e0da 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 @@ -137,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; @@ -211,9 +217,12 @@ 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; -#ifdef CONFIG_ACPI - u32 acpi_dsm_funcs_valid; +#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/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); } diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c index 4ae4d215e633..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; @@ -721,17 +722,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); @@ -743,24 +739,66 @@ int iwl_uefi_get_dsm(struct iwl_fw_runtime *fwrt, enum iwl_dsm_funcs func, data->revision); goto out; } + fwrt->dsm_revision = data->revision; + fwrt->dsm_source = BIOS_SOURCE_UEFI; - 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; 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 { 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) 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/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) 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/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/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 55b484c16280..df8221277d51 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,38 @@ 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); + + 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 */ + 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); @@ -318,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)) @@ -616,10 +677,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 +709,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 +739,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); @@ -984,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); @@ -992,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); @@ -1016,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); @@ -1506,6 +1581,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; @@ -1706,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) @@ -2699,4 +2780,7 @@ 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, + .nan_change_conf = iwl_mld_nan_change_config, }; 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/mlo.c b/drivers/net/wireless/intel/iwlwifi/mld/mlo.c index c6b151f26921..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) @@ -451,29 +452,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); } } +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 +502,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 +515,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 @@ -844,9 +858,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 && @@ -1197,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 new file mode 100644 index 000000000000..2dbd3d58b0c6 --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/mld/nan.c @@ -0,0 +1,299 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* + * Copyright (C) 2025 Intel Corporation + */ + +#include "mld.h" +#include "iface.h" +#include "mlo.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 + +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 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 iwl_host_cmd hcmd = { + .id = WIDE_ID(MAC_CONF_GROUP, NAN_CFG_CMD), + }; + + 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; + } + + return iwl_mld_send_cmd(mld, &hcmd); +} + +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_vif *mld_vif = iwl_mld_vif_from_mac80211(vif); + struct iwl_nan_config_cmd cmd = { + .action = cpu_to_le32(action), + }; + u8 *data __free(kfree) = NULL; + + lockdep_assert_wiphy(mld->wiphy); + + ether_addr_copy(cmd.nmi_addr, vif->addr); + cmd.master_pref = conf->master_pref; + + if (conf->cluster_id) + 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 = + 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); + } + + 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_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); + 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; +} + +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) +{ + 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); + + /* 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); + + iwl_mld_update_emlsr_block(mld, false, IWL_MLD_EMLSR_BLOCKED_NAN); + + 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; + 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] = { + 0x50, 0x6f, 0x9a, 0x01, + notif->cluster_id[0], notif->cluster_id[1] + }; + + IWL_DEBUG_INFO(mld, + "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; + + if (IWL_FW_CHECK(mld, !ieee80211_vif_nan_started(mld->nan_device_vif), + "NAN: cluster event without NAN started\n")) + return; + + 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, + 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; + struct wireless_dev *wdev; + struct ieee80211_channel *chan; + + IWL_INFO(mld, "NAN: DW end: band=%u\n", notif->band); + + 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)) + 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); + + /* 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 new file mode 100644 index 000000000000..c9c83d1012f0 --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/mld/nan.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ +/* + * Copyright (C) 2025 Intel Corporation + */ + +#include <net/cfg80211.h> +#include <linux/etherdevice.h> + +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, + 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 4cf3920b005f..35356b244c0a 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) { @@ -344,6 +347,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 +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_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); @@ -531,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; @@ -571,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, 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, 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), diff --git a/drivers/net/wireless/intel/iwlwifi/mld/regulatory.c b/drivers/net/wireless/intel/iwlwifi/mld/regulatory.c index 40571125b3ab..6ab5a3410353 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; @@ -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); @@ -265,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 && @@ -273,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), @@ -295,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", @@ -373,8 +421,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/mld/rx.c b/drivers/net/wireless/intel/iwlwifi/mld/rx.c index 6a76e3fcb581..214dcfde2fb4 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/rx.c @@ -208,6 +208,134 @@ static void iwl_mld_fill_signal(struct iwl_mld *mld, int link_id, } 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, u8 ru_with_p80) @@ -268,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, @@ -280,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); @@ -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); 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, 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/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, diff --git a/drivers/net/wireless/intel/iwlwifi/mld/tx.c b/drivers/net/wireless/intel/iwlwifi/mld/tx.c index 3b4b575aadaa..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; @@ -667,6 +672,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"); break; 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/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index edae13755ee6..43cf94c9a36b 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); @@ -1165,13 +1166,208 @@ 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; + + switch (cmd_ver) { + case 12: + 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); + 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_mvm_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, 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 867807abde66..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; @@ -1761,6 +1750,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; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 44029ceb8f77..169c87588938 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); @@ -2639,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; @@ -2659,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); @@ -2860,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); @@ -3921,12 +3882,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 +3927,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); @@ -4197,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, @@ -5568,8 +5522,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 +5686,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 <linux/kernel.h> #include <net/mac80211.h> @@ -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..075ff09e93cc 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); } 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..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 */ @@ -380,14 +379,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 +426,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 +506,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 +1606,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 +1961,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; @@ -2064,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) @@ -2884,8 +2828,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 b588f1dcf20d..9c51953d255d 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, @@ -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/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 <linux/etherdevice.h> #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 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); } |
