162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Driver for ARTPEC-6 crypto block using the kernel asynchronous crypto api. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2014-2017 Axis Communications AB 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/bitfield.h> 1062306a36Sopenharmony_ci#include <linux/crypto.h> 1162306a36Sopenharmony_ci#include <linux/debugfs.h> 1262306a36Sopenharmony_ci#include <linux/delay.h> 1362306a36Sopenharmony_ci#include <linux/dma-mapping.h> 1462306a36Sopenharmony_ci#include <linux/fault-inject.h> 1562306a36Sopenharmony_ci#include <linux/init.h> 1662306a36Sopenharmony_ci#include <linux/interrupt.h> 1762306a36Sopenharmony_ci#include <linux/kernel.h> 1862306a36Sopenharmony_ci#include <linux/list.h> 1962306a36Sopenharmony_ci#include <linux/module.h> 2062306a36Sopenharmony_ci#include <linux/of.h> 2162306a36Sopenharmony_ci#include <linux/platform_device.h> 2262306a36Sopenharmony_ci#include <linux/scatterlist.h> 2362306a36Sopenharmony_ci#include <linux/slab.h> 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#include <crypto/aes.h> 2662306a36Sopenharmony_ci#include <crypto/gcm.h> 2762306a36Sopenharmony_ci#include <crypto/internal/aead.h> 2862306a36Sopenharmony_ci#include <crypto/internal/hash.h> 2962306a36Sopenharmony_ci#include <crypto/internal/skcipher.h> 3062306a36Sopenharmony_ci#include <crypto/scatterwalk.h> 3162306a36Sopenharmony_ci#include <crypto/sha1.h> 3262306a36Sopenharmony_ci#include <crypto/sha2.h> 3362306a36Sopenharmony_ci#include <crypto/xts.h> 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci/* Max length of a line in all cache levels for Artpec SoCs. */ 3662306a36Sopenharmony_ci#define ARTPEC_CACHE_LINE_MAX 32 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci#define PDMA_OUT_CFG 0x0000 3962306a36Sopenharmony_ci#define PDMA_OUT_BUF_CFG 0x0004 4062306a36Sopenharmony_ci#define PDMA_OUT_CMD 0x0008 4162306a36Sopenharmony_ci#define PDMA_OUT_DESCRQ_PUSH 0x0010 4262306a36Sopenharmony_ci#define PDMA_OUT_DESCRQ_STAT 0x0014 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci#define A6_PDMA_IN_CFG 0x0028 4562306a36Sopenharmony_ci#define A6_PDMA_IN_BUF_CFG 0x002c 4662306a36Sopenharmony_ci#define A6_PDMA_IN_CMD 0x0030 4762306a36Sopenharmony_ci#define A6_PDMA_IN_STATQ_PUSH 0x0038 4862306a36Sopenharmony_ci#define A6_PDMA_IN_DESCRQ_PUSH 0x0044 4962306a36Sopenharmony_ci#define A6_PDMA_IN_DESCRQ_STAT 0x0048 5062306a36Sopenharmony_ci#define A6_PDMA_INTR_MASK 0x0068 5162306a36Sopenharmony_ci#define A6_PDMA_ACK_INTR 0x006c 5262306a36Sopenharmony_ci#define A6_PDMA_MASKED_INTR 0x0074 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci#define A7_PDMA_IN_CFG 0x002c 5562306a36Sopenharmony_ci#define A7_PDMA_IN_BUF_CFG 0x0030 5662306a36Sopenharmony_ci#define A7_PDMA_IN_CMD 0x0034 5762306a36Sopenharmony_ci#define A7_PDMA_IN_STATQ_PUSH 0x003c 5862306a36Sopenharmony_ci#define A7_PDMA_IN_DESCRQ_PUSH 0x0048 5962306a36Sopenharmony_ci#define A7_PDMA_IN_DESCRQ_STAT 0x004C 6062306a36Sopenharmony_ci#define A7_PDMA_INTR_MASK 0x006c 6162306a36Sopenharmony_ci#define A7_PDMA_ACK_INTR 0x0070 6262306a36Sopenharmony_ci#define A7_PDMA_MASKED_INTR 0x0078 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci#define PDMA_OUT_CFG_EN BIT(0) 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci#define PDMA_OUT_BUF_CFG_DATA_BUF_SIZE GENMASK(4, 0) 6762306a36Sopenharmony_ci#define PDMA_OUT_BUF_CFG_DESCR_BUF_SIZE GENMASK(9, 5) 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci#define PDMA_OUT_CMD_START BIT(0) 7062306a36Sopenharmony_ci#define A6_PDMA_OUT_CMD_STOP BIT(3) 7162306a36Sopenharmony_ci#define A7_PDMA_OUT_CMD_STOP BIT(2) 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci#define PDMA_OUT_DESCRQ_PUSH_LEN GENMASK(5, 0) 7462306a36Sopenharmony_ci#define PDMA_OUT_DESCRQ_PUSH_ADDR GENMASK(31, 6) 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci#define PDMA_OUT_DESCRQ_STAT_LEVEL GENMASK(3, 0) 7762306a36Sopenharmony_ci#define PDMA_OUT_DESCRQ_STAT_SIZE GENMASK(7, 4) 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci#define PDMA_IN_CFG_EN BIT(0) 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci#define PDMA_IN_BUF_CFG_DATA_BUF_SIZE GENMASK(4, 0) 8262306a36Sopenharmony_ci#define PDMA_IN_BUF_CFG_DESCR_BUF_SIZE GENMASK(9, 5) 8362306a36Sopenharmony_ci#define PDMA_IN_BUF_CFG_STAT_BUF_SIZE GENMASK(14, 10) 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci#define PDMA_IN_CMD_START BIT(0) 8662306a36Sopenharmony_ci#define A6_PDMA_IN_CMD_FLUSH_STAT BIT(2) 8762306a36Sopenharmony_ci#define A6_PDMA_IN_CMD_STOP BIT(3) 8862306a36Sopenharmony_ci#define A7_PDMA_IN_CMD_FLUSH_STAT BIT(1) 8962306a36Sopenharmony_ci#define A7_PDMA_IN_CMD_STOP BIT(2) 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci#define PDMA_IN_STATQ_PUSH_LEN GENMASK(5, 0) 9262306a36Sopenharmony_ci#define PDMA_IN_STATQ_PUSH_ADDR GENMASK(31, 6) 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci#define PDMA_IN_DESCRQ_PUSH_LEN GENMASK(5, 0) 9562306a36Sopenharmony_ci#define PDMA_IN_DESCRQ_PUSH_ADDR GENMASK(31, 6) 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci#define PDMA_IN_DESCRQ_STAT_LEVEL GENMASK(3, 0) 9862306a36Sopenharmony_ci#define PDMA_IN_DESCRQ_STAT_SIZE GENMASK(7, 4) 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci#define A6_PDMA_INTR_MASK_IN_DATA BIT(2) 10162306a36Sopenharmony_ci#define A6_PDMA_INTR_MASK_IN_EOP BIT(3) 10262306a36Sopenharmony_ci#define A6_PDMA_INTR_MASK_IN_EOP_FLUSH BIT(4) 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci#define A7_PDMA_INTR_MASK_IN_DATA BIT(3) 10562306a36Sopenharmony_ci#define A7_PDMA_INTR_MASK_IN_EOP BIT(4) 10662306a36Sopenharmony_ci#define A7_PDMA_INTR_MASK_IN_EOP_FLUSH BIT(5) 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci#define A6_CRY_MD_OPER GENMASK(19, 16) 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci#define A6_CRY_MD_HASH_SEL_CTX GENMASK(21, 20) 11162306a36Sopenharmony_ci#define A6_CRY_MD_HASH_HMAC_FIN BIT(23) 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci#define A6_CRY_MD_CIPHER_LEN GENMASK(21, 20) 11462306a36Sopenharmony_ci#define A6_CRY_MD_CIPHER_DECR BIT(22) 11562306a36Sopenharmony_ci#define A6_CRY_MD_CIPHER_TWEAK BIT(23) 11662306a36Sopenharmony_ci#define A6_CRY_MD_CIPHER_DSEQ BIT(24) 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci#define A7_CRY_MD_OPER GENMASK(11, 8) 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci#define A7_CRY_MD_HASH_SEL_CTX GENMASK(13, 12) 12162306a36Sopenharmony_ci#define A7_CRY_MD_HASH_HMAC_FIN BIT(15) 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci#define A7_CRY_MD_CIPHER_LEN GENMASK(13, 12) 12462306a36Sopenharmony_ci#define A7_CRY_MD_CIPHER_DECR BIT(14) 12562306a36Sopenharmony_ci#define A7_CRY_MD_CIPHER_TWEAK BIT(15) 12662306a36Sopenharmony_ci#define A7_CRY_MD_CIPHER_DSEQ BIT(16) 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci/* DMA metadata constants */ 12962306a36Sopenharmony_ci#define regk_crypto_aes_cbc 0x00000002 13062306a36Sopenharmony_ci#define regk_crypto_aes_ctr 0x00000003 13162306a36Sopenharmony_ci#define regk_crypto_aes_ecb 0x00000001 13262306a36Sopenharmony_ci#define regk_crypto_aes_gcm 0x00000004 13362306a36Sopenharmony_ci#define regk_crypto_aes_xts 0x00000005 13462306a36Sopenharmony_ci#define regk_crypto_cache 0x00000002 13562306a36Sopenharmony_ci#define a6_regk_crypto_dlkey 0x0000000a 13662306a36Sopenharmony_ci#define a7_regk_crypto_dlkey 0x0000000e 13762306a36Sopenharmony_ci#define regk_crypto_ext 0x00000001 13862306a36Sopenharmony_ci#define regk_crypto_hmac_sha1 0x00000007 13962306a36Sopenharmony_ci#define regk_crypto_hmac_sha256 0x00000009 14062306a36Sopenharmony_ci#define regk_crypto_init 0x00000000 14162306a36Sopenharmony_ci#define regk_crypto_key_128 0x00000000 14262306a36Sopenharmony_ci#define regk_crypto_key_192 0x00000001 14362306a36Sopenharmony_ci#define regk_crypto_key_256 0x00000002 14462306a36Sopenharmony_ci#define regk_crypto_null 0x00000000 14562306a36Sopenharmony_ci#define regk_crypto_sha1 0x00000006 14662306a36Sopenharmony_ci#define regk_crypto_sha256 0x00000008 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci/* DMA descriptor structures */ 14962306a36Sopenharmony_cistruct pdma_descr_ctrl { 15062306a36Sopenharmony_ci unsigned char short_descr : 1; 15162306a36Sopenharmony_ci unsigned char pad1 : 1; 15262306a36Sopenharmony_ci unsigned char eop : 1; 15362306a36Sopenharmony_ci unsigned char intr : 1; 15462306a36Sopenharmony_ci unsigned char short_len : 3; 15562306a36Sopenharmony_ci unsigned char pad2 : 1; 15662306a36Sopenharmony_ci} __packed; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_cistruct pdma_data_descr { 15962306a36Sopenharmony_ci unsigned int len : 24; 16062306a36Sopenharmony_ci unsigned int buf : 32; 16162306a36Sopenharmony_ci} __packed; 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_cistruct pdma_short_descr { 16462306a36Sopenharmony_ci unsigned char data[7]; 16562306a36Sopenharmony_ci} __packed; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_cistruct pdma_descr { 16862306a36Sopenharmony_ci struct pdma_descr_ctrl ctrl; 16962306a36Sopenharmony_ci union { 17062306a36Sopenharmony_ci struct pdma_data_descr data; 17162306a36Sopenharmony_ci struct pdma_short_descr shrt; 17262306a36Sopenharmony_ci }; 17362306a36Sopenharmony_ci}; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_cistruct pdma_stat_descr { 17662306a36Sopenharmony_ci unsigned char pad1 : 1; 17762306a36Sopenharmony_ci unsigned char pad2 : 1; 17862306a36Sopenharmony_ci unsigned char eop : 1; 17962306a36Sopenharmony_ci unsigned char pad3 : 5; 18062306a36Sopenharmony_ci unsigned int len : 24; 18162306a36Sopenharmony_ci}; 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci/* Each descriptor array can hold max 64 entries */ 18462306a36Sopenharmony_ci#define PDMA_DESCR_COUNT 64 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci#define MODULE_NAME "Artpec-6 CA" 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci/* Hash modes (including HMAC variants) */ 18962306a36Sopenharmony_ci#define ARTPEC6_CRYPTO_HASH_SHA1 1 19062306a36Sopenharmony_ci#define ARTPEC6_CRYPTO_HASH_SHA256 2 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci/* Crypto modes */ 19362306a36Sopenharmony_ci#define ARTPEC6_CRYPTO_CIPHER_AES_ECB 1 19462306a36Sopenharmony_ci#define ARTPEC6_CRYPTO_CIPHER_AES_CBC 2 19562306a36Sopenharmony_ci#define ARTPEC6_CRYPTO_CIPHER_AES_CTR 3 19662306a36Sopenharmony_ci#define ARTPEC6_CRYPTO_CIPHER_AES_XTS 5 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci/* The PDMA is a DMA-engine tightly coupled with a ciphering engine. 19962306a36Sopenharmony_ci * It operates on a descriptor array with up to 64 descriptor entries. 20062306a36Sopenharmony_ci * The arrays must be 64 byte aligned in memory. 20162306a36Sopenharmony_ci * 20262306a36Sopenharmony_ci * The ciphering unit has no registers and is completely controlled by 20362306a36Sopenharmony_ci * a 4-byte metadata that is inserted at the beginning of each dma packet. 20462306a36Sopenharmony_ci * 20562306a36Sopenharmony_ci * A dma packet is a sequence of descriptors terminated by setting the .eop 20662306a36Sopenharmony_ci * field in the final descriptor of the packet. 20762306a36Sopenharmony_ci * 20862306a36Sopenharmony_ci * Multiple packets are used for providing context data, key data and 20962306a36Sopenharmony_ci * the plain/ciphertext. 21062306a36Sopenharmony_ci * 21162306a36Sopenharmony_ci * PDMA Descriptors (Array) 21262306a36Sopenharmony_ci * +------+------+------+~~+-------+------+---- 21362306a36Sopenharmony_ci * | 0 | 1 | 2 |~~| 11 EOP| 12 | .... 21462306a36Sopenharmony_ci * +--+---+--+---+----+-+~~+-------+----+-+---- 21562306a36Sopenharmony_ci * | | | | | 21662306a36Sopenharmony_ci * | | | | | 21762306a36Sopenharmony_ci * __|__ +-------++-------++-------+ +----+ 21862306a36Sopenharmony_ci * | MD | |Payload||Payload||Payload| | MD | 21962306a36Sopenharmony_ci * +-----+ +-------++-------++-------+ +----+ 22062306a36Sopenharmony_ci */ 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_cistruct artpec6_crypto_bounce_buffer { 22362306a36Sopenharmony_ci struct list_head list; 22462306a36Sopenharmony_ci size_t length; 22562306a36Sopenharmony_ci struct scatterlist *sg; 22662306a36Sopenharmony_ci size_t offset; 22762306a36Sopenharmony_ci /* buf is aligned to ARTPEC_CACHE_LINE_MAX and 22862306a36Sopenharmony_ci * holds up to ARTPEC_CACHE_LINE_MAX bytes data. 22962306a36Sopenharmony_ci */ 23062306a36Sopenharmony_ci void *buf; 23162306a36Sopenharmony_ci}; 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_cistruct artpec6_crypto_dma_map { 23462306a36Sopenharmony_ci dma_addr_t dma_addr; 23562306a36Sopenharmony_ci size_t size; 23662306a36Sopenharmony_ci enum dma_data_direction dir; 23762306a36Sopenharmony_ci}; 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_cistruct artpec6_crypto_dma_descriptors { 24062306a36Sopenharmony_ci struct pdma_descr out[PDMA_DESCR_COUNT] __aligned(64); 24162306a36Sopenharmony_ci struct pdma_descr in[PDMA_DESCR_COUNT] __aligned(64); 24262306a36Sopenharmony_ci u32 stat[PDMA_DESCR_COUNT] __aligned(64); 24362306a36Sopenharmony_ci struct list_head bounce_buffers; 24462306a36Sopenharmony_ci /* Enough maps for all out/in buffers, and all three descr. arrays */ 24562306a36Sopenharmony_ci struct artpec6_crypto_dma_map maps[PDMA_DESCR_COUNT * 2 + 2]; 24662306a36Sopenharmony_ci dma_addr_t out_dma_addr; 24762306a36Sopenharmony_ci dma_addr_t in_dma_addr; 24862306a36Sopenharmony_ci dma_addr_t stat_dma_addr; 24962306a36Sopenharmony_ci size_t out_cnt; 25062306a36Sopenharmony_ci size_t in_cnt; 25162306a36Sopenharmony_ci size_t map_count; 25262306a36Sopenharmony_ci}; 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_cienum artpec6_crypto_variant { 25562306a36Sopenharmony_ci ARTPEC6_CRYPTO, 25662306a36Sopenharmony_ci ARTPEC7_CRYPTO, 25762306a36Sopenharmony_ci}; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_cistruct artpec6_crypto { 26062306a36Sopenharmony_ci void __iomem *base; 26162306a36Sopenharmony_ci spinlock_t queue_lock; 26262306a36Sopenharmony_ci struct list_head queue; /* waiting for pdma fifo space */ 26362306a36Sopenharmony_ci struct list_head pending; /* submitted to pdma fifo */ 26462306a36Sopenharmony_ci struct tasklet_struct task; 26562306a36Sopenharmony_ci struct kmem_cache *dma_cache; 26662306a36Sopenharmony_ci int pending_count; 26762306a36Sopenharmony_ci struct timer_list timer; 26862306a36Sopenharmony_ci enum artpec6_crypto_variant variant; 26962306a36Sopenharmony_ci void *pad_buffer; /* cache-aligned block padding buffer */ 27062306a36Sopenharmony_ci void *zero_buffer; 27162306a36Sopenharmony_ci}; 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_cienum artpec6_crypto_hash_flags { 27462306a36Sopenharmony_ci HASH_FLAG_INIT_CTX = 2, 27562306a36Sopenharmony_ci HASH_FLAG_UPDATE = 4, 27662306a36Sopenharmony_ci HASH_FLAG_FINALIZE = 8, 27762306a36Sopenharmony_ci HASH_FLAG_HMAC = 16, 27862306a36Sopenharmony_ci HASH_FLAG_UPDATE_KEY = 32, 27962306a36Sopenharmony_ci}; 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_cistruct artpec6_crypto_req_common { 28262306a36Sopenharmony_ci struct list_head list; 28362306a36Sopenharmony_ci struct list_head complete_in_progress; 28462306a36Sopenharmony_ci struct artpec6_crypto_dma_descriptors *dma; 28562306a36Sopenharmony_ci struct crypto_async_request *req; 28662306a36Sopenharmony_ci void (*complete)(struct crypto_async_request *req); 28762306a36Sopenharmony_ci gfp_t gfp_flags; 28862306a36Sopenharmony_ci}; 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_cistruct artpec6_hash_request_context { 29162306a36Sopenharmony_ci char partial_buffer[SHA256_BLOCK_SIZE]; 29262306a36Sopenharmony_ci char partial_buffer_out[SHA256_BLOCK_SIZE]; 29362306a36Sopenharmony_ci char key_buffer[SHA256_BLOCK_SIZE]; 29462306a36Sopenharmony_ci char pad_buffer[SHA256_BLOCK_SIZE + 32]; 29562306a36Sopenharmony_ci unsigned char digeststate[SHA256_DIGEST_SIZE]; 29662306a36Sopenharmony_ci size_t partial_bytes; 29762306a36Sopenharmony_ci u64 digcnt; 29862306a36Sopenharmony_ci u32 key_md; 29962306a36Sopenharmony_ci u32 hash_md; 30062306a36Sopenharmony_ci enum artpec6_crypto_hash_flags hash_flags; 30162306a36Sopenharmony_ci struct artpec6_crypto_req_common common; 30262306a36Sopenharmony_ci}; 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_cistruct artpec6_hash_export_state { 30562306a36Sopenharmony_ci char partial_buffer[SHA256_BLOCK_SIZE]; 30662306a36Sopenharmony_ci unsigned char digeststate[SHA256_DIGEST_SIZE]; 30762306a36Sopenharmony_ci size_t partial_bytes; 30862306a36Sopenharmony_ci u64 digcnt; 30962306a36Sopenharmony_ci int oper; 31062306a36Sopenharmony_ci unsigned int hash_flags; 31162306a36Sopenharmony_ci}; 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_cistruct artpec6_hashalg_context { 31462306a36Sopenharmony_ci char hmac_key[SHA256_BLOCK_SIZE]; 31562306a36Sopenharmony_ci size_t hmac_key_length; 31662306a36Sopenharmony_ci struct crypto_shash *child_hash; 31762306a36Sopenharmony_ci}; 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_cistruct artpec6_crypto_request_context { 32062306a36Sopenharmony_ci u32 cipher_md; 32162306a36Sopenharmony_ci bool decrypt; 32262306a36Sopenharmony_ci struct artpec6_crypto_req_common common; 32362306a36Sopenharmony_ci}; 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_cistruct artpec6_cryptotfm_context { 32662306a36Sopenharmony_ci unsigned char aes_key[2*AES_MAX_KEY_SIZE]; 32762306a36Sopenharmony_ci size_t key_length; 32862306a36Sopenharmony_ci u32 key_md; 32962306a36Sopenharmony_ci int crypto_type; 33062306a36Sopenharmony_ci struct crypto_sync_skcipher *fallback; 33162306a36Sopenharmony_ci}; 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_cistruct artpec6_crypto_aead_hw_ctx { 33462306a36Sopenharmony_ci __be64 aad_length_bits; 33562306a36Sopenharmony_ci __be64 text_length_bits; 33662306a36Sopenharmony_ci __u8 J0[AES_BLOCK_SIZE]; 33762306a36Sopenharmony_ci}; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_cistruct artpec6_crypto_aead_req_ctx { 34062306a36Sopenharmony_ci struct artpec6_crypto_aead_hw_ctx hw_ctx; 34162306a36Sopenharmony_ci u32 cipher_md; 34262306a36Sopenharmony_ci bool decrypt; 34362306a36Sopenharmony_ci struct artpec6_crypto_req_common common; 34462306a36Sopenharmony_ci __u8 decryption_tag[AES_BLOCK_SIZE] ____cacheline_aligned; 34562306a36Sopenharmony_ci}; 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci/* The crypto framework makes it hard to avoid this global. */ 34862306a36Sopenharmony_cistatic struct device *artpec6_crypto_dev; 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci#ifdef CONFIG_FAULT_INJECTION 35162306a36Sopenharmony_cistatic DECLARE_FAULT_ATTR(artpec6_crypto_fail_status_read); 35262306a36Sopenharmony_cistatic DECLARE_FAULT_ATTR(artpec6_crypto_fail_dma_array_full); 35362306a36Sopenharmony_ci#endif 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_cienum { 35662306a36Sopenharmony_ci ARTPEC6_CRYPTO_PREPARE_HASH_NO_START, 35762306a36Sopenharmony_ci ARTPEC6_CRYPTO_PREPARE_HASH_START, 35862306a36Sopenharmony_ci}; 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_cistatic int artpec6_crypto_prepare_aead(struct aead_request *areq); 36162306a36Sopenharmony_cistatic int artpec6_crypto_prepare_crypto(struct skcipher_request *areq); 36262306a36Sopenharmony_cistatic int artpec6_crypto_prepare_hash(struct ahash_request *areq); 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_cistatic void 36562306a36Sopenharmony_ciartpec6_crypto_complete_crypto(struct crypto_async_request *req); 36662306a36Sopenharmony_cistatic void 36762306a36Sopenharmony_ciartpec6_crypto_complete_cbc_encrypt(struct crypto_async_request *req); 36862306a36Sopenharmony_cistatic void 36962306a36Sopenharmony_ciartpec6_crypto_complete_cbc_decrypt(struct crypto_async_request *req); 37062306a36Sopenharmony_cistatic void 37162306a36Sopenharmony_ciartpec6_crypto_complete_aead(struct crypto_async_request *req); 37262306a36Sopenharmony_cistatic void 37362306a36Sopenharmony_ciartpec6_crypto_complete_hash(struct crypto_async_request *req); 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_cistatic int 37662306a36Sopenharmony_ciartpec6_crypto_common_destroy(struct artpec6_crypto_req_common *common); 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_cistatic void 37962306a36Sopenharmony_ciartpec6_crypto_start_dma(struct artpec6_crypto_req_common *common); 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_cistruct artpec6_crypto_walk { 38262306a36Sopenharmony_ci struct scatterlist *sg; 38362306a36Sopenharmony_ci size_t offset; 38462306a36Sopenharmony_ci}; 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_cistatic void artpec6_crypto_walk_init(struct artpec6_crypto_walk *awalk, 38762306a36Sopenharmony_ci struct scatterlist *sg) 38862306a36Sopenharmony_ci{ 38962306a36Sopenharmony_ci awalk->sg = sg; 39062306a36Sopenharmony_ci awalk->offset = 0; 39162306a36Sopenharmony_ci} 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_cistatic size_t artpec6_crypto_walk_advance(struct artpec6_crypto_walk *awalk, 39462306a36Sopenharmony_ci size_t nbytes) 39562306a36Sopenharmony_ci{ 39662306a36Sopenharmony_ci while (nbytes && awalk->sg) { 39762306a36Sopenharmony_ci size_t piece; 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci WARN_ON(awalk->offset > awalk->sg->length); 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci piece = min(nbytes, (size_t)awalk->sg->length - awalk->offset); 40262306a36Sopenharmony_ci nbytes -= piece; 40362306a36Sopenharmony_ci awalk->offset += piece; 40462306a36Sopenharmony_ci if (awalk->offset == awalk->sg->length) { 40562306a36Sopenharmony_ci awalk->sg = sg_next(awalk->sg); 40662306a36Sopenharmony_ci awalk->offset = 0; 40762306a36Sopenharmony_ci } 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci } 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci return nbytes; 41262306a36Sopenharmony_ci} 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_cistatic size_t 41562306a36Sopenharmony_ciartpec6_crypto_walk_chunklen(const struct artpec6_crypto_walk *awalk) 41662306a36Sopenharmony_ci{ 41762306a36Sopenharmony_ci WARN_ON(awalk->sg->length == awalk->offset); 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci return awalk->sg->length - awalk->offset; 42062306a36Sopenharmony_ci} 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_cistatic dma_addr_t 42362306a36Sopenharmony_ciartpec6_crypto_walk_chunk_phys(const struct artpec6_crypto_walk *awalk) 42462306a36Sopenharmony_ci{ 42562306a36Sopenharmony_ci return sg_phys(awalk->sg) + awalk->offset; 42662306a36Sopenharmony_ci} 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_cistatic void 42962306a36Sopenharmony_ciartpec6_crypto_copy_bounce_buffers(struct artpec6_crypto_req_common *common) 43062306a36Sopenharmony_ci{ 43162306a36Sopenharmony_ci struct artpec6_crypto_dma_descriptors *dma = common->dma; 43262306a36Sopenharmony_ci struct artpec6_crypto_bounce_buffer *b; 43362306a36Sopenharmony_ci struct artpec6_crypto_bounce_buffer *next; 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci list_for_each_entry_safe(b, next, &dma->bounce_buffers, list) { 43662306a36Sopenharmony_ci pr_debug("bounce entry %p: %zu bytes @ %zu from %p\n", 43762306a36Sopenharmony_ci b, b->length, b->offset, b->buf); 43862306a36Sopenharmony_ci sg_pcopy_from_buffer(b->sg, 43962306a36Sopenharmony_ci 1, 44062306a36Sopenharmony_ci b->buf, 44162306a36Sopenharmony_ci b->length, 44262306a36Sopenharmony_ci b->offset); 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci list_del(&b->list); 44562306a36Sopenharmony_ci kfree(b); 44662306a36Sopenharmony_ci } 44762306a36Sopenharmony_ci} 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_cistatic inline bool artpec6_crypto_busy(void) 45062306a36Sopenharmony_ci{ 45162306a36Sopenharmony_ci struct artpec6_crypto *ac = dev_get_drvdata(artpec6_crypto_dev); 45262306a36Sopenharmony_ci int fifo_count = ac->pending_count; 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci return fifo_count > 6; 45562306a36Sopenharmony_ci} 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_cistatic int artpec6_crypto_submit(struct artpec6_crypto_req_common *req) 45862306a36Sopenharmony_ci{ 45962306a36Sopenharmony_ci struct artpec6_crypto *ac = dev_get_drvdata(artpec6_crypto_dev); 46062306a36Sopenharmony_ci int ret = -EBUSY; 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci spin_lock_bh(&ac->queue_lock); 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci if (!artpec6_crypto_busy()) { 46562306a36Sopenharmony_ci list_add_tail(&req->list, &ac->pending); 46662306a36Sopenharmony_ci artpec6_crypto_start_dma(req); 46762306a36Sopenharmony_ci ret = -EINPROGRESS; 46862306a36Sopenharmony_ci } else if (req->req->flags & CRYPTO_TFM_REQ_MAY_BACKLOG) { 46962306a36Sopenharmony_ci list_add_tail(&req->list, &ac->queue); 47062306a36Sopenharmony_ci } else { 47162306a36Sopenharmony_ci artpec6_crypto_common_destroy(req); 47262306a36Sopenharmony_ci } 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci spin_unlock_bh(&ac->queue_lock); 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci return ret; 47762306a36Sopenharmony_ci} 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_cistatic void artpec6_crypto_start_dma(struct artpec6_crypto_req_common *common) 48062306a36Sopenharmony_ci{ 48162306a36Sopenharmony_ci struct artpec6_crypto *ac = dev_get_drvdata(artpec6_crypto_dev); 48262306a36Sopenharmony_ci enum artpec6_crypto_variant variant = ac->variant; 48362306a36Sopenharmony_ci void __iomem *base = ac->base; 48462306a36Sopenharmony_ci struct artpec6_crypto_dma_descriptors *dma = common->dma; 48562306a36Sopenharmony_ci u32 ind, statd, outd; 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci /* Make descriptor content visible to the DMA before starting it. */ 48862306a36Sopenharmony_ci wmb(); 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci ind = FIELD_PREP(PDMA_IN_DESCRQ_PUSH_LEN, dma->in_cnt - 1) | 49162306a36Sopenharmony_ci FIELD_PREP(PDMA_IN_DESCRQ_PUSH_ADDR, dma->in_dma_addr >> 6); 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci statd = FIELD_PREP(PDMA_IN_STATQ_PUSH_LEN, dma->in_cnt - 1) | 49462306a36Sopenharmony_ci FIELD_PREP(PDMA_IN_STATQ_PUSH_ADDR, dma->stat_dma_addr >> 6); 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci outd = FIELD_PREP(PDMA_OUT_DESCRQ_PUSH_LEN, dma->out_cnt - 1) | 49762306a36Sopenharmony_ci FIELD_PREP(PDMA_OUT_DESCRQ_PUSH_ADDR, dma->out_dma_addr >> 6); 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci if (variant == ARTPEC6_CRYPTO) { 50062306a36Sopenharmony_ci writel_relaxed(ind, base + A6_PDMA_IN_DESCRQ_PUSH); 50162306a36Sopenharmony_ci writel_relaxed(statd, base + A6_PDMA_IN_STATQ_PUSH); 50262306a36Sopenharmony_ci writel_relaxed(PDMA_IN_CMD_START, base + A6_PDMA_IN_CMD); 50362306a36Sopenharmony_ci } else { 50462306a36Sopenharmony_ci writel_relaxed(ind, base + A7_PDMA_IN_DESCRQ_PUSH); 50562306a36Sopenharmony_ci writel_relaxed(statd, base + A7_PDMA_IN_STATQ_PUSH); 50662306a36Sopenharmony_ci writel_relaxed(PDMA_IN_CMD_START, base + A7_PDMA_IN_CMD); 50762306a36Sopenharmony_ci } 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci writel_relaxed(outd, base + PDMA_OUT_DESCRQ_PUSH); 51062306a36Sopenharmony_ci writel_relaxed(PDMA_OUT_CMD_START, base + PDMA_OUT_CMD); 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci ac->pending_count++; 51362306a36Sopenharmony_ci} 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_cistatic void 51662306a36Sopenharmony_ciartpec6_crypto_init_dma_operation(struct artpec6_crypto_req_common *common) 51762306a36Sopenharmony_ci{ 51862306a36Sopenharmony_ci struct artpec6_crypto_dma_descriptors *dma = common->dma; 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci dma->out_cnt = 0; 52162306a36Sopenharmony_ci dma->in_cnt = 0; 52262306a36Sopenharmony_ci dma->map_count = 0; 52362306a36Sopenharmony_ci INIT_LIST_HEAD(&dma->bounce_buffers); 52462306a36Sopenharmony_ci} 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_cistatic bool fault_inject_dma_descr(void) 52762306a36Sopenharmony_ci{ 52862306a36Sopenharmony_ci#ifdef CONFIG_FAULT_INJECTION 52962306a36Sopenharmony_ci return should_fail(&artpec6_crypto_fail_dma_array_full, 1); 53062306a36Sopenharmony_ci#else 53162306a36Sopenharmony_ci return false; 53262306a36Sopenharmony_ci#endif 53362306a36Sopenharmony_ci} 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci/** artpec6_crypto_setup_out_descr_phys - Setup an out channel with a 53662306a36Sopenharmony_ci * physical address 53762306a36Sopenharmony_ci * 53862306a36Sopenharmony_ci * @addr: The physical address of the data buffer 53962306a36Sopenharmony_ci * @len: The length of the data buffer 54062306a36Sopenharmony_ci * @eop: True if this is the last buffer in the packet 54162306a36Sopenharmony_ci * 54262306a36Sopenharmony_ci * @return 0 on success or -ENOSPC if there are no more descriptors available 54362306a36Sopenharmony_ci */ 54462306a36Sopenharmony_cistatic int 54562306a36Sopenharmony_ciartpec6_crypto_setup_out_descr_phys(struct artpec6_crypto_req_common *common, 54662306a36Sopenharmony_ci dma_addr_t addr, size_t len, bool eop) 54762306a36Sopenharmony_ci{ 54862306a36Sopenharmony_ci struct artpec6_crypto_dma_descriptors *dma = common->dma; 54962306a36Sopenharmony_ci struct pdma_descr *d; 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci if (dma->out_cnt >= PDMA_DESCR_COUNT || 55262306a36Sopenharmony_ci fault_inject_dma_descr()) { 55362306a36Sopenharmony_ci pr_err("No free OUT DMA descriptors available!\n"); 55462306a36Sopenharmony_ci return -ENOSPC; 55562306a36Sopenharmony_ci } 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci d = &dma->out[dma->out_cnt++]; 55862306a36Sopenharmony_ci memset(d, 0, sizeof(*d)); 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci d->ctrl.short_descr = 0; 56162306a36Sopenharmony_ci d->ctrl.eop = eop; 56262306a36Sopenharmony_ci d->data.len = len; 56362306a36Sopenharmony_ci d->data.buf = addr; 56462306a36Sopenharmony_ci return 0; 56562306a36Sopenharmony_ci} 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci/** artpec6_crypto_setup_out_descr_short - Setup a short out descriptor 56862306a36Sopenharmony_ci * 56962306a36Sopenharmony_ci * @dst: The virtual address of the data 57062306a36Sopenharmony_ci * @len: The length of the data, must be between 1 to 7 bytes 57162306a36Sopenharmony_ci * @eop: True if this is the last buffer in the packet 57262306a36Sopenharmony_ci * 57362306a36Sopenharmony_ci * @return 0 on success 57462306a36Sopenharmony_ci * -ENOSPC if no more descriptors are available 57562306a36Sopenharmony_ci * -EINVAL if the data length exceeds 7 bytes 57662306a36Sopenharmony_ci */ 57762306a36Sopenharmony_cistatic int 57862306a36Sopenharmony_ciartpec6_crypto_setup_out_descr_short(struct artpec6_crypto_req_common *common, 57962306a36Sopenharmony_ci void *dst, unsigned int len, bool eop) 58062306a36Sopenharmony_ci{ 58162306a36Sopenharmony_ci struct artpec6_crypto_dma_descriptors *dma = common->dma; 58262306a36Sopenharmony_ci struct pdma_descr *d; 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci if (dma->out_cnt >= PDMA_DESCR_COUNT || 58562306a36Sopenharmony_ci fault_inject_dma_descr()) { 58662306a36Sopenharmony_ci pr_err("No free OUT DMA descriptors available!\n"); 58762306a36Sopenharmony_ci return -ENOSPC; 58862306a36Sopenharmony_ci } else if (len > 7 || len < 1) { 58962306a36Sopenharmony_ci return -EINVAL; 59062306a36Sopenharmony_ci } 59162306a36Sopenharmony_ci d = &dma->out[dma->out_cnt++]; 59262306a36Sopenharmony_ci memset(d, 0, sizeof(*d)); 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci d->ctrl.short_descr = 1; 59562306a36Sopenharmony_ci d->ctrl.short_len = len; 59662306a36Sopenharmony_ci d->ctrl.eop = eop; 59762306a36Sopenharmony_ci memcpy(d->shrt.data, dst, len); 59862306a36Sopenharmony_ci return 0; 59962306a36Sopenharmony_ci} 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_cistatic int artpec6_crypto_dma_map_page(struct artpec6_crypto_req_common *common, 60262306a36Sopenharmony_ci struct page *page, size_t offset, 60362306a36Sopenharmony_ci size_t size, 60462306a36Sopenharmony_ci enum dma_data_direction dir, 60562306a36Sopenharmony_ci dma_addr_t *dma_addr_out) 60662306a36Sopenharmony_ci{ 60762306a36Sopenharmony_ci struct artpec6_crypto_dma_descriptors *dma = common->dma; 60862306a36Sopenharmony_ci struct device *dev = artpec6_crypto_dev; 60962306a36Sopenharmony_ci struct artpec6_crypto_dma_map *map; 61062306a36Sopenharmony_ci dma_addr_t dma_addr; 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci *dma_addr_out = 0; 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci if (dma->map_count >= ARRAY_SIZE(dma->maps)) 61562306a36Sopenharmony_ci return -ENOMEM; 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci dma_addr = dma_map_page(dev, page, offset, size, dir); 61862306a36Sopenharmony_ci if (dma_mapping_error(dev, dma_addr)) 61962306a36Sopenharmony_ci return -ENOMEM; 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci map = &dma->maps[dma->map_count++]; 62262306a36Sopenharmony_ci map->size = size; 62362306a36Sopenharmony_ci map->dma_addr = dma_addr; 62462306a36Sopenharmony_ci map->dir = dir; 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci *dma_addr_out = dma_addr; 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci return 0; 62962306a36Sopenharmony_ci} 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_cistatic int 63262306a36Sopenharmony_ciartpec6_crypto_dma_map_single(struct artpec6_crypto_req_common *common, 63362306a36Sopenharmony_ci void *ptr, size_t size, 63462306a36Sopenharmony_ci enum dma_data_direction dir, 63562306a36Sopenharmony_ci dma_addr_t *dma_addr_out) 63662306a36Sopenharmony_ci{ 63762306a36Sopenharmony_ci struct page *page = virt_to_page(ptr); 63862306a36Sopenharmony_ci size_t offset = (uintptr_t)ptr & ~PAGE_MASK; 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci return artpec6_crypto_dma_map_page(common, page, offset, size, dir, 64162306a36Sopenharmony_ci dma_addr_out); 64262306a36Sopenharmony_ci} 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_cistatic int 64562306a36Sopenharmony_ciartpec6_crypto_dma_map_descs(struct artpec6_crypto_req_common *common) 64662306a36Sopenharmony_ci{ 64762306a36Sopenharmony_ci struct artpec6_crypto_dma_descriptors *dma = common->dma; 64862306a36Sopenharmony_ci int ret; 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci ret = artpec6_crypto_dma_map_single(common, dma->in, 65162306a36Sopenharmony_ci sizeof(dma->in[0]) * dma->in_cnt, 65262306a36Sopenharmony_ci DMA_TO_DEVICE, &dma->in_dma_addr); 65362306a36Sopenharmony_ci if (ret) 65462306a36Sopenharmony_ci return ret; 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci ret = artpec6_crypto_dma_map_single(common, dma->out, 65762306a36Sopenharmony_ci sizeof(dma->out[0]) * dma->out_cnt, 65862306a36Sopenharmony_ci DMA_TO_DEVICE, &dma->out_dma_addr); 65962306a36Sopenharmony_ci if (ret) 66062306a36Sopenharmony_ci return ret; 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci /* We only read one stat descriptor */ 66362306a36Sopenharmony_ci dma->stat[dma->in_cnt - 1] = 0; 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci /* 66662306a36Sopenharmony_ci * DMA_BIDIRECTIONAL since we need our zeroing of the stat descriptor 66762306a36Sopenharmony_ci * to be written. 66862306a36Sopenharmony_ci */ 66962306a36Sopenharmony_ci return artpec6_crypto_dma_map_single(common, 67062306a36Sopenharmony_ci dma->stat, 67162306a36Sopenharmony_ci sizeof(dma->stat[0]) * dma->in_cnt, 67262306a36Sopenharmony_ci DMA_BIDIRECTIONAL, 67362306a36Sopenharmony_ci &dma->stat_dma_addr); 67462306a36Sopenharmony_ci} 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_cistatic void 67762306a36Sopenharmony_ciartpec6_crypto_dma_unmap_all(struct artpec6_crypto_req_common *common) 67862306a36Sopenharmony_ci{ 67962306a36Sopenharmony_ci struct artpec6_crypto_dma_descriptors *dma = common->dma; 68062306a36Sopenharmony_ci struct device *dev = artpec6_crypto_dev; 68162306a36Sopenharmony_ci int i; 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci for (i = 0; i < dma->map_count; i++) { 68462306a36Sopenharmony_ci struct artpec6_crypto_dma_map *map = &dma->maps[i]; 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci dma_unmap_page(dev, map->dma_addr, map->size, map->dir); 68762306a36Sopenharmony_ci } 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci dma->map_count = 0; 69062306a36Sopenharmony_ci} 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci/** artpec6_crypto_setup_out_descr - Setup an out descriptor 69362306a36Sopenharmony_ci * 69462306a36Sopenharmony_ci * @dst: The virtual address of the data 69562306a36Sopenharmony_ci * @len: The length of the data 69662306a36Sopenharmony_ci * @eop: True if this is the last buffer in the packet 69762306a36Sopenharmony_ci * @use_short: If this is true and the data length is 7 bytes or less then 69862306a36Sopenharmony_ci * a short descriptor will be used 69962306a36Sopenharmony_ci * 70062306a36Sopenharmony_ci * @return 0 on success 70162306a36Sopenharmony_ci * Any errors from artpec6_crypto_setup_out_descr_short() or 70262306a36Sopenharmony_ci * setup_out_descr_phys() 70362306a36Sopenharmony_ci */ 70462306a36Sopenharmony_cistatic int 70562306a36Sopenharmony_ciartpec6_crypto_setup_out_descr(struct artpec6_crypto_req_common *common, 70662306a36Sopenharmony_ci void *dst, unsigned int len, bool eop, 70762306a36Sopenharmony_ci bool use_short) 70862306a36Sopenharmony_ci{ 70962306a36Sopenharmony_ci if (use_short && len < 7) { 71062306a36Sopenharmony_ci return artpec6_crypto_setup_out_descr_short(common, dst, len, 71162306a36Sopenharmony_ci eop); 71262306a36Sopenharmony_ci } else { 71362306a36Sopenharmony_ci int ret; 71462306a36Sopenharmony_ci dma_addr_t dma_addr; 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci ret = artpec6_crypto_dma_map_single(common, dst, len, 71762306a36Sopenharmony_ci DMA_TO_DEVICE, 71862306a36Sopenharmony_ci &dma_addr); 71962306a36Sopenharmony_ci if (ret) 72062306a36Sopenharmony_ci return ret; 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci return artpec6_crypto_setup_out_descr_phys(common, dma_addr, 72362306a36Sopenharmony_ci len, eop); 72462306a36Sopenharmony_ci } 72562306a36Sopenharmony_ci} 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci/** artpec6_crypto_setup_in_descr_phys - Setup an in channel with a 72862306a36Sopenharmony_ci * physical address 72962306a36Sopenharmony_ci * 73062306a36Sopenharmony_ci * @addr: The physical address of the data buffer 73162306a36Sopenharmony_ci * @len: The length of the data buffer 73262306a36Sopenharmony_ci * @intr: True if an interrupt should be fired after HW processing of this 73362306a36Sopenharmony_ci * descriptor 73462306a36Sopenharmony_ci * 73562306a36Sopenharmony_ci */ 73662306a36Sopenharmony_cistatic int 73762306a36Sopenharmony_ciartpec6_crypto_setup_in_descr_phys(struct artpec6_crypto_req_common *common, 73862306a36Sopenharmony_ci dma_addr_t addr, unsigned int len, bool intr) 73962306a36Sopenharmony_ci{ 74062306a36Sopenharmony_ci struct artpec6_crypto_dma_descriptors *dma = common->dma; 74162306a36Sopenharmony_ci struct pdma_descr *d; 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_ci if (dma->in_cnt >= PDMA_DESCR_COUNT || 74462306a36Sopenharmony_ci fault_inject_dma_descr()) { 74562306a36Sopenharmony_ci pr_err("No free IN DMA descriptors available!\n"); 74662306a36Sopenharmony_ci return -ENOSPC; 74762306a36Sopenharmony_ci } 74862306a36Sopenharmony_ci d = &dma->in[dma->in_cnt++]; 74962306a36Sopenharmony_ci memset(d, 0, sizeof(*d)); 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci d->ctrl.intr = intr; 75262306a36Sopenharmony_ci d->data.len = len; 75362306a36Sopenharmony_ci d->data.buf = addr; 75462306a36Sopenharmony_ci return 0; 75562306a36Sopenharmony_ci} 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci/** artpec6_crypto_setup_in_descr - Setup an in channel descriptor 75862306a36Sopenharmony_ci * 75962306a36Sopenharmony_ci * @buffer: The virtual address to of the data buffer 76062306a36Sopenharmony_ci * @len: The length of the data buffer 76162306a36Sopenharmony_ci * @last: If this is the last data buffer in the request (i.e. an interrupt 76262306a36Sopenharmony_ci * is needed 76362306a36Sopenharmony_ci * 76462306a36Sopenharmony_ci * Short descriptors are not used for the in channel 76562306a36Sopenharmony_ci */ 76662306a36Sopenharmony_cistatic int 76762306a36Sopenharmony_ciartpec6_crypto_setup_in_descr(struct artpec6_crypto_req_common *common, 76862306a36Sopenharmony_ci void *buffer, unsigned int len, bool last) 76962306a36Sopenharmony_ci{ 77062306a36Sopenharmony_ci dma_addr_t dma_addr; 77162306a36Sopenharmony_ci int ret; 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci ret = artpec6_crypto_dma_map_single(common, buffer, len, 77462306a36Sopenharmony_ci DMA_FROM_DEVICE, &dma_addr); 77562306a36Sopenharmony_ci if (ret) 77662306a36Sopenharmony_ci return ret; 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci return artpec6_crypto_setup_in_descr_phys(common, dma_addr, len, last); 77962306a36Sopenharmony_ci} 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_cistatic struct artpec6_crypto_bounce_buffer * 78262306a36Sopenharmony_ciartpec6_crypto_alloc_bounce(gfp_t flags) 78362306a36Sopenharmony_ci{ 78462306a36Sopenharmony_ci void *base; 78562306a36Sopenharmony_ci size_t alloc_size = sizeof(struct artpec6_crypto_bounce_buffer) + 78662306a36Sopenharmony_ci 2 * ARTPEC_CACHE_LINE_MAX; 78762306a36Sopenharmony_ci struct artpec6_crypto_bounce_buffer *bbuf = kzalloc(alloc_size, flags); 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci if (!bbuf) 79062306a36Sopenharmony_ci return NULL; 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci base = bbuf + 1; 79362306a36Sopenharmony_ci bbuf->buf = PTR_ALIGN(base, ARTPEC_CACHE_LINE_MAX); 79462306a36Sopenharmony_ci return bbuf; 79562306a36Sopenharmony_ci} 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_cistatic int setup_bounce_buffer_in(struct artpec6_crypto_req_common *common, 79862306a36Sopenharmony_ci struct artpec6_crypto_walk *walk, size_t size) 79962306a36Sopenharmony_ci{ 80062306a36Sopenharmony_ci struct artpec6_crypto_bounce_buffer *bbuf; 80162306a36Sopenharmony_ci int ret; 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci bbuf = artpec6_crypto_alloc_bounce(common->gfp_flags); 80462306a36Sopenharmony_ci if (!bbuf) 80562306a36Sopenharmony_ci return -ENOMEM; 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ci bbuf->length = size; 80862306a36Sopenharmony_ci bbuf->sg = walk->sg; 80962306a36Sopenharmony_ci bbuf->offset = walk->offset; 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci ret = artpec6_crypto_setup_in_descr(common, bbuf->buf, size, false); 81262306a36Sopenharmony_ci if (ret) { 81362306a36Sopenharmony_ci kfree(bbuf); 81462306a36Sopenharmony_ci return ret; 81562306a36Sopenharmony_ci } 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci pr_debug("BOUNCE %zu offset %zu\n", size, walk->offset); 81862306a36Sopenharmony_ci list_add_tail(&bbuf->list, &common->dma->bounce_buffers); 81962306a36Sopenharmony_ci return 0; 82062306a36Sopenharmony_ci} 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_cistatic int 82362306a36Sopenharmony_ciartpec6_crypto_setup_sg_descrs_in(struct artpec6_crypto_req_common *common, 82462306a36Sopenharmony_ci struct artpec6_crypto_walk *walk, 82562306a36Sopenharmony_ci size_t count) 82662306a36Sopenharmony_ci{ 82762306a36Sopenharmony_ci size_t chunk; 82862306a36Sopenharmony_ci int ret; 82962306a36Sopenharmony_ci dma_addr_t addr; 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci while (walk->sg && count) { 83262306a36Sopenharmony_ci chunk = min(count, artpec6_crypto_walk_chunklen(walk)); 83362306a36Sopenharmony_ci addr = artpec6_crypto_walk_chunk_phys(walk); 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_ci /* When destination buffers are not aligned to the cache line 83662306a36Sopenharmony_ci * size we need bounce buffers. The DMA-API requires that the 83762306a36Sopenharmony_ci * entire line is owned by the DMA buffer and this holds also 83862306a36Sopenharmony_ci * for the case when coherent DMA is used. 83962306a36Sopenharmony_ci */ 84062306a36Sopenharmony_ci if (!IS_ALIGNED(addr, ARTPEC_CACHE_LINE_MAX)) { 84162306a36Sopenharmony_ci chunk = min_t(dma_addr_t, chunk, 84262306a36Sopenharmony_ci ALIGN(addr, ARTPEC_CACHE_LINE_MAX) - 84362306a36Sopenharmony_ci addr); 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci pr_debug("CHUNK-b %pad:%zu\n", &addr, chunk); 84662306a36Sopenharmony_ci ret = setup_bounce_buffer_in(common, walk, chunk); 84762306a36Sopenharmony_ci } else if (chunk < ARTPEC_CACHE_LINE_MAX) { 84862306a36Sopenharmony_ci pr_debug("CHUNK-b %pad:%zu\n", &addr, chunk); 84962306a36Sopenharmony_ci ret = setup_bounce_buffer_in(common, walk, chunk); 85062306a36Sopenharmony_ci } else { 85162306a36Sopenharmony_ci dma_addr_t dma_addr; 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci chunk = chunk & ~(ARTPEC_CACHE_LINE_MAX-1); 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_ci pr_debug("CHUNK %pad:%zu\n", &addr, chunk); 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci ret = artpec6_crypto_dma_map_page(common, 85862306a36Sopenharmony_ci sg_page(walk->sg), 85962306a36Sopenharmony_ci walk->sg->offset + 86062306a36Sopenharmony_ci walk->offset, 86162306a36Sopenharmony_ci chunk, 86262306a36Sopenharmony_ci DMA_FROM_DEVICE, 86362306a36Sopenharmony_ci &dma_addr); 86462306a36Sopenharmony_ci if (ret) 86562306a36Sopenharmony_ci return ret; 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_ci ret = artpec6_crypto_setup_in_descr_phys(common, 86862306a36Sopenharmony_ci dma_addr, 86962306a36Sopenharmony_ci chunk, false); 87062306a36Sopenharmony_ci } 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ci if (ret) 87362306a36Sopenharmony_ci return ret; 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci count = count - chunk; 87662306a36Sopenharmony_ci artpec6_crypto_walk_advance(walk, chunk); 87762306a36Sopenharmony_ci } 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_ci if (count) 88062306a36Sopenharmony_ci pr_err("EOL unexpected %zu bytes left\n", count); 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci return count ? -EINVAL : 0; 88362306a36Sopenharmony_ci} 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_cistatic int 88662306a36Sopenharmony_ciartpec6_crypto_setup_sg_descrs_out(struct artpec6_crypto_req_common *common, 88762306a36Sopenharmony_ci struct artpec6_crypto_walk *walk, 88862306a36Sopenharmony_ci size_t count) 88962306a36Sopenharmony_ci{ 89062306a36Sopenharmony_ci size_t chunk; 89162306a36Sopenharmony_ci int ret; 89262306a36Sopenharmony_ci dma_addr_t addr; 89362306a36Sopenharmony_ci 89462306a36Sopenharmony_ci while (walk->sg && count) { 89562306a36Sopenharmony_ci chunk = min(count, artpec6_crypto_walk_chunklen(walk)); 89662306a36Sopenharmony_ci addr = artpec6_crypto_walk_chunk_phys(walk); 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_ci pr_debug("OUT-CHUNK %pad:%zu\n", &addr, chunk); 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci if (addr & 3) { 90162306a36Sopenharmony_ci char buf[3]; 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_ci chunk = min_t(size_t, chunk, (4-(addr&3))); 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci sg_pcopy_to_buffer(walk->sg, 1, buf, chunk, 90662306a36Sopenharmony_ci walk->offset); 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_ci ret = artpec6_crypto_setup_out_descr_short(common, buf, 90962306a36Sopenharmony_ci chunk, 91062306a36Sopenharmony_ci false); 91162306a36Sopenharmony_ci } else { 91262306a36Sopenharmony_ci dma_addr_t dma_addr; 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_ci ret = artpec6_crypto_dma_map_page(common, 91562306a36Sopenharmony_ci sg_page(walk->sg), 91662306a36Sopenharmony_ci walk->sg->offset + 91762306a36Sopenharmony_ci walk->offset, 91862306a36Sopenharmony_ci chunk, 91962306a36Sopenharmony_ci DMA_TO_DEVICE, 92062306a36Sopenharmony_ci &dma_addr); 92162306a36Sopenharmony_ci if (ret) 92262306a36Sopenharmony_ci return ret; 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_ci ret = artpec6_crypto_setup_out_descr_phys(common, 92562306a36Sopenharmony_ci dma_addr, 92662306a36Sopenharmony_ci chunk, false); 92762306a36Sopenharmony_ci } 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ci if (ret) 93062306a36Sopenharmony_ci return ret; 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_ci count = count - chunk; 93362306a36Sopenharmony_ci artpec6_crypto_walk_advance(walk, chunk); 93462306a36Sopenharmony_ci } 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_ci if (count) 93762306a36Sopenharmony_ci pr_err("EOL unexpected %zu bytes left\n", count); 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_ci return count ? -EINVAL : 0; 94062306a36Sopenharmony_ci} 94162306a36Sopenharmony_ci 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_ci/** artpec6_crypto_terminate_out_descrs - Set the EOP on the last out descriptor 94462306a36Sopenharmony_ci * 94562306a36Sopenharmony_ci * If the out descriptor list is non-empty, then the eop flag on the 94662306a36Sopenharmony_ci * last used out descriptor will be set. 94762306a36Sopenharmony_ci * 94862306a36Sopenharmony_ci * @return 0 on success 94962306a36Sopenharmony_ci * -EINVAL if the out descriptor is empty or has overflown 95062306a36Sopenharmony_ci */ 95162306a36Sopenharmony_cistatic int 95262306a36Sopenharmony_ciartpec6_crypto_terminate_out_descrs(struct artpec6_crypto_req_common *common) 95362306a36Sopenharmony_ci{ 95462306a36Sopenharmony_ci struct artpec6_crypto_dma_descriptors *dma = common->dma; 95562306a36Sopenharmony_ci struct pdma_descr *d; 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_ci if (!dma->out_cnt || dma->out_cnt > PDMA_DESCR_COUNT) { 95862306a36Sopenharmony_ci pr_err("%s: OUT descriptor list is %s\n", 95962306a36Sopenharmony_ci MODULE_NAME, dma->out_cnt ? "empty" : "full"); 96062306a36Sopenharmony_ci return -EINVAL; 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci } 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_ci d = &dma->out[dma->out_cnt-1]; 96562306a36Sopenharmony_ci d->ctrl.eop = 1; 96662306a36Sopenharmony_ci 96762306a36Sopenharmony_ci return 0; 96862306a36Sopenharmony_ci} 96962306a36Sopenharmony_ci 97062306a36Sopenharmony_ci/** artpec6_crypto_terminate_in_descrs - Set the interrupt flag on the last 97162306a36Sopenharmony_ci * in descriptor 97262306a36Sopenharmony_ci * 97362306a36Sopenharmony_ci * See artpec6_crypto_terminate_out_descrs() for return values 97462306a36Sopenharmony_ci */ 97562306a36Sopenharmony_cistatic int 97662306a36Sopenharmony_ciartpec6_crypto_terminate_in_descrs(struct artpec6_crypto_req_common *common) 97762306a36Sopenharmony_ci{ 97862306a36Sopenharmony_ci struct artpec6_crypto_dma_descriptors *dma = common->dma; 97962306a36Sopenharmony_ci struct pdma_descr *d; 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_ci if (!dma->in_cnt || dma->in_cnt > PDMA_DESCR_COUNT) { 98262306a36Sopenharmony_ci pr_err("%s: IN descriptor list is %s\n", 98362306a36Sopenharmony_ci MODULE_NAME, dma->in_cnt ? "empty" : "full"); 98462306a36Sopenharmony_ci return -EINVAL; 98562306a36Sopenharmony_ci } 98662306a36Sopenharmony_ci 98762306a36Sopenharmony_ci d = &dma->in[dma->in_cnt-1]; 98862306a36Sopenharmony_ci d->ctrl.intr = 1; 98962306a36Sopenharmony_ci return 0; 99062306a36Sopenharmony_ci} 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_ci/** create_hash_pad - Create a Secure Hash conformant pad 99362306a36Sopenharmony_ci * 99462306a36Sopenharmony_ci * @dst: The destination buffer to write the pad. Must be at least 64 bytes 99562306a36Sopenharmony_ci * @dgstlen: The total length of the hash digest in bytes 99662306a36Sopenharmony_ci * @bitcount: The total length of the digest in bits 99762306a36Sopenharmony_ci * 99862306a36Sopenharmony_ci * @return The total number of padding bytes written to @dst 99962306a36Sopenharmony_ci */ 100062306a36Sopenharmony_cistatic size_t 100162306a36Sopenharmony_cicreate_hash_pad(int oper, unsigned char *dst, u64 dgstlen, u64 bitcount) 100262306a36Sopenharmony_ci{ 100362306a36Sopenharmony_ci unsigned int mod, target, diff, pad_bytes, size_bytes; 100462306a36Sopenharmony_ci __be64 bits = __cpu_to_be64(bitcount); 100562306a36Sopenharmony_ci 100662306a36Sopenharmony_ci switch (oper) { 100762306a36Sopenharmony_ci case regk_crypto_sha1: 100862306a36Sopenharmony_ci case regk_crypto_sha256: 100962306a36Sopenharmony_ci case regk_crypto_hmac_sha1: 101062306a36Sopenharmony_ci case regk_crypto_hmac_sha256: 101162306a36Sopenharmony_ci target = 448 / 8; 101262306a36Sopenharmony_ci mod = 512 / 8; 101362306a36Sopenharmony_ci size_bytes = 8; 101462306a36Sopenharmony_ci break; 101562306a36Sopenharmony_ci default: 101662306a36Sopenharmony_ci target = 896 / 8; 101762306a36Sopenharmony_ci mod = 1024 / 8; 101862306a36Sopenharmony_ci size_bytes = 16; 101962306a36Sopenharmony_ci break; 102062306a36Sopenharmony_ci } 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_ci target -= 1; 102362306a36Sopenharmony_ci diff = dgstlen & (mod - 1); 102462306a36Sopenharmony_ci pad_bytes = diff > target ? target + mod - diff : target - diff; 102562306a36Sopenharmony_ci 102662306a36Sopenharmony_ci memset(dst + 1, 0, pad_bytes); 102762306a36Sopenharmony_ci dst[0] = 0x80; 102862306a36Sopenharmony_ci 102962306a36Sopenharmony_ci if (size_bytes == 16) { 103062306a36Sopenharmony_ci memset(dst + 1 + pad_bytes, 0, 8); 103162306a36Sopenharmony_ci memcpy(dst + 1 + pad_bytes + 8, &bits, 8); 103262306a36Sopenharmony_ci } else { 103362306a36Sopenharmony_ci memcpy(dst + 1 + pad_bytes, &bits, 8); 103462306a36Sopenharmony_ci } 103562306a36Sopenharmony_ci 103662306a36Sopenharmony_ci return pad_bytes + size_bytes + 1; 103762306a36Sopenharmony_ci} 103862306a36Sopenharmony_ci 103962306a36Sopenharmony_cistatic int artpec6_crypto_common_init(struct artpec6_crypto_req_common *common, 104062306a36Sopenharmony_ci struct crypto_async_request *parent, 104162306a36Sopenharmony_ci void (*complete)(struct crypto_async_request *req), 104262306a36Sopenharmony_ci struct scatterlist *dstsg, unsigned int nbytes) 104362306a36Sopenharmony_ci{ 104462306a36Sopenharmony_ci gfp_t flags; 104562306a36Sopenharmony_ci struct artpec6_crypto *ac = dev_get_drvdata(artpec6_crypto_dev); 104662306a36Sopenharmony_ci 104762306a36Sopenharmony_ci flags = (parent->flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? 104862306a36Sopenharmony_ci GFP_KERNEL : GFP_ATOMIC; 104962306a36Sopenharmony_ci 105062306a36Sopenharmony_ci common->gfp_flags = flags; 105162306a36Sopenharmony_ci common->dma = kmem_cache_alloc(ac->dma_cache, flags); 105262306a36Sopenharmony_ci if (!common->dma) 105362306a36Sopenharmony_ci return -ENOMEM; 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_ci common->req = parent; 105662306a36Sopenharmony_ci common->complete = complete; 105762306a36Sopenharmony_ci return 0; 105862306a36Sopenharmony_ci} 105962306a36Sopenharmony_ci 106062306a36Sopenharmony_cistatic void 106162306a36Sopenharmony_ciartpec6_crypto_bounce_destroy(struct artpec6_crypto_dma_descriptors *dma) 106262306a36Sopenharmony_ci{ 106362306a36Sopenharmony_ci struct artpec6_crypto_bounce_buffer *b; 106462306a36Sopenharmony_ci struct artpec6_crypto_bounce_buffer *next; 106562306a36Sopenharmony_ci 106662306a36Sopenharmony_ci list_for_each_entry_safe(b, next, &dma->bounce_buffers, list) { 106762306a36Sopenharmony_ci kfree(b); 106862306a36Sopenharmony_ci } 106962306a36Sopenharmony_ci} 107062306a36Sopenharmony_ci 107162306a36Sopenharmony_cistatic int 107262306a36Sopenharmony_ciartpec6_crypto_common_destroy(struct artpec6_crypto_req_common *common) 107362306a36Sopenharmony_ci{ 107462306a36Sopenharmony_ci struct artpec6_crypto *ac = dev_get_drvdata(artpec6_crypto_dev); 107562306a36Sopenharmony_ci 107662306a36Sopenharmony_ci artpec6_crypto_dma_unmap_all(common); 107762306a36Sopenharmony_ci artpec6_crypto_bounce_destroy(common->dma); 107862306a36Sopenharmony_ci kmem_cache_free(ac->dma_cache, common->dma); 107962306a36Sopenharmony_ci common->dma = NULL; 108062306a36Sopenharmony_ci return 0; 108162306a36Sopenharmony_ci} 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_ci/* 108462306a36Sopenharmony_ci * Ciphering functions. 108562306a36Sopenharmony_ci */ 108662306a36Sopenharmony_cistatic int artpec6_crypto_encrypt(struct skcipher_request *req) 108762306a36Sopenharmony_ci{ 108862306a36Sopenharmony_ci struct crypto_skcipher *cipher = crypto_skcipher_reqtfm(req); 108962306a36Sopenharmony_ci struct artpec6_cryptotfm_context *ctx = crypto_skcipher_ctx(cipher); 109062306a36Sopenharmony_ci struct artpec6_crypto_request_context *req_ctx = NULL; 109162306a36Sopenharmony_ci void (*complete)(struct crypto_async_request *req); 109262306a36Sopenharmony_ci int ret; 109362306a36Sopenharmony_ci 109462306a36Sopenharmony_ci req_ctx = skcipher_request_ctx(req); 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_ci switch (ctx->crypto_type) { 109762306a36Sopenharmony_ci case ARTPEC6_CRYPTO_CIPHER_AES_CBC: 109862306a36Sopenharmony_ci case ARTPEC6_CRYPTO_CIPHER_AES_ECB: 109962306a36Sopenharmony_ci case ARTPEC6_CRYPTO_CIPHER_AES_XTS: 110062306a36Sopenharmony_ci req_ctx->decrypt = 0; 110162306a36Sopenharmony_ci break; 110262306a36Sopenharmony_ci default: 110362306a36Sopenharmony_ci break; 110462306a36Sopenharmony_ci } 110562306a36Sopenharmony_ci 110662306a36Sopenharmony_ci switch (ctx->crypto_type) { 110762306a36Sopenharmony_ci case ARTPEC6_CRYPTO_CIPHER_AES_CBC: 110862306a36Sopenharmony_ci complete = artpec6_crypto_complete_cbc_encrypt; 110962306a36Sopenharmony_ci break; 111062306a36Sopenharmony_ci default: 111162306a36Sopenharmony_ci complete = artpec6_crypto_complete_crypto; 111262306a36Sopenharmony_ci break; 111362306a36Sopenharmony_ci } 111462306a36Sopenharmony_ci 111562306a36Sopenharmony_ci ret = artpec6_crypto_common_init(&req_ctx->common, 111662306a36Sopenharmony_ci &req->base, 111762306a36Sopenharmony_ci complete, 111862306a36Sopenharmony_ci req->dst, req->cryptlen); 111962306a36Sopenharmony_ci if (ret) 112062306a36Sopenharmony_ci return ret; 112162306a36Sopenharmony_ci 112262306a36Sopenharmony_ci ret = artpec6_crypto_prepare_crypto(req); 112362306a36Sopenharmony_ci if (ret) { 112462306a36Sopenharmony_ci artpec6_crypto_common_destroy(&req_ctx->common); 112562306a36Sopenharmony_ci return ret; 112662306a36Sopenharmony_ci } 112762306a36Sopenharmony_ci 112862306a36Sopenharmony_ci return artpec6_crypto_submit(&req_ctx->common); 112962306a36Sopenharmony_ci} 113062306a36Sopenharmony_ci 113162306a36Sopenharmony_cistatic int artpec6_crypto_decrypt(struct skcipher_request *req) 113262306a36Sopenharmony_ci{ 113362306a36Sopenharmony_ci int ret; 113462306a36Sopenharmony_ci struct crypto_skcipher *cipher = crypto_skcipher_reqtfm(req); 113562306a36Sopenharmony_ci struct artpec6_cryptotfm_context *ctx = crypto_skcipher_ctx(cipher); 113662306a36Sopenharmony_ci struct artpec6_crypto_request_context *req_ctx = NULL; 113762306a36Sopenharmony_ci void (*complete)(struct crypto_async_request *req); 113862306a36Sopenharmony_ci 113962306a36Sopenharmony_ci req_ctx = skcipher_request_ctx(req); 114062306a36Sopenharmony_ci 114162306a36Sopenharmony_ci switch (ctx->crypto_type) { 114262306a36Sopenharmony_ci case ARTPEC6_CRYPTO_CIPHER_AES_CBC: 114362306a36Sopenharmony_ci case ARTPEC6_CRYPTO_CIPHER_AES_ECB: 114462306a36Sopenharmony_ci case ARTPEC6_CRYPTO_CIPHER_AES_XTS: 114562306a36Sopenharmony_ci req_ctx->decrypt = 1; 114662306a36Sopenharmony_ci break; 114762306a36Sopenharmony_ci default: 114862306a36Sopenharmony_ci break; 114962306a36Sopenharmony_ci } 115062306a36Sopenharmony_ci 115162306a36Sopenharmony_ci 115262306a36Sopenharmony_ci switch (ctx->crypto_type) { 115362306a36Sopenharmony_ci case ARTPEC6_CRYPTO_CIPHER_AES_CBC: 115462306a36Sopenharmony_ci complete = artpec6_crypto_complete_cbc_decrypt; 115562306a36Sopenharmony_ci break; 115662306a36Sopenharmony_ci default: 115762306a36Sopenharmony_ci complete = artpec6_crypto_complete_crypto; 115862306a36Sopenharmony_ci break; 115962306a36Sopenharmony_ci } 116062306a36Sopenharmony_ci 116162306a36Sopenharmony_ci ret = artpec6_crypto_common_init(&req_ctx->common, &req->base, 116262306a36Sopenharmony_ci complete, 116362306a36Sopenharmony_ci req->dst, req->cryptlen); 116462306a36Sopenharmony_ci if (ret) 116562306a36Sopenharmony_ci return ret; 116662306a36Sopenharmony_ci 116762306a36Sopenharmony_ci ret = artpec6_crypto_prepare_crypto(req); 116862306a36Sopenharmony_ci if (ret) { 116962306a36Sopenharmony_ci artpec6_crypto_common_destroy(&req_ctx->common); 117062306a36Sopenharmony_ci return ret; 117162306a36Sopenharmony_ci } 117262306a36Sopenharmony_ci 117362306a36Sopenharmony_ci return artpec6_crypto_submit(&req_ctx->common); 117462306a36Sopenharmony_ci} 117562306a36Sopenharmony_ci 117662306a36Sopenharmony_cistatic int 117762306a36Sopenharmony_ciartpec6_crypto_ctr_crypt(struct skcipher_request *req, bool encrypt) 117862306a36Sopenharmony_ci{ 117962306a36Sopenharmony_ci struct crypto_skcipher *cipher = crypto_skcipher_reqtfm(req); 118062306a36Sopenharmony_ci struct artpec6_cryptotfm_context *ctx = crypto_skcipher_ctx(cipher); 118162306a36Sopenharmony_ci size_t iv_len = crypto_skcipher_ivsize(cipher); 118262306a36Sopenharmony_ci unsigned int counter = be32_to_cpup((__be32 *) 118362306a36Sopenharmony_ci (req->iv + iv_len - 4)); 118462306a36Sopenharmony_ci unsigned int nblks = ALIGN(req->cryptlen, AES_BLOCK_SIZE) / 118562306a36Sopenharmony_ci AES_BLOCK_SIZE; 118662306a36Sopenharmony_ci 118762306a36Sopenharmony_ci /* 118862306a36Sopenharmony_ci * The hardware uses only the last 32-bits as the counter while the 118962306a36Sopenharmony_ci * kernel tests (aes_ctr_enc_tv_template[4] for example) expect that 119062306a36Sopenharmony_ci * the whole IV is a counter. So fallback if the counter is going to 119162306a36Sopenharmony_ci * overlow. 119262306a36Sopenharmony_ci */ 119362306a36Sopenharmony_ci if (counter + nblks < counter) { 119462306a36Sopenharmony_ci int ret; 119562306a36Sopenharmony_ci 119662306a36Sopenharmony_ci pr_debug("counter %x will overflow (nblks %u), falling back\n", 119762306a36Sopenharmony_ci counter, counter + nblks); 119862306a36Sopenharmony_ci 119962306a36Sopenharmony_ci ret = crypto_sync_skcipher_setkey(ctx->fallback, ctx->aes_key, 120062306a36Sopenharmony_ci ctx->key_length); 120162306a36Sopenharmony_ci if (ret) 120262306a36Sopenharmony_ci return ret; 120362306a36Sopenharmony_ci 120462306a36Sopenharmony_ci { 120562306a36Sopenharmony_ci SYNC_SKCIPHER_REQUEST_ON_STACK(subreq, ctx->fallback); 120662306a36Sopenharmony_ci 120762306a36Sopenharmony_ci skcipher_request_set_sync_tfm(subreq, ctx->fallback); 120862306a36Sopenharmony_ci skcipher_request_set_callback(subreq, req->base.flags, 120962306a36Sopenharmony_ci NULL, NULL); 121062306a36Sopenharmony_ci skcipher_request_set_crypt(subreq, req->src, req->dst, 121162306a36Sopenharmony_ci req->cryptlen, req->iv); 121262306a36Sopenharmony_ci ret = encrypt ? crypto_skcipher_encrypt(subreq) 121362306a36Sopenharmony_ci : crypto_skcipher_decrypt(subreq); 121462306a36Sopenharmony_ci skcipher_request_zero(subreq); 121562306a36Sopenharmony_ci } 121662306a36Sopenharmony_ci return ret; 121762306a36Sopenharmony_ci } 121862306a36Sopenharmony_ci 121962306a36Sopenharmony_ci return encrypt ? artpec6_crypto_encrypt(req) 122062306a36Sopenharmony_ci : artpec6_crypto_decrypt(req); 122162306a36Sopenharmony_ci} 122262306a36Sopenharmony_ci 122362306a36Sopenharmony_cistatic int artpec6_crypto_ctr_encrypt(struct skcipher_request *req) 122462306a36Sopenharmony_ci{ 122562306a36Sopenharmony_ci return artpec6_crypto_ctr_crypt(req, true); 122662306a36Sopenharmony_ci} 122762306a36Sopenharmony_ci 122862306a36Sopenharmony_cistatic int artpec6_crypto_ctr_decrypt(struct skcipher_request *req) 122962306a36Sopenharmony_ci{ 123062306a36Sopenharmony_ci return artpec6_crypto_ctr_crypt(req, false); 123162306a36Sopenharmony_ci} 123262306a36Sopenharmony_ci 123362306a36Sopenharmony_ci/* 123462306a36Sopenharmony_ci * AEAD functions 123562306a36Sopenharmony_ci */ 123662306a36Sopenharmony_cistatic int artpec6_crypto_aead_init(struct crypto_aead *tfm) 123762306a36Sopenharmony_ci{ 123862306a36Sopenharmony_ci struct artpec6_cryptotfm_context *tfm_ctx = crypto_aead_ctx(tfm); 123962306a36Sopenharmony_ci 124062306a36Sopenharmony_ci memset(tfm_ctx, 0, sizeof(*tfm_ctx)); 124162306a36Sopenharmony_ci 124262306a36Sopenharmony_ci crypto_aead_set_reqsize(tfm, 124362306a36Sopenharmony_ci sizeof(struct artpec6_crypto_aead_req_ctx)); 124462306a36Sopenharmony_ci 124562306a36Sopenharmony_ci return 0; 124662306a36Sopenharmony_ci} 124762306a36Sopenharmony_ci 124862306a36Sopenharmony_cistatic int artpec6_crypto_aead_set_key(struct crypto_aead *tfm, const u8 *key, 124962306a36Sopenharmony_ci unsigned int len) 125062306a36Sopenharmony_ci{ 125162306a36Sopenharmony_ci struct artpec6_cryptotfm_context *ctx = crypto_tfm_ctx(&tfm->base); 125262306a36Sopenharmony_ci 125362306a36Sopenharmony_ci if (len != 16 && len != 24 && len != 32) 125462306a36Sopenharmony_ci return -EINVAL; 125562306a36Sopenharmony_ci 125662306a36Sopenharmony_ci ctx->key_length = len; 125762306a36Sopenharmony_ci 125862306a36Sopenharmony_ci memcpy(ctx->aes_key, key, len); 125962306a36Sopenharmony_ci return 0; 126062306a36Sopenharmony_ci} 126162306a36Sopenharmony_ci 126262306a36Sopenharmony_cistatic int artpec6_crypto_aead_encrypt(struct aead_request *req) 126362306a36Sopenharmony_ci{ 126462306a36Sopenharmony_ci int ret; 126562306a36Sopenharmony_ci struct artpec6_crypto_aead_req_ctx *req_ctx = aead_request_ctx(req); 126662306a36Sopenharmony_ci 126762306a36Sopenharmony_ci req_ctx->decrypt = false; 126862306a36Sopenharmony_ci ret = artpec6_crypto_common_init(&req_ctx->common, &req->base, 126962306a36Sopenharmony_ci artpec6_crypto_complete_aead, 127062306a36Sopenharmony_ci NULL, 0); 127162306a36Sopenharmony_ci if (ret) 127262306a36Sopenharmony_ci return ret; 127362306a36Sopenharmony_ci 127462306a36Sopenharmony_ci ret = artpec6_crypto_prepare_aead(req); 127562306a36Sopenharmony_ci if (ret) { 127662306a36Sopenharmony_ci artpec6_crypto_common_destroy(&req_ctx->common); 127762306a36Sopenharmony_ci return ret; 127862306a36Sopenharmony_ci } 127962306a36Sopenharmony_ci 128062306a36Sopenharmony_ci return artpec6_crypto_submit(&req_ctx->common); 128162306a36Sopenharmony_ci} 128262306a36Sopenharmony_ci 128362306a36Sopenharmony_cistatic int artpec6_crypto_aead_decrypt(struct aead_request *req) 128462306a36Sopenharmony_ci{ 128562306a36Sopenharmony_ci int ret; 128662306a36Sopenharmony_ci struct artpec6_crypto_aead_req_ctx *req_ctx = aead_request_ctx(req); 128762306a36Sopenharmony_ci 128862306a36Sopenharmony_ci req_ctx->decrypt = true; 128962306a36Sopenharmony_ci if (req->cryptlen < AES_BLOCK_SIZE) 129062306a36Sopenharmony_ci return -EINVAL; 129162306a36Sopenharmony_ci 129262306a36Sopenharmony_ci ret = artpec6_crypto_common_init(&req_ctx->common, 129362306a36Sopenharmony_ci &req->base, 129462306a36Sopenharmony_ci artpec6_crypto_complete_aead, 129562306a36Sopenharmony_ci NULL, 0); 129662306a36Sopenharmony_ci if (ret) 129762306a36Sopenharmony_ci return ret; 129862306a36Sopenharmony_ci 129962306a36Sopenharmony_ci ret = artpec6_crypto_prepare_aead(req); 130062306a36Sopenharmony_ci if (ret) { 130162306a36Sopenharmony_ci artpec6_crypto_common_destroy(&req_ctx->common); 130262306a36Sopenharmony_ci return ret; 130362306a36Sopenharmony_ci } 130462306a36Sopenharmony_ci 130562306a36Sopenharmony_ci return artpec6_crypto_submit(&req_ctx->common); 130662306a36Sopenharmony_ci} 130762306a36Sopenharmony_ci 130862306a36Sopenharmony_cistatic int artpec6_crypto_prepare_hash(struct ahash_request *areq) 130962306a36Sopenharmony_ci{ 131062306a36Sopenharmony_ci struct artpec6_hashalg_context *ctx = crypto_tfm_ctx(areq->base.tfm); 131162306a36Sopenharmony_ci struct artpec6_hash_request_context *req_ctx = ahash_request_ctx(areq); 131262306a36Sopenharmony_ci size_t digestsize = crypto_ahash_digestsize(crypto_ahash_reqtfm(areq)); 131362306a36Sopenharmony_ci size_t contextsize = digestsize; 131462306a36Sopenharmony_ci size_t blocksize = crypto_tfm_alg_blocksize( 131562306a36Sopenharmony_ci crypto_ahash_tfm(crypto_ahash_reqtfm(areq))); 131662306a36Sopenharmony_ci struct artpec6_crypto_req_common *common = &req_ctx->common; 131762306a36Sopenharmony_ci struct artpec6_crypto *ac = dev_get_drvdata(artpec6_crypto_dev); 131862306a36Sopenharmony_ci enum artpec6_crypto_variant variant = ac->variant; 131962306a36Sopenharmony_ci u32 sel_ctx; 132062306a36Sopenharmony_ci bool ext_ctx = false; 132162306a36Sopenharmony_ci bool run_hw = false; 132262306a36Sopenharmony_ci int error = 0; 132362306a36Sopenharmony_ci 132462306a36Sopenharmony_ci artpec6_crypto_init_dma_operation(common); 132562306a36Sopenharmony_ci 132662306a36Sopenharmony_ci /* Upload HMAC key, must be first the first packet */ 132762306a36Sopenharmony_ci if (req_ctx->hash_flags & HASH_FLAG_HMAC) { 132862306a36Sopenharmony_ci if (variant == ARTPEC6_CRYPTO) { 132962306a36Sopenharmony_ci req_ctx->key_md = FIELD_PREP(A6_CRY_MD_OPER, 133062306a36Sopenharmony_ci a6_regk_crypto_dlkey); 133162306a36Sopenharmony_ci } else { 133262306a36Sopenharmony_ci req_ctx->key_md = FIELD_PREP(A7_CRY_MD_OPER, 133362306a36Sopenharmony_ci a7_regk_crypto_dlkey); 133462306a36Sopenharmony_ci } 133562306a36Sopenharmony_ci 133662306a36Sopenharmony_ci /* Copy and pad up the key */ 133762306a36Sopenharmony_ci memcpy(req_ctx->key_buffer, ctx->hmac_key, 133862306a36Sopenharmony_ci ctx->hmac_key_length); 133962306a36Sopenharmony_ci memset(req_ctx->key_buffer + ctx->hmac_key_length, 0, 134062306a36Sopenharmony_ci blocksize - ctx->hmac_key_length); 134162306a36Sopenharmony_ci 134262306a36Sopenharmony_ci error = artpec6_crypto_setup_out_descr(common, 134362306a36Sopenharmony_ci (void *)&req_ctx->key_md, 134462306a36Sopenharmony_ci sizeof(req_ctx->key_md), false, false); 134562306a36Sopenharmony_ci if (error) 134662306a36Sopenharmony_ci return error; 134762306a36Sopenharmony_ci 134862306a36Sopenharmony_ci error = artpec6_crypto_setup_out_descr(common, 134962306a36Sopenharmony_ci req_ctx->key_buffer, blocksize, 135062306a36Sopenharmony_ci true, false); 135162306a36Sopenharmony_ci if (error) 135262306a36Sopenharmony_ci return error; 135362306a36Sopenharmony_ci } 135462306a36Sopenharmony_ci 135562306a36Sopenharmony_ci if (!(req_ctx->hash_flags & HASH_FLAG_INIT_CTX)) { 135662306a36Sopenharmony_ci /* Restore context */ 135762306a36Sopenharmony_ci sel_ctx = regk_crypto_ext; 135862306a36Sopenharmony_ci ext_ctx = true; 135962306a36Sopenharmony_ci } else { 136062306a36Sopenharmony_ci sel_ctx = regk_crypto_init; 136162306a36Sopenharmony_ci } 136262306a36Sopenharmony_ci 136362306a36Sopenharmony_ci if (variant == ARTPEC6_CRYPTO) { 136462306a36Sopenharmony_ci req_ctx->hash_md &= ~A6_CRY_MD_HASH_SEL_CTX; 136562306a36Sopenharmony_ci req_ctx->hash_md |= FIELD_PREP(A6_CRY_MD_HASH_SEL_CTX, sel_ctx); 136662306a36Sopenharmony_ci 136762306a36Sopenharmony_ci /* If this is the final round, set the final flag */ 136862306a36Sopenharmony_ci if (req_ctx->hash_flags & HASH_FLAG_FINALIZE) 136962306a36Sopenharmony_ci req_ctx->hash_md |= A6_CRY_MD_HASH_HMAC_FIN; 137062306a36Sopenharmony_ci } else { 137162306a36Sopenharmony_ci req_ctx->hash_md &= ~A7_CRY_MD_HASH_SEL_CTX; 137262306a36Sopenharmony_ci req_ctx->hash_md |= FIELD_PREP(A7_CRY_MD_HASH_SEL_CTX, sel_ctx); 137362306a36Sopenharmony_ci 137462306a36Sopenharmony_ci /* If this is the final round, set the final flag */ 137562306a36Sopenharmony_ci if (req_ctx->hash_flags & HASH_FLAG_FINALIZE) 137662306a36Sopenharmony_ci req_ctx->hash_md |= A7_CRY_MD_HASH_HMAC_FIN; 137762306a36Sopenharmony_ci } 137862306a36Sopenharmony_ci 137962306a36Sopenharmony_ci /* Setup up metadata descriptors */ 138062306a36Sopenharmony_ci error = artpec6_crypto_setup_out_descr(common, 138162306a36Sopenharmony_ci (void *)&req_ctx->hash_md, 138262306a36Sopenharmony_ci sizeof(req_ctx->hash_md), false, false); 138362306a36Sopenharmony_ci if (error) 138462306a36Sopenharmony_ci return error; 138562306a36Sopenharmony_ci 138662306a36Sopenharmony_ci error = artpec6_crypto_setup_in_descr(common, ac->pad_buffer, 4, false); 138762306a36Sopenharmony_ci if (error) 138862306a36Sopenharmony_ci return error; 138962306a36Sopenharmony_ci 139062306a36Sopenharmony_ci if (ext_ctx) { 139162306a36Sopenharmony_ci error = artpec6_crypto_setup_out_descr(common, 139262306a36Sopenharmony_ci req_ctx->digeststate, 139362306a36Sopenharmony_ci contextsize, false, false); 139462306a36Sopenharmony_ci 139562306a36Sopenharmony_ci if (error) 139662306a36Sopenharmony_ci return error; 139762306a36Sopenharmony_ci } 139862306a36Sopenharmony_ci 139962306a36Sopenharmony_ci if (req_ctx->hash_flags & HASH_FLAG_UPDATE) { 140062306a36Sopenharmony_ci size_t done_bytes = 0; 140162306a36Sopenharmony_ci size_t total_bytes = areq->nbytes + req_ctx->partial_bytes; 140262306a36Sopenharmony_ci size_t ready_bytes = round_down(total_bytes, blocksize); 140362306a36Sopenharmony_ci struct artpec6_crypto_walk walk; 140462306a36Sopenharmony_ci 140562306a36Sopenharmony_ci run_hw = ready_bytes > 0; 140662306a36Sopenharmony_ci if (req_ctx->partial_bytes && ready_bytes) { 140762306a36Sopenharmony_ci /* We have a partial buffer and will at least some bytes 140862306a36Sopenharmony_ci * to the HW. Empty this partial buffer before tackling 140962306a36Sopenharmony_ci * the SG lists 141062306a36Sopenharmony_ci */ 141162306a36Sopenharmony_ci memcpy(req_ctx->partial_buffer_out, 141262306a36Sopenharmony_ci req_ctx->partial_buffer, 141362306a36Sopenharmony_ci req_ctx->partial_bytes); 141462306a36Sopenharmony_ci 141562306a36Sopenharmony_ci error = artpec6_crypto_setup_out_descr(common, 141662306a36Sopenharmony_ci req_ctx->partial_buffer_out, 141762306a36Sopenharmony_ci req_ctx->partial_bytes, 141862306a36Sopenharmony_ci false, true); 141962306a36Sopenharmony_ci if (error) 142062306a36Sopenharmony_ci return error; 142162306a36Sopenharmony_ci 142262306a36Sopenharmony_ci /* Reset partial buffer */ 142362306a36Sopenharmony_ci done_bytes += req_ctx->partial_bytes; 142462306a36Sopenharmony_ci req_ctx->partial_bytes = 0; 142562306a36Sopenharmony_ci } 142662306a36Sopenharmony_ci 142762306a36Sopenharmony_ci artpec6_crypto_walk_init(&walk, areq->src); 142862306a36Sopenharmony_ci 142962306a36Sopenharmony_ci error = artpec6_crypto_setup_sg_descrs_out(common, &walk, 143062306a36Sopenharmony_ci ready_bytes - 143162306a36Sopenharmony_ci done_bytes); 143262306a36Sopenharmony_ci if (error) 143362306a36Sopenharmony_ci return error; 143462306a36Sopenharmony_ci 143562306a36Sopenharmony_ci if (walk.sg) { 143662306a36Sopenharmony_ci size_t sg_skip = ready_bytes - done_bytes; 143762306a36Sopenharmony_ci size_t sg_rem = areq->nbytes - sg_skip; 143862306a36Sopenharmony_ci 143962306a36Sopenharmony_ci sg_pcopy_to_buffer(areq->src, sg_nents(areq->src), 144062306a36Sopenharmony_ci req_ctx->partial_buffer + 144162306a36Sopenharmony_ci req_ctx->partial_bytes, 144262306a36Sopenharmony_ci sg_rem, sg_skip); 144362306a36Sopenharmony_ci 144462306a36Sopenharmony_ci req_ctx->partial_bytes += sg_rem; 144562306a36Sopenharmony_ci } 144662306a36Sopenharmony_ci 144762306a36Sopenharmony_ci req_ctx->digcnt += ready_bytes; 144862306a36Sopenharmony_ci req_ctx->hash_flags &= ~(HASH_FLAG_UPDATE); 144962306a36Sopenharmony_ci } 145062306a36Sopenharmony_ci 145162306a36Sopenharmony_ci /* Finalize */ 145262306a36Sopenharmony_ci if (req_ctx->hash_flags & HASH_FLAG_FINALIZE) { 145362306a36Sopenharmony_ci size_t hash_pad_len; 145462306a36Sopenharmony_ci u64 digest_bits; 145562306a36Sopenharmony_ci u32 oper; 145662306a36Sopenharmony_ci 145762306a36Sopenharmony_ci if (variant == ARTPEC6_CRYPTO) 145862306a36Sopenharmony_ci oper = FIELD_GET(A6_CRY_MD_OPER, req_ctx->hash_md); 145962306a36Sopenharmony_ci else 146062306a36Sopenharmony_ci oper = FIELD_GET(A7_CRY_MD_OPER, req_ctx->hash_md); 146162306a36Sopenharmony_ci 146262306a36Sopenharmony_ci /* Write out the partial buffer if present */ 146362306a36Sopenharmony_ci if (req_ctx->partial_bytes) { 146462306a36Sopenharmony_ci memcpy(req_ctx->partial_buffer_out, 146562306a36Sopenharmony_ci req_ctx->partial_buffer, 146662306a36Sopenharmony_ci req_ctx->partial_bytes); 146762306a36Sopenharmony_ci error = artpec6_crypto_setup_out_descr(common, 146862306a36Sopenharmony_ci req_ctx->partial_buffer_out, 146962306a36Sopenharmony_ci req_ctx->partial_bytes, 147062306a36Sopenharmony_ci false, true); 147162306a36Sopenharmony_ci if (error) 147262306a36Sopenharmony_ci return error; 147362306a36Sopenharmony_ci 147462306a36Sopenharmony_ci req_ctx->digcnt += req_ctx->partial_bytes; 147562306a36Sopenharmony_ci req_ctx->partial_bytes = 0; 147662306a36Sopenharmony_ci } 147762306a36Sopenharmony_ci 147862306a36Sopenharmony_ci if (req_ctx->hash_flags & HASH_FLAG_HMAC) 147962306a36Sopenharmony_ci digest_bits = 8 * (req_ctx->digcnt + blocksize); 148062306a36Sopenharmony_ci else 148162306a36Sopenharmony_ci digest_bits = 8 * req_ctx->digcnt; 148262306a36Sopenharmony_ci 148362306a36Sopenharmony_ci /* Add the hash pad */ 148462306a36Sopenharmony_ci hash_pad_len = create_hash_pad(oper, req_ctx->pad_buffer, 148562306a36Sopenharmony_ci req_ctx->digcnt, digest_bits); 148662306a36Sopenharmony_ci error = artpec6_crypto_setup_out_descr(common, 148762306a36Sopenharmony_ci req_ctx->pad_buffer, 148862306a36Sopenharmony_ci hash_pad_len, false, 148962306a36Sopenharmony_ci true); 149062306a36Sopenharmony_ci req_ctx->digcnt = 0; 149162306a36Sopenharmony_ci 149262306a36Sopenharmony_ci if (error) 149362306a36Sopenharmony_ci return error; 149462306a36Sopenharmony_ci 149562306a36Sopenharmony_ci /* Descriptor for the final result */ 149662306a36Sopenharmony_ci error = artpec6_crypto_setup_in_descr(common, areq->result, 149762306a36Sopenharmony_ci digestsize, 149862306a36Sopenharmony_ci true); 149962306a36Sopenharmony_ci if (error) 150062306a36Sopenharmony_ci return error; 150162306a36Sopenharmony_ci 150262306a36Sopenharmony_ci } else { /* This is not the final operation for this request */ 150362306a36Sopenharmony_ci if (!run_hw) 150462306a36Sopenharmony_ci return ARTPEC6_CRYPTO_PREPARE_HASH_NO_START; 150562306a36Sopenharmony_ci 150662306a36Sopenharmony_ci /* Save the result to the context */ 150762306a36Sopenharmony_ci error = artpec6_crypto_setup_in_descr(common, 150862306a36Sopenharmony_ci req_ctx->digeststate, 150962306a36Sopenharmony_ci contextsize, false); 151062306a36Sopenharmony_ci if (error) 151162306a36Sopenharmony_ci return error; 151262306a36Sopenharmony_ci /* fall through */ 151362306a36Sopenharmony_ci } 151462306a36Sopenharmony_ci 151562306a36Sopenharmony_ci req_ctx->hash_flags &= ~(HASH_FLAG_INIT_CTX | HASH_FLAG_UPDATE | 151662306a36Sopenharmony_ci HASH_FLAG_FINALIZE); 151762306a36Sopenharmony_ci 151862306a36Sopenharmony_ci error = artpec6_crypto_terminate_in_descrs(common); 151962306a36Sopenharmony_ci if (error) 152062306a36Sopenharmony_ci return error; 152162306a36Sopenharmony_ci 152262306a36Sopenharmony_ci error = artpec6_crypto_terminate_out_descrs(common); 152362306a36Sopenharmony_ci if (error) 152462306a36Sopenharmony_ci return error; 152562306a36Sopenharmony_ci 152662306a36Sopenharmony_ci error = artpec6_crypto_dma_map_descs(common); 152762306a36Sopenharmony_ci if (error) 152862306a36Sopenharmony_ci return error; 152962306a36Sopenharmony_ci 153062306a36Sopenharmony_ci return ARTPEC6_CRYPTO_PREPARE_HASH_START; 153162306a36Sopenharmony_ci} 153262306a36Sopenharmony_ci 153362306a36Sopenharmony_ci 153462306a36Sopenharmony_cistatic int artpec6_crypto_aes_ecb_init(struct crypto_skcipher *tfm) 153562306a36Sopenharmony_ci{ 153662306a36Sopenharmony_ci struct artpec6_cryptotfm_context *ctx = crypto_skcipher_ctx(tfm); 153762306a36Sopenharmony_ci 153862306a36Sopenharmony_ci tfm->reqsize = sizeof(struct artpec6_crypto_request_context); 153962306a36Sopenharmony_ci ctx->crypto_type = ARTPEC6_CRYPTO_CIPHER_AES_ECB; 154062306a36Sopenharmony_ci 154162306a36Sopenharmony_ci return 0; 154262306a36Sopenharmony_ci} 154362306a36Sopenharmony_ci 154462306a36Sopenharmony_cistatic int artpec6_crypto_aes_ctr_init(struct crypto_skcipher *tfm) 154562306a36Sopenharmony_ci{ 154662306a36Sopenharmony_ci struct artpec6_cryptotfm_context *ctx = crypto_skcipher_ctx(tfm); 154762306a36Sopenharmony_ci 154862306a36Sopenharmony_ci ctx->fallback = 154962306a36Sopenharmony_ci crypto_alloc_sync_skcipher(crypto_tfm_alg_name(&tfm->base), 155062306a36Sopenharmony_ci 0, CRYPTO_ALG_NEED_FALLBACK); 155162306a36Sopenharmony_ci if (IS_ERR(ctx->fallback)) 155262306a36Sopenharmony_ci return PTR_ERR(ctx->fallback); 155362306a36Sopenharmony_ci 155462306a36Sopenharmony_ci tfm->reqsize = sizeof(struct artpec6_crypto_request_context); 155562306a36Sopenharmony_ci ctx->crypto_type = ARTPEC6_CRYPTO_CIPHER_AES_CTR; 155662306a36Sopenharmony_ci 155762306a36Sopenharmony_ci return 0; 155862306a36Sopenharmony_ci} 155962306a36Sopenharmony_ci 156062306a36Sopenharmony_cistatic int artpec6_crypto_aes_cbc_init(struct crypto_skcipher *tfm) 156162306a36Sopenharmony_ci{ 156262306a36Sopenharmony_ci struct artpec6_cryptotfm_context *ctx = crypto_skcipher_ctx(tfm); 156362306a36Sopenharmony_ci 156462306a36Sopenharmony_ci tfm->reqsize = sizeof(struct artpec6_crypto_request_context); 156562306a36Sopenharmony_ci ctx->crypto_type = ARTPEC6_CRYPTO_CIPHER_AES_CBC; 156662306a36Sopenharmony_ci 156762306a36Sopenharmony_ci return 0; 156862306a36Sopenharmony_ci} 156962306a36Sopenharmony_ci 157062306a36Sopenharmony_cistatic int artpec6_crypto_aes_xts_init(struct crypto_skcipher *tfm) 157162306a36Sopenharmony_ci{ 157262306a36Sopenharmony_ci struct artpec6_cryptotfm_context *ctx = crypto_skcipher_ctx(tfm); 157362306a36Sopenharmony_ci 157462306a36Sopenharmony_ci tfm->reqsize = sizeof(struct artpec6_crypto_request_context); 157562306a36Sopenharmony_ci ctx->crypto_type = ARTPEC6_CRYPTO_CIPHER_AES_XTS; 157662306a36Sopenharmony_ci 157762306a36Sopenharmony_ci return 0; 157862306a36Sopenharmony_ci} 157962306a36Sopenharmony_ci 158062306a36Sopenharmony_cistatic void artpec6_crypto_aes_exit(struct crypto_skcipher *tfm) 158162306a36Sopenharmony_ci{ 158262306a36Sopenharmony_ci struct artpec6_cryptotfm_context *ctx = crypto_skcipher_ctx(tfm); 158362306a36Sopenharmony_ci 158462306a36Sopenharmony_ci memset(ctx, 0, sizeof(*ctx)); 158562306a36Sopenharmony_ci} 158662306a36Sopenharmony_ci 158762306a36Sopenharmony_cistatic void artpec6_crypto_aes_ctr_exit(struct crypto_skcipher *tfm) 158862306a36Sopenharmony_ci{ 158962306a36Sopenharmony_ci struct artpec6_cryptotfm_context *ctx = crypto_skcipher_ctx(tfm); 159062306a36Sopenharmony_ci 159162306a36Sopenharmony_ci crypto_free_sync_skcipher(ctx->fallback); 159262306a36Sopenharmony_ci artpec6_crypto_aes_exit(tfm); 159362306a36Sopenharmony_ci} 159462306a36Sopenharmony_ci 159562306a36Sopenharmony_cistatic int 159662306a36Sopenharmony_ciartpec6_crypto_cipher_set_key(struct crypto_skcipher *cipher, const u8 *key, 159762306a36Sopenharmony_ci unsigned int keylen) 159862306a36Sopenharmony_ci{ 159962306a36Sopenharmony_ci struct artpec6_cryptotfm_context *ctx = 160062306a36Sopenharmony_ci crypto_skcipher_ctx(cipher); 160162306a36Sopenharmony_ci 160262306a36Sopenharmony_ci switch (keylen) { 160362306a36Sopenharmony_ci case 16: 160462306a36Sopenharmony_ci case 24: 160562306a36Sopenharmony_ci case 32: 160662306a36Sopenharmony_ci break; 160762306a36Sopenharmony_ci default: 160862306a36Sopenharmony_ci return -EINVAL; 160962306a36Sopenharmony_ci } 161062306a36Sopenharmony_ci 161162306a36Sopenharmony_ci memcpy(ctx->aes_key, key, keylen); 161262306a36Sopenharmony_ci ctx->key_length = keylen; 161362306a36Sopenharmony_ci return 0; 161462306a36Sopenharmony_ci} 161562306a36Sopenharmony_ci 161662306a36Sopenharmony_cistatic int 161762306a36Sopenharmony_ciartpec6_crypto_xts_set_key(struct crypto_skcipher *cipher, const u8 *key, 161862306a36Sopenharmony_ci unsigned int keylen) 161962306a36Sopenharmony_ci{ 162062306a36Sopenharmony_ci struct artpec6_cryptotfm_context *ctx = 162162306a36Sopenharmony_ci crypto_skcipher_ctx(cipher); 162262306a36Sopenharmony_ci int ret; 162362306a36Sopenharmony_ci 162462306a36Sopenharmony_ci ret = xts_verify_key(cipher, key, keylen); 162562306a36Sopenharmony_ci if (ret) 162662306a36Sopenharmony_ci return ret; 162762306a36Sopenharmony_ci 162862306a36Sopenharmony_ci switch (keylen) { 162962306a36Sopenharmony_ci case 32: 163062306a36Sopenharmony_ci case 48: 163162306a36Sopenharmony_ci case 64: 163262306a36Sopenharmony_ci break; 163362306a36Sopenharmony_ci default: 163462306a36Sopenharmony_ci return -EINVAL; 163562306a36Sopenharmony_ci } 163662306a36Sopenharmony_ci 163762306a36Sopenharmony_ci memcpy(ctx->aes_key, key, keylen); 163862306a36Sopenharmony_ci ctx->key_length = keylen; 163962306a36Sopenharmony_ci return 0; 164062306a36Sopenharmony_ci} 164162306a36Sopenharmony_ci 164262306a36Sopenharmony_ci/** artpec6_crypto_process_crypto - Prepare an async block cipher crypto request 164362306a36Sopenharmony_ci * 164462306a36Sopenharmony_ci * @req: The asynch request to process 164562306a36Sopenharmony_ci * 164662306a36Sopenharmony_ci * @return 0 if the dma job was successfully prepared 164762306a36Sopenharmony_ci * <0 on error 164862306a36Sopenharmony_ci * 164962306a36Sopenharmony_ci * This function sets up the PDMA descriptors for a block cipher request. 165062306a36Sopenharmony_ci * 165162306a36Sopenharmony_ci * The required padding is added for AES-CTR using a statically defined 165262306a36Sopenharmony_ci * buffer. 165362306a36Sopenharmony_ci * 165462306a36Sopenharmony_ci * The PDMA descriptor list will be as follows: 165562306a36Sopenharmony_ci * 165662306a36Sopenharmony_ci * OUT: [KEY_MD][KEY][EOP]<CIPHER_MD>[IV]<data_0>...[data_n][AES-CTR_pad]<eop> 165762306a36Sopenharmony_ci * IN: <CIPHER_MD><data_0>...[data_n]<intr> 165862306a36Sopenharmony_ci * 165962306a36Sopenharmony_ci */ 166062306a36Sopenharmony_cistatic int artpec6_crypto_prepare_crypto(struct skcipher_request *areq) 166162306a36Sopenharmony_ci{ 166262306a36Sopenharmony_ci int ret; 166362306a36Sopenharmony_ci struct artpec6_crypto_walk walk; 166462306a36Sopenharmony_ci struct crypto_skcipher *cipher = crypto_skcipher_reqtfm(areq); 166562306a36Sopenharmony_ci struct artpec6_cryptotfm_context *ctx = crypto_skcipher_ctx(cipher); 166662306a36Sopenharmony_ci struct artpec6_crypto_request_context *req_ctx = NULL; 166762306a36Sopenharmony_ci size_t iv_len = crypto_skcipher_ivsize(cipher); 166862306a36Sopenharmony_ci struct artpec6_crypto *ac = dev_get_drvdata(artpec6_crypto_dev); 166962306a36Sopenharmony_ci enum artpec6_crypto_variant variant = ac->variant; 167062306a36Sopenharmony_ci struct artpec6_crypto_req_common *common; 167162306a36Sopenharmony_ci bool cipher_decr = false; 167262306a36Sopenharmony_ci size_t cipher_klen; 167362306a36Sopenharmony_ci u32 cipher_len = 0; /* Same as regk_crypto_key_128 for NULL crypto */ 167462306a36Sopenharmony_ci u32 oper; 167562306a36Sopenharmony_ci 167662306a36Sopenharmony_ci req_ctx = skcipher_request_ctx(areq); 167762306a36Sopenharmony_ci common = &req_ctx->common; 167862306a36Sopenharmony_ci 167962306a36Sopenharmony_ci artpec6_crypto_init_dma_operation(common); 168062306a36Sopenharmony_ci 168162306a36Sopenharmony_ci if (variant == ARTPEC6_CRYPTO) 168262306a36Sopenharmony_ci ctx->key_md = FIELD_PREP(A6_CRY_MD_OPER, a6_regk_crypto_dlkey); 168362306a36Sopenharmony_ci else 168462306a36Sopenharmony_ci ctx->key_md = FIELD_PREP(A7_CRY_MD_OPER, a7_regk_crypto_dlkey); 168562306a36Sopenharmony_ci 168662306a36Sopenharmony_ci ret = artpec6_crypto_setup_out_descr(common, (void *)&ctx->key_md, 168762306a36Sopenharmony_ci sizeof(ctx->key_md), false, false); 168862306a36Sopenharmony_ci if (ret) 168962306a36Sopenharmony_ci return ret; 169062306a36Sopenharmony_ci 169162306a36Sopenharmony_ci ret = artpec6_crypto_setup_out_descr(common, ctx->aes_key, 169262306a36Sopenharmony_ci ctx->key_length, true, false); 169362306a36Sopenharmony_ci if (ret) 169462306a36Sopenharmony_ci return ret; 169562306a36Sopenharmony_ci 169662306a36Sopenharmony_ci req_ctx->cipher_md = 0; 169762306a36Sopenharmony_ci 169862306a36Sopenharmony_ci if (ctx->crypto_type == ARTPEC6_CRYPTO_CIPHER_AES_XTS) 169962306a36Sopenharmony_ci cipher_klen = ctx->key_length/2; 170062306a36Sopenharmony_ci else 170162306a36Sopenharmony_ci cipher_klen = ctx->key_length; 170262306a36Sopenharmony_ci 170362306a36Sopenharmony_ci /* Metadata */ 170462306a36Sopenharmony_ci switch (cipher_klen) { 170562306a36Sopenharmony_ci case 16: 170662306a36Sopenharmony_ci cipher_len = regk_crypto_key_128; 170762306a36Sopenharmony_ci break; 170862306a36Sopenharmony_ci case 24: 170962306a36Sopenharmony_ci cipher_len = regk_crypto_key_192; 171062306a36Sopenharmony_ci break; 171162306a36Sopenharmony_ci case 32: 171262306a36Sopenharmony_ci cipher_len = regk_crypto_key_256; 171362306a36Sopenharmony_ci break; 171462306a36Sopenharmony_ci default: 171562306a36Sopenharmony_ci pr_err("%s: Invalid key length %zu!\n", 171662306a36Sopenharmony_ci MODULE_NAME, ctx->key_length); 171762306a36Sopenharmony_ci return -EINVAL; 171862306a36Sopenharmony_ci } 171962306a36Sopenharmony_ci 172062306a36Sopenharmony_ci switch (ctx->crypto_type) { 172162306a36Sopenharmony_ci case ARTPEC6_CRYPTO_CIPHER_AES_ECB: 172262306a36Sopenharmony_ci oper = regk_crypto_aes_ecb; 172362306a36Sopenharmony_ci cipher_decr = req_ctx->decrypt; 172462306a36Sopenharmony_ci break; 172562306a36Sopenharmony_ci 172662306a36Sopenharmony_ci case ARTPEC6_CRYPTO_CIPHER_AES_CBC: 172762306a36Sopenharmony_ci oper = regk_crypto_aes_cbc; 172862306a36Sopenharmony_ci cipher_decr = req_ctx->decrypt; 172962306a36Sopenharmony_ci break; 173062306a36Sopenharmony_ci 173162306a36Sopenharmony_ci case ARTPEC6_CRYPTO_CIPHER_AES_CTR: 173262306a36Sopenharmony_ci oper = regk_crypto_aes_ctr; 173362306a36Sopenharmony_ci cipher_decr = false; 173462306a36Sopenharmony_ci break; 173562306a36Sopenharmony_ci 173662306a36Sopenharmony_ci case ARTPEC6_CRYPTO_CIPHER_AES_XTS: 173762306a36Sopenharmony_ci oper = regk_crypto_aes_xts; 173862306a36Sopenharmony_ci cipher_decr = req_ctx->decrypt; 173962306a36Sopenharmony_ci 174062306a36Sopenharmony_ci if (variant == ARTPEC6_CRYPTO) 174162306a36Sopenharmony_ci req_ctx->cipher_md |= A6_CRY_MD_CIPHER_DSEQ; 174262306a36Sopenharmony_ci else 174362306a36Sopenharmony_ci req_ctx->cipher_md |= A7_CRY_MD_CIPHER_DSEQ; 174462306a36Sopenharmony_ci break; 174562306a36Sopenharmony_ci 174662306a36Sopenharmony_ci default: 174762306a36Sopenharmony_ci pr_err("%s: Invalid cipher mode %d!\n", 174862306a36Sopenharmony_ci MODULE_NAME, ctx->crypto_type); 174962306a36Sopenharmony_ci return -EINVAL; 175062306a36Sopenharmony_ci } 175162306a36Sopenharmony_ci 175262306a36Sopenharmony_ci if (variant == ARTPEC6_CRYPTO) { 175362306a36Sopenharmony_ci req_ctx->cipher_md |= FIELD_PREP(A6_CRY_MD_OPER, oper); 175462306a36Sopenharmony_ci req_ctx->cipher_md |= FIELD_PREP(A6_CRY_MD_CIPHER_LEN, 175562306a36Sopenharmony_ci cipher_len); 175662306a36Sopenharmony_ci if (cipher_decr) 175762306a36Sopenharmony_ci req_ctx->cipher_md |= A6_CRY_MD_CIPHER_DECR; 175862306a36Sopenharmony_ci } else { 175962306a36Sopenharmony_ci req_ctx->cipher_md |= FIELD_PREP(A7_CRY_MD_OPER, oper); 176062306a36Sopenharmony_ci req_ctx->cipher_md |= FIELD_PREP(A7_CRY_MD_CIPHER_LEN, 176162306a36Sopenharmony_ci cipher_len); 176262306a36Sopenharmony_ci if (cipher_decr) 176362306a36Sopenharmony_ci req_ctx->cipher_md |= A7_CRY_MD_CIPHER_DECR; 176462306a36Sopenharmony_ci } 176562306a36Sopenharmony_ci 176662306a36Sopenharmony_ci ret = artpec6_crypto_setup_out_descr(common, 176762306a36Sopenharmony_ci &req_ctx->cipher_md, 176862306a36Sopenharmony_ci sizeof(req_ctx->cipher_md), 176962306a36Sopenharmony_ci false, false); 177062306a36Sopenharmony_ci if (ret) 177162306a36Sopenharmony_ci return ret; 177262306a36Sopenharmony_ci 177362306a36Sopenharmony_ci ret = artpec6_crypto_setup_in_descr(common, ac->pad_buffer, 4, false); 177462306a36Sopenharmony_ci if (ret) 177562306a36Sopenharmony_ci return ret; 177662306a36Sopenharmony_ci 177762306a36Sopenharmony_ci if (iv_len) { 177862306a36Sopenharmony_ci ret = artpec6_crypto_setup_out_descr(common, areq->iv, iv_len, 177962306a36Sopenharmony_ci false, false); 178062306a36Sopenharmony_ci if (ret) 178162306a36Sopenharmony_ci return ret; 178262306a36Sopenharmony_ci } 178362306a36Sopenharmony_ci /* Data out */ 178462306a36Sopenharmony_ci artpec6_crypto_walk_init(&walk, areq->src); 178562306a36Sopenharmony_ci ret = artpec6_crypto_setup_sg_descrs_out(common, &walk, areq->cryptlen); 178662306a36Sopenharmony_ci if (ret) 178762306a36Sopenharmony_ci return ret; 178862306a36Sopenharmony_ci 178962306a36Sopenharmony_ci /* Data in */ 179062306a36Sopenharmony_ci artpec6_crypto_walk_init(&walk, areq->dst); 179162306a36Sopenharmony_ci ret = artpec6_crypto_setup_sg_descrs_in(common, &walk, areq->cryptlen); 179262306a36Sopenharmony_ci if (ret) 179362306a36Sopenharmony_ci return ret; 179462306a36Sopenharmony_ci 179562306a36Sopenharmony_ci /* CTR-mode padding required by the HW. */ 179662306a36Sopenharmony_ci if (ctx->crypto_type == ARTPEC6_CRYPTO_CIPHER_AES_CTR || 179762306a36Sopenharmony_ci ctx->crypto_type == ARTPEC6_CRYPTO_CIPHER_AES_XTS) { 179862306a36Sopenharmony_ci size_t pad = ALIGN(areq->cryptlen, AES_BLOCK_SIZE) - 179962306a36Sopenharmony_ci areq->cryptlen; 180062306a36Sopenharmony_ci 180162306a36Sopenharmony_ci if (pad) { 180262306a36Sopenharmony_ci ret = artpec6_crypto_setup_out_descr(common, 180362306a36Sopenharmony_ci ac->pad_buffer, 180462306a36Sopenharmony_ci pad, false, false); 180562306a36Sopenharmony_ci if (ret) 180662306a36Sopenharmony_ci return ret; 180762306a36Sopenharmony_ci 180862306a36Sopenharmony_ci ret = artpec6_crypto_setup_in_descr(common, 180962306a36Sopenharmony_ci ac->pad_buffer, pad, 181062306a36Sopenharmony_ci false); 181162306a36Sopenharmony_ci if (ret) 181262306a36Sopenharmony_ci return ret; 181362306a36Sopenharmony_ci } 181462306a36Sopenharmony_ci } 181562306a36Sopenharmony_ci 181662306a36Sopenharmony_ci ret = artpec6_crypto_terminate_out_descrs(common); 181762306a36Sopenharmony_ci if (ret) 181862306a36Sopenharmony_ci return ret; 181962306a36Sopenharmony_ci 182062306a36Sopenharmony_ci ret = artpec6_crypto_terminate_in_descrs(common); 182162306a36Sopenharmony_ci if (ret) 182262306a36Sopenharmony_ci return ret; 182362306a36Sopenharmony_ci 182462306a36Sopenharmony_ci return artpec6_crypto_dma_map_descs(common); 182562306a36Sopenharmony_ci} 182662306a36Sopenharmony_ci 182762306a36Sopenharmony_cistatic int artpec6_crypto_prepare_aead(struct aead_request *areq) 182862306a36Sopenharmony_ci{ 182962306a36Sopenharmony_ci size_t count; 183062306a36Sopenharmony_ci int ret; 183162306a36Sopenharmony_ci size_t input_length; 183262306a36Sopenharmony_ci struct artpec6_cryptotfm_context *ctx = crypto_tfm_ctx(areq->base.tfm); 183362306a36Sopenharmony_ci struct artpec6_crypto_aead_req_ctx *req_ctx = aead_request_ctx(areq); 183462306a36Sopenharmony_ci struct crypto_aead *cipher = crypto_aead_reqtfm(areq); 183562306a36Sopenharmony_ci struct artpec6_crypto_req_common *common = &req_ctx->common; 183662306a36Sopenharmony_ci struct artpec6_crypto *ac = dev_get_drvdata(artpec6_crypto_dev); 183762306a36Sopenharmony_ci enum artpec6_crypto_variant variant = ac->variant; 183862306a36Sopenharmony_ci u32 md_cipher_len; 183962306a36Sopenharmony_ci 184062306a36Sopenharmony_ci artpec6_crypto_init_dma_operation(common); 184162306a36Sopenharmony_ci 184262306a36Sopenharmony_ci /* Key */ 184362306a36Sopenharmony_ci if (variant == ARTPEC6_CRYPTO) { 184462306a36Sopenharmony_ci ctx->key_md = FIELD_PREP(A6_CRY_MD_OPER, 184562306a36Sopenharmony_ci a6_regk_crypto_dlkey); 184662306a36Sopenharmony_ci } else { 184762306a36Sopenharmony_ci ctx->key_md = FIELD_PREP(A7_CRY_MD_OPER, 184862306a36Sopenharmony_ci a7_regk_crypto_dlkey); 184962306a36Sopenharmony_ci } 185062306a36Sopenharmony_ci ret = artpec6_crypto_setup_out_descr(common, (void *)&ctx->key_md, 185162306a36Sopenharmony_ci sizeof(ctx->key_md), false, false); 185262306a36Sopenharmony_ci if (ret) 185362306a36Sopenharmony_ci return ret; 185462306a36Sopenharmony_ci 185562306a36Sopenharmony_ci ret = artpec6_crypto_setup_out_descr(common, ctx->aes_key, 185662306a36Sopenharmony_ci ctx->key_length, true, false); 185762306a36Sopenharmony_ci if (ret) 185862306a36Sopenharmony_ci return ret; 185962306a36Sopenharmony_ci 186062306a36Sopenharmony_ci req_ctx->cipher_md = 0; 186162306a36Sopenharmony_ci 186262306a36Sopenharmony_ci switch (ctx->key_length) { 186362306a36Sopenharmony_ci case 16: 186462306a36Sopenharmony_ci md_cipher_len = regk_crypto_key_128; 186562306a36Sopenharmony_ci break; 186662306a36Sopenharmony_ci case 24: 186762306a36Sopenharmony_ci md_cipher_len = regk_crypto_key_192; 186862306a36Sopenharmony_ci break; 186962306a36Sopenharmony_ci case 32: 187062306a36Sopenharmony_ci md_cipher_len = regk_crypto_key_256; 187162306a36Sopenharmony_ci break; 187262306a36Sopenharmony_ci default: 187362306a36Sopenharmony_ci return -EINVAL; 187462306a36Sopenharmony_ci } 187562306a36Sopenharmony_ci 187662306a36Sopenharmony_ci if (variant == ARTPEC6_CRYPTO) { 187762306a36Sopenharmony_ci req_ctx->cipher_md |= FIELD_PREP(A6_CRY_MD_OPER, 187862306a36Sopenharmony_ci regk_crypto_aes_gcm); 187962306a36Sopenharmony_ci req_ctx->cipher_md |= FIELD_PREP(A6_CRY_MD_CIPHER_LEN, 188062306a36Sopenharmony_ci md_cipher_len); 188162306a36Sopenharmony_ci if (req_ctx->decrypt) 188262306a36Sopenharmony_ci req_ctx->cipher_md |= A6_CRY_MD_CIPHER_DECR; 188362306a36Sopenharmony_ci } else { 188462306a36Sopenharmony_ci req_ctx->cipher_md |= FIELD_PREP(A7_CRY_MD_OPER, 188562306a36Sopenharmony_ci regk_crypto_aes_gcm); 188662306a36Sopenharmony_ci req_ctx->cipher_md |= FIELD_PREP(A7_CRY_MD_CIPHER_LEN, 188762306a36Sopenharmony_ci md_cipher_len); 188862306a36Sopenharmony_ci if (req_ctx->decrypt) 188962306a36Sopenharmony_ci req_ctx->cipher_md |= A7_CRY_MD_CIPHER_DECR; 189062306a36Sopenharmony_ci } 189162306a36Sopenharmony_ci 189262306a36Sopenharmony_ci ret = artpec6_crypto_setup_out_descr(common, 189362306a36Sopenharmony_ci (void *) &req_ctx->cipher_md, 189462306a36Sopenharmony_ci sizeof(req_ctx->cipher_md), false, 189562306a36Sopenharmony_ci false); 189662306a36Sopenharmony_ci if (ret) 189762306a36Sopenharmony_ci return ret; 189862306a36Sopenharmony_ci 189962306a36Sopenharmony_ci ret = artpec6_crypto_setup_in_descr(common, ac->pad_buffer, 4, false); 190062306a36Sopenharmony_ci if (ret) 190162306a36Sopenharmony_ci return ret; 190262306a36Sopenharmony_ci 190362306a36Sopenharmony_ci /* For the decryption, cryptlen includes the tag. */ 190462306a36Sopenharmony_ci input_length = areq->cryptlen; 190562306a36Sopenharmony_ci if (req_ctx->decrypt) 190662306a36Sopenharmony_ci input_length -= crypto_aead_authsize(cipher); 190762306a36Sopenharmony_ci 190862306a36Sopenharmony_ci /* Prepare the context buffer */ 190962306a36Sopenharmony_ci req_ctx->hw_ctx.aad_length_bits = 191062306a36Sopenharmony_ci __cpu_to_be64(8*areq->assoclen); 191162306a36Sopenharmony_ci 191262306a36Sopenharmony_ci req_ctx->hw_ctx.text_length_bits = 191362306a36Sopenharmony_ci __cpu_to_be64(8*input_length); 191462306a36Sopenharmony_ci 191562306a36Sopenharmony_ci memcpy(req_ctx->hw_ctx.J0, areq->iv, crypto_aead_ivsize(cipher)); 191662306a36Sopenharmony_ci // The HW omits the initial increment of the counter field. 191762306a36Sopenharmony_ci memcpy(req_ctx->hw_ctx.J0 + GCM_AES_IV_SIZE, "\x00\x00\x00\x01", 4); 191862306a36Sopenharmony_ci 191962306a36Sopenharmony_ci ret = artpec6_crypto_setup_out_descr(common, &req_ctx->hw_ctx, 192062306a36Sopenharmony_ci sizeof(struct artpec6_crypto_aead_hw_ctx), false, false); 192162306a36Sopenharmony_ci if (ret) 192262306a36Sopenharmony_ci return ret; 192362306a36Sopenharmony_ci 192462306a36Sopenharmony_ci { 192562306a36Sopenharmony_ci struct artpec6_crypto_walk walk; 192662306a36Sopenharmony_ci 192762306a36Sopenharmony_ci artpec6_crypto_walk_init(&walk, areq->src); 192862306a36Sopenharmony_ci 192962306a36Sopenharmony_ci /* Associated data */ 193062306a36Sopenharmony_ci count = areq->assoclen; 193162306a36Sopenharmony_ci ret = artpec6_crypto_setup_sg_descrs_out(common, &walk, count); 193262306a36Sopenharmony_ci if (ret) 193362306a36Sopenharmony_ci return ret; 193462306a36Sopenharmony_ci 193562306a36Sopenharmony_ci if (!IS_ALIGNED(areq->assoclen, 16)) { 193662306a36Sopenharmony_ci size_t assoc_pad = 16 - (areq->assoclen % 16); 193762306a36Sopenharmony_ci /* The HW mandates zero padding here */ 193862306a36Sopenharmony_ci ret = artpec6_crypto_setup_out_descr(common, 193962306a36Sopenharmony_ci ac->zero_buffer, 194062306a36Sopenharmony_ci assoc_pad, false, 194162306a36Sopenharmony_ci false); 194262306a36Sopenharmony_ci if (ret) 194362306a36Sopenharmony_ci return ret; 194462306a36Sopenharmony_ci } 194562306a36Sopenharmony_ci 194662306a36Sopenharmony_ci /* Data to crypto */ 194762306a36Sopenharmony_ci count = input_length; 194862306a36Sopenharmony_ci ret = artpec6_crypto_setup_sg_descrs_out(common, &walk, count); 194962306a36Sopenharmony_ci if (ret) 195062306a36Sopenharmony_ci return ret; 195162306a36Sopenharmony_ci 195262306a36Sopenharmony_ci if (!IS_ALIGNED(input_length, 16)) { 195362306a36Sopenharmony_ci size_t crypto_pad = 16 - (input_length % 16); 195462306a36Sopenharmony_ci /* The HW mandates zero padding here */ 195562306a36Sopenharmony_ci ret = artpec6_crypto_setup_out_descr(common, 195662306a36Sopenharmony_ci ac->zero_buffer, 195762306a36Sopenharmony_ci crypto_pad, 195862306a36Sopenharmony_ci false, 195962306a36Sopenharmony_ci false); 196062306a36Sopenharmony_ci if (ret) 196162306a36Sopenharmony_ci return ret; 196262306a36Sopenharmony_ci } 196362306a36Sopenharmony_ci } 196462306a36Sopenharmony_ci 196562306a36Sopenharmony_ci /* Data from crypto */ 196662306a36Sopenharmony_ci { 196762306a36Sopenharmony_ci struct artpec6_crypto_walk walk; 196862306a36Sopenharmony_ci size_t output_len = areq->cryptlen; 196962306a36Sopenharmony_ci 197062306a36Sopenharmony_ci if (req_ctx->decrypt) 197162306a36Sopenharmony_ci output_len -= crypto_aead_authsize(cipher); 197262306a36Sopenharmony_ci 197362306a36Sopenharmony_ci artpec6_crypto_walk_init(&walk, areq->dst); 197462306a36Sopenharmony_ci 197562306a36Sopenharmony_ci /* skip associated data in the output */ 197662306a36Sopenharmony_ci count = artpec6_crypto_walk_advance(&walk, areq->assoclen); 197762306a36Sopenharmony_ci if (count) 197862306a36Sopenharmony_ci return -EINVAL; 197962306a36Sopenharmony_ci 198062306a36Sopenharmony_ci count = output_len; 198162306a36Sopenharmony_ci ret = artpec6_crypto_setup_sg_descrs_in(common, &walk, count); 198262306a36Sopenharmony_ci if (ret) 198362306a36Sopenharmony_ci return ret; 198462306a36Sopenharmony_ci 198562306a36Sopenharmony_ci /* Put padding between the cryptotext and the auth tag */ 198662306a36Sopenharmony_ci if (!IS_ALIGNED(output_len, 16)) { 198762306a36Sopenharmony_ci size_t crypto_pad = 16 - (output_len % 16); 198862306a36Sopenharmony_ci 198962306a36Sopenharmony_ci ret = artpec6_crypto_setup_in_descr(common, 199062306a36Sopenharmony_ci ac->pad_buffer, 199162306a36Sopenharmony_ci crypto_pad, false); 199262306a36Sopenharmony_ci if (ret) 199362306a36Sopenharmony_ci return ret; 199462306a36Sopenharmony_ci } 199562306a36Sopenharmony_ci 199662306a36Sopenharmony_ci /* The authentication tag shall follow immediately after 199762306a36Sopenharmony_ci * the output ciphertext. For decryption it is put in a context 199862306a36Sopenharmony_ci * buffer for later compare against the input tag. 199962306a36Sopenharmony_ci */ 200062306a36Sopenharmony_ci 200162306a36Sopenharmony_ci if (req_ctx->decrypt) { 200262306a36Sopenharmony_ci ret = artpec6_crypto_setup_in_descr(common, 200362306a36Sopenharmony_ci req_ctx->decryption_tag, AES_BLOCK_SIZE, false); 200462306a36Sopenharmony_ci if (ret) 200562306a36Sopenharmony_ci return ret; 200662306a36Sopenharmony_ci 200762306a36Sopenharmony_ci } else { 200862306a36Sopenharmony_ci /* For encryption the requested tag size may be smaller 200962306a36Sopenharmony_ci * than the hardware's generated tag. 201062306a36Sopenharmony_ci */ 201162306a36Sopenharmony_ci size_t authsize = crypto_aead_authsize(cipher); 201262306a36Sopenharmony_ci 201362306a36Sopenharmony_ci ret = artpec6_crypto_setup_sg_descrs_in(common, &walk, 201462306a36Sopenharmony_ci authsize); 201562306a36Sopenharmony_ci if (ret) 201662306a36Sopenharmony_ci return ret; 201762306a36Sopenharmony_ci 201862306a36Sopenharmony_ci if (authsize < AES_BLOCK_SIZE) { 201962306a36Sopenharmony_ci count = AES_BLOCK_SIZE - authsize; 202062306a36Sopenharmony_ci ret = artpec6_crypto_setup_in_descr(common, 202162306a36Sopenharmony_ci ac->pad_buffer, 202262306a36Sopenharmony_ci count, false); 202362306a36Sopenharmony_ci if (ret) 202462306a36Sopenharmony_ci return ret; 202562306a36Sopenharmony_ci } 202662306a36Sopenharmony_ci } 202762306a36Sopenharmony_ci 202862306a36Sopenharmony_ci } 202962306a36Sopenharmony_ci 203062306a36Sopenharmony_ci ret = artpec6_crypto_terminate_in_descrs(common); 203162306a36Sopenharmony_ci if (ret) 203262306a36Sopenharmony_ci return ret; 203362306a36Sopenharmony_ci 203462306a36Sopenharmony_ci ret = artpec6_crypto_terminate_out_descrs(common); 203562306a36Sopenharmony_ci if (ret) 203662306a36Sopenharmony_ci return ret; 203762306a36Sopenharmony_ci 203862306a36Sopenharmony_ci return artpec6_crypto_dma_map_descs(common); 203962306a36Sopenharmony_ci} 204062306a36Sopenharmony_ci 204162306a36Sopenharmony_cistatic void artpec6_crypto_process_queue(struct artpec6_crypto *ac, 204262306a36Sopenharmony_ci struct list_head *completions) 204362306a36Sopenharmony_ci{ 204462306a36Sopenharmony_ci struct artpec6_crypto_req_common *req; 204562306a36Sopenharmony_ci 204662306a36Sopenharmony_ci while (!list_empty(&ac->queue) && !artpec6_crypto_busy()) { 204762306a36Sopenharmony_ci req = list_first_entry(&ac->queue, 204862306a36Sopenharmony_ci struct artpec6_crypto_req_common, 204962306a36Sopenharmony_ci list); 205062306a36Sopenharmony_ci list_move_tail(&req->list, &ac->pending); 205162306a36Sopenharmony_ci artpec6_crypto_start_dma(req); 205262306a36Sopenharmony_ci 205362306a36Sopenharmony_ci list_add_tail(&req->complete_in_progress, completions); 205462306a36Sopenharmony_ci } 205562306a36Sopenharmony_ci 205662306a36Sopenharmony_ci /* 205762306a36Sopenharmony_ci * In some cases, the hardware can raise an in_eop_flush interrupt 205862306a36Sopenharmony_ci * before actually updating the status, so we have an timer which will 205962306a36Sopenharmony_ci * recheck the status on timeout. Since the cases are expected to be 206062306a36Sopenharmony_ci * very rare, we use a relatively large timeout value. There should be 206162306a36Sopenharmony_ci * no noticeable negative effect if we timeout spuriously. 206262306a36Sopenharmony_ci */ 206362306a36Sopenharmony_ci if (ac->pending_count) 206462306a36Sopenharmony_ci mod_timer(&ac->timer, jiffies + msecs_to_jiffies(100)); 206562306a36Sopenharmony_ci else 206662306a36Sopenharmony_ci del_timer(&ac->timer); 206762306a36Sopenharmony_ci} 206862306a36Sopenharmony_ci 206962306a36Sopenharmony_cistatic void artpec6_crypto_timeout(struct timer_list *t) 207062306a36Sopenharmony_ci{ 207162306a36Sopenharmony_ci struct artpec6_crypto *ac = from_timer(ac, t, timer); 207262306a36Sopenharmony_ci 207362306a36Sopenharmony_ci dev_info_ratelimited(artpec6_crypto_dev, "timeout\n"); 207462306a36Sopenharmony_ci 207562306a36Sopenharmony_ci tasklet_schedule(&ac->task); 207662306a36Sopenharmony_ci} 207762306a36Sopenharmony_ci 207862306a36Sopenharmony_cistatic void artpec6_crypto_task(unsigned long data) 207962306a36Sopenharmony_ci{ 208062306a36Sopenharmony_ci struct artpec6_crypto *ac = (struct artpec6_crypto *)data; 208162306a36Sopenharmony_ci struct artpec6_crypto_req_common *req; 208262306a36Sopenharmony_ci struct artpec6_crypto_req_common *n; 208362306a36Sopenharmony_ci struct list_head complete_done; 208462306a36Sopenharmony_ci struct list_head complete_in_progress; 208562306a36Sopenharmony_ci 208662306a36Sopenharmony_ci INIT_LIST_HEAD(&complete_done); 208762306a36Sopenharmony_ci INIT_LIST_HEAD(&complete_in_progress); 208862306a36Sopenharmony_ci 208962306a36Sopenharmony_ci if (list_empty(&ac->pending)) { 209062306a36Sopenharmony_ci pr_debug("Spurious IRQ\n"); 209162306a36Sopenharmony_ci return; 209262306a36Sopenharmony_ci } 209362306a36Sopenharmony_ci 209462306a36Sopenharmony_ci spin_lock(&ac->queue_lock); 209562306a36Sopenharmony_ci 209662306a36Sopenharmony_ci list_for_each_entry_safe(req, n, &ac->pending, list) { 209762306a36Sopenharmony_ci struct artpec6_crypto_dma_descriptors *dma = req->dma; 209862306a36Sopenharmony_ci u32 stat; 209962306a36Sopenharmony_ci dma_addr_t stataddr; 210062306a36Sopenharmony_ci 210162306a36Sopenharmony_ci stataddr = dma->stat_dma_addr + 4 * (req->dma->in_cnt - 1); 210262306a36Sopenharmony_ci dma_sync_single_for_cpu(artpec6_crypto_dev, 210362306a36Sopenharmony_ci stataddr, 210462306a36Sopenharmony_ci 4, 210562306a36Sopenharmony_ci DMA_BIDIRECTIONAL); 210662306a36Sopenharmony_ci 210762306a36Sopenharmony_ci stat = req->dma->stat[req->dma->in_cnt-1]; 210862306a36Sopenharmony_ci 210962306a36Sopenharmony_ci /* A non-zero final status descriptor indicates 211062306a36Sopenharmony_ci * this job has finished. 211162306a36Sopenharmony_ci */ 211262306a36Sopenharmony_ci pr_debug("Request %p status is %X\n", req, stat); 211362306a36Sopenharmony_ci if (!stat) 211462306a36Sopenharmony_ci break; 211562306a36Sopenharmony_ci 211662306a36Sopenharmony_ci /* Allow testing of timeout handling with fault injection */ 211762306a36Sopenharmony_ci#ifdef CONFIG_FAULT_INJECTION 211862306a36Sopenharmony_ci if (should_fail(&artpec6_crypto_fail_status_read, 1)) 211962306a36Sopenharmony_ci continue; 212062306a36Sopenharmony_ci#endif 212162306a36Sopenharmony_ci 212262306a36Sopenharmony_ci pr_debug("Completing request %p\n", req); 212362306a36Sopenharmony_ci 212462306a36Sopenharmony_ci list_move_tail(&req->list, &complete_done); 212562306a36Sopenharmony_ci 212662306a36Sopenharmony_ci ac->pending_count--; 212762306a36Sopenharmony_ci } 212862306a36Sopenharmony_ci 212962306a36Sopenharmony_ci artpec6_crypto_process_queue(ac, &complete_in_progress); 213062306a36Sopenharmony_ci 213162306a36Sopenharmony_ci spin_unlock(&ac->queue_lock); 213262306a36Sopenharmony_ci 213362306a36Sopenharmony_ci /* Perform the completion callbacks without holding the queue lock 213462306a36Sopenharmony_ci * to allow new request submissions from the callbacks. 213562306a36Sopenharmony_ci */ 213662306a36Sopenharmony_ci list_for_each_entry_safe(req, n, &complete_done, list) { 213762306a36Sopenharmony_ci artpec6_crypto_dma_unmap_all(req); 213862306a36Sopenharmony_ci artpec6_crypto_copy_bounce_buffers(req); 213962306a36Sopenharmony_ci artpec6_crypto_common_destroy(req); 214062306a36Sopenharmony_ci 214162306a36Sopenharmony_ci req->complete(req->req); 214262306a36Sopenharmony_ci } 214362306a36Sopenharmony_ci 214462306a36Sopenharmony_ci list_for_each_entry_safe(req, n, &complete_in_progress, 214562306a36Sopenharmony_ci complete_in_progress) { 214662306a36Sopenharmony_ci crypto_request_complete(req->req, -EINPROGRESS); 214762306a36Sopenharmony_ci } 214862306a36Sopenharmony_ci} 214962306a36Sopenharmony_ci 215062306a36Sopenharmony_cistatic void artpec6_crypto_complete_crypto(struct crypto_async_request *req) 215162306a36Sopenharmony_ci{ 215262306a36Sopenharmony_ci crypto_request_complete(req, 0); 215362306a36Sopenharmony_ci} 215462306a36Sopenharmony_ci 215562306a36Sopenharmony_cistatic void 215662306a36Sopenharmony_ciartpec6_crypto_complete_cbc_decrypt(struct crypto_async_request *req) 215762306a36Sopenharmony_ci{ 215862306a36Sopenharmony_ci struct skcipher_request *cipher_req = container_of(req, 215962306a36Sopenharmony_ci struct skcipher_request, base); 216062306a36Sopenharmony_ci 216162306a36Sopenharmony_ci scatterwalk_map_and_copy(cipher_req->iv, cipher_req->src, 216262306a36Sopenharmony_ci cipher_req->cryptlen - AES_BLOCK_SIZE, 216362306a36Sopenharmony_ci AES_BLOCK_SIZE, 0); 216462306a36Sopenharmony_ci skcipher_request_complete(cipher_req, 0); 216562306a36Sopenharmony_ci} 216662306a36Sopenharmony_ci 216762306a36Sopenharmony_cistatic void 216862306a36Sopenharmony_ciartpec6_crypto_complete_cbc_encrypt(struct crypto_async_request *req) 216962306a36Sopenharmony_ci{ 217062306a36Sopenharmony_ci struct skcipher_request *cipher_req = container_of(req, 217162306a36Sopenharmony_ci struct skcipher_request, base); 217262306a36Sopenharmony_ci 217362306a36Sopenharmony_ci scatterwalk_map_and_copy(cipher_req->iv, cipher_req->dst, 217462306a36Sopenharmony_ci cipher_req->cryptlen - AES_BLOCK_SIZE, 217562306a36Sopenharmony_ci AES_BLOCK_SIZE, 0); 217662306a36Sopenharmony_ci skcipher_request_complete(cipher_req, 0); 217762306a36Sopenharmony_ci} 217862306a36Sopenharmony_ci 217962306a36Sopenharmony_cistatic void artpec6_crypto_complete_aead(struct crypto_async_request *req) 218062306a36Sopenharmony_ci{ 218162306a36Sopenharmony_ci int result = 0; 218262306a36Sopenharmony_ci 218362306a36Sopenharmony_ci /* Verify GCM hashtag. */ 218462306a36Sopenharmony_ci struct aead_request *areq = container_of(req, 218562306a36Sopenharmony_ci struct aead_request, base); 218662306a36Sopenharmony_ci struct crypto_aead *aead = crypto_aead_reqtfm(areq); 218762306a36Sopenharmony_ci struct artpec6_crypto_aead_req_ctx *req_ctx = aead_request_ctx(areq); 218862306a36Sopenharmony_ci 218962306a36Sopenharmony_ci if (req_ctx->decrypt) { 219062306a36Sopenharmony_ci u8 input_tag[AES_BLOCK_SIZE]; 219162306a36Sopenharmony_ci unsigned int authsize = crypto_aead_authsize(aead); 219262306a36Sopenharmony_ci 219362306a36Sopenharmony_ci sg_pcopy_to_buffer(areq->src, 219462306a36Sopenharmony_ci sg_nents(areq->src), 219562306a36Sopenharmony_ci input_tag, 219662306a36Sopenharmony_ci authsize, 219762306a36Sopenharmony_ci areq->assoclen + areq->cryptlen - 219862306a36Sopenharmony_ci authsize); 219962306a36Sopenharmony_ci 220062306a36Sopenharmony_ci if (crypto_memneq(req_ctx->decryption_tag, 220162306a36Sopenharmony_ci input_tag, 220262306a36Sopenharmony_ci authsize)) { 220362306a36Sopenharmony_ci pr_debug("***EBADMSG:\n"); 220462306a36Sopenharmony_ci print_hex_dump_debug("ref:", DUMP_PREFIX_ADDRESS, 32, 1, 220562306a36Sopenharmony_ci input_tag, authsize, true); 220662306a36Sopenharmony_ci print_hex_dump_debug("out:", DUMP_PREFIX_ADDRESS, 32, 1, 220762306a36Sopenharmony_ci req_ctx->decryption_tag, 220862306a36Sopenharmony_ci authsize, true); 220962306a36Sopenharmony_ci 221062306a36Sopenharmony_ci result = -EBADMSG; 221162306a36Sopenharmony_ci } 221262306a36Sopenharmony_ci } 221362306a36Sopenharmony_ci 221462306a36Sopenharmony_ci aead_request_complete(areq, result); 221562306a36Sopenharmony_ci} 221662306a36Sopenharmony_ci 221762306a36Sopenharmony_cistatic void artpec6_crypto_complete_hash(struct crypto_async_request *req) 221862306a36Sopenharmony_ci{ 221962306a36Sopenharmony_ci crypto_request_complete(req, 0); 222062306a36Sopenharmony_ci} 222162306a36Sopenharmony_ci 222262306a36Sopenharmony_ci 222362306a36Sopenharmony_ci/*------------------- Hash functions -----------------------------------------*/ 222462306a36Sopenharmony_cistatic int 222562306a36Sopenharmony_ciartpec6_crypto_hash_set_key(struct crypto_ahash *tfm, 222662306a36Sopenharmony_ci const u8 *key, unsigned int keylen) 222762306a36Sopenharmony_ci{ 222862306a36Sopenharmony_ci struct artpec6_hashalg_context *tfm_ctx = crypto_tfm_ctx(&tfm->base); 222962306a36Sopenharmony_ci size_t blocksize; 223062306a36Sopenharmony_ci int ret; 223162306a36Sopenharmony_ci 223262306a36Sopenharmony_ci if (!keylen) { 223362306a36Sopenharmony_ci pr_err("Invalid length (%d) of HMAC key\n", 223462306a36Sopenharmony_ci keylen); 223562306a36Sopenharmony_ci return -EINVAL; 223662306a36Sopenharmony_ci } 223762306a36Sopenharmony_ci 223862306a36Sopenharmony_ci memset(tfm_ctx->hmac_key, 0, sizeof(tfm_ctx->hmac_key)); 223962306a36Sopenharmony_ci 224062306a36Sopenharmony_ci blocksize = crypto_tfm_alg_blocksize(crypto_ahash_tfm(tfm)); 224162306a36Sopenharmony_ci 224262306a36Sopenharmony_ci if (keylen > blocksize) { 224362306a36Sopenharmony_ci tfm_ctx->hmac_key_length = blocksize; 224462306a36Sopenharmony_ci 224562306a36Sopenharmony_ci ret = crypto_shash_tfm_digest(tfm_ctx->child_hash, key, keylen, 224662306a36Sopenharmony_ci tfm_ctx->hmac_key); 224762306a36Sopenharmony_ci if (ret) 224862306a36Sopenharmony_ci return ret; 224962306a36Sopenharmony_ci } else { 225062306a36Sopenharmony_ci memcpy(tfm_ctx->hmac_key, key, keylen); 225162306a36Sopenharmony_ci tfm_ctx->hmac_key_length = keylen; 225262306a36Sopenharmony_ci } 225362306a36Sopenharmony_ci 225462306a36Sopenharmony_ci return 0; 225562306a36Sopenharmony_ci} 225662306a36Sopenharmony_ci 225762306a36Sopenharmony_cistatic int 225862306a36Sopenharmony_ciartpec6_crypto_init_hash(struct ahash_request *req, u8 type, int hmac) 225962306a36Sopenharmony_ci{ 226062306a36Sopenharmony_ci struct artpec6_crypto *ac = dev_get_drvdata(artpec6_crypto_dev); 226162306a36Sopenharmony_ci enum artpec6_crypto_variant variant = ac->variant; 226262306a36Sopenharmony_ci struct artpec6_hash_request_context *req_ctx = ahash_request_ctx(req); 226362306a36Sopenharmony_ci u32 oper; 226462306a36Sopenharmony_ci 226562306a36Sopenharmony_ci memset(req_ctx, 0, sizeof(*req_ctx)); 226662306a36Sopenharmony_ci 226762306a36Sopenharmony_ci req_ctx->hash_flags = HASH_FLAG_INIT_CTX; 226862306a36Sopenharmony_ci if (hmac) 226962306a36Sopenharmony_ci req_ctx->hash_flags |= (HASH_FLAG_HMAC | HASH_FLAG_UPDATE_KEY); 227062306a36Sopenharmony_ci 227162306a36Sopenharmony_ci switch (type) { 227262306a36Sopenharmony_ci case ARTPEC6_CRYPTO_HASH_SHA1: 227362306a36Sopenharmony_ci oper = hmac ? regk_crypto_hmac_sha1 : regk_crypto_sha1; 227462306a36Sopenharmony_ci break; 227562306a36Sopenharmony_ci case ARTPEC6_CRYPTO_HASH_SHA256: 227662306a36Sopenharmony_ci oper = hmac ? regk_crypto_hmac_sha256 : regk_crypto_sha256; 227762306a36Sopenharmony_ci break; 227862306a36Sopenharmony_ci default: 227962306a36Sopenharmony_ci pr_err("%s: Unsupported hash type 0x%x\n", MODULE_NAME, type); 228062306a36Sopenharmony_ci return -EINVAL; 228162306a36Sopenharmony_ci } 228262306a36Sopenharmony_ci 228362306a36Sopenharmony_ci if (variant == ARTPEC6_CRYPTO) 228462306a36Sopenharmony_ci req_ctx->hash_md = FIELD_PREP(A6_CRY_MD_OPER, oper); 228562306a36Sopenharmony_ci else 228662306a36Sopenharmony_ci req_ctx->hash_md = FIELD_PREP(A7_CRY_MD_OPER, oper); 228762306a36Sopenharmony_ci 228862306a36Sopenharmony_ci return 0; 228962306a36Sopenharmony_ci} 229062306a36Sopenharmony_ci 229162306a36Sopenharmony_cistatic int artpec6_crypto_prepare_submit_hash(struct ahash_request *req) 229262306a36Sopenharmony_ci{ 229362306a36Sopenharmony_ci struct artpec6_hash_request_context *req_ctx = ahash_request_ctx(req); 229462306a36Sopenharmony_ci int ret; 229562306a36Sopenharmony_ci 229662306a36Sopenharmony_ci if (!req_ctx->common.dma) { 229762306a36Sopenharmony_ci ret = artpec6_crypto_common_init(&req_ctx->common, 229862306a36Sopenharmony_ci &req->base, 229962306a36Sopenharmony_ci artpec6_crypto_complete_hash, 230062306a36Sopenharmony_ci NULL, 0); 230162306a36Sopenharmony_ci 230262306a36Sopenharmony_ci if (ret) 230362306a36Sopenharmony_ci return ret; 230462306a36Sopenharmony_ci } 230562306a36Sopenharmony_ci 230662306a36Sopenharmony_ci ret = artpec6_crypto_prepare_hash(req); 230762306a36Sopenharmony_ci switch (ret) { 230862306a36Sopenharmony_ci case ARTPEC6_CRYPTO_PREPARE_HASH_START: 230962306a36Sopenharmony_ci ret = artpec6_crypto_submit(&req_ctx->common); 231062306a36Sopenharmony_ci break; 231162306a36Sopenharmony_ci 231262306a36Sopenharmony_ci case ARTPEC6_CRYPTO_PREPARE_HASH_NO_START: 231362306a36Sopenharmony_ci ret = 0; 231462306a36Sopenharmony_ci fallthrough; 231562306a36Sopenharmony_ci 231662306a36Sopenharmony_ci default: 231762306a36Sopenharmony_ci artpec6_crypto_common_destroy(&req_ctx->common); 231862306a36Sopenharmony_ci break; 231962306a36Sopenharmony_ci } 232062306a36Sopenharmony_ci 232162306a36Sopenharmony_ci return ret; 232262306a36Sopenharmony_ci} 232362306a36Sopenharmony_ci 232462306a36Sopenharmony_cistatic int artpec6_crypto_hash_final(struct ahash_request *req) 232562306a36Sopenharmony_ci{ 232662306a36Sopenharmony_ci struct artpec6_hash_request_context *req_ctx = ahash_request_ctx(req); 232762306a36Sopenharmony_ci 232862306a36Sopenharmony_ci req_ctx->hash_flags |= HASH_FLAG_FINALIZE; 232962306a36Sopenharmony_ci 233062306a36Sopenharmony_ci return artpec6_crypto_prepare_submit_hash(req); 233162306a36Sopenharmony_ci} 233262306a36Sopenharmony_ci 233362306a36Sopenharmony_cistatic int artpec6_crypto_hash_update(struct ahash_request *req) 233462306a36Sopenharmony_ci{ 233562306a36Sopenharmony_ci struct artpec6_hash_request_context *req_ctx = ahash_request_ctx(req); 233662306a36Sopenharmony_ci 233762306a36Sopenharmony_ci req_ctx->hash_flags |= HASH_FLAG_UPDATE; 233862306a36Sopenharmony_ci 233962306a36Sopenharmony_ci return artpec6_crypto_prepare_submit_hash(req); 234062306a36Sopenharmony_ci} 234162306a36Sopenharmony_ci 234262306a36Sopenharmony_cistatic int artpec6_crypto_sha1_init(struct ahash_request *req) 234362306a36Sopenharmony_ci{ 234462306a36Sopenharmony_ci return artpec6_crypto_init_hash(req, ARTPEC6_CRYPTO_HASH_SHA1, 0); 234562306a36Sopenharmony_ci} 234662306a36Sopenharmony_ci 234762306a36Sopenharmony_cistatic int artpec6_crypto_sha1_digest(struct ahash_request *req) 234862306a36Sopenharmony_ci{ 234962306a36Sopenharmony_ci struct artpec6_hash_request_context *req_ctx = ahash_request_ctx(req); 235062306a36Sopenharmony_ci 235162306a36Sopenharmony_ci artpec6_crypto_init_hash(req, ARTPEC6_CRYPTO_HASH_SHA1, 0); 235262306a36Sopenharmony_ci 235362306a36Sopenharmony_ci req_ctx->hash_flags |= HASH_FLAG_UPDATE | HASH_FLAG_FINALIZE; 235462306a36Sopenharmony_ci 235562306a36Sopenharmony_ci return artpec6_crypto_prepare_submit_hash(req); 235662306a36Sopenharmony_ci} 235762306a36Sopenharmony_ci 235862306a36Sopenharmony_cistatic int artpec6_crypto_sha256_init(struct ahash_request *req) 235962306a36Sopenharmony_ci{ 236062306a36Sopenharmony_ci return artpec6_crypto_init_hash(req, ARTPEC6_CRYPTO_HASH_SHA256, 0); 236162306a36Sopenharmony_ci} 236262306a36Sopenharmony_ci 236362306a36Sopenharmony_cistatic int artpec6_crypto_sha256_digest(struct ahash_request *req) 236462306a36Sopenharmony_ci{ 236562306a36Sopenharmony_ci struct artpec6_hash_request_context *req_ctx = ahash_request_ctx(req); 236662306a36Sopenharmony_ci 236762306a36Sopenharmony_ci artpec6_crypto_init_hash(req, ARTPEC6_CRYPTO_HASH_SHA256, 0); 236862306a36Sopenharmony_ci req_ctx->hash_flags |= HASH_FLAG_UPDATE | HASH_FLAG_FINALIZE; 236962306a36Sopenharmony_ci 237062306a36Sopenharmony_ci return artpec6_crypto_prepare_submit_hash(req); 237162306a36Sopenharmony_ci} 237262306a36Sopenharmony_ci 237362306a36Sopenharmony_cistatic int artpec6_crypto_hmac_sha256_init(struct ahash_request *req) 237462306a36Sopenharmony_ci{ 237562306a36Sopenharmony_ci return artpec6_crypto_init_hash(req, ARTPEC6_CRYPTO_HASH_SHA256, 1); 237662306a36Sopenharmony_ci} 237762306a36Sopenharmony_ci 237862306a36Sopenharmony_cistatic int artpec6_crypto_hmac_sha256_digest(struct ahash_request *req) 237962306a36Sopenharmony_ci{ 238062306a36Sopenharmony_ci struct artpec6_hash_request_context *req_ctx = ahash_request_ctx(req); 238162306a36Sopenharmony_ci 238262306a36Sopenharmony_ci artpec6_crypto_init_hash(req, ARTPEC6_CRYPTO_HASH_SHA256, 1); 238362306a36Sopenharmony_ci req_ctx->hash_flags |= HASH_FLAG_UPDATE | HASH_FLAG_FINALIZE; 238462306a36Sopenharmony_ci 238562306a36Sopenharmony_ci return artpec6_crypto_prepare_submit_hash(req); 238662306a36Sopenharmony_ci} 238762306a36Sopenharmony_ci 238862306a36Sopenharmony_cistatic int artpec6_crypto_ahash_init_common(struct crypto_tfm *tfm, 238962306a36Sopenharmony_ci const char *base_hash_name) 239062306a36Sopenharmony_ci{ 239162306a36Sopenharmony_ci struct artpec6_hashalg_context *tfm_ctx = crypto_tfm_ctx(tfm); 239262306a36Sopenharmony_ci 239362306a36Sopenharmony_ci crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm), 239462306a36Sopenharmony_ci sizeof(struct artpec6_hash_request_context)); 239562306a36Sopenharmony_ci memset(tfm_ctx, 0, sizeof(*tfm_ctx)); 239662306a36Sopenharmony_ci 239762306a36Sopenharmony_ci if (base_hash_name) { 239862306a36Sopenharmony_ci struct crypto_shash *child; 239962306a36Sopenharmony_ci 240062306a36Sopenharmony_ci child = crypto_alloc_shash(base_hash_name, 0, 240162306a36Sopenharmony_ci CRYPTO_ALG_NEED_FALLBACK); 240262306a36Sopenharmony_ci 240362306a36Sopenharmony_ci if (IS_ERR(child)) 240462306a36Sopenharmony_ci return PTR_ERR(child); 240562306a36Sopenharmony_ci 240662306a36Sopenharmony_ci tfm_ctx->child_hash = child; 240762306a36Sopenharmony_ci } 240862306a36Sopenharmony_ci 240962306a36Sopenharmony_ci return 0; 241062306a36Sopenharmony_ci} 241162306a36Sopenharmony_ci 241262306a36Sopenharmony_cistatic int artpec6_crypto_ahash_init(struct crypto_tfm *tfm) 241362306a36Sopenharmony_ci{ 241462306a36Sopenharmony_ci return artpec6_crypto_ahash_init_common(tfm, NULL); 241562306a36Sopenharmony_ci} 241662306a36Sopenharmony_ci 241762306a36Sopenharmony_cistatic int artpec6_crypto_ahash_init_hmac_sha256(struct crypto_tfm *tfm) 241862306a36Sopenharmony_ci{ 241962306a36Sopenharmony_ci return artpec6_crypto_ahash_init_common(tfm, "sha256"); 242062306a36Sopenharmony_ci} 242162306a36Sopenharmony_ci 242262306a36Sopenharmony_cistatic void artpec6_crypto_ahash_exit(struct crypto_tfm *tfm) 242362306a36Sopenharmony_ci{ 242462306a36Sopenharmony_ci struct artpec6_hashalg_context *tfm_ctx = crypto_tfm_ctx(tfm); 242562306a36Sopenharmony_ci 242662306a36Sopenharmony_ci if (tfm_ctx->child_hash) 242762306a36Sopenharmony_ci crypto_free_shash(tfm_ctx->child_hash); 242862306a36Sopenharmony_ci 242962306a36Sopenharmony_ci memset(tfm_ctx->hmac_key, 0, sizeof(tfm_ctx->hmac_key)); 243062306a36Sopenharmony_ci tfm_ctx->hmac_key_length = 0; 243162306a36Sopenharmony_ci} 243262306a36Sopenharmony_ci 243362306a36Sopenharmony_cistatic int artpec6_crypto_hash_export(struct ahash_request *req, void *out) 243462306a36Sopenharmony_ci{ 243562306a36Sopenharmony_ci const struct artpec6_hash_request_context *ctx = ahash_request_ctx(req); 243662306a36Sopenharmony_ci struct artpec6_hash_export_state *state = out; 243762306a36Sopenharmony_ci struct artpec6_crypto *ac = dev_get_drvdata(artpec6_crypto_dev); 243862306a36Sopenharmony_ci enum artpec6_crypto_variant variant = ac->variant; 243962306a36Sopenharmony_ci 244062306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(state->partial_buffer) != 244162306a36Sopenharmony_ci sizeof(ctx->partial_buffer)); 244262306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(state->digeststate) != sizeof(ctx->digeststate)); 244362306a36Sopenharmony_ci 244462306a36Sopenharmony_ci state->digcnt = ctx->digcnt; 244562306a36Sopenharmony_ci state->partial_bytes = ctx->partial_bytes; 244662306a36Sopenharmony_ci state->hash_flags = ctx->hash_flags; 244762306a36Sopenharmony_ci 244862306a36Sopenharmony_ci if (variant == ARTPEC6_CRYPTO) 244962306a36Sopenharmony_ci state->oper = FIELD_GET(A6_CRY_MD_OPER, ctx->hash_md); 245062306a36Sopenharmony_ci else 245162306a36Sopenharmony_ci state->oper = FIELD_GET(A7_CRY_MD_OPER, ctx->hash_md); 245262306a36Sopenharmony_ci 245362306a36Sopenharmony_ci memcpy(state->partial_buffer, ctx->partial_buffer, 245462306a36Sopenharmony_ci sizeof(state->partial_buffer)); 245562306a36Sopenharmony_ci memcpy(state->digeststate, ctx->digeststate, 245662306a36Sopenharmony_ci sizeof(state->digeststate)); 245762306a36Sopenharmony_ci 245862306a36Sopenharmony_ci return 0; 245962306a36Sopenharmony_ci} 246062306a36Sopenharmony_ci 246162306a36Sopenharmony_cistatic int artpec6_crypto_hash_import(struct ahash_request *req, const void *in) 246262306a36Sopenharmony_ci{ 246362306a36Sopenharmony_ci struct artpec6_hash_request_context *ctx = ahash_request_ctx(req); 246462306a36Sopenharmony_ci const struct artpec6_hash_export_state *state = in; 246562306a36Sopenharmony_ci struct artpec6_crypto *ac = dev_get_drvdata(artpec6_crypto_dev); 246662306a36Sopenharmony_ci enum artpec6_crypto_variant variant = ac->variant; 246762306a36Sopenharmony_ci 246862306a36Sopenharmony_ci memset(ctx, 0, sizeof(*ctx)); 246962306a36Sopenharmony_ci 247062306a36Sopenharmony_ci ctx->digcnt = state->digcnt; 247162306a36Sopenharmony_ci ctx->partial_bytes = state->partial_bytes; 247262306a36Sopenharmony_ci ctx->hash_flags = state->hash_flags; 247362306a36Sopenharmony_ci 247462306a36Sopenharmony_ci if (variant == ARTPEC6_CRYPTO) 247562306a36Sopenharmony_ci ctx->hash_md = FIELD_PREP(A6_CRY_MD_OPER, state->oper); 247662306a36Sopenharmony_ci else 247762306a36Sopenharmony_ci ctx->hash_md = FIELD_PREP(A7_CRY_MD_OPER, state->oper); 247862306a36Sopenharmony_ci 247962306a36Sopenharmony_ci memcpy(ctx->partial_buffer, state->partial_buffer, 248062306a36Sopenharmony_ci sizeof(state->partial_buffer)); 248162306a36Sopenharmony_ci memcpy(ctx->digeststate, state->digeststate, 248262306a36Sopenharmony_ci sizeof(state->digeststate)); 248362306a36Sopenharmony_ci 248462306a36Sopenharmony_ci return 0; 248562306a36Sopenharmony_ci} 248662306a36Sopenharmony_ci 248762306a36Sopenharmony_cistatic int init_crypto_hw(struct artpec6_crypto *ac) 248862306a36Sopenharmony_ci{ 248962306a36Sopenharmony_ci enum artpec6_crypto_variant variant = ac->variant; 249062306a36Sopenharmony_ci void __iomem *base = ac->base; 249162306a36Sopenharmony_ci u32 out_descr_buf_size; 249262306a36Sopenharmony_ci u32 out_data_buf_size; 249362306a36Sopenharmony_ci u32 in_data_buf_size; 249462306a36Sopenharmony_ci u32 in_descr_buf_size; 249562306a36Sopenharmony_ci u32 in_stat_buf_size; 249662306a36Sopenharmony_ci u32 in, out; 249762306a36Sopenharmony_ci 249862306a36Sopenharmony_ci /* 249962306a36Sopenharmony_ci * The PDMA unit contains 1984 bytes of internal memory for the OUT 250062306a36Sopenharmony_ci * channels and 1024 bytes for the IN channel. This is an elastic 250162306a36Sopenharmony_ci * memory used to internally store the descriptors and data. The values 250262306a36Sopenharmony_ci * ares specified in 64 byte incremements. Trustzone buffers are not 250362306a36Sopenharmony_ci * used at this stage. 250462306a36Sopenharmony_ci */ 250562306a36Sopenharmony_ci out_data_buf_size = 16; /* 1024 bytes for data */ 250662306a36Sopenharmony_ci out_descr_buf_size = 15; /* 960 bytes for descriptors */ 250762306a36Sopenharmony_ci in_data_buf_size = 8; /* 512 bytes for data */ 250862306a36Sopenharmony_ci in_descr_buf_size = 4; /* 256 bytes for descriptors */ 250962306a36Sopenharmony_ci in_stat_buf_size = 4; /* 256 bytes for stat descrs */ 251062306a36Sopenharmony_ci 251162306a36Sopenharmony_ci BUILD_BUG_ON_MSG((out_data_buf_size 251262306a36Sopenharmony_ci + out_descr_buf_size) * 64 > 1984, 251362306a36Sopenharmony_ci "Invalid OUT configuration"); 251462306a36Sopenharmony_ci 251562306a36Sopenharmony_ci BUILD_BUG_ON_MSG((in_data_buf_size 251662306a36Sopenharmony_ci + in_descr_buf_size 251762306a36Sopenharmony_ci + in_stat_buf_size) * 64 > 1024, 251862306a36Sopenharmony_ci "Invalid IN configuration"); 251962306a36Sopenharmony_ci 252062306a36Sopenharmony_ci in = FIELD_PREP(PDMA_IN_BUF_CFG_DATA_BUF_SIZE, in_data_buf_size) | 252162306a36Sopenharmony_ci FIELD_PREP(PDMA_IN_BUF_CFG_DESCR_BUF_SIZE, in_descr_buf_size) | 252262306a36Sopenharmony_ci FIELD_PREP(PDMA_IN_BUF_CFG_STAT_BUF_SIZE, in_stat_buf_size); 252362306a36Sopenharmony_ci 252462306a36Sopenharmony_ci out = FIELD_PREP(PDMA_OUT_BUF_CFG_DATA_BUF_SIZE, out_data_buf_size) | 252562306a36Sopenharmony_ci FIELD_PREP(PDMA_OUT_BUF_CFG_DESCR_BUF_SIZE, out_descr_buf_size); 252662306a36Sopenharmony_ci 252762306a36Sopenharmony_ci writel_relaxed(out, base + PDMA_OUT_BUF_CFG); 252862306a36Sopenharmony_ci writel_relaxed(PDMA_OUT_CFG_EN, base + PDMA_OUT_CFG); 252962306a36Sopenharmony_ci 253062306a36Sopenharmony_ci if (variant == ARTPEC6_CRYPTO) { 253162306a36Sopenharmony_ci writel_relaxed(in, base + A6_PDMA_IN_BUF_CFG); 253262306a36Sopenharmony_ci writel_relaxed(PDMA_IN_CFG_EN, base + A6_PDMA_IN_CFG); 253362306a36Sopenharmony_ci writel_relaxed(A6_PDMA_INTR_MASK_IN_DATA | 253462306a36Sopenharmony_ci A6_PDMA_INTR_MASK_IN_EOP_FLUSH, 253562306a36Sopenharmony_ci base + A6_PDMA_INTR_MASK); 253662306a36Sopenharmony_ci } else { 253762306a36Sopenharmony_ci writel_relaxed(in, base + A7_PDMA_IN_BUF_CFG); 253862306a36Sopenharmony_ci writel_relaxed(PDMA_IN_CFG_EN, base + A7_PDMA_IN_CFG); 253962306a36Sopenharmony_ci writel_relaxed(A7_PDMA_INTR_MASK_IN_DATA | 254062306a36Sopenharmony_ci A7_PDMA_INTR_MASK_IN_EOP_FLUSH, 254162306a36Sopenharmony_ci base + A7_PDMA_INTR_MASK); 254262306a36Sopenharmony_ci } 254362306a36Sopenharmony_ci 254462306a36Sopenharmony_ci return 0; 254562306a36Sopenharmony_ci} 254662306a36Sopenharmony_ci 254762306a36Sopenharmony_cistatic void artpec6_crypto_disable_hw(struct artpec6_crypto *ac) 254862306a36Sopenharmony_ci{ 254962306a36Sopenharmony_ci enum artpec6_crypto_variant variant = ac->variant; 255062306a36Sopenharmony_ci void __iomem *base = ac->base; 255162306a36Sopenharmony_ci 255262306a36Sopenharmony_ci if (variant == ARTPEC6_CRYPTO) { 255362306a36Sopenharmony_ci writel_relaxed(A6_PDMA_IN_CMD_STOP, base + A6_PDMA_IN_CMD); 255462306a36Sopenharmony_ci writel_relaxed(0, base + A6_PDMA_IN_CFG); 255562306a36Sopenharmony_ci writel_relaxed(A6_PDMA_OUT_CMD_STOP, base + PDMA_OUT_CMD); 255662306a36Sopenharmony_ci } else { 255762306a36Sopenharmony_ci writel_relaxed(A7_PDMA_IN_CMD_STOP, base + A7_PDMA_IN_CMD); 255862306a36Sopenharmony_ci writel_relaxed(0, base + A7_PDMA_IN_CFG); 255962306a36Sopenharmony_ci writel_relaxed(A7_PDMA_OUT_CMD_STOP, base + PDMA_OUT_CMD); 256062306a36Sopenharmony_ci } 256162306a36Sopenharmony_ci 256262306a36Sopenharmony_ci writel_relaxed(0, base + PDMA_OUT_CFG); 256362306a36Sopenharmony_ci 256462306a36Sopenharmony_ci} 256562306a36Sopenharmony_ci 256662306a36Sopenharmony_cistatic irqreturn_t artpec6_crypto_irq(int irq, void *dev_id) 256762306a36Sopenharmony_ci{ 256862306a36Sopenharmony_ci struct artpec6_crypto *ac = dev_id; 256962306a36Sopenharmony_ci enum artpec6_crypto_variant variant = ac->variant; 257062306a36Sopenharmony_ci void __iomem *base = ac->base; 257162306a36Sopenharmony_ci u32 mask_in_data, mask_in_eop_flush; 257262306a36Sopenharmony_ci u32 in_cmd_flush_stat, in_cmd_reg; 257362306a36Sopenharmony_ci u32 ack_intr_reg; 257462306a36Sopenharmony_ci u32 ack = 0; 257562306a36Sopenharmony_ci u32 intr; 257662306a36Sopenharmony_ci 257762306a36Sopenharmony_ci if (variant == ARTPEC6_CRYPTO) { 257862306a36Sopenharmony_ci intr = readl_relaxed(base + A6_PDMA_MASKED_INTR); 257962306a36Sopenharmony_ci mask_in_data = A6_PDMA_INTR_MASK_IN_DATA; 258062306a36Sopenharmony_ci mask_in_eop_flush = A6_PDMA_INTR_MASK_IN_EOP_FLUSH; 258162306a36Sopenharmony_ci in_cmd_flush_stat = A6_PDMA_IN_CMD_FLUSH_STAT; 258262306a36Sopenharmony_ci in_cmd_reg = A6_PDMA_IN_CMD; 258362306a36Sopenharmony_ci ack_intr_reg = A6_PDMA_ACK_INTR; 258462306a36Sopenharmony_ci } else { 258562306a36Sopenharmony_ci intr = readl_relaxed(base + A7_PDMA_MASKED_INTR); 258662306a36Sopenharmony_ci mask_in_data = A7_PDMA_INTR_MASK_IN_DATA; 258762306a36Sopenharmony_ci mask_in_eop_flush = A7_PDMA_INTR_MASK_IN_EOP_FLUSH; 258862306a36Sopenharmony_ci in_cmd_flush_stat = A7_PDMA_IN_CMD_FLUSH_STAT; 258962306a36Sopenharmony_ci in_cmd_reg = A7_PDMA_IN_CMD; 259062306a36Sopenharmony_ci ack_intr_reg = A7_PDMA_ACK_INTR; 259162306a36Sopenharmony_ci } 259262306a36Sopenharmony_ci 259362306a36Sopenharmony_ci /* We get two interrupt notifications from each job. 259462306a36Sopenharmony_ci * The in_data means all data was sent to memory and then 259562306a36Sopenharmony_ci * we request a status flush command to write the per-job 259662306a36Sopenharmony_ci * status to its status vector. This ensures that the 259762306a36Sopenharmony_ci * tasklet can detect exactly how many submitted jobs 259862306a36Sopenharmony_ci * that have finished. 259962306a36Sopenharmony_ci */ 260062306a36Sopenharmony_ci if (intr & mask_in_data) 260162306a36Sopenharmony_ci ack |= mask_in_data; 260262306a36Sopenharmony_ci 260362306a36Sopenharmony_ci if (intr & mask_in_eop_flush) 260462306a36Sopenharmony_ci ack |= mask_in_eop_flush; 260562306a36Sopenharmony_ci else 260662306a36Sopenharmony_ci writel_relaxed(in_cmd_flush_stat, base + in_cmd_reg); 260762306a36Sopenharmony_ci 260862306a36Sopenharmony_ci writel_relaxed(ack, base + ack_intr_reg); 260962306a36Sopenharmony_ci 261062306a36Sopenharmony_ci if (intr & mask_in_eop_flush) 261162306a36Sopenharmony_ci tasklet_schedule(&ac->task); 261262306a36Sopenharmony_ci 261362306a36Sopenharmony_ci return IRQ_HANDLED; 261462306a36Sopenharmony_ci} 261562306a36Sopenharmony_ci 261662306a36Sopenharmony_ci/*------------------- Algorithm definitions ----------------------------------*/ 261762306a36Sopenharmony_ci 261862306a36Sopenharmony_ci/* Hashes */ 261962306a36Sopenharmony_cistatic struct ahash_alg hash_algos[] = { 262062306a36Sopenharmony_ci /* SHA-1 */ 262162306a36Sopenharmony_ci { 262262306a36Sopenharmony_ci .init = artpec6_crypto_sha1_init, 262362306a36Sopenharmony_ci .update = artpec6_crypto_hash_update, 262462306a36Sopenharmony_ci .final = artpec6_crypto_hash_final, 262562306a36Sopenharmony_ci .digest = artpec6_crypto_sha1_digest, 262662306a36Sopenharmony_ci .import = artpec6_crypto_hash_import, 262762306a36Sopenharmony_ci .export = artpec6_crypto_hash_export, 262862306a36Sopenharmony_ci .halg.digestsize = SHA1_DIGEST_SIZE, 262962306a36Sopenharmony_ci .halg.statesize = sizeof(struct artpec6_hash_export_state), 263062306a36Sopenharmony_ci .halg.base = { 263162306a36Sopenharmony_ci .cra_name = "sha1", 263262306a36Sopenharmony_ci .cra_driver_name = "artpec-sha1", 263362306a36Sopenharmony_ci .cra_priority = 300, 263462306a36Sopenharmony_ci .cra_flags = CRYPTO_ALG_ASYNC | 263562306a36Sopenharmony_ci CRYPTO_ALG_ALLOCATES_MEMORY, 263662306a36Sopenharmony_ci .cra_blocksize = SHA1_BLOCK_SIZE, 263762306a36Sopenharmony_ci .cra_ctxsize = sizeof(struct artpec6_hashalg_context), 263862306a36Sopenharmony_ci .cra_alignmask = 3, 263962306a36Sopenharmony_ci .cra_module = THIS_MODULE, 264062306a36Sopenharmony_ci .cra_init = artpec6_crypto_ahash_init, 264162306a36Sopenharmony_ci .cra_exit = artpec6_crypto_ahash_exit, 264262306a36Sopenharmony_ci } 264362306a36Sopenharmony_ci }, 264462306a36Sopenharmony_ci /* SHA-256 */ 264562306a36Sopenharmony_ci { 264662306a36Sopenharmony_ci .init = artpec6_crypto_sha256_init, 264762306a36Sopenharmony_ci .update = artpec6_crypto_hash_update, 264862306a36Sopenharmony_ci .final = artpec6_crypto_hash_final, 264962306a36Sopenharmony_ci .digest = artpec6_crypto_sha256_digest, 265062306a36Sopenharmony_ci .import = artpec6_crypto_hash_import, 265162306a36Sopenharmony_ci .export = artpec6_crypto_hash_export, 265262306a36Sopenharmony_ci .halg.digestsize = SHA256_DIGEST_SIZE, 265362306a36Sopenharmony_ci .halg.statesize = sizeof(struct artpec6_hash_export_state), 265462306a36Sopenharmony_ci .halg.base = { 265562306a36Sopenharmony_ci .cra_name = "sha256", 265662306a36Sopenharmony_ci .cra_driver_name = "artpec-sha256", 265762306a36Sopenharmony_ci .cra_priority = 300, 265862306a36Sopenharmony_ci .cra_flags = CRYPTO_ALG_ASYNC | 265962306a36Sopenharmony_ci CRYPTO_ALG_ALLOCATES_MEMORY, 266062306a36Sopenharmony_ci .cra_blocksize = SHA256_BLOCK_SIZE, 266162306a36Sopenharmony_ci .cra_ctxsize = sizeof(struct artpec6_hashalg_context), 266262306a36Sopenharmony_ci .cra_alignmask = 3, 266362306a36Sopenharmony_ci .cra_module = THIS_MODULE, 266462306a36Sopenharmony_ci .cra_init = artpec6_crypto_ahash_init, 266562306a36Sopenharmony_ci .cra_exit = artpec6_crypto_ahash_exit, 266662306a36Sopenharmony_ci } 266762306a36Sopenharmony_ci }, 266862306a36Sopenharmony_ci /* HMAC SHA-256 */ 266962306a36Sopenharmony_ci { 267062306a36Sopenharmony_ci .init = artpec6_crypto_hmac_sha256_init, 267162306a36Sopenharmony_ci .update = artpec6_crypto_hash_update, 267262306a36Sopenharmony_ci .final = artpec6_crypto_hash_final, 267362306a36Sopenharmony_ci .digest = artpec6_crypto_hmac_sha256_digest, 267462306a36Sopenharmony_ci .import = artpec6_crypto_hash_import, 267562306a36Sopenharmony_ci .export = artpec6_crypto_hash_export, 267662306a36Sopenharmony_ci .setkey = artpec6_crypto_hash_set_key, 267762306a36Sopenharmony_ci .halg.digestsize = SHA256_DIGEST_SIZE, 267862306a36Sopenharmony_ci .halg.statesize = sizeof(struct artpec6_hash_export_state), 267962306a36Sopenharmony_ci .halg.base = { 268062306a36Sopenharmony_ci .cra_name = "hmac(sha256)", 268162306a36Sopenharmony_ci .cra_driver_name = "artpec-hmac-sha256", 268262306a36Sopenharmony_ci .cra_priority = 300, 268362306a36Sopenharmony_ci .cra_flags = CRYPTO_ALG_ASYNC | 268462306a36Sopenharmony_ci CRYPTO_ALG_ALLOCATES_MEMORY, 268562306a36Sopenharmony_ci .cra_blocksize = SHA256_BLOCK_SIZE, 268662306a36Sopenharmony_ci .cra_ctxsize = sizeof(struct artpec6_hashalg_context), 268762306a36Sopenharmony_ci .cra_alignmask = 3, 268862306a36Sopenharmony_ci .cra_module = THIS_MODULE, 268962306a36Sopenharmony_ci .cra_init = artpec6_crypto_ahash_init_hmac_sha256, 269062306a36Sopenharmony_ci .cra_exit = artpec6_crypto_ahash_exit, 269162306a36Sopenharmony_ci } 269262306a36Sopenharmony_ci }, 269362306a36Sopenharmony_ci}; 269462306a36Sopenharmony_ci 269562306a36Sopenharmony_ci/* Crypto */ 269662306a36Sopenharmony_cistatic struct skcipher_alg crypto_algos[] = { 269762306a36Sopenharmony_ci /* AES - ECB */ 269862306a36Sopenharmony_ci { 269962306a36Sopenharmony_ci .base = { 270062306a36Sopenharmony_ci .cra_name = "ecb(aes)", 270162306a36Sopenharmony_ci .cra_driver_name = "artpec6-ecb-aes", 270262306a36Sopenharmony_ci .cra_priority = 300, 270362306a36Sopenharmony_ci .cra_flags = CRYPTO_ALG_ASYNC | 270462306a36Sopenharmony_ci CRYPTO_ALG_ALLOCATES_MEMORY, 270562306a36Sopenharmony_ci .cra_blocksize = AES_BLOCK_SIZE, 270662306a36Sopenharmony_ci .cra_ctxsize = sizeof(struct artpec6_cryptotfm_context), 270762306a36Sopenharmony_ci .cra_alignmask = 3, 270862306a36Sopenharmony_ci .cra_module = THIS_MODULE, 270962306a36Sopenharmony_ci }, 271062306a36Sopenharmony_ci .min_keysize = AES_MIN_KEY_SIZE, 271162306a36Sopenharmony_ci .max_keysize = AES_MAX_KEY_SIZE, 271262306a36Sopenharmony_ci .setkey = artpec6_crypto_cipher_set_key, 271362306a36Sopenharmony_ci .encrypt = artpec6_crypto_encrypt, 271462306a36Sopenharmony_ci .decrypt = artpec6_crypto_decrypt, 271562306a36Sopenharmony_ci .init = artpec6_crypto_aes_ecb_init, 271662306a36Sopenharmony_ci .exit = artpec6_crypto_aes_exit, 271762306a36Sopenharmony_ci }, 271862306a36Sopenharmony_ci /* AES - CTR */ 271962306a36Sopenharmony_ci { 272062306a36Sopenharmony_ci .base = { 272162306a36Sopenharmony_ci .cra_name = "ctr(aes)", 272262306a36Sopenharmony_ci .cra_driver_name = "artpec6-ctr-aes", 272362306a36Sopenharmony_ci .cra_priority = 300, 272462306a36Sopenharmony_ci .cra_flags = CRYPTO_ALG_ASYNC | 272562306a36Sopenharmony_ci CRYPTO_ALG_ALLOCATES_MEMORY | 272662306a36Sopenharmony_ci CRYPTO_ALG_NEED_FALLBACK, 272762306a36Sopenharmony_ci .cra_blocksize = 1, 272862306a36Sopenharmony_ci .cra_ctxsize = sizeof(struct artpec6_cryptotfm_context), 272962306a36Sopenharmony_ci .cra_alignmask = 3, 273062306a36Sopenharmony_ci .cra_module = THIS_MODULE, 273162306a36Sopenharmony_ci }, 273262306a36Sopenharmony_ci .min_keysize = AES_MIN_KEY_SIZE, 273362306a36Sopenharmony_ci .max_keysize = AES_MAX_KEY_SIZE, 273462306a36Sopenharmony_ci .ivsize = AES_BLOCK_SIZE, 273562306a36Sopenharmony_ci .setkey = artpec6_crypto_cipher_set_key, 273662306a36Sopenharmony_ci .encrypt = artpec6_crypto_ctr_encrypt, 273762306a36Sopenharmony_ci .decrypt = artpec6_crypto_ctr_decrypt, 273862306a36Sopenharmony_ci .init = artpec6_crypto_aes_ctr_init, 273962306a36Sopenharmony_ci .exit = artpec6_crypto_aes_ctr_exit, 274062306a36Sopenharmony_ci }, 274162306a36Sopenharmony_ci /* AES - CBC */ 274262306a36Sopenharmony_ci { 274362306a36Sopenharmony_ci .base = { 274462306a36Sopenharmony_ci .cra_name = "cbc(aes)", 274562306a36Sopenharmony_ci .cra_driver_name = "artpec6-cbc-aes", 274662306a36Sopenharmony_ci .cra_priority = 300, 274762306a36Sopenharmony_ci .cra_flags = CRYPTO_ALG_ASYNC | 274862306a36Sopenharmony_ci CRYPTO_ALG_ALLOCATES_MEMORY, 274962306a36Sopenharmony_ci .cra_blocksize = AES_BLOCK_SIZE, 275062306a36Sopenharmony_ci .cra_ctxsize = sizeof(struct artpec6_cryptotfm_context), 275162306a36Sopenharmony_ci .cra_alignmask = 3, 275262306a36Sopenharmony_ci .cra_module = THIS_MODULE, 275362306a36Sopenharmony_ci }, 275462306a36Sopenharmony_ci .min_keysize = AES_MIN_KEY_SIZE, 275562306a36Sopenharmony_ci .max_keysize = AES_MAX_KEY_SIZE, 275662306a36Sopenharmony_ci .ivsize = AES_BLOCK_SIZE, 275762306a36Sopenharmony_ci .setkey = artpec6_crypto_cipher_set_key, 275862306a36Sopenharmony_ci .encrypt = artpec6_crypto_encrypt, 275962306a36Sopenharmony_ci .decrypt = artpec6_crypto_decrypt, 276062306a36Sopenharmony_ci .init = artpec6_crypto_aes_cbc_init, 276162306a36Sopenharmony_ci .exit = artpec6_crypto_aes_exit 276262306a36Sopenharmony_ci }, 276362306a36Sopenharmony_ci /* AES - XTS */ 276462306a36Sopenharmony_ci { 276562306a36Sopenharmony_ci .base = { 276662306a36Sopenharmony_ci .cra_name = "xts(aes)", 276762306a36Sopenharmony_ci .cra_driver_name = "artpec6-xts-aes", 276862306a36Sopenharmony_ci .cra_priority = 300, 276962306a36Sopenharmony_ci .cra_flags = CRYPTO_ALG_ASYNC | 277062306a36Sopenharmony_ci CRYPTO_ALG_ALLOCATES_MEMORY, 277162306a36Sopenharmony_ci .cra_blocksize = 1, 277262306a36Sopenharmony_ci .cra_ctxsize = sizeof(struct artpec6_cryptotfm_context), 277362306a36Sopenharmony_ci .cra_alignmask = 3, 277462306a36Sopenharmony_ci .cra_module = THIS_MODULE, 277562306a36Sopenharmony_ci }, 277662306a36Sopenharmony_ci .min_keysize = 2*AES_MIN_KEY_SIZE, 277762306a36Sopenharmony_ci .max_keysize = 2*AES_MAX_KEY_SIZE, 277862306a36Sopenharmony_ci .ivsize = 16, 277962306a36Sopenharmony_ci .setkey = artpec6_crypto_xts_set_key, 278062306a36Sopenharmony_ci .encrypt = artpec6_crypto_encrypt, 278162306a36Sopenharmony_ci .decrypt = artpec6_crypto_decrypt, 278262306a36Sopenharmony_ci .init = artpec6_crypto_aes_xts_init, 278362306a36Sopenharmony_ci .exit = artpec6_crypto_aes_exit, 278462306a36Sopenharmony_ci }, 278562306a36Sopenharmony_ci}; 278662306a36Sopenharmony_ci 278762306a36Sopenharmony_cistatic struct aead_alg aead_algos[] = { 278862306a36Sopenharmony_ci { 278962306a36Sopenharmony_ci .init = artpec6_crypto_aead_init, 279062306a36Sopenharmony_ci .setkey = artpec6_crypto_aead_set_key, 279162306a36Sopenharmony_ci .encrypt = artpec6_crypto_aead_encrypt, 279262306a36Sopenharmony_ci .decrypt = artpec6_crypto_aead_decrypt, 279362306a36Sopenharmony_ci .ivsize = GCM_AES_IV_SIZE, 279462306a36Sopenharmony_ci .maxauthsize = AES_BLOCK_SIZE, 279562306a36Sopenharmony_ci 279662306a36Sopenharmony_ci .base = { 279762306a36Sopenharmony_ci .cra_name = "gcm(aes)", 279862306a36Sopenharmony_ci .cra_driver_name = "artpec-gcm-aes", 279962306a36Sopenharmony_ci .cra_priority = 300, 280062306a36Sopenharmony_ci .cra_flags = CRYPTO_ALG_ASYNC | 280162306a36Sopenharmony_ci CRYPTO_ALG_ALLOCATES_MEMORY | 280262306a36Sopenharmony_ci CRYPTO_ALG_KERN_DRIVER_ONLY, 280362306a36Sopenharmony_ci .cra_blocksize = 1, 280462306a36Sopenharmony_ci .cra_ctxsize = sizeof(struct artpec6_cryptotfm_context), 280562306a36Sopenharmony_ci .cra_alignmask = 3, 280662306a36Sopenharmony_ci .cra_module = THIS_MODULE, 280762306a36Sopenharmony_ci }, 280862306a36Sopenharmony_ci } 280962306a36Sopenharmony_ci}; 281062306a36Sopenharmony_ci 281162306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 281262306a36Sopenharmony_ci 281362306a36Sopenharmony_cistruct dbgfs_u32 { 281462306a36Sopenharmony_ci char *name; 281562306a36Sopenharmony_ci mode_t mode; 281662306a36Sopenharmony_ci u32 *flag; 281762306a36Sopenharmony_ci char *desc; 281862306a36Sopenharmony_ci}; 281962306a36Sopenharmony_ci 282062306a36Sopenharmony_cistatic struct dentry *dbgfs_root; 282162306a36Sopenharmony_ci 282262306a36Sopenharmony_cistatic void artpec6_crypto_init_debugfs(void) 282362306a36Sopenharmony_ci{ 282462306a36Sopenharmony_ci dbgfs_root = debugfs_create_dir("artpec6_crypto", NULL); 282562306a36Sopenharmony_ci 282662306a36Sopenharmony_ci#ifdef CONFIG_FAULT_INJECTION 282762306a36Sopenharmony_ci fault_create_debugfs_attr("fail_status_read", dbgfs_root, 282862306a36Sopenharmony_ci &artpec6_crypto_fail_status_read); 282962306a36Sopenharmony_ci 283062306a36Sopenharmony_ci fault_create_debugfs_attr("fail_dma_array_full", dbgfs_root, 283162306a36Sopenharmony_ci &artpec6_crypto_fail_dma_array_full); 283262306a36Sopenharmony_ci#endif 283362306a36Sopenharmony_ci} 283462306a36Sopenharmony_ci 283562306a36Sopenharmony_cistatic void artpec6_crypto_free_debugfs(void) 283662306a36Sopenharmony_ci{ 283762306a36Sopenharmony_ci debugfs_remove_recursive(dbgfs_root); 283862306a36Sopenharmony_ci dbgfs_root = NULL; 283962306a36Sopenharmony_ci} 284062306a36Sopenharmony_ci#endif 284162306a36Sopenharmony_ci 284262306a36Sopenharmony_cistatic const struct of_device_id artpec6_crypto_of_match[] = { 284362306a36Sopenharmony_ci { .compatible = "axis,artpec6-crypto", .data = (void *)ARTPEC6_CRYPTO }, 284462306a36Sopenharmony_ci { .compatible = "axis,artpec7-crypto", .data = (void *)ARTPEC7_CRYPTO }, 284562306a36Sopenharmony_ci {} 284662306a36Sopenharmony_ci}; 284762306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, artpec6_crypto_of_match); 284862306a36Sopenharmony_ci 284962306a36Sopenharmony_cistatic int artpec6_crypto_probe(struct platform_device *pdev) 285062306a36Sopenharmony_ci{ 285162306a36Sopenharmony_ci const struct of_device_id *match; 285262306a36Sopenharmony_ci enum artpec6_crypto_variant variant; 285362306a36Sopenharmony_ci struct artpec6_crypto *ac; 285462306a36Sopenharmony_ci struct device *dev = &pdev->dev; 285562306a36Sopenharmony_ci void __iomem *base; 285662306a36Sopenharmony_ci int irq; 285762306a36Sopenharmony_ci int err; 285862306a36Sopenharmony_ci 285962306a36Sopenharmony_ci if (artpec6_crypto_dev) 286062306a36Sopenharmony_ci return -ENODEV; 286162306a36Sopenharmony_ci 286262306a36Sopenharmony_ci match = of_match_node(artpec6_crypto_of_match, dev->of_node); 286362306a36Sopenharmony_ci if (!match) 286462306a36Sopenharmony_ci return -EINVAL; 286562306a36Sopenharmony_ci 286662306a36Sopenharmony_ci variant = (enum artpec6_crypto_variant)match->data; 286762306a36Sopenharmony_ci 286862306a36Sopenharmony_ci base = devm_platform_ioremap_resource(pdev, 0); 286962306a36Sopenharmony_ci if (IS_ERR(base)) 287062306a36Sopenharmony_ci return PTR_ERR(base); 287162306a36Sopenharmony_ci 287262306a36Sopenharmony_ci irq = platform_get_irq(pdev, 0); 287362306a36Sopenharmony_ci if (irq < 0) 287462306a36Sopenharmony_ci return -ENODEV; 287562306a36Sopenharmony_ci 287662306a36Sopenharmony_ci ac = devm_kzalloc(&pdev->dev, sizeof(struct artpec6_crypto), 287762306a36Sopenharmony_ci GFP_KERNEL); 287862306a36Sopenharmony_ci if (!ac) 287962306a36Sopenharmony_ci return -ENOMEM; 288062306a36Sopenharmony_ci 288162306a36Sopenharmony_ci platform_set_drvdata(pdev, ac); 288262306a36Sopenharmony_ci ac->variant = variant; 288362306a36Sopenharmony_ci 288462306a36Sopenharmony_ci spin_lock_init(&ac->queue_lock); 288562306a36Sopenharmony_ci INIT_LIST_HEAD(&ac->queue); 288662306a36Sopenharmony_ci INIT_LIST_HEAD(&ac->pending); 288762306a36Sopenharmony_ci timer_setup(&ac->timer, artpec6_crypto_timeout, 0); 288862306a36Sopenharmony_ci 288962306a36Sopenharmony_ci ac->base = base; 289062306a36Sopenharmony_ci 289162306a36Sopenharmony_ci ac->dma_cache = kmem_cache_create("artpec6_crypto_dma", 289262306a36Sopenharmony_ci sizeof(struct artpec6_crypto_dma_descriptors), 289362306a36Sopenharmony_ci 64, 289462306a36Sopenharmony_ci 0, 289562306a36Sopenharmony_ci NULL); 289662306a36Sopenharmony_ci if (!ac->dma_cache) 289762306a36Sopenharmony_ci return -ENOMEM; 289862306a36Sopenharmony_ci 289962306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 290062306a36Sopenharmony_ci artpec6_crypto_init_debugfs(); 290162306a36Sopenharmony_ci#endif 290262306a36Sopenharmony_ci 290362306a36Sopenharmony_ci tasklet_init(&ac->task, artpec6_crypto_task, 290462306a36Sopenharmony_ci (unsigned long)ac); 290562306a36Sopenharmony_ci 290662306a36Sopenharmony_ci ac->pad_buffer = devm_kzalloc(&pdev->dev, 2 * ARTPEC_CACHE_LINE_MAX, 290762306a36Sopenharmony_ci GFP_KERNEL); 290862306a36Sopenharmony_ci if (!ac->pad_buffer) 290962306a36Sopenharmony_ci return -ENOMEM; 291062306a36Sopenharmony_ci ac->pad_buffer = PTR_ALIGN(ac->pad_buffer, ARTPEC_CACHE_LINE_MAX); 291162306a36Sopenharmony_ci 291262306a36Sopenharmony_ci ac->zero_buffer = devm_kzalloc(&pdev->dev, 2 * ARTPEC_CACHE_LINE_MAX, 291362306a36Sopenharmony_ci GFP_KERNEL); 291462306a36Sopenharmony_ci if (!ac->zero_buffer) 291562306a36Sopenharmony_ci return -ENOMEM; 291662306a36Sopenharmony_ci ac->zero_buffer = PTR_ALIGN(ac->zero_buffer, ARTPEC_CACHE_LINE_MAX); 291762306a36Sopenharmony_ci 291862306a36Sopenharmony_ci err = init_crypto_hw(ac); 291962306a36Sopenharmony_ci if (err) 292062306a36Sopenharmony_ci goto free_cache; 292162306a36Sopenharmony_ci 292262306a36Sopenharmony_ci err = devm_request_irq(&pdev->dev, irq, artpec6_crypto_irq, 0, 292362306a36Sopenharmony_ci "artpec6-crypto", ac); 292462306a36Sopenharmony_ci if (err) 292562306a36Sopenharmony_ci goto disable_hw; 292662306a36Sopenharmony_ci 292762306a36Sopenharmony_ci artpec6_crypto_dev = &pdev->dev; 292862306a36Sopenharmony_ci 292962306a36Sopenharmony_ci err = crypto_register_ahashes(hash_algos, ARRAY_SIZE(hash_algos)); 293062306a36Sopenharmony_ci if (err) { 293162306a36Sopenharmony_ci dev_err(dev, "Failed to register ahashes\n"); 293262306a36Sopenharmony_ci goto disable_hw; 293362306a36Sopenharmony_ci } 293462306a36Sopenharmony_ci 293562306a36Sopenharmony_ci err = crypto_register_skciphers(crypto_algos, ARRAY_SIZE(crypto_algos)); 293662306a36Sopenharmony_ci if (err) { 293762306a36Sopenharmony_ci dev_err(dev, "Failed to register ciphers\n"); 293862306a36Sopenharmony_ci goto unregister_ahashes; 293962306a36Sopenharmony_ci } 294062306a36Sopenharmony_ci 294162306a36Sopenharmony_ci err = crypto_register_aeads(aead_algos, ARRAY_SIZE(aead_algos)); 294262306a36Sopenharmony_ci if (err) { 294362306a36Sopenharmony_ci dev_err(dev, "Failed to register aeads\n"); 294462306a36Sopenharmony_ci goto unregister_algs; 294562306a36Sopenharmony_ci } 294662306a36Sopenharmony_ci 294762306a36Sopenharmony_ci return 0; 294862306a36Sopenharmony_ci 294962306a36Sopenharmony_ciunregister_algs: 295062306a36Sopenharmony_ci crypto_unregister_skciphers(crypto_algos, ARRAY_SIZE(crypto_algos)); 295162306a36Sopenharmony_ciunregister_ahashes: 295262306a36Sopenharmony_ci crypto_unregister_ahashes(hash_algos, ARRAY_SIZE(hash_algos)); 295362306a36Sopenharmony_cidisable_hw: 295462306a36Sopenharmony_ci artpec6_crypto_disable_hw(ac); 295562306a36Sopenharmony_cifree_cache: 295662306a36Sopenharmony_ci kmem_cache_destroy(ac->dma_cache); 295762306a36Sopenharmony_ci return err; 295862306a36Sopenharmony_ci} 295962306a36Sopenharmony_ci 296062306a36Sopenharmony_cistatic int artpec6_crypto_remove(struct platform_device *pdev) 296162306a36Sopenharmony_ci{ 296262306a36Sopenharmony_ci struct artpec6_crypto *ac = platform_get_drvdata(pdev); 296362306a36Sopenharmony_ci int irq = platform_get_irq(pdev, 0); 296462306a36Sopenharmony_ci 296562306a36Sopenharmony_ci crypto_unregister_ahashes(hash_algos, ARRAY_SIZE(hash_algos)); 296662306a36Sopenharmony_ci crypto_unregister_skciphers(crypto_algos, ARRAY_SIZE(crypto_algos)); 296762306a36Sopenharmony_ci crypto_unregister_aeads(aead_algos, ARRAY_SIZE(aead_algos)); 296862306a36Sopenharmony_ci 296962306a36Sopenharmony_ci tasklet_disable(&ac->task); 297062306a36Sopenharmony_ci devm_free_irq(&pdev->dev, irq, ac); 297162306a36Sopenharmony_ci tasklet_kill(&ac->task); 297262306a36Sopenharmony_ci del_timer_sync(&ac->timer); 297362306a36Sopenharmony_ci 297462306a36Sopenharmony_ci artpec6_crypto_disable_hw(ac); 297562306a36Sopenharmony_ci 297662306a36Sopenharmony_ci kmem_cache_destroy(ac->dma_cache); 297762306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 297862306a36Sopenharmony_ci artpec6_crypto_free_debugfs(); 297962306a36Sopenharmony_ci#endif 298062306a36Sopenharmony_ci return 0; 298162306a36Sopenharmony_ci} 298262306a36Sopenharmony_ci 298362306a36Sopenharmony_cistatic struct platform_driver artpec6_crypto_driver = { 298462306a36Sopenharmony_ci .probe = artpec6_crypto_probe, 298562306a36Sopenharmony_ci .remove = artpec6_crypto_remove, 298662306a36Sopenharmony_ci .driver = { 298762306a36Sopenharmony_ci .name = "artpec6-crypto", 298862306a36Sopenharmony_ci .of_match_table = artpec6_crypto_of_match, 298962306a36Sopenharmony_ci }, 299062306a36Sopenharmony_ci}; 299162306a36Sopenharmony_ci 299262306a36Sopenharmony_cimodule_platform_driver(artpec6_crypto_driver); 299362306a36Sopenharmony_ci 299462306a36Sopenharmony_ciMODULE_AUTHOR("Axis Communications AB"); 299562306a36Sopenharmony_ciMODULE_DESCRIPTION("ARTPEC-6 Crypto driver"); 299662306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 2997