1
0
Fork 0

x86: major refactoring

Refactored 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 correct
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.

Signed-off-by: Peter Oruba <peter.oruba@amd.com>
Cc: Tigran Aivazian <tigran@aivazian.fsnet.co.uk>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
hifive-unleashed-5.1
Peter Oruba 2008-07-28 18:44:21 +02:00 committed by Ingo Molnar
parent 26bf7a48c3
commit 8d86f390d9
5 changed files with 112 additions and 50 deletions

View File

@ -782,7 +782,7 @@ config X86_REBOOTFIXUPS
Say N otherwise. Say N otherwise.
config MICROCODE config MICROCODE
tristate "/dev/cpu/microcode - Intel IA32 CPU microcode support" tristate "/dev/cpu/microcode - microcode support"
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
@ -791,14 +791,29 @@ config MICROCODE
actual microcode binary data itself which is not shipped with the actual microcode binary data itself which is not shipped with the
Linux kernel. Linux kernel.
For latest news and information on obtaining all the required This option selects the general module only, you need to select
ingredients for this driver, check: at least one vendor specific module as well.
<http://www.urbanmyth.org/microcode/>.
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called microcode. module will be called microcode.
config MICROCODE_OLD_INTERFACE config MICROCODE_INTEL
tristate "Intel microcode patch loading support"
depends on MICROCODE
default 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 def_bool y
depends on MICROCODE depends on MICROCODE

View File

@ -51,8 +51,8 @@ obj-$(CONFIG_X86_BIOS_REBOOT) += reboot.o
obj-$(CONFIG_MCA) += mca_32.o obj-$(CONFIG_MCA) += mca_32.o
obj-$(CONFIG_X86_MSR) += msr.o obj-$(CONFIG_X86_MSR) += msr.o
obj-$(CONFIG_X86_CPUID) += cpuid.o obj-$(CONFIG_X86_CPUID) += cpuid.o
obj-$(CONFIG_MICROCODE) += ucode.o obj-$(CONFIG_MICROCODE) += microcode.o
ucode-objs := microcode.o microcode_intel.o obj-$(CONFIG_MICROCODE_INTEL) += microcode_intel.o
obj-$(CONFIG_PCI) += early-quirks.o obj-$(CONFIG_PCI) += early-quirks.o
apm-y := apm_32.o apm-y := apm_32.o
obj-$(CONFIG_APM) += apm.o obj-$(CONFIG_APM) += apm.o

View File

