aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/microcode_intel.c
diff options
context:
space:
mode:
authorPeter Oruba <peter.oruba@amd.com>2008-07-28 12:44:17 -0400
committerIngo Molnar <mingo@elte.hu>2008-07-28 13:57:55 -0400
commit3e135d887c973b525d43fbb67dfc5972694882f6 (patch)
treef24650c6d57c72f4fe77b96b19d891bee6865349 /arch/x86/kernel/microcode_intel.c
parent1abae31096007cc993f67ae2576fe8f812270ad6 (diff)
x86: code split to two parts
Split off existing code into two seperate files. One file holds general code, the other file vendor specific parts. No functional changes, only refactoring. Temporarily Introduced a new module name 'ucode' for result, due to already taken name 'microcode'. Signed-off-by: Peter Oruba <peter.oruba@amd.com> Cc: Tigran Aivazian <tigran@aivazian.fsnet.co.uk> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/x86/kernel/microcode_intel.c')
-rw-r--r--arch/x86/kernel/microcode_intel.c387
1 files changed, 23 insertions, 364 deletions
diff --git a/arch/x86/kernel/microcode_intel.c b/arch/x86/kernel/microcode_intel.c
index 4e7b2f65fed6..eded0a154ea8 100644
--- a/arch/x86/kernel/microcode_intel.c
+++ b/arch/x86/kernel/microcode_intel.c
@@ -95,18 +95,16 @@
95#include <asm/processor.h> 95#include <asm/processor.h>
96#include <asm/microcode.h> 96#include <asm/microcode.h>
97 97
98MODULE_DESCRIPTION("Intel CPU (IA-32) Microcode Update Driver"); 98MODULE_DESCRIPTION("Microcode Update Driver");
99MODULE_AUTHOR("Tigran Aivazian <tigran@aivazian.fsnet.co.uk>"); 99MODULE_AUTHOR("Tigran Aivazian <tigran@aivazian.fsnet.co.uk>");
100MODULE_LICENSE("GPL"); 100MODULE_LICENSE("GPL");
101 101
102#define MICROCODE_VERSION "1.14a"
103
104#define DEFAULT_UCODE_DATASIZE (2000) /* 2000 bytes */ 102#define DEFAULT_UCODE_DATASIZE (2000) /* 2000 bytes */
105#define MC_HEADER_SIZE (sizeof (struct microcode_header)) /* 48 bytes */ 103#define MC_HEADER_SIZE (sizeof(struct microcode_header)) /* 48 bytes */
106#define DEFAULT_UCODE_TOTALSIZE (DEFAULT_UCODE_DATASIZE + MC_HEADER_SIZE) /* 2048 bytes */ 104#define DEFAULT_UCODE_TOTALSIZE (DEFAULT_UCODE_DATASIZE + MC_HEADER_SIZE) /* 2048 bytes */
107#define EXT_HEADER_SIZE (sizeof (struct extended_sigtable)) /* 20 bytes */ 105#define EXT_HEADER_SIZE (sizeof(struct extended_sigtable)) /* 20 bytes */
108#define EXT_SIGNATURE_SIZE (sizeof (struct extended_signature)) /* 12 bytes */ 106#define EXT_SIGNATURE_SIZE (sizeof(struct extended_signature)) /* 12 bytes */
109#define DWSIZE (sizeof (u32)) 107#define DWSIZE (sizeof(u32))
110#define get_totalsize(mc) \ 108#define get_totalsize(mc) \
111 (((struct microcode *)mc)->hdr.totalsize ? \ 109 (((struct microcode *)mc)->hdr.totalsize ? \
112 ((struct microcode *)mc)->hdr.totalsize : DEFAULT_UCODE_TOTALSIZE) 110 ((struct microcode *)mc)->hdr.totalsize : DEFAULT_UCODE_TOTALSIZE)
@@ -123,11 +121,11 @@ MODULE_LICENSE("GPL");
123static DEFINE_SPINLOCK(microcode_update_lock); 121static DEFINE_SPINLOCK(microcode_update_lock);
124 122
125/* no concurrent ->write()s are allowed on /dev/cpu/microcode */ 123/* no concurrent ->write()s are allowed on /dev/cpu/microcode */
126static DEFINE_MUTEX(microcode_mutex); 124extern struct mutex microcode_mutex;
127 125
128static struct ucode_cpu_info ucode_cpu_info[NR_CPUS]; 126extern struct ucode_cpu_info ucode_cpu_info[NR_CPUS];
129 127
130static void collect_cpu_info(int cpu_num) 128void collect_cpu_info(int cpu_num)
131{ 129{
132 struct cpuinfo_x86 *c = &cpu_data(cpu_num); 130 struct cpuinfo_x86 *c = &cpu_data(cpu_num);
133 struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num; 131 struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num;
@@ -140,7 +138,7 @@ static void collect_cpu_info(int cpu_num)
140 uci->valid = 1; 138 uci->valid = 1;
141 139
142 if (c->x86_vendor != X86_VENDOR_INTEL || c->x86 < 6 || 140 if (c->x86_vendor != X86_VENDOR_INTEL || c->x86 < 6 ||
143 cpu_has(c, X86_FEATURE_IA64)) { 141 cpu_has(c, X86_FEATURE_IA64)) {
144 printk(KERN_ERR "microcode: CPU%d not a capable Intel " 142 printk(KERN_ERR "microcode: CPU%d not a capable Intel "
145 "processor\n", cpu_num); 143 "processor\n", cpu_num);
146 uci->valid = 0; 144 uci->valid = 0;
@@ -175,7 +173,7 @@ static inline int microcode_update_match(int cpu_num,
175 return 1; 173 return 1;
176} 174}
177 175
178static int microcode_sanity_check(void *mc) 176int microcode_sanity_check(void *mc)
179{ 177{
180 struct microcode_header *mc_header = mc; 178 struct microcode_header *mc_header = mc;
181 struct extended_sigtable *ext_header = NULL; 179 struct extended_sigtable *ext_header = NULL;
@@ -259,7 +257,7 @@ static int microcode_sanity_check(void *mc)
259 * return 1 - found update 257 * return 1 - found update
260 * return < 0 - error 258 * return < 0 - error
261 */ 259 */
262static int get_maching_microcode(void *mc, int cpu) 260int get_matching_microcode(void *mc, int cpu)
263{ 261{
264 struct ucode_cpu_info *uci = ucode_cpu_info + cpu; 262 struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
265 struct microcode_header *mc_header = mc; 263 struct microcode_header *mc_header = mc;
@@ -288,7 +286,7 @@ static int get_maching_microcode(void *mc, int cpu)
288 return 0; 286 return 0;
289find: 287find:
290 pr_debug("microcode: CPU%d found a matching microcode update with" 288 pr_debug("microcode: CPU%d found a matching microcode update with"
291 " version 0x%x (current=0x%x)\n", cpu, mc_header->rev,uci->rev); 289 " version 0x%x (current=0x%x)\n", cpu, mc_header->rev, uci->rev);
292 new_mc = vmalloc(total_size); 290 new_mc = vmalloc(total_size);
293 if (!new_mc) { 291 if (!new_mc) {
294 printk(KERN_ERR "microcode: error! Can not allocate memory\n"); 292 printk(KERN_ERR "microcode: error! Can not allocate memory\n");
@@ -303,7 +301,7 @@ find:
303 return 1; 301 return 1;
304} 302}
305 303
306static void apply_microcode(int cpu) 304void apply_microcode(int cpu)
307{ 305{
308 unsigned long flags; 306 unsigned long flags;
309 unsigned int val[2]; 307 unsigned int val[2];
@@ -344,10 +342,10 @@ static void apply_microcode(int cpu)
344} 342}
345 343
346#ifdef CONFIG_MICROCODE_OLD_INTERFACE 344#ifdef CONFIG_MICROCODE_OLD_INTERFACE
347static void __user *user_buffer; /* user area microcode data buffer */ 345extern void __user *user_buffer; /* user area microcode data buffer */
348static unsigned int user_buffer_size; /* it's size */ 346extern unsigned int user_buffer_size; /* it's size */
349 347
350static long get_next_ucode(void **mc, long offset) 348long get_next_ucode(void **mc, long offset)
351{ 349{
352 struct microcode_header mc_header; 350 struct microcode_header mc_header;
353 unsigned long total_size; 351 unsigned long total_size;
@@ -375,117 +373,6 @@ static long get_next_ucode(void **mc, long offset)
375 } 373 }
376 return offset + total_size; 374 return offset + total_size;
377} 375}
378
379static int do_microcode_update (void)
380{
381 long cursor = 0;
382 int error = 0;
383 void *new_mc = NULL;
384 int cpu;
385 cpumask_t old;
386 cpumask_of_cpu_ptr_declare(newmask);
387
388 old = current->cpus_allowed;
389
390 while ((cursor = get_next_ucode(&new_mc, cursor)) > 0) {
391 error = microcode_sanity_check(new_mc);
392 if (error)
393 goto out;
394 /*
395 * It's possible the data file has multiple matching ucode,
396 * lets keep searching till the latest version
397 */
398 for_each_online_cpu(cpu) {
399 struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
400
401 if (!uci->valid)
402 continue;
403 cpumask_of_cpu_ptr_next(newmask, cpu);
404 set_cpus_allowed_ptr(current, newmask);
405 error = get_maching_microcode(new_mc, cpu);
406 if (error < 0)
407 goto out;
408 if (error == 1)
409 apply_microcode(cpu);
410 }
411 vfree(new_mc);
412 }
413out:
414 if (cursor > 0)
415 vfree(new_mc);
416 if (cursor < 0)
417 error = cursor;
418 set_cpus_allowed_ptr(current, &old);
419 return error;
420}
421
422static int microcode_open (struct inode *unused1, struct file *unused2)
423{
424 cycle_kernel_lock();
425 return capable(CAP_SYS_RAWIO) ? 0 : -EPERM;
426}
427
428static ssize_t microcode_write (struct file *file, const char __user *buf, size_t len, loff_t *ppos)
429{
430 ssize_t ret;
431
432 if ((len >> PAGE_SHIFT) > num_physpages) {
433 printk(KERN_ERR "microcode: too much data (max %ld pages)\n", num_physpages);
434 return -EINVAL;
435 }
436
437 get_online_cpus();
438 mutex_lock(&microcode_mutex);
439
440 user_buffer = (void __user *) buf;
441 user_buffer_size = (int) len;
442
443 ret = do_microcode_update();
444 if (!ret)
445 ret = (ssize_t)len;
446
447 mutex_unlock(&microcode_mutex);
448 put_online_cpus();
449
450 return ret;
451}
452
453static const struct file_operations microcode_fops = {
454 .owner = THIS_MODULE,
455 .write = microcode_write,
456 .open = microcode_open,
457};
458
459static struct miscdevice microcode_dev = {
460 .minor = MICROCODE_MINOR,
461 .name = "microcode",
462 .fops = &microcode_fops,
463};
464
465static int __init microcode_dev_init (void)
466{
467 int error;
468
469 error = misc_register(&microcode_dev);
470 if (error) {
471 printk(KERN_ERR
472 "microcode: can't misc_register on minor=%d\n",
473 MICROCODE_MINOR);
474 return error;
475 }
476
477 return 0;
478}
479
480static void microcode_dev_exit (void)
481{
482 misc_deregister(&microcode_dev);
483}
484
485MODULE_ALIAS_MISCDEV(MICROCODE_MINOR);
486#else
487#define microcode_dev_init() 0
488#define microcode_dev_exit() do { } while(0)
489#endif 376#endif
490 377
491static long get_next_ucode_from_buffer(void **mc, const u8 *buf, 378static long get_next_ucode_from_buffer(void **mc, const u8 *buf,
@@ -515,9 +402,9 @@ static long get_next_ucode_from_buffer(void **mc, const u8 *buf,
515} 402}
516 403
517/* fake device for request_firmware */ 404/* fake device for request_firmware */
518static struct platform_device *microcode_pdev; 405extern struct platform_device *microcode_pdev;
519 406
520static int cpu_request_microcode(int cpu) 407int cpu_request_microcode(int cpu)
521{ 408{
522 char name[30]; 409 char name[30];
523 struct cpuinfo_x86 *c = &cpu_data(cpu); 410 struct cpuinfo_x86 *c = &cpu_data(cpu);
@@ -530,7 +417,7 @@ static int cpu_request_microcode(int cpu)
530 417
531 /* We should bind the task to the CPU */ 418 /* We should bind the task to the CPU */
532 BUG_ON(cpu != raw_smp_processor_id()); 419 BUG_ON(cpu != raw_smp_processor_id());
533 sprintf(name,"intel-ucode/%02x-%02x-%02x", 420 sprintf(name, "intel-ucode/%02x-%02x-%02x",
534 c->x86, c->x86_model, c->x86_mask); 421 c->x86, c->x86_model, c->x86_mask);
535 error = request_firmware(&firmware, name, &microcode_pdev->dev); 422 error = request_firmware(&firmware, name, &microcode_pdev->dev);
536 if (error) { 423 if (error) {
@@ -544,7 +431,7 @@ static int cpu_request_microcode(int cpu)
544 error = microcode_sanity_check(mc); 431 error = microcode_sanity_check(mc);
545 if (error) 432 if (error)
546 break; 433 break;
547 error = get_maching_microcode(mc, cpu); 434 error = get_matching_microcode(mc, cpu);
548 if (error < 0) 435 if (error < 0)
549 break; 436 break;
550 /* 437 /*
@@ -566,7 +453,7 @@ static int cpu_request_microcode(int cpu)
566 return error; 453 return error;
567} 454}
568 455
569static int apply_microcode_check_cpu(int cpu) 456int apply_microcode_check_cpu(int cpu)
570{ 457{
571 struct cpuinfo_x86 *c = &cpu_data(cpu); 458 struct cpuinfo_x86 *c = &cpu_data(cpu);
572 struct ucode_cpu_info *uci = ucode_cpu_info + cpu; 459 struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
@@ -615,241 +502,13 @@ static int apply_microcode_check_cpu(int cpu)
615 return err; 502 return err;
616} 503}
617 504
618static void microcode_init_cpu(int cpu, int resume) 505void microcode_fini_cpu(int cpu)
619{
620 cpumask_t old;
621 cpumask_of_cpu_ptr(newmask, cpu);
622 struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
623
624 old = current->cpus_allowed;
625
626 set_cpus_allowed_ptr(current, newmask);
627 mutex_lock(&microcode_mutex);
628 collect_cpu_info(cpu);
629 if (uci->valid && system_state == SYSTEM_RUNNING && !resume)
630 cpu_request_microcode(cpu);
631 mutex_unlock(&microcode_mutex);
632 set_cpus_allowed_ptr(current, &old);
633}
634
635static void microcode_fini_cpu(int cpu)
636{ 506{
637 struct ucode_cpu_info *uci = ucode_cpu_info + cpu; 507 struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
638 508
639 mutex_lock(&microcode_mutex); 509 mutex_lock(&microcode_mutex);
640 uci->valid = 0; 510 uci->valid = 0;
641 vfree(uci->mc); 511 kfree(uci->mc);
642 uci->mc = NULL; 512 uci->mc = NULL;
643 mutex_unlock(&microcode_mutex); 513 mutex_unlock(&microcode_mutex);
644} 514}
645
646static ssize_t reload_store(struct sys_device *dev,
647 struct sysdev_attribute *attr,
648 const char *buf, size_t sz)
649{
650 struct ucode_cpu_info *uci = ucode_cpu_info + dev->id;
651 char *end;
652 unsigned long val = simple_strtoul(buf, &end, 0);
653 int err = 0;
654 int cpu = dev->id;
655
656 if (end == buf)
657 return -EINVAL;
658 if (val == 1) {
659 cpumask_t old;
660 cpumask_of_cpu_ptr(newmask, cpu);
661
662 old = current->cpus_allowed;
663
664 get_online_cpus();
665 set_cpus_allowed_ptr(current, newmask);
666
667 mutex_lock(&microcode_mutex);
668 if (uci->valid)
669 err = cpu_request_microcode(cpu);
670 mutex_unlock(&microcode_mutex);
671 put_online_cpus();
672 set_cpus_allowed_ptr(current, &old);
673 }
674 if (err)
675 return err;
676 return sz;
677}
678
679static ssize_t version_show(struct sys_device *dev,
680 struct sysdev_attribute *attr, char *buf)
681{
682 struct ucode_cpu_info *uci = ucode_cpu_info + dev->id;
683
684 return sprintf(buf, "0x%x\n", uci->rev);
685}
686
687static ssize_t pf_show(struct sys_device *dev,
688 struct sysdev_attribute *attr, char *buf)
689{
690 struct ucode_cpu_info *uci = ucode_cpu_info + dev->id;
691
692 return sprintf(buf, "0x%x\n", uci->pf);
693}
694
695static SYSDEV_ATTR(reload, 0200, NULL, reload_store);
696static SYSDEV_ATTR(version, 0400, version_show, NULL);
697static SYSDEV_ATTR(processor_flags, 0400, pf_show, NULL);
698
699static struct attribute *mc_default_attrs[] = {
700 &attr_reload.attr,
701 &attr_version.attr,
702 &attr_processor_flags.attr,
703 NULL
704};
705
706static struct attribute_group mc_attr_group = {
707 .attrs = mc_default_attrs,
708 .name = "microcode",
709};
710
711static int __mc_sysdev_add(struct sys_device *sys_dev, int resume)
712{
713 int err, cpu = sys_dev->id;
714 struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
715
716 if (!cpu_online(cpu))
717 return 0;
718
719 pr_debug("microcode: CPU%d added\n", cpu);
720 memset(uci, 0, sizeof(*uci));
721
722 err = sysfs_create_group(&sys_dev->kobj, &mc_attr_group);
723 if (err)
724 return err;
725
726 microcode_init_cpu(cpu, resume);
727
728 return 0;
729}
730
731static int mc_sysdev_add(struct sys_device *sys_dev)
732{
733 return __mc_sysdev_add(sys_dev, 0);
734}
735
736static int mc_sysdev_remove(struct sys_device *sys_dev)
737{
738 int cpu = sys_dev->id;
739
740 if (!cpu_online(cpu))
741 return 0;
742
743 pr_debug("microcode: CPU%d removed\n", cpu);
744 microcode_fini_cpu(cpu);
745 sysfs_remove_group(&sys_dev->kobj, &mc_attr_group);
746 return 0;
747}
748
749static int mc_sysdev_resume(struct sys_device *dev)
750{
751 int cpu = dev->id;
752
753 if (!cpu_online(cpu))
754 return 0;
755 pr_debug("microcode: CPU%d resumed\n", cpu);
756 /* only CPU 0 will apply ucode here */
757 apply_microcode(0);
758 return 0;
759}
760
761static struct sysdev_driver mc_sysdev_driver = {
762 .add = mc_sysdev_add,
763 .remove = mc_sysdev_remove,
764 .resume = mc_sysdev_resume,
765};
766
767static __cpuinit int
768mc_cpu_callback(struct notifier_block *nb, unsigned long action, void *hcpu)
769{
770 unsigned int cpu = (unsigned long)hcpu;
771 struct sys_device *sys_dev;
772
773 sys_dev = get_cpu_sysdev(cpu);
774 switch (action) {
775 case CPU_UP_CANCELED_FROZEN:
776 /* The CPU refused to come up during a system resume */
777 microcode_fini_cpu(cpu);
778 break;
779 case CPU_ONLINE:
780 case CPU_DOWN_FAILED:
781 mc_sysdev_add(sys_dev);
782 break;
783 case CPU_ONLINE_FROZEN:
784 /* System-wide resume is in progress, try to apply microcode */
785 if (apply_microcode_check_cpu(cpu)) {
786 /* The application of microcode failed */
787 microcode_fini_cpu(cpu);
788 __mc_sysdev_add(sys_dev, 1);
789 break;
790 }
791 case CPU_DOWN_FAILED_FROZEN:
792 if (sysfs_create_group(&sys_dev->kobj, &mc_attr_group))
793 printk(KERN_ERR "microcode: Failed to create the sysfs "
794 "group for CPU%d\n", cpu);
795 break;
796 case CPU_DOWN_PREPARE:
797 mc_sysdev_remove(sys_dev);
798 break;
799 case CPU_DOWN_PREPARE_FROZEN:
800 /* Suspend is in progress, only remove the interface */
801 sysfs_remove_group(&sys_dev->kobj, &mc_attr_group);
802 break;
803 }
804 return NOTIFY_OK;
805}
806
807static struct notifier_block __refdata mc_cpu_notifier = {
808 .notifier_call = mc_cpu_callback,
809};
810
811static int __init microcode_init (void)
812{
813 int error;
814
815 printk(KERN_INFO
816 "IA-32 Microcode Update Driver: v" MICROCODE_VERSION " <tigran@aivazian.fsnet.co.uk>\n");
817
818 error = microcode_dev_init();
819 if (error)
820 return error;
821 microcode_pdev = platform_device_register_simple("microcode", -1,
822 NULL, 0);
823 if (IS_ERR(microcode_pdev)) {
824 microcode_dev_exit();
825 return PTR_ERR(microcode_pdev);
826 }
827
828 get_online_cpus();
829 error = sysdev_driver_register(&cpu_sysdev_class, &mc_sysdev_driver);
830 put_online_cpus();
831 if (error) {
832 microcode_dev_exit();
833 platform_device_unregister(microcode_pdev);
834 return error;
835 }
836
837 register_hotcpu_notifier(&mc_cpu_notifier);
838 return 0;
839}
840
841static void __exit microcode_exit (void)
842{
843 microcode_dev_exit();
844
845 unregister_hotcpu_notifier(&mc_cpu_notifier);
846
847 get_online_cpus();
848 sysdev_driver_unregister(&cpu_sysdev_class, &mc_sysdev_driver);
849 put_online_cpus();
850
851 platform_device_unregister(microcode_pdev);
852}
853
854module_init(microcode_init)
855module_exit(microcode_exit)