aboutsummaryrefslogtreecommitdiffstats
path: root/arch/i386/kernel
diff options
context:
space:
mode:
authorShaohua Li <shaohua.li@intel.com>2006-09-27 04:50:52 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-09-27 11:26:18 -0400
commita30a6a2cb0fdc2c9701d6ddfb21affeb8146c038 (patch)
tree72502de7266fbed2e4791cc162ef7607710f7cd0 /arch/i386/kernel
parent9a3110bf4bb0466b43b898533bfd4952001bc38f (diff)
[PATCH] x86 microcode: using request_firmware to pull microcode
Using request_firmware to pull ucode from userspace, so we don't need the application 'microcode_ctl' to assist. We name each ucode file according to CPU's info as intel-ucode/family-model-stepping. In this way we could split ucode file as small one. This has a lot of advantages such as selectively update and validate microcode for specific models, better manage microcode file, easily write tools for administerators and so on. with the changes, we should put all intel-ucode/xx-xx-xx microcode files into the firmware dir (I had a tool to split previous big data file into small one and later we will release new style data file). The init script should be changed to just loading the driver without unloading Signed-off-by: Shaohua Li <shaohua.li@intel.com> Acked-by: Tigran Aivazian <tigran@veritas.com> Cc: Greg KH <greg@kroah.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch/i386/kernel')
-rw-r--r--arch/i386/kernel/microcode.c116
1 files changed, 116 insertions, 0 deletions
diff --git a/arch/i386/kernel/microcode.c b/arch/i386/kernel/microcode.c
index 00bdc3dd693e..f8f1ec5f26c1 100644
--- a/arch/i386/kernel/microcode.c
+++ b/arch/i386/kernel/microcode.c
@@ -83,6 +83,9 @@
83#include <linux/spinlock.h> 83#include <linux/spinlock.h>
84#include <linux/mm.h> 84#include <linux/mm.h>
85#include <linux/mutex.h> 85#include <linux/mutex.h>
86#include <linux/cpu.h>
87#include <linux/firmware.h>
88#include <linux/platform_device.h>
86 89
87#include <asm/msr.h> 90#include <asm/msr.h>
88#include <asm/uaccess.h> 91#include <asm/uaccess.h>
@@ -493,6 +496,112 @@ MODULE_ALIAS_MISCDEV(MICROCODE_MINOR);
493#define microcode_dev_exit() do { } while(0) 496#define microcode_dev_exit() do { } while(0)
494#endif 497#endif
495 498
499static long get_next_ucode_from_buffer(void **mc, void *buf,
500 unsigned long size, long offset)
501{
502 microcode_header_t *mc_header;
503 unsigned long total_size;
504
505 /* No more data */
506 if (offset >= size)
507 return 0;
508 mc_header = (microcode_header_t *)(buf + offset);
509 total_size = get_totalsize(mc_header);
510
511 if ((offset + total_size > size)
512 || (total_size < DEFAULT_UCODE_TOTALSIZE)) {
513 printk(KERN_ERR "microcode: error! Bad data in microcode data file\n");
514 return -EINVAL;
515 }
516
517 *mc = vmalloc(total_size);
518 if (!*mc) {
519 printk(KERN_ERR "microcode: error! Can not allocate memory\n");
520 return -ENOMEM;
521 }
522 memcpy(*mc, buf + offset, total_size);
523 return offset + total_size;
524}
525
526/* fake device for request_firmware */
527static struct platform_device *microcode_pdev;
528
529static int cpu_request_microcode(int cpu)
530{
531 char name[30];
532 struct cpuinfo_x86 *c = cpu_data + cpu;
533 const struct firmware *firmware;
534 void * buf;
535 unsigned long size;
536 long offset = 0;
537 int error;
538 void *mc;
539
540 /* We should bind the task to the CPU */
541 BUG_ON(cpu != raw_smp_processor_id());
542 sprintf(name,"intel-ucode/%02x-%02x-%02x",
543 c->x86, c->x86_model, c->x86_mask);
544 error = request_firmware(&firmware, name, &microcode_pdev->dev);
545 if (error) {
546 pr_debug("ucode data file %s load failed\n", name);
547 return error;
548 }
549 buf = (void *)firmware->data;
550 size = firmware->size;
551 while ((offset = get_next_ucode_from_buffer(&mc, buf, size, offset))
552 > 0) {
553 error = microcode_sanity_check(mc);
554 if (error)
555 break;
556 error = get_maching_microcode(mc, cpu);
557 if (error < 0)
558 break;
559 /*
560 * It's possible the data file has multiple matching ucode,
561 * lets keep searching till the latest version
562 */
563 if (error == 1) {
564 apply_microcode(cpu);
565 error = 0;
566 }
567 vfree(mc);
568 }
569 if (offset > 0)
570 vfree(mc);
571 if (offset < 0)
572 error = offset;
573 release_firmware(firmware);
574
575 return error;
576}
577
578static void microcode_init_cpu(int cpu)
579{
580 cpumask_t old;
581 struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
582
583 old = current->cpus_allowed;
584
585 set_cpus_allowed(current, cpumask_of_cpu(cpu));
586 mutex_lock(&microcode_mutex);
587 collect_cpu_info(cpu);
588 if (uci->valid)
589 cpu_request_microcode(cpu);
590 mutex_unlock(&microcode_mutex);
591 set_cpus_allowed(current, old);
592}
593
594static void microcode_fini_cpu(int cpu)
595{
596 struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
597
598 mutex_lock(&microcode_mutex);
599 uci->valid = 0;
600 vfree(uci->mc);
601 uci->mc = NULL;
602 mutex_unlock(&microcode_mutex);
603}
604
496static int __init microcode_init (void) 605static int __init microcode_init (void)
497{ 606{
498 int error; 607 int error;
@@ -500,6 +609,12 @@ static int __init microcode_init (void)
500 error = microcode_dev_init(); 609 error = microcode_dev_init();
501 if (error) 610 if (error)
502 return error; 611 return error;
612 microcode_pdev = platform_device_register_simple("microcode", -1,
613 NULL, 0);
614 if (IS_ERR(microcode_pdev)) {
615 microcode_dev_exit();
616 return PTR_ERR(microcode_pdev);
617 }
503 618
504 printk(KERN_INFO 619 printk(KERN_INFO
505 "IA-32 Microcode Update Driver: v" MICROCODE_VERSION " <tigran@veritas.com>\n"); 620 "IA-32 Microcode Update Driver: v" MICROCODE_VERSION " <tigran@veritas.com>\n");
@@ -509,6 +624,7 @@ static int __init microcode_init (void)
509static void __exit microcode_exit (void) 624static void __exit microcode_exit (void)
510{ 625{
511 microcode_dev_exit(); 626 microcode_dev_exit();
627 platform_device_unregister(microcode_pdev);
512} 628}
513 629
514module_init(microcode_init) 630module_init(microcode_init)