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