|
@@ -55,6 +55,7 @@ static LIST_HEAD(deferred_probe_pending_list);
|
|
static LIST_HEAD(deferred_probe_active_list);
|
|
static LIST_HEAD(deferred_probe_active_list);
|
|
static atomic_t deferred_trigger_count = ATOMIC_INIT(0);
|
|
static atomic_t deferred_trigger_count = ATOMIC_INIT(0);
|
|
static struct dentry *deferred_devices;
|
|
static struct dentry *deferred_devices;
|
|
|
|
+static bool initcalls_done;
|
|
|
|
|
|
/*
|
|
/*
|
|
* In some cases, like suspend to RAM or hibernation, It might be reasonable
|
|
* In some cases, like suspend to RAM or hibernation, It might be reasonable
|
|
@@ -219,6 +220,51 @@ static int deferred_devs_show(struct seq_file *s, void *data)
|
|
}
|
|
}
|
|
DEFINE_SHOW_ATTRIBUTE(deferred_devs);
|
|
DEFINE_SHOW_ATTRIBUTE(deferred_devs);
|
|
|
|
|
|
|
|
+static int deferred_probe_timeout = -1;
|
|
|
|
+static int __init deferred_probe_timeout_setup(char *str)
|
|
|
|
+{
|
|
|
|
+ deferred_probe_timeout = simple_strtol(str, NULL, 10);
|
|
|
|
+ return 1;
|
|
|
|
+}
|
|
|
|
+__setup("deferred_probe_timeout=", deferred_probe_timeout_setup);
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * driver_deferred_probe_check_state() - Check deferred probe state
|
|
|
|
+ * @dev: device to check
|
|
|
|
+ *
|
|
|
|
+ * Returns -ENODEV if init is done and all built-in drivers have had a chance
|
|
|
|
+ * to probe (i.e. initcalls are done), -ETIMEDOUT if deferred probe debug
|
|
|
|
+ * timeout has expired, or -EPROBE_DEFER if none of those conditions are met.
|
|
|
|
+ *
|
|
|
|
+ * Drivers or subsystems can opt-in to calling this function instead of directly
|
|
|
|
+ * returning -EPROBE_DEFER.
|
|
|
|
+ */
|
|
|
|
+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;
|
|
|
|
+ }
|
|
|
|
+ return -EPROBE_DEFER;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void deferred_probe_timeout_work_func(struct work_struct *work)
|
|
|
|
+{
|
|
|
|
+ struct device_private *private, *p;
|
|
|
|
+
|
|
|
|
+ deferred_probe_timeout = 0;
|
|
|
|
+ driver_deferred_probe_trigger();
|
|
|
|
+ flush_work(&deferred_probe_work);
|
|
|
|
+
|
|
|
|
+ list_for_each_entry_safe(private, p, &deferred_probe_pending_list, deferred_probe)
|
|
|
|
+ dev_info(private->device, "deferred probe pending");
|
|
|
|
+}
|
|
|
|
+static DECLARE_DELAYED_WORK(deferred_probe_timeout_work, deferred_probe_timeout_work_func);
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* deferred_probe_initcall() - Enable probing of deferred devices
|
|
* deferred_probe_initcall() - Enable probing of deferred devices
|
|
*
|
|
*
|
|
@@ -235,6 +281,19 @@ static int deferred_probe_initcall(void)
|
|
driver_deferred_probe_trigger();
|
|
driver_deferred_probe_trigger();
|
|
/* Sort as many dependencies as possible before exiting initcalls */
|
|
/* Sort as many dependencies as possible before exiting initcalls */
|
|
flush_work(&deferred_probe_work);
|
|
flush_work(&deferred_probe_work);
|
|
|
|
+ initcalls_done = true;
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * Trigger deferred probe again, this time we won't defer anything
|
|
|
|
+ * that is optional
|
|
|
|
+ */
|
|
|
|
+ driver_deferred_probe_trigger();
|
|
|
|
+ flush_work(&deferred_probe_work);
|
|
|
|
+
|
|
|
|
+ if (deferred_probe_timeout > 0) {
|
|
|
|
+ schedule_delayed_work(&deferred_probe_timeout_work,
|
|
|
|
+ deferred_probe_timeout * HZ);
|
|
|
|
+ }
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
late_initcall(deferred_probe_initcall);
|
|
late_initcall(deferred_probe_initcall);
|