Commit b99e32cb authored by Alon Giladi's avatar Alon Giladi Committed by Johannes Berg

wifi: iwlwifi: Take loading and setting of pnvm image out of parsing part

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: default avatarAlon Giladi <alon.giladi@intel.com>
Signed-off-by: default avatarGregory Greenman <gregory.greenman@intel.com>
Link: https://lore.kernel.org/r/20230606103519.504b42fc1611.I4ddf6ad76d922d118fcbcc4f0e9ec003753d0b75@changeidSigned-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 194d1f84
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause // 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" #include "iwl-drv.h"
...@@ -31,17 +31,18 @@ static bool iwl_pnvm_complete_fn(struct iwl_notif_wait_data *notif_wait, ...@@ -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, 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; const struct iwl_ucode_tlv *tlv;
u32 sha1 = 0; u32 sha1 = 0;
u16 mac_type = 0, rf_id = 0; u16 mac_type = 0, rf_id = 0;
struct iwl_pnvm_image pnvm_data = {};
bool hw_match = false; bool hw_match = false;
int ret;
IWL_DEBUG_FW(trans, "Handling PNVM section\n"); IWL_DEBUG_FW(trans, "Handling PNVM section\n");
memset(pnvm_data, 0, sizeof(*pnvm_data));
while (len >= sizeof(*tlv)) { while (len >= sizeof(*tlv)) {
u32 tlv_len, tlv_type; u32 tlv_len, tlv_type;
...@@ -73,6 +74,7 @@ static int iwl_pnvm_handle_section(struct iwl_trans *trans, const u8 *data, ...@@ -73,6 +74,7 @@ static int iwl_pnvm_handle_section(struct iwl_trans *trans, const u8 *data,
IWL_DEBUG_FW(trans, IWL_DEBUG_FW(trans,
"Got IWL_UCODE_TLV_PNVM_VERSION %0x\n", "Got IWL_UCODE_TLV_PNVM_VERSION %0x\n",
sha1); sha1);
pnvm_data->version = sha1;
break; break;
case IWL_UCODE_TLV_HW_TYPE: case IWL_UCODE_TLV_HW_TYPE:
if (tlv_len < 2 * sizeof(__le16)) { if (tlv_len < 2 * sizeof(__le16)) {
...@@ -110,7 +112,7 @@ static int iwl_pnvm_handle_section(struct iwl_trans *trans, const u8 *data, ...@@ -110,7 +112,7 @@ static int iwl_pnvm_handle_section(struct iwl_trans *trans, const u8 *data,
break; 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, IWL_DEBUG_FW(trans,
"too many payloads to allocate in DRAM.\n"); "too many payloads to allocate in DRAM.\n");
return -EINVAL; return -EINVAL;
...@@ -119,9 +121,9 @@ static int iwl_pnvm_handle_section(struct iwl_trans *trans, const u8 *data, ...@@ -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", IWL_DEBUG_FW(trans, "Adding data (size %d)\n",
data_len); data_len);
pnvm_data.chunks[pnvm_data.n_chunks].data = section->data; pnvm_data->chunks[pnvm_data->n_chunks].data = section->data;
pnvm_data.chunks[pnvm_data.n_chunks].len = data_len; pnvm_data->chunks[pnvm_data->n_chunks].len = data_len;
pnvm_data.n_chunks++; pnvm_data->n_chunks++;
break; break;
} }
...@@ -148,23 +150,17 @@ static int iwl_pnvm_handle_section(struct iwl_trans *trans, const u8 *data, ...@@ -148,23 +150,17 @@ static int iwl_pnvm_handle_section(struct iwl_trans *trans, const u8 *data,
return -ENOENT; return -ENOENT;
} }
if (!pnvm_data.n_chunks) { if (!pnvm_data->n_chunks) {
IWL_DEBUG_FW(trans, "Empty PNVM, skipping.\n"); IWL_DEBUG_FW(trans, "Empty PNVM, skipping.\n");
return -ENOENT; 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; return 0;
} }
static int iwl_pnvm_parse(struct iwl_trans *trans, const u8 *data, 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; const struct iwl_ucode_tlv *tlv;
...@@ -205,7 +201,8 @@ static int iwl_pnvm_parse(struct iwl_trans *trans, const u8 *data, ...@@ -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])) { trans->sku_id[2] == le32_to_cpu(sku_id->data[2])) {
int ret; int ret;
ret = iwl_pnvm_handle_section(trans, data, len); ret = iwl_pnvm_handle_section(trans, data, len,
pnvm_data);
if (!ret) if (!ret)
return 0; return 0;
} else { } else {
...@@ -248,70 +245,81 @@ static int iwl_pnvm_get_from_fs(struct iwl_trans *trans, u8 **data, size_t *len) ...@@ -248,70 +245,81 @@ static int iwl_pnvm_get_from_fs(struct iwl_trans *trans, u8 **data, size_t *len)
return 0; 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, int iwl_pnvm_load(struct iwl_trans *trans,
struct iwl_notif_wait_data *notif_wait) struct iwl_notif_wait_data *notif_wait)
{ {
u8 *data; u8 *data;
size_t len; size_t length;
struct pnvm_sku_package *package;
struct iwl_notification_wait pnvm_wait; struct iwl_notification_wait pnvm_wait;
static const u16 ntf_cmds[] = { WIDE_ID(REGULATORY_AND_NVM_GROUP, static const u16 ntf_cmds[] = { WIDE_ID(REGULATORY_AND_NVM_GROUP,
PNVM_INIT_COMPLETE_NTFY) }; PNVM_INIT_COMPLETE_NTFY) };
struct iwl_pnvm_image pnvm_data;
int ret; int ret;
/* if the SKU_ID is empty, there's nothing to do */ /* if the SKU_ID is empty, there's nothing to do */
if (!trans->sku_id[0] && !trans->sku_id[1] && !trans->sku_id[2]) if (!trans->sku_id[0] && !trans->sku_id[1] && !trans->sku_id[2])
return 0; return 0;
/* /* failed to get/parse the image in the past, no use to try again */
* If we already loaded (or tried to load) it before, we just if (trans->fail_to_parse_pnvm_image)
* need to set it again. goto reduce_tables;
*/
if (trans->pnvm_loaded) {
iwl_trans_set_pnvm(trans);
goto skip_parse;
}
/* First attempt to get the PNVM from BIOS */ /* get the image, parse and load it, if not loaded yet */
package = iwl_uefi_get_pnvm(trans, &len); if (!trans->pnvm_loaded) {
if (!IS_ERR_OR_NULL(package)) { data = iwl_get_pnvm_image(trans, &length);
if (len >= sizeof(*package)) { if (!data) {
/* we need only the data */ trans->fail_to_parse_pnvm_image = true;
len -= sizeof(*package); goto reduce_tables;
data = kmemdup(package->data, len, GFP_KERNEL); }
} else { ret = iwl_pnvm_parse(trans, data, length, &pnvm_data);
data = NULL; if (ret) {
trans->fail_to_parse_pnvm_image = true;
kfree(data);
goto reduce_tables;
} }
/* free package regardless of whether kmemdup succeeded */ ret = iwl_trans_load_pnvm(trans, &pnvm_data);
kfree(package); /* can only free data after pvnm_data use, but
* pnvm_data.version used below is not a pointer
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.
*/ */
trans->pnvm_loaded = true; kfree(data);
if (ret)
goto skip_parse; goto reduce_tables;
IWL_INFO(trans, "loaded PNVM version %08x\n",
pnvm_data.version);
} }
parse: iwl_trans_set_pnvm(trans);
iwl_pnvm_parse(trans, data, len);
kfree(data);
skip_parse: reduce_tables:
/* now try to get the reduce power table, if not loaded yet */ /* now try to get the reduce power table, if not loaded yet */
if (!trans->reduce_power_loaded) { 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)) { if (IS_ERR_OR_NULL(data)) {
/* /*
* Pretend we've loaded it - at least we've tried and * Pretend we've loaded it - at least we've tried and
...@@ -320,7 +328,7 @@ int iwl_pnvm_load(struct iwl_trans *trans, ...@@ -320,7 +328,7 @@ int iwl_pnvm_load(struct iwl_trans *trans,
*/ */
trans->reduce_power_loaded = true; trans->reduce_power_loaded = true;
} else { } else {
ret = iwl_trans_set_reduce_power(trans, data, len); ret = iwl_trans_set_reduce_power(trans, data, length);
if (ret) if (ret)
IWL_DEBUG_FW(trans, IWL_DEBUG_FW(trans,
"Failed to set reduce power table %d\n", "Failed to set reduce power table %d\n",
......
...@@ -466,6 +466,7 @@ struct iwl_trans_rxq_dma_data { ...@@ -466,6 +466,7 @@ struct iwl_trans_rxq_dma_data {
* struct iwl_pnvm_image - contains info about the parsed pnvm image * struct iwl_pnvm_image - contains info about the parsed pnvm image
* @chunks: array of pointers to pnvm payloads and their sizes * @chunks: array of pointers to pnvm payloads and their sizes
* @n_chunks: the number of the pnvm payloads. * @n_chunks: the number of the pnvm payloads.
* @version: the version of the loaded PNVM image
*/ */
struct iwl_pnvm_image { struct iwl_pnvm_image {
struct { struct {
...@@ -473,6 +474,7 @@ struct iwl_pnvm_image { ...@@ -473,6 +474,7 @@ struct iwl_pnvm_image {
u32 len; u32 len;
} chunks[IPC_DRAM_MAP_ENTRY_NUM_MAX]; } chunks[IPC_DRAM_MAP_ENTRY_NUM_MAX];
u32 n_chunks; u32 n_chunks;
u32 version;
}; };
/** /**
...@@ -1023,6 +1025,7 @@ struct iwl_trans_txqs { ...@@ -1023,6 +1025,7 @@ struct iwl_trans_txqs {
* @hw_rev_step: The mac step of the HW * @hw_rev_step: The mac step of the HW
* @pm_support: set to true in start_hw if link pm is supported * @pm_support: set to true in start_hw if link pm is supported
* @ltr_enabled: set to true if the LTR is enabled * @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 * @wide_cmd_header: true when ucode supports wide command header format
* @wait_command_queue: wait queue for sync commands * @wait_command_queue: wait queue for sync commands
* @num_rx_queues: number of RX queues allocated by the transport; * @num_rx_queues: number of RX queues allocated by the transport;
...@@ -1070,6 +1073,7 @@ struct iwl_trans { ...@@ -1070,6 +1073,7 @@ struct iwl_trans {
bool pm_support; bool pm_support;
bool ltr_enabled; bool ltr_enabled;
u8 pnvm_loaded:1; u8 pnvm_loaded:1;
u8 fail_to_parse_pnvm_image:1;
u8 reduce_power_loaded:1; u8 reduce_power_loaded:1;
const struct iwl_hcmd_arr *command_groups; const struct iwl_hcmd_arr *command_groups;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment