[PATCH 1/4] Staging: memrar: adding memrar_core code Splitting up memrar_handler into memrar_core and memrar_user as requested in TODO

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Signed-off-by: Chris McIntosh <rougechampion2002@xxxxxxxxx>
---
 drivers/staging/memrar/memrar_core.c |  852 ++++++++++++++++++++++++++++++++++
 1 files changed, 852 insertions(+), 0 deletions(-)
 create mode 100644 drivers/staging/memrar/memrar_core.c

diff --git a/drivers/staging/memrar/memrar_core.c b/drivers/staging/memrar/memrar_core.c
new file mode 100644
index 0000000..e3ce40c
--- /dev/null
+++ b/drivers/staging/memrar/memrar_core.c
@@ -0,0 +1,852 @@
+/*
+ *      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"
+
+
+#define MEMRAR_VER "1.0"
+
+/*
+ * 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 that keeps track of all RAR buffers
+ * @list:	Linked list of memrar_buffer_info objects.
+ * @buffer:	Core RAR buffer information.
+ * @refcount:	Reference count.
+ * @owner:	File handle corresponding to process that reserved the
+ *		block of memory in RAR.  This will be zero for buffers
+ *		allocated by other drivers instead of by a user space
+ *		process.
+ *
+ * This structure encapsulates a link list of RAR buffers, as well as
+ * other characteristics specific to a given list node, such as the
+ * reference count on the corresponding RAR buffer.
+ */
+struct memrar_buffer_info {
+	struct list_head list;
+	struct RAR_buffer buffer;
+	struct kref refcount;
+	struct file *owner;
+};
+
+/**
+ * struct memrar_rar_info - characteristics of a given RAR
+ * @base:	Base bus address of the RAR.
+ * @length:	Length of the RAR.
+ * @iobase:	Virtual address of RAR mapped into kernel.
+ * @allocator:	Allocator associated with the RAR.  Note the allocator
+ *		"capacity" may be smaller than the RAR length if the
+ *		length is not a multiple of the configured allocator
+ *		block size.
+ * @buffers:	Table that keeps track of all reserved RAR buffers.
+ * @lock:	Lock used to synchronize access to RAR-specific data
+ *		structures.
+ *
+ * Each RAR has an associated memrar_rar_info structure that describes
+ * where in memory the RAR is located, how large it is, and a list of
+ * reserved RAR buffers inside that RAR.  Each RAR also has a mutex
+ * associated with it to reduce lock contention when operations on
+ * multiple RARs are performed in parallel.
+ */
+struct memrar_rar_info {
+	dma_addr_t base;
+	unsigned long length;
+	void __iomem *iobase;
+	struct memrar_allocator *allocator;
+	struct memrar_buffer_info buffers;
+	struct mutex lock;
+	int allocated;	/* True if we own this RAR */
+};
+
+/*
+ * Array of RAR characteristics.
+ */
+static struct memrar_rar_info memrars[MRST_NUM_RAR];
+
+/* ---------------- -------------------- ------------------- */
+
+/* Validate RAR type. */
+static inline int memrar_is_valid_rar_type(u32 type)
+{
+	return type == RAR_TYPE_VIDEO || type == RAR_TYPE_AUDIO;
+}
+
+/* Check if an address/handle falls with the given RAR memory range. */
+static inline int memrar_handle_in_range(struct memrar_rar_info *rar,
+					 u32 vaddr)
+{
+	unsigned long const iobase = (unsigned long) (rar->iobase);
+	return (vaddr >= iobase && vaddr < iobase + rar->length);
+}
+
+/* Retrieve RAR information associated with the given handle. */
+static struct memrar_rar_info *memrar_get_rar_info(u32 vaddr)
+{
+	int i;
+	for (i = 0; i < MRST_NUM_RAR; ++i) {
+		struct memrar_rar_info * const rar = &memrars[i];
+		if (memrar_handle_in_range(rar, vaddr))
+			return rar;
+	}
+
+	return NULL;
+}
+
+/**
+ *	memrar_get_bus address		-	handle to bus address
+ *
+ *	Retrieve bus address from given handle.
+ *
+ *	Returns address corresponding to given handle.  Zero if handle is
+ *	invalid.
+ */
+static dma_addr_t memrar_get_bus_address(
+	struct memrar_rar_info *rar,
+	u32 vaddr)
+{
+	unsigned long const iobase = (unsigned long) (rar->iobase);
+
+	if (!memrar_handle_in_range(rar, vaddr))
+		return 0;
+
+	/*
+	 * An assumption is made that the virtual address offset is
+	 * the same as the bus address offset, at least based on the
+	 * way this driver is implemented.  For example, vaddr + 2 ==
+	 * baddr + 2.
+	 *
+	 * @todo Is that a valid assumption?
+	 */
+	return rar->base + (vaddr - iobase);
+}
+
+/**
+ *	memrar_get_physical_address	-	handle to physical address
+ *
+ *	Retrieve physical address from given handle.
+ *
+ *	Returns address corresponding to given handle.  Zero if handle is
+ *	invalid.
+ */
+static dma_addr_t memrar_get_physical_address(
+	struct memrar_rar_info *rar,
+	u32 vaddr)
+{
+	/*
+	 * @todo This assumes that the bus address and physical
+	 *       address are the same.  That is true for Moorestown
+	 *       but not necessarily on other platforms.  This
+	 *       deficiency should be addressed at some point.
+	 */
+	return memrar_get_bus_address(rar, vaddr);
+}
+
+/**
+ *	memrar_release_block	-	release a block to the pool
+ *	@kref: kref of block
+ *
+ *	Core block release code. A node has hit zero references so can
+ *	be released and the lists must be updated.
+ *
+ *	Note: This code removes the node from a list.  Make sure any list
+ *	iteration is performed using list_for_each_safe().
+ */
+static void memrar_release_block_i(struct kref *ref)
+{
+	/*
+	 * Last reference is being released.  Remove from the table,
+	 * and reclaim resources.
+	 */
+
+	struct memrar_buffer_info * const node =
+		container_of(ref, struct memrar_buffer_info, refcount);
+
+	struct RAR_block_info * const user_info =
+		&node->buffer.info;
+
+	struct memrar_allocator * const allocator =
+		memrars[user_info->type].allocator;
+
+	list_del(&node->list);
+
+	memrar_allocator_free(allocator, user_info->handle);
+
+	kfree(node);
+}
+
+/**
+ *	memrar_init_rar_resources	-	configure a RAR
+ *	@rarnum: rar that has been allocated
+ *	@devname: name of our device
+ *
+ *	Initialize RAR parameters, such as bus addresses, etc and make
+ *	the resource accessible.
+ */
+static int memrar_init_rar_resources(int rarnum, char const *devname)
+{
+	/* ---- Sanity Checks ----
+	 * 1. RAR bus addresses in both Lincroft and Langwell RAR
+	 *    registers should be the same.
+	 *    a. There's no way we can do this through IA.
+	 *
+	 * 2. Secure device ID in Langwell RAR registers should be set
+	 *    appropriately, e.g. only LPE DMA for the audio RAR, and
+	 *    security for the other Langwell based RAR registers.
+	 *    a. There's no way we can do this through IA.
+	 *
+	 * 3. Audio and video RAR registers and RAR access should be
+	 *    locked down.  If not, enable RAR access control.  Except
+	 *    for debugging purposes, there is no reason for them to
+	 *    be unlocked.
+	 *    a.  We can only do this for the Lincroft (IA) side.
+	 *
+	 * @todo Should the RAR handler driver even be aware of audio
+	 *       and video RAR settings?
+	 */
+
+	/*
+	 * RAR buffer block size.
+	 *
+	 * We choose it to be the size of a page to simplify the
+	 * /dev/memrar mmap() implementation and usage.  Otherwise
+	 * paging is not involved once an RAR is locked down.
+	 */
+	static size_t const RAR_BLOCK_SIZE = PAGE_SIZE;
+
+	dma_addr_t low, high;
+	struct memrar_rar_info * const rar = &memrars[rarnum];
+
+	BUG_ON(MRST_NUM_RAR != ARRAY_SIZE(memrars));
+	BUG_ON(!memrar_is_valid_rar_type(rarnum));
+	BUG_ON(rar->allocated);
+
+	mutex_init(&rar->lock);
+
+	/*
+	 * Initialize the process table before we reach any
+	 * code that exit on failure since the finalization
+	 * code requires an initialized list.
+	 */
+	INIT_LIST_HEAD(&rar->buffers.list);
+
+	if (rar_get_address(rarnum, &low, &high) != 0)
+		/* No RAR is available. */
+		return -ENODEV;
+
+	if (low == 0 || high == 0) {
+		rar->base      = 0;
+		rar->length    = 0;
+		rar->iobase    = NULL;
+		rar->allocator = NULL;
+		return -ENOSPC;
+	}
+
+	/*
+	 * @todo Verify that LNC and LNW RAR register contents
+	 *       addresses, security, etc are compatible and
+	 *       consistent).
+	 */
+
+	rar->length = high - low + 1;
+
+	/* Claim RAR memory as our own. */
+	if (request_mem_region(low, rar->length, devname) == NULL) {
+		rar->length = 0;
+		pr_err("%s: Unable to claim RAR[%d] memory.\n",
+		       devname, rarnum);
+		pr_err("%s: RAR[%d] disabled.\n", devname, rarnum);
+		return -EBUSY;
+	}
+
+	rar->base = low;
+
+	/*
+	 * Now map it into the kernel address space.
+	 *
+	 * Note that the RAR memory may only be accessed by IA
+	 * when debugging.  Otherwise attempts to access the
+	 * RAR memory when it is locked down will result in
+	 * behavior similar to writing to /dev/null and
+	 * reading from /dev/zero.  This behavior is enforced
+	 * by the hardware.  Even if we don't access the
+	 * memory, mapping it into the kernel provides us with
+	 * a convenient RAR handle to bus address mapping.
+	 */
+	rar->iobase = ioremap_nocache(rar->base, rar->length);
+	if (rar->iobase == NULL) {
+		pr_err("%s: Unable to map RAR memory.\n", devname);
+		release_mem_region(low, rar->length);
+		return -ENOMEM;
+	}
+
+	/* Initialize corresponding memory allocator. */
+	rar->allocator = memrar_create_allocator((unsigned long) rar->iobase,
+						rar->length, RAR_BLOCK_SIZE);
+	if (rar->allocator == NULL) {
+		iounmap(rar->iobase);
+		release_mem_region(low, rar->length);
+		return -ENOMEM;
+	}
+
+	pr_info("%s: BRAR[%d] bus address range = [0x%lx, 0x%lx]\n",
+		devname, rarnum, (unsigned long) low, (unsigned long) high);
+
+	pr_info("%s: BRAR[%d] size = %zu KiB\n",
+			devname, rarnum, rar->allocator->capacity / 1024);
+
+	rar->allocated = 1;
+	return 0;
+}
+
+/**
+ *	memrar_fini_rar_resources	-	free up RAR resources
+ *
+ *	Finalize RAR resources. Free up the resource tables, hand the memory
+ *	back to the kernel, unmap the device and release the address space.
+ */
+static void memrar_fini_rar_resources(void)
+{
+	int z;
+	struct memrar_buffer_info *pos;
+	struct memrar_buffer_info *tmp;
+
+	/*
+	 * @todo Do we need to hold a lock at this point in time?
+	 *       (module initialization failure or exit?)
+	 */
+
+	for (z = MRST_NUM_RAR; z-- != 0; ) {
+		struct memrar_rar_info * const rar = &memrars[z];
+
+		if (!rar->allocated)
+			continue;
+
+		/* Clean up remaining resources. */
+
+		list_for_each_entry_safe(pos,
+					 tmp,
+					 &rar->buffers.list,
+					 list) {
+			kref_put(&pos->refcount, memrar_release_block_i);
+		}
+
+		memrar_destroy_allocator(rar->allocator);
+		rar->allocator = NULL;
+
+		iounmap(rar->iobase);
+		release_mem_region(rar->base, rar->length);
+
+		rar->iobase = NULL;
+		rar->base = 0;
+		rar->length = 0;
+
+		unregister_rar(z);
+	}
+}
+
+/**
+ *	memrar_reserve_block	-	handle an allocation request
+ *	@request: block being requested
+ *	@filp: owner it is tied to
+ *
+ *	Allocate a block of the requested RAR. If successful return the
+ *	request object filled in and zero, if not report an error code
+ */
+
+static long memrar_reserve_block(struct RAR_buffer *request,
+				 struct file *filp)
+{
+	struct RAR_block_info * const rinfo = &request->info;
+	struct RAR_buffer *buffer;
+	struct memrar_buffer_info *buffer_info;
+	u32 handle;
+	struct memrar_rar_info *rar = NULL;
+
+	/* Prevent array overflow. */
+	if (!memrar_is_valid_rar_type(rinfo->type))
+		return -EINVAL;
+
+	rar = &memrars[rinfo->type];
+	if (!rar->allocated)
+		return -ENODEV;
+
+	/* Reserve memory in RAR. */
+	handle = memrar_allocator_alloc(rar->allocator, rinfo->size);
+	if (handle == 0)
+		return -ENOMEM;
+
+	buffer_info = kmalloc(sizeof(*buffer_info), GFP_KERNEL);
+
+	if (buffer_info == NULL) {
+		memrar_allocator_free(rar->allocator, handle);
+		return -ENOMEM;
+	}
+
+	buffer = &buffer_info->buffer;
+	buffer->info.type = rinfo->type;
+	buffer->info.size = rinfo->size;
+
+	/* Memory handle corresponding to the bus address. */
+	buffer->info.handle = handle;
+	buffer->bus_address = memrar_get_bus_address(rar, handle);
+
+	/*
+	 * Keep track of owner so that we can later cleanup if
+	 * necessary.
+	 */
+	buffer_info->owner = filp;
+
+	kref_init(&buffer_info->refcount);
+
+	mutex_lock(&rar->lock);
+	list_add(&buffer_info->list, &rar->buffers.list);
+	mutex_unlock(&rar->lock);
+
+	rinfo->handle = buffer->info.handle;
+	request->bus_address = buffer->bus_address;
+
+	return 0;
+}
+
+/**
+ *	memrar_release_block		-	release a RAR block
+ *	@addr: address in RAR space
+ *
+ *	Release a previously allocated block. Releases act on complete
+ *	blocks, partially freeing a block is not supported
+ */
+
+static long memrar_release_block(u32 addr)
+{
+	struct memrar_buffer_info *pos;
+	struct memrar_buffer_info *tmp;
+	struct memrar_rar_info * const rar = memrar_get_rar_info(addr);
+	long result = -EINVAL;
+
+	if (rar == NULL)
+		return -ENOENT;
+
+	mutex_lock(&rar->lock);
+
+	/*
+	 * Iterate through the buffer list to find the corresponding
+	 * buffer to be released.
+	 */
+	list_for_each_entry_safe(pos,
+				 tmp,
+				 &rar->buffers.list,
+				 list) {
+		struct RAR_block_info * const 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);
+		 *     rar_release(handle);
+		 */
+		if (addr >= info->handle
+		    && addr < (info->handle + info->size)
+		    && memrar_is_valid_rar_type(info->type)) {
+			kref_put(&pos->refcount, memrar_release_block_i);
+			result = 0;
+			break;
+		}
+	}
+
+	mutex_unlock(&rar->lock);
+
+	return result;
+}
+
+/**
+ *	memrar_get_stats	-	read statistics for a RAR
+ *	@r: statistics to be filled in
+ *
+ *	Returns the statistics data for the RAR, or an error code if
+ *	the request cannot be completed
+ */
+static long memrar_get_stat(struct RAR_stat *r)
+{
+	struct memrar_allocator *allocator;
+
+	if (!memrar_is_valid_rar_type(r->type))
+		return -EINVAL;
+
+	if (!memrars[r->type].allocated)
+		return -ENODEV;
+
+	allocator = memrars[r->type].allocator;
+
+	BUG_ON(allocator == NULL);
+
+	/*
+	 * Allocator capacity doesn't change over time.  No
+	 * need to synchronize.
+	 */
+	r->capacity = allocator->capacity;
+
+	mutex_lock(&allocator->lock);
+	r->largest_block_size = allocator->largest_free_area;
+	mutex_unlock(&allocator->lock);
+	return 0;
+}
+
+
+/**
+ *	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;
+}
+
+/**
+ *	memrar_mmap		-	mmap helper for deubgging
+ *	@filp: handle doing the mapping
+ *	@vma: memory area
+ *
+ *	Support the mmap operation on the RAR space for debugging systems
+ *	when the memory is not locked down.
+ */
+
+static int memrar_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+	/*
+	 * This mmap() implementation is predominantly useful for
+	 * debugging since the CPU will be prevented from accessing
+	 * RAR memory by the hardware when RAR is properly locked
+	 * down.
+	 *
+	 * In order for this implementation to be useful RAR memory
+	 * must be not be locked down.  However, we only want to do
+	 * that when debugging.  DO NOT leave RAR memory unlocked in a
+	 * deployed device that utilizes RAR.
+	 */
+
+	size_t const size = vma->vm_end - vma->vm_start;
+
+	/* Users pass the RAR handle as the mmap() offset parameter. */
+	unsigned long const handle = vma->vm_pgoff << PAGE_SHIFT;
+
+	struct memrar_rar_info * const rar = memrar_get_rar_info(handle);
+	unsigned long pfn;
+
+	/* Only allow priviledged apps to go poking around this way */
+	if (!capable(CAP_SYS_RAWIO))
+		return -EPERM;
+
+	/* Invalid RAR handle or size passed to mmap(). */
+	if (rar == NULL
+	    || handle == 0
+	    || size > (handle - (unsigned long) rar->iobase))
+		return -EINVAL;
+
+	/*
+	 * Retrieve physical address corresponding to the RAR handle,
+	 * and convert it to a page frame.
+	 */
+	pfn = memrar_get_physical_address(rar, handle) >> PAGE_SHIFT;
+
+
+	pr_debug("memrar: mapping RAR range [0x%lx, 0x%lx) into user space.\n",
+		 handle,
+		 handle + size);
+
+	/*
+	 * Map RAR memory into user space.  This is really only useful
+	 * for debugging purposes since the memory won't be
+	 * accessible, i.e. reads return zero and writes are ignored,
+	 * when RAR access control is enabled.
+	 */
+	if (remap_pfn_range(vma,
+			    vma->vm_start,
+			    pfn,
+			    size,
+			    vma->vm_page_prot))
+		return -EAGAIN;
+
+	/* vma->vm_ops = &memrar_mem_ops; */
+
+	return 0;
+}
+
+/**
+ *	memrar_open		-	device open method
+ *	@inode: inode to open
+ *	@filp: file handle
+ *
+ *	As we support multiple arbitary opens there is no work to be done
+ *	really.
+ */
+
+static int memrar_open(struct inode *inode, struct file *filp)
+{
+	nonseekable_open(inode, filp);
+	return 0;
+}
+
+/**
+ *	memrar_release		-	close method for miscev
+ *	@inode: inode of device
+ *	@filp: handle that is going away
+ *
+ *	Free up all the regions that belong to this file handle. We use
+ *	the handle as a natural Linux style 'lifetime' indicator and to
+ *	ensure resources are not leaked when their owner explodes in an
+ *	unplanned fashion.
+ */
+
+static int memrar_release(struct inode *inode, struct file *filp)
+{
+	/* Free all regions associated with the given file handle. */
+
+	struct memrar_buffer_info *pos;
+	struct memrar_buffer_info *tmp;
+	int z;
+
+	for (z = 0; z != MRST_NUM_RAR; ++z) {
+		struct memrar_rar_info * const rar = &memrars[z];
+
+		mutex_lock(&rar->lock);
+
+		list_for_each_entry_safe(pos,
+					 tmp,
+					 &rar->buffers.list,
+					 list) {
+			if (filp == pos->owner)
+				kref_put(&pos->refcount,
+					 memrar_release_block_i);
+		}
+
+		mutex_unlock(&rar->lock);
+	}
+
+	return 0;
+}
+
+static const struct file_operations memrar_fops = {
+	.owner = THIS_MODULE,
+	.unlocked_ioctl = memrar_ioctl,
+	.mmap           = memrar_mmap,
+	.open           = memrar_open,
+	.release        = memrar_release,
+};
+
+static struct miscdevice memrar_miscdev = {
+	.minor = MISC_DYNAMIC_MINOR,    /* dynamic allocation */
+	.name = "memrar",               /* /dev/memrar */
+	.fops = &memrar_fops
+};
+
+static char const banner[] __initdata =
+	KERN_INFO
+	"Intel RAR Handler: " MEMRAR_VER " initialized.\n";
+
+/**
+ *	memrar_registration_callback	-	RAR obtained
+ *	@rar: RAR number
+ *
+ *	We have been granted ownership of the RAR. Add it to our memory
+ *	management tables
+ */
+
+static int memrar_registration_callback(unsigned long rar)
+{
+	/*
+	 * We initialize the RAR parameters early on so that we can
+	 * discontinue memrar device initialization and registration
+	 * if suitably configured RARs are not available.
+	 */
+	return memrar_init_rar_resources(rar, memrar_miscdev.name);
+}
+
+/**
+ *	memrar_init	-	initialise RAR support
+ *
+ *	Initialise support for RAR handlers. This may get loaded before
+ *	the RAR support is activated, but the callbacks on the registration
+ *	will handle that situation for us anyway.
+ */
+
+static int __init memrar_init(void)
+{
+	int err;
+
+	printk(banner);
+
+	err = misc_register(&memrar_miscdev);
+	if (err)
+		return err;
+
+	/* Now claim the two RARs we want */
+	err = register_rar(0, memrar_registration_callback, 0);
+	if (err)
+		goto fail;
+
+	err = register_rar(1, memrar_registration_callback, 1);
+	if (err == 0)
+		return 0;
+
+	/* It is possible rar 0 registered and allocated resources then rar 1
+	   failed so do a full resource free */
+	memrar_fini_rar_resources();
+fail:
+	misc_deregister(&memrar_miscdev);
+	return err;
+}
+
+/**
+ *	memrar_exit	-	unregister and unload
+ *
+ *	Unregister the device and then unload any mappings and release
+ *	the RAR resources
+ */
+
+static void __exit memrar_exit(void)
+{
+	misc_deregister(&memrar_miscdev);
+	memrar_fini_rar_resources();
+}
+
+
+module_init(memrar_init);
+module_exit(memrar_exit);
+
+
+MODULE_AUTHOR("Ossama Othman <ossama.othman@xxxxxxxxx>");
+MODULE_DESCRIPTION("Intel Restricted Access Region Handler");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(MEMRAR_VER);
+
+
+
+/*
+  Local Variables:
+    c-file-style: "linux"
+  End:
+*/
-- 
1.7.0.4

_______________________________________________
devel mailing list
devel@xxxxxxxxxxxxxxxxxxxxxx
http://driverdev.linuxdriverproject.org/mailman/listinfo/devel


[Index of Archives]     [Linux Driver Backports]     [DMA Engine]     [Linux GPIO]     [Linux SPI]     [Video for Linux]     [Linux USB Devel]     [Linux Coverity]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]
  Powered by Linux