diff options
Diffstat (limited to 'arch/x86/kernel/microcode_intel.c')
| -rw-r--r-- | arch/x86/kernel/microcode_intel.c | 79 |
1 files changed, 49 insertions, 30 deletions
diff --git a/arch/x86/kernel/microcode_intel.c b/arch/x86/kernel/microcode_intel.c index 48ed3cef58c1..622dc4a21784 100644 --- a/arch/x86/kernel/microcode_intel.c +++ b/arch/x86/kernel/microcode_intel.c | |||
| @@ -97,6 +97,38 @@ MODULE_DESCRIPTION("Microcode Update Driver"); | |||
| 97 | MODULE_AUTHOR("Tigran Aivazian <tigran@aivazian.fsnet.co.uk>"); | 97 | MODULE_AUTHOR("Tigran Aivazian <tigran@aivazian.fsnet.co.uk>"); |
| 98 | MODULE_LICENSE("GPL"); | 98 | MODULE_LICENSE("GPL"); |
| 99 | 99 | ||
| 100 | struct microcode_header_intel { | ||
| 101 | unsigned int hdrver; | ||
| 102 | unsigned int rev; | ||
| 103 | unsigned int date; | ||
| 104 | unsigned int sig; | ||
| 105 | unsigned int cksum; | ||
| 106 | unsigned int ldrver; | ||
| 107 | unsigned int pf; | ||
| 108 | unsigned int datasize; | ||
| 109 | unsigned int totalsize; | ||
| 110 | unsigned int reserved[3]; | ||
| 111 | }; | ||
| 112 | |||
| 113 | struct microcode_intel { | ||
| 114 | struct microcode_header_intel hdr; | ||
| 115 | unsigned int bits[0]; | ||
| 116 | }; | ||
| 117 | |||
| 118 | /* microcode format is extended from prescott processors */ | ||
| 119 | struct extended_signature { | ||
| 120 | unsigned int sig; | ||
| 121 | unsigned int pf; | ||
| 122 | unsigned int cksum; | ||
| 123 | }; | ||
| 124 | |||
| 125 | struct extended_sigtable { | ||
| 126 | unsigned int count; | ||
| 127 | unsigned int cksum; | ||
| 128 | unsigned int reserved[3]; | ||
| 129 | struct extended_signature sigs[0]; | ||
| 130 | }; | ||
| 131 | |||
| 100 | #define DEFAULT_UCODE_DATASIZE (2000) | 132 | #define DEFAULT_UCODE_DATASIZE (2000) |
| 101 | #define MC_HEADER_SIZE (sizeof(struct microcode_header_intel)) | 133 | #define MC_HEADER_SIZE (sizeof(struct microcode_header_intel)) |
| 102 | #define DEFAULT_UCODE_TOTALSIZE (DEFAULT_UCODE_DATASIZE + MC_HEADER_SIZE) | 134 | #define DEFAULT_UCODE_TOTALSIZE (DEFAULT_UCODE_DATASIZE + MC_HEADER_SIZE) |
| @@ -284,11 +316,12 @@ static void apply_microcode(int cpu) | |||
| 284 | unsigned int val[2]; | 316 | unsigned int val[2]; |
| 285 | int cpu_num = raw_smp_processor_id(); | 317 | int cpu_num = raw_smp_processor_id(); |
| 286 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu; | 318 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu; |
| 319 | struct microcode_intel *mc_intel = uci->mc; | ||
| 287 | 320 | ||
| 288 | /* We should bind the task to the CPU */ | 321 | /* We should bind the task to the CPU */ |
| 289 | BUG_ON(cpu_num != cpu); | 322 | BUG_ON(cpu_num != cpu); |
| 290 | 323 | ||
| 291 | if (uci->mc.mc_intel == NULL) | 324 | if (mc_intel == NULL) |
| 292 | return; | 325 | return; |
| 293 | 326 | ||
| 294 | /* serialize access to the physical write to MSR 0x79 */ | 327 | /* serialize access to the physical write to MSR 0x79 */ |
| @@ -296,8 +329,8 @@ static void apply_microcode(int cpu) | |||
| 296 | 329 | ||
| 297 | /* write microcode via MSR 0x79 */ | 330 | /* write microcode via MSR 0x79 */ |
| 298 | wrmsr(MSR_IA32_UCODE_WRITE, | 331 | wrmsr(MSR_IA32_UCODE_WRITE, |
| 299 | (unsigned long) uci->mc.mc_intel->bits, | 332 | (unsigned long) mc_intel->bits, |
| 300 | (unsigned long) uci->mc.mc_intel->bits >> 16 >> 16); | 333 | (unsigned long) mc_intel->bits >> 16 >> 16); |
| 301 | wrmsr(MSR_IA32_UCODE_REV, 0, 0); | 334 | wrmsr(MSR_IA32_UCODE_REV, 0, 0); |
| 302 | 335 | ||
| 303 | /* see notes above for revision 1.07. Apparent chip bug */ | 336 | /* see notes above for revision 1.07. Apparent chip bug */ |
| @@ -307,7 +340,7 @@ static void apply_microcode(int cpu) | |||
| 307 | rdmsr(MSR_IA32_UCODE_REV, val[0], val[1]); | 340 | rdmsr(MSR_IA32_UCODE_REV, val[0], val[1]); |
| 308 | 341 | ||
| 309 | spin_unlock_irqrestore(µcode_update_lock, flags); | 342 | spin_unlock_irqrestore(µcode_update_lock, flags); |
| 310 | if (val[1] != uci->mc.mc_intel->hdr.rev) { | 343 | if (val[1] != mc_intel->hdr.rev) { |
| 311 | printk(KERN_ERR "microcode: CPU%d update from revision " | 344 | printk(KERN_ERR "microcode: CPU%d update from revision " |
| 312 | "0x%x to 0x%x failed\n", cpu_num, uci->cpu_sig.rev, val[1]); | 345 | "0x%x to 0x%x failed\n", cpu_num, uci->cpu_sig.rev, val[1]); |
| 313 | return; | 346 | return; |
| @@ -315,9 +348,9 @@ static void apply_microcode(int cpu) | |||
| 315 | printk(KERN_INFO "microcode: CPU%d updated from revision " | 348 | printk(KERN_INFO "microcode: CPU%d updated from revision " |
| 316 | "0x%x to 0x%x, date = %04x-%02x-%02x \n", | 349 | "0x%x to 0x%x, date = %04x-%02x-%02x \n", |
| 317 | cpu_num, uci->cpu_sig.rev, val[1], | 350 | cpu_num, uci->cpu_sig.rev, val[1], |
| 318 | uci->mc.mc_intel->hdr.date & 0xffff, | 351 | mc_intel->hdr.date & 0xffff, |
| 319 | uci->mc.mc_intel->hdr.date >> 24, | 352 | mc_intel->hdr.date >> 24, |
| 320 | (uci->mc.mc_intel->hdr.date >> 16) & 0xff); | 353 | (mc_intel->hdr.date >> 16) & 0xff); |
| 321 | uci->cpu_sig.rev = val[1]; | 354 | uci->cpu_sig.rev = val[1]; |
| 322 | } | 355 | } |
| 323 | 356 | ||
| @@ -367,12 +400,12 @@ static int generic_load_microcode(int cpu, void *data, size_t size, | |||
| 367 | 400 | ||
| 368 | if (new_mc) { | 401 | if (new_mc) { |
| 369 | if (!leftover) { | 402 | if (!leftover) { |
| 370 | if (uci->mc.mc_intel) | 403 | if (uci->mc) |
| 371 | vfree(uci->mc.mc_intel); | 404 | vfree(uci->mc); |
| 372 | uci->mc.mc_intel = (struct microcode_intel *)new_mc; | 405 | uci->mc = (struct microcode_intel *)new_mc; |
| 373 | pr_debug("microcode: CPU%d found a matching microcode update with" | 406 | pr_debug("microcode: CPU%d found a matching microcode update with" |
| 374 | " version 0x%x (current=0x%x)\n", | 407 | " version 0x%x (current=0x%x)\n", |
| 375 | cpu, uci->mc.mc_intel->hdr.rev, uci->cpu_sig.rev); | 408 | cpu, new_rev, uci->cpu_sig.rev); |
| 376 | } else | 409 | } else |
| 377 | vfree(new_mc); | 410 | vfree(new_mc); |
| 378 | } | 411 | } |
| @@ -428,11 +461,11 @@ static void microcode_fini_cpu(int cpu) | |||
| 428 | { | 461 | { |
| 429 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu; | 462 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu; |
| 430 | 463 | ||
| 431 | vfree(uci->mc.mc_intel); | 464 | vfree(uci->mc); |
| 432 | uci->mc.mc_intel = NULL; | 465 | uci->mc = NULL; |
| 433 | } | 466 | } |
| 434 | 467 | ||
| 435 | static struct microcode_ops microcode_intel_ops = { | 468 | struct microcode_ops microcode_intel_ops = { |
| 436 | .request_microcode_user = request_microcode_user, | 469 | .request_microcode_user = request_microcode_user, |
| 437 | .request_microcode_fw = request_microcode_fw, | 470 | .request_microcode_fw = request_microcode_fw, |
| 438 | .collect_cpu_info = collect_cpu_info, | 471 | .collect_cpu_info = collect_cpu_info, |
| @@ -440,22 +473,8 @@ static struct microcode_ops microcode_intel_ops = { | |||
| 440 | .microcode_fini_cpu = microcode_fini_cpu, | 473 | .microcode_fini_cpu = microcode_fini_cpu, |
| 441 | }; | 474 | }; |
| 442 | 475 | ||
| 443 | static int __init microcode_intel_module_init(void) | 476 | struct microcode_ops * __init init_intel_microcode(void) |
| 444 | { | ||
| 445 | struct cpuinfo_x86 *c = &cpu_data(0); | ||
| 446 | |||
| 447 | if (c->x86_vendor != X86_VENDOR_INTEL) { | ||
| 448 | printk(KERN_ERR "microcode: CPU platform is not Intel-capable\n"); | ||
| 449 | return -ENODEV; | ||
| 450 | } | ||
| 451 | |||
| 452 | return microcode_init(µcode_intel_ops, THIS_MODULE); | ||
| 453 | } | ||
| 454 | |||
| 455 | static void __exit microcode_intel_module_exit(void) | ||
| 456 | { | 477 | { |
| 457 | microcode_exit(); | 478 | return µcode_intel_ops; |
| 458 | } | 479 | } |
| 459 | 480 | ||
| 460 | module_init(microcode_intel_module_init) | ||
| 461 | module_exit(microcode_intel_module_exit) | ||
