From e2ae9bcc4aaacda04edb75c4eea93384719efaa5 Mon Sep 17 00:00:00 2001 From: Saravana Kannan Date: Wed, 4 Sep 2019 14:11:21 -0700 Subject: driver core: Add support for linking devices during device addition The firmware corresponding to a device (dev.fwnode) might be able to provide functional dependency information between a device and its supplier and consumer devices. Tracking this functional dependency allows optimizing device probe order and informing a supplier when all its consumers have probed (and thereby actively managing their resources). The existing device links feature allows tracking and using supplier-consumer relationships. So, this patch adds the add_links() fwnode callback to allow firmware to create device links for each device as the device is added. However, when consumer devices are added, they might not have a supplier device to link to despite needing mandatory resources/functionality from one or more suppliers. A waiting_for_suppliers list is created to track such consumers and retry linking them when new devices get added. Signed-off-by: Saravana Kannan Link: https://lore.kernel.org/r/20190904211126.47518-3-saravanak@google.com Signed-off-by: Greg Kroah-Hartman --- Documentation/driver-api/device_link.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'Documentation/driver-api') diff --git a/Documentation/driver-api/device_link.rst b/Documentation/driver-api/device_link.rst index 1b5020ec6517..bc2d89af88ce 100644 --- a/Documentation/driver-api/device_link.rst +++ b/Documentation/driver-api/device_link.rst @@ -281,7 +281,8 @@ State machine :c:func:`driver_bound()`.) * Before a consumer device is probed, presence of supplier drivers is - verified by checking that links to suppliers are in ``DL_STATE_AVAILABLE`` + verified by checking the consumer device is not in the wait_for_suppliers + list and by checking that links to suppliers are in ``DL_STATE_AVAILABLE`` state. The state of the links is updated to ``DL_STATE_CONSUMER_PROBE``. (Call to :c:func:`device_links_check_suppliers()` from :c:func:`really_probe()`.) -- cgit v1.2.3-59-g8ed1b From a3caeb8ffe5d2bbe01da66081f0ef28c26302d99 Mon Sep 17 00:00:00 2001 From: Saravana Kannan Date: Fri, 11 Oct 2019 12:15:21 -0700 Subject: docs: driver-model: Add documentation for sync_state The sync_state() driver callback was added recently, but the documentation was missing. Adding it now. Signed-off-by: Saravana Kannan Link: https://lore.kernel.org/r/20191011191521.179614-4-saravanak@google.com Signed-off-by: Greg Kroah-Hartman --- Documentation/driver-api/driver-model/driver.rst | 43 ++++++++++++++++++++++++ 1 file changed, 43 insertions(+) (limited to 'Documentation/driver-api') diff --git a/Documentation/driver-api/driver-model/driver.rst b/Documentation/driver-api/driver-model/driver.rst index 11d281506a04..baa6a85c8287 100644 --- a/Documentation/driver-api/driver-model/driver.rst +++ b/Documentation/driver-api/driver-model/driver.rst @@ -169,6 +169,49 @@ A driver's probe() may return a negative errno value to indicate that the driver did not bind to this device, in which case it should have released all resources it allocated:: + void (*sync_state)(struct device *dev); + +sync_state is called only once for a device. It's called when all the consumer +devices of the device have successfully probed. The list of consumers of the +device is obtained by looking at the device links connecting that device to its +consumer devices. + +The first attempt to call sync_state() is made during late_initcall_sync() to +give firmware and drivers time to link devices to each other. During the first +attempt at calling sync_state(), if all the consumers of the device at that +point in time have already probed successfully, sync_state() is called right +away. If there are no consumers of the device during the first attempt, that +too is considered as "all consumers of the device have probed" and sync_state() +is called right away. + +If during the first attempt at calling sync_state() for a device, there are +still consumers that haven't probed successfully, the sync_state() call is +postponed and reattempted in the future only when one or more consumers of the +device probe successfully. If during the reattempt, the driver core finds that +there are one or more consumers of the device that haven't probed yet, then +sync_state() call is postponed again. + +A typical use case for sync_state() is to have the kernel cleanly take over +management of devices from the bootloader. For example, if a device is left on +and at a particular hardware configuration by the bootloader, the device's +driver might need to keep the device in the boot configuration until all the +consumers of the device have probed. Once all the consumers of the device have +probed, the device's driver can synchronize the hardware state of the device to +match the aggregated software state requested by all the consumers. Hence the +name sync_state(). + +While obvious examples of resources that can benefit from sync_state() include +resources such as regulator, sync_state() can also be useful for complex +resources like IOMMUs. For example, IOMMUs with multiple consumers (devices +whose addresses are remapped by the IOMMU) might need to keep their mappings +fixed at (or additive to) the boot configuration until all its consumers have +probed. + +While the typical use case for sync_state() is to have the kernel cleanly take +over management of devices from the bootloader, the usage of sync_state() is +not restricted to that. Use it whenever it makes sense to take an action after +all the consumers of a device have probed. + int (*remove) (struct device *dev); remove is called to unbind a driver from a device. This may be -- cgit v1.2.3-59-g8ed1b From 4154abca299e0f27dfe362733bb5296c7bb4d63f Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Tue, 22 Oct 2019 10:43:11 +0200 Subject: Documentation: devres: add missing entry for devm_platform_ioremap_resource() devm_platform_ioremap_resource() should be documented in devres.rst. Add the missing entry. Signed-off-by: Bartosz Golaszewski Reviewed-by: Arnd Bergmann Link: https://lore.kernel.org/r/20191022084318.22256-2-brgl@bgdev.pl Signed-off-by: Greg Kroah-Hartman --- Documentation/driver-api/driver-model/devres.rst | 1 + 1 file changed, 1 insertion(+) (limited to 'Documentation/driver-api') diff --git a/Documentation/driver-api/driver-model/devres.rst b/Documentation/driver-api/driver-model/devres.rst index a100bef54952..8e3087662daf 100644 --- a/Documentation/driver-api/driver-model/devres.rst +++ b/Documentation/driver-api/driver-model/devres.rst @@ -316,6 +316,7 @@ IOMAP devm_ioremap_nocache() devm_ioremap_wc() devm_ioremap_resource() : checks resource, requests memory region, ioremaps + devm_platform_ioremap_resource() : calls devm_ioremap_resource() for platform device devm_iounmap() pcim_iomap() pcim_iomap_regions() : do request_region() and iomap() on multiple BARs -- cgit v1.2.3-59-g8ed1b From b873af620e58863b70ae9cf97f6fab4cf4c544af Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Tue, 22 Oct 2019 10:43:13 +0200 Subject: lib: devres: provide devm_ioremap_resource_wc() Provide a variant of devm_ioremap_resource() for write-combined ioremap. Signed-off-by: Bartosz Golaszewski Reviewed-by: Arnd Bergmann Link: https://lore.kernel.org/r/20191022084318.22256-4-brgl@bgdev.pl Signed-off-by: Greg Kroah-Hartman --- Documentation/driver-api/driver-model/devres.rst | 1 + include/linux/device.h | 2 ++ lib/devres.c | 15 +++++++++++++++ 3 files changed, 18 insertions(+) (limited to 'Documentation/driver-api') diff --git a/Documentation/driver-api/driver-model/devres.rst b/Documentation/driver-api/driver-model/devres.rst index 8e3087662daf..e605bb9df6e1 100644 --- a/Documentation/driver-api/driver-model/devres.rst +++ b/Documentation/driver-api/driver-model/devres.rst @@ -316,6 +316,7 @@ IOMAP devm_ioremap_nocache() devm_ioremap_wc() devm_ioremap_resource() : checks resource, requests memory region, ioremaps + devm_ioremap_resource_wc() devm_platform_ioremap_resource() : calls devm_ioremap_resource() for platform device devm_iounmap() pcim_iomap() diff --git a/include/linux/device.h b/include/linux/device.h index d1bcc8f122f6..f05c5b92e61f 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -962,6 +962,8 @@ extern void devm_free_pages(struct device *dev, unsigned long addr); void __iomem *devm_ioremap_resource(struct device *dev, const struct resource *res); +void __iomem *devm_ioremap_resource_wc(struct device *dev, + const struct resource *res); void __iomem *devm_of_iomap(struct device *dev, struct device_node *node, int index, diff --git a/lib/devres.c b/lib/devres.c index a14c727128c1..97fb44e5b4d6 100644 --- a/lib/devres.c +++ b/lib/devres.c @@ -169,6 +169,21 @@ void __iomem *devm_ioremap_resource(struct device *dev, } EXPORT_SYMBOL(devm_ioremap_resource); +/** + * devm_ioremap_resource_wc() - write-combined variant of + * devm_ioremap_resource() + * @dev: generic device to handle the resource for + * @res: resource to be handled + * + * Returns a pointer to the remapped memory or an ERR_PTR() encoded error code + * on failure. Usage example: + */ +void __iomem *devm_ioremap_resource_wc(struct device *dev, + const struct resource *res) +{ + return __devm_ioremap_resource(dev, res, DEVM_IOREMAP_WC); +} + /* * devm_of_iomap - Requests a resource and maps the memory mapped IO * for a given device_node managed by a given device -- cgit v1.2.3-59-g8ed1b From bb6243b4f73d29f8c8faf8f805a2042ac3973b71 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Tue, 22 Oct 2019 10:43:14 +0200 Subject: drivers: platform: provide devm_platform_ioremap_resource_wc() Provide a write-combined variant of devm_platform_ioremap_resource(). Signed-off-by: Bartosz Golaszewski Reviewed-by: Arnd Bergmann Link: https://lore.kernel.org/r/20191022084318.22256-5-brgl@bgdev.pl Signed-off-by: Greg Kroah-Hartman --- Documentation/driver-api/driver-model/devres.rst | 1 + drivers/base/platform.c | 19 ++++++++++++++++++- include/linux/platform_device.h | 3 +++ 3 files changed, 22 insertions(+), 1 deletion(-) (limited to 'Documentation/driver-api') diff --git a/Documentation/driver-api/driver-model/devres.rst b/Documentation/driver-api/driver-model/devres.rst index e605bb9df6e1..480b78ca3871 100644 --- a/Documentation/driver-api/driver-model/devres.rst +++ b/Documentation/driver-api/driver-model/devres.rst @@ -318,6 +318,7 @@ IOMAP devm_ioremap_resource() : checks resource, requests memory region, ioremaps devm_ioremap_resource_wc() devm_platform_ioremap_resource() : calls devm_ioremap_resource() for platform device + devm_platform_ioremap_resource_wc() devm_iounmap() pcim_iomap() pcim_iomap_regions() : do request_region() and iomap() on multiple BARs diff --git a/drivers/base/platform.c b/drivers/base/platform.c index e0ca682a756d..28eb71967f17 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -60,6 +60,7 @@ struct resource *platform_get_resource(struct platform_device *dev, } EXPORT_SYMBOL_GPL(platform_get_resource); +#ifdef CONFIG_HAS_IOMEM /** * devm_platform_ioremap_resource - call devm_ioremap_resource() for a platform * device @@ -68,7 +69,6 @@ EXPORT_SYMBOL_GPL(platform_get_resource); * resource management * @index: resource index */ -#ifdef CONFIG_HAS_IOMEM void __iomem *devm_platform_ioremap_resource(struct platform_device *pdev, unsigned int index) { @@ -78,6 +78,23 @@ void __iomem *devm_platform_ioremap_resource(struct platform_device *pdev, return devm_ioremap_resource(&pdev->dev, res); } EXPORT_SYMBOL_GPL(devm_platform_ioremap_resource); + +/** + * devm_platform_ioremap_resource_wc - write-combined variant of + * devm_platform_ioremap_resource() + * + * @pdev: platform device to use both for memory resource lookup as well as + * resource management + * @index: resource index + */ +void __iomem *devm_platform_ioremap_resource_wc(struct platform_device *pdev, + unsigned int index) +{ + struct resource *res; + + res = platform_get_resource(pdev, IORESOURCE_MEM, index); + return devm_ioremap_resource_wc(&pdev->dev, res); +} #endif /* CONFIG_HAS_IOMEM */ /** diff --git a/include/linux/platform_device.h b/include/linux/platform_device.h index 51fb7fc28587..91fcdbbae89d 100644 --- a/include/linux/platform_device.h +++ b/include/linux/platform_device.h @@ -57,6 +57,9 @@ platform_find_device_by_driver(struct device *start, extern void __iomem * devm_platform_ioremap_resource(struct platform_device *pdev, unsigned int index); +extern void __iomem * +devm_platform_ioremap_resource_wc(struct platform_device *pdev, + unsigned int index); extern int platform_get_irq(struct platform_device *, unsigned int); extern int platform_get_irq_optional(struct platform_device *, unsigned int); extern int platform_irq_count(struct platform_device *); -- cgit v1.2.3-59-g8ed1b From c9c8641d3ebd79274af75f7df3e6a9c6cc8a66e9 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Tue, 22 Oct 2019 10:43:16 +0200 Subject: drivers: provide devm_platform_ioremap_resource_byname() Provide a variant of devm_platform_ioremap_resource() that allows to lookup resources from platform devices by name rather than by index. Signed-off-by: Bartosz Golaszewski Reviewed-by: Arnd Bergmann Link: https://lore.kernel.org/r/20191022084318.22256-7-brgl@bgdev.pl Signed-off-by: Greg Kroah-Hartman --- Documentation/driver-api/driver-model/devres.rst | 1 + drivers/base/platform.c | 20 ++++++++++++++++++++ include/linux/platform_device.h | 3 +++ 3 files changed, 24 insertions(+) (limited to 'Documentation/driver-api') diff --git a/Documentation/driver-api/driver-model/devres.rst b/Documentation/driver-api/driver-model/devres.rst index 480b78ca3871..4ab193319d8c 100644 --- a/Documentation/driver-api/driver-model/devres.rst +++ b/Documentation/driver-api/driver-model/devres.rst @@ -319,6 +319,7 @@ IOMAP devm_ioremap_resource_wc() devm_platform_ioremap_resource() : calls devm_ioremap_resource() for platform device devm_platform_ioremap_resource_wc() + devm_platform_ioremap_resource_byname() devm_iounmap() pcim_iomap() pcim_iomap_regions() : do request_region() and iomap() on multiple BARs diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 28eb71967f17..1b8a20466eef 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -95,6 +95,26 @@ void __iomem *devm_platform_ioremap_resource_wc(struct platform_device *pdev, res = platform_get_resource(pdev, IORESOURCE_MEM, index); return devm_ioremap_resource_wc(&pdev->dev, res); } + +/** + * devm_platform_ioremap_resource_byname - call devm_ioremap_resource for + * a platform device, retrieve the + * resource by name + * + * @pdev: platform device to use both for memory resource lookup as well as + * resource management + * @name: name of the resource + */ +void __iomem * +devm_platform_ioremap_resource_byname(struct platform_device *pdev, + const char *name) +{ + struct resource *res; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, name); + return devm_ioremap_resource(&pdev->dev, res); +} +EXPORT_SYMBOL_GPL(devm_platform_ioremap_resource_byname); #endif /* CONFIG_HAS_IOMEM */ /** diff --git a/include/linux/platform_device.h b/include/linux/platform_device.h index 91fcdbbae89d..276a03c24691 100644 --- a/include/linux/platform_device.h +++ b/include/linux/platform_device.h @@ -60,6 +60,9 @@ devm_platform_ioremap_resource(struct platform_device *pdev, extern void __iomem * devm_platform_ioremap_resource_wc(struct platform_device *pdev, unsigned int index); +extern void __iomem * +devm_platform_ioremap_resource_byname(struct platform_device *pdev, + const char *name); extern int platform_get_irq(struct platform_device *, unsigned int); extern int platform_get_irq_optional(struct platform_device *, unsigned int); extern int platform_irq_count(struct platform_device *); -- cgit v1.2.3-59-g8ed1b