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
|
kernel/x86/microcode/GenuineIntel.bin
|
||||||
on AMD :
|
on AMD :
|
||||||
kernel/x86/microcode/AuthenticAMD.bin
|
kernel/x86/microcode/AuthenticAMD.bin
|
||||||
|
on Hygon:
|
||||||
|
kernel/x86/microcode/HygonGenuine.bin
|
||||||
|
|
||||||
During BSP (BootStrapping Processor) boot (pre-SMP), the kernel
|
During BSP (BootStrapping Processor) boot (pre-SMP), the kernel
|
||||||
scans the microcode file in the initrd. If microcode matching the
|
scans the microcode file in the initrd. If microcode matching the
|
||||||
|
@ -68,6 +70,10 @@ here for future reference only).
|
||||||
cd $TMPDIR
|
cd $TMPDIR
|
||||||
mkdir -p $DSTDIR
|
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
|
if [ -d /lib/firmware/amd-ucode ]; then
|
||||||
cat /lib/firmware/amd-ucode/microcode_amd*.bin > $DSTDIR/AuthenticAMD.bin
|
cat /lib/firmware/amd-ucode/microcode_amd*.bin > $DSTDIR/AuthenticAMD.bin
|
||||||
fi
|
fi
|
||||||
|
@ -119,7 +125,8 @@ currently supported.
|
||||||
|
|
||||||
Here's an example::
|
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"
|
CONFIG_EXTRA_FIRMWARE_DIR="/lib/firmware"
|
||||||
|
|
||||||
This basically means, you have the following tree structure locally::
|
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
|
| |-- microcode_amd_fam15h.bin
|
||||||
...
|
...
|
||||||
|
|-- hygon-ucode
|
||||||
|
...
|
||||||
|
| |-- microcode_hygon_fam18h.bin
|
||||||
|
...
|
||||||
|-- intel-ucode
|
|-- intel-ucode
|
||||||
...
|
...
|
||||||
| |-- 06-3a-09
|
| |-- 06-3a-09
|
||||||
|
|
|
@ -1310,15 +1310,15 @@ config X86_REBOOTFIXUPS
|
||||||
config MICROCODE
|
config MICROCODE
|
||||||
bool "CPU microcode loading support"
|
bool "CPU microcode loading support"
|
||||||
default y
|
default y
|
||||||
depends on CPU_SUP_AMD || CPU_SUP_INTEL
|
depends on CPU_SUP_AMD || CPU_SUP_INTEL || CPU_SUP_HYGON
|
||||||
select FW_LOADER
|
select FW_LOADER
|
||||||
---help---
|
---help---
|
||||||
If you say Y here, you will be able to update the microcode on
|
If you say Y here, you will be able to update the microcode on Intel,
|
||||||
Intel and AMD processors. The Intel support is for the IA32 family,
|
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
|
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
|
AMD support is for families 0x10 and later. The Hygon support is for
|
||||||
the actual microcode binary data itself which is not shipped with
|
families 0x18 and later. You will obviously need the actual microcode
|
||||||
the Linux kernel.
|
binary data itself which is not shipped with the Linux kernel.
|
||||||
|
|
||||||
The preferred method to load microcode from a detached initrd is described
|
The preferred method to load microcode from a detached initrd is described
|
||||||
in Documentation/x86/microcode.rst. For that you need to enable
|
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
|
If you select this option, microcode patch loading support for AMD
|
||||||
processors will be enabled.
|
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
|
config MICROCODE_OLD_INTERFACE
|
||||||
bool "Ancient loading interface (DEPRECATED)"
|
bool "Ancient loading interface (DEPRECATED)"
|
||||||
default n
|
default n
|
||||||
|
|
|
@ -79,6 +79,12 @@ static inline struct microcode_ops * __init init_amd_microcode(void)
|
||||||
static inline void __exit exit_amd_microcode(void) {}
|
static inline void __exit exit_amd_microcode(void) {}
|
||||||
#endif
|
#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 MAX_UCODE_COUNT 128
|
||||||
|
|
||||||
#define QCHAR(a, b, c, d) ((a) + ((b) << 8) + ((c) << 16) + ((d) << 24))
|
#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_AMD1 QCHAR('A', 'u', 't', 'h')
|
||||||
#define CPUID_AMD2 QCHAR('e', 'n', 't', 'i')
|
#define CPUID_AMD2 QCHAR('e', 'n', 't', 'i')
|
||||||
#define CPUID_AMD3 QCHAR('c', 'A', 'M', 'D')
|
#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) \
|
#define CPUID_IS(a, b, c, ebx, ecx, edx) \
|
||||||
(!((ebx ^ (a))|(edx ^ (b))|(ecx ^ (c))))
|
(!((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))
|
if (CPUID_IS(CPUID_AMD1, CPUID_AMD2, CPUID_AMD3, ebx, ecx, edx))
|
||||||
return X86_VENDOR_AMD;
|
return X86_VENDOR_AMD;
|
||||||
|
|
||||||
|
if (CPUID_IS(CPUID_HYGON1, CPUID_HYGON2, CPUID_HYGON3, ebx, ecx, edx))
|
||||||
|
return X86_VENDOR_HYGON;
|
||||||
|
|
||||||
return X86_VENDOR_UNKNOWN;
|
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)
|
static bool get_builtin_microcode(struct cpio_data *cp, unsigned int family)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_X86_64
|
#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),
|
snprintf(fw_name, sizeof(fw_name),
|
||||||
"amd-ucode/microcode_amd_fam%.2xh.bin", family);
|
"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);
|
return get_builtin_firmware(cp, fw_name);
|
||||||
#else
|
#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)) {
|
if (IS_ENABLED(CONFIG_X86_32)) {
|
||||||
uci = (struct ucode_cpu_info *)__pa_nodebug(ucode_cpu_info);
|
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;
|
use_pa = true;
|
||||||
} else {
|
} else {
|
||||||
uci = ucode_cpu_info;
|
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;
|
use_pa = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -557,8 +567,14 @@ int __init save_microcode_in_initrd_amd(unsigned int cpuid_1_eax)
|
||||||
struct cont_desc desc = { 0 };
|
struct cont_desc desc = { 0 };
|
||||||
enum ucode_state ret;
|
enum ucode_state ret;
|
||||||
struct cpio_data cp;
|
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))
|
if (!(cp.data && cp.size))
|
||||||
return -EINVAL;
|
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,
|
static enum ucode_state request_microcode_amd(int cpu, struct device *device,
|
||||||
bool refresh_fw)
|
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);
|
struct cpuinfo_x86 *c = &cpu_data(cpu);
|
||||||
enum ucode_state ret = UCODE_NFOUND;
|
enum ucode_state ret = UCODE_NFOUND;
|
||||||
const struct firmware *fw;
|
const struct firmware *fw;
|
||||||
|
@ -910,8 +926,12 @@ static enum ucode_state request_microcode_amd(int cpu, struct device *device,
|
||||||
if (!refresh_fw)
|
if (!refresh_fw)
|
||||||
return UCODE_OK;
|
return UCODE_OK;
|
||||||
|
|
||||||
if (c->x86 >= 0x15)
|
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);
|
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)) {
|
if (request_firmware_direct(&fw, (const char *)fw_name, device)) {
|
||||||
pr_debug("failed to load file %s\n", fw_name);
|
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;
|
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)
|
void __exit exit_amd_microcode(void)
|
||||||
{
|
{
|
||||||
cleanup();
|
cleanup();
|
||||||
|
|
|
@ -42,7 +42,11 @@
|
||||||
|
|
||||||
#define DRIVER_VERSION "2.2"
|
#define DRIVER_VERSION "2.2"
|
||||||
|
|
||||||
|
#ifdef CONFIG_MICROCODE_HYGON
|
||||||
|
static const struct microcode_ops *microcode_ops;
|
||||||
|
#else
|
||||||
static struct microcode_ops *microcode_ops;
|
static struct microcode_ops *microcode_ops;
|
||||||
|
#endif
|
||||||
static bool dis_ucode_ldr = true;
|
static bool dis_ucode_ldr = true;
|
||||||
|
|
||||||
bool initrd_gone;
|
bool initrd_gone;
|
||||||
|
@ -134,7 +138,8 @@ static bool __init check_loader_disabled_bsp(void)
|
||||||
if (native_cpuid_ecx(1) & BIT(31))
|
if (native_cpuid_ecx(1) & BIT(31))
|
||||||
return *res;
|
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())
|
if (amd_check_current_patch_level())
|
||||||
return *res;
|
return *res;
|
||||||
}
|
}
|
||||||
|
@ -186,6 +191,10 @@ void __init load_ucode_bsp(void)
|
||||||
intel = false;
|
intel = false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case X86_VENDOR_HYGON:
|
||||||
|
intel = false;
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -226,6 +235,9 @@ void load_ucode_ap(void)
|
||||||
if (x86_family(cpuid_1_eax) >= 0x10)
|
if (x86_family(cpuid_1_eax) >= 0x10)
|
||||||
load_ucode_amd_ap(cpuid_1_eax);
|
load_ucode_amd_ap(cpuid_1_eax);
|
||||||
break;
|
break;
|
||||||
|
case X86_VENDOR_HYGON:
|
||||||
|
load_ucode_amd_ap(cpuid_1_eax);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -245,6 +257,9 @@ static int __init save_microcode_in_initrd(void)
|
||||||
if (c->x86 >= 0x10)
|
if (c->x86 >= 0x10)
|
||||||
ret = save_microcode_in_initrd_amd(cpuid_eax(1));
|
ret = save_microcode_in_initrd_amd(cpuid_eax(1));
|
||||||
break;
|
break;
|
||||||
|
case X86_VENDOR_HYGON:
|
||||||
|
ret = save_microcode_in_initrd_amd(cpuid_eax(1));
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -338,6 +353,9 @@ void reload_early_microcode(unsigned int cpu)
|
||||||
if (family >= 0x10)
|
if (family >= 0x10)
|
||||||
reload_ucode_amd(cpu);
|
reload_ucode_amd(cpu);
|
||||||
break;
|
break;
|
||||||
|
case X86_VENDOR_HYGON:
|
||||||
|
reload_ucode_amd(cpu);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -839,6 +857,8 @@ int __init microcode_init(void)
|
||||||
microcode_ops = init_intel_microcode();
|
microcode_ops = init_intel_microcode();
|
||||||
else if (c->x86_vendor == X86_VENDOR_AMD)
|
else if (c->x86_vendor == X86_VENDOR_AMD)
|
||||||
microcode_ops = init_amd_microcode();
|
microcode_ops = init_amd_microcode();
|
||||||
|
else if (c->x86_vendor == X86_VENDOR_HYGON)
|
||||||
|
microcode_ops = init_hygon_microcode();
|
||||||
else
|
else
|
||||||
pr_err("no support for this CPU vendor\n");
|
pr_err("no support for this CPU vendor\n");
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue