aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/apic
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2011-03-23 17:15:54 -0400
committerRafael J. Wysocki <rjw@sisk.pl>2011-03-23 17:15:54 -0400
commitf3c6ea1b06c71b43f751b36bd99345369fe911af (patch)
treea7ed142d4a183cc97fa7fc2af1cc5dec61827aa2 /arch/x86/kernel/apic
parent4bbba111d94781d34081c37856bbc5eb33f6c72a (diff)
x86: Use syscore_ops instead of sysdev classes and sysdevs
Some subsystems in the x86 tree need to carry out suspend/resume and shutdown operations with one CPU on-line and interrupts disabled and they define sysdev classes and sysdevs or sysdev drivers for this purpose. This leads to unnecessarily complicated code and excessive memory usage, so switch them to using struct syscore_ops objects for this purpose instead. Generally, there are three categories of subsystems that use sysdevs for implementing PM operations: (1) subsystems whose suspend/resume callbacks ignore their arguments entirely (the majority), (2) subsystems whose suspend/resume callbacks use their struct sys_device argument, but don't really need to do that, because they can be implemented differently in an arguably simpler way (io_apic.c), and (3) subsystems whose suspend/resume callbacks use their struct sys_device argument, but the value of that argument is always the same and could be ignored (microcode_core.c). In all of these cases the subsystems in question may be readily converted to using struct syscore_ops objects for power management and shutdown. Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> Reviewed-by: Thomas Gleixner <tglx@linutronix.de> Acked-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/x86/kernel/apic')
-rw-r--r--arch/x86/kernel/apic/apic.c33
-rw-r--r--arch/x86/kernel/apic/io_apic.c97
2 files changed, 55 insertions, 75 deletions
diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c
index 966673f44141..fabf01eff771 100644
--- a/arch/x86/kernel/apic/apic.c
+++ b/arch/x86/kernel/apic/apic.c
@@ -24,7 +24,7 @@
24#include <linux/ftrace.h> 24#include <linux/ftrace.h>
25#include <linux/ioport.h> 25#include <linux/ioport.h>
26#include <linux/module.h> 26#include <linux/module.h>
27#include <linux/sysdev.h> 27#include <linux/syscore_ops.h>
28#include <linux/delay.h> 28#include <linux/delay.h>
29#include <linux/timex.h> 29#include <linux/timex.h>
30#include <linux/dmar.h> 30#include <linux/dmar.h>
@@ -2046,7 +2046,7 @@ static struct {
2046 unsigned int apic_thmr; 2046 unsigned int apic_thmr;
2047} apic_pm_state; 2047} apic_pm_state;
2048 2048
2049static int lapic_suspend(struct sys_device *dev, pm_message_t state) 2049static int lapic_suspend(void)
2050{ 2050{
2051 unsigned long flags; 2051 unsigned long flags;
2052 int maxlvt; 2052 int maxlvt;
@@ -2084,23 +2084,21 @@ static int lapic_suspend(struct sys_device *dev, pm_message_t state)
2084 return 0; 2084 return 0;
2085} 2085}
2086 2086
2087static int lapic_resume(struct sys_device *dev) 2087static void lapic_resume(void)
2088{ 2088{
2089 unsigned int l, h; 2089 unsigned int l, h;
2090 unsigned long flags; 2090 unsigned long flags;
2091 int maxlvt; 2091 int maxlvt, ret;
2092 int ret = 0;
2093 struct IO_APIC_route_entry **ioapic_entries = NULL; 2092 struct IO_APIC_route_entry **ioapic_entries = NULL;
2094 2093
2095 if (!apic_pm_state.active) 2094 if (!apic_pm_state.active)
2096 return 0; 2095 return;
2097 2096
2098 local_irq_save(flags); 2097 local_irq_save(flags);
2099 if (intr_remapping_enabled) { 2098 if (intr_remapping_enabled) {
2100 ioapic_entries = alloc_ioapic_entries(); 2099 ioapic_entries = alloc_ioapic_entries();
2101 if (!ioapic_entries) { 2100 if (!ioapic_entries) {
2102 WARN(1, "Alloc ioapic_entries in lapic resume failed."); 2101 WARN(1, "Alloc ioapic_entries in lapic resume failed.");
2103 ret = -ENOMEM;
2104 goto restore; 2102 goto restore;
2105 } 2103 }
2106 2104
@@ -2162,8 +2160,6 @@ static int lapic_resume(struct sys_device *dev)
2162 } 2160 }
2163restore: 2161restore:
2164 local_irq_restore(flags); 2162 local_irq_restore(flags);
2165
2166 return ret;
2167} 2163}
2168 2164
2169/* 2165/*
@@ -2171,17 +2167,11 @@ restore:
2171 * are needed on every CPU up until machine_halt/restart/poweroff. 2167 * are needed on every CPU up until machine_halt/restart/poweroff.
2172 */ 2168 */
2173 2169
2174static struct sysdev_class lapic_sysclass = { 2170static struct syscore_ops lapic_syscore_ops = {
2175 .name = "lapic",
2176 .resume = lapic_resume, 2171 .resume = lapic_resume,
2177 .suspend = lapic_suspend, 2172 .suspend = lapic_suspend,
2178}; 2173};
2179 2174
2180static struct sys_device device_lapic = {
2181 .id = 0,
2182 .cls = &lapic_sysclass,
2183};
2184
2185static void __cpuinit apic_pm_activate(void) 2175static void __cpuinit apic_pm_activate(void)
2186{ 2176{
2187 apic_pm_state.active = 1; 2177 apic_pm_state.active = 1;
@@ -2189,16 +2179,11 @@ static void __cpuinit apic_pm_activate(void)
2189 2179
2190static int __init init_lapic_sysfs(void) 2180static int __init init_lapic_sysfs(void)
2191{ 2181{
2192 int error;
2193
2194 if (!cpu_has_apic)
2195 return 0;
2196 /* XXX: remove suspend/resume procs if !apic_pm_state.active? */ 2182 /* XXX: remove suspend/resume procs if !apic_pm_state.active? */
2183 if (cpu_has_apic)
2184 register_syscore_ops(&lapic_syscore_ops);
2197 2185
2198 error = sysdev_class_register(&lapic_sysclass); 2186 return 0;
2199 if (!error)
2200 error = sysdev_register(&device_lapic);
2201 return error;
2202} 2187}
2203 2188
2204/* local apic needs to resume before other devices access its registers. */ 2189/* local apic needs to resume before other devices access its registers. */
diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c
index 180ca240e03c..68df09bba92e 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
2919late_initcall(io_apic_bug_finalize); 2919late_initcall(io_apic_bug_finalize);
2920 2920
2921struct sysfs_ioapic_data { 2921static 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};
2925static struct sysfs_ioapic_data * mp_ioapic_data[MAX_IO_APICS];
2926 2922
2927static int ioapic_suspend(struct sys_device *dev, pm_message_t state) 2923static 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
2935static 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
2941static int ioapic_resume(struct sys_device *dev) 2945static 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; 2966static 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
2965static struct sysdev_class ioapic_sysdev_class = { 2974static 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
2971static int __init ioapic_init_sysfs(void) 2979static 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
3003device_initcall(ioapic_init_sysfs); 2998device_initcall(ioapic_init_ops);
3004 2999
3005/* 3000/*
3006 * Dynamic irq allocate and deallocation 3001 * Dynamic irq allocate and deallocation