diff options
Diffstat (limited to 'drivers/staging/vc04_services')
13 files changed, 241 insertions, 259 deletions
diff --git a/drivers/staging/vc04_services/interface/vchi/connections/connection.h b/drivers/staging/vc04_services/interface/vchi/connections/connection.h index fef6ac34c6d2..e793cdf2847c 100644 --- a/drivers/staging/vc04_services/interface/vchi/connections/connection.h +++ b/drivers/staging/vc04_services/interface/vchi/connections/connection.h @@ -217,8 +217,7 @@ typedef void (*VCHI_BUFFER_FREE)(VCHI_CONNECTION_SERVICE_HANDLE_T service_hand System driver struct *****************************************************************************/ -struct opaque_vchi_connection_api_t -{ +struct opaque_vchi_connection_api_t { // Routine to init the connection VCHI_CONNECTION_INIT_T init; diff --git a/drivers/staging/vc04_services/interface/vchi/message_drivers/message.h b/drivers/staging/vc04_services/interface/vchi/message_drivers/message.h index 8b3f76735bd4..a7740a425388 100644 --- a/drivers/staging/vc04_services/interface/vchi/message_drivers/message.h +++ b/drivers/staging/vc04_services/interface/vchi/message_drivers/message.h @@ -53,14 +53,12 @@ typedef enum message_event_type { MESSAGE_EVENT_MSG_DISCARDED } MESSAGE_EVENT_TYPE_T; -typedef enum vchi_msg_flags -{ +typedef enum vchi_msg_flags { VCHI_MSG_FLAGS_NONE = 0x0, VCHI_MSG_FLAGS_TERMINATE_DMA = 0x1 } VCHI_MSG_FLAGS_T; -typedef enum message_tx_channel -{ +typedef enum message_tx_channel { MESSAGE_TX_CHANNEL_MESSAGE = 0, MESSAGE_TX_CHANNEL_BULK = 1 // drivers may provide multiple bulk channels, from 1 upwards } MESSAGE_TX_CHANNEL_T; @@ -69,8 +67,7 @@ typedef enum message_tx_channel #define MESSAGE_TX_CHANNEL_BULK_PREV(c) (MESSAGE_TX_CHANNEL_BULK+((c)-MESSAGE_TX_CHANNEL_BULK+VCHI_MAX_BULK_TX_CHANNELS_PER_CONNECTION-1)%VCHI_MAX_BULK_TX_CHANNELS_PER_CONNECTION) #define MESSAGE_TX_CHANNEL_BULK_NEXT(c) (MESSAGE_TX_CHANNEL_BULK+((c)-MESSAGE_TX_CHANNEL_BULK+1)%VCHI_MAX_BULK_TX_CHANNELS_PER_CONNECTION) -typedef enum message_rx_channel -{ +typedef enum message_rx_channel { MESSAGE_RX_CHANNEL_MESSAGE = 0, MESSAGE_RX_CHANNEL_BULK = 1 // drivers may provide multiple bulk channels, from 1 upwards } MESSAGE_RX_CHANNEL_T; diff --git a/drivers/staging/vc04_services/interface/vchi/vchi.h b/drivers/staging/vc04_services/interface/vchi/vchi.h index d6937288210c..addb7b00b688 100644 --- a/drivers/staging/vc04_services/interface/vchi/vchi.h +++ b/drivers/staging/vc04_services/interface/vchi/vchi.h @@ -61,8 +61,7 @@ struct vchi_version { #define VCHI_VERSION(v_) { v_, v_ } #define VCHI_VERSION_EX(v_, m_) { v_, m_ } -typedef enum -{ +typedef enum { VCHI_VEC_POINTER, VCHI_VEC_HANDLE, VCHI_VEC_LIST @@ -71,26 +70,22 @@ typedef enum typedef struct vchi_msg_vector_ex { VCHI_MSG_VECTOR_TYPE_T type; - union - { + union { // a memory handle - struct - { + struct { VCHI_MEM_HANDLE_T handle; uint32_t offset; int32_t vec_len; } handle; // an ordinary data pointer - struct - { + struct { const void *vec_base; int32_t vec_len; } ptr; // a nested vector list - struct - { + struct { struct vchi_msg_vector_ex *vec; uint32_t vec_len; } list; @@ -114,8 +109,7 @@ 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. -typedef struct -{ +typedef struct { struct opaque_vchi_service_t *service; void *message; } VCHI_HELD_MSG_T; @@ -225,13 +219,17 @@ extern int32_t vchi_service_set_option( const VCHI_SERVICE_HANDLE_T handle, VCHI_SERVICE_OPTION_T option, int value); -// Routine to send a message across a service -extern int32_t - vchi_msg_queue(VCHI_SERVICE_HANDLE_T handle, - ssize_t (*copy_callback)(void *context, void *dest, - size_t offset, size_t maxsize), - void *context, - uint32_t data_size); +/* Routine to send a message from kernel memory across a service */ +extern int +vchi_queue_kernel_message(VCHI_SERVICE_HANDLE_T handle, + void *data, + unsigned int size); + +/* Routine to send a message from user memory across a service */ +extern int +vchi_queue_user_message(VCHI_SERVICE_HANDLE_T handle, + void __user *data, + unsigned int size); // Routine to receive a msg from a service // Dequeue is equivalent to hold, copy into client buffer, release diff --git a/drivers/staging/vc04_services/interface/vchi/vchi_common.h b/drivers/staging/vc04_services/interface/vchi/vchi_common.h index d535a72970d3..45c2070d46b0 100644 --- a/drivers/staging/vc04_services/interface/vchi/vchi_common.h +++ b/drivers/staging/vc04_services/interface/vchi/vchi_common.h @@ -36,8 +36,7 @@ //flags used when sending messages (must be bitmapped) -typedef enum -{ +typedef enum { 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 @@ -62,8 +61,7 @@ typedef enum { } VCHI_CRC_CONTROL_T; //callback reasons when an event occurs on a service -typedef enum -{ +typedef enum { VCHI_CALLBACK_REASON_MIN, //This indicates that there is data available @@ -111,8 +109,7 @@ typedef enum } VCHI_CALLBACK_REASON_T; // service control options -typedef enum -{ +typedef enum { VCHI_SERVICE_OPTION_MIN, VCHI_SERVICE_OPTION_TRACE, @@ -123,9 +120,9 @@ typedef enum //Callback used by all services / bulk transfers -typedef void (*VCHI_CALLBACK_T)( void *callback_param, //my service local param - VCHI_CALLBACK_REASON_T reason, - void *handle ); //for transmitting msg's only +typedef void (*VCHI_CALLBACK_T)(void *callback_param, //my service local param + VCHI_CALLBACK_REASON_T reason, + void *handle); //for transmitting msg's only diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835.h b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835.h deleted file mode 100644 index 7ea5c64d5343..000000000000 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835.h +++ /dev/null @@ -1,42 +0,0 @@ -/** - * Copyright (c) 2010-2012 Broadcom. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The names of the above-listed copyright holders may not be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * ALTERNATIVELY, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2, as published by the Free - * Software Foundation. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef VCHIQ_2835_H -#define VCHIQ_2835_H - -#include "vchiq_pagelist.h" - -#define VCHIQ_PLATFORM_FRAGMENTS_OFFSET_IDX 0 -#define VCHIQ_PLATFORM_FRAGMENTS_COUNT_IDX 1 - -#endif /* VCHIQ_2835_H */ 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 2b500d85cebc..e6241fb5cfa6 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 @@ -48,18 +48,21 @@ #define TOTAL_SLOTS (VCHIQ_SLOT_ZERO_SLOTS + 2 * 32) #include "vchiq_arm.h" -#include "vchiq_2835.h" #include "vchiq_connected.h" #include "vchiq_killable.h" +#include "vchiq_pagelist.h" #define MAX_FRAGMENTS (VCHIQ_NUM_CURRENT_BULKS * 2) +#define VCHIQ_PLATFORM_FRAGMENTS_OFFSET_IDX 0 +#define VCHIQ_PLATFORM_FRAGMENTS_COUNT_IDX 1 + #define BELL0 0x00 #define BELL2 0x08 typedef struct vchiq_2835_state_struct { - int inited; - VCHIQ_ARM_STATE_T arm_state; + int inited; + VCHIQ_ARM_STATE_T arm_state; } VCHIQ_2835_ARM_STATE_T; struct vchiq_pagelist_info { @@ -192,31 +195,31 @@ int vchiq_platform_init(struct platform_device *pdev, VCHIQ_STATE_T *state) vchiq_call_connected_callbacks(); - return 0; + return 0; } VCHIQ_STATUS_T vchiq_platform_init_state(VCHIQ_STATE_T *state) { - VCHIQ_STATUS_T status = VCHIQ_SUCCESS; - state->platform_state = kzalloc(sizeof(VCHIQ_2835_ARM_STATE_T), GFP_KERNEL); - ((VCHIQ_2835_ARM_STATE_T*)state->platform_state)->inited = 1; - status = vchiq_arm_init_state(state, &((VCHIQ_2835_ARM_STATE_T*)state->platform_state)->arm_state); - if(status != VCHIQ_SUCCESS) - { - ((VCHIQ_2835_ARM_STATE_T*)state->platform_state)->inited = 0; - } - return status; + VCHIQ_STATUS_T status = VCHIQ_SUCCESS; + state->platform_state = kzalloc(sizeof(VCHIQ_2835_ARM_STATE_T), GFP_KERNEL); + ((VCHIQ_2835_ARM_STATE_T *)state->platform_state)->inited = 1; + status = vchiq_arm_init_state(state, &((VCHIQ_2835_ARM_STATE_T *)state->platform_state)->arm_state); + if (status != VCHIQ_SUCCESS) + { + ((VCHIQ_2835_ARM_STATE_T *)state->platform_state)->inited = 0; + } + return status; } VCHIQ_ARM_STATE_T* vchiq_platform_get_arm_state(VCHIQ_STATE_T *state) { - if(!((VCHIQ_2835_ARM_STATE_T*)state->platform_state)->inited) - { - BUG(); - } - return &((VCHIQ_2835_ARM_STATE_T*)state->platform_state)->arm_state; + if (!((VCHIQ_2835_ARM_STATE_T *)state->platform_state)->inited) + { + BUG(); + } + return &((VCHIQ_2835_ARM_STATE_T *)state->platform_state)->arm_state; } void @@ -292,13 +295,13 @@ vchiq_dump_platform_state(void *dump_context) VCHIQ_STATUS_T vchiq_platform_suspend(VCHIQ_STATE_T *state) { - return VCHIQ_ERROR; + return VCHIQ_ERROR; } VCHIQ_STATUS_T vchiq_platform_resume(VCHIQ_STATE_T *state) { - return VCHIQ_SUCCESS; + return VCHIQ_SUCCESS; } void @@ -312,15 +315,15 @@ vchiq_platform_resumed(VCHIQ_STATE_T *state) } int -vchiq_platform_videocore_wanted(VCHIQ_STATE_T* state) +vchiq_platform_videocore_wanted(VCHIQ_STATE_T *state) { - return 1; // autosuspend not supported - videocore always wanted + return 1; // autosuspend not supported - videocore always wanted } int vchiq_platform_use_suspend_timer(void) { - return 0; + return 0; } void vchiq_dump_platform_use_state(VCHIQ_STATE_T *state) 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 0d987898b4f8..1dc8627e65b0 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c @@ -64,10 +64,10 @@ #define VCHIQ_MINOR 0 /* Some per-instance constants */ -#define MAX_COMPLETIONS 16 +#define MAX_COMPLETIONS 128 #define MAX_SERVICES 64 #define MAX_ELEMENTS 8 -#define MSG_QUEUE_SIZE 64 +#define MSG_QUEUE_SIZE 128 #define KEEPALIVE_VER 1 #define KEEPALIVE_VER_MIN KEEPALIVE_VER @@ -194,7 +194,7 @@ vchiq_static_assert(ARRAY_SIZE(ioctl_names) == (VCHIQ_IOC_MAX + 1)); static void -dump_phys_mem(void *virt_addr, uint32_t num_bytes); +dump_phys_mem(void *virt_addr, u32 num_bytes); /**************************************************************************** * @@ -208,10 +208,11 @@ add_completion(VCHIQ_INSTANCE_T instance, VCHIQ_REASON_T reason, void *bulk_userdata) { VCHIQ_COMPLETION_DATA_T *completion; + int insert; DEBUG_INITIALISE(g_state.local) - while (instance->completion_insert == - (instance->completion_remove + MAX_COMPLETIONS)) { + insert = instance->completion_insert; + while ((insert - instance->completion_remove) >= MAX_COMPLETIONS) { /* Out of space - wait for the client */ DEBUG_TRACE(SERVICE_CALLBACK_LINE); vchiq_log_trace(vchiq_arm_log_level, @@ -224,14 +225,12 @@ add_completion(VCHIQ_INSTANCE_T instance, VCHIQ_REASON_T reason, } else if (instance->closing) { vchiq_log_info(vchiq_arm_log_level, "service_callback closing"); - return VCHIQ_ERROR; + return VCHIQ_SUCCESS; } DEBUG_TRACE(SERVICE_CALLBACK_LINE); } - completion = - &instance->completions[instance->completion_insert & - (MAX_COMPLETIONS - 1)]; + completion = &instance->completions[insert & (MAX_COMPLETIONS - 1)]; completion->header = header; completion->reason = reason; @@ -252,9 +251,10 @@ add_completion(VCHIQ_INSTANCE_T instance, VCHIQ_REASON_T reason, wmb(); if (reason == VCHIQ_MESSAGE_AVAILABLE) - user_service->message_available_pos = - instance->completion_insert; - instance->completion_insert++; + user_service->message_available_pos = insert; + + insert++; + instance->completion_insert = insert; up(&instance->insert_event); @@ -279,6 +279,7 @@ service_callback(VCHIQ_REASON_T reason, VCHIQ_HEADER_T *header, USER_SERVICE_T *user_service; VCHIQ_SERVICE_T *service; VCHIQ_INSTANCE_T instance; + bool skip_completion = false; DEBUG_INITIALISE(g_state.local) DEBUG_TRACE(SERVICE_CALLBACK_LINE); @@ -345,9 +346,6 @@ service_callback(VCHIQ_REASON_T reason, VCHIQ_HEADER_T *header, user_service->msg_queue[user_service->msg_insert & (MSG_QUEUE_SIZE - 1)] = header; user_service->msg_insert++; - spin_unlock(&msg_queue_spinlock); - - up(&user_service->insert_event); /* If there is a thread waiting in DEQUEUE_MESSAGE, or if ** there is a MESSAGE_AVAILABLE in the completion queue then @@ -356,15 +354,20 @@ service_callback(VCHIQ_REASON_T reason, VCHIQ_HEADER_T *header, if (((user_service->message_available_pos - instance->completion_remove) >= 0) || user_service->dequeue_pending) { - DEBUG_TRACE(SERVICE_CALLBACK_LINE); user_service->dequeue_pending = 0; - return VCHIQ_SUCCESS; + skip_completion = true; } + spin_unlock(&msg_queue_spinlock); + up(&user_service->insert_event); + header = NULL; } DEBUG_TRACE(SERVICE_CALLBACK_LINE); + if (skip_completion) + return VCHIQ_SUCCESS; + return add_completion(instance, reason, header, user_service, bulk_userdata); } @@ -665,7 +668,7 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg) USER_SERVICE_T *user_service = (USER_SERVICE_T *)service->base.userdata; /* close_pending is false on first entry, and when the - wait in vchiq_close_service has been interrupted. */ + wait in vchiq_close_service has been interrupted. */ if (!user_service->close_pending) { status = vchiq_close_service(service->handle); if (status != VCHIQ_SUCCESS) @@ -691,7 +694,7 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg) USER_SERVICE_T *user_service = (USER_SERVICE_T *)service->base.userdata; /* close_pending is false on first entry, and when the - wait in vchiq_close_service has been interrupted. */ + wait in vchiq_close_service has been interrupted. */ if (!user_service->close_pending) { status = vchiq_remove_service(service->handle); if (status != VCHIQ_SUCCESS) @@ -892,24 +895,27 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg) } DEBUG_TRACE(AWAIT_COMPLETION_LINE); - /* A read memory barrier is needed to stop prefetch of a stale - ** completion record - */ - rmb(); - if (ret == 0) { int msgbufcount = args.msgbufcount; + int remove = instance->completion_remove; + for (ret = 0; ret < args.count; ret++) { VCHIQ_COMPLETION_DATA_T *completion; VCHIQ_SERVICE_T *service; USER_SERVICE_T *user_service; VCHIQ_HEADER_T *header; - if (instance->completion_remove == - instance->completion_insert) + + if (remove == instance->completion_insert) break; + completion = &instance->completions[ - instance->completion_remove & - (MAX_COMPLETIONS - 1)]; + remove & (MAX_COMPLETIONS - 1)]; + + /* + * A read memory barrier is needed to stop + * prefetch of a stale completion record + */ + rmb(); service = completion->service_userdata; user_service = service->base.userdata; @@ -984,7 +990,13 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg) break; } - instance->completion_remove++; + /* + * Ensure that the above copy has completed + * before advancing the remove pointer. + */ + mb(); + remove++; + instance->completion_remove = remove; } if (msgbufcount != args.msgbufcount) { @@ -1535,10 +1547,10 @@ vchiq_dump_platform_service_state(void *dump_context, VCHIQ_SERVICE_T *service) ***************************************************************************/ static void -dump_phys_mem(void *virt_addr, uint32_t num_bytes) +dump_phys_mem(void *virt_addr, u32 num_bytes) { int rc; - uint8_t *end_virt_addr = virt_addr + num_bytes; + u8 *end_virt_addr = virt_addr + num_bytes; int num_pages; int offset; int end_offset; @@ -1546,7 +1558,7 @@ dump_phys_mem(void *virt_addr, uint32_t num_bytes) int prev_idx; struct page *page; struct page **pages; - uint8_t *kmapped_virt_ptr; + u8 *kmapped_virt_ptr; /* Align virtAddr and endVirtAddr to 16 byte boundaries. */ @@ -1602,7 +1614,7 @@ dump_phys_mem(void *virt_addr, uint32_t num_bytes) if (vchiq_arm_log_level >= VCHIQ_LOG_TRACE) vchiq_log_dump_mem("ph", - (uint32_t)(unsigned long)&kmapped_virt_ptr[ + (u32)(unsigned long)&kmapped_virt_ptr[ page_offset], &kmapped_virt_ptr[page_offset], 16); @@ -1996,7 +2008,7 @@ block_resume(VCHIQ_ARM_STATE_T *arm_state) &arm_state->blocked_blocker, timeout_val) <= 0) { vchiq_log_error(vchiq_susp_log_level, "%s wait for " - "previously blocked clients failed" , __func__); + "previously blocked clients failed", __func__); status = VCHIQ_ERROR; write_lock_bh(&arm_state->susp_res_lock); goto out; @@ -2012,7 +2024,7 @@ block_resume(VCHIQ_ARM_STATE_T *arm_state) if (resume_count > 1) { status = VCHIQ_ERROR; vchiq_log_error(vchiq_susp_log_level, "%s waited too " - "many times for resume" , __func__); + "many times for resume", __func__); goto out; } write_unlock_bh(&arm_state->susp_res_lock); @@ -2372,52 +2384,6 @@ out: return resume; } -void -vchiq_platform_check_resume(VCHIQ_STATE_T *state) -{ - VCHIQ_ARM_STATE_T *arm_state = vchiq_platform_get_arm_state(state); - int res = 0; - - if (!arm_state) - goto out; - - vchiq_log_trace(vchiq_susp_log_level, "%s", __func__); - - write_lock_bh(&arm_state->susp_res_lock); - if (arm_state->wake_address == 0) { - vchiq_log_info(vchiq_susp_log_level, - "%s: already awake", __func__); - goto unlock; - } - if (arm_state->vc_resume_state == VC_RESUME_IN_PROGRESS) { - vchiq_log_info(vchiq_susp_log_level, - "%s: already resuming", __func__); - goto unlock; - } - - if (arm_state->vc_resume_state == VC_RESUME_REQUESTED) { - set_resume_state(arm_state, VC_RESUME_IN_PROGRESS); - res = 1; - } else - vchiq_log_trace(vchiq_susp_log_level, - "%s: not resuming (resume state %s)", __func__, - resume_state_names[arm_state->vc_resume_state + - VC_RESUME_NUM_OFFSET]); - -unlock: - write_unlock_bh(&arm_state->susp_res_lock); - - if (res) - vchiq_platform_resume(state); - -out: - vchiq_log_trace(vchiq_susp_log_level, "%s exit", __func__); - return; - -} - - - VCHIQ_STATUS_T vchiq_use_internal(VCHIQ_STATE_T *state, VCHIQ_SERVICE_T *service, enum USE_TYPE_E use_type) @@ -2870,10 +2836,10 @@ void vchiq_platform_conn_state_changed(VCHIQ_STATE_T *state, if (state->conn_state == VCHIQ_CONNSTATE_CONNECTED) { write_lock_bh(&arm_state->susp_res_lock); if (!arm_state->first_connect) { - char threadname[10]; + char threadname[16]; arm_state->first_connect = 1; write_unlock_bh(&arm_state->susp_res_lock); - snprintf(threadname, sizeof(threadname), "VCHIQka-%d", + snprintf(threadname, sizeof(threadname), "vchiq-keep/%d", state->id); arm_state->ka_thread = kthread_create( &vchiq_keepalive_thread_func, diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h index 9740e1afbc9d..bfbd81d9db33 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h @@ -154,7 +154,7 @@ vchiq_check_resume(VCHIQ_STATE_T *state); extern void vchiq_check_suspend(VCHIQ_STATE_T *state); - VCHIQ_STATUS_T +VCHIQ_STATUS_T vchiq_use_service(VCHIQ_SERVICE_HANDLE_T handle); extern VCHIQ_STATUS_T 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 028e90bc1cdc..d587097b261c 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c @@ -90,7 +90,7 @@ static atomic_t pause_bulks_count = ATOMIC_INIT(0); static DEFINE_SPINLOCK(service_spinlock); DEFINE_SPINLOCK(bulk_waiter_spinlock); -DEFINE_SPINLOCK(quota_spinlock); +static DEFINE_SPINLOCK(quota_spinlock); VCHIQ_STATE_T *vchiq_states[VCHIQ_MAX_STATES]; static unsigned int handle_seq; @@ -517,7 +517,7 @@ get_connected_service(VCHIQ_STATE_T *state, unsigned int port) inline void request_poll(VCHIQ_STATE_T *state, VCHIQ_SERVICE_T *service, int poll_type) { - uint32_t value; + u32 value; if (service) { do { @@ -607,15 +607,17 @@ process_free_queue(VCHIQ_STATE_T *state) BITSET_T service_found[BITSET_SIZE(VCHIQ_MAX_SERVICES)]; int slot_queue_available; - /* Use a read memory barrier to ensure that any state that may have - ** been modified by another thread is not masked by stale prefetched - ** values. */ - rmb(); - /* Find slots which have been freed by the other side, and return them ** to the available queue. */ slot_queue_available = state->slot_queue_available; + /* + * Use a memory barrier to ensure that any state that may have been + * modified by another thread is not masked by stale prefetched + * values. + */ + mb(); + while (slot_queue_available != local->slot_queue_recycle) { unsigned int pos; int slot_index = local->slot_queue[slot_queue_available++ & @@ -623,6 +625,12 @@ process_free_queue(VCHIQ_STATE_T *state) char *data = (char *)SLOT_DATA_FROM_INDEX(state, slot_index); int data_found = 0; + /* + * Beware of the address dependency - data is calculated + * using an index written by the other side. + */ + rmb(); + vchiq_log_trace(vchiq_core_log_level, "%d: pfq %d=%pK %x %x", state->id, slot_index, data, local->slot_queue_recycle, slot_queue_available); @@ -721,6 +729,12 @@ process_free_queue(VCHIQ_STATE_T *state) up(&state->data_quota_event); } + /* + * Don't allow the slot to be reused until we are no + * longer interested in it. + */ + mb(); + state->slot_queue_available = slot_queue_available; up(&state->slot_available_event); } @@ -920,7 +934,7 @@ queue_message(VCHIQ_STATE_T *state, VCHIQ_SERVICE_T *service, VCHIQ_LOG_INFO)) vchiq_log_dump_mem("Sent", 0, header->data, - min((size_t)64, + min((size_t)16, (size_t)callback_result)); spin_lock("a_spinlock); @@ -1073,7 +1087,7 @@ queue_message_sync(VCHIQ_STATE_T *state, VCHIQ_SERVICE_T *service, VCHIQ_LOG_INFO)) vchiq_log_dump_mem("Sent", 0, header->data, - min((size_t)64, + min((size_t)16, (size_t)callback_result)); VCHIQ_SERVICE_STATS_INC(service, ctrl_tx_count); @@ -1286,14 +1300,14 @@ poll_services(VCHIQ_STATE_T *state) int group, i; for (group = 0; group < BITSET_SIZE(state->unused_service); group++) { - uint32_t flags; + u32 flags; flags = atomic_xchg(&state->poll_services[group], 0); for (i = 0; flags; i++) { if (flags & (1 << i)) { VCHIQ_SERVICE_T *service = find_service_by_port(state, (group<<5) + i); - uint32_t service_flags; + u32 service_flags; flags &= ~(1 << i); if (!service) continue; @@ -1513,12 +1527,10 @@ parse_open(VCHIQ_STATE_T *state, VCHIQ_HEADER_T *header) { VCHIQ_SERVICE_T *service = NULL; int msgid, size; - int type; unsigned int localport, remoteport; msgid = header->msgid; size = header->size; - type = VCHIQ_MSG_TYPE(msgid); localport = VCHIQ_MSG_DSTPORT(msgid); remoteport = VCHIQ_MSG_SRCPORT(msgid); if (size >= sizeof(struct vchiq_open_payload)) { @@ -1620,7 +1632,7 @@ fail_open: /* No available service, or an invalid request - send a CLOSE */ if (queue_message(state, NULL, VCHIQ_MAKE_MSG(VCHIQ_MSG_CLOSE, 0, VCHIQ_MSG_SRCPORT(msgid)), - NULL, 0, 0, 0) == VCHIQ_RETRY) + NULL, NULL, 0, 0) == VCHIQ_RETRY) goto bail_not_ready; return 1; @@ -1736,7 +1748,7 @@ parse_rx_slots(VCHIQ_STATE_T *state) remoteport, localport, size); if (size > 0) vchiq_log_dump_mem("Rcvd", 0, header->data, - min(64, size)); + min(16, size)); } if (((unsigned long)header & VCHIQ_SLOT_MASK) + @@ -1973,7 +1985,7 @@ parse_rx_slots(VCHIQ_STATE_T *state) /* Send a PAUSE in response */ if (queue_message(state, NULL, VCHIQ_MAKE_MSG(VCHIQ_MSG_PAUSE, 0, 0), - NULL, 0, 0, QMFLAGS_NO_MUTEX_UNLOCK) + NULL, NULL, 0, QMFLAGS_NO_MUTEX_UNLOCK) == VCHIQ_RETRY) goto bail_not_ready; if (state->is_master) @@ -2072,7 +2084,7 @@ slot_handler_func(void *v) pause_bulks(state); if (queue_message(state, NULL, VCHIQ_MAKE_MSG(VCHIQ_MSG_PAUSE, 0, 0), - NULL, 0, 0, + NULL, NULL, 0, QMFLAGS_NO_MUTEX_UNLOCK) != VCHIQ_RETRY) { vchiq_set_conn_state(state, @@ -2092,7 +2104,7 @@ slot_handler_func(void *v) case VCHIQ_CONNSTATE_RESUMING: if (queue_message(state, NULL, VCHIQ_MAKE_MSG(VCHIQ_MSG_RESUME, 0, 0), - NULL, 0, 0, QMFLAGS_NO_MUTEX_LOCK) + NULL, NULL, 0, QMFLAGS_NO_MUTEX_LOCK) != VCHIQ_RETRY) { if (state->is_master) resume_bulks(state); @@ -2193,7 +2205,7 @@ sync_func(void *v) remoteport, localport, size); if (size > 0) vchiq_log_dump_mem("Rcvd", 0, header->data, - min(64, size)); + min(16, size)); } switch (type) { @@ -2317,7 +2329,7 @@ vchiq_init_state(VCHIQ_STATE_T *state, VCHIQ_SLOT_ZERO_T *slot_zero, VCHIQ_SHARED_STATE_T *local; VCHIQ_SHARED_STATE_T *remote; VCHIQ_STATUS_T status; - char threadname[10]; + char threadname[16]; static int id; int i; @@ -2485,7 +2497,7 @@ vchiq_init_state(VCHIQ_STATE_T *state, VCHIQ_SLOT_ZERO_T *slot_zero, /* bring up slot handler thread */ - snprintf(threadname, sizeof(threadname), "VCHIQ-%d", state->id); + snprintf(threadname, sizeof(threadname), "vchiq-slot/%d", state->id); state->slot_handler_thread = kthread_create(&slot_handler_func, (void *)state, threadname); @@ -2499,7 +2511,7 @@ vchiq_init_state(VCHIQ_STATE_T *state, VCHIQ_SLOT_ZERO_T *slot_zero, set_user_nice(state->slot_handler_thread, -19); wake_up_process(state->slot_handler_thread); - snprintf(threadname, sizeof(threadname), "VCHIQr-%d", state->id); + snprintf(threadname, sizeof(threadname), "vchiq-recy/%d", state->id); state->recycle_thread = kthread_create(&recycle_func, (void *)state, threadname); @@ -2512,7 +2524,7 @@ vchiq_init_state(VCHIQ_STATE_T *state, VCHIQ_SLOT_ZERO_T *slot_zero, set_user_nice(state->recycle_thread, -19); wake_up_process(state->recycle_thread); - snprintf(threadname, sizeof(threadname), "VCHIQs-%d", state->id); + snprintf(threadname, sizeof(threadname), "vchiq-sync/%d", state->id); state->sync_thread = kthread_create(&sync_func, (void *)state, threadname); @@ -2904,7 +2916,7 @@ vchiq_close_service_internal(VCHIQ_SERVICE_T *service, int close_recvd) (VCHIQ_MSG_CLOSE, service->localport, VCHIQ_MSG_DSTPORT(service->remoteport)), - NULL, 0, 0, 0); + NULL, NULL, 0, 0); } break; @@ -2926,7 +2938,7 @@ vchiq_close_service_internal(VCHIQ_SERVICE_T *service, int close_recvd) (VCHIQ_MSG_CLOSE, service->localport, VCHIQ_MSG_DSTPORT(service->remoteport)), - NULL, 0, 0, QMFLAGS_NO_MUTEX_UNLOCK); + NULL, NULL, 0, QMFLAGS_NO_MUTEX_UNLOCK); if (status == VCHIQ_SUCCESS) { if (!close_recvd) { @@ -3056,7 +3068,7 @@ vchiq_connect_internal(VCHIQ_STATE_T *state, VCHIQ_INSTANCE_T instance) if (state->conn_state == VCHIQ_CONNSTATE_DISCONNECTED) { if (queue_message(state, NULL, - VCHIQ_MAKE_MSG(VCHIQ_MSG_CONNECT, 0, 0), NULL, 0, + VCHIQ_MAKE_MSG(VCHIQ_MSG_CONNECT, 0, 0), NULL, NULL, 0, QMFLAGS_IS_BLOCKING) == VCHIQ_RETRY) return VCHIQ_RETRY; @@ -3509,20 +3521,20 @@ release_message_sync(VCHIQ_STATE_T *state, VCHIQ_HEADER_T *header) VCHIQ_STATUS_T vchiq_get_peer_version(VCHIQ_SERVICE_HANDLE_T handle, short *peer_version) { - VCHIQ_STATUS_T status = VCHIQ_ERROR; - VCHIQ_SERVICE_T *service = find_service_by_handle(handle); + VCHIQ_STATUS_T status = VCHIQ_ERROR; + VCHIQ_SERVICE_T *service = find_service_by_handle(handle); - if (!service || - (vchiq_check_service(service) != VCHIQ_SUCCESS) || - !peer_version) - goto exit; - *peer_version = service->peer_version; - status = VCHIQ_SUCCESS; + if (!service || + (vchiq_check_service(service) != VCHIQ_SUCCESS) || + !peer_version) + goto exit; + *peer_version = service->peer_version; + status = VCHIQ_SUCCESS; exit: - if (service) - unlock_service(service); - return status; + if (service) + unlock_service(service); + return status; } VCHIQ_STATUS_T @@ -3626,7 +3638,7 @@ vchiq_set_service_option(VCHIQ_SERVICE_HANDLE_T handle, return status; } -void +static void vchiq_dump_shared_state(void *dump_context, VCHIQ_STATE_T *state, VCHIQ_SHARED_STATE_T *shared, const char *label) { @@ -3816,7 +3828,7 @@ vchiq_dump_service_state(void *dump_context, VCHIQ_SERVICE_T *service) service->stats.bulk_stalls, service->stats.bulk_aborted_count, service->stats.error_count); - } + } } vchiq_dump(dump_context, buf, len + 1); @@ -3857,7 +3869,7 @@ VCHIQ_STATUS_T vchiq_send_remote_use(VCHIQ_STATE_T *state) if (state->conn_state != VCHIQ_CONNSTATE_DISCONNECTED) status = queue_message(state, NULL, VCHIQ_MAKE_MSG(VCHIQ_MSG_REMOTE_USE, 0, 0), - NULL, 0, 0, 0); + NULL, NULL, 0, 0); return status; } @@ -3867,7 +3879,7 @@ VCHIQ_STATUS_T vchiq_send_remote_release(VCHIQ_STATE_T *state) if (state->conn_state != VCHIQ_CONNSTATE_DISCONNECTED) status = queue_message(state, NULL, VCHIQ_MAKE_MSG(VCHIQ_MSG_REMOTE_RELEASE, 0, 0), - NULL, 0, 0, 0); + NULL, NULL, 0, 0); return status; } @@ -3877,14 +3889,14 @@ VCHIQ_STATUS_T vchiq_send_remote_use_active(VCHIQ_STATE_T *state) if (state->conn_state != VCHIQ_CONNSTATE_DISCONNECTED) status = queue_message(state, NULL, VCHIQ_MAKE_MSG(VCHIQ_MSG_REMOTE_USE_ACTIVE, 0, 0), - NULL, 0, 0, 0); + NULL, NULL, 0, 0); return status; } -void vchiq_log_dump_mem(const char *label, uint32_t addr, const void *void_mem, +void vchiq_log_dump_mem(const char *label, u32 addr, const void *void_mem, size_t num_bytes) { - const uint8_t *mem = (const uint8_t *)void_mem; + const u8 *mem = (const u8 *)void_mem; size_t offset; char line_buf[100]; char *s; @@ -3901,7 +3913,7 @@ void vchiq_log_dump_mem(const char *label, uint32_t addr, const void *void_mem, for (offset = 0; offset < 16; offset++) { if (offset < num_bytes) { - uint8_t ch = mem[offset]; + u8 ch = mem[offset]; if ((ch < ' ') || (ch > '~')) ch = '.'; diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_debugfs.h b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_debugfs.h index 4d6a3788e9c5..1d95e3d70621 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_debugfs.h +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_debugfs.h @@ -36,8 +36,7 @@ #include "vchiq_core.h" -typedef struct vchiq_debugfs_node_struct -{ +typedef struct vchiq_debugfs_node_struct { struct dentry *dentry; } VCHIQ_DEBUGFS_NODE_T; diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_kern_lib.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_kern_lib.c index e93922a87263..4317c06943a6 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_kern_lib.c +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_kern_lib.c @@ -75,23 +75,23 @@ VCHIQ_STATUS_T vchiq_initialise(VCHIQ_INSTANCE_T *instance_out) VCHIQ_STATUS_T status = VCHIQ_ERROR; VCHIQ_STATE_T *state; VCHIQ_INSTANCE_T instance = NULL; - int i; + int i; vchiq_log_trace(vchiq_core_log_level, "%s called", __func__); - /* VideoCore may not be ready due to boot up timing. - It may never be ready if kernel and firmware are mismatched, so don't block forever. */ - for (i=0; i<VCHIQ_INIT_RETRIES; i++) { + /* VideoCore may not be ready due to boot up timing. + It may never be ready if kernel and firmware are mismatched, so don't block forever. */ + for (i = 0; i < VCHIQ_INIT_RETRIES; i++) { state = vchiq_get_state(); if (state) break; udelay(500); } - if (i==VCHIQ_INIT_RETRIES) { + if (i == VCHIQ_INIT_RETRIES) { vchiq_log_error(vchiq_core_log_level, "%s: videocore not initialized\n", __func__); goto failed; - } else if (i>0) { + } else if (i > 0) { vchiq_log_warning(vchiq_core_log_level, "%s: videocore initialized after %d retries\n", __func__, i); } @@ -172,7 +172,7 @@ EXPORT_SYMBOL(vchiq_shutdown); * ***************************************************************************/ -int vchiq_is_connected(VCHIQ_INSTANCE_T instance) +static int vchiq_is_connected(VCHIQ_INSTANCE_T instance) { return instance->connected; } diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_shim.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_shim.c index d9771394a041..48984abc3854 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_shim.c +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_shim.c @@ -39,8 +39,6 @@ #include "vchiq_util.h" -#include <stddef.h> - #define vchiq_status_to_vchi(status) ((int32_t)status) typedef struct { @@ -158,6 +156,7 @@ EXPORT_SYMBOL(vchi_msg_remove); * Returns: int32_t - success == 0 * ***********************************************************/ +static int32_t vchi_msg_queue(VCHI_SERVICE_HANDLE_T handle, ssize_t (*copy_callback)(void *context, void *dest, size_t offset, size_t maxsize), @@ -186,7 +185,62 @@ int32_t vchi_msg_queue(VCHI_SERVICE_HANDLE_T handle, return vchiq_status_to_vchi(status); } -EXPORT_SYMBOL(vchi_msg_queue); + +static ssize_t +vchi_queue_kernel_message_callback(void *context, + void *dest, + size_t offset, + size_t maxsize) +{ + memcpy(dest, context + offset, maxsize); + return maxsize; +} + +int +vchi_queue_kernel_message(VCHI_SERVICE_HANDLE_T handle, + void *data, + unsigned int size) +{ + return vchi_msg_queue(handle, + vchi_queue_kernel_message_callback, + data, + size); +} +EXPORT_SYMBOL(vchi_queue_kernel_message); + +struct vchi_queue_user_message_context { + void __user *data; +}; + +static ssize_t +vchi_queue_user_message_callback(void *context, + void *dest, + size_t offset, + size_t maxsize) +{ + struct vchi_queue_user_message_context *copycontext = context; + + if (copy_from_user(dest, copycontext->data + offset, maxsize)) + return -EFAULT; + + return maxsize; +} + +int +vchi_queue_user_message(VCHI_SERVICE_HANDLE_T handle, + void __user *data, + unsigned int size) +{ + struct vchi_queue_user_message_context copycontext = { + .data = data + }; + + return vchi_msg_queue(handle, + vchi_queue_user_message_callback, + ©context, + size); +} +EXPORT_SYMBOL(vchi_queue_user_message); /*********************************************************** * Name: vchi_bulk_queue_receive @@ -527,7 +581,7 @@ static VCHIQ_STATUS_T shim_callback(VCHIQ_REASON_T reason, SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)VCHIQ_GET_SERVICE_USERDATA(handle); - if (!service->callback) + if (!service->callback) goto release; switch (reason) { @@ -577,7 +631,7 @@ static VCHIQ_STATUS_T shim_callback(VCHIQ_REASON_T reason, } release: - vchiq_release_message(service->handle, header); + vchiq_release_message(service->handle, header); done: return VCHIQ_SUCCESS; } @@ -739,16 +793,18 @@ int32_t vchi_service_set_option(const VCHI_SERVICE_HANDLE_T handle, } EXPORT_SYMBOL(vchi_service_set_option); -int32_t vchi_get_peer_version( const VCHI_SERVICE_HANDLE_T handle, short *peer_version ) +int32_t vchi_get_peer_version(const VCHI_SERVICE_HANDLE_T handle, short *peer_version) { - int32_t ret = -1; - SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle; - if(service) - { - VCHIQ_STATUS_T status = vchiq_get_peer_version(service->handle, peer_version); - ret = vchiq_status_to_vchi( status ); - } - return ret; + int32_t ret = -1; + SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle; + if (service) + { + VCHIQ_STATUS_T status; + + status = vchiq_get_peer_version(service->handle, peer_version); + ret = vchiq_status_to_vchi(status); + } + return ret; } EXPORT_SYMBOL(vchi_get_peer_version); diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_util.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_util.c index f76f4d790532..e0ba0ed704fd 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_util.c +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_util.c @@ -80,9 +80,8 @@ void vchiu_queue_push(VCHIU_QUEUE_T *queue, VCHIQ_HEADER_T *header) return; while (queue->write == queue->read + queue->size) { - if (down_interruptible(&queue->pop) != 0) { + if (down_interruptible(&queue->pop) != 0) flush_signals(current); - } } /* @@ -107,9 +106,8 @@ void vchiu_queue_push(VCHIU_QUEUE_T *queue, VCHIQ_HEADER_T *header) VCHIQ_HEADER_T *vchiu_queue_peek(VCHIU_QUEUE_T *queue) { while (queue->write == queue->read) { - if (down_interruptible(&queue->push) != 0) { + if (down_interruptible(&queue->push) != 0) flush_signals(current); - } } up(&queue->push); // We haven't removed anything from the queue. @@ -128,9 +126,8 @@ VCHIQ_HEADER_T *vchiu_queue_pop(VCHIU_QUEUE_T *queue) VCHIQ_HEADER_T *header; while (queue->write == queue->read) { - if (down_interruptible(&queue->push) != 0) { + if (down_interruptible(&queue->push) != 0) flush_signals(current); - } } /* |