greybus: hd: make host device a device
authorJohan Hovold <johan@hovoldconsulting.com>
Wed, 25 Nov 2015 14:59:02 +0000 (15:59 +0100)
committerGreg Kroah-Hartman <gregkh@google.com>
Wed, 25 Nov 2015 23:27:06 +0000 (15:27 -0800)
Make the host device a proper device in the kernel device model.

Host devices will be our new greybus-bus root devices.

Signed-off-by: Johan Hovold <johan@hovoldconsulting.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
drivers/staging/greybus/connection.c
drivers/staging/greybus/core.c
drivers/staging/greybus/endo.c
drivers/staging/greybus/greybus.h
drivers/staging/greybus/greybus_trace.h
drivers/staging/greybus/hd.c
drivers/staging/greybus/hd.h
drivers/staging/greybus/interface.c
drivers/staging/greybus/svc.c

index 695f1481ba0fc77119c8ef95c9115b2c646415df..c076171cba7a6bbc9d8845f10ba3bed1443e1e94 100644 (file)
@@ -55,7 +55,7 @@ void greybus_data_rcvd(struct gb_host_device *hd, u16 cport_id,
 
        connection = gb_connection_hd_find(hd, cport_id);
        if (!connection) {
-               dev_err(hd->parent,
+               dev_err(&hd->dev,
                        "nonexistent connection (%zu bytes dropped)\n", length);
                return;
        }
@@ -196,7 +196,7 @@ static int gb_connection_hd_cport_enable(struct gb_connection *connection)
 
        ret = hd->driver->cport_enable(hd, connection->hd_cport_id);
        if (ret) {
-               dev_err(hd->parent,
+               dev_err(&hd->dev,
                        "failed to enable host cport: %d\n", ret);
                return ret;
        }
@@ -502,7 +502,7 @@ int gb_connection_bind_protocol(struct gb_connection *connection)
                                   connection->major,
                                   connection->minor);
        if (!protocol) {
-               dev_warn(connection->hd->parent,
+               dev_warn(&connection->hd->dev,
                                "protocol 0x%02hhx version %hhu.%hhu not found\n",
                                connection->protocol_id,
                                connection->major, connection->minor);
index b3c422acf352fbe0c54c7122408f469b6de46ae6..8c8ba02b76e9ee03c92d2ecc4eef2f47474e4f2f 100644 (file)
@@ -77,6 +77,7 @@ static int greybus_module_match(struct device *dev, struct device_driver *drv)
 
 static int greybus_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
+       struct gb_host_device *hd = NULL;
        struct gb_module *module = NULL;
        struct gb_interface *intf = NULL;
        struct gb_bundle *bundle = NULL;
@@ -89,7 +90,9 @@ static int greybus_uevent(struct device *dev, struct kobj_uevent_env *env)
                return 0;
        }
 
-       if (is_gb_module(dev)) {
+       if (is_gb_host_device(dev)) {
+               hd = to_gb_host_device(dev);
+       } else if (is_gb_module(dev)) {
                module = to_gb_module(dev);
        } else if (is_gb_interface(dev)) {
                intf = to_gb_interface(dev);
@@ -196,6 +199,12 @@ static int __init gb_init(void)
                goto error_bus;
        }
 
+       retval = gb_hd_init();
+       if (retval) {
+               pr_err("gb_hd_init failed (%d)\n", retval);
+               goto error_hd;
+       }
+
        retval = gb_operation_init();
        if (retval) {
                pr_err("gb_operation_init failed (%d)\n", retval);
@@ -237,6 +246,8 @@ error_control:
 error_endo:
        gb_operation_exit();
 error_operation:
+       gb_hd_exit();
+error_hd:
        bus_unregister(&greybus_bus_type);
 error_bus:
        gb_debugfs_cleanup();
@@ -252,6 +263,7 @@ static void __exit gb_exit(void)
        gb_control_protocol_exit();
        gb_endo_exit();
        gb_operation_exit();
+       gb_hd_exit();
        bus_unregister(&greybus_bus_type);
        gb_debugfs_cleanup();
        tracepoint_synchronize_unregister();
index 775dbcea539b6ac6bbf420a663ad9a72d71ab339..6fb22fb8e85b7cd3756c9eeb20b8a5afa3e1faf9 100644 (file)
@@ -219,7 +219,7 @@ static bool validate_front_ribs(struct gb_host_device *hd,
                layout->front_ribs = 0x5;
                break;
        default:
-               dev_err(hd->parent,
+               dev_err(&hd->dev,
                        "%s: Invalid endo front mask 0x%02x, id 0x%04x\n",
                        __func__, front_mask, endo_id);
                return false;
@@ -266,21 +266,21 @@ static bool validate_back_ribs(struct gb_host_device *hd,
        right_ribs = endo_back_right_ribs(endo_id, max_ribs);
 
        if (!single_cross_rib(left_ribs, right_ribs)) {
-               dev_err(hd->parent,
+               dev_err(&hd->dev,
                        "%s: More than one spanning rib (left 0x%02x right 0x%02x), id 0x%04x\n",
                        __func__, left_ribs, right_ribs, endo_id);
                return false;
        }
 
        if (modules_oversized(max_ribs, left_ribs)) {
-                       dev_err(hd->parent,
+                       dev_err(&hd->dev,
                                "%s: Oversized module (left) 0x%02x, id 0x%04x\n",
                                __func__, left_ribs, endo_id);
                        return false;
        }
 
        if (modules_oversized(max_ribs, right_ribs)) {
-                       dev_err(hd->parent,
+                       dev_err(&hd->dev,
                                "%s: Oversized module (Right) 0x%02x, id 0x%04x\n",
                                __func__, right_ribs, endo_id);
                        return false;
@@ -306,7 +306,7 @@ static bool validate_back_ribs(struct gb_host_device *hd,
         * are of different widths.
         */
        if (max_ribs != ENDO_BACK_RIBS_MEDIUM && left_ribs < right_ribs) {
-               dev_err(hd->parent, "%s: Non-canonical endo id 0x%04x\n", __func__,
+               dev_err(&hd->dev, "%s: Non-canonical endo id 0x%04x\n", __func__,
                        endo_id);
                return false;
        }
@@ -334,7 +334,7 @@ static int gb_endo_validate_id(struct gb_host_device *hd,
                /* Mini Endo type */
                layout->max_ribs = ENDO_BACK_RIBS_MINI;
        } else {
-               dev_err(hd->parent, "%s: Invalid endo type, id 0x%04x\n",
+               dev_err(&hd->dev, "%s: Invalid endo type, id 0x%04x\n",
                        __func__, endo_id);
                return -EINVAL;
        }
@@ -447,11 +447,11 @@ static int gb_endo_register(struct gb_host_device *hd,
 
        endo->dev_id = dev_id;
 
-       endo->dev.parent = hd->parent;
+       endo->dev.parent = &hd->dev;
        endo->dev.bus = &greybus_bus_type;
        endo->dev.type = &greybus_endo_type;
        endo->dev.groups = endo_groups;
-       endo->dev.dma_mask = hd->parent->dma_mask;
+       endo->dev.dma_mask = hd->dev.dma_mask;
        device_initialize(&endo->dev);
        dev_set_name(&endo->dev, "endo%hu", endo->dev_id);
 
@@ -463,7 +463,7 @@ static int gb_endo_register(struct gb_host_device *hd,
 
        retval = device_add(&endo->dev);
        if (retval) {
-               dev_err(hd->parent, "failed to add endo device of id 0x%04x\n",
+               dev_err(&hd->dev, "failed to add endo device of id 0x%04x\n",
                        endo->id);
                put_device(&endo->dev);
        }
index 6da4e78248a89457b11cdd5af9df4ee8e6631665..8ef3a0426a0923a06a3d9af7900ee5d14e9834d7 100644 (file)
@@ -104,11 +104,17 @@ struct dentry *gb_debugfs_get(void);
 
 extern struct bus_type greybus_bus_type;
 
+extern struct device_type greybus_hd_type;
 extern struct device_type greybus_endo_type;
 extern struct device_type greybus_module_type;
 extern struct device_type greybus_interface_type;
 extern struct device_type greybus_bundle_type;
 
+static inline int is_gb_host_device(const struct device *dev)
+{
+       return dev->type == &greybus_hd_type;
+}
+
 static inline int is_gb_endo(const struct device *dev)
 {
        return dev->type == &greybus_endo_type;
index a39fa396d9494a629ac41bc63213bfc53637c6c3..1ca07064f5de58c7d17e0715032ce07c13e2ee97 100644 (file)
@@ -114,13 +114,13 @@ DECLARE_EVENT_CLASS(gb_host_device,
        TP_ARGS(hd, intf_cport_id, payload_size),
 
        TP_STRUCT__entry(
-               __string(name, dev_name(hd->parent))
+               __string(name, dev_name(&hd->dev))
                __field(u16, intf_cport_id)
                __field(size_t, payload_size)
        ),
 
        TP_fast_assign(
-               __assign_str(name, dev_name(hd->parent))
+               __assign_str(name, dev_name(&hd->dev))
                __entry->intf_cport_id = intf_cport_id;
                __entry->payload_size = payload_size;
        ),
index 3446fec358958b41c01f70c292f5b6e25883ec8d..88d2f01f79d13a0091307b1a2b8b13ac18620357 100644 (file)
 
 #include "greybus.h"
 
-static DEFINE_MUTEX(hd_mutex);
 
+static struct ida gb_hd_bus_id_map;
 
-static void free_hd(struct kref *kref)
+static void gb_hd_release(struct device *dev)
 {
-       struct gb_host_device *hd;
-
-       hd = container_of(kref, struct gb_host_device, kref);
+       struct gb_host_device *hd = to_gb_host_device(dev);
 
+       ida_simple_remove(&gb_hd_bus_id_map, hd->bus_id);
        ida_destroy(&hd->cport_id_map);
        kfree(hd);
-       mutex_unlock(&hd_mutex);
 }
 
+struct device_type greybus_hd_type = {
+       .name           = "greybus_host_device",
+       .release        = gb_hd_release,
+};
+
 struct gb_host_device *gb_hd_create(struct gb_hd_driver *driver,
                                        struct device *parent,
                                        size_t buffer_size_max,
                                        size_t num_cports)
 {
        struct gb_host_device *hd;
+       int ret;
 
        /*
         * Validate that the driver implements all of the callbacks
@@ -68,8 +72,21 @@ struct gb_host_device *gb_hd_create(struct gb_hd_driver *driver,
        if (!hd)
                return ERR_PTR(-ENOMEM);
 
-       kref_init(&hd->kref);
-       hd->parent = parent;
+       hd->dev.parent = parent;
+       hd->dev.bus = &greybus_bus_type;
+       hd->dev.type = &greybus_hd_type;
+       hd->dev.dma_mask = hd->dev.parent->dma_mask;
+       device_initialize(&hd->dev);
+
+       ret = ida_simple_get(&gb_hd_bus_id_map, 1, 0, GFP_KERNEL);
+       if (ret < 0) {
+               kfree(hd);
+               return ERR_PTR(ret);
+       }
+
+       hd->bus_id = ret;
+       dev_set_name(&hd->dev, "greybus%d", hd->bus_id);
+
        hd->driver = driver;
        INIT_LIST_HEAD(&hd->interfaces);
        INIT_LIST_HEAD(&hd->connections);
@@ -83,6 +100,12 @@ EXPORT_SYMBOL_GPL(gb_hd_create);
 
 int gb_hd_add(struct gb_host_device *hd)
 {
+       int ret;
+
+       ret = device_add(&hd->dev);
+       if (ret)
+               return ret;
+
        /*
         * Initialize AP's SVC protocol connection:
         *
@@ -93,8 +116,10 @@ int gb_hd_add(struct gb_host_device *hd)
         * time we will create a fully initialized svc-connection, as we need
         * endo-id and AP's interface id for that.
         */
-       if (!gb_ap_svc_connection_create(hd))
+       if (!gb_ap_svc_connection_create(hd)) {
+               device_del(&hd->dev);
                return -ENOMEM;
+       }
 
        return 0;
 }
@@ -113,11 +138,25 @@ void gb_hd_del(struct gb_host_device *hd)
        /* Is the SVC still using the partially uninitialized connection ? */
        if (hd->initial_svc_connection)
                gb_connection_destroy(hd->initial_svc_connection);
+
+       device_del(&hd->dev);
 }
 EXPORT_SYMBOL_GPL(gb_hd_del);
 
 void gb_hd_put(struct gb_host_device *hd)
 {
-       kref_put_mutex(&hd->kref, free_hd, &hd_mutex);
+       put_device(&hd->dev);
 }
 EXPORT_SYMBOL_GPL(gb_hd_put);
+
+int __init gb_hd_init(void)
+{
+       ida_init(&gb_hd_bus_id_map);
+
+       return 0;
+}
+
+void gb_hd_exit(void)
+{
+       ida_destroy(&gb_hd_bus_id_map);
+}
index 6724cfea1e19c4a1d90ddcc3f1762706233e1da6..6bc9ce3df672b566fb9efd52fd06e0e24ec3a970 100644 (file)
@@ -26,8 +26,8 @@ struct gb_hd_driver {
 };
 
 struct gb_host_device {
-       struct kref kref;
-       struct device *parent;
+       struct device dev;
+       int bus_id;
        const struct gb_hd_driver *driver;
 
        struct list_head interfaces;
@@ -47,6 +47,7 @@ struct gb_host_device {
        /* Private data for the host driver */
        unsigned long hd_priv[0] __aligned(sizeof(s64));
 };
+#define to_gb_host_device(d) container_of(d, struct gb_host_device, d)
 
 struct gb_host_device *gb_hd_create(struct gb_hd_driver *driver,
                                        struct device *parent,
@@ -56,4 +57,7 @@ int gb_hd_add(struct gb_host_device *hd);
 void gb_hd_del(struct gb_host_device *hd);
 void gb_hd_put(struct gb_host_device *hd);
 
+int gb_hd_init(void);
+void gb_hd_exit(void);
+
 #endif /* __HD_H */
index b5d9046ead443afcf88167e65234c260fcf71677..4c99e3e9b0f535e8fe96ae9efa9477db2f8c9221 100644 (file)
@@ -149,7 +149,7 @@ struct gb_interface *gb_interface_create(struct gb_host_device *hd,
        intf->dev.bus = &greybus_bus_type;
        intf->dev.type = &greybus_interface_type;
        intf->dev.groups = interface_groups;
-       intf->dev.dma_mask = hd->parent->dma_mask;
+       intf->dev.dma_mask = hd->dev.dma_mask;
        device_initialize(&intf->dev);
        dev_set_name(&intf->dev, "%s:%d", dev_name(&module->dev), interface_id);
 
index 2e8c444d8b16cb83d4c5eed91d34cfe8fab8d10a..7425c4980c38f7da6c722c568d27e3a58c5b9a8e 100644 (file)
@@ -46,7 +46,7 @@ gb_ap_svc_connection_create(struct gb_host_device *hd)
 {
        struct gb_connection *connection;
 
-       connection = gb_connection_create_range(hd, NULL, hd->parent,
+       connection = gb_connection_create_range(hd, NULL, &hd->dev,
                                                GB_SVC_CPORT_ID,
                                                GREYBUS_PROTOCOL_SVC,
                                                GB_SVC_CPORT_ID,