--- zzzz-none-000/linux-3.10.107/drivers/base/dd.c 2017-06-27 09:49:32.000000000 +0000 +++ scorpion-7490-727/linux-3.10.107/drivers/base/dd.c 2021-02-04 17:41:59.000000000 +0000 @@ -54,7 +54,7 @@ static struct workqueue_struct *deferred_wq; static atomic_t deferred_trigger_count = ATOMIC_INIT(0); -/** +/* * deferred_probe_work_func() - Retry probing devices in the active list. */ static void deferred_probe_work_func(struct work_struct *work) @@ -141,7 +141,7 @@ * more than one device is probing at the same time, it is possible for one * probe to complete successfully while another is about to defer. If the second * depends on the first, then it will get put on the pending list after the - * trigger event has already occured and will be stuck there. + * trigger event has already occurred and will be stuck there. * * The atomic 'deferred_trigger_count' is used to determine if a successful * trigger has occurred in the midst of probing a driver. If the trigger count @@ -200,8 +200,8 @@ return; } - pr_debug("driver: '%s': %s: bound to device '%s'\n", dev_name(dev), - __func__, dev->driver->name); + pr_debug("driver: '%s': %s: bound to device '%s'\n", dev->driver->name, + __func__, dev_name(dev)); klist_add_tail(&dev->p->knode_driver, &dev->driver->p->klist_devices); @@ -298,6 +298,20 @@ goto probe_failed; } + if (dev->pm_domain && dev->pm_domain->activate) { + ret = dev->pm_domain->activate(dev); + if (ret) + goto probe_failed; + } + + /* + * Ensure devices are listed in devices_kset in correct order + * It's important to move Dev to the end of devices_kset before + * calling .probe, because it could be recursive and parent Dev + * should always go first + */ + devices_kset_move_last(dev); + if (dev->bus->probe) { ret = dev->bus->probe(dev); if (ret) @@ -308,6 +322,11 @@ goto probe_failed; } + pinctrl_init_done(dev); + + if (dev->pm_domain && dev->pm_domain->sync) + dev->pm_domain->sync(dev); + driver_bound(dev); ret = 1; pr_debug("bus: '%s': %s: bound device %s to driver %s\n", @@ -319,22 +338,28 @@ driver_sysfs_remove(dev); dev->driver = NULL; dev_set_drvdata(dev, NULL); + if (dev->pm_domain && dev->pm_domain->dismiss) + dev->pm_domain->dismiss(dev); - if (ret == -EPROBE_DEFER) { + switch (ret) { + case -EPROBE_DEFER: /* Driver requested deferred probing */ - dev_info(dev, "Driver %s requests probe deferral\n", drv->name); + dev_dbg(dev, "Driver %s requests probe deferral\n", drv->name); driver_deferred_probe_add(dev); /* Did a trigger occur while probing? Need to re-trigger if yes */ if (local_trigger_count != atomic_read(&deferred_trigger_count)) driver_deferred_probe_trigger(); - } else if (ret != -ENODEV && ret != -ENXIO) { + break; + case -ENODEV: + case -ENXIO: + pr_debug("%s: probe of %s rejects match %d\n", + drv->name, dev_name(dev), ret); + break; + default: /* driver matched but the probe failed */ printk(KERN_WARNING "%s: probe of %s failed with error %d\n", drv->name, dev_name(dev), ret); - } else { - pr_debug("%s: probe of %s rejects match %d\n", - drv->name, dev_name(dev), ret); } /* * Ignore errors returned by ->probe so that the next driver can try @@ -384,6 +409,8 @@ * * This function must be called with @dev lock held. When called for a * USB interface, @dev->parent lock must be held as well. + * + * If the device has a parent, runtime-resume the parent before driver probing. */ int driver_probe_device(struct device_driver *drv, struct device *dev) { @@ -395,38 +422,126 @@ pr_debug("bus: '%s': %s: matched device %s with driver %s\n", drv->bus->name, __func__, dev_name(dev), drv->name); + if (dev->parent) + pm_runtime_get_sync(dev->parent); + pm_runtime_barrier(dev); ret = really_probe(dev, drv); pm_request_idle(dev); + if (dev->parent) + pm_runtime_put(dev->parent); + return ret; } -static int __device_attach(struct device_driver *drv, void *data) +bool driver_allows_async_probing(struct device_driver *drv) +{ + switch (drv->probe_type) { + case PROBE_PREFER_ASYNCHRONOUS: + return true; + + case PROBE_FORCE_SYNCHRONOUS: + return false; + + default: + if (module_requested_async_probing(drv->owner)) + return true; + + return false; + } +} + +struct device_attach_data { + struct device *dev; + + /* + * Indicates whether we are are considering asynchronous probing or + * not. Only initial binding after device or driver registration + * (including deferral processing) may be done asynchronously, the + * rest is always synchronous, as we expect it is being done by + * request from userspace. + */ + bool check_async; + + /* + * Indicates if we are binding synchronous or asynchronous drivers. + * When asynchronous probing is enabled we'll execute 2 passes + * over drivers: first pass doing synchronous probing and second + * doing asynchronous probing (if synchronous did not succeed - + * most likely because there was no driver requiring synchronous + * probing - and we found asynchronous driver during first pass). + * The 2 passes are done because we can't shoot asynchronous + * probe for given device and driver from bus_for_each_drv() since + * driver pointer is not guaranteed to stay valid once + * bus_for_each_drv() iterates to the next driver on the bus. + */ + bool want_async; + + /* + * We'll set have_async to 'true' if, while scanning for matching + * driver, we'll encounter one that requests asynchronous probing. + */ + bool have_async; +}; + +static int __device_attach_driver(struct device_driver *drv, void *_data) { - struct device *dev = data; + struct device_attach_data *data = _data; + struct device *dev = data->dev; + bool async_allowed; + + /* + * Check if device has already been claimed. This may + * happen with driver loading, device discovery/registration, + * and deferred probe processing happens all at once with + * multiple threads. + */ + if (dev->driver) + return -EBUSY; if (!driver_match_device(drv, dev)) return 0; + async_allowed = driver_allows_async_probing(drv); + + if (async_allowed) + data->have_async = true; + + if (data->check_async && async_allowed != data->want_async) + return 0; + return driver_probe_device(drv, dev); } -/** - * device_attach - try to attach device to a driver. - * @dev: device. - * - * Walk the list of drivers that the bus has and call - * driver_probe_device() for each pair. If a compatible - * pair is found, break out and return. - * - * Returns 1 if the device was bound to a driver; - * 0 if no matching driver was found; - * -ENODEV if the device is not registered. - * - * When called for a USB interface, @dev->parent lock must be held. - */ -int device_attach(struct device *dev) +static void __device_attach_async_helper(void *_dev, async_cookie_t cookie) +{ + struct device *dev = _dev; + struct device_attach_data data = { + .dev = dev, + .check_async = true, + .want_async = true, + }; + + device_lock(dev); + + if (dev->parent) + pm_runtime_get_sync(dev->parent); + + bus_for_each_drv(dev->bus, NULL, &data, __device_attach_driver); + dev_dbg(dev, "async probe completed\n"); + + pm_request_idle(dev); + + if (dev->parent) + pm_runtime_put(dev->parent); + + device_unlock(dev); + + put_device(dev); +} + +static int __device_attach(struct device *dev, bool allow_async) { int ret = 0; @@ -444,15 +559,65 @@ ret = 0; } } else { - ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach); - pm_request_idle(dev); + struct device_attach_data data = { + .dev = dev, + .check_async = allow_async, + .want_async = false, + }; + + if (dev->parent) + pm_runtime_get_sync(dev->parent); + + ret = bus_for_each_drv(dev->bus, NULL, &data, + __device_attach_driver); + if (!ret && allow_async && data.have_async) { + /* + * If we could not find appropriate driver + * synchronously and we are allowed to do + * async probes and there are drivers that + * want to probe asynchronously, we'll + * try them. + */ + dev_dbg(dev, "scheduling asynchronous probe\n"); + get_device(dev); + async_schedule(__device_attach_async_helper, dev); + } else { + pm_request_idle(dev); + } + + if (dev->parent) + pm_runtime_put(dev->parent); } out_unlock: device_unlock(dev); return ret; } + +/** + * device_attach - try to attach device to a driver. + * @dev: device. + * + * Walk the list of drivers that the bus has and call + * driver_probe_device() for each pair. If a compatible + * pair is found, break out and return. + * + * Returns 1 if the device was bound to a driver; + * 0 if no matching driver was found; + * -ENODEV if the device is not registered. + * + * When called for a USB interface, @dev->parent lock must be held. + */ +int device_attach(struct device *dev) +{ + return __device_attach(dev, false); +} EXPORT_SYMBOL_GPL(device_attach); +void device_initial_probe(struct device *dev) +{ + __device_attach(dev, true); +} + static int __driver_attach(struct device *dev, void *data) { struct device_driver *drv = data; @@ -507,6 +672,9 @@ drv = dev->driver; if (drv) { + if (driver_allows_async_probing(drv)) + async_synchronize_full(); + pm_runtime_get_sync(dev); driver_sysfs_remove(dev); @@ -525,6 +693,9 @@ devres_release_all(dev); dev->driver = NULL; dev_set_drvdata(dev, NULL); + if (dev->pm_domain && dev->pm_domain->dismiss) + dev->pm_domain->dismiss(dev); + klist_remove(&dev->p->knode_driver); if (dev->bus) blocking_notifier_call_chain(&dev->bus->p->bus_notifier, @@ -587,29 +758,3 @@ put_device(dev); } } - -/* - * These exports can't be _GPL due to .h files using this within them, and it - * might break something that was previously working... - */ -void *dev_get_drvdata(const struct device *dev) -{ - if (dev && dev->p) - return dev->p->driver_data; - return NULL; -} -EXPORT_SYMBOL(dev_get_drvdata); - -int dev_set_drvdata(struct device *dev, void *data) -{ - int error; - - if (!dev->p) { - error = device_private_init(dev); - if (error) - return error; - } - dev->p->driver_data = data; - return 0; -} -EXPORT_SYMBOL(dev_set_drvdata);