Loading Documentation/kernel-parameters.txt +3 −0 Original line number Diff line number Diff line Loading @@ -929,6 +929,9 @@ bytes respectively. Such letter suffixes can also be entirely omitted. Enable debug messages at boot time. See Documentation/dynamic-debug-howto.txt for details. module.async_probe [KNL] Enable asynchronous probe on this module. early_ioremap_debug [KNL] Enable debug messages in early_ioremap support. This is useful for tracking down temporary early mappings Loading arch/powerpc/mm/hugetlbpage.c +2 −2 Original line number Diff line number Diff line Loading @@ -333,7 +333,7 @@ int alloc_bootmem_huge_page(struct hstate *hstate) unsigned long gpage_npages[MMU_PAGE_COUNT]; static int __init do_gpage_early_setup(char *param, char *val, const char *unused) const char *unused, void *arg) { static phys_addr_t size; unsigned long npages; Loading Loading @@ -375,7 +375,7 @@ void __init reserve_hugetlb_gpages(void) strlcpy(cmdline, boot_command_line, COMMAND_LINE_SIZE); parse_args("hugetlb gpages", cmdline, NULL, 0, 0, 0, &do_gpage_early_setup); NULL, &do_gpage_early_setup); /* * Walk gpage list in reverse, allocating larger page sizes first. Loading drivers/base/base.h +1 −0 Original line number Diff line number Diff line Loading @@ -116,6 +116,7 @@ static inline int driver_match_device(struct device_driver *drv, { return drv->bus->match ? drv->bus->match(dev, drv) : 1; } extern bool driver_allows_async_probing(struct device_driver *drv); extern int driver_add_groups(struct device_driver *drv, const struct attribute_group **groups); Loading drivers/base/bus.c +23 −8 Original line number Diff line number Diff line Loading @@ -10,6 +10,7 @@ * */ #include <linux/async.h> #include <linux/device.h> #include <linux/module.h> #include <linux/errno.h> Loading Loading @@ -549,15 +550,12 @@ void bus_probe_device(struct device *dev) { struct bus_type *bus = dev->bus; struct subsys_interface *sif; int ret; if (!bus) return; if (bus->p->drivers_autoprobe) { ret = device_attach(dev); WARN_ON(ret < 0); } if (bus->p->drivers_autoprobe) device_initial_probe(dev); mutex_lock(&bus->p->mutex); list_for_each_entry(sif, &bus->p->interfaces, node) Loading Loading @@ -659,6 +657,17 @@ static ssize_t uevent_store(struct device_driver *drv, const char *buf, } static DRIVER_ATTR_WO(uevent); static void driver_attach_async(void *_drv, async_cookie_t cookie) { struct device_driver *drv = _drv; int ret; ret = driver_attach(drv); pr_debug("bus: '%s': driver %s async attach completed: %d\n", drv->bus->name, drv->name, ret); } /** * bus_add_driver - Add a driver to the bus. * @drv: driver. Loading Loading @@ -691,10 +700,16 @@ int bus_add_driver(struct device_driver *drv) klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers); if (drv->bus->p->drivers_autoprobe) { if (driver_allows_async_probing(drv)) { pr_debug("bus: '%s': probing driver %s asynchronously\n", drv->bus->name, drv->name); async_schedule(driver_attach_async, drv); } else { error = driver_attach(drv); if (error) goto out_unregister; } } module_add_driver(drv->owner, drv); error = driver_create_file(drv, &driver_attr_uevent); Loading drivers/base/dd.c +142 −19 Original line number Diff line number Diff line Loading @@ -425,31 +425,107 @@ int driver_probe_device(struct device_driver *drv, struct device *dev) return ret; } static int __device_attach(struct device_driver *drv, void *data) bool driver_allows_async_probing(struct device_driver *drv) { struct device *dev = data; 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_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); bus_for_each_drv(dev->bus, NULL, &data, __device_attach_driver); dev_dbg(dev, "async probe completed\n"); pm_request_idle(dev); device_unlock(dev); put_device(dev); } static int __device_attach(struct device *dev, bool allow_async) { int ret = 0; Loading @@ -467,15 +543,59 @@ int device_attach(struct device *dev) ret = 0; } } else { ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach); struct device_attach_data data = { .dev = dev, .check_async = allow_async, .want_async = false, }; 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); } } 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; Loading Loading @@ -530,6 +650,9 @@ static void __device_release_driver(struct device *dev) drv = dev->driver; if (drv) { if (driver_allows_async_probing(drv)) async_synchronize_full(); pm_runtime_get_sync(dev); driver_sysfs_remove(dev); Loading Loading
Documentation/kernel-parameters.txt +3 −0 Original line number Diff line number Diff line Loading @@ -929,6 +929,9 @@ bytes respectively. Such letter suffixes can also be entirely omitted. Enable debug messages at boot time. See Documentation/dynamic-debug-howto.txt for details. module.async_probe [KNL] Enable asynchronous probe on this module. early_ioremap_debug [KNL] Enable debug messages in early_ioremap support. This is useful for tracking down temporary early mappings Loading
arch/powerpc/mm/hugetlbpage.c +2 −2 Original line number Diff line number Diff line Loading @@ -333,7 +333,7 @@ int alloc_bootmem_huge_page(struct hstate *hstate) unsigned long gpage_npages[MMU_PAGE_COUNT]; static int __init do_gpage_early_setup(char *param, char *val, const char *unused) const char *unused, void *arg) { static phys_addr_t size; unsigned long npages; Loading Loading @@ -375,7 +375,7 @@ void __init reserve_hugetlb_gpages(void) strlcpy(cmdline, boot_command_line, COMMAND_LINE_SIZE); parse_args("hugetlb gpages", cmdline, NULL, 0, 0, 0, &do_gpage_early_setup); NULL, &do_gpage_early_setup); /* * Walk gpage list in reverse, allocating larger page sizes first. Loading
drivers/base/base.h +1 −0 Original line number Diff line number Diff line Loading @@ -116,6 +116,7 @@ static inline int driver_match_device(struct device_driver *drv, { return drv->bus->match ? drv->bus->match(dev, drv) : 1; } extern bool driver_allows_async_probing(struct device_driver *drv); extern int driver_add_groups(struct device_driver *drv, const struct attribute_group **groups); Loading
drivers/base/bus.c +23 −8 Original line number Diff line number Diff line Loading @@ -10,6 +10,7 @@ * */ #include <linux/async.h> #include <linux/device.h> #include <linux/module.h> #include <linux/errno.h> Loading Loading @@ -549,15 +550,12 @@ void bus_probe_device(struct device *dev) { struct bus_type *bus = dev->bus; struct subsys_interface *sif; int ret; if (!bus) return; if (bus->p->drivers_autoprobe) { ret = device_attach(dev); WARN_ON(ret < 0); } if (bus->p->drivers_autoprobe) device_initial_probe(dev); mutex_lock(&bus->p->mutex); list_for_each_entry(sif, &bus->p->interfaces, node) Loading Loading @@ -659,6 +657,17 @@ static ssize_t uevent_store(struct device_driver *drv, const char *buf, } static DRIVER_ATTR_WO(uevent); static void driver_attach_async(void *_drv, async_cookie_t cookie) { struct device_driver *drv = _drv; int ret; ret = driver_attach(drv); pr_debug("bus: '%s': driver %s async attach completed: %d\n", drv->bus->name, drv->name, ret); } /** * bus_add_driver - Add a driver to the bus. * @drv: driver. Loading Loading @@ -691,10 +700,16 @@ int bus_add_driver(struct device_driver *drv) klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers); if (drv->bus->p->drivers_autoprobe) { if (driver_allows_async_probing(drv)) { pr_debug("bus: '%s': probing driver %s asynchronously\n", drv->bus->name, drv->name); async_schedule(driver_attach_async, drv); } else { error = driver_attach(drv); if (error) goto out_unregister; } } module_add_driver(drv->owner, drv); error = driver_create_file(drv, &driver_attr_uevent); Loading
drivers/base/dd.c +142 −19 Original line number Diff line number Diff line Loading @@ -425,31 +425,107 @@ int driver_probe_device(struct device_driver *drv, struct device *dev) return ret; } static int __device_attach(struct device_driver *drv, void *data) bool driver_allows_async_probing(struct device_driver *drv) { struct device *dev = data; 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_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); bus_for_each_drv(dev->bus, NULL, &data, __device_attach_driver); dev_dbg(dev, "async probe completed\n"); pm_request_idle(dev); device_unlock(dev); put_device(dev); } static int __device_attach(struct device *dev, bool allow_async) { int ret = 0; Loading @@ -467,15 +543,59 @@ int device_attach(struct device *dev) ret = 0; } } else { ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach); struct device_attach_data data = { .dev = dev, .check_async = allow_async, .want_async = false, }; 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); } } 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; Loading Loading @@ -530,6 +650,9 @@ static void __device_release_driver(struct device *dev) drv = dev->driver; if (drv) { if (driver_allows_async_probing(drv)) async_synchronize_full(); pm_runtime_get_sync(dev); driver_sysfs_remove(dev); Loading