Signed-off-by: Chris McIntosh <[email protected]>
---
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
_______________________________________________
devel mailing list
[email protected]
http://driverdev.linuxdriverproject.org/mailman/listinfo/devel