linux-am335x-3.2.0-psp04.06.00.08: Add PSP v04.06.00.08 of the Linux kernel
authorFranklin S. Cooper Jr <fcooper@ti.com>
Fri, 12 Oct 2012 05:14:45 +0000 (00:14 -0500)
committerDenys Dmytriyenko <denys@ti.com>
Wed, 17 Oct 2012 20:24:06 +0000 (16:24 -0400)
* Add the PSP release version of the Linux kernel for the am335x-evm
* Include a variable called KERNEL_PATCHES which can be used to add
  patches on top of the PSP release of the Linux kernel. Currently used
  to apply various patches that add functionality or fixes bugs.

Signed-off-by: Franklin S. Cooper Jr <fcooper@ti.com>
Signed-off-by: Denys Dmytriyenko <denys@ti.com>
23 files changed:
recipes-kernel/linux/linux-am335x-3.2.0-psp04.06.00.08/0001-am3358-sk-modified-WLAN-enable-and-irq-to-match-boar.patch [new file with mode: 0644]
recipes-kernel/linux/linux-am335x-3.2.0-psp04.06.00.08/0001-am335x-Add-crypto-driver-settings-to-defconfig.patch [new file with mode: 0644]
recipes-kernel/linux/linux-am335x-3.2.0-psp04.06.00.08/0001-am335x-Add-pm_runtime-API-to-crypto-driver.patch [new file with mode: 0644]
recipes-kernel/linux/linux-am335x-3.2.0-psp04.06.00.08/0001-am335x-enable-pullup-on-the-WLAN-enable-pin-fo.patch [new file with mode: 0644]
recipes-kernel/linux/linux-am335x-3.2.0-psp04.06.00.08/0001-am335x_evm_defconfig-turn-off-MUSB-DMA.patch [new file with mode: 0644]
recipes-kernel/linux/linux-am335x-3.2.0-psp04.06.00.08/0001-am335xevm-using-edge-triggered-interrupts-for-WLAN.patch [new file with mode: 0644]
recipes-kernel/linux/linux-am335x-3.2.0-psp04.06.00.08/0001-am33x-Add-memory-addresses-for-crypto-modules.patch [new file with mode: 0644]
recipes-kernel/linux/linux-am335x-3.2.0-psp04.06.00.08/0001-am33xx-Add-SmartReflex-support.patch [new file with mode: 0644]
recipes-kernel/linux/linux-am335x-3.2.0-psp04.06.00.08/0001-mach-omap2-pm33xx-Disable-VT-switch.patch [new file with mode: 0644]
recipes-kernel/linux/linux-am335x-3.2.0-psp04.06.00.08/0001-musb-update-PIO-mode-help-information-in-Kconfig.patch [new file with mode: 0644]
recipes-kernel/linux/linux-am335x-3.2.0-psp04.06.00.08/0001-omap-serial-add-delay-before-suspending.patch [new file with mode: 0644]
recipes-kernel/linux/linux-am335x-3.2.0-psp04.06.00.08/0002-AM335x-OCF-Driver-for-Linux-3.patch [new file with mode: 0644]
recipes-kernel/linux/linux-am335x-3.2.0-psp04.06.00.08/0002-am335x-Add-suspend-resume-routines-to-crypto-driver.patch [new file with mode: 0644]
recipes-kernel/linux/linux-am335x-3.2.0-psp04.06.00.08/0002-am33x-Add-crypto-device-and-resource-structures.patch [new file with mode: 0644]
recipes-kernel/linux/linux-am335x-3.2.0-psp04.06.00.08/0002-am33xx-Enable-CONFIG_AM33XX_SMARTREFLEX.patch [new file with mode: 0644]
recipes-kernel/linux/linux-am335x-3.2.0-psp04.06.00.08/0003-am33x-Add-crypto-device-and-resource-structure-for-T.patch [new file with mode: 0644]
recipes-kernel/linux/linux-am335x-3.2.0-psp04.06.00.08/0004-am33x-Add-crypto-drivers-to-Kconfig-and-Makefiles.patch [new file with mode: 0644]
recipes-kernel/linux/linux-am335x-3.2.0-psp04.06.00.08/0005-am33x-Create-header-file-for-OMAP4-crypto-modules.patch [new file with mode: 0644]
recipes-kernel/linux/linux-am335x-3.2.0-psp04.06.00.08/0006-am33x-Create-driver-for-TRNG-crypto-module.patch [new file with mode: 0644]
recipes-kernel/linux/linux-am335x-3.2.0-psp04.06.00.08/0007-am33x-Create-driver-for-AES-crypto-module.patch [new file with mode: 0644]
recipes-kernel/linux/linux-am335x-3.2.0-psp04.06.00.08/0008-am33x-Create-driver-for-SHA-MD5-crypto-module.patch [new file with mode: 0644]
recipes-kernel/linux/linux-am335x-3.2.0-psp04.06.00.08/defconfig [new file with mode: 0644]
recipes-kernel/linux/linux-am335x_3.2.0-psp04.06.00.08.bb [new file with mode: 0644]

diff --git a/recipes-kernel/linux/linux-am335x-3.2.0-psp04.06.00.08/0001-am3358-sk-modified-WLAN-enable-and-irq-to-match-boar.patch b/recipes-kernel/linux/linux-am335x-3.2.0-psp04.06.00.08/0001-am3358-sk-modified-WLAN-enable-and-irq-to-match-boar.patch
new file mode 100644 (file)
index 0000000..25d2fdf
--- /dev/null
@@ -0,0 +1,62 @@
+From 69c82f68876d24e798388fc053c8d6766236ac65 Mon Sep 17 00:00:00 2001
+From: Vita Preskovsky <vitap@ti.com>
+Date: Thu, 28 Jun 2012 14:53:12 +0300
+Subject: [PATCH] am3358-sk: modified WLAN enable and irq to match board revision 1.2
+       * 1. WLAN enable and irq are modified to match board revision 1.2
+         2. support suspend/resume for SK board
+
+Upstream-Status: Pending
+
+Signed-off-by: Vita Preskovsky <vitap@ti.com>
+---
+ arch/arm/mach-omap2/board-am335xevm.c |   11 +++++++----
+ 1 files changed, 7 insertions(+), 4 deletions(-)
+
+diff --git a/arch/arm/mach-omap2/board-am335xevm.c b/arch/arm/mach-omap2/board-am335xevm.c
+index 64f7547..6ae4e68 100755
+--- a/arch/arm/mach-omap2/board-am335xevm.c
++++ b/arch/arm/mach-omap2/board-am335xevm.c
+@@ -905,7 +905,7 @@ static struct pinmux_config ecap2_pin_mux[] = {
+
+ #define AM335XEVM_WLAN_PMENA_GPIO     GPIO_TO_PIN(1, 30)
+ #define AM335XEVM_WLAN_IRQ_GPIO               GPIO_TO_PIN(3, 17)
+-#define AM335XEVM_SK_WLAN_IRQ_GPIO      GPIO_TO_PIN(1, 29)
++#define AM335XEVM_SK_WLAN_IRQ_GPIO      GPIO_TO_PIN(0, 31)
+
+ struct wl12xx_platform_data am335xevm_wlan_data = {
+       .irq = OMAP_GPIO_IRQ(AM335XEVM_WLAN_IRQ_GPIO),
+@@ -941,8 +941,8 @@ static struct pinmux_config wl12xx_pin_mux[] = {
+  };
+
+ static struct pinmux_config wl12xx_pin_mux_sk[] = {
+-      {"gpmc_wpn.gpio0_31", OMAP_MUX_MODE7 | AM33XX_PIN_OUTPUT},
+-      {"gpmc_csn0.gpio1_29", OMAP_MUX_MODE7 | AM33XX_PIN_INPUT},
++      {"gpmc_wpn.gpio0_31", OMAP_MUX_MODE7 | AM33XX_PIN_INPUT},
++      {"gpmc_csn0.gpio1_29", OMAP_MUX_MODE7 | AM33XX_PIN_OUTPUT_PULLUP},
+       {"mcasp0_ahclkx.gpio3_21", OMAP_MUX_MODE7 | AM33XX_PIN_OUTPUT},
+       {NULL, 0},
+ };
+@@ -1618,6 +1618,7 @@ static void mmc1_wl12xx_init(int evm_id, int profile)
+       am335x_mmc[1].name = "wl1271";
+       am335x_mmc[1].caps = MMC_CAP_4_BIT_DATA | MMC_CAP_POWER_OFF_CARD;
+       am335x_mmc[1].nonremovable = true;
++      am335x_mmc[1].pm_caps = MMC_PM_KEEP_POWER;
+       am335x_mmc[1].gpio_cd = -EINVAL;
+       am335x_mmc[1].gpio_wp = -EINVAL;
+       am335x_mmc[1].ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34; /* 3V3 */
+@@ -1674,10 +1675,12 @@ static void wl12xx_init(int evm_id, int profile)
+       int ret;
+
+       if (evm_id == EVM_SK) {
+-              am335xevm_wlan_data.wlan_enable_gpio = GPIO_TO_PIN(0, 31);
++              am335xevm_wlan_data.wlan_enable_gpio = GPIO_TO_PIN(1, 29);
+               am335xevm_wlan_data.bt_enable_gpio = GPIO_TO_PIN(3, 21);
+               am335xevm_wlan_data.irq =
+                               OMAP_GPIO_IRQ(AM335XEVM_SK_WLAN_IRQ_GPIO);
++              am335xevm_wlan_data.platform_quirks =
++                              WL12XX_PLATFORM_QUIRK_EDGE_IRQ;
+               setup_pin_mux(wl12xx_pin_mux_sk);
+       } else {
+               setup_pin_mux(wl12xx_pin_mux);
+--
+1.7.0.4
diff --git a/recipes-kernel/linux/linux-am335x-3.2.0-psp04.06.00.08/0001-am335x-Add-crypto-driver-settings-to-defconfig.patch b/recipes-kernel/linux/linux-am335x-3.2.0-psp04.06.00.08/0001-am335x-Add-crypto-driver-settings-to-defconfig.patch
new file mode 100644 (file)
index 0000000..46f02cb
--- /dev/null
@@ -0,0 +1,130 @@
+From 1edc97015f69fac420c32df514e1d1d546041d42 Mon Sep 17 00:00:00 2001
+From: Greg Turner <gregturner@ti.com>
+Date: Fri, 8 Jun 2012 13:54:13 -0500
+Subject: [PATCH] [am335x]: Add crypto driver settings to defconfig
+
+* Add Crypto Driver and configuration to defconfig
+---
+ arch/arm/configs/am335x_evm_defconfig |   39 +++++++++++++++++++++++---------
+ 1 files changed, 28 insertions(+), 11 deletions(-)
+ mode change 100644 => 100755 arch/arm/configs/am335x_evm_defconfig
+
+diff --git a/arch/arm/configs/am335x_evm_defconfig b/arch/arm/configs/am335x_evm_defconfig
+old mode 100644
+new mode 100755
+index de1eaad..0bf7efd
+--- a/arch/arm/configs/am335x_evm_defconfig
++++ b/arch/arm/configs/am335x_evm_defconfig
+@@ -1277,6 +1277,9 @@ CONFIG_SERIAL_OMAP_CONSOLE=y
+ # CONFIG_SERIAL_XILINX_PS_UART is not set
+ # CONFIG_HVC_DCC is not set
+ # CONFIG_IPMI_HANDLER is not set
++CONFIG_HW_RANDOM=y
++# CONFIG_HW_RANDOM_TIMERIOMEM is not set
++CONFIG_HW_RANDOM_OMAP4=y
+ # CONFIG_HW_RANDOM is not set
+ # CONFIG_R3964 is not set
+ # CONFIG_RAW_DRIVER is not set
+@@ -2472,36 +2475,38 @@ CONFIG_CRYPTO=y
+ #
+ CONFIG_CRYPTO_ALGAPI=y
+ CONFIG_CRYPTO_ALGAPI2=y
++CONFIG_CRYPTO_AEAD=y
+ CONFIG_CRYPTO_AEAD2=y
+ CONFIG_CRYPTO_BLKCIPHER=y
+ CONFIG_CRYPTO_BLKCIPHER2=y
+ CONFIG_CRYPTO_HASH=y
+ CONFIG_CRYPTO_HASH2=y
++CONFIG_CRYPTO_RNG=y
+ CONFIG_CRYPTO_RNG2=y
+ CONFIG_CRYPTO_PCOMP2=y
+ CONFIG_CRYPTO_MANAGER=y
+ CONFIG_CRYPTO_MANAGER2=y
+ # CONFIG_CRYPTO_USER is not set
+-CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y
++# CONFIG_CRYPTO_MANAGER_DISABLE_TESTS is not set
+ # CONFIG_CRYPTO_GF128MUL is not set
+ # CONFIG_CRYPTO_NULL is not set
+ CONFIG_CRYPTO_WORKQUEUE=y
+ # CONFIG_CRYPTO_CRYPTD is not set
+ # CONFIG_CRYPTO_AUTHENC is not set
+-# CONFIG_CRYPTO_TEST is not set
++CONFIG_CRYPTO_TEST=m
+
+ #
+ # Authenticated Encryption with Associated Data
+ #
+ # CONFIG_CRYPTO_CCM is not set
+ # CONFIG_CRYPTO_GCM is not set
+-# CONFIG_CRYPTO_SEQIV is not set
++CONFIG_CRYPTO_SEQIV=y
+
+ #
+ # Block modes
+ #
+-# CONFIG_CRYPTO_CBC is not set
+-# CONFIG_CRYPTO_CTR is not set
++CONFIG_CRYPTO_CBC=y
++CONFIG_CRYPTO_CTR=y
+ # CONFIG_CRYPTO_CTS is not set
+ CONFIG_CRYPTO_ECB=y
+ # CONFIG_CRYPTO_LRW is not set
+@@ -2511,7 +2516,7 @@ CONFIG_CRYPTO_ECB=y
+ #
+ # Hash modes
+ #
+-# CONFIG_CRYPTO_HMAC is not set
++CONFIG_CRYPTO_HMAC=y
+ # CONFIG_CRYPTO_XCBC is not set
+ # CONFIG_CRYPTO_VMAC is not set
+
+@@ -2521,14 +2526,14 @@ CONFIG_CRYPTO_ECB=y
+ CONFIG_CRYPTO_CRC32C=y
+ # CONFIG_CRYPTO_GHASH is not set
+ # CONFIG_CRYPTO_MD4 is not set
+-# CONFIG_CRYPTO_MD5 is not set
++CONFIG_CRYPTO_MD5=y
+ CONFIG_CRYPTO_MICHAEL_MIC=y
+ # CONFIG_CRYPTO_RMD128 is not set
+ # CONFIG_CRYPTO_RMD160 is not set
+ # CONFIG_CRYPTO_RMD256 is not set
+ # CONFIG_CRYPTO_RMD320 is not set
+-# CONFIG_CRYPTO_SHA1 is not set
+-# CONFIG_CRYPTO_SHA256 is not set
++CONFIG_CRYPTO_SHA1=y
++CONFIG_CRYPTO_SHA256=y
+ # CONFIG_CRYPTO_SHA512 is not set
+ # CONFIG_CRYPTO_TGR192 is not set
+ # CONFIG_CRYPTO_WP512 is not set
+@@ -2543,7 +2548,7 @@ CONFIG_CRYPTO_ARC4=y
+ # CONFIG_CRYPTO_CAMELLIA is not set
+ # CONFIG_CRYPTO_CAST5 is not set
+ # CONFIG_CRYPTO_CAST6 is not set
+-# CONFIG_CRYPTO_DES is not set
++CONFIG_CRYPTO_DES=y
+ # CONFIG_CRYPTO_FCRYPT is not set
+ # CONFIG_CRYPTO_KHAZAD is not set
+ # CONFIG_CRYPTO_SALSA20 is not set
+@@ -2565,7 +2570,19 @@ CONFIG_CRYPTO_LZO=y
+ # CONFIG_CRYPTO_ANSI_CPRNG is not set
+ # CONFIG_CRYPTO_USER_API_HASH is not set
+ # CONFIG_CRYPTO_USER_API_SKCIPHER is not set
+-# CONFIG_CRYPTO_HW is not set
++CONFIG_CRYPTO_HW=y
++CONFIG_CRYPTO_DEV_OMAP4_AES=y
++CONFIG_CRYPTO_DEV_OMAP4_SHAM=y
++
++#
++# OCF Configuration
++#
++CONFIG_OCF_OCF=y
++# CONFIG_OCF_RANDOMHARVEST is not set
++CONFIG_OCF_CRYPTODEV=y
++CONFIG_OCF_CRYPTOSOFT=y
++# CONFIG_OCF_OCFNULL is not set
++# CONFIG_OCF_BENCH is not set
+ # CONFIG_BINARY_PRINTF is not set
+
+ #
+--
+1.7.0.4
diff --git a/recipes-kernel/linux/linux-am335x-3.2.0-psp04.06.00.08/0001-am335x-Add-pm_runtime-API-to-crypto-driver.patch b/recipes-kernel/linux/linux-am335x-3.2.0-psp04.06.00.08/0001-am335x-Add-pm_runtime-API-to-crypto-driver.patch
new file mode 100644 (file)
index 0000000..cef94b7
--- /dev/null
@@ -0,0 +1,405 @@
+From 7cb6dbae57e2bb5d237bb88f6eb40971cf8fc3b5 Mon Sep 17 00:00:00 2001
+From: Greg Turner <gregturner@ti.com>
+Date: Wed, 18 Jul 2012 09:15:18 -0500
+Subject: [PATCH] [am335x]: Add pm_runtime API to crypto driver
+
+* Add pm_runtime API to crypto driver AES and SHA
+* Mod devices.c file to add pm_runtime for crypto
+* Mod omap_hwmod_33xx_data.c to add resources structures
+* Crypto module clocks are enabled in probe function
+  and disabled only on remove or other error.
+---
+ arch/arm/mach-omap2/devices.c              |   66 ++++++++++++++++++++++++++++
+ arch/arm/mach-omap2/omap_hwmod_33xx_data.c |   15 ++++++-
+ drivers/crypto/omap4-aes.c                 |   52 +++++++++++----------
+ drivers/crypto/omap4-sham.c                |   45 ++++++++++---------
+ 4 files changed, 131 insertions(+), 47 deletions(-)
+ mode change 100644 => 100755 arch/arm/mach-omap2/devices.c
+ mode change 100644 => 100755 arch/arm/mach-omap2/omap_hwmod_33xx_data.c
+ mode change 100644 => 100755 drivers/crypto/omap4-aes.c
+ mode change 100644 => 100755 drivers/crypto/omap4-sham.c
+
+diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c
+old mode 100644
+new mode 100755
+index ebf0d9e..156e363
+--- a/arch/arm/mach-omap2/devices.c
++++ b/arch/arm/mach-omap2/devices.c
+@@ -751,6 +751,7 @@ static struct platform_device sham_device = {
+       .id             = -1,
+ };
+
++#if 0
+ static void omap_init_sham(void)
+ {
+       sham_device.resource = omap4_sham_resources;
+@@ -758,6 +759,38 @@ static void omap_init_sham(void)
+
+       platform_device_register(&sham_device);
+ }
++#endif
++
++int __init omap_init_sham(void)
++{
++      int id = -1;
++      struct platform_device *pdev;
++      struct omap_hwmod *oh;
++      char *oh_name = "sha0";
++      char *name = "omap4-sham";
++
++      oh = omap_hwmod_lookup(oh_name);
++      if (!oh) {
++              pr_err("Could not look up %s\n", oh_name);
++              return -ENODEV;
++      }
++
++      pdev = omap_device_build(name, id, oh, NULL, 0, NULL, 0, 0);
++      //pdev.resource = omap4_sham_resources;
++      //pdev.num_resources = omap4_sham_resources_sz;
++
++      if (IS_ERR(pdev)) {
++              WARN(1, "Can't build omap_device for %s:%s.\n",
++                                              name, oh->name);
++              return PTR_ERR(pdev);
++      }
++
++      return 0;
++}
++
++
++
++
+
+ #else
+ static inline void omap_init_sham(void) { }
+@@ -853,12 +886,45 @@ static struct platform_device aes_device = {
+       .id             = -1,
+ };
+
++#if 0
+ static void omap_init_aes(void)
+ {
+       aes_device.resource = omap4_aes_resources;
+       aes_device.num_resources = omap4_aes_resources_sz;
+       platform_device_register(&aes_device);
+ }
++#endif
++
++int __init omap_init_aes(void)
++{
++      int id = -1;
++      struct platform_device *pdev;
++      struct omap_hwmod *oh;
++      char *oh_name = "aes0";
++      char *name = "omap4-aes";
++
++      oh = omap_hwmod_lookup(oh_name);
++      if (!oh) {
++              pr_err("Could not look up %s\n", oh_name);
++              return -ENODEV;
++      }
++
++      pdev = omap_device_build(name, id, oh, NULL, 0, NULL, 0, 0);
++      //pdev.resource = omap4_sham_resources;
++      //pdev.num_resources = omap4_sham_resources_sz;
++
++      if (IS_ERR(pdev)) {
++              WARN(1, "Can't build omap_device for %s:%s.\n",
++                                              name, oh->name);
++              return PTR_ERR(pdev);
++      }
++
++      return 0;
++}
++
++
++
++
+
+ #else
+ static inline void omap_init_aes(void) { }
+diff --git a/arch/arm/mach-omap2/omap_hwmod_33xx_data.c b/arch/arm/mach-omap2/omap_hwmod_33xx_data.c
+old mode 100644
+new mode 100755
+index 995b73f..2f9982c
+--- a/arch/arm/mach-omap2/omap_hwmod_33xx_data.c
++++ b/arch/arm/mach-omap2/omap_hwmod_33xx_data.c
+@@ -434,11 +434,18 @@ static struct omap_hwmod_irq_info am33xx_aes0_irqs[] = {
+       { .irq = -1 }
+ };
+
++static struct omap_hwmod_dma_info am33xx_aes0_dma[] = {
++      { .dma_req = AM33XX_DMA_AESEIP36T0_DOUT },
++      { .dma_req = AM33XX_DMA_AESEIP36T0_DIN },
++      { .dma_req = -1 }
++};
++
+ static struct omap_hwmod am33xx_aes0_hwmod = {
+       .name           = "aes0",
+       .class          = &am33xx_aes_hwmod_class,
+       .clkdm_name     = "l3_clkdm",
+       .mpu_irqs       = am33xx_aes0_irqs,
++      .sdma_reqs      = am33xx_aes0_dma,
+       .main_clk       = "aes0_fck",
+       .prcm           = {
+               .omap4  = {
+@@ -2165,15 +2172,21 @@ static struct omap_hwmod_class am33xx_sha0_hwmod_class = {
+ };
+
+ static struct omap_hwmod_irq_info am33xx_sha0_irqs[] = {
+-      { .irq = 108 },
++      { .irq = AM33XX_IRQ_SHAEIP57t0_P },
+       { .irq = -1 }
+ };
+
++static struct omap_hwmod_dma_info am33xx_sha0_dma[] = {
++      { .dma_req = AM33XX_DMA_SHAEIP57T0_DIN },
++      { .dma_req = -1 }
++};
++
+ static struct omap_hwmod am33xx_sha0_hwmod = {
+       .name           = "sha0",
+       .class          = &am33xx_sha0_hwmod_class,
+       .clkdm_name     = "l3_clkdm",
+       .mpu_irqs       = am33xx_sha0_irqs,
++      .sdma_reqs      = am33xx_sha0_dma,
+       .main_clk       = "sha0_fck",
+       .prcm           = {
+               .omap4  = {
+diff --git a/drivers/crypto/omap4-aes.c b/drivers/crypto/omap4-aes.c
+old mode 100644
+new mode 100755
+index f0b3fe2..76f988a
+--- a/drivers/crypto/omap4-aes.c
++++ b/drivers/crypto/omap4-aes.c
+@@ -32,13 +32,14 @@
+ #include <linux/init.h>
+ #include <linux/errno.h>
+ #include <linux/kernel.h>
+-#include <linux/clk.h>
+ #include <linux/platform_device.h>
+ #include <linux/scatterlist.h>
+ #include <linux/dma-mapping.h>
+ #include <linux/io.h>
+ #include <linux/crypto.h>
++#include <linux/pm_runtime.h>
+ #include <linux/interrupt.h>
++#include <linux/delay.h>
+ #include <crypto/scatterwalk.h>
+ #include <crypto/aes.h>
+
+@@ -145,12 +146,6 @@ static void omap4_aes_write_n(struct omap4_aes_dev *dd, u32 offset,
+
+ static int omap4_aes_hw_init(struct omap4_aes_dev *dd)
+ {
+-      /*
+-       * clocks are enabled when request starts and disabled when finished.
+-       * It may be long delays between requests.
+-       * Device might go to off mode to save power.
+-       */
+-      clk_enable(dd->iclk);
+       omap4_aes_write(dd, AES_REG_SYSCFG, 0);
+
+       if (!(dd->flags & FLAGS_INIT)) {
+@@ -494,7 +489,6 @@ static void omap4_aes_finish_req(struct omap4_aes_dev *dd, int err)
+
+       pr_debug("err: %d\n", err);
+
+-      clk_disable(dd->iclk);
+       dd->flags &= ~FLAGS_BUSY;
+
+       req->base.complete(&req->base, err);
+@@ -801,13 +795,15 @@ static int omap4_aes_probe(struct platform_device *pdev)
+       crypto_init_queue(&dd->queue, AM33X_AES_QUEUE_LENGTH);
+
+       /* Get the base address */
+-      res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+-      if (!res) {
+-              dev_err(dev, "invalid resource type\n");
+-              err = -ENODEV;
+-              goto err_res;
+-      }
+-      dd->phys_base = res->start;
++      //res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++      //if (!res) {
++      //      dev_err(dev, "invalid resource type\n");
++      //      err = -ENODEV;
++      //      goto err_res;
++      //}
++
++      //dd->phys_base = res->start;
++      dd->phys_base = AM33XX_AES0_P_BASE;
+
+       /* Get the DMA */
+       res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+@@ -823,13 +819,10 @@ static int omap4_aes_probe(struct platform_device *pdev)
+       else
+               dd->dma_in = res->start;
+
+-      /* Initializing the clock */
+-      dd->iclk = clk_get(dev, "aes0_fck");
+-      if (IS_ERR(dd->iclk)) {
+-              dev_err(dev, "clock initialization failed.\n");
+-              err = PTR_ERR(dd->iclk);
+-              goto err_res;
+-      }
++      pm_runtime_enable(dev);
++      udelay(1);
++      pm_runtime_get_sync(dev);
++      udelay(1);
+
+       dd->io_base = ioremap(dd->phys_base, SZ_4K);
+       if (!dd->io_base) {
+@@ -840,7 +833,7 @@ static int omap4_aes_probe(struct platform_device *pdev)
+
+       omap4_aes_hw_init(dd);
+       reg = omap4_aes_read(dd, AES_REG_REV);
+-      clk_disable(dd->iclk);
++
+       dev_info(dev, "AM33X AES hw accel rev: %u.%02u\n",
+                ((reg & AES_REG_REV_X_MAJOR_MASK) >> 8),
+                (reg & AES_REG_REV_Y_MINOR_MASK));
+@@ -879,7 +872,12 @@ err_dma:
+       iounmap(dd->io_base);
+
+ err_io:
+-      clk_put(dd->iclk);
++      pm_runtime_put_sync(dev);
++      udelay(1);
++      pm_runtime_disable(dev);
++      udelay(1);
++
++
+ err_res:
+       kfree(dd);
+       dd = NULL;
+@@ -907,7 +905,11 @@ static int omap4_aes_remove(struct platform_device *pdev)
+       tasklet_kill(&dd->queue_task);
+       omap4_aes_dma_cleanup(dd);
+       iounmap(dd->io_base);
+-      clk_put(dd->iclk);
++      pm_runtime_put_sync(&pdev->dev);
++      udelay(1);
++      pm_runtime_disable(&pdev->dev);
++      udelay(1);
++
+       kfree(dd);
+       dd = NULL;
+
+diff --git a/drivers/crypto/omap4-sham.c b/drivers/crypto/omap4-sham.c
+old mode 100644
+new mode 100755
+index 79f6be9..21f1b48
+--- a/drivers/crypto/omap4-sham.c
++++ b/drivers/crypto/omap4-sham.c
+@@ -31,7 +31,6 @@
+ #include <linux/errno.h>
+ #include <linux/interrupt.h>
+ #include <linux/kernel.h>
+-#include <linux/clk.h>
+ #include <linux/irq.h>
+ #include <linux/io.h>
+ #include <linux/platform_device.h>
+@@ -40,6 +39,7 @@
+ #include <linux/delay.h>
+ #include <linux/crypto.h>
+ #include <linux/cryptohash.h>
++#include <linux/pm_runtime.h>
+ #include <crypto/scatterwalk.h>
+ #include <crypto/algapi.h>
+ #include <crypto/sha.h>
+@@ -700,7 +700,6 @@ static void omap4_sham_finish_req(struct ahash_request *req, int err)
+       /* atomic operation is not needed here */
+       dd->dflags &= ~(BIT(FLAGS_BUSY) | BIT(FLAGS_FINAL) | BIT(FLAGS_CPU) |
+                       BIT(FLAGS_DMA_READY) | BIT(FLAGS_OUTPUT_READY));
+-      clk_disable(dd->iclk);
+
+       if (req->base.complete)
+               req->base.complete(&req->base, err);
+@@ -743,7 +742,6 @@ static int omap4_sham_handle_queue(struct omap4_sham_dev *dd,
+       dev_dbg(dd->dev, "handling new req, op: %lu, nbytes: %d\n",
+                                               ctx->op, req->nbytes);
+
+-      clk_enable(dd->iclk);
+       if (!test_bit(FLAGS_INIT, &dd->dflags)) {
+               set_bit(FLAGS_INIT, &dd->dflags);
+               dd->err = 0;
+@@ -1272,13 +1270,15 @@ static int __devinit omap4_sham_probe(struct platform_device *pdev)
+       dd->irq = -1;
+
+       /* Get the base address */
+-      res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+-      if (!res) {
+-              dev_err(dev, "no MEM resource info\n");
+-              err = -ENODEV;
+-              goto res_err;
+-      }
+-      dd->phys_base = res->start;
++      //res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++      //if (!res) {
++      //      dev_err(dev, "no MEM resource info\n");
++      //      err = -ENODEV;
++      //      goto res_err;
++      //}
++
++      //dd->phys_base = res->start;
++      dd->phys_base = AM33XX_SHA1MD5_P_BASE;
+
+       /* Get the DMA */
+       res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+@@ -1308,13 +1308,10 @@ static int __devinit omap4_sham_probe(struct platform_device *pdev)
+       if (err)
+               goto dma_err;
+
+-      /* Initializing the clock */
+-      dd->iclk = clk_get(dev, "sha0_fck");
+-      if (IS_ERR(dd->iclk)) {
+-              dev_err(dev, "clock initialization failed.\n");
+-              err = PTR_ERR(dd->iclk);
+-              goto clk_err;
+-      }
++      pm_runtime_enable(dev);
++      udelay(1);
++      pm_runtime_get_sync(dev);
++      udelay(1);
+
+       dd->io_base = ioremap(dd->phys_base, SZ_4K);
+       if (!dd->io_base) {
+@@ -1323,9 +1320,7 @@ static int __devinit omap4_sham_probe(struct platform_device *pdev)
+               goto io_err;
+       }
+
+-      clk_enable(dd->iclk);
+       reg = omap4_sham_read(dd, SHA_REG_REV);
+-      clk_disable(dd->iclk);
+
+       dev_info(dev, "AM33X SHA/MD5 hw accel rev: %u.%02u\n",
+                (reg & SHA_REG_REV_X_MAJOR_MASK) >> 8, reg & SHA_REG_REV_Y_MINOR_MASK);
+@@ -1349,7 +1344,11 @@ err_algs:
+               crypto_unregister_ahash(&algs[j]);
+       iounmap(dd->io_base);
+ io_err:
+-      clk_put(dd->iclk);
++      pm_runtime_put_sync(dev);
++      udelay(1);
++      pm_runtime_disable(dev);
++      udelay(1);
++
+ clk_err:
+       omap4_sham_dma_cleanup(dd);
+ dma_err:
+@@ -1379,7 +1378,11 @@ static int __devexit omap4_sham_remove(struct platform_device *pdev)
+               crypto_unregister_ahash(&algs[i]);
+       tasklet_kill(&dd->done_task);
+       iounmap(dd->io_base);
+-      clk_put(dd->iclk);
++      pm_runtime_put_sync(&pdev->dev);
++      udelay(1);
++      pm_runtime_disable(&pdev->dev);
++      udelay(1);
++
+       omap4_sham_dma_cleanup(dd);
+       if (dd->irq >= 0)
+               free_irq(dd->irq, dd);
+--
+1.7.0.4
diff --git a/recipes-kernel/linux/linux-am335x-3.2.0-psp04.06.00.08/0001-am335x-enable-pullup-on-the-WLAN-enable-pin-fo.patch b/recipes-kernel/linux/linux-am335x-3.2.0-psp04.06.00.08/0001-am335x-enable-pullup-on-the-WLAN-enable-pin-fo.patch
new file mode 100644 (file)
index 0000000..863fe37
--- /dev/null
@@ -0,0 +1,57 @@
+From f69ffbef6793b7238a8518481735fd53326e0cdf Mon Sep 17 00:00:00 2001
+From: Vita Preskovsky <vitap@ti.com>
+Date: Tue, 24 Jul 2012 20:02:28 +0300
+Subject: [PATCH] am335x: enable pullup on the WLAN enable pin for keeping wlan
+
+  * Enable pullup on the WLAN enable pin for keeping wlan active
+    during suspend in wowlan mode. The fix is relevant only in the case
+    of am335x-SK board.
+
+
+Signed-off-by: Vita Preskovsky <vitap@ti.com>
+---
+ arch/arm/mach-omap2/board-am335xevm.c |   22 ++++++++++++++++++++++
+ 1 files changed, 22 insertions(+), 0 deletions(-)
+
+diff --git a/arch/arm/mach-omap2/board-am335xevm.c b/arch/arm/mach-omap2/board-am335xevm.c
+index f68710c..f263f84 100644
+--- a/arch/arm/mach-omap2/board-am335xevm.c
++++ b/arch/arm/mach-omap2/board-am335xevm.c
+@@ -1673,13 +1673,35 @@ static void wl12xx_bluetooth_enable(void)
+       gpio_direction_output(am335xevm_wlan_data.bt_enable_gpio, 0);
+ }
+
++#define AM33XX_CTRL_REGADDR(reg)                                      \
++              AM33XX_L4_WK_IO_ADDRESS(AM33XX_SCM_BASE + (reg))
++
++/* wlan enable pin */
++#define AM33XX_CONTROL_PADCONF_GPMC_CSN0_OFFSET               0x087C
+ static int wl12xx_set_power(struct device *dev, int slot, int on, int vdd)
+ {
++      int pad_mux_value;
++
+       if (on) {
+               gpio_direction_output(am335xevm_wlan_data.wlan_enable_gpio, 1);
++
++              /* Enable pullup on the WLAN enable pin for keeping wlan active during suspend
++                 in wowlan mode */
++              if ( am335x_evm_get_id() == EVM_SK ) {
++                      pad_mux_value = readl(AM33XX_CTRL_REGADDR(AM33XX_CONTROL_PADCONF_GPMC_CSN0_OFFSET));
++                      pad_mux_value &= (~AM33XX_PULL_DISA);
++                      writel(pad_mux_value, AM33XX_CTRL_REGADDR(AM33XX_CONTROL_PADCONF_GPMC_CSN0_OFFSET));
++              }
++
+               mdelay(70);
+       } else {
+               gpio_direction_output(am335xevm_wlan_data.wlan_enable_gpio, 0);
++              /* Disable pullup on the WLAN enable when WLAN is off */
++              if ( am335x_evm_get_id() == EVM_SK ) {
++                      pad_mux_value = readl(AM33XX_CTRL_REGADDR(AM33XX_CONTROL_PADCONF_GPMC_CSN0_OFFSET));
++                      pad_mux_value |= AM33XX_PULL_DISA;
++                      writel(pad_mux_value, AM33XX_CTRL_REGADDR(AM33XX_CONTROL_PADCONF_GPMC_CSN0_OFFSET));
++              }
+       }
+
+       return 0;
+--
+1.7.0.4
diff --git a/recipes-kernel/linux/linux-am335x-3.2.0-psp04.06.00.08/0001-am335x_evm_defconfig-turn-off-MUSB-DMA.patch b/recipes-kernel/linux/linux-am335x-3.2.0-psp04.06.00.08/0001-am335x_evm_defconfig-turn-off-MUSB-DMA.patch
new file mode 100644 (file)
index 0000000..6a32c2c
--- /dev/null
@@ -0,0 +1,35 @@
+From 95eca5a896c96d0af7188c97825a3b3ef5313ed3 Mon Sep 17 00:00:00 2001
+From: Chase Maupin <Chase.Maupin@ti.com>
+Date: Thu, 2 Feb 2012 16:38:51 -0600
+Subject: [PATCH] am335x_evm_defconfig: turn off MUSB DMA
+
+* Turn off the MUSB DMA in the am335x_evm_defconfig.  This way
+  we can pull the default defconfig without enabling the
+  faulty USB DMA.
+
+Signed-off-by: Chase Maupin <Chase.Maupin@ti.com>
+---
+ arch/arm/configs/am335x_evm_defconfig |    6 +++---
+ 1 files changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/arch/arm/configs/am335x_evm_defconfig b/arch/arm/configs/am335x_evm_defconfig
+index d105c61..121dc7f 100644
+--- a/arch/arm/configs/am335x_evm_defconfig
++++ b/arch/arm/configs/am335x_evm_defconfig
+@@ -1982,11 +1982,11 @@ CONFIG_USB_MUSB_TI81XX_GLUE=y
+ CONFIG_USB_MUSB_TI81XX=y
+ # CONFIG_USB_MUSB_BLACKFIN is not set
+ # CONFIG_USB_MUSB_UX500 is not set
+-CONFIG_USB_TI_CPPI41_DMA_HW=y
+-# CONFIG_MUSB_PIO_ONLY is not set
++# CONFIG_USB_TI_CPPI41_DMA_HW is not set
++CONFIG_MUSB_PIO_ONLY=y
+ # CONFIG_USB_INVENTRA_DMA is not set
+ # CONFIG_USB_TI_CPPI_DMA is not set
+-CONFIG_USB_TI_CPPI41_DMA=y
++# CONFIG_USB_TI_CPPI41_DMA is not set
+ # CONFIG_USB_TUSB_OMAP_DMA is not set
+ # CONFIG_USB_UX500_DMA is not set
+ # CONFIG_USB_RENESAS_USBHS is not set
+--
+1.7.0.4
diff --git a/recipes-kernel/linux/linux-am335x-3.2.0-psp04.06.00.08/0001-am335xevm-using-edge-triggered-interrupts-for-WLAN.patch b/recipes-kernel/linux/linux-am335x-3.2.0-psp04.06.00.08/0001-am335xevm-using-edge-triggered-interrupts-for-WLAN.patch
new file mode 100644 (file)
index 0000000..98b3a31
--- /dev/null
@@ -0,0 +1,35 @@
+From be52bac69dfe6a56276b16ccd234970c4f7b1255 Mon Sep 17 00:00:00 2001
+From: Vita Preskovsky <vitap@ti.com>
+Date: Wed, 18 Jul 2012 16:20:36 +0300
+Subject: [PATCH] am335xevm: using edge triggered interrupts for WLAN
+
+  *using edge triggered interrupts instead of default level triggered in
+   all platforms supporting WLAN. This reduces CPU cycles and possibility
+   for missed interrupts.
+
+
+Signed-off-by: Vita Preskovsky <vitap@ti.com>
+---
+ arch/arm/mach-omap2/board-am335xevm.c |    3 +--
+ 1 files changed, 1 insertions(+), 2 deletions(-)
+
+diff --git a/arch/arm/mach-omap2/board-am335xevm.c b/arch/arm/mach-omap2/board-am335xevm.c
+index 6ae4e68..ac005c8 100644
+--- a/arch/arm/mach-omap2/board-am335xevm.c
++++ b/arch/arm/mach-omap2/board-am335xevm.c
+@@ -1679,12 +1679,11 @@ static void wl12xx_init(int evm_id, int profile)
+               am335xevm_wlan_data.bt_enable_gpio = GPIO_TO_PIN(3, 21);
+               am335xevm_wlan_data.irq =
+                               OMAP_GPIO_IRQ(AM335XEVM_SK_WLAN_IRQ_GPIO);
+-              am335xevm_wlan_data.platform_quirks =
+-                              WL12XX_PLATFORM_QUIRK_EDGE_IRQ;
+               setup_pin_mux(wl12xx_pin_mux_sk);
+       } else {
+               setup_pin_mux(wl12xx_pin_mux);
+       }
++      am335xevm_wlan_data.platform_quirks = WL12XX_PLATFORM_QUIRK_EDGE_IRQ;
+       wl12xx_bluetooth_enable();
+
+       if (wl12xx_set_platform_data(&am335xevm_wlan_data))
+--
+1.7.0.4
diff --git a/recipes-kernel/linux/linux-am335x-3.2.0-psp04.06.00.08/0001-am33x-Add-memory-addresses-for-crypto-modules.patch b/recipes-kernel/linux/linux-am335x-3.2.0-psp04.06.00.08/0001-am33x-Add-memory-addresses-for-crypto-modules.patch
new file mode 100644 (file)
index 0000000..f92a7fc
--- /dev/null
@@ -0,0 +1,41 @@
+From 5f2f17a488aba4319b537aed040ea13607af128b Mon Sep 17 00:00:00 2001
+From: Greg Turner <gregturner@ti.com>
+Date: Thu, 17 May 2012 14:25:40 -0500
+Subject: [PATCH 1/8] am33x: Add memory addresses for crypto modules
+
+* Add base memory addresses to the am33xx.h header file
+
+These addresses are for the HW crypto modules including TRNG, AES, and SHA/MD5
+
+Signed-off-by: Greg Turner <gregturner@ti.com>
+---
+ arch/arm/plat-omap/include/plat/am33xx.h |   11 +++++++++++
+ 1 files changed, 11 insertions(+), 0 deletions(-)
+ mode change 100644 => 100755 arch/arm/plat-omap/include/plat/am33xx.h
+
+diff --git a/arch/arm/plat-omap/include/plat/am33xx.h b/arch/arm/plat-omap/include/plat/am33xx.h
+old mode 100644
+new mode 100755
+index a16e72c..96ab1c3
+--- a/arch/arm/plat-omap/include/plat/am33xx.h
++++ b/arch/arm/plat-omap/include/plat/am33xx.h
+@@ -65,6 +65,17 @@
+
+ #define AM33XX_ELM_BASE               0x48080000
+
++/* Base address for crypto modules */
++#define AM33XX_SHA1MD5_S_BASE 0x53000000
++#define AM33XX_SHA1MD5_P_BASE 0x53100000
++
++#define       AM33XX_AES0_S_BASE      0x53400000
++#define       AM33XX_AES0_P_BASE      0x53500000
++#define       AM33XX_AES1_S_BASE      0x53600000
++#define       AM33XX_AES1_P_BASE      0x53700000
++
++#define       AM33XX_RNG_BASE         0x48310000
++
+ #define AM33XX_ASP0_BASE      0x48038000
+ #define AM33XX_ASP1_BASE      0x4803C000
+
+--
+1.7.0.4
diff --git a/recipes-kernel/linux/linux-am335x-3.2.0-psp04.06.00.08/0001-am33xx-Add-SmartReflex-support.patch b/recipes-kernel/linux/linux-am335x-3.2.0-psp04.06.00.08/0001-am33xx-Add-SmartReflex-support.patch
new file mode 100644 (file)
index 0000000..a17f62c
--- /dev/null
@@ -0,0 +1,2014 @@
+From 35ae6b61d349e5b4efd1c6337a0d1e23b6e86899 Mon Sep 17 00:00:00 2001
+From: Greg Guyotte <gguyotte@ti.com>
+Date: Thu, 7 Jun 2012 18:05:31 -0500
+Subject: [PATCH] am33xx: Add SmartReflex support.
+
+This patch introduces SmartReflex support to AM33XX devices.  The
+purpose of SmartReflex is to optimize (lower) voltage based upon
+silicon process and temperature.
+
+The SmartReflex driver requires the silicon to be programmed with
+"nTarget" EFUSE values.  If the values are not present (as with
+pre-RTP samples), the driver will simply fail to load and kernel
+boot will continue normally.
+
+The SR driver logs several items in the debugfs at /debug/smartreflex.
+To disable SmartReflex, use the command 'echo 0 > /debug/smartreflex/autocomp'.
+The node /debug/smartreflex/smartreflex0 gives information about
+the CORE voltage domain, and /smartreflex1 is related to the MPU voltage
+domain.
+
+To determine the effectiveness of SmartReflex, you can compare the
+initial voltage with the current voltage for a given OPP.  For example,
+'cat /debug/smartreflex/smartreflex1/current_voltage' gives the current
+MPU voltage.  Comparing that with 'cat /debug/smartreflex/smartreflex1/
+initial_voltage' will show you the voltage drop associated with SR
+operation.
+
+Signed-off-by: Greg Guyotte <gguyotte@ti.com>
+---
+ arch/arm/mach-omap2/Makefile                       |    1 +
+ arch/arm/mach-omap2/am33xx-smartreflex-class2.c    | 1055 ++++++++++++++++++++
+ arch/arm/mach-omap2/board-am335xevm.c              |    7 +
+ arch/arm/mach-omap2/devices.c                      |  269 +++++
+ arch/arm/mach-omap2/include/mach/board-am335xevm.h |    1 +
+ arch/arm/plat-omap/Kconfig                         |   21 +
+ arch/arm/plat-omap/include/plat/am33xx.h           |    3 +
+ arch/arm/plat-omap/include/plat/smartreflex.h      |  431 ++++++++
+ drivers/regulator/core.c                           |    4 +
+ include/linux/regulator/driver.h                   |    2 +-
+ include/linux/regulator/machine.h                  |    3 +-
+ 11 files changed, 1795 insertions(+), 2 deletions(-)
+ create mode 100644 arch/arm/mach-omap2/am33xx-smartreflex-class2.c
+ create mode 100644 arch/arm/plat-omap/include/plat/smartreflex.h
+
+diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
+index f275e74..c01b62d 100644
+--- a/arch/arm/mach-omap2/Makefile
++++ b/arch/arm/mach-omap2/Makefile
+@@ -73,6 +73,7 @@ obj-$(CONFIG_SOC_OMAPAM33XX)         += cpuidle33xx.o pm33xx.o \
+ obj-$(CONFIG_PM_DEBUG)                        += pm-debug.o
+ obj-$(CONFIG_OMAP_SMARTREFLEX)          += sr_device.o smartreflex.o
+ obj-$(CONFIG_OMAP_SMARTREFLEX_CLASS3) += smartreflex-class3.o
++obj-$(CONFIG_AM33XX_SMARTREFLEX)        += am33xx-smartreflex-class2.o
+
+ AFLAGS_sleep24xx.o                    :=-Wa,-march=armv6
+ AFLAGS_sleep34xx.o                    :=-Wa,-march=armv7-a$(plus_sec)
+diff --git a/arch/arm/mach-omap2/am33xx-smartreflex-class2.c b/arch/arm/mach-omap2/am33xx-smartreflex-class2.c
+new file mode 100644
+index 0000000..66f98b7
+--- /dev/null
++++ b/arch/arm/mach-omap2/am33xx-smartreflex-class2.c
+@@ -0,0 +1,1055 @@
++/*
++ * SmartReflex Voltage Control driver
++ *
++ * Copyright (C) 2012 Texas Instruments, Inc. - http://www.ti.com/
++ * Author: Greg Guyotte <gguyotte@ti.com> (modified for AM33xx)
++ *
++ * Copyright (C) 2011 Texas Instruments, Inc. - http://www.ti.com/
++ * Author: AnilKumar Ch <anilkumar@ti.com>
++ *
++ * 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 version 2.
++ *
++ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
++ * kind, whether express or implied; without even the implied warranty
++ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/interrupt.h>
++#include <linux/clk.h>
++#include <linux/io.h>
++#include <linux/debugfs.h>
++#include <linux/slab.h>
++#include <linux/regulator/consumer.h>
++#include <linux/cpufreq.h>
++#include <linux/opp.h>
++
++#include <plat/common.h>
++#include <plat/smartreflex.h>
++
++#include "control.h"
++#include "voltage.h"
++
++#define CLK_NAME_LEN          40
++
++static inline void sr_write_reg(struct am33xx_sr *sr, int offset, u32 value,
++                                      u32 srid)
++{
++      writel(value, sr->sen[srid].base + offset);
++}
++
++static inline void sr_modify_reg(struct am33xx_sr *sr, int offset, u32 mask,
++                              u32 value, u32 srid)
++{
++      u32 reg_val;
++
++      reg_val = readl(sr->sen[srid].base + offset);
++      reg_val &= ~mask;
++      reg_val |= (value&mask);
++
++      writel(reg_val, sr->sen[srid].base + offset);
++}
++
++static inline u32 sr_read_reg(struct am33xx_sr *sr, int offset, u32 srid)
++{
++      return readl(sr->sen[srid].base + offset);
++}
++
++static void cal_reciprocal(u32 sensor, u32 *sengain, u32 *rnsen) {
++         u32 gn, rn, mul;
++
++         for (gn = 0; gn < GAIN_MAXLIMIT; gn++) {
++                 mul = 1 << (gn + 8);
++                 rn = mul / sensor;
++                 if (rn < R_MAXLIMIT) {
++                         *sengain = gn;
++                         *rnsen = rn;
++                 }
++         }
++}
++
++static u32 cal_test_nvalue(u32 sennval, u32 senpval) {
++         u32 senpgain=0, senngain=0;
++         u32 rnsenp=0, rnsenn=0;
++
++         /* Calculating the gain and reciprocal of the SenN and SenP values */
++         cal_reciprocal(senpval, &senpgain, &rnsenp);
++         cal_reciprocal(sennval, &senngain, &rnsenn);
++
++         return (senpgain << NVALUERECIPROCAL_SENPGAIN_SHIFT) |
++                 (senngain << NVALUERECIPROCAL_SENNGAIN_SHIFT) |
++                 (rnsenp << NVALUERECIPROCAL_RNSENP_SHIFT) |
++                 (rnsenn << NVALUERECIPROCAL_RNSENN_SHIFT);
++}
++
++static unsigned int sr_adjust_efuse_nvalue(unsigned int opp_no,
++                                                 unsigned int orig_opp_nvalue,
++                                                 unsigned int mv_delta) {
++         unsigned int new_opp_nvalue;
++         unsigned int senp_gain, senn_gain, rnsenp, rnsenn, pnt_delta, nnt_delta;
++         unsigned int new_senn, new_senp, senn, senp;
++
++         /* calculate SenN and SenP from the efuse value */
++         senp_gain = ((orig_opp_nvalue >> 20) & 0xf);
++         senn_gain = ((orig_opp_nvalue >> 16) & 0xf);
++         rnsenp = ((orig_opp_nvalue >> 8) & 0xff);
++         rnsenn = (orig_opp_nvalue & 0xff);
++
++         senp = ((1<<(senp_gain+8))/(rnsenp));
++         senn = ((1<<(senn_gain+8))/(rnsenn));
++
++         /* calculate the voltage delta */
++         pnt_delta = (26 * mv_delta)/10;
++         nnt_delta = (3 * mv_delta);
++
++         /* now lets add the voltage delta to the sensor values */
++         new_senn = senn + nnt_delta;
++         new_senp = senp + pnt_delta;
++
++         new_opp_nvalue = cal_test_nvalue(new_senn, new_senp);
++
++         printk("Compensating OPP%d for %dmV Orig nvalue:0x%x New nvalue:0x%x \n",
++                         opp_no, mv_delta, orig_opp_nvalue, new_opp_nvalue);
++
++         return new_opp_nvalue;
++}
++
++/* irq_sr_reenable - Re-enable SR interrupts (triggered by delayed work queue)
++ * @work:     pointer to work_struct embedded in am33xx_sr_sensor struct
++ *
++ * While servicing the IRQ, this function is added to the delayed work queue.
++ * This gives time for the voltage change to settle before we re-enable
++ * the interrupt.
++ */
++static void irq_sr_reenable(struct work_struct *work)
++{
++        u32 srid;
++      struct am33xx_sr_sensor *sens;
++        struct am33xx_sr *sr;
++
++        sens = container_of((void *)work, struct am33xx_sr_sensor,
++                work_reenable);
++
++        srid = sens->sr_id;
++
++        sr = container_of((void *)sens, struct am33xx_sr, sen[srid]);
++
++        dev_dbg(&sr->pdev->dev, "%s: SR %d\n", __func__, srid);
++
++        /* Must clear IRQ status */
++        sens->irq_status = 0;
++
++        /* Re-enable the interrupt */
++      sr_modify_reg(sr, IRQENABLE_SET, IRQENABLE_MCUBOUNDSINT,
++              IRQENABLE_MCUBOUNDSINT, srid);
++
++      /* Restart the module after voltage set */
++      sr_modify_reg(sr, SRCONFIG, SRCONFIG_SRENABLE,
++              SRCONFIG_SRENABLE, srid);
++}
++
++/* get_errvolt - get error voltage from SR error register
++ * @sr:               contains SR driver data
++ * @srid:     contains the srid, indicates which SR moduel lswe are using
++ *
++ * Read the error from SENSOR error register and then convert
++ * to voltage delta, return value is the voltage delta in micro
++ * volt.
++ */
++static int get_errvolt(struct am33xx_sr *sr, s32 srid)
++{
++        struct am33xx_sr_sensor *sens;
++      int senerror_reg;
++      s32 uvoltage;
++      s8 terror;
++
++        sens = &sr->sen[srid];
++
++      senerror_reg = sr_read_reg(sr, SENERROR_V2, srid);
++      senerror_reg = (senerror_reg & 0x0000FF00);
++      terror = (s8)(senerror_reg >> 8);
++
++        /* math defined in SR functional spec */
++      uvoltage = ((terror) * sr->uvoltage_step_size) >> 7;
++      uvoltage = uvoltage * sens->opp_data[sens->curr_opp].e2v_gain;
++
++      return uvoltage;
++}
++
++/* set_voltage - Schedule task for setting the voltage
++ * @work:     pointer to the work structure
++ *
++ * Voltage is set based on previous voltage and calculated
++ * voltage error.
++ *
++ * Generic voltage regulator set voltage is used for changing
++ * the voltage to new value.  Could potentially use voltdm_scale
++ * but at time of testing voltdm was not populated with volt_data.
++ *
++ * Disabling the module before changing the voltage, this is
++ * needed for not generating interrupt during voltage change,
++ * enabling after voltage change. This will also take care of
++ * resetting the SR registers.
++ */
++static void set_voltage(struct work_struct *work)
++{
++      struct am33xx_sr *sr;
++      int prev_volt, new_volt, i, ret;
++      s32 delta_v;
++
++      sr = container_of((void *)work, struct am33xx_sr, work);
++
++        for (i = 0; i < sr->no_of_sens; i++) {
++                if (sr->sen[i].irq_status != 1)
++                        continue;
++
++                /* Get the current voltage from PMIC */
++                prev_volt = regulator_get_voltage(sr->sen[i].reg);
++
++                if (prev_volt < 0) {
++                        dev_err(&sr->pdev->dev,
++                                "%s: SR %d: regulator_get_voltage error %d\n",
++                                __func__, i, prev_volt);
++
++                        goto reenable;
++                }
++
++              delta_v = get_errvolt(sr, i);
++                new_volt = prev_volt + delta_v;
++
++                /* this is the primary output for debugging SR activity */
++                dev_dbg(&sr->pdev->dev,
++                        "%s: SR %d: prev volt=%d, delta_v=%d, req_volt=%d\n",
++                         __func__, i, prev_volt, delta_v, new_volt);
++
++              /* Clear the counter, SR module disable */
++              sr_modify_reg(sr, SRCONFIG, SRCONFIG_SRENABLE,
++                      ~SRCONFIG_SRENABLE, i);
++
++                if (delta_v != 0) {
++                      ret = regulator_set_voltage(sr->sen[i].reg, new_volt,
++                                new_volt + sr->uvoltage_step_size);
++
++                        if (ret < 0)
++                                dev_err(&sr->pdev->dev,
++                                "%s: regulator_set_voltage failed! (err %d)\n",
++                                __func__, ret);
++                }
++reenable:
++                /* allow time for voltage to settle before re-enabling SR
++                   module and interrupt */
++                schedule_delayed_work(&sr->sen[i].work_reenable,
++                        msecs_to_jiffies(sr->irq_delay));
++        }
++}
++
++/* sr_class2_irq - sr irq handling
++ * @irq:      Number of the irq serviced
++ * @data:     data contains the SR driver structure
++ *
++ * Smartreflex IRQ handling for class2 IP, once the IRQ handler
++ * is here then disable the interrupt and re-enable after some
++ * time. This is the work around for handling both interrupts,
++ * while one got satisfied with the voltage change but not the
++ * other. The same logic helps the case where PMIC cannot set
++ * the exact voltage requested by SR IP
++ *
++ * Schedule work only if both interrupts are serviced
++ *
++ * Note that same irq handler is used for both the interrupts,
++ * needed for decision making for voltage change
++ */
++static irqreturn_t sr_class2_irq(int irq, void *data)
++{
++      u32 srid;
++        struct am33xx_sr *sr;
++        struct am33xx_sr_sensor *sr_sensor = (struct am33xx_sr_sensor *)data;
++
++        srid = sr_sensor->sr_id;
++
++        sr = container_of(data, struct am33xx_sr, sen[srid]);
++
++      sr->sen[srid].irq_status = 1;
++
++      /* Clear MCUBounds Interrupt */
++      sr_modify_reg(sr, IRQSTATUS, IRQSTATUS_MCBOUNDSINT,
++                      IRQSTATUS_MCBOUNDSINT, srid);
++
++      /* Disable the interrupt and re-enable in set_voltage() */
++      sr_modify_reg(sr, IRQENABLE_CLR, IRQENABLE_MCUBOUNDSINT,
++                      IRQENABLE_MCUBOUNDSINT, srid);
++
++        /* Causes set_voltage() to get called at a later time.  Set_voltage()
++           will check the irq_status flags to determine which SR needs to
++           be serviced.  This was previously done with schedule_work, but
++           I observed a crash in set_voltage() when changing OPPs on weak
++           silicon, which may have been related to insufficient voltage
++           settling time for OPP change.  This additional delay avoids the
++           crash. */
++        schedule_delayed_work(&sr->work,
++                        msecs_to_jiffies(250));
++
++      return IRQ_HANDLED;
++}
++
++static int sr_clk_enable(struct am33xx_sr *sr, u32 srid)
++{
++      if (clk_enable(sr->sen[srid].fck) != 0) {
++              dev_err(&sr->pdev->dev, "%s: Could not enable sr_fck\n",
++                                      __func__);
++              return -EINVAL;
++      }
++
++      return 0;
++}
++
++static int sr_clk_disable(struct am33xx_sr *sr, u32 srid)
++{
++      clk_disable(sr->sen[srid].fck);
++
++      return 0;
++}
++
++static inline int sr_set_nvalues(struct am33xx_sr *sr, u32 srid)
++{
++        int i;
++        struct am33xx_sr_sensor *sens = &sr->sen[srid];
++
++        for (i = 0; i < sens->no_of_opps; i++) {
++              /* Read nTarget value form EFUSE register*/
++              sens->opp_data[i].nvalue = readl(AM33XX_CTRL_REGADDR
++                      (sens->opp_data[i].efuse_offs)) & 0xFFFFFF;
++
++                /* validate nTarget value */
++                if (sens->opp_data[i].nvalue == 0)
++                        return -EINVAL;
++
++                /* adjust nTarget based on margin in mv */
++                sens->opp_data[i].adj_nvalue = sr_adjust_efuse_nvalue(i,
++                        sens->opp_data[i].nvalue,
++                        sens->opp_data[i].margin);
++
++                dev_dbg(&sr->pdev->dev,
++                        "NValueReciprocal value (from efuse) = %08x\n",
++                        sens->opp_data[i].nvalue);
++
++                dev_dbg(&sr->pdev->dev,
++                        "Adjusted NValueReciprocal value = %08x\n",
++                        sens->opp_data[i].adj_nvalue);
++        }
++      return 0;
++}
++
++/* sr_configure - Configure SR module to work in Error generator mode
++ * @sr:               contains SR driver data
++ * @srid:     contains the srid, specify whether it is CORE or MPU
++ *
++ * Configure the corresponding values to SR module registers for
++ * operating SR module in Error Generator mode.
++ */
++static void sr_configure(struct am33xx_sr *sr, u32 srid)
++{
++        struct am33xx_sr_sensor *sens = &sr->sen[srid];
++
++      /* Configuring the SR module with clock length, enabling the
++       * error generator, enable SR module, enable individual N and P
++       * sensors
++       */
++      sr_write_reg(sr, SRCONFIG, (SRCLKLENGTH_125MHZ_SYSCLK |
++              SRCONFIG_SENENABLE | SRCONFIG_ERRGEN_EN |
++              (sens->senn_en << SRCONFIG_SENNENABLE_V2_SHIFT) |
++              (sens->senp_en << SRCONFIG_SENPENABLE_V2_SHIFT)),
++              srid);
++
++      /* Configuring the Error Generator */
++      sr_modify_reg(sr, ERRCONFIG_V2, (SR_ERRWEIGHT_MASK |
++              SR_ERRMAXLIMIT_MASK | SR_ERRMINLIMIT_MASK),
++              ((sens->opp_data[sens->curr_opp].err_weight <<
++                        ERRCONFIG_ERRWEIGHT_SHIFT) |
++              (sens->opp_data[sens->curr_opp].err_maxlimit <<
++                        ERRCONFIG_ERRMAXLIMIT_SHIFT) |
++              (sens->opp_data[sens->curr_opp].err_minlimit <<
++                        ERRCONFIG_ERRMINLIMIT_SHIFT)),
++              srid);
++}
++
++/* sr_enable - Enable SR module
++ * @sr:               contains SR driver data
++ * @srid:     contains the srid, specify whether it is CORE or MPU
++ *
++ * Enable SR module by writing nTarget values to corresponding SR
++ * NVALUERECIPROCAL register, enable the interrupt and enable SR
++ */
++static void sr_enable(struct am33xx_sr *sr, u32 srid)
++{
++        struct am33xx_sr_sensor *sens;
++
++        sens = &sr->sen[srid];
++
++      /* Check if SR is already enabled. If yes do nothing */
++      if (sr_read_reg(sr, SRCONFIG, srid) & SRCONFIG_SRENABLE)
++              return;
++
++      if (sens->opp_data[sens->curr_opp].nvalue == 0)
++              dev_err(&sr->pdev->dev,
++                        "%s: OPP doesn't support SmartReflex\n", __func__);
++
++      /* Writing the nReciprocal value to the register */
++      sr_write_reg(sr, NVALUERECIPROCAL,
++                sens->opp_data[sens->curr_opp].adj_nvalue, srid);
++
++      /* Enable the interrupt */
++      sr_modify_reg(sr, IRQENABLE_SET, IRQENABLE_MCUBOUNDSINT,
++                              IRQENABLE_MCUBOUNDSINT, srid);
++
++      /* SRCONFIG - enable SR */
++      sr_modify_reg(sr, SRCONFIG, SRCONFIG_SRENABLE,
++                              SRCONFIG_SRENABLE, srid);
++}
++
++/* sr_disable - Disable SR module
++ * @sr:               contains SR driver data
++ * @srid:     contains the srid, specify whether it is CORE or MPU
++ *
++ * Disable SR module by disabling the interrupt and Smartreflex module
++ */
++static void sr_disable(struct am33xx_sr *sr, u32 srid)
++{
++      /* Disable the interrupt */
++      sr_modify_reg(sr, IRQENABLE_CLR, IRQENABLE_MCUBOUNDSINT,
++                              IRQENABLE_MCUBOUNDSINT, srid);
++
++      /* SRCONFIG - disable SR */
++      sr_modify_reg(sr, SRCONFIG, SRCONFIG_SRENABLE,
++                              ~SRCONFIG_SRENABLE, srid);
++}
++
++/* sr_start_vddautocomp - Start VDD auto compensation
++ * @sr:               contains SR driver data
++ *
++ * This is the starting point for AVS enable from user space.
++ * Also used to re-enable SR after OPP change.
++ */
++static void sr_start_vddautocomp(struct am33xx_sr *sr)
++{
++      int i;
++
++      if ((sr->sen[SR_CORE].opp_data[0].nvalue == 0) ||
++                (sr->sen[SR_MPU].opp_data[0].nvalue == 0)) {
++              dev_err(&sr->pdev->dev, "SR module not enabled, nTarget"
++                                      " values are not found\n");
++              return;
++      }
++
++      if (sr->autocomp_active == 1) {
++              dev_warn(&sr->pdev->dev, "SR VDD autocomp already active\n");
++              return;
++      }
++
++      for (i = 0; i < sr->no_of_sens; i++) {
++                      /* Read current regulator value and voltage */
++              sr->sen[i].init_volt_mv = regulator_get_voltage(sr->sen[i].reg);
++
++                dev_dbg(&sr->pdev->dev, "%s: regulator %d, init_volt = %d\n",
++                        __func__, i, sr->sen[i].init_volt_mv);
++
++              if (sr_clk_enable(sr, i))
++                        return;
++              sr_configure(sr, i);
++              sr_enable(sr, i);
++      }
++
++      sr->autocomp_active = 1;
++}
++
++/* sr_stop_vddautocomp - Stop VDD auto compensation
++ * @sr:               contains SR driver data
++ *
++ * This is the ending point during SR disable from user space.
++ * Also used to disable SR after OPP change.
++ */
++static void sr_stop_vddautocomp(struct am33xx_sr *sr)
++{
++      int i;
++
++      if (sr->autocomp_active == 0) {
++              dev_warn(&sr->pdev->dev, "SR VDD autocomp is not active\n");
++              return;
++      }
++
++        /* cancel bottom half interrupt handlers that haven't run yet */
++      cancel_delayed_work_sync(&sr->work);
++
++      for (i = 0; i < sr->no_of_sens; i++) {
++                /* cancel any outstanding SR IRQ re-enables on work queue */
++                cancel_delayed_work_sync(&sr->sen[i].work_reenable);
++              sr_disable(sr, i);
++              sr_clk_disable(sr, i);
++      }
++
++      sr->autocomp_active = 0;
++}
++
++/* am33xx_sr_autocomp_show - Store user input value and stop SR
++ * @data:             contains SR driver data
++ * @val:              pointer to store autocomp_active status
++ *
++ * This is the Debug Fs enteries to show whether SR is enabled
++ * or disabled
++ */
++static int am33xx_sr_autocomp_show(void *data, u64 *val)
++{
++      struct am33xx_sr *sr_info = (struct am33xx_sr *) data;
++
++      *val = (u64) sr_info->autocomp_active;
++
++      return 0;
++}
++
++static int am33xx_sr_margin_show(void *data, u64 *val)
++{
++        struct am33xx_sr_opp_data *sr_opp_data = (struct am33xx_sr_opp_data *)data;
++
++      *val = (u64) sr_opp_data->margin;
++
++      return 0;
++}
++
++static int am33xx_sr_margin_update(void *data, u64 val)
++{
++        struct am33xx_sr_opp_data *sr_opp_data =
++                (struct am33xx_sr_opp_data *)data;
++        struct am33xx_sr_sensor *sr_sensor;
++        struct am33xx_sr *sr_info;
++
++        /* work back to the sr_info pointer */
++        sr_sensor = container_of((void *)sr_opp_data, struct am33xx_sr_sensor,
++                opp_data[sr_opp_data->opp_id]);
++
++        sr_info = container_of((void *)sr_sensor, struct am33xx_sr,
++                sen[sr_sensor->sr_id]);
++
++        /* store the value of margin */
++        sr_opp_data->margin = (s32)val;
++
++        dev_warn(&sr_info->pdev->dev, "%s: new margin=%d, srid=%d, opp=%d\n",
++                __func__, sr_opp_data->margin, sr_sensor->sr_id,
++                sr_opp_data->opp_id);
++
++        /* updata ntarget values based upon new margin */
++        if (sr_set_nvalues(sr_info, sr_sensor->sr_id) == -EINVAL)
++                dev_err(&sr_info->pdev->dev,
++                        "%s: Zero NValue read from EFUSE\n", __func__);
++
++        /* restart SmartReflex to adapt to new values */
++        sr_stop_vddautocomp(sr_info);
++        sr_start_vddautocomp(sr_info);
++
++        return 0;
++}
++
++/* am33xx_sr_autocomp_store - Store user input and start SR
++ * @data:             contains SR driver data
++ * @val:              contains the value pased by user
++ *
++ * This is the Debug Fs enteries to store user input and
++ * enable smartreflex.
++ */
++static int am33xx_sr_autocomp_store(void *data, u64 val)
++{
++      struct am33xx_sr *sr_info = (struct am33xx_sr *) data;
++
++      /* Sanity check */
++      if (val && (val != 1)) {
++              dev_warn(&sr_info->pdev->dev, "%s: Invalid argument %llu\n",
++                      __func__, val);
++              return -EINVAL;
++      }
++
++      if (!val) {
++                sr_info->disabled_by_user = 1;
++              sr_stop_vddautocomp(sr_info);
++        }
++      else {
++                sr_info->disabled_by_user = 0;
++              sr_start_vddautocomp(sr_info);
++        }
++
++      return 0;
++}
++
++DEFINE_SIMPLE_ATTRIBUTE(sr_fops, am33xx_sr_autocomp_show,
++              am33xx_sr_autocomp_store, "%llu\n");
++
++/* sr_curr_volt_show - Show current voltage value
++ * @data:             contains SR driver data
++ * @val:              pointer to store current voltage value
++ *
++ * Read the current voltage value and display the same on console
++ * This is used in debugfs entries
++ */
++static int am33xx_sr_curr_volt_show(void *data, u64 *val)
++{
++      struct am33xx_sr_sensor *sr_sensor = (struct am33xx_sr_sensor *) data;
++
++      *val = (u64) regulator_get_voltage(sr_sensor->reg);
++
++      return 0;
++}
++
++DEFINE_SIMPLE_ATTRIBUTE(curr_volt_fops, am33xx_sr_curr_volt_show,
++              NULL, "%llu\n");
++
++DEFINE_SIMPLE_ATTRIBUTE(margin_fops, am33xx_sr_margin_show,
++              am33xx_sr_margin_update, "%llu\n");
++
++#ifdef CONFIG_DEBUG_FS
++/* sr_debugfs_entries - Create debugfs entries
++ * @sr_info:          contains SR driver data
++ *
++ * Create debugfs entries, which is exposed to user for knowing
++ * the current status. Some of the parameters can change during
++ * run time
++ */
++static int sr_debugfs_entries(struct am33xx_sr *sr_info)
++{
++        struct am33xx_sr_sensor *sens;
++      struct dentry *dbg_dir, *sen_dir, *opp_dir;
++      int i, j;
++
++      dbg_dir = debugfs_create_dir("smartreflex", NULL);
++      if (IS_ERR(dbg_dir)) {
++              dev_err(&sr_info->pdev->dev, "%s: Unable to create debugfs"
++                              " directory\n", __func__);
++              return PTR_ERR(dbg_dir);
++      }
++
++      (void) debugfs_create_file("autocomp", S_IRUGO | S_IWUGO, dbg_dir,
++                              (void *)sr_info, &sr_fops);
++        (void) debugfs_create_u32("interrupt_delay", S_IRUGO | S_IWUGO,
++                              dbg_dir, &sr_info->irq_delay);
++
++      for (i = 0; i < sr_info->no_of_sens; i++) {
++                sens = &sr_info->sen[i];
++              sen_dir = debugfs_create_dir(sens->name, dbg_dir);
++              if (IS_ERR(sen_dir)) {
++                      dev_err(&sr_info->pdev->dev, "%s: Unable to create"
++                              " debugfs directory\n", __func__);
++                      return PTR_ERR(sen_dir);
++              }
++
++                (void)debugfs_create_u32("initial_voltage", S_IRUGO, sen_dir,
++                              &sens->init_volt_mv);
++              (void)debugfs_create_file("current_voltage", S_IRUGO, sen_dir,
++                              (void *)sens, &curr_volt_fops);
++
++                for (j = 0; j < sr_info->sen[i].no_of_opps; j++) {
++                        char tmp[20];
++
++                        sprintf(&tmp[0], "opp%d", j);
++                        opp_dir = debugfs_create_dir(tmp, sen_dir);
++                        if (IS_ERR(opp_dir)) {
++                              dev_err(&sr_info->pdev->dev,
++                                        "%s: Unable to create debugfs directory\n",
++                                        __func__);
++                              return PTR_ERR(opp_dir);
++                      }
++
++                        (void)debugfs_create_file("margin", S_IRUGO | S_IWUGO,
++                             opp_dir, (void *)&sens->opp_data[j],
++                               &margin_fops);
++                        (void)debugfs_create_x32("err2voltgain",
++                               S_IRUGO | S_IWUGO,
++                             opp_dir,
++                               &sens->opp_data[j].e2v_gain);
++                      (void)debugfs_create_x32("nvalue", S_IRUGO,
++                             opp_dir,
++                               &sens->opp_data[j].nvalue);
++                        (void)debugfs_create_x32("adj_nvalue", S_IRUGO,
++                             opp_dir,
++                               &sens->opp_data[j].adj_nvalue);
++                }
++      }
++      return 0;
++}
++#else
++static int sr_debugfs_entries(struct am33xx_sr *sr_info)
++{
++      return 0;
++}
++#endif
++
++#ifdef CONFIG_CPU_FREQ
++
++/* Find and return current OPP.  This should change to use system APIs,
++   but voltdm is not currently populated, and opp APIs are also not working. */
++static int get_current_opp(struct am33xx_sr *sr, u32 srid, u32 freq)  {
++        int i;
++
++        for (i = 0; i < sr->sen[srid].no_of_opps; i++) {
++                if (sr->sen[srid].opp_data[i].frequency == freq)
++                        return i;
++        }
++
++        return -EINVAL;
++}
++
++static int am33xx_sr_cpufreq_transition(struct notifier_block *nb,
++                                        unsigned long val, void *data)
++{
++        struct am33xx_sr *sr;
++        struct cpufreq_freqs *cpu;
++
++      sr = container_of(nb, struct am33xx_sr, freq_transition);
++
++        /* We are required to disable SR while OPP change is occurring */
++      if (val == CPUFREQ_PRECHANGE) {
++                dev_dbg(&sr->pdev->dev, "%s: prechange\n", __func__);
++                sr_stop_vddautocomp(sr);
++      } else if (val == CPUFREQ_POSTCHANGE) {
++                cpu = (struct cpufreq_freqs *)data;
++                dev_dbg(&sr->pdev->dev,
++                        "%s: postchange, cpu=%d, old=%d, new=%d\n",
++                        __func__, cpu->cpu, cpu->old, cpu->new);
++
++                /* update current OPP */
++                sr->sen[SR_MPU].curr_opp = get_current_opp(sr, SR_MPU,
++                        cpu->new*1000);
++                if (sr->sen[SR_MPU].curr_opp == -EINVAL) {
++                        dev_err(&sr->pdev->dev, "%s: cannot determine opp\n",
++                                __func__);
++                        return -EINVAL;
++                }
++
++                dev_dbg(&sr->pdev->dev, "%s: postchange, new opp=%d\n",
++                        __func__, sr->sen[SR_MPU].curr_opp);
++
++                /* this handles the case when the user has disabled SR via
++                   debugfs, therefore we do not want to enable SR */
++                if (sr->disabled_by_user == 0)
++                        sr_start_vddautocomp(sr);
++      }
++
++      return 0;
++}
++
++static inline int am33xx_sr_cpufreq_register(struct am33xx_sr *sr)
++{
++        sr->freq_transition.notifier_call = am33xx_sr_cpufreq_transition;
++
++      return cpufreq_register_notifier(&sr->freq_transition,
++                                       CPUFREQ_TRANSITION_NOTIFIER);
++}
++
++static inline void am33xx_sr_cpufreq_deregister(struct am33xx_sr *sr)
++{
++      cpufreq_unregister_notifier(&sr->freq_transition,
++                                  CPUFREQ_TRANSITION_NOTIFIER);
++}
++
++#endif
++
++static int __init am33xx_sr_probe(struct platform_device *pdev)
++{
++      struct am33xx_sr *sr_info;
++      struct am33xx_sr_platform_data *pdata;
++      struct resource *res[MAX_SENSORS];
++      int irq;
++      int ret;
++      int i,j;
++
++      sr_info = kzalloc(sizeof(struct am33xx_sr), GFP_KERNEL);
++      if (!sr_info) {
++              dev_err(&pdev->dev, "%s: unable to allocate sr_info\n",
++                                      __func__);
++              return -ENOMEM;
++      }
++
++      pdata = pdev->dev.platform_data;
++      if (!pdata) {
++              dev_err(&pdev->dev, "%s: platform data missing\n", __func__);
++              ret = -EINVAL;
++              goto err_free_sr_info;
++      }
++
++      sr_info->pdev = pdev;
++      sr_info->sen[SR_CORE].name = "smartreflex0";
++      sr_info->sen[SR_MPU].name = "smartreflex1";
++      sr_info->ip_type = pdata->ip_type;
++        sr_info->irq_delay = pdata->irq_delay;
++        sr_info->no_of_sens = pdata->no_of_sens;
++        sr_info->no_of_vds = pdata->no_of_vds;
++      sr_info->uvoltage_step_size = pdata->vstep_size_uv;
++      sr_info->autocomp_active = false;
++        sr_info->disabled_by_user = false;
++
++      for (i = 0; i < sr_info->no_of_sens; i++) {
++                u32 curr_freq=0;
++
++                sr_info->sen[i].reg_name = pdata->vd_name[i];
++
++                /* this should be determined from voltdm or opp layer, but
++                   those approaches are not working */
++                sr_info->sen[i].no_of_opps = pdata->sr_sdata[i].no_of_opps;
++                sr_info->sen[i].sr_id = i;
++
++                /* Reading per OPP Values */
++                for (j = 0; j < sr_info->sen[i].no_of_opps; j++) {
++                      sr_info->sen[i].opp_data[j].efuse_offs =
++                                pdata->sr_sdata[i].sr_opp_data[j].efuse_offs;
++                        sr_info->sen[i].opp_data[j].e2v_gain =
++                                pdata->sr_sdata[i].sr_opp_data[j].e2v_gain;
++                      sr_info->sen[i].opp_data[j].err_weight =
++                                pdata->sr_sdata[i].sr_opp_data[j].err_weight;
++                      sr_info->sen[i].opp_data[j].err_minlimit =
++                                pdata->sr_sdata[i].sr_opp_data[j].err_minlimit;
++                      sr_info->sen[i].opp_data[j].err_maxlimit =
++                                pdata->sr_sdata[i].sr_opp_data[j].err_maxlimit;
++                        sr_info->sen[i].opp_data[j].margin =
++                                pdata->sr_sdata[i].sr_opp_data[j].margin;
++                        sr_info->sen[i].opp_data[j].nominal_volt =
++                                pdata->sr_sdata[i].sr_opp_data[j].nominal_volt;
++                        sr_info->sen[i].opp_data[j].frequency =
++                                pdata->sr_sdata[i].sr_opp_data[j].frequency;
++                        sr_info->sen[i].opp_data[j].opp_id = j;
++                }
++
++                if (i == SR_MPU) {
++                        /* hardcoded CPU NR */
++                        curr_freq = cpufreq_get(0);
++
++                        /* update current OPP */
++                        sr_info->sen[i].curr_opp = get_current_opp(sr_info, i,
++                                        curr_freq*1000);
++                        if (sr_info->sen[i].curr_opp == -EINVAL) {
++                                dev_err(&sr_info->pdev->dev,
++                                        "%s: cannot determine opp\n",__func__);
++                                ret = -EINVAL;
++                                goto err_free_sr_info;
++                        }
++                } else {
++                        sr_info->sen[i].curr_opp =
++                                pdata->sr_sdata[i].default_opp;
++                }
++
++                dev_dbg(&pdev->dev,
++                        "%s: SR%d, curr_opp=%d, no_of_opps=%d, step_size=%d\n",
++                        __func__, i, sr_info->sen[i].curr_opp,
++                        sr_info->sen[i].no_of_opps,
++                        sr_info->uvoltage_step_size);
++
++                ret = sr_set_nvalues(sr_info, i);
++                if (ret == -EINVAL) {
++                        dev_err(&sr_info->pdev->dev,
++                                "%s: Zero NValue read from EFUSE\n", __func__);
++                        goto err_free_sr_info;
++                }
++
++                INIT_DELAYED_WORK(&sr_info->sen[i].work_reenable,
++                        irq_sr_reenable);
++
++              sr_info->res_name[i] = kzalloc(CLK_NAME_LEN + 1, GFP_KERNEL);
++
++              /* resources */
++              res[i] = platform_get_resource_byname(pdev, IORESOURCE_MEM,
++                                      sr_info->sen[i].name);
++              if (!res[i]) {
++                      dev_err(&pdev->dev, "%s: no mem resource\n", __func__);
++                      ret = -ENOENT;
++                      goto err_free_mem;
++              }
++
++              irq = platform_get_irq_byname(pdev, sr_info->sen[i].name);
++              if (irq < 0) {
++                      dev_err(&pdev->dev, "Can't get interrupt resource\n");
++                      ret = irq;
++                      goto err_free_mem;
++              }
++              sr_info->sen[i].irq = irq;
++
++              res[i] = request_mem_region(res[i]->start,
++                              resource_size(res[i]), pdev->name);
++              if (!res[i]) {
++                      dev_err(&pdev->dev, "can't request mem region\n");
++                      ret = -EBUSY;
++                      goto err_free_mem;
++              }
++
++              sr_info->sen[i].base = ioremap(res[i]->start,
++                              resource_size(res[i]));
++              if (!sr_info->sen[i].base) {
++                      dev_err(&pdev->dev, "%s: ioremap fail\n", __func__);
++                      ret = -ENOMEM;
++                      goto err_release_mem;
++              }
++
++              strcat(sr_info->res_name[i], sr_info->sen[i].name);
++              strcat(sr_info->res_name[i], "_fck");
++
++              sr_info->sen[i].fck = clk_get(NULL, sr_info->res_name[i]);
++              if (IS_ERR(sr_info->sen[i].fck)) {
++                      dev_err(&pdev->dev, "%s: Could not get sr fck\n",
++                                              __func__);
++                      ret = PTR_ERR(sr_info->sen[i].fck);
++                      goto err_unmap;
++              }
++
++              ret = request_irq(sr_info->sen[i].irq, sr_class2_irq,
++                      IRQF_DISABLED, sr_info->sen[i].name,
++                        (void *)&sr_info->sen[i]);
++              if (ret) {
++                      dev_err(&pdev->dev, "%s: Could not install SR ISR\n",
++                                              __func__);
++                      goto err_put_clock;
++              }
++
++              sr_info->sen[i].senn_en = pdata->sr_sdata[i].senn_mod;
++              sr_info->sen[i].senp_en = pdata->sr_sdata[i].senp_mod;
++
++                sr_info->sen[i].reg =
++                        regulator_get(NULL, sr_info->sen[i].reg_name);
++                      if (IS_ERR(sr_info->sen[i].reg)) {
++                        ret = -EINVAL;
++                      goto err_free_irq;
++                }
++
++                      /* Read current regulator value and voltage */
++              sr_info->sen[i].init_volt_mv =
++                        regulator_get_voltage(sr_info->sen[i].reg);
++
++                dev_dbg(&pdev->dev, "%s: regulator %d, init_volt = %d\n",
++                        __func__, i, sr_info->sen[i].init_volt_mv);
++      } /* for() */
++
++        /* set_voltage() will be used as the bottom half IRQ handler */
++      INIT_DELAYED_WORK(&sr_info->work, set_voltage);
++
++#ifdef CONFIG_CPU_FREQ
++      ret = am33xx_sr_cpufreq_register(sr_info);
++      if (ret) {
++              dev_err(&pdev->dev, "failed to register cpufreq\n");
++              goto err_reg_put;
++      }
++#endif
++
++      /* debugfs entries */
++      ret = sr_debugfs_entries(sr_info);
++      if (ret)
++              dev_warn(&pdev->dev, "%s: Debugfs entries are not created\n",
++                                              __func__);
++
++      platform_set_drvdata(pdev, sr_info);
++
++      dev_info(&pdev->dev, "%s: Driver initialized\n", __func__);
++
++        /* disabled_by_user used to ensure SR doesn't come on via CPUFREQ
++           scaling if user has disabled SR via debugfs on enable_on_init */
++      if (pdata->enable_on_init)
++              sr_start_vddautocomp(sr_info);
++        else
++                sr_info->disabled_by_user = 1;
++
++      return ret;
++
++#ifdef CONFIG_CPU_FREQ
++      am33xx_sr_cpufreq_deregister(sr_info);
++#endif
++
++err_reg_put:
++        i--; /* back up i by one to walk back through the for loop */
++        regulator_put(sr_info->sen[i].reg);
++err_free_irq:
++      free_irq(sr_info->sen[i].irq, (void *)sr_info);
++err_put_clock:
++      clk_put(sr_info->sen[i].fck);
++err_unmap:
++      iounmap(sr_info->sen[i].base);
++err_release_mem:
++      release_mem_region(res[i]->start, resource_size(res[i]));
++err_free_mem:
++        kfree(sr_info->res_name[i]);
++        /* unwind back through the for loop */
++        if (i != 0) {
++                goto err_reg_put;
++        }
++
++err_free_sr_info:
++      kfree(sr_info);
++      return ret;
++}
++
++static int __devexit am33xx_sr_remove(struct platform_device *pdev)
++{
++      struct am33xx_sr *sr_info;
++      struct resource *res[MAX_SENSORS];
++      int irq;
++      int i;
++
++      sr_info = dev_get_drvdata(&pdev->dev);
++      if (!sr_info) {
++              dev_err(&pdev->dev, "%s: sr_info missing\n", __func__);
++              return -EINVAL;
++      }
++
++      if (sr_info->autocomp_active)
++              sr_stop_vddautocomp(sr_info);
++
++#ifdef CONFIG_CPU_FREQ
++      am33xx_sr_cpufreq_deregister(sr_info);
++#endif
++
++      for (i = 0; i < sr_info->no_of_sens; i++) {
++                regulator_put(sr_info->sen[i].reg);
++                irq = platform_get_irq_byname(pdev, sr_info->sen[i].name);
++              free_irq(irq, (void *)sr_info);
++              clk_put(sr_info->sen[i].fck);
++              iounmap(sr_info->sen[i].base);
++              res[i] = platform_get_resource_byname(pdev,
++                              IORESOURCE_MEM, sr_info->sen[i].name);
++              release_mem_region(res[i]->start, resource_size(res[i]));
++                kfree(sr_info->res_name[i]);
++      }
++
++      kfree(sr_info);
++
++        dev_info(&pdev->dev, "%s: SR has been removed\n", __func__);
++      return 0;
++}
++
++static struct platform_driver smartreflex_driver = {
++      .driver         = {
++              .name   = "smartreflex",
++              .owner  = THIS_MODULE,
++      },
++      .remove         = am33xx_sr_remove,
++};
++
++static int __init sr_init(void)
++{
++      int ret;
++
++      ret = platform_driver_probe(&smartreflex_driver, am33xx_sr_probe);
++      if (ret) {
++              pr_err("%s: platform driver register failed\n", __func__);
++              return ret;
++      }
++
++      return 0;
++}
++
++static void __exit sr_exit(void)
++{
++      platform_driver_unregister(&smartreflex_driver);
++}
++late_initcall(sr_init);
++module_exit(sr_exit);
++
++MODULE_DESCRIPTION("AM33XX Smartreflex Class2 Driver");
++MODULE_LICENSE("GPL");
++MODULE_ALIAS("platform:" DRIVER_NAME);
++MODULE_AUTHOR("Texas Instruments Inc");
+diff --git a/arch/arm/mach-omap2/board-am335xevm.c b/arch/arm/mach-omap2/board-am335xevm.c
+index 0bcadd7..6e1c026 100644
+--- a/arch/arm/mach-omap2/board-am335xevm.c
++++ b/arch/arm/mach-omap2/board-am335xevm.c
+@@ -1410,6 +1410,7 @@ static struct regulator_init_data tps65217_regulator_data[] = {
+               .num_consumer_supplies = ARRAY_SIZE(tps65217_dcdc2_consumers),
+               .consumer_supplies = tps65217_dcdc2_consumers,
+               .driver_data = &dcdc2_ramp_delay,
++              .ignore_check_consumers = 1,
+       },
+
+       /* dcdc3 */
+@@ -1424,6 +1425,7 @@ static struct regulator_init_data tps65217_regulator_data[] = {
+               },
+               .num_consumer_supplies = ARRAY_SIZE(tps65217_dcdc3_consumers),
+               .consumer_supplies = tps65217_dcdc3_consumers,
++              .ignore_check_consumers = 1,
+       },
+
+       /* ldo1 */
+@@ -2214,6 +2216,9 @@ static void am335x_evm_setup(struct memory_accessor *mem_acc, void *context)
+                       goto out;
+       }
+
++      /* SmartReflex also requires board information. */
++      am33xx_sr_init();
++
+       return;
+
+ out:
+@@ -2265,6 +2270,7 @@ static struct regulator_init_data am335x_vdd1 = {
+       },
+       .num_consumer_supplies  = ARRAY_SIZE(am335x_vdd1_supply),
+       .consumer_supplies      = am335x_vdd1_supply,
++      .ignore_check_consumers = 1,
+ };
+
+ static struct regulator_consumer_supply am335x_vdd2_supply[] = {
+@@ -2281,6 +2287,7 @@ static struct regulator_init_data am335x_vdd2 = {
+       },
+       .num_consumer_supplies  = ARRAY_SIZE(am335x_vdd2_supply),
+       .consumer_supplies      = am335x_vdd2_supply,
++      .ignore_check_consumers = 1,
+ };
+
+ static struct tps65910_board am335x_tps65910_info = {
+diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c
+index 6113654..ebf0d9e 100644
+--- a/arch/arm/mach-omap2/devices.c
++++ b/arch/arm/mach-omap2/devices.c
+@@ -52,6 +52,7 @@
+ #include <plat/config_pwm.h>
+ #include <plat/cpu.h>
+ #include <plat/gpmc.h>
++#include <plat/smartreflex.h>
+ #include <plat/am33xx.h>
+
+ /* LCD controller similar DA8xx */
+@@ -60,10 +61,28 @@
+ #include "mux.h"
+ #include "control.h"
+ #include "devices.h"
++#include "omap_opp_data.h"
+
+ #define L3_MODULES_MAX_LEN 12
+ #define L3_MODULES 3
+
++static unsigned int   am33xx_evmid;
++
++/*
++ * am33xx_evmid_fillup - set up board evmid
++ * @evmid - evm id which needs to be configured
++ *
++ * This function is called to configure board evm id.
++ * IA Motor Control EVM needs special setting of MAC PHY Id.
++ * This function is called when IA Motor Control EVM is detected
++ * during boot-up.
++ */
++void am33xx_evmid_fillup(unsigned int evmid)
++{
++       am33xx_evmid = evmid;
++       return;
++}
++
+ static int __init omap3_l3_init(void)
+ {
+       int l;
+@@ -1226,6 +1245,256 @@ static struct platform_device am335x_sgx = {
+
+ #endif
+
++#ifdef CONFIG_AM33XX_SMARTREFLEX
++
++/* smartreflex platform data */
++
++/* The values below are based upon silicon characterization data.
++ * Each OPP and sensor combination potentially has different values.
++ * The values of ERR2VOLT_GAIN and ERR_MIN_LIMIT also change based on
++ * the PMIC step size.  Values have been given to cover the AM335 EVM
++ * (12.5mV step) and the Beaglebone (25mV step).  If the step
++ * size changes, you should update these values, and don't forget to
++ * change the step size in the platform data structure, am33xx_sr_pdata.
++ */
++
++#define AM33XX_SR0_OPP50_CNTRL_OFFSET          0x07B8
++#define AM33XX_SR0_OPP50_EVM_ERR2VOLT_GAIN     0xC
++#define AM33XX_SR0_OPP50_EVM_ERR_MIN_LIMIT     0xF5
++#define AM33XX_SR0_OPP50_BB_ERR2VOLT_GAIN      0x6
++#define AM33XX_SR0_OPP50_BB_ERR_MIN_LIMIT      0xEA
++#define AM33XX_SR0_OPP50_ERR_MAX_LIMIT         0x2
++#define AM33XX_SR0_OPP50_ERR_WEIGHT             0x4
++#define AM33XX_SR0_OPP50_MARGIN                 0
++
++#define AM33XX_SR0_OPP100_CNTRL_OFFSET         0x07BC
++#define AM33XX_SR0_OPP100_EVM_ERR2VOLT_GAIN     0x12
++#define AM33XX_SR0_OPP100_EVM_ERR_MIN_LIMIT    0xF8
++#define AM33XX_SR0_OPP100_BB_ERR2VOLT_GAIN      0x9
++#define AM33XX_SR0_OPP100_BB_ERR_MIN_LIMIT     0xF1
++#define AM33XX_SR0_OPP100_ERR_MAX_LIMIT                0x2
++#define AM33XX_SR0_OPP100_ERR_WEIGHT            0x4
++#define AM33XX_SR0_OPP100_MARGIN                0
++
++#define AM33XX_SR1_OPP50_CNTRL_OFFSET          0x0770
++#define AM33XX_SR1_OPP50_EVM_ERR2VOLT_GAIN     0x5
++#define AM33XX_SR1_OPP50_EVM_ERR_MIN_LIMIT     0xE6
++#define AM33XX_SR1_OPP50_BB_ERR2VOLT_GAIN      0x2
++#define AM33XX_SR1_OPP50_BB_ERR_MIN_LIMIT      0xC0
++#define AM33XX_SR1_OPP50_ERR_MAX_LIMIT         0x2
++#define AM33XX_SR1_OPP50_ERR_WEIGHT             0x4
++#define AM33XX_SR1_OPP50_MARGIN                 0
++
++#define AM33XX_SR1_OPP100_CNTRL_OFFSET         0x0774
++#define AM33XX_SR1_OPP100_EVM_ERR2VOLT_GAIN    0x8
++#define AM33XX_SR1_OPP100_EVM_ERR_MIN_LIMIT    0xF0
++#define AM33XX_SR1_OPP100_BB_ERR2VOLT_GAIN     0x4
++#define AM33XX_SR1_OPP100_BB_ERR_MIN_LIMIT     0xDF
++#define AM33XX_SR1_OPP100_ERR_MAX_LIMIT                0x2
++#define AM33XX_SR1_OPP100_ERR_WEIGHT            0x4
++#define AM33XX_SR1_OPP100_MARGIN                0
++
++#define AM33XX_SR1_OPP120_CNTRL_OFFSET         0x0778
++#define AM33XX_SR1_OPP120_EVM_ERR2VOLT_GAIN    0xB
++#define AM33XX_SR1_OPP120_EVM_ERR_MIN_LIMIT    0xF4
++#define AM33XX_SR1_OPP120_BB_ERR2VOLT_GAIN     0x5
++#define AM33XX_SR1_OPP120_BB_ERR_MIN_LIMIT     0xE6
++#define AM33XX_SR1_OPP120_ERR_MAX_LIMIT                0x2
++#define AM33XX_SR1_OPP120_ERR_WEIGHT            0x4
++#define AM33XX_SR1_OPP120_MARGIN                0
++
++#define AM33XX_SR1_OPPTURBO_CNTRL_OFFSET        0x077C
++#define AM33XX_SR1_OPPTURBO_EVM_ERR2VOLT_GAIN  0xC
++#define AM33XX_SR1_OPPTURBO_EVM_ERR_MIN_LIMIT  0xF5
++#define AM33XX_SR1_OPPTURBO_BB_ERR2VOLT_GAIN   0x6
++#define AM33XX_SR1_OPPTURBO_BB_ERR_MIN_LIMIT   0xEA
++#define AM33XX_SR1_OPPTURBO_ERR_MAX_LIMIT      0x2
++#define AM33XX_SR1_OPPTURBO_ERR_WEIGHT          0x4
++#define AM33XX_SR1_OPPTURBO_MARGIN              0
++
++/* the voltages and frequencies should probably be defined in opp3xxx_data.c.
++   Once SR is integrated to the mainline driver, and voltdm is working
++   correctly in AM335x, these can be removed.  */
++#define AM33XX_VDD_MPU_OPP50_UV                950000
++#define AM33XX_VDD_MPU_OPP100_UV       1100000
++#define AM33XX_VDD_MPU_OPP120_UV       1200000
++#define AM33XX_VDD_MPU_OPPTURBO_UV     1260000
++#define AM33XX_VDD_CORE_OPP50_UV        950000
++#define AM33XX_VDD_CORE_OPP100_UV       1100000
++
++#define AM33XX_VDD_MPU_OPP50_FREQ      275000000
++#define AM33XX_VDD_MPU_OPP100_FREQ     500000000
++#define AM33XX_VDD_MPU_OPP120_FREQ     600000000
++#define AM33XX_VDD_MPU_OPPTURBO_FREQ   720000000
++
++static struct am33xx_sr_opp_data sr1_opp_data[] = {
++        {
++                .efuse_offs    = AM33XX_SR1_OPP50_CNTRL_OFFSET,
++               .e2v_gain       = AM33XX_SR1_OPP50_EVM_ERR2VOLT_GAIN,
++               .err_minlimit   = AM33XX_SR1_OPP50_EVM_ERR_MIN_LIMIT,
++               .err_maxlimit   = AM33XX_SR1_OPP50_ERR_MAX_LIMIT,
++               .err_weight     = AM33XX_SR1_OPP50_ERR_WEIGHT,
++                .margin         = AM33XX_SR1_OPP50_MARGIN,
++                .nominal_volt   = AM33XX_VDD_MPU_OPP50_UV,
++                .frequency      = AM33XX_VDD_MPU_OPP50_FREQ,
++        },
++        {
++                .efuse_offs    = AM33XX_SR1_OPP100_CNTRL_OFFSET,
++               .e2v_gain       = AM33XX_SR1_OPP100_EVM_ERR2VOLT_GAIN,
++               .err_minlimit   = AM33XX_SR1_OPP100_EVM_ERR_MIN_LIMIT,
++               .err_maxlimit   = AM33XX_SR1_OPP100_ERR_MAX_LIMIT,
++               .err_weight     = AM33XX_SR1_OPP100_ERR_WEIGHT,
++                .margin         = AM33XX_SR1_OPP100_MARGIN,
++                .nominal_volt   = AM33XX_VDD_MPU_OPP100_UV,
++                .frequency      = AM33XX_VDD_MPU_OPP100_FREQ,
++        },
++        {
++                .efuse_offs    = AM33XX_SR1_OPP120_CNTRL_OFFSET,
++               .e2v_gain       = AM33XX_SR1_OPP120_EVM_ERR2VOLT_GAIN,
++               .err_minlimit   = AM33XX_SR1_OPP120_EVM_ERR_MIN_LIMIT,
++               .err_maxlimit   = AM33XX_SR1_OPP120_ERR_MAX_LIMIT,
++               .err_weight     = AM33XX_SR1_OPP120_ERR_WEIGHT,
++                .margin         = AM33XX_SR1_OPP120_MARGIN,
++                .nominal_volt   = AM33XX_VDD_MPU_OPP120_UV,
++                .frequency      = AM33XX_VDD_MPU_OPP120_FREQ,
++        },
++        {
++                .efuse_offs    = AM33XX_SR1_OPPTURBO_CNTRL_OFFSET,
++               .e2v_gain       = AM33XX_SR1_OPPTURBO_EVM_ERR2VOLT_GAIN,
++               .err_minlimit   = AM33XX_SR1_OPPTURBO_EVM_ERR_MIN_LIMIT,
++               .err_maxlimit   = AM33XX_SR1_OPPTURBO_ERR_MAX_LIMIT,
++               .err_weight     = AM33XX_SR1_OPPTURBO_ERR_WEIGHT,
++                .margin         = AM33XX_SR1_OPPTURBO_MARGIN,
++                .nominal_volt   = AM33XX_VDD_MPU_OPPTURBO_UV,
++                .frequency      = AM33XX_VDD_MPU_OPPTURBO_FREQ,
++        },
++};
++
++static struct am33xx_sr_opp_data sr0_opp_data[] = {
++        {
++                .efuse_offs    = AM33XX_SR0_OPP50_CNTRL_OFFSET,
++               .e2v_gain       = AM33XX_SR0_OPP50_EVM_ERR2VOLT_GAIN,
++               .err_minlimit   = AM33XX_SR0_OPP50_EVM_ERR_MIN_LIMIT,
++               .err_maxlimit   = AM33XX_SR0_OPP50_ERR_MAX_LIMIT,
++               .err_weight     = AM33XX_SR0_OPP50_ERR_WEIGHT,
++                .margin         = AM33XX_SR0_OPP50_MARGIN,
++                .nominal_volt   = AM33XX_VDD_CORE_OPP50_UV,
++        },
++        {
++                .efuse_offs    = AM33XX_SR0_OPP100_CNTRL_OFFSET,
++               .e2v_gain       = AM33XX_SR0_OPP100_EVM_ERR2VOLT_GAIN,
++               .err_minlimit   = AM33XX_SR0_OPP100_EVM_ERR_MIN_LIMIT,
++               .err_maxlimit   = AM33XX_SR0_OPP100_ERR_MAX_LIMIT,
++               .err_weight     = AM33XX_SR0_OPP100_ERR_WEIGHT,
++                .margin         = AM33XX_SR0_OPP100_MARGIN,
++                .nominal_volt   = AM33XX_VDD_CORE_OPP100_UV,
++        },
++};
++
++static struct am33xx_sr_sdata sr_sensor_data[] = {
++       {
++                .sr_opp_data    = sr0_opp_data,
++                /* note that OPP50 is NOT used in Linux kernel for AM335x */
++                .no_of_opps     = 0x2,
++                .default_opp    = 0x1,
++               .senn_mod       = 0x1,
++               .senp_mod       = 0x1,
++       },
++       {
++               .sr_opp_data    = sr1_opp_data,
++                /* the opp data below should be determined
++                   dynamically during SR probe */
++                .no_of_opps     = 0x4,
++                .default_opp    = 0x3,
++               .senn_mod       = 0x1,
++               .senp_mod       = 0x1,
++       },
++};
++
++static struct am33xx_sr_platform_data am33xx_sr_pdata = {
++       .vd_name[0]             = "vdd_core",
++        .vd_name[1]             = "vdd_mpu",
++       .ip_type                = 2,
++        .irq_delay              = 1000,
++       .no_of_vds              = 2,
++       .no_of_sens             = ARRAY_SIZE(sr_sensor_data),
++       .vstep_size_uv          = 12500,
++       .enable_on_init         = true,
++       .sr_sdata               = sr_sensor_data,
++};
++
++static struct resource am33xx_sr_resources[] = {
++       {
++               .name   =       "smartreflex0",
++               .start  =       AM33XX_SR0_BASE,
++               .end    =       AM33XX_SR0_BASE + SZ_4K - 1,
++               .flags  =       IORESOURCE_MEM,
++       },
++       {
++               .name   =       "smartreflex0",
++               .start  =       AM33XX_IRQ_SMARTREFLEX0,
++               .end    =       AM33XX_IRQ_SMARTREFLEX0,
++               .flags  =       IORESOURCE_IRQ,
++       },
++       {
++               .name   =       "smartreflex1",
++               .start  =       AM33XX_SR1_BASE,
++               .end    =       AM33XX_SR1_BASE + SZ_4K - 1,
++               .flags  =       IORESOURCE_MEM,
++       },
++       {
++               .name   =       "smartreflex1",
++               .start  =       AM33XX_IRQ_SMARTREFLEX1,
++               .end    =       AM33XX_IRQ_SMARTREFLEX1,
++               .flags  =       IORESOURCE_IRQ,
++       },
++};
++
++/* VCORE for SR regulator init */
++static struct platform_device am33xx_sr_device = {
++       .name           = "smartreflex",
++       .id             = -1,
++       .num_resources  = ARRAY_SIZE(am33xx_sr_resources),
++       .resource       = am33xx_sr_resources,
++       .dev = {
++               .platform_data = &am33xx_sr_pdata,
++       },
++};
++
++void __init am33xx_sr_init(void)
++{
++        /* For beaglebone, update voltage step size and related parameters
++           appropriately.  All other AM33XX platforms are good with the
++           structure defaults as initialized above. */
++        if ((am33xx_evmid == BEAGLE_BONE_OLD) ||
++                        (am33xx_evmid == BEAGLE_BONE_A3)) {
++                printk(KERN_ERR "address of pdata = %08x\n", (u32)&am33xx_sr_pdata);
++                am33xx_sr_pdata.vstep_size_uv = 25000;
++                /* CORE */
++                sr0_opp_data[0].e2v_gain     = AM33XX_SR0_OPP50_BB_ERR2VOLT_GAIN;
++                sr0_opp_data[0].err_minlimit = AM33XX_SR0_OPP50_BB_ERR_MIN_LIMIT;
++                sr0_opp_data[1].e2v_gain     = AM33XX_SR0_OPP100_BB_ERR2VOLT_GAIN;
++                sr0_opp_data[1].err_minlimit = AM33XX_SR0_OPP100_BB_ERR_MIN_LIMIT;
++                /* MPU */
++                sr1_opp_data[0].e2v_gain     = AM33XX_SR1_OPP50_BB_ERR2VOLT_GAIN;
++                sr1_opp_data[0].err_minlimit = AM33XX_SR1_OPP50_BB_ERR_MIN_LIMIT;
++                sr1_opp_data[1].e2v_gain     = AM33XX_SR1_OPP100_BB_ERR2VOLT_GAIN;
++                sr1_opp_data[1].err_minlimit = AM33XX_SR1_OPP100_BB_ERR_MIN_LIMIT;
++                sr1_opp_data[2].e2v_gain     = AM33XX_SR1_OPP120_BB_ERR2VOLT_GAIN;
++                sr1_opp_data[2].err_minlimit = AM33XX_SR1_OPP120_BB_ERR_MIN_LIMIT;
++                sr1_opp_data[3].e2v_gain     = AM33XX_SR1_OPPTURBO_BB_ERR2VOLT_GAIN;
++                sr1_opp_data[3].err_minlimit = AM33XX_SR1_OPPTURBO_BB_ERR_MIN_LIMIT;
++        }
++
++       if (platform_device_register(&am33xx_sr_device))
++               printk(KERN_ERR "failed to register am33xx_sr device\n");
++       else
++               printk(KERN_INFO "registered am33xx_sr device\n");
++}
++#else
++inline void am33xx_sr_init(void) {}
++#endif
++
+ /*-------------------------------------------------------------------------*/
+
+ static int __init omap2_init_devices(void)
+diff --git a/arch/arm/mach-omap2/include/mach/board-am335xevm.h b/arch/arm/mach-omap2/include/mach/board-am335xevm.h
+index 1d24495..85a8df0 100644
+--- a/arch/arm/mach-omap2/include/mach/board-am335xevm.h
++++ b/arch/arm/mach-omap2/include/mach/board-am335xevm.h
+@@ -41,6 +41,7 @@
+ void am335x_evm_set_id(unsigned int evmid);
+ int am335x_evm_get_id(void);
+ void am33xx_cpsw_macidfillup(char *eeprommacid0, char *eeprommacid1);
++void am33xx_sr_init(void);
+ void am33xx_d_can_init(unsigned int instance);
+
+ #endif
+diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig
+index 734009a..33f17f2 100644
+--- a/arch/arm/plat-omap/Kconfig
++++ b/arch/arm/plat-omap/Kconfig
+@@ -43,6 +43,27 @@ config OMAP_DEBUG_LEDS
+       depends on OMAP_DEBUG_DEVICES
+       default y if LEDS_CLASS
+
++config AM33XX_SMARTREFLEX
++      bool "AM33XX SmartReflex support"
++      depends on (SOC_OMAPAM33XX) && PM
++      help
++        Say Y if you want to enable SmartReflex.
++
++        SmartReflex can perform continuous dynamic voltage
++        scaling around the nominal operating point voltage
++        according to silicon characteristics and operating
++        conditions. Enabling SmartReflex reduces active power
++        consumption.
++
++        Please note, that by default SmartReflex is enabled.
++          To disable the automatic voltage compensation for
++          vdd mpu and vdd core from user space, user must
++          write 1 to /debug/smartreflex/autocomp.
++
++        Optionally autocompensation can be disabled in the kernel
++        by default during system init via the enable_on_init flag
++        which an be passed as platform data to the smartreflex driver.
++
+ config OMAP_SMARTREFLEX
+       bool "SmartReflex support"
+       depends on (ARCH_OMAP3 || ARCH_OMAP4) && PM
+diff --git a/arch/arm/plat-omap/include/plat/am33xx.h b/arch/arm/plat-omap/include/plat/am33xx.h
+index 32522df..a628b1f 100644
+--- a/arch/arm/plat-omap/include/plat/am33xx.h
++++ b/arch/arm/plat-omap/include/plat/am33xx.h
+@@ -43,6 +43,9 @@
+ #define AM33XX_TSC_BASE               0x44E0D000
+ #define AM33XX_RTC_BASE               0x44E3E000
+
++#define AM33XX_SR0_BASE         0x44E37000
++#define AM33XX_SR1_BASE         0x44E39000
++
+ #define AM33XX_ASP0_BASE      0x48038000
+ #define AM33XX_ASP1_BASE      0x4803C000
+
+diff --git a/arch/arm/plat-omap/include/plat/smartreflex.h b/arch/arm/plat-omap/include/plat/smartreflex.h
+new file mode 100644
+index 0000000..36338f7
+--- /dev/null
++++ b/arch/arm/plat-omap/include/plat/smartreflex.h
+@@ -0,0 +1,431 @@
++/*
++ * OMAP Smartreflex Defines and Routines
++ *
++ * Author: Thara Gopinath     <thara@ti.com>
++ *
++ * Copyright (C) 2010 Texas Instruments, Inc.
++ * Thara Gopinath <thara@ti.com>
++ *
++ * Copyright (C) 2008 Nokia Corporation
++ * Kalle Jokiniemi
++ *
++ * Copyright (C) 2007 Texas Instruments, Inc.
++ * Lesly A M <x0080970@ti.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#ifndef __ASM_ARM_OMAP_SMARTREFLEX_H
++#define __ASM_ARM_OMAP_SMARTREFLEX_H
++
++#include <linux/platform_device.h>
++#include <plat/voltage.h>
++
++/*
++ * Different Smartreflex IPs version. The v1 is the 65nm version used in
++ * OMAP3430. The v2 is the update for the 45nm version of the IP
++ * used in OMAP3630 and OMAP4430
++ */
++#define SR_TYPE_V1    1
++#define SR_TYPE_V2    2
++
++/* SMART REFLEX REG ADDRESS OFFSET */
++#define SRCONFIG              0x00
++#define SRSTATUS              0x04
++#define SENVAL                        0x08
++#define SENMIN                        0x0C
++#define SENMAX                        0x10
++#define SENAVG                        0x14
++#define AVGWEIGHT             0x18
++#define NVALUERECIPROCAL      0x1c
++#define SENERROR_V1           0x20
++#define ERRCONFIG_V1          0x24
++#define IRQ_EOI                       0x20
++#define IRQSTATUS_RAW         0x24
++#define IRQSTATUS             0x28
++#define IRQENABLE_SET         0x2C
++#define IRQENABLE_CLR         0x30
++#define SENERROR_V2           0x34
++#define ERRCONFIG_V2          0x38
++
++/* Bit/Shift Positions */
++
++/* SRCONFIG */
++#define SRCONFIG_ACCUMDATA_SHIFT      22
++#define SRCONFIG_SRCLKLENGTH_SHIFT    12
++#define SRCONFIG_SENNENABLE_V1_SHIFT  5
++#define SRCONFIG_SENPENABLE_V1_SHIFT  3
++#define SRCONFIG_SENNENABLE_V2_SHIFT  1
++#define SRCONFIG_SENPENABLE_V2_SHIFT  0
++#define SRCONFIG_CLKCTRL_SHIFT                0
++
++#define SRCONFIG_ACCUMDATA_MASK               (0x3ff << 22)
++
++#define SRCONFIG_SRENABLE             BIT(11)
++#define SRCONFIG_SENENABLE            BIT(10)
++#define SRCONFIG_ERRGEN_EN            BIT(9)
++#define SRCONFIG_MINMAXAVG_EN         BIT(8)
++#define SRCONFIG_DELAYCTRL            BIT(2)
++
++/* AVGWEIGHT */
++#define AVGWEIGHT_SENPAVGWEIGHT_SHIFT 2
++#define AVGWEIGHT_SENNAVGWEIGHT_SHIFT 0
++
++/* NVALUERECIPROCAL */
++#define NVALUERECIPROCAL_SENPGAIN_SHIFT       20
++#define NVALUERECIPROCAL_SENNGAIN_SHIFT       16
++#define NVALUERECIPROCAL_RNSENP_SHIFT 8
++#define NVALUERECIPROCAL_RNSENN_SHIFT 0
++
++/* ERRCONFIG */
++#define ERRCONFIG_ERRWEIGHT_SHIFT     16
++#define ERRCONFIG_ERRMAXLIMIT_SHIFT   8
++#define ERRCONFIG_ERRMINLIMIT_SHIFT   0
++
++#define SR_ERRWEIGHT_MASK             (0x07 << 16)
++#define SR_ERRMAXLIMIT_MASK           (0xff << 8)
++#define SR_ERRMINLIMIT_MASK           (0xff << 0)
++
++#define ERRCONFIG_VPBOUNDINTEN_V1     BIT(31)
++#define ERRCONFIG_VPBOUNDINTST_V1     BIT(30)
++#define       ERRCONFIG_MCUACCUMINTEN         BIT(29)
++#define ERRCONFIG_MCUACCUMINTST               BIT(28)
++#define       ERRCONFIG_MCUVALIDINTEN         BIT(27)
++#define ERRCONFIG_MCUVALIDINTST               BIT(26)
++#define ERRCONFIG_MCUBOUNDINTEN               BIT(25)
++#define       ERRCONFIG_MCUBOUNDINTST         BIT(24)
++#define       ERRCONFIG_MCUDISACKINTEN        BIT(23)
++#define ERRCONFIG_VPBOUNDINTST_V2     BIT(23)
++#define ERRCONFIG_MCUDISACKINTST      BIT(22)
++#define ERRCONFIG_VPBOUNDINTEN_V2     BIT(22)
++
++#define ERRCONFIG_STATUS_V1_MASK      (ERRCONFIG_VPBOUNDINTST_V1 | \
++                                      ERRCONFIG_MCUACCUMINTST | \
++                                      ERRCONFIG_MCUVALIDINTST | \
++                                      ERRCONFIG_MCUBOUNDINTST | \
++                                      ERRCONFIG_MCUDISACKINTST)
++/* IRQSTATUS */
++#define IRQSTATUS_MCUACCUMINT         BIT(3)
++#define IRQSTATUS_MCVALIDINT          BIT(2)
++#define IRQSTATUS_MCBOUNDSINT         BIT(1)
++#define IRQSTATUS_MCUDISABLEACKINT    BIT(0)
++
++/* IRQENABLE_SET and IRQENABLE_CLEAR */
++#define IRQENABLE_MCUACCUMINT         BIT(3)
++#define IRQENABLE_MCUVALIDINT         BIT(2)
++#define IRQENABLE_MCUBOUNDSINT                BIT(1)
++#define IRQENABLE_MCUDISABLEACKINT    BIT(0)
++
++/* Common Bit values */
++
++#define SRCLKLENGTH_12MHZ_SYSCLK      0x3c
++#define SRCLKLENGTH_13MHZ_SYSCLK      0x41
++#define SRCLKLENGTH_19MHZ_SYSCLK      0x60
++#define SRCLKLENGTH_26MHZ_SYSCLK      0x82
++#define SRCLKLENGTH_38MHZ_SYSCLK      0xC0
++
++/*
++ * 3430 specific values. Maybe these should be passed from board file or
++ * pmic structures.
++ */
++#define OMAP3430_SR_ACCUMDATA         0x1f4
++
++#define OMAP3430_SR1_SENPAVGWEIGHT    0x03
++#define OMAP3430_SR1_SENNAVGWEIGHT    0x03
++
++#define OMAP3430_SR2_SENPAVGWEIGHT    0x01
++#define OMAP3430_SR2_SENNAVGWEIGHT    0x01
++
++#define OMAP3430_SR_ERRWEIGHT         0x04
++#define OMAP3430_SR_ERRMAXLIMIT               0x02
++
++/**
++ * struct omap_sr_pmic_data - Strucutre to be populated by pmic code to pass
++ *                            pmic specific info to smartreflex driver
++ *
++ * @sr_pmic_init:     API to initialize smartreflex on the PMIC side.
++ */
++struct omap_sr_pmic_data {
++      void (*sr_pmic_init) (void);
++};
++
++#ifdef CONFIG_OMAP_SMARTREFLEX
++/*
++ * The smart reflex driver supports CLASS1 CLASS2 and CLASS3 SR.
++ * The smartreflex class driver should pass the class type.
++ * Should be used to populate the class_type field of the
++ * omap_smartreflex_class_data structure.
++ */
++#define SR_CLASS1     0x1
++#define SR_CLASS2     0x2
++#define SR_CLASS3     0x3
++
++/**
++ * struct omap_sr_class_data - Smartreflex class driver info
++ *
++ * @enable:           API to enable a particular class smaartreflex.
++ * @disable:          API to disable a particular class smartreflex.
++ * @configure:                API to configure a particular class smartreflex.
++ * @notify:           API to notify the class driver about an event in SR.
++ *                    Not needed for class3.
++ * @notify_flags:     specify the events to be notified to the class driver
++ * @class_type:               specify which smartreflex class.
++ *                    Can be used by the SR driver to take any class
++ *                    based decisions.
++ */
++struct omap_sr_class_data {
++      int (*enable)(struct voltagedomain *voltdm);
++      int (*disable)(struct voltagedomain *voltdm, int is_volt_reset);
++      int (*configure)(struct voltagedomain *voltdm);
++      int (*notify)(struct voltagedomain *voltdm, u32 status);
++      u8 notify_flags;
++      u8 class_type;
++};
++
++/**
++ * struct omap_sr_nvalue_table        - Smartreflex n-target value info
++ *
++ * @efuse_offs:       The offset of the efuse where n-target values are stored.
++ * @nvalue:   The n-target value.
++ */
++struct omap_sr_nvalue_table {
++      u32 efuse_offs;
++      u32 nvalue;
++};
++
++/**
++ * struct omap_sr_data - Smartreflex platform data.
++ *
++ * @ip_type:          Smartreflex IP type.
++ * @senp_mod:         SENPENABLE value for the sr
++ * @senn_mod:         SENNENABLE value for sr
++ * @nvalue_count:     Number of distinct nvalues in the nvalue table
++ * @enable_on_init:   whether this sr module needs to enabled at
++ *                    boot up or not.
++ * @nvalue_table:     table containing the  efuse offsets and nvalues
++ *                    corresponding to them.
++ * @voltdm:           Pointer to the voltage domain associated with the SR
++ */
++struct omap_sr_data {
++      int                             ip_type;
++      u32                             senp_mod;
++      u32                             senn_mod;
++      int                             nvalue_count;
++      bool                            enable_on_init;
++      struct omap_sr_nvalue_table     *nvalue_table;
++      struct voltagedomain            *voltdm;
++};
++
++/* Smartreflex module enable/disable interface */
++void omap_sr_enable(struct voltagedomain *voltdm);
++void omap_sr_disable(struct voltagedomain *voltdm);
++void omap_sr_disable_reset_volt(struct voltagedomain *voltdm);
++
++/* API to register the pmic specific data with the smartreflex driver. */
++void omap_sr_register_pmic(struct omap_sr_pmic_data *pmic_data);
++
++/* Smartreflex driver hooks to be called from Smartreflex class driver */
++int sr_enable(struct voltagedomain *voltdm, unsigned long volt);
++void sr_disable(struct voltagedomain *voltdm);
++int sr_configure_errgen(struct voltagedomain *voltdm);
++int sr_configure_minmax(struct voltagedomain *voltdm);
++
++/* API to register the smartreflex class driver with the smartreflex driver */
++int sr_register_class(struct omap_sr_class_data *class_data);
++#else
++
++#ifdef CONFIG_AM33XX_SMARTREFLEX
++
++#define SR_CORE                         (0)
++#define SR_MPU                          (1)
++#define SRCLKLENGTH_125MHZ_SYSCLK     (0x78 << 12)
++#define GAIN_MAXLIMIT                   (16)
++#define R_MAXLIMIT                      (256)
++#define MAX_SENSORS                     2
++/* GG: eventually this should be determined at runtime */
++#define AM33XX_OPP_COUNT                4
++
++/**
++ * struct am33xx_sr_opp_data  - Smartreflex data per OPP
++ * @efuse_offs:               The offset of the efuse where n-target values are
++ *                    stored.
++ * @nvalue:             NTarget as stored in EFUSE.
++ * @adj_nvalue:         Adjusted NTarget (adjusted by margin)
++ * @e2v_gain:         Error to voltage gain for changing the percentage
++ *                    error into voltage delta
++ * @err_weight:               Average sensor error weight
++ * @err_minlimit:     Minimum error limit of the sensor
++ * @err_maxlimit:     Maximum error limit of the sensor
++ * @margin:             Voltage margin to apply
++ * @nominal_volt:       Nominal voltage for this OPP
++ * @frequency:          Defined frequency for this OPP (in KHz)
++ */
++struct am33xx_sr_opp_data {
++      u32     efuse_offs;
++        u32     nvalue;
++        u32     adj_nvalue;
++      s32     e2v_gain;
++      u32     err_weight;
++      u32     err_minlimit;
++      u32     err_maxlimit;
++        s32     margin;
++        u32     nominal_volt; /* nominal_volt and frequency may be removed
++                                 once am33xx voltdm layer works */
++        u32     frequency;
++        u32     opp_id;
++};
++
++/**
++ * struct am33xx_sr_sdata     - Smartreflex sensors data
++ * @sr_opp_data:      Pointer to data structure containing per OPP data
++ *                      for this SR module.
++ * @no_of_opps:         Number of OPP's supported for this sensor -
++ *                       determined dynamically when possible.
++ * @default_opp:        Defines the opp to use on startup if OPP is fixed
++ *                       or cannot be determined dynamically.
++ * @senn_mod:         Enable bit for N sensor
++ * @senp_mod:         Enable bit for P sensor
++ */
++struct am33xx_sr_sdata {
++      struct am33xx_sr_opp_data *sr_opp_data;
++        u32     no_of_opps;
++        u32     default_opp;
++      u32     senn_mod;
++      u32     senp_mod;
++};
++
++struct am33xx_sr_sensor {
++        u32                             sr_id;
++      u32                             irq;
++      u32                             irq_status;
++      u32                             senn_en;
++      u32                             senp_en;
++      char                            *name;
++        char                            *reg_name;
++      void __iomem                    *base;
++        int                           init_volt_mv;
++        int                             curr_opp;
++        u32                             no_of_opps;
++        struct delayed_work             work_reenable;
++        struct regulator              *reg;
++        struct am33xx_sr_opp_data       opp_data[AM33XX_OPP_COUNT];
++      struct clk                      *fck;
++        struct voltagedomain          *voltdm;
++        struct omap_volt_data           *volt_data;
++};
++
++struct am33xx_sr {
++      u32                             autocomp_active;
++      u32                             sens_per_vd;
++        u32                             no_of_sens;
++        u32                             no_of_vds;
++      u32                             ip_type;
++        u32                           irq_delay;
++        u32                             disabled_by_user;
++      int                             uvoltage_step_size;
++        char                            *res_name[MAX_SENSORS];
++#ifdef CONFIG_CPU_FREQ
++      struct notifier_block           freq_transition;
++#endif
++      /*struct work_struct            work;*/
++        struct delayed_work             work;
++      struct sr_platform_data         *sr_data;
++      struct am33xx_sr_sensor         sen[MAX_SENSORS];
++      struct platform_device          *pdev;
++};
++
++/**
++ * struct am33xx_sr_platform_data - Smartreflex platform data.
++ * @sr_sdata:         SR per sensor details, contains the efuse off-sets,
++ *                    error to voltage gain factor, minimum error limits
++ * @vd_name:          Name of the voltage domain.
++ * @ip_type:          Smartreflex IP type, class1 or class2 or class3.
++ * @irq_delay:          Amount of time required for changed voltage to settle.
++ * @no_of_vds:                Number of voltage domains to which SR applicable
++ * @no_of_sens:               Number of SR sensors used to monitor the device
++ *                    performance, temp etc...
++ * @vstep_size_uv:    PMIC voltage step size in micro volts
++ * @enable_on_init:   whether this sr module needs to enabled at
++ *                    boot up or not.
++ */
++struct am33xx_sr_platform_data {
++      struct am33xx_sr_sdata  *sr_sdata;
++      char                    *vd_name[2];
++      u32                     ip_type;
++        u32                     irq_delay;
++      u32                     no_of_vds;
++      u32                     no_of_sens;
++      u32                     vstep_size_uv;
++      bool                    enable_on_init;
++};
++
++#endif /*CONFIG_AM33XX_SMARTREFLEX*/
++
++#ifdef CONFIG_TI816X_SMARTREFLEX
++
++#define SRHVT                         0
++#define SRSVT                         1
++
++/* SRClk = 100KHz */
++#define SRCLKLENGTH_125MHZ_SYSCLK     (0x271 << 12)
++
++/**
++ * struct ti816x_sr_sdata     - Smartreflex sensors data
++ * @efuse_offs:               The offset of the efuse where n-target values are
++ *                    stored.
++ * @e2v_gain:         Error to voltage gain for changing the percentage
++ *                    error into voltage delta
++ * @err_weight:               Average sensor error weight
++ * @err_minlimit:     Minimum error limit of the sensor
++ * @err_maxlimit:     Maximum error limit of the sensor
++ * @senn_mod:         Enable bit for N sensor
++ * @senp_mod:         Enable bit for P sensor
++ */
++struct ti816x_sr_sdata {
++      u32     efuse_offs;
++      u32     e2v_gain;
++      u32     err_weight;
++      u32     err_minlimit;
++      u32     err_maxlimit;
++      u32     senn_mod;
++      u32     senp_mod;
++};
++
++/**
++ * struct ti816x_sr_platform_data - Smartreflex platform data.
++ * @sr_sdata:         SR per sensor details, contains the efuse off-sets,
++ *                    error to voltage gain factor, minimum error limits
++ * @vd_name:          Name of the voltage domain.
++ * @ip_type:          Smartreflex IP type, class1 or class2 or class3.
++ * @irq_delay:                Time delay between disable and re-enable the
++ *                    interrupts, in msec
++ * @no_of_vds:                Number of voltage domains to which SR applicable
++ * @no_of_sens:               Number of SR sensors used to monitor the device
++ *                    performance, temp etc...
++ * @vstep_size_uv:    PMIC voltage step size in micro volts
++ * @enable_on_init:   whether this sr module needs to enabled at
++ *                    boot up or not.
++ */
++struct ti816x_sr_platform_data {
++      struct ti816x_sr_sdata  *sr_sdata;
++      char                    *vd_name;
++      u32                     ip_type;
++      u32                     irq_delay;
++      u32                     no_of_vds;
++      u32                     no_of_sens;
++      u32                     vstep_size_uv;
++      bool                    enable_on_init;
++};
++
++#endif /* CONFIG_TI816X_SMARTREFLEX */
++
++static inline void omap_sr_enable(struct voltagedomain *voltdm) {}
++static inline void omap_sr_disable(struct voltagedomain *voltdm) {}
++static inline void omap_sr_disable_reset_volt(
++              struct voltagedomain *voltdm) {}
++static inline void omap_sr_register_pmic(
++              struct omap_sr_pmic_data *pmic_data) {}
++#endif
++#endif
+diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
+index 00706c6..382ce2d 100644
+--- a/drivers/regulator/core.c
++++ b/drivers/regulator/core.c
+@@ -169,6 +169,9 @@ static int regulator_check_consumers(struct regulator_dev *rdev,
+ {
+       struct regulator *regulator;
+
++        if (rdev->ignore_check_consumers)
++                return 0;
++
+       list_for_each_entry(regulator, &rdev->consumer_list, list) {
+               /*
+                * Assume consumers that didn't say anything are OK
+@@ -2688,6 +2691,7 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
+       rdev->reg_data = driver_data;
+       rdev->owner = regulator_desc->owner;
+       rdev->desc = regulator_desc;
++        rdev->ignore_check_consumers = init_data->ignore_check_consumers;
+       INIT_LIST_HEAD(&rdev->consumer_list);
+       INIT_LIST_HEAD(&rdev->list);
+       BLOCKING_INIT_NOTIFIER_HEAD(&rdev->notifier);
+diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h
+index 52c89ae..6176167 100644
+--- a/include/linux/regulator/driver.h
++++ b/include/linux/regulator/driver.h
+@@ -204,7 +204,7 @@ struct regulator_dev {
+       int deferred_disables;
+
+       void *reg_data;         /* regulator_dev data */
+-
++        int ignore_check_consumers;
+ #ifdef CONFIG_DEBUG_FS
+       struct dentry *debugfs;
+ #endif
+diff --git a/include/linux/regulator/machine.h b/include/linux/regulator/machine.h
+index f3f13fd..0de52a3 100644
+--- a/include/linux/regulator/machine.h
++++ b/include/linux/regulator/machine.h
+@@ -169,7 +169,7 @@ struct regulator_consumer_supply {
+  *               be usable.
+  * @num_consumer_supplies: Number of consumer device supplies.
+  * @consumer_supplies: Consumer device supply configuration.
+- *
++ * @ignore_check_consumers: If != 0, regulator_check_consumers() is disabled.
+  * @regulator_init: Callback invoked when the regulator has been registered.
+  * @driver_data: Data passed to regulator_init.
+  */
+@@ -181,6 +181,7 @@ struct regulator_init_data {
+       int num_consumer_supplies;
+       struct regulator_consumer_supply *consumer_supplies;
+
++        int ignore_check_consumers;
+       /* optional regulator machine specific init */
+       int (*regulator_init)(void *driver_data);
+       void *driver_data;      /* core does not touch this */
+--
+1.7.0.4
diff --git a/recipes-kernel/linux/linux-am335x-3.2.0-psp04.06.00.08/0001-mach-omap2-pm33xx-Disable-VT-switch.patch b/recipes-kernel/linux/linux-am335x-3.2.0-psp04.06.00.08/0001-mach-omap2-pm33xx-Disable-VT-switch.patch
new file mode 100644 (file)
index 0000000..66c643e
--- /dev/null
@@ -0,0 +1,71 @@
+From 31ec2850e89414efb30accb9d8b5228257e507b1 Mon Sep 17 00:00:00 2001
+From: Chase Maupin <Chase.Maupin@ti.com>
+Date: Wed, 21 Mar 2012 10:18:03 -0500
+Subject: [PATCH 1/1] mach-omap2: pm33xx: Disable VT switch
+
+* Added a new config option TI_PM_DISABLE_VT_SWITCH which
+  disables the VT console switch which normally occurs during
+  suspend.  This console switch can cause a hange when performed
+  with applications like Matrix running.  The VT switch is
+  considered unnecessary.
+* Modified the am335x_evm_defconfig file to default the
+  TI_PM_DISABLE_VT_SWITCH to "y".
+* Based on a patch for the linux-omap3 kernel by Greg Guyotte
+
+Signed-off-by: Chase Maupin <Chase.Maupin@ti.com>
+---
+ arch/arm/configs/am335x_evm_defconfig |    1 +
+ arch/arm/mach-omap2/Kconfig           |    9 +++++++++
+ arch/arm/mach-omap2/pm33xx.c          |    5 +++++
+ 3 files changed, 15 insertions(+), 0 deletions(-)
+
+diff --git a/arch/arm/configs/am335x_evm_defconfig b/arch/arm/configs/am335x_evm_defconfig
+index 53d1b6a..7a5e7ad 100644
+--- a/arch/arm/configs/am335x_evm_defconfig
++++ b/arch/arm/configs/am335x_evm_defconfig
+@@ -325,6 +325,7 @@ CONFIG_MACH_TI8148EVM=y
+ CONFIG_MACH_AM335XEVM=y
+ CONFIG_MACH_AM335XIAEVM=y
+ # CONFIG_OMAP3_EMU is not set
++CONFIG_TI_PM_DISABLE_VT_SWITCH=y
+ # CONFIG_OMAP3_SDRC_AC_TIMING is not set
+ CONFIG_OMAP3_EDMA=y
+
+diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig
+index e44e942..f13e9dc 100644
+--- a/arch/arm/mach-omap2/Kconfig
++++ b/arch/arm/mach-omap2/Kconfig
+@@ -372,6 +372,15 @@ config OMAP3_EMU
+       help
+         Say Y here to enable debugging hardware of omap3
+
++config TI_PM_DISABLE_VT_SWITCH
++      bool "TI Disable PM Console Switch"
++      depends on ARCH_OMAP3
++      default y
++      help
++        This option disables the default PM VT switch behavior for TI devices.
++        Some platforms hang during suspend due to a failed attempt to
++        perform the VT switch.  The VT switch is unnecessary on many platforms.
++
+ config OMAP3_SDRC_AC_TIMING
+       bool "Enable SDRC AC timing register changes"
+       depends on ARCH_OMAP3
+diff --git a/arch/arm/mach-omap2/pm33xx.c b/arch/arm/mach-omap2/pm33xx.c
+index 70bcb42..019ae46 100644
+--- a/arch/arm/mach-omap2/pm33xx.c
++++ b/arch/arm/mach-omap2/pm33xx.c
+@@ -502,6 +502,11 @@ static int __init am33xx_pm_init(void)
+       pr_info("Power Management for AM33XX family\n");
+
+ #ifdef CONFIG_SUSPEND
++
++#ifdef CONFIG_TI_PM_DISABLE_VT_SWITCH
++      pm_set_vt_switch(0);
++#endif
++
+ /* Read SDRAM_CONFIG register to determine Memory Type */
+       base = am33xx_get_ram_base();
+       reg = readl(base + EMIF4_0_SDRAM_CONFIG);
+--
+1.7.0.4
diff --git a/recipes-kernel/linux/linux-am335x-3.2.0-psp04.06.00.08/0001-musb-update-PIO-mode-help-information-in-Kconfig.patch b/recipes-kernel/linux/linux-am335x-3.2.0-psp04.06.00.08/0001-musb-update-PIO-mode-help-information-in-Kconfig.patch
new file mode 100644 (file)
index 0000000..f7652bd
--- /dev/null
@@ -0,0 +1,45 @@
+From 214f6b2fee005dba5e01b3b434f184adf4386a25 Mon Sep 17 00:00:00 2001
+From: Chase Maupin <Chase.Maupin@ti.com>
+Date: Thu, 2 Feb 2012 15:52:10 -0600
+Subject: [PATCH] musb: update PIO mode help information in Kconfig
+
+* Updated the Kconfig help information for the PIO mode for MUSB
+  to make it more clear to the customer when to select this option
+  and which devices currently have issues with this option.
+* This is in accordance with the findings for CPPI4.1 DMA usage
+  for MUSB
+
+Upstream-Status: Submitted
+    * Submitted to the PSP team using the lpr list
+
+Signed-off-by: Matt Porter <mporter@ti.com>
+Signed-off-by: Chase Maupin <Chase.Maupin@ti.com>
+---
+ drivers/usb/musb/Kconfig |   12 ++++++++----
+ 1 files changed, 8 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig
+index a06335f..3576afe 100644
+--- a/drivers/usb/musb/Kconfig
++++ b/drivers/usb/musb/Kconfig
+@@ -159,10 +159,14 @@ config MUSB_PIO_ONLY
+         All data is copied between memory and FIFO by the CPU.
+         DMA controllers are ignored.
+
+-        Do not choose this unless DMA support for your SOC or board
+-        is unavailable (or unstable).  When DMA is enabled at compile time,
+-        you can still disable it at run time using the "use_dma=n" module
+-        parameter.
++        Select 'y' here if DMA support for your SOC or board
++        is unavailable (or unstable). On CPPI 4.1 DMA based
++        systems (AM335x, AM35x, and AM180x) DMA support is
++        considered unstable and this option should be enabled
++        in production systems so that DMA is disabled, unless DMA
++        has been validated for all use cases. When DMA is enabled at
++        compile time, you can still disable it at run time using the
++        "use_dma=n" module parameter.
+
+ endchoice
+
+--
+1.7.0.4
diff --git a/recipes-kernel/linux/linux-am335x-3.2.0-psp04.06.00.08/0001-omap-serial-add-delay-before-suspending.patch b/recipes-kernel/linux/linux-am335x-3.2.0-psp04.06.00.08/0001-omap-serial-add-delay-before-suspending.patch
new file mode 100644 (file)
index 0000000..7780786
--- /dev/null
@@ -0,0 +1,42 @@
+From 0f62d1f4d4543a315815b8eb15ea9cdad25d16c8 Mon Sep 17 00:00:00 2001
+From: Eyal Reizer <eyalr@ti.com>
+Date: Wed, 27 Jun 2012 16:08:53 +0300
+Subject: [PATCH] omap-serial: add delay before suspending
+
+In case suspending during Bluetooth traffic, after resume the bluetooth is
+stuck.
+It was identified that suspend is happening before the UART buffer was
+fully drained which caused this hang after resume.
+The folliwng delay is a temporary workaround until the issue is resolved
+properly.
+
+Upstream Status: Pending
+
+Signed-off-by: Eyal Reizer <eyalr@ti.com>
+---
+ drivers/tty/serial/omap-serial.c |   10 ++++++++++
+ 1 files changed, 10 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
+index ca24ab3..108ea2b 100755
+--- a/drivers/tty/serial/omap-serial.c
++++ b/drivers/tty/serial/omap-serial.c
+@@ -1166,6 +1166,16 @@ static int serial_omap_suspend(struct device *dev)
+       struct uart_omap_port *up = dev_get_drvdata(dev);
+
+       if (up) {
++                /*
++                  In case suspending during Bluetooth traffic, after resume
++                  the bluetooth is stuck.
++                  It was identified that suspend is happening before the
++                  UART buffer was fully drained which caused this hang after
++                  resume. The following delay is a temporary workaround until
++                  the issue is resolved properly.
++                */
++                msleep(10);
++
+               uart_suspend_port(&serial_omap_reg, &up->port);
+               flush_work_sync(&up->qos_work);
+       }
+--
+1.7.0.4
diff --git a/recipes-kernel/linux/linux-am335x-3.2.0-psp04.06.00.08/0002-AM335x-OCF-Driver-for-Linux-3.patch b/recipes-kernel/linux/linux-am335x-3.2.0-psp04.06.00.08/0002-AM335x-OCF-Driver-for-Linux-3.patch
new file mode 100644 (file)
index 0000000..916b190
--- /dev/null
@@ -0,0 +1,7228 @@
+From a97aac248717d62bdbf322c1d6d422ddfde87de0 Mon Sep 17 00:00:00 2001
+From: Greg Turner <gregturner@ti.com>
+Date: Thu, 3 May 2012 10:33:13 -0500
+Subject: [PATCH 2/2] AM335x OCF Driver for Linux 3
+
+---
+ crypto/Kconfig               |    3 +
+ crypto/Makefile              |    2 +
+ crypto/ocf/Config.in         |   20 +
+ crypto/ocf/Kconfig           |   48 ++
+ crypto/ocf/Makefile          |  138 ++++
+ crypto/ocf/criov.c           |  215 +++++
+ crypto/ocf/crypto.c          | 1766 ++++++++++++++++++++++++++++++++++++++++++
+ crypto/ocf/cryptodev.c       | 1069 +++++++++++++++++++++++++
+ crypto/ocf/cryptodev.h       |  480 ++++++++++++
+ crypto/ocf/cryptosoft.c      | 1322 +++++++++++++++++++++++++++++++
+ crypto/ocf/ocf-bench.c       |  514 ++++++++++++
+ crypto/ocf/ocf-compat.h      |  372 +++++++++
+ crypto/ocf/ocfnull/Makefile  |   12 +
+ crypto/ocf/ocfnull/ocfnull.c |  204 +++++
+ crypto/ocf/random.c          |  317 ++++++++
+ crypto/ocf/rndtest.c         |  300 +++++++
+ crypto/ocf/rndtest.h         |   54 ++
+ crypto/ocf/uio.h             |   54 ++
+ drivers/char/random.c        |   67 ++
+ fs/fcntl.c                   |    1 +
+ include/linux/miscdevice.h   |    1 +
+ include/linux/random.h       |   28 +
+ kernel/pid.c                 |    1 +
+ 23 files changed, 6988 insertions(+), 0 deletions(-)
+ create mode 100755 crypto/ocf/Config.in
+ create mode 100755 crypto/ocf/Kconfig
+ create mode 100755 crypto/ocf/Makefile
+ create mode 100644 crypto/ocf/criov.c
+ create mode 100644 crypto/ocf/crypto.c
+ create mode 100644 crypto/ocf/cryptodev.c
+ create mode 100644 crypto/ocf/cryptodev.h
+ create mode 100644 crypto/ocf/cryptosoft.c
+ create mode 100644 crypto/ocf/ocf-bench.c
+ create mode 100644 crypto/ocf/ocf-compat.h
+ create mode 100644 crypto/ocf/ocfnull/Makefile
+ create mode 100644 crypto/ocf/ocfnull/ocfnull.c
+ create mode 100644 crypto/ocf/random.c
+ create mode 100644 crypto/ocf/rndtest.c
+ create mode 100644 crypto/ocf/rndtest.h
+ create mode 100644 crypto/ocf/uio.h
+
+diff --git a/crypto/Kconfig b/crypto/Kconfig
+index 527a857..8871f10 100644
+--- a/crypto/Kconfig
++++ b/crypto/Kconfig
+@@ -923,3 +923,6 @@ config CRYPTO_USER_API_SKCIPHER
+ source "drivers/crypto/Kconfig"
+
+ endif # if CRYPTO
++
++source "crypto/ocf/Kconfig"
++
+diff --git a/crypto/Makefile b/crypto/Makefile
+index 9e6eee2..3cde9f8 100644
+--- a/crypto/Makefile
++++ b/crypto/Makefile
+@@ -91,6 +91,8 @@ obj-$(CONFIG_CRYPTO_USER_API) += af_alg.o
+ obj-$(CONFIG_CRYPTO_USER_API_HASH) += algif_hash.o
+ obj-$(CONFIG_CRYPTO_USER_API_SKCIPHER) += algif_skcipher.o
+
++obj-$(CONFIG_OCF_OCF) += ocf/
++
+ #
+ # generic algorithms and the async_tx api
+ #
+diff --git a/crypto/ocf/Config.in b/crypto/ocf/Config.in
+new file mode 100755
+index 0000000..423d11f
+--- /dev/null
++++ b/crypto/ocf/Config.in
+@@ -0,0 +1,20 @@
++#############################################################################
++
++mainmenu_option next_comment
++comment 'OCF Configuration'
++tristate 'OCF (Open Cryptograhic Framework)' CONFIG_OCF_OCF
++dep_mbool '  enable fips RNG checks (fips check on RNG data before use)' \
++                              CONFIG_OCF_FIPS $CONFIG_OCF_OCF
++dep_mbool '  enable harvesting entropy for /dev/random' \
++                              CONFIG_OCF_RANDOMHARVEST $CONFIG_OCF_OCF
++dep_tristate '  cryptodev (user space support)' \
++                              CONFIG_OCF_CRYPTODEV $CONFIG_OCF_OCF
++dep_tristate '  cryptosoft (software crypto engine)' \
++                              CONFIG_OCF_CRYPTOSOFT $CONFIG_OCF_OCF
++dep_tristate '  ocfnull (does no crypto)' \
++                              CONFIG_OCF_OCFNULL $CONFIG_OCF_OCF
++dep_tristate '  ocf-bench (HW crypto in-kernel benchmark)' \
++                              CONFIG_OCF_BENCH $CONFIG_OCF_OCF
++endmenu
++
++#############################################################################
+diff --git a/crypto/ocf/Kconfig b/crypto/ocf/Kconfig
+new file mode 100755
+index 0000000..44459f4
+--- /dev/null
++++ b/crypto/ocf/Kconfig
+@@ -0,0 +1,48 @@
++menu "OCF Configuration"
++
++config OCF_OCF
++      tristate "OCF (Open Cryptograhic Framework)"
++      help
++        A linux port of the OpenBSD/FreeBSD crypto framework.
++
++config OCF_RANDOMHARVEST
++      bool "crypto random --- harvest entropy for /dev/random"
++      depends on OCF_OCF
++      help
++        Includes code to harvest random numbers from devices that support it.
++
++config OCF_FIPS
++      bool "enable fips RNG checks"
++      depends on OCF_OCF && OCF_RANDOMHARVEST
++      help
++        Run all RNG provided data through a fips check before
++        adding it /dev/random's entropy pool.
++
++config OCF_CRYPTODEV
++      tristate "cryptodev (user space support)"
++      depends on OCF_OCF
++      help
++        The user space API to access crypto hardware.
++
++config OCF_CRYPTOSOFT
++      tristate "cryptosoft (software crypto engine)"
++      depends on OCF_OCF
++      help
++        A software driver for the OCF framework that uses
++        the kernel CryptoAPI.
++
++config OCF_OCFNULL
++      tristate "ocfnull (fake crypto engine)"
++      depends on OCF_OCF
++      help
++        OCF driver for measuring ipsec overheads (does no crypto)
++
++config OCF_BENCH
++      tristate "ocf-bench (HW crypto in-kernel benchmark)"
++      depends on OCF_OCF
++      help
++        A very simple encryption test for the in-kernel interface
++        of OCF.  Also includes code to benchmark the IXP Access library
++        for comparison.
++
++endmenu
+diff --git a/crypto/ocf/Makefile b/crypto/ocf/Makefile
+new file mode 100755
+index 0000000..29ac280
+--- /dev/null
++++ b/crypto/ocf/Makefile
+@@ -0,0 +1,138 @@
++# for SGlinux builds
++-include $(ROOTDIR)/modules/.config
++
++OCF_OBJS = crypto.o criov.o
++
++ifdef CONFIG_OCF_RANDOMHARVEST
++      OCF_OBJS += random.o
++endif
++
++ifdef CONFIG_OCF_FIPS
++      OCF_OBJS += rndtest.o
++endif
++
++# Add in autoconf.h to get #defines for CONFIG_xxx
++AUTOCONF_H=$(ROOTDIR)/modules/autoconf.h
++ifeq ($(AUTOCONF_H), $(wildcard $(AUTOCONF_H)))
++      EXTRA_CFLAGS += -include $(AUTOCONF_H)
++      export EXTRA_CFLAGS
++endif
++
++ifndef obj
++      obj ?= .
++      _obj = subdir
++      mod-subdirs := safe hifn ixp4xx talitos ocfnull
++      export-objs += crypto.o criov.o random.o
++      list-multi += ocf.o
++      _slash :=
++else
++      _obj = obj
++      _slash := /
++endif
++
++EXTRA_CFLAGS += -I$(obj)/.
++
++obj-$(CONFIG_OCF_OCF)         += ocf.o
++obj-$(CONFIG_OCF_CRYPTODEV)   += cryptodev.o
++obj-$(CONFIG_OCF_CRYPTOSOFT)  += cryptosoft.o
++obj-$(CONFIG_OCF_BENCH)       += ocf-bench.o
++
++$(_obj)-$(CONFIG_OCF_OCFNULL) += ocfnull$(_slash)
++
++ocf-objs := $(OCF_OBJS)
++
++dummy:
++      @echo "Please consult the README for how to build OCF."
++      @echo "If you can't wait then the following should do it:"
++      @echo ""
++      @echo "    make ocf_modules"
++      @echo "    sudo make ocf_install"
++      @echo ""
++      @exit 1
++
++$(list-multi) dummy1: $(ocf-objs)
++      $(LD) -r -o $@ $(ocf-objs)
++
++.PHONY:
++clean:
++      rm -f *.o *.ko .*.o.flags .*.ko.cmd .*.o.cmd .*.mod.o.cmd *.mod.c
++      rm -f */*.o */*.ko */.*.o.cmd */.*.ko.cmd */.*.mod.o.cmd */*.mod.c */.*.o.flags
++      rm -f */modules.order */modules.builtin modules.order modules.builtin
++
++ifdef TOPDIR
++-include $(TOPDIR)/Rules.make
++endif
++
++#
++# targets to build easily on the current machine
++#
++
++ocf_make:
++      make -C /lib/modules/$(shell uname -r)/build M=`pwd` $(OCF_TARGET) CONFIG_OCF_OCF=m
++      make -C /lib/modules/$(shell uname -r)/build M=`pwd` $(OCF_TARGET) CONFIG_OCF_OCF=m CONFIG_OCF_CRYPTOSOFT=m
++      -make -C /lib/modules/$(shell uname -r)/build M=`pwd` $(OCF_TARGET) CONFIG_OCF_OCF=m CONFIG_OCF_BENCH=m
++      -make -C /lib/modules/$(shell uname -r)/build M=`pwd` $(OCF_TARGET) CONFIG_OCF_OCF=m CONFIG_OCF_OCFNULL=m
++      -make -C /lib/modules/$(shell uname -r)/build M=`pwd` $(OCF_TARGET) CONFIG_OCF_OCF=m CONFIG_OCF_HIFN=m
++
++ocf_modules:
++      $(MAKE) ocf_make OCF_TARGET=modules
++
++ocf_install:
++      $(MAKE) ocf_make OCF_TARGET="modules modules_install"
++      depmod
++      mkdir -p /usr/include/crypto
++      cp cryptodev.h /usr/include/crypto/.
++
++#
++# generate full kernel patches for 2.4 and 2.6 kernels to make patching
++# your kernel easier
++#
++
++.PHONY: patch
++patch:
++      patchbase=.; \
++              [ -d $$patchbase/patches ] || patchbase=..; \
++              patch=ocf-linux-base.patch; \
++              patch24=ocf-linux-24.patch; \
++              patch26=ocf-linux-26.patch; \
++              patch3=ocf-linux-3.patch; \
++              ( \
++                      find . -name Makefile; \
++                      find . -name Config.in; \
++                      find . -name Kconfig; \
++                      find . -name README; \
++                      find . -name '*.[ch]' | grep -v '.mod.c'; \
++              ) | while read t; do \
++                      diff -Nau /dev/null $$t | sed 's?^+++ \./?+++ linux/crypto/ocf/?'; \
++              done > $$patch; \
++              cat $$patchbase/patches/linux-2.4.35-ocf.patch $$patch > $$patch24; \
++              cat $$patchbase/patches/linux-2.6.38-ocf.patch $$patch > $$patch26; \
++              cat $$patchbase/patches/linux-3.2.1-ocf.patch $$patch > $$patch3; \
++
++
++#
++# this target probably does nothing for anyone but me - davidm
++#
++
++.PHONY: release
++release:
++      REL=`date +%Y%m%d`; RELDIR=/tmp/ocf-linux-$$REL; \
++              CURDIR=`pwd`; \
++              rm -rf /tmp/ocf-linux-$$REL*; \
++              mkdir -p $$RELDIR/ocf; \
++              mkdir -p $$RELDIR/patches; \
++              mkdir -p $$RELDIR/crypto-tools; \
++              cp README* $$RELDIR/.; \
++              cp patches/[!C]* $$RELDIR/patches/.; \
++              cp tools/[!C]* $$RELDIR/crypto-tools/.; \
++              cp -r [!C]* Config.in $$RELDIR/ocf/.; \
++              rm -rf $$RELDIR/ocf/patches $$RELDIR/ocf/tools; \
++              rm -f $$RELDIR/ocf/README*; \
++              cp $$CURDIR/../../user/crypto-tools/[!C]* $$RELDIR/crypto-tools/.; \
++              make -C $$RELDIR/crypto-tools clean; \
++              make -C $$RELDIR/ocf clean; \
++              find $$RELDIR/ocf -name CVS | xargs rm -rf; \
++              cd $$RELDIR/..; \
++              tar cvf ocf-linux-$$REL.tar ocf-linux-$$REL; \
++              gzip -9 ocf-linux-$$REL.tar
++
+diff --git a/crypto/ocf/criov.c b/crypto/ocf/criov.c
+new file mode 100644
+index 0000000..a8c1a8c
+--- /dev/null
++++ b/crypto/ocf/criov.c
+@@ -0,0 +1,215 @@
++/*      $OpenBSD: criov.c,v 1.9 2002/01/29 15:48:29 jason Exp $       */
++
++/*
++ * Linux port done by David McCullough <david_mccullough@mcafee.com>
++ * Copyright (C) 2006-2010 David McCullough
++ * Copyright (C) 2004-2005 Intel Corporation.
++ * The license and original author are listed below.
++ *
++ * Copyright (c) 1999 Theo de Raadt
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ *
++ * 1. Redistributions of source code must retain the above copyright
++ *   notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *   notice, this list of conditions and the following disclaimer in the
++ *   documentation and/or other materials provided with the distribution.
++ * 3. The name of the author may not be used to endorse or promote products
++ *   derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++__FBSDID("$FreeBSD: src/sys/opencrypto/criov.c,v 1.5 2006/06/04 22:15:13 pjd Exp $");
++ */
++
++#include <linux/version.h>
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) && !defined(AUTOCONF_INCLUDED)
++#include <linux/config.h>
++#endif
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <linux/uio.h>
++#include <linux/skbuff.h>
++#include <linux/kernel.h>
++#include <linux/mm.h>
++#include <asm/io.h>
++
++#include <uio.h>
++#include <cryptodev.h>
++
++/*
++ * This macro is only for avoiding code duplication, as we need to skip
++ * given number of bytes in the same way in three functions below.
++ */
++#define       CUIO_SKIP()     do {                                            \
++      KASSERT(off >= 0, ("%s: off %d < 0", __func__, off));           \
++      KASSERT(len >= 0, ("%s: len %d < 0", __func__, len));           \
++      while (off > 0) {                                               \
++              KASSERT(iol >= 0, ("%s: empty in skip", __func__));     \
++              if (off < iov->iov_len)                                 \
++                      break;                                          \
++              off -= iov->iov_len;                                    \
++              iol--;                                                  \
++              iov++;                                                  \
++      }                                                               \
++} while (0)
++
++void
++cuio_copydata(struct uio* uio, int off, int len, caddr_t cp)
++{
++      struct iovec *iov = uio->uio_iov;
++      int iol = uio->uio_iovcnt;
++      unsigned count;
++
++      CUIO_SKIP();
++      while (len > 0) {
++              KASSERT(iol >= 0, ("%s: empty", __func__));
++              count = min((int)(iov->iov_len - off), len);
++              memcpy(cp, ((caddr_t)iov->iov_base) + off, count);
++              len -= count;
++              cp += count;
++              off = 0;
++              iol--;
++              iov++;
++      }
++}
++
++void
++cuio_copyback(struct uio* uio, int off, int len, caddr_t cp)
++{
++      struct iovec *iov = uio->uio_iov;
++      int iol = uio->uio_iovcnt;
++      unsigned count;
++
++      CUIO_SKIP();
++      while (len > 0) {
++              KASSERT(iol >= 0, ("%s: empty", __func__));
++              count = min((int)(iov->iov_len - off), len);
++              memcpy(((caddr_t)iov->iov_base) + off, cp, count);
++              len -= count;
++              cp += count;
++              off = 0;
++              iol--;
++              iov++;
++      }
++}
++
++/*
++ * Return a pointer to iov/offset of location in iovec list.
++ */
++struct iovec *
++cuio_getptr(struct uio *uio, int loc, int *off)
++{
++      struct iovec *iov = uio->uio_iov;
++      int iol = uio->uio_iovcnt;
++
++      while (loc >= 0) {
++              /* Normal end of search */
++              if (loc < iov->iov_len) {
++                      *off = loc;
++                      return (iov);
++              }
++
++              loc -= iov->iov_len;
++              if (iol == 0) {
++                      if (loc == 0) {
++                              /* Point at the end of valid data */
++                              *off = iov->iov_len;
++                              return (iov);
++                      } else
++                              return (NULL);
++              } else {
++                      iov++, iol--;
++              }
++      }
++
++      return (NULL);
++}
++
++EXPORT_SYMBOL(cuio_copyback);
++EXPORT_SYMBOL(cuio_copydata);
++EXPORT_SYMBOL(cuio_getptr);
++
++static void
++skb_copy_bits_back(struct sk_buff *skb, int offset, caddr_t cp, int len)
++{
++      int i;
++      if (offset < skb_headlen(skb)) {
++              memcpy(skb->data + offset, cp, min_t(int, skb_headlen(skb), len));
++              len -= skb_headlen(skb);
++              cp += skb_headlen(skb);
++      }
++      offset -= skb_headlen(skb);
++      for (i = 0; len > 0 && i < skb_shinfo(skb)->nr_frags; i++) {
++              if (offset < skb_shinfo(skb)->frags[i].size) {
++                      memcpy(page_address(skb_frag_page(&skb_shinfo(skb)->frags[i])) +
++                                      skb_shinfo(skb)->frags[i].page_offset,
++                                      cp, min_t(int, skb_shinfo(skb)->frags[i].size, len));
++                      len -= skb_shinfo(skb)->frags[i].size;
++                      cp += skb_shinfo(skb)->frags[i].size;
++              }
++              offset -= skb_shinfo(skb)->frags[i].size;
++      }
++}
++
++void
++crypto_copyback(int flags, caddr_t buf, int off, int size, caddr_t in)
++{
++
++      if ((flags & CRYPTO_F_SKBUF) != 0)
++              skb_copy_bits_back((struct sk_buff *)buf, off, in, size);
++      else if ((flags & CRYPTO_F_IOV) != 0)
++              cuio_copyback((struct uio *)buf, off, size, in);
++      else
++              bcopy(in, buf + off, size);
++}
++
++void
++crypto_copydata(int flags, caddr_t buf, int off, int size, caddr_t out)
++{
++
++      if ((flags & CRYPTO_F_SKBUF) != 0)
++              skb_copy_bits((struct sk_buff *)buf, off, out, size);
++      else if ((flags & CRYPTO_F_IOV) != 0)
++              cuio_copydata((struct uio *)buf, off, size, out);
++      else
++              bcopy(buf + off, out, size);
++}
++
++int
++crypto_apply(int flags, caddr_t buf, int off, int len,
++    int (*f)(void *, void *, u_int), void *arg)
++{
++#if 0
++      int error;
++
++      if ((flags & CRYPTO_F_SKBUF) != 0)
++              error = XXXXXX((struct mbuf *)buf, off, len, f, arg);
++      else if ((flags & CRYPTO_F_IOV) != 0)
++              error = cuio_apply((struct uio *)buf, off, len, f, arg);
++      else
++              error = (*f)(arg, buf + off, len);
++      return (error);
++#else
++      KASSERT(0, ("crypto_apply not implemented!\n"));
++#endif
++      return 0;
++}
++
++EXPORT_SYMBOL(crypto_copyback);
++EXPORT_SYMBOL(crypto_copydata);
++EXPORT_SYMBOL(crypto_apply);
++
+diff --git a/crypto/ocf/crypto.c b/crypto/ocf/crypto.c
+new file mode 100644
+index 0000000..f48210d
+--- /dev/null
++++ b/crypto/ocf/crypto.c
+@@ -0,0 +1,1766 @@
++/*-
++ * Linux port done by David McCullough <david_mccullough@mcafee.com>
++ * Copyright (C) 2006-2010 David McCullough
++ * Copyright (C) 2004-2005 Intel Corporation.
++ * The license and original author are listed below.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * Copyright (c) 2002-2006 Sam Leffler.  All rights reserved.
++ *
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#if 0
++#include <sys/cdefs.h>
++__FBSDID("$FreeBSD: src/sys/opencrypto/crypto.c,v 1.27 2007/03/21 03:42:51 sam Exp $");
++#endif
++
++/*
++ * Cryptographic Subsystem.
++ *
++ * This code is derived from the Openbsd Cryptographic Framework (OCF)
++ * that has the copyright shown below.  Very little of the original
++ * code remains.
++ */
++/*-
++ * The author of this code is Angelos D. Keromytis (angelos@cis.upenn.edu)
++ *
++ * This code was written by Angelos D. Keromytis in Athens, Greece, in
++ * February 2000. Network Security Technologies Inc. (NSTI) kindly
++ * supported the development of this code.
++ *
++ * Copyright (c) 2000, 2001 Angelos D. Keromytis
++ *
++ * Permission to use, copy, and modify this software with or without fee
++ * is hereby granted, provided that this entire notice is included in
++ * all source code copies of any software which is or includes a copy or
++ * modification of this software.
++ *
++ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
++ * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
++ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
++ * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
++ * PURPOSE.
++ *
++__FBSDID("$FreeBSD: src/sys/opencrypto/crypto.c,v 1.16 2005/01/07 02:29:16 imp Exp $");
++ */
++
++
++#include <linux/version.h>
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) && !defined(AUTOCONF_INCLUDED)
++#include <linux/config.h>
++#endif
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/list.h>
++#include <linux/slab.h>
++#include <linux/wait.h>
++#include <linux/sched.h>
++#include <linux/spinlock.h>
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,4)
++#include <linux/kthread.h>
++#endif
++#include <cryptodev.h>
++
++/*
++ * keep track of whether or not we have been initialised, a big
++ * issue if we are linked into the kernel and a driver gets started before
++ * us
++ */
++static int crypto_initted = 0;
++
++/*
++ * Crypto drivers register themselves by allocating a slot in the
++ * crypto_drivers table with crypto_get_driverid() and then registering
++ * each algorithm they support with crypto_register() and crypto_kregister().
++ */
++
++/*
++ * lock on driver table
++ * we track its state as spin_is_locked does not do anything on non-SMP boxes
++ */
++static spinlock_t     crypto_drivers_lock;
++static int                    crypto_drivers_locked;          /* for non-SMP boxes */
++
++#define       CRYPTO_DRIVER_LOCK() \
++                      ({ \
++                              spin_lock_irqsave(&crypto_drivers_lock, d_flags); \
++                              crypto_drivers_locked = 1; \
++                              dprintk("%s,%d: DRIVER_LOCK()\n", __FILE__, __LINE__); \
++                       })
++#define       CRYPTO_DRIVER_UNLOCK() \
++                      ({ \
++                              dprintk("%s,%d: DRIVER_UNLOCK()\n", __FILE__, __LINE__); \
++                              crypto_drivers_locked = 0; \
++                              spin_unlock_irqrestore(&crypto_drivers_lock, d_flags); \
++                       })
++#define       CRYPTO_DRIVER_ASSERT() \
++                      ({ \
++                              if (!crypto_drivers_locked) { \
++                                      dprintk("%s,%d: DRIVER_ASSERT!\n", __FILE__, __LINE__); \
++                              } \
++                       })
++
++/*
++ * Crypto device/driver capabilities structure.
++ *
++ * Synchronization:
++ * (d) - protected by CRYPTO_DRIVER_LOCK()
++ * (q) - protected by CRYPTO_Q_LOCK()
++ * Not tagged fields are read-only.
++ */
++struct cryptocap {
++      device_t        cc_dev;                 /* (d) device/driver */
++      u_int32_t       cc_sessions;            /* (d) # of sessions */
++      u_int32_t       cc_koperations;         /* (d) # os asym operations */
++      /*
++       * Largest possible operator length (in bits) for each type of
++       * encryption algorithm. XXX not used
++       */
++      u_int16_t       cc_max_op_len[CRYPTO_ALGORITHM_MAX + 1];
++      u_int8_t        cc_alg[CRYPTO_ALGORITHM_MAX + 1];
++      u_int8_t        cc_kalg[CRK_ALGORITHM_MAX + 1];
++
++      int             cc_flags;               /* (d) flags */
++#define CRYPTOCAP_F_CLEANUP   0x80000000      /* needs resource cleanup */
++      int             cc_qblocked;            /* (q) symmetric q blocked */
++      int             cc_kqblocked;           /* (q) asymmetric q blocked */
++
++      int             cc_unqblocked;          /* (q) symmetric q blocked */
++      int             cc_unkqblocked;         /* (q) asymmetric q blocked */
++};
++static struct cryptocap *crypto_drivers = NULL;
++static int crypto_drivers_num = 0;
++
++/*
++ * There are two queues for crypto requests; one for symmetric (e.g.
++ * cipher) operations and one for asymmetric (e.g. MOD)operations.
++ * A single mutex is used to lock access to both queues.  We could
++ * have one per-queue but having one simplifies handling of block/unblock
++ * operations.
++ */
++static LIST_HEAD(crp_q);              /* crypto request queue */
++static LIST_HEAD(crp_kq);             /* asym request queue */
++
++static spinlock_t crypto_q_lock;
++
++int crypto_all_qblocked = 0;  /* protect with Q_LOCK */
++module_param(crypto_all_qblocked, int, 0444);
++MODULE_PARM_DESC(crypto_all_qblocked, "Are all crypto queues blocked");
++
++int crypto_all_kqblocked = 0; /* protect with Q_LOCK */
++module_param(crypto_all_kqblocked, int, 0444);
++MODULE_PARM_DESC(crypto_all_kqblocked, "Are all asym crypto queues blocked");
++
++#define       CRYPTO_Q_LOCK() \
++                      ({ \
++                              spin_lock_irqsave(&crypto_q_lock, q_flags); \
++                              dprintk("%s,%d: Q_LOCK()\n", __FILE__, __LINE__); \
++                       })
++#define       CRYPTO_Q_UNLOCK() \
++                      ({ \
++                              dprintk("%s,%d: Q_UNLOCK()\n", __FILE__, __LINE__); \
++                              spin_unlock_irqrestore(&crypto_q_lock, q_flags); \
++                       })
++
++/*
++ * There are two queues for processing completed crypto requests; one
++ * for the symmetric and one for the asymmetric ops.  We only need one
++ * but have two to avoid type futzing (cryptop vs. cryptkop).  A single
++ * mutex is used to lock access to both queues.  Note that this lock
++ * must be separate from the lock on request queues to insure driver
++ * callbacks don't generate lock order reversals.
++ */
++static LIST_HEAD(crp_ret_q);          /* callback queues */
++static LIST_HEAD(crp_ret_kq);
++
++static spinlock_t crypto_ret_q_lock;
++#define       CRYPTO_RETQ_LOCK() \
++                      ({ \
++                              spin_lock_irqsave(&crypto_ret_q_lock, r_flags); \
++                              dprintk("%s,%d: RETQ_LOCK\n", __FILE__, __LINE__); \
++                       })
++#define       CRYPTO_RETQ_UNLOCK() \
++                      ({ \
++                              dprintk("%s,%d: RETQ_UNLOCK\n", __FILE__, __LINE__); \
++                              spin_unlock_irqrestore(&crypto_ret_q_lock, r_flags); \
++                       })
++#define       CRYPTO_RETQ_EMPTY()     (list_empty(&crp_ret_q) && list_empty(&crp_ret_kq))
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
++static kmem_cache_t *cryptop_zone;
++static kmem_cache_t *cryptodesc_zone;
++#else
++static struct kmem_cache *cryptop_zone;
++static struct kmem_cache *cryptodesc_zone;
++#endif
++
++#define debug crypto_debug
++int crypto_debug = 0;
++module_param(crypto_debug, int, 0644);
++MODULE_PARM_DESC(crypto_debug, "Enable debug");
++EXPORT_SYMBOL(crypto_debug);
++
++/*
++ * Maximum number of outstanding crypto requests before we start
++ * failing requests.  We need this to prevent DOS when too many
++ * requests are arriving for us to keep up.  Otherwise we will
++ * run the system out of memory.  Since crypto is slow,  we are
++ * usually the bottleneck that needs to say, enough is enough.
++ *
++ * We cannot print errors when this condition occurs,  we are already too
++ * slow,  printing anything will just kill us
++ */
++
++static int crypto_q_cnt = 0;
++module_param(crypto_q_cnt, int, 0444);
++MODULE_PARM_DESC(crypto_q_cnt,
++              "Current number of outstanding crypto requests");
++
++static int crypto_q_max = 1000;
++module_param(crypto_q_max, int, 0644);
++MODULE_PARM_DESC(crypto_q_max,
++              "Maximum number of outstanding crypto requests");
++
++#define bootverbose crypto_verbose
++static int crypto_verbose = 0;
++module_param(crypto_verbose, int, 0644);
++MODULE_PARM_DESC(crypto_verbose,
++              "Enable verbose crypto startup");
++
++int   crypto_usercrypto = 1;  /* userland may do crypto reqs */
++module_param(crypto_usercrypto, int, 0644);
++MODULE_PARM_DESC(crypto_usercrypto,
++         "Enable/disable user-mode access to crypto support");
++
++int   crypto_userasymcrypto = 1;      /* userland may do asym crypto reqs */
++module_param(crypto_userasymcrypto, int, 0644);
++MODULE_PARM_DESC(crypto_userasymcrypto,
++         "Enable/disable user-mode access to asymmetric crypto support");
++
++int   crypto_devallowsoft = 0;        /* only use hardware crypto */
++module_param(crypto_devallowsoft, int, 0644);
++MODULE_PARM_DESC(crypto_devallowsoft,
++         "Enable/disable use of software crypto support");
++
++/*
++ * This parameter controls the maximum number of crypto operations to
++ * do consecutively in the crypto kernel thread before scheduling to allow
++ * other processes to run. Without it, it is possible to get into a
++ * situation where the crypto thread never allows any other processes to run.
++ * Default to 1000 which should be less than one second.
++ */
++static int crypto_max_loopcount = 1000;
++module_param(crypto_max_loopcount, int, 0644);
++MODULE_PARM_DESC(crypto_max_loopcount,
++         "Maximum number of crypto ops to do before yielding to other processes");
++
++#ifndef CONFIG_NR_CPUS
++#define CONFIG_NR_CPUS 1
++#endif
++
++static struct task_struct *cryptoproc[CONFIG_NR_CPUS];
++static struct task_struct *cryptoretproc[CONFIG_NR_CPUS];
++static DECLARE_WAIT_QUEUE_HEAD(cryptoproc_wait);
++static DECLARE_WAIT_QUEUE_HEAD(cryptoretproc_wait);
++
++static        int crypto_proc(void *arg);
++static        int crypto_ret_proc(void *arg);
++static        int crypto_invoke(struct cryptocap *cap, struct cryptop *crp, int hint);
++static        int crypto_kinvoke(struct cryptkop *krp, int flags);
++static        void crypto_exit(void);
++static  int crypto_init(void);
++
++static        struct cryptostats cryptostats;
++
++static struct cryptocap *
++crypto_checkdriver(u_int32_t hid)
++{
++      if (crypto_drivers == NULL)
++              return NULL;
++      return (hid >= crypto_drivers_num ? NULL : &crypto_drivers[hid]);
++}
++
++/*
++ * Compare a driver's list of supported algorithms against another
++ * list; return non-zero if all algorithms are supported.
++ */
++static int
++driver_suitable(const struct cryptocap *cap, const struct cryptoini *cri)
++{
++      const struct cryptoini *cr;
++
++      /* See if all the algorithms are supported. */
++      for (cr = cri; cr; cr = cr->cri_next)
++              if (cap->cc_alg[cr->cri_alg] == 0)
++                      return 0;
++      return 1;
++}
++
++
++/*
++ * Select a driver for a new session that supports the specified
++ * algorithms and, optionally, is constrained according to the flags.
++ * The algorithm we use here is pretty stupid; just use the
++ * first driver that supports all the algorithms we need. If there
++ * are multiple drivers we choose the driver with the fewest active
++ * sessions.  We prefer hardware-backed drivers to software ones.
++ *
++ * XXX We need more smarts here (in real life too, but that's
++ * XXX another story altogether).
++ */
++static struct cryptocap *
++crypto_select_driver(const struct cryptoini *cri, int flags)
++{
++      struct cryptocap *cap, *best;
++      int match, hid;
++
++      CRYPTO_DRIVER_ASSERT();
++
++      /*
++       * Look first for hardware crypto devices if permitted.
++       */
++      if (flags & CRYPTOCAP_F_HARDWARE)
++              match = CRYPTOCAP_F_HARDWARE;
++      else
++              match = CRYPTOCAP_F_SOFTWARE;
++      best = NULL;
++again:
++      for (hid = 0; hid < crypto_drivers_num; hid++) {
++              cap = &crypto_drivers[hid];
++              /*
++               * If it's not initialized, is in the process of
++               * going away, or is not appropriate (hardware
++               * or software based on match), then skip.
++               */
++              if (cap->cc_dev == NULL ||
++                  (cap->cc_flags & CRYPTOCAP_F_CLEANUP) ||
++                  (cap->cc_flags & match) == 0)
++                      continue;
++
++              /* verify all the algorithms are supported. */
++              if (driver_suitable(cap, cri)) {
++                      if (best == NULL ||
++                          cap->cc_sessions < best->cc_sessions)
++                              best = cap;
++              }
++      }
++      if (best != NULL)
++              return best;
++      if (match == CRYPTOCAP_F_HARDWARE && (flags & CRYPTOCAP_F_SOFTWARE)) {
++              /* sort of an Algol 68-style for loop */
++              match = CRYPTOCAP_F_SOFTWARE;
++              goto again;
++      }
++      return best;
++}
++
++/*
++ * Create a new session.  The crid argument specifies a crypto
++ * driver to use or constraints on a driver to select (hardware
++ * only, software only, either).  Whatever driver is selected
++ * must be capable of the requested crypto algorithms.
++ */
++int
++crypto_newsession(u_int64_t *sid, struct cryptoini *cri, int crid)
++{
++      struct cryptocap *cap;
++      u_int32_t hid, lid;
++      int err;
++      unsigned long d_flags;
++
++      CRYPTO_DRIVER_LOCK();
++      if ((crid & (CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SOFTWARE)) == 0) {
++              /*
++               * Use specified driver; verify it is capable.
++               */
++              cap = crypto_checkdriver(crid);
++              if (cap != NULL && !driver_suitable(cap, cri))
++                      cap = NULL;
++      } else {
++              /*
++               * No requested driver; select based on crid flags.
++               */
++              cap = crypto_select_driver(cri, crid);
++              /*
++               * if NULL then can't do everything in one session.
++               * XXX Fix this. We need to inject a "virtual" session
++               * XXX layer right about here.
++               */
++      }
++      if (cap != NULL) {
++              /* Call the driver initialization routine. */
++              hid = cap - crypto_drivers;
++              lid = hid;              /* Pass the driver ID. */
++              cap->cc_sessions++;
++              CRYPTO_DRIVER_UNLOCK();
++              err = CRYPTODEV_NEWSESSION(cap->cc_dev, &lid, cri);
++              CRYPTO_DRIVER_LOCK();
++              if (err == 0) {
++                      (*sid) = (cap->cc_flags & 0xff000000)
++                             | (hid & 0x00ffffff);
++                      (*sid) <<= 32;
++                      (*sid) |= (lid & 0xffffffff);
++              } else
++                      cap->cc_sessions--;
++      } else
++              err = EINVAL;
++      CRYPTO_DRIVER_UNLOCK();
++      return err;
++}
++
++static void
++crypto_remove(struct cryptocap *cap)
++{
++      CRYPTO_DRIVER_ASSERT();
++      if (cap->cc_sessions == 0 && cap->cc_koperations == 0)
++              bzero(cap, sizeof(*cap));
++}
++
++/*
++ * Delete an existing session (or a reserved session on an unregistered
++ * driver).
++ */
++int
++crypto_freesession(u_int64_t sid)
++{
++      struct cryptocap *cap;
++      u_int32_t hid;
++      int err = 0;
++      unsigned long d_flags;
++
++      dprintk("%s()\n", __FUNCTION__);
++      CRYPTO_DRIVER_LOCK();
++
++      if (crypto_drivers == NULL) {
++              err = EINVAL;
++              goto done;
++      }
++
++      /* Determine two IDs. */
++      hid = CRYPTO_SESID2HID(sid);
++
++      if (hid >= crypto_drivers_num) {
++              dprintk("%s - INVALID DRIVER NUM %d\n", __FUNCTION__, hid);
++              err = ENOENT;
++              goto done;
++      }
++      cap = &crypto_drivers[hid];
++
++      if (cap->cc_dev) {
++              CRYPTO_DRIVER_UNLOCK();
++              /* Call the driver cleanup routine, if available, unlocked. */
++              err = CRYPTODEV_FREESESSION(cap->cc_dev, sid);
++              CRYPTO_DRIVER_LOCK();
++      }
++
++      if (cap->cc_sessions)
++              cap->cc_sessions--;
++
++      if (cap->cc_flags & CRYPTOCAP_F_CLEANUP)
++              crypto_remove(cap);
++
++done:
++      CRYPTO_DRIVER_UNLOCK();
++      return err;
++}
++
++/*
++ * Return an unused driver id.  Used by drivers prior to registering
++ * support for the algorithms they handle.
++ */
++int32_t
++crypto_get_driverid(device_t dev, int flags)
++{
++      struct cryptocap *newdrv;
++      int i;
++      unsigned long d_flags;
++
++      if ((flags & (CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SOFTWARE)) == 0) {
++              printf("%s: no flags specified when registering driver\n",
++                  device_get_nameunit(dev));
++              return -1;
++      }
++
++      CRYPTO_DRIVER_LOCK();
++
++      for (i = 0; i < crypto_drivers_num; i++) {
++              if (crypto_drivers[i].cc_dev == NULL &&
++                  (crypto_drivers[i].cc_flags & CRYPTOCAP_F_CLEANUP) == 0) {
++                      break;
++              }
++      }
++
++      /* Out of entries, allocate some more. */
++      if (i == crypto_drivers_num) {
++              /* Be careful about wrap-around. */
++              if (2 * crypto_drivers_num <= crypto_drivers_num) {
++                      CRYPTO_DRIVER_UNLOCK();
++                      printk("crypto: driver count wraparound!\n");
++                      return -1;
++              }
++
++              newdrv = kmalloc(2 * crypto_drivers_num * sizeof(struct cryptocap),
++                              GFP_KERNEL);
++              if (newdrv == NULL) {
++                      CRYPTO_DRIVER_UNLOCK();
++                      printk("crypto: no space to expand driver table!\n");
++                      return -1;
++              }
++
++              memcpy(newdrv, crypto_drivers,
++                              crypto_drivers_num * sizeof(struct cryptocap));
++              memset(&newdrv[crypto_drivers_num], 0,
++                              crypto_drivers_num * sizeof(struct cryptocap));
++
++              crypto_drivers_num *= 2;
++
++              kfree(crypto_drivers);
++              crypto_drivers = newdrv;
++      }
++
++      /* NB: state is zero'd on free */
++      crypto_drivers[i].cc_sessions = 1;      /* Mark */
++      crypto_drivers[i].cc_dev = dev;
++      crypto_drivers[i].cc_flags = flags;
++      if (bootverbose)
++              printf("crypto: assign %s driver id %u, flags %u\n",
++                  device_get_nameunit(dev), i, flags);
++
++      CRYPTO_DRIVER_UNLOCK();
++
++      return i;
++}
++
++/*
++ * Lookup a driver by name.  We match against the full device
++ * name and unit, and against just the name.  The latter gives
++ * us a simple widlcarding by device name.  On success return the
++ * driver/hardware identifier; otherwise return -1.
++ */
++int
++crypto_find_driver(const char *match)
++{
++      int i, len = strlen(match);
++      unsigned long d_flags;
++
++      CRYPTO_DRIVER_LOCK();
++      for (i = 0; i < crypto_drivers_num; i++) {
++              device_t dev = crypto_drivers[i].cc_dev;
++              if (dev == NULL ||
++                  (crypto_drivers[i].cc_flags & CRYPTOCAP_F_CLEANUP))
++                      continue;
++              if (strncmp(match, device_get_nameunit(dev), len) == 0 ||
++                  strncmp(match, device_get_name(dev), len) == 0)
++                      break;
++      }
++      CRYPTO_DRIVER_UNLOCK();
++      return i < crypto_drivers_num ? i : -1;
++}
++
++/*
++ * Return the device_t for the specified driver or NULL
++ * if the driver identifier is invalid.
++ */
++device_t
++crypto_find_device_byhid(int hid)
++{
++      struct cryptocap *cap = crypto_checkdriver(hid);
++      return cap != NULL ? cap->cc_dev : NULL;
++}
++
++/*
++ * Return the device/driver capabilities.
++ */
++int
++crypto_getcaps(int hid)
++{
++      struct cryptocap *cap = crypto_checkdriver(hid);
++      return cap != NULL ? cap->cc_flags : 0;
++}
++
++/*
++ * Register support for a key-related algorithm.  This routine
++ * is called once for each algorithm supported a driver.
++ */
++int
++crypto_kregister(u_int32_t driverid, int kalg, u_int32_t flags)
++{
++      struct cryptocap *cap;
++      int err;
++      unsigned long d_flags;
++
++      dprintk("%s()\n", __FUNCTION__);
++      CRYPTO_DRIVER_LOCK();
++
++      cap = crypto_checkdriver(driverid);
++      if (cap != NULL &&
++          (CRK_ALGORITM_MIN <= kalg && kalg <= CRK_ALGORITHM_MAX)) {
++              /*
++               * XXX Do some performance testing to determine placing.
++               * XXX We probably need an auxiliary data structure that
++               * XXX describes relative performances.
++               */
++
++              cap->cc_kalg[kalg] = flags | CRYPTO_ALG_FLAG_SUPPORTED;
++              if (bootverbose)
++                      printf("crypto: %s registers key alg %u flags %u\n"
++                              , device_get_nameunit(cap->cc_dev)
++                              , kalg
++                              , flags
++                      );
++              err = 0;
++      } else
++              err = EINVAL;
++
++      CRYPTO_DRIVER_UNLOCK();
++      return err;
++}
++
++/*
++ * Register support for a non-key-related algorithm.  This routine
++ * is called once for each such algorithm supported by a driver.
++ */
++int
++crypto_register(u_int32_t driverid, int alg, u_int16_t maxoplen,
++    u_int32_t flags)
++{
++      struct cryptocap *cap;
++      int err;
++      unsigned long d_flags;
++
++      dprintk("%s(id=0x%x, alg=%d, maxoplen=%d, flags=0x%x)\n", __FUNCTION__,
++                      driverid, alg, maxoplen, flags);
++
++      CRYPTO_DRIVER_LOCK();
++
++      cap = crypto_checkdriver(driverid);
++      /* NB: algorithms are in the range [1..max] */
++      if (cap != NULL &&
++          (CRYPTO_ALGORITHM_MIN <= alg && alg <= CRYPTO_ALGORITHM_MAX)) {
++              /*
++               * XXX Do some performance testing to determine placing.
++               * XXX We probably need an auxiliary data structure that
++               * XXX describes relative performances.
++               */
++
++              cap->cc_alg[alg] = flags | CRYPTO_ALG_FLAG_SUPPORTED;
++              cap->cc_max_op_len[alg] = maxoplen;
++              if (bootverbose)
++                      printf("crypto: %s registers alg %u flags %u maxoplen %u\n"
++                              , device_get_nameunit(cap->cc_dev)
++                              , alg
++                              , flags
++                              , maxoplen
++                      );
++              cap->cc_sessions = 0;           /* Unmark */
++              err = 0;
++      } else
++              err = EINVAL;
++
++      CRYPTO_DRIVER_UNLOCK();
++      return err;
++}
++
++static void
++driver_finis(struct cryptocap *cap)
++{
++      u_int32_t ses, kops;
++
++      CRYPTO_DRIVER_ASSERT();
++
++      ses = cap->cc_sessions;
++      kops = cap->cc_koperations;
++      bzero(cap, sizeof(*cap));
++      if (ses != 0 || kops != 0) {
++              /*
++               * If there are pending sessions,
++               * just mark as invalid.
++               */
++              cap->cc_flags |= CRYPTOCAP_F_CLEANUP;
++              cap->cc_sessions = ses;
++              cap->cc_koperations = kops;
++      }
++}
++
++/*
++ * Unregister a crypto driver. If there are pending sessions using it,
++ * leave enough information around so that subsequent calls using those
++ * sessions will correctly detect the driver has been unregistered and
++ * reroute requests.
++ */
++int
++crypto_unregister(u_int32_t driverid, int alg)
++{
++      struct cryptocap *cap;
++      int i, err;
++      unsigned long d_flags;
++
++      dprintk("%s()\n", __FUNCTION__);
++      CRYPTO_DRIVER_LOCK();
++
++      cap = crypto_checkdriver(driverid);
++      if (cap != NULL &&
++          (CRYPTO_ALGORITHM_MIN <= alg && alg <= CRYPTO_ALGORITHM_MAX) &&
++          cap->cc_alg[alg] != 0) {
++              cap->cc_alg[alg] = 0;
++              cap->cc_max_op_len[alg] = 0;
++
++              /* Was this the last algorithm ? */
++              for (i = 1; i <= CRYPTO_ALGORITHM_MAX; i++)
++                      if (cap->cc_alg[i] != 0)
++                              break;
++
++              if (i == CRYPTO_ALGORITHM_MAX + 1)
++                      driver_finis(cap);
++              err = 0;
++      } else
++              err = EINVAL;
++      CRYPTO_DRIVER_UNLOCK();
++      return err;
++}
++
++/*
++ * Unregister all algorithms associated with a crypto driver.
++ * If there are pending sessions using it, leave enough information
++ * around so that subsequent calls using those sessions will
++ * correctly detect the driver has been unregistered and reroute
++ * requests.
++ */
++int
++crypto_unregister_all(u_int32_t driverid)
++{
++      struct cryptocap *cap;
++      int err;
++      unsigned long d_flags;
++
++      dprintk("%s()\n", __FUNCTION__);
++      CRYPTO_DRIVER_LOCK();
++      cap = crypto_checkdriver(driverid);
++      if (cap != NULL) {
++              driver_finis(cap);
++              err = 0;
++      } else
++              err = EINVAL;
++      CRYPTO_DRIVER_UNLOCK();
++
++      return err;
++}
++
++/*
++ * Clear blockage on a driver.  The what parameter indicates whether
++ * the driver is now ready for cryptop's and/or cryptokop's.
++ */
++int
++crypto_unblock(u_int32_t driverid, int what)
++{
++      struct cryptocap *cap;
++      int err;
++      unsigned long q_flags;
++
++      CRYPTO_Q_LOCK();
++      cap = crypto_checkdriver(driverid);
++      if (cap != NULL) {
++              if (what & CRYPTO_SYMQ) {
++                      cap->cc_qblocked = 0;
++                      cap->cc_unqblocked = 0;
++                      crypto_all_qblocked = 0;
++              }
++              if (what & CRYPTO_ASYMQ) {
++                      cap->cc_kqblocked = 0;
++                      cap->cc_unkqblocked = 0;
++                      crypto_all_kqblocked = 0;
++              }
++              wake_up_interruptible(&cryptoproc_wait);
++              err = 0;
++      } else
++              err = EINVAL;
++      CRYPTO_Q_UNLOCK(); //DAVIDM should this be a driver lock
++
++      return err;
++}
++
++/*
++ * Add a crypto request to a queue, to be processed by the kernel thread.
++ */
++int
++crypto_dispatch(struct cryptop *crp)
++{
++      struct cryptocap *cap;
++      int result = -1;
++      unsigned long q_flags;
++
++      dprintk("%s()\n", __FUNCTION__);
++
++      cryptostats.cs_ops++;
++
++      CRYPTO_Q_LOCK();
++      if (crypto_q_cnt >= crypto_q_max) {
++              cryptostats.cs_drops++;
++              CRYPTO_Q_UNLOCK();
++              return ENOMEM;
++      }
++      crypto_q_cnt++;
++
++      /* make sure we are starting a fresh run on this crp. */
++      crp->crp_flags &= ~CRYPTO_F_DONE;
++      crp->crp_etype = 0;
++
++      /*
++       * Caller marked the request to be processed immediately; dispatch
++       * it directly to the driver unless the driver is currently blocked.
++       */
++      if ((crp->crp_flags & CRYPTO_F_BATCH) == 0) {
++              int hid = CRYPTO_SESID2HID(crp->crp_sid);
++              cap = crypto_checkdriver(hid);
++              /* Driver cannot disappear when there is an active session. */
++              KASSERT(cap != NULL, ("%s: Driver disappeared.", __func__));
++              if (!cap->cc_qblocked) {
++                      crypto_all_qblocked = 0;
++                      crypto_drivers[hid].cc_unqblocked = 1;
++                      CRYPTO_Q_UNLOCK();
++                      result = crypto_invoke(cap, crp, 0);
++                      CRYPTO_Q_LOCK();
++                      if (result == ERESTART)
++                              if (crypto_drivers[hid].cc_unqblocked)
++                                      crypto_drivers[hid].cc_qblocked = 1;
++                      crypto_drivers[hid].cc_unqblocked = 0;
++              }
++      }
++      if (result == ERESTART) {
++              /*
++               * The driver ran out of resources, mark the
++               * driver ``blocked'' for cryptop's and put
++               * the request back in the queue.  It would
++               * best to put the request back where we got
++               * it but that's hard so for now we put it
++               * at the front.  This should be ok; putting
++               * it at the end does not work.
++               */
++              list_add(&crp->crp_next, &crp_q);
++              cryptostats.cs_blocks++;
++              result = 0;
++      } else if (result == -1) {
++              TAILQ_INSERT_TAIL(&crp_q, crp, crp_next);
++              result = 0;
++      }
++      wake_up_interruptible(&cryptoproc_wait);
++      CRYPTO_Q_UNLOCK();
++      return result;
++}
++
++/*
++ * Add an asymetric crypto request to a queue,
++ * to be processed by the kernel thread.
++ */
++int
++crypto_kdispatch(struct cryptkop *krp)
++{
++      int error;
++      unsigned long q_flags;
++
++      cryptostats.cs_kops++;
++
++      error = crypto_kinvoke(krp, krp->krp_crid);
++      if (error == ERESTART) {
++              CRYPTO_Q_LOCK();
++              TAILQ_INSERT_TAIL(&crp_kq, krp, krp_next);
++              wake_up_interruptible(&cryptoproc_wait);
++              CRYPTO_Q_UNLOCK();
++              error = 0;
++      }
++      return error;
++}
++
++/*
++ * Verify a driver is suitable for the specified operation.
++ */
++static __inline int
++kdriver_suitable(const struct cryptocap *cap, const struct cryptkop *krp)
++{
++      return (cap->cc_kalg[krp->krp_op] & CRYPTO_ALG_FLAG_SUPPORTED) != 0;
++}
++
++/*
++ * Select a driver for an asym operation.  The driver must
++ * support the necessary algorithm.  The caller can constrain
++ * which device is selected with the flags parameter.  The
++ * algorithm we use here is pretty stupid; just use the first
++ * driver that supports the algorithms we need. If there are
++ * multiple suitable drivers we choose the driver with the
++ * fewest active operations.  We prefer hardware-backed
++ * drivers to software ones when either may be used.
++ */
++static struct cryptocap *
++crypto_select_kdriver(const struct cryptkop *krp, int flags)
++{
++      struct cryptocap *cap, *best, *blocked;
++      int match, hid;
++
++      CRYPTO_DRIVER_ASSERT();
++
++      /*
++       * Look first for hardware crypto devices if permitted.
++       */
++      if (flags & CRYPTOCAP_F_HARDWARE)
++              match = CRYPTOCAP_F_HARDWARE;
++      else
++              match = CRYPTOCAP_F_SOFTWARE;
++      best = NULL;
++      blocked = NULL;
++again:
++      for (hid = 0; hid < crypto_drivers_num; hid++) {
++              cap = &crypto_drivers[hid];
++              /*
++               * If it's not initialized, is in the process of
++               * going away, or is not appropriate (hardware
++               * or software based on match), then skip.
++               */
++              if (cap->cc_dev == NULL ||
++                  (cap->cc_flags & CRYPTOCAP_F_CLEANUP) ||
++                  (cap->cc_flags & match) == 0)
++                      continue;
++
++              /* verify all the algorithms are supported. */
++              if (kdriver_suitable(cap, krp)) {
++                      if (best == NULL ||
++                          cap->cc_koperations < best->cc_koperations)
++                              best = cap;
++              }
++      }
++      if (best != NULL)
++              return best;
++      if (match == CRYPTOCAP_F_HARDWARE && (flags & CRYPTOCAP_F_SOFTWARE)) {
++              /* sort of an Algol 68-style for loop */
++              match = CRYPTOCAP_F_SOFTWARE;
++              goto again;
++      }
++      return best;
++}
++
++/*
++ * Dispatch an assymetric crypto request.
++ */
++static int
++crypto_kinvoke(struct cryptkop *krp, int crid)
++{
++      struct cryptocap *cap = NULL;
++      int error;
++      unsigned long d_flags;
++
++      KASSERT(krp != NULL, ("%s: krp == NULL", __func__));
++      KASSERT(krp->krp_callback != NULL,
++          ("%s: krp->crp_callback == NULL", __func__));
++
++      CRYPTO_DRIVER_LOCK();
++      if ((crid & (CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SOFTWARE)) == 0) {
++              cap = crypto_checkdriver(crid);
++              if (cap != NULL) {
++                      /*
++                       * Driver present, it must support the necessary
++                       * algorithm and, if s/w drivers are excluded,
++                       * it must be registered as hardware-backed.
++                       */
++                      if (!kdriver_suitable(cap, krp) ||
++                          (!crypto_devallowsoft &&
++                           (cap->cc_flags & CRYPTOCAP_F_HARDWARE) == 0))
++                              cap = NULL;
++              }
++      } else {
++              /*
++               * No requested driver; select based on crid flags.
++               */
++              if (!crypto_devallowsoft)       /* NB: disallow s/w drivers */
++                      crid &= ~CRYPTOCAP_F_SOFTWARE;
++              cap = crypto_select_kdriver(krp, crid);
++      }
++      if (cap != NULL && !cap->cc_kqblocked) {
++              krp->krp_hid = cap - crypto_drivers;
++              cap->cc_koperations++;
++              CRYPTO_DRIVER_UNLOCK();
++              error = CRYPTODEV_KPROCESS(cap->cc_dev, krp, 0);
++              CRYPTO_DRIVER_LOCK();
++              if (error == ERESTART) {
++                      cap->cc_koperations--;
++                      CRYPTO_DRIVER_UNLOCK();
++                      return (error);
++              }
++              /* return the actual device used */
++              krp->krp_crid = krp->krp_hid;
++      } else {
++              /*
++               * NB: cap is !NULL if device is blocked; in
++               *     that case return ERESTART so the operation
++               *     is resubmitted if possible.
++               */
++              error = (cap == NULL) ? ENODEV : ERESTART;
++      }
++      CRYPTO_DRIVER_UNLOCK();
++
++      if (error) {
++              krp->krp_status = error;
++              crypto_kdone(krp);
++      }
++      return 0;
++}
++
++
++/*
++ * Dispatch a crypto request to the appropriate crypto devices.
++ */
++static int
++crypto_invoke(struct cryptocap *cap, struct cryptop *crp, int hint)
++{
++      KASSERT(crp != NULL, ("%s: crp == NULL", __func__));
++      KASSERT(crp->crp_callback != NULL,
++          ("%s: crp->crp_callback == NULL", __func__));
++      KASSERT(crp->crp_desc != NULL, ("%s: crp->crp_desc == NULL", __func__));
++
++      dprintk("%s()\n", __FUNCTION__);
++
++#ifdef CRYPTO_TIMING
++      if (crypto_timing)
++              crypto_tstat(&cryptostats.cs_invoke, &crp->crp_tstamp);
++#endif
++      if (cap->cc_flags & CRYPTOCAP_F_CLEANUP) {
++              struct cryptodesc *crd;
++              u_int64_t nid;
++
++              /*
++               * Driver has unregistered; migrate the session and return
++               * an error to the caller so they'll resubmit the op.
++               *
++               * XXX: What if there are more already queued requests for this
++               *      session?
++               */
++              crypto_freesession(crp->crp_sid);
++
++              for (crd = crp->crp_desc; crd->crd_next; crd = crd->crd_next)
++                      crd->CRD_INI.cri_next = &(crd->crd_next->CRD_INI);
++
++              /* XXX propagate flags from initial session? */
++              if (crypto_newsession(&nid, &(crp->crp_desc->CRD_INI),
++                  CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SOFTWARE) == 0)
++                      crp->crp_sid = nid;
++
++              crp->crp_etype = EAGAIN;
++              crypto_done(crp);
++              return 0;
++      } else {
++              /*
++               * Invoke the driver to process the request.
++               */
++              return CRYPTODEV_PROCESS(cap->cc_dev, crp, hint);
++      }
++}
++
++/*
++ * Release a set of crypto descriptors.
++ */
++void
++crypto_freereq(struct cryptop *crp)
++{
++      struct cryptodesc *crd;
++
++      if (crp == NULL)
++              return;
++
++#ifdef DIAGNOSTIC
++      {
++              struct cryptop *crp2;
++              unsigned long q_flags;
++
++              CRYPTO_Q_LOCK();
++              TAILQ_FOREACH(crp2, &crp_q, crp_next) {
++                      KASSERT(crp2 != crp,
++                          ("Freeing cryptop from the crypto queue (%p).",
++                          crp));
++              }
++              CRYPTO_Q_UNLOCK();
++              CRYPTO_RETQ_LOCK();
++              TAILQ_FOREACH(crp2, &crp_ret_q, crp_next) {
++                      KASSERT(crp2 != crp,
++                          ("Freeing cryptop from the return queue (%p).",
++                          crp));
++              }
++              CRYPTO_RETQ_UNLOCK();
++      }
++#endif
++
++      while ((crd = crp->crp_desc) != NULL) {
++              crp->crp_desc = crd->crd_next;
++              kmem_cache_free(cryptodesc_zone, crd);
++      }
++      kmem_cache_free(cryptop_zone, crp);
++}
++
++/*
++ * Acquire a set of crypto descriptors.
++ */
++struct cryptop *
++crypto_getreq(int num)
++{
++      struct cryptodesc *crd;
++      struct cryptop *crp;
++
++      crp = kmem_cache_alloc(cryptop_zone, SLAB_ATOMIC);
++      if (crp != NULL) {
++              memset(crp, 0, sizeof(*crp));
++              INIT_LIST_HEAD(&crp->crp_next);
++              init_waitqueue_head(&crp->crp_waitq);
++              while (num--) {
++                      crd = kmem_cache_alloc(cryptodesc_zone, SLAB_ATOMIC);
++                      if (crd == NULL) {
++                              crypto_freereq(crp);
++                              return NULL;
++                      }
++                      memset(crd, 0, sizeof(*crd));
++                      crd->crd_next = crp->crp_desc;
++                      crp->crp_desc = crd;
++              }
++      }
++      return crp;
++}
++
++/*
++ * Invoke the callback on behalf of the driver.
++ */
++void
++crypto_done(struct cryptop *crp)
++{
++      unsigned long q_flags;
++
++      dprintk("%s()\n", __FUNCTION__);
++      if ((crp->crp_flags & CRYPTO_F_DONE) == 0) {
++              crp->crp_flags |= CRYPTO_F_DONE;
++              CRYPTO_Q_LOCK();
++              crypto_q_cnt--;
++              CRYPTO_Q_UNLOCK();
++      } else
++              printk("crypto: crypto_done op already done, flags 0x%x",
++                              crp->crp_flags);
++      if (crp->crp_etype != 0)
++              cryptostats.cs_errs++;
++      /*
++       * CBIMM means unconditionally do the callback immediately;
++       * CBIFSYNC means do the callback immediately only if the
++       * operation was done synchronously.  Both are used to avoid
++       * doing extraneous context switches; the latter is mostly
++       * used with the software crypto driver.
++       */
++      if ((crp->crp_flags & CRYPTO_F_CBIMM) ||
++          ((crp->crp_flags & CRYPTO_F_CBIFSYNC) &&
++           (CRYPTO_SESID2CAPS(crp->crp_sid) & CRYPTOCAP_F_SYNC))) {
++              /*
++               * Do the callback directly.  This is ok when the
++               * callback routine does very little (e.g. the
++               * /dev/crypto callback method just does a wakeup).
++               */
++              crp->crp_callback(crp);
++      } else {
++              unsigned long r_flags;
++              /*
++               * Normal case; queue the callback for the thread.
++               */
++              CRYPTO_RETQ_LOCK();
++              wake_up_interruptible(&cryptoretproc_wait);/* shared wait channel */
++              TAILQ_INSERT_TAIL(&crp_ret_q, crp, crp_next);
++              CRYPTO_RETQ_UNLOCK();
++      }
++}
++
++/*
++ * Invoke the callback on behalf of the driver.
++ */
++void
++crypto_kdone(struct cryptkop *krp)
++{
++      struct cryptocap *cap;
++      unsigned long d_flags;
++
++      if ((krp->krp_flags & CRYPTO_KF_DONE) != 0)
++              printk("crypto: crypto_kdone op already done, flags 0x%x",
++                              krp->krp_flags);
++      krp->krp_flags |= CRYPTO_KF_DONE;
++      if (krp->krp_status != 0)
++              cryptostats.cs_kerrs++;
++
++      CRYPTO_DRIVER_LOCK();
++      /* XXX: What if driver is loaded in the meantime? */
++      if (krp->krp_hid < crypto_drivers_num) {
++              cap = &crypto_drivers[krp->krp_hid];
++              cap->cc_koperations--;
++              KASSERT(cap->cc_koperations >= 0, ("cc_koperations < 0"));
++              if (cap->cc_flags & CRYPTOCAP_F_CLEANUP)
++                      crypto_remove(cap);
++      }
++      CRYPTO_DRIVER_UNLOCK();
++
++      /*
++       * CBIMM means unconditionally do the callback immediately;
++       * This is used to avoid doing extraneous context switches
++       */
++      if ((krp->krp_flags & CRYPTO_KF_CBIMM)) {
++              /*
++               * Do the callback directly.  This is ok when the
++               * callback routine does very little (e.g. the
++               * /dev/crypto callback method just does a wakeup).
++               */
++              krp->krp_callback(krp);
++      } else {
++              unsigned long r_flags;
++              /*
++               * Normal case; queue the callback for the thread.
++               */
++              CRYPTO_RETQ_LOCK();
++              wake_up_interruptible(&cryptoretproc_wait);/* shared wait channel */
++              TAILQ_INSERT_TAIL(&crp_ret_kq, krp, krp_next);
++              CRYPTO_RETQ_UNLOCK();
++      }
++}
++
++int
++crypto_getfeat(int *featp)
++{
++      int hid, kalg, feat = 0;
++      unsigned long d_flags;
++
++      CRYPTO_DRIVER_LOCK();
++      for (hid = 0; hid < crypto_drivers_num; hid++) {
++              const struct cryptocap *cap = &crypto_drivers[hid];
++
++              if ((cap->cc_flags & CRYPTOCAP_F_SOFTWARE) &&
++                  !crypto_devallowsoft) {
++                      continue;
++              }
++              for (kalg = 0; kalg < CRK_ALGORITHM_MAX; kalg++)
++                      if (cap->cc_kalg[kalg] & CRYPTO_ALG_FLAG_SUPPORTED)
++                              feat |=  1 << kalg;
++      }
++      CRYPTO_DRIVER_UNLOCK();
++      *featp = feat;
++      return (0);
++}
++
++/*
++ * Crypto thread, dispatches crypto requests.
++ */
++static int
++crypto_proc(void *arg)
++{
++      struct cryptop *crp, *submit;
++      struct cryptkop *krp, *krpp;
++      struct cryptocap *cap;
++      u_int32_t hid;
++      int result, hint;
++      unsigned long q_flags;
++      int loopcount = 0;
++
++      set_current_state(TASK_INTERRUPTIBLE);
++
++      CRYPTO_Q_LOCK();
++      for (;;) {
++              /*
++               * we need to make sure we don't get into a busy loop with nothing
++               * to do,  the two crypto_all_*blocked vars help us find out when
++               * we are all full and can do nothing on any driver or Q.  If so we
++               * wait for an unblock.
++               */
++              crypto_all_qblocked  = !list_empty(&crp_q);
++
++              /*
++               * Find the first element in the queue that can be
++               * processed and look-ahead to see if multiple ops
++               * are ready for the same driver.
++               */
++              submit = NULL;
++              hint = 0;
++              list_for_each_entry(crp, &crp_q, crp_next) {
++                      hid = CRYPTO_SESID2HID(crp->crp_sid);
++                      cap = crypto_checkdriver(hid);
++                      /*
++                       * Driver cannot disappear when there is an active
++                       * session.
++                       */
++                      KASSERT(cap != NULL, ("%s:%u Driver disappeared.",
++                          __func__, __LINE__));
++                      if (cap == NULL || cap->cc_dev == NULL) {
++                              /* Op needs to be migrated, process it. */
++                              if (submit == NULL)
++                                      submit = crp;
++                              break;
++                      }
++                      if (!cap->cc_qblocked) {
++                              if (submit != NULL) {
++                                      /*
++                                       * We stop on finding another op,
++                                       * regardless whether its for the same
++                                       * driver or not.  We could keep
++                                       * searching the queue but it might be
++                                       * better to just use a per-driver
++                                       * queue instead.
++                                       */
++                                      if (CRYPTO_SESID2HID(submit->crp_sid) == hid)
++                                              hint = CRYPTO_HINT_MORE;
++                                      break;
++                              } else {
++                                      submit = crp;
++                                      if ((submit->crp_flags & CRYPTO_F_BATCH) == 0)
++                                              break;
++                                      /* keep scanning for more are q'd */
++                              }
++                      }
++              }
++              if (submit != NULL) {
++                      hid = CRYPTO_SESID2HID(submit->crp_sid);
++                      crypto_all_qblocked = 0;
++                      list_del(&submit->crp_next);
++                      crypto_drivers[hid].cc_unqblocked = 1;
++                      cap = crypto_checkdriver(hid);
++                      CRYPTO_Q_UNLOCK();
++                      KASSERT(cap != NULL, ("%s:%u Driver disappeared.",
++                          __func__, __LINE__));
++                      result = crypto_invoke(cap, submit, hint);
++                      CRYPTO_Q_LOCK();
++                      if (result == ERESTART) {
++                              /*
++                               * The driver ran out of resources, mark the
++                               * driver ``blocked'' for cryptop's and put
++                               * the request back in the queue.  It would
++                               * best to put the request back where we got
++                               * it but that's hard so for now we put it
++                               * at the front.  This should be ok; putting
++                               * it at the end does not work.
++                               */
++                              /* XXX validate sid again? */
++                              list_add(&submit->crp_next, &crp_q);
++                              cryptostats.cs_blocks++;
++                              if (crypto_drivers[hid].cc_unqblocked)
++                                      crypto_drivers[hid].cc_qblocked=0;
++                              crypto_drivers[hid].cc_unqblocked=0;
++                      }
++                      crypto_drivers[hid].cc_unqblocked = 0;
++              }
++
++              crypto_all_kqblocked = !list_empty(&crp_kq);
++
++              /* As above, but for key ops */
++              krp = NULL;
++              list_for_each_entry(krpp, &crp_kq, krp_next) {
++                      cap = crypto_checkdriver(krpp->krp_hid);
++                      if (cap == NULL || cap->cc_dev == NULL) {
++                              /*
++                               * Operation needs to be migrated, invalidate
++                               * the assigned device so it will reselect a
++                               * new one below.  Propagate the original
++                               * crid selection flags if supplied.
++                               */
++                              krp->krp_hid = krp->krp_crid &
++                                  (CRYPTOCAP_F_SOFTWARE|CRYPTOCAP_F_HARDWARE);
++                              if (krp->krp_hid == 0)
++                                      krp->krp_hid =
++                                  CRYPTOCAP_F_SOFTWARE|CRYPTOCAP_F_HARDWARE;
++                              break;
++                      }
++                      if (!cap->cc_kqblocked) {
++                              krp = krpp;
++                              break;
++                      }
++              }
++              if (krp != NULL) {
++                      crypto_all_kqblocked = 0;
++                      list_del(&krp->krp_next);
++                      crypto_drivers[krp->krp_hid].cc_kqblocked = 1;
++                      CRYPTO_Q_UNLOCK();
++                      result = crypto_kinvoke(krp, krp->krp_hid);
++                      CRYPTO_Q_LOCK();
++                      if (result == ERESTART) {
++                              /*
++                               * The driver ran out of resources, mark the
++                               * driver ``blocked'' for cryptkop's and put
++                               * the request back in the queue.  It would
++                               * best to put the request back where we got
++                               * it but that's hard so for now we put it
++                               * at the front.  This should be ok; putting
++                               * it at the end does not work.
++                               */
++                              /* XXX validate sid again? */
++                              list_add(&krp->krp_next, &crp_kq);
++                              cryptostats.cs_kblocks++;
++                      } else
++                              crypto_drivers[krp->krp_hid].cc_kqblocked = 0;
++              }
++
++              if (submit == NULL && krp == NULL) {
++                      /*
++                       * Nothing more to be processed.  Sleep until we're
++                       * woken because there are more ops to process.
++                       * This happens either by submission or by a driver
++                       * becoming unblocked and notifying us through
++                       * crypto_unblock.  Note that when we wakeup we
++                       * start processing each queue again from the
++                       * front. It's not clear that it's important to
++                       * preserve this ordering since ops may finish
++                       * out of order if dispatched to different devices
++                       * and some become blocked while others do not.
++                       */
++                      dprintk("%s - sleeping (qe=%d qb=%d kqe=%d kqb=%d)\n",
++                                      __FUNCTION__,
++                                      list_empty(&crp_q), crypto_all_qblocked,
++                                      list_empty(&crp_kq), crypto_all_kqblocked);
++                      loopcount = 0;
++                      CRYPTO_Q_UNLOCK();
++                      wait_event_interruptible(cryptoproc_wait,
++                                      !(list_empty(&crp_q) || crypto_all_qblocked) ||
++                                      !(list_empty(&crp_kq) || crypto_all_kqblocked) ||
++                                      kthread_should_stop());
++                      if (signal_pending (current)) {
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
++                              spin_lock_irq(&current->sigmask_lock);
++#endif
++                              flush_signals(current);
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
++                              spin_unlock_irq(&current->sigmask_lock);
++#endif
++                      }
++                      CRYPTO_Q_LOCK();
++                      dprintk("%s - awake\n", __FUNCTION__);
++                      if (kthread_should_stop())
++                              break;
++                      cryptostats.cs_intrs++;
++              } else if (loopcount > crypto_max_loopcount) {
++                      /*
++                       * Give other processes a chance to run if we've
++                       * been using the CPU exclusively for a while.
++                       */
++                      loopcount = 0;
++                      CRYPTO_Q_UNLOCK();
++                      schedule();
++                      CRYPTO_Q_LOCK();
++              }
++              loopcount++;
++      }
++      CRYPTO_Q_UNLOCK();
++      return 0;
++}
++
++/*
++ * Crypto returns thread, does callbacks for processed crypto requests.
++ * Callbacks are done here, rather than in the crypto drivers, because
++ * callbacks typically are expensive and would slow interrupt handling.
++ */
++static int
++crypto_ret_proc(void *arg)
++{
++      struct cryptop *crpt;
++      struct cryptkop *krpt;
++      unsigned long  r_flags;
++
++      set_current_state(TASK_INTERRUPTIBLE);
++
++      CRYPTO_RETQ_LOCK();
++      for (;;) {
++              /* Harvest return q's for completed ops */
++              crpt = NULL;
++              if (!list_empty(&crp_ret_q))
++                      crpt = list_entry(crp_ret_q.next, typeof(*crpt), crp_next);
++              if (crpt != NULL)
++                      list_del(&crpt->crp_next);
++
++              krpt = NULL;
++              if (!list_empty(&crp_ret_kq))
++                      krpt = list_entry(crp_ret_kq.next, typeof(*krpt), krp_next);
++              if (krpt != NULL)
++                      list_del(&krpt->krp_next);
++
++              if (crpt != NULL || krpt != NULL) {
++                      CRYPTO_RETQ_UNLOCK();
++                      /*
++                       * Run callbacks unlocked.
++                       */
++                      if (crpt != NULL)
++                              crpt->crp_callback(crpt);
++                      if (krpt != NULL)
++                              krpt->krp_callback(krpt);
++                      CRYPTO_RETQ_LOCK();
++              } else {
++                      /*
++                       * Nothing more to be processed.  Sleep until we're
++                       * woken because there are more returns to process.
++                       */
++                      dprintk("%s - sleeping\n", __FUNCTION__);
++                      CRYPTO_RETQ_UNLOCK();
++                      wait_event_interruptible(cryptoretproc_wait,
++                                      !list_empty(&crp_ret_q) ||
++                                      !list_empty(&crp_ret_kq) ||
++                                      kthread_should_stop());
++                      if (signal_pending (current)) {
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
++                              spin_lock_irq(&current->sigmask_lock);
++#endif
++                              flush_signals(current);
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
++                              spin_unlock_irq(&current->sigmask_lock);
++#endif
++                      }
++                      CRYPTO_RETQ_LOCK();
++                      dprintk("%s - awake\n", __FUNCTION__);
++                      if (kthread_should_stop()) {
++                              dprintk("%s - EXITING!\n", __FUNCTION__);
++                              break;
++                      }
++                      cryptostats.cs_rets++;
++              }
++      }
++      CRYPTO_RETQ_UNLOCK();
++      return 0;
++}
++
++
++#if 0 /* should put this into /proc or something */
++static void
++db_show_drivers(void)
++{
++      int hid;
++
++      db_printf("%12s %4s %4s %8s %2s %2s\n"
++              , "Device"
++              , "Ses"
++              , "Kops"
++              , "Flags"
++              , "QB"
++              , "KB"
++      );
++      for (hid = 0; hid < crypto_drivers_num; hid++) {
++              const struct cryptocap *cap = &crypto_drivers[hid];
++              if (cap->cc_dev == NULL)
++                      continue;
++              db_printf("%-12s %4u %4u %08x %2u %2u\n"
++                  , device_get_nameunit(cap->cc_dev)
++                  , cap->cc_sessions
++                  , cap->cc_koperations
++                  , cap->cc_flags
++                  , cap->cc_qblocked
++                  , cap->cc_kqblocked
++              );
++      }
++}
++
++DB_SHOW_COMMAND(crypto, db_show_crypto)
++{
++      struct cryptop *crp;
++
++      db_show_drivers();
++      db_printf("\n");
++
++      db_printf("%4s %8s %4s %4s %4s %4s %8s %8s\n",
++          "HID", "Caps", "Ilen", "Olen", "Etype", "Flags",
++          "Desc", "Callback");
++      TAILQ_FOREACH(crp, &crp_q, crp_next) {
++              db_printf("%4u %08x %4u %4u %4u %04x %8p %8p\n"
++                  , (int) CRYPTO_SESID2HID(crp->crp_sid)
++                  , (int) CRYPTO_SESID2CAPS(crp->crp_sid)
++                  , crp->crp_ilen, crp->crp_olen
++                  , crp->crp_etype
++                  , crp->crp_flags
++                  , crp->crp_desc
++                  , crp->crp_callback
++              );
++      }
++      if (!TAILQ_EMPTY(&crp_ret_q)) {
++              db_printf("\n%4s %4s %4s %8s\n",
++                  "HID", "Etype", "Flags", "Callback");
++              TAILQ_FOREACH(crp, &crp_ret_q, crp_next) {
++                      db_printf("%4u %4u %04x %8p\n"
++                          , (int) CRYPTO_SESID2HID(crp->crp_sid)
++                          , crp->crp_etype
++                          , crp->crp_flags
++                          , crp->crp_callback
++                      );
++              }
++      }
++}
++
++DB_SHOW_COMMAND(kcrypto, db_show_kcrypto)
++{
++      struct cryptkop *krp;
++
++      db_show_drivers();
++      db_printf("\n");
++
++      db_printf("%4s %5s %4s %4s %8s %4s %8s\n",
++          "Op", "Status", "#IP", "#OP", "CRID", "HID", "Callback");
++      TAILQ_FOREACH(krp, &crp_kq, krp_next) {
++              db_printf("%4u %5u %4u %4u %08x %4u %8p\n"
++                  , krp->krp_op
++                  , krp->krp_status
++                  , krp->krp_iparams, krp->krp_oparams
++                  , krp->krp_crid, krp->krp_hid
++                  , krp->krp_callback
++              );
++      }
++      if (!TAILQ_EMPTY(&crp_ret_q)) {
++              db_printf("%4s %5s %8s %4s %8s\n",
++                  "Op", "Status", "CRID", "HID", "Callback");
++              TAILQ_FOREACH(krp, &crp_ret_kq, krp_next) {
++                      db_printf("%4u %5u %08x %4u %8p\n"
++                          , krp->krp_op
++                          , krp->krp_status
++                          , krp->krp_crid, krp->krp_hid
++                          , krp->krp_callback
++                      );
++              }
++      }
++}
++#endif
++
++
++static int
++crypto_init(void)
++{
++      int error;
++      unsigned long cpu;
++
++      dprintk("%s(%p)\n", __FUNCTION__, (void *) crypto_init);
++
++      if (crypto_initted)
++              return 0;
++      crypto_initted = 1;
++
++      spin_lock_init(&crypto_drivers_lock);
++      spin_lock_init(&crypto_q_lock);
++      spin_lock_init(&crypto_ret_q_lock);
++
++      cryptop_zone = kmem_cache_create("cryptop", sizeof(struct cryptop),
++                                     0, SLAB_HWCACHE_ALIGN, NULL
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
++                                     , NULL
++#endif
++                                      );
++
++      cryptodesc_zone = kmem_cache_create("cryptodesc", sizeof(struct cryptodesc),
++                                     0, SLAB_HWCACHE_ALIGN, NULL
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
++                                     , NULL
++#endif
++                                      );
++
++      if (cryptodesc_zone == NULL || cryptop_zone == NULL) {
++              printk("crypto: crypto_init cannot setup crypto zones\n");
++              error = ENOMEM;
++              goto bad;
++      }
++
++      crypto_drivers_num = CRYPTO_DRIVERS_INITIAL;
++      crypto_drivers = kmalloc(crypto_drivers_num * sizeof(struct cryptocap),
++                      GFP_KERNEL);
++      if (crypto_drivers == NULL) {
++              printk("crypto: crypto_init cannot setup crypto drivers\n");
++              error = ENOMEM;
++              goto bad;
++      }
++
++      memset(crypto_drivers, 0, crypto_drivers_num * sizeof(struct cryptocap));
++
++      ocf_for_each_cpu(cpu) {
++              cryptoproc[cpu] = kthread_create(crypto_proc, (void *) cpu,
++                                                                      "ocf_%d", (int) cpu);
++              if (IS_ERR(cryptoproc[cpu])) {
++                      error = PTR_ERR(cryptoproc[cpu]);
++                      printk("crypto: crypto_init cannot start crypto thread; error %d",
++                              error);
++                      goto bad;
++              }
++              kthread_bind(cryptoproc[cpu], cpu);
++              wake_up_process(cryptoproc[cpu]);
++
++              cryptoretproc[cpu] = kthread_create(crypto_ret_proc, (void *) cpu,
++                                                                      "ocf_ret_%d", (int) cpu);
++              if (IS_ERR(cryptoretproc[cpu])) {
++                      error = PTR_ERR(cryptoretproc[cpu]);
++                      printk("crypto: crypto_init cannot start cryptoret thread; error %d",
++                                      error);
++                      goto bad;
++              }
++              kthread_bind(cryptoretproc[cpu], cpu);
++              wake_up_process(cryptoretproc[cpu]);
++      }
++
++      return 0;
++bad:
++      crypto_exit();
++      return error;
++}
++
++
++static void
++crypto_exit(void)
++{
++      int cpu;
++
++      dprintk("%s()\n", __FUNCTION__);
++
++      /*
++       * Terminate any crypto threads.
++       */
++      ocf_for_each_cpu(cpu) {
++              kthread_stop(cryptoproc[cpu]);
++              kthread_stop(cryptoretproc[cpu]);
++      }
++
++      /*
++       * Reclaim dynamically allocated resources.
++       */
++      if (crypto_drivers != NULL)
++              kfree(crypto_drivers);
++
++      if (cryptodesc_zone != NULL)
++              kmem_cache_destroy(cryptodesc_zone);
++      if (cryptop_zone != NULL)
++              kmem_cache_destroy(cryptop_zone);
++}
++
++
++EXPORT_SYMBOL(crypto_newsession);
++EXPORT_SYMBOL(crypto_freesession);
++EXPORT_SYMBOL(crypto_get_driverid);
++EXPORT_SYMBOL(crypto_kregister);
++EXPORT_SYMBOL(crypto_register);
++EXPORT_SYMBOL(crypto_unregister);
++EXPORT_SYMBOL(crypto_unregister_all);
++EXPORT_SYMBOL(crypto_unblock);
++EXPORT_SYMBOL(crypto_dispatch);
++EXPORT_SYMBOL(crypto_kdispatch);
++EXPORT_SYMBOL(crypto_freereq);
++EXPORT_SYMBOL(crypto_getreq);
++EXPORT_SYMBOL(crypto_done);
++EXPORT_SYMBOL(crypto_kdone);
++EXPORT_SYMBOL(crypto_getfeat);
++EXPORT_SYMBOL(crypto_userasymcrypto);
++EXPORT_SYMBOL(crypto_getcaps);
++EXPORT_SYMBOL(crypto_find_driver);
++EXPORT_SYMBOL(crypto_find_device_byhid);
++
++module_init(crypto_init);
++module_exit(crypto_exit);
++
++MODULE_LICENSE("BSD");
++MODULE_AUTHOR("David McCullough <david_mccullough@mcafee.com>");
++MODULE_DESCRIPTION("OCF (OpenBSD Cryptographic Framework)");
+diff --git a/crypto/ocf/cryptodev.c b/crypto/ocf/cryptodev.c
+new file mode 100644
+index 0000000..2ee3618
+--- /dev/null
++++ b/crypto/ocf/cryptodev.c
+@@ -0,0 +1,1069 @@
++/*    $OpenBSD: cryptodev.c,v 1.52 2002/06/19 07:22:46 deraadt Exp $  */
++
++/*-
++ * Linux port done by David McCullough <david_mccullough@mcafee.com>
++ * Copyright (C) 2006-2010 David McCullough
++ * Copyright (C) 2004-2005 Intel Corporation.
++ * The license and original author are listed below.
++ *
++ * Copyright (c) 2001 Theo de Raadt
++ * Copyright (c) 2002-2006 Sam Leffler, Errno Consulting
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ *
++ * 1. Redistributions of source code must retain the above copyright
++ *   notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *   notice, this list of conditions and the following disclaimer in the
++ *   documentation and/or other materials provided with the distribution.
++ * 3. The name of the author may not be used to endorse or promote products
++ *   derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * Effort sponsored in part by the Defense Advanced Research Projects
++ * Agency (DARPA) and Air Force Research Laboratory, Air Force
++ * Materiel Command, USAF, under agreement number F30602-01-2-0537.
++ *
++__FBSDID("$FreeBSD: src/sys/opencrypto/cryptodev.c,v 1.34 2007/05/09 19:37:02 gnn Exp $");
++ */
++
++#include <linux/version.h>
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) && !defined(AUTOCONF_INCLUDED)
++#include <linux/config.h>
++#endif
++#include <linux/types.h>
++#include <linux/time.h>
++#include <linux/delay.h>
++#include <linux/list.h>
++#include <linux/init.h>
++#include <linux/sched.h>
++#include <linux/unistd.h>
++#include <linux/module.h>
++#include <linux/wait.h>
++#include <linux/slab.h>
++#include <linux/fs.h>
++#include <linux/dcache.h>
++#include <linux/file.h>
++#include <linux/mount.h>
++#include <linux/miscdevice.h>
++#include <asm/uaccess.h>
++
++#include <cryptodev.h>
++#include <uio.h>
++
++extern asmlinkage long sys_dup(unsigned int fildes);
++
++#define debug cryptodev_debug
++int cryptodev_debug = 0;
++module_param(cryptodev_debug, int, 0644);
++MODULE_PARM_DESC(cryptodev_debug, "Enable cryptodev debug");
++
++struct csession_info {
++      u_int16_t       blocksize;
++      u_int16_t       minkey, maxkey;
++
++      u_int16_t       keysize;
++      /* u_int16_t    hashsize;  */
++      u_int16_t       authsize;
++      u_int16_t       authkey;
++      /* u_int16_t    ctxsize; */
++};
++
++struct csession {
++      struct list_head        list;
++      u_int64_t       sid;
++      u_int32_t       ses;
++
++      wait_queue_head_t waitq;
++
++      u_int32_t       cipher;
++
++      u_int32_t       mac;
++
++      caddr_t         key;
++      int             keylen;
++      u_char          tmp_iv[EALG_MAX_BLOCK_LEN];
++
++      caddr_t         mackey;
++      int             mackeylen;
++
++      struct csession_info info;
++
++      struct iovec    iovec;
++      struct uio      uio;
++      int             error;
++};
++
++struct fcrypt {
++      struct list_head        csessions;
++      int             sesn;
++};
++
++static struct csession *csefind(struct fcrypt *, u_int);
++static int csedelete(struct fcrypt *, struct csession *);
++static struct csession *cseadd(struct fcrypt *, struct csession *);
++static struct csession *csecreate(struct fcrypt *, u_int64_t,
++              struct cryptoini *crie, struct cryptoini *cria, struct csession_info *);
++static int csefree(struct csession *);
++
++static        int cryptodev_op(struct csession *, struct crypt_op *);
++static        int cryptodev_key(struct crypt_kop *);
++static        int cryptodev_find(struct crypt_find_op *);
++
++static int cryptodev_cb(void *);
++static int cryptodev_open(struct inode *inode, struct file *filp);
++
++/*
++ * Check a crypto identifier to see if it requested
++ * a valid crid and it's capabilities match.
++ */
++static int
++checkcrid(int crid)
++{
++      int hid = crid & ~(CRYPTOCAP_F_SOFTWARE | CRYPTOCAP_F_HARDWARE);
++      int typ = crid & (CRYPTOCAP_F_SOFTWARE | CRYPTOCAP_F_HARDWARE);
++      int caps = 0;
++
++      /* if the user hasn't selected a driver, then just call newsession */
++      if (hid == 0 && typ != 0)
++              return 0;
++
++      caps = crypto_getcaps(hid);
++
++      /* didn't find anything with capabilities */
++      if (caps == 0) {
++              dprintk("%s: hid=%x typ=%x not matched\n", __FUNCTION__, hid, typ);
++              return EINVAL;
++      }
++
++      /* the user didn't specify SW or HW, so the driver is ok */
++      if (typ == 0)
++              return 0;
++
++      /* if the type specified didn't match */
++      if (typ != (caps & (CRYPTOCAP_F_SOFTWARE | CRYPTOCAP_F_HARDWARE))) {
++              dprintk("%s: hid=%x typ=%x caps=%x not matched\n", __FUNCTION__,
++                              hid, typ, caps);
++              return EINVAL;
++      }
++
++      return 0;
++}
++
++static int
++cryptodev_op(struct csession *cse, struct crypt_op *cop)
++{
++      struct cryptop *crp = NULL;
++      struct cryptodesc *crde = NULL, *crda = NULL;
++      int error = 0;
++
++      dprintk("%s()\n", __FUNCTION__);
++      if (cop->len > CRYPTO_MAX_DATA_LEN) {
++              dprintk("%s: %d > %d\n", __FUNCTION__, cop->len, CRYPTO_MAX_DATA_LEN);
++              return (E2BIG);
++      }
++
++      if (cse->info.blocksize && (cop->len % cse->info.blocksize) != 0) {
++              dprintk("%s: blocksize=%d len=%d\n", __FUNCTION__, cse->info.blocksize,
++                              cop->len);
++              return (EINVAL);
++      }
++
++      cse->uio.uio_iov = &cse->iovec;
++      cse->uio.uio_iovcnt = 1;
++      cse->uio.uio_offset = 0;
++#if 0
++      cse->uio.uio_resid = cop->len;
++      cse->uio.uio_segflg = UIO_SYSSPACE;
++      cse->uio.uio_rw = UIO_WRITE;
++      cse->uio.uio_td = td;
++#endif
++      cse->uio.uio_iov[0].iov_len = cop->len;
++      if (cse->info.authsize)
++              cse->uio.uio_iov[0].iov_len += cse->info.authsize;
++      cse->uio.uio_iov[0].iov_base = kmalloc(cse->uio.uio_iov[0].iov_len,
++                      GFP_KERNEL);
++
++      if (cse->uio.uio_iov[0].iov_base == NULL) {
++              dprintk("%s: iov_base kmalloc(%d) failed\n", __FUNCTION__,
++                              (int)cse->uio.uio_iov[0].iov_len);
++              return (ENOMEM);
++      }
++
++      crp = crypto_getreq((cse->info.blocksize != 0) + (cse->info.authsize != 0));
++      if (crp == NULL) {
++              dprintk("%s: ENOMEM\n", __FUNCTION__);
++              error = ENOMEM;
++              goto bail;
++      }
++
++      if (cse->info.authsize && cse->info.blocksize) {
++              if (cop->op == COP_ENCRYPT) {
++                      crde = crp->crp_desc;
++                      crda = crde->crd_next;
++              } else {
++                      crda = crp->crp_desc;
++                      crde = crda->crd_next;
++              }
++      } else if (cse->info.authsize) {
++              crda = crp->crp_desc;
++      } else if (cse->info.blocksize) {
++              crde = crp->crp_desc;
++      } else {
++              dprintk("%s: bad request\n", __FUNCTION__);
++              error = EINVAL;
++              goto bail;
++      }
++
++      if ((error = copy_from_user(cse->uio.uio_iov[0].iov_base, cop->src,
++                                      cop->len))) {
++              dprintk("%s: bad copy\n", __FUNCTION__);
++              goto bail;
++      }
++
++      if (crda) {
++              crda->crd_skip = 0;
++              crda->crd_len = cop->len;
++              crda->crd_inject = cop->len;
++
++              crda->crd_alg = cse->mac;
++              crda->crd_key = cse->mackey;
++              crda->crd_klen = cse->mackeylen * 8;
++      }
++
++      if (crde) {
++              if (cop->op == COP_ENCRYPT)
++                      crde->crd_flags |= CRD_F_ENCRYPT;
++              else
++                      crde->crd_flags &= ~CRD_F_ENCRYPT;
++              crde->crd_len = cop->len;
++              crde->crd_inject = 0;
++
++              crde->crd_alg = cse->cipher;
++              crde->crd_key = cse->key;
++              crde->crd_klen = cse->keylen * 8;
++      }
++
++      crp->crp_ilen = cse->uio.uio_iov[0].iov_len;
++      crp->crp_flags = CRYPTO_F_IOV | CRYPTO_F_CBIMM
++                     | (cop->flags & COP_F_BATCH);
++      crp->crp_buf = (caddr_t)&cse->uio;
++      crp->crp_callback = (int (*) (struct cryptop *)) cryptodev_cb;
++      crp->crp_sid = cse->sid;
++      crp->crp_opaque = (void *)cse;
++
++      if (cop->iv) {
++              if (crde == NULL) {
++                      error = EINVAL;
++                      dprintk("%s no crde\n", __FUNCTION__);
++                      goto bail;
++              }
++              if (cse->cipher == CRYPTO_ARC4) { /* XXX use flag? */
++                      error = EINVAL;
++                      dprintk("%s arc4 with IV\n", __FUNCTION__);
++                      goto bail;
++              }
++              if ((error = copy_from_user(cse->tmp_iv, cop->iv,
++                                              cse->info.blocksize))) {
++                      dprintk("%s bad iv copy\n", __FUNCTION__);
++                      goto bail;
++              }
++              memcpy(crde->crd_iv, cse->tmp_iv, cse->info.blocksize);
++              crde->crd_flags |= CRD_F_IV_EXPLICIT | CRD_F_IV_PRESENT;
++              crde->crd_skip = 0;
++      } else if (cse->cipher == CRYPTO_ARC4) { /* XXX use flag? */
++              crde->crd_skip = 0;
++      } else if (crde) {
++              crde->crd_flags |= CRD_F_IV_PRESENT;
++              crde->crd_skip = cse->info.blocksize;
++              crde->crd_len -= cse->info.blocksize;
++      }
++
++      if (cop->mac && crda == NULL) {
++              error = EINVAL;
++              dprintk("%s no crda\n", __FUNCTION__);
++              goto bail;
++      }
++
++      /*
++       * Let the dispatch run unlocked, then, interlock against the
++       * callback before checking if the operation completed and going
++       * to sleep.  This insures drivers don't inherit our lock which
++       * results in a lock order reversal between crypto_dispatch forced
++       * entry and the crypto_done callback into us.
++       */
++      error = crypto_dispatch(crp);
++      if (error) {
++              dprintk("%s error in crypto_dispatch\n", __FUNCTION__);
++              goto bail;
++      }
++
++      dprintk("%s about to WAIT\n", __FUNCTION__);
++      /*
++       * we really need to wait for driver to complete to maintain
++       * state,  luckily interrupts will be remembered
++       */
++      do {
++              error = wait_event_interruptible(crp->crp_waitq,
++                              ((crp->crp_flags & CRYPTO_F_DONE) != 0));
++              /*
++               * we can't break out of this loop or we will leave behind
++               * a huge mess,  however,  staying here means if your driver
++               * is broken user applications can hang and not be killed.
++               * The solution,  fix your driver :-)
++               */
++              if (error) {
++                      schedule();
++                      error = 0;
++              }
++      } while ((crp->crp_flags & CRYPTO_F_DONE) == 0);
++      dprintk("%s finished WAITING error=%d\n", __FUNCTION__, error);
++
++      if (crp->crp_etype != 0) {
++              error = crp->crp_etype;
++              dprintk("%s error in crp processing\n", __FUNCTION__);
++              goto bail;
++      }
++
++      if (cse->error) {
++              error = cse->error;
++              dprintk("%s error in cse processing\n", __FUNCTION__);
++              goto bail;
++      }
++
++      if (cop->dst && (error = copy_to_user(cop->dst,
++                                      cse->uio.uio_iov[0].iov_base, cop->len))) {
++              dprintk("%s bad dst copy\n", __FUNCTION__);
++              goto bail;
++      }
++
++      if (cop->mac &&
++                      (error=copy_to_user(cop->mac,
++                              (caddr_t)cse->uio.uio_iov[0].iov_base + cop->len,
++                              cse->info.authsize))) {
++              dprintk("%s bad mac copy\n", __FUNCTION__);
++              goto bail;
++      }
++
++bail:
++      if (crp)
++              crypto_freereq(crp);
++      if (cse->uio.uio_iov[0].iov_base)
++              kfree(cse->uio.uio_iov[0].iov_base);
++
++      return (error);
++}
++
++static int
++cryptodev_cb(void *op)
++{
++      struct cryptop *crp = (struct cryptop *) op;
++      struct csession *cse = (struct csession *)crp->crp_opaque;
++      int error;
++
++      dprintk("%s()\n", __FUNCTION__);
++      error = crp->crp_etype;
++      if (error == EAGAIN) {
++              crp->crp_flags &= ~CRYPTO_F_DONE;
++#ifdef NOTYET
++              /*
++               * DAVIDM I am fairly sure that we should turn this into a batch
++               * request to stop bad karma/lockup, revisit
++               */
++              crp->crp_flags |= CRYPTO_F_BATCH;
++#endif
++              return crypto_dispatch(crp);
++      }
++      if (error != 0 || (crp->crp_flags & CRYPTO_F_DONE)) {
++              cse->error = error;
++              wake_up_interruptible(&crp->crp_waitq);
++      }
++      return (0);
++}
++
++static int
++cryptodevkey_cb(void *op)
++{
++      struct cryptkop *krp = (struct cryptkop *) op;
++      dprintk("%s()\n", __FUNCTION__);
++      wake_up_interruptible(&krp->krp_waitq);
++      return (0);
++}
++
++static int
++cryptodev_key(struct crypt_kop *kop)
++{
++      struct cryptkop *krp = NULL;
++      int error = EINVAL;
++      int in, out, size, i;
++
++      dprintk("%s()\n", __FUNCTION__);
++      if (kop->crk_iparams + kop->crk_oparams > CRK_MAXPARAM) {
++              dprintk("%s params too big\n", __FUNCTION__);
++              return (EFBIG);
++      }
++
++      in = kop->crk_iparams;
++      out = kop->crk_oparams;
++      switch (kop->crk_op) {
++      case CRK_MOD_EXP:
++              if (in == 3 && out == 1)
++                      break;
++              return (EINVAL);
++      case CRK_MOD_EXP_CRT:
++              if (in == 6 && out == 1)
++                      break;
++              return (EINVAL);
++      case CRK_DSA_SIGN:
++              if (in == 5 && out == 2)
++                      break;
++              return (EINVAL);
++      case CRK_DSA_VERIFY:
++              if (in == 7 && out == 0)
++                      break;
++              return (EINVAL);
++      case CRK_DH_COMPUTE_KEY:
++              if (in == 3 && out == 1)
++                      break;
++              return (EINVAL);
++      default:
++              return (EINVAL);
++      }
++
++      krp = (struct cryptkop *)kmalloc(sizeof *krp, GFP_KERNEL);
++      if (!krp)
++              return (ENOMEM);
++      bzero(krp, sizeof *krp);
++      krp->krp_op = kop->crk_op;
++      krp->krp_status = kop->crk_status;
++      krp->krp_iparams = kop->crk_iparams;
++      krp->krp_oparams = kop->crk_oparams;
++      krp->krp_crid = kop->crk_crid;
++      krp->krp_status = 0;
++      krp->krp_flags = CRYPTO_KF_CBIMM;
++      krp->krp_callback = (int (*) (struct cryptkop *)) cryptodevkey_cb;
++      init_waitqueue_head(&krp->krp_waitq);
++
++      for (i = 0; i < CRK_MAXPARAM; i++)
++              krp->krp_param[i].crp_nbits = kop->crk_param[i].crp_nbits;
++      for (i = 0; i < krp->krp_iparams + krp->krp_oparams; i++) {
++              size = (krp->krp_param[i].crp_nbits + 7) / 8;
++              if (size == 0)
++                      continue;
++              krp->krp_param[i].crp_p = (caddr_t) kmalloc(size, GFP_KERNEL);
++              if (i >= krp->krp_iparams)
++                      continue;
++              error = copy_from_user(krp->krp_param[i].crp_p,
++                              kop->crk_param[i].crp_p, size);
++              if (error)
++                      goto fail;
++      }
++
++      error = crypto_kdispatch(krp);
++      if (error)
++              goto fail;
++
++      do {
++              error = wait_event_interruptible(krp->krp_waitq,
++                              ((krp->krp_flags & CRYPTO_KF_DONE) != 0));
++              /*
++               * we can't break out of this loop or we will leave behind
++               * a huge mess,  however,  staying here means if your driver
++               * is broken user applications can hang and not be killed.
++               * The solution,  fix your driver :-)
++               */
++              if (error) {
++                      schedule();
++                      error = 0;
++              }
++      } while ((krp->krp_flags & CRYPTO_KF_DONE) == 0);
++
++      dprintk("%s finished WAITING error=%d\n", __FUNCTION__, error);
++
++      kop->crk_crid = krp->krp_crid;          /* device that did the work */
++      if (krp->krp_status != 0) {
++              error = krp->krp_status;
++              goto fail;
++      }
++
++      for (i = krp->krp_iparams; i < krp->krp_iparams + krp->krp_oparams; i++) {
++              size = (krp->krp_param[i].crp_nbits + 7) / 8;
++              if (size == 0)
++                      continue;
++              error = copy_to_user(kop->crk_param[i].crp_p, krp->krp_param[i].crp_p,
++                              size);
++              if (error)
++                      goto fail;
++      }
++
++fail:
++      if (krp) {
++              kop->crk_status = krp->krp_status;
++              for (i = 0; i < CRK_MAXPARAM; i++) {
++                      if (krp->krp_param[i].crp_p)
++                              kfree(krp->krp_param[i].crp_p);
++              }
++              kfree(krp);
++      }
++      return (error);
++}
++
++static int
++cryptodev_find(struct crypt_find_op *find)
++{
++      device_t dev;
++
++      if (find->crid != -1) {
++              dev = crypto_find_device_byhid(find->crid);
++              if (dev == NULL)
++                      return (ENOENT);
++              strlcpy(find->name, device_get_nameunit(dev),
++                  sizeof(find->name));
++      } else {
++              find->crid = crypto_find_driver(find->name);
++              if (find->crid == -1)
++                      return (ENOENT);
++      }
++      return (0);
++}
++
++static struct csession *
++csefind(struct fcrypt *fcr, u_int ses)
++{
++      struct csession *cse;
++
++      dprintk("%s()\n", __FUNCTION__);
++      list_for_each_entry(cse, &fcr->csessions, list)
++              if (cse->ses == ses)
++                      return (cse);
++      return (NULL);
++}
++
++static int
++csedelete(struct fcrypt *fcr, struct csession *cse_del)
++{
++      struct csession *cse;
++
++      dprintk("%s()\n", __FUNCTION__);
++      list_for_each_entry(cse, &fcr->csessions, list) {
++              if (cse == cse_del) {
++                      list_del(&cse->list);
++                      return (1);
++              }
++      }
++      return (0);
++}
++
++static struct csession *
++cseadd(struct fcrypt *fcr, struct csession *cse)
++{
++      dprintk("%s()\n", __FUNCTION__);
++      list_add_tail(&cse->list, &fcr->csessions);
++      cse->ses = fcr->sesn++;
++      return (cse);
++}
++
++static struct csession *
++csecreate(struct fcrypt *fcr, u_int64_t sid, struct cryptoini *crie,
++      struct cryptoini *cria, struct csession_info *info)
++{
++      struct csession *cse;
++
++      dprintk("%s()\n", __FUNCTION__);
++      cse = (struct csession *) kmalloc(sizeof(struct csession), GFP_KERNEL);
++      if (cse == NULL)
++              return NULL;
++      memset(cse, 0, sizeof(struct csession));
++
++      INIT_LIST_HEAD(&cse->list);
++      init_waitqueue_head(&cse->waitq);
++
++      cse->key = crie->cri_key;
++      cse->keylen = crie->cri_klen/8;
++      cse->mackey = cria->cri_key;
++      cse->mackeylen = cria->cri_klen/8;
++      cse->sid = sid;
++      cse->cipher = crie->cri_alg;
++      cse->mac = cria->cri_alg;
++      cse->info = *info;
++      cseadd(fcr, cse);
++      return (cse);
++}
++
++static int
++csefree(struct csession *cse)
++{
++      int error;
++
++      dprintk("%s()\n", __FUNCTION__);
++      error = crypto_freesession(cse->sid);
++      if (cse->key)
++              kfree(cse->key);
++      if (cse->mackey)
++              kfree(cse->mackey);
++      kfree(cse);
++      return(error);
++}
++
++static int
++cryptodev_ioctl(
++      struct inode *inode,
++      struct file *filp,
++      unsigned int cmd,
++      unsigned long arg)
++{
++      struct cryptoini cria, crie;
++      struct fcrypt *fcr = filp->private_data;
++      struct csession *cse;
++      struct csession_info info;
++      struct session2_op sop;
++      struct crypt_op cop;
++      struct crypt_kop kop;
++      struct crypt_find_op fop;
++      u_int64_t sid;
++      u_int32_t ses = 0;
++      int feat, fd, error = 0, crid;
++      mm_segment_t fs;
++
++      dprintk("%s(cmd=%x arg=%lx)\n", __FUNCTION__, cmd, arg);
++
++      switch (cmd) {
++
++      case CRIOGET: {
++              dprintk("%s(CRIOGET)\n", __FUNCTION__);
++              fs = get_fs();
++              set_fs(get_ds());
++              for (fd = 0; fd < files_fdtable(current->files)->max_fds; fd++)
++                      if (files_fdtable(current->files)->fd[fd] == filp)
++                              break;
++              fd = sys_dup(fd);
++              set_fs(fs);
++              put_user(fd, (int *) arg);
++              return IS_ERR_VALUE(fd) ? fd : 0;
++              }
++
++#define       CIOCGSESSSTR    (cmd == CIOCGSESSION ? "CIOCGSESSION" : "CIOCGSESSION2")
++      case CIOCGSESSION:
++      case CIOCGSESSION2:
++              dprintk("%s(%s)\n", __FUNCTION__, CIOCGSESSSTR);
++              memset(&crie, 0, sizeof(crie));
++              memset(&cria, 0, sizeof(cria));
++              memset(&info, 0, sizeof(info));
++              memset(&sop, 0, sizeof(sop));
++
++              if (copy_from_user(&sop, (void*)arg, (cmd == CIOCGSESSION) ?
++                                      sizeof(struct session_op) : sizeof(sop))) {
++                      dprintk("%s(%s) - bad copy\n", __FUNCTION__, CIOCGSESSSTR);
++                      error = EFAULT;
++                      goto bail;
++              }
++
++              switch (sop.cipher) {
++              case 0:
++                      dprintk("%s(%s) - no cipher\n", __FUNCTION__, CIOCGSESSSTR);
++                      break;
++              case CRYPTO_NULL_CBC:
++                      info.blocksize = NULL_BLOCK_LEN;
++                      info.minkey = NULL_MIN_KEY_LEN;
++                      info.maxkey = NULL_MAX_KEY_LEN;
++                      break;
++              case CRYPTO_DES_CBC:
++                      info.blocksize = DES_BLOCK_LEN;
++                      info.minkey = DES_MIN_KEY_LEN;
++                      info.maxkey = DES_MAX_KEY_LEN;
++                      break;
++              case CRYPTO_3DES_CBC:
++                      info.blocksize = DES3_BLOCK_LEN;
++                      info.minkey = DES3_MIN_KEY_LEN;
++                      info.maxkey = DES3_MAX_KEY_LEN;
++                      break;
++              case CRYPTO_BLF_CBC:
++                      info.blocksize = BLOWFISH_BLOCK_LEN;
++                      info.minkey = BLOWFISH_MIN_KEY_LEN;
++                      info.maxkey = BLOWFISH_MAX_KEY_LEN;
++                      break;
++              case CRYPTO_CAST_CBC:
++                      info.blocksize = CAST128_BLOCK_LEN;
++                      info.minkey = CAST128_MIN_KEY_LEN;
++                      info.maxkey = CAST128_MAX_KEY_LEN;
++                      break;
++              case CRYPTO_SKIPJACK_CBC:
++                      info.blocksize = SKIPJACK_BLOCK_LEN;
++                      info.minkey = SKIPJACK_MIN_KEY_LEN;
++                      info.maxkey = SKIPJACK_MAX_KEY_LEN;
++                      break;
++              case CRYPTO_AES_CBC:
++                      info.blocksize = AES_BLOCK_LEN;
++                      info.minkey = AES_MIN_KEY_LEN;
++                      info.maxkey = AES_MAX_KEY_LEN;
++                      break;
++              case CRYPTO_ARC4:
++                      info.blocksize = ARC4_BLOCK_LEN;
++                      info.minkey = ARC4_MIN_KEY_LEN;
++                      info.maxkey = ARC4_MAX_KEY_LEN;
++                      break;
++              case CRYPTO_CAMELLIA_CBC:
++                      info.blocksize = CAMELLIA_BLOCK_LEN;
++                      info.minkey = CAMELLIA_MIN_KEY_LEN;
++                      info.maxkey = CAMELLIA_MAX_KEY_LEN;
++                      break;
++              default:
++                      dprintk("%s(%s) - bad cipher\n", __FUNCTION__, CIOCGSESSSTR);
++                      error = EINVAL;
++                      goto bail;
++              }
++
++              switch (sop.mac) {
++              case 0:
++                      dprintk("%s(%s) - no mac\n", __FUNCTION__, CIOCGSESSSTR);
++                      break;
++              case CRYPTO_NULL_HMAC:
++                      info.authsize = NULL_HASH_LEN;
++                      break;
++              case CRYPTO_MD5:
++                      info.authsize = MD5_HASH_LEN;
++                      break;
++              case CRYPTO_SHA1:
++                      info.authsize = SHA1_HASH_LEN;
++                      break;
++              case CRYPTO_SHA2_256:
++                      info.authsize = SHA2_256_HASH_LEN;
++                      break;
++              case CRYPTO_SHA2_384:
++                      info.authsize = SHA2_384_HASH_LEN;
++                      break;
++              case CRYPTO_SHA2_512:
++                      info.authsize = SHA2_512_HASH_LEN;
++                      break;
++              case CRYPTO_RIPEMD160:
++                      info.authsize = RIPEMD160_HASH_LEN;
++                      break;
++              case CRYPTO_MD5_HMAC:
++                      info.authsize = MD5_HASH_LEN;
++                      info.authkey = 16;
++                      break;
++              case CRYPTO_SHA1_HMAC:
++                      info.authsize = SHA1_HASH_LEN;
++                      info.authkey = 20;
++                      break;
++              case CRYPTO_SHA2_256_HMAC:
++                      info.authsize = SHA2_256_HASH_LEN;
++                      info.authkey = 32;
++                      break;
++              case CRYPTO_SHA2_384_HMAC:
++                      info.authsize = SHA2_384_HASH_LEN;
++                      info.authkey = 48;
++                      break;
++              case CRYPTO_SHA2_512_HMAC:
++                      info.authsize = SHA2_512_HASH_LEN;
++                      info.authkey = 64;
++                      break;
++              case CRYPTO_RIPEMD160_HMAC:
++                      info.authsize = RIPEMD160_HASH_LEN;
++                      info.authkey = 20;
++                      break;
++              default:
++                      dprintk("%s(%s) - bad mac\n", __FUNCTION__, CIOCGSESSSTR);
++                      error = EINVAL;
++                      goto bail;
++              }
++
++              if (info.blocksize) {
++                      crie.cri_alg = sop.cipher;
++                      crie.cri_klen = sop.keylen * 8;
++                      if ((info.maxkey && sop.keylen > info.maxkey) ||
++                                      sop.keylen < info.minkey) {
++                              dprintk("%s(%s) - bad key\n", __FUNCTION__, CIOCGSESSSTR);
++                              error = EINVAL;
++                              goto bail;
++                      }
++
++                      crie.cri_key = (u_int8_t *) kmalloc(crie.cri_klen/8+1, GFP_KERNEL);
++                      if (copy_from_user(crie.cri_key, sop.key,
++                                                      crie.cri_klen/8)) {
++                              dprintk("%s(%s) - bad copy\n", __FUNCTION__, CIOCGSESSSTR);
++                              error = EFAULT;
++                              goto bail;
++                      }
++                      if (info.authsize)
++                              crie.cri_next = &cria;
++              }
++
++              if (info.authsize) {
++                      cria.cri_alg = sop.mac;
++                      cria.cri_klen = sop.mackeylen * 8;
++                      if (info.authkey && sop.mackeylen != info.authkey) {
++                              dprintk("%s(%s) - mackeylen %d != %d\n", __FUNCTION__,
++                                              CIOCGSESSSTR, sop.mackeylen, info.authkey);
++                              error = EINVAL;
++                              goto bail;
++                      }
++
++                      if (cria.cri_klen) {
++                              cria.cri_key = (u_int8_t *) kmalloc(cria.cri_klen/8,GFP_KERNEL);
++                              if (copy_from_user(cria.cri_key, sop.mackey,
++                                                              cria.cri_klen / 8)) {
++                                      dprintk("%s(%s) - bad copy\n", __FUNCTION__, CIOCGSESSSTR);
++                                      error = EFAULT;
++                                      goto bail;
++                              }
++                      }
++              }
++
++              /* NB: CIOGSESSION2 has the crid */
++              if (cmd == CIOCGSESSION2) {
++                      crid = sop.crid;
++                      error = checkcrid(crid);
++                      if (error) {
++                              dprintk("%s(%s) - checkcrid %x\n", __FUNCTION__,
++                                              CIOCGSESSSTR, error);
++                              goto bail;
++                      }
++              } else {
++                      /* allow either HW or SW to be used */
++                      crid = CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SOFTWARE;
++              }
++              error = crypto_newsession(&sid, (info.blocksize ? &crie : &cria), crid);
++              if (error) {
++                      dprintk("%s(%s) - newsession %d\n",__FUNCTION__,CIOCGSESSSTR,error);
++                      goto bail;
++              }
++
++              cse = csecreate(fcr, sid, &crie, &cria, &info);
++              if (cse == NULL) {
++                      crypto_freesession(sid);
++                      error = EINVAL;
++                      dprintk("%s(%s) - csecreate failed\n", __FUNCTION__, CIOCGSESSSTR);
++                      goto bail;
++              }
++              sop.ses = cse->ses;
++
++              if (cmd == CIOCGSESSION2) {
++                      /* return hardware/driver id */
++                      sop.crid = CRYPTO_SESID2HID(cse->sid);
++              }
++
++              if (copy_to_user((void*)arg, &sop, (cmd == CIOCGSESSION) ?
++                                      sizeof(struct session_op) : sizeof(sop))) {
++                      dprintk("%s(%s) - bad copy\n", __FUNCTION__, CIOCGSESSSTR);
++                      error = EFAULT;
++              }
++bail:
++              if (error) {
++                      dprintk("%s(%s) - bail %d\n", __FUNCTION__, CIOCGSESSSTR, error);
++                      if (crie.cri_key)
++                              kfree(crie.cri_key);
++                      if (cria.cri_key)
++                              kfree(cria.cri_key);
++              }
++              break;
++      case CIOCFSESSION:
++              dprintk("%s(CIOCFSESSION)\n", __FUNCTION__);
++              get_user(ses, (uint32_t*)arg);
++              cse = csefind(fcr, ses);
++              if (cse == NULL) {
++                      error = EINVAL;
++                      dprintk("%s(CIOCFSESSION) - Fail %d\n", __FUNCTION__, error);
++                      break;
++              }
++              csedelete(fcr, cse);
++              error = csefree(cse);
++              break;
++      case CIOCCRYPT:
++              dprintk("%s(CIOCCRYPT)\n", __FUNCTION__);
++              if(copy_from_user(&cop, (void*)arg, sizeof(cop))) {
++                      dprintk("%s(CIOCCRYPT) - bad copy\n", __FUNCTION__);
++                      error = EFAULT;
++                      goto bail;
++              }
++              cse = csefind(fcr, cop.ses);
++              if (cse == NULL) {
++                      error = EINVAL;
++                      dprintk("%s(CIOCCRYPT) - Fail %d\n", __FUNCTION__, error);
++                      break;
++              }
++              error = cryptodev_op(cse, &cop);
++              if(copy_to_user((void*)arg, &cop, sizeof(cop))) {
++                      dprintk("%s(CIOCCRYPT) - bad return copy\n", __FUNCTION__);
++                      error = EFAULT;
++                      goto bail;
++              }
++              break;
++      case CIOCKEY:
++      case CIOCKEY2:
++              dprintk("%s(CIOCKEY)\n", __FUNCTION__);
++              if (!crypto_userasymcrypto)
++                      return (EPERM);         /* XXX compat? */
++              if(copy_from_user(&kop, (void*)arg, sizeof(kop))) {
++                      dprintk("%s(CIOCKEY) - bad copy\n", __FUNCTION__);
++                      error = EFAULT;
++                      goto bail;
++              }
++              if (cmd == CIOCKEY) {
++                      /* NB: crypto core enforces s/w driver use */
++                      kop.crk_crid =
++                          CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SOFTWARE;
++              }
++              error = cryptodev_key(&kop);
++              if(copy_to_user((void*)arg, &kop, sizeof(kop))) {
++                      dprintk("%s(CIOCGKEY) - bad return copy\n", __FUNCTION__);
++                      error = EFAULT;
++                      goto bail;
++              }
++              break;
++      case CIOCASYMFEAT:
++              dprintk("%s(CIOCASYMFEAT)\n", __FUNCTION__);
++              if (!crypto_userasymcrypto) {
++                      /*
++                       * NB: if user asym crypto operations are
++                       * not permitted return "no algorithms"
++                       * so well-behaved applications will just
++                       * fallback to doing them in software.
++                       */
++                      feat = 0;
++              } else
++                      error = crypto_getfeat(&feat);
++              if (!error) {
++                error = copy_to_user((void*)arg, &feat, sizeof(feat));
++              }
++              break;
++      case CIOCFINDDEV:
++              if (copy_from_user(&fop, (void*)arg, sizeof(fop))) {
++                      dprintk("%s(CIOCFINDDEV) - bad copy\n", __FUNCTION__);
++                      error = EFAULT;
++                      goto bail;
++              }
++              error = cryptodev_find(&fop);
++              if (copy_to_user((void*)arg, &fop, sizeof(fop))) {
++                      dprintk("%s(CIOCFINDDEV) - bad return copy\n", __FUNCTION__);
++                      error = EFAULT;
++                      goto bail;
++              }
++              break;
++      default:
++              dprintk("%s(unknown ioctl 0x%x)\n", __FUNCTION__, cmd);
++              error = EINVAL;
++              break;
++      }
++      return(-error);
++}
++
++#ifdef HAVE_UNLOCKED_IOCTL
++static long
++cryptodev_unlocked_ioctl(
++      struct file *filp,
++      unsigned int cmd,
++      unsigned long arg)
++{
++      return cryptodev_ioctl(NULL, filp, cmd, arg);
++}
++#endif
++
++static int
++cryptodev_open(struct inode *inode, struct file *filp)
++{
++      struct fcrypt *fcr;
++
++      dprintk("%s()\n", __FUNCTION__);
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35)
++      /*
++       * on 2.6.35 private_data points to a miscdevice structure, we override
++       * it,  which is currently safe to do.
++       */
++      if (filp->private_data) {
++              printk("cryptodev: Private data already exists - %p!\n", filp->private_data);
++              return(-ENODEV);
++      }
++#endif
++
++      fcr = kmalloc(sizeof(*fcr), GFP_KERNEL);
++      if (!fcr) {
++              dprintk("%s() - malloc failed\n", __FUNCTION__);
++              return(-ENOMEM);
++      }
++      memset(fcr, 0, sizeof(*fcr));
++
++      INIT_LIST_HEAD(&fcr->csessions);
++      filp->private_data = fcr;
++      return(0);
++}
++
++static int
++cryptodev_release(struct inode *inode, struct file *filp)
++{
++      struct fcrypt *fcr = filp->private_data;
++      struct csession *cse, *tmp;
++
++      dprintk("%s()\n", __FUNCTION__);
++      if (!filp) {
++              printk("cryptodev: No private data on release\n");
++              return(0);
++      }
++
++      list_for_each_entry_safe(cse, tmp, &fcr->csessions, list) {
++              list_del(&cse->list);
++              (void)csefree(cse);
++      }
++      filp->private_data = NULL;
++      kfree(fcr);
++      return(0);
++}
++
++static struct file_operations cryptodev_fops = {
++      .owner = THIS_MODULE,
++      .open = cryptodev_open,
++      .release = cryptodev_release,
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36)
++      .ioctl = cryptodev_ioctl,
++#endif
++#ifdef HAVE_UNLOCKED_IOCTL
++      .unlocked_ioctl = cryptodev_unlocked_ioctl,
++#endif
++};
++
++static struct miscdevice cryptodev = {
++      .minor = CRYPTODEV_MINOR,
++      .name = "crypto",
++      .fops = &cryptodev_fops,
++};
++
++static int __init
++cryptodev_init(void)
++{
++      int rc;
++
++      dprintk("%s(%p)\n", __FUNCTION__, cryptodev_init);
++      rc = misc_register(&cryptodev);
++      if (rc) {
++              printk(KERN_ERR "cryptodev: registration of /dev/crypto failed\n");
++              return(rc);
++      }
++
++      return(0);
++}
++
++static void __exit
++cryptodev_exit(void)
++{
++      dprintk("%s()\n", __FUNCTION__);
++      misc_deregister(&cryptodev);
++}
++
++module_init(cryptodev_init);
++module_exit(cryptodev_exit);
++
++MODULE_LICENSE("BSD");
++MODULE_AUTHOR("David McCullough <david_mccullough@mcafee.com>");
++MODULE_DESCRIPTION("Cryptodev (user interface to OCF)");
+diff --git a/crypto/ocf/cryptodev.h b/crypto/ocf/cryptodev.h
+new file mode 100644
+index 0000000..cca0ec8
+--- /dev/null
++++ b/crypto/ocf/cryptodev.h
+@@ -0,0 +1,480 @@
++/*    $FreeBSD: src/sys/opencrypto/cryptodev.h,v 1.25 2007/05/09 19:37:02 gnn Exp $   */
++/*    $OpenBSD: cryptodev.h,v 1.31 2002/06/11 11:14:29 beck Exp $     */
++
++/*-
++ * Linux port done by David McCullough <david_mccullough@mcafee.com>
++ * Copyright (C) 2006-2010 David McCullough
++ * Copyright (C) 2004-2005 Intel Corporation.
++ * The license and original author are listed below.
++ *
++ * The author of this code is Angelos D. Keromytis (angelos@cis.upenn.edu)
++ * Copyright (c) 2002-2006 Sam Leffler, Errno Consulting
++ *
++ * This code was written by Angelos D. Keromytis in Athens, Greece, in
++ * February 2000. Network Security Technologies Inc. (NSTI) kindly
++ * supported the development of this code.
++ *
++ * Copyright (c) 2000 Angelos D. Keromytis
++ *
++ * Permission to use, copy, and modify this software with or without fee
++ * is hereby granted, provided that this entire notice is included in
++ * all source code copies of any software which is or includes a copy or
++ * modification of this software.
++ *
++ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
++ * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
++ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
++ * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
++ * PURPOSE.
++ *
++ * Copyright (c) 2001 Theo de Raadt
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ *
++ * 1. Redistributions of source code must retain the above copyright
++ *   notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *   notice, this list of conditions and the following disclaimer in the
++ *   documentation and/or other materials provided with the distribution.
++ * 3. The name of the author may not be used to endorse or promote products
++ *   derived from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * Effort sponsored in part by the Defense Advanced Research Projects
++ * Agency (DARPA) and Air Force Research Laboratory, Air Force
++ * Materiel Command, USAF, under agreement number F30602-01-2-0537.
++ *
++ */
++
++#ifndef _CRYPTO_CRYPTO_H_
++#define _CRYPTO_CRYPTO_H_
++
++/* Some initial values */
++#define CRYPTO_DRIVERS_INITIAL        4
++#define CRYPTO_SW_SESSIONS    32
++
++/* Hash values */
++#define NULL_HASH_LEN         0
++#define MD5_HASH_LEN          16
++#define SHA1_HASH_LEN         20
++#define RIPEMD160_HASH_LEN    20
++#define SHA2_256_HASH_LEN     32
++#define SHA2_384_HASH_LEN     48
++#define SHA2_512_HASH_LEN     64
++#define MD5_KPDK_HASH_LEN     16
++#define SHA1_KPDK_HASH_LEN    20
++/* Maximum hash algorithm result length */
++#define HASH_MAX_LEN          SHA2_512_HASH_LEN /* Keep this updated */
++
++/* HMAC values */
++#define NULL_HMAC_BLOCK_LEN                   1
++#define MD5_HMAC_BLOCK_LEN                    64
++#define SHA1_HMAC_BLOCK_LEN                   64
++#define RIPEMD160_HMAC_BLOCK_LEN      64
++#define SHA2_256_HMAC_BLOCK_LEN               64
++#define SHA2_384_HMAC_BLOCK_LEN               128
++#define SHA2_512_HMAC_BLOCK_LEN               128
++/* Maximum HMAC block length */
++#define HMAC_MAX_BLOCK_LEN            SHA2_512_HMAC_BLOCK_LEN /* Keep this updated */
++#define HMAC_IPAD_VAL                 0x36
++#define HMAC_OPAD_VAL                 0x5C
++
++/* Encryption algorithm block sizes */
++#define NULL_BLOCK_LEN                        1
++#define DES_BLOCK_LEN                 8
++#define DES3_BLOCK_LEN                        8
++#define BLOWFISH_BLOCK_LEN            8
++#define SKIPJACK_BLOCK_LEN            8
++#define CAST128_BLOCK_LEN             8
++#define RIJNDAEL128_BLOCK_LEN 16
++#define AES_BLOCK_LEN                 RIJNDAEL128_BLOCK_LEN
++#define CAMELLIA_BLOCK_LEN            16
++#define ARC4_BLOCK_LEN                        1
++#define EALG_MAX_BLOCK_LEN            AES_BLOCK_LEN /* Keep this updated */
++
++/* Encryption algorithm min and max key sizes */
++#define NULL_MIN_KEY_LEN              0
++#define NULL_MAX_KEY_LEN              0
++#define DES_MIN_KEY_LEN                       8
++#define DES_MAX_KEY_LEN                       8
++#define DES3_MIN_KEY_LEN              24
++#define DES3_MAX_KEY_LEN              24
++#define BLOWFISH_MIN_KEY_LEN  4
++#define BLOWFISH_MAX_KEY_LEN  56
++#define SKIPJACK_MIN_KEY_LEN  10
++#define SKIPJACK_MAX_KEY_LEN  10
++#define CAST128_MIN_KEY_LEN           5
++#define CAST128_MAX_KEY_LEN           16
++#define RIJNDAEL128_MIN_KEY_LEN       16
++#define RIJNDAEL128_MAX_KEY_LEN       32
++#define AES_MIN_KEY_LEN                       RIJNDAEL128_MIN_KEY_LEN
++#define AES_MAX_KEY_LEN                       RIJNDAEL128_MAX_KEY_LEN
++#define CAMELLIA_MIN_KEY_LEN  16
++#define CAMELLIA_MAX_KEY_LEN  32
++#define ARC4_MIN_KEY_LEN              1
++#define ARC4_MAX_KEY_LEN              256
++
++/* Max size of data that can be processed */
++#define CRYPTO_MAX_DATA_LEN           64*1024 - 1
++
++#define CRYPTO_ALGORITHM_MIN  1
++#define CRYPTO_DES_CBC                        1
++#define CRYPTO_3DES_CBC                       2
++#define CRYPTO_BLF_CBC                        3
++#define CRYPTO_CAST_CBC                       4
++#define CRYPTO_SKIPJACK_CBC           5
++#define CRYPTO_MD5_HMAC                       6
++#define CRYPTO_SHA1_HMAC              7
++#define CRYPTO_RIPEMD160_HMAC 8
++#define CRYPTO_MD5_KPDK                       9
++#define CRYPTO_SHA1_KPDK              10
++#define CRYPTO_RIJNDAEL128_CBC        11 /* 128 bit blocksize */
++#define CRYPTO_AES_CBC                        11 /* 128 bit blocksize -- the same as above */
++#define CRYPTO_ARC4                           12
++#define CRYPTO_MD5                            13
++#define CRYPTO_SHA1                           14
++#define CRYPTO_NULL_HMAC              15
++#define CRYPTO_NULL_CBC                       16
++#define CRYPTO_DEFLATE_COMP           17 /* Deflate compression algorithm */
++#define CRYPTO_SHA2_256_HMAC  18
++#define CRYPTO_SHA2_384_HMAC  19
++#define CRYPTO_SHA2_512_HMAC  20
++#define CRYPTO_CAMELLIA_CBC           21
++#define CRYPTO_SHA2_256                       22
++#define CRYPTO_SHA2_384                       23
++#define CRYPTO_SHA2_512                       24
++#define CRYPTO_RIPEMD160              25
++#define       CRYPTO_LZS_COMP                 26
++#define CRYPTO_ALGORITHM_MAX  26 /* Keep updated - see above */
++
++/* Algorithm flags */
++#define CRYPTO_ALG_FLAG_SUPPORTED     0x01 /* Algorithm is supported */
++#define CRYPTO_ALG_FLAG_RNG_ENABLE    0x02 /* Has HW RNG for DH/DSA */
++#define CRYPTO_ALG_FLAG_DSA_SHA               0x04 /* Can do SHA on msg */
++
++/*
++ * Crypto driver/device flags.  They can set in the crid
++ * parameter when creating a session or submitting a key
++ * op to affect the device/driver assigned.  If neither
++ * of these are specified then the crid is assumed to hold
++ * the driver id of an existing (and suitable) device that
++ * must be used to satisfy the request.
++ */
++#define CRYPTO_FLAG_HARDWARE  0x01000000      /* hardware accelerated */
++#define CRYPTO_FLAG_SOFTWARE  0x02000000      /* software implementation */
++
++/* NB: deprecated */
++struct session_op {
++      u_int32_t       cipher;         /* ie. CRYPTO_DES_CBC */
++      u_int32_t       mac;            /* ie. CRYPTO_MD5_HMAC */
++
++      u_int32_t       keylen;         /* cipher key */
++      caddr_t         key;
++      int             mackeylen;      /* mac key */
++      caddr_t         mackey;
++
++      u_int32_t       ses;            /* returns: session # */
++};
++
++struct session2_op {
++      u_int32_t       cipher;         /* ie. CRYPTO_DES_CBC */
++      u_int32_t       mac;            /* ie. CRYPTO_MD5_HMAC */
++
++      u_int32_t       keylen;         /* cipher key */
++      caddr_t         key;
++      int             mackeylen;      /* mac key */
++      caddr_t         mackey;
++
++      u_int32_t       ses;            /* returns: session # */
++      int             crid;           /* driver id + flags (rw) */
++      int             pad[4];         /* for future expansion */
++};
++
++struct crypt_op {
++      u_int32_t       ses;
++      u_int16_t       op;             /* i.e. COP_ENCRYPT */
++#define COP_NONE      0
++#define COP_ENCRYPT   1
++#define COP_DECRYPT   2
++      u_int16_t       flags;
++#define       COP_F_BATCH     0x0008          /* Batch op if possible */
++      u_int           len;
++      caddr_t         src, dst;       /* become iov[] inside kernel */
++      caddr_t         mac;            /* must be big enough for chosen MAC */
++      caddr_t         iv;
++};
++
++/*
++ * Parameters for looking up a crypto driver/device by
++ * device name or by id.  The latter are returned for
++ * created sessions (crid) and completed key operations.
++ */
++struct crypt_find_op {
++      int             crid;           /* driver id + flags */
++      char            name[32];       /* device/driver name */
++};
++
++/* bignum parameter, in packed bytes, ... */
++struct crparam {
++      caddr_t         crp_p;
++      u_int           crp_nbits;
++};
++
++#define CRK_MAXPARAM  8
++
++struct crypt_kop {
++      u_int           crk_op;         /* ie. CRK_MOD_EXP or other */
++      u_int           crk_status;     /* return status */
++      u_short         crk_iparams;    /* # of input parameters */
++      u_short         crk_oparams;    /* # of output parameters */
++      u_int           crk_crid;       /* NB: only used by CIOCKEY2 (rw) */
++      struct crparam  crk_param[CRK_MAXPARAM];
++};
++#define CRK_ALGORITM_MIN      0
++#define CRK_MOD_EXP           0
++#define CRK_MOD_EXP_CRT               1
++#define CRK_DSA_SIGN          2
++#define CRK_DSA_VERIFY                3
++#define CRK_DH_COMPUTE_KEY    4
++#define CRK_ALGORITHM_MAX     4 /* Keep updated - see below */
++
++#define CRF_MOD_EXP           (1 << CRK_MOD_EXP)
++#define CRF_MOD_EXP_CRT               (1 << CRK_MOD_EXP_CRT)
++#define CRF_DSA_SIGN          (1 << CRK_DSA_SIGN)
++#define CRF_DSA_VERIFY                (1 << CRK_DSA_VERIFY)
++#define CRF_DH_COMPUTE_KEY    (1 << CRK_DH_COMPUTE_KEY)
++
++/*
++ * done against open of /dev/crypto, to get a cloned descriptor.
++ * Please use F_SETFD against the cloned descriptor.
++ */
++#define CRIOGET               _IOWR('c', 100, u_int32_t)
++#define CRIOASYMFEAT  CIOCASYMFEAT
++#define CRIOFINDDEV   CIOCFINDDEV
++
++/* the following are done against the cloned descriptor */
++#define CIOCGSESSION  _IOWR('c', 101, struct session_op)
++#define CIOCFSESSION  _IOW('c', 102, u_int32_t)
++#define CIOCCRYPT     _IOWR('c', 103, struct crypt_op)
++#define CIOCKEY               _IOWR('c', 104, struct crypt_kop)
++#define CIOCASYMFEAT  _IOR('c', 105, u_int32_t)
++#define CIOCGSESSION2 _IOWR('c', 106, struct session2_op)
++#define CIOCKEY2      _IOWR('c', 107, struct crypt_kop)
++#define CIOCFINDDEV   _IOWR('c', 108, struct crypt_find_op)
++
++struct cryptotstat {
++      struct timespec acc;            /* total accumulated time */
++      struct timespec min;            /* min time */
++      struct timespec max;            /* max time */
++      u_int32_t       count;          /* number of observations */
++};
++
++struct cryptostats {
++      u_int32_t       cs_ops;         /* symmetric crypto ops submitted */
++      u_int32_t       cs_errs;        /* symmetric crypto ops that failed */
++      u_int32_t       cs_kops;        /* asymetric/key ops submitted */
++      u_int32_t       cs_kerrs;       /* asymetric/key ops that failed */
++      u_int32_t       cs_intrs;       /* crypto swi thread activations */
++      u_int32_t       cs_rets;        /* crypto return thread activations */
++      u_int32_t       cs_blocks;      /* symmetric op driver block */
++      u_int32_t       cs_kblocks;     /* symmetric op driver block */
++      /*
++       * When CRYPTO_TIMING is defined at compile time and the
++       * sysctl debug.crypto is set to 1, the crypto system will
++       * accumulate statistics about how long it takes to process
++       * crypto requests at various points during processing.
++       */
++      struct cryptotstat cs_invoke;   /* crypto_dipsatch -> crypto_invoke */
++      struct cryptotstat cs_done;     /* crypto_invoke -> crypto_done */
++      struct cryptotstat cs_cb;       /* crypto_done -> callback */
++      struct cryptotstat cs_finis;    /* callback -> callback return */
++
++      u_int32_t       cs_drops;               /* crypto ops dropped due to congestion */
++};
++
++#ifdef __KERNEL__
++
++/* Standard initialization structure beginning */
++struct cryptoini {
++      int             cri_alg;        /* Algorithm to use */
++      int             cri_klen;       /* Key length, in bits */
++      int             cri_mlen;       /* Number of bytes we want from the
++                                         entire hash. 0 means all. */
++      caddr_t         cri_key;        /* key to use */
++      u_int8_t        cri_iv[EALG_MAX_BLOCK_LEN];     /* IV to use */
++      struct cryptoini *cri_next;
++};
++
++/* Describe boundaries of a single crypto operation */
++struct cryptodesc {
++      int             crd_skip;       /* How many bytes to ignore from start */
++      int             crd_len;        /* How many bytes to process */
++      int             crd_inject;     /* Where to inject results, if applicable */
++      int             crd_flags;
++
++#define CRD_F_ENCRYPT         0x01    /* Set when doing encryption */
++#define CRD_F_IV_PRESENT      0x02    /* When encrypting, IV is already in
++                                         place, so don't copy. */
++#define CRD_F_IV_EXPLICIT     0x04    /* IV explicitly provided */
++#define CRD_F_DSA_SHA_NEEDED  0x08    /* Compute SHA-1 of buffer for DSA */
++#define CRD_F_KEY_EXPLICIT    0x10    /* Key explicitly provided */
++#define CRD_F_COMP            0x0f    /* Set when doing compression */
++
++      struct cryptoini        CRD_INI; /* Initialization/context data */
++#define crd_iv                CRD_INI.cri_iv
++#define crd_key               CRD_INI.cri_key
++#define crd_alg               CRD_INI.cri_alg
++#define crd_klen      CRD_INI.cri_klen
++#define crd_mlen      CRD_INI.cri_mlen
++
++      struct cryptodesc *crd_next;
++};
++
++/* Structure describing complete operation */
++struct cryptop {
++      struct list_head crp_next;
++      wait_queue_head_t crp_waitq;
++
++      u_int64_t       crp_sid;        /* Session ID */
++      int             crp_ilen;       /* Input data total length */
++      int             crp_olen;       /* Result total length */
++
++      int             crp_etype;      /*
++                                       * Error type (zero means no error).
++                                       * All error codes except EAGAIN
++                                       * indicate possible data corruption (as in,
++                                       * the data have been touched). On all
++                                       * errors, the crp_sid may have changed
++                                       * (reset to a new one), so the caller
++                                       * should always check and use the new
++                                       * value on future requests.
++                                       */
++      int             crp_flags;
++
++#define CRYPTO_F_SKBUF                0x0001  /* Input/output are skbuf chains */
++#define CRYPTO_F_IOV          0x0002  /* Input/output are uio */
++#define CRYPTO_F_REL          0x0004  /* Must return data in same place */
++#define CRYPTO_F_BATCH                0x0008  /* Batch op if possible */
++#define CRYPTO_F_CBIMM                0x0010  /* Do callback immediately */
++#define CRYPTO_F_DONE         0x0020  /* Operation completed */
++#define CRYPTO_F_CBIFSYNC     0x0040  /* Do CBIMM if op is synchronous */
++
++      caddr_t         crp_buf;        /* Data to be processed */
++      caddr_t         crp_opaque;     /* Opaque pointer, passed along */
++      struct cryptodesc *crp_desc;    /* Linked list of processing descriptors */
++
++      int (*crp_callback)(struct cryptop *); /* Callback function */
++};
++
++#define CRYPTO_BUF_CONTIG     0x0
++#define CRYPTO_BUF_IOV                0x1
++#define CRYPTO_BUF_SKBUF              0x2
++
++#define CRYPTO_OP_DECRYPT     0x0
++#define CRYPTO_OP_ENCRYPT     0x1
++
++/*
++ * Hints passed to process methods.
++ */
++#define CRYPTO_HINT_MORE      0x1     /* more ops coming shortly */
++
++struct cryptkop {
++      struct list_head krp_next;
++      wait_queue_head_t krp_waitq;
++
++      int             krp_flags;
++#define CRYPTO_KF_DONE                0x0001  /* Operation completed */
++#define CRYPTO_KF_CBIMM               0x0002  /* Do callback immediately */
++
++      u_int           krp_op;         /* ie. CRK_MOD_EXP or other */
++      u_int           krp_status;     /* return status */
++      u_short         krp_iparams;    /* # of input parameters */
++      u_short         krp_oparams;    /* # of output parameters */
++      u_int           krp_crid;       /* desired device, etc. */
++      u_int32_t       krp_hid;
++      struct crparam  krp_param[CRK_MAXPARAM];        /* kvm */
++      int             (*krp_callback)(struct cryptkop *);
++};
++
++#include <ocf-compat.h>
++
++/*
++ * Session ids are 64 bits.  The lower 32 bits contain a "local id" which
++ * is a driver-private session identifier.  The upper 32 bits contain a
++ * "hardware id" used by the core crypto code to identify the driver and
++ * a copy of the driver's capabilities that can be used by client code to
++ * optimize operation.
++ */
++#define CRYPTO_SESID2HID(_sid)        (((_sid) >> 32) & 0x00ffffff)
++#define CRYPTO_SESID2CAPS(_sid)       (((_sid) >> 32) & 0xff000000)
++#define CRYPTO_SESID2LID(_sid)        (((u_int32_t) (_sid)) & 0xffffffff)
++
++extern        int crypto_newsession(u_int64_t *sid, struct cryptoini *cri, int hard);
++extern        int crypto_freesession(u_int64_t sid);
++#define CRYPTOCAP_F_HARDWARE  CRYPTO_FLAG_HARDWARE
++#define CRYPTOCAP_F_SOFTWARE  CRYPTO_FLAG_SOFTWARE
++#define CRYPTOCAP_F_SYNC      0x04000000      /* operates synchronously */
++extern        int32_t crypto_get_driverid(device_t dev, int flags);
++extern        int crypto_find_driver(const char *);
++extern        device_t crypto_find_device_byhid(int hid);
++extern        int crypto_getcaps(int hid);
++extern        int crypto_register(u_int32_t driverid, int alg, u_int16_t maxoplen,
++          u_int32_t flags);
++extern        int crypto_kregister(u_int32_t, int, u_int32_t);
++extern        int crypto_unregister(u_int32_t driverid, int alg);
++extern        int crypto_unregister_all(u_int32_t driverid);
++extern        int crypto_dispatch(struct cryptop *crp);
++extern        int crypto_kdispatch(struct cryptkop *);
++#define CRYPTO_SYMQ   0x1
++#define CRYPTO_ASYMQ  0x2
++extern        int crypto_unblock(u_int32_t, int);
++extern        void crypto_done(struct cryptop *crp);
++extern        void crypto_kdone(struct cryptkop *);
++extern        int crypto_getfeat(int *);
++
++extern        void crypto_freereq(struct cryptop *crp);
++extern        struct cryptop *crypto_getreq(int num);
++
++extern  int crypto_usercrypto;      /* userland may do crypto requests */
++extern  int crypto_userasymcrypto;  /* userland may do asym crypto reqs */
++extern  int crypto_devallowsoft;    /* only use hardware crypto */
++
++/*
++ * random number support,  crypto_unregister_all will unregister
++ */
++extern int crypto_rregister(u_int32_t driverid,
++              int (*read_random)(void *arg, u_int32_t *buf, int len), void *arg);
++extern int crypto_runregister_all(u_int32_t driverid);
++
++/*
++ * Crypto-related utility routines used mainly by drivers.
++ *
++ * XXX these don't really belong here; but for now they're
++ *     kept apart from the rest of the system.
++ */
++struct uio;
++extern        void cuio_copydata(struct uio* uio, int off, int len, caddr_t cp);
++extern        void cuio_copyback(struct uio* uio, int off, int len, caddr_t cp);
++extern        struct iovec *cuio_getptr(struct uio *uio, int loc, int *off);
++
++extern        void crypto_copyback(int flags, caddr_t buf, int off, int size,
++          caddr_t in);
++extern        void crypto_copydata(int flags, caddr_t buf, int off, int size,
++          caddr_t out);
++extern        int crypto_apply(int flags, caddr_t buf, int off, int len,
++          int (*f)(void *, void *, u_int), void *arg);
++
++#endif /* __KERNEL__ */
++#endif /* _CRYPTO_CRYPTO_H_ */
+diff --git a/crypto/ocf/cryptosoft.c b/crypto/ocf/cryptosoft.c
+new file mode 100644
+index 0000000..aa2383d
+--- /dev/null
++++ b/crypto/ocf/cryptosoft.c
+@@ -0,0 +1,1322 @@
++/*
++ * An OCF module that uses the linux kernel cryptoapi, based on the
++ * original cryptosoft for BSD by Angelos D. Keromytis (angelos@cis.upenn.edu)
++ * but is mostly unrecognisable,
++ *
++ * Written by David McCullough <david_mccullough@mcafee.com>
++ * Copyright (C) 2004-2011 David McCullough
++ * Copyright (C) 2004-2005 Intel Corporation.
++ *
++ * LICENSE TERMS
++ *
++ * The free distribution and use of this software in both source and binary
++ * form is allowed (with or without changes) provided that:
++ *
++ *   1. distributions of this source code include the above copyright
++ *      notice, this list of conditions and the following disclaimer;
++ *
++ *   2. distributions in binary form include the above copyright
++ *      notice, this list of conditions and the following disclaimer
++ *      in the documentation and/or other associated materials;
++ *
++ *   3. the copyright holder's name is not used to endorse products
++ *      built using this software without specific written permission.
++ *
++ * ALTERNATIVELY, provided that this notice is retained in full, this product
++ * may be distributed under the terms of the GNU General Public License (GPL),
++ * in which case the provisions of the GPL apply INSTEAD OF those given above.
++ *
++ * DISCLAIMER
++ *
++ * This software is provided 'as is' with no explicit or implied warranties
++ * in respect of its properties, including, but not limited to, correctness
++ * and/or fitness for purpose.
++ * ---------------------------------------------------------------------------
++ */
++
++#include <linux/version.h>
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) && !defined(AUTOCONF_INCLUDED)
++#include <linux/config.h>
++#endif
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/list.h>
++#include <linux/slab.h>
++#include <linux/sched.h>
++#include <linux/wait.h>
++#include <linux/crypto.h>
++#include <linux/mm.h>
++#include <linux/skbuff.h>
++#include <linux/random.h>
++#include <linux/interrupt.h>
++#include <linux/spinlock.h>
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,10)
++#include <linux/scatterlist.h>
++#endif
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)
++#include <crypto/hash.h>
++#endif
++
++#include <cryptodev.h>
++#include <uio.h>
++
++struct {
++      softc_device_decl       sc_dev;
++} swcr_softc;
++
++#define offset_in_page(p) ((unsigned long)(p) & ~PAGE_MASK)
++
++#define SW_TYPE_CIPHER                0x01
++#define SW_TYPE_HMAC          0x02
++#define SW_TYPE_HASH          0x04
++#define SW_TYPE_COMP          0x08
++#define SW_TYPE_BLKCIPHER     0x10
++#define SW_TYPE_ALG_MASK      0x1f
++
++#define SW_TYPE_ASYNC         0x8000
++
++#define SW_TYPE_INUSE         0x10000000
++
++/* We change some of the above if we have an async interface */
++
++#define SW_TYPE_ALG_AMASK     (SW_TYPE_ALG_MASK | SW_TYPE_ASYNC)
++
++#define SW_TYPE_ABLKCIPHER    (SW_TYPE_BLKCIPHER | SW_TYPE_ASYNC)
++#define SW_TYPE_AHASH         (SW_TYPE_HASH | SW_TYPE_ASYNC)
++#define SW_TYPE_AHMAC         (SW_TYPE_HMAC | SW_TYPE_ASYNC)
++
++#define SCATTERLIST_MAX 16
++
++struct swcr_data {
++      struct work_struct  workq;
++      int                                     sw_type;
++      int                                     sw_alg;
++      struct crypto_tfm       *sw_tfm;
++      spinlock_t                      sw_tfm_lock;
++      union {
++              struct {
++                      char *sw_key;
++                      int  sw_klen;
++                      int  sw_mlen;
++              } hmac;
++              void *sw_comp_buf;
++      } u;
++      struct swcr_data        *sw_next;
++};
++
++struct swcr_req {
++      struct swcr_data        *sw_head;
++      struct swcr_data        *sw;
++      struct cryptop          *crp;
++      struct cryptodesc       *crd;
++      struct scatterlist       sg[SCATTERLIST_MAX];
++      unsigned char            iv[EALG_MAX_BLOCK_LEN];
++      char                             result[HASH_MAX_LEN];
++      void                            *crypto_req;
++};
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
++static kmem_cache_t *swcr_req_cache;
++#else
++static struct kmem_cache *swcr_req_cache;
++#endif
++
++#ifndef CRYPTO_TFM_MODE_CBC
++/*
++ * As of linux-2.6.21 this is no longer defined, and presumably no longer
++ * needed to be passed into the crypto core code.
++ */
++#define       CRYPTO_TFM_MODE_CBC     0
++#define       CRYPTO_TFM_MODE_ECB     0
++#endif
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
++      /*
++       * Linux 2.6.19 introduced a new Crypto API, setup macro's to convert new
++       * API into old API.
++       */
++
++      /* Symmetric/Block Cipher */
++      struct blkcipher_desc
++      {
++              struct crypto_tfm *tfm;
++              void *info;
++      };
++      #define ecb(X)                                                          #X , CRYPTO_TFM_MODE_ECB
++      #define cbc(X)                                                          #X , CRYPTO_TFM_MODE_CBC
++      #define crypto_has_blkcipher(X, Y, Z)           crypto_alg_available(X, 0)
++      #define crypto_blkcipher_cast(X)                        X
++      #define crypto_blkcipher_tfm(X)                         X
++      #define crypto_alloc_blkcipher(X, Y, Z)         crypto_alloc_tfm(X, mode)
++      #define crypto_blkcipher_ivsize(X)                      crypto_tfm_alg_ivsize(X)
++      #define crypto_blkcipher_blocksize(X)           crypto_tfm_alg_blocksize(X)
++      #define crypto_blkcipher_setkey(X, Y, Z)        crypto_cipher_setkey(X, Y, Z)
++      #define crypto_blkcipher_encrypt_iv(W, X, Y, Z) \
++                              crypto_cipher_encrypt_iv((W)->tfm, X, Y, Z, (u8 *)((W)->info))
++      #define crypto_blkcipher_decrypt_iv(W, X, Y, Z) \
++                              crypto_cipher_decrypt_iv((W)->tfm, X, Y, Z, (u8 *)((W)->info))
++      #define crypto_blkcipher_set_flags(x, y)        /* nop */
++      #define crypto_free_blkcipher(x)                        crypto_free_tfm(x)
++      #define crypto_free_comp                                        crypto_free_tfm
++      #define crypto_free_hash                                        crypto_free_tfm
++
++      /* Hash/HMAC/Digest */
++      struct hash_desc
++      {
++              struct crypto_tfm *tfm;
++      };
++      #define hmac(X)                                                 #X , 0
++      #define crypto_has_hash(X, Y, Z)                crypto_alg_available(X, 0)
++      #define crypto_hash_cast(X)                             X
++      #define crypto_hash_tfm(X)                              X
++      #define crypto_alloc_hash(X, Y, Z)              crypto_alloc_tfm(X, mode)
++      #define crypto_hash_digestsize(X)               crypto_tfm_alg_digestsize(X)
++      #define crypto_hash_digest(W, X, Y, Z)  \
++                              crypto_digest_digest((W)->tfm, X, sg_num, Z)
++
++      /* Asymmetric Cipher */
++      #define crypto_has_cipher(X, Y, Z)              crypto_alg_available(X, 0)
++
++      /* Compression */
++      #define crypto_has_comp(X, Y, Z)                crypto_alg_available(X, 0)
++      #define crypto_comp_tfm(X)                              X
++      #define crypto_comp_cast(X)                             X
++      #define crypto_alloc_comp(X, Y, Z)              crypto_alloc_tfm(X, mode)
++      #define plain(X)        #X , 0
++#else
++      #define ecb(X)  "ecb(" #X ")" , 0
++      #define cbc(X)  "cbc(" #X ")" , 0
++      #define hmac(X) "hmac(" #X ")" , 0
++      #define plain(X)        #X , 0
++#endif /* if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) */
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
++/* no ablkcipher in older kernels */
++#define crypto_alloc_ablkcipher(a,b,c)                (NULL)
++#define crypto_ablkcipher_tfm(x)                      ((struct crypto_tfm *)(x))
++#define crypto_ablkcipher_set_flags(a, b)     /* nop */
++#define crypto_ablkcipher_setkey(x, y, z)     (-EINVAL)
++#define       crypto_has_ablkcipher(a,b,c)            (0)
++#else
++#define       HAVE_ABLKCIPHER
++#endif
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32)
++/* no ahash in older kernels */
++#define crypto_ahash_tfm(x)                                   ((struct crypto_tfm *)(x))
++#define       crypto_alloc_ahash(a,b,c)                       (NULL)
++#define       crypto_ahash_digestsize(x)                      0
++#else
++#define       HAVE_AHASH
++#endif
++
++struct crypto_details {
++      char *alg_name;
++      int mode;
++      int sw_type;
++};
++
++static struct crypto_details crypto_details[] = {
++      [CRYPTO_DES_CBC]         = { cbc(des),          SW_TYPE_BLKCIPHER, },
++      [CRYPTO_3DES_CBC]        = { cbc(des3_ede),     SW_TYPE_BLKCIPHER, },
++      [CRYPTO_BLF_CBC]         = { cbc(blowfish),     SW_TYPE_BLKCIPHER, },
++      [CRYPTO_CAST_CBC]        = { cbc(cast5),        SW_TYPE_BLKCIPHER, },
++      [CRYPTO_SKIPJACK_CBC]    = { cbc(skipjack),     SW_TYPE_BLKCIPHER, },
++      [CRYPTO_MD5_HMAC]        = { hmac(md5),         SW_TYPE_HMAC, },
++      [CRYPTO_SHA1_HMAC]       = { hmac(sha1),        SW_TYPE_HMAC, },
++      [CRYPTO_RIPEMD160_HMAC]  = { hmac(ripemd160),   SW_TYPE_HMAC, },
++      [CRYPTO_MD5_KPDK]        = { plain(md5-kpdk),   SW_TYPE_HASH, },
++      [CRYPTO_SHA1_KPDK]       = { plain(sha1-kpdk),  SW_TYPE_HASH, },
++      [CRYPTO_AES_CBC]         = { cbc(aes),          SW_TYPE_BLKCIPHER, },
++      [CRYPTO_ARC4]            = { ecb(arc4),         SW_TYPE_BLKCIPHER, },
++      [CRYPTO_MD5]             = { plain(md5),        SW_TYPE_HASH, },
++      [CRYPTO_SHA1]            = { plain(sha1),       SW_TYPE_HASH, },
++      [CRYPTO_NULL_HMAC]       = { hmac(digest_null), SW_TYPE_HMAC, },
++      [CRYPTO_NULL_CBC]        = { cbc(cipher_null),  SW_TYPE_BLKCIPHER, },
++      [CRYPTO_DEFLATE_COMP]    = { plain(deflate),    SW_TYPE_COMP, },
++      [CRYPTO_SHA2_256_HMAC]   = { hmac(sha256),      SW_TYPE_HMAC, },
++      [CRYPTO_SHA2_384_HMAC]   = { hmac(sha384),      SW_TYPE_HMAC, },
++      [CRYPTO_SHA2_512_HMAC]   = { hmac(sha512),      SW_TYPE_HMAC, },
++      [CRYPTO_CAMELLIA_CBC]    = { cbc(camellia),     SW_TYPE_BLKCIPHER, },
++      [CRYPTO_SHA2_256]        = { plain(sha256),     SW_TYPE_HASH, },
++      [CRYPTO_SHA2_384]        = { plain(sha384),     SW_TYPE_HASH, },
++      [CRYPTO_SHA2_512]        = { plain(sha512),     SW_TYPE_HASH, },
++      [CRYPTO_RIPEMD160]       = { plain(ripemd160),  SW_TYPE_HASH, },
++};
++
++int32_t swcr_id = -1;
++module_param(swcr_id, int, 0444);
++MODULE_PARM_DESC(swcr_id, "Read-Only OCF ID for cryptosoft driver");
++
++int swcr_fail_if_compression_grows = 1;
++module_param(swcr_fail_if_compression_grows, int, 0644);
++MODULE_PARM_DESC(swcr_fail_if_compression_grows,
++                "Treat compression that results in more data as a failure");
++
++int swcr_no_ahash = 0;
++module_param(swcr_no_ahash, int, 0644);
++MODULE_PARM_DESC(swcr_no_ahash,
++                "Do not use async hash/hmac even if available");
++
++int swcr_no_ablk = 0;
++module_param(swcr_no_ablk, int, 0644);
++MODULE_PARM_DESC(swcr_no_ablk,
++                "Do not use async blk ciphers even if available");
++
++static struct swcr_data **swcr_sessions = NULL;
++static u_int32_t swcr_sesnum = 0;
++
++static        int swcr_process(device_t, struct cryptop *, int);
++static        int swcr_newsession(device_t, u_int32_t *, struct cryptoini *);
++static        int swcr_freesession(device_t, u_int64_t);
++
++static device_method_t swcr_methods = {
++      /* crypto device methods */
++      DEVMETHOD(cryptodev_newsession, swcr_newsession),
++      DEVMETHOD(cryptodev_freesession,swcr_freesession),
++      DEVMETHOD(cryptodev_process,    swcr_process),
++};
++
++#define debug swcr_debug
++int swcr_debug = 0;
++module_param(swcr_debug, int, 0644);
++MODULE_PARM_DESC(swcr_debug, "Enable debug");
++
++static void swcr_process_req(struct swcr_req *req);
++
++/*
++ * somethings just need to be run with user context no matter whether
++ * the kernel compression libs use vmalloc/vfree for example.
++ */
++
++typedef struct {
++      struct work_struct wq;
++      void    (*func)(void *arg);
++      void    *arg;
++} execute_later_t;
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
++static void
++doing_it_now(struct work_struct *wq)
++{
++      execute_later_t *w = container_of(wq, execute_later_t, wq);
++      (w->func)(w->arg);
++      kfree(w);
++}
++#else
++static void
++doing_it_now(void *arg)
++{
++      execute_later_t *w = (execute_later_t *) arg;
++      (w->func)(w->arg);
++      kfree(w);
++}
++#endif
++
++static void
++execute_later(void (fn)(void *), void *arg)
++{
++      execute_later_t *w;
++
++      w = (execute_later_t *) kmalloc(sizeof(execute_later_t), SLAB_ATOMIC);
++      if (w) {
++              memset(w, '\0', sizeof(w));
++              w->func = fn;
++              w->arg = arg;
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
++              INIT_WORK(&w->wq, doing_it_now);
++#else
++              INIT_WORK(&w->wq, doing_it_now, w);
++#endif
++              schedule_work(&w->wq);
++      }
++}
++
++/*
++ * Generate a new software session.
++ */
++static int
++swcr_newsession(device_t dev, u_int32_t *sid, struct cryptoini *cri)
++{
++      struct swcr_data **swd;
++      u_int32_t i;
++      int error;
++      char *algo;
++      int mode;
++
++      dprintk("%s()\n", __FUNCTION__);
++      if (sid == NULL || cri == NULL) {
++              dprintk("%s,%d - EINVAL\n", __FILE__, __LINE__);
++              return EINVAL;
++      }
++
++      if (swcr_sessions) {
++              for (i = 1; i < swcr_sesnum; i++)
++                      if (swcr_sessions[i] == NULL)
++                              break;
++      } else
++              i = 1;          /* NB: to silence compiler warning */
++
++      if (swcr_sessions == NULL || i == swcr_sesnum) {
++              if (swcr_sessions == NULL) {
++                      i = 1; /* We leave swcr_sessions[0] empty */
++                      swcr_sesnum = CRYPTO_SW_SESSIONS;
++              } else
++                      swcr_sesnum *= 2;
++
++              swd = kmalloc(swcr_sesnum * sizeof(struct swcr_data *), SLAB_ATOMIC);
++              if (swd == NULL) {
++                      /* Reset session number */
++                      if (swcr_sesnum == CRYPTO_SW_SESSIONS)
++                              swcr_sesnum = 0;
++                      else
++                              swcr_sesnum /= 2;
++                      dprintk("%s,%d: ENOBUFS\n", __FILE__, __LINE__);
++                      return ENOBUFS;
++              }
++              memset(swd, 0, swcr_sesnum * sizeof(struct swcr_data *));
++
++              /* Copy existing sessions */
++              if (swcr_sessions) {
++                      memcpy(swd, swcr_sessions,
++                          (swcr_sesnum / 2) * sizeof(struct swcr_data *));
++                      kfree(swcr_sessions);
++              }
++
++              swcr_sessions = swd;
++      }
++
++      swd = &swcr_sessions[i];
++      *sid = i;
++
++      while (cri) {
++              *swd = (struct swcr_data *) kmalloc(sizeof(struct swcr_data),
++                              SLAB_ATOMIC);
++              if (*swd == NULL) {
++                      swcr_freesession(NULL, i);
++                      dprintk("%s,%d: ENOBUFS\n", __FILE__, __LINE__);
++                      return ENOBUFS;
++              }
++              memset(*swd, 0, sizeof(struct swcr_data));
++
++              if (cri->cri_alg < 0 ||
++                              cri->cri_alg>=sizeof(crypto_details)/sizeof(crypto_details[0])){
++                      printk("cryptosoft: Unknown algorithm 0x%x\n", cri->cri_alg);
++                      swcr_freesession(NULL, i);
++                      return EINVAL;
++              }
++
++              algo = crypto_details[cri->cri_alg].alg_name;
++              if (!algo || !*algo) {
++                      printk("cryptosoft: Unsupported algorithm 0x%x\n", cri->cri_alg);
++                      swcr_freesession(NULL, i);
++                      return EINVAL;
++              }
++
++              mode = crypto_details[cri->cri_alg].mode;
++              (*swd)->sw_type = crypto_details[cri->cri_alg].sw_type;
++              (*swd)->sw_alg = cri->cri_alg;
++
++              spin_lock_init(&(*swd)->sw_tfm_lock);
++
++              /* Algorithm specific configuration */
++              switch (cri->cri_alg) {
++              case CRYPTO_NULL_CBC:
++                      cri->cri_klen = 0; /* make it work with crypto API */
++                      break;
++              default:
++                      break;
++              }
++
++              if ((*swd)->sw_type & SW_TYPE_BLKCIPHER) {
++                      dprintk("%s crypto_alloc_*blkcipher(%s, 0x%x)\n", __FUNCTION__,
++                                      algo, mode);
++
++                      /* try async first */
++                      (*swd)->sw_tfm = swcr_no_ablk ? NULL :
++                                      crypto_ablkcipher_tfm(crypto_alloc_ablkcipher(algo, 0, 0));
++                      if ((*swd)->sw_tfm && !IS_ERR((*swd)->sw_tfm)) {
++                              dprintk("%s %s cipher is async\n", __FUNCTION__, algo);
++                              (*swd)->sw_type |= SW_TYPE_ASYNC;
++                      } else {
++                              (*swd)->sw_tfm = crypto_blkcipher_tfm(
++                                              crypto_alloc_blkcipher(algo, 0, CRYPTO_ALG_ASYNC));
++                              if ((*swd)->sw_tfm && !IS_ERR((*swd)->sw_tfm))
++                                      dprintk("%s %s cipher is sync\n", __FUNCTION__, algo);
++                      }
++                      if (!(*swd)->sw_tfm || IS_ERR((*swd)->sw_tfm)) {
++                              int err;
++                              dprintk("cryptosoft: crypto_alloc_blkcipher failed(%s, 0x%x)\n",
++                                              algo,mode);
++                              err = IS_ERR((*swd)->sw_tfm) ? -(PTR_ERR((*swd)->sw_tfm)) : EINVAL;
++                              (*swd)->sw_tfm = NULL; /* ensure NULL */
++                              swcr_freesession(NULL, i);
++                              return err;
++                      }
++
++                      if (debug) {
++                              dprintk("%s key:cri->cri_klen=%d,(cri->cri_klen + 7)/8=%d",
++                                              __FUNCTION__, cri->cri_klen, (cri->cri_klen + 7) / 8);
++                              for (i = 0; i < (cri->cri_klen + 7) / 8; i++)
++                                      dprintk("%s0x%x", (i % 8) ? " " : "\n    ",
++                                                      cri->cri_key[i] & 0xff);
++                              dprintk("\n");
++                      }
++                      if ((*swd)->sw_type & SW_TYPE_ASYNC) {
++                              /* OCF doesn't enforce keys */
++                              crypto_ablkcipher_set_flags(
++                                              __crypto_ablkcipher_cast((*swd)->sw_tfm),
++                                                      CRYPTO_TFM_REQ_WEAK_KEY);
++                              error = crypto_ablkcipher_setkey(
++                                                      __crypto_ablkcipher_cast((*swd)->sw_tfm),
++                                                              cri->cri_key, (cri->cri_klen + 7) / 8);
++                      } else {
++                              /* OCF doesn't enforce keys */
++                              crypto_blkcipher_set_flags(
++                                              crypto_blkcipher_cast((*swd)->sw_tfm),
++                                                      CRYPTO_TFM_REQ_WEAK_KEY);
++                              error = crypto_blkcipher_setkey(
++                                                      crypto_blkcipher_cast((*swd)->sw_tfm),
++                                                              cri->cri_key, (cri->cri_klen + 7) / 8);
++                      }
++                      if (error) {
++                              printk("cryptosoft: setkey failed %d (crt_flags=0x%x)\n", error,
++                                              (*swd)->sw_tfm->crt_flags);
++                              swcr_freesession(NULL, i);
++                              return error;
++                      }
++              } else if ((*swd)->sw_type & (SW_TYPE_HMAC | SW_TYPE_HASH)) {
++                      dprintk("%s crypto_alloc_*hash(%s, 0x%x)\n", __FUNCTION__,
++                                      algo, mode);
++
++                      /* try async first */
++                      (*swd)->sw_tfm = swcr_no_ahash ? NULL :
++                                      crypto_ahash_tfm(crypto_alloc_ahash(algo, 0, 0));
++                      if ((*swd)->sw_tfm) {
++                              dprintk("%s %s hash is async\n", __FUNCTION__, algo);
++                              (*swd)->sw_type |= SW_TYPE_ASYNC;
++                      } else {
++                              dprintk("%s %s hash is sync\n", __FUNCTION__, algo);
++                              (*swd)->sw_tfm = crypto_hash_tfm(
++                                              crypto_alloc_hash(algo, 0, CRYPTO_ALG_ASYNC));
++                      }
++
++                      if (!(*swd)->sw_tfm) {
++                              dprintk("cryptosoft: crypto_alloc_hash failed(%s,0x%x)\n",
++                                              algo, mode);
++                              swcr_freesession(NULL, i);
++                              return EINVAL;
++                      }
++
++                      (*swd)->u.hmac.sw_klen = (cri->cri_klen + 7) / 8;
++                      (*swd)->u.hmac.sw_key = (char *)kmalloc((*swd)->u.hmac.sw_klen,
++                                      SLAB_ATOMIC);
++                      if ((*swd)->u.hmac.sw_key == NULL) {
++                              swcr_freesession(NULL, i);
++                              dprintk("%s,%d: ENOBUFS\n", __FILE__, __LINE__);
++                              return ENOBUFS;
++                      }
++                      memcpy((*swd)->u.hmac.sw_key, cri->cri_key, (*swd)->u.hmac.sw_klen);
++                      if (cri->cri_mlen) {
++                              (*swd)->u.hmac.sw_mlen = cri->cri_mlen;
++                      } else if ((*swd)->sw_type & SW_TYPE_ASYNC) {
++                              (*swd)->u.hmac.sw_mlen = crypto_ahash_digestsize(
++                                              __crypto_ahash_cast((*swd)->sw_tfm));
++                      } else  {
++                              (*swd)->u.hmac.sw_mlen = crypto_hash_digestsize(
++                                              crypto_hash_cast((*swd)->sw_tfm));
++                      }
++              } else if ((*swd)->sw_type & SW_TYPE_COMP) {
++                      (*swd)->sw_tfm = crypto_comp_tfm(
++                                      crypto_alloc_comp(algo, 0, CRYPTO_ALG_ASYNC));
++                      if (!(*swd)->sw_tfm) {
++                              dprintk("cryptosoft: crypto_alloc_comp failed(%s,0x%x)\n",
++                                              algo, mode);
++                              swcr_freesession(NULL, i);
++                              return EINVAL;
++                      }
++                      (*swd)->u.sw_comp_buf = kmalloc(CRYPTO_MAX_DATA_LEN, SLAB_ATOMIC);
++                      if ((*swd)->u.sw_comp_buf == NULL) {
++                              swcr_freesession(NULL, i);
++                              dprintk("%s,%d: ENOBUFS\n", __FILE__, __LINE__);
++                              return ENOBUFS;
++                      }
++              } else {
++                      printk("cryptosoft: Unhandled sw_type %d\n", (*swd)->sw_type);
++                      swcr_freesession(NULL, i);
++                      return EINVAL;
++              }
++
++              cri = cri->cri_next;
++              swd = &((*swd)->sw_next);
++      }
++      return 0;
++}
++
++/*
++ * Free a session.
++ */
++static int
++swcr_freesession(device_t dev, u_int64_t tid)
++{
++      struct swcr_data *swd;
++      u_int32_t sid = CRYPTO_SESID2LID(tid);
++
++      dprintk("%s()\n", __FUNCTION__);
++      if (sid > swcr_sesnum || swcr_sessions == NULL ||
++                      swcr_sessions[sid] == NULL) {
++              dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__);
++              return(EINVAL);
++      }
++
++      /* Silently accept and return */
++      if (sid == 0)
++              return(0);
++
++      while ((swd = swcr_sessions[sid]) != NULL) {
++              swcr_sessions[sid] = swd->sw_next;
++              if (swd->sw_tfm) {
++                      switch (swd->sw_type & SW_TYPE_ALG_AMASK) {
++#ifdef HAVE_AHASH
++                      case SW_TYPE_AHMAC:
++                      case SW_TYPE_AHASH:
++                              crypto_free_ahash(__crypto_ahash_cast(swd->sw_tfm));
++                              break;
++#endif
++#ifdef HAVE_ABLKCIPHER
++                      case SW_TYPE_ABLKCIPHER:
++                              crypto_free_ablkcipher(__crypto_ablkcipher_cast(swd->sw_tfm));
++                              break;
++#endif
++                      case SW_TYPE_BLKCIPHER:
++                              crypto_free_blkcipher(crypto_blkcipher_cast(swd->sw_tfm));
++                              break;
++                      case SW_TYPE_HMAC:
++                      case SW_TYPE_HASH:
++                              crypto_free_hash(crypto_hash_cast(swd->sw_tfm));
++                              break;
++                      case SW_TYPE_COMP:
++                              if (in_interrupt())
++                                      execute_later((void (*)(void *))crypto_free_comp, (void *)crypto_comp_cast(swd->sw_tfm));
++                              else
++                                      crypto_free_comp(crypto_comp_cast(swd->sw_tfm));
++                              break;
++                      default:
++                              crypto_free_tfm(swd->sw_tfm);
++                              break;
++                      }
++                      swd->sw_tfm = NULL;
++              }
++              if (swd->sw_type & SW_TYPE_COMP) {
++                      if (swd->u.sw_comp_buf)
++                              kfree(swd->u.sw_comp_buf);
++              } else {
++                      if (swd->u.hmac.sw_key)
++                              kfree(swd->u.hmac.sw_key);
++              }
++              kfree(swd);
++      }
++      return 0;
++}
++
++static void swcr_process_req_complete(struct swcr_req *req)
++{
++      dprintk("%s()\n", __FUNCTION__);
++
++      if (req->sw->sw_type & SW_TYPE_INUSE) {
++              unsigned long flags;
++              spin_lock_irqsave(&req->sw->sw_tfm_lock, flags);
++              req->sw->sw_type &= ~SW_TYPE_INUSE;
++              spin_unlock_irqrestore(&req->sw->sw_tfm_lock, flags);
++      }
++
++      if (req->crp->crp_etype)
++              goto done;
++
++      switch (req->sw->sw_type & SW_TYPE_ALG_AMASK) {
++#if defined(HAVE_AHASH)
++      case SW_TYPE_AHMAC:
++      case SW_TYPE_AHASH:
++              crypto_copyback(req->crp->crp_flags, req->crp->crp_buf,
++                              req->crd->crd_inject, req->sw->u.hmac.sw_mlen, req->result);
++              ahash_request_free(req->crypto_req);
++              break;
++#endif
++#if defined(HAVE_ABLKCIPHER)
++      case SW_TYPE_ABLKCIPHER:
++              ablkcipher_request_free(req->crypto_req);
++              break;
++#endif
++      case SW_TYPE_CIPHER:
++      case SW_TYPE_HMAC:
++      case SW_TYPE_HASH:
++      case SW_TYPE_COMP:
++      case SW_TYPE_BLKCIPHER:
++              break;
++      default:
++              req->crp->crp_etype = EINVAL;
++              goto done;
++      }
++
++      req->crd = req->crd->crd_next;
++      if (req->crd) {
++              swcr_process_req(req);
++              return;
++      }
++
++done:
++      dprintk("%s crypto_done %p\n", __FUNCTION__, req);
++      crypto_done(req->crp);
++      kmem_cache_free(swcr_req_cache, req);
++}
++
++#if defined(HAVE_ABLKCIPHER) || defined(HAVE_AHASH)
++static void swcr_process_callback(struct crypto_async_request *creq, int err)
++{
++      struct swcr_req *req = creq->data;
++
++      dprintk("%s()\n", __FUNCTION__);
++      if (err) {
++              if (err == -EINPROGRESS)
++                      return;
++              dprintk("%s() fail %d\n", __FUNCTION__, -err);
++              req->crp->crp_etype = -err;
++      }
++
++      swcr_process_req_complete(req);
++}
++#endif /* defined(HAVE_ABLKCIPHER) || defined(HAVE_AHASH) */
++
++
++static void swcr_process_req(struct swcr_req *req)
++{
++      struct swcr_data *sw;
++      struct cryptop *crp = req->crp;
++      struct cryptodesc *crd = req->crd;
++      struct sk_buff *skb = (struct sk_buff *) crp->crp_buf;
++      struct uio *uiop = (struct uio *) crp->crp_buf;
++      int sg_num, sg_len, skip;
++
++      dprintk("%s()\n", __FUNCTION__);
++
++      /*
++       * Find the crypto context.
++       *
++       * XXX Note that the logic here prevents us from having
++       * XXX the same algorithm multiple times in a session
++       * XXX (or rather, we can but it won't give us the right
++       * XXX results). To do that, we'd need some way of differentiating
++       * XXX between the various instances of an algorithm (so we can
++       * XXX locate the correct crypto context).
++       */
++      for (sw = req->sw_head; sw && sw->sw_alg != crd->crd_alg; sw = sw->sw_next)
++              ;
++
++      /* No such context ? */
++      if (sw == NULL) {
++              crp->crp_etype = EINVAL;
++              dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__);
++              goto done;
++      }
++
++      /*
++       * for some types we need to ensure only one user as info is stored in
++       * the tfm during an operation that can get corrupted
++       */
++      switch (sw->sw_type & SW_TYPE_ALG_AMASK) {
++#ifdef HAVE_AHASH
++      case SW_TYPE_AHMAC:
++      case SW_TYPE_AHASH:
++#endif
++      case SW_TYPE_HMAC:
++      case SW_TYPE_HASH: {
++              unsigned long flags;
++              spin_lock_irqsave(&sw->sw_tfm_lock, flags);
++              if (sw->sw_type & SW_TYPE_INUSE) {
++                      spin_unlock_irqrestore(&sw->sw_tfm_lock, flags);
++                      execute_later((void (*)(void *))swcr_process_req, (void *)req);
++                      return;
++              }
++              sw->sw_type |= SW_TYPE_INUSE;
++              spin_unlock_irqrestore(&sw->sw_tfm_lock, flags);
++              } break;
++      }
++
++      req->sw = sw;
++      skip = crd->crd_skip;
++
++      /*
++       * setup the SG list skip from the start of the buffer
++       */
++      memset(req->sg, 0, sizeof(req->sg));
++      sg_init_table(req->sg, SCATTERLIST_MAX);
++      if (crp->crp_flags & CRYPTO_F_SKBUF) {
++              int i, len;
++
++              sg_num = 0;
++              sg_len = 0;
++
++              if (skip < skb_headlen(skb)) {
++                      len = skb_headlen(skb) - skip;
++                      if (len + sg_len > crd->crd_len)
++                              len = crd->crd_len - sg_len;
++                      sg_set_page(&req->sg[sg_num],
++                              virt_to_page(skb->data + skip), len,
++                              offset_in_page(skb->data + skip));
++                      sg_len += len;
++                      sg_num++;
++                      skip = 0;
++              } else
++                      skip -= skb_headlen(skb);
++
++              for (i = 0; sg_len < crd->crd_len &&
++                                      i < skb_shinfo(skb)->nr_frags &&
++                                      sg_num < SCATTERLIST_MAX; i++) {
++                      if (skip < skb_shinfo(skb)->frags[i].size) {
++                              len = skb_shinfo(skb)->frags[i].size - skip;
++                              if (len + sg_len > crd->crd_len)
++                                      len = crd->crd_len - sg_len;
++                              sg_set_page(&req->sg[sg_num],
++                                      skb_frag_page(&skb_shinfo(skb)->frags[i]),
++                                      len,
++                                      skb_shinfo(skb)->frags[i].page_offset + skip);
++                              sg_len += len;
++                              sg_num++;
++                              skip = 0;
++                      } else
++                              skip -= skb_shinfo(skb)->frags[i].size;
++              }
++      } else if (crp->crp_flags & CRYPTO_F_IOV) {
++              int len;
++
++              sg_len = 0;
++              for (sg_num = 0; sg_len < crd->crd_len &&
++                              sg_num < uiop->uio_iovcnt &&
++                              sg_num < SCATTERLIST_MAX; sg_num++) {
++                      if (skip <= uiop->uio_iov[sg_num].iov_len) {
++                              len = uiop->uio_iov[sg_num].iov_len - skip;
++                              if (len + sg_len > crd->crd_len)
++                                      len = crd->crd_len - sg_len;
++                              sg_set_page(&req->sg[sg_num],
++                                      virt_to_page(uiop->uio_iov[sg_num].iov_base+skip),
++                                      len,
++                                      offset_in_page(uiop->uio_iov[sg_num].iov_base+skip));
++                              sg_len += len;
++                              skip = 0;
++                      } else
++                              skip -= uiop->uio_iov[sg_num].iov_len;
++              }
++      } else {
++              sg_len = (crp->crp_ilen - skip);
++              if (sg_len > crd->crd_len)
++                      sg_len = crd->crd_len;
++              sg_set_page(&req->sg[0], virt_to_page(crp->crp_buf + skip),
++                      sg_len, offset_in_page(crp->crp_buf + skip));
++              sg_num = 1;
++      }
++      if (sg_num > 0)
++              sg_mark_end(&req->sg[sg_num-1]);
++
++      switch (sw->sw_type & SW_TYPE_ALG_AMASK) {
++
++#ifdef HAVE_AHASH
++      case SW_TYPE_AHMAC:
++      case SW_TYPE_AHASH:
++              {
++              int ret;
++
++              /* check we have room for the result */
++              if (crp->crp_ilen - crd->crd_inject < sw->u.hmac.sw_mlen) {
++                      dprintk("cryptosoft: EINVAL crp_ilen=%d, len=%d, inject=%d "
++                                      "digestsize=%d\n", crp->crp_ilen, crd->crd_skip + sg_len,
++                                      crd->crd_inject, sw->u.hmac.sw_mlen);
++                      crp->crp_etype = EINVAL;
++                      goto done;
++              }
++
++              req->crypto_req =
++                              ahash_request_alloc(__crypto_ahash_cast(sw->sw_tfm),GFP_ATOMIC);
++              if (!req->crypto_req) {
++                      crp->crp_etype = ENOMEM;
++                      dprintk("%s,%d: ENOMEM ahash_request_alloc", __FILE__, __LINE__);
++                      goto done;
++              }
++
++              ahash_request_set_callback(req->crypto_req,
++                              CRYPTO_TFM_REQ_MAY_BACKLOG, swcr_process_callback, req);
++
++              memset(req->result, 0, sizeof(req->result));
++
++              if (sw->sw_type & SW_TYPE_AHMAC)
++                      crypto_ahash_setkey(__crypto_ahash_cast(sw->sw_tfm),
++                                      sw->u.hmac.sw_key, sw->u.hmac.sw_klen);
++              ahash_request_set_crypt(req->crypto_req, req->sg, req->result, sg_len);
++              ret = crypto_ahash_digest(req->crypto_req);
++              switch (ret) {
++              case -EINPROGRESS:
++              case -EBUSY:
++                      return;
++              default:
++              case 0:
++                      dprintk("hash OP %s %d\n", ret ? "failed" : "success", ret);
++                      crp->crp_etype = ret;
++                      goto done;
++              }
++              } break;
++#endif /* HAVE_AHASH */
++
++#ifdef HAVE_ABLKCIPHER
++      case SW_TYPE_ABLKCIPHER: {
++              int ret;
++              unsigned char *ivp = req->iv;
++              int ivsize =
++                      crypto_ablkcipher_ivsize(__crypto_ablkcipher_cast(sw->sw_tfm));
++
++              if (sg_len < crypto_ablkcipher_blocksize(
++                              __crypto_ablkcipher_cast(sw->sw_tfm))) {
++                      crp->crp_etype = EINVAL;
++                      dprintk("%s,%d: EINVAL len %d < %d\n", __FILE__, __LINE__,
++                                      sg_len, crypto_ablkcipher_blocksize(
++                                              __crypto_ablkcipher_cast(sw->sw_tfm)));
++                      goto done;
++              }
++
++              if (ivsize > sizeof(req->iv)) {
++                      crp->crp_etype = EINVAL;
++                      dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__);
++                      goto done;
++              }
++
++              req->crypto_req = ablkcipher_request_alloc(
++                              __crypto_ablkcipher_cast(sw->sw_tfm), GFP_ATOMIC);
++              if (!req->crypto_req) {
++                      crp->crp_etype = ENOMEM;
++                      dprintk("%s,%d: ENOMEM ablkcipher_request_alloc",
++                                      __FILE__, __LINE__);
++                      goto done;
++              }
++
++              ablkcipher_request_set_callback(req->crypto_req,
++                              CRYPTO_TFM_REQ_MAY_BACKLOG, swcr_process_callback, req);
++
++              if (crd->crd_flags & CRD_F_KEY_EXPLICIT) {
++                      int i, error;
++
++                      if (debug) {
++                              dprintk("%s key:", __FUNCTION__);
++                              for (i = 0; i < (crd->crd_klen + 7) / 8; i++)
++                                      dprintk("%s0x%x", (i % 8) ? " " : "\n    ",
++                                                      crd->crd_key[i] & 0xff);
++                              dprintk("\n");
++                      }
++                      /* OCF doesn't enforce keys */
++                      crypto_ablkcipher_set_flags(__crypto_ablkcipher_cast(sw->sw_tfm),
++                                      CRYPTO_TFM_REQ_WEAK_KEY);
++                      error = crypto_ablkcipher_setkey(
++                                              __crypto_ablkcipher_cast(sw->sw_tfm), crd->crd_key,
++                                              (crd->crd_klen + 7) / 8);
++                      if (error) {
++                              dprintk("cryptosoft: setkey failed %d (crt_flags=0x%x)\n",
++                                              error, sw->sw_tfm->crt_flags);
++                              crp->crp_etype = -error;
++                      }
++              }
++
++              if (crd->crd_flags & CRD_F_ENCRYPT) { /* encrypt */
++
++                      if (crd->crd_flags & CRD_F_IV_EXPLICIT)
++                              ivp = crd->crd_iv;
++                      else
++                              get_random_bytes(ivp, ivsize);
++                      /*
++                       * do we have to copy the IV back to the buffer ?
++                       */
++                      if ((crd->crd_flags & CRD_F_IV_PRESENT) == 0) {
++                              crypto_copyback(crp->crp_flags, crp->crp_buf,
++                                              crd->crd_inject, ivsize, (caddr_t)ivp);
++                      }
++                      ablkcipher_request_set_crypt(req->crypto_req, req->sg, req->sg,
++                                      sg_len, ivp);
++                      ret = crypto_ablkcipher_encrypt(req->crypto_req);
++
++              } else { /*decrypt */
++
++                      if (crd->crd_flags & CRD_F_IV_EXPLICIT)
++                              ivp = crd->crd_iv;
++                      else
++                              crypto_copydata(crp->crp_flags, crp->crp_buf,
++                                              crd->crd_inject, ivsize, (caddr_t)ivp);
++                      ablkcipher_request_set_crypt(req->crypto_req, req->sg, req->sg,
++                                      sg_len, ivp);
++                      ret = crypto_ablkcipher_decrypt(req->crypto_req);
++              }
++
++              switch (ret) {
++              case -EINPROGRESS:
++              case -EBUSY:
++                      return;
++              default:
++              case 0:
++                      dprintk("crypto OP %s %d\n", ret ? "failed" : "success", ret);
++                      crp->crp_etype = ret;
++                      goto done;
++              }
++              } break;
++#endif /* HAVE_ABLKCIPHER */
++
++      case SW_TYPE_BLKCIPHER: {
++              unsigned char iv[EALG_MAX_BLOCK_LEN];
++              unsigned char *ivp = iv;
++              struct blkcipher_desc desc;
++              int ivsize = crypto_blkcipher_ivsize(crypto_blkcipher_cast(sw->sw_tfm));
++
++              if (sg_len < crypto_blkcipher_blocksize(
++                              crypto_blkcipher_cast(sw->sw_tfm))) {
++                      crp->crp_etype = EINVAL;
++                      dprintk("%s,%d: EINVAL len %d < %d\n", __FILE__, __LINE__,
++                                      sg_len, crypto_blkcipher_blocksize(
++                                              crypto_blkcipher_cast(sw->sw_tfm)));
++                      goto done;
++              }
++
++              if (ivsize > sizeof(iv)) {
++                      crp->crp_etype = EINVAL;
++                      dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__);
++                      goto done;
++              }
++
++              if (crd->crd_flags & CRD_F_KEY_EXPLICIT) {
++                      int i, error;
++
++                      if (debug) {
++                              dprintk("%s key:", __FUNCTION__);
++                              for (i = 0; i < (crd->crd_klen + 7) / 8; i++)
++                                      dprintk("%s0x%x", (i % 8) ? " " : "\n    ",
++                                                      crd->crd_key[i] & 0xff);
++                              dprintk("\n");
++                      }
++                      /* OCF doesn't enforce keys */
++                      crypto_blkcipher_set_flags(crypto_blkcipher_cast(sw->sw_tfm),
++                                      CRYPTO_TFM_REQ_WEAK_KEY);
++                      error = crypto_blkcipher_setkey(
++                                              crypto_blkcipher_cast(sw->sw_tfm), crd->crd_key,
++                                              (crd->crd_klen + 7) / 8);
++                      if (error) {
++                              dprintk("cryptosoft: setkey failed %d (crt_flags=0x%x)\n",
++                                              error, sw->sw_tfm->crt_flags);
++                              crp->crp_etype = -error;
++                      }
++              }
++
++              memset(&desc, 0, sizeof(desc));
++              desc.tfm = crypto_blkcipher_cast(sw->sw_tfm);
++
++              if (crd->crd_flags & CRD_F_ENCRYPT) { /* encrypt */
++
++                      if (crd->crd_flags & CRD_F_IV_EXPLICIT) {
++                              ivp = crd->crd_iv;
++                      } else {
++                              get_random_bytes(ivp, ivsize);
++                      }
++                      /*
++                       * do we have to copy the IV back to the buffer ?
++                       */
++                      if ((crd->crd_flags & CRD_F_IV_PRESENT) == 0) {
++                              crypto_copyback(crp->crp_flags, crp->crp_buf,
++                                              crd->crd_inject, ivsize, (caddr_t)ivp);
++                      }
++                      desc.info = ivp;
++                      crypto_blkcipher_encrypt_iv(&desc, req->sg, req->sg, sg_len);
++
++              } else { /*decrypt */
++
++                      if (crd->crd_flags & CRD_F_IV_EXPLICIT) {
++                              ivp = crd->crd_iv;
++                      } else {
++                              crypto_copydata(crp->crp_flags, crp->crp_buf,
++                                              crd->crd_inject, ivsize, (caddr_t)ivp);
++                      }
++                      desc.info = ivp;
++                      crypto_blkcipher_decrypt_iv(&desc, req->sg, req->sg, sg_len);
++              }
++              } break;
++
++      case SW_TYPE_HMAC:
++      case SW_TYPE_HASH:
++              {
++              char result[HASH_MAX_LEN];
++              struct hash_desc desc;
++
++              /* check we have room for the result */
++              if (crp->crp_ilen - crd->crd_inject < sw->u.hmac.sw_mlen) {
++                      dprintk("cryptosoft: EINVAL crp_ilen=%d, len=%d, inject=%d "
++                                      "digestsize=%d\n", crp->crp_ilen, crd->crd_skip + sg_len,
++                                      crd->crd_inject, sw->u.hmac.sw_mlen);
++                      crp->crp_etype = EINVAL;
++                      goto done;
++              }
++
++              memset(&desc, 0, sizeof(desc));
++              desc.tfm = crypto_hash_cast(sw->sw_tfm);
++
++              memset(result, 0, sizeof(result));
++
++              if (sw->sw_type & SW_TYPE_HMAC) {
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
++                      crypto_hmac(sw->sw_tfm, sw->u.hmac.sw_key, &sw->u.hmac.sw_klen,
++                                      req->sg, sg_num, result);
++#else
++                      crypto_hash_setkey(desc.tfm, sw->u.hmac.sw_key,
++                                      sw->u.hmac.sw_klen);
++                      crypto_hash_digest(&desc, req->sg, sg_len, result);
++#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) */
++
++              } else { /* SW_TYPE_HASH */
++                      crypto_hash_digest(&desc, req->sg, sg_len, result);
++              }
++
++              crypto_copyback(crp->crp_flags, crp->crp_buf,
++                              crd->crd_inject, sw->u.hmac.sw_mlen, result);
++              }
++              break;
++
++      case SW_TYPE_COMP: {
++              void *ibuf = NULL;
++              void *obuf = sw->u.sw_comp_buf;
++              int ilen = sg_len, olen = CRYPTO_MAX_DATA_LEN;
++              int ret = 0;
++
++              /*
++               * we need to use an additional copy if there is more than one
++               * input chunk since the kernel comp routines do not handle
++               * SG yet.  Otherwise we just use the input buffer as is.
++               * Rather than allocate another buffer we just split the tmp
++               * buffer we already have.
++               * Perhaps we should just use zlib directly ?
++               */
++              if (sg_num > 1) {
++                      int blk;
++
++                      ibuf = obuf;
++                      for (blk = 0; blk < sg_num; blk++) {
++                              memcpy(obuf, sg_virt(&req->sg[blk]),
++                                              req->sg[blk].length);
++                              obuf += req->sg[blk].length;
++                      }
++                      olen -= sg_len;
++              } else
++                      ibuf = sg_virt(&req->sg[0]);
++
++              if (crd->crd_flags & CRD_F_ENCRYPT) { /* compress */
++                      ret = crypto_comp_compress(crypto_comp_cast(sw->sw_tfm),
++                                      ibuf, ilen, obuf, &olen);
++                      if (!ret && olen > crd->crd_len) {
++                              dprintk("cryptosoft: ERANGE compress %d into %d\n",
++                                              crd->crd_len, olen);
++                              if (swcr_fail_if_compression_grows)
++                                      ret = ERANGE;
++                      }
++              } else { /* decompress */
++                      ret = crypto_comp_decompress(crypto_comp_cast(sw->sw_tfm),
++                                      ibuf, ilen, obuf, &olen);
++                      if (!ret && (olen + crd->crd_inject) > crp->crp_olen) {
++                              dprintk("cryptosoft: ETOOSMALL decompress %d into %d, "
++                                              "space for %d,at offset %d\n",
++                                              crd->crd_len, olen, crp->crp_olen, crd->crd_inject);
++                         &