greybus: hd: rename host-device structure
[cascardo/linux.git] / drivers / staging / greybus / svc.c
1 /*
2  * SVC Greybus driver.
3  *
4  * Copyright 2015 Google Inc.
5  * Copyright 2015 Linaro Ltd.
6  *
7  * Released under the GPLv2 only.
8  */
9
10 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
11 #include <linux/workqueue.h>
12
13 #include "greybus.h"
14
15 #define CPORT_FLAGS_E2EFC       (1)
16 #define CPORT_FLAGS_CSD_N       (2)
17 #define CPORT_FLAGS_CSV_N       (4)
18
19 enum gb_svc_state {
20         GB_SVC_STATE_RESET,
21         GB_SVC_STATE_PROTOCOL_VERSION,
22         GB_SVC_STATE_SVC_HELLO,
23 };
24
25 struct gb_svc {
26         struct gb_connection    *connection;
27         enum gb_svc_state       state;
28         struct ida              device_id_map;
29 };
30
31 struct svc_hotplug {
32         struct work_struct work;
33         struct gb_connection *connection;
34         struct gb_svc_intf_hotplug_request data;
35 };
36
37
38 /*
39  * AP's SVC cport is required early to get messages from the SVC. This happens
40  * even before the Endo is created and hence any modules or interfaces.
41  *
42  * This is a temporary connection, used only at initial bootup.
43  */
44 struct gb_connection *
45 gb_ap_svc_connection_create(struct gb_host_device *hd)
46 {
47         struct gb_connection *connection;
48
49         connection = gb_connection_create_range(hd, NULL, hd->parent,
50                                                 GB_SVC_CPORT_ID,
51                                                 GREYBUS_PROTOCOL_SVC,
52                                                 GB_SVC_CPORT_ID,
53                                                 GB_SVC_CPORT_ID + 1);
54
55         return connection;
56 }
57
58 /*
59  * We know endo-type and AP's interface id now, lets create a proper svc
60  * connection (and its interface/bundle) now and get rid of the initial
61  * 'partially' initialized one svc connection.
62  */
63 static struct gb_interface *
64 gb_ap_interface_create(struct gb_host_device *hd,
65                        struct gb_connection *connection, u8 interface_id)
66 {
67         struct gb_interface *intf;
68         struct device *dev = &hd->endo->dev;
69
70         intf = gb_interface_create(hd, interface_id);
71         if (!intf) {
72                 dev_err(dev, "%s: Failed to create interface with id %hhu\n",
73                         __func__, interface_id);
74                 return NULL;
75         }
76
77         intf->device_id = GB_DEVICE_ID_AP;
78         svc_update_connection(intf, connection);
79
80         /* Its no longer a partially initialized connection */
81         hd->initial_svc_connection = NULL;
82
83         return intf;
84 }
85
86 static int gb_svc_intf_device_id(struct gb_svc *svc, u8 intf_id, u8 device_id)
87 {
88         struct gb_svc_intf_device_id_request request;
89
90         request.intf_id = intf_id;
91         request.device_id = device_id;
92
93         return gb_operation_sync(svc->connection, GB_SVC_TYPE_INTF_DEVICE_ID,
94                                  &request, sizeof(request), NULL, 0);
95 }
96
97 int gb_svc_intf_reset(struct gb_svc *svc, u8 intf_id)
98 {
99         struct gb_svc_intf_reset_request request;
100
101         request.intf_id = intf_id;
102
103         return gb_operation_sync(svc->connection, GB_SVC_TYPE_INTF_RESET,
104                                  &request, sizeof(request), NULL, 0);
105 }
106 EXPORT_SYMBOL_GPL(gb_svc_intf_reset);
107
108 int gb_svc_dme_peer_get(struct gb_svc *svc, u8 intf_id, u16 attr, u16 selector,
109                         u32 *value)
110 {
111         struct gb_svc_dme_peer_get_request request;
112         struct gb_svc_dme_peer_get_response response;
113         u16 result;
114         int ret;
115
116         request.intf_id = intf_id;
117         request.attr = cpu_to_le16(attr);
118         request.selector = cpu_to_le16(selector);
119
120         ret = gb_operation_sync(svc->connection, GB_SVC_TYPE_DME_PEER_GET,
121                                 &request, sizeof(request),
122                                 &response, sizeof(response));
123         if (ret) {
124                 pr_err("failed to get DME attribute (%hhu %hx %hu) %d\n",
125                        intf_id, attr, selector, ret);
126                 return ret;
127         }
128
129         result = le16_to_cpu(response.result_code);
130         if (result) {
131                 pr_err("Unipro error %hu while getting DME attribute (%hhu %hx %hu)\n",
132                        result, intf_id, attr, selector);
133                 return -EINVAL;
134         }
135
136         if (value)
137                 *value = le32_to_cpu(response.attr_value);
138
139         return 0;
140 }
141 EXPORT_SYMBOL_GPL(gb_svc_dme_peer_get);
142
143 int gb_svc_dme_peer_set(struct gb_svc *svc, u8 intf_id, u16 attr, u16 selector,
144                         u32 value)
145 {
146         struct gb_svc_dme_peer_set_request request;
147         struct gb_svc_dme_peer_set_response response;
148         u16 result;
149         int ret;
150
151         request.intf_id = intf_id;
152         request.attr = cpu_to_le16(attr);
153         request.selector = cpu_to_le16(selector);
154         request.value = cpu_to_le32(value);
155
156         ret = gb_operation_sync(svc->connection, GB_SVC_TYPE_DME_PEER_SET,
157                                 &request, sizeof(request),
158                                 &response, sizeof(response));
159         if (ret) {
160                 pr_err("failed to set DME attribute (%hhu %hx %hu %u) %d\n",
161                        intf_id, attr, selector, value, ret);
162                 return ret;
163         }
164
165         result = le16_to_cpu(response.result_code);
166         if (result) {
167                 pr_err("Unipro error %hu while setting DME attribute (%hhu %hx %hu %u)\n",
168                        result, intf_id, attr, selector, value);
169                 return -EINVAL;
170         }
171
172         return 0;
173 }
174 EXPORT_SYMBOL_GPL(gb_svc_dme_peer_set);
175
176 /*
177  * T_TstSrcIncrement is written by the module on ES2 as a stand-in for boot
178  * status attribute. AP needs to read and clear it, after reading a non-zero
179  * value from it.
180  *
181  * FIXME: This is module-hardware dependent and needs to be extended for every
182  * type of module we want to support.
183  */
184 static int gb_svc_read_and_clear_module_boot_status(struct gb_interface *intf)
185 {
186         struct gb_host_device *hd = intf->hd;
187         int ret;
188         u32 value;
189
190         /* Read and clear boot status in T_TstSrcIncrement */
191         ret = gb_svc_dme_peer_get(hd->svc, intf->interface_id,
192                                   DME_ATTR_T_TST_SRC_INCREMENT,
193                                   DME_ATTR_SELECTOR_INDEX, &value);
194
195         if (ret)
196                 return ret;
197
198         /*
199          * A nonzero boot status indicates the module has finished
200          * booting. Clear it.
201          */
202         if (!value) {
203                 dev_err(&intf->dev, "Module not ready yet\n");
204                 return -ENODEV;
205         }
206
207         /*
208          * Check if the module needs to boot from unipro.
209          * For ES2: We need to check lowest 8 bits of 'value'.
210          * For ES3: We need to check highest 8 bits out of 32 of 'value'.
211          *
212          * FIXME: Add code to find if we are on ES2 or ES3 to have separate
213          * checks.
214          */
215         if (value == DME_TSI_UNIPRO_BOOT_STARTED ||
216             value == DME_TSI_FALLBACK_UNIPRO_BOOT_STARTED)
217                 intf->boot_over_unipro = true;
218
219         return gb_svc_dme_peer_set(hd->svc, intf->interface_id,
220                                    DME_ATTR_T_TST_SRC_INCREMENT,
221                                    DME_ATTR_SELECTOR_INDEX, 0);
222 }
223
224 int gb_svc_connection_create(struct gb_svc *svc,
225                                 u8 intf1_id, u16 cport1_id,
226                                 u8 intf2_id, u16 cport2_id,
227                                 bool boot_over_unipro)
228 {
229         struct gb_svc_conn_create_request request;
230
231         request.intf1_id = intf1_id;
232         request.cport1_id = cpu_to_le16(cport1_id);
233         request.intf2_id = intf2_id;
234         request.cport2_id = cpu_to_le16(cport2_id);
235         /*
236          * XXX: fix connections paramaters to TC0 and all CPort flags
237          * for now.
238          */
239         request.tc = 0;
240
241         /*
242          * We need to skip setting E2EFC and other flags to the connection
243          * create request, for all cports, on an interface that need to boot
244          * over unipro, i.e. interfaces required to download firmware.
245          */
246         if (boot_over_unipro)
247                 request.flags = CPORT_FLAGS_CSV_N | CPORT_FLAGS_CSD_N;
248         else
249                 request.flags = CPORT_FLAGS_CSV_N | CPORT_FLAGS_E2EFC;
250
251         return gb_operation_sync(svc->connection, GB_SVC_TYPE_CONN_CREATE,
252                                  &request, sizeof(request), NULL, 0);
253 }
254 EXPORT_SYMBOL_GPL(gb_svc_connection_create);
255
256 void gb_svc_connection_destroy(struct gb_svc *svc, u8 intf1_id, u16 cport1_id,
257                                u8 intf2_id, u16 cport2_id)
258 {
259         struct gb_svc_conn_destroy_request request;
260         struct gb_connection *connection = svc->connection;
261         int ret;
262
263         request.intf1_id = intf1_id;
264         request.cport1_id = cpu_to_le16(cport1_id);
265         request.intf2_id = intf2_id;
266         request.cport2_id = cpu_to_le16(cport2_id);
267
268         ret = gb_operation_sync(connection, GB_SVC_TYPE_CONN_DESTROY,
269                                 &request, sizeof(request), NULL, 0);
270         if (ret)
271                 pr_err("failed to destroy connection (%hhx:%hx %hhx:%hx) %d\n",
272                        intf1_id, cport1_id, intf2_id, cport2_id, ret);
273 }
274 EXPORT_SYMBOL_GPL(gb_svc_connection_destroy);
275
276 /* Creates bi-directional routes between the devices */
277 static int gb_svc_route_create(struct gb_svc *svc, u8 intf1_id, u8 dev1_id,
278                                u8 intf2_id, u8 dev2_id)
279 {
280         struct gb_svc_route_create_request request;
281
282         request.intf1_id = intf1_id;
283         request.dev1_id = dev1_id;
284         request.intf2_id = intf2_id;
285         request.dev2_id = dev2_id;
286
287         return gb_operation_sync(svc->connection, GB_SVC_TYPE_ROUTE_CREATE,
288                                  &request, sizeof(request), NULL, 0);
289 }
290
291 /* Destroys bi-directional routes between the devices */
292 static void gb_svc_route_destroy(struct gb_svc *svc, u8 intf1_id, u8 intf2_id)
293 {
294         struct gb_svc_route_destroy_request request;
295         int ret;
296
297         request.intf1_id = intf1_id;
298         request.intf2_id = intf2_id;
299
300         ret = gb_operation_sync(svc->connection, GB_SVC_TYPE_ROUTE_DESTROY,
301                                 &request, sizeof(request), NULL, 0);
302         if (ret)
303                 pr_err("failed to destroy route (%hhx %hhx) %d\n",
304                         intf1_id, intf2_id, ret);
305 }
306
307 static int gb_svc_version_request(struct gb_operation *op)
308 {
309         struct gb_connection *connection = op->connection;
310         struct gb_protocol_version_request *request;
311         struct gb_protocol_version_response *response;
312
313         request = op->request->payload;
314
315         if (request->major > GB_SVC_VERSION_MAJOR) {
316                 pr_err("%d: unsupported major version (%hhu > %hhu)\n",
317                        connection->intf_cport_id, request->major,
318                        GB_SVC_VERSION_MAJOR);
319                 return -ENOTSUPP;
320         }
321
322         connection->module_major = request->major;
323         connection->module_minor = request->minor;
324
325         if (!gb_operation_response_alloc(op, sizeof(*response), GFP_KERNEL)) {
326                 pr_err("%d: error allocating response\n",
327                        connection->intf_cport_id);
328                 return -ENOMEM;
329         }
330
331         response = op->response->payload;
332         response->major = connection->module_major;
333         response->minor = connection->module_minor;
334
335         return 0;
336 }
337
338 static int gb_svc_hello(struct gb_operation *op)
339 {
340         struct gb_connection *connection = op->connection;
341         struct gb_host_device *hd = connection->hd;
342         struct gb_svc_hello_request *hello_request;
343         struct gb_interface *intf;
344         u16 endo_id;
345         u8 interface_id;
346         int ret;
347
348         /*
349          * SVC sends information about the endo and interface-id on the hello
350          * request, use that to create an endo.
351          */
352         if (op->request->payload_size < sizeof(*hello_request)) {
353                 pr_err("%d: Illegal size of hello request (%zu < %zu)\n",
354                        connection->intf_cport_id, op->request->payload_size,
355                        sizeof(*hello_request));
356                 return -EINVAL;
357         }
358
359         hello_request = op->request->payload;
360         endo_id = le16_to_cpu(hello_request->endo_id);
361         interface_id = hello_request->interface_id;
362
363         /* Setup Endo */
364         ret = greybus_endo_setup(hd, endo_id, interface_id);
365         if (ret)
366                 return ret;
367
368         /*
369          * Endo and its modules are ready now, fix AP's partially initialized
370          * svc protocol and its connection.
371          */
372         intf = gb_ap_interface_create(hd, connection, interface_id);
373         if (!intf) {
374                 gb_endo_remove(hd->endo);
375                 return ret;
376         }
377
378         return 0;
379 }
380
381 static void svc_intf_remove(struct gb_connection *connection,
382                             struct gb_interface *intf)
383 {
384         struct gb_host_device *hd = connection->hd;
385         struct gb_svc *svc = connection->private;
386         u8 intf_id = intf->interface_id;
387         u8 device_id;
388
389         device_id = intf->device_id;
390         gb_interface_remove(intf);
391
392         /*
393          * Destroy the two-way route between the AP and the interface.
394          */
395         gb_svc_route_destroy(svc, hd->endo->ap_intf_id, intf_id);
396
397         ida_simple_remove(&svc->device_id_map, device_id);
398 }
399
400 /*
401  * 'struct svc_hotplug' should be freed by svc_process_hotplug() before it
402  * returns, irrespective of success or Failure in bringing up the module.
403  */
404 static void svc_process_hotplug(struct work_struct *work)
405 {
406         struct svc_hotplug *svc_hotplug = container_of(work, struct svc_hotplug,
407                                                        work);
408         struct gb_svc_intf_hotplug_request *hotplug = &svc_hotplug->data;
409         struct gb_connection *connection = svc_hotplug->connection;
410         struct gb_svc *svc = connection->private;
411         struct gb_host_device *hd = connection->hd;
412         struct gb_interface *intf;
413         u8 intf_id, device_id;
414         int ret;
415
416         /*
417          * Grab the information we need.
418          */
419         intf_id = hotplug->intf_id;
420
421         intf = gb_interface_find(hd, intf_id);
422         if (intf) {
423                 /*
424                  * We have received a hotplug request for an interface that
425                  * already exists.
426                  *
427                  * This can happen in cases like:
428                  * - bootrom loading the firmware image and booting into that,
429                  *   which only generates a hotplug event. i.e. no hot-unplug
430                  *   event.
431                  * - Or the firmware on the module crashed and sent hotplug
432                  *   request again to the SVC, which got propagated to AP.
433                  *
434                  * Remove the interface and add it again, and let user know
435                  * about this with a print message.
436                  */
437                 pr_info("%d: Removed interface (%hhu) to add it again\n",
438                         connection->intf_cport_id, intf_id);
439                 svc_intf_remove(connection, intf);
440         }
441
442         intf = gb_interface_create(hd, intf_id);
443         if (!intf) {
444                 pr_err("%d: Failed to create interface with id %hhu\n",
445                        connection->intf_cport_id, intf_id);
446                 goto free_svc_hotplug;
447         }
448
449         ret = gb_svc_read_and_clear_module_boot_status(intf);
450         if (ret)
451                 goto destroy_interface;
452
453         intf->unipro_mfg_id = le32_to_cpu(hotplug->data.unipro_mfg_id);
454         intf->unipro_prod_id = le32_to_cpu(hotplug->data.unipro_prod_id);
455         intf->ara_vend_id = le32_to_cpu(hotplug->data.ara_vend_id);
456         intf->ara_prod_id = le32_to_cpu(hotplug->data.ara_prod_id);
457
458         /*
459          * Create a device id for the interface:
460          * - device id 0 (GB_DEVICE_ID_SVC) belongs to the SVC
461          * - device id 1 (GB_DEVICE_ID_AP) belongs to the AP
462          *
463          * XXX Do we need to allocate device ID for SVC or the AP here? And what
464          * XXX about an AP with multiple interface blocks?
465          */
466         device_id = ida_simple_get(&svc->device_id_map,
467                                    GB_DEVICE_ID_MODULES_START, 0, GFP_KERNEL);
468         if (device_id < 0) {
469                 ret = device_id;
470                 pr_err("%d: Failed to allocate device id for interface with id %hhu (%d)\n",
471                        connection->intf_cport_id, intf_id, ret);
472                 goto destroy_interface;
473         }
474
475         ret = gb_svc_intf_device_id(svc, intf_id, device_id);
476         if (ret) {
477                 pr_err("%d: Device id operation failed, interface %hhu device_id %hhu (%d)\n",
478                        connection->intf_cport_id, intf_id, device_id, ret);
479                 goto ida_put;
480         }
481
482         /*
483          * Create a two-way route between the AP and the new interface
484          */
485         ret = gb_svc_route_create(svc, hd->endo->ap_intf_id, GB_DEVICE_ID_AP,
486                                   intf_id, device_id);
487         if (ret) {
488                 pr_err("%d: Route create operation failed, interface %hhu device_id %hhu (%d)\n",
489                        connection->intf_cport_id, intf_id, device_id, ret);
490                 goto svc_id_free;
491         }
492
493         ret = gb_interface_init(intf, device_id);
494         if (ret) {
495                 pr_err("%d: Failed to initialize interface, interface %hhu device_id %hhu (%d)\n",
496                        connection->intf_cport_id, intf_id, device_id, ret);
497                 goto destroy_route;
498         }
499
500         goto free_svc_hotplug;
501
502 destroy_route:
503         gb_svc_route_destroy(svc, hd->endo->ap_intf_id, intf_id);
504 svc_id_free:
505         /*
506          * XXX Should we tell SVC that this id doesn't belong to interface
507          * XXX anymore.
508          */
509 ida_put:
510         ida_simple_remove(&svc->device_id_map, device_id);
511 destroy_interface:
512         gb_interface_remove(intf);
513 free_svc_hotplug:
514         kfree(svc_hotplug);
515 }
516
517 /*
518  * Bringing up a module can be time consuming, as that may require lots of
519  * initialization on the module side. Over that, we may also need to download
520  * the firmware first and flash that on the module.
521  *
522  * In order to make other hotplug events to not wait for all this to finish,
523  * handle most of module hotplug stuff outside of the hotplug callback, with
524  * help of a workqueue.
525  */
526 static int gb_svc_intf_hotplug_recv(struct gb_operation *op)
527 {
528         struct gb_message *request = op->request;
529         struct svc_hotplug *svc_hotplug;
530
531         if (request->payload_size < sizeof(svc_hotplug->data)) {
532                 pr_err("%d: short hotplug request received (%zu < %zu)\n",
533                        op->connection->intf_cport_id, request->payload_size,
534                        sizeof(svc_hotplug->data));
535                 return -EINVAL;
536         }
537
538         svc_hotplug = kmalloc(sizeof(*svc_hotplug), GFP_KERNEL);
539         if (!svc_hotplug)
540                 return -ENOMEM;
541
542         svc_hotplug->connection = op->connection;
543         memcpy(&svc_hotplug->data, op->request->payload, sizeof(svc_hotplug->data));
544
545         INIT_WORK(&svc_hotplug->work, svc_process_hotplug);
546         queue_work(system_unbound_wq, &svc_hotplug->work);
547
548         return 0;
549 }
550
551 static int gb_svc_intf_hot_unplug_recv(struct gb_operation *op)
552 {
553         struct gb_message *request = op->request;
554         struct gb_svc_intf_hot_unplug_request *hot_unplug = request->payload;
555         struct gb_host_device *hd = op->connection->hd;
556         struct gb_interface *intf;
557         u8 intf_id;
558
559         if (request->payload_size < sizeof(*hot_unplug)) {
560                 pr_err("connection %d: short hot unplug request received (%zu < %zu)\n",
561                        op->connection->intf_cport_id, request->payload_size,
562                        sizeof(*hot_unplug));
563                 return -EINVAL;
564         }
565
566         intf_id = hot_unplug->intf_id;
567
568         intf = gb_interface_find(hd, intf_id);
569         if (!intf) {
570                 pr_err("connection %d: Couldn't find interface for id %hhu\n",
571                        op->connection->intf_cport_id, intf_id);
572                 return -EINVAL;
573         }
574
575         svc_intf_remove(op->connection, intf);
576
577         return 0;
578 }
579
580 static int gb_svc_intf_reset_recv(struct gb_operation *op)
581 {
582         struct gb_message *request = op->request;
583         struct gb_svc_intf_reset_request *reset;
584         u8 intf_id;
585
586         if (request->payload_size < sizeof(*reset)) {
587                 pr_err("connection %d: short reset request received (%zu < %zu)\n",
588                        op->connection->intf_cport_id, request->payload_size,
589                        sizeof(*reset));
590                 return -EINVAL;
591         }
592         reset = request->payload;
593
594         intf_id = reset->intf_id;
595
596         /* FIXME Reset the interface here */
597
598         return 0;
599 }
600
601 static int gb_svc_request_recv(u8 type, struct gb_operation *op)
602 {
603         struct gb_connection *connection = op->connection;
604         struct gb_svc *svc = connection->private;
605         int ret = 0;
606
607         /*
608          * SVC requests need to follow a specific order (at least initially) and
609          * below code takes care of enforcing that. The expected order is:
610          * - PROTOCOL_VERSION
611          * - SVC_HELLO
612          * - Any other request, but the earlier two.
613          *
614          * Incoming requests are guaranteed to be serialized and so we don't
615          * need to protect 'state' for any races.
616          */
617         switch (type) {
618         case GB_REQUEST_TYPE_PROTOCOL_VERSION:
619                 if (svc->state != GB_SVC_STATE_RESET)
620                         ret = -EINVAL;
621                 break;
622         case GB_SVC_TYPE_SVC_HELLO:
623                 if (svc->state != GB_SVC_STATE_PROTOCOL_VERSION)
624                         ret = -EINVAL;
625                 break;
626         default:
627                 if (svc->state != GB_SVC_STATE_SVC_HELLO)
628                         ret = -EINVAL;
629                 break;
630         }
631
632         if (ret) {
633                 pr_warn("connection %d: unexpected SVC request 0x%02x received (state %u)\n",
634                         connection->intf_cport_id, type, svc->state);
635                 return ret;
636         }
637
638         switch (type) {
639         case GB_REQUEST_TYPE_PROTOCOL_VERSION:
640                 ret = gb_svc_version_request(op);
641                 if (!ret)
642                         svc->state = GB_SVC_STATE_PROTOCOL_VERSION;
643                 return ret;
644         case GB_SVC_TYPE_SVC_HELLO:
645                 ret = gb_svc_hello(op);
646                 if (!ret)
647                         svc->state = GB_SVC_STATE_SVC_HELLO;
648                 return ret;
649         case GB_SVC_TYPE_INTF_HOTPLUG:
650                 return gb_svc_intf_hotplug_recv(op);
651         case GB_SVC_TYPE_INTF_HOT_UNPLUG:
652                 return gb_svc_intf_hot_unplug_recv(op);
653         case GB_SVC_TYPE_INTF_RESET:
654                 return gb_svc_intf_reset_recv(op);
655         default:
656                 pr_err("connection %d: unsupported request: %hhu\n",
657                        connection->intf_cport_id, type);
658                 return -EINVAL;
659         }
660 }
661
662 static int gb_svc_connection_init(struct gb_connection *connection)
663 {
664         struct gb_svc *svc;
665
666         svc = kzalloc(sizeof(*svc), GFP_KERNEL);
667         if (!svc)
668                 return -ENOMEM;
669
670         connection->hd->svc = svc;
671         svc->state = GB_SVC_STATE_RESET;
672         svc->connection = connection;
673         connection->private = svc;
674
675         WARN_ON(connection->hd->initial_svc_connection);
676         connection->hd->initial_svc_connection = connection;
677
678         ida_init(&svc->device_id_map);
679
680         return 0;
681 }
682
683 static void gb_svc_connection_exit(struct gb_connection *connection)
684 {
685         struct gb_svc *svc = connection->private;
686
687         ida_destroy(&svc->device_id_map);
688         connection->hd->svc = NULL;
689         connection->private = NULL;
690         kfree(svc);
691 }
692
693 static struct gb_protocol svc_protocol = {
694         .name                   = "svc",
695         .id                     = GREYBUS_PROTOCOL_SVC,
696         .major                  = GB_SVC_VERSION_MAJOR,
697         .minor                  = GB_SVC_VERSION_MINOR,
698         .connection_init        = gb_svc_connection_init,
699         .connection_exit        = gb_svc_connection_exit,
700         .request_recv           = gb_svc_request_recv,
701         .flags                  = GB_PROTOCOL_SKIP_CONTROL_CONNECTED |
702                                   GB_PROTOCOL_SKIP_CONTROL_DISCONNECTED |
703                                   GB_PROTOCOL_NO_BUNDLE |
704                                   GB_PROTOCOL_SKIP_VERSION |
705                                   GB_PROTOCOL_SKIP_SVC_CONNECTION,
706 };
707 gb_builtin_protocol_driver(svc_protocol);