You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
246 lines
6.4 KiB
Diff
246 lines
6.4 KiB
Diff
5 years ago
|
From b17f6dc1d79ae057294ac2d8d824aa2258ab09a8 Mon Sep 17 00:00:00 2001
|
||
5 years ago
|
From: Dave Stevenson <dave.stevenson@raspberrypi.org>
|
||
|
Date: Wed, 20 Mar 2019 10:40:00 +0000
|
||
5 years ago
|
Subject: [PATCH] staging: vcsm-cma: Add cache control ioctls
|
||
5 years ago
|
|
||
|
The old driver allowed for direct cache manipulation and that
|
||
|
was used by various clients. Replicate here.
|
||
|
|
||
|
Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
|
||
|
---
|
||
|
.../staging/vc04_services/vc-sm-cma/vc_sm.c | 141 +++++++++++++++++-
|
||
|
include/linux/broadcom/vc_sm_cma_ioctl.h | 27 ++++
|
||
|
2 files changed, 165 insertions(+), 3 deletions(-)
|
||
|
|
||
|
--- a/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
|
||
|
+++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
|
||
|
@@ -46,6 +46,7 @@
|
||
|
#include <linux/seq_file.h>
|
||
|
#include <linux/syscalls.h>
|
||
|
#include <linux/types.h>
|
||
|
+#include <asm/cacheflush.h>
|
||
|
|
||
|
#include "vchiq_connected.h"
|
||
|
#include "vc_sm_cma_vchi.h"
|
||
|
@@ -1258,6 +1259,99 @@ error:
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
+/* Converts VCSM_CACHE_OP_* to an operating function. */
|
||
|
+static void (*cache_op_to_func(const unsigned int cache_op))
|
||
|
+ (const void*, const void*)
|
||
|
+{
|
||
|
+ switch (cache_op) {
|
||
|
+ case VC_SM_CACHE_OP_NOP:
|
||
|
+ return NULL;
|
||
|
+
|
||
|
+ case VC_SM_CACHE_OP_INV:
|
||
|
+ return dmac_inv_range;
|
||
|
+
|
||
|
+ case VC_SM_CACHE_OP_CLEAN:
|
||
|
+ return dmac_clean_range;
|
||
|
+
|
||
|
+ case VC_SM_CACHE_OP_FLUSH:
|
||
|
+ return dmac_flush_range;
|
||
|
+
|
||
|
+ default:
|
||
|
+ pr_err("[%s]: Invalid cache_op: 0x%08x\n", __func__, cache_op);
|
||
|
+ return NULL;
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
+/*
|
||
|
+ * Clean/invalid/flush cache of which buffer is already pinned (i.e. accessed).
|
||
|
+ */
|
||
|
+static int clean_invalid_contig_2d(const void __user *addr,
|
||
|
+ const size_t block_count,
|
||
|
+ const size_t block_size,
|
||
|
+ const size_t stride,
|
||
|
+ const unsigned int cache_op)
|
||
|
+{
|
||
|
+ size_t i;
|
||
|
+ void (*op_fn)(const void *start, const void *end);
|
||
|
+
|
||
|
+ if (!block_size) {
|
||
|
+ pr_err("[%s]: size cannot be 0\n", __func__);
|
||
|
+ return -EINVAL;
|
||
|
+ }
|
||
|
+
|
||
|
+ op_fn = cache_op_to_func(cache_op);
|
||
|
+ if (!op_fn)
|
||
|
+ return -EINVAL;
|
||
|
+
|
||
|
+ for (i = 0; i < block_count; i ++, addr += stride)
|
||
|
+ op_fn(addr, addr + block_size);
|
||
|
+
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+static int vc_sm_cma_clean_invalid2(unsigned int cmdnr, unsigned long arg)
|
||
|
+{
|
||
|
+ struct vc_sm_cma_ioctl_clean_invalid2 ioparam;
|
||
|
+ struct vc_sm_cma_ioctl_clean_invalid_block *block = NULL;
|
||
|
+ int i, ret = 0;
|
||
|
+
|
||
|
+ /* Get parameter data. */
|
||
|
+ if (copy_from_user(&ioparam, (void *)arg, sizeof(ioparam))) {
|
||
|
+ pr_err("[%s]: failed to copy-from-user header for cmd %x\n",
|
||
|
+ __func__, cmdnr);
|
||
|
+ return -EFAULT;
|
||
|
+ }
|
||
|
+ block = kmalloc(ioparam.op_count * sizeof(*block), GFP_KERNEL);
|
||
|
+ if (!block)
|
||
|
+ return -EFAULT;
|
||
|
+
|
||
|
+ if (copy_from_user(block, (void *)(arg + sizeof(ioparam)),
|
||
|
+ ioparam.op_count * sizeof(*block)) != 0) {
|
||
|
+ pr_err("[%s]: failed to copy-from-user payload for cmd %x\n",
|
||
|
+ __func__, cmdnr);
|
||
|
+ ret = -EFAULT;
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+
|
||
|
+ for (i = 0; i < ioparam.op_count; i++) {
|
||
|
+ const struct vc_sm_cma_ioctl_clean_invalid_block * const op = block + i;
|
||
|
+
|
||
|
+ if (op->invalidate_mode == VC_SM_CACHE_OP_NOP)
|
||
|
+ continue;
|
||
|
+
|
||
|
+ ret = clean_invalid_contig_2d((void __user *)op->start_address,
|
||
|
+ op->block_count, op->block_size,
|
||
|
+ op->inter_block_stride,
|
||
|
+ op->invalidate_mode);
|
||
|
+ if (ret)
|
||
|
+ break;
|
||
|
+ }
|
||
|
+out:
|
||
|
+ kfree(block);
|
||
|
+
|
||
|
+ return ret;
|
||
|
+}
|
||
|
+
|
||
|
static long vc_sm_cma_ioctl(struct file *file, unsigned int cmd,
|
||
|
unsigned long arg)
|
||
|
{
|
||
|
@@ -1272,9 +1366,6 @@ static long vc_sm_cma_ioctl(struct file
|
||
|
return -EPERM;
|
||
|
}
|
||
|
|
||
|
- pr_debug("[%s]: cmd %x tgid %u, owner %u\n", __func__, cmdnr,
|
||
|
- current->tgid, file_data->pid);
|
||
|
-
|
||
|
/* Action is a re-post of a previously interrupted action? */
|
||
|
if (file_data->restart_sys == -EINTR) {
|
||
|
struct vc_sm_action_clean_t action_clean;
|
||
|
@@ -1357,7 +1448,18 @@ static long vc_sm_cma_ioctl(struct file
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
+ /*
|
||
|
+ * Flush/Invalidate the cache for a given mapping.
|
||
|
+ * Blocks must be pinned (i.e. accessed) before this call.
|
||
|
+ */
|
||
|
+ case VC_SM_CMA_CMD_CLEAN_INVALID2:
|
||
|
+ ret = vc_sm_cma_clean_invalid2(cmdnr, arg);
|
||
|
+ break;
|
||
|
+
|
||
|
default:
|
||
|
+ pr_debug("[%s]: cmd %x tgid %u, owner %u\n", __func__, cmdnr,
|
||
|
+ current->tgid, file_data->pid);
|
||
|
+
|
||
|
ret = -EINVAL;
|
||
|
break;
|
||
|
}
|
||
|
@@ -1365,10 +1467,43 @@ static long vc_sm_cma_ioctl(struct file
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
+#ifdef CONFIG_COMPAT
|
||
|
+struct vc_sm_cma_ioctl_clean_invalid2_32 {
|
||
|
+ u32 op_count;
|
||
|
+ struct vc_sm_cma_ioctl_clean_invalid_block {
|
||
|
+ u16 invalidate_mode;
|
||
|
+ u16 block_count;
|
||
|
+ compat_uptr_t start_address;
|
||
|
+ u32 block_size;
|
||
|
+ u32 inter_block_stride;
|
||
|
+ } s[0];
|
||
|
+};
|
||
|
+
|
||
|
+#define VC_SM_CMA_CMD_CLEAN_INVALID2_32\
|
||
|
+ _IOR(VC_SM_CMA_MAGIC_TYPE, VC_SM_CMA_CMD_CLEAN_INVALID2,\
|
||
|
+ struct vc_sm_cma_ioctl_clean_invalid2)
|
||
|
+
|
||
|
+static long vc_sm_cma_compat_ioctl(struct file *file, unsigned int cmd,
|
||
|
+ unsigned long arg)
|
||
|
+{
|
||
|
+ switch (cmd) {
|
||
|
+ case VC_SM_CMA_CMD_CLEAN_INVALID2_32:
|
||
|
+ /* FIXME */
|
||
|
+ break;
|
||
|
+
|
||
|
+ default:
|
||
|
+ return vc_sm_cma_compat_ioctl(file, cmd, arg);
|
||
|
+ }
|
||
|
+}
|
||
|
+#endif
|
||
|
+
|
||
|
/* Device operations that we managed in this driver. */
|
||
|
static const struct file_operations vc_sm_ops = {
|
||
|
.owner = THIS_MODULE,
|
||
|
.unlocked_ioctl = vc_sm_cma_ioctl,
|
||
|
+#ifdef CONFIG_COMPAT
|
||
|
+ .compat_ioctl = vc_sm_cma_compat_ioctl,
|
||
|
+#endif
|
||
|
.open = vc_sm_cma_open,
|
||
|
.release = vc_sm_cma_release,
|
||
|
};
|
||
|
--- a/include/linux/broadcom/vc_sm_cma_ioctl.h
|
||
|
+++ b/include/linux/broadcom/vc_sm_cma_ioctl.h
|
||
|
@@ -33,6 +33,8 @@ enum vc_sm_cma_cmd_e {
|
||
|
|
||
|
VC_SM_CMA_CMD_IMPORT_DMABUF,
|
||
|
|
||
|
+ VC_SM_CMA_CMD_CLEAN_INVALID2,
|
||
|
+
|
||
|
VC_SM_CMA_CMD_LAST /* Do not delete */
|
||
|
};
|
||
|
|
||
|
@@ -75,6 +77,27 @@ struct vc_sm_cma_ioctl_import_dmabuf {
|
||
|
__u64 dma_addr;
|
||
|
};
|
||
|
|
||
|
+/*
|
||
|
+ * Cache functions to be set to struct vc_sm_cma_ioctl_clean_invalid2
|
||
|
+ * invalidate_mode.
|
||
|
+ */
|
||
|
+#define VC_SM_CACHE_OP_NOP 0x00
|
||
|
+#define VC_SM_CACHE_OP_INV 0x01
|
||
|
+#define VC_SM_CACHE_OP_CLEAN 0x02
|
||
|
+#define VC_SM_CACHE_OP_FLUSH 0x03
|
||
|
+
|
||
|
+struct vc_sm_cma_ioctl_clean_invalid2 {
|
||
|
+ __u32 op_count;
|
||
|
+ __u32 pad;
|
||
|
+ struct vc_sm_cma_ioctl_clean_invalid_block {
|
||
|
+ __u32 invalidate_mode;
|
||
|
+ __u32 block_count;
|
||
|
+ void * __user start_address;
|
||
|
+ __u32 block_size;
|
||
|
+ __u32 inter_block_stride;
|
||
|
+ } s[0];
|
||
|
+};
|
||
|
+
|
||
|
/* IOCTL numbers */
|
||
|
#define VC_SM_CMA_IOCTL_MEM_ALLOC\
|
||
|
_IOR(VC_SM_CMA_MAGIC_TYPE, VC_SM_CMA_CMD_ALLOC,\
|
||
|
@@ -84,4 +107,8 @@ struct vc_sm_cma_ioctl_import_dmabuf {
|
||
|
_IOR(VC_SM_CMA_MAGIC_TYPE, VC_SM_CMA_CMD_IMPORT_DMABUF,\
|
||
|
struct vc_sm_cma_ioctl_import_dmabuf)
|
||
|
|
||
|
+#define VC_SM_CMA_IOCTL_MEM_CLEAN_INVALID2\
|
||
|
+ _IOR(VC_SM_CMA_MAGIC_TYPE, VC_SM_CMA_CMD_CLEAN_INVALID2,\
|
||
|
+ struct vc_sm_cma_ioctl_clean_invalid2)
|
||
|
+
|
||
|
#endif /* __VC_SM_CMA_IOCTL_H */
|