From 2adaefb1458f67b3f71111fcf6a15670ab64101d Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 25 Nov 2015 15:59:02 +0100 Subject: [PATCH] greybus: hd: make host device a device 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 Signed-off-by: Greg Kroah-Hartman --- drivers/staging/greybus/connection.c | 6 ++-- drivers/staging/greybus/core.c | 14 +++++++- drivers/staging/greybus/endo.c | 18 +++++----- drivers/staging/greybus/greybus.h | 6 ++++ drivers/staging/greybus/greybus_trace.h | 4 +-- drivers/staging/greybus/hd.c | 59 +++++++++++++++++++++++++++------ drivers/staging/greybus/hd.h | 8 +++-- drivers/staging/greybus/interface.c | 2 +- drivers/staging/greybus/svc.c | 2 +- 9 files changed, 90 insertions(+), 29 deletions(-) diff --git a/drivers/staging/greybus/connection.c b/drivers/staging/greybus/connection.c index 695f1481ba0f..c076171cba7a 100644 --- a/drivers/staging/greybus/connection.c +++ b/drivers/staging/greybus/connection.c @@ -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); diff --git a/drivers/staging/greybus/core.c b/drivers/staging/greybus/core.c index b3c422acf352..8c8ba02b76e9 100644 --- a/drivers/staging/greybus/core.c +++ b/drivers/staging/greybus/core.c @@ -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(); diff --git a/drivers/staging/greybus/endo.c b/drivers/staging/greybus/endo.c index 775dbcea539b..6fb22fb8e85b 100644 --- a/drivers/staging/greybus/endo.c +++ b/drivers/staging/greybus/endo.c @@ -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); } diff --git a/drivers/staging/greybus/greybus.h b/drivers/staging/greybus/greybus.h index 6da4e78248a8..8ef3a0426a09 100644 --- a/drivers/staging/greybus/greybus.h +++ b/drivers/staging/greybus/greybus.h @@ -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; diff --git a/drivers/staging/greybus/greybus_trace.h b/drivers/staging/greybus/greybus_trace.h index a39fa396d949..1ca07064f5de 100644 --- a/drivers/staging/greybus/greybus_trace.h +++ b/drivers/staging/greybus/greybus_trace.h @@ -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; ), diff --git a/drivers/staging/greybus/hd.c b/drivers/staging/greybus/hd.c index 3446fec35895..88d2f01f79d1 100644 --- a/drivers/staging/greybus/hd.c +++ b/drivers/staging/greybus/hd.c @@ -14,26 +14,30 @@ #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); +} diff --git a/drivers/staging/greybus/hd.h b/drivers/staging/greybus/hd.h index 6724cfea1e19..6bc9ce3df672 100644 --- a/drivers/staging/greybus/hd.h +++ b/drivers/staging/greybus/hd.h @@ -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 */ diff --git a/drivers/staging/greybus/interface.c b/drivers/staging/greybus/interface.c index b5d9046ead44..4c99e3e9b0f5 100644 --- a/drivers/staging/greybus/interface.c +++ b/drivers/staging/greybus/interface.c @@ -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); diff --git a/drivers/staging/greybus/svc.c b/drivers/staging/greybus/svc.c index 2e8c444d8b16..7425c4980c38 100644 --- a/drivers/staging/greybus/svc.c +++ b/drivers/staging/greybus/svc.c @@ -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, -- 2.11.0