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

Reply via email to