]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
wifi: iwlwifi: use PNVM data embedded in .ucode files
authorJohannes Berg <johannes.berg@intel.com>
Wed, 9 Jul 2025 05:16:21 +0000 (08:16 +0300)
committerMiri Korenblit <miriam.rachel.korenblit@intel.com>
Wed, 9 Jul 2025 08:39:28 +0000 (11:39 +0300)
Given compatibility issues with external PNVM data that doesn't match
the firmware it was designed with/for, future firmware releases will
include the PNVM data in the firmware files directly, avoiding those
mismatch issues. Make the driver load and use that embedded PNVM data
in preference of external files, falling back to the external file if
it isn't present.

Co-developed-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
Link: https://patch.msgid.link/20250709081300.c843f77aa2d3.I7200f8dd40ef82aff1f5574fdd3966913cda592c@changeid
drivers/net/wireless/intel/iwlwifi/fw/file.h
drivers/net/wireless/intel/iwlwifi/fw/img.h
drivers/net/wireless/intel/iwlwifi/fw/pnvm.c
drivers/net/wireless/intel/iwlwifi/fw/pnvm.h
drivers/net/wireless/intel/iwlwifi/iwl-drv.c
drivers/net/wireless/intel/iwlwifi/mld/fw.c
drivers/net/wireless/intel/iwlwifi/mvm/fw.c

