driver core: Better distinguish probe errors in really_probe
[linux-2.6-microblaze.git] / drivers / base / dd.c
index ecd7cf8..fd83817 100644 (file)
@@ -513,12 +513,44 @@ static ssize_t state_synced_show(struct device *dev,
 }
 static DEVICE_ATTR_RO(state_synced);
 
+
+static int call_driver_probe(struct device *dev, struct device_driver *drv)
+{
+       int ret = 0;
+
+       if (dev->bus->probe)
+               ret = dev->bus->probe(dev);
+       else if (drv->probe)
+               ret = drv->probe(dev);
+
+       switch (ret) {
+       case 0:
+               break;
+       case -EPROBE_DEFER:
+               /* Driver requested deferred probing */
+               dev_dbg(dev, "Driver %s requests probe deferral\n", drv->name);
+               break;
+       case -ENODEV:
+       case -ENXIO:
+               pr_debug("%s: probe of %s rejects match %d\n",
+                        drv->name, dev_name(dev), ret);
+               break;
+       default:
+               /* driver matched but the probe failed */
+               pr_warn("%s: probe of %s failed with error %d\n",
+                       drv->name, dev_name(dev), ret);
+               break;
+       }
+
+       return ret;
+}
+
 static int really_probe(struct device *dev, struct device_driver *drv)
 {
-       int ret = -EPROBE_DEFER;
        int local_trigger_count = atomic_read(&deferred_trigger_count);
        bool test_remove = IS_ENABLED(CONFIG_DEBUG_TEST_DRIVER_REMOVE) &&
                           !drv->suppress_bind_attrs;
+       int ret = -EPROBE_DEFER, probe_ret = 0;
 
        if (defer_all_probes) {
                /*
@@ -572,14 +604,14 @@ re_probe:
                        goto probe_failed;
        }
 
-       if (dev->bus->probe) {
-               ret = dev->bus->probe(dev);
-               if (ret)
-                       goto probe_failed;
-       } else if (drv->probe) {
-               ret = drv->probe(dev);
-               if (ret)
-                       goto probe_failed;
+       probe_ret = call_driver_probe(dev, drv);
+       if (probe_ret) {
+               /*
+                * Ignore errors returned by ->probe so that the next driver can
+                * try its luck.
+                */
+               ret = 0;
+               goto probe_failed;
        }
 
        if (device_add_groups(dev, drv->dev_groups)) {
@@ -650,28 +682,8 @@ pinctrl_bind_failed:
                dev->pm_domain->dismiss(dev);
        pm_runtime_reinit(dev);
        dev_pm_set_driver_flags(dev, 0);
-
-       switch (ret) {
-       case -EPROBE_DEFER:
-               /* Driver requested deferred probing */
-               dev_dbg(dev, "Driver %s requests probe deferral\n", drv->name);
+       if (probe_ret == -EPROBE_DEFER)
                driver_deferred_probe_add_trigger(dev, local_trigger_count);
-               break;
-       case -ENODEV:
-       case -ENXIO:
-               pr_debug("%s: probe of %s rejects match %d\n",
-                        drv->name, dev_name(dev), ret);
-               break;
-       default:
-               /* driver matched but the probe failed */
-               pr_warn("%s: probe of %s failed with error %d\n",
-                       drv->name, dev_name(dev), ret);
-       }
-       /*
-        * Ignore errors returned by ->probe so that the next driver can try
-        * its luck.
-        */
-       ret = 0;
 done:
        atomic_dec(&probe_count);
        wake_up_all(&probe_waitqueue);
@@ -733,8 +745,9 @@ EXPORT_SYMBOL_GPL(wait_for_device_probe);
  * @drv: driver to bind a device to
  * @dev: device to try to bind to the driver
  *
- * This function returns -ENODEV if the device is not registered,
- * 1 if the device is bound successfully and 0 otherwise.
+ * This function returns -ENODEV if the device is not registered, -EBUSY if it
+ * already has a driver, and 1 if the device is bound successfully and 0
+ * otherwise.
  *
  * This function must be called with @dev lock held.  When called for a
  * USB interface, @dev->parent lock must be held as well.
@@ -745,8 +758,10 @@ static int driver_probe_device(struct device_driver *drv, struct device *dev)
 {
        int ret = 0;
 
-       if (!device_is_registered(dev))
+       if (dev->p->dead || !device_is_registered(dev))
                return -ENODEV;
+       if (dev->driver)
+               return -EBUSY;
 
        dev->can_match = true;
        pr_debug("bus: '%s': %s: matched device %s with driver %s\n",
@@ -1027,17 +1042,10 @@ static void __device_driver_unlock(struct device *dev, struct device *parent)
  */
 int device_driver_attach(struct device_driver *drv, struct device *dev)
 {
-       int ret = 0;
+       int ret;
 
        __device_driver_lock(dev, dev->parent);
-
-       /*
-        * 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);
-
+       ret = driver_probe_device(drv, dev);
        __device_driver_unlock(dev, dev->parent);
 
        return ret;
@@ -1047,19 +1055,11 @@ static void __driver_attach_async_helper(void *_dev, async_cookie_t cookie)
 {
        struct device *dev = _dev;
        struct device_driver *drv;
-       int ret = 0;
+       int ret;
 
        __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);
-
+       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);