aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging/vc04_services/interface
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/vc04_services/interface')
-rw-r--r--drivers/staging/vc04_services/interface/TESTING82
-rw-r--r--drivers/staging/vc04_services/interface/TODO60
-rw-r--r--drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c181
-rw-r--r--drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h8
-rw-r--r--drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c243
-rw-r--r--drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h43
-rw-r--r--drivers/staging/vc04_services/interface/vchiq_arm/vchiq_debugfs.c4
-rw-r--r--drivers/staging/vc04_services/interface/vchiq_arm/vchiq_dev.c60
8 files changed, 372 insertions, 309 deletions
diff --git a/drivers/staging/vc04_services/interface/TESTING b/drivers/staging/vc04_services/interface/TESTING
new file mode 100644
index 000000000000..a6d63efcbcb9
--- /dev/null
+++ b/drivers/staging/vc04_services/interface/TESTING
@@ -0,0 +1,82 @@
+This document contains some hints to test the function of the VCHIQ driver
+without having additional hardware to the Raspberry Pi.
+
+* Requirements & limitations
+
+Testing the VCHIQ driver requires a Raspberry Pi with one of the following SoC:
+ - BCM2835 ( e.g. Raspberry Pi Zero W )
+ - BCM2836 ( e.g. Raspberry Pi 2 )
+ - BCM2837 ( e.g. Raspberry Pi 3 B+ )
+
+The BCM2711 used in the Raspberry Pi 4 is currently not supported in the
+mainline kernel.
+
+There are no specific requirements to the VideoCore firmware to get VCHIQ
+working.
+
+The test scenarios described in this document based on the tool vchiq_test.
+Its source code is available here: https://github.com/raspberrypi/userland
+
+* Configuration
+
+Here are the most common kernel configurations:
+
+ 1. BCM2835 target SoC (ARM 32 bit)
+
+ Just use bcm2835_defconfig which already has VCHIQ enabled.
+
+ 2. BCM2836/7 target SoC (ARM 32 bit)
+
+ Use the multi_v7_defconfig as a base and then enable all VCHIQ options.
+
+ 3. BCM2837 target SoC (ARM 64 bit)
+
+ Use the defconfig as a base and then enable all VCHIQ options.
+
+* Scenarios
+
+ * Initial test
+
+ Check the driver is probed and /dev/vchiq is created
+
+ * Functional test
+
+ Command: vchiq_test -f 10
+
+ Expected output:
+ Functional test - iters:10
+ ======== iteration 1 ========
+ Testing bulk transfer for alignment.
+ Testing bulk transfer at PAGE_SIZE.
+ ...
+
+ * Ping test
+
+ Command: vchiq_test -p 1
+
+ Expected output:
+ Ping test - service:echo, iters:1, version 3
+ vchi ping (size 0) -> 57.000000us
+ vchi ping (size 0, 0 async, 0 oneway) -> 122.000000us
+ vchi bulk (size 0, 0 async, 0 oneway) -> 546.000000us
+ vchi bulk (size 0, 0 oneway) -> 230.000000us
+ vchi ping (size 0) -> 49.000000us
+ vchi ping (size 0, 0 async, 0 oneway) -> 70.000000us
+ vchi bulk (size 0, 0 async, 0 oneway) -> 296.000000us
+ vchi bulk (size 0, 0 oneway) -> 266.000000us
+ vchi ping (size 0, 1 async, 0 oneway) -> 65.000000us
+ vchi bulk (size 0, 0 oneway) -> 456.000000us
+ vchi ping (size 0, 2 async, 0 oneway) -> 74.000000us
+ vchi bulk (size 0, 0 oneway) -> 640.000000us
+ vchi ping (size 0, 10 async, 0 oneway) -> 125.000000us
+ vchi bulk (size 0, 0 oneway) -> 2309.000000us
+ vchi ping (size 0, 0 async, 1 oneway) -> 70.000000us
+ vchi ping (size 0, 0 async, 2 oneway) -> 76.000000us
+ vchi ping (size 0, 0 async, 10 oneway) -> 105.000000us
+ vchi ping (size 0, 10 async, 10 oneway) -> 165.000000us
+ vchi ping (size 0, 100 async, 0 oneway) -> nanus
+ vchi bulk (size 0, 0 oneway) -> nanus
+ vchi ping (size 0, 0 async, 100 oneway) -> nanus
+ vchi ping (size 0, 100 async, 100 oneway) -> infus
+ vchi ping (size 0, 200 async, 0 oneway) -> infus
+ ...
diff --git a/drivers/staging/vc04_services/interface/TODO b/drivers/staging/vc04_services/interface/TODO
index 39810ce017cd..97085a0b3223 100644
--- a/drivers/staging/vc04_services/interface/TODO
+++ b/drivers/staging/vc04_services/interface/TODO
@@ -1,4 +1,4 @@
-1) Import drivers using VCHI.
+* Import drivers using VCHI.
VCHI is just a tool to let drivers talk to the firmware. Here are
some of the ones we want:
@@ -16,75 +16,42 @@ some of the ones we want:
to manage these buffers as dmabufs so that we can zero-copy import
camera images into vc4 for rendering/display.
-2) Garbage-collect unused code
-
-One of the reasons this driver wasn't upstreamed previously was that
-there's a lot code that got built that's probably unnecessary these
-days. Once we have the set of VCHI-using drivers we want in tree, we
-should be able to do a sweep of the code to see what's left that's
-unused.
-
-3) Make driver more portable
-
-Building this driver with arm/multi_v7_defconfig or arm64/defconfig
-leads to data corruption during the following command:
-
- vchiq_test -f 1
-
-This should be fixed.
-
-4) Fix kernel module support
+* Fix kernel module support
Even the VPU firmware doesn't support a VCHI re-connect, the driver
should properly handle a module unload. This also includes that all
resources must be freed (kthreads, debugfs entries, ...) and global
variables avoided.
-5) Cleanup logging mechanism
+* Cleanup logging mechanism
The driver should probably be using the standard kernel logging mechanisms
such as dev_info, dev_dbg, and friends.
-6) Documentation
+* Documentation
A short top-down description of this driver's architecture (function of
kthreads, userspace, limitations) could be very helpful for reviewers.
-7) Review and comment memory barriers
+* Review and comment memory barriers
There is a heavy use of memory barriers in this driver, it would be very
beneficial to go over all of them and, if correct, comment on their merits.
Extra points to whomever confidently reviews the remote_event_*() family of
functions.
-8) Get rid of custom function return values
+* Get rid of custom function return values
Most functions use a custom set of return values, we should force proper Linux
error numbers. Special care is needed for VCHIQ_RETRY.
-9) Reformat core code with more sane indentations
+* Reformat core code with more sane indentations
The code follows the 80 characters limitation yet tends to go 3 or 4 levels of
indentation deep making it very unpleasant to read. This is specially relevant
in the character driver ioctl code and in the core thread functions.
-10) Reorganize file structure: Move char driver to it's own file and join both
-platform files
-
-The cdev is defined alongside with the platform code in vchiq_arm.c. It would
-be nice to completely decouple it from the actual core code. For instance to be
-able to use bcm2835-audio without having /dev/vchiq created. One could argue
-it's better for security reasons or general cleanliness. It could even be
-interesting to create two different kernel modules, something the likes of
-vchiq-core.ko and vchiq-dev.ko. This would also ease the upstreaming process.
-
-The code in vchiq_bcm2835_arm.c should fit in the generic platform file.
-
-12) Get rid of all the struct typedefs
-
-Most structs are typedefd, it's not encouraged in the kernel.
-
-13) Get rid of all non essential global structures and create a proper per
+* Get rid of all non essential global structures and create a proper per
device structure
The first thing one generally sees in a probe function is a memory allocation
@@ -92,6 +59,15 @@ for all the device specific data. This structure is then passed all over the
driver. This is good practice since it makes the driver work regardless of the
number of devices probed.
-14) Clean up Sparse warnings from __user annotations. See
+* Clean up Sparse warnings from __user annotations. See
vchiq_irq_queue_bulk_tx_rx(). Ensure that the address of "&waiter->bulk_waiter"
is never disclosed to userspace.
+
+* Fix behavior of message handling
+
+The polling behavior of vchiq_bulk_transmit(), vchiq_bulk_receive() and
+vchiq_queue_kernel_message() looks broken. A possible signal should be
+propagated back to user space to let the calling task handle it before
+retrying. Hopefully these msleep(1) shouldn't be necessary anymore.
+
+https://lore.kernel.org/linux-staging/CAK8P3a3HGm1cPo4sW9fOY4E8AN8yAq3tevXxU5m8bmtmsU8WKw@mail.gmail.com/
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 c650a32bcedf..dc33490ba7fb 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
@@ -148,12 +148,11 @@ static unsigned int g_fragments_size;
static char *g_fragments_base;
static char *g_free_fragments;
static struct semaphore g_free_fragments_sema;
-static struct device *g_dev;
static DEFINE_SEMAPHORE(g_free_fragments_mutex);
static enum vchiq_status
-vchiq_blocking_bulk_transfer(unsigned int handle, void *data,
+vchiq_blocking_bulk_transfer(struct vchiq_instance *instance, unsigned int handle, void *data,
unsigned int size, enum vchiq_bulk_dir dir);
static irqreturn_t
@@ -175,20 +174,34 @@ vchiq_doorbell_irq(int irq, void *dev_id)
}
static void
-cleanup_pagelistinfo(struct vchiq_pagelist_info *pagelistinfo)
+cleanup_pagelistinfo(struct vchiq_instance *instance, struct vchiq_pagelist_info *pagelistinfo)
{
if (pagelistinfo->scatterlist_mapped) {
- dma_unmap_sg(g_dev, pagelistinfo->scatterlist,
+ dma_unmap_sg(instance->state->dev, pagelistinfo->scatterlist,
pagelistinfo->num_pages, pagelistinfo->dma_dir);
}
if (pagelistinfo->pages_need_release)
unpin_user_pages(pagelistinfo->pages, pagelistinfo->num_pages);
- dma_free_coherent(g_dev, pagelistinfo->pagelist_buffer_size,
+ dma_free_coherent(instance->state->dev, pagelistinfo->pagelist_buffer_size,
pagelistinfo->pagelist, pagelistinfo->dma_addr);
}
+static inline bool
+is_adjacent_block(u32 *addrs, u32 addr, unsigned int k)
+{
+ u32 tmp;
+
+ if (!k)
+ return false;
+
+ tmp = (addrs[k - 1] & PAGE_MASK) +
+ (((addrs[k - 1] & ~PAGE_MASK) + 1) << PAGE_SHIFT);
+
+ return tmp == (addr & PAGE_MASK);
+}
+
/* There is a potential problem with partial cache lines (pages?)
* at the ends of the block when reading. If the CPU accessed anything in
* the same line (page?) then it may have pulled old data into the cache,
@@ -198,7 +211,7 @@ cleanup_pagelistinfo(struct vchiq_pagelist_info *pagelistinfo)
*/
static struct vchiq_pagelist_info *
-create_pagelist(char *buf, char __user *ubuf,
+create_pagelist(struct vchiq_instance *instance, char *buf, char __user *ubuf,
size_t count, unsigned short type)
{
struct pagelist *pagelist;
@@ -236,7 +249,7 @@ create_pagelist(char *buf, char __user *ubuf,
/* Allocate enough storage to hold the page pointers and the page
* list
*/
- pagelist = dma_alloc_coherent(g_dev, pagelist_size, &dma_addr,
+ pagelist = dma_alloc_coherent(instance->state->dev, pagelist_size, &dma_addr,
GFP_KERNEL);
vchiq_log_trace(vchiq_arm_log_level, "%s - %pK", __func__, pagelist);
@@ -278,7 +291,7 @@ create_pagelist(char *buf, char __user *ubuf,
size_t bytes = PAGE_SIZE - off;
if (!pg) {
- cleanup_pagelistinfo(pagelistinfo);
+ cleanup_pagelistinfo(instance, pagelistinfo);
return NULL;
}
@@ -301,7 +314,7 @@ create_pagelist(char *buf, char __user *ubuf,
/* This is probably due to the process being killed */
if (actual_pages > 0)
unpin_user_pages(pages, actual_pages);
- cleanup_pagelistinfo(pagelistinfo);
+ cleanup_pagelistinfo(instance, pagelistinfo);
return NULL;
}
/* release user pages */
@@ -324,13 +337,13 @@ create_pagelist(char *buf, char __user *ubuf,
count -= len;
}
- dma_buffers = dma_map_sg(g_dev,
+ dma_buffers = dma_map_sg(instance->state->dev,
scatterlist,
num_pages,
pagelistinfo->dma_dir);
if (dma_buffers == 0) {
- cleanup_pagelistinfo(pagelistinfo);
+ cleanup_pagelistinfo(instance, pagelistinfo);
return NULL;
}
@@ -349,10 +362,7 @@ create_pagelist(char *buf, char __user *ubuf,
WARN_ON(len == 0);
WARN_ON(i && (i != (dma_buffers - 1)) && (len & ~PAGE_MASK));
WARN_ON(i && (addr & ~PAGE_MASK));
- if (k > 0 &&
- ((addrs[k - 1] & PAGE_MASK) +
- (((addrs[k - 1] & ~PAGE_MASK) + 1) << PAGE_SHIFT))
- == (addr & PAGE_MASK))
+ if (is_adjacent_block(addrs, addr, k))
addrs[k - 1] += ((len + PAGE_SIZE - 1) >> PAGE_SHIFT);
else
addrs[k++] = (addr & PAGE_MASK) |
@@ -367,7 +377,7 @@ create_pagelist(char *buf, char __user *ubuf,
char *fragments;
if (down_interruptible(&g_free_fragments_sema)) {
- cleanup_pagelistinfo(pagelistinfo);
+ cleanup_pagelistinfo(instance, pagelistinfo);
return NULL;
}
@@ -386,7 +396,7 @@ create_pagelist(char *buf, char __user *ubuf,
}
static void
-free_pagelist(struct vchiq_pagelist_info *pagelistinfo,
+free_pagelist(struct vchiq_instance *instance, struct vchiq_pagelist_info *pagelistinfo,
int actual)
{
struct pagelist *pagelist = pagelistinfo->pagelist;
@@ -400,7 +410,7 @@ free_pagelist(struct vchiq_pagelist_info *pagelistinfo,
* NOTE: dma_unmap_sg must be called before the
* cpu can touch any of the data/pages.
*/
- dma_unmap_sg(g_dev, pagelistinfo->scatterlist,
+ dma_unmap_sg(instance->state->dev, pagelistinfo->scatterlist,
pagelistinfo->num_pages, pagelistinfo->dma_dir);
pagelistinfo->scatterlist_mapped = 0;
@@ -420,21 +430,18 @@ free_pagelist(struct vchiq_pagelist_info *pagelistinfo,
if (head_bytes > actual)
head_bytes = actual;
- memcpy((char *)kmap(pages[0]) +
+ memcpy_to_page(pages[0],
pagelist->offset,
fragments,
head_bytes);
- kunmap(pages[0]);
}
if ((actual >= 0) && (head_bytes < actual) &&
- (tail_bytes != 0)) {
- memcpy((char *)kmap(pages[num_pages - 1]) +
- ((pagelist->offset + actual) &
- (PAGE_SIZE - 1) & ~(g_cache_line_size - 1)),
+ (tail_bytes != 0))
+ memcpy_to_page(pages[num_pages - 1],
+ (pagelist->offset + actual) &
+ (PAGE_SIZE - 1) & ~(g_cache_line_size - 1),
fragments + g_cache_line_size,
tail_bytes);
- kunmap(pages[num_pages - 1]);
- }
down(&g_free_fragments_mutex);
*(char **)fragments = g_free_fragments;
@@ -452,7 +459,7 @@ free_pagelist(struct vchiq_pagelist_info *pagelistinfo,
set_page_dirty(pages[i]);
}
- cleanup_pagelistinfo(pagelistinfo);
+ cleanup_pagelistinfo(instance, pagelistinfo);
}
int vchiq_platform_init(struct platform_device *pdev, struct vchiq_state *state)
@@ -511,7 +518,7 @@ int vchiq_platform_init(struct platform_device *pdev, struct vchiq_state *state)
*(char **)&g_fragments_base[i * g_fragments_size] = NULL;
sema_init(&g_free_fragments_sema, MAX_FRAGMENTS);
- err = vchiq_init_state(state, vchiq_slot_zero);
+ err = vchiq_init_state(state, vchiq_slot_zero, dev);
if (err)
return err;
@@ -539,7 +546,6 @@ int vchiq_platform_init(struct platform_device *pdev, struct vchiq_state *state)
return err ? : -ENXIO;
}
- g_dev = dev;
vchiq_log_info(vchiq_arm_log_level, "vchiq_init - done (slots %pK, phys %pad)",
vchiq_slot_zero, &slot_phys);
@@ -582,8 +588,7 @@ vchiq_platform_init_state(struct vchiq_state *state)
return 0;
}
-struct vchiq_arm_state*
-vchiq_platform_get_arm_state(struct vchiq_state *state)
+static struct vchiq_arm_state *vchiq_platform_get_arm_state(struct vchiq_state *state)
{
struct vchiq_2835_state *platform_state;
@@ -597,6 +602,10 @@ vchiq_platform_get_arm_state(struct vchiq_state *state)
void
remote_event_signal(struct remote_event *event)
{
+ /*
+ * Ensure that all writes to shared data structures have completed
+ * before signalling the peer.
+ */
wmb();
event->fired = 1;
@@ -608,12 +617,12 @@ remote_event_signal(struct remote_event *event)
}
int
-vchiq_prepare_bulk_data(struct vchiq_bulk *bulk, void *offset,
+vchiq_prepare_bulk_data(struct vchiq_instance *instance, struct vchiq_bulk *bulk, void *offset,
void __user *uoffset, int size, int dir)
{
struct vchiq_pagelist_info *pagelistinfo;
- pagelistinfo = create_pagelist(offset, uoffset, size,
+ pagelistinfo = create_pagelist(instance, offset, uoffset, size,
(dir == VCHIQ_BULK_RECEIVE)
? PAGELIST_READ
: PAGELIST_WRITE);
@@ -633,10 +642,10 @@ vchiq_prepare_bulk_data(struct vchiq_bulk *bulk, void *offset,
}
void
-vchiq_complete_bulk(struct vchiq_bulk *bulk)
+vchiq_complete_bulk(struct vchiq_instance *instance, struct vchiq_bulk *bulk)
{
if (bulk && bulk->remote_data && bulk->actual)
- free_pagelist((struct vchiq_pagelist_info *)bulk->remote_data,
+ free_pagelist(instance, (struct vchiq_pagelist_info *)bulk->remote_data,
bulk->actual);
}
@@ -814,7 +823,7 @@ vchiq_open_service(struct vchiq_instance *instance,
*phandle = service->handle;
status = vchiq_open_service_internal(service, current->pid);
if (status != VCHIQ_SUCCESS) {
- vchiq_remove_service(service->handle);
+ vchiq_remove_service(instance, service->handle);
*phandle = VCHIQ_SERVICE_HANDLE_INVALID;
}
}
@@ -827,8 +836,8 @@ failed:
EXPORT_SYMBOL(vchiq_open_service);
enum vchiq_status
-vchiq_bulk_transmit(unsigned int handle, const void *data, unsigned int size,
- void *userdata, enum vchiq_bulk_mode mode)
+vchiq_bulk_transmit(struct vchiq_instance *instance, unsigned int handle, const void *data,
+ unsigned int size, void *userdata, enum vchiq_bulk_mode mode)
{
enum vchiq_status status;
@@ -836,13 +845,13 @@ vchiq_bulk_transmit(unsigned int handle, const void *data, unsigned int size,
switch (mode) {
case VCHIQ_BULK_MODE_NOCALLBACK:
case VCHIQ_BULK_MODE_CALLBACK:
- status = vchiq_bulk_transfer(handle,
+ status = vchiq_bulk_transfer(instance, handle,
(void *)data, NULL,
size, userdata, mode,
VCHIQ_BULK_TRANSMIT);
break;
case VCHIQ_BULK_MODE_BLOCKING:
- status = vchiq_blocking_bulk_transfer(handle, (void *)data, size,
+ status = vchiq_blocking_bulk_transfer(instance, handle, (void *)data, size,
VCHIQ_BULK_TRANSMIT);
break;
default:
@@ -864,8 +873,8 @@ vchiq_bulk_transmit(unsigned int handle, const void *data, unsigned int size,
}
EXPORT_SYMBOL(vchiq_bulk_transmit);
-enum vchiq_status vchiq_bulk_receive(unsigned int handle, void *data,
- unsigned int size, void *userdata,
+enum vchiq_status vchiq_bulk_receive(struct vchiq_instance *instance, unsigned int handle,
+ void *data, unsigned int size, void *userdata,
enum vchiq_bulk_mode mode)
{
enum vchiq_status status;
@@ -874,12 +883,12 @@ enum vchiq_status vchiq_bulk_receive(unsigned int handle, void *data,
switch (mode) {
case VCHIQ_BULK_MODE_NOCALLBACK:
case VCHIQ_BULK_MODE_CALLBACK:
- status = vchiq_bulk_transfer(handle, data, NULL,
+ status = vchiq_bulk_transfer(instance, handle, data, NULL,
size, userdata,
mode, VCHIQ_BULK_RECEIVE);
break;
case VCHIQ_BULK_MODE_BLOCKING:
- status = vchiq_blocking_bulk_transfer(handle, (void *)data, size,
+ status = vchiq_blocking_bulk_transfer(instance, handle, (void *)data, size,
VCHIQ_BULK_RECEIVE);
break;
default:
@@ -902,34 +911,30 @@ enum vchiq_status vchiq_bulk_receive(unsigned int handle, void *data,
EXPORT_SYMBOL(vchiq_bulk_receive);
static enum vchiq_status
-vchiq_blocking_bulk_transfer(unsigned int handle, void *data, unsigned int size,
- enum vchiq_bulk_dir dir)
+vchiq_blocking_bulk_transfer(struct vchiq_instance *instance, unsigned int handle, void *data,
+ unsigned int size, enum vchiq_bulk_dir dir)
{
- struct vchiq_instance *instance;
struct vchiq_service *service;
enum vchiq_status status;
- struct bulk_waiter_node *waiter = NULL;
- bool found = false;
+ struct bulk_waiter_node *waiter = NULL, *iter;
- service = find_service_by_handle(handle);
+ service = find_service_by_handle(instance, handle);
if (!service)
return VCHIQ_ERROR;
- instance = service->instance;
-
vchiq_service_put(service);
mutex_lock(&instance->bulk_waiter_list_mutex);
- list_for_each_entry(waiter, &instance->bulk_waiter_list, list) {
- if (waiter->pid == current->pid) {
- list_del(&waiter->list);
- found = true;
+ list_for_each_entry(iter, &instance->bulk_waiter_list, list) {
+ if (iter->pid == current->pid) {
+ list_del(&iter->list);
+ waiter = iter;
break;
}
}
mutex_unlock(&instance->bulk_waiter_list_mutex);
- if (found) {
+ if (waiter) {
struct vchiq_bulk *bulk = waiter->bulk_waiter.bulk;
if (bulk) {
@@ -953,7 +958,7 @@ vchiq_blocking_bulk_transfer(unsigned int handle, void *data, unsigned int size,
}
}
- status = vchiq_bulk_transfer(handle, data, NULL, size,
+ status = vchiq_bulk_transfer(instance, handle, data, NULL, size,
&waiter->bulk_waiter,
VCHIQ_BULK_MODE_BLOCKING, dir);
if ((status != VCHIQ_RETRY) || fatal_signal_pending(current) || !waiter->bulk_waiter.bulk) {
@@ -1040,8 +1045,8 @@ add_completion(struct vchiq_instance *instance, enum vchiq_reason reason,
}
enum vchiq_status
-service_callback(enum vchiq_reason reason, struct vchiq_header *header,
- unsigned int handle, void *bulk_userdata)
+service_callback(struct vchiq_instance *instance, enum vchiq_reason reason,
+ struct vchiq_header *header, unsigned int handle, void *bulk_userdata)
{
/*
* How do we ensure the callback goes to the right client?
@@ -1051,22 +1056,32 @@ service_callback(enum vchiq_reason reason, struct vchiq_header *header,
*/
struct user_service *user_service;
struct vchiq_service *service;
- struct vchiq_instance *instance;
bool skip_completion = false;
DEBUG_INITIALISE(g_state.local);
DEBUG_TRACE(SERVICE_CALLBACK_LINE);
- service = handle_to_service(handle);
- if (WARN_ON(!service))
+ rcu_read_lock();
+ service = handle_to_service(instance, handle);
+ if (WARN_ON(!service)) {
+ rcu_read_unlock();
return VCHIQ_SUCCESS;
+ }
user_service = (struct user_service *)service->base.userdata;
- instance = user_service->instance;
- if (!instance || instance->closing)
+ if (!instance || instance->closing) {
+ rcu_read_unlock();
return VCHIQ_SUCCESS;
+ }
+
+ /*
+ * As hopping around different synchronization mechanism,
+ * taking an extra reference results in simpler implementation.
+ */
+ vchiq_service_get(service);
+ rcu_read_unlock();
vchiq_log_trace(vchiq_arm_log_level,
"%s - service %lx(%d,%p), reason %d, header %lx, instance %lx, bulk_userdata %lx",
@@ -1097,6 +1112,7 @@ service_callback(enum vchiq_reason reason, struct vchiq_header *header,
bulk_userdata);
if (status != VCHIQ_SUCCESS) {
DEBUG_TRACE(SERVICE_CALLBACK_LINE);
+ vchiq_service_put(service);
return status;
}
}
@@ -1105,10 +1121,12 @@ service_callback(enum vchiq_reason reason, struct vchiq_header *header,
if (wait_for_completion_interruptible(&user_service->remove_event)) {
vchiq_log_info(vchiq_arm_log_level, "%s interrupted", __func__);
DEBUG_TRACE(SERVICE_CALLBACK_LINE);
+ vchiq_service_put(service);
return VCHIQ_RETRY;
} else if (instance->closing) {
vchiq_log_info(vchiq_arm_log_level, "%s closing", __func__);
DEBUG_TRACE(SERVICE_CALLBACK_LINE);
+ vchiq_service_put(service);
return VCHIQ_ERROR;
}
DEBUG_TRACE(SERVICE_CALLBACK_LINE);
@@ -1137,6 +1155,7 @@ service_callback(enum vchiq_reason reason, struct vchiq_header *header,
header = NULL;
}
DEBUG_TRACE(SERVICE_CALLBACK_LINE);
+ vchiq_service_put(service);
if (skip_completion)
return VCHIQ_SUCCESS;
@@ -1193,6 +1212,9 @@ int vchiq_dump_platform_instances(void *dump_context)
int len;
int i;
+ if (!state)
+ return -ENOTCONN;
+
/*
* There is no list of instances, so instead scan all services,
* marking those that have been dumped.
@@ -1274,14 +1296,18 @@ int vchiq_dump_platform_service_state(void *dump_context,
struct vchiq_state *
vchiq_get_state(void)
{
- if (!g_state.remote)
+ if (!g_state.remote) {
pr_err("%s: g_state.remote == NULL\n", __func__);
- else if (g_state.remote->initialised != 1)
+ return NULL;
+ }
+
+ if (g_state.remote->initialised != 1) {
pr_notice("%s: g_state.remote->initialised != 1 (%d)\n",
__func__, g_state.remote->initialised);
+ return NULL;
+ }
- return (g_state.remote &&
- (g_state.remote->initialised == 1)) ? &g_state : NULL;
+ return &g_state;
}
/*
@@ -1289,7 +1315,8 @@ vchiq_get_state(void)
*/
static enum vchiq_status
-vchiq_keepalive_vchiq_callback(enum vchiq_reason reason,
+vchiq_keepalive_vchiq_callback(struct vchiq_instance *instance,
+ enum vchiq_reason reason,
struct vchiq_header *header,
unsigned int service_user, void *bulk_user)
{
@@ -1358,14 +1385,14 @@ vchiq_keepalive_thread_func(void *v)
*/
while (uc--) {
atomic_inc(&arm_state->ka_use_ack_count);
- status = vchiq_use_service(ka_handle);
+ status = vchiq_use_service(instance, ka_handle);
if (status != VCHIQ_SUCCESS) {
vchiq_log_error(vchiq_susp_log_level,
"%s vchiq_use_service error %d", __func__, status);
}
}
while (rc--) {
- status = vchiq_release_service(ka_handle);
+ status = vchiq_release_service(instance, ka_handle);
if (status != VCHIQ_SUCCESS) {
vchiq_log_error(vchiq_susp_log_level,
"%s vchiq_release_service error %d", __func__,
@@ -1561,10 +1588,10 @@ vchiq_instance_set_trace(struct vchiq_instance *instance, int trace)
}
enum vchiq_status
-vchiq_use_service(unsigned int handle)
+vchiq_use_service(struct vchiq_instance *instance, unsigned int handle)
{
enum vchiq_status ret = VCHIQ_ERROR;
- struct vchiq_service *service = find_service_by_handle(handle);
+ struct vchiq_service *service = find_service_by_handle(instance, handle);
if (service) {
ret = vchiq_use_internal(service->state, service, USE_TYPE_SERVICE);
@@ -1575,10 +1602,10 @@ vchiq_use_service(unsigned int handle)
EXPORT_SYMBOL(vchiq_use_service);
enum vchiq_status
-vchiq_release_service(unsigned int handle)
+vchiq_release_service(struct vchiq_instance *instance, unsigned int handle)
{
enum vchiq_status ret = VCHIQ_ERROR;
- struct vchiq_service *service = find_service_by_handle(handle);
+ struct vchiq_service *service = find_service_by_handle(instance, handle);
if (service) {
ret = vchiq_release_internal(service->state, service);
@@ -1661,7 +1688,7 @@ vchiq_dump_service_use_state(struct vchiq_state *state)
service_data[i].clientid, service_data[i].use_count,
service_data[i].use_count ? nz : "");
}
- vchiq_log_warning(vchiq_susp_log_level, "----- VCHIQ use count count %d", peer_count);
+ vchiq_log_warning(vchiq_susp_log_level, "----- VCHIQ use count %d", peer_count);
vchiq_log_warning(vchiq_susp_log_level, "--- Overall vchiq instance use count %d",
vc_use_count);
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 2aa46b119a46..2851ef6b9cd0 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h
@@ -86,10 +86,10 @@ extern struct vchiq_state *
vchiq_get_state(void);
enum vchiq_status
-vchiq_use_service(unsigned int handle);
+vchiq_use_service(struct vchiq_instance *instance, unsigned int handle);
extern enum vchiq_status
-vchiq_release_service(unsigned int handle);
+vchiq_release_service(struct vchiq_instance *instance, unsigned int handle);
extern enum vchiq_status
vchiq_check_service(struct vchiq_service *service);
@@ -138,8 +138,8 @@ static inline int vchiq_register_chrdev(struct device *parent) { return 0; }
#endif /* IS_ENABLED(CONFIG_VCHIQ_CDEV) */
extern enum vchiq_status
-service_callback(enum vchiq_reason reason, struct vchiq_header *header,
- unsigned int handle, void *bulk_userdata);
+service_callback(struct vchiq_instance *vchiq_instance, enum vchiq_reason reason,
+ struct vchiq_header *header, unsigned int handle, void *bulk_userdata);
extern void
free_bulk_waiter(struct vchiq_instance *instance);
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 7fe20d4b7ba2..45ed30bfdbf5 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c
@@ -13,6 +13,7 @@
#include <linux/rcupdate.h>
#include <linux/sched/signal.h>
+#include "vchiq_arm.h"
#include "vchiq_core.h"
#define VCHIQ_SLOT_HANDLER_STACK 8192
@@ -161,7 +162,6 @@ int vchiq_sync_log_level = VCHIQ_LOG_DEFAULT;
DEFINE_SPINLOCK(bulk_waiter_spinlock);
static DEFINE_SPINLOCK(quota_spinlock);
-struct vchiq_state *vchiq_states[VCHIQ_MAX_STATES];
static unsigned int handle_seq;
static const char *const srvstate_names[] = {
@@ -205,27 +205,27 @@ release_message_sync(struct vchiq_state *state, struct vchiq_header *header);
static const char *msg_type_str(unsigned int msg_type)
{
switch (msg_type) {
- case VCHIQ_MSG_PADDING: return "PADDING";
- case VCHIQ_MSG_CONNECT: return "CONNECT";
- case VCHIQ_MSG_OPEN: return "OPEN";
- case VCHIQ_MSG_OPENACK: return "OPENACK";
- case VCHIQ_MSG_CLOSE: return "CLOSE";
- case VCHIQ_MSG_DATA: return "DATA";
- case VCHIQ_MSG_BULK_RX: return "BULK_RX";
- case VCHIQ_MSG_BULK_TX: return "BULK_TX";
- case VCHIQ_MSG_BULK_RX_DONE: return "BULK_RX_DONE";
- case VCHIQ_MSG_BULK_TX_DONE: return "BULK_TX_DONE";
- case VCHIQ_MSG_PAUSE: return "PAUSE";
- case VCHIQ_MSG_RESUME: return "RESUME";
- case VCHIQ_MSG_REMOTE_USE: return "REMOTE_USE";
- case VCHIQ_MSG_REMOTE_RELEASE: return "REMOTE_RELEASE";
- case VCHIQ_MSG_REMOTE_USE_ACTIVE: return "REMOTE_USE_ACTIVE";
+ case VCHIQ_MSG_PADDING: return "PADDING";
+ case VCHIQ_MSG_CONNECT: return "CONNECT";
+ case VCHIQ_MSG_OPEN: return "OPEN";
+ case VCHIQ_MSG_OPENACK: return "OPENACK";
+ case VCHIQ_MSG_CLOSE: return "CLOSE";
+ case VCHIQ_MSG_DATA: return "DATA";
+ case VCHIQ_MSG_BULK_RX: return "BULK_RX";
+ case VCHIQ_MSG_BULK_TX: return "BULK_TX";
+ case VCHIQ_MSG_BULK_RX_DONE: return "BULK_RX_DONE";
+ case VCHIQ_MSG_BULK_TX_DONE: return "BULK_TX_DONE";
+ case VCHIQ_MSG_PAUSE: return "PAUSE";
+ case VCHIQ_MSG_RESUME: return "RESUME";
+ case VCHIQ_MSG_REMOTE_USE: return "REMOTE_USE";
+ case VCHIQ_MSG_REMOTE_RELEASE: return "REMOTE_RELEASE";
+ case VCHIQ_MSG_REMOTE_USE_ACTIVE: return "REMOTE_USE_ACTIVE";
}
return "???";
}
static inline void
-vchiq_set_service_state(struct vchiq_service *service, int newstate)
+set_service_state(struct vchiq_service *service, int newstate)
{
vchiq_log_info(vchiq_core_log_level, "%d: srv:%d %s->%s",
service->state->id, service->localport,
@@ -234,13 +234,19 @@ vchiq_set_service_state(struct vchiq_service *service, int newstate)
service->srvstate = newstate;
}
+struct vchiq_service *handle_to_service(struct vchiq_instance *instance, unsigned int handle)
+{
+ int idx = handle & (VCHIQ_MAX_SERVICES - 1);
+
+ return rcu_dereference(instance->state->services[idx]);
+}
struct vchiq_service *
-find_service_by_handle(unsigned int handle)
+find_service_by_handle(struct vchiq_instance *instance, unsigned int handle)
{
struct vchiq_service *service;
rcu_read_lock();
- service = handle_to_service(handle);
+ service = handle_to_service(instance, handle);
if (service && service->srvstate != VCHIQ_SRVSTATE_FREE &&
service->handle == handle &&
kref_get_unless_zero(&service->ref_count)) {
@@ -255,9 +261,9 @@ find_service_by_handle(unsigned int handle)
}
struct vchiq_service *
-find_service_by_port(struct vchiq_state *state, int localport)
+find_service_by_port(struct vchiq_state *state, unsigned int localport)
{
- if ((unsigned int)localport <= VCHIQ_PORT_MAX) {
+ if (localport <= VCHIQ_PORT_MAX) {
struct vchiq_service *service;
rcu_read_lock();
@@ -271,7 +277,7 @@ find_service_by_port(struct vchiq_state *state, int localport)
rcu_read_unlock();
}
vchiq_log_info(vchiq_core_log_level,
- "Invalid port %d", localport);
+ "Invalid port %u", localport);
return NULL;
}
@@ -281,7 +287,7 @@ find_service_for_instance(struct vchiq_instance *instance, unsigned int handle)
struct vchiq_service *service;
rcu_read_lock();
- service = handle_to_service(handle);
+ service = handle_to_service(instance, handle);
if (service && service->srvstate != VCHIQ_SRVSTATE_FREE &&
service->handle == handle &&
service->instance == instance &&
@@ -302,7 +308,7 @@ find_closed_service_for_instance(struct vchiq_instance *instance, unsigned int h
struct vchiq_service *service;
rcu_read_lock();
- service = handle_to_service(handle);
+ service = handle_to_service(instance, handle);
if (service &&
(service->srvstate == VCHIQ_SRVSTATE_FREE ||
service->srvstate == VCHIQ_SRVSTATE_CLOSED) &&
@@ -398,26 +404,26 @@ vchiq_service_put(struct vchiq_service *service)
}
int
-vchiq_get_client_id(unsigned int handle)
+vchiq_get_client_id(struct vchiq_instance *instance, unsigned int handle)
{
struct vchiq_service *service;
int id;
rcu_read_lock();
- service = handle_to_service(handle);
+ service = handle_to_service(instance, handle);
id = service ? service->client_id : 0;
rcu_read_unlock();
return id;
}
void *
-vchiq_get_service_userdata(unsigned int handle)
+vchiq_get_service_userdata(struct vchiq_instance *instance, unsigned int handle)
{
void *userdata;
struct vchiq_service *service;
rcu_read_lock();
- service = handle_to_service(handle);
+ service = handle_to_service(instance, handle);
userdata = service ? service->base.userdata : NULL;
rcu_read_unlock();
return userdata;
@@ -466,7 +472,8 @@ make_service_callback(struct vchiq_service *service, enum vchiq_reason reason,
vchiq_log_trace(vchiq_core_log_level, "%d: callback:%d (%s, %pK, %pK)",
service->state->id, service->localport, reason_names[reason],
header, bulk_userdata);
- status = service->base.callback(reason, header, service->handle, bulk_userdata);
+ status = service->base.callback(service->instance, reason, header, service->handle,
+ bulk_userdata);
if (status == VCHIQ_ERROR) {
vchiq_log_warning(vchiq_core_log_level,
"%d: ignoring ERROR from callback to service %x",
@@ -475,7 +482,7 @@ make_service_callback(struct vchiq_service *service, enum vchiq_reason reason,
}
if (reason != VCHIQ_MESSAGE_AVAILABLE)
- vchiq_release_message(service->handle, header);
+ vchiq_release_message(service->instance, service->handle, header);
return status;
}
@@ -521,6 +528,7 @@ remote_event_wait(wait_queue_head_t *wq, struct remote_event *event)
return 0;
}
event->armed = 0;
+ /* Ensure that the peer sees that we are not waiting (armed == 0). */
wmb();
}
@@ -643,6 +651,7 @@ request_poll(struct vchiq_state *state, struct vchiq_service *service,
skip_service:
state->poll_needed = 1;
+ /* Ensure the slot handler thread sees the poll_needed flag. */
wmb();
/* ... and ensure the slot handler runs. */
@@ -872,9 +881,8 @@ copy_message_data(ssize_t (*copy_callback)(void *context, void *dest, size_t off
ssize_t callback_result;
size_t max_bytes = size - pos;
- callback_result =
- copy_callback(context, dest + pos,
- pos, max_bytes);
+ callback_result = copy_callback(context, dest + pos, pos,
+ max_bytes);
if (callback_result < 0)
return callback_result;
@@ -1028,8 +1036,7 @@ queue_message(struct vchiq_state *state, struct vchiq_service *service,
if (callback_result < 0) {
mutex_unlock(&state->slot_mutex);
- VCHIQ_SERVICE_STATS_INC(service,
- error_count);
+ VCHIQ_SERVICE_STATS_INC(service, error_count);
return VCHIQ_ERROR;
}
@@ -1037,8 +1044,7 @@ queue_message(struct vchiq_state *state, struct vchiq_service *service,
VCHIQ_LOG_INFO))
vchiq_log_dump_mem("Sent", 0,
header->data,
- min((size_t)16,
- (size_t)callback_result));
+ min_t(size_t, 16, callback_result));
spin_lock(&quota_spinlock);
quota->message_use_count++;
@@ -1122,7 +1128,7 @@ queue_message(struct vchiq_state *state, struct vchiq_service *service,
wmb();
if (service && (type == VCHIQ_MSG_CLOSE))
- vchiq_set_service_state(service, VCHIQ_SRVSTATE_CLOSESENT);
+ set_service_state(service, VCHIQ_SRVSTATE_CLOSESENT);
if (!(flags & QMFLAGS_NO_MUTEX_UNLOCK))
mutex_unlock(&state->slot_mutex);
@@ -1152,6 +1158,7 @@ queue_message_sync(struct vchiq_state *state, struct vchiq_service *service,
remote_event_wait(&state->sync_release_event, &local->sync_release);
+ /* Ensure that reads don't overtake the remote_event_wait. */
rmb();
header = (struct vchiq_header *)SLOT_DATA_FROM_INDEX(state,
@@ -1177,8 +1184,7 @@ queue_message_sync(struct vchiq_state *state, struct vchiq_service *service,
if (callback_result < 0) {
mutex_unlock(&state->slot_mutex);
- VCHIQ_SERVICE_STATS_INC(service,
- error_count);
+ VCHIQ_SERVICE_STATS_INC(service, error_count);
return VCHIQ_ERROR;
}
@@ -1187,8 +1193,7 @@ queue_message_sync(struct vchiq_state *state, struct vchiq_service *service,
VCHIQ_LOG_INFO))
vchiq_log_dump_mem("Sent", 0,
header->data,
- min((size_t)16,
- (size_t)callback_result));
+ min_t(size_t, 16, callback_result));
VCHIQ_SERVICE_STATS_INC(service, ctrl_tx_count);
VCHIQ_SERVICE_STATS_ADD(service, ctrl_tx_bytes, size);
@@ -1446,7 +1451,7 @@ abort_outstanding_bulks(struct vchiq_service *service,
}
if (queue->process != queue->local_insert) {
- vchiq_complete_bulk(bulk);
+ vchiq_complete_bulk(service->instance, bulk);
vchiq_log_info(SRVTRACE_LEVEL(service),
"%s %c%c%c%c d:%d ABORTED - tx len:%d, rx len:%d",
@@ -1524,15 +1529,17 @@ parse_open(struct vchiq_state *state, struct vchiq_header *header)
if (queue_message_sync(state, NULL, openack_id, memcpy_copy_callback,
&ack_payload, sizeof(ack_payload), 0) == VCHIQ_RETRY)
goto bail_not_ready;
+
+ /* The service is now open */
+ set_service_state(service, VCHIQ_SRVSTATE_OPENSYNC);
} else {
if (queue_message(state, NULL, openack_id, memcpy_copy_callback,
&ack_payload, sizeof(ack_payload), 0) == VCHIQ_RETRY)
goto bail_not_ready;
- }
- /* The service is now open */
- vchiq_set_service_state(service, service->sync ? VCHIQ_SRVSTATE_OPENSYNC
- : VCHIQ_SRVSTATE_OPEN);
+ /* The service is now open */
+ set_service_state(service, VCHIQ_SRVSTATE_OPEN);
+ }
}
/* Success - the message has been dealt with */
@@ -1666,7 +1673,7 @@ parse_message(struct vchiq_state *state, struct vchiq_header *header)
service->peer_version);
if (service->srvstate == VCHIQ_SRVSTATE_OPENING) {
service->remoteport = remoteport;
- vchiq_set_service_state(service, VCHIQ_SRVSTATE_OPEN);
+ set_service_state(service, VCHIQ_SRVSTATE_OPEN);
complete(&service->remove_event);
} else {
vchiq_log_error(vchiq_core_log_level, "OPENACK received in state %s",
@@ -1772,7 +1779,7 @@ parse_message(struct vchiq_state *state, struct vchiq_header *header)
DEBUG_TRACE(PARSE_LINE);
WARN_ON(queue->process == queue->local_insert);
- vchiq_complete_bulk(bulk);
+ vchiq_complete_bulk(service->instance, bulk);
queue->process++;
mutex_unlock(&service->bulk_mutex);
DEBUG_TRACE(PARSE_LINE);
@@ -1955,6 +1962,7 @@ slot_handler_func(void *v)
DEBUG_TRACE(SLOT_HANDLER_LINE);
remote_event_wait(&state->trigger_event, &local->trigger);
+ /* Ensure that reads don't overtake the remote_event_wait. */
rmb();
DEBUG_TRACE(SLOT_HANDLER_LINE);
@@ -2017,6 +2025,7 @@ sync_func(void *v)
remote_event_wait(&state->sync_trigger_event, &local->sync_trigger);
+ /* Ensure that reads don't overtake the remote_event_wait. */
rmb();
msgid = header->msgid;
@@ -2063,7 +2072,7 @@ sync_func(void *v)
service->peer_version);
if (service->srvstate == VCHIQ_SRVSTATE_OPENING) {
service->remoteport = remoteport;
- vchiq_set_service_state(service, VCHIQ_SRVSTATE_OPENSYNC);
+ set_service_state(service, VCHIQ_SRVSTATE_OPENSYNC);
service->sync = 1;
complete(&service->remove_event);
}
@@ -2097,16 +2106,6 @@ sync_func(void *v)
return 0;
}
-static void
-init_bulk_queue(struct vchiq_bulk_queue *queue)
-{
- queue->local_insert = 0;
- queue->remote_insert = 0;
- queue->process = 0;
- queue->remote_notify = 0;
- queue->remove = 0;
-}
-
inline const char *
get_conn_state_name(enum vchiq_connstate conn_state)
{
@@ -2155,18 +2154,13 @@ vchiq_init_slots(void *mem_base, int mem_size)
}
int
-vchiq_init_state(struct vchiq_state *state, struct vchiq_slot_zero *slot_zero)
+vchiq_init_state(struct vchiq_state *state, struct vchiq_slot_zero *slot_zero, struct device *dev)
{
struct vchiq_shared_state *local;
struct vchiq_shared_state *remote;
char threadname[16];
int i, ret;
- if (vchiq_states[0]) {
- pr_err("%s: VCHIQ state already initialized\n", __func__);
- return -EINVAL;
- }
-
local = &slot_zero->slave;
remote = &slot_zero->master;
@@ -2182,6 +2176,8 @@ vchiq_init_state(struct vchiq_state *state, struct vchiq_slot_zero *slot_zero)
memset(state, 0, sizeof(struct vchiq_state));
+ state->dev = dev;
+
/*
* initialize shared state pointers
*/
@@ -2220,8 +2216,7 @@ vchiq_init_state(struct vchiq_state *state, struct vchiq_slot_zero *slot_zero)
state->default_slot_quota = state->slot_queue_available / 2;
state->default_message_quota =
- min((unsigned short)(state->default_slot_quota * 256),
- (unsigned short)~0);
+ min_t(unsigned short, state->default_slot_quota * 256, ~0);
state->previous_data_index = -1;
state->data_use_count = 0;
@@ -2286,8 +2281,6 @@ vchiq_init_state(struct vchiq_state *state, struct vchiq_slot_zero *slot_zero)
wake_up_process(state->recycle_thread);
wake_up_process(state->sync_thread);
- vchiq_states[0] = state;
-
/* Indicate readiness to the other side */
local->initialised = 1;
@@ -2301,11 +2294,15 @@ fail_free_handler_thread:
return ret;
}
-void vchiq_msg_queue_push(unsigned int handle, struct vchiq_header *header)
+void vchiq_msg_queue_push(struct vchiq_instance *instance, unsigned int handle,
+ struct vchiq_header *header)
{
- struct vchiq_service *service = find_service_by_handle(handle);
+ struct vchiq_service *service = find_service_by_handle(instance, handle);
int pos;
+ if (!service)
+ return;
+
while (service->msg_queue_write == service->msg_queue_read +
VCHIQ_MAX_SLOTS) {
if (wait_for_completion_interruptible(&service->msg_queue_pop))
@@ -2320,12 +2317,15 @@ void vchiq_msg_queue_push(unsigned int handle, struct vchiq_header *header)
}
EXPORT_SYMBOL(vchiq_msg_queue_push);
-struct vchiq_header *vchiq_msg_hold(unsigned int handle)
+struct vchiq_header *vchiq_msg_hold(struct vchiq_instance *instance, unsigned int handle)
{
- struct vchiq_service *service = find_service_by_handle(handle);
+ struct vchiq_service *service = find_service_by_handle(instance, handle);
struct vchiq_header *header;
int pos;
+ if (!service)
+ return NULL;
+
if (service->msg_queue_write == service->msg_queue_read)
return NULL;
@@ -2371,7 +2371,7 @@ vchiq_add_service_internal(struct vchiq_state *state,
if (ret)
return NULL;
- service = kmalloc(sizeof(*service), GFP_KERNEL);
+ service = kzalloc(sizeof(*service), GFP_KERNEL);
if (!service)
return service;
@@ -2387,28 +2387,17 @@ vchiq_add_service_internal(struct vchiq_state *state,
service->public_fourcc = (srvstate == VCHIQ_SRVSTATE_OPENING) ?
VCHIQ_FOURCC_INVALID : params->fourcc;
- service->client_id = 0;
service->auto_close = 1;
- service->sync = 0;
- service->closing = 0;
- service->trace = 0;
atomic_set(&service->poll_flags, 0);
service->version = params->version;
service->version_min = params->version_min;
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
@@ -2486,7 +2475,7 @@ vchiq_add_service_internal(struct vchiq_state *state,
- 1;
/* Bring this service online */
- vchiq_set_service_state(service, srvstate);
+ set_service_state(service, srvstate);
vchiq_log_info(vchiq_core_msg_log_level, "%s Service %c%c%c%c SrcPort:%d",
(srvstate == VCHIQ_SRVSTATE_OPENING) ? "Open" : "Add",
@@ -2642,7 +2631,7 @@ close_service_complete(struct vchiq_service *service, int failstate)
} else {
newstate = VCHIQ_SRVSTATE_CLOSED;
}
- vchiq_set_service_state(service, newstate);
+ set_service_state(service, newstate);
break;
case VCHIQ_SRVSTATE_LISTENING:
break;
@@ -2678,7 +2667,7 @@ close_service_complete(struct vchiq_service *service, int failstate)
complete(&service->remove_event);
}
} else {
- vchiq_set_service_state(service, failstate);
+ set_service_state(service, failstate);
}
return status;
@@ -2711,9 +2700,8 @@ vchiq_close_service_internal(struct vchiq_service *service, int close_recvd)
} else {
service->client_id = 0;
service->remoteport = VCHIQ_PORT_FREE;
- if (service->srvstate ==
- VCHIQ_SRVSTATE_CLOSEWAIT)
- vchiq_set_service_state(service, VCHIQ_SRVSTATE_LISTENING);
+ if (service->srvstate == VCHIQ_SRVSTATE_CLOSEWAIT)
+ set_service_state(service, VCHIQ_SRVSTATE_LISTENING);
}
complete(&service->remove_event);
} else {
@@ -2723,7 +2711,7 @@ vchiq_close_service_internal(struct vchiq_service *service, int close_recvd)
case VCHIQ_SRVSTATE_OPENING:
if (close_recvd) {
/* The open was rejected - tell the user */
- vchiq_set_service_state(service, VCHIQ_SRVSTATE_CLOSEWAIT);
+ set_service_state(service, VCHIQ_SRVSTATE_CLOSEWAIT);
complete(&service->remove_event);
} else {
/* Shutdown mid-open - let the other side know */
@@ -2754,8 +2742,7 @@ vchiq_close_service_internal(struct vchiq_service *service, int close_recvd)
if (!close_recvd) {
/* Change the state while the mutex is still held */
- vchiq_set_service_state(service,
- VCHIQ_SRVSTATE_CLOSESENT);
+ set_service_state(service, VCHIQ_SRVSTATE_CLOSESENT);
mutex_unlock(&state->slot_mutex);
if (service->sync)
mutex_unlock(&state->sync_mutex);
@@ -2763,7 +2750,7 @@ vchiq_close_service_internal(struct vchiq_service *service, int close_recvd)
}
/* Change the state while the mutex is still held */
- vchiq_set_service_state(service, VCHIQ_SRVSTATE_CLOSERECVD);
+ set_service_state(service, VCHIQ_SRVSTATE_CLOSERECVD);
mutex_unlock(&state->slot_mutex);
if (service->sync)
mutex_unlock(&state->sync_mutex);
@@ -2788,7 +2775,7 @@ vchiq_close_service_internal(struct vchiq_service *service, int close_recvd)
case VCHIQ_SRVSTATE_CLOSERECVD:
if (!close_recvd && is_server)
/* Force into LISTENING mode */
- vchiq_set_service_state(service, VCHIQ_SRVSTATE_LISTENING);
+ set_service_state(service, VCHIQ_SRVSTATE_LISTENING);
status = close_service_complete(service, VCHIQ_SRVSTATE_CLOSERECVD);
break;
@@ -2837,7 +2824,7 @@ vchiq_free_service_internal(struct vchiq_service *service)
return;
}
- vchiq_set_service_state(service, VCHIQ_SRVSTATE_FREE);
+ set_service_state(service, VCHIQ_SRVSTATE_FREE);
complete(&service->remove_event);
@@ -2855,7 +2842,7 @@ vchiq_connect_internal(struct vchiq_state *state, struct vchiq_instance *instanc
i = 0;
while ((service = next_service_by_instance(state, instance, &i)) != NULL) {
if (service->srvstate == VCHIQ_SRVSTATE_HIDDEN)
- vchiq_set_service_state(service, VCHIQ_SRVSTATE_LISTENING);
+ set_service_state(service, VCHIQ_SRVSTATE_LISTENING);
vchiq_service_put(service);
}
@@ -2887,16 +2874,16 @@ vchiq_shutdown_internal(struct vchiq_state *state, struct vchiq_instance *instan
/* Find all services registered to this client and remove them. */
i = 0;
while ((service = next_service_by_instance(state, instance, &i)) != NULL) {
- (void)vchiq_remove_service(service->handle);
+ (void)vchiq_remove_service(instance, service->handle);
vchiq_service_put(service);
}
}
enum vchiq_status
-vchiq_close_service(unsigned int handle)
+vchiq_close_service(struct vchiq_instance *instance, unsigned int handle)
{
/* Unregister the service */
- struct vchiq_service *service = find_service_by_handle(handle);
+ struct vchiq_service *service = find_service_by_handle(instance, handle);
enum vchiq_status status = VCHIQ_SUCCESS;
if (!service)
@@ -2918,7 +2905,7 @@ vchiq_close_service(unsigned int handle)
status = vchiq_close_service_internal(service, NO_CLOSE_RECVD);
WARN_ON(status == VCHIQ_RETRY);
} else {
- /* Mark the service for termination by the slot handler */
+ /* Mark the service for termination by the slot handler */
request_poll(service->state, service, VCHIQ_POLL_TERMINATE);
}
@@ -2951,10 +2938,10 @@ vchiq_close_service(unsigned int handle)
EXPORT_SYMBOL(vchiq_close_service);
enum vchiq_status
-vchiq_remove_service(unsigned int handle)
+vchiq_remove_service(struct vchiq_instance *instance, unsigned int handle)
{
/* Unregister the service */
- struct vchiq_service *service = find_service_by_handle(handle);
+ struct vchiq_service *service = find_service_by_handle(instance, handle);
enum vchiq_status status = VCHIQ_SUCCESS;
if (!service)
@@ -3017,11 +3004,11 @@ vchiq_remove_service(unsigned int handle)
* When called in blocking mode, the userdata field points to a bulk_waiter
* structure.
*/
-enum vchiq_status vchiq_bulk_transfer(unsigned int handle, void *offset, void __user *uoffset,
- int size, void *userdata, enum vchiq_bulk_mode mode,
- enum vchiq_bulk_dir dir)
+enum vchiq_status vchiq_bulk_transfer(struct vchiq_instance *instance, unsigned int handle,
+ void *offset, void __user *uoffset, int size, void *userdata,
+ enum vchiq_bulk_mode mode, enum vchiq_bulk_dir dir)
{
- struct vchiq_service *service = find_service_by_handle(handle);
+ struct vchiq_service *service = find_service_by_handle(instance, handle);
struct vchiq_bulk_queue *queue;
struct vchiq_bulk *bulk;
struct vchiq_state *state;
@@ -3096,9 +3083,13 @@ enum vchiq_status vchiq_bulk_transfer(unsigned int handle, void *offset, void __
bulk->size = size;
bulk->actual = VCHIQ_BULK_ACTUAL_ABORTED;
- if (vchiq_prepare_bulk_data(bulk, offset, uoffset, size, dir))
+ if (vchiq_prepare_bulk_data(instance, bulk, offset, uoffset, size, dir))
goto unlock_error_exit;
+ /*
+ * Ensure that the bulk data record is visible to the peer
+ * before proceeding.
+ */
wmb();
vchiq_log_info(vchiq_core_log_level, "%d: bt (%d->%d) %cx %x@%pad %pK",
@@ -3160,7 +3151,7 @@ waiting:
unlock_both_error_exit:
mutex_unlock(&state->slot_mutex);
cancel_bulk_error_exit:
- vchiq_complete_bulk(bulk);
+ vchiq_complete_bulk(service->instance, bulk);
unlock_error_exit:
mutex_unlock(&service->bulk_mutex);
@@ -3171,13 +3162,13 @@ error_exit:
}
enum vchiq_status
-vchiq_queue_message(unsigned int handle,
+vchiq_queue_message(struct vchiq_instance *instance, unsigned int handle,
ssize_t (*copy_callback)(void *context, void *dest,
size_t offset, size_t maxsize),
void *context,
size_t size)
{
- struct vchiq_service *service = find_service_by_handle(handle);
+ struct vchiq_service *service = find_service_by_handle(instance, handle);
enum vchiq_status status = VCHIQ_ERROR;
int data_id;
@@ -3220,12 +3211,13 @@ error_exit:
return status;
}
-int vchiq_queue_kernel_message(unsigned int handle, void *data, unsigned int size)
+int vchiq_queue_kernel_message(struct vchiq_instance *instance, unsigned int handle, void *data,
+ unsigned int size)
{
enum vchiq_status status;
while (1) {
- status = vchiq_queue_message(handle, memcpy_copy_callback,
+ status = vchiq_queue_message(instance, handle, memcpy_copy_callback,
data, size);
/*
@@ -3244,10 +3236,10 @@ int vchiq_queue_kernel_message(unsigned int handle, void *data, unsigned int siz
EXPORT_SYMBOL(vchiq_queue_kernel_message);
void
-vchiq_release_message(unsigned int handle,
+vchiq_release_message(struct vchiq_instance *instance, unsigned int handle,
struct vchiq_header *header)
{
- struct vchiq_service *service = find_service_by_handle(handle);
+ struct vchiq_service *service = find_service_by_handle(instance, handle);
struct vchiq_shared_state *remote;
struct vchiq_state *state;
int slot_index;
@@ -3286,10 +3278,10 @@ release_message_sync(struct vchiq_state *state, struct vchiq_header *header)
}
enum vchiq_status
-vchiq_get_peer_version(unsigned int handle, short *peer_version)
+vchiq_get_peer_version(struct vchiq_instance *instance, unsigned int handle, short *peer_version)
{
enum vchiq_status status = VCHIQ_ERROR;
- struct vchiq_service *service = find_service_by_handle(handle);
+ struct vchiq_service *service = find_service_by_handle(instance, handle);
if (!service)
goto exit;
@@ -3321,9 +3313,10 @@ void vchiq_get_config(struct vchiq_config *config)
}
int
-vchiq_set_service_option(unsigned int handle, enum vchiq_service_option option, int value)
+vchiq_set_service_option(struct vchiq_instance *instance, unsigned int handle,
+ enum vchiq_service_option option, int value)
{
- struct vchiq_service *service = find_service_by_handle(handle);
+ struct vchiq_service *service = find_service_by_handle(instance, handle);
struct vchiq_service_quota *quota;
int ret = -EINVAL;
@@ -3666,10 +3659,10 @@ enum vchiq_status vchiq_send_remote_use_active(struct vchiq_state *state)
void vchiq_log_dump_mem(const char *label, u32 addr, const void *void_mem, size_t num_bytes)
{
- const u8 *mem = void_mem;
- size_t offset;
- char line_buf[100];
- char *s;
+ const u8 *mem = void_mem;
+ size_t offset;
+ char line_buf[100];
+ char *s;
while (num_bytes > 0) {
s = line_buf;
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 53a98949b294..8b4a38f5b3f2 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h
@@ -74,14 +74,11 @@
((fourcc) >> 8) & 0xff, \
(fourcc) & 0xff
-static_assert((sizeof(u32) * 8) == 32);
-
#define BITSET_SIZE(b) ((b + 31) >> 5)
#define BITSET_WORD(b) (b >> 5)
#define BITSET_BIT(b) (1 << (b & 31))
#define BITSET_IS_SET(bs, b) (bs[BITSET_WORD(b)] & BITSET_BIT(b))
#define BITSET_SET(bs, b) (bs[BITSET_WORD(b)] |= BITSET_BIT(b))
-#define BITSET_CLR(bs, b) (bs[BITSET_WORD(b)] &= ~BITSET_BIT(b))
enum {
DEBUG_ENTRIES,
@@ -317,6 +314,7 @@ struct vchiq_slot_zero {
};
struct vchiq_state {
+ struct device *dev;
int id;
int initialised;
enum vchiq_connstate conn_state;
@@ -451,8 +449,6 @@ extern int vchiq_core_log_level;
extern int vchiq_core_msg_log_level;
extern int vchiq_sync_log_level;
-extern struct vchiq_state *vchiq_states[VCHIQ_MAX_STATES];
-
extern const char *
get_conn_state_name(enum vchiq_connstate conn_state);
@@ -460,7 +456,7 @@ extern struct vchiq_slot_zero *
vchiq_init_slots(void *mem_base, int mem_size);
extern int
-vchiq_init_state(struct vchiq_state *state, struct vchiq_slot_zero *slot_zero);
+vchiq_init_state(struct vchiq_state *state, struct vchiq_slot_zero *slot_zero, struct device *dev);
extern enum vchiq_status
vchiq_connect_internal(struct vchiq_state *state, struct vchiq_instance *instance);
@@ -490,8 +486,8 @@ extern void
remote_event_pollall(struct vchiq_state *state);
extern enum vchiq_status
-vchiq_bulk_transfer(unsigned int handle, void *offset, void __user *uoffset,
- int size, void *userdata, enum vchiq_bulk_mode mode,
+vchiq_bulk_transfer(struct vchiq_instance *instance, unsigned int handle, void *offset,
+ void __user *uoffset, int size, void *userdata, enum vchiq_bulk_mode mode,
enum vchiq_bulk_dir dir);
extern int
@@ -510,23 +506,13 @@ extern void
request_poll(struct vchiq_state *state, struct vchiq_service *service,
int poll_type);
-static inline struct vchiq_service *
-handle_to_service(unsigned int handle)
-{
- int idx = handle & (VCHIQ_MAX_SERVICES - 1);
- struct vchiq_state *state = vchiq_states[(handle / VCHIQ_MAX_SERVICES) &
- (VCHIQ_MAX_STATES - 1)];
-
- if (!state)
- return NULL;
- return rcu_dereference(state->services[idx]);
-}
+struct vchiq_service *handle_to_service(struct vchiq_instance *instance, unsigned int handle);
extern struct vchiq_service *
-find_service_by_handle(unsigned int handle);
+find_service_by_handle(struct vchiq_instance *instance, unsigned int handle);
extern struct vchiq_service *
-find_service_by_port(struct vchiq_state *state, int localport);
+find_service_by_port(struct vchiq_state *state, unsigned int localport);
extern struct vchiq_service *
find_service_for_instance(struct vchiq_instance *instance, unsigned int handle);
@@ -551,16 +537,16 @@ extern void
vchiq_service_put(struct vchiq_service *service);
extern enum vchiq_status
-vchiq_queue_message(unsigned int handle,
+vchiq_queue_message(struct vchiq_instance *instance, unsigned int handle,
ssize_t (*copy_callback)(void *context, void *dest,
size_t offset, size_t maxsize),
void *context,
size_t size);
-int vchiq_prepare_bulk_data(struct vchiq_bulk *bulk, void *offset, void __user *uoffset,
- int size, int dir);
+int vchiq_prepare_bulk_data(struct vchiq_instance *instance, struct vchiq_bulk *bulk, void *offset,
+ void __user *uoffset, int size, int dir);
-void vchiq_complete_bulk(struct vchiq_bulk *bulk);
+void vchiq_complete_bulk(struct vchiq_instance *instance, struct vchiq_bulk *bulk);
void remote_event_signal(struct remote_event *event);
@@ -598,12 +584,13 @@ void vchiq_set_conn_state(struct vchiq_state *state, enum vchiq_connstate newsta
void vchiq_log_dump_mem(const char *label, u32 addr, const void *void_mem, size_t num_bytes);
-enum vchiq_status vchiq_remove_service(unsigned int service);
+enum vchiq_status vchiq_remove_service(struct vchiq_instance *instance, unsigned int service);
-int vchiq_get_client_id(unsigned int service);
+int vchiq_get_client_id(struct vchiq_instance *instance, unsigned int service);
void vchiq_get_config(struct vchiq_config *config);
-int vchiq_set_service_option(unsigned int service, enum vchiq_service_option option, int value);
+int vchiq_set_service_option(struct vchiq_instance *instance, unsigned int service,
+ enum vchiq_service_option option, int value);
#endif
diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_debugfs.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_debugfs.c
index 8f3d9cb2d562..dc667afd1f8c 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_debugfs.c
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_debugfs.c
@@ -36,8 +36,6 @@ static struct vchiq_debugfs_log_entry vchiq_debugfs_log_entries[] = {
{ "arm", &vchiq_arm_log_level },
};
-static int n_log_entries = ARRAY_SIZE(vchiq_debugfs_log_entries);
-
static int debugfs_log_show(struct seq_file *f, void *offset)
{
int *levp = f->private;
@@ -216,7 +214,7 @@ void vchiq_debugfs_init(void)
/* create an entry under <debugfs>/vchiq/log for each log category */
dir = debugfs_create_dir("log", vchiq_dbg_dir);
- for (i = 0; i < n_log_entries; i++)
+ for (i = 0; i < ARRAY_SIZE(vchiq_debugfs_log_entries); i++)
debugfs_create_file(vchiq_debugfs_log_entries[i].name, 0644,
dir, vchiq_debugfs_log_entries[i].plevel,
&debugfs_log_fops);
diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_dev.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_dev.c
index 2325844b0880..7e297494437e 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_dev.c
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_dev.c
@@ -108,8 +108,8 @@ static ssize_t vchiq_ioc_copy_element_data(void *context, void *dest,
}
static int
-vchiq_ioc_queue_message(unsigned int handle, struct vchiq_element *elements,
- unsigned long count)
+vchiq_ioc_queue_message(struct vchiq_instance *instance, unsigned int handle,
+ struct vchiq_element *elements, unsigned long count)
{
struct vchiq_io_copy_callback_context context;
enum vchiq_status status = VCHIQ_SUCCESS;
@@ -127,7 +127,7 @@ vchiq_ioc_queue_message(unsigned int handle, struct vchiq_element *elements,
total_size += elements[i].size;
}
- status = vchiq_queue_message(handle, vchiq_ioc_copy_element_data,
+ status = vchiq_queue_message(instance, handle, vchiq_ioc_copy_element_data,
&context, total_size);
if (status == VCHIQ_ERROR)
@@ -146,15 +146,14 @@ static int vchiq_ioc_create_service(struct vchiq_instance *instance,
struct vchiq_service_params_kernel params;
int srvstate;
+ if (args->is_open && !instance->connected)
+ return -ENOTCONN;
+
user_service = kmalloc(sizeof(*user_service), GFP_KERNEL);
if (!user_service)
return -ENOMEM;
if (args->is_open) {
- if (!instance->connected) {
- kfree(user_service);
- return -ENOTCONN;
- }
srvstate = VCHIQ_SRVSTATE_OPENING;
} else {
srvstate = instance->connected ?
@@ -192,7 +191,7 @@ static int vchiq_ioc_create_service(struct vchiq_instance *instance,
if (args->is_open) {
status = vchiq_open_service_internal(service, instance->pid);
if (status != VCHIQ_SUCCESS) {
- vchiq_remove_service(service->handle);
+ vchiq_remove_service(instance, service->handle);
return (status == VCHIQ_RETRY) ?
-EINTR : -EIO;
}
@@ -267,7 +266,7 @@ static int vchiq_ioc_dequeue_message(struct vchiq_instance *instance,
/* Copy to user space if msgbuf is not NULL */
if (!args->buf || (copy_to_user(args->buf, header->data, header->size) == 0)) {
ret = header->size;
- vchiq_release_message(service->handle, header);
+ vchiq_release_message(instance, service->handle, header);
} else {
ret = -EFAULT;
}
@@ -290,8 +289,7 @@ static int vchiq_irq_queue_bulk_tx_rx(struct vchiq_instance *instance,
enum vchiq_bulk_mode __user *mode)
{
struct vchiq_service *service;
- struct bulk_waiter_node *waiter = NULL;
- bool found = false;
+ struct bulk_waiter_node *waiter = NULL, *iter;
void *userdata;
int status = 0;
int ret;
@@ -310,16 +308,16 @@ static int vchiq_irq_queue_bulk_tx_rx(struct vchiq_instance *instance,
userdata = &waiter->bulk_waiter;
} else if (args->mode == VCHIQ_BULK_MODE_WAITING) {
mutex_lock(&instance->bulk_waiter_list_mutex);
- list_for_each_entry(waiter, &instance->bulk_waiter_list,
+ list_for_each_entry(iter, &instance->bulk_waiter_list,
list) {
- if (waiter->pid == current->pid) {
- list_del(&waiter->list);
- found = true;
+ if (iter->pid == current->pid) {
+ list_del(&iter->list);
+ waiter = iter;
break;
}
}
mutex_unlock(&instance->bulk_waiter_list_mutex);
- if (!found) {
+ if (!waiter) {
vchiq_log_error(vchiq_arm_log_level,
"no bulk_waiter found for pid %d", current->pid);
ret = -ESRCH;
@@ -332,7 +330,7 @@ static int vchiq_irq_queue_bulk_tx_rx(struct vchiq_instance *instance,
userdata = args->userdata;
}
- status = vchiq_bulk_transfer(args->handle, NULL, args->data, args->size,
+ status = vchiq_bulk_transfer(instance, args->handle, NULL, args->data, args->size,
userdata, args->mode, dir);
if (!waiter) {
@@ -531,7 +529,7 @@ static int vchiq_ioc_await_completion(struct vchiq_instance *instance,
}
/* Now it has been copied, the message can be released. */
- vchiq_release_message(service->handle, header);
+ vchiq_release_message(instance, service->handle, header);
/* The completion must point to the msgbuf. */
user_completion.header = msgbuf;
@@ -598,7 +596,7 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
i = 0;
while ((service = next_service_by_instance(instance->state,
instance, &i))) {
- status = vchiq_remove_service(service->handle);
+ status = vchiq_remove_service(instance, service->handle);
vchiq_service_put(service);
if (status != VCHIQ_SUCCESS)
break;
@@ -651,7 +649,7 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
break;
if (put_user(args.handle, &argp->handle)) {
- vchiq_remove_service(args.handle);
+ vchiq_remove_service(instance, args.handle);
ret = -EFAULT;
}
} break;
@@ -675,8 +673,8 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
*/
if (!user_service->close_pending) {
status = (cmd == VCHIQ_IOC_CLOSE_SERVICE) ?
- vchiq_close_service(service->handle) :
- vchiq_remove_service(service->handle);
+ vchiq_close_service(instance, service->handle) :
+ vchiq_remove_service(instance, service->handle);
if (status != VCHIQ_SUCCESS)
break;
}
@@ -733,7 +731,7 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
if (copy_from_user(elements, args.elements,
args.count * sizeof(struct vchiq_element)) == 0)
- ret = vchiq_ioc_queue_message(args.handle, elements,
+ ret = vchiq_ioc_queue_message(instance, args.handle, elements,
args.count);
else
ret = -EFAULT;
@@ -790,7 +788,7 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
case VCHIQ_IOC_GET_CLIENT_ID: {
unsigned int handle = (unsigned int)arg;
- ret = vchiq_get_client_id(handle);
+ ret = vchiq_get_client_id(instance, handle);
} break;
case VCHIQ_IOC_GET_CONFIG: {
@@ -829,7 +827,7 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
break;
}
- ret = vchiq_set_service_option(args.handle, args.option,
+ ret = vchiq_set_service_option(instance, args.handle, args.option,
args.value);
} break;
@@ -910,6 +908,7 @@ vchiq_compat_ioctl_create_service(struct file *file, unsigned int cmd,
{
struct vchiq_create_service args;
struct vchiq_create_service32 args32;
+ struct vchiq_instance *instance = file->private_data;
long ret;
if (copy_from_user(&args32, ptrargs32, sizeof(args32)))
@@ -928,12 +927,12 @@ vchiq_compat_ioctl_create_service(struct file *file, unsigned int cmd,
.handle = args32.handle,
};
- ret = vchiq_ioc_create_service(file->private_data, &args);
+ ret = vchiq_ioc_create_service(instance, &args);
if (ret < 0)
return ret;
if (put_user(args.handle, &ptrargs32->handle)) {
- vchiq_remove_service(args.handle);
+ vchiq_remove_service(instance, args.handle);
return -EFAULT;
}
@@ -962,6 +961,7 @@ vchiq_compat_ioctl_queue_message(struct file *file,
struct vchiq_queue_message args;
struct vchiq_queue_message32 args32;
struct vchiq_service *service;
+ struct vchiq_instance *instance = file->private_data;
int ret;
if (copy_from_user(&args32, arg, sizeof(args32)))
@@ -976,7 +976,7 @@ vchiq_compat_ioctl_queue_message(struct file *file,
if (args32.count > MAX_ELEMENTS)
return -EINVAL;
- service = find_service_for_instance(file->private_data, args.handle);
+ service = find_service_for_instance(instance, args.handle);
if (!service)
return -EINVAL;
@@ -996,7 +996,7 @@ vchiq_compat_ioctl_queue_message(struct file *file,
compat_ptr(element32[count].data);
elements[count].size = element32[count].size;
}
- ret = vchiq_ioc_queue_message(args.handle, elements,
+ ret = vchiq_ioc_queue_message(instance, args.handle, elements,
args.count);
} else {
ret = -EINVAL;
@@ -1263,7 +1263,7 @@ static int vchiq_release(struct inode *inode, struct file *file)
spin_unlock(&msg_queue_spinlock);
if (header)
- vchiq_release_message(service->handle, header);
+ vchiq_release_message(instance, service->handle, header);
spin_lock(&msg_queue_spinlock);
}