1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2 /* Copyright (c) 2010-2012 Broadcom. All rights reserved. */
3 #include <linux/module.h>
4 #include <linux/types.h>
6 #include "../vchi/vchi.h"
8 #include "vchiq_core.h"
10 #include "vchiq_util.h"
15 struct vchiu_queue queue;
17 vchi_callback callback;
21 /***********************************************************
24 * Arguments: struct vchi_service_handle *handle,
28 * enum vchi_flags flags
30 * Description: Routine to return a pointer to the current message (to allow in
31 * place processing). The message can be removed using
32 * vchi_msg_remove when you're finished
34 * Returns: int32_t - success == 0
36 ***********************************************************/
37 int32_t vchi_msg_peek(struct vchi_service_handle *handle,
40 enum vchi_flags flags)
42 struct shim_service *service = (struct shim_service *)handle;
43 struct vchiq_header *header;
45 WARN_ON((flags != VCHI_FLAGS_NONE) &&
46 (flags != VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE));
48 if (flags == VCHI_FLAGS_NONE)
49 if (vchiu_queue_is_empty(&service->queue))
52 header = vchiu_queue_peek(&service->queue);
55 *msg_size = header->size;
59 EXPORT_SYMBOL(vchi_msg_peek);
61 /***********************************************************
62 * Name: vchi_msg_remove
64 * Arguments: struct vchi_service_handle *handle,
66 * Description: Routine to remove a message (after it has been read with
69 * Returns: int32_t - success == 0
71 ***********************************************************/
72 int32_t vchi_msg_remove(struct vchi_service_handle *handle)
74 struct shim_service *service = (struct shim_service *)handle;
75 struct vchiq_header *header;
77 header = vchiu_queue_pop(&service->queue);
79 vchiq_release_message(service->handle, header);
83 EXPORT_SYMBOL(vchi_msg_remove);
85 int vchi_queue_kernel_message(struct vchi_service_handle *handle, void *data,
88 struct shim_service *service = (struct shim_service *)handle;
89 enum vchiq_status status;
92 status = vchiq_queue_kernel_message(service->handle, data,
96 * vchiq_queue_message() may return VCHIQ_RETRY, so we need to
97 * implement a retry mechanism since this function is supposed
98 * to block until queued
100 if (status != VCHIQ_RETRY)
108 EXPORT_SYMBOL(vchi_queue_kernel_message);
110 /***********************************************************
111 * Name: vchi_bulk_queue_receive
113 * Arguments: VCHI_BULK_HANDLE_T handle,
115 * const uint32_t data_size,
116 * enum vchi_flags flags
119 * Description: Routine to setup a rcv buffer
121 * Returns: int32_t - success == 0
123 ***********************************************************/
124 int32_t vchi_bulk_queue_receive(struct vchi_service_handle *handle, void *data_dst,
125 uint32_t data_size, enum vchi_flags flags,
128 struct shim_service *service = (struct shim_service *)handle;
129 enum vchiq_bulk_mode mode;
130 enum vchiq_status status;
132 switch ((int)flags) {
133 case VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE
134 | VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
135 WARN_ON(!service->callback);
136 mode = VCHIQ_BULK_MODE_CALLBACK;
138 case VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE:
139 mode = VCHIQ_BULK_MODE_BLOCKING;
141 case VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
142 case VCHI_FLAGS_NONE:
143 mode = VCHIQ_BULK_MODE_NOCALLBACK;
146 WARN(1, "unsupported message\n");
151 status = vchiq_bulk_receive(service->handle, data_dst,
152 data_size, bulk_handle, mode);
154 * vchiq_bulk_receive() may return VCHIQ_RETRY, so we need to
155 * implement a retry mechanism since this function is supposed
156 * to block until queued
158 if (status != VCHIQ_RETRY)
166 EXPORT_SYMBOL(vchi_bulk_queue_receive);
168 /***********************************************************
169 * Name: vchi_bulk_queue_transmit
171 * Arguments: VCHI_BULK_HANDLE_T handle,
172 * const void *data_src,
173 * uint32_t data_size,
174 * enum vchi_flags flags,
177 * Description: Routine to transmit some data
179 * Returns: int32_t - success == 0
181 ***********************************************************/
182 int32_t vchi_bulk_queue_transmit(struct vchi_service_handle *handle,
183 const void *data_src,
185 enum vchi_flags flags,
188 struct shim_service *service = (struct shim_service *)handle;
189 enum vchiq_bulk_mode mode;
190 enum vchiq_status status;
192 switch ((int)flags) {
193 case VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE
194 | VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
195 WARN_ON(!service->callback);
196 mode = VCHIQ_BULK_MODE_CALLBACK;
198 case VCHI_FLAGS_BLOCK_UNTIL_DATA_READ:
199 case VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE:
200 mode = VCHIQ_BULK_MODE_BLOCKING;
202 case VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
203 case VCHI_FLAGS_NONE:
204 mode = VCHIQ_BULK_MODE_NOCALLBACK;
207 WARN(1, "unsupported message\n");
212 status = vchiq_bulk_transmit(service->handle, data_src,
213 data_size, bulk_handle, mode);
216 * vchiq_bulk_transmit() may return VCHIQ_RETRY, so we need to
217 * implement a retry mechanism since this function is supposed
218 * to block until queued
220 if (status != VCHIQ_RETRY)
228 EXPORT_SYMBOL(vchi_bulk_queue_transmit);
230 /***********************************************************
231 * Name: vchi_msg_dequeue
233 * Arguments: struct vchi_service_handle *handle,
235 * uint32_t max_data_size_to_read,
236 * uint32_t *actual_msg_size
237 * enum vchi_flags flags
239 * Description: Routine to dequeue a message into the supplied buffer
241 * Returns: int32_t - success == 0
243 ***********************************************************/
244 int32_t vchi_msg_dequeue(struct vchi_service_handle *handle, void *data,
245 uint32_t max_data_size_to_read,
246 uint32_t *actual_msg_size, enum vchi_flags flags)
248 struct shim_service *service = (struct shim_service *)handle;
249 struct vchiq_header *header;
251 WARN_ON((flags != VCHI_FLAGS_NONE) &&
252 (flags != VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE));
254 if (flags == VCHI_FLAGS_NONE)
255 if (vchiu_queue_is_empty(&service->queue))
258 header = vchiu_queue_pop(&service->queue);
260 memcpy(data, header->data, header->size < max_data_size_to_read ?
261 header->size : max_data_size_to_read);
263 *actual_msg_size = header->size;
265 vchiq_release_message(service->handle, header);
269 EXPORT_SYMBOL(vchi_msg_dequeue);
271 /***********************************************************
272 * Name: vchi_held_msg_release
274 * Arguments: struct vchi_held_msg *message
276 * Description: Routine to release a held message (after it has been read with
279 * Returns: int32_t - success == 0
281 ***********************************************************/
282 int32_t vchi_held_msg_release(struct vchi_held_msg *message)
285 * Convert the service field pointer back to an
286 * unsigned int which is an int.
287 * This pointer is opaque to everything except
288 * vchi_msg_hold which simply upcasted the int
292 vchiq_release_message((unsigned int)(long)message->service,
293 (struct vchiq_header *)message->message);
297 EXPORT_SYMBOL(vchi_held_msg_release);
299 /***********************************************************
300 * Name: vchi_msg_hold
302 * Arguments: struct vchi_service_handle *handle,
304 * uint32_t *msg_size,
305 * enum vchi_flags flags,
306 * struct vchi_held_msg *message_handle
308 * Description: Routine to return a pointer to the current message (to allow
309 * in place processing). The message is dequeued - don't forget
310 * to release the message using vchi_held_msg_release when you're
313 * Returns: int32_t - success == 0
315 ***********************************************************/
316 int32_t vchi_msg_hold(struct vchi_service_handle *handle, void **data,
317 uint32_t *msg_size, enum vchi_flags flags,
318 struct vchi_held_msg *message_handle)
320 struct shim_service *service = (struct shim_service *)handle;
321 struct vchiq_header *header;
323 WARN_ON((flags != VCHI_FLAGS_NONE) &&
324 (flags != VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE));
326 if (flags == VCHI_FLAGS_NONE)
327 if (vchiu_queue_is_empty(&service->queue))
330 header = vchiu_queue_pop(&service->queue);
332 *data = header->data;
333 *msg_size = header->size;
336 * upcast the unsigned int which is an int
337 * to a pointer and stuff it in the held message.
338 * This pointer is opaque to everything except
339 * vchi_held_msg_release which simply downcasts it back
343 message_handle->service =
344 (struct opaque_vchi_service_t *)(long)service->handle;
345 message_handle->message = header;
349 EXPORT_SYMBOL(vchi_msg_hold);
351 /***********************************************************
352 * Name: vchi_initialise
354 * Arguments: struct vchi_instance_handle **instance_handle
356 * Description: Initialises the hardware but does not transmit anything
357 * When run as a Host App this will be called twice hence the need
358 * to malloc the state information
360 * Returns: 0 if successful, failure otherwise
362 ***********************************************************/
364 int32_t vchi_initialise(struct vchi_instance_handle **instance_handle)
366 struct vchiq_instance *instance;
367 enum vchiq_status status;
369 status = vchiq_initialise(&instance);
371 *instance_handle = (struct vchi_instance_handle *)instance;
375 EXPORT_SYMBOL(vchi_initialise);
377 /***********************************************************
380 * Arguments: struct vchi_instance_handle *instance_handle
382 * Description: Starts the command service on each connection,
383 * causing INIT messages to be pinged back and forth
385 * Returns: 0 if successful, failure otherwise
387 ***********************************************************/
388 int32_t vchi_connect(struct vchi_instance_handle *instance_handle)
390 struct vchiq_instance *instance = (struct vchiq_instance *)instance_handle;
392 return vchiq_connect(instance);
394 EXPORT_SYMBOL(vchi_connect);
396 /***********************************************************
397 * Name: vchi_disconnect
399 * Arguments: struct vchi_instance_handle *instance_handle
401 * Description: Stops the command service on each connection,
402 * causing DE-INIT messages to be pinged back and forth
404 * Returns: 0 if successful, failure otherwise
406 ***********************************************************/
407 int32_t vchi_disconnect(struct vchi_instance_handle *instance_handle)
409 struct vchiq_instance *instance = (struct vchiq_instance *)instance_handle;
411 return vchiq_shutdown(instance);
413 EXPORT_SYMBOL(vchi_disconnect);
415 /***********************************************************
416 * Name: vchi_service_open
417 * Name: vchi_service_create
419 * Arguments: struct vchi_instance_handle *instance_handle
420 * struct service_creation *setup,
421 * struct vchi_service_handle **handle
423 * Description: Routine to open a service
425 * Returns: int32_t - success == 0
427 ***********************************************************/
429 static enum vchiq_status shim_callback(enum vchiq_reason reason,
430 struct vchiq_header *header,
434 struct shim_service *service =
435 (struct shim_service *)VCHIQ_GET_SERVICE_USERDATA(handle);
437 if (!service->callback)
441 case VCHIQ_MESSAGE_AVAILABLE:
442 vchiu_queue_push(&service->queue, header);
444 service->callback(service->callback_param,
445 VCHI_CALLBACK_MSG_AVAILABLE, NULL);
449 case VCHIQ_BULK_TRANSMIT_DONE:
450 service->callback(service->callback_param,
451 VCHI_CALLBACK_BULK_SENT, bulk_user);
454 case VCHIQ_BULK_RECEIVE_DONE:
455 service->callback(service->callback_param,
456 VCHI_CALLBACK_BULK_RECEIVED, bulk_user);
459 case VCHIQ_SERVICE_CLOSED:
460 service->callback(service->callback_param,
461 VCHI_CALLBACK_SERVICE_CLOSED, NULL);
464 case VCHIQ_BULK_TRANSMIT_ABORTED:
465 service->callback(service->callback_param,
466 VCHI_CALLBACK_BULK_TRANSMIT_ABORTED,
470 case VCHIQ_BULK_RECEIVE_ABORTED:
471 service->callback(service->callback_param,
472 VCHI_CALLBACK_BULK_RECEIVE_ABORTED,
477 WARN(1, "not supported\n");
482 return VCHIQ_SUCCESS;
485 static struct shim_service *service_alloc(struct vchiq_instance *instance,
486 struct service_creation *setup)
488 struct shim_service *service = kzalloc(sizeof(struct shim_service), GFP_KERNEL);
493 if (!vchiu_queue_init(&service->queue, 64)) {
494 service->callback = setup->callback;
495 service->callback_param = setup->callback_param;
505 static void service_free(struct shim_service *service)
508 vchiu_queue_delete(&service->queue);
513 int32_t vchi_service_open(struct vchi_instance_handle *instance_handle,
514 struct service_creation *setup,
515 struct vchi_service_handle **handle)
517 struct vchiq_instance *instance = (struct vchiq_instance *)instance_handle;
518 struct shim_service *service = service_alloc(instance, setup);
520 *handle = (struct vchi_service_handle *)service;
523 struct vchiq_service_params params;
524 enum vchiq_status status;
526 memset(¶ms, 0, sizeof(params));
527 params.fourcc = setup->service_id;
528 params.callback = shim_callback;
529 params.userdata = service;
530 params.version = setup->version.version;
531 params.version_min = setup->version.version_min;
533 status = vchiq_open_service(instance, ¶ms,
535 if (status != VCHIQ_SUCCESS) {
536 service_free(service);
542 return service ? 0 : -1;
544 EXPORT_SYMBOL(vchi_service_open);
546 int32_t vchi_service_close(const struct vchi_service_handle *handle)
549 struct shim_service *service = (struct shim_service *)handle;
552 enum vchiq_status status = vchiq_close_service(service->handle);
553 if (status == VCHIQ_SUCCESS)
554 service_free(service);
560 EXPORT_SYMBOL(vchi_service_close);
562 int32_t vchi_get_peer_version(const struct vchi_service_handle *handle, short *peer_version)
565 struct shim_service *service = (struct shim_service *)handle;
568 enum vchiq_status status;
570 status = vchiq_get_peer_version(service->handle, peer_version);
575 EXPORT_SYMBOL(vchi_get_peer_version);
577 /***********************************************************
578 * Name: vchi_service_use
580 * Arguments: const struct vchi_service_handle *handle
582 * Description: Routine to increment refcount on a service
586 ***********************************************************/
587 int32_t vchi_service_use(const struct vchi_service_handle *handle)
591 struct shim_service *service = (struct shim_service *)handle;
593 ret = vchiq_use_service(service->handle);
596 EXPORT_SYMBOL(vchi_service_use);
598 /***********************************************************
599 * Name: vchi_service_release
601 * Arguments: const struct vchi_service_handle *handle
603 * Description: Routine to decrement refcount on a service
607 ***********************************************************/
608 int32_t vchi_service_release(const struct vchi_service_handle *handle)
612 struct shim_service *service = (struct shim_service *)handle;
614 ret = vchiq_release_service(service->handle);
617 EXPORT_SYMBOL(vchi_service_release);