greybus: hd: make host device a device
[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       BIT(0)
16 #define CPORT_FLAGS_CSD_N       BIT(1)
17 #define CPORT_FLAGS_CSV_N       BIT(2)
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->dev,
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 (%hhu:%hu %hhu:%hu) %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 (%hhu %hhu) %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         if (op->request->payload_size < sizeof(*request)) {
314                 pr_err("%d: short version request (%zu < %zu)\n",
315                                 connection->intf_cport_id,
316                                 op->request->payload_size,
317                                 sizeof(*request));
318                 return -EINVAL;
319         }
320
321         request = op->request->payload;
322
323         if (request->major > GB_SVC_VERSION_MAJOR) {
324                 pr_err("%d: unsupported major version (%hhu > %hhu)\n",
325                        connection->intf_cport_id, request->major,
326                        GB_SVC_VERSION_MAJOR);
327                 return -ENOTSUPP;
328         }
329
330         connection->module_major = request->major;
331         connection->module_minor = request->minor;
332
333         if (!gb_operation_response_alloc(op, sizeof(*response), GFP_KERNEL)) {
334                 pr_err("%d: error allocating response\n",
335                        connection->intf_cport_id);
336                 return -ENOMEM;
337         }
338
339         response = op->response->payload;
340         response->major = connection->module_major;
341         response->minor = connection->module_minor;
342
343         return 0;
344 }
345
346 static int gb_svc_hello(struct gb_operation *op)
347 {
348         struct gb_connection *connection = op->connection;
349         struct gb_host_device *hd = connection->hd;
350         struct gb_svc_hello_request *hello_request;
351         struct gb_interface *intf;
352         u16 endo_id;
353         u8 interface_id;
354         int ret;
355
356         /*
357          * SVC sends information about the endo and interface-id on the hello
358          * request, use that to create an endo.
359          */
360         if (op->request->payload_size < sizeof(*hello_request)) {
361                 pr_err("%d: Illegal size of hello request (%zu < %zu)\n",
362                        connection->intf_cport_id, op->request->payload_size,
363                        sizeof(*hello_request));
364                 return -EINVAL;
365         }
366
367         hello_request = op->request->payload;
368         endo_id = le16_to_cpu(hello_request->endo_id);
369         interface_id = hello_request->interface_id;
370
371         /* Setup Endo */
372         ret = greybus_endo_setup(hd, endo_id, interface_id);
373         if (ret)
374                 return ret;
375
376         /*
377          * Endo and its modules are ready now, fix AP's partially initialized
378          * svc protocol and its connection.
379          */
380         intf = gb_ap_interface_create(hd, connection, interface_id);
381         if (!intf) {
382                 gb_endo_remove(hd->endo);
383                 return ret;
384         }
385
386         return 0;
387 }
388
389 static void svc_intf_remove(struct gb_connection *connection,
390                             struct gb_interface *intf)
391 {
392         struct gb_host_device *hd = connection->hd;
393         struct gb_svc *svc = connection->private;
394         u8 intf_id = intf->interface_id;
395         u8 device_id;
396
397         device_id = intf->device_id;
398         gb_interface_remove(intf);
399
400         /*
401          * Destroy the two-way route between the AP and the interface.
402          */
403         gb_svc_route_destroy(svc, hd->endo->ap_intf_id, intf_id);
404
405         ida_simple_remove(&svc->device_id_map, device_id);
406 }
407
408 /*
409  * 'struct svc_hotplug' should be freed by svc_process_hotplug() before it
410  * returns, irrespective of success or Failure in bringing up the module.
411  */
412 static void svc_process_hotplug(struct work_struct *work)
413 {
414         struct svc_hotplug *svc_hotplug = container_of(work, struct svc_hotplug,
415                                                        work);
416         struct gb_svc_intf_hotplug_request *hotplug = &svc_hotplug->data;
417         struct gb_connection *connection = svc_hotplug->connection;
418         struct gb_svc *svc = connection->private;
419         struct gb_host_device *hd = connection->hd;
420         struct gb_interface *intf;
421         u8 intf_id, device_id;
422         int ret;
423
424         /*
425          * Grab the information we need.
426          */
427         intf_id = hotplug->intf_id;
428
429         intf = gb_interface_find(hd, intf_id);
430         if (intf) {
431                 /*
432                  * We have received a hotplug request for an interface that
433                  * already exists.
434                  *
435                  * This can happen in cases like:
436                  * - bootrom loading the firmware image and booting into that,
437                  *   which only generates a hotplug event. i.e. no hot-unplug
438                  *   event.
439                  * - Or the firmware on the module crashed and sent hotplug
440                  *   request again to the SVC, which got propagated to AP.
441                  *
442                  * Remove the interface and add it again, and let user know
443                  * about this with a print message.
444                  */
445                 pr_info("%d: Removed interface (%hhu) to add it again\n",
446                         connection->intf_cport_id, intf_id);
447                 svc_intf_remove(connection, intf);
448         }
449
450         intf = gb_interface_create(hd, intf_id);
451         if (!intf) {
452                 pr_err("%d: Failed to create interface with id %hhu\n",
453                        connection->intf_cport_id, intf_id);
454                 goto free_svc_hotplug;
455         }
456
457         ret = gb_svc_read_and_clear_module_boot_status(intf);
458         if (ret)
459                 goto destroy_interface;
460
461         intf->unipro_mfg_id = le32_to_cpu(hotplug->data.unipro_mfg_id);
462         intf->unipro_prod_id = le32_to_cpu(hotplug->data.unipro_prod_id);
463         intf->vendor_id = le32_to_cpu(hotplug->data.ara_vend_id);
464         intf->product_id = le32_to_cpu(hotplug->data.ara_prod_id);
465
466         /*
467          * Create a device id for the interface:
468          * - device id 0 (GB_DEVICE_ID_SVC) belongs to the SVC
469          * - device id 1 (GB_DEVICE_ID_AP) belongs to the AP
470          *
471          * XXX Do we need to allocate device ID for SVC or the AP here? And what
472          * XXX about an AP with multiple interface blocks?
473          */
474         device_id = ida_simple_get(&svc->device_id_map,
475                                    GB_DEVICE_ID_MODULES_START, 0, GFP_KERNEL);
476         if (device_id < 0) {
477                 ret = device_id;
478                 pr_err("%d: Failed to allocate device id for interface with id %hhu (%d)\n",
479                        connection->intf_cport_id, intf_id, ret);
480                 goto destroy_interface;
481         }
482
483         ret = gb_svc_intf_device_id(svc, intf_id, device_id);
484         if (ret) {
485                 pr_err("%d: Device id operation failed, interface %hhu device_id %hhu (%d)\n",
486                        connection->intf_cport_id, intf_id, device_id, ret);
487                 goto ida_put;
488         }
489
490         /*
491          * Create a two-way route between the AP and the new interface
492          */
493         ret = gb_svc_route_create(svc, hd->endo->ap_intf_id, GB_DEVICE_ID_AP,
494                                   intf_id, device_id);
495         if (ret) {
496                 pr_err("%d: Route create operation failed, interface %hhu device_id %hhu (%d)\n",
497                        connection->intf_cport_id, intf_id, device_id, ret);
498                 goto svc_id_free;
499         }
500
501         ret = gb_interface_init(intf, device_id);
502         if (ret) {
503                 pr_err("%d: Failed to initialize interface, interface %hhu device_id %hhu (%d)\n",
504                        connection->intf_cport_id, intf_id, device_id, ret);
505                 goto destroy_route;
506         }
507
508         goto free_svc_hotplug;
509
510 destroy_route:
511         gb_svc_route_destroy(svc, hd->endo->ap_intf_id, intf_id);
512 svc_id_free:
513         /*
514          * XXX Should we tell SVC that this id doesn't belong to interface
515          * XXX anymore.
516          */
517 ida_put:
518         ida_simple_remove(&svc->device_id_map, device_id);
519 destroy_interface:
520         gb_interface_remove(intf);
521 free_svc_hotplug:
522         kfree(svc_hotplug);
523 }
524
525 /*
526  * Bringing up a module can be time consuming, as that may require lots of
527  * initialization on the module side. Over that, we may also need to download
528  * the firmware first and flash that on the module.
529  *
530  * In order to make other hotplug events to not wait for all this to finish,
531  * handle most of module hotplug stuff outside of the hotplug callback, with
532  * help of a workqueue.
533  */
534 static int gb_svc_intf_hotplug_recv(struct gb_operation *op)
535 {
536         struct gb_message *request = op->request;
537         struct svc_hotplug *svc_hotplug;
538
539         if (request->payload_size < sizeof(svc_hotplug->data)) {
540                 pr_err("%d: short hotplug request received (%zu < %zu)\n",
541                        op->connection->intf_cport_id, request->payload_size,
542                        sizeof(svc_hotplug->data));
543                 return -EINVAL;
544         }
545
546         svc_hotplug = kmalloc(sizeof(*svc_hotplug), GFP_KERNEL);
547         if (!svc_hotplug)
548                 return -ENOMEM;
549
550         svc_hotplug->connection = op->connection;
551         memcpy(&svc_hotplug->data, op->request->payload, sizeof(svc_hotplug->data));
552
553         INIT_WORK(&svc_hotplug->work, svc_process_hotplug);
554         queue_work(system_unbound_wq, &svc_hotplug->work);
555
556         return 0;
557 }
558
559 static int gb_svc_intf_hot_unplug_recv(struct gb_operation *op)
560 {
561         struct gb_message *request = op->request;
562         struct gb_svc_intf_hot_unplug_request *hot_unplug = request->payload;
563         struct gb_host_device *hd = op->connection->hd;
564         struct gb_interface *intf;
565         u8 intf_id;
566
567         if (request->payload_size < sizeof(*hot_unplug)) {
568                 pr_err("connection %d: short hot unplug request received (%zu < %zu)\n",
569                        op->connection->intf_cport_id, request->payload_size,
570                        sizeof(*hot_unplug));
571                 return -EINVAL;
572         }
573
574         intf_id = hot_unplug->intf_id;
575
576         intf = gb_interface_find(hd, intf_id);
577         if (!intf) {
578                 pr_err("connection %d: Couldn't find interface for id %hhu\n",
579                        op->connection->intf_cport_id, intf_id);
580                 return -EINVAL;
581         }
582
583         svc_intf_remove(op->connection, intf);
584
585         return 0;
586 }
587
588 static int gb_svc_intf_reset_recv(struct gb_operation *op)
589 {
590         struct gb_message *request = op->request;
591         struct gb_svc_intf_reset_request *reset;
592         u8 intf_id;
593
594         if (request->payload_size < sizeof(*reset)) {
595                 pr_err("connection %d: short reset request received (%zu < %zu)\n",
596                        op->connection->intf_cport_id, request->payload_size,
597                        sizeof(*reset));
598                 return -EINVAL;
599         }
600         reset = request->payload;
601
602         intf_id = reset->intf_id;
603
604         /* FIXME Reset the interface here */
605
606         return 0;
607 }
608
609 static int gb_svc_request_recv(u8 type, struct gb_operation *op)
610 {
611         struct gb_connection *connection = op->connection;
612         struct gb_svc *svc = connection->private;
613         int ret = 0;
614
615         /*
616          * SVC requests need to follow a specific order (at least initially) and
617          * below code takes care of enforcing that. The expected order is:
618          * - PROTOCOL_VERSION
619          * - SVC_HELLO
620          * - Any other request, but the earlier two.
621          *
622          * Incoming requests are guaranteed to be serialized and so we don't
623          * need to protect 'state' for any races.
624          */
625         switch (type) {
626         case GB_REQUEST_TYPE_PROTOCOL_VERSION:
627                 if (svc->state != GB_SVC_STATE_RESET)
628                         ret = -EINVAL;
629                 break;
630         case GB_SVC_TYPE_SVC_HELLO:
631                 if (svc->state != GB_SVC_STATE_PROTOCOL_VERSION)
632                         ret = -EINVAL;
633                 break;
634         default:
635                 if (svc->state != GB_SVC_STATE_SVC_HELLO)
636                         ret = -EINVAL;
637                 break;
638         }
639
640         if (ret) {
641                 pr_warn("connection %d: unexpected SVC request 0x%02x received (state %u)\n",
642                         connection->intf_cport_id, type, svc->state);
643                 return ret;
644         }
645
646         switch (type) {
647         case GB_REQUEST_TYPE_PROTOCOL_VERSION:
648                 ret = gb_svc_version_request(op);
649                 if (!ret)
650                         svc->state = GB_SVC_STATE_PROTOCOL_VERSION;
651                 return ret;
652         case GB_SVC_TYPE_SVC_HELLO:
653                 ret = gb_svc_hello(op);
654                 if (!ret)
655                         svc->state = GB_SVC_STATE_SVC_HELLO;
656                 return ret;
657         case GB_SVC_TYPE_INTF_HOTPLUG:
658                 return gb_svc_intf_hotplug_recv(op);
659         case GB_SVC_TYPE_INTF_HOT_UNPLUG:
660                 return gb_svc_intf_hot_unplug_recv(op);
661         case GB_SVC_TYPE_INTF_RESET:
662                 return gb_svc_intf_reset_recv(op);
663         default:
664                 pr_err("connection %d: unsupported request: %hhu\n",
665                        connection->intf_cport_id, type);
666                 return -EINVAL;
667         }
668 }
669
670 static int gb_svc_connection_init(struct gb_connection *connection)
671 {
672         struct gb_svc *svc;
673
674         svc = kzalloc(sizeof(*svc), GFP_KERNEL);
675         if (!svc)
676                 return -ENOMEM;
677
678         connection->hd->svc = svc;
679         svc->state = GB_SVC_STATE_RESET;
680         svc->connection = connection;
681         connection->private = svc;
682
683         WARN_ON(connection->hd->initial_svc_connection);
684         connection->hd->initial_svc_connection = connection;
685
686         ida_init(&svc->device_id_map);
687
688         return 0;
689 }
690
691 static void gb_svc_connection_exit(struct gb_connection *connection)
692 {
693         struct gb_svc *svc = connection->private;
694
695         ida_destroy(&svc->device_id_map);
696         connection->hd->svc = NULL;
697         connection->private = NULL;
698         kfree(svc);
699 }
700
701 static struct gb_protocol svc_protocol = {
702         .name                   = "svc",
703         .id                     = GREYBUS_PROTOCOL_SVC,
704         .major                  = GB_SVC_VERSION_MAJOR,
705         .minor                  = GB_SVC_VERSION_MINOR,
706         .connection_init        = gb_svc_connection_init,
707         .connection_exit        = gb_svc_connection_exit,
708         .request_recv           = gb_svc_request_recv,
709         .flags                  = GB_PROTOCOL_SKIP_CONTROL_CONNECTED |
710                                   GB_PROTOCOL_SKIP_CONTROL_DISCONNECTED |
711                                   GB_PROTOCOL_NO_BUNDLE |
712                                   GB_PROTOCOL_SKIP_VERSION |
713                                   GB_PROTOCOL_SKIP_SVC_CONNECTION,
714 };
715 gb_builtin_protocol_driver(svc_protocol);