diff options
Diffstat (limited to 'arch/x86/kernel/cpu/microcode/intel.c')
| -rw-r--r-- | arch/x86/kernel/cpu/microcode/intel.c | 52 |
1 files changed, 43 insertions, 9 deletions
diff --git a/arch/x86/kernel/cpu/microcode/intel.c b/arch/x86/kernel/cpu/microcode/intel.c index 923054a6b760..32b8e5724f96 100644 --- a/arch/x86/kernel/cpu/microcode/intel.c +++ b/arch/x86/kernel/cpu/microcode/intel.c | |||
| @@ -589,6 +589,23 @@ static int apply_microcode_early(struct ucode_cpu_info *uci, bool early) | |||
| 589 | if (!mc) | 589 | if (!mc) |
| 590 | return 0; | 590 | return 0; |
| 591 | 591 | ||
| 592 | /* | ||
| 593 | * Save us the MSR write below - which is a particular expensive | ||
| 594 | * operation - when the other hyperthread has updated the microcode | ||
| 595 | * already. | ||
| 596 | */ | ||
| 597 | rev = intel_get_microcode_revision(); | ||
| 598 | if (rev >= mc->hdr.rev) { | ||
| 599 | uci->cpu_sig.rev = rev; | ||
| 600 | return UCODE_OK; | ||
| 601 | } | ||
| 602 | |||
| 603 | /* | ||
| 604 | * Writeback and invalidate caches before updating microcode to avoid | ||
| 605 | * internal issues depending on what the microcode is updating. | ||
| 606 | */ | ||
| 607 | native_wbinvd(); | ||
| 608 | |||
| 592 | /* write microcode via MSR 0x79 */ | 609 | /* write microcode via MSR 0x79 */ |
| 593 | native_wrmsrl(MSR_IA32_UCODE_WRITE, (unsigned long)mc->bits); | 610 | native_wrmsrl(MSR_IA32_UCODE_WRITE, (unsigned long)mc->bits); |
| 594 | 611 | ||
| @@ -774,9 +791,9 @@ static int collect_cpu_info(int cpu_num, struct cpu_signature *csig) | |||
| 774 | 791 | ||
| 775 | static enum ucode_state apply_microcode_intel(int cpu) | 792 | static enum ucode_state apply_microcode_intel(int cpu) |
| 776 | { | 793 | { |
| 794 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu; | ||
| 795 | struct cpuinfo_x86 *c = &cpu_data(cpu); | ||
| 777 | struct microcode_intel *mc; | 796 | struct microcode_intel *mc; |
| 778 | struct ucode_cpu_info *uci; | ||
| 779 | struct cpuinfo_x86 *c; | ||
| 780 | static int prev_rev; | 797 | static int prev_rev; |
| 781 | u32 rev; | 798 | u32 rev; |
| 782 | 799 | ||
| @@ -784,15 +801,32 @@ static enum ucode_state apply_microcode_intel(int cpu) | |||
| 784 | if (WARN_ON(raw_smp_processor_id() != cpu)) | 801 | if (WARN_ON(raw_smp_processor_id() != cpu)) |
| 785 | return UCODE_ERROR; | 802 | return UCODE_ERROR; |
| 786 | 803 | ||
| 787 | uci = ucode_cpu_info + cpu; | 804 | /* Look for a newer patch in our cache: */ |
| 788 | mc = uci->mc; | 805 | mc = find_patch(uci); |
| 789 | if (!mc) { | 806 | if (!mc) { |
| 790 | /* Look for a newer patch in our cache: */ | 807 | mc = uci->mc; |
| 791 | mc = find_patch(uci); | ||
| 792 | if (!mc) | 808 | if (!mc) |
| 793 | return UCODE_NFOUND; | 809 | return UCODE_NFOUND; |
| 794 | } | 810 | } |
| 795 | 811 | ||
| 812 | /* | ||
| 813 | * Save us the MSR write below - which is a particular expensive | ||
| 814 | * operation - when the other hyperthread has updated the microcode | ||
| 815 | * already. | ||
| 816 | */ | ||
| 817 | rev = intel_get_microcode_revision(); | ||
| 818 | if (rev >= mc->hdr.rev) { | ||
| 819 | uci->cpu_sig.rev = rev; | ||
| 820 | c->microcode = rev; | ||
| 821 | return UCODE_OK; | ||
| 822 | } | ||
| 823 | |||
| 824 | /* | ||
| 825 | * Writeback and invalidate caches before updating microcode to avoid | ||
| 826 | * internal issues depending on what the microcode is updating. | ||
| 827 | */ | ||
| 828 | native_wbinvd(); | ||
| 829 | |||
| 796 | /* write microcode via MSR 0x79 */ | 830 | /* write microcode via MSR 0x79 */ |
| 797 | wrmsrl(MSR_IA32_UCODE_WRITE, (unsigned long)mc->bits); | 831 | wrmsrl(MSR_IA32_UCODE_WRITE, (unsigned long)mc->bits); |
| 798 | 832 | ||
| @@ -813,8 +847,6 @@ static enum ucode_state apply_microcode_intel(int cpu) | |||
| 813 | prev_rev = rev; | 847 | prev_rev = rev; |
| 814 | } | 848 | } |
| 815 | 849 | ||
| 816 | c = &cpu_data(cpu); | ||
| 817 | |||
| 818 | uci->cpu_sig.rev = rev; | 850 | uci->cpu_sig.rev = rev; |
| 819 | c->microcode = rev; | 851 | c->microcode = rev; |
| 820 | 852 | ||
| @@ -830,6 +862,7 @@ static enum ucode_state generic_load_microcode(int cpu, void *data, size_t size, | |||
| 830 | unsigned int leftover = size; | 862 | unsigned int leftover = size; |
| 831 | unsigned int curr_mc_size = 0, new_mc_size = 0; | 863 | unsigned int curr_mc_size = 0, new_mc_size = 0; |
| 832 | unsigned int csig, cpf; | 864 | unsigned int csig, cpf; |
| 865 | enum ucode_state ret = UCODE_OK; | ||
| 833 | 866 | ||
| 834 | while (leftover) { | 867 | while (leftover) { |
| 835 | struct microcode_header_intel mc_header; | 868 | struct microcode_header_intel mc_header; |
| @@ -871,6 +904,7 @@ static enum ucode_state generic_load_microcode(int cpu, void *data, size_t size, | |||
| 871 | new_mc = mc; | 904 | new_mc = mc; |
| 872 | new_mc_size = mc_size; | 905 | new_mc_size = mc_size; |
| 873 | mc = NULL; /* trigger new vmalloc */ | 906 | mc = NULL; /* trigger new vmalloc */ |
| 907 | ret = UCODE_NEW; | ||
| 874 | } | 908 | } |
| 875 | 909 | ||
| 876 | ucode_ptr += mc_size; | 910 | ucode_ptr += mc_size; |
| @@ -900,7 +934,7 @@ static enum ucode_state generic_load_microcode(int cpu, void *data, size_t size, | |||
| 900 | pr_debug("CPU%d found a matching microcode update with version 0x%x (current=0x%x)\n", | 934 | pr_debug("CPU%d found a matching microcode update with version 0x%x (current=0x%x)\n", |
| 901 | cpu, new_rev, uci->cpu_sig.rev); | 935 | cpu, new_rev, uci->cpu_sig.rev); |
| 902 | 936 | ||
| 903 | return UCODE_OK; | 937 | return ret; |
| 904 | } | 938 | } |
| 905 | 939 | ||
| 906 | static int get_ucode_fw(void *to, const void *from, size_t n) | 940 | static int get_ucode_fw(void *to, const void *from, size_t n) |
