x86: AMD microcode patch loading support
cover x86: AMD microcode patch loading support
This patch set introduces microcode patch loading support for AMD processors. It includes refactoring of existing code to allow code sharing. Vendor specific code has been split off, leading to a multi-module solution as compared to the current single-module approach.
Thanks,
Peter Oruba
--
Advanced Micro Devices, Inc.
Operating System Research Center
email: [email protected]
Quoted 1 line
From [email protected] Fri Jul 25 18:20:02 2008
Message-Id: <[email protected]>
User-Agent: quilt/0.46_cvs20080326-19.1
Date: Fri, 25 Jul 2008 18:17:24 +0200
From: Peter Oruba <[email protected]>
To: Ingo Molnar <[email protected]>,
Thomas Gleixner <[email protected]>,
Tigran Aivazian <[email protected]>
Cc: LKML <[email protected]>,
Peter Oruba <[email protected]>
Bcc: [email protected]
Subject: [patch 1/9] [PATCH 1/9] x86: Moved Intel microcode patch loader declarations to seperate header file.
References: <[email protected]>
Content-Disposition: inline; filename=0001-x86-Moved-Intel-microcode-patch-loader-declarations.patch
Intel specific microcode declarations have been moved to a seperate header file. There are no code changes to the code itself and no side effects to other parts.
--- arch/x86/kernel/microcode.c | 1 + include/asm-x86/microcode.h | 34 ++++++++++++++++++++++++++++++++++ include/asm-x86/processor.h | 35 ----------------------------------- 3 files changed, 35 insertions(+), 35 deletions(-) create mode 100644 include/asm-x86/microcode.h
arch/x86/kernel/microcode.c +1 -0
@@ -93,6 +93,7 @@#include <asm/msr.h> #include <asm/uaccess.h> #include <asm/processor.h> +#include <asm/microcode.h> MODULE_DESCRIPTION ("Intel CPU (IA-32) Microcode Update Driver" );MODULE_AUTHOR ("Tigran Aivazian <[email protected]>" );
include/asm-x86/microcode.h new file +34 -0
@@ -0,0 +1,34 @@ +struct microcode_header { +unsigned int hdrver; +unsigned int rev; +unsigned int date; +unsigned int sig; +unsigned int cksum; +unsigned int ldrver; +unsigned int pf; +unsigned int datasize; +unsigned int totalsize; +unsigned int reserved[3 ]; +}; + +struct microcode { +struct microcode_header hdr; +unsigned int bits[0 ]; +}; + +typedef struct microcode microcode_t ; +typedef struct microcode_header microcode_header_t ; + +/* microcode format is extended from prescott processors */ +struct extended_signature { +unsigned int sig; +unsigned int pf; +unsigned int cksum; +}; + +struct extended_sigtable { +unsigned int count; +unsigned int cksum; +unsigned int reserved[3 ]; +struct extended_signature sigs[0 ]; +};
include/asm-x86/processor.h +0 -35
@@ -561,41 +561,6 @@ static inline void clear_in_cr4(unsigned long mask)write_cr4 (cr4); } -struct microcode_header { -unsigned int hdrver; -unsigned int rev; -unsigned int date; -unsigned int sig; -unsigned int cksum; -unsigned int ldrver; -unsigned int pf; -unsigned int datasize; -unsigned int totalsize; -unsigned int reserved[3 ]; -}; - -struct microcode { -struct microcode_header hdr; -unsigned int bits[0 ]; -}; - -typedef struct microcode microcode_t ; -typedef struct microcode_header microcode_header_t ; - -/* microcode format is extended from prescott processors */ -struct extended_signature { -unsigned int sig; -unsigned int pf; -unsigned int cksum; -}; - -struct extended_sigtable { -unsigned int count; -unsigned int cksum; -unsigned int reserved[3 ]; -struct extended_signature sigs[0 ]; -}; -typedef struct {unsigned long seg; }mm_segment_t ;
Signature · 1 line
1.5.4.5
PATCH 1/9 x86: Moved Intel microcode patch loader declarations to seperate header file.
Intel specific microcode declarations have been moved to a seperate header file. There are no code changes to the code itself and no side effects to other parts.
--- arch/x86/kernel/microcode.c | 1 + include/asm-x86/microcode.h | 34 ++++++++++++++++++++++++++++++++++ include/asm-x86/processor.h | 35 ----------------------------------- 3 files changed, 35 insertions(+), 35 deletions(-) create mode 100644 include/asm-x86/microcode.h
arch/x86/kernel/microcode.c +1 -0
@@ -93,6 +93,7 @@#include <asm/msr.h> #include <asm/uaccess.h> #include <asm/processor.h> +#include <asm/microcode.h> MODULE_DESCRIPTION ("Intel CPU (IA-32) Microcode Update Driver" );MODULE_AUTHOR ("Tigran Aivazian <[email protected]>" );
include/asm-x86/microcode.h new file +34 -0
@@ -0,0 +1,34 @@ +struct microcode_header { +unsigned int hdrver; +unsigned int rev; +unsigned int date; +unsigned int sig; +unsigned int cksum; +unsigned int ldrver; +unsigned int pf; +unsigned int datasize; +unsigned int totalsize; +unsigned int reserved[3 ]; +}; + +struct microcode { +struct microcode_header hdr; +unsigned int bits[0 ]; +}; + +typedef struct microcode microcode_t ; +typedef struct microcode_header microcode_header_t ; + +/* microcode format is extended from prescott processors */ +struct extended_signature { +unsigned int sig; +unsigned int pf; +unsigned int cksum; +}; + +struct extended_sigtable { +unsigned int count; +unsigned int cksum; +unsigned int reserved[3 ]; +struct extended_signature sigs[0 ]; +};
include/asm-x86/processor.h +0 -35
@@ -561,41 +561,6 @@ static inline void clear_in_cr4(unsigned long mask)write_cr4 (cr4); } -struct microcode_header { -unsigned int hdrver; -unsigned int rev; -unsigned int date; -unsigned int sig; -unsigned int cksum; -unsigned int ldrver; -unsigned int pf; -unsigned int datasize; -unsigned int totalsize; -unsigned int reserved[3 ]; -}; - -struct microcode { -struct microcode_header hdr; -unsigned int bits[0 ]; -}; - -typedef struct microcode microcode_t ; -typedef struct microcode_header microcode_header_t ; - -/* microcode format is extended from prescott processors */ -struct extended_signature { -unsigned int sig; -unsigned int pf; -unsigned int cksum; -}; - -struct extended_sigtable { -unsigned int count; -unsigned int cksum; -unsigned int reserved[3 ]; -struct extended_signature sigs[0 ]; -}; -typedef struct {unsigned long seg; }mm_segment_t ;
Signature · 1 line
1.5.4.5
PATCH 2/9 x86: Typedef removal.
In reply to Peter OrubaRemoved typedefs. No functional changes to the code.
--- arch/x86/kernel/microcode.c | 24 ++++++++++++------------ include/asm-x86/microcode.h | 3 --- 2 files changed, 12 insertions(+), 15 deletions(-)
arch/x86/kernel/microcode.c +12 -12
@@ -102,17 +102,17 @@ MODULE_LICENSE("GPL");#define MICROCODE_VERSION "1.14a"#define DEFAULT_UCODE_DATASIZE (2000)/* 2000 bytes */ -#define MC_HEADER_SIZE (sizeof (microcode_header_t))/* 48 bytes */ +#define MC_HEADER_SIZE (sizeof (struct microcode_header))/* 48 bytes */ #define DEFAULT_UCODE_TOTALSIZE (DEFAULT_UCODE_DATASIZE + MC_HEADER_SIZE)/* 2048 bytes */ #define EXT_HEADER_SIZE (sizeof (struct extended_sigtable))/* 20 bytes */ #define EXT_SIGNATURE_SIZE (sizeof (struct extended_signature))/* 12 bytes */ #define DWSIZE (sizeof (u32))#define get_totalsize (mc) \ - (((microcode_t *)mc)->hdr.totalsize ? \ - ((microcode_t *)mc)->hdr.totalsize : DEFAULT_UCODE_TOTALSIZE) + (((struct microcode *)mc)->hdr.totalsize ? \ + ((struct microcode *)mc)->hdr.totalsize : DEFAULT_UCODE_TOTALSIZE)#define get_datasize (mc) \ - (((microcode_t *)mc)->hdr.datasize ? \ - ((microcode_t *)mc)->hdr.datasize : DEFAULT_UCODE_DATASIZE) + (((struct microcode *)mc)->hdr.datasize ? \ + ((struct microcode *)mc)->hdr.datasize : DEFAULT_UCODE_DATASIZE)#define sigmatch (s1, s2, p1, p2) \ (((s1) == (s2)) && (((p1) & (p2)) || (((p1) == 0) && ((p2) == 0))))
@@ -130,7 +130,7 @@ static struct ucode_cpu_info {unsigned int sig;unsigned int pf;unsigned int rev; -microcode_t *mc; +struct microcode *mc; } ucode_cpu_info[NR_CPUS ];static void collect_cpu_info (int cpu_num)
@@ -171,7 +171,7 @@ static void collect_cpu_info(int cpu_num) }static inline int microcode_update_match (int cpu_num, -microcode_header_t *mc_header,int sig,int pf) +struct microcode_header *mc_header,int sig,int pf) {struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num;
@@ -183,7 +183,7 @@ static inline int microcode_update_match(int cpu_num,static int microcode_sanity_check (void *mc) { -microcode_header_t *mc_header = mc; +struct microcode_header *mc_header = mc;struct extended_sigtable *ext_header =NULL ;struct extended_signature *ext_sig;unsigned long total_size, data_size, ext_table_size;
@@ -268,7 +268,7 @@ static int microcode_sanity_check(void *mc)static int get_maching_microcode (void *mc,int cpu) {struct ucode_cpu_info *uci = ucode_cpu_info + cpu; -microcode_header_t *mc_header = mc; +struct microcode_header *mc_header = mc;struct extended_sigtable *ext_header;unsigned long total_size =get_totalsize (mc_header);int ext_sigcount, i;
@@ -355,7 +355,7 @@ static unsigned int user_buffer_size; /* it's size */static long get_next_ucode (void **mc,long offset) { -microcode_header_t mc_header; +struct microcode_header mc_header;unsigned long total_size;/* No more data */
@@ -495,13 +495,13 @@ MODULE_ALIAS_MISCDEV(MICROCODE_MINOR);static long get_next_ucode_from_buffer (void **mc,const u8 *buf,unsigned long size,long offset) { -microcode_header_t *mc_header; +struct microcode_header *mc_header;unsigned long total_size;/* No more data */ if (offset >= size)return 0 ; - mc_header = (microcode_header_t *)(buf + offset); + mc_header = (struct microcode_header *)(buf + offset); total_size =get_totalsize (mc_header);if (offset + total_size > size) {
include/asm-x86/microcode.h +0 -3
@@ -16,9 +16,6 @@ struct microcode {unsigned int bits[0 ]; }; -typedef struct microcode microcode_t ; -typedef struct microcode_header microcode_header_t ; -/* microcode format is extended from prescott processors */ struct extended_signature {unsigned int sig;
Signature · 1 line
1.5.4.5
PATCH 3/9 x86: Moved per CPU microcode structure declaration to header file.
In reply to Peter OrubaThis structure will be later used by other modules as well and needs therfore to be moved out to a header file.
--- arch/x86/kernel/microcode.c | 8 +------- include/asm-x86/microcode.h | 8 ++++++++ 2 files changed, 9 insertions(+), 7 deletions(-)
arch/x86/kernel/microcode.c +1 -7
@@ -125,13 +125,7 @@ static DEFINE_SPINLOCK(microcode_update_lock);/* no concurrent ->write()s are allowed on /dev/cpu/microcode */ static DEFINE_MUTEX (microcode_mutex); -static struct ucode_cpu_info { -int valid; -unsigned int sig; -unsigned int pf; -unsigned int rev; -struct microcode *mc; -} ucode_cpu_info[NR_CPUS ]; +static struct ucode_cpu_info ucode_cpu_info[NR_CPUS ];static void collect_cpu_info (int cpu_num) {
include/asm-x86/microcode.h +8 -0
@@ -29,3 +29,11 @@ struct extended_sigtable {unsigned int reserved[3 ];struct extended_signature sigs[0 ]; }; + +struct ucode_cpu_info { +int valid; +unsigned int sig; +unsigned int pf; +unsigned int rev; +struct microcode *mc; +};
Signature · 1 line
1.5.4.5
PATCH 4/9 x86: Code split to two parts.
In reply to Peter OrubaSplit off existing code into two seperate files. One file holds general code, the other file vendor specific parts. No functional changes, only refactoring. Temporarily Introduced a new module name 'ucode' for result, due to already taken name 'microcode'.
--- arch/x86/kernel/Makefile | 3 +- arch/x86/kernel/microcode.c | 421 +----------------------------- arch/x86/kernel/microcode_intel.c | 513 +++++++++++++++++++++++++++++++++++++ 3 files changed, 530 insertions(+), 407 deletions(-) create mode 100644 arch/x86/kernel/microcode_intel.c
arch/x86/kernel/Makefile +2 -1
@@ -51,7 +51,8 @@ obj-$(CONFIG_X86_BIOS_REBOOT) += reboot.o obj-$(CONFIG_MCA) += mca_32.o obj-$(CONFIG_X86_MSR) += msr.o obj-$(CONFIG_X86_CPUID) += cpuid.o -obj-$(CONFIG_MICROCODE) += microcode.o +obj-$(CONFIG_MICROCODE) += ucode.o +ucode-objs := microcode.o microcode_intel.o obj-$(CONFIG_PCI) += early-quirks.o apm-y := apm_32.o obj-$(CONFIG_APM) += apm.o
arch/x86/kernel/microcode.c +15 -406
456 lines not on this page · raw message
arch/x86/kernel/microcode_intel.c new file +513 -0
513 lines not on this page · raw message
Signature · 1 line
1.5.4.5
PATCH 5/9 x86: Structure declaration renaming.
In reply to Peter OrubaRenamed common structures to vendor specific naming scheme so other vendors will be able to use the same naming convention.
Conflicts:
--- arch/x86/kernel/microcode_intel.c | 46 +++++++++++++++++++----------------- include/asm-x86/microcode.h | 10 +++++--- 2 files changed, 30 insertions(+), 26 deletions(-)
arch/x86/kernel/microcode_intel.c +24 -22
@@ -100,17 +100,19 @@ MODULE_AUTHOR("Tigran Aivazian <[email protected]>");MODULE_LICENSE ("GPL" );#define DEFAULT_UCODE_DATASIZE (2000)/* 2000 bytes */ -#define MC_HEADER_SIZE (sizeof(struct microcode_header))/* 48 bytes */ +#define MC_HEADER_SIZE (sizeof(struct microcode_header_intel))/* 48 bytes */ #define DEFAULT_UCODE_TOTALSIZE (DEFAULT_UCODE_DATASIZE + MC_HEADER_SIZE)/* 2048 bytes */ #define EXT_HEADER_SIZE (sizeof(struct extended_sigtable))/* 20 bytes */ #define EXT_SIGNATURE_SIZE (sizeof(struct extended_signature))/* 12 bytes */ #define DWSIZE (sizeof(u32))#define get_totalsize (mc) \ - (((struct microcode *)mc)->hdr.totalsize ? \ - ((struct microcode *)mc)->hdr.totalsize : DEFAULT_UCODE_TOTALSIZE) + (((struct microcode_intel *)mc)->hdr.totalsize ? \ + ((struct microcode_intel *)mc)->hdr.totalsize : \ + DEFAULT_UCODE_TOTALSIZE) +#define get_datasize (mc) \ - (((struct microcode *)mc)->hdr.datasize ? \ - ((struct microcode *)mc)->hdr.datasize : DEFAULT_UCODE_DATASIZE) + (((struct microcode_intel *)mc)->hdr.datasize ? \ + ((struct microcode_intel *)mc)->hdr.datasize : DEFAULT_UCODE_DATASIZE)#define sigmatch (s1, s2, p1, p2) \ (((s1) == (s2)) && (((p1) & (p2)) || (((p1) == 0) && ((p2) == 0))))
@@ -134,7 +136,7 @@ void collect_cpu_info(int cpu_num)/* We should bind the task to the CPU */ BUG_ON (raw_smp_processor_id () != cpu_num); uci->pf = uci->rev =0 ; - uci->mc =NULL ; + uci->mc.mc_intel =NULL ; uci->valid =1 ; if (c->x86_vendor != X86_VENDOR_INTEL || c->x86 < 6 ||
@@ -163,7 +165,7 @@ void collect_cpu_info(int cpu_num) }static inline int microcode_update_match (int cpu_num, -struct microcode_header *mc_header,int sig,int pf) +struct microcode_header_intel *mc_header,int sig,int pf) {struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num;
@@ -175,7 +177,7 @@ static inline int microcode_update_match(int cpu_num,int microcode_sanity_check (void *mc) { -struct microcode_header *mc_header = mc; +struct microcode_header_intel *mc_header = mc;struct extended_sigtable *ext_header =NULL ;struct extended_signature *ext_sig;unsigned long total_size, data_size, ext_table_size;
@@ -260,7 +262,7 @@ int microcode_sanity_check(void *mc)int get_matching_microcode (void *mc,int cpu) {struct ucode_cpu_info *uci = ucode_cpu_info + cpu; -struct microcode_header *mc_header = mc; +struct microcode_header_intel *mc_header = mc;struct extended_sigtable *ext_header;unsigned long total_size =get_totalsize (mc_header);int ext_sigcount, i;
@@ -294,10 +296,10 @@ find: }/* free previous update file */ -vfree (uci->mc); +vfree (uci->mc.mc_intel);memcpy (new_mc, mc, total_size); - uci->mc = new_mc; + uci->mc.mc_intel = new_mc;return 1 ; }
@@ -311,7 +313,7 @@ void apply_microcode(int cpu)/* We should bind the task to the CPU */ BUG_ON (cpu_num != cpu); -if (uci->mc ==NULL ) +if (uci->mc.mc_intel ==NULL )return ;/* serialize access to the physical write to MSR 0x79 */
@@ -319,8 +321,8 @@ void apply_microcode(int cpu)/* write microcode via MSR 0x79 */ wrmsr (MSR_IA32_UCODE_WRITE , - (unsigned long ) uci->mc->bits, - (unsigned long ) uci->mc->bits >>16 >>16 ); + (unsigned long ) uci->mc.mc_intel->bits, + (unsigned long ) uci->mc.mc_intel->bits >>16 >>16 );wrmsr (MSR_IA32_UCODE_REV ,0 ,0 );/* see notes above for revision 1.07. Apparent chip bug */
@@ -330,14 +332,14 @@ void apply_microcode(int cpu)rdmsr (MSR_IA32_UCODE_REV , val[0 ], val[1 ]);spin_unlock_irqrestore (µcode_update_lock, flags); -if (val[1 ] != uci->mc->hdr.rev) { +if (val[1 ] != uci->mc.mc_intel->hdr.rev) {printk (KERN_ERR "microcode: CPU%d update from revision " "0x%x to 0x%x failed\n" , cpu_num, uci->rev, val[1 ]);return ; }printk (KERN_INFO "microcode: CPU%d updated from revision " "0x%x to 0x%x, date = %08x \n" , - cpu_num, uci->rev, val[1 ], uci->mc->hdr.date); + cpu_num, uci->rev, val[1 ], uci->mc.mc_intel->hdr.date); uci->rev = val[1 ]; }
@@ -347,7 +349,7 @@ extern unsigned int user_buffer_size; /* it's size */long get_next_ucode (void **mc,long offset) { -struct microcode_header mc_header; +struct microcode_header_intel mc_header;unsigned long total_size;/* No more data */
@@ -378,13 +380,13 @@ long get_next_ucode(void **mc, long offset)static long get_next_ucode_from_buffer (void **mc,const u8 *buf,unsigned long size,long offset) { -struct microcode_header *mc_header; +struct microcode_header_intel *mc_header;unsigned long total_size;/* No more data */ if (offset >= size)return 0 ; - mc_header = (struct microcode_header *)(buf + offset); + mc_header = (struct microcode_header_intel *)(buf + offset); total_size =get_totalsize (mc_header);if (offset + total_size > size) {
@@ -462,7 +464,7 @@ int apply_microcode_check_cpu(int cpu)int err =0 ;/* Check if the microcode is available */ -if (!uci->mc) +if (!uci->mc.mc_intel)return 0 ; old = current->cpus_allowed;
@@ -507,7 +509,7 @@ void microcode_fini_cpu(int cpu)mutex_lock (µcode_mutex); uci->valid =0 ; -kfree (uci->mc); - uci->mc =NULL ; +kfree (uci->mc.mc_intel); + uci->mc.mc_intel =NULL ;mutex_unlock (µcode_mutex); }
include/asm-x86/microcode.h +6 -4
@@ -1,4 +1,4 @@ -struct microcode_header { +struct microcode_header_intel {unsigned int hdrver;unsigned int rev;unsigned int date;
@@ -11,8 +11,8 @@ struct microcode_header {unsigned int reserved[3 ]; }; -struct microcode { -struct microcode_header hdr; +struct microcode_intel { +struct microcode_header_intel hdr;unsigned int bits[0 ]; };
@@ -35,5 +35,7 @@ struct ucode_cpu_info {unsigned int sig;unsigned int pf;unsigned int rev; -struct microcode *mc; +union { +struct microcode_intel *mc_intel; + } mc; };
Signature · 1 line
1.5.4.5
PATCH 6/9 x86: Add AMD specific declarations.
In reply to Peter OrubaAdded AMD specific declarations to header file.
--- include/asm-x86/microcode.h | 30 ++++++++++++++++++++++++++++++ 1 files changed, 30 insertions(+), 0 deletions(-)
include/asm-x86/microcode.h +30 -0
@@ -30,6 +30,35 @@ struct extended_sigtable {struct extended_signature sigs[0 ]; }; +struct equiv_cpu_entry { +unsigned int installed_cpu; +unsigned int fixed_errata_mask; +unsigned int fixed_errata_compare; +unsigned int equiv_cpu; +}; + +struct microcode_header_amd { +unsigned int data_code; +unsigned int patch_id; +unsigned char mc_patch_data_id[2 ]; +unsigned char mc_patch_data_len; +unsigned char init_flag; +unsigned int mc_patch_data_checksum; +unsigned int nb_dev_id; +unsigned int sb_dev_id; +unsigned char processor_rev_id[2 ]; +unsigned char nb_rev_id; +unsigned char sb_rev_id; +unsigned char bios_api_rev; +unsigned char reserved1[3 ]; +unsigned int match_reg[8 ]; +}; + +struct microcode_amd { +struct microcode_header_amd hdr; +unsigned int mpb[0 ]; +}; +struct ucode_cpu_info {int valid;unsigned int sig;
@@ -37,5 +66,6 @@ struct ucode_cpu_info {unsigned int rev;union {struct microcode_intel *mc_intel; +struct microcode_amd *mc_amd; } mc; };
Signature · 1 line
1.5.4.5
PATCH 7/9 x86: First step of refactoring, introducing microcode_ops.
In reply to Peter OrubaRefactoring with the goal of having one general module and separate vendor specific modules that hook into the general one.
Microcode_ops is a function pointer structure in which vendor specific modules will enter all functions that differ between vendors and that need to be accessed from the general module.
--- include/asm-x86/microcode.h | 13 +++++++++++++ 1 files changed, 13 insertions(+), 0 deletions(-)
include/asm-x86/microcode.h +13 -0
@@ -1,3 +1,16 @@ +struct microcode_ops { +long (*get_next_ucode)(void **mc,long offset); +long (*microcode_get_next_ucode)(void **mc,long offset); +int (*get_matching_microcode)(void *mc,int cpu); +int (*apply_microcode_check_cpu)(int cpu); +int (*microcode_sanity_check)(void *mc); +int (*cpu_request_microcode)(int cpu); +void (*collect_cpu_info)(int cpu_num); +void (*apply_microcode)(int cpu); +void (*microcode_fini_cpu)(int cpu); +void (*clear_patch)(void *data); +}; +struct microcode_header_intel {unsigned int hdrver;unsigned int rev;
Signature · 1 line
1.5.4.5
PATCH 8/9 x86: Major refactoring.
In reply to Peter OrubaRefactored code by introducing a two-module solution. There is one general module in which vendor specific modules can hook into. However, that is exclusive, there is only one vendor specific module allowed at a time. A CPU vendor check makes sure only the corect module for the underlying system gets called. Functinally in terms of patch loading itself there are no changes. This refactoring provides a basis for future implementations of other vendors' patch loaders.
--- arch/x86/Kconfig | 24 +++++++++-- arch/x86/kernel/Makefile | 4 +- arch/x86/kernel/microcode.c | 80 +++++++++++++++++++++--------------- arch/x86/kernel/microcode_intel.c | 54 ++++++++++++++++++++----- 4 files changed, 112 insertions(+), 50 deletions(-)
arch/x86/Kconfig +19 -5
@@ -782,7 +782,7 @@ config X86_REBOOTFIXUPS Say N otherwise. config MICROCODE - tristate "/dev/cpu/microcode - Intel IA32 CPU microcode support" + tristate "/dev/cpu/microcode - microcode support" select FW_LOADER ---help--- If you say Y here, you will be able to update the microcode on
@@ -791,14 +791,28 @@ config MICROCODE actual microcode binary data itself which is not shipped with the Linux kernel. - For latest news and information on obtaining all the required - ingredients for this driver, check: - <http://www.urbanmyth.org/microcode/>. + This option selects the general module only, you need to select + at least one vendor specific module as well. To compile this driver as a module, choose M here: the module will be called microcode. -config MICROCODE_OLD_INTERFACE +config MICROCODE_INTEL + tristate "Intel microcode patch loading support" + depends on MICROCODE + select FW_LOADER + --help--- + This options enables microcode patch loading support for Intel + processors. + + For latest news and information on obtaining all the required + Intel ingredients for this driver, check: + <http://www.urbanmyth.org/microcode/>. + + This driver is only available as a module: the module + will be called microcode_intel. + + config MICROCODE_OLD_INTERFACE def_bool y depends on MICROCODE
arch/x86/kernel/Makefile +2 -2
@@ -51,8 +51,8 @@ obj-$(CONFIG_X86_BIOS_REBOOT) += reboot.o obj-$(CONFIG_MCA) += mca_32.o obj-$(CONFIG_X86_MSR) += msr.o obj-$(CONFIG_X86_CPUID) += cpuid.o -obj-$(CONFIG_MICROCODE) += ucode.o -ucode-objs := microcode.o microcode_intel.o +obj-$(CONFIG_MICROCODE) += microcode.o +obj-$(CONFIG_MICROCODE_INTEL) += microcode_intel.o obj-$(CONFIG_PCI) += early-quirks.o apm-y := apm_32.o obj-$(CONFIG_APM) += apm.o
arch/x86/kernel/microcode.c +47 -33
171 lines not on this page · raw message
arch/x86/kernel/microcode_intel.c +44 -10
119 lines not on this page · raw message
Signature · 1 line
1.5.4.5
Re: [patch 8/9] [PATCH 8/9] x86: Major refactoring.
Quoted 16 lines · Peter Oruba
Refactored code by introducing a two-module solution. There is one general module in which vendor specific modules can hook into.
config MICROCODE
arch/x86/Kconfig +1
-4- tristate "/dev/cpu/microcode - Intel IA32 CPU microcode support" + tristate "/dev/cpu/microcode - microcode support" select FW_LOADER ---help--- If you say Y here, you will be able to update the microcode on@@ -791,14 +791,28 @@ config MICROCODE actual microcode binary data itself which is not shipped with the Linux kernel. - For latest news and information on obtaining all the required - ingredients for this driver, check: - <http://www.urbanmyth.org/microcode/>.
arch/x86/Kconfig config MICROCODE · line 802
Quoted 10 lines
arch/x86/Kconfig +5
-1+ This option selects the general module only, you need to select + at least one vendor specific module as well. To compile this driver as a module, choose M here: the module will be called microcode. -config MICROCODE_OLD_INTERFACE +config MICROCODE_INTEL + tristate "Intel microcode patch loading support" + depends on MICROCODE
default MICROCODE
so that users doing make oldconfig don't get a surprise?
arch/x86/Kconfig config MICROCODE · line 815
Quoted 13 lines
arch/x86/Kconfig +13
-0+ select FW_LOADER + --help--- + This options enables microcode patch loading support for Intel + processors. + + For latest news and information on obtaining all the required + Intel ingredients for this driver, check: + <http://www.urbanmyth.org/microcode/>. + + This driver is only available as a module: the module + will be called microcode_intel. + + config MICROCODE_OLD_INTERFACE
Kill the extra spaces.
Daniel K.
PATCH 9/9 x86: AMD microcode patch loading support.
In reply to Peter OrubaThis patch introduces microcode patch loading for AMD processors. It is based on previous corresponding work for Intel processors.
It hooks into the general patch loading module. Main difference is that a container file format is used to hold all patch data for multiple processors as well as an equivalent CPU table, which comes seperately, as opposed to Intel's microcode patching solution.
Kconfig and Makefile have been changed provice config and build option for new source file.
--- arch/x86/Kconfig | 21 ++- arch/x86/kernel/Makefile | 1 + arch/x86/kernel/microcode_amd.c | 516 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 534 insertions(+), 4 deletions(-) create mode 100644 arch/x86/kernel/microcode_amd.c
arch/x86/Kconfig +17 -4
@@ -786,10 +786,12 @@ config MICROCODE select FW_LOADER ---help--- If you say Y here, you will be able to update the microcode on - Intel processors in the IA32 family, e.g. Pentium Pro, Pentium II, - Pentium III, Pentium 4, Xeon etc. You will obviously need the - actual microcode binary data itself which is not shipped with the - Linux kernel. + certain Intel and AMD 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 family 0x10 and + 0x11 processors, e.g. Opteron, Phenom and Turion 64 Ultra. + You will obviously need the actual microcode binary data itself + which is not shipped with the Linux kernel. This option selects the general module only, you need to select at least one vendor specific module as well.
@@ -812,6 +814,17 @@ config MICROCODE_INTEL This driver is only available as a module: the module will be called microcode_intel. +config MICROCODE_AMD + tristate "AMD microcode patch loading support" + depends on MICROCODE + select FW_LOADER + --help--- + If you select this option, microcode patch loading support for AMD + processors will be enabled. + + This driver is only available as a module: the module + will be called microcode_intel. + config MICROCODE_OLD_INTERFACE def_bool y depends on MICROCODE
arch/x86/kernel/Makefile +1 -0
@@ -53,6 +53,7 @@ obj-$(CONFIG_X86_MSR) += msr.o obj-$(CONFIG_X86_CPUID) += cpuid.o obj-$(CONFIG_MICROCODE) += microcode.o obj-$(CONFIG_MICROCODE_INTEL) += microcode_intel.o +obj-$(CONFIG_MICROCODE_AMD) += microcode_amd.o obj-$(CONFIG_PCI) += early-quirks.o apm-y := apm_32.o obj-$(CONFIG_APM) += apm.o
arch/x86/kernel/microcode_amd.c new file +516 -0
516 lines not on this page · raw message
Signature · 1 line
1.5.4.5
Re: [patch 9/9] [PATCH 9/9] x86: AMD microcode patch loading support.
Quoted 10 lines · Peter Oruba
This patch introduces microcode patch loading for AMD processors. It is based on previous corresponding work for Intel processors.
It hooks into the general patch loading module. Main difference is that a container file format is used to hold all patch data for multiple processors as well as an equivalent CPU table, which comes seperately, as opposed to Intel's microcode patching solution.
Quoted 4 lines
KconfigandMakefilehave been changed provice config and build option for new source file.Signed-off-by Peter Oruba <[email protected]>
Can't comment on your refactoring/design, but see below for some things to possibly fix in the code.
Quoted 32 lines
--- arch/x86/Kconfig | 21 ++- arch/x86/kernel/Makefile | 1 + arch/x86/kernel/microcode_amd.c | 516 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 534 insertions(+), 4 deletions(-) create mode 100644 arch/x86/kernel/microcode_amd.carch/x86/Kconfig +6
-4@@ -786,10 +786,12 @@ config MICROCODE select FW_LOADER ---help--- If you say Y here, you will be able to update the microcode on - Intel processors in the IA32 family, e.g. Pentium Pro, Pentium II, - Pentium III, Pentium 4, Xeon etc. You will obviously need the - actual microcode binary data itself which is not shipped with the - Linux kernel. + certain Intel and AMD 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 family 0x10 and + 0x11 processors, e.g. Opteron, Phenom and Turion 64 Ultra. + You will obviously need the actual microcode binary data itself + which is not shipped with the Linux kernel. This option selects the general module only, you need to select at least one vendor specific module as well.@@ -812,6 +814,17 @@ config MICROCODE_INTEL This driver is only available as a module: the module will be called microcode_intel.
arch/x86/Kconfig config MICROCODE_INTEL · line 826
Quoted 10 lines
arch/x86/Kconfig +10
-0+config MICROCODE_AMD + tristate "AMD microcode patch loading support" + depends on MICROCODE + select FW_LOADER + --help--- + If you select this option, microcode patch loading support for AMD + processors will be enabled. + + This driver is only available as a module: the module + will be called microcode_intel.
Should say microcode_amd.
Quoted 55 lines
arch/x86/Kconfig +1
-0+ config MICROCODE_OLD_INTERFACE def_bool y depends on MICROCODEarch/x86/kernel/Makefile +1
-0@@ -53,6 +53,7 @@ obj-$(CONFIG_X86_MSR) += msr.o obj-$(CONFIG_X86_CPUID) += cpuid.o obj-$(CONFIG_MICROCODE) += microcode.o obj-$(CONFIG_MICROCODE_INTEL) += microcode_intel.o +obj-$(CONFIG_MICROCODE_AMD) += microcode_amd.o obj-$(CONFIG_PCI) += early-quirks.o apm-y := apm_32.o obj-$(CONFIG_APM) += apm.oarch/x86/kernel/microcode_amd.c new file +33
-0@@ -0,0 +1,516 @@ +/* +* AMD CPU Microcode Update Driver for Linux +* Copyright (C) 2008 Advanced Micro Devices Inc. +* +* Author: Peter Oruba <[email protected]> +* +* Based on work by: +* Tigran Aivazian <[email protected]> +* +* This driver allows to upgrade microcode on AMD +* family 0x10 and 0x11 processors. +* +* Licensed unter the terms of the GNU General Public +* License version 2. See file COPYING for details. +*/ + +#include <linux/capability.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/sched.h> +#include <linux/cpumask.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/vmalloc.h> +#include <linux/miscdevice.h> +#include <linux/spinlock.h> +#include <linux/mm.h> +#include <linux/fs.h> +#include <linux/mutex.h> +#include <linux/cpu.h> +#include <linux/firmware.h> +#include <linux/platform_device.h> +#include <linux/pci.h>
arch/x86/kernel/microcode_amd.c line 43
Quoted 10 lines
arch/x86/kernel/microcode_amd.c new file +10
-0+#include <linux/pci_ids.h> + +#include <asm/msr.h> +#include <asm/uaccess.h> +#include <asm/processor.h> +#include <asm/microcode.h> + +MODULE_DESCRIPTION ("AMD Microcode Update Driver" ); +MODULE_AUTHOR ("Peter Oruba <[email protected]>" ); +MODULE_LICENSE ("GPL" );
Based on the license in the comments at the top of the file, I think this should be "GPLv2".
Quoted 7 lines
arch/x86/kernel/microcode_amd.c new file +7
-0+ +#define UCODE_MAGIC 0x00414d44 +#define UCODE_EQUIV_CPU_TABLE_TYPE 0x00000000 +#define UCODE_UCODE_TYPE 0x00000001 + +#define UCODE_MAX_SIZE (2048) +#define DEFAULT_UCODE_DATASIZE (896)/* 896 bytes */
arch/x86/kernel/microcode_amd.c line 60
Quoted 10 lines
arch/x86/kernel/microcode_amd.c new file +10
-0+#define MC_HEADER_SIZE (sizeof(struct microcode_header_amd))/* 64 bytes */ +#define DEFAULT_UCODE_TOTALSIZE (DEFAULT_UCODE_DATASIZE + MC_HEADER_SIZE)/* 960 bytes */ +#define DWSIZE (sizeof(u32)) +/* For now we support a fixed ucode total size only */ +#define get_totalsize (mc) \ + ((((struct microcode_amd *)mc)->hdr.mc_patch_data_len * 28) \ + + MC_HEADER_SIZE) + +extern int microcode_init (void *opaque,struct module *module); +extern void microcode_exit (void );
Since these declarations (and the other externs) are shared with the other Intel driver, why not move them to the header file?
Quoted 51 lines
arch/x86/kernel/microcode_amd.c new file +51
-0+ +/* serialize access to the physical write */ +static DEFINE_SPINLOCK (microcode_update_lock); + +/* no concurrent ->write()s are allowed on /dev/cpu/microcode */ +extern struct mutex (microcode_mutex); + +struct equiv_cpu_entry *equiv_cpu_table; + +extern struct ucode_cpu_info ucode_cpu_info[NR_CPUS ]; + +static void collect_cpu_info_amd (int cpu) +{ +struct cpuinfo_x86 *c = &cpu_data (cpu); +struct ucode_cpu_info *uci = ucode_cpu_info + cpu; + +/* We should bind the task to the CPU */ +BUG_ON (raw_smp_processor_id () != cpu); + uci->rev =0 ; + uci->pf =0 ; + uci->mc.mc_amd =NULL ; + uci->valid =1 ; + +if (c->x86_vendor !=X86_VENDOR_AMD || c->x86 <0x10 ) { +printk (KERN_ERR "microcode: CPU%d not a capable AMD processor\n" , + cpu); + uci->valid =0 ; +return ; + } + + asmvolatile ("movl %1, %%ecx; rdmsr" + :"=a" (uci->rev) + :"i" (0x0000008B ) :"ecx" ); + +printk (KERN_INFO "microcode: collect_cpu_info_amd : patch_id=0x%x\n" , + uci->rev); +} + +static int get_matching_microcode_amd (void *mc,int cpu) +{ +struct ucode_cpu_info *uci = ucode_cpu_info + cpu; +struct microcode_header_amd *mc_header = mc; +unsigned long total_size =get_totalsize (mc_header); +void *new_mc; +struct pci_dev *nb_pci_dev, *sb_pci_dev; +unsigned int current_cpu_id; +unsigned int equiv_cpu_id =0x00 ; +unsigned int i =0 ; + +/* We should bind the task to the CPU */ +BUG_ON (cpu !=raw_smp_processor_id ());
arch/x86/kernel/microcode_amd.c line 121
Quoted 10 lines
arch/x86/kernel/microcode_amd.c new file +10
-0+ +/* This is a tricky part. We might be called from a write operation */ +/* to the device file instead of the usual process of firmware */ +/* loading. This routine needs to be able to distinguish both */ +/* cases. This is done by checking if there alread is a equivalent */ +/* CPU table installed. If not, we're written through */ +/* /dev/cpu/microcode. */ +/* Since we ignore all checks. The error case in which going through */ +/* firmware loading and that table is not loaded has already been */ +/* checked earlier. */
Some spaces seem to have sneaked in the indentation above.
Quoted 69 lines
arch/x86/kernel/microcode_amd.c new file +69
-0+if (equiv_cpu_table ==NULL ) { +printk (KERN_INFO "microcode: CPU%d microcode update with " +"version 0x%x (current=0x%x)\n" , + cpu, mc_header->patch_id, uci->rev); + goto out; + } + + current_cpu_id =cpuid_eax (0x00000001 ); + +while (equiv_cpu_table[i].installed_cpu !=0 ) { +if (current_cpu_id == equiv_cpu_table[i].installed_cpu) { + equiv_cpu_id = equiv_cpu_table[i].equiv_cpu; +break ; + } + i++; + } + +if (!equiv_cpu_id) { +printk (KERN_ERR "microcode: CPU%d cpu_id " +"not found in equivalent cpu table \n" , cpu); +return 0 ; + } + +if ((mc_header->processor_rev_id[0 ]) != (equiv_cpu_id &0xff )) { +printk (KERN_ERR +"microcode: CPU%d patch does not match " +"(patch is %x, cpu extended is %x) \n" , + cpu, mc_header->processor_rev_id[0 ], + (equiv_cpu_id &0xff )); +return 0 ; + } + +if ((mc_header->processor_rev_id[1 ]) != ((equiv_cpu_id >>16 ) &0xff )) { +printk (KERN_ERR "microcode: CPU%d patch does not match " +"(patch is %x, cpu base id is %x) \n" , + cpu, mc_header->processor_rev_id[1 ], + ((equiv_cpu_id >>16 ) &0xff )); + +return 0 ; + } + +/* ucode may be northbridge specific */ +if (mc_header->nb_dev_id) { + nb_pci_dev =pci_get_device (PCI_VENDOR_ID_AMD , + (mc_header->nb_dev_id &0xff ), +NULL ); +if ((!nb_pci_dev) || + (mc_header->nb_rev_id != nb_pci_dev->revision)) { +printk (KERN_ERR "microcode: CPU%d NB mismatch \n" , cpu); +pci_dev_put (nb_pci_dev); +return 0 ; + } +pci_dev_put (nb_pci_dev); + } + +/* ucode may be southbridge specific */ +if (mc_header->sb_dev_id) { + sb_pci_dev =pci_get_device (PCI_VENDOR_ID_AMD , + (mc_header->sb_dev_id &0xff ), +NULL ); +if ((!sb_pci_dev) || + (mc_header->sb_rev_id != sb_pci_dev->revision)) { +printk (KERN_ERR "microcode: CPU%d SB mismatch \n" , cpu); +pci_dev_put (sb_pci_dev); +return 0 ; + } +pci_dev_put (sb_pci_dev); + } +
arch/x86/kernel/microcode_amd.c line 200
Quoted 10 lines
arch/x86/kernel/microcode_amd.c new file +10
-0+if (mc_header->patch_id <= uci->rev) +return 0 ; + +printk (KERN_INFO "microcode: CPU%d found a matching microcode " +"update with version 0x%x (current=0x%x)\n" , + cpu, mc_header->patch_id, uci->rev); + +out: + new_mc =vmalloc (UCODE_MAX_SIZE ); +memset (new_mc,0 ,UCODE_MAX_SIZE );
The memset() should come after the vmalloc() failure check.
Quoted 75 lines
arch/x86/kernel/microcode_amd.c new file +75
-0+ +if (!new_mc) { +printk (KERN_ERR "microcode: error, can't allocate memory\n" ); +return -ENOMEM ; + } + +/* free previous update file */ +vfree (uci->mc.mc_amd); + +memcpy (new_mc, mc, total_size); + + uci->mc.mc_amd = new_mc; +return 1 ; +} + +static void apply_microcode_amd (int cpu) +{ +unsigned long flags; +unsigned int eax, edx; +unsigned int rev; +int cpu_num =raw_smp_processor_id (); +struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num; + +/* We should bind the task to the CPU */ +BUG_ON (cpu_num != cpu); + +if (uci->mc.mc_amd ==NULL ) +return ; + +spin_lock_irqsave (µcode_update_lock, flags); + + edx = (unsigned int )(((unsigned long ) + &(uci->mc.mc_amd->hdr.data_code)) >>32 ); + eax = (unsigned int )(((unsigned long ) + &(uci->mc.mc_amd->hdr.data_code)) &0xffffffffL ); + + asmvolatile ("movl %0, %%ecx; wrmsr" : + :"i" (0xc0010020 ),"a" (eax),"d" (edx) :"ecx" ); + +/* get patch id after patching */ + asmvolatile ("movl %1, %%ecx; rdmsr" + :"=a" (rev) + :"i" (0x0000008B ) :"ecx" ); + +spin_unlock_irqrestore (µcode_update_lock, flags); + +/* check current patch id and patch's id for match */ +if (rev != uci->mc.mc_amd->hdr.patch_id) { +printk (KERN_ERR "microcode: CPU%d update from revision " +"0x%x to 0x%x failed\n" , cpu_num, + uci->mc.mc_amd->hdr.patch_id, rev); +return ; + } + +printk (KERN_INFO "microcode: CPU%d updated from revision " +"0x%x to 0x%x \n" , + cpu_num, uci->rev, uci->mc.mc_amd->hdr.patch_id); + + uci->rev = rev; +} + +#ifdef CONFIG_MICROCODE_OLD_INTERFACE +extern void __user *user_buffer;/* user area microcode data buffer */ +extern unsigned int user_buffer_size;/* it's size */ + +static long get_next_ucode_amd (void **mc,long offset) +{ +struct microcode_header_amd mc_header; +unsigned long total_size; + +/* No more data */ +if (offset >= user_buffer_size) +return 0 ; +if (copy_from_user (&mc_header, user_buffer + offset,MC_HEADER_SIZE )) { +printk (KERN_ERR "microcode: error! Can not read user data\n" );
arch/x86/kernel/microcode_amd.c line 285
Quoted 10 lines
arch/x86/kernel/microcode_amd.c new file +10
-0+return -EFAULT ; + } + total_size =get_totalsize (&mc_header); +if (offset + total_size > user_buffer_size) { +printk (KERN_ERR "microcode: error! Bad total size in microcode " +"data file\n" ); +return -EINVAL ; + } + *mc =vmalloc (UCODE_MAX_SIZE ); +memset (*mc,0 ,UCODE_MAX_SIZE );
The memset() should come after the vmalloc() failure check.
Quoted 28 lines
arch/x86/kernel/microcode_amd.c new file +28
-0+ +if (!*mc) +return -ENOMEM ; +if (copy_from_user (*mc, user_buffer + offset, total_size)) { +printk (KERN_ERR "microcode: error! Can not read user data\n" ); +vfree (*mc); +return -EFAULT ; + } + return offset + total_size; +} +#else +#define get_next_ucode_amd () NULL +#endif + +static long get_next_ucode_from_buffer_amd (void **mc,void *buf, +unsigned long size,long offset) +{ +struct microcode_header_amd *mc_header; +unsigned long total_size; +unsigned char *buf_pos = buf; + +/* No more data */ +if (offset >= size) +return 0 ; + +if (buf_pos[offset] !=UCODE_UCODE_TYPE ) { +printk (KERN_ERR "microcode: error! " +"Wrong microcode payload type field\n" );
arch/x86/kernel/microcode_amd.c line 323
Quoted 10 lines
arch/x86/kernel/microcode_amd.c new file +10
-0+return -EINVAL ; + } + + mc_header = (struct microcode_header_amd *)(&buf_pos[offset+8 ]); + + total_size = (unsigned long ) (buf_pos[offset+4 ] + + (buf_pos[offset+5 ] <<8 )); + +printk (KERN_ERR "microcode: size %lu, total_size %lu, offset %ld\n" , + size, total_size, offset);
Unconditional KERN_ERR?
arch/x86/kernel/microcode_amd.c line 331
Quoted 8 lines
arch/x86/kernel/microcode_amd.c new file +8
-0+ +if (offset + total_size > size) { +printk (KERN_ERR "microcode: error! Bad data in microcode data file\n" ); +return -EINVAL ; + } + + *mc =vmalloc (UCODE_MAX_SIZE ); +memset (*mc,0 ,UCODE_MAX_SIZE );
The memset() should come after the vmalloc() failure check.
Quoted 23 lines
arch/x86/kernel/microcode_amd.c new file +23
-0+ +if (!*mc) { +printk (KERN_ERR "microcode: error! " +"Can not allocate memory for microcode patch\n" ); +return -ENOMEM ; + } +memcpy (*mc, buf + offset +8 , total_size); + +return offset + total_size +8 ; +} + +static long install_equiv_cpu_table (void *buf,unsigned long size,long offset) +{ +unsigned int *buf_pos = buf; + +/* No more data */ +if (offset >= size) +return 0 ; + +if (buf_pos[1 ] !=UCODE_EQUIV_CPU_TABLE_TYPE ) { +printk (KERN_ERR "microcode: error! " +"Wrong microcode equivalnet cpu table type field\n" ); +return 0 ;
arch/x86/kernel/microcode_amd.c line 364
Quoted 10 lines
arch/x86/kernel/microcode_amd.c new file +10
-0+ } + +if (size ==0 ) { +printk (KERN_ERR "microcode: error! " +"Wrong microcode equivalnet cpu table length\n" ); +return 0 ; + } + + equiv_cpu_table = (struct equiv_cpu_entry *)vmalloc (size); +memset (equiv_cpu_table,0 , size);
No failure check for the allocation here.
Quoted 14 lines
arch/x86/kernel/microcode_amd.c new file +14
-0+ +memcpy (equiv_cpu_table, &buf_pos[3 ], size); + +return size +12 ;/* add header length */ +} + +/* fake device for request_firmware */ +extern struct platform_device *microcode_pdev; + +static int cpu_request_microcode_amd (int cpu) +{ +char name[30 ]; +const struct firmware *firmware; +void *buf;
arch/x86/kernel/microcode_amd.c line 388
Quoted 10 lines
arch/x86/kernel/microcode_amd.c new file +10
-0+unsigned int *buf_pos; +unsigned long size; +long offset =0 ; +int error; +void *mc; + +/* We should bind the task to the CPU */ +BUG_ON (cpu !=raw_smp_processor_id ()); + +sprintf (name,"amd-ucode/microcode_amd.bin" );
Just pass the string directly to request_firmware.
Quoted 10 lines
arch/x86/kernel/microcode_amd.c new file +10
-0+ error =request_firmware (&firmware, name, µcode_pdev->dev); +if (error) { +printk (KERN_ERR "microcode: ucode data file %s load failed\n" , + name); +return error; + } + + buf_pos = buf = firmware->data; + size = firmware->size; +
arch/x86/kernel/microcode_amd.c line 408
Quoted 10 lines
arch/x86/kernel/microcode_amd.c new file +10
-0+if (buf_pos[0 ] !=UCODE_MAGIC ) { +printk (KERN_ERR "microcode: error! Wrong microcode patch file magic\n" ); +return 0 ; + } + + offset =install_equiv_cpu_table (buf, buf_pos[2 ], offset); + +if (!offset) { +printk (KERN_ERR "microcode: installing equivalent cpu table failed\n" ); +return error;
This will always return zero, since error has not been touched since the last check after request_firmware().
Quoted 11 lines
arch/x86/kernel/microcode_amd.c new file +11
-0+ } + +while ((offset = +get_next_ucode_from_buffer_amd (&mc, buf, size, offset)) >0 ) { + error =get_matching_microcode_amd (mc, cpu); +if (error <0 ) +break ; +/* +* It's possible the data file has multiple matching ucode, +* lets keep searching till the latest version +*/
arch/x86/kernel/microcode_amd.c line 429
Quoted 10 lines
arch/x86/kernel/microcode_amd.c new file +10
-0+if (error ==1 ) { +apply_microcode_amd (cpu); + error =0 ; + } +vfree (mc); + } + +if (offset >0 ) { +vfree (mc); +vfree (equiv_cpu_table);
Set equiv_cpu_table to NULL after freeing it.
Quoted 87 lines
arch/x86/kernel/microcode_amd.c new file +87
-0+ } +if (offset <0 ) + error = offset; +release_firmware (firmware); + +return error; +} + +static int apply_microcode_check_cpu_amd (int cpu) +{ +struct cpuinfo_x86 *c = &cpu_data (cpu); +struct ucode_cpu_info *uci = ucode_cpu_info + cpu; +unsigned int rev; +cpumask_t old; +int err =0 ; + +/* Check if the microcode is available */ +if (!uci->mc.mc_amd) +return 0 ; + + old = current->cpus_allowed; +set_cpus_allowed (current,cpumask_of_cpu (cpu)); + +/* Check if the microcode we have in memory matches the CPU */ +if (c->x86_vendor !=X86_VENDOR_AMD || c->x86 <16 ) + err = -EINVAL ; + +if (!err) { + asmvolatile ("movl %1, %%ecx; rdmsr" + :"=a" (rev) + :"i" (0x0000008B ) :"ecx" ); + +if (uci->rev != rev) + err = -EINVAL ; + } + +if (!err) +apply_microcode_amd (cpu); +else +printk (KERN_ERR "microcode: Could not apply microcode to CPU%d:" +" rev=0x%x\n" , + cpu, uci->rev); + +set_cpus_allowed (current, old); +return err; +} + +static void microcode_fini_cpu_amd (int cpu) +{ +struct ucode_cpu_info *uci = ucode_cpu_info + cpu; + +mutex_lock (µcode_mutex); + uci->valid =0 ; +vfree (uci->mc.mc_amd); + uci->mc.mc_amd =NULL ; +mutex_unlock (µcode_mutex); +} + +static struct microcode_ops microcode_amd_ops = { + .get_next_ucode = get_next_ucode_amd, + .get_matching_microcode = get_matching_microcode_amd, + .microcode_sanity_check =NULL , + .apply_microcode_check_cpu = apply_microcode_check_cpu_amd, + .cpu_request_microcode = cpu_request_microcode_amd, + .collect_cpu_info = collect_cpu_info_amd, + .apply_microcode = apply_microcode_amd, + .microcode_fini_cpu = microcode_fini_cpu_amd, +}; + +static int __init microcode_amd_module_init (void ) +{ +struct cpuinfo_x86 *c = &cpu_data (get_cpu ()); + + equiv_cpu_table =NULL ; +if (c->x86_vendor ==X86_VENDOR_AMD ) +return microcode_init (µcode_amd_ops,THIS_MODULE ); +else +return -ENODEV ; +} + +static void __exit microcode_amd_module_exit(void) +{ +microcode_exit (); +} + +module_init (microcode_amd_module_init) +module_exit (microcode_amd_module_exit)
PATCH 1/1 x86: Add entry to MAINTAINERS file
In reply to Peter OrubaAdd an entry to the MAINTAINERS file for AMD CPU microcode patch loading support.
--- MAINTAINERS | 5 +++++ 1 files changed, 5 insertions(+), 0 deletions(-)
MAINTAINERS +5 -0
@@ -384,6 +384,11 @@ M: [email protected] L: [email protected] S: Supported +AMD MICROCODE UPDATE SUPPORT +P: Peter Oruba +M: [email protected] +S: Supported + AMS (Apple Motion Sensor) DRIVER P: Stelian Pop M: [email protected]
Signature · 1 line
1.5.4.5
Quoted 5 lines · Peter Oruba
This patch set introduces microcode patch loading support for AMD processors. It includes refactoring of existing code to allow code sharing. Vendor specific code has been split off, leading to a multi-module solution as compared to the current single-module approach.
patch #4 does not apply anymore to latest -git:
patching file arch/x86/kernel/microcode.c
Hunk #2 FAILED at 143.
Hunk #3 FAILED at 229.
Hunk #4 FAILED at 248.
3 out of 4 hunks FAILED -- rejects in file arch/x86/kernel/microcode.c
could you please resend?
Thanks,
Ingo