aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86
diff options
context:
space:
mode:
authorDmitry Adamushko <dmitry.adamushko@gmail.com>2008-09-11 17:27:52 -0400
committerIngo Molnar <mingo@elte.hu>2008-09-12 06:20:27 -0400
commita0a29b62a9cac6b7d83b7514679f2ed8d33d4372 (patch)
treee07ab66cbe3c90da70a7195104413cae00104de6 /arch/x86
parent5b792d320f28ff83dd4c13f984807e26235f7703 (diff)
x86, microcode rework, v2
this is a rework of the microcode splitup in tip/x86/microcode (1) I think this new interface is cleaner (look at the changes in 'struct microcode_ops' in microcode.h); (2) it's -64 lines of code; Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/x86')
-rw-r--r--arch/x86/kernel/microcode.c84
-rw-r--r--arch/x86/kernel/microcode_amd.c329
-rw-r--r--arch/x86/kernel/microcode_intel.c220
3 files changed, 285 insertions, 348 deletions
diff --git a/arch/x86/kernel/microcode.c b/arch/x86/kernel/microcode.c
index b2f84ce5eed3..902dada2eb6d 100644
--- a/arch/x86/kernel/microcode.c
+++ b/arch/x86/kernel/microcode.c
@@ -110,50 +110,28 @@ struct ucode_cpu_info ucode_cpu_info[NR_CPUS];
110EXPORT_SYMBOL_GPL(ucode_cpu_info); 110EXPORT_SYMBOL_GPL(ucode_cpu_info);
111 111
112#ifdef CONFIG_MICROCODE_OLD_INTERFACE 112#ifdef CONFIG_MICROCODE_OLD_INTERFACE
113void __user *user_buffer; /* user area microcode data buffer */ 113static int do_microcode_update(const void __user *buf, size_t size)
114EXPORT_SYMBOL_GPL(user_buffer);
115unsigned int user_buffer_size; /* it's size */
116EXPORT_SYMBOL_GPL(user_buffer_size);
117
118static int do_microcode_update(void)
119{ 114{
120 long cursor = 0; 115 cpumask_t old;
121 int error = 0; 116 int error = 0;
122 void *new_mc = NULL;
123 int cpu; 117 int cpu;
124 cpumask_t old;
125 118
126 old = current->cpus_allowed; 119 old = current->cpus_allowed;
127 120
128 while ((cursor = microcode_ops->get_next_ucode(&new_mc, cursor)) > 0) { 121 for_each_online_cpu(cpu) {
129 if (microcode_ops->microcode_sanity_check != NULL) 122 struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
130 error = microcode_ops->microcode_sanity_check(new_mc); 123
131 if (error) 124 if (!uci->valid)
125 continue;
126
127 set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu));
128 error = microcode_ops->request_microcode_user(cpu, buf, size);
129 if (error < 0)
132 goto out; 130 goto out;
133 /* 131 if (!error)
134 * It's possible the data file has multiple matching ucode, 132 microcode_ops->apply_microcode(cpu);
135 * lets keep searching till the latest version
136 */
137 for_each_online_cpu(cpu) {
138 struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
139
140 if (!uci->valid)
141 continue;
142 set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu));
143 error = microcode_ops->get_matching_microcode(new_mc,
144 cpu);
145 if (error < 0)
146 goto out;
147 if (error == 1)
148 microcode_ops->apply_microcode(cpu);
149 }
150 vfree(new_mc);
151 } 133 }
152out: 134out:
153 if (cursor > 0)
154 vfree(new_mc);
155 if (cursor < 0)
156 error = cursor;
157 set_cpus_allowed_ptr(current, &old); 135 set_cpus_allowed_ptr(current, &old);
158 return error; 136 return error;
159} 137}
@@ -178,10 +156,7 @@ static ssize_t microcode_write(struct file *file, const char __user *buf,
178 get_online_cpus(); 156 get_online_cpus();
179 mutex_lock(&microcode_mutex); 157 mutex_lock(&microcode_mutex);
180 158
181 user_buffer = (void __user *) buf; 159 ret = do_microcode_update(buf, len);
182 user_buffer_size = (int) len;
183
184 ret = do_microcode_update();
185 if (!ret) 160 if (!ret)
186 ret = (ssize_t)len; 161 ret = (ssize_t)len;
187 162
@@ -231,7 +206,6 @@ MODULE_ALIAS_MISCDEV(MICROCODE_MINOR);
231 206
232/* fake device for request_firmware */ 207/* fake device for request_firmware */
233struct platform_device *microcode_pdev; 208struct platform_device *microcode_pdev;
234EXPORT_SYMBOL_GPL(microcode_pdev);
235 209
236static ssize_t reload_store(struct sys_device *dev, 210static ssize_t reload_store(struct sys_device *dev,
237 struct sysdev_attribute *attr, 211 struct sysdev_attribute *attr,
@@ -252,8 +226,12 @@ static ssize_t reload_store(struct sys_device *dev,
252 if (cpu_online(cpu)) { 226 if (cpu_online(cpu)) {
253 set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu)); 227 set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu));
254 mutex_lock(&microcode_mutex); 228 mutex_lock(&microcode_mutex);
255 if (uci->valid) 229 if (uci->valid) {
256 err = microcode_ops->cpu_request_microcode(cpu); 230 err = microcode_ops->request_microcode_fw(cpu,
231 &microcode_pdev->dev);
232 if (!err)
233 microcode_ops->apply_microcode(cpu);
234 }
257 mutex_unlock(&microcode_mutex); 235 mutex_unlock(&microcode_mutex);
258 set_cpus_allowed_ptr(current, &old); 236 set_cpus_allowed_ptr(current, &old);
259 } 237 }
@@ -315,7 +293,7 @@ static void collect_cpu_info(int cpu)
315 uci->valid = 1; 293 uci->valid = 1;
316} 294}
317 295
318static void microcode_resume_cpu(int cpu) 296static int microcode_resume_cpu(int cpu)
319{ 297{
320 struct ucode_cpu_info *uci = ucode_cpu_info + cpu; 298 struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
321 struct cpu_signature nsig; 299 struct cpu_signature nsig;
@@ -323,7 +301,7 @@ static void microcode_resume_cpu(int cpu)
323 pr_debug("microcode: CPU%d resumed\n", cpu); 301 pr_debug("microcode: CPU%d resumed\n", cpu);
324 302
325 if (!uci->mc.valid_mc) 303 if (!uci->mc.valid_mc)
326 return; 304 return 1;
327 305
328 /* 306 /*
329 * Let's verify that the 'cached' ucode does belong 307 * Let's verify that the 'cached' ucode does belong
@@ -331,21 +309,22 @@ static void microcode_resume_cpu(int cpu)
331 */ 309 */
332 if (microcode_ops->collect_cpu_info(cpu, &nsig)) { 310 if (microcode_ops->collect_cpu_info(cpu, &nsig)) {
333 microcode_fini_cpu(cpu); 311 microcode_fini_cpu(cpu);
334 return; 312 return -1;
335 } 313 }
336 314
337 if (memcmp(&nsig, &uci->cpu_sig, sizeof(nsig))) { 315 if (memcmp(&nsig, &uci->cpu_sig, sizeof(nsig))) {
338 microcode_fini_cpu(cpu); 316 microcode_fini_cpu(cpu);
339 /* Should we look for a new ucode here? */ 317 /* Should we look for a new ucode here? */
340 return; 318 return 1;
341 } 319 }
342 320
343 microcode_ops->apply_microcode(cpu); 321 return 0;
344} 322}
345 323
346void microcode_update_cpu(int cpu) 324void microcode_update_cpu(int cpu)
347{ 325{
348 struct ucode_cpu_info *uci = ucode_cpu_info + cpu; 326 struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
327 int err = 0;
349 328
350 /* We should bind the task to the CPU */ 329 /* We should bind the task to the CPU */
351 BUG_ON(raw_smp_processor_id() != cpu); 330 BUG_ON(raw_smp_processor_id() != cpu);
@@ -356,12 +335,17 @@ void microcode_update_cpu(int cpu)
356 * otherwise just request a firmware: 335 * otherwise just request a firmware:
357 */ 336 */
358 if (uci->valid) { 337 if (uci->valid) {
359 microcode_resume_cpu(cpu); 338 err = microcode_resume_cpu(cpu);
360 } else { 339 } else {
361 collect_cpu_info(cpu); 340 collect_cpu_info(cpu);
362 if (uci->valid && system_state == SYSTEM_RUNNING) 341 if (uci->valid && system_state == SYSTEM_RUNNING)
363 microcode_ops->cpu_request_microcode(cpu); 342 err = microcode_ops->request_microcode_fw(cpu,
343 &microcode_pdev->dev);
364 } 344 }
345
346 if (!err)
347 microcode_ops->apply_microcode(cpu);
348
365 mutex_unlock(&microcode_mutex); 349 mutex_unlock(&microcode_mutex);
366} 350}
367 351
@@ -414,7 +398,7 @@ static int mc_sysdev_resume(struct sys_device *dev)
414 return 0; 398 return 0;
415 pr_debug("microcode: CPU%d resumed\n", cpu); 399 pr_debug("microcode: CPU%d resumed\n", cpu);
416 /* only CPU 0 will apply ucode here */ 400 /* only CPU 0 will apply ucode here */
417 microcode_ops->apply_microcode(0); 401 microcode_update_cpu(0);
418 return 0; 402 return 0;
419} 403}
420 404
diff --git a/arch/x86/kernel/microcode_amd.c b/arch/x86/kernel/microcode_amd.c
index d606a05545ca..6815837a7753 100644
--- a/arch/x86/kernel/microcode_amd.c
+++ b/arch/x86/kernel/microcode_amd.c
@@ -59,7 +59,7 @@ MODULE_LICENSE("GPL v2");
59/* serialize access to the physical write */ 59/* serialize access to the physical write */
60static DEFINE_SPINLOCK(microcode_update_lock); 60static DEFINE_SPINLOCK(microcode_update_lock);
61 61
62struct equiv_cpu_entry *equiv_cpu_table; 62static struct equiv_cpu_entry *equiv_cpu_table;
63 63
64static int collect_cpu_info_amd(int cpu, struct cpu_signature *csig) 64static int collect_cpu_info_amd(int cpu, struct cpu_signature *csig)
65{ 65{
@@ -83,36 +83,37 @@ static int collect_cpu_info_amd(int cpu, struct cpu_signature *csig)
83 return 0; 83 return 0;
84} 84}
85 85
86static int get_matching_microcode_amd(void *mc, int cpu) 86static int get_matching_microcode(int cpu, void *mc, int rev)
87{ 87{
88 struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
89 struct microcode_header_amd *mc_header = mc; 88 struct microcode_header_amd *mc_header = mc;
90 unsigned long total_size = get_totalsize(mc_header);
91 void *new_mc;
92 struct pci_dev *nb_pci_dev, *sb_pci_dev; 89 struct pci_dev *nb_pci_dev, *sb_pci_dev;
93 unsigned int current_cpu_id; 90 unsigned int current_cpu_id;
94 unsigned int equiv_cpu_id = 0x00; 91 unsigned int equiv_cpu_id = 0x00;
95 unsigned int i = 0; 92 unsigned int i = 0;
96 93
97 /* We should bind the task to the CPU */ 94 /*
98 BUG_ON(cpu != raw_smp_processor_id()); 95 * dimm: do we need this? Why an update via /dev/... is different
99 96 * from the one via firmware?
100 /* This is a tricky part. We might be called from a write operation */ 97 *
101 /* to the device file instead of the usual process of firmware */ 98 * This is a tricky part. We might be called from a write operation
102 /* loading. This routine needs to be able to distinguish both */ 99 * to the device file instead of the usual process of firmware
103/* cases. This is done by checking if there alread is a equivalent */ 100 * loading. This routine needs to be able to distinguish both
104 /* CPU table installed. If not, we're written through */ 101 * cases. This is done by checking if there alread is a equivalent
105 /* /dev/cpu/microcode. */ 102 * CPU table installed. If not, we're written through
106/* Since we ignore all checks. The error case in which going through */ 103 * /dev/cpu/microcode.
107/* firmware loading and that table is not loaded has already been */ 104 * Since we ignore all checks. The error case in which going through
108 /* checked earlier. */ 105 * firmware loading and that table is not loaded has already been
106 * checked earlier.
107 */
108 BUG_ON(equiv_cpu_table == NULL);
109#if 0
109 if (equiv_cpu_table == NULL) { 110 if (equiv_cpu_table == NULL) {
110 printk(KERN_INFO "microcode: CPU%d microcode update with " 111 printk(KERN_INFO "microcode: CPU%d microcode update with "
111 "version 0x%x (current=0x%x)\n", 112 "version 0x%x (current=0x%x)\n",
112 cpu, mc_header->patch_id, uci->cpu_sig.rev); 113 cpu, mc_header->patch_id, uci->cpu_sig.rev);
113 goto out; 114 goto out;
114 } 115 }
115 116#endif
116 current_cpu_id = cpuid_eax(0x00000001); 117 current_cpu_id = cpuid_eax(0x00000001);
117 118
118 while (equiv_cpu_table[i].installed_cpu != 0) { 119 while (equiv_cpu_table[i].installed_cpu != 0) {
@@ -175,27 +176,9 @@ static int get_matching_microcode_amd(void *mc, int cpu)
175 pci_dev_put(sb_pci_dev); 176 pci_dev_put(sb_pci_dev);
176 } 177 }
177 178
178 if (mc_header->patch_id <= uci->cpu_sig.rev) 179 if (mc_header->patch_id <= rev)
179 return 0; 180 return 0;
180 181
181 printk(KERN_INFO "microcode: CPU%d found a matching microcode "
182 "update with version 0x%x (current=0x%x)\n",
183 cpu, mc_header->patch_id, uci->cpu_sig.rev);
184
185out:
186 new_mc = vmalloc(UCODE_MAX_SIZE);
187 if (!new_mc) {
188 printk(KERN_ERR "microcode: error, can't allocate memory\n");
189 return -ENOMEM;
190 }
191 memset(new_mc, 0, UCODE_MAX_SIZE);
192
193 /* free previous update file */
194 vfree(uci->mc.mc_amd);
195
196 memcpy(new_mc, mc, total_size);
197
198 uci->mc.mc_amd = new_mc;
199 return 1; 182 return 1;
200} 183}
201 184
@@ -245,104 +228,65 @@ static void apply_microcode_amd(int cpu)
245 uci->cpu_sig.rev = rev; 228 uci->cpu_sig.rev = rev;
246} 229}
247 230
248#ifdef CONFIG_MICROCODE_OLD_INTERFACE 231static void * get_next_ucode(u8 *buf, unsigned int size,
249extern void __user *user_buffer; /* user area microcode data buffer */ 232 int (*get_ucode_data)(void *, const void *, size_t),
250extern unsigned int user_buffer_size; /* it's size */ 233 unsigned int *mc_size)
251
252static long get_next_ucode_amd(void **mc, long offset)
253{
254 struct microcode_header_amd mc_header;
255 unsigned long total_size;
256
257 /* No more data */
258 if (offset >= user_buffer_size)
259 return 0;
260 if (copy_from_user(&mc_header, user_buffer + offset, MC_HEADER_SIZE)) {
261 printk(KERN_ERR "microcode: error! Can not read user data\n");
262 return -EFAULT;
263 }
264 total_size = get_totalsize(&mc_header);
265 if (offset + total_size > user_buffer_size) {
266 printk(KERN_ERR "microcode: error! Bad total size in microcode "
267 "data file\n");
268 return -EINVAL;
269 }
270 *mc = vmalloc(UCODE_MAX_SIZE);
271 if (!*mc)
272 return -ENOMEM;
273 memset(*mc, 0, UCODE_MAX_SIZE);
274
275 if (copy_from_user(*mc, user_buffer + offset, total_size)) {
276 printk(KERN_ERR "microcode: error! Can not read user data\n");
277 vfree(*mc);
278 return -EFAULT;
279 }
280 return offset + total_size;
281}
282#else
283#define get_next_ucode_amd() NULL
284#endif
285
286static long get_next_ucode_from_buffer_amd(void **mc, void *buf,
287 unsigned long size, long offset)
288{ 234{
289 struct microcode_header_amd *mc_header; 235 unsigned int total_size;
290 unsigned long total_size; 236#define UCODE_UNKNOWN_HDR 8
291 unsigned char *buf_pos = buf; 237 u8 hdr[UCODE_UNKNOWN_HDR];
238 void *mc;
292 239
293 /* No more data */ 240 if (get_ucode_data(hdr, buf, UCODE_UNKNOWN_HDR))
294 if (offset >= size) 241 return NULL;
295 return 0;
296 242
297 if (buf_pos[offset] != UCODE_UCODE_TYPE) { 243 if (hdr[0] != UCODE_UCODE_TYPE) {
298 printk(KERN_ERR "microcode: error! " 244 printk(KERN_ERR "microcode: error! "
299 "Wrong microcode payload type field\n"); 245 "Wrong microcode payload type field\n");
300 return -EINVAL; 246 return NULL;
301 } 247 }
302 248
303 mc_header = (struct microcode_header_amd *)(&buf_pos[offset+8]); 249 /* Why not by means of get_totalsize(hdr)? */
250 total_size = (unsigned long) (hdr[4] + (hdr[5] << 8));
304 251
305 total_size = (unsigned long) (buf_pos[offset+4] + 252 printk(KERN_INFO "microcode: size %u, total_size %u\n",
306 (buf_pos[offset+5] << 8)); 253 size, total_size);
307 254
308 printk(KERN_INFO "microcode: size %lu, total_size %lu, offset %ld\n", 255 if (total_size > size || total_size > UCODE_MAX_SIZE) {
309 size, total_size, offset);
310
311 if (offset + total_size > size) {
312 printk(KERN_ERR "microcode: error! Bad data in microcode data file\n"); 256 printk(KERN_ERR "microcode: error! Bad data in microcode data file\n");
313 return -EINVAL; 257 return NULL;
314 } 258 }
315 259
316 *mc = vmalloc(UCODE_MAX_SIZE); 260 mc = vmalloc(UCODE_MAX_SIZE);
317 if (!*mc) { 261 if (mc) {
318 printk(KERN_ERR "microcode: error! " 262 memset(mc, 0, UCODE_MAX_SIZE);
319 "Can not allocate memory for microcode patch\n"); 263 if (get_ucode_data(mc, buf + UCODE_UNKNOWN_HDR, total_size)) {
320 return -ENOMEM; 264 vfree(mc);
265 mc = NULL;
266 } else
267 *mc_size = total_size + UCODE_UNKNOWN_HDR;
321 } 268 }
322 269#undef UCODE_UNKNOWN_HDR
323 memset(*mc, 0, UCODE_MAX_SIZE); 270 return mc;
324 memcpy(*mc, buf + offset + 8, total_size);
325
326 return offset + total_size + 8;
327} 271}
328 272
329static long install_equiv_cpu_table(void *buf, unsigned long size, long offset) 273
274static int install_equiv_cpu_table(u8 *buf,
275 int (*get_ucode_data)(void *, const void *, size_t))
330{ 276{
331 unsigned int *buf_pos = buf; 277#define UCODE_HEADER_SIZE 12
278 u8 *hdr[UCODE_HEADER_SIZE];
279 unsigned int *buf_pos = (unsigned int *)hdr;
280 unsigned long size;
332 281
333 /* No more data */ 282 if (get_ucode_data(&hdr, buf, UCODE_HEADER_SIZE))
334 if (offset >= size)
335 return 0; 283 return 0;
336 284
337 if (buf_pos[1] != UCODE_EQUIV_CPU_TABLE_TYPE) { 285 size = buf_pos[2];
338 printk(KERN_ERR "microcode: error! "
339 "Wrong microcode equivalnet cpu table type field\n");
340 return 0;
341 }
342 286
343 if (size == 0) { 287 if (buf_pos[1] != UCODE_EQUIV_CPU_TABLE_TYPE || !size) {
344 printk(KERN_ERR "microcode: error! " 288 printk(KERN_ERR "microcode: error! "
345 "Wrong microcode equivalnet cpu table length\n"); 289 "Wrong microcode equivalnet cpu table\n");
346 return 0; 290 return 0;
347 } 291 }
348 292
@@ -352,79 +296,118 @@ static long install_equiv_cpu_table(void *buf, unsigned long size, long offset)
352 return 0; 296 return 0;
353 } 297 }
354 298
355 memset(equiv_cpu_table, 0, size); 299 buf += UCODE_HEADER_SIZE;
356 memcpy(equiv_cpu_table, &buf_pos[3], size); 300 if (get_ucode_data(equiv_cpu_table, buf, size)) {
301 vfree(equiv_cpu_table);
302 return 0;
303 }
357 304
358 return size + 12; /* add header length */ 305 return size + UCODE_HEADER_SIZE; /* add header length */
306#undef UCODE_HEADER_SIZE
359} 307}
360 308
361/* fake device for request_firmware */ 309static void free_equiv_cpu_table(void)
362extern struct platform_device *microcode_pdev;
363
364static int cpu_request_microcode_amd(int cpu)
365{ 310{
366 char name[30]; 311 if (equiv_cpu_table) {
367 const struct firmware *firmware; 312 vfree(equiv_cpu_table);
368 void *buf; 313 equiv_cpu_table = NULL;
369 unsigned int *buf_pos;
370 unsigned long size;
371 long offset = 0;
372 int error;
373 void *mc;
374
375 /* We should bind the task to the CPU */
376 BUG_ON(cpu != raw_smp_processor_id());
377
378 sprintf(name, "amd-ucode/microcode_amd.bin");
379 error = request_firmware(&firmware, "amd-ucode/microcode_amd.bin",
380 &microcode_pdev->dev);
381 if (error) {
382 printk(KERN_ERR "microcode: ucode data file %s load failed\n",
383 name);
384 return error;
385 }
386
387 buf_pos = (unsigned int *)firmware->data;
388 buf = (void *)firmware->data;
389 size = firmware->size;
390
391 if (buf_pos[0] != UCODE_MAGIC) {
392 printk(KERN_ERR "microcode: error! Wrong microcode patch file magic\n");
393 return -EINVAL;
394 } 314 }
315}
395 316
396 offset = install_equiv_cpu_table(buf, buf_pos[2], offset); 317static int generic_load_microcode(int cpu, void *data, size_t size,
318 int (*get_ucode_data)(void *, const void *, size_t))
319{
320 struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
321 u8 *ucode_ptr = data, *new_mc = NULL, *mc;
322 int new_rev = uci->cpu_sig.rev;
323 unsigned int leftover;
324 unsigned long offset;
397 325
326 offset = install_equiv_cpu_table(ucode_ptr, get_ucode_data);
398 if (!offset) { 327 if (!offset) {
399 printk(KERN_ERR "microcode: installing equivalent cpu table failed\n"); 328 printk(KERN_ERR "microcode: installing equivalent cpu table failed\n");
400 return -EINVAL; 329 return -EINVAL;
401 } 330 }
402 331
403 while ((offset = 332 ucode_ptr += offset;
404 get_next_ucode_from_buffer_amd(&mc, buf, size, offset)) > 0) { 333 leftover = size - offset;
405 error = get_matching_microcode_amd(mc, cpu); 334
406 if (error < 0) 335 while (leftover) {
336 unsigned int mc_size;
337 struct microcode_header_amd *mc_header;
338
339 mc = get_next_ucode(ucode_ptr, leftover, get_ucode_data, &mc_size);
340 if (!mc)
407 break; 341 break;
408 /* 342
409 * It's possible the data file has multiple matching ucode, 343 mc_header = (struct microcode_header_amd *)mc;
410 * lets keep searching till the latest version 344 if (get_matching_microcode(cpu, mc, new_rev)) {
411 */ 345 new_rev = mc_header->patch_id;
412 if (error == 1) { 346 new_mc = mc;
413 apply_microcode_amd(cpu); 347 } else
414 error = 0; 348 vfree(mc);
415 } 349
416 vfree(mc); 350 ucode_ptr += mc_size;
351 leftover -= mc_size;
417 } 352 }
418 if (offset > 0) { 353
419 vfree(mc); 354 if (new_mc) {
420 vfree(equiv_cpu_table); 355 if (!leftover) {
421 equiv_cpu_table = NULL; 356 if (uci->mc.mc_amd)
357 vfree(uci->mc.mc_amd);
358 uci->mc.mc_amd = (struct microcode_amd *)new_mc;
359 pr_debug("microcode: CPU%d found a matching microcode update with"
360 " version 0x%x (current=0x%x)\n",
361 cpu, uci->mc.mc_amd->hdr.patch_id, uci->cpu_sig.rev);
362 } else
363 vfree(new_mc);
422 } 364 }
423 if (offset < 0) 365
424 error = offset; 366 free_equiv_cpu_table();
367
368 return (int)leftover;
369}
370
371static int get_ucode_fw(void *to, const void *from, size_t n)
372{
373 memcpy(to, from, n);
374 return 0;
375}
376
377static int request_microcode_fw(int cpu, struct device *device)
378{
379 const char *fw_name = "amd-ucode/microcode_amd.bin";
380 const struct firmware *firmware;
381 int ret;
382
383 /* We should bind the task to the CPU */
384 BUG_ON(cpu != raw_smp_processor_id());
385
386 ret = request_firmware(&firmware, fw_name, device);
387 if (ret) {
388 printk(KERN_ERR "microcode: ucode data file %s load failed\n", fw_name);
389 return ret;
390 }
391
392 ret = generic_load_microcode(cpu, (void*)firmware->data, firmware->size,
393 &get_ucode_fw);
394
425 release_firmware(firmware); 395 release_firmware(firmware);
426 396
427 return error; 397 return ret;
398}
399
400static int get_ucode_user(void *to, const void *from, size_t n)
401{
402 return copy_from_user(to, from, n);
403}
404
405static int request_microcode_user(int cpu, const void __user *buf, size_t size)
406{
407 /* We should bind the task to the CPU */
408 BUG_ON(cpu != raw_smp_processor_id());
409
410 return generic_load_microcode(cpu, (void*)buf, size, &get_ucode_user);
428} 411}
429 412
430static void microcode_fini_cpu_amd(int cpu) 413static void microcode_fini_cpu_amd(int cpu)
@@ -436,10 +419,8 @@ static void microcode_fini_cpu_amd(int cpu)
436} 419}
437 420
438static struct microcode_ops microcode_amd_ops = { 421static struct microcode_ops microcode_amd_ops = {
439 .get_next_ucode = get_next_ucode_amd, 422 .request_microcode_user = request_microcode_user,
440 .get_matching_microcode = get_matching_microcode_amd, 423 .request_microcode_fw = request_microcode_fw,
441 .microcode_sanity_check = NULL,
442 .cpu_request_microcode = cpu_request_microcode_amd,
443 .collect_cpu_info = collect_cpu_info_amd, 424 .collect_cpu_info = collect_cpu_info_amd,
444 .apply_microcode = apply_microcode_amd, 425 .apply_microcode = apply_microcode_amd,
445 .microcode_fini_cpu = microcode_fini_cpu_amd, 426 .microcode_fini_cpu = microcode_fini_cpu_amd,
diff --git a/arch/x86/kernel/microcode_intel.c b/arch/x86/kernel/microcode_intel.c
index c9b53202ba3d..f4930b55c6a0 100644
--- a/arch/x86/kernel/microcode_intel.c
+++ b/arch/x86/kernel/microcode_intel.c
@@ -155,15 +155,15 @@ static int collect_cpu_info(int cpu_num, struct cpu_signature *csig)
155 return 0; 155 return 0;
156} 156}
157 157
158static inline int microcode_update_match(int cpu_num, 158static inline int update_match_cpu(struct cpu_signature *csig, int sig, int pf)
159 struct microcode_header_intel *mc_header, int sig, int pf)
160{ 159{
161 struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num; 160 return (!sigmatch(sig, csig->sig, pf, csig->pf)) ? 0 : 1;
161}
162 162
163 if (!sigmatch(sig, uci->cpu_sig.sig, pf, uci->cpu_sig.pf) 163static inline int
164 || mc_header->rev <= uci->cpu_sig.rev) 164update_match_revision(struct microcode_header_intel *mc_header, int rev)
165 return 0; 165{
166 return 1; 166 return (mc_header->rev <= rev) ? 0 : 1;
167} 167}
168 168
169static int microcode_sanity_check(void *mc) 169static int microcode_sanity_check(void *mc)
@@ -248,51 +248,36 @@ static int microcode_sanity_check(void *mc)
248/* 248/*
249 * return 0 - no update found 249 * return 0 - no update found
250 * return 1 - found update 250 * return 1 - found update
251 * return < 0 - error
252 */ 251 */
253static int get_matching_microcode(void *mc, int cpu) 252static int
253get_matching_microcode(struct cpu_signature *cpu_sig, void *mc, int rev)
254{ 254{
255 struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
256 struct microcode_header_intel *mc_header = mc; 255 struct microcode_header_intel *mc_header = mc;
257 struct extended_sigtable *ext_header; 256 struct extended_sigtable *ext_header;
258 unsigned long total_size = get_totalsize(mc_header); 257 unsigned long total_size = get_totalsize(mc_header);
259 int ext_sigcount, i; 258 int ext_sigcount, i;
260 struct extended_signature *ext_sig; 259 struct extended_signature *ext_sig;
261 void *new_mc;
262 260
263 if (microcode_update_match(cpu, mc_header, 261 if (!update_match_revision(mc_header, rev))
264 mc_header->sig, mc_header->pf)) 262 return 0;
265 goto find; 263
264 if (update_match_cpu(cpu_sig, mc_header->sig, mc_header->pf))
265 return 1;
266 266
267 /* Look for ext. headers: */
267 if (total_size <= get_datasize(mc_header) + MC_HEADER_SIZE) 268 if (total_size <= get_datasize(mc_header) + MC_HEADER_SIZE)
268 return 0; 269 return 0;
269 270
270 ext_header = mc + get_datasize(mc_header) + MC_HEADER_SIZE; 271 ext_header = mc + get_datasize(mc_header) + MC_HEADER_SIZE;
271 ext_sigcount = ext_header->count; 272 ext_sigcount = ext_header->count;
272 ext_sig = (void *)ext_header + EXT_HEADER_SIZE; 273 ext_sig = (void *)ext_header + EXT_HEADER_SIZE;
274
273 for (i = 0; i < ext_sigcount; i++) { 275 for (i = 0; i < ext_sigcount; i++) {
274 if (microcode_update_match(cpu, mc_header, 276 if (update_match_cpu(cpu_sig, ext_sig->sig, ext_sig->pf))
275 ext_sig->sig, ext_sig->pf)) 277 return 1;
276 goto find;
277 ext_sig++; 278 ext_sig++;
278 } 279 }
279 return 0; 280 return 0;
280find:
281 pr_debug("microcode: CPU%d found a matching microcode update with"
282 " version 0x%x (current=0x%x)\n",
283 cpu, mc_header->rev, uci->cpu_sig.rev);
284 new_mc = vmalloc(total_size);
285 if (!new_mc) {
286 printk(KERN_ERR "microcode: error! Can not allocate memory\n");
287 return -ENOMEM;
288 }
289
290 /* free previous update file */
291 vfree(uci->mc.mc_intel);
292
293 memcpy(new_mc, mc, total_size);
294 uci->mc.mc_intel = new_mc;
295 return 1;
296} 281}
297 282
298static void apply_microcode(int cpu) 283static void apply_microcode(int cpu)
@@ -300,7 +285,7 @@ static void apply_microcode(int cpu)
300 unsigned long flags; 285 unsigned long flags;
301 unsigned int val[2]; 286 unsigned int val[2];
302 int cpu_num = raw_smp_processor_id(); 287 int cpu_num = raw_smp_processor_id();
303 struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num; 288 struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
304 289
305 /* We should bind the task to the CPU */ 290 /* We should bind the task to the CPU */
306 BUG_ON(cpu_num != cpu); 291 BUG_ON(cpu_num != cpu);
@@ -338,116 +323,105 @@ static void apply_microcode(int cpu)
338 uci->cpu_sig.rev = val[1]; 323 uci->cpu_sig.rev = val[1];
339} 324}
340 325
341#ifdef CONFIG_MICROCODE_OLD_INTERFACE 326static int generic_load_microcode(int cpu, void *data, size_t size,
342extern void __user *user_buffer; /* user area microcode data buffer */ 327 int (*get_ucode_data)(void *, const void *, size_t))
343extern unsigned int user_buffer_size; /* it's size */
344
345static long get_next_ucode(void **mc, long offset)
346{ 328{
347 struct microcode_header_intel mc_header; 329 struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
348 unsigned long total_size; 330 u8 *ucode_ptr = data, *new_mc = NULL, *mc;
331 int new_rev = uci->cpu_sig.rev;
332 unsigned int leftover = size;
349 333
350 /* No more data */ 334 while (leftover) {
351 if (offset >= user_buffer_size) 335 struct microcode_header_intel mc_header;
352 return 0; 336 unsigned int mc_size;
353 if (copy_from_user(&mc_header, user_buffer + offset, MC_HEADER_SIZE)) {
354 printk(KERN_ERR "microcode: error! Can not read user data\n");
355 return -EFAULT;
356 }
357 total_size = get_totalsize(&mc_header);
358 if (offset + total_size > user_buffer_size) {
359 printk(KERN_ERR "microcode: error! Bad total size in microcode "
360 "data file\n");
361 return -EINVAL;
362 }
363 *mc = vmalloc(total_size);
364 if (!*mc)
365 return -ENOMEM;
366 if (copy_from_user(*mc, user_buffer + offset, total_size)) {
367 printk(KERN_ERR "microcode: error! Can not read user data\n");
368 vfree(*mc);
369 return -EFAULT;
370 }
371 return offset + total_size;
372}
373#endif
374 337
375static long get_next_ucode_from_buffer(void **mc, const u8 *buf, 338 if (get_ucode_data(&mc_header, ucode_ptr, sizeof(mc_header)))
376 unsigned long size, long offset) 339 break;
377{
378 struct microcode_header_intel *mc_header;
379 unsigned long total_size;
380 340
381 /* No more data */ 341 mc_size = get_totalsize(&mc_header);
382 if (offset >= size) 342 if (!mc_size || mc_size > leftover) {
383 return 0; 343 printk(KERN_ERR "microcode: error!"
384 mc_header = (struct microcode_header_intel *)(buf + offset); 344 "Bad data in microcode data file\n");
385 total_size = get_totalsize(mc_header); 345 break;
346 }
386 347
387 if (offset + total_size > size) { 348 mc = vmalloc(mc_size);
388 printk(KERN_ERR "microcode: error! Bad data in microcode data file\n"); 349 if (!mc)
389 return -EINVAL; 350 break;
351
352 if (get_ucode_data(mc, ucode_ptr, mc_size) ||
353 microcode_sanity_check(mc) < 0) {
354 vfree(mc);
355 break;
356 }
357
358 if (get_matching_microcode(&uci->cpu_sig, mc, new_rev)) {
359 new_rev = mc_header.rev;
360 new_mc = mc;
361 } else
362 vfree(mc);
363
364 ucode_ptr += mc_size;
365 leftover -= mc_size;
390 } 366 }
391 367
392 *mc = vmalloc(total_size); 368 if (new_mc) {
393 if (!*mc) { 369 if (!leftover) {
394 printk(KERN_ERR "microcode: error! Can not allocate memory\n"); 370 if (uci->mc.mc_intel)
395 return -ENOMEM; 371 vfree(uci->mc.mc_intel);
372 uci->mc.mc_intel = (struct microcode_intel *)new_mc;
373 pr_debug("microcode: CPU%d found a matching microcode update with"
374 " version 0x%x (current=0x%x)\n",
375 cpu, uci->mc.mc_intel->hdr.rev, uci->cpu_sig.rev);
376 } else
377 vfree(new_mc);
396 } 378 }
397 memcpy(*mc, buf + offset, total_size); 379
398 return offset + total_size; 380 return (int)leftover;
399} 381}
400 382
401/* fake device for request_firmware */ 383static int get_ucode_fw(void *to, const void *from, size_t n)
402extern struct platform_device *microcode_pdev; 384{
385 memcpy(to, from, n);
386 return 0;
387}
403 388
404static int cpu_request_microcode(int cpu) 389static int request_microcode_fw(int cpu, struct device *device)
405{ 390{
406 char name[30]; 391 char name[30];
407 struct cpuinfo_x86 *c = &cpu_data(cpu); 392 struct cpuinfo_x86 *c = &cpu_data(cpu);
408 const struct firmware *firmware; 393 const struct firmware *firmware;
409 const u8 *buf; 394 int ret;
410 unsigned long size;
411 long offset = 0;
412 int error;
413 void *mc;
414 395
415 /* We should bind the task to the CPU */ 396 /* We should bind the task to the CPU */
416 BUG_ON(cpu != raw_smp_processor_id()); 397 BUG_ON(cpu != raw_smp_processor_id());
417 sprintf(name, "intel-ucode/%02x-%02x-%02x", 398 sprintf(name, "intel-ucode/%02x-%02x-%02x",
418 c->x86, c->x86_model, c->x86_mask); 399 c->x86, c->x86_model, c->x86_mask);
419 error = request_firmware(&firmware, name, &microcode_pdev->dev); 400 ret = request_firmware(&firmware, name, device);
420 if (error) { 401 if (ret) {
421 pr_debug("microcode: data file %s load failed\n", name); 402 pr_debug("microcode: data file %s load failed\n", name);
422 return error; 403 return ret;
423 }
424 buf = firmware->data;
425 size = firmware->size;
426 while ((offset = get_next_ucode_from_buffer(&mc, buf, size, offset))
427 > 0) {
428 error = microcode_sanity_check(mc);
429 if (error)
430 break;
431 error = get_matching_microcode(mc, cpu);
432 if (error < 0)
433 break;
434 /*
435 * It's possible the data file has multiple matching ucode,
436 * lets keep searching till the latest version
437 */
438 if (error == 1) {
439 apply_microcode(cpu);
440 error = 0;
441 }
442 vfree(mc);
443 } 404 }
444 if (offset > 0) 405
445 vfree(mc); 406 ret = generic_load_microcode(cpu, (void*)firmware->data, firmware->size,
446 if (offset < 0) 407 &get_ucode_fw);
447 error = offset; 408
448 release_firmware(firmware); 409 release_firmware(firmware);
449 410
450 return error; 411 return ret;
412}
413
414static int get_ucode_user(void *to, const void *from, size_t n)
415{
416 return copy_from_user(to, from, n);
417}
418
419static int request_microcode_user(int cpu, const void __user *buf, size_t size)
420{
421 /* We should bind the task to the CPU */
422 BUG_ON(cpu != raw_smp_processor_id());
423
424 return generic_load_microcode(cpu, (void*)buf, size, &get_ucode_user);
451} 425}
452 426
453static void microcode_fini_cpu(int cpu) 427static void microcode_fini_cpu(int cpu)
@@ -459,10 +433,8 @@ static void microcode_fini_cpu(int cpu)
459} 433}
460 434
461static struct microcode_ops microcode_intel_ops = { 435static struct microcode_ops microcode_intel_ops = {
462 .get_next_ucode = get_next_ucode, 436 .request_microcode_user = request_microcode_user,
463 .get_matching_microcode = get_matching_microcode, 437 .request_microcode_fw = request_microcode_fw,
464 .microcode_sanity_check = microcode_sanity_check,
465 .cpu_request_microcode = cpu_request_microcode,
466 .collect_cpu_info = collect_cpu_info, 438 .collect_cpu_info = collect_cpu_info,
467 .apply_microcode = apply_microcode, 439 .apply_microcode = apply_microcode,
468 .microcode_fini_cpu = microcode_fini_cpu, 440 .microcode_fini_cpu = microcode_fini_cpu,