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) |