From fe6b91f47080eb17d21cbf2a39311877d57f6938 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 6 Dec 2011 23:24:52 +0100 Subject: PM / Driver core: leave runtime PM enabled during system shutdown Disabling all runtime PM during system shutdown turns out not to be a good idea, because some devices may need to be woken up from a low-power state at that time. The whole point of disabling runtime PM for system shutdown was to prevent untimely runtime-suspend method calls. This patch (as1504) accomplishes the same result by incrementing the usage count for each device and waiting for ongoing runtime-PM callbacks to finish. This is what we already do during system suspend and hibernation, which makes sense since the shutdown method is pretty much a legacy analog of the pm->poweroff method. This fixes a recent regression on some OMAP systems introduced by commit af8db1508f2c9f3b6e633e2d2d906c6557c617f9 (PM / driver core: disable device's runtime PM during shutdown). Reported-and-tested-by: NeilBrown Signed-off-by: Alan Stern Acked-by: Greg Kroah-Hartman Signed-off-by: Rafael J. Wysocki --- drivers/base/core.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/base/core.c') diff --git a/drivers/base/core.c b/drivers/base/core.c index d8b3d89db043..919daa7cd5b1 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -1743,8 +1743,10 @@ void device_shutdown(void) */ list_del_init(&dev->kobj.entry); spin_unlock(&devices_kset->list_lock); - /* Disable all device's runtime power management */ - pm_runtime_disable(dev); + + /* Don't allow any more runtime suspends */ + pm_runtime_get_noresume(dev); + pm_runtime_barrier(dev); if (dev->bus && dev->bus->shutdown) { dev_dbg(dev, "shutdown\n"); -- cgit v1.2.3 From ca22e56debc57b47c422b749c93217ba62644be2 Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Wed, 14 Dec 2011 14:29:38 -0800 Subject: driver-core: implement 'sysdev' functionality for regular devices and buses All sysdev classes and sysdev devices will converted to regular devices and buses to properly hook userspace into the event processing. There is no interesting difference between a 'sysdev' and 'device' which would justify to roll an entire own subsystem with different userspace export semantics. Userspace relies on events and generic sysfs subsystem infrastructure from sysdev devices, which are currently not properly available. Every converted sysdev class will create a regular device with the class name in /sys/devices/system and all registered devices will becom a children of theses devices. For compatibility reasons, the sysdev class-wide attributes are created at this parent device. (Do not copy that logic for anything new, subsystem- wide properties belong to the subsystem, not to some fake parent device created in /sys/devices.) Every sysdev driver is implemented as a simple subsystem interface now, and no longer called a driver. After all sysdev classes are ported to regular driver core entities, the sysdev implementation will be entirely removed from the kernel. Signed-off-by: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- drivers/base/core.c | 85 +++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 69 insertions(+), 16 deletions(-) (limited to 'drivers/base/core.c') diff --git a/drivers/base/core.c b/drivers/base/core.c index 82c865452c70..a31ea193fba0 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -117,6 +117,56 @@ static const struct sysfs_ops dev_sysfs_ops = { .store = dev_attr_store, }; +#define to_ext_attr(x) container_of(x, struct dev_ext_attribute, attr) + +ssize_t device_store_ulong(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct dev_ext_attribute *ea = to_ext_attr(attr); + char *end; + unsigned long new = simple_strtoul(buf, &end, 0); + if (end == buf) + return -EINVAL; + *(unsigned long *)(ea->var) = new; + /* Always return full write size even if we didn't consume all */ + return size; +} +EXPORT_SYMBOL_GPL(device_store_ulong); + +ssize_t device_show_ulong(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct dev_ext_attribute *ea = to_ext_attr(attr); + return snprintf(buf, PAGE_SIZE, "%lx\n", *(unsigned long *)(ea->var)); +} +EXPORT_SYMBOL_GPL(device_show_ulong); + +ssize_t device_store_int(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct dev_ext_attribute *ea = to_ext_attr(attr); + char *end; + long new = simple_strtol(buf, &end, 0); + if (end == buf || new > INT_MAX || new < INT_MIN) + return -EINVAL; + *(int *)(ea->var) = new; + /* Always return full write size even if we didn't consume all */ + return size; +} +EXPORT_SYMBOL_GPL(device_store_int); + +ssize_t device_show_int(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct dev_ext_attribute *ea = to_ext_attr(attr); + + return snprintf(buf, PAGE_SIZE, "%d\n", *(int *)(ea->var)); +} +EXPORT_SYMBOL_GPL(device_show_int); /** * device_release - free device structure. @@ -463,7 +513,7 @@ static ssize_t show_dev(struct device *dev, struct device_attribute *attr, static struct device_attribute devt_attr = __ATTR(dev, S_IRUGO, show_dev, NULL); -/* kset to create /sys/devices/ */ +/* /sys/devices/ */ struct kset *devices_kset; /** @@ -710,6 +760,10 @@ static struct kobject *get_device_parent(struct device *dev, return k; } + /* subsystems can specify a default root directory for their devices */ + if (!parent && dev->bus && dev->bus->dev_root) + return &dev->bus->dev_root->kobj; + if (parent) return &parent->kobj; return NULL; @@ -730,14 +784,6 @@ static void cleanup_device_parent(struct device *dev) cleanup_glue_dir(dev, dev->kobj.parent); } -static void setup_parent(struct device *dev, struct device *parent) -{ - struct kobject *kobj; - kobj = get_device_parent(dev, parent); - if (kobj) - dev->kobj.parent = kobj; -} - static int device_add_class_symlinks(struct device *dev) { int error; @@ -890,6 +936,7 @@ int device_private_init(struct device *dev) int device_add(struct device *dev) { struct device *parent = NULL; + struct kobject *kobj; struct class_interface *class_intf; int error = -EINVAL; @@ -913,6 +960,10 @@ int device_add(struct device *dev) dev->init_name = NULL; } + /* subsystems can specify simple device enumeration */ + if (!dev_name(dev) && dev->bus && dev->bus->dev_name) + dev_set_name(dev, "%s%u", dev->bus->dev_name, dev->id); + if (!dev_name(dev)) { error = -EINVAL; goto name_error; @@ -921,7 +972,9 @@ int device_add(struct device *dev) pr_debug("device: '%s': %s\n", dev_name(dev), __func__); parent = get_device(dev->parent); - setup_parent(dev, parent); + kobj = get_device_parent(dev, parent); + if (kobj) + dev->kobj.parent = kobj; /* use parent numa_node */ if (parent) @@ -981,17 +1034,17 @@ int device_add(struct device *dev) &parent->p->klist_children); if (dev->class) { - mutex_lock(&dev->class->p->class_mutex); + mutex_lock(&dev->class->p->mutex); /* tie the class to the device */ klist_add_tail(&dev->knode_class, &dev->class->p->klist_devices); /* notify any interfaces that the device is here */ list_for_each_entry(class_intf, - &dev->class->p->class_interfaces, node) + &dev->class->p->interfaces, node) if (class_intf->add_dev) class_intf->add_dev(dev, class_intf); - mutex_unlock(&dev->class->p->class_mutex); + mutex_unlock(&dev->class->p->mutex); } done: put_device(dev); @@ -1106,15 +1159,15 @@ void device_del(struct device *dev) if (dev->class) { device_remove_class_symlinks(dev); - mutex_lock(&dev->class->p->class_mutex); + mutex_lock(&dev->class->p->mutex); /* notify any interfaces that the device is now gone */ list_for_each_entry(class_intf, - &dev->class->p->class_interfaces, node) + &dev->class->p->interfaces, node) if (class_intf->remove_dev) class_intf->remove_dev(dev, class_intf); /* remove the device from the class list */ klist_del(&dev->knode_class); - mutex_unlock(&dev->class->p->class_mutex); + mutex_unlock(&dev->class->p->mutex); } device_remove_file(dev, &uevent_attr); device_remove_attrs(dev); -- cgit v1.2.3 From 2c9ede55ecec58099b72e4bb8eab719f32f72c31 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 23 Jul 2011 20:24:48 -0400 Subject: switch device_get_devnode() and ->devnode() to umode_t * both callers of device_get_devnode() are only interested in lower 16bits and nobody tries to return anything wider than 16bit anyway. Signed-off-by: Al Viro --- drivers/base/core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/base/core.c') diff --git a/drivers/base/core.c b/drivers/base/core.c index 919daa7cd5b1..1dfa1d616fa5 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -198,7 +198,7 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj, if (MAJOR(dev->devt)) { const char *tmp; const char *name; - mode_t mode = 0; + umode_t mode = 0; add_uevent_var(env, "MAJOR=%u", MAJOR(dev->devt)); add_uevent_var(env, "MINOR=%u", MINOR(dev->devt)); @@ -1182,7 +1182,7 @@ static struct device *next_device(struct klist_iter *i) * freed by the caller. */ const char *device_get_devnode(struct device *dev, - mode_t *mode, const char **tmp) + umode_t *mode, const char **tmp) { char *s; -- cgit v1.2.3 From b10d5efdf7892d18b3b7d899edce2c8d9b80aea9 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 17 Jan 2012 11:39:00 -0500 Subject: Documentation update for the driver model core This patch (as1509) documents two important points regarding the use of device structures in the driver model: Structures must be initialized to all 0's before they are passed to device_initialize(). Structures must not be passed to device_add() or device_register() more than once. Although these restrictions have applied ever since the driver model was first created, they have not been mentioned anywhere. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/base/core.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'drivers/base/core.c') diff --git a/drivers/base/core.c b/drivers/base/core.c index 4a67cc0c8b37..ad29e928baaa 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -632,6 +632,11 @@ static void klist_children_put(struct klist_node *n) * may be used for reference counting of @dev after calling this * function. * + * All fields in @dev must be initialized by the caller to 0, except + * for those explicitly set to some other value. The simplest + * approach is to use kzalloc() to allocate the structure containing + * @dev. + * * NOTE: Use put_device() to give up your reference instead of freeing * @dev directly once you have called this function. */ @@ -930,6 +935,13 @@ int device_private_init(struct device *dev) * to the global and sibling lists for the device, then * adds it to the other relevant subsystems of the driver model. * + * Do not call this routine or device_register() more than once for + * any device structure. The driver model core is not designed to work + * with devices that get unregistered and then spring back to life. + * (Among other things, it's very hard to guarantee that all references + * to the previous incarnation of @dev have been dropped.) Allocate + * and register a fresh new struct device instead. + * * NOTE: _Never_ directly free @dev after calling this function, even * if it returned an error! Always use put_device() to give up your * reference instead. @@ -1090,6 +1102,9 @@ name_error: * have a clearly defined need to use and refcount the device * before it is added to the hierarchy. * + * For more information, see the kerneldoc for device_initialize() + * and device_add(). + * * NOTE: _Never_ directly free @dev after calling this function, even * if it returned an error! Always use put_device() to give up the * reference initialized in this function instead. -- cgit v1.2.3 From 268863f43629ef88763400d0cae4a66c754a0d23 Mon Sep 17 00:00:00 2001 From: majianpeng Date: Wed, 11 Jan 2012 15:12:06 +0000 Subject: base/core.c:fix typo in comment in function device_add Signed-off-by: majianpeng Signed-off-by: Greg Kroah-Hartman --- drivers/base/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/base/core.c') diff --git a/drivers/base/core.c b/drivers/base/core.c index ad29e928baaa..74dda4f697f9 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -1034,7 +1034,7 @@ int device_add(struct device *dev) device_pm_add(dev); /* Notify clients of device addition. This call must come - * after dpm_sysf_add() and before kobject_uevent(). + * after dpm_sysfs_add() and before kobject_uevent(). */ if (dev->bus) blocking_notifier_call_chain(&dev->bus->p->bus_notifier, -- cgit v1.2.3