wifi: iwlwifi: Take loading and setting of pnvm image out of parsing part
authorAlon Giladi <alon.giladi@intel.com>
Tue, 6 Jun 2023 07:43:00 +0000 (10:43 +0300)
committerJohannes Berg <johannes.berg@intel.com>
Tue, 6 Jun 2023 11:43:30 +0000 (13:43 +0200)
Change iwl_pnvm_parse so it will only save the information into the
iwl_pnvm_image struct. This enables to use the parsing code for the
power reduce tables in the future.

Signed-off-by: Alon Giladi <alon.giladi@intel.com>
Signed-off-by: Gregory Greenman <gregory.greenman@intel.com>
Link: https://lore.kernel.org/r/20230606103519.504b42fc1611.I4ddf6ad76d922d118fcbcc4f0e9ec003753d0b75@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
drivers/net/wireless/intel/iwlwifi/fw/pnvm.c
drivers/net/wireless/intel/iwlwifi/iwl-trans.h

index f99328cc6b01a2712776453bbe8f4cc3b5bb2143..cb6a9191cf95c8d17096acb42ff4caee88fea62b 100644 (file)
@@ -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,17 +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;
-       struct iwl_pnvm_image pnvm_data = {};
        bool hw_match = false;
-       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;
 
@@ -73,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)) {
@@ -110,7 +112,7 @@ static int iwl_pnvm_handle_section(struct iwl_trans *trans, const u8 *data,
                                break;
                        }
 
-                       if (pnvm_data.n_chunks == IPC_DRAM_MAP_ENTRY_NUM_MAX) {
+                       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;
@@ -119,9 +121,9 @@ static int iwl_pnvm_handle_section(struct iwl_trans *trans, const u8 *data,
                        IWL_DEBUG_FW(trans, "Adding data (size %d)\n",
                                     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++;
+                       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;
                }
@@ -148,23 +150,17 @@ done:
                return -ENOENT;
        }
 
-       if (!pnvm_data.n_chunks) {
+       if (!pnvm_data->n_chunks) {
                IWL_DEBUG_FW(trans, "Empty PNVM, skipping.\n");
                return -ENOENT;
        }
 
-       ret = iwl_trans_load_pnvm(trans, &pnvm_data);
-       if (ret)
-               return ret;
-
-       IWL_INFO(trans, "loaded PNVM version %08x\n", sha1);
-
-       iwl_trans_set_pnvm(trans);
        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;
 
@@ -205,7 +201,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 {
@@ -248,70 +245,81 @@ 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)
+{
+       struct pnvm_sku_package *package;
+       u8 *image = NULL;
+
+       /* First attempt to get the PNVM from BIOS */
+       package = iwl_uefi_get_pnvm(trans_p, len);
+       if (!IS_ERR_OR_NULL(package)) {
+               if (*len >= sizeof(*package)) {
+                       /* we need only the data */
+                       *len -= sizeof(*package);
+                       image = kmemdup(package->data, *len, GFP_KERNEL);
+               }
+               /* free package regardless of whether kmemdup succeeded */
+               kfree(package);
+               if (image)
+                       return image;
+       }
+
+       /* If it's not available, try from the filesystem */
+       if (iwl_pnvm_get_from_fs(trans_p, &image, len))
+               return NULL;
+       return image;
+}
+
 int iwl_pnvm_load(struct iwl_trans *trans,
                  struct iwl_notif_wait_data *notif_wait)
 {
        u8 *data;
-       size_t len;
-       struct pnvm_sku_package *package;
+       size_t length;
        struct iwl_notification_wait pnvm_wait;
        static const u16 ntf_cmds[] = { WIDE_ID(REGULATORY_AND_NVM_GROUP,
                                                PNVM_INIT_COMPLETE_NTFY) };
+       struct iwl_pnvm_image pnvm_data;
        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) {
-               iwl_trans_set_pnvm(trans);
-               goto skip_parse;
-       }
+       /* failed to get/parse the image in the past, no use to try again */
+       if (trans->fail_to_parse_pnvm_image)
+               goto reduce_tables;
 
-       /* First attempt to get the PNVM from BIOS */
-       package = iwl_uefi_get_pnvm(trans, &len);
-       if (!IS_ERR_OR_NULL(package)) {
-               if (len >= sizeof(*package)) {
-                       /* we need only the data */
-                       len -= sizeof(*package);
-                       data = kmemdup(package->data, len, GFP_KERNEL);
-               } else {
-                       data = NULL;
+       /* get the image, parse and load it, if not loaded yet */
+       if (!trans->pnvm_loaded) {
+               data = iwl_get_pnvm_image(trans, &length);
+               if (!data) {
+                       trans->fail_to_parse_pnvm_image = true;
+                       goto reduce_tables;
+               }
+               ret = iwl_pnvm_parse(trans, data, length, &pnvm_data);
+               if (ret) {
+                       trans->fail_to_parse_pnvm_image = true;
+                       kfree(data);
+                       goto reduce_tables;
                }
 
-               /* free package regardless of whether kmemdup succeeded */
-               kfree(package);
-
-               if (data)
-                       goto parse;
-       }
-
-       /* If it's not available, try from the filesystem */
-       ret = iwl_pnvm_get_from_fs(trans, &data, &len);
-       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.
+               ret = iwl_trans_load_pnvm(trans, &pnvm_data);
+               /* can only free data after pvnm_data use, but
+                * pnvm_data.version used below is not a pointer
                 */
-               trans->pnvm_loaded = true;
-
-               goto skip_parse;
+               kfree(data);
+               if (ret)
+                       goto reduce_tables;
+               IWL_INFO(trans, "loaded PNVM version %08x\n",
+                        pnvm_data.version);
        }
 
-parse:
-       iwl_pnvm_parse(trans, data, len);
-
-       kfree(data);
+       iwl_trans_set_pnvm(trans);
 
-skip_parse:
+reduce_tables:
        /* 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);
+               data = iwl_uefi_get_reduced_power(trans, &length);
                if (IS_ERR_OR_NULL(data)) {
                        /*
                         * Pretend we've loaded it - at least we've tried and
@@ -320,7 +328,7 @@ skip_parse:
                         */
                        trans->reduce_power_loaded = true;
                } else {
-                       ret = iwl_trans_set_reduce_power(trans, data, len);
+                       ret = iwl_trans_set_reduce_power(trans, data, length);
                        if (ret)
                                IWL_DEBUG_FW(trans,
                                             "Failed to set reduce power table %d\n",
index 35782cba5b8165d422a6ad82c05bd5c7e3e64702..84485d69f19522f4aeaf71ec6aea3b1d2ebb1734 100644 (file)
@@ -466,6 +466,7 @@ struct iwl_trans_rxq_dma_data {
  * struct iwl_pnvm_image - contains info about the parsed pnvm image
  * @chunks: array of pointers to pnvm payloads and their sizes
  * @n_chunks: the number of the pnvm payloads.
+ * @version: the version of the loaded PNVM image
  */
 struct iwl_pnvm_image {
        struct {
@@ -473,6 +474,7 @@ struct iwl_pnvm_image {
                u32 len;
        } chunks[IPC_DRAM_MAP_ENTRY_NUM_MAX];
        u32 n_chunks;
+       u32 version;
 };
 
 /**
@@ -1023,6 +1025,7 @@ struct iwl_trans_txqs {
  * @hw_rev_step: The mac step of the HW
  * @pm_support: set to true in start_hw if link pm is supported
  * @ltr_enabled: set to true if the LTR is enabled
+ * @fail_to_parse_pnvm_image: set to true if pnvm parsing failed
  * @wide_cmd_header: true when ucode supports wide command header format
  * @wait_command_queue: wait queue for sync commands
  * @num_rx_queues: number of RX queues allocated by the transport;
@@ -1070,6 +1073,7 @@ struct iwl_trans {
        bool pm_support;
        bool ltr_enabled;
        u8 pnvm_loaded:1;
+       u8 fail_to_parse_pnvm_image:1;
        u8 reduce_power_loaded:1;
 
        const struct iwl_hcmd_arr *command_groups;