Merge tag 'driver-core-5.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-2.6-microblaze.git] / drivers / base / dd.c
index 94b7ac9..5443b09 100644 (file)
@@ -60,6 +60,7 @@ static bool initcalls_done;
 /* Save the async probe drivers' name from kernel cmdline */
 #define ASYNC_DRV_NAMES_MAX_LEN        256
 static char async_probe_drv_names[ASYNC_DRV_NAMES_MAX_LEN];
+static bool async_probe_default;
 
 /*
  * In some cases, like suspend to RAM or hibernation, It might be reasonable
@@ -255,7 +256,12 @@ static int deferred_devs_show(struct seq_file *s, void *data)
 }
 DEFINE_SHOW_ATTRIBUTE(deferred_devs);
 
+#ifdef CONFIG_MODULES
+int driver_deferred_probe_timeout = 10;
+#else
 int driver_deferred_probe_timeout;
+#endif
+
 EXPORT_SYMBOL_GPL(driver_deferred_probe_timeout);
 static DECLARE_WAIT_QUEUE_HEAD(probe_timeout_waitqueue);
 
@@ -274,10 +280,10 @@ __setup("deferred_probe_timeout=", deferred_probe_timeout_setup);
  * @dev: device to check
  *
  * Return:
- * -ENODEV if initcalls have completed and modules are disabled.
- * -ETIMEDOUT if the deferred probe timeout was set and has expired
- *  and modules are enabled.
- * -EPROBE_DEFER in other cases.
+ * -ENODEV if initcalls have completed and modules are disabled.
+ * -ETIMEDOUT if the deferred probe timeout was set and has expired
+ *   and modules are enabled.
+ * -EPROBE_DEFER in other cases.
  *
  * Drivers or subsystems can opt-in to calling this function instead of directly
  * returning -EPROBE_DEFER.
@@ -316,6 +322,20 @@ static void deferred_probe_timeout_work_func(struct work_struct *work)
 }
 static DECLARE_DELAYED_WORK(deferred_probe_timeout_work, deferred_probe_timeout_work_func);
 
+void deferred_probe_extend_timeout(void)
+{
+       /*
+        * If the work hasn't been queued yet or if the work expired, don't
+        * start a new one.
+        */
+       if (cancel_delayed_work(&deferred_probe_timeout_work)) {
+               schedule_delayed_work(&deferred_probe_timeout_work,
+                               driver_deferred_probe_timeout * HZ);
+               pr_debug("Extended deferred probe timeout by %d secs\n",
+                                       driver_deferred_probe_timeout);
+       }
+}
+
 /**
  * deferred_probe_initcall() - Enable probing of deferred devices
  *
@@ -799,7 +819,11 @@ static int driver_probe_device(struct device_driver *drv, struct device *dev)
 
 static inline bool cmdline_requested_async_probing(const char *drv_name)
 {
-       return parse_option_str(async_probe_drv_names, drv_name);
+       bool async_drv;
+
+       async_drv = parse_option_str(async_probe_drv_names, drv_name);
+
+       return (async_probe_default != async_drv);
 }
 
 /* The option format is "driver_async_probe=drv_name1,drv_name2,..." */
@@ -809,6 +833,8 @@ static int __init save_async_options(char *buf)
                pr_warn("Too long list of driver names for 'driver_async_probe'!\n");
 
        strlcpy(async_probe_drv_names, buf, ASYNC_DRV_NAMES_MAX_LEN);
+       async_probe_default = parse_option_str(async_probe_drv_names, "*");
+
        return 1;
 }
 __setup("driver_async_probe=", save_async_options);
@@ -943,6 +969,7 @@ out_unlock:
 static int __device_attach(struct device *dev, bool allow_async)
 {
        int ret = 0;
+       bool async = false;
 
        device_lock(dev);
        if (dev->p->dead) {
@@ -981,7 +1008,7 @@ static int __device_attach(struct device *dev, bool allow_async)
                         */
                        dev_dbg(dev, "scheduling asynchronous probe\n");
                        get_device(dev);
-                       async_schedule_dev(__device_attach_async_helper, dev);
+                       async = true;
                } else {
                        pm_request_idle(dev);
                }
@@ -991,6 +1018,8 @@ static int __device_attach(struct device *dev, bool allow_async)
        }
 out_unlock:
        device_unlock(dev);
+       if (async)
+               async_schedule_dev(__device_attach_async_helper, dev);
        return ret;
 }
 
@@ -1084,6 +1113,7 @@ static void __driver_attach_async_helper(void *_dev, async_cookie_t cookie)
 
        __device_driver_lock(dev, dev->parent);
        drv = dev->p->async_driver;
+       dev->p->async_driver = NULL;
        ret = driver_probe_device(drv, dev);
        __device_driver_unlock(dev, dev->parent);
 
@@ -1130,7 +1160,7 @@ static int __driver_attach(struct device *dev, void *data)
                 */
                dev_dbg(dev, "probing driver %s asynchronously\n", drv->name);
                device_lock(dev);
-               if (!dev->driver) {
+               if (!dev->driver && !dev->p->async_driver) {
                        get_device(dev);
                        dev->p->async_driver = drv;
                        async_schedule_dev(__driver_attach_async_helper, dev);