summaryrefslogtreecommitdiff
path: root/meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-moorestown-rar-handler-driver-3.1.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-moorestown-rar-handler-driver-3.1.patch')
-rw-r--r--meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-moorestown-rar-handler-driver-3.1.patch2531
1 files changed, 2531 insertions, 0 deletions
diff --git a/meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-moorestown-rar-handler-driver-3.1.patch b/meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-moorestown-rar-handler-driver-3.1.patch
new file mode 100644
index 000000000..a1a0fd61a
--- /dev/null
+++ b/meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-moorestown-rar-handler-driver-3.1.patch
@@ -0,0 +1,2531 @@
+Index: linux-2.6.33/drivers/staging/Kconfig
+===================================================================
+--- linux-2.6.33.orig/drivers/staging/Kconfig
++++ linux-2.6.33/drivers/staging/Kconfig
+@@ -141,5 +141,7 @@ source "drivers/staging/netwave/Kconfig"
+
+ source "drivers/staging/sm7xx/Kconfig"
+
++source "drivers/staging/rar_register/Kconfig"
++
+ endif # !STAGING_EXCLUDE_BUILD
+ endif # STAGING
+Index: linux-2.6.33/drivers/staging/Makefile
+===================================================================
+--- linux-2.6.33.orig/drivers/staging/Makefile
++++ linux-2.6.33/drivers/staging/Makefile
+@@ -38,7 +38,7 @@ obj-$(CONFIG_VT6656) += vt6656/
+ obj-$(CONFIG_FB_UDL) += udlfb/
+ obj-$(CONFIG_HYPERV) += hv/
+ obj-$(CONFIG_VME_BUS) += vme/
+-obj-$(CONFIG_RAR_REGISTER) += rar/
++obj-$(CONFIG_RAR_DRIVER) += rar/
+ obj-$(CONFIG_DX_SEP) += sep/
+ obj-$(CONFIG_IIO) += iio/
+ obj-$(CONFIG_RAMZSWAP) += ramzswap/
+@@ -52,3 +52,4 @@ obj-$(CONFIG_WAVELAN) += wavelan/
+ obj-$(CONFIG_PCMCIA_WAVELAN) += wavelan/
+ obj-$(CONFIG_PCMCIA_NETWAVE) += netwave/
+ obj-$(CONFIG_FB_SM7XX) += sm7xx/
++obj-$(CONFIG_RAR_REGISTER) += rar_register/
+Index: linux-2.6.33/drivers/staging/rar_register/Kconfig
+===================================================================
+--- /dev/null
++++ linux-2.6.33/drivers/staging/rar_register/Kconfig
+@@ -0,0 +1,14 @@
++#
++# Serial device configuration
++#
++
++menu "RAR Register Driver"
++
++config RAR_REGISTER
++ tristate "Intel Restricted Access Region Register Driver"
++ default n
++ ---help---
++ This driver allows other kernel drivers access to the
++ contents of the restricted access region registers.
++
++endmenu
+Index: linux-2.6.33/drivers/staging/rar_register/Makefile
+===================================================================
+--- /dev/null
++++ linux-2.6.33/drivers/staging/rar_register/Makefile
+@@ -0,0 +1,3 @@
++EXTRA_CFLAGS += -DLITTLE__ENDIAN
++obj-$(CONFIG_RAR_REGISTER) += rar_register.o
++rar_register_driver-objs := rar_register.o
+Index: linux-2.6.33/drivers/staging/rar_register/rar_register.c
+===================================================================
+--- /dev/null
++++ linux-2.6.33/drivers/staging/rar_register/rar_register.c
+@@ -0,0 +1,669 @@
++/*
++ * 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.
++ *
++ * -------------------------------------------------------------------
++ *
++ * 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
++ */
++
++#include <linux/rar/rar_register.h>
++#include <linux/rar/memrar.h>
++
++#include <linux/module.h>
++#include <linux/pci.h>
++#include <linux/spinlock.h>
++#include <linux/device.h>
++#include <linux/kernel.h>
++
++
++/* PCI vendor id for controller */
++#define VENDOR_ID 0x8086
++
++/* PCI device id for controller */
++#define DEVICE_ID 0x4110
++
++
++/* === 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
++
++/* Moorestown supports three restricted access regions. */
++#define MRST_NUM_RAR 3
++
++
++/* RAR Bus Address Range */
++struct RAR_address_range {
++ u32 low;
++ u32 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. */
++};
++
++struct RAR_client {
++ int (*client_callback)(void *client_data);
++ void *customer_data;
++ int client_called;
++ };
++
++DEFINE_SPINLOCK(rar_spinlock_lock);
++DEFINE_SPINLOCK(lnc_reg_lock);
++
++struct RAR_device {
++ unsigned long rar_flags;
++ unsigned long lnc_reg_flags;
++ struct RAR_offsets rar_offsets[MRST_NUM_RAR];
++ struct RAR_address_range rar_addr[MRST_NUM_RAR];
++ struct pci_dev *rar_dev;
++ u32 registered;
++ };
++
++/* this platform has only one rar_device for 3 rar regions */
++struct RAR_device my_rar_device;
++
++/* flag to indicatew whether or not this driver is registered;
++ * this is for the entire driver and not just a device */
++int driver_registered;
++
++/* this data is for handling requests from other drivers which arrive
++ * prior to this driver initializing
++ */
++
++struct RAR_client clients[MRST_NUM_RAR];
++int num_clients;
++
++/* prototype for init */
++static int __init rar_init_handler(void);
++static void __exit rar_exit_handler(void);
++
++const struct pci_device_id rar_pci_id_tbl[] = {
++ { PCI_DEVICE(VENDOR_ID, DEVICE_ID) },
++ { 0 }
++};
++
++MODULE_DEVICE_TABLE(pci, rar_pci_id_tbl);
++
++/*
++ * Function that is activated 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);
++
++/* field for registering driver to PCI device */
++static struct pci_driver rar_pci_driver = {
++ .name = "rar_register",
++ .id_table = rar_pci_id_tbl,
++ .probe = rar_probe
++};
++
++const struct pci_device_id *my_id_table = rar_pci_id_tbl;
++
++/*
++ * This function is used to retrieved RAR info using the Lincroft
++ * 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;
++
++ /* Construct control message */
++ u32 const message =
++ (LNC_MESSAGE_READ_OPCODE << 24)
++ | (LNC_BUNIT_PORT << 16)
++ | (offset << 8)
++ | (LNC_MESSAGE_BYTE_WRITE_ENABLES << 4);
++
++ dev_dbg(&pdev->dev, "Offset for 'get' LNC MSG is %x\n", offset);
++
++ if (addr == 0) {
++ WARN_ON(1);
++ return -EINVAL;
++ }
++
++ spin_lock_irqsave(&lnc_reg_lock, my_rar_device.lnc_reg_flags);
++
++ /* 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,
++ addr);
++
++ dev_dbg(&pdev->dev,
++ "Result from read data register is %x\n",
++ result);
++
++ dev_dbg(&pdev->dev,
++ "Value read from data register is %x\n",
++ *addr);
++ }
++
++ spin_unlock_irqrestore(&lnc_reg_lock, my_rar_device.lnc_reg_flags);
++
++ return result;
++}
++
++static int memrar_set_rar_addr(struct pci_dev *pdev,
++ int offset,
++ u32 addr)
++{
++ /*
++ * Data being written to this register must be written before
++ * writing the appropriate control message to the MCR
++ * register.
++ *
++ * @note See memrar_get_rar_addr() for a description of the
++ * message bus interface being used here.
++ */
++
++ 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);
++
++ if (addr == 0) {
++ WARN_ON(1);
++ return -EINVAL;
++ }
++
++ spin_lock_irqsave(&lnc_reg_lock, my_rar_device.lnc_reg_flags);
++
++ dev_dbg(&pdev->dev,
++ "Offset for 'set' LNC MSG is %x\n", offset);
++
++ /* 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 %x\n",
++ addr);
++
++ result = pci_write_config_dword(pdev,
++ LNC_MCR_OFFSET,
++ message);
++
++ dev_dbg(&pdev->dev,
++ "Result from send ctl register is %x\n",
++ result);
++ }
++
++ spin_unlock_irqrestore(&lnc_reg_lock, my_rar_device.lnc_reg_flags);
++
++ return result;
++}
++
++/*
++ * Initialize RAR parameters, such as bus addresses, etc.
++ */
++static int memrar_init_rar_params(struct pci_dev *pdev)
++{
++ struct RAR_offsets const *end = my_rar_device.rar_offsets
++ + MRST_NUM_RAR;
++ struct RAR_offsets const *i;
++ struct pci_dev *my_pdev;
++ unsigned int n = 0;
++ int result = 0;
++
++ /* 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.
++ */
++
++ /* struct pci_dev *pdev = pci_get_bus_and_slot(0, PCI_DEVFN(0,0)); */
++
++ my_pdev = pci_dev_get(pdev);
++
++ if (my_pdev == NULL) {
++ WARN_ON(1);
++ return -ENODEV;
++ }
++
++ for (i = my_rar_device.rar_offsets; i != end; ++i, ++n) {
++ if (memrar_get_rar_addr(my_pdev,
++ i->low,
++ &(my_rar_device.rar_addr[n].low)) != 0
++ || memrar_get_rar_addr(my_pdev,
++ i->high,
++ &(my_rar_device.rar_addr[n].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
++ * high = 0x3fffffff
++ *
++ * This is not arbitrary, and is actually how RAR
++ * addressing/configuration works.
++ */
++ my_rar_device.rar_addr[n].low &= 0xfffffc00u;
++
++ /*
++ * Set bits 9:0 if the 1 KiB aligned (the upper 22
++ * bits) high address is non-zero.
++ *
++ * Otherwise set all bits to zero since that indicates
++ * no RAR address is configured.
++ */
++ if ((my_rar_device.rar_addr[n].high & 0xfffffc00u) == 0)
++ my_rar_device.rar_addr[n].high = 0;
++ else
++ my_rar_device.rar_addr[n].high |= 0x3ffu;
++ }
++
++ /* Done accessing the device. */
++ /* pci_dev_put(pdev); */
++
++ if (result == 0) {
++ size_t 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 = "
++ "[0x%08x, 0x%08x]\n",
++ z,
++ my_rar_device.rar_addr[z].low,
++ my_rar_device.rar_addr[z].high);
++ }
++ }
++
++ return result;
++}
++
++/*
++ * This function registers the driver with 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");
++MODULE_DESCRIPTION("Intel Restricted Access Region Register Driver");
++
++/*
++ * Function that is activaed on the succesful probe of the RAR device
++ * (Moorestown host controller).
++ */
++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(dev);
++ if (error) {
++ dev_err(&dev->dev,
++ "Error enabling RAR register PCI device\n");
++ goto end_function;
++ }
++
++ /* we have only one device; fill in the rar_device structure */
++ my_rar_device.rar_dev = dev;
++ my_rar_device.rar_flags = 0;
++ my_rar_device.lnc_reg_flags = 0;
++ my_rar_device.rar_offsets[0].low = LNC_BRAR0L;
++ my_rar_device.rar_offsets[0].high = LNC_BRAR0H;
++ my_rar_device.rar_offsets[1].low = LNC_BRAR1L;
++ my_rar_device.rar_offsets[1].high = LNC_BRAR1H;
++ my_rar_device.rar_offsets[2].low = LNC_BRAR2L;
++ my_rar_device.rar_offsets[2].high = LNC_BRAR2H;
++ my_rar_device.registered = 1;
++
++ /*
++ * Initialize the RAR parameters, which have to be retrieved */
++ /* via the message bus interface.
++ */
++ error = memrar_init_rar_params(dev);
++ if (error) {
++ pci_disable_device(dev);
++
++ dev_err(&dev->dev,
++ "Error retrieving RAR addresses\n");
++
++ goto end_function;
++ }
++
++ driver_registered = 1;
++
++ /* now call anyone who has registered (using callbacks) */
++ for (counter = 0; counter < num_clients; counter += 1) {
++ if (!clients[counter].client_called) {
++ error = (*clients[counter].client_callback)(
++ clients[counter].customer_data);
++ clients[counter].client_called = 1;
++ dev_dbg(&my_rar_device.rar_dev->dev,
++ "Callback called for %d\n",
++ counter);
++ }
++ }
++
++end_function:
++
++ return error;
++}
++
++
++/*
++ * 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,
++ u32 *start_address,
++ u32 *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);
++
++/*
++ * 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;
++ goto exit_rar_lock;
++ }
++
++ spin_lock_irqsave(&rar_spinlock_lock, my_rar_device.rar_flags);
++
++ if (my_rar_device.registered) {
++
++ u32 low;
++ u32 high;
++
++ /*
++ * Clear bits 4:0 in low register to lock.
++ * Clear bits 8,4:0 in high register to lock.
++ *
++ * The rest of the lower 10 bits in both registers are
++ * unused so we might as well clear them all.
++ */
++ if (rar_index == RAR_TYPE_VIDEO) {
++ low = my_rar_device.rar_addr[rar_index].low &
++ 0xfffffc00u;
++ high = my_rar_device.rar_addr[rar_index].high &
++ 0xfffffc00u;
++ low |= 0x00000009;
++ high |= 0x00000015;
++ }
++
++ else if (rar_index == RAR_TYPE_AUDIO) {
++ low = my_rar_device.rar_addr[rar_index].low &
++ 0xfffffc00u;
++ high = my_rar_device.rar_addr[rar_index].high &
++ 0xfffffc00u;
++ low |= 0x00000008;
++ high |= 0x00000018;
++ }
++
++ else {
++ low = my_rar_device.rar_addr[rar_index].low &
++ 0xfffffc00u;
++ high = my_rar_device.rar_addr[rar_index].high &
++ 0xfffffc00u;
++ high |= 0x00000018;
++ }
++
++ /*
++ * Now program the register using the Lincroft message
++ * bus interface.
++ */
++ result = memrar_set_rar_addr(my_rar_device.rar_dev,
++ my_rar_device.rar_offsets[rar_index].low,
++ low);
++
++ if (result == 0)
++ result = memrar_set_rar_addr(
++ my_rar_device.rar_dev,
++ my_rar_device.rar_offsets[rar_index].high,
++ high);
++ }
++
++ spin_unlock_irqrestore(&rar_spinlock_lock, my_rar_device.rar_flags);
++
++exit_rar_lock:
++
++ 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 get_rar_address()
++ * This function return 0 on success an -1 on failure.
++ */
++int register_rar(int (*callback)(void *yourparameter), void *yourparameter)
++{
++
++ int result;
++
++ result = 0;
++
++ if (driver_registered) {
++
++ /* if the driver already registered, then we can simply
++ call the callback right now */
++
++ result = (*callback)(yourparameter);
++ if (result) {
++ dev_dbg(&my_rar_device.rar_dev->dev,
++ "Immediate Callback failed: %x\n",
++ result);
++ } else {
++ dev_dbg(&my_rar_device.rar_dev->dev,
++ "Immediate Callback ran okay\n");
++ }
++
++ return result;
++ }
++
++ else if (num_clients >= MRST_NUM_RAR) {
++ return -ENODEV;
++ }
++
++ else {
++
++ clients[num_clients].client_callback = callback;
++ clients[num_clients].customer_data = yourparameter;
++ clients[num_clients].client_called = 0;
++ num_clients += 1;
++ dev_dbg(&my_rar_device.rar_dev->dev, "Callback registered\n");
++ }
++
++return result;
++
++}
++EXPORT_SYMBOL(register_rar);
++
++/*
++ Local Variables:
++ c-file-style: "linux"
++ End:
++*/
+Index: linux-2.6.33/include/linux/rar/memrar.h
+===================================================================
+--- /dev/null
++++ linux-2.6.33/include/linux/rar/memrar.h
+@@ -0,0 +1,172 @@
++/*
++ * RAR Handler (/dev/memrar) internal driver API.
++ * 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 version 2 of the GNU General
++ * Public License as published by the Free Software Foundation.
++ *
++ * 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.
++ * The full GNU General Public License is included in this
++ * distribution in the file called COPYING.
++ */
++
++
++#ifndef _MEMRAR_H
++#define _MEMRAR_H
++
++#include <linux/ioctl.h>
++#include <linux/types.h>
++
++
++/*
++ * Constants that specify different kinds of RAR regions that could be
++ * set up.
++ */
++static __u32 const RAR_TYPE_VIDEO; /* 0 */
++static __u32 const RAR_TYPE_AUDIO = 1;
++static __u32 const RAR_TYPE_IMAGE = 2;
++static __u32 const RAR_TYPE_DATA = 3;
++
++/*
++ * @struct RAR_stat
++ *
++ * @brief This structure is used for @c RAR_HANDLER_STAT ioctl and for
++ * @c RAR_get_stat() user space wrapper function.
++ */
++struct RAR_stat {
++ /* Type of RAR memory (e.g., audio vs. video) */
++ __u32 type;
++
++ /*
++ * Total size of RAR memory region.
++ */
++ __u32 capacity;
++
++ /* Size of the largest reservable block. */
++ __u32 largest_block_size;
++};
++
++
++/*
++ * @struct RAR_block_info
++ *
++ * @brief The argument for the @c RAR_HANDLER_RESERVE @c ioctl.
++ *
++ */
++struct RAR_block_info {
++ /* Type of RAR memory (e.g., audio vs. video) */
++ __u32 type;
++
++ /* Requested size of a block to be reserved in RAR. */
++ __u32 size;
++
++ /* Handle that can be used to refer to reserved block. */
++ __u32 handle;
++};
++
++/*
++ * @struct RAR_buffer
++ *
++ * Structure that contains all information related to a given block of
++ * memory in RAR. It is generally only used when retrieving bus
++ * addresses.
++ *
++ * @note This structure is used only by RAR-enabled drivers, and is
++ * not intended to be exposed to the user space.
++ */
++struct RAR_buffer {
++ /* Structure containing base RAR buffer information */
++ struct RAR_block_info info;
++
++ /* Buffer bus address */
++ __u32 bus_address;
++};
++
++
++#define RAR_IOCTL_BASE 0xE0
++
++/* Reserve RAR block. */
++#define RAR_HANDLER_RESERVE _IOWR(RAR_IOCTL_BASE, 0x00, struct RAR_block_info)
++
++/* Release previously reserved RAR block. */
++#define RAR_HANDLER_RELEASE _IOW(RAR_IOCTL_BASE, 0x01, __u32)
++
++/* Get RAR stats. */
++#define RAR_HANDLER_STAT _IOWR(RAR_IOCTL_BASE, 0x02, struct RAR_stat)
++
++
++/* -------------------------------------------------------------- */
++/* Kernel Side RAR Handler Interface */
++/* -------------------------------------------------------------- */
++
++/*
++ * @function rar_reserve
++ *
++ * @brief Reserve RAR buffers.
++ *
++ * This function will reserve buffers in the restricted access regions
++ * of given types.
++ *
++ * @return Number of successfully reserved buffers.
++ * Successful buffer reservations will have the corresponding
++ * @c bus_address field set to a non-zero value in the
++ * given @a buffers vector.
++ */
++extern size_t rar_reserve(struct RAR_buffer *buffers,
++ size_t count);
++
++/*
++ * @function rar_release
++ *
++ * @brief Release RAR buffers retrieved through call to
++ * @c rar_reserve() or @c rar_handle_to_bus().
++ *
++ * This function will release RAR buffers that were retrieved through
++ * a call to @c rar_reserve() or @c rar_handle_to_bus() by
++ * decrementing the reference count. The RAR buffer will be reclaimed
++ * when the reference count drops to zero.
++ *
++ * @return Number of successfully released buffers.
++ * Successful releases will have their handle field set to
++ * zero in the given @a buffers vector.
++ */
++extern size_t rar_release(struct RAR_buffer *buffers,
++ size_t count);
++
++/*
++ * @function rar_handle_to_bus
++ *
++ * @brief Convert a vector of RAR handles to bus addresses.
++ *
++ * This function will retrieve the RAR buffer bus addresses, type and
++ * size corresponding to the RAR handles provided in the @a buffers
++ * vector.
++ *
++ * @return Number of successfully converted buffers.
++ * The bus address will be set to @c 0 for unrecognized
++ * handles.
++ *
++ * @note The reference count for each corresponding buffer in RAR will
++ * be incremented. Call @c rar_release() when done with the
++ * buffers.
++ */
++extern size_t rar_handle_to_bus(struct RAR_buffer *buffers,
++ size_t count);
++
++
++#endif /* _MEMRAR_H */
++
++
++/*
++ Local Variables:
++ c-file-style: "linux"
++ End:
++*/
+Index: linux-2.6.33/include/linux/rar/rar_register.h
+===================================================================
+--- /dev/null
++++ linux-2.6.33/include/linux/rar/rar_register.h
+@@ -0,0 +1,79 @@
++/*
++ * Copyright (C) 2008, 2009 Intel Corporation. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of version 2 of the GNU General
++ * Public License as published by the Free Software Foundation.
++ *
++ * 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.
++ * The full GNU General Public License is included in this
++ * distribution in the file called COPYING.
++ */
++
++
++#ifndef _RAR_REGISTER_H
++#define _RAR_REGISTER_H
++
++# include <linux/types.h>
++
++/* 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,
++ u32 *start_address,
++ u32 *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 rar_lock(int rar_index);
++
++
++#endif /* _RAR_REGISTER_H */
++
++
++/*
++ Local Variables:
++ c-file-style: "linux"
++ End:
++*/
+Index: linux-2.6.33/drivers/misc/Kconfig
+===================================================================
+--- linux-2.6.33.orig/drivers/misc/Kconfig
++++ linux-2.6.33/drivers/misc/Kconfig
+@@ -249,6 +249,17 @@ config SGI_GRU_DEBUG
+ This option enables addition debugging code for the SGI GRU driver. If
+ you are unsure, say N.
+
++config MRST_RAR_HANDLER
++ tristate "RAR handler driver for Intel Moorestown platform"
++ depends on X86
++ select RAR_REGISTER
++ ---help---
++ This driver provides a memory management interface to
++ restricted access regions available in the Intel Moorestown
++ platform.
++
++ If unsure, say N.
++
+ config MRST_VIB
+ tristate "vibrator driver for Intel Moorestown platform"
+ help
+Index: linux-2.6.33/drivers/misc/Makefile
+===================================================================
+--- linux-2.6.33.orig/drivers/misc/Makefile
++++ linux-2.6.33/drivers/misc/Makefile
+@@ -22,6 +22,8 @@ obj-$(CONFIG_CS5535_MFGPT) += cs5535-mfg
+ obj-$(CONFIG_HP_ILO) += hpilo.o
+ obj-$(CONFIG_MRST) += intel_mrst.o
+ obj-$(CONFIG_ISL29003) += isl29003.o
++obj-$(CONFIG_MRST_RAR_HANDLER) += memrar.o
++memrar-y := memrar_allocator.o memrar_handler.o
+ obj-$(CONFIG_MRST_VIB) += mrst_vib.o
+ obj-$(CONFIG_EP93XX_PWM) += ep93xx_pwm.o
+ obj-$(CONFIG_DS1682) += ds1682.o
+Index: linux-2.6.33/drivers/misc/memrar_allocator.c
+===================================================================
+--- /dev/null
++++ linux-2.6.33/drivers/misc/memrar_allocator.c
+@@ -0,0 +1,374 @@
++/*
++ * memrar_allocator 0.2: An allocator for Intel RAR.
++ *
++ * 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 version 2 of the GNU General
++ * Public License as published by the Free Software Foundation.
++ *
++ * 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.
++ * The full GNU General Public License is included in this
++ * distribution in the file called COPYING.
++ *
++ *
++ * ------------------------------------------------------------------
++ *
++ * This simple allocator implementation provides a
++ * malloc()/free()-like interface for reserving space within a
++ * previously reserved block of memory. It is not specific to
++ * any hardware, nor is it coupled with the lower level paging
++ * mechanism.
++ *
++ * The primary goal of this implementation is to provide a means
++ * to partition an arbitrary block of memory without actually
++ * accessing the memory or incurring any hardware side-effects
++ * (e.g. paging). It is, in effect, a bookkeeping mechanism for
++ * buffers.
++ */
++
++
++#include "memrar_allocator.h"
++#include <linux/slab.h>
++#include <linux/bug.h>
++#include <linux/kernel.h>
++
++
++struct memrar_allocator *memrar_create_allocator(unsigned long base,
++ size_t capacity,
++ size_t block_size)
++{
++ struct memrar_allocator *allocator = NULL;
++ struct memrar_free_list *first_node = NULL;
++
++ /*
++ * Make sure the base address is aligned on a block_size
++ * boundary.
++ *
++ * @todo Is this necessary?
++ */
++ /* base = ALIGN(base, block_size); */
++
++ /* Validate parameters.
++ *
++ * Make sure we can allocate the entire memory allocator
++ * space. Zero capacity or block size are obviously invalid.
++ */
++ if (base == 0
++ || capacity == 0
++ || block_size == 0
++ || ULONG_MAX - capacity < base
++ || capacity < block_size)
++ return allocator;
++
++ /*
++ * There isn't much point in creating a memory allocator that
++ * is only capable of holding one block but we'll allow it,
++ * and issue a diagnostic.
++ */
++ WARN(capacity < block_size * 2,
++ "memrar: Only one block available to allocator.\n");
++
++ allocator = kmalloc(sizeof(*allocator), GFP_KERNEL);
++
++ if (allocator == NULL)
++ return allocator;
++
++ mutex_init(&allocator->lock);
++ allocator->base = base;
++
++ /* Round the capacity down to a multiple of block_size. */
++ allocator->capacity = (capacity / block_size) * block_size;
++
++ allocator->block_size = block_size;
++
++ allocator->largest_free_area = allocator->capacity;
++
++ /* Initialize the handle and free lists. */
++ INIT_LIST_HEAD(&allocator->handle_list.list);
++ INIT_LIST_HEAD(&allocator->free_list.list);
++
++ first_node = kmalloc(sizeof(*first_node), GFP_KERNEL);
++ if (first_node == NULL) {
++ kfree(allocator);
++ allocator = NULL;
++ } else {
++ /* Full range of blocks is available. */
++ first_node->begin = base;
++ first_node->end = base + allocator->capacity;
++ list_add(&first_node->list,
++ &allocator->free_list.list);
++ }
++
++ return allocator;
++}
++
++void memrar_destroy_allocator(struct memrar_allocator *allocator)
++{
++ /*
++ * Assume that the memory allocator lock isn't held at this
++ * point in time. Caller must ensure that.
++ */
++
++ struct memrar_free_list *pos;
++ struct memrar_free_list *n;
++
++ if (allocator == NULL)
++ return;
++
++ mutex_lock(&allocator->lock);
++
++ /* Reclaim free list resources. */
++ list_for_each_entry_safe(pos,
++ n,
++ &allocator->free_list.list,
++ list) {
++ list_del(&pos->list);
++ kfree(pos);
++ }
++
++ mutex_unlock(&allocator->lock);
++
++ kfree(allocator);
++}
++
++unsigned long memrar_allocator_alloc(struct memrar_allocator *allocator,
++ size_t size)
++{
++ struct memrar_free_list *pos = NULL;
++
++ size_t num_blocks;
++ unsigned long reserved_bytes;
++
++ /*
++ * Address of allocated buffer. We assume that zero is not a
++ * valid address.
++ */
++ unsigned long addr = 0;
++
++ if (allocator == NULL || size == 0)
++ return addr;
++
++ /* Reserve enough blocks to hold the amount of bytes requested. */
++ num_blocks = DIV_ROUND_UP(size, allocator->block_size);
++
++ reserved_bytes = num_blocks * allocator->block_size;
++
++ mutex_lock(&allocator->lock);
++
++ if (reserved_bytes > allocator->largest_free_area) {
++ mutex_unlock(&allocator->lock);
++ return addr;
++ }
++
++ /*
++ * Iterate through the free list to find a suitably sized
++ * range of free contiguous memory blocks.
++ */
++ list_for_each_entry(pos, &allocator->free_list.list, list) {
++ size_t const curr_size = pos->end - pos->begin;
++
++ if (curr_size >= reserved_bytes) {
++ struct memrar_handle *handle = NULL;
++ struct memrar_handle_list * const new_node =
++ kmalloc(sizeof(*new_node), GFP_KERNEL);
++
++ if (new_node == NULL)
++ break;
++
++ list_add(&new_node->list,
++ &allocator->handle_list.list);
++
++ handle = &new_node->handle;
++ handle->end = pos->end;
++ pos->end -= reserved_bytes;
++ handle->begin = pos->end;
++ addr = handle->begin;
++
++ if (curr_size == allocator->largest_free_area)
++ allocator->largest_free_area -=
++ reserved_bytes;
++
++ break;
++ }
++ }
++
++ mutex_unlock(&allocator->lock);
++
++ return addr;
++}
++
++long memrar_allocator_free(struct memrar_allocator *allocator,
++ unsigned long addr)
++{
++ struct list_head *pos = NULL;
++ struct list_head *tmp = NULL;
++ struct memrar_handle_list *handles = NULL;
++ struct memrar_handle *handle = NULL;
++ struct memrar_free_list *new_node = NULL;
++ int result = -ENOMEM;
++
++ if (allocator == NULL)
++ return -EINVAL;
++
++ if (addr == 0)
++ return 0; /* Ignore free(0). */
++
++ mutex_lock(&allocator->lock);
++
++ /* Find the corresponding handle. */
++ list_for_each_entry(handles,
++ &allocator->handle_list.list,
++ list) {
++ if (handles->handle.begin == addr) {
++ handle = &handles->handle;
++ break;
++ }
++ }
++
++ /* No such buffer created by this allocator. */
++ if (handle == NULL) {
++ mutex_unlock(&allocator->lock);
++ return -EFAULT;
++ }
++
++ /*
++ * Coalesce adjacent chunks of memory if possible.
++ *
++ * @note This isn't full blown coalescing since we're only
++ * coalescing at most three chunks of memory.
++ */
++ list_for_each_safe(pos, tmp, &allocator->free_list.list) {
++ /* @todo O(n) performance. Optimize. */
++
++ struct memrar_free_list * const chunk =
++ list_entry(pos,
++ struct memrar_free_list,
++ list);
++
++ struct memrar_free_list * const next =
++ list_entry(pos->next,
++ struct memrar_free_list,
++ list);
++
++ /* Extend size of existing free adjacent chunk. */
++ if (chunk->end == handle->begin) {
++ /*
++ * Chunk "less than" than the one we're
++ * freeing is adjacent.
++ */
++
++ unsigned long new_chunk_size;
++
++ chunk->end = handle->end;
++
++ /*
++ * Now check if next free chunk is adjacent to
++ * the current extended free chunk.
++ */
++ if (pos != pos->next
++ && chunk->end == next->begin) {
++ chunk->end = next->end;
++ list_del(pos->next);
++ kfree(next);
++ }
++
++ new_chunk_size = chunk->end - chunk->begin;
++
++ if (new_chunk_size > allocator->largest_free_area)
++ allocator->largest_free_area =
++ new_chunk_size;
++
++ result = 0;
++ goto exit_memrar_free;
++ } else if (chunk->begin == handle->end) {
++ /*
++ * Chunk "greater than" than the one we're
++ * freeing is adjacent.
++ */
++
++ unsigned long new_chunk_size;
++
++ chunk->begin = handle->begin;
++
++ /*
++ * Now check if next free chunk is adjacent to
++ * the current extended free chunk.
++ */
++ if (pos != pos->next
++ && chunk->begin == next->end) {
++ chunk->begin = next->begin;
++ list_del(pos->next);
++ kfree(next);
++ }
++
++ new_chunk_size = chunk->end - chunk->begin;
++
++ if (new_chunk_size > allocator->largest_free_area)
++ allocator->largest_free_area =
++ new_chunk_size;
++
++ result = 0;
++ goto exit_memrar_free;
++ }
++ }
++
++ /*
++ * Memory being freed is not adjacent to existing free areas
++ * of memory in the allocator. Add a new item to the free list.
++ *
++ * @todo Allocate this free_list node when the buffer itself
++ * is allocated to avoid a potential problem where a new
++ * node cannot be allocated due to lack of available
++ * kernel memory. We can then free this node in the
++ * above coalescing code node if it isn't needed.
++ *
++ * @todo While making this change would address potential
++ * memory allocation failure, it would also
++ * unfortunately reduce performance of buffer allocation
++ * provided by this allocator.
++ */
++ new_node = kmalloc(sizeof(*new_node), GFP_KERNEL);
++ if (new_node != NULL) {
++ unsigned long new_chunk_size;
++
++ new_node->begin = handle->begin;
++ new_node->end = handle->end;
++ list_add(&new_node->list,
++ &allocator->free_list.list);
++
++ new_chunk_size = handle->end - handle->begin;
++
++ if (new_chunk_size > allocator->largest_free_area)
++ allocator->largest_free_area =
++ new_chunk_size;
++
++ result = 0;
++ }
++
++exit_memrar_free:
++
++ if (result == 0)
++ list_del(&handles->list);
++
++ mutex_unlock(&allocator->lock);
++
++ kfree(handles);
++
++ return result;
++}
++
++
++
++/*
++ Local Variables:
++ c-file-style: "linux"
++ End:
++*/
+Index: linux-2.6.33/drivers/misc/memrar_allocator.h
+===================================================================
+--- /dev/null
++++ linux-2.6.33/drivers/misc/memrar_allocator.h
+@@ -0,0 +1,165 @@
++/*
++ * 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 version 2 of the GNU General
++ * Public License as published by the Free Software Foundation.
++ *
++ * 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.
++ * The full GNU General Public License is included in this
++ * distribution in the file called COPYING.
++ */
++
++#ifndef MEMRAR_ALLOCATOR_H
++#define MEMRAR_ALLOCATOR_H
++
++
++#include <linux/mutex.h>
++#include <linux/list.h>
++#include <linux/types.h>
++#include <linux/kernel.h>
++
++/*
++ * @struct memrar_free_list
++ *
++ * @brief List of available areas of memory.
++ */
++struct memrar_free_list {
++ /* Linked list of free memory allocator blocks. */
++ struct list_head list;
++
++ /* Beginning of available address range. */
++ unsigned long begin;
++
++ /*
++ * End of available address range, one past the end,
++ * i.e. [begin, end).
++ */
++ unsigned long end;
++};
++
++struct memrar_allocator;
++
++/* Structure that describes a chunk memory reserved by the allocator. */
++struct memrar_handle {
++ /* Beginning of available address range. */
++ unsigned long begin;
++
++ /*
++ * End of available address range, one past the end,
++ * i.e. [begin, end).
++ */
++ unsigned long end;
++};
++
++/*
++ * @struct memrar_handle_list
++ *
++ * @brief List of handles corresponding to allocated blocks of memory.
++ */
++struct memrar_handle_list {
++ /* Linked list of handles corresponding to allocated blocks. */
++ struct list_head list;
++
++ /* Handle for the allocated block of memory. */
++ struct memrar_handle handle;
++};
++
++/*
++ * @struct memrar_allocator
++ *
++ * @brief Encapsulation of the memory allocator state.
++ *
++ * This structure contains all memory allocator state, including the
++ * base address, capacity, free list, lock, etc.
++ */
++struct memrar_allocator {
++ /*
++ * Lock used to synchronize access to the memory allocator
++ * state.
++ */
++ struct mutex lock;
++
++ /* Base (start) address of the memory allocator. */
++ unsigned long base;
++
++ /* Size of the memory allocator in bytes. */
++ size_t capacity;
++
++ /*
++ * The size in bytes of individual blocks within the memory
++ * allocator.
++ */
++ size_t block_size;
++
++ /* Largest free area of memory in the allocator in bytes. */
++ size_t largest_free_area;
++
++ /* List of handles for allocated blocks of memory. */
++ struct memrar_handle_list handle_list;
++
++ /* List of free address ranges. */
++ struct memrar_free_list free_list;
++};
++
++/*
++ * @function memrar_create_allocator
++ *
++ * @brief Create a memory allocator.
++ *
++ * Create a memory allocator with the given capacity and block size.
++ * The capacity will be reduced to be a multiple of the block size, if
++ * necessary.
++ *
++ * @param base Address at which the memory allocator begins.
++ * @param capacity Desired size of the memory allocator. This value
++ * must be larger than the block_size, ideally more
++ * than twice as large since there wouldn't be much
++ * point in using a memory allocator otherwise.
++ * @param block_size The size of individual blocks within the memory
++ * allocator. This value must smaller than the
++ * capacity.
++ * @return An instance of the memory allocator, if creation succeeds.
++ * @return Zero if creation fails. Failure may occur if not enough
++ * kernel memory exists to create the memrar_allocator
++ * instance itself, or if the capacity and block_size
++ * arguments are not compatible or make sense.
++ */
++struct memrar_allocator *memrar_create_allocator(unsigned long base,
++ size_t capacity,
++ size_t block_size);
++
++/*
++ * Reclaim resources held by the memory allocator. The caller must
++ * explicitly free all memory reserved by memrar_allocator_alloc()
++ * prior to calling this function. Otherwise leaks will occur.
++ */
++void memrar_destroy_allocator(struct memrar_allocator *allocator);
++
++/*
++ * Reserve chunk of memory of given size in the memory allocator.
++ */
++unsigned long memrar_allocator_alloc(struct memrar_allocator *allocator,
++ size_t size);
++
++/*
++ * Reserve chunk of memory of given size in the memory allocator.
++ */
++long memrar_allocator_free(struct memrar_allocator *allocator,
++ unsigned long handle);
++
++#endif /* MEMRAR_ALLOCATOR_H */
++
++
++/*
++ Local Variables:
++ c-file-style: "linux"
++ End:
++*/
+Index: linux-2.6.33/drivers/misc/memrar_handler.c
+===================================================================
+--- /dev/null
++++ linux-2.6.33/drivers/misc/memrar_handler.c
+@@ -0,0 +1,929 @@
++/*
++ * memrar_handler 1.0: An Intel restricted access region handler device
++ *
++ * 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 version 2 of the GNU General
++ * Public License as published by the Free Software Foundation.
++ *
++ * 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.
++ * The full GNU General Public License is included in this
++ * distribution in the file called COPYING.
++ *
++ * -------------------------------------------------------------------
++ *
++ * Moorestown restricted access regions (RAR) provide isolated
++ * areas of main memory that are only acceessible by authorized
++ * devices.
++ *
++ * The Intel Moorestown RAR handler module exposes a kernel space
++ * RAR memory management mechanism. It is essentially a
++ * RAR-specific allocator.
++ *
++ * Besides providing RAR buffer management, the RAR handler also
++ * behaves in many ways like an OS virtual memory manager. For
++ * example, the RAR "handles" created by the RAR handler are
++ * analogous to user space virtual addresses.
++ *
++ * RAR memory itself is never accessed directly by the RAR
++ * handler.
++ *
++ * -------------------------------------------------------------------
++ *
++ * TODO
++ *
++ * 1. Split user space interface from core/kernel code, e.g.:
++ * memrar_handler.c -> memrar_core.c, memrar_user.c
++ *
++ * 2. Convert API documentation to Kerneldoc.
++ *
++ * 3. Move memrar_allocator.* to kernel lib' directory since it
++ * is HW neutral.
++ * a. Alternatively, use lib/genalloc.c instead.
++ * b. A kernel port of Doug Lea's malloc() implementation may
++ * also be an option.
++ */
++
++#include <linux/miscdevice.h>
++#include <linux/fs.h>
++#include <linux/slab.h>
++#include <linux/kref.h>
++#include <linux/mutex.h>
++#include <linux/kernel.h>
++#include <linux/uaccess.h>
++#include <linux/mm.h>
++#include <linux/ioport.h>
++#include <linux/io.h>
++
++#include <linux/rar/rar_register.h>
++#include <linux/rar/memrar.h>
++
++#include "memrar_allocator.h"
++
++
++#define MEMRAR_VER "1.0"
++
++/*
++ * Moorestown supports three restricted access regions.
++ *
++ * We only care about the first two, video and audio. The third,
++ * reserved for Chaabi and the P-unit, will be handled by their
++ * respective drivers.
++ */
++#define MRST_NUM_RAR 2
++
++/* ---------------- -------------------- ------------------- */
++
++/*
++ * List structure that keeps track of all RAR buffers.
++ */
++struct memrar_buffer_info {
++ /* Linked list of memrar_buffer_info objects. */
++ struct list_head list;
++
++ /* Core RAR buffer information. */
++ struct RAR_buffer buffer;
++
++ /* Reference count */
++ struct kref refcount;
++
++ /*
++ * File handle corresponding to process that reserved the
++ * block of memory in RAR. This will be zero for buffers
++ * allocated by other drivers instead of by a user space
++ * process.
++ */
++ struct file *owner;
++};
++
++/*
++ * Structure that describes that characteristics of a given RAR.
++ */
++struct memrar_rar_info {
++ /* Base bus address of the RAR. */
++ unsigned long base;
++
++ /* Length of the RAR. */
++ unsigned long length;
++
++ /* Virtual address of RAR mapped into kernel. */
++ void __iomem *iobase;
++
++ /*
++ * Allocator associated with the RAR.
++ *
++ * @note The allocator "capacity" may be smaller than the RAR
++ * length if the length is not a multiple of the
++ * configured allocator block size.
++ */
++ struct memrar_allocator *allocator;
++
++ /*
++ * Table that keeps track of all reserved RAR buffers.
++ */
++ struct memrar_buffer_info buffers;
++
++ /*
++ * Lock used to synchronize access to RAR-specific data
++ * structures.
++ */
++ struct mutex lock;
++};
++
++/*
++ * Array of RAR characteristics.
++ */
++static struct memrar_rar_info memrars[MRST_NUM_RAR];
++
++
++/* ---------------- -------------------- ------------------- */
++
++/* Validate RAR type. */
++static inline int memrar_is_valid_rar_type(u32 type)
++{
++ return type == RAR_TYPE_VIDEO || type == RAR_TYPE_AUDIO;
++}
++
++/* Check if an address/handle falls with the given RAR memory range. */
++static inline int memrar_handle_in_range(struct memrar_rar_info *rar,
++ u32 vaddr)
++{
++ unsigned long const iobase = (unsigned long) (rar->iobase);
++ return (vaddr >= iobase && vaddr < iobase + rar->length);
++}
++
++/* Retrieve RAR information associated with the given handle. */
++static struct memrar_rar_info *memrar_get_rar_info(u32 vaddr)
++{
++ int i;
++ for (i = 0; i < MRST_NUM_RAR; ++i) {
++ struct memrar_rar_info * const rar = &memrars[i];
++ if (memrar_handle_in_range(rar, vaddr))
++ return rar;
++ }
++
++ return NULL;
++}
++
++/*
++ * Retrieve bus address from given handle.
++ *
++ * @return Address corresponding to given handle. Zero if handle
++ * is invalid.
++ */
++static unsigned long memrar_get_bus_address(
++ struct memrar_rar_info *rar,
++ u32 vaddr)
++{
++ unsigned long const iobase = (unsigned long) (rar->iobase);
++
++ if (!memrar_handle_in_range(rar, vaddr))
++ return 0;
++
++ /*
++ * An assumption is made that the virtual address offset is
++ * the same as the bus address offset, at least based on the
++ * way this driver is implemented. For example, vaddr + 2 ==
++ * baddr + 2.
++ *
++ * @todo Is that a valid assumption?
++ */
++ return rar->base + (vaddr - iobase);
++}
++
++/*
++ * Retrieve physical address from given handle.
++ *
++ * @return Address corresponding to given handle. Zero if handle
++ * is invalid.
++ */
++static unsigned long memrar_get_physical_address(
++ struct memrar_rar_info *rar,
++ u32 vaddr)
++{
++ /*
++ * @todo This assumes that the bus address and physical
++ * address are the same. That is true for Moorestown
++ * but not necessarily on other platforms. This
++ * deficiency should be addressed at some point.
++ */
++ return memrar_get_bus_address(rar, vaddr);
++}
++
++/*
++ * Core block release code.
++ *
++ * @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)
++{
++ /*
++ * Last reference is being released. Remove from the table,
++ * and reclaim resources.
++ */
++
++ struct memrar_buffer_info * const node =
++ container_of(ref, struct memrar_buffer_info, refcount);
++
++ struct RAR_block_info * const user_info =
++ &node->buffer.info;
++
++ struct memrar_allocator * const allocator =
++ memrars[user_info->type].allocator;
++
++ list_del(&node->list);
++
++ memrar_allocator_free(allocator, user_info->handle);
++
++ kfree(node);
++}
++
++/*
++ * Initialize RAR parameters, such as bus addresses, etc.
++ */
++static int memrar_init_rar_resources(char const *devname)
++{
++ /* ---- Sanity Checks ----
++ * 1. RAR bus addresses in both Lincroft and Langwell RAR
++ * registers should be the same.
++ * 2. Secure device ID in Langwell RAR registers should be set
++ * appropriately, i.e. only LPE DMA for the audio RAR, and
++ * security for the other Langwell based RAR register. The
++ * video RAR is not accessed from the Langwell side,
++ * meaning its corresponding Langwell RAR should only be
++ * accessible by the security engine.
++ * 3. Audio and video RAR register and RAR access should be
++ * locked. If not, lock them. Except for debugging
++ * purposes, there is no reason for them to be unlocked.
++ *
++ * @todo Should the RAR handler driver even be aware of audio
++ * and video RAR settings?
++ */
++
++ /*
++ * RAR buffer block size.
++ *
++ * We choose it to be the size of a page to simplify the
++ * /dev/memrar mmap() implementation and usage. Otherwise
++ * paging is not involved once an RAR is locked down.
++ */
++ static size_t const RAR_BLOCK_SIZE = PAGE_SIZE;
++
++ int z;
++ int found_rar = 0;
++
++ BUG_ON(MRST_NUM_RAR != ARRAY_SIZE(memrars));
++
++ for (z = 0; z != MRST_NUM_RAR; ++z) {
++ u32 low, high;
++ struct memrar_rar_info * const rar = &memrars[z];
++
++ BUG_ON(!memrar_is_valid_rar_type(z));
++
++ 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 physical 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) {
++ /* @todo Enable once LNW A2 is widely available. */
++ rar_lock(z);
++ } else {
++ pr_warning("%s: LNC RAR[%d] no lock sanity check.\n",
++ devname,
++ z);
++ }
++
++ /* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ */
++ /* |||||||||||||||||||||||||||||||||||||||||||||||||| */
++
++ /*
++ * Enable RAR protection on the Langwell side.
++ *
++ * Ideally Langwell side RAR protection should already
++ * have been enabled by the OEM in the SMIP header but
++ * we perform a sanity check, just in case.
++ *
++ * @todo Set appropriate "lock"/"valid" bits in LNW
++ * {LOW,UP}RAR[12] SCCB registers **and** LNW
++ * {LOW,UP}RAR[01] cDMI registers only if a
++ * suitable SDID (i.e. for security or LPE DMA)
++ * is set.
++ */
++ pr_warning("%s: LNW RAR[%d] no lock sanity check.\n",
++ devname,
++ z);
++
++
++ pr_info("%s: BRAR[%d]\n"
++ "\tlow address: 0x%x\n"
++ "\thigh address: 0x%x\n"
++ "\tsize : %u KiB\n",
++ devname,
++ z,
++ low,
++ high,
++ 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);
++ return -ENODEV;
++ }
++
++ return 0;
++}
++
++/*
++ * Finalize RAR resources.
++ */
++static void memrar_fini_rar_resources(void)
++{
++ int z;
++ struct memrar_buffer_info *pos;
++ struct memrar_buffer_info *tmp;
++
++ /*
++ * @todo Do we need to hold a lock at this point in time?
++ * (module initialization failure or exit?)
++ */
++
++ for (z = MRST_NUM_RAR; z-- != 0; ) {
++ struct memrar_rar_info * const rar = &memrars[z];
++
++ /* Clean up remaining resources. */
++
++ list_for_each_entry_safe(pos,
++ tmp,
++ &rar->buffers.list,
++ list) {
++ kref_put(&pos->refcount, memrar_release_block_i);
++ }
++
++ memrar_destroy_allocator(rar->allocator);
++ rar->allocator = NULL;
++
++ iounmap(rar->iobase);
++ rar->iobase = NULL;
++
++ release_mem_region(rar->base, rar->length);
++ rar->base = 0;
++
++ rar->length = 0;
++ }
++}
++
++static long memrar_reserve_block(struct RAR_buffer *request,
++ struct file *filp)
++{
++ struct RAR_block_info * const rinfo = &request->info;
++ struct RAR_buffer *buffer;
++ struct memrar_buffer_info *buffer_info;
++ u32 handle;
++ struct memrar_rar_info *rar = NULL;
++
++ /* Prevent array overflow. */
++ if (!memrar_is_valid_rar_type(rinfo->type))
++ return -EINVAL;
++
++ rar = &memrars[rinfo->type];
++
++ /* Reserve memory in RAR. */
++ handle = memrar_allocator_alloc(rar->allocator, rinfo->size);
++ if (handle == 0)
++ return -ENOMEM;
++
++ buffer_info = kmalloc(sizeof(*buffer_info), GFP_KERNEL);
++
++ if (buffer_info == NULL) {
++ memrar_allocator_free(rar->allocator, handle);
++ return -ENOMEM;
++ }
++
++ buffer = &buffer_info->buffer;
++ buffer->info.type = rinfo->type;
++ buffer->info.size = rinfo->size;
++
++ /* Memory handle corresponding to the bus address. */
++ buffer->info.handle = handle;
++ buffer->bus_address = memrar_get_bus_address(rar, handle);
++
++ /*
++ * Keep track of owner so that we can later cleanup if
++ * necessary.
++ */
++ buffer_info->owner = filp;
++
++ kref_init(&buffer_info->refcount);
++
++ mutex_lock(&rar->lock);
++ list_add(&buffer_info->list, &rar->buffers.list);
++ mutex_unlock(&rar->lock);
++
++ rinfo->handle = buffer->info.handle;
++ request->bus_address = buffer->bus_address;
++
++ return 0;
++}
++
++static long memrar_release_block(u32 addr)
++{
++ struct memrar_buffer_info *pos;
++ struct memrar_buffer_info *tmp;
++ struct memrar_rar_info * const rar = memrar_get_rar_info(addr);
++ long result = -EINVAL;
++
++ if (rar == NULL)
++ return -EFAULT;
++
++ mutex_lock(&rar->lock);
++
++ /*
++ * Iterate through the buffer list to find the corresponding
++ * buffer to be released.
++ */
++ list_for_each_entry_safe(pos,
++ tmp,
++ &rar->buffers.list,
++ list) {
++ if (addr == pos->buffer.info.handle
++ && memrar_is_valid_rar_type(pos->buffer.info.type)) {
++ kref_put(&pos->refcount, memrar_release_block_i);
++ result = 0;
++ break;
++ }
++ }
++
++ mutex_unlock(&rar->lock);
++
++ return result;
++}
++
++static long memrar_get_stat(struct RAR_stat *r)
++{
++ long result = -EINVAL;
++
++ if (likely(r != NULL) && memrar_is_valid_rar_type(r->type)) {
++ struct memrar_allocator * const allocator =
++ memrars[r->type].allocator;
++
++ BUG_ON(allocator == NULL);
++
++ /*
++ * Allocator capacity doesn't change over time. No
++ * need to synchronize.
++ */
++ r->capacity = allocator->capacity;
++
++ mutex_lock(&allocator->lock);
++
++ r->largest_block_size = allocator->largest_free_area;
++
++ mutex_unlock(&allocator->lock);
++
++ result = 0;
++ }
++
++ return result;
++}
++
++static long memrar_ioctl(struct file *filp,
++ unsigned int cmd,
++ unsigned long arg)
++{
++ void __user *argp = (void __user *)arg;
++ long result = 0;
++
++ struct RAR_buffer buffer;
++ struct RAR_block_info * const request = &buffer.info;
++ struct RAR_stat rar_info;
++ u32 rar_handle;
++
++ switch (cmd) {
++ case RAR_HANDLER_RESERVE:
++ if (copy_from_user(request,
++ argp,
++ sizeof(*request)))
++ return -EFAULT;
++
++ result = memrar_reserve_block(&buffer, filp);
++ if (result != 0)
++ return result;
++
++ return copy_to_user(argp, request, sizeof(*request));
++
++ case RAR_HANDLER_RELEASE:
++ if (copy_from_user(&rar_handle,
++ argp,
++ sizeof(rar_handle)))
++ return -EFAULT;
++
++ return memrar_release_block(rar_handle);
++
++ case RAR_HANDLER_STAT:
++ if (copy_from_user(&rar_info,
++ argp,
++ sizeof(rar_info)))
++ return -EFAULT;
++
++ /*
++ * Populate the RAR_stat structure based on the RAR
++ * type given by the user
++ */
++ if (memrar_get_stat(&rar_info) != 0)
++ return -EINVAL;
++
++ /*
++ * @todo Do we need to verify destination pointer
++ * "argp" is non-zero? Is that already done by
++ * copy_to_user()?
++ */
++ return copy_to_user(argp,
++ &rar_info,
++ sizeof(rar_info)) ? -EFAULT : 0;
++
++ default:
++ return -ENOTTY;
++ }
++
++ return 0;
++}
++
++static int memrar_mmap(struct file *filp, struct vm_area_struct *vma)
++{
++ size_t const size = vma->vm_end - vma->vm_start;
++
++ /* Users pass the RAR handle as the mmap() offset parameter. */
++ unsigned long const handle = vma->vm_pgoff << PAGE_SHIFT;
++
++ struct memrar_rar_info * const rar = memrar_get_rar_info(handle);
++
++ unsigned long pfn;
++
++ /* Invalid RAR handle or size passed to mmap(). */
++ if (rar == NULL
++ || handle == 0
++ || size > (handle - (unsigned long) rar->iobase))
++ return -EINVAL;
++
++ /*
++ * Retrieve physical address corresponding to the RAR handle,
++ * and convert it to a page frame.
++ */
++ pfn = memrar_get_physical_address(rar, handle) >> PAGE_SHIFT;
++
++
++ pr_debug("memrar: mapping RAR range [0x%lx, 0x%lx) into user space.\n",
++ handle,
++ handle + size);
++
++ /*
++ * Map RAR memory into user space. This is really only useful
++ * for debugging purposes since the memory won't be
++ * accesssible, i.e. reads return zero and writes are ignired,
++ * when it is locked down.
++ */
++ if (remap_pfn_range(vma,
++ vma->vm_start,
++ pfn,
++ size,
++ vma->vm_page_prot))
++ return -EAGAIN;
++
++ /* vma->vm_ops = &memrar_mem_ops; */
++
++ return 0;
++}
++
++static int memrar_open(struct inode *inode, struct file *filp)
++{
++ /* Nothing to do yet. */
++
++ return 0;
++}
++
++static int memrar_release(struct inode *inode, struct file *filp)
++{
++ /* Free all regions associated with the given file handle. */
++
++ struct memrar_buffer_info *pos;
++ struct memrar_buffer_info *tmp;
++ int z;
++
++ for (z = 0; z != MRST_NUM_RAR; ++z) {
++ struct memrar_rar_info * const rar = &memrars[z];
++
++ mutex_lock(&rar->lock);
++
++ list_for_each_entry_safe(pos,
++ tmp,
++ &rar->buffers.list,
++ list) {
++ if (filp == pos->owner)
++ kref_put(&pos->refcount,
++ memrar_release_block_i);
++ }
++
++ mutex_unlock(&rar->lock);
++ }
++
++ return 0;
++}
++
++/*
++ * @note This function is part of the kernel space memrar driver API.
++ */
++size_t rar_reserve(struct RAR_buffer *buffers, size_t count)
++{
++ struct RAR_buffer * const end =
++ (buffers == NULL ? buffers : buffers + count);
++ struct RAR_buffer *i;
++
++ size_t reserve_count = 0;
++
++ for (i = buffers; i != end; ++i) {
++ if (memrar_reserve_block(i, NULL) == 0)
++ ++reserve_count;
++ else
++ i->bus_address = 0;
++ }
++
++ return reserve_count;
++}
++EXPORT_SYMBOL(rar_reserve);
++
++/*
++ * @note This function is part of the kernel space memrar driver API.
++ */
++size_t rar_release(struct RAR_buffer *buffers, size_t count)
++{
++ struct RAR_buffer * const end =
++ (buffers == NULL ? buffers : buffers + count);
++ struct RAR_buffer *i;
++
++ size_t release_count = 0;
++
++ for (i = buffers; i != end; ++i) {
++ u32 * const handle = &i->info.handle;
++ if (memrar_release_block(*handle) == 0) {
++ /*
++ * @todo We assume we should do this each time
++ * the ref count is decremented. Should
++ * we instead only do this when the ref
++ * count has dropped to zero, and the
++ * buffer has been completely
++ * released/unmapped?
++ */
++ *handle = 0;
++ ++release_count;
++ }
++ }
++
++ return release_count;
++}
++EXPORT_SYMBOL(rar_release);
++
++/*
++ * @note This function is part of the kernel space driver API.
++ */
++size_t rar_handle_to_bus(struct RAR_buffer *buffers, size_t count)
++{
++ struct RAR_buffer * const end =
++ (buffers == NULL ? buffers : buffers + count);
++ struct RAR_buffer *i;
++ struct memrar_buffer_info *pos;
++
++ size_t conversion_count = 0;
++
++ /*
++ * Find all bus addresses corresponding to the given handles.
++ *
++ * @todo Not liking this nested loop. Optimize.
++ */
++ for (i = buffers; i != end; ++i) {
++ struct memrar_rar_info * const rar =
++ memrar_get_rar_info(i->info.handle);
++
++ /*
++ * Check if we have a bogus handle, and then continue
++ * with remaining buffers.
++ */
++ if (rar == NULL) {
++ i->bus_address = 0;
++ continue;
++ }
++
++ mutex_lock(&rar->lock);
++
++ list_for_each_entry(pos, &rar->buffers.list, list) {
++ struct RAR_block_info * const user_info =
++ &pos->buffer.info;
++
++ if (i->info.handle >= user_info->handle
++ && i->info.handle < (user_info->handle
++ + user_info->size)) {
++ u32 const offset =
++ i->info.handle - user_info->handle;
++
++ i->info.type = user_info->type;
++ i->info.size = user_info->size - offset;
++ i->bus_address =
++ pos->buffer.bus_address
++ + offset;
++
++ /* Increment the reference count. */
++ kref_get(&pos->refcount);
++
++ ++conversion_count;
++ break;
++ } else {
++ i->bus_address = 0;
++ }
++ }
++
++ mutex_unlock(&rar->lock);
++ }
++
++ return conversion_count;
++}
++EXPORT_SYMBOL(rar_handle_to_bus);
++
++static const struct file_operations memrar_fops = {
++ .owner = THIS_MODULE,
++ .unlocked_ioctl = memrar_ioctl,
++ .mmap = memrar_mmap,
++ .open = memrar_open,
++ .release = memrar_release,
++};
++
++static struct miscdevice memrar_miscdev = {
++ .minor = MISC_DYNAMIC_MINOR, /* dynamic allocation */
++ .name = "memrar", /* /dev/memrar */
++ .fops = &memrar_fops
++};
++
++static char const banner[] __initdata =
++ KERN_INFO
++ "Intel RAR Handler: " MEMRAR_VER " initialized.\n";
++
++static int __init memrar_init(void)
++{
++ int result = 0;
++
++ printk(banner);
++
++ /*
++ * We initialize the RAR parameters early on so that we can
++ * discontinue memrar device initialization and registration
++ * if suitably configured RARs are not available.
++ */
++ 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;
++}
++
++static void __exit memrar_exit(void)
++{
++ memrar_fini_rar_resources();
++
++ misc_deregister(&memrar_miscdev);
++}
++
++#ifndef MODULE
++/*
++ * The RAR handler must be initialized after the RAR register driver.
++ * Otherwise the RAR handler will always assume no RAR support
++ * exists.
++ */
++late_initcall_sync(memrar_init);
++#else
++module_init(memrar_init);
++#endif /* MODULE */
++
++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);
++
++
++
++/*
++ Local Variables:
++ c-file-style: "linux"
++ End:
++*/
+Index: linux-2.6.33/drivers/staging/rar/Kconfig
+===================================================================
+--- linux-2.6.33.orig/drivers/staging/rar/Kconfig
++++ linux-2.6.33/drivers/staging/rar/Kconfig
+@@ -6,7 +6,7 @@ menu "RAR Register Driver"
+ #
+ # Restricted Access Register Manager
+ #
+-config RAR_REGISTER
++config RAR_DRIVER
+ tristate "Restricted Access Region Register Driver"
+ default n
+ ---help---
+Index: linux-2.6.33/drivers/staging/rar/Makefile
+===================================================================
+--- linux-2.6.33.orig/drivers/staging/rar/Makefile
++++ linux-2.6.33/drivers/staging/rar/Makefile
+@@ -1,2 +1,2 @@
+ EXTRA_CFLAGS += -DLITTLE__ENDIAN
+-obj-$(CONFIG_RAR_REGISTER) += rar_driver.o
++obj-$(CONFIG_RAR_DRIVER) += rar_driver.o