diff options
Diffstat (limited to '')
-rw-r--r-- | drivers/staging/sep/sep_crypto.c | 3962 |
1 files changed, 0 insertions, 3962 deletions
diff --git a/drivers/staging/sep/sep_crypto.c b/drivers/staging/sep/sep_crypto.c deleted file mode 100644 index 415f8ec5276b..000000000000 --- a/drivers/staging/sep/sep_crypto.c +++ /dev/null @@ -1,3962 +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); - if (result) - return result; - - if (sep_dev->power_save_setup == 1) - pm_runtime_get_sync(&sep_dev->pdev->dev); - - /* Copy in the message */ - memcpy(sep->shared_addr, ta_ctx->msg, - SEP_DRIVER_MESSAGE_SHARED_AREA_SIZE_IN_BYTES); - - /* Copy in the dcb information if there is any */ - if (ta_ctx->dcb_region) { - result = sep_activate_dcb_dmatables_context(sep, - &ta_ctx->dcb_region, &ta_ctx->dmatables_region, - ta_ctx->dma_ctx); - if (result) - return result; - } - - /* Mark the device so we know how to finish the job in the tasklet */ - if (ta_ctx->current_hash_req) - sep->current_hash_req = ta_ctx->current_hash_req; - else - sep->current_cypher_req = ta_ctx->current_cypher_req; - - sep->current_request = ta_ctx->current_request; - sep->current_hash_stage = ta_ctx->current_hash_stage; - sep->ta_ctx = ta_ctx; - sep->in_kernel = 1; - ta_ctx->i_own_sep = 1; - - /* need to set bit first to avoid race condition with interrupt */ - set_bit(SEP_LEGACY_SENDMSG_DONE_OFFSET, &ta_ctx->call_status.status); - - result = sep_send_command_handler(sep); - - dev_dbg(&sep->pdev->dev, "[PID%d]: sending command to the sep\n", - current->pid); - - if (!result) - dev_dbg(&sep->pdev->dev, "[PID%d]: command sent okay\n", - current->pid); - else { - dev_dbg(&sep->pdev->dev, "[PID%d]: cant send command\n", - current->pid); - clear_bit(SEP_LEGACY_SENDMSG_DONE_OFFSET, - &ta_ctx->call_status.status); - } - - return result; -} - -/** - * This function sets things up for a crypto data block process - * This does all preparation, but does not try to grab the - * sep - * @req: pointer to struct ablkcipher_request - * returns: 0 if all went well, non zero if error - */ -static int sep_crypto_block_data(struct ablkcipher_request *req) -{ - - int int_error; - u32 msg_offset; - static u32 msg[10]; - void *src_ptr; - void *dst_ptr; - - static char small_buf[100]; - ssize_t copy_result; - int result; - - struct scatterlist *new_sg; - struct this_task_ctx *ta_ctx; - struct crypto_ablkcipher *tfm; - struct sep_system_ctx *sctx; - - struct sep_des_internal_context *des_internal; - struct sep_aes_internal_context *aes_internal; - - ta_ctx = ablkcipher_request_ctx(req); - tfm = crypto_ablkcipher_reqtfm(req); - sctx = crypto_ablkcipher_ctx(tfm); - - /* start the walk on scatterlists */ - ablkcipher_walk_init(&ta_ctx->walk, req->src, req->dst, req->nbytes); - dev_dbg(&ta_ctx->sep_used->pdev->dev, "sep crypto block data size of %x\n", - req->nbytes); - - int_error = ablkcipher_walk_phys(req, &ta_ctx->walk); - if (int_error) { - dev_warn(&ta_ctx->sep_used->pdev->dev, "walk phys error %x\n", - int_error); - return -ENOMEM; - } - - dev_dbg(&ta_ctx->sep_used->pdev->dev, - "crypto block: src is %lx dst is %lx\n", - (unsigned long)req->src, (unsigned long)req->dst); - - /* Make sure all pages are even block */ - int_error = sep_oddball_pages(ta_ctx->sep_used, req->src, - req->nbytes, ta_ctx->walk.blocksize, &new_sg, 1); - - if (int_error < 0) { - dev_warn(&ta_ctx->sep_used->pdev->dev, "oddball page error\n"); - return int_error; - } else if (int_error == 1) { - ta_ctx->src_sg = new_sg; - ta_ctx->src_sg_hold = new_sg; - } else { - ta_ctx->src_sg = req->src; - ta_ctx->src_sg_hold = NULL; - } - - int_error = sep_oddball_pages(ta_ctx->sep_used, req->dst, - req->nbytes, ta_ctx->walk.blocksize, &new_sg, 0); - - if (int_error < 0) { - dev_warn(&ta_ctx->sep_used->pdev->dev, "walk phys error %x\n", - int_error); - return int_error; - } else if (int_error == 1) { - ta_ctx->dst_sg = new_sg; - ta_ctx->dst_sg_hold = new_sg; - } else { - ta_ctx->dst_sg = req->dst; - ta_ctx->dst_sg_hold = NULL; - } - - /* set nbytes for queue status */ - ta_ctx->nbytes = req->nbytes; - - /* Key already done; this is for data */ - dev_dbg(&ta_ctx->sep_used->pdev->dev, "sending data\n"); - - /* check for valid data and proper spacing */ - src_ptr = sg_virt(ta_ctx->src_sg); - dst_ptr = sg_virt(ta_ctx->dst_sg); - - if (!src_ptr || !dst_ptr || - (ta_ctx->current_cypher_req->nbytes % - crypto_ablkcipher_blocksize(tfm))) { - - dev_warn(&ta_ctx->sep_used->pdev->dev, - "cipher block size odd\n"); - dev_warn(&ta_ctx->sep_used->pdev->dev, - "cipher block size is %x\n", - crypto_ablkcipher_blocksize(tfm)); - dev_warn(&ta_ctx->sep_used->pdev->dev, - "cipher data size is %x\n", - ta_ctx->current_cypher_req->nbytes); - return -EINVAL; - } - - if (partial_overlap(src_ptr, dst_ptr, - ta_ctx->current_cypher_req->nbytes)) { - dev_warn(&ta_ctx->sep_used->pdev->dev, - "block partial overlap\n"); - return -EINVAL; - } - - /* Put together the message */ - sep_make_header(ta_ctx, &msg_offset, ta_ctx->block_opcode); - - /* If des, and size is 1 block, put directly in msg */ - if ((ta_ctx->block_opcode == SEP_DES_BLOCK_OPCODE) && - (req->nbytes == crypto_ablkcipher_blocksize(tfm))) { - - dev_dbg(&ta_ctx->sep_used->pdev->dev, - "writing out one block des\n"); - - copy_result = sg_copy_to_buffer( - ta_ctx->src_sg, sep_sg_nents(ta_ctx->src_sg), - small_buf, crypto_ablkcipher_blocksize(tfm)); - - if (copy_result != crypto_ablkcipher_blocksize(tfm)) { - dev_warn(&ta_ctx->sep_used->pdev->dev, - "des block copy failed\n"); - return -ENOMEM; - } - - /* Put data into message */ - sep_write_msg(ta_ctx, small_buf, - crypto_ablkcipher_blocksize(tfm), - crypto_ablkcipher_blocksize(tfm) * 2, - &msg_offset, 1); - - /* Put size into message */ - sep_write_msg(ta_ctx, &req->nbytes, - sizeof(u32), sizeof(u32), &msg_offset, 0); - } else { - /* Otherwise, fill out dma tables */ - ta_ctx->dcb_input_data.app_in_address = src_ptr; - ta_ctx->dcb_input_data.data_in_size = req->nbytes; - ta_ctx->dcb_input_data.app_out_address = dst_ptr; - ta_ctx->dcb_input_data.block_size = - crypto_ablkcipher_blocksize(tfm); - ta_ctx->dcb_input_data.tail_block_size = 0; - ta_ctx->dcb_input_data.is_applet = 0; - ta_ctx->dcb_input_data.src_sg = ta_ctx->src_sg; - ta_ctx->dcb_input_data.dst_sg = ta_ctx->dst_sg; - - result = sep_create_dcb_dmatables_context_kernel( - ta_ctx->sep_used, - &ta_ctx->dcb_region, - &ta_ctx->dmatables_region, - &ta_ctx->dma_ctx, - &ta_ctx->dcb_input_data, - 1); - if (result) { - dev_warn(&ta_ctx->sep_used->pdev->dev, - "crypto dma table create failed\n"); - return -EINVAL; - } - - /* Portion of msg is nulled (no data) */ - msg[0] = (u32)0; - msg[1] = (u32)0; - msg[2] = (u32)0; - msg[3] = (u32)0; - msg[4] = (u32)0; - sep_write_msg(ta_ctx, (void *)msg, sizeof(u32) * 5, - sizeof(u32) * 5, &msg_offset, 0); - } - - /** - * Before we write the message, we need to overwrite the - * vendor's IV with the one from our own ablkcipher walk - * iv because this is needed for dm-crypt - */ - sep_dump_ivs(req, "sending data block to sep\n"); - if ((ta_ctx->current_request == DES_CBC) && - (ta_ctx->des_opmode == SEP_DES_CBC)) { - - dev_dbg(&ta_ctx->sep_used->pdev->dev, - "overwrite vendor iv on DES\n"); - des_internal = (struct sep_des_internal_context *) - sctx->des_private_ctx.ctx_buf; - memcpy((void *)des_internal->iv_context, - ta_ctx->walk.iv, crypto_ablkcipher_ivsize(tfm)); - } else if ((ta_ctx->current_request == AES_CBC) && - (ta_ctx->aes_opmode == SEP_AES_CBC)) { - - dev_dbg(&ta_ctx->sep_used->pdev->dev, - "overwrite vendor iv on AES\n"); - aes_internal = (struct sep_aes_internal_context *) - sctx->aes_private_ctx.cbuff; - memcpy((void *)aes_internal->aes_ctx_iv, - ta_ctx->walk.iv, crypto_ablkcipher_ivsize(tfm)); - } - - /* Write context into message */ - if (ta_ctx->block_opcode == SEP_DES_BLOCK_OPCODE) { - sep_write_context(ta_ctx, &msg_offset, - &sctx->des_private_ctx, - sizeof(struct sep_des_private_context)); - } else { - sep_write_context(ta_ctx, &msg_offset, - &sctx->aes_private_ctx, - sizeof(struct sep_aes_private_context)); - } - - /* conclude message */ - sep_end_msg(ta_ctx, msg_offset); - - /* Parent (caller) is now ready to tell the sep to do ahead */ - return 0; -} - - -/** - * This function sets things up for a crypto key submit process - * This does all preparation, but does not try to grab the - * sep - * @req: pointer to struct ablkcipher_request - * returns: 0 if all went well, non zero if error - */ -static int sep_crypto_send_key(struct ablkcipher_request *req) -{ - - int int_error; - u32 msg_offset; - static u32 msg[10]; - - u32 max_length; - 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, "sending key\n"); - - /* start the walk on scatterlists */ - ablkcipher_walk_init(&ta_ctx->walk, req->src, req->dst, req->nbytes); - dev_dbg(&ta_ctx->sep_used->pdev->dev, - "sep crypto block data size of %x\n", req->nbytes); - - int_error = ablkcipher_walk_phys(req, &ta_ctx->walk); - if (int_error) { - dev_warn(&ta_ctx->sep_used->pdev->dev, "walk phys error %x\n", - int_error); - return -ENOMEM; - } - - /* check iv */ - if ((ta_ctx->current_request == DES_CBC) && - (ta_ctx->des_opmode == SEP_DES_CBC)) { - if (!ta_ctx->walk.iv) { - dev_warn(&ta_ctx->sep_used->pdev->dev, "no iv found\n"); - return -EINVAL; - } - - memcpy(ta_ctx->iv, ta_ctx->walk.iv, SEP_DES_IV_SIZE_BYTES); - } - - if ((ta_ctx->current_request == AES_CBC) && - (ta_ctx->aes_opmode == SEP_AES_CBC)) { - if (!ta_ctx->walk.iv) { - dev_warn(&ta_ctx->sep_used->pdev->dev, "no iv found\n"); - return -EINVAL; - } - - memcpy(ta_ctx->iv, ta_ctx->walk.iv, SEP_AES_IV_SIZE_BYTES); - } - - /* put together message to SEP */ - /* Start with op code */ - sep_make_header(ta_ctx, &msg_offset, ta_ctx->init_opcode); - - /* now deal with IV */ - if (ta_ctx->init_opcode == SEP_DES_INIT_OPCODE) { - if (ta_ctx->des_opmode == SEP_DES_CBC) { - sep_write_msg(ta_ctx, ta_ctx->iv, - SEP_DES_IV_SIZE_BYTES, sizeof(u32) * 4, - &msg_offset, 1); - } else { - /* Skip if ECB */ - msg_offset += 4 * sizeof(u32); - } - } else { - max_length = ((SEP_AES_IV_SIZE_BYTES + 3) / - sizeof(u32)) * sizeof(u32); - if (ta_ctx->aes_opmode == SEP_AES_CBC) { - sep_write_msg(ta_ctx, ta_ctx->iv, - SEP_AES_IV_SIZE_BYTES, max_length, - &msg_offset, 1); - } else { - /* Skip if ECB */ - msg_offset += max_length; - } - } - - /* load the key */ - if (ta_ctx->init_opcode == SEP_DES_INIT_OPCODE) { - sep_write_msg(ta_ctx, (void *)&sctx->key.des.key1, - sizeof(u32) * 8, sizeof(u32) * 8, - &msg_offset, 1); - - msg[0] = (u32)sctx->des_nbr_keys; - msg[1] = (u32)ta_ctx->des_encmode; - msg[2] = (u32)ta_ctx->des_opmode; - - sep_write_msg(ta_ctx, (void *)msg, - sizeof(u32) * 3, sizeof(u32) * 3, - &msg_offset, 0); - } else { - sep_write_msg(ta_ctx, (void *)&sctx->key.aes, - sctx->keylen, - SEP_AES_MAX_KEY_SIZE_BYTES, - &msg_offset, 1); - - msg[0] = (u32)sctx->aes_key_size; - msg[1] = (u32)ta_ctx->aes_encmode; - msg[2] = (u32)ta_ctx->aes_opmode; - msg[3] = (u32)0; /* Secret key is not used */ - sep_write_msg(ta_ctx, (void *)msg, - sizeof(u32) * 4, sizeof(u32) * 4, - &msg_offset, 0); - } - - /* conclude message */ - sep_end_msg(ta_ctx, msg_offset); - - /* Parent (caller) is now ready to tell the sep to do ahead */ - return 0; -} - - -/* This needs to be run as a work queue as it can be put asleep */ -static void sep_crypto_block(void *data) -{ - unsigned long end_time; - - int result; - - struct ablkcipher_request *req; - struct this_task_ctx *ta_ctx; - struct crypto_ablkcipher *tfm; - struct sep_system_ctx *sctx; - int are_we_done_yet; - - req = (struct ablkcipher_request *)data; - ta_ctx = ablkcipher_request_ctx(req); - tfm = crypto_ablkcipher_reqtfm(req); - sctx = crypto_ablkcipher_ctx(tfm); - - ta_ctx->are_we_done_yet = &are_we_done_yet; - - pr_debug("sep_crypto_block\n"); - pr_debug("tfm is %p sctx is %p ta_ctx is %p\n", - tfm, sctx, ta_ctx); - pr_debug("key_sent is %d\n", sctx->key_sent); - - /* do we need to send the key */ - if (sctx->key_sent == 0) { - are_we_done_yet = 0; - result = sep_crypto_send_key(req); /* prep to send key */ - if (result != 0) { - dev_dbg(&ta_ctx->sep_used->pdev->dev, - "could not prep key %x\n", result); - sep_crypto_release(sctx, ta_ctx, result); - return; - } - - result = sep_crypto_take_sep(ta_ctx); - if (result) { - dev_warn(&ta_ctx->sep_used->pdev->dev, - "sep_crypto_take_sep for key send failed\n"); - sep_crypto_release(sctx, ta_ctx, result); - return; - } - - /* now we sit and wait up to a fixed time for completion */ - end_time = jiffies + (WAIT_TIME * HZ); - while ((time_before(jiffies, end_time)) && - (are_we_done_yet == 0)) - schedule(); - - /* Done waiting; still not done yet? */ - if (are_we_done_yet == 0) { - dev_dbg(&ta_ctx->sep_used->pdev->dev, - "Send key job never got done\n"); - sep_crypto_release(sctx, ta_ctx, -EINVAL); - return; - } - - /* Set the key sent variable so this can be skipped later */ - sctx->key_sent = 1; - } - - /* Key sent (or maybe not if we did not have to), now send block */ - are_we_done_yet = 0; - - result = sep_crypto_block_data(req); - - if (result != 0) { - dev_dbg(&ta_ctx->sep_used->pdev->dev, - "could prep not send block %x\n", result); - sep_crypto_release(sctx, ta_ctx, result); - return; - } - - result = sep_crypto_take_sep(ta_ctx); - if (result) { - dev_warn(&ta_ctx->sep_used->pdev->dev, - "sep_crypto_take_sep for block send failed\n"); - sep_crypto_release(sctx, ta_ctx, result); - return; - } - - /* now we sit and wait up to a fixed time for completion */ - end_time = jiffies + (WAIT_TIME * HZ); - while ((time_before(jiffies, end_time)) && (are_we_done_yet == 0)) - schedule(); - - /* Done waiting; still not done yet? */ - if (are_we_done_yet == 0) { - dev_dbg(&ta_ctx->sep_used->pdev->dev, - "Send block job never got done\n"); - sep_crypto_release(sctx, ta_ctx, -EINVAL); - return; - } - - /* That's it; entire thing done, get out of queue */ - - pr_debug("crypto_block leaving\n"); - pr_debug("tfm is %p sctx is %p ta_ctx is %p\n", tfm, sctx, ta_ctx); -} - -/** - * Post operation (after interrupt) for crypto block - */ -static u32 crypto_post_op(struct sep_device *sep) -{ - /* HERE */ - u32 u32_error; - u32 msg_offset; - - ssize_t copy_result; - static char small_buf[100]; - - struct ablkcipher_request *req; - struct this_task_ctx *ta_ctx; - struct sep_system_ctx *sctx; - struct crypto_ablkcipher *tfm; - - struct sep_des_internal_context *des_internal; - struct sep_aes_internal_context *aes_internal; - - if (!sep->current_cypher_req) - return -EINVAL; - - /* hold req since we need to submit work after clearing sep */ - req = sep->current_cypher_req; - - ta_ctx = ablkcipher_request_ctx(sep->current_cypher_req); - tfm = crypto_ablkcipher_reqtfm(sep->current_cypher_req); - sctx = crypto_ablkcipher_ctx(tfm); - - pr_debug("crypto_post op\n"); - pr_debug("key_sent is %d tfm is %p sctx is %p ta_ctx is %p\n", - sctx->key_sent, tfm, sctx, ta_ctx); - - dev_dbg(&ta_ctx->sep_used->pdev->dev, "crypto post_op\n"); - dev_dbg(&ta_ctx->sep_used->pdev->dev, "crypto post_op message dump\n"); - - /* first bring msg from shared area to local area */ - memcpy(ta_ctx->msg, sep->shared_addr, - SEP_DRIVER_MESSAGE_SHARED_AREA_SIZE_IN_BYTES); - - /* Is this the result of performing init (key to SEP */ - if (sctx->key_sent == 0) { - - /* Did SEP do it okay */ - u32_error = sep_verify_op(ta_ctx, ta_ctx->init_opcode, - &msg_offset); - if (u32_error) { - dev_warn(&ta_ctx->sep_used->pdev->dev, - "aes init error %x\n", u32_error); - sep_crypto_release(sctx, ta_ctx, u32_error); - return u32_error; - } - - /* Read Context */ - if (ta_ctx->init_opcode == SEP_DES_INIT_OPCODE) { - sep_read_context(ta_ctx, &msg_offset, - &sctx->des_private_ctx, - sizeof(struct sep_des_private_context)); - } else { - sep_read_context(ta_ctx, &msg_offset, - &sctx->aes_private_ctx, - sizeof(struct sep_aes_private_context)); - } - - sep_dump_ivs(req, "after sending key to sep\n"); - - /* key sent went okay; release sep, and set are_we_done_yet */ - sctx->key_sent = 1; - sep_crypto_release(sctx, ta_ctx, -EINPROGRESS); - - } else { - - /** - * This is the result of a block request - */ - dev_dbg(&ta_ctx->sep_used->pdev->dev, - "crypto_post_op block response\n"); - - u32_error = sep_verify_op(ta_ctx, ta_ctx->block_opcode, - &msg_offset); - - if (u32_error) { - dev_warn(&ta_ctx->sep_used->pdev->dev, - "sep block error %x\n", u32_error); - sep_crypto_release(sctx, ta_ctx, u32_error); - return -EINVAL; - } - - if (ta_ctx->block_opcode == SEP_DES_BLOCK_OPCODE) { - - dev_dbg(&ta_ctx->sep_used->pdev->dev, - "post op for DES\n"); - - /* special case for 1 block des */ - if (sep->current_cypher_req->nbytes == - crypto_ablkcipher_blocksize(tfm)) { - - sep_read_msg(ta_ctx, small_buf, - crypto_ablkcipher_blocksize(tfm), - crypto_ablkcipher_blocksize(tfm) * 2, - &msg_offset, 1); - - dev_dbg(&ta_ctx->sep_used->pdev->dev, - "reading in block des\n"); - - copy_result = sg_copy_from_buffer( - ta_ctx->dst_sg, - sep_sg_nents(ta_ctx->dst_sg), - small_buf, - crypto_ablkcipher_blocksize(tfm)); - - if (copy_result != - crypto_ablkcipher_blocksize(tfm)) { - - dev_warn(&ta_ctx->sep_used->pdev->dev, - "des block copy failed\n"); - sep_crypto_release(sctx, ta_ctx, - -ENOMEM); - return -ENOMEM; - } - } - - /* Read Context */ - sep_read_context(ta_ctx, &msg_offset, - &sctx->des_private_ctx, - sizeof(struct sep_des_private_context)); - } else { - - dev_dbg(&ta_ctx->sep_used->pdev->dev, - "post op for AES\n"); - - /* Skip the MAC Output */ - msg_offset += (sizeof(u32) * 4); - - /* Read Context */ - sep_read_context(ta_ctx, &msg_offset, - &sctx->aes_private_ctx, - sizeof(struct sep_aes_private_context)); - } - - /* Copy to correct sg if this block had oddball pages */ - if (ta_ctx->dst_sg_hold) - sep_copy_sg(ta_ctx->sep_used, - ta_ctx->dst_sg, - ta_ctx->current_cypher_req->dst, - ta_ctx->current_cypher_req->nbytes); - - /** - * Copy the iv's back to the walk.iv - * This is required for dm_crypt - */ - sep_dump_ivs(req, "got data block from sep\n"); - if ((ta_ctx->current_request == DES_CBC) && - (ta_ctx->des_opmode == SEP_DES_CBC)) { - - dev_dbg(&ta_ctx->sep_used->pdev->dev, - "returning result iv to walk on DES\n"); - des_internal = (struct sep_des_internal_context *) - sctx->des_private_ctx.ctx_buf; - memcpy(ta_ctx->walk.iv, - (void *)des_internal->iv_context, - crypto_ablkcipher_ivsize(tfm)); - } else if ((ta_ctx->current_request == AES_CBC) && - (ta_ctx->aes_opmode == SEP_AES_CBC)) { - - dev_dbg(&ta_ctx->sep_used->pdev->dev, - "returning result iv to walk on AES\n"); - aes_internal = (struct sep_aes_internal_context *) - sctx->aes_private_ctx.cbuff; - memcpy(ta_ctx->walk.iv, - (void *)aes_internal->aes_ctx_iv, - crypto_ablkcipher_ivsize(tfm)); - } - - /* finished, release everything */ - sep_crypto_release(sctx, ta_ctx, 0); - } - pr_debug("crypto_post_op done\n"); - pr_debug("key_sent is %d tfm is %p sctx is %p ta_ctx is %p\n", - sctx->key_sent, tfm, sctx, ta_ctx); - - return 0; -} - -static u32 hash_init_post_op(struct sep_device *sep) -{ - u32 u32_error; - u32 msg_offset; - struct crypto_ahash *tfm = crypto_ahash_reqtfm(sep->current_hash_req); - struct this_task_ctx *ta_ctx = ahash_request_ctx(sep->current_hash_req); - struct sep_system_ctx *sctx = crypto_ahash_ctx(tfm); - dev_dbg(&ta_ctx->sep_used->pdev->dev, - "hash init post op\n"); - - /* first bring msg from shared area to local area */ - memcpy(ta_ctx->msg, sep->shared_addr, - SEP_DRIVER_MESSAGE_SHARED_AREA_SIZE_IN_BYTES); - - u32_error = sep_verify_op(ta_ctx, SEP_HASH_INIT_OPCODE, - &msg_offset); - - if (u32_error) { - dev_warn(&ta_ctx->sep_used->pdev->dev, "hash init error %x\n", - u32_error); - sep_crypto_release(sctx, ta_ctx, u32_error); - return u32_error; - } - - /* Read Context */ - sep_read_context(ta_ctx, &msg_offset, - &sctx->hash_private_ctx, - sizeof(struct sep_hash_private_context)); - - /* Signal to crypto infrastructure and clear out */ - dev_dbg(&ta_ctx->sep_used->pdev->dev, "hash init post op done\n"); - sep_crypto_release(sctx, ta_ctx, 0); - return 0; -} - -static u32 hash_update_post_op(struct sep_device *sep) -{ - u32 u32_error; - u32 msg_offset; - struct crypto_ahash *tfm = crypto_ahash_reqtfm(sep->current_hash_req); - struct this_task_ctx *ta_ctx = ahash_request_ctx(sep->current_hash_req); - struct sep_system_ctx *sctx = crypto_ahash_ctx(tfm); - dev_dbg(&ta_ctx->sep_used->pdev->dev, - "hash update post op\n"); - - /* first bring msg from shared area to local area */ - memcpy(ta_ctx->msg, sep->shared_addr, - SEP_DRIVER_MESSAGE_SHARED_AREA_SIZE_IN_BYTES); - - u32_error = sep_verify_op(ta_ctx, SEP_HASH_UPDATE_OPCODE, - &msg_offset); - - if (u32_error) { - dev_warn(&ta_ctx->sep_used->pdev->dev, "hash init error %x\n", - u32_error); - sep_crypto_release(sctx, ta_ctx, u32_error); - return u32_error; - } - - /* Read Context */ - sep_read_context(ta_ctx, &msg_offset, - &sctx->hash_private_ctx, - sizeof(struct sep_hash_private_context)); - - /** - * Following is only for finup; if we just completed the - * data portion of finup, we now need to kick off the - * finish portion of finup. - */ - - if (ta_ctx->sep_used->current_hash_stage == HASH_FINUP_DATA) { - - /* first reset stage to HASH_FINUP_FINISH */ - ta_ctx->sep_used->current_hash_stage = HASH_FINUP_FINISH; - - /* now enqueue the finish operation */ - spin_lock_irq(&queue_lock); - u32_error = crypto_enqueue_request(&sep_queue, - &ta_ctx->sep_used->current_hash_req->base); - spin_unlock_irq(&queue_lock); - - if ((u32_error != 0) && (u32_error != -EINPROGRESS)) { - dev_warn(&ta_ctx->sep_used->pdev->dev, - "spe cypher post op cant queue\n"); - sep_crypto_release(sctx, ta_ctx, u32_error); - return u32_error; - } - - /* schedule the data send */ - u32_error = sep_submit_work(ta_ctx->sep_used->workqueue, - sep_dequeuer, (void *)&sep_queue); - - if (u32_error) { - dev_warn(&ta_ctx->sep_used->pdev->dev, - "cant submit work sep_crypto_block\n"); - sep_crypto_release(sctx, ta_ctx, -EINVAL); - return -EINVAL; - } - } - - /* Signal to crypto infrastructure and clear out */ - dev_dbg(&ta_ctx->sep_used->pdev->dev, "hash update post op done\n"); - sep_crypto_release(sctx, ta_ctx, 0); - return 0; -} - -static u32 hash_final_post_op(struct sep_device *sep) -{ - int max_length; - u32 u32_error; - u32 msg_offset; - struct crypto_ahash *tfm = crypto_ahash_reqtfm(sep->current_hash_req); - struct sep_system_ctx *sctx = crypto_ahash_ctx(tfm); - struct this_task_ctx *ta_ctx = ahash_request_ctx(sep->current_hash_req); - dev_dbg(&ta_ctx->sep_used->pdev->dev, - "hash final post op\n"); - - /* first bring msg from shared area to local area */ - memcpy(ta_ctx->msg, sep->shared_addr, - SEP_DRIVER_MESSAGE_SHARED_AREA_SIZE_IN_BYTES); - - u32_error = sep_verify_op(ta_ctx, SEP_HASH_FINISH_OPCODE, - &msg_offset); - - if (u32_error) { - dev_warn(&ta_ctx->sep_used->pdev->dev, "hash finish error %x\n", - u32_error); - sep_crypto_release(sctx, ta_ctx, u32_error); - return u32_error; - } - - /* Grab the result */ - if (ta_ctx->current_hash_req->result == NULL) { - /* Oops, null buffer; error out here */ - dev_warn(&ta_ctx->sep_used->pdev->dev, - "hash finish null buffer\n"); - sep_crypto_release(sctx, ta_ctx, (u32)-ENOMEM); - return -ENOMEM; - } - - max_length = (((SEP_HASH_RESULT_SIZE_WORDS * sizeof(u32)) + 3) / - sizeof(u32)) * sizeof(u32); - - sep_read_msg(ta_ctx, - ta_ctx->current_hash_req->result, - crypto_ahash_digestsize(tfm), max_length, - &msg_offset, 0); - - /* Signal to crypto infrastructure and clear out */ - dev_dbg(&ta_ctx->sep_used->pdev->dev, "hash finish post op done\n"); - sep_crypto_release(sctx, ta_ctx, 0); - return 0; -} - -static u32 hash_digest_post_op(struct sep_device *sep) -{ - int max_length; - u32 u32_error; - u32 msg_offset; - struct crypto_ahash *tfm = crypto_ahash_reqtfm(sep->current_hash_req); - struct sep_system_ctx *sctx = crypto_ahash_ctx(tfm); - struct this_task_ctx *ta_ctx = ahash_request_ctx(sep->current_hash_req); - dev_dbg(&ta_ctx->sep_used->pdev->dev, - "hash digest post op\n"); - - /* first bring msg from shared area to local area */ - memcpy(ta_ctx->msg, sep->shared_addr, - SEP_DRIVER_MESSAGE_SHARED_AREA_SIZE_IN_BYTES); - - u32_error = sep_verify_op(ta_ctx, SEP_HASH_SINGLE_OPCODE, - &msg_offset); - - if (u32_error) { - dev_warn(&ta_ctx->sep_used->pdev->dev, - "hash digest finish error %x\n", u32_error); - - sep_crypto_release(sctx, ta_ctx, u32_error); - return u32_error; - } - - /* Grab the result */ - if (ta_ctx->current_hash_req->result == NULL) { - /* Oops, null buffer; error out here */ - dev_warn(&ta_ctx->sep_used->pdev->dev, - "hash digest finish null buffer\n"); - sep_crypto_release(sctx, ta_ctx, (u32)-ENOMEM); - return -ENOMEM; - } - - max_length = (((SEP_HASH_RESULT_SIZE_WORDS * sizeof(u32)) + 3) / - sizeof(u32)) * sizeof(u32); - - sep_read_msg(ta_ctx, - ta_ctx->current_hash_req->result, - crypto_ahash_digestsize(tfm), max_length, - &msg_offset, 0); - - /* Signal to crypto infrastructure and clear out */ - dev_dbg(&ta_ctx->sep_used->pdev->dev, - "hash digest finish post op done\n"); - - sep_crypto_release(sctx, ta_ctx, 0); - return 0; -} - -/** - * The sep_finish function is the function that is scheduled (via tasklet) - * by the interrupt service routine when the SEP sends and interrupt - * This is only called by the interrupt handler as a tasklet. - */ -static void sep_finish(unsigned long data) -{ - struct sep_device *sep_dev; - int res; - - res = 0; - - if (data == 0) { - pr_debug("sep_finish called with null data\n"); - return; - } - - sep_dev = (struct sep_device *)data; - if (sep_dev == NULL) { - pr_debug("sep_finish; sep_dev is NULL\n"); - return; - } - - if (sep_dev->in_kernel == (u32)0) { - dev_warn(&sep_dev->pdev->dev, - "sep_finish; not in kernel operation\n"); - return; - } - - /* Did we really do a sep command prior to this? */ - if (0 == test_bit(SEP_LEGACY_SENDMSG_DONE_OFFSET, - &sep_dev->ta_ctx->call_status.status)) { - - dev_warn(&sep_dev->pdev->dev, "[PID%d] sendmsg not called\n", - current->pid); - return; - } - - if (sep_dev->send_ct != sep_dev->reply_ct) { - dev_warn(&sep_dev->pdev->dev, - "[PID%d] poll; no message came back\n", - current->pid); - return; - } - - /* Check for error (In case time ran out) */ - if ((res != 0x0) && (res != 0x8)) { - dev_warn(&sep_dev->pdev->dev, - "[PID%d] poll; poll error GPR3 is %x\n", - current->pid, res); - return; - } - - /* What kind of interrupt from sep was this? */ - res = sep_read_reg(sep_dev, HW_HOST_SEP_HOST_GPR2_REG_ADDR); - - dev_dbg(&sep_dev->pdev->dev, "[PID%d] GPR2 at crypto finish is %x\n", - current->pid, res); - - /* Print request? */ - if ((res >> 30) & 0x1) { - dev_dbg(&sep_dev->pdev->dev, "[PID%d] sep print req\n", - current->pid); - dev_dbg(&sep_dev->pdev->dev, "[PID%d] contents: %s\n", - current->pid, - (char *)(sep_dev->shared_addr + - SEP_DRIVER_PRINTF_OFFSET_IN_BYTES)); - return; - } - - /* Request for daemon (not currently in POR)? */ - if (res >> 31) { - dev_dbg(&sep_dev->pdev->dev, - "[PID%d] sep request; ignoring\n", - current->pid); - return; - } - - /* If we got here, then we have a replay to a sep command */ - - dev_dbg(&sep_dev->pdev->dev, - "[PID%d] sep reply to command; processing request: %x\n", - current->pid, sep_dev->current_request); - - switch (sep_dev->current_request) { - case AES_CBC: - case AES_ECB: - case DES_CBC: - case DES_ECB: - res = crypto_post_op(sep_dev); - break; - case SHA1: - case MD5: - case SHA224: - case SHA256: - switch (sep_dev->current_hash_stage) { - case HASH_INIT: - res = hash_init_post_op(sep_dev); - break; - case HASH_UPDATE: - case HASH_FINUP_DATA: - res = hash_update_post_op(sep_dev); - break; - case HASH_FINUP_FINISH: - case HASH_FINISH: - res = hash_final_post_op(sep_dev); - break; - case HASH_DIGEST: - res = hash_digest_post_op(sep_dev); - break; - default: - pr_debug("sep - invalid stage for hash finish\n"); - } - break; - default: - pr_debug("sep - invalid request for finish\n"); - } - - if (res) - pr_debug("sep - finish returned error %x\n", res); -} - -static int sep_hash_cra_init(struct crypto_tfm *tfm) - { - const char *alg_name = crypto_tfm_alg_name(tfm); - - pr_debug("sep_hash_cra_init name is %s\n", alg_name); - - crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm), - sizeof(struct this_task_ctx)); - return 0; - } - -static void sep_hash_cra_exit(struct crypto_tfm *tfm) -{ - pr_debug("sep_hash_cra_exit\n"); -} - -static void sep_hash_init(void *data) -{ - u32 msg_offset; - int result; - struct ahash_request *req; - struct crypto_ahash *tfm; - struct this_task_ctx *ta_ctx; - struct sep_system_ctx *sctx; - unsigned long end_time; - int are_we_done_yet; - - req = (struct ahash_request *)data; - tfm = crypto_ahash_reqtfm(req); - sctx = crypto_ahash_ctx(tfm); - ta_ctx = ahash_request_ctx(req); - ta_ctx->sep_used = sep_dev; - - ta_ctx->are_we_done_yet = &are_we_done_yet; - - dev_dbg(&ta_ctx->sep_used->pdev->dev, - "sep_hash_init\n"); - ta_ctx->current_hash_stage = HASH_INIT; - /* opcode and mode */ - sep_make_header(ta_ctx, &msg_offset, SEP_HASH_INIT_OPCODE); - sep_write_msg(ta_ctx, &ta_ctx->hash_opmode, - sizeof(u32), sizeof(u32), &msg_offset, 0); - sep_end_msg(ta_ctx, msg_offset); - - are_we_done_yet = 0; - result = sep_crypto_take_sep(ta_ctx); - if (result) { - dev_warn(&ta_ctx->sep_used->pdev->dev, - "sep_hash_init take sep failed\n"); - sep_crypto_release(sctx, ta_ctx, -EINVAL); - } - - /* now we sit and wait up to a fixed time for completion */ - end_time = jiffies + (WAIT_TIME * HZ); - while ((time_before(jiffies, end_time)) && (are_we_done_yet == 0)) - schedule(); - - /* Done waiting; still not done yet? */ - if (are_we_done_yet == 0) { - dev_dbg(&ta_ctx->sep_used->pdev->dev, - "hash init never got done\n"); - sep_crypto_release(sctx, ta_ctx, -EINVAL); - return; - } - -} - -static void sep_hash_update(void *data) -{ - int int_error; - u32 msg_offset; - u32 len; - struct sep_hash_internal_context *int_ctx; - u32 block_size; - u32 head_len; - u32 tail_len; - int are_we_done_yet; - - static u32 msg[10]; - static char small_buf[100]; - void *src_ptr; - struct scatterlist *new_sg; - ssize_t copy_result; - struct ahash_request *req; - struct crypto_ahash *tfm; - struct this_task_ctx *ta_ctx; - struct sep_system_ctx *sctx; - unsigned long end_time; - - req = (struct ahash_request *)data; - tfm = crypto_ahash_reqtfm(req); - sctx = crypto_ahash_ctx(tfm); - ta_ctx = ahash_request_ctx(req); - ta_ctx->sep_used = sep_dev; - - ta_ctx->are_we_done_yet = &are_we_done_yet; - - /* length for queue status */ - ta_ctx->nbytes = req->nbytes; - - dev_dbg(&ta_ctx->sep_used->pdev->dev, - "sep_hash_update\n"); - ta_ctx->current_hash_stage = HASH_UPDATE; - len = req->nbytes; - - block_size = crypto_tfm_alg_blocksize(crypto_ahash_tfm(tfm)); - tail_len = req->nbytes % block_size; - dev_dbg(&ta_ctx->sep_used->pdev->dev, "length is %x\n", len); - dev_dbg(&ta_ctx->sep_used->pdev->dev, "block_size is %x\n", block_size); - dev_dbg(&ta_ctx->sep_used->pdev->dev, "tail len is %x\n", tail_len); - - /* Compute header/tail sizes */ - int_ctx = (struct sep_hash_internal_context *)&sctx-> - hash_private_ctx.internal_context; - head_len = (block_size - int_ctx->prev_update_bytes) % block_size; - tail_len = (req->nbytes - head_len) % block_size; - - /* Make sure all pages are an even block */ - int_error = sep_oddball_pages(ta_ctx->sep_used, req->src, - req->nbytes, - block_size, &new_sg, 1); - - if (int_error < 0) { - dev_warn(&ta_ctx->sep_used->pdev->dev, - "oddball pages error in crash update\n"); - sep_crypto_release(sctx, ta_ctx, -ENOMEM); - return; - } else if (int_error == 1) { - ta_ctx->src_sg = new_sg; - ta_ctx->src_sg_hold = new_sg; - } else { - ta_ctx->src_sg = req->src; - ta_ctx->src_sg_hold = NULL; - } - - src_ptr = sg_virt(ta_ctx->src_sg); - - if ((!req->nbytes) || (!ta_ctx->src_sg)) { - /* null data */ - src_ptr = NULL; - } - - ta_ctx->dcb_input_data.app_in_address = src_ptr; - ta_ctx->dcb_input_data.data_in_size = - req->nbytes - (head_len + tail_len); - ta_ctx->dcb_input_data.app_out_address = NULL; - ta_ctx->dcb_input_data.block_size = block_size; - ta_ctx->dcb_input_data.tail_block_size = 0; - ta_ctx->dcb_input_data.is_applet = 0; - ta_ctx->dcb_input_data.src_sg = ta_ctx->src_sg; - ta_ctx->dcb_input_data.dst_sg = NULL; - - int_error = sep_create_dcb_dmatables_context_kernel( - ta_ctx->sep_used, - &ta_ctx->dcb_region, - &ta_ctx->dmatables_region, - &ta_ctx->dma_ctx, - &ta_ctx->dcb_input_data, - 1); - if (int_error) { - dev_warn(&ta_ctx->sep_used->pdev->dev, - "hash update dma table create failed\n"); - sep_crypto_release(sctx, ta_ctx, -EINVAL); - return; - } - - /* Construct message to SEP */ - sep_make_header(ta_ctx, &msg_offset, SEP_HASH_UPDATE_OPCODE); - - msg[0] = (u32)0; - msg[1] = (u32)0; - msg[2] = (u32)0; - - sep_write_msg(ta_ctx, msg, sizeof(u32) * 3, sizeof(u32) * 3, - &msg_offset, 0); - - /* Handle remainders */ - - /* Head */ - sep_write_msg(ta_ctx, &head_len, sizeof(u32), - sizeof(u32), &msg_offset, 0); - - if (head_len) { - copy_result = sg_copy_to_buffer( - req->src, - sep_sg_nents(ta_ctx->src_sg), - small_buf, head_len); - - if (copy_result != head_len) { - dev_warn(&ta_ctx->sep_used->pdev->dev, - "sg head copy failure in hash block\n"); - sep_crypto_release(sctx, ta_ctx, -ENOMEM); - return; - } - - sep_write_msg(ta_ctx, small_buf, head_len, - sizeof(u32) * 32, &msg_offset, 1); - } else { - msg_offset += sizeof(u32) * 32; - } - - /* Tail */ - sep_write_msg(ta_ctx, &tail_len, sizeof(u32), - sizeof(u32), &msg_offset, 0); - - if (tail_len) { - copy_result = sep_copy_offset_sg( - ta_ctx->sep_used, - ta_ctx->src_sg, - req->nbytes - tail_len, - small_buf, tail_len); - - if (copy_result != tail_len) { - dev_warn(&ta_ctx->sep_used->pdev->dev, - "sg tail copy failure in hash block\n"); - sep_crypto_release(sctx, ta_ctx, -ENOMEM); - return; - } - - sep_write_msg(ta_ctx, small_buf, tail_len, - sizeof(u32) * 32, &msg_offset, 1); - } else { - msg_offset += sizeof(u32) * 32; - } - - /* Context */ - sep_write_context(ta_ctx, &msg_offset, &sctx->hash_private_ctx, - sizeof(struct sep_hash_private_context)); - - sep_end_msg(ta_ctx, msg_offset); - are_we_done_yet = 0; - int_error = sep_crypto_take_sep(ta_ctx); - if (int_error) { - dev_warn(&ta_ctx->sep_used->pdev->dev, - "sep_hash_update take sep failed\n"); - sep_crypto_release(sctx, ta_ctx, -EINVAL); - } - - /* now we sit and wait up to a fixed time for completion */ - end_time = jiffies + (WAIT_TIME * HZ); - while ((time_before(jiffies, end_time)) && (are_we_done_yet == 0)) - schedule(); - - /* Done waiting; still not done yet? */ - if (are_we_done_yet == 0) { - dev_dbg(&ta_ctx->sep_used->pdev->dev, - "hash update never got done\n"); - sep_crypto_release(sctx, ta_ctx, -EINVAL); - return; - } - -} - -static void sep_hash_final(void *data) -{ - u32 msg_offset; - struct ahash_request *req; - struct crypto_ahash *tfm; - struct this_task_ctx *ta_ctx; - struct sep_system_ctx *sctx; - int result; - unsigned long end_time; - int are_we_done_yet; - - req = (struct ahash_request *)data; - tfm = crypto_ahash_reqtfm(req); - sctx = crypto_ahash_ctx(tfm); - ta_ctx = ahash_request_ctx(req); - ta_ctx->sep_used = sep_dev; - - dev_dbg(&ta_ctx->sep_used->pdev->dev, - "sep_hash_final\n"); - ta_ctx->current_hash_stage = HASH_FINISH; - - ta_ctx->are_we_done_yet = &are_we_done_yet; - - /* opcode and mode */ - sep_make_header(ta_ctx, &msg_offset, SEP_HASH_FINISH_OPCODE); - - /* Context */ - sep_write_context(ta_ctx, &msg_offset, &sctx->hash_private_ctx, - sizeof(struct sep_hash_private_context)); - - sep_end_msg(ta_ctx, msg_offset); - are_we_done_yet = 0; - result = sep_crypto_take_sep(ta_ctx); - if (result) { - dev_warn(&ta_ctx->sep_used->pdev->dev, - "sep_hash_final take sep failed\n"); - sep_crypto_release(sctx, ta_ctx, -EINVAL); - } - - /* now we sit and wait up to a fixed time for completion */ - end_time = jiffies + (WAIT_TIME * HZ); - while ((time_before(jiffies, end_time)) && (are_we_done_yet == 0)) - schedule(); - - /* Done waiting; still not done yet? */ - if (are_we_done_yet == 0) { - dev_dbg(&ta_ctx->sep_used->pdev->dev, - "hash final job never got done\n"); - sep_crypto_release(sctx, ta_ctx, -EINVAL); - return; - } - -} - -static void sep_hash_digest(void *data) -{ - int int_error; - u32 msg_offset; - u32 block_size; - u32 msg[10]; - size_t copy_result; - int result; - int are_we_done_yet; - u32 tail_len; - static char small_buf[100]; - struct scatterlist *new_sg; - void *src_ptr; - - struct ahash_request *req; - struct crypto_ahash *tfm; - struct this_task_ctx *ta_ctx; - struct sep_system_ctx *sctx; - unsigned long end_time; - - req = (struct ahash_request *)data; - tfm = crypto_ahash_reqtfm(req); - sctx = crypto_ahash_ctx(tfm); - ta_ctx = ahash_request_ctx(req); - ta_ctx->sep_used = sep_dev; - - dev_dbg(&ta_ctx->sep_used->pdev->dev, - "sep_hash_digest\n"); - ta_ctx->current_hash_stage = HASH_DIGEST; - - ta_ctx->are_we_done_yet = &are_we_done_yet; - - /* length for queue status */ - ta_ctx->nbytes = req->nbytes; - - block_size = crypto_tfm_alg_blocksize(crypto_ahash_tfm(tfm)); - tail_len = req->nbytes % block_size; - dev_dbg(&ta_ctx->sep_used->pdev->dev, "length is %x\n", req->nbytes); - dev_dbg(&ta_ctx->sep_used->pdev->dev, "block_size is %x\n", block_size); - dev_dbg(&ta_ctx->sep_used->pdev->dev, "tail len is %x\n", tail_len); - - /* Make sure all pages are an even block */ - int_error = sep_oddball_pages(ta_ctx->sep_used, req->src, - req->nbytes, - block_size, &new_sg, 1); - - if (int_error < 0) { - dev_warn(&ta_ctx->sep_used->pdev->dev, - "oddball pages error in crash update\n"); - sep_crypto_release(sctx, ta_ctx, -ENOMEM); - return; - } else if (int_error == 1) { - ta_ctx->src_sg = new_sg; - ta_ctx->src_sg_hold = new_sg; - } else { - ta_ctx->src_sg = req->src; - ta_ctx->src_sg_hold = NULL; - } - - src_ptr = sg_virt(ta_ctx->src_sg); - - if ((!req->nbytes) || (!ta_ctx->src_sg)) { - /* null data */ - src_ptr = NULL; - } - - ta_ctx->dcb_input_data.app_in_address = src_ptr; - ta_ctx->dcb_input_data.data_in_size = req->nbytes - tail_len; - ta_ctx->dcb_input_data.app_out_address = NULL; - ta_ctx->dcb_input_data.block_size = block_size; - ta_ctx->dcb_input_data.tail_block_size = 0; - ta_ctx->dcb_input_data.is_applet = 0; - ta_ctx->dcb_input_data.src_sg = ta_ctx->src_sg; - ta_ctx->dcb_input_data.dst_sg = NULL; - - int_error = sep_create_dcb_dmatables_context_kernel( - ta_ctx->sep_used, - &ta_ctx->dcb_region, - &ta_ctx->dmatables_region, - &ta_ctx->dma_ctx, - &ta_ctx->dcb_input_data, - 1); - if (int_error) { - dev_warn(&ta_ctx->sep_used->pdev->dev, - "hash update dma table create failed\n"); - sep_crypto_release(sctx, ta_ctx, -EINVAL); - return; - } - - /* Construct message to SEP */ - sep_make_header(ta_ctx, &msg_offset, SEP_HASH_SINGLE_OPCODE); - sep_write_msg(ta_ctx, &ta_ctx->hash_opmode, - sizeof(u32), sizeof(u32), &msg_offset, 0); - - msg[0] = (u32)0; - msg[1] = (u32)0; - msg[2] = (u32)0; - - sep_write_msg(ta_ctx, msg, sizeof(u32) * 3, sizeof(u32) * 3, - &msg_offset, 0); - - /* Tail */ - sep_write_msg(ta_ctx, &tail_len, sizeof(u32), - sizeof(u32), &msg_offset, 0); - - if (tail_len) { - copy_result = sep_copy_offset_sg( - ta_ctx->sep_used, - ta_ctx->src_sg, - req->nbytes - tail_len, - small_buf, tail_len); - - if (copy_result != tail_len) { - dev_warn(&ta_ctx->sep_used->pdev->dev, - "sg tail copy failure in hash block\n"); - sep_crypto_release(sctx, ta_ctx, -ENOMEM); - return; - } - - sep_write_msg(ta_ctx, small_buf, tail_len, - sizeof(u32) * 32, &msg_offset, 1); - } else { - msg_offset += sizeof(u32) * 32; - } - - sep_end_msg(ta_ctx, msg_offset); - - are_we_done_yet = 0; - result = sep_crypto_take_sep(ta_ctx); - if (result) { - dev_warn(&ta_ctx->sep_used->pdev->dev, - "sep_hash_digest take sep failed\n"); - sep_crypto_release(sctx, ta_ctx, -EINVAL); - } - - /* now we sit and wait up to a fixed time for completion */ - end_time = jiffies + (WAIT_TIME * HZ); - while ((time_before(jiffies, end_time)) && (are_we_done_yet == 0)) - schedule(); - - /* Done waiting; still not done yet? */ - if (are_we_done_yet == 0) { - dev_dbg(&ta_ctx->sep_used->pdev->dev, - "hash digest job never got done\n"); - sep_crypto_release(sctx, ta_ctx, -EINVAL); - return; - } - -} - -/** - * This is what is called by each of the API's provided - * in the kernel crypto descriptors. It is run in a process - * context using the kernel workqueues. Therefore it can - * be put to sleep. - */ -static void sep_dequeuer(void *data) -{ - struct crypto_queue *this_queue; - struct crypto_async_request *async_req; - struct crypto_async_request *backlog; - struct ablkcipher_request *cypher_req; - struct ahash_request *hash_req; - struct sep_system_ctx *sctx; - struct crypto_ahash *hash_tfm; - struct this_task_ctx *ta_ctx; - - - this_queue = (struct crypto_queue *)data; - - spin_lock_irq(&queue_lock); - backlog = crypto_get_backlog(this_queue); - async_req = crypto_dequeue_request(this_queue); - spin_unlock_irq(&queue_lock); - - if (!async_req) { - pr_debug("sep crypto queue is empty\n"); - return; - } - - if (backlog) { - pr_debug("sep crypto backlog set\n"); - if (backlog->complete) - backlog->complete(backlog, -EINPROGRESS); - backlog = NULL; - } - - if (!async_req->tfm) { - pr_debug("sep crypto queue null tfm\n"); - return; - } - - if (!async_req->tfm->__crt_alg) { - pr_debug("sep crypto queue null __crt_alg\n"); - return; - } - - if (!async_req->tfm->__crt_alg->cra_type) { - pr_debug("sep crypto queue null cra_type\n"); - return; - } - - /* we have stuff in the queue */ - if (async_req->tfm->__crt_alg->cra_type != - &crypto_ahash_type) { - /* This is for a cypher */ - pr_debug("sep crypto queue doing cipher\n"); - cypher_req = container_of(async_req, - struct ablkcipher_request, - base); - if (!cypher_req) { - pr_debug("sep crypto queue null cypher_req\n"); - return; - } - - sep_crypto_block((void *)cypher_req); - return; - } else { - /* This is a hash */ - pr_debug("sep crypto queue doing hash\n"); - /** - * This is a bit more complex than cipher; we - * need to figure out what type of operation - */ - hash_req = ahash_request_cast(async_req); - if (!hash_req) { - pr_debug("sep crypto queue null hash_req\n"); - return; - } - - hash_tfm = crypto_ahash_reqtfm(hash_req); - if (!hash_tfm) { - pr_debug("sep crypto queue null hash_tfm\n"); - return; - } - - - sctx = crypto_ahash_ctx(hash_tfm); - if (!sctx) { - pr_debug("sep crypto queue null sctx\n"); - return; - } - - ta_ctx = ahash_request_ctx(hash_req); - - if (ta_ctx->current_hash_stage == HASH_INIT) { - pr_debug("sep crypto queue hash init\n"); - sep_hash_init((void *)hash_req); - return; - } else if (ta_ctx->current_hash_stage == HASH_UPDATE) { - pr_debug("sep crypto queue hash update\n"); - sep_hash_update((void *)hash_req); - return; - } else if (ta_ctx->current_hash_stage == HASH_FINISH) { - pr_debug("sep crypto queue hash final\n"); - sep_hash_final((void *)hash_req); - return; - } else if (ta_ctx->current_hash_stage == HASH_DIGEST) { - pr_debug("sep crypto queue hash digest\n"); - sep_hash_digest((void *)hash_req); - return; - } else if (ta_ctx->current_hash_stage == HASH_FINUP_DATA) { - pr_debug("sep crypto queue hash digest\n"); - sep_hash_update((void *)hash_req); - return; - } else if (ta_ctx->current_hash_stage == HASH_FINUP_FINISH) { - pr_debug("sep crypto queue hash digest\n"); - sep_hash_final((void *)hash_req); - return; - } else { - pr_debug("sep crypto queue hash oops nothing\n"); - return; - } - } -} - -static int sep_sha1_init(struct ahash_request *req) -{ - int error; - int error1; - struct this_task_ctx *ta_ctx = ahash_request_ctx(req); - - pr_debug("sep - doing sha1 init\n"); - - /* Clear out task context */ - memset(ta_ctx, 0, sizeof(struct this_task_ctx)); - - ta_ctx->sep_used = sep_dev; - ta_ctx->current_request = SHA1; - ta_ctx->current_hash_req = req; - ta_ctx->current_cypher_req = NULL; - ta_ctx->hash_opmode = SEP_HASH_SHA1; - ta_ctx->current_hash_stage = HASH_INIT; - - /* lock necessary so that only one entity touches the queues */ - spin_lock_irq(&queue_lock); - error = crypto_enqueue_request(&sep_queue, &req->base); - - if ((error != 0) && (error != -EINPROGRESS)) - pr_debug(" sep - crypto enqueue failed: %x\n", - error); - error1 = sep_submit_work(ta_ctx->sep_used->workqueue, - sep_dequeuer, (void *)&sep_queue); - if (error1) - pr_debug(" sep - workqueue submit failed: %x\n", - error1); - spin_unlock_irq(&queue_lock); - /* We return result of crypto enqueue */ - return error; -} - -static int sep_sha1_update(struct ahash_request *req) -{ - int error; - int error1; - struct this_task_ctx *ta_ctx = ahash_request_ctx(req); - - pr_debug("sep - doing sha1 update\n"); - - ta_ctx->sep_used = sep_dev; - ta_ctx->current_request = SHA1; - ta_ctx->current_hash_req = req; - ta_ctx->current_cypher_req = NULL; - ta_ctx->hash_opmode = SEP_HASH_SHA1; - ta_ctx->current_hash_stage = HASH_UPDATE; - - /* lock necessary so that only one entity touches the queues */ - spin_lock_irq(&queue_lock); - error = crypto_enqueue_request(&sep_queue, &req->base); - - if ((error != 0) && (error != -EINPROGRESS)) - pr_debug(" sep - crypto enqueue failed: %x\n", - error); - error1 = sep_submit_work(ta_ctx->sep_used->workqueue, - sep_dequeuer, (void *)&sep_queue); - if (error1) - pr_debug(" sep - workqueue submit failed: %x\n", - error1); - spin_unlock_irq(&queue_lock); - /* We return result of crypto enqueue */ - return error; -} - -static int sep_sha1_final(struct ahash_request *req) -{ - int error; - int error1; - struct this_task_ctx *ta_ctx = ahash_request_ctx(req); - pr_debug("sep - doing sha1 final\n"); - - ta_ctx->sep_used = sep_dev; - ta_ctx->current_request = SHA1; - ta_ctx->current_hash_req = req; - ta_ctx->current_cypher_req = NULL; - ta_ctx->hash_opmode = SEP_HASH_SHA1; - ta_ctx->current_hash_stage = HASH_FINISH; - - /* lock necessary so that only one entity touches the queues */ - spin_lock_irq(&queue_lock); - error = crypto_enqueue_request(&sep_queue, &req->base); - - if ((error != 0) && (error != -EINPROGRESS)) - pr_debug(" sep - crypto enqueue failed: %x\n", - error); - error1 = sep_submit_work(ta_ctx->sep_used->workqueue, - sep_dequeuer, (void *)&sep_queue); - if (error1) - pr_debug(" sep - workqueue submit failed: %x\n", - error1); - spin_unlock_irq(&queue_lock); - /* We return result of crypto enqueue */ - return error; -} - -static int sep_sha1_digest(struct ahash_request *req) -{ - int error; - int error1; - struct this_task_ctx *ta_ctx = ahash_request_ctx(req); - pr_debug("sep - doing sha1 digest\n"); - - /* Clear out task context */ - memset(ta_ctx, 0, sizeof(struct this_task_ctx)); - - ta_ctx->sep_used = sep_dev; - ta_ctx->current_request = SHA1; - ta_ctx->current_hash_req = req; - ta_ctx->current_cypher_req = NULL; - ta_ctx->hash_opmode = SEP_HASH_SHA1; - ta_ctx->current_hash_stage = HASH_DIGEST; - - /* lock necessary so that only one entity touches the queues */ - spin_lock_irq(&queue_lock); - error = crypto_enqueue_request(&sep_queue, &req->base); - - if ((error != 0) && (error != -EINPROGRESS)) - pr_debug(" sep - crypto enqueue failed: %x\n", - error); - error1 = sep_submit_work(ta_ctx->sep_used->workqueue, - sep_dequeuer, (void *)&sep_queue); - if (error1) - pr_debug(" sep - workqueue submit failed: %x\n", - error1); - spin_unlock_irq(&queue_lock); - /* We return result of crypto enqueue */ - return error; -} - -static int sep_sha1_finup(struct ahash_request *req) -{ - int error; - int error1; - struct this_task_ctx *ta_ctx = ahash_request_ctx(req); - pr_debug("sep - doing sha1 finup\n"); - - ta_ctx->sep_used = sep_dev; - ta_ctx->current_request = SHA1; - ta_ctx->current_hash_req = req; - ta_ctx->current_cypher_req = NULL; - ta_ctx->hash_opmode = SEP_HASH_SHA1; - ta_ctx->current_hash_stage = HASH_FINUP_DATA; - - /* lock necessary so that only one entity touches the queues */ - spin_lock_irq(&queue_lock); - error = crypto_enqueue_request(&sep_queue, &req->base); - - if ((error != 0) && (error != -EINPROGRESS)) - pr_debug(" sep - crypto enqueue failed: %x\n", - error); - error1 = sep_submit_work(ta_ctx->sep_used->workqueue, - sep_dequeuer, (void *)&sep_queue); - if (error1) - pr_debug(" sep - workqueue submit failed: %x\n", - error1); - spin_unlock_irq(&queue_lock); - /* We return result of crypto enqueue */ - return error; -} - -static int sep_md5_init(struct ahash_request *req) -{ - int error; - int error1; - struct this_task_ctx *ta_ctx = ahash_request_ctx(req); - pr_debug("sep - doing md5 init\n"); - - /* Clear out task context */ - memset(ta_ctx, 0, sizeof(struct this_task_ctx)); - - ta_ctx->sep_used = sep_dev; - ta_ctx->current_request = MD5; - ta_ctx->current_hash_req = req; - ta_ctx->current_cypher_req = NULL; - ta_ctx->hash_opmode = SEP_HASH_MD5; - ta_ctx->current_hash_stage = HASH_INIT; - - /* lock necessary so that only one entity touches the queues */ - spin_lock_irq(&queue_lock); - error = crypto_enqueue_request(&sep_queue, &req->base); - - if ((error != 0) && (error != -EINPROGRESS)) - pr_debug(" sep - crypto enqueue failed: %x\n", - error); - error1 = sep_submit_work(ta_ctx->sep_used->workqueue, - sep_dequeuer, (void *)&sep_queue); - if (error1) - pr_debug(" sep - workqueue submit failed: %x\n", - error1); - spin_unlock_irq(&queue_lock); - /* We return result of crypto enqueue */ - return error; -} - -static int sep_md5_update(struct ahash_request *req) -{ - int error; - int error1; - struct this_task_ctx *ta_ctx = ahash_request_ctx(req); - pr_debug("sep - doing md5 update\n"); - - ta_ctx->sep_used = sep_dev; - ta_ctx->current_request = MD5; - ta_ctx->current_hash_req = req; - ta_ctx->current_cypher_req = NULL; - ta_ctx->hash_opmode = SEP_HASH_MD5; - ta_ctx->current_hash_stage = HASH_UPDATE; - - /* lock necessary so that only one entity touches the queues */ - spin_lock_irq(&queue_lock); - error = crypto_enqueue_request(&sep_queue, &req->base); - - if ((error != 0) && (error != -EINPROGRESS)) - pr_debug(" sep - crypto enqueue failed: %x\n", - error); - error1 = sep_submit_work(ta_ctx->sep_used->workqueue, - sep_dequeuer, (void *)&sep_queue); - if (error1) - pr_debug(" sep - workqueue submit failed: %x\n", - error1); - spin_unlock_irq(&queue_lock); - /* We return result of crypto enqueue */ - return error; -} - -static int sep_md5_final(struct ahash_request *req) -{ - int error; - int error1; - struct this_task_ctx *ta_ctx = ahash_request_ctx(req); - pr_debug("sep - doing md5 final\n"); - - ta_ctx->sep_used = sep_dev; - ta_ctx->current_request = MD5; - ta_ctx->current_hash_req = req; - ta_ctx->current_cypher_req = NULL; - ta_ctx->hash_opmode = SEP_HASH_MD5; - ta_ctx->current_hash_stage = HASH_FINISH; - - /* lock necessary so that only one entity touches the queues */ - spin_lock_irq(&queue_lock); - error = crypto_enqueue_request(&sep_queue, &req->base); - - if ((error != 0) && (error != -EINPROGRESS)) - pr_debug(" sep - crypto enqueue failed: %x\n", - error); - error1 = sep_submit_work(ta_ctx->sep_used->workqueue, - sep_dequeuer, (void *)&sep_queue); - if (error1) - pr_debug(" sep - workqueue submit failed: %x\n", - error1); - spin_unlock_irq(&queue_lock); - /* We return result of crypto enqueue */ - return error; -} - -static int sep_md5_digest(struct ahash_request *req) -{ - int error; - int error1; - struct this_task_ctx *ta_ctx = ahash_request_ctx(req); - - pr_debug("sep - doing md5 digest\n"); - - /* Clear out task context */ - memset(ta_ctx, 0, sizeof(struct this_task_ctx)); - - ta_ctx->sep_used = sep_dev; - ta_ctx->current_request = MD5; - ta_ctx->current_hash_req = req; - ta_ctx->current_cypher_req = NULL; - ta_ctx->hash_opmode = SEP_HASH_MD5; - ta_ctx->current_hash_stage = HASH_DIGEST; - - /* lock necessary so that only one entity touches the queues */ - spin_lock_irq(&queue_lock); - error = crypto_enqueue_request(&sep_queue, &req->base); - - if ((error != 0) && (error != -EINPROGRESS)) - pr_debug(" sep - crypto enqueue failed: %x\n", - error); - error1 = sep_submit_work(ta_ctx->sep_used->workqueue, - sep_dequeuer, (void *)&sep_queue); - if (error1) - pr_debug(" sep - workqueue submit failed: %x\n", - error1); - spin_unlock_irq(&queue_lock); - /* We return result of crypto enqueue */ - return error; -} - -static int sep_md5_finup(struct ahash_request *req) -{ - int error; - int error1; - struct this_task_ctx *ta_ctx = ahash_request_ctx(req); - - pr_debug("sep - doing md5 finup\n"); - - ta_ctx->sep_used = sep_dev; - ta_ctx->current_request = MD5; - ta_ctx->current_hash_req = req; - ta_ctx->current_cypher_req = NULL; - ta_ctx->hash_opmode = SEP_HASH_MD5; - ta_ctx->current_hash_stage = HASH_FINUP_DATA; - - /* lock necessary so that only one entity touches the queues */ - spin_lock_irq(&queue_lock); - error = crypto_enqueue_request(&sep_queue, &req->base); - - if ((error != 0) && (error != -EINPROGRESS)) - pr_debug(" sep - crypto enqueue failed: %x\n", - error); - error1 = sep_submit_work(ta_ctx->sep_used->workqueue, - sep_dequeuer, (void *)&sep_queue); - if (error1) - pr_debug(" sep - workqueue submit failed: %x\n", - error1); - spin_unlock_irq(&queue_lock); - /* We return result of crypto enqueue */ - return error; -} - -static int sep_sha224_init(struct ahash_request *req) -{ - int error; - int error1; - struct this_task_ctx *ta_ctx = ahash_request_ctx(req); - pr_debug("sep - doing sha224 init\n"); - - /* Clear out task context */ - memset(ta_ctx, 0, sizeof(struct this_task_ctx)); - - ta_ctx->sep_used = sep_dev; - ta_ctx->current_request = SHA224; - ta_ctx->current_hash_req = req; - ta_ctx->current_cypher_req = NULL; - ta_ctx->hash_opmode = SEP_HASH_SHA224; - ta_ctx->current_hash_stage = HASH_INIT; - - /* lock necessary so that only one entity touches the queues */ - spin_lock_irq(&queue_lock); - error = crypto_enqueue_request(&sep_queue, &req->base); - - if ((error != 0) && (error != -EINPROGRESS)) - pr_debug(" sep - crypto enqueue failed: %x\n", - error); - error1 = sep_submit_work(ta_ctx->sep_used->workqueue, - sep_dequeuer, (void *)&sep_queue); - if (error1) - pr_debug(" sep - workqueue submit failed: %x\n", - error1); - spin_unlock_irq(&queue_lock); - /* We return result of crypto enqueue */ - return error; -} - -static int sep_sha224_update(struct ahash_request *req) -{ - int error; - int error1; - struct this_task_ctx *ta_ctx = ahash_request_ctx(req); - pr_debug("sep - doing sha224 update\n"); - - ta_ctx->sep_used = sep_dev; - ta_ctx->current_request = SHA224; - ta_ctx->current_hash_req = req; - ta_ctx->current_cypher_req = NULL; - ta_ctx->hash_opmode = SEP_HASH_SHA224; - ta_ctx->current_hash_stage = HASH_UPDATE; - - /* lock necessary so that only one entity touches the queues */ - spin_lock_irq(&queue_lock); - error = crypto_enqueue_request(&sep_queue, &req->base); - - if ((error != 0) && (error != -EINPROGRESS)) - pr_debug(" sep - crypto enqueue failed: %x\n", - error); - error1 = sep_submit_work(ta_ctx->sep_used->workqueue, - sep_dequeuer, (void *)&sep_queue); - if (error1) - pr_debug(" sep - workqueue submit failed: %x\n", - error1); - spin_unlock_irq(&queue_lock); - /* We return result of crypto enqueue */ - return error; -} - -static int sep_sha224_final(struct ahash_request *req) -{ - int error; - int error1; - struct this_task_ctx *ta_ctx = ahash_request_ctx(req); - pr_debug("sep - doing sha224 final\n"); - - ta_ctx->sep_used = sep_dev; - ta_ctx->current_request = SHA224; - ta_ctx->current_hash_req = req; - ta_ctx->current_cypher_req = NULL; - ta_ctx->hash_opmode = SEP_HASH_SHA224; - ta_ctx->current_hash_stage = HASH_FINISH; - - /* lock necessary so that only one entity touches the queues */ - spin_lock_irq(&queue_lock); - error = crypto_enqueue_request(&sep_queue, &req->base); - - if ((error != 0) && (error != -EINPROGRESS)) - pr_debug(" sep - crypto enqueue failed: %x\n", - error); - error1 = sep_submit_work(ta_ctx->sep_used->workqueue, - sep_dequeuer, (void *)&sep_queue); - if (error1) - pr_debug(" sep - workqueue submit failed: %x\n", - error1); - spin_unlock_irq(&queue_lock); - /* We return result of crypto enqueue */ - return error; -} - -static int sep_sha224_digest(struct ahash_request *req) -{ - int error; - int error1; - struct this_task_ctx *ta_ctx = ahash_request_ctx(req); - - pr_debug("sep - doing sha224 digest\n"); - - /* Clear out task context */ - memset(ta_ctx, 0, sizeof(struct this_task_ctx)); - - ta_ctx->sep_used = sep_dev; - ta_ctx->current_request = SHA224; - ta_ctx->current_hash_req = req; - ta_ctx->current_cypher_req = NULL; - ta_ctx->hash_opmode = SEP_HASH_SHA224; - ta_ctx->current_hash_stage = HASH_DIGEST; - - /* lock necessary so that only one entity touches the queues */ - spin_lock_irq(&queue_lock); - error = crypto_enqueue_request(&sep_queue, &req->base); - - if ((error != 0) && (error != -EINPROGRESS)) - pr_debug(" sep - crypto enqueue failed: %x\n", - error); - error1 = sep_submit_work(ta_ctx->sep_used->workqueue, - sep_dequeuer, (void *)&sep_queue); - if (error1) - pr_debug(" sep - workqueue submit failed: %x\n", - error1); - spin_unlock_irq(&queue_lock); - /* We return result of crypto enqueue */ - return error; -} - -static int sep_sha224_finup(struct ahash_request *req) -{ - int error; - int error1; - struct this_task_ctx *ta_ctx = ahash_request_ctx(req); - - pr_debug("sep - doing sha224 finup\n"); - - ta_ctx->sep_used = sep_dev; - ta_ctx->current_request = SHA224; - ta_ctx->current_hash_req = req; - ta_ctx->current_cypher_req = NULL; - ta_ctx->hash_opmode = SEP_HASH_SHA224; - ta_ctx->current_hash_stage = HASH_FINUP_DATA; - - /* lock necessary so that only one entity touches the queues */ - spin_lock_irq(&queue_lock); - error = crypto_enqueue_request(&sep_queue, &req->base); - - if ((error != 0) && (error != -EINPROGRESS)) - pr_debug(" sep - crypto enqueue failed: %x\n", - error); - error1 = sep_submit_work(ta_ctx->sep_used->workqueue, - sep_dequeuer, (void *)&sep_queue); - if (error1) - pr_debug(" sep - workqueue submit failed: %x\n", - error1); - spin_unlock_irq(&queue_lock); - /* We return result of crypto enqueue */ - return error; -} - -static int sep_sha256_init(struct ahash_request *req) -{ - int error; - int error1; - struct this_task_ctx *ta_ctx = ahash_request_ctx(req); - pr_debug("sep - doing sha256 init\n"); - - /* Clear out task context */ - memset(ta_ctx, 0, sizeof(struct this_task_ctx)); - - ta_ctx->sep_used = sep_dev; - ta_ctx->current_request = SHA256; - ta_ctx->current_hash_req = req; - ta_ctx->current_cypher_req = NULL; - ta_ctx->hash_opmode = SEP_HASH_SHA256; - ta_ctx->current_hash_stage = HASH_INIT; - - /* lock necessary so that only one entity touches the queues */ - spin_lock_irq(&queue_lock); - error = crypto_enqueue_request(&sep_queue, &req->base); - - if ((error != 0) && (error != -EINPROGRESS)) - pr_debug(" sep - crypto enqueue failed: %x\n", - error); - error1 = sep_submit_work(ta_ctx->sep_used->workqueue, - sep_dequeuer, (void *)&sep_queue); - if (error1) - pr_debug(" sep - workqueue submit failed: %x\n", - error1); - spin_unlock_irq(&queue_lock); - /* We return result of crypto enqueue */ - return error; -} - -static int sep_sha256_update(struct ahash_request *req) -{ - int error; - int error1; - struct this_task_ctx *ta_ctx = ahash_request_ctx(req); - pr_debug("sep - doing sha256 update\n"); - - ta_ctx->sep_used = sep_dev; - ta_ctx->current_request = SHA256; - ta_ctx->current_hash_req = req; - ta_ctx->current_cypher_req = NULL; - ta_ctx->hash_opmode = SEP_HASH_SHA256; - ta_ctx->current_hash_stage = HASH_UPDATE; - - /* lock necessary so that only one entity touches the queues */ - spin_lock_irq(&queue_lock); - error = crypto_enqueue_request(&sep_queue, &req->base); - - if ((error != 0) && (error != -EINPROGRESS)) - pr_debug(" sep - crypto enqueue failed: %x\n", - error); - error1 = sep_submit_work(ta_ctx->sep_used->workqueue, - sep_dequeuer, (void *)&sep_queue); - if (error1) - pr_debug(" sep - workqueue submit failed: %x\n", - error1); - spin_unlock_irq(&queue_lock); - /* We return result of crypto enqueue */ - return error; -} - -static int sep_sha256_final(struct ahash_request *req) -{ - int error; - int error1; - struct this_task_ctx *ta_ctx = ahash_request_ctx(req); - pr_debug("sep - doing sha256 final\n"); - - ta_ctx->sep_used = sep_dev; - ta_ctx->current_request = SHA256; - ta_ctx->current_hash_req = req; - ta_ctx->current_cypher_req = NULL; - ta_ctx->hash_opmode = SEP_HASH_SHA256; - ta_ctx->current_hash_stage = HASH_FINISH; - - /* lock necessary so that only one entity touches the queues */ - spin_lock_irq(&queue_lock); - error = crypto_enqueue_request(&sep_queue, &req->base); - - if ((error != 0) && (error != -EINPROGRESS)) - pr_debug(" sep - crypto enqueue failed: %x\n", - error); - error1 = sep_submit_work(ta_ctx->sep_used->workqueue, - sep_dequeuer, (void *)&sep_queue); - if (error1) - pr_debug(" sep - workqueue submit failed: %x\n", - error1); - spin_unlock_irq(&queue_lock); - /* We return result of crypto enqueue */ - return error; -} - -static int sep_sha256_digest(struct ahash_request *req) -{ - int error; - int error1; - struct this_task_ctx *ta_ctx = ahash_request_ctx(req); - - pr_debug("sep - doing sha256 digest\n"); - - /* Clear out task context */ - memset(ta_ctx, 0, sizeof(struct this_task_ctx)); - - ta_ctx->sep_used = sep_dev; - ta_ctx->current_request = SHA256; - ta_ctx->current_hash_req = req; - ta_ctx->current_cypher_req = NULL; - ta_ctx->hash_opmode = SEP_HASH_SHA256; - ta_ctx->current_hash_stage = HASH_DIGEST; - - /* lock necessary so that only one entity touches the queues */ - spin_lock_irq(&queue_lock); - error = crypto_enqueue_request(&sep_queue, &req->base); - - if ((error != 0) && (error != -EINPROGRESS)) - pr_debug(" sep - crypto enqueue failed: %x\n", - error); - error1 = sep_submit_work(ta_ctx->sep_used->workqueue, - sep_dequeuer, (void *)&sep_queue); - if (error1) - pr_debug(" sep - workqueue submit failed: %x\n", - error1); - spin_unlock_irq(&queue_lock); - /* We return result of crypto enqueue */ - return error; -} - -static int sep_sha256_finup(struct ahash_request *req) -{ - int error; - int error1; - struct this_task_ctx *ta_ctx = ahash_request_ctx(req); - - pr_debug("sep - doing sha256 finup\n"); - - ta_ctx->sep_used = sep_dev; - ta_ctx->current_request = SHA256; - ta_ctx->current_hash_req = req; - ta_ctx->current_cypher_req = NULL; - ta_ctx->hash_opmode = SEP_HASH_SHA256; - ta_ctx->current_hash_stage = HASH_FINUP_DATA; - - /* lock necessary so that only one entity touches the queues */ - spin_lock_irq(&queue_lock); - error = crypto_enqueue_request(&sep_queue, &req->base); - - if ((error != 0) && (error != -EINPROGRESS)) - pr_debug(" sep - crypto enqueue failed: %x\n", - error); - error1 = sep_submit_work(ta_ctx->sep_used->workqueue, - sep_dequeuer, (void *)&sep_queue); - if (error1) - pr_debug(" sep - workqueue submit failed: %x\n", - error1); - spin_unlock_irq(&queue_lock); - /* We return result of crypto enqueue */ - return error; -} - -static int sep_crypto_init(struct crypto_tfm *tfm) -{ - const char *alg_name = crypto_tfm_alg_name(tfm); - - if (alg_name == NULL) - pr_debug("sep_crypto_init alg is NULL\n"); - else - pr_debug("sep_crypto_init alg is %s\n", alg_name); - - tfm->crt_ablkcipher.reqsize = sizeof(struct this_task_ctx); - return 0; -} - -static void sep_crypto_exit(struct crypto_tfm *tfm) -{ - pr_debug("sep_crypto_exit\n"); -} - -static int sep_aes_setkey(struct crypto_ablkcipher *tfm, const u8 *key, - unsigned int keylen) -{ - struct sep_system_ctx *sctx = crypto_ablkcipher_ctx(tfm); - - pr_debug("sep aes setkey\n"); - - pr_debug("tfm is %p sctx is %p\n", tfm, sctx); - switch (keylen) { - case SEP_AES_KEY_128_SIZE: - sctx->aes_key_size = AES_128; - break; - case SEP_AES_KEY_192_SIZE: - sctx->aes_key_size = AES_192; - break; - case SEP_AES_KEY_256_SIZE: - sctx->aes_key_size = AES_256; - break; - case SEP_AES_KEY_512_SIZE: - sctx->aes_key_size = AES_512; - break; - default: - pr_debug("invalid sep aes key size %x\n", - keylen); - return -EINVAL; - } - - memset(&sctx->key.aes, 0, sizeof(u32) * - SEP_AES_MAX_KEY_SIZE_WORDS); - memcpy(&sctx->key.aes, key, keylen); - sctx->keylen = keylen; - /* Indicate to encrypt/decrypt function to send key to SEP */ - sctx->key_sent = 0; - - return 0; -} - -static int sep_aes_ecb_encrypt(struct ablkcipher_request *req) -{ - int error; - int error1; - struct this_task_ctx *ta_ctx = ablkcipher_request_ctx(req); - - pr_debug("sep - doing aes ecb encrypt\n"); - - /* Clear out task context */ - memset(ta_ctx, 0, sizeof(struct this_task_ctx)); - - ta_ctx->sep_used = sep_dev; - ta_ctx->current_request = AES_ECB; - ta_ctx->current_hash_req = NULL; - ta_ctx->current_cypher_req = req; - ta_ctx->aes_encmode = SEP_AES_ENCRYPT; - ta_ctx->aes_opmode = SEP_AES_ECB; - ta_ctx->init_opcode = SEP_AES_INIT_OPCODE; - ta_ctx->block_opcode = SEP_AES_BLOCK_OPCODE; - - /* lock necessary so that only one entity touches the queues */ - spin_lock_irq(&queue_lock); - error = crypto_enqueue_request(&sep_queue, &req->base); - - if ((error != 0) && (error != -EINPROGRESS)) - pr_debug(" sep - crypto enqueue failed: %x\n", - error); - error1 = sep_submit_work(ta_ctx->sep_used->workqueue, - sep_dequeuer, (void *)&sep_queue); - if (error1) - pr_debug(" sep - workqueue submit failed: %x\n", - error1); - spin_unlock_irq(&queue_lock); - /* We return result of crypto enqueue */ - return error; -} - -static int sep_aes_ecb_decrypt(struct ablkcipher_request *req) -{ - int error; - int error1; - struct this_task_ctx *ta_ctx = ablkcipher_request_ctx(req); - - pr_debug("sep - doing aes ecb decrypt\n"); - - /* Clear out task context */ - memset(ta_ctx, 0, sizeof(struct this_task_ctx)); - - ta_ctx->sep_used = sep_dev; - ta_ctx->current_request = AES_ECB; - ta_ctx->current_hash_req = NULL; - ta_ctx->current_cypher_req = req; - ta_ctx->aes_encmode = SEP_AES_DECRYPT; - ta_ctx->aes_opmode = SEP_AES_ECB; - ta_ctx->init_opcode = SEP_AES_INIT_OPCODE; - ta_ctx->block_opcode = SEP_AES_BLOCK_OPCODE; - - /* lock necessary so that only one entity touches the queues */ - spin_lock_irq(&queue_lock); - error = crypto_enqueue_request(&sep_queue, &req->base); - - if ((error != 0) && (error != -EINPROGRESS)) - pr_debug(" sep - crypto enqueue failed: %x\n", - error); - error1 = sep_submit_work(ta_ctx->sep_used->workqueue, - sep_dequeuer, (void *)&sep_queue); - if (error1) - pr_debug(" sep - workqueue submit failed: %x\n", - error1); - spin_unlock_irq(&queue_lock); - /* We return result of crypto enqueue */ - return error; -} - -static int sep_aes_cbc_encrypt(struct ablkcipher_request *req) -{ - int error; - int error1; - struct this_task_ctx *ta_ctx = ablkcipher_request_ctx(req); - struct sep_system_ctx *sctx = crypto_ablkcipher_ctx( - crypto_ablkcipher_reqtfm(req)); - - pr_debug("sep - doing aes cbc encrypt\n"); - - /* Clear out task context */ - memset(ta_ctx, 0, sizeof(struct this_task_ctx)); - - pr_debug("tfm is %p sctx is %p and ta_ctx is %p\n", - crypto_ablkcipher_reqtfm(req), sctx, ta_ctx); - - ta_ctx->sep_used = sep_dev; - ta_ctx->current_request = AES_CBC; - ta_ctx->current_hash_req = NULL; - ta_ctx->current_cypher_req = req; - ta_ctx->aes_encmode = SEP_AES_ENCRYPT; - ta_ctx->aes_opmode = SEP_AES_CBC; - ta_ctx->init_opcode = SEP_AES_INIT_OPCODE; - ta_ctx->block_opcode = SEP_AES_BLOCK_OPCODE; - - /* lock necessary so that only one entity touches the queues */ - spin_lock_irq(&queue_lock); - error = crypto_enqueue_request(&sep_queue, &req->base); - - if ((error != 0) && (error != -EINPROGRESS)) - pr_debug(" sep - crypto enqueue failed: %x\n", - error); - error1 = sep_submit_work(ta_ctx->sep_used->workqueue, - sep_dequeuer, (void *)&sep_queue); - if (error1) - pr_debug(" sep - workqueue submit failed: %x\n", - error1); - spin_unlock_irq(&queue_lock); - /* We return result of crypto enqueue */ - return error; -} - -static int sep_aes_cbc_decrypt(struct ablkcipher_request *req) -{ - int error; - int error1; - struct this_task_ctx *ta_ctx = ablkcipher_request_ctx(req); - struct sep_system_ctx *sctx = crypto_ablkcipher_ctx( - crypto_ablkcipher_reqtfm(req)); - - pr_debug("sep - doing aes cbc decrypt\n"); - - pr_debug("tfm is %p sctx is %p and ta_ctx is %p\n", - crypto_ablkcipher_reqtfm(req), sctx, ta_ctx); - - /* Clear out task context */ - memset(ta_ctx, 0, sizeof(struct this_task_ctx)); - - ta_ctx->sep_used = sep_dev; - ta_ctx->current_request = AES_CBC; - ta_ctx->current_hash_req = NULL; - ta_ctx->current_cypher_req = req; - ta_ctx->aes_encmode = SEP_AES_DECRYPT; - ta_ctx->aes_opmode = SEP_AES_CBC; - ta_ctx->init_opcode = SEP_AES_INIT_OPCODE; - ta_ctx->block_opcode = SEP_AES_BLOCK_OPCODE; - - /* lock necessary so that only one entity touches the queues */ - spin_lock_irq(&queue_lock); - error = crypto_enqueue_request(&sep_queue, &req->base); - - if ((error != 0) && (error != -EINPROGRESS)) - pr_debug(" sep - crypto enqueue failed: %x\n", - error); - error1 = sep_submit_work(ta_ctx->sep_used->workqueue, - sep_dequeuer, (void *)&sep_queue); - if (error1) - pr_debug(" sep - workqueue submit failed: %x\n", - error1); - spin_unlock_irq(&queue_lock); - /* We return result of crypto enqueue */ - return error; -} - -static int sep_des_setkey(struct crypto_ablkcipher *tfm, const u8 *key, - unsigned int keylen) -{ - struct sep_system_ctx *sctx = crypto_ablkcipher_ctx(tfm); - struct crypto_tfm *ctfm = crypto_ablkcipher_tfm(tfm); - u32 *flags = &ctfm->crt_flags; - - pr_debug("sep des setkey\n"); - - switch (keylen) { - case DES_KEY_SIZE: - sctx->des_nbr_keys = DES_KEY_1; - break; - case DES_KEY_SIZE * 2: - sctx->des_nbr_keys = DES_KEY_2; - break; - case DES_KEY_SIZE * 3: - sctx->des_nbr_keys = DES_KEY_3; - break; - default: - pr_debug("invalid key size %x\n", - keylen); - return -EINVAL; - } - - if ((*flags & CRYPTO_TFM_REQ_WEAK_KEY) && - (sep_weak_key(key, keylen))) { - - *flags |= CRYPTO_TFM_RES_WEAK_KEY; - pr_debug("weak key\n"); - return -EINVAL; - } - - memset(&sctx->key.des, 0, sizeof(struct sep_des_key)); - memcpy(&sctx->key.des.key1, key, keylen); - sctx->keylen = keylen; - /* Indicate to encrypt/decrypt function to send key to SEP */ - sctx->key_sent = 0; - - return 0; -} - -static int sep_des_ebc_encrypt(struct ablkcipher_request *req) -{ - int error; - int error1; - struct this_task_ctx *ta_ctx = ablkcipher_request_ctx(req); - - pr_debug("sep - doing des ecb encrypt\n"); - - /* Clear out task context */ - memset(ta_ctx, 0, sizeof(struct this_task_ctx)); - - ta_ctx->sep_used = sep_dev; - ta_ctx->current_request = DES_ECB; - ta_ctx->current_hash_req = NULL; - ta_ctx->current_cypher_req = req; - ta_ctx->des_encmode = SEP_DES_ENCRYPT; - ta_ctx->des_opmode = SEP_DES_ECB; - ta_ctx->init_opcode = SEP_DES_INIT_OPCODE; - ta_ctx->block_opcode = SEP_DES_BLOCK_OPCODE; - - /* lock necessary so that only one entity touches the queues */ - spin_lock_irq(&queue_lock); - error = crypto_enqueue_request(&sep_queue, &req->base); - - if ((error != 0) && (error != -EINPROGRESS)) - pr_debug(" sep - crypto enqueue failed: %x\n", - error); - error1 = sep_submit_work(ta_ctx->sep_used->workqueue, - sep_dequeuer, (void *)&sep_queue); - if (error1) - pr_debug(" sep - workqueue submit failed: %x\n", - error1); - spin_unlock_irq(&queue_lock); - /* We return result of crypto enqueue */ - return error; -} - -static int sep_des_ebc_decrypt(struct ablkcipher_request *req) -{ - int error; - int error1; - struct this_task_ctx *ta_ctx = ablkcipher_request_ctx(req); - - pr_debug("sep - doing des ecb decrypt\n"); - - /* Clear out task context */ - memset(ta_ctx, 0, sizeof(struct this_task_ctx)); - - ta_ctx->sep_used = sep_dev; - ta_ctx->current_request = DES_ECB; - ta_ctx->current_hash_req = NULL; - ta_ctx->current_cypher_req = req; - ta_ctx->des_encmode = SEP_DES_DECRYPT; - ta_ctx->des_opmode = SEP_DES_ECB; - ta_ctx->init_opcode = SEP_DES_INIT_OPCODE; - ta_ctx->block_opcode = SEP_DES_BLOCK_OPCODE; - - /* lock necessary so that only one entity touches the queues */ - spin_lock_irq(&queue_lock); - error = crypto_enqueue_request(&sep_queue, &req->base); - - if ((error != 0) && (error != -EINPROGRESS)) - pr_debug(" sep - crypto enqueue failed: %x\n", - error); - error1 = sep_submit_work(ta_ctx->sep_used->workqueue, - sep_dequeuer, (void *)&sep_queue); - if (error1) - pr_debug(" sep - workqueue submit failed: %x\n", - error1); - spin_unlock_irq(&queue_lock); - /* We return result of crypto enqueue */ - return error; -} - -static int sep_des_cbc_encrypt(struct ablkcipher_request *req) -{ - int error; - int error1; - struct this_task_ctx *ta_ctx = ablkcipher_request_ctx(req); - - pr_debug("sep - doing des cbc encrypt\n"); - - /* Clear out task context */ - memset(ta_ctx, 0, sizeof(struct this_task_ctx)); - - ta_ctx->sep_used = sep_dev; - ta_ctx->current_request = DES_CBC; - ta_ctx->current_hash_req = NULL; - ta_ctx->current_cypher_req = req; - ta_ctx->des_encmode = SEP_DES_ENCRYPT; - ta_ctx->des_opmode = SEP_DES_CBC; - ta_ctx->init_opcode = SEP_DES_INIT_OPCODE; - ta_ctx->block_opcode = SEP_DES_BLOCK_OPCODE; - - /* lock necessary so that only one entity touches the queues */ - spin_lock_irq(&queue_lock); - error = crypto_enqueue_request(&sep_queue, &req->base); - - if ((error != 0) && (error != -EINPROGRESS)) - pr_debug(" sep - crypto enqueue failed: %x\n", - error); - error1 = sep_submit_work(ta_ctx->sep_used->workqueue, - sep_dequeuer, (void *)&sep_queue); - if (error1) - pr_debug(" sep - workqueue submit failed: %x\n", - error1); - spin_unlock_irq(&queue_lock); - /* We return result of crypto enqueue */ - return error; -} - -static int sep_des_cbc_decrypt(struct ablkcipher_request *req) -{ - int error; - int error1; - struct this_task_ctx *ta_ctx = ablkcipher_request_ctx(req); - - pr_debug("sep - doing des ecb decrypt\n"); - - /* Clear out task context */ - memset(ta_ctx, 0, sizeof(struct this_task_ctx)); - - ta_ctx->sep_used = sep_dev; - ta_ctx->current_request = DES_CBC; - ta_ctx->current_hash_req = NULL; - ta_ctx->current_cypher_req = req; - ta_ctx->des_encmode = SEP_DES_DECRYPT; - ta_ctx->des_opmode = SEP_DES_CBC; - ta_ctx->init_opcode = SEP_DES_INIT_OPCODE; - ta_ctx->block_opcode = SEP_DES_BLOCK_OPCODE; - - /* lock necessary so that only one entity touches the queues */ - spin_lock_irq(&queue_lock); - error = crypto_enqueue_request(&sep_queue, &req->base); - - if ((error != 0) && (error != -EINPROGRESS)) - pr_debug(" sep - crypto enqueue failed: %x\n", - error); - error1 = sep_submit_work(ta_ctx->sep_used->workqueue, - sep_dequeuer, (void *)&sep_queue); - if (error1) - pr_debug(" sep - workqueue submit failed: %x\n", - error1); - spin_unlock_irq(&queue_lock); - /* We return result of crypto enqueue */ - return error; -} - -static struct ahash_alg hash_algs[] = { -{ - .init = sep_sha1_init, - .update = sep_sha1_update, - .final = sep_sha1_final, - .digest = sep_sha1_digest, - .finup = sep_sha1_finup, - .halg = { - .digestsize = SHA1_DIGEST_SIZE, - .base = { - .cra_name = "sha1", - .cra_driver_name = "sha1-sep", - .cra_priority = 100, - .cra_flags = CRYPTO_ALG_TYPE_AHASH | - CRYPTO_ALG_ASYNC, - .cra_blocksize = SHA1_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct sep_system_ctx), - .cra_alignmask = 0, - .cra_module = THIS_MODULE, - .cra_init = sep_hash_cra_init, - .cra_exit = sep_hash_cra_exit, - } - } -}, -{ - .init = sep_md5_init, - .update = sep_md5_update, - .final = sep_md5_final, - .digest = sep_md5_digest, - .finup = sep_md5_finup, - .halg = { - .digestsize = MD5_DIGEST_SIZE, - .base = { - .cra_name = "md5", - .cra_driver_name = "md5-sep", - .cra_priority = 100, - .cra_flags = CRYPTO_ALG_TYPE_AHASH | - CRYPTO_ALG_ASYNC, - .cra_blocksize = SHA1_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct sep_system_ctx), - .cra_alignmask = 0, - .cra_module = THIS_MODULE, - .cra_init = sep_hash_cra_init, - .cra_exit = sep_hash_cra_exit, - } - } -}, -{ - .init = sep_sha224_init, - .update = sep_sha224_update, - .final = sep_sha224_final, - .digest = sep_sha224_digest, - .finup = sep_sha224_finup, - .halg = { - .digestsize = SHA224_DIGEST_SIZE, - .base = { - .cra_name = "sha224", - .cra_driver_name = "sha224-sep", - .cra_priority = 100, - .cra_flags = CRYPTO_ALG_TYPE_AHASH | - CRYPTO_ALG_ASYNC, - .cra_blocksize = SHA224_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct sep_system_ctx), - .cra_alignmask = 0, - .cra_module = THIS_MODULE, - .cra_init = sep_hash_cra_init, - .cra_exit = sep_hash_cra_exit, - } - } -}, -{ - .init = sep_sha256_init, - .update = sep_sha256_update, - .final = sep_sha256_final, - .digest = sep_sha256_digest, - .finup = sep_sha256_finup, - .halg = { - .digestsize = SHA256_DIGEST_SIZE, - .base = { - .cra_name = "sha256", - .cra_driver_name = "sha256-sep", - .cra_priority = 100, - .cra_flags = CRYPTO_ALG_TYPE_AHASH | - CRYPTO_ALG_ASYNC, - .cra_blocksize = SHA256_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct sep_system_ctx), - .cra_alignmask = 0, - .cra_module = THIS_MODULE, - .cra_init = sep_hash_cra_init, - .cra_exit = sep_hash_cra_exit, - } - } -} -}; - -static struct crypto_alg crypto_algs[] = { -{ - .cra_name = "ecb(aes)", - .cra_driver_name = "ecb-aes-sep", - .cra_priority = 100, - .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, - .cra_blocksize = AES_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct sep_system_ctx), - .cra_alignmask = 0, - .cra_type = &crypto_ablkcipher_type, - .cra_module = THIS_MODULE, - .cra_init = sep_crypto_init, - .cra_exit = sep_crypto_exit, - .cra_u.ablkcipher = { - .min_keysize = AES_MIN_KEY_SIZE, - .max_keysize = AES_MAX_KEY_SIZE, - .setkey = sep_aes_setkey, - .encrypt = sep_aes_ecb_encrypt, - .decrypt = sep_aes_ecb_decrypt, - } -}, -{ - .cra_name = "cbc(aes)", - .cra_driver_name = "cbc-aes-sep", - .cra_priority = 100, - .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, - .cra_blocksize = AES_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct sep_system_ctx), - .cra_alignmask = 0, - .cra_type = &crypto_ablkcipher_type, - .cra_module = THIS_MODULE, - .cra_init = sep_crypto_init, - .cra_exit = sep_crypto_exit, - .cra_u.ablkcipher = { - .min_keysize = AES_MIN_KEY_SIZE, - .max_keysize = AES_MAX_KEY_SIZE, - .setkey = sep_aes_setkey, - .encrypt = sep_aes_cbc_encrypt, - .ivsize = AES_BLOCK_SIZE, - .decrypt = sep_aes_cbc_decrypt, - } -}, -{ - .cra_name = "ebc(des)", - .cra_driver_name = "ebc-des-sep", - .cra_priority = 100, - .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, - .cra_blocksize = DES_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct sep_system_ctx), - .cra_alignmask = 0, - .cra_type = &crypto_ablkcipher_type, - .cra_module = THIS_MODULE, - .cra_init = sep_crypto_init, - .cra_exit = sep_crypto_exit, - .cra_u.ablkcipher = { - .min_keysize = DES_KEY_SIZE, - .max_keysize = DES_KEY_SIZE, - .setkey = sep_des_setkey, - .encrypt = sep_des_ebc_encrypt, - .decrypt = sep_des_ebc_decrypt, - } -}, -{ - .cra_name = "cbc(des)", - .cra_driver_name = "cbc-des-sep", - .cra_priority = 100, - .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, - .cra_blocksize = DES_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct sep_system_ctx), - .cra_alignmask = 0, - .cra_type = &crypto_ablkcipher_type, - .cra_module = THIS_MODULE, - .cra_init = sep_crypto_init, - .cra_exit = sep_crypto_exit, - .cra_u.ablkcipher = { - .min_keysize = DES_KEY_SIZE, - .max_keysize = DES_KEY_SIZE, - .setkey = sep_des_setkey, - .encrypt = sep_des_cbc_encrypt, - .ivsize = DES_BLOCK_SIZE, - .decrypt = sep_des_cbc_decrypt, - } -}, -{ - .cra_name = "ebc(des3-ede)", - .cra_driver_name = "ebc-des3-ede-sep", - .cra_priority = 100, - .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, - .cra_blocksize = DES_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct sep_system_ctx), - .cra_alignmask = 0, - .cra_type = &crypto_ablkcipher_type, - .cra_module = THIS_MODULE, - .cra_init = sep_crypto_init, - .cra_exit = sep_crypto_exit, - .cra_u.ablkcipher = { - .min_keysize = DES3_EDE_KEY_SIZE, - .max_keysize = DES3_EDE_KEY_SIZE, - .setkey = sep_des_setkey, - .encrypt = sep_des_ebc_encrypt, - .decrypt = sep_des_ebc_decrypt, - } -}, -{ - .cra_name = "cbc(des3-ede)", - .cra_driver_name = "cbc-des3--ede-sep", - .cra_priority = 100, - .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, - .cra_blocksize = DES_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct sep_system_ctx), - .cra_alignmask = 0, - .cra_type = &crypto_ablkcipher_type, - .cra_module = THIS_MODULE, - .cra_init = sep_crypto_init, - .cra_exit = sep_crypto_exit, - .cra_u.ablkcipher = { - .min_keysize = DES3_EDE_KEY_SIZE, - .max_keysize = DES3_EDE_KEY_SIZE, - .setkey = sep_des_setkey, - .encrypt = sep_des_cbc_encrypt, - .decrypt = sep_des_cbc_decrypt, - } -} -}; - -int sep_crypto_setup(void) -{ - int err, i, j, k; - - tasklet_init(&sep_dev->finish_tasklet, sep_finish, - (unsigned long)sep_dev); - - crypto_init_queue(&sep_queue, SEP_QUEUE_LENGTH); - - sep_dev->workqueue = create_singlethread_workqueue( - "sep_crypto_workqueue"); - if (!sep_dev->workqueue) { - dev_warn(&sep_dev->pdev->dev, "cant create workqueue\n"); - return -ENOMEM; - } - - spin_lock_init(&queue_lock); - - err = 0; - for (i = 0; i < ARRAY_SIZE(hash_algs); i++) { - err = crypto_register_ahash(&hash_algs[i]); - if (err) - goto err_algs; - } - - err = 0; - for (j = 0; j < ARRAY_SIZE(crypto_algs); j++) { - err = crypto_register_alg(&crypto_algs[j]); - if (err) - goto err_crypto_algs; - } - - return err; - -err_algs: - for (k = 0; k < i; k++) - crypto_unregister_ahash(&hash_algs[k]); - destroy_workqueue(sep_dev->workqueue); - return err; - -err_crypto_algs: - for (k = 0; k < j; k++) - crypto_unregister_alg(&crypto_algs[k]); - goto err_algs; -} - -void sep_crypto_takedown(void) -{ - - int i; - - for (i = 0; i < ARRAY_SIZE(hash_algs); i++) - crypto_unregister_ahash(&hash_algs[i]); - for (i = 0; i < ARRAY_SIZE(crypto_algs); i++) - crypto_unregister_alg(&crypto_algs[i]); - - destroy_workqueue(sep_dev->workqueue); - tasklet_kill(&sep_dev->finish_tasklet); -} - -#endif |