diff options
-rw-r--r-- | drivers/staging/Kconfig | 2 | ||||
-rw-r--r-- | drivers/staging/Makefile | 1 | ||||
-rw-r--r-- | drivers/staging/sep/Kconfig | 11 | ||||
-rw-r--r-- | drivers/staging/sep/Makefile | 3 | ||||
-rw-r--r-- | drivers/staging/sep/TODO | 3 | ||||
-rw-r--r-- | drivers/staging/sep/sep_crypto.c | 3979 | ||||
-rw-r--r-- | drivers/staging/sep/sep_crypto.h | 359 | ||||
-rw-r--r-- | drivers/staging/sep/sep_dev.h | 162 | ||||
-rw-r--r-- | drivers/staging/sep/sep_driver_api.h | 402 | ||||
-rw-r--r-- | drivers/staging/sep/sep_driver_config.h | 298 | ||||
-rw-r--r-- | drivers/staging/sep/sep_driver_hw_defs.h | 56 | ||||
-rw-r--r-- | drivers/staging/sep/sep_main.c | 4411 | ||||
-rw-r--r-- | drivers/staging/sep/sep_trace_events.h | 193 |
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); |