diff options
author | Tero Kristo <t-kristo@ti.com> | 2017-05-24 09:35:26 +0200 |
---|---|---|
committer | Herbert Xu <herbert@gondor.apana.org.au> | 2017-06-10 06:04:15 +0200 |
commit | 74ed87e7e7f7197137164738dd0610ccd5ec5ed1 (patch) | |
tree | 3d17637e5eb4b650596f880285de5c0c784a5f6b /drivers | |
parent | crypto: omap-des - use runtime_pm autosuspend for clock handling (diff) | |
download | linux-74ed87e7e7f7197137164738dd0610ccd5ec5ed1.tar.xz linux-74ed87e7e7f7197137164738dd0610ccd5ec5ed1.zip |
crypto: omap - add base support library for common routines
This contains the generic APIs for aligning SG buffers.
Signed-off-by: Tero Kristo <t-kristo@ti.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/crypto/Kconfig | 11 | ||||
-rw-r--r-- | drivers/crypto/Makefile | 1 | ||||
-rw-r--r-- | drivers/crypto/omap-crypto.c | 184 | ||||
-rw-r--r-- | drivers/crypto/omap-crypto.h | 37 |
4 files changed, 233 insertions, 0 deletions
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index fb1e60f5002e..64171cad735d 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -314,6 +314,15 @@ config HW_RANDOM_PPC4XX This option provides the kernel-side support for the TRNG hardware found in the security function of some PowerPC 4xx SoCs. +config CRYPTO_DEV_OMAP + tristate "Support for OMAP crypto HW accelerators" + depends on ARCH_OMAP2PLUS + help + OMAP processors have various crypto HW accelerators. Select this if + you want to use the OMAP modules for any of the crypto algorithms. + +if CRYPTO_DEV_OMAP + config CRYPTO_DEV_OMAP_SHAM tristate "Support for OMAP MD5/SHA1/SHA2 hw accelerator" depends on ARCH_OMAP2PLUS @@ -351,6 +360,8 @@ config CRYPTO_DEV_OMAP_DES the ECB and CBC modes of operation are supported by the driver. Also accesses made on unaligned boundaries are supported. +endif # CRYPTO_DEV_OMAP + config CRYPTO_DEV_PICOXCELL tristate "Support for picoXcell IPSEC and Layer2 crypto engines" depends on (ARCH_PICOXCELL || COMPILE_TEST) && HAVE_CLK diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile index 463f33592d93..8fd11510f6b9 100644 --- a/drivers/crypto/Makefile +++ b/drivers/crypto/Makefile @@ -20,6 +20,7 @@ obj-$(CONFIG_CRYPTO_DEV_MXC_SCC) += mxc-scc.o obj-$(CONFIG_CRYPTO_DEV_NIAGARA2) += n2_crypto.o n2_crypto-y := n2_core.o n2_asm.o obj-$(CONFIG_CRYPTO_DEV_NX) += nx/ +obj-$(CONFIG_CRYPTO_DEV_OMAP) += omap-crypto.o obj-$(CONFIG_CRYPTO_DEV_OMAP_AES) += omap-aes.o obj-$(CONFIG_CRYPTO_DEV_OMAP_DES) += omap-des.o obj-$(CONFIG_CRYPTO_DEV_OMAP_SHAM) += omap-sham.o diff --git a/drivers/crypto/omap-crypto.c b/drivers/crypto/omap-crypto.c new file mode 100644 index 000000000000..23e37779317e --- /dev/null +++ b/drivers/crypto/omap-crypto.c @@ -0,0 +1,184 @@ +/* + * OMAP Crypto driver common support routines. + * + * Copyright (c) 2017 Texas Instruments Incorporated + * Tero Kristo <t-kristo@ti.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/scatterlist.h> +#include <crypto/scatterwalk.h> + +#include "omap-crypto.h" + +static int omap_crypto_copy_sg_lists(int total, int bs, + struct scatterlist **sg, + struct scatterlist *new_sg, u16 flags) +{ + int n = sg_nents(*sg); + struct scatterlist *tmp; + + if (!(flags & OMAP_CRYPTO_FORCE_SINGLE_ENTRY)) { + new_sg = kmalloc_array(n, sizeof(*sg), GFP_KERNEL); + if (!new_sg) + return -ENOMEM; + + sg_init_table(new_sg, n); + } + + tmp = new_sg; + + while (*sg && total) { + int len = (*sg)->length; + + if (total < len) + len = total; + + if (len > 0) { + total -= len; + sg_set_page(tmp, sg_page(*sg), len, (*sg)->offset); + if (total <= 0) + sg_mark_end(tmp); + tmp = sg_next(tmp); + } + + *sg = sg_next(*sg); + } + + *sg = new_sg; + + return 0; +} + +static int omap_crypto_copy_sgs(int total, int bs, struct scatterlist **sg, + struct scatterlist *new_sg, u16 flags) +{ + void *buf; + int pages; + int new_len; + + new_len = ALIGN(total, bs); + pages = get_order(new_len); + + buf = (void *)__get_free_pages(GFP_ATOMIC, pages); + if (!buf) { + pr_err("%s: Couldn't allocate pages for unaligned cases.\n", + __func__); + return -ENOMEM; + } + + if (flags & OMAP_CRYPTO_COPY_DATA) { + scatterwalk_map_and_copy(buf, *sg, 0, total, 0); + if (flags & OMAP_CRYPTO_ZERO_BUF) + memset(buf + total, 0, new_len - total); + } + + if (!(flags & OMAP_CRYPTO_FORCE_SINGLE_ENTRY)) + sg_init_table(new_sg, 1); + + sg_set_buf(new_sg, buf, new_len); + + *sg = new_sg; + + return 0; +} + +static int omap_crypto_check_sg(struct scatterlist *sg, int total, int bs, + u16 flags) +{ + int len = 0; + int num_sg = 0; + + if (!IS_ALIGNED(total, bs)) + return OMAP_CRYPTO_NOT_ALIGNED; + + while (sg) { + num_sg++; + + if (!IS_ALIGNED(sg->offset, 4)) + return OMAP_CRYPTO_NOT_ALIGNED; + if (!IS_ALIGNED(sg->length, bs)) + return OMAP_CRYPTO_NOT_ALIGNED; + + len += sg->length; + sg = sg_next(sg); + + if (len >= total) + break; + } + + if ((flags & OMAP_CRYPTO_FORCE_SINGLE_ENTRY) && num_sg > 1) + return OMAP_CRYPTO_NOT_ALIGNED; + + if (len != total) + return OMAP_CRYPTO_BAD_DATA_LENGTH; + + return 0; +} + +int omap_crypto_align_sg(struct scatterlist **sg, int total, int bs, + struct scatterlist *new_sg, u16 flags, + u8 flags_shift, unsigned long *dd_flags) +{ + int ret; + + *dd_flags &= ~(OMAP_CRYPTO_COPY_MASK << flags_shift); + + if (flags & OMAP_CRYPTO_FORCE_COPY) + ret = OMAP_CRYPTO_NOT_ALIGNED; + else + ret = omap_crypto_check_sg(*sg, total, bs, flags); + + if (ret == OMAP_CRYPTO_NOT_ALIGNED) { + ret = omap_crypto_copy_sgs(total, bs, sg, new_sg, flags); + if (ret) + return ret; + *dd_flags |= OMAP_CRYPTO_DATA_COPIED << flags_shift; + } else if (ret == OMAP_CRYPTO_BAD_DATA_LENGTH) { + ret = omap_crypto_copy_sg_lists(total, bs, sg, new_sg, flags); + if (ret) + return ret; + if (!(flags & OMAP_CRYPTO_FORCE_SINGLE_ENTRY)) + *dd_flags |= OMAP_CRYPTO_SG_COPIED << flags_shift; + } else if (flags & OMAP_CRYPTO_FORCE_SINGLE_ENTRY) { + sg_set_buf(new_sg, sg_virt(*sg), (*sg)->length); + } + + return 0; +} +EXPORT_SYMBOL_GPL(omap_crypto_align_sg); + +void omap_crypto_cleanup(struct scatterlist *sg, struct scatterlist *orig, + int offset, int len, u8 flags_shift, + unsigned long flags) +{ + void *buf; + int pages; + + flags >>= flags_shift; + flags &= OMAP_CRYPTO_COPY_MASK; + + if (!flags) + return; + + buf = sg_virt(sg); + pages = get_order(len); + + if (orig && (flags & OMAP_CRYPTO_COPY_MASK)) + scatterwalk_map_and_copy(buf, orig, offset, len, 1); + + if (flags & OMAP_CRYPTO_DATA_COPIED) + free_pages((unsigned long)buf, pages); + else if (flags & OMAP_CRYPTO_SG_COPIED) + kfree(sg); +} +EXPORT_SYMBOL_GPL(omap_crypto_cleanup); + +MODULE_DESCRIPTION("OMAP crypto support library."); +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Tero Kristo <t-kristo@ti.com>"); diff --git a/drivers/crypto/omap-crypto.h b/drivers/crypto/omap-crypto.h new file mode 100644 index 000000000000..36a230eb87af --- /dev/null +++ b/drivers/crypto/omap-crypto.h @@ -0,0 +1,37 @@ +/* + * OMAP Crypto driver common support routines. + * + * Copyright (c) 2017 Texas Instruments Incorporated + * Tero Kristo <t-kristo@ti.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + */ + +#ifndef __CRYPTO_OMAP_CRYPTO_H +#define __CRYPTO_OMAP_CRYPTO_H + +enum { + OMAP_CRYPTO_NOT_ALIGNED = 1, + OMAP_CRYPTO_BAD_DATA_LENGTH, +}; + +#define OMAP_CRYPTO_DATA_COPIED BIT(0) +#define OMAP_CRYPTO_SG_COPIED BIT(1) + +#define OMAP_CRYPTO_COPY_MASK 0x3 + +#define OMAP_CRYPTO_COPY_DATA BIT(0) +#define OMAP_CRYPTO_FORCE_COPY BIT(1) +#define OMAP_CRYPTO_ZERO_BUF BIT(2) +#define OMAP_CRYPTO_FORCE_SINGLE_ENTRY BIT(3) + +int omap_crypto_align_sg(struct scatterlist **sg, int total, int bs, + struct scatterlist *new_sg, u16 flags, + u8 flags_shift, unsigned long *dd_flags); +void omap_crypto_cleanup(struct scatterlist *sg, struct scatterlist *orig, + int offset, int len, u8 flags_shift, + unsigned long flags); + +#endif |