diff options
author | Johan Hovold <johan@hovoldconsulting.com> | 2015-11-03 17:03:22 (GMT) |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@google.com> | 2015-11-05 04:25:57 (GMT) |
commit | 7bc6faaca7d829d4e6f5d65909d5068f73b76bda (patch) | |
tree | 80ebab1a7366c6aaae4fd197cac39d4cd3b236c3 /drivers/staging | |
parent | 04fdd6a51a5b3b448047b83624dbfac85d3daf9a (diff) | |
download | linux-7bc6faaca7d829d4e6f5d65909d5068f73b76bda.tar.xz |
greybus: create host-device compilation unit
Move everything host-device related to hd.c and hd.h.
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>
Diffstat (limited to 'drivers/staging')
-rw-r--r-- | drivers/staging/greybus/Makefile | 1 | ||||
-rw-r--r-- | drivers/staging/greybus/core.c | 100 | ||||
-rw-r--r-- | drivers/staging/greybus/greybus.h | 48 | ||||
-rw-r--r-- | drivers/staging/greybus/hd.c | 115 | ||||
-rw-r--r-- | drivers/staging/greybus/hd.h | 61 |
5 files changed, 178 insertions, 147 deletions
diff --git a/drivers/staging/greybus/Makefile b/drivers/staging/greybus/Makefile index b8dc36b..ba60430 100644 --- a/drivers/staging/greybus/Makefile +++ b/drivers/staging/greybus/Makefile @@ -1,5 +1,6 @@ greybus-y := core.o \ debugfs.o \ + hd.o \ manifest.o \ endo.o \ module.o \ diff --git a/drivers/staging/greybus/core.c b/drivers/staging/greybus/core.c index 726bf64..4396f90 100644 --- a/drivers/staging/greybus/core.c +++ b/drivers/staging/greybus/core.c @@ -146,106 +146,6 @@ void greybus_deregister_driver(struct greybus_driver *driver) } EXPORT_SYMBOL_GPL(greybus_deregister_driver); - -static DEFINE_MUTEX(hd_mutex); - -static void free_hd(struct kref *kref) -{ - struct greybus_host_device *hd; - - hd = container_of(kref, struct greybus_host_device, kref); - - ida_destroy(&hd->cport_id_map); - kfree(hd); - mutex_unlock(&hd_mutex); -} - -struct greybus_host_device *greybus_create_hd(struct greybus_host_driver *driver, - struct device *parent, - size_t buffer_size_max, - size_t num_cports) -{ - struct greybus_host_device *hd; - - /* - * Validate that the driver implements all of the callbacks - * so that we don't have to every time we make them. - */ - if ((!driver->message_send) || (!driver->message_cancel)) { - pr_err("Must implement all greybus_host_driver callbacks!\n"); - return ERR_PTR(-EINVAL); - } - - if (buffer_size_max < GB_OPERATION_MESSAGE_SIZE_MIN) { - dev_err(parent, "greybus host-device buffers too small\n"); - return ERR_PTR(-EINVAL); - } - - if (num_cports == 0 || num_cports > CPORT_ID_MAX) { - dev_err(parent, "Invalid number of CPorts: %zu\n", num_cports); - return ERR_PTR(-EINVAL); - } - - /* - * Make sure to never allocate messages larger than what the Greybus - * protocol supports. - */ - if (buffer_size_max > GB_OPERATION_MESSAGE_SIZE_MAX) { - dev_warn(parent, "limiting buffer size to %u\n", - GB_OPERATION_MESSAGE_SIZE_MAX); - buffer_size_max = GB_OPERATION_MESSAGE_SIZE_MAX; - } - - hd = kzalloc(sizeof(*hd) + driver->hd_priv_size, GFP_KERNEL); - if (!hd) - return ERR_PTR(-ENOMEM); - - kref_init(&hd->kref); - hd->parent = parent; - hd->driver = driver; - INIT_LIST_HEAD(&hd->interfaces); - INIT_LIST_HEAD(&hd->connections); - ida_init(&hd->cport_id_map); - hd->buffer_size_max = buffer_size_max; - hd->num_cports = num_cports; - - /* - * Initialize AP's SVC protocol connection: - * - * This is required as part of early initialization of the host device - * as we need this connection in order to start any kind of message - * exchange between the AP and the SVC. SVC will start with a - * 'get-version' request followed by a 'svc-hello' message and at that - * 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)) { - kref_put_mutex(&hd->kref, free_hd, &hd_mutex); - return ERR_PTR(-ENOMEM); - } - - return hd; -} -EXPORT_SYMBOL_GPL(greybus_create_hd); - -void greybus_remove_hd(struct greybus_host_device *hd) -{ - /* - * Tear down all interfaces, modules, and the endo that is associated - * with this host controller before freeing the memory associated with - * the host controller. - */ - gb_interfaces_remove(hd); - gb_endo_remove(hd->endo); - - /* Is the SVC still using the partially uninitialized connection ? */ - if (hd->initial_svc_connection) - gb_connection_destroy(hd->initial_svc_connection); - - kref_put_mutex(&hd->kref, free_hd, &hd_mutex); -} -EXPORT_SYMBOL_GPL(greybus_remove_hd); - static int __init gb_init(void) { int retval; diff --git a/drivers/staging/greybus/greybus.h b/drivers/staging/greybus/greybus.h index 219b2ff..8eb63e0 100644 --- a/drivers/staging/greybus/greybus.h +++ b/drivers/staging/greybus/greybus.h @@ -25,6 +25,7 @@ #include "greybus_manifest.h" #include "greybus_protocols.h" #include "manifest.h" +#include "hd.h" #include "endo.h" #include "svc.h" #include "firmware.h" @@ -57,53 +58,6 @@ #define CPORT_ID_MAX 4095 /* UniPro max id is 4095 */ #define CPORT_ID_BAD U16_MAX -struct greybus_host_device; - -/* Greybus "Host driver" structure, needed by a host controller driver to be - * able to handle both SVC control as well as "real" greybus messages - */ -struct greybus_host_driver { - size_t hd_priv_size; - - int (*cport_enable)(struct greybus_host_device *hd, u16 cport_id); - int (*cport_disable)(struct greybus_host_device *hd, u16 cport_id); - int (*message_send)(struct greybus_host_device *hd, u16 dest_cport_id, - struct gb_message *message, gfp_t gfp_mask); - void (*message_cancel)(struct gb_message *message); - int (*latency_tag_enable)(struct greybus_host_device *hd, u16 cport_id); - int (*latency_tag_disable)(struct greybus_host_device *hd, - u16 cport_id); -}; - -struct greybus_host_device { - struct kref kref; - struct device *parent; - const struct greybus_host_driver *driver; - - struct list_head interfaces; - struct list_head connections; - struct ida cport_id_map; - - /* Number of CPorts supported by the UniPro IP */ - size_t num_cports; - - /* Host device buffer constraints */ - size_t buffer_size_max; - - struct gb_endo *endo; - struct gb_connection *initial_svc_connection; - struct gb_svc *svc; - - /* Private data for the host driver */ - unsigned long hd_priv[0] __aligned(sizeof(s64)); -}; - -struct greybus_host_device *greybus_create_hd(struct greybus_host_driver *hd, - struct device *parent, - size_t buffer_size_max, - size_t num_cports); -void greybus_remove_hd(struct greybus_host_device *hd); - struct greybus_driver { const char *name; diff --git a/drivers/staging/greybus/hd.c b/drivers/staging/greybus/hd.c new file mode 100644 index 0000000..3ac8507 --- /dev/null +++ b/drivers/staging/greybus/hd.c @@ -0,0 +1,115 @@ +/* + * Greybus Host Device + * + * Copyright 2014-2015 Google Inc. + * Copyright 2014-2015 Linaro Ltd. + * + * Released under the GPLv2 only. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/kernel.h> +#include <linux/slab.h> + +#include "greybus.h" + +static DEFINE_MUTEX(hd_mutex); + + +static void free_hd(struct kref *kref) +{ + struct greybus_host_device *hd; + + hd = container_of(kref, struct greybus_host_device, kref); + + ida_destroy(&hd->cport_id_map); + kfree(hd); + mutex_unlock(&hd_mutex); +} + +struct greybus_host_device *greybus_create_hd(struct greybus_host_driver *driver, + struct device *parent, + size_t buffer_size_max, + size_t num_cports) +{ + struct greybus_host_device *hd; + + /* + * Validate that the driver implements all of the callbacks + * so that we don't have to every time we make them. + */ + if ((!driver->message_send) || (!driver->message_cancel)) { + pr_err("Must implement all greybus_host_driver callbacks!\n"); + return ERR_PTR(-EINVAL); + } + + if (buffer_size_max < GB_OPERATION_MESSAGE_SIZE_MIN) { + dev_err(parent, "greybus host-device buffers too small\n"); + return ERR_PTR(-EINVAL); + } + + if (num_cports == 0 || num_cports > CPORT_ID_MAX) { + dev_err(parent, "Invalid number of CPorts: %zu\n", num_cports); + return ERR_PTR(-EINVAL); + } + + /* + * Make sure to never allocate messages larger than what the Greybus + * protocol supports. + */ + if (buffer_size_max > GB_OPERATION_MESSAGE_SIZE_MAX) { + dev_warn(parent, "limiting buffer size to %u\n", + GB_OPERATION_MESSAGE_SIZE_MAX); + buffer_size_max = GB_OPERATION_MESSAGE_SIZE_MAX; + } + + hd = kzalloc(sizeof(*hd) + driver->hd_priv_size, GFP_KERNEL); + if (!hd) + return ERR_PTR(-ENOMEM); + + kref_init(&hd->kref); + hd->parent = parent; + hd->driver = driver; + INIT_LIST_HEAD(&hd->interfaces); + INIT_LIST_HEAD(&hd->connections); + ida_init(&hd->cport_id_map); + hd->buffer_size_max = buffer_size_max; + hd->num_cports = num_cports; + + /* + * Initialize AP's SVC protocol connection: + * + * This is required as part of early initialization of the host device + * as we need this connection in order to start any kind of message + * exchange between the AP and the SVC. SVC will start with a + * 'get-version' request followed by a 'svc-hello' message and at that + * 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)) { + kref_put_mutex(&hd->kref, free_hd, &hd_mutex); + return ERR_PTR(-ENOMEM); + } + + return hd; +} +EXPORT_SYMBOL_GPL(greybus_create_hd); + +void greybus_remove_hd(struct greybus_host_device *hd) +{ + /* + * Tear down all interfaces, modules, and the endo that is associated + * with this host controller before freeing the memory associated with + * the host controller. + */ + gb_interfaces_remove(hd); + gb_endo_remove(hd->endo); + + /* Is the SVC still using the partially uninitialized connection ? */ + if (hd->initial_svc_connection) + gb_connection_destroy(hd->initial_svc_connection); + + kref_put_mutex(&hd->kref, free_hd, &hd_mutex); +} +EXPORT_SYMBOL_GPL(greybus_remove_hd); diff --git a/drivers/staging/greybus/hd.h b/drivers/staging/greybus/hd.h new file mode 100644 index 0000000..df953d4 --- /dev/null +++ b/drivers/staging/greybus/hd.h @@ -0,0 +1,61 @@ +/* + * Greybus Host Device + * + * Copyright 2014-2015 Google Inc. + * Copyright 2014-2015 Linaro Ltd. + * + * Released under the GPLv2 only. + */ + +#ifndef __HD_H +#define __HD_H + +struct greybus_host_device; +struct gb_message; + +/* Greybus "Host driver" structure, needed by a host controller driver to be + * able to handle both SVC control as well as "real" greybus messages + */ +struct greybus_host_driver { + size_t hd_priv_size; + + int (*cport_enable)(struct greybus_host_device *hd, u16 cport_id); + int (*cport_disable)(struct greybus_host_device *hd, u16 cport_id); + int (*message_send)(struct greybus_host_device *hd, u16 dest_cport_id, + struct gb_message *message, gfp_t gfp_mask); + void (*message_cancel)(struct gb_message *message); + int (*latency_tag_enable)(struct greybus_host_device *hd, u16 cport_id); + int (*latency_tag_disable)(struct greybus_host_device *hd, + u16 cport_id); +}; + +struct greybus_host_device { + struct kref kref; + struct device *parent; + const struct greybus_host_driver *driver; + + struct list_head interfaces; + struct list_head connections; + struct ida cport_id_map; + + /* Number of CPorts supported by the UniPro IP */ + size_t num_cports; + + /* Host device buffer constraints */ + size_t buffer_size_max; + + struct gb_endo *endo; + struct gb_connection *initial_svc_connection; + struct gb_svc *svc; + + /* Private data for the host driver */ + unsigned long hd_priv[0] __aligned(sizeof(s64)); +}; + +struct greybus_host_device *greybus_create_hd(struct greybus_host_driver *hd, + struct device *parent, + size_t buffer_size_max, + size_t num_cports); +void greybus_remove_hd(struct greybus_host_device *hd); + +#endif /* __HD_H */ |