greybus: svc: create svc along with host device
authorJohan Hovold <johan@hovoldconsulting.com>
Mon, 7 Dec 2015 14:05:37 +0000 (15:05 +0100)
committerGreg Kroah-Hartman <gregkh@google.com>
Tue, 8 Dec 2015 20:31:14 +0000 (15:31 -0500)
Create svc device along with host-device and move the svc-connection to
the svc structure.

The svc connection is enabled when registering the host device, but as
the SVC protocol is currently driven by the SVC, we need to defer
registration of the svc device to the connection request handler.

Signed-off-by: Johan Hovold <johan@hovoldconsulting.com>
Reviewed-by: Viresh Kumar <viresh.kumar@linaro.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
drivers/staging/greybus/hd.c
drivers/staging/greybus/hd.h
drivers/staging/greybus/svc.c
drivers/staging/greybus/svc.h

index 469b31e..bff6861 100644 (file)
@@ -21,8 +21,8 @@ static void gb_hd_release(struct device *dev)
 {
        struct gb_host_device *hd = to_gb_host_device(dev);
 
-       if (hd->svc_connection)
-               gb_connection_destroy(hd->svc_connection);
+       if (hd->svc)
+               gb_svc_put(hd->svc);
        ida_simple_remove(&gb_hd_bus_id_map, hd->bus_id);
        ida_destroy(&hd->cport_id_map);
        kfree(hd);
@@ -95,10 +95,9 @@ struct gb_host_device *gb_hd_create(struct gb_hd_driver *driver,
        device_initialize(&hd->dev);
        dev_set_name(&hd->dev, "greybus%d", hd->bus_id);
 
-       hd->svc_connection = gb_connection_create_static(hd, GB_SVC_CPORT_ID,
-                                                       GREYBUS_PROTOCOL_SVC);
-       if (!hd->svc_connection) {
-               dev_err(&hd->dev, "failed to create svc connection\n");
+       hd->svc = gb_svc_create(hd);
+       if (!hd->svc) {
+               dev_err(&hd->dev, "failed to create svc\n");
                put_device(&hd->dev);
                return ERR_PTR(-ENOMEM);
        }
@@ -115,7 +114,7 @@ int gb_hd_add(struct gb_host_device *hd)
        if (ret)
                return ret;
 
-       ret = gb_connection_init(hd->svc_connection);
+       ret = gb_svc_add(hd->svc);
        if (ret) {
                device_del(&hd->dev);
                return ret;
@@ -129,7 +128,7 @@ void gb_hd_del(struct gb_host_device *hd)
 {
        gb_interfaces_remove(hd);
 
-       gb_connection_exit(hd->svc_connection);
+       gb_svc_del(hd->svc);
 
        device_del(&hd->dev);
 }
index 5612b48..d828129 100644 (file)
@@ -41,8 +41,6 @@ struct gb_host_device {
        size_t buffer_size_max;
 
        struct gb_svc *svc;
-       struct gb_connection *svc_connection;
-
        /* Private data for the host driver */
        unsigned long hd_priv[0] __aligned(sizeof(s64));
 };
index 2a8f79e..c013083 100644 (file)
@@ -661,6 +661,8 @@ static void gb_svc_release(struct device *dev)
 {
        struct gb_svc *svc = to_gb_svc(dev);
 
+       if (svc->connection)
+               gb_connection_destroy(svc->connection);
        ida_destroy(&svc->device_id_map);
        destroy_workqueue(svc->wq);
        kfree(svc);
@@ -671,19 +673,18 @@ struct device_type greybus_svc_type = {
        .release        = gb_svc_release,
 };
 
-static int gb_svc_connection_init(struct gb_connection *connection)
+struct gb_svc *gb_svc_create(struct gb_host_device *hd)
 {
-       struct gb_host_device *hd = connection->hd;
        struct gb_svc *svc;
 
        svc = kzalloc(sizeof(*svc), GFP_KERNEL);
        if (!svc)
-               return -ENOMEM;
+               return NULL;
 
        svc->wq = alloc_workqueue("%s:svc", WQ_UNBOUND, 1, dev_name(&hd->dev));
        if (!svc->wq) {
                kfree(svc);
-               return -ENOMEM;
+               return NULL;
        }
 
        svc->dev.parent = &hd->dev;
@@ -697,30 +698,71 @@ static int gb_svc_connection_init(struct gb_connection *connection)
 
        ida_init(&svc->device_id_map);
        svc->state = GB_SVC_STATE_RESET;
-       svc->connection = connection;
        svc->hd = hd;
-       connection->private = svc;
 
-       hd->svc = svc;
+       svc->connection = gb_connection_create_static(hd, GB_SVC_CPORT_ID,
+                                                       GREYBUS_PROTOCOL_SVC);
+       if (!svc->connection) {
+               dev_err(&svc->dev, "failed to create connection\n");
+               put_device(&svc->dev);
+               return NULL;
+       }
+
+       svc->connection->private = svc;
 
-       return 0;
+       return svc;
 }
 
-static void gb_svc_connection_exit(struct gb_connection *connection)
+int gb_svc_add(struct gb_svc *svc)
 {
-       struct gb_svc *svc = connection->private;
+       int ret;
 
+       /*
+        * The SVC protocol is currently driven by the SVC, so the SVC device
+        * is added from the connection request handler when enough
+        * information has been received.
+        */
+       ret = gb_connection_init(svc->connection);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+void gb_svc_del(struct gb_svc *svc)
+{
+       /*
+        * The SVC device may have been registered from the request handler.
+        */
        if (device_is_registered(&svc->dev))
                device_del(&svc->dev);
 
-       flush_workqueue(svc->wq);
+       gb_connection_exit(svc->connection);
 
-       connection->hd->svc = NULL;
-       connection->private = NULL;
+       flush_workqueue(svc->wq);
+}
 
+void gb_svc_put(struct gb_svc *svc)
+{
        put_device(&svc->dev);
 }
 
+static int gb_svc_connection_init(struct gb_connection *connection)
+{
+       struct gb_svc *svc = connection->private;
+
+       dev_dbg(&svc->dev, "%s\n", __func__);
+
+       return 0;
+}
+
+static void gb_svc_connection_exit(struct gb_connection *connection)
+{
+       struct gb_svc *svc = connection->private;
+
+       dev_dbg(&svc->dev, "%s\n", __func__);
+}
+
 static struct gb_protocol svc_protocol = {
        .name                   = "svc",
        .id                     = GREYBUS_PROTOCOL_SVC,
index ca0f71d..b7cb7e4 100644 (file)
@@ -30,6 +30,11 @@ struct gb_svc {
 };
 #define to_gb_svc(d) container_of(d, struct gb_svc, d)
 
+struct gb_svc *gb_svc_create(struct gb_host_device *hd);
+int gb_svc_add(struct gb_svc *svc);
+void gb_svc_del(struct gb_svc *svc);
+void gb_svc_put(struct gb_svc *svc);
+
 int gb_svc_intf_reset(struct gb_svc *svc, u8 intf_id);
 int gb_svc_connection_create(struct gb_svc *svc, u8 intf1_id, u16 cport1_id,
                             u8 intf2_id, u16 cport2_id, bool boot_over_unipro);