]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
wifi: iwlwifi: fw: Add TLV support for BIOS revision of command
authorPagadala Yesu Anjaneyulu <pagadala.yesu.anjaneyulu@intel.com>
Fri, 20 Mar 2026 08:09:10 +0000 (10:09 +0200)
committerMiri Korenblit <miriam.rachel.korenblit@intel.com>
Wed, 25 Mar 2026 09:31:57 +0000 (11:31 +0200)
Add support for newer firmware API versions that support
multiple BIOS revisions. Use the new TLV provided by
firmware to determine which BIOS revision it supports.

Future patches will use this information to either
drop commands when the BIOS revision is higher than
supported or convert commands based on the command
specific implementation.

Since we are including now nvm-reg.h in img.h, this causes a
re-definition error of IWL_NUM_CHANNELS which is also defined in
eeprom.c, so rename IWL_NUM_CHANNELS to IWL_NUM_CHANNELS_V2

Signed-off-by: Pagadala Yesu Anjaneyulu <pagadala.yesu.anjaneyulu@intel.com>
Reviewed-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
Link: https://patch.msgid.link/20260320100746.76c8a9589ea0.I7f9157115de702e07511f2c3ed5fcb9ae4c667aa@changeid
drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h
drivers/net/wireless/intel/iwlwifi/fw/file.h
drivers/net/wireless/intel/iwlwifi/fw/img.c
drivers/net/wireless/intel/iwlwifi/fw/img.h
drivers/net/wireless/intel/iwlwifi/iwl-drv.c
drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c

index 25c860a05b0e935668835faeaf95b459269b557e..443a9a416325232cbba132302696ef84bf7cc5ff 100644 (file)
@@ -204,7 +204,7 @@ struct iwl_nvm_get_info_phy {
 } __packed; /* REGULATORY_NVM_GET_INFO_PHY_SKU_SECTION_S_VER_1 */
 
 #define IWL_NUM_CHANNELS_V1    51
-#define IWL_NUM_CHANNELS       110
+#define IWL_NUM_CHANNELS_V2    110
 
 /**
  * struct iwl_nvm_get_info_regulatory_v1 - regulatory information
@@ -227,7 +227,7 @@ struct iwl_nvm_get_info_regulatory_v1 {
 struct iwl_nvm_get_info_regulatory {
        __le32 lar_enabled;
        __le32 n_channels;
-       __le32 channel_profile[IWL_NUM_CHANNELS];
+       __le32 channel_profile[IWL_NUM_CHANNELS_V2];
 } __packed; /* REGULATORY_NVM_GET_INFO_REGULATORY_S_VER_2 */
 
 /**
index 378788de1d74f95b208a29f9d92014e904868208..f7a6f21267e9d148b16c364f8b68698275ec62f5 100644 (file)
@@ -103,6 +103,7 @@ enum iwl_ucode_tlv_type {
        IWL_UCODE_TLV_D3_KEK_KCK_ADDR           = 67,
        IWL_UCODE_TLV_CURRENT_PC                = 68,
        IWL_UCODE_TLV_FSEQ_BIN_VERSION          = 72,
+       IWL_UCODE_TLV_CMD_BIOS_TABLE            = 73,
 
        /* contains sub-sections like PNVM file does (did) */
        IWL_UCODE_TLV_PNVM_DATA                 = 74,
@@ -1040,6 +1041,20 @@ struct iwl_fw_cmd_version {
        u8 notif_ver;
 } __packed;
 
+/**
+ * struct iwl_fw_cmd_bios_table - firmware command BIOS revision entry
+ * @cmd: command ID
+ * @group: group ID
+ * @max_acpi_revision: max supported ACPI revision of command.
+ * @max_uefi_revision: max supported UEFI revision of command.
+ */
+struct iwl_fw_cmd_bios_table {
+       u8 cmd;
+       u8 group;
+       u8 max_acpi_revision;
+       u8 max_uefi_revision;
+} __packed;
+
 struct iwl_fw_tcm_error_addr {
        __le32 addr;
 }; /* FW_TLV_TCM_ERROR_INFO_ADDRS_S */
index c2f4fc83a22cd1660d4fa5abab79b72b143c6539..3cc1e3ae085896a1adda8555bbf56ad18d60b328 100644 (file)
@@ -1,11 +1,41 @@
 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
 /*
  * Copyright(c) 2019 - 2021 Intel Corporation
- * Copyright(c) 2024 Intel Corporation
+ * Copyright(c) 2024 - 2025 Intel Corporation
  */
 #include <fw/api/commands.h>
 #include "img.h"
 
