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:
Alan Cox 2010-05-04 20:40:12 +01:00 committed by Greg Kroah-Hartman
parent a9d26f00b8
commit 375d65db27
3 changed files with 619 additions and 540 deletions

View file

@ -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);

View file

@ -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)

View file

@ -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__ */