diff options
Diffstat (limited to 'drivers/net/wireless/intel/iwlwifi/fw')
22 files changed, 492 insertions, 319 deletions
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c index cb9181f05501..018d820ae231 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c @@ -41,6 +41,34 @@ static const struct dmi_system_id dmi_ppag_approved_list[] = { DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), }, }, + { .ident = "GOOGLE-HP", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Google"), + DMI_MATCH(DMI_BOARD_VENDOR, "HP"), + }, + }, + { .ident = "GOOGLE-ASUS", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Google"), + DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTek COMPUTER INC."), + }, + }, + { .ident = "GOOGLE-SAMSUNG", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Google"), + DMI_MATCH(DMI_BOARD_VENDOR, "SAMSUNG ELECTRONICS CO., LTD"), + }, + }, + { .ident = "DELL", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + }, + }, + { .ident = "DELL", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), + }, + }, {} }; @@ -1149,7 +1177,15 @@ int iwl_read_ppag_table(struct iwl_fw_runtime *fwrt, union iwl_ppag_table_cmd *c IWL_DEBUG_RADIO(fwrt, "PPAG table rev is %d but FW supports v1, sending truncated table\n", fwrt->ppag_ver); - cmd->v1.flags &= cpu_to_le32(IWL_PPAG_ETSI_MASK); + if (!fw_has_capa(&fwrt->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_PPAG_CHINA_BIOS_SUPPORT)) { + cmd->v1.flags &= cpu_to_le32(IWL_PPAG_ETSI_MASK); + IWL_DEBUG_RADIO(fwrt, + "FW doesn't support ppag China bit\n"); + } else { + IWL_DEBUG_RADIO(fwrt, + "FW supports ppag China bit\n"); + } } } else if (cmd_ver >= 2 && cmd_ver <= 4) { num_sub_bands = IWL_NUM_SUB_BANDS_V2; diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/binding.h b/drivers/net/wireless/intel/iwlwifi/fw/api/binding.h index 29e2816e7052..b6b5959cb259 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/binding.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/binding.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2012-2014, 2020 Intel Corporation + * Copyright (C) 2012-2014, 2020, 2022 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -18,7 +18,7 @@ * ( BINDING_CONTEXT_CMD = 0x2b ) * @id_and_color: ID and color of the relevant Binding, * &enum iwl_ctxt_id_and_color - * @action: action to perform, one of FW_CTXT_ACTION_* + * @action: action to perform, see &enum iwl_ctxt_action * @macs: array of MAC id and colors which belong to the binding, * &enum iwl_ctxt_id_and_color * @phy: PHY id and color which belongs to the binding, @@ -38,7 +38,7 @@ struct iwl_binding_cmd_v1 { * ( BINDING_CONTEXT_CMD = 0x2b ) * @id_and_color: ID and color of the relevant Binding, * &enum iwl_ctxt_id_and_color - * @action: action to perform, one of FW_CTXT_ACTION_* + * @action: action to perform, see &enum iwl_ctxt_action * @macs: array of MAC id and colors which belong to the binding * &enum iwl_ctxt_id_and_color * @phy: PHY id and color which belongs to the binding diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h b/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h index 111d96cbde6f..13cb0d53a1a3 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h @@ -139,11 +139,6 @@ enum iwl_legacy_cmds { REMOVE_STA = 0x19, /** - * @FW_GET_ITEM_CMD: uses &struct iwl_fw_get_item_cmd - */ - FW_GET_ITEM_CMD = 0x1a, - - /** * @TX_CMD: uses &struct iwl_tx_cmd or &struct iwl_tx_cmd_gen2 or * &struct iwl_tx_cmd_gen3, * response in &struct iwl_mvm_tx_resp or @@ -534,12 +529,6 @@ enum iwl_legacy_cmds { PROT_OFFLOAD_CONFIG_CMD = 0xd4, /** - * @OFFLOADS_QUERY_CMD: - * No data in command, response in &struct iwl_wowlan_status - */ - OFFLOADS_QUERY_CMD = 0xd5, - - /** * @D0I3_END_CMD: End D0i3/D3 state, no command data */ D0I3_END_CMD = 0xed, @@ -566,18 +555,22 @@ enum iwl_legacy_cmds { WOWLAN_TKIP_PARAM = 0xe3, /** - * @WOWLAN_KEK_KCK_MATERIAL: &struct iwl_wowlan_kek_kck_material_cmd + * @WOWLAN_KEK_KCK_MATERIAL: &struct iwl_wowlan_kek_kck_material_cmd_v2, + * &struct iwl_wowlan_kek_kck_material_cmd_v3 or + * &struct iwl_wowlan_kek_kck_material_cmd_v4 */ WOWLAN_KEK_KCK_MATERIAL = 0xe4, /** - * @WOWLAN_GET_STATUSES: response in &struct iwl_wowlan_status + * @WOWLAN_GET_STATUSES: response in &struct iwl_wowlan_status_v6, + * &struct iwl_wowlan_status_v7, &struct iwl_wowlan_status_v9 or + * &struct iwl_wowlan_status_v12 */ WOWLAN_GET_STATUSES = 0xe5, /** - * @SCAN_OFFLOAD_PROFILES_QUERY_CMD: - * No command data, response is &struct iwl_scan_offload_profiles_query + * @SCAN_OFFLOAD_PROFILES_QUERY_CMD: No command data, response is + * &struct iwl_scan_offload_profiles_query_v1 */ SCAN_OFFLOAD_PROFILES_QUERY_CMD = 0x56, }; diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/context.h b/drivers/net/wireless/intel/iwlwifi/fw/api/context.h index 105ba7170c3f..1fa5678c1cd6 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/context.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/context.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2012-2014 Intel Corporation + * Copyright (C) 2012-2014, 2022 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -26,13 +26,18 @@ enum iwl_ctxt_id_and_color { #define FW_CMD_ID_AND_COLOR(_id, _color) (((_id) << FW_CTXT_ID_POS) |\ ((_color) << FW_CTXT_COLOR_POS)) -/* Possible actions on PHYs, MACs and Bindings */ +/** + * enum iwl_ctxt_action - Posssible actions on PHYs, MACs, Bindings and other + * @FW_CTXT_ACTION_INVALID: unused, invalid action + * @FW_CTXT_ACTION_ADD: add the context + * @FW_CTXT_ACTION_MODIFY: modify the context + * @FW_CTXT_ACTION_REMOVE: remove the context + */ enum iwl_ctxt_action { - FW_CTXT_ACTION_STUB = 0, + FW_CTXT_ACTION_INVALID = 0, FW_CTXT_ACTION_ADD, FW_CTXT_ACTION_MODIFY, FW_CTXT_ACTION_REMOVE, - FW_CTXT_ACTION_NUM }; /* COMMON_CONTEXT_ACTION_API_E_VER_1 */ #endif /* __iwl_fw_api_context_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h b/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h index 8a613e150a02..37ac2364e714 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h @@ -47,12 +47,14 @@ struct iwl_d3_manager_config { * @IWL_D3_PROTO_OFFLOAD_NS: NS (Neighbor Solicitation) is enabled * @IWL_D3_PROTO_IPV4_VALID: IPv4 data is valid * @IWL_D3_PROTO_IPV6_VALID: IPv6 data is valid + * @IWL_D3_PROTO_REJECT_BTM: reject BTM request */ enum iwl_proto_offloads { IWL_D3_PROTO_OFFLOAD_ARP = BIT(0), IWL_D3_PROTO_OFFLOAD_NS = BIT(1), IWL_D3_PROTO_IPV4_VALID = BIT(2), IWL_D3_PROTO_IPV6_VALID = BIT(3), + IWL_D3_PROTO_REJECT_BTM = BIT(4), }; #define IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V1 2 diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h b/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h index 6f59381b9f9a..751b596ea1a5 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h @@ -38,7 +38,9 @@ enum iwl_data_path_subcmd_ids { WNM_80211V_TIMING_MEASUREMENT_CONFIG_CMD = 0x4, /** - * @STA_HE_CTXT_CMD: &struct iwl_he_sta_context_cmd + * @STA_HE_CTXT_CMD: &struct iwl_he_sta_context_cmd_v1, + * &struct iwl_he_sta_context_cmd_v2 or + * &struct iwl_he_sta_context_cmd_v3 */ STA_HE_CTXT_CMD = 0x7, @@ -447,7 +449,7 @@ struct iwl_sad_properties { * @phy_id: PHY index * @rlc: RLC properties, &struct iwl_rlc_properties * @sad: SAD (single antenna diversity) options, &struct iwl_sad_properties - * @flags: flags, &enum iwl_rlc_flags + * @flags: flags (unused) * @reserved: reserved */ struct iwl_rlc_config_cmd { diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/location.h b/drivers/net/wireless/intel/iwlwifi/fw/api/location.h index 12af94e166ed..b044990c7b87 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/location.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/location.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* * Copyright (C) 2015-2017 Intel Deutschland GmbH - * Copyright (C) 2018-2021 Intel Corporation + * Copyright (C) 2018-2022 Intel Corporation */ #ifndef __iwl_fw_api_location_h__ #define __iwl_fw_api_location_h__ @@ -35,8 +35,11 @@ enum iwl_location_subcmd_ids { */ TOF_RANGE_REQ_EXT_CMD = 0x3, /** - * @TOF_RESPONDER_CONFIG_CMD: FTM responder configuration, - * uses &struct iwl_tof_responder_config_cmd + * @TOF_RESPONDER_CONFIG_CMD: FTM responder configuration, one of + * &struct iwl_tof_responder_config_cmd_v6, + * &struct iwl_tof_responder_config_cmd_v7, + * &struct iwl_tof_responder_config_cmd_v8 or + * &struct iwl_tof_responder_config_cmd_v9 */ TOF_RESPONDER_CONFIG_CMD = 0x4, /** @@ -69,8 +72,11 @@ enum iwl_location_subcmd_ids { */ TOF_MCSI_DEBUG_NOTIF = 0xFE, /** - * @TOF_RANGE_RESPONSE_NOTIF: ranging response, using - * &struct iwl_tof_range_rsp_ntfy + * @TOF_RANGE_RESPONSE_NOTIF: ranging response, using one of + * &struct iwl_tof_range_rsp_ntfy_v5, + * &struct iwl_tof_range_rsp_ntfy_v6, + * &struct iwl_tof_range_rsp_ntfy_v7 or + * &struct iwl_tof_range_rsp_ntfy_v8 */ TOF_RANGE_RESPONSE_NOTIF = 0xFF, }; 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 74f2efbad34e..a4cb24934a01 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h @@ -140,40 +140,60 @@ struct iwl_missed_vap_notif { * * @id_and_color: ID and color of the MAC */ -struct iwl_channel_switch_start_notif { +struct iwl_channel_switch_start_notif_v1 { __le32 id_and_color; } __packed; /* CHANNEL_SWITCH_START_NTFY_API_S_VER_1 */ +/** + * struct iwl_channel_switch_start_notif - Channel switch start notification + * + * @link_id: FW link id + */ +struct iwl_channel_switch_start_notif { + __le32 link_id; +} __packed; /* CHANNEL_SWITCH_START_NTFY_API_S_VER_3 */ + #define CS_ERR_COUNT_ERROR BIT(0) #define CS_ERR_LONG_DELAY_AFTER_CS BIT(1) #define CS_ERR_LONG_TX_BLOCK BIT(2) #define CS_ERR_TX_BLOCK_TIMER_EXPIRED BIT(3) /** - * struct iwl_channel_switch_error_notif - Channel switch error notification + * struct iwl_channel_switch_error_notif_v1 - Channel switch error notification * * @mac_id: the mac for which the ucode sends the notification for * @csa_err_mask: mask of channel switch error that can occur */ -struct iwl_channel_switch_error_notif { +struct iwl_channel_switch_error_notif_v1 { __le32 mac_id; __le32 csa_err_mask; } __packed; /* CHANNEL_SWITCH_ERROR_NTFY_API_S_VER_1 */ /** + * struct iwl_channel_switch_error_notif - Channel switch error notification + * + * @link_id: FW link id + * @csa_err_mask: mask of channel switch error that can occur + */ +struct iwl_channel_switch_error_notif { + __le32 link_id; + __le32 csa_err_mask; +} __packed; /* CHANNEL_SWITCH_ERROR_NTFY_API_S_VER_2 */ + +/** * struct iwl_cancel_channel_switch_cmd - Cancel Channel Switch command * - * @mac_id: the mac that should cancel the channel switch + * @id: the id of the link or mac that should cancel the channel switch */ struct iwl_cancel_channel_switch_cmd { - __le32 mac_id; + __le32 id; } __packed; /* MAC_CANCEL_CHANNEL_SWITCH_S_VER_1 */ /** * struct iwl_chan_switch_te_cmd - Channel Switch Time Event command * * @mac_id: MAC ID for channel switch - * @action: action to perform, one of FW_CTXT_ACTION_* + * @action: action to perform, see &enum iwl_ctxt_action * @tsf: beacon tsf * @cs_count: channel switch count from CSA/eCSA IE * @cs_delayed_bcn_count: if set to N (!= 0) GO/AP can delay N beacon intervals @@ -211,17 +231,30 @@ struct iwl_mac_low_latency_cmd { * struct iwl_mac_client_data - configuration data for client MAC context * * @is_assoc: 1 for associated state, 0 otherwise + * @esr_transition_timeout: the timeout required by the AP for the + * eSR transition. + * Available only from version 2 of the command. + * This values comes from the EMLSR transition delay in the EML + * Capabilities subfield. + * @reserved: alignment * @assoc_id: unique ID assigned by the AP during association + * @reserved1: alignment * @data_policy: see &enum iwl_mac_data_policy + * @reserved2: alignment * @ctwin: client traffic window in TU (period after TBTT when GO is present). * 0 indicates that there is no CT window. */ struct iwl_mac_client_data { - __le32 is_assoc; - __le32 assoc_id; - __le32 data_policy; + u8 is_assoc; + u8 esr_transition_timeout; + __le16 reserved; + + __le16 assoc_id; + __le16 reserved1; + __le16 data_policy; + __le16 reserved2; __le32 ctwin; -} __packed; /* MAC_CONTEXT_CONFIG_CLIENT_DATA_API_S_VER_1 */ +} __packed; /* MAC_CONTEXT_CONFIG_CLIENT_DATA_API_S_VER_2 */ /** * struct iwl_mac_p2p_dev_data - configuration data for P2P device MAC context @@ -263,7 +296,7 @@ enum iwl_mac_config_filter_flags { * ( MAC_CONTEXT_CONFIG_CMD = 0x8 ) * * @id_and_color: ID and color of the MAC - * @action: action to perform, one of FW_CTXT_ACTION_* + * @action: action to perform, see &enum iwl_ctxt_action * @mac_type: one of &enum iwl_mac_types * @local_mld_addr: mld address * @reserved_for_local_mld_addr: reserved @@ -292,12 +325,12 @@ struct iwl_mac_config_cmd { __le16 he_ap_support; __le32 eht_support; __le32 nic_not_ack_enabled; - /* MAC_CONTEXT_CONFIG_SPECIFIC_DATA_API_U_VER_1 */ + /* MAC_CONTEXT_CONFIG_SPECIFIC_DATA_API_U_VER_2 */ union { struct iwl_mac_client_data client; struct iwl_mac_p2p_dev_data p2p_dev; }; -} __packed; /* MAC_CONTEXT_CONFIG_CMD_API_S_VER_1 */ +} __packed; /* MAC_CONTEXT_CONFIG_CMD_API_S_VER_2 */ /** * enum iwl_link_ctx_modify_flags - indicate to the fw what fields are being @@ -390,7 +423,7 @@ enum iwl_link_ctx_flags { * in MLD API * ( LINK_CONFIG_CMD =0x9 ) * - * @action: action to perform, one of FW_CTXT_ACTION_* + * @action: action to perform, see &enum iwl_ctxt_action * @link_id: the id of the link that this cmd configures * @mac_id: interface ID. Relevant only if action is FW_CTXT_ACTION_ADD * @phy_id: PHY index. Can be changed only if the link was inactive @@ -430,6 +463,7 @@ enum iwl_link_ctx_flags { * @reserved_for_ref_bssid_addr: reserved * @bssid_index: index of the associated VAP * @bss_color: 11ax AP ID that is used in the HE SIG-A to mark inter BSS frame + * @spec_link_id: link_id as the AP knows it * @reserved: alignment * @ibss_bssid_addr: bssid for ibss * @reserved_for_ibss_bssid_addr: reserved @@ -469,7 +503,8 @@ struct iwl_link_config_cmd { __le16 reserved_for_ref_bssid_addr; u8 bssid_index; u8 bss_color; - u8 reserved[2]; + u8 spec_link_id; + u8 reserved; u8 ibss_bssid_addr[6]; __le16 reserved_for_ibss_bssid_addr; __le32 reserved1[8]; diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/mac.h b/drivers/net/wireless/intel/iwlwifi/fw/api/mac.h index e3eda251c728..55882190251c 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/mac.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/mac.h @@ -295,7 +295,7 @@ struct iwl_ac_qos { * struct iwl_mac_ctx_cmd - command structure to configure MAC contexts * ( MAC_CONTEXT_CMD = 0x28 ) * @id_and_color: ID and color of the MAC - * @action: action to perform, one of FW_CTXT_ACTION_* + * @action: action to perform, see &enum iwl_ctxt_action * @mac_type: one of &enum iwl_mac_types * @tsf_id: TSF HW timer, one of &enum iwl_tsf_id * @node_addr: MAC address @@ -353,7 +353,7 @@ struct iwl_nonqos_seq_query_cmd { } __packed; /* NON_QOS_TX_COUNTER_GET_SET_API_S_VER_1 */ /** - * struct iwl_missed_beacons_notif - information on missed beacons + * struct iwl_missed_beacons_notif_ver_3 - information on missed beacons * ( MISSED_BEACONS_NOTIFICATION = 0xa2 ) * @mac_id: interface ID * @consec_missed_beacons_since_last_rx: number of consecutive missed @@ -362,7 +362,7 @@ struct iwl_nonqos_seq_query_cmd { * @num_expected_beacons: number of expected beacons * @num_recvd_beacons: number of received beacons */ -struct iwl_missed_beacons_notif { +struct iwl_missed_beacons_notif_ver_3 { __le32 mac_id; __le32 consec_missed_beacons_since_last_rx; __le32 consec_missed_beacons; @@ -371,6 +371,24 @@ struct iwl_missed_beacons_notif { } __packed; /* MISSED_BEACON_NTFY_API_S_VER_3 */ /** + * struct iwl_missed_beacons_notif - information on missed beacons + * ( MISSED_BEACONS_NOTIFICATION = 0xa2 ) + * @link_id: fw link ID + * @consec_missed_beacons_since_last_rx: number of consecutive missed + * beacons since last RX. + * @consec_missed_beacons: number of consecutive missed beacons + * @num_expected_beacons: number of expected beacons + * @num_recvd_beacons: number of received beacons + */ +struct iwl_missed_beacons_notif { + __le32 link_id; + __le32 consec_missed_beacons_since_last_rx; + __le32 consec_missed_beacons; + __le32 num_expected_beacons; + __le32 num_recvd_beacons; +} __packed; /* MISSED_BEACON_NTFY_API_S_VER_4 */ + +/** * struct iwl_he_backoff_conf - used for backoff configuration * Per each trigger-based AC, (set by MU EDCA Parameter set info-element) * used for backoff configuration of TXF5..TXF8 trigger based. 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 91bfde6d5367..71cce6dfeaf9 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h @@ -17,7 +17,12 @@ enum iwl_regulatory_and_nvm_subcmd_ids { NVM_ACCESS_COMPLETE = 0x0, /** - * @LARI_CONFIG_CHANGE: &struct iwl_lari_config_change_cmd + * @LARI_CONFIG_CHANGE: &struct iwl_lari_config_change_cmd_v1, + * &struct iwl_lari_config_change_cmd_v2, + * &struct iwl_lari_config_change_cmd_v3, + * &struct iwl_lari_config_change_cmd_v4, + * &struct iwl_lari_config_change_cmd_v5 or + * &struct iwl_lari_config_change_cmd_v6 */ LARI_CONFIG_CHANGE = 0x1, @@ -29,12 +34,12 @@ enum iwl_regulatory_and_nvm_subcmd_ids { NVM_GET_INFO = 0x2, /** - * @TAS_CONFIG: &struct iwl_tas_config_cmd + * @TAS_CONFIG: &union iwl_tas_config_cmd */ TAS_CONFIG = 0x3, /** - * @SAR_OFFSET_MAPPING_TABLE_CMD: &iwl_sar_offset_mapping_cmd + * @SAR_OFFSET_MAPPING_TABLE_CMD: &struct iwl_sar_offset_mapping_cmd */ SAR_OFFSET_MAPPING_TABLE_CMD = 0x4, diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/offload.h b/drivers/net/wireless/intel/iwlwifi/fw/api/offload.h index a0123f81f5d8..898bf351f6e4 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/offload.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/offload.h @@ -28,7 +28,8 @@ enum iwl_prot_offload_subcmd_ids { D3_END_NOTIFICATION = 0xFE, /** - * @STORED_BEACON_NTF: &struct iwl_stored_beacon_notif + * @STORED_BEACON_NTF: &struct iwl_stored_beacon_notif_v2 or + * &struct iwl_stored_beacon_notif_v3 */ STORED_BEACON_NTF = 0xFF, }; diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/phy-ctxt.h b/drivers/net/wireless/intel/iwlwifi/fw/api/phy-ctxt.h index 2f7d8558becd..8fe42cff1102 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/phy-ctxt.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/phy-ctxt.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2012-2014, 2018, 2020-2021 Intel Corporation + * Copyright (C) 2012-2014, 2018, 2020-2022 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -116,7 +116,7 @@ struct iwl_phy_context_cmd_tail { * struct iwl_phy_context_cmd - config of the PHY context * ( PHY_CONTEXT_CMD = 0x8 ) * @id_and_color: ID and color of the relevant Binding - * @action: action to perform, one of FW_CTXT_ACTION_* + * @action: action to perform, see &enum iwl_ctxt_action * @apply_time: 0 means immediate apply and context switch. * other value means apply new params after X usecs * @tx_param_color: ??? @@ -138,7 +138,7 @@ struct iwl_phy_context_cmd_v1 { * struct iwl_phy_context_cmd - config of the PHY context * ( PHY_CONTEXT_CMD = 0x8 ) * @id_and_color: ID and color of the relevant Binding - * @action: action to perform, one of FW_CTXT_ACTION_* + * @action: action to perform, see &enum iwl_ctxt_action * @lmac_id: the lmac id the phy context belongs to * @ci: channel info * @rxchain_info: ??? diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/phy.h b/drivers/net/wireless/intel/iwlwifi/fw/api/phy.h index b1b9c29859c1..5a3f30e5e06d 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/phy.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/phy.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2012-2014, 2019-2021 Intel Corporation + * Copyright (C) 2012-2014, 2019-2022 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -29,12 +29,16 @@ enum iwl_phy_ops_subcmd_ids { TEMP_REPORTING_THRESHOLDS_CMD = 0x04, /** - * @PER_CHAIN_LIMIT_OFFSET_CMD: &struct iwl_geo_tx_power_profiles_cmd + * @PER_CHAIN_LIMIT_OFFSET_CMD: &struct iwl_geo_tx_power_profiles_cmd_v1, + * &struct iwl_geo_tx_power_profiles_cmd_v2, + * &struct iwl_geo_tx_power_profiles_cmd_v3, + * &struct iwl_geo_tx_power_profiles_cmd_v4 or + * &struct iwl_geo_tx_power_profiles_cmd_v5 */ PER_CHAIN_LIMIT_OFFSET_CMD = 0x05, /** - * @PER_PLATFORM_ANT_GAIN_CMD: &struct iwl_ppag_table_cmd + * @PER_PLATFORM_ANT_GAIN_CMD: &union iwl_ppag_table_cmd */ PER_PLATFORM_ANT_GAIN_CMD = 0x07, diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/power.h b/drivers/net/wireless/intel/iwlwifi/fw/api/power.h index f92cac1da764..85d89f559f6c 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/power.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/power.h @@ -537,7 +537,7 @@ union iwl_ppag_table_cmd { struct iwl_sar_offset_mapping_cmd { u8 offset_map[MCC_TO_SAR_OFFSET_TABLE_ROW_SIZE] [MCC_TO_SAR_OFFSET_TABLE_COL_SIZE]; - u16 reserved; + __le16 reserved; } __packed; /*SAR_OFFSET_MAPPING_TABLE_CMD_API_S*/ /** diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h b/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h index fdd8b01f09e4..67af922fd3ba 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h @@ -367,8 +367,8 @@ enum iwl_rx_phy_eht_data1 { /* number of EHT-LTF symbols 0 - 1 EHT-LTF, 1 - 2 EHT-LTFs, 2 - 4 EHT-LTFs, * 3 - 6 EHT-LTFs, 4 - 8 EHT-LTFs */ IWL_RX_PHY_DATA1_EHT_SIG_LTF_NUM = 0x000000e0, - IWL_RX_PHY_DATA1_EHT_B0 = 0x00000100, - IWL_RX_PHY_DATA1_EHT_RU_B1_B7_ALLOC = 0x0000fe00, + IWL_RX_PHY_DATA1_EHT_RU_ALLOC_B0 = 0x00000100, + IWL_RX_PHY_DATA1_EHT_RU_ALLOC_B1_B7 = 0x0000fe00, }; /* goes into Metadata DW 7 */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/time-event.h b/drivers/net/wireless/intel/iwlwifi/fw/api/time-event.h index 904cd78a9fa0..7cc706731d70 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/time-event.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/time-event.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2012-2014, 2018-2020 Intel Corporation + * Copyright (C) 2012-2014, 2018-2020, 2022 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -292,7 +292,7 @@ struct iwl_hs20_roc_req_tail { * ( HOT_SPOT_CMD 0x53 ) * * @id_and_color: ID and color of the MAC - * @action: action to perform, one of FW_CTXT_ACTION_* + * @action: action to perform, see &enum iwl_ctxt_action * @event_unique_id: If the action FW_CTXT_ACTION_REMOVE then the * event_unique_id should be the id of the time event assigned by ucode. * Otherwise ignore the event_unique_id. @@ -377,7 +377,8 @@ enum iwl_mvm_session_prot_conf_id { * struct iwl_mvm_session_prot_cmd - configure a session protection * @id_and_color: the id and color of the mac for which this session protection * is sent - * @action: can be either FW_CTXT_ACTION_ADD or FW_CTXT_ACTION_REMOVE + * @action: can be either FW_CTXT_ACTION_ADD or FW_CTXT_ACTION_REMOVE, + * see &enum iwl_ctxt_action * @conf_id: see &enum iwl_mvm_session_prot_conf_id * @duration_tu: the duration of the whole protection in TUs. * @repetition_count: not used diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c index 55219974b92b..3c5a43a619c6 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c @@ -2034,7 +2034,6 @@ static u32 iwl_dump_ini_imr_get_size(struct iwl_fw_runtime *fwrt, struct iwl_dump_ini_region_data *reg_data) { - u32 size = 0; u32 ranges = 0; u32 imr_enable = fwrt->trans->dbg.imr_data.imr_enable; u32 imr_size = fwrt->trans->dbg.imr_data.imr_size; @@ -2044,17 +2043,16 @@ iwl_dump_ini_imr_get_size(struct iwl_fw_runtime *fwrt, IWL_DEBUG_INFO(fwrt, "WRT: Invalid imr data enable: %d, imr_size: %d, sram_size: %d\n", imr_enable, imr_size, sram_size); - return size; + return 0; } - size = imr_size; ranges = iwl_dump_ini_imr_ranges(fwrt, reg_data); - if (!size && !ranges) { - IWL_ERR(fwrt, "WRT: imr_size :=%d, ranges :=%d\n", size, ranges); + if (!ranges) { + IWL_ERR(fwrt, "WRT: ranges :=%d\n", ranges); return 0; } - size += sizeof(struct iwl_fw_ini_error_dump) + + imr_size += sizeof(struct iwl_fw_ini_error_dump) + ranges * sizeof(struct iwl_fw_ini_error_dump_range); - return size; + return imr_size; } /** diff --git a/drivers/net/wireless/intel/iwlwifi/fw/file.h b/drivers/net/wireless/intel/iwlwifi/fw/file.h index cddf09d6be1c..a78b68c2ae3d 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/file.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/file.h @@ -323,6 +323,7 @@ typedef unsigned int __bitwise iwl_ucode_tlv_capa_t; * is supported. * @IWL_UCODE_TLV_CAPA_BT_COEX_RRC: supports BT Coex RRC * @IWL_UCODE_TLV_CAPA_GSCAN_SUPPORT: supports gscan (no longer used) + * @IWL_UCODE_TLV_CAPA_FRAGMENTED_PNVM_IMG: supports fragmented PNVM image * @IWL_UCODE_TLV_CAPA_SOC_LATENCY_SUPPORT: the firmware supports setting * stabilization latency for SoCs. * @IWL_UCODE_TLV_CAPA_STA_PM_NOTIF: firmware will send STA PM notification @@ -398,6 +399,7 @@ enum iwl_ucode_tlv_capa { IWL_UCODE_TLV_CAPA_GSCAN_SUPPORT = (__force iwl_ucode_tlv_capa_t)31, /* set 1 */ + IWL_UCODE_TLV_CAPA_FRAGMENTED_PNVM_IMG = (__force iwl_ucode_tlv_capa_t)32, IWL_UCODE_TLV_CAPA_SOC_LATENCY_SUPPORT = (__force iwl_ucode_tlv_capa_t)37, IWL_UCODE_TLV_CAPA_STA_PM_NOTIF = (__force iwl_ucode_tlv_capa_t)38, IWL_UCODE_TLV_CAPA_BINDING_CDB_SUPPORT = (__force iwl_ucode_tlv_capa_t)39, @@ -462,6 +464,9 @@ enum iwl_ucode_tlv_capa { IWL_UCODE_TLV_CAPA_BIGTK_TX_SUPPORT = (__force iwl_ucode_tlv_capa_t)109, IWL_UCODE_TLV_CAPA_MLD_API_SUPPORT = (__force iwl_ucode_tlv_capa_t)110, IWL_UCODE_TLV_CAPA_SCAN_DONT_TOGGLE_ANT = (__force iwl_ucode_tlv_capa_t)111, + IWL_UCODE_TLV_CAPA_PPAG_CHINA_BIOS_SUPPORT = (__force iwl_ucode_tlv_capa_t)112, + IWL_UCODE_TLV_CAPA_OFFLOAD_REJ_BTM_SUPPORT = (__force iwl_ucode_tlv_capa_t)113, + IWL_UCODE_TLV_CAPA_STA_EXP_MFP_SUPPORT = (__force iwl_ucode_tlv_capa_t)114, #ifdef __CHECKER__ /* sparse says it cannot increment the previous enum member */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c index c6f2672fdc73..650e4bde9c17 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright(c) 2020-2022 Intel Corporation + * Copyright(c) 2020-2023 Intel Corporation */ #include "iwl-drv.h" @@ -31,18 +31,18 @@ static bool iwl_pnvm_complete_fn(struct iwl_notif_wait_data *notif_wait, } static int iwl_pnvm_handle_section(struct iwl_trans *trans, const u8 *data, - size_t len) + size_t len, + struct iwl_pnvm_image *pnvm_data) { const struct iwl_ucode_tlv *tlv; u32 sha1 = 0; u16 mac_type = 0, rf_id = 0; - u8 *pnvm_data = NULL, *tmp; bool hw_match = false; - u32 size = 0; - int ret; IWL_DEBUG_FW(trans, "Handling PNVM section\n"); + memset(pnvm_data, 0, sizeof(*pnvm_data)); + while (len >= sizeof(*tlv)) { u32 tlv_len, tlv_type; @@ -55,8 +55,7 @@ static int iwl_pnvm_handle_section(struct iwl_trans *trans, const u8 *data, if (len < tlv_len) { IWL_ERR(trans, "invalid TLV len: %zd/%u\n", len, tlv_len); - ret = -EINVAL; - goto out; + return -EINVAL; } data += sizeof(*tlv); @@ -75,6 +74,7 @@ static int iwl_pnvm_handle_section(struct iwl_trans *trans, const u8 *data, IWL_DEBUG_FW(trans, "Got IWL_UCODE_TLV_PNVM_VERSION %0x\n", sha1); + pnvm_data->version = sha1; break; case IWL_UCODE_TLV_HW_TYPE: if (tlv_len < 2 * sizeof(__le16)) { @@ -112,26 +112,26 @@ static int iwl_pnvm_handle_section(struct iwl_trans *trans, const u8 *data, break; } - IWL_DEBUG_FW(trans, "Adding data (size %d)\n", - data_len); - - tmp = krealloc(pnvm_data, size + data_len, GFP_KERNEL); - if (!tmp) { + if (pnvm_data->n_chunks == IPC_DRAM_MAP_ENTRY_NUM_MAX) { IWL_DEBUG_FW(trans, - "Couldn't allocate (more) pnvm_data\n"); - - ret = -ENOMEM; - goto out; + "too many payloads to allocate in DRAM.\n"); + return -EINVAL; } - pnvm_data = tmp; - - memcpy(pnvm_data + size, section->data, data_len); + IWL_DEBUG_FW(trans, "Adding data (size %d)\n", + data_len); - size += data_len; + pnvm_data->chunks[pnvm_data->n_chunks].data = section->data; + pnvm_data->chunks[pnvm_data->n_chunks].len = data_len; + pnvm_data->n_chunks++; break; } + case IWL_UCODE_TLV_MEM_DESC: + if (iwl_uefi_handle_tlv_mem_desc(trans, data, tlv_len, + pnvm_data)) + return -EINVAL; + break; case IWL_UCODE_TLV_PNVM_SKU: IWL_DEBUG_FW(trans, "New PNVM section started, stop parsing.\n"); @@ -152,26 +152,20 @@ done: "HW mismatch, skipping PNVM section (need mac_type 0x%x rf_id 0x%x)\n", CSR_HW_REV_TYPE(trans->hw_rev), CSR_HW_RFID_TYPE(trans->hw_rf_id)); - ret = -ENOENT; - goto out; + return -ENOENT; } - if (!size) { + if (!pnvm_data->n_chunks) { IWL_DEBUG_FW(trans, "Empty PNVM, skipping.\n"); - ret = -ENOENT; - goto out; + return -ENOENT; } - IWL_INFO(trans, "loaded PNVM version %08x\n", sha1); - - ret = iwl_trans_set_pnvm(trans, pnvm_data, size); -out: - kfree(pnvm_data); - return ret; + return 0; } static int iwl_pnvm_parse(struct iwl_trans *trans, const u8 *data, - size_t len) + size_t len, + struct iwl_pnvm_image *pnvm_data) { const struct iwl_ucode_tlv *tlv; @@ -212,7 +206,8 @@ static int iwl_pnvm_parse(struct iwl_trans *trans, const u8 *data, trans->sku_id[2] == le32_to_cpu(sku_id->data[2])) { int ret; - ret = iwl_pnvm_handle_section(trans, data, len); + ret = iwl_pnvm_handle_section(trans, data, len, + pnvm_data); if (!ret) return 0; } else { @@ -255,89 +250,136 @@ static int iwl_pnvm_get_from_fs(struct iwl_trans *trans, u8 **data, size_t *len) return 0; } -int iwl_pnvm_load(struct iwl_trans *trans, - struct iwl_notif_wait_data *notif_wait) +static u8 *iwl_get_pnvm_image(struct iwl_trans *trans_p, size_t *len) { - u8 *data; - size_t len; struct pnvm_sku_package *package; - struct iwl_notification_wait pnvm_wait; - static const u16 ntf_cmds[] = { WIDE_ID(REGULATORY_AND_NVM_GROUP, - PNVM_INIT_COMPLETE_NTFY) }; - int ret; - - /* if the SKU_ID is empty, there's nothing to do */ - if (!trans->sku_id[0] && !trans->sku_id[1] && !trans->sku_id[2]) - return 0; - - /* - * If we already loaded (or tried to load) it before, we just - * need to set it again. - */ - if (trans->pnvm_loaded) { - ret = iwl_trans_set_pnvm(trans, NULL, 0); - if (ret) - return ret; - goto skip_parse; - } + u8 *image = NULL; /* First attempt to get the PNVM from BIOS */ - package = iwl_uefi_get_pnvm(trans, &len); + package = iwl_uefi_get_pnvm(trans_p, len); if (!IS_ERR_OR_NULL(package)) { - if (len >= sizeof(*package)) { + if (*len >= sizeof(*package)) { /* we need only the data */ - len -= sizeof(*package); - data = kmemdup(package->data, len, GFP_KERNEL); - } else { - data = NULL; + *len -= sizeof(*package); + image = kmemdup(package->data, *len, GFP_KERNEL); } - /* free package regardless of whether kmemdup succeeded */ kfree(package); - - if (data) - goto parse; + if (image) + return image; } /* If it's not available, try from the filesystem */ - ret = iwl_pnvm_get_from_fs(trans, &data, &len); + if (iwl_pnvm_get_from_fs(trans_p, &image, len)) + return NULL; + return image; +} + +static void iwl_pnvm_load_pnvm_to_trans(struct iwl_trans *trans, + const struct iwl_ucode_capabilities *capa) +{ + struct iwl_pnvm_image *pnvm_data = NULL; + u8 *data = NULL; + size_t length; + int ret; + + /* failed to get/parse the image in the past, no use trying again */ + if (trans->fail_to_parse_pnvm_image) + return; + + if (trans->pnvm_loaded) + goto set; + + data = iwl_get_pnvm_image(trans, &length); + if (!data) { + trans->fail_to_parse_pnvm_image = true; + return; + } + + pnvm_data = kzalloc(sizeof(*pnvm_data), GFP_KERNEL); + if (!pnvm_data) + goto free; + + ret = iwl_pnvm_parse(trans, data, length, pnvm_data); if (ret) { - /* - * Pretend we've loaded it - at least we've tried and - * couldn't load it at all, so there's no point in - * trying again over and over. - */ - trans->pnvm_loaded = true; - - goto skip_parse; + trans->fail_to_parse_pnvm_image = true; + goto free; } -parse: - iwl_pnvm_parse(trans, data, len); + ret = iwl_trans_load_pnvm(trans, pnvm_data, capa); + if (ret) + goto free; + IWL_INFO(trans, "loaded PNVM version %08x\n", pnvm_data->version); +set: + iwl_trans_set_pnvm(trans, capa); +free: kfree(data); + kfree(pnvm_data); +} -skip_parse: - /* now try to get the reduce power table, if not loaded yet */ - if (!trans->reduce_power_loaded) { - data = iwl_uefi_get_reduced_power(trans, &len); - if (IS_ERR_OR_NULL(data)) { - /* - * Pretend we've loaded it - at least we've tried and - * couldn't load it at all, so there's no point in - * trying again over and over. - */ - trans->reduce_power_loaded = true; - } else { - ret = iwl_trans_set_reduce_power(trans, data, len); - if (ret) - IWL_DEBUG_FW(trans, - "Failed to set reduce power table %d\n", - ret); - kfree(data); - } +static void +iwl_pnvm_load_reduce_power_to_trans(struct iwl_trans *trans, + const struct iwl_ucode_capabilities *capa) +{ + struct iwl_pnvm_image *pnvm_data = NULL; + u8 *data = NULL; + size_t length; + int ret; + + if (trans->failed_to_load_reduce_power_image) + return; + + if (trans->reduce_power_loaded) + goto set; + + data = iwl_uefi_get_reduced_power(trans, &length); + if (IS_ERR(data)) { + trans->failed_to_load_reduce_power_image = true; + return; } + pnvm_data = kzalloc(sizeof(*pnvm_data), GFP_KERNEL); + if (!pnvm_data) + goto free; + + ret = iwl_uefi_reduce_power_parse(trans, data, length, pnvm_data); + if (ret) { + trans->failed_to_load_reduce_power_image = true; + goto free; + } + + ret = iwl_trans_load_reduce_power(trans, pnvm_data, capa); + if (ret) { + IWL_DEBUG_FW(trans, + "Failed to load reduce power table %d\n", + ret); + trans->failed_to_load_reduce_power_image = true; + goto free; + } + +set: + iwl_trans_set_reduce_power(trans, capa); +free: + kfree(data); + kfree(pnvm_data); +} + +int iwl_pnvm_load(struct iwl_trans *trans, + struct iwl_notif_wait_data *notif_wait, + const struct iwl_ucode_capabilities *capa) +{ + struct iwl_notification_wait pnvm_wait; + static const u16 ntf_cmds[] = { WIDE_ID(REGULATORY_AND_NVM_GROUP, + PNVM_INIT_COMPLETE_NTFY) }; + + /* if the SKU_ID is empty, there's nothing to do */ + if (!trans->sku_id[0] && !trans->sku_id[1] && !trans->sku_id[2]) + return 0; + + iwl_pnvm_load_pnvm_to_trans(trans, capa); + iwl_pnvm_load_reduce_power_to_trans(trans, capa); + iwl_init_notification_wait(notif_wait, &pnvm_wait, ntf_cmds, ARRAY_SIZE(ntf_cmds), iwl_pnvm_complete_fn, trans); diff --git a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.h b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.h index 203c367dd4de..4e10baa01738 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /****************************************************************************** * - * Copyright(c) 2020-2021 Intel Corporation + * Copyright(c) 2020-2022 Intel Corporation * *****************************************************************************/ @@ -15,7 +15,8 @@ #define MAX_PNVM_NAME 64 int iwl_pnvm_load(struct iwl_trans *trans, - struct iwl_notif_wait_data *notif_wait); + struct iwl_notif_wait_data *notif_wait, + const struct iwl_ucode_capabilities *capa); static inline void iwl_pnvm_get_fs_name(struct iwl_trans *trans, diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c index 01afea33c38c..9877988db0d2 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright(c) 2021-2022 Intel Corporation + * Copyright(c) 2021-2023 Intel Corporation */ #include "iwl-drv.h" @@ -17,52 +17,109 @@ 0xb2, 0xec, 0xf5, 0xa3, \ 0x59, 0x4f, 0x4a, 0xea) -void *iwl_uefi_get_pnvm(struct iwl_trans *trans, size_t *len) +struct iwl_uefi_pnvm_mem_desc { + __le32 addr; + __le32 size; + const u8 data[]; +} __packed; + +static void *iwl_uefi_get_variable(efi_char16_t *name, efi_guid_t *guid, + unsigned long *data_size) { - void *data; - unsigned long package_size; efi_status_t status; + void *data; - *len = 0; + if (!data_size) + return ERR_PTR(-EINVAL); if (!efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE)) return ERR_PTR(-ENODEV); - /* - * TODO: we hardcode a maximum length here, because reading - * from the UEFI is not working. To implement this properly, - * we have to call efivar_entry_size(). - */ - package_size = IWL_HARDCODED_PNVM_SIZE; + /* first call with NULL data to get the exact entry size */ + *data_size = 0; + status = efi.get_variable(name, guid, NULL, data_size, NULL); + if (status != EFI_BUFFER_TOO_SMALL || !*data_size) + return ERR_PTR(-EIO); - data = kmalloc(package_size, GFP_KERNEL); + data = kmalloc(*data_size, GFP_KERNEL); if (!data) return ERR_PTR(-ENOMEM); - status = efi.get_variable(IWL_UEFI_OEM_PNVM_NAME, &IWL_EFI_VAR_GUID, - NULL, &package_size, data); + status = efi.get_variable(name, guid, NULL, data_size, data); if (status != EFI_SUCCESS) { - IWL_DEBUG_FW(trans, - "PNVM UEFI variable not found 0x%lx (len %lu)\n", - status, package_size); kfree(data); return ERR_PTR(-ENOENT); } + return data; +} + +void *iwl_uefi_get_pnvm(struct iwl_trans *trans, size_t *len) +{ + unsigned long package_size; + void *data; + + *len = 0; + + data = iwl_uefi_get_variable(IWL_UEFI_OEM_PNVM_NAME, &IWL_EFI_VAR_GUID, + &package_size); + if (IS_ERR(data)) { + IWL_DEBUG_FW(trans, + "PNVM UEFI variable not found 0x%lx (len %lu)\n", + PTR_ERR(data), package_size); + return data; + } + IWL_DEBUG_FW(trans, "Read PNVM from UEFI with size %lu\n", package_size); *len = package_size; return data; } -static void *iwl_uefi_reduce_power_section(struct iwl_trans *trans, - const u8 *data, size_t len) +int iwl_uefi_handle_tlv_mem_desc(struct iwl_trans *trans, const u8 *data, + u32 tlv_len, struct iwl_pnvm_image *pnvm_data) +{ + const struct iwl_uefi_pnvm_mem_desc *desc = (const void *)data; + u32 data_len; + + if (tlv_len < sizeof(*desc)) { + IWL_DEBUG_FW(trans, "TLV len (%d) is too small\n", tlv_len); + return -EINVAL; + } + + data_len = tlv_len - sizeof(*desc); + + IWL_DEBUG_FW(trans, + "Handle IWL_UCODE_TLV_MEM_DESC, len %d data_len %d\n", + tlv_len, data_len); + + if (le32_to_cpu(desc->size) != data_len) { + IWL_DEBUG_FW(trans, "invalid mem desc size %d\n", desc->size); + return -EINVAL; + } + + if (pnvm_data->n_chunks == IPC_DRAM_MAP_ENTRY_NUM_MAX) { + IWL_DEBUG_FW(trans, "too many payloads to allocate in DRAM.\n"); + return -EINVAL; + } + + IWL_DEBUG_FW(trans, "Adding data (size %d)\n", data_len); + + pnvm_data->chunks[pnvm_data->n_chunks].data = desc->data; + pnvm_data->chunks[pnvm_data->n_chunks].len = data_len; + pnvm_data->n_chunks++; + + return 0; +} + +static int iwl_uefi_reduce_power_section(struct iwl_trans *trans, + const u8 *data, size_t len, + struct iwl_pnvm_image *pnvm_data) { const struct iwl_ucode_tlv *tlv; - u8 *reduce_power_data = NULL, *tmp; - u32 size = 0; IWL_DEBUG_FW(trans, "Handling REDUCE_POWER section\n"); + memset(pnvm_data, 0, sizeof(*pnvm_data)); while (len >= sizeof(*tlv)) { u32 tlv_len, tlv_type; @@ -76,39 +133,17 @@ static void *iwl_uefi_reduce_power_section(struct iwl_trans *trans, if (len < tlv_len) { IWL_ERR(trans, "invalid TLV len: %zd/%u\n", len, tlv_len); - kfree(reduce_power_data); - reduce_power_data = ERR_PTR(-EINVAL); - goto out; + return -EINVAL; } data += sizeof(*tlv); switch (tlv_type) { - case IWL_UCODE_TLV_MEM_DESC: { - IWL_DEBUG_FW(trans, - "Got IWL_UCODE_TLV_MEM_DESC len %d\n", - tlv_len); - - IWL_DEBUG_FW(trans, "Adding data (size %d)\n", tlv_len); - - tmp = krealloc(reduce_power_data, size + tlv_len, GFP_KERNEL); - if (!tmp) { - IWL_DEBUG_FW(trans, - "Couldn't allocate (more) reduce_power_data\n"); - - kfree(reduce_power_data); - reduce_power_data = ERR_PTR(-ENOMEM); - goto out; - } - - reduce_power_data = tmp; - - memcpy(reduce_power_data + size, data, tlv_len); - - size += tlv_len; - + case IWL_UCODE_TLV_MEM_DESC: + if (iwl_uefi_handle_tlv_mem_desc(trans, data, tlv_len, + pnvm_data)) + return -EINVAL; break; - } case IWL_UCODE_TLV_PNVM_SKU: IWL_DEBUG_FW(trans, "New REDUCE_POWER section started, stop parsing.\n"); @@ -124,27 +159,18 @@ static void *iwl_uefi_reduce_power_section(struct iwl_trans *trans, } done: - if (!size) { + if (!pnvm_data->n_chunks) { IWL_DEBUG_FW(trans, "Empty REDUCE_POWER, skipping.\n"); - /* Better safe than sorry, but 'reduce_power_data' should - * always be NULL if !size. - */ - kfree(reduce_power_data); - reduce_power_data = ERR_PTR(-ENOENT); - goto out; + return -ENOENT; } - - IWL_INFO(trans, "loaded REDUCE_POWER\n"); - -out: - return reduce_power_data; + return 0; } -static void *iwl_uefi_reduce_power_parse(struct iwl_trans *trans, - const u8 *data, size_t len) +int iwl_uefi_reduce_power_parse(struct iwl_trans *trans, + const u8 *data, size_t len, + struct iwl_pnvm_image *pnvm_data) { const struct iwl_ucode_tlv *tlv; - void *sec_data; IWL_DEBUG_FW(trans, "Parsing REDUCE_POWER data\n"); @@ -160,7 +186,7 @@ static void *iwl_uefi_reduce_power_parse(struct iwl_trans *trans, if (len < tlv_len) { IWL_ERR(trans, "invalid TLV len: %zd/%u\n", len, tlv_len); - return ERR_PTR(-EINVAL); + return -EINVAL; } if (tlv_type == IWL_UCODE_TLV_PNVM_SKU) { @@ -181,11 +207,11 @@ static void *iwl_uefi_reduce_power_parse(struct iwl_trans *trans, if (trans->sku_id[0] == le32_to_cpu(sku_id->data[0]) && trans->sku_id[1] == le32_to_cpu(sku_id->data[1]) && trans->sku_id[2] == le32_to_cpu(sku_id->data[2])) { - sec_data = iwl_uefi_reduce_power_section(trans, - data, - len); - if (!IS_ERR(sec_data)) - return sec_data; + int ret = iwl_uefi_reduce_power_section(trans, + data, len, + pnvm_data); + if (!ret) + return 0; } else { IWL_DEBUG_FW(trans, "SKU ID didn't match!\n"); } @@ -195,51 +221,45 @@ static void *iwl_uefi_reduce_power_parse(struct iwl_trans *trans, } } - return ERR_PTR(-ENOENT); + return -ENOENT; } -void *iwl_uefi_get_reduced_power(struct iwl_trans *trans, size_t *len) +u8 *iwl_uefi_get_reduced_power(struct iwl_trans *trans, size_t *len) { struct pnvm_sku_package *package; - void *data = NULL; unsigned long package_size; - efi_status_t status; + u8 *data; - *len = 0; + package = iwl_uefi_get_variable(IWL_UEFI_REDUCED_POWER_NAME, + &IWL_EFI_VAR_GUID, &package_size); - if (!efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE)) - return ERR_PTR(-ENODEV); - - /* - * TODO: we hardcode a maximum length here, because reading - * from the UEFI is not working. To implement this properly, - * we have to call efivar_entry_size(). - */ - package_size = IWL_HARDCODED_REDUCE_POWER_SIZE; - - package = kmalloc(package_size, GFP_KERNEL); - if (!package) - return ERR_PTR(-ENOMEM); - - status = efi.get_variable(IWL_UEFI_REDUCED_POWER_NAME, &IWL_EFI_VAR_GUID, - NULL, &package_size, package); - if (status != EFI_SUCCESS) { + if (IS_ERR(package)) { IWL_DEBUG_FW(trans, "Reduced Power UEFI variable not found 0x%lx (len %lu)\n", - status, package_size); + PTR_ERR(package), package_size); + return ERR_CAST(package); + } + + if (package_size < sizeof(*package)) { + IWL_DEBUG_FW(trans, + "Invalid Reduced Power UEFI variable len (%lu)\n", + package_size); kfree(package); - return ERR_PTR(-ENOENT); + return ERR_PTR(-EINVAL); } IWL_DEBUG_FW(trans, "Read reduced power from UEFI with size %lu\n", package_size); - *len = package_size; IWL_DEBUG_FW(trans, "rev %d, total_size %d, n_skus %d\n", package->rev, package->total_size, package->n_skus); - data = iwl_uefi_reduce_power_parse(trans, package->data, - *len - sizeof(*package)); + *len = package_size - sizeof(*package); + data = kmemdup(package->data, *len, GFP_KERNEL); + if (!data) { + kfree(package); + return ERR_PTR(-ENOMEM); + } kfree(package); @@ -264,31 +284,27 @@ void iwl_uefi_get_step_table(struct iwl_trans *trans) { struct uefi_cnv_common_step_data *data; unsigned long package_size; - efi_status_t status; int ret; if (trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_AX210) return; - if (!efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE)) - return; + data = iwl_uefi_get_variable(IWL_UEFI_STEP_NAME, &IWL_EFI_VAR_GUID, + &package_size); - /* TODO: we hardcode a maximum length here, because reading - * from the UEFI is not working. To implement this properly, - * we have to call efivar_entry_size(). - */ - package_size = IWL_HARDCODED_STEP_SIZE; - - data = kmalloc(package_size, GFP_KERNEL); - if (!data) + if (IS_ERR(data)) { + IWL_DEBUG_FW(trans, + "STEP UEFI variable not found 0x%lx\n", + PTR_ERR(data)); return; + } - status = efi.get_variable(IWL_UEFI_STEP_NAME, &IWL_EFI_VAR_GUID, - NULL, &package_size, data); - if (status != EFI_SUCCESS) { + if (package_size < sizeof(*data)) { IWL_DEBUG_FW(trans, - "STEP UEFI variable not found 0x%lx\n", status); - goto out_free; + "Invalid STEP table UEFI variable len (%lu)\n", + package_size); + kfree(data); + return; } IWL_DEBUG_FW(trans, "Read STEP from UEFI with size %lu\n", @@ -298,7 +314,6 @@ void iwl_uefi_get_step_table(struct iwl_trans *trans) if (ret < 0) IWL_DEBUG_FW(trans, "Cannot read STEP tables. rev is invalid\n"); -out_free: kfree(data); } IWL_EXPORT_SYMBOL(iwl_uefi_get_step_table); @@ -341,29 +356,26 @@ void iwl_uefi_get_sgom_table(struct iwl_trans *trans, { struct uefi_cnv_wlan_sgom_data *data; unsigned long package_size; - efi_status_t status; int ret; - if (!fwrt->geo_enabled || - !efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE)) + if (!fwrt->geo_enabled) return; - /* TODO: we hardcode a maximum length here, because reading - * from the UEFI is not working. To implement this properly, - * we have to call efivar_entry_size(). - */ - package_size = IWL_HARDCODED_SGOM_SIZE; - - data = kmalloc(package_size, GFP_KERNEL); - if (!data) + data = iwl_uefi_get_variable(IWL_UEFI_SGOM_NAME, &IWL_EFI_VAR_GUID, + &package_size); + if (IS_ERR(data)) { + IWL_DEBUG_FW(trans, + "SGOM UEFI variable not found 0x%lx\n", + PTR_ERR(data)); return; + } - status = efi.get_variable(IWL_UEFI_SGOM_NAME, &IWL_EFI_VAR_GUID, - NULL, &package_size, data); - if (status != EFI_SUCCESS) { + if (package_size < sizeof(*data)) { IWL_DEBUG_FW(trans, - "SGOM UEFI variable not found 0x%lx\n", status); - goto out_free; + "Invalid SGOM table UEFI variable len (%lu)\n", + package_size); + kfree(data); + return; } IWL_DEBUG_FW(trans, "Read SGOM from UEFI with size %lu\n", @@ -373,9 +385,7 @@ void iwl_uefi_get_sgom_table(struct iwl_trans *trans, if (ret < 0) IWL_DEBUG_FW(trans, "Cannot read SGOM tables. rev is invalid\n"); -out_free: kfree(data); - } IWL_EXPORT_SYMBOL(iwl_uefi_get_sgom_table); #endif /* CONFIG_ACPI */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.h b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h index 17089bc74cf9..1369cc4855c3 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright(c) 2021-2022 Intel Corporation + * Copyright(c) 2021-2023 Intel Corporation */ #ifndef __iwl_fw_uefi__ #define __iwl_fw_uefi__ @@ -10,16 +10,7 @@ #define IWL_UEFI_SGOM_NAME L"UefiCnvWlanSarGeoOffsetMapping" #define IWL_UEFI_STEP_NAME L"UefiCnvCommonSTEP" -/* - * TODO: we have these hardcoded values that the caller must pass, - * because reading from the UEFI is not working. To implement this - * properly, we have to change iwl_pnvm_get_from_uefi() to call - * efivar_entry_size() and return the value to the caller instead. - */ -#define IWL_HARDCODED_PNVM_SIZE 4096 -#define IWL_HARDCODED_REDUCE_POWER_SIZE 32768 -#define IWL_HARDCODED_SGOM_SIZE 339 -#define IWL_HARDCODED_STEP_SIZE 6 +#define IWL_SGOM_MAP_SIZE 339 struct pnvm_sku_package { u8 rev; @@ -31,7 +22,7 @@ struct pnvm_sku_package { struct uefi_cnv_wlan_sgom_data { u8 revision; - u8 offset_map[IWL_HARDCODED_SGOM_SIZE - 1]; + u8 offset_map[IWL_SGOM_MAP_SIZE - 1]; } __packed; struct uefi_cnv_common_step_data { @@ -50,24 +41,42 @@ struct uefi_cnv_common_step_data { */ #ifdef CONFIG_EFI void *iwl_uefi_get_pnvm(struct iwl_trans *trans, size_t *len); -void *iwl_uefi_get_reduced_power(struct iwl_trans *trans, size_t *len); +u8 *iwl_uefi_get_reduced_power(struct iwl_trans *trans, size_t *len); +int iwl_uefi_reduce_power_parse(struct iwl_trans *trans, + const u8 *data, size_t len, + struct iwl_pnvm_image *pnvm_data); void iwl_uefi_get_step_table(struct iwl_trans *trans); +int iwl_uefi_handle_tlv_mem_desc(struct iwl_trans *trans, const u8 *data, + u32 tlv_len, struct iwl_pnvm_image *pnvm_data); #else /* CONFIG_EFI */ -static inline -void *iwl_uefi_get_pnvm(struct iwl_trans *trans, size_t *len) +static inline void *iwl_uefi_get_pnvm(struct iwl_trans *trans, size_t *len) { return ERR_PTR(-EOPNOTSUPP); } -static inline -void *iwl_uefi_get_reduced_power(struct iwl_trans *trans, size_t *len) +static inline int +iwl_uefi_reduce_power_parse(struct iwl_trans *trans, + const u8 *data, size_t len, + struct iwl_pnvm_image *pnvm_data) +{ + return -EOPNOTSUPP; +} + +static inline u8 * +iwl_uefi_get_reduced_power(struct iwl_trans *trans, size_t *len) { return ERR_PTR(-EOPNOTSUPP); } -static inline -void iwl_uefi_get_step_table(struct iwl_trans *trans) +static inline void iwl_uefi_get_step_table(struct iwl_trans *trans) +{ +} + +static inline int +iwl_uefi_handle_tlv_mem_desc(struct iwl_trans *trans, const u8 *data, + u32 tlv_len, struct iwl_pnvm_image *pnvm_data) { + return 0; } #endif /* CONFIG_EFI */ |