4 * Copyright 2015 Google Inc.
5 * Copyright 2015 Linaro Ltd.
7 * Released under the GPLv2 only.
11 #include <linux/workqueue.h>
13 #define CPORT_FLAGS_E2EFC (1)
14 #define CPORT_FLAGS_CSD_N (2)
15 #define CPORT_FLAGS_CSV_N (4)
18 struct gb_connection *connection;
22 struct work_struct work;
23 struct gb_connection *connection;
24 struct gb_svc_intf_hotplug_request data;
27 static struct ida greybus_svc_device_id_map;
30 * AP's SVC cport is required early to get messages from the SVC. This happens
31 * even before the Endo is created and hence any modules or interfaces.
33 * This is a temporary connection, used only at initial bootup.
35 struct gb_connection *
36 gb_ap_svc_connection_create(struct greybus_host_device *hd)
38 struct gb_connection *connection;
40 connection = gb_connection_create_range(hd, NULL, hd->parent,
50 * We know endo-type and AP's interface id now, lets create a proper svc
51 * connection (and its interface/bundle) now and get rid of the initial
52 * 'partially' initialized one svc connection.
54 static struct gb_interface *
55 gb_ap_interface_create(struct greybus_host_device *hd,
56 struct gb_connection *connection, u8 interface_id)
58 struct gb_interface *intf;
59 struct device *dev = &hd->endo->dev;
61 intf = gb_interface_create(hd, interface_id);
63 dev_err(dev, "%s: Failed to create interface with id %hhu\n",
64 __func__, interface_id);
68 intf->device_id = GB_DEVICE_ID_AP;
69 svc_update_connection(intf, connection);
71 /* Its no longer a partially initialized connection */
72 hd->initial_svc_connection = NULL;
77 static int intf_device_id_operation(struct gb_svc *svc,
78 u8 intf_id, u8 device_id)
80 struct gb_svc_intf_device_id_request request;
82 request.intf_id = intf_id;
83 request.device_id = device_id;
85 return gb_operation_sync(svc->connection, GB_SVC_TYPE_INTF_DEVICE_ID,
86 &request, sizeof(request), NULL, 0);
89 static int intf_reset_operation(struct gb_svc *svc, u8 intf_id)
91 struct gb_svc_intf_reset_request request;
93 request.intf_id = intf_id;
95 return gb_operation_sync(svc->connection, GB_SVC_TYPE_INTF_RESET,
96 &request, sizeof(request), NULL, 0);
99 static int connection_create_operation(struct gb_svc *svc,
100 u8 intf1_id, u16 cport1_id,
101 u8 intf2_id, u16 cport2_id)
103 struct gb_svc_conn_create_request request;
105 request.intf1_id = intf1_id;
106 request.cport1_id = cport1_id;
107 request.intf2_id = intf2_id;
108 request.cport2_id = cport2_id;
110 * XXX: fix connections paramaters to TC0 and all CPort flags
114 request.flags = CPORT_FLAGS_CSV_N | CPORT_FLAGS_E2EFC;
116 return gb_operation_sync(svc->connection, GB_SVC_TYPE_CONN_CREATE,
117 &request, sizeof(request), NULL, 0);
120 static int connection_destroy_operation(struct gb_svc *svc,
121 u8 intf1_id, u16 cport1_id,
122 u8 intf2_id, u16 cport2_id)
124 struct gb_svc_conn_destroy_request request;
126 request.intf1_id = intf1_id;
127 request.cport1_id = cport1_id;
128 request.intf2_id = intf2_id;
129 request.cport2_id = cport2_id;
131 return gb_operation_sync(svc->connection, GB_SVC_TYPE_CONN_DESTROY,
132 &request, sizeof(request), NULL, 0);
135 static int route_create_operation(struct gb_svc *svc, u8 intf1_id, u8 dev1_id,
136 u8 intf2_id, u8 dev2_id)
138 struct gb_svc_route_create_request request;
140 request.intf1_id = intf1_id;
141 request.dev1_id = dev1_id;
142 request.intf2_id = intf2_id;
143 request.dev2_id = dev2_id;
145 return gb_operation_sync(svc->connection, GB_SVC_TYPE_ROUTE_CREATE,
146 &request, sizeof(request), NULL, 0);
149 int gb_svc_intf_device_id(struct gb_svc *svc, u8 intf_id, u8 device_id)
151 return intf_device_id_operation(svc, intf_id, device_id);
153 EXPORT_SYMBOL_GPL(gb_svc_intf_device_id);
155 int gb_svc_intf_reset(struct gb_svc *svc, u8 intf_id)
157 return intf_reset_operation(svc, intf_id);
159 EXPORT_SYMBOL_GPL(gb_svc_intf_reset);
161 int gb_svc_connection_create(struct gb_svc *svc,
162 u8 intf1_id, u16 cport1_id,
163 u8 intf2_id, u16 cport2_id)
165 return connection_create_operation(svc, intf1_id, cport1_id,
166 intf2_id, cport2_id);
168 EXPORT_SYMBOL_GPL(gb_svc_connection_create);
170 int gb_svc_connection_destroy(struct gb_svc *svc,
171 u8 intf1_id, u16 cport1_id,
172 u8 intf2_id, u16 cport2_id)
174 return connection_destroy_operation(svc, intf1_id, cport1_id,
175 intf2_id, cport2_id);
177 EXPORT_SYMBOL_GPL(gb_svc_connection_destroy);
179 int gb_svc_route_create(struct gb_svc *svc, u8 intf1_id, u8 dev1_id,
180 u8 intf2_id, u8 dev2_id)
182 return route_create_operation(svc, intf1_id, dev1_id,
185 EXPORT_SYMBOL_GPL(gb_svc_route_create);
187 static int gb_svc_version_request(struct gb_operation *op)
189 struct gb_connection *connection = op->connection;
190 struct gb_protocol_version_response *version;
191 struct device *dev = &connection->dev;
193 version = op->request->payload;
195 if (version->major > GB_SVC_VERSION_MAJOR) {
196 dev_err(&connection->dev,
197 "unsupported major version (%hhu > %hhu)\n",
198 version->major, GB_SVC_VERSION_MAJOR);
202 connection->module_major = version->major;
203 connection->module_minor = version->minor;
205 if (!gb_operation_response_alloc(op, sizeof(*version), GFP_KERNEL)) {
206 dev_err(dev, "%s: error allocating response\n",
211 version = op->response->payload;
212 version->major = GB_SVC_VERSION_MAJOR;
213 version->minor = GB_SVC_VERSION_MINOR;
217 static int gb_svc_hello(struct gb_operation *op)
219 struct gb_connection *connection = op->connection;
220 struct greybus_host_device *hd = connection->hd;
221 struct gb_svc_hello_request *hello_request;
222 struct device *dev = &connection->dev;
223 struct gb_interface *intf;
228 /* Hello message should be received only during early bootup */
229 WARN_ON(hd->initial_svc_connection != connection);
232 * SVC sends information about the endo and interface-id on the hello
233 * request, use that to create an endo.
235 if (op->request->payload_size < sizeof(*hello_request)) {
236 dev_err(dev, "%s: Illegal size of hello request (%zu < %zu)\n",
237 __func__, op->request->payload_size,
238 sizeof(*hello_request));
242 hello_request = op->request->payload;
243 endo_id = le16_to_cpu(hello_request->endo_id);
244 interface_id = hello_request->interface_id;
247 ret = greybus_endo_setup(hd, endo_id, interface_id);
252 * Endo and its modules are ready now, fix AP's partially initialized
253 * svc protocol and its connection.
255 intf = gb_ap_interface_create(hd, connection, interface_id);
257 gb_endo_remove(hd->endo);
265 * 'struct svc_hotplug' should be freed by svc_process_hotplug() before it
266 * returns, irrespective of success or Failure in bringing up the module.
268 static void svc_process_hotplug(struct work_struct *work)
270 struct svc_hotplug *svc_hotplug = container_of(work, struct svc_hotplug,
272 struct gb_svc_intf_hotplug_request *hotplug = &svc_hotplug->data;
273 struct gb_connection *connection = svc_hotplug->connection;
274 struct gb_svc *svc = connection->private;
275 struct greybus_host_device *hd = connection->hd;
276 struct device *dev = &connection->dev;
277 struct gb_interface *intf;
278 u8 intf_id, device_id;
282 * Grab the information we need.
284 intf_id = hotplug->intf_id;
286 intf = gb_interface_create(hd, intf_id);
288 dev_err(dev, "%s: Failed to create interface with id %hhu\n",
290 goto free_svc_hotplug;
293 intf->unipro_mfg_id = le32_to_cpu(hotplug->data.unipro_mfg_id);
294 intf->unipro_prod_id = le32_to_cpu(hotplug->data.unipro_prod_id);
295 intf->ara_vend_id = le32_to_cpu(hotplug->data.ara_vend_id);
296 intf->ara_prod_id = le32_to_cpu(hotplug->data.ara_prod_id);
299 * Create a device id for the interface:
300 * - device id 0 (GB_DEVICE_ID_SVC) belongs to the SVC
301 * - device id 1 (GB_DEVICE_ID_AP) belongs to the AP
303 * XXX Do we need to allocate device ID for SVC or the AP here? And what
304 * XXX about an AP with multiple interface blocks?
306 device_id = ida_simple_get(&greybus_svc_device_id_map,
307 GB_DEVICE_ID_MODULES_START, 0, GFP_KERNEL);
310 dev_err(dev, "%s: Failed to allocate device id for interface with id %hhu (%d)\n",
311 __func__, intf_id, ret);
312 goto destroy_interface;
315 ret = intf_device_id_operation(svc, intf_id, device_id);
317 dev_err(dev, "%s: Device id operation failed, interface %hhu device_id %hhu (%d)\n",
318 __func__, intf_id, device_id, ret);
323 * Create a two-way route between the AP and the new interface
325 ret = route_create_operation(svc, hd->endo->ap_intf_id,
326 GB_DEVICE_ID_AP, intf_id, device_id);
328 dev_err(dev, "%s: Route create operation failed, interface %hhu device_id %hhu (%d)\n",
329 __func__, intf_id, device_id, ret);
333 ret = route_create_operation(svc, intf_id, device_id,
334 hd->endo->ap_intf_id, GB_DEVICE_ID_AP);
336 dev_err(dev, "%s: Route create operation failed, interface %hhu device_id %hhu (%d)\n",
337 __func__, intf_id, device_id, ret);
341 ret = gb_interface_init(intf, device_id);
343 dev_err(dev, "%s: Failed to initialize interface, interface %hhu device_id %hhu (%d)\n",
344 __func__, intf_id, device_id, ret);
348 goto free_svc_hotplug;
352 * XXX Should we tell SVC that this id doesn't belong to interface
356 ida_simple_remove(&greybus_svc_device_id_map, device_id);
358 gb_interface_remove(hd, intf_id);
364 * Bringing up a module can be time consuming, as that may require lots of
365 * initialization on the module side. Over that, we may also need to download
366 * the firmware first and flash that on the module.
368 * In order to make other hotplug events to not wait for all this to finish,
369 * handle most of module hotplug stuff outside of the hotplug callback, with
370 * help of a workqueue.
372 static int gb_svc_intf_hotplug_recv(struct gb_operation *op)
374 struct gb_message *request = op->request;
375 struct svc_hotplug *svc_hotplug;
377 if (request->payload_size < sizeof(svc_hotplug->data)) {
378 dev_err(&op->connection->dev,
379 "%s: short hotplug request received (%zu < %zu)\n",
380 __func__, request->payload_size,
381 sizeof(svc_hotplug->data));
385 svc_hotplug = kmalloc(sizeof(*svc_hotplug), GFP_KERNEL);
389 svc_hotplug->connection = op->connection;
390 memcpy(&svc_hotplug->data, op->request->payload, sizeof(svc_hotplug->data));
392 INIT_WORK(&svc_hotplug->work, svc_process_hotplug);
393 queue_work(system_unbound_wq, &svc_hotplug->work);
398 static int gb_svc_intf_hot_unplug_recv(struct gb_operation *op)
400 struct gb_message *request = op->request;
401 struct gb_svc_intf_hot_unplug_request *hot_unplug = request->payload;
402 struct greybus_host_device *hd = op->connection->hd;
403 struct device *dev = &op->connection->dev;
405 struct gb_interface *intf;
408 if (request->payload_size < sizeof(*hot_unplug)) {
409 dev_err(&op->connection->dev,
410 "short hot unplug request received (%zu < %zu)\n",
411 request->payload_size, sizeof(*hot_unplug));
415 intf_id = hot_unplug->intf_id;
417 intf = gb_interface_find(hd, intf_id);
419 dev_err(dev, "%s: Couldn't find interface for id %hhu\n",
424 device_id = intf->device_id;
425 gb_interface_remove(hd, intf_id);
426 ida_simple_remove(&greybus_svc_device_id_map, device_id);
431 static int gb_svc_intf_reset_recv(struct gb_operation *op)
433 struct gb_message *request = op->request;
434 struct gb_svc_intf_reset_request *reset;
437 if (request->payload_size < sizeof(*reset)) {
438 dev_err(&op->connection->dev,
439 "short reset request received (%zu < %zu)\n",
440 request->payload_size, sizeof(*reset));
443 reset = request->payload;
445 intf_id = reset->intf_id;
447 /* FIXME Reset the interface here */
452 static int gb_svc_request_recv(u8 type, struct gb_operation *op)
455 case GB_REQUEST_TYPE_PROTOCOL_VERSION:
456 return gb_svc_version_request(op);
457 case GB_SVC_TYPE_SVC_HELLO:
458 return gb_svc_hello(op);
459 case GB_SVC_TYPE_INTF_HOTPLUG:
460 return gb_svc_intf_hotplug_recv(op);
461 case GB_SVC_TYPE_INTF_HOT_UNPLUG:
462 return gb_svc_intf_hot_unplug_recv(op);
463 case GB_SVC_TYPE_INTF_RESET:
464 return gb_svc_intf_reset_recv(op);
466 dev_err(&op->connection->dev,
467 "unsupported request: %hhu\n", type);
472 static int gb_svc_connection_init(struct gb_connection *connection)
476 svc = kzalloc(sizeof(*svc), GFP_KERNEL);
480 connection->hd->svc = svc;
481 svc->connection = connection;
482 connection->private = svc;
484 WARN_ON(connection->hd->initial_svc_connection);
485 connection->hd->initial_svc_connection = connection;
487 ida_init(&greybus_svc_device_id_map);
492 static void gb_svc_connection_exit(struct gb_connection *connection)
494 struct gb_svc *svc = connection->private;
496 connection->hd->svc = NULL;
497 connection->private = NULL;
501 static struct gb_protocol svc_protocol = {
503 .id = GREYBUS_PROTOCOL_SVC,
504 .major = GB_SVC_VERSION_MAJOR,
505 .minor = GB_SVC_VERSION_MINOR,
506 .connection_init = gb_svc_connection_init,
507 .connection_exit = gb_svc_connection_exit,
508 .request_recv = gb_svc_request_recv,
510 gb_builtin_protocol_driver(svc_protocol);