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>
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;
}
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;
}
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);
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;
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);
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);
error_endo:
gb_operation_exit();
error_operation:
+ gb_hd_exit();
+error_hd:
bus_unregister(&greybus_bus_type);
error_bus:
gb_debugfs_cleanup();
gb_control_protocol_exit();
gb_endo_exit();
gb_operation_exit();
+ gb_hd_exit();
bus_unregister(&greybus_bus_type);
gb_debugfs_cleanup();
tracepoint_synchronize_unregister();
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;
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;
* 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;
}
/* 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;
}
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);
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);
}
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;
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;
),
#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
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);
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:
*
* 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;
}
/* 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);
+}
};
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;
/* 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,
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 */
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);
{
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,