From: Gregory Greenman <[email protected]>
Hi,
This patch set includes iwlwifi patches intended for v6.5.
All the patches are related to the same feature - adding support
for fragmented PNVM image.
Thanks,
Gregory
Alon Giladi (10):
wifi: iwlwifi: Generalize the parsing of the pnvm image
wifi: iwlwifi: Separate loading and setting of pnvm image into two functions
wifi: iwlwifi: Take loading and setting of pnvm image out of parsing part
wifi: iwlwifi: Allow trans_pcie track more than 1 pnvm DRAM region
wifi: iwlwifi: Add support for fragmented pnvm images
wifi: iwlwifi: Implement loading and setting of fragmented pnvm image
wifi: iwlwifi: Separate loading and setting of power reduce tables
wifi: iwlwifi: Use iwl_pnvm_image in reduce power tables flow
wifi: iwlwifi: Enable loading of reduce-power tables into several segments
wifi: iwlwifi: Separate reading and parsing of reduce power table
Gregory Greenman (2):
wifi: iwlwifi: fw: don't use constant size with efi.get_variable
wifi: iwlwifi: pnvm: handle memory descriptor tlv
Johannes Berg (1):
wifi: iwlwifi: fw: clean up PNVM loading code
drivers/net/wireless/intel/iwlwifi/fw/file.h | 2 +
drivers/net/wireless/intel/iwlwifi/fw/pnvm.c | 234 +++++++++------
drivers/net/wireless/intel/iwlwifi/fw/pnvm.h | 5 +-
drivers/net/wireless/intel/iwlwifi/fw/uefi.c | 272 ++++++++---------
drivers/net/wireless/intel/iwlwifi/fw/uefi.h | 47 +--
.../intel/iwlwifi/iwl-context-info-gen3.h | 32 +-
.../wireless/intel/iwlwifi/iwl-context-info.h | 5 +-
.../net/wireless/intel/iwlwifi/iwl-trans.h | 95 ++++--
drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 3 +-
.../intel/iwlwifi/pcie/ctxt-info-gen3.c | 273 +++++++++++++++---
.../wireless/intel/iwlwifi/pcie/ctxt-info.c | 8 +-
.../wireless/intel/iwlwifi/pcie/internal.h | 12 +-
.../net/wireless/intel/iwlwifi/pcie/trans.c | 39 ++-
13 files changed, 694 insertions(+), 333 deletions(-)
--
2.38.1
From: Alon Giladi <[email protected]>
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 <[email protected]>
Signed-off-by: Gregory Greenman <[email protected]>
---
drivers/net/wireless/intel/iwlwifi/fw/pnvm.c | 12 ++--
.../intel/iwlwifi/iwl-context-info-gen3.h | 5 +-
.../net/wireless/intel/iwlwifi/iwl-trans.h | 25 ++++---
.../intel/iwlwifi/pcie/ctxt-info-gen3.c | 69 +++++++++++--------
.../net/wireless/intel/iwlwifi/pcie/trans.c | 1 +
5 files changed, 65 insertions(+), 47 deletions(-)
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 @@ static int iwl_pnvm_handle_section(struct iwl_trans *trans, const u8 *data,
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;
}
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-context-info-gen3.h b/drivers/net/wireless/intel/iwlwifi/iwl-context-info-gen3.h
index 9d2dcb64523c..9f718e43dd81 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-context-info-gen3.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-context-info-gen3.h
@@ -279,8 +279,9 @@ int iwl_pcie_ctxt_info_gen3_init(struct iwl_trans *trans,
const struct fw_img *fw);
void iwl_pcie_ctxt_info_gen3_free(struct iwl_trans *trans, bool alive);
-int iwl_trans_pcie_ctx_info_gen3_set_pnvm(struct iwl_trans *trans,
- const struct iwl_pnvm_image *pnvm_payloads);
+int iwl_trans_pcie_ctx_info_gen3_load_pnvm(struct iwl_trans *trans,
+ const struct iwl_pnvm_image *pnvm_payloads);
+void iwl_trans_pcie_ctx_info_gen3_set_pnvm(struct iwl_trans *trans);
int iwl_trans_pcie_ctx_info_gen3_set_reduce_power(struct iwl_trans *trans,
const void *data, u32 len);
int iwl_trans_pcie_ctx_info_gen3_set_step(struct iwl_trans *trans,
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h
index 35ddb4cfa356..a7e8d45c874c 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h
@@ -557,6 +557,7 @@ struct iwl_pnvm_image {
* Note that the transport must fill in the proper file headers.
* @debugfs_cleanup: used in the driver unload flow to make a proper cleanup
* of the trans debugfs
+ * @load_pnvm: save the pnvm data in DRAM
* @set_pnvm: set the pnvm data in the prph scratch buffer, inside the
* context info.
* @interrupts: disable/enable interrupts to transport
@@ -630,8 +631,9 @@ struct iwl_trans_ops {
void *sanitize_ctx);
void (*debugfs_cleanup)(struct iwl_trans *trans);
void (*sync_nmi)(struct iwl_trans *trans);
- int (*set_pnvm)(struct iwl_trans *trans,
- const struct iwl_pnvm_image *pnvm_data);
+ int (*load_pnvm)(struct iwl_trans *trans,
+ const struct iwl_pnvm_image *pnvm_payloads);
+ void (*set_pnvm)(struct iwl_trans *trans);
int (*set_reduce_power)(struct iwl_trans *trans,
const void *data, u32 len);
void (*interrupts)(struct iwl_trans *trans, bool enable);
@@ -1532,19 +1534,16 @@ static inline void iwl_trans_sync_nmi(struct iwl_trans *trans)
void iwl_trans_sync_nmi_with_addr(struct iwl_trans *trans, u32 inta_addr,
u32 sw_err_bit);
-static inline int iwl_trans_set_pnvm(struct iwl_trans *trans,
- const struct iwl_pnvm_image *pnvm_data)
+static inline int iwl_trans_load_pnvm(struct iwl_trans *trans,
+ const struct iwl_pnvm_image *pnvm_data)
{
- if (trans->ops->set_pnvm) {
- int ret = trans->ops->set_pnvm(trans, pnvm_data);
-
- if (ret)
- return ret;
- }
-
- trans->pnvm_loaded = true;
+ return trans->ops->load_pnvm(trans, pnvm_data);
+}
- return 0;
+static inline void iwl_trans_set_pnvm(struct iwl_trans *trans)
+{
+ if (trans->ops->set_pnvm)
+ trans->ops->set_pnvm(trans);
}
static inline int iwl_trans_set_reduce_power(struct iwl_trans *trans,
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c
index 800857e61d65..e9f3799d4593 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c
@@ -281,55 +281,68 @@ void iwl_pcie_ctxt_info_gen3_free(struct iwl_trans *trans, bool alive)
trans_pcie->prph_info = NULL;
}
-int iwl_trans_pcie_ctx_info_gen3_set_pnvm(struct iwl_trans *trans,
- const struct iwl_pnvm_image *pnvm_payloads)
+int iwl_trans_pcie_ctx_info_gen3_load_pnvm(struct iwl_trans *trans,
+ const struct iwl_pnvm_image *pnvm_payloads)
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
struct iwl_prph_scratch_ctrl_cfg *prph_sc_ctrl =
&trans_pcie->prph_scratch->ctrl_cfg;
struct iwl_dram_data *dram = &trans_pcie->pnvm_dram;
+ u32 len, len0, len1;
if (trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_AX210)
return 0;
/* only allocate the DRAM if not allocated yet */
- if (!trans->pnvm_loaded) {
- u32 len, len0, len1;
+ if (trans->pnvm_loaded)
+ return 0;
- if (WARN_ON(prph_sc_ctrl->pnvm_cfg.pnvm_size))
- return -EBUSY;
+ if (WARN_ON(prph_sc_ctrl->pnvm_cfg.pnvm_size))
+ return -EBUSY;
- if (pnvm_payloads->n_chunks !=
- UNFRAGMENTED_PNVM_PAYLOADS_NUMBER) {
- IWL_DEBUG_FW(trans, "expected 2 payloads, got %d.\n",
- pnvm_payloads->n_chunks);
- return -EINVAL;
- }
- len0 = pnvm_payloads->chunks[0].len;
- len1 = pnvm_payloads->chunks[1].len;
- if (len1 > 0xFFFFFFFF - len0) {
- IWL_DEBUG_FW(trans, "sizes of payloads overflow.\n");
+ if (pnvm_payloads->n_chunks != UNFRAGMENTED_PNVM_PAYLOADS_NUMBER) {
+ IWL_DEBUG_FW(trans, "expected 2 payloads, got %d.\n",
+ pnvm_payloads->n_chunks);
return -EINVAL;
- }
- len = len0 + len1;
+ }
- dram->block = iwl_pcie_ctxt_info_dma_alloc_coherent(trans, len, &dram->physical);
- if (!dram->block) {
- IWL_DEBUG_FW(trans, "Failed to allocate PNVM DMA.\n");
- return -ENOMEM;
- }
- dram->size = len;
- memcpy(dram->block, pnvm_payloads->chunks[0].data, len0);
- memcpy((u8 *)dram->block + len0, pnvm_payloads->chunks[1].data,
- len1);
+ len0 = pnvm_payloads->chunks[0].len;
+ len1 = pnvm_payloads->chunks[1].len;
+ if (len1 > 0xFFFFFFFF - len0) {
+ IWL_DEBUG_FW(trans, "sizes of payloads overflow.\n");
+ return -EINVAL;
+ }
+ len = len0 + len1;
+
+ dram->block = iwl_pcie_ctxt_info_dma_alloc_coherent(trans, len,
+ &dram->physical);
+ if (!dram->block) {
+ IWL_DEBUG_FW(trans, "Failed to allocate PNVM DMA.\n");
+ return -ENOMEM;
}
+ dram->size = len;
+ memcpy(dram->block, pnvm_payloads->chunks[0].data, len0);
+ memcpy((u8 *)dram->block + len0, pnvm_payloads->chunks[1].data, len1);
+
+ trans->pnvm_loaded = true;
+ return 0;
+}
+
+void iwl_trans_pcie_ctx_info_gen3_set_pnvm(struct iwl_trans *trans)
+{
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+ struct iwl_prph_scratch_ctrl_cfg *prph_sc_ctrl =
+ &trans_pcie->prph_scratch->ctrl_cfg;
+
+ if (trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_AX210)
+ return;
+
prph_sc_ctrl->pnvm_cfg.pnvm_base_addr =
cpu_to_le64(trans_pcie->pnvm_dram.physical);
prph_sc_ctrl->pnvm_cfg.pnvm_size =
cpu_to_le32(trans_pcie->pnvm_dram.size);
- return 0;
}
int iwl_trans_pcie_ctx_info_gen3_set_reduce_power(struct iwl_trans *trans,
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
index b281850fbf7a..6691d89d7226 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
@@ -3534,6 +3534,7 @@ static const struct iwl_trans_ops trans_ops_pcie_gen2 = {
.txq_free = iwl_txq_dyn_free,
.wait_txq_empty = iwl_trans_pcie_wait_txq_empty,
.rxq_dma_data = iwl_trans_pcie_rxq_dma_data,
+ .load_pnvm = iwl_trans_pcie_ctx_info_gen3_load_pnvm,
.set_pnvm = iwl_trans_pcie_ctx_info_gen3_set_pnvm,
.set_reduce_power = iwl_trans_pcie_ctx_info_gen3_set_reduce_power,
#ifdef CONFIG_IWLWIFI_DEBUGFS
--
2.38.1
From: Alon Giladi <[email protected]>
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 <[email protected]>
Signed-off-by: Gregory Greenman <[email protected]>
---
drivers/net/wireless/intel/iwlwifi/fw/pnvm.c | 43 +++++++------------
.../intel/iwlwifi/iwl-context-info-gen3.h | 4 +-
.../wireless/intel/iwlwifi/iwl-context-info.h | 5 ++-
.../net/wireless/intel/iwlwifi/iwl-trans.h | 23 ++++++++--
.../intel/iwlwifi/pcie/ctxt-info-gen3.c | 34 +++++++++++----
.../wireless/intel/iwlwifi/pcie/ctxt-info.c | 8 ++--
6 files changed, 72 insertions(+), 45 deletions(-)
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 @@ static int iwl_pnvm_handle_section(struct iwl_trans *trans, const u8 *data,
"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;
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-context-info-gen3.h b/drivers/net/wireless/intel/iwlwifi/iwl-context-info-gen3.h
index 3f7278014009..9d2dcb64523c 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-context-info-gen3.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-context-info-gen3.h
@@ -13,6 +13,8 @@
#define CSR_IML_SIZE_ADDR 0x128
#define CSR_IML_RESP_ADDR 0x12c
+#define UNFRAGMENTED_PNVM_PAYLOADS_NUMBER 2
+
/* Set bit for enabling automatic function boot */
#define CSR_AUTO_FUNC_BOOT_ENA BIT(1)
/* Set bit for initiating function boot */
@@ -278,7 +280,7 @@ int iwl_pcie_ctxt_info_gen3_init(struct iwl_trans *trans,
void iwl_pcie_ctxt_info_gen3_free(struct iwl_trans *trans, bool alive);
int iwl_trans_pcie_ctx_info_gen3_set_pnvm(struct iwl_trans *trans,
- const void *data, u32 len);
+ const struct iwl_pnvm_image *pnvm_payloads);
int iwl_trans_pcie_ctx_info_gen3_set_reduce_power(struct iwl_trans *trans,
const void *data, u32 len);
int iwl_trans_pcie_ctx_info_gen3_set_step(struct iwl_trans *trans,
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-context-info.h b/drivers/net/wireless/intel/iwlwifi/iwl-context-info.h
index 4354d5acac9f..1a1321db137c 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-context-info.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-context-info.h
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/*
* Copyright (C) 2017 Intel Deutschland GmbH
- * Copyright (C) 2018-2020 Intel Corporation
+ * Copyright (C) 2018-2020, 2022 Intel Corporation
*/
#ifndef __iwl_context_info_file_h__
#define __iwl_context_info_file_h__
@@ -177,6 +177,9 @@ void iwl_pcie_ctxt_info_free_paging(struct iwl_trans *trans);
int iwl_pcie_init_fw_sec(struct iwl_trans *trans,
const struct fw_img *fw,
struct iwl_context_info_dram *ctxt_dram);
+void *iwl_pcie_ctxt_info_dma_alloc_coherent(struct iwl_trans *trans,
+ size_t size,
+ dma_addr_t *phys);
int iwl_pcie_ctxt_info_alloc_dma(struct iwl_trans *trans,
const void *data, u32 len,
struct iwl_dram_data *dram);
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h
index 9f1228b5a384..35ddb4cfa356 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h
@@ -459,6 +459,22 @@ struct iwl_trans_rxq_dma_data {
u64 ur_bd_cb;
};
+/* maximal number of DRAM MAP entries supported by FW */
+#define IPC_DRAM_MAP_ENTRY_NUM_MAX 64
+
+/**
+ * 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.
+ */
+struct iwl_pnvm_image {
+ struct {
+ const void *data;
+ u32 len;
+ } chunks[IPC_DRAM_MAP_ENTRY_NUM_MAX];
+ u32 n_chunks;
+};
+
/**
* struct iwl_trans_ops - transport specific operations
*
@@ -614,7 +630,8 @@ struct iwl_trans_ops {
void *sanitize_ctx);
void (*debugfs_cleanup)(struct iwl_trans *trans);
void (*sync_nmi)(struct iwl_trans *trans);
- int (*set_pnvm)(struct iwl_trans *trans, const void *data, u32 len);
+ int (*set_pnvm)(struct iwl_trans *trans,
+ const struct iwl_pnvm_image *pnvm_data);
int (*set_reduce_power)(struct iwl_trans *trans,
const void *data, u32 len);
void (*interrupts)(struct iwl_trans *trans, bool enable);
@@ -1516,10 +1533,10 @@ void iwl_trans_sync_nmi_with_addr(struct iwl_trans *trans, u32 inta_addr,
u32 sw_err_bit);
static inline int iwl_trans_set_pnvm(struct iwl_trans *trans,
- const void *data, u32 len)
+ const struct iwl_pnvm_image *pnvm_data)
{
if (trans->ops->set_pnvm) {
- int ret = trans->ops->set_pnvm(trans, data, len);
+ int ret = trans->ops->set_pnvm(trans, pnvm_data);
if (ret)
return ret;
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c
index cb60ba40fe97..800857e61d65 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c
@@ -282,28 +282,46 @@ void iwl_pcie_ctxt_info_gen3_free(struct iwl_trans *trans, bool alive)
}
int iwl_trans_pcie_ctx_info_gen3_set_pnvm(struct iwl_trans *trans,
- const void *data, u32 len)
+ const struct iwl_pnvm_image *pnvm_payloads)
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
struct iwl_prph_scratch_ctrl_cfg *prph_sc_ctrl =
&trans_pcie->prph_scratch->ctrl_cfg;
- int ret;
+ struct iwl_dram_data *dram = &trans_pcie->pnvm_dram;
if (trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_AX210)
return 0;
/* only allocate the DRAM if not allocated yet */
if (!trans->pnvm_loaded) {
+ u32 len, len0, len1;
+
if (WARN_ON(prph_sc_ctrl->pnvm_cfg.pnvm_size))
return -EBUSY;
- ret = iwl_pcie_ctxt_info_alloc_dma(trans, data, len,
- &trans_pcie->pnvm_dram);
- if (ret < 0) {
- IWL_DEBUG_FW(trans, "Failed to allocate PNVM DMA %d.\n",
- ret);
- return ret;
+ if (pnvm_payloads->n_chunks !=
+ UNFRAGMENTED_PNVM_PAYLOADS_NUMBER) {
+ IWL_DEBUG_FW(trans, "expected 2 payloads, got %d.\n",
+ pnvm_payloads->n_chunks);
+ return -EINVAL;
+ }
+ len0 = pnvm_payloads->chunks[0].len;
+ len1 = pnvm_payloads->chunks[1].len;
+ if (len1 > 0xFFFFFFFF - len0) {
+ IWL_DEBUG_FW(trans, "sizes of payloads overflow.\n");
+ return -EINVAL;
+ }
+ len = len0 + len1;
+
+ dram->block = iwl_pcie_ctxt_info_dma_alloc_coherent(trans, len, &dram->physical);
+ if (!dram->block) {
+ IWL_DEBUG_FW(trans, "Failed to allocate PNVM DMA.\n");
+ return -ENOMEM;
}
+ dram->size = len;
+ memcpy(dram->block, pnvm_payloads->chunks[0].data, len0);
+ memcpy((u8 *)dram->block + len0, pnvm_payloads->chunks[1].data,
+ len1);
}
prph_sc_ctrl->pnvm_cfg.pnvm_base_addr =
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c
index 74ce31fdf45e..5f55efe64bf5 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
* Copyright (C) 2017 Intel Deutschland GmbH
- * Copyright (C) 2018-2021 Intel Corporation
+ * Copyright (C) 2018-2022 Intel Corporation
*/
#include "iwl-trans.h"
#include "iwl-fh.h"
@@ -38,9 +38,9 @@ static void *_iwl_pcie_ctxt_info_dma_alloc_coherent(struct iwl_trans *trans,
return result;
}
-static void *iwl_pcie_ctxt_info_dma_alloc_coherent(struct iwl_trans *trans,
- size_t size,
- dma_addr_t *phys)
+void *iwl_pcie_ctxt_info_dma_alloc_coherent(struct iwl_trans *trans,
+ size_t size,
+ dma_addr_t *phys)
{
return _iwl_pcie_ctxt_info_dma_alloc_coherent(trans, size, phys, 0);
}
--
2.38.1
From: Alon Giladi <[email protected]>
Change the field pnvm_dram to an array that describes many regions
and add a counter to the number of pnvm regions that were allocated
in DRAM.
Signed-off-by: Alon Giladi <[email protected]>
Signed-off-by: Gregory Greenman <[email protected]>
---
.../intel/iwlwifi/pcie/ctxt-info-gen3.c | 13 +++++++++----
.../net/wireless/intel/iwlwifi/pcie/internal.h | 10 ++++++++--
.../net/wireless/intel/iwlwifi/pcie/trans.c | 18 ++++++++++++++----
3 files changed, 31 insertions(+), 10 deletions(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c
index e9f3799d4593..f43246b45a85 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c
@@ -287,7 +287,7 @@ int iwl_trans_pcie_ctx_info_gen3_load_pnvm(struct iwl_trans *trans,
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
struct iwl_prph_scratch_ctrl_cfg *prph_sc_ctrl =
&trans_pcie->prph_scratch->ctrl_cfg;
- struct iwl_dram_data *dram = &trans_pcie->pnvm_dram;
+ struct iwl_dram_data *dram = &trans_pcie->pnvm_dram[0];
u32 len, len0, len1;
if (trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_AX210)
@@ -324,6 +324,7 @@ int iwl_trans_pcie_ctx_info_gen3_load_pnvm(struct iwl_trans *trans,
dram->size = len;
memcpy(dram->block, pnvm_payloads->chunks[0].data, len0);
memcpy((u8 *)dram->block + len0, pnvm_payloads->chunks[1].data, len1);
+ trans_pcie->n_pnvm_regions = 1;
trans->pnvm_loaded = true;
return 0;
@@ -337,11 +338,15 @@ void iwl_trans_pcie_ctx_info_gen3_set_pnvm(struct iwl_trans *trans)
if (trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_AX210)
return;
-
+ /* FIXME: currently we concatenate payloads and save them only in
+ * pnvm_dram[0] - therefor only pnvm_dram[0] is delivered to the
+ * prph_sc. Need to add a UCODE sensitivity and another case in which
+ * we deliver to the prph_sc an array with all the DRAM addresses.
+ */
prph_sc_ctrl->pnvm_cfg.pnvm_base_addr =
- cpu_to_le64(trans_pcie->pnvm_dram.physical);
+ cpu_to_le64(trans_pcie->pnvm_dram[0].physical);
prph_sc_ctrl->pnvm_cfg.pnvm_size =
- cpu_to_le32(trans_pcie->pnvm_dram.size);
+ cpu_to_le32(trans_pcie->pnvm_dram[0].size);
}
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h
index 69b95ad5993b..ca2e7bb2def8 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h
@@ -23,6 +23,7 @@
#include "iwl-op-mode.h"
#include "iwl-drv.h"
#include "queue/tx.h"
+#include "iwl-context-info.h"
/*
* RX related structures and functions
@@ -306,7 +307,8 @@ enum iwl_pcie_imr_status {
* @trans: pointer to the generic transport area
* @scd_base_addr: scheduler sram base address in SRAM
* @kw: keep warm address
- * @pnvm_dram: DRAM area that contains the PNVM data
+ * @pnvm_dram: array of several DRAM areas that contains the PNVM data
+ * @n_pnvm_regions: number of DRAM regions that were allocated for the pnvm
* @pci_dev: basic pci-network driver stuff
* @hw_base: pci hardware address support
* @ucode_write_complete: indicates that the ucode has been copied.
@@ -380,7 +382,9 @@ struct iwl_trans_pcie {
u32 scd_base_addr;
struct iwl_dma_ptr kw;
- struct iwl_dram_data pnvm_dram;
+ /* pnvm data */
+ struct iwl_dram_data pnvm_dram[IPC_DRAM_MAP_ENTRY_NUM_MAX];
+ u8 n_pnvm_regions;
struct iwl_dram_data reduce_power_dram;
struct iwl_txq *txq_memory;
@@ -478,6 +482,8 @@ struct iwl_trans
const struct pci_device_id *ent,
const struct iwl_cfg_trans_params *cfg_trans);
void iwl_trans_pcie_free(struct iwl_trans *trans);
+void iwl_trans_pcie_free_pnvm_dram(struct iwl_trans_pcie *trans_pcie,
+ struct device *dev);
bool __iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans);
#define _iwl_trans_pcie_grab_nic_access(trans) \
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
index 6691d89d7226..cd177addd884 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
@@ -1993,6 +1993,19 @@ static void iwl_trans_pcie_configure(struct iwl_trans *trans,
trans_pcie->fw_reset_handshake = trans_cfg->fw_reset_handshake;
}
+void iwl_trans_pcie_free_pnvm_dram(struct iwl_trans_pcie *trans_pcie,
+ struct device *dev)
+{
+ u8 i;
+
+ for (i = 0; i < trans_pcie->n_pnvm_regions; i++) {
+ dma_free_coherent(dev, trans_pcie->pnvm_dram[i].size,
+ trans_pcie->pnvm_dram[i].block,
+ trans_pcie->pnvm_dram[i].physical);
+ }
+ trans_pcie->n_pnvm_regions = 0;
+}
+
void iwl_trans_pcie_free(struct iwl_trans *trans)
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
@@ -2025,10 +2038,7 @@ void iwl_trans_pcie_free(struct iwl_trans *trans)
iwl_pcie_free_fw_monitor(trans);
- if (trans_pcie->pnvm_dram.size)
- dma_free_coherent(trans->dev, trans_pcie->pnvm_dram.size,
- trans_pcie->pnvm_dram.block,
- trans_pcie->pnvm_dram.physical);
+ iwl_trans_pcie_free_pnvm_dram(trans_pcie, trans->dev);
if (trans_pcie->reduce_power_dram.size)
dma_free_coherent(trans->dev,
--
2.38.1
From: Alon Giladi <[email protected]>
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 <[email protected]>
Signed-off-by: Gregory Greenman <[email protected]>
---
drivers/net/wireless/intel/iwlwifi/fw/pnvm.c | 130 ++++++++++--------
.../net/wireless/intel/iwlwifi/iwl-trans.h | 4 +
2 files changed, 73 insertions(+), 61 deletions(-)
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 @@ static int iwl_pnvm_handle_section(struct iwl_trans *trans, const u8 *data,
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 @@ int iwl_pnvm_load(struct iwl_trans *trans,
*/
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",
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h
index a7e8d45c874c..684b57df9b48 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h
@@ -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;
--
2.38.1
From: Alon Giladi <[email protected]>
Add support for fragmented pnvm images, depending on the FW capability.
Signed-off-by: Alon Giladi <[email protected]>
Signed-off-by: Gregory Greenman <[email protected]>
---
drivers/net/wireless/intel/iwlwifi/fw/file.h | 2 +
drivers/net/wireless/intel/iwlwifi/fw/pnvm.c | 7 +-
drivers/net/wireless/intel/iwlwifi/fw/pnvm.h | 5 +-
.../intel/iwlwifi/iwl-context-info-gen3.h | 6 +-
.../net/wireless/intel/iwlwifi/iwl-trans.h | 16 ++--
drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 3 +-
.../intel/iwlwifi/pcie/ctxt-info-gen3.c | 95 ++++++++++++-------
7 files changed, 88 insertions(+), 46 deletions(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/file.h b/drivers/net/wireless/intel/iwlwifi/fw/file.h
index cddf09d6be1c..96e15f2631ed 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/file.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/file.h
@@ -323,6 +323,7 @@ typedef unsigned int __bitwise iwl_ucode_tlv_capa_t;
* is supported.
* @IWL_UCODE_TLV_CAPA_BT_COEX_RRC: supports BT Coex RRC
* @IWL_UCODE_TLV_CAPA_GSCAN_SUPPORT: supports gscan (no longer used)
+ * @IWL_UCODE_TLV_CAPA_FRAGMENTED_PNVM_IMG: supports fragmented PNVM image
* @IWL_UCODE_TLV_CAPA_SOC_LATENCY_SUPPORT: the firmware supports setting
* stabilization latency for SoCs.
* @IWL_UCODE_TLV_CAPA_STA_PM_NOTIF: firmware will send STA PM notification
@@ -398,6 +399,7 @@ enum iwl_ucode_tlv_capa {
IWL_UCODE_TLV_CAPA_GSCAN_SUPPORT = (__force iwl_ucode_tlv_capa_t)31,
/* set 1 */
+ IWL_UCODE_TLV_CAPA_FRAGMENTED_PNVM_IMG = (__force iwl_ucode_tlv_capa_t)32,
IWL_UCODE_TLV_CAPA_SOC_LATENCY_SUPPORT = (__force iwl_ucode_tlv_capa_t)37,
IWL_UCODE_TLV_CAPA_STA_PM_NOTIF = (__force iwl_ucode_tlv_capa_t)38,
IWL_UCODE_TLV_CAPA_BINDING_CDB_SUPPORT = (__force iwl_ucode_tlv_capa_t)39,
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 */
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.h b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.h
index 203c367dd4de..4e10baa01738 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.h
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/******************************************************************************
*
- * Copyright(c) 2020-2021 Intel Corporation
+ * Copyright(c) 2020-2022 Intel Corporation
*
*****************************************************************************/
@@ -15,7 +15,8 @@
#define MAX_PNVM_NAME 64
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);
static inline
void iwl_pnvm_get_fs_name(struct iwl_trans *trans,
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-context-info-gen3.h b/drivers/net/wireless/intel/iwlwifi/iwl-context-info-gen3.h
index 9f718e43dd81..23208be831f3 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-context-info-gen3.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-context-info-gen3.h
@@ -280,8 +280,10 @@ int iwl_pcie_ctxt_info_gen3_init(struct iwl_trans *trans,
void iwl_pcie_ctxt_info_gen3_free(struct iwl_trans *trans, bool alive);
int iwl_trans_pcie_ctx_info_gen3_load_pnvm(struct iwl_trans *trans,
- const struct iwl_pnvm_image *pnvm_payloads);
-void iwl_trans_pcie_ctx_info_gen3_set_pnvm(struct iwl_trans *trans);
+ const struct iwl_pnvm_image *pnvm_payloads,
+ const struct iwl_ucode_capabilities *capa);
+void iwl_trans_pcie_ctx_info_gen3_set_pnvm(struct iwl_trans *trans,
+ const struct iwl_ucode_capabilities *capa);
int iwl_trans_pcie_ctx_info_gen3_set_reduce_power(struct iwl_trans *trans,
const void *data, u32 len);
int iwl_trans_pcie_ctx_info_gen3_set_step(struct iwl_trans *trans,
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h
index 684b57df9b48..541841bc8f21 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h
@@ -634,8 +634,10 @@ struct iwl_trans_ops {
void (*debugfs_cleanup)(struct iwl_trans *trans);
void (*sync_nmi)(struct iwl_trans *trans);
int (*load_pnvm)(struct iwl_trans *trans,
- const struct iwl_pnvm_image *pnvm_payloads);
- void (*set_pnvm)(struct iwl_trans *trans);
+ const struct iwl_pnvm_image *pnvm_payloads,
+ const struct iwl_ucode_capabilities *capa);
+ void (*set_pnvm)(struct iwl_trans *trans,
+ const struct iwl_ucode_capabilities *capa);
int (*set_reduce_power)(struct iwl_trans *trans,
const void *data, u32 len);
void (*interrupts)(struct iwl_trans *trans, bool enable);
@@ -1539,15 +1541,17 @@ void iwl_trans_sync_nmi_with_addr(struct iwl_trans *trans, u32 inta_addr,
u32 sw_err_bit);
static inline int iwl_trans_load_pnvm(struct iwl_trans *trans,
- const struct iwl_pnvm_image *pnvm_data)
+ const struct iwl_pnvm_image *pnvm_data,
+ const struct iwl_ucode_capabilities *capa)
{
- return trans->ops->load_pnvm(trans, pnvm_data);
+ return trans->ops->load_pnvm(trans, pnvm_data, capa);
}
-static inline void iwl_trans_set_pnvm(struct iwl_trans *trans)
+static inline void iwl_trans_set_pnvm(struct iwl_trans *trans,
+ const struct iwl_ucode_capabilities *capa)
{
if (trans->ops->set_pnvm)
- trans->ops->set_pnvm(trans);
+ trans->ops->set_pnvm(trans, capa);
}
static inline int iwl_trans_set_reduce_power(struct iwl_trans *trans,
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
index b35c96cf7ad2..1b5a80279e3c 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
@@ -433,7 +433,8 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm,
/* if reached this point, Alive notification was received */
iwl_mei_alive_notif(true);
- ret = iwl_pnvm_load(mvm->trans, &mvm->notif_wait);
+ ret = iwl_pnvm_load(mvm->trans, &mvm->notif_wait,
+ &mvm->fw->ucode_capa);
if (ret) {
IWL_ERR(mvm, "Timeout waiting for PNVM load!\n");
iwl_fw_set_current_image(&mvm->fwrt, old_type);
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c
index f43246b45a85..fc450c0d1145 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c
@@ -281,33 +281,20 @@ void iwl_pcie_ctxt_info_gen3_free(struct iwl_trans *trans, bool alive)
trans_pcie->prph_info = NULL;
}
-int iwl_trans_pcie_ctx_info_gen3_load_pnvm(struct iwl_trans *trans,
- const struct iwl_pnvm_image *pnvm_payloads)
+static int iwl_pcie_load_payloads_continuously(struct iwl_trans *trans,
+ const struct iwl_pnvm_image *pnvm_data,
+ struct iwl_dram_data *dram)
{
- struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
- struct iwl_prph_scratch_ctrl_cfg *prph_sc_ctrl =
- &trans_pcie->prph_scratch->ctrl_cfg;
- struct iwl_dram_data *dram = &trans_pcie->pnvm_dram[0];
u32 len, len0, len1;
- if (trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_AX210)
- return 0;
-
- /* only allocate the DRAM if not allocated yet */
- if (trans->pnvm_loaded)
- return 0;
-
- if (WARN_ON(prph_sc_ctrl->pnvm_cfg.pnvm_size))
- return -EBUSY;
-
- if (pnvm_payloads->n_chunks != UNFRAGMENTED_PNVM_PAYLOADS_NUMBER) {
+ if (pnvm_data->n_chunks != UNFRAGMENTED_PNVM_PAYLOADS_NUMBER) {
IWL_DEBUG_FW(trans, "expected 2 payloads, got %d.\n",
- pnvm_payloads->n_chunks);
- return -EINVAL;
+ pnvm_data->n_chunks);
+ return -EINVAL;
}
- len0 = pnvm_payloads->chunks[0].len;
- len1 = pnvm_payloads->chunks[1].len;
+ len0 = pnvm_data->chunks[0].len;
+ len1 = pnvm_data->chunks[1].len;
if (len1 > 0xFFFFFFFF - len0) {
IWL_DEBUG_FW(trans, "sizes of payloads overflow.\n");
return -EINVAL;
@@ -322,32 +309,76 @@ int iwl_trans_pcie_ctx_info_gen3_load_pnvm(struct iwl_trans *trans,
}
dram->size = len;
- memcpy(dram->block, pnvm_payloads->chunks[0].data, len0);
- memcpy((u8 *)dram->block + len0, pnvm_payloads->chunks[1].data, len1);
- trans_pcie->n_pnvm_regions = 1;
+ memcpy(dram->block, pnvm_data->chunks[0].data, len0);
+ memcpy((u8 *)dram->block + len0, pnvm_data->chunks[1].data, len1);
- trans->pnvm_loaded = true;
return 0;
}
-void iwl_trans_pcie_ctx_info_gen3_set_pnvm(struct iwl_trans *trans)
+/* FIXME: An implementation will be added with the next several commits. */
+static int iwl_pcie_load_payloads_segments(struct iwl_trans *trans,
+ const struct iwl_pnvm_image *pnvm_payloads)
+{
+ return -ENOMEM;
+}
+
+int iwl_trans_pcie_ctx_info_gen3_load_pnvm(struct iwl_trans *trans,
+ const struct iwl_pnvm_image *pnvm_payloads,
+ const struct iwl_ucode_capabilities *capa)
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
struct iwl_prph_scratch_ctrl_cfg *prph_sc_ctrl =
&trans_pcie->prph_scratch->ctrl_cfg;
+ struct iwl_dram_data *dram = &trans_pcie->pnvm_dram[0];
+ int ret = 0;
+
+ /* only allocate the DRAM if not allocated yet */
+ if (trans->pnvm_loaded)
+ return 0;
+
+ if (WARN_ON(prph_sc_ctrl->pnvm_cfg.pnvm_size))
+ return -EBUSY;
if (trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_AX210)
- return;
- /* FIXME: currently we concatenate payloads and save them only in
- * pnvm_dram[0] - therefor only pnvm_dram[0] is delivered to the
- * prph_sc. Need to add a UCODE sensitivity and another case in which
- * we deliver to the prph_sc an array with all the DRAM addresses.
- */
+ return 0;
+
+ if (fw_has_capa(capa, IWL_UCODE_TLV_CAPA_FRAGMENTED_PNVM_IMG))
+ return iwl_pcie_load_payloads_segments(trans, pnvm_payloads);
+
+ ret = iwl_pcie_load_payloads_continuously(trans, pnvm_payloads, dram);
+ if (!ret) {
+ trans_pcie->n_pnvm_regions = 1;
+ trans->pnvm_loaded = true;
+ }
+
+ return ret;
+}
+
+/* FIXME: An implementation will be added with the next several commits. */
+static void iwl_pcie_set_pnvm_segments(struct iwl_trans *trans) {}
+
+static void iwl_pcie_set_continuous_pnvm(struct iwl_trans *trans)
+{
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+ struct iwl_prph_scratch_ctrl_cfg *prph_sc_ctrl =
+ &trans_pcie->prph_scratch->ctrl_cfg;
+
prph_sc_ctrl->pnvm_cfg.pnvm_base_addr =
cpu_to_le64(trans_pcie->pnvm_dram[0].physical);
prph_sc_ctrl->pnvm_cfg.pnvm_size =
cpu_to_le32(trans_pcie->pnvm_dram[0].size);
+}
+
+void iwl_trans_pcie_ctx_info_gen3_set_pnvm(struct iwl_trans *trans,
+ const struct iwl_ucode_capabilities *capa)
+{
+ if (trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_AX210)
+ return;
+ if (fw_has_capa(capa, IWL_UCODE_TLV_CAPA_FRAGMENTED_PNVM_IMG))
+ iwl_pcie_set_pnvm_segments(trans);
+ else
+ iwl_pcie_set_continuous_pnvm(trans);
}
int iwl_trans_pcie_ctx_info_gen3_set_reduce_power(struct iwl_trans *trans,
--
2.38.1
From: Alon Giladi <[email protected]>
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 <[email protected]>
Signed-off-by: Gregory Greenman <[email protected]>
---
drivers/net/wireless/intel/iwlwifi/fw/pnvm.c | 7 +-
drivers/net/wireless/intel/iwlwifi/fw/uefi.c | 90 ++++++++-----------
drivers/net/wireless/intel/iwlwifi/fw/uefi.h | 8 +-
.../intel/iwlwifi/iwl-context-info-gen3.h | 5 +-
.../net/wireless/intel/iwlwifi/iwl-trans.h | 11 ++-
.../intel/iwlwifi/pcie/ctxt-info-gen3.c | 25 ++----
6 files changed, 63 insertions(+), 83 deletions(-)
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 @@ int iwl_pnvm_load(struct iwl_trans *trans,
*/
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",
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c
index 01afea33c38c..64b45a5b767e 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c
+++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c
@@ -55,14 +55,14 @@ void *iwl_uefi_get_pnvm(struct iwl_trans *trans, size_t *len)
return data;
}
-static void *iwl_uefi_reduce_power_section(struct iwl_trans *trans,
- const u8 *data, size_t len)
+static int iwl_uefi_reduce_power_section(struct iwl_trans *trans,
+ const u8 *data, size_t len,
+ struct iwl_pnvm_image *pnvm_data)
{
const struct iwl_ucode_tlv *tlv;
- u8 *reduce_power_data = NULL, *tmp;
- u32 size = 0;
IWL_DEBUG_FW(trans, "Handling REDUCE_POWER section\n");
+ memset(pnvm_data, 0, sizeof(*pnvm_data));
while (len >= sizeof(*tlv)) {
u32 tlv_len, tlv_type;
@@ -76,9 +76,7 @@ static void *iwl_uefi_reduce_power_section(struct iwl_trans *trans,
if (len < tlv_len) {
IWL_ERR(trans, "invalid TLV len: %zd/%u\n",
len, tlv_len);
- kfree(reduce_power_data);
- reduce_power_data = ERR_PTR(-EINVAL);
- goto out;
+ return -EINVAL;
}
data += sizeof(*tlv);
@@ -89,23 +87,17 @@ static void *iwl_uefi_reduce_power_section(struct iwl_trans *trans,
"Got IWL_UCODE_TLV_MEM_DESC len %d\n",
tlv_len);
- IWL_DEBUG_FW(trans, "Adding data (size %d)\n", tlv_len);
-
- tmp = krealloc(reduce_power_data, size + tlv_len, GFP_KERNEL);
- if (!tmp) {
+ if (pnvm_data->n_chunks == IPC_DRAM_MAP_ENTRY_NUM_MAX) {
IWL_DEBUG_FW(trans,
- "Couldn't allocate (more) reduce_power_data\n");
-
- kfree(reduce_power_data);
- reduce_power_data = ERR_PTR(-ENOMEM);
- goto out;
+ "too many payloads to allocate in DRAM.\n");
+ return -EINVAL;
}
- reduce_power_data = tmp;
-
- memcpy(reduce_power_data + size, data, tlv_len);
+ IWL_DEBUG_FW(trans, "Adding data (size %d)\n", tlv_len);
- size += tlv_len;
+ pnvm_data->chunks[pnvm_data->n_chunks].data = data;
+ pnvm_data->chunks[pnvm_data->n_chunks].len = tlv_len;
+ pnvm_data->n_chunks++;
break;
}
@@ -124,27 +116,18 @@ static void *iwl_uefi_reduce_power_section(struct iwl_trans *trans,
}
done:
- if (!size) {
+ if (!pnvm_data->n_chunks) {
IWL_DEBUG_FW(trans, "Empty REDUCE_POWER, skipping.\n");
- /* Better safe than sorry, but 'reduce_power_data' should
- * always be NULL if !size.
- */
- kfree(reduce_power_data);
- reduce_power_data = ERR_PTR(-ENOENT);
- goto out;
+ return -ENOENT;
}
-
- IWL_INFO(trans, "loaded REDUCE_POWER\n");
-
-out:
- return reduce_power_data;
+ return 0;
}
-static void *iwl_uefi_reduce_power_parse(struct iwl_trans *trans,
- const u8 *data, size_t len)
+static int iwl_uefi_reduce_power_parse(struct iwl_trans *trans,
+ const u8 *data, size_t len,
+ struct iwl_pnvm_image *pnvm_data)
{
const struct iwl_ucode_tlv *tlv;
- void *sec_data;
IWL_DEBUG_FW(trans, "Parsing REDUCE_POWER data\n");
@@ -160,7 +143,7 @@ static void *iwl_uefi_reduce_power_parse(struct iwl_trans *trans,
if (len < tlv_len) {
IWL_ERR(trans, "invalid TLV len: %zd/%u\n",
len, tlv_len);
- return ERR_PTR(-EINVAL);
+ return -EINVAL;
}
if (tlv_type == IWL_UCODE_TLV_PNVM_SKU) {
@@ -181,11 +164,11 @@ static void *iwl_uefi_reduce_power_parse(struct iwl_trans *trans,
if (trans->sku_id[0] == le32_to_cpu(sku_id->data[0]) &&
trans->sku_id[1] == le32_to_cpu(sku_id->data[1]) &&
trans->sku_id[2] == le32_to_cpu(sku_id->data[2])) {
- sec_data = iwl_uefi_reduce_power_section(trans,
- data,
- len);
- if (!IS_ERR(sec_data))
- return sec_data;
+ int ret = iwl_uefi_reduce_power_section(trans,
+ data, len,
+ pnvm_data);
+ if (!ret)
+ return 0;
} else {
IWL_DEBUG_FW(trans, "SKU ID didn't match!\n");
}
@@ -195,20 +178,20 @@ static void *iwl_uefi_reduce_power_parse(struct iwl_trans *trans,
}
}
- return ERR_PTR(-ENOENT);
+ return -ENOENT;
}
-void *iwl_uefi_get_reduced_power(struct iwl_trans *trans, size_t *len)
+int iwl_uefi_get_reduced_power(struct iwl_trans *trans,
+ struct iwl_pnvm_image *pnvm_data)
{
struct pnvm_sku_package *package;
- void *data = NULL;
unsigned long package_size;
efi_status_t status;
-
- *len = 0;
+ int ret;
+ size_t len = 0;
if (!efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE))
- return ERR_PTR(-ENODEV);
+ return -ENODEV;
/*
* TODO: we hardcode a maximum length here, because reading
@@ -219,7 +202,7 @@ void *iwl_uefi_get_reduced_power(struct iwl_trans *trans, size_t *len)
package = kmalloc(package_size, GFP_KERNEL);
if (!package)
- return ERR_PTR(-ENOMEM);
+ return -ENOMEM;
status = efi.get_variable(IWL_UEFI_REDUCED_POWER_NAME, &IWL_EFI_VAR_GUID,
NULL, &package_size, package);
@@ -228,22 +211,23 @@ void *iwl_uefi_get_reduced_power(struct iwl_trans *trans, size_t *len)
"Reduced Power UEFI variable not found 0x%lx (len %lu)\n",
status, package_size);
kfree(package);
- return ERR_PTR(-ENOENT);
+ return -ENOENT;
}
IWL_DEBUG_FW(trans, "Read reduced power from UEFI with size %lu\n",
package_size);
- *len = package_size;
+ len = package_size;
IWL_DEBUG_FW(trans, "rev %d, total_size %d, n_skus %d\n",
package->rev, package->total_size, package->n_skus);
- data = iwl_uefi_reduce_power_parse(trans, package->data,
- *len - sizeof(*package));
+ ret = iwl_uefi_reduce_power_parse(trans, package->data,
+ len - sizeof(*package),
+ pnvm_data);
kfree(package);
- return data;
+ return ret;
}
static int iwl_uefi_step_parse(struct uefi_cnv_common_step_data *common_step_data,
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.h b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h
index 17089bc74cf9..03176f73151a 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h
@@ -50,7 +50,8 @@ struct uefi_cnv_common_step_data {
*/
#ifdef CONFIG_EFI
void *iwl_uefi_get_pnvm(struct iwl_trans *trans, size_t *len);
-void *iwl_uefi_get_reduced_power(struct iwl_trans *trans, size_t *len);
+int iwl_uefi_get_reduced_power(struct iwl_trans *trans,
+ struct iwl_pnvm_image *pnvm_data);
void iwl_uefi_get_step_table(struct iwl_trans *trans);
#else /* CONFIG_EFI */
static inline
@@ -60,9 +61,10 @@ void *iwl_uefi_get_pnvm(struct iwl_trans *trans, size_t *len)
}
static inline
-void *iwl_uefi_get_reduced_power(struct iwl_trans *trans, size_t *len)
+int iwl_uefi_get_reduced_power(struct iwl_trans *trans,
+ struct iwl_pnvm_image *pnvm_data)
{
- return ERR_PTR(-EOPNOTSUPP);
+ return -EOPNOTSUPP;
}
static inline
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-context-info-gen3.h b/drivers/net/wireless/intel/iwlwifi/iwl-context-info-gen3.h
index e019aec027d6..7e7d135e85b1 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-context-info-gen3.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-context-info-gen3.h
@@ -292,8 +292,9 @@ int iwl_trans_pcie_ctx_info_gen3_load_pnvm(struct iwl_trans *trans,
const struct iwl_ucode_capabilities *capa);
void iwl_trans_pcie_ctx_info_gen3_set_pnvm(struct iwl_trans *trans,
const struct iwl_ucode_capabilities *capa);
-int iwl_trans_pcie_ctx_info_gen3_load_reduce_power(struct iwl_trans *trans,
- const void *data, u32 len);
+int iwl_trans_pcie_ctx_info_gen3_load_reduce_power
+ (struct iwl_trans *trans,
+ const struct iwl_pnvm_image *payloads);
void iwl_trans_pcie_ctx_info_gen3_set_reduce_power(struct iwl_trans *trans);
int iwl_trans_pcie_ctx_info_gen3_set_step(struct iwl_trans *trans,
u32 mbx_addr_0_step, u32 mbx_addr_1_step);
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h
index 888869d9c94a..8e9585d3a0ee 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h
@@ -641,8 +641,7 @@ struct iwl_trans_ops {
void (*set_pnvm)(struct iwl_trans *trans,
const struct iwl_ucode_capabilities *capa);
int (*load_reduce_power)(struct iwl_trans *trans,
- const void *data,
- u32 len);
+ const struct iwl_pnvm_image *payloads);
void (*set_reduce_power)(struct iwl_trans *trans);
void (*interrupts)(struct iwl_trans *trans, bool enable);
@@ -1559,11 +1558,11 @@ static inline void iwl_trans_set_pnvm(struct iwl_trans *trans,
trans->ops->set_pnvm(trans, capa);
}
-static inline int iwl_trans_load_reduce_power(struct iwl_trans *trans,
- const void *data,
- u32 len)
+static inline int iwl_trans_load_reduce_power
+ (struct iwl_trans *trans,
+ const struct iwl_pnvm_image *payloads)
{
- return trans->ops->load_reduce_power(trans, data, len);
+ return trans->ops->load_reduce_power(trans, payloads);
}
static inline void iwl_trans_set_reduce_power(struct iwl_trans *trans)
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c
index 2619c868b51f..26d5ba777d24 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c
@@ -443,31 +443,24 @@ void iwl_trans_pcie_ctx_info_gen3_set_pnvm(struct iwl_trans *trans,
}
int iwl_trans_pcie_ctx_info_gen3_load_reduce_power(struct iwl_trans *trans,
- const void *data,
- u32 len)
+ const struct iwl_pnvm_image *payloads)
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
struct iwl_prph_scratch_ctrl_cfg *prph_sc_ctrl =
&trans_pcie->prph_scratch->ctrl_cfg;
- int ret;
+ struct iwl_dram_data *dram = &trans_pcie->reduce_power_dram;
if (trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_AX210)
return 0;
- /* only allocate the DRAM if not allocated yet */
- if (!trans->reduce_power_loaded) {
- if (WARN_ON(prph_sc_ctrl->reduce_power_cfg.size))
- return -EBUSY;
+ if (WARN_ON(prph_sc_ctrl->reduce_power_cfg.size))
+ return -EBUSY;
- ret = iwl_pcie_ctxt_info_alloc_dma(trans, data, len,
- &trans_pcie->reduce_power_dram);
- if (ret < 0) {
- IWL_DEBUG_FW(trans,
- "Failed to allocate reduce power DMA %d.\n",
- ret);
- return ret;
- }
- }
+ /* only allocate the DRAM if not allocated yet */
+ if (!trans->reduce_power_loaded)
+ return iwl_pcie_load_payloads_continuously(trans,
+ payloads,
+ dram);
return 0;
}
--
2.38.1
From: Alon Giladi <[email protected]>
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 <[email protected]>
Signed-off-by: Gregory Greenman <[email protected]>
---
drivers/net/wireless/intel/iwlwifi/fw/pnvm.c | 9 ++++--
.../intel/iwlwifi/iwl-context-info-gen3.h | 5 ++--
.../net/wireless/intel/iwlwifi/iwl-trans.h | 28 +++++++++++--------
.../intel/iwlwifi/pcie/ctxt-info-gen3.c | 18 +++++++++---
.../net/wireless/intel/iwlwifi/pcie/trans.c | 1 +
5 files changed, 40 insertions(+), 21 deletions(-)
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 @@ int iwl_pnvm_load(struct iwl_trans *trans,
*/
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),
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-context-info-gen3.h b/drivers/net/wireless/intel/iwlwifi/iwl-context-info-gen3.h
index bbf4b18cd9de..e019aec027d6 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-context-info-gen3.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-context-info-gen3.h
@@ -292,8 +292,9 @@ int iwl_trans_pcie_ctx_info_gen3_load_pnvm(struct iwl_trans *trans,
const struct iwl_ucode_capabilities *capa);
void iwl_trans_pcie_ctx_info_gen3_set_pnvm(struct iwl_trans *trans,
const struct iwl_ucode_capabilities *capa);
-int iwl_trans_pcie_ctx_info_gen3_set_reduce_power(struct iwl_trans *trans,
- const void *data, u32 len);
+int iwl_trans_pcie_ctx_info_gen3_load_reduce_power(struct iwl_trans *trans,
+ const void *data, u32 len);
+void iwl_trans_pcie_ctx_info_gen3_set_reduce_power(struct iwl_trans *trans);
int iwl_trans_pcie_ctx_info_gen3_set_step(struct iwl_trans *trans,
u32 mbx_addr_0_step, u32 mbx_addr_1_step);
#endif /* __iwl_context_info_file_gen3_h__ */
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h
index 541841bc8f21..888869d9c94a 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h
@@ -562,6 +562,8 @@ struct iwl_pnvm_image {
* @load_pnvm: save the pnvm data in DRAM
* @set_pnvm: set the pnvm data in the prph scratch buffer, inside the
* context info.
+ * @load_reduce_power: copy reduce power table to the corresponding DRAM memory
+ * @set_reduce_power: set reduce power table addresses in the sratch buffer
* @interrupts: disable/enable interrupts to transport
*/
struct iwl_trans_ops {
@@ -638,8 +640,11 @@ struct iwl_trans_ops {
const struct iwl_ucode_capabilities *capa);
void (*set_pnvm)(struct iwl_trans *trans,
const struct iwl_ucode_capabilities *capa);
- int (*set_reduce_power)(struct iwl_trans *trans,
- const void *data, u32 len);
+ int (*load_reduce_power)(struct iwl_trans *trans,
+ const void *data,
+ u32 len);
+ void (*set_reduce_power)(struct iwl_trans *trans);
+
void (*interrupts)(struct iwl_trans *trans, bool enable);
int (*imr_dma_data)(struct iwl_trans *trans,
u32 dst_addr, u64 src_addr,
@@ -1554,18 +1559,17 @@ static inline void iwl_trans_set_pnvm(struct iwl_trans *trans,
trans->ops->set_pnvm(trans, capa);
}
-static inline int iwl_trans_set_reduce_power(struct iwl_trans *trans,
- const void *data, u32 len)
+static inline int iwl_trans_load_reduce_power(struct iwl_trans *trans,
+ const void *data,
+ u32 len)
{
- if (trans->ops->set_reduce_power) {
- int ret = trans->ops->set_reduce_power(trans, data, len);
-
- if (ret)
- return ret;
- }
+ return trans->ops->load_reduce_power(trans, data, len);
+}
- trans->reduce_power_loaded = true;
- return 0;
+static inline void iwl_trans_set_reduce_power(struct iwl_trans *trans)
+{
+ if (trans->ops->set_reduce_power)
+ trans->ops->set_reduce_power(trans);
}
static inline bool iwl_trans_dbg_ini_valid(struct iwl_trans *trans)
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c
index e0477ca4ccc3..2619c868b51f 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c
@@ -442,8 +442,9 @@ void iwl_trans_pcie_ctx_info_gen3_set_pnvm(struct iwl_trans *trans,
iwl_pcie_set_continuous_pnvm(trans);
}
-int iwl_trans_pcie_ctx_info_gen3_set_reduce_power(struct iwl_trans *trans,
- const void *data, u32 len)
+int iwl_trans_pcie_ctx_info_gen3_load_reduce_power(struct iwl_trans *trans,
+ const void *data,
+ u32 len)
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
struct iwl_prph_scratch_ctrl_cfg *prph_sc_ctrl =
@@ -467,12 +468,21 @@ int iwl_trans_pcie_ctx_info_gen3_set_reduce_power(struct iwl_trans *trans,
return ret;
}
}
+ return 0;
+}
+
+void iwl_trans_pcie_ctx_info_gen3_set_reduce_power(struct iwl_trans *trans)
+{
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+ struct iwl_prph_scratch_ctrl_cfg *prph_sc_ctrl =
+ &trans_pcie->prph_scratch->ctrl_cfg;
+
+ if (trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_AX210)
+ return;
prph_sc_ctrl->reduce_power_cfg.base_addr =
cpu_to_le64(trans_pcie->reduce_power_dram.physical);
prph_sc_ctrl->reduce_power_cfg.size =
cpu_to_le32(trans_pcie->reduce_power_dram.size);
-
- return 0;
}
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
index 5235a7517c53..55541c1be5d6 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
@@ -3554,6 +3554,7 @@ static const struct iwl_trans_ops trans_ops_pcie_gen2 = {
.rxq_dma_data = iwl_trans_pcie_rxq_dma_data,
.load_pnvm = iwl_trans_pcie_ctx_info_gen3_load_pnvm,
.set_pnvm = iwl_trans_pcie_ctx_info_gen3_set_pnvm,
+ .load_reduce_power = iwl_trans_pcie_ctx_info_gen3_load_reduce_power,
.set_reduce_power = iwl_trans_pcie_ctx_info_gen3_set_reduce_power,
#ifdef CONFIG_IWLWIFI_DEBUGFS
.debugfs_cleanup = iwl_trans_pcie_debugfs_cleanup,
--
2.38.1
From: Gregory Greenman <[email protected]>
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 <[email protected]>
---
drivers/net/wireless/intel/iwlwifi/fw/pnvm.c | 5 ++
drivers/net/wireless/intel/iwlwifi/fw/uefi.c | 62 ++++++++++++++------
drivers/net/wireless/intel/iwlwifi/fw/uefi.h | 9 +++
3 files changed, 59 insertions(+), 17 deletions(-)
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");
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c
index 488b9fb79743..9877988db0d2 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c
+++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c
@@ -17,6 +17,12 @@
0xb2, 0xec, 0xf5, 0xa3, \
0x59, 0x4f, 0x4a, 0xea)
+struct iwl_uefi_pnvm_mem_desc {
+ __le32 addr;
+ __le32 size;
+ const u8 data[];
+} __packed;
+
static void *iwl_uefi_get_variable(efi_char16_t *name, efi_guid_t *guid,
unsigned long *data_size)
{
@@ -70,6 +76,42 @@ void *iwl_uefi_get_pnvm(struct iwl_trans *trans, size_t *len)
return data;
}
+int iwl_uefi_handle_tlv_mem_desc(struct iwl_trans *trans, const u8 *data,
+ u32 tlv_len, struct iwl_pnvm_image *pnvm_data)
+{
+ const struct iwl_uefi_pnvm_mem_desc *desc = (const void *)data;
+ u32 data_len;
+
+ if (tlv_len < sizeof(*desc)) {
+ IWL_DEBUG_FW(trans, "TLV len (%d) is too small\n", tlv_len);
+ return -EINVAL;
+ }
+
+ data_len = tlv_len - sizeof(*desc);
+
+ IWL_DEBUG_FW(trans,
+ "Handle IWL_UCODE_TLV_MEM_DESC, len %d data_len %d\n",
+ tlv_len, data_len);
+
+ if (le32_to_cpu(desc->size) != data_len) {
+ IWL_DEBUG_FW(trans, "invalid mem desc size %d\n", desc->size);
+ return -EINVAL;
+ }
+
+ 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;
+ }
+
+ IWL_DEBUG_FW(trans, "Adding data (size %d)\n", data_len);
+
+ pnvm_data->chunks[pnvm_data->n_chunks].data = desc->data;
+ pnvm_data->chunks[pnvm_data->n_chunks].len = data_len;
+ pnvm_data->n_chunks++;
+
+ return 0;
+}
+
static int iwl_uefi_reduce_power_section(struct iwl_trans *trans,
const u8 *data, size_t len,
struct iwl_pnvm_image *pnvm_data)
@@ -97,25 +139,11 @@ static int iwl_uefi_reduce_power_section(struct iwl_trans *trans,
data += sizeof(*tlv);
switch (tlv_type) {
- case IWL_UCODE_TLV_MEM_DESC: {
- IWL_DEBUG_FW(trans,
- "Got IWL_UCODE_TLV_MEM_DESC len %d\n",
- tlv_len);
-
- if (pnvm_data->n_chunks == IPC_DRAM_MAP_ENTRY_NUM_MAX) {
- IWL_DEBUG_FW(trans,
- "too many payloads to allocate in DRAM.\n");
+ case IWL_UCODE_TLV_MEM_DESC:
+ if (iwl_uefi_handle_tlv_mem_desc(trans, data, tlv_len,
+ pnvm_data))
return -EINVAL;
- }
-
- IWL_DEBUG_FW(trans, "Adding data (size %d)\n", tlv_len);
-
- pnvm_data->chunks[pnvm_data->n_chunks].data = data;
- pnvm_data->chunks[pnvm_data->n_chunks].len = tlv_len;
- pnvm_data->n_chunks++;
-
break;
- }
case IWL_UCODE_TLV_PNVM_SKU:
IWL_DEBUG_FW(trans,
"New REDUCE_POWER section started, stop parsing.\n");
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.h b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h
index dc7ccf49d92d..1369cc4855c3 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h
@@ -46,6 +46,8 @@ int iwl_uefi_reduce_power_parse(struct iwl_trans *trans,
const u8 *data, size_t len,
struct iwl_pnvm_image *pnvm_data);
void iwl_uefi_get_step_table(struct iwl_trans *trans);
+int iwl_uefi_handle_tlv_mem_desc(struct iwl_trans *trans, const u8 *data,
+ u32 tlv_len, struct iwl_pnvm_image *pnvm_data);
#else /* CONFIG_EFI */
static inline void *iwl_uefi_get_pnvm(struct iwl_trans *trans, size_t *len)
{
@@ -69,6 +71,13 @@ iwl_uefi_get_reduced_power(struct iwl_trans *trans, size_t *len)
static inline void iwl_uefi_get_step_table(struct iwl_trans *trans)
{
}
+
+static inline int
+iwl_uefi_handle_tlv_mem_desc(struct iwl_trans *trans, const u8 *data,
+ u32 tlv_len, struct iwl_pnvm_image *pnvm_data)
+{
+ return 0;
+}
#endif /* CONFIG_EFI */
#if defined(CONFIG_EFI) && defined(CONFIG_ACPI)
--
2.38.1
From: Johannes Berg <[email protected]>
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 <[email protected]>
Signed-off-by: Gregory Greenman <[email protected]>
---
drivers/net/wireless/intel/iwlwifi/fw/pnvm.c | 155 +++++++++++--------
1 file changed, 89 insertions(+), 66 deletions(-)
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);
--
2.38.1
From: Alon Giladi <[email protected]>
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 <[email protected]>
Signed-off-by: Gregory Greenman <[email protected]>
---
drivers/net/wireless/intel/iwlwifi/fw/pnvm.c | 40 ++++++++++++-------
drivers/net/wireless/intel/iwlwifi/fw/uefi.c | 31 +++++++-------
drivers/net/wireless/intel/iwlwifi/fw/uefi.h | 27 ++++++++-----
.../net/wireless/intel/iwlwifi/iwl-trans.h | 2 +
4 files changed, 58 insertions(+), 42 deletions(-)
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);
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c
index 64b45a5b767e..1666ef3a482e 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c
+++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
- * Copyright(c) 2021-2022 Intel Corporation
+ * Copyright(c) 2021-2023 Intel Corporation
*/
#include "iwl-drv.h"
@@ -123,9 +123,9 @@ static int iwl_uefi_reduce_power_section(struct iwl_trans *trans,
return 0;
}
-static int iwl_uefi_reduce_power_parse(struct iwl_trans *trans,
- const u8 *data, size_t len,
- struct iwl_pnvm_image *pnvm_data)
+int iwl_uefi_reduce_power_parse(struct iwl_trans *trans,
+ const u8 *data, size_t len,
+ struct iwl_pnvm_image *pnvm_data)
{
const struct iwl_ucode_tlv *tlv;
@@ -181,17 +181,15 @@ static int iwl_uefi_reduce_power_parse(struct iwl_trans *trans,
return -ENOENT;
}
-int iwl_uefi_get_reduced_power(struct iwl_trans *trans,
- struct iwl_pnvm_image *pnvm_data)
+u8 *iwl_uefi_get_reduced_power(struct iwl_trans *trans, size_t *len)
{
struct pnvm_sku_package *package;
unsigned long package_size;
efi_status_t status;
- int ret;
- size_t len = 0;
+ u8 *data;
if (!efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE))
- return -ENODEV;
+ return ERR_PTR(-ENODEV);
/*
* TODO: we hardcode a maximum length here, because reading
@@ -202,7 +200,7 @@ int iwl_uefi_get_reduced_power(struct iwl_trans *trans,
package = kmalloc(package_size, GFP_KERNEL);
if (!package)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
status = efi.get_variable(IWL_UEFI_REDUCED_POWER_NAME, &IWL_EFI_VAR_GUID,
NULL, &package_size, package);
@@ -211,23 +209,22 @@ int iwl_uefi_get_reduced_power(struct iwl_trans *trans,
"Reduced Power UEFI variable not found 0x%lx (len %lu)\n",
status, package_size);
kfree(package);
- return -ENOENT;
+ return ERR_PTR(-ENOENT);
}
IWL_DEBUG_FW(trans, "Read reduced power from UEFI with size %lu\n",
package_size);
- len = package_size;
IWL_DEBUG_FW(trans, "rev %d, total_size %d, n_skus %d\n",
package->rev, package->total_size, package->n_skus);
- ret = iwl_uefi_reduce_power_parse(trans, package->data,
- len - sizeof(*package),
- pnvm_data);
-
+ *len = package_size - sizeof(*package);
+ data = kmemdup(package->data, *len, GFP_KERNEL);
+ if (!data)
+ return ERR_PTR(-ENOMEM);
kfree(package);
- return ret;
+ return data;
}
static int iwl_uefi_step_parse(struct uefi_cnv_common_step_data *common_step_data,
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.h b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h
index 03176f73151a..10bed372e67c 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/*
- * Copyright(c) 2021-2022 Intel Corporation
+ * Copyright(c) 2021-2023 Intel Corporation
*/
#ifndef __iwl_fw_uefi__
#define __iwl_fw_uefi__
@@ -50,25 +50,32 @@ struct uefi_cnv_common_step_data {
*/
#ifdef CONFIG_EFI
void *iwl_uefi_get_pnvm(struct iwl_trans *trans, size_t *len);
-int iwl_uefi_get_reduced_power(struct iwl_trans *trans,
- struct iwl_pnvm_image *pnvm_data);
+u8 *iwl_uefi_get_reduced_power(struct iwl_trans *trans, size_t *len);
+int iwl_uefi_reduce_power_parse(struct iwl_trans *trans,
+ const u8 *data, size_t len,
+ struct iwl_pnvm_image *pnvm_data);
void iwl_uefi_get_step_table(struct iwl_trans *trans);
#else /* CONFIG_EFI */
-static inline
-void *iwl_uefi_get_pnvm(struct iwl_trans *trans, size_t *len)
+static inline void *iwl_uefi_get_pnvm(struct iwl_trans *trans, size_t *len)
{
return ERR_PTR(-EOPNOTSUPP);
}
-static inline
-int iwl_uefi_get_reduced_power(struct iwl_trans *trans,
- struct iwl_pnvm_image *pnvm_data)
+static inline int
+iwl_uefi_reduce_power_parse(struct iwl_trans *trans,
+ const u8 *data, size_t len,
+ struct iwl_pnvm_image *pnvm_data)
{
return -EOPNOTSUPP;
}
-static inline
-void iwl_uefi_get_step_table(struct iwl_trans *trans)
+static inline u8 *
+iwl_uefi_get_reduced_power(struct iwl_trans *trans, size_t *len)
+{
+ return ERR_PTR(-EOPNOTSUPP);
+}
+
+static inline void iwl_uefi_get_step_table(struct iwl_trans *trans)
{
}
#endif /* CONFIG_EFI */
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h
index 61ee6c1f4a1e..2915f9b2534c 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h
@@ -1047,6 +1047,7 @@ struct iwl_trans_txqs {
* @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
+ * @failed_to_load_reduce_power_image: set to true if pnvm loading 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;
@@ -1096,6 +1097,7 @@ struct iwl_trans {
u8 pnvm_loaded:1;
u8 fail_to_parse_pnvm_image:1;
u8 reduce_power_loaded:1;
+ u8 failed_to_load_reduce_power_image:1;
const struct iwl_hcmd_arr *command_groups;
int command_groups_size;
--
2.38.1
From: Gregory Greenman <[email protected]>
Use efi.get_variable() with NULL pointer for data in order to
obtain entry size and then call it again with the correct size
to get the entry itself.
Signed-off-by: Gregory Greenman <[email protected]>
---
drivers/net/wireless/intel/iwlwifi/fw/uefi.c | 143 ++++++++++---------
drivers/net/wireless/intel/iwlwifi/fw/uefi.h | 13 +-
2 files changed, 74 insertions(+), 82 deletions(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c
index 1666ef3a482e..488b9fb79743 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c
+++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c
@@ -17,38 +17,53 @@
0xb2, 0xec, 0xf5, 0xa3, \
0x59, 0x4f, 0x4a, 0xea)
-void *iwl_uefi_get_pnvm(struct iwl_trans *trans, size_t *len)
+static void *iwl_uefi_get_variable(efi_char16_t *name, efi_guid_t *guid,
+ unsigned long *data_size)
{
- void *data;
- unsigned long package_size;
efi_status_t status;
+ void *data;
- *len = 0;
+ if (!data_size)
+ return ERR_PTR(-EINVAL);
if (!efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE))
return ERR_PTR(-ENODEV);
- /*
- * TODO: we hardcode a maximum length here, because reading
- * from the UEFI is not working. To implement this properly,
- * we have to call efivar_entry_size().
- */
- package_size = IWL_HARDCODED_PNVM_SIZE;
+ /* first call with NULL data to get the exact entry size */
+ *data_size = 0;
+ status = efi.get_variable(name, guid, NULL, data_size, NULL);
+ if (status != EFI_BUFFER_TOO_SMALL || !*data_size)
+ return ERR_PTR(-EIO);
- data = kmalloc(package_size, GFP_KERNEL);
+ data = kmalloc(*data_size, GFP_KERNEL);
if (!data)
return ERR_PTR(-ENOMEM);
- status = efi.get_variable(IWL_UEFI_OEM_PNVM_NAME, &IWL_EFI_VAR_GUID,
- NULL, &package_size, data);
+ status = efi.get_variable(name, guid, NULL, data_size, data);
if (status != EFI_SUCCESS) {
- IWL_DEBUG_FW(trans,
- "PNVM UEFI variable not found 0x%lx (len %lu)\n",
- status, package_size);
kfree(data);
return ERR_PTR(-ENOENT);
}
+ return data;
+}
+
+void *iwl_uefi_get_pnvm(struct iwl_trans *trans, size_t *len)
+{
+ unsigned long package_size;
+ void *data;
+
+ *len = 0;
+
+ data = iwl_uefi_get_variable(IWL_UEFI_OEM_PNVM_NAME, &IWL_EFI_VAR_GUID,
+ &package_size);
+ if (IS_ERR(data)) {
+ IWL_DEBUG_FW(trans,
+ "PNVM UEFI variable not found 0x%lx (len %lu)\n",
+ PTR_ERR(data), package_size);
+ return data;
+ }
+
IWL_DEBUG_FW(trans, "Read PNVM from UEFI with size %lu\n", package_size);
*len = package_size;
@@ -185,31 +200,24 @@ u8 *iwl_uefi_get_reduced_power(struct iwl_trans *trans, size_t *len)
{
struct pnvm_sku_package *package;
unsigned long package_size;
- efi_status_t status;
u8 *data;
- if (!efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE))
- return ERR_PTR(-ENODEV);
-
- /*
- * TODO: we hardcode a maximum length here, because reading
- * from the UEFI is not working. To implement this properly,
- * we have to call efivar_entry_size().
- */
- package_size = IWL_HARDCODED_REDUCE_POWER_SIZE;
+ package = iwl_uefi_get_variable(IWL_UEFI_REDUCED_POWER_NAME,
+ &IWL_EFI_VAR_GUID, &package_size);
- package = kmalloc(package_size, GFP_KERNEL);
- if (!package)
- return ERR_PTR(-ENOMEM);
-
- status = efi.get_variable(IWL_UEFI_REDUCED_POWER_NAME, &IWL_EFI_VAR_GUID,
- NULL, &package_size, package);
- if (status != EFI_SUCCESS) {
+ if (IS_ERR(package)) {
IWL_DEBUG_FW(trans,
"Reduced Power UEFI variable not found 0x%lx (len %lu)\n",
- status, package_size);
+ PTR_ERR(package), package_size);
+ return ERR_CAST(package);
+ }
+
+ if (package_size < sizeof(*package)) {
+ IWL_DEBUG_FW(trans,
+ "Invalid Reduced Power UEFI variable len (%lu)\n",
+ package_size);
kfree(package);
- return ERR_PTR(-ENOENT);
+ return ERR_PTR(-EINVAL);
}
IWL_DEBUG_FW(trans, "Read reduced power from UEFI with size %lu\n",
@@ -220,8 +228,11 @@ u8 *iwl_uefi_get_reduced_power(struct iwl_trans *trans, size_t *len)
*len = package_size - sizeof(*package);
data = kmemdup(package->data, *len, GFP_KERNEL);
- if (!data)
+ if (!data) {
+ kfree(package);
return ERR_PTR(-ENOMEM);
+ }
+
kfree(package);
return data;
@@ -245,31 +256,27 @@ void iwl_uefi_get_step_table(struct iwl_trans *trans)
{
struct uefi_cnv_common_step_data *data;
unsigned long package_size;
- efi_status_t status;
int ret;
if (trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_AX210)
return;
- if (!efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE))
- return;
+ data = iwl_uefi_get_variable(IWL_UEFI_STEP_NAME, &IWL_EFI_VAR_GUID,
+ &package_size);
- /* TODO: we hardcode a maximum length here, because reading
- * from the UEFI is not working. To implement this properly,
- * we have to call efivar_entry_size().
- */
- package_size = IWL_HARDCODED_STEP_SIZE;
-
- data = kmalloc(package_size, GFP_KERNEL);
- if (!data)
+ if (IS_ERR(data)) {
+ IWL_DEBUG_FW(trans,
+ "STEP UEFI variable not found 0x%lx\n",
+ PTR_ERR(data));
return;
+ }
- status = efi.get_variable(IWL_UEFI_STEP_NAME, &IWL_EFI_VAR_GUID,
- NULL, &package_size, data);
- if (status != EFI_SUCCESS) {
+ if (package_size < sizeof(*data)) {
IWL_DEBUG_FW(trans,
- "STEP UEFI variable not found 0x%lx\n", status);
- goto out_free;
+ "Invalid STEP table UEFI variable len (%lu)\n",
+ package_size);
+ kfree(data);
+ return;
}
IWL_DEBUG_FW(trans, "Read STEP from UEFI with size %lu\n",
@@ -279,7 +286,6 @@ void iwl_uefi_get_step_table(struct iwl_trans *trans)
if (ret < 0)
IWL_DEBUG_FW(trans, "Cannot read STEP tables. rev is invalid\n");
-out_free:
kfree(data);
}
IWL_EXPORT_SYMBOL(iwl_uefi_get_step_table);
@@ -322,29 +328,26 @@ void iwl_uefi_get_sgom_table(struct iwl_trans *trans,
{
struct uefi_cnv_wlan_sgom_data *data;
unsigned long package_size;
- efi_status_t status;
int ret;
- if (!fwrt->geo_enabled ||
- !efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE))
+ if (!fwrt->geo_enabled)
return;
- /* TODO: we hardcode a maximum length here, because reading
- * from the UEFI is not working. To implement this properly,
- * we have to call efivar_entry_size().
- */
- package_size = IWL_HARDCODED_SGOM_SIZE;
-
- data = kmalloc(package_size, GFP_KERNEL);
- if (!data)
+ data = iwl_uefi_get_variable(IWL_UEFI_SGOM_NAME, &IWL_EFI_VAR_GUID,
+ &package_size);
+ if (IS_ERR(data)) {
+ IWL_DEBUG_FW(trans,
+ "SGOM UEFI variable not found 0x%lx\n",
+ PTR_ERR(data));
return;
+ }
- status = efi.get_variable(IWL_UEFI_SGOM_NAME, &IWL_EFI_VAR_GUID,
- NULL, &package_size, data);
- if (status != EFI_SUCCESS) {
+ if (package_size < sizeof(*data)) {
IWL_DEBUG_FW(trans,
- "SGOM UEFI variable not found 0x%lx\n", status);
- goto out_free;
+ "Invalid SGOM table UEFI variable len (%lu)\n",
+ package_size);
+ kfree(data);
+ return;
}
IWL_DEBUG_FW(trans, "Read SGOM from UEFI with size %lu\n",
@@ -354,9 +357,7 @@ void iwl_uefi_get_sgom_table(struct iwl_trans *trans,
if (ret < 0)
IWL_DEBUG_FW(trans, "Cannot read SGOM tables. rev is invalid\n");
-out_free:
kfree(data);
-
}
IWL_EXPORT_SYMBOL(iwl_uefi_get_sgom_table);
#endif /* CONFIG_ACPI */
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.h b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h
index 10bed372e67c..dc7ccf49d92d 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h
@@ -10,16 +10,7 @@
#define IWL_UEFI_SGOM_NAME L"UefiCnvWlanSarGeoOffsetMapping"
#define IWL_UEFI_STEP_NAME L"UefiCnvCommonSTEP"
-/*
- * TODO: we have these hardcoded values that the caller must pass,
- * because reading from the UEFI is not working. To implement this
- * properly, we have to change iwl_pnvm_get_from_uefi() to call
- * efivar_entry_size() and return the value to the caller instead.
- */
-#define IWL_HARDCODED_PNVM_SIZE 4096
-#define IWL_HARDCODED_REDUCE_POWER_SIZE 32768
-#define IWL_HARDCODED_SGOM_SIZE 339
-#define IWL_HARDCODED_STEP_SIZE 6
+#define IWL_SGOM_MAP_SIZE 339
struct pnvm_sku_package {
u8 rev;
@@ -31,7 +22,7 @@ struct pnvm_sku_package {
struct uefi_cnv_wlan_sgom_data {
u8 revision;
- u8 offset_map[IWL_HARDCODED_SGOM_SIZE - 1];
+ u8 offset_map[IWL_SGOM_MAP_SIZE - 1];
} __packed;
struct uefi_cnv_common_step_data {
--
2.38.1
From: Alon Giladi <[email protected]>
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 <[email protected]>
Signed-off-by: Gregory Greenman <[email protected]>
---
drivers/net/wireless/intel/iwlwifi/fw/pnvm.c | 4 +-
.../intel/iwlwifi/iwl-context-info-gen3.h | 17 +-
.../net/wireless/intel/iwlwifi/iwl-trans.h | 30 +++-
.../intel/iwlwifi/pcie/ctxt-info-gen3.c | 150 +++++++++++++-----
.../wireless/intel/iwlwifi/pcie/internal.h | 17 +-
.../net/wireless/intel/iwlwifi/pcie/trans.c | 31 ++--
6 files changed, 169 insertions(+), 80 deletions(-)
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 @@ int iwl_pnvm_load(struct iwl_trans *trans,
*/
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 @@ int iwl_pnvm_load(struct iwl_trans *trans,
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),
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-context-info-gen3.h b/drivers/net/wireless/intel/iwlwifi/iwl-context-info-gen3.h
index 7e7d135e85b1..96bf353469b8 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-context-info-gen3.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-context-info-gen3.h
@@ -98,9 +98,9 @@ struct iwl_prph_scratch_control {
} __packed; /* PERIPH_SCRATCH_CONTROL_S */
/*
- * struct iwl_prph_scratch_pnvm_cfg - ror config
+ * struct iwl_prph_scratch_pnvm_cfg - PNVM scratch
* @pnvm_base_addr: PNVM start address
- * @pnvm_size: PNVM size in DWs
+ * @pnvm_size: the size of the PNVM image in bytes
* @reserved: reserved
*/
struct iwl_prph_scratch_pnvm_cfg {
@@ -142,7 +142,7 @@ struct iwl_prph_scratch_rbd_cfg {
/*
* struct iwl_prph_scratch_uefi_cfg - prph scratch reduce power table
* @base_addr: reduce power table address
- * @size: table size in dwords
+ * @size: the size of the entire power table image
*/
struct iwl_prph_scratch_uefi_cfg {
__le64 base_addr;
@@ -292,10 +292,13 @@ int iwl_trans_pcie_ctx_info_gen3_load_pnvm(struct iwl_trans *trans,
const struct iwl_ucode_capabilities *capa);
void iwl_trans_pcie_ctx_info_gen3_set_pnvm(struct iwl_trans *trans,
const struct iwl_ucode_capabilities *capa);
-int iwl_trans_pcie_ctx_info_gen3_load_reduce_power
- (struct iwl_trans *trans,
- const struct iwl_pnvm_image *payloads);
-void iwl_trans_pcie_ctx_info_gen3_set_reduce_power(struct iwl_trans *trans);
+int
+iwl_trans_pcie_ctx_info_gen3_load_reduce_power(struct iwl_trans *trans,
+ const struct iwl_pnvm_image *payloads,
+ const struct iwl_ucode_capabilities *capa);
+void
+iwl_trans_pcie_ctx_info_gen3_set_reduce_power(struct iwl_trans *trans,
+ const struct iwl_ucode_capabilities *capa);
int iwl_trans_pcie_ctx_info_gen3_set_step(struct iwl_trans *trans,
u32 mbx_addr_0_step, u32 mbx_addr_1_step);
#endif /* __iwl_context_info_file_gen3_h__ */
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h
index 8e9585d3a0ee..61ee6c1f4a1e 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h
@@ -641,8 +641,10 @@ struct iwl_trans_ops {
void (*set_pnvm)(struct iwl_trans *trans,
const struct iwl_ucode_capabilities *capa);
int (*load_reduce_power)(struct iwl_trans *trans,
- const struct iwl_pnvm_image *payloads);
- void (*set_reduce_power)(struct iwl_trans *trans);
+ const struct iwl_pnvm_image *payloads,
+ const struct iwl_ucode_capabilities *capa);
+ void (*set_reduce_power)(struct iwl_trans *trans,
+ const struct iwl_ucode_capabilities *capa);
void (*interrupts)(struct iwl_trans *trans, bool enable);
int (*imr_dma_data)(struct iwl_trans *trans,
@@ -731,6 +733,19 @@ struct iwl_dram_data {
int size;
};
+/**
+ * @drams: array of several DRAM areas that contains the pnvm and power
+ * reduction table payloads.
+ * @n_regions: number of DRAM regions that were allocated
+ * @prph_scratch_mem_desc: points to a structure allocated in dram,
+ * designed to show FW where all the payloads are.
+ */
+struct iwl_dram_regions {
+ struct iwl_dram_data drams[IPC_DRAM_MAP_ENTRY_NUM_MAX];
+ struct iwl_dram_data prph_scratch_mem_desc;
+ u8 n_regions;
+};
+
/**
* struct iwl_fw_mon - fw monitor per allocation id
* @num_frags: number of fragments
@@ -1560,15 +1575,18 @@ static inline void iwl_trans_set_pnvm(struct iwl_trans *trans,
static inline int iwl_trans_load_reduce_power
(struct iwl_trans *trans,
- const struct iwl_pnvm_image *payloads)
+ const struct iwl_pnvm_image *payloads,
+ const struct iwl_ucode_capabilities *capa)
{
- return trans->ops->load_reduce_power(trans, payloads);
+ return trans->ops->load_reduce_power(trans, payloads, capa);
}
-static inline void iwl_trans_set_reduce_power(struct iwl_trans *trans)
+static inline void
+iwl_trans_set_reduce_power(struct iwl_trans *trans,
+ const struct iwl_ucode_capabilities *capa)
{
if (trans->ops->set_reduce_power)
- trans->ops->set_reduce_power(trans);
+ trans->ops->set_reduce_power(trans, capa);
}
static inline bool iwl_trans_dbg_ini_valid(struct iwl_trans *trans)
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c
index 26d5ba777d24..fa4a14546860 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
- * Copyright (C) 2018-2022 Intel Corporation
+ * Copyright (C) 2018-2023 Intel Corporation
*/
#include "iwl-trans.h"
#include "iwl-fh.h"
@@ -317,11 +317,11 @@ static int iwl_pcie_load_payloads_continuously(struct iwl_trans *trans,
static int iwl_pcie_load_payloads_segments
(struct iwl_trans *trans,
+ struct iwl_dram_regions *dram_regions,
const struct iwl_pnvm_image *pnvm_data)
{
- struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
- struct iwl_dram_data *cur_pnvm_dram = &trans_pcie->pnvm_dram[0],
- *desc_dram = &trans_pcie->pnvm_regions_desc_array;
+ struct iwl_dram_data *cur_payload_dram = &dram_regions->drams[0];
+ struct iwl_dram_data *desc_dram = &dram_regions->prph_scratch_mem_desc;
struct iwl_prph_scrath_mem_desc_addr_array *addresses;
const void *data;
u32 len;
@@ -341,30 +341,31 @@ static int iwl_pcie_load_payloads_segments
memset(desc_dram->block, 0, len);
/* allocate DRAM region for each payload */
- trans_pcie->n_pnvm_regions = 0;
+ dram_regions->n_regions = 0;
for (i = 0; i < pnvm_data->n_chunks; i++) {
len = pnvm_data->chunks[i].len;
data = pnvm_data->chunks[i].data;
- if (iwl_pcie_ctxt_info_alloc_dma(trans, data, len,
- cur_pnvm_dram)) {
- iwl_trans_pcie_free_pnvm_dram(trans_pcie, trans->dev);
+ if (iwl_pcie_ctxt_info_alloc_dma(trans,
+ data,
+ len,
+ cur_payload_dram)) {
+ iwl_trans_pcie_free_pnvm_dram_regions(dram_regions,
+ trans->dev);
return -ENOMEM;
}
- trans_pcie->n_pnvm_regions++;
- cur_pnvm_dram++;
+ dram_regions->n_regions++;
+ cur_payload_dram++;
}
/* fill desc with the DRAM payloads addresses */
addresses = desc_dram->block;
-
for (i = 0; i < pnvm_data->n_chunks; i++) {
addresses->mem_descs[i] =
- cpu_to_le64(trans_pcie->pnvm_dram[i].physical);
+ cpu_to_le64(dram_regions->drams[i].physical);
}
- trans->pnvm_loaded = true;
return 0;
}
@@ -376,7 +377,7 @@ int iwl_trans_pcie_ctx_info_gen3_load_pnvm(struct iwl_trans *trans,
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
struct iwl_prph_scratch_ctrl_cfg *prph_sc_ctrl =
&trans_pcie->prph_scratch->ctrl_cfg;
- struct iwl_dram_data *dram = &trans_pcie->pnvm_dram[0];
+ struct iwl_dram_regions *dram_regions = &trans_pcie->pnvm_data;
int ret = 0;
/* only allocate the DRAM if not allocated yet */
@@ -394,28 +395,51 @@ int iwl_trans_pcie_ctx_info_gen3_load_pnvm(struct iwl_trans *trans,
return -EINVAL;
}
- /* allocate several DRAM sections */
- if (fw_has_capa(capa, IWL_UCODE_TLV_CAPA_FRAGMENTED_PNVM_IMG))
- return iwl_pcie_load_payloads_segments(trans, pnvm_payloads);
-
- /* allocate one DRAM section */
- ret = iwl_pcie_load_payloads_continuously(trans, pnvm_payloads, dram);
- if (!ret) {
- trans_pcie->n_pnvm_regions = 1;
- trans->pnvm_loaded = true;
+ /* save payloads in several DRAM sections */
+ if (fw_has_capa(capa, IWL_UCODE_TLV_CAPA_FRAGMENTED_PNVM_IMG)) {
+ ret = iwl_pcie_load_payloads_segments(trans,
+ dram_regions,
+ pnvm_payloads);
+ if (!ret)
+ trans->pnvm_loaded = true;
+ } else {
+ /* save only in one DRAM section */
+ ret = iwl_pcie_load_payloads_continuously
+ (trans,
+ pnvm_payloads,
+ &dram_regions->drams[0]);
+ if (!ret) {
+ dram_regions->n_regions = 1;
+ trans->pnvm_loaded = true;
+ }
}
return ret;
}
+static inline size_t
+iwl_dram_regions_size(const struct iwl_dram_regions *dram_regions)
+{
+ size_t total_size = 0;
+ int i;
+
+ for (i = 0; i < dram_regions->n_regions; i++)
+ total_size += dram_regions->drams[i].size;
+
+ return total_size;
+}
+
static void iwl_pcie_set_pnvm_segments(struct iwl_trans *trans)
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
struct iwl_prph_scratch_ctrl_cfg *prph_sc_ctrl =
&trans_pcie->prph_scratch->ctrl_cfg;
+ struct iwl_dram_regions *dram_regions = &trans_pcie->pnvm_data;
prph_sc_ctrl->pnvm_cfg.pnvm_base_addr =
- cpu_to_le64(trans_pcie->pnvm_regions_desc_array.physical);
+ cpu_to_le64(dram_regions->prph_scratch_mem_desc.physical);
+ prph_sc_ctrl->pnvm_cfg.pnvm_size =
+ cpu_to_le32(iwl_dram_regions_size(dram_regions));
}
static void iwl_pcie_set_continuous_pnvm(struct iwl_trans *trans)
@@ -425,9 +449,9 @@ static void iwl_pcie_set_continuous_pnvm(struct iwl_trans *trans)
&trans_pcie->prph_scratch->ctrl_cfg;
prph_sc_ctrl->pnvm_cfg.pnvm_base_addr =
- cpu_to_le64(trans_pcie->pnvm_dram[0].physical);
+ cpu_to_le64(trans_pcie->pnvm_data.drams[0].physical);
prph_sc_ctrl->pnvm_cfg.pnvm_size =
- cpu_to_le32(trans_pcie->pnvm_dram[0].size);
+ cpu_to_le32(trans_pcie->pnvm_data.drams[0].size);
}
void iwl_trans_pcie_ctx_info_gen3_set_pnvm(struct iwl_trans *trans,
@@ -443,12 +467,18 @@ void iwl_trans_pcie_ctx_info_gen3_set_pnvm(struct iwl_trans *trans,
}
int iwl_trans_pcie_ctx_info_gen3_load_reduce_power(struct iwl_trans *trans,
- const struct iwl_pnvm_image *payloads)
+ const struct iwl_pnvm_image *payloads,
+ const struct iwl_ucode_capabilities *capa)
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
struct iwl_prph_scratch_ctrl_cfg *prph_sc_ctrl =
&trans_pcie->prph_scratch->ctrl_cfg;
- struct iwl_dram_data *dram = &trans_pcie->reduce_power_dram;
+ struct iwl_dram_regions *dram_regions = &trans_pcie->reduced_tables_data;
+ int ret = 0;
+
+ /* only allocate the DRAM if not allocated yet */
+ if (trans->reduce_power_loaded)
+ return 0;
if (trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_AX210)
return 0;
@@ -456,26 +486,68 @@ int iwl_trans_pcie_ctx_info_gen3_load_reduce_power(struct iwl_trans *trans,
if (WARN_ON(prph_sc_ctrl->reduce_power_cfg.size))
return -EBUSY;
- /* only allocate the DRAM if not allocated yet */
- if (!trans->reduce_power_loaded)
- return iwl_pcie_load_payloads_continuously(trans,
- payloads,
- dram);
- return 0;
+ if (!payloads->n_chunks) {
+ IWL_DEBUG_FW(trans, "no payloads\n");
+ return -EINVAL;
+ }
+
+ /* save payloads in several DRAM sections */
+ if (fw_has_capa(capa, IWL_UCODE_TLV_CAPA_FRAGMENTED_PNVM_IMG)) {
+ ret = iwl_pcie_load_payloads_segments(trans,
+ dram_regions,
+ payloads);
+ if (!ret)
+ trans->reduce_power_loaded = true;
+ } else {
+ /* save only in one DRAM section */
+ ret = iwl_pcie_load_payloads_continuously
+ (trans,
+ payloads,
+ &dram_regions->drams[0]);
+ if (!ret) {
+ dram_regions->n_regions = 1;
+ trans->reduce_power_loaded = true;
+ }
+ }
+
+ return ret;
}
-void iwl_trans_pcie_ctx_info_gen3_set_reduce_power(struct iwl_trans *trans)
+static void iwl_pcie_set_reduce_power_segments(struct iwl_trans *trans)
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
struct iwl_prph_scratch_ctrl_cfg *prph_sc_ctrl =
&trans_pcie->prph_scratch->ctrl_cfg;
+ struct iwl_dram_regions *dram_regions = &trans_pcie->reduced_tables_data;
- if (trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_AX210)
- return;
+ prph_sc_ctrl->reduce_power_cfg.base_addr =
+ cpu_to_le64(dram_regions->prph_scratch_mem_desc.physical);
+ prph_sc_ctrl->reduce_power_cfg.size =
+ cpu_to_le32(iwl_dram_regions_size(dram_regions));
+}
+
+static void iwl_pcie_set_continuous_reduce_power(struct iwl_trans *trans)
+{
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+ struct iwl_prph_scratch_ctrl_cfg *prph_sc_ctrl =
+ &trans_pcie->prph_scratch->ctrl_cfg;
prph_sc_ctrl->reduce_power_cfg.base_addr =
- cpu_to_le64(trans_pcie->reduce_power_dram.physical);
+ cpu_to_le64(trans_pcie->reduced_tables_data.drams[0].physical);
prph_sc_ctrl->reduce_power_cfg.size =
- cpu_to_le32(trans_pcie->reduce_power_dram.size);
+ cpu_to_le32(trans_pcie->reduced_tables_data.drams[0].size);
+}
+
+void
+iwl_trans_pcie_ctx_info_gen3_set_reduce_power(struct iwl_trans *trans,
+ const struct iwl_ucode_capabilities *capa)
+{
+ if (trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_AX210)
+ return;
+
+ if (fw_has_capa(capa, IWL_UCODE_TLV_CAPA_FRAGMENTED_PNVM_IMG))
+ iwl_pcie_set_reduce_power_segments(trans);
+ else
+ iwl_pcie_set_continuous_reduce_power(trans);
}
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h
index d10f25da0eec..0adcf0e13e85 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h
@@ -307,10 +307,9 @@ enum iwl_pcie_imr_status {
* @trans: pointer to the generic transport area
* @scd_base_addr: scheduler sram base address in SRAM
* @kw: keep warm address
- * @pnvm_dram: array of several DRAM areas that contains the PNVM data
- * @n_pnvm_regions: number of DRAM regions that were allocated for the pnvm
- * @pnvm_regions_desc_array: array of PNVM payloads addresses.
- * allocated in DRAM and sent to FW.
+ * @pnvm_data: holds info about pnvm payloads allocated in DRAM
+ * @reduced_tables_data: holds info about power reduced tablse
+ * payloads allocated in DRAM
* @pci_dev: basic pci-network driver stuff
* @hw_base: pci hardware address support
* @ucode_write_complete: indicates that the ucode has been copied.
@@ -385,10 +384,8 @@ struct iwl_trans_pcie {
struct iwl_dma_ptr kw;
/* pnvm data */
- struct iwl_dram_data pnvm_dram[IPC_DRAM_MAP_ENTRY_NUM_MAX];
- u8 n_pnvm_regions;
- struct iwl_dram_data pnvm_regions_desc_array;
- struct iwl_dram_data reduce_power_dram;
+ struct iwl_dram_regions pnvm_data;
+ struct iwl_dram_regions reduced_tables_data;
struct iwl_txq *txq_memory;
@@ -485,8 +482,8 @@ struct iwl_trans
const struct pci_device_id *ent,
const struct iwl_cfg_trans_params *cfg_trans);
void iwl_trans_pcie_free(struct iwl_trans *trans);
-void iwl_trans_pcie_free_pnvm_dram(struct iwl_trans_pcie *trans_pcie,
- struct device *dev);
+void iwl_trans_pcie_free_pnvm_dram_regions(struct iwl_dram_regions *dram_regions,
+ struct device *dev);
bool __iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans);
#define _iwl_trans_pcie_grab_nic_access(trans) \
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
index 55541c1be5d6..70e8c20fb9b9 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
@@ -1993,25 +1993,27 @@ static void iwl_trans_pcie_configure(struct iwl_trans *trans,
trans_pcie->fw_reset_handshake = trans_cfg->fw_reset_handshake;
}
-void iwl_trans_pcie_free_pnvm_dram(struct iwl_trans_pcie *trans_pcie,
- struct device *dev)
+void iwl_trans_pcie_free_pnvm_dram_regions(struct iwl_dram_regions *dram_regions,
+ struct device *dev)
{
u8 i;
- struct iwl_dram_data *desc_dram = &trans_pcie->pnvm_regions_desc_array;
+ struct iwl_dram_data *desc_dram = &dram_regions->prph_scratch_mem_desc;
- for (i = 0; i < trans_pcie->n_pnvm_regions; i++) {
- dma_free_coherent(dev, trans_pcie->pnvm_dram[i].size,
- trans_pcie->pnvm_dram[i].block,
- trans_pcie->pnvm_dram[i].physical);
+ /* free DRAM payloads */
+ for (i = 0; i < dram_regions->n_regions; i++) {
+ dma_free_coherent(dev, dram_regions->drams[i].size,
+ dram_regions->drams[i].block,
+ dram_regions->drams[i].physical);
}
- trans_pcie->n_pnvm_regions = 0;
+ dram_regions->n_regions = 0;
+ /* free DRAM addresses array */
if (desc_dram->block) {
dma_free_coherent(dev, desc_dram->size,
desc_dram->block,
desc_dram->physical);
}
- desc_dram->block = NULL;
+ memset(desc_dram, 0, sizeof(*desc_dram));
}
void iwl_trans_pcie_free(struct iwl_trans *trans)
@@ -2046,13 +2048,10 @@ void iwl_trans_pcie_free(struct iwl_trans *trans)
iwl_pcie_free_fw_monitor(trans);
- iwl_trans_pcie_free_pnvm_dram(trans_pcie, trans->dev);
-
- if (trans_pcie->reduce_power_dram.size)
- dma_free_coherent(trans->dev,
- trans_pcie->reduce_power_dram.size,
- trans_pcie->reduce_power_dram.block,
- trans_pcie->reduce_power_dram.physical);
+ iwl_trans_pcie_free_pnvm_dram_regions(&trans_pcie->pnvm_data,
+ trans->dev);
+ iwl_trans_pcie_free_pnvm_dram_regions(&trans_pcie->reduced_tables_data,
+ trans->dev);
mutex_destroy(&trans_pcie->mutex);
iwl_trans_free(trans);
--
2.38.1
From: Alon Giladi <[email protected]>
Save the pnvm payloads in several DRAM segments (not only in one as
used to). In addition, allocate a FW structure in DRAM that holds the
segments' addresses and forward its address to the FW. It's done when
FW has the capability to handle pnvm images this way (helps to process
large pnvm images).
Signed-off-by: Alon Giladi <[email protected]>
Signed-off-by: Gregory Greenman <[email protected]>
---
.../intel/iwlwifi/iwl-context-info-gen3.h | 8 ++
.../intel/iwlwifi/pcie/ctxt-info-gen3.c | 73 +++++++++++++++++--
.../wireless/intel/iwlwifi/pcie/internal.h | 3 +
.../net/wireless/intel/iwlwifi/pcie/trans.c | 8 ++
4 files changed, 86 insertions(+), 6 deletions(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-context-info-gen3.h b/drivers/net/wireless/intel/iwlwifi/iwl-context-info-gen3.h
index 23208be831f3..bbf4b18cd9de 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-context-info-gen3.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-context-info-gen3.h
@@ -109,6 +109,14 @@ struct iwl_prph_scratch_pnvm_cfg {
__le32 reserved;
} __packed; /* PERIPH_SCRATCH_PNVM_CFG_S */
+/**
+ * struct iwl_prph_scrath_mem_desc_addr_array
+ * @mem_descs: array of dram addresses.
+ * Each address is the beggining of a pnvm payload.
+ */
+struct iwl_prph_scrath_mem_desc_addr_array {
+ __le64 mem_descs[IPC_DRAM_MAP_ENTRY_NUM_MAX];
+} __packed; /* PERIPH_SCRATCH_MEM_DESC_ADDR_ARRAY_S_VER_1 */
/*
* struct iwl_prph_scratch_hwm_cfg - hwm config
* @hwm_base_addr: hwm start address
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c
index fc450c0d1145..e0477ca4ccc3 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c
@@ -315,11 +315,58 @@ static int iwl_pcie_load_payloads_continuously(struct iwl_trans *trans,
return 0;
}
-/* FIXME: An implementation will be added with the next several commits. */
-static int iwl_pcie_load_payloads_segments(struct iwl_trans *trans,
- const struct iwl_pnvm_image *pnvm_payloads)
+static int iwl_pcie_load_payloads_segments
+ (struct iwl_trans *trans,
+ const struct iwl_pnvm_image *pnvm_data)
{
- return -ENOMEM;
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+ struct iwl_dram_data *cur_pnvm_dram = &trans_pcie->pnvm_dram[0],
+ *desc_dram = &trans_pcie->pnvm_regions_desc_array;
+ struct iwl_prph_scrath_mem_desc_addr_array *addresses;
+ const void *data;
+ u32 len;
+ int i;
+
+ /* allocate and init DRAM descriptors array */
+ len = sizeof(struct iwl_prph_scrath_mem_desc_addr_array);
+ desc_dram->block = iwl_pcie_ctxt_info_dma_alloc_coherent
+ (trans,
+ len,
+ &desc_dram->physical);
+ if (!desc_dram->block) {
+ IWL_DEBUG_FW(trans, "Failed to allocate PNVM DMA.\n");
+ return -ENOMEM;
+ }
+ desc_dram->size = len;
+ memset(desc_dram->block, 0, len);
+
+ /* allocate DRAM region for each payload */
+ trans_pcie->n_pnvm_regions = 0;
+ for (i = 0; i < pnvm_data->n_chunks; i++) {
+ len = pnvm_data->chunks[i].len;
+ data = pnvm_data->chunks[i].data;
+
+ if (iwl_pcie_ctxt_info_alloc_dma(trans, data, len,
+ cur_pnvm_dram)) {
+ iwl_trans_pcie_free_pnvm_dram(trans_pcie, trans->dev);
+ return -ENOMEM;
+ }
+
+ trans_pcie->n_pnvm_regions++;
+ cur_pnvm_dram++;
+ }
+
+ /* fill desc with the DRAM payloads addresses */
+ addresses = desc_dram->block;
+
+ for (i = 0; i < pnvm_data->n_chunks; i++) {
+ addresses->mem_descs[i] =
+ cpu_to_le64(trans_pcie->pnvm_dram[i].physical);
+ }
+
+ trans->pnvm_loaded = true;
+ return 0;
+
}
int iwl_trans_pcie_ctx_info_gen3_load_pnvm(struct iwl_trans *trans,
@@ -342,9 +389,16 @@ int iwl_trans_pcie_ctx_info_gen3_load_pnvm(struct iwl_trans *trans,
if (trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_AX210)
return 0;
+ if (!pnvm_payloads->n_chunks) {
+ IWL_DEBUG_FW(trans, "no payloads\n");
+ return -EINVAL;
+ }
+
+ /* allocate several DRAM sections */
if (fw_has_capa(capa, IWL_UCODE_TLV_CAPA_FRAGMENTED_PNVM_IMG))
return iwl_pcie_load_payloads_segments(trans, pnvm_payloads);
+ /* allocate one DRAM section */
ret = iwl_pcie_load_payloads_continuously(trans, pnvm_payloads, dram);
if (!ret) {
trans_pcie->n_pnvm_regions = 1;
@@ -354,8 +408,15 @@ int iwl_trans_pcie_ctx_info_gen3_load_pnvm(struct iwl_trans *trans,
return ret;
}
-/* FIXME: An implementation will be added with the next several commits. */
-static void iwl_pcie_set_pnvm_segments(struct iwl_trans *trans) {}
+static void iwl_pcie_set_pnvm_segments(struct iwl_trans *trans)
+{
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+ struct iwl_prph_scratch_ctrl_cfg *prph_sc_ctrl =
+ &trans_pcie->prph_scratch->ctrl_cfg;
+
+ prph_sc_ctrl->pnvm_cfg.pnvm_base_addr =
+ cpu_to_le64(trans_pcie->pnvm_regions_desc_array.physical);
+}
static void iwl_pcie_set_continuous_pnvm(struct iwl_trans *trans)
{
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h
index ca2e7bb2def8..d10f25da0eec 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h
@@ -309,6 +309,8 @@ enum iwl_pcie_imr_status {
* @kw: keep warm address
* @pnvm_dram: array of several DRAM areas that contains the PNVM data
* @n_pnvm_regions: number of DRAM regions that were allocated for the pnvm
+ * @pnvm_regions_desc_array: array of PNVM payloads addresses.
+ * allocated in DRAM and sent to FW.
* @pci_dev: basic pci-network driver stuff
* @hw_base: pci hardware address support
* @ucode_write_complete: indicates that the ucode has been copied.
@@ -385,6 +387,7 @@ struct iwl_trans_pcie {
/* pnvm data */
struct iwl_dram_data pnvm_dram[IPC_DRAM_MAP_ENTRY_NUM_MAX];
u8 n_pnvm_regions;
+ struct iwl_dram_data pnvm_regions_desc_array;
struct iwl_dram_data reduce_power_dram;
struct iwl_txq *txq_memory;
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
index cd177addd884..5235a7517c53 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
@@ -1997,6 +1997,7 @@ void iwl_trans_pcie_free_pnvm_dram(struct iwl_trans_pcie *trans_pcie,
struct device *dev)
{
u8 i;
+ struct iwl_dram_data *desc_dram = &trans_pcie->pnvm_regions_desc_array;
for (i = 0; i < trans_pcie->n_pnvm_regions; i++) {
dma_free_coherent(dev, trans_pcie->pnvm_dram[i].size,
@@ -2004,6 +2005,13 @@ void iwl_trans_pcie_free_pnvm_dram(struct iwl_trans_pcie *trans_pcie,
trans_pcie->pnvm_dram[i].physical);
}
trans_pcie->n_pnvm_regions = 0;
+
+ if (desc_dram->block) {
+ dma_free_coherent(dev, desc_dram->size,
+ desc_dram->block,
+ desc_dram->physical);
+ }
+ desc_dram->block = NULL;
}
void iwl_trans_pcie_free(struct iwl_trans *trans)
--
2.38.1