diff options
59 files changed, 1157 insertions, 766 deletions
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index 46b826fcb5ad..12937349d79d 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -3170,6 +3170,11 @@ This can be set from sysctl after boot. See Documentation/admin-guide/sysctl/vm.rst for details. + of_devlink [KNL] Make device links from common DT bindings. Useful + for optimizing probe order and making sure resources + aren't turned off before the consumer devices have + probed. + ohci1394_dma=early [HW] enable debugging via the ohci1394 driver. See Documentation/debugging-via-ohci1394.txt for more info. diff --git a/Documentation/driver-api/device_link.rst b/Documentation/driver-api/device_link.rst index ae1e3d0394b0..1b5020ec6517 100644 --- a/Documentation/driver-api/device_link.rst +++ b/Documentation/driver-api/device_link.rst @@ -78,8 +78,8 @@ typically deleted in its ``->remove`` callback for symmetry. That way, if the driver is compiled as a module, the device link is added on module load and orderly deleted on unload. The same restrictions that apply to device link addition (e.g. exclusion of a parallel suspend/resume transition) apply equally -to deletion. Device links with ``DL_FLAG_STATELESS`` unset (i.e. managed -device links) are deleted automatically by the driver core. +to deletion. Device links managed by the driver core are deleted automatically +by it. Several flags may be specified on device link addition, two of which have already been mentioned above: ``DL_FLAG_STATELESS`` to express that no diff --git a/drivers/amba/tegra-ahb.c b/drivers/amba/tegra-ahb.c index aa64eece77a6..57d3b2e2d007 100644 --- a/drivers/amba/tegra-ahb.c +++ b/drivers/amba/tegra-ahb.c @@ -134,22 +134,13 @@ static inline void gizmo_writel(struct tegra_ahb *ahb, u32 value, u32 offset) } #ifdef CONFIG_TEGRA_IOMMU_SMMU -static int tegra_ahb_match_by_smmu(struct device *dev, const void *data) -{ - struct tegra_ahb *ahb = dev_get_drvdata(dev); - const struct device_node *dn = data; - - return (ahb->dev->of_node == dn) ? 1 : 0; -} - int tegra_ahb_enable_smmu(struct device_node *dn) { struct device *dev; u32 val; struct tegra_ahb *ahb; - dev = driver_find_device(&tegra_ahb_driver.driver, NULL, dn, - tegra_ahb_match_by_smmu); + dev = driver_find_device_by_of_node(&tegra_ahb_driver.driver, dn); if (!dev) return -EPROBE_DEFER; ahb = dev_get_drvdata(dev); diff --git a/drivers/base/bus.c b/drivers/base/bus.c index df3cac739813..a1d1e8256324 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -342,30 +342,6 @@ struct device *bus_find_device(struct bus_type *bus, } EXPORT_SYMBOL_GPL(bus_find_device); -static int match_name(struct device *dev, const void *data) -{ - const char *name = data; - - return sysfs_streq(name, dev_name(dev)); -} - -/** - * bus_find_device_by_name - device iterator for locating a particular device of a specific name - * @bus: bus type - * @start: Device to begin with - * @name: name of the device to match - * - * This is similar to the bus_find_device() function above, but it handles - * searching by a name automatically, no need to write another strcmp matching - * function. - */ -struct device *bus_find_device_by_name(struct bus_type *bus, - struct device *start, const char *name) -{ - return bus_find_device(bus, start, (void *)name, match_name); -} -EXPORT_SYMBOL_GPL(bus_find_device_by_name); - /** * subsys_find_device_by_id - find a device with a specific enumeration number * @subsys: subsystem diff --git a/drivers/base/core.c b/drivers/base/core.c index da84a73f2ba6..5b1795cd116a 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -44,6 +44,10 @@ early_param("sysfs.deprecated", sysfs_deprecated_setup); #endif /* Device links support. */ +static LIST_HEAD(wait_for_suppliers); +static DEFINE_MUTEX(wfs_lock); +static LIST_HEAD(deferred_sync); +static unsigned int supplier_sync_state_disabled; #ifdef CONFIG_SRCU static DEFINE_MUTEX(device_links_lock); @@ -124,6 +128,50 @@ static int device_is_dependent(struct device *dev, void *target) return ret; } +static void device_link_init_status(struct device_link *link, + struct device *consumer, + struct device *supplier) +{ + switch (supplier->links.status) { + case DL_DEV_PROBING: + switch (consumer->links.status) { + case DL_DEV_PROBING: + /* + * A consumer driver can create a link to a supplier + * that has not completed its probing yet as long as it + * knows that the supplier is already functional (for + * example, it has just acquired some resources from the + * supplier). + */ + link->status = DL_STATE_CONSUMER_PROBE; + break; + default: + link->status = DL_STATE_DORMANT; + break; + } + break; + case DL_DEV_DRIVER_BOUND: + switch (consumer->links.status) { + case DL_DEV_PROBING: + link->status = DL_STATE_CONSUMER_PROBE; + break; + case DL_DEV_DRIVER_BOUND: + link->status = DL_STATE_ACTIVE; + break; + default: + link->status = DL_STATE_AVAILABLE; + break; + } + break; + case DL_DEV_UNBINDING: + link->status = DL_STATE_SUPPLIER_UNBIND; + break; + default: + link->status = DL_STATE_DORMANT; + break; + } +} + static int device_reorder_to_tail(struct device *dev, void *not_used) { struct device_link *link; @@ -165,6 +213,13 @@ void device_pm_move_to_tail(struct device *dev) device_links_read_unlock(idx); } +#define DL_MANAGED_LINK_FLAGS (DL_FLAG_AUTOREMOVE_CONSUMER | \ + DL_FLAG_AUTOREMOVE_SUPPLIER | \ + DL_FLAG_AUTOPROBE_CONSUMER) + +#define DL_ADD_VALID_FLAGS (DL_MANAGED_LINK_FLAGS | DL_FLAG_STATELESS | \ + DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE) + /** * device_link_add - Create a link between two devices. * @consumer: Consumer end of the link. @@ -179,9 +234,9 @@ void device_pm_move_to_tail(struct device *dev) * of the link. If DL_FLAG_PM_RUNTIME is not set, DL_FLAG_RPM_ACTIVE will be * ignored. * - * If DL_FLAG_STATELESS is set in @flags, the link is not going to be managed by - * the driver core and, in particular, the caller of this function is expected - * to drop the reference to the link acquired by it directly. + * If DL_FLAG_STATELESS is set in @flags, the caller of this function is + * expected to release the link returned by it directly with the help of either + * device_link_del() or device_link_remove(). * * If that flag is not set, however, the caller of this function is handing the * management of the link over to the driver core entirely and its return value @@ -201,9 +256,16 @@ void device_pm_move_to_tail(struct device *dev) * be used to request the driver core to automaticall probe for a consmer * driver after successfully binding a driver to the supplier device. * - * The combination of DL_FLAG_STATELESS and either DL_FLAG_AUTOREMOVE_CONSUMER - * or DL_FLAG_AUTOREMOVE_SUPPLIER set in @flags at the same time is invalid and - * will cause NULL to be returned upfront. + * The combination of DL_FLAG_STATELESS and one of DL_FLAG_AUTOREMOVE_CONSUMER, + * DL_FLAG_AUTOREMOVE_SUPPLIER, or DL_FLAG_AUTOPROBE_CONSUMER set in @flags at + * the same time is invalid and will cause NULL to be returned upfront. + * However, if a device link between the given @consumer and @supplier pair + * exists already when this function is called for them, the existing link will + * be returned regardless of its current type and status (the link's flags may + * be modified then). The caller of this function is then expected to treat + * the link as though it has just been created, so (in particular) if + * DL_FLAG_STATELESS was passed in @flags, the link needs to be released + * explicitly when not needed any more (as stated above). * * A side effect of the link creation is re-ordering of dpm_list and the * devices_kset list by moving the consumer device and all devices depending @@ -219,11 +281,8 @@ struct device_link *device_link_add(struct device *consumer, { struct device_link *link; - if (!consumer || !supplier || - (flags & DL_FLAG_STATELESS && - flags & (DL_FLAG_AUTOREMOVE_CONSUMER | - DL_FLAG_AUTOREMOVE_SUPPLIER | - DL_FLAG_AUTOPROBE_CONSUMER)) || + if (!consumer || !supplier || flags & ~DL_ADD_VALID_FLAGS || + (flags & DL_FLAG_STATELESS && flags & DL_MANAGED_LINK_FLAGS) || (flags & DL_FLAG_AUTOPROBE_CONSUMER && flags & (DL_FLAG_AUTOREMOVE_CONSUMER | DL_FLAG_AUTOREMOVE_SUPPLIER))) @@ -236,6 +295,9 @@ struct device_link *device_link_add(struct device *consumer, } } + if (!(flags & DL_FLAG_STATELESS)) + flags |= DL_FLAG_MANAGED; + device_links_write_lock(); device_pm_lock(); @@ -262,15 +324,6 @@ struct device_link *device_link_add(struct device *consumer, if (link->consumer != consumer) continue; - /* - * Don't return a stateless link if the caller wants a stateful - * one and vice versa. - */ - if (WARN_ON((flags & DL_FLAG_STATELESS) != (link->flags & DL_FLAG_STATELESS))) { - link = NULL; - goto out; - } - if (flags & DL_FLAG_PM_RUNTIME) { if (!(link->flags & DL_FLAG_PM_RUNTIME)) { pm_runtime_new_link(consumer); @@ -281,6 +334,7 @@ struct device_link *device_link_add(struct device *consumer, } if (flags & DL_FLAG_STATELESS) { + link->flags |= DL_FLAG_STATELESS; kref_get(&link->kref); goto out; } @@ -299,6 +353,11 @@ struct device_link *device_link_add(struct device *consumer, link->flags &= ~(DL_FLAG_AUTOREMOVE_CONSUMER | DL_FLAG_AUTOREMOVE_SUPPLIER); } + if (!(link->flags & DL_FLAG_MANAGED)) { + kref_get(&link->kref); + link->flags |= DL_FLAG_MANAGED; + device_link_init_status(link, consumer, supplier); + } goto out; } @@ -325,48 +384,10 @@ struct device_link *device_link_add(struct device *consumer, kref_init(&link->kref); /* Determine the initial link state. */ - if (flags & DL_FLAG_STATELESS) { + if (flags & DL_FLAG_STATELESS) link->status = DL_STATE_NONE; - } else { - switch (supplier->links.status) { - case DL_DEV_PROBING: - switch (consumer->links.status) { - case DL_DEV_PROBING: - /* - * A consumer driver can create a link to a - * supplier that has not completed its probing - * yet as long as it knows that the supplier is - * already functional (for example, it has just - * acquired some resources from the supplier). - */ - link->status = DL_STATE_CONSUMER_PROBE; - break; - default: - link->status = DL_STATE_DORMANT; - break; - } - break; - case DL_DEV_DRIVER_BOUND: - switch (consumer->links.status) { - case DL_DEV_PROBING: - link->status = DL_STATE_CONSUMER_PROBE; - break; - case DL_DEV_DRIVER_BOUND: - link->status = DL_STATE_ACTIVE; - break; - default: - link->status = DL_STATE_AVAILABLE; - break; - } - break; - case DL_DEV_UNBINDING: - link->status = DL_STATE_SUPPLIER_UNBIND; - break; - default: - link->status = DL_STATE_DORMANT; - break; - } - } + else + device_link_init_status(link, consumer, supplier); /* * Some callers expect the link creation during consumer driver probe to @@ -401,6 +422,71 @@ struct device_link *device_link_add(struct device *consumer, } EXPORT_SYMBOL_GPL(device_link_add); +/** + * device_link_wait_for_supplier - Mark device as waiting for supplier + * @consumer: Consumer device + * + * Marks the consumer device as waiting for suppliers to become available. The + * consumer device will never be probed until it's unmarked as waiting for + * suppliers. The caller is responsible for adding the link to the supplier + * once the supplier device is present. + * + * This function is NOT meant to be called from the probe function of the + * consumer but rather from code that creates/adds the consumer device. + */ +static void device_link_wait_for_supplier(struct device *consumer) +{ + mutex_lock(&wfs_lock); + list_add_tail(&consumer->links.needs_suppliers, &wait_for_suppliers); + mutex_unlock(&wfs_lock); +} + +/** + * device_link_remove_from_wfs - Unmark device as waiting for supplier + * @consumer: Consumer device + * + * Unmark the consumer device as waiting for suppliers to become available. + */ +void device_link_remove_from_wfs(struct device *consumer) +{ + mutex_lock(&wfs_lock); + list_del_init(&consumer->links.needs_suppliers); + mutex_unlock(&wfs_lock); +} + +/** + * device_link_check_waiting_consumers - Try to unmark waiting consumers + * + * Loops through all consumers waiting on suppliers and tries to add all their + * supplier links. If that succeeds, the consumer device is unmarked as waiting + * for suppliers. Otherwise, they are left marked as waiting on suppliers, + * + * The add_links bus callback is expected to return 0 if it has found and added + * all the supplier links for the consumer device. It should return an error if + * it isn't able to do so. + * + * The caller of device_link_wait_for_supplier() is expected to call this once + * it's aware of potential suppliers becoming available. + */ +static void device_link_check_waiting_consumers(void) +{ + struct device *dev, *tmp; + int ret; + + mutex_lock(&wfs_lock); + list_for_each_entry_safe(dev, tmp, &wait_for_suppliers, + links.needs_suppliers) { + ret = 0; + if (dev->has_edit_links) + ret = driver_edit_links(dev); + else if (dev->bus->add_links) + ret = dev->bus->add_links(dev); + if (!ret) + list_del_init(&dev->links.needs_suppliers); + } + mutex_unlock(&wfs_lock); +} + static void device_link_free(struct device_link *link) { while (refcount_dec_not_one(&link->rpm_active)) @@ -528,17 +614,30 @@ static void device_links_missing_supplier(struct device *dev) * mark the link as "consumer probe in progress" to make the supplier removal * wait for us to complete (or bad things may happen). * - * Links with the DL_FLAG_STATELESS flag set are ignored. + * Links without the DL_FLAG_MANAGED flag set are ignored. */ int device_links_check_suppliers(struct device *dev) { struct device_link *link; int ret = 0; + /* + * If a device is waiting for one or more suppliers (in + * wait_for_suppliers list), it is not ready to probe yet. So just + * return -EPROBE_DEFER without having to check the links with existing + * suppliers. + */ + mutex_lock(&wfs_lock); + if (!list_empty(&dev->links.needs_suppliers)) { + mutex_unlock(&wfs_lock); + return -EPROBE_DEFER; + } + mutex_unlock(&wfs_lock); + device_links_write_lock(); list_for_each_entry(link, &dev->links.suppliers, c_node) { - if (link->flags & DL_FLAG_STATELESS) + if (!(link->flags & DL_FLAG_MANAGED)) continue; if (link->status != DL_STATE_AVAILABLE) { @@ -554,6 +653,62 @@ int device_links_check_suppliers(struct device *dev) return ret; } +static void __device_links_supplier_sync_state(struct device *dev) +{ + struct device_link *link; + + if (dev->state_synced) + return; + + list_for_each_entry(link, &dev->links.consumers, s_node) { + if (!(link->flags & DL_FLAG_MANAGED)) + continue; + if (link->status != DL_STATE_ACTIVE) + return; + } + + if (dev->bus->sync_state) + dev->bus->sync_state(dev); + else if (dev->driver && dev->driver->sync_state) + dev->driver->sync_state(dev); + + dev->state_synced = true; +} + +void device_links_supplier_sync_state_pause(void) +{ + device_links_write_lock(); + supplier_sync_state_disabled++; + device_links_write_unlock(); +} + +void device_links_supplier_sync_state_resume(void) +{ + struct device *dev, *tmp; + + device_links_write_lock(); + if (!supplier_sync_state_disabled) { + WARN(true, "Unmatched sync_state pause/resume!"); + goto out; + } + supplier_sync_state_disabled--; + if (supplier_sync_state_disabled) + goto out; + + list_for_each_entry_safe(dev, tmp, &deferred_sync, links.defer_sync) { + __device_links_supplier_sync_state(dev); + list_del_init(&dev->links.defer_sync); + } +out: + device_links_write_unlock(); +} + +static void __device_links_supplier_defer_sync(struct device *sup) +{ + if (list_empty(&sup->links.defer_sync)) + list_add_tail(&sup->links.defer_sync, &deferred_sync); +} + /** * device_links_driver_bound - Update device links after probing its driver. * @dev: Device to update the links for. @@ -563,7 +718,7 @@ int device_links_check_suppliers(struct device *dev) * * Also change the status of @dev's links to suppliers to "active". * - * Links with the DL_FLAG_STATELESS flag set are ignored. + * Links without the DL_FLAG_MANAGED flag set are ignored. */ void device_links_driver_bound(struct device *dev) { @@ -572,7 +727,7 @@ void device_links_driver_bound(struct device *dev) device_links_write_lock(); list_for_each_entry(link, &dev->links.consumers, s_node) { - if (link->flags & DL_FLAG_STATELESS) + if (!(link->flags & DL_FLAG_MANAGED)) continue; /* @@ -593,11 +748,16 @@ void device_links_driver_bound(struct device *dev) } list_for_each_entry(link, &dev->links.suppliers, c_node) { - if (link->flags & DL_FLAG_STATELESS) + if (!(link->flags & DL_FLAG_MANAGED)) continue; WARN_ON(link->status != DL_STATE_CONSUMER_PROBE); WRITE_ONCE(link->status, DL_STATE_ACTIVE); + + if (supplier_sync_state_disabled) + __device_links_supplier_defer_sync(link->supplier); + else + __device_links_supplier_sync_state(link->supplier); } dev->links.status = DL_DEV_DRIVER_BOUND; @@ -605,6 +765,13 @@ void device_links_driver_bound(struct device *dev) device_links_write_unlock(); } +static void device_link_drop_managed(struct device_link *link) +{ + link->flags &= ~DL_FLAG_MANAGED; + WRITE_ONCE(link->status, DL_STATE_NONE); + kref_put(&link->kref, __device_link_del); +} + /** * __device_links_no_driver - Update links of a device without a driver. * @dev: Device without a drvier. @@ -615,18 +782,18 @@ void device_links_driver_bound(struct device *dev) * unless they already are in the "supplier unbind in progress" state in which * case they need not be updated. * - * Links with the DL_FLAG_STATELESS flag set are ignored. + * Links without the DL_FLAG_MANAGED flag set are ignored. */ static void __device_links_no_driver(struct device *dev) { struct device_link *link, *ln; list_for_each_entry_safe_reverse(link, ln, &dev->links.suppliers, c_node) { - if (link->flags & DL_FLAG_STATELESS) + if (!(link->flags & DL_FLAG_MANAGED)) continue; if (link->flags & DL_FLAG_AUTOREMOVE_CONSUMER) - __device_link_del(&link->kref); + device_link_drop_managed(link); else if (link->status == DL_STATE_CONSUMER_PROBE || link->status == DL_STATE_ACTIVE) WRITE_ONCE(link->status, DL_STATE_AVAILABLE); @@ -643,7 +810,7 @@ static void __device_links_no_driver(struct device *dev) * %__device_links_no_driver() to update links to suppliers for it as * appropriate. * - * Links with the DL_FLAG_STATELESS flag set are ignored. + * Links without the DL_FLAG_MANAGED flag set are ignored. */ void device_links_no_driver(struct device *dev) { @@ -652,7 +819,7 @@ void device_links_no_driver(struct device *dev) device_links_write_lock(); list_for_each_entry(link, &dev->links.consumers, s_node) { - if (link->flags & DL_FLAG_STATELESS) + if (!(link->flags & DL_FLAG_MANAGED)) continue; /* @@ -680,7 +847,7 @@ void device_links_no_driver(struct device *dev) * invoke %__device_links_no_driver() to update links to suppliers for it as * appropriate. * - * Links with the DL_FLAG_STATELESS flag set are ignored. + * Links without the DL_FLAG_MANAGED flag set are ignored. */ void device_links_driver_cleanup(struct device *dev) { @@ -689,7 +856,7 @@ void device_links_driver_cleanup(struct device *dev) device_links_write_lock(); list_for_each_entry_safe(link, ln, &dev->links.consumers, s_node) { - if (link->flags & DL_FLAG_STATELESS) + if (!(link->flags & DL_FLAG_MANAGED)) continue; WARN_ON(link->flags & DL_FLAG_AUTOREMOVE_CONSUMER); @@ -702,11 +869,12 @@ void device_links_driver_cleanup(struct device *dev) */ if (link->status == DL_STATE_SUPPLIER_UNBIND && link->flags & DL_FLAG_AUTOREMOVE_SUPPLIER) - __device_link_del(&link->kref); + device_link_drop_managed(link); WRITE_ONCE(link->status, DL_STATE_DORMANT); } + list_del_init(&dev->links.defer_sync); __device_links_no_driver(dev); device_links_write_unlock(); @@ -724,7 +892,7 @@ void device_links_driver_cleanup(struct device *dev) * * Return 'false' if there are no probing or active consumers. * - * Links with the DL_FLAG_STATELESS flag set are ignored. + * Links without the DL_FLAG_MANAGED flag set are ignored. */ bool device_links_busy(struct device *dev) { @@ -734,7 +902,7 @@ bool device_links_busy(struct device *dev) device_links_write_lock(); list_for_each_entry(link, &dev->links.consumers, s_node) { - if (link->flags & DL_FLAG_STATELESS) + if (!(link->flags & DL_FLAG_MANAGED)) continue; if (link->status == DL_STATE_CONSUMER_PROBE @@ -764,7 +932,7 @@ bool device_links_busy(struct device *dev) * driver to unbind and start over (the consumer will not re-probe as we have * changed the state of the link already). * - * Links with the DL_FLAG_STATELESS flag set are ignored. + * Links without the DL_FLAG_MANAGED flag set are ignored. */ void device_links_unbind_consumers(struct device *dev) { @@ -776,7 +944,7 @@ void device_links_unbind_consumers(struct device *dev) list_for_each_entry(link, &dev->links.consumers, s_node) { enum device_link_state status; - if (link->flags & DL_FLAG_STATELESS) + if (!(link->flags & DL_FLAG_MANAGED)) continue; status = link->status; @@ -812,6 +980,10 @@ static void device_links_purge(struct device *dev) { struct device_link *link, *ln; + mutex_lock(&wfs_lock); + list_del(&dev->links.needs_suppliers); + mutex_unlock(&wfs_lock); + /* * Delete all of the remaining links from this device to any other * devices (either consumers or suppliers). @@ -1673,6 +1845,8 @@ void device_initialize(struct device *dev) #endif INIT_LIST_HEAD(&dev->links.consumers); INIT_LIST_HEAD(&dev->links.suppliers); + INIT_LIST_HEAD(&dev->links.needs_suppliers); + INIT_LIST_HEAD(&dev->links.defer_sync); dev->links.status = DL_DEV_NO_DRIVER; } EXPORT_SYMBOL_GPL(device_initialize); @@ -2108,6 +2282,24 @@ int device_add(struct device *dev) BUS_NOTIFY_ADD_DEVICE, dev); kobject_uevent(&dev->kobj, KOBJ_ADD); + + /* + * Check if any of the other devices (consumers) have been waiting for + * this device (supplier) to be added so that they can create a device + * link to it. + * + * This needs to happen after device_pm_add() because device_link_add() + * requires the supplier be registered before it's called. + * + * But this also needs to happe before bus_probe_device() to make sure + * waiting consumers can link to it before the driver is bound to the + * device and the driver sync_state callback is called for this device. + */ + device_link_check_waiting_consumers(); + + if (dev->bus && dev->bus->add_links && dev->bus->add_links(dev)) + device_link_wait_for_supplier(dev); + bus_probe_device(dev); if (parent) klist_add_tail(&dev->p->knode_parent, @@ -2867,13 +3059,6 @@ struct device *device_create_with_groups(struct class *class, } EXPORT_SYMBOL_GPL(device_create_with_groups); -static int __match_devt(struct device *dev, const void *data) -{ - const dev_t *devt = data; - - return dev->devt == *devt; -} - /** * device_destroy - removes a device that was created with device_create() * @class: pointer to the struct class that this device was registered with @@ -2886,7 +3071,7 @@ void device_destroy(struct class *class, dev_t devt) { struct device *dev; - dev = class_find_device(class, NULL, &devt, __match_devt); + dev = class_find_device_by_devt(class, devt); if (dev) { put_device(dev); device_unregister(dev); @@ -3357,8 +3542,38 @@ void device_set_of_node_from_dev(struct device *dev, const struct device *dev2) } EXPORT_SYMBOL_GPL(device_set_of_node_from_dev); +int device_match_name(struct device *dev, const void *name) +{ + return sysfs_streq(dev_name(dev), name); +} +EXPORT_SYMBOL_GPL(device_match_name); + int device_match_of_node(struct device *dev, const void *np) { return dev->of_node == np; } EXPORT_SYMBOL_GPL(device_match_of_node); + +int device_match_fwnode(struct device *dev, const void *fwnode) +{ + return dev_fwnode(dev) == fwnode; +} +EXPORT_SYMBOL_GPL(device_match_fwnode); + +int device_match_devt(struct device *dev, const void *pdevt) +{ + return dev->devt == *(dev_t *)pdevt; +} +EXPORT_SYMBOL_GPL(device_match_devt); + +int device_match_acpi_dev(struct device *dev, const void *adev) +{ + return ACPI_COMPANION(dev) == adev; +} +EXPORT_SYMBOL(device_match_acpi_dev); + +int device_match_any(struct device *dev, const void *unused) +{ + return 1; +} +EXPORT_SYMBOL_GPL(device_match_any); diff --git a/drivers/base/dd.c b/drivers/base/dd.c index d811e60610d3..55fbc2467b37 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -710,6 +710,12 @@ int driver_probe_device(struct device_driver *drv, struct device *dev) pr_debug("bus: '%s': %s: matched device %s with driver %s\n", drv->bus->name, __func__, dev_name(dev), drv->name); + if (drv->edit_links) { + if (drv->edit_links(dev)) + dev->has_edit_links = true; + else + device_link_remove_from_wfs(dev); + } pm_runtime_get_suppliers(dev); if (dev->parent) pm_runtime_get_sync(dev->parent); @@ -798,6 +804,29 @@ struct device_attach_data { bool have_async; }; +static int __driver_edit_links(struct device_driver *drv, void *data) +{ + struct device *dev = data; + + if (!drv->edit_links) + return 0; + + if (driver_match_device(drv, dev) <= 0) + return 0; + + return drv->edit_links(dev); +} + +int driver_edit_links(struct device *dev) +{ + int ret; + + device_lock(dev); + ret = bus_for_each_drv(dev->bus, NULL, dev, __driver_edit_links); + device_unlock(dev); + return ret; +} + static int __device_attach_driver(struct device_driver *drv, void *_data) { struct device_attach_data *data = _data; diff --git a/drivers/base/devcon.c b/drivers/base/devcon.c index 09f28479b243..1d488dc5dd0c 100644 --- a/drivers/base/devcon.c +++ b/drivers/base/devcon.c @@ -133,19 +133,13 @@ static struct bus_type *generic_match_buses[] = { NULL, }; -static int device_fwnode_match(struct device *dev, const void *fwnode) -{ - return dev_fwnode(dev) == fwnode; -} - static void *device_connection_fwnode_match(struct device_connection *con) { struct bus_type *bus; struct device *dev; for (bus = generic_match_buses[0]; bus; bus++) { - dev = bus_find_device(bus, NULL, (void *)con->fwnode, - device_fwnode_match); + dev = bus_find_device_by_fwnode(bus, con->fwnode); if (dev && !strncmp(dev_name(dev), con->id, strlen(con->id))) return dev; diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 506a0175a5a7..9426736551b5 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -99,12 +99,7 @@ void __iomem *devm_platform_ioremap_resource(struct platform_device *pdev, EXPORT_SYMBOL_GPL(devm_platform_ioremap_resource); #endif /* CONFIG_HAS_IOMEM */ -/** - * platform_get_irq - get an IRQ for a device - * @dev: platform device - * @num: IRQ number index - */ -int platform_get_irq(struct platform_device *dev, unsigned int num) +static int __platform_get_irq(struct platform_device *dev, unsigned int num) { #ifdef CONFIG_SPARC /* sparc does not have irqs represented as IORESOURCE_IRQ resources */ @@ -163,6 +158,33 @@ int platform_get_irq(struct platform_device *dev, unsigned int num) return -ENXIO; #endif } + +/** + * platform_get_irq - get an IRQ for a device + * @dev: platform device + * @num: IRQ number index + * + * Gets an IRQ for a platform device and prints an error message if finding the + * IRQ fails. Device drivers should check the return value for errors so as to + * not pass a negative integer value to the request_irq() APIs. + * + * Example: + * int irq = platform_get_irq(pdev, 0); + * if (irq < 0) + * return irq; + * + * Return: IRQ number on success, negative error number on failure. + */ +int platform_get_irq(struct platform_device *dev, unsigned int num) +{ + int ret; + + ret = __platform_get_irq(dev, num); + if (ret < 0 && ret != -EPROBE_DEFER) + dev_err(&dev->dev, "IRQ index %u not found\n", num); + + return ret; +} EXPORT_SYMBOL_GPL(platform_get_irq); /** @@ -175,7 +197,7 @@ int platform_irq_count(struct platform_device *dev) { int ret, nr = 0; - while ((ret = platform_get_irq(dev, nr)) >= 0) + while ((ret = __platform_get_irq(dev, nr)) >= 0) nr++; if (ret == -EPROBE_DEFER) @@ -228,7 +250,11 @@ int platform_get_irq_byname(struct platform_device *dev, const char *name) } r = platform_get_resource_byname(dev, IORESOURCE_IRQ, name); - return r ? r->start : -ENXIO; + if (r) + return r->start; + + dev_err(&dev->dev, "IRQ %s not found\n", name); + return -ENXIO; } EXPORT_SYMBOL_GPL(platform_get_irq_byname); @@ -1197,6 +1223,20 @@ struct bus_type platform_bus_type = { }; EXPORT_SYMBOL_GPL(platform_bus_type); +/** + * platform_find_device_by_driver - Find a platform device with a given + * driver. + * @start: The device to start the search from. + * @drv: The device driver to look for. + */ +struct device *platform_find_device_by_driver(struct device *start, + const struct device_driver *drv) +{ + return bus_find_device(&platform_bus_type, start, drv, + (void *)platform_match); +} +EXPORT_SYMBOL_GPL(platform_find_device_by_driver); + int __init platform_bus_init(void) { int error; diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index b75335508d2c..45a8fbe6987a 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c @@ -1624,7 +1624,7 @@ void pm_runtime_remove(struct device *dev) * runtime PM references to the device, drop the usage counter of the device * (as many times as needed). * - * Links with the DL_FLAG_STATELESS flag set are ignored. + * Links with the DL_FLAG_MANAGED flag unset are ignored. * * Since the device is guaranteed to be runtime-active at the point this is * called, nothing else needs to be done here. @@ -1641,7 +1641,7 @@ void pm_runtime_clean_up_links(struct device *dev) idx = device_links_read_lock(); list_for_each_entry_rcu(link, &dev->links.consumers, s_node) { - if (link->flags & DL_FLAG_STATELESS) + if (!(link->flags & DL_FLAG_MANAGED)) continue; while (refcount_dec_not_one(&link->rpm_active)) diff --git a/drivers/fpga/fpga-bridge.c b/drivers/fpga/fpga-bridge.c index 80bd8f1b2aa6..4bab9028940a 100644 --- a/drivers/fpga/fpga-bridge.c +++ b/drivers/fpga/fpga-bridge.c @@ -19,11 +19,6 @@ static struct class *fpga_bridge_class; /* Lock for adding/removing bridges to linked lists*/ static spinlock_t bridge_list_lock; -static int fpga_bridge_of_node_match(struct device *dev, const void *data) -{ - return dev->of_node == data; -} - /** * fpga_bridge_enable - Enable transactions on the bridge * @@ -104,8 +99,7 @@ struct fpga_bridge *of_fpga_bridge_get(struct device_node *np, { struct device *dev; - dev = class_find_device(fpga_bridge_class, NULL, np, - fpga_bridge_of_node_match); + dev = class_find_device_by_of_node(fpga_bridge_class, np); if (!dev) return ERR_PTR(-ENODEV); diff --git a/drivers/fpga/fpga-mgr.c b/drivers/fpga/fpga-mgr.c index c3866816456a..e05104f5e40c 100644 --- a/drivers/fpga/fpga-mgr.c +++ b/drivers/fpga/fpga-mgr.c @@ -482,11 +482,6 @@ struct fpga_manager *fpga_mgr_get(struct device *dev) } EXPORT_SYMBOL_GPL(fpga_mgr_get); -static int fpga_mgr_of_node_match(struct device *dev, const void *data) -{ - return dev->of_node == data; -} - /** * of_fpga_mgr_get - Given a device node, get a reference to a fpga mgr. * @@ -498,8 +493,7 @@ struct fpga_manager *of_fpga_mgr_get(struct device_node *node) { struct device *dev; - dev = class_find_device(fpga_mgr_class, NULL, node, - fpga_mgr_of_node_match); + dev = class_find_device_by_of_node(fpga_mgr_class, node); if (!dev) return ERR_PTR(-ENODEV); diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c index ad19df0686c9..bd2498bbd74a 100644 --- a/drivers/gpu/drm/drm_mipi_dsi.c +++ b/drivers/gpu/drm/drm_mipi_dsi.c @@ -93,11 +93,6 @@ static struct bus_type mipi_dsi_bus_type = { .pm = &mipi_dsi_device_pm_ops, }; -static int of_device_match(struct device *dev, const void *data) -{ - return dev->of_node == data; -} - /** * of_find_mipi_dsi_device_by_node() - find the MIPI DSI device matching a * device tree node @@ -110,7 +105,7 @@ struct mipi_dsi_device *of_find_mipi_dsi_device_by_node(struct device_node *np) { struct device *dev; - dev = bus_find_device(&mipi_dsi_bus_type, NULL, np, of_device_match); + dev = bus_find_device_by_of_node(&mipi_dsi_bus_type, np); return dev ? to_mipi_dsi_device(dev) : NULL; } diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index 58baf49d9926..badab94be2d6 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c @@ -242,9 +242,7 @@ static struct component_match *exynos_drm_match_add(struct device *dev) if (!info->driver || !(info->flags & DRM_COMPONENT_DRIVER)) continue; - while ((d = bus_find_device(&platform_bus_type, p, - &info->driver->driver, - (void *)platform_bus_type.match))) { + while ((d = platform_find_device_by_driver(p, &info->driver->driver))) { put_device(p); if (!(info->flags & DRM_FIMC_DEVICE) || @@ -412,9 +410,8 @@ static void exynos_drm_unregister_devices(void) if (!info->driver || !(info->flags & DRM_VIRTUAL_DEVICE)) continue; - while ((dev = bus_find_device(&platform_bus_type, NULL, - &info->driver->driver, - (void *)platform_bus_type.match))) { + while ((dev = platform_find_device_by_driver(NULL, + &info->driver->driver))) { put_device(dev); platform_device_unregister(to_platform_device(dev)); } diff --git a/drivers/gpu/drm/mcde/mcde_drv.c b/drivers/gpu/drm/mcde/mcde_drv.c index baf63fb6850a..c07abf9e201c 100644 --- a/drivers/gpu/drm/mcde/mcde_drv.c +++ b/drivers/gpu/drm/mcde/mcde_drv.c @@ -477,8 +477,7 @@ static int mcde_probe(struct platform_device *pdev) struct device_driver *drv = &mcde_component_drivers[i]->driver; struct device *p = NULL, *d; - while ((d = bus_find_device(&platform_bus_type, p, drv, - (void *)platform_bus_type.match))) { + while ((d = platform_find_device_by_driver(p, drv))) { put_device(p); component_match_add(dev, &match, mcde_compare_dev, d); p = d; diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c index 53d2c5bd61dc..38dc26376961 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c @@ -330,8 +330,7 @@ static struct component_match *rockchip_drm_match_add(struct device *dev) struct device *p = NULL, *d; do { - d = bus_find_device(&platform_bus_type, p, &drv->driver, - (void *)platform_bus_type.match); + d = platform_find_device_by_driver(p, &drv->driver); put_device(p); p = d; diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c index bf11930e40e1..1551c8253bec 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.c +++ b/drivers/gpu/drm/vc4/vc4_drv.c @@ -237,8 +237,7 @@ static void vc4_match_add_drivers(struct device *dev, struct device_driver *drv = &drivers[i]->driver; struct device *p = NULL, *d; - while ((d = bus_find_device(&platform_bus_type, p, drv, - (void *)platform_bus_type.match))) { + while ((d = platform_find_device_by_driver(p, drv))) { put_device(p); component_match_add(dev, match, compare_dev, d); p = d; diff --git a/drivers/hwtracing/coresight/coresight-platform.c b/drivers/hwtracing/coresight/coresight-platform.c index dad7d96c5943..3c5bee429105 100644 --- a/drivers/hwtracing/coresight/coresight-platform.c +++ b/drivers/hwtracing/coresight/coresight-platform.c @@ -37,11 +37,6 @@ static int coresight_alloc_conns(struct device *dev, return 0; } -int coresight_device_fwnode_match(struct device *dev, const void *fwnode) -{ - return dev_fwnode(dev) == fwnode; -} - static struct device * coresight_find_device_by_fwnode(struct fwnode_handle *fwnode) { @@ -51,8 +46,7 @@ coresight_find_device_by_fwnode(struct fwnode_handle *fwnode) * If we have a non-configurable replicator, it will be found on the * platform bus. */ - dev = bus_find_device(&platform_bus_type, NULL, - fwnode, coresight_device_fwnode_match); + dev = bus_find_device_by_fwnode(&platform_bus_type, fwnode); if (dev) return dev; @@ -60,8 +54,7 @@ coresight_find_device_by_fwnode(struct fwnode_handle *fwnode) * We have a configurable component - circle through the AMBA bus * looking for the device that matches the endpoint node. */ - return bus_find_device(&amba_bustype, NULL, - fwnode, coresight_device_fwnode_match); + return bus_find_device_by_fwnode(&amba_bustype, fwnode); } #ifdef CONFIG_OF diff --git a/drivers/hwtracing/coresight/coresight-priv.h b/drivers/hwtracing/coresight/coresight-priv.h index 7d401790dd7e..61d7f9ff054d 100644 --- a/drivers/hwtracing/coresight/coresight-priv.h +++ b/drivers/hwtracing/coresight/coresight-priv.h @@ -202,6 +202,4 @@ static inline void *coresight_get_uci_data(const struct amba_id *id) void coresight_release_platform_data(struct coresight_platform_data *pdata); -int coresight_device_fwnode_match(struct device *dev, const void *fwnode); - #endif diff --git a/drivers/hwtracing/coresight/coresight.c b/drivers/hwtracing/coresight/coresight.c index 55db77f6410b..6453c67a4d01 100644 --- a/drivers/hwtracing/coresight/coresight.c +++ b/drivers/hwtracing/coresight/coresight.c @@ -1046,9 +1046,7 @@ static void coresight_fixup_device_conns(struct coresight_device *csdev) struct coresight_connection *conn = &csdev->pdata->conns[i]; struct device *dev = NULL; - dev = bus_find_device(&coresight_bustype, NULL, - (void *)conn->child_fwnode, - coresight_device_fwnode_match); + dev = bus_find_device_by_fwnode(&coresight_bustype, conn->child_fwnode); if (dev) { conn->child_dev = to_coresight_device(dev); /* and put reference from 'bus_find_device()' */ diff --git a/drivers/hwtracing/intel_th/core.c b/drivers/hwtracing/intel_th/core.c index 55922896d862..d5c1821b31c6 100644 --- a/drivers/hwtracing/intel_th/core.c +++ b/drivers/hwtracing/intel_th/core.c @@ -789,12 +789,6 @@ static int intel_th_populate(struct intel_th *th) return 0; } -static int match_devt(struct device *dev, const void *data) -{ - dev_t devt = (dev_t)(unsigned long)(void *)data; - return dev->devt == devt; -} - static int intel_th_output_open(struct inode *inode, struct file *file) { const struct file_operations *fops; @@ -802,9 +796,7 @@ static int intel_th_output_open(struct inode *inode, struct file *file) struct device *dev; int err; - dev = bus_find_device(&intel_th_bus, NULL, - (void *)(unsigned long)inode->i_rdev, - match_devt); + dev = bus_find_device_by_devt(&intel_th_bus, inode->i_rdev); if (!dev || !dev->driver) return -ENODEV; diff --git a/drivers/hwtracing/stm/core.c b/drivers/hwtracing/stm/core.c index e55b902560de..2b6bd42632e8 100644 --- a/drivers/hwtracing/stm/core.c +++ b/drivers/hwtracing/stm/core.c @@ -89,13 +89,6 @@ static struct class stm_class = { .dev_groups = stm_groups, }; -static int stm_dev_match(struct device *dev, const void *data) -{ - const char *name = data; - - return sysfs_streq(name, dev_name(dev)); -} - /** * stm_find_device() - find stm device by name * @buf: character buffer containing the name @@ -116,7 +109,7 @@ struct stm_device *stm_find_device(const char *buf) if (!stm_core_up) return NULL; - dev = class_find_device(&stm_class, NULL, buf, stm_dev_match); + dev = class_find_device_by_name(&stm_class, buf); if (!dev) return NULL; diff --git a/drivers/i2c/busses/i2c-amd-mp2-pci.c b/drivers/i2c/busses/i2c-amd-mp2-pci.c index c7fe3b44a860..5e4800d72e00 100644 --- a/drivers/i2c/busses/i2c-amd-mp2-pci.c +++ b/drivers/i2c/busses/i2c-amd-mp2-pci.c @@ -457,18 +457,12 @@ static struct pci_driver amd_mp2_pci_driver = { }; module_pci_driver(amd_mp2_pci_driver); -static int amd_mp2_device_match(struct device *dev, const void *data) -{ - return 1; -} - struct amd_mp2_dev *amd_mp2_find_device(void) { struct device *dev; struct pci_dev *pci_dev; - dev = driver_find_device(&amd_mp2_pci_driver.driver, NULL, NULL, - amd_mp2_device_match); + dev = driver_find_next_device(&amd_mp2_pci_driver.driver, NULL); if (!dev) return NULL; diff --git a/drivers/i2c/i2c-core-acpi.c b/drivers/i2c/i2c-core-acpi.c index 4dbbc9a35f65..f60f7a95d48e 100644 --- a/drivers/i2c/i2c-core-acpi.c +++ b/drivers/i2c/i2c-core-acpi.c @@ -354,10 +354,6 @@ static int i2c_acpi_find_match_adapter(struct device *dev, const void *data) return ACPI_HANDLE(dev) == (acpi_handle)data; } -static int i2c_acpi_find_match_device(struct device *dev, const void *data) -{ - return ACPI_COMPANION(dev) == data; -} struct i2c_adapter *i2c_acpi_find_adapter_by_handle(acpi_handle handle) { @@ -365,6 +361,7 @@ struct i2c_adapter *i2c_acpi_find_adapter_by_handle(acpi_handle handle) dev = bus_find_device(&i2c_bus_type, NULL, handle, i2c_acpi_find_match_adapter); + return dev ? i2c_verify_adapter(dev) : NULL; } EXPORT_SYMBOL_GPL(i2c_acpi_find_adapter_by_handle); @@ -373,8 +370,7 @@ static struct i2c_client *i2c_acpi_find_client_by_adev(struct acpi_device *adev) { struct device *dev; - dev = bus_find_device(&i2c_bus_type, NULL, adev, - i2c_acpi_find_match_device); + dev = bus_find_device_by_acpi_dev(&i2c_bus_type, adev); return dev ? i2c_verify_client(dev) : NULL; } diff --git a/drivers/i2c/i2c-core-of.c b/drivers/i2c/i2c-core-of.c index d1c48dec7118..6f632d543fcc 100644 --- a/drivers/i2c/i2c-core-of.c +++ b/drivers/i2c/i2c-core-of.c @@ -113,11 +113,6 @@ void of_i2c_register_devices(struct i2c_adapter *adap) of_node_put(bus); } -static int of_dev_node_match(struct device *dev, const void *data) -{ - return dev->of_node == data; -} - static int of_dev_or_parent_node_match(struct device *dev, const void *data) { if (dev->of_node == data) @@ -135,7 +130,7 @@ struct i2c_client *of_find_i2c_device_by_node(struct device_node *node) struct device *dev; struct i2c_client *client; - dev = bus_find_device(&i2c_bus_type, NULL, node, of_dev_node_match); + dev = bus_find_device_by_of_node(&i2c_bus_type, node); if (!dev) return NULL; diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v1.c b/drivers/infiniband/hw/hns/hns_roce_hw_v1.c index 81e6dedb1e02..fa05e943038a 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v1.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v1.c @@ -4499,19 +4499,13 @@ static const struct acpi_device_id hns_roce_acpi_match[] = { }; MODULE_DEVICE_TABLE(acpi, hns_roce_acpi_match); -static int hns_roce_node_match(struct device *dev, const void *fwnode) -{ - return dev->fwnode == fwnode; -} - static struct platform_device *hns_roce_find_pdev(struct fwnode_handle *fwnode) { struct device *dev; /* get the 'device' corresponding to the matching 'fwnode' */ - dev = bus_find_device(&platform_bus_type, NULL, - fwnode, hns_roce_node_match); + dev = bus_find_device_by_fwnode(&platform_bus_type, fwnode); /* get the platform device */ return dev ? to_platform_device(dev) : NULL; } diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c index a9a9fabd3968..6f0e13fa5e1a 100644 --- a/drivers/iommu/arm-smmu-v3.c +++ b/drivers/iommu/arm-smmu-v3.c @@ -2034,16 +2034,11 @@ arm_smmu_iova_to_phys(struct iommu_domain *domain, dma_addr_t iova) static struct platform_driver arm_smmu_driver; -static int arm_smmu_match_node(struct device *dev, const void *data) -{ - return dev->fwnode == data; -} - static struct arm_smmu_device *arm_smmu_get_by_fwnode(struct fwnode_handle *fwnode) { - struct device *dev = driver_find_device(&arm_smmu_driver.driver, NULL, - fwnode, arm_smmu_match_node); + struct device *dev = driver_find_device_by_fwnode(&arm_smmu_driver.driver, + fwnode); put_device(dev); return dev ? dev_get_drvdata(dev) : NULL; } diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index 64977c131ee6..aa06498f291d 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -1426,16 +1426,11 @@ static bool arm_smmu_capable(enum iommu_cap cap) } } -static int arm_smmu_match_node(struct device *dev, const void *data) -{ - return dev->fwnode == data; -} - static struct arm_smmu_device *arm_smmu_get_by_fwnode(struct fwnode_handle *fwnode) { - struct device *dev = driver_find_device(&arm_smmu_driver.driver, NULL, - fwnode, arm_smmu_match_node); + struct device *dev = driver_find_device_by_fwnode(&arm_smmu_driver.driver, + fwnode); put_device(dev); return dev ? dev_get_drvdata(dev) : NULL; } diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c index 4793e77808e2..d54c8e4d8954 100644 --- a/drivers/leds/led-class.c +++ b/drivers/leds/led-class.c @@ -213,13 +213,6 @@ static int led_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(leds_class_dev_pm_ops, led_suspend, led_resume); -static int match_name(struct device *dev, const void *data) -{ - if (!dev_name(dev)) - return 0; - return !strcmp(dev_name(dev), (char *)data); -} - static int led_classdev_next_name(const char *init_name, char *name, size_t len) { @@ -230,7 +223,7 @@ static int led_classdev_next_name(const char *init_name, char *name, strlcpy(name, init_name, len); while ((ret < len) && - (dev = class_find_device(leds_class, NULL, name, match_name))) { + (dev = class_find_device_by_name(leds_class, name))) { put_device(dev); ret = snprintf(name, len, "%s_%u", init_name, ++i); } diff --git a/drivers/mfd/aat2870-core.c b/drivers/mfd/aat2870-core.c index 9f58cb2d3789..78ee4b28fca2 100644 --- a/drivers/mfd/aat2870-core.c +++ b/drivers/mfd/aat2870-core.c @@ -321,18 +321,9 @@ static const struct file_operations aat2870_reg_fops = { static void aat2870_init_debugfs(struct aat2870_data *aat2870) { aat2870->dentry_root = debugfs_create_dir("aat2870", NULL); - if (!aat2870->dentry_root) { - dev_warn(aat2870->dev, - "Failed to create debugfs root directory\n"); - return; - } - aat2870->dentry_reg = debugfs_create_file("regs", 0644, - aat2870->dentry_root, - aat2870, &aat2870_reg_fops); - if (!aat2870->dentry_reg) - dev_warn(aat2870->dev, - "Failed to create debugfs register file\n"); + debugfs_create_file("regs", 0644, aat2870->dentry_root, aat2870, + &aat2870_reg_fops); } #else diff --git a/drivers/mfd/ab3100-core.c b/drivers/mfd/ab3100-core.c index e350ab64238e..9f3dbc31d3e9 100644 --- a/drivers/mfd/ab3100-core.c +++ b/drivers/mfd/ab3100-core.c @@ -575,58 +575,27 @@ static const struct file_operations ab3100_get_set_reg_fops = { .llseek = noop_llseek, }; -static struct dentry *ab3100_dir; -static struct dentry *ab3100_reg_file; static struct ab3100_get_set_reg_priv ab3100_get_priv; -static struct dentry *ab3100_get_reg_file; static struct ab3100_get_set_reg_priv ab3100_set_priv; -static struct dentry *ab3100_set_reg_file; static void ab3100_setup_debugfs(struct ab3100 *ab3100) { - int err; + struct dentry *ab3100_dir; ab3100_dir = debugfs_create_dir("ab3100", NULL); - if (!ab3100_dir) - goto exit_no_debugfs; - ab3100_reg_file = debugfs_create_file("registers", - S_IRUGO, ab3100_dir, ab3100, - &ab3100_registers_fops); - if (!ab3100_reg_file) { - err = -ENOMEM; - goto exit_destroy_dir; - } + debugfs_create_file("registers", S_IRUGO, ab3100_dir, ab3100, + &ab3100_registers_fops); ab3100_get_priv.ab3100 = ab3100; ab3100_get_priv.mode = false; - ab3100_get_reg_file = debugfs_create_file("get_reg", - S_IWUSR, ab3100_dir, &ab3100_get_priv, - &ab3100_get_set_reg_fops); - if (!ab3100_get_reg_file) { - err = -ENOMEM; - goto exit_destroy_reg; - } + debugfs_create_file("get_reg", S_IWUSR, ab3100_dir, &ab3100_get_priv, + &ab3100_get_set_reg_fops); ab3100_set_priv.ab3100 = ab3100; ab3100_set_priv.mode = true; - ab3100_set_reg_file = debugfs_create_file("set_reg", - S_IWUSR, ab3100_dir, &ab3100_set_priv, - &ab3100_get_set_reg_fops); - if (!ab3100_set_reg_file) { - err = -ENOMEM; - goto exit_destroy_get_reg; - } - return; - - exit_destroy_get_reg: - debugfs_remove(ab3100_get_reg_file); - exit_destroy_reg: - debugfs_remove(ab3100_reg_file); - exit_destroy_dir: - debugfs_remove(ab3100_dir); - exit_no_debugfs: - return; + debugfs_create_file("set_reg", S_IWUSR, ab3100_dir, &ab3100_set_priv, + &ab3100_get_set_reg_fops); } #else static inline void ab3100_setup_debugfs(struct ab3100 *ab3100) diff --git a/drivers/mfd/ab3100-otp.c b/drivers/mfd/ab3100-otp.c index b3f8d359f409..c4751fb9bc22 100644 --- a/drivers/mfd/ab3100-otp.c +++ b/drivers/mfd/ab3100-otp.c @@ -122,17 +122,11 @@ static const struct file_operations ab3100_otp_operations = { .release = single_release, }; -static int __init ab3100_otp_init_debugfs(struct device *dev, - struct ab3100_otp *otp) +static void __init ab3100_otp_init_debugfs(struct device *dev, + struct ab3100_otp *otp) { otp->debugfs = debugfs_create_file("ab3100_otp", S_IFREG | S_IRUGO, - NULL, otp, - &ab3100_otp_operations); - if (!otp->debugfs) { - dev_err(dev, "AB3100 debugfs OTP file registration failed!\n"); - return -ENOENT; - } - return 0; + NULL, otp, &ab3100_otp_operations); } static void __exit ab3100_otp_exit_debugfs(struct ab3100_otp *otp) @@ -141,10 +135,9 @@ static void __exit ab3100_otp_exit_debugfs(struct ab3100_otp *otp) } #else /* Compile this out if debugfs not selected */ -static inline int __init ab3100_otp_init_debugfs(struct device *dev, - struct ab3100_otp *otp) +static inline void __init ab3100_otp_init_debugfs(struct device *dev, + struct ab3100_otp *otp) { - return 0; } static inline void __exit ab3100_otp_exit_debugfs(struct ab3100_otp *otp) @@ -211,9 +204,7 @@ static int __init ab3100_otp_probe(struct platform_device *pdev) } /* debugfs entries */ - err = ab3100_otp_init_debugfs(&pdev->dev, otp); - if (err) - goto err; + ab3100_otp_init_debugfs(&pdev->dev, otp); return 0; diff --git a/drivers/mfd/ab8500-debugfs.c b/drivers/mfd/ab8500-debugfs.c index d24c6ecccb88..567a34b073dd 100644 --- a/drivers/mfd/ab8500-debugfs.c +++ b/drivers/mfd/ab8500-debugfs.c @@ -2644,12 +2644,10 @@ static const struct file_operations ab8500_hwreg_fops = { .owner = THIS_MODULE, }; -static struct dentry *ab8500_dir; -static struct dentry *ab8500_gpadc_dir; - static int ab8500_debug_probe(struct platform_device *plf) { - struct dentry *file; + struct dentry *ab8500_dir; + struct dentry *ab8500_gpadc_dir; struct ab8500 *ab8500; struct resource *res; @@ -2694,47 +2692,22 @@ static int ab8500_debug_probe(struct platform_device *plf) } ab8500_dir = debugfs_create_dir(AB8500_NAME_STRING, NULL); - if (!ab8500_dir) - goto err; ab8500_gpadc_dir = debugfs_create_dir(AB8500_ADC_NAME_STRING, ab8500_dir); - if (!ab8500_gpadc_dir) - goto err; - - file = debugfs_create_file("all-bank-registers", S_IRUGO, ab8500_dir, - &plf->dev, &ab8500_bank_registers_fops); - if (!file) - goto err; - - file = debugfs_create_file("all-banks", S_IRUGO, ab8500_dir, - &plf->dev, &ab8500_all_banks_fops); - if (!file) - goto err; - - file = debugfs_create_file("register-bank", - (S_IRUGO | S_IWUSR | S_IWGRP), - ab8500_dir, &plf->dev, &ab8500_bank_fops); - if (!file) - goto err; - - file = debugfs_create_file("register-address", - (S_IRUGO | S_IWUSR | S_IWGRP), - ab8500_dir, &plf->dev, &ab8500_address_fops); - if (!file) - goto err; - - file = debugfs_create_file("register-value", - (S_IRUGO | S_IWUSR | S_IWGRP), - ab8500_dir, &plf->dev, &ab8500_val_fops); - if (!file) - goto err; - - file = debugfs_create_file("irq-subscribe", - (S_IRUGO | S_IWUSR | S_IWGRP), ab8500_dir, - &plf->dev, &ab8500_subscribe_fops); - if (!file) - goto err; + + debugfs_create_file("all-bank-registers", S_IRUGO, ab8500_dir, + &plf->dev, &ab8500_bank_registers_fops); + debugfs_create_file("all-banks", S_IRUGO, ab8500_dir, + &plf->dev, &ab8500_all_banks_fops); + debugfs_create_file("register-bank", (S_IRUGO | S_IWUSR | S_IWGRP), + ab8500_dir, &plf->dev, &ab8500_bank_fops); + debugfs_create_file("register-address", (S_IRUGO | S_IWUSR | S_IWGRP), + ab8500_dir, &plf->dev, &ab8500_address_fops); + debugfs_create_file("register-value", (S_IRUGO | S_IWUSR | S_IWGRP), + ab8500_dir, &plf->dev, &ab8500_val_fops); + debugfs_create_file("irq-subscribe", (S_IRUGO | S_IWUSR | S_IWGRP), + ab8500_dir, &plf->dev, &ab8500_subscribe_fops); if (is_ab8500(ab8500)) { debug_ranges = ab8500_debug_ranges; @@ -2750,194 +2723,93 @@ static int ab8500_debug_probe(struct platform_device *plf) num_interrupt_lines = AB8540_NR_IRQS; } - file = debugfs_create_file("interrupts", (S_IRUGO), ab8500_dir, - &plf->dev, &ab8500_interrupts_fops); - if (!file) - goto err; - - file = debugfs_create_file("irq-unsubscribe", - (S_IRUGO | S_IWUSR | S_IWGRP), ab8500_dir, - &plf->dev, &ab8500_unsubscribe_fops); - if (!file) - goto err; - - file = debugfs_create_file("hwreg", (S_IRUGO | S_IWUSR | S_IWGRP), - ab8500_dir, &plf->dev, &ab8500_hwreg_fops); - if (!file) - goto err; - - file = debugfs_create_file("all-modem-registers", - (S_IRUGO | S_IWUSR | S_IWGRP), - ab8500_dir, &plf->dev, &ab8500_modem_fops); - if (!file) - goto err; - - file = debugfs_create_file("bat_ctrl", (S_IRUGO | S_IWUSR | S_IWGRP), - ab8500_gpadc_dir, &plf->dev, - &ab8500_gpadc_bat_ctrl_fops); - if (!file) - goto err; - - file = debugfs_create_file("btemp_ball", (S_IRUGO | S_IWUSR | S_IWGRP), - ab8500_gpadc_dir, - &plf->dev, &ab8500_gpadc_btemp_ball_fops); - if (!file) - goto err; - - file = debugfs_create_file("main_charger_v", - (S_IRUGO | S_IWUSR | S_IWGRP), - ab8500_gpadc_dir, &plf->dev, - &ab8500_gpadc_main_charger_v_fops); - if (!file) - goto err; - - file = debugfs_create_file("acc_detect1", - (S_IRUGO | S_IWUSR | S_IWGRP), - ab8500_gpadc_dir, &plf->dev, - &ab8500_gpadc_acc_detect1_fops); - if (!file) - goto err; - - file = debugfs_create_file("acc_detect2", - (S_IRUGO | S_IWUSR | S_IWGRP), - ab8500_gpadc_dir, &plf->dev, - &ab8500_gpadc_acc_detect2_fops); - if (!file) - goto err; - - file = debugfs_create_file("adc_aux1", (S_IRUGO | S_IWUSR | S_IWGRP), - ab8500_gpadc_dir, &plf->dev, - &ab8500_gpadc_aux1_fops); - if (!file) - goto err; - - file = debugfs_create_file("adc_aux2", (S_IRUGO | S_IWUSR | S_IWGRP), - ab8500_gpadc_dir, &plf->dev, - &ab8500_gpadc_aux2_fops); - if (!file) - goto err; - - file = debugfs_create_file("main_bat_v", (S_IRUGO | S_IWUSR | S_IWGRP), - ab8500_gpadc_dir, &plf->dev, - &ab8500_gpadc_main_bat_v_fops); - if (!file) - goto err; - - file = debugfs_create_file("vbus_v", (S_IRUGO | S_IWUSR | S_IWGRP), - ab8500_gpadc_dir, &plf->dev, - &ab8500_gpadc_vbus_v_fops); - if (!file) - goto err; - - file = debugfs_create_file("main_charger_c", - (S_IRUGO | S_IWUSR | S_IWGRP), - ab8500_gpadc_dir, &plf->dev, - &ab8500_gpadc_main_charger_c_fops); - if (!file) - goto err; - - file = debugfs_create_file("usb_charger_c", - (S_IRUGO | S_IWUSR | S_IWGRP), - ab8500_gpadc_dir, - &plf->dev, &ab8500_gpadc_usb_charger_c_fops); - if (!file) - goto err; - - file = debugfs_create_file("bk_bat_v", (S_IRUGO | S_IWUSR | S_IWGRP), - ab8500_gpadc_dir, &plf->dev, - &ab8500_gpadc_bk_bat_v_fops); - if (!file) - goto err; - - file = debugfs_create_file("die_temp", (S_IRUGO | S_IWUSR | S_IWGRP), - ab8500_gpadc_dir, &plf->dev, - &ab8500_gpadc_die_temp_fops); - if (!file) - goto err; - - file = debugfs_create_file("usb_id", (S_IRUGO | S_IWUSR | S_IWGRP), - ab8500_gpadc_dir, &plf->dev, - &ab8500_gpadc_usb_id_fops); - if (!file) - goto err; - + debugfs_create_file("interrupts", (S_IRUGO), ab8500_dir, &plf->dev, + &ab8500_interrupts_fops); + debugfs_create_file("irq-unsubscribe", (S_IRUGO | S_IWUSR | S_IWGRP), + ab8500_dir, &plf->dev, &ab8500_unsubscribe_fops); + debugfs_create_file("hwreg", (S_IRUGO | S_IWUSR | S_IWGRP), ab8500_dir, + &plf->dev, &ab8500_hwreg_fops); + debugfs_create_file("all-modem-registers", (S_IRUGO | S_IWUSR | S_IWGRP), + ab8500_dir, &plf->dev, &ab8500_modem_fops); + debugfs_create_file("bat_ctrl", (S_IRUGO | S_IWUSR | S_IWGRP), + ab8500_gpadc_dir, &plf->dev, + &ab8500_gpadc_bat_ctrl_fops); + debugfs_create_file("btemp_ball", (S_IRUGO | S_IWUSR | S_IWGRP), + ab8500_gpadc_dir, &plf->dev, + &ab8500_gpadc_btemp_ball_fops); + debugfs_create_file("main_charger_v", (S_IRUGO | S_IWUSR | S_IWGRP), + ab8500_gpadc_dir, &plf->dev, + &ab8500_gpadc_main_charger_v_fops); + debugfs_create_file("acc_detect1", (S_IRUGO | S_IWUSR | S_IWGRP), + ab8500_gpadc_dir, &plf->dev, + &ab8500_gpadc_acc_detect1_fops); + debugfs_create_file("acc_detect2", (S_IRUGO | S_IWUSR | S_IWGRP), + ab8500_gpadc_dir, &plf->dev, + &ab8500_gpadc_acc_detect2_fops); + debugfs_create_file("adc_aux1", (S_IRUGO | S_IWUSR | S_IWGRP), + ab8500_gpadc_dir, &plf->dev, + &ab8500_gpadc_aux1_fops); + debugfs_create_file("adc_aux2", (S_IRUGO | S_IWUSR | S_IWGRP), + ab8500_gpadc_dir, &plf->dev, + &ab8500_gpadc_aux2_fops); + debugfs_create_file("main_bat_v", (S_IRUGO | S_IWUSR | S_IWGRP), + ab8500_gpadc_dir, &plf->dev, + &ab8500_gpadc_main_bat_v_fops); + debugfs_create_file("vbus_v", (S_IRUGO | S_IWUSR | S_IWGRP), + ab8500_gpadc_dir, &plf->dev, + &ab8500_gpadc_vbus_v_fops); + debugfs_create_file("main_charger_c", (S_IRUGO | S_IWUSR | S_IWGRP), + ab8500_gpadc_dir, &plf->dev, + &ab8500_gpadc_main_charger_c_fops); + debugfs_create_file("usb_charger_c", (S_IRUGO | S_IWUSR | S_IWGRP), + ab8500_gpadc_dir, &plf->dev, + &ab8500_gpadc_usb_charger_c_fops); + debugfs_create_file("bk_bat_v", (S_IRUGO | S_IWUSR | S_IWGRP), + ab8500_gpadc_dir, &plf->dev, + &ab8500_gpadc_bk_bat_v_fops); + debugfs_create_file("die_temp", (S_IRUGO | S_IWUSR | S_IWGRP), + ab8500_gpadc_dir, &plf->dev, + &ab8500_gpadc_die_temp_fops); + debugfs_create_file("usb_id", (S_IRUGO | S_IWUSR | S_IWGRP), + ab8500_gpadc_dir, &plf->dev, + &ab8500_gpadc_usb_id_fops); if (is_ab8540(ab8500)) { - file = debugfs_create_file("xtal_temp", - (S_IRUGO | S_IWUSR | S_IWGRP), - ab8500_gpadc_dir, &plf->dev, - &ab8540_gpadc_xtal_temp_fops); - if (!file) - goto err; - file = debugfs_create_file("vbattruemeas", - (S_IRUGO | S_IWUSR | S_IWGRP), - ab8500_gpadc_dir, &plf->dev, - &ab8540_gpadc_vbat_true_meas_fops); - if (!file) - goto err; - file = debugfs_create_file("batctrl_and_ibat", - (S_IRUGO | S_IWUGO), - ab8500_gpadc_dir, - &plf->dev, - &ab8540_gpadc_bat_ctrl_and_ibat_fops); - if (!file) - goto err; - file = debugfs_create_file("vbatmeas_and_ibat", - (S_IRUGO | S_IWUGO), - ab8500_gpadc_dir, &plf->dev, - &ab8540_gpadc_vbat_meas_and_ibat_fops); - if (!file) - goto err; - file = debugfs_create_file("vbattruemeas_and_ibat", - (S_IRUGO | S_IWUGO), - ab8500_gpadc_dir, - &plf->dev, - &ab8540_gpadc_vbat_true_meas_and_ibat_fops); - if (!file) - goto err; - file = debugfs_create_file("battemp_and_ibat", - (S_IRUGO | S_IWUGO), - ab8500_gpadc_dir, - &plf->dev, &ab8540_gpadc_bat_temp_and_ibat_fops); - if (!file) - goto err; - file = debugfs_create_file("otp_calib", - (S_IRUGO | S_IWUSR | S_IWGRP), - ab8500_gpadc_dir, - &plf->dev, &ab8540_gpadc_otp_calib_fops); - if (!file) - goto err; + debugfs_create_file("xtal_temp", (S_IRUGO | S_IWUSR | S_IWGRP), + ab8500_gpadc_dir, &plf->dev, + &ab8540_gpadc_xtal_temp_fops); + debugfs_create_file("vbattruemeas", (S_IRUGO | S_IWUSR | S_IWGRP), + ab8500_gpadc_dir, &plf->dev, + &ab8540_gpadc_vbat_true_meas_fops); + debugfs_create_file("batctrl_and_ibat", (S_IRUGO | S_IWUGO), + ab8500_gpadc_dir, &plf->dev, + &ab8540_gpadc_bat_ctrl_and_ibat_fops); + debugfs_create_file("vbatmeas_and_ibat", (S_IRUGO | S_IWUGO), + ab8500_gpadc_dir, &plf->dev, + &ab8540_gpadc_vbat_meas_and_ibat_fops); + debugfs_create_file("vbattruemeas_and_ibat", (S_IRUGO | S_IWUGO), + ab8500_gpadc_dir, &plf->dev, + &ab8540_gpadc_vbat_true_meas_and_ibat_fops); + debugfs_create_file("battemp_and_ibat", (S_IRUGO | S_IWUGO), + ab8500_gpadc_dir, &plf->dev, + &ab8540_gpadc_bat_temp_and_ibat_fops); + debugfs_create_file("otp_calib", (S_IRUGO | S_IWUSR | S_IWGRP), + ab8500_gpadc_dir, &plf->dev, + &ab8540_gpadc_otp_calib_fops); } - file = debugfs_create_file("avg_sample", (S_IRUGO | S_IWUSR | S_IWGRP), - ab8500_gpadc_dir, &plf->dev, - &ab8500_gpadc_avg_sample_fops); - if (!file) - goto err; - - file = debugfs_create_file("trig_edge", (S_IRUGO | S_IWUSR | S_IWGRP), - ab8500_gpadc_dir, &plf->dev, - &ab8500_gpadc_trig_edge_fops); - if (!file) - goto err; - - file = debugfs_create_file("trig_timer", (S_IRUGO | S_IWUSR | S_IWGRP), - ab8500_gpadc_dir, &plf->dev, - &ab8500_gpadc_trig_timer_fops); - if (!file) - goto err; - - file = debugfs_create_file("conv_type", (S_IRUGO | S_IWUSR | S_IWGRP), - ab8500_gpadc_dir, &plf->dev, - &ab8500_gpadc_conv_type_fops); - if (!file) - goto err; + debugfs_create_file("avg_sample", (S_IRUGO | S_IWUSR | S_IWGRP), + ab8500_gpadc_dir, &plf->dev, + &ab8500_gpadc_avg_sample_fops); + debugfs_create_file("trig_edge", (S_IRUGO | S_IWUSR | S_IWGRP), + ab8500_gpadc_dir, &plf->dev, + &ab8500_gpadc_trig_edge_fops); + debugfs_create_file("trig_timer", (S_IRUGO | S_IWUSR | S_IWGRP), + ab8500_gpadc_dir, &plf->dev, + &ab8500_gpadc_trig_timer_fops); + debugfs_create_file("conv_type", (S_IRUGO | S_IWUSR | S_IWGRP), + ab8500_gpadc_dir, &plf->dev, + &ab8500_gpadc_conv_type_fops); return 0; - -err: - debugfs_remove_recursive(ab8500_dir); - dev_err(&plf->dev, "failed to create debugfs entries.\n"); - - return -ENOMEM; } static struct platform_driver ab8500_debug_driver = { diff --git a/drivers/mfd/altera-sysmgr.c b/drivers/mfd/altera-sysmgr.c index 2ee14d8a6d31..d2a13a547a3c 100644 --- a/drivers/mfd/altera-sysmgr.c +++ b/drivers/mfd/altera-sysmgr.c @@ -88,16 +88,6 @@ static struct regmap_config altr_sysmgr_regmap_cfg = { }; /** - * sysmgr_match_phandle - * Matching function used by driver_find_device(). - * Return: True if match is found, otherwise false. - */ -static int sysmgr_match_phandle(struct device *dev, const void *data) -{ - return dev->of_node == (const struct device_node *)data; -} - -/** * altr_sysmgr_regmap_lookup_by_phandle * Find the sysmgr previous configured in probe() and return regmap property. * Return: regmap if found or error if not found. @@ -117,8 +107,8 @@ struct regmap *altr_sysmgr_regmap_lookup_by_phandle(struct device_node *np, if (!sysmgr_np) return ERR_PTR(-ENODEV); - dev = driver_find_device(&altr_sysmgr_driver.driver, NULL, - (void *)sysmgr_np, sysmgr_match_phandle); + dev = driver_find_device_by_of_node(&altr_sysmgr_driver.driver, + (void *)sysmgr_np); of_node_put(sysmgr_np); if (!dev) return ERR_PTR(-EPROBE_DEFER); diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c index f894d1f8a53e..7310b476323c 100644 --- a/drivers/misc/mei/main.c +++ b/drivers/misc/mei/main.c @@ -858,13 +858,6 @@ static ssize_t dev_state_show(struct device *device, } static DEVICE_ATTR_RO(dev_state); -static int match_devt(struct device *dev, const void *data) -{ - const dev_t *devt = data; - - return dev->devt == *devt; -} - /** * dev_set_devstate: set to new device state and notify sysfs file. * @@ -880,7 +873,7 @@ void mei_set_devstate(struct mei_device *dev, enum mei_dev_state state) dev->dev_state = state; - clsdev = class_find_device(mei_class, NULL, &dev->cdev.dev, match_devt); + clsdev = class_find_device_by_devt(mei_class, dev->cdev.dev); if (clsdev) { sysfs_notify(&clsdev->kobj, NULL, "dev_state"); put_device(clsdev); diff --git a/drivers/mux/core.c b/drivers/mux/core.c index d1271c1ee23c..1fb22388e7e0 100644 --- a/drivers/mux/core.c +++ b/drivers/mux/core.c @@ -405,17 +405,12 @@ int mux_control_deselect(struct mux_control *mux) } EXPORT_SYMBOL_GPL(mux_control_deselect); -static int of_dev_node_match(struct device *dev, const void *data) -{ - return dev->of_node == data; -} - /* Note this function returns a reference to the mux_chip dev. */ static struct mux_chip *of_find_mux_chip_by_node(struct device_node *np) { struct device *dev; - dev = class_find_device(&mux_class, NULL, np, of_dev_node_match); + dev = class_find_device_by_of_node(&mux_class, np); return dev ? to_mux_chip(dev) : NULL; } diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.c index bb6586d0e5af..ed3829ae4ef1 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.c @@ -754,17 +754,11 @@ struct dsaf_misc_op *hns_misc_op_get(struct dsaf_device *dsaf_dev) return (void *)misc_op; } -static int hns_dsaf_dev_match(struct device *dev, const void *fwnode) -{ - return dev->fwnode == fwnode; -} - struct platform_device *hns_dsaf_find_platform_device(struct fwnode_handle *fwnode) { struct device *dev; - dev = bus_find_device(&platform_bus_type, NULL, - fwnode, hns_dsaf_dev_match); + dev = bus_find_device_by_fwnode(&platform_bus_type, fwnode); return dev ? to_platform_device(dev) : NULL; } diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c index bd04fe762056..ce940871331e 100644 --- a/drivers/net/phy/mdio_bus.c +++ b/drivers/net/phy/mdio_bus.c @@ -262,11 +262,6 @@ static struct class mdio_bus_class = { }; #if IS_ENABLED(CONFIG_OF_MDIO) -/* Helper function for of_mdio_find_bus */ -static int of_mdio_bus_match(struct device *dev, const void *mdio_bus_np) -{ - return dev->of_node == mdio_bus_np; -} /** * of_mdio_find_bus - Given an mii_bus node, find the mii_bus. * @mdio_bus_np: Pointer to the mii_bus. @@ -287,9 +282,7 @@ struct mii_bus *of_mdio_find_bus(struct device_node *mdio_bus_np) if (!mdio_bus_np) return NULL; - d = class_find_device(&mdio_bus_class, NULL, mdio_bus_np, - of_mdio_bus_match); - + d = class_find_device_by_of_node(&mdio_bus_class, mdio_bus_np); return d ? to_mii_bus(d) : NULL; } EXPORT_SYMBOL(of_mdio_find_bus); diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c index ac5d945be88a..057d1ff87d5d 100644 --- a/drivers/nvmem/core.c +++ b/drivers/nvmem/core.c @@ -76,11 +76,6 @@ static struct bus_type nvmem_bus_type = { .name = "nvmem", }; -static int of_nvmem_match(struct device *dev, const void *nvmem_np) -{ - return dev->of_node == nvmem_np; -} - static struct nvmem_device *of_nvmem_find(struct device_node *nvmem_np) { struct device *d; @@ -88,7 +83,7 @@ static struct nvmem_device *of_nvmem_find(struct device_node *nvmem_np) if (!nvmem_np) return NULL; - d = bus_find_device(&nvmem_bus_type, NULL, nvmem_np, of_nvmem_match); + d = bus_find_device_by_of_node(&nvmem_bus_type, nvmem_np); if (!d) return NULL; diff --git a/drivers/of/of_mdio.c b/drivers/of/of_mdio.c index 44f53496cab1..000b95787df1 100644 --- a/drivers/of/of_mdio.c +++ b/drivers/of/of_mdio.c @@ -280,12 +280,6 @@ unregister: } EXPORT_SYMBOL(of_mdiobus_register); -/* Helper function for of_phy_find_device */ -static int of_phy_match(struct device *dev, const void *phy_np) -{ - return dev->of_node == phy_np; -} - /** * of_phy_find_device - Give a PHY node, find the phy_device * @phy_np: Pointer to the phy's device tree node @@ -301,7 +295,7 @@ struct phy_device *of_phy_find_device(struct device_node *phy_np) if (!phy_np) return NULL; - d = bus_find_device(&mdio_bus_type, NULL, phy_np, of_phy_match); + d = bus_find_device_by_of_node(&mdio_bus_type, phy_np); if (d) { mdiodev = to_mdio_device(d); if (mdiodev->flags & MDIO_DEVICE_FLAG_PHY) diff --git a/drivers/of/platform.c b/drivers/of/platform.c index 7801e25e6895..21838226d68a 100644 --- a/drivers/of/platform.c +++ b/drivers/of/platform.c @@ -37,11 +37,6 @@ static const struct of_device_id of_skipped_node_table[] = { {} /* Empty terminated list */ }; -static int of_dev_node_match(struct device *dev, const void *data) -{ - return dev->of_node == data; -} - /** * of_find_device_by_node - Find the platform_device associated with a node * @np: Pointer to device tree node @@ -55,7 +50,7 @@ struct platform_device *of_find_device_by_node(struct device_node *np) { struct device *dev; - dev = bus_find_device(&platform_bus_type, NULL, np, of_dev_node_match); + dev = bus_find_device_by_of_node(&platform_bus_type, np); return dev ? to_platform_device(dev) : NULL; } EXPORT_SYMBOL(of_find_device_by_node); @@ -485,6 +480,7 @@ int of_platform_populate(struct device_node *root, pr_debug("%s()\n", __func__); pr_debug(" starting at: %pOF\n", root); + device_links_supplier_sync_state_pause(); for_each_child_of_node(root, child) { rc = of_platform_bus_create(child, matches, lookup, parent, true); if (rc) { @@ -492,6 +488,8 @@ int of_platform_populate(struct device_node *root, break; } } + device_links_supplier_sync_state_resume(); + of_node_set_flag(root, OF_POPULATED_BUS); of_node_put(root); @@ -508,6 +506,183 @@ int of_platform_default_populate(struct device_node *root, } EXPORT_SYMBOL_GPL(of_platform_default_populate); +bool of_link_is_valid(struct device_node *con, struct device_node *sup) +{ + of_node_get(sup); + /* + * Don't allow linking a device node as a consumer of one of its + * descendant nodes. By definition, a child node can't be a functional + * dependency for the parent node. + */ + while (sup) { + if (sup == con) { + of_node_put(sup); + return false; + } + sup = of_get_next_parent(sup); + } + return true; +} + +static int of_link_to_phandle(struct device *dev, struct device_node *sup_np) +{ + struct platform_device *sup_dev; + u32 dl_flags = DL_FLAG_AUTOPROBE_CONSUMER; + int ret = 0; + + /* + * Since we are trying to create device links, we need to find + * the actual device node that owns this supplier phandle. + * Often times it's the same node, but sometimes it can be one + * of the parents. So walk up the parent till you find a + * device. + */ + while (sup_np && !of_find_property(sup_np, "compatible", NULL)) + sup_np = of_get_next_parent(sup_np); + if (!sup_np) + return 0; + + if (!of_link_is_valid(dev->of_node, sup_np)) { + of_node_put(sup_np); + return 0; + } + sup_dev = of_find_device_by_node(sup_np); + of_node_put(sup_np); + if (!sup_dev) + return -ENODEV; + if (!device_link_add(dev, &sup_dev->dev, dl_flags)) + ret = -ENODEV; + put_device(&sup_dev->dev); + return ret; +} + +static struct device_node *parse_prop_cells(struct device_node *np, + const char *prop, int index, + const char *binding, + const char *cell) +{ + struct of_phandle_args sup_args; + + /* Don't need to check property name for every index. */ + if (!index && strcmp(prop, binding)) + return NULL; + + if (of_parse_phandle_with_args(np, binding, cell, index, &sup_args)) + return NULL; + + return sup_args.np; +} + +static struct device_node *parse_clocks(struct device_node *np, + const char *prop, int index) +{ + return parse_prop_cells(np, prop, index, "clocks", "#clock-cells"); +} + +static struct device_node *parse_interconnects(struct device_node *np, + const char *prop, int index) +{ + return parse_prop_cells(np, prop, index, "interconnects", + "#interconnect-cells"); +} + +static int strcmp_suffix(const char *str, const char *suffix) +{ + unsigned int len, suffix_len; + + len = strlen(str); + suffix_len = strlen(suffix); + if (len <= suffix_len) + return -1; + return strcmp(str + len - suffix_len, suffix); +} + +static struct device_node *parse_regulators(struct device_node *np, + const char *prop, int index) +{ + if (index || strcmp_suffix(prop, "-supply")) + return NULL; + + return of_parse_phandle(np, prop, 0); +} + +/** + * struct supplier_bindings - Information for parsing supplier DT binding + * + * @parse_prop: If the function cannot parse the property, return NULL. + * Otherwise, return the phandle listed in the property + * that corresponds to the index. + */ +struct supplier_bindings { + struct device_node *(*parse_prop)(struct device_node *np, + const char *name, int index); +}; + +static const struct supplier_bindings bindings[] = { + { .parse_prop = parse_clocks, }, + { .parse_prop = parse_interconnects, }, + { .parse_prop = parse_regulators, }, + { }, +}; + +static bool of_link_property(struct device *dev, struct device_node *con_np, + const char *prop) +{ + struct device_node *phandle; + const struct supplier_bindings *s = bindings; + unsigned int i = 0; + bool done = true, matched = false; + + while (!matched && s->parse_prop) { + while ((phandle = s->parse_prop(con_np, prop, i))) { + matched = true; + i++; + if (of_link_to_phandle(dev, phandle)) + /* + * Don't stop at the first failure. See + * Documentation for bus_type.add_links for + * more details. + */ + done = false; + } + s++; + } + return done ? 0 : -ENODEV; +} + +static int __of_link_to_suppliers(struct device *dev, + struct device_node *con_np) +{ + struct device_node *child; + struct property *p; + bool done = true; + + for_each_property_of_node(con_np, p) + if (of_link_property(dev, con_np, p->name)) + done = false; + + for_each_child_of_node(con_np, child) + if (__of_link_to_suppliers(dev, child)) + done = false; + + return done ? 0 : -ENODEV; +} + +static bool of_devlink; +core_param(of_devlink, of_devlink, bool, 0); + +static int of_link_to_suppliers(struct device *dev) +{ + if (!of_devlink) + return 0; + if (unlikely(!dev->of_node)) + return 0; + if (of_match_node(of_default_bus_match_table, dev->of_node)) + return 0; + + return __of_link_to_suppliers(dev, dev->of_node); +} + #ifndef CONFIG_PPC static const struct of_device_id reserved_mem_matches[] = { { .compatible = "qcom,rmtfs-mem" }, @@ -523,6 +698,8 @@ static int __init of_platform_default_populate_init(void) if (!of_have_populated_dt()) return -ENODEV; + platform_bus_type.add_links = of_link_to_suppliers; + device_links_supplier_sync_state_pause(); /* * Handle certain compatibles explicitly, since we don't want to create * platform_devices for every node in /reserved-memory with a @@ -543,6 +720,13 @@ static int __init of_platform_default_populate_init(void) return 0; } arch_initcall_sync(of_platform_default_populate_init); + +static int __init of_platform_sync_state_init(void) +{ + device_links_supplier_sync_state_resume(); + return 0; +} +late_initcall_sync(of_platform_sync_state_init); #endif int of_platform_device_destroy(struct device *dev, void *data) diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index a3c7338fad86..dbeeb385fb9f 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -64,11 +64,6 @@ static struct resource *get_pci_domain_busn_res(int domain_nr) return &r->res; } -static int find_anything(struct device *dev, const void *data) -{ - return 1; -} - /* * Some device drivers need know if PCI is initiated. * Basically, we think PCI is not initiated when there @@ -79,7 +74,7 @@ int no_pci_devices(void) struct device *dev; int no_devices; - dev = bus_find_device(&pci_bus_type, NULL, NULL, find_anything); + dev = bus_find_next_device(&pci_bus_type, NULL); no_devices = (dev == NULL); put_device(dev); return no_devices; diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c index 397918ebba55..20dcc9c03adc 100644 --- a/drivers/regulator/of_regulator.c +++ b/drivers/regulator/of_regulator.c @@ -460,16 +460,11 @@ error: return NULL; } -static int of_node_match(struct device *dev, const void *data) -{ - return dev->of_node == data; -} - struct regulator_dev *of_find_regulator_by_node(struct device_node *np) { struct device *dev; - dev = class_find_device(®ulator_class, NULL, np, of_node_match); + dev = class_find_device_by_of_node(®ulator_class, np); return dev ? dev_to_rdev(dev) : NULL; } diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index 72b7ddc43116..c93ef33b01d3 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c @@ -663,21 +663,12 @@ void rtc_update_irq(struct rtc_device *rtc, } EXPORT_SYMBOL_GPL(rtc_update_irq); -static int __rtc_match(struct device *dev, const void *data) -{ - const char *name = data; - - if (strcmp(dev_name(dev), name) == 0) - return 1; - return 0; -} - struct rtc_device *rtc_class_open(const char *name) { struct device *dev; struct rtc_device *rtc = NULL; - dev = class_find_device(rtc_class, NULL, name, __rtc_match); + dev = class_find_device_by_name(rtc_class, name); if (dev) rtc = to_rtc_device(dev); diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c index c522e9313c50..0005ec9285aa 100644 --- a/drivers/s390/cio/ccwgroup.c +++ b/drivers/s390/cio/ccwgroup.c @@ -581,11 +581,6 @@ int ccwgroup_driver_register(struct ccwgroup_driver *cdriver) } EXPORT_SYMBOL(ccwgroup_driver_register); -static int __ccwgroup_match_all(struct device *dev, const void *data) -{ - return 1; -} - /** * ccwgroup_driver_unregister() - deregister a ccw group driver * @cdriver: driver to be deregistered @@ -597,8 +592,7 @@ void ccwgroup_driver_unregister(struct ccwgroup_driver *cdriver) struct device *dev; /* We don't want ccwgroup devices to live longer than their driver. */ - while ((dev = driver_find_device(&cdriver->driver, NULL, NULL, - __ccwgroup_match_all))) { + while ((dev = driver_find_next_device(&cdriver->driver, NULL))) { struct ccwgroup_device *gdev = to_ccwgroupdev(dev); ccwgroup_ungroup(gdev); @@ -608,13 +602,6 @@ void ccwgroup_driver_unregister(struct ccwgroup_driver *cdriver) } EXPORT_SYMBOL(ccwgroup_driver_unregister); -static int __ccwgroupdev_check_busid(struct device *dev, const void *id) -{ - const char *bus_id = id; - - return (strcmp(bus_id, dev_name(dev)) == 0); -} - /** * get_ccwgroupdev_by_busid() - obtain device from a bus id * @gdrv: driver the device is owned by @@ -631,8 +618,7 @@ struct ccwgroup_device *get_ccwgroupdev_by_busid(struct ccwgroup_driver *gdrv, { struct device *dev; - dev = driver_find_device(&gdrv->driver, NULL, bus_id, - __ccwgroupdev_check_busid); + dev = driver_find_device_by_name(&gdrv->driver, bus_id); return dev ? to_ccwgroupdev(dev) : NULL; } diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index c421899be20f..131430bd48d9 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -1695,18 +1695,6 @@ int ccw_device_force_console(struct ccw_device *cdev) EXPORT_SYMBOL_GPL(ccw_device_force_console); #endif -/* - * get ccw_device matching the busid, but only if owned by cdrv - */ -static int -__ccwdev_check_busid(struct device *dev, const void *id) -{ - const char *bus_id = id; - - return (strcmp(bus_id, dev_name(dev)) == 0); -} - - /** * get_ccwdev_by_busid() - obtain device from a bus id * @cdrv: driver the device is owned by @@ -1723,8 +1711,7 @@ struct ccw_device *get_ccwdev_by_busid(struct ccw_driver *cdrv, { struct device *dev; - dev = driver_find_device(&cdrv->driver, NULL, (void *)bus_id, - __ccwdev_check_busid); + dev = driver_find_device_by_name(&cdrv->driver, bus_id); return dev ? to_ccwdev(dev) : NULL; } diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c index 1058b4b5cc1e..150f6236c9bb 100644 --- a/drivers/s390/crypto/zcrypt_api.c +++ b/drivers/s390/crypto/zcrypt_api.c @@ -133,18 +133,6 @@ struct zcdn_device { static int zcdn_create(const char *name); static int zcdn_destroy(const char *name); -/* helper function, matches the name for find_zcdndev_by_name() */ -static int __match_zcdn_name(struct device *dev, const void *data) -{ - return strcmp(dev_name(dev), (const char *)data) == 0; -} - -/* helper function, matches the devt value for find_zcdndev_by_devt() */ -static int __match_zcdn_devt(struct device *dev, const void *data) -{ - return dev->devt == *((dev_t *) data); -} - /* * Find zcdn device by name. * Returns reference to the zcdn device which needs to be released @@ -152,10 +140,7 @@ static int __match_zcdn_devt(struct device *dev, const void *data) */ static inline struct zcdn_device *find_zcdndev_by_name(const char *name) { - struct device *dev = - class_find_device(zcrypt_class, NULL, - (void *) name, - __match_zcdn_name); + struct device *dev = class_find_device_by_name(zcrypt_class, name); return dev ? to_zcdn_dev(dev) : NULL; } @@ -167,10 +152,7 @@ static inline struct zcdn_device *find_zcdndev_by_name(const char *name) */ static inline struct zcdn_device *find_zcdndev_by_devt(dev_t devt) { - struct device *dev = - class_find_device(zcrypt_class, NULL, - (void *) &devt, - __match_zcdn_devt); + struct device *dev = class_find_device_by_devt(zcrypt_class, devt); return dev ? to_zcdn_dev(dev) : NULL; } diff --git a/drivers/scsi/scsi_proc.c b/drivers/scsi/scsi_proc.c index c074631086a4..5b313226f11c 100644 --- a/drivers/scsi/scsi_proc.c +++ b/drivers/scsi/scsi_proc.c @@ -372,15 +372,10 @@ static ssize_t proc_scsi_write(struct file *file, const char __user *buf, return err; } -static int always_match(struct device *dev, const void *data) -{ - return 1; -} - static inline struct device *next_scsi_device(struct device *start) { - struct device *next = bus_find_device(&scsi_bus_type, start, NULL, - always_match); + struct device *next = bus_find_next_device(&scsi_bus_type, start); + put_device(start); return next; } diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 75ac046cae52..c486a6f84c2c 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -3652,37 +3652,25 @@ EXPORT_SYMBOL_GPL(spi_write_then_read); /*-------------------------------------------------------------------------*/ #if IS_ENABLED(CONFIG_OF) -static int __spi_of_device_match(struct device *dev, const void *data) -{ - return dev->of_node == data; -} - /* must call put_device() when done with returned spi_device device */ struct spi_device *of_find_spi_device_by_node(struct device_node *node) { - struct device *dev = bus_find_device(&spi_bus_type, NULL, node, - __spi_of_device_match); + struct device *dev = bus_find_device_by_of_node(&spi_bus_type, node); + return dev ? to_spi_device(dev) : NULL; } EXPORT_SYMBOL_GPL(of_find_spi_device_by_node); #endif /* IS_ENABLED(CONFIG_OF) */ #if IS_ENABLED(CONFIG_OF_DYNAMIC) -static int __spi_of_controller_match(struct device *dev, const void *data) -{ - return dev->of_node == data; -} - /* the spi controllers are not using spi_bus, so we find it with another way */ static struct spi_controller *of_find_spi_controller_by_node(struct device_node *node) { struct device *dev; - dev = class_find_device(&spi_master_class, NULL, node, - __spi_of_controller_match); + dev = class_find_device_by_of_node(&spi_master_class, node); if (!dev && IS_ENABLED(CONFIG_SPI_SLAVE)) - dev = class_find_device(&spi_slave_class, NULL, node, - __spi_of_controller_match); + dev = class_find_device_by_of_node(&spi_slave_class, node); if (!dev) return NULL; @@ -3753,11 +3741,6 @@ static int spi_acpi_controller_match(struct device *dev, const void *data) return ACPI_COMPANION(dev->parent) == data; } -static int spi_acpi_device_match(struct device *dev, const void *data) -{ - return ACPI_COMPANION(dev) == data; -} - static struct spi_controller *acpi_spi_find_controller_by_adev(struct acpi_device *adev) { struct device *dev; @@ -3777,8 +3760,7 @@ static struct spi_device *acpi_spi_find_device_by_adev(struct acpi_device *adev) { struct device *dev; - dev = bus_find_device(&spi_bus_type, NULL, adev, spi_acpi_device_match); - + dev = bus_find_device_by_acpi_dev(&spi_bus_type, adev); return dev ? to_spi_device(dev) : NULL; } diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 566728fbaf3c..802c1210558f 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -2952,17 +2952,11 @@ void do_SAK(struct tty_struct *tty) EXPORT_SYMBOL(do_SAK); -static int dev_match_devt(struct device *dev, const void *data) -{ - const dev_t *devt = data; - return dev->devt == *devt; -} - /* Must put_device() after it's unused! */ static struct device *tty_get_device(struct tty_struct *tty) { dev_t devt = tty_devnum(tty); - return class_find_device(tty_class, NULL, &devt, dev_match_devt); + return class_find_device_by_devt(tty_class, devt); } diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index b265ab5405f9..60268aee93a8 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -942,17 +942,11 @@ error: return ret; } -static int match_devt(struct device *dev, const void *data) -{ - return dev->devt == (dev_t)(unsigned long)(void *)data; -} - static struct usb_device *usbdev_lookup_by_devt(dev_t devt) { struct device *dev; - dev = bus_find_device(&usb_bus_type, NULL, - (void *) (unsigned long) devt, match_devt); + dev = bus_find_device_by_devt(&usb_bus_type, devt); if (!dev) return NULL; return to_usb_device(dev); diff --git a/drivers/usb/roles/class.c b/drivers/usb/roles/class.c index 86defca6623e..0526efbc4922 100644 --- a/drivers/usb/roles/class.c +++ b/drivers/usb/roles/class.c @@ -85,16 +85,6 @@ enum usb_role usb_role_switch_get_role(struct usb_role_switch *sw) } EXPORT_SYMBOL_GPL(usb_role_switch_get_role); -static int switch_fwnode_match(struct device *dev, const void *fwnode) -{ - return dev_fwnode(dev) == fwnode; -} - -static int switch_name_match(struct device *dev, const void *name) -{ - return !strcmp((const char *)name, dev_name(dev)); -} - static void *usb_role_switch_match(struct device_connection *con, int ep, void *data) { @@ -104,11 +94,9 @@ static void *usb_role_switch_match(struct device_connection *con, int ep, if (con->id && !fwnode_property_present(con->fwnode, con->id)) return NULL; - dev = class_find_device(role_class, NULL, con->fwnode, - switch_fwnode_match); + dev = class_find_device_by_fwnode(role_class, con->fwnode); } else { - dev = class_find_device(role_class, NULL, con->endpoint[ep], - switch_name_match); + dev = class_find_device_by_name(role_class, con->endpoint[ep]); } return dev ? to_role_switch(dev) : ERR_PTR(-EPROBE_DEFER); diff --git a/drivers/usb/typec/class.c b/drivers/usb/typec/class.c index a18285a990a8..94a3eda62add 100644 --- a/drivers/usb/typec/class.c +++ b/drivers/usb/typec/class.c @@ -205,16 +205,6 @@ static void typec_altmode_put_partner(struct altmode *altmode) put_device(&adev->dev); } -static int typec_port_fwnode_match(struct device *dev, const void *fwnode) -{ - return dev_fwnode(dev) == fwnode; -} - -static int typec_port_name_match(struct device *dev, const void *name) -{ - return !strcmp((const char *)name, dev_name(dev)); -} - static void *typec_port_match(struct device_connection *con, int ep, void *data) { struct device *dev; @@ -224,11 +214,9 @@ static void *typec_port_match(struct device_connection *con, int ep, void *data) * we need to return ERR_PTR(-PROBE_DEFER) when there is no device. */ if (con->fwnode) - return class_find_device(typec_class, NULL, con->fwnode, - typec_port_fwnode_match); + return class_find_device_by_fwnode(typec_class, con->fwnode); - dev = class_find_device(typec_class, NULL, con->endpoint[ep], - typec_port_name_match); + dev = class_find_device_by_name(typec_class, con->endpoint[ep]); return dev ? dev : ERR_PTR(-EPROBE_DEFER); } diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c index a387534c9577..6ebae6bbe6a5 100644 --- a/fs/kernfs/dir.c +++ b/fs/kernfs/dir.c @@ -137,6 +137,9 @@ static int kernfs_path_from_node_locked(struct kernfs_node *kn_to, if (kn_from == kn_to) return strlcpy(buf, "/", buflen); + if (!buf) + return -EINVAL; + common = kernfs_common_ancestor(kn_from, kn_to); if (WARN_ON(!common)) return -EINVAL; @@ -144,8 +147,7 @@ static int kernfs_path_from_node_locked(struct kernfs_node *kn_to, depth_to = kernfs_depth(common, kn_to); depth_from = kernfs_depth(common, kn_from); - if (buf) - buf[0] = '\0'; + buf[0] = '\0'; for (i = 0; i < depth_from; i++) len += strlcpy(buf + len, parent_str, @@ -430,7 +432,6 @@ struct kernfs_node *kernfs_get_active(struct kernfs_node *kn) */ void kernfs_put_active(struct kernfs_node *kn) { - struct kernfs_root *root = kernfs_root(kn); int v; if (unlikely(!kn)) @@ -442,7 +443,7 @@ void kernfs_put_active(struct kernfs_node *kn) if (likely(v != KN_DEACTIVATED_BIAS)) return; - wake_up_all(&root->deactivate_waitq); + wake_up_all(&kernfs_root(kn)->deactivate_waitq); } /** diff --git a/include/linux/device.h b/include/linux/device.h index 98c00b71b598..23efaff5f10c 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -78,8 +78,28 @@ extern void bus_remove_file(struct bus_type *, struct bus_attribute *); * -EPROBE_DEFER it will queue the device for deferred probing. * @uevent: Called when a device is added, removed, or a few other things * that generate uevents to add the environment variables. + * @add_links: Called, perhaps multiple times per device, after a device is + * added to this bus. The function is expected to create device + * links to all the suppliers of the input device that are + * available at the time this function is called. As in, the + * function should NOT stop at the first failed device link if + * other unlinked supplier devices are present in the system. + * This is necessary for the sync_state() callback to work + * correctly. + * + * Return 0 if device links have been successfully created to all + * the suppliers of this device. Return an error if some of the + * suppliers are not yet available and this function needs to be + * reattempted in the future. * @probe: Called when a new device or driver add to this bus, and callback * the specific driver's probe to initial the matched device. + * @sync_state: Called to sync device state to software state after all the + * state tracking consumers linked to this device (present at + * the time of late_initcall) have successfully bound to a + * driver. If the device has no consumers, this function will + * be called at late_initcall_sync level. If the device has + * consumers that are never bound to a driver, this function + * will never get called until they do. * @remove: Called when a device removed from this bus. * @shutdown: Called at shut-down time to quiesce the device. * @@ -122,7 +142,9 @@ struct bus_type { int (*match)(struct device *dev, struct device_driver *drv); int (*uevent)(struct device *dev, struct kobj_uevent_env *env); + int (*add_links)(struct device *dev); int (*probe)(struct device *dev); + void (*sync_state)(struct device *dev); int (*remove)(struct device *dev); void (*shutdown)(struct device *dev); @@ -164,16 +186,102 @@ void subsys_dev_iter_init(struct subsys_dev_iter *iter, struct device *subsys_dev_iter_next(struct subsys_dev_iter *iter); void subsys_dev_iter_exit(struct subsys_dev_iter *iter); +int device_match_name(struct device *dev, const void *name); int device_match_of_node(struct device *dev, const void *np); +int device_match_fwnode(struct device *dev, const void *fwnode); +int device_match_devt(struct device *dev, const void *pdevt); +int device_match_acpi_dev(struct device *dev, const void *adev); +int device_match_any(struct device *dev, const void *unused); int bus_for_each_dev(struct bus_type *bus, struct device *start, void *data, int (*fn)(struct device *dev, void *data)); struct device *bus_find_device(struct bus_type *bus, struct device *start, const void *data, int (*match)(struct device *dev, const void *data)); -struct device *bus_find_device_by_name(struct bus_type *bus, - struct device *start, - const char *name); +/** + * bus_find_device_by_name - device iterator for locating a particular device + * of a specific name. + * @bus: bus type + * @start: Device to begin with + * @name: name of the device to match + */ +static inline struct device *bus_find_device_by_name(struct bus_type *bus, + struct device *start, + const char *name) +{ + return bus_find_device(bus, start, name, device_match_name); +} + +/** + * bus_find_device_by_of_node : device iterator for locating a particular device + * matching the of_node. + * @bus: bus type + * @np: of_node of the device to match. + */ +static inline struct device * +bus_find_device_by_of_node(struct bus_type *bus, const struct device_node *np) +{ + return bus_find_device(bus, NULL, np, device_match_of_node); +} + +/** + * bus_find_device_by_fwnode : device iterator for locating a particular device + * matching the fwnode. + * @bus: bus type + * @fwnode: fwnode of the device to match. + */ +static inline struct device * +bus_find_device_by_fwnode(struct bus_type *bus, const struct fwnode_handle *fwnode) +{ + return bus_find_device(bus, NULL, fwnode, device_match_fwnode); +} + +/** + * bus_find_device_by_devt : device iterator for locating a particular device + * matching the device type. + * @bus: bus type + * @devt: device type of the device to match. + */ +static inline struct device *bus_find_device_by_devt(struct bus_type *bus, + dev_t devt) +{ + return bus_find_device(bus, NULL, &devt, device_match_devt); +} + +/** + * bus_find_next_device - Find the next device after a given device in a + * given bus. + * @bus: bus type + * @cur: device to begin the search with. + */ +static inline struct device * +bus_find_next_device(struct bus_type *bus,struct device *cur) +{ + return bus_find_device(bus, cur, NULL, device_match_any); +} + +#ifdef CONFIG_ACPI +struct acpi_device; + +/** + * bus_find_device_by_acpi_dev : device iterator for locating a particular device + * matching the ACPI COMPANION device. + * @bus: bus type + * @adev: ACPI COMPANION device to match. + */ +static inline struct device * +bus_find_device_by_acpi_dev(struct bus_type *bus, const struct acpi_device *adev) +{ + return bus_find_device(bus, NULL, adev, device_match_acpi_dev); +} +#else +static inline struct device * +bus_find_device_by_acpi_dev(struct bus_type *bus, const void *adev) +{ + return NULL; +} +#endif + struct device *subsys_find_device_by_id(struct bus_type *bus, unsigned int id, struct device *hint); int bus_for_each_drv(struct bus_type *bus, struct device_driver *start, @@ -251,9 +359,30 @@ enum probe_type { * @probe_type: Type of the probe (synchronous or asynchronous) to use. * @of_match_table: The open firmware table. * @acpi_match_table: The ACPI match table. + * @edit_links: Called to allow a matched driver to edit the device links the + * bus might have added incorrectly. This will be useful to handle + * cases where the bus incorrectly adds functional dependencies + * that aren't true or tries to create cyclic dependencies. But + * doesn't correctly handle functional dependencies that are + * missed by the bus as the supplier's sync_state might get to + * execute before the driver for a missing consumer is loaded and + * gets to edit the device links for the consumer. + * + * This function might be called multiple times after a new device + * is added. The function is expected to create all the device + * links for the new device and return 0 if it was completed + * successfully or return an error if it needs to be reattempted + * in the future. * @probe: Called to query the existence of a specific device, * whether this driver can work with it, and bind the driver * to a specific device. + * @sync_state: Called to sync device state to software state after all the + * state tracking consumers linked to this device (present at + * the time of late_initcall) have successfully bound to a + * driver. If the device has no consumers, this function will + * be called at late_initcall_sync level. If the device has + * consumers that are never bound to a driver, this function + * will never get called until they do. * @remove: Called when the device is removed from the system to * unbind a device from this driver. * @shutdown: Called at shut-down time to quiesce the device. @@ -292,7 +421,9 @@ struct device_driver { const struct of_device_id *of_match_table; const struct acpi_device_id *acpi_match_table; + int (*edit_links)(struct device *dev); int (*probe) (struct device *dev); + void (*sync_state)(struct device *dev); int (*remove) (struct device *dev); void (*shutdown) (struct device *dev); int (*suspend) (struct device *dev, pm_message_t state); @@ -345,6 +476,83 @@ struct device *driver_find_device(struct device_driver *drv, struct device *start, const void *data, int (*match)(struct device *dev, const void *data)); +/** + * driver_find_device_by_name - device iterator for locating a particular device + * of a specific name. + * @driver: the driver we're iterating + * @name: name of the device to match + */ +static inline struct device *driver_find_device_by_name(struct device_driver *drv, + const char *name) +{ + return driver_find_device(drv, NULL, name, device_match_name); +} + +/** + * driver_find_device_by_of_node- device iterator for locating a particular device + * by of_node pointer. + * @driver: the driver we're iterating + * @np: of_node pointer to match. + */ +static inline struct device * +driver_find_device_by_of_node(struct device_driver *drv, + const struct device_node *np) +{ + return driver_find_device(drv, NULL, np, device_match_of_node); +} + +/** + * driver_find_device_by_fwnode- device iterator for locating a particular device + * by fwnode pointer. + * @driver: the driver we're iterating + * @fwnode: fwnode pointer to match. + */ +static inline struct device * +driver_find_device_by_fwnode(struct device_driver *drv, + const struct fwnode_handle *fwnode) +{ + return driver_find_device(drv, NULL, fwnode, device_match_fwnode); +} + +/** + * driver_find_device_by_devt- device iterator for locating a particular device + * by devt. + * @drv: the driver we're iterating + * @devt: devt pointer to match. + */ +static inline struct device *driver_find_device_by_devt(struct device_driver *drv, + dev_t devt) +{ + return driver_find_device(drv, NULL, &devt, device_match_devt); +} + +static inline struct device *driver_find_next_device(struct device_driver *drv, + struct device *start) +{ + return driver_find_device(drv, start, NULL, device_match_any); +} + +#ifdef CONFIG_ACPI +/** + * driver_find_device_by_acpi_dev : device iterator for locating a particular + * device matching the ACPI_COMPANION device. + * @driver: the driver we're iterating + * @adev: ACPI_COMPANION device to match. + */ +static inline struct device * +driver_find_device_by_acpi_dev(struct device_driver *drv, + const struct acpi_device *adev) +{ + return driver_find_device(drv, NULL, adev, device_match_acpi_dev); +} +#else +static inline struct device * +driver_find_device_by_acpi_dev(struct device_driver *drv, const void *adev) +{ + return NULL; +} +#endif + void driver_deferred_probe_add(struct device *dev); int driver_deferred_probe_check_state(struct device *dev); int driver_deferred_probe_check_state_continue(struct device *dev); @@ -474,6 +682,76 @@ extern struct device *class_find_device(struct class *class, struct device *start, const void *data, int (*match)(struct device *, const void *)); +/** + * class_find_device_by_name - device iterator for locating a particular device + * of a specific name. + * @class: class type + * @name: name of the device to match + */ +static inline struct device *class_find_device_by_name(struct class *class, + const char *name) +{ + return class_find_device(class, NULL, name, device_match_name); +} + +/** + * class_find_device_by_of_node : device iterator for locating a particular device + * matching the of_node. + * @class: class type + * @np: of_node of the device to match. + */ +static inline struct device * +class_find_device_by_of_node(struct class *class, const struct device_node *np) +{ + return class_find_device(class, NULL, np, device_match_of_node); +} + +/** + * class_find_device_by_fwnode : device iterator for locating a particular device + * matching the fwnode. + * @class: class type + * @fwnode: fwnode of the device to match. + */ +static inline struct device * +class_find_device_by_fwnode(struct class *class, + const struct fwnode_handle *fwnode) +{ + return class_find_device(class, NULL, fwnode, device_match_fwnode); +} + +/** + * class_find_device_by_devt : device iterator for locating a particular device + * matching the device type. + * @class: class type + * @devt: device type of the device to match. + */ +static inline struct device *class_find_device_by_devt(struct class *class, + dev_t devt) +{ + return class_find_device(class, NULL, &devt, device_match_devt); +} + +#ifdef CONFIG_ACPI +struct acpi_device; +/** + * class_find_device_by_acpi_dev : device iterator for locating a particular + * device matching the ACPI_COMPANION device. + * @class: class type + * @adev: ACPI_COMPANION device to match. + */ +static inline struct device * +class_find_device_by_acpi_dev(struct class *class, const struct acpi_device *adev) +{ + return class_find_device(class, NULL, adev, device_match_acpi_dev); +} +#else +static inline struct device * +class_find_device_by_acpi_dev(struct class *class, const void *adev) +{ + return NULL; +} +#endif + struct class_attribute { struct attribute attr; ssize_t (*show)(struct class *class, struct class_attribute *attr, @@ -836,12 +1114,13 @@ enum device_link_state { /* * Device link flags. * - * STATELESS: The core won't track the presence of supplier/consumer drivers. + * STATELESS: The core will not remove this link automatically. * AUTOREMOVE_CONSUMER: Remove the link automatically on consumer driver unbind. * PM_RUNTIME: If set, the runtime PM framework will use this link. * RPM_ACTIVE: Run pm_runtime_get_sync() on the supplier during link creation. * AUTOREMOVE_SUPPLIER: Remove the link automatically on supplier driver unbind. * AUTOPROBE_CONSUMER: Probe consumer driver automatically after supplier binds. + * MANAGED: The core tracks presence of supplier/consumer drivers (internal). */ #define DL_FLAG_STATELESS BIT(0) #define DL_FLAG_AUTOREMOVE_CONSUMER BIT(1) @@ -849,6 +1128,7 @@ enum device_link_state { #define DL_FLAG_RPM_ACTIVE BIT(3) #define DL_FLAG_AUTOREMOVE_SUPPLIER BIT(4) #define DL_FLAG_AUTOPROBE_CONSUMER BIT(5) +#define DL_FLAG_MANAGED BIT(6) /** * struct device_link - Device link representation. @@ -896,11 +1176,15 @@ enum dl_dev_state { * struct dev_links_info - Device data related to device links. * @suppliers: List of links to supplier devices. * @consumers: List of links to consumer devices. + * @needs_suppliers: Hook to global list of devices waiting for suppliers. + * @defer_sync: Hook to global list of devices that have deferred sync_state. * @status: Driver status information. */ struct dev_links_info { struct list_head suppliers; struct list_head consumers; + struct list_head needs_suppliers; + struct list_head defer_sync; enum dl_dev_state status; }; @@ -974,6 +1258,11 @@ struct dev_links_info { * @offline: Set after successful invocation of bus type's .offline(). * @of_node_reused: Set if the device-tree node is shared with an ancestor * device. + * @has_edit_links: This device has a driver than is capable of + * editing the device links created by driver core. + * @state_synced: The hardware state of this device has been synced to match + * the software state of this device by calling the driver/bus + * sync_state() callback. * @dma_coherent: this particular device is dma coherent, even if the * architecture supports non-coherent devices. * @@ -1067,6 +1356,8 @@ struct device { bool offline_disabled:1; bool offline:1; bool of_node_reused:1; + bool has_edit_links:1; + bool state_synced:1; #if defined(CONFIG_ARCH_HAS_SYNC_DMA_FOR_DEVICE) || \ defined(CONFIG_ARCH_HAS_SYNC_DMA_FOR_CPU) || \ defined(CONFIG_ARCH_HAS_SYNC_DMA_FOR_CPU_ALL) @@ -1318,6 +1609,7 @@ extern int __must_check device_attach(struct device *dev); extern int __must_check driver_attach(struct device_driver *drv); extern void device_initial_probe(struct device *dev); extern int __must_check device_reprobe(struct device *dev); +extern int driver_edit_links(struct device *dev); extern bool device_is_bound(struct device *dev); @@ -1408,6 +1700,9 @@ struct device_link *device_link_add(struct device *consumer, struct device *supplier, u32 flags); void device_link_del(struct device_link *link); void device_link_remove(void *consumer, struct device *supplier); +void device_link_remove_from_wfs(struct device *consumer); +void device_links_supplier_sync_state_pause(void); +void device_links_supplier_sync_state_resume(void); #ifndef dev_fmt #define dev_fmt(fmt) fmt diff --git a/include/linux/mfd/aat2870.h b/include/linux/mfd/aat2870.h index af7267c480ee..2445842d482d 100644 --- a/include/linux/mfd/aat2870.h +++ b/include/linux/mfd/aat2870.h @@ -136,7 +136,6 @@ struct aat2870_data { /* for debugfs */ struct dentry *dentry_root; - struct dentry *dentry_reg; }; struct aat2870_subdev_info { diff --git a/include/linux/platform_device.h b/include/linux/platform_device.h index 9bc36b589827..37e15a935a42 100644 --- a/include/linux/platform_device.h +++ b/include/linux/platform_device.h @@ -51,6 +51,9 @@ extern struct device platform_bus; extern void arch_setup_pdev_archdata(struct platform_device *); extern struct resource *platform_get_resource(struct platform_device *, unsigned int, unsigned int); +extern struct device * +platform_find_device_by_driver(struct device *start, + const struct device_driver *drv); extern void __iomem * devm_platform_ioremap_resource(struct platform_device *pdev, unsigned int index); diff --git a/net/ieee802154/core.c b/net/ieee802154/core.c index 60b7ac56a1f5..de259b5170ab 100644 --- a/net/ieee802154/core.c +++ b/net/ieee802154/core.c @@ -23,11 +23,6 @@ LIST_HEAD(cfg802154_rdev_list); int cfg802154_rdev_list_generation; -static int wpan_phy_match(struct device *dev, const void *data) -{ - return !strcmp(dev_name(dev), (const char *)data); -} - struct wpan_phy *wpan_phy_find(const char *str) { struct device *dev; @@ -35,7 +30,7 @@ struct wpan_phy *wpan_phy_find(const char *str) if (WARN_ON(!str)) return NULL; - dev = class_find_device(&wpan_phy_class, NULL, str, wpan_phy_match); + dev = class_find_device_by_name(&wpan_phy_class, str); if (!dev) return NULL; diff --git a/scripts/coccinelle/api/platform_get_irq.cocci b/scripts/coccinelle/api/platform_get_irq.cocci new file mode 100644 index 000000000000..f6e1afc08c0b --- /dev/null +++ b/scripts/coccinelle/api/platform_get_irq.cocci @@ -0,0 +1,102 @@ +// SPDX-License-Identifier: GPL-2.0 +/// Remove dev_err() messages after platform_get_irq*() failures +// +// Confidence: Medium +// Options: --include-headers + +virtual patch +virtual context +virtual org +virtual report + +@depends on context@ +expression ret; +struct platform_device *E; +@@ + +ret = +( +platform_get_irq +| +platform_get_irq_byname +)(E, ...); + +if ( ret \( < \| <= \) 0 ) +{ +( +if (ret != -EPROBE_DEFER) +{ ... +*dev_err(...); +... } +| +... +*dev_err(...); +) +... +} + +@depends on patch@ +expression ret; +struct platform_device *E; +@@ + +ret = +( +platform_get_irq +| +platform_get_irq_byname +)(E, ...); + +if ( ret \( < \| <= \) 0 ) +{ +( +-if (ret != -EPROBE_DEFER) +-{ ... +-dev_err(...); +-... } +| +... +-dev_err(...); +) +... +} + +@r depends on org || report@ +position p1; +expression ret; +struct platform_device *E; +@@ + +ret = +( +platform_get_irq +| +platform_get_irq_byname +)(E, ...); + +if ( ret \( < \| <= \) 0 ) +{ +( +if (ret != -EPROBE_DEFER) +{ ... +dev_err@p1(...); +... } +| +... +dev_err@p1(...); +) +... +} + +@script:python depends on org@ +p1 << r.p1; +@@ + +cocci.print_main(p1) + +@script:python depends on report@ +p1 << r.p1; +@@ + +msg = "line %s is redundant because platform_get_irq() already prints an error" % (p1[0].line) +coccilib.report.print_report(p1[0],msg) diff --git a/sound/soc/rockchip/rk3399_gru_sound.c b/sound/soc/rockchip/rk3399_gru_sound.c index c16b0ffe8cfc..d951100bf770 100644 --- a/sound/soc/rockchip/rk3399_gru_sound.c +++ b/sound/soc/rockchip/rk3399_gru_sound.c @@ -422,11 +422,6 @@ static const struct dailink_match_data dailink_match[] = { }, }; -static int of_dev_node_match(struct device *dev, const void *data) -{ - return dev->of_node == data; -} - static int rockchip_sound_codec_node_match(struct device_node *np_codec) { struct device *dev; @@ -438,8 +433,8 @@ static int rockchip_sound_codec_node_match(struct device_node *np_codec) continue; if (dailink_match[i].bus_type) { - dev = bus_find_device(dailink_match[i].bus_type, NULL, - np_codec, of_dev_node_match); + dev = bus_find_device_by_of_node(dailink_match[i].bus_type, + np_codec); if (!dev) continue; put_device(dev); |