Documentation: rockchip-dw-mshc: add description for rk3399
[firefly-linux-kernel-4.4.55.git] / drivers / base / bus.c
index d414331b480e72afc9ac8ac505dee449f1c795d9..500592486e8832cfd61673302359cc352b51efa0 100644 (file)
@@ -10,6 +10,7 @@
  *
  */
 
+#include <linux/async.h>
 #include <linux/device.h>
 #include <linux/module.h>
 #include <linux/errno.h>
@@ -17,6 +18,7 @@
 #include <linux/init.h>
 #include <linux/string.h>
 #include <linux/mutex.h>
+#include <linux/sysfs.h>
 #include "base.h"
 #include "power/power.h"
 
@@ -145,8 +147,19 @@ void bus_remove_file(struct bus_type *bus, struct bus_attribute *attr)
 }
 EXPORT_SYMBOL_GPL(bus_remove_file);
 
+static void bus_release(struct kobject *kobj)
+{
+       struct subsys_private *priv =
+               container_of(kobj, typeof(*priv), subsys.kobj);
+       struct bus_type *bus = priv->bus;
+
+       kfree(priv);
+       bus->p = NULL;
+}
+
 static struct kobj_type bus_ktype = {
        .sysfs_ops      = &bus_sysfs_ops,
+       .release        = bus_release,
 };
 
 static int bus_uevent_filter(struct kset *kset, struct kobject *kobj)
