aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/bcm27xx/patches-4.19/950-0240-staging-vc04_services-Add-new-vc-sm-cma-driver.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/bcm27xx/patches-4.19/950-0240-staging-vc04_services-Add-new-vc-sm-cma-driver.patch')
-rw-r--r--target/linux/bcm27xx/patches-4.19/950-0240-staging-vc04_services-Add-new-vc-sm-cma-driver.patch1881
1 files changed, 0 insertions, 1881 deletions
diff --git a/target/linux/bcm27xx/patches-4.19/950-0240-staging-vc04_services-Add-new-vc-sm-cma-driver.patch b/target/linux/bcm27xx/patches-4.19/950-0240-staging-vc04_services-Add-new-vc-sm-cma-driver.patch
deleted file mode 100644
index 9e9af47a37..0000000000
--- a/target/linux/bcm27xx/patches-4.19/950-0240-staging-vc04_services-Add-new-vc-sm-cma-driver.patch
+++ /dev/null
@@ -1,1881 +0,0 @@
-From 2994fdc0a9d48be68d6e403bc8ddadecfc8d8796 Mon Sep 17 00:00:00 2001
-From: Dave Stevenson <dave.stevenson@raspberrypi.org>
-Date: Tue, 25 Sep 2018 10:27:11 +0100
-Subject: [PATCH] staging: vc04_services: Add new vc-sm-cma driver
-
-This new driver allows contiguous memory blocks to be imported
-into the VideoCore VPU memory map, and manages the lifetime of
-those objects, only releasing the source dmabuf once the VPU has
-confirmed it has finished with it.
-
-Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
----
- drivers/staging/vc04_services/Kconfig | 1 +
- drivers/staging/vc04_services/Makefile | 1 +
- .../staging/vc04_services/vc-sm-cma/Kconfig | 10 +
- .../staging/vc04_services/vc-sm-cma/Makefile | 8 +
- drivers/staging/vc04_services/vc-sm-cma/TODO | 2 +
- .../staging/vc04_services/vc-sm-cma/vc_sm.c | 838 ++++++++++++++++++
- .../staging/vc04_services/vc-sm-cma/vc_sm.h | 59 ++
- .../vc04_services/vc-sm-cma/vc_sm_cma_vchi.c | 498 +++++++++++
- .../vc04_services/vc-sm-cma/vc_sm_cma_vchi.h | 59 ++
- .../vc04_services/vc-sm-cma/vc_sm_defs.h | 298 +++++++
- .../vc04_services/vc-sm-cma/vc_sm_knl.h | 28 +
- 11 files changed, 1802 insertions(+)
- create mode 100644 drivers/staging/vc04_services/vc-sm-cma/Kconfig
- create mode 100644 drivers/staging/vc04_services/vc-sm-cma/Makefile
- create mode 100644 drivers/staging/vc04_services/vc-sm-cma/TODO
- create mode 100644 drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
- create mode 100644 drivers/staging/vc04_services/vc-sm-cma/vc_sm.h
- create mode 100644 drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma_vchi.c
- create mode 100644 drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma_vchi.h
- create mode 100644 drivers/staging/vc04_services/vc-sm-cma/vc_sm_defs.h
- create mode 100644 drivers/staging/vc04_services/vc-sm-cma/vc_sm_knl.h
-
---- a/drivers/staging/vc04_services/Kconfig
-+++ b/drivers/staging/vc04_services/Kconfig
-@@ -22,6 +22,7 @@ source "drivers/staging/vc04_services/bc
-
- source "drivers/staging/vc04_services/bcm2835-camera/Kconfig"
- source "drivers/staging/vc04_services/vchiq-mmal/Kconfig"
-+source "drivers/staging/vc04_services/vc-sm-cma/Kconfig"
-
- endif
-
---- a/drivers/staging/vc04_services/Makefile
-+++ b/drivers/staging/vc04_services/Makefile
-@@ -13,6 +13,7 @@ vchiq-objs := \
- obj-$(CONFIG_SND_BCM2835) += bcm2835-audio/
- obj-$(CONFIG_VIDEO_BCM2835) += bcm2835-camera/
- obj-$(CONFIG_BCM2835_VCHIQ_MMAL) += vchiq-mmal/
-+obj-$(CONFIG_BCM_VC_SM_CMA) += vc-sm-cma/
-
- ccflags-y += -Idrivers/staging/vc04_services -D__VCCOREVER__=0x04000000
-
---- /dev/null
-+++ b/drivers/staging/vc04_services/vc-sm-cma/Kconfig
-@@ -0,0 +1,10 @@
-+config BCM_VC_SM_CMA
-+ tristate "VideoCore Shared Memory (CMA) driver"
-+ depends on BCM2835_VCHIQ
-+ select RBTREE
-+ select DMA_SHARED_BUFFER
-+ help
-+ Say Y here to enable the shared memory interface that
-+ supports sharing dmabufs with VideoCore.
-+ This operates over the VCHIQ interface to a service
-+ running on VideoCore.
---- /dev/null
-+++ b/drivers/staging/vc04_services/vc-sm-cma/Makefile
-@@ -0,0 +1,8 @@
-+ccflags-y += -Idrivers/staging/vc04_services -Idrivers/staging/vc04_services/interface/vchi -Idrivers/staging/vc04_services/interface/vchiq_arm
-+# -I"drivers/staging/android/ion/" -I"$(srctree)/fs/"
-+ccflags-y += -D__VCCOREVER__=0
-+
-+vc-sm-cma-$(CONFIG_BCM_VC_SM_CMA) := \
-+ vc_sm.o vc_sm_cma_vchi.o
-+
-+obj-$(CONFIG_BCM_VC_SM_CMA) += vc-sm-cma.o
---- /dev/null
-+++ b/drivers/staging/vc04_services/vc-sm-cma/TODO
-@@ -0,0 +1,2 @@
-+1) Convert to a platform driver.
-+
---- /dev/null
-+++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
-@@ -0,0 +1,838 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/*
-+ * VideoCore Shared Memory driver using CMA.
-+ *
-+ * Copyright: 2018, Raspberry Pi (Trading) Ltd
-+ * Dave Stevenson <dave.stevenson@raspberrypi.org>
-+ *
-+ * Based on vmcs_sm driver from Broadcom Corporation for some API,
-+ * and taking some code for CMA/dmabuf handling from the Android Ion
-+ * driver (Google/Linaro).
-+ *
-+ * This is cut down version to only support import of dma_bufs from
-+ * other kernel drivers. A more complete implementation of the old
-+ * vmcs_sm functionality can follow later.
-+ *
-+ */
-+
-+/* ---- Include Files ----------------------------------------------------- */
-+#include <linux/cdev.h>
-+#include <linux/device.h>
-+#include <linux/debugfs.h>
-+#include <linux/dma-mapping.h>
-+#include <linux/dma-buf.h>
-+#include <linux/errno.h>
-+#include <linux/fs.h>
-+#include <linux/kernel.h>
-+#include <linux/list.h>
-+#include <linux/miscdevice.h>
-+#include <linux/module.h>
-+#include <linux/mm.h>
-+#include <linux/of_device.h>
-+#include <linux/platform_device.h>
-+#include <linux/proc_fs.h>
-+#include <linux/slab.h>
-+#include <linux/seq_file.h>
-+#include <linux/syscalls.h>
-+#include <linux/types.h>
-+
-+#include "vchiq_connected.h"
-+#include "vc_sm_cma_vchi.h"
-+
-+#include "vc_sm.h"
-+#include "vc_sm_knl.h"
-+
-+/* ---- Private Constants and Types --------------------------------------- */
-+
-+#define DEVICE_NAME "vcsm-cma"
-+#define DEVICE_MINOR 0
-+
-+#define VC_SM_RESOURCE_NAME_DEFAULT "sm-host-resource"
-+
-+#define VC_SM_DIR_ROOT_NAME "vcsm-cma"
-+#define VC_SM_STATE "state"
-+
-+/* Private file data associated with each opened device. */
-+struct vc_sm_privdata_t {
-+ pid_t pid; /* PID of creator. */
-+
-+ int restart_sys; /* Tracks restart on interrupt. */
-+ enum vc_sm_msg_type int_action; /* Interrupted action. */
-+ u32 int_trans_id; /* Interrupted transaction. */
-+};
-+
-+typedef int (*VC_SM_SHOW) (struct seq_file *s, void *v);
-+struct sm_pde_t {
-+ VC_SM_SHOW show; /* Debug fs function hookup. */
-+ struct dentry *dir_entry; /* Debug fs directory entry. */
-+ void *priv_data; /* Private data */
-+};
-+
-+/* Global state information. */
-+struct sm_state_t {
-+ struct platform_device *pdev;
-+
-+ struct miscdevice dev;
-+ struct sm_instance *sm_handle; /* Handle for videocore service. */
-+
-+ struct mutex map_lock; /* Global map lock. */
-+ struct list_head buffer_list; /* List of buffer. */
-+
-+ struct vc_sm_privdata_t *data_knl; /* Kernel internal data tracking. */
-+ struct dentry *dir_root; /* Debug fs entries root. */
-+ struct sm_pde_t dir_state; /* Debug fs entries state sub-tree. */
-+
-+ bool require_released_callback; /* VPU will send a released msg when it
-+ * has finished with a resource.
-+ */
-+ u32 int_trans_id; /* Interrupted transaction. */
-+};
-+
-+/* ---- Private Variables ----------------------------------------------- */
-+
-+static struct sm_state_t *sm_state;
-+static int sm_inited;
-+
-+/* ---- Private Function Prototypes -------------------------------------- */
-+
-+/* ---- Private Functions ------------------------------------------------ */
-+
-+static int vc_sm_cma_seq_file_show(struct seq_file *s, void *v)
-+{
-+ struct sm_pde_t *sm_pde;
-+
-+ sm_pde = (struct sm_pde_t *)(s->private);
-+
-+ if (sm_pde && sm_pde->show)
-+ sm_pde->show(s, v);
-+
-+ return 0;
-+}
-+
-+static int vc_sm_cma_single_open(struct inode *inode, struct file *file)
-+{
-+ return single_open(file, vc_sm_cma_seq_file_show, inode->i_private);
-+}
-+
-+static const struct file_operations vc_sm_cma_debug_fs_fops = {
-+ .open = vc_sm_cma_single_open,
-+ .read = seq_read,
-+ .llseek = seq_lseek,
-+ .release = single_release,
-+};
-+
-+static int vc_sm_cma_global_state_show(struct seq_file *s, void *v)
-+{
-+ struct vc_sm_buffer *resource = NULL;
-+ int resource_count = 0;
-+
-+ if (!sm_state)
-+ return 0;
-+
-+ seq_printf(s, "\nVC-ServiceHandle 0x%x\n",
-+ (unsigned int)sm_state->sm_handle);
-+
-+ /* Log all applicable mapping(s). */
-+
-+ mutex_lock(&sm_state->map_lock);
-+ seq_puts(s, "\nResources\n");
-+ if (!list_empty(&sm_state->buffer_list)) {
-+ list_for_each_entry(resource, &sm_state->buffer_list,
-+ global_buffer_list) {
-+ resource_count++;
-+
-+ seq_printf(s, "\nResource %p\n",
-+ resource);
-+ seq_printf(s, " NAME %s\n",
-+ resource->name);
-+ seq_printf(s, " SIZE %d\n",
-+ resource->size);
-+ seq_printf(s, " DMABUF %p\n",
-+ resource->dma_buf);
-+ seq_printf(s, " ATTACH %p\n",
-+ resource->attach);
-+ seq_printf(s, " SG_TABLE %p\n",
-+ resource->sg_table);
-+ seq_printf(s, " SGT %p\n",
-+ resource->sgt);
-+ seq_printf(s, " DMA_ADDR %pad\n",
-+ &resource->dma_addr);
-+ seq_printf(s, " VC_HANDLE %08x\n",
-+ resource->vc_handle);
-+ seq_printf(s, " VC_MAPPING %d\n",
-+ resource->vpu_state);
-+ }
-+ }
-+ seq_printf(s, "\n\nTotal resource count: %d\n\n", resource_count);
-+
-+ mutex_unlock(&sm_state->map_lock);
-+
-+ return 0;
-+}
-+
-+/*
-+ * Adds a buffer to the private data list which tracks all the allocated
-+ * data.
-+ */
-+static void vc_sm_add_resource(struct vc_sm_privdata_t *privdata,
-+ struct vc_sm_buffer *buffer)
-+{
-+ mutex_lock(&sm_state->map_lock);
-+ list_add(&buffer->global_buffer_list, &sm_state->buffer_list);
-+ mutex_unlock(&sm_state->map_lock);
-+
-+ pr_debug("[%s]: added buffer %p (name %s, size %d)\n",
-+ __func__, buffer, buffer->name, buffer->size);
-+}
-+
-+/*
-+ * Release an allocation.
-+ * All refcounting is done via the dma buf object.
-+ */
-+static void vc_sm_release_resource(struct vc_sm_buffer *buffer, int force)
-+{
-+ mutex_lock(&sm_state->map_lock);
-+ mutex_lock(&buffer->lock);
-+
-+ pr_debug("[%s]: buffer %p (name %s, size %d)\n",
-+ __func__, buffer, buffer->name, buffer->size);
-+
-+ if (buffer->vc_handle && buffer->vpu_state == VPU_MAPPED) {
-+ struct vc_sm_free_t free = { buffer->vc_handle, 0 };
-+ int status = vc_sm_cma_vchi_free(sm_state->sm_handle, &free,
-+ &sm_state->int_trans_id);
-+ if (status != 0 && status != -EINTR) {
-+ pr_err("[%s]: failed to free memory on videocore (status: %u, trans_id: %u)\n",
-+ __func__, status, sm_state->int_trans_id);
-+ }
-+
-+ if (sm_state->require_released_callback) {
-+ /* Need to wait for the VPU to confirm the free */
-+
-+ /* Retain a reference on this until the VPU has
-+ * released it
-+ */
-+ buffer->vpu_state = VPU_UNMAPPING;
-+ goto defer;
-+ }
-+ buffer->vpu_state = VPU_NOT_MAPPED;
-+ buffer->vc_handle = 0;
-+ }
-+ if (buffer->vc_handle) {
-+ /* We've sent the unmap request but not had the response. */
-+ pr_err("[%s]: Waiting for VPU unmap response on %p\n",
-+ __func__, buffer);
-+ goto defer;
-+ }
-+ if (buffer->in_use) {
-+ /* Don't release dmabuf here - we await the release */
-+ pr_err("[%s]: buffer %p is still in use\n",
-+ __func__, buffer);
-+ goto defer;
-+ }
-+
-+ /* Handle cleaning up imported dmabufs */
-+ if (buffer->sgt) {
-+ dma_buf_unmap_attachment(buffer->attach, buffer->sgt,
-+ DMA_BIDIRECTIONAL);
-+ buffer->sgt = NULL;
-+ }
-+ if (buffer->attach) {
-+ dma_buf_detach(buffer->dma_buf, buffer->attach);
-+ buffer->attach = NULL;
-+ }
-+
-+ /* Release the dma_buf (whether ours or imported) */
-+ if (buffer->import_dma_buf) {
-+ dma_buf_put(buffer->import_dma_buf);
-+ buffer->import_dma_buf = NULL;
-+ buffer->dma_buf = NULL;
-+ } else if (buffer->dma_buf) {
-+ dma_buf_put(buffer->dma_buf);
-+ buffer->dma_buf = NULL;
-+ }
-+
-+ if (buffer->sg_table && !buffer->import_dma_buf) {
-+ /* Our own allocation that we need to dma_unmap_sg */
-+ dma_unmap_sg(&sm_state->pdev->dev, buffer->sg_table->sgl,
-+ buffer->sg_table->nents, DMA_BIDIRECTIONAL);
-+ }
-+
-+ /* Free the local resource. Start by removing it from the list */
-+ buffer->private = NULL;
-+ list_del(&buffer->global_buffer_list);
-+
-+ mutex_unlock(&buffer->lock);
-+ mutex_unlock(&sm_state->map_lock);
-+
-+ mutex_destroy(&buffer->lock);
-+
-+ kfree(buffer);
-+ return;
-+
-+defer:
-+ mutex_unlock(&buffer->lock);
-+ mutex_unlock(&sm_state->map_lock);
-+}
-+
-+/* Create support for private data tracking. */
-+static struct vc_sm_privdata_t *vc_sm_cma_create_priv_data(pid_t id)
-+{
-+ char alloc_name[32];
-+ struct vc_sm_privdata_t *file_data = NULL;
-+
-+ /* Allocate private structure. */
-+ file_data = kzalloc(sizeof(*file_data), GFP_KERNEL);
-+
-+ if (!file_data)
-+ return NULL;
-+
-+ snprintf(alloc_name, sizeof(alloc_name), "%d", id);
-+
-+ file_data->pid = id;
-+
-+ return file_data;
-+}
-+
-+/* Dma_buf operations for chaining through to an imported dma_buf */
-+static
-+int vc_sm_import_dma_buf_attach(struct dma_buf *dmabuf,
-+ struct dma_buf_attachment *attachment)
-+{
-+ struct vc_sm_buffer *res = dmabuf->priv;
-+
-+ if (!res->import_dma_buf)
-+ return -EINVAL;
-+ return res->import_dma_buf->ops->attach(res->import_dma_buf,
-+ attachment);
-+}
-+
-+static
-+void vc_sm_import_dma_buf_detatch(struct dma_buf *dmabuf,
-+ struct dma_buf_attachment *attachment)
-+{
-+ struct vc_sm_buffer *res = dmabuf->priv;
-+
-+ if (!res->import_dma_buf)
-+ return;
-+ res->import_dma_buf->ops->detach(res->import_dma_buf, attachment);
-+}
-+
-+static
-+struct sg_table *vc_sm_import_map_dma_buf(struct dma_buf_attachment *attachment,
-+ enum dma_data_direction direction)
-+{
-+ struct vc_sm_buffer *res = attachment->dmabuf->priv;
-+
-+ if (!res->import_dma_buf)
-+ return NULL;
-+ return res->import_dma_buf->ops->map_dma_buf(attachment, direction);
-+}
-+
-+static
-+void vc_sm_import_unmap_dma_buf(struct dma_buf_attachment *attachment,
-+ struct sg_table *table,
-+ enum dma_data_direction direction)
-+{
-+ struct vc_sm_buffer *res = attachment->dmabuf->priv;
-+
-+ if (!res->import_dma_buf)
-+ return;
-+ res->import_dma_buf->ops->unmap_dma_buf(attachment, table, direction);
-+}
-+
-+static
-+int vc_sm_import_dmabuf_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma)
-+{
-+ struct vc_sm_buffer *res = dmabuf->priv;
-+
-+ pr_debug("%s: mmap dma_buf %p, res %p, imported db %p\n", __func__,
-+ dmabuf, res, res->import_dma_buf);
-+ if (!res->import_dma_buf) {
-+ pr_err("%s: mmap dma_buf %p- not an imported buffer\n",
-+ __func__, dmabuf);
-+ return -EINVAL;
-+ }
-+ return res->import_dma_buf->ops->mmap(res->import_dma_buf, vma);
-+}
-+
-+static
-+void vc_sm_import_dma_buf_release(struct dma_buf *dmabuf)
-+{
-+ struct vc_sm_buffer *res = dmabuf->priv;
-+
-+ pr_debug("%s: Relasing dma_buf %p\n", __func__, dmabuf);
-+ if (!res->import_dma_buf)
-+ return;
-+
-+ res->in_use = 0;
-+
-+ vc_sm_release_resource(res, 0);
-+}
-+
-+static
-+void *vc_sm_import_dma_buf_kmap(struct dma_buf *dmabuf,
-+ unsigned long offset)
-+{
-+ struct vc_sm_buffer *res = dmabuf->priv;
-+
-+ if (!res->import_dma_buf)
-+ return NULL;
-+ return res->import_dma_buf->ops->map(res->import_dma_buf,
-+ offset);
-+}
-+
-+static
-+void vc_sm_import_dma_buf_kunmap(struct dma_buf *dmabuf,
-+ unsigned long offset, void *ptr)
-+{
-+ struct vc_sm_buffer *res = dmabuf->priv;
-+
-+ if (!res->import_dma_buf)
-+ return;
-+ res->import_dma_buf->ops->unmap(res->import_dma_buf,
-+ offset, ptr);
-+}
-+
-+static
-+int vc_sm_import_dma_buf_begin_cpu_access(struct dma_buf *dmabuf,
-+ enum dma_data_direction direction)
-+{
-+ struct vc_sm_buffer *res = dmabuf->priv;
-+
-+ if (!res->import_dma_buf)
-+ return -EINVAL;
-+ return res->import_dma_buf->ops->begin_cpu_access(res->import_dma_buf,
-+ direction);
-+}
-+
-+static
-+int vc_sm_import_dma_buf_end_cpu_access(struct dma_buf *dmabuf,
-+ enum dma_data_direction direction)
-+{
-+ struct vc_sm_buffer *res = dmabuf->priv;
-+
-+ if (!res->import_dma_buf)
-+ return -EINVAL;
-+ return res->import_dma_buf->ops->end_cpu_access(res->import_dma_buf,
-+ direction);
-+}
-+
-+static const struct dma_buf_ops dma_buf_import_ops = {
-+ .map_dma_buf = vc_sm_import_map_dma_buf,
-+ .unmap_dma_buf = vc_sm_import_unmap_dma_buf,
-+ .mmap = vc_sm_import_dmabuf_mmap,
-+ .release = vc_sm_import_dma_buf_release,
-+ .attach = vc_sm_import_dma_buf_attach,
-+ .detach = vc_sm_import_dma_buf_detatch,
-+ .begin_cpu_access = vc_sm_import_dma_buf_begin_cpu_access,
-+ .end_cpu_access = vc_sm_import_dma_buf_end_cpu_access,
-+ .map = vc_sm_import_dma_buf_kmap,
-+ .unmap = vc_sm_import_dma_buf_kunmap,
-+};
-+
-+/* Import a dma_buf to be shared with VC. */
-+int
-+vc_sm_cma_import_dmabuf_internal(struct vc_sm_privdata_t *private,
-+ struct dma_buf *dma_buf,
-+ struct dma_buf **imported_buf)
-+{
-+ DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
-+ struct vc_sm_buffer *buffer = NULL;
-+ struct vc_sm_import import = { };
-+ struct vc_sm_import_result result = { };
-+ struct dma_buf_attachment *attach = NULL;
-+ struct sg_table *sgt = NULL;
-+ int ret = 0;
-+ int status;
-+
-+ /* Setup our allocation parameters */
-+ pr_debug("%s: importing dma_buf %p\n", __func__, dma_buf);
-+
-+ get_dma_buf(dma_buf);
-+ dma_buf = dma_buf;
-+
-+ attach = dma_buf_attach(dma_buf, &sm_state->pdev->dev);
-+ if (IS_ERR(attach)) {
-+ ret = PTR_ERR(attach);
-+ goto error;
-+ }
-+
-+ sgt = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL);
-+ if (IS_ERR(sgt)) {
-+ ret = PTR_ERR(sgt);
-+ goto error;
-+ }
-+
-+ /* Verify that the address block is contiguous */
-+ if (sgt->nents != 1) {
-+ ret = -ENOMEM;
-+ goto error;
-+ }
-+
-+ /* Allocate local buffer to track this allocation. */
-+ buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
-+ if (!buffer) {
-+ ret = -ENOMEM;
-+ goto error;
-+ }
-+
-+ import.type = VC_SM_ALLOC_NON_CACHED;
-+ import.addr = (uint32_t)sg_dma_address(sgt->sgl);
-+ if ((import.addr & 0xC0000000) != 0xC0000000) {
-+ pr_err("%s: Expecting an uncached alias for dma_addr %08x\n",
-+ __func__, import.addr);
-+ import.addr |= 0xC0000000;
-+ }
-+ import.size = sg_dma_len(sgt->sgl);
-+ import.allocator = current->tgid;
-+ import.kernel_id = (uint32_t)buffer; //FIXME: 64 bit support needed.
-+
-+ memcpy(import.name, VC_SM_RESOURCE_NAME_DEFAULT,
-+ sizeof(VC_SM_RESOURCE_NAME_DEFAULT));
-+
-+ pr_debug("[%s]: attempt to import \"%s\" data - type %u, addr %p, size %u\n",
-+ __func__, import.name, import.type, (void *)import.addr,
-+ import.size);
-+
-+ /* Allocate the videocore buffer. */
-+ status = vc_sm_cma_vchi_import(sm_state->sm_handle, &import, &result,
-+ &sm_state->int_trans_id);
-+ if (status == -EINTR) {
-+ pr_debug("[%s]: requesting import memory action restart (trans_id: %u)\n",
-+ __func__, sm_state->int_trans_id);
-+ ret = -ERESTARTSYS;
-+ private->restart_sys = -EINTR;
-+ private->int_action = VC_SM_MSG_TYPE_IMPORT;
-+ goto error;
-+ } else if (status || !result.res_handle) {
-+ pr_debug("[%s]: failed to import memory on videocore (status: %u, trans_id: %u)\n",
-+ __func__, status, sm_state->int_trans_id);
-+ ret = -ENOMEM;
-+ goto error;
-+ }
-+
-+ mutex_init(&buffer->lock);
-+ INIT_LIST_HEAD(&buffer->attachments);
-+ memcpy(buffer->name, import.name,
-+ min(sizeof(buffer->name), sizeof(import.name) - 1));
-+
-+ /* Keep track of the buffer we created. */
-+ buffer->private = private;
-+ buffer->vc_handle = result.res_handle;
-+ buffer->size = import.size;
-+ buffer->vpu_state = VPU_MAPPED;
-+
-+ buffer->import_dma_buf = dma_buf;
-+
-+ buffer->attach = attach;
-+ buffer->sgt = sgt;
-+ buffer->dma_addr = sg_dma_address(sgt->sgl);
-+ buffer->in_use = 1;
-+
-+ /*
-+ * We're done - we need to export a new dmabuf chaining through most
-+ * functions, but enabling us to release our own internal references
-+ * here.
-+ */
-+ exp_info.ops = &dma_buf_import_ops;
-+ exp_info.size = import.size;
-+ exp_info.flags = O_RDWR;
-+ exp_info.priv = buffer;
-+
-+ buffer->dma_buf = dma_buf_export(&exp_info);
-+ if (IS_ERR(buffer->dma_buf)) {
-+ ret = PTR_ERR(buffer->dma_buf);
-+ goto error;
-+ }
-+
-+ vc_sm_add_resource(private, buffer);
-+
-+ *imported_buf = buffer->dma_buf;
-+
-+ return 0;
-+
-+error:
-+ if (result.res_handle) {
-+ struct vc_sm_free_t free = { result.res_handle, 0 };
-+
-+ vc_sm_cma_vchi_free(sm_state->sm_handle, &free,
-+ &sm_state->int_trans_id);
-+ }
-+ kfree(buffer);
-+ if (sgt)
-+ dma_buf_unmap_attachment(attach, sgt, DMA_BIDIRECTIONAL);
-+ if (attach)
-+ dma_buf_detach(dma_buf, attach);
-+ dma_buf_put(dma_buf);
-+ return ret;
-+}
-+
-+/* FIXME: Pass a function pointer to this into vc_vchi_sm.c */
-+void
-+vc_sm_vpu_event(struct sm_instance *instance, struct vc_sm_result_t *reply,
-+ int reply_len)
-+{
-+ switch (reply->trans_id & ~0x80000000) {
-+ case VC_SM_MSG_TYPE_CLIENT_VERSION:
-+ {
-+ /* Acknowledge that the firmware supports the version command */
-+ pr_debug("%s: firmware acked version msg. Require release cb\n",
-+ __func__);
-+ sm_state->require_released_callback = true;
-+ }
-+ break;
-+ case VC_SM_MSG_TYPE_RELEASED:
-+ {
-+ struct vc_sm_released *release = (struct vc_sm_released *)reply;
-+ struct vc_sm_buffer *buffer =
-+ (struct vc_sm_buffer *)release->kernel_id;
-+
-+ /*
-+ * FIXME: Need to check buffer is still valid and allocated
-+ * before continuing
-+ */
-+ pr_debug("%s: Released addr %08x, size %u, id %08x, mem_handle %08x\n",
-+ __func__, release->addr, release->size,
-+ release->kernel_id, release->vc_handle);
-+ mutex_lock(&buffer->lock);
-+ buffer->vc_handle = 0;
-+ buffer->vpu_state = VPU_NOT_MAPPED;
-+ mutex_unlock(&buffer->lock);
-+
-+ vc_sm_release_resource(buffer, 0);
-+ }
-+ break;
-+ default:
-+ pr_err("%s: Unknown vpu cmd %x\n", __func__, reply->trans_id);
-+ break;
-+ }
-+}
-+
-+/* Videocore connected. */
-+static void vc_sm_connected_init(void)
-+{
-+ int ret;
-+ VCHI_INSTANCE_T vchi_instance;
-+ struct vc_sm_version version;
-+ struct vc_sm_result_t version_result;
-+
-+ pr_info("[%s]: start\n", __func__);
-+
-+ /*
-+ * Initialize and create a VCHI connection for the shared memory service
-+ * running on videocore.
-+ */
-+ ret = vchi_initialise(&vchi_instance);
-+ if (ret) {
-+ pr_err("[%s]: failed to initialise VCHI instance (ret=%d)\n",
-+ __func__, ret);
-+
-+ ret = -EIO;
-+ goto err_free_mem;
-+ }
-+
-+ ret = vchi_connect(vchi_instance);
-+ if (ret) {
-+ pr_err("[%s]: failed to connect VCHI instance (ret=%d)\n",
-+ __func__, ret);
-+
-+ ret = -EIO;
-+ goto err_free_mem;
-+ }
-+
-+ /* Initialize an instance of the shared memory service. */
-+ sm_state->sm_handle = vc_sm_cma_vchi_init(vchi_instance, 1,
-+ vc_sm_vpu_event);
-+ if (!sm_state->sm_handle) {
-+ pr_err("[%s]: failed to initialize shared memory service\n",
-+ __func__);
-+
-+ ret = -EPERM;
-+ goto err_free_mem;
-+ }
-+
-+ /* Create a debug fs directory entry (root). */
-+ sm_state->dir_root = debugfs_create_dir(VC_SM_DIR_ROOT_NAME, NULL);
-+ if (!sm_state->dir_root) {
-+ pr_err("[%s]: failed to create \'%s\' directory entry\n",
-+ __func__, VC_SM_DIR_ROOT_NAME);
-+
-+ ret = -EPERM;
-+ goto err_stop_sm_service;
-+ }
-+
-+ sm_state->dir_state.show = &vc_sm_cma_global_state_show;
-+ sm_state->dir_state.dir_entry =
-+ debugfs_create_file(VC_SM_STATE, 0444, sm_state->dir_root,
-+ &sm_state->dir_state,
-+ &vc_sm_cma_debug_fs_fops);
-+
-+ INIT_LIST_HEAD(&sm_state->buffer_list);
-+
-+ sm_state->data_knl = vc_sm_cma_create_priv_data(0);
-+ if (!sm_state->data_knl) {
-+ pr_err("[%s]: failed to create kernel private data tracker\n",
-+ __func__);
-+ goto err_remove_shared_memory;
-+ }
-+
-+ version.version = 1;
-+ ret = vc_sm_cma_vchi_client_version(sm_state->sm_handle, &version,
-+ &version_result,
-+ &sm_state->int_trans_id);
-+ if (ret) {
-+ pr_err("[%s]: Failed to send version request %d\n", __func__,
-+ ret);
-+ }
-+
-+ /* Done! */
-+ sm_inited = 1;
-+ pr_info("[%s]: installed successfully\n", __func__);
-+ return;
-+
-+err_remove_shared_memory:
-+ debugfs_remove_recursive(sm_state->dir_root);
-+err_stop_sm_service:
-+ vc_sm_cma_vchi_stop(&sm_state->sm_handle);
-+err_free_mem:
-+ kfree(sm_state);
-+ pr_info("[%s]: failed, ret %d\n", __func__, ret);
-+}
-+
-+/* Driver loading. */
-+static int bcm2835_vc_sm_cma_probe(struct platform_device *pdev)
-+{
-+ struct device *dev = &pdev->dev;
-+ int err;
-+
-+ pr_info("%s: Videocore shared memory driver\n", __func__);
-+
-+ sm_state = kzalloc(sizeof(*sm_state), GFP_KERNEL);
-+ if (!sm_state)
-+ return -ENOMEM;
-+ sm_state->pdev = pdev;
-+ mutex_init(&sm_state->map_lock);
-+
-+ dev->coherent_dma_mask = DMA_BIT_MASK(32);
-+ dev->dma_mask = &dev->coherent_dma_mask;
-+ err = of_dma_configure(dev, NULL, true);
-+ if (err) {
-+ dev_err(dev, "Unable to setup DMA: %d\n", err);
-+ return err;
-+ }
-+
-+ vchiq_add_connected_callback(vc_sm_connected_init);
-+ return 0;
-+}
-+
-+/* Driver unloading. */
-+static int bcm2835_vc_sm_cma_remove(struct platform_device *pdev)
-+{
-+ pr_debug("[%s]: start\n", __func__);
-+ if (sm_inited) {
-+ /* Remove shared memory device. */
-+ misc_deregister(&sm_state->dev);
-+
-+ /* Remove all proc entries. */
-+ //debugfs_remove_recursive(sm_state->dir_root);
-+
-+ /* Stop the videocore shared memory service. */
-+ vc_sm_cma_vchi_stop(&sm_state->sm_handle);
-+
-+ /* Free the memory for the state structure. */
-+ mutex_destroy(&sm_state->map_lock);
-+ kfree(sm_state);
-+ }
-+
-+ pr_debug("[%s]: end\n", __func__);
-+ return 0;
-+}
-+
-+/* Get an internal resource handle mapped from the external one. */
-+int vc_sm_cma_int_handle(int handle)
-+{
-+ struct dma_buf *dma_buf = (struct dma_buf *)handle;
-+ struct vc_sm_buffer *res;
-+
-+ /* Validate we can work with this device. */
-+ if (!sm_state || !handle) {
-+ pr_err("[%s]: invalid input\n", __func__);
-+ return 0;
-+ }
-+
-+ res = (struct vc_sm_buffer *)dma_buf->priv;
-+ return res->vc_handle;
-+}
-+EXPORT_SYMBOL_GPL(vc_sm_cma_int_handle);
-+
-+/* Free a previously allocated shared memory handle and block. */
-+int vc_sm_cma_free(int handle)
-+{
-+ struct dma_buf *dma_buf = (struct dma_buf *)handle;
-+
-+ /* Validate we can work with this device. */
-+ if (!sm_state || !handle) {
-+ pr_err("[%s]: invalid input\n", __func__);
-+ return -EPERM;
-+ }
-+
-+ pr_debug("%s: handle %08x/dmabuf %p\n", __func__, handle, dma_buf);
-+
-+ dma_buf_put(dma_buf);
-+
-+ return 0;
-+}
-+EXPORT_SYMBOL_GPL(vc_sm_cma_free);
-+
-+/* Import a dmabuf to be shared with VC. */
-+int vc_sm_cma_import_dmabuf(struct dma_buf *src_dmabuf, int *handle)
-+{
-+ struct dma_buf *new_dma_buf;
-+ struct vc_sm_buffer *res;
-+ int ret;
-+
-+ /* Validate we can work with this device. */
-+ if (!sm_state || !src_dmabuf || !handle) {
-+ pr_err("[%s]: invalid input\n", __func__);
-+ return -EPERM;
-+ }
-+
-+ ret = vc_sm_cma_import_dmabuf_internal(sm_state->data_knl, src_dmabuf,
-+ &new_dma_buf);
-+
-+ if (!ret) {
-+ pr_debug("%s: imported to ptr %p\n", __func__, new_dma_buf);
-+ res = (struct vc_sm_buffer *)new_dma_buf->priv;
-+
-+ /* Assign valid handle at this time.*/
-+ *handle = (int)new_dma_buf;
-+ } else {
-+ /*
-+ * succeeded in importing the dma_buf, but then
-+ * failed to look it up again. How?
-+ * Release the fd again.
-+ */
-+ pr_err("%s: imported vc_sm_cma_get_buffer failed %d\n",
-+ __func__, ret);
-+ }
-+
-+ return ret;
-+}
-+EXPORT_SYMBOL_GPL(vc_sm_cma_import_dmabuf);
-+
-+static struct platform_driver bcm2835_vcsm_cma_driver = {
-+ .probe = bcm2835_vc_sm_cma_probe,
-+ .remove = bcm2835_vc_sm_cma_remove,
-+ .driver = {
-+ .name = DEVICE_NAME,
-+ .owner = THIS_MODULE,
-+ },
-+};
-+
-+module_platform_driver(bcm2835_vcsm_cma_driver);
-+
-+MODULE_AUTHOR("Dave Stevenson");
-+MODULE_DESCRIPTION("VideoCore CMA Shared Memory Driver");
-+MODULE_LICENSE("GPL v2");
-+MODULE_ALIAS("platform:vcsm-cma");
---- /dev/null
-+++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm.h
-@@ -0,0 +1,59 @@
-+/* SPDX-License-Identifier: GPL-2.0 */
-+
-+/*
-+ * VideoCore Shared Memory driver using CMA.
-+ *
-+ * Copyright: 2018, Raspberry Pi (Trading) Ltd
-+ *
-+ */
-+
-+#ifndef VC_SM_H
-+#define VC_SM_H
-+
-+#include <linux/device.h>
-+#include <linux/dma-direction.h>
-+#include <linux/kref.h>
-+#include <linux/mm_types.h>
-+#include <linux/mutex.h>
-+#include <linux/rbtree.h>
-+#include <linux/sched.h>
-+#include <linux/shrinker.h>
-+#include <linux/types.h>
-+#include <linux/miscdevice.h>
-+
-+#define VC_SM_MAX_NAME_LEN 32
-+
-+enum vc_sm_vpu_mapping_state {
-+ VPU_NOT_MAPPED,
-+ VPU_MAPPED,
-+ VPU_UNMAPPING
-+};
-+
-+struct vc_sm_buffer {
-+ struct list_head global_buffer_list; /* Global list of buffers. */
-+
-+ size_t size;
-+
-+ /* Lock over all the following state for this buffer */
-+ struct mutex lock;
-+ struct sg_table *sg_table;
-+ struct list_head attachments;
-+
-+ char name[VC_SM_MAX_NAME_LEN];
-+
-+ int in_use:1; /* Kernel is still using this resource */
-+
-+ enum vc_sm_vpu_mapping_state vpu_state;
-+ u32 vc_handle; /* VideoCore handle for this buffer */
-+
-+ /* DMABUF related fields */
-+ struct dma_buf *import_dma_buf;
-+ struct dma_buf *dma_buf;
-+ struct dma_buf_attachment *attach;
-+ struct sg_table *sgt;
-+ dma_addr_t dma_addr;
-+
-+ struct vc_sm_privdata_t *private;
-+};
-+
-+#endif
---- /dev/null
-+++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma_vchi.c
-@@ -0,0 +1,498 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/*
-+ * VideoCore Shared Memory CMA allocator
-+ *
-+ * Copyright: 2018, Raspberry Pi (Trading) Ltd
-+ * Copyright 2011-2012 Broadcom Corporation. All rights reserved.
-+ *
-+ * Based on vmcs_sm driver from Broadcom Corporation.
-+ *
-+ */
-+
-+/* ---- Include Files ----------------------------------------------------- */
-+#include <linux/completion.h>
-+#include <linux/kernel.h>
-+#include <linux/kthread.h>
-+#include <linux/list.h>
-+#include <linux/mutex.h>
-+#include <linux/semaphore.h>
-+#include <linux/slab.h>
-+#include <linux/types.h>
-+
-+#include "vc_sm_cma_vchi.h"
-+
-+#define VC_SM_VER 1
-+#define VC_SM_MIN_VER 0
-+
-+/* ---- Private Constants and Types -------------------------------------- */
-+
-+/* Command blocks come from a pool */
-+#define SM_MAX_NUM_CMD_RSP_BLKS 32
-+
-+struct sm_cmd_rsp_blk {
-+ struct list_head head; /* To create lists */
-+ /* To be signaled when the response is there */
-+ struct completion cmplt;
-+
-+ u16 id;
-+ u16 length;
-+
-+ u8 msg[VC_SM_MAX_MSG_LEN];
-+
-+ uint32_t wait:1;
-+ uint32_t sent:1;
-+ uint32_t alloc:1;
-+
-+};
-+
-+struct sm_instance {
-+ u32 num_connections;
-+ VCHI_SERVICE_HANDLE_T vchi_handle[VCHI_MAX_NUM_CONNECTIONS];
-+ struct task_struct *io_thread;
-+ struct completion io_cmplt;
-+
-+ vpu_event_cb vpu_event;
-+
-+ /* Mutex over the following lists */
-+ struct mutex lock;
-+ u32 trans_id;
-+ struct list_head cmd_list;
-+ struct list_head rsp_list;
-+ struct list_head dead_list;
-+
-+ struct sm_cmd_rsp_blk free_blk[SM_MAX_NUM_CMD_RSP_BLKS];
-+
-+ /* Mutex over the free_list */
-+ struct mutex free_lock;
-+ struct list_head free_list;
-+
-+ struct semaphore free_sema;
-+
-+};
-+
-+/* ---- Private Variables ------------------------------------------------ */
-+
-+/* ---- Private Function Prototypes -------------------------------------- */
-+
-+/* ---- Private Functions ------------------------------------------------ */
-+static int
-+bcm2835_vchi_msg_queue(VCHI_SERVICE_HANDLE_T handle,
-+ void *data,
-+ unsigned int size)
-+{
-+ return vchi_queue_kernel_message(handle,
-+ data,
-+ size);
-+}
-+
-+static struct
-+sm_cmd_rsp_blk *vc_vchi_cmd_create(struct sm_instance *instance,
-+ enum vc_sm_msg_type id, void *msg,
-+ u32 size, int wait)
-+{
-+ struct sm_cmd_rsp_blk *blk;
-+ struct vc_sm_msg_hdr_t *hdr;
-+
-+ if (down_interruptible(&instance->free_sema)) {
-+ blk = kmalloc(sizeof(*blk), GFP_KERNEL);
-+ if (!blk)
-+ return NULL;
-+
-+ blk->alloc = 1;
-+ init_completion(&blk->cmplt);
-+ } else {
-+ mutex_lock(&instance->free_lock);
-+ blk =
-+ list_first_entry(&instance->free_list,
-+ struct sm_cmd_rsp_blk, head);
-+ list_del(&blk->head);
-+ mutex_unlock(&instance->free_lock);
-+ }
-+
-+ blk->sent = 0;
-+ blk->wait = wait;
-+ blk->length = sizeof(*hdr) + size;
-+
-+ hdr = (struct vc_sm_msg_hdr_t *)blk->msg;
-+ hdr->type = id;
-+ mutex_lock(&instance->lock);
-+ instance->trans_id++;
-+ /*
-+ * Retain the top bit for identifying asynchronous events, or VPU cmds.
-+ */
-+ instance->trans_id &= ~0x80000000;
-+ hdr->trans_id = instance->trans_id;
-+ blk->id = instance->trans_id;
-+ mutex_unlock(&instance->lock);
-+
-+ if (size)
-+ memcpy(hdr->body, msg, size);
-+
-+ return blk;
-+}
-+
-+static void
-+vc_vchi_cmd_delete(struct sm_instance *instance, struct sm_cmd_rsp_blk *blk)
-+{
-+ if (blk->alloc) {
-+ kfree(blk);
-+ return;
-+ }
-+
-+ mutex_lock(&instance->free_lock);
-+ list_add(&blk->head, &instance->free_list);
-+ mutex_unlock(&instance->free_lock);
-+ up(&instance->free_sema);
-+}
-+
-+static void vc_sm_cma_vchi_rx_ack(struct sm_instance *instance,
-+ struct sm_cmd_rsp_blk *cmd,
-+ struct vc_sm_result_t *reply,
-+ u32 reply_len)
-+{
-+ mutex_lock(&instance->lock);
-+ list_for_each_entry(cmd,
-+ &instance->rsp_list,
-+ head) {
-+ if (cmd->id == reply->trans_id)
-+ break;
-+ }
-+ mutex_unlock(&instance->lock);
-+
-+ if (&cmd->head == &instance->rsp_list) {
-+ //pr_debug("%s: received response %u, throw away...",
-+ pr_err("%s: received response %u, throw away...",
-+ __func__,
-+ reply->trans_id);
-+ } else if (reply_len > sizeof(cmd->msg)) {
-+ pr_err("%s: reply too big (%u) %u, throw away...",
-+ __func__, reply_len,
-+ reply->trans_id);
-+ } else {
-+ memcpy(cmd->msg, reply,
-+ reply_len);
-+ complete(&cmd->cmplt);
-+ }
-+}
-+
-+static int vc_sm_cma_vchi_videocore_io(void *arg)
-+{
-+ struct sm_instance *instance = arg;
-+ struct sm_cmd_rsp_blk *cmd = NULL, *cmd_tmp;
-+ struct vc_sm_result_t *reply;
-+ u32 reply_len;
-+ s32 status;
-+ int svc_use = 1;
-+
-+ while (1) {
-+ if (svc_use)
-+ vchi_service_release(instance->vchi_handle[0]);
-+ svc_use = 0;
-+ if (!wait_for_completion_interruptible(&instance->io_cmplt)) {
-+ vchi_service_use(instance->vchi_handle[0]);
-+ svc_use = 1;
-+
-+ do {
-+ /*
-+ * Get new command and move it to response list
-+ */
-+ mutex_lock(&instance->lock);
-+ if (list_empty(&instance->cmd_list)) {
-+ /* no more commands to process */
-+ mutex_unlock(&instance->lock);
-+ break;
-+ }
-+ cmd =
-+ list_first_entry(&instance->cmd_list,
-+ struct sm_cmd_rsp_blk,
-+ head);
-+ list_move(&cmd->head, &instance->rsp_list);
-+ cmd->sent = 1;
-+ mutex_unlock(&instance->lock);
-+
-+ /* Send the command */
-+ status = bcm2835_vchi_msg_queue(
-+ instance->vchi_handle[0],
-+ cmd->msg, cmd->length);
-+ if (status) {
-+ pr_err("%s: failed to queue message (%d)",
-+ __func__, status);
-+ }
-+
-+ /* If no reply is needed then we're done */
-+ if (!cmd->wait) {
-+ mutex_lock(&instance->lock);
-+ list_del(&cmd->head);
-+ mutex_unlock(&instance->lock);
-+ vc_vchi_cmd_delete(instance, cmd);
-+ continue;
-+ }
-+
-+ if (status) {
-+ complete(&cmd->cmplt);
-+ continue;
-+ }
-+
-+ } while (1);
-+
-+ while (!vchi_msg_peek(instance->vchi_handle[0],
-+ (void **)&reply, &reply_len,
-+ VCHI_FLAGS_NONE)) {
-+ if (reply->trans_id & 0x80000000) {
-+ /* Async event or cmd from the VPU */
-+ if (instance->vpu_event)
-+ instance->vpu_event(
-+ instance, reply,
-+ reply_len);
-+ } else {
-+ vc_sm_cma_vchi_rx_ack(instance, cmd,
-+ reply, reply_len);
-+ }
-+
-+ vchi_msg_remove(instance->vchi_handle[0]);
-+ }
-+
-+ /* Go through the dead list and free them */
-+ mutex_lock(&instance->lock);
-+ list_for_each_entry_safe(cmd, cmd_tmp,
-+ &instance->dead_list, head) {
-+ list_del(&cmd->head);
-+ vc_vchi_cmd_delete(instance, cmd);
-+ }
-+ mutex_unlock(&instance->lock);
-+ }
-+ }
-+
-+ return 0;
-+}
-+
-+static void vc_sm_cma_vchi_callback(void *param,
-+ const VCHI_CALLBACK_REASON_T reason,
-+ void *msg_handle)
-+{
-+ struct sm_instance *instance = param;
-+
-+ (void)msg_handle;
-+
-+ switch (reason) {
-+ case VCHI_CALLBACK_MSG_AVAILABLE:
-+ complete(&instance->io_cmplt);
-+ break;
-+
-+ case VCHI_CALLBACK_SERVICE_CLOSED:
-+ pr_info("%s: service CLOSED!!", __func__);
-+ default:
-+ break;
-+ }
-+}
-+
-+struct sm_instance *vc_sm_cma_vchi_init(VCHI_INSTANCE_T vchi_instance,
-+ unsigned int num_connections,
-+ vpu_event_cb vpu_event)
-+{
-+ u32 i;
-+ struct sm_instance *instance;
-+ int status;
-+
-+ pr_debug("%s: start", __func__);
-+
-+ if (num_connections > VCHI_MAX_NUM_CONNECTIONS) {
-+ pr_err("%s: unsupported number of connections %u (max=%u)",
-+ __func__, num_connections, VCHI_MAX_NUM_CONNECTIONS);
-+
-+ goto err_null;
-+ }
-+ /* Allocate memory for this instance */
-+ instance = kzalloc(sizeof(*instance), GFP_KERNEL);
-+
-+ /* Misc initialisations */
-+ mutex_init(&instance->lock);
-+ init_completion(&instance->io_cmplt);
-+ INIT_LIST_HEAD(&instance->cmd_list);
-+ INIT_LIST_HEAD(&instance->rsp_list);
-+ INIT_LIST_HEAD(&instance->dead_list);
-+ INIT_LIST_HEAD(&instance->free_list);
-+ sema_init(&instance->free_sema, SM_MAX_NUM_CMD_RSP_BLKS);
-+ mutex_init(&instance->free_lock);
-+ for (i = 0; i < SM_MAX_NUM_CMD_RSP_BLKS; i++) {
-+ init_completion(&instance->free_blk[i].cmplt);
-+ list_add(&instance->free_blk[i].head, &instance->free_list);
-+ }
-+
-+ /* Open the VCHI service connections */
-+ instance->num_connections = num_connections;
-+ for (i = 0; i < num_connections; i++) {
-+ SERVICE_CREATION_T params = {
-+ .version = VCHI_VERSION_EX(VC_SM_VER, VC_SM_MIN_VER),
-+ .service_id = VC_SM_SERVER_NAME,
-+ .callback = vc_sm_cma_vchi_callback,
-+ .callback_param = instance,
-+ };
-+
-+ status = vchi_service_open(vchi_instance,
-+ &params, &instance->vchi_handle[i]);
-+ if (status) {
-+ pr_err("%s: failed to open VCHI service (%d)",
-+ __func__, status);
-+
-+ goto err_close_services;
-+ }
-+ }
-+
-+ /* Create the thread which takes care of all io to/from videoocore. */
-+ instance->io_thread = kthread_create(&vc_sm_cma_vchi_videocore_io,
-+ (void *)instance, "SMIO");
-+ if (!instance->io_thread) {
-+ pr_err("%s: failed to create SMIO thread", __func__);
-+
-+ goto err_close_services;
-+ }
-+ instance->vpu_event = vpu_event;
-+ set_user_nice(instance->io_thread, -10);
-+ wake_up_process(instance->io_thread);
-+
-+ pr_debug("%s: success - instance 0x%x", __func__,
-+ (unsigned int)instance);
-+ return instance;
-+
-+err_close_services:
-+ for (i = 0; i < instance->num_connections; i++) {
-+ if (instance->vchi_handle[i])
-+ vchi_service_close(instance->vchi_handle[i]);
-+ }
-+ kfree(instance);
-+err_null:
-+ pr_debug("%s: FAILED", __func__);
-+ return NULL;
-+}
-+
-+int vc_sm_cma_vchi_stop(struct sm_instance **handle)
-+{
-+ struct sm_instance *instance;
-+ u32 i;
-+
-+ if (!handle) {
-+ pr_err("%s: invalid pointer to handle %p", __func__, handle);
-+ goto lock;
-+ }
-+
-+ if (!*handle) {
-+ pr_err("%s: invalid handle %p", __func__, *handle);
-+ goto lock;
-+ }
-+
-+ instance = *handle;
-+
-+ /* Close all VCHI service connections */
-+ for (i = 0; i < instance->num_connections; i++) {
-+ s32 success;
-+
-+ vchi_service_use(instance->vchi_handle[i]);
-+
-+ success = vchi_service_close(instance->vchi_handle[i]);
-+ }
-+
-+ kfree(instance);
-+
-+ *handle = NULL;
-+ return 0;
-+
-+lock:
-+ return -EINVAL;
-+}
-+
-+static int vc_sm_cma_vchi_send_msg(struct sm_instance *handle,
-+ enum vc_sm_msg_type msg_id, void *msg,
-+ u32 msg_size, void *result, u32 result_size,
-+ u32 *cur_trans_id, u8 wait_reply)
-+{
-+ int status = 0;
-+ struct sm_instance *instance = handle;
-+ struct sm_cmd_rsp_blk *cmd_blk;
-+
-+ if (!handle) {
-+ pr_err("%s: invalid handle", __func__);
-+ return -EINVAL;
-+ }
-+ if (!msg) {
-+ pr_err("%s: invalid msg pointer", __func__);
-+ return -EINVAL;
-+ }
-+
-+ cmd_blk =
-+ vc_vchi_cmd_create(instance, msg_id, msg, msg_size, wait_reply);
-+ if (!cmd_blk) {
-+ pr_err("[%s]: failed to allocate global tracking resource",
-+ __func__);
-+ return -ENOMEM;
-+ }
-+
-+ if (cur_trans_id)
-+ *cur_trans_id = cmd_blk->id;
-+
-+ mutex_lock(&instance->lock);
-+ list_add_tail(&cmd_blk->head, &instance->cmd_list);
-+ mutex_unlock(&instance->lock);
-+ complete(&instance->io_cmplt);
-+
-+ if (!wait_reply)
-+ /* We're done */
-+ return 0;
-+
-+ /* Wait for the response */
-+ if (wait_for_completion_interruptible(&cmd_blk->cmplt)) {
-+ mutex_lock(&instance->lock);
-+ if (!cmd_blk->sent) {
-+ list_del(&cmd_blk->head);
-+ mutex_unlock(&instance->lock);
-+ vc_vchi_cmd_delete(instance, cmd_blk);
-+ return -ENXIO;
-+ }
-+
-+ list_move(&cmd_blk->head, &instance->dead_list);
-+ mutex_unlock(&instance->lock);
-+ complete(&instance->io_cmplt);
-+ return -EINTR; /* We're done */
-+ }
-+
-+ if (result && result_size) {
-+ memcpy(result, cmd_blk->msg, result_size);
-+ } else {
-+ struct vc_sm_result_t *res =
-+ (struct vc_sm_result_t *)cmd_blk->msg;
-+ status = (res->success == 0) ? 0 : -ENXIO;
-+ }
-+
-+ mutex_lock(&instance->lock);
-+ list_del(&cmd_blk->head);
-+ mutex_unlock(&instance->lock);
-+ vc_vchi_cmd_delete(instance, cmd_blk);
-+ return status;
-+}
-+
-+int vc_sm_cma_vchi_free(struct sm_instance *handle, struct vc_sm_free_t *msg,
-+ u32 *cur_trans_id)
-+{
-+ return vc_sm_cma_vchi_send_msg(handle, VC_SM_MSG_TYPE_FREE,
-+ msg, sizeof(*msg), 0, 0, cur_trans_id, 0);
-+}
-+
-+int vc_sm_cma_vchi_import(struct sm_instance *handle, struct vc_sm_import *msg,
-+ struct vc_sm_import_result *result, u32 *cur_trans_id)
-+{
-+ return vc_sm_cma_vchi_send_msg(handle, VC_SM_MSG_TYPE_IMPORT,
-+ msg, sizeof(*msg), result, sizeof(*result),
-+ cur_trans_id, 1);
-+}
-+
-+int vc_sm_cma_vchi_client_version(struct sm_instance *handle,
-+ struct vc_sm_version *msg,
-+ struct vc_sm_result_t *result,
-+ u32 *cur_trans_id)
-+{
-+ return vc_sm_cma_vchi_send_msg(handle, VC_SM_MSG_TYPE_CLIENT_VERSION,
-+ //msg, sizeof(*msg), result, sizeof(*result),
-+ //cur_trans_id, 1);
-+ msg, sizeof(*msg), NULL, 0,
-+ cur_trans_id, 0);
-+}
---- /dev/null
-+++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma_vchi.h
-@@ -0,0 +1,59 @@
-+/* SPDX-License-Identifier: GPL-2.0 */
-+
-+/*
-+ * VideoCore Shared Memory CMA allocator
-+ *
-+ * Copyright: 2018, Raspberry Pi (Trading) Ltd
-+ * Copyright 2011-2012 Broadcom Corporation. All rights reserved.
-+ *
-+ * Based on vmcs_sm driver from Broadcom Corporation.
-+ *
-+ */
-+
-+#ifndef __VC_SM_CMA_VCHI_H__INCLUDED__
-+#define __VC_SM_CMA_VCHI_H__INCLUDED__
-+
-+#include "interface/vchi/vchi.h"
-+
-+#include "vc_sm_defs.h"
-+
-+/*
-+ * Forward declare.
-+ */
-+struct sm_instance;
-+
-+typedef void (*vpu_event_cb)(struct sm_instance *instance,
-+ struct vc_sm_result_t *reply, int reply_len);
-+
-+/*
-+ * Initialize the shared memory service, opens up vchi connection to talk to it.
-+ */
-+struct sm_instance *vc_sm_cma_vchi_init(VCHI_INSTANCE_T vchi_instance,
-+ unsigned int num_connections,
-+ vpu_event_cb vpu_event);
-+
-+/*
-+ * Terminates the shared memory service.
-+ */
-+int vc_sm_cma_vchi_stop(struct sm_instance **handle);
-+
-+/*
-+ * Ask the shared memory service to free up some memory that was previously
-+ * allocated by the vc_sm_cma_vchi_alloc function call.
-+ */
-+int vc_sm_cma_vchi_free(struct sm_instance *handle, struct vc_sm_free_t *msg,
-+ u32 *cur_trans_id);
-+
-+/*
-+ * Import a contiguous block of memory and wrap it in a GPU MEM_HANDLE_T.
-+ */
-+int vc_sm_cma_vchi_import(struct sm_instance *handle, struct vc_sm_import *msg,
-+ struct vc_sm_import_result *result,
-+ u32 *cur_trans_id);
-+
-+int vc_sm_cma_vchi_client_version(struct sm_instance *handle,
-+ struct vc_sm_version *msg,
-+ struct vc_sm_result_t *result,
-+ u32 *cur_trans_id);
-+
-+#endif /* __VC_SM_CMA_VCHI_H__INCLUDED__ */
---- /dev/null
-+++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm_defs.h
-@@ -0,0 +1,298 @@
-+/* SPDX-License-Identifier: GPL-2.0 */
-+
-+/*
-+ * VideoCore Shared Memory CMA allocator
-+ *
-+ * Copyright: 2018, Raspberry Pi (Trading) Ltd
-+ *
-+ * Based on vc_sm_defs.h from the vmcs_sm driver Copyright Broadcom Corporation.
-+ * All IPC messages are copied across to this file, even if the vc-sm-cma
-+ * driver is not currently using them.
-+ *
-+ ****************************************************************************
-+ */
-+
-+#ifndef __VC_SM_DEFS_H__INCLUDED__
-+#define __VC_SM_DEFS_H__INCLUDED__
-+
-+/* FourCC code used for VCHI connection */
-+#define VC_SM_SERVER_NAME MAKE_FOURCC("SMEM")
-+
-+/* Maximum message length */
-+#define VC_SM_MAX_MSG_LEN (sizeof(union vc_sm_msg_union_t) + \
-+ sizeof(struct vc_sm_msg_hdr_t))
-+#define VC_SM_MAX_RSP_LEN (sizeof(union vc_sm_msg_union_t))
-+
-+/* Resource name maximum size */
-+#define VC_SM_RESOURCE_NAME 32
-+
-+/*
-+ * Version to be reported to the VPU
-+ * VPU assumes 0 (aka 1) which does not require the released callback, nor
-+ * expect the client to handle VC_MEM_REQUESTS.
-+ * Version 2 requires the released callback, and must support VC_MEM_REQUESTS.
-+ */
-+#define VC_SM_PROTOCOL_VERSION 2
-+
-+enum vc_sm_msg_type {
-+ /* Message types supported for HOST->VC direction */
-+
-+ /* Allocate shared memory block */
-+ VC_SM_MSG_TYPE_ALLOC,
-+ /* Lock allocated shared memory block */
-+ VC_SM_MSG_TYPE_LOCK,
-+ /* Unlock allocated shared memory block */
-+ VC_SM_MSG_TYPE_UNLOCK,
-+ /* Unlock allocated shared memory block, do not answer command */
-+ VC_SM_MSG_TYPE_UNLOCK_NOANS,
-+ /* Free shared memory block */
-+ VC_SM_MSG_TYPE_FREE,
-+ /* Resize a shared memory block */
-+ VC_SM_MSG_TYPE_RESIZE,
-+ /* Walk the allocated shared memory block(s) */
-+ VC_SM_MSG_TYPE_WALK_ALLOC,
-+
-+ /* A previously applied action will need to be reverted */
-+ VC_SM_MSG_TYPE_ACTION_CLEAN,
-+
-+ /*
-+ * Import a physical address and wrap into a MEM_HANDLE_T.
-+ * Release with VC_SM_MSG_TYPE_FREE.
-+ */
-+ VC_SM_MSG_TYPE_IMPORT,
-+ /*
-+ *Tells VC the protocol version supported by this client.
-+ * 2 supports the async/cmd messages from the VPU for final release
-+ * of memory, and for VC allocations.
-+ */
-+ VC_SM_MSG_TYPE_CLIENT_VERSION,
-+ /* Response to VC request for memory */
-+ VC_SM_MSG_TYPE_VC_MEM_REQUEST_REPLY,
-+
-+ /*
-+ * Asynchronous/cmd messages supported for VC->HOST direction.
-+ * Signalled by setting the top bit in vc_sm_result_t trans_id.
-+ */
-+
-+ /*
-+ * VC has finished with an imported memory allocation.
-+ * Release any Linux reference counts on the underlying block.
-+ */
-+ VC_SM_MSG_TYPE_RELEASED,
-+ /* VC request for memory */
-+ VC_SM_MSG_TYPE_VC_MEM_REQUEST,
-+
-+ VC_SM_MSG_TYPE_MAX
-+};
-+
-+/* Type of memory to be allocated */
-+enum vc_sm_alloc_type_t {
-+ VC_SM_ALLOC_CACHED,
-+ VC_SM_ALLOC_NON_CACHED,
-+};
-+
-+/* Message header for all messages in HOST->VC direction */
-+struct vc_sm_msg_hdr_t {
-+ u32 type;
-+ u32 trans_id;
-+ u8 body[0];
-+
-+};
-+
-+/* Request to allocate memory (HOST->VC) */
-+struct vc_sm_alloc_t {
-+ /* type of memory to allocate */
-+ enum vc_sm_alloc_type_t type;
-+ /* byte amount of data to allocate per unit */
-+ u32 base_unit;
-+ /* number of unit to allocate */
-+ u32 num_unit;
-+ /* alignment to be applied on allocation */
-+ u32 alignment;
-+ /* identity of who allocated this block */
-+ u32 allocator;
-+ /* resource name (for easier tracking on vc side) */
-+ char name[VC_SM_RESOURCE_NAME];
-+
-+};
-+
-+/* Result of a requested memory allocation (VC->HOST) */
-+struct vc_sm_alloc_result_t {
-+ /* Transaction identifier */
-+ u32 trans_id;
-+
-+ /* Resource handle */
-+ u32 res_handle;
-+ /* Pointer to resource buffer */
-+ u32 res_mem;
-+ /* Resource base size (bytes) */
-+ u32 res_base_size;
-+ /* Resource number */
-+ u32 res_num;
-+
-+};
-+
-+/* Request to free a previously allocated memory (HOST->VC) */
-+struct vc_sm_free_t {
-+ /* Resource handle (returned from alloc) */
-+ u32 res_handle;
-+ /* Resource buffer (returned from alloc) */
-+ u32 res_mem;
-+
-+};
-+
-+/* Request to lock a previously allocated memory (HOST->VC) */
-+struct vc_sm_lock_unlock_t {
-+ /* Resource handle (returned from alloc) */
-+ u32 res_handle;
-+ /* Resource buffer (returned from alloc) */
-+ u32 res_mem;
-+
-+};
-+
-+/* Request to resize a previously allocated memory (HOST->VC) */
-+struct vc_sm_resize_t {
-+ /* Resource handle (returned from alloc) */
-+ u32 res_handle;
-+ /* Resource buffer (returned from alloc) */
-+ u32 res_mem;
-+ /* Resource *new* size requested (bytes) */
-+ u32 res_new_size;
-+
-+};
-+
-+/* Result of a requested memory lock (VC->HOST) */
-+struct vc_sm_lock_result_t {
-+ /* Transaction identifier */
-+ u32 trans_id;
-+
-+ /* Resource handle */
-+ u32 res_handle;
-+ /* Pointer to resource buffer */
-+ u32 res_mem;
-+ /*
-+ * Pointer to former resource buffer if the memory
-+ * was reallocated
-+ */
-+ u32 res_old_mem;
-+
-+};
-+
-+/* Generic result for a request (VC->HOST) */
-+struct vc_sm_result_t {
-+ /* Transaction identifier */
-+ u32 trans_id;
-+
-+ s32 success;
-+
-+};
-+
-+/* Request to revert a previously applied action (HOST->VC) */
-+struct vc_sm_action_clean_t {
-+ /* Action of interest */
-+ enum vc_sm_msg_type res_action;
-+ /* Transaction identifier for the action of interest */
-+ u32 action_trans_id;
-+
-+};
-+
-+/* Request to remove all data associated with a given allocator (HOST->VC) */
-+struct vc_sm_free_all_t {
-+ /* Allocator identifier */
-+ u32 allocator;
-+};
-+
-+/* Request to import memory (HOST->VC) */
-+struct vc_sm_import {
-+ /* type of memory to allocate */
-+ enum vc_sm_alloc_type_t type;
-+ /* pointer to the VC (ie physical) address of the allocated memory */
-+ u32 addr;
-+ /* size of buffer */
-+ u32 size;
-+ /* opaque handle returned in RELEASED messages */
-+ u32 kernel_id;
-+ /* Allocator identifier */
-+ u32 allocator;
-+ /* resource name (for easier tracking on vc side) */
-+ char name[VC_SM_RESOURCE_NAME];
-+};
-+
-+/* Result of a requested memory import (VC->HOST) */
-+struct vc_sm_import_result {
-+ /* Transaction identifier */
-+ u32 trans_id;
-+
-+ /* Resource handle */
-+ u32 res_handle;
-+};
-+
-+/* Notification that VC has finished with an allocation (VC->HOST) */
-+struct vc_sm_released {
-+ /* cmd type / trans_id */
-+ u32 cmd;
-+
-+ /* pointer to the VC (ie physical) address of the allocated memory */
-+ u32 addr;
-+ /* size of buffer */
-+ u32 size;
-+ /* opaque handle returned in RELEASED messages */
-+ u32 kernel_id;
-+ u32 vc_handle;
-+};
-+
-+/*
-+ * Client informing VC as to the protocol version it supports.
-+ * >=2 requires the released callback, and supports VC asking for memory.
-+ * Failure means that the firmware doesn't support this call, and therefore the
-+ * client should either fail, or NOT rely on getting the released callback.
-+ */
-+struct vc_sm_version {
-+ u32 version;
-+};
-+
-+/* Request FROM VideoCore for some memory */
-+struct vc_sm_vc_mem_request {
-+ /* cmd type */
-+ u32 cmd;
-+
-+ /* trans_id (from VPU) */
-+ u32 trans_id;
-+ /* size of buffer */
-+ u32 size;
-+ /* alignment of buffer */
-+ u32 align;
-+ /* resource name (for easier tracking) */
-+ char name[VC_SM_RESOURCE_NAME];
-+};
-+
-+/* Response from the kernel to provide the VPU with some memory */
-+struct vc_sm_vc_mem_request_result {
-+ /* Transaction identifier for the VPU */
-+ u32 trans_id;
-+ /* pointer to the physical address of the allocated memory */
-+ u32 addr;
-+ /* opaque handle returned in RELEASED messages */
-+ u32 kernel_id;
-+};
-+
-+/* Union of ALL messages */
-+union vc_sm_msg_union_t {
-+ struct vc_sm_alloc_t alloc;
-+ struct vc_sm_alloc_result_t alloc_result;
-+ struct vc_sm_free_t free;
-+ struct vc_sm_lock_unlock_t lock_unlock;
-+ struct vc_sm_action_clean_t action_clean;
-+ struct vc_sm_resize_t resize;
-+ struct vc_sm_lock_result_t lock_result;
-+ struct vc_sm_result_t result;
-+ struct vc_sm_free_all_t free_all;
-+ struct vc_sm_import import;
-+ struct vc_sm_import_result import_result;
-+ struct vc_sm_version version;
-+ struct vc_sm_released released;
-+ struct vc_sm_vc_mem_request vc_request;
-+ struct vc_sm_vc_mem_request_result vc_request_result;
-+};
-+
-+#endif /* __VC_SM_DEFS_H__INCLUDED__ */
---- /dev/null
-+++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm_knl.h
-@@ -0,0 +1,28 @@
-+/* SPDX-License-Identifier: GPL-2.0 */
-+
-+/*
-+ * VideoCore Shared Memory CMA allocator
-+ *
-+ * Copyright: 2018, Raspberry Pi (Trading) Ltd
-+ *
-+ * Based on vc_sm_defs.h from the vmcs_sm driver Copyright Broadcom Corporation.
-+ *
-+ */
-+
-+#ifndef __VC_SM_KNL_H__INCLUDED__
-+#define __VC_SM_KNL_H__INCLUDED__
-+
-+#if !defined(__KERNEL__)
-+#error "This interface is for kernel use only..."
-+#endif
-+
-+/* Free a previously allocated or imported shared memory handle and block. */
-+int vc_sm_cma_free(int handle);
-+
-+/* Get an internal resource handle mapped from the external one. */
-+int vc_sm_cma_int_handle(int handle);
-+
-+/* Import a block of memory into the GPU space. */
-+int vc_sm_cma_import_dmabuf(struct dma_buf *dmabuf, int *handle);
-+
-+#endif /* __VC_SM_KNL_H__INCLUDED__ */