aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/i386/kernel/microcode.c71
-rw-r--r--include/linux/cpu.h4
-rw-r--r--kernel/cpu.c32
3 files changed, 87 insertions, 20 deletions
diff --git a/arch/i386/kernel/microcode.c b/arch/i386/kernel/microcode.c
index b8f16633a6ec..cbe7ec8dbb9f 100644
--- a/arch/i386/kernel/microcode.c
+++ b/arch/i386/kernel/microcode.c
@@ -567,6 +567,53 @@ static int cpu_request_microcode(int cpu)
567 return error; 567 return error;
568} 568}
569 569
570static int apply_microcode_on_cpu(int cpu)
571{
572 struct cpuinfo_x86 *c = cpu_data + cpu;
573 struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
574 cpumask_t old;
575 unsigned int val[2];
576 int err = 0;
577
578 if (!uci->mc)
579 return -EINVAL;
580
581 old = current->cpus_allowed;
582 set_cpus_allowed(current, cpumask_of_cpu(cpu));
583
584 /* Check if the microcode we have in memory matches the CPU */
585 if (c->x86_vendor != X86_VENDOR_INTEL || c->x86 < 6 ||
586 cpu_has(c, X86_FEATURE_IA64) || uci->sig != cpuid_eax(0x00000001))
587 err = -EINVAL;
588
589 if (!err && ((c->x86_model >= 5) || (c->x86 > 6))) {
590 /* get processor flags from MSR 0x17 */
591 rdmsr(MSR_IA32_PLATFORM_ID, val[0], val[1]);
592 if (uci->pf != (1 << ((val[1] >> 18) & 7)))
593 err = -EINVAL;
594 }
595
596 if (!err) {
597 wrmsr(MSR_IA32_UCODE_REV, 0, 0);
598 /* see notes above for revision 1.07. Apparent chip bug */
599 sync_core();
600 /* get the current revision from MSR 0x8B */
601 rdmsr(MSR_IA32_UCODE_REV, val[0], val[1]);
602 if (uci->rev != val[1])
603 err = -EINVAL;
604 }
605
606 if (!err)
607 apply_microcode(cpu);
608 else
609 printk(KERN_ERR "microcode: Could not apply microcode to CPU%d:"
610 " sig=0x%x, pf=0x%x, rev=0x%x\n",
611 cpu, uci->sig, uci->pf, uci->rev);
612
613 set_cpus_allowed(current, old);
614 return err;
615}
616
570static void microcode_init_cpu(int cpu) 617static void microcode_init_cpu(int cpu)
571{ 618{
572 cpumask_t old; 619 cpumask_t old;
@@ -577,7 +624,8 @@ static void microcode_init_cpu(int cpu)
577 set_cpus_allowed(current, cpumask_of_cpu(cpu)); 624 set_cpus_allowed(current, cpumask_of_cpu(cpu));
578 mutex_lock(&microcode_mutex); 625 mutex_lock(&microcode_mutex);
579 collect_cpu_info(cpu); 626 collect_cpu_info(cpu);
580 if (uci->valid && system_state == SYSTEM_RUNNING) 627 if (uci->valid && system_state == SYSTEM_RUNNING &&
628 !suspend_cpu_hotplug)
581 cpu_request_microcode(cpu); 629 cpu_request_microcode(cpu);
582 mutex_unlock(&microcode_mutex); 630 mutex_unlock(&microcode_mutex);
583 set_cpus_allowed(current, old); 631 set_cpus_allowed(current, old);
@@ -663,13 +711,24 @@ static int mc_sysdev_add(struct sys_device *sys_dev)
663 return 0; 711 return 0;
664 712
665 pr_debug("Microcode:CPU %d added\n", cpu); 713 pr_debug("Microcode:CPU %d added\n", cpu);
666 memset(uci, 0, sizeof(*uci)); 714 /* If suspend_cpu_hotplug is set, the system is resuming and we should
715 * use the data from before the suspend.
716 */
717 if (suspend_cpu_hotplug) {
718 err = apply_microcode_on_cpu(cpu);
719 if (err)
720 microcode_fini_cpu(cpu);
721 }
722 if (!uci->valid)
723 memset(uci, 0, sizeof(*uci));
667 724
668 err = sysfs_create_group(&sys_dev->kobj, &mc_attr_group); 725 err = sysfs_create_group(&sys_dev->kobj, &mc_attr_group);
669 if (err) 726 if (err)
670 return err; 727 return err;
671 728
672 microcode_init_cpu(cpu); 729 if (!uci->valid)
730 microcode_init_cpu(cpu);
731
673 return 0; 732 return 0;
674} 733}
675 734
@@ -680,7 +739,11 @@ static int mc_sysdev_remove(struct sys_device *sys_dev)
680 if (!cpu_online(cpu)) 739 if (!cpu_online(cpu))
681 return 0; 740 return 0;
682 pr_debug("Microcode:CPU %d removed\n", cpu); 741 pr_debug("Microcode:CPU %d removed\n", cpu);
683 microcode_fini_cpu(cpu); 742 /* If suspend_cpu_hotplug is set, the system is suspending and we should
743 * keep the microcode in memory for the resume.
744 */
745 if (!suspend_cpu_hotplug)
746 microcode_fini_cpu(cpu);
684 sysfs_remove_group(&sys_dev->kobj, &mc_attr_group); 747 sysfs_remove_group(&sys_dev->kobj, &mc_attr_group);
685 return 0; 748 return 0;
686} 749}
diff --git a/include/linux/cpu.h b/include/linux/cpu.h
index 769ddc6df492..c22b0dfcbcd2 100644
--- a/include/linux/cpu.h
+++ b/include/linux/cpu.h
@@ -127,9 +127,13 @@ static inline int cpu_is_offline(int cpu) { return 0; }
127#endif /* CONFIG_HOTPLUG_CPU */ 127#endif /* CONFIG_HOTPLUG_CPU */
128 128
129#ifdef CONFIG_SUSPEND_SMP 129#ifdef CONFIG_SUSPEND_SMP
130extern int suspend_cpu_hotplug;
131
130extern int disable_nonboot_cpus(void); 132extern int disable_nonboot_cpus(void);
131extern void enable_nonboot_cpus(void); 133extern void enable_nonboot_cpus(void);
132#else 134#else
135#define suspend_cpu_hotplug 0
136
133static inline int disable_nonboot_cpus(void) { return 0; } 137static inline int disable_nonboot_cpus(void) { return 0; }
134static inline void enable_nonboot_cpus(void) {} 138static inline void enable_nonboot_cpus(void) {}
135#endif 139#endif
diff --git a/kernel/cpu.c b/kernel/cpu.c
index 3d4206ada5c9..36e70845cfc3 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -254,6 +254,12 @@ int __cpuinit cpu_up(unsigned int cpu)
254} 254}
255 255
256#ifdef CONFIG_SUSPEND_SMP 256#ifdef CONFIG_SUSPEND_SMP
257/* Needed to prevent the microcode driver from requesting firmware in its CPU
258 * hotplug notifier during the suspend/resume.
259 */
260int suspend_cpu_hotplug;
261EXPORT_SYMBOL(suspend_cpu_hotplug);
262
257static cpumask_t frozen_cpus; 263static cpumask_t frozen_cpus;
258 264
259int disable_nonboot_cpus(void) 265int disable_nonboot_cpus(void)
@@ -261,16 +267,8 @@ int disable_nonboot_cpus(void)
261 int cpu, first_cpu, error = 0; 267 int cpu, first_cpu, error = 0;
262 268
263 mutex_lock(&cpu_add_remove_lock); 269 mutex_lock(&cpu_add_remove_lock);
264 first_cpu = first_cpu(cpu_present_map); 270 suspend_cpu_hotplug = 1;
265 if (!cpu_online(first_cpu)) { 271 first_cpu = first_cpu(cpu_online_map);
266 error = _cpu_up(first_cpu);
267 if (error) {
268 printk(KERN_ERR "Could not bring CPU%d up.\n",
269 first_cpu);
270 goto out;
271 }
272 }
273
274 /* We take down all of the non-boot CPUs in one shot to avoid races 272 /* We take down all of the non-boot CPUs in one shot to avoid races
275 * with the userspace trying to use the CPU hotplug at the same time 273 * with the userspace trying to use the CPU hotplug at the same time
276 */ 274 */
@@ -296,7 +294,7 @@ int disable_nonboot_cpus(void)
296 } else { 294 } else {
297 printk(KERN_ERR "Non-boot CPUs are not disabled\n"); 295 printk(KERN_ERR "Non-boot CPUs are not disabled\n");
298 } 296 }
299out: 297 suspend_cpu_hotplug = 0;
300 mutex_unlock(&cpu_add_remove_lock); 298 mutex_unlock(&cpu_add_remove_lock);
301 return error; 299 return error;
302} 300}
@@ -308,20 +306,22 @@ void enable_nonboot_cpus(void)
308 /* Allow everyone to use the CPU hotplug again */ 306 /* Allow everyone to use the CPU hotplug again */
309 mutex_lock(&cpu_add_remove_lock); 307 mutex_lock(&cpu_add_remove_lock);
310 cpu_hotplug_disabled = 0; 308 cpu_hotplug_disabled = 0;
311 mutex_unlock(&cpu_add_remove_lock);
312 if (cpus_empty(frozen_cpus)) 309 if (cpus_empty(frozen_cpus))
313 return; 310 goto out;
314 311
312 suspend_cpu_hotplug = 1;
315 printk("Enabling non-boot CPUs ...\n"); 313 printk("Enabling non-boot CPUs ...\n");
316 for_each_cpu_mask(cpu, frozen_cpus) { 314 for_each_cpu_mask(cpu, frozen_cpus) {
317 error = cpu_up(cpu); 315 error = _cpu_up(cpu);
318 if (!error) { 316 if (!error) {
319 printk("CPU%d is up\n", cpu); 317 printk("CPU%d is up\n", cpu);
320 continue; 318 continue;
321 } 319 }
322 printk(KERN_WARNING "Error taking CPU%d up: %d\n", 320 printk(KERN_WARNING "Error taking CPU%d up: %d\n", cpu, error);
323 cpu, error);
324 } 321 }
325 cpus_clear(frozen_cpus); 322 cpus_clear(frozen_cpus);
323 suspend_cpu_hotplug = 0;
324out:
325 mutex_unlock(&cpu_add_remove_lock);
326} 326}
327#endif 327#endif