Commit 375d65db authored by Alan Cox's avatar Alan Cox Committed by Greg Kroah-Hartman
Browse files

Staging: rar and memrar updates



rar: perform a clean up pass

- Move to a registration model where each RAR is claimed/unclaimed
- Use that to fix the client stuff (one client per RAR so no need to queue stuff)
- Support unregister so drivers can rmmod themselves safely
- Fix locking hang on calling rar lock from rar callback
- Clean up
- Kerneldoc

Folded in the memrar update as Greg asked

- Fix various unload related bugs
- Use the per RAR allocator/deallocator
- Add kerneldoc

Signed-off-by: default avatarAlan Cox <alan@linux.intel.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent a9d26f00
Loading
Loading
Loading
Loading
+264 −205
Original line number Diff line number Diff line
@@ -114,6 +114,7 @@ struct memrar_rar_info {
	struct memrar_allocator *allocator;
	struct memrar_buffer_info buffers;
	struct mutex lock;
	int allocated;	/* True if we own this RAR */
};

/*
@@ -150,7 +151,9 @@ static struct memrar_rar_info *memrar_get_rar_info(u32 vaddr)
	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
@@ -176,7 +179,9 @@ static dma_addr_t memrar_get_bus_address(
	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
@@ -195,8 +200,12 @@ static dma_addr_t memrar_get_physical_address(
	return memrar_get_bus_address(rar, vaddr);
}

/*
 * Core block release code.
/**
 *	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().
@@ -224,10 +233,15 @@ static void memrar_release_block_i(struct kref *ref)
	kfree(node);
}

/*
 * Initialize RAR parameters, such as bus addresses, etc.
/**
 *	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(char const *devname)
static int memrar_init_rar_resources(int rarnum, char const *devname)
{
	/* ---- Sanity Checks ----
	 * 1. RAR bus addresses in both Lincroft and Langwell RAR
@@ -258,16 +272,12 @@ static int memrar_init_rar_resources(char const *devname)
	 */
	static size_t const RAR_BLOCK_SIZE = PAGE_SIZE;

	int z;
	int found_rar = 0;

	BUG_ON(MRST_NUM_RAR != ARRAY_SIZE(memrars));

	for (z = 0; z != MRST_NUM_RAR; ++z) {
	dma_addr_t low, high;
		struct memrar_rar_info * const rar = &memrars[z];
	struct memrar_rar_info * const rar = &memrars[rarnum];

		BUG_ON(!memrar_is_valid_rar_type(z));
	BUG_ON(MRST_NUM_RAR != ARRAY_SIZE(memrars));
	BUG_ON(!memrar_is_valid_rar_type(rarnum));
	BUG_ON(rar->allocated);

	mutex_init(&rar->lock);

@@ -278,19 +288,16 @@ static int memrar_init_rar_resources(char const *devname)
	 */
	INIT_LIST_HEAD(&rar->buffers.list);

		if (rar_get_address(z, &low, &high) != 0) {
	if (rar_get_address(rarnum, &low, &high) != 0)
		/* No RAR is available. */
			break;
		} else if (low == 0 || high == 0) {
			/*
			 * We don't immediately break out of the loop
			 * since the next type of RAR may be enabled.
			 */
		return -ENODEV;
	
	if (low == 0 || high == 0) {
		rar->base      = 0;
		rar->length    = 0;
		rar->iobase    = NULL;
		rar->allocator = NULL;
			continue;
		return -ENOSPC;
	}

	/*
@@ -304,19 +311,9 @@ static int memrar_init_rar_resources(char const *devname)
	/* 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,
			       z);
			pr_err("%s: RAR[%d] disabled.\n", devname, z);

			/*
			 * Rather than break out of the loop by
			 * returning -EBUSY, for example, we may be
			 * able to claim memory of the next RAR region
			 * as our own.
			 */
			continue;
		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;
@@ -335,85 +332,35 @@ static int memrar_init_rar_resources(char const *devname)
	 */
	rar->iobase = ioremap_nocache(rar->base, rar->length);
	if (rar->iobase == NULL) {
			pr_err("%s: Unable to map RAR memory.\n",
			       devname);
		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)
			return -1;

		/*
		 * -------------------------------------------------
		 * Make sure all RARs handled by us are locked down.
		 * -------------------------------------------------
		 */

		/* Enable RAR protection on the Lincroft side. */
		if (0) {
			/*
			 * This is mostly a sanity check since the
			 * vendor should have locked down RAR in the
			 * SMIP header RAR configuration.
			 */
			rar_lock(z);
		} else {
			pr_warning("%s: LNC RAR[%d] no lock sanity check.\n",
				   devname,
				   z);
	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;
	}

		/* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ */
		/* |||||||||||||||||||||||||||||||||||||||||||||||||| */

		/*
		 * It would be nice if we could verify that RAR
		 * protection on the Langwell side is enabled, but
		 * there is no way to do that from here.  The
		 * necessary Langwell RAR registers are not accessible
		 * from the Lincroft (IA) side.
		 *
		 * Hopefully the ODM did the right thing and enabled
		 * Langwell side RAR protection in the integrated
		 * firmware SMIP header.
		 */

		pr_info("%s: BRAR[%d] bus address range = "
			"[0x%lx, 0x%lx]\n",
			devname,
			z,
			(unsigned long) low,
			(unsigned long) high);
	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,
			z,
			rar->allocator->capacity / 1024);

		found_rar = 1;
	}

	if (!found_rar)	{
		/*
		 * No RAR support.  Don't bother continuing.
		 *
		 * Note that this is not a failure.
		 */
		pr_info("%s: No Moorestown RAR support available.\n",
			devname);
		return -ENODEV;
	}
			devname, rarnum, rar->allocator->capacity / 1024);

	rar->allocated = 1;
	return 0;
}

