|
@@ -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
|
|
|
+/* Current platforms have only one rar_device for 3 rar regions */
|
|
|
+static struct rar_device my_rar_device;
|
|
|
+
|
|
|
+/*
|
|
|
+ * Abstract out multiple device support. Current platforms only
|
|
|
+ * have a single RAR device.
|
|
|
*/
|
|
|
|
|
|
-static struct client clients[MAX_RAR_CLIENTS];
|
|
|
-static int num_clients;
|
|
|
+/**
|
|
|
+ * 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;
|
|
|
+}
|
|
|
|
|
|
-/*
|
|
|
- * This function is used to retrieved RAR info using the Lincroft
|
|
|
- * message bus interface.
|
|
|
+/**
|
|
|
+ * free_rar_device - free a RAR object
|
|
|
+ * @rar: the RAR device being freed
|
|
|
+ *
|
|
|
+ * Release a RAR object and any attached resources
|
|
|
*/
|
|
|
-static int retrieve_rar_addr(struct pci_dev *pdev,
|
|
|
- int offset,
|
|
|
- dma_addr_t *addr)
|
|
|
+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];
|
|
|
-
|
|
|
- if ((retrieve_rar_addr(pdev, offset->low, &addr->low) != 0)
|
|
|
- || (retrieve_rar_addr(pdev, offset->high, &addr->high) != 0)) {
|
|
|
- result = -1;
|
|
|
- break;
|
|
|
- }
|
|
|
+ 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;
|
|
|
+
|
|
|
|
|
|
/*
|
|
|
* 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;
|
|
|
-
|
|
|
- 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;
|
|
|
- }
|
|
|
+ int idx;
|
|
|
+ struct rar_device *rar = rar_to_device(rar_index, &idx);
|
|
|
+
|
|
|
+ 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;
|
|
|
-
|
|
|
- if (rar_index >= MRST_NUM_RAR || rar_index < 0) {
|
|
|
- result = -EINVAL;
|
|
|
- return result;
|
|
|
- }
|
|
|
-
|
|
|
- dev_dbg(&my_rar_device.rar_dev->dev, "rar_lock mutex locking\n");
|
|
|
- mutex_lock(&rar_mutex);
|
|
|
+ struct rar_device *rar;
|
|
|
+ int result;
|
|
|
+ int idx;
|
|
|
+ dma_addr_t low, high;
|
|
|
|
|
|
- if (my_rar_device.registered) {
|
|
|
+ rar = rar_to_device(rar_index, &idx);
|
|
|
|
|
|
- dma_addr_t low = my_rar_device.rar_addr[rar_index].low &
|
|
|
- 0xfffffc00u;
|
|
|
+ if (rar == NULL) {
|
|
|
+ WARN_ON(1);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
|
|
|
- dma_addr_t high = my_rar_device.rar_addr[rar_index].high &
|
|
|
- 0xfffffc00u;
|
|
|
+ low = rar->rar_addr[idx].low & 0xfffffc00u;
|
|
|
+ high = rar->rar_addr[idx].high & 0xfffffc00u;
|
|
|
|
|
|
- /*
|
|
|
- * 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;
|
|
|
- }
|
|
|
+ /*
|
|
|
+ * Only allow I/O from the graphics and Langwell;
|
|
|
+ * not from the x86 processor
|
|
|
+ */
|
|
|
|
|
|
- else if (rar_index == (int)RAR_TYPE_AUDIO) {
|
|
|
- /* Only allow I/O from Langwell; nothing from x86 */
|
|
|
- low |= 0x00000008;
|
|
|
- high |= 0x00000018;
|
|
|
- }
|
|
|
+ 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;
|
|
|
|
|
|
- else
|
|
|
- /* Read-only from all agents */
|
|
|
- high |= 0x00000018;
|
|
|
+ /*
|
|
|
+ * Now program the register using the Lincroft message
|
|
|
+ * bus interface.
|
|
|
+ */
|
|
|
+ result = rar_set_addr(rar->rar_dev,
|
|
|
+ 2 * idx, low);
|
|
|
|
|
|
- /*
|
|
|
- * 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);
|
|
|
- }
|
|
|
+ if (result == 0)
|
|
|
+ result = rar_set_addr(rar->rar_dev,
|
|
|
+ 2 * idx + 1, 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;
|
|
|
+
|
|
|
+ /* See if we have a handler for this RAR yet, if we do then fire it */
|
|
|
+ rar = rar_to_device(num, &idx);
|
|
|
|
|
|
- mutex_unlock(&rar_mutex);
|
|
|
+ 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);
|
|
|
|
|
|
-static int rar_resume(struct pci_dev *dev)
|
|
|
+/**
|
|
|
+ * 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)
|
|
|
{
|
|
|
- return -ENOSYS;
|
|
|
+ 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);
|
|
|
}
|
|
|
|
|
|
-/*
|
|
|
- * 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)
|