162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Intel IXP4xx NPE-C crypto driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2008 Christian Hohnstaedt <chohnstaedt@innominate.com> 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/platform_device.h> 962306a36Sopenharmony_ci#include <linux/dma-mapping.h> 1062306a36Sopenharmony_ci#include <linux/dmapool.h> 1162306a36Sopenharmony_ci#include <linux/crypto.h> 1262306a36Sopenharmony_ci#include <linux/kernel.h> 1362306a36Sopenharmony_ci#include <linux/rtnetlink.h> 1462306a36Sopenharmony_ci#include <linux/interrupt.h> 1562306a36Sopenharmony_ci#include <linux/spinlock.h> 1662306a36Sopenharmony_ci#include <linux/gfp.h> 1762306a36Sopenharmony_ci#include <linux/module.h> 1862306a36Sopenharmony_ci#include <linux/of.h> 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#include <crypto/ctr.h> 2162306a36Sopenharmony_ci#include <crypto/internal/des.h> 2262306a36Sopenharmony_ci#include <crypto/aes.h> 2362306a36Sopenharmony_ci#include <crypto/hmac.h> 2462306a36Sopenharmony_ci#include <crypto/sha1.h> 2562306a36Sopenharmony_ci#include <crypto/algapi.h> 2662306a36Sopenharmony_ci#include <crypto/internal/aead.h> 2762306a36Sopenharmony_ci#include <crypto/internal/skcipher.h> 2862306a36Sopenharmony_ci#include <crypto/authenc.h> 2962306a36Sopenharmony_ci#include <crypto/scatterwalk.h> 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci#include <linux/soc/ixp4xx/npe.h> 3262306a36Sopenharmony_ci#include <linux/soc/ixp4xx/qmgr.h> 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci/* Intermittent includes, delete this after v5.14-rc1 */ 3562306a36Sopenharmony_ci#include <linux/soc/ixp4xx/cpu.h> 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci#define MAX_KEYLEN 32 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci/* hash: cfgword + 2 * digestlen; crypt: keylen + cfgword */ 4062306a36Sopenharmony_ci#define NPE_CTX_LEN 80 4162306a36Sopenharmony_ci#define AES_BLOCK128 16 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci#define NPE_OP_HASH_VERIFY 0x01 4462306a36Sopenharmony_ci#define NPE_OP_CCM_ENABLE 0x04 4562306a36Sopenharmony_ci#define NPE_OP_CRYPT_ENABLE 0x08 4662306a36Sopenharmony_ci#define NPE_OP_HASH_ENABLE 0x10 4762306a36Sopenharmony_ci#define NPE_OP_NOT_IN_PLACE 0x20 4862306a36Sopenharmony_ci#define NPE_OP_HMAC_DISABLE 0x40 4962306a36Sopenharmony_ci#define NPE_OP_CRYPT_ENCRYPT 0x80 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci#define NPE_OP_CCM_GEN_MIC 0xcc 5262306a36Sopenharmony_ci#define NPE_OP_HASH_GEN_ICV 0x50 5362306a36Sopenharmony_ci#define NPE_OP_ENC_GEN_KEY 0xc9 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci#define MOD_ECB 0x0000 5662306a36Sopenharmony_ci#define MOD_CTR 0x1000 5762306a36Sopenharmony_ci#define MOD_CBC_ENC 0x2000 5862306a36Sopenharmony_ci#define MOD_CBC_DEC 0x3000 5962306a36Sopenharmony_ci#define MOD_CCM_ENC 0x4000 6062306a36Sopenharmony_ci#define MOD_CCM_DEC 0x5000 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci#define KEYLEN_128 4 6362306a36Sopenharmony_ci#define KEYLEN_192 6 6462306a36Sopenharmony_ci#define KEYLEN_256 8 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci#define CIPH_DECR 0x0000 6762306a36Sopenharmony_ci#define CIPH_ENCR 0x0400 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci#define MOD_DES 0x0000 7062306a36Sopenharmony_ci#define MOD_TDEA2 0x0100 7162306a36Sopenharmony_ci#define MOD_3DES 0x0200 7262306a36Sopenharmony_ci#define MOD_AES 0x0800 7362306a36Sopenharmony_ci#define MOD_AES128 (0x0800 | KEYLEN_128) 7462306a36Sopenharmony_ci#define MOD_AES192 (0x0900 | KEYLEN_192) 7562306a36Sopenharmony_ci#define MOD_AES256 (0x0a00 | KEYLEN_256) 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci#define MAX_IVLEN 16 7862306a36Sopenharmony_ci#define NPE_QLEN 16 7962306a36Sopenharmony_ci/* Space for registering when the first 8062306a36Sopenharmony_ci * NPE_QLEN crypt_ctl are busy */ 8162306a36Sopenharmony_ci#define NPE_QLEN_TOTAL 64 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci#define CTL_FLAG_UNUSED 0x0000 8462306a36Sopenharmony_ci#define CTL_FLAG_USED 0x1000 8562306a36Sopenharmony_ci#define CTL_FLAG_PERFORM_ABLK 0x0001 8662306a36Sopenharmony_ci#define CTL_FLAG_GEN_ICV 0x0002 8762306a36Sopenharmony_ci#define CTL_FLAG_GEN_REVAES 0x0004 8862306a36Sopenharmony_ci#define CTL_FLAG_PERFORM_AEAD 0x0008 8962306a36Sopenharmony_ci#define CTL_FLAG_MASK 0x000f 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci#define HMAC_PAD_BLOCKLEN SHA1_BLOCK_SIZE 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci#define MD5_DIGEST_SIZE 16 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_cistruct buffer_desc { 9662306a36Sopenharmony_ci u32 phys_next; 9762306a36Sopenharmony_ci#ifdef __ARMEB__ 9862306a36Sopenharmony_ci u16 buf_len; 9962306a36Sopenharmony_ci u16 pkt_len; 10062306a36Sopenharmony_ci#else 10162306a36Sopenharmony_ci u16 pkt_len; 10262306a36Sopenharmony_ci u16 buf_len; 10362306a36Sopenharmony_ci#endif 10462306a36Sopenharmony_ci dma_addr_t phys_addr; 10562306a36Sopenharmony_ci u32 __reserved[4]; 10662306a36Sopenharmony_ci struct buffer_desc *next; 10762306a36Sopenharmony_ci enum dma_data_direction dir; 10862306a36Sopenharmony_ci}; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_cistruct crypt_ctl { 11162306a36Sopenharmony_ci#ifdef __ARMEB__ 11262306a36Sopenharmony_ci u8 mode; /* NPE_OP_* operation mode */ 11362306a36Sopenharmony_ci u8 init_len; 11462306a36Sopenharmony_ci u16 reserved; 11562306a36Sopenharmony_ci#else 11662306a36Sopenharmony_ci u16 reserved; 11762306a36Sopenharmony_ci u8 init_len; 11862306a36Sopenharmony_ci u8 mode; /* NPE_OP_* operation mode */ 11962306a36Sopenharmony_ci#endif 12062306a36Sopenharmony_ci u8 iv[MAX_IVLEN]; /* IV for CBC mode or CTR IV for CTR mode */ 12162306a36Sopenharmony_ci u32 icv_rev_aes; /* icv or rev aes */ 12262306a36Sopenharmony_ci u32 src_buf; 12362306a36Sopenharmony_ci u32 dst_buf; 12462306a36Sopenharmony_ci#ifdef __ARMEB__ 12562306a36Sopenharmony_ci u16 auth_offs; /* Authentication start offset */ 12662306a36Sopenharmony_ci u16 auth_len; /* Authentication data length */ 12762306a36Sopenharmony_ci u16 crypt_offs; /* Cryption start offset */ 12862306a36Sopenharmony_ci u16 crypt_len; /* Cryption data length */ 12962306a36Sopenharmony_ci#else 13062306a36Sopenharmony_ci u16 auth_len; /* Authentication data length */ 13162306a36Sopenharmony_ci u16 auth_offs; /* Authentication start offset */ 13262306a36Sopenharmony_ci u16 crypt_len; /* Cryption data length */ 13362306a36Sopenharmony_ci u16 crypt_offs; /* Cryption start offset */ 13462306a36Sopenharmony_ci#endif 13562306a36Sopenharmony_ci u32 aadAddr; /* Additional Auth Data Addr for CCM mode */ 13662306a36Sopenharmony_ci u32 crypto_ctx; /* NPE Crypto Param structure address */ 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci /* Used by Host: 4*4 bytes*/ 13962306a36Sopenharmony_ci unsigned int ctl_flags; 14062306a36Sopenharmony_ci union { 14162306a36Sopenharmony_ci struct skcipher_request *ablk_req; 14262306a36Sopenharmony_ci struct aead_request *aead_req; 14362306a36Sopenharmony_ci struct crypto_tfm *tfm; 14462306a36Sopenharmony_ci } data; 14562306a36Sopenharmony_ci struct buffer_desc *regist_buf; 14662306a36Sopenharmony_ci u8 *regist_ptr; 14762306a36Sopenharmony_ci}; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_cistruct ablk_ctx { 15062306a36Sopenharmony_ci struct buffer_desc *src; 15162306a36Sopenharmony_ci struct buffer_desc *dst; 15262306a36Sopenharmony_ci u8 iv[MAX_IVLEN]; 15362306a36Sopenharmony_ci bool encrypt; 15462306a36Sopenharmony_ci struct skcipher_request fallback_req; // keep at the end 15562306a36Sopenharmony_ci}; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_cistruct aead_ctx { 15862306a36Sopenharmony_ci struct buffer_desc *src; 15962306a36Sopenharmony_ci struct buffer_desc *dst; 16062306a36Sopenharmony_ci struct scatterlist ivlist; 16162306a36Sopenharmony_ci /* used when the hmac is not on one sg entry */ 16262306a36Sopenharmony_ci u8 *hmac_virt; 16362306a36Sopenharmony_ci int encrypt; 16462306a36Sopenharmony_ci}; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_cistruct ix_hash_algo { 16762306a36Sopenharmony_ci u32 cfgword; 16862306a36Sopenharmony_ci unsigned char *icv; 16962306a36Sopenharmony_ci}; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_cistruct ix_sa_dir { 17262306a36Sopenharmony_ci unsigned char *npe_ctx; 17362306a36Sopenharmony_ci dma_addr_t npe_ctx_phys; 17462306a36Sopenharmony_ci int npe_ctx_idx; 17562306a36Sopenharmony_ci u8 npe_mode; 17662306a36Sopenharmony_ci}; 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_cistruct ixp_ctx { 17962306a36Sopenharmony_ci struct ix_sa_dir encrypt; 18062306a36Sopenharmony_ci struct ix_sa_dir decrypt; 18162306a36Sopenharmony_ci int authkey_len; 18262306a36Sopenharmony_ci u8 authkey[MAX_KEYLEN]; 18362306a36Sopenharmony_ci int enckey_len; 18462306a36Sopenharmony_ci u8 enckey[MAX_KEYLEN]; 18562306a36Sopenharmony_ci u8 salt[MAX_IVLEN]; 18662306a36Sopenharmony_ci u8 nonce[CTR_RFC3686_NONCE_SIZE]; 18762306a36Sopenharmony_ci unsigned int salted; 18862306a36Sopenharmony_ci atomic_t configuring; 18962306a36Sopenharmony_ci struct completion completion; 19062306a36Sopenharmony_ci struct crypto_skcipher *fallback_tfm; 19162306a36Sopenharmony_ci}; 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_cistruct ixp_alg { 19462306a36Sopenharmony_ci struct skcipher_alg crypto; 19562306a36Sopenharmony_ci const struct ix_hash_algo *hash; 19662306a36Sopenharmony_ci u32 cfg_enc; 19762306a36Sopenharmony_ci u32 cfg_dec; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci int registered; 20062306a36Sopenharmony_ci}; 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_cistruct ixp_aead_alg { 20362306a36Sopenharmony_ci struct aead_alg crypto; 20462306a36Sopenharmony_ci const struct ix_hash_algo *hash; 20562306a36Sopenharmony_ci u32 cfg_enc; 20662306a36Sopenharmony_ci u32 cfg_dec; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci int registered; 20962306a36Sopenharmony_ci}; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_cistatic const struct ix_hash_algo hash_alg_md5 = { 21262306a36Sopenharmony_ci .cfgword = 0xAA010004, 21362306a36Sopenharmony_ci .icv = "\x01\x23\x45\x67\x89\xAB\xCD\xEF" 21462306a36Sopenharmony_ci "\xFE\xDC\xBA\x98\x76\x54\x32\x10", 21562306a36Sopenharmony_ci}; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_cistatic const struct ix_hash_algo hash_alg_sha1 = { 21862306a36Sopenharmony_ci .cfgword = 0x00000005, 21962306a36Sopenharmony_ci .icv = "\x67\x45\x23\x01\xEF\xCD\xAB\x89\x98\xBA" 22062306a36Sopenharmony_ci "\xDC\xFE\x10\x32\x54\x76\xC3\xD2\xE1\xF0", 22162306a36Sopenharmony_ci}; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_cistatic struct npe *npe_c; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_cistatic unsigned int send_qid; 22662306a36Sopenharmony_cistatic unsigned int recv_qid; 22762306a36Sopenharmony_cistatic struct dma_pool *buffer_pool; 22862306a36Sopenharmony_cistatic struct dma_pool *ctx_pool; 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_cistatic struct crypt_ctl *crypt_virt; 23162306a36Sopenharmony_cistatic dma_addr_t crypt_phys; 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_cistatic int support_aes = 1; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_cistatic struct platform_device *pdev; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_cistatic inline dma_addr_t crypt_virt2phys(struct crypt_ctl *virt) 23862306a36Sopenharmony_ci{ 23962306a36Sopenharmony_ci return crypt_phys + (virt - crypt_virt) * sizeof(struct crypt_ctl); 24062306a36Sopenharmony_ci} 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_cistatic inline struct crypt_ctl *crypt_phys2virt(dma_addr_t phys) 24362306a36Sopenharmony_ci{ 24462306a36Sopenharmony_ci return crypt_virt + (phys - crypt_phys) / sizeof(struct crypt_ctl); 24562306a36Sopenharmony_ci} 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_cistatic inline u32 cipher_cfg_enc(struct crypto_tfm *tfm) 24862306a36Sopenharmony_ci{ 24962306a36Sopenharmony_ci return container_of(tfm->__crt_alg, struct ixp_alg, crypto.base)->cfg_enc; 25062306a36Sopenharmony_ci} 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_cistatic inline u32 cipher_cfg_dec(struct crypto_tfm *tfm) 25362306a36Sopenharmony_ci{ 25462306a36Sopenharmony_ci return container_of(tfm->__crt_alg, struct ixp_alg, crypto.base)->cfg_dec; 25562306a36Sopenharmony_ci} 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_cistatic inline const struct ix_hash_algo *ix_hash(struct crypto_tfm *tfm) 25862306a36Sopenharmony_ci{ 25962306a36Sopenharmony_ci return container_of(tfm->__crt_alg, struct ixp_alg, crypto.base)->hash; 26062306a36Sopenharmony_ci} 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_cistatic int setup_crypt_desc(void) 26362306a36Sopenharmony_ci{ 26462306a36Sopenharmony_ci struct device *dev = &pdev->dev; 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci BUILD_BUG_ON(!(IS_ENABLED(CONFIG_COMPILE_TEST) && 26762306a36Sopenharmony_ci IS_ENABLED(CONFIG_64BIT)) && 26862306a36Sopenharmony_ci sizeof(struct crypt_ctl) != 64); 26962306a36Sopenharmony_ci crypt_virt = dma_alloc_coherent(dev, 27062306a36Sopenharmony_ci NPE_QLEN * sizeof(struct crypt_ctl), 27162306a36Sopenharmony_ci &crypt_phys, GFP_ATOMIC); 27262306a36Sopenharmony_ci if (!crypt_virt) 27362306a36Sopenharmony_ci return -ENOMEM; 27462306a36Sopenharmony_ci return 0; 27562306a36Sopenharmony_ci} 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_cistatic DEFINE_SPINLOCK(desc_lock); 27862306a36Sopenharmony_cistatic struct crypt_ctl *get_crypt_desc(void) 27962306a36Sopenharmony_ci{ 28062306a36Sopenharmony_ci int i; 28162306a36Sopenharmony_ci static int idx; 28262306a36Sopenharmony_ci unsigned long flags; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci spin_lock_irqsave(&desc_lock, flags); 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci if (unlikely(!crypt_virt)) 28762306a36Sopenharmony_ci setup_crypt_desc(); 28862306a36Sopenharmony_ci if (unlikely(!crypt_virt)) { 28962306a36Sopenharmony_ci spin_unlock_irqrestore(&desc_lock, flags); 29062306a36Sopenharmony_ci return NULL; 29162306a36Sopenharmony_ci } 29262306a36Sopenharmony_ci i = idx; 29362306a36Sopenharmony_ci if (crypt_virt[i].ctl_flags == CTL_FLAG_UNUSED) { 29462306a36Sopenharmony_ci if (++idx >= NPE_QLEN) 29562306a36Sopenharmony_ci idx = 0; 29662306a36Sopenharmony_ci crypt_virt[i].ctl_flags = CTL_FLAG_USED; 29762306a36Sopenharmony_ci spin_unlock_irqrestore(&desc_lock, flags); 29862306a36Sopenharmony_ci return crypt_virt + i; 29962306a36Sopenharmony_ci } else { 30062306a36Sopenharmony_ci spin_unlock_irqrestore(&desc_lock, flags); 30162306a36Sopenharmony_ci return NULL; 30262306a36Sopenharmony_ci } 30362306a36Sopenharmony_ci} 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_cistatic DEFINE_SPINLOCK(emerg_lock); 30662306a36Sopenharmony_cistatic struct crypt_ctl *get_crypt_desc_emerg(void) 30762306a36Sopenharmony_ci{ 30862306a36Sopenharmony_ci int i; 30962306a36Sopenharmony_ci static int idx = NPE_QLEN; 31062306a36Sopenharmony_ci struct crypt_ctl *desc; 31162306a36Sopenharmony_ci unsigned long flags; 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci desc = get_crypt_desc(); 31462306a36Sopenharmony_ci if (desc) 31562306a36Sopenharmony_ci return desc; 31662306a36Sopenharmony_ci if (unlikely(!crypt_virt)) 31762306a36Sopenharmony_ci return NULL; 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci spin_lock_irqsave(&emerg_lock, flags); 32062306a36Sopenharmony_ci i = idx; 32162306a36Sopenharmony_ci if (crypt_virt[i].ctl_flags == CTL_FLAG_UNUSED) { 32262306a36Sopenharmony_ci if (++idx >= NPE_QLEN_TOTAL) 32362306a36Sopenharmony_ci idx = NPE_QLEN; 32462306a36Sopenharmony_ci crypt_virt[i].ctl_flags = CTL_FLAG_USED; 32562306a36Sopenharmony_ci spin_unlock_irqrestore(&emerg_lock, flags); 32662306a36Sopenharmony_ci return crypt_virt + i; 32762306a36Sopenharmony_ci } else { 32862306a36Sopenharmony_ci spin_unlock_irqrestore(&emerg_lock, flags); 32962306a36Sopenharmony_ci return NULL; 33062306a36Sopenharmony_ci } 33162306a36Sopenharmony_ci} 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_cistatic void free_buf_chain(struct device *dev, struct buffer_desc *buf, 33462306a36Sopenharmony_ci dma_addr_t phys) 33562306a36Sopenharmony_ci{ 33662306a36Sopenharmony_ci while (buf) { 33762306a36Sopenharmony_ci struct buffer_desc *buf1; 33862306a36Sopenharmony_ci u32 phys1; 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci buf1 = buf->next; 34162306a36Sopenharmony_ci phys1 = buf->phys_next; 34262306a36Sopenharmony_ci dma_unmap_single(dev, buf->phys_addr, buf->buf_len, buf->dir); 34362306a36Sopenharmony_ci dma_pool_free(buffer_pool, buf, phys); 34462306a36Sopenharmony_ci buf = buf1; 34562306a36Sopenharmony_ci phys = phys1; 34662306a36Sopenharmony_ci } 34762306a36Sopenharmony_ci} 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_cistatic struct tasklet_struct crypto_done_tasklet; 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_cistatic void finish_scattered_hmac(struct crypt_ctl *crypt) 35262306a36Sopenharmony_ci{ 35362306a36Sopenharmony_ci struct aead_request *req = crypt->data.aead_req; 35462306a36Sopenharmony_ci struct aead_ctx *req_ctx = aead_request_ctx(req); 35562306a36Sopenharmony_ci struct crypto_aead *tfm = crypto_aead_reqtfm(req); 35662306a36Sopenharmony_ci int authsize = crypto_aead_authsize(tfm); 35762306a36Sopenharmony_ci int decryptlen = req->assoclen + req->cryptlen - authsize; 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci if (req_ctx->encrypt) { 36062306a36Sopenharmony_ci scatterwalk_map_and_copy(req_ctx->hmac_virt, req->dst, 36162306a36Sopenharmony_ci decryptlen, authsize, 1); 36262306a36Sopenharmony_ci } 36362306a36Sopenharmony_ci dma_pool_free(buffer_pool, req_ctx->hmac_virt, crypt->icv_rev_aes); 36462306a36Sopenharmony_ci} 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_cistatic void one_packet(dma_addr_t phys) 36762306a36Sopenharmony_ci{ 36862306a36Sopenharmony_ci struct device *dev = &pdev->dev; 36962306a36Sopenharmony_ci struct crypt_ctl *crypt; 37062306a36Sopenharmony_ci struct ixp_ctx *ctx; 37162306a36Sopenharmony_ci int failed; 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci failed = phys & 0x1 ? -EBADMSG : 0; 37462306a36Sopenharmony_ci phys &= ~0x3; 37562306a36Sopenharmony_ci crypt = crypt_phys2virt(phys); 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci switch (crypt->ctl_flags & CTL_FLAG_MASK) { 37862306a36Sopenharmony_ci case CTL_FLAG_PERFORM_AEAD: { 37962306a36Sopenharmony_ci struct aead_request *req = crypt->data.aead_req; 38062306a36Sopenharmony_ci struct aead_ctx *req_ctx = aead_request_ctx(req); 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci free_buf_chain(dev, req_ctx->src, crypt->src_buf); 38362306a36Sopenharmony_ci free_buf_chain(dev, req_ctx->dst, crypt->dst_buf); 38462306a36Sopenharmony_ci if (req_ctx->hmac_virt) 38562306a36Sopenharmony_ci finish_scattered_hmac(crypt); 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci aead_request_complete(req, failed); 38862306a36Sopenharmony_ci break; 38962306a36Sopenharmony_ci } 39062306a36Sopenharmony_ci case CTL_FLAG_PERFORM_ABLK: { 39162306a36Sopenharmony_ci struct skcipher_request *req = crypt->data.ablk_req; 39262306a36Sopenharmony_ci struct ablk_ctx *req_ctx = skcipher_request_ctx(req); 39362306a36Sopenharmony_ci struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 39462306a36Sopenharmony_ci unsigned int ivsize = crypto_skcipher_ivsize(tfm); 39562306a36Sopenharmony_ci unsigned int offset; 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci if (ivsize > 0) { 39862306a36Sopenharmony_ci offset = req->cryptlen - ivsize; 39962306a36Sopenharmony_ci if (req_ctx->encrypt) { 40062306a36Sopenharmony_ci scatterwalk_map_and_copy(req->iv, req->dst, 40162306a36Sopenharmony_ci offset, ivsize, 0); 40262306a36Sopenharmony_ci } else { 40362306a36Sopenharmony_ci memcpy(req->iv, req_ctx->iv, ivsize); 40462306a36Sopenharmony_ci memzero_explicit(req_ctx->iv, ivsize); 40562306a36Sopenharmony_ci } 40662306a36Sopenharmony_ci } 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci if (req_ctx->dst) 40962306a36Sopenharmony_ci free_buf_chain(dev, req_ctx->dst, crypt->dst_buf); 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci free_buf_chain(dev, req_ctx->src, crypt->src_buf); 41262306a36Sopenharmony_ci skcipher_request_complete(req, failed); 41362306a36Sopenharmony_ci break; 41462306a36Sopenharmony_ci } 41562306a36Sopenharmony_ci case CTL_FLAG_GEN_ICV: 41662306a36Sopenharmony_ci ctx = crypto_tfm_ctx(crypt->data.tfm); 41762306a36Sopenharmony_ci dma_pool_free(ctx_pool, crypt->regist_ptr, 41862306a36Sopenharmony_ci crypt->regist_buf->phys_addr); 41962306a36Sopenharmony_ci dma_pool_free(buffer_pool, crypt->regist_buf, crypt->src_buf); 42062306a36Sopenharmony_ci if (atomic_dec_and_test(&ctx->configuring)) 42162306a36Sopenharmony_ci complete(&ctx->completion); 42262306a36Sopenharmony_ci break; 42362306a36Sopenharmony_ci case CTL_FLAG_GEN_REVAES: 42462306a36Sopenharmony_ci ctx = crypto_tfm_ctx(crypt->data.tfm); 42562306a36Sopenharmony_ci *(__be32 *)ctx->decrypt.npe_ctx &= cpu_to_be32(~CIPH_ENCR); 42662306a36Sopenharmony_ci if (atomic_dec_and_test(&ctx->configuring)) 42762306a36Sopenharmony_ci complete(&ctx->completion); 42862306a36Sopenharmony_ci break; 42962306a36Sopenharmony_ci default: 43062306a36Sopenharmony_ci BUG(); 43162306a36Sopenharmony_ci } 43262306a36Sopenharmony_ci crypt->ctl_flags = CTL_FLAG_UNUSED; 43362306a36Sopenharmony_ci} 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_cistatic void irqhandler(void *_unused) 43662306a36Sopenharmony_ci{ 43762306a36Sopenharmony_ci tasklet_schedule(&crypto_done_tasklet); 43862306a36Sopenharmony_ci} 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_cistatic void crypto_done_action(unsigned long arg) 44162306a36Sopenharmony_ci{ 44262306a36Sopenharmony_ci int i; 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci for (i = 0; i < 4; i++) { 44562306a36Sopenharmony_ci dma_addr_t phys = qmgr_get_entry(recv_qid); 44662306a36Sopenharmony_ci if (!phys) 44762306a36Sopenharmony_ci return; 44862306a36Sopenharmony_ci one_packet(phys); 44962306a36Sopenharmony_ci } 45062306a36Sopenharmony_ci tasklet_schedule(&crypto_done_tasklet); 45162306a36Sopenharmony_ci} 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_cistatic int init_ixp_crypto(struct device *dev) 45462306a36Sopenharmony_ci{ 45562306a36Sopenharmony_ci struct device_node *np = dev->of_node; 45662306a36Sopenharmony_ci u32 msg[2] = { 0, 0 }; 45762306a36Sopenharmony_ci int ret = -ENODEV; 45862306a36Sopenharmony_ci u32 npe_id; 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci dev_info(dev, "probing...\n"); 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci /* Locate the NPE and queue manager to use from device tree */ 46362306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_OF) && np) { 46462306a36Sopenharmony_ci struct of_phandle_args queue_spec; 46562306a36Sopenharmony_ci struct of_phandle_args npe_spec; 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci ret = of_parse_phandle_with_fixed_args(np, "intel,npe-handle", 46862306a36Sopenharmony_ci 1, 0, &npe_spec); 46962306a36Sopenharmony_ci if (ret) { 47062306a36Sopenharmony_ci dev_err(dev, "no NPE engine specified\n"); 47162306a36Sopenharmony_ci return -ENODEV; 47262306a36Sopenharmony_ci } 47362306a36Sopenharmony_ci npe_id = npe_spec.args[0]; 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci ret = of_parse_phandle_with_fixed_args(np, "queue-rx", 1, 0, 47662306a36Sopenharmony_ci &queue_spec); 47762306a36Sopenharmony_ci if (ret) { 47862306a36Sopenharmony_ci dev_err(dev, "no rx queue phandle\n"); 47962306a36Sopenharmony_ci return -ENODEV; 48062306a36Sopenharmony_ci } 48162306a36Sopenharmony_ci recv_qid = queue_spec.args[0]; 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci ret = of_parse_phandle_with_fixed_args(np, "queue-txready", 1, 0, 48462306a36Sopenharmony_ci &queue_spec); 48562306a36Sopenharmony_ci if (ret) { 48662306a36Sopenharmony_ci dev_err(dev, "no txready queue phandle\n"); 48762306a36Sopenharmony_ci return -ENODEV; 48862306a36Sopenharmony_ci } 48962306a36Sopenharmony_ci send_qid = queue_spec.args[0]; 49062306a36Sopenharmony_ci } else { 49162306a36Sopenharmony_ci /* 49262306a36Sopenharmony_ci * Hardcoded engine when using platform data, this goes away 49362306a36Sopenharmony_ci * when we switch to using DT only. 49462306a36Sopenharmony_ci */ 49562306a36Sopenharmony_ci npe_id = 2; 49662306a36Sopenharmony_ci send_qid = 29; 49762306a36Sopenharmony_ci recv_qid = 30; 49862306a36Sopenharmony_ci } 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci npe_c = npe_request(npe_id); 50162306a36Sopenharmony_ci if (!npe_c) 50262306a36Sopenharmony_ci return ret; 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci if (!npe_running(npe_c)) { 50562306a36Sopenharmony_ci ret = npe_load_firmware(npe_c, npe_name(npe_c), dev); 50662306a36Sopenharmony_ci if (ret) 50762306a36Sopenharmony_ci goto npe_release; 50862306a36Sopenharmony_ci if (npe_recv_message(npe_c, msg, "STATUS_MSG")) 50962306a36Sopenharmony_ci goto npe_error; 51062306a36Sopenharmony_ci } else { 51162306a36Sopenharmony_ci if (npe_send_message(npe_c, msg, "STATUS_MSG")) 51262306a36Sopenharmony_ci goto npe_error; 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci if (npe_recv_message(npe_c, msg, "STATUS_MSG")) 51562306a36Sopenharmony_ci goto npe_error; 51662306a36Sopenharmony_ci } 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci switch ((msg[1] >> 16) & 0xff) { 51962306a36Sopenharmony_ci case 3: 52062306a36Sopenharmony_ci dev_warn(dev, "Firmware of %s lacks AES support\n", npe_name(npe_c)); 52162306a36Sopenharmony_ci support_aes = 0; 52262306a36Sopenharmony_ci break; 52362306a36Sopenharmony_ci case 4: 52462306a36Sopenharmony_ci case 5: 52562306a36Sopenharmony_ci support_aes = 1; 52662306a36Sopenharmony_ci break; 52762306a36Sopenharmony_ci default: 52862306a36Sopenharmony_ci dev_err(dev, "Firmware of %s lacks crypto support\n", npe_name(npe_c)); 52962306a36Sopenharmony_ci ret = -ENODEV; 53062306a36Sopenharmony_ci goto npe_release; 53162306a36Sopenharmony_ci } 53262306a36Sopenharmony_ci /* buffer_pool will also be used to sometimes store the hmac, 53362306a36Sopenharmony_ci * so assure it is large enough 53462306a36Sopenharmony_ci */ 53562306a36Sopenharmony_ci BUILD_BUG_ON(SHA1_DIGEST_SIZE > sizeof(struct buffer_desc)); 53662306a36Sopenharmony_ci buffer_pool = dma_pool_create("buffer", dev, sizeof(struct buffer_desc), 53762306a36Sopenharmony_ci 32, 0); 53862306a36Sopenharmony_ci ret = -ENOMEM; 53962306a36Sopenharmony_ci if (!buffer_pool) 54062306a36Sopenharmony_ci goto err; 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci ctx_pool = dma_pool_create("context", dev, NPE_CTX_LEN, 16, 0); 54362306a36Sopenharmony_ci if (!ctx_pool) 54462306a36Sopenharmony_ci goto err; 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci ret = qmgr_request_queue(send_qid, NPE_QLEN_TOTAL, 0, 0, 54762306a36Sopenharmony_ci "ixp_crypto:out", NULL); 54862306a36Sopenharmony_ci if (ret) 54962306a36Sopenharmony_ci goto err; 55062306a36Sopenharmony_ci ret = qmgr_request_queue(recv_qid, NPE_QLEN, 0, 0, 55162306a36Sopenharmony_ci "ixp_crypto:in", NULL); 55262306a36Sopenharmony_ci if (ret) { 55362306a36Sopenharmony_ci qmgr_release_queue(send_qid); 55462306a36Sopenharmony_ci goto err; 55562306a36Sopenharmony_ci } 55662306a36Sopenharmony_ci qmgr_set_irq(recv_qid, QUEUE_IRQ_SRC_NOT_EMPTY, irqhandler, NULL); 55762306a36Sopenharmony_ci tasklet_init(&crypto_done_tasklet, crypto_done_action, 0); 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci qmgr_enable_irq(recv_qid); 56062306a36Sopenharmony_ci return 0; 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_cinpe_error: 56362306a36Sopenharmony_ci dev_err(dev, "%s not responding\n", npe_name(npe_c)); 56462306a36Sopenharmony_ci ret = -EIO; 56562306a36Sopenharmony_cierr: 56662306a36Sopenharmony_ci dma_pool_destroy(ctx_pool); 56762306a36Sopenharmony_ci dma_pool_destroy(buffer_pool); 56862306a36Sopenharmony_cinpe_release: 56962306a36Sopenharmony_ci npe_release(npe_c); 57062306a36Sopenharmony_ci return ret; 57162306a36Sopenharmony_ci} 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_cistatic void release_ixp_crypto(struct device *dev) 57462306a36Sopenharmony_ci{ 57562306a36Sopenharmony_ci qmgr_disable_irq(recv_qid); 57662306a36Sopenharmony_ci tasklet_kill(&crypto_done_tasklet); 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci qmgr_release_queue(send_qid); 57962306a36Sopenharmony_ci qmgr_release_queue(recv_qid); 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci dma_pool_destroy(ctx_pool); 58262306a36Sopenharmony_ci dma_pool_destroy(buffer_pool); 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci npe_release(npe_c); 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci if (crypt_virt) 58762306a36Sopenharmony_ci dma_free_coherent(dev, NPE_QLEN * sizeof(struct crypt_ctl), 58862306a36Sopenharmony_ci crypt_virt, crypt_phys); 58962306a36Sopenharmony_ci} 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_cistatic void reset_sa_dir(struct ix_sa_dir *dir) 59262306a36Sopenharmony_ci{ 59362306a36Sopenharmony_ci memset(dir->npe_ctx, 0, NPE_CTX_LEN); 59462306a36Sopenharmony_ci dir->npe_ctx_idx = 0; 59562306a36Sopenharmony_ci dir->npe_mode = 0; 59662306a36Sopenharmony_ci} 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_cistatic int init_sa_dir(struct ix_sa_dir *dir) 59962306a36Sopenharmony_ci{ 60062306a36Sopenharmony_ci dir->npe_ctx = dma_pool_alloc(ctx_pool, GFP_KERNEL, &dir->npe_ctx_phys); 60162306a36Sopenharmony_ci if (!dir->npe_ctx) 60262306a36Sopenharmony_ci return -ENOMEM; 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci reset_sa_dir(dir); 60562306a36Sopenharmony_ci return 0; 60662306a36Sopenharmony_ci} 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_cistatic void free_sa_dir(struct ix_sa_dir *dir) 60962306a36Sopenharmony_ci{ 61062306a36Sopenharmony_ci memset(dir->npe_ctx, 0, NPE_CTX_LEN); 61162306a36Sopenharmony_ci dma_pool_free(ctx_pool, dir->npe_ctx, dir->npe_ctx_phys); 61262306a36Sopenharmony_ci} 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_cistatic int init_tfm(struct crypto_tfm *tfm) 61562306a36Sopenharmony_ci{ 61662306a36Sopenharmony_ci struct ixp_ctx *ctx = crypto_tfm_ctx(tfm); 61762306a36Sopenharmony_ci int ret; 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci atomic_set(&ctx->configuring, 0); 62062306a36Sopenharmony_ci ret = init_sa_dir(&ctx->encrypt); 62162306a36Sopenharmony_ci if (ret) 62262306a36Sopenharmony_ci return ret; 62362306a36Sopenharmony_ci ret = init_sa_dir(&ctx->decrypt); 62462306a36Sopenharmony_ci if (ret) 62562306a36Sopenharmony_ci free_sa_dir(&ctx->encrypt); 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci return ret; 62862306a36Sopenharmony_ci} 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_cistatic int init_tfm_ablk(struct crypto_skcipher *tfm) 63162306a36Sopenharmony_ci{ 63262306a36Sopenharmony_ci struct crypto_tfm *ctfm = crypto_skcipher_tfm(tfm); 63362306a36Sopenharmony_ci struct ixp_ctx *ctx = crypto_tfm_ctx(ctfm); 63462306a36Sopenharmony_ci const char *name = crypto_tfm_alg_name(ctfm); 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci ctx->fallback_tfm = crypto_alloc_skcipher(name, 0, CRYPTO_ALG_NEED_FALLBACK); 63762306a36Sopenharmony_ci if (IS_ERR(ctx->fallback_tfm)) { 63862306a36Sopenharmony_ci pr_err("ERROR: Cannot allocate fallback for %s %ld\n", 63962306a36Sopenharmony_ci name, PTR_ERR(ctx->fallback_tfm)); 64062306a36Sopenharmony_ci return PTR_ERR(ctx->fallback_tfm); 64162306a36Sopenharmony_ci } 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci pr_info("Fallback for %s is %s\n", 64462306a36Sopenharmony_ci crypto_tfm_alg_driver_name(&tfm->base), 64562306a36Sopenharmony_ci crypto_tfm_alg_driver_name(crypto_skcipher_tfm(ctx->fallback_tfm)) 64662306a36Sopenharmony_ci ); 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci crypto_skcipher_set_reqsize(tfm, sizeof(struct ablk_ctx) + crypto_skcipher_reqsize(ctx->fallback_tfm)); 64962306a36Sopenharmony_ci return init_tfm(crypto_skcipher_tfm(tfm)); 65062306a36Sopenharmony_ci} 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_cistatic int init_tfm_aead(struct crypto_aead *tfm) 65362306a36Sopenharmony_ci{ 65462306a36Sopenharmony_ci crypto_aead_set_reqsize(tfm, sizeof(struct aead_ctx)); 65562306a36Sopenharmony_ci return init_tfm(crypto_aead_tfm(tfm)); 65662306a36Sopenharmony_ci} 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_cistatic void exit_tfm(struct crypto_tfm *tfm) 65962306a36Sopenharmony_ci{ 66062306a36Sopenharmony_ci struct ixp_ctx *ctx = crypto_tfm_ctx(tfm); 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci free_sa_dir(&ctx->encrypt); 66362306a36Sopenharmony_ci free_sa_dir(&ctx->decrypt); 66462306a36Sopenharmony_ci} 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_cistatic void exit_tfm_ablk(struct crypto_skcipher *tfm) 66762306a36Sopenharmony_ci{ 66862306a36Sopenharmony_ci struct crypto_tfm *ctfm = crypto_skcipher_tfm(tfm); 66962306a36Sopenharmony_ci struct ixp_ctx *ctx = crypto_tfm_ctx(ctfm); 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci crypto_free_skcipher(ctx->fallback_tfm); 67262306a36Sopenharmony_ci exit_tfm(crypto_skcipher_tfm(tfm)); 67362306a36Sopenharmony_ci} 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_cistatic void exit_tfm_aead(struct crypto_aead *tfm) 67662306a36Sopenharmony_ci{ 67762306a36Sopenharmony_ci exit_tfm(crypto_aead_tfm(tfm)); 67862306a36Sopenharmony_ci} 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_cistatic int register_chain_var(struct crypto_tfm *tfm, u8 xpad, u32 target, 68162306a36Sopenharmony_ci int init_len, u32 ctx_addr, const u8 *key, 68262306a36Sopenharmony_ci int key_len) 68362306a36Sopenharmony_ci{ 68462306a36Sopenharmony_ci struct ixp_ctx *ctx = crypto_tfm_ctx(tfm); 68562306a36Sopenharmony_ci struct crypt_ctl *crypt; 68662306a36Sopenharmony_ci struct buffer_desc *buf; 68762306a36Sopenharmony_ci int i; 68862306a36Sopenharmony_ci u8 *pad; 68962306a36Sopenharmony_ci dma_addr_t pad_phys, buf_phys; 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci BUILD_BUG_ON(NPE_CTX_LEN < HMAC_PAD_BLOCKLEN); 69262306a36Sopenharmony_ci pad = dma_pool_alloc(ctx_pool, GFP_KERNEL, &pad_phys); 69362306a36Sopenharmony_ci if (!pad) 69462306a36Sopenharmony_ci return -ENOMEM; 69562306a36Sopenharmony_ci buf = dma_pool_alloc(buffer_pool, GFP_KERNEL, &buf_phys); 69662306a36Sopenharmony_ci if (!buf) { 69762306a36Sopenharmony_ci dma_pool_free(ctx_pool, pad, pad_phys); 69862306a36Sopenharmony_ci return -ENOMEM; 69962306a36Sopenharmony_ci } 70062306a36Sopenharmony_ci crypt = get_crypt_desc_emerg(); 70162306a36Sopenharmony_ci if (!crypt) { 70262306a36Sopenharmony_ci dma_pool_free(ctx_pool, pad, pad_phys); 70362306a36Sopenharmony_ci dma_pool_free(buffer_pool, buf, buf_phys); 70462306a36Sopenharmony_ci return -EAGAIN; 70562306a36Sopenharmony_ci } 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci memcpy(pad, key, key_len); 70862306a36Sopenharmony_ci memset(pad + key_len, 0, HMAC_PAD_BLOCKLEN - key_len); 70962306a36Sopenharmony_ci for (i = 0; i < HMAC_PAD_BLOCKLEN; i++) 71062306a36Sopenharmony_ci pad[i] ^= xpad; 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci crypt->data.tfm = tfm; 71362306a36Sopenharmony_ci crypt->regist_ptr = pad; 71462306a36Sopenharmony_ci crypt->regist_buf = buf; 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci crypt->auth_offs = 0; 71762306a36Sopenharmony_ci crypt->auth_len = HMAC_PAD_BLOCKLEN; 71862306a36Sopenharmony_ci crypt->crypto_ctx = ctx_addr; 71962306a36Sopenharmony_ci crypt->src_buf = buf_phys; 72062306a36Sopenharmony_ci crypt->icv_rev_aes = target; 72162306a36Sopenharmony_ci crypt->mode = NPE_OP_HASH_GEN_ICV; 72262306a36Sopenharmony_ci crypt->init_len = init_len; 72362306a36Sopenharmony_ci crypt->ctl_flags |= CTL_FLAG_GEN_ICV; 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci buf->next = NULL; 72662306a36Sopenharmony_ci buf->buf_len = HMAC_PAD_BLOCKLEN; 72762306a36Sopenharmony_ci buf->pkt_len = 0; 72862306a36Sopenharmony_ci buf->phys_addr = pad_phys; 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci atomic_inc(&ctx->configuring); 73162306a36Sopenharmony_ci qmgr_put_entry(send_qid, crypt_virt2phys(crypt)); 73262306a36Sopenharmony_ci BUG_ON(qmgr_stat_overflow(send_qid)); 73362306a36Sopenharmony_ci return 0; 73462306a36Sopenharmony_ci} 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_cistatic int setup_auth(struct crypto_tfm *tfm, int encrypt, unsigned int authsize, 73762306a36Sopenharmony_ci const u8 *key, int key_len, unsigned int digest_len) 73862306a36Sopenharmony_ci{ 73962306a36Sopenharmony_ci u32 itarget, otarget, npe_ctx_addr; 74062306a36Sopenharmony_ci unsigned char *cinfo; 74162306a36Sopenharmony_ci int init_len, ret = 0; 74262306a36Sopenharmony_ci u32 cfgword; 74362306a36Sopenharmony_ci struct ix_sa_dir *dir; 74462306a36Sopenharmony_ci struct ixp_ctx *ctx = crypto_tfm_ctx(tfm); 74562306a36Sopenharmony_ci const struct ix_hash_algo *algo; 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ci dir = encrypt ? &ctx->encrypt : &ctx->decrypt; 74862306a36Sopenharmony_ci cinfo = dir->npe_ctx + dir->npe_ctx_idx; 74962306a36Sopenharmony_ci algo = ix_hash(tfm); 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci /* write cfg word to cryptinfo */ 75262306a36Sopenharmony_ci cfgword = algo->cfgword | (authsize << 6); /* (authsize/4) << 8 */ 75362306a36Sopenharmony_ci#ifndef __ARMEB__ 75462306a36Sopenharmony_ci cfgword ^= 0xAA000000; /* change the "byte swap" flags */ 75562306a36Sopenharmony_ci#endif 75662306a36Sopenharmony_ci *(__be32 *)cinfo = cpu_to_be32(cfgword); 75762306a36Sopenharmony_ci cinfo += sizeof(cfgword); 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci /* write ICV to cryptinfo */ 76062306a36Sopenharmony_ci memcpy(cinfo, algo->icv, digest_len); 76162306a36Sopenharmony_ci cinfo += digest_len; 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci itarget = dir->npe_ctx_phys + dir->npe_ctx_idx 76462306a36Sopenharmony_ci + sizeof(algo->cfgword); 76562306a36Sopenharmony_ci otarget = itarget + digest_len; 76662306a36Sopenharmony_ci init_len = cinfo - (dir->npe_ctx + dir->npe_ctx_idx); 76762306a36Sopenharmony_ci npe_ctx_addr = dir->npe_ctx_phys + dir->npe_ctx_idx; 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci dir->npe_ctx_idx += init_len; 77062306a36Sopenharmony_ci dir->npe_mode |= NPE_OP_HASH_ENABLE; 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci if (!encrypt) 77362306a36Sopenharmony_ci dir->npe_mode |= NPE_OP_HASH_VERIFY; 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci ret = register_chain_var(tfm, HMAC_OPAD_VALUE, otarget, 77662306a36Sopenharmony_ci init_len, npe_ctx_addr, key, key_len); 77762306a36Sopenharmony_ci if (ret) 77862306a36Sopenharmony_ci return ret; 77962306a36Sopenharmony_ci return register_chain_var(tfm, HMAC_IPAD_VALUE, itarget, 78062306a36Sopenharmony_ci init_len, npe_ctx_addr, key, key_len); 78162306a36Sopenharmony_ci} 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_cistatic int gen_rev_aes_key(struct crypto_tfm *tfm) 78462306a36Sopenharmony_ci{ 78562306a36Sopenharmony_ci struct crypt_ctl *crypt; 78662306a36Sopenharmony_ci struct ixp_ctx *ctx = crypto_tfm_ctx(tfm); 78762306a36Sopenharmony_ci struct ix_sa_dir *dir = &ctx->decrypt; 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci crypt = get_crypt_desc_emerg(); 79062306a36Sopenharmony_ci if (!crypt) 79162306a36Sopenharmony_ci return -EAGAIN; 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci *(__be32 *)dir->npe_ctx |= cpu_to_be32(CIPH_ENCR); 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci crypt->data.tfm = tfm; 79662306a36Sopenharmony_ci crypt->crypt_offs = 0; 79762306a36Sopenharmony_ci crypt->crypt_len = AES_BLOCK128; 79862306a36Sopenharmony_ci crypt->src_buf = 0; 79962306a36Sopenharmony_ci crypt->crypto_ctx = dir->npe_ctx_phys; 80062306a36Sopenharmony_ci crypt->icv_rev_aes = dir->npe_ctx_phys + sizeof(u32); 80162306a36Sopenharmony_ci crypt->mode = NPE_OP_ENC_GEN_KEY; 80262306a36Sopenharmony_ci crypt->init_len = dir->npe_ctx_idx; 80362306a36Sopenharmony_ci crypt->ctl_flags |= CTL_FLAG_GEN_REVAES; 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci atomic_inc(&ctx->configuring); 80662306a36Sopenharmony_ci qmgr_put_entry(send_qid, crypt_virt2phys(crypt)); 80762306a36Sopenharmony_ci BUG_ON(qmgr_stat_overflow(send_qid)); 80862306a36Sopenharmony_ci return 0; 80962306a36Sopenharmony_ci} 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_cistatic int setup_cipher(struct crypto_tfm *tfm, int encrypt, const u8 *key, 81262306a36Sopenharmony_ci int key_len) 81362306a36Sopenharmony_ci{ 81462306a36Sopenharmony_ci u8 *cinfo; 81562306a36Sopenharmony_ci u32 cipher_cfg; 81662306a36Sopenharmony_ci u32 keylen_cfg = 0; 81762306a36Sopenharmony_ci struct ix_sa_dir *dir; 81862306a36Sopenharmony_ci struct ixp_ctx *ctx = crypto_tfm_ctx(tfm); 81962306a36Sopenharmony_ci int err; 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci dir = encrypt ? &ctx->encrypt : &ctx->decrypt; 82262306a36Sopenharmony_ci cinfo = dir->npe_ctx; 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci if (encrypt) { 82562306a36Sopenharmony_ci cipher_cfg = cipher_cfg_enc(tfm); 82662306a36Sopenharmony_ci dir->npe_mode |= NPE_OP_CRYPT_ENCRYPT; 82762306a36Sopenharmony_ci } else { 82862306a36Sopenharmony_ci cipher_cfg = cipher_cfg_dec(tfm); 82962306a36Sopenharmony_ci } 83062306a36Sopenharmony_ci if (cipher_cfg & MOD_AES) { 83162306a36Sopenharmony_ci switch (key_len) { 83262306a36Sopenharmony_ci case 16: 83362306a36Sopenharmony_ci keylen_cfg = MOD_AES128; 83462306a36Sopenharmony_ci break; 83562306a36Sopenharmony_ci case 24: 83662306a36Sopenharmony_ci keylen_cfg = MOD_AES192; 83762306a36Sopenharmony_ci break; 83862306a36Sopenharmony_ci case 32: 83962306a36Sopenharmony_ci keylen_cfg = MOD_AES256; 84062306a36Sopenharmony_ci break; 84162306a36Sopenharmony_ci default: 84262306a36Sopenharmony_ci return -EINVAL; 84362306a36Sopenharmony_ci } 84462306a36Sopenharmony_ci cipher_cfg |= keylen_cfg; 84562306a36Sopenharmony_ci } else { 84662306a36Sopenharmony_ci err = crypto_des_verify_key(tfm, key); 84762306a36Sopenharmony_ci if (err) 84862306a36Sopenharmony_ci return err; 84962306a36Sopenharmony_ci } 85062306a36Sopenharmony_ci /* write cfg word to cryptinfo */ 85162306a36Sopenharmony_ci *(__be32 *)cinfo = cpu_to_be32(cipher_cfg); 85262306a36Sopenharmony_ci cinfo += sizeof(cipher_cfg); 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_ci /* write cipher key to cryptinfo */ 85562306a36Sopenharmony_ci memcpy(cinfo, key, key_len); 85662306a36Sopenharmony_ci /* NPE wants keylen set to DES3_EDE_KEY_SIZE even for single DES */ 85762306a36Sopenharmony_ci if (key_len < DES3_EDE_KEY_SIZE && !(cipher_cfg & MOD_AES)) { 85862306a36Sopenharmony_ci memset(cinfo + key_len, 0, DES3_EDE_KEY_SIZE - key_len); 85962306a36Sopenharmony_ci key_len = DES3_EDE_KEY_SIZE; 86062306a36Sopenharmony_ci } 86162306a36Sopenharmony_ci dir->npe_ctx_idx = sizeof(cipher_cfg) + key_len; 86262306a36Sopenharmony_ci dir->npe_mode |= NPE_OP_CRYPT_ENABLE; 86362306a36Sopenharmony_ci if ((cipher_cfg & MOD_AES) && !encrypt) 86462306a36Sopenharmony_ci return gen_rev_aes_key(tfm); 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ci return 0; 86762306a36Sopenharmony_ci} 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_cistatic struct buffer_desc *chainup_buffers(struct device *dev, 87062306a36Sopenharmony_ci struct scatterlist *sg, unsigned int nbytes, 87162306a36Sopenharmony_ci struct buffer_desc *buf, gfp_t flags, 87262306a36Sopenharmony_ci enum dma_data_direction dir) 87362306a36Sopenharmony_ci{ 87462306a36Sopenharmony_ci for (; nbytes > 0; sg = sg_next(sg)) { 87562306a36Sopenharmony_ci unsigned int len = min(nbytes, sg->length); 87662306a36Sopenharmony_ci struct buffer_desc *next_buf; 87762306a36Sopenharmony_ci dma_addr_t next_buf_phys; 87862306a36Sopenharmony_ci void *ptr; 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_ci nbytes -= len; 88162306a36Sopenharmony_ci ptr = sg_virt(sg); 88262306a36Sopenharmony_ci next_buf = dma_pool_alloc(buffer_pool, flags, &next_buf_phys); 88362306a36Sopenharmony_ci if (!next_buf) { 88462306a36Sopenharmony_ci buf = NULL; 88562306a36Sopenharmony_ci break; 88662306a36Sopenharmony_ci } 88762306a36Sopenharmony_ci sg_dma_address(sg) = dma_map_single(dev, ptr, len, dir); 88862306a36Sopenharmony_ci buf->next = next_buf; 88962306a36Sopenharmony_ci buf->phys_next = next_buf_phys; 89062306a36Sopenharmony_ci buf = next_buf; 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ci buf->phys_addr = sg_dma_address(sg); 89362306a36Sopenharmony_ci buf->buf_len = len; 89462306a36Sopenharmony_ci buf->dir = dir; 89562306a36Sopenharmony_ci } 89662306a36Sopenharmony_ci buf->next = NULL; 89762306a36Sopenharmony_ci buf->phys_next = 0; 89862306a36Sopenharmony_ci return buf; 89962306a36Sopenharmony_ci} 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_cistatic int ablk_setkey(struct crypto_skcipher *tfm, const u8 *key, 90262306a36Sopenharmony_ci unsigned int key_len) 90362306a36Sopenharmony_ci{ 90462306a36Sopenharmony_ci struct ixp_ctx *ctx = crypto_skcipher_ctx(tfm); 90562306a36Sopenharmony_ci int ret; 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_ci init_completion(&ctx->completion); 90862306a36Sopenharmony_ci atomic_inc(&ctx->configuring); 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci reset_sa_dir(&ctx->encrypt); 91162306a36Sopenharmony_ci reset_sa_dir(&ctx->decrypt); 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_ci ctx->encrypt.npe_mode = NPE_OP_HMAC_DISABLE; 91462306a36Sopenharmony_ci ctx->decrypt.npe_mode = NPE_OP_HMAC_DISABLE; 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ci ret = setup_cipher(&tfm->base, 0, key, key_len); 91762306a36Sopenharmony_ci if (ret) 91862306a36Sopenharmony_ci goto out; 91962306a36Sopenharmony_ci ret = setup_cipher(&tfm->base, 1, key, key_len); 92062306a36Sopenharmony_ciout: 92162306a36Sopenharmony_ci if (!atomic_dec_and_test(&ctx->configuring)) 92262306a36Sopenharmony_ci wait_for_completion(&ctx->completion); 92362306a36Sopenharmony_ci if (ret) 92462306a36Sopenharmony_ci return ret; 92562306a36Sopenharmony_ci crypto_skcipher_clear_flags(ctx->fallback_tfm, CRYPTO_TFM_REQ_MASK); 92662306a36Sopenharmony_ci crypto_skcipher_set_flags(ctx->fallback_tfm, tfm->base.crt_flags & CRYPTO_TFM_REQ_MASK); 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_ci return crypto_skcipher_setkey(ctx->fallback_tfm, key, key_len); 92962306a36Sopenharmony_ci} 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_cistatic int ablk_des3_setkey(struct crypto_skcipher *tfm, const u8 *key, 93262306a36Sopenharmony_ci unsigned int key_len) 93362306a36Sopenharmony_ci{ 93462306a36Sopenharmony_ci return verify_skcipher_des3_key(tfm, key) ?: 93562306a36Sopenharmony_ci ablk_setkey(tfm, key, key_len); 93662306a36Sopenharmony_ci} 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_cistatic int ablk_rfc3686_setkey(struct crypto_skcipher *tfm, const u8 *key, 93962306a36Sopenharmony_ci unsigned int key_len) 94062306a36Sopenharmony_ci{ 94162306a36Sopenharmony_ci struct ixp_ctx *ctx = crypto_skcipher_ctx(tfm); 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_ci /* the nonce is stored in bytes at end of key */ 94462306a36Sopenharmony_ci if (key_len < CTR_RFC3686_NONCE_SIZE) 94562306a36Sopenharmony_ci return -EINVAL; 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_ci memcpy(ctx->nonce, key + (key_len - CTR_RFC3686_NONCE_SIZE), 94862306a36Sopenharmony_ci CTR_RFC3686_NONCE_SIZE); 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_ci key_len -= CTR_RFC3686_NONCE_SIZE; 95162306a36Sopenharmony_ci return ablk_setkey(tfm, key, key_len); 95262306a36Sopenharmony_ci} 95362306a36Sopenharmony_ci 95462306a36Sopenharmony_cistatic int ixp4xx_cipher_fallback(struct skcipher_request *areq, int encrypt) 95562306a36Sopenharmony_ci{ 95662306a36Sopenharmony_ci struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq); 95762306a36Sopenharmony_ci struct ixp_ctx *op = crypto_skcipher_ctx(tfm); 95862306a36Sopenharmony_ci struct ablk_ctx *rctx = skcipher_request_ctx(areq); 95962306a36Sopenharmony_ci int err; 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_ci skcipher_request_set_tfm(&rctx->fallback_req, op->fallback_tfm); 96262306a36Sopenharmony_ci skcipher_request_set_callback(&rctx->fallback_req, areq->base.flags, 96362306a36Sopenharmony_ci areq->base.complete, areq->base.data); 96462306a36Sopenharmony_ci skcipher_request_set_crypt(&rctx->fallback_req, areq->src, areq->dst, 96562306a36Sopenharmony_ci areq->cryptlen, areq->iv); 96662306a36Sopenharmony_ci if (encrypt) 96762306a36Sopenharmony_ci err = crypto_skcipher_encrypt(&rctx->fallback_req); 96862306a36Sopenharmony_ci else 96962306a36Sopenharmony_ci err = crypto_skcipher_decrypt(&rctx->fallback_req); 97062306a36Sopenharmony_ci return err; 97162306a36Sopenharmony_ci} 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_cistatic int ablk_perform(struct skcipher_request *req, int encrypt) 97462306a36Sopenharmony_ci{ 97562306a36Sopenharmony_ci struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 97662306a36Sopenharmony_ci struct ixp_ctx *ctx = crypto_skcipher_ctx(tfm); 97762306a36Sopenharmony_ci unsigned int ivsize = crypto_skcipher_ivsize(tfm); 97862306a36Sopenharmony_ci struct ix_sa_dir *dir; 97962306a36Sopenharmony_ci struct crypt_ctl *crypt; 98062306a36Sopenharmony_ci unsigned int nbytes = req->cryptlen; 98162306a36Sopenharmony_ci enum dma_data_direction src_direction = DMA_BIDIRECTIONAL; 98262306a36Sopenharmony_ci struct ablk_ctx *req_ctx = skcipher_request_ctx(req); 98362306a36Sopenharmony_ci struct buffer_desc src_hook; 98462306a36Sopenharmony_ci struct device *dev = &pdev->dev; 98562306a36Sopenharmony_ci unsigned int offset; 98662306a36Sopenharmony_ci gfp_t flags = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP ? 98762306a36Sopenharmony_ci GFP_KERNEL : GFP_ATOMIC; 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_ci if (sg_nents(req->src) > 1 || sg_nents(req->dst) > 1) 99062306a36Sopenharmony_ci return ixp4xx_cipher_fallback(req, encrypt); 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_ci if (qmgr_stat_full(send_qid)) 99362306a36Sopenharmony_ci return -EAGAIN; 99462306a36Sopenharmony_ci if (atomic_read(&ctx->configuring)) 99562306a36Sopenharmony_ci return -EAGAIN; 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_ci dir = encrypt ? &ctx->encrypt : &ctx->decrypt; 99862306a36Sopenharmony_ci req_ctx->encrypt = encrypt; 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci crypt = get_crypt_desc(); 100162306a36Sopenharmony_ci if (!crypt) 100262306a36Sopenharmony_ci return -ENOMEM; 100362306a36Sopenharmony_ci 100462306a36Sopenharmony_ci crypt->data.ablk_req = req; 100562306a36Sopenharmony_ci crypt->crypto_ctx = dir->npe_ctx_phys; 100662306a36Sopenharmony_ci crypt->mode = dir->npe_mode; 100762306a36Sopenharmony_ci crypt->init_len = dir->npe_ctx_idx; 100862306a36Sopenharmony_ci 100962306a36Sopenharmony_ci crypt->crypt_offs = 0; 101062306a36Sopenharmony_ci crypt->crypt_len = nbytes; 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_ci BUG_ON(ivsize && !req->iv); 101362306a36Sopenharmony_ci memcpy(crypt->iv, req->iv, ivsize); 101462306a36Sopenharmony_ci if (ivsize > 0 && !encrypt) { 101562306a36Sopenharmony_ci offset = req->cryptlen - ivsize; 101662306a36Sopenharmony_ci scatterwalk_map_and_copy(req_ctx->iv, req->src, offset, ivsize, 0); 101762306a36Sopenharmony_ci } 101862306a36Sopenharmony_ci if (req->src != req->dst) { 101962306a36Sopenharmony_ci struct buffer_desc dst_hook; 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_ci crypt->mode |= NPE_OP_NOT_IN_PLACE; 102262306a36Sopenharmony_ci /* This was never tested by Intel 102362306a36Sopenharmony_ci * for more than one dst buffer, I think. */ 102462306a36Sopenharmony_ci req_ctx->dst = NULL; 102562306a36Sopenharmony_ci if (!chainup_buffers(dev, req->dst, nbytes, &dst_hook, 102662306a36Sopenharmony_ci flags, DMA_FROM_DEVICE)) 102762306a36Sopenharmony_ci goto free_buf_dest; 102862306a36Sopenharmony_ci src_direction = DMA_TO_DEVICE; 102962306a36Sopenharmony_ci req_ctx->dst = dst_hook.next; 103062306a36Sopenharmony_ci crypt->dst_buf = dst_hook.phys_next; 103162306a36Sopenharmony_ci } else { 103262306a36Sopenharmony_ci req_ctx->dst = NULL; 103362306a36Sopenharmony_ci } 103462306a36Sopenharmony_ci req_ctx->src = NULL; 103562306a36Sopenharmony_ci if (!chainup_buffers(dev, req->src, nbytes, &src_hook, flags, 103662306a36Sopenharmony_ci src_direction)) 103762306a36Sopenharmony_ci goto free_buf_src; 103862306a36Sopenharmony_ci 103962306a36Sopenharmony_ci req_ctx->src = src_hook.next; 104062306a36Sopenharmony_ci crypt->src_buf = src_hook.phys_next; 104162306a36Sopenharmony_ci crypt->ctl_flags |= CTL_FLAG_PERFORM_ABLK; 104262306a36Sopenharmony_ci qmgr_put_entry(send_qid, crypt_virt2phys(crypt)); 104362306a36Sopenharmony_ci BUG_ON(qmgr_stat_overflow(send_qid)); 104462306a36Sopenharmony_ci return -EINPROGRESS; 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_cifree_buf_src: 104762306a36Sopenharmony_ci free_buf_chain(dev, req_ctx->src, crypt->src_buf); 104862306a36Sopenharmony_cifree_buf_dest: 104962306a36Sopenharmony_ci if (req->src != req->dst) 105062306a36Sopenharmony_ci free_buf_chain(dev, req_ctx->dst, crypt->dst_buf); 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_ci crypt->ctl_flags = CTL_FLAG_UNUSED; 105362306a36Sopenharmony_ci return -ENOMEM; 105462306a36Sopenharmony_ci} 105562306a36Sopenharmony_ci 105662306a36Sopenharmony_cistatic int ablk_encrypt(struct skcipher_request *req) 105762306a36Sopenharmony_ci{ 105862306a36Sopenharmony_ci return ablk_perform(req, 1); 105962306a36Sopenharmony_ci} 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_cistatic int ablk_decrypt(struct skcipher_request *req) 106262306a36Sopenharmony_ci{ 106362306a36Sopenharmony_ci return ablk_perform(req, 0); 106462306a36Sopenharmony_ci} 106562306a36Sopenharmony_ci 106662306a36Sopenharmony_cistatic int ablk_rfc3686_crypt(struct skcipher_request *req) 106762306a36Sopenharmony_ci{ 106862306a36Sopenharmony_ci struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 106962306a36Sopenharmony_ci struct ixp_ctx *ctx = crypto_skcipher_ctx(tfm); 107062306a36Sopenharmony_ci u8 iv[CTR_RFC3686_BLOCK_SIZE]; 107162306a36Sopenharmony_ci u8 *info = req->iv; 107262306a36Sopenharmony_ci int ret; 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_ci /* set up counter block */ 107562306a36Sopenharmony_ci memcpy(iv, ctx->nonce, CTR_RFC3686_NONCE_SIZE); 107662306a36Sopenharmony_ci memcpy(iv + CTR_RFC3686_NONCE_SIZE, info, CTR_RFC3686_IV_SIZE); 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_ci /* initialize counter portion of counter block */ 107962306a36Sopenharmony_ci *(__be32 *)(iv + CTR_RFC3686_NONCE_SIZE + CTR_RFC3686_IV_SIZE) = 108062306a36Sopenharmony_ci cpu_to_be32(1); 108162306a36Sopenharmony_ci 108262306a36Sopenharmony_ci req->iv = iv; 108362306a36Sopenharmony_ci ret = ablk_perform(req, 1); 108462306a36Sopenharmony_ci req->iv = info; 108562306a36Sopenharmony_ci return ret; 108662306a36Sopenharmony_ci} 108762306a36Sopenharmony_ci 108862306a36Sopenharmony_cistatic int aead_perform(struct aead_request *req, int encrypt, 108962306a36Sopenharmony_ci int cryptoffset, int eff_cryptlen, u8 *iv) 109062306a36Sopenharmony_ci{ 109162306a36Sopenharmony_ci struct crypto_aead *tfm = crypto_aead_reqtfm(req); 109262306a36Sopenharmony_ci struct ixp_ctx *ctx = crypto_aead_ctx(tfm); 109362306a36Sopenharmony_ci unsigned int ivsize = crypto_aead_ivsize(tfm); 109462306a36Sopenharmony_ci unsigned int authsize = crypto_aead_authsize(tfm); 109562306a36Sopenharmony_ci struct ix_sa_dir *dir; 109662306a36Sopenharmony_ci struct crypt_ctl *crypt; 109762306a36Sopenharmony_ci unsigned int cryptlen; 109862306a36Sopenharmony_ci struct buffer_desc *buf, src_hook; 109962306a36Sopenharmony_ci struct aead_ctx *req_ctx = aead_request_ctx(req); 110062306a36Sopenharmony_ci struct device *dev = &pdev->dev; 110162306a36Sopenharmony_ci gfp_t flags = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP ? 110262306a36Sopenharmony_ci GFP_KERNEL : GFP_ATOMIC; 110362306a36Sopenharmony_ci enum dma_data_direction src_direction = DMA_BIDIRECTIONAL; 110462306a36Sopenharmony_ci unsigned int lastlen; 110562306a36Sopenharmony_ci 110662306a36Sopenharmony_ci if (qmgr_stat_full(send_qid)) 110762306a36Sopenharmony_ci return -EAGAIN; 110862306a36Sopenharmony_ci if (atomic_read(&ctx->configuring)) 110962306a36Sopenharmony_ci return -EAGAIN; 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_ci if (encrypt) { 111262306a36Sopenharmony_ci dir = &ctx->encrypt; 111362306a36Sopenharmony_ci cryptlen = req->cryptlen; 111462306a36Sopenharmony_ci } else { 111562306a36Sopenharmony_ci dir = &ctx->decrypt; 111662306a36Sopenharmony_ci /* req->cryptlen includes the authsize when decrypting */ 111762306a36Sopenharmony_ci cryptlen = req->cryptlen - authsize; 111862306a36Sopenharmony_ci eff_cryptlen -= authsize; 111962306a36Sopenharmony_ci } 112062306a36Sopenharmony_ci crypt = get_crypt_desc(); 112162306a36Sopenharmony_ci if (!crypt) 112262306a36Sopenharmony_ci return -ENOMEM; 112362306a36Sopenharmony_ci 112462306a36Sopenharmony_ci crypt->data.aead_req = req; 112562306a36Sopenharmony_ci crypt->crypto_ctx = dir->npe_ctx_phys; 112662306a36Sopenharmony_ci crypt->mode = dir->npe_mode; 112762306a36Sopenharmony_ci crypt->init_len = dir->npe_ctx_idx; 112862306a36Sopenharmony_ci 112962306a36Sopenharmony_ci crypt->crypt_offs = cryptoffset; 113062306a36Sopenharmony_ci crypt->crypt_len = eff_cryptlen; 113162306a36Sopenharmony_ci 113262306a36Sopenharmony_ci crypt->auth_offs = 0; 113362306a36Sopenharmony_ci crypt->auth_len = req->assoclen + cryptlen; 113462306a36Sopenharmony_ci BUG_ON(ivsize && !req->iv); 113562306a36Sopenharmony_ci memcpy(crypt->iv, req->iv, ivsize); 113662306a36Sopenharmony_ci 113762306a36Sopenharmony_ci buf = chainup_buffers(dev, req->src, crypt->auth_len, 113862306a36Sopenharmony_ci &src_hook, flags, src_direction); 113962306a36Sopenharmony_ci req_ctx->src = src_hook.next; 114062306a36Sopenharmony_ci crypt->src_buf = src_hook.phys_next; 114162306a36Sopenharmony_ci if (!buf) 114262306a36Sopenharmony_ci goto free_buf_src; 114362306a36Sopenharmony_ci 114462306a36Sopenharmony_ci lastlen = buf->buf_len; 114562306a36Sopenharmony_ci if (lastlen >= authsize) 114662306a36Sopenharmony_ci crypt->icv_rev_aes = buf->phys_addr + 114762306a36Sopenharmony_ci buf->buf_len - authsize; 114862306a36Sopenharmony_ci 114962306a36Sopenharmony_ci req_ctx->dst = NULL; 115062306a36Sopenharmony_ci 115162306a36Sopenharmony_ci if (req->src != req->dst) { 115262306a36Sopenharmony_ci struct buffer_desc dst_hook; 115362306a36Sopenharmony_ci 115462306a36Sopenharmony_ci crypt->mode |= NPE_OP_NOT_IN_PLACE; 115562306a36Sopenharmony_ci src_direction = DMA_TO_DEVICE; 115662306a36Sopenharmony_ci 115762306a36Sopenharmony_ci buf = chainup_buffers(dev, req->dst, crypt->auth_len, 115862306a36Sopenharmony_ci &dst_hook, flags, DMA_FROM_DEVICE); 115962306a36Sopenharmony_ci req_ctx->dst = dst_hook.next; 116062306a36Sopenharmony_ci crypt->dst_buf = dst_hook.phys_next; 116162306a36Sopenharmony_ci 116262306a36Sopenharmony_ci if (!buf) 116362306a36Sopenharmony_ci goto free_buf_dst; 116462306a36Sopenharmony_ci 116562306a36Sopenharmony_ci if (encrypt) { 116662306a36Sopenharmony_ci lastlen = buf->buf_len; 116762306a36Sopenharmony_ci if (lastlen >= authsize) 116862306a36Sopenharmony_ci crypt->icv_rev_aes = buf->phys_addr + 116962306a36Sopenharmony_ci buf->buf_len - authsize; 117062306a36Sopenharmony_ci } 117162306a36Sopenharmony_ci } 117262306a36Sopenharmony_ci 117362306a36Sopenharmony_ci if (unlikely(lastlen < authsize)) { 117462306a36Sopenharmony_ci dma_addr_t dma; 117562306a36Sopenharmony_ci /* The 12 hmac bytes are scattered, 117662306a36Sopenharmony_ci * we need to copy them into a safe buffer */ 117762306a36Sopenharmony_ci req_ctx->hmac_virt = dma_pool_alloc(buffer_pool, flags, &dma); 117862306a36Sopenharmony_ci if (unlikely(!req_ctx->hmac_virt)) 117962306a36Sopenharmony_ci goto free_buf_dst; 118062306a36Sopenharmony_ci crypt->icv_rev_aes = dma; 118162306a36Sopenharmony_ci if (!encrypt) { 118262306a36Sopenharmony_ci scatterwalk_map_and_copy(req_ctx->hmac_virt, 118362306a36Sopenharmony_ci req->src, cryptlen, authsize, 0); 118462306a36Sopenharmony_ci } 118562306a36Sopenharmony_ci req_ctx->encrypt = encrypt; 118662306a36Sopenharmony_ci } else { 118762306a36Sopenharmony_ci req_ctx->hmac_virt = NULL; 118862306a36Sopenharmony_ci } 118962306a36Sopenharmony_ci 119062306a36Sopenharmony_ci crypt->ctl_flags |= CTL_FLAG_PERFORM_AEAD; 119162306a36Sopenharmony_ci qmgr_put_entry(send_qid, crypt_virt2phys(crypt)); 119262306a36Sopenharmony_ci BUG_ON(qmgr_stat_overflow(send_qid)); 119362306a36Sopenharmony_ci return -EINPROGRESS; 119462306a36Sopenharmony_ci 119562306a36Sopenharmony_cifree_buf_dst: 119662306a36Sopenharmony_ci free_buf_chain(dev, req_ctx->dst, crypt->dst_buf); 119762306a36Sopenharmony_cifree_buf_src: 119862306a36Sopenharmony_ci free_buf_chain(dev, req_ctx->src, crypt->src_buf); 119962306a36Sopenharmony_ci crypt->ctl_flags = CTL_FLAG_UNUSED; 120062306a36Sopenharmony_ci return -ENOMEM; 120162306a36Sopenharmony_ci} 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_cistatic int aead_setup(struct crypto_aead *tfm, unsigned int authsize) 120462306a36Sopenharmony_ci{ 120562306a36Sopenharmony_ci struct ixp_ctx *ctx = crypto_aead_ctx(tfm); 120662306a36Sopenharmony_ci unsigned int digest_len = crypto_aead_maxauthsize(tfm); 120762306a36Sopenharmony_ci int ret; 120862306a36Sopenharmony_ci 120962306a36Sopenharmony_ci if (!ctx->enckey_len && !ctx->authkey_len) 121062306a36Sopenharmony_ci return 0; 121162306a36Sopenharmony_ci init_completion(&ctx->completion); 121262306a36Sopenharmony_ci atomic_inc(&ctx->configuring); 121362306a36Sopenharmony_ci 121462306a36Sopenharmony_ci reset_sa_dir(&ctx->encrypt); 121562306a36Sopenharmony_ci reset_sa_dir(&ctx->decrypt); 121662306a36Sopenharmony_ci 121762306a36Sopenharmony_ci ret = setup_cipher(&tfm->base, 0, ctx->enckey, ctx->enckey_len); 121862306a36Sopenharmony_ci if (ret) 121962306a36Sopenharmony_ci goto out; 122062306a36Sopenharmony_ci ret = setup_cipher(&tfm->base, 1, ctx->enckey, ctx->enckey_len); 122162306a36Sopenharmony_ci if (ret) 122262306a36Sopenharmony_ci goto out; 122362306a36Sopenharmony_ci ret = setup_auth(&tfm->base, 0, authsize, ctx->authkey, 122462306a36Sopenharmony_ci ctx->authkey_len, digest_len); 122562306a36Sopenharmony_ci if (ret) 122662306a36Sopenharmony_ci goto out; 122762306a36Sopenharmony_ci ret = setup_auth(&tfm->base, 1, authsize, ctx->authkey, 122862306a36Sopenharmony_ci ctx->authkey_len, digest_len); 122962306a36Sopenharmony_ciout: 123062306a36Sopenharmony_ci if (!atomic_dec_and_test(&ctx->configuring)) 123162306a36Sopenharmony_ci wait_for_completion(&ctx->completion); 123262306a36Sopenharmony_ci return ret; 123362306a36Sopenharmony_ci} 123462306a36Sopenharmony_ci 123562306a36Sopenharmony_cistatic int aead_setauthsize(struct crypto_aead *tfm, unsigned int authsize) 123662306a36Sopenharmony_ci{ 123762306a36Sopenharmony_ci int max = crypto_aead_maxauthsize(tfm) >> 2; 123862306a36Sopenharmony_ci 123962306a36Sopenharmony_ci if ((authsize >> 2) < 1 || (authsize >> 2) > max || (authsize & 3)) 124062306a36Sopenharmony_ci return -EINVAL; 124162306a36Sopenharmony_ci return aead_setup(tfm, authsize); 124262306a36Sopenharmony_ci} 124362306a36Sopenharmony_ci 124462306a36Sopenharmony_cistatic int aead_setkey(struct crypto_aead *tfm, const u8 *key, 124562306a36Sopenharmony_ci unsigned int keylen) 124662306a36Sopenharmony_ci{ 124762306a36Sopenharmony_ci struct ixp_ctx *ctx = crypto_aead_ctx(tfm); 124862306a36Sopenharmony_ci struct crypto_authenc_keys keys; 124962306a36Sopenharmony_ci 125062306a36Sopenharmony_ci if (crypto_authenc_extractkeys(&keys, key, keylen) != 0) 125162306a36Sopenharmony_ci goto badkey; 125262306a36Sopenharmony_ci 125362306a36Sopenharmony_ci if (keys.authkeylen > sizeof(ctx->authkey)) 125462306a36Sopenharmony_ci goto badkey; 125562306a36Sopenharmony_ci 125662306a36Sopenharmony_ci if (keys.enckeylen > sizeof(ctx->enckey)) 125762306a36Sopenharmony_ci goto badkey; 125862306a36Sopenharmony_ci 125962306a36Sopenharmony_ci memcpy(ctx->authkey, keys.authkey, keys.authkeylen); 126062306a36Sopenharmony_ci memcpy(ctx->enckey, keys.enckey, keys.enckeylen); 126162306a36Sopenharmony_ci ctx->authkey_len = keys.authkeylen; 126262306a36Sopenharmony_ci ctx->enckey_len = keys.enckeylen; 126362306a36Sopenharmony_ci 126462306a36Sopenharmony_ci memzero_explicit(&keys, sizeof(keys)); 126562306a36Sopenharmony_ci return aead_setup(tfm, crypto_aead_authsize(tfm)); 126662306a36Sopenharmony_cibadkey: 126762306a36Sopenharmony_ci memzero_explicit(&keys, sizeof(keys)); 126862306a36Sopenharmony_ci return -EINVAL; 126962306a36Sopenharmony_ci} 127062306a36Sopenharmony_ci 127162306a36Sopenharmony_cistatic int des3_aead_setkey(struct crypto_aead *tfm, const u8 *key, 127262306a36Sopenharmony_ci unsigned int keylen) 127362306a36Sopenharmony_ci{ 127462306a36Sopenharmony_ci struct ixp_ctx *ctx = crypto_aead_ctx(tfm); 127562306a36Sopenharmony_ci struct crypto_authenc_keys keys; 127662306a36Sopenharmony_ci int err; 127762306a36Sopenharmony_ci 127862306a36Sopenharmony_ci err = crypto_authenc_extractkeys(&keys, key, keylen); 127962306a36Sopenharmony_ci if (unlikely(err)) 128062306a36Sopenharmony_ci goto badkey; 128162306a36Sopenharmony_ci 128262306a36Sopenharmony_ci err = -EINVAL; 128362306a36Sopenharmony_ci if (keys.authkeylen > sizeof(ctx->authkey)) 128462306a36Sopenharmony_ci goto badkey; 128562306a36Sopenharmony_ci 128662306a36Sopenharmony_ci err = verify_aead_des3_key(tfm, keys.enckey, keys.enckeylen); 128762306a36Sopenharmony_ci if (err) 128862306a36Sopenharmony_ci goto badkey; 128962306a36Sopenharmony_ci 129062306a36Sopenharmony_ci memcpy(ctx->authkey, keys.authkey, keys.authkeylen); 129162306a36Sopenharmony_ci memcpy(ctx->enckey, keys.enckey, keys.enckeylen); 129262306a36Sopenharmony_ci ctx->authkey_len = keys.authkeylen; 129362306a36Sopenharmony_ci ctx->enckey_len = keys.enckeylen; 129462306a36Sopenharmony_ci 129562306a36Sopenharmony_ci memzero_explicit(&keys, sizeof(keys)); 129662306a36Sopenharmony_ci return aead_setup(tfm, crypto_aead_authsize(tfm)); 129762306a36Sopenharmony_cibadkey: 129862306a36Sopenharmony_ci memzero_explicit(&keys, sizeof(keys)); 129962306a36Sopenharmony_ci return err; 130062306a36Sopenharmony_ci} 130162306a36Sopenharmony_ci 130262306a36Sopenharmony_cistatic int aead_encrypt(struct aead_request *req) 130362306a36Sopenharmony_ci{ 130462306a36Sopenharmony_ci return aead_perform(req, 1, req->assoclen, req->cryptlen, req->iv); 130562306a36Sopenharmony_ci} 130662306a36Sopenharmony_ci 130762306a36Sopenharmony_cistatic int aead_decrypt(struct aead_request *req) 130862306a36Sopenharmony_ci{ 130962306a36Sopenharmony_ci return aead_perform(req, 0, req->assoclen, req->cryptlen, req->iv); 131062306a36Sopenharmony_ci} 131162306a36Sopenharmony_ci 131262306a36Sopenharmony_cistatic struct ixp_alg ixp4xx_algos[] = { 131362306a36Sopenharmony_ci{ 131462306a36Sopenharmony_ci .crypto = { 131562306a36Sopenharmony_ci .base.cra_name = "cbc(des)", 131662306a36Sopenharmony_ci .base.cra_blocksize = DES_BLOCK_SIZE, 131762306a36Sopenharmony_ci 131862306a36Sopenharmony_ci .min_keysize = DES_KEY_SIZE, 131962306a36Sopenharmony_ci .max_keysize = DES_KEY_SIZE, 132062306a36Sopenharmony_ci .ivsize = DES_BLOCK_SIZE, 132162306a36Sopenharmony_ci }, 132262306a36Sopenharmony_ci .cfg_enc = CIPH_ENCR | MOD_DES | MOD_CBC_ENC | KEYLEN_192, 132362306a36Sopenharmony_ci .cfg_dec = CIPH_DECR | MOD_DES | MOD_CBC_DEC | KEYLEN_192, 132462306a36Sopenharmony_ci 132562306a36Sopenharmony_ci}, { 132662306a36Sopenharmony_ci .crypto = { 132762306a36Sopenharmony_ci .base.cra_name = "ecb(des)", 132862306a36Sopenharmony_ci .base.cra_blocksize = DES_BLOCK_SIZE, 132962306a36Sopenharmony_ci .min_keysize = DES_KEY_SIZE, 133062306a36Sopenharmony_ci .max_keysize = DES_KEY_SIZE, 133162306a36Sopenharmony_ci }, 133262306a36Sopenharmony_ci .cfg_enc = CIPH_ENCR | MOD_DES | MOD_ECB | KEYLEN_192, 133362306a36Sopenharmony_ci .cfg_dec = CIPH_DECR | MOD_DES | MOD_ECB | KEYLEN_192, 133462306a36Sopenharmony_ci}, { 133562306a36Sopenharmony_ci .crypto = { 133662306a36Sopenharmony_ci .base.cra_name = "cbc(des3_ede)", 133762306a36Sopenharmony_ci .base.cra_blocksize = DES3_EDE_BLOCK_SIZE, 133862306a36Sopenharmony_ci 133962306a36Sopenharmony_ci .min_keysize = DES3_EDE_KEY_SIZE, 134062306a36Sopenharmony_ci .max_keysize = DES3_EDE_KEY_SIZE, 134162306a36Sopenharmony_ci .ivsize = DES3_EDE_BLOCK_SIZE, 134262306a36Sopenharmony_ci .setkey = ablk_des3_setkey, 134362306a36Sopenharmony_ci }, 134462306a36Sopenharmony_ci .cfg_enc = CIPH_ENCR | MOD_3DES | MOD_CBC_ENC | KEYLEN_192, 134562306a36Sopenharmony_ci .cfg_dec = CIPH_DECR | MOD_3DES | MOD_CBC_DEC | KEYLEN_192, 134662306a36Sopenharmony_ci}, { 134762306a36Sopenharmony_ci .crypto = { 134862306a36Sopenharmony_ci .base.cra_name = "ecb(des3_ede)", 134962306a36Sopenharmony_ci .base.cra_blocksize = DES3_EDE_BLOCK_SIZE, 135062306a36Sopenharmony_ci 135162306a36Sopenharmony_ci .min_keysize = DES3_EDE_KEY_SIZE, 135262306a36Sopenharmony_ci .max_keysize = DES3_EDE_KEY_SIZE, 135362306a36Sopenharmony_ci .setkey = ablk_des3_setkey, 135462306a36Sopenharmony_ci }, 135562306a36Sopenharmony_ci .cfg_enc = CIPH_ENCR | MOD_3DES | MOD_ECB | KEYLEN_192, 135662306a36Sopenharmony_ci .cfg_dec = CIPH_DECR | MOD_3DES | MOD_ECB | KEYLEN_192, 135762306a36Sopenharmony_ci}, { 135862306a36Sopenharmony_ci .crypto = { 135962306a36Sopenharmony_ci .base.cra_name = "cbc(aes)", 136062306a36Sopenharmony_ci .base.cra_blocksize = AES_BLOCK_SIZE, 136162306a36Sopenharmony_ci 136262306a36Sopenharmony_ci .min_keysize = AES_MIN_KEY_SIZE, 136362306a36Sopenharmony_ci .max_keysize = AES_MAX_KEY_SIZE, 136462306a36Sopenharmony_ci .ivsize = AES_BLOCK_SIZE, 136562306a36Sopenharmony_ci }, 136662306a36Sopenharmony_ci .cfg_enc = CIPH_ENCR | MOD_AES | MOD_CBC_ENC, 136762306a36Sopenharmony_ci .cfg_dec = CIPH_DECR | MOD_AES | MOD_CBC_DEC, 136862306a36Sopenharmony_ci}, { 136962306a36Sopenharmony_ci .crypto = { 137062306a36Sopenharmony_ci .base.cra_name = "ecb(aes)", 137162306a36Sopenharmony_ci .base.cra_blocksize = AES_BLOCK_SIZE, 137262306a36Sopenharmony_ci 137362306a36Sopenharmony_ci .min_keysize = AES_MIN_KEY_SIZE, 137462306a36Sopenharmony_ci .max_keysize = AES_MAX_KEY_SIZE, 137562306a36Sopenharmony_ci }, 137662306a36Sopenharmony_ci .cfg_enc = CIPH_ENCR | MOD_AES | MOD_ECB, 137762306a36Sopenharmony_ci .cfg_dec = CIPH_DECR | MOD_AES | MOD_ECB, 137862306a36Sopenharmony_ci}, { 137962306a36Sopenharmony_ci .crypto = { 138062306a36Sopenharmony_ci .base.cra_name = "ctr(aes)", 138162306a36Sopenharmony_ci .base.cra_blocksize = 1, 138262306a36Sopenharmony_ci 138362306a36Sopenharmony_ci .min_keysize = AES_MIN_KEY_SIZE, 138462306a36Sopenharmony_ci .max_keysize = AES_MAX_KEY_SIZE, 138562306a36Sopenharmony_ci .ivsize = AES_BLOCK_SIZE, 138662306a36Sopenharmony_ci }, 138762306a36Sopenharmony_ci .cfg_enc = CIPH_ENCR | MOD_AES | MOD_CTR, 138862306a36Sopenharmony_ci .cfg_dec = CIPH_ENCR | MOD_AES | MOD_CTR, 138962306a36Sopenharmony_ci}, { 139062306a36Sopenharmony_ci .crypto = { 139162306a36Sopenharmony_ci .base.cra_name = "rfc3686(ctr(aes))", 139262306a36Sopenharmony_ci .base.cra_blocksize = 1, 139362306a36Sopenharmony_ci 139462306a36Sopenharmony_ci .min_keysize = AES_MIN_KEY_SIZE, 139562306a36Sopenharmony_ci .max_keysize = AES_MAX_KEY_SIZE, 139662306a36Sopenharmony_ci .ivsize = AES_BLOCK_SIZE, 139762306a36Sopenharmony_ci .setkey = ablk_rfc3686_setkey, 139862306a36Sopenharmony_ci .encrypt = ablk_rfc3686_crypt, 139962306a36Sopenharmony_ci .decrypt = ablk_rfc3686_crypt, 140062306a36Sopenharmony_ci }, 140162306a36Sopenharmony_ci .cfg_enc = CIPH_ENCR | MOD_AES | MOD_CTR, 140262306a36Sopenharmony_ci .cfg_dec = CIPH_ENCR | MOD_AES | MOD_CTR, 140362306a36Sopenharmony_ci} }; 140462306a36Sopenharmony_ci 140562306a36Sopenharmony_cistatic struct ixp_aead_alg ixp4xx_aeads[] = { 140662306a36Sopenharmony_ci{ 140762306a36Sopenharmony_ci .crypto = { 140862306a36Sopenharmony_ci .base = { 140962306a36Sopenharmony_ci .cra_name = "authenc(hmac(md5),cbc(des))", 141062306a36Sopenharmony_ci .cra_blocksize = DES_BLOCK_SIZE, 141162306a36Sopenharmony_ci }, 141262306a36Sopenharmony_ci .ivsize = DES_BLOCK_SIZE, 141362306a36Sopenharmony_ci .maxauthsize = MD5_DIGEST_SIZE, 141462306a36Sopenharmony_ci }, 141562306a36Sopenharmony_ci .hash = &hash_alg_md5, 141662306a36Sopenharmony_ci .cfg_enc = CIPH_ENCR | MOD_DES | MOD_CBC_ENC | KEYLEN_192, 141762306a36Sopenharmony_ci .cfg_dec = CIPH_DECR | MOD_DES | MOD_CBC_DEC | KEYLEN_192, 141862306a36Sopenharmony_ci}, { 141962306a36Sopenharmony_ci .crypto = { 142062306a36Sopenharmony_ci .base = { 142162306a36Sopenharmony_ci .cra_name = "authenc(hmac(md5),cbc(des3_ede))", 142262306a36Sopenharmony_ci .cra_blocksize = DES3_EDE_BLOCK_SIZE, 142362306a36Sopenharmony_ci }, 142462306a36Sopenharmony_ci .ivsize = DES3_EDE_BLOCK_SIZE, 142562306a36Sopenharmony_ci .maxauthsize = MD5_DIGEST_SIZE, 142662306a36Sopenharmony_ci .setkey = des3_aead_setkey, 142762306a36Sopenharmony_ci }, 142862306a36Sopenharmony_ci .hash = &hash_alg_md5, 142962306a36Sopenharmony_ci .cfg_enc = CIPH_ENCR | MOD_3DES | MOD_CBC_ENC | KEYLEN_192, 143062306a36Sopenharmony_ci .cfg_dec = CIPH_DECR | MOD_3DES | MOD_CBC_DEC | KEYLEN_192, 143162306a36Sopenharmony_ci}, { 143262306a36Sopenharmony_ci .crypto = { 143362306a36Sopenharmony_ci .base = { 143462306a36Sopenharmony_ci .cra_name = "authenc(hmac(sha1),cbc(des))", 143562306a36Sopenharmony_ci .cra_blocksize = DES_BLOCK_SIZE, 143662306a36Sopenharmony_ci }, 143762306a36Sopenharmony_ci .ivsize = DES_BLOCK_SIZE, 143862306a36Sopenharmony_ci .maxauthsize = SHA1_DIGEST_SIZE, 143962306a36Sopenharmony_ci }, 144062306a36Sopenharmony_ci .hash = &hash_alg_sha1, 144162306a36Sopenharmony_ci .cfg_enc = CIPH_ENCR | MOD_DES | MOD_CBC_ENC | KEYLEN_192, 144262306a36Sopenharmony_ci .cfg_dec = CIPH_DECR | MOD_DES | MOD_CBC_DEC | KEYLEN_192, 144362306a36Sopenharmony_ci}, { 144462306a36Sopenharmony_ci .crypto = { 144562306a36Sopenharmony_ci .base = { 144662306a36Sopenharmony_ci .cra_name = "authenc(hmac(sha1),cbc(des3_ede))", 144762306a36Sopenharmony_ci .cra_blocksize = DES3_EDE_BLOCK_SIZE, 144862306a36Sopenharmony_ci }, 144962306a36Sopenharmony_ci .ivsize = DES3_EDE_BLOCK_SIZE, 145062306a36Sopenharmony_ci .maxauthsize = SHA1_DIGEST_SIZE, 145162306a36Sopenharmony_ci .setkey = des3_aead_setkey, 145262306a36Sopenharmony_ci }, 145362306a36Sopenharmony_ci .hash = &hash_alg_sha1, 145462306a36Sopenharmony_ci .cfg_enc = CIPH_ENCR | MOD_3DES | MOD_CBC_ENC | KEYLEN_192, 145562306a36Sopenharmony_ci .cfg_dec = CIPH_DECR | MOD_3DES | MOD_CBC_DEC | KEYLEN_192, 145662306a36Sopenharmony_ci}, { 145762306a36Sopenharmony_ci .crypto = { 145862306a36Sopenharmony_ci .base = { 145962306a36Sopenharmony_ci .cra_name = "authenc(hmac(md5),cbc(aes))", 146062306a36Sopenharmony_ci .cra_blocksize = AES_BLOCK_SIZE, 146162306a36Sopenharmony_ci }, 146262306a36Sopenharmony_ci .ivsize = AES_BLOCK_SIZE, 146362306a36Sopenharmony_ci .maxauthsize = MD5_DIGEST_SIZE, 146462306a36Sopenharmony_ci }, 146562306a36Sopenharmony_ci .hash = &hash_alg_md5, 146662306a36Sopenharmony_ci .cfg_enc = CIPH_ENCR | MOD_AES | MOD_CBC_ENC, 146762306a36Sopenharmony_ci .cfg_dec = CIPH_DECR | MOD_AES | MOD_CBC_DEC, 146862306a36Sopenharmony_ci}, { 146962306a36Sopenharmony_ci .crypto = { 147062306a36Sopenharmony_ci .base = { 147162306a36Sopenharmony_ci .cra_name = "authenc(hmac(sha1),cbc(aes))", 147262306a36Sopenharmony_ci .cra_blocksize = AES_BLOCK_SIZE, 147362306a36Sopenharmony_ci }, 147462306a36Sopenharmony_ci .ivsize = AES_BLOCK_SIZE, 147562306a36Sopenharmony_ci .maxauthsize = SHA1_DIGEST_SIZE, 147662306a36Sopenharmony_ci }, 147762306a36Sopenharmony_ci .hash = &hash_alg_sha1, 147862306a36Sopenharmony_ci .cfg_enc = CIPH_ENCR | MOD_AES | MOD_CBC_ENC, 147962306a36Sopenharmony_ci .cfg_dec = CIPH_DECR | MOD_AES | MOD_CBC_DEC, 148062306a36Sopenharmony_ci} }; 148162306a36Sopenharmony_ci 148262306a36Sopenharmony_ci#define IXP_POSTFIX "-ixp4xx" 148362306a36Sopenharmony_ci 148462306a36Sopenharmony_cistatic int ixp_crypto_probe(struct platform_device *_pdev) 148562306a36Sopenharmony_ci{ 148662306a36Sopenharmony_ci struct device *dev = &_pdev->dev; 148762306a36Sopenharmony_ci int num = ARRAY_SIZE(ixp4xx_algos); 148862306a36Sopenharmony_ci int i, err; 148962306a36Sopenharmony_ci 149062306a36Sopenharmony_ci pdev = _pdev; 149162306a36Sopenharmony_ci 149262306a36Sopenharmony_ci err = init_ixp_crypto(dev); 149362306a36Sopenharmony_ci if (err) 149462306a36Sopenharmony_ci return err; 149562306a36Sopenharmony_ci 149662306a36Sopenharmony_ci for (i = 0; i < num; i++) { 149762306a36Sopenharmony_ci struct skcipher_alg *cra = &ixp4xx_algos[i].crypto; 149862306a36Sopenharmony_ci 149962306a36Sopenharmony_ci if (snprintf(cra->base.cra_driver_name, CRYPTO_MAX_ALG_NAME, 150062306a36Sopenharmony_ci "%s"IXP_POSTFIX, cra->base.cra_name) >= 150162306a36Sopenharmony_ci CRYPTO_MAX_ALG_NAME) 150262306a36Sopenharmony_ci continue; 150362306a36Sopenharmony_ci if (!support_aes && (ixp4xx_algos[i].cfg_enc & MOD_AES)) 150462306a36Sopenharmony_ci continue; 150562306a36Sopenharmony_ci 150662306a36Sopenharmony_ci /* block ciphers */ 150762306a36Sopenharmony_ci cra->base.cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY | 150862306a36Sopenharmony_ci CRYPTO_ALG_ASYNC | 150962306a36Sopenharmony_ci CRYPTO_ALG_ALLOCATES_MEMORY | 151062306a36Sopenharmony_ci CRYPTO_ALG_NEED_FALLBACK; 151162306a36Sopenharmony_ci if (!cra->setkey) 151262306a36Sopenharmony_ci cra->setkey = ablk_setkey; 151362306a36Sopenharmony_ci if (!cra->encrypt) 151462306a36Sopenharmony_ci cra->encrypt = ablk_encrypt; 151562306a36Sopenharmony_ci if (!cra->decrypt) 151662306a36Sopenharmony_ci cra->decrypt = ablk_decrypt; 151762306a36Sopenharmony_ci cra->init = init_tfm_ablk; 151862306a36Sopenharmony_ci cra->exit = exit_tfm_ablk; 151962306a36Sopenharmony_ci 152062306a36Sopenharmony_ci cra->base.cra_ctxsize = sizeof(struct ixp_ctx); 152162306a36Sopenharmony_ci cra->base.cra_module = THIS_MODULE; 152262306a36Sopenharmony_ci cra->base.cra_alignmask = 3; 152362306a36Sopenharmony_ci cra->base.cra_priority = 300; 152462306a36Sopenharmony_ci if (crypto_register_skcipher(cra)) 152562306a36Sopenharmony_ci dev_err(&pdev->dev, "Failed to register '%s'\n", 152662306a36Sopenharmony_ci cra->base.cra_name); 152762306a36Sopenharmony_ci else 152862306a36Sopenharmony_ci ixp4xx_algos[i].registered = 1; 152962306a36Sopenharmony_ci } 153062306a36Sopenharmony_ci 153162306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(ixp4xx_aeads); i++) { 153262306a36Sopenharmony_ci struct aead_alg *cra = &ixp4xx_aeads[i].crypto; 153362306a36Sopenharmony_ci 153462306a36Sopenharmony_ci if (snprintf(cra->base.cra_driver_name, CRYPTO_MAX_ALG_NAME, 153562306a36Sopenharmony_ci "%s"IXP_POSTFIX, cra->base.cra_name) >= 153662306a36Sopenharmony_ci CRYPTO_MAX_ALG_NAME) 153762306a36Sopenharmony_ci continue; 153862306a36Sopenharmony_ci if (!support_aes && (ixp4xx_algos[i].cfg_enc & MOD_AES)) 153962306a36Sopenharmony_ci continue; 154062306a36Sopenharmony_ci 154162306a36Sopenharmony_ci /* authenc */ 154262306a36Sopenharmony_ci cra->base.cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY | 154362306a36Sopenharmony_ci CRYPTO_ALG_ASYNC | 154462306a36Sopenharmony_ci CRYPTO_ALG_ALLOCATES_MEMORY; 154562306a36Sopenharmony_ci cra->setkey = cra->setkey ?: aead_setkey; 154662306a36Sopenharmony_ci cra->setauthsize = aead_setauthsize; 154762306a36Sopenharmony_ci cra->encrypt = aead_encrypt; 154862306a36Sopenharmony_ci cra->decrypt = aead_decrypt; 154962306a36Sopenharmony_ci cra->init = init_tfm_aead; 155062306a36Sopenharmony_ci cra->exit = exit_tfm_aead; 155162306a36Sopenharmony_ci 155262306a36Sopenharmony_ci cra->base.cra_ctxsize = sizeof(struct ixp_ctx); 155362306a36Sopenharmony_ci cra->base.cra_module = THIS_MODULE; 155462306a36Sopenharmony_ci cra->base.cra_alignmask = 3; 155562306a36Sopenharmony_ci cra->base.cra_priority = 300; 155662306a36Sopenharmony_ci 155762306a36Sopenharmony_ci if (crypto_register_aead(cra)) 155862306a36Sopenharmony_ci dev_err(&pdev->dev, "Failed to register '%s'\n", 155962306a36Sopenharmony_ci cra->base.cra_driver_name); 156062306a36Sopenharmony_ci else 156162306a36Sopenharmony_ci ixp4xx_aeads[i].registered = 1; 156262306a36Sopenharmony_ci } 156362306a36Sopenharmony_ci return 0; 156462306a36Sopenharmony_ci} 156562306a36Sopenharmony_ci 156662306a36Sopenharmony_cistatic int ixp_crypto_remove(struct platform_device *pdev) 156762306a36Sopenharmony_ci{ 156862306a36Sopenharmony_ci int num = ARRAY_SIZE(ixp4xx_algos); 156962306a36Sopenharmony_ci int i; 157062306a36Sopenharmony_ci 157162306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(ixp4xx_aeads); i++) { 157262306a36Sopenharmony_ci if (ixp4xx_aeads[i].registered) 157362306a36Sopenharmony_ci crypto_unregister_aead(&ixp4xx_aeads[i].crypto); 157462306a36Sopenharmony_ci } 157562306a36Sopenharmony_ci 157662306a36Sopenharmony_ci for (i = 0; i < num; i++) { 157762306a36Sopenharmony_ci if (ixp4xx_algos[i].registered) 157862306a36Sopenharmony_ci crypto_unregister_skcipher(&ixp4xx_algos[i].crypto); 157962306a36Sopenharmony_ci } 158062306a36Sopenharmony_ci release_ixp_crypto(&pdev->dev); 158162306a36Sopenharmony_ci 158262306a36Sopenharmony_ci return 0; 158362306a36Sopenharmony_ci} 158462306a36Sopenharmony_cistatic const struct of_device_id ixp4xx_crypto_of_match[] = { 158562306a36Sopenharmony_ci { 158662306a36Sopenharmony_ci .compatible = "intel,ixp4xx-crypto", 158762306a36Sopenharmony_ci }, 158862306a36Sopenharmony_ci {}, 158962306a36Sopenharmony_ci}; 159062306a36Sopenharmony_ci 159162306a36Sopenharmony_cistatic struct platform_driver ixp_crypto_driver = { 159262306a36Sopenharmony_ci .probe = ixp_crypto_probe, 159362306a36Sopenharmony_ci .remove = ixp_crypto_remove, 159462306a36Sopenharmony_ci .driver = { 159562306a36Sopenharmony_ci .name = "ixp4xx_crypto", 159662306a36Sopenharmony_ci .of_match_table = ixp4xx_crypto_of_match, 159762306a36Sopenharmony_ci }, 159862306a36Sopenharmony_ci}; 159962306a36Sopenharmony_cimodule_platform_driver(ixp_crypto_driver); 160062306a36Sopenharmony_ci 160162306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 160262306a36Sopenharmony_ciMODULE_AUTHOR("Christian Hohnstaedt <chohnstaedt@innominate.com>"); 160362306a36Sopenharmony_ciMODULE_DESCRIPTION("IXP4xx hardware crypto"); 160462306a36Sopenharmony_ci 1605