diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-10-01 14:15:17 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-10-01 14:15:17 -0400 |
| commit | b3eda8d05c1afe722dc19be3fee7eeadc75e25e2 (patch) | |
| tree | e301bb7d93be3c1d6192a5186e248c2f00294609 | |
| parent | a5fa7b7d8fe0eef36d0adbb36ae71dc82aa0a458 (diff) | |
| parent | bd13178169d5fd17da3221b55ba313270393649a (diff) | |
Merge branch 'x86-microcode-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86/microcode changes from Ingo Molnar:
"The biggest changes are to AMD microcode patching: add code for
caching all microcode patches which belong to the current family on
which we're running, in the kernel.
We look up the patch needed for each core from the cache at
patch-application time instead of holding a single patch per-system"
* 'x86-microcode-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
x86, microcode, AMD: Fix use after free in free_cache()
x86, microcode, AMD: Rewrite patch application procedure
x86, microcode, AMD: Add a small, per-family patches cache
x86, microcode, AMD: Add reverse equiv table search
x86, microcode: Add a refresh firmware flag to ->request_microcode_fw
x86, microcode, AMD: Read CPUID(1).EAX on the correct cpu
x86, microcode, AMD: Check before applying a patch
x86, microcode, AMD: Remove useless get_ucode_data wrapper
x86, microcode: Straighten out Kconfig text
x86, microcode: Cleanup cpu hotplug notifier callback
x86, microcode: Drop uci->mc check on resume path
x86, microcode: Save an indentation level in reload_for_cpu
| -rw-r--r-- | arch/x86/Kconfig | 20 | ||||
| -rw-r--r-- | arch/x86/include/asm/microcode.h | 10 | ||||
| -rw-r--r-- | arch/x86/kernel/microcode_amd.c | 357 | ||||
| -rw-r--r-- | arch/x86/kernel/microcode_core.c | 67 | ||||
| -rw-r--r-- | arch/x86/kernel/microcode_intel.c | 3 |
5 files changed, 273 insertions, 184 deletions
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 6cd6f24e1223..943667050dae 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig | |||
| @@ -986,25 +986,25 @@ config X86_REBOOTFIXUPS | |||
| 986 | Say N otherwise. | 986 | Say N otherwise. |
| 987 | 987 | ||
| 988 | config MICROCODE | 988 | config MICROCODE |
| 989 | tristate "/dev/cpu/microcode - microcode support" | 989 | tristate "CPU microcode loading support" |
| 990 | select FW_LOADER | 990 | select FW_LOADER |
| 991 | ---help--- | 991 | ---help--- |
| 992 | |||
| 992 | If you say Y here, you will be able to update the microcode on | 993 | If you say Y here, you will be able to update the microcode on |
| 993 | certain Intel and AMD processors. The Intel support is for the | 994 | certain Intel and AMD processors. The Intel support is for the |
| 994 | IA32 family, e.g. Pentium Pro, Pentium II, Pentium III, | 995 | IA32 family, e.g. Pentium Pro, Pentium II, Pentium III, Pentium 4, |
| 995 | Pentium 4, Xeon etc. The AMD support is for family 0x10 and | 996 | Xeon etc. The AMD support is for families 0x10 and later. You will |
| 996 | 0x11 processors, e.g. Opteron, Phenom and Turion 64 Ultra. | 997 | obviously need the actual microcode binary data itself which is not |
| 997 | You will obviously need the actual microcode binary data itself | 998 | shipped with the Linux kernel. |
| 998 | which is not shipped with the Linux kernel. | ||
| 999 | 999 | ||
| 1000 | This option selects the general module only, you need to select | 1000 | This option selects the general module only, you need to select |
| 1001 | at least one vendor specific module as well. | 1001 | at least one vendor specific module as well. |
| 1002 | 1002 | ||
| 1003 | To compile this driver as a module, choose M here: the | 1003 | To compile this driver as a module, choose M here: the module |
| 1004 | module will be called microcode. | 1004 | will be called microcode. |
| 1005 | 1005 | ||
| 1006 | config MICROCODE_INTEL | 1006 | config MICROCODE_INTEL |
| 1007 | bool "Intel microcode patch loading support" | 1007 | bool "Intel microcode loading support" |
| 1008 | depends on MICROCODE | 1008 | depends on MICROCODE |
| 1009 | default MICROCODE | 1009 | default MICROCODE |
| 1010 | select FW_LOADER | 1010 | select FW_LOADER |
| @@ -1017,7 +1017,7 @@ config MICROCODE_INTEL | |||
| 1017 | <http://www.urbanmyth.org/microcode/>. | 1017 | <http://www.urbanmyth.org/microcode/>. |
| 1018 | 1018 | ||
| 1019 | config MICROCODE_AMD | 1019 | config MICROCODE_AMD |
| 1020 | bool "AMD microcode patch loading support" | 1020 | bool "AMD microcode loading support" |
| 1021 | depends on MICROCODE | 1021 | depends on MICROCODE |
| 1022 | select FW_LOADER | 1022 | select FW_LOADER |
| 1023 | ---help--- | 1023 | ---help--- |
diff --git a/arch/x86/include/asm/microcode.h b/arch/x86/include/asm/microcode.h index 4ebe157bf73d..43d921b4752c 100644 --- a/arch/x86/include/asm/microcode.h +++ b/arch/x86/include/asm/microcode.h | |||
| @@ -15,8 +15,8 @@ struct microcode_ops { | |||
| 15 | enum ucode_state (*request_microcode_user) (int cpu, | 15 | enum ucode_state (*request_microcode_user) (int cpu, |
| 16 | const void __user *buf, size_t size); | 16 | const void __user *buf, size_t size); |
| 17 | 17 | ||
| 18 | enum ucode_state (*request_microcode_fw) (int cpu, | 18 | enum ucode_state (*request_microcode_fw) (int cpu, struct device *, |
| 19 | struct device *device); | 19 | bool refresh_fw); |
| 20 | 20 | ||
| 21 | void (*microcode_fini_cpu) (int cpu); | 21 | void (*microcode_fini_cpu) (int cpu); |
| 22 | 22 | ||
| @@ -49,12 +49,6 @@ static inline struct microcode_ops * __init init_intel_microcode(void) | |||
| 49 | #ifdef CONFIG_MICROCODE_AMD | 49 | #ifdef CONFIG_MICROCODE_AMD |
| 50 | extern struct microcode_ops * __init init_amd_microcode(void); | 50 | extern struct microcode_ops * __init init_amd_microcode(void); |
| 51 | extern void __exit exit_amd_microcode(void); | 51 | extern void __exit exit_amd_microcode(void); |
| 52 | |||
| 53 | static inline void get_ucode_data(void *to, const u8 *from, size_t n) | ||
| 54 | { | ||
| 55 | memcpy(to, from, n); | ||
| 56 | } | ||
| 57 | |||
| 58 | #else | 52 | #else |
| 59 | static inline struct microcode_ops * __init init_amd_microcode(void) | 53 | static inline struct microcode_ops * __init init_amd_microcode(void) |
| 60 | { | 54 | { |
diff --git a/arch/x86/kernel/microcode_amd.c b/arch/x86/kernel/microcode_amd.c index 82746f942cd8..7720ff5a9ee2 100644 --- a/arch/x86/kernel/microcode_amd.c +++ b/arch/x86/kernel/microcode_amd.c | |||
| @@ -75,20 +75,113 @@ struct microcode_amd { | |||
| 75 | 75 | ||
| 76 | static struct equiv_cpu_entry *equiv_cpu_table; | 76 | static struct equiv_cpu_entry *equiv_cpu_table; |
| 77 | 77 | ||
| 78 | /* page-sized ucode patch buffer */ | 78 | struct ucode_patch { |
| 79 | void *patch; | 79 | struct list_head plist; |
| 80 | void *data; | ||
| 81 | u32 patch_id; | ||
| 82 | u16 equiv_cpu; | ||
| 83 | }; | ||
| 84 | |||
| 85 | static LIST_HEAD(pcache); | ||
| 86 | |||
| 87 | static u16 find_equiv_id(unsigned int cpu) | ||
| 88 | { | ||
| 89 | struct ucode_cpu_info *uci = ucode_cpu_info + cpu; | ||
| 90 | int i = 0; | ||
| 91 | |||
| 92 | if (!equiv_cpu_table) | ||
| 93 | return 0; | ||
| 94 | |||
| 95 | while (equiv_cpu_table[i].installed_cpu != 0) { | ||
| 96 | if (uci->cpu_sig.sig == equiv_cpu_table[i].installed_cpu) | ||
| 97 | return equiv_cpu_table[i].equiv_cpu; | ||
| 98 | |||
| 99 | i++; | ||
| 100 | } | ||
| 101 | return 0; | ||
| 102 | } | ||
| 103 | |||
| 104 | static u32 find_cpu_family_by_equiv_cpu(u16 equiv_cpu) | ||
| 105 | { | ||
| 106 | int i = 0; | ||
| 107 | |||
| 108 | BUG_ON(!equiv_cpu_table); | ||
| 109 | |||
| 110 | while (equiv_cpu_table[i].equiv_cpu != 0) { | ||
| 111 | if (equiv_cpu == equiv_cpu_table[i].equiv_cpu) | ||
| 112 | return equiv_cpu_table[i].installed_cpu; | ||
| 113 | i++; | ||
| 114 | } | ||
| 115 | return 0; | ||
| 116 | } | ||
| 117 | |||
| 118 | /* | ||
| 119 | * a small, trivial cache of per-family ucode patches | ||
| 120 | */ | ||
| 121 | static struct ucode_patch *cache_find_patch(u16 equiv_cpu) | ||
| 122 | { | ||
| 123 | struct ucode_patch *p; | ||
| 124 | |||
| 125 | list_for_each_entry(p, &pcache, plist) | ||
| 126 | if (p->equiv_cpu == equiv_cpu) | ||
| 127 | return p; | ||
| 128 | return NULL; | ||
| 129 | } | ||
| 130 | |||
| 131 | static void update_cache(struct ucode_patch *new_patch) | ||
| 132 | { | ||
| 133 | struct ucode_patch *p; | ||
| 134 | |||
| 135 | list_for_each_entry(p, &pcache, plist) { | ||
| 136 | if (p->equiv_cpu == new_patch->equiv_cpu) { | ||
| 137 | if (p->patch_id >= new_patch->patch_id) | ||
| 138 | /* we already have the latest patch */ | ||
| 139 | return; | ||
| 140 | |||
| 141 | list_replace(&p->plist, &new_patch->plist); | ||
| 142 | kfree(p->data); | ||
| 143 | kfree(p); | ||
| 144 | return; | ||
| 145 | } | ||
| 146 | } | ||
| 147 | /* no patch found, add it */ | ||
| 148 | list_add_tail(&new_patch->plist, &pcache); | ||
| 149 | } | ||
| 150 | |||
| 151 | static void free_cache(void) | ||
| 152 | { | ||
| 153 | struct ucode_patch *p, *tmp; | ||
| 154 | |||
| 155 | list_for_each_entry_safe(p, tmp, &pcache, plist) { | ||
| 156 | __list_del(p->plist.prev, p->plist.next); | ||
| 157 | kfree(p->data); | ||
| 158 | kfree(p); | ||
| 159 | } | ||
| 160 | } | ||
| 161 | |||
| 162 | static struct ucode_patch *find_patch(unsigned int cpu) | ||
| 163 | { | ||
| 164 | u16 equiv_id; | ||
| 165 | |||
| 166 | equiv_id = find_equiv_id(cpu); | ||
| 167 | if (!equiv_id) | ||
| 168 | |||
