aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
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
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')
-rw-r--r--drivers/base/base.h1
-rw-r--r--drivers/base/core.c2
-rw-r--r--drivers/base/dd.c138
3 files changed, 140 insertions, 1 deletions
diff --git a/drivers/base/base.h b/drivers/base/base.h
index b858dfd9a37c..2c13deae5f82 100644
--- a/drivers/base/base.h
+++ b/drivers/base/base.h
@@ -105,6 +105,7 @@ extern void bus_remove_driver(struct device_driver *drv);
105 105
106extern void driver_detach(struct device_driver *drv); 106extern void driver_detach(struct device_driver *drv);
107extern int driver_probe_device(struct device_driver *drv, struct device *dev); 107extern int driver_probe_device(struct device_driver *drv, struct device *dev);
108extern void driver_deferred_probe_del(struct device *dev);
108static inline int driver_match_device(struct device_driver *drv, 109static inline int driver_match_device(struct device_driver *drv,
109 struct device *dev) 110 struct device *dev)
110{ 111{
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 74dda4f697f9..d4ff7adce38c 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -644,6 +644,7 @@ void device_initialize(struct device *dev)
644{ 644{
645 dev->kobj.kset = devices_kset; 645 dev->kobj.kset = devices_kset;
646 kobject_init(&dev->kobj, &device_ktype); 646 kobject_init(&dev->kobj, &device_ktype);
647 INIT_LIST_HEAD(&dev->deferred_probe);
647 INIT_LIST_HEAD(&dev->dma_pools); 648 INIT_LIST_HEAD(&dev->dma_pools);
648 mutex_init(&dev->mutex); 649 mutex_init(&dev->mutex);
649 lockdep_set_novalidate_class(&dev->mutex); 650 lockdep_set_novalidate_class(&dev->mutex);
@@ -1188,6 +1189,7 @@ void device_del(struct device *dev)
1188 device_remove_file(dev, &uevent_attr); 1189 device_remove_file(dev, &uevent_attr);
1189 device_remove_attrs(dev); 1190 device_remove_attrs(dev);
1190 bus_remove_device(dev); 1191 bus_remove_device(dev);
1192 driver_deferred_probe_del(dev);
1191 1193
1192 /* 1194 /*
1193 * Some platform devices are driven without driver attached 1195 * Some platform devices are driven without driver attached
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",