Signed-off-by: Chris McIntosh <rougechampion2002@xxxxxxxxx> --- 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 devel@xxxxxxxxxxxxxxxxxxxxxx http://driverdev.linuxdriverproject.org/mailman/listinfo/devel