summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVikram Mulukutla <markivx@codeaurora.org>2013-12-09 13:36:33 -0800
committerRohit Vaswani <rvaswani@codeaurora.org>2016-03-01 13:00:26 -0800
commita4234c60dbf0fd5d8c53befbdffcedaa30d4ec13 (patch)
tree9538bc5364853dc65e85468936e12a75f5537286
parent786761b2918512ad79d3e961751e7a337dc70120 (diff)
dd: Invoke one probe retry cycle after every initcall level
Drivers that are registered at an initcall level may have to wait until late_init before the probe deferral mechanism can retry their probe functions. It is possible that their dependencies were resolved much earlier, in some cases even before the next initcall level. Invoke one probe retry cycle at every _sync initcall level, allowing these drivers to be probed earlier. A real world example of how this change helps follows. On the MSM8974, there are 3 devices that need to be probed in order for the display driver to be able to probe and bring up a display panel. These are the gdsc_mdss (a regulator device), the mmsscc-dsi device (a display clock controller), and the dsipllcc device (a PLL controller). Here is a kernel log that shows these devices probing in the wrong order: [0.503253] mmsscc-dsi fd8c0000.qcom,mmsscc-dsi: Failed to get pixel source. -- [1] [0.505210] dsipllcc fd8c0000.qcom,dsipllcc: Failed to get MDSS GDSC -- [2] [0.523264] gdsc_mdss: no parameters -- [3] Only gdsc_mdss successfully probed at 0.52 seconds. Now without _this_ change, the current probe deferral mechanism results in the devices probing at or after late_init: [9.196006] dsipllcc fd8c0000.qcom,dsipllcc: Registered DSI PLL clocks. -- [2] [9.357440] mmsscc-dsi fd8c0000.qcom,mmsscc-dsi: Registered MMSSCC DSI clocks. -- [1] Thus the display can only be brought up after 9.35 seconds. However, by allowing a probe retry after each initcall level, this number reduces drastically: [0.608252] dsipllcc fd8c0000.qcom,dsipllcc: Registered DSI PLL clocks. -- [2] [0.613758] mmsscc-dsi fd8c0000.qcom,mmsscc-dsi: Registered MMSSCC DSI clocks.-- [1] Thus the display can be brought up just after 0.61 seconds. Change-Id: I83d8ac89e591e89e27934c0402449437b61b2124 Signed-off-by: Vikram Mulukutla <markivx@codeaurora.org>
-rw-r--r--drivers/base/dd.c41
1 files changed, 32 insertions, 9 deletions
diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index a641cf3ccad6..918ce439534b 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -171,26 +171,49 @@ static void driver_deferred_probe_trigger(void)
queue_work(deferred_wq, &deferred_probe_work);
}
+static void enable_trigger_defer_cycle(void)
+{
+ driver_deferred_probe_enable = true;
+ driver_deferred_probe_trigger();
+ /*
+ * Sort as many dependencies as possible before the next initcall
+ * level
+ */
+ flush_workqueue(deferred_wq);
+}
+
/**
* deferred_probe_initcall() - Enable probing of deferred devices
*
* We don't want to get in the way when the bulk of drivers are getting probed.
* Instead, this initcall makes sure that deferred probing is delayed until
- * late_initcall time.
+ * all the registered initcall functions at a particular level are completed.
+ * This function is invoked at every *_initcall_sync level.
*/
static int deferred_probe_initcall(void)
{
- deferred_wq = create_singlethread_workqueue("deferwq");
- if (WARN_ON(!deferred_wq))
- return -ENOMEM;
+ if (!deferred_wq) {
+ deferred_wq = create_singlethread_workqueue("deferwq");
+ if (WARN_ON(!deferred_wq))
+ return -ENOMEM;
+ }
- driver_deferred_probe_enable = true;
- driver_deferred_probe_trigger();
- /* Sort as many dependencies as possible before exiting initcalls */
- flush_workqueue(deferred_wq);
+ enable_trigger_defer_cycle();
+ driver_deferred_probe_enable = false;
+ return 0;
+}
+arch_initcall_sync(deferred_probe_initcall);
+subsys_initcall_sync(deferred_probe_initcall);
+fs_initcall_sync(deferred_probe_initcall);
+device_initcall_sync(deferred_probe_initcall);
+
+static int deferred_probe_enable_fn(void)
+{
+ /* Enable deferred probing for all time */
+ enable_trigger_defer_cycle();
return 0;
}
-late_initcall(deferred_probe_initcall);
+late_initcall(deferred_probe_enable_fn);
static void driver_bound(struct device *dev)
{