[PATCH 2/4] Staging: memrar: adding memrar user code adding the user code portion of memrar_handler

Chris McIntosh rougechampion2002 at gmail.com
Sun Jul 25 10:18:24 UTC 2010


Signed-off-by: Chris McIntosh <rougechampion2002 at gmail.com>
---
 drivers/staging/memrar/memrar_user.c |  305 ++++++++++++++++++++++++++++++++++
 1 files changed, 305 insertions(+), 0 deletions(-)
 create mode 100644 drivers/staging/memrar/memrar_user.c

diff --git a/drivers/staging/memrar/memrar_user.c b/drivers/staging/memrar/memrar_user.c
new file mode 100644
index 0000000..8936d78
--- /dev/null
+++ b/drivers/staging/memrar/memrar_user.c
@@ -0,0 +1,305 @@
+/*
+ *      memrar_core 1.0:  An Intel restricted access region handler device
+ *
+ *      Copyright (C) 2010 Intel Corporation. All rights reserved.
+ *
+ *      This program is free software; you can redistribute it and/or
+ *      modify it under the terms of version 2 of the GNU General
+ *      Public License as published by the Free Software Foundation.
+ *
+ *      This program is distributed in the hope that it will be
+ *      useful, but WITHOUT ANY WARRANTY; without even the implied
+ *      warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ *      PURPOSE.  See the GNU General Public License for more details.
+ *      You should have received a copy of the GNU General Public
+ *      License along with this program; if not, write to the Free
+ *      Software Foundation, Inc., 59 Temple Place - Suite 330,
+ *      Boston, MA  02111-1307, USA.
+ *      The full GNU General Public License is included in this
+ *      distribution in the file called COPYING.
+ *
+ * -------------------------------------------------------------------
+ *
+ *      Moorestown restricted access regions (RAR) provide isolated
+ *      areas of main memory that are only acceessible by authorized
+ *      devices.
+ *
+ *      The Intel Moorestown RAR handler module exposes a kernel space
+ *      RAR memory management mechanism.  It is essentially a
+ *      RAR-specific allocator.
+ *
+ *      Besides providing RAR buffer management, the RAR handler also
+ *      behaves in many ways like an OS virtual memory manager.  For
+ *      example, the RAR "handles" created by the RAR handler are
+ *      analogous to user space virtual addresses.
+ *
+ *      RAR memory itself is never accessed directly by the RAR
+ *      handler.
+ */
+
+#include <linux/miscdevice.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/kref.h>
+#include <linux/mutex.h>
+#include <linux/kernel.h>
+#include <linux/uaccess.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/io.h>
+#include <linux/rar_register.h>
+
+#include "memrar.h"
+#include "memrar_allocator.h"
+
+
+/*
+ * Moorestown supports three restricted access regions.
+ *
+ * We only care about the first two, video and audio.  The third,
+ * reserved for Chaabi and the P-unit, will be handled by their
+ * respective drivers.
+ */
+#define MRST_NUM_RAR 2
+
+struct memrar_buffer_info; 
+struct memrar_rar_info; 
+static struct memrar_rar_info memrars[MRST_NUM_RAR];
+
+static inline int memrar_is_valid_rar_type(u32 type);
+static inline int memrar_handle_in_range(struct memrar_rar_info *rar,
+					 u32 vaddr);
+static struct memrar_rar_info *memrar_get_rar_info(u32 vaddr);
+static dma_addr_t memrar_get_bus_address(
+	struct memrar_rar_info *rar,
+	u32 vaddr);
+static dma_addr_t memrar_get_physical_address(
+	struct memrar_rar_info *rar,
+	u32 vaddr);
+static void memrar_release_block_i(struct kref *ref);
+static int memrar_init_rar_resources(int rarnum, char const *devname);
+static void memrar_fini_rar_resources(void);
+static long memrar_reserve_block(struct RAR_buffer *request,
+				 struct file *filp);
+static long memrar_release_block(u32 addr);
+static long memrar_get_stat(struct RAR_stat *r);
+static int memrar_mmap(struct file *filp, struct vm_area_struct *vma);
+static int memrar_open(struct inode *inode, struct file *filp);
+static int memrar_release(struct inode *inode, struct file *filp);
+static int memrar_registration_callback(unsigned long rar);
+
+/**
+ *	memrar_ioctl		-	ioctl callback
+ *	@filp: file issuing the request
+ *	@cmd: command
+ *	@arg: pointer to control information
+ *
+ *	Perform one of the ioctls supported by the memrar device
+ */
+
+static long memrar_ioctl(struct file *filp,
+			 unsigned int cmd,
+			 unsigned long arg)
+{
+	void __user *argp = (void __user *)arg;
+	long result = 0;
+
+	struct RAR_buffer buffer;
+	struct RAR_block_info * const request = &buffer.info;
+	struct RAR_stat rar_info;
+	u32 rar_handle;
+
+	switch (cmd) {
+	case RAR_HANDLER_RESERVE:
+		if (copy_from_user(request,
+				   argp,
+				   sizeof(*request)))
+			return -EFAULT;
+
+		result = memrar_reserve_block(&buffer, filp);
+		if (result != 0)
+			return result;
+
+		return copy_to_user(argp, request, sizeof(*request));
+
+	case RAR_HANDLER_RELEASE:
+		if (copy_from_user(&rar_handle,
+				   argp,
+				   sizeof(rar_handle)))
+			return -EFAULT;
+
+		return memrar_release_block(rar_handle);
+
+	case RAR_HANDLER_STAT:
+		if (copy_from_user(&rar_info,
+				   argp,
+				   sizeof(rar_info)))
+			return -EFAULT;
+
+		/*
+		 * Populate the RAR_stat structure based on the RAR
+		 * type given by the user
+		 */
+		if (memrar_get_stat(&rar_info) != 0)
+			return -EINVAL;
+
+		/*
+		 * @todo Do we need to verify destination pointer
+		 *       "argp" is non-zero?  Is that already done by
+		 *       copy_to_user()?
+		 */
+		return copy_to_user(argp,
+				    &rar_info,
+				    sizeof(rar_info)) ? -EFAULT : 0;
+
+	default:
+		return -ENOTTY;
+	}
+
+	return 0;
+}
+
+/**
+ *	rar_reserve		-	reserve RAR memory
+ *	@buffers: buffers to reserve
+ *	@count: number wanted
+ *
+ *	Reserve a series of buffers in the RAR space. Returns the number of
+ *	buffers successfully allocated
+ */
+
+size_t rar_reserve(struct RAR_buffer *buffers, size_t count)
+{
+	struct RAR_buffer * const end =
+		(buffers == NULL ? buffers : buffers + count);
+	struct RAR_buffer *i;
+
+	size_t reserve_count = 0;
+
+	for (i = buffers; i != end; ++i) {
+		if (memrar_reserve_block(i, NULL) == 0)
+			++reserve_count;
+		else
+			i->bus_address = 0;
+	}
+
+	return reserve_count;
+}
+EXPORT_SYMBOL(rar_reserve);
+
+/**
+ *	rar_release		-	return RAR buffers
+ *	@buffers: buffers to release
+ *	@size: size of released block
+ *
+ *	Return a set of buffers to the RAR pool
+ */
+
+size_t rar_release(struct RAR_buffer *buffers, size_t count)
+{
+	struct RAR_buffer * const end =
+		(buffers == NULL ? buffers : buffers + count);
+	struct RAR_buffer *i;
+
+	size_t release_count = 0;
+
+	for (i = buffers; i != end; ++i) {
+		u32 * const handle = &i->info.handle;
+		if (memrar_release_block(*handle) == 0) {
+			/*
+			 * @todo We assume we should do this each time
+			 *       the ref count is decremented.  Should
+			 *       we instead only do this when the ref
+			 *       count has dropped to zero, and the
+			 *       buffer has been completely
+			 *       released/unmapped?
+			 */
+			*handle = 0;
+			++release_count;
+		}
+	}
+
+	return release_count;
+}
+EXPORT_SYMBOL(rar_release);
+
+/**
+ *	rar_handle_to_bus	-	RAR to bus address
+ *	@buffers: RAR buffer structure
+ *	@count: number of buffers to convert
+ *
+ *	Turn a list of RAR handle mappings into actual bus addresses. Note
+ *	that when the device is locked down the bus addresses in question
+ *	are not CPU accessible.
+ */
+
+size_t rar_handle_to_bus(struct RAR_buffer *buffers, size_t count)
+{
+	struct RAR_buffer * const end =
+		(buffers == NULL ? buffers : buffers + count);
+	struct RAR_buffer *i;
+	struct memrar_buffer_info *pos;
+
+	size_t conversion_count = 0;
+
+	/*
+	 * Find all bus addresses corresponding to the given handles.
+	 *
+	 * @todo Not liking this nested loop.  Optimize.
+	 */
+	for (i = buffers; i != end; ++i) {
+		struct memrar_rar_info * const rar =
+			memrar_get_rar_info(i->info.handle);
+
+		/*
+		 * Check if we have a bogus handle, and then continue
+		 * with remaining buffers.
+		 */
+		if (rar == NULL) {
+			i->bus_address = 0;
+			continue;
+		}
+
+		mutex_lock(&rar->lock);
+
+		list_for_each_entry(pos, &rar->buffers.list, list) {
+			struct RAR_block_info * const user_info =
+				&pos->buffer.info;
+
+			/*
+			 * Take into account handle offsets that may
+			 * have been added to the base handle, such as
+			 * in the following scenario:
+			 *
+			 *     u32 handle = base + offset;
+			 *     rar_handle_to_bus(handle);
+			 */
+
+			if (i->info.handle >= user_info->handle
+			    && i->info.handle < (user_info->handle
+						 + user_info->size)) {
+				u32 const offset =
+					i->info.handle - user_info->handle;
+
+				i->info.type = user_info->type;
+				i->info.size = user_info->size - offset;
+				i->bus_address =
+					pos->buffer.bus_address
+					+ offset;
+
+				/* Increment the reference count. */
+				kref_get(&pos->refcount);
+
+				++conversion_count;
+				break;
+			} else {
+				i->bus_address = 0;
+			}
+		}
+
+		mutex_unlock(&rar->lock);
+	}
+
+	return conversion_count;
+}
+EXPORT_SYMBOL(rar_handle_to_bus);
-- 
1.7.0.4




More information about the devel mailing list