x86/microcode/hygon: Add microcode loading support for Hygon processors
Add support for loading Hygon microcode, which is compatible with AMD one. Signed-off-by: Pu Wen <puwen@hygon.cn> Signed-off-by: Jinliang Zheng <alexjlzheng@tencent.com> Reviewed-by: Bin Lai <robinlai@tencent.com> Signed-off-by: Jinliang Zheng <alexjlzheng@tencent.com> Reviewed-by: caelli <caelli@tencent.com> Signed-off-by: Jianping Liu <frankjpliu@tencent.com>
This commit is contained in:
parent
602852c638
commit
871c9d1964
|
@ -34,6 +34,8 @@ on Intel:
|
|||
kernel/x86/microcode/GenuineIntel.bin
|
||||
on AMD :
|
||||
kernel/x86/microcode/AuthenticAMD.bin
|
||||
on Hygon:
|
||||
kernel/x86/microcode/HygonGenuine.bin
|
||||
|
||||
During BSP (BootStrapping Processor) boot (pre-SMP), the kernel
|
||||
scans the microcode file in the initrd. If microcode matching the
|
||||
|
@ -68,6 +70,10 @@ here for future reference only).
|
|||
cd $TMPDIR
|
||||
mkdir -p $DSTDIR
|
||||
|
||||
if [ -d /lib/firmware/hygon-ucode ]; then
|
||||
cat /lib/firmware/hygon-ucode/microcode_hygon*.bin > $DSTDIR/HygonGenuine.bin
|
||||
fi
|
||||
|
||||
if [ -d /lib/firmware/amd-ucode ]; then
|
||||
cat /lib/firmware/amd-ucode/microcode_amd*.bin > $DSTDIR/AuthenticAMD.bin
|
||||
fi
|
||||
|
@ -119,7 +125,8 @@ currently supported.
|
|||
|
||||
Here's an example::
|
||||
|
||||
CONFIG_EXTRA_FIRMWARE="intel-ucode/06-3a-09 amd-ucode/microcode_amd_fam15h.bin"
|
||||
CONFIG_EXTRA_FIRMWARE="intel-ucode/06-3a-09 \
|
||||
amd-ucode/microcode_amd_fam15h.bin hygon-ucode/microcode_hygon_fam18h.bin"
|
||||
CONFIG_EXTRA_FIRMWARE_DIR="/lib/firmware"
|
||||
|
||||
This basically means, you have the following tree structure locally::
|
||||
|
@ -129,6 +136,10 @@ This basically means, you have the following tree structure locally::
|
|||
...
|
||||
| |-- microcode_amd_fam15h.bin
|
||||
...
|
||||
|-- hygon-ucode
|
||||
...
|
||||
| |-- microcode_hygon_fam18h.bin
|
||||
...
|
||||
|-- intel-ucode
|
||||
...
|
||||
| |-- 06-3a-09
|
||||
|
|
|
@ -1310,15 +1310,15 @@ config X86_REBOOTFIXUPS
|
|||
config MICROCODE
|
||||
bool "CPU microcode loading support"
|
||||
default y
|
||||
depends on CPU_SUP_AMD || CPU_SUP_INTEL
|
||||
depends on CPU_SUP_AMD || CPU_SUP_INTEL || CPU_SUP_HYGON
|
||||
select FW_LOADER
|
||||
---help---
|
||||
If you say Y here, you will be able to update the microcode on
|
||||
Intel and AMD processors. The Intel support is for the IA32 family,
|
||||
If you say Y here, you will be able to update the microcode on Intel,
|
||||
AMD and Hygon processors. The Intel support is for the IA32 family,
|
||||
e.g. Pentium Pro, Pentium II, Pentium III, Pentium 4, Xeon etc. The
|
||||
AMD support is for families 0x10 and later. You will obviously need
|
||||
the actual microcode binary data itself which is not shipped with
|
||||
the Linux kernel.
|
||||
AMD support is for families 0x10 and later. The Hygon support is for
|
||||
families 0x18 and later. You will obviously need the actual microcode
|
||||
binary data itself which is not shipped with the Linux kernel.
|
||||
|
||||
The preferred method to load microcode from a detached initrd is described
|
||||
in Documentation/x86/microcode.rst. For that you need to enable
|
||||
|
@ -1350,6 +1350,14 @@ config MICROCODE_AMD
|
|||
If you select this option, microcode patch loading support for AMD
|
||||
processors will be enabled.
|
||||
|
||||
config MICROCODE_HYGON
|
||||
bool "Hygon microcode loading support"
|
||||
depends on CPU_SUP_HYGON && MICROCODE
|
||||
select MICROCODE_AMD
|
||||
help
|
||||
If you select this option, microcode patch loading support for Hygon
|
||||
processors will be enabled.
|
||||
|
||||
config MICROCODE_OLD_INTERFACE
|
||||
bool "Ancient loading interface (DEPRECATED)"
|
||||
default n
|
||||
|
|
|
@ -79,6 +79,12 @@ static inline struct microcode_ops * __init init_amd_microcode(void)
|
|||
static inline void __exit exit_amd_microcode(void) {}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MICROCODE_HYGON
|
||||
extern const struct microcode_ops * __init init_hygon_microcode(void);
|
||||
#else
|
||||
#define init_hygon_microcode() NULL
|
||||
#endif
|
||||
|
||||
#define MAX_UCODE_COUNT 128
|
||||
|
||||
#define QCHAR(a, b, c, d) ((a) + ((b) << 8) + ((c) << 16) + ((d) << 24))
|
||||
|
@ -88,6 +94,9 @@ static inline void __exit exit_amd_microcode(void) {}
|
|||
#define CPUID_AMD1 QCHAR('A', 'u', 't', 'h')
|
||||
#define CPUID_AMD2 QCHAR('e', 'n', 't', 'i')
|
||||
#define CPUID_AMD3 QCHAR('c', 'A', 'M', 'D')
|
||||
#define CPUID_HYGON1 QCHAR('H', 'y', 'g', 'o')
|
||||
#define CPUID_HYGON2 QCHAR('n', 'G', 'e', 'n')
|
||||
#define CPUID_HYGON3 QCHAR('u', 'i', 'n', 'e')
|
||||
|
||||
#define CPUID_IS(a, b, c, ebx, ecx, edx) \
|
||||
(!((ebx ^ (a))|(edx ^ (b))|(ecx ^ (c))))
|
||||
|
@ -114,6 +123,9 @@ static inline int x86_cpuid_vendor(void)
|
|||
if (CPUID_IS(CPUID_AMD1, CPUID_AMD2, CPUID_AMD3, ebx, ecx, edx))
|
||||
return X86_VENDOR_AMD;
|
||||
|
||||
if (CPUID_IS(CPUID_HYGON1, CPUID_HYGON2, CPUID_HYGON3, ebx, ecx, edx))
|
||||
return X86_VENDOR_HYGON;
|
||||
|
||||
return X86_VENDOR_UNKNOWN;
|
||||
}
|
||||
|
||||
|
|
|
@ -466,11 +466,14 @@ 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";
|
||||
char fw_name[40] = "amd-ucode/microcode_amd.bin";
|
||||
|
||||
if (family >= 0x15)
|
||||
if (x86_cpuid_vendor() == X86_VENDOR_AMD && family >= 0x15)
|
||||
snprintf(fw_name, sizeof(fw_name),
|
||||
"amd-ucode/microcode_amd_fam%.2xh.bin", family);
|
||||
else if (x86_cpuid_vendor() == X86_VENDOR_HYGON)
|
||||
snprintf(fw_name, sizeof(fw_name),
|
||||
"hygon-ucode/microcode_hygon_fam%.2xh.bin", family);
|
||||
|
||||
return get_builtin_firmware(cp, fw_name);
|
||||
#else
|
||||
|
@ -487,11 +490,18 @@ static void __load_ucode_amd(unsigned int cpuid_1_eax, struct cpio_data *ret)
|
|||
|
||||
if (IS_ENABLED(CONFIG_X86_32)) {
|
||||
uci = (struct ucode_cpu_info *)__pa_nodebug(ucode_cpu_info);
|
||||
path = (const char *)__pa_nodebug(ucode_path);
|
||||
if (x86_cpuid_vendor() == X86_VENDOR_HYGON)
|
||||
path = (const char *)__pa_nodebug(
|
||||
"kernel/x86/microcode/HygonGenuine.bin");
|
||||
else
|
||||
path = (const char *)__pa_nodebug(ucode_path);
|
||||
use_pa = true;
|
||||
} else {
|
||||
uci = ucode_cpu_info;
|
||||
path = ucode_path;
|
||||
if (x86_cpuid_vendor() == X86_VENDOR_HYGON)
|
||||
path = "kernel/x86/microcode/HygonGenuine.bin";
|
||||
else
|
||||
path = ucode_path;
|
||||
use_pa = false;
|
||||
}
|
||||
|
||||
|
@ -557,8 +567,14 @@ int __init save_microcode_in_initrd_amd(unsigned int cpuid_1_eax)
|
|||
struct cont_desc desc = { 0 };
|
||||
enum ucode_state ret;
|
||||
struct cpio_data cp;
|
||||
const char *path;
|
||||
|
||||
cp = find_microcode_in_initrd(ucode_path, false);
|
||||
if (x86_cpuid_vendor() == X86_VENDOR_HYGON)
|
||||
path = "kernel/x86/microcode/HygonGenuine.bin";
|
||||
else
|
||||
path = ucode_path;
|
||||
|
||||
cp = find_microcode_in_initrd(path, false);
|
||||
if (!(cp.data && cp.size))
|
||||
return -EINVAL;
|
||||
|
||||
|
@ -901,7 +917,7 @@ static enum ucode_state load_microcode_amd(u8 family, const u8 *data, size_t siz
|
|||
static enum ucode_state request_microcode_amd(int cpu, struct device *device,
|
||||
bool refresh_fw)
|
||||
{
|
||||
char fw_name[36] = "amd-ucode/microcode_amd.bin";
|
||||
char fw_name[40] = "amd-ucode/microcode_amd.bin";
|
||||
struct cpuinfo_x86 *c = &cpu_data(cpu);
|
||||
enum ucode_state ret = UCODE_NFOUND;
|
||||
const struct firmware *fw;
|
||||
|
@ -910,8 +926,12 @@ static enum ucode_state request_microcode_amd(int cpu, struct device *device,
|
|||
if (!refresh_fw)
|
||||
return UCODE_OK;
|
||||
|
||||
if (c->x86 >= 0x15)
|
||||
snprintf(fw_name, sizeof(fw_name), "amd-ucode/microcode_amd_fam%.2xh.bin", c->x86);
|
||||
if (x86_cpuid_vendor() == X86_VENDOR_AMD && c->x86 >= 0x15)
|
||||
snprintf(fw_name, sizeof(fw_name),
|
||||
"amd-ucode/microcode_amd_fam%.2xh.bin", c->x86);
|
||||
else if (x86_cpuid_vendor() == X86_VENDOR_HYGON)
|
||||
snprintf(fw_name, sizeof(fw_name),
|
||||
"hygon-ucode/microcode_hygon_fam%.2xh.bin", c->x86);
|
||||
|
||||
if (request_firmware_direct(&fw, (const char *)fw_name, device)) {
|
||||
pr_debug("failed to load file %s\n", fw_name);
|
||||
|
@ -968,6 +988,22 @@ struct microcode_ops * __init init_amd_microcode(void)
|
|||
return µcode_amd_ops;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MICROCODE_HYGON
|
||||
const struct microcode_ops * __init init_hygon_microcode(void)
|
||||
{
|
||||
struct cpuinfo_x86 *c = &boot_cpu_data;
|
||||
|
||||
if (c->x86_vendor != X86_VENDOR_HYGON)
|
||||
return NULL;
|
||||
|
||||
if (ucode_new_rev)
|
||||
pr_info_once("microcode updated early to new patch_level=0x%08x\n",
|
||||
ucode_new_rev);
|
||||
|
||||
return µcode_amd_ops;
|
||||
}
|
||||
#endif
|
||||
|
||||
void __exit exit_amd_microcode(void)
|
||||
{
|
||||
cleanup();
|
||||
|
|
|
@ -42,7 +42,11 @@
|
|||
|
||||
#define DRIVER_VERSION "2.2"
|
||||
|
||||
#ifdef CONFIG_MICROCODE_HYGON
|
||||
static const struct microcode_ops *microcode_ops;
|
||||
#else
|
||||
static struct microcode_ops *microcode_ops;
|
||||
#endif
|
||||
static bool dis_ucode_ldr = true;
|
||||
|
||||
bool initrd_gone;
|
||||
|
@ -134,7 +138,8 @@ static bool __init check_loader_disabled_bsp(void)
|
|||
if (native_cpuid_ecx(1) & BIT(31))
|
||||
return *res;
|
||||
|
||||
if (x86_cpuid_vendor() == X86_VENDOR_AMD) {
|
||||
if (x86_cpuid_vendor() == X86_VENDOR_AMD ||
|
||||
x86_cpuid_vendor() == X86_VENDOR_HYGON) {
|
||||
if (amd_check_current_patch_level())
|
||||
return *res;
|
||||
}
|
||||
|
@ -186,6 +191,10 @@ void __init load_ucode_bsp(void)
|
|||
intel = false;
|
||||
break;
|
||||
|
||||
case X86_VENDOR_HYGON:
|
||||
intel = false;
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
@ -226,6 +235,9 @@ void load_ucode_ap(void)
|
|||
if (x86_family(cpuid_1_eax) >= 0x10)
|
||||
load_ucode_amd_ap(cpuid_1_eax);
|
||||
break;
|
||||
case X86_VENDOR_HYGON:
|
||||
load_ucode_amd_ap(cpuid_1_eax);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -245,6 +257,9 @@ static int __init save_microcode_in_initrd(void)
|
|||
if (c->x86 >= 0x10)
|
||||
ret = save_microcode_in_initrd_amd(cpuid_eax(1));
|
||||
break;
|
||||
case X86_VENDOR_HYGON:
|
||||
ret = save_microcode_in_initrd_amd(cpuid_eax(1));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -338,6 +353,9 @@ void reload_early_microcode(unsigned int cpu)
|
|||
if (family >= 0x10)
|
||||
reload_ucode_amd(cpu);
|
||||
break;
|
||||
case X86_VENDOR_HYGON:
|
||||
reload_ucode_amd(cpu);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -839,6 +857,8 @@ int __init microcode_init(void)
|
|||
microcode_ops = init_intel_microcode();
|
||||
else if (c->x86_vendor == X86_VENDOR_AMD)
|
||||
microcode_ops = init_amd_microcode();
|
||||
else if (c->x86_vendor == X86_VENDOR_HYGON)
|
||||
microcode_ops = init_hygon_microcode();
|
||||
else
|
||||
pr_err("no support for this CPU vendor\n");
|
||||
|
||||
|
|
Loading…
Reference in New Issue