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"
12 #define vchiq_status_to_vchi(status) ((int32_t)status)
17 struct vchiu_queue queue;
19 vchi_callback callback;
23 /***********************************************************
26 * Arguments: struct vchi_service_handle *handle,
30 * enum vchi_flags flags
32 * Description: Routine to return a pointer to the current message (to allow in
33 * place processing). The message can be removed using
34 * vchi_msg_remove when you're finished
36 * Returns: int32_t - success == 0
38 ***********************************************************/
39 int32_t vchi_msg_peek(struct vchi_service_handle *handle,
42 enum vchi_flags flags)
44 struct shim_service *service = (struct shim_service *)handle;
45 struct vchiq_header *header;
47 WARN_ON((flags != VCHI_FLAGS_NONE) &&
48 (flags != VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE));
50 if (flags == VCHI_FLAGS_NONE)
51 if (vchiu_queue_is_empty(&service->queue))
54 header = vchiu_queue_peek(&service->queue);
57 *msg_size = header->size;
61 EXPORT_SYMBOL(vchi_msg_peek);
63 /***********************************************************
64 * Name: vchi_msg_remove
66 * Arguments: struct vchi_service_handle *handle,
68 * Description: Routine to remove a message (after it has been read with
71 * Returns: int32_t - success == 0
73 ***********************************************************/
74 int32_t vchi_msg_remove(struct vchi_service_handle *handle)
76 struct shim_service *service = (struct shim_service *)handle;
77 struct vchiq_header *header;
79 header = vchiu_queue_pop(&service->queue);
81 vchiq_release_message(service->handle, header);
85 EXPORT_SYMBOL(vchi_msg_remove);
87 /***********************************************************
88 * Name: vchi_msg_queue
90 * Arguments: struct vchi_service_handle *handle,
91 * ssize_t (*copy_callback)(void *context, void *dest,
92 * size_t offset, size_t maxsize),
96 * Description: Thin wrapper to queue a message onto a connection
98 * Returns: int32_t - success == 0
100 ***********************************************************/
102 int32_t vchi_msg_queue(struct vchi_service_handle *handle,
103 ssize_t (*copy_callback)(void *context, void *dest,
104 size_t offset, size_t maxsize),
108 struct shim_service *service = (struct shim_service *)handle;
109 enum vchiq_status status;
112 status = vchiq_queue_message(service->handle,
118 * vchiq_queue_message() may return VCHIQ_RETRY, so we need to
119 * implement a retry mechanism since this function is supposed
120 * to block until queued
122 if (status != VCHIQ_RETRY)
128 return vchiq_status_to_vchi(status);
132 vchi_queue_kernel_message_callback(void *context,
137 memcpy(dest, context + offset, maxsize);
142 vchi_queue_kernel_message(struct vchi_service_handle *handle,
146 return vchi_msg_queue(handle,
147 vchi_queue_kernel_message_callback,
151 EXPORT_SYMBOL(vchi_queue_kernel_message);
153 struct vchi_queue_user_message_context {
158 vchi_queue_user_message_callback(void *context,
163 struct vchi_queue_user_message_context *copycontext = context;
165 if (copy_from_user(dest, copycontext->data + offset, maxsize))
172 vchi_queue_user_message(struct vchi_service_handle *handle,
176 struct vchi_queue_user_message_context copycontext = {
180 return vchi_msg_queue(handle,
181 vchi_queue_user_message_callback,
185 EXPORT_SYMBOL(vchi_queue_user_message);
187 /***********************************************************
188 * Name: vchi_bulk_queue_receive
190 * Arguments: VCHI_BULK_HANDLE_T handle,
192 * const uint32_t data_size,
193 * enum vchi_flags flags
196 * Description: Routine to setup a rcv buffer
198 * Returns: int32_t - success == 0
200 ***********************************************************/
201 int32_t vchi_bulk_queue_receive(struct vchi_service_handle *handle, void *data_dst,
202 uint32_t data_size, enum vchi_flags flags,
205 struct shim_service *service = (struct shim_service *)handle;
206 enum vchiq_bulk_mode mode;
207 enum vchiq_status status;
209 switch ((int)flags) {
210 case VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE
211 | VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
212 WARN_ON(!service->callback);
213 mode = VCHIQ_BULK_MODE_CALLBACK;
215 case VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE:
216 mode = VCHIQ_BULK_MODE_BLOCKING;
218 case VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
219 case VCHI_FLAGS_NONE:
220 mode = VCHIQ_BULK_MODE_NOCALLBACK;
223 WARN(1, "unsupported message\n");
224 return vchiq_status_to_vchi(VCHIQ_ERROR);
228 status = vchiq_bulk_receive(service->handle, data_dst,
229 data_size, bulk_handle, mode);
231 * vchiq_bulk_receive() may return VCHIQ_RETRY, so we need to
232 * implement a retry mechanism since this function is supposed
233 * to block until queued
235 if (status != VCHIQ_RETRY)
241 return vchiq_status_to_vchi(status);
243 EXPORT_SYMBOL(vchi_bulk_queue_receive);
245 /***********************************************************
246 * Name: vchi_bulk_queue_transmit
248 * Arguments: VCHI_BULK_HANDLE_T handle,
249 * const void *data_src,
250 * uint32_t data_size,
251 * enum vchi_flags flags,
254 * Description: Routine to transmit some data
256 * Returns: int32_t - success == 0
258 ***********************************************************/
259 int32_t vchi_bulk_queue_transmit(struct vchi_service_handle *handle,
260 const void *data_src,
262 enum vchi_flags flags,
265 struct shim_service *service = (struct shim_service *)handle;
266 enum vchiq_bulk_mode mode;
267 enum vchiq_status status;
269 switch ((int)flags) {
270 case VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE
271 | VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
272 WARN_ON(!service->callback);
273 mode = VCHIQ_BULK_MODE_CALLBACK;
275 case VCHI_FLAGS_BLOCK_UNTIL_DATA_READ:
276 case VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE:
277 mode = VCHIQ_BULK_MODE_BLOCKING;
279 case VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
280 case VCHI_FLAGS_NONE:
281 mode = VCHIQ_BULK_MODE_NOCALLBACK;
284 WARN(1, "unsupported message\n");
285 return vchiq_status_to_vchi(VCHIQ_ERROR);
289 status = vchiq_bulk_transmit(service->handle, data_src,
290 data_size, bulk_handle, mode);
293 * vchiq_bulk_transmit() may return VCHIQ_RETRY, so we need to
294 * implement a retry mechanism since this function is supposed
295 * to block until queued
297 if (status != VCHIQ_RETRY)
303 return vchiq_status_to_vchi(status);
305 EXPORT_SYMBOL(vchi_bulk_queue_transmit);
307 /***********************************************************
308 * Name: vchi_msg_dequeue
310 * Arguments: struct vchi_service_handle *handle,
312 * uint32_t max_data_size_to_read,
313 * uint32_t *actual_msg_size
314 * enum vchi_flags flags
316 * Description: Routine to dequeue a message into the supplied buffer
318 * Returns: int32_t - success == 0
320 ***********************************************************/
321 int32_t vchi_msg_dequeue(struct vchi_service_handle *handle, void *data,
322 uint32_t max_data_size_to_read,
323 uint32_t *actual_msg_size, enum vchi_flags flags)
325 struct shim_service *service = (struct shim_service *)handle;
326 struct vchiq_header *header;
328 WARN_ON((flags != VCHI_FLAGS_NONE) &&
329 (flags != VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE));
331 if (flags == VCHI_FLAGS_NONE)
332 if (vchiu_queue_is_empty(&service->queue))
335 header = vchiu_queue_pop(&service->queue);
337 memcpy(data, header->data, header->size < max_data_size_to_read ?
338 header->size : max_data_size_to_read);
340 *actual_msg_size = header->size;
342 vchiq_release_message(service->handle, header);
346 EXPORT_SYMBOL(vchi_msg_dequeue);
348 /***********************************************************
349 * Name: vchi_held_msg_release
351 * Arguments: struct vchi_held_msg *message
353 * Description: Routine to release a held message (after it has been read with
356 * Returns: int32_t - success == 0
358 ***********************************************************/
359 int32_t vchi_held_msg_release(struct vchi_held_msg *message)
362 * Convert the service field pointer back to an
363 * unsigned int which is an int.
364 * This pointer is opaque to everything except
365 * vchi_msg_hold which simply upcasted the int
369 vchiq_release_message((unsigned int)(long)message->service,
370 (struct vchiq_header *)message->message);
374 EXPORT_SYMBOL(vchi_held_msg_release);
376 /***********************************************************
377 * Name: vchi_msg_hold
379 * Arguments: struct vchi_service_handle *handle,
381 * uint32_t *msg_size,
382 * enum vchi_flags flags,
383 * struct vchi_held_msg *message_handle
385 * Description: Routine to return a pointer to the current message (to allow
386 * in place processing). The message is dequeued - don't forget
387 * to release the message using vchi_held_msg_release when you're
390 * Returns: int32_t - success == 0
392 ***********************************************************/
393 int32_t vchi_msg_hold(struct vchi_service_handle *handle, void **data,
394 uint32_t *msg_size, enum vchi_flags flags,
395 struct vchi_held_msg *message_handle)
397 struct shim_service *service = (struct shim_service *)handle;
398 struct vchiq_header *header;
400 WARN_ON((flags != VCHI_FLAGS_NONE) &&
401 (flags != VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE));
403 if (flags == VCHI_FLAGS_NONE)
404 if (vchiu_queue_is_empty(&service->queue))
407 header = vchiu_queue_pop(&service->queue);
409 *data = header->data;
410 *msg_size = header->size;
413 * upcast the unsigned int which is an int
414 * to a pointer and stuff it in the held message.
415 * This pointer is opaque to everything except
416 * vchi_held_msg_release which simply downcasts it back
420 message_handle->service =
421 (struct opaque_vchi_service_t *)(long)service->handle;
422 message_handle->message = header;
426 EXPORT_SYMBOL(vchi_msg_hold);
428 /***********************************************************
429 * Name: vchi_initialise
431 * Arguments: struct vchi_instance_handle **instance_handle
433 * Description: Initialises the hardware but does not transmit anything
434 * When run as a Host App this will be called twice hence the need
435 * to malloc the state information
437 * Returns: 0 if successful, failure otherwise
439 ***********************************************************/
441 int32_t vchi_initialise(struct vchi_instance_handle **instance_handle)
443 struct vchiq_instance *instance;
444 enum vchiq_status status;
446 status = vchiq_initialise(&instance);
448 *instance_handle = (struct vchi_instance_handle *)instance;
450 return vchiq_status_to_vchi(status);
452 EXPORT_SYMBOL(vchi_initialise);
454 /***********************************************************
457 * Arguments: struct vchi_instance_handle *instance_handle
459 * Description: Starts the command service on each connection,
460 * causing INIT messages to be pinged back and forth
462 * Returns: 0 if successful, failure otherwise
464 ***********************************************************/
465 int32_t vchi_connect(struct vchi_instance_handle *instance_handle)
467 struct vchiq_instance *instance = (struct vchiq_instance *)instance_handle;
469 return vchiq_connect(instance);
471 EXPORT_SYMBOL(vchi_connect);
473 /***********************************************************
474 * Name: vchi_disconnect
476 * Arguments: struct vchi_instance_handle *instance_handle
478 * Description: Stops the command service on each connection,
479 * causing DE-INIT messages to be pinged back and forth
481 * Returns: 0 if successful, failure otherwise
483 ***********************************************************/
484 int32_t vchi_disconnect(struct vchi_instance_handle *instance_handle)
486 struct vchiq_instance *instance = (struct vchiq_instance *)instance_handle;
488 return vchiq_status_to_vchi(vchiq_shutdown(instance));
490 EXPORT_SYMBOL(vchi_disconnect);
492 /***********************************************************
493 * Name: vchi_service_open
494 * Name: vchi_service_create
496 * Arguments: struct vchi_instance_handle *instance_handle
497 * struct service_creation *setup,
498 * struct vchi_service_handle **handle
500 * Description: Routine to open a service
502 * Returns: int32_t - success == 0
504 ***********************************************************/
506 static enum vchiq_status shim_callback(enum vchiq_reason reason,
507 struct vchiq_header *header,
511 struct shim_service *service =
512 (struct shim_service *)VCHIQ_GET_SERVICE_USERDATA(handle);
514 if (!service->callback)
518 case VCHIQ_MESSAGE_AVAILABLE:
519 vchiu_queue_push(&service->queue, header);
521 service->callback(service->callback_param,
522 VCHI_CALLBACK_MSG_AVAILABLE, NULL);
526 case VCHIQ_BULK_TRANSMIT_DONE:
527 service->callback(service->callback_param,
528 VCHI_CALLBACK_BULK_SENT, bulk_user);
531 case VCHIQ_BULK_RECEIVE_DONE:
532 service->callback(service->callback_param,
533 VCHI_CALLBACK_BULK_RECEIVED, bulk_user);
536 case VCHIQ_SERVICE_CLOSED:
537 service->callback(service->callback_param,
538 VCHI_CALLBACK_SERVICE_CLOSED, NULL);
541 case VCHIQ_SERVICE_OPENED:
542 /* No equivalent VCHI reason */
545 case VCHIQ_BULK_TRANSMIT_ABORTED:
546 service->callback(service->callback_param,
547 VCHI_CALLBACK_BULK_TRANSMIT_ABORTED,
551 case VCHIQ_BULK_RECEIVE_ABORTED:
552 service->callback(service->callback_param,
553 VCHI_CALLBACK_BULK_RECEIVE_ABORTED,
558 WARN(1, "not supported\n");
563 vchiq_release_message(service->handle, header);
565 return VCHIQ_SUCCESS;
568 static struct shim_service *service_alloc(struct vchiq_instance *instance,
569 struct service_creation *setup)
571 struct shim_service *service = kzalloc(sizeof(struct shim_service), GFP_KERNEL);
576 if (!vchiu_queue_init(&service->queue, 64)) {
577 service->callback = setup->callback;
578 service->callback_param = setup->callback_param;
588 static void service_free(struct shim_service *service)
591 vchiu_queue_delete(&service->queue);
596 int32_t vchi_service_open(struct vchi_instance_handle *instance_handle,
597 struct service_creation *setup,
598 struct vchi_service_handle **handle)
600 struct vchiq_instance *instance = (struct vchiq_instance *)instance_handle;
601 struct shim_service *service = service_alloc(instance, setup);
603 *handle = (struct vchi_service_handle *)service;
606 struct vchiq_service_params params;
607 enum vchiq_status status;
609 memset(¶ms, 0, sizeof(params));
610 params.fourcc = setup->service_id;
611 params.callback = shim_callback;
612 params.userdata = service;
613 params.version = setup->version.version;
614 params.version_min = setup->version.version_min;
616 status = vchiq_open_service(instance, ¶ms,
618 if (status != VCHIQ_SUCCESS) {
619 service_free(service);
625 return service ? 0 : -1;
627 EXPORT_SYMBOL(vchi_service_open);
629 int32_t vchi_service_close(const struct vchi_service_handle *handle)
632 struct shim_service *service = (struct shim_service *)handle;
635 enum vchiq_status status = vchiq_close_service(service->handle);
636 if (status == VCHIQ_SUCCESS)
637 service_free(service);
639 ret = vchiq_status_to_vchi(status);
643 EXPORT_SYMBOL(vchi_service_close);
645 int32_t vchi_service_destroy(const struct vchi_service_handle *handle)
648 struct shim_service *service = (struct shim_service *)handle;
651 enum vchiq_status status = vchiq_remove_service(service->handle);
653 if (status == VCHIQ_SUCCESS) {
654 service_free(service);
658 ret = vchiq_status_to_vchi(status);
662 EXPORT_SYMBOL(vchi_service_destroy);
664 int32_t vchi_service_set_option(const struct vchi_service_handle *handle,
665 enum vchi_service_option option,
669 struct shim_service *service = (struct shim_service *)handle;
670 enum vchiq_service_option vchiq_option;
673 case VCHI_SERVICE_OPTION_TRACE:
674 vchiq_option = VCHIQ_SERVICE_OPTION_TRACE;
676 case VCHI_SERVICE_OPTION_SYNCHRONOUS:
677 vchiq_option = VCHIQ_SERVICE_OPTION_SYNCHRONOUS;
684 enum vchiq_status status =
685 vchiq_set_service_option(service->handle,
689 ret = vchiq_status_to_vchi(status);
693 EXPORT_SYMBOL(vchi_service_set_option);
695 int32_t vchi_get_peer_version(const struct vchi_service_handle *handle, short *peer_version)
698 struct shim_service *service = (struct shim_service *)handle;
701 enum vchiq_status status;
703 status = vchiq_get_peer_version(service->handle, peer_version);
704 ret = vchiq_status_to_vchi(status);
708 EXPORT_SYMBOL(vchi_get_peer_version);
710 /***********************************************************
711 * Name: vchi_service_use
713 * Arguments: const struct vchi_service_handle *handle
715 * Description: Routine to increment refcount on a service
719 ***********************************************************/
720 int32_t vchi_service_use(const struct vchi_service_handle *handle)
724 struct shim_service *service = (struct shim_service *)handle;
726 ret = vchiq_status_to_vchi(vchiq_use_service(service->handle));
729 EXPORT_SYMBOL(vchi_service_use);
731 /***********************************************************
732 * Name: vchi_service_release
734 * Arguments: const struct vchi_service_handle *handle
736 * Description: Routine to decrement refcount on a service
740 ***********************************************************/
741 int32_t vchi_service_release(const struct vchi_service_handle *handle)
745 struct shim_service *service = (struct shim_service *)handle;
747 ret = vchiq_status_to_vchi(
748 vchiq_release_service(service->handle));
751 EXPORT_SYMBOL(vchi_service_release);