Skip to content

Commit a1a6a4c

Browse files
committed
iwlwifi: pnvm: implement reading PNVM from UEFI
We now support fetching the PNVM data from a UEFI variable. Add the code to read this variable first and use it. If it's not available, we fall back to reading the data from the filesystem, as before. Signed-off-by: Luca Coelho <[email protected]> Link: https://lore.kernel.org/r/iwlwifi.20210211015026.289084803334.Ie234805047df3be84f4235f9dafaf4cdecf0db9a@changeid Signed-off-by: Luca Coelho <[email protected]>
1 parent cdda18f commit a1a6a4c

File tree

1 file changed

+90
-1
lines changed
  • drivers/net/wireless/intel/iwlwifi/fw

1 file changed

+90
-1
lines changed

drivers/net/wireless/intel/iwlwifi/fw/pnvm.c

Lines changed: 90 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "fw/api/commands.h"
1111
#include "fw/api/nvm-reg.h"
1212
#include "fw/api/alive.h"
13+
#include <linux/efi.h>
1314

1415
struct iwl_pnvm_section {
1516
__le32 offset;
@@ -219,6 +220,88 @@ static int iwl_pnvm_parse(struct iwl_trans *trans, const u8 *data,
219220
return -ENOENT;
220221
}
221222

223+
/*
224+
* This is known to be broken on v4.19 and to work on v5.4. Until we
225+
* figure out why this is the case and how to make it work, simply
226+
* disable the feature in old kernels.
227+
*/
228+
#if defined(CONFIG_EFI)
229+
230+
#define IWL_EFI_VAR_GUID EFI_GUID(0x92daaf2f, 0xc02b, 0x455b, \
231+
0xb2, 0xec, 0xf5, 0xa3, \
232+
0x59, 0x4f, 0x4a, 0xea)
233+
234+
#define IWL_UEFI_OEM_PNVM_NAME L"UefiCnvWlanOemSignedPnvm"
235+
236+
#define IWL_HARDCODED_PNVM_SIZE 4096
237+
238+
struct pnvm_sku_package {
239+
u8 rev;
240+
u8 reserved1[3];
241+
u32 total_size;
242+
u8 n_skus;
243+
u8 reserved2[11];
244+
u8 data[];
245+
};
246+
247+
static int iwl_pnvm_get_from_efi(struct iwl_trans *trans,
248+
u8 **data, size_t *len)
249+
{
250+
struct efivar_entry *pnvm_efivar;
251+
struct pnvm_sku_package *package;
252+
unsigned long package_size;
253+
int err;
254+
255+
pnvm_efivar = kzalloc(sizeof(*pnvm_efivar), GFP_KERNEL);
256+
if (!pnvm_efivar)
257+
return -ENOMEM;
258+
259+
memcpy(&pnvm_efivar->var.VariableName, IWL_UEFI_OEM_PNVM_NAME,
260+
sizeof(IWL_UEFI_OEM_PNVM_NAME));
261+
pnvm_efivar->var.VendorGuid = IWL_EFI_VAR_GUID;
262+
263+
/*
264+
* TODO: we hardcode a maximum length here, because reading
265+
* from the UEFI is not working. To implement this properly,
266+
* we have to call efivar_entry_size().
267+
*/
268+
package_size = IWL_HARDCODED_PNVM_SIZE;
269+
270+
package = kmalloc(package_size, GFP_KERNEL);
271+
if (!package) {
272+
err = -ENOMEM;
273+
goto out;
274+
}
275+
276+
err = efivar_entry_get(pnvm_efivar, NULL, &package_size, package);
277+
if (err) {
278+
IWL_DEBUG_FW(trans,
279+
"PNVM UEFI variable not found %d (len %zd)\n",
280+
err, package_size);
281+
goto out;
282+
}
283+
284+
IWL_DEBUG_FW(trans, "Read PNVM fro UEFI with size %zd\n", package_size);
285+
286+
*data = kmemdup(package->data, *len, GFP_KERNEL);
287+
if (!*data)
288+
err = -ENOMEM;
289+
*len = package_size - sizeof(*package);
290+
291+
out:
292+
kfree(package);
293+
kfree(pnvm_efivar);
294+
295+
return err;
296+
}
297+
#else /* CONFIG_EFI */
298+
static inline int iwl_pnvm_get_from_efi(struct iwl_trans *trans,
299+
u8 **data, size_t *len)
300+
{
301+
return -EOPNOTSUPP;
302+
}
303+
#endif /* CONFIG_EFI */
304+
222305
static int iwl_pnvm_get_from_fs(struct iwl_trans *trans, u8 **data, size_t *len)
223306
{
224307
const struct firmware *pnvm;
@@ -277,7 +360,12 @@ int iwl_pnvm_load(struct iwl_trans *trans,
277360
goto skip_parse;
278361
}
279362

280-
/* Try to load the PNVM from the filesystem */
363+
/* First attempt to get the PNVM from BIOS */
364+
ret = iwl_pnvm_get_from_efi(trans, &data, &len);
365+
if (!ret)
366+
goto parse;
367+
368+
/* If it's not available, try from the filesystem */
281369
ret = iwl_pnvm_get_from_fs(trans, &data, &len);
282370
if (ret) {
283371
/*
@@ -290,6 +378,7 @@ int iwl_pnvm_load(struct iwl_trans *trans,
290378
goto skip_parse;
291379
}
292380

381+
parse:
293382
iwl_pnvm_parse(trans, data, len);
294383

295384
kfree(data);

0 commit comments

Comments
 (0)