*     binding of drivers which were unable to get all the resources needed by
  *     the device; typically because it depends on another driver getting
  *     probed first.
+ * @async_driver - pointer to device driver awaiting probe via async_probe
  * @device - pointer back to the struct device that this structure is
  * associated with.
  * @dead - This device is currently either in the process of or has been
        struct klist_node knode_bus;
        struct klist_node knode_class;
        struct list_head deferred_probe;
+       struct device_driver *async_driver;
        struct device *device;
        u8 dead:1;
 };
 
 }
 static DRIVER_ATTR_WO(uevent);
 
-static void driver_attach_async(void *_drv, async_cookie_t cookie)
-{
-       struct device_driver *drv = _drv;
-       int ret;
-
-       ret = driver_attach(drv);
-
-       pr_debug("bus: '%s': driver %s async attach completed: %d\n",
-                drv->bus->name, drv->name, ret);
-}
-
 /**
  * bus_add_driver - Add a driver to the bus.
  * @drv: driver.
 
        klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
        if (drv->bus->p->drivers_autoprobe) {
-               if (driver_allows_async_probing(drv)) {
-                       pr_debug("bus: '%s': probing driver %s asynchronously\n",
-                               drv->bus->name, drv->name);
-                       async_schedule(driver_attach_async, drv);
-               } else {
-                       error = driver_attach(drv);
-                       if (error)
-                               goto out_unregister;
-               }
+               error = driver_attach(drv);
+               if (error)
+                       goto out_unregister;
        }
        module_add_driver(drv->owner, drv);
 
 
        return ret;
 }
 
+static void __driver_attach_async_helper(void *_dev, async_cookie_t cookie)
+{
+       struct device *dev = _dev;
+       struct device_driver *drv;
+       int ret = 0;
+
+       __device_driver_lock(dev, dev->parent);
+
+       drv = dev->p->async_driver;
+
+       /*
+        * If device has been removed or someone has already successfully
+        * bound a driver before us just skip the driver probe call.
+        */
+       if (!dev->p->dead && !dev->driver)
+               ret = driver_probe_device(drv, dev);
+
+       __device_driver_unlock(dev, dev->parent);
+
+       dev_dbg(dev, "driver %s async attach completed: %d\n", drv->name, ret);
+
+       put_device(dev);
+}
+
 static int __driver_attach(struct device *dev, void *data)
 {
        struct device_driver *drv = data;
                return ret;
        } /* ret > 0 means positive match */
 
+       if (driver_allows_async_probing(drv)) {
+               /*
+                * Instead of probing the device synchronously we will
+                * probe it asynchronously to allow for more parallelism.
+                *
+                * We only take the device lock here in order to guarantee
+                * that the dev->driver and async_driver fields are protected
+                */
+               dev_dbg(dev, "probing driver %s asynchronously\n", drv->name);
+               device_lock(dev);
+               if (!dev->driver) {
+                       get_device(dev);
+                       dev->p->async_driver = drv;
+                       async_schedule(__driver_attach_async_helper, dev);
+               }
+               device_unlock(dev);
+               return 0;
+       }
+
        device_driver_attach(drv, dev);
 
        return 0;