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 <johan@hovoldconsulting.com> Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
This commit is contained in:
parent
a97015c9e9
commit
2adaefb145
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
),
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue