greybus: connection: remove WARN_ON from destroy
[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
15 static DEFINE_SPINLOCK(gb_connections_lock);
16
17 /* This is only used at initialization time; no locking is required. */
18 static struct gb_connection *
19 gb_connection_intf_find(struct gb_interface *intf, u16 cport_id)
20 {
21         struct gb_host_device *hd = intf->hd;
22         struct gb_connection *connection;
23
24         list_for_each_entry(connection, &hd->connections, hd_links) {
25                 if (connection->intf == intf &&
26                                 connection->intf_cport_id == cport_id)
27                         return connection;
28         }
29
30         return NULL;
31 }
32
33 static struct gb_connection *
34 gb_connection_hd_find(struct gb_host_device *hd, u16 cport_id)
35 {
36         struct gb_connection *connection;
37         unsigned long flags;
38
39         spin_lock_irqsave(&gb_connections_lock, flags);
40         list_for_each_entry(connection, &hd->connections, hd_links)
41                 if (connection->hd_cport_id == cport_id)
42                         goto found;
43         connection = NULL;
44 found:
45         spin_unlock_irqrestore(&gb_connections_lock, flags);
46
47         return connection;
48 }
49
50 /*
51  * Callback from the host driver to let us know that data has been
52  * received on the bundle.
53  */
54 void greybus_data_rcvd(struct gb_host_device *hd, u16 cport_id,
55                         u8 *data, size_t length)
56 {
57         struct gb_connection *connection;
58
59         connection = gb_connection_hd_find(hd, cport_id);
60         if (!connection) {
61                 dev_err(&hd->dev,
62                         "nonexistent connection (%zu bytes dropped)\n", length);
63                 return;
64         }
65         gb_connection_recv(connection, data, length);
66 }
67 EXPORT_SYMBOL_GPL(greybus_data_rcvd);
68
69 static DEFINE_MUTEX(connection_mutex);
70
71 static void gb_connection_kref_release(struct kref *kref)
72 {
73         struct gb_connection *connection;
74
75         connection = container_of(kref, struct gb_connection, kref);
76         destroy_workqueue(connection->wq);
77         kfree(connection);
78         mutex_unlock(&connection_mutex);
79 }
80
81 static void gb_connection_init_name(struct gb_connection *connection)
82 {
83         u16 hd_cport_id = connection->hd_cport_id;
84         u16 cport_id = 0;
85         u8 intf_id = 0;
86
87         if (connection->intf) {
88                 intf_id = connection->intf->interface_id;
89                 cport_id = connection->intf_cport_id;
90         }
91
92         snprintf(connection->name, sizeof(connection->name),
93                         "%u/%u:%u", hd_cport_id, intf_id, cport_id);
94 }
95
96 /*
97  * gb_connection_create() - create a Greybus connection
98  * @hd:                 host device of the connection
99  * @hd_cport_id:        host-device cport id, or -1 for dynamic allocation
100  * @intf:               remote interface, or NULL for static connections
101  * @bundle:             remote-interface bundle (may be NULL)
102  * @cport_id:           remote-interface cport id, or 0 for static connections
103  * @protocol_id:        protocol id
104  *
105  * Create a Greybus connection, representing the bidirectional link
106  * between a CPort on a (local) Greybus host device and a CPort on
107  * another Greybus interface.
108  *
109  * A connection also maintains the state of operations sent over the
110  * connection.
111  *
112  * Return: A pointer to the new connection if successful, or NULL otherwise.
113  */
114 static struct gb_connection *
115 gb_connection_create(struct gb_host_device *hd, int hd_cport_id,
116                                 struct gb_interface *intf,
117                                 struct gb_bundle *bundle, int cport_id,
118                                 u8 protocol_id)
119 {
120         struct gb_connection *connection;
121         struct ida *id_map = &hd->cport_id_map;
122         int ida_start, ida_end;
123
124         /*
125          * If a manifest tries to reuse a cport, reject it.  We
126          * initialize connections serially so we don't need to worry
127          * about holding the connection lock.
128          */
129         if (bundle && gb_connection_intf_find(bundle->intf, cport_id)) {
130                 dev_err(&bundle->dev, "cport %u already connected\n",
131                                 cport_id);
132                 return NULL;
133         }
134
135         if (hd_cport_id < 0) {
136                 ida_start = 0;
137                 ida_end = hd->num_cports;
138         } else if (hd_cport_id < hd->num_cports) {
139                 ida_start = hd_cport_id;
140                 ida_end = hd_cport_id + 1;
141         } else {
142                 dev_err(&hd->dev, "cport %d not available\n", hd_cport_id);
143                 return NULL;
144         }
145
146         hd_cport_id = ida_simple_get(id_map, ida_start, ida_end, GFP_KERNEL);
147         if (hd_cport_id < 0)
148                 return NULL;
149
150         connection = kzalloc(sizeof(*connection), GFP_KERNEL);
151         if (!connection)
152                 goto err_remove_ida;
153
154         connection->hd_cport_id = hd_cport_id;
155         connection->intf_cport_id = cport_id;
156         connection->hd = hd;
157         connection->intf = intf;
158
159         connection->protocol_id = protocol_id;
160
161         connection->bundle = bundle;
162         connection->state = GB_CONNECTION_STATE_DISABLED;
163
164         atomic_set(&connection->op_cycle, 0);
165         mutex_init(&connection->mutex);
166         spin_lock_init(&connection->lock);
167         INIT_LIST_HEAD(&connection->operations);
168
169         connection->wq = alloc_workqueue("%s:%d", WQ_UNBOUND, 1,
170                                          dev_name(&hd->dev), hd_cport_id);
171         if (!connection->wq)
172                 goto err_free_connection;
173
174         kref_init(&connection->kref);
175
176         gb_connection_init_name(connection);
177
178         spin_lock_irq(&gb_connections_lock);
179         list_add(&connection->hd_links, &hd->connections);
180
181         if (bundle)
182                 list_add(&connection->bundle_links, &bundle->connections);
183         else
184                 INIT_LIST_HEAD(&connection->bundle_links);
185
186         spin_unlock_irq(&gb_connections_lock);
187
188         return connection;
189
190 err_free_connection:
191         kfree(connection);
192 err_remove_ida:
193         ida_simple_remove(id_map, hd_cport_id);
194
195         return NULL;
196 }
197
198 struct gb_connection *
199 gb_connection_create_static(struct gb_host_device *hd,
200                                         u16 hd_cport_id, u8 protocol_id)
201 {
202         return gb_connection_create(hd, hd_cport_id, NULL, NULL, 0,
203                                                                 protocol_id);
204 }
205
206 struct gb_connection *
207 gb_connection_create_dynamic(struct gb_interface *intf,
208                                         struct gb_bundle *bundle,
209                                         u16 cport_id, u8 protocol_id)
210 {
211         return gb_connection_create(intf->hd, -1, intf, bundle, cport_id,
212                                                                 protocol_id);
213 }
214
215 static int gb_connection_hd_cport_enable(struct gb_connection *connection)
216 {
217         struct gb_host_device *hd = connection->hd;
218         int ret;
219
220         if (!hd->driver->cport_enable)
221                 return 0;
222
223         ret = hd->driver->cport_enable(hd, connection->hd_cport_id);
224         if (ret) {
225                 dev_err(&hd->dev,
226                         "failed to enable host cport: %d\n", ret);
227                 return ret;
228         }
229
230         return 0;
231 }
232
233 static void gb_connection_hd_cport_disable(struct gb_connection *connection)
234 {
235         struct gb_host_device *hd = connection->hd;
236
237         if (!hd->driver->cport_disable)
238                 return;
239
240         hd->driver->cport_disable(hd, connection->hd_cport_id);
241 }
242
243 /*
244  * Request the SVC to create a connection from AP's cport to interface's
245  * cport.
246  */
247 static int
248 gb_connection_svc_connection_create(struct gb_connection *connection)
249 {
250         struct gb_host_device *hd = connection->hd;
251         struct gb_interface *intf;
252         int ret;
253
254         if (gb_connection_is_static(connection))
255                 return 0;
256
257         intf = connection->intf;
258         ret = gb_svc_connection_create(hd->svc,
259                         hd->svc->ap_intf_id,
260                         connection->hd_cport_id,
261                         intf->interface_id,
262                         connection->intf_cport_id,
263                         intf->boot_over_unipro);
264         if (ret) {
265                 dev_err(&connection->hd->dev,
266                         "%s: failed to create svc connection: %d\n",
267                         connection->name, ret);
268                 return ret;
269         }
270
271         return 0;
272 }
273
274 static void
275 gb_connection_svc_connection_destroy(struct gb_connection *connection)
276 {
277         if (gb_connection_is_static(connection))
278                 return;
279
280         gb_svc_connection_destroy(connection->hd->svc,
281                                   connection->hd->svc->ap_intf_id,
282                                   connection->hd_cport_id,
283                                   connection->intf->interface_id,
284                                   connection->intf_cport_id);
285 }
286
287 /* Inform Interface about active CPorts */
288 static int gb_connection_control_connected(struct gb_connection *connection)
289 {
290         struct gb_control *control;
291         u16 cport_id = connection->intf_cport_id;
292         int ret;
293
294         if (gb_connection_is_static(connection))
295                 return 0;
296
297         control = connection->intf->control;
298
299         if (connection == control->connection)
300                 return 0;
301
302         ret = gb_control_connected_operation(control, cport_id);
303         if (ret) {
304                 dev_err(&connection->bundle->dev,
305                         "failed to connect cport: %d\n", ret);
306                 return ret;
307         }
308
309         return 0;
310 }
311
312 /* Inform Interface about inactive CPorts */
313 static void
314 gb_connection_control_disconnected(struct gb_connection *connection)
315 {
316         struct gb_control *control;
317         u16 cport_id = connection->intf_cport_id;
318         int ret;
319
320         if (gb_connection_is_static(connection))
321                 return;
322
323         control = connection->intf->control;
324
325         if (connection == control->connection)
326                 return;
327
328         ret = gb_control_disconnected_operation(control, cport_id);
329         if (ret) {
330                 dev_warn(&connection->bundle->dev,
331                          "failed to disconnect cport: %d\n", ret);
332         }
333 }
334
335 /*
336  * Cancel all active operations on a connection.
337  *
338  * Locking: Called with connection lock held and state set to DISABLED.
339  */
340 static void gb_connection_cancel_operations(struct gb_connection *connection,
341                                                 int errno)
342 {
343         struct gb_operation *operation;
344
345         while (!list_empty(&connection->operations)) {
346                 operation = list_last_entry(&connection->operations,
347                                                 struct gb_operation, links);
348                 gb_operation_get(operation);
349                 spin_unlock_irq(&connection->lock);
350
351                 if (gb_operation_is_incoming(operation))
352                         gb_operation_cancel_incoming(operation, errno);
353                 else
354                         gb_operation_cancel(operation, errno);
355
356                 gb_operation_put(operation);
357
358                 spin_lock_irq(&connection->lock);
359         }
360 }
361
362 /*
363  * Cancel all active incoming operations on a connection.
364  *
365  * Locking: Called with connection lock held and state set to ENABLED_TX.
366  */
367 static void
368 gb_connection_flush_incoming_operations(struct gb_connection *connection,
369                                                 int errno)
370 {
371         struct gb_operation *operation;
372         bool incoming;
373
374         while (!list_empty(&connection->operations)) {
375                 incoming = false;
376                 list_for_each_entry(operation, &connection->operations,
377                                                                 links) {
378                         if (gb_operation_is_incoming(operation)) {
379                                 gb_operation_get(operation);
380                                 incoming = true;
381                                 break;
382                         }
383                 }
384
385                 if (!incoming)
386                         break;
387
388                 spin_unlock_irq(&connection->lock);
389
390                 /* FIXME: flush, not cancel? */
391                 gb_operation_cancel_incoming(operation, errno);
392                 gb_operation_put(operation);
393
394                 spin_lock_irq(&connection->lock);
395         }
396 }
397
398 int gb_connection_enable(struct gb_connection *connection,
399                                 gb_request_handler_t handler)
400 {
401         int ret;
402
403         mutex_lock(&connection->mutex);
404
405         if (connection->state == GB_CONNECTION_STATE_ENABLED)
406                 goto out_unlock;
407
408         if (connection->state == GB_CONNECTION_STATE_ENABLED_TX) {
409                 if (!handler)
410                         goto out_unlock;
411
412                 spin_lock_irq(&connection->lock);
413                 connection->handler = handler;
414                 connection->state = GB_CONNECTION_STATE_ENABLED;
415                 spin_unlock_irq(&connection->lock);
416
417                 goto out_unlock;
418         }
419
420         ret = gb_connection_hd_cport_enable(connection);
421         if (ret)
422                 goto err_unlock;
423
424         ret = gb_connection_svc_connection_create(connection);
425         if (ret)
426                 goto err_hd_cport_disable;
427
428         spin_lock_irq(&connection->lock);
429         connection->handler = handler;
430         if (handler)
431                 connection->state = GB_CONNECTION_STATE_ENABLED;
432         else
433                 connection->state = GB_CONNECTION_STATE_ENABLED_TX;
434         spin_unlock_irq(&connection->lock);
435
436         ret = gb_connection_control_connected(connection);
437         if (ret)
438                 goto err_svc_destroy;
439
440 out_unlock:
441         mutex_unlock(&connection->mutex);
442
443         return 0;
444
445 err_svc_destroy:
446         spin_lock_irq(&connection->lock);
447         connection->state = GB_CONNECTION_STATE_DISABLED;
448         gb_connection_cancel_operations(connection, -ESHUTDOWN);
449         connection->handler = NULL;
450         spin_unlock_irq(&connection->lock);
451
452         gb_connection_svc_connection_destroy(connection);
453 err_hd_cport_disable:
454         gb_connection_hd_cport_disable(connection);
455 err_unlock:
456         mutex_unlock(&connection->mutex);
457
458         return ret;
459 }
460 EXPORT_SYMBOL_GPL(gb_connection_enable);
461
462 void gb_connection_disable_rx(struct gb_connection *connection)
463 {
464         mutex_lock(&connection->mutex);
465
466         spin_lock_irq(&connection->lock);
467         if (connection->state != GB_CONNECTION_STATE_ENABLED) {
468                 spin_unlock_irq(&connection->lock);
469                 goto out_unlock;
470         }
471         connection->state = GB_CONNECTION_STATE_ENABLED_TX;
472         gb_connection_flush_incoming_operations(connection, -ESHUTDOWN);
473         connection->handler = NULL;
474         spin_unlock_irq(&connection->lock);
475
476 out_unlock:
477         mutex_unlock(&connection->mutex);
478 }
479
480 void gb_connection_disable(struct gb_connection *connection)
481 {
482         mutex_lock(&connection->mutex);
483
484         if (connection->state == GB_CONNECTION_STATE_DISABLED)
485                 goto out_unlock;
486
487         gb_connection_control_disconnected(connection);
488
489         spin_lock_irq(&connection->lock);
490         connection->state = GB_CONNECTION_STATE_DISABLED;
491         gb_connection_cancel_operations(connection, -ESHUTDOWN);
492         connection->handler = NULL;
493         spin_unlock_irq(&connection->lock);
494
495         gb_connection_svc_connection_destroy(connection);
496         gb_connection_hd_cport_disable(connection);
497
498 out_unlock:
499         mutex_unlock(&connection->mutex);
500 }
501 EXPORT_SYMBOL_GPL(gb_connection_disable);
502
503 /*
504  * Tear down a previously set up connection.
505  */
506 void gb_connection_destroy(struct gb_connection *connection)
507 {
508         struct ida *id_map;
509
510         if (!connection)
511                 return;
512
513         spin_lock_irq(&gb_connections_lock);
514         list_del(&connection->bundle_links);
515         list_del(&connection->hd_links);
516         spin_unlock_irq(&gb_connections_lock);
517
518         id_map = &connection->hd->cport_id_map;
519         ida_simple_remove(id_map, connection->hd_cport_id);
520         connection->hd_cport_id = CPORT_ID_BAD;
521
522         kref_put_mutex(&connection->kref, gb_connection_kref_release,
523                        &connection_mutex);
524 }
525
526 void gb_connection_latency_tag_enable(struct gb_connection *connection)
527 {
528         struct gb_host_device *hd = connection->hd;
529         int ret;
530
531         if (!hd->driver->latency_tag_enable)
532                 return;
533
534         ret = hd->driver->latency_tag_enable(hd, connection->hd_cport_id);
535         if (ret) {
536                 dev_err(&connection->hd->dev,
537                         "%s: failed to enable latency tag: %d\n",
538                         connection->name, ret);
539         }
540 }
541 EXPORT_SYMBOL_GPL(gb_connection_latency_tag_enable);
542
543 void gb_connection_latency_tag_disable(struct gb_connection *connection)
544 {
545         struct gb_host_device *hd = connection->hd;
546         int ret;
547
548         if (!hd->driver->latency_tag_disable)
549                 return;
550
551         ret = hd->driver->latency_tag_disable(hd, connection->hd_cport_id);
552         if (ret) {
553                 dev_err(&connection->hd->dev,
554                         "%s: failed to disable latency tag: %d\n",
555                         connection->name, ret);
556         }
557 }
558 EXPORT_SYMBOL_GPL(gb_connection_latency_tag_disable);