greybus: connection: fix potential null-deref in connection create
[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 DEFINE_MUTEX(connection_mutex);
67
68 static void gb_connection_kref_release(struct kref *kref)
69 {
70         struct gb_connection *connection;
71
72         connection = container_of(kref, struct gb_connection, kref);
73         destroy_workqueue(connection->wq);
74         kfree(connection);
75         mutex_unlock(&connection_mutex);
76 }
77
78 int svc_update_connection(struct gb_interface *intf,
79                           struct gb_connection *connection)
80 {
81         struct gb_bundle *bundle;
82
83         bundle = gb_bundle_create(intf, GB_SVC_BUNDLE_ID, GREYBUS_CLASS_SVC);
84         if (!bundle)
85                 return -EINVAL;
86
87         connection->bundle = bundle;
88
89         spin_lock_irq(&gb_connections_lock);
90         list_add(&connection->bundle_links, &bundle->connections);
91         spin_unlock_irq(&gb_connections_lock);
92
93         return 0;
94 }
95
96 /*
97  * Set up a Greybus connection, representing the bidirectional link
98  * between a CPort on a (local) Greybus host device and a CPort on
99  * another Greybus module.
100  *
101  * A connection also maintains the state of operations sent over the
102  * connection.
103  *
104  * Returns a pointer to the new connection if successful, or a null
105  * pointer otherwise.
106  */
107 struct gb_connection *
108 gb_connection_create_range(struct greybus_host_device *hd,
109                            struct gb_bundle *bundle, struct device *parent,
110                            u16 cport_id, u8 protocol_id, u32 ida_start,
111                            u32 ida_end)
112 {
113         struct gb_connection *connection;
114         struct ida *id_map = &hd->cport_id_map;
115         int hd_cport_id;
116         int retval;
117         u8 major = 0;
118         u8 minor = 1;
119
120         /*
121          * If a manifest tries to reuse a cport, reject it.  We
122          * initialize connections serially so we don't need to worry
123          * about holding the connection lock.
124          */
125         if (bundle && gb_connection_intf_find(bundle->intf, cport_id)) {
126                 dev_err(&bundle->dev, "cport 0x%04hx already connected\n",
127                                 cport_id);
128                 return NULL;
129         }
130
131         hd_cport_id = ida_simple_get(id_map, ida_start, ida_end, GFP_KERNEL);
132         if (hd_cport_id < 0)
133                 return NULL;
134
135         connection = kzalloc(sizeof(*connection), GFP_KERNEL);
136         if (!connection)
137                 goto err_remove_ida;
138
139         connection->hd_cport_id = hd_cport_id;
140         connection->intf_cport_id = cport_id;
141         connection->hd = hd;
142
143         connection->protocol_id = protocol_id;
144         connection->major = major;
145         connection->minor = minor;
146
147         connection->bundle = bundle;
148         connection->state = GB_CONNECTION_STATE_DISABLED;
149
150         atomic_set(&connection->op_cycle, 0);
151         spin_lock_init(&connection->lock);
152         INIT_LIST_HEAD(&connection->operations);
153
154         connection->wq = alloc_workqueue("%s:%d", WQ_UNBOUND, 1,
155                                          dev_name(parent), cport_id);
156         if (!connection->wq)
157                 goto err_free_connection;
158
159         kref_init(&connection->kref);
160
161         spin_lock_irq(&gb_connections_lock);
162         list_add(&connection->hd_links, &hd->connections);
163
164         if (bundle)
165                 list_add(&connection->bundle_links, &bundle->connections);
166         else
167                 INIT_LIST_HEAD(&connection->bundle_links);
168
169         spin_unlock_irq(&gb_connections_lock);
170
171         retval = gb_connection_bind_protocol(connection);
172         if (retval) {
173                 dev_err(parent, "%d: failed to bind protocol: %d\n",
174                         cport_id, retval);
175                 gb_connection_destroy(connection);
176                 return NULL;
177         }
178
179         return connection;
180
181 err_free_connection:
182         kfree(connection);
183 err_remove_ida:
184         ida_simple_remove(id_map, hd_cport_id);
185
186         return NULL;
187 }
188
189 static int gb_connection_hd_cport_enable(struct gb_connection *connection)
190 {
191         struct greybus_host_device *hd = connection->hd;
192         int ret;
193
194         if (!hd->driver->cport_enable)
195                 return 0;
196
197         ret = hd->driver->cport_enable(hd, connection->hd_cport_id);
198         if (ret) {
199                 dev_err(hd->parent,
200                         "failed to enable host cport: %d\n", ret);
201                 return ret;
202         }
203
204         return 0;
205 }
206
207 static void gb_connection_hd_cport_disable(struct gb_connection *connection)
208 {
209         struct greybus_host_device *hd = connection->hd;
210
211         if (!hd->driver->cport_disable)
212                 return;
213
214         hd->driver->cport_disable(hd, connection->hd_cport_id);
215 }
216
217 struct gb_connection *gb_connection_create(struct gb_bundle *bundle,
218                                 u16 cport_id, u8 protocol_id)
219 {
220         return gb_connection_create_range(bundle->intf->hd, bundle,
221                                           &bundle->dev, cport_id, protocol_id,
222                                           0, bundle->intf->hd->num_cports - 1);
223 }
224
225 /*
226  * Cancel all active operations on a connection.
227  *
228  * Should only be called during connection tear down.
229  */
230 static void gb_connection_cancel_operations(struct gb_connection *connection,
231                                                 int errno)
232 {
233         struct gb_operation *operation;
234
235         spin_lock_irq(&connection->lock);
236         while (!list_empty(&connection->operations)) {
237                 operation = list_last_entry(&connection->operations,
238                                                 struct gb_operation, links);
239                 gb_operation_get(operation);
240                 spin_unlock_irq(&connection->lock);
241
242                 if (gb_operation_is_incoming(operation))
243                         gb_operation_cancel_incoming(operation, errno);
244                 else
245                         gb_operation_cancel(operation, errno);
246
247                 gb_operation_put(operation);
248
249                 spin_lock_irq(&connection->lock);
250         }
251         spin_unlock_irq(&connection->lock);
252 }
253
254 /*
255  * Request the SVC to create a connection from AP's cport to interface's
256  * cport.
257  */
258 static int
259 gb_connection_svc_connection_create(struct gb_connection *connection)
260 {
261         struct greybus_host_device *hd = connection->hd;
262         struct gb_protocol *protocol = connection->protocol;
263         struct gb_interface *intf;
264         int ret;
265
266         if (protocol->flags & GB_PROTOCOL_SKIP_SVC_CONNECTION)
267                 return 0;
268
269         intf = connection->bundle->intf;
270         ret = gb_svc_connection_create(hd->svc,
271                         hd->endo->ap_intf_id,
272                         connection->hd_cport_id,
273                         intf->interface_id,
274                         connection->intf_cport_id,
275                         intf->boot_over_unipro);
276         if (ret) {
277                 dev_err(&connection->bundle->dev,
278                         "failed to create svc connection: %d\n", ret);
279                 return ret;
280         }
281
282         return 0;
283 }
284
285 static void
286 gb_connection_svc_connection_destroy(struct gb_connection *connection)
287 {
288         if (connection->protocol->flags & GB_PROTOCOL_SKIP_SVC_CONNECTION)
289                 return;
290
291         gb_svc_connection_destroy(connection->hd->svc,
292                                   connection->hd->endo->ap_intf_id,
293                                   connection->hd_cport_id,
294                                   connection->bundle->intf->interface_id,
295                                   connection->intf_cport_id);
296 }
297
298 /* Inform Interface about active CPorts */
299 static int gb_connection_control_connected(struct gb_connection *connection)
300 {
301         struct gb_protocol *protocol = connection->protocol;
302         struct gb_control *control;
303         u16 cport_id = connection->intf_cport_id;
304         int ret;
305
306         if (protocol->flags & GB_PROTOCOL_SKIP_CONTROL_CONNECTED)
307                 return 0;
308
309         control = connection->bundle->intf->control;
310
311         ret = gb_control_connected_operation(control, cport_id);
312         if (ret) {
313                 dev_err(&connection->bundle->dev,
314                         "failed to connect cport: %d\n", ret);
315                 return ret;
316         }
317
318         return 0;
319 }
320
321 /* Inform Interface about inactive CPorts */
322 static void
323 gb_connection_control_disconnected(struct gb_connection *connection)
324 {
325         struct gb_protocol *protocol = connection->protocol;
326         struct gb_control *control;
327         u16 cport_id = connection->intf_cport_id;
328         int ret;
329
330         if (protocol->flags & GB_PROTOCOL_SKIP_CONTROL_DISCONNECTED)
331                 return;
332
333         control = connection->bundle->intf->control;
334
335         ret = gb_control_disconnected_operation(control, cport_id);
336         if (ret) {
337                 dev_warn(&connection->bundle->dev,
338                          "failed to disconnect cport: %d\n", ret);
339         }
340 }
341
342 /*
343  * Request protocol version supported by the module. We don't need to do
344  * this for SVC as that is initiated by the SVC.
345  */
346 static int gb_connection_protocol_get_version(struct gb_connection *connection)
347 {
348         struct gb_protocol *protocol = connection->protocol;
349         int ret;
350
351         if (protocol->flags & GB_PROTOCOL_SKIP_VERSION)
352                 return 0;
353
354         ret = gb_protocol_get_version(connection);
355         if (ret) {
356                 dev_err(&connection->bundle->dev,
357                         "failed to get protocol version: %d\n", ret);
358                 return ret;
359         }
360
361         return 0;
362 }
363
364 static int gb_connection_init(struct gb_connection *connection)
365 {
366         struct gb_protocol *protocol = connection->protocol;
367         int ret;
368
369         ret = gb_connection_hd_cport_enable(connection);
370         if (ret)
371                 return ret;
372
373         ret = gb_connection_svc_connection_create(connection);
374         if (ret)
375                 goto err_hd_cport_disable;
376
377         ret = gb_connection_control_connected(connection);
378         if (ret)
379                 goto err_svc_destroy;
380
381         /* Need to enable the connection to initialize it */
382         spin_lock_irq(&connection->lock);
383         connection->state = GB_CONNECTION_STATE_ENABLED;
384         spin_unlock_irq(&connection->lock);
385
386         ret = gb_connection_protocol_get_version(connection);
387         if (ret)
388                 goto err_disconnect;
389
390         ret = protocol->connection_init(connection);
391         if (ret)
392                 goto err_disconnect;
393
394         return 0;
395
396 err_disconnect:
397         spin_lock_irq(&connection->lock);
398         connection->state = GB_CONNECTION_STATE_ERROR;
399         spin_unlock_irq(&connection->lock);
400
401         gb_connection_control_disconnected(connection);
402 err_svc_destroy:
403         gb_connection_svc_connection_destroy(connection);
404 err_hd_cport_disable:
405         gb_connection_hd_cport_disable(connection);
406
407         return ret;
408 }
409
410 static void gb_connection_exit(struct gb_connection *connection)
411 {
412         if (!connection->protocol)
413                 return;
414
415         spin_lock_irq(&connection->lock);
416         if (connection->state != GB_CONNECTION_STATE_ENABLED) {
417                 spin_unlock_irq(&connection->lock);
418                 return;
419         }
420         connection->state = GB_CONNECTION_STATE_DESTROYING;
421         spin_unlock_irq(&connection->lock);
422
423         gb_connection_cancel_operations(connection, -ESHUTDOWN);
424
425         connection->protocol->connection_exit(connection);
426         gb_connection_control_disconnected(connection);
427         gb_connection_svc_connection_destroy(connection);
428         gb_connection_hd_cport_disable(connection);
429 }
430
431 /*
432  * Tear down a previously set up connection.
433  */
434 void gb_connection_destroy(struct gb_connection *connection)
435 {
436         struct ida *id_map;
437
438         if (WARN_ON(!connection))
439                 return;
440
441         gb_connection_exit(connection);
442
443         spin_lock_irq(&gb_connections_lock);
444         list_del(&connection->bundle_links);
445         list_del(&connection->hd_links);
446         spin_unlock_irq(&gb_connections_lock);
447
448         if (connection->protocol)
449                 gb_protocol_put(connection->protocol);
450         connection->protocol = NULL;
451
452         id_map = &connection->hd->cport_id_map;
453         ida_simple_remove(id_map, connection->hd_cport_id);
454         connection->hd_cport_id = CPORT_ID_BAD;
455
456         kref_put_mutex(&connection->kref, gb_connection_kref_release,
457                        &connection_mutex);
458 }
459
460 void gb_connection_latency_tag_enable(struct gb_connection *connection)
461 {
462         struct greybus_host_device *hd = connection->hd;
463         int ret;
464
465         if (!hd->driver->latency_tag_enable)
466                 return;
467
468         ret = hd->driver->latency_tag_enable(hd, connection->hd_cport_id);
469         if (ret) {
470                 dev_err(&connection->bundle->dev,
471                         "failed to enable latency tag: %d\n", ret);
472         }
473 }
474 EXPORT_SYMBOL_GPL(gb_connection_latency_tag_enable);
475
476 void gb_connection_latency_tag_disable(struct gb_connection *connection)
477 {
478         struct greybus_host_device *hd = connection->hd;
479         int ret;
480
481         if (!hd->driver->latency_tag_disable)
482                 return;
483
484         ret = hd->driver->latency_tag_disable(hd, connection->hd_cport_id);
485         if (ret) {
486                 dev_err(&connection->bundle->dev,
487                         "failed to disable latency tag: %d\n", ret);
488         }
489 }
490 EXPORT_SYMBOL_GPL(gb_connection_latency_tag_disable);
491
492 void gb_hd_connections_exit(struct greybus_host_device *hd)
493 {
494         struct gb_connection *connection;
495
496         list_for_each_entry(connection, &hd->connections, hd_links)
497                 gb_connection_destroy(connection);
498 }
499
500 int gb_connection_bind_protocol(struct gb_connection *connection)
501 {
502         struct gb_protocol *protocol;
503         int ret;
504
505         /* If we already have a protocol bound here, just return */
506         if (connection->protocol)
507                 return 0;
508
509         protocol = gb_protocol_get(connection->protocol_id,
510                                    connection->major,
511                                    connection->minor);
512         if (!protocol) {
513                 dev_warn(&connection->bundle->dev,
514                                 "protocol 0x%02hhx version %hhu.%hhu not found\n",
515                                 connection->protocol_id,
516                                 connection->major, connection->minor);
517                 return 0;
518         }
519         connection->protocol = protocol;
520
521         /*
522          * If we have a valid device_id for the interface block, then we have an
523          * active device, so bring up the connection at the same time.
524          */
525         if ((!connection->bundle &&
526              protocol->flags & GB_PROTOCOL_NO_BUNDLE) ||
527             connection->bundle->intf->device_id != GB_DEVICE_ID_BAD) {
528                 ret = gb_connection_init(connection);
529                 if (ret) {
530                         gb_protocol_put(protocol);
531                         connection->protocol = NULL;
532                         return ret;
533                 }
534         }
535
536         return 0;
537 }