diff options
| -rw-r--r-- | arch/arm/kernel/pm.c | 8 | ||||
| -rw-r--r-- | arch/i386/kernel/apic.c | 45 | ||||
| -rw-r--r-- | arch/i386/kernel/cpu/mtrr/main.c | 60 | ||||
| -rw-r--r-- | arch/i386/kernel/i8259.c | 62 | ||||
| -rw-r--r-- | arch/i386/kernel/nmi.c | 38 | ||||
| -rw-r--r-- | arch/i386/kernel/time.c | 16 | ||||
| -rw-r--r-- | arch/i386/oprofile/nmi_int.c | 33 | ||||
| -rw-r--r-- | arch/x86_64/kernel/i8259.c | 28 | ||||
| -rw-r--r-- | drivers/base/cpu.c | 46 | ||||
| -rw-r--r-- | drivers/base/memblk.c | 31 | ||||
| -rw-r--r-- | drivers/base/node.c | 41 | ||||
| -rw-r--r-- | drivers/base/power.c | 43 | ||||
| -rw-r--r-- | drivers/base/sys.c | 467 | ||||
| -rw-r--r-- | drivers/s390/block/xpram.c | 23 | ||||
| -rw-r--r-- | fs/sysfs/file.c | 4 | ||||
| -rw-r--r-- | include/linux/cpu.h | 5 | ||||
| -rw-r--r-- | include/linux/cpufreq.h | 4 | ||||
| -rw-r--r-- | include/linux/device.h | 24 | ||||
| -rw-r--r-- | include/linux/kobject.h | 8 | ||||
| -rw-r--r-- | include/linux/list.h | 14 | ||||
| -rw-r--r-- | include/linux/node.h | 4 | ||||
| -rw-r--r-- | include/linux/sysdev.h | 98 | ||||
| -rw-r--r-- | kernel/cpufreq.c | 83 |
23 files changed, 792 insertions, 393 deletions
diff --git a/arch/arm/kernel/pm.c b/arch/arm/kernel/pm.c index 03fcb771b579..e80142d9304b 100644 --- a/arch/arm/kernel/pm.c +++ b/arch/arm/kernel/pm.c @@ -11,7 +11,6 @@ #include <linux/config.h> #include <linux/pm.h> #include <linux/device.h> -#include <linux/cpufreq.h> #include <asm/leds.h> #include <asm/system.h> @@ -67,13 +66,6 @@ int suspend(void) device_resume(RESUME_POWER_ON); /* - * Restore the CPU frequency settings. - */ -#ifdef CONFIG_CPU_FREQ - cpufreq_restore(); -#endif - - /* * Resume LDM devices. */ device_resume(RESUME_RESTORE_STATE); diff --git a/arch/i386/kernel/apic.c b/arch/i386/kernel/apic.c index 3f1216c60f44..00d1a2ba56a1 100644 --- a/arch/i386/kernel/apic.c +++ b/arch/i386/kernel/apic.c @@ -25,6 +25,9 @@ #include <linux/interrupt.h> #include <linux/mc146818rtc.h> #include <linux/kernel_stat.h> +#include <linux/sysdev.h> +#include <linux/module.h> + #include <asm/atomic.h> #include <asm/smp.h> @@ -460,9 +463,6 @@ void __init setup_local_APIC (void) #ifdef CONFIG_PM -#include <linux/device.h> -#include <linux/module.h> - static struct { /* 'active' is true if the local APIC was enabled by us and not the BIOS; this signifies that we are also responsible @@ -484,13 +484,11 @@ static struct { unsigned int apic_thmr; } apic_pm_state; -static int lapic_suspend(struct device *dev, u32 state, u32 level) +static int lapic_suspend(struct sys_device *dev, u32 state) { unsigned int l, h; unsigned long flags; - if (level != SUSPEND_POWER_DOWN) - return 0; if (!apic_pm_state.active) return 0; @@ -517,13 +515,11 @@ static int lapic_suspend(struct device *dev, u32 state, u32 level) return 0; } -static int lapic_resume(struct device *dev, u32 level) +static int lapic_resume(struct sys_device *dev) { unsigned int l, h; unsigned long flags; - if (level != RESUME_POWER_ON) - return 0; if (!apic_pm_state.active) return 0; @@ -557,38 +553,37 @@ static int lapic_resume(struct device *dev, u32 level) return 0; } -static struct device_driver lapic_driver = { - .name = "lapic", - .bus = &system_bus_type, + +static struct sysdev_class lapic_sysclass = { + set_kset_name("lapic"), .resume = lapic_resume, .suspend = lapic_suspend, }; -/* not static, needed by child devices */ -struct sys_device device_lapic = { - .name = "lapic", - .id = 0, - .dev = { - .name = "lapic", - .driver = &lapic_driver, - }, +static struct sys_device device_lapic = { + .id = 0, + .cls = &lapic_sysclass, }; -EXPORT_SYMBOL(device_lapic); static void __init apic_pm_activate(void) { apic_pm_state.active = 1; } -static int __init init_lapic_devicefs(void) +static int __init init_lapic_sysfs(void) { + int error; + if (!cpu_has_apic) return 0; /* XXX: remove suspend/resume procs if !apic_pm_state.active? */ - driver_register(&lapic_driver); - return sys_device_register(&device_lapic); + + error = sysdev_class_register(&lapic_sysclass); + if (!error) + error = sys_device_register(&device_lapic); + return error; } -device_initcall(init_lapic_devicefs); +device_initcall(init_lapic_sysfs); #else /* CONFIG_PM */ diff --git a/arch/i386/kernel/cpu/mtrr/main.c b/arch/i386/kernel/cpu/mtrr/main.c index 5b82d52983db..3db7d11848a4 100644 --- a/arch/i386/kernel/cpu/mtrr/main.c +++ b/arch/i386/kernel/cpu/mtrr/main.c @@ -35,6 +35,7 @@ #include <linux/init.h> #include <linux/pci.h> #include <linux/smp.h> +#include <linux/cpu.h> #include <asm/mtrr.h> @@ -546,6 +547,58 @@ static void init_other_cpus(void) } } + +struct mtrr_value { + mtrr_type ltype; + unsigned long lbase; + unsigned int lsize; +}; + +static struct mtrr_value * mtrr_state; + +static int mtrr_save(struct sys_device * sysdev, u32 state) +{ + int i; + int size = num_var_ranges * sizeof(struct mtrr_value); + + mtrr_state = kmalloc(size,GFP_KERNEL); + if (mtrr_state) + memset(mtrr_state,0,size); + else + return -ENOMEM; + + for (i = 0; i < num_var_ranges; i++) { + mtrr_if->get(i, + &mtrr_state[i].lbase, + &mtrr_state[i].lsize, + &mtrr_state[i].ltype); + } + return 0; +} + +static int mtrr_restore(struct sys_device * sysdev) +{ + int i; + + for (i = 0; i < num_var_ranges; i++) { + if (mtrr_state[i].lsize) + set_mtrr(i, + mtrr_state[i].lbase, + mtrr_state[i].lsize, + mtrr_state[i].ltype); + } + kfree(mtrr_state); + return 0; +} + + + +static struct sysdev_driver mtrr_sysdev_driver = { + .save = mtrr_save, + .restore = mtrr_restore, +}; + + /** * mtrr_init - initialie mtrrs on the boot CPU * @@ -630,8 +683,11 @@ static int __init mtrr_init(void) set_num_var_ranges(); init_table(); init_other_cpus(); + + return sysdev_driver_register(&cpu_sysdev_class, + &mtrr_sysdev_driver); } - return mtrr_if ? -ENXIO : 0; + return -ENXIO; } char *mtrr_strings[MTRR_NUM_TYPES] = @@ -645,5 +701,5 @@ char *mtrr_strings[MTRR_NUM_TYPES] = "write-back", /* 6 */ }; -core_initcall(mtrr_init); +subsys_initcall(mtrr_init); diff --git a/arch/i386/kernel/i8259.c b/arch/i386/kernel/i8259.c index fb6d35da09e7..bc1268725f34 100644 --- a/arch/i386/kernel/i8259.c +++ b/arch/i386/kernel/i8259.c @@ -10,7 +10,7 @@ #include <linux/smp_lock.h> #include <linux/init.h> #include <linux/kernel_stat.h> -#include <linux/device.h> +#include <linux/sysdev.h> #include <asm/atomic.h> #include <asm/system.h> @@ -238,35 +238,31 @@ spurious_8259A_irq: } } -static int i8259A_resume(struct device *dev, u32 level) +static int i8259A_resume(struct sys_device *dev) { - if (level == RESUME_POWER_ON) - init_8259A(0); + init_8259A(0); return 0; } -static struct device_driver i8259A_driver = { - .name = "pic", - .bus = &system_bus_type, - .resume = i8259A_resume, +static struct sysdev_class i8259_sysdev_class = { + set_kset_name("i8259"), + .resume = i8259A_resume, }; static struct sys_device device_i8259A = { - .name = "pic", - .id = 0, - .dev = { - .name = "i8259A PIC", - .driver = &i8259A_driver, - }, + .id = 0, + .cls = &i8259_sysdev_class, }; -static int __init init_8259A_devicefs(void) +static int __init i8259A_init_sysfs(void) { - driver_register(&i8259A_driver); - return sys_device_register(&device_i8259A); + int error = sysdev_class_register(&i8259_sysdev_class); + if (!error) + error = sys_device_register(&device_i8259A); + return error; } -device_initcall(init_8259A_devicefs); +device_initcall(i8259A_init_sysfs); void init_8259A(int auto_eoi) { @@ -385,35 +381,31 @@ static void setup_timer(void) spin_unlock_irqrestore(&i8253_lock, flags); } -static int timer_resume(struct device *dev, u32 level) +static int timer_resume(struct sys_device *dev) { - if (level == RESUME_POWER_ON) - setup_timer(); + setup_timer(); return 0; } -static struct device_driver timer_driver = { - .name = "timer", - .bus = &system_bus_type, - .resume = timer_resume, +static struct sysdev_class timer_sysclass = { + set_kset_name("timer"), + .resume = timer_resume, }; static struct sys_device device_timer = { - .name = "timer", - .id = 0, - .dev = { - .name = "timer", - .driver = &timer_driver, - }, + .id = 0, + .cls = &timer_sysclass, }; -static int __init init_timer_devicefs(void) +static int __init init_timer_sysfs(void) { - driver_register(&timer_driver); - return sys_device_register(&device_timer); + int error = sysdev_class_register(&timer_sysclass); + if (!error) + error = sys_device_register(&device_timer); + return error; } -device_initcall(init_timer_devicefs); +device_initcall(init_timer_sysfs); void __init init_IRQ(void) { diff --git a/arch/i386/kernel/nmi.c b/arch/i386/kernel/nmi.c index e8910adcd6bb..656eb3bcff58 100644 --- a/arch/i386/kernel/nmi.c +++ b/arch/i386/kernel/nmi.c @@ -23,6 +23,7 @@ #include <linux/mc146818rtc.h> #include <linux/kernel_stat.h> #include <linux/module.h> +#include <linux/sysdev.h> #include <asm/smp.h> #include <asm/mtrr.h> @@ -180,53 +181,48 @@ void enable_lapic_nmi_watchdog(void) #ifdef CONFIG_PM -#include <linux/device.h> static int nmi_pm_active; /* nmi_active before suspend */ -static int lapic_nmi_suspend(struct device *dev, u32 state, u32 level) +static int lapic_nmi_suspend(struct sys_device *dev, u32 state) { - if (level != SUSPEND_POWER_DOWN) - return 0; nmi_pm_active = nmi_active; disable_lapic_nmi_watchdog(); return 0; } -static int lapic_nmi_resume(struct device *dev, u32 level) +static int lapic_nmi_resume(struct sys_device *dev) { - if (level != RESUME_POWER_ON) - return 0; if (nmi_pm_active > 0) enable_lapic_nmi_watchdog(); return 0; } -static struct device_driver lapic_nmi_driver = { - .name = "lapic_nmi", - .bus = &system_bus_type, + +static struct sysdev_class nmi_sysclass = { + set_kset_name("lapic_nmi"), .resume = lapic_nmi_resume, .suspend = lapic_nmi_suspend, }; static struct sys_device device_lapic_nmi = { - .name = "lapic_nmi", - .id = 0, - .dev = { - .name = "lapic_nmi", - .driver = &lapic_nmi_driver, - .parent = &device_lapic.dev, - }, + .id = 0, + .cls = &nmi_sysclass, }; -static int __init init_lapic_nmi_devicefs(void) +static int __init init_lapic_nmi_sysfs(void) { + int error; + if (nmi_active == 0) return 0; - driver_register(&lapic_nmi_driver); - return sys_device_register(&device_lapic_nmi); + + error = sysdev_class_register(&nmi_sysclass); + if (!error) + error = sys_device_register(&device_lapic_nmi); + return error; } /* must come after the local APIC's device_initcall() */ -late_initcall(init_lapic_nmi_devicefs); +late_initcall(init_lapic_nmi_sysfs); #endif /* CONFIG_PM */ diff --git a/arch/i386/kernel/time.c b/arch/i386/kernel/time.c index 2acbd3d6b0b3..13a6b41ddcd8 100644 --- a/arch/i386/kernel/time.c +++ b/arch/i386/kernel/time.c @@ -42,7 +42,7 @@ #include <linux/init.h> #include <linux/smp.h> #include <linux/module.h> -#include <linux/device.h> +#include <linux/sysdev.h> #include <linux/bcd.h> #include <asm/io.h> @@ -278,18 +278,22 @@ unsigned long get_cmos_time(void) return retval; } +static struct sysdev_class rtc_sysclass = { + set_kset_name("rtc"), +}; + /* XXX this driverfs stuff should probably go elsewhere later -john */ static struct sys_device device_i8253 = { - .name = "rtc", .id = 0, - .dev = { - .name = "i8253 Real Time Clock", - }, + .cls = &rtc_sysclass, }; static int time_init_device(void) { - return sys_device_register(&device_i8253); + int error = sysdev_class_register(&rtc_sysclass); + if (!error) + error = sys_device_register(&device_i8253); + return error; } device_initcall(time_init_device); diff --git a/arch/i386/oprofile/nmi_int.c b/arch/i386/oprofile/nmi_int.c index b6841b98a3ac..030f0fa8c45a 100644 --- a/arch/i386/oprofile/nmi_int.c +++ b/arch/i386/oprofile/nmi_int.c @@ -11,7 +11,7 @@ #include <linux/notifier.h> #include <linux/smp.h> #include <linux/oprofile.h> -#include <linux/device.h> +#include <linux/sysdev.h> #include <asm/nmi.h> #include <asm/msr.h> #include <asm/apic.h> @@ -31,53 +31,48 @@ static int nmi_enabled = 0; #ifdef CONFIG_PM -static int nmi_suspend(struct device *dev, u32 state, u32 level) +static int nmi_suspend(struct sys_device *dev, u32 state) { - if (level != SUSPEND_POWER_DOWN) - return 0; if (nmi_enabled == 1) nmi_stop(); return 0; } -static int nmi_resume(struct device *dev, u32 level) +static int nmi_resume(struct sys_device *dev) { - if (level != RESUME_POWER_ON) - return 0; if (nmi_enabled == 1) nmi_start(); return 0; } -static struct device_driver nmi_driver = { - .name = "oprofile", - .bus = &system_bus_type, +static struct sysdev_class oprofile_sysclass = { + set_kset_name("oprofile"), .resume = nmi_resume, .suspend = nmi_suspend, }; -static struct device device_nmi = { - .name = "oprofile", - .bus_id = "oprofile", - .driver = &nmi_driver, - .parent = &device_lapic.dev, +static struct sys_device device_oprofile = { + .id = 0, + .cls = &oprofile_sysclass, }; static int __init init_driverfs(void) { - driver_register(&nmi_driver); - return device_register(&device_nmi); + int error; + if (!(error = sysdev_class_register(&oprofile_sysclass))) + error = sys_device_register(&device_oprofile); + return error; } static void __exit exit_driverfs(void) { - device_unregister(&device_nmi); - driver_unregister(&nmi_driver); + sys_device_unregister(&device_oprofile); + sysdev_class_unregister(&oprofile_sysclass); } #else diff --git a/arch/x86_64/kernel/i8259.c b/arch/x86_64/kernel/i8259.c index 61eb01ca8716..ce6ea7a396be 100644 --- a/arch/x86_64/kernel/i8259.c +++ b/arch/x86_64/kernel/i8259.c @@ -11,7 +11,7 @@ #include <linux/smp_lock.h> #include <linux/init.h> #include <linux/kernel_stat.h> -#include <linux/device.h> +#include <linux/sysdev.h> #include <asm/atomic.h> #include <asm/system.h> @@ -413,35 +413,31 @@ static void setup_timer(void) outb(LATCH >> 8 , 0x40); /* MSB */ } -static int timer_resume(struct device *dev, u32 level) +static int timer_resume(struct sys_device *dev) { - if (level == RESUME_POWER_ON) - setup_timer(); + setup_timer(); return 0; } -static struct device_driver timer_driver = { - .name = "timer", - .bus = &system_bus_type, +static struct sysdev_class timer_sysclass = { + set_kset_name("timer"), .resume = timer_resume, }; static struct sys_device device_timer = { - .name = "timer", .id = 0, - .dev = { - .name = "timer", - .driver = &timer_driver, - }, + .cls &timer_sysclass, }; -static int __init init_timer_devicefs(void) +static int __init init_timer_sysfs(void) { - driver_register(&timer_driver); - return sys_device_register(&device_timer); + int error = sysdev_class_register(&timer_sysclass); + if (!error) + error = sys_device_register(&device_timer); + return error; } -device_initcall(init_timer_devicefs); +device_initcall(init_timer_sysfs); void __init init_IRQ(void) { diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c index 78a9f57e48f3..4456bceabeaf 100644 --- a/drivers/base/cpu.c +++ b/drivers/base/cpu.c @@ -2,23 +2,18 @@ * drivers/base/cpu.c - basic CPU class support */ -#include <linux/device.h> +#include <linux/sysdev.h> #include <linux/module.h> #include <linux/init.h> #include <linux/cpu.h> #include <linux/topology.h> -struct class cpu_class = { - .name = "cpu", +struct sysdev_class cpu_sysdev_class = { + set_kset_name("cpu"), }; -struct device_driver cpu_driver = { - .name = "cpu", - .bus = &system_bus_type, -}; - /* * register_cpu - Setup a driverfs device for a CPU. * @num - CPU number to use when creating the device. @@ -27,42 +22,15 @@ struct device_driver cpu_driver = { */ int __init register_cpu(struct cpu *cpu, int num, struct node *root) { - int retval; - cpu->node_id = cpu_to_node(num); - cpu->sysdev.name = "cpu"; cpu->sysdev.id = num; - if (root) - cpu->sysdev.root = &root->sysroot; - snprintf(cpu->sysdev.dev.name, DEVICE_NAME_SIZE, "CPU %u", num); - cpu->sysdev.dev.driver = &cpu_driver; - retval = sys_device_register(&cpu->sysdev); - if (retval) - return retval; - memset(&cpu->sysdev.class_dev, 0x00, sizeof(struct class_device)); - cpu->sysdev.class_dev.dev = &cpu->sysdev.dev; - cpu->sysdev.class_dev.class = &cpu_class; - snprintf(cpu->sysdev.class_dev.class_id, BUS_ID_SIZE, "cpu%d", num); - retval = class_device_register(&cpu->sysdev.class_dev); - if (retval) { - sys_device_unregister(&cpu->sysdev); - return retval; - } - return 0; + cpu->sysdev.cls = &cpu_sysdev_class; + return sys_device_register(&cpu->sysdev); } + int __init cpu_dev_init(void) { - int error; - - error = class_register(&cpu_class); - if (error) - goto out; - - error = driver_register(&cpu_driver); - if (error) - class_unregister(&cpu_class); -out: - return error; + return sysdev_class_register(&cpu_sysdev_class); } diff --git a/drivers/base/memblk.c b/drivers/base/memblk.c index cbaa98b3dce1..f3f3fdf7292c 100644 --- a/drivers/base/memblk.c +++ b/drivers/base/memblk.c @@ -2,7 +2,6 @@ * drivers/base/memblk.c - basic Memory Block class support */ -#include <linux/device.h> #include <linux/module.h> #include <linux/init.h> #include <linux/memblk.h> @@ -10,8 +9,8 @@ #include <linux/topology.h> -static struct class memblk_class = { - .name = "memblk", +static struct sysdev_class memblk_class = { + set_kset_name("memblk"), }; @@ -29,27 +28,23 @@ static struct device_driver memblk_driver = { */ int __init register_memblk(struct memblk *memblk, int num, struct node *root) { + int error; + memblk->node_id = memblk_to_node(num); - memblk->sysdev.name = "memblk"; + memblk->sysdev.cls = &memblk_class, memblk->sysdev.id = num; - if (root) - memblk->sysdev.root = &root->sysroot; - snprintf(memblk->sysdev.dev.name, DEVICE_NAME_SIZE, "Memory Block %u", num); - memblk->sysdev.dev.driver = &memblk_driver; - return sys_device_register(&memblk->sysdev); + + error = sys_device_register(&memblk->sysdev); + if (!error) + error = sysfs_create_link(&root->sysdev.kobj, + &memblk->sysdev,kobj, + memblk->sysdev.kobj.name); + return error; } int __init register_memblk_type(void) { - int error; - - error = class_register(&memblk_class); - if (!error) { - error = driver_register(&memblk_driver); - if (error) - class_unregister(&memblk_class); - } - return error; + return sysdev_class_register(&memblk_class); } postcore_initcall(register_memblk_type); diff --git a/drivers/base/node.c b/drivers/base/node.c index 2f77b0afb862..08e7c52c68e6 100644 --- a/drivers/base/node.c +++ b/drivers/base/node.c @@ -9,15 +9,8 @@ #include <linux/node.h> #include <linux/topology.h> - -static struct class node_class = { - .name = "node", -}; - - -static struct device_driver node_driver = { - .name = "node", - .bus = &system_bus_type, +static struct sysdev_class node_class = { + set_kset_name("node"), }; @@ -26,7 +19,7 @@ static ssize_t node_read_cpumap(struct device * dev, char * buf) struct node *node_dev = to_node(to_root(dev)); return sprintf(buf,"%lx\n",node_dev->cpumap); } -static DEVICE_ATTR(cpumap,S_IRUGO,node_read_cpumap,NULL); +static SYSDEV_ATTR(cpumap,S_IRUGO,node_read_cpumap,NULL); #define K(x) ((x) << (PAGE_SHIFT - 10)) static ssize_t node_read_meminfo(struct device * dev, char * buf) @@ -52,7 +45,7 @@ static ssize_t node_read_meminfo(struct device * dev, char * buf) nid, K(i.freeram-i.freehigh)); } #undef K -static DEVICE_ATTR(meminfo,S_IRUGO,node_read_meminfo,NULL); +static SYSDEV_ATTR(meminfo,S_IRUGO,node_read_meminfo,NULL); /* @@ -66,17 +59,13 @@ int __init register_node(struct node *node, int num, struct node *parent) int error; node->cpumap = node_to_cpumask(num); - node->sysroot.id = num; - if (parent) - node->sysroot.dev.parent = &parent->sysroot.sysdev; - snprintf(node->sysroot.dev.name, DEVICE_NAME_SIZE, "Node %u", num); - snprintf(node->sysroot.dev.bus_id, BUS_ID_SIZE, "node%u", num); - node->sysroot.dev.driver = &node_driver; - node->sysroot.dev.bus = &system_bus_type; - error = sys_register_root(&node->sysroot); + node->sysdev.id = num; + node->sysdev.cls = &node_class; + error = sys_device_register(&node->sysdev); + if (!error){ - device_create_file(&node->sysroot.dev, &dev_attr_cpumap); - device_create_file(&node->sysroot.dev, &dev_attr_meminfo); + sys_device_create_file(&node->sysroot.dev, &attr_cpumap); + sys_device_create_file(&node->sysroot.dev, &attr_meminfo); } return error; } @@ -84,14 +73,6 @@ int __init register_node(struct node *node, int num, struct node *parent) int __init register_node_type(void) { - int error; - - error = class_register(&node_class); - if (!error) { - error = driver_register(&node_driver); - if (error) - class_unregister(&node_class); - } - return error; + return sysdev_class_register(&node_class); } postcore_initcall(register_node_type); diff --git a/drivers/base/power.c b/drivers/base/power.c index e389891c574d..7f5a6abc4e00 100644 --- a/drivers/base/power.c +++ b/drivers/base/power.c @@ -22,6 +22,21 @@ extern struct subsystem devices_subsys; /** + * We handle system devices differently - we suspend and shut them + * down first and resume them first. That way, we do anything stupid like + * shutting down the interrupt controller before any devices.. + * + * Note that there are not different stages for power management calls - + * they only get one called once when interrupts are disabled. + */ + +extern int sysdev_shutdown(void); +extern int sysdev_save(u32 state); +extern int sysdev_suspend(u32 state); +extern int sysdev_resume(void); +extern int sysdev_restore(void); + +/** * device_suspend - suspend/remove all devices on the device ree * @state: state we're entering * @level: what stage of the suspend process we're at @@ -50,6 +65,21 @@ int device_suspend(u32 state, u32 level) } } up_write(&devices_subsys.rwsem); + + /* + * Make sure system devices are suspended. + */ + switch(level) { + case SUSPEND_SAVE_STATE: + sysdev_save(state); + break; + case SUSPEND_POWER_DOWN: + sysdev_suspend(state); + break; + default: + break; + } + return error; } @@ -65,6 +95,17 @@ void device_resume(u32 level) { struct list_head * node; + switch (level) { + case RESUME_POWER_ON: + sysdev_resume(); + break; + case RESUME_RESTORE_STATE: + sysdev_restore(); + break; + default: + break; + } + down_write(&devices_subsys.rwsem); list_for_each_prev(node,&devices_subsys.kset.list) { struct device * dev = to_dev(node); @@ -98,6 +139,8 @@ void device_shutdown(void) pr_debug("Ignored.\n"); } up_write(&devices_subsys.rwsem); + + sysdev_shutdown(); } EXPORT_SYMBOL(device_suspend); diff --git a/drivers/base/sys.c b/drivers/base/sys.c index 5ae457170548..34001cb52fa1 100644 --- a/drivers/base/sys.c +++ b/drivers/base/sys.c @@ -12,9 +12,9 @@ * add themselves as children of the system bus. */ -#undef DEBUG +#define DEBUG -#include <linux/device.h> +#include <linux/sysdev.h> #include <linux/err.h> #include <linux/module.h> #include <linux/kernel.h> @@ -22,130 +22,435 @@ #include <linux/slab.h> #include <linux/string.h> -/* The default system device parent. */ -static struct device system_bus = { - .name = "System Bus", - .bus_id = "sys", + +extern struct subsystem devices_subsys; + +#define to_sysdev(k) container_of(k,struct sys_device,kobj) +#define to_sysdev_attr(a) container_of(a,struct sysdev_attribute,attr) + + +static ssize_t +sysdev_show(struct kobject * kobj, struct attribute * attr, char * buffer) +{ + struct sys_device * sysdev = to_sysdev(kobj); + struct sysdev_attribute * sysdev_attr = to_sysdev_attr(attr); + + if (sysdev_attr->show) + return sysdev_attr->show(sysdev,buffer); + return 0; +} + + +static ssize_t +sysdev_store(struct kobject * kobj, struct attribute * attr, + const char * buffer, size_t count) +{ + struct sys_device * sysdev = to_sysdev(kobj); + struct sysdev_attribute * sysdev_attr = to_sysdev_attr(attr); + + if (sysdev_attr->store) + return sysdev_attr->store(sysdev,buffer,count); + return 0; +} + +static struct sysfs_ops sysfs_ops = { + .show = sysdev_show, + .store = sysdev_store, +}; + +static struct kobj_type ktype_sysdev = { + .sysfs_ops = &sysfs_ops, }; +/* + * declare system_subsys + */ +decl_subsys(system,&ktype_sysdev,NULL); + +int sysdev_class_register(struct sysdev_class * cls) +{ + pr_debug("Registering sysdev class '%s'\n",cls->kset.kobj.name); + INIT_LIST_HEAD(&cls->drivers); + cls->kset.subsys = &system_subsys; + kset_set_kset_s(cls,system_subsys); + return kset_register(&cls->kset); +} + +void sysdev_class_unregister(struct sysdev_class * cls) +{ + pr_debug("Unregistering sysdev class '%s'\n",cls->kset.kobj.name); + kset_unregister(&cls->kset); +} + +EXPORT_SYMBOL(sysdev_class_register); +EXPORT_SYMBOL(sysdev_class_unregister); + + +static LIST_HEAD(global_drivers); /** - * sys_register_root - add a subordinate system root - * @root: new root - * - * This is for NUMA-like systems so they can accurately - * represent the topology of the entire system. - * As boards are discovered, a new struct sys_root should - * be allocated and registered. - * The discovery mechanism should initialize the id field - * of the struture, as well as much of the embedded device - * structure as possible, inlcuding the name, the bus_id - * and parent fields. + * sysdev_driver_register - Register auxillary driver + * @cls: Device class driver belongs to. + * @drv: Driver. * - * This simply calls device_register on the embedded device. - * On success, it will use the struct @root->sysdev - * device to create a pseudo-parent for system devices - * on that board. + * If @cls is valid, then @drv is inserted into @cls->drivers to be + * called on each operation on devices of that class. The refcount + * of @cls is incremented. + * Otherwise, @drv is inserted into global_drivers, and called for + * each device. + */ + +int sysdev_driver_register(struct sysdev_class * cls, + struct sysdev_driver * drv) +{ + down_write(&system_subsys.rwsem); + if (cls && kset_get(&cls->kset)) + list_add_tail(&drv->entry,&cls->drivers); + else + list_add_tail(&drv->entry,&global_drivers); + up_write(&system_subsys.rwsem); + return 0; +} + + +/** + * sysdev_driver_unregister - Remove an auxillary driver. + * @cls: Class driver belongs to. + * @drv: Driver. + */ +void sysdev_driver_unregister(struct sysdev_class * cls, + struct sysdev_driver * drv) +{ + down_write(&system_subsys.rwsem); + list_del_init(&drv->entry); + if (cls) + kset_put(&cls->kset); + up_write(&system_subsys.rwsem); +} + + +/** + * sys_device_register - add a system device to the tree + * @sysdev: device in question * - * The platform code can then use @root to specifiy the - * controlling board when discovering and registering - * system devices. */ -int sys_register_root(struct sys_root * root) +int sys_device_register(struct sys_device * sysdev) { - int error = 0; + int error; + struct sysdev_class * cls = sysdev->cls; - if (!root) + if (!cls) return -EINVAL; - if (!root->dev.parent) - root->dev.parent = &system_bus; + /* Make sure the kset is set */ + sysdev->kobj.kset = &cls->kset; + + /* set the kobject name */ + snprintf(sysdev->kobj.name,KOBJ_NAME_LEN,"%s%d", + cls->kset.kobj.name,sysdev->id); - pr_debug("Registering system board %d\n",root->id); + pr_debug("Registering sys device '%s'\n",sysdev->kobj.name); + + /* Register the object */ + error = kobject_register(&sysdev->kobj); - error = device_register(&root->dev); if (!error) { - strlcpy(root->sysdev.bus_id,"sys",BUS_ID_SIZE); - strlcpy(root->sysdev.name,"System Bus",DEVICE_NAME_SIZE); - root->sysdev.parent = &root->dev; - error = device_register(&root->sysdev); - }; + struct sysdev_driver * drv; + + down_read(&system_subsys.rwsem); + /* Generic notification is implicit, because it's that + * code that should have called us. + */ + /* Notify global drivers */ + list_for_each_entry(drv,&global_drivers,entry) { + if (drv->add) + drv->add(sysdev); + } + + /* Notify class auxillary drivers */ + list_for_each_entry(drv,&cls->drivers,entry) { + if (drv->add) + drv->add(sysdev); + } + up_read(&system_subsys.rwsem); + } return error; } +void sys_device_unregister(struct sys_device * sysdev) +{ + struct sysdev_driver * drv; + + down_read(&system_subsys.rwsem); + list_for_each_entry(drv,&global_drivers,entry) { + if (drv->remove) + drv->remove(sysdev); + } + + list_for_each_entry(drv,&sysdev->cls->drivers,entry) { + if (drv->remove) + drv->remove(sysdev); + } + up_read(&system_subsys.rwsem); + + kobject_unregister(&sysdev->kobj); +} + + + /** - * sys_unregister_root - remove subordinate root from tree - * @root: subordinate root in question. + * sysdev_shutdown - Shut down all system devices. + * + * Loop over each class of system devices, and the devices in each + * of those classes. For each device, we call the shutdown method for + * each driver registered for the device - the globals, the auxillaries, + * and the class driver. * - * We only decrement the reference count on @root->sysdev - * and @root->dev. - * If both are 0, they will be cleaned up by the core. + * Note: The list is iterated in reverse order, so that we shut down + * child devices before we shut down thier parents. The list ordering + * is guaranteed by virtue of the fact that child devices are registered + * after their parents. */ -void sys_unregister_root(struct sys_root *root) + +void sysdev_shutdown(void) { - device_unregister(&root->sysdev); - device_unregister(&root->dev); + struct sysdev_class * cls; + + pr_debug("Shutting Down System Devices\n"); + + down_write(&system_subsys.rwsem); + list_for_each_entry_reverse(cls,&system_subsys.kset.list, + kset.kobj.entry) { + struct sys_device * sysdev; + + pr_debug("Shutting down type '%s':\n",cls->kset.kobj.name); + + list_for_each_entry(sysdev,&cls->kset.list,kobj.entry) { + struct sysdev_driver * drv; + pr_debug(" %s\n",sysdev->kobj.name); + + /* Call global drivers first. */ + list_for_each_entry(drv,&global_drivers,entry) { + if (drv->shutdown) + drv->shutdown(sysdev); + } + + /* Call auxillary drivers next. */ + list_for_each_entry(drv,&cls->drivers,entry) { + if (drv->shutdown) + drv->shutdown(sysdev); + } + + /* Now call the generic one */ + if (cls->shutdown) + cls->shutdown(sysdev); + } + } + up_write(&system_subsys.rwsem); } + /** - * sys_device_register - add a system device to the tree - * @sysdev: device in question + * sysdev_save - Save system device state + * @state: Power state we're entering. * - * The hardest part about this is getting the ancestry right. - * If the device has a parent - super! We do nothing. - * If the device doesn't, but @dev->root is set, then we're - * dealing with a NUMA like architecture where each root - * has a system pseudo-bus to foster the device. - * If not, then we fallback to system_bus (at the top of - * this file). + * This is called when the system is going to sleep, but before interrupts + * have been disabled. This allows system device drivers to allocate and + * save device state, including sleeping during the process.. + */ + +int sysdev_save(u32 state) +{ + struct sysdev_class * cls; + + pr_debug("Saving System Device State\n"); + + down_write(&system_subsys.rwsem); + + list_for_each_entry_reverse(cls,&system_subsys.kset.list, + kset.kobj.entry) { + struct sys_device * sysdev; + pr_debug("Saving state for type '%s':\n",cls->kset.kobj.name); + + list_for_each_entry(sysdev,&cls->kset.list,kobj.entry) { + struct sysdev_driver * drv; + + pr_debug(" %s\n",sysdev->kobj.name); + + list_for_each_entry(drv,&global_drivers,entry) { + if (drv->save) + drv->save(sysdev,state); + } + + list_for_each_entry(drv,&cls->drivers,entry) { + if (drv->save) + drv->save(sysdev,state); + } + + if (cls->save) + cls->save(sysdev,state); + } + } + up_write(&system_subsys.rwsem); + return 0; +} + + +/** + * sysdev_suspend - Suspend all system devices. + * @state: Power state to enter. * - * One way or another, we call device_register() on it and - * are done. + * We perform an almost identical operation as sys_device_shutdown() + * above, though calling ->suspend() instead. * - * The caller is also responsible for initializing the bus_id - * and name fields of @sysdev->dev. + * Note: Interrupts are disabled when called, so we can't sleep when + * trying to get the subsystem's rwsem. If that happens, print a nasty + * warning and return an error. */ -int sys_device_register(struct sys_device * sysdev) + +int sysdev_suspend(u32 state) { - if (!sysdev) - return -EINVAL; + struct sysdev_class * cls; + + pr_debug("Suspending System Devices\n"); - if (!sysdev->dev.parent) { - if (sysdev->root) - sysdev->dev.parent = &sysdev->root->sysdev; - else - sysdev->dev.parent = &system_bus; + if (!down_write_trylock(&system_subsys.rwsem)) { + printk("%s: Cannot acquire semaphore; Failing\n",__FUNCTION__); + return -EFAULT; } - /* make sure bus type is set */ - if (!sysdev->dev.bus) - sysdev->dev.bus = &system_bus_type; + list_for_each_entry_reverse(cls,&system_subsys.kset.list, + kset.kobj.entry) { + struct sys_device * sysdev; + + pr_debug("Suspending type '%s':\n",cls->kset.kobj.name); + + list_for_each_entry(sysdev,&cls->kset.list,kobj.entry) { + struct sysdev_driver * drv; + pr_debug(" %s\n",sysdev->kobj.name); - /* construct bus_id */ - snprintf(sysdev->dev.bus_id,BUS_ID_SIZE,"%s%u",sysdev->name,sysdev->id); + /* Call global drivers first. */ + list_for_each_entry(drv,&global_drivers,entry) { + if (drv->suspend) + drv->suspend(sysdev,state); + } - pr_debug("Registering system device %s\n", sysdev->dev.bus_id); + /* Call auxillary drivers next. */ + list_for_each_entry(drv,&cls->drivers,entry) { + if (drv->suspend) + drv->suspend(sysdev,state); + } - return device_register(&sysdev->dev); + /* Now call the generic one */ + if (cls->suspend) + cls->suspend(sysdev,state); + } + } + up_write(&system_subsys.rwsem); + + return 0; } -void sys_device_unregister(struct sys_device * sysdev) + +/** + * sysdev_resume - Bring system devices back to life. + * + * Similar to sys_device_suspend(), but we iterate the list forwards + * to guarantee that parent devices are resumed before their children. + * + * Note: Interrupts are disabled when called. + */ + +int sysdev_resume(void) { - if (sysdev) - device_unregister(&sysdev->dev); + struct sysdev_class * cls; + + pr_debug("Resuming System Devices\n"); + + if(!down_write_trylock(&system_subsys.rwsem)) + return -EFAULT; + + list_for_each_entry(cls,&system_subsys.kset.list,kset.kobj.entry) { + struct sys_device * sysdev; + + pr_debug("Resuming type '%s':\n",cls->kset.kobj.name); + + list_for_each_entry(sysdev,&cls->kset.list,kobj.entry) { + struct sysdev_driver * drv; + pr_debug(" %s\n",sysdev->kobj.name); + + /* First, call the class-specific one */ + if (cls->resume) + cls->resume(sysdev); + + /* Call auxillary drivers next. */ + list_for_each_entry(drv,&cls->drivers,entry) { + if (drv->resume) + drv->resume(sysdev); + } + + /* Call global drivers. */ + list_for_each_entry(drv,&global_drivers,entry) { + if (drv->resume) + drv->resume(sysdev); + } + + } + } + up_write(&system_subsys.rwsem); + return 0; +} + + +/** + * sysdev_restore - Restore system device state + * + * This is called during a suspend/resume cycle last, after interrupts + * have been re-enabled. This is intended for auxillary drivers, etc, + * that may sleep when restoring state. + */ + +int sysdev_restore(void) +{ + struct sysdev_class * cls; + + down_write(&system_subsys.rwsem); + pr_debug("Restoring System Device State\n"); + + list_for_each_entry(cls,&system_subsys.kset.list,kset.kobj.entry) { + struct sys_device * sysdev; + + pr_debug("Restoring state for type '%s':\n",cls->kset.kobj.name); + list_for_each_entry(sysdev,&cls->kset.list,kobj.entry) { + struct sysdev_driver * drv; + pr_debug(" %s\n",sysdev->kobj.name); + + if (cls->restore) + cls->restore(sysdev); + + list_for_each_entry(drv,&cls->drivers,entry) { + if (drv->restore) + drv->restore(sysdev); + } + + list_for_each_entry(drv,&global_drivers,entry) { + if (drv->restore) + drv->restore(sysdev); + } + } + } + + up_write(&system_subsys.rwsem); + return 0; } -struct bus_type system_bus_type = { - .name = "system", -}; int __init sys_bus_init(void) { - bus_register(&system_bus_type); - return device_register(&system_bus); + system_subsys.kset.kobj.parent = &devices_subsys.kset.kobj; + return subsystem_register(&system_subsys); } -EXPORT_SYMBOL(system_bus_type); EXPORT_SYMBOL(sys_device_register); EXPORT_SYMBOL(sys_device_unregister); diff --git a/drivers/s390/block/xpram.c b/drivers/s390/block/xpram.c index fbb02dd40042..486e0111891d 100644 --- a/drivers/s390/block/xpram.c +++ b/drivers/s390/block/xpram.c @@ -34,7 +34,7 @@ #include <linux/blk.h> #include <linux/blkpg.h> #include <linux/hdreg.h> /* HDIO_GETGEO */ -#include <linux/device.h> +#include <linux/sysdev.h> #include <linux/bio.h> #include <linux/devfs_fs_kernel.h> #include <asm/uaccess.h> @@ -48,12 +48,14 @@ #define PRINT_WARN(x...) printk(KERN_WARNING XPRAM_NAME " warning:" x) #define PRINT_ERR(x...) printk(KERN_ERR XPRAM_NAME " error:" x) + +static struct sysdev_class xpram_sysclass = { + set_kset_name("xpram"), +}; + static struct sys_device xpram_sys_device = { - .name = "S/390 expanded memory RAM disk", - .dev = { - .name = "S/390 expanded memory RAM disk", - .bus_id = "xpram", - }, + .id = 0, + .cls = &xpram_sysclass, }; typedef struct { @@ -485,6 +487,7 @@ static void __exit xpram_exit(void) unregister_blkdev(XPRAM_MAJOR, XPRAM_NAME); devfs_remove("slram"); sys_device_unregister(&xpram_sys_device); + sysdev_class_unregister(&xpram_sys_class); } static int __init xpram_init(void) @@ -502,9 +505,15 @@ static int __init xpram_init(void) rc = xpram_setup_sizes(xpram_pages); if (rc) return rc; - rc = sys_device_register(&xpram_sys_device); + rc = sysdev_class_register(&xpram_sysclass); if (rc) return rc; + + rc = sys_device_register(&xpram_sys_device); + if (rc) { + sysdev_class_unregister(&xpram_syclass); + return rc; + } rc = xpram_setup_blkdev(); if (rc) sys_device_unregister(&xpram_sys_device); diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index 26796e91bb16..3c9f3ef77a54 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -84,7 +84,7 @@ static int fill_read_buffer(struct file * file, struct sysfs_buffer * buffer) ssize_t count; if (!buffer->page) - buffer->page = (char *) __get_free_page(GFP_KERNEL); + buffer->page = (char *) get_zeroed_page(GFP_KERNEL); if (!buffer->page) return -ENOMEM; @@ -174,7 +174,7 @@ fill_write_buffer(struct sysfs_buffer * buffer, const char * buf, size_t count) int error; if (!buffer->page) - buffer->page = (char *)__get_free_page(GFP_KERNEL); + buffer->page = (char *)get_zeroed_page(GFP_KERNEL); if (!buffer->page) return -ENOMEM; diff --git a/include/linux/cpu.h b/include/linux/cpu.h index 93853448aeb9..2f374d79f157 100644 --- a/include/linux/cpu.h +++ b/include/linux/cpu.h @@ -19,7 +19,7 @@ #ifndef _LINUX_CPU_H_ #define _LINUX_CPU_H_ -#include <linux/device.h> +#include <linux/sysdev.h> #include <linux/node.h> #include <asm/semaphore.h> @@ -29,8 +29,6 @@ struct cpu { }; extern int register_cpu(struct cpu *, int, struct node *); -extern struct class cpu_class; - struct notifier_block; #ifdef CONFIG_SMP @@ -48,6 +46,7 @@ static inline void unregister_cpu_notifier(struct notifier_block *nb) { } #endif /* CONFIG_SMP */ +extern struct sysdev_class cpu_sysdev_class; /* Stop CPUs going up and down. */ extern struct semaphore cpucontrol; diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index 3dc9062bd414..1bdb797bf9bd 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -205,10 +205,6 @@ struct freq_attr { int cpufreq_set_policy(struct cpufreq_policy *policy); int cpufreq_get_policy(struct cpufreq_policy *policy, unsigned int cpu); -#ifdef CONFIG_PM -int cpufreq_restore(void); -#endif - /* the proc_intf.c needs this */ int cpufreq_parse_governor (char *str_governor, unsigned int *policy, struct cpufreq_governor **governor); diff --git a/include/linux/device.h b/include/linux/device.h index 3604d351f3f0..1bd92551c077 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -351,30 +351,6 @@ extern int (*platform_notify_remove)(struct device * dev); extern struct device * get_device(struct device * dev); extern void put_device(struct device * dev); -/* drivers/base/sys.c */ - -struct sys_root { - u32 id; - struct device dev; - struct device sysdev; -}; - -extern int sys_register_root(struct sys_root *); -extern void sys_unregister_root(struct sys_root *); - - -struct sys_device { - char * name; - u32 id; - struct sys_root * root; - struct device dev; - struct class_device class_dev; -}; - -extern int sys_device_register(struct sys_device *); -extern void sys_device_unregister(struct sys_device *); - -extern struct bus_type system_bus_type; /* drivers/base/platform.c */ diff --git a/include/linux/kobject.h b/include/linux/kobject.h index c982391cf8d6..5d42248dd95f 100644 --- a/include/linux/kobject.h +++ b/include/linux/kobject.h @@ -118,6 +118,14 @@ static inline struct kobj_type * get_ktype(struct kobject * k) extern struct kobject * kset_find_obj(struct kset *, const char *); +/** + * Use this when initializing an embedded kset with no other + * fields to initialize. + */ +#define set_kset_name(str) .kset = { .kobj = { .name = str } } + + + struct subsystem { struct kset kset; struct rw_semaphore rwsem; diff --git a/include/linux/list.h b/include/linux/list.h index d6305f84bfe6..eed55ea5860a 100644 --- a/include/linux/list.h +++ b/include/linux/list.h @@ -310,6 +310,20 @@ static inline void list_splice_init(struct list_head *list, prefetch(pos->member.next)) /** + * list_for_each_entry_reverse - iterate backwards over list of given type. + * @pos: the type * to use as a loop counter. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry_reverse(pos, head, member) \ + for (pos = list_entry((head)->prev, typeof(*pos), member), \ + prefetch(pos->member.prev); \ + &pos->member != (head); \ + pos = list_entry(pos->member.prev, typeof(*pos), member), \ + prefetch(pos->member.prev)) + + +/** * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry * @pos: the type * to use as a loop counter. * @n: another type * to use as temporary storage diff --git a/include/linux/node.h b/include/linux/node.h index 294606bbff5a..90543a94b86e 100644 --- a/include/linux/node.h +++ b/include/linux/node.h @@ -19,11 +19,11 @@ #ifndef _LINUX_NODE_H_ #define _LINUX_NODE_H_ -#include <linux/device.h> +#include <linux/sysdev.h> struct node { unsigned long cpumap; /* Bitmap of CPUs on the Node */ - struct sys_root sysroot; + struct sys_device sysdev; }; extern int register_node(struct node *, int, struct node *); diff --git a/include/linux/sysdev.h b/include/linux/sysdev.h new file mode 100644 index 000000000000..4bc3e22b5104 --- /dev/null +++ b/include/linux/sysdev.h @@ -0,0 +1,98 @@ +/** + * System devices follow a slightly different driver model. + * They don't need to do dynammic driver binding, can't be probed, + * and don't reside on any type of peripheral bus. + * So, we represent and treat them a little differently. + * + * We still have a notion of a driver for a system device, because we still + * want to perform basic operations on these devices. + * + * We also support auxillary drivers binding to devices of a certain class. + * + * This allows configurable drivers to register themselves for devices of + * a certain type. And, it allows class definitions to reside in generic + * code while arch-specific code can register specific drivers. + * + * Auxillary drivers registered with a NULL cls are registered as drivers + * for all system devices, and get notification calls for each device. + */ + + +#ifndef _SYSDEV_H_ +#define _SYSDEV_H_ + +#include <linux/kobject.h> + + +struct sys_device; + +struct sysdev_class { + struct list_head drivers; + + /* Default operations for these types of devices */ + int (*shutdown)(struct sys_device *); + int (*save)(struct sys_device *, u32 state); + int (*suspend)(struct sys_device *, u32 state); + int (*resume)(struct sys_device *); + int (*restore)(struct sys_device *); + struct kset kset; +}; + + +extern int sysdev_class_register(struct sysdev_class *); +extern void sysdev_class_unregister(struct sysdev_class *); + + +/** + * Auxillary system device drivers. + */ + +struct sysdev_driver { + struct list_head entry; + int (*add)(struct sys_device *); + int (*remove)(struct sys_device *); + int (*shutdown)(struct sys_device *); + int (*save)(struct sys_device *, u32 state); + int (*suspend)(struct sys_device *, u32 state); + int (*resume)(struct sys_device *); + int (*restore)(struct sys_device *); +}; + + +extern int sysdev_driver_register(struct sysdev_class *, struct sysdev_driver *); +extern void sysdev_driver_unregister(struct sysdev_class *, struct sysdev_driver *); + + +/** + * sys_devices can be simplified a lot from regular devices, because they're + * simply not as versatile. + */ + +struct sys_device { + u32 id; + struct sysdev_class * cls; + struct kobject kobj; +}; + +extern int sys_device_register(struct sys_device *); +extern void sys_device_unregister(struct sys_device *); + + +struct sysdev_attribute { + struct attribute attr; + ssize_t (*show)(struct sys_device *, char *); + ssize_t (*store)(struct sys_device *, const char *, size_t); +}; + + +#define SYSDEV_ATTR(_name,_mode,_show,_store) \ +struct sysdev_attribute attr_##_name = { \ + .attr = {.name = __stringify(_name), .mode = _mode }, \ + .show = _show, \ + .store = _store, \ +}; + +extern int sysdev_create_file(struct sys_device *, struct sysdev_attribute *); +extern void sysdev_remove_file(struct sys_device *, struct sysdev_attribute *); + +#endif /* _SYSDEV_H_ */ diff --git a/kernel/cpufreq.c b/kernel/cpufreq.c index ab772ccf9c59..6ae2b821830e 100644 --- a/kernel/cpufreq.c +++ b/kernel/cpufreq.c @@ -49,8 +49,6 @@ static DECLARE_RWSEM (cpufreq_notifier_rwsem); static LIST_HEAD(cpufreq_governor_list); static DECLARE_MUTEX (cpufreq_governor_sem); -static struct class_interface cpufreq_interface; - static int cpufreq_cpu_get(unsigned int cpu) { if (cpu >= NR_CPUS) @@ -113,24 +111,8 @@ int cpufreq_parse_governor (char *str_governor, unsigned int *policy, EXPORT_SYMBOL_GPL(cpufreq_parse_governor); -/* forward declarations */ -static int cpufreq_add_dev (struct class_device * dev); -static void cpufreq_remove_dev (struct class_device * dev); - /* drivers/base/cpu.c */ -extern struct device_class cpu_devclass; - -static struct class_interface cpufreq_interface = { - .class = &cpu_class, - .add = &cpufreq_add_dev, - .remove = &cpufreq_remove_dev, -}; - -static inline int to_cpu_nr (struct class_device *dev) -{ - struct sys_device * cpu_sys_dev = container_of(dev->dev, struct sys_device, dev); - return (cpu_sys_dev->id); -} +extern struct sysdev_class cpu_sysdev_class; /** @@ -331,9 +313,9 @@ static struct kobj_type ktype_cpufreq = { * * Adds the cpufreq interface for a CPU device. */ -static int cpufreq_add_dev (struct class_device * class_dev) +static int cpufreq_add_dev (struct sys_device * sys_dev) { - unsigned int cpu = to_cpu_nr(class_dev); + unsigned int cpu = sys_dev->id; int ret = 0; struct cpufreq_policy new_policy; struct cpufreq_policy *policy; @@ -358,14 +340,12 @@ static int cpufreq_add_dev (struct class_device * class_dev) memcpy(&new_policy, policy, sizeof(struct cpufreq_policy)); - class_set_devdata(class_dev, policy); up(&cpufreq_driver_sem); init_MUTEX(&policy->lock); /* prepare interface data */ - policy->kobj.parent = &class_dev->kobj; + policy->kobj.parent = &sys_dev->kobj; policy->kobj.ktype = &ktype_cpufreq; -// policy->dev = dev->dev; strlcpy(policy->kobj.name, "cpufreq", KOBJ_NAME_LEN); ret = kobject_register(&policy->kobj); @@ -396,12 +376,12 @@ static int cpufreq_add_dev (struct class_device * class_dev) * * Removes the cpufreq interface for a CPU device. */ -static void cpufreq_remove_dev (struct class_device * class_dev) +static int cpufreq_remove_dev (struct sys_device * sys_dev) { - unsigned int cpu = to_cpu_nr(class_dev); + unsigned int cpu = sys_dev->id; if (!kobject_get(&cpufreq_driver->policy[cpu].kobj)) - return; + return -EFAULT; down(&cpufreq_driver_sem); if ((cpufreq_driver->target) && @@ -421,9 +401,17 @@ static void cpufreq_remove_dev (struct class_device * class_dev) up(&cpufreq_driver_sem); kobject_put(&cpufreq_driver->policy[cpu].kobj); - return; + return 0; } +static int cpufreq_restore(struct sys_device *); + +static struct sysdev_driver cpufreq_sysdev_driver = { + .add = cpufreq_add_dev, + .remove = cpufreq_remove_dev, + .restore = cpufreq_restore, +}; + /********************************************************************* * NOTIFIER LISTS INTERFACE * @@ -843,7 +831,7 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data) memset(cpufreq_driver->policy, 0, NR_CPUS * sizeof(struct cpufreq_policy)); - return class_interface_register(&cpufreq_interface); + return sysdev_driver_register(&cpu_sysdev_class,&cpufreq_sysdev_driver); } EXPORT_SYMBOL_GPL(cpufreq_register_driver); @@ -861,7 +849,7 @@ int cpufreq_unregister_driver(struct cpufreq_driver *driver) if (!cpufreq_driver || (driver != cpufreq_driver)) return -EINVAL; - class_interface_unregister(&cpufreq_interface); + sysdev_driver_unregister(&cpu_sysdev_class, &cpufreq_sysdev_driver); down(&cpufreq_driver_sem); kfree(cpufreq_driver->policy); @@ -874,41 +862,34 @@ EXPORT_SYMBOL_GPL(cpufreq_unregister_driver); #ifdef CONFIG_PM + /** * cpufreq_restore - restore the CPU clock frequency after resume * * Restore the CPU clock frequency so that our idea of the current * frequency reflects the actual hardware. */ -int cpufreq_restore(void) +static int cpufreq_restore(struct sys_device * sysdev) { - struct cpufreq_policy policy; - unsigned int i; + int cpu = sysdev->id; unsigned int ret = 0; + struct cpufreq_policy policy; - if (in_interrupt()) - panic("cpufreq_restore() called from interrupt context!"); - - if (!try_module_get(cpufreq_driver->owner)) - goto error_out; - - for (i=0;i<NR_CPUS;i++) { - if (!cpu_online(i) || !cpufreq_cpu_get(i)) - continue; - + if (cpu_online(cpu) && cpufreq_cpu_get(cpu)) { down(&cpufreq_driver_sem); - memcpy(&policy, &cpufreq_driver->policy[i], sizeof(struct cpufreq_policy)); + memcpy(&policy, &cpufreq_driver->policy[cpu], + sizeof(struct cpufreq_policy)); up(&cpufreq_driver_sem); - ret += cpufreq_set_policy(&policy); - - cpufreq_cpu_put(i); + ret = cpufreq_set_policy(&policy); + cpufreq_cpu_put(cpu); } - module_put(cpufreq_driver->owner); - error_out: return ret; } -EXPORT_SYMBOL_GPL(cpufreq_restore); + #else -#define cpufreq_restore() do {} while (0) +static int cpufreq_restore(struct sys_device * sysdev) +{ + return 0; +} #endif /* CONFIG_PM */ |