+u8 iwl_fw_lookup_cmd_bios_supported_revision(const struct iwl_fw *fw,
+                                            enum bios_source table_source,
+                                            u32 cmd_id, u8 def)
+{
+       const struct iwl_fw_cmd_bios_table *entry;
+       /* prior to LONG_GROUP, we never used this CMD version API */
+       u8 grp = iwl_cmd_groupid(cmd_id) ?: LONG_GROUP;
+       u8 cmd = iwl_cmd_opcode(cmd_id);
+
+       if (table_source != BIOS_SOURCE_ACPI &&
+           table_source != BIOS_SOURCE_UEFI)
+               return def;
+
+       if (!fw->ucode_capa.cmd_bios_tables ||
+           !fw->ucode_capa.n_cmd_bios_tables)
+               return def;
+
+       entry = fw->ucode_capa.cmd_bios_tables;
+       for (int i = 0; i < fw->ucode_capa.n_cmd_bios_tables; i++, entry++) {
+               if (entry->group == grp && entry->cmd == cmd) {
+                       if (table_source == BIOS_SOURCE_ACPI)
+                               return entry->max_acpi_revision;
+                       return entry->max_uefi_revision;
+               }
+       }
+
+       return def;
+}
+EXPORT_SYMBOL_GPL(iwl_fw_lookup_cmd_bios_supported_revision);
+
 u8 iwl_fw_lookup_cmd_ver(const struct iwl_fw *fw, u32 cmd_id, u8 def)
 {
        const struct iwl_fw_cmd_version *entry;
index 045a3e0094291cd68d1c302543f1cf93da3f5b8e..94113d1db8e13273715c4be557c3edb8f3df60e6 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/types.h>
 
 #include "api/dbg-tlv.h"
+#include "api/nvm-reg.h"
 
 #include "file.h"
 #include "error-dump.h"
@@ -57,6 +58,9 @@ struct iwl_ucode_capabilities {
 
        const struct iwl_fw_cmd_version *cmd_versions;
        u32 n_cmd_versions;
+
+       const struct iwl_fw_cmd_bios_table *cmd_bios_tables;
+       u32 n_cmd_bios_tables;
 };
 
 static inline bool
@@ -274,6 +278,10 @@ iwl_get_ucode_image(const struct iwl_fw *fw, enum iwl_ucode_type ucode_type)
        return &fw->img[ucode_type];
 }
 
+u8 iwl_fw_lookup_cmd_bios_supported_revision(const struct iwl_fw *fw,
+                                            enum bios_source table_source,
+                                            u32 cmd_id, u8 def);
+
 u8 iwl_fw_lookup_cmd_ver(const struct iwl_fw *fw, u32 cmd_id, u8 def);
 
 u8 iwl_fw_lookup_notif_ver(const struct iwl_fw *fw, u8 grp, u8 cmd, u8 def);
index 475b3e417efa89d786d179f2bd73e9255f722df0..4cdd0fe1b788f41a2e80c81e2e1d12ba2c6a0313 100644 (file)
@@ -133,6 +133,7 @@ static void iwl_dealloc_ucode(struct iwl_drv *drv)
        kfree(drv->fw.dbg.mem_tlv);
        kfree(drv->fw.iml);
        kfree(drv->fw.ucode_capa.cmd_versions);
+       kfree(drv->fw.ucode_capa.cmd_bios_tables);
        kfree(drv->fw.phy_integration_ver);
        kfree(drv->trans->dbg.pc_data);
        drv->trans->dbg.pc_data = NULL;
@@ -1426,6 +1427,26 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
                                return -ENOMEM;
                        drv->fw.pnvm_size = tlv_len;
                        break;
+               case IWL_UCODE_TLV_CMD_BIOS_TABLE:
+                       if (tlv_len % sizeof(struct iwl_fw_cmd_bios_table)) {
+                               IWL_ERR(drv,
+                                       "Invalid length for command bios table: %u\n",
+                                       tlv_len);
+                               return -EINVAL;
+                       }
+
+                       if (capa->cmd_bios_tables) {
+                               IWL_ERR(drv, "Duplicate TLV type 0x%02X detected\n",
+                                       tlv_type);
+                               return -EINVAL;
+                       }
+                       capa->cmd_bios_tables = kmemdup(tlv_data, tlv_len,
+                                                       GFP_KERNEL);
+                       if (!capa->cmd_bios_tables)
+                               return -ENOMEM;
+                       capa->n_cmd_bios_tables =
+                               tlv_len / sizeof(struct iwl_fw_cmd_bios_table);
+                       break;
                default:
                        IWL_DEBUG_INFO(drv, "unknown TLV: %d\n", tlv_type);
                        break;
index 6d235c417fdd1ac24474b7cb624055d9dc7d7410..e5b08c4e7f159c485ee1ebb8cb89dd7a4b222208 100644 (file)
@@ -2031,7 +2031,7 @@ struct iwl_nvm_data *iwl_get_nvm(struct iwl_trans *trans,
        if (empty_otp)
                IWL_INFO(trans, "OTP is empty\n");
 
-       nvm = kzalloc_flex(*nvm, channels, IWL_NUM_CHANNELS);
+       nvm = kzalloc_flex(*nvm, channels, IWL_NUM_CHANNELS_V2);
        if (!nvm) {
                ret = -ENOMEM;
                goto out;