diff options
| author | David Woodhouse <dwmw2@infradead.org> | 2007-04-26 04:31:28 -0400 |
|---|---|---|
| committer | David Woodhouse <dwmw2@infradead.org> | 2007-04-26 04:31:28 -0400 |
| commit | ef2e58ea6b9931c3a4816c66593da49bb20e3b24 (patch) | |
| tree | ce7432add3becbe78de4ea06425cd2d9e91f4ada /arch/i386/kernel/microcode.c | |
| parent | 06d63cc51d47f572009138a7f3ac34d95773405d (diff) | |
| parent | de46c33745f5e2ad594c72f2cf5f490861b16ce1 (diff) | |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
Diffstat (limited to 'arch/i386/kernel/microcode.c')
| -rw-r--r-- | arch/i386/kernel/microcode.c | 71 |
1 files changed, 67 insertions, 4 deletions
diff --git a/arch/i386/kernel/microcode.c b/arch/i386/kernel/microcode.c index b8f16633a6ec..cbe7ec8dbb9f 100644 --- a/arch/i386/kernel/microcode.c +++ b/arch/i386/kernel/microcode.c | |||
| @@ -567,6 +567,53 @@ static int cpu_request_microcode(int cpu) | |||
| 567 | return error; | 567 | return error; |
| 568 | } | 568 | } |
| 569 | 569 | ||
| 570 | static int apply_microcode_on_cpu(int cpu) | ||
| 571 | { | ||
| 572 | struct cpuinfo_x86 *c = cpu_data + cpu; | ||
| 573 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu; | ||
| 574 | cpumask_t old; | ||
| 575 | unsigned int val[2]; | ||
| 576 | int err = 0; | ||
| 577 | |||
| 578 | if (!uci->mc) | ||
| 579 | return -EINVAL; | ||
| 580 | |||
| 581 | old = current->cpus_allowed; | ||
| 582 | set_cpus_allowed(current, cpumask_of_cpu(cpu)); | ||
| 583 | |||
| 584 | /* Check if the microcode we have in memory matches the CPU */ | ||
| 585 | if (c->x86_vendor != X86_VENDOR_INTEL || c->x86 < 6 || | ||
| 586 | cpu_has(c, X86_FEATURE_IA64) || uci->sig != cpuid_eax(0x00000001)) | ||
| 587 | err = -EINVAL; | ||
| 588 | |||
| 589 | if (!err && ((c->x86_model >= 5) || (c->x86 > 6))) { | ||
| 590 | /* get processor flags from MSR 0x17 */ | ||
| 591 | rdmsr(MSR_IA32_PLATFORM_ID, val[0], val[1]); | ||
| 592 | if (uci->pf != (1 << ((val[1] >> 18) & 7))) | ||
| 593 | err = -EINVAL; | ||
| 594 | } | ||
| 595 | |||
| 596 | if (!err) { | ||
| 597 | wrmsr(MSR_IA32_UCODE_REV, 0, 0); | ||
| 598 | /* see notes above for revision 1.07. Apparent chip bug */ | ||
| 599 | sync_core(); | ||
| 600 | /* get the current revision from MSR 0x8B */ | ||
| 601 | rdmsr(MSR_IA32_UCODE_REV, val[0], val[1]); | ||
| 602 | if (uci->rev != val[1]) | ||
| 603 | err = -EINVAL; | ||
| 604 | } | ||
| 605 | |||
| 606 | if (!err) | ||
| 607 | apply_microcode(cpu); | ||
| 608 | else | ||
| 609 | printk(KERN_ERR "microcode: Could not apply microcode to CPU%d:" | ||
| 610 | " sig=0x%x, pf=0x%x, rev=0x%x\n", | ||
| 611 | cpu, uci->sig, uci->pf, uci->rev); | ||
| 612 | |||
| 613 | set_cpus_allowed(current, old); | ||
| 614 | return err; | ||
| 615 | } | ||
| 616 | |||
| 570 | static void microcode_init_cpu(int cpu) | 617 | static void microcode_init_cpu(int cpu) |
| 571 | { | 618 | { |
| 572 | cpumask_t old; | 619 | cpumask_t old; |
| @@ -577,7 +624,8 @@ static void microcode_init_cpu(int cpu) | |||
| 577 | set_cpus_allowed(current, cpumask_of_cpu(cpu)); | 624 | set_cpus_allowed(current, cpumask_of_cpu(cpu)); |
| 578 | mutex_lock(µcode_mutex); | 625 | mutex_lock(µcode_mutex); |
| 579 | collect_cpu_info(cpu); | 626 | collect_cpu_info(cpu); |
| 580 | if (uci->valid && system_state == SYSTEM_RUNNING) | 627 | if (uci->valid && system_state == SYSTEM_RUNNING && |
| 628 | !suspend_cpu_hotplug) | ||
| 581 | cpu_request_microcode(cpu); | 629 | cpu_request_microcode(cpu); |
| 582 | mutex_unlock(µcode_mutex); | 630 | mutex_unlock(µcode_mutex); |
| 583 | set_cpus_allowed(current, old); | 631 | set_cpus_allowed(current, old); |
| @@ -663,13 +711,24 @@ static int mc_sysdev_add(struct sys_device *sys_dev) | |||
| 663 | return 0; | 711 | return 0; |
| 664 | 712 | ||
| 665 | pr_debug("Microcode:CPU %d added\n", cpu); | 713 | pr_debug("Microcode:CPU %d added\n", cpu); |
| 666 | memset(uci, 0, sizeof(*uci)); | 714 | /* If suspend_cpu_hotplug is set, the system is resuming and we should |
| 715 | * use the data from before the suspend. | ||
| 716 | */ | ||
| 717 | if (suspend_cpu_hotplug) { | ||
| 718 | err = apply_microcode_on_cpu(cpu); | ||
| 719 | if (err) | ||
| 720 | microcode_fini_cpu(cpu); | ||
| 721 | } | ||
| 722 | if (!uci->valid) | ||
| 723 | memset(uci, 0, sizeof(*uci)); | ||
| 667 | 724 | ||
| 668 | err = sysfs_create_group(&sys_dev->kobj, &mc_attr_group); | 725 | err = sysfs_create_group(&sys_dev->kobj, &mc_attr_group); |
| 669 | if (err) | 726 | if (err) |
| 670 | return err; | 727 | return err; |
| 671 | 728 | ||
| 672 | microcode_init_cpu(cpu); | 729 | if (!uci->valid) |
| 730 | microcode_init_cpu(cpu); | ||
| 731 | |||
| 673 | return 0; | 732 | return 0; |
| 674 | } | 733 | } |
| 675 | 734 | ||
| @@ -680,7 +739,11 @@ static int mc_sysdev_remove(struct sys_device *sys_dev) | |||
| 680 | if (!cpu_online(cpu)) | 739 | if (!cpu_online(cpu)) |
| 681 | return 0; | 740 | return 0; |
| 682 | pr_debug("Microcode:CPU %d removed\n", cpu); | 741 | pr_debug("Microcode:CPU %d removed\n", cpu); |
| 683 | microcode_fini_cpu(cpu); | 742 | /* If suspend_cpu_hotplug is set, the system is suspending and we should |
| 743 | * keep the microcode in memory for the resume. | ||
| 744 | */ | ||
| 745 | if (!suspend_cpu_hotplug) | ||
| 746 | microcode_fini_cpu(cpu); | ||
| 684 | sysfs_remove_group(&sys_dev->kobj, &mc_attr_group); | 747 | sysfs_remove_group(&sys_dev->kobj, &mc_attr_group); |
| 685 | return 0; | 748 | return 0; |
| 686 | } | 749 | } |