/*
 * Finalize RAR resources.
/**
 *	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)
{
@@ -429,6 +376,9 @@ static void memrar_fini_rar_resources(void)
	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,
@@ -442,15 +392,25 @@ static void memrar_fini_rar_resources(void)
		rar->allocator = NULL;

		iounmap(rar->iobase);
		rar->iobase = NULL;

		release_mem_region(rar->base, rar->length);
		rar->base = 0;

		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)
{
@@ -465,6 +425,8 @@ static long memrar_reserve_block(struct RAR_buffer *request,
		return -EINVAL;

	rar = &memrars[rinfo->type];
	if (!rar->allocated)
		return -ENODEV;

	/* Reserve memory in RAR. */
	handle = memrar_allocator_alloc(rar->allocator, rinfo->size);
@@ -504,6 +466,14 @@ static long memrar_reserve_block(struct RAR_buffer *request,
	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;
@@ -512,7 +482,7 @@ static long memrar_release_block(u32 addr)
	long result = -EINVAL;

	if (rar == NULL)
		return -EFAULT;
		return -ENOENT;

	mutex_lock(&rar->lock);

@@ -550,13 +520,24 @@ static long memrar_release_block(u32 addr)
	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)
{
	long result = -EINVAL;
	struct memrar_allocator *allocator;

	if (likely(r != NULL) && memrar_is_valid_rar_type(r->type)) {
		struct memrar_allocator * const allocator =
			memrars[r->type].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);

@@ -567,16 +548,19 @@ static long memrar_get_stat(struct RAR_stat *r)
	r->capacity = allocator->capacity;

	mutex_lock(&allocator->lock);

	r->largest_block_size = allocator->largest_free_area;

	mutex_unlock(&allocator->lock);

		result = 0;
	return 0;
}

	return result;
}
/**
 *	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,
@@ -640,6 +624,15 @@ static long memrar_ioctl(struct file *filp,
	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)
{
	/*
@@ -660,9 +653,12 @@ static int memrar_mmap(struct file *filp, struct vm_area_struct *vma)
	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
@@ -698,13 +694,32 @@ static int memrar_mmap(struct file *filp, struct vm_area_struct *vma)
	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)
{
	/* Nothing to do yet. */

	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. */
@@ -733,9 +748,15 @@ static int memrar_release(struct inode *inode, struct file *filp)
	return 0;
}