@ -99,25 +99,22 @@ MODULE_DESCRIPTION("Microcode Update Driver");
MODULE_AUTHOR("Tigran Aivazian <tigran@aivazian.fsnet.co.uk>"); MODULE_AUTHOR("Tigran Aivazian <tigran@aivazian.fsnet.co.uk>");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
#define MICROCODE_VERSION "1.14a" #define MICROCODE_VERSION "2.00"
struct microcode_ops *microcode_ops;
/* no concurrent ->write()s are allowed on /dev/cpu/microcode */ /* no concurrent ->write()s are allowed on /dev/cpu/microcode */
DEFINE_MUTEX(microcode_mutex); static DEFINE_MUTEX(microcode_mutex);
EXPORT_SYMBOL_GPL(microcode_mutex);
struct ucode_cpu_info ucode_cpu_info[NR_CPUS]; static struct ucode_cpu_info ucode_cpu_info[NR_CPUS];
EXPORT_SYMBOL_GPL(ucode_cpu_info);
extern long get_next_ucode(void **mc, long offset);
extern int microcode_sanity_check(void *mc);
extern int get_matching_microcode(void *mc, int cpu);
extern void collect_cpu_info(int cpu_num);
extern int cpu_request_microcode(int cpu);
extern void microcode_fini_cpu(int cpu);
extern void apply_microcode(int cpu);
extern int apply_microcode_check_cpu(int cpu);
#ifdef CONFIG_MICROCODE_OLD_INTERFACE #ifdef CONFIG_MICROCODE_OLD_INTERFACE
void __user *user_buffer; /* user area microcode data buffer */ static void __user *user_buffer; /* user area microcode data buffer */
unsigned int user_buffer_size; /* it's size */ EXPORT_SYMBOL_GPL(user_buffer);
static unsigned int user_buffer_size; /* it's size */
EXPORT_SYMBOL_GPL(user_buffer_size);
static int do_microcode_update (void) static int do_microcode_update (void)
{ {
@ -130,8 +127,8 @@ static int do_microcode_update (void)
old = current->cpus_allowed; old = current->cpus_allowed;
while ((cursor = get_next_ucode(&new_mc, cursor)) > 0) { while ((cursor = microcode_ops->get_next_ucode(&new_mc, cursor)) > 0) {
error = microcode_sanity_check(new_mc); error = microcode_ops->microcode_sanity_check(new_mc);
if (error) if (error)
goto out; goto out;
/* /*
@ -145,11 +142,12 @@ static int do_microcode_update (void)
continue; continue;
cpumask_of_cpu_ptr_next(newmask, cpu); cpumask_of_cpu_ptr_next(newmask, cpu);
set_cpus_allowed_ptr(current, newmask); set_cpus_allowed_ptr(current, newmask);
error = get_maching_microcode(new_mc, cpu); error = microcode_ops->get_matching_microcode(new_mc,
cpu);
if (error < 0) if (error < 0)
goto out; goto out;
if (error == 1) if (error == 1)
apply_microcode(cpu); microcode_ops->apply_microcode(cpu);
} }
vfree(new_mc); vfree(new_mc);
} }
@ -232,7 +230,8 @@ MODULE_ALIAS_MISCDEV(MICROCODE_MINOR);
#endif #endif
/* fake device for request_firmware */ /* fake device for request_firmware */
struct platform_device *microcode_pdev; static struct platform_device *microcode_pdev;
EXPORT_SYMBOL_GPL(microcode_pdev);
static void microcode_init_cpu(int cpu, int resume) static void microcode_init_cpu(int cpu, int resume)
{ {
@ -244,9 +243,9 @@ static void microcode_init_cpu(int cpu, int resume)
set_cpus_allowed_ptr(current, newmask); set_cpus_allowed_ptr(current, newmask);
mutex_lock(&microcode_mutex); mutex_lock(&microcode_mutex);
collect_cpu_info(cpu); microcode_ops->collect_cpu_info(cpu);
if (uci->valid && system_state == SYSTEM_RUNNING && !resume) if (uci->valid && system_state == SYSTEM_RUNNING && !resume)
cpu_request_microcode(cpu); microcode_ops->cpu_request_microcode(cpu);
mutex_unlock(&microcode_mutex); mutex_unlock(&microcode_mutex);
set_cpus_allowed_ptr(current, &old); set_cpus_allowed_ptr(current, &old);
} }
@ -274,7 +273,7 @@ static ssize_t reload_store(struct sys_device *dev,
mutex_lock(&microcode_mutex); mutex_lock(&microcode_mutex);
if (uci->valid) if (uci->valid)
err = cpu_request_microcode(cpu); err = microcode_ops->cpu_request_microcode(cpu);
mutex_unlock(&microcode_mutex); mutex_unlock(&microcode_mutex);
put_online_cpus(); put_online_cpus();
set_cpus_allowed_ptr(current, &old); set_cpus_allowed_ptr(current, &old);
@ -349,7 +348,7 @@ static int mc_sysdev_remove(struct sys_device *sys_dev)
return 0; return 0;
pr_debug("microcode: CPU%d removed\n", cpu); pr_debug("microcode: CPU%d removed\n", cpu);
microcode_fini_cpu(cpu); microcode_ops->microcode_fini_cpu(cpu);
sysfs_remove_group(&sys_dev->kobj, &mc_attr_group); sysfs_remove_group(&sys_dev->kobj, &mc_attr_group);
return 0; return 0;
} }
@ -362,7 +361,7 @@ static int mc_sysdev_resume(struct sys_device *dev)
return 0; return 0;
pr_debug("microcode: CPU%d resumed\n", cpu); pr_debug("microcode: CPU%d resumed\n", cpu);
/* only CPU 0 will apply ucode here */ /* only CPU 0 will apply ucode here */
apply_microcode(0); microcode_ops->apply_microcode(0);
return 0; return 0;
} }
@ -382,7 +381,7 @@ mc_cpu_callback(struct notifier_block *nb, unsigned long action, void *hcpu)
switch (action) { switch (action) {
case CPU_UP_CANCELED_FROZEN: case CPU_UP_CANCELED_FROZEN:
/* The CPU refused to come up during a system resume */ /* The CPU refused to come up during a system resume */
microcode_fini_cpu(cpu); microcode_ops->microcode_fini_cpu(cpu);
break; break;
case CPU_ONLINE: case CPU_ONLINE:
case CPU_DOWN_FAILED: case CPU_DOWN_FAILED:
@ -390,9 +389,9 @@ mc_cpu_callback(struct notifier_block *nb, unsigned long action, void *hcpu)
break; break;
case CPU_ONLINE_FROZEN: case CPU_ONLINE_FROZEN:
/* System-wide resume is in progress, try to apply microcode */ /* System-wide resume is in progress, try to apply microcode */
if (apply_microcode_check_cpu(cpu)) { if (microcode_ops->apply_microcode_check_cpu(cpu)) {
/* The application of microcode failed */ /* The application of microcode failed */
microcode_fini_cpu(cpu); microcode_ops->microcode_fini_cpu(cpu);
__mc_sysdev_add(sys_dev, 1); __mc_sysdev_add(sys_dev, 1);
break; break;
} }
@ -416,12 +415,17 @@ static struct notifier_block __refdata mc_cpu_notifier = {
.notifier_call = mc_cpu_callback, .notifier_call = mc_cpu_callback,
}; };
static int __init microcode_init (void) static int microcode_init(void *opaque, struct module *module)
{ {
struct microcode_ops *ops = (struct microcode_ops *)opaque;
int error; int error;
printk(KERN_INFO if (microcode_ops) {
"IA-32 Microcode Update Driver: v" MICROCODE_VERSION " <tigran@aivazian.fsnet.co.uk>\n"); printk(KERN_ERR "microcode: already loaded the other module\n");
return -EEXIST;
}
microcode_ops = ops;
error = microcode_dev_init(); error = microcode_dev_init();
if (error) if (error)
@ -443,8 +447,15 @@ static int __init microcode_init (void)
} }
register_hotcpu_notifier(&mc_cpu_notifier); register_hotcpu_notifier(&mc_cpu_notifier);
printk(KERN_INFO
"Microcode Update Driver: v" MICROCODE_VERSION
" <tigran@aivazian.fsnet.co.uk>"
" <peter.oruba@amd.com>\n");
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(microcode_init);
static void __exit microcode_exit (void) static void __exit microcode_exit (void)
{ {
@ -457,7 +468,10 @@ static void __exit microcode_exit (void)
put_online_cpus(); put_online_cpus();
platform_device_unregister(microcode_pdev); platform_device_unregister(microcode_pdev);
}
module_init(microcode_init) microcode_ops = NULL;
module_exit(microcode_exit)
printk(KERN_INFO
"Microcode Update Driver: v" MICROCODE_VERSION " removed.\n");
}
EXPORT_SYMBOL_GPL(microcode_exit);

View File

@ -127,7 +127,7 @@ extern struct mutex microcode_mutex;
extern struct ucode_cpu_info ucode_cpu_info[NR_CPUS]; extern struct ucode_cpu_info ucode_cpu_info[NR_CPUS];
void collect_cpu_info(int cpu_num) static void collect_cpu_info(int cpu_num)
{ {
struct cpuinfo_x86 *c = &cpu_data(cpu_num); struct cpuinfo_x86 *c = &cpu_data(cpu_num);
struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num; struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num;
@ -175,7 +175,7 @@ static inline int microcode_update_match(int cpu_num,
return 1; return 1;
} }
int microcode_sanity_check(void *mc) static int microcode_sanity_check(void *mc)
{ {
struct microcode_header_intel *mc_header = mc; struct microcode_header_intel *mc_header = mc;
struct extended_sigtable *ext_header = NULL; struct extended_sigtable *ext_header = NULL;
@ -259,7 +259,7 @@ int microcode_sanity_check(void *mc)
* return 1 - found update * return 1 - found update
* return < 0 - error * return < 0 - error
*/ */
int get_matching_microcode(void *mc, int cpu) static int get_matching_microcode(void *mc, int cpu)
{ {
struct ucode_cpu_info *uci = ucode_cpu_info + cpu; struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
struct microcode_header_intel *mc_header = mc; struct microcode_header_intel *mc_header = mc;
@ -288,7 +288,8 @@ int get_matching_microcode(void *mc, int cpu)
return 0; return 0;
find: find:
pr_debug("microcode: CPU%d found a matching microcode update with" pr_debug("microcode: CPU%d found a matching microcode update with"
" version 0x%x (current=0x%x)\n", cpu, mc_header->rev, uci->rev); " version 0x%x (current=0x%x)\n",
cpu, mc_header->rev, uci->rev);
new_mc = vmalloc(total_size); new_mc = vmalloc(total_size);
if (!new_mc) { if (!new_mc) {
printk(KERN_ERR "microcode: error! Can not allocate memory\n"); printk(KERN_ERR "microcode: error! Can not allocate memory\n");
@ -303,7 +304,7 @@ find:
return 1; return 1;
} }
void apply_microcode(int cpu) static void apply_microcode(int cpu)
{ {
unsigned long flags; unsigned long flags;
unsigned int val[2]; unsigned int val[2];
@ -347,7 +348,7 @@ void apply_microcode(int cpu)
extern void __user *user_buffer; /* user area microcode data buffer */ extern void __user *user_buffer; /* user area microcode data buffer */
extern unsigned int user_buffer_size; /* it's size */ extern unsigned int user_buffer_size; /* it's size */
long get_next_ucode(void **mc, long offset) static long get_next_ucode(void **mc, long offset)
{ {
struct microcode_header_intel mc_header; struct microcode_header_intel mc_header;
unsigned long total_size; unsigned long total_size;
@ -406,7 +407,7 @@ static long get_next_ucode_from_buffer(void **mc, const u8 *buf,
/* fake device for request_firmware */ /* fake device for request_firmware */
extern struct platform_device *microcode_pdev; extern struct platform_device *microcode_pdev;
int cpu_request_microcode(int cpu) static int cpu_request_microcode(int cpu)
{ {
char name[30]; char name[30];
struct cpuinfo_x86 *c = &cpu_data(cpu); struct cpuinfo_x86 *c = &cpu_data(cpu);
@ -455,7 +456,7 @@ int cpu_request_microcode(int cpu)
return error; return error;
} }
int apply_microcode_check_cpu(int cpu) static int apply_microcode_check_cpu(int cpu)
{ {
struct cpuinfo_x86 *c = &cpu_data(cpu); struct cpuinfo_x86 *c = &cpu_data(cpu);
struct ucode_cpu_info *uci = ucode_cpu_info + cpu; struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
@ -504,13 +505,42 @@ int apply_microcode_check_cpu(int cpu)
return err; return err;
} }
void microcode_fini_cpu(int cpu) static void microcode_fini_cpu(int cpu)
{ {
struct ucode_cpu_info *uci = ucode_cpu_info + cpu; struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
mutex_lock(&microcode_mutex); mutex_lock(&microcode_mutex);
uci->valid = 0; uci->valid = 0;
kfree(uci->mc.mc_intel); vfree(uci->mc.mc_intel);
uci->mc.mc_intel = NULL; uci->mc.mc_intel = NULL;
mutex_unlock(&microcode_mutex); mutex_unlock(&microcode_mutex);
} }
static struct microcode_ops microcode_intel_ops = {
.get_next_ucode = get_next_ucode,
.get_matching_microcode = get_matching_microcode,
.microcode_sanity_check = microcode_sanity_check,
.apply_microcode_check_cpu = apply_microcode_check_cpu,
.cpu_request_microcode = cpu_request_microcode,
.collect_cpu_info = collect_cpu_info,
.apply_microcode = apply_microcode,
.microcode_fini_cpu = microcode_fini_cpu,
};
static int __init microcode_intel_module_init(void)
{
struct cpuinfo_x86 *c = &cpu_data(get_cpu());
if (c->x86_vendor == X86_VENDOR_INTEL)
return microcode_init(&microcode_intel_ops, THIS_MODULE);
else
return -ENODEV;
}
static void __exit microcode_intel_module_exit(void)
{
microcode_exit();
}
module_init(microcode_intel_module_init)
module_exit(microcode_intel_module_exit)

View File

@ -1,3 +1,6 @@
extern int microcode_init(void *opaque, struct module *module);
extern void microcode_exit(void);
struct microcode_ops { struct microcode_ops {
long (*get_next_ucode)(void **mc, long offset); long (*get_next_ucode)(void **mc, long offset);
long (*microcode_get_next_ucode)(void **mc, long offset); long (*microcode_get_next_ucode)(void **mc, long offset);