From b45ed06f46737f8c2ee65698f4305409f2386674 Mon Sep 17 00:00:00 2001 From: Zijun Hu Date: Tue, 13 Aug 2024 22:19:32 +0800 Subject: drivers/base: Introduce device_match_t for device finding APIs There are several drivers/base APIs for finding a specific device, and they currently use the following good type for the @match parameter: int (*match)(struct device *dev, const void *data) Since these operations do not modify the caller-provided @*data, this type is worthy of a dedicated typedef: typedef int (*device_match_t)(struct device *dev, const void *data) Advantages of using device_match_t: - Shorter API declarations and definitions - Prevent further APIs from using a bad type for @match So introduce device_match_t and apply it to the existing (bus|class|driver|auxiliary)_find_device() APIs. Signed-off-by: Zijun Hu Link: https://lore.kernel.org/r/20240813-dev_match_api-v3-1-6c6878a99b9f@quicinc.com Signed-off-by: Greg Kroah-Hartman --- include/linux/auxiliary_bus.h | 2 +- include/linux/device/bus.h | 6 ++++-- include/linux/device/class.h | 2 +- include/linux/device/driver.h | 2 +- 4 files changed, 7 insertions(+), 5 deletions(-) (limited to 'include/linux') diff --git a/include/linux/auxiliary_bus.h b/include/linux/auxiliary_bus.h index 662b8ae54b6a..31762324bcc9 100644 --- a/include/linux/auxiliary_bus.h +++ b/include/linux/auxiliary_bus.h @@ -271,6 +271,6 @@ void auxiliary_driver_unregister(struct auxiliary_driver *auxdrv); struct auxiliary_device *auxiliary_find_device(struct device *start, const void *data, - int (*match)(struct device *dev, const void *data)); + device_match_t match); #endif /* _AUXILIARY_BUS_H_ */ diff --git a/include/linux/device/bus.h b/include/linux/device/bus.h index 807831d6bf0f..cdc4757217f9 100644 --- a/include/linux/device/bus.h +++ b/include/linux/device/bus.h @@ -126,6 +126,9 @@ struct bus_attribute { int __must_check bus_create_file(const struct bus_type *bus, struct bus_attribute *attr); void bus_remove_file(const struct bus_type *bus, struct bus_attribute *attr); +/* Matching function type for drivers/base APIs to find a specific device */ +typedef int (*device_match_t)(struct device *dev, const void *data); + /* Generic device matching functions that all busses can use to match with */ int device_match_name(struct device *dev, const void *name); int device_match_of_node(struct device *dev, const void *np); @@ -139,8 +142,7 @@ int device_match_any(struct device *dev, const void *unused); int bus_for_each_dev(const struct bus_type *bus, struct device *start, void *data, int (*fn)(struct device *dev, void *data)); struct device *bus_find_device(const struct bus_type *bus, struct device *start, - const void *data, - int (*match)(struct device *dev, const void *data)); + const void *data, device_match_t match); /** * bus_find_device_by_name - device iterator for locating a particular device * of a specific name. diff --git a/include/linux/device/class.h b/include/linux/device/class.h index c576b49c55c2..518c9c83d64b 100644 --- a/include/linux/device/class.h +++ b/include/linux/device/class.h @@ -95,7 +95,7 @@ void class_dev_iter_exit(struct class_dev_iter *iter); int class_for_each_device(const struct class *class, const struct device *start, void *data, int (*fn)(struct device *dev, void *data)); struct device *class_find_device(const struct class *class, const struct device *start, - const void *data, int (*match)(struct device *, const void *)); + const void *data, device_match_t match); /** * class_find_device_by_name - device iterator for locating a particular device diff --git a/include/linux/device/driver.h b/include/linux/device/driver.h index 1fc8b68786de..5c04b8e3833b 100644 --- a/include/linux/device/driver.h +++ b/include/linux/device/driver.h @@ -157,7 +157,7 @@ int __must_check driver_for_each_device(struct device_driver *drv, struct device void *data, int (*fn)(struct device *dev, void *)); struct device *driver_find_device(const struct device_driver *drv, struct device *start, const void *data, - int (*match)(struct device *dev, const void *data)); + device_match_t match); /** * driver_find_device_by_name - device iterator for locating a particular device -- cgit v1.2.3 From 24e041e1e48d06f25a12caaf73728a4ec2e511fe Mon Sep 17 00:00:00 2001 From: Kunwu Chan Date: Fri, 23 Aug 2024 15:55:44 +0800 Subject: platform: Make platform_bus_type constant Since commit d492cc2573a0 ("driver core: device.h: make struct bus_type a const *"), the driver core can properly handle constant struct bus_type, move the platform_bus_type variable to be a constant structure as well, placing it into read-only memory which can not be modified at runtime. Cc: Greg Kroah-Hartman Suggested-by: Greg Kroah-Hartman Signed-off-by: Kunwu Chan Link: https://lore.kernel.org/r/20240823075544.144426-1-kunwu.chan@linux.dev Signed-off-by: Greg Kroah-Hartman --- drivers/base/platform.c | 2 +- include/linux/platform_device.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 4c3ee6521ba5..6f2a33722c52 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -1474,7 +1474,7 @@ static const struct dev_pm_ops platform_dev_pm_ops = { USE_PLATFORM_PM_SLEEP_OPS }; -struct bus_type platform_bus_type = { +const struct bus_type platform_bus_type = { .name = "platform", .dev_groups = platform_dev_groups, .match = platform_match, diff --git a/include/linux/platform_device.h b/include/linux/platform_device.h index d422db6eec63..7132623e4658 100644 --- a/include/linux/platform_device.h +++ b/include/linux/platform_device.h @@ -52,7 +52,7 @@ struct platform_device { extern int platform_device_register(struct platform_device *); extern void platform_device_unregister(struct platform_device *); -extern struct bus_type platform_bus_type; +extern const struct bus_type platform_bus_type; extern struct device platform_bus; extern struct resource *platform_get_resource(struct platform_device *, -- cgit v1.2.3 From 8064952c65045f05ee2671fe437770e50c151776 Mon Sep 17 00:00:00 2001 From: Stuart Hayes Date: Thu, 22 Aug 2024 15:28:04 -0500 Subject: driver core: shut down devices asynchronously Add code to allow asynchronous shutdown of devices, ensuring that each device is shut down before its parents & suppliers. Only devices with drivers that have async_shutdown_enable enabled will be shut down asynchronously. This can dramatically reduce system shutdown/reboot time on systems that have multiple devices that take many seconds to shut down (like certain NVMe drives). On one system tested, the shutdown time went from 11 minutes without this patch to 55 seconds with the patch. Signed-off-by: Stuart Hayes Signed-off-by: David Jeffery Reviewed-by: Christoph Hellwig Reviewed-by: Sagi Grimberg Reviewed-by: Keith Busch Tested-by: Keith Busch Link: https://lore.kernel.org/r/20240822202805.6379-4-stuart.w.hayes@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/base/base.h | 4 ++++ drivers/base/core.c | 54 ++++++++++++++++++++++++++++++++++++++++++- include/linux/device/driver.h | 2 ++ 3 files changed, 59 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/drivers/base/base.h b/drivers/base/base.h index 8cf04a557bdb..ea18aa70f151 100644 --- a/drivers/base/base.h +++ b/drivers/base/base.h @@ -10,6 +10,7 @@ * shared outside of the drivers/base/ directory. * */ +#include #include /** @@ -97,6 +98,8 @@ struct driver_private { * the device; typically because it depends on another driver getting * probed first. * @async_driver - pointer to device driver awaiting probe via async_probe + * @shutdown_after - used during device shutdown to ensure correct shutdown + * ordering. * @device - pointer back to the struct device that this structure is * associated with. * @dead - This device is currently either in the process of or has been @@ -114,6 +117,7 @@ struct device_private { struct list_head deferred_probe; const struct device_driver *async_driver; char *deferred_probe_reason; + async_cookie_t shutdown_after; struct device *device; u8 dead:1; }; diff --git a/drivers/base/core.c b/drivers/base/core.c index 8598421cbb7f..6113bc1092ae 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -9,6 +9,7 @@ */ #include +#include #include #include #include @@ -3524,6 +3525,7 @@ static int device_private_init(struct device *dev) klist_init(&dev->p->klist_children, klist_children_get, klist_children_put); INIT_LIST_HEAD(&dev->p->deferred_probe); + dev->p->shutdown_after = 0; return 0; } @@ -4779,6 +4781,8 @@ out: } EXPORT_SYMBOL_GPL(device_change_owner); +static ASYNC_DOMAIN(sd_domain); + static void shutdown_one_device(struct device *dev) { /* hold lock to avoid race with probe/release */ @@ -4814,12 +4818,34 @@ static void shutdown_one_device(struct device *dev) put_device(dev->parent); } +/** + * shutdown_one_device_async + * @data: the pointer to the struct device to be shutdown + * @cookie: not used + * + * Shuts down one device, after waiting for shutdown_after to complete. + * shutdown_after should be set to the cookie of the last child or consumer + * of this device to be shutdown (if any), or to the cookie of the previous + * device to be shut down for devices that don't enable asynchronous shutdown. + */ +static void shutdown_one_device_async(void *data, async_cookie_t cookie) +{ + struct device *dev = data; + + async_synchronize_cookie_domain(dev->p->shutdown_after + 1, &sd_domain); + + shutdown_one_device(dev); +} + /** * device_shutdown - call ->shutdown() on each device to shutdown. */ void device_shutdown(void) { struct device *dev, *parent; + async_cookie_t cookie = 0; + struct device_link *link; + int idx; wait_for_device_probe(); device_block_probing(); @@ -4850,11 +4876,37 @@ void device_shutdown(void) list_del_init(&dev->kobj.entry); spin_unlock(&devices_kset->list_lock); - shutdown_one_device(dev); + + /* + * Set cookie for devices that will be shut down synchronously + */ + if (!dev->driver || !dev->driver->async_shutdown_enable) + dev->p->shutdown_after = cookie; + + get_device(dev); + get_device(parent); + + cookie = async_schedule_domain(shutdown_one_device_async, + dev, &sd_domain); + /* + * Ensure parent & suppliers wait for this device to shut down + */ + if (parent) { + parent->p->shutdown_after = cookie; + put_device(parent); + } + + idx = device_links_read_lock(); + list_for_each_entry_rcu(link, &dev->links.suppliers, c_node, + device_links_read_lock_held()) + link->supplier->p->shutdown_after = cookie; + device_links_read_unlock(idx); + put_device(dev); spin_lock(&devices_kset->list_lock); } spin_unlock(&devices_kset->list_lock); + async_synchronize_full_domain(&sd_domain); } /* diff --git a/include/linux/device/driver.h b/include/linux/device/driver.h index 5c04b8e3833b..14c9211b82d6 100644 --- a/include/linux/device/driver.h +++ b/include/linux/device/driver.h @@ -56,6 +56,7 @@ enum probe_type { * @mod_name: Used for built-in modules. * @suppress_bind_attrs: Disables bind/unbind via sysfs. * @probe_type: Type of the probe (synchronous or asynchronous) to use. + * @async_shutdown_enable: Enables devices to be shutdown asynchronously. * @of_match_table: The open firmware table. * @acpi_match_table: The ACPI match table. * @probe: Called to query the existence of a specific device, @@ -102,6 +103,7 @@ struct device_driver { bool suppress_bind_attrs; /* disables bind/unbind via sysfs */ enum probe_type probe_type; + bool async_shutdown_enable; const struct of_device_id *of_match_table; const struct acpi_device_id *acpi_match_table; -- cgit v1.2.3 From 8ab0f4605d5ce3c0d386b3828b07719f1e8e0505 Mon Sep 17 00:00:00 2001 From: Kunwu Chan Date: Fri, 23 Aug 2024 14:24:40 +0800 Subject: bus: fsl-mc: make fsl_mc_bus_type const Since commit d492cc2573a0 ("driver core: device.h: make struct bus_type a const *"), the driver core can properly handle constant struct bus_type, move the fsl_mc_bus_type variable to be a constant structure as well, placing it into read-only memory which can not be modified at runtime. Cc: Greg Kroah-Hartman Suggested-by: Greg Kroah-Hartman Signed-off-by: Kunwu Chan Acked-by: Christophe Leroy # for Link: https://lore.kernel.org/r/20240823062440.113628-1-kunwu.chan@linux.dev Signed-off-by: Greg Kroah-Hartman --- drivers/bus/fsl-mc/fsl-mc-bus.c | 2 +- include/linux/fsl/mc.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/drivers/bus/fsl-mc/fsl-mc-bus.c b/drivers/bus/fsl-mc/fsl-mc-bus.c index dd68b8191a0a..930d8a3ba722 100644 --- a/drivers/bus/fsl-mc/fsl-mc-bus.c +++ b/drivers/bus/fsl-mc/fsl-mc-bus.c @@ -309,7 +309,7 @@ static struct attribute *fsl_mc_bus_attrs[] = { ATTRIBUTE_GROUPS(fsl_mc_bus); -struct bus_type fsl_mc_bus_type = { +const struct bus_type fsl_mc_bus_type = { .name = "fsl-mc", .match = fsl_mc_bus_match, .uevent = fsl_mc_bus_uevent, diff --git a/include/linux/fsl/mc.h b/include/linux/fsl/mc.h index 083c860fd28e..c90ec889bfc2 100644 --- a/include/linux/fsl/mc.h +++ b/include/linux/fsl/mc.h @@ -436,7 +436,7 @@ void fsl_mc_free_irqs(struct fsl_mc_device *mc_dev); struct fsl_mc_device *fsl_mc_get_endpoint(struct fsl_mc_device *mc_dev, u16 if_id); -extern struct bus_type fsl_mc_bus_type; +extern const struct bus_type fsl_mc_bus_type; extern struct device_type fsl_mc_bus_dprc_type; extern struct device_type fsl_mc_bus_dpni_type; -- cgit v1.2.3 From 6a36d828bdef0e02b1e6c12e2160f5b83be6aab5 Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Fri, 13 Sep 2024 02:09:55 +0100 Subject: driver core: attribute_container: Remove unused functions I can't find any use of 'attribute_container_add_class_device_adapter' or 'attribute_container_trigger' in git history. Their export decls went in 2006: commit 1740757e8f94 ("[PATCH] Driver Core: remove unused exports") and their docs disappeared in 2016: commit 47cb398dd75a ("Docs: sphinxify device-drivers.tmpl") Remove them. Signed-off-by: Dr. David Alan Gilbert Link: https://lore.kernel.org/r/20240913010955.1393995-1-linux@treblig.org Signed-off-by: Greg Kroah-Hartman --- drivers/base/attribute_container.c | 48 +------------------------------------ include/linux/attribute_container.h | 6 ----- 2 files changed, 1 insertion(+), 53 deletions(-) (limited to 'include/linux') diff --git a/drivers/base/attribute_container.c b/drivers/base/attribute_container.c index 01ef796c2055..b6f941a6ab69 100644 --- a/drivers/base/attribute_container.c +++ b/drivers/base/attribute_container.c @@ -346,8 +346,7 @@ attribute_container_device_trigger_safe(struct device *dev, * @fn: the function to execute for each classdev. * * This function is for executing a trigger when you need to know both - * the container and the classdev. If you only care about the - * container, then use attribute_container_trigger() instead. + * the container and the classdev. */ void attribute_container_device_trigger(struct device *dev, @@ -378,33 +377,6 @@ attribute_container_device_trigger(struct device *dev, mutex_unlock(&attribute_container_mutex); } -/** - * attribute_container_trigger - trigger a function for each matching container - * - * @dev: The generic device to activate the trigger for - * @fn: the function to trigger - * - * This routine triggers a function that only needs to know the - * matching containers (not the classdev) associated with a device. - * It is more lightweight than attribute_container_device_trigger, so - * should be used in preference unless the triggering function - * actually needs to know the classdev. - */ -void -attribute_container_trigger(struct device *dev, - int (*fn)(struct attribute_container *, - struct device *)) -{ - struct attribute_container *cont; - - mutex_lock(&attribute_container_mutex); - list_for_each_entry(cont, &attribute_container_list, node) { - if (cont->match(cont, dev)) - fn(cont, dev); - } - mutex_unlock(&attribute_container_mutex); -} - /** * attribute_container_add_attrs - add attributes * @@ -458,24 +430,6 @@ attribute_container_add_class_device(struct device *classdev) return attribute_container_add_attrs(classdev); } -/** - * attribute_container_add_class_device_adapter - simple adapter for triggers - * - * @cont: the container to register. - * @dev: the generic device to activate the trigger for - * @classdev: the class device to add - * - * This function is identical to attribute_container_add_class_device except - * that it is designed to be called from the triggers - */ -int -attribute_container_add_class_device_adapter(struct attribute_container *cont, - struct device *dev, - struct device *classdev) -{ - return attribute_container_add_class_device(classdev); -} - /** * attribute_container_remove_attrs - remove any attribute files * diff --git a/include/linux/attribute_container.h b/include/linux/attribute_container.h index e4004d1e6725..b3643de9931d 100644 --- a/include/linux/attribute_container.h +++ b/include/linux/attribute_container.h @@ -61,14 +61,8 @@ int attribute_container_device_trigger_safe(struct device *dev, int (*undo)(struct attribute_container *, struct device *, struct device *)); -void attribute_container_trigger(struct device *dev, - int (*fn)(struct attribute_container *, - struct device *)); int attribute_container_add_attrs(struct device *classdev); int attribute_container_add_class_device(struct device *classdev); -int attribute_container_add_class_device_adapter(struct attribute_container *cont, - struct device *dev, - struct device *classdev); void attribute_container_remove_attrs(struct device *classdev); void attribute_container_class_device_del(struct device *classdev); struct attribute_container *attribute_container_classdev_to_container(struct device *); -- cgit v1.2.3 From 2efddb5575cd9f5f4d61ad417c92365a5f18d2f1 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 25 Sep 2024 10:57:00 +0200 Subject: Revert "driver core: shut down devices asynchronously" This reverts commit 8064952c65045f05ee2671fe437770e50c151776. The series is being reverted before -rc1 as there are still reports of lockups on shutdown, so it's not quite ready for "prime time." Reported-by: Andrey Skvortsov Link: https://lore.kernel.org/r/ZvMkkhyJrohaajuk@skv.local Cc: Christoph Hellwig Cc: David Jeffery Cc: Keith Busch Cc: Laurence Oberman Cc: Nathan Chancellor Cc: Sagi Grimberg Cc: Stuart Hayes Signed-off-by: Greg Kroah-Hartman --- drivers/base/base.h | 4 ---- drivers/base/core.c | 54 +------------------------------------------ include/linux/device/driver.h | 2 -- 3 files changed, 1 insertion(+), 59 deletions(-) (limited to 'include/linux') diff --git a/drivers/base/base.h b/drivers/base/base.h index ea18aa70f151..8cf04a557bdb 100644 --- a/drivers/base/base.h +++ b/drivers/base/base.h @@ -10,7 +10,6 @@ * shared outside of the drivers/base/ directory. * */ -#include #include /** @@ -98,8 +97,6 @@ struct driver_private { * the device; typically because it depends on another driver getting * probed first. * @async_driver - pointer to device driver awaiting probe via async_probe - * @shutdown_after - used during device shutdown to ensure correct shutdown - * ordering. * @device - pointer back to the struct device that this structure is * associated with. * @dead - This device is currently either in the process of or has been @@ -117,7 +114,6 @@ struct device_private { struct list_head deferred_probe; const struct device_driver *async_driver; char *deferred_probe_reason; - async_cookie_t shutdown_after; struct device *device; u8 dead:1; }; diff --git a/drivers/base/core.c b/drivers/base/core.c index b69b82da8837..4482382fb947 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -9,7 +9,6 @@ */ #include -#include #include #include #include @@ -3525,7 +3524,6 @@ static int device_private_init(struct device *dev) klist_init(&dev->p->klist_children, klist_children_get, klist_children_put); INIT_LIST_HEAD(&dev->p->deferred_probe); - dev->p->shutdown_after = 0; return 0; } @@ -4781,8 +4779,6 @@ out: } EXPORT_SYMBOL_GPL(device_change_owner); -static ASYNC_DOMAIN(sd_domain); - static void shutdown_one_device(struct device *dev) { /* hold lock to avoid race with probe/release */ @@ -4818,34 +4814,12 @@ static void shutdown_one_device(struct device *dev) put_device(dev->parent); } -/** - * shutdown_one_device_async - * @data: the pointer to the struct device to be shutdown - * @cookie: not used - * - * Shuts down one device, after waiting for shutdown_after to complete. - * shutdown_after should be set to the cookie of the last child or consumer - * of this device to be shutdown (if any), or to the cookie of the previous - * device to be shut down for devices that don't enable asynchronous shutdown. - */ -static void shutdown_one_device_async(void *data, async_cookie_t cookie) -{ - struct device *dev = data; - - async_synchronize_cookie_domain(dev->p->shutdown_after + 1, &sd_domain); - - shutdown_one_device(dev); -} - /** * device_shutdown - call ->shutdown() on each device to shutdown. */ void device_shutdown(void) { struct device *dev, *parent; - async_cookie_t cookie = 0; - struct device_link *link; - int idx; wait_for_device_probe(); device_block_probing(); @@ -4876,37 +4850,11 @@ void device_shutdown(void) list_del_init(&dev->kobj.entry); spin_unlock(&devices_kset->list_lock); - - /* - * Set cookie for devices that will be shut down synchronously - */ - if (!dev->driver || !dev->driver->async_shutdown_enable) - dev->p->shutdown_after = cookie; - - get_device(dev); - get_device(parent); - - cookie = async_schedule_domain(shutdown_one_device_async, - dev, &sd_domain); - /* - * Ensure parent & suppliers wait for this device to shut down - */ - if (parent) { - parent->p->shutdown_after = cookie; - put_device(parent); - } - - idx = device_links_read_lock(); - list_for_each_entry_rcu(link, &dev->links.suppliers, c_node, - device_links_read_lock_held()) - link->supplier->p->shutdown_after = cookie; - device_links_read_unlock(idx); - put_device(dev); + shutdown_one_device(dev); spin_lock(&devices_kset->list_lock); } spin_unlock(&devices_kset->list_lock); - async_synchronize_full_domain(&sd_domain); } /* diff --git a/include/linux/device/driver.h b/include/linux/device/driver.h index 14c9211b82d6..5c04b8e3833b 100644 --- a/include/linux/device/driver.h +++ b/include/linux/device/driver.h @@ -56,7 +56,6 @@ enum probe_type { * @mod_name: Used for built-in modules. * @suppress_bind_attrs: Disables bind/unbind via sysfs. * @probe_type: Type of the probe (synchronous or asynchronous) to use. - * @async_shutdown_enable: Enables devices to be shutdown asynchronously. * @of_match_table: The open firmware table. * @acpi_match_table: The ACPI match table. * @probe: Called to query the existence of a specific device, @@ -103,7 +102,6 @@ struct device_driver { bool suppress_bind_attrs; /* disables bind/unbind via sysfs */ enum probe_type probe_type; - bool async_shutdown_enable; const struct of_device_id *of_match_table; const struct acpi_device_id *acpi_match_table; -- cgit v1.2.3