index 5a1ec880ed7230c3d4ca99bf5ca1805bbd34811a..dc1db563c5eb66dfdd5403ac253dd55726f06534 100644 (file)
@@ -104,6 +104,9 @@ enum iwl_ucode_tlv_type {
        IWL_UCODE_TLV_CURRENT_PC                = 68,
        IWL_UCODE_TLV_FSEQ_BIN_VERSION          = 72,
 
+       /* contains sub-sections like PNVM file does (did) */
+       IWL_UCODE_TLV_PNVM_DATA                 = 74,
+
        IWL_UCODE_TLV_FW_NUM_STATIONS           = IWL_UCODE_TLV_CONST_BASE + 0,
        IWL_UCODE_TLV_FW_NUM_LINKS              = IWL_UCODE_TLV_CONST_BASE + 1,
        IWL_UCODE_TLV_FW_NUM_BEACONS            = IWL_UCODE_TLV_CONST_BASE + 2,
index e055f798a398c8c1bf7e6273485be76677b296f1..5256f20623e90b457cf088bba77cb7ae4c71f84d 100644 (file)
@@ -195,6 +195,8 @@ struct iwl_dump_exclude {
  * @phy_integration_ver_len: length of @phy_integration_ver
  * @dump_excl: image dump exclusion areas for RT image
  * @dump_excl_wowlan: image dump exclusion areas for WoWLAN image
+ * @pnvm_data: PNVM data embedded in the .ucode file, if any
+ * @pnvm_size: size of the embedded PNVM data
  */
 struct iwl_fw {
        u32 ucode_ver;
@@ -227,6 +229,9 @@ struct iwl_fw {
        u32 phy_integration_ver_len;
 
        struct iwl_dump_exclude dump_excl[2], dump_excl_wowlan[2];
+
+       const void *pnvm_data;
+       u32 pnvm_size;
 };
 
 static inline const char *get_fw_dbg_mode_string(int mode)
index 3bcd375995cc423b0d63f82cca95337e129542f5..4d91ae065c8daedd84b2a1686b6d05b84af892e4 100644 (file)
@@ -11,6 +11,7 @@
 #include "fw/api/nvm-reg.h"
 #include "fw/api/alive.h"
 #include "fw/uefi.h"
+#include "fw/img.h"
 
 #define IWL_PNVM_REDUCED_CAP_BIT BIT(25)
 
@@ -264,8 +265,8 @@ static int iwl_pnvm_get_from_fs(struct iwl_trans *trans, u8 **data, size_t *len)
        return 0;
 }
 
-static u8 *iwl_get_pnvm_image(struct iwl_trans *trans_p, size_t *len,
-                             __le32 sku_id[3])
+static const u8 *iwl_get_pnvm_image(struct iwl_trans *trans_p, size_t *len,
+                                   __le32 sku_id[3], const struct iwl_fw *fw)
 {
        struct pnvm_sku_package *package;
        u8 *image = NULL;
@@ -290,6 +291,12 @@ static u8 *iwl_get_pnvm_image(struct iwl_trans *trans_p, size_t *len,
                }
        }
 
+       if (fw->pnvm_data) {
+               *len = fw->pnvm_size;
+
+               return fw->pnvm_data;
+       }
+
        /* If it's not available, or for Intel SKU, try from the filesystem */
        if (iwl_pnvm_get_from_fs(trans_p, &image, len))
                return NULL;
@@ -298,11 +305,11 @@ static u8 *iwl_get_pnvm_image(struct iwl_trans *trans_p, size_t *len,
 
 static void
 iwl_pnvm_load_pnvm_to_trans(struct iwl_trans *trans,
-                           const struct iwl_ucode_capabilities *capa,
+                           const struct iwl_fw *fw,
                            __le32 sku_id[3])
 {
        struct iwl_pnvm_image *pnvm_data = NULL;
-       u8 *data = NULL;
+       const u8 *data = NULL;
        size_t length;
        int ret;
 
@@ -313,7 +320,7 @@ iwl_pnvm_load_pnvm_to_trans(struct iwl_trans *trans,
        if (trans->pnvm_loaded)
                goto set;
 
-       data = iwl_get_pnvm_image(trans, &length, sku_id);
+       data = iwl_get_pnvm_image(trans, &length, sku_id, fw);
        if (!data) {
                trans->fail_to_parse_pnvm_image = true;
                return;
@@ -329,15 +336,17 @@ iwl_pnvm_load_pnvm_to_trans(struct iwl_trans *trans,
                goto free;
        }
 
-       ret = iwl_trans_load_pnvm(trans, pnvm_data, capa);
+       ret = iwl_trans_load_pnvm(trans, pnvm_data, &fw->ucode_capa);
        if (ret)
                goto free;
        IWL_DEBUG_INFO(trans, "loaded PNVM version %08x\n", pnvm_data->version);
 
 set:
-       iwl_trans_set_pnvm(trans, capa);
+       iwl_trans_set_pnvm(trans, &fw->ucode_capa);
 free:
-       kvfree(data);
+       /* free only if it was allocated, i.e. not just embedded PNVM data */
+       if (data != fw->pnvm_data)
+               kvfree(data);
        kfree(pnvm_data);
 }
 
@@ -392,8 +401,7 @@ free:
 
 int iwl_pnvm_load(struct iwl_trans *trans,
                  struct iwl_notif_wait_data *notif_wait,
-                 const struct iwl_ucode_capabilities *capa,
-                 __le32 sku_id[3])
+                 const struct iwl_fw *fw, __le32 sku_id[3])
 {
        struct iwl_notification_wait pnvm_wait;
        static const u16 ntf_cmds[] = { WIDE_ID(REGULATORY_AND_NVM_GROUP,
@@ -403,8 +411,8 @@ int iwl_pnvm_load(struct iwl_trans *trans,
        if (!sku_id[0] && !sku_id[1] && !sku_id[2])
                return 0;
 
-       iwl_pnvm_load_pnvm_to_trans(trans, capa, sku_id);
-       iwl_pnvm_load_reduce_power_to_trans(trans, capa, sku_id);
+       iwl_pnvm_load_pnvm_to_trans(trans, fw, sku_id);
+       iwl_pnvm_load_reduce_power_to_trans(trans, &fw->ucode_capa, sku_id);
 
        iwl_init_notification_wait(notif_wait, &pnvm_wait,
                                   ntf_cmds, ARRAY_SIZE(ntf_cmds),
index 9540926e8a0f1220daf8c108f11e956f2d25ec22..ad3b7e2423ac73334c5a21ee2e31aa4f484e5766 100644 (file)
@@ -7,6 +7,7 @@
 
 #include "iwl-drv.h"
 #include "fw/notif-wait.h"
+#include "fw/img.h"
 
 #define MVM_UCODE_PNVM_TIMEOUT (HZ / 4)
 
@@ -14,8 +15,7 @@
 
 int iwl_pnvm_load(struct iwl_trans *trans,
                  struct iwl_notif_wait_data *notif_wait,
-                 const struct iwl_ucode_capabilities *capa,
-                 __le32 sku_id[3]);
+                 const struct iwl_fw *fw, __le32 sku_id[3]);
 
 static inline
 void iwl_pnvm_get_fs_name(struct iwl_trans *trans,
index 6492bc7d16803f5129c90ac577438ba914996668..064ff21354116fb89871a2c11f49fbd32c577a01 100644 (file)
@@ -136,6 +136,9 @@ static void iwl_dealloc_ucode(struct iwl_drv *drv)
        kfree(drv->fw.phy_integration_ver);
        kfree(drv->trans->dbg.pc_data);
        drv->trans->dbg.pc_data = NULL;
+       kvfree(drv->fw.pnvm_data);
+       drv->fw.pnvm_data = NULL;
+       drv->fw.pnvm_size = 0;
 
        for (i = 0; i < IWL_UCODE_TYPE_MAX; i++)
                iwl_free_fw_img(drv, drv->fw.img + i);
@@ -1400,6 +1403,15 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
                        drv->trans->dbg.num_pc =
                                tlv_len / sizeof(struct iwl_pc_data);
                        break;
+               case IWL_UCODE_TLV_PNVM_DATA:
+                       if (drv->fw.pnvm_data)
+                               break;
+                       drv->fw.pnvm_data =
+                               kvmemdup(tlv_data, tlv_len, GFP_KERNEL);
+                       if (!drv->fw.pnvm_data)
+                               return -ENOMEM;
+                       drv->fw.pnvm_size = tlv_len;
+                       break;
                default:
                        IWL_DEBUG_INFO(drv, "unknown TLV: %d\n", tlv_type);
                        break;
index 9d2c087360e7d01221615b2a50e0a5c4ef228c7f..b372173c4a79548695afc1d2e3765d111377376d 100644 (file)
@@ -294,7 +294,7 @@ static int iwl_mld_run_fw_init_sequence(struct iwl_mld *mld)
                return ret;
 
        ret = iwl_pnvm_load(mld->trans, &mld->notif_wait,
-                           &mld->fw->ucode_capa, alive_data.sku_id);
+                           mld->fw, alive_data.sku_id);
        if (ret) {
                IWL_ERR(mld, "Timeout waiting for PNVM load %d\n", ret);
                return ret;
index 819e3228462a3fbc16f5ba53c480434bf35a2b6a..ab3d78c1e20c6e1d5f35a45e63246abcb1d6d6f3 100644 (file)
@@ -432,7 +432,7 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm,
        iwl_trans_fw_alive(mvm->trans);
 
        ret = iwl_pnvm_load(mvm->trans, &mvm->notif_wait,
-                           &mvm->fw->ucode_capa, alive_data.sku_id);
+                           mvm->fw, alive_data.sku_id);
        if (ret) {
                IWL_ERR(mvm, "Timeout waiting for PNVM load!\n");
                iwl_fw_set_current_image(&mvm->fwrt, old_type);