18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Intel IXP4xx NPE-C crypto driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2008 Christian Hohnstaedt <chohnstaedt@innominate.com> 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 98c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 108c2ecf20Sopenharmony_ci#include <linux/dmapool.h> 118c2ecf20Sopenharmony_ci#include <linux/crypto.h> 128c2ecf20Sopenharmony_ci#include <linux/kernel.h> 138c2ecf20Sopenharmony_ci#include <linux/rtnetlink.h> 148c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 158c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 168c2ecf20Sopenharmony_ci#include <linux/gfp.h> 178c2ecf20Sopenharmony_ci#include <linux/module.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include <crypto/ctr.h> 208c2ecf20Sopenharmony_ci#include <crypto/internal/des.h> 218c2ecf20Sopenharmony_ci#include <crypto/aes.h> 228c2ecf20Sopenharmony_ci#include <crypto/hmac.h> 238c2ecf20Sopenharmony_ci#include <crypto/sha.h> 248c2ecf20Sopenharmony_ci#include <crypto/algapi.h> 258c2ecf20Sopenharmony_ci#include <crypto/internal/aead.h> 268c2ecf20Sopenharmony_ci#include <crypto/internal/skcipher.h> 278c2ecf20Sopenharmony_ci#include <crypto/authenc.h> 288c2ecf20Sopenharmony_ci#include <crypto/scatterwalk.h> 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#include <linux/soc/ixp4xx/npe.h> 318c2ecf20Sopenharmony_ci#include <linux/soc/ixp4xx/qmgr.h> 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#define MAX_KEYLEN 32 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci/* hash: cfgword + 2 * digestlen; crypt: keylen + cfgword */ 368c2ecf20Sopenharmony_ci#define NPE_CTX_LEN 80 378c2ecf20Sopenharmony_ci#define AES_BLOCK128 16 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci#define NPE_OP_HASH_VERIFY 0x01 408c2ecf20Sopenharmony_ci#define NPE_OP_CCM_ENABLE 0x04 418c2ecf20Sopenharmony_ci#define NPE_OP_CRYPT_ENABLE 0x08 428c2ecf20Sopenharmony_ci#define NPE_OP_HASH_ENABLE 0x10 438c2ecf20Sopenharmony_ci#define NPE_OP_NOT_IN_PLACE 0x20 448c2ecf20Sopenharmony_ci#define NPE_OP_HMAC_DISABLE 0x40 458c2ecf20Sopenharmony_ci#define NPE_OP_CRYPT_ENCRYPT 0x80 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci#define NPE_OP_CCM_GEN_MIC 0xcc 488c2ecf20Sopenharmony_ci#define NPE_OP_HASH_GEN_ICV 0x50 498c2ecf20Sopenharmony_ci#define NPE_OP_ENC_GEN_KEY 0xc9 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci#define MOD_ECB 0x0000 528c2ecf20Sopenharmony_ci#define MOD_CTR 0x1000 538c2ecf20Sopenharmony_ci#define MOD_CBC_ENC 0x2000 548c2ecf20Sopenharmony_ci#define MOD_CBC_DEC 0x3000 558c2ecf20Sopenharmony_ci#define MOD_CCM_ENC 0x4000 568c2ecf20Sopenharmony_ci#define MOD_CCM_DEC 0x5000 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci#define KEYLEN_128 4 598c2ecf20Sopenharmony_ci#define KEYLEN_192 6 608c2ecf20Sopenharmony_ci#define KEYLEN_256 8 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci#define CIPH_DECR 0x0000 638c2ecf20Sopenharmony_ci#define CIPH_ENCR 0x0400 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci#define MOD_DES 0x0000 668c2ecf20Sopenharmony_ci#define MOD_TDEA2 0x0100 678c2ecf20Sopenharmony_ci#define MOD_3DES 0x0200 688c2ecf20Sopenharmony_ci#define MOD_AES 0x0800 698c2ecf20Sopenharmony_ci#define MOD_AES128 (0x0800 | KEYLEN_128) 708c2ecf20Sopenharmony_ci#define MOD_AES192 (0x0900 | KEYLEN_192) 718c2ecf20Sopenharmony_ci#define MOD_AES256 (0x0a00 | KEYLEN_256) 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci#define MAX_IVLEN 16 748c2ecf20Sopenharmony_ci#define NPE_ID 2 /* NPE C */ 758c2ecf20Sopenharmony_ci#define NPE_QLEN 16 768c2ecf20Sopenharmony_ci/* Space for registering when the first 778c2ecf20Sopenharmony_ci * NPE_QLEN crypt_ctl are busy */ 788c2ecf20Sopenharmony_ci#define NPE_QLEN_TOTAL 64 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci#define SEND_QID 29 818c2ecf20Sopenharmony_ci#define RECV_QID 30 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci#define CTL_FLAG_UNUSED 0x0000 848c2ecf20Sopenharmony_ci#define CTL_FLAG_USED 0x1000 858c2ecf20Sopenharmony_ci#define CTL_FLAG_PERFORM_ABLK 0x0001 868c2ecf20Sopenharmony_ci#define CTL_FLAG_GEN_ICV 0x0002 878c2ecf20Sopenharmony_ci#define CTL_FLAG_GEN_REVAES 0x0004 888c2ecf20Sopenharmony_ci#define CTL_FLAG_PERFORM_AEAD 0x0008 898c2ecf20Sopenharmony_ci#define CTL_FLAG_MASK 0x000f 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci#define HMAC_PAD_BLOCKLEN SHA1_BLOCK_SIZE 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci#define MD5_DIGEST_SIZE 16 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_cistruct buffer_desc { 968c2ecf20Sopenharmony_ci u32 phys_next; 978c2ecf20Sopenharmony_ci#ifdef __ARMEB__ 988c2ecf20Sopenharmony_ci u16 buf_len; 998c2ecf20Sopenharmony_ci u16 pkt_len; 1008c2ecf20Sopenharmony_ci#else 1018c2ecf20Sopenharmony_ci u16 pkt_len; 1028c2ecf20Sopenharmony_ci u16 buf_len; 1038c2ecf20Sopenharmony_ci#endif 1048c2ecf20Sopenharmony_ci dma_addr_t phys_addr; 1058c2ecf20Sopenharmony_ci u32 __reserved[4]; 1068c2ecf20Sopenharmony_ci struct buffer_desc *next; 1078c2ecf20Sopenharmony_ci enum dma_data_direction dir; 1088c2ecf20Sopenharmony_ci}; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_cistruct crypt_ctl { 1118c2ecf20Sopenharmony_ci#ifdef __ARMEB__ 1128c2ecf20Sopenharmony_ci u8 mode; /* NPE_OP_* operation mode */ 1138c2ecf20Sopenharmony_ci u8 init_len; 1148c2ecf20Sopenharmony_ci u16 reserved; 1158c2ecf20Sopenharmony_ci#else 1168c2ecf20Sopenharmony_ci u16 reserved; 1178c2ecf20Sopenharmony_ci u8 init_len; 1188c2ecf20Sopenharmony_ci u8 mode; /* NPE_OP_* operation mode */ 1198c2ecf20Sopenharmony_ci#endif 1208c2ecf20Sopenharmony_ci u8 iv[MAX_IVLEN]; /* IV for CBC mode or CTR IV for CTR mode */ 1218c2ecf20Sopenharmony_ci dma_addr_t icv_rev_aes; /* icv or rev aes */ 1228c2ecf20Sopenharmony_ci dma_addr_t src_buf; 1238c2ecf20Sopenharmony_ci dma_addr_t dst_buf; 1248c2ecf20Sopenharmony_ci#ifdef __ARMEB__ 1258c2ecf20Sopenharmony_ci u16 auth_offs; /* Authentication start offset */ 1268c2ecf20Sopenharmony_ci u16 auth_len; /* Authentication data length */ 1278c2ecf20Sopenharmony_ci u16 crypt_offs; /* Cryption start offset */ 1288c2ecf20Sopenharmony_ci u16 crypt_len; /* Cryption data length */ 1298c2ecf20Sopenharmony_ci#else 1308c2ecf20Sopenharmony_ci u16 auth_len; /* Authentication data length */ 1318c2ecf20Sopenharmony_ci u16 auth_offs; /* Authentication start offset */ 1328c2ecf20Sopenharmony_ci u16 crypt_len; /* Cryption data length */ 1338c2ecf20Sopenharmony_ci u16 crypt_offs; /* Cryption start offset */ 1348c2ecf20Sopenharmony_ci#endif 1358c2ecf20Sopenharmony_ci u32 aadAddr; /* Additional Auth Data Addr for CCM mode */ 1368c2ecf20Sopenharmony_ci u32 crypto_ctx; /* NPE Crypto Param structure address */ 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci /* Used by Host: 4*4 bytes*/ 1398c2ecf20Sopenharmony_ci unsigned ctl_flags; 1408c2ecf20Sopenharmony_ci union { 1418c2ecf20Sopenharmony_ci struct skcipher_request *ablk_req; 1428c2ecf20Sopenharmony_ci struct aead_request *aead_req; 1438c2ecf20Sopenharmony_ci struct crypto_tfm *tfm; 1448c2ecf20Sopenharmony_ci } data; 1458c2ecf20Sopenharmony_ci struct buffer_desc *regist_buf; 1468c2ecf20Sopenharmony_ci u8 *regist_ptr; 1478c2ecf20Sopenharmony_ci}; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_cistruct ablk_ctx { 1508c2ecf20Sopenharmony_ci struct buffer_desc *src; 1518c2ecf20Sopenharmony_ci struct buffer_desc *dst; 1528c2ecf20Sopenharmony_ci u8 iv[MAX_IVLEN]; 1538c2ecf20Sopenharmony_ci bool encrypt; 1548c2ecf20Sopenharmony_ci}; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_cistruct aead_ctx { 1578c2ecf20Sopenharmony_ci struct buffer_desc *src; 1588c2ecf20Sopenharmony_ci struct buffer_desc *dst; 1598c2ecf20Sopenharmony_ci struct scatterlist ivlist; 1608c2ecf20Sopenharmony_ci /* used when the hmac is not on one sg entry */ 1618c2ecf20Sopenharmony_ci u8 *hmac_virt; 1628c2ecf20Sopenharmony_ci int encrypt; 1638c2ecf20Sopenharmony_ci}; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_cistruct ix_hash_algo { 1668c2ecf20Sopenharmony_ci u32 cfgword; 1678c2ecf20Sopenharmony_ci unsigned char *icv; 1688c2ecf20Sopenharmony_ci}; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_cistruct ix_sa_dir { 1718c2ecf20Sopenharmony_ci unsigned char *npe_ctx; 1728c2ecf20Sopenharmony_ci dma_addr_t npe_ctx_phys; 1738c2ecf20Sopenharmony_ci int npe_ctx_idx; 1748c2ecf20Sopenharmony_ci u8 npe_mode; 1758c2ecf20Sopenharmony_ci}; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_cistruct ixp_ctx { 1788c2ecf20Sopenharmony_ci struct ix_sa_dir encrypt; 1798c2ecf20Sopenharmony_ci struct ix_sa_dir decrypt; 1808c2ecf20Sopenharmony_ci int authkey_len; 1818c2ecf20Sopenharmony_ci u8 authkey[MAX_KEYLEN]; 1828c2ecf20Sopenharmony_ci int enckey_len; 1838c2ecf20Sopenharmony_ci u8 enckey[MAX_KEYLEN]; 1848c2ecf20Sopenharmony_ci u8 salt[MAX_IVLEN]; 1858c2ecf20Sopenharmony_ci u8 nonce[CTR_RFC3686_NONCE_SIZE]; 1868c2ecf20Sopenharmony_ci unsigned salted; 1878c2ecf20Sopenharmony_ci atomic_t configuring; 1888c2ecf20Sopenharmony_ci struct completion completion; 1898c2ecf20Sopenharmony_ci}; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_cistruct ixp_alg { 1928c2ecf20Sopenharmony_ci struct skcipher_alg crypto; 1938c2ecf20Sopenharmony_ci const struct ix_hash_algo *hash; 1948c2ecf20Sopenharmony_ci u32 cfg_enc; 1958c2ecf20Sopenharmony_ci u32 cfg_dec; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci int registered; 1988c2ecf20Sopenharmony_ci}; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_cistruct ixp_aead_alg { 2018c2ecf20Sopenharmony_ci struct aead_alg crypto; 2028c2ecf20Sopenharmony_ci const struct ix_hash_algo *hash; 2038c2ecf20Sopenharmony_ci u32 cfg_enc; 2048c2ecf20Sopenharmony_ci u32 cfg_dec; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci int registered; 2078c2ecf20Sopenharmony_ci}; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_cistatic const struct ix_hash_algo hash_alg_md5 = { 2108c2ecf20Sopenharmony_ci .cfgword = 0xAA010004, 2118c2ecf20Sopenharmony_ci .icv = "\x01\x23\x45\x67\x89\xAB\xCD\xEF" 2128c2ecf20Sopenharmony_ci "\xFE\xDC\xBA\x98\x76\x54\x32\x10", 2138c2ecf20Sopenharmony_ci}; 2148c2ecf20Sopenharmony_cistatic const struct ix_hash_algo hash_alg_sha1 = { 2158c2ecf20Sopenharmony_ci .cfgword = 0x00000005, 2168c2ecf20Sopenharmony_ci .icv = "\x67\x45\x23\x01\xEF\xCD\xAB\x89\x98\xBA" 2178c2ecf20Sopenharmony_ci "\xDC\xFE\x10\x32\x54\x76\xC3\xD2\xE1\xF0", 2188c2ecf20Sopenharmony_ci}; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_cistatic struct npe *npe_c; 2218c2ecf20Sopenharmony_cistatic struct dma_pool *buffer_pool = NULL; 2228c2ecf20Sopenharmony_cistatic struct dma_pool *ctx_pool = NULL; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_cistatic struct crypt_ctl *crypt_virt = NULL; 2258c2ecf20Sopenharmony_cistatic dma_addr_t crypt_phys; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_cistatic int support_aes = 1; 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci#define DRIVER_NAME "ixp4xx_crypto" 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_cistatic struct platform_device *pdev; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_cistatic inline dma_addr_t crypt_virt2phys(struct crypt_ctl *virt) 2348c2ecf20Sopenharmony_ci{ 2358c2ecf20Sopenharmony_ci return crypt_phys + (virt - crypt_virt) * sizeof(struct crypt_ctl); 2368c2ecf20Sopenharmony_ci} 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_cistatic inline struct crypt_ctl *crypt_phys2virt(dma_addr_t phys) 2398c2ecf20Sopenharmony_ci{ 2408c2ecf20Sopenharmony_ci return crypt_virt + (phys - crypt_phys) / sizeof(struct crypt_ctl); 2418c2ecf20Sopenharmony_ci} 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_cistatic inline u32 cipher_cfg_enc(struct crypto_tfm *tfm) 2448c2ecf20Sopenharmony_ci{ 2458c2ecf20Sopenharmony_ci return container_of(tfm->__crt_alg, struct ixp_alg,crypto.base)->cfg_enc; 2468c2ecf20Sopenharmony_ci} 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_cistatic inline u32 cipher_cfg_dec(struct crypto_tfm *tfm) 2498c2ecf20Sopenharmony_ci{ 2508c2ecf20Sopenharmony_ci return container_of(tfm->__crt_alg, struct ixp_alg,crypto.base)->cfg_dec; 2518c2ecf20Sopenharmony_ci} 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_cistatic inline const struct ix_hash_algo *ix_hash(struct crypto_tfm *tfm) 2548c2ecf20Sopenharmony_ci{ 2558c2ecf20Sopenharmony_ci return container_of(tfm->__crt_alg, struct ixp_alg, crypto.base)->hash; 2568c2ecf20Sopenharmony_ci} 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_cistatic int setup_crypt_desc(void) 2598c2ecf20Sopenharmony_ci{ 2608c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 2618c2ecf20Sopenharmony_ci BUILD_BUG_ON(sizeof(struct crypt_ctl) != 64); 2628c2ecf20Sopenharmony_ci crypt_virt = dma_alloc_coherent(dev, 2638c2ecf20Sopenharmony_ci NPE_QLEN * sizeof(struct crypt_ctl), 2648c2ecf20Sopenharmony_ci &crypt_phys, GFP_ATOMIC); 2658c2ecf20Sopenharmony_ci if (!crypt_virt) 2668c2ecf20Sopenharmony_ci return -ENOMEM; 2678c2ecf20Sopenharmony_ci return 0; 2688c2ecf20Sopenharmony_ci} 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_cistatic spinlock_t desc_lock; 2718c2ecf20Sopenharmony_cistatic struct crypt_ctl *get_crypt_desc(void) 2728c2ecf20Sopenharmony_ci{ 2738c2ecf20Sopenharmony_ci int i; 2748c2ecf20Sopenharmony_ci static int idx = 0; 2758c2ecf20Sopenharmony_ci unsigned long flags; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci spin_lock_irqsave(&desc_lock, flags); 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci if (unlikely(!crypt_virt)) 2808c2ecf20Sopenharmony_ci setup_crypt_desc(); 2818c2ecf20Sopenharmony_ci if (unlikely(!crypt_virt)) { 2828c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&desc_lock, flags); 2838c2ecf20Sopenharmony_ci return NULL; 2848c2ecf20Sopenharmony_ci } 2858c2ecf20Sopenharmony_ci i = idx; 2868c2ecf20Sopenharmony_ci if (crypt_virt[i].ctl_flags == CTL_FLAG_UNUSED) { 2878c2ecf20Sopenharmony_ci if (++idx >= NPE_QLEN) 2888c2ecf20Sopenharmony_ci idx = 0; 2898c2ecf20Sopenharmony_ci crypt_virt[i].ctl_flags = CTL_FLAG_USED; 2908c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&desc_lock, flags); 2918c2ecf20Sopenharmony_ci return crypt_virt +i; 2928c2ecf20Sopenharmony_ci } else { 2938c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&desc_lock, flags); 2948c2ecf20Sopenharmony_ci return NULL; 2958c2ecf20Sopenharmony_ci } 2968c2ecf20Sopenharmony_ci} 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_cistatic spinlock_t emerg_lock; 2998c2ecf20Sopenharmony_cistatic struct crypt_ctl *get_crypt_desc_emerg(void) 3008c2ecf20Sopenharmony_ci{ 3018c2ecf20Sopenharmony_ci int i; 3028c2ecf20Sopenharmony_ci static int idx = NPE_QLEN; 3038c2ecf20Sopenharmony_ci struct crypt_ctl *desc; 3048c2ecf20Sopenharmony_ci unsigned long flags; 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci desc = get_crypt_desc(); 3078c2ecf20Sopenharmony_ci if (desc) 3088c2ecf20Sopenharmony_ci return desc; 3098c2ecf20Sopenharmony_ci if (unlikely(!crypt_virt)) 3108c2ecf20Sopenharmony_ci return NULL; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci spin_lock_irqsave(&emerg_lock, flags); 3138c2ecf20Sopenharmony_ci i = idx; 3148c2ecf20Sopenharmony_ci if (crypt_virt[i].ctl_flags == CTL_FLAG_UNUSED) { 3158c2ecf20Sopenharmony_ci if (++idx >= NPE_QLEN_TOTAL) 3168c2ecf20Sopenharmony_ci idx = NPE_QLEN; 3178c2ecf20Sopenharmony_ci crypt_virt[i].ctl_flags = CTL_FLAG_USED; 3188c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&emerg_lock, flags); 3198c2ecf20Sopenharmony_ci return crypt_virt +i; 3208c2ecf20Sopenharmony_ci } else { 3218c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&emerg_lock, flags); 3228c2ecf20Sopenharmony_ci return NULL; 3238c2ecf20Sopenharmony_ci } 3248c2ecf20Sopenharmony_ci} 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_cistatic void free_buf_chain(struct device *dev, struct buffer_desc *buf, 3278c2ecf20Sopenharmony_ci dma_addr_t phys) 3288c2ecf20Sopenharmony_ci{ 3298c2ecf20Sopenharmony_ci while (buf) { 3308c2ecf20Sopenharmony_ci struct buffer_desc *buf1; 3318c2ecf20Sopenharmony_ci u32 phys1; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci buf1 = buf->next; 3348c2ecf20Sopenharmony_ci phys1 = buf->phys_next; 3358c2ecf20Sopenharmony_ci dma_unmap_single(dev, buf->phys_addr, buf->buf_len, buf->dir); 3368c2ecf20Sopenharmony_ci dma_pool_free(buffer_pool, buf, phys); 3378c2ecf20Sopenharmony_ci buf = buf1; 3388c2ecf20Sopenharmony_ci phys = phys1; 3398c2ecf20Sopenharmony_ci } 3408c2ecf20Sopenharmony_ci} 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_cistatic struct tasklet_struct crypto_done_tasklet; 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_cistatic void finish_scattered_hmac(struct crypt_ctl *crypt) 3458c2ecf20Sopenharmony_ci{ 3468c2ecf20Sopenharmony_ci struct aead_request *req = crypt->data.aead_req; 3478c2ecf20Sopenharmony_ci struct aead_ctx *req_ctx = aead_request_ctx(req); 3488c2ecf20Sopenharmony_ci struct crypto_aead *tfm = crypto_aead_reqtfm(req); 3498c2ecf20Sopenharmony_ci int authsize = crypto_aead_authsize(tfm); 3508c2ecf20Sopenharmony_ci int decryptlen = req->assoclen + req->cryptlen - authsize; 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci if (req_ctx->encrypt) { 3538c2ecf20Sopenharmony_ci scatterwalk_map_and_copy(req_ctx->hmac_virt, 3548c2ecf20Sopenharmony_ci req->dst, decryptlen, authsize, 1); 3558c2ecf20Sopenharmony_ci } 3568c2ecf20Sopenharmony_ci dma_pool_free(buffer_pool, req_ctx->hmac_virt, crypt->icv_rev_aes); 3578c2ecf20Sopenharmony_ci} 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_cistatic void one_packet(dma_addr_t phys) 3608c2ecf20Sopenharmony_ci{ 3618c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 3628c2ecf20Sopenharmony_ci struct crypt_ctl *crypt; 3638c2ecf20Sopenharmony_ci struct ixp_ctx *ctx; 3648c2ecf20Sopenharmony_ci int failed; 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci failed = phys & 0x1 ? -EBADMSG : 0; 3678c2ecf20Sopenharmony_ci phys &= ~0x3; 3688c2ecf20Sopenharmony_ci crypt = crypt_phys2virt(phys); 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci switch (crypt->ctl_flags & CTL_FLAG_MASK) { 3718c2ecf20Sopenharmony_ci case CTL_FLAG_PERFORM_AEAD: { 3728c2ecf20Sopenharmony_ci struct aead_request *req = crypt->data.aead_req; 3738c2ecf20Sopenharmony_ci struct aead_ctx *req_ctx = aead_request_ctx(req); 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci free_buf_chain(dev, req_ctx->src, crypt->src_buf); 3768c2ecf20Sopenharmony_ci free_buf_chain(dev, req_ctx->dst, crypt->dst_buf); 3778c2ecf20Sopenharmony_ci if (req_ctx->hmac_virt) { 3788c2ecf20Sopenharmony_ci finish_scattered_hmac(crypt); 3798c2ecf20Sopenharmony_ci } 3808c2ecf20Sopenharmony_ci req->base.complete(&req->base, failed); 3818c2ecf20Sopenharmony_ci break; 3828c2ecf20Sopenharmony_ci } 3838c2ecf20Sopenharmony_ci case CTL_FLAG_PERFORM_ABLK: { 3848c2ecf20Sopenharmony_ci struct skcipher_request *req = crypt->data.ablk_req; 3858c2ecf20Sopenharmony_ci struct ablk_ctx *req_ctx = skcipher_request_ctx(req); 3868c2ecf20Sopenharmony_ci struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 3878c2ecf20Sopenharmony_ci unsigned int ivsize = crypto_skcipher_ivsize(tfm); 3888c2ecf20Sopenharmony_ci unsigned int offset; 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci if (ivsize > 0) { 3918c2ecf20Sopenharmony_ci offset = req->cryptlen - ivsize; 3928c2ecf20Sopenharmony_ci if (req_ctx->encrypt) { 3938c2ecf20Sopenharmony_ci scatterwalk_map_and_copy(req->iv, req->dst, 3948c2ecf20Sopenharmony_ci offset, ivsize, 0); 3958c2ecf20Sopenharmony_ci } else { 3968c2ecf20Sopenharmony_ci memcpy(req->iv, req_ctx->iv, ivsize); 3978c2ecf20Sopenharmony_ci memzero_explicit(req_ctx->iv, ivsize); 3988c2ecf20Sopenharmony_ci } 3998c2ecf20Sopenharmony_ci } 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci if (req_ctx->dst) { 4028c2ecf20Sopenharmony_ci free_buf_chain(dev, req_ctx->dst, crypt->dst_buf); 4038c2ecf20Sopenharmony_ci } 4048c2ecf20Sopenharmony_ci free_buf_chain(dev, req_ctx->src, crypt->src_buf); 4058c2ecf20Sopenharmony_ci req->base.complete(&req->base, failed); 4068c2ecf20Sopenharmony_ci break; 4078c2ecf20Sopenharmony_ci } 4088c2ecf20Sopenharmony_ci case CTL_FLAG_GEN_ICV: 4098c2ecf20Sopenharmony_ci ctx = crypto_tfm_ctx(crypt->data.tfm); 4108c2ecf20Sopenharmony_ci dma_pool_free(ctx_pool, crypt->regist_ptr, 4118c2ecf20Sopenharmony_ci crypt->regist_buf->phys_addr); 4128c2ecf20Sopenharmony_ci dma_pool_free(buffer_pool, crypt->regist_buf, crypt->src_buf); 4138c2ecf20Sopenharmony_ci if (atomic_dec_and_test(&ctx->configuring)) 4148c2ecf20Sopenharmony_ci complete(&ctx->completion); 4158c2ecf20Sopenharmony_ci break; 4168c2ecf20Sopenharmony_ci case CTL_FLAG_GEN_REVAES: 4178c2ecf20Sopenharmony_ci ctx = crypto_tfm_ctx(crypt->data.tfm); 4188c2ecf20Sopenharmony_ci *(u32*)ctx->decrypt.npe_ctx &= cpu_to_be32(~CIPH_ENCR); 4198c2ecf20Sopenharmony_ci if (atomic_dec_and_test(&ctx->configuring)) 4208c2ecf20Sopenharmony_ci complete(&ctx->completion); 4218c2ecf20Sopenharmony_ci break; 4228c2ecf20Sopenharmony_ci default: 4238c2ecf20Sopenharmony_ci BUG(); 4248c2ecf20Sopenharmony_ci } 4258c2ecf20Sopenharmony_ci crypt->ctl_flags = CTL_FLAG_UNUSED; 4268c2ecf20Sopenharmony_ci} 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_cistatic void irqhandler(void *_unused) 4298c2ecf20Sopenharmony_ci{ 4308c2ecf20Sopenharmony_ci tasklet_schedule(&crypto_done_tasklet); 4318c2ecf20Sopenharmony_ci} 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_cistatic void crypto_done_action(unsigned long arg) 4348c2ecf20Sopenharmony_ci{ 4358c2ecf20Sopenharmony_ci int i; 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci for(i=0; i<4; i++) { 4388c2ecf20Sopenharmony_ci dma_addr_t phys = qmgr_get_entry(RECV_QID); 4398c2ecf20Sopenharmony_ci if (!phys) 4408c2ecf20Sopenharmony_ci return; 4418c2ecf20Sopenharmony_ci one_packet(phys); 4428c2ecf20Sopenharmony_ci } 4438c2ecf20Sopenharmony_ci tasklet_schedule(&crypto_done_tasklet); 4448c2ecf20Sopenharmony_ci} 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_cistatic int init_ixp_crypto(struct device *dev) 4478c2ecf20Sopenharmony_ci{ 4488c2ecf20Sopenharmony_ci int ret = -ENODEV; 4498c2ecf20Sopenharmony_ci u32 msg[2] = { 0, 0 }; 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci if (! ( ~(*IXP4XX_EXP_CFG2) & (IXP4XX_FEATURE_HASH | 4528c2ecf20Sopenharmony_ci IXP4XX_FEATURE_AES | IXP4XX_FEATURE_DES))) { 4538c2ecf20Sopenharmony_ci printk(KERN_ERR "ixp_crypto: No HW crypto available\n"); 4548c2ecf20Sopenharmony_ci return ret; 4558c2ecf20Sopenharmony_ci } 4568c2ecf20Sopenharmony_ci npe_c = npe_request(NPE_ID); 4578c2ecf20Sopenharmony_ci if (!npe_c) 4588c2ecf20Sopenharmony_ci return ret; 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci if (!npe_running(npe_c)) { 4618c2ecf20Sopenharmony_ci ret = npe_load_firmware(npe_c, npe_name(npe_c), dev); 4628c2ecf20Sopenharmony_ci if (ret) 4638c2ecf20Sopenharmony_ci goto npe_release; 4648c2ecf20Sopenharmony_ci if (npe_recv_message(npe_c, msg, "STATUS_MSG")) 4658c2ecf20Sopenharmony_ci goto npe_error; 4668c2ecf20Sopenharmony_ci } else { 4678c2ecf20Sopenharmony_ci if (npe_send_message(npe_c, msg, "STATUS_MSG")) 4688c2ecf20Sopenharmony_ci goto npe_error; 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci if (npe_recv_message(npe_c, msg, "STATUS_MSG")) 4718c2ecf20Sopenharmony_ci goto npe_error; 4728c2ecf20Sopenharmony_ci } 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci switch ((msg[1]>>16) & 0xff) { 4758c2ecf20Sopenharmony_ci case 3: 4768c2ecf20Sopenharmony_ci printk(KERN_WARNING "Firmware of %s lacks AES support\n", 4778c2ecf20Sopenharmony_ci npe_name(npe_c)); 4788c2ecf20Sopenharmony_ci support_aes = 0; 4798c2ecf20Sopenharmony_ci break; 4808c2ecf20Sopenharmony_ci case 4: 4818c2ecf20Sopenharmony_ci case 5: 4828c2ecf20Sopenharmony_ci support_aes = 1; 4838c2ecf20Sopenharmony_ci break; 4848c2ecf20Sopenharmony_ci default: 4858c2ecf20Sopenharmony_ci printk(KERN_ERR "Firmware of %s lacks crypto support\n", 4868c2ecf20Sopenharmony_ci npe_name(npe_c)); 4878c2ecf20Sopenharmony_ci ret = -ENODEV; 4888c2ecf20Sopenharmony_ci goto npe_release; 4898c2ecf20Sopenharmony_ci } 4908c2ecf20Sopenharmony_ci /* buffer_pool will also be used to sometimes store the hmac, 4918c2ecf20Sopenharmony_ci * so assure it is large enough 4928c2ecf20Sopenharmony_ci */ 4938c2ecf20Sopenharmony_ci BUILD_BUG_ON(SHA1_DIGEST_SIZE > sizeof(struct buffer_desc)); 4948c2ecf20Sopenharmony_ci buffer_pool = dma_pool_create("buffer", dev, 4958c2ecf20Sopenharmony_ci sizeof(struct buffer_desc), 32, 0); 4968c2ecf20Sopenharmony_ci ret = -ENOMEM; 4978c2ecf20Sopenharmony_ci if (!buffer_pool) { 4988c2ecf20Sopenharmony_ci goto err; 4998c2ecf20Sopenharmony_ci } 5008c2ecf20Sopenharmony_ci ctx_pool = dma_pool_create("context", dev, 5018c2ecf20Sopenharmony_ci NPE_CTX_LEN, 16, 0); 5028c2ecf20Sopenharmony_ci if (!ctx_pool) { 5038c2ecf20Sopenharmony_ci goto err; 5048c2ecf20Sopenharmony_ci } 5058c2ecf20Sopenharmony_ci ret = qmgr_request_queue(SEND_QID, NPE_QLEN_TOTAL, 0, 0, 5068c2ecf20Sopenharmony_ci "ixp_crypto:out", NULL); 5078c2ecf20Sopenharmony_ci if (ret) 5088c2ecf20Sopenharmony_ci goto err; 5098c2ecf20Sopenharmony_ci ret = qmgr_request_queue(RECV_QID, NPE_QLEN, 0, 0, 5108c2ecf20Sopenharmony_ci "ixp_crypto:in", NULL); 5118c2ecf20Sopenharmony_ci if (ret) { 5128c2ecf20Sopenharmony_ci qmgr_release_queue(SEND_QID); 5138c2ecf20Sopenharmony_ci goto err; 5148c2ecf20Sopenharmony_ci } 5158c2ecf20Sopenharmony_ci qmgr_set_irq(RECV_QID, QUEUE_IRQ_SRC_NOT_EMPTY, irqhandler, NULL); 5168c2ecf20Sopenharmony_ci tasklet_init(&crypto_done_tasklet, crypto_done_action, 0); 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci qmgr_enable_irq(RECV_QID); 5198c2ecf20Sopenharmony_ci return 0; 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_cinpe_error: 5228c2ecf20Sopenharmony_ci printk(KERN_ERR "%s not responding\n", npe_name(npe_c)); 5238c2ecf20Sopenharmony_ci ret = -EIO; 5248c2ecf20Sopenharmony_cierr: 5258c2ecf20Sopenharmony_ci dma_pool_destroy(ctx_pool); 5268c2ecf20Sopenharmony_ci dma_pool_destroy(buffer_pool); 5278c2ecf20Sopenharmony_cinpe_release: 5288c2ecf20Sopenharmony_ci npe_release(npe_c); 5298c2ecf20Sopenharmony_ci return ret; 5308c2ecf20Sopenharmony_ci} 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_cistatic void release_ixp_crypto(struct device *dev) 5338c2ecf20Sopenharmony_ci{ 5348c2ecf20Sopenharmony_ci qmgr_disable_irq(RECV_QID); 5358c2ecf20Sopenharmony_ci tasklet_kill(&crypto_done_tasklet); 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci qmgr_release_queue(SEND_QID); 5388c2ecf20Sopenharmony_ci qmgr_release_queue(RECV_QID); 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci dma_pool_destroy(ctx_pool); 5418c2ecf20Sopenharmony_ci dma_pool_destroy(buffer_pool); 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci npe_release(npe_c); 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci if (crypt_virt) { 5468c2ecf20Sopenharmony_ci dma_free_coherent(dev, 5478c2ecf20Sopenharmony_ci NPE_QLEN * sizeof(struct crypt_ctl), 5488c2ecf20Sopenharmony_ci crypt_virt, crypt_phys); 5498c2ecf20Sopenharmony_ci } 5508c2ecf20Sopenharmony_ci} 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_cistatic void reset_sa_dir(struct ix_sa_dir *dir) 5538c2ecf20Sopenharmony_ci{ 5548c2ecf20Sopenharmony_ci memset(dir->npe_ctx, 0, NPE_CTX_LEN); 5558c2ecf20Sopenharmony_ci dir->npe_ctx_idx = 0; 5568c2ecf20Sopenharmony_ci dir->npe_mode = 0; 5578c2ecf20Sopenharmony_ci} 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_cistatic int init_sa_dir(struct ix_sa_dir *dir) 5608c2ecf20Sopenharmony_ci{ 5618c2ecf20Sopenharmony_ci dir->npe_ctx = dma_pool_alloc(ctx_pool, GFP_KERNEL, &dir->npe_ctx_phys); 5628c2ecf20Sopenharmony_ci if (!dir->npe_ctx) { 5638c2ecf20Sopenharmony_ci return -ENOMEM; 5648c2ecf20Sopenharmony_ci } 5658c2ecf20Sopenharmony_ci reset_sa_dir(dir); 5668c2ecf20Sopenharmony_ci return 0; 5678c2ecf20Sopenharmony_ci} 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_cistatic void free_sa_dir(struct ix_sa_dir *dir) 5708c2ecf20Sopenharmony_ci{ 5718c2ecf20Sopenharmony_ci memset(dir->npe_ctx, 0, NPE_CTX_LEN); 5728c2ecf20Sopenharmony_ci dma_pool_free(ctx_pool, dir->npe_ctx, dir->npe_ctx_phys); 5738c2ecf20Sopenharmony_ci} 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_cistatic int init_tfm(struct crypto_tfm *tfm) 5768c2ecf20Sopenharmony_ci{ 5778c2ecf20Sopenharmony_ci struct ixp_ctx *ctx = crypto_tfm_ctx(tfm); 5788c2ecf20Sopenharmony_ci int ret; 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci atomic_set(&ctx->configuring, 0); 5818c2ecf20Sopenharmony_ci ret = init_sa_dir(&ctx->encrypt); 5828c2ecf20Sopenharmony_ci if (ret) 5838c2ecf20Sopenharmony_ci return ret; 5848c2ecf20Sopenharmony_ci ret = init_sa_dir(&ctx->decrypt); 5858c2ecf20Sopenharmony_ci if (ret) { 5868c2ecf20Sopenharmony_ci free_sa_dir(&ctx->encrypt); 5878c2ecf20Sopenharmony_ci } 5888c2ecf20Sopenharmony_ci return ret; 5898c2ecf20Sopenharmony_ci} 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_cistatic int init_tfm_ablk(struct crypto_skcipher *tfm) 5928c2ecf20Sopenharmony_ci{ 5938c2ecf20Sopenharmony_ci crypto_skcipher_set_reqsize(tfm, sizeof(struct ablk_ctx)); 5948c2ecf20Sopenharmony_ci return init_tfm(crypto_skcipher_tfm(tfm)); 5958c2ecf20Sopenharmony_ci} 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_cistatic int init_tfm_aead(struct crypto_aead *tfm) 5988c2ecf20Sopenharmony_ci{ 5998c2ecf20Sopenharmony_ci crypto_aead_set_reqsize(tfm, sizeof(struct aead_ctx)); 6008c2ecf20Sopenharmony_ci return init_tfm(crypto_aead_tfm(tfm)); 6018c2ecf20Sopenharmony_ci} 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_cistatic void exit_tfm(struct crypto_tfm *tfm) 6048c2ecf20Sopenharmony_ci{ 6058c2ecf20Sopenharmony_ci struct ixp_ctx *ctx = crypto_tfm_ctx(tfm); 6068c2ecf20Sopenharmony_ci free_sa_dir(&ctx->encrypt); 6078c2ecf20Sopenharmony_ci free_sa_dir(&ctx->decrypt); 6088c2ecf20Sopenharmony_ci} 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_cistatic void exit_tfm_ablk(struct crypto_skcipher *tfm) 6118c2ecf20Sopenharmony_ci{ 6128c2ecf20Sopenharmony_ci exit_tfm(crypto_skcipher_tfm(tfm)); 6138c2ecf20Sopenharmony_ci} 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_cistatic void exit_tfm_aead(struct crypto_aead *tfm) 6168c2ecf20Sopenharmony_ci{ 6178c2ecf20Sopenharmony_ci exit_tfm(crypto_aead_tfm(tfm)); 6188c2ecf20Sopenharmony_ci} 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_cistatic int register_chain_var(struct crypto_tfm *tfm, u8 xpad, u32 target, 6218c2ecf20Sopenharmony_ci int init_len, u32 ctx_addr, const u8 *key, int key_len) 6228c2ecf20Sopenharmony_ci{ 6238c2ecf20Sopenharmony_ci struct ixp_ctx *ctx = crypto_tfm_ctx(tfm); 6248c2ecf20Sopenharmony_ci struct crypt_ctl *crypt; 6258c2ecf20Sopenharmony_ci struct buffer_desc *buf; 6268c2ecf20Sopenharmony_ci int i; 6278c2ecf20Sopenharmony_ci u8 *pad; 6288c2ecf20Sopenharmony_ci dma_addr_t pad_phys, buf_phys; 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci BUILD_BUG_ON(NPE_CTX_LEN < HMAC_PAD_BLOCKLEN); 6318c2ecf20Sopenharmony_ci pad = dma_pool_alloc(ctx_pool, GFP_KERNEL, &pad_phys); 6328c2ecf20Sopenharmony_ci if (!pad) 6338c2ecf20Sopenharmony_ci return -ENOMEM; 6348c2ecf20Sopenharmony_ci buf = dma_pool_alloc(buffer_pool, GFP_KERNEL, &buf_phys); 6358c2ecf20Sopenharmony_ci if (!buf) { 6368c2ecf20Sopenharmony_ci dma_pool_free(ctx_pool, pad, pad_phys); 6378c2ecf20Sopenharmony_ci return -ENOMEM; 6388c2ecf20Sopenharmony_ci } 6398c2ecf20Sopenharmony_ci crypt = get_crypt_desc_emerg(); 6408c2ecf20Sopenharmony_ci if (!crypt) { 6418c2ecf20Sopenharmony_ci dma_pool_free(ctx_pool, pad, pad_phys); 6428c2ecf20Sopenharmony_ci dma_pool_free(buffer_pool, buf, buf_phys); 6438c2ecf20Sopenharmony_ci return -EAGAIN; 6448c2ecf20Sopenharmony_ci } 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci memcpy(pad, key, key_len); 6478c2ecf20Sopenharmony_ci memset(pad + key_len, 0, HMAC_PAD_BLOCKLEN - key_len); 6488c2ecf20Sopenharmony_ci for (i = 0; i < HMAC_PAD_BLOCKLEN; i++) { 6498c2ecf20Sopenharmony_ci pad[i] ^= xpad; 6508c2ecf20Sopenharmony_ci } 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci crypt->data.tfm = tfm; 6538c2ecf20Sopenharmony_ci crypt->regist_ptr = pad; 6548c2ecf20Sopenharmony_ci crypt->regist_buf = buf; 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci crypt->auth_offs = 0; 6578c2ecf20Sopenharmony_ci crypt->auth_len = HMAC_PAD_BLOCKLEN; 6588c2ecf20Sopenharmony_ci crypt->crypto_ctx = ctx_addr; 6598c2ecf20Sopenharmony_ci crypt->src_buf = buf_phys; 6608c2ecf20Sopenharmony_ci crypt->icv_rev_aes = target; 6618c2ecf20Sopenharmony_ci crypt->mode = NPE_OP_HASH_GEN_ICV; 6628c2ecf20Sopenharmony_ci crypt->init_len = init_len; 6638c2ecf20Sopenharmony_ci crypt->ctl_flags |= CTL_FLAG_GEN_ICV; 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci buf->next = 0; 6668c2ecf20Sopenharmony_ci buf->buf_len = HMAC_PAD_BLOCKLEN; 6678c2ecf20Sopenharmony_ci buf->pkt_len = 0; 6688c2ecf20Sopenharmony_ci buf->phys_addr = pad_phys; 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci atomic_inc(&ctx->configuring); 6718c2ecf20Sopenharmony_ci qmgr_put_entry(SEND_QID, crypt_virt2phys(crypt)); 6728c2ecf20Sopenharmony_ci BUG_ON(qmgr_stat_overflow(SEND_QID)); 6738c2ecf20Sopenharmony_ci return 0; 6748c2ecf20Sopenharmony_ci} 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_cistatic int setup_auth(struct crypto_tfm *tfm, int encrypt, unsigned authsize, 6778c2ecf20Sopenharmony_ci const u8 *key, int key_len, unsigned digest_len) 6788c2ecf20Sopenharmony_ci{ 6798c2ecf20Sopenharmony_ci u32 itarget, otarget, npe_ctx_addr; 6808c2ecf20Sopenharmony_ci unsigned char *cinfo; 6818c2ecf20Sopenharmony_ci int init_len, ret = 0; 6828c2ecf20Sopenharmony_ci u32 cfgword; 6838c2ecf20Sopenharmony_ci struct ix_sa_dir *dir; 6848c2ecf20Sopenharmony_ci struct ixp_ctx *ctx = crypto_tfm_ctx(tfm); 6858c2ecf20Sopenharmony_ci const struct ix_hash_algo *algo; 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci dir = encrypt ? &ctx->encrypt : &ctx->decrypt; 6888c2ecf20Sopenharmony_ci cinfo = dir->npe_ctx + dir->npe_ctx_idx; 6898c2ecf20Sopenharmony_ci algo = ix_hash(tfm); 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci /* write cfg word to cryptinfo */ 6928c2ecf20Sopenharmony_ci cfgword = algo->cfgword | ( authsize << 6); /* (authsize/4) << 8 */ 6938c2ecf20Sopenharmony_ci#ifndef __ARMEB__ 6948c2ecf20Sopenharmony_ci cfgword ^= 0xAA000000; /* change the "byte swap" flags */ 6958c2ecf20Sopenharmony_ci#endif 6968c2ecf20Sopenharmony_ci *(u32*)cinfo = cpu_to_be32(cfgword); 6978c2ecf20Sopenharmony_ci cinfo += sizeof(cfgword); 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci /* write ICV to cryptinfo */ 7008c2ecf20Sopenharmony_ci memcpy(cinfo, algo->icv, digest_len); 7018c2ecf20Sopenharmony_ci cinfo += digest_len; 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci itarget = dir->npe_ctx_phys + dir->npe_ctx_idx 7048c2ecf20Sopenharmony_ci + sizeof(algo->cfgword); 7058c2ecf20Sopenharmony_ci otarget = itarget + digest_len; 7068c2ecf20Sopenharmony_ci init_len = cinfo - (dir->npe_ctx + dir->npe_ctx_idx); 7078c2ecf20Sopenharmony_ci npe_ctx_addr = dir->npe_ctx_phys + dir->npe_ctx_idx; 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci dir->npe_ctx_idx += init_len; 7108c2ecf20Sopenharmony_ci dir->npe_mode |= NPE_OP_HASH_ENABLE; 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci if (!encrypt) 7138c2ecf20Sopenharmony_ci dir->npe_mode |= NPE_OP_HASH_VERIFY; 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci ret = register_chain_var(tfm, HMAC_OPAD_VALUE, otarget, 7168c2ecf20Sopenharmony_ci init_len, npe_ctx_addr, key, key_len); 7178c2ecf20Sopenharmony_ci if (ret) 7188c2ecf20Sopenharmony_ci return ret; 7198c2ecf20Sopenharmony_ci return register_chain_var(tfm, HMAC_IPAD_VALUE, itarget, 7208c2ecf20Sopenharmony_ci init_len, npe_ctx_addr, key, key_len); 7218c2ecf20Sopenharmony_ci} 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_cistatic int gen_rev_aes_key(struct crypto_tfm *tfm) 7248c2ecf20Sopenharmony_ci{ 7258c2ecf20Sopenharmony_ci struct crypt_ctl *crypt; 7268c2ecf20Sopenharmony_ci struct ixp_ctx *ctx = crypto_tfm_ctx(tfm); 7278c2ecf20Sopenharmony_ci struct ix_sa_dir *dir = &ctx->decrypt; 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci crypt = get_crypt_desc_emerg(); 7308c2ecf20Sopenharmony_ci if (!crypt) { 7318c2ecf20Sopenharmony_ci return -EAGAIN; 7328c2ecf20Sopenharmony_ci } 7338c2ecf20Sopenharmony_ci *(u32*)dir->npe_ctx |= cpu_to_be32(CIPH_ENCR); 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci crypt->data.tfm = tfm; 7368c2ecf20Sopenharmony_ci crypt->crypt_offs = 0; 7378c2ecf20Sopenharmony_ci crypt->crypt_len = AES_BLOCK128; 7388c2ecf20Sopenharmony_ci crypt->src_buf = 0; 7398c2ecf20Sopenharmony_ci crypt->crypto_ctx = dir->npe_ctx_phys; 7408c2ecf20Sopenharmony_ci crypt->icv_rev_aes = dir->npe_ctx_phys + sizeof(u32); 7418c2ecf20Sopenharmony_ci crypt->mode = NPE_OP_ENC_GEN_KEY; 7428c2ecf20Sopenharmony_ci crypt->init_len = dir->npe_ctx_idx; 7438c2ecf20Sopenharmony_ci crypt->ctl_flags |= CTL_FLAG_GEN_REVAES; 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci atomic_inc(&ctx->configuring); 7468c2ecf20Sopenharmony_ci qmgr_put_entry(SEND_QID, crypt_virt2phys(crypt)); 7478c2ecf20Sopenharmony_ci BUG_ON(qmgr_stat_overflow(SEND_QID)); 7488c2ecf20Sopenharmony_ci return 0; 7498c2ecf20Sopenharmony_ci} 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_cistatic int setup_cipher(struct crypto_tfm *tfm, int encrypt, 7528c2ecf20Sopenharmony_ci const u8 *key, int key_len) 7538c2ecf20Sopenharmony_ci{ 7548c2ecf20Sopenharmony_ci u8 *cinfo; 7558c2ecf20Sopenharmony_ci u32 cipher_cfg; 7568c2ecf20Sopenharmony_ci u32 keylen_cfg = 0; 7578c2ecf20Sopenharmony_ci struct ix_sa_dir *dir; 7588c2ecf20Sopenharmony_ci struct ixp_ctx *ctx = crypto_tfm_ctx(tfm); 7598c2ecf20Sopenharmony_ci int err; 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci dir = encrypt ? &ctx->encrypt : &ctx->decrypt; 7628c2ecf20Sopenharmony_ci cinfo = dir->npe_ctx; 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci if (encrypt) { 7658c2ecf20Sopenharmony_ci cipher_cfg = cipher_cfg_enc(tfm); 7668c2ecf20Sopenharmony_ci dir->npe_mode |= NPE_OP_CRYPT_ENCRYPT; 7678c2ecf20Sopenharmony_ci } else { 7688c2ecf20Sopenharmony_ci cipher_cfg = cipher_cfg_dec(tfm); 7698c2ecf20Sopenharmony_ci } 7708c2ecf20Sopenharmony_ci if (cipher_cfg & MOD_AES) { 7718c2ecf20Sopenharmony_ci switch (key_len) { 7728c2ecf20Sopenharmony_ci case 16: keylen_cfg = MOD_AES128; break; 7738c2ecf20Sopenharmony_ci case 24: keylen_cfg = MOD_AES192; break; 7748c2ecf20Sopenharmony_ci case 32: keylen_cfg = MOD_AES256; break; 7758c2ecf20Sopenharmony_ci default: 7768c2ecf20Sopenharmony_ci return -EINVAL; 7778c2ecf20Sopenharmony_ci } 7788c2ecf20Sopenharmony_ci cipher_cfg |= keylen_cfg; 7798c2ecf20Sopenharmony_ci } else { 7808c2ecf20Sopenharmony_ci err = crypto_des_verify_key(tfm, key); 7818c2ecf20Sopenharmony_ci if (err) 7828c2ecf20Sopenharmony_ci return err; 7838c2ecf20Sopenharmony_ci } 7848c2ecf20Sopenharmony_ci /* write cfg word to cryptinfo */ 7858c2ecf20Sopenharmony_ci *(u32*)cinfo = cpu_to_be32(cipher_cfg); 7868c2ecf20Sopenharmony_ci cinfo += sizeof(cipher_cfg); 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci /* write cipher key to cryptinfo */ 7898c2ecf20Sopenharmony_ci memcpy(cinfo, key, key_len); 7908c2ecf20Sopenharmony_ci /* NPE wants keylen set to DES3_EDE_KEY_SIZE even for single DES */ 7918c2ecf20Sopenharmony_ci if (key_len < DES3_EDE_KEY_SIZE && !(cipher_cfg & MOD_AES)) { 7928c2ecf20Sopenharmony_ci memset(cinfo + key_len, 0, DES3_EDE_KEY_SIZE -key_len); 7938c2ecf20Sopenharmony_ci key_len = DES3_EDE_KEY_SIZE; 7948c2ecf20Sopenharmony_ci } 7958c2ecf20Sopenharmony_ci dir->npe_ctx_idx = sizeof(cipher_cfg) + key_len; 7968c2ecf20Sopenharmony_ci dir->npe_mode |= NPE_OP_CRYPT_ENABLE; 7978c2ecf20Sopenharmony_ci if ((cipher_cfg & MOD_AES) && !encrypt) { 7988c2ecf20Sopenharmony_ci return gen_rev_aes_key(tfm); 7998c2ecf20Sopenharmony_ci } 8008c2ecf20Sopenharmony_ci return 0; 8018c2ecf20Sopenharmony_ci} 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_cistatic struct buffer_desc *chainup_buffers(struct device *dev, 8048c2ecf20Sopenharmony_ci struct scatterlist *sg, unsigned nbytes, 8058c2ecf20Sopenharmony_ci struct buffer_desc *buf, gfp_t flags, 8068c2ecf20Sopenharmony_ci enum dma_data_direction dir) 8078c2ecf20Sopenharmony_ci{ 8088c2ecf20Sopenharmony_ci for (; nbytes > 0; sg = sg_next(sg)) { 8098c2ecf20Sopenharmony_ci unsigned len = min(nbytes, sg->length); 8108c2ecf20Sopenharmony_ci struct buffer_desc *next_buf; 8118c2ecf20Sopenharmony_ci dma_addr_t next_buf_phys; 8128c2ecf20Sopenharmony_ci void *ptr; 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci nbytes -= len; 8158c2ecf20Sopenharmony_ci ptr = sg_virt(sg); 8168c2ecf20Sopenharmony_ci next_buf = dma_pool_alloc(buffer_pool, flags, &next_buf_phys); 8178c2ecf20Sopenharmony_ci if (!next_buf) { 8188c2ecf20Sopenharmony_ci buf = NULL; 8198c2ecf20Sopenharmony_ci break; 8208c2ecf20Sopenharmony_ci } 8218c2ecf20Sopenharmony_ci sg_dma_address(sg) = dma_map_single(dev, ptr, len, dir); 8228c2ecf20Sopenharmony_ci buf->next = next_buf; 8238c2ecf20Sopenharmony_ci buf->phys_next = next_buf_phys; 8248c2ecf20Sopenharmony_ci buf = next_buf; 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci buf->phys_addr = sg_dma_address(sg); 8278c2ecf20Sopenharmony_ci buf->buf_len = len; 8288c2ecf20Sopenharmony_ci buf->dir = dir; 8298c2ecf20Sopenharmony_ci } 8308c2ecf20Sopenharmony_ci buf->next = NULL; 8318c2ecf20Sopenharmony_ci buf->phys_next = 0; 8328c2ecf20Sopenharmony_ci return buf; 8338c2ecf20Sopenharmony_ci} 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_cistatic int ablk_setkey(struct crypto_skcipher *tfm, const u8 *key, 8368c2ecf20Sopenharmony_ci unsigned int key_len) 8378c2ecf20Sopenharmony_ci{ 8388c2ecf20Sopenharmony_ci struct ixp_ctx *ctx = crypto_skcipher_ctx(tfm); 8398c2ecf20Sopenharmony_ci int ret; 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci init_completion(&ctx->completion); 8428c2ecf20Sopenharmony_ci atomic_inc(&ctx->configuring); 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci reset_sa_dir(&ctx->encrypt); 8458c2ecf20Sopenharmony_ci reset_sa_dir(&ctx->decrypt); 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci ctx->encrypt.npe_mode = NPE_OP_HMAC_DISABLE; 8488c2ecf20Sopenharmony_ci ctx->decrypt.npe_mode = NPE_OP_HMAC_DISABLE; 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_ci ret = setup_cipher(&tfm->base, 0, key, key_len); 8518c2ecf20Sopenharmony_ci if (ret) 8528c2ecf20Sopenharmony_ci goto out; 8538c2ecf20Sopenharmony_ci ret = setup_cipher(&tfm->base, 1, key, key_len); 8548c2ecf20Sopenharmony_ciout: 8558c2ecf20Sopenharmony_ci if (!atomic_dec_and_test(&ctx->configuring)) 8568c2ecf20Sopenharmony_ci wait_for_completion(&ctx->completion); 8578c2ecf20Sopenharmony_ci return ret; 8588c2ecf20Sopenharmony_ci} 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_cistatic int ablk_des3_setkey(struct crypto_skcipher *tfm, const u8 *key, 8618c2ecf20Sopenharmony_ci unsigned int key_len) 8628c2ecf20Sopenharmony_ci{ 8638c2ecf20Sopenharmony_ci return verify_skcipher_des3_key(tfm, key) ?: 8648c2ecf20Sopenharmony_ci ablk_setkey(tfm, key, key_len); 8658c2ecf20Sopenharmony_ci} 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_cistatic int ablk_rfc3686_setkey(struct crypto_skcipher *tfm, const u8 *key, 8688c2ecf20Sopenharmony_ci unsigned int key_len) 8698c2ecf20Sopenharmony_ci{ 8708c2ecf20Sopenharmony_ci struct ixp_ctx *ctx = crypto_skcipher_ctx(tfm); 8718c2ecf20Sopenharmony_ci 8728c2ecf20Sopenharmony_ci /* the nonce is stored in bytes at end of key */ 8738c2ecf20Sopenharmony_ci if (key_len < CTR_RFC3686_NONCE_SIZE) 8748c2ecf20Sopenharmony_ci return -EINVAL; 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci memcpy(ctx->nonce, key + (key_len - CTR_RFC3686_NONCE_SIZE), 8778c2ecf20Sopenharmony_ci CTR_RFC3686_NONCE_SIZE); 8788c2ecf20Sopenharmony_ci 8798c2ecf20Sopenharmony_ci key_len -= CTR_RFC3686_NONCE_SIZE; 8808c2ecf20Sopenharmony_ci return ablk_setkey(tfm, key, key_len); 8818c2ecf20Sopenharmony_ci} 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_cistatic int ablk_perform(struct skcipher_request *req, int encrypt) 8848c2ecf20Sopenharmony_ci{ 8858c2ecf20Sopenharmony_ci struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 8868c2ecf20Sopenharmony_ci struct ixp_ctx *ctx = crypto_skcipher_ctx(tfm); 8878c2ecf20Sopenharmony_ci unsigned ivsize = crypto_skcipher_ivsize(tfm); 8888c2ecf20Sopenharmony_ci struct ix_sa_dir *dir; 8898c2ecf20Sopenharmony_ci struct crypt_ctl *crypt; 8908c2ecf20Sopenharmony_ci unsigned int nbytes = req->cryptlen; 8918c2ecf20Sopenharmony_ci enum dma_data_direction src_direction = DMA_BIDIRECTIONAL; 8928c2ecf20Sopenharmony_ci struct ablk_ctx *req_ctx = skcipher_request_ctx(req); 8938c2ecf20Sopenharmony_ci struct buffer_desc src_hook; 8948c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 8958c2ecf20Sopenharmony_ci unsigned int offset; 8968c2ecf20Sopenharmony_ci gfp_t flags = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP ? 8978c2ecf20Sopenharmony_ci GFP_KERNEL : GFP_ATOMIC; 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_ci if (qmgr_stat_full(SEND_QID)) 9008c2ecf20Sopenharmony_ci return -EAGAIN; 9018c2ecf20Sopenharmony_ci if (atomic_read(&ctx->configuring)) 9028c2ecf20Sopenharmony_ci return -EAGAIN; 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_ci dir = encrypt ? &ctx->encrypt : &ctx->decrypt; 9058c2ecf20Sopenharmony_ci req_ctx->encrypt = encrypt; 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_ci crypt = get_crypt_desc(); 9088c2ecf20Sopenharmony_ci if (!crypt) 9098c2ecf20Sopenharmony_ci return -ENOMEM; 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ci crypt->data.ablk_req = req; 9128c2ecf20Sopenharmony_ci crypt->crypto_ctx = dir->npe_ctx_phys; 9138c2ecf20Sopenharmony_ci crypt->mode = dir->npe_mode; 9148c2ecf20Sopenharmony_ci crypt->init_len = dir->npe_ctx_idx; 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_ci crypt->crypt_offs = 0; 9178c2ecf20Sopenharmony_ci crypt->crypt_len = nbytes; 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ci BUG_ON(ivsize && !req->iv); 9208c2ecf20Sopenharmony_ci memcpy(crypt->iv, req->iv, ivsize); 9218c2ecf20Sopenharmony_ci if (ivsize > 0 && !encrypt) { 9228c2ecf20Sopenharmony_ci offset = req->cryptlen - ivsize; 9238c2ecf20Sopenharmony_ci scatterwalk_map_and_copy(req_ctx->iv, req->src, offset, ivsize, 0); 9248c2ecf20Sopenharmony_ci } 9258c2ecf20Sopenharmony_ci if (req->src != req->dst) { 9268c2ecf20Sopenharmony_ci struct buffer_desc dst_hook; 9278c2ecf20Sopenharmony_ci crypt->mode |= NPE_OP_NOT_IN_PLACE; 9288c2ecf20Sopenharmony_ci /* This was never tested by Intel 9298c2ecf20Sopenharmony_ci * for more than one dst buffer, I think. */ 9308c2ecf20Sopenharmony_ci req_ctx->dst = NULL; 9318c2ecf20Sopenharmony_ci if (!chainup_buffers(dev, req->dst, nbytes, &dst_hook, 9328c2ecf20Sopenharmony_ci flags, DMA_FROM_DEVICE)) 9338c2ecf20Sopenharmony_ci goto free_buf_dest; 9348c2ecf20Sopenharmony_ci src_direction = DMA_TO_DEVICE; 9358c2ecf20Sopenharmony_ci req_ctx->dst = dst_hook.next; 9368c2ecf20Sopenharmony_ci crypt->dst_buf = dst_hook.phys_next; 9378c2ecf20Sopenharmony_ci } else { 9388c2ecf20Sopenharmony_ci req_ctx->dst = NULL; 9398c2ecf20Sopenharmony_ci } 9408c2ecf20Sopenharmony_ci req_ctx->src = NULL; 9418c2ecf20Sopenharmony_ci if (!chainup_buffers(dev, req->src, nbytes, &src_hook, 9428c2ecf20Sopenharmony_ci flags, src_direction)) 9438c2ecf20Sopenharmony_ci goto free_buf_src; 9448c2ecf20Sopenharmony_ci 9458c2ecf20Sopenharmony_ci req_ctx->src = src_hook.next; 9468c2ecf20Sopenharmony_ci crypt->src_buf = src_hook.phys_next; 9478c2ecf20Sopenharmony_ci crypt->ctl_flags |= CTL_FLAG_PERFORM_ABLK; 9488c2ecf20Sopenharmony_ci qmgr_put_entry(SEND_QID, crypt_virt2phys(crypt)); 9498c2ecf20Sopenharmony_ci BUG_ON(qmgr_stat_overflow(SEND_QID)); 9508c2ecf20Sopenharmony_ci return -EINPROGRESS; 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_cifree_buf_src: 9538c2ecf20Sopenharmony_ci free_buf_chain(dev, req_ctx->src, crypt->src_buf); 9548c2ecf20Sopenharmony_cifree_buf_dest: 9558c2ecf20Sopenharmony_ci if (req->src != req->dst) { 9568c2ecf20Sopenharmony_ci free_buf_chain(dev, req_ctx->dst, crypt->dst_buf); 9578c2ecf20Sopenharmony_ci } 9588c2ecf20Sopenharmony_ci crypt->ctl_flags = CTL_FLAG_UNUSED; 9598c2ecf20Sopenharmony_ci return -ENOMEM; 9608c2ecf20Sopenharmony_ci} 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_cistatic int ablk_encrypt(struct skcipher_request *req) 9638c2ecf20Sopenharmony_ci{ 9648c2ecf20Sopenharmony_ci return ablk_perform(req, 1); 9658c2ecf20Sopenharmony_ci} 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_cistatic int ablk_decrypt(struct skcipher_request *req) 9688c2ecf20Sopenharmony_ci{ 9698c2ecf20Sopenharmony_ci return ablk_perform(req, 0); 9708c2ecf20Sopenharmony_ci} 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_cistatic int ablk_rfc3686_crypt(struct skcipher_request *req) 9738c2ecf20Sopenharmony_ci{ 9748c2ecf20Sopenharmony_ci struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 9758c2ecf20Sopenharmony_ci struct ixp_ctx *ctx = crypto_skcipher_ctx(tfm); 9768c2ecf20Sopenharmony_ci u8 iv[CTR_RFC3686_BLOCK_SIZE]; 9778c2ecf20Sopenharmony_ci u8 *info = req->iv; 9788c2ecf20Sopenharmony_ci int ret; 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci /* set up counter block */ 9818c2ecf20Sopenharmony_ci memcpy(iv, ctx->nonce, CTR_RFC3686_NONCE_SIZE); 9828c2ecf20Sopenharmony_ci memcpy(iv + CTR_RFC3686_NONCE_SIZE, info, CTR_RFC3686_IV_SIZE); 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_ci /* initialize counter portion of counter block */ 9858c2ecf20Sopenharmony_ci *(__be32 *)(iv + CTR_RFC3686_NONCE_SIZE + CTR_RFC3686_IV_SIZE) = 9868c2ecf20Sopenharmony_ci cpu_to_be32(1); 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_ci req->iv = iv; 9898c2ecf20Sopenharmony_ci ret = ablk_perform(req, 1); 9908c2ecf20Sopenharmony_ci req->iv = info; 9918c2ecf20Sopenharmony_ci return ret; 9928c2ecf20Sopenharmony_ci} 9938c2ecf20Sopenharmony_ci 9948c2ecf20Sopenharmony_cistatic int aead_perform(struct aead_request *req, int encrypt, 9958c2ecf20Sopenharmony_ci int cryptoffset, int eff_cryptlen, u8 *iv) 9968c2ecf20Sopenharmony_ci{ 9978c2ecf20Sopenharmony_ci struct crypto_aead *tfm = crypto_aead_reqtfm(req); 9988c2ecf20Sopenharmony_ci struct ixp_ctx *ctx = crypto_aead_ctx(tfm); 9998c2ecf20Sopenharmony_ci unsigned ivsize = crypto_aead_ivsize(tfm); 10008c2ecf20Sopenharmony_ci unsigned authsize = crypto_aead_authsize(tfm); 10018c2ecf20Sopenharmony_ci struct ix_sa_dir *dir; 10028c2ecf20Sopenharmony_ci struct crypt_ctl *crypt; 10038c2ecf20Sopenharmony_ci unsigned int cryptlen; 10048c2ecf20Sopenharmony_ci struct buffer_desc *buf, src_hook; 10058c2ecf20Sopenharmony_ci struct aead_ctx *req_ctx = aead_request_ctx(req); 10068c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 10078c2ecf20Sopenharmony_ci gfp_t flags = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP ? 10088c2ecf20Sopenharmony_ci GFP_KERNEL : GFP_ATOMIC; 10098c2ecf20Sopenharmony_ci enum dma_data_direction src_direction = DMA_BIDIRECTIONAL; 10108c2ecf20Sopenharmony_ci unsigned int lastlen; 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_ci if (qmgr_stat_full(SEND_QID)) 10138c2ecf20Sopenharmony_ci return -EAGAIN; 10148c2ecf20Sopenharmony_ci if (atomic_read(&ctx->configuring)) 10158c2ecf20Sopenharmony_ci return -EAGAIN; 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_ci if (encrypt) { 10188c2ecf20Sopenharmony_ci dir = &ctx->encrypt; 10198c2ecf20Sopenharmony_ci cryptlen = req->cryptlen; 10208c2ecf20Sopenharmony_ci } else { 10218c2ecf20Sopenharmony_ci dir = &ctx->decrypt; 10228c2ecf20Sopenharmony_ci /* req->cryptlen includes the authsize when decrypting */ 10238c2ecf20Sopenharmony_ci cryptlen = req->cryptlen -authsize; 10248c2ecf20Sopenharmony_ci eff_cryptlen -= authsize; 10258c2ecf20Sopenharmony_ci } 10268c2ecf20Sopenharmony_ci crypt = get_crypt_desc(); 10278c2ecf20Sopenharmony_ci if (!crypt) 10288c2ecf20Sopenharmony_ci return -ENOMEM; 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_ci crypt->data.aead_req = req; 10318c2ecf20Sopenharmony_ci crypt->crypto_ctx = dir->npe_ctx_phys; 10328c2ecf20Sopenharmony_ci crypt->mode = dir->npe_mode; 10338c2ecf20Sopenharmony_ci crypt->init_len = dir->npe_ctx_idx; 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_ci crypt->crypt_offs = cryptoffset; 10368c2ecf20Sopenharmony_ci crypt->crypt_len = eff_cryptlen; 10378c2ecf20Sopenharmony_ci 10388c2ecf20Sopenharmony_ci crypt->auth_offs = 0; 10398c2ecf20Sopenharmony_ci crypt->auth_len = req->assoclen + cryptlen; 10408c2ecf20Sopenharmony_ci BUG_ON(ivsize && !req->iv); 10418c2ecf20Sopenharmony_ci memcpy(crypt->iv, req->iv, ivsize); 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_ci buf = chainup_buffers(dev, req->src, crypt->auth_len, 10448c2ecf20Sopenharmony_ci &src_hook, flags, src_direction); 10458c2ecf20Sopenharmony_ci req_ctx->src = src_hook.next; 10468c2ecf20Sopenharmony_ci crypt->src_buf = src_hook.phys_next; 10478c2ecf20Sopenharmony_ci if (!buf) 10488c2ecf20Sopenharmony_ci goto free_buf_src; 10498c2ecf20Sopenharmony_ci 10508c2ecf20Sopenharmony_ci lastlen = buf->buf_len; 10518c2ecf20Sopenharmony_ci if (lastlen >= authsize) 10528c2ecf20Sopenharmony_ci crypt->icv_rev_aes = buf->phys_addr + 10538c2ecf20Sopenharmony_ci buf->buf_len - authsize; 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_ci req_ctx->dst = NULL; 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_ci if (req->src != req->dst) { 10588c2ecf20Sopenharmony_ci struct buffer_desc dst_hook; 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_ci crypt->mode |= NPE_OP_NOT_IN_PLACE; 10618c2ecf20Sopenharmony_ci src_direction = DMA_TO_DEVICE; 10628c2ecf20Sopenharmony_ci 10638c2ecf20Sopenharmony_ci buf = chainup_buffers(dev, req->dst, crypt->auth_len, 10648c2ecf20Sopenharmony_ci &dst_hook, flags, DMA_FROM_DEVICE); 10658c2ecf20Sopenharmony_ci req_ctx->dst = dst_hook.next; 10668c2ecf20Sopenharmony_ci crypt->dst_buf = dst_hook.phys_next; 10678c2ecf20Sopenharmony_ci 10688c2ecf20Sopenharmony_ci if (!buf) 10698c2ecf20Sopenharmony_ci goto free_buf_dst; 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_ci if (encrypt) { 10728c2ecf20Sopenharmony_ci lastlen = buf->buf_len; 10738c2ecf20Sopenharmony_ci if (lastlen >= authsize) 10748c2ecf20Sopenharmony_ci crypt->icv_rev_aes = buf->phys_addr + 10758c2ecf20Sopenharmony_ci buf->buf_len - authsize; 10768c2ecf20Sopenharmony_ci } 10778c2ecf20Sopenharmony_ci } 10788c2ecf20Sopenharmony_ci 10798c2ecf20Sopenharmony_ci if (unlikely(lastlen < authsize)) { 10808c2ecf20Sopenharmony_ci /* The 12 hmac bytes are scattered, 10818c2ecf20Sopenharmony_ci * we need to copy them into a safe buffer */ 10828c2ecf20Sopenharmony_ci req_ctx->hmac_virt = dma_pool_alloc(buffer_pool, flags, 10838c2ecf20Sopenharmony_ci &crypt->icv_rev_aes); 10848c2ecf20Sopenharmony_ci if (unlikely(!req_ctx->hmac_virt)) 10858c2ecf20Sopenharmony_ci goto free_buf_dst; 10868c2ecf20Sopenharmony_ci if (!encrypt) { 10878c2ecf20Sopenharmony_ci scatterwalk_map_and_copy(req_ctx->hmac_virt, 10888c2ecf20Sopenharmony_ci req->src, cryptlen, authsize, 0); 10898c2ecf20Sopenharmony_ci } 10908c2ecf20Sopenharmony_ci req_ctx->encrypt = encrypt; 10918c2ecf20Sopenharmony_ci } else { 10928c2ecf20Sopenharmony_ci req_ctx->hmac_virt = NULL; 10938c2ecf20Sopenharmony_ci } 10948c2ecf20Sopenharmony_ci 10958c2ecf20Sopenharmony_ci crypt->ctl_flags |= CTL_FLAG_PERFORM_AEAD; 10968c2ecf20Sopenharmony_ci qmgr_put_entry(SEND_QID, crypt_virt2phys(crypt)); 10978c2ecf20Sopenharmony_ci BUG_ON(qmgr_stat_overflow(SEND_QID)); 10988c2ecf20Sopenharmony_ci return -EINPROGRESS; 10998c2ecf20Sopenharmony_ci 11008c2ecf20Sopenharmony_cifree_buf_dst: 11018c2ecf20Sopenharmony_ci free_buf_chain(dev, req_ctx->dst, crypt->dst_buf); 11028c2ecf20Sopenharmony_cifree_buf_src: 11038c2ecf20Sopenharmony_ci free_buf_chain(dev, req_ctx->src, crypt->src_buf); 11048c2ecf20Sopenharmony_ci crypt->ctl_flags = CTL_FLAG_UNUSED; 11058c2ecf20Sopenharmony_ci return -ENOMEM; 11068c2ecf20Sopenharmony_ci} 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_cistatic int aead_setup(struct crypto_aead *tfm, unsigned int authsize) 11098c2ecf20Sopenharmony_ci{ 11108c2ecf20Sopenharmony_ci struct ixp_ctx *ctx = crypto_aead_ctx(tfm); 11118c2ecf20Sopenharmony_ci unsigned digest_len = crypto_aead_maxauthsize(tfm); 11128c2ecf20Sopenharmony_ci int ret; 11138c2ecf20Sopenharmony_ci 11148c2ecf20Sopenharmony_ci if (!ctx->enckey_len && !ctx->authkey_len) 11158c2ecf20Sopenharmony_ci return 0; 11168c2ecf20Sopenharmony_ci init_completion(&ctx->completion); 11178c2ecf20Sopenharmony_ci atomic_inc(&ctx->configuring); 11188c2ecf20Sopenharmony_ci 11198c2ecf20Sopenharmony_ci reset_sa_dir(&ctx->encrypt); 11208c2ecf20Sopenharmony_ci reset_sa_dir(&ctx->decrypt); 11218c2ecf20Sopenharmony_ci 11228c2ecf20Sopenharmony_ci ret = setup_cipher(&tfm->base, 0, ctx->enckey, ctx->enckey_len); 11238c2ecf20Sopenharmony_ci if (ret) 11248c2ecf20Sopenharmony_ci goto out; 11258c2ecf20Sopenharmony_ci ret = setup_cipher(&tfm->base, 1, ctx->enckey, ctx->enckey_len); 11268c2ecf20Sopenharmony_ci if (ret) 11278c2ecf20Sopenharmony_ci goto out; 11288c2ecf20Sopenharmony_ci ret = setup_auth(&tfm->base, 0, authsize, ctx->authkey, 11298c2ecf20Sopenharmony_ci ctx->authkey_len, digest_len); 11308c2ecf20Sopenharmony_ci if (ret) 11318c2ecf20Sopenharmony_ci goto out; 11328c2ecf20Sopenharmony_ci ret = setup_auth(&tfm->base, 1, authsize, ctx->authkey, 11338c2ecf20Sopenharmony_ci ctx->authkey_len, digest_len); 11348c2ecf20Sopenharmony_ciout: 11358c2ecf20Sopenharmony_ci if (!atomic_dec_and_test(&ctx->configuring)) 11368c2ecf20Sopenharmony_ci wait_for_completion(&ctx->completion); 11378c2ecf20Sopenharmony_ci return ret; 11388c2ecf20Sopenharmony_ci} 11398c2ecf20Sopenharmony_ci 11408c2ecf20Sopenharmony_cistatic int aead_setauthsize(struct crypto_aead *tfm, unsigned int authsize) 11418c2ecf20Sopenharmony_ci{ 11428c2ecf20Sopenharmony_ci int max = crypto_aead_maxauthsize(tfm) >> 2; 11438c2ecf20Sopenharmony_ci 11448c2ecf20Sopenharmony_ci if ((authsize>>2) < 1 || (authsize>>2) > max || (authsize & 3)) 11458c2ecf20Sopenharmony_ci return -EINVAL; 11468c2ecf20Sopenharmony_ci return aead_setup(tfm, authsize); 11478c2ecf20Sopenharmony_ci} 11488c2ecf20Sopenharmony_ci 11498c2ecf20Sopenharmony_cistatic int aead_setkey(struct crypto_aead *tfm, const u8 *key, 11508c2ecf20Sopenharmony_ci unsigned int keylen) 11518c2ecf20Sopenharmony_ci{ 11528c2ecf20Sopenharmony_ci struct ixp_ctx *ctx = crypto_aead_ctx(tfm); 11538c2ecf20Sopenharmony_ci struct crypto_authenc_keys keys; 11548c2ecf20Sopenharmony_ci 11558c2ecf20Sopenharmony_ci if (crypto_authenc_extractkeys(&keys, key, keylen) != 0) 11568c2ecf20Sopenharmony_ci goto badkey; 11578c2ecf20Sopenharmony_ci 11588c2ecf20Sopenharmony_ci if (keys.authkeylen > sizeof(ctx->authkey)) 11598c2ecf20Sopenharmony_ci goto badkey; 11608c2ecf20Sopenharmony_ci 11618c2ecf20Sopenharmony_ci if (keys.enckeylen > sizeof(ctx->enckey)) 11628c2ecf20Sopenharmony_ci goto badkey; 11638c2ecf20Sopenharmony_ci 11648c2ecf20Sopenharmony_ci memcpy(ctx->authkey, keys.authkey, keys.authkeylen); 11658c2ecf20Sopenharmony_ci memcpy(ctx->enckey, keys.enckey, keys.enckeylen); 11668c2ecf20Sopenharmony_ci ctx->authkey_len = keys.authkeylen; 11678c2ecf20Sopenharmony_ci ctx->enckey_len = keys.enckeylen; 11688c2ecf20Sopenharmony_ci 11698c2ecf20Sopenharmony_ci memzero_explicit(&keys, sizeof(keys)); 11708c2ecf20Sopenharmony_ci return aead_setup(tfm, crypto_aead_authsize(tfm)); 11718c2ecf20Sopenharmony_cibadkey: 11728c2ecf20Sopenharmony_ci memzero_explicit(&keys, sizeof(keys)); 11738c2ecf20Sopenharmony_ci return -EINVAL; 11748c2ecf20Sopenharmony_ci} 11758c2ecf20Sopenharmony_ci 11768c2ecf20Sopenharmony_cistatic int des3_aead_setkey(struct crypto_aead *tfm, const u8 *key, 11778c2ecf20Sopenharmony_ci unsigned int keylen) 11788c2ecf20Sopenharmony_ci{ 11798c2ecf20Sopenharmony_ci struct ixp_ctx *ctx = crypto_aead_ctx(tfm); 11808c2ecf20Sopenharmony_ci struct crypto_authenc_keys keys; 11818c2ecf20Sopenharmony_ci int err; 11828c2ecf20Sopenharmony_ci 11838c2ecf20Sopenharmony_ci err = crypto_authenc_extractkeys(&keys, key, keylen); 11848c2ecf20Sopenharmony_ci if (unlikely(err)) 11858c2ecf20Sopenharmony_ci goto badkey; 11868c2ecf20Sopenharmony_ci 11878c2ecf20Sopenharmony_ci err = -EINVAL; 11888c2ecf20Sopenharmony_ci if (keys.authkeylen > sizeof(ctx->authkey)) 11898c2ecf20Sopenharmony_ci goto badkey; 11908c2ecf20Sopenharmony_ci 11918c2ecf20Sopenharmony_ci err = verify_aead_des3_key(tfm, keys.enckey, keys.enckeylen); 11928c2ecf20Sopenharmony_ci if (err) 11938c2ecf20Sopenharmony_ci goto badkey; 11948c2ecf20Sopenharmony_ci 11958c2ecf20Sopenharmony_ci memcpy(ctx->authkey, keys.authkey, keys.authkeylen); 11968c2ecf20Sopenharmony_ci memcpy(ctx->enckey, keys.enckey, keys.enckeylen); 11978c2ecf20Sopenharmony_ci ctx->authkey_len = keys.authkeylen; 11988c2ecf20Sopenharmony_ci ctx->enckey_len = keys.enckeylen; 11998c2ecf20Sopenharmony_ci 12008c2ecf20Sopenharmony_ci memzero_explicit(&keys, sizeof(keys)); 12018c2ecf20Sopenharmony_ci return aead_setup(tfm, crypto_aead_authsize(tfm)); 12028c2ecf20Sopenharmony_cibadkey: 12038c2ecf20Sopenharmony_ci memzero_explicit(&keys, sizeof(keys)); 12048c2ecf20Sopenharmony_ci return err; 12058c2ecf20Sopenharmony_ci} 12068c2ecf20Sopenharmony_ci 12078c2ecf20Sopenharmony_cistatic int aead_encrypt(struct aead_request *req) 12088c2ecf20Sopenharmony_ci{ 12098c2ecf20Sopenharmony_ci return aead_perform(req, 1, req->assoclen, req->cryptlen, req->iv); 12108c2ecf20Sopenharmony_ci} 12118c2ecf20Sopenharmony_ci 12128c2ecf20Sopenharmony_cistatic int aead_decrypt(struct aead_request *req) 12138c2ecf20Sopenharmony_ci{ 12148c2ecf20Sopenharmony_ci return aead_perform(req, 0, req->assoclen, req->cryptlen, req->iv); 12158c2ecf20Sopenharmony_ci} 12168c2ecf20Sopenharmony_ci 12178c2ecf20Sopenharmony_cistatic struct ixp_alg ixp4xx_algos[] = { 12188c2ecf20Sopenharmony_ci{ 12198c2ecf20Sopenharmony_ci .crypto = { 12208c2ecf20Sopenharmony_ci .base.cra_name = "cbc(des)", 12218c2ecf20Sopenharmony_ci .base.cra_blocksize = DES_BLOCK_SIZE, 12228c2ecf20Sopenharmony_ci 12238c2ecf20Sopenharmony_ci .min_keysize = DES_KEY_SIZE, 12248c2ecf20Sopenharmony_ci .max_keysize = DES_KEY_SIZE, 12258c2ecf20Sopenharmony_ci .ivsize = DES_BLOCK_SIZE, 12268c2ecf20Sopenharmony_ci }, 12278c2ecf20Sopenharmony_ci .cfg_enc = CIPH_ENCR | MOD_DES | MOD_CBC_ENC | KEYLEN_192, 12288c2ecf20Sopenharmony_ci .cfg_dec = CIPH_DECR | MOD_DES | MOD_CBC_DEC | KEYLEN_192, 12298c2ecf20Sopenharmony_ci 12308c2ecf20Sopenharmony_ci}, { 12318c2ecf20Sopenharmony_ci .crypto = { 12328c2ecf20Sopenharmony_ci .base.cra_name = "ecb(des)", 12338c2ecf20Sopenharmony_ci .base.cra_blocksize = DES_BLOCK_SIZE, 12348c2ecf20Sopenharmony_ci .min_keysize = DES_KEY_SIZE, 12358c2ecf20Sopenharmony_ci .max_keysize = DES_KEY_SIZE, 12368c2ecf20Sopenharmony_ci }, 12378c2ecf20Sopenharmony_ci .cfg_enc = CIPH_ENCR | MOD_DES | MOD_ECB | KEYLEN_192, 12388c2ecf20Sopenharmony_ci .cfg_dec = CIPH_DECR | MOD_DES | MOD_ECB | KEYLEN_192, 12398c2ecf20Sopenharmony_ci}, { 12408c2ecf20Sopenharmony_ci .crypto = { 12418c2ecf20Sopenharmony_ci .base.cra_name = "cbc(des3_ede)", 12428c2ecf20Sopenharmony_ci .base.cra_blocksize = DES3_EDE_BLOCK_SIZE, 12438c2ecf20Sopenharmony_ci 12448c2ecf20Sopenharmony_ci .min_keysize = DES3_EDE_KEY_SIZE, 12458c2ecf20Sopenharmony_ci .max_keysize = DES3_EDE_KEY_SIZE, 12468c2ecf20Sopenharmony_ci .ivsize = DES3_EDE_BLOCK_SIZE, 12478c2ecf20Sopenharmony_ci .setkey = ablk_des3_setkey, 12488c2ecf20Sopenharmony_ci }, 12498c2ecf20Sopenharmony_ci .cfg_enc = CIPH_ENCR | MOD_3DES | MOD_CBC_ENC | KEYLEN_192, 12508c2ecf20Sopenharmony_ci .cfg_dec = CIPH_DECR | MOD_3DES | MOD_CBC_DEC | KEYLEN_192, 12518c2ecf20Sopenharmony_ci}, { 12528c2ecf20Sopenharmony_ci .crypto = { 12538c2ecf20Sopenharmony_ci .base.cra_name = "ecb(des3_ede)", 12548c2ecf20Sopenharmony_ci .base.cra_blocksize = DES3_EDE_BLOCK_SIZE, 12558c2ecf20Sopenharmony_ci 12568c2ecf20Sopenharmony_ci .min_keysize = DES3_EDE_KEY_SIZE, 12578c2ecf20Sopenharmony_ci .max_keysize = DES3_EDE_KEY_SIZE, 12588c2ecf20Sopenharmony_ci .setkey = ablk_des3_setkey, 12598c2ecf20Sopenharmony_ci }, 12608c2ecf20Sopenharmony_ci .cfg_enc = CIPH_ENCR | MOD_3DES | MOD_ECB | KEYLEN_192, 12618c2ecf20Sopenharmony_ci .cfg_dec = CIPH_DECR | MOD_3DES | MOD_ECB | KEYLEN_192, 12628c2ecf20Sopenharmony_ci}, { 12638c2ecf20Sopenharmony_ci .crypto = { 12648c2ecf20Sopenharmony_ci .base.cra_name = "cbc(aes)", 12658c2ecf20Sopenharmony_ci .base.cra_blocksize = AES_BLOCK_SIZE, 12668c2ecf20Sopenharmony_ci 12678c2ecf20Sopenharmony_ci .min_keysize = AES_MIN_KEY_SIZE, 12688c2ecf20Sopenharmony_ci .max_keysize = AES_MAX_KEY_SIZE, 12698c2ecf20Sopenharmony_ci .ivsize = AES_BLOCK_SIZE, 12708c2ecf20Sopenharmony_ci }, 12718c2ecf20Sopenharmony_ci .cfg_enc = CIPH_ENCR | MOD_AES | MOD_CBC_ENC, 12728c2ecf20Sopenharmony_ci .cfg_dec = CIPH_DECR | MOD_AES | MOD_CBC_DEC, 12738c2ecf20Sopenharmony_ci}, { 12748c2ecf20Sopenharmony_ci .crypto = { 12758c2ecf20Sopenharmony_ci .base.cra_name = "ecb(aes)", 12768c2ecf20Sopenharmony_ci .base.cra_blocksize = AES_BLOCK_SIZE, 12778c2ecf20Sopenharmony_ci 12788c2ecf20Sopenharmony_ci .min_keysize = AES_MIN_KEY_SIZE, 12798c2ecf20Sopenharmony_ci .max_keysize = AES_MAX_KEY_SIZE, 12808c2ecf20Sopenharmony_ci }, 12818c2ecf20Sopenharmony_ci .cfg_enc = CIPH_ENCR | MOD_AES | MOD_ECB, 12828c2ecf20Sopenharmony_ci .cfg_dec = CIPH_DECR | MOD_AES | MOD_ECB, 12838c2ecf20Sopenharmony_ci}, { 12848c2ecf20Sopenharmony_ci .crypto = { 12858c2ecf20Sopenharmony_ci .base.cra_name = "ctr(aes)", 12868c2ecf20Sopenharmony_ci .base.cra_blocksize = 1, 12878c2ecf20Sopenharmony_ci 12888c2ecf20Sopenharmony_ci .min_keysize = AES_MIN_KEY_SIZE, 12898c2ecf20Sopenharmony_ci .max_keysize = AES_MAX_KEY_SIZE, 12908c2ecf20Sopenharmony_ci .ivsize = AES_BLOCK_SIZE, 12918c2ecf20Sopenharmony_ci }, 12928c2ecf20Sopenharmony_ci .cfg_enc = CIPH_ENCR | MOD_AES | MOD_CTR, 12938c2ecf20Sopenharmony_ci .cfg_dec = CIPH_ENCR | MOD_AES | MOD_CTR, 12948c2ecf20Sopenharmony_ci}, { 12958c2ecf20Sopenharmony_ci .crypto = { 12968c2ecf20Sopenharmony_ci .base.cra_name = "rfc3686(ctr(aes))", 12978c2ecf20Sopenharmony_ci .base.cra_blocksize = 1, 12988c2ecf20Sopenharmony_ci 12998c2ecf20Sopenharmony_ci .min_keysize = AES_MIN_KEY_SIZE, 13008c2ecf20Sopenharmony_ci .max_keysize = AES_MAX_KEY_SIZE, 13018c2ecf20Sopenharmony_ci .ivsize = AES_BLOCK_SIZE, 13028c2ecf20Sopenharmony_ci .setkey = ablk_rfc3686_setkey, 13038c2ecf20Sopenharmony_ci .encrypt = ablk_rfc3686_crypt, 13048c2ecf20Sopenharmony_ci .decrypt = ablk_rfc3686_crypt, 13058c2ecf20Sopenharmony_ci }, 13068c2ecf20Sopenharmony_ci .cfg_enc = CIPH_ENCR | MOD_AES | MOD_CTR, 13078c2ecf20Sopenharmony_ci .cfg_dec = CIPH_ENCR | MOD_AES | MOD_CTR, 13088c2ecf20Sopenharmony_ci} }; 13098c2ecf20Sopenharmony_ci 13108c2ecf20Sopenharmony_cistatic struct ixp_aead_alg ixp4xx_aeads[] = { 13118c2ecf20Sopenharmony_ci{ 13128c2ecf20Sopenharmony_ci .crypto = { 13138c2ecf20Sopenharmony_ci .base = { 13148c2ecf20Sopenharmony_ci .cra_name = "authenc(hmac(md5),cbc(des))", 13158c2ecf20Sopenharmony_ci .cra_blocksize = DES_BLOCK_SIZE, 13168c2ecf20Sopenharmony_ci }, 13178c2ecf20Sopenharmony_ci .ivsize = DES_BLOCK_SIZE, 13188c2ecf20Sopenharmony_ci .maxauthsize = MD5_DIGEST_SIZE, 13198c2ecf20Sopenharmony_ci }, 13208c2ecf20Sopenharmony_ci .hash = &hash_alg_md5, 13218c2ecf20Sopenharmony_ci .cfg_enc = CIPH_ENCR | MOD_DES | MOD_CBC_ENC | KEYLEN_192, 13228c2ecf20Sopenharmony_ci .cfg_dec = CIPH_DECR | MOD_DES | MOD_CBC_DEC | KEYLEN_192, 13238c2ecf20Sopenharmony_ci}, { 13248c2ecf20Sopenharmony_ci .crypto = { 13258c2ecf20Sopenharmony_ci .base = { 13268c2ecf20Sopenharmony_ci .cra_name = "authenc(hmac(md5),cbc(des3_ede))", 13278c2ecf20Sopenharmony_ci .cra_blocksize = DES3_EDE_BLOCK_SIZE, 13288c2ecf20Sopenharmony_ci }, 13298c2ecf20Sopenharmony_ci .ivsize = DES3_EDE_BLOCK_SIZE, 13308c2ecf20Sopenharmony_ci .maxauthsize = MD5_DIGEST_SIZE, 13318c2ecf20Sopenharmony_ci .setkey = des3_aead_setkey, 13328c2ecf20Sopenharmony_ci }, 13338c2ecf20Sopenharmony_ci .hash = &hash_alg_md5, 13348c2ecf20Sopenharmony_ci .cfg_enc = CIPH_ENCR | MOD_3DES | MOD_CBC_ENC | KEYLEN_192, 13358c2ecf20Sopenharmony_ci .cfg_dec = CIPH_DECR | MOD_3DES | MOD_CBC_DEC | KEYLEN_192, 13368c2ecf20Sopenharmony_ci}, { 13378c2ecf20Sopenharmony_ci .crypto = { 13388c2ecf20Sopenharmony_ci .base = { 13398c2ecf20Sopenharmony_ci .cra_name = "authenc(hmac(sha1),cbc(des))", 13408c2ecf20Sopenharmony_ci .cra_blocksize = DES_BLOCK_SIZE, 13418c2ecf20Sopenharmony_ci }, 13428c2ecf20Sopenharmony_ci .ivsize = DES_BLOCK_SIZE, 13438c2ecf20Sopenharmony_ci .maxauthsize = SHA1_DIGEST_SIZE, 13448c2ecf20Sopenharmony_ci }, 13458c2ecf20Sopenharmony_ci .hash = &hash_alg_sha1, 13468c2ecf20Sopenharmony_ci .cfg_enc = CIPH_ENCR | MOD_DES | MOD_CBC_ENC | KEYLEN_192, 13478c2ecf20Sopenharmony_ci .cfg_dec = CIPH_DECR | MOD_DES | MOD_CBC_DEC | KEYLEN_192, 13488c2ecf20Sopenharmony_ci}, { 13498c2ecf20Sopenharmony_ci .crypto = { 13508c2ecf20Sopenharmony_ci .base = { 13518c2ecf20Sopenharmony_ci .cra_name = "authenc(hmac(sha1),cbc(des3_ede))", 13528c2ecf20Sopenharmony_ci .cra_blocksize = DES3_EDE_BLOCK_SIZE, 13538c2ecf20Sopenharmony_ci }, 13548c2ecf20Sopenharmony_ci .ivsize = DES3_EDE_BLOCK_SIZE, 13558c2ecf20Sopenharmony_ci .maxauthsize = SHA1_DIGEST_SIZE, 13568c2ecf20Sopenharmony_ci .setkey = des3_aead_setkey, 13578c2ecf20Sopenharmony_ci }, 13588c2ecf20Sopenharmony_ci .hash = &hash_alg_sha1, 13598c2ecf20Sopenharmony_ci .cfg_enc = CIPH_ENCR | MOD_3DES | MOD_CBC_ENC | KEYLEN_192, 13608c2ecf20Sopenharmony_ci .cfg_dec = CIPH_DECR | MOD_3DES | MOD_CBC_DEC | KEYLEN_192, 13618c2ecf20Sopenharmony_ci}, { 13628c2ecf20Sopenharmony_ci .crypto = { 13638c2ecf20Sopenharmony_ci .base = { 13648c2ecf20Sopenharmony_ci .cra_name = "authenc(hmac(md5),cbc(aes))", 13658c2ecf20Sopenharmony_ci .cra_blocksize = AES_BLOCK_SIZE, 13668c2ecf20Sopenharmony_ci }, 13678c2ecf20Sopenharmony_ci .ivsize = AES_BLOCK_SIZE, 13688c2ecf20Sopenharmony_ci .maxauthsize = MD5_DIGEST_SIZE, 13698c2ecf20Sopenharmony_ci }, 13708c2ecf20Sopenharmony_ci .hash = &hash_alg_md5, 13718c2ecf20Sopenharmony_ci .cfg_enc = CIPH_ENCR | MOD_AES | MOD_CBC_ENC, 13728c2ecf20Sopenharmony_ci .cfg_dec = CIPH_DECR | MOD_AES | MOD_CBC_DEC, 13738c2ecf20Sopenharmony_ci}, { 13748c2ecf20Sopenharmony_ci .crypto = { 13758c2ecf20Sopenharmony_ci .base = { 13768c2ecf20Sopenharmony_ci .cra_name = "authenc(hmac(sha1),cbc(aes))", 13778c2ecf20Sopenharmony_ci .cra_blocksize = AES_BLOCK_SIZE, 13788c2ecf20Sopenharmony_ci }, 13798c2ecf20Sopenharmony_ci .ivsize = AES_BLOCK_SIZE, 13808c2ecf20Sopenharmony_ci .maxauthsize = SHA1_DIGEST_SIZE, 13818c2ecf20Sopenharmony_ci }, 13828c2ecf20Sopenharmony_ci .hash = &hash_alg_sha1, 13838c2ecf20Sopenharmony_ci .cfg_enc = CIPH_ENCR | MOD_AES | MOD_CBC_ENC, 13848c2ecf20Sopenharmony_ci .cfg_dec = CIPH_DECR | MOD_AES | MOD_CBC_DEC, 13858c2ecf20Sopenharmony_ci} }; 13868c2ecf20Sopenharmony_ci 13878c2ecf20Sopenharmony_ci#define IXP_POSTFIX "-ixp4xx" 13888c2ecf20Sopenharmony_ci 13898c2ecf20Sopenharmony_cistatic const struct platform_device_info ixp_dev_info __initdata = { 13908c2ecf20Sopenharmony_ci .name = DRIVER_NAME, 13918c2ecf20Sopenharmony_ci .id = 0, 13928c2ecf20Sopenharmony_ci .dma_mask = DMA_BIT_MASK(32), 13938c2ecf20Sopenharmony_ci}; 13948c2ecf20Sopenharmony_ci 13958c2ecf20Sopenharmony_cistatic int __init ixp_module_init(void) 13968c2ecf20Sopenharmony_ci{ 13978c2ecf20Sopenharmony_ci int num = ARRAY_SIZE(ixp4xx_algos); 13988c2ecf20Sopenharmony_ci int i, err; 13998c2ecf20Sopenharmony_ci 14008c2ecf20Sopenharmony_ci pdev = platform_device_register_full(&ixp_dev_info); 14018c2ecf20Sopenharmony_ci if (IS_ERR(pdev)) 14028c2ecf20Sopenharmony_ci return PTR_ERR(pdev); 14038c2ecf20Sopenharmony_ci 14048c2ecf20Sopenharmony_ci spin_lock_init(&desc_lock); 14058c2ecf20Sopenharmony_ci spin_lock_init(&emerg_lock); 14068c2ecf20Sopenharmony_ci 14078c2ecf20Sopenharmony_ci err = init_ixp_crypto(&pdev->dev); 14088c2ecf20Sopenharmony_ci if (err) { 14098c2ecf20Sopenharmony_ci platform_device_unregister(pdev); 14108c2ecf20Sopenharmony_ci return err; 14118c2ecf20Sopenharmony_ci } 14128c2ecf20Sopenharmony_ci for (i=0; i< num; i++) { 14138c2ecf20Sopenharmony_ci struct skcipher_alg *cra = &ixp4xx_algos[i].crypto; 14148c2ecf20Sopenharmony_ci 14158c2ecf20Sopenharmony_ci if (snprintf(cra->base.cra_driver_name, CRYPTO_MAX_ALG_NAME, 14168c2ecf20Sopenharmony_ci "%s"IXP_POSTFIX, cra->base.cra_name) >= 14178c2ecf20Sopenharmony_ci CRYPTO_MAX_ALG_NAME) 14188c2ecf20Sopenharmony_ci { 14198c2ecf20Sopenharmony_ci continue; 14208c2ecf20Sopenharmony_ci } 14218c2ecf20Sopenharmony_ci if (!support_aes && (ixp4xx_algos[i].cfg_enc & MOD_AES)) { 14228c2ecf20Sopenharmony_ci continue; 14238c2ecf20Sopenharmony_ci } 14248c2ecf20Sopenharmony_ci 14258c2ecf20Sopenharmony_ci /* block ciphers */ 14268c2ecf20Sopenharmony_ci cra->base.cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY | 14278c2ecf20Sopenharmony_ci CRYPTO_ALG_ASYNC | 14288c2ecf20Sopenharmony_ci CRYPTO_ALG_ALLOCATES_MEMORY; 14298c2ecf20Sopenharmony_ci if (!cra->setkey) 14308c2ecf20Sopenharmony_ci cra->setkey = ablk_setkey; 14318c2ecf20Sopenharmony_ci if (!cra->encrypt) 14328c2ecf20Sopenharmony_ci cra->encrypt = ablk_encrypt; 14338c2ecf20Sopenharmony_ci if (!cra->decrypt) 14348c2ecf20Sopenharmony_ci cra->decrypt = ablk_decrypt; 14358c2ecf20Sopenharmony_ci cra->init = init_tfm_ablk; 14368c2ecf20Sopenharmony_ci cra->exit = exit_tfm_ablk; 14378c2ecf20Sopenharmony_ci 14388c2ecf20Sopenharmony_ci cra->base.cra_ctxsize = sizeof(struct ixp_ctx); 14398c2ecf20Sopenharmony_ci cra->base.cra_module = THIS_MODULE; 14408c2ecf20Sopenharmony_ci cra->base.cra_alignmask = 3; 14418c2ecf20Sopenharmony_ci cra->base.cra_priority = 300; 14428c2ecf20Sopenharmony_ci if (crypto_register_skcipher(cra)) 14438c2ecf20Sopenharmony_ci printk(KERN_ERR "Failed to register '%s'\n", 14448c2ecf20Sopenharmony_ci cra->base.cra_name); 14458c2ecf20Sopenharmony_ci else 14468c2ecf20Sopenharmony_ci ixp4xx_algos[i].registered = 1; 14478c2ecf20Sopenharmony_ci } 14488c2ecf20Sopenharmony_ci 14498c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(ixp4xx_aeads); i++) { 14508c2ecf20Sopenharmony_ci struct aead_alg *cra = &ixp4xx_aeads[i].crypto; 14518c2ecf20Sopenharmony_ci 14528c2ecf20Sopenharmony_ci if (snprintf(cra->base.cra_driver_name, CRYPTO_MAX_ALG_NAME, 14538c2ecf20Sopenharmony_ci "%s"IXP_POSTFIX, cra->base.cra_name) >= 14548c2ecf20Sopenharmony_ci CRYPTO_MAX_ALG_NAME) 14558c2ecf20Sopenharmony_ci continue; 14568c2ecf20Sopenharmony_ci if (!support_aes && (ixp4xx_algos[i].cfg_enc & MOD_AES)) 14578c2ecf20Sopenharmony_ci continue; 14588c2ecf20Sopenharmony_ci 14598c2ecf20Sopenharmony_ci /* authenc */ 14608c2ecf20Sopenharmony_ci cra->base.cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY | 14618c2ecf20Sopenharmony_ci CRYPTO_ALG_ASYNC | 14628c2ecf20Sopenharmony_ci CRYPTO_ALG_ALLOCATES_MEMORY; 14638c2ecf20Sopenharmony_ci cra->setkey = cra->setkey ?: aead_setkey; 14648c2ecf20Sopenharmony_ci cra->setauthsize = aead_setauthsize; 14658c2ecf20Sopenharmony_ci cra->encrypt = aead_encrypt; 14668c2ecf20Sopenharmony_ci cra->decrypt = aead_decrypt; 14678c2ecf20Sopenharmony_ci cra->init = init_tfm_aead; 14688c2ecf20Sopenharmony_ci cra->exit = exit_tfm_aead; 14698c2ecf20Sopenharmony_ci 14708c2ecf20Sopenharmony_ci cra->base.cra_ctxsize = sizeof(struct ixp_ctx); 14718c2ecf20Sopenharmony_ci cra->base.cra_module = THIS_MODULE; 14728c2ecf20Sopenharmony_ci cra->base.cra_alignmask = 3; 14738c2ecf20Sopenharmony_ci cra->base.cra_priority = 300; 14748c2ecf20Sopenharmony_ci 14758c2ecf20Sopenharmony_ci if (crypto_register_aead(cra)) 14768c2ecf20Sopenharmony_ci printk(KERN_ERR "Failed to register '%s'\n", 14778c2ecf20Sopenharmony_ci cra->base.cra_driver_name); 14788c2ecf20Sopenharmony_ci else 14798c2ecf20Sopenharmony_ci ixp4xx_aeads[i].registered = 1; 14808c2ecf20Sopenharmony_ci } 14818c2ecf20Sopenharmony_ci return 0; 14828c2ecf20Sopenharmony_ci} 14838c2ecf20Sopenharmony_ci 14848c2ecf20Sopenharmony_cistatic void __exit ixp_module_exit(void) 14858c2ecf20Sopenharmony_ci{ 14868c2ecf20Sopenharmony_ci int num = ARRAY_SIZE(ixp4xx_algos); 14878c2ecf20Sopenharmony_ci int i; 14888c2ecf20Sopenharmony_ci 14898c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(ixp4xx_aeads); i++) { 14908c2ecf20Sopenharmony_ci if (ixp4xx_aeads[i].registered) 14918c2ecf20Sopenharmony_ci crypto_unregister_aead(&ixp4xx_aeads[i].crypto); 14928c2ecf20Sopenharmony_ci } 14938c2ecf20Sopenharmony_ci 14948c2ecf20Sopenharmony_ci for (i=0; i< num; i++) { 14958c2ecf20Sopenharmony_ci if (ixp4xx_algos[i].registered) 14968c2ecf20Sopenharmony_ci crypto_unregister_skcipher(&ixp4xx_algos[i].crypto); 14978c2ecf20Sopenharmony_ci } 14988c2ecf20Sopenharmony_ci release_ixp_crypto(&pdev->dev); 14998c2ecf20Sopenharmony_ci platform_device_unregister(pdev); 15008c2ecf20Sopenharmony_ci} 15018c2ecf20Sopenharmony_ci 15028c2ecf20Sopenharmony_cimodule_init(ixp_module_init); 15038c2ecf20Sopenharmony_cimodule_exit(ixp_module_exit); 15048c2ecf20Sopenharmony_ci 15058c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 15068c2ecf20Sopenharmony_ciMODULE_AUTHOR("Christian Hohnstaedt <chohnstaedt@innominate.com>"); 15078c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("IXP4xx hardware crypto"); 15088c2ecf20Sopenharmony_ci 1509