From alan@lxorguk.ukuu.org.uk Fri Aug 7 16:47:35 2009 From: Alan Cox Date: Thu, 06 Aug 2009 20:44:18 +0100 Subject: Staging: sep: Move the RAR support into staging where it is supposed to be To: greg@kroah.com, mark.a.allyn@intel.com Message-ID: <20090806194414.18419.75295.stgit@localhost.localdomain> From: Alan Cox Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/staging/Kconfig | 2 drivers/staging/Makefile | 1 drivers/staging/rar/Kconfig | 17 + drivers/staging/rar/Makefile | 2 drivers/staging/rar/rar_driver.c | 450 +++++++++++++++++++++++++++++++++++++++ drivers/staging/rar/rar_driver.h | 99 ++++++++ 6 files changed, 571 insertions(+) create mode 100755 drivers/staging/rar/Kconfig create mode 100755 drivers/staging/rar/Makefile create mode 100755 drivers/staging/rar/rar_driver.c create mode 100755 drivers/staging/rar/rar_driver.h --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -135,6 +135,8 @@ source "drivers/staging/hv/Kconfig" source "drivers/staging/vme/Kconfig" +source "drivers/staging/rar/Kconfig" + source "drivers/staging/sep/Kconfig" endif # !STAGING_EXCLUDE_BUILD --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -49,4 +49,5 @@ obj-$(CONFIG_USB_CPC) += cpc-usb/ obj-$(CONFIG_FB_UDL) += udlfb/ obj-$(CONFIG_HYPERV) += hv/ obj-$(CONFIG_VME_BUS) += vme/ +obj-$(CONFIG_RAR_REGISTER) += rar/ obj-$(CONFIG_DX_SEP) += sep/ --- /dev/null +++ b/drivers/staging/rar/Kconfig @@ -0,0 +1,17 @@ +# +# RAR device configuration +# + +menu "RAR Register Driver" +# +# Restricted Access Register Manager +# +config RAR_REGISTER + tristate "Restricted Access Region Register Driver" + default n + ---help--- + This driver allows other kernel drivers access to the + contents of the restricted access region control + registers. + +endmenu --- /dev/null +++ b/drivers/staging/rar/Makefile @@ -0,0 +1,2 @@ +EXTRA_CFLAGS += -DLITTLE__ENDIAN +obj-$(CONFIG_RAR_REGISTER) += rar_driver.o --- /dev/null +++ b/drivers/staging/rar/rar_driver.c @@ -0,0 +1,450 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "rar_driver.h" + +/* PCI vendor id for controler */ +#define VENDOR_ID 0x8086 + +/* PCI device id for controler */ +#define DEVICE_ID 0x4110 + +/* 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 succesfull probe of the RAR device +*/ +static int __devinit rar_probe(struct pci_dev *pdev, struct pci_device_id *ent); + +static struct pci_device_id rar_pci_id_tbl[] = { + { PCI_DEVICE(VENDOR_ID, DEVICE_ID) }, + { 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[%u] 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 activaed on the succesfull probe of the RAR device +*/ +static int __devinit rar_probe(struct pci_dev *pdev, 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 th 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 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 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; + } +} --- /dev/null +++ b/drivers/staging/rar/rar_driver.h @@ -0,0 +1,99 @@ +/* === RAR Physical Addresses === */ +struct RAR_address_struct { + u32 low; + u32 high; +}; + +/* 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); + + +/* 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 lock_rar(int rar_index); + + +/* DEBUG LEVEL MASKS */ +#define RAR_DEBUG_LEVEL_BASIC 0x1 + +#define RAR_DEBUG_LEVEL_REGISTERS 0x2 + +#define RAR_DEBUG_LEVEL_EXTENDED 0x4 + +#define DEBUG_LEVEL 0x7 + +/* FUNCTIONAL MACROS */ + +/* debug macro without paramaters */ +#define DEBUG_PRINT_0(DEBUG_LEVEL , info) \ +do \ +{ \ + if(DEBUG_LEVEL) \ + { \ + printk(KERN_WARNING info); \ + } \ +}while(0) + +/* debug macro with 1 paramater */ +#define DEBUG_PRINT_1(DEBUG_LEVEL , info , param1) \ +do \ +{ \ + if(DEBUG_LEVEL) \ + { \ + printk(KERN_WARNING info , param1); \ + } \ +}while(0) + +/* debug macro with 2 paramaters */ +#define DEBUG_PRINT_2(DEBUG_LEVEL , info , param1, param2) \ +do \ +{ \ + if(DEBUG_LEVEL) \ + { \ + printk(KERN_WARNING info , param1, param2); \ + } \ +}while(0) + +/* debug macro with 3 paramaters */ +#define DEBUG_PRINT_3(DEBUG_LEVEL , info , param1, param2 , param3) \ +do \ +{ \ + if(DEBUG_LEVEL) \ + { \ + printk(KERN_WARNING info , param1, param2 , param3); \ + } \ +}while(0) + +/* debug macro with 4 paramaters */ +#define DEBUG_PRINT_4(DEBUG_LEVEL , info , param1, param2 , param3 , param4) \ +do \ +{ \ + if(DEBUG_LEVEL) \ + { \ + printk(KERN_WARNING info , param1, param2 , param3 , param4); \ + } \ +}while(0) +