aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
Diffstat (limited to 'arch')
-rw-r--r--arch/x86_64/kernel/mce.c93
1 files changed, 74 insertions, 19 deletions
diff --git a/arch/x86_64/kernel/mce.c b/arch/x86_64/kernel/mce.c
index 21e70625a495..3b267c91bb0c 100644
--- a/arch/x86_64/kernel/mce.c
+++ b/arch/x86_64/kernel/mce.c
@@ -15,6 +15,8 @@
15#include <linux/sysdev.h> 15#include <linux/sysdev.h>
16#include <linux/miscdevice.h> 16#include <linux/miscdevice.h>
17#include <linux/fs.h> 17#include <linux/fs.h>
18#include <linux/cpu.h>
19#include <linux/percpu.h>
18#include <asm/processor.h> 20#include <asm/processor.h>
19#include <asm/msr.h> 21#include <asm/msr.h>
20#include <asm/mce.h> 22#include <asm/mce.h>
@@ -514,10 +516,7 @@ static struct sysdev_class mce_sysclass = {
514 set_kset_name("machinecheck"), 516 set_kset_name("machinecheck"),
515}; 517};
516 518
517static struct sys_device device_mce = { 519static DEFINE_PER_CPU(struct sys_device, device_mce);
518 .id = 0,
519 .cls = &mce_sysclass,
520};
521 520
522/* Why are there no generic functions for this? */ 521/* Why are there no generic functions for this? */
523#define ACCESSOR(name, var, start) \ 522#define ACCESSOR(name, var, start) \
@@ -542,27 +541,83 @@ ACCESSOR(bank4ctl,bank[4],mce_restart())
542ACCESSOR(tolerant,tolerant,) 541ACCESSOR(tolerant,tolerant,)
543ACCESSOR(check_interval,check_interval,mce_restart()) 542ACCESSOR(check_interval,check_interval,mce_restart())
544 543
545static __cpuinit int mce_init_device(void) 544/* Per cpu sysdev init. All of the cpus still share the same ctl bank */
545static __cpuinit int mce_create_device(unsigned int cpu)
546{ 546{
547 int err; 547 int err;
548 if (!mce_available(&cpu_data[cpu]))
549 return -EIO;
550
551 per_cpu(device_mce,cpu).id = cpu;
552 per_cpu(device_mce,cpu).cls = &mce_sysclass;
553
554 err = sysdev_register(&per_cpu(device_mce,cpu));
555
556 if (!err) {
557 sysdev_create_file(&per_cpu(device_mce,cpu), &attr_bank0ctl);
558 sysdev_create_file(&per_cpu(device_mce,cpu), &attr_bank1ctl);
559 sysdev_create_file(&per_cpu(device_mce,cpu), &attr_bank2ctl);
560 sysdev_create_file(&per_cpu(device_mce,cpu), &attr_bank3ctl);
561 sysdev_create_file(&per_cpu(device_mce,cpu), &attr_bank4ctl);
562 sysdev_create_file(&per_cpu(device_mce,cpu), &attr_tolerant);
563 sysdev_create_file(&per_cpu(device_mce,cpu), &attr_check_interval);
564 }
565 return err;
566}
567
568#ifdef CONFIG_HOTPLUG_CPU
569static __cpuinit void mce_remove_device(unsigned int cpu)
570{
571 sysdev_remove_file(&per_cpu(device_mce,cpu), &attr_bank0ctl);
572 sysdev_remove_file(&per_cpu(device_mce,cpu), &attr_bank1ctl);
573 sysdev_remove_file(&per_cpu(device_mce,cpu), &attr_bank2ctl);
574 sysdev_remove_file(&per_cpu(device_mce,cpu), &attr_bank3ctl);
575 sysdev_remove_file(&per_cpu(device_mce,cpu), &attr_bank4ctl);
576 sysdev_remove_file(&per_cpu(device_mce,cpu), &attr_tolerant);
577 sysdev_remove_file(&per_cpu(device_mce,cpu), &attr_check_interval);
578 sysdev_unregister(&per_cpu(device_mce,cpu));
579}
580#endif
581
582/* Get notified when a cpu comes on/off. Be hotplug friendly. */
583static __cpuinit int
584mce_cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu)
585{
586 unsigned int cpu = (unsigned long)hcpu;
587
588 switch (action) {
589 case CPU_ONLINE:
590 mce_create_device(cpu);
591 break;
592#ifdef CONFIG_HOTPLUG_CPU
593 case CPU_DEAD:
594 mce_remove_device(cpu);
595 break;
596#endif
597 }
598 return NOTIFY_OK;
599}
600
601static struct notifier_block mce_cpu_notifier = {
602 .notifier_call = mce_cpu_callback,
603};
604
605static __init int mce_init_device(void)
606{
607 int err;
608 int i = 0;
609
548 if (!mce_available(&boot_cpu_data)) 610 if (!mce_available(&boot_cpu_data))
549 return -EIO; 611 return -EIO;
550 err = sysdev_class_register(&mce_sysclass); 612 err = sysdev_class_register(&mce_sysclass);
551 if (!err) 613
552 err = sysdev_register(&device_mce); 614 for_each_online_cpu(i) {
553 if (!err) { 615 mce_create_device(i);
554 /* could create per CPU objects, but it is not worth it. */ 616 }
555 sysdev_create_file(&device_mce, &attr_bank0ctl); 617
556 sysdev_create_file(&device_mce, &attr_bank1ctl); 618 register_cpu_notifier(&mce_cpu_notifier);
557 sysdev_create_file(&device_mce, &attr_bank2ctl);
558 sysdev_create_file(&device_mce, &attr_bank3ctl);
559 sysdev_create_file(&device_mce, &attr_bank4ctl);
560 sysdev_create_file(&device_mce, &attr_tolerant);
561 sysdev_create_file(&device_mce, &attr_check_interval);
562 }
563
564 misc_register(&mce_log_device); 619 misc_register(&mce_log_device);
565 return err; 620 return err;
566
567} 621}
622
568device_initcall(mce_init_device); 623device_initcall(mce_init_device);