diff --git a/drivers/base/dd.c b/drivers/base/dd.c index 04e9977ed743..52123251965d 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -1030,6 +1030,38 @@ static int __device_attach_driver(struct device_driver *drv, void *_data) return ret == 0; } +/* + * __device_driver_lock - acquire locks needed to manipulate dev->drv + * @dev: Device we will update driver info for + * @parent: Parent device. Needed if the device type requires parent lock + * + * This function will take the required locks for manipulating dev->drv. + * Normally this will just be the @dev lock, but when called for a USB + * interface, @parent lock will be held as well. + */ +static void __device_driver_lock(struct device *dev, struct device *parent) +{ + if (dev->type && dev->type->need_parent_lock && parent) + device_lock(parent); + device_lock(dev); +} + +/* + * __device_driver_unlock - release locks needed to manipulate dev->drv + * @dev: Device we will update driver info for + * @parent: Parent device. Needed if the device type requires parent lock + * + * This function will release the required locks for manipulating dev->drv. + * Normally this will just be the @dev lock, but when called for a + * USB interface, @parent lock will be released as well. + */ +static void __device_driver_unlock(struct device *dev, struct device *parent) +{ + device_unlock(dev); + if (dev->type && dev->type->need_parent_lock && parent) + device_unlock(parent); +} + static void __device_attach_async_helper(void *_dev, async_cookie_t cookie) { struct device *dev = _dev; @@ -1039,7 +1071,7 @@ static void __device_attach_async_helper(void *_dev, async_cookie_t cookie) .want_async = true, }; - device_lock(dev); + __device_driver_lock(dev, dev->parent); /* * Check if device has already been removed or claimed. This may @@ -1061,7 +1093,7 @@ static void __device_attach_async_helper(void *_dev, async_cookie_t cookie) if (dev->parent) pm_runtime_put(dev->parent); out_unlock: - device_unlock(dev); + __device_driver_unlock(dev, dev->parent); put_device(dev); } @@ -1118,8 +1150,11 @@ static int __device_attach(struct device *dev, bool allow_async) } out_unlock: device_unlock(dev); - if (async) - async_schedule_dev(__device_attach_async_helper, dev); + if (async && !async_schedule_dev_nocall(__device_attach_async_helper, dev)) { + put_device(dev); + ret = 2; /* retry synchronously */ + } + return ret; } @@ -1146,48 +1181,20 @@ EXPORT_SYMBOL_GPL(device_attach); void device_initial_probe(struct device *dev) { struct subsys_private *sp = bus_to_subsys(dev->bus); + int ret; if (!sp) return; - if (sp->drivers_autoprobe) - __device_attach(dev, true); + if (sp->drivers_autoprobe) { + ret = __device_attach(dev, true); + if (ret == 2) + __device_attach(dev, false); + } subsys_put(sp); } -/* - * __device_driver_lock - acquire locks needed to manipulate dev->drv - * @dev: Device we will update driver info for - * @parent: Parent device. Needed if the device type requires parent lock - * - * This function will take the required locks for manipulating dev->drv. - * Normally this will just be the @dev lock, but when called for a USB - * interface, @parent lock will be held as well. - */ -static void __device_driver_lock(struct device *dev, struct device *parent) -{ - if (dev->type && dev->type->need_parent_lock && parent) - device_lock(parent); - device_lock(dev); -} - -/* - * __device_driver_unlock - release locks needed to manipulate dev->drv - * @dev: Device we will update driver info for - * @parent: Parent device. Needed if the device type requires parent lock - * - * This function will release the required locks for manipulating dev->drv. - * Normally this will just be the @dev lock, but when called for a - * USB interface, @parent lock will be released as well. - */ -static void __device_driver_unlock(struct device *dev, struct device *parent) -{ - device_unlock(dev); - if (dev->type && dev->type->need_parent_lock && parent) - device_unlock(parent); -} - /** * device_driver_attach - attach a specific driver to a specific device * @drv: Driver to attach