aboutsummaryrefslogtreecommitdiffstats
path: root/arch/i386/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'arch/i386/kernel')
-rw-r--r--arch/i386/kernel/microcode.c154
1 files changed, 151 insertions, 3 deletions
diff --git a/arch/i386/kernel/microcode.c b/arch/i386/kernel/microcode.c
index f8f1ec5f26c1..467901ebb992 100644
--- a/arch/i386/kernel/microcode.c
+++ b/arch/i386/kernel/microcode.c
@@ -219,7 +219,7 @@ static int microcode_sanity_check(void *mc)
219 /* check extended table checksum */ 219 /* check extended table checksum */
220 if (ext_table_size) { 220 if (ext_table_size) {
221 int ext_table_sum = 0; 221 int ext_table_sum = 0;
222 int * ext_tablep = (int *)ext_header; 222 int *ext_tablep = (int *)ext_header;
223 223
224 i = ext_table_size / DWSIZE; 224 i = ext_table_size / DWSIZE;
225 while (i--) 225 while (i--)
@@ -386,7 +386,7 @@ static int do_microcode_update (void)
386{ 386{
387 long cursor = 0; 387 long cursor = 0;
388 int error = 0; 388 int error = 0;
389 void * new_mc; 389 void *new_mc;
390 int cpu; 390 int cpu;
391 cpumask_t old; 391 cpumask_t old;
392 392
@@ -531,7 +531,7 @@ static int cpu_request_microcode(int cpu)
531 char name[30]; 531 char name[30];
532 struct cpuinfo_x86 *c = cpu_data + cpu; 532 struct cpuinfo_x86 *c = cpu_data + cpu;
533 const struct firmware *firmware; 533 const struct firmware *firmware;
534 void * buf; 534 void *buf;
535 unsigned long size; 535 unsigned long size;
536 long offset = 0; 536 long offset = 0;
537 int error; 537 int error;
@@ -602,6 +602,136 @@ static void microcode_fini_cpu(int cpu)
602 mutex_unlock(&microcode_mutex); 602 mutex_unlock(&microcode_mutex);
603} 603}
604 604
605static ssize_t reload_store(struct sys_device *dev, const char *buf, size_t sz)
606{
607 struct ucode_cpu_info *uci = ucode_cpu_info + dev->id;
608 char *end;
609 unsigned long val = simple_strtoul(buf, &end, 0);
610 int err = 0;
611 int cpu = dev->id;
612
613 if (end == buf)
614 return -EINVAL;
615 if (val == 1) {
616 cpumask_t old;
617
618 old = current->cpus_allowed;
619
620 lock_cpu_hotplug();
621 set_cpus_allowed(current, cpumask_of_cpu(cpu));
622
623 mutex_lock(&microcode_mutex);
624 if (uci->valid)
625 err = cpu_request_microcode(cpu);
626 mutex_unlock(&microcode_mutex);
627 unlock_cpu_hotplug();
628 set_cpus_allowed(current, old);
629 }
630 if (err)
631 return err;
632 return sz;
633}
634
635static ssize_t version_show(struct sys_device *dev, char *buf)
636{
637 struct ucode_cpu_info *uci = ucode_cpu_info + dev->id;
638
639 return sprintf(buf, "0x%x\n", uci->rev);
640}
641
642static ssize_t pf_show(struct sys_device *dev, char *buf)
643{
644 struct ucode_cpu_info *uci = ucode_cpu_info + dev->id;
645
646 return sprintf(buf, "0x%x\n", uci->pf);
647}
648
649static SYSDEV_ATTR(reload, 0200, NULL, reload_store);
650static SYSDEV_ATTR(version, 0400, version_show, NULL);
651static SYSDEV_ATTR(processor_flags, 0400, pf_show, NULL);
652
653static struct attribute *mc_default_attrs[] = {
654 &attr_reload.attr,
655 &attr_version.attr,
656 &attr_processor_flags.attr,
657 NULL
658};
659
660static struct attribute_group mc_attr_group = {
661 .attrs = mc_default_attrs,
662 .name = "microcode",
663};
664
665static int mc_sysdev_add(struct sys_device *sys_dev)
666{
667 int cpu = sys_dev->id;
668 struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
669
670 if (!cpu_online(cpu))
671 return 0;
672 pr_debug("Microcode:CPU %d added\n", cpu);
673 memset(uci, 0, sizeof(*uci));
674 sysfs_create_group(&sys_dev->kobj, &mc_attr_group);
675
676 microcode_init_cpu(cpu);
677 return 0;
678}
679
680static int mc_sysdev_remove(struct sys_device *sys_dev)
681{
682 int cpu = sys_dev->id;
683
684 if (!cpu_online(cpu))
685 return 0;
686 pr_debug("Microcode:CPU %d removed\n", cpu);
687 microcode_fini_cpu(cpu);
688 sysfs_remove_group(&sys_dev->kobj, &mc_attr_group);
689 return 0;
690}
691
692static int mc_sysdev_resume(struct sys_device *dev)
693{
694 int cpu = dev->id;
695
696 if (!cpu_online(cpu))
697 return 0;
698 pr_debug("Microcode:CPU %d resumed\n", cpu);
699 /* only CPU 0 will apply ucode here */
700 apply_microcode(0);
701 return 0;
702}
703
704static struct sysdev_driver mc_sysdev_driver = {
705 .add = mc_sysdev_add,
706 .remove = mc_sysdev_remove,
707 .resume = mc_sysdev_resume,
708};
709
710#ifdef CONFIG_HOTPLUG_CPU
711static __cpuinit int
712mc_cpu_callback(struct notifier_block *nb, unsigned long action, void *hcpu)
713{
714 unsigned int cpu = (unsigned long)hcpu;
715 struct sys_device *sys_dev;
716
717 sys_dev = get_cpu_sysdev(cpu);
718 switch (action) {
719 case CPU_ONLINE:
720 case CPU_DOWN_FAILED:
721 mc_sysdev_add(sys_dev);
722 break;
723 case CPU_DOWN_PREPARE:
724 mc_sysdev_remove(sys_dev);
725 break;
726 }
727 return NOTIFY_OK;
728}
729
730static struct notifier_block mc_cpu_notifier = {
731 .notifier_call = mc_cpu_callback,
732};
733#endif
734
605static int __init microcode_init (void) 735static int __init microcode_init (void)
606{ 736{
607 int error; 737 int error;
@@ -616,6 +746,17 @@ static int __init microcode_init (void)
616 return PTR_ERR(microcode_pdev); 746 return PTR_ERR(microcode_pdev);
617 } 747 }
618 748
749 lock_cpu_hotplug();
750 error = sysdev_driver_register(&cpu_sysdev_class, &mc_sysdev_driver);
751 unlock_cpu_hotplug();
752 if (error) {
753 microcode_dev_exit();
754 platform_device_unregister(microcode_pdev);
755 return error;
756 }
757
758 register_hotcpu_notifier(&mc_cpu_notifier);
759
619 printk(KERN_INFO 760 printk(KERN_INFO
620 "IA-32 Microcode Update Driver: v" MICROCODE_VERSION " <tigran@veritas.com>\n"); 761 "IA-32 Microcode Update Driver: v" MICROCODE_VERSION " <tigran@veritas.com>\n");
621 return 0; 762 return 0;
@@ -624,6 +765,13 @@ static int __init microcode_init (void)
624static void __exit microcode_exit (void) 765static void __exit microcode_exit (void)
625{ 766{
626 microcode_dev_exit(); 767 microcode_dev_exit();
768
769 unregister_hotcpu_notifier(&mc_cpu_notifier);
770
771 lock_cpu_hotplug();
772 sysdev_driver_unregister(&cpu_sysdev_class, &mc_sysdev_driver);
773 unlock_cpu_hotplug();
774
627 platform_device_unregister(microcode_pdev); 775 platform_device_unregister(microcode_pdev);
628} 776}
629 777