summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/staging/Kconfig2
-rw-r--r--drivers/staging/Makefile1
-rw-r--r--drivers/staging/sep/Kconfig11
-rw-r--r--drivers/staging/sep/Makefile3
-rw-r--r--drivers/staging/sep/TODO3
-rw-r--r--drivers/staging/sep/sep_crypto.c3979
-rw-r--r--drivers/staging/sep/sep_crypto.h359
-rw-r--r--drivers/staging/sep/sep_dev.h162
-rw-r--r--drivers/staging/sep/sep_driver_api.h402
-rw-r--r--drivers/staging/sep/sep_driver_config.h298
-rw-r--r--drivers/staging/sep/sep_driver_hw_defs.h56
-rw-r--r--drivers/staging/sep/sep_main.c4411
-rw-r--r--drivers/staging/sep/sep_trace_events.h193
13 files changed, 0 insertions, 9880 deletions
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index 90624df0db6f..2c486ea6236b 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -64,8 +64,6 @@ source "drivers/staging/vt6655/Kconfig"
source "drivers/staging/vt6656/Kconfig"
-source "drivers/staging/sep/Kconfig"
-
source "drivers/staging/iio/Kconfig"
source "drivers/staging/xgifb/Kconfig"
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index 27f44cdde516..1e1a3a10faf7 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -26,7 +26,6 @@ obj-$(CONFIG_OCTEON_USB) += octeon-usb/
obj-$(CONFIG_VT6655) += vt6655/
obj-$(CONFIG_VT6656) += vt6656/
obj-$(CONFIG_VME_BUS) += vme/
-obj-$(CONFIG_DX_SEP) += sep/
obj-$(CONFIG_IIO) += iio/
obj-$(CONFIG_FB_XGI) += xgifb/
obj-$(CONFIG_USB_EMXX) += emxx_udc/
diff --git a/drivers/staging/sep/Kconfig b/drivers/staging/sep/Kconfig
deleted file mode 100644
index aab945a316ea..000000000000
--- a/drivers/staging/sep/Kconfig
+++ /dev/null
@@ -1,11 +0,0 @@
-config DX_SEP
- tristate "Discretix SEP driver"
- depends on PCI && CRYPTO
- help
- Discretix SEP driver; used for the security processor subsystem
- on board the Intel Mobile Internet Device and adds SEP availability
- to the kernel crypto infrastructure
-
- The driver's name is sep_driver.
-
- If unsure, select N.
diff --git a/drivers/staging/sep/Makefile b/drivers/staging/sep/Makefile
deleted file mode 100644
index e48a7959289e..000000000000
--- a/drivers/staging/sep/Makefile
+++ /dev/null
@@ -1,3 +0,0 @@
-ccflags-y += -I$(srctree)/$(src)
-obj-$(CONFIG_DX_SEP) += sep_driver.o
-sep_driver-objs := sep_crypto.o sep_main.o
diff --git a/drivers/staging/sep/TODO b/drivers/staging/sep/TODO
deleted file mode 100644
index 3524d0cf84ba..000000000000
--- a/drivers/staging/sep/TODO
+++ /dev/null
@@ -1,3 +0,0 @@
-Todo's so far (from Alan Cox)
-- Clean up unused ioctls
-- Clean up unused fields in ioctl structures
diff --git a/drivers/staging/sep/sep_crypto.c b/drivers/staging/sep/sep_crypto.c
deleted file mode 100644
index 415322867581..000000000000
--- a/drivers/staging/sep/sep_crypto.c
+++ /dev/null
@@ -1,3979 +0,0 @@
-/*
- *
- * sep_crypto.c - Crypto interface structures
- *
- * Copyright(c) 2009-2011 Intel Corporation. All rights reserved.
- * Contributions(c) 2009-2010 Discretix. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 59
- * Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * CONTACTS:
- *
- * Mark Allyn mark.a.allyn@intel.com
- * Jayant Mangalampalli jayant.mangalampalli@intel.com
- *
- * CHANGES:
- *
- * 2009.06.26 Initial publish
- * 2010.09.14 Upgrade to Medfield
- * 2011.02.22 Enable Kernel Crypto
- *
- */
-
-/* #define DEBUG */
-#include <linux/module.h>
-#include <linux/miscdevice.h>
-#include <linux/fs.h>
-#include <linux/cdev.h>
-#include <linux/kdev_t.h>
-#include <linux/mutex.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/poll.h>
-#include <linux/wait.h>
-#include <linux/pci.h>
-#include <linux/pm_runtime.h>
-#include <linux/err.h>
-#include <linux/device.h>
-#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>
-#include <linux/list.h>
-#include <linux/dma-mapping.h>
-#include <linux/delay.h>
-#include <linux/jiffies.h>
-#include <linux/workqueue.h>
-#include <linux/crypto.h>
-#include <crypto/internal/hash.h>
-#include <crypto/scatterwalk.h>
-#include <crypto/sha.h>
-#include <crypto/md5.h>
-#include <crypto/aes.h>
-#include <crypto/des.h>
-#include <crypto/hash.h>
-#include "sep_driver_hw_defs.h"
-#include "sep_driver_config.h"
-#include "sep_driver_api.h"
-#include "sep_dev.h"
-#include "sep_crypto.h"
-
-#if defined(CONFIG_CRYPTO) || defined(CONFIG_CRYPTO_MODULE)
-
-/* Globals for queuing */
-static spinlock_t queue_lock;
-static struct crypto_queue sep_queue;
-
-/* Declare of dequeuer */
-static void sep_dequeuer(void *data);
-
-/* TESTING */
-/**
- * sep_do_callback
- * @work: pointer to work_struct
- * This is what is called by the queue; it is generic so that it
- * can be used by any type of operation as each different callback
- * function can use the data parameter in its own way
- */
-static void sep_do_callback(struct work_struct *work)
-{
- struct sep_work_struct *sep_work = container_of(work,
- struct sep_work_struct, work);
-
- if (sep_work != NULL) {
- (sep_work->callback)(sep_work->data);
- kfree(sep_work);
- } else {
- pr_debug("sep crypto: do callback - NULL container\n");
- }
-}
-
-/**
- * sep_submit_work
- * @work_queue: pointer to struct_workqueue
- * @funct: pointer to function to execute
- * @data: pointer to data; function will know
- * how to use it
- * This is a generic API to submit something to
- * the queue. The callback function will depend
- * on what operation is to be done
- */
-static int sep_submit_work(struct workqueue_struct *work_queue,
- void (*funct)(void *),
- void *data)
-{
- struct sep_work_struct *sep_work;
- int result;
-
- sep_work = kmalloc(sizeof(struct sep_work_struct), GFP_ATOMIC);
-
- if (sep_work == NULL) {
- pr_debug("sep crypto: cant allocate work structure\n");
- return -ENOMEM;
- }
-
- sep_work->callback = funct;
- sep_work->data = data;
- INIT_WORK(&sep_work->work, sep_do_callback);
- result = queue_work(work_queue, &sep_work->work);
- if (!result) {
- pr_debug("sep_crypto: queue_work failed\n");
- return -EINVAL;
- }
- return 0;
-}
-
-/**
- * sep_alloc_sg_buf -
- * @sep: pointer to struct sep_device
- * @size: total size of area
- * @block_size: minimum size of chunks
- * each page is minimum or modulo this size
- * @returns: pointer to struct scatterlist for new
- * buffer
- **/
-static struct scatterlist *sep_alloc_sg_buf(
- struct sep_device *sep,
- size_t size,
- size_t block_size)
-{
- u32 nbr_pages;
- u32 ct1;
- void *buf;
- size_t current_size;
- size_t real_page_size;
-
- struct scatterlist *sg, *sg_temp;
-
- if (size == 0)
- return NULL;
-
- dev_dbg(&sep->pdev->dev, "sep alloc sg buf\n");
-
- current_size = 0;
- nbr_pages = 0;
- real_page_size = PAGE_SIZE - (PAGE_SIZE % block_size);
- /**
- * The size of each page must be modulo of the operation
- * block size; increment by the modified page size until
- * the total size is reached, then you have the number of
- * pages
- */
- while (current_size < size) {
- current_size += real_page_size;
- nbr_pages += 1;
- }
-
- sg = kmalloc_array(nbr_pages, sizeof(struct scatterlist), GFP_ATOMIC);
- if (!sg)
- return NULL;
-
- sg_init_table(sg, nbr_pages);
-
- current_size = 0;
- sg_temp = sg;
- for (ct1 = 0; ct1 < nbr_pages; ct1 += 1) {
- buf = (void *)get_zeroed_page(GFP_ATOMIC);
- if (!buf) {
- dev_warn(&sep->pdev->dev,
- "Cannot allocate page for new buffer\n");
- kfree(sg);
- return NULL;
- }
-
- sg_set_buf(sg_temp, buf, real_page_size);
- if ((size - current_size) > real_page_size) {
- sg_temp->length = real_page_size;
- current_size += real_page_size;
- } else {
- sg_temp->length = (size - current_size);
- current_size = size;
- }
- sg_temp = sg_next(sg);
- }
- return sg;
-}
-
-/**
- * sep_free_sg_buf -
- * @sg: pointer to struct scatterlist; points to area to free
- */
-static void sep_free_sg_buf(struct scatterlist *sg)
-{
- struct scatterlist *sg_temp = sg;
- while (sg_temp) {
- free_page((unsigned long)sg_virt(sg_temp));
- sg_temp = sg_next(sg_temp);
- }
- kfree(sg);
-}
-
-/**
- * sep_copy_sg -
- * @sep: pointer to struct sep_device
- * @sg_src: pointer to struct scatterlist for source
- * @sg_dst: pointer to struct scatterlist for destination
- * @size: size (in bytes) of data to copy
- *
- * Copy data from one scatterlist to another; both must
- * be the same size
- */
-static void sep_copy_sg(
- struct sep_device *sep,
- struct scatterlist *sg_src,
- struct scatterlist *sg_dst,
- size_t size)
-{
- u32 seg_size;
- u32 in_offset, out_offset;
-
- u32 count = 0;
- struct scatterlist *sg_src_tmp = sg_src;
- struct scatterlist *sg_dst_tmp = sg_dst;
-
- in_offset = 0;
- out_offset = 0;
-
- dev_dbg(&sep->pdev->dev, "sep copy sg\n");
-
- if ((sg_src == NULL) || (sg_dst == NULL) || (size == 0))
- return;
-
- dev_dbg(&sep->pdev->dev, "sep copy sg not null\n");
-
- while (count < size) {
- if ((sg_src_tmp->length - in_offset) >
- (sg_dst_tmp->length - out_offset))
- seg_size = sg_dst_tmp->length - out_offset;
- else
- seg_size = sg_src_tmp->length - in_offset;
-
- if (seg_size > (size - count))
- seg_size = (size = count);
-
- memcpy(sg_virt(sg_dst_tmp) + out_offset,
- sg_virt(sg_src_tmp) + in_offset,
- seg_size);
-
- in_offset += seg_size;
- out_offset += seg_size;
- count += seg_size;
-
- if (in_offset >= sg_src_tmp->length) {
- sg_src_tmp = sg_next(sg_src_tmp);
- in_offset = 0;
- }
-
- if (out_offset >= sg_dst_tmp->length) {
- sg_dst_tmp = sg_next(sg_dst_tmp);
- out_offset = 0;
- }
- }
-}
-
-/**
- * sep_oddball_pages -
- * @sep: pointer to struct sep_device
- * @sg: pointer to struct scatterlist - buffer to check
- * @size: total data size
- * @blocksize: minimum block size; must be multiples of this size
- * @to_copy: 1 means do copy, 0 means do not copy
- * @new_sg: pointer to location to put pointer to new sg area
- * @returns: 1 if new scatterlist is needed; 0 if not needed;
- * error value if operation failed
- *
- * The SEP device requires all pages to be multiples of the
- * minimum block size appropriate for the operation
- * This function check all pages; if any are oddball sizes
- * (not multiple of block sizes), it creates a new scatterlist.
- * If the to_copy parameter is set to 1, then a scatter list
- * copy is performed. The pointer to the new scatterlist is
- * put into the address supplied by the new_sg parameter; if
- * no new scatterlist is needed, then a NULL is put into
- * the location at new_sg.
- *
- */
-static int sep_oddball_pages(
- struct sep_device *sep,
- struct scatterlist *sg,
- size_t data_size,
- u32 block_size,
- struct scatterlist **new_sg,
- u32 do_copy)
-{
- struct scatterlist *sg_temp;
- u32 flag;
- u32 nbr_pages, page_count;
-
- dev_dbg(&sep->pdev->dev, "sep oddball\n");
- if ((sg == NULL) || (data_size == 0) || (data_size < block_size))
- return 0;
-
- dev_dbg(&sep->pdev->dev, "sep oddball not null\n");
- flag = 0;
- nbr_pages = 0;
- page_count = 0;
- sg_temp = sg;
-
- while (sg_temp) {
- nbr_pages += 1;
- sg_temp = sg_next(sg_temp);
- }
-
- sg_temp = sg;
- while ((sg_temp) && (flag == 0)) {
- page_count += 1;
- if (sg_temp->length % block_size)
- flag = 1;
- else
- sg_temp = sg_next(sg_temp);
- }
-
- /* Do not process if last (or only) page is oddball */
- if (nbr_pages == page_count)
- flag = 0;
-
- if (flag) {
- dev_dbg(&sep->pdev->dev, "sep oddball processing\n");
- *new_sg = sep_alloc_sg_buf(sep, data_size, block_size);
- if (*new_sg == NULL) {
- dev_warn(&sep->pdev->dev, "cannot allocate new sg\n");
- return -ENOMEM;
- }
-
- if (do_copy)
- sep_copy_sg(sep, sg, *new_sg, data_size);
-
- return 1;
- } else {
- return 0;
- }
-}
-
-/**
- * sep_copy_offset_sg -
- * @sep: pointer to struct sep_device;
- * @sg: pointer to struct scatterlist
- * @offset: offset into scatterlist memory
- * @dst: place to put data
- * @len: length of data
- * @returns: number of bytes copies
- *
- * This copies data from scatterlist buffer
- * offset from beginning - it is needed for
- * handling tail data in hash
- */
-static size_t sep_copy_offset_sg(
- struct sep_device *sep,
- struct scatterlist *sg,
- u32 offset,
- void *dst,
- u32 len)
-{
- size_t page_start;
- size_t page_end;
- size_t offset_within_page;
- size_t length_within_page;
- size_t length_remaining;
- size_t current_offset;
-
- /* Find which page is beginning of segment */
- page_start = 0;
- page_end = sg->length;
- while ((sg) && (offset > page_end)) {
- page_start += sg->length;
- sg = sg_next(sg);
- if (sg)
- page_end += sg->length;
- }
-
- if (sg == NULL)
- return -ENOMEM;
-
- offset_within_page = offset - page_start;
- if ((sg->length - offset_within_page) >= len) {
- /* All within this page */
- memcpy(dst, sg_virt(sg) + offset_within_page, len);
- return len;
- } else {
- /* Scattered multiple pages */
- current_offset = 0;
- length_remaining = len;
- while ((sg) && (current_offset < len)) {
- length_within_page = sg->length - offset_within_page;
- if (length_within_page >= length_remaining) {
- memcpy(dst+current_offset,
- sg_virt(sg) + offset_within_page,
- length_remaining);
- length_remaining = 0;
- current_offset = len;
- } else {
- memcpy(dst+current_offset,
- sg_virt(sg) + offset_within_page,
- length_within_page);
- length_remaining -= length_within_page;
- current_offset += length_within_page;
- offset_within_page = 0;
- sg = sg_next(sg);
- }
- }
-
- if (sg == NULL)
- return -ENOMEM;
- }
- return len;
-}
-
-/**
- * partial_overlap -
- * @src_ptr: source pointer
- * @dst_ptr: destination pointer
- * @nbytes: number of bytes
- * @returns: 0 for success; -1 for failure
- * We cannot have any partial overlap. Total overlap
- * where src is the same as dst is okay
- */
-static int partial_overlap(void *src_ptr, void *dst_ptr, u32 nbytes)
-{
- /* Check for partial overlap */
- if (src_ptr != dst_ptr) {
- if (src_ptr < dst_ptr) {
- if ((src_ptr + nbytes) > dst_ptr)
- return -EINVAL;
- } else {
- if ((dst_ptr + nbytes) > src_ptr)
- return -EINVAL;
- }
- }
-
- return 0;
-}
-
-/* Debug - prints only if DEBUG is defined */
-static void sep_dump_ivs(struct ablkcipher_request *req, char *reason)
-
- {
- unsigned char *cptr;
- struct sep_aes_internal_context *aes_internal;
- struct sep_des_internal_context *des_internal;
- int ct1;
-
- struct this_task_ctx *ta_ctx;
- struct crypto_ablkcipher *tfm;
- struct sep_system_ctx *sctx;
-
- ta_ctx = ablkcipher_request_ctx(req);
- tfm = crypto_ablkcipher_reqtfm(req);
- sctx = crypto_ablkcipher_ctx(tfm);
-
- dev_dbg(&ta_ctx->sep_used->pdev->dev, "IV DUMP - %s\n", reason);
- if ((ta_ctx->current_request == DES_CBC) &&
- (ta_ctx->des_opmode == SEP_DES_CBC)) {
-
- des_internal = (struct sep_des_internal_context *)
- sctx->des_private_ctx.ctx_buf;
- /* print vendor */
- dev_dbg(&ta_ctx->sep_used->pdev->dev,
- "sep - vendor iv for DES\n");
- cptr = (unsigned char *)des_internal->iv_context;
- for (ct1 = 0; ct1 < crypto_ablkcipher_ivsize(tfm); ct1 += 1)
- dev_dbg(&ta_ctx->sep_used->pdev->dev,
- "%02x\n", *(cptr + ct1));
-
- /* print walk */
- dev_dbg(&ta_ctx->sep_used->pdev->dev,
- "sep - walk from kernel crypto iv for DES\n");
- cptr = (unsigned char *)ta_ctx->walk.iv;
- for (ct1 = 0; ct1 < crypto_ablkcipher_ivsize(tfm); ct1 += 1)
- dev_dbg(&ta_ctx->sep_used->pdev->dev,
- "%02x\n", *(cptr + ct1));
- } else if ((ta_ctx->current_request == AES_CBC) &&
- (ta_ctx->aes_opmode == SEP_AES_CBC)) {
-
- aes_internal = (struct sep_aes_internal_context *)
- sctx->aes_private_ctx.cbuff;
- /* print vendor */
- dev_dbg(&ta_ctx->sep_used->pdev->dev,
- "sep - vendor iv for AES\n");
- cptr = (unsigned char *)aes_internal->aes_ctx_iv;
- for (ct1 = 0; ct1 < crypto_ablkcipher_ivsize(tfm); ct1 += 1)
- dev_dbg(&ta_ctx->sep_used->pdev->dev,
- "%02x\n", *(cptr + ct1));
-
- /* print walk */
- dev_dbg(&ta_ctx->sep_used->pdev->dev,
- "sep - walk from kernel crypto iv for AES\n");
- cptr = (unsigned char *)ta_ctx->walk.iv;
- for (ct1 = 0; ct1 < crypto_ablkcipher_ivsize(tfm); ct1 += 1)
- dev_dbg(&ta_ctx->sep_used->pdev->dev,
- "%02x\n", *(cptr + ct1));
- }
-}
-
-/**
- * RFC2451: Weak key check
- * Returns: 1 (weak), 0 (not weak)
- */
-static int sep_weak_key(const u8 *key, unsigned int keylen)
-{
- static const u8 parity[] = {
- 8, 1, 0, 8, 0, 8, 8, 0, 0, 8, 8, 0, 8, 0, 2, 8,
- 0, 8, 8, 0, 8, 0, 0, 8, 8,
- 0, 0, 8, 0, 8, 8, 3,
- 0, 8, 8, 0, 8, 0, 0, 8, 8, 0, 0, 8, 0, 8, 8, 0,
- 8, 0, 0, 8, 0, 8, 8, 0, 0,
- 8, 8, 0, 8, 0, 0, 8,
- 0, 8, 8, 0, 8, 0, 0, 8, 8, 0, 0, 8, 0, 8, 8, 0,
- 8, 0, 0, 8, 0, 8, 8, 0, 0,
- 8, 8, 0, 8, 0, 0, 8,
- 8, 0, 0, 8, 0, 8, 8, 0, 0, 8, 8, 0, 8, 0, 0, 8,
- 0, 8, 8, 0, 8, 0, 0, 8, 8,
- 0, 0, 8, 0, 8, 8, 0,
- 0, 8, 8, 0, 8, 0, 0, 8, 8, 0, 0, 8, 0, 8, 8, 0,
- 8, 0, 0, 8, 0, 8, 8, 0, 0,
- 8, 8, 0, 8, 0, 0, 8,
- 8, 0, 0, 8, 0, 8, 8, 0, 0, 8, 8, 0, 8, 0, 0, 8,
- 0, 8, 8, 0, 8, 0, 0, 8, 8,
- 0, 0, 8, 0, 8, 8, 0,
- 8, 0, 0, 8, 0, 8, 8, 0, 0, 8, 8, 0, 8, 0, 0, 8,
- 0, 8, 8, 0, 8, 0, 0, 8, 8,
- 0, 0, 8, 0, 8, 8, 0,
- 4, 8, 8, 0, 8, 0, 0, 8, 8, 0, 0, 8, 0, 8, 8, 0,
- 8, 5, 0, 8, 0, 8, 8, 0, 0,
- 8, 8, 0, 8, 0, 6, 8,
- };
-
- u32 n, w;
-
- n = parity[key[0]]; n <<= 4;
- n |= parity[key[1]]; n <<= 4;
- n |= parity[key[2]]; n <<= 4;
- n |= parity[key[3]]; n <<= 4;
- n |= parity[key[4]]; n <<= 4;
- n |= parity[key[5]]; n <<= 4;
- n |= parity[key[6]]; n <<= 4;
- n |= parity[key[7]];
- w = 0x88888888L;
-
- /* 1 in 10^10 keys passes this test */
- if (!((n - (w >> 3)) & w)) {
- if (n < 0x41415151) {
- if (n < 0x31312121) {
- if (n < 0x14141515) {
- /* 01 01 01 01 01 01 01 01 */
- if (n == 0x11111111)
- goto weak;
- /* 01 1F 01 1F 01 0E 01 0E */
- if (n == 0x13131212)
- goto weak;
- } else {
- /* 01 E0 01 E0 01 F1 01 F1 */
- if (n == 0x14141515)
- goto weak;
- /* 01 FE 01 FE 01 FE 01 FE */
- if (n == 0x16161616)
- goto weak;
- }
- } else {
- if (n < 0x34342525) {
- /* 1F 01 1F 01 0E 01 0E 01 */
- if (n == 0x31312121)
- goto weak;
- /* 1F 1F 1F 1F 0E 0E 0E 0E (?) */
- if (n == 0x33332222)
- goto weak;
- } else {
- /* 1F E0 1F E0 0E F1 0E F1 */
- if (n == 0x34342525)
- goto weak;
- /* 1F FE 1F FE 0E FE 0E FE */
- if (n == 0x36362626)
- goto weak;
- }
- }
- } else {
- if (n < 0x61616161) {
- if (n < 0x44445555) {
- /* E0 01 E0 01 F1 01 F1 01 */
- if (n == 0x41415151)
- goto weak;
- /* E0 1F E0 1F F1 0E F1 0E */
- if (n == 0x43435252)
- goto weak;
- } else {
- /* E0 E0 E0 E0 F1 F1 F1 F1 (?) */
- if (n == 0x44445555)
- goto weak;
- /* E0 FE E0 FE F1 FE F1 FE */
- if (n == 0x46465656)
- goto weak;
- }
- } else {
- if (n < 0x64646565) {
- /* FE 01 FE 01 FE 01 FE 01 */
- if (n == 0x61616161)
- goto weak;
- /* FE 1F FE 1F FE 0E FE 0E */
- if (n == 0x63636262)
- goto weak;
- } else {
- /* FE E0 FE E0 FE F1 FE F1 */
- if (n == 0x64646565)
- goto weak;
- /* FE FE FE FE FE FE FE FE */
- if (n == 0x66666666)
- goto weak;
- }
- }
- }
- }
- return 0;
-weak:
- return 1;
-}
-/**
- * sep_sg_nents
- */
-static u32 sep_sg_nents(struct scatterlist *sg)
-{
- u32 ct1 = 0;
-
- while (sg) {
- ct1 += 1;
- sg = sg_next(sg);
- }
-
- return ct1;
-}
-
-/**
- * sep_start_msg -
- * @ta_ctx: pointer to struct this_task_ctx
- * @returns: offset to place for the next word in the message
- * Set up pointer in message pool for new message
- */
-static u32 sep_start_msg(struct this_task_ctx *ta_ctx)
-{
- u32 *word_ptr;
-
- ta_ctx->msg_len_words = 2;
- ta_ctx->msgptr = ta_ctx->msg;
- memset(ta_ctx->msg, 0, SEP_DRIVER_MESSAGE_SHARED_AREA_SIZE_IN_BYTES);
- ta_ctx->msgptr += sizeof(u32) * 2;
- word_ptr = (u32 *)ta_ctx->msgptr;
- *word_ptr = SEP_START_MSG_TOKEN;
- return sizeof(u32) * 2;
-}
-
-/**
- * sep_end_msg -
- * @ta_ctx: pointer to struct this_task_ctx
- * @messages_offset: current message offset
- * Returns: 0 for success; <0 otherwise
- * End message; set length and CRC; and
- * send interrupt to the SEP
- */
-static void sep_end_msg(struct this_task_ctx *ta_ctx, u32 msg_offset)
-{
- u32 *word_ptr;
- /* Msg size goes into msg after token */
- ta_ctx->msg_len_words = msg_offset / sizeof(u32) + 1;
- word_ptr = (u32 *)ta_ctx->msgptr;
- word_ptr += 1;
- *word_ptr = ta_ctx->msg_len_words;
-
- /* CRC (currently 0) goes at end of msg */
- word_ptr = (u32 *)(ta_ctx->msgptr + msg_offset);
- *word_ptr = 0;
-}
-
-/**
- * sep_start_inbound_msg -
- * @ta_ctx: pointer to struct this_task_ctx
- * @msg_offset: offset to place for the next word in the message
- * @returns: 0 for success; error value for failure
- * Set up pointer in message pool for inbound message
- */
-static u32 sep_start_inbound_msg(struct this_task_ctx *ta_ctx, u32 *msg_offset)
-{
- u32 *word_ptr;
- u32 token;
- u32 error = SEP_OK;
-
- *msg_offset = sizeof(u32) * 2;
- word_ptr = (u32 *)ta_ctx->msgptr;
- token = *word_ptr;
- ta_ctx->msg_len_words = *(word_ptr + 1);
-
- if (token != SEP_START_MSG_TOKEN) {
- error = SEP_INVALID_START;
- goto end_function;
- }
-
-end_function:
-
- return error;
-}
-
-/**
- * sep_write_msg -
- * @ta_ctx: pointer to struct this_task_ctx
- * @in_addr: pointer to start of parameter
- * @size: size of parameter to copy (in bytes)
- * @max_size: size to move up offset; SEP mesg is in word sizes
- * @msg_offset: pointer to current offset (is updated)
- * @byte_array: flag ti indicate whether endian must be changed
- * Copies data into the message area from caller
- */
-static void sep_write_msg(struct this_task_ctx *ta_ctx, void *in_addr,
- u32 size, u32 max_size, u32 *msg_offset, u32 byte_array)
-{
- u32 *word_ptr;
- void *void_ptr;
-
- void_ptr = ta_ctx->msgptr + *msg_offset;
- word_ptr = (u32 *)void_ptr;
- memcpy(void_ptr, in_addr, size);
- *msg_offset += max_size;
-
- /* Do we need to manipulate endian? */
- if (byte_array) {
- u32 i;
-
- for (i = 0; i < ((size + 3) / 4); i += 1)
- *(word_ptr + i) = CHG_ENDIAN(*(word_ptr + i));
- }
-}
-
-/**
- * sep_make_header
- * @ta_ctx: pointer to struct this_task_ctx
- * @msg_offset: pointer to current offset (is updated)
- * @op_code: op code to put into message
- * Puts op code into message and updates offset
- */
-static void sep_make_header(struct this_task_ctx *ta_ctx, u32 *msg_offset,
- u32 op_code)
-{
- u32 *word_ptr;
-
- *msg_offset = sep_start_msg(ta_ctx);
- word_ptr = (u32 *)(ta_ctx->msgptr + *msg_offset);
- *word_ptr = op_code;
- *msg_offset += sizeof(u32);
-}
-
-
-
-/**
- * sep_read_msg -
- * @ta_ctx: pointer to struct this_task_ctx
- * @in_addr: pointer to start of parameter
- * @size: size of parameter to copy (in bytes)
- * @max_size: size to move up offset; SEP mesg is in word sizes
- * @msg_offset: pointer to current offset (is updated)
- * @byte_array: flag ti indicate whether endian must be changed
- * Copies data out of the message area to caller
- */
-static void sep_read_msg(struct this_task_ctx *ta_ctx, void *in_addr,
- u32 size, u32 max_size, u32 *msg_offset, u32 byte_array)
-{
- u32 *word_ptr;
- void *void_ptr;
-
- void_ptr = ta_ctx->msgptr + *msg_offset;
- word_ptr = (u32 *)void_ptr;
-
- /* Do we need to manipulate endian? */
- if (byte_array) {
- u32 i;
-
- for (i = 0; i < ((size + 3) / 4); i += 1)
- *(word_ptr + i) = CHG_ENDIAN(*(word_ptr + i));
- }
-
- memcpy(in_addr, void_ptr, size);
- *msg_offset += max_size;
-}
-
-/**
- * sep_verify_op -
- * @ta_ctx: pointer to struct this_task_ctx
- * @op_code: expected op_code
- * @msg_offset: pointer to current offset (is updated)
- * @returns: 0 for success; error for failure
- */
-static u32 sep_verify_op(struct this_task_ctx *ta_ctx, u32 op_code,
- u32 *msg_offset)
-{
- u32 error;
- u32 in_ary[2];
-
- struct sep_device *sep = ta_ctx->sep_used;
-
- dev_dbg(&sep->pdev->dev, "dumping return message\n");
- error = sep_start_inbound_msg(ta_ctx, msg_offset);
- if (error) {
- dev_warn(&sep->pdev->dev,
- "sep_start_inbound_msg error\n");
- return error;
- }
-
- sep_read_msg(ta_ctx, in_ary, sizeof(u32) * 2, sizeof(u32) * 2,
- msg_offset, 0);
-
- if (in_ary[0] != op_code) {
- dev_warn(&sep->pdev->dev,
- "sep got back wrong opcode\n");
- dev_warn(&sep->pdev->dev,
- "got back %x; expected %x\n",
- in_ary[0], op_code);
- return SEP_WRONG_OPCODE;
- }
-
- if (in_ary[1] != SEP_OK) {
- dev_warn(&sep->pdev->dev,
- "sep execution error\n");
- dev_warn(&sep->pdev->dev,
- "got back %x; expected %x\n",
- in_ary[1], SEP_OK);
- return in_ary[0];
- }
-
-return 0;
-}
-
-/**
- * sep_read_context -
- * @ta_ctx: pointer to struct this_task_ctx
- * @msg_offset: point to current place in SEP msg; is updated
- * @dst: pointer to place to put the context
- * @len: size of the context structure (differs for crypro/hash)
- * This function reads the context from the msg area
- * There is a special way the vendor needs to have the maximum
- * length calculated so that the msg_offset is updated properly;
- * it skips over some words in the msg area depending on the size
- * of the context
- */
-static void sep_read_context(struct this_task_ctx *ta_ctx, u32 *msg_offset,
- void *dst, u32 len)
-{
- u32 max_length = ((len + 3) / sizeof(u32)) * sizeof(u32);
-
- sep_read_msg(ta_ctx, dst, len, max_length, msg_offset, 0);
-}
-
-/**
- * sep_write_context -
- * @ta_ctx: pointer to struct this_task_ctx
- * @msg_offset: point to current place in SEP msg; is updated
- * @src: pointer to the current context
- * @len: size of the context structure (differs for crypro/hash)
- * This function writes the context to the msg area
- * There is a special way the vendor needs to have the maximum
- * length calculated so that the msg_offset is updated properly;
- * it skips over some words in the msg area depending on the size
- * of the context
- */
-static void sep_write_context(struct this_task_ctx *ta_ctx, u32 *msg_offset,
- void *src, u32 len)
-{
- u32 max_length = ((len + 3) / sizeof(u32)) * sizeof(u32);
-
- sep_write_msg(ta_ctx, src, len, max_length, msg_offset, 0);
-}
-
-/**
- * sep_clear_out -
- * @ta_ctx: pointer to struct this_task_ctx
- * Clear out crypto related values in sep device structure
- * to enable device to be used by anyone; either kernel
- * crypto or userspace app via middleware
- */
-static void sep_clear_out(struct this_task_ctx *ta_ctx)
-{
- if (ta_ctx->src_sg_hold) {
- sep_free_sg_buf(ta_ctx->src_sg_hold);
- ta_ctx->src_sg_hold = NULL;
- }
-
- if (ta_ctx->dst_sg_hold) {
- sep_free_sg_buf(ta_ctx->dst_sg_hold);
- ta_ctx->dst_sg_hold = NULL;
- }
-
- ta_ctx->src_sg = NULL;
- ta_ctx->dst_sg = NULL;
-
- sep_free_dma_table_data_handler(ta_ctx->sep_used, &ta_ctx->dma_ctx);
-
- if (ta_ctx->i_own_sep) {
- /**
- * The following unlocks the sep and makes it available
- * to any other application
- * First, null out crypto entries in sep before releasing it
- */
- ta_ctx->sep_used->current_hash_req = NULL;
- ta_ctx->sep_used->current_cypher_req = NULL;
- ta_ctx->sep_used->current_request = 0;
- ta_ctx->sep_used->current_hash_stage = 0;
- ta_ctx->sep_used->ta_ctx = NULL;
- ta_ctx->sep_used->in_kernel = 0;
-
- ta_ctx->call_status.status = 0;
-
- /* Remove anything confidential */
- memset(ta_ctx->sep_used->shared_addr, 0,
- SEP_DRIVER_MESSAGE_SHARED_AREA_SIZE_IN_BYTES);
-
- sep_queue_status_remove(ta_ctx->sep_used, &ta_ctx->queue_elem);
-
-#ifdef SEP_ENABLE_RUNTIME_PM
- ta_ctx->sep_used->in_use = 0;
- pm_runtime_mark_last_busy(&ta_ctx->sep_used->pdev->dev);
- pm_runtime_put_autosuspend(&ta_ctx->sep_used->pdev->dev);
-#endif
-
- clear_bit(SEP_WORKING_LOCK_BIT,
- &ta_ctx->sep_used->in_use_flags);
- ta_ctx->sep_used->pid_doing_transaction = 0;
-
- dev_dbg(&ta_ctx->sep_used->pdev->dev,
- "[PID%d] waking up next transaction\n",
- current->pid);
-
- clear_bit(SEP_TRANSACTION_STARTED_LOCK_BIT,
- &ta_ctx->sep_used->in_use_flags);
- wake_up(&ta_ctx->sep_used->event_transactions);
-
- ta_ctx->i_own_sep = 0;
- }
-}
-
-/**
- * Release crypto infrastructure from EINPROGRESS and
- * clear sep_dev so that SEP is available to anyone
- */
-static void sep_crypto_release(struct sep_system_ctx *sctx,
- struct this_task_ctx *ta_ctx, u32 error)
-{
- struct ahash_request *hash_req = ta_ctx->current_hash_req;
- struct ablkcipher_request *cypher_req =
- ta_ctx->current_cypher_req;
- struct sep_device *sep = ta_ctx->sep_used;
-
- sep_clear_out(ta_ctx);
-
- /**
- * This may not yet exist depending when we
- * chose to bail out. If it does exist, set
- * it to 1
- */
- if (ta_ctx->are_we_done_yet != NULL)
- *ta_ctx->are_we_done_yet = 1;
-
- if (cypher_req != NULL) {
- if ((sctx->key_sent == 1) ||
- ((error != 0) && (error != -EINPROGRESS))) {
- if (cypher_req->base.complete == NULL) {
- dev_dbg(&sep->pdev->dev,
- "release is null for cypher!");
- } else {
- cypher_req->base.complete(
- &cypher_req->base, error);
- }
- }
- }
-
- if (hash_req != NULL) {
- if (hash_req->base.complete == NULL) {
- dev_dbg(&sep->pdev->dev,
- "release is null for hash!");
- } else {
- hash_req->base.complete(
- &hash_req->base, error);
- }
- }
-}
-
-/**
- * This is where we grab the sep itself and tell it to do something.
- * It will sleep if the sep is currently busy
- * and it will return 0 if sep is now ours; error value if there
- * were problems
- */
-static int sep_crypto_take_sep(struct this_task_ctx *ta_ctx)
-{
- struct sep_device *sep = ta_ctx->sep_used;
- int result;
- struct sep_msgarea_hdr *my_msg_header;
-
- my_msg_header = (struct sep_msgarea_hdr *)ta_ctx->msg;
-
- /* add to status queue */
- ta_ctx->queue_elem = sep_queue_status_add(sep, my_msg_header->opcode,
- ta_ctx->nbytes, current->pid,
- current->comm, sizeof(current->comm));
-
- if (!ta_ctx->queue_elem) {
- dev_dbg(&sep->pdev->dev,
- "[PID%d] updating queue status error\n", current->pid);
- return -EINVAL;
- }
-
- /* get the device; this can sleep */
- result = sep_wait_transaction(sep);