Commit 8d86f390d9bb5b39f0a315838d1616de6363e1b9
Committed by
Ingo Molnar
1 parent
26bf7a48c3
Exists in
master
and in
7 other branches
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>
Showing 5 changed files with 112 additions and 50 deletions Side-by-side Diff
arch/x86/Kconfig
... | ... | @@ -782,7 +782,7 @@ |
782 | 782 | Say N otherwise. |
783 | 783 | |
784 | 784 | config MICROCODE |
785 | - tristate "/dev/cpu/microcode - Intel IA32 CPU microcode support" | |
785 | + tristate "/dev/cpu/microcode - microcode support" | |
786 | 786 | select FW_LOADER |
787 | 787 | ---help--- |
788 | 788 | If you say Y here, you will be able to update the microcode on |
789 | 789 | |
... | ... | @@ -791,14 +791,29 @@ |
791 | 791 | actual microcode binary data itself which is not shipped with the |
792 | 792 | Linux kernel. |
793 | 793 | |
794 | - For latest news and information on obtaining all the required | |
795 | - ingredients for this driver, check: | |
796 | - <http://www.urbanmyth.org/microcode/>. | |
794 | + This option selects the general module only, you need to select | |
795 | + at least one vendor specific module as well. | |
797 | 796 | |
798 | 797 | To compile this driver as a module, choose M here: the |
799 | 798 | module will be called microcode. |
800 | 799 | |
801 | -config MICROCODE_OLD_INTERFACE | |
800 | +config 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 | 817 | def_bool y |
803 | 818 | depends on MICROCODE |
804 | 819 |
arch/x86/kernel/Makefile
... | ... | @@ -51,8 +51,8 @@ |
51 | 51 | obj-$(CONFIG_MCA) += mca_32.o |
52 | 52 | obj-$(CONFIG_X86_MSR) += msr.o |
53 | 53 | obj-$(CONFIG_X86_CPUID) += cpuid.o |
54 | -obj-$(CONFIG_MICROCODE) += ucode.o | |
55 | -ucode-objs := microcode.o microcode_intel.o | |
54 | +obj-$(CONFIG_MICROCODE) += microcode.o | |
55 | +obj-$(CONFIG_MICROCODE_INTEL) += microcode_intel.o | |
56 | 56 | obj-$(CONFIG_PCI) += early-quirks.o |
57 | 57 | apm-y := apm_32.o |
58 | 58 | obj-$(CONFIG_APM) += apm.o |
arch/x86/kernel/microcode.c
... | ... | @@ -99,25 +99,22 @@ |
99 | 99 | MODULE_AUTHOR("Tigran Aivazian <tigran@aivazian.fsnet.co.uk>"); |
100 | 100 | MODULE_LICENSE("GPL"); |
101 | 101 | |
102 | -#define MICROCODE_VERSION "1.14a" | |
102 | +#define MICROCODE_VERSION "2.00" | |
103 | 103 | |
104 | +struct microcode_ops *microcode_ops; | |
105 | + | |
104 | 106 | /* no concurrent ->write()s are allowed on /dev/cpu/microcode */ |
105 | -DEFINE_MUTEX(microcode_mutex); | |
107 | +static DEFINE_MUTEX(microcode_mutex); | |
108 | +EXPORT_SYMBOL_GPL(microcode_mutex); | |
106 | 109 | |
107 | -struct ucode_cpu_info ucode_cpu_info[NR_CPUS]; | |
110 | +static struct ucode_cpu_info ucode_cpu_info[NR_CPUS]; | |
111 | +EXPORT_SYMBOL_GPL(ucode_cpu_info); | |
108 | 112 | |
109 | -extern long get_next_ucode(void **mc, long offset); | |
110 | -extern int microcode_sanity_check(void *mc); | |
111 | -extern int get_matching_microcode(void *mc, int cpu); | |
112 | -extern void collect_cpu_info(int cpu_num); | |
113 | -extern int cpu_request_microcode(int cpu); | |
114 | -extern void microcode_fini_cpu(int cpu); | |
115 | -extern void apply_microcode(int cpu); | |
116 | -extern int apply_microcode_check_cpu(int cpu); | |
117 | - | |
118 | 113 | #ifdef CONFIG_MICROCODE_OLD_INTERFACE |
119 | -void __user *user_buffer; /* user area microcode data buffer */ | |
120 | -unsigned int user_buffer_size; /* it's size */ | |
114 | +static void __user *user_buffer; /* user area microcode data buffer */ | |
115 | +EXPORT_SYMBOL_GPL(user_buffer); | |
116 | +static unsigned int user_buffer_size; /* it's size */ | |
117 | +EXPORT_SYMBOL_GPL(user_buffer_size); | |
121 | 118 | |
122 | 119 | static int do_microcode_update (void) |
123 | 120 | { |
... | ... | @@ -130,8 +127,8 @@ |
130 | 127 | |
131 | 128 | old = current->cpus_allowed; |
132 | 129 | |
133 | - while ((cursor = get_next_ucode(&new_mc, cursor)) > 0) { | |
134 | - error = microcode_sanity_check(new_mc); | |
130 | + while ((cursor = microcode_ops->get_next_ucode(&new_mc, cursor)) > 0) { | |
131 | + error = microcode_ops->microcode_sanity_check(new_mc); | |
135 | 132 | if (error) |
136 | 133 | goto out; |
137 | 134 | /* |
138 | 135 | |
... | ... | @@ -145,11 +142,12 @@ |
145 | 142 | continue; |
146 | 143 | cpumask_of_cpu_ptr_next(newmask, cpu); |
147 | 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 | 147 | if (error < 0) |
150 | 148 | goto out; |
151 | 149 | if (error == 1) |
152 | - apply_microcode(cpu); | |
150 | + microcode_ops->apply_microcode(cpu); | |
153 | 151 | } |
154 | 152 | vfree(new_mc); |
155 | 153 | } |
... | ... | @@ -232,7 +230,8 @@ |
232 | 230 | #endif |
233 | 231 | |
234 | 232 | /* fake device for request_firmware */ |
235 | -struct platform_device *microcode_pdev; | |
233 | +static struct platform_device *microcode_pdev; | |
234 | +EXPORT_SYMBOL_GPL(microcode_pdev); | |
236 | 235 | |
237 | 236 | static void microcode_init_cpu(int cpu, int resume) |
238 | 237 | { |
239 | 238 | |
... | ... | @@ -244,9 +243,9 @@ |
244 | 243 | |
245 | 244 | set_cpus_allowed_ptr(current, newmask); |
246 | 245 | mutex_lock(µcode_mutex); |
247 | - collect_cpu_info(cpu); | |
246 | + microcode_ops->collect_cpu_info(cpu); | |
248 | 247 | if (uci->valid && system_state == SYSTEM_RUNNING && !resume) |
249 | - cpu_request_microcode(cpu); | |
248 | + microcode_ops->cpu_request_microcode(cpu); | |
250 | 249 | mutex_unlock(µcode_mutex); |
251 | 250 | set_cpus_allowed_ptr(current, &old); |
252 | 251 | } |
... | ... | @@ -274,7 +273,7 @@ |
274 | 273 | |
275 | 274 | mutex_lock(µcode_mutex); |
276 | 275 | if (uci->valid) |
277 | - err = cpu_request_microcode(cpu); | |
276 | + err = microcode_ops->cpu_request_microcode(cpu); | |
278 | 277 | mutex_unlock(µcode_mutex); |
279 | 278 | put_online_cpus(); |
280 | 279 | set_cpus_allowed_ptr(current, &old); |
... | ... | @@ -349,7 +348,7 @@ |
349 | 348 | return 0; |
350 | 349 | |
351 | 350 | pr_debug("microcode: CPU%d removed\n", cpu); |
352 | - microcode_fini_cpu(cpu); | |
351 | + microcode_ops->microcode_fini_cpu(cpu); | |
353 | 352 | sysfs_remove_group(&sys_dev->kobj, &mc_attr_group); |
354 | 353 | return 0; |
355 | 354 | } |
... | ... | @@ -362,7 +361,7 @@ |
362 | 361 | return 0; |
363 | 362 | pr_debug("microcode: CPU%d resumed\n", cpu); |
364 | 363 | /* only CPU 0 will apply ucode here */ |
365 | - apply_microcode(0); | |
364 | + microcode_ops->apply_microcode(0); | |
366 | 365 | return 0; |
367 | 366 | } |
368 | 367 | |
... | ... | @@ -382,7 +381,7 @@ |
382 | 381 | switch (action) { |
383 | 382 | case CPU_UP_CANCELED_FROZEN: |
384 | 383 | /* The CPU refused to come up during a system resume */ |
385 | - microcode_fini_cpu(cpu); | |
384 | + microcode_ops->microcode_fini_cpu(cpu); | |
386 | 385 | break; |
387 | 386 | case CPU_ONLINE: |
388 | 387 | case CPU_DOWN_FAILED: |
389 | 388 | |
... | ... | @@ -390,9 +389,9 @@ |
390 | 389 | break; |
391 | 390 | case CPU_ONLINE_FROZEN: |
392 | 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 | 393 | /* The application of microcode failed */ |
395 | - microcode_fini_cpu(cpu); | |
394 | + microcode_ops->microcode_fini_cpu(cpu); | |
396 | 395 | __mc_sysdev_add(sys_dev, 1); |
397 | 396 | break; |
398 | 397 | } |
399 | 398 | |
400 | 399 | |
401 | 400 | |
... | ... | @@ -416,13 +415,18 @@ |
416 | 415 | .notifier_call = mc_cpu_callback, |
417 | 416 | }; |
418 | 417 | |
419 | -static int __init microcode_init (void) | |
418 | +static int microcode_init(void *opaque, struct module *module) | |
420 | 419 | { |
420 | + struct microcode_ops *ops = (struct microcode_ops *)opaque; | |
421 | 421 | int error; |
422 | 422 | |
423 | - printk(KERN_INFO | |
424 | - "IA-32 Microcode Update Driver: v" MICROCODE_VERSION " <tigran@aivazian.fsnet.co.uk>\n"); | |
423 | + if (microcode_ops) { | |
424 | + printk(KERN_ERR "microcode: already loaded the other module\n"); | |
425 | + return -EEXIST; | |
426 | + } | |
425 | 427 | |
428 | + microcode_ops = ops; | |
429 | + | |
426 | 430 | error = microcode_dev_init(); |
427 | 431 | if (error) |
428 | 432 | return error; |
429 | 433 | |
... | ... | @@ -443,8 +447,15 @@ |
443 | 447 | } |
444 | 448 | |
445 | 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 | 456 | return 0; |
447 | 457 | } |
458 | +EXPORT_SYMBOL_GPL(microcode_init); | |
448 | 459 | |
449 | 460 | static void __exit microcode_exit (void) |
450 | 461 | { |
451 | 462 | |
... | ... | @@ -457,8 +468,11 @@ |
457 | 468 | put_online_cpus(); |
458 | 469 | |
459 | 470 | platform_device_unregister(microcode_pdev); |
460 | -} | |
461 | 471 | |
462 | -module_init(microcode_init) | |
463 | -module_exit(microcode_exit) | |
472 | + microcode_ops = NULL; | |
473 | + | |
474 | + printk(KERN_INFO | |
475 | + "Microcode Update Driver: v" MICROCODE_VERSION " removed.\n"); | |
476 | +} | |
477 | +EXPORT_SYMBOL_GPL(microcode_exit); |
arch/x86/kernel/microcode_intel.c
... | ... | @@ -127,7 +127,7 @@ |
127 | 127 | |
128 | 128 | extern struct ucode_cpu_info ucode_cpu_info[NR_CPUS]; |
129 | 129 | |
130 | -void collect_cpu_info(int cpu_num) | |
130 | +static void collect_cpu_info(int cpu_num) | |
131 | 131 | { |
132 | 132 | struct cpuinfo_x86 *c = &cpu_data(cpu_num); |
133 | 133 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num; |
... | ... | @@ -175,7 +175,7 @@ |
175 | 175 | return 1; |
176 | 176 | } |
177 | 177 | |
178 | -int microcode_sanity_check(void *mc) | |
178 | +static int microcode_sanity_check(void *mc) | |
179 | 179 | { |
180 | 180 | struct microcode_header_intel *mc_header = mc; |
181 | 181 | struct extended_sigtable *ext_header = NULL; |
... | ... | @@ -259,7 +259,7 @@ |
259 | 259 | * return 1 - found update |
260 | 260 | * return < 0 - error |
261 | 261 | */ |
262 | -int get_matching_microcode(void *mc, int cpu) | |
262 | +static int get_matching_microcode(void *mc, int cpu) | |
263 | 263 | { |
264 | 264 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu; |
265 | 265 | struct microcode_header_intel *mc_header = mc; |
... | ... | @@ -288,7 +288,8 @@ |
288 | 288 | return 0; |
289 | 289 | find: |
290 | 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 | 293 | new_mc = vmalloc(total_size); |
293 | 294 | if (!new_mc) { |
294 | 295 | printk(KERN_ERR "microcode: error! Can not allocate memory\n"); |
... | ... | @@ -303,7 +304,7 @@ |
303 | 304 | return 1; |
304 | 305 | } |
305 | 306 | |
306 | -void apply_microcode(int cpu) | |
307 | +static void apply_microcode(int cpu) | |
307 | 308 | { |
308 | 309 | unsigned long flags; |
309 | 310 | unsigned int val[2]; |
... | ... | @@ -347,7 +348,7 @@ |
347 | 348 | extern void __user *user_buffer; /* user area microcode data buffer */ |
348 | 349 | extern unsigned int user_buffer_size; /* it's size */ |
349 | 350 | |
350 | -long get_next_ucode(void **mc, long offset) | |
351 | +static long get_next_ucode(void **mc, long offset) | |
351 | 352 | { |
352 | 353 | struct microcode_header_intel mc_header; |
353 | 354 | unsigned long total_size; |
... | ... | @@ -406,7 +407,7 @@ |
406 | 407 | /* fake device for request_firmware */ |
407 | 408 | extern struct platform_device *microcode_pdev; |
408 | 409 | |
409 | -int cpu_request_microcode(int cpu) | |
410 | +static int cpu_request_microcode(int cpu) | |
410 | 411 | { |
411 | 412 | char name[30]; |
412 | 413 | struct cpuinfo_x86 *c = &cpu_data(cpu); |
... | ... | @@ -455,7 +456,7 @@ |
455 | 456 | return error; |
456 | 457 | } |
457 | 458 | |
458 | -int apply_microcode_check_cpu(int cpu) | |
459 | +static int apply_microcode_check_cpu(int cpu) | |
459 | 460 | { |
460 | 461 | struct cpuinfo_x86 *c = &cpu_data(cpu); |
461 | 462 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu; |
462 | 463 | |
463 | 464 | |
... | ... | @@ -504,14 +505,43 @@ |
504 | 505 | return err; |
505 | 506 | } |
506 | 507 | |
507 | -void microcode_fini_cpu(int cpu) | |
508 | +static void microcode_fini_cpu(int cpu) | |
508 | 509 | { |
509 | 510 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu; |
510 | 511 | |
511 | 512 | mutex_lock(µcode_mutex); |
512 | 513 | uci->valid = 0; |
513 | - kfree(uci->mc.mc_intel); | |
514 | + vfree(uci->mc.mc_intel); | |
514 | 515 | uci->mc.mc_intel = NULL; |
515 | 516 | mutex_unlock(µcode_mutex); |
516 | 517 | } |
518 | + | |
519 | +static 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 | + | |
530 | +static 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(µcode_intel_ops, THIS_MODULE); | |
536 | + else | |
537 | + return -ENODEV; | |
538 | +} | |
539 | + | |
540 | +static void __exit microcode_intel_module_exit(void) | |
541 | +{ | |
542 | + microcode_exit(); | |
543 | +} | |
544 | + | |
545 | +module_init(microcode_intel_module_init) | |
546 | +module_exit(microcode_intel_module_exit) |
include/asm-x86/microcode.h