aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging/rar/rar_register.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/rar/rar_register.c')
-rw-r--r--drivers/staging/rar/rar_register.c440
1 files changed, 440 insertions, 0 deletions
diff --git a/drivers/staging/rar/rar_register.c b/drivers/staging/rar/rar_register.c
new file mode 100644
index 000000000000..51eb5a360f1c
--- /dev/null
+++ b/drivers/staging/rar/rar_register.c
@@ -0,0 +1,440 @@
+#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>
+#include "rar_register.h"
+
+/* The following defines are for the IPC process to retrieve RAR in */
+
+/* === Lincroft Message Bus Interface === */
+/* Message Control Register */
+#define LNC_MCR_OFFSET 0xD0
+
+/* Message Data Register */
+#define LNC_MDR_OFFSET 0xD4
+
+/* Message Opcodes */
+#define LNC_MESSAGE_READ_OPCODE 0xD0
+#define LNC_MESSAGE_WRITE_OPCODE 0xE0
+
+/* Message Write Byte Enables */
+#define LNC_MESSAGE_BYTE_WRITE_ENABLES 0xF
+
+/* B-unit Port */
+#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
+
+/* Reserved for SeP */
+#define LNC_BRAR2L 0x14
+#define LNC_BRAR2H 0x15
+
+
+/* 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;
+
+/* Moorestown supports three restricted access regions. */
+#define MRST_NUM_RAR 3
+
+struct RAR_address_struct rar_addr[MRST_NUM_RAR];
+
+/* prototype for init */
+static int __init rar_init_handler(void);
+static void __exit rar_exit_handler(void);
+
+/*
+ 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);
+
+static const struct pci_device_id rar_pci_id_tbl[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x4110) },
+ { 0 }
+};
+
+MODULE_DEVICE_TABLE(pci, rar_pci_id_tbl);
+
+/* 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
+};
+
+/* 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)
+{
+ /*
+ * ======== 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.
+ */
+
+ 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);
+
+ printk(KERN_WARNING "rar- offset to LNC MSG is %x\n", offset);
+
+ if (addr == 0)
+ return -EINVAL;
+
+ /* Send the control message */
+ result = pci_write_config_dword(pdev,
+ LNC_MCR_OFFSET,
+ message);
+
+ printk(KERN_WARNING "rar- result from send ctl register is %x\n",
+ result);
+
+ if (!result)
+ result = pci_read_config_dword(pdev,
+ LNC_MDR_OFFSET,
+ addr);
+
+ printk(KERN_WARNING "rar- result from read data register is %x\n",
+ result);
+
+ printk(KERN_WARNING "rar- value read from data register is %x\n",
+ *addr);
+
+ if (result)
+ return -1;
+ else
+ return 0;
+}
+
+static int memrar_set_rar_addr(struct pci_dev *pdev,
+ int offset,
+ u32 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.
+ */
+
+ int result = 0; /* result */
+
+ /* 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);
+
+ if (addr == 0)
+ return -EINVAL;
+
+ /* Send the control message */
+ result = pci_write_config_dword(pdev,
+ LNC_MDR_OFFSET,
+ addr);
+
+ printk(KERN_WARNING "rar- result from send ctl register is %x\n",
+ result);
+
+ if (!result)
+ result = pci_write_config_dword(pdev,
+ LNC_MCR_OFFSET,
+ message);
+
+ printk(KERN_WARNING "rar- result from write data register is %x\n",
+ result);
+
+ printk(KERN_WARNING "rar- value read to data register is %x\n",
+ addr);
+
+ if (result)
+ return -1;
+ else
+ return 0;
+}
+
+/*
+
+ * Initialize RAR parameters, such as physical addresses, etc.
+
+ */
+static int memrar_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;
+ int result = 0;
+
+ /* Retrieve RAR start and end physical addresses. */
+
+ /*
+ * 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;
+ }
+ }
+
+ /* 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);
+ }
+ }
+ }
+
+ return result;
+}
+
+/*
+ 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)
+{
+ /* error */
+ int error;
+
+ /*------------------------
+ CODE
+ ---------------------------*/
+
+ DEBUG_PRINT_0(RAR_DEBUG_LEVEL_EXTENDED,
+ "Rar pci probe starting\n");
+ error = 0;
+
+ /* enable the device */
+ error = pci_enable_device(pdev);
+ if (error) {
+ DEBUG_PRINT_0(RAR_DEBUG_LEVEL_EXTENDED,
+ "error enabling 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);
+
+ if (error) {
+ DEBUG_PRINT_0(RAR_DEBUG_LEVEL_EXTENDED,
+ "error getting RAR addresses device\n");
+ registered = 0;
+ goto end_function;
+ }
+
+end_function:
+
+ return error;
+}
+
+/*
+ this function registers the driver to
+ the device subsystem (either PCI, USB, etc)
+*/
+static int __init rar_init_handler(void)
+{
+ return pci_register_driver(&rar_pci_driver);
+}
+
+static void __exit rar_exit_handler(void)
+{
+ pci_unregister_driver(&rar_pci_driver);
+}
+
+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;
+}