summaryrefslogtreecommitdiffstats
path: root/drivers/staging/vc04_services
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-08-07 13:17:46 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-08-07 13:17:46 +0000
commit7f3a4257159dea8e7ef66d1a539dc6df708b8ed3 (patch)
treebcc69b5f4609f348fac49e2f59e210b29eaea783 /drivers/staging/vc04_services
parentAdding upstream version 6.9.12. (diff)
downloadlinux-7f3a4257159dea8e7ef66d1a539dc6df708b8ed3.tar.xz
linux-7f3a4257159dea8e7ef66d1a539dc6df708b8ed3.zip
Adding upstream version 6.10.3.upstream/6.10.3
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'drivers/staging/vc04_services')
-rw-r--r--drivers/staging/vc04_services/Kconfig36
-rw-r--r--drivers/staging/vc04_services/Makefile1
-rw-r--r--drivers/staging/vc04_services/bcm2835-audio/Kconfig2
-rw-r--r--drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c5
-rw-r--r--drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c4
-rw-r--r--drivers/staging/vc04_services/include/linux/raspberrypi/vchiq.h4
-rw-r--r--drivers/staging/vc04_services/interface/TODO15
-rw-r--r--drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c271
-rw-r--r--drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h41
-rw-r--r--drivers/staging/vc04_services/interface/vchiq_arm/vchiq_bus.c13
-rw-r--r--drivers/staging/vc04_services/interface/vchiq_arm/vchiq_bus.h3
-rw-r--r--drivers/staging/vc04_services/interface/vchiq_arm/vchiq_connected.c74
-rw-r--r--drivers/staging/vc04_services/interface/vchiq_arm/vchiq_connected.h12
-rw-r--r--drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c67
-rw-r--r--drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h22
-rw-r--r--drivers/staging/vc04_services/interface/vchiq_arm/vchiq_debugfs.c11
-rw-r--r--drivers/staging/vc04_services/interface/vchiq_arm/vchiq_debugfs.h2
-rw-r--r--drivers/staging/vc04_services/interface/vchiq_arm/vchiq_dev.c40
-rw-r--r--drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c14
-rw-r--r--drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h32
20 files changed, 326 insertions, 343 deletions
diff --git a/drivers/staging/vc04_services/Kconfig b/drivers/staging/vc04_services/Kconfig
index 31e58c9d1a..ccc8e15886 100644
--- a/drivers/staging/vc04_services/Kconfig
+++ b/drivers/staging/vc04_services/Kconfig
@@ -16,27 +16,33 @@ config BCM2835_VCHIQ
depends on HAS_DMA
imply VCHIQ_CDEV
help
- Broadcom BCM2835 and similar SoCs have a VPU called VideoCore. This config
- enables the VCHIQ driver, which implements a messaging interface between
- the kernel and the firmware running on VideoCore. Other drivers use this
- interface to communicate to the VPU. More specifically, the VCHIQ driver is
- used by audio/video and camera drivers as well as for implementing MMAL
- API, which is in turn used by several multimedia services on the BCM2835
- family of SoCs.
- Defaults to Y when the Broadcom Videocore services are included in
- the build, N otherwise.
+ Broadcom BCM2835 and similar SoCs have a VPU called VideoCore.
+ This config enables the VCHIQ driver, which implements a
+ messaging interface between the kernel and the firmware running
+ on VideoCore. Other drivers use this interface to communicate to
+ the VPU. More specifically, the VCHIQ driver is used by
+ audio/video and camera drivers as well as for implementing MMAL
+ API, which is in turn used by several multimedia services on the
+ BCM2835 family of SoCs.
+
+ Defaults to Y when the Broadcom Videocore services are included
+ in the build, N otherwise.
if BCM2835_VCHIQ
config VCHIQ_CDEV
bool "VCHIQ Character Driver"
help
- Enable the creation of VCHIQ character driver. The cdev exposes ioctls used
- by userspace libraries and testing tools to interact with VideoCore, via
- the VCHIQ core driver (Check BCM2835_VCHIQ for more info).
- This can be set to 'N' if the VideoCore communication is not needed by
- userspace but only by other kernel modules (like bcm2835-audio). If not
- sure, set this to 'Y'.
+ Enable the creation of VCHIQ character driver. The cdev exposes
+ ioctls used by userspace libraries and testing tools to interact
+ with VideoCore, via the VCHIQ core driver (Check BCM2835_VCHIQ
+ for more info).
+
+ This can be set to 'N' if the VideoCore communication is not
+ needed by userspace but only by other kernel modules
+ (like bcm2835-audio).
+
+ If not sure, set this to 'Y'.
endif
diff --git a/drivers/staging/vc04_services/Makefile b/drivers/staging/vc04_services/Makefile
index e8b897a7b9..dad3789522 100644
--- a/drivers/staging/vc04_services/Makefile
+++ b/drivers/staging/vc04_services/Makefile
@@ -6,7 +6,6 @@ vchiq-objs := \
interface/vchiq_arm/vchiq_arm.o \
interface/vchiq_arm/vchiq_bus.o \
interface/vchiq_arm/vchiq_debugfs.o \
- interface/vchiq_arm/vchiq_connected.o \
ifdef CONFIG_VCHIQ_CDEV
vchiq-objs += interface/vchiq_arm/vchiq_dev.o
diff --git a/drivers/staging/vc04_services/bcm2835-audio/Kconfig b/drivers/staging/vc04_services/bcm2835-audio/Kconfig
index 7f22f6c850..7fbb29d3c3 100644
--- a/drivers/staging/vc04_services/bcm2835-audio/Kconfig
+++ b/drivers/staging/vc04_services/bcm2835-audio/Kconfig
@@ -8,4 +8,4 @@ config SND_BCM2835
Say Y or M if you want to support BCM2835 built in audio.
This driver handles both 3.5mm and HDMI audio, by leveraging
the VCHIQ messaging interface between the kernel and the firmware
- running on VideoCore. \ No newline at end of file
+ running on VideoCore.
diff --git a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c
index d74110ca17..133ed15f3d 100644
--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c
+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c
@@ -7,6 +7,8 @@
#include "bcm2835.h"
#include "vc_vchi_audioserv_defs.h"
+#include "../interface/vchiq_arm/vchiq_arm.h"
+
struct bcm2835_audio_instance {
struct device *dev;
unsigned int service_handle;
@@ -175,10 +177,11 @@ static void vc_vchi_audio_deinit(struct bcm2835_audio_instance *instance)
int bcm2835_new_vchi_ctx(struct device *dev, struct bcm2835_vchi_ctx *vchi_ctx)
{
+ struct vchiq_drv_mgmt *mgmt = dev_get_drvdata(dev->parent);
int ret;
/* Initialize and create a VCHI connection */
- ret = vchiq_initialise(&vchi_ctx->instance);
+ ret = vchiq_initialise(&mgmt->state, &vchi_ctx->instance);
if (ret) {
dev_err(dev, "failed to initialise VCHI instance (ret=%d)\n",
ret);
diff --git a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
index c3ba490e53..b3599ec629 100644
--- a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
+++ b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
@@ -1555,7 +1555,7 @@ static int mmal_init(struct bcm2835_mmal_dev *dev)
u32 param_size;
struct vchiq_mmal_component *camera;
- ret = vchiq_mmal_init(&dev->instance);
+ ret = vchiq_mmal_init(dev->v4l2_dev.dev, &dev->instance);
if (ret < 0) {
v4l2_err(&dev->v4l2_dev, "%s: vchiq mmal init failed %d\n",
__func__, ret);
@@ -1854,7 +1854,7 @@ static int bcm2835_mmal_probe(struct vchiq_device *device)
return ret;
}
- ret = vchiq_mmal_init(&instance);
+ ret = vchiq_mmal_init(&device->dev, &instance);
if (ret < 0)
return ret;
diff --git a/drivers/staging/vc04_services/include/linux/raspberrypi/vchiq.h b/drivers/staging/vc04_services/include/linux/raspberrypi/vchiq.h
index 52e106f117..6c40d8c1dd 100644
--- a/drivers/staging/vc04_services/include/linux/raspberrypi/vchiq.h
+++ b/drivers/staging/vc04_services/include/linux/raspberrypi/vchiq.h
@@ -48,6 +48,7 @@ struct vchiq_element {
};
struct vchiq_instance;
+struct vchiq_state;
struct vchiq_service_base {
int fourcc;
@@ -78,7 +79,8 @@ struct vchiq_service_params_kernel {
short version_min; /* Update for incompatible changes */
};
-extern int vchiq_initialise(struct vchiq_instance **pinstance);
+extern int vchiq_initialise(struct vchiq_state *state,
+ struct vchiq_instance **pinstance);
extern int vchiq_shutdown(struct vchiq_instance *instance);
extern int vchiq_connect(struct vchiq_instance *instance);
extern int vchiq_open_service(struct vchiq_instance *instance,
diff --git a/drivers/staging/vc04_services/interface/TODO b/drivers/staging/vc04_services/interface/TODO
index 05eb5140d0..05f129c0c2 100644
--- a/drivers/staging/vc04_services/interface/TODO
+++ b/drivers/staging/vc04_services/interface/TODO
@@ -28,27 +28,12 @@ variables avoided.
A short top-down description of this driver's architecture (function of
kthreads, userspace, limitations) could be very helpful for reviewers.
-* 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.
-
* 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.
-* 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
-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.
-
* 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.
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 1579bd4e52..5f518e5a92 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
@@ -36,7 +36,6 @@
#include "vchiq_arm.h"
#include "vchiq_bus.h"
#include "vchiq_debugfs.h"
-#include "vchiq_connected.h"
#include "vchiq_pagelist.h"
#define DEVICE_NAME "vchiq"
@@ -60,9 +59,6 @@
#define KEEPALIVE_VER 1
#define KEEPALIVE_VER_MIN KEEPALIVE_VER
-DEFINE_SPINLOCK(msg_queue_spinlock);
-struct vchiq_state g_state;
-
/*
* The devices implemented in the VCHIQ firmware are not discoverable,
* so we need to maintain a list of them in order to register them with
@@ -71,16 +67,11 @@ struct vchiq_state g_state;
static struct vchiq_device *bcm2835_audio;
static struct vchiq_device *bcm2835_camera;
-struct vchiq_drvdata {
- const unsigned int cache_line_size;
- struct rpi_firmware *fw;
-};
-
-static struct vchiq_drvdata bcm2835_drvdata = {
+static const struct vchiq_platform_info bcm2835_info = {
.cache_line_size = 32,
};
-static struct vchiq_drvdata bcm2836_drvdata = {
+static const struct vchiq_platform_info bcm2836_info = {
.cache_line_size = 64,
};
@@ -135,25 +126,6 @@ struct vchiq_pagelist_info {
unsigned int scatterlist_mapped;
};
-static void __iomem *g_regs;
-/* This value is the size of the L2 cache lines as understood by the
- * VPU firmware, which determines the required alignment of the
- * offsets/sizes in pagelists.
- *
- * Modern VPU firmware looks for a DT "cache-line-size" property in
- * the VCHIQ node and will overwrite it with the actual L2 cache size,
- * which the kernel must then respect. That property was rejected
- * upstream, so we have to use the VPU firmware's compatibility value
- * of 32.
- */
-static unsigned int g_cache_line_size = 32;
-static unsigned int g_fragments_size;
-static char *g_fragments_base;
-static char *g_free_fragments;
-static struct semaphore g_free_fragments_sema;
-
-static DEFINE_SEMAPHORE(g_free_fragments_mutex, 1);
-
static int
vchiq_blocking_bulk_transfer(struct vchiq_instance *instance, unsigned int handle, void *data,
unsigned int size, enum vchiq_bulk_dir dir);
@@ -162,11 +134,14 @@ static irqreturn_t
vchiq_doorbell_irq(int irq, void *dev_id)
{
struct vchiq_state *state = dev_id;
+ struct vchiq_drv_mgmt *mgmt;
irqreturn_t ret = IRQ_NONE;
unsigned int status;
+ mgmt = dev_get_drvdata(state->dev);
+
/* Read (and clear) the doorbell */
- status = readl(g_regs + BELL0);
+ status = readl(mgmt->regs + BELL0);
if (status & ARM_DS_ACTIVE) { /* Was the doorbell rung? */
remote_event_pollall(state);
@@ -205,6 +180,56 @@ is_adjacent_block(u32 *addrs, u32 addr, unsigned int k)
return tmp == (addr & PAGE_MASK);
}
+/*
+ * This function is called by the vchiq stack once it has been connected to
+ * the videocore and clients can start to use the stack.
+ */
+static void vchiq_call_connected_callbacks(struct vchiq_drv_mgmt *drv_mgmt)
+{
+ int i;
+
+ if (mutex_lock_killable(&drv_mgmt->connected_mutex))
+ return;
+
+ for (i = 0; i < drv_mgmt->num_deferred_callbacks; i++)
+ drv_mgmt->deferred_callback[i]();
+
+ drv_mgmt->num_deferred_callbacks = 0;
+ drv_mgmt->connected = true;
+ mutex_unlock(&drv_mgmt->connected_mutex);
+}
+
+/*
+ * This function is used to defer initialization until the vchiq stack is
+ * initialized. If the stack is already initialized, then the callback will
+ * be made immediately, otherwise it will be deferred until
+ * vchiq_call_connected_callbacks is called.
+ */
+void vchiq_add_connected_callback(struct vchiq_device *device, void (*callback)(void))
+{
+ struct vchiq_drv_mgmt *drv_mgmt = device->drv_mgmt;
+
+ if (mutex_lock_killable(&drv_mgmt->connected_mutex))
+ return;
+
+ if (drv_mgmt->connected) {
+ /* We're already connected. Call the callback immediately. */
+ callback();
+ } else {
+ if (drv_mgmt->num_deferred_callbacks >= VCHIQ_DRV_MAX_CALLBACKS) {
+ dev_err(&device->dev,
+ "core: deferred callbacks(%d) exceeded the maximum limit(%d)\n",
+ drv_mgmt->num_deferred_callbacks, VCHIQ_DRV_MAX_CALLBACKS);
+ } else {
+ drv_mgmt->deferred_callback[drv_mgmt->num_deferred_callbacks] =
+ callback;
+ drv_mgmt->num_deferred_callbacks++;
+ }
+ }
+ mutex_unlock(&drv_mgmt->connected_mutex);
+}
+EXPORT_SYMBOL(vchiq_add_connected_callback);
+
/* 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,
@@ -217,6 +242,7 @@ static struct vchiq_pagelist_info *
create_pagelist(struct vchiq_instance *instance, char *buf, char __user *ubuf,
size_t count, unsigned short type)
{
+ struct vchiq_drv_mgmt *drv_mgmt;
struct pagelist *pagelist;
struct vchiq_pagelist_info *pagelistinfo;
struct page **pages;
@@ -231,6 +257,8 @@ create_pagelist(struct vchiq_instance *instance, char *buf, char __user *ubuf,
if (count >= INT_MAX - PAGE_SIZE)
return NULL;
+ drv_mgmt = dev_get_drvdata(instance->state->dev);
+
if (buf)
offset = (uintptr_t)buf & (PAGE_SIZE - 1);
else
@@ -373,25 +401,25 @@ create_pagelist(struct vchiq_instance *instance, char *buf, char __user *ubuf,
/* Partial cache lines (fragments) require special measures */
if ((type == PAGELIST_READ) &&
- ((pagelist->offset & (g_cache_line_size - 1)) ||
+ ((pagelist->offset & (drv_mgmt->info->cache_line_size - 1)) ||
((pagelist->offset + pagelist->length) &
- (g_cache_line_size - 1)))) {
+ (drv_mgmt->info->cache_line_size - 1)))) {
char *fragments;
- if (down_interruptible(&g_free_fragments_sema)) {
+ if (down_interruptible(&drv_mgmt->free_fragments_sema)) {
cleanup_pagelistinfo(instance, pagelistinfo);
return NULL;
}
- WARN_ON(!g_free_fragments);
+ WARN_ON(!drv_mgmt->free_fragments);
- down(&g_free_fragments_mutex);
- fragments = g_free_fragments;
+ down(&drv_mgmt->free_fragments_mutex);
+ fragments = drv_mgmt->free_fragments;
WARN_ON(!fragments);
- g_free_fragments = *(char **)g_free_fragments;
- up(&g_free_fragments_mutex);
+ drv_mgmt->free_fragments = *(char **)drv_mgmt->free_fragments;
+ up(&drv_mgmt->free_fragments_mutex);
pagelist->type = PAGELIST_READ_WITH_FRAGMENTS +
- (fragments - g_fragments_base) / g_fragments_size;
+ (fragments - drv_mgmt->fragments_base) / drv_mgmt->fragments_size;
}
return pagelistinfo;
@@ -401,12 +429,15 @@ static void
free_pagelist(struct vchiq_instance *instance, struct vchiq_pagelist_info *pagelistinfo,
int actual)
{
+ struct vchiq_drv_mgmt *drv_mgmt;
struct pagelist *pagelist = pagelistinfo->pagelist;
struct page **pages = pagelistinfo->pages;
unsigned int num_pages = pagelistinfo->num_pages;
dev_dbg(instance->state->dev, "arm: %pK, %d\n", pagelistinfo->pagelist, actual);
+ drv_mgmt = dev_get_drvdata(instance->state->dev);
+
/*
* NOTE: dma_unmap_sg must be called before the
* cpu can touch any of the data/pages.
@@ -416,16 +447,16 @@ free_pagelist(struct vchiq_instance *instance, struct vchiq_pagelist_info *pagel
pagelistinfo->scatterlist_mapped = 0;
/* Deal with any partial cache lines (fragments) */
- if (pagelist->type >= PAGELIST_READ_WITH_FRAGMENTS && g_fragments_base) {
- char *fragments = g_fragments_base +
+ if (pagelist->type >= PAGELIST_READ_WITH_FRAGMENTS && drv_mgmt->fragments_base) {
+ char *fragments = drv_mgmt->fragments_base +
(pagelist->type - PAGELIST_READ_WITH_FRAGMENTS) *
- g_fragments_size;
+ drv_mgmt->fragments_size;
int head_bytes, tail_bytes;
- head_bytes = (g_cache_line_size - pagelist->offset) &
- (g_cache_line_size - 1);
+ head_bytes = (drv_mgmt->info->cache_line_size - pagelist->offset) &
+ (drv_mgmt->info->cache_line_size - 1);
tail_bytes = (pagelist->offset + actual) &
- (g_cache_line_size - 1);
+ (drv_mgmt->info->cache_line_size - 1);
if ((actual >= 0) && (head_bytes != 0)) {
if (head_bytes > actual)
@@ -440,15 +471,15 @@ free_pagelist(struct vchiq_instance *instance, struct vchiq_pagelist_info *pagel
(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,
+ (PAGE_SIZE - 1) & ~(drv_mgmt->info->cache_line_size - 1),
+ fragments + drv_mgmt->info->cache_line_size,
tail_bytes);
- down(&g_free_fragments_mutex);
- *(char **)fragments = g_free_fragments;
- g_free_fragments = fragments;
- up(&g_free_fragments_mutex);
- up(&g_free_fragments_sema);
+ down(&drv_mgmt->free_fragments_mutex);
+ *(char **)fragments = drv_mgmt->free_fragments;
+ drv_mgmt->free_fragments = fragments;
+ up(&drv_mgmt->free_fragments_mutex);
+ up(&drv_mgmt->free_fragments_sema);
}
/* Need to mark all the pages dirty. */
@@ -466,8 +497,8 @@ free_pagelist(struct vchiq_instance *instance, struct vchiq_pagelist_info *pagel
static int vchiq_platform_init(struct platform_device *pdev, struct vchiq_state *state)
{
struct device *dev = &pdev->dev;
- struct vchiq_drvdata *drvdata = platform_get_drvdata(pdev);
- struct rpi_firmware *fw = drvdata->fw;
+ struct vchiq_drv_mgmt *drv_mgmt = platform_get_drvdata(pdev);
+ struct rpi_firmware *fw = drv_mgmt->fw;
struct vchiq_slot_zero *vchiq_slot_zero;
void *slot_mem;
dma_addr_t slot_phys;
@@ -484,12 +515,11 @@ static int vchiq_platform_init(struct platform_device *pdev, struct vchiq_state
if (err < 0)
return err;
- g_cache_line_size = drvdata->cache_line_size;
- g_fragments_size = 2 * g_cache_line_size;
+ drv_mgmt->fragments_size = 2 * drv_mgmt->info->cache_line_size;
/* Allocate space for the channels in coherent memory */
slot_mem_size = PAGE_ALIGN(TOTAL_SLOTS * VCHIQ_SLOT_SIZE);
- frag_mem_size = PAGE_ALIGN(g_fragments_size * MAX_FRAGMENTS);
+ frag_mem_size = PAGE_ALIGN(drv_mgmt->fragments_size * MAX_FRAGMENTS);
slot_mem = dmam_alloc_coherent(dev, slot_mem_size + frag_mem_size,
&slot_phys, GFP_KERNEL);
@@ -509,23 +539,24 @@ static int vchiq_platform_init(struct platform_device *pdev, struct vchiq_state
vchiq_slot_zero->platform_data[VCHIQ_PLATFORM_FRAGMENTS_COUNT_IDX] =
MAX_FRAGMENTS;
- g_fragments_base = (char *)slot_mem + slot_mem_size;
+ drv_mgmt->fragments_base = (char *)slot_mem + slot_mem_size;
- g_free_fragments = g_fragments_base;
+ drv_mgmt->free_fragments = drv_mgmt->fragments_base;
for (i = 0; i < (MAX_FRAGMENTS - 1); i++) {
- *(char **)&g_fragments_base[i * g_fragments_size] =
- &g_fragments_base[(i + 1) * g_fragments_size];
+ *(char **)&drv_mgmt->fragments_base[i * drv_mgmt->fragments_size] =
+ &drv_mgmt->fragments_base[(i + 1) * drv_mgmt->fragments_size];
}
- *(char **)&g_fragments_base[i * g_fragments_size] = NULL;
- sema_init(&g_free_fragments_sema, MAX_FRAGMENTS);
+ *(char **)&drv_mgmt->fragments_base[i * drv_mgmt->fragments_size] = NULL;
+ sema_init(&drv_mgmt->free_fragments_sema, MAX_FRAGMENTS);
+ sema_init(&drv_mgmt->free_fragments_mutex, 1);
err = vchiq_init_state(state, vchiq_slot_zero, dev);
if (err)
return err;
- g_regs = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(g_regs))
- return PTR_ERR(g_regs);
+ drv_mgmt->regs = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(drv_mgmt->regs))
+ return PTR_ERR(drv_mgmt->regs);
irq = platform_get_irq(pdev, 0);
if (irq <= 0)
@@ -556,7 +587,8 @@ static int vchiq_platform_init(struct platform_device *pdev, struct vchiq_state
dev_dbg(&pdev->dev, "arm: vchiq_init - done (slots %pK, phys %pad)\n",
vchiq_slot_zero, &slot_phys);
- vchiq_call_connected_callbacks();
+ mutex_init(&drv_mgmt->connected_mutex);
+ vchiq_call_connected_callbacks(drv_mgmt);
return 0;
}
@@ -607,8 +639,10 @@ static struct vchiq_arm_state *vchiq_platform_get_arm_state(struct vchiq_state *
}
void
-remote_event_signal(struct remote_event *event)
+remote_event_signal(struct vchiq_state *state, struct remote_event *event)
{
+ struct vchiq_drv_mgmt *mgmt = dev_get_drvdata(state->dev);
+
/*
* Ensure that all writes to shared data structures have completed
* before signalling the peer.
@@ -620,7 +654,7 @@ remote_event_signal(struct remote_event *event)
dsb(sy); /* data barrier operation */
if (event->armed)
- writel(0, g_regs + BELL2); /* trigger vc interrupt */
+ writel(0, mgmt->regs + BELL2); /* trigger vc interrupt */
}
int
@@ -662,9 +696,8 @@ void vchiq_dump_platform_state(struct seq_file *f)
}
#define VCHIQ_INIT_RETRIES 10
-int vchiq_initialise(struct vchiq_instance **instance_out)
+int vchiq_initialise(struct vchiq_state *state, struct vchiq_instance **instance_out)
{
- struct vchiq_state *state;
struct vchiq_instance *instance = NULL;
int i, ret;
@@ -674,8 +707,7 @@ int vchiq_initialise(struct vchiq_instance **instance_out)
* block forever.
*/
for (i = 0; i < VCHIQ_INIT_RETRIES; i++) {
- state = vchiq_get_state();
- if (state)
+ if (vchiq_remote_initialised(state))
break;
usleep_range(500, 600);
}
@@ -690,7 +722,6 @@ int vchiq_initialise(struct vchiq_instance **instance_out)
instance = kzalloc(sizeof(*instance), GFP_KERNEL);
if (!instance) {
- dev_err(state->dev, "core: %s: Cannot allocate vchiq instance\n", __func__);
ret = -ENOMEM;
goto failed;
}
@@ -949,17 +980,15 @@ vchiq_blocking_bulk_transfer(struct vchiq_instance *instance, unsigned int handl
* This is not a retry of the previous one.
* Cancel the signal when the transfer completes.
*/
- spin_lock(&bulk_waiter_spinlock);
+ spin_lock(&service->state->bulk_waiter_spinlock);
bulk->userdata = NULL;
- spin_unlock(&bulk_waiter_spinlock);
+ spin_unlock(&service->state->bulk_waiter_spinlock);
}
}
} else {
waiter = kzalloc(sizeof(*waiter), GFP_KERNEL);
- if (!waiter) {
- dev_err(service->state->dev, "core: %s: - Out of memory\n", __func__);
+ if (!waiter)
return -ENOMEM;
- }
}
status = vchiq_bulk_transfer(instance, handle, data, NULL, size,
@@ -970,9 +999,9 @@ vchiq_blocking_bulk_transfer(struct vchiq_instance *instance, unsigned int handl
if (bulk) {
/* Cancel the signal when the transfer completes. */
- spin_lock(&bulk_waiter_spinlock);
+ spin_lock(&service->state->bulk_waiter_spinlock);
bulk->userdata = NULL;
- spin_unlock(&bulk_waiter_spinlock);
+ spin_unlock(&service->state->bulk_waiter_spinlock);
}
kfree(waiter);
} else {
@@ -993,9 +1022,10 @@ add_completion(struct vchiq_instance *instance, enum vchiq_reason reason,
void *bulk_userdata)
{
struct vchiq_completion_data_kernel *completion;
+ struct vchiq_drv_mgmt *mgmt = dev_get_drvdata(instance->state->dev);
int insert;
- DEBUG_INITIALISE(g_state.local);
+ DEBUG_INITIALISE(mgmt->state.local);
insert = instance->completion_insert;
while ((insert - instance->completion_remove) >= MAX_COMPLETIONS) {
@@ -1058,11 +1088,12 @@ service_callback(struct vchiq_instance *instance, enum vchiq_reason reason,
* containing the original callback and the user state structure, which
* contains a circular buffer for completion records.
*/
+ struct vchiq_drv_mgmt *mgmt = dev_get_drvdata(instance->state->dev);
struct user_service *user_service;
struct vchiq_service *service;
bool skip_completion = false;
- DEBUG_INITIALISE(g_state.local);
+ DEBUG_INITIALISE(mgmt->state.local);
DEBUG_TRACE(SERVICE_CALLBACK_LINE);
@@ -1075,7 +1106,7 @@ service_callback(struct vchiq_instance *instance, enum vchiq_reason reason,
user_service = (struct user_service *)service->base.userdata;
- if (!instance || instance->closing) {
+ if (instance->closing) {
rcu_read_unlock();
return 0;
}
@@ -1093,10 +1124,10 @@ service_callback(struct vchiq_instance *instance, enum vchiq_reason reason,
reason, header, instance, bulk_userdata);
if (header && user_service->is_vchi) {
- spin_lock(&msg_queue_spinlock);
+ spin_lock(&service->state->msg_queue_spinlock);
while (user_service->msg_insert ==
(user_service->msg_remove + MSG_QUEUE_SIZE)) {
- spin_unlock(&msg_queue_spinlock);
+ spin_unlock(&service->state->msg_queue_spinlock);
DEBUG_TRACE(SERVICE_CALLBACK_LINE);
DEBUG_COUNT(MSG_QUEUE_FULL_COUNT);
dev_dbg(service->state->dev, "arm: msg queue full\n");
@@ -1133,7 +1164,7 @@ service_callback(struct vchiq_instance *instance, enum vchiq_reason reason,
return -EINVAL;
}
DEBUG_TRACE(SERVICE_CALLBACK_LINE);
- spin_lock(&msg_queue_spinlock);
+ spin_lock(&service->state->msg_queue_spinlock);
}
user_service->msg_queue[user_service->msg_insert &
@@ -1152,7 +1183,7 @@ service_callback(struct vchiq_instance *instance, enum vchiq_reason reason,
skip_completion = true;
}
- spin_unlock(&msg_queue_spinlock);
+ spin_unlock(&service->state->msg_queue_spinlock);
complete(&user_service->insert_event);
header = NULL;
@@ -1167,12 +1198,11 @@ service_callback(struct vchiq_instance *instance, enum vchiq_reason reason,
bulk_userdata);
}
-void vchiq_dump_platform_instances(struct seq_file *f)
+void vchiq_dump_platform_instances(struct vchiq_state *state, struct seq_file *f)
{
- struct vchiq_state *state = vchiq_get_state();
int i;
- if (!state)
+ if (!vchiq_remote_initialised(state))
return;
/*
@@ -1244,23 +1274,6 @@ void vchiq_dump_platform_service_state(struct seq_file *f,
seq_puts(f, "\n");
}
-struct vchiq_state *
-vchiq_get_state(void)
-{
- if (!g_state.remote) {
- pr_err("%s: g_state.remote == NULL\n", __func__);
- 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;
-}
-
/*
* Autosuspend related functionality
*/
@@ -1294,7 +1307,7 @@ vchiq_keepalive_thread_func(void *v)
.version_min = KEEPALIVE_VER_MIN
};
- ret = vchiq_initialise(&instance);
+ ret = vchiq_initialise(state, &instance);
if (ret) {
dev_err(state->dev, "suspend: %s: vchiq_initialise failed %d\n", __func__, ret);
goto exit;
@@ -1317,7 +1330,7 @@ vchiq_keepalive_thread_func(void *v)
long rc = 0, uc = 0;
if (wait_for_completion_interruptible(&arm_state->ka_evt)) {
- dev_err(state->dev, "suspend: %s: interrupted\n", __func__);
+ dev_dbg(state->dev, "suspend: %s: interrupted\n", __func__);
flush_signals(current);
continue;
}
@@ -1706,8 +1719,8 @@ void vchiq_platform_conn_state_changed(struct vchiq_state *state,
}
static const struct of_device_id vchiq_of_match[] = {
- { .compatible = "brcm,bcm2835-vchiq", .data = &bcm2835_drvdata },
- { .compatible = "brcm,bcm2836-vchiq", .data = &bcm2836_drvdata },
+ { .compatible = "brcm,bcm2835-vchiq", .data = &bcm2835_info },
+ { .compatible = "brcm,bcm2836-vchiq", .data = &bcm2836_info },
{},
};
MODULE_DEVICE_TABLE(of, vchiq_of_match);
@@ -1715,13 +1728,12 @@ MODULE_DEVICE_TABLE(of, vchiq_of_match);
static int vchiq_probe(struct platform_device *pdev)
{
struct device_node *fw_node;
- const struct of_device_id *of_id;
- struct vchiq_drvdata *drvdata;
+ const struct vchiq_platform_info *info;
+ struct vchiq_drv_mgmt *mgmt;
int err;
- of_id = of_match_node(vchiq_of_match, pdev->dev.of_node);
- drvdata = (struct vchiq_drvdata *)of_id->data;
- if (!drvdata)
+ info = of_device_get_match_data(&pdev->dev);
+ if (!info)
return -EINVAL;
fw_node = of_find_compatible_node(NULL, NULL,
@@ -1731,18 +1743,23 @@ static int vchiq_probe(struct platform_device *pdev)
return -ENOENT;
}
- drvdata->fw = devm_rpi_firmware_get(&pdev->dev, fw_node);
+ mgmt = kzalloc(sizeof(*mgmt), GFP_KERNEL);
+ if (!mgmt)
+ return -ENOMEM;
+
+ mgmt->fw = devm_rpi_firmware_get(&pdev->dev, fw_node);
of_node_put(fw_node);
- if (!drvdata->fw)
+ if (!mgmt->fw)
return -EPROBE_DEFER;
- platform_set_drvdata(pdev, drvdata);
+ mgmt->info = info;
+ platform_set_drvdata(pdev, mgmt);
- err = vchiq_platform_init(pdev, &g_state);
+ err = vchiq_platform_init(pdev, &mgmt->state);
if (err)
goto failed_platform_init;
- vchiq_debugfs_init();
+ vchiq_debugfs_init(&mgmt->state);
dev_dbg(&pdev->dev, "arm: platform initialised - version %d (min %d)\n",
VCHIQ_VERSION, VCHIQ_VERSION_MIN);
@@ -1753,7 +1770,7 @@ static int vchiq_probe(struct platform_device *pdev)
*/
err = vchiq_register_chrdev(&pdev->dev);
if (err) {
- dev_warn(&pdev->dev, "arm: Failed to initialize vchiq cdev\n");
+ dev_err(&pdev->dev, "arm: Failed to initialize vchiq cdev\n");
goto error_exit;
}
@@ -1763,17 +1780,21 @@ static int vchiq_probe(struct platform_device *pdev)
return 0;
failed_platform_init:
- dev_warn(&pdev->dev, "arm: Could not initialize vchiq platform\n");
+ dev_err(&pdev->dev, "arm: Could not initialize vchiq platform\n");
error_exit:
return err;
}
static void vchiq_remove(struct platform_device *pdev)
{
+ struct vchiq_drv_mgmt *mgmt = dev_get_drvdata(&pdev->dev);
+
vchiq_device_unregister(bcm2835_audio);
vchiq_device_unregister(bcm2835_camera);
vchiq_debugfs_deinit();
vchiq_deregister_chrdev();
+
+ kfree(mgmt);
}
static struct platform_driver vchiq_driver = {
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 7844ef765a..fd1b9d3555 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h
@@ -20,11 +20,42 @@
#define MAX_ELEMENTS 8
#define MSG_QUEUE_SIZE 128
+#define VCHIQ_DRV_MAX_CALLBACKS 10
+
+struct rpi_firmware;
+struct vchiq_device;
+
enum USE_TYPE_E {
USE_TYPE_SERVICE,
USE_TYPE_VCHIQ
};
+struct vchiq_platform_info {
+ unsigned int cache_line_size;
+};
+
+struct vchiq_drv_mgmt {
+ struct rpi_firmware *fw;
+ const struct vchiq_platform_info *info;
+
+ bool connected;
+ int num_deferred_callbacks;
+ /* Protects connected and num_deferred_callbacks */
+ struct mutex connected_mutex;
+
+ void (*deferred_callback[VCHIQ_DRV_MAX_CALLBACKS])(void);
+
+ struct semaphore free_fragments_sema;
+ struct semaphore free_fragments_mutex;
+ char *fragments_base;
+ char *free_fragments;
+ unsigned int fragments_size;
+
+ void __iomem *regs;
+
+ struct vchiq_state state;
+};
+
struct user_service {
struct vchiq_service *service;
void __user *userdata;
@@ -69,12 +100,6 @@ struct vchiq_instance {
struct vchiq_debugfs_node debugfs_node;
};
-extern spinlock_t msg_queue_spinlock;
-extern struct vchiq_state g_state;
-
-extern struct vchiq_state *
-vchiq_get_state(void);
-
int
vchiq_use_service(struct vchiq_instance *instance, unsigned int handle);
@@ -112,6 +137,10 @@ vchiq_instance_get_trace(struct vchiq_instance *instance);
extern void
vchiq_instance_set_trace(struct vchiq_instance *instance, int trace);
+extern void
+vchiq_add_connected_callback(struct vchiq_device *device,
+ void (*callback)(void));
+
#if IS_ENABLED(CONFIG_VCHIQ_CDEV)
extern void
diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_bus.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_bus.c
index 68f830d755..3f87b93c65 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_bus.c
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_bus.c
@@ -11,6 +11,7 @@
#include <linux/slab.h>
#include <linux/string.h>
+#include "vchiq_arm.h"
#include "vchiq_bus.h"
static int vchiq_bus_type_match(struct device *dev, struct device_driver *drv)
@@ -37,11 +38,21 @@ static int vchiq_bus_probe(struct device *dev)
return driver->probe(device);
}
+static void vchiq_bus_remove(struct device *dev)
+{
+ struct vchiq_device *device = to_vchiq_device(dev);
+ struct vchiq_driver *driver = to_vchiq_driver(dev->driver);
+
+ if (driver->remove)
+ driver->remove(device);
+}
+
const struct bus_type vchiq_bus_type = {
.name = "vchiq-bus",
.match = vchiq_bus_type_match,
.uevent = vchiq_bus_uevent,
.probe = vchiq_bus_probe,
+ .remove = vchiq_bus_remove,
};
static void vchiq_device_release(struct device *dev)
@@ -67,6 +78,8 @@ vchiq_device_register(struct device *parent, const char *name)
device->dev.dma_mask = &device->dev.coherent_dma_mask;
device->dev.release = vchiq_device_release;
+ device->drv_mgmt = dev_get_drvdata(parent);
+
of_dma_configure(&device->dev, parent->of_node, true);
ret = device_register(&device->dev);
diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_bus.h b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_bus.h
index 4db86e76ed..9de179b39f 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_bus.h
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_bus.h
@@ -9,8 +9,11 @@
#include <linux/device.h>
#include <linux/mod_devicetable.h>
+struct vchiq_drv_mgmt;
+
struct vchiq_device {
struct device dev;
+ struct vchiq_drv_mgmt *drv_mgmt;
};
struct vchiq_driver {
diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_connected.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_connected.c
deleted file mode 100644
index 3cad13f09e..0000000000
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_connected.c
+++ /dev/null
@@ -1,74 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
-/* Copyright (c) 2010-2012 Broadcom. All rights reserved. */
-
-#include "vchiq_connected.h"
-#include "vchiq_core.h"
-#include <linux/module.h>
-#include <linux/mutex.h>
-
-#define MAX_CALLBACKS 10
-
-static int g_connected;
-static int g_num_deferred_callbacks;
-static void (*g_deferred_callback[MAX_CALLBACKS])(void);
-static int g_once_init;
-static DEFINE_MUTEX(g_connected_mutex);
-
-/* Function to initialize our lock */
-static void connected_init(void)
-{
- if (!g_once_init)
- g_once_init = 1;
-}
-
-/*
- * This function is used to defer initialization until the vchiq stack is
- * initialized. If the stack is already initialized, then the callback will
- * be made immediately, otherwise it will be deferred until
- * vchiq_call_connected_callbacks is called.
- */
-void vchiq_add_connected_callback(struct vchiq_device *device, void (*callback)(void))
-{
- connected_init();
-
- if (mutex_lock_killable(&g_connected_mutex))
- return;
-
- if (g_connected) {
- /* We're already connected. Call the callback immediately. */
- callback();
- } else {
- if (g_num_deferred_callbacks >= MAX_CALLBACKS) {
- dev_err(&device->dev,
- "core: There already %d callback registered - please increase MAX_CALLBACKS\n",
- g_num_deferred_callbacks);
- } else {
- g_deferred_callback[g_num_deferred_callbacks] =
- callback;
- g_num_deferred_callbacks++;
- }
- }
- mutex_unlock(&g_connected_mutex);
-}
-EXPORT_SYMBOL(vchiq_add_connected_callback);
-
-/*
- * This function is called by the vchiq stack once it has been connected to
- * the videocore and clients can start to use the stack.
- */
-void vchiq_call_connected_callbacks(void)
-{
- int i;
-
- connected_init();
-
- if (mutex_lock_killable(&g_connected_mutex))
- return;
-
- for (i = 0; i < g_num_deferred_callbacks; i++)
- g_deferred_callback[i]();
-
- g_num_deferred_callbacks = 0;
- g_connected = 1;
- mutex_unlock(&g_connected_mutex);
-}
diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_connected.h b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_connected.h
deleted file mode 100644
index e4ed56446f..0000000000
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_connected.h
+++ /dev/null
@@ -1,12 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
-/* Copyright (c) 2010-2012 Broadcom. All rights reserved. */
-
-#include "vchiq_bus.h"
-
-#ifndef VCHIQ_CONNECTED_H
-#define VCHIQ_CONNECTED_H
-
-void vchiq_add_connected_callback(struct vchiq_device *device, void (*callback)(void));
-void vchiq_call_connected_callbacks(void);
-
-#endif /* VCHIQ_CONNECTED_H */
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 76c2777815..df3af821f2 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c
@@ -43,7 +43,7 @@
(((type) << TYPE_SHIFT) | ((srcport) << 12) | ((dstport) << 0))
#define VCHIQ_MSG_TYPE(msgid) ((unsigned int)(msgid) >> TYPE_SHIFT)
#define VCHIQ_MSG_SRCPORT(msgid) \
- (unsigned short)(((unsigned int)(msgid) >> 12) & 0xfff)
+ ((unsigned short)(((unsigned int)(msgid) >> 12) & 0xfff))
#define VCHIQ_MSG_DSTPORT(msgid) \
((unsigned short)(msgid) & 0xfff)
@@ -149,9 +149,6 @@ static inline void check_sizes(void)
BUILD_BUG_ON_NOT_POWER_OF_2(VCHIQ_MAX_SERVICES);
}
-DEFINE_SPINLOCK(bulk_waiter_spinlock);
-static DEFINE_SPINLOCK(quota_spinlock);
-
static unsigned int handle_seq;
static const char *const srvstate_names[] = {
@@ -230,6 +227,7 @@ struct vchiq_service *handle_to_service(struct vchiq_instance *instance, unsigne
return rcu_dereference(instance->state->services[idx]);
}
+
struct vchiq_service *
find_service_by_handle(struct vchiq_instance *instance, unsigned int handle)
{
@@ -691,7 +689,7 @@ reserve_space(struct vchiq_state *state, size_t space, int is_blocking)
/* But first, flush through the last slot. */
state->local_tx_pos = tx_pos;
local->tx_pos = tx_pos;
- remote_event_signal(&state->remote->trigger);
+ remote_event_signal(state, &state->remote->trigger);
if (!is_blocking ||
(wait_for_completion_interruptible(&state->slot_available_event)))
@@ -700,7 +698,8 @@ reserve_space(struct vchiq_state *state, size_t space, int is_blocking)
if (tx_pos == (state->slot_queue_available * VCHIQ_SLOT_SIZE)) {
complete(&state->slot_available_event);
- pr_warn("%s: invalid tx_pos: %d\n", __func__, tx_pos);
+ dev_warn(state->dev, "%s: invalid tx_pos: %d\n",
+ __func__, tx_pos);
return NULL;
}
@@ -724,11 +723,11 @@ process_free_data_message(struct vchiq_state *state, u32 *service_found,
struct vchiq_service_quota *quota = &state->service_quotas[port];
int count;
- spin_lock(&quota_spinlock);
+ spin_lock(&state->quota_spinlock);
count = quota->message_use_count;
if (count > 0)
quota->message_use_count = count - 1;
- spin_unlock(&quota_spinlock);
+ spin_unlock(&state->quota_spinlock);
if (count == quota->message_quota) {
/*
@@ -747,11 +746,11 @@ process_free_data_message(struct vchiq_state *state, u32 *service_found,
/* Set the found bit for this service */
BITSET_SET(service_found, port);
- spin_lock(&quota_spinlock);
+ spin_lock(&state->quota_spinlock);
count = quota->slot_use_count;
if (count > 0)
quota->slot_use_count = count - 1;
- spin_unlock(&quota_spinlock);
+ spin_unlock(&state->quota_spinlock);
if (count > 0) {
/*
@@ -837,11 +836,11 @@ process_free_queue(struct vchiq_state *state, u32 *service_found,
if (data_found) {
int count;
- spin_lock(&quota_spinlock);
+ spin_lock(&state->quota_spinlock);
count = state->data_use_count;
if (count > 0)
state->data_use_count = count - 1;
- spin_unlock(&quota_spinlock);
+ spin_unlock(&state->quota_spinlock);
if (count == state->data_quota)
complete(&state->data_quota_event);
}
@@ -940,7 +939,7 @@ queue_message(struct vchiq_state *state, struct vchiq_service *service,
quota = &state->service_quotas[service->localport];
- spin_lock(&quota_spinlock);
+ spin_lock(&state->quota_spinlock);
/*
* Ensure this service doesn't use more than its quota of
@@ -955,14 +954,14 @@ queue_message(struct vchiq_state *state, struct vchiq_service *service,
while ((tx_end_index != state->previous_data_index) &&
(state->data_use_count == state->data_quota)) {
VCHIQ_STATS_INC(state, data_stalls);
- spin_unlock(&quota_spinlock);
+ spin_unlock(&state->quota_spinlock);
mutex_unlock(&state->slot_mutex);
if (wait_for_completion_interruptible(&state->data_quota_event))
return -EAGAIN;
mutex_lock(&state->slot_mutex);
- spin_lock(&quota_spinlock);
+ spin_lock(&state->quota_spinlock);
tx_end_index = SLOT_QUEUE_INDEX_FROM_POS(state->local_tx_pos + stride - 1);
if ((tx_end_index == state->previous_data_index) ||
(state->data_use_count < state->data_quota)) {
@@ -975,7 +974,7 @@ queue_message(struct vchiq_state *state, struct vchiq_service *service,
while ((quota->message_use_count == quota->message_quota) ||
((tx_end_index != quota->previous_tx_index) &&
(quota->slot_use_count == quota->slot_quota))) {
- spin_unlock(&quota_spinlock);
+ spin_unlock(&state->quota_spinlock);
dev_dbg(state->dev,
"core: %d: qm:%d %s,%zx - quota stall (msg %d, slot %d)\n",
state->id, service->localport, msg_type_str(type), size,
@@ -993,11 +992,11 @@ queue_message(struct vchiq_state *state, struct vchiq_service *service,
mutex_unlock(&state->slot_mutex);
return -EHOSTDOWN;
}
- spin_lock(&quota_spinlock);
+ spin_lock(&state->quota_spinlock);
tx_end_index = SLOT_QUEUE_INDEX_FROM_POS(state->local_tx_pos + stride - 1);
}
- spin_unlock(&quota_spinlock);
+ spin_unlock(&state->quota_spinlock);
}
header = reserve_space(state, stride, flags & QMFLAGS_IS_BLOCKING);
@@ -1040,7 +1039,7 @@ queue_message(struct vchiq_state *state, struct vchiq_service *service,
header->data,
min_t(size_t, 16, callback_result));
- spin_lock(&quota_spinlock);
+ spin_lock(&state->quota_spinlock);
quota->message_use_count++;
tx_end_index =
@@ -1066,7 +1065,7 @@ queue_message(struct vchiq_state *state, struct vchiq_service *service,
slot_use_count = 0;
}
- spin_unlock(&quota_spinlock);
+ spin_unlock(&state->quota_spinlock);
if (slot_use_count)
dev_dbg(state->dev, "core: %d: qm:%d %s,%zx - slot_use->%d (hdr %p)\n",
@@ -1124,7 +1123,7 @@ queue_message(struct vchiq_state *state, struct vchiq_service *service,
if (!(flags & QMFLAGS_NO_MUTEX_UNLOCK))
mutex_unlock(&state->slot_mutex);
- remote_event_signal(&state->remote->trigger);
+ remote_event_signal(state, &state->remote->trigger);
return 0;
}
@@ -1192,7 +1191,6 @@ queue_message_sync(struct vchiq_state *state, struct vchiq_service *service,
header->size = size;
header->msgid = msgid;
-
svc_fourcc = service ? service->base.fourcc
: VCHIQ_MAKE_FOURCC('?', '?', '?', '?');
@@ -1202,7 +1200,7 @@ queue_message_sync(struct vchiq_state *state, struct vchiq_service *service,
&svc_fourcc, VCHIQ_MSG_SRCPORT(msgid),
VCHIQ_MSG_DSTPORT(msgid), size);
- remote_event_signal(&state->remote->sync_trigger);
+ remote_event_signal(state, &state->remote->sync_trigger);
if (VCHIQ_MSG_TYPE(msgid) != VCHIQ_MSG_PAUSE)
mutex_unlock(&state->sync_mutex);
@@ -1260,7 +1258,7 @@ release_slot(struct vchiq_state *state, struct vchiq_slot_info *slot_info,
* A write barrier is necessary, but remote_event_signal
* contains one.
*/
- remote_event_signal(&state->remote->recycle);
+ remote_event_signal(state, &state->remote->recycle);
}
mutex_unlock(&state->recycle_mutex);
@@ -1322,13 +1320,13 @@ notify_bulks(struct vchiq_service *service, struct vchiq_bulk_queue *queue,
if (bulk->mode == VCHIQ_BULK_MODE_BLOCKING) {
struct bulk_waiter *waiter;
- spin_lock(&bulk_waiter_spinlock);
+ spin_lock(&service->state->bulk_waiter_spinlock);
waiter = bulk->userdata;
if (waiter) {
waiter->actual = bulk->actual;
complete(&waiter->event);
}
- spin_unlock(&bulk_waiter_spinlock);
+ spin_unlock(&service->state->bulk_waiter_spinlock);
} else if (bulk->mode == VCHIQ_BULK_MODE_CALLBACK) {
enum vchiq_reason reason =
get_bulk_reason(bulk);
@@ -1618,7 +1616,6 @@ parse_message(struct vchiq_state *state, struct vchiq_header *header)
break;
}
-
svc_fourcc = service ? service->base.fourcc
: VCHIQ_MAKE_FOURCC('?', '?', '?', '?');
@@ -1735,10 +1732,9 @@ parse_message(struct vchiq_state *state, struct vchiq_header *header)
break;
}
if (queue->process != queue->remote_insert) {
- pr_err("%s: p %x != ri %x\n",
- __func__,
- queue->process,
- queue->remote_insert);
+ dev_err(state->dev, "%s: p %x != ri %x\n",
+ __func__, queue->process,
+ queue->remote_insert);
mutex_unlock(&service->bulk_mutex);
goto bail_not_ready;
}
@@ -2169,6 +2165,10 @@ vchiq_init_state(struct vchiq_state *state, struct vchiq_slot_zero *slot_zero, s
mutex_init(&state->sync_mutex);
mutex_init(&state->bulk_transfer_mutex);
+ spin_lock_init(&state->msg_queue_spinlock);
+ spin_lock_init(&state->bulk_waiter_spinlock);
+ spin_lock_init(&state->quota_spinlock);
+
init_completion(&state->slot_available_event);
init_completion(&state->slot_remove_event);
init_completion(&state->data_quota_event);
@@ -2177,6 +2177,7 @@ vchiq_init_state(struct vchiq_state *state, struct vchiq_slot_zero *slot_zero, s
for (i = 0; i < VCHIQ_MAX_SERVICES; i++) {
struct vchiq_service_quota *quota = &state->service_quotas[i];
+
init_completion(&quota->quota_event);
}
@@ -3240,7 +3241,7 @@ static void
release_message_sync(struct vchiq_state *state, struct vchiq_header *header)
{
header->msgid = VCHIQ_MSGID_PADDING;
- remote_event_signal(&state->remote->sync_release);
+ remote_event_signal(state, &state->remote->sync_release);
}
int
@@ -3504,7 +3505,7 @@ void vchiq_dump_state(struct seq_file *f, struct vchiq_state *state)
vchiq_dump_shared_state(f, state, state->remote, "Remote");
- vchiq_dump_platform_instances(f);
+ vchiq_dump_platform_instances(state, f);
for (i = 0; i < state->unused_service; i++) {
struct vchiq_service *service = find_service_by_port(state, i);
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 c8527551b5..382ec08f6a 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h
@@ -11,6 +11,7 @@
#include <linux/kthread.h>
#include <linux/kref.h>
#include <linux/rcupdate.h>
+#include <linux/spinlock_types.h>
#include <linux/wait.h>
#include "../../include/linux/raspberrypi/vchiq.h"
@@ -348,6 +349,12 @@ struct vchiq_state {
struct mutex bulk_transfer_mutex;
+ spinlock_t msg_queue_spinlock;
+
+ spinlock_t bulk_waiter_spinlock;
+
+ spinlock_t quota_spinlock;
+
/*
* Indicates the byte position within the stream from where the next
* message will be read. The least significant bits are an index into
@@ -406,6 +413,11 @@ struct vchiq_state {
struct opaque_platform_state *platform_state;
};
+static inline bool vchiq_remote_initialised(const struct vchiq_state *state)
+{
+ return state->remote && state->remote->initialised;
+}
+
struct bulk_waiter {
struct vchiq_bulk *bulk;
struct completion event;
@@ -471,12 +483,6 @@ extern void
vchiq_dump_state(struct seq_file *f, struct vchiq_state *state);
extern void
-vchiq_loud_error_header(void);
-
-extern void
-vchiq_loud_error_footer(void);
-
-extern void
request_poll(struct vchiq_state *state, struct vchiq_service *service,
int poll_type);
@@ -522,11 +528,11 @@ int vchiq_prepare_bulk_data(struct vchiq_instance *instance, struct vchiq_bulk *
void vchiq_complete_bulk(struct vchiq_instance *instance, struct vchiq_bulk *bulk);
-void remote_event_signal(struct remote_event *event);
+void remote_event_signal(struct vchiq_state *state, struct remote_event *event);
void vchiq_dump_platform_state(struct seq_file *f);
-void vchiq_dump_platform_instances(struct seq_file *f);
+void vchiq_dump_platform_instances(struct vchiq_state *state, struct seq_file *f);
void vchiq_dump_platform_service_state(struct seq_file *f, struct vchiq_service *service);
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 d833e4e297..d5f7f61c56 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_debugfs.c
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_debugfs.c
@@ -42,7 +42,10 @@ static int debugfs_trace_show(struct seq_file *f, void *offset)
static int vchiq_dump_show(struct seq_file *f, void *offset)
{
- vchiq_dump_state(f, &g_state);
+ struct vchiq_state *state = f->private;
+
+ vchiq_dump_state(f, state);
+
return 0;
}
DEFINE_SHOW_ATTRIBUTE(vchiq_dump);
@@ -118,12 +121,12 @@ void vchiq_debugfs_remove_instance(struct vchiq_instance *instance)
debugfs_remove_recursive(node->dentry);
}
-void vchiq_debugfs_init(void)
+void vchiq_debugfs_init(struct vchiq_state *state)
{
vchiq_dbg_dir = debugfs_create_dir("vchiq", NULL);
vchiq_dbg_clients = debugfs_create_dir("clients", vchiq_dbg_dir);
- debugfs_create_file("state", S_IFREG | 0444, vchiq_dbg_dir, NULL,
+ debugfs_create_file("state", S_IFREG | 0444, vchiq_dbg_dir, state,
&vchiq_dump_fops);
}
@@ -135,7 +138,7 @@ void vchiq_debugfs_deinit(void)
#else /* CONFIG_DEBUG_FS */
-void vchiq_debugfs_init(void)
+void vchiq_debugfs_init(struct vchiq_state *state)
{
}
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 e9bf055a4c..fabffd81b1 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_debugfs.h
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_debugfs.h
@@ -10,7 +10,7 @@ struct vchiq_debugfs_node {
struct dentry *dentry;
};
-void vchiq_debugfs_init(void);
+void vchiq_debugfs_init(struct vchiq_state *state);
void vchiq_debugfs_deinit(void);
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 4d9deeeb63..430f2ed2cc 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_dev.c
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_dev.c
@@ -208,7 +208,7 @@ static int vchiq_ioc_dequeue_message(struct vchiq_instance *instance,
struct vchiq_header *header;
int ret;
- DEBUG_INITIALISE(g_state.local);
+ DEBUG_INITIALISE(instance->state->local);
DEBUG_TRACE(DEQUEUE_MESSAGE_LINE);
service = find_service_for_instance(instance, args->handle);
if (!service)
@@ -220,10 +220,10 @@ static int vchiq_ioc_dequeue_message(struct vchiq_instance *instance,
goto out;
}
- spin_lock(&msg_queue_spinlock);
+ spin_lock(&service->state->msg_queue_spinlock);
if (user_service->msg_remove == user_service->msg_insert) {
if (!args->blocking) {
- spin_unlock(&msg_queue_spinlock);
+ spin_unlock(&service->state->msg_queue_spinlock);
DEBUG_TRACE(DEQUEUE_MESSAGE_LINE);
ret = -EWOULDBLOCK;
goto out;
@@ -231,14 +231,14 @@ static int vchiq_ioc_dequeue_message(struct vchiq_instance *instance,
user_service->dequeue_pending = 1;
ret = 0;
do {
- spin_unlock(&msg_queue_spinlock);
+ spin_unlock(&service->state->msg_queue_spinlock);
DEBUG_TRACE(DEQUEUE_MESSAGE_LINE);
if (wait_for_completion_interruptible(&user_service->insert_event)) {
dev_dbg(service->state->dev, "arm: DEQUEUE_MESSAGE interrupted\n");
ret = -EINTR;
break;
}
- spin_lock(&msg_queue_spinlock);
+ spin_lock(&service->state->msg_queue_spinlock);
} while (user_service->msg_remove == user_service->msg_insert);
if (ret)
@@ -247,7 +247,7 @@ static int vchiq_ioc_dequeue_message(struct vchiq_instance *instance,
if (WARN_ON_ONCE((int)(user_service->msg_insert -
user_service->msg_remove) < 0)) {
- spin_unlock(&msg_queue_spinlock);
+ spin_unlock(&service->state->msg_queue_spinlock);
ret = -EINVAL;
goto out;
}
@@ -255,7 +255,7 @@ static int vchiq_ioc_dequeue_message(struct vchiq_instance *instance,
header = user_service->msg_queue[user_service->msg_remove &
(MSG_QUEUE_SIZE - 1)];
user_service->msg_remove++;
- spin_unlock(&msg_queue_spinlock);
+ spin_unlock(&service->state->msg_queue_spinlock);
complete(&user_service->remove_event);
if (!header) {
@@ -340,9 +340,9 @@ static int vchiq_irq_queue_bulk_tx_rx(struct vchiq_instance *instance,
!waiter->bulk_waiter.bulk) {
if (waiter->bulk_waiter.bulk) {
/* Cancel the signal when the transfer completes. */
- spin_lock(&bulk_waiter_spinlock);
+ spin_lock(&service->state->bulk_waiter_spinlock);
waiter->bulk_waiter.bulk->userdata = NULL;
- spin_unlock(&bulk_waiter_spinlock);
+ spin_unlock(&service->state->bulk_waiter_spinlock);
}
kfree(waiter);
ret = 0;
@@ -435,7 +435,7 @@ static int vchiq_ioc_await_completion(struct vchiq_instance *instance,
int remove;
int ret;
- DEBUG_INITIALISE(g_state.local);
+ DEBUG_INITIALISE(instance->state->local);
DEBUG_TRACE(AWAIT_COMPLETION_LINE);
if (!instance->connected)
@@ -1163,13 +1163,15 @@ vchiq_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
static int vchiq_open(struct inode *inode, struct file *file)
{
- struct vchiq_state *state = vchiq_get_state();
+ struct miscdevice *vchiq_miscdev = file->private_data;
+ struct vchiq_drv_mgmt *mgmt = dev_get_drvdata(vchiq_miscdev->parent);
+ struct vchiq_state *state = &mgmt->state;
struct vchiq_instance *instance;
dev_dbg(state->dev, "arm: vchiq open\n");
- if (!state) {
- dev_err(state->dev, "arm: vchiq has no connection to VideoCore\n");
+ if (!vchiq_remote_initialised(state)) {
+ dev_dbg(state->dev, "arm: vchiq has no connection to VideoCore\n");
return -ENOTCONN;
}
@@ -1196,14 +1198,14 @@ static int vchiq_open(struct inode *inode, struct file *file)
static int vchiq_release(struct inode *inode, struct file *file)
{
struct vchiq_instance *instance = file->private_data;
- struct vchiq_state *state = vchiq_get_state();
+ struct vchiq_state *state = instance->state;
struct vchiq_service *service;
int ret = 0;
int i;
dev_dbg(state->dev, "arm: instance=%p\n", instance);
- if (!state) {
+ if (!vchiq_remote_initialised(state)) {
ret = -EPERM;
goto out;
}
@@ -1246,7 +1248,7 @@ static int vchiq_release(struct inode *inode, struct file *file)
break;
}
- spin_lock(&msg_queue_spinlock);
+ spin_lock(&service->state->msg_queue_spinlock);
while (user_service->msg_remove != user_service->msg_insert) {
struct vchiq_header *header;
@@ -1254,14 +1256,14 @@ static int vchiq_release(struct inode *inode, struct file *file)
header = user_service->msg_queue[m];
user_service->msg_remove++;
- spin_unlock(&msg_queue_spinlock);
+ spin_unlock(&service->state->msg_queue_spinlock);
if (header)
vchiq_release_message(instance, service->handle, header);
- spin_lock(&msg_queue_spinlock);
+ spin_lock(&service->state->msg_queue_spinlock);
}
- spin_unlock(&msg_queue_spinlock);
+ spin_unlock(&service->state->msg_queue_spinlock);
vchiq_service_put(service);
}
diff --git a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c
index 4c3684dd90..fca920d41e 100644
--- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c
+++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c
@@ -26,6 +26,7 @@
#include <media/videobuf2-vmalloc.h>
#include "../include/linux/raspberrypi/vchiq.h"
+#include "../interface/vchiq_arm/vchiq_arm.h"
#include "mmal-common.h"
#include "mmal-vchiq.h"
#include "mmal-msg.h"
@@ -548,9 +549,9 @@ static void bulk_abort_cb(struct vchiq_mmal_instance *instance,
}
/* incoming event service callback */
-static int service_callback(struct vchiq_instance *vchiq_instance,
- enum vchiq_reason reason, struct vchiq_header *header,
- unsigned int handle, void *bulk_ctx)
+static int mmal_service_callback(struct vchiq_instance *vchiq_instance,
+ enum vchiq_reason reason, struct vchiq_header *header,
+ unsigned int handle, void *bulk_ctx)
{
struct vchiq_mmal_instance *instance = vchiq_get_service_userdata(vchiq_instance, handle);
u32 msg_len;
@@ -1852,7 +1853,7 @@ int vchiq_mmal_finalise(struct vchiq_mmal_instance *instance)
}
EXPORT_SYMBOL_GPL(vchiq_mmal_finalise);
-int vchiq_mmal_init(struct vchiq_mmal_instance **out_instance)
+int vchiq_mmal_init(struct device *dev, struct vchiq_mmal_instance **out_instance)
{
int status;
int err = -ENODEV;
@@ -1862,9 +1863,10 @@ int vchiq_mmal_init(struct vchiq_mmal_instance **out_instance)
.version = VC_MMAL_VER,
.version_min = VC_MMAL_MIN_VER,
.fourcc = VCHIQ_MAKE_FOURCC('m', 'm', 'a', 'l'),
- .callback = service_callback,
+ .callback = mmal_service_callback,
.userdata = NULL,
};
+ struct vchiq_drv_mgmt *mgmt = dev_get_drvdata(dev->parent);
/* compile time checks to ensure structure size as they are
* directly (de)serialised from memory.
@@ -1880,7 +1882,7 @@ int vchiq_mmal_init(struct vchiq_mmal_instance **out_instance)
BUILD_BUG_ON(sizeof(struct mmal_port) != 64);
/* create a vchi instance */
- status = vchiq_initialise(&vchiq_instance);
+ status = vchiq_initialise(&mgmt->state, &vchiq_instance);
if (status) {
pr_err("Failed to initialise VCHI instance (status=%d)\n",
status);
diff --git a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h
index 09f030919d..97abe4bdcf 100644
--- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h
+++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.h
@@ -25,6 +25,7 @@
#define MMAL_FORMAT_EXTRADATA_MAX_SIZE 128
struct vchiq_mmal_instance;
+struct device;
enum vchiq_mmal_es_type {
MMAL_ES_TYPE_UNKNOWN, /**< Unknown elementary stream type */
@@ -42,8 +43,7 @@ struct vchiq_mmal_port_buffer {
struct vchiq_mmal_port;
-typedef void (*vchiq_mmal_buffer_cb)(
- struct vchiq_mmal_instance *instance,
+typedef void (*vchiq_mmal_buffer_cb)(struct vchiq_mmal_instance *instance,
struct vchiq_mmal_port *port,
int status, struct mmal_buffer *buffer);
@@ -95,37 +95,31 @@ struct vchiq_mmal_component {
u32 client_component; /* Used to ref back to client struct */
};
-int vchiq_mmal_init(struct vchiq_mmal_instance **out_instance);
+int vchiq_mmal_init(struct device *dev, struct vchiq_mmal_instance **out_instance);
int vchiq_mmal_finalise(struct vchiq_mmal_instance *instance);
/* Initialise a mmal component and its ports
*
*/
-int vchiq_mmal_component_init(
- struct vchiq_mmal_instance *instance,
- const char *name,
- struct vchiq_mmal_component **component_out);
+int vchiq_mmal_component_init(struct vchiq_mmal_instance *instance,
+ const char *name, struct vchiq_mmal_component **component_out);
-int vchiq_mmal_component_finalise(
- struct vchiq_mmal_instance *instance,
- struct vchiq_mmal_component *component);
+int vchiq_mmal_component_finalise(struct vchiq_mmal_instance *instance,
+ struct vchiq_mmal_component *component);
-int vchiq_mmal_component_enable(
- struct vchiq_mmal_instance *instance,
- struct vchiq_mmal_component *component);
+int vchiq_mmal_component_enable(struct vchiq_mmal_instance *instance,
+ struct vchiq_mmal_component *component);
-int vchiq_mmal_component_disable(
- struct vchiq_mmal_instance *instance,
- struct vchiq_mmal_component *component);
+int vchiq_mmal_component_disable(struct vchiq_mmal_instance *instance,
+ struct vchiq_mmal_component *component);
/* enable a mmal port
*
* enables a port and if a buffer callback provided enque buffer
* headers as appropriate for the port.
*/
-int vchiq_mmal_port_enable(
- struct vchiq_mmal_instance *instance,
- struct vchiq_mmal_port *port,
+int vchiq_mmal_port_enable(struct vchiq_mmal_instance *instance,
+ struct vchiq_mmal_port *port,
vchiq_mmal_buffer_cb buffer_cb);
/* disable a port