From ec748fa9ed3fec44aeebbf86ae050b0cc7a978d9 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Mon, 21 Jul 2008 22:33:36 +0300 Subject: driver core: make struct platform_pm_ops static This patch makes the needlessly global struct platform_pm_ops static. Signed-off-by: Adrian Bunk Signed-off-by: Greg Kroah-Hartman --- drivers/base/platform.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/base') diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 3f94039..e621dad 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -862,7 +862,7 @@ static int platform_pm_restore_noirq(struct device *dev) #endif /* !CONFIG_HIBERNATION */ -struct pm_ext_ops platform_pm_ops = { +static struct pm_ext_ops platform_pm_ops = { .base = { .prepare = platform_pm_prepare, .complete = platform_pm_complete, -- cgit v1.1 From 5739411acbaa63a6c22c91e340fdcdbcc7d82a51 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Wed, 3 Sep 2008 18:26:40 +0200 Subject: Driver core: Clarify device cleanup. Make the comments on how to use device_initialize(), device_add() and device_register() a bit clearer - in particular, explicitly note that put_device() must be used once we tried to add the device to the hierarchy. Signed-off-by: Cornelia Huck Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/base/core.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) (limited to 'drivers/base') diff --git a/drivers/base/core.c b/drivers/base/core.c index b98cb14..aac91e8 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -523,11 +523,16 @@ static void klist_children_put(struct klist_node *n) * device_initialize - init device structure. * @dev: device. * - * This prepares the device for use by other layers, - * including adding it to the device hierarchy. + * This prepares the device for use by other layers by initializing + * its fields. * It is the first half of device_register(), if called by - * that, though it can also be called separately, so one - * may use @dev's fields (e.g. the refcount). + * that function, though it can also be called separately, so one + * may use @dev's fields. In particular, get_device()/put_device() + * may be used for reference counting of @dev after calling this + * function. + * + * NOTE: Use put_device() to give up your reference instead of freeing + * @dev directly once you have called this function. */ void device_initialize(struct device *dev) { @@ -835,9 +840,13 @@ static void device_remove_sys_dev_entry(struct device *dev) * This is part 2 of device_register(), though may be called * separately _iff_ device_initialize() has been called separately. * - * This adds it to the kobject hierarchy via kobject_add(), adds it + * This adds @dev to the kobject hierarchy via kobject_add(), adds it * to the global and sibling lists for the device, then * adds it to the other relevant subsystems of the driver model. + * + * 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. */ int device_add(struct device *dev) { @@ -965,6 +974,10 @@ done: * I.e. you should only call the two helpers separately if * have a clearly defined need to use and refcount the device * before it is added to the hierarchy. + * + * 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. */ int device_register(struct device *dev) { -- cgit v1.1 From 286661b3777897220ecfcd774bccc68a34667f39 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Wed, 3 Sep 2008 18:26:41 +0200 Subject: Driver core: Fix cleanup in device_create_vargs(). If device_register() in device_create_vargs() fails, the device must be cleaned up with put_device() (which is also fine on NULL) instead of kfree(). Signed-off-by: Cornelia Huck Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/base/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/base') diff --git a/drivers/base/core.c b/drivers/base/core.c index aac91e8..9649d1c 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -1256,7 +1256,7 @@ struct device *device_create_vargs(struct class *class, struct device *parent, return dev; error: - kfree(dev); + put_device(dev); return ERR_PTR(retval); } EXPORT_SYMBOL_GPL(device_create_vargs); -- cgit v1.1 From 6cd49586090187a2a145bb6570fb2392f121aa22 Mon Sep 17 00:00:00 2001 From: Arjan van de Ven Date: Sun, 14 Sep 2008 08:32:06 -0700 Subject: device model: Do a quickcheck for driver binding before doing an expensive check This patch adds a quick check for the driver<->device match before taking the locks and doin gthe expensive checks. Taking the lock hurts in asynchronous boot context where the device lock gets hit; one of the init functions takes the lock and goes to do an expensive hardware init; the other init functions walk the same PCI list and get stuck on the lock as a result. For the common case, we can know there's no chance whatsoever of a match if the device isn't in the drivers ID table... so this patch does that check as a best-effort-avoid-the-lock approach. Bootcharts for before and after can be seen at http://www.fenrus.org/before.svg http://www.fenrus.org/after.svg Note the long time "agp_ali_init" takes in the first graph; my laptop doesn't even have an ALI chip in it! (the bootgraphs look a bit dissimilar, but that's the point, the first one has a bunch of arbitrary delays in it that cause it to look very different) This reduces my kernel boot time by about 20% Signed-off-by: Arjan van de Ven Cc: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/base/dd.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/base') diff --git a/drivers/base/dd.c b/drivers/base/dd.c index 3ac443b..20febc0 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -257,6 +257,9 @@ static int __driver_attach(struct device *dev, void *data) * is an error. */ + if (drv->bus->match && !drv->bus->match(dev, drv)) + return 0; + if (dev->parent) /* Needed for USB */ down(&dev->parent->sem); down(&dev->sem); -- cgit v1.1 From 728f08934b087b96aacb00467f5551e0a5593fca Mon Sep 17 00:00:00 2001 From: Arjan van de Ven Date: Sat, 20 Sep 2008 19:09:00 -0700 Subject: debug: use dev_WARN() rather than WARN_ON() in device_pm_add() device_pm_add() has a WARN_ON that is showing relatively high on kerneloops.org, but unfortunately the WARN_ON is less than useful in that it doesn't print any information about what device is causing the issue. This patch fixes this by turning the WARN_ON() into the newly introduces dev_WARN() which will print information about the device in question. Signed-off-by: Arjan van de Ven Signed-off-by: Greg Kroah-Hartman --- drivers/base/power/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/base') diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 273a944..b0eb6af 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -83,7 +83,7 @@ void device_pm_add(struct device *dev) * transition is in progress in order to avoid leaving them * unhandled down the road */ - WARN_ON(true); + dev_WARN(dev, "Parentless device registered during a PM transaction\n"); } list_add_tail(&dev->power.entry, &dpm_list); -- cgit v1.1 From 3ce24d8d93f8f9617841d0c8416174da7ee1b042 Mon Sep 17 00:00:00 2001 From: Peter Korsgaard Date: Tue, 23 Sep 2008 22:01:27 +0200 Subject: Driver core: make bus_find_device_by_name() more robust Use sysfs_streq() in bus_find_device_by_name() so trailing newlines are ignored (E.G. in bind/unbind). Signed-off-by: Peter Korsgaard Signed-off-by: Greg Kroah-Hartman --- drivers/base/bus.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/base') diff --git a/drivers/base/bus.c b/drivers/base/bus.c index ef522ae..39b9b58 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -333,9 +333,7 @@ static int match_name(struct device *dev, void *data) { const char *name = data; - if (strcmp(name, dev->bus_id) == 0) - return 1; - return 0; + return sysfs_streq(name, dev->bus_id); } /** -- cgit v1.1 From d8bf254089a6c31d7d01a4d1d2f1861662900855 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Mon, 22 Sep 2008 14:41:40 -0700 Subject: platform: add new device registration helper Add a helper that registers simple platform_device w/o resources but with parent and device data. This is usefull to cleanup platform code from code that registers such simple devices as leds-gpio, generic-bl, etc. Signed-off-by: Dmitry Baryshkov Cc: David Brownell Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/base/platform.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) (limited to 'drivers/base') diff --git a/drivers/base/platform.c b/drivers/base/platform.c index e621dad..9e60f7c 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -391,6 +391,53 @@ error: } EXPORT_SYMBOL_GPL(platform_device_register_simple); +/** + * platform_device_register_data + * @parent: parent device for the device we're adding + * @name: base name of the device we're adding + * @id: instance id + * @data: platform specific data for this platform device + * @size: size of platform specific data + * + * This function creates a simple platform device that requires minimal + * resource and memory management. Canned release function freeing memory + * allocated for the device allows drivers using such devices to be + * unloaded without waiting for the last reference to the device to be + * dropped. + */ +struct platform_device *platform_device_register_data( + struct device *parent, + const char *name, int id, + const void *data, size_t size) +{ + struct platform_device *pdev; + int retval; + + pdev = platform_device_alloc(name, id); + if (!pdev) { + retval = -ENOMEM; + goto error; + } + + pdev->dev.parent = parent; + + if (size) { + retval = platform_device_add_data(pdev, data, size); + if (retval) + goto error; + } + + retval = platform_device_add(pdev); + if (retval) + goto error; + + return pdev; + +error: + platform_device_put(pdev); + return ERR_PTR(retval); +} + static int platform_drv_probe(struct device *_dev) { struct platform_driver *drv = to_platform_driver(_dev->driver); -- cgit v1.1 From 030c1d2bfcc2187650fb975456ca0b61a5bb77f4 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Thu, 8 May 2008 14:41:00 -0700 Subject: kobject: Fix kobject_rename and !CONFIG_SYSFS When looking at kobject_rename I found two bugs with that exist when sysfs support is disabled in the kernel. kobject_rename does not change the name on the kobject when sysfs support is not compiled in. kobject_rename without locking attempts to check the validity of a rename operation, which the kobject layer simply does not have the infrastructure to do. This patch documents the previously unstated requirement of kobject_rename that is the responsibility of the caller to provide mutual exclusion and to be certain that the new_name for the kobject is valid. This patch modifies sysfs_rename_dir in !CONFIG_SYSFS case to call kobject_set_name to actually change the kobject_name. This patch removes the bogus and misleading check in kobject_rename that attempts to see if a rename is valid. The check is bogus because we do not have the proper locking. The check is misleading because it looks like we can and do perform checking at the kobject level that we don't. Signed-off-by: Eric W. Biederman Signed-off-by: Greg Kroah-Hartman --- drivers/base/core.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/base') diff --git a/drivers/base/core.c b/drivers/base/core.c index 9649d1c..8c2cc26 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -1327,6 +1327,11 @@ EXPORT_SYMBOL_GPL(device_destroy); * device_rename - renames a device * @dev: the pointer to the struct device to be renamed * @new_name: the new name of the device + * + * It is the responsibility of the caller to provide mutual + * exclusion between two different calls of device_rename + * on the same device to ensure that new_name is valid and + * won't conflict with other devices. */ int device_rename(struct device *dev, char *new_name) { -- cgit v1.1 From 99178b036c97293a65004ff5ec5cff9f833aaecd Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 26 Aug 2008 11:00:57 -0500 Subject: Driver core: add bus_sort_breadthfirst() function The PCI core wants to reorder the devices in the bus list. So move this functionality out of the pci core and into the driver core so that anyone else can also do this if needed. This also lets us change how struct device is attached to drivers in the future without messing with the PCI core. Acked-by: Jesse Barnes Signed-off-by: Greg Kroah-Hartman --- drivers/base/bus.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) (limited to 'drivers/base') diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 39b9b58..5aee1c0 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -980,6 +980,56 @@ struct klist *bus_get_device_klist(struct bus_type *bus) } EXPORT_SYMBOL_GPL(bus_get_device_klist); +/* + * Yes, this forcably breaks the klist abstraction temporarily. It + * just wants to sort the klist, not change reference counts and + * take/drop locks rapidly in the process. It does all this while + * holding the lock for the list, so objects can't otherwise be + * added/removed while we're swizzling. + */ +static void device_insertion_sort_klist(struct device *a, struct list_head *list, + int (*compare)(const struct device *a, + const struct device *b)) +{ + struct list_head *pos; + struct klist_node *n; + 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); + if (compare(a, b) <= 0) { + list_move_tail(&a->knode_bus.n_node, + &b->knode_bus.n_node); + return; + } + } + list_move_tail(&a->knode_bus.n_node, list); +} + +void bus_sort_breadthfirst(struct bus_type *bus, + int (*compare)(const struct device *a, + const struct device *b)) +{ + LIST_HEAD(sorted_devices); + struct list_head *pos, *tmp; + struct klist_node *n; + struct device *dev; + struct klist *device_klist; + + device_klist = bus_get_device_klist(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); + device_insertion_sort_klist(dev, &sorted_devices, compare); + } + list_splice(&sorted_devices, &device_klist->k_list); + spin_unlock(&device_klist->k_lock); +} +EXPORT_SYMBOL_GPL(bus_sort_breadthfirst); + int __init buses_init(void) { bus_kset = kset_create_and_add("bus", &bus_uevent_ops, NULL); -- cgit v1.1