[add Phil] > Arnd Bergmann <arnd@xxxxxxxx> hat am 2. Februar 2018 um 16:01 geschrieben: > > > There are two incompatible definitions of 'vchiq_instance_struct', so > passing them through vchiq_initialise(), vchiq_connect() or another > such interface is broken, as shown by building the driver with link-time > optimizations: > > drivers/staging/vc04_services/interface/vchiq_arm/vchiq_if.h:129:0: error: type of 'vchiq_initialise' does not match original declaration [-Werror=lto-type-mismatch] > extern VCHIQ_STATUS_T vchiq_initialise(VCHIQ_INSTANCE_T *pinstance); > > drivers/staging/vc04_services/interface/vchiq_arm/vchiq_kern_lib.c:68:0: note: 'vchiq_initialise' was previously declared here > VCHIQ_STATUS_T vchiq_initialise(VCHIQ_INSTANCE_T *instance_out) > > drivers/staging/vc04_services/interface/vchiq_arm/vchiq_kern_lib.c:68:0: note: code may be misoptimized unless -fno-strict-aliasing is used > drivers/staging/vc04_services/interface/vchiq_arm/vchiq_if.h:131:0: error: type of 'vchiq_connect' does not match original declaration [-Werror=lto-type-mismatch] > extern VCHIQ_STATUS_T vchiq_connect(VCHIQ_INSTANCE_T instance); > > drivers/staging/vc04_services/interface/vchiq_arm/vchiq_kern_lib.c:168:0: note: 'vchiq_connect' was previously declared here > VCHIQ_STATUS_T vchiq_connect(VCHIQ_INSTANCE_T instance) > > It's possible that only one of the two sides actually access the members, > but it's clear that they need to agree on the layout. The easiest way > to achieve this appears to be to merge the two files into one. I tried > moving the structure definition into a shared header first, but ended > up running into too many interdependencies that way. > > Signed-off-by: Arnd Bergmann <arnd@xxxxxxxx> > --- > drivers/staging/vc04_services/Makefile | 1 - > .../vc04_services/interface/vchiq_arm/vchiq_arm.c | 369 ++++++++++++++++++ > .../interface/vchiq_arm/vchiq_kern_lib.c | 431 --------------------- > 3 files changed, 369 insertions(+), 432 deletions(-) > delete mode 100644 drivers/staging/vc04_services/interface/vchiq_arm/vchiq_kern_lib.c > > diff --git a/drivers/staging/vc04_services/Makefile b/drivers/staging/vc04_services/Makefile > index 1ecb261e04ae..fb26b826e640 100644 > --- a/drivers/staging/vc04_services/Makefile > +++ b/drivers/staging/vc04_services/Makefile > @@ -4,7 +4,6 @@ obj-$(CONFIG_BCM2835_VCHIQ) += vchiq.o > vchiq-objs := \ > interface/vchiq_arm/vchiq_core.o \ > interface/vchiq_arm/vchiq_arm.o \ > - interface/vchiq_arm/vchiq_kern_lib.o \ > interface/vchiq_arm/vchiq_2835_arm.o \ > interface/vchiq_arm/vchiq_debugfs.o \ > interface/vchiq_arm/vchiq_shim.o \ > 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 c2c440009cac..f5cefda49b22 100644 > --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c > +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c > @@ -193,6 +193,375 @@ static const char *const ioctl_names[] = { > vchiq_static_assert(ARRAY_SIZE(ioctl_names) == > (VCHIQ_IOC_MAX + 1)); > > +static VCHIQ_STATUS_T > +vchiq_blocking_bulk_transfer(VCHIQ_SERVICE_HANDLE_T handle, void *data, > + unsigned int size, VCHIQ_BULK_DIR_T dir); > + > +#define VCHIQ_INIT_RETRIES 10 > +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; > + > + 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++) { > + state = vchiq_get_state(); > + if (state) > + break; > + udelay(500); > + } > + if (i == VCHIQ_INIT_RETRIES) { > + vchiq_log_error(vchiq_core_log_level, > + "%s: videocore not initialized\n", __func__); > + goto failed; > + } else if (i > 0) { > + vchiq_log_warning(vchiq_core_log_level, > + "%s: videocore initialized after %d retries\n", > + __func__, i); > + } > + > + instance = kzalloc(sizeof(*instance), GFP_KERNEL); > + if (!instance) { > + vchiq_log_error(vchiq_core_log_level, > + "%s: error allocating vchiq instance\n", __func__); > + goto failed; > + } > + > + instance->connected = 0; > + instance->state = state; > + mutex_init(&instance->bulk_waiter_list_mutex); > + INIT_LIST_HEAD(&instance->bulk_waiter_list); > + > + *instance_out = instance; > + > + status = VCHIQ_SUCCESS; > + > +failed: > + vchiq_log_trace(vchiq_core_log_level, > + "%s(%p): returning %d", __func__, instance, status); > + > + return status; > +} > +EXPORT_SYMBOL(vchiq_initialise); > + > +VCHIQ_STATUS_T vchiq_shutdown(VCHIQ_INSTANCE_T instance) > +{ > + VCHIQ_STATUS_T status; > + VCHIQ_STATE_T *state = instance->state; > + > + vchiq_log_trace(vchiq_core_log_level, > + "%s(%p) called", __func__, instance); > + > + if (mutex_lock_killable(&state->mutex) != 0) > + return VCHIQ_RETRY; > + > + /* Remove all services */ > + status = vchiq_shutdown_internal(state, instance); > + > + mutex_unlock(&state->mutex); > + > + vchiq_log_trace(vchiq_core_log_level, > + "%s(%p): returning %d", __func__, instance, status); > + > + if (status == VCHIQ_SUCCESS) { > + struct list_head *pos, *next; > + > + list_for_each_safe(pos, next, > + &instance->bulk_waiter_list) { > + struct bulk_waiter_node *waiter; > + > + waiter = list_entry(pos, > + struct bulk_waiter_node, > + list); > + list_del(pos); > + vchiq_log_info(vchiq_arm_log_level, > + "bulk_waiter - cleaned up %pK for pid %d", > + waiter, waiter->pid); > + kfree(waiter); > + } > + kfree(instance); > + } > + > + return status; > +} > +EXPORT_SYMBOL(vchiq_shutdown); > + > +static int vchiq_is_connected(VCHIQ_INSTANCE_T instance) > +{ > + return instance->connected; > +} > + > +VCHIQ_STATUS_T vchiq_connect(VCHIQ_INSTANCE_T instance) > +{ > + VCHIQ_STATUS_T status; > + VCHIQ_STATE_T *state = instance->state; > + > + vchiq_log_trace(vchiq_core_log_level, > + "%s(%p) called", __func__, instance); > + > + if (mutex_lock_killable(&state->mutex) != 0) { > + vchiq_log_trace(vchiq_core_log_level, > + "%s: call to mutex_lock failed", __func__); > + status = VCHIQ_RETRY; > + goto failed; > + } > + status = vchiq_connect_internal(state, instance); > + > + if (status == VCHIQ_SUCCESS) > + instance->connected = 1; > + > + mutex_unlock(&state->mutex); > + > +failed: > + vchiq_log_trace(vchiq_core_log_level, > + "%s(%p): returning %d", __func__, instance, status); > + > + return status; > +} > +EXPORT_SYMBOL(vchiq_connect); > + > +VCHIQ_STATUS_T vchiq_add_service( > + VCHIQ_INSTANCE_T instance, > + const VCHIQ_SERVICE_PARAMS_T *params, > + VCHIQ_SERVICE_HANDLE_T *phandle) > +{ > + VCHIQ_STATUS_T status; > + VCHIQ_STATE_T *state = instance->state; > + VCHIQ_SERVICE_T *service = NULL; > + int srvstate; > + > + vchiq_log_trace(vchiq_core_log_level, > + "%s(%p) called", __func__, instance); > + > + *phandle = VCHIQ_SERVICE_HANDLE_INVALID; > + > + srvstate = vchiq_is_connected(instance) > + ? VCHIQ_SRVSTATE_LISTENING > + : VCHIQ_SRVSTATE_HIDDEN; > + > + service = vchiq_add_service_internal( > + state, > + params, > + srvstate, > + instance, > + NULL); > + > + if (service) { > + *phandle = service->handle; > + status = VCHIQ_SUCCESS; > + } else > + status = VCHIQ_ERROR; > + > + vchiq_log_trace(vchiq_core_log_level, > + "%s(%p): returning %d", __func__, instance, status); > + > + return status; > +} > +EXPORT_SYMBOL(vchiq_add_service); > + > +VCHIQ_STATUS_T vchiq_open_service( > + VCHIQ_INSTANCE_T instance, > + const VCHIQ_SERVICE_PARAMS_T *params, > + VCHIQ_SERVICE_HANDLE_T *phandle) > +{ > + VCHIQ_STATUS_T status = VCHIQ_ERROR; > + VCHIQ_STATE_T *state = instance->state; > + VCHIQ_SERVICE_T *service = NULL; > + > + vchiq_log_trace(vchiq_core_log_level, > + "%s(%p) called", __func__, instance); > + > + *phandle = VCHIQ_SERVICE_HANDLE_INVALID; > + > + if (!vchiq_is_connected(instance)) > + goto failed; > + > + service = vchiq_add_service_internal(state, > + params, > + VCHIQ_SRVSTATE_OPENING, > + instance, > + NULL); > + > + if (service) { > + *phandle = service->handle; > + status = vchiq_open_service_internal(service, current->pid); > + if (status != VCHIQ_SUCCESS) { > + vchiq_remove_service(service->handle); > + *phandle = VCHIQ_SERVICE_HANDLE_INVALID; > + } > + } > + > +failed: > + vchiq_log_trace(vchiq_core_log_level, > + "%s(%p): returning %d", __func__, instance, status); > + > + return status; > +} > +EXPORT_SYMBOL(vchiq_open_service); > + > +VCHIQ_STATUS_T > +vchiq_queue_bulk_transmit(VCHIQ_SERVICE_HANDLE_T handle, > + const void *data, unsigned int size, void *userdata) > +{ > + return vchiq_bulk_transfer(handle, > + VCHI_MEM_HANDLE_INVALID, (void *)data, size, userdata, > + VCHIQ_BULK_MODE_CALLBACK, VCHIQ_BULK_TRANSMIT); > +} > +EXPORT_SYMBOL(vchiq_queue_bulk_transmit); > + > +VCHIQ_STATUS_T > +vchiq_queue_bulk_receive(VCHIQ_SERVICE_HANDLE_T handle, void *data, > + unsigned int size, void *userdata) > +{ > + return vchiq_bulk_transfer(handle, > + VCHI_MEM_HANDLE_INVALID, data, size, userdata, > + VCHIQ_BULK_MODE_CALLBACK, VCHIQ_BULK_RECEIVE); > +} > +EXPORT_SYMBOL(vchiq_queue_bulk_receive); > + > +VCHIQ_STATUS_T > +vchiq_bulk_transmit(VCHIQ_SERVICE_HANDLE_T handle, const void *data, > + unsigned int size, void *userdata, VCHIQ_BULK_MODE_T mode) > +{ > + VCHIQ_STATUS_T status; > + > + switch (mode) { > + case VCHIQ_BULK_MODE_NOCALLBACK: > + case VCHIQ_BULK_MODE_CALLBACK: > + status = vchiq_bulk_transfer(handle, > + VCHI_MEM_HANDLE_INVALID, (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; > + } > + > + return status; > +} > +EXPORT_SYMBOL(vchiq_bulk_transmit); > + > +VCHIQ_STATUS_T > +vchiq_bulk_receive(VCHIQ_SERVICE_HANDLE_T handle, void *data, > + unsigned int size, void *userdata, VCHIQ_BULK_MODE_T mode) > +{ > + VCHIQ_STATUS_T status; > + > + switch (mode) { > + case VCHIQ_BULK_MODE_NOCALLBACK: > + case VCHIQ_BULK_MODE_CALLBACK: > + status = vchiq_bulk_transfer(handle, > + VCHI_MEM_HANDLE_INVALID, 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; > + } > + > + return status; > +} > +EXPORT_SYMBOL(vchiq_bulk_receive); > + > +static VCHIQ_STATUS_T > +vchiq_blocking_bulk_transfer(VCHIQ_SERVICE_HANDLE_T handle, void *data, > + unsigned int size, VCHIQ_BULK_DIR_T dir) > +{ > + VCHIQ_INSTANCE_T instance; > + VCHIQ_SERVICE_T *service; > + VCHIQ_STATUS_T status; > + struct bulk_waiter_node *waiter = NULL; > + struct list_head *pos; > + > + service = find_service_by_handle(handle); > + if (!service) > + return VCHIQ_ERROR; > + > + instance = service->instance; > + > + unlock_service(service); > + > + mutex_lock(&instance->bulk_waiter_list_mutex); > + list_for_each(pos, &instance->bulk_waiter_list) { > + if (list_entry(pos, struct bulk_waiter_node, > + list)->pid == current->pid) { > + waiter = list_entry(pos, > + struct bulk_waiter_node, > + list); > + list_del(pos); > + break; > + } > + } > + mutex_unlock(&instance->bulk_waiter_list_mutex); > + > + if (waiter) { > + VCHIQ_BULK_T *bulk = waiter->bulk_waiter.bulk; > + > + if (bulk) { > + /* This thread has an outstanding bulk transfer. */ > + if ((bulk->data != data) || > + (bulk->size != size)) { > + /* This is not a retry of the previous one. > + * Cancel the signal when the transfer > + * completes. > + */ > + spin_lock(&bulk_waiter_spinlock); > + bulk->userdata = NULL; > + spin_unlock(&bulk_waiter_spinlock); > + } > + } > + } > + > + if (!waiter) { > + waiter = kzalloc(sizeof(struct bulk_waiter_node), GFP_KERNEL); > + if (!waiter) { > + vchiq_log_error(vchiq_core_log_level, > + "%s - out of memory", __func__); > + return VCHIQ_ERROR; > + } > + } > + > + status = vchiq_bulk_transfer(handle, VCHI_MEM_HANDLE_INVALID, > + data, size, &waiter->bulk_waiter, VCHIQ_BULK_MODE_BLOCKING, > + dir); > + if ((status != VCHIQ_RETRY) || fatal_signal_pending(current) || > + !waiter->bulk_waiter.bulk) { > + VCHIQ_BULK_T *bulk = waiter->bulk_waiter.bulk; > + > + if (bulk) { > + /* Cancel the signal when the transfer > + * completes. > + */ > + spin_lock(&bulk_waiter_spinlock); > + bulk->userdata = NULL; > + spin_unlock(&bulk_waiter_spinlock); > + } > + kfree(waiter); > + } else { > + waiter->pid = current->pid; > + mutex_lock(&instance->bulk_waiter_list_mutex); > + list_add(&waiter->list, &instance->bulk_waiter_list); > + mutex_unlock(&instance->bulk_waiter_list_mutex); > + vchiq_log_info(vchiq_arm_log_level, > + "saved bulk_waiter %pK for pid %d", > + waiter, current->pid); > + } > + > + return status; > +} > /**************************************************************************** > * > * add_completion > 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 > deleted file mode 100644 > index 43c89a08bda9..000000000000 > --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_kern_lib.c > +++ /dev/null > @@ -1,431 +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. > - */ > - > -/* ---- Include Files ---------------------------------------------------- */ > - > -#include <linux/kernel.h> > -#include <linux/module.h> > -#include <linux/mutex.h> > - > -#include "vchiq_core.h" > -#include "vchiq_arm.h" > -#include "vchiq_killable.h" > - > -/* ---- Public Variables ------------------------------------------------- */ > - > -/* ---- Private Constants and Types -------------------------------------- */ > - > -struct bulk_waiter_node { > - struct bulk_waiter bulk_waiter; > - int pid; > - struct list_head list; > -}; > - > -struct vchiq_instance_struct { > - VCHIQ_STATE_T *state; > - > - int connected; > - > - struct list_head bulk_waiter_list; > - struct mutex bulk_waiter_list_mutex; > -}; > - > -static VCHIQ_STATUS_T > -vchiq_blocking_bulk_transfer(VCHIQ_SERVICE_HANDLE_T handle, void *data, > - unsigned int size, VCHIQ_BULK_DIR_T dir); > - > -#define VCHIQ_INIT_RETRIES 10 > -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; > - > - 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++) { > - state = vchiq_get_state(); > - if (state) > - break; > - udelay(500); > - } > - if (i == VCHIQ_INIT_RETRIES) { > - vchiq_log_error(vchiq_core_log_level, > - "%s: videocore not initialized\n", __func__); > - goto failed; > - } else if (i > 0) { > - vchiq_log_warning(vchiq_core_log_level, > - "%s: videocore initialized after %d retries\n", > - __func__, i); > - } > - > - instance = kzalloc(sizeof(*instance), GFP_KERNEL); > - if (!instance) { > - vchiq_log_error(vchiq_core_log_level, > - "%s: error allocating vchiq instance\n", __func__); > - goto failed; > - } > - > - instance->connected = 0; > - instance->state = state; > - mutex_init(&instance->bulk_waiter_list_mutex); > - INIT_LIST_HEAD(&instance->bulk_waiter_list); > - > - *instance_out = instance; > - > - status = VCHIQ_SUCCESS; > - > -failed: > - vchiq_log_trace(vchiq_core_log_level, > - "%s(%p): returning %d", __func__, instance, status); > - > - return status; > -} > -EXPORT_SYMBOL(vchiq_initialise); > - > -VCHIQ_STATUS_T vchiq_shutdown(VCHIQ_INSTANCE_T instance) > -{ > - VCHIQ_STATUS_T status; > - VCHIQ_STATE_T *state = instance->state; > - > - vchiq_log_trace(vchiq_core_log_level, > - "%s(%p) called", __func__, instance); > - > - if (mutex_lock_killable(&state->mutex) != 0) > - return VCHIQ_RETRY; > - > - /* Remove all services */ > - status = vchiq_shutdown_internal(state, instance); > - > - mutex_unlock(&state->mutex); > - > - vchiq_log_trace(vchiq_core_log_level, > - "%s(%p): returning %d", __func__, instance, status); > - > - if (status == VCHIQ_SUCCESS) { > - struct list_head *pos, *next; > - > - list_for_each_safe(pos, next, > - &instance->bulk_waiter_list) { > - struct bulk_waiter_node *waiter; > - > - waiter = list_entry(pos, > - struct bulk_waiter_node, > - list); > - list_del(pos); > - vchiq_log_info(vchiq_arm_log_level, > - "bulk_waiter - cleaned up %pK for pid %d", > - waiter, waiter->pid); > - kfree(waiter); > - } > - kfree(instance); > - } > - > - return status; > -} > -EXPORT_SYMBOL(vchiq_shutdown); > - > -static int vchiq_is_connected(VCHIQ_INSTANCE_T instance) > -{ > - return instance->connected; > -} > - > -VCHIQ_STATUS_T vchiq_connect(VCHIQ_INSTANCE_T instance) > -{ > - VCHIQ_STATUS_T status; > - VCHIQ_STATE_T *state = instance->state; > - > - vchiq_log_trace(vchiq_core_log_level, > - "%s(%p) called", __func__, instance); > - > - if (mutex_lock_killable(&state->mutex) != 0) { > - vchiq_log_trace(vchiq_core_log_level, > - "%s: call to mutex_lock failed", __func__); > - status = VCHIQ_RETRY; > - goto failed; > - } > - status = vchiq_connect_internal(state, instance); > - > - if (status == VCHIQ_SUCCESS) > - instance->connected = 1; > - > - mutex_unlock(&state->mutex); > - > -failed: > - vchiq_log_trace(vchiq_core_log_level, > - "%s(%p): returning %d", __func__, instance, status); > - > - return status; > -} > -EXPORT_SYMBOL(vchiq_connect); > - > -VCHIQ_STATUS_T vchiq_add_service( > - VCHIQ_INSTANCE_T instance, > - const VCHIQ_SERVICE_PARAMS_T *params, > - VCHIQ_SERVICE_HANDLE_T *phandle) > -{ > - VCHIQ_STATUS_T status; > - VCHIQ_STATE_T *state = instance->state; > - VCHIQ_SERVICE_T *service = NULL; > - int srvstate; > - > - vchiq_log_trace(vchiq_core_log_level, > - "%s(%p) called", __func__, instance); > - > - *phandle = VCHIQ_SERVICE_HANDLE_INVALID; > - > - srvstate = vchiq_is_connected(instance) > - ? VCHIQ_SRVSTATE_LISTENING > - : VCHIQ_SRVSTATE_HIDDEN; > - > - service = vchiq_add_service_internal( > - state, > - params, > - srvstate, > - instance, > - NULL); > - > - if (service) { > - *phandle = service->handle; > - status = VCHIQ_SUCCESS; > - } else > - status = VCHIQ_ERROR; > - > - vchiq_log_trace(vchiq_core_log_level, > - "%s(%p): returning %d", __func__, instance, status); > - > - return status; > -} > -EXPORT_SYMBOL(vchiq_add_service); > - > -VCHIQ_STATUS_T vchiq_open_service( > - VCHIQ_INSTANCE_T instance, > - const VCHIQ_SERVICE_PARAMS_T *params, > - VCHIQ_SERVICE_HANDLE_T *phandle) > -{ > - VCHIQ_STATUS_T status = VCHIQ_ERROR; > - VCHIQ_STATE_T *state = instance->state; > - VCHIQ_SERVICE_T *service = NULL; > - > - vchiq_log_trace(vchiq_core_log_level, > - "%s(%p) called", __func__, instance); > - > - *phandle = VCHIQ_SERVICE_HANDLE_INVALID; > - > - if (!vchiq_is_connected(instance)) > - goto failed; > - > - service = vchiq_add_service_internal(state, > - params, > - VCHIQ_SRVSTATE_OPENING, > - instance, > - NULL); > - > - if (service) { > - *phandle = service->handle; > - status = vchiq_open_service_internal(service, current->pid); > - if (status != VCHIQ_SUCCESS) { > - vchiq_remove_service(service->handle); > - *phandle = VCHIQ_SERVICE_HANDLE_INVALID; > - } > - } > - > -failed: > - vchiq_log_trace(vchiq_core_log_level, > - "%s(%p): returning %d", __func__, instance, status); > - > - return status; > -} > -EXPORT_SYMBOL(vchiq_open_service); > - > -VCHIQ_STATUS_T > -vchiq_queue_bulk_transmit(VCHIQ_SERVICE_HANDLE_T handle, > - const void *data, unsigned int size, void *userdata) > -{ > - return vchiq_bulk_transfer(handle, > - VCHI_MEM_HANDLE_INVALID, (void *)data, size, userdata, > - VCHIQ_BULK_MODE_CALLBACK, VCHIQ_BULK_TRANSMIT); > -} > -EXPORT_SYMBOL(vchiq_queue_bulk_transmit); > - > -VCHIQ_STATUS_T > -vchiq_queue_bulk_receive(VCHIQ_SERVICE_HANDLE_T handle, void *data, > - unsigned int size, void *userdata) > -{ > - return vchiq_bulk_transfer(handle, > - VCHI_MEM_HANDLE_INVALID, data, size, userdata, > - VCHIQ_BULK_MODE_CALLBACK, VCHIQ_BULK_RECEIVE); > -} > -EXPORT_SYMBOL(vchiq_queue_bulk_receive); > - > -VCHIQ_STATUS_T > -vchiq_bulk_transmit(VCHIQ_SERVICE_HANDLE_T handle, const void *data, > - unsigned int size, void *userdata, VCHIQ_BULK_MODE_T mode) > -{ > - VCHIQ_STATUS_T status; > - > - switch (mode) { > - case VCHIQ_BULK_MODE_NOCALLBACK: > - case VCHIQ_BULK_MODE_CALLBACK: > - status = vchiq_bulk_transfer(handle, > - VCHI_MEM_HANDLE_INVALID, (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; > - } > - > - return status; > -} > -EXPORT_SYMBOL(vchiq_bulk_transmit); > - > -VCHIQ_STATUS_T > -vchiq_bulk_receive(VCHIQ_SERVICE_HANDLE_T handle, void *data, > - unsigned int size, void *userdata, VCHIQ_BULK_MODE_T mode) > -{ > - VCHIQ_STATUS_T status; > - > - switch (mode) { > - case VCHIQ_BULK_MODE_NOCALLBACK: > - case VCHIQ_BULK_MODE_CALLBACK: > - status = vchiq_bulk_transfer(handle, > - VCHI_MEM_HANDLE_INVALID, 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; > - } > - > - return status; > -} > -EXPORT_SYMBOL(vchiq_bulk_receive); > - > -static VCHIQ_STATUS_T > -vchiq_blocking_bulk_transfer(VCHIQ_SERVICE_HANDLE_T handle, void *data, > - unsigned int size, VCHIQ_BULK_DIR_T dir) > -{ > - VCHIQ_INSTANCE_T instance; > - VCHIQ_SERVICE_T *service; > - VCHIQ_STATUS_T status; > - struct bulk_waiter_node *waiter = NULL; > - struct list_head *pos; > - > - service = find_service_by_handle(handle); > - if (!service) > - return VCHIQ_ERROR; > - > - instance = service->instance; > - > - unlock_service(service); > - > - mutex_lock(&instance->bulk_waiter_list_mutex); > - list_for_each(pos, &instance->bulk_waiter_list) { > - if (list_entry(pos, struct bulk_waiter_node, > - list)->pid == current->pid) { > - waiter = list_entry(pos, > - struct bulk_waiter_node, > - list); > - list_del(pos); > - break; > - } > - } > - mutex_unlock(&instance->bulk_waiter_list_mutex); > - > - if (waiter) { > - VCHIQ_BULK_T *bulk = waiter->bulk_waiter.bulk; > - > - if (bulk) { > - /* This thread has an outstanding bulk transfer. */ > - if ((bulk->data != data) || > - (bulk->size != size)) { > - /* This is not a retry of the previous one. > - * Cancel the signal when the transfer > - * completes. > - */ > - spin_lock(&bulk_waiter_spinlock); > - bulk->userdata = NULL; > - spin_unlock(&bulk_waiter_spinlock); > - } > - } > - } > - > - if (!waiter) { > - waiter = kzalloc(sizeof(struct bulk_waiter_node), GFP_KERNEL); > - if (!waiter) { > - vchiq_log_error(vchiq_core_log_level, > - "%s - out of memory", __func__); > - return VCHIQ_ERROR; > - } > - } > - > - status = vchiq_bulk_transfer(handle, VCHI_MEM_HANDLE_INVALID, > - data, size, &waiter->bulk_waiter, VCHIQ_BULK_MODE_BLOCKING, > - dir); > - if ((status != VCHIQ_RETRY) || fatal_signal_pending(current) || > - !waiter->bulk_waiter.bulk) { > - VCHIQ_BULK_T *bulk = waiter->bulk_waiter.bulk; > - > - if (bulk) { > - /* Cancel the signal when the transfer > - * completes. > - */ > - spin_lock(&bulk_waiter_spinlock); > - bulk->userdata = NULL; > - spin_unlock(&bulk_waiter_spinlock); > - } > - kfree(waiter); > - } else { > - waiter->pid = current->pid; > - mutex_lock(&instance->bulk_waiter_list_mutex); > - list_add(&waiter->list, &instance->bulk_waiter_list); > - mutex_unlock(&instance->bulk_waiter_list_mutex); > - vchiq_log_info(vchiq_arm_log_level, > - "saved bulk_waiter %pK for pid %d", > - waiter, current->pid); > - } > - > - return status; > -} > -- > 2.9.0 > > > _______________________________________________ > linux-arm-kernel mailing list > linux-arm-kernel@xxxxxxxxxxxxxxxxxxx > http://lists.infradead.org/mailman/listinfo/linux-arm-kernel _______________________________________________ devel mailing list devel@xxxxxxxxxxxxxxxxxxxxxx http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel