diff options
Diffstat (limited to 'drivers/base')
-rw-r--r-- | drivers/base/attribute_container.c | 2 | ||||
-rw-r--r-- | drivers/base/base.h | 26 | ||||
-rw-r--r-- | drivers/base/bus.c | 52 | ||||
-rw-r--r-- | drivers/base/core.c | 197 | ||||
-rw-r--r-- | drivers/base/dd.c | 26 | ||||
-rw-r--r-- | drivers/base/driver.c | 13 | ||||
-rw-r--r-- | drivers/base/firmware_class.c | 8 | ||||
-rw-r--r-- | drivers/base/isa.c | 7 | ||||
-rw-r--r-- | drivers/base/memory.c | 19 | ||||
-rw-r--r-- | drivers/base/node.c | 103 | ||||
-rw-r--r-- | drivers/base/platform.c | 130 | ||||
-rw-r--r-- | drivers/base/power/main.c | 21 | ||||
-rw-r--r-- | drivers/base/power/trace.c | 4 |
13 files changed, 439 insertions, 169 deletions
diff --git a/drivers/base/attribute_container.c b/drivers/base/attribute_container.c index f57652d..b9cda05 100644 --- a/drivers/base/attribute_container.c +++ b/drivers/base/attribute_container.c @@ -167,7 +167,7 @@ attribute_container_add_device(struct device *dev, ic->classdev.parent = get_device(dev); ic->classdev.class = cont->class; cont->class->dev_release = attribute_container_release; - strcpy(ic->classdev.bus_id, dev->bus_id); + dev_set_name(&ic->classdev, dev_name(dev)); if (fn) fn(cont, dev, &ic->classdev); else diff --git a/drivers/base/base.h b/drivers/base/base.h index 0a5f055..b676f8f 100644 --- a/drivers/base/base.h +++ b/drivers/base/base.h @@ -63,6 +63,32 @@ struct class_private { #define to_class(obj) \ container_of(obj, struct class_private, class_subsys.kobj) +/** + * struct device_private - structure to hold the private to the driver core portions of the device structure. + * + * @klist_children - klist containing all children of this device + * @knode_parent - node in sibling list + * @knode_driver - node in driver list + * @knode_bus - node in bus list + * @device - pointer back to the struct class that this structure is + * associated with. + * + * Nothing outside of the driver core should ever touch these fields. + */ +struct device_private { + struct klist klist_children; + struct klist_node knode_parent; + struct klist_node knode_driver; + struct klist_node knode_bus; + struct device *device; +}; +#define to_device_private_parent(obj) \ + container_of(obj, struct device_private, knode_parent) +#define to_device_private_driver(obj) \ + container_of(obj, struct device_private, knode_driver) +#define to_device_private_bus(obj) \ + container_of(obj, struct device_private, knode_bus) + /* initialisation functions */ extern int devices_init(void); extern int buses_init(void); diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 5aee1c0..0f0a504 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -253,7 +253,14 @@ static ssize_t store_drivers_probe(struct bus_type *bus, static struct device *next_device(struct klist_iter *i) { struct klist_node *n = klist_next(i); - return n ? container_of(n, struct device, knode_bus) : NULL; + struct device *dev = NULL; + struct device_private *dev_prv; + + if (n) { + dev_prv = to_device_private_bus(n); + dev = dev_prv->device; + } + return dev; } /** @@ -286,7 +293,7 @@ int bus_for_each_dev(struct bus_type *bus, struct device *start, return -EINVAL; klist_iter_init_node(&bus->p->klist_devices, &i, - (start ? &start->knode_bus : NULL)); + (start ? &start->p->knode_bus : NULL)); while ((dev = next_device(&i)) && !error) error = fn(dev, data); klist_iter_exit(&i); @@ -320,7 +327,7 @@ struct device *bus_find_device(struct bus_type *bus, return NULL; klist_iter_init_node(&bus->p->klist_devices, &i, - (start ? &start->knode_bus : NULL)); + (start ? &start->p->knode_bus : NULL)); while ((dev = next_device(&i))) if (match(dev, data) && get_device(dev)) break; @@ -333,7 +340,7 @@ static int match_name(struct device *dev, void *data) { const char *name = data; - return sysfs_streq(name, dev->bus_id); + return sysfs_streq(name, dev_name(dev)); } /** @@ -461,12 +468,12 @@ int bus_add_device(struct device *dev) int error = 0; if (bus) { - pr_debug("bus: '%s': add device %s\n", bus->name, dev->bus_id); + pr_debug("bus: '%s': add device %s\n", bus->name, dev_name(dev)); error = device_add_attrs(bus, dev); if (error) goto out_put; error = sysfs_create_link(&bus->p->devices_kset->kobj, - &dev->kobj, dev->bus_id); + &dev->kobj, dev_name(dev)); if (error) goto out_id; error = sysfs_create_link(&dev->kobj, @@ -482,7 +489,7 @@ int bus_add_device(struct device *dev) out_deprecated: sysfs_remove_link(&dev->kobj, "subsystem"); out_subsys: - sysfs_remove_link(&bus->p->devices_kset->kobj, dev->bus_id); + sysfs_remove_link(&bus->p->devices_kset->kobj, dev_name(dev)); out_id: device_remove_attrs(bus, dev); out_put: @@ -507,7 +514,8 @@ void bus_attach_device(struct device *dev) ret = device_attach(dev); WARN_ON(ret < 0); if (ret >= 0) - klist_add_tail(&dev->knode_bus, &bus->p->klist_devices); + klist_add_tail(&dev->p->knode_bus, + &bus->p->klist_devices); } } @@ -526,13 +534,13 @@ void bus_remove_device(struct device *dev) sysfs_remove_link(&dev->kobj, "subsystem"); remove_deprecated_bus_links(dev); sysfs_remove_link(&dev->bus->p->devices_kset->kobj, - dev->bus_id); + dev_name(dev)); device_remove_attrs(dev->bus, dev); - if (klist_node_attached(&dev->knode_bus)) - klist_del(&dev->knode_bus); + if (klist_node_attached(&dev->p->knode_bus)) + klist_del(&dev->p->knode_bus); pr_debug("bus: '%s': remove device %s\n", - dev->bus->name, dev->bus_id); + dev->bus->name, dev_name(dev)); device_release_driver(dev); bus_put(dev->bus); } @@ -831,14 +839,16 @@ static void bus_remove_attrs(struct bus_type *bus) static void klist_devices_get(struct klist_node *n) { - struct device *dev = container_of(n, struct device, knode_bus); + struct device_private *dev_prv = to_device_private_bus(n); + struct device *dev = dev_prv->device; get_device(dev); } static void klist_devices_put(struct klist_node *n) { - struct device *dev = container_of(n, struct device, knode_bus); + struct device_private *dev_prv = to_device_private_bus(n); + struct device *dev = dev_prv->device; put_device(dev); } @@ -993,18 +1003,20 @@ static void device_insertion_sort_klist(struct device *a, struct list_head *list { struct list_head *pos; struct klist_node *n; + struct device_private *dev_prv; struct device *b; list_for_each(pos, list) { n = container_of(pos, struct klist_node, n_node); - b = container_of(n, struct device, knode_bus); + dev_prv = to_device_private_bus(n); + b = dev_prv->device; if (compare(a, b) <= 0) { - list_move_tail(&a->knode_bus.n_node, - &b->knode_bus.n_node); + list_move_tail(&a->p->knode_bus.n_node, + &b->p->knode_bus.n_node); return; } } - list_move_tail(&a->knode_bus.n_node, list); + list_move_tail(&a->p->knode_bus.n_node, list); } void bus_sort_breadthfirst(struct bus_type *bus, @@ -1014,6 +1026,7 @@ void bus_sort_breadthfirst(struct bus_type *bus, LIST_HEAD(sorted_devices); struct list_head *pos, *tmp; struct klist_node *n; + struct device_private *dev_prv; struct device *dev; struct klist *device_klist; @@ -1022,7 +1035,8 @@ void bus_sort_breadthfirst(struct bus_type *bus, spin_lock(&device_klist->k_lock); list_for_each_safe(pos, tmp, &device_klist->k_list) { n = container_of(pos, struct klist_node, n_node); - dev = container_of(n, struct device, knode_bus); + dev_prv = to_device_private_bus(n); + dev = dev_prv->device; device_insertion_sort_klist(dev, &sorted_devices, compare); } list_splice(&sorted_devices, &device_klist->k_list); diff --git a/drivers/base/core.c b/drivers/base/core.c index 8c2cc26..61df508 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -109,6 +109,7 @@ static struct sysfs_ops dev_sysfs_ops = { static void device_release(struct kobject *kobj) { struct device *dev = to_dev(kobj); + struct device_private *p = dev->p; if (dev->release) dev->release(dev); @@ -119,7 +120,8 @@ static void device_release(struct kobject *kobj) else WARN(1, KERN_ERR "Device '%s' does not have a release() " "function, it is broken and must be fixed.\n", - dev->bus_id); + dev_name(dev)); + kfree(p); } static struct kobj_type device_ktype = { @@ -209,7 +211,7 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj, retval = dev->bus->uevent(dev, env); if (retval) pr_debug("device: '%s': %s: bus uevent() returned %d\n", - dev->bus_id, __func__, retval); + dev_name(dev), __func__, retval); } /* have the class specific function add its stuff */ @@ -217,7 +219,7 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj, retval = dev->class->dev_uevent(dev, env); if (retval) pr_debug("device: '%s': %s: class uevent() " - "returned %d\n", dev->bus_id, + "returned %d\n", dev_name(dev), __func__, retval); } @@ -226,7 +228,7 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj, retval = dev->type->uevent(dev, env); if (retval) pr_debug("device: '%s': %s: dev_type uevent() " - "returned %d\n", dev->bus_id, + "returned %d\n", dev_name(dev), __func__, retval); } @@ -507,14 +509,16 @@ EXPORT_SYMBOL_GPL(device_schedule_callback_owner); static void klist_children_get(struct klist_node *n) { - struct device *dev = container_of(n, struct device, knode_parent); + struct device_private *p = to_device_private_parent(n); + struct device *dev = p->device; get_device(dev); } static void klist_children_put(struct klist_node *n) { - struct device *dev = container_of(n, struct device, knode_parent); + struct device_private *p = to_device_private_parent(n); + struct device *dev = p->device; put_device(dev); } @@ -536,9 +540,15 @@ static void klist_children_put(struct klist_node *n) */ void device_initialize(struct device *dev) { + dev->p = kzalloc(sizeof(*dev->p), GFP_KERNEL); + if (!dev->p) { + WARN_ON(1); + return; + } + dev->p->device = dev; dev->kobj.kset = devices_kset; kobject_init(&dev->kobj, &device_ktype); - klist_init(&dev->klist_children, klist_children_get, + klist_init(&dev->p->klist_children, klist_children_get, klist_children_put); INIT_LIST_HEAD(&dev->dma_pools); init_MUTEX(&dev->sem); @@ -672,7 +682,7 @@ static int device_add_class_symlinks(struct device *dev) if (dev->kobj.parent != &dev->class->p->class_subsys.kobj && device_is_not_partition(dev)) { error = sysfs_create_link(&dev->class->p->class_subsys.kobj, - &dev->kobj, dev->bus_id); + &dev->kobj, dev_name(dev)); if (error) goto out_subsys; } @@ -712,11 +722,11 @@ out_busid: if (dev->kobj.parent != &dev->class->p->class_subsys.kobj && device_is_not_partition(dev)) sysfs_remove_link(&dev->class->p->class_subsys.kobj, - dev->bus_id); + dev_name(dev)); #else /* link in the class directory pointing to the device */ error = sysfs_create_link(&dev->class->p->class_subsys.kobj, - &dev->kobj, dev->bus_id); + &dev->kobj, dev_name(dev)); if (error) goto out_subsys; @@ -729,7 +739,7 @@ out_busid: return 0; out_busid: - sysfs_remove_link(&dev->class->p->class_subsys.kobj, dev->bus_id); + sysfs_remove_link(&dev->class->p->class_subsys.kobj, dev_name(dev)); #endif out_subsys: @@ -758,12 +768,12 @@ static void device_remove_class_symlinks(struct device *dev) if (dev->kobj.parent != &dev->class->p->class_subsys.kobj && device_is_not_partition(dev)) sysfs_remove_link(&dev->class->p->class_subsys.kobj, - dev->bus_id); + dev_name(dev)); #else if (dev->parent && device_is_not_partition(dev)) sysfs_remove_link(&dev->kobj, "device"); - sysfs_remove_link(&dev->class->p->class_subsys.kobj, dev->bus_id); + sysfs_remove_link(&dev->class->p->class_subsys.kobj, dev_name(dev)); #endif sysfs_remove_link(&dev->kobj, "subsystem"); @@ -866,7 +876,7 @@ int device_add(struct device *dev) if (!strlen(dev->bus_id)) goto done; - pr_debug("device: '%s': %s\n", dev->bus_id, __func__); + pr_debug("device: '%s': %s\n", dev_name(dev), __func__); parent = get_device(dev->parent); setup_parent(dev, parent); @@ -876,7 +886,7 @@ int device_add(struct device *dev) set_dev_node(dev, dev_to_node(parent)); /* first, register with generic layer. */ - error = kobject_add(&dev->kobj, dev->kobj.parent, "%s", dev->bus_id); + error = kobject_add(&dev->kobj, dev->kobj.parent, "%s", dev_name(dev)); if (error) goto Error; @@ -884,11 +894,6 @@ int device_add(struct device *dev) if (platform_notify) platform_notify(dev); - /* notify clients of device entry (new way) */ - if (dev->bus) - blocking_notifier_call_chain(&dev->bus->p->bus_notifier, - BUS_NOTIFY_ADD_DEVICE, dev); - error = device_create_file(dev, &uevent_attr); if (error) goto attrError; @@ -916,10 +921,19 @@ int device_add(struct device *dev) if (error) goto DPMError; device_pm_add(dev); + + /* Notify clients of device addition. This call must come + * after dpm_sysf_add() and before kobject_uevent(). + */ + if (dev->bus) + blocking_notifier_call_chain(&dev->bus->p->bus_notifier, + BUS_NOTIFY_ADD_DEVICE, dev); + kobject_uevent(&dev->kobj, KOBJ_ADD); bus_attach_device(dev); if (parent) - klist_add_tail(&dev->knode_parent, &parent->klist_children); + klist_add_tail(&dev->p->knode_parent, + &parent->p->klist_children); if (dev->class) { mutex_lock(&dev->class->p->class_mutex); @@ -940,9 +954,6 @@ done: DPMError: bus_remove_device(dev); BusError: - if (dev->bus) - blocking_notifier_call_chain(&dev->bus->p->bus_notifier, - BUS_NOTIFY_DEL_DEVICE, dev); device_remove_attrs(dev); AttrsError: device_remove_class_symlinks(dev); @@ -1027,10 +1038,16 @@ void device_del(struct device *dev) struct device *parent = dev->parent; struct class_interface *class_intf; + /* Notify clients of device removal. This call must come + * before dpm_sysfs_remove(). + */ + if (dev->bus) + blocking_notifier_call_chain(&dev->bus->p->bus_notifier, + BUS_NOTIFY_DEL_DEVICE, dev); device_pm_remove(dev); dpm_sysfs_remove(dev); if (parent) - klist_del(&dev->knode_parent); + klist_del(&dev->p->knode_parent); if (MAJOR(dev->devt)) { device_remove_sys_dev_entry(dev); device_remove_file(dev, &devt_attr); @@ -1064,9 +1081,6 @@ void device_del(struct device *dev) */ if (platform_notify_remove) platform_notify_remove(dev); - if (dev->bus) - blocking_notifier_call_chain(&dev->bus->p->bus_notifier, - BUS_NOTIFY_DEL_DEVICE, dev); kobject_uevent(&dev->kobj, KOBJ_REMOVE); cleanup_device_parent(dev); kobject_del(&dev->kobj); @@ -1086,7 +1100,7 @@ void device_del(struct device *dev) */ void device_unregister(struct device *dev) { - pr_debug("device: '%s': %s\n", dev->bus_id, __func__); + pr_debug("device: '%s': %s\n", dev_name(dev), __func__); device_del(dev); put_device(dev); } @@ -1094,7 +1108,14 @@ void device_unregister(struct device *dev) static struct device *next_device(struct klist_iter *i) { struct klist_node *n = klist_next(i); - return n ? container_of(n, struct device, knode_parent) : NULL; + struct device *dev = NULL; + struct device_private *p; + + if (n) { + p = to_device_private_parent(n); + dev = p->device; + } + return dev; } /** @@ -1116,7 +1137,7 @@ int device_for_each_child(struct device *parent, void *data, struct device *child; int error = 0; - klist_iter_init(&parent->klist_children, &i); + klist_iter_init(&parent->p->klist_children, &i); while ((child = next_device(&i)) && !error) error = fn(child, data); klist_iter_exit(&i); @@ -1147,7 +1168,7 @@ struct device *device_find_child(struct device *parent, void *data, if (!parent) return NULL; - klist_iter_init(&parent->klist_children, &i); + klist_iter_init(&parent->p->klist_children, &i); while ((child = next_device(&i))) if (match(child, data) && get_device(child)) break; @@ -1196,10 +1217,101 @@ EXPORT_SYMBOL_GPL(put_device); EXPORT_SYMBOL_GPL(device_create_file); EXPORT_SYMBOL_GPL(device_remove_file); +struct root_device +{ + struct device dev; + struct module *owner; +}; + +#define to_root_device(dev) container_of(dev, struct root_device, dev) + +static void root_device_release(struct device *dev) +{ + kfree(to_root_device(dev)); +} + +/** + * __root_device_register - allocate and register a root device + * @name: root device name + * @owner: owner module of the root device, usually THIS_MODULE + * + * This function allocates a root device and registers it + * using device_register(). In order to free the returned + * device, use root_device_unregister(). + * + * Root devices are dummy devices which allow other devices + * to be grouped under /sys/devices. Use this function to + * allocate a root device and then use it as the parent of + * any device which should appear under /sys/devices/{name} + * + * The /sys/devices/{name} directory will also contain a + * 'module' symlink which points to the @owner directory + * in sysfs. + * + * Note: You probably want to use root_device_register(). + */ +struct device *__root_device_register(const char *name, struct module *owner) +{ + struct root_device *root; + int err = -ENOMEM; + + root = kzalloc(sizeof(struct root_device), GFP_KERNEL); + if (!root) + return ERR_PTR(err); + + err = dev_set_name(&root->dev, name); + if (err) { + kfree(root); + return ERR_PTR(err); + } + + root->dev.release = root_device_release; + + err = device_register(&root->dev); + if (err) { + put_device(&root->dev); + return ERR_PTR(err); + } + +#ifdef CONFIG_MODULE /* gotta find a "cleaner" way to do this */ + if (owner) { + struct module_kobject *mk = &owner->mkobj; + + err = sysfs_create_link(&root->dev.kobj, &mk->kobj, "module"); + if (err) { + device_unregister(&root->dev); + return ERR_PTR(err); + } + root->owner = owner; + } +#endif + + return &root->dev; +} +EXPORT_SYMBOL_GPL(__root_device_register); + +/** + * root_device_unregister - unregister and free a root device + * @root: device going away. + * + * This function unregisters and cleans up a device that was created by + * root_device_register(). + */ +void root_device_unregister(struct device *dev) +{ + struct root_device *root = to_root_device(dev); + + if (root->owner) + sysfs_remove_link(&root->dev.kobj, "module"); + + device_unregister(dev); +} +EXPORT_SYMBOL_GPL(root_device_unregister); + static void device_create_release(struct device *dev) { - pr_debug("device: '%s': %s\n", dev->bus_id, __func__); + pr_debug("device: '%s': %s\n", dev_name(dev), __func__); kfree(dev); } @@ -1344,7 +1456,7 @@ int device_rename(struct device *dev, char *new_name) if (!dev) return -EINVAL; - pr_debug("device: '%s': %s: renaming to '%s'\n", dev->bus_id, + pr_debug("device: '%s': %s: renaming to '%s'\n", dev_name(dev), __func__, new_name); #ifdef CONFIG_SYSFS_DEPRECATED @@ -1381,7 +1493,7 @@ int device_rename(struct device *dev, char *new_name) #else if (dev->class) { error = sysfs_create_link_nowarn(&dev->class->p->class_subsys.kobj, - &dev->kobj, dev->bus_id); + &dev->kobj, dev_name(dev)); if (error) goto out; sysfs_remove_link(&dev->class->p->class_subsys.kobj, @@ -1459,8 +1571,8 @@ int device_move(struct device *dev, struct device *new_parent) new_parent = get_device(new_parent); new_parent_kobj = get_device_parent(dev, new_parent); - pr_debug("device: '%s': %s: moving to '%s'\n", dev->bus_id, - __func__, new_parent ? new_parent->bus_id : "<NULL>"); + pr_debug("device: '%s': %s: moving to '%s'\n", dev_name(dev), + __func__, new_parent ? dev_name(new_parent) : "<NULL>"); error = kobject_move(&dev->kobj, new_parent_kobj); if (error) { cleanup_glue_dir(dev, new_parent_kobj); @@ -1470,9 +1582,10 @@ int device_move(struct device *dev, struct device *new_parent) old_parent = dev->parent; dev->parent = new_parent; if (old_parent) - klist_remove(&dev->knode_parent); + klist_remove(&dev->p->knode_parent); if (new_parent) { - klist_add_tail(&dev->knode_parent, &new_parent->klist_children); + klist_add_tail(&dev->p->knode_parent, + &new_parent->p->klist_children); set_dev_node(dev, dev_to_node(new_parent)); } @@ -1484,11 +1597,11 @@ int device_move(struct device *dev, struct device *new_parent) device_move_class_links(dev, new_parent, old_parent); if (!kobject_move(&dev->kobj, &old_parent->kobj)) { if (new_parent) - klist_remove(&dev->knode_parent); + klist_remove(&dev->p->knode_parent); dev->parent = old_parent; if (old_parent) { - klist_add_tail(&dev->knode_parent, - &old_parent->klist_children); + klist_add_tail(&dev->p->knode_parent, + &old_parent->p->klist_children); set_dev_node(dev, dev_to_node(old_parent)); } } diff --git a/drivers/base/dd.c b/drivers/base/dd.c index 20febc0..6fdaf76 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -28,20 +28,20 @@ static void driver_bound(struct device *dev) { - if (klist_node_attached(&dev->knode_driver)) { + if (klist_node_attached(&dev->p->knode_driver)) { printk(KERN_WARNING "%s: device %s already bound\n", __func__, kobject_name(&dev->kobj)); return; } - pr_debug("driver: '%s': %s: bound to device '%s'\n", dev->bus_id, + pr_debug("driver: '%s': %s: bound to device '%s'\n", dev_name(dev), __func__, dev->driver->name); if (dev->bus) blocking_notifier_call_chain(&dev->bus->p->bus_notifier, BUS_NOTIFY_BOUND_DRIVER, dev); - klist_add_tail(&dev->knode_driver, &dev->driver->p->klist_devices); + klist_add_tail(&dev->p->knode_driver, &dev->driver->p->klist_devices); } static int driver_sysfs_add(struct device *dev) @@ -104,13 +104,13 @@ static int really_probe(struct device *dev, struct device_driver *drv) atomic_inc(&probe_count); pr_debug("bus: '%s': %s: probing driver %s with device %s\n", - drv->bus->name, __func__, drv->name, dev->bus_id); + drv->bus->name, __func__, drv->name, dev_name(dev)); WARN_ON(!list_empty(&dev->devres_head)); dev->driver = drv; if (driver_sysfs_add(dev)) { printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n", - __func__, dev->bus_id); + __func__, dev_name(dev)); goto probe_failed; } @@ -127,7 +127,7 @@ static int really_probe(struct device *dev, struct device_driver *drv) driver_bound(dev); ret = 1; pr_debug("bus: '%s': %s: bound device %s to driver %s\n", - drv->bus->name, __func__, dev->bus_id, drv->name); + drv->bus->name, __func__, dev_name(dev), drv->name); goto done; probe_failed: @@ -139,7 +139,7 @@ probe_failed: /* driver matched but the probe failed */ printk(KERN_WARNING "%s: probe of %s failed with error %d\n", - drv->name, dev->bus_id, ret); + drv->name, dev_name(dev), ret); } /* * Ignore errors returned by ->probe so that the next driver can try @@ -194,7 +194,7 @@ int driver_probe_device(struct device_driver *drv, struct device *dev) goto done; pr_debug("bus: '%s': %s: matched device %s with driver %s\n", - drv->bus->name, __func__, dev->bus_id, drv->name); + drv->bus->name, __func__, dev_name(dev), drv->name); ret = really_probe(dev, drv); @@ -298,7 +298,6 @@ static void __device_release_driver(struct device *dev) drv = dev->driver; if (drv) { driver_sysfs_remove(dev); - sysfs_remove_link(&dev->kobj, "driver"); if (dev->bus) blocking_notifier_call_chain(&dev->bus->p->bus_notifier, @@ -311,7 +310,7 @@ static void __device_release_driver(struct device *dev) drv->remove(dev); devres_release_all(dev); dev->driver = NULL; - klist_remove(&dev->knode_driver); + klist_remove(&dev->p->knode_driver); } } @@ -341,6 +340,7 @@ EXPORT_SYMBOL_GPL(device_release_driver); */ void driver_detach(struct device_driver *drv) { + struct device_private *dev_prv; struct device *dev; for (;;) { @@ -349,8 +349,10 @@ void driver_detach(struct device_driver *drv) spin_unlock(&drv->p->klist_devices.k_lock); break; } - dev = list_entry(drv->p->klist_devices.k_list.prev, - struct device, knode_driver.n_node); + dev_prv = list_entry(drv->p->klist_devices.k_list.prev, + struct device_private, + knode_driver.n_node); + dev = dev_prv->device; get_device(dev); spin_unlock(&drv->p->klist_devices.k_lock); diff --git a/drivers/base/driver.c b/drivers/base/driver.c index 1e2bda7..b76cc69 100644 --- a/drivers/base/driver.c +++ b/drivers/base/driver.c @@ -19,7 +19,14 @@ static struct device *next_device(struct klist_iter *i) { struct klist_node *n = klist_next(i); - return n ? container_of(n, struct device, knode_driver) : NULL; + struct device *dev = NULL; + struct device_private *dev_prv; + + if (n) { + dev_prv = to_device_private_driver(n); + dev = dev_prv->device; + } + return dev; } /** @@ -42,7 +49,7 @@ int driver_for_each_device(struct device_driver *drv, struct device *start, return -EINVAL; klist_iter_init_node(&drv->p->klist_devices, &i, - start ? &start->knode_driver : NULL); + start ? &start->p->knode_driver : NULL); while ((dev = next_device(&i)) && !error) error = fn(dev, data); klist_iter_exit(&i); @@ -76,7 +83,7 @@ struct device *driver_find_device(struct device_driver *drv, return NULL; klist_iter_init_node(&drv->p->klist_devices, &i, - (start ? &start->knode_driver : NULL)); + (start ? &start->p->knode_driver : NULL)); while ((dev = next_device(&i))) if (match(dev, data) && get_device(dev)) break; diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index b7e5710..44699d9 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c @@ -291,12 +291,6 @@ firmware_class_timeout(u_long data) fw_load_abort(fw_priv); } -static inline void fw_setup_device_id(struct device *f_dev, struct device *dev) -{ - /* XXX warning we should watch out for name collisions */ - strlcpy(f_dev->bus_id, dev->bus_id, BUS_ID_SIZE); -} - static int fw_register_device(struct device **dev_p, const char *fw_name, struct device *device) { @@ -321,7 +315,7 @@ static int fw_register_device(struct device **dev_p, const char *fw_name, fw_priv->timeout.data = (u_long) fw_priv; init_timer(&fw_priv->timeout); - fw_setup_device_id(f_dev, device); + dev_set_name(f_dev, dev_name(device)); f_dev->parent = device; f_dev->class = &firmware_class; dev_set_drvdata(f_dev, fw_priv); diff --git a/drivers/base/isa.c b/drivers/base/isa.c index efd5775..479694b 100644 --- a/drivers/base/isa.c +++ b/drivers/base/isa.c @@ -11,7 +11,7 @@ #include <linux/isa.h> static struct device isa_bus = { - .bus_id = "isa" + .init_name = "isa" }; struct isa_dev { @@ -135,9 +135,8 @@ int isa_register_driver(struct isa_driver *isa_driver, unsigned int ndev) isa_dev->dev.parent = &isa_bus; isa_dev->dev.bus = &isa_bus_type; - snprintf(isa_dev->dev.bus_id, BUS_ID_SIZE, "%s.%u", - isa_driver->driver.name, id); - + dev_set_name(&isa_dev->dev, "%s.%u", + isa_driver->driver.name, id); isa_dev->dev.platform_data = isa_driver; isa_dev->dev.release = isa_dev_release; isa_dev->id = id; diff --git a/drivers/base/memory.c b/drivers/base/memory.c index 5260e9e..989429c 100644 --- a/drivers/base/memory.c +++ b/drivers/base/memory.c @@ -347,8 +347,9 @@ static inline int memory_probe_init(void) * section belongs to... */ -static int add_memory_block(unsigned long node_id, struct mem_section *section, - unsigned long state, int phys_device) +static int add_memory_block(int nid, struct mem_section *section, + unsigned long state, int phys_device, + enum mem_add_context context) { struct memory_block *mem = kzalloc(sizeof(*mem), GFP_KERNEL); int ret = 0; @@ -370,6 +371,10 @@ static int add_memory_block(unsigned long node_id, struct mem_section *section, ret = mem_create_simple_file(mem, phys_device); if (!ret) ret = mem_create_simple_file(mem, removable); + if (!ret) { + if (context == HOTPLUG) + ret = register_mem_sect_under_node(mem, nid); + } return ret; } @@ -382,7 +387,7 @@ static int add_memory_block(unsigned long node_id, struct mem_section *section, * * This could be made generic for all sysdev classes. */ -static struct memory_block *find_memory_block(struct mem_section *section) +struct memory_block *find_memory_block(struct mem_section *section) { struct kobject *kobj; struct sys_device *sysdev; @@ -411,6 +416,7 @@ int remove_memory_block(unsigned long node_id, struct mem_section *section, struct memory_block *mem; mem = find_memory_block(section); + unregister_mem_sect_under_nodes(mem); mem_remove_simple_file(mem, phys_index); mem_remove_simple_file(mem, state); mem_remove_simple_file(mem, phys_device); @@ -424,9 +430,9 @@ int remove_memory_block(unsigned long node_id, struct mem_section *section, * need an interface for the VM to add new memory regions, * but without onlining it. */ -int register_new_memory(struct mem_section *section) +int register_new_memory(int nid, struct mem_section *section) { - return add_memory_block(0, section, MEM_OFFLINE, 0); + return add_memory_block(nid, section, MEM_OFFLINE, 0, HOTPLUG); } int unregister_memory_section(struct mem_section *section) @@ -458,7 +464,8 @@ int __init memory_dev_init(void) for (i = 0; i < NR_MEM_SECTIONS; i++) { if (!present_section_nr(i)) continue; - err = add_memory_block(0, __nr_to_section(i), MEM_ONLINE, 0); + err = add_memory_block(0, __nr_to_section(i), MEM_ONLINE, + 0, BOOT); if (!ret) ret = err; } diff --git a/drivers/base/node.c b/drivers/base/node.c index 91636cd..43fa90b 100644 --- a/drivers/base/node.c +++ b/drivers/base/node.c @@ -6,6 +6,7 @@ #include <linux/module.h> #include <linux/init.h> #include <linux/mm.h> +#include <linux/memory.h> #include <linux/node.h> #include <linux/hugetlb.h> #include <linux/cpumask.h> @@ -248,6 +249,105 @@ int unregister_cpu_under_node(unsigned int cpu, unsigned int nid) return 0; } +#ifdef CONFIG_MEMORY_HOTPLUG_SPARSE +#define page_initialized(page) (page->lru.next) + +static int get_nid_for_pfn(unsigned long pfn) +{ + struct page *page; + + if (!pfn_valid_within(pfn)) + return -1; + page = pfn_to_page(pfn); + if (!page_initialized(page)) + return -1; + return pfn_to_nid(pfn); +} + +/* register memory section under specified node if it spans that node */ +int register_mem_sect_under_node(struct memory_block *mem_blk, int nid) +{ + unsigned long pfn, sect_start_pfn, sect_end_pfn; + + if (!mem_blk) + return -EFAULT; + if (!node_online(nid)) + return 0; + sect_start_pfn = section_nr_to_pfn(mem_blk->phys_index); + sect_end_pfn = sect_start_pfn + PAGES_PER_SECTION - 1; + for (pfn = sect_start_pfn; pfn <= sect_end_pfn; pfn++) { + int page_nid; + + page_nid = get_nid_for_pfn(pfn); + if (page_nid < 0) + continue; + if (page_nid != nid) + continue; + return sysfs_create_link_nowarn(&node_devices[nid].sysdev.kobj, + &mem_blk->sysdev.kobj, + kobject_name(&mem_blk->sysdev.kobj)); + } + /* mem section does not span the specified node */ + return 0; +} + +/* unregister memory section under all nodes that it spans */ +int unregister_mem_sect_under_nodes(struct memory_block *mem_blk) +{ + nodemask_t unlinked_nodes; + unsigned long pfn, sect_start_pfn, sect_end_pfn; + + if (!mem_blk) + return -EFAULT; + nodes_clear(unlinked_nodes); + sect_start_pfn = section_nr_to_pfn(mem_blk->phys_index); + sect_end_pfn = sect_start_pfn + PAGES_PER_SECTION - 1; + for (pfn = sect_start_pfn; pfn <= sect_end_pfn; pfn++) { + unsigned int nid; + + nid = get_nid_for_pfn(pfn); + if (nid < 0) + continue; + if (!node_online(nid)) + continue; + if (node_test_and_set(nid, unlinked_nodes)) + continue; + sysfs_remove_link(&node_devices[nid].sysdev.kobj, + kobject_name(&mem_blk->sysdev.kobj)); + } + return 0; +} + +static int link_mem_sections(int nid) +{ + unsigned long start_pfn = NODE_DATA(nid)->node_start_pfn; + unsigned long end_pfn = start_pfn + NODE_DATA(nid)->node_spanned_pages; + unsigned long pfn; + int err = 0; + + for (pfn = start_pfn; pfn < end_pfn; pfn += PAGES_PER_SECTION) { + unsigned long section_nr = pfn_to_section_nr(pfn); + struct mem_section *mem_sect; + struct memory_block *mem_blk; + int ret; + + if (!present_section_nr(section_nr)) + continue; + mem_sect = __nr_to_section(section_nr); + mem_blk = find_memory_block(mem_sect); + ret = register_mem_sect_under_node(mem_blk, nid); + if (!err) + err = ret; + + /* discard ref obtained in find_memory_block() */ + kobject_put(&mem_blk->sysdev.kobj); + } + return err; +} +#else +static int link_mem_sections(int nid) { return 0; } +#endif /* CONFIG_MEMORY_HOTPLUG_SPARSE */ + int register_one_node(int nid) { int error = 0; @@ -267,6 +367,9 @@ int register_one_node(int nid) if (cpu_to_node(cpu) == nid) register_cpu_under_node(cpu, nid); } + + /* link memory sections under this node */ + error = link_mem_sections(nid); } return error; diff --git a/drivers/base/platform.c b/drivers/base/platform.c index dfcbfe5..349a101 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -24,7 +24,7 @@ driver)) struct device platform_bus = { - .bus_id = "platform", + .init_name = "platform", }; EXPORT_SYMBOL_GPL(platform_bus); @@ -242,16 +242,15 @@ int platform_device_add(struct platform_device *pdev) pdev->dev.bus = &platform_bus_type; if (pdev->id != -1) - snprintf(pdev->dev.bus_id, BUS_ID_SIZE, "%s.%d", pdev->name, - pdev->id); + dev_set_name(&pdev->dev, "%s.%d", pdev->name, pdev->id); else - strlcpy(pdev->dev.bus_id, pdev->name, BUS_ID_SIZE); + dev_set_name(&pdev->dev, pdev->name); for (i = 0; i < pdev->num_resources; i++) { struct resource *p, *r = &pdev->resource[i]; if (r->name == NULL) - r->name = pdev->dev.bus_id; + r->name = dev_name(&pdev->dev); p = r->parent; if (!p) { @@ -264,14 +263,14 @@ int platform_device_add(struct platform_device *pdev) if (p && insert_resource(p, r)) { printk(KERN_ERR "%s: failed to claim resource %d\n", - pdev->dev.bus_id, i); + dev_name(&pdev->dev), i); ret = -EBUSY; goto failed; } } pr_debug("Registering platform device '%s'. Parent at %s\n", - pdev->dev.bus_id, pdev->dev.parent->bus_id); + dev_name(&pdev->dev), dev_name(pdev->dev.parent)); ret = device_add(&pdev->dev); if (ret == 0) @@ -503,8 +502,6 @@ int platform_driver_register(struct platform_driver *drv) drv->driver.suspend = platform_drv_suspend; if (drv->resume) drv->driver.resume = platform_drv_resume; - if (drv->pm) - drv->driver.pm = &drv->pm->base; return driver_register(&drv->driver); } EXPORT_SYMBOL_GPL(platform_driver_register); @@ -609,7 +606,7 @@ static int platform_match(struct device *dev, struct device_driver *drv) struct platform_device *pdev; pdev = container_of(dev, struct platform_device, dev); - return (strncmp(pdev->name, drv->name, BUS_ID_SIZE) == 0); + return (strcmp(pdev->name, drv->name) == 0); } #ifdef CONFIG_PM_SLEEP @@ -686,7 +683,10 @@ static int platform_pm_suspend(struct device *dev) struct device_driver *drv = dev->driver; int ret = 0; - if (drv && drv->pm) { + if (!drv) + return 0; + + if (drv->pm) { if (drv->pm->suspend) ret = drv->pm->suspend(dev); } else { @@ -698,16 +698,15 @@ static int platform_pm_suspend(struct device *dev) static int platform_pm_suspend_noirq(struct device *dev) { - struct platform_driver *pdrv; + struct device_driver *drv = dev->driver; int ret = 0; - if (!dev->driver) + if (!drv) return 0; - pdrv = to_platform_driver(dev->driver); - if (pdrv->pm) { - if (pdrv->pm->suspend_noirq) - ret = pdrv->pm->suspend_noirq(dev); + if (drv->pm) { + if (drv->pm->suspend_noirq) + ret = drv->pm->suspend_noirq(dev); } else { ret = platform_legacy_suspend_late(dev, PMSG_SUSPEND); } @@ -720,7 +719,10 @@ static int platform_pm_resume(struct device *dev) struct device_driver *drv = dev->driver; int ret = 0; - if (drv && drv->pm) { + if (!drv) + return 0; + + if (drv->pm) { if (drv->pm->resume) ret = drv->pm->resume(dev); } else { @@ -732,16 +734,15 @@ static int platform_pm_resume(struct device *dev) static int platform_pm_resume_noirq(struct device *dev) { - struct platform_driver *pdrv; + struct device_driver *drv = dev->driver; int ret = 0; - if (!dev->driver) + if (!drv) return 0; - pdrv = to_platform_driver(dev->driver); - if (pdrv->pm) { - if (pdrv->pm->resume_noirq) - ret = pdrv->pm->resume_noirq(dev); + if (drv->pm) { + if (drv->pm->resume_noirq) + ret = drv->pm->resume_noirq(dev); } else { ret = platform_legacy_resume_early(dev); } @@ -780,16 +781,15 @@ static int platform_pm_freeze(struct device *dev) static int platform_pm_freeze_noirq(struct device *dev) { - struct platform_driver *pdrv; + struct device_driver *drv = dev->driver; int ret = 0; - if (!dev->driver) + if (!drv) return 0; - pdrv = to_platform_driver(dev->driver); - if (pdrv->pm) { - if (pdrv->pm->freeze_noirq) - ret = pdrv->pm->freeze_noirq(dev); + if (drv->pm) { + if (drv->pm->freeze_noirq) + ret = drv->pm->freeze_noirq(dev); } else { ret = platform_legacy_suspend_late(dev, PMSG_FREEZE); } @@ -802,7 +802,10 @@ static int platform_pm_thaw(struct device *dev) struct device_driver *drv = dev->driver; int ret = 0; - if (drv && drv->pm) { + if (!drv) + return 0; + + if (drv->pm) { if (drv->pm->thaw) ret = drv->pm->thaw(dev); } else { @@ -814,16 +817,15 @@ static int platform_pm_thaw(struct device *dev) static int platform_pm_thaw_noirq(struct device *dev) { - struct platform_driver *pdrv; + struct device_driver *drv = dev->driver; int ret = 0; - if (!dev->driver) + if (!drv) return 0; - pdrv = to_platform_driver(dev->driver); - if (pdrv->pm) { - if (pdrv->pm->thaw_noirq) - ret = pdrv->pm->thaw_noirq(dev); + if (drv->pm) { + if (drv->pm->thaw_noirq) + ret = drv->pm->thaw_noirq(dev); } else { ret = platform_legacy_resume_early(dev); } @@ -836,7 +838,10 @@ static int platform_pm_poweroff(struct device *dev) struct device_driver *drv = dev->driver; int ret = 0; - if (drv && drv->pm) { + if (!drv) + return 0; + + if (drv->pm) { if (drv->pm->poweroff) ret = drv->pm->poweroff(dev); } else { @@ -848,16 +853,15 @@ static int platform_pm_poweroff(struct device *dev) static int platform_pm_poweroff_noirq(struct device *dev) { - struct platform_driver *pdrv; + struct device_driver *drv = dev->driver; int ret = 0; - if (!dev->driver) + if (!drv) return 0; - pdrv = to_platform_driver(dev->driver); - if (pdrv->pm) { - if (pdrv->pm->poweroff_noirq) - ret = pdrv->pm->poweroff_noirq(dev); + if (drv->pm) { + if (drv->pm->poweroff_noirq) + ret = drv->pm->poweroff_noirq(dev); } else { ret = platform_legacy_suspend_late(dev, PMSG_HIBERNATE); } @@ -870,7 +874,10 @@ static int platform_pm_restore(struct device *dev) struct device_driver *drv = dev->driver; int ret = 0; - if (drv && drv->pm) { + if (!drv) + return 0; + + if (drv->pm) { if (drv->pm->restore) ret = drv->pm->restore(dev); } else { @@ -882,16 +889,15 @@ static int platform_pm_restore(struct device *dev) static int platform_pm_restore_noirq(struct device *dev) { - struct platform_driver *pdrv; + struct device_driver *drv = dev->driver; int ret = 0; - if (!dev->driver) + if (!drv) return 0; - pdrv = to_platform_driver(dev->driver); - if (pdrv->pm) { - if (pdrv->pm->restore_noirq) - ret = pdrv->pm->restore_noirq(dev); + if (drv->pm) { + if (drv->pm->restore_noirq) + ret = drv->pm->restore_noirq(dev); } else { ret = platform_legacy_resume_early(dev); } @@ -912,17 +918,15 @@ static int platform_pm_restore_noirq(struct device *dev) #endif /* !CONFIG_HIBERNATION */ -static struct pm_ext_ops platform_pm_ops = { - .base = { - .prepare = platform_pm_prepare, - .complete = platform_pm_complete, - .suspend = platform_pm_suspend, - .resume = platform_pm_resume, - .freeze = platform_pm_freeze, - .thaw = platform_pm_thaw, - .poweroff = platform_pm_poweroff, - .restore = platform_pm_restore, - }, +static struct dev_pm_ops platform_dev_pm_ops = { + .prepare = platform_pm_prepare, + .complete = platform_pm_complete, + .suspend = platform_pm_suspend, + .resume = platform_pm_resume, + .freeze = platform_pm_freeze, + .thaw = platform_pm_thaw, + .poweroff = platform_pm_poweroff, + .restore = platform_pm_restore, .suspend_noirq = platform_pm_suspend_noirq, .resume_noirq = platform_pm_resume_noirq, .freeze_noirq = platform_pm_freeze_noirq, @@ -931,7 +935,7 @@ static struct pm_ext_ops platform_pm_ops = { .restore_noirq = platform_pm_restore_noirq, }; -#define PLATFORM_PM_OPS_PTR &platform_pm_ops +#define PLATFORM_PM_OPS_PTR (&platform_dev_pm_ops) #else /* !CONFIG_PM_SLEEP */ diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 692c20b..670c9d6 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -76,7 +76,7 @@ void device_pm_add(struct device *dev) if (dev->parent) { if (dev->parent->power.status >= DPM_SUSPENDING) dev_warn(dev, "parent %s should not be sleeping\n", - dev->parent->bus_id); + dev_name(dev->parent)); } else if (transition_started) { /* * We refuse to register parentless devices while a PM @@ -112,7 +112,8 @@ void device_pm_remove(struct device *dev) * @ops: PM operations to choose from. * @state: PM transition of the system being carried out. */ -static int pm_op(struct device *dev, struct pm_ops *ops, pm_message_t state) +static int pm_op(struct device *dev, struct dev_pm_ops *ops, + pm_message_t state) { int error = 0; @@ -174,7 +175,7 @@ static int pm_op(struct device *dev, struct pm_ops *ops, pm_message_t state) * The operation is executed with interrupts disabled by the only remaining * functional CPU in the system. */ -static int pm_noirq_op(struct device *dev, struct pm_ext_ops *ops, +static int pm_noirq_op(struct device *dev, struct dev_pm_ops *ops, pm_message_t state) { int error = 0; @@ -354,7 +355,7 @@ static int resume_device(struct device *dev, pm_message_t state) if (dev->bus) { if (dev->bus->pm) { pm_dev_dbg(dev, state, ""); - error = pm_op(dev, &dev->bus->pm->base, state); + error = pm_op(dev, dev->bus->pm, state); } else if (dev->bus->resume) { pm_dev_dbg(dev, state, "legacy "); error = dev->bus->resume(dev); @@ -451,9 +452,9 @@ static void complete_device(struct device *dev, pm_message_t state) dev->type->pm->complete(dev); } - if (dev->bus && dev->bus->pm && dev->bus->pm->base.complete) { + if (dev->bus && dev->bus->pm && dev->bus->pm->complete) { pm_dev_dbg(dev, state, "completing "); - dev->bus->pm->base.complete(dev); + dev->bus->pm->complete(dev); } up(&dev->sem); @@ -624,7 +625,7 @@ static int suspend_device(struct device *dev, pm_message_t state) if (dev->bus) { if (dev->bus->pm) { pm_dev_dbg(dev, state, ""); - error = pm_op(dev, &dev->bus->pm->base, state); + error = pm_op(dev, dev->bus->pm, state); } else if (dev->bus->suspend) { pm_dev_dbg(dev, state, "legacy "); error = dev->bus->suspend(dev, state); @@ -685,10 +686,10 @@ static int prepare_device(struct device *dev, pm_message_t state) down(&dev->sem); - if (dev->bus && dev->bus->pm && dev->bus->pm->base.prepare) { + if (dev->bus && dev->bus->pm && dev->bus->pm->prepare) { pm_dev_dbg(dev, state, "preparing "); - error = dev->bus->pm->base.prepare(dev); - suspend_report_result(dev->bus->pm->base.prepare, error); + error = dev->bus->pm->prepare(dev); + suspend_report_result(dev->bus->pm->prepare, error); if (error) goto End; } diff --git a/drivers/base/power/trace.c b/drivers/base/power/trace.c index 2aa6e8f..0a1a2c4 100644 --- a/drivers/base/power/trace.c +++ b/drivers/base/power/trace.c @@ -140,7 +140,7 @@ static unsigned int hash_string(unsigned int seed, const char *data, unsigned in void set_trace_device(struct device *dev) { - dev_hash_value = hash_string(DEVSEED, dev->bus_id, DEVHASH); + dev_hash_value = hash_string(DEVSEED, dev_name(dev), DEVHASH); } EXPORT_SYMBOL(set_trace_device); @@ -192,7 +192,7 @@ static int show_dev_hash(unsigned int value) while (entry != &dpm_list) { struct device * dev = to_device(entry); - unsigned int hash = hash_string(DEVSEED, dev->bus_id, DEVHASH); + unsigned int hash = hash_string(DEVSEED, dev_name(dev), DEVHASH); if (hash == value) { dev_info(dev, "hash matches\n"); match++; |