aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/base/dd.c55
-rw-r--r--drivers/pinctrl/devicetree.c7
-rw-r--r--include/linux/device.h1
3 files changed, 51 insertions, 12 deletions
diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index 0df9b4461766..994a90747420 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -235,6 +235,19 @@ static int __init deferred_probe_timeout_setup(char *str)
}
__setup("deferred_probe_timeout=", deferred_probe_timeout_setup);
+static int __driver_deferred_probe_check_state(struct device *dev)
+{
+ if (!initcalls_done)
+ return -EPROBE_DEFER;
+
+ if (!deferred_probe_timeout) {
+ dev_WARN(dev, "deferred probe timeout, ignoring dependency");
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
/**
* driver_deferred_probe_check_state() - Check deferred probe state
* @dev: device to check
@@ -248,14 +261,40 @@ __setup("deferred_probe_timeout=", deferred_probe_timeout_setup);
*/
int driver_deferred_probe_check_state(struct device *dev)
{
- if (initcalls_done) {
- if (!deferred_probe_timeout) {
- dev_WARN(dev, "deferred probe timeout, ignoring dependency");
- return -ETIMEDOUT;
- }
- dev_warn(dev, "ignoring dependency for device, assuming no driver");
- return -ENODEV;
- }
+ int ret;
+
+ ret = __driver_deferred_probe_check_state(dev);
+ if (ret < 0)
+ return ret;
+
+ dev_warn(dev, "ignoring dependency for device, assuming no driver");
+
+ return -ENODEV;
+}
+
+/**
+ * driver_deferred_probe_check_state_continue() - check deferred probe state
+ * @dev: device to check
+ *
+ * Returns -ETIMEDOUT if deferred probe debug timeout has expired, or
+ * -EPROBE_DEFER otherwise.
+ *
+ * Drivers or subsystems can opt-in to calling this function instead of
+ * directly returning -EPROBE_DEFER.
+ *
+ * This is similar to driver_deferred_probe_check_state(), but it allows the
+ * subsystem to keep deferring probe after built-in drivers have had a chance
+ * to probe. One scenario where that is useful is if built-in drivers rely on
+ * resources that are provided by modular drivers.
+ */
+int driver_deferred_probe_check_state_continue(struct device *dev)
+{
+ int ret;
+
+ ret = __driver_deferred_probe_check_state(dev);
+ if (ret < 0)
+ return ret;
+
return -EPROBE_DEFER;
}
diff --git a/drivers/pinctrl/devicetree.c b/drivers/pinctrl/devicetree.c
index f7e354f85518..88ddbb2e30de 100644
--- a/drivers/pinctrl/devicetree.c
+++ b/drivers/pinctrl/devicetree.c
@@ -112,12 +112,11 @@ static int dt_to_map_one_config(struct pinctrl *p,
np_pctldev = of_get_next_parent(np_pctldev);
if (!np_pctldev || of_node_is_root(np_pctldev)) {
of_node_put(np_pctldev);
- ret = driver_deferred_probe_check_state(p->dev);
/* keep deferring if modules are enabled unless we've timed out */
- if (IS_ENABLED(CONFIG_MODULES) && !allow_default && ret == -ENODEV)
- ret = -EPROBE_DEFER;
+ if (IS_ENABLED(CONFIG_MODULES) && !allow_default)
+ return driver_deferred_probe_check_state_continue(p->dev);
- return ret;
+ return driver_deferred_probe_check_state(p->dev);
}
/* If we're creating a hog we can use the passed pctldev */
if (hog_pctldev && (np_pctldev == p->dev->of_node)) {
diff --git a/include/linux/device.h b/include/linux/device.h
index 709308560d32..ef61e2d50ecc 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -343,6 +343,7 @@ struct device *driver_find_device(struct device_driver *drv,
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);
/**
* struct subsys_interface - interfaces to device functions