aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base/dd.c
diff options
context:
space:
mode:
authorGrant Likely <grant.likely@secretlab.ca>2012-03-05 10:47:41 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-03-08 14:53:13 -0500
commitd1c3414c2a9d10ef7f0f7665f5d2947cd088c093 (patch)
treebd33518d50f23adc2e55e7b4c99b6b1753a41a03 /drivers/base/dd.c
parentfef37e9a47b9927ce2817fe1a0fa8cf40f6eefb6 (diff)
drivercore: Add driver probe deferral mechanism
Allow drivers to report at probe time that they cannot get all the resources required by the device, and should be retried at a later time. This should completely solve the problem of getting devices initialized in the right order. Right now this is mostly handled by mucking about with initcall ordering which is a complete hack, and doesn't even remotely handle the case where device drivers are in modules. This approach completely sidesteps the issues by allowing driver registration to occur in any order, and any driver can request to be retried after a few more other drivers get probed. v4: - Integrate Manjunath's addition of a separate workqueue - Change -EAGAIN to -EPROBE_DEFER for drivers to trigger deferral - Update comment blocks to reflect how the code really works v3: - Hold off workqueue scheduling until late_initcall so that the bulk of driver probes are complete before we start retrying deferred devices. - Tested with simple use cases. Still needs more testing though. Using it to get rid of the gpio early_initcall madness, or to replace the ASoC internal probe deferral code would be ideal. v2: - added locking so it should no longer be utterly broken in that regard - remove device from deferred list at device_del time. - Still completely untested with any real use case, but has been boot tested. Signed-off-by: Grant Likely <grant.likely@secretlab.ca> Cc: Mark Brown <broonie@opensource.wolfsonmicro.com> Cc: Arnd Bergmann <arnd@arndb.de> Cc: Dilan Lee <dilee@nvidia.com> Cc: Manjunath GKondaiah <manjunath.gkondaiah@linaro.org> Cc: Alan Stern <stern@rowland.harvard.edu> Cc: Tony Lindgren <tony@atomide.com> Cc: Alan Cox <alan@lxorguk.ukuu.org.uk> Reviewed-by: Mark Brown <broonie@opensource.wolfsonmicro.com> Acked-by: David Daney <david.daney@cavium.com> Reviewed-by: Arnd Bergmann <arnd@arndb.de> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/base/dd.c')
-rw-r--r--drivers/base/dd.c138
1 files changed, 137 insertions, 1 deletions
diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index 142e3d600f14..442b7641a086 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -28,6 +28,133 @@
28#include "base.h" 28#include "base.h"
29#include "power/power.h" 29#include "power/power.h"
30 30
31/*
32 * Deferred Probe infrastructure.
33 *
34 * Sometimes driver probe order matters, but the kernel doesn't always have
35 * dependency information which means some drivers will get probed before a
36 * resource it depends on is available. For example, an SDHCI driver may
37 * first need a GPIO line from an i2c GPIO controller before it can be
38 * initialized. If a required resource is not available yet, a driver can
39 * request probing to be deferred by returning -EPROBE_DEFER from its probe hook
40 *
41 * Deferred probe maintains two lists of devices, a pending list and an active
42 * list. A driver returning -EPROBE_DEFER causes the device to be added to the
43 * pending list. A successful driver probe will trigger moving all devices
44 * from the pending to the active list so that the workqueue will eventually
45 * retry them.
46 *
47 * The deferred_probe_mutex must be held any time the deferred_probe_*_list
48 * of the (struct device*)->deferred_probe pointers are manipulated
49 */
50static DEFINE_MUTEX(deferred_probe_mutex);
51static LIST_HEAD(deferred_probe_pending_list);
52static LIST_HEAD(deferred_probe_active_list);
53static struct workqueue_struct *deferred_wq;
54
55/**
56 * deferred_probe_work_func() - Retry probing devices in the active list.
57 */
58static void deferred_probe_work_func(struct work_struct *work)
59{
60 struct device *dev;
61 /*
62 * This block processes every device in the deferred 'active' list.
63 * Each device is removed from the active list and passed to
64 * bus_probe_device() to re-attempt the probe. The loop continues
65 * until every device in the active list is removed and retried.
66 *
67 * Note: Once the device is removed from the list and the mutex is
68 * released, it is possible for the device get freed by another thread
69 * and cause a illegal pointer dereference. This code uses
70 * get/put_device() to ensure the device structure cannot disappear
71 * from under our feet.
72 */
73 mutex_lock(&deferred_probe_mutex);
74 while (!list_empty(&deferred_probe_active_list)) {
75 dev = list_first_entry(&deferred_probe_active_list,
76 typeof(*dev), deferred_probe);
77 list_del_init(&dev->deferred_probe);
78
79 get_device(dev);
80
81 /* Drop the mutex while probing each device; the probe path
82 * may manipulate the deferred list */
83 mutex_unlock(&deferred_probe_mutex);
84 dev_dbg(dev, "Retrying from deferred list\n");
85 bus_probe_device(dev);
86 mutex_lock(&deferred_probe_mutex);
87
88 put_device(dev);
89 }
90 mutex_unlock(&deferred_probe_mutex);
91}
92static DECLARE_WORK(deferred_probe_work, deferred_probe_work_func);
93
94static void driver_deferred_probe_add(struct device *dev)
95{
96 mutex_lock(&deferred_probe_mutex);
97 if (list_empty(&dev->deferred_probe)) {
98 dev_dbg(dev, "Added to deferred list\n");
99 list_add(&dev->deferred_probe, &deferred_probe_pending_list);
100 }
101 mutex_unlock(&deferred_probe_mutex);
102}
103
104void driver_deferred_probe_del(struct device *dev)
105{
106 mutex_lock(&deferred_probe_mutex);
107 if (!list_empty(&dev->deferred_probe)) {
108 dev_dbg(dev, "Removed from deferred list\n");
109 list_del_init(&dev->deferred_probe);
110 }
111 mutex_unlock(&deferred_probe_mutex);
112}
113
114static bool driver_deferred_probe_enable = false;
115/**
116 * driver_deferred_probe_trigger() - Kick off re-probing deferred devices
117 *
118 * This functions moves all devices from the pending list to the active
119 * list and schedules the deferred probe workqueue to process them. It
120 * should be called anytime a driver is successfully bound to a device.
121 */
122static void driver_deferred_probe_trigger(void)
123{
124 if (!driver_deferred_probe_enable)
125 return;
126
127 /* A successful probe means that all the devices in the pending list
128 * should be triggered to be reprobed. Move all the deferred devices
129 * into the active list so they can be retried by the workqueue */
130 mutex_lock(&deferred_probe_mutex);
131 list_splice_tail_init(&deferred_probe_pending_list,
132 &deferred_probe_active_list);
133 mutex_unlock(&deferred_probe_mutex);
134
135 /* Kick the re-probe thread. It may already be scheduled, but
136 * it is safe to kick it again. */
137 queue_work(deferred_wq, &deferred_probe_work);
138}
139
140/**
141 * deferred_probe_initcall() - Enable probing of deferred devices
142 *
143 * We don't want to get in the way when the bulk of drivers are getting probed.
144 * Instead, this initcall makes sure that deferred probing is delayed until
145 * late_initcall time.
146 */
147static int deferred_probe_initcall(void)
148{
149 deferred_wq = create_singlethread_workqueue("deferwq");
150 if (WARN_ON(!deferred_wq))
151 return -ENOMEM;
152
153 driver_deferred_probe_enable = true;
154 driver_deferred_probe_trigger();
155 return 0;
156}
157late_initcall(deferred_probe_initcall);
31 158
32static void driver_bound(struct device *dev) 159static void driver_bound(struct device *dev)
33{ 160{
@@ -42,6 +169,11 @@ static void driver_bound(struct device *dev)
42 169
43 klist_add_tail(&dev->p->knode_driver, &dev->driver->p->klist_devices); 170 klist_add_tail(&dev->p->knode_driver, &dev->driver->p->klist_devices);
44 171
172 /* Make sure the device is no longer in one of the deferred lists
173 * and kick off retrying all pending devices */
174 driver_deferred_probe_del(dev);
175 driver_deferred_probe_trigger();
176
45 if (dev->bus) 177 if (dev->bus)
46 blocking_notifier_call_chain(&dev->bus->p->bus_notifier, 178 blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
47 BUS_NOTIFY_BOUND_DRIVER, dev); 179 BUS_NOTIFY_BOUND_DRIVER, dev);
@@ -142,7 +274,11 @@ probe_failed:
142 driver_sysfs_remove(dev); 274 driver_sysfs_remove(dev);
143 dev->driver = NULL; 275 dev->driver = NULL;
144 276
145 if (ret != -ENODEV && ret != -ENXIO) { 277 if (ret == -EPROBE_DEFER) {
278 /* Driver requested deferred probing */
279 dev_info(dev, "Driver %s requests probe deferral\n", drv->name);
280 driver_deferred_probe_add(dev);
281 } else if (ret != -ENODEV && ret != -ENXIO) {
146 /* driver matched but the probe failed */ 282 /* driver matched but the probe failed */
147 printk(KERN_WARNING 283 printk(KERN_WARNING
148 "%s: probe of %s failed with error %d\n", 284 "%s: probe of %s failed with error %d\n",