aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-10-01 14:15:17 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2012-10-01 14:15:17 -0400
commitb3eda8d05c1afe722dc19be3fee7eeadc75e25e2 (patch)
treee301bb7d93be3c1d6192a5186e248c2f00294609
parenta5fa7b7d8fe0eef36d0adbb36ae71dc82aa0a458 (diff)
parentbd13178169d5fd17da3221b55ba313270393649a (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/Kconfig20
-rw-r--r--arch/x86/include/asm/microcode.h10
-rw-r--r--arch/x86/kernel/microcode_amd.c357
-rw-r--r--arch/x86/kernel/microcode_core.c67
-rw-r--r--arch/x86/kernel/microcode_intel.c3
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
988config MICROCODE 988config 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
1006config MICROCODE_INTEL 1006config 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
1019config MICROCODE_AMD 1019config 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
50extern struct microcode_ops * __init init_amd_microcode(void); 50extern struct microcode_ops * __init init_amd_microcode(void);
51extern void __exit exit_amd_microcode(void); 51extern void __exit exit_amd_microcode(void);
52
53static 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
59static inline struct microcode_ops * __init init_amd_microcode(void) 53static 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
76static struct equiv_cpu_entry *equiv_cpu_table; 76static struct equiv_cpu_entry *equiv_cpu_table;
77 77
78/* page-sized ucode patch buffer */ 78struct ucode_patch {
79void *patch; 79 struct list_head plist;
80 void *data;
81 u32 patch_id;
82 u16 equiv_cpu;
83};
84
85static LIST_HEAD(pcache);
86
87static 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
104static 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 */
121static 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
131static 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
151static 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
162static 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