/*
 * This function is part of the kernel space memrar driver API.
/**
 *	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 =
@@ -755,9 +776,14 @@ size_t rar_reserve(struct RAR_buffer *buffers, size_t count)
}
EXPORT_SYMBOL(rar_reserve);

/*
 * This function is part of the kernel space memrar driver API.
/**
 *	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 =
@@ -786,9 +812,16 @@ size_t rar_release(struct RAR_buffer *buffers, size_t count)
}
EXPORT_SYMBOL(rar_release);

/*
 * This function is part of the kernel space driver API.
/**
 *	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 =
@@ -878,43 +911,70 @@ static char const banner[] __initdata =
	KERN_INFO
	"Intel RAR Handler: " MEMRAR_VER " initialized.\n";

static int memrar_registration_callback(void *ctx)
/**
 *	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.
	 */
	int result = memrar_init_rar_resources(memrar_miscdev.name);

	if (result != 0)
		return result;

	result = misc_register(&memrar_miscdev);

	if (result != 0) {
		pr_err("%s: misc_register() failed.\n",
			memrar_miscdev.name);

		/* Clean up resources previously reserved. */
		memrar_fini_rar_resources();
	return memrar_init_rar_resources(rar, memrar_miscdev.name);
}

	return result;
}
/**
 *	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);

	return register_rar(&memrar_registration_callback, 0);
	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)
{
	memrar_fini_rar_resources();

	misc_deregister(&memrar_miscdev);
	memrar_fini_rar_resources();
}


@@ -925,7 +985,6 @@ module_exit(memrar_exit);
MODULE_AUTHOR("Ossama Othman <ossama.othman@intel.com>");
MODULE_DESCRIPTION("Intel Restricted Access Region Handler");
MODULE_LICENSE("GPL");
MODULE_ALIAS_MISCDEV(MISC_DYNAMIC_MINOR);
MODULE_VERSION(MEMRAR_VER);


+335 −275

File changed.

Preview size limit exceeded, changes collapsed.

+11 −51
Original line number Diff line number Diff line
@@ -24,60 +24,20 @@
#include <linux/types.h>

/* following are used both in drivers as well as user space apps */
enum RAR_type {
	RAR_TYPE_VIDEO = 0,
	RAR_TYPE_AUDIO,
	RAR_TYPE_IMAGE,
	RAR_TYPE_DATA
};

#ifdef __KERNEL__
#define	RAR_TYPE_VIDEO	0
#define	RAR_TYPE_AUDIO	1
#define	RAR_TYPE_IMAGE	2
#define	RAR_TYPE_DATA	3

/* PCI device id for controller */
#define PCI_RAR_DEVICE_ID 0x4110
#ifdef __KERNEL__

/* The register_rar function is to used by other device drivers
 * to ensure that this driver is ready. As we cannot be sure of
 * the compile/execute order of dirvers in ther kernel, it is
 * best to give this driver a callback function to call when
 * it is ready to give out addresses. The callback function
 * would have those steps that continue the initialization of
 * a driver that do require a valid RAR address. One of those
 * steps would be to call get_rar_address()
 * This function return 0 on success an -1 on failure.
 */
int register_rar(int (*callback)(void *yourparameter), void *yourparameter);
struct rar_device;

/* The get_rar_address function is used by other device drivers
 * to obtain RAR address information on a RAR. It takes two
 * parameter:
 *
 * int rar_index
 * The rar_index is an index to the rar for which you wish to retrieve
 * the address information.
 * Values can be 0,1, or 2.
 *
 * struct RAR_address_struct is a pointer to a place to which the function
 * can return the address structure for the RAR.
 *
 * The function returns a 0 upon success or a -1 if there is no RAR
 * facility on this system.
 */
int rar_get_address(int rar_index,
		dma_addr_t *start_address,
		dma_addr_t *end_address);

/* The lock_rar function is ued by other device drivers to lock an RAR.
 * once an RAR is locked, it stays locked until the next system reboot.
 * The function takes one parameter:
 *
 * int rar_index
 * The rar_index is an index to the rar that you want to lock.
 * Values can be 0,1, or 2.
 *
 * The function returns a 0 upon success or a -1 if there is no RAR
 * facility on this system.
 */
int register_rar(int num,
		int (*callback)(unsigned long data), unsigned long data);
void unregister_rar(int num);
int rar_get_address(int rar_index, dma_addr_t *start, dma_addr_t *end);
int rar_lock(int rar_index);

#endif  /* __KERNEL__ */