greybus: svc: connection: ask SVC to create connections
[cascardo/linux.git] / drivers / staging / greybus / connection.c
1 /*
2  * Greybus connections
3  *
4  * Copyright 2014 Google Inc.
5  * Copyright 2014 Linaro Ltd.
6  *
7  * Released under the GPLv2 only.
8  */
9
10 #include <linux/workqueue.h>
11
12 #include "greybus.h"
13
14 static DEFINE_SPINLOCK(gb_connections_lock);
15
16 /* This is only used at initialization time; no locking is required. */
17 static struct gb_connection *
18 gb_connection_intf_find(struct gb_interface *intf, u16 cport_id)
19 {
20         struct greybus_host_device *hd = intf->hd;
21         struct gb_connection *connection;
22
23         list_for_each_entry(connection, &hd->connections, hd_links)
24                 if (connection->bundle->intf == intf &&
25                                 connection->intf_cport_id == cport_id)
26                         return connection;
27         return NULL;
28 }
29
30 static struct gb_connection *
31 gb_connection_hd_find(struct greybus_host_device *hd, u16 cport_id)
32 {
33         struct gb_connection *connection;
34         unsigned long flags;
35
36         spin_lock_irqsave(&gb_connections_lock, flags);
37         list_for_each_entry(connection, &hd->connections, hd_links)
38                 if (connection->hd_cport_id == cport_id)
39                         goto found;
40         connection = NULL;
41 found:
42         spin_unlock_irqrestore(&gb_connections_lock, flags);
43
44         return connection;
45 }
46
47 /*
48  * Callback from the host driver to let us know that data has been
49  * received on the bundle.
50  */
51 void greybus_data_rcvd(struct greybus_host_device *hd, u16 cport_id,
52                         u8 *data, size_t length)
53 {
54         struct gb_connection *connection;
55
56         connection = gb_connection_hd_find(hd, cport_id);
57         if (!connection) {
58                 dev_err(hd->parent,
59                         "nonexistent connection (%zu bytes dropped)\n", length);
60                 return;
61         }
62         gb_connection_recv(connection, data, length);
63 }
64 EXPORT_SYMBOL_GPL(greybus_data_rcvd);
65
66 static ssize_t state_show(struct device *dev, struct device_attribute *attr,
67                           char *buf)
68 {
69         struct gb_connection *connection = to_gb_connection(dev);
70         enum gb_connection_state state;
71
72         spin_lock_irq(&connection->lock);
73         state = connection->state;
74         spin_unlock_irq(&connection->lock);
75
76         return sprintf(buf, "%d\n", state);
77 }
78 static DEVICE_ATTR_RO(state);
79
80 static ssize_t
81 protocol_id_show(struct device *dev, struct device_attribute *attr, char *buf)
82 {
83         struct gb_connection *connection = to_gb_connection(dev);
84
85         if (connection->protocol)
86                 return sprintf(buf, "%d\n", connection->protocol->id);
87         else
88                 return -EINVAL;
89 }
90 static DEVICE_ATTR_RO(protocol_id);
91
92 static struct attribute *connection_attrs[] = {
93         &dev_attr_state.attr,
94         &dev_attr_protocol_id.attr,
95         NULL,
96 };
97
98 ATTRIBUTE_GROUPS(connection);
99
100 static void gb_connection_release(struct device *dev)
101 {
102         struct gb_connection *connection = to_gb_connection(dev);
103
104         destroy_workqueue(connection->wq);
105         kfree(connection);
106 }
107
108 struct device_type greybus_connection_type = {
109         .name =         "greybus_connection",
110         .release =      gb_connection_release,
111 };
112
113
114 int svc_update_connection(struct gb_interface *intf,
115                           struct gb_connection *connection)
116 {
117         struct gb_bundle *bundle;
118
119         bundle = gb_bundle_create(intf, GB_SVC_BUNDLE_ID, GREYBUS_CLASS_SVC);
120         if (!bundle)
121                 return -EINVAL;
122
123         device_del(&connection->dev);
124         connection->bundle = bundle;
125         connection->dev.parent = &bundle->dev;
126         dev_set_name(&connection->dev, "%s:%d", dev_name(&bundle->dev),
127                      GB_SVC_CPORT_ID);
128
129         WARN_ON(device_add(&connection->dev));
130
131         spin_lock_irq(&gb_connections_lock);
132         list_add(&connection->bundle_links, &bundle->connections);
133         spin_unlock_irq(&gb_connections_lock);
134
135         return 0;
136 }
137
138 void gb_connection_bind_protocol(struct gb_connection *connection)
139 {
140         struct gb_protocol *protocol;
141
142         /* If we already have a protocol bound here, just return */
143         if (connection->protocol)
144                 return;
145
146         protocol = gb_protocol_get(connection->protocol_id,
147                                    connection->major,
148                                    connection->minor);
149         if (!protocol)
150                 return;
151         connection->protocol = protocol;
152
153         /*
154          * If we have a valid device_id for the interface block, then we have an
155          * active device, so bring up the connection at the same time.
156          */
157         if ((!connection->bundle &&
158              connection->hd_cport_id == GB_SVC_CPORT_ID) ||
159             connection->bundle->intf->device_id != GB_DEVICE_ID_BAD)
160                 gb_connection_init(connection);
161 }
162
163 /*
164  * Set up a Greybus connection, representing the bidirectional link
165  * between a CPort on a (local) Greybus host device and a CPort on
166  * another Greybus module.
167  *
168  * A connection also maintains the state of operations sent over the
169  * connection.
170  *
171  * Returns a pointer to the new connection if successful, or a null
172  * pointer otherwise.
173  */
174 struct gb_connection *
175 gb_connection_create_range(struct greybus_host_device *hd,
176                            struct gb_bundle *bundle, struct device *parent,
177                            u16 cport_id, u8 protocol_id, u32 ida_start,
178                            u32 ida_end)
179 {
180         struct gb_connection *connection;
181         struct ida *id_map = &hd->cport_id_map;
182         int hd_cport_id;
183         int retval;
184         u8 major = 0;
185         u8 minor = 1;
186
187         /*
188          * If a manifest tries to reuse a cport, reject it.  We
189          * initialize connections serially so we don't need to worry
190          * about holding the connection lock.
191          */
192         if (bundle && gb_connection_intf_find(bundle->intf, cport_id)) {
193                 pr_err("duplicate interface cport id 0x%04hx\n", cport_id);
194                 return NULL;
195         }
196
197         hd_cport_id = ida_simple_get(id_map, ida_start, ida_end, GFP_KERNEL);
198         if (hd_cport_id < 0)
199                 return NULL;
200
201         connection = kzalloc(sizeof(*connection), GFP_KERNEL);
202         if (!connection)
203                 goto err_remove_ida;
204
205         connection->hd_cport_id = hd_cport_id;
206         connection->intf_cport_id = cport_id;
207         connection->hd = hd;
208
209         connection->protocol_id = protocol_id;
210         connection->major = major;
211         connection->minor = minor;
212
213         connection->bundle = bundle;
214         connection->state = GB_CONNECTION_STATE_DISABLED;
215
216         atomic_set(&connection->op_cycle, 0);
217         spin_lock_init(&connection->lock);
218         INIT_LIST_HEAD(&connection->operations);
219
220         connection->wq = alloc_workqueue("%s:%d", WQ_UNBOUND, 1,
221                                          dev_name(parent), cport_id);
222         if (!connection->wq)
223                 goto err_free_connection;
224
225         connection->dev.parent = parent;
226         connection->dev.bus = &greybus_bus_type;
227         connection->dev.type = &greybus_connection_type;
228         connection->dev.groups = connection_groups;
229         device_initialize(&connection->dev);
230         dev_set_name(&connection->dev, "%s:%d",
231                      dev_name(parent), cport_id);
232
233         retval = device_add(&connection->dev);
234         if (retval) {
235                 connection->hd_cport_id = CPORT_ID_BAD;
236                 put_device(&connection->dev);
237
238                 pr_err("failed to add connection device for cport 0x%04hx\n",
239                         cport_id);
240
241                 goto err_remove_ida;
242         }
243
244         spin_lock_irq(&gb_connections_lock);
245         list_add(&connection->hd_links, &hd->connections);
246
247         if (bundle)
248                 list_add(&connection->bundle_links, &bundle->connections);
249         else
250                 INIT_LIST_HEAD(&connection->bundle_links);
251
252         spin_unlock_irq(&gb_connections_lock);
253
254         if (hd_cport_id != GB_SVC_CPORT_ID) {
255                 gb_svc_connection_create(hd->svc,
256                                          hd->endo->ap_intf_id, hd_cport_id,
257                                          bundle->intf->interface_id, cport_id);
258         }
259
260         gb_connection_bind_protocol(connection);
261         if (!connection->protocol)
262                 dev_warn(&connection->dev,
263                          "protocol 0x%02hhx handler not found\n", protocol_id);
264
265         return connection;
266
267 err_free_connection:
268         kfree(connection);
269 err_remove_ida:
270         ida_simple_remove(id_map, hd_cport_id);
271
272         return NULL;
273 }
274
275 struct gb_connection *gb_connection_create(struct gb_bundle *bundle,
276                                 u16 cport_id, u8 protocol_id)
277 {
278         return gb_connection_create_range(bundle->intf->hd, bundle,
279                                           &bundle->dev, cport_id, protocol_id,
280                                           0, CPORT_ID_MAX);
281 }
282
283 /*
284  * Cancel all active operations on a connection.
285  *
286  * Should only be called during connection tear down.
287  */
288 static void gb_connection_cancel_operations(struct gb_connection *connection,
289                                                 int errno)
290 {
291         struct gb_operation *operation;
292
293         spin_lock_irq(&connection->lock);
294         while (!list_empty(&connection->operations)) {
295                 operation = list_last_entry(&connection->operations,
296                                                 struct gb_operation, links);
297                 gb_operation_get(operation);
298                 spin_unlock_irq(&connection->lock);
299
300                 if (gb_operation_is_incoming(operation))
301                         gb_operation_cancel_incoming(operation, errno);
302                 else
303                         gb_operation_cancel(operation, errno);
304
305                 gb_operation_put(operation);
306
307                 spin_lock_irq(&connection->lock);
308         }
309         spin_unlock_irq(&connection->lock);
310 }
311
312 /*
313  * Tear down a previously set up connection.
314  */
315 void gb_connection_destroy(struct gb_connection *connection)
316 {
317         struct ida *id_map;
318
319         if (WARN_ON(!connection))
320                 return;
321
322         spin_lock_irq(&gb_connections_lock);
323         list_del(&connection->bundle_links);
324         list_del(&connection->hd_links);
325         spin_unlock_irq(&gb_connections_lock);
326
327         if (connection->protocol)
328                 gb_protocol_put(connection->protocol);
329         connection->protocol = NULL;
330
331         id_map = &connection->hd->cport_id_map;
332         ida_simple_remove(id_map, connection->hd_cport_id);
333         connection->hd_cport_id = CPORT_ID_BAD;
334
335         device_unregister(&connection->dev);
336 }
337
338 int gb_connection_init(struct gb_connection *connection)
339 {
340         int cport_id = connection->intf_cport_id;
341         int ret;
342
343         if (!connection->protocol) {
344                 dev_warn(&connection->dev, "init without protocol.\n");
345                 return 0;
346         }
347
348         /*
349          * Inform Interface about Active CPorts. We don't need to do this
350          * operation for control cport.
351          */
352         if (cport_id != GB_CONTROL_CPORT_ID &&
353             connection->hd_cport_id != GB_SVC_CPORT_ID) {
354                 struct gb_control *control = connection->bundle->intf->control;
355
356                 ret = gb_control_connected_operation(control, cport_id);
357                 if (ret) {
358                         dev_warn(&connection->dev,
359                                  "Failed to connect CPort-%d (%d)\n",
360                                  cport_id, ret);
361                         return 0;
362                 }
363         }
364
365         /* Need to enable the connection to initialize it */
366         spin_lock_irq(&connection->lock);
367         connection->state = GB_CONNECTION_STATE_ENABLED;
368         spin_unlock_irq(&connection->lock);
369
370         ret = connection->protocol->connection_init(connection);
371         if (ret) {
372                 spin_lock_irq(&connection->lock);
373                 connection->state = GB_CONNECTION_STATE_ERROR;
374                 spin_unlock_irq(&connection->lock);
375         }
376
377         return ret;
378 }
379
380 void gb_connection_exit(struct gb_connection *connection)
381 {
382         int cport_id = connection->intf_cport_id;
383
384         if (!connection->protocol) {
385                 dev_warn(&connection->dev, "exit without protocol.\n");
386                 return;
387         }
388
389         spin_lock_irq(&connection->lock);
390         if (connection->state != GB_CONNECTION_STATE_ENABLED) {
391                 spin_unlock_irq(&connection->lock);
392                 return;
393         }
394         connection->state = GB_CONNECTION_STATE_DESTROYING;
395         spin_unlock_irq(&connection->lock);
396
397         gb_connection_cancel_operations(connection, -ESHUTDOWN);
398
399         connection->protocol->connection_exit(connection);
400
401         /*
402          * Inform Interface about In-active CPorts. We don't need to do this
403          * operation for control cport.
404          */
405         if (cport_id != GB_CONTROL_CPORT_ID &&
406             connection->hd_cport_id != GB_SVC_CPORT_ID) {
407                 struct gb_control *control = connection->bundle->intf->control;
408                 int ret;
409
410                 ret = gb_control_disconnected_operation(control, cport_id);
411                 if (ret)
412                         dev_warn(&connection->dev,
413                                  "Failed to disconnect CPort-%d (%d)\n",
414                                  cport_id, ret);
415         }
416 }
417
418 void gb_hd_connections_exit(struct greybus_host_device *hd)
419 {
420         struct gb_connection *connection;
421
422         list_for_each_entry(connection, &hd->connections, hd_links) {
423                 gb_connection_exit(connection);
424                 gb_connection_destroy(connection);
425         }
426 }