mirror of
https://github.com/torvalds/linux.git
synced 2026-06-01 02:53:36 +02:00
wifi: iwlwifi: use PNVM data embedded in .ucode files
Given compatibility issues with external PNVM data that doesn't match the firmware it was designed with/for, future firmware releases will include the PNVM data in the firmware files directly, avoiding those mismatch issues. Make the driver load and use that embedded PNVM data in preference of external files, falling back to the external file if it isn't present. Co-developed-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com> Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com> Link: https://patch.msgid.link/20250709081300.c843f77aa2d3.I7200f8dd40ef82aff1f5574fdd3966913cda592c@changeid
This commit is contained in:
parent
14db492738
commit
563abc938f
|
|
@ -104,6 +104,9 @@ enum iwl_ucode_tlv_type {
|
|||
IWL_UCODE_TLV_CURRENT_PC = 68,
|
||||
IWL_UCODE_TLV_FSEQ_BIN_VERSION = 72,
|
||||
|
||||
/* contains sub-sections like PNVM file does (did) */
|
||||
IWL_UCODE_TLV_PNVM_DATA = 74,
|
||||
|
||||
IWL_UCODE_TLV_FW_NUM_STATIONS = IWL_UCODE_TLV_CONST_BASE + 0,
|
||||
IWL_UCODE_TLV_FW_NUM_LINKS = IWL_UCODE_TLV_CONST_BASE + 1,
|
||||
IWL_UCODE_TLV_FW_NUM_BEACONS = IWL_UCODE_TLV_CONST_BASE + 2,
|
||||
|
|
|
|||
|
|
@ -195,6 +195,8 @@ struct iwl_dump_exclude {
|
|||
* @phy_integration_ver_len: length of @phy_integration_ver
|
||||
* @dump_excl: image dump exclusion areas for RT image
|
||||
* @dump_excl_wowlan: image dump exclusion areas for WoWLAN image
|
||||
* @pnvm_data: PNVM data embedded in the .ucode file, if any
|
||||
* @pnvm_size: size of the embedded PNVM data
|
||||
*/
|
||||
struct iwl_fw {
|
||||
u32 ucode_ver;
|
||||
|
|
@ -227,6 +229,9 @@ struct iwl_fw {
|
|||
u32 phy_integration_ver_len;
|
||||
|
||||
struct iwl_dump_exclude dump_excl[2], dump_excl_wowlan[2];
|
||||
|
||||
const void *pnvm_data;
|
||||
u32 pnvm_size;
|
||||
};
|
||||
|
||||
static inline const char *get_fw_dbg_mode_string(int mode)
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#include "fw/api/nvm-reg.h"
|
||||
#include "fw/api/alive.h"
|
||||
#include "fw/uefi.h"
|
||||
#include "fw/img.h"
|
||||
|
||||
#define IWL_PNVM_REDUCED_CAP_BIT BIT(25)
|
||||
|
||||
|
|
@ -264,8 +265,8 @@ static int iwl_pnvm_get_from_fs(struct iwl_trans *trans, u8 **data, size_t *len)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static u8 *iwl_get_pnvm_image(struct iwl_trans *trans_p, size_t *len,
|
||||
__le32 sku_id[3])
|
||||
static const u8 *iwl_get_pnvm_image(struct iwl_trans *trans_p, size_t *len,
|
||||
__le32 sku_id[3], const struct iwl_fw *fw)
|
||||
{
|
||||
struct pnvm_sku_package *package;
|
||||
u8 *image = NULL;
|
||||
|
|
@ -290,6 +291,12 @@ static u8 *iwl_get_pnvm_image(struct iwl_trans *trans_p, size_t *len,
|
|||
}
|
||||
}
|
||||
|
||||
if (fw->pnvm_data) {
|
||||
*len = fw->pnvm_size;
|
||||
|
||||
return fw->pnvm_data;
|
||||
}
|
||||
|
||||
/* If it's not available, or for Intel SKU, try from the filesystem */
|
||||
if (iwl_pnvm_get_from_fs(trans_p, &image, len))
|
||||
return NULL;
|
||||
|
|
@ -298,11 +305,11 @@ static u8 *iwl_get_pnvm_image(struct iwl_trans *trans_p, size_t *len,
|
|||
|
||||
static void
|
||||
iwl_pnvm_load_pnvm_to_trans(struct iwl_trans *trans,
|
||||
const struct iwl_ucode_capabilities *capa,
|
||||
const struct iwl_fw *fw,
|
||||
__le32 sku_id[3])
|
||||
{
|
||||
struct iwl_pnvm_image *pnvm_data = NULL;
|
||||
u8 *data = NULL;
|
||||
const u8 *data = NULL;
|
||||
size_t length;
|
||||
int ret;
|
||||
|
||||
|
|
@ -313,7 +320,7 @@ iwl_pnvm_load_pnvm_to_trans(struct iwl_trans *trans,
|
|||
if (trans->pnvm_loaded)
|
||||
goto set;
|
||||
|
||||
data = iwl_get_pnvm_image(trans, &length, sku_id);
|
||||
data = iwl_get_pnvm_image(trans, &length, sku_id, fw);
|
||||
if (!data) {
|
||||
trans->fail_to_parse_pnvm_image = true;
|
||||
return;
|
||||
|
|
@ -329,15 +336,17 @@ iwl_pnvm_load_pnvm_to_trans(struct iwl_trans *trans,
|
|||
goto free;
|
||||
}
|
||||
|
||||
ret = iwl_trans_load_pnvm(trans, pnvm_data, capa);
|
||||
ret = iwl_trans_load_pnvm(trans, pnvm_data, &fw->ucode_capa);
|
||||
if (ret)
|
||||
goto free;
|
||||
IWL_DEBUG_INFO(trans, "loaded PNVM version %08x\n", pnvm_data->version);
|
||||
|
||||
set:
|
||||
iwl_trans_set_pnvm(trans, capa);
|
||||
iwl_trans_set_pnvm(trans, &fw->ucode_capa);
|
||||
free:
|
||||
kvfree(data);
|
||||
/* free only if it was allocated, i.e. not just embedded PNVM data */
|
||||
if (data != fw->pnvm_data)
|
||||
kvfree(data);
|
||||
kfree(pnvm_data);
|
||||
}
|
||||
|
||||
|
|
@ -392,8 +401,7 @@ iwl_pnvm_load_reduce_power_to_trans(struct iwl_trans *trans,
|
|||
|
||||
int iwl_pnvm_load(struct iwl_trans *trans,
|
||||
struct iwl_notif_wait_data *notif_wait,
|
||||
const struct iwl_ucode_capabilities *capa,
|
||||
__le32 sku_id[3])
|
||||
const struct iwl_fw *fw, __le32 sku_id[3])
|
||||
{
|
||||
struct iwl_notification_wait pnvm_wait;
|
||||
static const u16 ntf_cmds[] = { WIDE_ID(REGULATORY_AND_NVM_GROUP,
|
||||
|
|
@ -403,8 +411,8 @@ int iwl_pnvm_load(struct iwl_trans *trans,
|
|||
if (!sku_id[0] && !sku_id[1] && !sku_id[2])
|
||||
return 0;
|
||||
|
||||
iwl_pnvm_load_pnvm_to_trans(trans, capa, sku_id);
|
||||
iwl_pnvm_load_reduce_power_to_trans(trans, capa, sku_id);
|
||||
iwl_pnvm_load_pnvm_to_trans(trans, fw, sku_id);
|
||||
iwl_pnvm_load_reduce_power_to_trans(trans, &fw->ucode_capa, sku_id);
|
||||
|
||||
iwl_init_notification_wait(notif_wait, &pnvm_wait,
|
||||
ntf_cmds, ARRAY_SIZE(ntf_cmds),
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
#include "iwl-drv.h"
|
||||
#include "fw/notif-wait.h"
|
||||
#include "fw/img.h"
|
||||
|
||||
#define MVM_UCODE_PNVM_TIMEOUT (HZ / 4)
|
||||
|
||||
|
|
@ -14,8 +15,7 @@
|
|||
|
||||
int iwl_pnvm_load(struct iwl_trans *trans,
|
||||
struct iwl_notif_wait_data *notif_wait,
|
||||
const struct iwl_ucode_capabilities *capa,
|
||||
__le32 sku_id[3]);
|
||||
const struct iwl_fw *fw, __le32 sku_id[3]);
|
||||
|
||||
static inline
|
||||
void iwl_pnvm_get_fs_name(struct iwl_trans *trans,
|
||||
|
|
|
|||
|
|
@ -136,6 +136,9 @@ static void iwl_dealloc_ucode(struct iwl_drv *drv)
|
|||
kfree(drv->fw.phy_integration_ver);
|
||||
kfree(drv->trans->dbg.pc_data);
|
||||
drv->trans->dbg.pc_data = NULL;
|
||||
kvfree(drv->fw.pnvm_data);
|
||||
drv->fw.pnvm_data = NULL;
|
||||
drv->fw.pnvm_size = 0;
|
||||
|
||||
for (i = 0; i < IWL_UCODE_TYPE_MAX; i++)
|
||||
iwl_free_fw_img(drv, drv->fw.img + i);
|
||||
|
|
@ -1400,6 +1403,15 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
|
|||
drv->trans->dbg.num_pc =
|
||||
tlv_len / sizeof(struct iwl_pc_data);
|
||||
break;
|
||||
case IWL_UCODE_TLV_PNVM_DATA:
|
||||
if (drv->fw.pnvm_data)
|
||||
break;
|
||||
drv->fw.pnvm_data =
|
||||
kvmemdup(tlv_data, tlv_len, GFP_KERNEL);
|
||||
if (!drv->fw.pnvm_data)
|
||||
return -ENOMEM;
|
||||
drv->fw.pnvm_size = tlv_len;
|
||||
break;
|
||||
default:
|
||||
IWL_DEBUG_INFO(drv, "unknown TLV: %d\n", tlv_type);
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -294,7 +294,7 @@ static int iwl_mld_run_fw_init_sequence(struct iwl_mld *mld)
|
|||
return ret;
|
||||
|
||||
ret = iwl_pnvm_load(mld->trans, &mld->notif_wait,
|
||||
&mld->fw->ucode_capa, alive_data.sku_id);
|
||||
mld->fw, alive_data.sku_id);
|
||||
if (ret) {
|
||||
IWL_ERR(mld, "Timeout waiting for PNVM load %d\n", ret);
|
||||
return ret;
|
||||
|
|
|
|||
|
|
@ -432,7 +432,7 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm,
|
|||
iwl_trans_fw_alive(mvm->trans);
|
||||
|
||||
ret = iwl_pnvm_load(mvm->trans, &mvm->notif_wait,
|
||||
&mvm->fw->ucode_capa, alive_data.sku_id);
|
||||
mvm->fw, alive_data.sku_id);
|
||||
if (ret) {
|
||||
IWL_ERR(mvm, "Timeout waiting for PNVM load!\n");
|
||||
iwl_fw_set_current_image(&mvm->fwrt, old_type);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user