diff options
Diffstat (limited to 'drivers/staging/vc04_services/interface')
14 files changed, 216 insertions, 1506 deletions
diff --git a/drivers/staging/vc04_services/interface/vchi/TODO b/drivers/staging/vc04_services/interface/TODO index fc2752bc95b2..fc2752bc95b2 100644 --- a/drivers/staging/vc04_services/interface/vchi/TODO +++ b/drivers/staging/vc04_services/interface/TODO diff --git a/drivers/staging/vc04_services/interface/vchi/vchi.h b/drivers/staging/vc04_services/interface/vchi/vchi.h deleted file mode 100644 index 1a981e98e82b..000000000000 --- a/drivers/staging/vc04_services/interface/vchi/vchi.h +++ /dev/null @@ -1,159 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ -/* Copyright (c) 2010-2012 Broadcom. All rights reserved. */ - -#ifndef VCHI_H_ -#define VCHI_H_ - -#include "vchi_cfg.h" -#include "vchi_common.h" - -/****************************************************************************** - * Global defs - *****************************************************************************/ - -#define VCHI_BULK_ROUND_UP(x) ((((unsigned long)(x)) + VCHI_BULK_ALIGN - 1) & ~(VCHI_BULK_ALIGN - 1)) -#define VCHI_BULK_ROUND_DOWN(x) (((unsigned long)(x)) & ~(VCHI_BULK_ALIGN - 1)) -#define VCHI_BULK_ALIGN_NBYTES(x) (VCHI_BULK_ALIGNED(x) ? 0 : (VCHI_BULK_ALIGN - ((unsigned long)(x) & (VCHI_BULK_ALIGN - 1)))) - -#ifdef USE_VCHIQ_ARM -#define VCHI_BULK_ALIGNED(x) 1 -#else -#define VCHI_BULK_ALIGNED(x) (((unsigned long)(x) & (VCHI_BULK_ALIGN - 1)) == 0) -#endif - -struct vchi_version { - uint32_t version; - uint32_t version_min; -}; -#define VCHI_VERSION(v_) { v_, v_ } -#define VCHI_VERSION_EX(v_, m_) { v_, m_ } - -// Macros to manipulate 'FOURCC' values -#define MAKE_FOURCC(x) ((int32_t)((x[0] << 24) | (x[1] << 16) | (x[2] << 8) | x[3])) - -// Opaque service information -struct opaque_vchi_service_t; - -// Descriptor for a held message. Allocated by client, initialised by vchi_msg_hold, -// vchi_msg_iter_hold or vchi_msg_iter_hold_next. Fields are for internal VCHI use only. -struct vchi_held_msg { - struct opaque_vchi_service_t *service; - void *message; -}; - -// structure used to provide the information needed to open a server or a client -struct service_creation { - struct vchi_version version; - int32_t service_id; - vchi_callback callback; - void *callback_param; -}; - -// Opaque handle for a VCHI instance -struct vchi_instance_handle; - -// Opaque handle for a server or client -struct vchi_service_handle; - -/****************************************************************************** - * Global funcs - implementation is specific to which side you are on - * (local / remote) - *****************************************************************************/ - -// Routine used to initialise the vchi on both local + remote connections -extern int32_t vchi_initialise(struct vchi_instance_handle **instance_handle); - -extern int32_t vchi_connect(struct vchi_instance_handle *instance_handle); - -//When this is called, ensure that all services have no data pending. -//Bulk transfers can remain 'queued' -extern int32_t vchi_disconnect(struct vchi_instance_handle *instance_handle); - -/****************************************************************************** - * Global service API - *****************************************************************************/ -// Routine to open a named service -extern int32_t vchi_service_open(struct vchi_instance_handle *instance_handle, - struct service_creation *setup, - struct vchi_service_handle **handle); - -extern int32_t vchi_get_peer_version(const struct vchi_service_handle *handle, - short *peer_version); - -// Routine to close a named service -extern int32_t vchi_service_close(const struct vchi_service_handle *handle); - -// Routine to increment ref count on a named service -extern int32_t vchi_service_use(const struct vchi_service_handle *handle); - -// Routine to decrement ref count on a named service -extern int32_t vchi_service_release(const struct vchi_service_handle *handle); - -/* Routine to send a message from kernel memory across a service */ -extern int -vchi_queue_kernel_message(struct vchi_service_handle *handle, - void *data, - unsigned int size); - -// Routine to receive a msg from a service -// Dequeue is equivalent to hold, copy into client buffer, release -extern int32_t vchi_msg_dequeue(struct vchi_service_handle *handle, - void *data, - uint32_t max_data_size_to_read, - uint32_t *actual_msg_size, - enum vchi_flags flags); - -// Routine to look at a message in place. -// The message is not dequeued, so a subsequent call to peek or dequeue -// will return the same message. -extern int32_t vchi_msg_peek(struct vchi_service_handle *handle, - void **data, - uint32_t *msg_size, - enum vchi_flags flags); - -// Routine to remove a message after it has been read in place with peek -// The first message on the queue is dequeued. -extern int32_t vchi_msg_remove(struct vchi_service_handle *handle); - -// Routine to look at a message in place. -// The message is dequeued, so the caller is left holding it; the descriptor is -// filled in and must be released when the user has finished with the message. -extern int32_t vchi_msg_hold(struct vchi_service_handle *handle, - void **data, // } may be NULL, as info can be - uint32_t *msg_size, // } obtained from HELD_MSG_T - enum vchi_flags flags, - struct vchi_held_msg *message_descriptor); - -/******************************************************************************* - * Global service support API - operations on held messages - * and message iterators - ******************************************************************************/ - -// Routine to release a held message after it has been processed -extern int32_t vchi_held_msg_release(struct vchi_held_msg *message); - -/****************************************************************************** - * Global bulk API - *****************************************************************************/ - -// Routine to prepare interface for a transfer from the other side -extern int32_t vchi_bulk_queue_receive(struct vchi_service_handle *handle, - void *data_dst, - uint32_t data_size, - enum vchi_flags flags, - void *transfer_handle); - -// Routine to queue up data ready for transfer to the other (once they have signalled they are ready) -extern int32_t vchi_bulk_queue_transmit(struct vchi_service_handle *handle, - const void *data_src, - uint32_t data_size, - enum vchi_flags flags, - void *transfer_handle); - -/****************************************************************************** - * Configuration plumbing - *****************************************************************************/ - -#endif /* VCHI_H_ */ - -/****************************** End of file **********************************/ diff --git a/drivers/staging/vc04_services/interface/vchi/vchi_cfg.h b/drivers/staging/vc04_services/interface/vchi/vchi_cfg.h deleted file mode 100644 index 138c36151a22..000000000000 --- a/drivers/staging/vc04_services/interface/vchi/vchi_cfg.h +++ /dev/null @@ -1,238 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ -/* Copyright (c) 2010-2012 Broadcom. All rights reserved. */ - -#ifndef VCHI_CFG_H_ -#define VCHI_CFG_H_ - -/******************************************************************************* - * Defines in this first section are part of the VCHI API and may be examined by - * VCHI services. - ******************************************************************************/ - -/* - * Required alignment of base addresses for bulk transfer, if unaligned - * transfers are not enabled - * Really determined by the message driver, and should be available from - * a run-time call. - */ -#ifndef VCHI_BULK_ALIGN -# if __VCCOREVER__ >= 0x04000000 -# define VCHI_BULK_ALIGN 32 // Allows for the need to do cache cleans -# else -# define VCHI_BULK_ALIGN 16 -# endif -#endif - -/* - * Required length multiple for bulk transfers, if unaligned transfers are - * not enabled - * May be less than or greater than VCHI_BULK_ALIGN - * Really determined by the message driver, and should be available from - * a run-time call. - */ -#ifndef VCHI_BULK_GRANULARITY -# if __VCCOREVER__ >= 0x04000000 -# define VCHI_BULK_GRANULARITY 32 // Allows for the need to do cache cleans -# else -# define VCHI_BULK_GRANULARITY 16 -# endif -#endif - -/* The largest possible message to be queued with vchi_msg_queue. */ -#ifndef VCHI_MAX_MSG_SIZE -# if defined VCHI_LOCAL_HOST_PORT -# define VCHI_MAX_MSG_SIZE 16384 // makes file transfers fast, but should they be using bulk? -# else -# define VCHI_MAX_MSG_SIZE 4096 // NOTE: THIS MUST BE LARGER THAN OR EQUAL TO THE SIZE OF THE KHRONOS MERGE BUFFER!! -# endif -#endif - -/****************************************************************************** - * Defines below are system configuration options, and should not be used by - * VCHI services. - ******************************************************************************/ - -/* - * How many connections can we support? A localhost implementation uses - * 2 connections, 1 for host-app, 1 for VMCS, and these are hooked together - * by a loopback MPHI VCFW driver. - */ -#ifndef VCHI_MAX_NUM_CONNECTIONS -# define VCHI_MAX_NUM_CONNECTIONS 3 -#endif - -/* - * How many services can we open per connection? Extending this doesn't cost - * processing time, just a small amount of static memory. - */ -#ifndef VCHI_MAX_SERVICES_PER_CONNECTION -# define VCHI_MAX_SERVICES_PER_CONNECTION 36 -#endif - -/* Adjust if using a message driver that supports more logical TX channels */ -#ifndef VCHI_MAX_BULK_TX_CHANNELS_PER_CONNECTION -# define VCHI_MAX_BULK_TX_CHANNELS_PER_CONNECTION 9 // 1 MPHI + 8 CCP2 logical channels -#endif - -/* Adjust if using a message driver that supports more logical RX channels */ -#ifndef VCHI_MAX_BULK_RX_CHANNELS_PER_CONNECTION -# define VCHI_MAX_BULK_RX_CHANNELS_PER_CONNECTION 1 // 1 MPHI -#endif - -/* - * How many receive slots do we use. This times VCHI_MAX_MSG_SIZE gives the - * effective receive queue space, less message headers. - */ -#ifndef VCHI_NUM_READ_SLOTS -# if defined(VCHI_LOCAL_HOST_PORT) -# define VCHI_NUM_READ_SLOTS 4 -# else -# define VCHI_NUM_READ_SLOTS 48 -# endif -#endif - -/* - * Do we utilise overrun facility for receive message slots? Can aid peer - * transmit performance. Only define on VideoCore end, talking to host. - */ -//#define VCHI_MSG_RX_OVERRUN - -/* - * How many transmit slots do we use. Generally don't need many, - * as the hardware driver underneath VCHI will usually have its own buffering. - */ -#ifndef VCHI_NUM_WRITE_SLOTS -# define VCHI_NUM_WRITE_SLOTS 4 -#endif - -/* - * If a service has held or queued received messages in VCHI_XOFF_THRESHOLD or - * more slots, then it's taking up too much buffer space, - * and the peer service will be told to stop transmitting with an XOFF message. - * For this to be effective, the VCHI_NUM_READ_SLOTS needs to be considerably - * bigger than VCHI_NUM_WRITE_SLOTS, or the transmit latency is too high. - */ -#ifndef VCHI_XOFF_THRESHOLD -# define VCHI_XOFF_THRESHOLD (VCHI_NUM_READ_SLOTS / 2) -#endif - -/* - * After we've sent an XOFF, the peer will be told to resume transmission - * once the local service has dequeued/released enough messages that it's now - * occupying VCHI_XON_THRESHOLD slots or fewer. - */ -#ifndef VCHI_XON_THRESHOLD -# define VCHI_XON_THRESHOLD (VCHI_NUM_READ_SLOTS / 4) -#endif - -/* - * A size below which a bulk transfer omits the handshake completely and always - * goes via the message channel, if bulk auxiliary is being sent on that - * service. (The user can guarantee this by enabling unaligned transmits). - * Not API. - */ -#ifndef VCHI_MIN_BULK_SIZE -# define VCHI_MIN_BULK_SIZE (VCHI_MAX_MSG_SIZE / 2 < 4096 ? VCHI_MAX_MSG_SIZE / 2 : 4096) -#endif - -/* - * Maximum size of bulk transmission chunks, for each interface type. - * A trade-off between speed and latency; the smaller the chunk size the better - * change of messages and other bulk transmissions getting in when big bulk - * transfers are happening. Set to 0 to not break transmissions into chunks. - */ -#ifndef VCHI_MAX_BULK_CHUNK_SIZE_MPHI -# define VCHI_MAX_BULK_CHUNK_SIZE_MPHI (16 * 1024) -#endif - -/* - * NB Chunked CCP2 transmissions violate the letter of the CCP2 spec - * by using "JPEG8" mode with multiple-line frames. Only use if the receiver - * can cope. - */ -#ifndef VCHI_MAX_BULK_CHUNK_SIZE_CCP2 -# define VCHI_MAX_BULK_CHUNK_SIZE_CCP2 0 -#endif - -/* - * How many TX messages can we have pending in our transmit slots. - * Once exhausted, vchi_msg_queue will be blocked. - */ -#ifndef VCHI_TX_MSG_QUEUE_SIZE -# define VCHI_TX_MSG_QUEUE_SIZE 256 -#endif - -/* - * How many RX messages can we have parsed in the receive slots. Once exhausted, - * parsing will be suspended until older messages are dequeued/released. - */ -#ifndef VCHI_RX_MSG_QUEUE_SIZE -# define VCHI_RX_MSG_QUEUE_SIZE 256 -#endif - -/* - * Really should be able to cope if we run out of received message descriptors, - * by suspending parsing as the comment above says, but we don't. - * This sweeps the issue under the carpet. - */ -#if VCHI_RX_MSG_QUEUE_SIZE < (VCHI_MAX_MSG_SIZE / 16 + 1) * VCHI_NUM_READ_SLOTS -# undef VCHI_RX_MSG_QUEUE_SIZE -# define VCHI_RX_MSG_QUEUE_SIZE ((VCHI_MAX_MSG_SIZE / 16 + 1) * VCHI_NUM_READ_SLOTS) -#endif - -/* - * How many bulk transmits can we have pending. Once exhausted, - * vchi_bulk_queue_transmit will be blocked. - */ -#ifndef VCHI_TX_BULK_QUEUE_SIZE -# define VCHI_TX_BULK_QUEUE_SIZE 64 -#endif - -/* - * How many bulk receives can we have pending. Once exhausted, - *vchi_bulk_queue_receive will be blocked. - */ -#ifndef VCHI_RX_BULK_QUEUE_SIZE -# define VCHI_RX_BULK_QUEUE_SIZE 64 -#endif - -/* - * A limit on how many outstanding bulk requests we expect the peer to give us. - * If the peer asks for more than this, VCHI will fail and assert. - * The number is determined by the peer's hardware - * - it's the number of outstanding requests that can be queued - * on all bulk channels. VC3's MPHI peripheral allows 16. - */ -#ifndef VCHI_MAX_PEER_BULK_REQUESTS -# define VCHI_MAX_PEER_BULK_REQUESTS 32 -#endif - -/* - * Define VCHI_CCP2TX_MANUAL_POWER if the host tells us when to turn the CCP2 - * transmitter on and off. - */ -/*#define VCHI_CCP2TX_MANUAL_POWER*/ - -#ifndef VCHI_CCP2TX_MANUAL_POWER - -/* - * Timeout (in milliseconds) for putting the CCP2TX interface into IDLE state. - * Set negative for no IDLE. - */ -# ifndef VCHI_CCP2TX_IDLE_TIMEOUT -# define VCHI_CCP2TX_IDLE_TIMEOUT 5 -# endif - -/* - * Timeout (in milliseconds) for putting the CCP2TX interface into OFF state. - * Set negative for no OFF. - */ -# ifndef VCHI_CCP2TX_OFF_TIMEOUT -# define VCHI_CCP2TX_OFF_TIMEOUT 1000 -# endif - -#endif /* VCHI_CCP2TX_MANUAL_POWER */ - -#endif /* VCHI_CFG_H_ */ - -/****************************** End of file **********************************/ diff --git a/drivers/staging/vc04_services/interface/vchi/vchi_common.h b/drivers/staging/vc04_services/interface/vchi/vchi_common.h deleted file mode 100644 index 7fc04e38936d..000000000000 --- a/drivers/staging/vc04_services/interface/vchi/vchi_common.h +++ /dev/null @@ -1,138 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ -/* Copyright (c) 2010-2012 Broadcom. All rights reserved. */ - -#ifndef VCHI_COMMON_H_ -#define VCHI_COMMON_H_ - -//flags used when sending messages (must be bitmapped) -enum vchi_flags { - VCHI_FLAGS_NONE = 0x0, - VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE = 0x1, // waits for message to be received, or sent (NB. not the same as being seen on other side) - VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE = 0x2, // run a callback when message sent - VCHI_FLAGS_BLOCK_UNTIL_QUEUED = 0x4, // return once the transfer is in a queue ready to go - VCHI_FLAGS_ALLOW_PARTIAL = 0x8, - VCHI_FLAGS_BLOCK_UNTIL_DATA_READ = 0x10, - VCHI_FLAGS_CALLBACK_WHEN_DATA_READ = 0x20, - - VCHI_FLAGS_ALIGN_SLOT = 0x000080, // internal use only - VCHI_FLAGS_BULK_AUX_QUEUED = 0x010000, // internal use only - VCHI_FLAGS_BULK_AUX_COMPLETE = 0x020000, // internal use only - VCHI_FLAGS_BULK_DATA_QUEUED = 0x040000, // internal use only - VCHI_FLAGS_BULK_DATA_COMPLETE = 0x080000, // internal use only - VCHI_FLAGS_INTERNAL = 0xFF0000 -}; - -// constants for vchi_crc_control() -enum vchi_crc_control { - VCHI_CRC_NOTHING = -1, - VCHI_CRC_PER_SERVICE = 0, - VCHI_CRC_EVERYTHING = 1, -}; - -//callback reasons when an event occurs on a service -enum vchi_callback_reason { - VCHI_CALLBACK_REASON_MIN, - - /* - * This indicates that there is data available handle is the msg id that - * was transmitted with the data - * When a message is received and there was no FULL message available - * previously, send callback - * Tasks get kicked by the callback, reset their event and try and read - * from the fifo until it fails - */ - VCHI_CALLBACK_MSG_AVAILABLE, - VCHI_CALLBACK_MSG_SENT, - VCHI_CALLBACK_MSG_SPACE_AVAILABLE, // XXX not yet implemented - - // This indicates that a transfer from the other side has completed - VCHI_CALLBACK_BULK_RECEIVED, - //This indicates that data queued up to be sent has now gone - //handle is the msg id that was used when sending the data - VCHI_CALLBACK_BULK_SENT, - VCHI_CALLBACK_BULK_RX_SPACE_AVAILABLE, // XXX not yet implemented - VCHI_CALLBACK_BULK_TX_SPACE_AVAILABLE, // XXX not yet implemented - - VCHI_CALLBACK_SERVICE_CLOSED, - - /* - * this side has sent XOFF to peer due to lack of data consumption by - * service (suggests the service may need to take some recovery action - * if it has been deliberately holding off consuming data) - */ - VCHI_CALLBACK_SENT_XOFF, - VCHI_CALLBACK_SENT_XON, - - // indicates that a bulk transfer has finished reading the source buffer - VCHI_CALLBACK_BULK_DATA_READ, - - // power notification events (currently host side only) - VCHI_CALLBACK_PEER_OFF, - VCHI_CALLBACK_PEER_SUSPENDED, - VCHI_CALLBACK_PEER_ON, - VCHI_CALLBACK_PEER_RESUMED, - VCHI_CALLBACK_FORCED_POWER_OFF, - - // some extra notifications provided by vchiq_arm - VCHI_CALLBACK_SERVICE_OPENED, - VCHI_CALLBACK_BULK_RECEIVE_ABORTED, - VCHI_CALLBACK_BULK_TRANSMIT_ABORTED, - - VCHI_CALLBACK_REASON_MAX -}; - -// service control options -enum vchi_service_option { - VCHI_SERVICE_OPTION_MIN, - - VCHI_SERVICE_OPTION_TRACE, - VCHI_SERVICE_OPTION_SYNCHRONOUS, - - VCHI_SERVICE_OPTION_MAX -}; - -//Callback used by all services / bulk transfers -typedef void (*vchi_callback)(void *callback_param, //my service local param - enum vchi_callback_reason reason, - void *handle); //for transmitting msg's only - -/* - * Define vector struct for scatter-gather (vector) operations - * Vectors can be nested - if a vector element has negative length, then - * the data pointer is treated as pointing to another vector array, with - * '-vec_len' elements. Thus to append a header onto an existing vector, - * you can do this: - * - * void foo(const struct vchi_msg_vector *v, int n) - * { - * struct vchi_msg_vector nv[2]; - * nv[0].vec_base = my_header; - * nv[0].vec_len = sizeof my_header; - * nv[1].vec_base = v; - * nv[1].vec_len = -n; - * ... - * - */ -struct vchi_msg_vector { - const void *vec_base; - int32_t vec_len; -}; - -/* - * Iterator structure for reading ahead through received message queue. - * Allocated by client, initialised by vchi_msg_look_ahead. Fields are for - * internal VCHI use only. - * Iterates over messages in queue at the instant of the call to - * vchi_msg_lookahead - will not proceed to messages received since. - * Behaviour is undefined if an iterator is used again after messages for that - * service are removed/dequeued by any means other than vchi_msg_iter_... - * calls on the iterator itself. - */ -struct vchi_msg_iter { - struct opaque_vchi_service_t *service; - void *last; - void *next; - void *remove; -}; - -#endif // VCHI_COMMON_H_ diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq.h b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq.h deleted file mode 100644 index 25af99a0f394..000000000000 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq.h +++ /dev/null @@ -1,21 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ -/* Copyright (c) 2010-2012 Broadcom. All rights reserved. */ - -#ifndef VCHIQ_VCHIQ_H -#define VCHIQ_VCHIQ_H - -#include "vchiq_if.h" -#include "vchiq_util.h" - -/* Do this so that we can test-build the code on non-rpi systems */ -#if IS_ENABLED(CONFIG_RASPBERRYPI_FIRMWARE) - -#else - -#ifndef dsb -#define dsb(a) -#endif - -#endif /* IS_ENABLED(CONFIG_RASPBERRYPI_FIRMWARE) */ - -#endif diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c index 38a13e4618a8..5ed36d557014 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c @@ -12,6 +12,7 @@ #include <linux/uaccess.h> #include <linux/mm.h> #include <linux/of.h> +#include <linux/slab.h> #include <soc/bcm2835/raspberrypi-firmware.h> #define TOTAL_SLOTS (VCHIQ_SLOT_ZERO_SLOTS + 2 * 32) @@ -287,12 +288,8 @@ cleanup_pagelistinfo(struct vchiq_pagelist_info *pagelistinfo) pagelistinfo->num_pages, pagelistinfo->dma_dir); } - if (pagelistinfo->pages_need_release) { - unsigned int i; - - for (i = 0; i < pagelistinfo->num_pages; i++) - put_page(pagelistinfo->pages[i]); - } + if (pagelistinfo->pages_need_release) + unpin_user_pages(pagelistinfo->pages, pagelistinfo->num_pages); dma_free_coherent(g_dev, pagelistinfo->pagelist_buffer_size, pagelistinfo->pagelist, pagelistinfo->dma_addr); @@ -395,7 +392,7 @@ create_pagelist(char __user *buf, size_t count, unsigned short type) } /* do not try and release vmalloc pages */ } else { - actual_pages = get_user_pages_fast( + actual_pages = pin_user_pages_fast( (unsigned long)buf & PAGE_MASK, num_pages, type == PAGELIST_READ, @@ -407,10 +404,8 @@ create_pagelist(char __user *buf, size_t count, unsigned short type) __func__, actual_pages, num_pages); /* This is probably due to the process being killed */ - while (actual_pages > 0) { - actual_pages--; - put_page(pages[actual_pages]); - } + if (actual_pages > 0) + unpin_user_pages(pages, actual_pages); cleanup_pagelistinfo(pagelistinfo); return NULL; } diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c index 28ea8c3a4cba..d4d811884861 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c @@ -23,6 +23,8 @@ #include <linux/compat.h> #include <linux/dma-mapping.h> #include <linux/rcupdate.h> +#include <linux/delay.h> +#include <linux/slab.h> #include <soc/bcm2835/raspberrypi-firmware.h> #include "vchiq_core.h" @@ -269,7 +271,7 @@ failed: } EXPORT_SYMBOL(vchiq_connect); -enum vchiq_status vchiq_add_service( +static enum vchiq_status vchiq_add_service( struct vchiq_instance *instance, const struct vchiq_service_params *params, unsigned int *phandle) @@ -306,7 +308,6 @@ enum vchiq_status vchiq_add_service( return status; } -EXPORT_SYMBOL(vchiq_add_service); enum vchiq_status vchiq_open_service( struct vchiq_instance *instance, @@ -354,43 +355,67 @@ vchiq_bulk_transmit(unsigned int handle, const void *data, { enum vchiq_status status; - switch (mode) { - case VCHIQ_BULK_MODE_NOCALLBACK: - case VCHIQ_BULK_MODE_CALLBACK: - status = vchiq_bulk_transfer(handle, (void *)data, size, - userdata, mode, - VCHIQ_BULK_TRANSMIT); - break; - case VCHIQ_BULK_MODE_BLOCKING: - status = vchiq_blocking_bulk_transfer(handle, - (void *)data, size, VCHIQ_BULK_TRANSMIT); - break; - default: - return VCHIQ_ERROR; + while (1) { + switch (mode) { + case VCHIQ_BULK_MODE_NOCALLBACK: + case VCHIQ_BULK_MODE_CALLBACK: + status = vchiq_bulk_transfer(handle, (void *)data, size, + userdata, mode, + VCHIQ_BULK_TRANSMIT); + break; + case VCHIQ_BULK_MODE_BLOCKING: + status = vchiq_blocking_bulk_transfer(handle, + (void *)data, size, VCHIQ_BULK_TRANSMIT); + break; + default: + return VCHIQ_ERROR; + } + + /* + * vchiq_*_bulk_transfer() may return VCHIQ_RETRY, so we need + * to implement a retry mechanism since this function is + * supposed to block until queued + */ + if (status != VCHIQ_RETRY) + break; + + msleep(1); } return status; } EXPORT_SYMBOL(vchiq_bulk_transmit); -enum vchiq_status -vchiq_bulk_receive(unsigned int handle, void *data, - unsigned int size, void *userdata, enum vchiq_bulk_mode mode) +enum vchiq_status vchiq_bulk_receive(unsigned int handle, void *data, + unsigned int size, void *userdata, + enum vchiq_bulk_mode mode) { enum vchiq_status status; - switch (mode) { - case VCHIQ_BULK_MODE_NOCALLBACK: - case VCHIQ_BULK_MODE_CALLBACK: - status = vchiq_bulk_transfer(handle, data, size, userdata, - mode, VCHIQ_BULK_RECEIVE); - break; - case VCHIQ_BULK_MODE_BLOCKING: - status = vchiq_blocking_bulk_transfer(handle, - (void *)data, size, VCHIQ_BULK_RECEIVE); - break; - default: - return VCHIQ_ERROR; + while (1) { + switch (mode) { + case VCHIQ_BULK_MODE_NOCALLBACK: + case VCHIQ_BULK_MODE_CALLBACK: + status = vchiq_bulk_transfer(handle, data, size, userdata, + mode, VCHIQ_BULK_RECEIVE); + break; + case VCHIQ_BULK_MODE_BLOCKING: + status = vchiq_blocking_bulk_transfer(handle, + (void *)data, size, VCHIQ_BULK_RECEIVE); + break; + default: + return VCHIQ_ERROR; + } + + /* + * vchiq_*_bulk_transfer() may return VCHIQ_RETRY, so we need + * to implement a retry mechanism since this function is + * supposed to block until queued + */ + if (status != VCHIQ_RETRY) + break; + + msleep(1); } return status; @@ -2547,6 +2572,7 @@ vchiq_use_service(unsigned int handle) } return ret; } +EXPORT_SYMBOL(vchiq_use_service); enum vchiq_status vchiq_release_service(unsigned int handle) @@ -2560,6 +2586,7 @@ vchiq_release_service(unsigned int handle) } return ret; } +EXPORT_SYMBOL(vchiq_release_service); struct service_data_struct { int fourcc; @@ -2805,6 +2832,7 @@ failed_platform_init: static int vchiq_remove(struct platform_device *pdev) { + platform_device_unregister(bcm2835_audio); platform_device_unregister(bcm2835_camera); vchiq_debugfs_deinit(); device_destroy(vchiq_class, vchiq_devid); diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c index ae9183db44ee..5a361e8e7c6c 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c @@ -1,8 +1,17 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* Copyright (c) 2010-2012 Broadcom. All rights reserved. */ +#include <linux/types.h> +#include <linux/completion.h> +#include <linux/mutex.h> +#include <linux/bitops.h> +#include <linux/kthread.h> +#include <linux/wait.h> +#include <linux/delay.h> +#include <linux/slab.h> #include <linux/kref.h> #include <linux/rcupdate.h> +#include <linux/sched/signal.h> #include "vchiq_core.h" @@ -39,9 +48,9 @@ struct vchiq_openack_payload { }; enum { - QMFLAGS_IS_BLOCKING = (1 << 0), - QMFLAGS_NO_MUTEX_LOCK = (1 << 1), - QMFLAGS_NO_MUTEX_UNLOCK = (1 << 2) + QMFLAGS_IS_BLOCKING = BIT(0), + QMFLAGS_NO_MUTEX_LOCK = BIT(1), + QMFLAGS_NO_MUTEX_UNLOCK = BIT(2) }; /* we require this for consistency between endpoints */ @@ -323,6 +332,7 @@ vchiq_get_service_userdata(unsigned int handle) rcu_read_unlock(); return userdata; } +EXPORT_SYMBOL(vchiq_get_service_userdata); static void mark_service_closing_internal(struct vchiq_service *service, int sh_thread) @@ -526,14 +536,14 @@ request_poll(struct vchiq_state *state, struct vchiq_service *service, do { value = atomic_read(&service->poll_flags); } while (atomic_cmpxchg(&service->poll_flags, value, - value | (1 << poll_type)) != value); + value | BIT(poll_type)) != value); do { value = atomic_read(&state->poll_services[ service->localport>>5]); } while (atomic_cmpxchg( &state->poll_services[service->localport>>5], - value, value | (1 << (service->localport & 0x1f))) + value, value | BIT(service->localport & 0x1f)) != value); } @@ -1287,19 +1297,19 @@ poll_services(struct vchiq_state *state) flags = atomic_xchg(&state->poll_services[group], 0); for (i = 0; flags; i++) { - if (flags & (1 << i)) { + if (flags & BIT(i)) { struct vchiq_service *service = find_service_by_port(state, (group<<5) + i); u32 service_flags; - flags &= ~(1 << i); + flags &= ~BIT(i); if (!service) continue; service_flags = atomic_xchg(&service->poll_flags, 0); if (service_flags & - (1 << VCHIQ_POLL_REMOVE)) { + BIT(VCHIQ_POLL_REMOVE)) { vchiq_log_info(vchiq_core_log_level, "%d: ps - remove %d<->%d", state->id, service->localport, @@ -1317,7 +1327,7 @@ poll_services(struct vchiq_state *state) request_poll(state, service, VCHIQ_POLL_REMOVE); } else if (service_flags & - (1 << VCHIQ_POLL_TERMINATE)) { + BIT(VCHIQ_POLL_TERMINATE)) { vchiq_log_info(vchiq_core_log_level, "%d: ps - terminate %d<->%d", state->id, service->localport, @@ -1328,11 +1338,11 @@ poll_services(struct vchiq_state *state) request_poll(state, service, VCHIQ_POLL_TERMINATE); } - if (service_flags & (1 << VCHIQ_POLL_TXNOTIFY)) + if (service_flags & BIT(VCHIQ_POLL_TXNOTIFY)) notify_bulks(service, &service->bulk_tx, 1/*retry_poll*/); - if (service_flags & (1 << VCHIQ_POLL_RXNOTIFY)) + if (service_flags & BIT(VCHIQ_POLL_RXNOTIFY)) notify_bulks(service, &service->bulk_rx, 1/*retry_poll*/); @@ -2265,6 +2275,57 @@ fail_free_handler_thread: return VCHIQ_ERROR; } +void vchiq_msg_queue_push(unsigned int handle, struct vchiq_header *header) +{ + struct vchiq_service *service = find_service_by_handle(handle); + int pos; + + while (service->msg_queue_write == service->msg_queue_read + + VCHIQ_MAX_SLOTS) { + if (wait_for_completion_interruptible(&service->msg_queue_pop)) + flush_signals(current); + } + + pos = service->msg_queue_write++ & (VCHIQ_MAX_SLOTS - 1); + service->msg_queue[pos] = header; + + complete(&service->msg_queue_push); +} +EXPORT_SYMBOL(vchiq_msg_queue_push); + +struct vchiq_header *vchiq_msg_hold(unsigned int handle) +{ + struct vchiq_service *service = find_service_by_handle(handle); + struct vchiq_header *header; + int pos; + + if (service->msg_queue_write == service->msg_queue_read) + return NULL; + + while (service->msg_queue_write == service->msg_queue_read) { + if (wait_for_completion_interruptible(&service->msg_queue_push)) + flush_signals(current); + } + + pos = service->msg_queue_read++ & (VCHIQ_MAX_SLOTS - 1); + header = service->msg_queue[pos]; + + complete(&service->msg_queue_pop); + + return header; +} +EXPORT_SYMBOL(vchiq_msg_hold); + +static int vchiq_validate_params(const struct vchiq_service_params *params) +{ + if (!params->callback || !params->fourcc) { + vchiq_loud_error("Can't add service, invalid params\n"); + return -EINVAL; + } + + return 0; +} + /* Called from application thread when a client or server service is created. */ struct vchiq_service * vchiq_add_service_internal(struct vchiq_state *state, @@ -2275,8 +2336,13 @@ vchiq_add_service_internal(struct vchiq_state *state, struct vchiq_service *service; struct vchiq_service __rcu **pservice = NULL; struct vchiq_service_quota *service_quota; + int ret; int i; + ret = vchiq_validate_params(params); + if (ret) + return NULL; + service = kmalloc(sizeof(*service), GFP_KERNEL); if (!service) return service; @@ -2304,12 +2370,17 @@ vchiq_add_service_internal(struct vchiq_state *state, service->state = state; service->instance = instance; service->service_use_count = 0; + service->msg_queue_read = 0; + service->msg_queue_write = 0; init_bulk_queue(&service->bulk_tx); init_bulk_queue(&service->bulk_rx); init_completion(&service->remove_event); init_completion(&service->bulk_remove_event); + init_completion(&service->msg_queue_pop); + init_completion(&service->msg_queue_push); mutex_init(&service->bulk_mutex); memset(&service->stats, 0, sizeof(service->stats)); + memset(&service->msg_queue, 0, sizeof(service->msg_queue)); /* Although it is perfectly possible to use a spinlock ** to protect the creation of services, it is overkill as it @@ -2639,7 +2710,7 @@ vchiq_close_service_internal(struct vchiq_service *service, int close_recvd) case VCHIQ_SRVSTATE_OPENSYNC: mutex_lock(&state->sync_mutex); - /* fall through */ + fallthrough; case VCHIQ_SRVSTATE_OPEN: if (close_recvd) { if (!do_abort_bulks(service)) @@ -2875,6 +2946,7 @@ vchiq_close_service(unsigned int handle) return status; } +EXPORT_SYMBOL(vchiq_close_service); enum vchiq_status vchiq_remove_service(unsigned int handle) @@ -3142,11 +3214,28 @@ error_exit: return status; } -enum vchiq_status vchiq_queue_kernel_message(unsigned int handle, void *context, - size_t size) +int vchiq_queue_kernel_message(unsigned int handle, void *data, unsigned int size) { - return vchiq_queue_message(handle, memcpy_copy_callback, context, size); + enum vchiq_status status; + + while (1) { + status = vchiq_queue_message(handle, memcpy_copy_callback, + data, size); + + /* + * vchiq_queue_message() may return VCHIQ_RETRY, so we need to + * implement a retry mechanism since this function is supposed + * to block until queued + */ + if (status != VCHIQ_RETRY) + break; + + msleep(1); + } + + return status; } +EXPORT_SYMBOL(vchiq_queue_kernel_message); void vchiq_release_message(unsigned int handle, @@ -3180,6 +3269,7 @@ vchiq_release_message(unsigned int handle, unlock_service(service); } +EXPORT_SYMBOL(vchiq_release_message); static void release_message_sync(struct vchiq_state *state, struct vchiq_header *header) @@ -3206,6 +3296,7 @@ exit: unlock_service(service); return status; } +EXPORT_SYMBOL(vchiq_get_peer_version); void vchiq_get_config(struct vchiq_config *config) { diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h index 1fe6cd8b86c0..e67692879249 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h @@ -10,10 +10,26 @@ #include <linux/kref.h> #include <linux/rcupdate.h> #include <linux/wait.h> +#include <linux/raspberrypi/vchiq.h> #include "vchiq_cfg.h" -#include "vchiq.h" + +/* Do this so that we can test-build the code on non-rpi systems */ +#if IS_ENABLED(CONFIG_RASPBERRYPI_FIRMWARE) + +#else + +#ifndef dsb +#define dsb(a) +#endif + +#endif /* IS_ENABLED(CONFIG_RASPBERRYPI_FIRMWARE) */ + +#define VCHIQ_SERVICE_HANDLE_INVALID 0 + +#define VCHIQ_SLOT_SIZE 4096 +#define VCHIQ_MAX_MSG_SIZE (VCHIQ_SLOT_SIZE - sizeof(struct vchiq_header)) /* Run time control of log level, based on KERN_XXX level. */ #define VCHIQ_LOG_DEFAULT 4 @@ -297,6 +313,12 @@ struct vchiq_service { uint64_t bulk_tx_bytes; uint64_t bulk_rx_bytes; } stats; + + int msg_queue_read; + int msg_queue_write; + struct completion msg_queue_pop; + struct completion msg_queue_push; + struct vchiq_header *msg_queue[VCHIQ_MAX_SLOTS]; }; /* The quota information is outside struct vchiq_service so that it can @@ -480,6 +502,18 @@ struct bulk_waiter { int actual; }; +struct vchiq_config { + unsigned int max_msg_size; + unsigned int bulk_threshold; /* The message size above which it + is better to use a bulk transfer + (<= max_msg_size) */ + unsigned int max_outstanding_bulks; + unsigned int max_services; + short version; /* The version of VCHIQ */ + short version_min; /* The minimum compatible version of VCHIQ */ +}; + + extern spinlock_t bulk_waiter_spinlock; extern int vchiq_core_log_level; @@ -659,4 +693,14 @@ extern void vchiq_log_dump_mem(const char *label, uint32_t addr, const void *voidMem, size_t numBytes); +extern enum vchiq_status vchiq_remove_service(unsigned int service); + +extern int vchiq_get_client_id(unsigned int service); + +extern void vchiq_get_config(struct vchiq_config *config); + +extern enum vchiq_status +vchiq_set_service_option(unsigned int service, enum vchiq_service_option option, + int value); + #endif diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_if.h b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_if.h deleted file mode 100644 index b62fd6d6f1ac..000000000000 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_if.h +++ /dev/null @@ -1,140 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ -/* Copyright (c) 2010-2012 Broadcom. All rights reserved. */ - -#ifndef VCHIQ_IF_H -#define VCHIQ_IF_H - -#define VCHIQ_SERVICE_HANDLE_INVALID 0 - -#define VCHIQ_SLOT_SIZE 4096 -#define VCHIQ_MAX_MSG_SIZE (VCHIQ_SLOT_SIZE - sizeof(struct vchiq_header)) -#define VCHIQ_CHANNEL_SIZE VCHIQ_MAX_MSG_SIZE /* For backwards compatibility */ - -#define VCHIQ_MAKE_FOURCC(x0, x1, x2, x3) \ - (((x0) << 24) | ((x1) << 16) | ((x2) << 8) | (x3)) -#define VCHIQ_GET_SERVICE_USERDATA(service) vchiq_get_service_userdata(service) - -enum vchiq_reason { - VCHIQ_SERVICE_OPENED, /* service, -, - */ - VCHIQ_SERVICE_CLOSED, /* service, -, - */ - VCHIQ_MESSAGE_AVAILABLE, /* service, header, - */ - VCHIQ_BULK_TRANSMIT_DONE, /* service, -, bulk_userdata */ - VCHIQ_BULK_RECEIVE_DONE, /* service, -, bulk_userdata */ - VCHIQ_BULK_TRANSMIT_ABORTED, /* service, -, bulk_userdata */ - VCHIQ_BULK_RECEIVE_ABORTED /* service, -, bulk_userdata */ -}; - -enum vchiq_status { - VCHIQ_ERROR = -1, - VCHIQ_SUCCESS = 0, - VCHIQ_RETRY = 1 -}; - -enum vchiq_bulk_mode { - VCHIQ_BULK_MODE_CALLBACK, - VCHIQ_BULK_MODE_BLOCKING, - VCHIQ_BULK_MODE_NOCALLBACK, - VCHIQ_BULK_MODE_WAITING /* Reserved for internal use */ -}; - -enum vchiq_service_option { - VCHIQ_SERVICE_OPTION_AUTOCLOSE, - VCHIQ_SERVICE_OPTION_SLOT_QUOTA, - VCHIQ_SERVICE_OPTION_MESSAGE_QUOTA, - VCHIQ_SERVICE_OPTION_SYNCHRONOUS, - VCHIQ_SERVICE_OPTION_TRACE -}; - -struct vchiq_header { - /* The message identifier - opaque to applications. */ - int msgid; - - /* Size of message data. */ - unsigned int size; - - char data[0]; /* message */ -}; - -struct vchiq_element { - const void __user *data; - unsigned int size; -}; - -typedef enum vchiq_status (*vchiq_callback)(enum vchiq_reason, - struct vchiq_header *, - unsigned int, void *); - -struct vchiq_service_base { - int fourcc; - vchiq_callback callback; - void *userdata; -}; - -struct vchiq_service_params { - int fourcc; - vchiq_callback callback; - void *userdata; - short version; /* Increment for non-trivial changes */ - short version_min; /* Update for incompatible changes */ -}; - -struct vchiq_config { - unsigned int max_msg_size; - unsigned int bulk_threshold; /* The message size above which it - is better to use a bulk transfer - (<= max_msg_size) */ - unsigned int max_outstanding_bulks; - unsigned int max_services; - short version; /* The version of VCHIQ */ - short version_min; /* The minimum compatible version of VCHIQ */ -}; - -struct vchiq_instance; -typedef void (*vchiq_remote_callback)(void *cb_arg); - -extern enum vchiq_status vchiq_initialise(struct vchiq_instance **pinstance); -extern enum vchiq_status vchiq_shutdown(struct vchiq_instance *instance); -extern enum vchiq_status vchiq_connect(struct vchiq_instance *instance); -extern enum vchiq_status vchiq_add_service(struct vchiq_instance *instance, - const struct vchiq_service_params *params, - unsigned int *pservice); -extern enum vchiq_status vchiq_open_service(struct vchiq_instance *instance, - const struct vchiq_service_params *params, - unsigned int *pservice); -extern enum vchiq_status vchiq_close_service(unsigned int service); -extern enum vchiq_status vchiq_remove_service(unsigned int service); -extern enum vchiq_status vchiq_use_service(unsigned int service); -extern enum vchiq_status vchiq_release_service(unsigned int service); -extern enum vchiq_status vchiq_queue_kernel_message(unsigned int handle, - void *context, size_t size); -extern void vchiq_release_message(unsigned int service, - struct vchiq_header *header); -extern enum vchiq_status vchiq_bulk_transmit(unsigned int service, - const void *data, unsigned int size, void *userdata, - enum vchiq_bulk_mode mode); -extern enum vchiq_status vchiq_bulk_receive(unsigned int service, - void *data, unsigned int size, void *userdata, - enum vchiq_bulk_mode mode); -extern enum vchiq_status vchiq_bulk_transmit_handle(unsigned int service, - const void *offset, unsigned int size, - void *userdata, enum vchiq_bulk_mode mode); -extern enum vchiq_status vchiq_bulk_receive_handle(unsigned int service, - void *offset, unsigned int size, void *userdata, - enum vchiq_bulk_mode mode); -extern int vchiq_get_client_id(unsigned int service); -extern void *vchiq_get_service_userdata(unsigned int service); -extern void vchiq_get_config(struct vchiq_config *config); -extern enum vchiq_status vchiq_set_service_option(unsigned int service, - enum vchiq_service_option option, int value); - -extern enum vchiq_status vchiq_remote_use(struct vchiq_instance *instance, - vchiq_remote_callback callback, void *cb_arg); -extern enum vchiq_status vchiq_remote_release(struct vchiq_instance *instance); - -extern enum vchiq_status vchiq_dump_phys_mem(unsigned int service, - void *ptr, size_t num_bytes); - -extern enum vchiq_status vchiq_get_peer_version(unsigned int handle, - short *peer_version); - -#endif /* VCHIQ_IF_H */ diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_ioctl.h b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_ioctl.h index 202889b3774f..3653fd99d8a1 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_ioctl.h +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_ioctl.h @@ -5,7 +5,7 @@ #define VCHIQ_IOCTLS_H #include <linux/ioctl.h> -#include "vchiq_if.h" +#include <linux/raspberrypi/vchiq.h> #define VCHIQ_IOC_MAGIC 0xc4 #define VCHIQ_INVALID_HANDLE (~0) diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_shim.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_shim.c deleted file mode 100644 index 75d87b6992c4..000000000000 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_shim.c +++ /dev/null @@ -1,617 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause -/* Copyright (c) 2010-2012 Broadcom. All rights reserved. */ -#include <linux/module.h> -#include <linux/types.h> - -#include "../vchi/vchi.h" -#include "vchiq.h" -#include "vchiq_core.h" - -#include "vchiq_util.h" - -struct shim_service { - unsigned int handle; - - struct vchiu_queue queue; - - vchi_callback callback; - void *callback_param; -}; - -/*********************************************************** - * Name: vchi_msg_peek - * - * Arguments: struct vchi_service_handle *handle, - * void **data, - * uint32_t *msg_size, - - * enum vchi_flags flags - * - * Description: Routine to return a pointer to the current message (to allow in - * place processing). The message can be removed using - * vchi_msg_remove when you're finished - * - * Returns: int32_t - success == 0 - * - ***********************************************************/ -int32_t vchi_msg_peek(struct vchi_service_handle *handle, - void **data, - uint32_t *msg_size, - enum vchi_flags flags) -{ - struct shim_service *service = (struct shim_service *)handle; - struct vchiq_header *header; - - WARN_ON((flags != VCHI_FLAGS_NONE) && - (flags != VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE)); - - if (flags == VCHI_FLAGS_NONE) - if (vchiu_queue_is_empty(&service->queue)) - return -1; - - header = vchiu_queue_peek(&service->queue); - - *data = header->data; - *msg_size = header->size; - - return 0; -} -EXPORT_SYMBOL(vchi_msg_peek); - -/*********************************************************** - * Name: vchi_msg_remove - * - * Arguments: struct vchi_service_handle *handle, - * - * Description: Routine to remove a message (after it has been read with - * vchi_msg_peek) - * - * Returns: int32_t - success == 0 - * - ***********************************************************/ -int32_t vchi_msg_remove(struct vchi_service_handle *handle) -{ - struct shim_service *service = (struct shim_service *)handle; - struct vchiq_header *header; - - header = vchiu_queue_pop(&service->queue); - - vchiq_release_message(service->handle, header); - - return 0; -} -EXPORT_SYMBOL(vchi_msg_remove); - -int vchi_queue_kernel_message(struct vchi_service_handle *handle, void *data, - unsigned int size) -{ - struct shim_service *service = (struct shim_service *)handle; - enum vchiq_status status; - - while (1) { - status = vchiq_queue_kernel_message(service->handle, data, - size); - - /* - * vchiq_queue_message() may return VCHIQ_RETRY, so we need to - * implement a retry mechanism since this function is supposed - * to block until queued - */ - if (status != VCHIQ_RETRY) - break; - - msleep(1); - } - - return status; -} -EXPORT_SYMBOL(vchi_queue_kernel_message); - -/*********************************************************** - * Name: vchi_bulk_queue_receive - * - * Arguments: VCHI_BULK_HANDLE_T handle, - * void *data_dst, - * const uint32_t data_size, - * enum vchi_flags flags - * void *bulk_handle - * - * Description: Routine to setup a rcv buffer - * - * Returns: int32_t - success == 0 - * - ***********************************************************/ -int32_t vchi_bulk_queue_receive(struct vchi_service_handle *handle, void *data_dst, - uint32_t data_size, enum vchi_flags flags, - void *bulk_handle) -{ - struct shim_service *service = (struct shim_service *)handle; - enum vchiq_bulk_mode mode; - enum vchiq_status status; - - switch ((int)flags) { - case VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE - | VCHI_FLAGS_BLOCK_UNTIL_QUEUED: - WARN_ON(!service->callback); - mode = VCHIQ_BULK_MODE_CALLBACK; - break; - case VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE: - mode = VCHIQ_BULK_MODE_BLOCKING; - break; - case VCHI_FLAGS_BLOCK_UNTIL_QUEUED: - case VCHI_FLAGS_NONE: - mode = VCHIQ_BULK_MODE_NOCALLBACK; - break; - default: - WARN(1, "unsupported message\n"); - return VCHIQ_ERROR; - } - - while (1) { - status = vchiq_bulk_receive(service->handle, data_dst, - data_size, bulk_handle, mode); - /* - * vchiq_bulk_receive() may return VCHIQ_RETRY, so we need to - * implement a retry mechanism since this function is supposed - * to block until queued - */ - if (status != VCHIQ_RETRY) - break; - - msleep(1); - } - - return status; -} -EXPORT_SYMBOL(vchi_bulk_queue_receive); - -/*********************************************************** - * Name: vchi_bulk_queue_transmit - * - * Arguments: VCHI_BULK_HANDLE_T handle, - * const void *data_src, - * uint32_t data_size, - * enum vchi_flags flags, - * void *bulk_handle - * - * Description: Routine to transmit some data - * - * Returns: int32_t - success == 0 - * - ***********************************************************/ -int32_t vchi_bulk_queue_transmit(struct vchi_service_handle *handle, - const void *data_src, - uint32_t data_size, - enum vchi_flags flags, - void *bulk_handle) -{ - struct shim_service *service = (struct shim_service *)handle; - enum vchiq_bulk_mode mode; - enum vchiq_status status; - - switch ((int)flags) { - case VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE - | VCHI_FLAGS_BLOCK_UNTIL_QUEUED: - WARN_ON(!service->callback); - mode = VCHIQ_BULK_MODE_CALLBACK; - break; - case VCHI_FLAGS_BLOCK_UNTIL_DATA_READ: - case VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE: - mode = VCHIQ_BULK_MODE_BLOCKING; - break; - case VCHI_FLAGS_BLOCK_UNTIL_QUEUED: - case VCHI_FLAGS_NONE: - mode = VCHIQ_BULK_MODE_NOCALLBACK; - break; - default: - WARN(1, "unsupported message\n"); - return VCHIQ_ERROR; - } - - while (1) { - status = vchiq_bulk_transmit(service->handle, data_src, - data_size, bulk_handle, mode); - - /* - * vchiq_bulk_transmit() may return VCHIQ_RETRY, so we need to - * implement a retry mechanism since this function is supposed - * to block until queued - */ - if (status != VCHIQ_RETRY) - break; - - msleep(1); - } - - return status; -} -EXPORT_SYMBOL(vchi_bulk_queue_transmit); - -/*********************************************************** - * Name: vchi_msg_dequeue - * - * Arguments: struct vchi_service_handle *handle, - * void *data, - * uint32_t max_data_size_to_read, - * uint32_t *actual_msg_size - * enum vchi_flags flags - * - * Description: Routine to dequeue a message into the supplied buffer - * - * Returns: int32_t - success == 0 - * - ***********************************************************/ -int32_t vchi_msg_dequeue(struct vchi_service_handle *handle, void *data, - uint32_t max_data_size_to_read, - uint32_t *actual_msg_size, enum vchi_flags flags) -{ - struct shim_service *service = (struct shim_service *)handle; - struct vchiq_header *header; - - WARN_ON((flags != VCHI_FLAGS_NONE) && - (flags != VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE)); - - if (flags == VCHI_FLAGS_NONE) - if (vchiu_queue_is_empty(&service->queue)) - return -1; - - header = vchiu_queue_pop(&service->queue); - - memcpy(data, header->data, header->size < max_data_size_to_read ? - header->size : max_data_size_to_read); - - *actual_msg_size = header->size; - - vchiq_release_message(service->handle, header); - - return 0; -} -EXPORT_SYMBOL(vchi_msg_dequeue); - -/*********************************************************** - * Name: vchi_held_msg_release - * - * Arguments: struct vchi_held_msg *message - * - * Description: Routine to release a held message (after it has been read with - * vchi_msg_hold) - * - * Returns: int32_t - success == 0 - * - ***********************************************************/ -int32_t vchi_held_msg_release(struct vchi_held_msg *message) -{ - /* - * Convert the service field pointer back to an - * unsigned int which is an int. - * This pointer is opaque to everything except - * vchi_msg_hold which simply upcasted the int - * to a pointer. - */ - - vchiq_release_message((unsigned int)(long)message->service, - (struct vchiq_header *)message->message); - - return 0; -} -EXPORT_SYMBOL(vchi_held_msg_release); - -/*********************************************************** - * Name: vchi_msg_hold - * - * Arguments: struct vchi_service_handle *handle, - * void **data, - * uint32_t *msg_size, - * enum vchi_flags flags, - * struct vchi_held_msg *message_handle - * - * Description: Routine to return a pointer to the current message (to allow - * in place processing). The message is dequeued - don't forget - * to release the message using vchi_held_msg_release when you're - * finished. - * - * Returns: int32_t - success == 0 - * - ***********************************************************/ -int32_t vchi_msg_hold(struct vchi_service_handle *handle, void **data, - uint32_t *msg_size, enum vchi_flags flags, - struct vchi_held_msg *message_handle) -{ - struct shim_service *service = (struct shim_service *)handle; - struct vchiq_header *header; - - WARN_ON((flags != VCHI_FLAGS_NONE) && - (flags != VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE)); - - if (flags == VCHI_FLAGS_NONE) - if (vchiu_queue_is_empty(&service->queue)) - return -1; - - header = vchiu_queue_pop(&service->queue); - - *data = header->data; - *msg_size = header->size; - - /* - * upcast the unsigned int which is an int - * to a pointer and stuff it in the held message. - * This pointer is opaque to everything except - * vchi_held_msg_release which simply downcasts it back - * to an int. - */ - - message_handle->service = - (struct opaque_vchi_service_t *)(long)service->handle; - message_handle->message = header; - - return 0; -} -EXPORT_SYMBOL(vchi_msg_hold); - -/*********************************************************** - * Name: vchi_initialise - * - * Arguments: struct vchi_instance_handle **instance_handle - * - * Description: Initialises the hardware but does not transmit anything - * When run as a Host App this will be called twice hence the need - * to malloc the state information - * - * Returns: 0 if successful, failure otherwise - * - ***********************************************************/ - -int32_t vchi_initialise(struct vchi_instance_handle **instance_handle) -{ - struct vchiq_instance *instance; - enum vchiq_status status; - - status = vchiq_initialise(&instance); - - *instance_handle = (struct vchi_instance_handle *)instance; - - return status; -} -EXPORT_SYMBOL(vchi_initialise); - -/*********************************************************** - * Name: vchi_connect - * - * Arguments: struct vchi_instance_handle *instance_handle - * - * Description: Starts the command service on each connection, - * causing INIT messages to be pinged back and forth - * - * Returns: 0 if successful, failure otherwise - * - ***********************************************************/ -int32_t vchi_connect(struct vchi_instance_handle *instance_handle) -{ - struct vchiq_instance *instance = (struct vchiq_instance *)instance_handle; - - return vchiq_connect(instance); -} -EXPORT_SYMBOL(vchi_connect); - -/*********************************************************** - * Name: vchi_disconnect - * - * Arguments: struct vchi_instance_handle *instance_handle - * - * Description: Stops the command service on each connection, - * causing DE-INIT messages to be pinged back and forth - * - * Returns: 0 if successful, failure otherwise - * - ***********************************************************/ -int32_t vchi_disconnect(struct vchi_instance_handle *instance_handle) -{ - struct vchiq_instance *instance = (struct vchiq_instance *)instance_handle; - - return vchiq_shutdown(instance); -} -EXPORT_SYMBOL(vchi_disconnect); - -/*********************************************************** - * Name: vchi_service_open - * Name: vchi_service_create - * - * Arguments: struct vchi_instance_handle *instance_handle - * struct service_creation *setup, - * struct vchi_service_handle **handle - * - * Description: Routine to open a service - * - * Returns: int32_t - success == 0 - * - ***********************************************************/ - -static enum vchiq_status shim_callback(enum vchiq_reason reason, - struct vchiq_header *header, - unsigned int handle, - void *bulk_user) -{ - struct shim_service *service = - (struct shim_service *)VCHIQ_GET_SERVICE_USERDATA(handle); - - if (!service->callback) - goto release; - - switch (reason) { - case VCHIQ_MESSAGE_AVAILABLE: - vchiu_queue_push(&service->queue, header); - - service->callback(service->callback_param, - VCHI_CALLBACK_MSG_AVAILABLE, NULL); - - break; - - case VCHIQ_BULK_TRANSMIT_DONE: - service->callback(service->callback_param, - VCHI_CALLBACK_BULK_SENT, bulk_user); - break; - - case VCHIQ_BULK_RECEIVE_DONE: - service->callback(service->callback_param, - VCHI_CALLBACK_BULK_RECEIVED, bulk_user); - break; - - case VCHIQ_SERVICE_CLOSED: - service->callback(service->callback_param, - VCHI_CALLBACK_SERVICE_CLOSED, NULL); - break; - - case VCHIQ_BULK_TRANSMIT_ABORTED: - service->callback(service->callback_param, - VCHI_CALLBACK_BULK_TRANSMIT_ABORTED, - bulk_user); - break; - - case VCHIQ_BULK_RECEIVE_ABORTED: - service->callback(service->callback_param, - VCHI_CALLBACK_BULK_RECEIVE_ABORTED, - bulk_user); - break; - - default: - WARN(1, "not supported\n"); - break; - } - -release: - return VCHIQ_SUCCESS; -} - -static struct shim_service *service_alloc(struct vchiq_instance *instance, - struct service_creation *setup) -{ - struct shim_service *service = kzalloc(sizeof(struct shim_service), GFP_KERNEL); - - (void)instance; - - if (service) { - if (!vchiu_queue_init(&service->queue, 64)) { - service->callback = setup->callback; - service->callback_param = setup->callback_param; - } else { - kfree(service); - service = NULL; - } - } - - return service; -} - -static void service_free(struct shim_service *service) -{ - if (service) { - vchiu_queue_delete(&service->queue); - kfree(service); - } -} - -int32_t vchi_service_open(struct vchi_instance_handle *instance_handle, - struct service_creation *setup, - struct vchi_service_handle **handle) -{ - struct vchiq_instance *instance = (struct vchiq_instance *)instance_handle; - struct shim_service *service = service_alloc(instance, setup); - - *handle = (struct vchi_service_handle *)service; - - if (service) { - struct vchiq_service_params params; - enum vchiq_status status; - - memset(¶ms, 0, sizeof(params)); - params.fourcc = setup->service_id; - params.callback = shim_callback; - params.userdata = service; - params.version = setup->version.version; - params.version_min = setup->version.version_min; - - status = vchiq_open_service(instance, ¶ms, - &service->handle); - if (status != VCHIQ_SUCCESS) { - service_free(service); - service = NULL; - *handle = NULL; - } - } - - return service ? 0 : -1; -} -EXPORT_SYMBOL(vchi_service_open); - -int32_t vchi_service_close(const struct vchi_service_handle *handle) -{ - int32_t ret = -1; - struct shim_service *service = (struct shim_service *)handle; - - if (service) { - enum vchiq_status status = vchiq_close_service(service->handle); - if (status == VCHIQ_SUCCESS) - service_free(service); - - ret = status; - } - return ret; -} -EXPORT_SYMBOL(vchi_service_close); - -int32_t vchi_get_peer_version(const struct vchi_service_handle *handle, short *peer_version) -{ - int32_t ret = -1; - struct shim_service *service = (struct shim_service *)handle; - - if (service) { - enum vchiq_status status; - - status = vchiq_get_peer_version(service->handle, peer_version); - ret = status; - } - return ret; -} -EXPORT_SYMBOL(vchi_get_peer_version); - -/*********************************************************** - * Name: vchi_service_use - * - * Arguments: const struct vchi_service_handle *handle - * - * Description: Routine to increment refcount on a service - * - * Returns: void - * - ***********************************************************/ -int32_t vchi_service_use(const struct vchi_service_handle *handle) -{ - int32_t ret = -1; - - struct shim_service *service = (struct shim_service *)handle; - if (service) - ret = vchiq_use_service(service->handle); - return ret; -} -EXPORT_SYMBOL(vchi_service_use); - -/*********************************************************** - * Name: vchi_service_release - * - * Arguments: const struct vchi_service_handle *handle - * - * Description: Routine to decrement refcount on a service - * - * Returns: void - * - ***********************************************************/ -int32_t vchi_service_release(const struct vchi_service_handle *handle) -{ - int32_t ret = -1; - - struct shim_service *service = (struct shim_service *)handle; - if (service) - ret = vchiq_release_service(service->handle); - return ret; -} -EXPORT_SYMBOL(vchi_service_release); diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_util.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_util.c deleted file mode 100644 index 644844d88fed..000000000000 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_util.c +++ /dev/null @@ -1,85 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause -/* Copyright (c) 2010-2012 Broadcom. All rights reserved. */ - -#include "vchiq_util.h" - -static inline int is_pow2(int i) -{ - return i && !(i & (i - 1)); -} - -int vchiu_queue_init(struct vchiu_queue *queue, int size) -{ - WARN_ON(!is_pow2(size)); - - queue->size = size; - queue->read = 0; - queue->write = 0; - queue->initialized = 1; - - init_completion(&queue->pop); - init_completion(&queue->push); - - queue->storage = kcalloc(size, sizeof(struct vchiq_header *), - GFP_KERNEL); - if (!queue->storage) { - vchiu_queue_delete(queue); - return -ENOMEM; - } - return 0; -} - -void vchiu_queue_delete(struct vchiu_queue *queue) -{ - kfree(queue->storage); -} - -int vchiu_queue_is_empty(struct vchiu_queue *queue) -{ - return queue->read == queue->write; -} - -void vchiu_queue_push(struct vchiu_queue *queue, struct vchiq_header *header) -{ - if (!queue->initialized) - return; - - while (queue->write == queue->read + queue->size) { - if (wait_for_completion_interruptible(&queue->pop)) - flush_signals(current); - } - - queue->storage[queue->write & (queue->size - 1)] = header; - queue->write++; - - complete(&queue->push); -} - -struct vchiq_header *vchiu_queue_peek(struct vchiu_queue *queue) -{ - while (queue->write == queue->read) { - if (wait_for_completion_interruptible(&queue->push)) - flush_signals(current); - } - - complete(&queue->push); // We haven't removed anything from the queue. - - return queue->storage[queue->read & (queue->size - 1)]; -} - -struct vchiq_header *vchiu_queue_pop(struct vchiu_queue *queue) -{ - struct vchiq_header *header; - - while (queue->write == queue->read) { - if (wait_for_completion_interruptible(&queue->push)) - flush_signals(current); - } - - header = queue->storage[queue->read & (queue->size - 1)]; - queue->read++; - - complete(&queue->pop); - - return header; -} diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_util.h b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_util.h deleted file mode 100644 index f03a4250de0d..000000000000 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_util.h +++ /dev/null @@ -1,50 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ -/* Copyright (c) 2010-2012 Broadcom. All rights reserved. */ - -#ifndef VCHIQ_UTIL_H -#define VCHIQ_UTIL_H - -#include <linux/types.h> -#include <linux/completion.h> -#include <linux/mutex.h> -#include <linux/bitops.h> -#include <linux/kthread.h> -#include <linux/wait.h> -#include <linux/vmalloc.h> -#include <linux/jiffies.h> -#include <linux/delay.h> -#include <linux/string.h> -#include <linux/interrupt.h> -#include <linux/random.h> -#include <linux/sched/signal.h> -#include <linux/ctype.h> -#include <linux/uaccess.h> -#include <linux/time.h> /* for time_t */ -#include <linux/slab.h> - -#include "vchiq_if.h" - -struct vchiu_queue { - int size; - int read; - int write; - int initialized; - - struct completion pop; - struct completion push; - - struct vchiq_header **storage; -}; - -extern int vchiu_queue_init(struct vchiu_queue *queue, int size); -extern void vchiu_queue_delete(struct vchiu_queue *queue); - -extern int vchiu_queue_is_empty(struct vchiu_queue *queue); - -extern void vchiu_queue_push(struct vchiu_queue *queue, - struct vchiq_header *header); - -extern struct vchiq_header *vchiu_queue_peek(struct vchiu_queue *queue); -extern struct vchiq_header *vchiu_queue_pop(struct vchiu_queue *queue); - -#endif |