|
@@ -1,33 +1,67 @@
|
|
|
-#include <linux/init.h>
|
|
|
-#include <linux/module.h>
|
|
|
-#include <linux/fs.h>
|
|
|
-#include <linux/cdev.h>
|
|
|
-#include <linux/kdev_t.h>
|
|
|
-#include <linux/semaphore.h>
|
|
|
-#include <linux/mm.h>
|
|
|
-#include <linux/poll.h>
|
|
|
-#include <linux/wait.h>
|
|
|
-#include <linux/ioctl.h>
|
|
|
-#include <linux/ioport.h>
|
|
|
-#include <linux/io.h>
|
|
|
-#include <linux/interrupt.h>
|
|
|
-#include <linux/pagemap.h>
|
|
|
-#include <linux/pci.h>
|
|
|
-#include <linux/firmware.h>
|
|
|
-#include <linux/sched.h>
|
|
|
+/*
|
|
|
+ * rar_register.c - An Intel Restricted Access Region register driver
|
|
|
+ *
|
|
|
+ * Copyright(c) 2009 Intel Corporation. All rights reserved.
|
|
|
+ *
|
|
|
+ * This program is free software; you can redistribute it and/or
|
|
|
+ * modify it under the terms of the GNU General Public License as
|
|
|
+ * published by the Free Software Foundation; either version 2 of the
|
|
|
+ * License, or (at your option) any later version.
|
|
|
+ *
|
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
+ * General Public License for more details.
|
|
|
+ *
|
|
|
+ * You should have received a copy of the GNU General Public License
|
|
|
+ * along with this program; if not, write to the Free Software
|
|
|
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
|
|
+ * 02111-1307, USA.
|
|
|
+ *
|
|
|
+ * -------------------------------------------------------------------
|
|
|
+ * 20091204 Mark Allyn <mark.a.allyn@intel.com>
|
|
|
+ * Ossama Othman <ossama.othman@intel.com>
|
|
|
+ * Cleanup per feedback from Alan Cox and Arjan Van De Ven
|
|
|
+ *
|
|
|
+ * 20090806 Ossama Othman <ossama.othman@intel.com>
|
|
|
+ * Return zero high address if upper 22 bits is zero.
|
|
|
+ * Cleaned up checkpatch errors.
|
|
|
+ * Clarified that driver is dealing with bus addresses.
|
|
|
+ *
|
|
|
+ * 20090702 Ossama Othman <ossama.othman@intel.com>
|
|
|
+ * Removed unnecessary include directives
|
|
|
+ * Cleaned up spinlocks.
|
|
|
+ * Cleaned up logging.
|
|
|
+ * Improved invalid parameter checks.
|
|
|
+ * Fixed and simplified RAR address retrieval and RAR locking
|
|
|
+ * code.
|
|
|
+ *
|
|
|
+ * 20090626 Mark Allyn <mark.a.allyn@intel.com>
|
|
|
+ * Initial publish
|
|
|
+ */
|
|
|
+
|
|
|
+#define DEBUG 1
|
|
|
+
|
|
|
#include "rar_register.h"
|
|
|
|
|
|
-/* The following defines are for the IPC process to retrieve RAR in */
|
|
|
+#include <linux/module.h>
|
|
|
+#include <linux/pci.h>
|
|
|
+#include <linux/spinlock.h>
|
|
|
+#include <linux/device.h>
|
|
|
+#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
|
|
|
|
|
|
/* Message Opcodes */
|
|
|
-#define LNC_MESSAGE_READ_OPCODE 0xD0
|
|
|
+#define LNC_MESSAGE_READ_OPCODE 0xD0
|
|
|
#define LNC_MESSAGE_WRITE_OPCODE 0xE0
|
|
|
|
|
|
/* Message Write Byte Enables */
|
|
@@ -37,59 +71,73 @@
|
|
|
#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
|
|
|
|
|
|
-/* This structure is only used during module initialization. */
|
|
|
-struct RAR_offsets {
|
|
|
- int low; /* Register offset for low RAR physical address. */
|
|
|
- int high; /* Register offset for high RAR physical address. */
|
|
|
-};
|
|
|
|
|
|
-struct pci_dev *rar_dev;
|
|
|
-static uint32_t registered;
|
|
|
+/* RAR Bus Address Range */
|
|
|
+struct RAR_address_range {
|
|
|
+ dma_addr_t low;
|
|
|
+ dma_addr_t high;
|
|
|
+};
|
|
|
|
|
|
-/* Moorestown supports three restricted access regions. */
|
|
|
-#define MRST_NUM_RAR 3
|
|
|
+/* 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. */
|
|
|
+};
|
|
|
|
|
|
-struct RAR_address_struct rar_addr[MRST_NUM_RAR];
|
|
|
+struct client {
|
|
|
+ int (*client_callback)(void *client_data);
|
|
|
+ void *customer_data;
|
|
|
+ int client_called;
|
|
|
+ };
|
|
|
|
|
|
-/* prototype for init */
|
|
|
-static int __init rar_init_handler(void);
|
|
|
-static void __exit rar_exit_handler(void);
|
|
|
+static DEFINE_MUTEX(rar_mutex);
|
|
|
+static DEFINE_MUTEX(lnc_reg_mutex);
|
|
|
|
|
|
-/*
|
|
|
- function that is activated on the successfull probe of the RAR device
|
|
|
-*/
|
|
|
-static int __devinit rar_probe(struct pci_dev *pdev,
|
|
|
- const struct pci_device_id *ent);
|
|
|
+struct RAR_device {
|
|
|
+ struct RAR_offsets const rar_offsets[MRST_NUM_RAR];
|
|
|
+ struct RAR_address_range rar_addr[MRST_NUM_RAR];
|
|
|
+ struct pci_dev *rar_dev;
|
|
|
+ bool registered;
|
|
|
+ };
|
|
|
|
|
|
-static const struct pci_device_id rar_pci_id_tbl[] = {
|
|
|
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x4110) },
|
|
|
- { 0 }
|
|
|
+/* 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
|
|
|
+ }
|
|
|
};
|
|
|
|
|
|
-MODULE_DEVICE_TABLE(pci, rar_pci_id_tbl);
|
|
|
+/* this data is for handling requests from other drivers which arrive
|
|
|
+ * prior to this driver initializing
|
|
|
+ */
|
|
|
|
|
|
-/* field for registering driver to PCI device */
|
|
|
-static struct pci_driver rar_pci_driver = {
|
|
|
- .name = "rar_driver",
|
|
|
- .id_table = rar_pci_id_tbl,
|
|
|
- .probe = rar_probe
|
|
|
-};
|
|
|
+static struct client clients[MAX_RAR_CLIENTS];
|
|
|
+static int num_clients;
|
|
|
|
|
|
-/* This function is used to retrieved RAR info using the IPC message
|
|
|
- bus interface */
|
|
|
-static int memrar_get_rar_addr(struct pci_dev *pdev,
|
|
|
- int offset,
|
|
|
- u32 *addr)
|
|
|
+/*
|
|
|
+ * This function is used to retrieved RAR info using the Lincroft
|
|
|
+ * message bus interface.
|
|
|
+ */
|
|
|
+static int retrieve_rar_addr(struct pci_dev *pdev,
|
|
|
+ int offset,
|
|
|
+ dma_addr_t *addr)
|
|
|
{
|
|
|
/*
|
|
|
* ======== The Lincroft Message Bus Interface ========
|
|
@@ -131,243 +179,412 @@ static int memrar_get_rar_addr(struct pci_dev *pdev,
|
|
|
* Data being written to this register must be written before
|
|
|
* writing the appropriate control message to the MCR
|
|
|
* register.
|
|
|
- */
|
|
|
+ */
|
|
|
+
|
|
|
+ int result;
|
|
|
|
|
|
- int result = 0; /* result */
|
|
|
/* Construct control message */
|
|
|
u32 const message =
|
|
|
- (LNC_MESSAGE_READ_OPCODE << 24)
|
|
|
- | (LNC_BUNIT_PORT << 16)
|
|
|
- | (offset << 8)
|
|
|
- | (LNC_MESSAGE_BYTE_WRITE_ENABLES << 4);
|
|
|
+ (LNC_MESSAGE_READ_OPCODE << 24)
|
|
|
+ | (LNC_BUNIT_PORT << 16)
|
|
|
+ | (offset << 8)
|
|
|
+ | (LNC_MESSAGE_BYTE_WRITE_ENABLES << 4);
|
|
|
|
|
|
- printk(KERN_WARNING "rar- offset to LNC MSG is %x\n", offset);
|
|
|
+ dev_dbg(&pdev->dev, "Offset for 'get' LNC MSG is %x\n", offset);
|
|
|
|
|
|
- if (addr == 0)
|
|
|
+ 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
|
|
|
+ * and the corresponding data is read from the MDR register.
|
|
|
+ * Otherwise a race condition would exist between accesses to
|
|
|
+ * both registers.
|
|
|
+ */
|
|
|
+
|
|
|
+ mutex_lock(&lnc_reg_mutex);
|
|
|
|
|
|
/* Send the control message */
|
|
|
- result = pci_write_config_dword(pdev,
|
|
|
- LNC_MCR_OFFSET,
|
|
|
- message);
|
|
|
+ result = pci_write_config_dword(pdev, LNC_MCR_OFFSET, message);
|
|
|
|
|
|
- printk(KERN_WARNING "rar- result from send ctl register is %x\n",
|
|
|
- result);
|
|
|
+ dev_dbg(&pdev->dev, "Result from send ctl register is %x\n", result);
|
|
|
|
|
|
- if (!result)
|
|
|
- result = pci_read_config_dword(pdev,
|
|
|
- LNC_MDR_OFFSET,
|
|
|
- addr);
|
|
|
+ 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);
|
|
|
|
|
|
- printk(KERN_WARNING "rar- result from read data register is %x\n",
|
|
|
- result);
|
|
|
+ dev_dbg(&pdev->dev,
|
|
|
+ "Value read from data register is %lx\n",
|
|
|
+ (unsigned long)*addr);
|
|
|
+ }
|
|
|
|
|
|
- printk(KERN_WARNING "rar- value read from data register is %x\n",
|
|
|
- *addr);
|
|
|
+ mutex_unlock(&lnc_reg_mutex);
|
|
|
|
|
|
- if (result)
|
|
|
- return -1;
|
|
|
- else
|
|
|
- return 0;
|
|
|
+ return result;
|
|
|
}
|
|
|
|
|
|
-static int memrar_set_rar_addr(struct pci_dev *pdev,
|
|
|
- int offset,
|
|
|
- u32 addr)
|
|
|
+static int set_rar_address(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
|
|
|
- * Interface. That message bus interface is generally
|
|
|
- * comprised of two registers: a control register (MCR, 0xDO)
|
|
|
- * and a data register (MDR, 0xD4).
|
|
|
- *
|
|
|
- * The MCR (message control register) format is the following:
|
|
|
- * 1. [31:24]: Opcode
|
|
|
- * 2. [23:16]: Port
|
|
|
- * 3. [15:8]: Register Offset
|
|
|
- * 4. [7:4]: Byte Enables (use 0xF to set all of these bits
|
|
|
- * to 1)
|
|
|
- * 5. [3:0]: reserved
|
|
|
- *
|
|
|
- * Read (0xD0) and write (0xE0) opcodes are written to the
|
|
|
- * control register when reading and writing to Lincroft
|
|
|
- * registers, respectively.
|
|
|
- *
|
|
|
- * We're interested in registers found in the Lincroft
|
|
|
- * B-unit. The B-unit port is 0x3.
|
|
|
- *
|
|
|
- * The six B-unit RAR register offsets we use are listed
|
|
|
- * earlier in this file.
|
|
|
- *
|
|
|
- * Lastly writing to the MCR register requires the "Byte
|
|
|
- * enables" bits to be set to 1. This may be achieved by
|
|
|
- * writing 0xF at bit 4.
|
|
|
- *
|
|
|
- * The MDR (message data register) format is the following:
|
|
|
- * 1. [31:0]: Read/Write Data
|
|
|
- *
|
|
|
- * Data being read from this register is only available after
|
|
|
- * writing the appropriate control message to the MCR
|
|
|
- * register.
|
|
|
- *
|
|
|
- * Data being written to this register must be written before
|
|
|
- * writing the appropriate control message to the MCR
|
|
|
- * register.
|
|
|
- */
|
|
|
+ * 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
|
|
|
+ * message bus interface being used here.
|
|
|
+ */
|
|
|
|
|
|
- int result = 0; /* result */
|
|
|
+ int result = 0;
|
|
|
|
|
|
/* Construct control message */
|
|
|
- u32 const message =
|
|
|
- (LNC_MESSAGE_WRITE_OPCODE << 24)
|
|
|
- | (LNC_BUNIT_PORT << 16)
|
|
|
- | (offset << 8)
|
|
|
- | (LNC_MESSAGE_BYTE_WRITE_ENABLES << 4);
|
|
|
-
|
|
|
- printk(KERN_WARNING "rar- offset to LNC MSG is %x\n", offset);
|
|
|
+ u32 const message = (LNC_MESSAGE_WRITE_OPCODE << 24)
|
|
|
+ | (LNC_BUNIT_PORT << 16)
|
|
|
+ | (offset << 8)
|
|
|
+ | (LNC_MESSAGE_BYTE_WRITE_ENABLES << 4);
|
|
|
|
|
|
- if (addr == 0)
|
|
|
+ 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
|
|
|
+ * and the corresponding data is read from the MDR register.
|
|
|
+ * Otherwise a race condition would exist between accesses to
|
|
|
+ * both registers.
|
|
|
+ */
|
|
|
+
|
|
|
+ mutex_lock(&lnc_reg_mutex);
|
|
|
|
|
|
/* Send the control message */
|
|
|
- result = pci_write_config_dword(pdev,
|
|
|
- LNC_MDR_OFFSET,
|
|
|
- addr);
|
|
|
+ result = pci_write_config_dword(pdev, LNC_MDR_OFFSET, addr);
|
|
|
|
|
|
- printk(KERN_WARNING "rar- result from send ctl register is %x\n",
|
|
|
- result);
|
|
|
+ dev_dbg(&pdev->dev, "Result from write data register is %x\n", result);
|
|
|
|
|
|
- if (!result)
|
|
|
- result = pci_write_config_dword(pdev,
|
|
|
- LNC_MCR_OFFSET,
|
|
|
- message);
|
|
|
+ if (!result) {
|
|
|
+ dev_dbg(&pdev->dev,
|
|
|
+ "Value written to data register is %lx\n",
|
|
|
+ (unsigned long)addr);
|
|
|
|
|
|
- printk(KERN_WARNING "rar- result from write data register is %x\n",
|
|
|
- result);
|
|
|
+ result = pci_write_config_dword(pdev, LNC_MCR_OFFSET, message);
|
|
|
+
|
|
|
+ dev_dbg(&pdev->dev, "Result from send ctl register is %x\n",
|
|
|
+ result);
|
|
|
+ }
|
|
|
|
|
|
- printk(KERN_WARNING "rar- value read to data register is %x\n",
|
|
|
- addr);
|
|
|
+ mutex_unlock(&lnc_reg_mutex);
|
|
|
|
|
|
- if (result)
|
|
|
- return -1;
|
|
|
- else
|
|
|
- return 0;
|
|
|
+ return result;
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
-
|
|
|
- * Initialize RAR parameters, such as physical addresses, etc.
|
|
|
-
|
|
|
- */
|
|
|
-static int memrar_init_rar_params(struct pci_dev *pdev)
|
|
|
+* Initialize RAR parameters, such as bus addresses, etc.
|
|
|
+*/
|
|
|
+static int init_rar_params(struct pci_dev *pdev)
|
|
|
{
|
|
|
- struct RAR_offsets const offsets[] = {
|
|
|
- { LNC_BRAR0L, LNC_BRAR0H },
|
|
|
- { LNC_BRAR1L, LNC_BRAR1H },
|
|
|
- { LNC_BRAR2L, LNC_BRAR2H }
|
|
|
- };
|
|
|
-
|
|
|
- size_t const num_offsets = sizeof(offsets) / sizeof(offsets[0]);
|
|
|
- struct RAR_offsets const *end = offsets + num_offsets;
|
|
|
- struct RAR_offsets const *i;
|
|
|
- unsigned int n = 0;
|
|
|
+ unsigned int i;
|
|
|
int result = 0;
|
|
|
|
|
|
- /* Retrieve RAR start and end physical addresses. */
|
|
|
+ /* Retrieve RAR start and end bus addresses.
|
|
|
+ * Access the RAR registers through the Lincroft Message Bus
|
|
|
+ * Interface on PCI device: 00:00.0 Host bridge.
|
|
|
+ */
|
|
|
|
|
|
- /*
|
|
|
- * Access the RAR registers through the Lincroft Message Bus
|
|
|
- * Interface on PCI device: 00:00.0 Host bridge.
|
|
|
- */
|
|
|
-
|
|
|
- /* struct pci_dev *pdev = pci_get_bus_and_slot(0, PCI_DEVFN(0,0)); */
|
|
|
-
|
|
|
- if (pdev == NULL)
|
|
|
- return -ENODEV;
|
|
|
-
|
|
|
- for (i = offsets; i != end; ++i, ++n) {
|
|
|
- if (memrar_get_rar_addr(pdev,
|
|
|
- (*i).low,
|
|
|
- &(rar_addr[n].low)) != 0
|
|
|
- || memrar_get_rar_addr(pdev,
|
|
|
- (*i).high,
|
|
|
- &(rar_addr[n].high)) != 0) {
|
|
|
- result = -1;
|
|
|
- break;
|
|
|
+ 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;
|
|
|
}
|
|
|
- }
|
|
|
|
|
|
+ /*
|
|
|
+ * Only the upper 22 bits of the RAR addresses are
|
|
|
+ * stored in their corresponding RAR registers so we
|
|
|
+ * must set the lower 10 bits accordingly.
|
|
|
+
|
|
|
+ * The low address has its lower 10 bits cleared, and
|
|
|
+ * the high address has all its lower 10 bits set,
|
|
|
+ * e.g.:
|
|
|
+ * low = 0x2ffffc00
|
|
|
+ */
|
|
|
+
|
|
|
+ addr->low &= (dma_addr_t)0xfffffc00u;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Set bits 9:0 on uppser address if bits 31:10 are non
|
|
|
+ * zero; otherwize clear all bits
|
|
|
+ */
|
|
|
+
|
|
|
+ if ((addr->high & 0xfffffc00u) == 0)
|
|
|
+ addr->high = 0;
|
|
|
+ else
|
|
|
+ addr->high |= 0x3ffu;
|
|
|
+ }
|
|
|
/* Done accessing the device. */
|
|
|
- /* pci_dev_put(pdev); */
|
|
|
|
|
|
if (result == 0) {
|
|
|
- if (1) {
|
|
|
- size_t z;
|
|
|
- for (z = 0; z != MRST_NUM_RAR; ++z) {
|
|
|
- printk(KERN_WARNING
|
|
|
- "rar - BRAR[%Zd] physical address low\n"
|
|
|
- "\tlow: 0x%08x\n"
|
|
|
- "\thigh: 0x%08x\n",
|
|
|
- z,
|
|
|
- rar_addr[z].low,
|
|
|
- rar_addr[z].high);
|
|
|
- }
|
|
|
+ int z;
|
|
|
+ for (z = 0; z != MRST_NUM_RAR; ++z) {
|
|
|
+ /*
|
|
|
+ * "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);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ 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:
|
|
|
+ *
|
|
|
+ * 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 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)
|
|
|
+{
|
|
|
+ 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;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return result;
|
|
|
}
|
|
|
+EXPORT_SYMBOL(rar_get_address);
|
|
|
|
|
|
/*
|
|
|
- function that is activated on the successfull probe of the RAR device
|
|
|
+ * 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:
|
|
|
+ *
|
|
|
+ * 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 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);
|
|
|
+
|
|
|
+ if (my_rar_device.registered) {
|
|
|
+
|
|
|
+ dma_addr_t low = my_rar_device.rar_addr[rar_index].low &
|
|
|
+ 0xfffffc00u;
|
|
|
+
|
|
|
+ dma_addr_t high = my_rar_device.rar_addr[rar_index].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;
|
|
|
+ }
|
|
|
+
|
|
|
+ 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.
|
|
|
*/
|
|
|
-static int __devinit rar_probe(struct pci_dev *pdev,
|
|
|
- const struct pci_device_id *ent)
|
|
|
+int register_rar(int (*callback)(void *yourparameter), void *yourparameter)
|
|
|
{
|
|
|
- /* error */
|
|
|
- int error;
|
|
|
|
|
|
- /*------------------------
|
|
|
- CODE
|
|
|
- ---------------------------*/
|
|
|
+ int result = -ENODEV;
|
|
|
|
|
|
- DEBUG_PRINT_0(RAR_DEBUG_LEVEL_EXTENDED,
|
|
|
- "Rar pci probe starting\n");
|
|
|
- error = 0;
|
|
|
+ if (callback == NULL)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ mutex_lock(&rar_mutex);
|
|
|
+
|
|
|
+ if (my_rar_device.registered) {
|
|
|
+
|
|
|
+ mutex_unlock(&rar_mutex);
|
|
|
+ /*
|
|
|
+ * 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;
|
|
|
+ }
|
|
|
+
|
|
|
+ mutex_unlock(&rar_mutex);
|
|
|
+ return result;
|
|
|
+
|
|
|
+}
|
|
|
+EXPORT_SYMBOL(register_rar);
|
|
|
+
|
|
|
+/*
|
|
|
+ * 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).
|
|
|
+ */
|
|
|
+static int rar_probe(struct pci_dev *dev, const struct pci_device_id *id)
|
|
|
+{
|
|
|
+ int error;
|
|
|
+ int counter;
|
|
|
+
|
|
|
+ dev_dbg(&dev->dev, "PCI probe starting\n");
|
|
|
|
|
|
/* enable the device */
|
|
|
- error = pci_enable_device(pdev);
|
|
|
+ error = pci_enable_device(dev);
|
|
|
if (error) {
|
|
|
- DEBUG_PRINT_0(RAR_DEBUG_LEVEL_EXTENDED,
|
|
|
- "error enabling pci device\n");
|
|
|
+ dev_err(&dev->dev,
|
|
|
+ "Error enabling RAR register PCI device\n");
|
|
|
goto end_function;
|
|
|
}
|
|
|
|
|
|
- rar_dev = pdev;
|
|
|
- registered = 1;
|
|
|
-
|
|
|
- /* Initialize the RAR parameters, which have to be retrieved */
|
|
|
- /* via the message bus service */
|
|
|
- error = memrar_init_rar_params(rar_dev);
|
|
|
+ /* we have only one device; fill in the rar_device structure */
|
|
|
+ my_rar_device.rar_dev = dev;
|
|
|
|
|
|
+ /*
|
|
|
+ * Initialize the RAR parameters, which have to be retrieved
|
|
|
+ * via the message bus interface.
|
|
|
+ */
|
|
|
+ error = init_rar_params(dev);
|
|
|
if (error) {
|
|
|
- DEBUG_PRINT_0(RAR_DEBUG_LEVEL_EXTENDED,
|
|
|
- "error getting RAR addresses device\n");
|
|
|
- registered = 0;
|
|
|
+ pci_disable_device(dev);
|
|
|
+
|
|
|
+ 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);
|
|
|
|
|
|
end_function:
|
|
|
|
|
|
return error;
|
|
|
}
|
|
|
|
|
|
-/*
|
|
|
- this function registers the driver to
|
|
|
- the device subsystem (either PCI, USB, etc)
|
|
|
-*/
|
|
|
+const struct pci_device_id rar_pci_id_tbl[] = {
|
|
|
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_RAR_DEVICE_ID) },
|
|
|
+ { 0 }
|
|
|
+};
|
|
|
+
|
|
|
+MODULE_DEVICE_TABLE(pci, rar_pci_id_tbl);
|
|
|
+
|
|
|
+const struct pci_device_id *my_id_table = rar_pci_id_tbl;
|
|
|
+
|
|
|
+/* field for registering driver to PCI device */
|
|
|
+static struct pci_driver rar_pci_driver = {
|
|
|
+ .name = "rar_register_driver",
|
|
|
+ .id_table = rar_pci_id_tbl,
|
|
|
+ .probe = rar_probe
|
|
|
+};
|
|
|
+
|
|
|
static int __init rar_init_handler(void)
|
|
|
{
|
|
|
return pci_register_driver(&rar_pci_driver);
|
|
@@ -382,59 +599,4 @@ module_init(rar_init_handler);
|
|
|
module_exit(rar_exit_handler);
|
|
|
|
|
|
MODULE_LICENSE("GPL");
|
|
|
-
|
|
|
-
|
|
|
-/* 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 get_rar_address(int rar_index, struct RAR_address_struct *addresses)
|
|
|
-{
|
|
|
- if (registered && (rar_index < 3) && (rar_index >= 0)) {
|
|
|
- *addresses = rar_addr[rar_index];
|
|
|
- /* strip off lock bit information */
|
|
|
- addresses->low = addresses->low & 0xfffffff0;
|
|
|
- addresses->high = addresses->high & 0xfffffff0;
|
|
|
- return 0;
|
|
|
- } else
|
|
|
- return -ENODEV;
|
|
|
-}
|
|
|
-EXPORT_SYMBOL(get_rar_address);
|
|
|
-
|
|
|
-/* The lock_rar function is used 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 lock_rar(int rar_index)
|
|
|
-{
|
|
|
- u32 working_addr;
|
|
|
- int result;
|
|
|
-
|
|
|
- if (registered && (rar_index < 3) && (rar_index >= 0)) {
|
|
|
- /* first make sure that lock bits are clear (this does lock) */
|
|
|
- working_addr = rar_addr[rar_index].low & 0xfffffff0;
|
|
|
-
|
|
|
- /* now send that value to the register using the IPC */
|
|
|
- result = memrar_set_rar_addr(rar_dev, rar_index, working_addr);
|
|
|
- return result;
|
|
|
- } else
|
|
|
- return -ENODEV;
|
|
|
-}
|
|
|
+MODULE_DESCRIPTION("Intel Restricted Access Region Register Driver");
|