4 * Copyright 2014 Google Inc.
6 * Released under the GPLv2 only.
9 #include <linux/atomic.h>
11 #include "kernel_ver.h"
14 static DEFINE_SPINLOCK(gb_connections_lock);
16 static void _gb_hd_connection_insert(struct greybus_host_device *hd,
17 struct gb_connection *connection)
19 struct rb_root *root = &hd->connections;
20 struct rb_node *node = &connection->hd_node;
21 struct rb_node **link = &root->rb_node;
22 struct rb_node *above = NULL;
23 u16 cport_id = connection->hd_cport_id;
26 struct gb_connection *connection;
29 connection = rb_entry(above, struct gb_connection, hd_node);
30 if (connection->hd_cport_id > cport_id)
31 link = &above->rb_left;
32 else if (connection->hd_cport_id < cport_id)
33 link = &above->rb_right;
35 rb_link_node(node, above, link);
36 rb_insert_color(node, root);
39 static void _gb_hd_connection_remove(struct gb_connection *connection)
41 rb_erase(&connection->hd_node, &connection->hd->connections);
44 struct gb_connection *gb_hd_connection_find(struct greybus_host_device *hd,
47 struct gb_connection *connection = NULL;
50 spin_lock_irq(&gb_connections_lock);
51 node = hd->connections.rb_node;
53 connection = rb_entry(node, struct gb_connection, hd_node);
54 if (connection->hd_cport_id > cport_id)
56 else if (connection->hd_cport_id < cport_id)
57 node = node->rb_right;
63 spin_unlock_irq(&gb_connections_lock);
69 * Allocate an available CPort Id for use for the host side of the
70 * given connection. The lowest-available id is returned, so the
71 * first call is guaranteed to allocate CPort Id 0.
73 * Assigns the connection's hd_cport_id and returns true if successful.
74 * Returns false otherwise.
76 static bool gb_connection_hd_cport_id_alloc(struct gb_connection *connection)
78 struct ida *ida = &connection->hd->cport_id_map;
81 spin_lock(&connection->hd->cport_id_map_lock);
82 id = ida_simple_get(ida, 0, HOST_DEV_CPORT_ID_MAX, GFP_KERNEL);
83 spin_unlock(&connection->hd->cport_id_map_lock);
87 connection->hd_cport_id = (u16)id;
93 * Free a previously-allocated CPort Id on the given host device.
95 static void gb_connection_hd_cport_id_free(struct gb_connection *connection)
97 struct ida *ida = &connection->hd->cport_id_map;
99 spin_lock(&connection->hd->cport_id_map_lock);
100 ida_simple_remove(ida, connection->hd_cport_id);
101 spin_unlock(&connection->hd->cport_id_map_lock);
102 connection->hd_cport_id = CPORT_ID_BAD;
105 static ssize_t state_show(struct device *dev, struct device_attribute *attr,
108 struct gb_connection *connection = to_gb_connection(dev);
110 return sprintf(buf, "%d", connection->state);
112 static DEVICE_ATTR_RO(state);
114 static ssize_t protocol_show(struct device *dev, struct device_attribute *attr,
117 struct gb_connection *connection = to_gb_connection(dev);
119 return sprintf(buf, "%d", connection->protocol);
121 static DEVICE_ATTR_RO(protocol);
123 static struct attribute *connection_attrs[] = {
124 &dev_attr_state.attr,
125 &dev_attr_protocol.attr,
129 ATTRIBUTE_GROUPS(connection);
131 static void gb_connection_release(struct device *dev)
133 struct gb_connection *connection = to_gb_connection(dev);
138 static struct device_type greybus_connection_type = {
139 .name = "greybus_connection",
140 .release = gb_connection_release,
144 * Set up a Greybus connection, representing the bidirectional link
145 * between a CPort on a (local) Greybus host device and a CPort on
146 * another Greybus module.
148 * A connection also maintains the state of operations sent over the
151 * Returns a pointer to the new connection if successful, or a null
154 struct gb_connection *gb_connection_create(struct gb_interface *interface,
155 u16 cport_id, enum greybus_protocol protocol)
157 struct gb_connection *connection;
158 struct greybus_host_device *hd;
161 connection = kzalloc(sizeof(*connection), GFP_KERNEL);
165 hd = interface->gmod->hd;
166 connection->hd = hd; /* XXX refcount? */
167 if (!gb_connection_hd_cport_id_alloc(connection)) {
168 /* kref_put(connection->hd); */
173 connection->interface = interface;
174 connection->interface_cport_id = cport_id;
175 connection->protocol = protocol;
176 connection->state = GB_CONNECTION_STATE_DISABLED;
178 connection->dev.parent = &interface->dev;
179 connection->dev.driver = NULL;
180 connection->dev.bus = &greybus_bus_type;
181 connection->dev.type = &greybus_connection_type;
182 connection->dev.groups = connection_groups;
183 device_initialize(&connection->dev);
184 dev_set_name(&connection->dev, "%s:%d",
185 dev_name(&interface->dev), cport_id);
187 retval = device_add(&connection->dev);
193 spin_lock_irq(&gb_connections_lock);
194 _gb_hd_connection_insert(hd, connection);
195 list_add_tail(&connection->interface_links, &interface->connections);
196 spin_unlock_irq(&gb_connections_lock);
198 INIT_LIST_HEAD(&connection->operations);
199 connection->pending = RB_ROOT;
200 atomic_set(&connection->op_cycle, 0);
206 * Tear down a previously set up connection.
208 void gb_connection_destroy(struct gb_connection *connection)
210 struct gb_operation *operation;
211 struct gb_operation *next;
213 if (WARN_ON(!connection))
216 /* XXX Need to wait for any outstanding requests to complete */
217 WARN_ON(!list_empty(&connection->operations));
219 list_for_each_entry_safe(operation, next, &connection->operations,
221 gb_operation_cancel(operation);
223 spin_lock_irq(&gb_connections_lock);
224 list_del(&connection->interface_links);
225 _gb_hd_connection_remove(connection);
226 spin_unlock_irq(&gb_connections_lock);
228 gb_connection_hd_cport_id_free(connection);
230 device_del(&connection->dev);
233 u16 gb_connection_operation_id(struct gb_connection *connection)
235 return (u16)(atomic_inc_return(&connection->op_cycle) & (int)U16_MAX);
238 void gb_connection_err(struct gb_connection *connection, const char *fmt, ...)
240 struct va_format vaf;
248 pr_err("greybus: [%hhu:%hhu:%hu]: %pV\n",
249 connection->interface->gmod->module_id,
250 connection->interface->id,
251 connection->interface_cport_id, &vaf);
257 * XXX Protocols should have a set of function pointers:
258 * ->init (called here, to initialize the device)
260 * ->exit (reverse of init)
262 int gb_connection_init(struct gb_connection *connection)
266 /* Need to enable the connection to initialize it */
267 connection->state = GB_CONNECTION_STATE_ENABLED;
268 switch (connection->protocol) {
269 case GREYBUS_PROTOCOL_I2C:
270 connection->handler = &gb_i2c_connection_handler;
272 case GREYBUS_PROTOCOL_GPIO:
273 connection->handler = &gb_gpio_connection_handler;
275 case GREYBUS_PROTOCOL_BATTERY:
276 connection->handler = &gb_battery_connection_handler;
278 case GREYBUS_PROTOCOL_UART:
279 connection->handler = &gb_uart_connection_handler;
281 case GREYBUS_PROTOCOL_CONTROL:
282 case GREYBUS_PROTOCOL_AP:
283 case GREYBUS_PROTOCOL_HID:
284 case GREYBUS_PROTOCOL_LED:
285 case GREYBUS_PROTOCOL_VENDOR:
287 gb_connection_err(connection, "unimplemented protocol %u",
288 (u32)connection->protocol);
294 connection->state = GB_CONNECTION_STATE_ERROR;
299 void gb_connection_exit(struct gb_connection *connection)
301 if (!connection->handler) {
302 gb_connection_err(connection, "uninitialized connection");
305 connection->state = GB_CONNECTION_STATE_DESTROYING;
306 connection->handler->connection_exit(connection);