From 5f40850399c61aec5f26861f4a5194aae64c27df Mon Sep 17 00:00:00 2001 From: Alon Giladi Date: Tue, 6 Jun 2023 10:42:58 +0300 Subject: wifi: iwlwifi: Generalize the parsing of the pnvm image Generalize iwl_pnvm_parse(). This saves us from copying each payload twice (first in the parsing and later when copying it to the dram). Moreover, its more compatible for handling larger pnvm tables in the future (in which payloads won't be concatenated). The main changes are: 1. Take out the concatenating of the payloads from the parsing level 2. Start using iwl_pnvm_image structure that will hold pointers to payloads that should be delivered to fw, their sizes and number. Signed-off-by: Alon Giladi Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230606103519.06c02f380b6f.I03a3030fca194aa0c4bc2ecd18531f8914e98cfd@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/pnvm.c | 43 ++++++++++------------------ 1 file changed, 15 insertions(+), 28 deletions(-) (limited to 'drivers/net/wireless/intel/iwlwifi/fw/pnvm.c') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c index c6f2672fdc73..bec3c7ec3f4c 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c @@ -36,10 +36,8 @@ static int iwl_pnvm_handle_section(struct iwl_trans *trans, const u8 *data, const struct iwl_ucode_tlv *tlv; u32 sha1 = 0; u16 mac_type = 0, rf_id = 0; - u8 *pnvm_data = NULL, *tmp; + struct iwl_pnvm_image pnvm_data = {}; bool hw_match = false; - u32 size = 0; - int ret; IWL_DEBUG_FW(trans, "Handling PNVM section\n"); @@ -55,8 +53,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); @@ -112,23 +109,18 @@ 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; } @@ -152,22 +144,17 @@ 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 iwl_trans_set_pnvm(trans, &pnvm_data); } static int iwl_pnvm_parse(struct iwl_trans *trans, const u8 *data, @@ -275,7 +262,7 @@ int iwl_pnvm_load(struct iwl_trans *trans, * need to set it again. */ if (trans->pnvm_loaded) { - ret = iwl_trans_set_pnvm(trans, NULL, 0); + ret = iwl_trans_set_pnvm(trans, NULL); if (ret) return ret; goto skip_parse; -- cgit v1.2.3 From 194d1f84d56e912459f166a80ef520037c84b0d3 Mon Sep 17 00:00:00 2001 From: Alon Giladi Date: Tue, 6 Jun 2023 10:42:59 +0300 Subject: wifi: iwlwifi: Separate loading and setting of pnvm image into two functions Take the part that is copying the pnvm image into DRAM, out of the the method that sets the prph_scratch. Makes the code cleaner since those 2 operations don't always happen together (loading should happen only once while setting can happen more than once). In addition, each operation will get more complex in the future when it will support also larger pnvm images. Signed-off-by: Alon Giladi Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230606103519.4c0728239fd6.Ibc30a9fbdb6123dadbe2dbb89318dbd5ec01080a@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/pnvm.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless/intel/iwlwifi/fw/pnvm.c') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c index bec3c7ec3f4c..f99328cc6b01 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c @@ -38,6 +38,7 @@ static int iwl_pnvm_handle_section(struct iwl_trans *trans, const u8 *data, 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"); @@ -152,9 +153,14 @@ done: return -ENOENT; } + ret = iwl_trans_load_pnvm(trans, &pnvm_data); + if (ret) + return ret; + IWL_INFO(trans, "loaded PNVM version %08x\n", sha1); - return iwl_trans_set_pnvm(trans, &pnvm_data); + iwl_trans_set_pnvm(trans); + return 0; } static int iwl_pnvm_parse(struct iwl_trans *trans, const u8 *data, @@ -262,9 +268,7 @@ int iwl_pnvm_load(struct iwl_trans *trans, * need to set it again. */ if (trans->pnvm_loaded) { - ret = iwl_trans_set_pnvm(trans, NULL); - if (ret) - return ret; + iwl_trans_set_pnvm(trans); goto skip_parse; } -- cgit v1.2.3 From b99e32cbfdf63a8acab18b0d44402172528ffe48 Mon Sep 17 00:00:00 2001 From: Alon Giladi Date: Tue, 6 Jun 2023 10:43:00 +0300 Subject: 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: Alon Giladi Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230606103519.504b42fc1611.I4ddf6ad76d922d118fcbcc4f0e9ec003753d0b75@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/pnvm.c | 130 ++++++++++++++------------- 1 file changed, 69 insertions(+), 61 deletions(-) (limited to 'drivers/net/wireless/intel/iwlwifi/fw/pnvm.c') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c index f99328cc6b01..cb6a9191cf95 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,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", -- cgit v1.2.3 From 331828106e52d76170fed605aeeb9ba1b7321f46 Mon Sep 17 00:00:00 2001 From: Alon Giladi Date: Tue, 6 Jun 2023 10:43:02 +0300 Subject: wifi: iwlwifi: Add support for fragmented pnvm images Add support for fragmented pnvm images, depending on the FW capability. Signed-off-by: Alon Giladi Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230606103519.c49bfaf435a9.I0278312e7c3355b224cd870d4f8cf6578d12f03e@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/pnvm.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless/intel/iwlwifi/fw/pnvm.c') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c index cb6a9191cf95..91e1faef76f6 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c @@ -271,7 +271,8 @@ static u8 *iwl_get_pnvm_image(struct iwl_trans *trans_p, size_t *len) } 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) { u8 *data; size_t length; @@ -303,7 +304,7 @@ int iwl_pnvm_load(struct iwl_trans *trans, goto reduce_tables; } - ret = iwl_trans_load_pnvm(trans, &pnvm_data); + ret = iwl_trans_load_pnvm(trans, &pnvm_data, capa); /* can only free data after pvnm_data use, but * pnvm_data.version used below is not a pointer */ @@ -314,7 +315,7 @@ int iwl_pnvm_load(struct iwl_trans *trans, pnvm_data.version); } - iwl_trans_set_pnvm(trans); + iwl_trans_set_pnvm(trans, capa); reduce_tables: /* now try to get the reduce power table, if not loaded yet */ -- cgit v1.2.3 From c738fb6163b213dd9565ba1951d4f130975db10f Mon Sep 17 00:00:00 2001 From: Alon Giladi Date: Tue, 6 Jun 2023 10:43:04 +0300 Subject: wifi: iwlwifi: Separate loading and setting of power reduce tables Take the part that copies the tables into DRAM, out of the method that sets the prph_scratch to make the code cleaner. Each of the operations will get more complex in the future when it will also support larger power-reduce tables images. Signed-off-by: Alon Giladi Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230606103519.7695684dc848.I13626cd318e5d68efec9618b2045f52788bff114@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/pnvm.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless/intel/iwlwifi/fw/pnvm.c') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c index 91e1faef76f6..bb6300469f4a 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c @@ -329,14 +329,17 @@ reduce_tables: */ trans->reduce_power_loaded = true; } else { - ret = iwl_trans_set_reduce_power(trans, data, length); - if (ret) + ret = iwl_trans_load_reduce_power(trans, data, length); + if (ret) { IWL_DEBUG_FW(trans, - "Failed to set reduce power table %d\n", + "Failed to load reduce power table %d\n", ret); + trans->reduce_power_loaded = true; + } kfree(data); } } + iwl_trans_set_reduce_power(trans); iwl_init_notification_wait(notif_wait, &pnvm_wait, ntf_cmds, ARRAY_SIZE(ntf_cmds), -- cgit v1.2.3 From ea3571f48953df2cf77a9c4200a7363236736673 Mon Sep 17 00:00:00 2001 From: Alon Giladi Date: Tue, 6 Jun 2023 10:43:05 +0300 Subject: wifi: iwlwifi: Use iwl_pnvm_image in reduce power tables flow Generalize the parsing, loading, and setting of the power-reduce tables, in order to support allocation of several DRAM payloads in the future. Signed-off-by: Alon Giladi Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230606103519.564f1eead99b.Iaba653b21dc09aafc72b9bbb3928abddce0db50a@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/pnvm.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless/intel/iwlwifi/fw/pnvm.c') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c index bb6300469f4a..42d994240b31 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c @@ -320,8 +320,9 @@ int iwl_pnvm_load(struct iwl_trans *trans, 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, &length); - if (IS_ERR_OR_NULL(data)) { + memset(&pnvm_data, 0, sizeof(pnvm_data)); + ret = iwl_uefi_get_reduced_power(trans, &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 @@ -329,7 +330,7 @@ reduce_tables: */ trans->reduce_power_loaded = true; } else { - ret = iwl_trans_load_reduce_power(trans, data, length); + ret = iwl_trans_load_reduce_power(trans, &pnvm_data); if (ret) { IWL_DEBUG_FW(trans, "Failed to load reduce power table %d\n", -- cgit v1.2.3 From 7c9c8477170d32def5df9d88823ea10d65749341 Mon Sep 17 00:00:00 2001 From: Alon Giladi Date: Tue, 6 Jun 2023 10:43:06 +0300 Subject: wifi: iwlwifi: Enable loading of reduce-power tables into several segments Replace the field reduce_power_dram with a struct that holds data about the reduced-power tables drams regions. Generalize load_payloads_segments() to work for both pnvm tables and reduction power tables. Make required adjustments in the data structures. Signed-off-by: Alon Giladi Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230606103519.6fe66958f049.I85d80682229fc02fe354462cc9da40937558f30c@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/pnvm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless/intel/iwlwifi/fw/pnvm.c') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c index 42d994240b31..b556abece896 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c @@ -330,7 +330,7 @@ reduce_tables: */ trans->reduce_power_loaded = true; } else { - ret = iwl_trans_load_reduce_power(trans, &pnvm_data); + ret = iwl_trans_load_reduce_power(trans, &pnvm_data, capa); if (ret) { IWL_DEBUG_FW(trans, "Failed to load reduce power table %d\n", @@ -340,7 +340,7 @@ reduce_tables: kfree(data); } } - iwl_trans_set_reduce_power(trans); + iwl_trans_set_reduce_power(trans, capa); iwl_init_notification_wait(notif_wait, &pnvm_wait, ntf_cmds, ARRAY_SIZE(ntf_cmds), -- cgit v1.2.3 From 380bf72d1b1dc3cb2572acd9b61153e79413b036 Mon Sep 17 00:00:00 2001 From: Alon Giladi Date: Tue, 6 Jun 2023 10:43:07 +0300 Subject: wifi: iwlwifi: Separate reading and parsing of reduce power table It enables to better handle error cases. Also save the image till the end of the loading and only then free it. Signed-off-by: Alon Giladi Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230606103519.71e3b3e0e794.Ifbe69ad99a7e805eb70e09280365821eb146b1c9@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/pnvm.c | 40 +++++++++++++++++----------- 1 file changed, 25 insertions(+), 15 deletions(-) (limited to 'drivers/net/wireless/intel/iwlwifi/fw/pnvm.c') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c index b556abece896..3b5a3c89fedf 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c @@ -319,29 +319,39 @@ int iwl_pnvm_load(struct iwl_trans *trans, reduce_tables: /* now try to get the reduce power table, if not loaded yet */ + if (trans->failed_to_load_reduce_power_image) + goto notification; + if (!trans->reduce_power_loaded) { memset(&pnvm_data, 0, sizeof(pnvm_data)); - ret = iwl_uefi_get_reduced_power(trans, &pnvm_data); + data = iwl_uefi_get_reduced_power(trans, &length); + if (IS_ERR(data)) { + ret = PTR_ERR(data); + trans->failed_to_load_reduce_power_image = true; + goto notification; + } + + ret = iwl_uefi_reduce_power_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->reduce_power_loaded = true; - } else { - 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->reduce_power_loaded = true; - } + trans->failed_to_load_reduce_power_image = true; kfree(data); + goto notification; + } + + ret = iwl_trans_load_reduce_power(trans, &pnvm_data, capa); + kfree(data); + if (ret) { + IWL_DEBUG_FW(trans, + "Failed to load reduce power table %d\n", + ret); + trans->failed_to_load_reduce_power_image = true; + goto notification; } } iwl_trans_set_reduce_power(trans, capa); +notification: iwl_init_notification_wait(notif_wait, &pnvm_wait, ntf_cmds, ARRAY_SIZE(ntf_cmds), iwl_pnvm_complete_fn, trans); -- cgit v1.2.3 From 875d035f37ec06a27c61abd9103178ae5a674672 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 6 Jun 2023 10:43:08 +0300 Subject: wifi: iwlwifi: fw: clean up PNVM loading code This code is a bit of a maze of gotos etc. Clean up the code a bit to make the intent clearer. Signed-off-by: Johannes Berg Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230606103519.51fb5ee63f21.I20f270b2d47612e84643dc235c2940b8d9ed9930@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/pnvm.c | 155 +++++++++++++++------------ 1 file changed, 89 insertions(+), 66 deletions(-) (limited to 'drivers/net/wireless/intel/iwlwifi/fw/pnvm.c') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c index 3b5a3c89fedf..82eb32e67a2c 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c @@ -270,88 +270,111 @@ static u8 *iwl_get_pnvm_image(struct iwl_trans *trans_p, size_t *len) return image; } -int iwl_pnvm_load(struct iwl_trans *trans, - struct iwl_notif_wait_data *notif_wait, - const struct iwl_ucode_capabilities *capa) +static void iwl_pnvm_load_pnvm_to_trans(struct iwl_trans *trans, + const struct iwl_ucode_capabilities *capa) { - u8 *data; + struct iwl_pnvm_image *pnvm_data = NULL; + u8 *data = NULL; 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; - - /* failed to get/parse the image in the past, no use to try again */ + /* failed to get/parse the image in the past, no use trying again */ if (trans->fail_to_parse_pnvm_image) - goto reduce_tables; - - /* 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; - } + return; + + if (trans->pnvm_loaded) + goto set; - ret = iwl_trans_load_pnvm(trans, &pnvm_data, capa); - /* can only free data after pvnm_data use, but - * pnvm_data.version used below is not a pointer - */ - kfree(data); - if (ret) - goto reduce_tables; - IWL_INFO(trans, "loaded PNVM version %08x\n", - pnvm_data.version); + 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) { + trans->fail_to_parse_pnvm_image = true; + goto free; + } + + 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); +} + +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; -reduce_tables: - /* now try to get the reduce power table, if not loaded yet */ if (trans->failed_to_load_reduce_power_image) - goto notification; - - if (!trans->reduce_power_loaded) { - memset(&pnvm_data, 0, sizeof(pnvm_data)); - data = iwl_uefi_get_reduced_power(trans, &length); - if (IS_ERR(data)) { - ret = PTR_ERR(data); - trans->failed_to_load_reduce_power_image = true; - goto notification; - } + return; - ret = iwl_uefi_reduce_power_parse(trans, data, length, - &pnvm_data); - if (ret) { - trans->failed_to_load_reduce_power_image = true; - kfree(data); - goto notification; - } + if (trans->reduce_power_loaded) + goto set; - ret = iwl_trans_load_reduce_power(trans, &pnvm_data, capa); - kfree(data); - if (ret) { - IWL_DEBUG_FW(trans, - "Failed to load reduce power table %d\n", - ret); - trans->failed_to_load_reduce_power_image = true; - goto notification; - } + 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); -notification: iwl_init_notification_wait(notif_wait, &pnvm_wait, ntf_cmds, ARRAY_SIZE(ntf_cmds), iwl_pnvm_complete_fn, trans); -- cgit v1.2.3 From 372a714808c8ec4f4ae4915c734d80d7f504997c Mon Sep 17 00:00:00 2001 From: Gregory Greenman Date: Tue, 6 Jun 2023 10:43:10 +0300 Subject: wifi: iwlwifi: pnvm: handle memory descriptor tlv When PNVM is obtained from UEFI, there's an additional memory descriptor TLV that has to be handled. It is the same TLV that holds data in the reduced power tables. Also, in this TLV, the actual data is located after address and size, so add the corresponding offset. Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230606103519.8c5f5ee8e30b.Id1893c9dec140b5ba4abe8a121c2e1a1d121d2d7@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/fw/pnvm.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/net/wireless/intel/iwlwifi/fw/pnvm.c') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c index 82eb32e67a2c..650e4bde9c17 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c @@ -127,6 +127,11 @@ static int iwl_pnvm_handle_section(struct iwl_trans *trans, const u8 *data, 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"); -- cgit v1.2.3