Commit 30e54a37 authored by Dave Stevenson's avatar Dave Stevenson Committed by popcornmix
Browse files

staging: vcsm-cma: Add cache control ioctls



The old driver allowed for direct cache manipulation and that
was used by various clients. Replicate here.

Signed-off-by: default avatarDave Stevenson <dave.stevenson@raspberrypi.org>
parent d218dac3
Loading
Loading
Loading
Loading
+138 −3
Original line number Original line Diff line number Diff line
@@ -46,6 +46,7 @@
#include <linux/seq_file.h>
#include <linux/seq_file.h>
#include <linux/syscalls.h>
#include <linux/syscalls.h>
#include <linux/types.h>
#include <linux/types.h>
#include <asm/cacheflush.h>


#include "vchiq_connected.h"
#include "vchiq_connected.h"
#include "vc_sm_cma_vchi.h"
#include "vc_sm_cma_vchi.h"
@@ -1258,6 +1259,99 @@ error:
	return ret;
	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,
static long vc_sm_cma_ioctl(struct file *file, unsigned int cmd,
			    unsigned long arg)
			    unsigned long arg)
{
{
@@ -1272,9 +1366,6 @@ static long vc_sm_cma_ioctl(struct file *file, unsigned int cmd,
		return -EPERM;
		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? */
	/* Action is a re-post of a previously interrupted action? */
	if (file_data->restart_sys == -EINTR) {
	if (file_data->restart_sys == -EINTR) {
		struct vc_sm_action_clean_t action_clean;
		struct vc_sm_action_clean_t action_clean;
@@ -1357,7 +1448,18 @@ static long vc_sm_cma_ioctl(struct file *file, unsigned int cmd,
		break;
		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:
	default:
		pr_debug("[%s]: cmd %x tgid %u, owner %u\n", __func__, cmdnr,
			 current->tgid, file_data->pid);

		ret = -EINVAL;
		ret = -EINVAL;
		break;
		break;
	}
	}
@@ -1365,10 +1467,43 @@ static long vc_sm_cma_ioctl(struct file *file, unsigned int cmd,
	return ret;
	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. */
/* Device operations that we managed in this driver. */
static const struct file_operations vc_sm_ops = {
static const struct file_operations vc_sm_ops = {
	.owner = THIS_MODULE,
	.owner = THIS_MODULE,
	.unlocked_ioctl = vc_sm_cma_ioctl,
	.unlocked_ioctl = vc_sm_cma_ioctl,
#ifdef CONFIG_COMPAT
	.compat_ioctl = vc_sm_cma_compat_ioctl,
#endif
	.open = vc_sm_cma_open,
	.open = vc_sm_cma_open,
	.release = vc_sm_cma_release,
	.release = vc_sm_cma_release,
};
};
+27 −0
Original line number Original line Diff line number Diff line
@@ -33,6 +33,8 @@ enum vc_sm_cma_cmd_e {


	VC_SM_CMA_CMD_IMPORT_DMABUF,
	VC_SM_CMA_CMD_IMPORT_DMABUF,


	VC_SM_CMA_CMD_CLEAN_INVALID2,

	VC_SM_CMA_CMD_LAST	/* Do not delete */
	VC_SM_CMA_CMD_LAST	/* Do not delete */
};
};


@@ -75,6 +77,27 @@ struct vc_sm_cma_ioctl_import_dmabuf {
	__u64 dma_addr;
	__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 */
/* IOCTL numbers */
#define VC_SM_CMA_IOCTL_MEM_ALLOC\
#define VC_SM_CMA_IOCTL_MEM_ALLOC\
	_IOR(VC_SM_CMA_MAGIC_TYPE, VC_SM_CMA_CMD_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,\
	_IOR(VC_SM_CMA_MAGIC_TYPE, VC_SM_CMA_CMD_IMPORT_DMABUF,\
	 struct vc_sm_cma_ioctl_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 */
#endif /* __VC_SM_CMA_IOCTL_H */