1 From b17f6dc1d79ae057294ac2d8d824aa2258ab09a8 Mon Sep 17 00:00:00 2001
2 From: Dave Stevenson <dave.stevenson@raspberrypi.org>
3 Date: Wed, 20 Mar 2019 10:40:00 +0000
4 Subject: [PATCH] staging: vcsm-cma: Add cache control ioctls
6 The old driver allowed for direct cache manipulation and that
7 was used by various clients. Replicate here.
9 Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
11 .../staging/vc04_services/vc-sm-cma/vc_sm.c | 141 +++++++++++++++++-
12 include/linux/broadcom/vc_sm_cma_ioctl.h | 27 ++++
13 2 files changed, 165 insertions(+), 3 deletions(-)
15 --- a/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
16 +++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm.c
18 #include <linux/seq_file.h>
19 #include <linux/syscalls.h>
20 #include <linux/types.h>
21 +#include <asm/cacheflush.h>
23 #include "vchiq_connected.h"
24 #include "vc_sm_cma_vchi.h"
25 @@ -1258,6 +1259,99 @@ error:
29 +/* Converts VCSM_CACHE_OP_* to an operating function. */
30 +static void (*cache_op_to_func(const unsigned int cache_op))
31 + (const void*, const void*)
34 + case VC_SM_CACHE_OP_NOP:
37 + case VC_SM_CACHE_OP_INV:
38 + return dmac_inv_range;
40 + case VC_SM_CACHE_OP_CLEAN:
41 + return dmac_clean_range;
43 + case VC_SM_CACHE_OP_FLUSH:
44 + return dmac_flush_range;
47 + pr_err("[%s]: Invalid cache_op: 0x%08x\n", __func__, cache_op);
53 + * Clean/invalid/flush cache of which buffer is already pinned (i.e. accessed).
55 +static int clean_invalid_contig_2d(const void __user *addr,
56 + const size_t block_count,
57 + const size_t block_size,
58 + const size_t stride,
59 + const unsigned int cache_op)
62 + void (*op_fn)(const void *start, const void *end);
65 + pr_err("[%s]: size cannot be 0\n", __func__);
69 + op_fn = cache_op_to_func(cache_op);
73 + for (i = 0; i < block_count; i ++, addr += stride)
74 + op_fn(addr, addr + block_size);
79 +static int vc_sm_cma_clean_invalid2(unsigned int cmdnr, unsigned long arg)
81 + struct vc_sm_cma_ioctl_clean_invalid2 ioparam;
82 + struct vc_sm_cma_ioctl_clean_invalid_block *block = NULL;
85 + /* Get parameter data. */
86 + if (copy_from_user(&ioparam, (void *)arg, sizeof(ioparam))) {
87 + pr_err("[%s]: failed to copy-from-user header for cmd %x\n",
91 + block = kmalloc(ioparam.op_count * sizeof(*block), GFP_KERNEL);
95 + if (copy_from_user(block, (void *)(arg + sizeof(ioparam)),
96 + ioparam.op_count * sizeof(*block)) != 0) {
97 + pr_err("[%s]: failed to copy-from-user payload for cmd %x\n",
103 + for (i = 0; i < ioparam.op_count; i++) {
104 + const struct vc_sm_cma_ioctl_clean_invalid_block * const op = block + i;
106 + if (op->invalidate_mode == VC_SM_CACHE_OP_NOP)
109 + ret = clean_invalid_contig_2d((void __user *)op->start_address,
110 + op->block_count, op->block_size,
111 + op->inter_block_stride,
112 + op->invalidate_mode);
122 static long vc_sm_cma_ioctl(struct file *file, unsigned int cmd,
125 @@ -1272,9 +1366,6 @@ static long vc_sm_cma_ioctl(struct file
129 - pr_debug("[%s]: cmd %x tgid %u, owner %u\n", __func__, cmdnr,
130 - current->tgid, file_data->pid);
132 /* Action is a re-post of a previously interrupted action? */
133 if (file_data->restart_sys == -EINTR) {
134 struct vc_sm_action_clean_t action_clean;
135 @@ -1357,7 +1448,18 @@ static long vc_sm_cma_ioctl(struct file
140 + * Flush/Invalidate the cache for a given mapping.
141 + * Blocks must be pinned (i.e. accessed) before this call.
143 + case VC_SM_CMA_CMD_CLEAN_INVALID2:
144 + ret = vc_sm_cma_clean_invalid2(cmdnr, arg);
148 + pr_debug("[%s]: cmd %x tgid %u, owner %u\n", __func__, cmdnr,
149 + current->tgid, file_data->pid);
154 @@ -1365,10 +1467,43 @@ static long vc_sm_cma_ioctl(struct file
158 +#ifdef CONFIG_COMPAT
159 +struct vc_sm_cma_ioctl_clean_invalid2_32 {
161 + struct vc_sm_cma_ioctl_clean_invalid_block {
162 + u16 invalidate_mode;
164 + compat_uptr_t start_address;
166 + u32 inter_block_stride;
170 +#define VC_SM_CMA_CMD_CLEAN_INVALID2_32\
171 + _IOR(VC_SM_CMA_MAGIC_TYPE, VC_SM_CMA_CMD_CLEAN_INVALID2,\
172 + struct vc_sm_cma_ioctl_clean_invalid2)
174 +static long vc_sm_cma_compat_ioctl(struct file *file, unsigned int cmd,
178 + case VC_SM_CMA_CMD_CLEAN_INVALID2_32:
183 + return vc_sm_cma_compat_ioctl(file, cmd, arg);
188 /* Device operations that we managed in this driver. */
189 static const struct file_operations vc_sm_ops = {
190 .owner = THIS_MODULE,
191 .unlocked_ioctl = vc_sm_cma_ioctl,
192 +#ifdef CONFIG_COMPAT
193 + .compat_ioctl = vc_sm_cma_compat_ioctl,
195 .open = vc_sm_cma_open,
196 .release = vc_sm_cma_release,
198 --- a/include/linux/broadcom/vc_sm_cma_ioctl.h
199 +++ b/include/linux/broadcom/vc_sm_cma_ioctl.h
200 @@ -33,6 +33,8 @@ enum vc_sm_cma_cmd_e {
202 VC_SM_CMA_CMD_IMPORT_DMABUF,
204 + VC_SM_CMA_CMD_CLEAN_INVALID2,
206 VC_SM_CMA_CMD_LAST /* Do not delete */
209 @@ -75,6 +77,27 @@ struct vc_sm_cma_ioctl_import_dmabuf {
214 + * Cache functions to be set to struct vc_sm_cma_ioctl_clean_invalid2
217 +#define VC_SM_CACHE_OP_NOP 0x00
218 +#define VC_SM_CACHE_OP_INV 0x01
219 +#define VC_SM_CACHE_OP_CLEAN 0x02
220 +#define VC_SM_CACHE_OP_FLUSH 0x03
222 +struct vc_sm_cma_ioctl_clean_invalid2 {
225 + struct vc_sm_cma_ioctl_clean_invalid_block {
226 + __u32 invalidate_mode;
228 + void * __user start_address;
230 + __u32 inter_block_stride;
235 #define VC_SM_CMA_IOCTL_MEM_ALLOC\
236 _IOR(VC_SM_CMA_MAGIC_TYPE, VC_SM_CMA_CMD_ALLOC,\
237 @@ -84,4 +107,8 @@ struct vc_sm_cma_ioctl_import_dmabuf {
238 _IOR(VC_SM_CMA_MAGIC_TYPE, VC_SM_CMA_CMD_IMPORT_DMABUF,\
239 struct vc_sm_cma_ioctl_import_dmabuf)
241 +#define VC_SM_CMA_IOCTL_MEM_CLEAN_INVALID2\
242 + _IOR(VC_SM_CMA_MAGIC_TYPE, VC_SM_CMA_CMD_CLEAN_INVALID2,\
243 + struct vc_sm_cma_ioctl_clean_invalid2)
245 #endif /* __VC_SM_CMA_IOCTL_H */