diff options
Diffstat (limited to 'arch/x86/kernel')
-rw-r--r-- | arch/x86/kernel/mce_64.c | 39 |
1 files changed, 29 insertions, 10 deletions
diff --git a/arch/x86/kernel/mce_64.c b/arch/x86/kernel/mce_64.c index 8ca8f8648969..66e6b797b2cb 100644 --- a/arch/x86/kernel/mce_64.c +++ b/arch/x86/kernel/mce_64.c | |||
@@ -802,16 +802,29 @@ static __cpuinit int mce_create_device(unsigned int cpu) | |||
802 | if (!mce_available(&cpu_data[cpu])) | 802 | if (!mce_available(&cpu_data[cpu])) |
803 | return -EIO; | 803 | return -EIO; |
804 | 804 | ||
805 | memset(&per_cpu(device_mce, cpu).kobj, 0, sizeof(struct kobject)); | ||
805 | per_cpu(device_mce,cpu).id = cpu; | 806 | per_cpu(device_mce,cpu).id = cpu; |
806 | per_cpu(device_mce,cpu).cls = &mce_sysclass; | 807 | per_cpu(device_mce,cpu).cls = &mce_sysclass; |
807 | 808 | ||
808 | err = sysdev_register(&per_cpu(device_mce,cpu)); | 809 | err = sysdev_register(&per_cpu(device_mce,cpu)); |
810 | if (err) | ||
811 | return err; | ||
812 | |||
813 | for (i = 0; mce_attributes[i]; i++) { | ||
814 | err = sysdev_create_file(&per_cpu(device_mce,cpu), | ||
815 | mce_attributes[i]); | ||
816 | if (err) | ||
817 | goto error; | ||
818 | } | ||
809 | 819 | ||
810 | if (!err) { | 820 | return 0; |
811 | for (i = 0; mce_attributes[i]; i++) | 821 | error: |
812 | sysdev_create_file(&per_cpu(device_mce,cpu), | 822 | while (i--) { |
813 | mce_attributes[i]); | 823 | sysdev_remove_file(&per_cpu(device_mce,cpu), |
824 | mce_attributes[i]); | ||
814 | } | 825 | } |
826 | sysdev_unregister(&per_cpu(device_mce,cpu)); | ||
827 | |||
815 | return err; | 828 | return err; |
816 | } | 829 | } |
817 | 830 | ||
@@ -823,7 +836,6 @@ static void mce_remove_device(unsigned int cpu) | |||
823 | sysdev_remove_file(&per_cpu(device_mce,cpu), | 836 | sysdev_remove_file(&per_cpu(device_mce,cpu), |
824 | mce_attributes[i]); | 837 | mce_attributes[i]); |
825 | sysdev_unregister(&per_cpu(device_mce,cpu)); | 838 | sysdev_unregister(&per_cpu(device_mce,cpu)); |
826 | memset(&per_cpu(device_mce, cpu).kobj, 0, sizeof(struct kobject)); | ||
827 | } | 839 | } |
828 | 840 | ||
829 | /* Get notified when a cpu comes on/off. Be hotplug friendly. */ | 841 | /* Get notified when a cpu comes on/off. Be hotplug friendly. */ |
@@ -831,18 +843,21 @@ static int | |||
831 | mce_cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu) | 843 | mce_cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu) |
832 | { | 844 | { |
833 | unsigned int cpu = (unsigned long)hcpu; | 845 | unsigned int cpu = (unsigned long)hcpu; |
846 | int err = 0; | ||
834 | 847 | ||
835 | switch (action) { | 848 | switch (action) { |
836 | case CPU_ONLINE: | 849 | case CPU_UP_PREPARE: |
837 | case CPU_ONLINE_FROZEN: | 850 | case CPU_UP_PREPARE_FROZEN: |
838 | mce_create_device(cpu); | 851 | err = mce_create_device(cpu); |
839 | break; | 852 | break; |
853 | case CPU_UP_CANCELED: | ||
854 | case CPU_UP_CANCELED_FROZEN: | ||
840 | case CPU_DEAD: | 855 | case CPU_DEAD: |
841 | case CPU_DEAD_FROZEN: | 856 | case CPU_DEAD_FROZEN: |
842 | mce_remove_device(cpu); | 857 | mce_remove_device(cpu); |
843 | break; | 858 | break; |
844 | } | 859 | } |
845 | return NOTIFY_OK; | 860 | return err ? NOTIFY_BAD : NOTIFY_OK; |
846 | } | 861 | } |
847 | 862 | ||
848 | static struct notifier_block mce_cpu_notifier = { | 863 | static struct notifier_block mce_cpu_notifier = { |
@@ -857,9 +872,13 @@ static __init int mce_init_device(void) | |||
857 | if (!mce_available(&boot_cpu_data)) | 872 | if (!mce_available(&boot_cpu_data)) |
858 | return -EIO; | 873 | return -EIO; |
859 | err = sysdev_class_register(&mce_sysclass); | 874 | err = sysdev_class_register(&mce_sysclass); |
875 | if (err) | ||
876 | return err; | ||
860 | 877 | ||
861 | for_each_online_cpu(i) { | 878 | for_each_online_cpu(i) { |
862 | mce_create_device(i); | 879 | err = mce_create_device(i); |
880 | if (err) | ||
881 | return err; | ||
863 | } | 882 | } |
864 | 883 | ||
865 | register_hotcpu_notifier(&mce_cpu_notifier); | 884 | register_hotcpu_notifier(&mce_cpu_notifier); |