diff options
Diffstat (limited to 'meta/recipes-kernel/linux/linux-netbook-2.6.33.2/linux-2.6.34-moorestown-rar-handler-driver-3.1.patch')
-rw-r--r-- | meta/recipes-kernel/linux/linux-netbook-2.6.33.2/linux-2.6.34-moorestown-rar-handler-driver-3.1.patch | 2531 |
1 files changed, 0 insertions, 2531 deletions
diff --git a/meta/recipes-kernel/linux/linux-netbook-2.6.33.2/linux-2.6.34-moorestown-rar-handler-driver-3.1.patch b/meta/recipes-kernel/linux/linux-netbook-2.6.33.2/linux-2.6.34-moorestown-rar-handler-driver-3.1.patch deleted file mode 100644 index a1a0fd61a..000000000 --- a/meta/recipes-kernel/linux/linux-netbook-2.6.33.2/linux-2.6.34-moorestown-rar-handler-driver-3.1.patch +++ /dev/null @@ -1,2531 +0,0 @@ -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 |