blob: e56cb187786f42c636603919d4e5bd5856783413 [file] [log] [blame]
Alex Elder30c6d9d2015-05-22 13:02:08 -05001/*
2 * SVC Greybus driver.
3 *
4 * Copyright 2015 Google Inc.
5 * Copyright 2015 Linaro Ltd.
6 *
7 * Released under the GPLv2 only.
8 */
9
Viresh Kumar067906f2015-08-06 12:44:55 +053010#include <linux/workqueue.h>
Alex Elder30c6d9d2015-05-22 13:02:08 -050011
Viresh Kumarf66427a2015-09-02 21:27:13 +053012#include "greybus.h"
13
Perry Hung0b226492015-07-24 19:02:34 -040014#define CPORT_FLAGS_E2EFC (1)
15#define CPORT_FLAGS_CSD_N (2)
16#define CPORT_FLAGS_CSV_N (4)
17
Viresh Kumar3ccb1602015-09-03 15:42:22 +053018enum gb_svc_state {
19 GB_SVC_STATE_RESET,
20 GB_SVC_STATE_PROTOCOL_VERSION,
21 GB_SVC_STATE_SVC_HELLO,
22};
23
Viresh Kumarb45864d2015-07-24 15:32:21 +053024struct gb_svc {
25 struct gb_connection *connection;
Viresh Kumar3ccb1602015-09-03 15:42:22 +053026 enum gb_svc_state state;
Viresh Kumarb45864d2015-07-24 15:32:21 +053027};
28
Viresh Kumar067906f2015-08-06 12:44:55 +053029struct svc_hotplug {
30 struct work_struct work;
31 struct gb_connection *connection;
32 struct gb_svc_intf_hotplug_request data;
33};
34
Viresh Kumaread35462015-07-21 17:44:19 +053035static struct ida greybus_svc_device_id_map;
36
Viresh Kumard3d44842015-07-21 17:44:18 +053037/*
38 * AP's SVC cport is required early to get messages from the SVC. This happens
39 * even before the Endo is created and hence any modules or interfaces.
40 *
41 * This is a temporary connection, used only at initial bootup.
42 */
43struct gb_connection *
44gb_ap_svc_connection_create(struct greybus_host_device *hd)
45{
46 struct gb_connection *connection;
47
48 connection = gb_connection_create_range(hd, NULL, hd->parent,
49 GB_SVC_CPORT_ID,
50 GREYBUS_PROTOCOL_SVC,
51 GB_SVC_CPORT_ID,
52 GB_SVC_CPORT_ID + 1);
53
54 return connection;
55}
Viresh Kumard3d44842015-07-21 17:44:18 +053056
57/*
58 * We know endo-type and AP's interface id now, lets create a proper svc
59 * connection (and its interface/bundle) now and get rid of the initial
60 * 'partially' initialized one svc connection.
61 */
62static struct gb_interface *
63gb_ap_interface_create(struct greybus_host_device *hd,
64 struct gb_connection *connection, u8 interface_id)
65{
66 struct gb_interface *intf;
67 struct device *dev = &hd->endo->dev;
Viresh Kumard3d44842015-07-21 17:44:18 +053068
69 intf = gb_interface_create(hd, interface_id);
70 if (!intf) {
71 dev_err(dev, "%s: Failed to create interface with id %hhu\n",
72 __func__, interface_id);
73 return NULL;
74 }
75
76 intf->device_id = GB_DEVICE_ID_AP;
Viresh Kumar67c93ae2015-07-24 15:32:19 +053077 svc_update_connection(intf, connection);
Viresh Kumard3d44842015-07-21 17:44:18 +053078
Viresh Kumardcd05002015-07-24 15:32:20 +053079 /* Its no longer a partially initialized connection */
80 hd->initial_svc_connection = NULL;
81
Viresh Kumard3d44842015-07-21 17:44:18 +053082 return intf;
83}
84
Alex Elder30c6d9d2015-05-22 13:02:08 -050085static int intf_device_id_operation(struct gb_svc *svc,
86 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
97static int intf_reset_operation(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
107static int connection_create_operation(struct gb_svc *svc,
108 u8 intf1_id, u16 cport1_id,
109 u8 intf2_id, u16 cport2_id)
110{
111 struct gb_svc_conn_create_request request;
112
113 request.intf1_id = intf1_id;
114 request.cport1_id = cport1_id;
115 request.intf2_id = intf2_id;
116 request.cport2_id = cport2_id;
Perry Hung0b226492015-07-24 19:02:34 -0400117 /*
118 * XXX: fix connections paramaters to TC0 and all CPort flags
119 * for now.
120 */
121 request.tc = 0;
122 request.flags = CPORT_FLAGS_CSV_N | CPORT_FLAGS_E2EFC;
Alex Elder30c6d9d2015-05-22 13:02:08 -0500123
124 return gb_operation_sync(svc->connection, GB_SVC_TYPE_CONN_CREATE,
125 &request, sizeof(request), NULL, 0);
126}
127
Viresh Kumard9fcfff2015-08-31 17:21:05 +0530128static void connection_destroy_operation(struct gb_svc *svc,
Alex Elder30c6d9d2015-05-22 13:02:08 -0500129 u8 intf1_id, u16 cport1_id,
130 u8 intf2_id, u16 cport2_id)
131{
132 struct gb_svc_conn_destroy_request request;
Viresh Kumard9fcfff2015-08-31 17:21:05 +0530133 struct gb_connection *connection = svc->connection;
134 int ret;
Alex Elder30c6d9d2015-05-22 13:02:08 -0500135
136 request.intf1_id = intf1_id;
137 request.cport1_id = cport1_id;
138 request.intf2_id = intf2_id;
139 request.cport2_id = cport2_id;
140
Viresh Kumard9fcfff2015-08-31 17:21:05 +0530141 ret = gb_operation_sync(connection, GB_SVC_TYPE_CONN_DESTROY,
142 &request, sizeof(request), NULL, 0);
143 if (ret) {
144 dev_err(&connection->dev,
145 "failed to destroy connection (%hhx:%hx %hhx:%hx) %d\n",
146 intf1_id, cport1_id, intf2_id, cport2_id, ret);
147 }
Alex Elder30c6d9d2015-05-22 13:02:08 -0500148}
149
Perry Hunge08aaa42015-07-24 19:02:31 -0400150static int route_create_operation(struct gb_svc *svc, u8 intf1_id, u8 dev1_id,
151 u8 intf2_id, u8 dev2_id)
152{
153 struct gb_svc_route_create_request request;
154
155 request.intf1_id = intf1_id;
156 request.dev1_id = dev1_id;
157 request.intf2_id = intf2_id;
158 request.dev2_id = dev2_id;
159
160 return gb_operation_sync(svc->connection, GB_SVC_TYPE_ROUTE_CREATE,
161 &request, sizeof(request), NULL, 0);
162}
163
Alex Elder30c6d9d2015-05-22 13:02:08 -0500164int gb_svc_intf_device_id(struct gb_svc *svc, u8 intf_id, u8 device_id)
165{
166 return intf_device_id_operation(svc, intf_id, device_id);
167}
168EXPORT_SYMBOL_GPL(gb_svc_intf_device_id);
169
170int gb_svc_intf_reset(struct gb_svc *svc, u8 intf_id)
171{
172 return intf_reset_operation(svc, intf_id);
173}
174EXPORT_SYMBOL_GPL(gb_svc_intf_reset);
175
176int gb_svc_connection_create(struct gb_svc *svc,
177 u8 intf1_id, u16 cport1_id,
178 u8 intf2_id, u16 cport2_id)
179{
180 return connection_create_operation(svc, intf1_id, cport1_id,
181 intf2_id, cport2_id);
182}
183EXPORT_SYMBOL_GPL(gb_svc_connection_create);
184
Viresh Kumard9fcfff2015-08-31 17:21:05 +0530185void gb_svc_connection_destroy(struct gb_svc *svc, u8 intf1_id, u16 cport1_id,
186 u8 intf2_id, u16 cport2_id)
Alex Elder30c6d9d2015-05-22 13:02:08 -0500187{
Viresh Kumard9fcfff2015-08-31 17:21:05 +0530188 connection_destroy_operation(svc, intf1_id, cport1_id, intf2_id,
189 cport2_id);
Alex Elder30c6d9d2015-05-22 13:02:08 -0500190}
191EXPORT_SYMBOL_GPL(gb_svc_connection_destroy);
192
Perry Hunge08aaa42015-07-24 19:02:31 -0400193int gb_svc_route_create(struct gb_svc *svc, u8 intf1_id, u8 dev1_id,
Viresh Kumar03cb4fa2015-07-29 11:44:08 +0530194 u8 intf2_id, u8 dev2_id)
195{
Perry Hunge08aaa42015-07-24 19:02:31 -0400196 return route_create_operation(svc, intf1_id, dev1_id,
197 intf2_id, dev2_id);
198}
199EXPORT_SYMBOL_GPL(gb_svc_route_create);
200
Viresh Kumaread35462015-07-21 17:44:19 +0530201static int gb_svc_version_request(struct gb_operation *op)
202{
203 struct gb_connection *connection = op->connection;
204 struct gb_protocol_version_response *version;
205 struct device *dev = &connection->dev;
206
207 version = op->request->payload;
208
209 if (version->major > GB_SVC_VERSION_MAJOR) {
210 dev_err(&connection->dev,
211 "unsupported major version (%hhu > %hhu)\n",
212 version->major, GB_SVC_VERSION_MAJOR);
213 return -ENOTSUPP;
214 }
215
Viresh Kumar3ea959e32015-08-11 07:36:14 +0530216 connection->module_major = version->major;
217 connection->module_minor = version->minor;
218
Viresh Kumaread35462015-07-21 17:44:19 +0530219 if (!gb_operation_response_alloc(op, sizeof(*version), GFP_KERNEL)) {
220 dev_err(dev, "%s: error allocating response\n",
221 __func__);
222 return -ENOMEM;
223 }
224
225 version = op->response->payload;
226 version->major = GB_SVC_VERSION_MAJOR;
227 version->minor = GB_SVC_VERSION_MINOR;
228 return 0;
229}
230
231static int gb_svc_hello(struct gb_operation *op)
232{
233 struct gb_connection *connection = op->connection;
234 struct greybus_host_device *hd = connection->hd;
235 struct gb_svc_hello_request *hello_request;
236 struct device *dev = &connection->dev;
237 struct gb_interface *intf;
238 u16 endo_id;
239 u8 interface_id;
240 int ret;
241
Viresh Kumaread35462015-07-21 17:44:19 +0530242 /*
243 * SVC sends information about the endo and interface-id on the hello
244 * request, use that to create an endo.
245 */
Viresh Kumar0c32d2a2015-08-11 07:29:19 +0530246 if (op->request->payload_size < sizeof(*hello_request)) {
247 dev_err(dev, "%s: Illegal size of hello request (%zu < %zu)\n",
Viresh Kumaread35462015-07-21 17:44:19 +0530248 __func__, op->request->payload_size,
249 sizeof(*hello_request));
250 return -EINVAL;
251 }
252
253 hello_request = op->request->payload;
254 endo_id = le16_to_cpu(hello_request->endo_id);
255 interface_id = hello_request->interface_id;
256
257 /* Setup Endo */
258 ret = greybus_endo_setup(hd, endo_id, interface_id);
259 if (ret)
260 return ret;
261
262 /*
263 * Endo and its modules are ready now, fix AP's partially initialized
264 * svc protocol and its connection.
265 */
266 intf = gb_ap_interface_create(hd, connection, interface_id);
267 if (!intf) {
268 gb_endo_remove(hd->endo);
269 return ret;
270 }
271
272 return 0;
273}
274
Viresh Kumar067906f2015-08-06 12:44:55 +0530275/*
276 * 'struct svc_hotplug' should be freed by svc_process_hotplug() before it
277 * returns, irrespective of success or Failure in bringing up the module.
278 */
279static void svc_process_hotplug(struct work_struct *work)
Alex Elder30c6d9d2015-05-22 13:02:08 -0500280{
Viresh Kumar067906f2015-08-06 12:44:55 +0530281 struct svc_hotplug *svc_hotplug = container_of(work, struct svc_hotplug,
282 work);
283 struct gb_svc_intf_hotplug_request *hotplug = &svc_hotplug->data;
284 struct gb_connection *connection = svc_hotplug->connection;
285 struct gb_svc *svc = connection->private;
Viresh Kumarb9fb7042015-09-01 17:16:16 +0530286 struct greybus_host_device *hd = connection->hd;
Viresh Kumar067906f2015-08-06 12:44:55 +0530287 struct device *dev = &connection->dev;
Viresh Kumaread35462015-07-21 17:44:19 +0530288 struct gb_interface *intf;
289 u8 intf_id, device_id;
Viresh Kumaread35462015-07-21 17:44:19 +0530290 int ret;
Alex Elder30c6d9d2015-05-22 13:02:08 -0500291
Alex Elder30c6d9d2015-05-22 13:02:08 -0500292 /*
293 * Grab the information we need.
Viresh Kumar7eb89192015-07-01 12:13:50 +0530294 */
Alex Elder30c6d9d2015-05-22 13:02:08 -0500295 intf_id = hotplug->intf_id;
Alex Elder30c6d9d2015-05-22 13:02:08 -0500296
Viresh Kumaread35462015-07-21 17:44:19 +0530297 intf = gb_interface_create(hd, intf_id);
298 if (!intf) {
299 dev_err(dev, "%s: Failed to create interface with id %hhu\n",
300 __func__, intf_id);
Viresh Kumar067906f2015-08-06 12:44:55 +0530301 goto free_svc_hotplug;
Viresh Kumaread35462015-07-21 17:44:19 +0530302 }
303
Viresh Kumar3944a452015-08-12 09:19:31 +0530304 intf->unipro_mfg_id = le32_to_cpu(hotplug->data.unipro_mfg_id);
305 intf->unipro_prod_id = le32_to_cpu(hotplug->data.unipro_prod_id);
306 intf->ara_vend_id = le32_to_cpu(hotplug->data.ara_vend_id);
307 intf->ara_prod_id = le32_to_cpu(hotplug->data.ara_prod_id);
308
Viresh Kumaread35462015-07-21 17:44:19 +0530309 /*
310 * Create a device id for the interface:
311 * - device id 0 (GB_DEVICE_ID_SVC) belongs to the SVC
312 * - device id 1 (GB_DEVICE_ID_AP) belongs to the AP
313 *
314 * XXX Do we need to allocate device ID for SVC or the AP here? And what
315 * XXX about an AP with multiple interface blocks?
316 */
317 device_id = ida_simple_get(&greybus_svc_device_id_map,
Johan Hovold89f637f2015-09-01 12:25:25 +0200318 GB_DEVICE_ID_MODULES_START, 0, GFP_KERNEL);
Viresh Kumaread35462015-07-21 17:44:19 +0530319 if (device_id < 0) {
320 ret = device_id;
321 dev_err(dev, "%s: Failed to allocate device id for interface with id %hhu (%d)\n",
322 __func__, intf_id, ret);
323 goto destroy_interface;
324 }
325
326 ret = intf_device_id_operation(svc, intf_id, device_id);
327 if (ret) {
328 dev_err(dev, "%s: Device id operation failed, interface %hhu device_id %hhu (%d)\n",
329 __func__, intf_id, device_id, ret);
330 goto ida_put;
331 }
332
Perry Hung7e275462015-07-24 19:02:32 -0400333 /*
334 * Create a two-way route between the AP and the new interface
335 */
336 ret = route_create_operation(svc, hd->endo->ap_intf_id,
337 GB_DEVICE_ID_AP, intf_id, device_id);
338 if (ret) {
339 dev_err(dev, "%s: Route create operation failed, interface %hhu device_id %hhu (%d)\n",
340 __func__, intf_id, device_id, ret);
341 goto ida_put;
342 }
343
344 ret = route_create_operation(svc, intf_id, device_id,
345 hd->endo->ap_intf_id, GB_DEVICE_ID_AP);
346 if (ret) {
347 dev_err(dev, "%s: Route create operation failed, interface %hhu device_id %hhu (%d)\n",
348 __func__, intf_id, device_id, ret);
349 goto ida_put;
350 }
351
Viresh Kumaread35462015-07-21 17:44:19 +0530352 ret = gb_interface_init(intf, device_id);
353 if (ret) {
354 dev_err(dev, "%s: Failed to initialize interface, interface %hhu device_id %hhu (%d)\n",
355 __func__, intf_id, device_id, ret);
356 goto svc_id_free;
357 }
Alex Elder30c6d9d2015-05-22 13:02:08 -0500358
Viresh Kumar067906f2015-08-06 12:44:55 +0530359 goto free_svc_hotplug;
Viresh Kumaread35462015-07-21 17:44:19 +0530360
361svc_id_free:
362 /*
363 * XXX Should we tell SVC that this id doesn't belong to interface
364 * XXX anymore.
365 */
366ida_put:
367 ida_simple_remove(&greybus_svc_device_id_map, device_id);
368destroy_interface:
369 gb_interface_remove(hd, intf_id);
Viresh Kumar067906f2015-08-06 12:44:55 +0530370free_svc_hotplug:
371 kfree(svc_hotplug);
372}
Viresh Kumaread35462015-07-21 17:44:19 +0530373
Viresh Kumar067906f2015-08-06 12:44:55 +0530374/*
375 * Bringing up a module can be time consuming, as that may require lots of
376 * initialization on the module side. Over that, we may also need to download
377 * the firmware first and flash that on the module.
378 *
379 * In order to make other hotplug events to not wait for all this to finish,
380 * handle most of module hotplug stuff outside of the hotplug callback, with
381 * help of a workqueue.
382 */
383static int gb_svc_intf_hotplug_recv(struct gb_operation *op)
384{
385 struct gb_message *request = op->request;
386 struct svc_hotplug *svc_hotplug;
387
388 if (request->payload_size < sizeof(svc_hotplug->data)) {
389 dev_err(&op->connection->dev,
390 "%s: short hotplug request received (%zu < %zu)\n",
391 __func__, request->payload_size,
392 sizeof(svc_hotplug->data));
393 return -EINVAL;
394 }
395
Johan Hovold287bba82015-09-01 12:25:26 +0200396 svc_hotplug = kmalloc(sizeof(*svc_hotplug), GFP_KERNEL);
Viresh Kumar067906f2015-08-06 12:44:55 +0530397 if (!svc_hotplug)
398 return -ENOMEM;
399
400 svc_hotplug->connection = op->connection;
401 memcpy(&svc_hotplug->data, op->request->payload, sizeof(svc_hotplug->data));
402
403 INIT_WORK(&svc_hotplug->work, svc_process_hotplug);
404 queue_work(system_unbound_wq, &svc_hotplug->work);
405
406 return 0;
Alex Elder30c6d9d2015-05-22 13:02:08 -0500407}
408
409static int gb_svc_intf_hot_unplug_recv(struct gb_operation *op)
410{
411 struct gb_message *request = op->request;
Viresh Kumaread35462015-07-21 17:44:19 +0530412 struct gb_svc_intf_hot_unplug_request *hot_unplug = request->payload;
Viresh Kumarb9fb7042015-09-01 17:16:16 +0530413 struct greybus_host_device *hd = op->connection->hd;
Viresh Kumaread35462015-07-21 17:44:19 +0530414 struct device *dev = &op->connection->dev;
415 u8 device_id;
416 struct gb_interface *intf;
Alex Elder30c6d9d2015-05-22 13:02:08 -0500417 u8 intf_id;
418
419 if (request->payload_size < sizeof(*hot_unplug)) {
420 dev_err(&op->connection->dev,
Viresh Kumar6d05ad32015-08-06 12:44:54 +0530421 "short hot unplug request received (%zu < %zu)\n",
422 request->payload_size, sizeof(*hot_unplug));
Alex Elder30c6d9d2015-05-22 13:02:08 -0500423 return -EINVAL;
424 }
Alex Elder30c6d9d2015-05-22 13:02:08 -0500425
426 intf_id = hot_unplug->intf_id;
427
Viresh Kumaread35462015-07-21 17:44:19 +0530428 intf = gb_interface_find(hd, intf_id);
429 if (!intf) {
430 dev_err(dev, "%s: Couldn't find interface for id %hhu\n",
431 __func__, intf_id);
432 return -EINVAL;
433 }
434
435 device_id = intf->device_id;
436 gb_interface_remove(hd, intf_id);
437 ida_simple_remove(&greybus_svc_device_id_map, device_id);
Alex Elder30c6d9d2015-05-22 13:02:08 -0500438
439 return 0;
Alex Elder30c6d9d2015-05-22 13:02:08 -0500440}
441
442static int gb_svc_intf_reset_recv(struct gb_operation *op)
443{
444 struct gb_message *request = op->request;
445 struct gb_svc_intf_reset_request *reset;
446 u8 intf_id;
447
448 if (request->payload_size < sizeof(*reset)) {
449 dev_err(&op->connection->dev,
Viresh Kumar6d05ad32015-08-06 12:44:54 +0530450 "short reset request received (%zu < %zu)\n",
451 request->payload_size, sizeof(*reset));
Alex Elder30c6d9d2015-05-22 13:02:08 -0500452 return -EINVAL;
453 }
454 reset = request->payload;
455
456 intf_id = reset->intf_id;
457
458 /* FIXME Reset the interface here */
459
460 return 0;
461}
462
463static int gb_svc_request_recv(u8 type, struct gb_operation *op)
464{
Viresh Kumar3ccb1602015-09-03 15:42:22 +0530465 struct gb_connection *connection = op->connection;
466 struct gb_svc *svc = connection->private;
467 int ret = 0;
468
469 /*
470 * SVC requests need to follow a specific order (at least initially) and
471 * below code takes care of enforcing that. The expected order is:
472 * - PROTOCOL_VERSION
473 * - SVC_HELLO
474 * - Any other request, but the earlier two.
475 *
476 * Incoming requests are guaranteed to be serialized and so we don't
477 * need to protect 'state' for any races.
478 */
Alex Elder30c6d9d2015-05-22 13:02:08 -0500479 switch (type) {
Viresh Kumar0e2462d2015-08-14 07:57:38 +0530480 case GB_REQUEST_TYPE_PROTOCOL_VERSION:
Viresh Kumar3ccb1602015-09-03 15:42:22 +0530481 if (svc->state != GB_SVC_STATE_RESET)
482 ret = -EINVAL;
483 break;
Viresh Kumaread35462015-07-21 17:44:19 +0530484 case GB_SVC_TYPE_SVC_HELLO:
Viresh Kumar3ccb1602015-09-03 15:42:22 +0530485 if (svc->state != GB_SVC_STATE_PROTOCOL_VERSION)
486 ret = -EINVAL;
487 break;
488 default:
489 if (svc->state != GB_SVC_STATE_SVC_HELLO)
490 ret = -EINVAL;
491 break;
492 }
493
494 if (ret) {
495 dev_warn(&connection->dev,
496 "unexpected SVC request 0x%02x received (state %u)\n",
497 type, svc->state);
498 return ret;
499 }
500
501 switch (type) {
502 case GB_REQUEST_TYPE_PROTOCOL_VERSION:
503 ret = gb_svc_version_request(op);
504 if (!ret)
505 svc->state = GB_SVC_STATE_PROTOCOL_VERSION;
506 return ret;
507 case GB_SVC_TYPE_SVC_HELLO:
508 ret = gb_svc_hello(op);
509 if (!ret)
510 svc->state = GB_SVC_STATE_SVC_HELLO;
511 return ret;
Alex Elder30c6d9d2015-05-22 13:02:08 -0500512 case GB_SVC_TYPE_INTF_HOTPLUG:
513 return gb_svc_intf_hotplug_recv(op);
514 case GB_SVC_TYPE_INTF_HOT_UNPLUG:
515 return gb_svc_intf_hot_unplug_recv(op);
516 case GB_SVC_TYPE_INTF_RESET:
517 return gb_svc_intf_reset_recv(op);
518 default:
519 dev_err(&op->connection->dev,
520 "unsupported request: %hhu\n", type);
521 return -EINVAL;
522 }
523}
524
Alex Elder30c6d9d2015-05-22 13:02:08 -0500525static int gb_svc_connection_init(struct gb_connection *connection)
526{
527 struct gb_svc *svc;
Alex Elder30c6d9d2015-05-22 13:02:08 -0500528
529 svc = kzalloc(sizeof(*svc), GFP_KERNEL);
530 if (!svc)
531 return -ENOMEM;
532
Perry Hung75a60ed2015-07-24 19:02:33 -0400533 connection->hd->svc = svc;
Viresh Kumar3ccb1602015-09-03 15:42:22 +0530534 svc->state = GB_SVC_STATE_RESET;
Alex Elder30c6d9d2015-05-22 13:02:08 -0500535 svc->connection = connection;
536 connection->private = svc;
Viresh Kumard3d44842015-07-21 17:44:18 +0530537
Viresh Kumardcd05002015-07-24 15:32:20 +0530538 WARN_ON(connection->hd->initial_svc_connection);
539 connection->hd->initial_svc_connection = connection;
Viresh Kumard3d44842015-07-21 17:44:18 +0530540
541 ida_init(&greybus_svc_device_id_map);
542
Viresh Kumar18d777c2015-07-21 17:44:20 +0530543 return 0;
Alex Elder30c6d9d2015-05-22 13:02:08 -0500544}
545
546static void gb_svc_connection_exit(struct gb_connection *connection)
547{
548 struct gb_svc *svc = connection->private;
549
Perry Hung75a60ed2015-07-24 19:02:33 -0400550 connection->hd->svc = NULL;
Viresh Kumard3d44842015-07-21 17:44:18 +0530551 connection->private = NULL;
Alex Elder30c6d9d2015-05-22 13:02:08 -0500552 kfree(svc);
553}
554
555static struct gb_protocol svc_protocol = {
556 .name = "svc",
557 .id = GREYBUS_PROTOCOL_SVC,
Viresh Kumar06e305f2015-07-01 12:13:51 +0530558 .major = GB_SVC_VERSION_MAJOR,
559 .minor = GB_SVC_VERSION_MINOR,
Alex Elder30c6d9d2015-05-22 13:02:08 -0500560 .connection_init = gb_svc_connection_init,
561 .connection_exit = gb_svc_connection_exit,
562 .request_recv = gb_svc_request_recv,
563};
Viresh Kumarab69c4c2015-07-03 17:00:29 +0530564gb_builtin_protocol_driver(svc_protocol);