@@ -165,8 +178,8 @@ static const struct kset_uevent_ops bus_uevent_ops = {
 static struct kset *bus_kset;
 
 /* Manually detach a device from its associated driver. */
-static ssize_t driver_unbind(struct device_driver *drv,
-                            const char *buf, size_t count)
+static ssize_t unbind_store(struct device_driver *drv, const char *buf,
+                           size_t count)
 {
        struct bus_type *bus = bus_get(drv->bus);
        struct device *dev;
@@ -185,15 +198,15 @@ static ssize_t driver_unbind(struct device_driver *drv,
        bus_put(bus);
        return err;
 }
-static DRIVER_ATTR(unbind, S_IWUSR, NULL, driver_unbind);
+static DRIVER_ATTR_WO(unbind);
 
 /*
  * Manually attach a device to a driver.
  * Note: the driver must want to bind to the device,
  * it is not possible to override the driver's id table.
  */
-static ssize_t driver_bind(struct device_driver *drv,
-                          const char *buf, size_t count)
+static ssize_t bind_store(struct device_driver *drv, const char *buf,
+                         size_t count)
 {
        struct bus_type *bus = bus_get(drv->bus);
        struct device *dev;
@@ -221,7 +234,7 @@ static ssize_t driver_bind(struct device_driver *drv,
        bus_put(bus);
        return err;
 }
-static DRIVER_ATTR(bind, S_IWUSR, NULL, driver_bind);
+static DRIVER_ATTR_WO(bind);
 
 static ssize_t show_drivers_autoprobe(struct bus_type *bus, char *buf)
 {
@@ -242,13 +255,15 @@ static ssize_t store_drivers_probe(struct bus_type *bus,
                                   const char *buf, size_t count)
 {
        struct device *dev;
+       int err = -EINVAL;
 
        dev = bus_find_device_by_name(bus, NULL, buf);
        if (!dev)
                return -ENODEV;
-       if (bus_rescan_devices_helper(dev, NULL) != 0)
-               return -EINVAL;
-       return count;
+       if (bus_rescan_devices_helper(dev, NULL) == 0)
+               err = count;
+       put_device(dev);
+       return err;
 }
 
 static struct device *next_device(struct klist_iter *i)
@@ -460,7 +475,7 @@ static int device_add_attrs(struct bus_type *bus, struct device *dev)
        if (!bus->dev_attrs)
                return 0;
 
-       for (i = 0; attr_name(bus->dev_attrs[i]); i++) {
+       for (i = 0; bus->dev_attrs[i].attr.name; i++) {
                error = device_create_file(dev, &bus->dev_attrs[i]);
                if (error) {
                        while (--i >= 0)
@@ -476,7 +491,7 @@ static void device_remove_attrs(struct bus_type *bus, struct device *dev)
        int i;
 
        if (bus->dev_attrs) {
-               for (i = 0; attr_name(bus->dev_attrs[i]); i++)
+               for (i = 0; bus->dev_attrs[i].attr.name; i++)
                        device_remove_file(dev, &bus->dev_attrs[i]);
        }
 }
@@ -499,10 +514,13 @@ int bus_add_device(struct device *dev)
                error = device_add_attrs(bus, dev);
                if (error)
                        goto out_put;
+               error = device_add_groups(dev, bus->dev_groups);
+               if (error)
+                       goto out_id;
                error = sysfs_create_link(&bus->p->devices_kset->kobj,
                                                &dev->kobj, dev_name(dev));
                if (error)
-                       goto out_id;
+                       goto out_groups;
                error = sysfs_create_link(&dev->kobj,
                                &dev->bus->p->subsys.kobj, "subsystem");
                if (error)
@@ -513,6 +531,8 @@ int bus_add_device(struct device *dev)
 
 out_subsys:
        sysfs_remove_link(&bus->p->devices_kset->kobj, dev_name(dev));
+out_groups:
+       device_remove_groups(dev, bus->dev_groups);
 out_id:
        device_remove_attrs(bus, dev);
 out_put:
@@ -530,15 +550,12 @@ void bus_probe_device(struct device *dev)
 {
        struct bus_type *bus = dev->bus;
        struct subsys_interface *sif;
-       int ret;
 
        if (!bus)
                return;
 
-       if (bus->p->drivers_autoprobe) {
-               ret = device_attach(dev);
-               WARN_ON(ret < 0);
-       }
+       if (bus->p->drivers_autoprobe)
+               device_initial_probe(dev);
 
        mutex_lock(&bus->p->mutex);
        list_for_each_entry(sif, &bus->p->interfaces, node)
@@ -575,6 +592,7 @@ void bus_remove_device(struct device *dev)
        sysfs_remove_link(&dev->bus->p->devices_kset->kobj,
                          dev_name(dev));
        device_remove_attrs(dev->bus, dev);
+       device_remove_groups(dev, dev->bus->dev_groups);
        if (klist_node_attached(&dev->p->knode_bus))
                klist_del(&dev->p->knode_bus);
 
@@ -584,37 +602,6 @@ void bus_remove_device(struct device *dev)
        bus_put(dev->bus);
 }
 
-static int driver_add_attrs(struct bus_type *bus, struct device_driver *drv)
-{
-       int error = 0;
-       int i;
-
-       if (bus->drv_attrs) {
-               for (i = 0; attr_name(bus->drv_attrs[i]); i++) {
-                       error = driver_create_file(drv, &bus->drv_attrs[i]);
-                       if (error)
-                               goto err;
-               }
-       }
-done:
-       return error;
-err:
-       while (--i >= 0)
-               driver_remove_file(drv, &bus->drv_attrs[i]);
-       goto done;
-}
-
-static void driver_remove_attrs(struct bus_type *bus,
-                               struct device_driver *drv)
-{
-       int i;
-
-       if (bus->drv_attrs) {
-               for (i = 0; attr_name(bus->drv_attrs[i]); i++)
-                       driver_remove_file(drv, &bus->drv_attrs[i]);
-       }
-}
-
 static int __must_check add_bind_files(struct device_driver *drv)
 {
        int ret;
@@ -659,8 +646,8 @@ static void remove_probe_files(struct bus_type *bus)
        bus_remove_file(bus, &bus_attr_drivers_probe);
 }
 
-static ssize_t driver_uevent_store(struct device_driver *drv,
-                                  const char *buf, size_t count)
+static ssize_t uevent_store(struct device_driver *drv, const char *buf,
+                           size_t count)
 {
        enum kobject_action action;
 
@@ -668,7 +655,18 @@ static ssize_t driver_uevent_store(struct device_driver *drv,
                kobject_uevent(&drv->p->kobj, action);
        return count;
 }
-static DRIVER_ATTR(uevent, S_IWUSR, NULL, driver_uevent_store);
+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.
@@ -702,9 +700,15 @@ int bus_add_driver(struct device_driver *drv)
 
        klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
        if (drv->bus->p->drivers_autoprobe) {
-               error = driver_attach(drv);
-               if (error)
-                       goto out_unregister;
+               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;
+               }
        }
        module_add_driver(drv->owner, drv);
 
@@ -713,10 +717,10 @@ int bus_add_driver(struct device_driver *drv)
                printk(KERN_ERR "%s: uevent attr (%s) failed\n",
                        __func__, drv->name);
        }
-       error = driver_add_attrs(bus, drv);
+       error = driver_add_groups(drv, bus->drv_groups);
        if (error) {
                /* How the hell do we get out of this pickle? Give up */
-               printk(KERN_ERR "%s: driver_add_attrs(%s) failed\n",
+               printk(KERN_ERR "%s: driver_create_groups(%s) failed\n",
                        __func__, drv->name);
        }
 
@@ -755,7 +759,7 @@ void bus_remove_driver(struct device_driver *drv)
 
        if (!drv->suppress_bind_attrs)
                remove_bind_files(drv);
-       driver_remove_attrs(drv->bus, drv);
+       driver_remove_groups(drv, drv->bus->drv_groups);
        driver_remove_file(drv, &driver_attr_uevent);
        klist_remove(&drv->p->knode_bus);
        pr_debug("bus: '%s': remove driver %s\n", drv->bus->name, drv->name);
@@ -834,40 +838,16 @@ struct bus_type *find_bus(char *name)
 }
 #endif  /*  0  */
 
-
-/**
- * bus_add_attrs - Add default attributes for this bus.
- * @bus: Bus that has just been registered.
- */
-
-static int bus_add_attrs(struct bus_type *bus)
+static int bus_add_groups(struct bus_type *bus,
+                         const struct attribute_group **groups)
 {
-       int error = 0;
-       int i;
-
-       if (bus->bus_attrs) {
-               for (i = 0; attr_name(bus->bus_attrs[i]); i++) {
-                       error = bus_create_file(bus, &bus->bus_attrs[i]);
-                       if (error)
-                               goto err;
-               }
-       }
-done:
-       return error;
-err:
-       while (--i >= 0)
-               bus_remove_file(bus, &bus->bus_attrs[i]);
-       goto done;
+       return sysfs_create_groups(&bus->p->subsys.kobj, groups);
 }
 
-static void bus_remove_attrs(struct bus_type *bus)
+static void bus_remove_groups(struct bus_type *bus,
+                             const struct attribute_group **groups)
 {
-       int i;
-
-       if (bus->bus_attrs) {
-               for (i = 0; attr_name(bus->bus_attrs[i]); i++)
-                       bus_remove_file(bus, &bus->bus_attrs[i]);
-       }
+       sysfs_remove_groups(&bus->p->subsys.kobj, groups);
 }
 
 static void klist_devices_get(struct klist_node *n)
@@ -959,14 +939,14 @@ int bus_register(struct bus_type *bus)
        if (retval)
                goto bus_probe_files_fail;
 
-       retval = bus_add_attrs(bus);
+       retval = bus_add_groups(bus, bus->bus_groups);
        if (retval)
-               goto bus_attrs_fail;
+               goto bus_groups_fail;
 
        pr_debug("bus: '%s': registered\n", bus->name);
        return 0;
 
-bus_attrs_fail:
+bus_groups_fail:
        remove_probe_files(bus);
 bus_probe_files_fail:
        kset_unregister(bus->p->drivers_kset);
@@ -995,14 +975,12 @@ void bus_unregister(struct bus_type *bus)
        pr_debug("bus: '%s': unregistering\n", bus->name);
        if (bus->dev_root)
                device_unregister(bus->dev_root);
-       bus_remove_attrs(bus);
+       bus_remove_groups(bus, bus->bus_groups);
        remove_probe_files(bus);
        kset_unregister(bus->p->drivers_kset);
        kset_unregister(bus->p->devices_kset);
        bus_remove_file(bus, &bus_attr_uevent);
        kset_unregister(&bus->p->subsys);
-       kfree(bus->p);
-       bus->p = NULL;
 }
 EXPORT_SYMBOL_GPL(bus_unregister);
 
@@ -1257,7 +1235,7 @@ err_dev:
  * with the name of the subsystem. The root device can carry subsystem-
  * wide attributes. All registered devices are below this single root
  * device and are named after the subsystem with a simple enumeration
- * number appended. The registered devices are not explicitely named;
+ * number appended. The registered devices are not explicitly named;
  * only 'id' in the device needs to be set.
  *
  * Do not use this interface for anything new, it exists for compatibility