|
@@ -52,6 +52,7 @@ static DEFINE_MUTEX(deferred_probe_mutex);
|
|
|
static LIST_HEAD(deferred_probe_pending_list);
|
|
|
static LIST_HEAD(deferred_probe_active_list);
|
|
|
static struct workqueue_struct *deferred_wq;
|
|
|
+static atomic_t deferred_trigger_count = ATOMIC_INIT(0);
|
|
|
|
|
|
/**
|
|
|
* deferred_probe_work_func() - Retry probing devices in the active list.
|
|
@@ -135,6 +136,17 @@ static bool driver_deferred_probe_enable = false;
|
|
|
* This functions moves all devices from the pending list to the active
|
|
|
* list and schedules the deferred probe workqueue to process them. It
|
|
|
* should be called anytime a driver is successfully bound to a device.
|
|
|
+ *
|
|
|
+ * Note, there is a race condition in multi-threaded probe. In the case where
|
|
|
+ * more than one device is probing at the same time, it is possible for one
|
|
|
+ * probe to complete successfully while another is about to defer. If the second
|
|
|
+ * depends on the first, then it will get put on the pending list after the
|
|
|
+ * trigger event has already occured and will be stuck there.
|
|
|
+ *
|
|
|
+ * The atomic 'deferred_trigger_count' is used to determine if a successful
|
|
|
+ * trigger has occurred in the midst of probing a driver. If the trigger count
|
|
|
+ * changes in the midst of a probe, then deferred processing should be triggered
|
|
|
+ * again.
|
|
|
*/
|
|
|
static void driver_deferred_probe_trigger(void)
|
|
|
{
|
|
@@ -147,6 +159,7 @@ static void driver_deferred_probe_trigger(void)
|
|
|
* into the active list so they can be retried by the workqueue
|
|
|
*/
|
|
|
mutex_lock(&deferred_probe_mutex);
|
|
|
+ atomic_inc(&deferred_trigger_count);
|
|
|
list_splice_tail_init(&deferred_probe_pending_list,
|
|
|
&deferred_probe_active_list);
|
|
|
mutex_unlock(&deferred_probe_mutex);
|
|
@@ -265,6 +278,7 @@ static DECLARE_WAIT_QUEUE_HEAD(probe_waitqueue);
|
|
|
static int really_probe(struct device *dev, struct device_driver *drv)
|
|
|
{
|
|
|
int ret = 0;
|
|
|
+ int local_trigger_count = atomic_read(&deferred_trigger_count);
|
|
|
|
|
|
atomic_inc(&probe_count);
|
|
|
pr_debug("bus: '%s': %s: probing driver %s with device %s\n",
|
|
@@ -310,6 +324,9 @@ probe_failed:
|
|
|
/* Driver requested deferred probing */
|
|
|
dev_info(dev, "Driver %s requests probe deferral\n", drv->name);
|
|
|
driver_deferred_probe_add(dev);
|
|
|
+ /* Did a trigger occur while probing? Need to re-trigger if yes */
|
|
|
+ if (local_trigger_count != atomic_read(&deferred_trigger_count))
|
|
|
+ driver_deferred_probe_trigger();
|
|
|
} else if (ret != -ENODEV && ret != -ENXIO) {
|
|
|
/* driver matched but the probe failed */
|
|
|
printk(KERN_WARNING
|