From a4ff342afe2d05c6bb8f479b51c7365412763e9c Mon Sep 17 00:00:00 2001 From: Patrick Mochel Date: Mon, 9 Jun 2003 02:40:02 -0700 Subject: [driver model] Rewrite system device API System devices are special, and after two years of listening to Linus preach this, it finally sunk in enough to do something about. We don't need to regard them as real devices that reside on a peripheral bus and can be dynamically bound to drivers. If we discover, e.g. a CPU, we know by default that we have a driver for it, and we know damn well that we have a CPU. We still need to keep track of all the devices, and all the devices of a particular type. The kobject infrastructure allows us to do this, without the overhead of the regular model. A new subsystem is defined that registers as a child object of devices_subsys, giving us: /sys/devices/system/ struct sysdev_class { struct list_head drivers; /* Default operations for these types of devices */ int (*shutdown)(struct sys_device *); int (*suspend)(struct sys_device *, u32 state); int (*resume)(struct sys_device *); struct kset kset; }; Defines a type of system device. These are registered on startup, by e.g. drivers/base/cpu.c. The methods are default operations for devices of that type that may or may not be used. For things like the i8259 controller, these will be filled in, since it is registered by the same component that the device controls reside in. For things like CPUs, generic code will register the class, but other architecture-specific or otherwise configurable drivers may register auxillary drivers, that look like: struct sysdev_driver { struct list_head entry; int (*add)(struct sys_device *); int (*remove)(struct sys_device *); int (*shutdown)(struct sys_device *); int (*suspend)(struct sys_device *, u32 state); int (*resume)(struct sys_device *); }; Each auxillary driver gets called during each operation on a device of a particular class. Auxillary drivers may register with a NULL class parameter, in which case they will be added to a list of 'global drivers' that get called for each device of each class. Besides providing a decent of cleanup for system device drivers, this also allows: - Special handling of system devices during power transitions. We no longer have to worry about shutting down the PIC before we shut down any devices. We can shut down the system devices after we've shut down every other device. Ditto for suspend/resume cycles. Almost (if not) all PM actions for system devices happen with interrupts off, and require only one call, which makes that easier. But, we can also make sure we take care of these last during suspend and first during resume. - Easy expression of configurable device-specific interfaces. Namely cpufreq and mtrr. We don't have to worry about mispresentation in the driver model (like recent MTRR patches) or using a cumbersome interface ({device,class}_interface) that don't receive all the necessary calls. - Consolidation of userspace representation. No longer do we have /sys/devices/sys, /sys/bus/sys, and /sys/class/cpu, etc. We have only /sys/devices/system: # tree /sys/devices/system/ /sys/devices/system/ |-- cpu | `-- cpu0 |-- i8259 | `-- i82590 |-- lapic | `-- lapic0 |-- rtc | `-- rtc0 `-- timer `-- timer0 Each directory in 'system' is the class, and each directory under that is the instance of each device in that class. --- drivers/base/sys.c | 343 +++++++++++++++++++++++++++++++++++++------------ include/linux/device.h | 68 ++++++++-- 2 files changed, 318 insertions(+), 93 deletions(-) diff --git a/drivers/base/sys.c b/drivers/base/sys.c index 5ae457170548..aa71e40a865e 100644 --- a/drivers/base/sys.c +++ b/drivers/base/sys.c @@ -12,7 +12,7 @@ * add themselves as children of the system bus. */ -#undef DEBUG +#define DEBUG #include #include @@ -22,130 +22,307 @@ #include #include -/* The default system device parent. */ -static struct device system_bus = { - .name = "System Bus", - .bus_id = "sys", -}; +extern struct subsystem devices_subsys; + +/* + * declare system_subsys + */ +decl_subsys(system,NULL,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 (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 sys device '%s'\n",sysdev->kobj.name); - pr_debug("Registering system board %d\n",root->id); + /* 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. + * sys_device_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 sys_device_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 - * - * 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). + * sys_device_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 sys_device_suspend(u32 state) { - if (!sysdev) - return -EINVAL; + struct sysdev_class * cls; - if (!sysdev->dev.parent) { - if (sysdev->root) - sysdev->dev.parent = &sysdev->root->sysdev; - else - sysdev->dev.parent = &system_bus; + pr_debug("Suspending System Devices\n"); + + 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); - /* construct bus_id */ - snprintf(sysdev->dev.bus_id,BUS_ID_SIZE,"%s%u",sysdev->name,sysdev->id); + list_for_each_entry(sysdev,&cls->kset.list,kobj.entry) { + struct sysdev_driver * drv; + pr_debug(" %s\n",sysdev->kobj.name); - pr_debug("Registering system device %s\n", sysdev->dev.bus_id); + /* Call global drivers first. */ + list_for_each_entry(drv,&global_drivers,entry) { + if (drv->suspend) + drv->suspend(sysdev,state); + } - return device_register(&sysdev->dev); + /* Call auxillary drivers next. */ + list_for_each_entry(drv,&cls->drivers,entry) { + if (drv->suspend) + drv->suspend(sysdev,state); + } + + /* 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) + +/** + * sys_device_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 sys_device_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); -struct bus_type system_bus_type = { - .name = "system", -}; + 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->resume) + drv->resume(sysdev); + } + + /* Call auxillary drivers next. */ + list_for_each_entry(drv,&cls->drivers,entry) { + if (drv->resume) + drv->resume(sysdev); + } + + /* Now call the generic one */ + if (cls->resume) + cls->resume(sysdev); + } + } + up_write(&system_subsys.rwsem); + return 0; +} 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/include/linux/device.h b/include/linux/device.h index 3604d351f3f0..de674eaea31c 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -351,24 +351,72 @@ 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; +/** + * 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. + */ + +struct sys_device; + +struct sysdev_class { + struct list_head drivers; + + /* Default operations for these types of devices */ + int (*shutdown)(struct sys_device *); + int (*suspend)(struct sys_device *, u32 state); + int (*resume)(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 (*suspend)(struct sys_device *, u32 state); + int (*resume)(struct sys_device *); }; -extern int sys_register_root(struct sys_root *); -extern void sys_unregister_root(struct sys_root *); + +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 { - char * name; u32 id; - struct sys_root * root; - struct device dev; - struct class_device class_dev; + struct sysdev_class * cls; + struct kobject kobj; }; extern int sys_device_register(struct sys_device *); -- cgit v1.2.3 From fab9792907faadd0803217fd73801b5f9eb29922 Mon Sep 17 00:00:00 2001 From: Patrick Mochel Date: Mon, 9 Jun 2003 02:40:34 -0700 Subject: [list.h] Add list_for_each_entry_reverse --- include/linux/list.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/include/linux/list.h b/include/linux/list.h index a6dea8afd99d..c46a278cce05 100644 --- a/include/linux/list.h +++ b/include/linux/list.h @@ -296,6 +296,20 @@ static inline void list_splice_init(struct list_head *list, pos = list_entry(pos->member.next, typeof(*pos), member), \ 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. -- cgit v1.2.3 From 651d7ed273c8b08bae12928149e4b1dbc693e076 Mon Sep 17 00:00:00 2001 From: Patrick Mochel Date: Mon, 9 Jun 2003 02:41:22 -0700 Subject: [kobject] Add set_kset_name Shorthand macro for initializing only the name of an embedded kset in an object. --- include/linux/kobject.h | 8 ++++++++ 1 file changed, 8 insertions(+) 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; -- cgit v1.2.3 From 9777b1def2c760ad5c3b2185ee7376836576b48c Mon Sep 17 00:00:00 2001 From: Patrick Mochel Date: Mon, 9 Jun 2003 02:43:08 -0700 Subject: [driver model] Make sure that system devices are handled specially power-wise - Suspend system devices last, after interrupts have been enabled. - Resume them first, before interrupts are enabled. - Shut them down last, after everything else. --- drivers/base/power.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/drivers/base/power.c b/drivers/base/power.c index e389891c574d..081ad32cadfd 100644 --- a/drivers/base/power.c +++ b/drivers/base/power.c @@ -21,6 +21,19 @@ 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 sys_device_shutdown(void); +extern int sys_device_suspend(u32 state); +extern int sys_device_resume(void); + /** * device_suspend - suspend/remove all devices on the device ree * @state: state we're entering @@ -50,6 +63,10 @@ int device_suspend(u32 state, u32 level) } } up_write(&devices_subsys.rwsem); + + if (level == SUSPEND_POWER_DOWN) + sys_device_suspend(state); + return error; } @@ -65,6 +82,9 @@ void device_resume(u32 level) { struct list_head * node; + if (level == RESUME_POWER_ON) + sys_device_resume(); + down_write(&devices_subsys.rwsem); list_for_each_prev(node,&devices_subsys.kset.list) { struct device * dev = to_dev(node); @@ -98,6 +118,8 @@ void device_shutdown(void) pr_debug("Ignored.\n"); } up_write(&devices_subsys.rwsem); + + sys_device_shutdown(); } EXPORT_SYMBOL(device_suspend); -- cgit v1.2.3 From 60c37a8b605f5b372f53c536f2adfa3628a95184 Mon Sep 17 00:00:00 2001 From: Patrick Mochel Date: Mon, 9 Jun 2003 02:44:27 -0700 Subject: [driver model] Convert to new system device API --- drivers/base/cpu.c | 46 ++++++---------------------------------------- 1 file changed, 6 insertions(+), 40 deletions(-) diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c index c02afc0b6deb..f30b746a2ec5 100644 --- a/drivers/base/cpu.c +++ b/drivers/base/cpu.c @@ -9,15 +9,8 @@ #include - -struct class cpu_class = { - .name = "cpu", -}; - - -struct device_driver cpu_driver = { - .name = "cpu", - .bus = &system_bus_type, +struct sysdev_class cpu_sysdev_class = { + set_kset_name("cpu"), }; /* @@ -28,42 +21,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); } -- cgit v1.2.3 From 3cc944bbdbbff7c243899db177dd09a65bddac2c Mon Sep 17 00:00:00 2001 From: Patrick Mochel Date: Mon, 9 Jun 2003 19:36:33 -0700 Subject: [lapic] Convert to new system device API. --- arch/i386/kernel/apic.c | 39 +++++++++++++++++---------------------- 1 file changed, 17 insertions(+), 22 deletions(-) diff --git a/arch/i386/kernel/apic.c b/arch/i386/kernel/apic.c index 3f1216c60f44..33e8cda5dd56 100644 --- a/arch/i386/kernel/apic.c +++ b/arch/i386/kernel/apic.c @@ -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 */ -- cgit v1.2.3 From 1a28d3fd2da2aab73cf22562b5fa92db36499e14 Mon Sep 17 00:00:00 2001 From: Patrick Mochel Date: Mon, 9 Jun 2003 19:41:55 -0700 Subject: [i8259] Convert to use new system device API. --- arch/i386/kernel/i8259.c | 60 +++++++++++++++++++++--------------------------- 1 file changed, 26 insertions(+), 34 deletions(-) diff --git a/arch/i386/kernel/i8259.c b/arch/i386/kernel/i8259.c index fb6d35da09e7..e6577d10bb56 100644 --- a/arch/i386/kernel/i8259.c +++ b/arch/i386/kernel/i8259.c @@ -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) { -- cgit v1.2.3 From c403e2b4a1e073557ad71fd3570ab377c9dc1925 Mon Sep 17 00:00:00 2001 From: Patrick Mochel Date: Mon, 9 Jun 2003 19:42:22 -0700 Subject: [nmi] Convert to use new system device API. --- arch/i386/kernel/nmi.c | 36 ++++++++++++++++-------------------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/arch/i386/kernel/nmi.c b/arch/i386/kernel/nmi.c index e8910adcd6bb..2fc98bdb26ee 100644 --- a/arch/i386/kernel/nmi.c +++ b/arch/i386/kernel/nmi.c @@ -183,50 +183,46 @@ void enable_lapic_nmi_watchdog(void) #include 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 */ -- cgit v1.2.3 From 9191f600abec2fa4d7dfff681f92e2f41ddda807 Mon Sep 17 00:00:00 2001 From: Patrick Mochel Date: Mon, 9 Jun 2003 19:43:00 -0700 Subject: [timer] Convert to use new system device API. --- arch/i386/kernel/time.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/arch/i386/kernel/time.c b/arch/i386/kernel/time.c index 2acbd3d6b0b3..3410758eefcc 100644 --- a/arch/i386/kernel/time.c +++ b/arch/i386/kernel/time.c @@ -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); -- cgit v1.2.3 From bc2f37ccbbe09bc10fea314f49c5cbaac6b9e4e1 Mon Sep 17 00:00:00 2001 From: Patrick Mochel Date: Mon, 9 Jun 2003 19:43:42 -0700 Subject: [oprofile] Convert to use new system device API. --- arch/i386/oprofile/nmi_int.c | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/arch/i386/oprofile/nmi_int.c b/arch/i386/oprofile/nmi_int.c index b6841b98a3ac..03f4f73412c8 100644 --- a/arch/i386/oprofile/nmi_int.c +++ b/arch/i386/oprofile/nmi_int.c @@ -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 -- cgit v1.2.3 From 9bbfa0fa4de2fa5e1db99184f7422fecbea56a22 Mon Sep 17 00:00:00 2001 From: Patrick Mochel Date: Mon, 9 Jun 2003 19:44:23 -0700 Subject: [x86-64 i8259] Convert to use new system device API. --- arch/x86_64/kernel/i8259.c | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/arch/x86_64/kernel/i8259.c b/arch/x86_64/kernel/i8259.c index 61eb01ca8716..85cd2dfa7480 100644 --- a/arch/x86_64/kernel/i8259.c +++ b/arch/x86_64/kernel/i8259.c @@ -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) { -- cgit v1.2.3 From e5496ae1e2caabe8b1d70e2199472b776c7745d5 Mon Sep 17 00:00:00 2001 From: Patrick Mochel Date: Mon, 9 Jun 2003 19:45:45 -0700 Subject: [s390 xpram] Convert to use new system device API. --- drivers/s390/block/xpram.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/drivers/s390/block/xpram.c b/drivers/s390/block/xpram.c index fbb02dd40042..918441a9b9cd 100644 --- a/drivers/s390/block/xpram.c +++ b/drivers/s390/block/xpram.c @@ -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); -- cgit v1.2.3 From 35e5d23476e00fb2d709b90d8fb4cc4a9caa660c Mon Sep 17 00:00:00 2001 From: Patrick Mochel Date: Mon, 9 Jun 2003 21:58:22 -0700 Subject: [driver model] Create include/linux/sysdev.h and define sysdev_attribute. Split out all system device definitions from device.h into their own header sysdev.h Define struct sysdev_attribute and define functions to export attributes in sysfs. --- drivers/base/sys.c | 41 ++++++++++++++++++++-- include/linux/sysdev.h | 94 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 133 insertions(+), 2 deletions(-) create mode 100644 include/linux/sysdev.h diff --git a/drivers/base/sys.c b/drivers/base/sys.c index aa71e40a865e..6ae79a036f0f 100644 --- a/drivers/base/sys.c +++ b/drivers/base/sys.c @@ -14,7 +14,7 @@ #define DEBUG -#include +#include #include #include #include @@ -25,10 +25,47 @@ 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,NULL,NULL); +decl_subsys(system,&ktype_sysdev,NULL); int sysdev_class_register(struct sysdev_class * cls) { diff --git a/include/linux/sysdev.h b/include/linux/sysdev.h new file mode 100644 index 000000000000..2a90db8d41de --- /dev/null +++ b/include/linux/sysdev.h @@ -0,0 +1,94 @@ +/** + * 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 + + +struct sys_device; + +struct sysdev_class { + struct list_head drivers; + + /* Default operations for these types of devices */ + int (*shutdown)(struct sys_device *); + int (*suspend)(struct sys_device *, u32 state); + int (*resume)(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 (*suspend)(struct sys_device *, u32 state); + int (*resume)(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_ */ -- cgit v1.2.3 From 22ff2891d8ab22a6559a55f6ba1496298b53c3f0 Mon Sep 17 00:00:00 2001 From: Patrick Mochel Date: Mon, 9 Jun 2003 21:59:13 -0700 Subject: [driver model] Make sure right header is used for cpu.c --- drivers/base/cpu.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c index f30b746a2ec5..60e2c4d36990 100644 --- a/drivers/base/cpu.c +++ b/drivers/base/cpu.c @@ -2,7 +2,7 @@ * drivers/base/cpu.c - basic CPU class support */ -#include +#include #include #include #include @@ -13,6 +13,7 @@ struct sysdev_class cpu_sysdev_class = { set_kset_name("cpu"), }; + /* * register_cpu - Setup a driverfs device for a CPU. * @num - CPU number to use when creating the device. -- cgit v1.2.3 From b65b902cf0afa015d5ad6442a15ab942db8c1f26 Mon Sep 17 00:00:00 2001 From: Patrick Mochel Date: Mon, 9 Jun 2003 22:00:07 -0700 Subject: [memblk] Convert to use new system device API --- drivers/base/memblk.c | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/drivers/base/memblk.c b/drivers/base/memblk.c index 4986211b0ca6..3e3d069b5327 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 #include #include #include @@ -11,8 +10,8 @@ #include -static struct class memblk_class = { - .name = "memblk", +static struct sysdev_class memblk_class = { + set_kset_name("memblk"), }; @@ -30,27 +29,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); -- cgit v1.2.3 From c81d6bf04f5fd7078b7373cc6cd7c7c917fc9fe9 Mon Sep 17 00:00:00 2001 From: Patrick Mochel Date: Mon, 9 Jun 2003 22:00:51 -0700 Subject: [numa nodes] Convert to use new system device API --- drivers/base/node.c | 41 +++++++++++------------------------------ include/linux/node.h | 4 ++-- 2 files changed, 13 insertions(+), 32 deletions(-) diff --git a/drivers/base/node.c b/drivers/base/node.c index 48fa6de5580a..8dc7ab848216 100644 --- a/drivers/base/node.c +++ b/drivers/base/node.c @@ -10,15 +10,8 @@ #include - -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"), }; @@ -27,7 +20,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) @@ -53,7 +46,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); /* @@ -67,17 +60,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; } @@ -85,14 +74,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/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 +#include 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 *); -- cgit v1.2.3 From ce8e83b38225d532c843693ebfe52ab3a041b783 Mon Sep 17 00:00:00 2001 From: Patrick Mochel Date: Mon, 9 Jun 2003 22:01:36 -0700 Subject: [driver model] Remove system device definitions from device.h Should have been in earlier changeset. D'oh. --- include/linux/device.h | 72 -------------------------------------------------- 1 file changed, 72 deletions(-) diff --git a/include/linux/device.h b/include/linux/device.h index de674eaea31c..1bd92551c077 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -352,78 +352,6 @@ extern struct device * get_device(struct device * dev); extern void put_device(struct device * dev); -/* drivers/base/sys.c */ - -/** - * 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. - */ - -struct sys_device; - -struct sysdev_class { - struct list_head drivers; - - /* Default operations for these types of devices */ - int (*shutdown)(struct sys_device *); - int (*suspend)(struct sys_device *, u32 state); - int (*resume)(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 (*suspend)(struct sys_device *, u32 state); - int (*resume)(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 *); - -extern struct bus_type system_bus_type; - /* drivers/base/platform.c */ struct platform_device { -- cgit v1.2.3 From faf2e4c3a6d4d9c4d8f60405708096319405d633 Mon Sep 17 00:00:00 2001 From: Patrick Mochel Date: Mon, 9 Jun 2003 22:02:44 -0700 Subject: [apic] Use sysdev.h instead of device.h --- arch/i386/kernel/apic.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/i386/kernel/apic.c b/arch/i386/kernel/apic.c index 33e8cda5dd56..00d1a2ba56a1 100644 --- a/arch/i386/kernel/apic.c +++ b/arch/i386/kernel/apic.c @@ -25,6 +25,9 @@ #include #include #include +#include +#include + #include #include @@ -460,9 +463,6 @@ void __init setup_local_APIC (void) #ifdef CONFIG_PM -#include -#include - static struct { /* 'active' is true if the local APIC was enabled by us and not the BIOS; this signifies that we are also responsible -- cgit v1.2.3 From 1e4b248031ce7817888c19e7e8e4fdbccb186273 Mon Sep 17 00:00:00 2001 From: Patrick Mochel Date: Mon, 9 Jun 2003 22:03:25 -0700 Subject: [i8259] Use sysdev.h instead of device.h --- arch/i386/kernel/i8259.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/i386/kernel/i8259.c b/arch/i386/kernel/i8259.c index e6577d10bb56..bc1268725f34 100644 --- a/arch/i386/kernel/i8259.c +++ b/arch/i386/kernel/i8259.c @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include #include -- cgit v1.2.3 From 750f6f046ab27696b1a00d8211a3b4981499db0c Mon Sep 17 00:00:00 2001 From: Patrick Mochel Date: Mon, 9 Jun 2003 22:04:07 -0700 Subject: [nmi] Use sysdev.h instead of device.h --- arch/i386/kernel/nmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/i386/kernel/nmi.c b/arch/i386/kernel/nmi.c index 2fc98bdb26ee..656eb3bcff58 100644 --- a/arch/i386/kernel/nmi.c +++ b/arch/i386/kernel/nmi.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -180,7 +181,6 @@ void enable_lapic_nmi_watchdog(void) #ifdef CONFIG_PM -#include static int nmi_pm_active; /* nmi_active before suspend */ static int lapic_nmi_suspend(struct sys_device *dev, u32 state) -- cgit v1.2.3 From 746814f13fb027aba621eba242cbce871c978157 Mon Sep 17 00:00:00 2001 From: Patrick Mochel Date: Mon, 9 Jun 2003 22:05:03 -0700 Subject: [timer] Use sysdev.h instead of device.h --- arch/i386/kernel/time.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/i386/kernel/time.c b/arch/i386/kernel/time.c index 3410758eefcc..13a6b41ddcd8 100644 --- a/arch/i386/kernel/time.c +++ b/arch/i386/kernel/time.c @@ -42,7 +42,7 @@ #include #include #include -#include +#include #include #include -- cgit v1.2.3 From c94999f213f21790b2c7e638c98c3082cb54c498 Mon Sep 17 00:00:00 2001 From: Patrick Mochel Date: Mon, 9 Jun 2003 22:06:44 -0700 Subject: [oprofile] Use sysdev.h instead of device.h --- arch/i386/oprofile/nmi_int.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/i386/oprofile/nmi_int.c b/arch/i386/oprofile/nmi_int.c index 03f4f73412c8..030f0fa8c45a 100644 --- a/arch/i386/oprofile/nmi_int.c +++ b/arch/i386/oprofile/nmi_int.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include #include -- cgit v1.2.3 From d7c3192e97ee1e3f963a24b6bc5e389bd8e9f278 Mon Sep 17 00:00:00 2001 From: Patrick Mochel Date: Mon, 9 Jun 2003 22:08:04 -0700 Subject: [x86-64 i8259] Use sysdev.h instead of device.h --- arch/x86_64/kernel/i8259.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86_64/kernel/i8259.c b/arch/x86_64/kernel/i8259.c index 85cd2dfa7480..ce6ea7a396be 100644 --- a/arch/x86_64/kernel/i8259.c +++ b/arch/x86_64/kernel/i8259.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include -- cgit v1.2.3 From 4db4540fc9455c8d0e3d506b0a62b433f31d2150 Mon Sep 17 00:00:00 2001 From: Patrick Mochel Date: Mon, 9 Jun 2003 22:10:39 -0700 Subject: [s390 xpram] Use sysdev.h instead of device.h --- drivers/s390/block/xpram.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/s390/block/xpram.c b/drivers/s390/block/xpram.c index 918441a9b9cd..486e0111891d 100644 --- a/drivers/s390/block/xpram.c +++ b/drivers/s390/block/xpram.c @@ -34,7 +34,7 @@ #include #include #include /* HDIO_GETGEO */ -#include +#include #include #include #include -- cgit v1.2.3 From d507789a02e933ab503a4457abd6f56c579dea05 Mon Sep 17 00:00:00 2001 From: Patrick Mochel Date: Mon, 9 Jun 2003 23:58:37 -0700 Subject: [driver model] Add save() and restore() methods for system device drivers. It turns out that at least some system device drivers need to allocate memory and/or sleep for one reason or another when either saving or restoring state. Instead of adding a 'level' paramter to the suspend() and resume() methods, which I despise and think is a horrible programming interface, two new methods have been added to struct sysdev_driver: int (*save)(struct sys_device *, u32 state); int (*restore)(struct sys_device *); that are called explicitly before and after suspend() and resume() respectively, with interrupts enabled. This gives the drivers the flexibility to allocate memory and sleep, if necessary. --- drivers/base/power.c | 37 ++++++++++++---- drivers/base/sys.c | 117 +++++++++++++++++++++++++++++++++++++++++++------ include/linux/sysdev.h | 4 ++ 3 files changed, 137 insertions(+), 21 deletions(-) diff --git a/drivers/base/power.c b/drivers/base/power.c index 081ad32cadfd..7f5a6abc4e00 100644 --- a/drivers/base/power.c +++ b/drivers/base/power.c @@ -30,9 +30,11 @@ extern struct subsystem devices_subsys; * they only get one called once when interrupts are disabled. */ -extern int sys_device_shutdown(void); -extern int sys_device_suspend(u32 state); -extern int sys_device_resume(void); +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 @@ -64,8 +66,19 @@ int device_suspend(u32 state, u32 level) } up_write(&devices_subsys.rwsem); - if (level == SUSPEND_POWER_DOWN) - sys_device_suspend(state); + /* + * 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; } @@ -82,8 +95,16 @@ void device_resume(u32 level) { struct list_head * node; - if (level == RESUME_POWER_ON) - sys_device_resume(); + 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) { @@ -119,7 +140,7 @@ void device_shutdown(void) } up_write(&devices_subsys.rwsem); - sys_device_shutdown(); + sysdev_shutdown(); } EXPORT_SYMBOL(device_suspend); diff --git a/drivers/base/sys.c b/drivers/base/sys.c index 6ae79a036f0f..3d6d2e1d1147 100644 --- a/drivers/base/sys.c +++ b/drivers/base/sys.c @@ -200,7 +200,7 @@ void sys_device_unregister(struct sys_device * sysdev) /** - * sys_device_shutdown - Shut down all system devices. + * 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 @@ -213,7 +213,7 @@ void sys_device_unregister(struct sys_device * sysdev) * after their parents. */ -void sys_device_shutdown(void) +void sysdev_shutdown(void) { struct sysdev_class * cls; @@ -252,7 +252,53 @@ void sys_device_shutdown(void) /** - * sys_device_suspend - Suspend all system devices. + * sysdev_save - Save system device state + * @state: Power state we're entering. + * + * 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. * * We perform an almost identical operation as sys_device_shutdown() @@ -263,7 +309,7 @@ void sys_device_shutdown(void) * warning and return an error. */ -int sys_device_suspend(u32 state) +int sysdev_suspend(u32 state) { struct sysdev_class * cls; @@ -308,7 +354,7 @@ int sys_device_suspend(u32 state) /** - * sys_device_resume - Bring system devices back to life. + * 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. @@ -316,7 +362,7 @@ int sys_device_suspend(u32 state) * Note: Interrupts are disabled when called. */ -int sys_device_resume(void) +int sysdev_resume(void) { struct sysdev_class * cls; @@ -334,27 +380,72 @@ int sys_device_resume(void) struct sysdev_driver * drv; pr_debug(" %s\n",sysdev->kobj.name); - /* Call global drivers first. */ - list_for_each_entry(drv,&global_drivers,entry) { + /* 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 auxillary drivers next. */ - list_for_each_entry(drv,&cls->drivers,entry) { + /* Call global drivers. */ + list_for_each_entry(drv,&global_drivers,entry) { if (drv->resume) drv->resume(sysdev); } - /* Now call the generic one */ - if (cls->resume) - cls->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; +} + + int __init sys_bus_init(void) { system_subsys.kset.kobj.parent = &devices_subsys.kset.kobj; diff --git a/include/linux/sysdev.h b/include/linux/sysdev.h index 2a90db8d41de..4bc3e22b5104 100644 --- a/include/linux/sysdev.h +++ b/include/linux/sysdev.h @@ -31,8 +31,10 @@ struct sysdev_class { /* 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; }; @@ -50,8 +52,10 @@ struct sysdev_driver { 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 *); }; -- cgit v1.2.3 From 52815e81f07afbad2f0f61b7a323abb2639e5992 Mon Sep 17 00:00:00 2001 From: Patrick Mochel Date: Tue, 10 Jun 2003 00:26:43 -0700 Subject: [driver model] Don't Oops when registering global sysdev drivers. --- drivers/base/sys.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/base/sys.c b/drivers/base/sys.c index 3d6d2e1d1147..34001cb52fa1 100644 --- a/drivers/base/sys.c +++ b/drivers/base/sys.c @@ -104,7 +104,7 @@ int sysdev_driver_register(struct sysdev_class * cls, struct sysdev_driver * drv) { down_write(&system_subsys.rwsem); - if (kset_get(&cls->kset)) + if (cls && kset_get(&cls->kset)) list_add_tail(&drv->entry,&cls->drivers); else list_add_tail(&drv->entry,&global_drivers); -- cgit v1.2.3 From 42ed4a84e267845d0af8eb39a8173f0ded151dc4 Mon Sep 17 00:00:00 2001 From: Patrick Mochel Date: Tue, 10 Jun 2003 00:27:26 -0700 Subject: [cpu] Use sysdev.h instead of device.h and export cpu_sysdev_class --- include/linux/cpu.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/linux/cpu.h b/include/linux/cpu.h index e9e7ebfd63d4..0975def4a2ba 100644 --- a/include/linux/cpu.h +++ b/include/linux/cpu.h @@ -19,7 +19,7 @@ #ifndef _LINUX_CPU_H_ #define _LINUX_CPU_H_ -#include +#include #include #include @@ -29,7 +29,7 @@ struct cpu { }; extern int register_cpu(struct cpu *, int, struct node *); -extern struct class cpu_class; +extern struct sysdev_class cpu_sysdev_class; /* Stop CPUs going up and down. */ extern struct semaphore cpucontrol; -- cgit v1.2.3 From 623532ff8638a9582a92164ab59ec21c3dd94ca9 Mon Sep 17 00:00:00 2001 From: Patrick Mochel Date: Tue, 10 Jun 2003 00:28:54 -0700 Subject: [mtrr] Add save()/restore() methods. Patch originally from Nigel Cunningham and Pavel Machek. Cleaned up and converted to new system device API by your truly. --- arch/i386/kernel/cpu/mtrr/main.c | 60 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 58 insertions(+), 2 deletions(-) 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 #include #include +#include #include @@ -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); -- cgit v1.2.3 From e15eba7e68cf7d40626f0d311dfdc94f57385d1d Mon Sep 17 00:00:00 2001 From: Patrick Mochel Date: Tue, 10 Jun 2003 00:32:08 -0700 Subject: [cpufreq] Convert to use new system device API - Remove explicit call from arm PM sequence, as its handled implicitly by sysdev_restore() in driver model core. --- arch/arm/kernel/pm.c | 8 ----- include/linux/cpufreq.h | 4 --- kernel/cpufreq.c | 83 +++++++++++++++++++------------------------------ 3 files changed, 32 insertions(+), 63 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 #include #include -#include #include #include @@ -66,13 +65,6 @@ int suspend(void) */ device_resume(RESUME_POWER_ON); - /* - * Restore the CPU frequency settings. - */ -#ifdef CONFIG_CPU_FREQ - cpufreq_restore(); -#endif - /* * Resume LDM devices. */ 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/kernel/cpufreq.c b/kernel/cpufreq.c index 8446f4d97a85..e1ddcb3461c2 100644 --- a/kernel/cpufreq.c +++ b/kernel/cpufreq.c @@ -52,8 +52,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) return 0; @@ -110,24 +108,8 @@ int cpufreq_parse_governor (char *str_governor, unsigned int *policy, struct cpu 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; /** @@ -327,9 +309,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; @@ -354,14 +336,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); @@ -392,12 +372,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) && @@ -417,9 +397,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 * @@ -839,7 +827,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); @@ -857,7 +845,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); @@ -870,41 +858,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;ipolicy[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 */ -- cgit v1.2.3 From 3d983e57eeb0d84ffafe1bb5b78688646ebd1d17 Mon Sep 17 00:00:00 2001 From: Patrick Mochel Date: Tue, 10 Jun 2003 00:53:51 -0700 Subject: [sysfs] Get zeroed page for file read/write buffers. --- fs/sysfs/file.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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; -- cgit v1.2.3 From 6508e77cc78d7abb04617bec00de21218e7d6df8 Mon Sep 17 00:00:00 2001 From: Patrick Mochel Date: Tue, 10 Jun 2003 01:27:47 -0700 Subject: hand merge --- drivers/base/cpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c index 60e2c4d36990..4456bceabeaf 100644 --- a/drivers/base/cpu.c +++ b/drivers/base/cpu.c @@ -6,8 +6,8 @@ #include #include #include +#include -#include struct sysdev_class cpu_sysdev_class = { set_kset_name("cpu"), -- cgit v1.2.3