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: Alan Cox <alan@linux.intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
parent
a9d26f00b8
commit
375d65db27
|
@ -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,11 +151,13 @@ static struct memrar_rar_info *memrar_get_rar_info(u32 vaddr)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Retrieve bus address from given handle.
|
||||
/**
|
||||
* memrar_get_bus address - handle to bus address
|
||||
*
|
||||
* Returns address corresponding to given handle. Zero if handle is
|
||||
* invalid.
|
||||
* 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,
|
||||
|
@ -176,11 +179,13 @@ static dma_addr_t memrar_get_bus_address(
|
|||
return rar->base + (vaddr - iobase);
|
||||
}
|
||||
|
||||
/*
|
||||
* Retrieve physical address from given handle.
|
||||
/**
|
||||
* memrar_get_physical_address - handle to physical address
|
||||
*
|
||||
* Returns address corresponding to given handle. Zero if handle is
|
||||
* invalid.
|
||||
* 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,
|
||||
|
@ -195,11 +200,15 @@ 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
|
||||
*
|
||||
* Note: This code removes the node from a list. Make sure any list
|
||||
* iteration is performed using list_for_each_safe().
|
||||
* 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)
|
||||
{
|
||||
|
@ -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,162 +272,95 @@ static int memrar_init_rar_resources(char const *devname)
|
|||
*/
|
||||
static size_t const RAR_BLOCK_SIZE = PAGE_SIZE;
|
||||
|
||||
int z;
|
||||
int found_rar = 0;
|
||||
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);
|
||||
|
||||
for (z = 0; z != MRST_NUM_RAR; ++z) {
|
||||
dma_addr_t low, high;
|
||||
struct memrar_rar_info * const rar = &memrars[z];
|
||||
mutex_init(&rar->lock);
|
||||
|
||||
BUG_ON(!memrar_is_valid_rar_type(z));
|
||||
/*
|
||||
* 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);
|
||||
|
||||
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(z, &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.
|
||||
*/
|
||||
rar->base = 0;
|
||||
rar->length = 0;
|
||||
rar->iobase = NULL;
|
||||
rar->allocator = NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* @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,
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
||||
/* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ */
|
||||
/* |||||||||||||||||||||||||||||||||||||||||||||||||| */
|
||||
|
||||
/*
|
||||
* 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] 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);
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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,34 +520,48 @@ 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;
|
||||
|
||||
BUG_ON(allocator == NULL);
|
||||
if (!memrars[r->type].allocated)
|
||||
return -ENODEV;
|
||||
|
||||
/*
|
||||
* Allocator capacity doesn't change over time. No
|
||||
* need to synchronize.
|
||||
*/
|
||||
r->capacity = allocator->capacity;
|
||||
allocator = memrars[r->type].allocator;
|
||||
|
||||
mutex_lock(&allocator->lock);
|
||||
BUG_ON(allocator == NULL);
|
||||
|
||||
r->largest_block_size = allocator->largest_free_area;
|
||||
/*
|
||||
* Allocator capacity doesn't change over time. No
|
||||
* need to synchronize.
|
||||
*/
|
||||
r->capacity = allocator->capacity;
|
||||
|
||||
mutex_unlock(&allocator->lock);
|
||||
|
||||
result = 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
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)
|
||||
|
@ -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 result;
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
|
||||
|
|
|
@ -51,98 +51,159 @@
|
|||
#include <linux/kernel.h>
|
||||
|
||||
/* === Lincroft Message Bus Interface === */
|
||||
/* Message Control Register */
|
||||
#define LNC_MCR_OFFSET 0xD0
|
||||
|
||||
/* Maximum number of clients (other drivers using this driver) */
|
||||
#define MAX_RAR_CLIENTS 10
|
||||
|
||||
/* Message Data Register */
|
||||
#define LNC_MDR_OFFSET 0xD4
|
||||
#define LNC_MCR_OFFSET 0xD0 /* Message Control Register */
|
||||
#define LNC_MDR_OFFSET 0xD4 /* Message Data Register */
|
||||
|
||||
/* Message Opcodes */
|
||||
#define LNC_MESSAGE_READ_OPCODE 0xD0
|
||||
#define LNC_MESSAGE_READ_OPCODE 0xD0
|
||||
#define LNC_MESSAGE_WRITE_OPCODE 0xE0
|
||||
|
||||
/* Message Write Byte Enables */
|
||||
#define LNC_MESSAGE_BYTE_WRITE_ENABLES 0xF
|
||||
#define LNC_MESSAGE_BYTE_WRITE_ENABLES 0xF
|
||||
|
||||
/* B-unit Port */
|
||||
#define LNC_BUNIT_PORT 0x3
|
||||
#define LNC_BUNIT_PORT 0x3
|
||||
|
||||
/* === Lincroft B-Unit Registers - Programmed by IA32 firmware === */
|
||||
#define LNC_BRAR0L 0x10
|
||||
#define LNC_BRAR0H 0x11
|
||||
#define LNC_BRAR1L 0x12
|
||||
#define LNC_BRAR1H 0x13
|
||||
|
||||
#define LNC_BRAR0L 0x10
|
||||
#define LNC_BRAR0H 0x11
|
||||
#define LNC_BRAR1L 0x12
|
||||
#define LNC_BRAR1H 0x13
|
||||
/* Reserved for SeP */
|
||||
#define LNC_BRAR2L 0x14
|
||||
#define LNC_BRAR2H 0x15
|
||||
#define LNC_BRAR2L 0x14
|
||||
#define LNC_BRAR2H 0x15
|
||||
|
||||
/* Moorestown supports three restricted access regions. */
|
||||
#define MRST_NUM_RAR 3
|
||||
|
||||
|
||||
/* RAR Bus Address Range */
|
||||
struct RAR_address_range {
|
||||
struct rar_addr {
|
||||
dma_addr_t low;
|
||||
dma_addr_t high;
|
||||
};
|
||||
|
||||
/* Structure containing low and high RAR register offsets. */
|
||||
struct RAR_offsets {
|
||||
u32 low; /* Register offset for low RAR bus address. */
|
||||
u32 high; /* Register offset for high RAR bus address. */
|
||||
};
|
||||
|
||||
/*
|
||||
* We create one of these for each RAR
|
||||
*/
|
||||
struct client {
|
||||
int (*client_callback)(void *client_data);
|
||||
void *customer_data;
|
||||
int client_called;
|
||||
};
|
||||
int (*callback)(unsigned long data);
|
||||
unsigned long driver_priv;
|
||||
bool busy;
|
||||
};
|
||||
|
||||
static DEFINE_MUTEX(rar_mutex);
|
||||
static DEFINE_MUTEX(lnc_reg_mutex);
|
||||
|
||||
struct RAR_device {
|
||||
struct RAR_offsets const rar_offsets[MRST_NUM_RAR];
|
||||
struct RAR_address_range rar_addr[MRST_NUM_RAR];
|
||||
/*
|
||||
* One per RAR device (currently only one device)
|
||||
*/
|
||||
struct rar_device {
|
||||
struct rar_addr rar_addr[MRST_NUM_RAR];
|
||||
struct pci_dev *rar_dev;
|
||||
bool registered;
|
||||
};
|
||||
|
||||
/* this platform has only one rar_device for 3 rar regions */
|
||||
static struct RAR_device my_rar_device = {
|
||||
.rar_offsets = {
|
||||
[0].low = LNC_BRAR0L,
|
||||
[0].high = LNC_BRAR0H,
|
||||
[1].low = LNC_BRAR1L,
|
||||
[1].high = LNC_BRAR1H,
|
||||
[2].low = LNC_BRAR2L,
|
||||
[2].high = LNC_BRAR2H
|
||||
}
|
||||
bool allocated;
|
||||
struct client client[MRST_NUM_RAR];
|
||||
};
|
||||
|
||||
/* this data is for handling requests from other drivers which arrive
|
||||
* prior to this driver initializing
|
||||
*/
|
||||
|
||||
static struct client clients[MAX_RAR_CLIENTS];
|
||||
static int num_clients;
|
||||
/* Current platforms have only one rar_device for 3 rar regions */
|
||||
static struct rar_device my_rar_device;
|
||||
|
||||
/*
|
||||
* This function is used to retrieved RAR info using the Lincroft
|
||||
* message bus interface.
|
||||
* Abstract out multiple device support. Current platforms only
|
||||
* have a single RAR device.
|
||||
*/
|
||||
static int retrieve_rar_addr(struct pci_dev *pdev,
|
||||
int offset,
|
||||
dma_addr_t *addr)
|
||||
|
||||
/**
|
||||
* alloc_rar_device - return a new RAR structure
|
||||
*
|
||||
* Return a new (but not yet ready) RAR device object
|
||||
*/
|
||||
static struct rar_device *alloc_rar_device(void)
|
||||
{
|
||||
if (my_rar_device.allocated)
|
||||
return NULL;
|
||||
my_rar_device.allocated = 1;
|
||||
return &my_rar_device;
|
||||
}
|
||||
|
||||
/**
|
||||
* free_rar_device - free a RAR object
|
||||
* @rar: the RAR device being freed
|
||||
*
|
||||
* Release a RAR object and any attached resources
|
||||
*/
|
||||
static void free_rar_device(struct rar_device *rar)
|
||||
{
|
||||
pci_dev_put(rar->rar_dev);
|
||||
rar->allocated = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* _rar_to_device - return the device handling this RAR
|
||||
* @rar: RAR number
|
||||
* @off: returned offset
|
||||
*
|
||||
* Internal helper for looking up RAR devices. This and alloc are the
|
||||
* two functions that need touching to go to multiple RAR devices.
|
||||
*/
|
||||
static struct rar_device *_rar_to_device(int rar, int *off)
|
||||
{
|
||||
if (rar >= 0 && rar <= 3) {
|
||||
*off = rar;
|
||||
return &my_rar_device;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* rar_to_device - return the device handling this RAR
|
||||
* @rar: RAR number
|
||||
* @off: returned offset
|
||||
*
|
||||
* Return the device this RAR maps to if one is present, otherwise
|
||||
* returns NULL. Reports the offset relative to the base of this
|
||||
* RAR device in off.
|
||||
*/
|
||||
static struct rar_device *rar_to_device(int rar, int *off)
|
||||
{
|
||||
struct rar_device *rar_dev = _rar_to_device(rar, off);
|
||||
if (rar_dev == NULL || !rar_dev->registered)
|
||||
return NULL;
|
||||
return rar_dev;
|
||||
}
|
||||
|
||||
/**
|
||||
* rar_to_client - return the client handling this RAR
|
||||
* @rar: RAR number
|
||||
*
|
||||
* Return the client this RAR maps to if a mapping is known, otherwise
|
||||
* returns NULL.
|
||||
*/
|
||||
static struct client *rar_to_client(int rar)
|
||||
{
|
||||
int idx;
|
||||
struct rar_device *r = _rar_to_device(rar, &idx);
|
||||
if (r != NULL)
|
||||
return &r->client[idx];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* rar_read_addr - retrieve a RAR mapping
|
||||
* @pdev: PCI device for the RAR
|
||||
* @offset: offset for message
|
||||
* @addr: returned address
|
||||
*
|
||||
* Reads the address of a given RAR register. Returns 0 on success
|
||||
* or an error code on failure.
|
||||
*/
|
||||
static int rar_read_addr(struct pci_dev *pdev, int offset, dma_addr_t *addr)
|
||||
{
|
||||
/*
|
||||
* ======== The Lincroft Message Bus Interface ========
|
||||
* Lincroft registers may be obtained from the PCI
|
||||
* (the Host Bridge) using the Lincroft Message Bus
|
||||
* Lincroft registers may be obtained via PCI from
|
||||
* the host bridge using the Lincroft Message Bus
|
||||
* Interface. That message bus interface is generally
|
||||
* comprised of two registers: a control register (MCR, 0xDO)
|
||||
* and a data register (MDR, 0xD4).
|
||||
|
@ -182,6 +243,7 @@ static int retrieve_rar_addr(struct pci_dev *pdev,
|
|||
*/
|
||||
|
||||
int result;
|
||||
u32 addr32;
|
||||
|
||||
/* Construct control message */
|
||||
u32 const message =
|
||||
|
@ -192,11 +254,6 @@ static int retrieve_rar_addr(struct pci_dev *pdev,
|
|||
|
||||
dev_dbg(&pdev->dev, "Offset for 'get' LNC MSG is %x\n", offset);
|
||||
|
||||
if (addr == 0) {
|
||||
WARN_ON(1);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* We synchronize access to the Lincroft MCR and MDR registers
|
||||
* until BOTH the command is issued through the MCR register
|
||||
|
@ -209,26 +266,25 @@ static int retrieve_rar_addr(struct pci_dev *pdev,
|
|||
|
||||
/* Send the control message */
|
||||
result = pci_write_config_dword(pdev, LNC_MCR_OFFSET, message);
|
||||
|
||||
dev_dbg(&pdev->dev, "Result from send ctl register is %x\n", result);
|
||||
|
||||
if (!result) {
|
||||
result = pci_read_config_dword(pdev, LNC_MDR_OFFSET,
|
||||
(u32 *)addr);
|
||||
dev_dbg(&pdev->dev,
|
||||
"Result from read data register is %x\n", result);
|
||||
|
||||
dev_dbg(&pdev->dev,
|
||||
"Value read from data register is %lx\n",
|
||||
(unsigned long)*addr);
|
||||
/* Read back the address as a 32bit value */
|
||||
result = pci_read_config_dword(pdev, LNC_MDR_OFFSET, &addr32);
|
||||
*addr = (dma_addr_t)addr32;
|
||||
}
|
||||
|
||||
mutex_unlock(&lnc_reg_mutex);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static int set_rar_address(struct pci_dev *pdev,
|
||||
/**
|
||||
* rar_set_addr - Set a RAR mapping
|
||||
* @pdev: PCI device for the RAR
|
||||
* @offset: offset for message
|
||||
* @addr: address to set
|
||||
*
|
||||
* Sets the address of a given RAR register. Returns 0 on success
|
||||
* or an error code on failure.
|
||||
*/
|
||||
static int rar_set_addr(struct pci_dev *pdev,
|
||||
int offset,
|
||||
dma_addr_t addr)
|
||||
{
|
||||
|
@ -236,11 +292,11 @@ static int set_rar_address(struct pci_dev *pdev,
|
|||
* Data being written to this register must be written before
|
||||
* writing the appropriate control message to the MCR
|
||||
* register.
|
||||
* @note See rar_get_address() for a description of the
|
||||
* See rar_get_addrs() for a description of the
|
||||
* message bus interface being used here.
|
||||
*/
|
||||
|
||||
int result = 0;
|
||||
int result;
|
||||
|
||||
/* Construct control message */
|
||||
u32 const message = (LNC_MESSAGE_WRITE_OPCODE << 24)
|
||||
|
@ -248,13 +304,6 @@ static int set_rar_address(struct pci_dev *pdev,
|
|||
| (offset << 8)
|
||||
| (LNC_MESSAGE_BYTE_WRITE_ENABLES << 4);
|
||||
|
||||
if (addr == 0) {
|
||||
WARN_ON(1);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dev_dbg(&pdev->dev, "Offset for 'set' LNC MSG is %x\n", offset);
|
||||
|
||||
/*
|
||||
* We synchronize access to the Lincroft MCR and MDR registers
|
||||
* until BOTH the command is issued through the MCR register
|
||||
|
@ -267,32 +316,27 @@ static int set_rar_address(struct pci_dev *pdev,
|
|||
|
||||
/* Send the control message */
|
||||
result = pci_write_config_dword(pdev, LNC_MDR_OFFSET, addr);
|
||||
|
||||
dev_dbg(&pdev->dev, "Result from write data register is %x\n", result);
|
||||
|
||||
if (!result) {
|
||||
dev_dbg(&pdev->dev,
|
||||
"Value written to data register is %lx\n",
|
||||
(unsigned long)addr);
|
||||
|
||||
if (!result)
|
||||
/* And address */
|
||||
result = pci_write_config_dword(pdev, LNC_MCR_OFFSET, message);
|
||||
|
||||
dev_dbg(&pdev->dev, "Result from send ctl register is %x\n",
|
||||
result);
|
||||
}
|
||||
|
||||
mutex_unlock(&lnc_reg_mutex);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize RAR parameters, such as bus addresses, etc.
|
||||
*/
|
||||
static int init_rar_params(struct pci_dev *pdev)
|
||||
* rar_init_params - Initialize RAR parameters
|
||||
* @rar: RAR device to initialise
|
||||
*
|
||||
* Initialize RAR parameters, such as bus addresses, etc. Returns 0
|
||||
* on success, or an error code on failure.
|
||||
*/
|
||||
static int init_rar_params(struct rar_device *rar)
|
||||
{
|
||||
struct pci_dev *pdev = rar->rar_dev;
|
||||
unsigned int i;
|
||||
int result = 0;
|
||||
int offset = 0x10; /* RAR 0 to 2 in order low/high/low/high/... */
|
||||
|
||||
/* Retrieve RAR start and end bus addresses.
|
||||
* Access the RAR registers through the Lincroft Message Bus
|
||||
|
@ -300,15 +344,16 @@ static int init_rar_params(struct pci_dev *pdev)
|
|||
*/
|
||||
|
||||
for (i = 0; i < MRST_NUM_RAR; ++i) {
|
||||
struct RAR_offsets const *offset =
|
||||
&my_rar_device.rar_offsets[i];
|
||||
struct RAR_address_range *addr = &my_rar_device.rar_addr[i];
|
||||
struct rar_addr *addr = &rar->rar_addr[i];
|
||||
|
||||
result = rar_read_addr(pdev, offset++, &addr->low);
|
||||
if (result != 0)
|
||||
return result;
|
||||
|
||||
result = rar_read_addr(pdev, offset++, &addr->high);
|
||||
if (result != 0)
|
||||
return result;
|
||||
|
||||
if ((retrieve_rar_addr(pdev, offset->low, &addr->low) != 0)
|
||||
|| (retrieve_rar_addr(pdev, offset->high, &addr->high) != 0)) {
|
||||
result = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Only the upper 22 bits of the RAR addresses are
|
||||
|
@ -336,201 +381,237 @@ static int init_rar_params(struct pci_dev *pdev)
|
|||
/* Done accessing the device. */
|
||||
|
||||
if (result == 0) {
|
||||
int z;
|
||||
for (z = 0; z != MRST_NUM_RAR; ++z) {
|
||||
for (i = 0; i != MRST_NUM_RAR; ++i) {
|
||||
/*
|
||||
* "BRAR" refers to the RAR registers in the
|
||||
* Lincroft B-unit.
|
||||
*/
|
||||
dev_info(&pdev->dev, "BRAR[%u] bus address range = "
|
||||
"[%lx, %lx]\n", z,
|
||||
(unsigned long)my_rar_device.rar_addr[z].low,
|
||||
(unsigned long)my_rar_device.rar_addr[z].high);
|
||||
"[%lx, %lx]\n", i,
|
||||
(unsigned long)rar->rar_addr[i].low,
|
||||
(unsigned long)rar->rar_addr[i].high);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* The rar_get_address function is used by other device drivers
|
||||
* to obtain RAR address information on a RAR. It takes three
|
||||
* parameters:
|
||||
/**
|
||||
* rar_get_address - get the bus address in a RAR
|
||||
* @start: return value of start address of block
|
||||
* @end: return value of end address of block
|
||||
*
|
||||
* 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.
|
||||
* The rar_get_address function is used by other device drivers
|
||||
* to obtain RAR address information on a RAR. It takes three
|
||||
* parameters:
|
||||
*
|
||||
* The function returns a 0 upon success or a -1 if there is no RAR
|
||||
* facility on this system.
|
||||
* The function returns a 0 upon success or an error 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)
|
||||
int rar_get_address(int rar_index, dma_addr_t *start, dma_addr_t *end)
|
||||
{
|
||||
int result = -ENODEV;
|
||||
int idx;
|
||||
struct rar_device *rar = rar_to_device(rar_index, &idx);
|
||||
|
||||
if (my_rar_device.registered) {
|
||||
if (start_address == 0 || end_address == 0
|
||||
|| rar_index >= MRST_NUM_RAR || rar_index < 0) {
|
||||
result = -EINVAL;
|
||||
} else {
|
||||
*start_address =
|
||||
my_rar_device.rar_addr[rar_index].low;
|
||||
*end_address =
|
||||
my_rar_device.rar_addr[rar_index].high;
|
||||
|
||||
result = 0;
|
||||
}
|
||||
if (rar == NULL) {
|
||||
WARN_ON(1);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return result;
|
||||
*start = rar->rar_addr[idx].low;
|
||||
*end = rar->rar_addr[idx].high;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(rar_get_address);
|
||||
|
||||
/*
|
||||
* The rar_lock 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:
|
||||
/**
|
||||
* rar_lock - lock a RAR register
|
||||
* @rar_index: RAR to lock (0-2)
|
||||
*
|
||||
* 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 rar_lock function is ued by other device drivers to lock an RAR.
|
||||
* once a RAR is locked, it stays locked until the next system reboot.
|
||||
*
|
||||
* The function returns a 0 upon success or a -1 if there is no RAR
|
||||
* facility on this system.
|
||||
* The function returns a 0 upon success or an error if there is no RAR
|
||||
* facility on this system, or the locking fails
|
||||
*/
|
||||
int rar_lock(int rar_index)
|
||||
{
|
||||
int result = -ENODEV;
|
||||
struct rar_device *rar;
|
||||
int result;
|
||||
int idx;
|
||||
dma_addr_t low, high;
|
||||
|
||||
if (rar_index >= MRST_NUM_RAR || rar_index < 0) {
|
||||
result = -EINVAL;
|
||||
return result;
|
||||
rar = rar_to_device(rar_index, &idx);
|
||||
|
||||
if (rar == NULL) {
|
||||
WARN_ON(1);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dev_dbg(&my_rar_device.rar_dev->dev, "rar_lock mutex locking\n");
|
||||
mutex_lock(&rar_mutex);
|
||||
low = rar->rar_addr[idx].low & 0xfffffc00u;
|
||||
high = rar->rar_addr[idx].high & 0xfffffc00u;
|
||||
|
||||
if (my_rar_device.registered) {
|
||||
/*
|
||||
* Only allow I/O from the graphics and Langwell;
|
||||
* not from the x86 processor
|
||||
*/
|
||||
|
||||
dma_addr_t low = my_rar_device.rar_addr[rar_index].low &
|
||||
0xfffffc00u;
|
||||
if (rar_index == RAR_TYPE_VIDEO) {
|
||||
low |= 0x00000009;
|
||||
high |= 0x00000015;
|
||||
} else if (rar_index == RAR_TYPE_AUDIO) {
|
||||
/* Only allow I/O from Langwell; nothing from x86 */
|
||||
low |= 0x00000008;
|
||||
high |= 0x00000018;
|
||||
} else
|
||||
/* Read-only from all agents */
|
||||
high |= 0x00000018;
|
||||
|
||||
dma_addr_t high = my_rar_device.rar_addr[rar_index].high &
|
||||
0xfffffc00u;
|
||||
/*
|
||||
* Now program the register using the Lincroft message
|
||||
* bus interface.
|
||||
*/
|
||||
result = rar_set_addr(rar->rar_dev,
|
||||
2 * idx, low);
|
||||
|
||||
/*
|
||||
* Only allow I/O from the graphics and Langwell;
|
||||
* Not from the x96 processor
|
||||
*/
|
||||
if (rar_index == (int)RAR_TYPE_VIDEO) {
|
||||
low |= 0x00000009;
|
||||
high |= 0x00000015;
|
||||
}
|
||||
if (result == 0)
|
||||
result = rar_set_addr(rar->rar_dev,
|
||||
2 * idx + 1, high);
|
||||
|
||||
else if (rar_index == (int)RAR_TYPE_AUDIO) {
|
||||
/* Only allow I/O from Langwell; nothing from x86 */
|
||||
low |= 0x00000008;
|
||||
high |= 0x00000018;
|
||||
}
|
||||
|
||||
else
|
||||
/* Read-only from all agents */
|
||||
high |= 0x00000018;
|
||||
|
||||
/*
|
||||
* Now program the register using the Lincroft message
|
||||
* bus interface.
|
||||
*/
|
||||
result = set_rar_address(my_rar_device.rar_dev,
|
||||
my_rar_device.rar_offsets[rar_index].low,
|
||||
low);
|
||||
|
||||
if (result == 0)
|
||||
result = set_rar_address(
|
||||
my_rar_device.rar_dev,
|
||||
my_rar_device.rar_offsets[rar_index].high,
|
||||
high);
|
||||
}
|
||||
|
||||
dev_dbg(&my_rar_device.rar_dev->dev, "rar_lock mutex unlocking\n");
|
||||
mutex_unlock(&rar_mutex);
|
||||
return result;
|
||||
}
|
||||
EXPORT_SYMBOL(rar_lock);
|
||||
|
||||
/* 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 rar_get_address()
|
||||
* This function return 0 on success an -1 on failure.
|
||||
*/
|
||||
int register_rar(int (*callback)(void *yourparameter), void *yourparameter)
|
||||
/**
|
||||
* register_rar - register a RAR handler
|
||||
* @num: RAR we wish to register for
|
||||
* @callback: function to call when RAR support is available
|
||||
* @data: data to pass to this function
|
||||
*
|
||||
* 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 drivers 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 rar_get_address()
|
||||
*
|
||||
* This function return 0 on success an error code on failure.
|
||||
*/
|
||||
int register_rar(int num, int (*callback)(unsigned long data),
|
||||
unsigned long data)
|
||||
{
|
||||
|
||||
int result = -ENODEV;
|
||||
|
||||
if (callback == NULL)
|
||||
return -EINVAL;
|
||||
/* For now we hardcode a single RAR device */
|
||||
struct rar_device *rar;
|
||||
struct client *c;
|
||||
int idx;
|
||||
int retval = 0;
|
||||
|
||||
mutex_lock(&rar_mutex);
|
||||
|
||||
if (my_rar_device.registered) {
|
||||
/* Do we have a client mapping for this RAR number ? */
|
||||
c = rar_to_client(num);
|
||||
if (c == NULL) {
|
||||
retval = -ERANGE;
|
||||
goto done;
|
||||
}
|
||||
/* Is it claimed ? */
|
||||
if (c->busy) {
|
||||
retval = -EBUSY;
|
||||
goto done;
|
||||
}
|
||||
c->busy = 1;
|
||||
|
||||
mutex_unlock(&rar_mutex);
|
||||
/* See if we have a handler for this RAR yet, if we do then fire it */
|
||||
rar = rar_to_device(num, &idx);
|
||||
|
||||
if (rar) {
|
||||
/*
|
||||
* if the driver already registered, then we can simply
|
||||
* call the callback right now
|
||||
*/
|
||||
|
||||
return (*callback)(yourparameter);
|
||||
}
|
||||
|
||||
if (num_clients < MRST_NUM_RAR) {
|
||||
|
||||
clients[num_clients].client_callback = callback;
|
||||
clients[num_clients].customer_data = yourparameter;
|
||||
num_clients += 1;
|
||||
result = 0;
|
||||
(*callback)(data);
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Arrange to be called back when the hardware is found */
|
||||
c->callback = callback;
|
||||
c->driver_priv = data;
|
||||
done:
|
||||
mutex_unlock(&rar_mutex);
|
||||
return result;
|
||||
|
||||
return retval;
|
||||
}
|
||||
EXPORT_SYMBOL(register_rar);
|
||||
|
||||
/* Suspend - returns -ENOSYS */
|
||||
static int rar_suspend(struct pci_dev *dev, pm_message_t state)
|
||||
/**
|
||||
* unregister_rar - release a RAR allocation
|
||||
* @num: RAR number
|
||||
*
|
||||
* Releases a RAR allocation, or pending allocation. If a callback is
|
||||
* pending then this function will either complete before the unregister
|
||||
* returns or not at all.
|
||||
*/
|
||||
|
||||
void unregister_rar(int num)
|
||||
{
|
||||
return -ENOSYS;
|
||||
struct client *c;
|
||||
|
||||
mutex_lock(&rar_mutex);
|
||||
c = rar_to_client(num);
|
||||
if (c == NULL || !c->busy)
|
||||
WARN_ON(1);
|
||||
else
|
||||
c->busy = 0;
|
||||
mutex_unlock(&rar_mutex);
|
||||
}
|
||||
EXPORT_SYMBOL(unregister_rar);
|
||||
|
||||
/**
|
||||
* rar_callback - Process callbacks
|
||||
* @rar: new RAR device
|
||||
*
|
||||
* Process the callbacks for a newly found RAR device.
|
||||
*/
|
||||
|
||||
static void rar_callback(struct rar_device *rar)
|
||||
{
|
||||
struct client *c = &rar->client[0];
|
||||
int i;
|
||||
|
||||
mutex_lock(&rar_mutex);
|
||||
|
||||
rar->registered = 1; /* Ensure no more callbacks queue */
|
||||
|
||||
for (i = 0; i < MRST_NUM_RAR; i++) {
|
||||
if (c->callback && c->busy) {
|
||||
c->callback(c->driver_priv);
|
||||
c->callback = NULL;
|
||||
}
|
||||
c++;
|
||||
}
|
||||
mutex_unlock(&rar_mutex);
|
||||
}
|
||||
|
||||
static int rar_resume(struct pci_dev *dev)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function registers the driver with the device subsystem (
|
||||
* either PCI, USB, etc).
|
||||
* Function that is activaed on the succesful probe of the RAR device
|
||||
* (Moorestown host controller).
|
||||
/**
|
||||
* rar_probe - PCI probe callback
|
||||
* @dev: PCI device
|
||||
* @id: matching entry in the match table
|
||||
*
|
||||
* A RAR device has been discovered. Initialise it and if successful
|
||||
* process any pending callbacks that can now be completed.
|
||||
*/
|
||||
static int rar_probe(struct pci_dev *dev, const struct pci_device_id *id)
|
||||
{
|
||||
int error;
|
||||
int counter;
|
||||
struct rar_device *rar;
|
||||
|
||||
dev_dbg(&dev->dev, "PCI probe starting\n");
|
||||
|
||||
/* enable the device */
|
||||
rar = alloc_rar_device();
|
||||
if (rar == NULL)
|
||||
return -EBUSY;
|
||||
|
||||
/* Enable the device */
|
||||
error = pci_enable_device(dev);
|
||||
if (error) {
|
||||
dev_err(&dev->dev,
|
||||
|
@ -538,50 +619,30 @@ static int rar_probe(struct pci_dev *dev, const struct pci_device_id *id)
|
|||
goto end_function;
|
||||
}
|
||||
|
||||
/* we have only one device; fill in the rar_device structure */
|
||||
my_rar_device.rar_dev = dev;
|
||||
/* Fill in the rar_device structure */
|
||||
rar->rar_dev = pci_dev_get(dev);
|
||||
pci_set_drvdata(dev, rar);
|
||||
|
||||
/*
|
||||
* Initialize the RAR parameters, which have to be retrieved
|
||||
* via the message bus interface.
|
||||
*/
|
||||
error = init_rar_params(dev);
|
||||
* Initialize the RAR parameters, which have to be retrieved
|
||||
* via the message bus interface.
|
||||
*/
|
||||
error = init_rar_params(rar);
|
||||
if (error) {
|
||||
pci_disable_device(dev);
|
||||
|
||||
dev_err(&dev->dev,
|
||||
"Error retrieving RAR addresses\n");
|
||||
|
||||
dev_err(&dev->dev, "Error retrieving RAR addresses\n");
|
||||
goto end_function;
|
||||
}
|
||||
|
||||
dev_dbg(&dev->dev, "PCI probe locking\n");
|
||||
mutex_lock(&rar_mutex);
|
||||
my_rar_device.registered = 1;
|
||||
|
||||
/* now call anyone who has registered (using callbacks) */
|
||||
for (counter = 0; counter < num_clients; counter += 1) {
|
||||
if (clients[counter].client_callback) {
|
||||
error = (*clients[counter].client_callback)(
|
||||
clients[counter].customer_data);
|
||||
/* set callback to NULL to indicate it has been done */
|
||||
clients[counter].client_callback = NULL;
|
||||
dev_dbg(&my_rar_device.rar_dev->dev,
|
||||
"Callback called for %d\n",
|
||||
counter);
|
||||
}
|
||||
}
|
||||
|
||||
dev_dbg(&dev->dev, "PCI probe unlocking\n");
|
||||
mutex_unlock(&rar_mutex);
|
||||
|
||||
rar_callback(rar);
|
||||
return 0;
|
||||
end_function:
|
||||
|
||||
free_rar_device(rar);
|
||||
return error;
|
||||
}
|
||||
|
||||
const struct pci_device_id rar_pci_id_tbl[] = {
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_RAR_DEVICE_ID) },
|
||||
{ PCI_VDEVICE(INTEL, 0x4110) },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
|
@ -594,8 +655,7 @@ static struct pci_driver rar_pci_driver = {
|
|||
.name = "rar_register_driver",
|
||||
.id_table = rar_pci_id_tbl,
|
||||
.probe = rar_probe,
|
||||
.suspend = rar_suspend,
|
||||
.resume = rar_resume
|
||||
/* Cannot be unplugged - no remove */
|
||||
};
|
||||
|
||||
static int __init rar_init_handler(void)
|
||||
|
|
|
@ -21,63 +21,23 @@
|
|||
#ifndef _RAR_REGISTER_H
|
||||
#define _RAR_REGISTER_H
|
||||
|
||||
# include <linux/types.h>
|
||||
#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
|
||||
};
|
||||
|
||||
#define RAR_TYPE_VIDEO 0
|
||||
#define RAR_TYPE_AUDIO 1
|
||||
#define RAR_TYPE_IMAGE 2
|
||||
#define RAR_TYPE_DATA 3
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
/* PCI device id for controller */
|
||||
#define PCI_RAR_DEVICE_ID 0x4110
|
||||
struct rar_device;
|
||||
|
||||
/* 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);
|
||||
|
||||
/* 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__ */
|
||||
|
|
Loading…
Reference in a new issue