aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/Kconfig25
-rw-r--r--arch/x86/kernel/Makefile4
-rw-r--r--arch/x86/kernel/microcode.c80
-rw-r--r--arch/x86/kernel/microcode_intel.c50
-rw-r--r--include/asm-x86/microcode.h3
5 files changed, 112 insertions, 50 deletions
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index b6fa2877b173..6b0b885cf47a 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -782,7 +782,7 @@ config X86_REBOOTFIXUPS
782 Say N otherwise. 782 Say N otherwise.
783 783
784config MICROCODE 784config MICROCODE
785 tristate "/dev/cpu/microcode - Intel IA32 CPU microcode support" 785 tristate "/dev/cpu/microcode - microcode support"
786 select FW_LOADER 786 select FW_LOADER
787 ---help--- 787 ---help---
788 If you say Y here, you will be able to update the microcode on 788 If you say Y here, you will be able to update the microcode on
@@ -791,14 +791,29 @@ config MICROCODE
791 actual microcode binary data itself which is not shipped with the 791 actual microcode binary data itself which is not shipped with the
792 Linux kernel. 792 Linux kernel.
793 793
794 For latest news and information on obtaining all the required 794 This option selects the general module only, you need to select
795 ingredients for this driver, check: 795 at least one vendor specific module as well.
796 <http://www.urbanmyth.org/microcode/>.
797 796
798 To compile this driver as a module, choose M here: the 797 To compile this driver as a module, choose M here: the
799 module will be called microcode. 798 module will be called microcode.
800 799
801config MICROCODE_OLD_INTERFACE 800config MICROCODE_INTEL
801 tristate "Intel microcode patch loading support"
802 depends on MICROCODE
803 default MICROCODE
804 select FW_LOADER
805 --help---
806 This options enables microcode patch loading support for Intel
807 processors.
808
809 For latest news and information on obtaining all the required
810 Intel ingredients for this driver, check:
811 <http://www.urbanmyth.org/microcode/>.
812
813 This driver is only available as a module: the module
814 will be called microcode_intel.
815
816 config MICROCODE_OLD_INTERFACE
802 def_bool y 817 def_bool y
803 depends on MICROCODE 818 depends on MICROCODE
804 819
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
index abb32aed7f4b..f2f9f6da8c18 100644
--- a/arch/x86/kernel/Makefile
+++ b/arch/x86/kernel/Makefile
@@ -51,8 +51,8 @@ obj-$(CONFIG_X86_BIOS_REBOOT) += reboot.o
51obj-$(CONFIG_MCA) += mca_32.o 51obj-$(CONFIG_MCA) += mca_32.o
52obj-$(CONFIG_X86_MSR) += msr.o 52obj-$(CONFIG_X86_MSR) += msr.o
53obj-$(CONFIG_X86_CPUID) += cpuid.o 53obj-$(CONFIG_X86_CPUID) += cpuid.o
54obj-$(CONFIG_MICROCODE) += ucode.o 54obj-$(CONFIG_MICROCODE) += microcode.o
55ucode-objs := microcode.o microcode_intel.o 55obj-$(CONFIG_MICROCODE_INTEL) += microcode_intel.o
56obj-$(CONFIG_PCI) += early-quirks.o 56obj-$(CONFIG_PCI) += early-quirks.o
57apm-y := apm_32.o 57apm-y := apm_32.o
58obj-$(CONFIG_APM) += apm.o 58obj-$(CONFIG_APM) += apm.o
diff --git a/arch/x86/kernel/microcode.c b/arch/x86/kernel/microcode.c
index c1047d7f7ede..1e42e79ca694 100644
--- a/arch/x86/kernel/microcode.c
+++ b/arch/x86/kernel/microcode.c
@@ -99,25 +99,22 @@ MODULE_DESCRIPTION("Microcode Update Driver");
99MODULE_AUTHOR("Tigran Aivazian <tigran@aivazian.fsnet.co.uk>"); 99MODULE_AUTHOR("Tigran Aivazian <tigran@aivazian.fsnet.co.uk>");
100MODULE_LICENSE("GPL"); 100MODULE_LICENSE("GPL");
101 101
102#define MICROCODE_VERSION "1.14a" 102#define MICROCODE_VERSION "2.00"
103 103
104/* no concurrent ->write()s are allowed on /dev/cpu/microcode */ 104struct microcode_ops *microcode_ops;
105DEFINE_MUTEX(microcode_mutex);
106 105
107struct ucode_cpu_info ucode_cpu_info[NR_CPUS]; 106/* no concurrent ->write()s are allowed on /dev/cpu/microcode */
107static DEFINE_MUTEX(microcode_mutex);
108EXPORT_SYMBOL_GPL(microcode_mutex);
108 109
109extern long get_next_ucode(void **mc, long offset); 110static struct ucode_cpu_info ucode_cpu_info[NR_CPUS];
110extern int microcode_sanity_check(void *mc); 111EXPORT_SYMBOL_GPL(ucode_cpu_info);
111extern int get_matching_microcode(void *mc, int cpu);
112extern void collect_cpu_info(int cpu_num);
113extern int cpu_request_microcode(int cpu);
114extern void microcode_fini_cpu(int cpu);
115extern void apply_microcode(int cpu);
116extern int apply_microcode_check_cpu(int cpu);
117 112
118#ifdef CONFIG_MICROCODE_OLD_INTERFACE 113#ifdef CONFIG_MICROCODE_OLD_INTERFACE
119void __user *user_buffer; /* user area microcode data buffer */ 114static void __user *user_buffer; /* user area microcode data buffer */
120unsigned int user_buffer_size; /* it's size */ 115EXPORT_SYMBOL_GPL(user_buffer);
116static unsigned int user_buffer_size; /* it's size */
117EXPORT_SYMBOL_GPL(user_buffer_size);
121 118
122static int do_microcode_update (void) 119static int do_microcode_update (void)
123{ 120{
@@ -130,8 +127,8 @@ static int do_microcode_update (void)
130 127
131 old = current->cpus_allowed; 128 old = current->cpus_allowed;
132 129
133 while ((cursor = get_next_ucode(&new_mc, cursor)) > 0) { 130 while ((cursor = microcode_ops->get_next_ucode(&new_mc, cursor)) > 0) {
134 error = microcode_sanity_check(new_mc); 131 error = microcode_ops->microcode_sanity_check(new_mc);
135 if (error) 132 if (error)
136 goto out; 133 goto out;
137 /* 134 /*
@@ -145,11 +142,12 @@ static int do_microcode_update (void)
145 continue; 142 continue;
146 cpumask_of_cpu_ptr_next(newmask, cpu); 143 cpumask_of_cpu_ptr_next(newmask, cpu);
147 set_cpus_allowed_ptr(current, newmask); 144 set_cpus_allowed_ptr(current, newmask);
148 error = get_maching_microcode(new_mc, cpu); 145 error = microcode_ops->get_matching_microcode(new_mc,
146 cpu);
149 if (error < 0) 147 if (error < 0)
150 goto out; 148 goto out;
151 if (error == 1) 149 if (error == 1)
152 apply_microcode(cpu); 150 microcode_ops->apply_microcode(cpu);
153 } 151 }
154 vfree(new_mc); 152 vfree(new_mc);
155 } 153 }
@@ -232,7 +230,8 @@ MODULE_ALIAS_MISCDEV(MICROCODE_MINOR);
232#endif 230#endif
233 231
234/* fake device for request_firmware */ 232/* fake device for request_firmware */
235struct platform_device *microcode_pdev; 233static struct platform_device *microcode_pdev;
234EXPORT_SYMBOL_GPL(microcode_pdev);
236 235
237static void microcode_init_cpu(int cpu, int resume) 236static void microcode_init_cpu(int cpu, int resume)
238{ 237{
@@ -244,9 +243,9 @@ static void microcode_init_cpu(int cpu, int resume)
244 243
245 set_cpus_allowed_ptr(current, newmask); 244 set_cpus_allowed_ptr(current, newmask);
246 mutex_lock(&microcode_mutex); 245 mutex_lock(&microcode_mutex);
247 collect_cpu_info(cpu); 246 microcode_ops->collect_cpu_info(cpu);
248 if (uci->valid && system_state == SYSTEM_RUNNING && !resume) 247 if (uci->valid && system_state == SYSTEM_RUNNING && !resume)
249 cpu_request_microcode(cpu); 248 microcode_ops->cpu_request_microcode(cpu);
250 mutex_unlock(&microcode_mutex); 249 mutex_unlock(&microcode_mutex);
251 set_cpus_allowed_ptr(current, &old); 250 set_cpus_allowed_ptr(current, &old);
252} 251}
@@ -274,7 +273,7 @@ static ssize_t reload_store(struct sys_device *dev,
274 273
275 mutex_lock(&microcode_mutex); 274 mutex_lock(&microcode_mutex);
276 if (uci->valid) 275 if (uci->valid)
277 err = cpu_request_microcode(cpu); 276 err = microcode_ops->cpu_request_microcode(cpu);
278 mutex_unlock(&microcode_mutex); 277 mutex_unlock(&microcode_mutex);
279 put_online_cpus(); 278 put_online_cpus();
280 set_cpus_allowed_ptr(current, &old); 279 set_cpus_allowed_ptr(current, &old);
@@ -349,7 +348,7 @@ static int mc_sysdev_remove(struct sys_device *sys_dev)
349 return 0; 348 return 0;
350 349
351 pr_debug("microcode: CPU%d removed\n", cpu); 350 pr_debug("microcode: CPU%d removed\n", cpu);
352 microcode_fini_cpu(cpu); 351 microcode_ops->microcode_fini_cpu(cpu);
353 sysfs_remove_group(&sys_dev->kobj, &mc_attr_group); 352 sysfs_remove_group(&sys_dev->kobj, &mc_attr_group);
354 return 0; 353 return 0;
355} 354}
@@ -362,7 +361,7 @@ static int mc_sysdev_resume(struct sys_device *dev)
362 return 0; 361 return 0;
363 pr_debug("microcode: CPU%d resumed\n", cpu); 362 pr_debug("microcode: CPU%d resumed\n", cpu);
364 /* only CPU 0 will apply ucode here */ 363 /* only CPU 0 will apply ucode here */
365 apply_microcode(0); 364 microcode_ops->apply_microcode(0);
366 return 0; 365 return 0;
367} 366}
368 367
@@ -382,7 +381,7 @@ mc_cpu_callback(struct notifier_block *nb, unsigned long action, void *hcpu)
382 switch (action) { 381 switch (action) {
383 case CPU_UP_CANCELED_FROZEN: 382 case CPU_UP_CANCELED_FROZEN:
384 /* The CPU refused to come up during a system resume */ 383 /* The CPU refused to come up during a system resume */
385 microcode_fini_cpu(cpu); 384 microcode_ops->microcode_fini_cpu(cpu);
386 break; 385 break;
387 case CPU_ONLINE: 386 case CPU_ONLINE:
388 case CPU_DOWN_FAILED: 387 case CPU_DOWN_FAILED:
@@ -390,9 +389,9 @@ mc_cpu_callback(struct notifier_block *nb, unsigned long action, void *hcpu)
390 break; 389 break;
391 case CPU_ONLINE_FROZEN: 390 case CPU_ONLINE_FROZEN:
392 /* System-wide resume is in progress, try to apply microcode */ 391 /* System-wide resume is in progress, try to apply microcode */
393 if (apply_microcode_check_cpu(cpu)) { 392 if (microcode_ops->apply_microcode_check_cpu(cpu)) {
394 /* The application of microcode failed */ 393 /* The application of microcode failed */
395 microcode_fini_cpu(cpu); 394 microcode_ops->microcode_fini_cpu(cpu);
396 __mc_sysdev_add(sys_dev, 1); 395 __mc_sysdev_add(sys_dev, 1);
397 break; 396 break;
398 } 397 }
@@ -416,12 +415,17 @@ static struct notifier_block __refdata mc_cpu_notifier = {
416 .notifier_call = mc_cpu_callback, 415 .notifier_call = mc_cpu_callback,
417}; 416};
418 417
419static int __init microcode_init (void) 418static int microcode_init(void *opaque, struct module *module)
420{ 419{
420 struct microcode_ops *ops = (struct microcode_ops *)opaque;
421 int error; 421 int error;
422 422
423 printk(KERN_INFO 423 if (microcode_ops) {
424 "IA-32 Microcode Update Driver: v" MICROCODE_VERSION " <tigran@aivazian.fsnet.co.uk>\n"); 424 printk(KERN_ERR "microcode: already loaded the other module\n");
425 return -EEXIST;
426 }
427
428 microcode_ops = ops;
425 429
426 error = microcode_dev_init(); 430 error = microcode_dev_init();
427 if (error) 431 if (error)
@@ -443,8 +447,15 @@ static int __init microcode_init (void)
443 } 447 }
444 448
445 register_hotcpu_notifier(&mc_cpu_notifier); 449 register_hotcpu_notifier(&mc_cpu_notifier);
450
451 printk(KERN_INFO
452 "Microcode Update Driver: v" MICROCODE_VERSION
453 " <tigran@aivazian.fsnet.co.uk>"
454 " <peter.oruba@amd.com>\n");
455
446 return 0; 456 return 0;
447} 457}
458EXPORT_SYMBOL_GPL(microcode_init);
448 459
449static void __exit microcode_exit (void) 460static void __exit microcode_exit (void)
450{ 461{
@@ -457,7 +468,10 @@ static void __exit microcode_exit (void)
457 put_online_cpus(); 468 put_online_cpus();
458 469
459 platform_device_unregister(microcode_pdev); 470 platform_device_unregister(microcode_pdev);
460}
461 471
462module_init(microcode_init) 472 microcode_ops = NULL;
463module_exit(microcode_exit) 473
474 printk(KERN_INFO
475 "Microcode Update Driver: v" MICROCODE_VERSION " removed.\n");
476}
477EXPORT_SYMBOL_GPL(microcode_exit);
diff --git a/arch/x86/kernel/microcode_intel.c b/arch/x86/kernel/microcode_intel.c
index ca9861bf067e..831db5363dba 100644
--- a/arch/x86/kernel/microcode_intel.c
+++ b/arch/x86/kernel/microcode_intel.c
@@ -127,7 +127,7 @@ extern struct mutex microcode_mutex;
127 127
128extern struct ucode_cpu_info ucode_cpu_info[NR_CPUS]; 128extern struct ucode_cpu_info ucode_cpu_info[NR_CPUS];
129 129
130void collect_cpu_info(int cpu_num) 130static void collect_cpu_info(int cpu_num)
131{ 131{
132 struct cpuinfo_x86 *c = &cpu_data(cpu_num); 132 struct cpuinfo_x86 *c = &cpu_data(cpu_num);
133 struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num; 133 struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num;
@@ -175,7 +175,7 @@ static inline int microcode_update_match(int cpu_num,
175 return 1; 175 return 1;
176} 176}
177 177
178int microcode_sanity_check(void *mc) 178static int microcode_sanity_check(void *mc)
179{ 179{
180 struct microcode_header_intel *mc_header = mc; 180 struct microcode_header_intel *mc_header = mc;
181 struct extended_sigtable *ext_header = NULL; 181 struct extended_sigtable *ext_header = NULL;
@@ -259,7 +259,7 @@ int microcode_sanity_check(void *mc)
259 * return 1 - found update 259 * return 1 - found update
260 * return < 0 - error 260 * return < 0 - error
261 */ 261 */
262int get_matching_microcode(void *mc, int cpu) 262static int get_matching_microcode(void *mc, int cpu)
263{ 263{
264 struct ucode_cpu_info *uci = ucode_cpu_info + cpu; 264 struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
265 struct microcode_header_intel *mc_header = mc; 265 struct microcode_header_intel *mc_header = mc;
@@ -288,7 +288,8 @@ int get_matching_microcode(void *mc, int cpu)
288 return 0; 288 return 0;
289find: 289find:
290 pr_debug("microcode: CPU%d found a matching microcode update with" 290 pr_debug("microcode: CPU%d found a matching microcode update with"
291 " version 0x%x (current=0x%x)\n", cpu, mc_header->rev, uci->rev); 291 " version 0x%x (current=0x%x)\n",
292 cpu, mc_header->rev, uci->rev);
292 new_mc = vmalloc(total_size); 293 new_mc = vmalloc(total_size);
293 if (!new_mc) { 294 if (!new_mc) {
294 printk(KERN_ERR "microcode: error! Can not allocate memory\n"); 295 printk(KERN_ERR "microcode: error! Can not allocate memory\n");
@@ -303,7 +304,7 @@ find:
303 return 1; 304 return 1;
304} 305}
305 306
306void apply_microcode(int cpu) 307static void apply_microcode(int cpu)
307{ 308{
308 unsigned long flags; 309 unsigned long flags;
309 unsigned int val[2]; 310 unsigned int val[2];
@@ -347,7 +348,7 @@ void apply_microcode(int cpu)
347extern void __user *user_buffer; /* user area microcode data buffer */ 348extern void __user *user_buffer; /* user area microcode data buffer */
348extern unsigned int user_buffer_size; /* it's size */ 349extern unsigned int user_buffer_size; /* it's size */
349 350
350long get_next_ucode(void **mc, long offset) 351static long get_next_ucode(void **mc, long offset)
351{ 352{
352 struct microcode_header_intel mc_header; 353 struct microcode_header_intel mc_header;
353 unsigned long total_size; 354 unsigned long total_size;
@@ -406,7 +407,7 @@ static long get_next_ucode_from_buffer(void **mc, const u8 *buf,
406/* fake device for request_firmware */ 407/* fake device for request_firmware */
407extern struct platform_device *microcode_pdev; 408extern struct platform_device *microcode_pdev;
408 409
409int cpu_request_microcode(int cpu) 410static int cpu_request_microcode(int cpu)
410{ 411{
411 char name[30]; 412 char name[30];
412 struct cpuinfo_x86 *c = &cpu_data(cpu); 413 struct cpuinfo_x86 *c = &cpu_data(cpu);
@@ -455,7 +456,7 @@ int cpu_request_microcode(int cpu)
455 return error; 456 return error;
456} 457}
457 458
458int apply_microcode_check_cpu(int cpu) 459static int apply_microcode_check_cpu(int cpu)
459{ 460{
460 struct cpuinfo_x86 *c = &cpu_data(cpu); 461 struct cpuinfo_x86 *c = &cpu_data(cpu);
461 struct ucode_cpu_info *uci = ucode_cpu_info + cpu; 462 struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
@@ -504,13 +505,42 @@ int apply_microcode_check_cpu(int cpu)
504 return err; 505 return err;
505} 506}
506 507
507void microcode_fini_cpu(int cpu) 508static void microcode_fini_cpu(int cpu)
508{ 509{
509 struct ucode_cpu_info *uci = ucode_cpu_info + cpu; 510 struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
510 511
511 mutex_lock(&microcode_mutex); 512 mutex_lock(&microcode_mutex);
512 uci->valid = 0; 513 uci->valid = 0;
513 kfree(uci->mc.mc_intel); 514 vfree(uci->mc.mc_intel);
514 uci->mc.mc_intel = NULL; 515 uci->mc.mc_intel = NULL;
515 mutex_unlock(&microcode_mutex); 516 mutex_unlock(&microcode_mutex);
516} 517}
518
519static struct microcode_ops microcode_intel_ops = {
520 .get_next_ucode = get_next_ucode,
521 .get_matching_microcode = get_matching_microcode,
522 .microcode_sanity_check = microcode_sanity_check,
523 .apply_microcode_check_cpu = apply_microcode_check_cpu,
524 .cpu_request_microcode = cpu_request_microcode,
525 .collect_cpu_info = collect_cpu_info,
526 .apply_microcode = apply_microcode,
527 .microcode_fini_cpu = microcode_fini_cpu,
528};
529
530static int __init microcode_intel_module_init(void)
531{
532 struct cpuinfo_x86 *c = &cpu_data(get_cpu());
533
534 if (c->x86_vendor == X86_VENDOR_INTEL)
535 return microcode_init(&microcode_intel_ops, THIS_MODULE);
536 else
537 return -ENODEV;
538}
539
540static void __exit microcode_intel_module_exit(void)
541{
542 microcode_exit();
543}
544
545module_init(microcode_intel_module_init)
546module_exit(microcode_intel_module_exit)
diff --git a/include/asm-x86/microcode.h b/include/asm-x86/microcode.h
index 9231c876e374..18b2aeec2adf 100644
--- a/include/asm-x86/microcode.h
+++ b/include/asm-x86/microcode.h
@@ -1,3 +1,6 @@
1extern int microcode_init(void *opaque, struct module *module);
2extern void microcode_exit(void);
3
1struct microcode_ops { 4struct microcode_ops {
2 long (*get_next_ucode)(void **mc, long offset); 5 long (*get_next_ucode)(void **mc, long offset);
3 long (*microcode_get_next_ucode)(void **mc, long offset); 6 long (*microcode_get_next_ucode)(void **mc, long offset);