Created
September 15, 2021 15:00
-
-
Save mcgrof/93d7389f22f07432a2ba8d7c1514c5b8 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/arch/x86/include/asm/microcode.h b/arch/x86/include/asm/microcode.h | |
index ab45a220fac4..d6bfdfb0f0af 100644 | |
--- a/arch/x86/include/asm/microcode.h | |
+++ b/arch/x86/include/asm/microcode.h | |
@@ -130,14 +130,11 @@ static inline unsigned int x86_cpuid_family(void) | |
extern void __init load_ucode_bsp(void); | |
extern void load_ucode_ap(void); | |
void reload_early_microcode(void); | |
-extern bool get_builtin_firmware(struct cpio_data *cd, const char *name); | |
extern bool initrd_gone; | |
#else | |
static inline void __init load_ucode_bsp(void) { } | |
static inline void load_ucode_ap(void) { } | |
static inline void reload_early_microcode(void) { } | |
-static inline bool | |
-get_builtin_firmware(struct cpio_data *cd, const char *name) { return false; } | |
#endif | |
#endif /* _ASM_X86_MICROCODE_H */ | |
diff --git a/arch/x86/kernel/cpu/microcode/amd.c b/arch/x86/kernel/cpu/microcode/amd.c | |
index 3d4a48336084..ae2a179a44da 100644 | |
--- a/arch/x86/kernel/cpu/microcode/amd.c | |
+++ b/arch/x86/kernel/cpu/microcode/amd.c | |
@@ -456,17 +456,25 @@ apply_microcode_early_amd(u32 cpuid_1_eax, void *ucode, size_t size, bool save_p | |
static bool get_builtin_microcode(struct cpio_data *cp, unsigned int family) | |
{ | |
-#ifdef CONFIG_X86_64 | |
char fw_name[36] = "amd-ucode/microcode_amd.bin"; | |
+ const struct firmware fw; | |
+ int ret; | |
+ | |
+ if (IS_ENABLED(CONFIG_X86_32)) | |
+ return false; | |
if (family >= 0x15) | |
snprintf(fw_name, sizeof(fw_name), | |
"amd-ucode/microcode_amd_fam%.2xh.bin", family); | |
- return get_builtin_firmware(cp, fw_name); | |
-#else | |
+ ret = firmware_request_builtin(&fw, fw_name); | |
+ if (ret == 0) { | |
+ cp->size = fw.size; | |
+ cp->data = (void *)fw.data; | |
+ return true; | |
+ } | |
+ | |
return false; | |
-#endif | |
} | |
static void __load_ucode_amd(unsigned int cpuid_1_eax, struct cpio_data *ret) | |
diff --git a/arch/x86/kernel/cpu/microcode/intel.c b/arch/x86/kernel/cpu/microcode/intel.c | |
index 7e8e07bddd5f..6752053d3ae3 100644 | |
--- a/arch/x86/kernel/cpu/microcode/intel.c | |
+++ b/arch/x86/kernel/cpu/microcode/intel.c | |
@@ -457,6 +457,8 @@ static bool load_builtin_intel_microcode(struct cpio_data *cp) | |
{ | |
unsigned int eax = 1, ebx, ecx = 0, edx; | |
char name[30]; | |
+ const struct firmware fw; | |
+ int ret; | |
if (IS_ENABLED(CONFIG_X86_32)) | |
return false; | |
@@ -466,7 +468,13 @@ static bool load_builtin_intel_microcode(struct cpio_data *cp) | |
sprintf(name, "intel-ucode/%02x-%02x-%02x", | |
x86_family(eax), x86_model(eax), x86_stepping(eax)); | |
- return get_builtin_firmware(cp, name); | |
+ ret = firmware_request_builtin(&fw, name); | |
+ if (ret == 0) { | |
+ cp->size = fw.size; | |
+ cp->data = (void *)fw.data; | |
+ } | |
+ | |
+ return false; | |
} | |
/* | |
diff --git a/drivers/base/firmware_loader/firmware.h b/drivers/base/firmware_loader/firmware.h | |
index a3014e9e2c85..7865dea190d5 100644 | |
--- a/drivers/base/firmware_loader/firmware.h | |
+++ b/drivers/base/firmware_loader/firmware.h | |
@@ -34,6 +34,11 @@ | |
* fallback are enabled, then this fallback will be tried first. | |
* @FW_OPT_PARTIAL: Allow partial read of firmware instead of needing to read | |
* entire file. | |
+ * @FW_OPT_NO_ALLOC_BUILTIN: The caller has a requirement so that the memory | |
+ * allocator is not used, as such the firmware pointer passed is allocated | |
+ * as part of the stack on the caller side and the type of firmware it is | |
+ * looking for must only be built-in. Because of this it does not need to | |
+ * use the release_firmware() call. | |
*/ | |
enum fw_opt { | |
FW_OPT_UEVENT = BIT(0), | |
@@ -44,6 +49,7 @@ enum fw_opt { | |
FW_OPT_NOFALLBACK_SYSFS = BIT(5), | |
FW_OPT_FALLBACK_PLATFORM = BIT(6), | |
FW_OPT_PARTIAL = BIT(7), | |
+ FW_OPT_NO_ALLOC_BUILTIN = BIT(8), | |
}; | |
enum fw_status { | |
diff --git a/drivers/base/firmware_loader/main.c b/drivers/base/firmware_loader/main.c | |
index bdbedc6660a8..ce629bd20941 100644 | |
--- a/drivers/base/firmware_loader/main.c | |
+++ b/drivers/base/firmware_loader/main.c | |
@@ -729,11 +729,13 @@ _request_firmware_prepare(struct firmware **firmware_p, const char *name, | |
struct fw_priv *fw_priv; | |
int ret; | |
- *firmware_p = firmware = kzalloc(sizeof(*firmware), GFP_KERNEL); | |
- if (!firmware) { | |
- dev_err(device, "%s: kmalloc(struct firmware) failed\n", | |
- __func__); | |
- return -ENOMEM; | |
+ if (!(opt_flags & FW_OPT_NO_ALLOC_BUILTIN)) { | |
+ *firmware_p = firmware = kzalloc(sizeof(*firmware), GFP_KERNEL); | |
+ if (!firmware) { | |
+ dev_err(device, "%s: kmalloc(struct firmware) failed\n", | |
+ __func__); | |
+ return -ENOMEM; | |
+ } | |
} | |
if (fw_get_builtin_firmware(firmware, name, dbuf, size)) { | |
@@ -741,6 +743,9 @@ _request_firmware_prepare(struct firmware **firmware_p, const char *name, | |
return 0; /* assigned */ | |
} | |
+ if (opt_flags & FW_OPT_NO_ALLOC_BUILTIN) | |
+ return -ENOENT; | |
+ | |
ret = alloc_lookup_fw_priv(name, &fw_cache, &fw_priv, dbuf, size, | |
offset, opt_flags); | |
@@ -805,6 +810,9 @@ _request_firmware(const struct firmware **firmware_p, const char *name, | |
goto out; | |
} | |
+ if (opt_flags & FW_OPT_NO_ALLOC_BUILTIN) | |
+ fw = *firmware_p; | |
+ | |
ret = _request_firmware_prepare(&fw, name, device, buf, size, | |
offset, opt_flags); | |
if (ret <= 0) /* error or already assigned */ | |
@@ -933,6 +941,20 @@ int request_firmware_direct(const struct firmware **firmware_p, | |
} | |
EXPORT_SYMBOL_GPL(request_firmware_direct); | |
+int firmware_request_builtin(const struct firmware *firmware, const char *name) | |
+{ | |
+ int ret; | |
+ | |
+ __module_get(THIS_MODULE); | |
+ ret = _request_firmware(&firmware, name, NULL, NULL, 0, 0, | |
+ FW_OPT_UEVENT | FW_OPT_NO_WARN | | |
+ FW_OPT_NOFALLBACK_SYSFS | | |
+ FW_OPT_NO_ALLOC_BUILTIN); | |
+ module_put(THIS_MODULE); | |
+ return ret; | |
+} | |
+EXPORT_SYMBOL_GPL(firmware_request_builtin); | |
+ | |
/** | |
* firmware_request_platform() - request firmware with platform-fw fallback | |
* @firmware: pointer to firmware image | |
diff --git a/include/linux/firmware.h b/include/linux/firmware.h | |
index 25109192cebe..29716e822500 100644 | |
--- a/include/linux/firmware.h | |
+++ b/include/linux/firmware.h | |
@@ -51,6 +51,7 @@ int request_firmware_nowait( | |
void (*cont)(const struct firmware *fw, void *context)); | |
int request_firmware_direct(const struct firmware **fw, const char *name, | |
struct device *device); | |
+int firmware_request_builtin(const struct firmware *firmware, const char *name); | |
int request_firmware_into_buf(const struct firmware **firmware_p, | |
const char *name, struct device *device, void *buf, size_t size); | |
int request_partial_firmware_into_buf(const struct firmware **firmware_p, | |
@@ -99,6 +100,12 @@ static inline int request_firmware_direct(const struct firmware **fw, | |
return -EINVAL; | |
} | |
+static inline int firmware_request_builtin(const struct firmware *firmware, | |
+ const char *name) | |
+{ | |
+ return -EINVAL; | |
+} | |
+ | |
static inline int request_firmware_into_buf(const struct firmware **firmware_p, | |
const char *name, struct device *device, void *buf, size_t size) | |
{ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment