| From 98e96cf80045a383fcc47c58dd4e87b3ae587b3e Mon Sep 17 00:00:00 2001 |
| From: Saravana Kannan <saravanak@google.com> |
| Date: Tue, 28 Sep 2021 17:07:33 -0700 |
| Subject: drivers: bus: simple-pm-bus: Add support for probing simple bus only devices |
| |
| From: Saravana Kannan <saravanak@google.com> |
| |
| commit 98e96cf80045a383fcc47c58dd4e87b3ae587b3e upstream. |
| |
| fw_devlink could end up creating device links for bus only devices. |
| However, bus only devices don't get probed and can block probe() or |
| sync_state() [1] call backs of other devices. To avoid this, probe these |
| devices using the simple-pm-bus driver. |
| |
| However, there are instances of devices that are not simple buses (they get |
| probed by their specific drivers) that also list the "simple-bus" (or other |
| bus only compatible strings) in their compatible property to automatically |
| populate their child devices. We still want these devices to get probed by |
| their specific drivers. So, we make sure this driver only probes devices |
| that are only buses. |
| |
| [1] - https://lore.kernel.org/lkml/CAPDyKFo9Bxremkb1dDrr4OcXSpE0keVze94Cm=zrkOVxHHxBmQ@mail.gmail.com/ |
| |
| Fixes: c442a0d18744 ("driver core: Set fw_devlink to "permissive" behavior by default") |
| Cc: stable <stable@vger.kernel.org> |
| Cc: Rob Herring <robh+dt@kernel.org> |
| Tested-by: Saravana Kannan <saravanak@google.com> |
| Tested-by: Ulf Hansson <ulf.hansson@linaro.org> |
| Tested-by: Geert Uytterhoeven <geert+renesas@glider.be> |
| Tested-by: Damien Le Moal <damien.lemoal@wdc.com> |
| Signed-off-by: Saravana Kannan <saravanak@google.com> |
| Link: https://lore.kernel.org/r/20210929000735.585237-2-saravanak@google.com |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| drivers/bus/simple-pm-bus.c | 39 ++++++++++++++++++++++++++++++++++++++- |
| 1 file changed, 38 insertions(+), 1 deletion(-) |
| |
| --- a/drivers/bus/simple-pm-bus.c |
| +++ b/drivers/bus/simple-pm-bus.c |
| @@ -16,7 +16,33 @@ |
| |
| static int simple_pm_bus_probe(struct platform_device *pdev) |
| { |
| - struct device_node *np = pdev->dev.of_node; |
| + const struct device *dev = &pdev->dev; |
| + struct device_node *np = dev->of_node; |
| + const struct of_device_id *match; |
| + |
| + /* |
| + * Allow user to use driver_override to bind this driver to a |
| + * transparent bus device which has a different compatible string |
| + * that's not listed in simple_pm_bus_of_match. We don't want to do any |
| + * of the simple-pm-bus tasks for these devices, so return early. |
| + */ |
| + if (pdev->driver_override) |
| + return 0; |
| + |
| + match = of_match_device(dev->driver->of_match_table, dev); |
| + /* |
| + * These are transparent bus devices (not simple-pm-bus matches) that |
| + * have their child nodes populated automatically. So, don't need to |
| + * do anything more. We only match with the device if this driver is |
| + * the most specific match because we don't want to incorrectly bind to |
| + * a device that has a more specific driver. |
| + */ |
| + if (match && match->data) { |
| + if (of_property_match_string(np, "compatible", match->compatible) == 0) |
| + return 0; |
| + else |
| + return -ENODEV; |
| + } |
| |
| dev_dbg(&pdev->dev, "%s\n", __func__); |
| |
| @@ -30,14 +56,25 @@ static int simple_pm_bus_probe(struct pl |
| |
| static int simple_pm_bus_remove(struct platform_device *pdev) |
| { |
| + const void *data = of_device_get_match_data(&pdev->dev); |
| + |
| + if (pdev->driver_override || data) |
| + return 0; |
| + |
| dev_dbg(&pdev->dev, "%s\n", __func__); |
| |
| pm_runtime_disable(&pdev->dev); |
| return 0; |
| } |
| |
| +#define ONLY_BUS ((void *) 1) /* Match if the device is only a bus. */ |
| + |
| static const struct of_device_id simple_pm_bus_of_match[] = { |
| { .compatible = "simple-pm-bus", }, |
| + { .compatible = "simple-bus", .data = ONLY_BUS }, |
| + { .compatible = "simple-mfd", .data = ONLY_BUS }, |
| + { .compatible = "isa", .data = ONLY_BUS }, |
| + { .compatible = "arm,amba-bus", .data = ONLY_BUS }, |
| { /* sentinel */ } |
| }; |
| MODULE_DEVICE_TABLE(of, simple_pm_bus_of_match); |