diff options
Diffstat (limited to 'arch/x86/kernel/apic/io_apic.c')
-rw-r--r-- | arch/x86/kernel/apic/io_apic.c | 97 |
1 files changed, 46 insertions, 51 deletions
diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index 180ca240e03..68df09bba92 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c | |||
@@ -30,7 +30,7 @@ | |||
30 | #include <linux/compiler.h> | 30 | #include <linux/compiler.h> |
31 | #include <linux/acpi.h> | 31 | #include <linux/acpi.h> |
32 | #include <linux/module.h> | 32 | #include <linux/module.h> |
33 | #include <linux/sysdev.h> | 33 | #include <linux/syscore_ops.h> |
34 | #include <linux/msi.h> | 34 | #include <linux/msi.h> |
35 | #include <linux/htirq.h> | 35 | #include <linux/htirq.h> |
36 | #include <linux/freezer.h> | 36 | #include <linux/freezer.h> |
@@ -2918,89 +2918,84 @@ static int __init io_apic_bug_finalize(void) | |||
2918 | 2918 | ||
2919 | late_initcall(io_apic_bug_finalize); | 2919 | late_initcall(io_apic_bug_finalize); |
2920 | 2920 | ||
2921 | struct sysfs_ioapic_data { | 2921 | static struct IO_APIC_route_entry *ioapic_saved_data[MAX_IO_APICS]; |
2922 | struct sys_device dev; | ||
2923 | struct IO_APIC_route_entry entry[0]; | ||
2924 | }; | ||
2925 | static struct sysfs_ioapic_data * mp_ioapic_data[MAX_IO_APICS]; | ||
2926 | 2922 | ||
2927 | static int ioapic_suspend(struct sys_device *dev, pm_message_t state) | 2923 | static void suspend_ioapic(int ioapic_id) |
2928 | { | 2924 | { |
2929 | struct IO_APIC_route_entry *entry; | 2925 | struct IO_APIC_route_entry *saved_data = ioapic_saved_data[ioapic_id]; |
2930 | struct sysfs_ioapic_data *data; | ||
2931 | int i; | 2926 | int i; |
2932 | 2927 | ||
2933 | data = container_of(dev, struct sysfs_ioapic_data, dev); | 2928 | if (!saved_data) |
2934 | entry = data->entry; | 2929 | return; |
2935 | for (i = 0; i < nr_ioapic_registers[dev->id]; i ++, entry ++ ) | 2930 | |
2936 | *entry = ioapic_read_entry(dev->id, i); | 2931 | for (i = 0; i < nr_ioapic_registers[ioapic_id]; i++) |
2932 | saved_data[i] = ioapic_read_entry(ioapic_id, i); | ||
2933 | } | ||
2934 | |||
2935 | static int ioapic_suspend(void) | ||
2936 | { | ||
2937 | int ioapic_id; | ||
2938 | |||
2939 | for (ioapic_id = 0; ioapic_id < nr_ioapics; ioapic_id++) | ||
2940 | suspend_ioapic(ioapic_id); | ||
2937 | 2941 | ||
2938 | return 0; | 2942 | return 0; |
2939 | } | 2943 | } |
2940 | 2944 | ||
2941 | static int ioapic_resume(struct sys_device *dev) | 2945 | static void resume_ioapic(int ioapic_id) |
2942 | { | 2946 | { |
2943 | struct IO_APIC_route_entry *entry; | 2947 | struct IO_APIC_route_entry *saved_data = ioapic_saved_data[ioapic_id]; |
2944 | struct sysfs_ioapic_data *data; | ||
2945 | unsigned long flags; | 2948 | unsigned long flags; |
2946 | union IO_APIC_reg_00 reg_00; | 2949 | union IO_APIC_reg_00 reg_00; |
2947 | int i; | 2950 | int i; |
2948 | 2951 | ||
2949 | data = container_of(dev, struct sysfs_ioapic_data, dev); | 2952 | if (!saved_data) |
2950 | entry = data->entry; | 2953 | return; |
2951 | 2954 | ||
2952 | raw_spin_lock_irqsave(&ioapic_lock, flags); | 2955 | raw_spin_lock_irqsave(&ioapic_lock, flags); |
2953 | reg_00.raw = io_apic_read(dev->id, 0); | 2956 | reg_00.raw = io_apic_read(ioapic_id, 0); |
2954 | if (reg_00.bits.ID != mp_ioapics[dev->id].apicid) { | 2957 | if (reg_00.bits.ID != mp_ioapics[ioapic_id].apicid) { |
2955 | reg_00.bits.ID = mp_ioapics[dev->id].apicid; | 2958 | reg_00.bits.ID = mp_ioapics[ioapic_id].apicid; |
2956 | io_apic_write(dev->id, 0, reg_00.raw); | 2959 | io_apic_write(ioapic_id, 0, reg_00.raw); |
2957 | } | 2960 | } |
2958 | raw_spin_unlock_irqrestore(&ioapic_lock, flags); | 2961 | raw_spin_unlock_irqrestore(&ioapic_lock, flags); |
2959 | for (i = 0; i < nr_ioapic_registers[dev->id]; i++) | 2962 | for (i = 0; i < nr_ioapic_registers[ioapic_id]; i++) |
2960 | ioapic_write_entry(dev->id, i, entry[i]); | 2963 | ioapic_write_entry(ioapic_id, i, saved_data[i]); |
2964 | } | ||
2961 | 2965 | ||
2962 | return 0; | 2966 | static void ioapic_resume(void) |
2967 | { | ||
2968 | int ioapic_id; | ||
2969 | |||
2970 | for (ioapic_id = nr_ioapics - 1; ioapic_id >= 0; ioapic_id--) | ||
2971 | resume_ioapic(ioapic_id); | ||
2963 | } | 2972 | } |
2964 | 2973 | ||
2965 | static struct sysdev_class ioapic_sysdev_class = { | 2974 | static struct syscore_ops ioapic_syscore_ops = { |
2966 | .name = "ioapic", | ||
2967 | .suspend = ioapic_suspend, | 2975 | .suspend = ioapic_suspend, |
2968 | .resume = ioapic_resume, | 2976 | .resume = ioapic_resume, |
2969 | }; | 2977 | }; |
2970 | 2978 | ||
2971 | static int __init ioapic_init_sysfs(void) | 2979 | static int __init ioapic_init_ops(void) |
2972 | { | 2980 | { |
2973 | struct sys_device * dev; | 2981 | int i; |
2974 | int i, size, error; | ||
2975 | 2982 | ||
2976 | error = sysdev_class_register(&ioapic_sysdev_class); | 2983 | for (i = 0; i < nr_ioapics; i++) { |
2977 | if (error) | 2984 | unsigned int size; |
2978 | return error; | ||
2979 | 2985 | ||
2980 | for (i = 0; i < nr_ioapics; i++ ) { | 2986 | size = nr_ioapic_registers[i] |
2981 | size = sizeof(struct sys_device) + nr_ioapic_registers[i] | ||
2982 | * sizeof(struct IO_APIC_route_entry); | 2987 | * sizeof(struct IO_APIC_route_entry); |
2983 | mp_ioapic_data[i] = kzalloc(size, GFP_KERNEL); | 2988 | ioapic_saved_data[i] = kzalloc(size, GFP_KERNEL); |
2984 | if (!mp_ioapic_data[i]) { | 2989 | if (!ioapic_saved_data[i]) |
2985 | printk(KERN_ERR "Can't suspend/resume IOAPIC %d\n", i); | 2990 | pr_err("IOAPIC %d: suspend/resume impossible!\n", i); |
2986 | continue; | ||
2987 | } | ||
2988 | dev = &mp_ioapic_data[i]->dev; | ||
2989 | dev->id = i; | ||
2990 | dev->cls = &ioapic_sysdev_class; | ||
2991 | error = sysdev_register(dev); | ||
2992 | if (error) { | ||
2993 | kfree(mp_ioapic_data[i]); | ||
2994 | mp_ioapic_data[i] = NULL; | ||
2995 | printk(KERN_ERR "Can't suspend/resume IOAPIC %d\n", i); | ||
2996 | continue; | ||
2997 | } | ||
2998 | } | 2991 | } |
2999 | 2992 | ||
2993 | register_syscore_ops(&ioapic_syscore_ops); | ||
2994 | |||
3000 | return 0; | 2995 | return 0; |
3001 | } | 2996 | } |
3002 | 2997 | ||
3003 | device_initcall(ioapic_init_sysfs); | 2998 | device_initcall(ioapic_init_ops); |
3004 | 2999 | ||
3005 | /* | 3000 | /* |
3006 | * Dynamic irq allocate and deallocation | 3001 | * Dynamic irq allocate and deallocation |