diff options
Diffstat (limited to 'drivers/net/wireless/intel/iwlwifi/fw/pnvm.c')
-rw-r--r-- | drivers/net/wireless/intel/iwlwifi/fw/pnvm.c | 145 |
1 files changed, 55 insertions, 90 deletions
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c index 40f2109a097f..b4b1f75b9c2a 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c @@ -10,7 +10,7 @@ #include "fw/api/commands.h" #include "fw/api/nvm-reg.h" #include "fw/api/alive.h" -#include <linux/efi.h> +#include "fw/uefi.h" struct iwl_pnvm_section { __le32 offset; @@ -37,6 +37,7 @@ static int iwl_pnvm_handle_section(struct iwl_trans *trans, const u8 *data, u32 sha1 = 0; u16 mac_type = 0, rf_id = 0; u8 *pnvm_data = NULL, *tmp; + bool hw_match = false; u32 size = 0; int ret; @@ -83,6 +84,9 @@ static int iwl_pnvm_handle_section(struct iwl_trans *trans, const u8 *data, break; } + if (hw_match) + break; + mac_type = le16_to_cpup((__le16 *)data); rf_id = le16_to_cpup((__le16 *)(data + sizeof(__le16))); @@ -90,15 +94,9 @@ static int iwl_pnvm_handle_section(struct iwl_trans *trans, const u8 *data, "Got IWL_UCODE_TLV_HW_TYPE mac_type 0x%0x rf_id 0x%0x\n", mac_type, rf_id); - if (mac_type != CSR_HW_REV_TYPE(trans->hw_rev) || - rf_id != CSR_HW_RFID_TYPE(trans->hw_rf_id)) { - IWL_DEBUG_FW(trans, - "HW mismatch, skipping PNVM section, mac_type 0x%0x, rf_id 0x%0x.\n", - CSR_HW_REV_TYPE(trans->hw_rev), trans->hw_rf_id); - ret = -ENOENT; - goto out; - } - + if (mac_type == CSR_HW_REV_TYPE(trans->hw_rev) && + rf_id == CSR_HW_RFID_TYPE(trans->hw_rf_id)) + hw_match = true; break; case IWL_UCODE_TLV_SEC_RT: { struct iwl_pnvm_section *section = (void *)data; @@ -149,6 +147,15 @@ static int iwl_pnvm_handle_section(struct iwl_trans *trans, const u8 *data, } done: + if (!hw_match) { + IWL_DEBUG_FW(trans, + "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; + } + if (!size) { IWL_DEBUG_FW(trans, "Empty PNVM, skipping.\n"); ret = -ENOENT; @@ -220,83 +227,6 @@ static int iwl_pnvm_parse(struct iwl_trans *trans, const u8 *data, return -ENOENT; } -#if defined(CONFIG_EFI) - -#define IWL_EFI_VAR_GUID EFI_GUID(0x92daaf2f, 0xc02b, 0x455b, \ - 0xb2, 0xec, 0xf5, 0xa3, \ - 0x59, 0x4f, 0x4a, 0xea) - -#define IWL_UEFI_OEM_PNVM_NAME L"UefiCnvWlanOemSignedPnvm" - -#define IWL_HARDCODED_PNVM_SIZE 4096 - -struct pnvm_sku_package { - u8 rev; - u8 reserved1[3]; - u32 total_size; - u8 n_skus; - u8 reserved2[11]; - u8 data[]; -}; - -static int iwl_pnvm_get_from_efi(struct iwl_trans *trans, - u8 **data, size_t *len) -{ - struct efivar_entry *pnvm_efivar; - struct pnvm_sku_package *package; - unsigned long package_size; - int err; - - pnvm_efivar = kzalloc(sizeof(*pnvm_efivar), GFP_KERNEL); - if (!pnvm_efivar) - return -ENOMEM; - - memcpy(&pnvm_efivar->var.VariableName, IWL_UEFI_OEM_PNVM_NAME, - sizeof(IWL_UEFI_OEM_PNVM_NAME)); - pnvm_efivar->var.VendorGuid = IWL_EFI_VAR_GUID; - - /* - * 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; - - package = kmalloc(package_size, GFP_KERNEL); - if (!package) { - err = -ENOMEM; - goto out; - } - - err = efivar_entry_get(pnvm_efivar, NULL, &package_size, package); - if (err) { - IWL_DEBUG_FW(trans, - "PNVM UEFI variable not found %d (len %lu)\n", - err, package_size); - goto out; - } - - IWL_DEBUG_FW(trans, "Read PNVM fro UEFI with size %lu\n", package_size); - - *data = kmemdup(package->data, *len, GFP_KERNEL); - if (!*data) - err = -ENOMEM; - *len = package_size - sizeof(*package); - -out: - kfree(package); - kfree(pnvm_efivar); - - return err; -} -#else /* CONFIG_EFI */ -static inline int iwl_pnvm_get_from_efi(struct iwl_trans *trans, - u8 **data, size_t *len) -{ - return -EOPNOTSUPP; -} -#endif /* CONFIG_EFI */ - static int iwl_pnvm_get_from_fs(struct iwl_trans *trans, u8 **data, size_t *len) { const struct firmware *pnvm; @@ -335,6 +265,7 @@ int iwl_pnvm_load(struct iwl_trans *trans, { u8 *data; size_t len; + struct pnvm_sku_package *package; struct iwl_notification_wait pnvm_wait; static const u16 ntf_cmds[] = { WIDE_ID(REGULATORY_AND_NVM_GROUP, PNVM_INIT_COMPLETE_NTFY) }; @@ -356,9 +287,19 @@ int iwl_pnvm_load(struct iwl_trans *trans, } /* First attempt to get the PNVM from BIOS */ - ret = iwl_pnvm_get_from_efi(trans, &data, &len); - if (!ret) - goto parse; + package = iwl_uefi_get_pnvm(trans, &len); + if (!IS_ERR_OR_NULL(package)) { + data = kmemdup(package->data, len, GFP_KERNEL); + + /* free package regardless of whether kmemdup succeeded */ + kfree(package); + + if (data) { + /* we need only the data size */ + len -= sizeof(*package); + goto parse; + } + } /* If it's not available, try from the filesystem */ ret = iwl_pnvm_get_from_fs(trans, &data, &len); @@ -379,6 +320,30 @@ parse: kfree(data); skip_parse: + data = NULL; + /* 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); + if (IS_ERR_OR_NULL(data)) { + /* + * 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; + + goto skip_reduce_power; + } + } + + ret = iwl_trans_set_reduce_power(trans, data, len); + if (ret) + IWL_DEBUG_FW(trans, + "Failed to set reduce power table %d\n", + ret); + kfree(data); + +skip_reduce_power: iwl_init_notification_wait(notif_wait, &pnvm_wait, ntf_cmds, ARRAY_SIZE(ntf_cmds), iwl_pnvm_complete_fn, trans); |