1820684ccSTudor Ambarus // SPDX-License-Identifier: GPL-2.0 2ebc82efaSNicolas Royer /* 3ebc82efaSNicolas Royer * Cryptographic API. 4ebc82efaSNicolas Royer * 5ebc82efaSNicolas Royer * Support for ATMEL SHA1/SHA256 HW acceleration. 6ebc82efaSNicolas Royer * 7ebc82efaSNicolas Royer * Copyright (c) 2012 Eukréa Electromatique - ATMEL 8ebc82efaSNicolas Royer * Author: Nicolas Royer <nicolas@eukrea.com> 9ebc82efaSNicolas Royer * 10ebc82efaSNicolas Royer * Some ideas are from omap-sham.c drivers. 11ebc82efaSNicolas Royer */ 12ebc82efaSNicolas Royer 13ebc82efaSNicolas Royer 14ebc82efaSNicolas Royer #include <linux/kernel.h> 15ebc82efaSNicolas Royer #include <linux/module.h> 16ebc82efaSNicolas Royer #include <linux/slab.h> 17ebc82efaSNicolas Royer #include <linux/err.h> 18ebc82efaSNicolas Royer #include <linux/clk.h> 19ebc82efaSNicolas Royer #include <linux/io.h> 20ebc82efaSNicolas Royer #include <linux/hw_random.h> 21ebc82efaSNicolas Royer #include <linux/platform_device.h> 22ebc82efaSNicolas Royer 23ebc82efaSNicolas Royer #include <linux/device.h> 24ebc82efaSNicolas Royer #include <linux/init.h> 25ebc82efaSNicolas Royer #include <linux/errno.h> 26ebc82efaSNicolas Royer #include <linux/interrupt.h> 27ebc82efaSNicolas Royer #include <linux/irq.h> 28ebc82efaSNicolas Royer #include <linux/scatterlist.h> 29ebc82efaSNicolas Royer #include <linux/dma-mapping.h> 30abfe7ae4SNicolas Ferre #include <linux/of_device.h> 31ebc82efaSNicolas Royer #include <linux/delay.h> 32ebc82efaSNicolas Royer #include <linux/crypto.h> 33ebc82efaSNicolas Royer #include <linux/cryptohash.h> 34ebc82efaSNicolas Royer #include <crypto/scatterwalk.h> 35ebc82efaSNicolas Royer #include <crypto/algapi.h> 36ebc82efaSNicolas Royer #include <crypto/sha.h> 37ebc82efaSNicolas Royer #include <crypto/hash.h> 38ebc82efaSNicolas Royer #include <crypto/internal/hash.h> 39d4905b38SNicolas Royer #include <linux/platform_data/crypto-atmel.h> 40ebc82efaSNicolas Royer #include "atmel-sha-regs.h" 4189a82ef8SCyrille Pitchen #include "atmel-authenc.h" 42ebc82efaSNicolas Royer 43ebc82efaSNicolas Royer /* SHA flags */ 44ebc82efaSNicolas Royer #define SHA_FLAGS_BUSY BIT(0) 45ebc82efaSNicolas Royer #define SHA_FLAGS_FINAL BIT(1) 46ebc82efaSNicolas Royer #define SHA_FLAGS_DMA_ACTIVE BIT(2) 47ebc82efaSNicolas Royer #define SHA_FLAGS_OUTPUT_READY BIT(3) 48ebc82efaSNicolas Royer #define SHA_FLAGS_INIT BIT(4) 49ebc82efaSNicolas Royer #define SHA_FLAGS_CPU BIT(5) 50ebc82efaSNicolas Royer #define SHA_FLAGS_DMA_READY BIT(6) 510569fc46SCyrille Pitchen #define SHA_FLAGS_DUMP_REG BIT(7) 52ebc82efaSNicolas Royer 5381d8750bSCyrille Pitchen /* bits[11:8] are reserved. */ 54f07cebadSCyrille Pitchen 55ebc82efaSNicolas Royer #define SHA_FLAGS_FINUP BIT(16) 56ebc82efaSNicolas Royer #define SHA_FLAGS_SG BIT(17) 57d4905b38SNicolas Royer #define SHA_FLAGS_ERROR BIT(23) 58d4905b38SNicolas Royer #define SHA_FLAGS_PAD BIT(24) 597cee3508SCyrille Pitchen #define SHA_FLAGS_RESTORE BIT(25) 60eec12f66SCyrille Pitchen #define SHA_FLAGS_IDATAR0 BIT(26) 61eec12f66SCyrille Pitchen #define SHA_FLAGS_WAIT_DATARDY BIT(27) 62ebc82efaSNicolas Royer 6381d8750bSCyrille Pitchen #define SHA_OP_INIT 0 64ebc82efaSNicolas Royer #define SHA_OP_UPDATE 1 65ebc82efaSNicolas Royer #define SHA_OP_FINAL 2 6681d8750bSCyrille Pitchen #define SHA_OP_DIGEST 3 67ebc82efaSNicolas Royer 68cc831d32SCyrille Pitchen #define SHA_BUFFER_LEN (PAGE_SIZE / 16) 69ebc82efaSNicolas Royer 70ebc82efaSNicolas Royer #define ATMEL_SHA_DMA_THRESHOLD 56 71ebc82efaSNicolas Royer 72d4905b38SNicolas Royer struct atmel_sha_caps { 73d4905b38SNicolas Royer bool has_dma; 74d4905b38SNicolas Royer bool has_dualbuff; 75d4905b38SNicolas Royer bool has_sha224; 76d4905b38SNicolas Royer bool has_sha_384_512; 777cee3508SCyrille Pitchen bool has_uihv; 7881d8750bSCyrille Pitchen bool has_hmac; 79d4905b38SNicolas Royer }; 80ebc82efaSNicolas Royer 81ebc82efaSNicolas Royer struct atmel_sha_dev; 82ebc82efaSNicolas Royer 83cc831d32SCyrille Pitchen /* 849c4274d9SCyrille Pitchen * .statesize = sizeof(struct atmel_sha_reqctx) must be <= PAGE_SIZE / 8 as 85cc831d32SCyrille Pitchen * tested by the ahash_prepare_alg() function. 86cc831d32SCyrille Pitchen */ 87ebc82efaSNicolas Royer struct atmel_sha_reqctx { 88ebc82efaSNicolas Royer struct atmel_sha_dev *dd; 89ebc82efaSNicolas Royer unsigned long flags; 90ebc82efaSNicolas Royer unsigned long op; 91ebc82efaSNicolas Royer 92d4905b38SNicolas Royer u8 digest[SHA512_DIGEST_SIZE] __aligned(sizeof(u32)); 93d4905b38SNicolas Royer u64 digcnt[2]; 94ebc82efaSNicolas Royer size_t bufcnt; 95ebc82efaSNicolas Royer size_t buflen; 96ebc82efaSNicolas Royer dma_addr_t dma_addr; 97ebc82efaSNicolas Royer 98ebc82efaSNicolas Royer /* walk state */ 99ebc82efaSNicolas Royer struct scatterlist *sg; 100ebc82efaSNicolas Royer unsigned int offset; /* offset in current sg */ 101ebc82efaSNicolas Royer unsigned int total; /* total request */ 102ebc82efaSNicolas Royer 103d4905b38SNicolas Royer size_t block_size; 10481d8750bSCyrille Pitchen size_t hash_size; 105d4905b38SNicolas Royer 1069c4274d9SCyrille Pitchen u8 buffer[SHA_BUFFER_LEN + SHA512_BLOCK_SIZE] __aligned(sizeof(u32)); 107ebc82efaSNicolas Royer }; 108ebc82efaSNicolas Royer 109a29af939SCyrille Pitchen typedef int (*atmel_sha_fn_t)(struct atmel_sha_dev *); 110a29af939SCyrille Pitchen 111ebc82efaSNicolas Royer struct atmel_sha_ctx { 112ebc82efaSNicolas Royer struct atmel_sha_dev *dd; 113a29af939SCyrille Pitchen atmel_sha_fn_t start; 114ebc82efaSNicolas Royer 115ebc82efaSNicolas Royer unsigned long flags; 116ebc82efaSNicolas Royer }; 117ebc82efaSNicolas Royer 118d4905b38SNicolas Royer #define ATMEL_SHA_QUEUE_LENGTH 50 119d4905b38SNicolas Royer 120d4905b38SNicolas Royer struct atmel_sha_dma { 121d4905b38SNicolas Royer struct dma_chan *chan; 122d4905b38SNicolas Royer struct dma_slave_config dma_conf; 12369303cf0SCyrille Pitchen struct scatterlist *sg; 12469303cf0SCyrille Pitchen int nents; 12569303cf0SCyrille Pitchen unsigned int last_sg_length; 126d4905b38SNicolas Royer }; 127ebc82efaSNicolas Royer 128ebc82efaSNicolas Royer struct atmel_sha_dev { 129ebc82efaSNicolas Royer struct list_head list; 130ebc82efaSNicolas Royer unsigned long phys_base; 131ebc82efaSNicolas Royer struct device *dev; 132ebc82efaSNicolas Royer struct clk *iclk; 133ebc82efaSNicolas Royer int irq; 134ebc82efaSNicolas Royer void __iomem *io_base; 135ebc82efaSNicolas Royer 136ebc82efaSNicolas Royer spinlock_t lock; 137ebc82efaSNicolas Royer int err; 138ebc82efaSNicolas Royer struct tasklet_struct done_task; 139f56809c3SCyrille Pitchen struct tasklet_struct queue_task; 140ebc82efaSNicolas Royer 141ebc82efaSNicolas Royer unsigned long flags; 142ebc82efaSNicolas Royer struct crypto_queue queue; 143ebc82efaSNicolas Royer struct ahash_request *req; 144a29af939SCyrille Pitchen bool is_async; 14589a82ef8SCyrille Pitchen bool force_complete; 146b5ce82a7SCyrille Pitchen atmel_sha_fn_t resume; 147eec12f66SCyrille Pitchen atmel_sha_fn_t cpu_transfer_complete; 148d4905b38SNicolas Royer 149d4905b38SNicolas Royer struct atmel_sha_dma dma_lch_in; 150d4905b38SNicolas Royer 151d4905b38SNicolas Royer struct atmel_sha_caps caps; 152d4905b38SNicolas Royer 15381d8750bSCyrille Pitchen struct scatterlist tmp; 15481d8750bSCyrille Pitchen 155d4905b38SNicolas Royer u32 hw_version; 156ebc82efaSNicolas Royer }; 157ebc82efaSNicolas Royer 158ebc82efaSNicolas Royer struct atmel_sha_drv { 159ebc82efaSNicolas Royer struct list_head dev_list; 160ebc82efaSNicolas Royer spinlock_t lock; 161ebc82efaSNicolas Royer }; 162ebc82efaSNicolas Royer 163ebc82efaSNicolas Royer static struct atmel_sha_drv atmel_sha = { 164ebc82efaSNicolas Royer .dev_list = LIST_HEAD_INIT(atmel_sha.dev_list), 165ebc82efaSNicolas Royer .lock = __SPIN_LOCK_UNLOCKED(atmel_sha.lock), 166ebc82efaSNicolas Royer }; 167ebc82efaSNicolas Royer 1680569fc46SCyrille Pitchen #ifdef VERBOSE_DEBUG 1690569fc46SCyrille Pitchen static const char *atmel_sha_reg_name(u32 offset, char *tmp, size_t sz, bool wr) 1700569fc46SCyrille Pitchen { 1710569fc46SCyrille Pitchen switch (offset) { 1720569fc46SCyrille Pitchen case SHA_CR: 1730569fc46SCyrille Pitchen return "CR"; 1740569fc46SCyrille Pitchen 1750569fc46SCyrille Pitchen case SHA_MR: 1760569fc46SCyrille Pitchen return "MR"; 1770569fc46SCyrille Pitchen 1780569fc46SCyrille Pitchen case SHA_IER: 1790569fc46SCyrille Pitchen return "IER"; 1800569fc46SCyrille Pitchen 1810569fc46SCyrille Pitchen case SHA_IDR: 1820569fc46SCyrille Pitchen return "IDR"; 1830569fc46SCyrille Pitchen 1840569fc46SCyrille Pitchen case SHA_IMR: 1850569fc46SCyrille Pitchen return "IMR"; 1860569fc46SCyrille Pitchen 1870569fc46SCyrille Pitchen case SHA_ISR: 1880569fc46SCyrille Pitchen return "ISR"; 1890569fc46SCyrille Pitchen 1900569fc46SCyrille Pitchen case SHA_MSR: 1910569fc46SCyrille Pitchen return "MSR"; 1920569fc46SCyrille Pitchen 1930569fc46SCyrille Pitchen case SHA_BCR: 1940569fc46SCyrille Pitchen return "BCR"; 1950569fc46SCyrille Pitchen 1960569fc46SCyrille Pitchen case SHA_REG_DIN(0): 1970569fc46SCyrille Pitchen case SHA_REG_DIN(1): 1980569fc46SCyrille Pitchen case SHA_REG_DIN(2): 1990569fc46SCyrille Pitchen case SHA_REG_DIN(3): 2000569fc46SCyrille Pitchen case SHA_REG_DIN(4): 2010569fc46SCyrille Pitchen case SHA_REG_DIN(5): 2020569fc46SCyrille Pitchen case SHA_REG_DIN(6): 2030569fc46SCyrille Pitchen case SHA_REG_DIN(7): 2040569fc46SCyrille Pitchen case SHA_REG_DIN(8): 2050569fc46SCyrille Pitchen case SHA_REG_DIN(9): 2060569fc46SCyrille Pitchen case SHA_REG_DIN(10): 2070569fc46SCyrille Pitchen case SHA_REG_DIN(11): 2080569fc46SCyrille Pitchen case SHA_REG_DIN(12): 2090569fc46SCyrille Pitchen case SHA_REG_DIN(13): 2100569fc46SCyrille Pitchen case SHA_REG_DIN(14): 2110569fc46SCyrille Pitchen case SHA_REG_DIN(15): 2120569fc46SCyrille Pitchen snprintf(tmp, sz, "IDATAR[%u]", (offset - SHA_REG_DIN(0)) >> 2); 2130569fc46SCyrille Pitchen break; 2140569fc46SCyrille Pitchen 2150569fc46SCyrille Pitchen case SHA_REG_DIGEST(0): 2160569fc46SCyrille Pitchen case SHA_REG_DIGEST(1): 2170569fc46SCyrille Pitchen case SHA_REG_DIGEST(2): 2180569fc46SCyrille Pitchen case SHA_REG_DIGEST(3): 2190569fc46SCyrille Pitchen case SHA_REG_DIGEST(4): 2200569fc46SCyrille Pitchen case SHA_REG_DIGEST(5): 2210569fc46SCyrille Pitchen case SHA_REG_DIGEST(6): 2220569fc46SCyrille Pitchen case SHA_REG_DIGEST(7): 2230569fc46SCyrille Pitchen case SHA_REG_DIGEST(8): 2240569fc46SCyrille Pitchen case SHA_REG_DIGEST(9): 2250569fc46SCyrille Pitchen case SHA_REG_DIGEST(10): 2260569fc46SCyrille Pitchen case SHA_REG_DIGEST(11): 2270569fc46SCyrille Pitchen case SHA_REG_DIGEST(12): 2280569fc46SCyrille Pitchen case SHA_REG_DIGEST(13): 2290569fc46SCyrille Pitchen case SHA_REG_DIGEST(14): 2300569fc46SCyrille Pitchen case SHA_REG_DIGEST(15): 2310569fc46SCyrille Pitchen if (wr) 2320569fc46SCyrille Pitchen snprintf(tmp, sz, "IDATAR[%u]", 2330569fc46SCyrille Pitchen 16u + ((offset - SHA_REG_DIGEST(0)) >> 2)); 2340569fc46SCyrille Pitchen else 2350569fc46SCyrille Pitchen snprintf(tmp, sz, "ODATAR[%u]", 2360569fc46SCyrille Pitchen (offset - SHA_REG_DIGEST(0)) >> 2); 2370569fc46SCyrille Pitchen break; 2380569fc46SCyrille Pitchen 2390569fc46SCyrille Pitchen case SHA_HW_VERSION: 2400569fc46SCyrille Pitchen return "HWVER"; 2410569fc46SCyrille Pitchen 2420569fc46SCyrille Pitchen default: 2430569fc46SCyrille Pitchen snprintf(tmp, sz, "0x%02x", offset); 2440569fc46SCyrille Pitchen break; 2450569fc46SCyrille Pitchen } 2460569fc46SCyrille Pitchen 2470569fc46SCyrille Pitchen return tmp; 2480569fc46SCyrille Pitchen } 2490569fc46SCyrille Pitchen 2500569fc46SCyrille Pitchen #endif /* VERBOSE_DEBUG */ 2510569fc46SCyrille Pitchen 252ebc82efaSNicolas Royer static inline u32 atmel_sha_read(struct atmel_sha_dev *dd, u32 offset) 253ebc82efaSNicolas Royer { 2540569fc46SCyrille Pitchen u32 value = readl_relaxed(dd->io_base + offset); 2550569fc46SCyrille Pitchen 2560569fc46SCyrille Pitchen #ifdef VERBOSE_DEBUG 2570569fc46SCyrille Pitchen if (dd->flags & SHA_FLAGS_DUMP_REG) { 2580569fc46SCyrille Pitchen char tmp[16]; 2590569fc46SCyrille Pitchen 2600569fc46SCyrille Pitchen dev_vdbg(dd->dev, "read 0x%08x from %s\n", value, 2610569fc46SCyrille Pitchen atmel_sha_reg_name(offset, tmp, sizeof(tmp), false)); 2620569fc46SCyrille Pitchen } 2630569fc46SCyrille Pitchen #endif /* VERBOSE_DEBUG */ 2640569fc46SCyrille Pitchen 2650569fc46SCyrille Pitchen return value; 266ebc82efaSNicolas Royer } 267ebc82efaSNicolas Royer 268ebc82efaSNicolas Royer static inline void atmel_sha_write(struct atmel_sha_dev *dd, 269ebc82efaSNicolas Royer u32 offset, u32 value) 270ebc82efaSNicolas Royer { 2710569fc46SCyrille Pitchen #ifdef VERBOSE_DEBUG 2720569fc46SCyrille Pitchen if (dd->flags & SHA_FLAGS_DUMP_REG) { 2730569fc46SCyrille Pitchen char tmp[16]; 2740569fc46SCyrille Pitchen 2750569fc46SCyrille Pitchen dev_vdbg(dd->dev, "write 0x%08x into %s\n", value, 2760569fc46SCyrille Pitchen atmel_sha_reg_name(offset, tmp, sizeof(tmp), true)); 2770569fc46SCyrille Pitchen } 2780569fc46SCyrille Pitchen #endif /* VERBOSE_DEBUG */ 2790569fc46SCyrille Pitchen 280ebc82efaSNicolas Royer writel_relaxed(value, dd->io_base + offset); 281ebc82efaSNicolas Royer } 282ebc82efaSNicolas Royer 283a29af939SCyrille Pitchen static inline int atmel_sha_complete(struct atmel_sha_dev *dd, int err) 284a29af939SCyrille Pitchen { 285a29af939SCyrille Pitchen struct ahash_request *req = dd->req; 286a29af939SCyrille Pitchen 287a29af939SCyrille Pitchen dd->flags &= ~(SHA_FLAGS_BUSY | SHA_FLAGS_FINAL | SHA_FLAGS_CPU | 2880569fc46SCyrille Pitchen SHA_FLAGS_DMA_READY | SHA_FLAGS_OUTPUT_READY | 2890569fc46SCyrille Pitchen SHA_FLAGS_DUMP_REG); 290a29af939SCyrille Pitchen 291a29af939SCyrille Pitchen clk_disable(dd->iclk); 292a29af939SCyrille Pitchen 29389a82ef8SCyrille Pitchen if ((dd->is_async || dd->force_complete) && req->base.complete) 294a29af939SCyrille Pitchen req->base.complete(&req->base, err); 295a29af939SCyrille Pitchen 296a29af939SCyrille Pitchen /* handle new request */ 297a29af939SCyrille Pitchen tasklet_schedule(&dd->queue_task); 298a29af939SCyrille Pitchen 299a29af939SCyrille Pitchen return err; 300a29af939SCyrille Pitchen } 301a29af939SCyrille Pitchen 302ebc82efaSNicolas Royer static size_t atmel_sha_append_sg(struct atmel_sha_reqctx *ctx) 303ebc82efaSNicolas Royer { 304ebc82efaSNicolas Royer size_t count; 305ebc82efaSNicolas Royer 306ebc82efaSNicolas Royer while ((ctx->bufcnt < ctx->buflen) && ctx->total) { 307ebc82efaSNicolas Royer count = min(ctx->sg->length - ctx->offset, ctx->total); 308ebc82efaSNicolas Royer count = min(count, ctx->buflen - ctx->bufcnt); 309ebc82efaSNicolas Royer 310803eeae8SLeilei Zhao if (count <= 0) { 311803eeae8SLeilei Zhao /* 312803eeae8SLeilei Zhao * Check if count <= 0 because the buffer is full or 313803eeae8SLeilei Zhao * because the sg length is 0. In the latest case, 314803eeae8SLeilei Zhao * check if there is another sg in the list, a 0 length 315803eeae8SLeilei Zhao * sg doesn't necessarily mean the end of the sg list. 316803eeae8SLeilei Zhao */ 317803eeae8SLeilei Zhao if ((ctx->sg->length == 0) && !sg_is_last(ctx->sg)) { 318803eeae8SLeilei Zhao ctx->sg = sg_next(ctx->sg); 319803eeae8SLeilei Zhao continue; 320803eeae8SLeilei Zhao } else { 321ebc82efaSNicolas Royer break; 322803eeae8SLeilei Zhao } 323803eeae8SLeilei Zhao } 324ebc82efaSNicolas Royer 325ebc82efaSNicolas Royer scatterwalk_map_and_copy(ctx->buffer + ctx->bufcnt, ctx->sg, 326ebc82efaSNicolas Royer ctx->offset, count, 0); 327ebc82efaSNicolas Royer 328ebc82efaSNicolas Royer ctx->bufcnt += count; 329ebc82efaSNicolas Royer ctx->offset += count; 330ebc82efaSNicolas Royer ctx->total -= count; 331ebc82efaSNicolas Royer 332ebc82efaSNicolas Royer if (ctx->offset == ctx->sg->length) { 333ebc82efaSNicolas Royer ctx->sg = sg_next(ctx->sg); 334ebc82efaSNicolas Royer if (ctx->sg) 335ebc82efaSNicolas Royer ctx->offset = 0; 336ebc82efaSNicolas Royer else 337ebc82efaSNicolas Royer ctx->total = 0; 338ebc82efaSNicolas Royer } 339ebc82efaSNicolas Royer } 340ebc82efaSNicolas Royer 341ebc82efaSNicolas Royer return 0; 342ebc82efaSNicolas Royer } 343ebc82efaSNicolas Royer 344ebc82efaSNicolas Royer /* 345d4905b38SNicolas Royer * The purpose of this padding is to ensure that the padded message is a 346d4905b38SNicolas Royer * multiple of 512 bits (SHA1/SHA224/SHA256) or 1024 bits (SHA384/SHA512). 347d4905b38SNicolas Royer * The bit "1" is appended at the end of the message followed by 348d4905b38SNicolas Royer * "padlen-1" zero bits. Then a 64 bits block (SHA1/SHA224/SHA256) or 349d4905b38SNicolas Royer * 128 bits block (SHA384/SHA512) equals to the message length in bits 350d4905b38SNicolas Royer * is appended. 351ebc82efaSNicolas Royer * 352d4905b38SNicolas Royer * For SHA1/SHA224/SHA256, padlen is calculated as followed: 353ebc82efaSNicolas Royer * - if message length < 56 bytes then padlen = 56 - message length 354ebc82efaSNicolas Royer * - else padlen = 64 + 56 - message length 355d4905b38SNicolas Royer * 356d4905b38SNicolas Royer * For SHA384/SHA512, padlen is calculated as followed: 357d4905b38SNicolas Royer * - if message length < 112 bytes then padlen = 112 - message length 358d4905b38SNicolas Royer * - else padlen = 128 + 112 - message length 359ebc82efaSNicolas Royer */ 360ebc82efaSNicolas Royer static void atmel_sha_fill_padding(struct atmel_sha_reqctx *ctx, int length) 361ebc82efaSNicolas Royer { 362ebc82efaSNicolas Royer unsigned int index, padlen; 363427e6e3aSHerbert Xu __be64 bits[2]; 364d4905b38SNicolas Royer u64 size[2]; 365ebc82efaSNicolas Royer 366d4905b38SNicolas Royer size[0] = ctx->digcnt[0]; 367d4905b38SNicolas Royer size[1] = ctx->digcnt[1]; 368ebc82efaSNicolas Royer 369d4905b38SNicolas Royer size[0] += ctx->bufcnt; 370d4905b38SNicolas Royer if (size[0] < ctx->bufcnt) 371d4905b38SNicolas Royer size[1]++; 372d4905b38SNicolas Royer 373d4905b38SNicolas Royer size[0] += length; 374d4905b38SNicolas Royer if (size[0] < length) 375d4905b38SNicolas Royer size[1]++; 376d4905b38SNicolas Royer 377d4905b38SNicolas Royer bits[1] = cpu_to_be64(size[0] << 3); 378d4905b38SNicolas Royer bits[0] = cpu_to_be64(size[1] << 3 | size[0] >> 61); 379d4905b38SNicolas Royer 380f07cebadSCyrille Pitchen switch (ctx->flags & SHA_FLAGS_ALGO_MASK) { 381f07cebadSCyrille Pitchen case SHA_FLAGS_SHA384: 382f07cebadSCyrille Pitchen case SHA_FLAGS_SHA512: 383d4905b38SNicolas Royer index = ctx->bufcnt & 0x7f; 384d4905b38SNicolas Royer padlen = (index < 112) ? (112 - index) : ((128+112) - index); 385d4905b38SNicolas Royer *(ctx->buffer + ctx->bufcnt) = 0x80; 386d4905b38SNicolas Royer memset(ctx->buffer + ctx->bufcnt + 1, 0, padlen-1); 387d4905b38SNicolas Royer memcpy(ctx->buffer + ctx->bufcnt + padlen, bits, 16); 388d4905b38SNicolas Royer ctx->bufcnt += padlen + 16; 389d4905b38SNicolas Royer ctx->flags |= SHA_FLAGS_PAD; 390f07cebadSCyrille Pitchen break; 391f07cebadSCyrille Pitchen 392f07cebadSCyrille Pitchen default: 393ebc82efaSNicolas Royer index = ctx->bufcnt & 0x3f; 394ebc82efaSNicolas Royer padlen = (index < 56) ? (56 - index) : ((64+56) - index); 395ebc82efaSNicolas Royer *(ctx->buffer + ctx->bufcnt) = 0x80; 396ebc82efaSNicolas Royer memset(ctx->buffer + ctx->bufcnt + 1, 0, padlen-1); 397d4905b38SNicolas Royer memcpy(ctx->buffer + ctx->bufcnt + padlen, &bits[1], 8); 398ebc82efaSNicolas Royer ctx->bufcnt += padlen + 8; 399ebc82efaSNicolas Royer ctx->flags |= SHA_FLAGS_PAD; 400f07cebadSCyrille Pitchen break; 401ebc82efaSNicolas Royer } 402d4905b38SNicolas Royer } 403ebc82efaSNicolas Royer 4048340c7fdSCyrille Pitchen static struct atmel_sha_dev *atmel_sha_find_dev(struct atmel_sha_ctx *tctx) 405ebc82efaSNicolas Royer { 406ebc82efaSNicolas Royer struct atmel_sha_dev *dd = NULL; 407ebc82efaSNicolas Royer struct atmel_sha_dev *tmp; 408ebc82efaSNicolas Royer 409ebc82efaSNicolas Royer spin_lock_bh(&atmel_sha.lock); 410ebc82efaSNicolas Royer if (!tctx->dd) { 411ebc82efaSNicolas Royer list_for_each_entry(tmp, &atmel_sha.dev_list, list) { 412ebc82efaSNicolas Royer dd = tmp; 413ebc82efaSNicolas Royer break; 414ebc82efaSNicolas Royer } 415ebc82efaSNicolas Royer tctx->dd = dd; 416ebc82efaSNicolas Royer } else { 417ebc82efaSNicolas Royer dd = tctx->dd; 418ebc82efaSNicolas Royer } 419ebc82efaSNicolas Royer 420ebc82efaSNicolas Royer spin_unlock_bh(&atmel_sha.lock); 421ebc82efaSNicolas Royer 4228340c7fdSCyrille Pitchen return dd; 4238340c7fdSCyrille Pitchen } 4248340c7fdSCyrille Pitchen 4258340c7fdSCyrille Pitchen static int atmel_sha_init(struct ahash_request *req) 4268340c7fdSCyrille Pitchen { 4278340c7fdSCyrille Pitchen struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); 4288340c7fdSCyrille Pitchen struct atmel_sha_ctx *tctx = crypto_ahash_ctx(tfm); 4298340c7fdSCyrille Pitchen struct atmel_sha_reqctx *ctx = ahash_request_ctx(req); 4308340c7fdSCyrille Pitchen struct atmel_sha_dev *dd = atmel_sha_find_dev(tctx); 4318340c7fdSCyrille Pitchen 432ebc82efaSNicolas Royer ctx->dd = dd; 433ebc82efaSNicolas Royer 434ebc82efaSNicolas Royer ctx->flags = 0; 435ebc82efaSNicolas Royer 436ebc82efaSNicolas Royer dev_dbg(dd->dev, "init: digest size: %d\n", 437ebc82efaSNicolas Royer crypto_ahash_digestsize(tfm)); 438ebc82efaSNicolas Royer 439d4905b38SNicolas Royer switch (crypto_ahash_digestsize(tfm)) { 440d4905b38SNicolas Royer case SHA1_DIGEST_SIZE: 441ebc82efaSNicolas Royer ctx->flags |= SHA_FLAGS_SHA1; 442d4905b38SNicolas Royer ctx->block_size = SHA1_BLOCK_SIZE; 443d4905b38SNicolas Royer break; 444d4905b38SNicolas Royer case SHA224_DIGEST_SIZE: 445d4905b38SNicolas Royer ctx->flags |= SHA_FLAGS_SHA224; 446d4905b38SNicolas Royer ctx->block_size = SHA224_BLOCK_SIZE; 447d4905b38SNicolas Royer break; 448d4905b38SNicolas Royer case SHA256_DIGEST_SIZE: 449ebc82efaSNicolas Royer ctx->flags |= SHA_FLAGS_SHA256; 450d4905b38SNicolas Royer ctx->block_size = SHA256_BLOCK_SIZE; 451d4905b38SNicolas Royer break; 452d4905b38SNicolas Royer case SHA384_DIGEST_SIZE: 453d4905b38SNicolas Royer ctx->flags |= SHA_FLAGS_SHA384; 454d4905b38SNicolas Royer ctx->block_size = SHA384_BLOCK_SIZE; 455d4905b38SNicolas Royer break; 456d4905b38SNicolas Royer case SHA512_DIGEST_SIZE: 457d4905b38SNicolas Royer ctx->flags |= SHA_FLAGS_SHA512; 458d4905b38SNicolas Royer ctx->block_size = SHA512_BLOCK_SIZE; 459d4905b38SNicolas Royer break; 460d4905b38SNicolas Royer default: 461d4905b38SNicolas Royer return -EINVAL; 462d4905b38SNicolas Royer break; 463d4905b38SNicolas Royer } 464ebc82efaSNicolas Royer 465ebc82efaSNicolas Royer ctx->bufcnt = 0; 466d4905b38SNicolas Royer ctx->digcnt[0] = 0; 467d4905b38SNicolas Royer ctx->digcnt[1] = 0; 468ebc82efaSNicolas Royer ctx->buflen = SHA_BUFFER_LEN; 469ebc82efaSNicolas Royer 470ebc82efaSNicolas Royer return 0; 471ebc82efaSNicolas Royer } 472ebc82efaSNicolas Royer 473ebc82efaSNicolas Royer static void atmel_sha_write_ctrl(struct atmel_sha_dev *dd, int dma) 474ebc82efaSNicolas Royer { 475ebc82efaSNicolas Royer struct atmel_sha_reqctx *ctx = ahash_request_ctx(dd->req); 4767cee3508SCyrille Pitchen u32 valmr = SHA_MR_MODE_AUTO; 4777cee3508SCyrille Pitchen unsigned int i, hashsize = 0; 478ebc82efaSNicolas Royer 479ebc82efaSNicolas Royer if (likely(dma)) { 480d4905b38SNicolas Royer if (!dd->caps.has_dma) 481ebc82efaSNicolas Royer atmel_sha_write(dd, SHA_IER, SHA_INT_TXBUFE); 482ebc82efaSNicolas Royer valmr = SHA_MR_MODE_PDC; 483d4905b38SNicolas Royer if (dd->caps.has_dualbuff) 484d4905b38SNicolas Royer valmr |= SHA_MR_DUALBUFF; 485ebc82efaSNicolas Royer } else { 486ebc82efaSNicolas Royer atmel_sha_write(dd, SHA_IER, SHA_INT_DATARDY); 487ebc82efaSNicolas Royer } 488ebc82efaSNicolas Royer 4897cee3508SCyrille Pitchen switch (ctx->flags & SHA_FLAGS_ALGO_MASK) { 4907cee3508SCyrille Pitchen case SHA_FLAGS_SHA1: 491d4905b38SNicolas Royer valmr |= SHA_MR_ALGO_SHA1; 4927cee3508SCyrille Pitchen hashsize = SHA1_DIGEST_SIZE; 4937cee3508SCyrille Pitchen break; 4947cee3508SCyrille Pitchen 4957cee3508SCyrille Pitchen case SHA_FLAGS_SHA224: 496d4905b38SNicolas Royer valmr |= SHA_MR_ALGO_SHA224; 4977cee3508SCyrille Pitchen hashsize = SHA256_DIGEST_SIZE; 4987cee3508SCyrille Pitchen break; 4997cee3508SCyrille Pitchen 5007cee3508SCyrille Pitchen case SHA_FLAGS_SHA256: 501ebc82efaSNicolas Royer valmr |= SHA_MR_ALGO_SHA256; 5027cee3508SCyrille Pitchen hashsize = SHA256_DIGEST_SIZE; 5037cee3508SCyrille Pitchen break; 5047cee3508SCyrille Pitchen 5057cee3508SCyrille Pitchen case SHA_FLAGS_SHA384: 506d4905b38SNicolas Royer valmr |= SHA_MR_ALGO_SHA384; 5077cee3508SCyrille Pitchen hashsize = SHA512_DIGEST_SIZE; 5087cee3508SCyrille Pitchen break; 5097cee3508SCyrille Pitchen 5107cee3508SCyrille Pitchen case SHA_FLAGS_SHA512: 511d4905b38SNicolas Royer valmr |= SHA_MR_ALGO_SHA512; 5127cee3508SCyrille Pitchen hashsize = SHA512_DIGEST_SIZE; 5137cee3508SCyrille Pitchen break; 5147cee3508SCyrille Pitchen 5157cee3508SCyrille Pitchen default: 5167cee3508SCyrille Pitchen break; 5177cee3508SCyrille Pitchen } 518ebc82efaSNicolas Royer 519ebc82efaSNicolas Royer /* Setting CR_FIRST only for the first iteration */ 5207cee3508SCyrille Pitchen if (!(ctx->digcnt[0] || ctx->digcnt[1])) { 5217cee3508SCyrille Pitchen atmel_sha_write(dd, SHA_CR, SHA_CR_FIRST); 5227cee3508SCyrille Pitchen } else if (dd->caps.has_uihv && (ctx->flags & SHA_FLAGS_RESTORE)) { 5237cee3508SCyrille Pitchen const u32 *hash = (const u32 *)ctx->digest; 524ebc82efaSNicolas Royer 5257cee3508SCyrille Pitchen /* 5267cee3508SCyrille Pitchen * Restore the hardware context: update the User Initialize 5277cee3508SCyrille Pitchen * Hash Value (UIHV) with the value saved when the latest 5287cee3508SCyrille Pitchen * 'update' operation completed on this very same crypto 5297cee3508SCyrille Pitchen * request. 5307cee3508SCyrille Pitchen */ 5317cee3508SCyrille Pitchen ctx->flags &= ~SHA_FLAGS_RESTORE; 5327cee3508SCyrille Pitchen atmel_sha_write(dd, SHA_CR, SHA_CR_WUIHV); 5337cee3508SCyrille Pitchen for (i = 0; i < hashsize / sizeof(u32); ++i) 5347cee3508SCyrille Pitchen atmel_sha_write(dd, SHA_REG_DIN(i), hash[i]); 5357cee3508SCyrille Pitchen atmel_sha_write(dd, SHA_CR, SHA_CR_FIRST); 5367cee3508SCyrille Pitchen valmr |= SHA_MR_UIHV; 5377cee3508SCyrille Pitchen } 5387cee3508SCyrille Pitchen /* 5397cee3508SCyrille Pitchen * WARNING: If the UIHV feature is not available, the hardware CANNOT 5407cee3508SCyrille Pitchen * process concurrent requests: the internal registers used to store 5417cee3508SCyrille Pitchen * the hash/digest are still set to the partial digest output values 5427cee3508SCyrille Pitchen * computed during the latest round. 5437cee3508SCyrille Pitchen */ 5447cee3508SCyrille Pitchen 545ebc82efaSNicolas Royer atmel_sha_write(dd, SHA_MR, valmr); 546ebc82efaSNicolas Royer } 547ebc82efaSNicolas Royer 5489064ed92SCyrille Pitchen static inline int atmel_sha_wait_for_data_ready(struct atmel_sha_dev *dd, 5499064ed92SCyrille Pitchen atmel_sha_fn_t resume) 5509064ed92SCyrille Pitchen { 5519064ed92SCyrille Pitchen u32 isr = atmel_sha_read(dd, SHA_ISR); 5529064ed92SCyrille Pitchen 5539064ed92SCyrille Pitchen if (unlikely(isr & SHA_INT_DATARDY)) 5549064ed92SCyrille Pitchen return resume(dd); 5559064ed92SCyrille Pitchen 5569064ed92SCyrille Pitchen dd->resume = resume; 5579064ed92SCyrille Pitchen atmel_sha_write(dd, SHA_IER, SHA_INT_DATARDY); 5589064ed92SCyrille Pitchen return -EINPROGRESS; 5599064ed92SCyrille Pitchen } 5609064ed92SCyrille Pitchen 561ebc82efaSNicolas Royer static int atmel_sha_xmit_cpu(struct atmel_sha_dev *dd, const u8 *buf, 562ebc82efaSNicolas Royer size_t length, int final) 563ebc82efaSNicolas Royer { 564ebc82efaSNicolas Royer struct atmel_sha_reqctx *ctx = ahash_request_ctx(dd->req); 565ebc82efaSNicolas Royer int count, len32; 566ebc82efaSNicolas Royer const u32 *buffer = (const u32 *)buf; 567ebc82efaSNicolas Royer 5684c147bcfSArnd Bergmann dev_dbg(dd->dev, "xmit_cpu: digcnt: 0x%llx 0x%llx, length: %zd, final: %d\n", 569d4905b38SNicolas Royer ctx->digcnt[1], ctx->digcnt[0], length, final); 570ebc82efaSNicolas Royer 571ebc82efaSNicolas Royer atmel_sha_write_ctrl(dd, 0); 572ebc82efaSNicolas Royer 573ebc82efaSNicolas Royer /* should be non-zero before next lines to disable clocks later */ 574d4905b38SNicolas Royer ctx->digcnt[0] += length; 575d4905b38SNicolas Royer if (ctx->digcnt[0] < length) 576d4905b38SNicolas Royer ctx->digcnt[1]++; 577ebc82efaSNicolas Royer 578ebc82efaSNicolas Royer if (final) 579ebc82efaSNicolas Royer dd->flags |= SHA_FLAGS_FINAL; /* catch last interrupt */ 580ebc82efaSNicolas Royer 581ebc82efaSNicolas Royer len32 = DIV_ROUND_UP(length, sizeof(u32)); 582ebc82efaSNicolas Royer 583ebc82efaSNicolas Royer dd->flags |= SHA_FLAGS_CPU; 584ebc82efaSNicolas Royer 585ebc82efaSNicolas Royer for (count = 0; count < len32; count++) 586ebc82efaSNicolas Royer atmel_sha_write(dd, SHA_REG_DIN(count), buffer[count]); 587ebc82efaSNicolas Royer 588ebc82efaSNicolas Royer return -EINPROGRESS; 589ebc82efaSNicolas Royer } 590ebc82efaSNicolas Royer 591ebc82efaSNicolas Royer static int atmel_sha_xmit_pdc(struct atmel_sha_dev *dd, dma_addr_t dma_addr1, 592ebc82efaSNicolas Royer size_t length1, dma_addr_t dma_addr2, size_t length2, int final) 593ebc82efaSNicolas Royer { 594ebc82efaSNicolas Royer struct atmel_sha_reqctx *ctx = ahash_request_ctx(dd->req); 595ebc82efaSNicolas Royer int len32; 596ebc82efaSNicolas Royer 5974c147bcfSArnd Bergmann dev_dbg(dd->dev, "xmit_pdc: digcnt: 0x%llx 0x%llx, length: %zd, final: %d\n", 598d4905b38SNicolas Royer ctx->digcnt[1], ctx->digcnt[0], length1, final); 599ebc82efaSNicolas Royer 600ebc82efaSNicolas Royer len32 = DIV_ROUND_UP(length1, sizeof(u32)); 601ebc82efaSNicolas Royer atmel_sha_write(dd, SHA_PTCR, SHA_PTCR_TXTDIS); 602ebc82efaSNicolas Royer atmel_sha_write(dd, SHA_TPR, dma_addr1); 603ebc82efaSNicolas Royer atmel_sha_write(dd, SHA_TCR, len32); 604ebc82efaSNicolas Royer 605ebc82efaSNicolas Royer len32 = DIV_ROUND_UP(length2, sizeof(u32)); 606ebc82efaSNicolas Royer atmel_sha_write(dd, SHA_TNPR, dma_addr2); 607ebc82efaSNicolas Royer atmel_sha_write(dd, SHA_TNCR, len32); 608ebc82efaSNicolas Royer 609ebc82efaSNicolas Royer atmel_sha_write_ctrl(dd, 1); 610ebc82efaSNicolas Royer 611ebc82efaSNicolas Royer /* should be non-zero before next lines to disable clocks later */ 612d4905b38SNicolas Royer ctx->digcnt[0] += length1; 613d4905b38SNicolas Royer if (ctx->digcnt[0] < length1) 614d4905b38SNicolas Royer ctx->digcnt[1]++; 615ebc82efaSNicolas Royer 616ebc82efaSNicolas Royer if (final) 617ebc82efaSNicolas Royer dd->flags |= SHA_FLAGS_FINAL; /* catch last interrupt */ 618ebc82efaSNicolas Royer 619ebc82efaSNicolas Royer dd->flags |= SHA_FLAGS_DMA_ACTIVE; 620ebc82efaSNicolas Royer 621ebc82efaSNicolas Royer /* Start DMA transfer */ 622ebc82efaSNicolas Royer atmel_sha_write(dd, SHA_PTCR, SHA_PTCR_TXTEN); 623ebc82efaSNicolas Royer 624ebc82efaSNicolas Royer return -EINPROGRESS; 625ebc82efaSNicolas Royer } 626ebc82efaSNicolas Royer 627d4905b38SNicolas Royer static void atmel_sha_dma_callback(void *data) 628d4905b38SNicolas Royer { 629d4905b38SNicolas Royer struct atmel_sha_dev *dd = data; 630d4905b38SNicolas Royer 631a29af939SCyrille Pitchen dd->is_async = true; 632a29af939SCyrille Pitchen 633d4905b38SNicolas Royer /* dma_lch_in - completed - wait DATRDY */ 634d4905b38SNicolas Royer atmel_sha_write(dd, SHA_IER, SHA_INT_DATARDY); 635d4905b38SNicolas Royer } 636d4905b38SNicolas Royer 637d4905b38SNicolas Royer static int atmel_sha_xmit_dma(struct atmel_sha_dev *dd, dma_addr_t dma_addr1, 638d4905b38SNicolas Royer size_t length1, dma_addr_t dma_addr2, size_t length2, int final) 639d4905b38SNicolas Royer { 640d4905b38SNicolas Royer struct atmel_sha_reqctx *ctx = ahash_request_ctx(dd->req); 641d4905b38SNicolas Royer struct dma_async_tx_descriptor *in_desc; 642d4905b38SNicolas Royer struct scatterlist sg[2]; 643d4905b38SNicolas Royer 6444c147bcfSArnd Bergmann dev_dbg(dd->dev, "xmit_dma: digcnt: 0x%llx 0x%llx, length: %zd, final: %d\n", 645d4905b38SNicolas Royer ctx->digcnt[1], ctx->digcnt[0], length1, final); 646d4905b38SNicolas Royer 647d4905b38SNicolas Royer dd->dma_lch_in.dma_conf.src_maxburst = 16; 648d4905b38SNicolas Royer dd->dma_lch_in.dma_conf.dst_maxburst = 16; 649d4905b38SNicolas Royer 650d4905b38SNicolas Royer dmaengine_slave_config(dd->dma_lch_in.chan, &dd->dma_lch_in.dma_conf); 651d4905b38SNicolas Royer 652d4905b38SNicolas Royer if (length2) { 653d4905b38SNicolas Royer sg_init_table(sg, 2); 654d4905b38SNicolas Royer sg_dma_address(&sg[0]) = dma_addr1; 655d4905b38SNicolas Royer sg_dma_len(&sg[0]) = length1; 656d4905b38SNicolas Royer sg_dma_address(&sg[1]) = dma_addr2; 657d4905b38SNicolas Royer sg_dma_len(&sg[1]) = length2; 658d4905b38SNicolas Royer in_desc = dmaengine_prep_slave_sg(dd->dma_lch_in.chan, sg, 2, 659d4905b38SNicolas Royer DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); 660d4905b38SNicolas Royer } else { 661d4905b38SNicolas Royer sg_init_table(sg, 1); 662d4905b38SNicolas Royer sg_dma_address(&sg[0]) = dma_addr1; 663d4905b38SNicolas Royer sg_dma_len(&sg[0]) = length1; 664d4905b38SNicolas Royer in_desc = dmaengine_prep_slave_sg(dd->dma_lch_in.chan, sg, 1, 665d4905b38SNicolas Royer DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); 666d4905b38SNicolas Royer } 667d4905b38SNicolas Royer if (!in_desc) 668dd3f9f40SCyrille Pitchen return atmel_sha_complete(dd, -EINVAL); 669d4905b38SNicolas Royer 670d4905b38SNicolas Royer in_desc->callback = atmel_sha_dma_callback; 671d4905b38SNicolas Royer in_desc->callback_param = dd; 672d4905b38SNicolas Royer 673d4905b38SNicolas Royer atmel_sha_write_ctrl(dd, 1); 674d4905b38SNicolas Royer 675d4905b38SNicolas Royer /* should be non-zero before next lines to disable clocks later */ 676d4905b38SNicolas Royer ctx->digcnt[0] += length1; 677d4905b38SNicolas Royer if (ctx->digcnt[0] < length1) 678d4905b38SNicolas Royer ctx->digcnt[1]++; 679d4905b38SNicolas Royer 680d4905b38SNicolas Royer if (final) 681d4905b38SNicolas Royer dd->flags |= SHA_FLAGS_FINAL; /* catch last interrupt */ 682d4905b38SNicolas Royer 683d4905b38SNicolas Royer dd->flags |= SHA_FLAGS_DMA_ACTIVE; 684d4905b38SNicolas Royer 685d4905b38SNicolas Royer /* Start DMA transfer */ 686d4905b38SNicolas Royer dmaengine_submit(in_desc); 687d4905b38SNicolas Royer dma_async_issue_pending(dd->dma_lch_in.chan); 688d4905b38SNicolas Royer 689d4905b38SNicolas Royer return -EINPROGRESS; 690d4905b38SNicolas Royer } 691d4905b38SNicolas Royer 692d4905b38SNicolas Royer static int atmel_sha_xmit_start(struct atmel_sha_dev *dd, dma_addr_t dma_addr1, 693d4905b38SNicolas Royer size_t length1, dma_addr_t dma_addr2, size_t length2, int final) 694d4905b38SNicolas Royer { 695d4905b38SNicolas Royer if (dd->caps.has_dma) 696d4905b38SNicolas Royer return atmel_sha_xmit_dma(dd, dma_addr1, length1, 697d4905b38SNicolas Royer dma_addr2, length2, final); 698d4905b38SNicolas Royer else 699d4905b38SNicolas Royer return atmel_sha_xmit_pdc(dd, dma_addr1, length1, 700d4905b38SNicolas Royer dma_addr2, length2, final); 701d4905b38SNicolas Royer } 702d4905b38SNicolas Royer 703ebc82efaSNicolas Royer static int atmel_sha_update_cpu(struct atmel_sha_dev *dd) 704ebc82efaSNicolas Royer { 705ebc82efaSNicolas Royer struct atmel_sha_reqctx *ctx = ahash_request_ctx(dd->req); 706ebc82efaSNicolas Royer int bufcnt; 707ebc82efaSNicolas Royer 708ebc82efaSNicolas Royer atmel_sha_append_sg(ctx); 709ebc82efaSNicolas Royer atmel_sha_fill_padding(ctx, 0); 710ebc82efaSNicolas Royer bufcnt = ctx->bufcnt; 711ebc82efaSNicolas Royer ctx->bufcnt = 0; 712ebc82efaSNicolas Royer 713ebc82efaSNicolas Royer return atmel_sha_xmit_cpu(dd, ctx->buffer, bufcnt, 1); 714ebc82efaSNicolas Royer } 715ebc82efaSNicolas Royer 716ebc82efaSNicolas Royer static int atmel_sha_xmit_dma_map(struct atmel_sha_dev *dd, 717ebc82efaSNicolas Royer struct atmel_sha_reqctx *ctx, 718ebc82efaSNicolas Royer size_t length, int final) 719ebc82efaSNicolas Royer { 720ebc82efaSNicolas Royer ctx->dma_addr = dma_map_single(dd->dev, ctx->buffer, 721d4905b38SNicolas Royer ctx->buflen + ctx->block_size, DMA_TO_DEVICE); 722ebc82efaSNicolas Royer if (dma_mapping_error(dd->dev, ctx->dma_addr)) { 7234c147bcfSArnd Bergmann dev_err(dd->dev, "dma %zu bytes error\n", ctx->buflen + 724d4905b38SNicolas Royer ctx->block_size); 725dd3f9f40SCyrille Pitchen return atmel_sha_complete(dd, -EINVAL); 726ebc82efaSNicolas Royer } 727ebc82efaSNicolas Royer 728ebc82efaSNicolas Royer ctx->flags &= ~SHA_FLAGS_SG; 729ebc82efaSNicolas Royer 730ebc82efaSNicolas Royer /* next call does not fail... so no unmap in the case of error */ 731d4905b38SNicolas Royer return atmel_sha_xmit_start(dd, ctx->dma_addr, length, 0, 0, final); 732ebc82efaSNicolas Royer } 733ebc82efaSNicolas Royer 734ebc82efaSNicolas Royer static int atmel_sha_update_dma_slow(struct atmel_sha_dev *dd) 735ebc82efaSNicolas Royer { 736ebc82efaSNicolas Royer struct atmel_sha_reqctx *ctx = ahash_request_ctx(dd->req); 737ebc82efaSNicolas Royer unsigned int final; 738ebc82efaSNicolas Royer size_t count; 739ebc82efaSNicolas Royer 740ebc82efaSNicolas Royer atmel_sha_append_sg(ctx); 741ebc82efaSNicolas Royer 742ebc82efaSNicolas Royer final = (ctx->flags & SHA_FLAGS_FINUP) && !ctx->total; 743ebc82efaSNicolas Royer 7444c147bcfSArnd Bergmann dev_dbg(dd->dev, "slow: bufcnt: %zu, digcnt: 0x%llx 0x%llx, final: %d\n", 745d4905b38SNicolas Royer ctx->bufcnt, ctx->digcnt[1], ctx->digcnt[0], final); 746ebc82efaSNicolas Royer 747ebc82efaSNicolas Royer if (final) 748ebc82efaSNicolas Royer atmel_sha_fill_padding(ctx, 0); 749ebc82efaSNicolas Royer 7500099286bSLudovic Desroches if (final || (ctx->bufcnt == ctx->buflen)) { 751ebc82efaSNicolas Royer count = ctx->bufcnt; 752ebc82efaSNicolas Royer ctx->bufcnt = 0; 753ebc82efaSNicolas Royer return atmel_sha_xmit_dma_map(dd, ctx, count, final); 754ebc82efaSNicolas Royer } 755ebc82efaSNicolas Royer 756ebc82efaSNicolas Royer return 0; 757ebc82efaSNicolas Royer } 758ebc82efaSNicolas Royer 759ebc82efaSNicolas Royer static int atmel_sha_update_dma_start(struct atmel_sha_dev *dd) 760ebc82efaSNicolas Royer { 761ebc82efaSNicolas Royer struct atmel_sha_reqctx *ctx = ahash_request_ctx(dd->req); 762ebc82efaSNicolas Royer unsigned int length, final, tail; 763ebc82efaSNicolas Royer struct scatterlist *sg; 764ebc82efaSNicolas Royer unsigned int count; 765ebc82efaSNicolas Royer 766ebc82efaSNicolas Royer if (!ctx->total) 767ebc82efaSNicolas Royer return 0; 768ebc82efaSNicolas Royer 769ebc82efaSNicolas Royer if (ctx->bufcnt || ctx->offset) 770ebc82efaSNicolas Royer return atmel_sha_update_dma_slow(dd); 771ebc82efaSNicolas Royer 7724c147bcfSArnd Bergmann dev_dbg(dd->dev, "fast: digcnt: 0x%llx 0x%llx, bufcnt: %zd, total: %u\n", 773d4905b38SNicolas Royer ctx->digcnt[1], ctx->digcnt[0], ctx->bufcnt, ctx->total); 774ebc82efaSNicolas Royer 775ebc82efaSNicolas Royer sg = ctx->sg; 776ebc82efaSNicolas Royer 777ebc82efaSNicolas Royer if (!IS_ALIGNED(sg->offset, sizeof(u32))) 778ebc82efaSNicolas Royer return atmel_sha_update_dma_slow(dd); 779ebc82efaSNicolas Royer 780d4905b38SNicolas Royer if (!sg_is_last(sg) && !IS_ALIGNED(sg->length, ctx->block_size)) 781d4905b38SNicolas Royer /* size is not ctx->block_size aligned */ 782ebc82efaSNicolas Royer return atmel_sha_update_dma_slow(dd); 783ebc82efaSNicolas Royer 784ebc82efaSNicolas Royer length = min(ctx->total, sg->length); 785ebc82efaSNicolas Royer 786ebc82efaSNicolas Royer if (sg_is_last(sg)) { 787ebc82efaSNicolas Royer if (!(ctx->flags & SHA_FLAGS_FINUP)) { 788d4905b38SNicolas Royer /* not last sg must be ctx->block_size aligned */ 789d4905b38SNicolas Royer tail = length & (ctx->block_size - 1); 790ebc82efaSNicolas Royer length -= tail; 791ebc82efaSNicolas Royer } 792ebc82efaSNicolas Royer } 793ebc82efaSNicolas Royer 794ebc82efaSNicolas Royer ctx->total -= length; 795ebc82efaSNicolas Royer ctx->offset = length; /* offset where to start slow */ 796ebc82efaSNicolas Royer 797ebc82efaSNicolas Royer final = (ctx->flags & SHA_FLAGS_FINUP) && !ctx->total; 798ebc82efaSNicolas Royer 799ebc82efaSNicolas Royer /* Add padding */ 800ebc82efaSNicolas Royer if (final) { 801d4905b38SNicolas Royer tail = length & (ctx->block_size - 1); 802ebc82efaSNicolas Royer length -= tail; 803ebc82efaSNicolas Royer ctx->total += tail; 804ebc82efaSNicolas Royer ctx->offset = length; /* offset where to start slow */ 805ebc82efaSNicolas Royer 806ebc82efaSNicolas Royer sg = ctx->sg; 807ebc82efaSNicolas Royer atmel_sha_append_sg(ctx); 808ebc82efaSNicolas Royer 809ebc82efaSNicolas Royer atmel_sha_fill_padding(ctx, length); 810ebc82efaSNicolas Royer 811ebc82efaSNicolas Royer ctx->dma_addr = dma_map_single(dd->dev, ctx->buffer, 812d4905b38SNicolas Royer ctx->buflen + ctx->block_size, DMA_TO_DEVICE); 813ebc82efaSNicolas Royer if (dma_mapping_error(dd->dev, ctx->dma_addr)) { 8144c147bcfSArnd Bergmann dev_err(dd->dev, "dma %zu bytes error\n", 815d4905b38SNicolas Royer ctx->buflen + ctx->block_size); 816dd3f9f40SCyrille Pitchen return atmel_sha_complete(dd, -EINVAL); 817ebc82efaSNicolas Royer } 818ebc82efaSNicolas Royer 819ebc82efaSNicolas Royer if (length == 0) { 820ebc82efaSNicolas Royer ctx->flags &= ~SHA_FLAGS_SG; 821ebc82efaSNicolas Royer count = ctx->bufcnt; 822ebc82efaSNicolas Royer ctx->bufcnt = 0; 823d4905b38SNicolas Royer return atmel_sha_xmit_start(dd, ctx->dma_addr, count, 0, 824ebc82efaSNicolas Royer 0, final); 825ebc82efaSNicolas Royer } else { 826ebc82efaSNicolas Royer ctx->sg = sg; 827ebc82efaSNicolas Royer if (!dma_map_sg(dd->dev, ctx->sg, 1, 828ebc82efaSNicolas Royer DMA_TO_DEVICE)) { 829ebc82efaSNicolas Royer dev_err(dd->dev, "dma_map_sg error\n"); 830dd3f9f40SCyrille Pitchen return atmel_sha_complete(dd, -EINVAL); 831ebc82efaSNicolas Royer } 832ebc82efaSNicolas Royer 833ebc82efaSNicolas Royer ctx->flags |= SHA_FLAGS_SG; 834ebc82efaSNicolas Royer 835ebc82efaSNicolas Royer count = ctx->bufcnt; 836ebc82efaSNicolas Royer ctx->bufcnt = 0; 837d4905b38SNicolas Royer return atmel_sha_xmit_start(dd, sg_dma_address(ctx->sg), 838ebc82efaSNicolas Royer length, ctx->dma_addr, count, final); 839ebc82efaSNicolas Royer } 840ebc82efaSNicolas Royer } 841ebc82efaSNicolas Royer 842ebc82efaSNicolas Royer if (!dma_map_sg(dd->dev, ctx->sg, 1, DMA_TO_DEVICE)) { 843ebc82efaSNicolas Royer dev_err(dd->dev, "dma_map_sg error\n"); 844dd3f9f40SCyrille Pitchen return atmel_sha_complete(dd, -EINVAL); 845ebc82efaSNicolas Royer } 846ebc82efaSNicolas Royer 847ebc82efaSNicolas Royer ctx->flags |= SHA_FLAGS_SG; 848ebc82efaSNicolas Royer 849ebc82efaSNicolas Royer /* next call does not fail... so no unmap in the case of error */ 850d4905b38SNicolas Royer return atmel_sha_xmit_start(dd, sg_dma_address(ctx->sg), length, 0, 851ebc82efaSNicolas Royer 0, final); 852ebc82efaSNicolas Royer } 853ebc82efaSNicolas Royer 854ebc82efaSNicolas Royer static int atmel_sha_update_dma_stop(struct atmel_sha_dev *dd) 855ebc82efaSNicolas Royer { 856ebc82efaSNicolas Royer struct atmel_sha_reqctx *ctx = ahash_request_ctx(dd->req); 857ebc82efaSNicolas Royer 858ebc82efaSNicolas Royer if (ctx->flags & SHA_FLAGS_SG) { 859ebc82efaSNicolas Royer dma_unmap_sg(dd->dev, ctx->sg, 1, DMA_TO_DEVICE); 860ebc82efaSNicolas Royer if (ctx->sg->length == ctx->offset) { 861ebc82efaSNicolas Royer ctx->sg = sg_next(ctx->sg); 862ebc82efaSNicolas Royer if (ctx->sg) 863ebc82efaSNicolas Royer ctx->offset = 0; 864ebc82efaSNicolas Royer } 865d4905b38SNicolas Royer if (ctx->flags & SHA_FLAGS_PAD) { 866ebc82efaSNicolas Royer dma_unmap_single(dd->dev, ctx->dma_addr, 867d4905b38SNicolas Royer ctx->buflen + ctx->block_size, DMA_TO_DEVICE); 868d4905b38SNicolas Royer } 869ebc82efaSNicolas Royer } else { 870ebc82efaSNicolas Royer dma_unmap_single(dd->dev, ctx->dma_addr, ctx->buflen + 871d4905b38SNicolas Royer ctx->block_size, DMA_TO_DEVICE); 872ebc82efaSNicolas Royer } 873ebc82efaSNicolas Royer 874ebc82efaSNicolas Royer return 0; 875ebc82efaSNicolas Royer } 876ebc82efaSNicolas Royer 877ebc82efaSNicolas Royer static int atmel_sha_update_req(struct atmel_sha_dev *dd) 878ebc82efaSNicolas Royer { 879ebc82efaSNicolas Royer struct ahash_request *req = dd->req; 880ebc82efaSNicolas Royer struct atmel_sha_reqctx *ctx = ahash_request_ctx(req); 881ebc82efaSNicolas Royer int err; 882ebc82efaSNicolas Royer 883d4905b38SNicolas Royer dev_dbg(dd->dev, "update_req: total: %u, digcnt: 0x%llx 0x%llx\n", 884d4905b38SNicolas Royer ctx->total, ctx->digcnt[1], ctx->digcnt[0]); 885ebc82efaSNicolas Royer 886ebc82efaSNicolas Royer if (ctx->flags & SHA_FLAGS_CPU) 887ebc82efaSNicolas Royer err = atmel_sha_update_cpu(dd); 888ebc82efaSNicolas Royer else 889ebc82efaSNicolas Royer err = atmel_sha_update_dma_start(dd); 890ebc82efaSNicolas Royer 891ebc82efaSNicolas Royer /* wait for dma completion before can take more data */ 892d4905b38SNicolas Royer dev_dbg(dd->dev, "update: err: %d, digcnt: 0x%llx 0%llx\n", 893d4905b38SNicolas Royer err, ctx->digcnt[1], ctx->digcnt[0]); 894ebc82efaSNicolas Royer 895ebc82efaSNicolas Royer return err; 896ebc82efaSNicolas Royer } 897ebc82efaSNicolas Royer 898ebc82efaSNicolas Royer static int atmel_sha_final_req(struct atmel_sha_dev *dd) 899ebc82efaSNicolas Royer { 900ebc82efaSNicolas Royer struct ahash_request *req = dd->req; 901ebc82efaSNicolas Royer struct atmel_sha_reqctx *ctx = ahash_request_ctx(req); 902ebc82efaSNicolas Royer int err = 0; 903ebc82efaSNicolas Royer int count; 904ebc82efaSNicolas Royer 905ebc82efaSNicolas Royer if (ctx->bufcnt >= ATMEL_SHA_DMA_THRESHOLD) { 906ebc82efaSNicolas Royer atmel_sha_fill_padding(ctx, 0); 907ebc82efaSNicolas Royer count = ctx->bufcnt; 908ebc82efaSNicolas Royer ctx->bufcnt = 0; 909ebc82efaSNicolas Royer err = atmel_sha_xmit_dma_map(dd, ctx, count, 1); 910ebc82efaSNicolas Royer } 911ebc82efaSNicolas Royer /* faster to handle last block with cpu */ 912ebc82efaSNicolas Royer else { 913ebc82efaSNicolas Royer atmel_sha_fill_padding(ctx, 0); 914ebc82efaSNicolas Royer count = ctx->bufcnt; 915ebc82efaSNicolas Royer ctx->bufcnt = 0; 916ebc82efaSNicolas Royer err = atmel_sha_xmit_cpu(dd, ctx->buffer, count, 1); 917ebc82efaSNicolas Royer } 918ebc82efaSNicolas Royer 919ebc82efaSNicolas Royer dev_dbg(dd->dev, "final_req: err: %d\n", err); 920ebc82efaSNicolas Royer 921ebc82efaSNicolas Royer return err; 922ebc82efaSNicolas Royer } 923ebc82efaSNicolas Royer 924ebc82efaSNicolas Royer static void atmel_sha_copy_hash(struct ahash_request *req) 925ebc82efaSNicolas Royer { 926ebc82efaSNicolas Royer struct atmel_sha_reqctx *ctx = ahash_request_ctx(req); 927ebc82efaSNicolas Royer u32 *hash = (u32 *)ctx->digest; 9287cee3508SCyrille Pitchen unsigned int i, hashsize; 929ebc82efaSNicolas Royer 9307cee3508SCyrille Pitchen switch (ctx->flags & SHA_FLAGS_ALGO_MASK) { 9317cee3508SCyrille Pitchen case SHA_FLAGS_SHA1: 9327cee3508SCyrille Pitchen hashsize = SHA1_DIGEST_SIZE; 9337cee3508SCyrille Pitchen break; 9347cee3508SCyrille Pitchen 9357cee3508SCyrille Pitchen case SHA_FLAGS_SHA224: 9367cee3508SCyrille Pitchen case SHA_FLAGS_SHA256: 9377cee3508SCyrille Pitchen hashsize = SHA256_DIGEST_SIZE; 9387cee3508SCyrille Pitchen break; 9397cee3508SCyrille Pitchen 9407cee3508SCyrille Pitchen case SHA_FLAGS_SHA384: 9417cee3508SCyrille Pitchen case SHA_FLAGS_SHA512: 9427cee3508SCyrille Pitchen hashsize = SHA512_DIGEST_SIZE; 9437cee3508SCyrille Pitchen break; 9447cee3508SCyrille Pitchen 9457cee3508SCyrille Pitchen default: 9467cee3508SCyrille Pitchen /* Should not happen... */ 9477cee3508SCyrille Pitchen return; 9487cee3508SCyrille Pitchen } 9497cee3508SCyrille Pitchen 9507cee3508SCyrille Pitchen for (i = 0; i < hashsize / sizeof(u32); ++i) 951ebc82efaSNicolas Royer hash[i] = atmel_sha_read(ctx->dd, SHA_REG_DIGEST(i)); 9527cee3508SCyrille Pitchen ctx->flags |= SHA_FLAGS_RESTORE; 953ebc82efaSNicolas Royer } 954ebc82efaSNicolas Royer 955ebc82efaSNicolas Royer static void atmel_sha_copy_ready_hash(struct ahash_request *req) 956ebc82efaSNicolas Royer { 957ebc82efaSNicolas Royer struct atmel_sha_reqctx *ctx = ahash_request_ctx(req); 958ebc82efaSNicolas Royer 959ebc82efaSNicolas Royer if (!req->result) 960ebc82efaSNicolas Royer return; 961ebc82efaSNicolas Royer 962f07cebadSCyrille Pitchen switch (ctx->flags & SHA_FLAGS_ALGO_MASK) { 963f07cebadSCyrille Pitchen default: 964f07cebadSCyrille Pitchen case SHA_FLAGS_SHA1: 965ebc82efaSNicolas Royer memcpy(req->result, ctx->digest, SHA1_DIGEST_SIZE); 966f07cebadSCyrille Pitchen break; 967f07cebadSCyrille Pitchen 968f07cebadSCyrille Pitchen case SHA_FLAGS_SHA224: 969d4905b38SNicolas Royer memcpy(req->result, ctx->digest, SHA224_DIGEST_SIZE); 970f07cebadSCyrille Pitchen break; 971f07cebadSCyrille Pitchen 972f07cebadSCyrille Pitchen case SHA_FLAGS_SHA256: 973ebc82efaSNicolas Royer memcpy(req->result, ctx->digest, SHA256_DIGEST_SIZE); 974f07cebadSCyrille Pitchen break; 975f07cebadSCyrille Pitchen 976f07cebadSCyrille Pitchen case SHA_FLAGS_SHA384: 977d4905b38SNicolas Royer memcpy(req->result, ctx->digest, SHA384_DIGEST_SIZE); 978f07cebadSCyrille Pitchen break; 979f07cebadSCyrille Pitchen 980f07cebadSCyrille Pitchen case SHA_FLAGS_SHA512: 981d4905b38SNicolas Royer memcpy(req->result, ctx->digest, SHA512_DIGEST_SIZE); 982f07cebadSCyrille Pitchen break; 983f07cebadSCyrille Pitchen } 984ebc82efaSNicolas Royer } 985ebc82efaSNicolas Royer 986ebc82efaSNicolas Royer static int atmel_sha_finish(struct ahash_request *req) 987ebc82efaSNicolas Royer { 988ebc82efaSNicolas Royer struct atmel_sha_reqctx *ctx = ahash_request_ctx(req); 989ebc82efaSNicolas Royer struct atmel_sha_dev *dd = ctx->dd; 990ebc82efaSNicolas Royer 991d4905b38SNicolas Royer if (ctx->digcnt[0] || ctx->digcnt[1]) 992ebc82efaSNicolas Royer atmel_sha_copy_ready_hash(req); 993ebc82efaSNicolas Royer 9944c147bcfSArnd Bergmann dev_dbg(dd->dev, "digcnt: 0x%llx 0x%llx, bufcnt: %zd\n", ctx->digcnt[1], 995d4905b38SNicolas Royer ctx->digcnt[0], ctx->bufcnt); 996ebc82efaSNicolas Royer 997871b88a8SRahul Pathak return 0; 998ebc82efaSNicolas Royer } 999ebc82efaSNicolas Royer 1000ebc82efaSNicolas Royer static void atmel_sha_finish_req(struct ahash_request *req, int err) 1001ebc82efaSNicolas Royer { 1002ebc82efaSNicolas Royer struct atmel_sha_reqctx *ctx = ahash_request_ctx(req); 1003ebc82efaSNicolas Royer struct atmel_sha_dev *dd = ctx->dd; 1004ebc82efaSNicolas Royer 1005ebc82efaSNicolas Royer if (!err) { 1006ebc82efaSNicolas Royer atmel_sha_copy_hash(req); 1007ebc82efaSNicolas Royer if (SHA_FLAGS_FINAL & dd->flags) 1008ebc82efaSNicolas Royer err = atmel_sha_finish(req); 1009ebc82efaSNicolas Royer } else { 1010ebc82efaSNicolas Royer ctx->flags |= SHA_FLAGS_ERROR; 1011ebc82efaSNicolas Royer } 1012ebc82efaSNicolas Royer 1013ebc82efaSNicolas Royer /* atomic operation is not needed here */ 1014a29af939SCyrille Pitchen (void)atmel_sha_complete(dd, err); 1015ebc82efaSNicolas Royer } 1016ebc82efaSNicolas Royer 1017ebc82efaSNicolas Royer static int atmel_sha_hw_init(struct atmel_sha_dev *dd) 1018ebc82efaSNicolas Royer { 10199d83d299SLABBE Corentin int err; 10209d83d299SLABBE Corentin 1021c033042aSCyrille Pitchen err = clk_enable(dd->iclk); 10229d83d299SLABBE Corentin if (err) 10239d83d299SLABBE Corentin return err; 1024ebc82efaSNicolas Royer 1025d4905b38SNicolas Royer if (!(SHA_FLAGS_INIT & dd->flags)) { 1026ebc82efaSNicolas Royer atmel_sha_write(dd, SHA_CR, SHA_CR_SWRST); 1027ebc82efaSNicolas Royer dd->flags |= SHA_FLAGS_INIT; 1028ebc82efaSNicolas Royer dd->err = 0; 1029ebc82efaSNicolas Royer } 1030ebc82efaSNicolas Royer 1031ebc82efaSNicolas Royer return 0; 1032ebc82efaSNicolas Royer } 1033ebc82efaSNicolas Royer 1034d4905b38SNicolas Royer static inline unsigned int atmel_sha_get_version(struct atmel_sha_dev *dd) 1035d4905b38SNicolas Royer { 1036d4905b38SNicolas Royer return atmel_sha_read(dd, SHA_HW_VERSION) & 0x00000fff; 1037d4905b38SNicolas Royer } 1038d4905b38SNicolas Royer 1039d4905b38SNicolas Royer static void atmel_sha_hw_version_init(struct atmel_sha_dev *dd) 1040d4905b38SNicolas Royer { 1041d4905b38SNicolas Royer atmel_sha_hw_init(dd); 1042d4905b38SNicolas Royer 1043d4905b38SNicolas Royer dd->hw_version = atmel_sha_get_version(dd); 1044d4905b38SNicolas Royer 1045d4905b38SNicolas Royer dev_info(dd->dev, 1046d4905b38SNicolas Royer "version: 0x%x\n", dd->hw_version); 1047d4905b38SNicolas Royer 1048c033042aSCyrille Pitchen clk_disable(dd->iclk); 1049d4905b38SNicolas Royer } 1050d4905b38SNicolas Royer 1051ebc82efaSNicolas Royer static int atmel_sha_handle_queue(struct atmel_sha_dev *dd, 1052ebc82efaSNicolas Royer struct ahash_request *req) 1053ebc82efaSNicolas Royer { 1054ebc82efaSNicolas Royer struct crypto_async_request *async_req, *backlog; 1055a29af939SCyrille Pitchen struct atmel_sha_ctx *ctx; 1056ebc82efaSNicolas Royer unsigned long flags; 1057a29af939SCyrille Pitchen bool start_async; 1058ebc82efaSNicolas Royer int err = 0, ret = 0; 1059ebc82efaSNicolas Royer 1060ebc82efaSNicolas Royer spin_lock_irqsave(&dd->lock, flags); 1061ebc82efaSNicolas Royer if (req) 1062ebc82efaSNicolas Royer ret = ahash_enqueue_request(&dd->queue, req); 1063ebc82efaSNicolas Royer 1064ebc82efaSNicolas Royer if (SHA_FLAGS_BUSY & dd->flags) { 1065ebc82efaSNicolas Royer spin_unlock_irqrestore(&dd->lock, flags); 1066ebc82efaSNicolas Royer return ret; 1067ebc82efaSNicolas Royer } 1068ebc82efaSNicolas Royer 1069ebc82efaSNicolas Royer backlog = crypto_get_backlog(&dd->queue); 1070ebc82efaSNicolas Royer async_req = crypto_dequeue_request(&dd->queue); 1071ebc82efaSNicolas Royer if (async_req) 1072ebc82efaSNicolas Royer dd->flags |= SHA_FLAGS_BUSY; 1073ebc82efaSNicolas Royer 1074ebc82efaSNicolas Royer spin_unlock_irqrestore(&dd->lock, flags); 1075ebc82efaSNicolas Royer 1076ebc82efaSNicolas Royer if (!async_req) 1077ebc82efaSNicolas Royer return ret; 1078ebc82efaSNicolas Royer 1079ebc82efaSNicolas Royer if (backlog) 1080ebc82efaSNicolas Royer backlog->complete(backlog, -EINPROGRESS); 1081ebc82efaSNicolas Royer 1082a29af939SCyrille Pitchen ctx = crypto_tfm_ctx(async_req->tfm); 1083a29af939SCyrille Pitchen 1084a29af939SCyrille Pitchen dd->req = ahash_request_cast(async_req); 1085a29af939SCyrille Pitchen start_async = (dd->req != req); 1086a29af939SCyrille Pitchen dd->is_async = start_async; 108789a82ef8SCyrille Pitchen dd->force_complete = false; 1088a29af939SCyrille Pitchen 1089a29af939SCyrille Pitchen /* WARNING: ctx->start() MAY change dd->is_async. */ 1090a29af939SCyrille Pitchen err = ctx->start(dd); 1091a29af939SCyrille Pitchen return (start_async) ? ret : err; 1092a29af939SCyrille Pitchen } 1093a29af939SCyrille Pitchen 1094b5ce82a7SCyrille Pitchen static int atmel_sha_done(struct atmel_sha_dev *dd); 1095b5ce82a7SCyrille Pitchen 1096a29af939SCyrille Pitchen static int atmel_sha_start(struct atmel_sha_dev *dd) 1097a29af939SCyrille Pitchen { 1098a29af939SCyrille Pitchen struct ahash_request *req = dd->req; 1099a29af939SCyrille Pitchen struct atmel_sha_reqctx *ctx = ahash_request_ctx(req); 1100a29af939SCyrille Pitchen int err; 1101ebc82efaSNicolas Royer 1102ebc82efaSNicolas Royer dev_dbg(dd->dev, "handling new req, op: %lu, nbytes: %d\n", 1103ebc82efaSNicolas Royer ctx->op, req->nbytes); 1104ebc82efaSNicolas Royer 1105ebc82efaSNicolas Royer err = atmel_sha_hw_init(dd); 1106ebc82efaSNicolas Royer if (err) 110719998acbSCyrille Pitchen return atmel_sha_complete(dd, err); 110819998acbSCyrille Pitchen 110919998acbSCyrille Pitchen /* 111019998acbSCyrille Pitchen * atmel_sha_update_req() and atmel_sha_final_req() can return either: 111119998acbSCyrille Pitchen * -EINPROGRESS: the hardware is busy and the SHA driver will resume 111219998acbSCyrille Pitchen * its job later in the done_task. 111319998acbSCyrille Pitchen * This is the main path. 111419998acbSCyrille Pitchen * 111519998acbSCyrille Pitchen * 0: the SHA driver can continue its job then release the hardware 111619998acbSCyrille Pitchen * later, if needed, with atmel_sha_finish_req(). 111719998acbSCyrille Pitchen * This is the alternate path. 111819998acbSCyrille Pitchen * 111919998acbSCyrille Pitchen * < 0: an error has occurred so atmel_sha_complete(dd, err) has already 112019998acbSCyrille Pitchen * been called, hence the hardware has been released. 112119998acbSCyrille Pitchen * The SHA driver must stop its job without calling 112219998acbSCyrille Pitchen * atmel_sha_finish_req(), otherwise atmel_sha_complete() would be 112319998acbSCyrille Pitchen * called a second time. 112419998acbSCyrille Pitchen * 112519998acbSCyrille Pitchen * Please note that currently, atmel_sha_final_req() never returns 0. 112619998acbSCyrille Pitchen */ 1127ebc82efaSNicolas Royer 1128b5ce82a7SCyrille Pitchen dd->resume = atmel_sha_done; 1129ebc82efaSNicolas Royer if (ctx->op == SHA_OP_UPDATE) { 1130ebc82efaSNicolas Royer err = atmel_sha_update_req(dd); 113119998acbSCyrille Pitchen if (!err && (ctx->flags & SHA_FLAGS_FINUP)) 1132ebc82efaSNicolas Royer /* no final() after finup() */ 1133ebc82efaSNicolas Royer err = atmel_sha_final_req(dd); 1134ebc82efaSNicolas Royer } else if (ctx->op == SHA_OP_FINAL) { 1135ebc82efaSNicolas Royer err = atmel_sha_final_req(dd); 1136ebc82efaSNicolas Royer } 1137ebc82efaSNicolas Royer 113819998acbSCyrille Pitchen if (!err) 1139ebc82efaSNicolas Royer /* done_task will not finish it, so do it here */ 1140ebc82efaSNicolas Royer atmel_sha_finish_req(req, err); 1141ebc82efaSNicolas Royer 1142ebc82efaSNicolas Royer dev_dbg(dd->dev, "exit, err: %d\n", err); 1143ebc82efaSNicolas Royer 1144a29af939SCyrille Pitchen return err; 1145ebc82efaSNicolas Royer } 1146ebc82efaSNicolas Royer 1147ebc82efaSNicolas Royer static int atmel_sha_enqueue(struct ahash_request *req, unsigned int op) 1148ebc82efaSNicolas Royer { 1149ebc82efaSNicolas Royer struct atmel_sha_reqctx *ctx = ahash_request_ctx(req); 1150ebc82efaSNicolas Royer struct atmel_sha_ctx *tctx = crypto_tfm_ctx(req->base.tfm); 1151ebc82efaSNicolas Royer struct atmel_sha_dev *dd = tctx->dd; 1152ebc82efaSNicolas Royer 1153ebc82efaSNicolas Royer ctx->op = op; 1154ebc82efaSNicolas Royer 1155ebc82efaSNicolas Royer return atmel_sha_handle_queue(dd, req); 1156ebc82efaSNicolas Royer } 1157ebc82efaSNicolas Royer 1158ebc82efaSNicolas Royer static int atmel_sha_update(struct ahash_request *req) 1159ebc82efaSNicolas Royer { 1160ebc82efaSNicolas Royer struct atmel_sha_reqctx *ctx = ahash_request_ctx(req); 1161ebc82efaSNicolas Royer 1162ebc82efaSNicolas Royer if (!req->nbytes) 1163ebc82efaSNicolas Royer return 0; 1164ebc82efaSNicolas Royer 1165ebc82efaSNicolas Royer ctx->total = req->nbytes; 1166ebc82efaSNicolas Royer ctx->sg = req->src; 1167ebc82efaSNicolas Royer ctx->offset = 0; 1168ebc82efaSNicolas Royer 1169ebc82efaSNicolas Royer if (ctx->flags & SHA_FLAGS_FINUP) { 1170ebc82efaSNicolas Royer if (ctx->bufcnt + ctx->total < ATMEL_SHA_DMA_THRESHOLD) 1171ebc82efaSNicolas Royer /* faster to use CPU for short transfers */ 1172ebc82efaSNicolas Royer ctx->flags |= SHA_FLAGS_CPU; 1173ebc82efaSNicolas Royer } else if (ctx->bufcnt + ctx->total < ctx->buflen) { 1174ebc82efaSNicolas Royer atmel_sha_append_sg(ctx); 1175ebc82efaSNicolas Royer return 0; 1176ebc82efaSNicolas Royer } 1177ebc82efaSNicolas Royer return atmel_sha_enqueue(req, SHA_OP_UPDATE); 1178ebc82efaSNicolas Royer } 1179ebc82efaSNicolas Royer 1180ebc82efaSNicolas Royer static int atmel_sha_final(struct ahash_request *req) 1181ebc82efaSNicolas Royer { 1182ebc82efaSNicolas Royer struct atmel_sha_reqctx *ctx = ahash_request_ctx(req); 1183ebc82efaSNicolas Royer 1184ebc82efaSNicolas Royer ctx->flags |= SHA_FLAGS_FINUP; 1185ebc82efaSNicolas Royer 1186ebc82efaSNicolas Royer if (ctx->flags & SHA_FLAGS_ERROR) 1187ebc82efaSNicolas Royer return 0; /* uncompleted hash is not needed */ 1188ebc82efaSNicolas Royer 1189ad84112aSCyrille Pitchen if (ctx->flags & SHA_FLAGS_PAD) 1190ebc82efaSNicolas Royer /* copy ready hash (+ finalize hmac) */ 1191ebc82efaSNicolas Royer return atmel_sha_finish(req); 1192ebc82efaSNicolas Royer 1193ad84112aSCyrille Pitchen return atmel_sha_enqueue(req, SHA_OP_FINAL); 1194ebc82efaSNicolas Royer } 1195ebc82efaSNicolas Royer 1196ebc82efaSNicolas Royer static int atmel_sha_finup(struct ahash_request *req) 1197ebc82efaSNicolas Royer { 1198ebc82efaSNicolas Royer struct atmel_sha_reqctx *ctx = ahash_request_ctx(req); 1199ebc82efaSNicolas Royer int err1, err2; 1200ebc82efaSNicolas Royer 1201ebc82efaSNicolas Royer ctx->flags |= SHA_FLAGS_FINUP; 1202ebc82efaSNicolas Royer 1203ebc82efaSNicolas Royer err1 = atmel_sha_update(req); 12041606043fSGilad Ben-Yossef if (err1 == -EINPROGRESS || 12051606043fSGilad Ben-Yossef (err1 == -EBUSY && (ahash_request_flags(req) & 12061606043fSGilad Ben-Yossef CRYPTO_TFM_REQ_MAY_BACKLOG))) 1207ebc82efaSNicolas Royer return err1; 1208ebc82efaSNicolas Royer 1209ebc82efaSNicolas Royer /* 1210ebc82efaSNicolas Royer * final() has to be always called to cleanup resources 1211ebc82efaSNicolas Royer * even if udpate() failed, except EINPROGRESS 1212ebc82efaSNicolas Royer */ 1213ebc82efaSNicolas Royer err2 = atmel_sha_final(req); 1214ebc82efaSNicolas Royer 1215ebc82efaSNicolas Royer return err1 ?: err2; 1216ebc82efaSNicolas Royer } 1217ebc82efaSNicolas Royer 1218ebc82efaSNicolas Royer static int atmel_sha_digest(struct ahash_request *req) 1219ebc82efaSNicolas Royer { 1220ebc82efaSNicolas Royer return atmel_sha_init(req) ?: atmel_sha_finup(req); 1221ebc82efaSNicolas Royer } 1222ebc82efaSNicolas Royer 1223cc831d32SCyrille Pitchen 1224cc831d32SCyrille Pitchen static int atmel_sha_export(struct ahash_request *req, void *out) 1225cc831d32SCyrille Pitchen { 1226cc831d32SCyrille Pitchen const struct atmel_sha_reqctx *ctx = ahash_request_ctx(req); 1227cc831d32SCyrille Pitchen 12289c4274d9SCyrille Pitchen memcpy(out, ctx, sizeof(*ctx)); 1229cc831d32SCyrille Pitchen return 0; 1230cc831d32SCyrille Pitchen } 1231cc831d32SCyrille Pitchen 1232cc831d32SCyrille Pitchen static int atmel_sha_import(struct ahash_request *req, const void *in) 1233cc831d32SCyrille Pitchen { 1234cc831d32SCyrille Pitchen struct atmel_sha_reqctx *ctx = ahash_request_ctx(req); 1235cc831d32SCyrille Pitchen 12369c4274d9SCyrille Pitchen memcpy(ctx, in, sizeof(*ctx)); 1237cc831d32SCyrille Pitchen return 0; 1238cc831d32SCyrille Pitchen } 1239cc831d32SCyrille Pitchen 1240be95f0faSSvenning Sørensen static int atmel_sha_cra_init(struct crypto_tfm *tfm) 1241ebc82efaSNicolas Royer { 1242a29af939SCyrille Pitchen struct atmel_sha_ctx *ctx = crypto_tfm_ctx(tfm); 1243a29af939SCyrille Pitchen 1244ebc82efaSNicolas Royer crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm), 12459c4274d9SCyrille Pitchen sizeof(struct atmel_sha_reqctx)); 1246a29af939SCyrille Pitchen ctx->start = atmel_sha_start; 1247ebc82efaSNicolas Royer 1248ebc82efaSNicolas Royer return 0; 1249ebc82efaSNicolas Royer } 1250ebc82efaSNicolas Royer 1251d4905b38SNicolas Royer static struct ahash_alg sha_1_256_algs[] = { 1252ebc82efaSNicolas Royer { 1253ebc82efaSNicolas Royer .init = atmel_sha_init, 1254ebc82efaSNicolas Royer .update = atmel_sha_update, 1255ebc82efaSNicolas Royer .final = atmel_sha_final, 1256ebc82efaSNicolas Royer .finup = atmel_sha_finup, 1257ebc82efaSNicolas Royer .digest = atmel_sha_digest, 1258cc831d32SCyrille Pitchen .export = atmel_sha_export, 1259cc831d32SCyrille Pitchen .import = atmel_sha_import, 1260ebc82efaSNicolas Royer .halg = { 1261ebc82efaSNicolas Royer .digestsize = SHA1_DIGEST_SIZE, 12629c4274d9SCyrille Pitchen .statesize = sizeof(struct atmel_sha_reqctx), 1263ebc82efaSNicolas Royer .base = { 1264ebc82efaSNicolas Royer .cra_name = "sha1", 1265ebc82efaSNicolas Royer .cra_driver_name = "atmel-sha1", 1266ebc82efaSNicolas Royer .cra_priority = 100, 1267be95f0faSSvenning Sørensen .cra_flags = CRYPTO_ALG_ASYNC, 1268ebc82efaSNicolas Royer .cra_blocksize = SHA1_BLOCK_SIZE, 1269ebc82efaSNicolas Royer .cra_ctxsize = sizeof(struct atmel_sha_ctx), 1270ebc82efaSNicolas Royer .cra_alignmask = 0, 1271ebc82efaSNicolas Royer .cra_module = THIS_MODULE, 1272ebc82efaSNicolas Royer .cra_init = atmel_sha_cra_init, 1273ebc82efaSNicolas Royer } 1274ebc82efaSNicolas Royer } 1275ebc82efaSNicolas Royer }, 1276ebc82efaSNicolas Royer { 1277ebc82efaSNicolas Royer .init = atmel_sha_init, 1278ebc82efaSNicolas Royer .update = atmel_sha_update, 1279ebc82efaSNicolas Royer .final = atmel_sha_final, 1280ebc82efaSNicolas Royer .finup = atmel_sha_finup, 1281ebc82efaSNicolas Royer .digest = atmel_sha_digest, 1282cc831d32SCyrille Pitchen .export = atmel_sha_export, 1283cc831d32SCyrille Pitchen .import = atmel_sha_import, 1284ebc82efaSNicolas Royer .halg = { 1285ebc82efaSNicolas Royer .digestsize = SHA256_DIGEST_SIZE, 12869c4274d9SCyrille Pitchen .statesize = sizeof(struct atmel_sha_reqctx), 1287ebc82efaSNicolas Royer .base = { 1288ebc82efaSNicolas Royer .cra_name = "sha256", 1289ebc82efaSNicolas Royer .cra_driver_name = "atmel-sha256", 1290ebc82efaSNicolas Royer .cra_priority = 100, 1291be95f0faSSvenning Sørensen .cra_flags = CRYPTO_ALG_ASYNC, 1292ebc82efaSNicolas Royer .cra_blocksize = SHA256_BLOCK_SIZE, 1293ebc82efaSNicolas Royer .cra_ctxsize = sizeof(struct atmel_sha_ctx), 1294ebc82efaSNicolas Royer .cra_alignmask = 0, 1295ebc82efaSNicolas Royer .cra_module = THIS_MODULE, 1296ebc82efaSNicolas Royer .cra_init = atmel_sha_cra_init, 1297ebc82efaSNicolas Royer } 1298ebc82efaSNicolas Royer } 1299ebc82efaSNicolas Royer }, 1300ebc82efaSNicolas Royer }; 1301ebc82efaSNicolas Royer 1302d4905b38SNicolas Royer static struct ahash_alg sha_224_alg = { 1303d4905b38SNicolas Royer .init = atmel_sha_init, 1304d4905b38SNicolas Royer .update = atmel_sha_update, 1305d4905b38SNicolas Royer .final = atmel_sha_final, 1306d4905b38SNicolas Royer .finup = atmel_sha_finup, 1307d4905b38SNicolas Royer .digest = atmel_sha_digest, 1308cc831d32SCyrille Pitchen .export = atmel_sha_export, 1309cc831d32SCyrille Pitchen .import = atmel_sha_import, 1310d4905b38SNicolas Royer .halg = { 1311d4905b38SNicolas Royer .digestsize = SHA224_DIGEST_SIZE, 13129c4274d9SCyrille Pitchen .statesize = sizeof(struct atmel_sha_reqctx), 1313d4905b38SNicolas Royer .base = { 1314d4905b38SNicolas Royer .cra_name = "sha224", 1315d4905b38SNicolas Royer .cra_driver_name = "atmel-sha224", 1316d4905b38SNicolas Royer .cra_priority = 100, 1317be95f0faSSvenning Sørensen .cra_flags = CRYPTO_ALG_ASYNC, 1318d4905b38SNicolas Royer .cra_blocksize = SHA224_BLOCK_SIZE, 1319d4905b38SNicolas Royer .cra_ctxsize = sizeof(struct atmel_sha_ctx), 1320d4905b38SNicolas Royer .cra_alignmask = 0, 1321d4905b38SNicolas Royer .cra_module = THIS_MODULE, 1322d4905b38SNicolas Royer .cra_init = atmel_sha_cra_init, 1323d4905b38SNicolas Royer } 1324d4905b38SNicolas Royer } 1325d4905b38SNicolas Royer }; 1326d4905b38SNicolas Royer 1327d4905b38SNicolas Royer static struct ahash_alg sha_384_512_algs[] = { 1328d4905b38SNicolas Royer { 1329d4905b38SNicolas Royer .init = atmel_sha_init, 1330d4905b38SNicolas Royer .update = atmel_sha_update, 1331d4905b38SNicolas Royer .final = atmel_sha_final, 1332d4905b38SNicolas Royer .finup = atmel_sha_finup, 1333d4905b38SNicolas Royer .digest = atmel_sha_digest, 1334cc831d32SCyrille Pitchen .export = atmel_sha_export, 1335cc831d32SCyrille Pitchen .import = atmel_sha_import, 1336d4905b38SNicolas Royer .halg = { 1337d4905b38SNicolas Royer .digestsize = SHA384_DIGEST_SIZE, 13389c4274d9SCyrille Pitchen .statesize = sizeof(struct atmel_sha_reqctx), 1339d4905b38SNicolas Royer .base = { 1340d4905b38SNicolas Royer .cra_name = "sha384", 1341d4905b38SNicolas Royer .cra_driver_name = "atmel-sha384", 1342d4905b38SNicolas Royer .cra_priority = 100, 1343be95f0faSSvenning Sørensen .cra_flags = CRYPTO_ALG_ASYNC, 1344d4905b38SNicolas Royer .cra_blocksize = SHA384_BLOCK_SIZE, 1345d4905b38SNicolas Royer .cra_ctxsize = sizeof(struct atmel_sha_ctx), 1346d4905b38SNicolas Royer .cra_alignmask = 0x3, 1347d4905b38SNicolas Royer .cra_module = THIS_MODULE, 1348d4905b38SNicolas Royer .cra_init = atmel_sha_cra_init, 1349d4905b38SNicolas Royer } 1350d4905b38SNicolas Royer } 1351d4905b38SNicolas Royer }, 1352d4905b38SNicolas Royer { 1353d4905b38SNicolas Royer .init = atmel_sha_init, 1354d4905b38SNicolas Royer .update = atmel_sha_update, 1355d4905b38SNicolas Royer .final = atmel_sha_final, 1356d4905b38SNicolas Royer .finup = atmel_sha_finup, 1357d4905b38SNicolas Royer .digest = atmel_sha_digest, 1358cc831d32SCyrille Pitchen .export = atmel_sha_export, 1359cc831d32SCyrille Pitchen .import = atmel_sha_import, 1360d4905b38SNicolas Royer .halg = { 1361d4905b38SNicolas Royer .digestsize = SHA512_DIGEST_SIZE, 13629c4274d9SCyrille Pitchen .statesize = sizeof(struct atmel_sha_reqctx), 1363d4905b38SNicolas Royer .base = { 1364d4905b38SNicolas Royer .cra_name = "sha512", 1365d4905b38SNicolas Royer .cra_driver_name = "atmel-sha512", 1366d4905b38SNicolas Royer .cra_priority = 100, 1367be95f0faSSvenning Sørensen .cra_flags = CRYPTO_ALG_ASYNC, 1368d4905b38SNicolas Royer .cra_blocksize = SHA512_BLOCK_SIZE, 1369d4905b38SNicolas Royer .cra_ctxsize = sizeof(struct atmel_sha_ctx), 1370d4905b38SNicolas Royer .cra_alignmask = 0x3, 1371d4905b38SNicolas Royer .cra_module = THIS_MODULE, 1372d4905b38SNicolas Royer .cra_init = atmel_sha_cra_init, 1373d4905b38SNicolas Royer } 1374d4905b38SNicolas Royer } 1375d4905b38SNicolas Royer }, 1376d4905b38SNicolas Royer }; 1377d4905b38SNicolas Royer 1378f56809c3SCyrille Pitchen static void atmel_sha_queue_task(unsigned long data) 1379f56809c3SCyrille Pitchen { 1380f56809c3SCyrille Pitchen struct atmel_sha_dev *dd = (struct atmel_sha_dev *)data; 1381f56809c3SCyrille Pitchen 1382f56809c3SCyrille Pitchen atmel_sha_handle_queue(dd, NULL); 1383f56809c3SCyrille Pitchen } 1384f56809c3SCyrille Pitchen 1385b5ce82a7SCyrille Pitchen static int atmel_sha_done(struct atmel_sha_dev *dd) 1386ebc82efaSNicolas Royer { 1387ebc82efaSNicolas Royer int err = 0; 1388ebc82efaSNicolas Royer 1389ebc82efaSNicolas Royer if (SHA_FLAGS_CPU & dd->flags) { 1390ebc82efaSNicolas Royer if (SHA_FLAGS_OUTPUT_READY & dd->flags) { 1391ebc82efaSNicolas Royer dd->flags &= ~SHA_FLAGS_OUTPUT_READY; 1392ebc82efaSNicolas Royer goto finish; 1393ebc82efaSNicolas Royer } 1394ebc82efaSNicolas Royer } else if (SHA_FLAGS_DMA_READY & dd->flags) { 1395ebc82efaSNicolas Royer if (SHA_FLAGS_DMA_ACTIVE & dd->flags) { 1396ebc82efaSNicolas Royer dd->flags &= ~SHA_FLAGS_DMA_ACTIVE; 1397ebc82efaSNicolas Royer atmel_sha_update_dma_stop(dd); 1398ebc82efaSNicolas Royer if (dd->err) { 1399ebc82efaSNicolas Royer err = dd->err; 1400ebc82efaSNicolas Royer goto finish; 1401ebc82efaSNicolas Royer } 1402ebc82efaSNicolas Royer } 1403ebc82efaSNicolas Royer if (SHA_FLAGS_OUTPUT_READY & dd->flags) { 1404ebc82efaSNicolas Royer /* hash or semi-hash ready */ 1405ebc82efaSNicolas Royer dd->flags &= ~(SHA_FLAGS_DMA_READY | 1406ebc82efaSNicolas Royer SHA_FLAGS_OUTPUT_READY); 1407ebc82efaSNicolas Royer err = atmel_sha_update_dma_start(dd); 1408ebc82efaSNicolas Royer if (err != -EINPROGRESS) 1409ebc82efaSNicolas Royer goto finish; 1410ebc82efaSNicolas Royer } 1411ebc82efaSNicolas Royer } 1412b5ce82a7SCyrille Pitchen return err; 1413ebc82efaSNicolas Royer 1414ebc82efaSNicolas Royer finish: 1415ebc82efaSNicolas Royer /* finish curent request */ 1416ebc82efaSNicolas Royer atmel_sha_finish_req(dd->req, err); 1417b5ce82a7SCyrille Pitchen 1418b5ce82a7SCyrille Pitchen return err; 1419b5ce82a7SCyrille Pitchen } 1420b5ce82a7SCyrille Pitchen 1421b5ce82a7SCyrille Pitchen static void atmel_sha_done_task(unsigned long data) 1422b5ce82a7SCyrille Pitchen { 1423b5ce82a7SCyrille Pitchen struct atmel_sha_dev *dd = (struct atmel_sha_dev *)data; 1424b5ce82a7SCyrille Pitchen 1425b5ce82a7SCyrille Pitchen dd->is_async = true; 1426b5ce82a7SCyrille Pitchen (void)dd->resume(dd); 1427ebc82efaSNicolas Royer } 1428ebc82efaSNicolas Royer 1429ebc82efaSNicolas Royer static irqreturn_t atmel_sha_irq(int irq, void *dev_id) 1430ebc82efaSNicolas Royer { 1431ebc82efaSNicolas Royer struct atmel_sha_dev *sha_dd = dev_id; 1432ebc82efaSNicolas Royer u32 reg; 1433ebc82efaSNicolas Royer 1434ebc82efaSNicolas Royer reg = atmel_sha_read(sha_dd, SHA_ISR); 1435ebc82efaSNicolas Royer if (reg & atmel_sha_read(sha_dd, SHA_IMR)) { 1436ebc82efaSNicolas Royer atmel_sha_write(sha_dd, SHA_IDR, reg); 1437ebc82efaSNicolas Royer if (SHA_FLAGS_BUSY & sha_dd->flags) { 1438ebc82efaSNicolas Royer sha_dd->flags |= SHA_FLAGS_OUTPUT_READY; 1439ebc82efaSNicolas Royer if (!(SHA_FLAGS_CPU & sha_dd->flags)) 1440ebc82efaSNicolas Royer sha_dd->flags |= SHA_FLAGS_DMA_READY; 1441ebc82efaSNicolas Royer tasklet_schedule(&sha_dd->done_task); 1442ebc82efaSNicolas Royer } else { 1443ebc82efaSNicolas Royer dev_warn(sha_dd->dev, "SHA interrupt when no active requests.\n"); 1444ebc82efaSNicolas Royer } 1445ebc82efaSNicolas Royer return IRQ_HANDLED; 1446ebc82efaSNicolas Royer } 1447ebc82efaSNicolas Royer 1448ebc82efaSNicolas Royer return IRQ_NONE; 1449ebc82efaSNicolas Royer } 1450ebc82efaSNicolas Royer 1451eec12f66SCyrille Pitchen 145269303cf0SCyrille Pitchen /* DMA transfer functions */ 145369303cf0SCyrille Pitchen 145469303cf0SCyrille Pitchen static bool atmel_sha_dma_check_aligned(struct atmel_sha_dev *dd, 145569303cf0SCyrille Pitchen struct scatterlist *sg, 145669303cf0SCyrille Pitchen size_t len) 145769303cf0SCyrille Pitchen { 145869303cf0SCyrille Pitchen struct atmel_sha_dma *dma = &dd->dma_lch_in; 145969303cf0SCyrille Pitchen struct ahash_request *req = dd->req; 146069303cf0SCyrille Pitchen struct atmel_sha_reqctx *ctx = ahash_request_ctx(req); 146169303cf0SCyrille Pitchen size_t bs = ctx->block_size; 146269303cf0SCyrille Pitchen int nents; 146369303cf0SCyrille Pitchen 146469303cf0SCyrille Pitchen for (nents = 0; sg; sg = sg_next(sg), ++nents) { 146569303cf0SCyrille Pitchen if (!IS_ALIGNED(sg->offset, sizeof(u32))) 146669303cf0SCyrille Pitchen return false; 146769303cf0SCyrille Pitchen 146869303cf0SCyrille Pitchen /* 146969303cf0SCyrille Pitchen * This is the last sg, the only one that is allowed to 147069303cf0SCyrille Pitchen * have an unaligned length. 147169303cf0SCyrille Pitchen */ 147269303cf0SCyrille Pitchen if (len <= sg->length) { 147369303cf0SCyrille Pitchen dma->nents = nents + 1; 147469303cf0SCyrille Pitchen dma->last_sg_length = sg->length; 147569303cf0SCyrille Pitchen sg->length = ALIGN(len, sizeof(u32)); 147669303cf0SCyrille Pitchen return true; 147769303cf0SCyrille Pitchen } 147869303cf0SCyrille Pitchen 147969303cf0SCyrille Pitchen /* All other sg lengths MUST be aligned to the block size. */ 148069303cf0SCyrille Pitchen if (!IS_ALIGNED(sg->length, bs)) 148169303cf0SCyrille Pitchen return false; 148269303cf0SCyrille Pitchen 148369303cf0SCyrille Pitchen len -= sg->length; 148469303cf0SCyrille Pitchen } 148569303cf0SCyrille Pitchen 148669303cf0SCyrille Pitchen return false; 148769303cf0SCyrille Pitchen } 148869303cf0SCyrille Pitchen 148969303cf0SCyrille Pitchen static void atmel_sha_dma_callback2(void *data) 149069303cf0SCyrille Pitchen { 149169303cf0SCyrille Pitchen struct atmel_sha_dev *dd = data; 149269303cf0SCyrille Pitchen struct atmel_sha_dma *dma = &dd->dma_lch_in; 149369303cf0SCyrille Pitchen struct scatterlist *sg; 149469303cf0SCyrille Pitchen int nents; 149569303cf0SCyrille Pitchen 149669303cf0SCyrille Pitchen dmaengine_terminate_all(dma->chan); 149769303cf0SCyrille Pitchen dma_unmap_sg(dd->dev, dma->sg, dma->nents, DMA_TO_DEVICE); 149869303cf0SCyrille Pitchen 149969303cf0SCyrille Pitchen sg = dma->sg; 150069303cf0SCyrille Pitchen for (nents = 0; nents < dma->nents - 1; ++nents) 150169303cf0SCyrille Pitchen sg = sg_next(sg); 150269303cf0SCyrille Pitchen sg->length = dma->last_sg_length; 150369303cf0SCyrille Pitchen 150469303cf0SCyrille Pitchen dd->is_async = true; 150569303cf0SCyrille Pitchen (void)atmel_sha_wait_for_data_ready(dd, dd->resume); 150669303cf0SCyrille Pitchen } 150769303cf0SCyrille Pitchen 150869303cf0SCyrille Pitchen static int atmel_sha_dma_start(struct atmel_sha_dev *dd, 150969303cf0SCyrille Pitchen struct scatterlist *src, 151069303cf0SCyrille Pitchen size_t len, 151169303cf0SCyrille Pitchen atmel_sha_fn_t resume) 151269303cf0SCyrille Pitchen { 151369303cf0SCyrille Pitchen struct atmel_sha_dma *dma = &dd->dma_lch_in; 151469303cf0SCyrille Pitchen struct dma_slave_config *config = &dma->dma_conf; 151569303cf0SCyrille Pitchen struct dma_chan *chan = dma->chan; 151669303cf0SCyrille Pitchen struct dma_async_tx_descriptor *desc; 151769303cf0SCyrille Pitchen dma_cookie_t cookie; 151869303cf0SCyrille Pitchen unsigned int sg_len; 151969303cf0SCyrille Pitchen int err; 152069303cf0SCyrille Pitchen 152169303cf0SCyrille Pitchen dd->resume = resume; 152269303cf0SCyrille Pitchen 152369303cf0SCyrille Pitchen /* 152469303cf0SCyrille Pitchen * dma->nents has already been initialized by 152569303cf0SCyrille Pitchen * atmel_sha_dma_check_aligned(). 152669303cf0SCyrille Pitchen */ 152769303cf0SCyrille Pitchen dma->sg = src; 152869303cf0SCyrille Pitchen sg_len = dma_map_sg(dd->dev, dma->sg, dma->nents, DMA_TO_DEVICE); 152969303cf0SCyrille Pitchen if (!sg_len) { 153069303cf0SCyrille Pitchen err = -ENOMEM; 153169303cf0SCyrille Pitchen goto exit; 153269303cf0SCyrille Pitchen } 153369303cf0SCyrille Pitchen 153469303cf0SCyrille Pitchen config->src_maxburst = 16; 153569303cf0SCyrille Pitchen config->dst_maxburst = 16; 153669303cf0SCyrille Pitchen err = dmaengine_slave_config(chan, config); 153769303cf0SCyrille Pitchen if (err) 153869303cf0SCyrille Pitchen goto unmap_sg; 153969303cf0SCyrille Pitchen 154069303cf0SCyrille Pitchen desc = dmaengine_prep_slave_sg(chan, dma->sg, sg_len, DMA_MEM_TO_DEV, 154169303cf0SCyrille Pitchen DMA_PREP_INTERRUPT | DMA_CTRL_ACK); 154269303cf0SCyrille Pitchen if (!desc) { 154369303cf0SCyrille Pitchen err = -ENOMEM; 154469303cf0SCyrille Pitchen goto unmap_sg; 154569303cf0SCyrille Pitchen } 154669303cf0SCyrille Pitchen 154769303cf0SCyrille Pitchen desc->callback = atmel_sha_dma_callback2; 154869303cf0SCyrille Pitchen desc->callback_param = dd; 154969303cf0SCyrille Pitchen cookie = dmaengine_submit(desc); 155069303cf0SCyrille Pitchen err = dma_submit_error(cookie); 155169303cf0SCyrille Pitchen if (err) 155269303cf0SCyrille Pitchen goto unmap_sg; 155369303cf0SCyrille Pitchen 155469303cf0SCyrille Pitchen dma_async_issue_pending(chan); 155569303cf0SCyrille Pitchen 155669303cf0SCyrille Pitchen return -EINPROGRESS; 155769303cf0SCyrille Pitchen 155869303cf0SCyrille Pitchen unmap_sg: 155969303cf0SCyrille Pitchen dma_unmap_sg(dd->dev, dma->sg, dma->nents, DMA_TO_DEVICE); 156069303cf0SCyrille Pitchen exit: 156169303cf0SCyrille Pitchen return atmel_sha_complete(dd, err); 156269303cf0SCyrille Pitchen } 156369303cf0SCyrille Pitchen 156469303cf0SCyrille Pitchen 1565eec12f66SCyrille Pitchen /* CPU transfer functions */ 1566eec12f66SCyrille Pitchen 1567eec12f66SCyrille Pitchen static int atmel_sha_cpu_transfer(struct atmel_sha_dev *dd) 1568eec12f66SCyrille Pitchen { 1569eec12f66SCyrille Pitchen struct ahash_request *req = dd->req; 1570eec12f66SCyrille Pitchen struct atmel_sha_reqctx *ctx = ahash_request_ctx(req); 1571eec12f66SCyrille Pitchen const u32 *words = (const u32 *)ctx->buffer; 1572eec12f66SCyrille Pitchen size_t i, num_words; 1573eec12f66SCyrille Pitchen u32 isr, din, din_inc; 1574eec12f66SCyrille Pitchen 1575eec12f66SCyrille Pitchen din_inc = (ctx->flags & SHA_FLAGS_IDATAR0) ? 0 : 1; 1576eec12f66SCyrille Pitchen for (;;) { 1577eec12f66SCyrille Pitchen /* Write data into the Input Data Registers. */ 1578eec12f66SCyrille Pitchen num_words = DIV_ROUND_UP(ctx->bufcnt, sizeof(u32)); 1579eec12f66SCyrille Pitchen for (i = 0, din = 0; i < num_words; ++i, din += din_inc) 1580eec12f66SCyrille Pitchen atmel_sha_write(dd, SHA_REG_DIN(din), words[i]); 1581eec12f66SCyrille Pitchen 1582eec12f66SCyrille Pitchen ctx->offset += ctx->bufcnt; 1583eec12f66SCyrille Pitchen ctx->total -= ctx->bufcnt; 1584eec12f66SCyrille Pitchen 1585eec12f66SCyrille Pitchen if (!ctx->total) 1586eec12f66SCyrille Pitchen break; 1587eec12f66SCyrille Pitchen 1588eec12f66SCyrille Pitchen /* 1589eec12f66SCyrille Pitchen * Prepare next block: 1590eec12f66SCyrille Pitchen * Fill ctx->buffer now with the next data to be written into 1591eec12f66SCyrille Pitchen * IDATARx: it gives time for the SHA hardware to process 1592eec12f66SCyrille Pitchen * the current data so the SHA_INT_DATARDY flag might be set 1593eec12f66SCyrille Pitchen * in SHA_ISR when polling this register at the beginning of 1594eec12f66SCyrille Pitchen * the next loop. 1595eec12f66SCyrille Pitchen */ 1596eec12f66SCyrille Pitchen ctx->bufcnt = min_t(size_t, ctx->block_size, ctx->total); 1597eec12f66SCyrille Pitchen scatterwalk_map_and_copy(ctx->buffer, ctx->sg, 1598eec12f66SCyrille Pitchen ctx->offset, ctx->bufcnt, 0); 1599eec12f66SCyrille Pitchen 1600eec12f66SCyrille Pitchen /* Wait for hardware to be ready again. */ 1601eec12f66SCyrille Pitchen isr = atmel_sha_read(dd, SHA_ISR); 1602eec12f66SCyrille Pitchen if (!(isr & SHA_INT_DATARDY)) { 1603eec12f66SCyrille Pitchen /* Not ready yet. */ 1604eec12f66SCyrille Pitchen dd->resume = atmel_sha_cpu_transfer; 1605eec12f66SCyrille Pitchen atmel_sha_write(dd, SHA_IER, SHA_INT_DATARDY); 1606eec12f66SCyrille Pitchen return -EINPROGRESS; 1607eec12f66SCyrille Pitchen } 1608eec12f66SCyrille Pitchen } 1609eec12f66SCyrille Pitchen 1610eec12f66SCyrille Pitchen if (unlikely(!(ctx->flags & SHA_FLAGS_WAIT_DATARDY))) 1611eec12f66SCyrille Pitchen return dd->cpu_transfer_complete(dd); 1612eec12f66SCyrille Pitchen 1613eec12f66SCyrille Pitchen return atmel_sha_wait_for_data_ready(dd, dd->cpu_transfer_complete); 1614eec12f66SCyrille Pitchen } 1615eec12f66SCyrille Pitchen 1616eec12f66SCyrille Pitchen static int atmel_sha_cpu_start(struct atmel_sha_dev *dd, 1617eec12f66SCyrille Pitchen struct scatterlist *sg, 1618eec12f66SCyrille Pitchen unsigned int len, 1619eec12f66SCyrille Pitchen bool idatar0_only, 1620eec12f66SCyrille Pitchen bool wait_data_ready, 1621eec12f66SCyrille Pitchen atmel_sha_fn_t resume) 1622eec12f66SCyrille Pitchen { 1623eec12f66SCyrille Pitchen struct ahash_request *req = dd->req; 1624eec12f66SCyrille Pitchen struct atmel_sha_reqctx *ctx = ahash_request_ctx(req); 1625eec12f66SCyrille Pitchen 1626eec12f66SCyrille Pitchen if (!len) 1627eec12f66SCyrille Pitchen return resume(dd); 1628eec12f66SCyrille Pitchen 1629eec12f66SCyrille Pitchen ctx->flags &= ~(SHA_FLAGS_IDATAR0 | SHA_FLAGS_WAIT_DATARDY); 1630eec12f66SCyrille Pitchen 1631eec12f66SCyrille Pitchen if (idatar0_only) 1632eec12f66SCyrille Pitchen ctx->flags |= SHA_FLAGS_IDATAR0; 1633eec12f66SCyrille Pitchen 1634eec12f66SCyrille Pitchen if (wait_data_ready) 1635eec12f66SCyrille Pitchen ctx->flags |= SHA_FLAGS_WAIT_DATARDY; 1636eec12f66SCyrille Pitchen 1637eec12f66SCyrille Pitchen ctx->sg = sg; 1638eec12f66SCyrille Pitchen ctx->total = len; 1639eec12f66SCyrille Pitchen ctx->offset = 0; 1640eec12f66SCyrille Pitchen 1641eec12f66SCyrille Pitchen /* Prepare the first block to be written. */ 1642eec12f66SCyrille Pitchen ctx->bufcnt = min_t(size_t, ctx->block_size, ctx->total); 1643eec12f66SCyrille Pitchen scatterwalk_map_and_copy(ctx->buffer, ctx->sg, 1644eec12f66SCyrille Pitchen ctx->offset, ctx->bufcnt, 0); 1645eec12f66SCyrille Pitchen 1646eec12f66SCyrille Pitchen dd->cpu_transfer_complete = resume; 1647eec12f66SCyrille Pitchen return atmel_sha_cpu_transfer(dd); 1648eec12f66SCyrille Pitchen } 1649eec12f66SCyrille Pitchen 165081d8750bSCyrille Pitchen static int atmel_sha_cpu_hash(struct atmel_sha_dev *dd, 165181d8750bSCyrille Pitchen const void *data, unsigned int datalen, 165281d8750bSCyrille Pitchen bool auto_padding, 165381d8750bSCyrille Pitchen atmel_sha_fn_t resume) 165481d8750bSCyrille Pitchen { 165581d8750bSCyrille Pitchen struct ahash_request *req = dd->req; 165681d8750bSCyrille Pitchen struct atmel_sha_reqctx *ctx = ahash_request_ctx(req); 165781d8750bSCyrille Pitchen u32 msglen = (auto_padding) ? datalen : 0; 165881d8750bSCyrille Pitchen u32 mr = SHA_MR_MODE_AUTO; 165981d8750bSCyrille Pitchen 166081d8750bSCyrille Pitchen if (!(IS_ALIGNED(datalen, ctx->block_size) || auto_padding)) 166181d8750bSCyrille Pitchen return atmel_sha_complete(dd, -EINVAL); 166281d8750bSCyrille Pitchen 166381d8750bSCyrille Pitchen mr |= (ctx->flags & SHA_FLAGS_ALGO_MASK); 166481d8750bSCyrille Pitchen atmel_sha_write(dd, SHA_MR, mr); 166581d8750bSCyrille Pitchen atmel_sha_write(dd, SHA_MSR, msglen); 166681d8750bSCyrille Pitchen atmel_sha_write(dd, SHA_BCR, msglen); 166781d8750bSCyrille Pitchen atmel_sha_write(dd, SHA_CR, SHA_CR_FIRST); 166881d8750bSCyrille Pitchen 166981d8750bSCyrille Pitchen sg_init_one(&dd->tmp, data, datalen); 167081d8750bSCyrille Pitchen return atmel_sha_cpu_start(dd, &dd->tmp, datalen, false, true, resume); 167181d8750bSCyrille Pitchen } 167281d8750bSCyrille Pitchen 167381d8750bSCyrille Pitchen 167481d8750bSCyrille Pitchen /* hmac functions */ 167581d8750bSCyrille Pitchen 167681d8750bSCyrille Pitchen struct atmel_sha_hmac_key { 167781d8750bSCyrille Pitchen bool valid; 167881d8750bSCyrille Pitchen unsigned int keylen; 167981d8750bSCyrille Pitchen u8 buffer[SHA512_BLOCK_SIZE]; 168081d8750bSCyrille Pitchen u8 *keydup; 168181d8750bSCyrille Pitchen }; 168281d8750bSCyrille Pitchen 168381d8750bSCyrille Pitchen static inline void atmel_sha_hmac_key_init(struct atmel_sha_hmac_key *hkey) 168481d8750bSCyrille Pitchen { 168581d8750bSCyrille Pitchen memset(hkey, 0, sizeof(*hkey)); 168681d8750bSCyrille Pitchen } 168781d8750bSCyrille Pitchen 168881d8750bSCyrille Pitchen static inline void atmel_sha_hmac_key_release(struct atmel_sha_hmac_key *hkey) 168981d8750bSCyrille Pitchen { 169081d8750bSCyrille Pitchen kfree(hkey->keydup); 169181d8750bSCyrille Pitchen memset(hkey, 0, sizeof(*hkey)); 169281d8750bSCyrille Pitchen } 169381d8750bSCyrille Pitchen 169481d8750bSCyrille Pitchen static inline int atmel_sha_hmac_key_set(struct atmel_sha_hmac_key *hkey, 169581d8750bSCyrille Pitchen const u8 *key, 169681d8750bSCyrille Pitchen unsigned int keylen) 169781d8750bSCyrille Pitchen { 169881d8750bSCyrille Pitchen atmel_sha_hmac_key_release(hkey); 169981d8750bSCyrille Pitchen 170081d8750bSCyrille Pitchen if (keylen > sizeof(hkey->buffer)) { 170181d8750bSCyrille Pitchen hkey->keydup = kmemdup(key, keylen, GFP_KERNEL); 170281d8750bSCyrille Pitchen if (!hkey->keydup) 170381d8750bSCyrille Pitchen return -ENOMEM; 170481d8750bSCyrille Pitchen 170581d8750bSCyrille Pitchen } else { 170681d8750bSCyrille Pitchen memcpy(hkey->buffer, key, keylen); 170781d8750bSCyrille Pitchen } 170881d8750bSCyrille Pitchen 170981d8750bSCyrille Pitchen hkey->valid = true; 171081d8750bSCyrille Pitchen hkey->keylen = keylen; 171181d8750bSCyrille Pitchen return 0; 171281d8750bSCyrille Pitchen } 171381d8750bSCyrille Pitchen 171481d8750bSCyrille Pitchen static inline bool atmel_sha_hmac_key_get(const struct atmel_sha_hmac_key *hkey, 171581d8750bSCyrille Pitchen const u8 **key, 171681d8750bSCyrille Pitchen unsigned int *keylen) 171781d8750bSCyrille Pitchen { 171881d8750bSCyrille Pitchen if (!hkey->valid) 171981d8750bSCyrille Pitchen return false; 172081d8750bSCyrille Pitchen 172181d8750bSCyrille Pitchen *keylen = hkey->keylen; 172281d8750bSCyrille Pitchen *key = (hkey->keydup) ? hkey->keydup : hkey->buffer; 172381d8750bSCyrille Pitchen return true; 172481d8750bSCyrille Pitchen } 172581d8750bSCyrille Pitchen 172681d8750bSCyrille Pitchen 172781d8750bSCyrille Pitchen struct atmel_sha_hmac_ctx { 172881d8750bSCyrille Pitchen struct atmel_sha_ctx base; 172981d8750bSCyrille Pitchen 173081d8750bSCyrille Pitchen struct atmel_sha_hmac_key hkey; 173181d8750bSCyrille Pitchen u32 ipad[SHA512_BLOCK_SIZE / sizeof(u32)]; 173281d8750bSCyrille Pitchen u32 opad[SHA512_BLOCK_SIZE / sizeof(u32)]; 173381d8750bSCyrille Pitchen atmel_sha_fn_t resume; 173481d8750bSCyrille Pitchen }; 173581d8750bSCyrille Pitchen 173681d8750bSCyrille Pitchen static int atmel_sha_hmac_setup(struct atmel_sha_dev *dd, 173781d8750bSCyrille Pitchen atmel_sha_fn_t resume); 173881d8750bSCyrille Pitchen static int atmel_sha_hmac_prehash_key(struct atmel_sha_dev *dd, 173981d8750bSCyrille Pitchen const u8 *key, unsigned int keylen); 174081d8750bSCyrille Pitchen static int atmel_sha_hmac_prehash_key_done(struct atmel_sha_dev *dd); 174181d8750bSCyrille Pitchen static int atmel_sha_hmac_compute_ipad_hash(struct atmel_sha_dev *dd); 174281d8750bSCyrille Pitchen static int atmel_sha_hmac_compute_opad_hash(struct atmel_sha_dev *dd); 174381d8750bSCyrille Pitchen static int atmel_sha_hmac_setup_done(struct atmel_sha_dev *dd); 174481d8750bSCyrille Pitchen 174581d8750bSCyrille Pitchen static int atmel_sha_hmac_init_done(struct atmel_sha_dev *dd); 174681d8750bSCyrille Pitchen static int atmel_sha_hmac_final(struct atmel_sha_dev *dd); 174781d8750bSCyrille Pitchen static int atmel_sha_hmac_final_done(struct atmel_sha_dev *dd); 174881d8750bSCyrille Pitchen static int atmel_sha_hmac_digest2(struct atmel_sha_dev *dd); 174981d8750bSCyrille Pitchen 175081d8750bSCyrille Pitchen static int atmel_sha_hmac_setup(struct atmel_sha_dev *dd, 175181d8750bSCyrille Pitchen atmel_sha_fn_t resume) 175281d8750bSCyrille Pitchen { 175381d8750bSCyrille Pitchen struct ahash_request *req = dd->req; 175481d8750bSCyrille Pitchen struct atmel_sha_reqctx *ctx = ahash_request_ctx(req); 175581d8750bSCyrille Pitchen struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); 175681d8750bSCyrille Pitchen struct atmel_sha_hmac_ctx *hmac = crypto_ahash_ctx(tfm); 175781d8750bSCyrille Pitchen unsigned int keylen; 175881d8750bSCyrille Pitchen const u8 *key; 175981d8750bSCyrille Pitchen size_t bs; 176081d8750bSCyrille Pitchen 176181d8750bSCyrille Pitchen hmac->resume = resume; 176281d8750bSCyrille Pitchen switch (ctx->flags & SHA_FLAGS_ALGO_MASK) { 176381d8750bSCyrille Pitchen case SHA_FLAGS_SHA1: 176481d8750bSCyrille Pitchen ctx->block_size = SHA1_BLOCK_SIZE; 176581d8750bSCyrille Pitchen ctx->hash_size = SHA1_DIGEST_SIZE; 176681d8750bSCyrille Pitchen break; 176781d8750bSCyrille Pitchen 176881d8750bSCyrille Pitchen case SHA_FLAGS_SHA224: 176981d8750bSCyrille Pitchen ctx->block_size = SHA224_BLOCK_SIZE; 177081d8750bSCyrille Pitchen ctx->hash_size = SHA256_DIGEST_SIZE; 177181d8750bSCyrille Pitchen break; 177281d8750bSCyrille Pitchen 177381d8750bSCyrille Pitchen case SHA_FLAGS_SHA256: 177481d8750bSCyrille Pitchen ctx->block_size = SHA256_BLOCK_SIZE; 177581d8750bSCyrille Pitchen ctx->hash_size = SHA256_DIGEST_SIZE; 177681d8750bSCyrille Pitchen break; 177781d8750bSCyrille Pitchen 177881d8750bSCyrille Pitchen case SHA_FLAGS_SHA384: 177981d8750bSCyrille Pitchen ctx->block_size = SHA384_BLOCK_SIZE; 178081d8750bSCyrille Pitchen ctx->hash_size = SHA512_DIGEST_SIZE; 178181d8750bSCyrille Pitchen break; 178281d8750bSCyrille Pitchen 178381d8750bSCyrille Pitchen case SHA_FLAGS_SHA512: 178481d8750bSCyrille Pitchen ctx->block_size = SHA512_BLOCK_SIZE; 178581d8750bSCyrille Pitchen ctx->hash_size = SHA512_DIGEST_SIZE; 178681d8750bSCyrille Pitchen break; 178781d8750bSCyrille Pitchen 178881d8750bSCyrille Pitchen default: 178981d8750bSCyrille Pitchen return atmel_sha_complete(dd, -EINVAL); 179081d8750bSCyrille Pitchen } 179181d8750bSCyrille Pitchen bs = ctx->block_size; 179281d8750bSCyrille Pitchen 179381d8750bSCyrille Pitchen if (likely(!atmel_sha_hmac_key_get(&hmac->hkey, &key, &keylen))) 179481d8750bSCyrille Pitchen return resume(dd); 179581d8750bSCyrille Pitchen 179681d8750bSCyrille Pitchen /* Compute K' from K. */ 179781d8750bSCyrille Pitchen if (unlikely(keylen > bs)) 179881d8750bSCyrille Pitchen return atmel_sha_hmac_prehash_key(dd, key, keylen); 179981d8750bSCyrille Pitchen 180081d8750bSCyrille Pitchen /* Prepare ipad. */ 180181d8750bSCyrille Pitchen memcpy((u8 *)hmac->ipad, key, keylen); 180281d8750bSCyrille Pitchen memset((u8 *)hmac->ipad + keylen, 0, bs - keylen); 180381d8750bSCyrille Pitchen return atmel_sha_hmac_compute_ipad_hash(dd); 180481d8750bSCyrille Pitchen } 180581d8750bSCyrille Pitchen 180681d8750bSCyrille Pitchen static int atmel_sha_hmac_prehash_key(struct atmel_sha_dev *dd, 180781d8750bSCyrille Pitchen const u8 *key, unsigned int keylen) 180881d8750bSCyrille Pitchen { 180981d8750bSCyrille Pitchen return atmel_sha_cpu_hash(dd, key, keylen, true, 181081d8750bSCyrille Pitchen atmel_sha_hmac_prehash_key_done); 181181d8750bSCyrille Pitchen } 181281d8750bSCyrille Pitchen 181381d8750bSCyrille Pitchen static int atmel_sha_hmac_prehash_key_done(struct atmel_sha_dev *dd) 181481d8750bSCyrille Pitchen { 181581d8750bSCyrille Pitchen struct ahash_request *req = dd->req; 181681d8750bSCyrille Pitchen struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); 181781d8750bSCyrille Pitchen struct atmel_sha_hmac_ctx *hmac = crypto_ahash_ctx(tfm); 181881d8750bSCyrille Pitchen struct atmel_sha_reqctx *ctx = ahash_request_ctx(req); 181981d8750bSCyrille Pitchen size_t ds = crypto_ahash_digestsize(tfm); 182081d8750bSCyrille Pitchen size_t bs = ctx->block_size; 182181d8750bSCyrille Pitchen size_t i, num_words = ds / sizeof(u32); 182281d8750bSCyrille Pitchen 182381d8750bSCyrille Pitchen /* Prepare ipad. */ 182481d8750bSCyrille Pitchen for (i = 0; i < num_words; ++i) 182581d8750bSCyrille Pitchen hmac->ipad[i] = atmel_sha_read(dd, SHA_REG_DIGEST(i)); 182681d8750bSCyrille Pitchen memset((u8 *)hmac->ipad + ds, 0, bs - ds); 182781d8750bSCyrille Pitchen return atmel_sha_hmac_compute_ipad_hash(dd); 182881d8750bSCyrille Pitchen } 182981d8750bSCyrille Pitchen 183081d8750bSCyrille Pitchen static int atmel_sha_hmac_compute_ipad_hash(struct atmel_sha_dev *dd) 183181d8750bSCyrille Pitchen { 183281d8750bSCyrille Pitchen struct ahash_request *req = dd->req; 183381d8750bSCyrille Pitchen struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); 183481d8750bSCyrille Pitchen struct atmel_sha_hmac_ctx *hmac = crypto_ahash_ctx(tfm); 183581d8750bSCyrille Pitchen struct atmel_sha_reqctx *ctx = ahash_request_ctx(req); 183681d8750bSCyrille Pitchen size_t bs = ctx->block_size; 183781d8750bSCyrille Pitchen size_t i, num_words = bs / sizeof(u32); 183881d8750bSCyrille Pitchen 183981d8750bSCyrille Pitchen memcpy(hmac->opad, hmac->ipad, bs); 184081d8750bSCyrille Pitchen for (i = 0; i < num_words; ++i) { 184181d8750bSCyrille Pitchen hmac->ipad[i] ^= 0x36363636; 184281d8750bSCyrille Pitchen hmac->opad[i] ^= 0x5c5c5c5c; 184381d8750bSCyrille Pitchen } 184481d8750bSCyrille Pitchen 184581d8750bSCyrille Pitchen return atmel_sha_cpu_hash(dd, hmac->ipad, bs, false, 184681d8750bSCyrille Pitchen atmel_sha_hmac_compute_opad_hash); 184781d8750bSCyrille Pitchen } 184881d8750bSCyrille Pitchen 184981d8750bSCyrille Pitchen static int atmel_sha_hmac_compute_opad_hash(struct atmel_sha_dev *dd) 185081d8750bSCyrille Pitchen { 185181d8750bSCyrille Pitchen struct ahash_request *req = dd->req; 185281d8750bSCyrille Pitchen struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); 185381d8750bSCyrille Pitchen struct atmel_sha_hmac_ctx *hmac = crypto_ahash_ctx(tfm); 185481d8750bSCyrille Pitchen struct atmel_sha_reqctx *ctx = ahash_request_ctx(req); 185581d8750bSCyrille Pitchen size_t bs = ctx->block_size; 185681d8750bSCyrille Pitchen size_t hs = ctx->hash_size; 185781d8750bSCyrille Pitchen size_t i, num_words = hs / sizeof(u32); 185881d8750bSCyrille Pitchen 185981d8750bSCyrille Pitchen for (i = 0; i < num_words; ++i) 186081d8750bSCyrille Pitchen hmac->ipad[i] = atmel_sha_read(dd, SHA_REG_DIGEST(i)); 186181d8750bSCyrille Pitchen return atmel_sha_cpu_hash(dd, hmac->opad, bs, false, 186281d8750bSCyrille Pitchen atmel_sha_hmac_setup_done); 186381d8750bSCyrille Pitchen } 186481d8750bSCyrille Pitchen 186581d8750bSCyrille Pitchen static int atmel_sha_hmac_setup_done(struct atmel_sha_dev *dd) 186681d8750bSCyrille Pitchen { 186781d8750bSCyrille Pitchen struct ahash_request *req = dd->req; 186881d8750bSCyrille Pitchen struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); 186981d8750bSCyrille Pitchen struct atmel_sha_hmac_ctx *hmac = crypto_ahash_ctx(tfm); 187081d8750bSCyrille Pitchen struct atmel_sha_reqctx *ctx = ahash_request_ctx(req); 187181d8750bSCyrille Pitchen size_t hs = ctx->hash_size; 187281d8750bSCyrille Pitchen size_t i, num_words = hs / sizeof(u32); 187381d8750bSCyrille Pitchen 187481d8750bSCyrille Pitchen for (i = 0; i < num_words; ++i) 187581d8750bSCyrille Pitchen hmac->opad[i] = atmel_sha_read(dd, SHA_REG_DIGEST(i)); 187681d8750bSCyrille Pitchen atmel_sha_hmac_key_release(&hmac->hkey); 187781d8750bSCyrille Pitchen return hmac->resume(dd); 187881d8750bSCyrille Pitchen } 187981d8750bSCyrille Pitchen 188081d8750bSCyrille Pitchen static int atmel_sha_hmac_start(struct atmel_sha_dev *dd) 188181d8750bSCyrille Pitchen { 188281d8750bSCyrille Pitchen struct ahash_request *req = dd->req; 188381d8750bSCyrille Pitchen struct atmel_sha_reqctx *ctx = ahash_request_ctx(req); 188481d8750bSCyrille Pitchen int err; 188581d8750bSCyrille Pitchen 188681d8750bSCyrille Pitchen err = atmel_sha_hw_init(dd); 188781d8750bSCyrille Pitchen if (err) 188881d8750bSCyrille Pitchen return atmel_sha_complete(dd, err); 188981d8750bSCyrille Pitchen 189081d8750bSCyrille Pitchen switch (ctx->op) { 189181d8750bSCyrille Pitchen case SHA_OP_INIT: 189281d8750bSCyrille Pitchen err = atmel_sha_hmac_setup(dd, atmel_sha_hmac_init_done); 189381d8750bSCyrille Pitchen break; 189481d8750bSCyrille Pitchen 189581d8750bSCyrille Pitchen case SHA_OP_UPDATE: 189681d8750bSCyrille Pitchen dd->resume = atmel_sha_done; 189781d8750bSCyrille Pitchen err = atmel_sha_update_req(dd); 189881d8750bSCyrille Pitchen break; 189981d8750bSCyrille Pitchen 190081d8750bSCyrille Pitchen case SHA_OP_FINAL: 190181d8750bSCyrille Pitchen dd->resume = atmel_sha_hmac_final; 190281d8750bSCyrille Pitchen err = atmel_sha_final_req(dd); 190381d8750bSCyrille Pitchen break; 190481d8750bSCyrille Pitchen 190581d8750bSCyrille Pitchen case SHA_OP_DIGEST: 190681d8750bSCyrille Pitchen err = atmel_sha_hmac_setup(dd, atmel_sha_hmac_digest2); 190781d8750bSCyrille Pitchen break; 190881d8750bSCyrille Pitchen 190981d8750bSCyrille Pitchen default: 191081d8750bSCyrille Pitchen return atmel_sha_complete(dd, -EINVAL); 191181d8750bSCyrille Pitchen } 191281d8750bSCyrille Pitchen 191381d8750bSCyrille Pitchen return err; 191481d8750bSCyrille Pitchen } 191581d8750bSCyrille Pitchen 191681d8750bSCyrille Pitchen static int atmel_sha_hmac_setkey(struct crypto_ahash *tfm, const u8 *key, 191781d8750bSCyrille Pitchen unsigned int keylen) 191881d8750bSCyrille Pitchen { 191981d8750bSCyrille Pitchen struct atmel_sha_hmac_ctx *hmac = crypto_ahash_ctx(tfm); 192081d8750bSCyrille Pitchen 192181d8750bSCyrille Pitchen if (atmel_sha_hmac_key_set(&hmac->hkey, key, keylen)) { 192281d8750bSCyrille Pitchen crypto_ahash_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN); 192381d8750bSCyrille Pitchen return -EINVAL; 192481d8750bSCyrille Pitchen } 192581d8750bSCyrille Pitchen 192681d8750bSCyrille Pitchen return 0; 192781d8750bSCyrille Pitchen } 192881d8750bSCyrille Pitchen 192981d8750bSCyrille Pitchen static int atmel_sha_hmac_init(struct ahash_request *req) 193081d8750bSCyrille Pitchen { 193181d8750bSCyrille Pitchen int err; 193281d8750bSCyrille Pitchen 193381d8750bSCyrille Pitchen err = atmel_sha_init(req); 193481d8750bSCyrille Pitchen if (err) 193581d8750bSCyrille Pitchen return err; 193681d8750bSCyrille Pitchen 193781d8750bSCyrille Pitchen return atmel_sha_enqueue(req, SHA_OP_INIT); 193881d8750bSCyrille Pitchen } 193981d8750bSCyrille Pitchen 194081d8750bSCyrille Pitchen static int atmel_sha_hmac_init_done(struct atmel_sha_dev *dd) 194181d8750bSCyrille Pitchen { 194281d8750bSCyrille Pitchen struct ahash_request *req = dd->req; 194381d8750bSCyrille Pitchen struct atmel_sha_reqctx *ctx = ahash_request_ctx(req); 194481d8750bSCyrille Pitchen struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); 194581d8750bSCyrille Pitchen struct atmel_sha_hmac_ctx *hmac = crypto_ahash_ctx(tfm); 194681d8750bSCyrille Pitchen size_t bs = ctx->block_size; 194781d8750bSCyrille Pitchen size_t hs = ctx->hash_size; 194881d8750bSCyrille Pitchen 194981d8750bSCyrille Pitchen ctx->bufcnt = 0; 195081d8750bSCyrille Pitchen ctx->digcnt[0] = bs; 195181d8750bSCyrille Pitchen ctx->digcnt[1] = 0; 195281d8750bSCyrille Pitchen ctx->flags |= SHA_FLAGS_RESTORE; 195381d8750bSCyrille Pitchen memcpy(ctx->digest, hmac->ipad, hs); 195481d8750bSCyrille Pitchen return atmel_sha_complete(dd, 0); 195581d8750bSCyrille Pitchen } 195681d8750bSCyrille Pitchen 195781d8750bSCyrille Pitchen static int atmel_sha_hmac_final(struct atmel_sha_dev *dd) 195881d8750bSCyrille Pitchen { 195981d8750bSCyrille Pitchen struct ahash_request *req = dd->req; 196081d8750bSCyrille Pitchen struct atmel_sha_reqctx *ctx = ahash_request_ctx(req); 196181d8750bSCyrille Pitchen struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); 196281d8750bSCyrille Pitchen struct atmel_sha_hmac_ctx *hmac = crypto_ahash_ctx(tfm); 196381d8750bSCyrille Pitchen u32 *digest = (u32 *)ctx->digest; 196481d8750bSCyrille Pitchen size_t ds = crypto_ahash_digestsize(tfm); 196581d8750bSCyrille Pitchen size_t bs = ctx->block_size; 196681d8750bSCyrille Pitchen size_t hs = ctx->hash_size; 196781d8750bSCyrille Pitchen size_t i, num_words; 196881d8750bSCyrille Pitchen u32 mr; 196981d8750bSCyrille Pitchen 197081d8750bSCyrille Pitchen /* Save d = SHA((K' + ipad) | msg). */ 197181d8750bSCyrille Pitchen num_words = ds / sizeof(u32); 197281d8750bSCyrille Pitchen for (i = 0; i < num_words; ++i) 197381d8750bSCyrille Pitchen digest[i] = atmel_sha_read(dd, SHA_REG_DIGEST(i)); 197481d8750bSCyrille Pitchen 197581d8750bSCyrille Pitchen /* Restore context to finish computing SHA((K' + opad) | d). */ 197681d8750bSCyrille Pitchen atmel_sha_write(dd, SHA_CR, SHA_CR_WUIHV); 197781d8750bSCyrille Pitchen num_words = hs / sizeof(u32); 197881d8750bSCyrille Pitchen for (i = 0; i < num_words; ++i) 197981d8750bSCyrille Pitchen atmel_sha_write(dd, SHA_REG_DIN(i), hmac->opad[i]); 198081d8750bSCyrille Pitchen 198181d8750bSCyrille Pitchen mr = SHA_MR_MODE_AUTO | SHA_MR_UIHV; 198281d8750bSCyrille Pitchen mr |= (ctx->flags & SHA_FLAGS_ALGO_MASK); 198381d8750bSCyrille Pitchen atmel_sha_write(dd, SHA_MR, mr); 198481d8750bSCyrille Pitchen atmel_sha_write(dd, SHA_MSR, bs + ds); 198581d8750bSCyrille Pitchen atmel_sha_write(dd, SHA_BCR, ds); 198681d8750bSCyrille Pitchen atmel_sha_write(dd, SHA_CR, SHA_CR_FIRST); 198781d8750bSCyrille Pitchen 198881d8750bSCyrille Pitchen sg_init_one(&dd->tmp, digest, ds); 198981d8750bSCyrille Pitchen return atmel_sha_cpu_start(dd, &dd->tmp, ds, false, true, 199081d8750bSCyrille Pitchen atmel_sha_hmac_final_done); 199181d8750bSCyrille Pitchen } 199281d8750bSCyrille Pitchen 199381d8750bSCyrille Pitchen static int atmel_sha_hmac_final_done(struct atmel_sha_dev *dd) 199481d8750bSCyrille Pitchen { 199581d8750bSCyrille Pitchen /* 199681d8750bSCyrille Pitchen * req->result might not be sizeof(u32) aligned, so copy the 199781d8750bSCyrille Pitchen * digest into ctx->digest[] before memcpy() the data into 199881d8750bSCyrille Pitchen * req->result. 199981d8750bSCyrille Pitchen */ 200081d8750bSCyrille Pitchen atmel_sha_copy_hash(dd->req); 200181d8750bSCyrille Pitchen atmel_sha_copy_ready_hash(dd->req); 200281d8750bSCyrille Pitchen return atmel_sha_complete(dd, 0); 200381d8750bSCyrille Pitchen } 200481d8750bSCyrille Pitchen 200581d8750bSCyrille Pitchen static int atmel_sha_hmac_digest(struct ahash_request *req) 200681d8750bSCyrille Pitchen { 200781d8750bSCyrille Pitchen int err; 200881d8750bSCyrille Pitchen 200981d8750bSCyrille Pitchen err = atmel_sha_init(req); 201081d8750bSCyrille Pitchen if (err) 201181d8750bSCyrille Pitchen return err; 201281d8750bSCyrille Pitchen 201381d8750bSCyrille Pitchen return atmel_sha_enqueue(req, SHA_OP_DIGEST); 201481d8750bSCyrille Pitchen } 201581d8750bSCyrille Pitchen 201681d8750bSCyrille Pitchen static int atmel_sha_hmac_digest2(struct atmel_sha_dev *dd) 201781d8750bSCyrille Pitchen { 201881d8750bSCyrille Pitchen struct ahash_request *req = dd->req; 201981d8750bSCyrille Pitchen struct atmel_sha_reqctx *ctx = ahash_request_ctx(req); 202081d8750bSCyrille Pitchen struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); 202181d8750bSCyrille Pitchen struct atmel_sha_hmac_ctx *hmac = crypto_ahash_ctx(tfm); 202281d8750bSCyrille Pitchen size_t hs = ctx->hash_size; 202381d8750bSCyrille Pitchen size_t i, num_words = hs / sizeof(u32); 202481d8750bSCyrille Pitchen bool use_dma = false; 202581d8750bSCyrille Pitchen u32 mr; 202681d8750bSCyrille Pitchen 202781d8750bSCyrille Pitchen /* Special case for empty message. */ 202881d8750bSCyrille Pitchen if (!req->nbytes) 202981d8750bSCyrille Pitchen return atmel_sha_complete(dd, -EINVAL); // TODO: 203081d8750bSCyrille Pitchen 203181d8750bSCyrille Pitchen /* Check DMA threshold and alignment. */ 203281d8750bSCyrille Pitchen if (req->nbytes > ATMEL_SHA_DMA_THRESHOLD && 203381d8750bSCyrille Pitchen atmel_sha_dma_check_aligned(dd, req->src, req->nbytes)) 203481d8750bSCyrille Pitchen use_dma = true; 203581d8750bSCyrille Pitchen 203681d8750bSCyrille Pitchen /* Write both initial hash values to compute a HMAC. */ 203781d8750bSCyrille Pitchen atmel_sha_write(dd, SHA_CR, SHA_CR_WUIHV); 203881d8750bSCyrille Pitchen for (i = 0; i < num_words; ++i) 203981d8750bSCyrille Pitchen atmel_sha_write(dd, SHA_REG_DIN(i), hmac->ipad[i]); 204081d8750bSCyrille Pitchen 204181d8750bSCyrille Pitchen atmel_sha_write(dd, SHA_CR, SHA_CR_WUIEHV); 204281d8750bSCyrille Pitchen for (i = 0; i < num_words; ++i) 204381d8750bSCyrille Pitchen atmel_sha_write(dd, SHA_REG_DIN(i), hmac->opad[i]); 204481d8750bSCyrille Pitchen 204581d8750bSCyrille Pitchen /* Write the Mode, Message Size, Bytes Count then Control Registers. */ 204681d8750bSCyrille Pitchen mr = (SHA_MR_HMAC | SHA_MR_DUALBUFF); 204781d8750bSCyrille Pitchen mr |= ctx->flags & SHA_FLAGS_ALGO_MASK; 204881d8750bSCyrille Pitchen if (use_dma) 204981d8750bSCyrille Pitchen mr |= SHA_MR_MODE_IDATAR0; 205081d8750bSCyrille Pitchen else 205181d8750bSCyrille Pitchen mr |= SHA_MR_MODE_AUTO; 205281d8750bSCyrille Pitchen atmel_sha_write(dd, SHA_MR, mr); 205381d8750bSCyrille Pitchen 205481d8750bSCyrille Pitchen atmel_sha_write(dd, SHA_MSR, req->nbytes); 205581d8750bSCyrille Pitchen atmel_sha_write(dd, SHA_BCR, req->nbytes); 205681d8750bSCyrille Pitchen 205781d8750bSCyrille Pitchen atmel_sha_write(dd, SHA_CR, SHA_CR_FIRST); 205881d8750bSCyrille Pitchen 205981d8750bSCyrille Pitchen /* Process data. */ 206081d8750bSCyrille Pitchen if (use_dma) 206181d8750bSCyrille Pitchen return atmel_sha_dma_start(dd, req->src, req->nbytes, 206281d8750bSCyrille Pitchen atmel_sha_hmac_final_done); 206381d8750bSCyrille Pitchen 206481d8750bSCyrille Pitchen return atmel_sha_cpu_start(dd, req->src, req->nbytes, false, true, 206581d8750bSCyrille Pitchen atmel_sha_hmac_final_done); 206681d8750bSCyrille Pitchen } 206781d8750bSCyrille Pitchen 206881d8750bSCyrille Pitchen static int atmel_sha_hmac_cra_init(struct crypto_tfm *tfm) 206981d8750bSCyrille Pitchen { 207081d8750bSCyrille Pitchen struct atmel_sha_hmac_ctx *hmac = crypto_tfm_ctx(tfm); 207181d8750bSCyrille Pitchen 207281d8750bSCyrille Pitchen crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm), 207381d8750bSCyrille Pitchen sizeof(struct atmel_sha_reqctx)); 207481d8750bSCyrille Pitchen hmac->base.start = atmel_sha_hmac_start; 207581d8750bSCyrille Pitchen atmel_sha_hmac_key_init(&hmac->hkey); 207681d8750bSCyrille Pitchen 207781d8750bSCyrille Pitchen return 0; 207881d8750bSCyrille Pitchen } 207981d8750bSCyrille Pitchen 208081d8750bSCyrille Pitchen static void atmel_sha_hmac_cra_exit(struct crypto_tfm *tfm) 208181d8750bSCyrille Pitchen { 208281d8750bSCyrille Pitchen struct atmel_sha_hmac_ctx *hmac = crypto_tfm_ctx(tfm); 208381d8750bSCyrille Pitchen 208481d8750bSCyrille Pitchen atmel_sha_hmac_key_release(&hmac->hkey); 208581d8750bSCyrille Pitchen } 208681d8750bSCyrille Pitchen 208781d8750bSCyrille Pitchen static struct ahash_alg sha_hmac_algs[] = { 208881d8750bSCyrille Pitchen { 208981d8750bSCyrille Pitchen .init = atmel_sha_hmac_init, 209081d8750bSCyrille Pitchen .update = atmel_sha_update, 209181d8750bSCyrille Pitchen .final = atmel_sha_final, 209281d8750bSCyrille Pitchen .digest = atmel_sha_hmac_digest, 209381d8750bSCyrille Pitchen .setkey = atmel_sha_hmac_setkey, 209481d8750bSCyrille Pitchen .export = atmel_sha_export, 209581d8750bSCyrille Pitchen .import = atmel_sha_import, 209681d8750bSCyrille Pitchen .halg = { 209781d8750bSCyrille Pitchen .digestsize = SHA1_DIGEST_SIZE, 209881d8750bSCyrille Pitchen .statesize = sizeof(struct atmel_sha_reqctx), 209981d8750bSCyrille Pitchen .base = { 210081d8750bSCyrille Pitchen .cra_name = "hmac(sha1)", 210181d8750bSCyrille Pitchen .cra_driver_name = "atmel-hmac-sha1", 210281d8750bSCyrille Pitchen .cra_priority = 100, 210381d8750bSCyrille Pitchen .cra_flags = CRYPTO_ALG_ASYNC, 210481d8750bSCyrille Pitchen .cra_blocksize = SHA1_BLOCK_SIZE, 210581d8750bSCyrille Pitchen .cra_ctxsize = sizeof(struct atmel_sha_hmac_ctx), 210681d8750bSCyrille Pitchen .cra_alignmask = 0, 210781d8750bSCyrille Pitchen .cra_module = THIS_MODULE, 210881d8750bSCyrille Pitchen .cra_init = atmel_sha_hmac_cra_init, 210981d8750bSCyrille Pitchen .cra_exit = atmel_sha_hmac_cra_exit, 211081d8750bSCyrille Pitchen } 211181d8750bSCyrille Pitchen } 211281d8750bSCyrille Pitchen }, 211381d8750bSCyrille Pitchen { 211481d8750bSCyrille Pitchen .init = atmel_sha_hmac_init, 211581d8750bSCyrille Pitchen .update = atmel_sha_update, 211681d8750bSCyrille Pitchen .final = atmel_sha_final, 211781d8750bSCyrille Pitchen .digest = atmel_sha_hmac_digest, 211881d8750bSCyrille Pitchen .setkey = atmel_sha_hmac_setkey, 211981d8750bSCyrille Pitchen .export = atmel_sha_export, 212081d8750bSCyrille Pitchen .import = atmel_sha_import, 212181d8750bSCyrille Pitchen .halg = { 212281d8750bSCyrille Pitchen .digestsize = SHA224_DIGEST_SIZE, 212381d8750bSCyrille Pitchen .statesize = sizeof(struct atmel_sha_reqctx), 212481d8750bSCyrille Pitchen .base = { 212581d8750bSCyrille Pitchen .cra_name = "hmac(sha224)", 212681d8750bSCyrille Pitchen .cra_driver_name = "atmel-hmac-sha224", 212781d8750bSCyrille Pitchen .cra_priority = 100, 212881d8750bSCyrille Pitchen .cra_flags = CRYPTO_ALG_ASYNC, 212981d8750bSCyrille Pitchen .cra_blocksize = SHA224_BLOCK_SIZE, 213081d8750bSCyrille Pitchen .cra_ctxsize = sizeof(struct atmel_sha_hmac_ctx), 213181d8750bSCyrille Pitchen .cra_alignmask = 0, 213281d8750bSCyrille Pitchen .cra_module = THIS_MODULE, 213381d8750bSCyrille Pitchen .cra_init = atmel_sha_hmac_cra_init, 213481d8750bSCyrille Pitchen .cra_exit = atmel_sha_hmac_cra_exit, 213581d8750bSCyrille Pitchen } 213681d8750bSCyrille Pitchen } 213781d8750bSCyrille Pitchen }, 213881d8750bSCyrille Pitchen { 213981d8750bSCyrille Pitchen .init = atmel_sha_hmac_init, 214081d8750bSCyrille Pitchen .update = atmel_sha_update, 214181d8750bSCyrille Pitchen .final = atmel_sha_final, 214281d8750bSCyrille Pitchen .digest = atmel_sha_hmac_digest, 214381d8750bSCyrille Pitchen .setkey = atmel_sha_hmac_setkey, 214481d8750bSCyrille Pitchen .export = atmel_sha_export, 214581d8750bSCyrille Pitchen .import = atmel_sha_import, 214681d8750bSCyrille Pitchen .halg = { 214781d8750bSCyrille Pitchen .digestsize = SHA256_DIGEST_SIZE, 214881d8750bSCyrille Pitchen .statesize = sizeof(struct atmel_sha_reqctx), 214981d8750bSCyrille Pitchen .base = { 215081d8750bSCyrille Pitchen .cra_name = "hmac(sha256)", 215181d8750bSCyrille Pitchen .cra_driver_name = "atmel-hmac-sha256", 215281d8750bSCyrille Pitchen .cra_priority = 100, 215381d8750bSCyrille Pitchen .cra_flags = CRYPTO_ALG_ASYNC, 215481d8750bSCyrille Pitchen .cra_blocksize = SHA256_BLOCK_SIZE, 215581d8750bSCyrille Pitchen .cra_ctxsize = sizeof(struct atmel_sha_hmac_ctx), 215681d8750bSCyrille Pitchen .cra_alignmask = 0, 215781d8750bSCyrille Pitchen .cra_module = THIS_MODULE, 215881d8750bSCyrille Pitchen .cra_init = atmel_sha_hmac_cra_init, 215981d8750bSCyrille Pitchen .cra_exit = atmel_sha_hmac_cra_exit, 216081d8750bSCyrille Pitchen } 216181d8750bSCyrille Pitchen } 216281d8750bSCyrille Pitchen }, 216381d8750bSCyrille Pitchen { 216481d8750bSCyrille Pitchen .init = atmel_sha_hmac_init, 216581d8750bSCyrille Pitchen .update = atmel_sha_update, 216681d8750bSCyrille Pitchen .final = atmel_sha_final, 216781d8750bSCyrille Pitchen .digest = atmel_sha_hmac_digest, 216881d8750bSCyrille Pitchen .setkey = atmel_sha_hmac_setkey, 216981d8750bSCyrille Pitchen .export = atmel_sha_export, 217081d8750bSCyrille Pitchen .import = atmel_sha_import, 217181d8750bSCyrille Pitchen .halg = { 217281d8750bSCyrille Pitchen .digestsize = SHA384_DIGEST_SIZE, 217381d8750bSCyrille Pitchen .statesize = sizeof(struct atmel_sha_reqctx), 217481d8750bSCyrille Pitchen .base = { 217581d8750bSCyrille Pitchen .cra_name = "hmac(sha384)", 217681d8750bSCyrille Pitchen .cra_driver_name = "atmel-hmac-sha384", 217781d8750bSCyrille Pitchen .cra_priority = 100, 217881d8750bSCyrille Pitchen .cra_flags = CRYPTO_ALG_ASYNC, 217981d8750bSCyrille Pitchen .cra_blocksize = SHA384_BLOCK_SIZE, 218081d8750bSCyrille Pitchen .cra_ctxsize = sizeof(struct atmel_sha_hmac_ctx), 218181d8750bSCyrille Pitchen .cra_alignmask = 0, 218281d8750bSCyrille Pitchen .cra_module = THIS_MODULE, 218381d8750bSCyrille Pitchen .cra_init = atmel_sha_hmac_cra_init, 218481d8750bSCyrille Pitchen .cra_exit = atmel_sha_hmac_cra_exit, 218581d8750bSCyrille Pitchen } 218681d8750bSCyrille Pitchen } 218781d8750bSCyrille Pitchen }, 218881d8750bSCyrille Pitchen { 218981d8750bSCyrille Pitchen .init = atmel_sha_hmac_init, 219081d8750bSCyrille Pitchen .update = atmel_sha_update, 219181d8750bSCyrille Pitchen .final = atmel_sha_final, 219281d8750bSCyrille Pitchen .digest = atmel_sha_hmac_digest, 219381d8750bSCyrille Pitchen .setkey = atmel_sha_hmac_setkey, 219481d8750bSCyrille Pitchen .export = atmel_sha_export, 219581d8750bSCyrille Pitchen .import = atmel_sha_import, 219681d8750bSCyrille Pitchen .halg = { 219781d8750bSCyrille Pitchen .digestsize = SHA512_DIGEST_SIZE, 219881d8750bSCyrille Pitchen .statesize = sizeof(struct atmel_sha_reqctx), 219981d8750bSCyrille Pitchen .base = { 220081d8750bSCyrille Pitchen .cra_name = "hmac(sha512)", 220181d8750bSCyrille Pitchen .cra_driver_name = "atmel-hmac-sha512", 220281d8750bSCyrille Pitchen .cra_priority = 100, 220381d8750bSCyrille Pitchen .cra_flags = CRYPTO_ALG_ASYNC, 220481d8750bSCyrille Pitchen .cra_blocksize = SHA512_BLOCK_SIZE, 220581d8750bSCyrille Pitchen .cra_ctxsize = sizeof(struct atmel_sha_hmac_ctx), 220681d8750bSCyrille Pitchen .cra_alignmask = 0, 220781d8750bSCyrille Pitchen .cra_module = THIS_MODULE, 220881d8750bSCyrille Pitchen .cra_init = atmel_sha_hmac_cra_init, 220981d8750bSCyrille Pitchen .cra_exit = atmel_sha_hmac_cra_exit, 221081d8750bSCyrille Pitchen } 221181d8750bSCyrille Pitchen } 221281d8750bSCyrille Pitchen }, 221381d8750bSCyrille Pitchen }; 2214eec12f66SCyrille Pitchen 22151520c725SHerbert Xu #if IS_ENABLED(CONFIG_CRYPTO_DEV_ATMEL_AUTHENC) 221689a82ef8SCyrille Pitchen /* authenc functions */ 221789a82ef8SCyrille Pitchen 221889a82ef8SCyrille Pitchen static int atmel_sha_authenc_init2(struct atmel_sha_dev *dd); 221989a82ef8SCyrille Pitchen static int atmel_sha_authenc_init_done(struct atmel_sha_dev *dd); 222089a82ef8SCyrille Pitchen static int atmel_sha_authenc_final_done(struct atmel_sha_dev *dd); 222189a82ef8SCyrille Pitchen 222289a82ef8SCyrille Pitchen 222389a82ef8SCyrille Pitchen struct atmel_sha_authenc_ctx { 222489a82ef8SCyrille Pitchen struct crypto_ahash *tfm; 222589a82ef8SCyrille Pitchen }; 222689a82ef8SCyrille Pitchen 222789a82ef8SCyrille Pitchen struct atmel_sha_authenc_reqctx { 222889a82ef8SCyrille Pitchen struct atmel_sha_reqctx base; 222989a82ef8SCyrille Pitchen 223089a82ef8SCyrille Pitchen atmel_aes_authenc_fn_t cb; 223189a82ef8SCyrille Pitchen struct atmel_aes_dev *aes_dev; 223289a82ef8SCyrille Pitchen 223389a82ef8SCyrille Pitchen /* _init() parameters. */ 223489a82ef8SCyrille Pitchen struct scatterlist *assoc; 223589a82ef8SCyrille Pitchen u32 assoclen; 223689a82ef8SCyrille Pitchen u32 textlen; 223789a82ef8SCyrille Pitchen 223889a82ef8SCyrille Pitchen /* _final() parameters. */ 223989a82ef8SCyrille Pitchen u32 *digest; 224089a82ef8SCyrille Pitchen unsigned int digestlen; 224189a82ef8SCyrille Pitchen }; 224289a82ef8SCyrille Pitchen 224389a82ef8SCyrille Pitchen static void atmel_sha_authenc_complete(struct crypto_async_request *areq, 224489a82ef8SCyrille Pitchen int err) 224589a82ef8SCyrille Pitchen { 224689a82ef8SCyrille Pitchen struct ahash_request *req = areq->data; 224789a82ef8SCyrille Pitchen struct atmel_sha_authenc_reqctx *authctx = ahash_request_ctx(req); 224889a82ef8SCyrille Pitchen 224989a82ef8SCyrille Pitchen authctx->cb(authctx->aes_dev, err, authctx->base.dd->is_async); 225089a82ef8SCyrille Pitchen } 225189a82ef8SCyrille Pitchen 225289a82ef8SCyrille Pitchen static int atmel_sha_authenc_start(struct atmel_sha_dev *dd) 225389a82ef8SCyrille Pitchen { 225489a82ef8SCyrille Pitchen struct ahash_request *req = dd->req; 225589a82ef8SCyrille Pitchen struct atmel_sha_authenc_reqctx *authctx = ahash_request_ctx(req); 225689a82ef8SCyrille Pitchen int err; 225789a82ef8SCyrille Pitchen 225889a82ef8SCyrille Pitchen /* 225989a82ef8SCyrille Pitchen * Force atmel_sha_complete() to call req->base.complete(), ie 226089a82ef8SCyrille Pitchen * atmel_sha_authenc_complete(), which in turn calls authctx->cb(). 226189a82ef8SCyrille Pitchen */ 226289a82ef8SCyrille Pitchen dd->force_complete = true; 226389a82ef8SCyrille Pitchen 226489a82ef8SCyrille Pitchen err = atmel_sha_hw_init(dd); 226589a82ef8SCyrille Pitchen return authctx->cb(authctx->aes_dev, err, dd->is_async); 226689a82ef8SCyrille Pitchen } 226789a82ef8SCyrille Pitchen 226889a82ef8SCyrille Pitchen bool atmel_sha_authenc_is_ready(void) 226989a82ef8SCyrille Pitchen { 227089a82ef8SCyrille Pitchen struct atmel_sha_ctx dummy; 227189a82ef8SCyrille Pitchen 227289a82ef8SCyrille Pitchen dummy.dd = NULL; 227389a82ef8SCyrille Pitchen return (atmel_sha_find_dev(&dummy) != NULL); 227489a82ef8SCyrille Pitchen } 227589a82ef8SCyrille Pitchen EXPORT_SYMBOL_GPL(atmel_sha_authenc_is_ready); 227689a82ef8SCyrille Pitchen 227789a82ef8SCyrille Pitchen unsigned int atmel_sha_authenc_get_reqsize(void) 227889a82ef8SCyrille Pitchen { 227989a82ef8SCyrille Pitchen return sizeof(struct atmel_sha_authenc_reqctx); 228089a82ef8SCyrille Pitchen } 228189a82ef8SCyrille Pitchen EXPORT_SYMBOL_GPL(atmel_sha_authenc_get_reqsize); 228289a82ef8SCyrille Pitchen 228389a82ef8SCyrille Pitchen struct atmel_sha_authenc_ctx *atmel_sha_authenc_spawn(unsigned long mode) 228489a82ef8SCyrille Pitchen { 228589a82ef8SCyrille Pitchen struct atmel_sha_authenc_ctx *auth; 228689a82ef8SCyrille Pitchen struct crypto_ahash *tfm; 228789a82ef8SCyrille Pitchen struct atmel_sha_ctx *tctx; 228889a82ef8SCyrille Pitchen const char *name; 228989a82ef8SCyrille Pitchen int err = -EINVAL; 229089a82ef8SCyrille Pitchen 229189a82ef8SCyrille Pitchen switch (mode & SHA_FLAGS_MODE_MASK) { 229289a82ef8SCyrille Pitchen case SHA_FLAGS_HMAC_SHA1: 229389a82ef8SCyrille Pitchen name = "atmel-hmac-sha1"; 229489a82ef8SCyrille Pitchen break; 229589a82ef8SCyrille Pitchen 229689a82ef8SCyrille Pitchen case SHA_FLAGS_HMAC_SHA224: 229789a82ef8SCyrille Pitchen name = "atmel-hmac-sha224"; 229889a82ef8SCyrille Pitchen break; 229989a82ef8SCyrille Pitchen 230089a82ef8SCyrille Pitchen case SHA_FLAGS_HMAC_SHA256: 230189a82ef8SCyrille Pitchen name = "atmel-hmac-sha256"; 230289a82ef8SCyrille Pitchen break; 230389a82ef8SCyrille Pitchen 230489a82ef8SCyrille Pitchen case SHA_FLAGS_HMAC_SHA384: 230589a82ef8SCyrille Pitchen name = "atmel-hmac-sha384"; 230689a82ef8SCyrille Pitchen break; 230789a82ef8SCyrille Pitchen 230889a82ef8SCyrille Pitchen case SHA_FLAGS_HMAC_SHA512: 230989a82ef8SCyrille Pitchen name = "atmel-hmac-sha512"; 231089a82ef8SCyrille Pitchen break; 231189a82ef8SCyrille Pitchen 231289a82ef8SCyrille Pitchen default: 231389a82ef8SCyrille Pitchen goto error; 231489a82ef8SCyrille Pitchen } 231589a82ef8SCyrille Pitchen 231685d7311fSEric Biggers tfm = crypto_alloc_ahash(name, 0, 0); 231789a82ef8SCyrille Pitchen if (IS_ERR(tfm)) { 231889a82ef8SCyrille Pitchen err = PTR_ERR(tfm); 231989a82ef8SCyrille Pitchen goto error; 232089a82ef8SCyrille Pitchen } 232189a82ef8SCyrille Pitchen tctx = crypto_ahash_ctx(tfm); 232289a82ef8SCyrille Pitchen tctx->start = atmel_sha_authenc_start; 232389a82ef8SCyrille Pitchen tctx->flags = mode; 232489a82ef8SCyrille Pitchen 232589a82ef8SCyrille Pitchen auth = kzalloc(sizeof(*auth), GFP_KERNEL); 232689a82ef8SCyrille Pitchen if (!auth) { 232789a82ef8SCyrille Pitchen err = -ENOMEM; 232889a82ef8SCyrille Pitchen goto err_free_ahash; 232989a82ef8SCyrille Pitchen } 233089a82ef8SCyrille Pitchen auth->tfm = tfm; 233189a82ef8SCyrille Pitchen 233289a82ef8SCyrille Pitchen return auth; 233389a82ef8SCyrille Pitchen 233489a82ef8SCyrille Pitchen err_free_ahash: 233589a82ef8SCyrille Pitchen crypto_free_ahash(tfm); 233689a82ef8SCyrille Pitchen error: 233789a82ef8SCyrille Pitchen return ERR_PTR(err); 233889a82ef8SCyrille Pitchen } 233989a82ef8SCyrille Pitchen EXPORT_SYMBOL_GPL(atmel_sha_authenc_spawn); 234089a82ef8SCyrille Pitchen 234189a82ef8SCyrille Pitchen void atmel_sha_authenc_free(struct atmel_sha_authenc_ctx *auth) 234289a82ef8SCyrille Pitchen { 234389a82ef8SCyrille Pitchen if (auth) 234489a82ef8SCyrille Pitchen crypto_free_ahash(auth->tfm); 234589a82ef8SCyrille Pitchen kfree(auth); 234689a82ef8SCyrille Pitchen } 234789a82ef8SCyrille Pitchen EXPORT_SYMBOL_GPL(atmel_sha_authenc_free); 234889a82ef8SCyrille Pitchen 234989a82ef8SCyrille Pitchen int atmel_sha_authenc_setkey(struct atmel_sha_authenc_ctx *auth, 235089a82ef8SCyrille Pitchen const u8 *key, unsigned int keylen, 235189a82ef8SCyrille Pitchen u32 *flags) 235289a82ef8SCyrille Pitchen { 235389a82ef8SCyrille Pitchen struct crypto_ahash *tfm = auth->tfm; 235489a82ef8SCyrille Pitchen int err; 235589a82ef8SCyrille Pitchen 235689a82ef8SCyrille Pitchen crypto_ahash_clear_flags(tfm, CRYPTO_TFM_REQ_MASK); 235789a82ef8SCyrille Pitchen crypto_ahash_set_flags(tfm, *flags & CRYPTO_TFM_REQ_MASK); 235889a82ef8SCyrille Pitchen err = crypto_ahash_setkey(tfm, key, keylen); 235989a82ef8SCyrille Pitchen *flags = crypto_ahash_get_flags(tfm); 236089a82ef8SCyrille Pitchen 236189a82ef8SCyrille Pitchen return err; 236289a82ef8SCyrille Pitchen } 236389a82ef8SCyrille Pitchen EXPORT_SYMBOL_GPL(atmel_sha_authenc_setkey); 236489a82ef8SCyrille Pitchen 236589a82ef8SCyrille Pitchen int atmel_sha_authenc_schedule(struct ahash_request *req, 236689a82ef8SCyrille Pitchen struct atmel_sha_authenc_ctx *auth, 236789a82ef8SCyrille Pitchen atmel_aes_authenc_fn_t cb, 236889a82ef8SCyrille Pitchen struct atmel_aes_dev *aes_dev) 236989a82ef8SCyrille Pitchen { 237089a82ef8SCyrille Pitchen struct atmel_sha_authenc_reqctx *authctx = ahash_request_ctx(req); 237189a82ef8SCyrille Pitchen struct atmel_sha_reqctx *ctx = &authctx->base; 237289a82ef8SCyrille Pitchen struct crypto_ahash *tfm = auth->tfm; 237389a82ef8SCyrille Pitchen struct atmel_sha_ctx *tctx = crypto_ahash_ctx(tfm); 237489a82ef8SCyrille Pitchen struct atmel_sha_dev *dd; 237589a82ef8SCyrille Pitchen 237689a82ef8SCyrille Pitchen /* Reset request context (MUST be done first). */ 237789a82ef8SCyrille Pitchen memset(authctx, 0, sizeof(*authctx)); 237889a82ef8SCyrille Pitchen 237989a82ef8SCyrille Pitchen /* Get SHA device. */ 238089a82ef8SCyrille Pitchen dd = atmel_sha_find_dev(tctx); 238189a82ef8SCyrille Pitchen if (!dd) 238289a82ef8SCyrille Pitchen return cb(aes_dev, -ENODEV, false); 238389a82ef8SCyrille Pitchen 238489a82ef8SCyrille Pitchen /* Init request context. */ 238589a82ef8SCyrille Pitchen ctx->dd = dd; 238689a82ef8SCyrille Pitchen ctx->buflen = SHA_BUFFER_LEN; 238789a82ef8SCyrille Pitchen authctx->cb = cb; 238889a82ef8SCyrille Pitchen authctx->aes_dev = aes_dev; 238989a82ef8SCyrille Pitchen ahash_request_set_tfm(req, tfm); 239089a82ef8SCyrille Pitchen ahash_request_set_callback(req, 0, atmel_sha_authenc_complete, req); 239189a82ef8SCyrille Pitchen 239289a82ef8SCyrille Pitchen return atmel_sha_handle_queue(dd, req); 239389a82ef8SCyrille Pitchen } 239489a82ef8SCyrille Pitchen EXPORT_SYMBOL_GPL(atmel_sha_authenc_schedule); 239589a82ef8SCyrille Pitchen 239689a82ef8SCyrille Pitchen int atmel_sha_authenc_init(struct ahash_request *req, 239789a82ef8SCyrille Pitchen struct scatterlist *assoc, unsigned int assoclen, 239889a82ef8SCyrille Pitchen unsigned int textlen, 239989a82ef8SCyrille Pitchen atmel_aes_authenc_fn_t cb, 240089a82ef8SCyrille Pitchen struct atmel_aes_dev *aes_dev) 240189a82ef8SCyrille Pitchen { 240289a82ef8SCyrille Pitchen struct atmel_sha_authenc_reqctx *authctx = ahash_request_ctx(req); 240389a82ef8SCyrille Pitchen struct atmel_sha_reqctx *ctx = &authctx->base; 240489a82ef8SCyrille Pitchen struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); 240589a82ef8SCyrille Pitchen struct atmel_sha_hmac_ctx *hmac = crypto_ahash_ctx(tfm); 240689a82ef8SCyrille Pitchen struct atmel_sha_dev *dd = ctx->dd; 240789a82ef8SCyrille Pitchen 240889a82ef8SCyrille Pitchen if (unlikely(!IS_ALIGNED(assoclen, sizeof(u32)))) 240989a82ef8SCyrille Pitchen return atmel_sha_complete(dd, -EINVAL); 241089a82ef8SCyrille Pitchen 241189a82ef8SCyrille Pitchen authctx->cb = cb; 241289a82ef8SCyrille Pitchen authctx->aes_dev = aes_dev; 241389a82ef8SCyrille Pitchen authctx->assoc = assoc; 241489a82ef8SCyrille Pitchen authctx->assoclen = assoclen; 241589a82ef8SCyrille Pitchen authctx->textlen = textlen; 241689a82ef8SCyrille Pitchen 241789a82ef8SCyrille Pitchen ctx->flags = hmac->base.flags; 241889a82ef8SCyrille Pitchen return atmel_sha_hmac_setup(dd, atmel_sha_authenc_init2); 241989a82ef8SCyrille Pitchen } 242089a82ef8SCyrille Pitchen EXPORT_SYMBOL_GPL(atmel_sha_authenc_init); 242189a82ef8SCyrille Pitchen 242289a82ef8SCyrille Pitchen static int atmel_sha_authenc_init2(struct atmel_sha_dev *dd) 242389a82ef8SCyrille Pitchen { 242489a82ef8SCyrille Pitchen struct ahash_request *req = dd->req; 242589a82ef8SCyrille Pitchen struct atmel_sha_authenc_reqctx *authctx = ahash_request_ctx(req); 242689a82ef8SCyrille Pitchen struct atmel_sha_reqctx *ctx = &authctx->base; 242789a82ef8SCyrille Pitchen struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); 242889a82ef8SCyrille Pitchen struct atmel_sha_hmac_ctx *hmac = crypto_ahash_ctx(tfm); 242989a82ef8SCyrille Pitchen size_t hs = ctx->hash_size; 243089a82ef8SCyrille Pitchen size_t i, num_words = hs / sizeof(u32); 243189a82ef8SCyrille Pitchen u32 mr, msg_size; 243289a82ef8SCyrille Pitchen 243389a82ef8SCyrille Pitchen atmel_sha_write(dd, SHA_CR, SHA_CR_WUIHV); 243489a82ef8SCyrille Pitchen for (i = 0; i < num_words; ++i) 243589a82ef8SCyrille Pitchen atmel_sha_write(dd, SHA_REG_DIN(i), hmac->ipad[i]); 243689a82ef8SCyrille Pitchen 243789a82ef8SCyrille Pitchen atmel_sha_write(dd, SHA_CR, SHA_CR_WUIEHV); 243889a82ef8SCyrille Pitchen for (i = 0; i < num_words; ++i) 243989a82ef8SCyrille Pitchen atmel_sha_write(dd, SHA_REG_DIN(i), hmac->opad[i]); 244089a82ef8SCyrille Pitchen 244189a82ef8SCyrille Pitchen mr = (SHA_MR_MODE_IDATAR0 | 244289a82ef8SCyrille Pitchen SHA_MR_HMAC | 244389a82ef8SCyrille Pitchen SHA_MR_DUALBUFF); 244489a82ef8SCyrille Pitchen mr |= ctx->flags & SHA_FLAGS_ALGO_MASK; 244589a82ef8SCyrille Pitchen atmel_sha_write(dd, SHA_MR, mr); 244689a82ef8SCyrille Pitchen 244789a82ef8SCyrille Pitchen msg_size = authctx->assoclen + authctx->textlen; 244889a82ef8SCyrille Pitchen atmel_sha_write(dd, SHA_MSR, msg_size); 244989a82ef8SCyrille Pitchen atmel_sha_write(dd, SHA_BCR, msg_size); 245089a82ef8SCyrille Pitchen 245189a82ef8SCyrille Pitchen atmel_sha_write(dd, SHA_CR, SHA_CR_FIRST); 245289a82ef8SCyrille Pitchen 245389a82ef8SCyrille Pitchen /* Process assoc data. */ 245489a82ef8SCyrille Pitchen return atmel_sha_cpu_start(dd, authctx->assoc, authctx->assoclen, 245589a82ef8SCyrille Pitchen true, false, 245689a82ef8SCyrille Pitchen atmel_sha_authenc_init_done); 245789a82ef8SCyrille Pitchen } 245889a82ef8SCyrille Pitchen 245989a82ef8SCyrille Pitchen static int atmel_sha_authenc_init_done(struct atmel_sha_dev *dd) 246089a82ef8SCyrille Pitchen { 246189a82ef8SCyrille Pitchen struct ahash_request *req = dd->req; 246289a82ef8SCyrille Pitchen struct atmel_sha_authenc_reqctx *authctx = ahash_request_ctx(req); 246389a82ef8SCyrille Pitchen 246489a82ef8SCyrille Pitchen return authctx->cb(authctx->aes_dev, 0, dd->is_async); 246589a82ef8SCyrille Pitchen } 246689a82ef8SCyrille Pitchen 246789a82ef8SCyrille Pitchen int atmel_sha_authenc_final(struct ahash_request *req, 246889a82ef8SCyrille Pitchen u32 *digest, unsigned int digestlen, 246989a82ef8SCyrille Pitchen atmel_aes_authenc_fn_t cb, 247089a82ef8SCyrille Pitchen struct atmel_aes_dev *aes_dev) 247189a82ef8SCyrille Pitchen { 247289a82ef8SCyrille Pitchen struct atmel_sha_authenc_reqctx *authctx = ahash_request_ctx(req); 247389a82ef8SCyrille Pitchen struct atmel_sha_reqctx *ctx = &authctx->base; 247489a82ef8SCyrille Pitchen struct atmel_sha_dev *dd = ctx->dd; 247589a82ef8SCyrille Pitchen 247689a82ef8SCyrille Pitchen switch (ctx->flags & SHA_FLAGS_ALGO_MASK) { 247789a82ef8SCyrille Pitchen case SHA_FLAGS_SHA1: 247889a82ef8SCyrille Pitchen authctx->digestlen = SHA1_DIGEST_SIZE; 247989a82ef8SCyrille Pitchen break; 248089a82ef8SCyrille Pitchen 248189a82ef8SCyrille Pitchen case SHA_FLAGS_SHA224: 248289a82ef8SCyrille Pitchen authctx->digestlen = SHA224_DIGEST_SIZE; 248389a82ef8SCyrille Pitchen break; 248489a82ef8SCyrille Pitchen 248589a82ef8SCyrille Pitchen case SHA_FLAGS_SHA256: 248689a82ef8SCyrille Pitchen authctx->digestlen = SHA256_DIGEST_SIZE; 248789a82ef8SCyrille Pitchen break; 248889a82ef8SCyrille Pitchen 248989a82ef8SCyrille Pitchen case SHA_FLAGS_SHA384: 249089a82ef8SCyrille Pitchen authctx->digestlen = SHA384_DIGEST_SIZE; 249189a82ef8SCyrille Pitchen break; 249289a82ef8SCyrille Pitchen 249389a82ef8SCyrille Pitchen case SHA_FLAGS_SHA512: 249489a82ef8SCyrille Pitchen authctx->digestlen = SHA512_DIGEST_SIZE; 249589a82ef8SCyrille Pitchen break; 249689a82ef8SCyrille Pitchen 249789a82ef8SCyrille Pitchen default: 249889a82ef8SCyrille Pitchen return atmel_sha_complete(dd, -EINVAL); 249989a82ef8SCyrille Pitchen } 250089a82ef8SCyrille Pitchen if (authctx->digestlen > digestlen) 250189a82ef8SCyrille Pitchen authctx->digestlen = digestlen; 250289a82ef8SCyrille Pitchen 250389a82ef8SCyrille Pitchen authctx->cb = cb; 250489a82ef8SCyrille Pitchen authctx->aes_dev = aes_dev; 250589a82ef8SCyrille Pitchen authctx->digest = digest; 250689a82ef8SCyrille Pitchen return atmel_sha_wait_for_data_ready(dd, 250789a82ef8SCyrille Pitchen atmel_sha_authenc_final_done); 250889a82ef8SCyrille Pitchen } 250989a82ef8SCyrille Pitchen EXPORT_SYMBOL_GPL(atmel_sha_authenc_final); 251089a82ef8SCyrille Pitchen 251189a82ef8SCyrille Pitchen static int atmel_sha_authenc_final_done(struct atmel_sha_dev *dd) 251289a82ef8SCyrille Pitchen { 251389a82ef8SCyrille Pitchen struct ahash_request *req = dd->req; 251489a82ef8SCyrille Pitchen struct atmel_sha_authenc_reqctx *authctx = ahash_request_ctx(req); 251589a82ef8SCyrille Pitchen size_t i, num_words = authctx->digestlen / sizeof(u32); 251689a82ef8SCyrille Pitchen 251789a82ef8SCyrille Pitchen for (i = 0; i < num_words; ++i) 251889a82ef8SCyrille Pitchen authctx->digest[i] = atmel_sha_read(dd, SHA_REG_DIGEST(i)); 251989a82ef8SCyrille Pitchen 252089a82ef8SCyrille Pitchen return atmel_sha_complete(dd, 0); 252189a82ef8SCyrille Pitchen } 252289a82ef8SCyrille Pitchen 252389a82ef8SCyrille Pitchen void atmel_sha_authenc_abort(struct ahash_request *req) 252489a82ef8SCyrille Pitchen { 252589a82ef8SCyrille Pitchen struct atmel_sha_authenc_reqctx *authctx = ahash_request_ctx(req); 252689a82ef8SCyrille Pitchen struct atmel_sha_reqctx *ctx = &authctx->base; 252789a82ef8SCyrille Pitchen struct atmel_sha_dev *dd = ctx->dd; 252889a82ef8SCyrille Pitchen 252989a82ef8SCyrille Pitchen /* Prevent atmel_sha_complete() from calling req->base.complete(). */ 253089a82ef8SCyrille Pitchen dd->is_async = false; 253189a82ef8SCyrille Pitchen dd->force_complete = false; 253289a82ef8SCyrille Pitchen (void)atmel_sha_complete(dd, 0); 253389a82ef8SCyrille Pitchen } 253489a82ef8SCyrille Pitchen EXPORT_SYMBOL_GPL(atmel_sha_authenc_abort); 253589a82ef8SCyrille Pitchen 253689a82ef8SCyrille Pitchen #endif /* CONFIG_CRYPTO_DEV_ATMEL_AUTHENC */ 253789a82ef8SCyrille Pitchen 253889a82ef8SCyrille Pitchen 2539ebc82efaSNicolas Royer static void atmel_sha_unregister_algs(struct atmel_sha_dev *dd) 2540ebc82efaSNicolas Royer { 2541ebc82efaSNicolas Royer int i; 2542ebc82efaSNicolas Royer 254381d8750bSCyrille Pitchen if (dd->caps.has_hmac) 254481d8750bSCyrille Pitchen for (i = 0; i < ARRAY_SIZE(sha_hmac_algs); i++) 254581d8750bSCyrille Pitchen crypto_unregister_ahash(&sha_hmac_algs[i]); 254681d8750bSCyrille Pitchen 2547d4905b38SNicolas Royer for (i = 0; i < ARRAY_SIZE(sha_1_256_algs); i++) 2548d4905b38SNicolas Royer crypto_unregister_ahash(&sha_1_256_algs[i]); 2549d4905b38SNicolas Royer 2550d4905b38SNicolas Royer if (dd->caps.has_sha224) 2551d4905b38SNicolas Royer crypto_unregister_ahash(&sha_224_alg); 2552d4905b38SNicolas Royer 2553d4905b38SNicolas Royer if (dd->caps.has_sha_384_512) { 2554d4905b38SNicolas Royer for (i = 0; i < ARRAY_SIZE(sha_384_512_algs); i++) 2555d4905b38SNicolas Royer crypto_unregister_ahash(&sha_384_512_algs[i]); 2556d4905b38SNicolas Royer } 2557ebc82efaSNicolas Royer } 2558ebc82efaSNicolas Royer 2559ebc82efaSNicolas Royer static int atmel_sha_register_algs(struct atmel_sha_dev *dd) 2560ebc82efaSNicolas Royer { 2561ebc82efaSNicolas Royer int err, i, j; 2562ebc82efaSNicolas Royer 2563d4905b38SNicolas Royer for (i = 0; i < ARRAY_SIZE(sha_1_256_algs); i++) { 2564d4905b38SNicolas Royer err = crypto_register_ahash(&sha_1_256_algs[i]); 2565ebc82efaSNicolas Royer if (err) 2566d4905b38SNicolas Royer goto err_sha_1_256_algs; 2567d4905b38SNicolas Royer } 2568d4905b38SNicolas Royer 2569d4905b38SNicolas Royer if (dd->caps.has_sha224) { 2570d4905b38SNicolas Royer err = crypto_register_ahash(&sha_224_alg); 2571d4905b38SNicolas Royer if (err) 2572d4905b38SNicolas Royer goto err_sha_224_algs; 2573d4905b38SNicolas Royer } 2574d4905b38SNicolas Royer 2575d4905b38SNicolas Royer if (dd->caps.has_sha_384_512) { 2576d4905b38SNicolas Royer for (i = 0; i < ARRAY_SIZE(sha_384_512_algs); i++) { 2577d4905b38SNicolas Royer err = crypto_register_ahash(&sha_384_512_algs[i]); 2578d4905b38SNicolas Royer if (err) 2579d4905b38SNicolas Royer goto err_sha_384_512_algs; 2580d4905b38SNicolas Royer } 2581ebc82efaSNicolas Royer } 2582ebc82efaSNicolas Royer 258381d8750bSCyrille Pitchen if (dd->caps.has_hmac) { 258481d8750bSCyrille Pitchen for (i = 0; i < ARRAY_SIZE(sha_hmac_algs); i++) { 258581d8750bSCyrille Pitchen err = crypto_register_ahash(&sha_hmac_algs[i]); 258681d8750bSCyrille Pitchen if (err) 258781d8750bSCyrille Pitchen goto err_sha_hmac_algs; 258881d8750bSCyrille Pitchen } 258981d8750bSCyrille Pitchen } 259081d8750bSCyrille Pitchen 2591ebc82efaSNicolas Royer return 0; 2592ebc82efaSNicolas Royer 259381d8750bSCyrille Pitchen /*i = ARRAY_SIZE(sha_hmac_algs);*/ 259481d8750bSCyrille Pitchen err_sha_hmac_algs: 259581d8750bSCyrille Pitchen for (j = 0; j < i; j++) 259681d8750bSCyrille Pitchen crypto_unregister_ahash(&sha_hmac_algs[j]); 259781d8750bSCyrille Pitchen i = ARRAY_SIZE(sha_384_512_algs); 2598d4905b38SNicolas Royer err_sha_384_512_algs: 2599ebc82efaSNicolas Royer for (j = 0; j < i; j++) 2600d4905b38SNicolas Royer crypto_unregister_ahash(&sha_384_512_algs[j]); 2601d4905b38SNicolas Royer crypto_unregister_ahash(&sha_224_alg); 2602d4905b38SNicolas Royer err_sha_224_algs: 2603d4905b38SNicolas Royer i = ARRAY_SIZE(sha_1_256_algs); 2604d4905b38SNicolas Royer err_sha_1_256_algs: 2605d4905b38SNicolas Royer for (j = 0; j < i; j++) 2606d4905b38SNicolas Royer crypto_unregister_ahash(&sha_1_256_algs[j]); 2607ebc82efaSNicolas Royer 2608ebc82efaSNicolas Royer return err; 2609ebc82efaSNicolas Royer } 2610ebc82efaSNicolas Royer 2611d4905b38SNicolas Royer static bool atmel_sha_filter(struct dma_chan *chan, void *slave) 2612d4905b38SNicolas Royer { 2613d4905b38SNicolas Royer struct at_dma_slave *sl = slave; 2614d4905b38SNicolas Royer 2615d4905b38SNicolas Royer if (sl && sl->dma_dev == chan->device->dev) { 2616d4905b38SNicolas Royer chan->private = sl; 2617d4905b38SNicolas Royer return true; 2618d4905b38SNicolas Royer } else { 2619d4905b38SNicolas Royer return false; 2620d4905b38SNicolas Royer } 2621d4905b38SNicolas Royer } 2622d4905b38SNicolas Royer 2623d4905b38SNicolas Royer static int atmel_sha_dma_init(struct atmel_sha_dev *dd, 2624d4905b38SNicolas Royer struct crypto_platform_data *pdata) 2625d4905b38SNicolas Royer { 2626d4905b38SNicolas Royer dma_cap_mask_t mask_in; 2627d4905b38SNicolas Royer 2628d4905b38SNicolas Royer /* Try to grab DMA channel */ 2629d4905b38SNicolas Royer dma_cap_zero(mask_in); 2630d4905b38SNicolas Royer dma_cap_set(DMA_SLAVE, mask_in); 2631d4905b38SNicolas Royer 2632abfe7ae4SNicolas Ferre dd->dma_lch_in.chan = dma_request_slave_channel_compat(mask_in, 2633abfe7ae4SNicolas Ferre atmel_sha_filter, &pdata->dma_slave->rxdata, dd->dev, "tx"); 2634abfe7ae4SNicolas Ferre if (!dd->dma_lch_in.chan) { 2635abfe7ae4SNicolas Ferre dev_warn(dd->dev, "no DMA channel available\n"); 26363c88761eSTudor-Dan Ambarus return -ENODEV; 2637abfe7ae4SNicolas Ferre } 2638d4905b38SNicolas Royer 2639d4905b38SNicolas Royer dd->dma_lch_in.dma_conf.direction = DMA_MEM_TO_DEV; 2640d4905b38SNicolas Royer dd->dma_lch_in.dma_conf.dst_addr = dd->phys_base + 2641d4905b38SNicolas Royer SHA_REG_DIN(0); 2642d4905b38SNicolas Royer dd->dma_lch_in.dma_conf.src_maxburst = 1; 2643d4905b38SNicolas Royer dd->dma_lch_in.dma_conf.src_addr_width = 2644d4905b38SNicolas Royer DMA_SLAVE_BUSWIDTH_4_BYTES; 2645d4905b38SNicolas Royer dd->dma_lch_in.dma_conf.dst_maxburst = 1; 2646d4905b38SNicolas Royer dd->dma_lch_in.dma_conf.dst_addr_width = 2647d4905b38SNicolas Royer DMA_SLAVE_BUSWIDTH_4_BYTES; 2648d4905b38SNicolas Royer dd->dma_lch_in.dma_conf.device_fc = false; 2649d4905b38SNicolas Royer 2650d4905b38SNicolas Royer return 0; 2651d4905b38SNicolas Royer } 2652d4905b38SNicolas Royer 2653d4905b38SNicolas Royer static void atmel_sha_dma_cleanup(struct atmel_sha_dev *dd) 2654d4905b38SNicolas Royer { 2655d4905b38SNicolas Royer dma_release_channel(dd->dma_lch_in.chan); 2656d4905b38SNicolas Royer } 2657d4905b38SNicolas Royer 2658d4905b38SNicolas Royer static void atmel_sha_get_cap(struct atmel_sha_dev *dd) 2659d4905b38SNicolas Royer { 2660d4905b38SNicolas Royer 2661d4905b38SNicolas Royer dd->caps.has_dma = 0; 2662d4905b38SNicolas Royer dd->caps.has_dualbuff = 0; 2663d4905b38SNicolas Royer dd->caps.has_sha224 = 0; 2664d4905b38SNicolas Royer dd->caps.has_sha_384_512 = 0; 26657cee3508SCyrille Pitchen dd->caps.has_uihv = 0; 266681d8750bSCyrille Pitchen dd->caps.has_hmac = 0; 2667d4905b38SNicolas Royer 2668d4905b38SNicolas Royer /* keep only major version number */ 2669d4905b38SNicolas Royer switch (dd->hw_version & 0xff0) { 2670507c5cc2SCyrille Pitchen case 0x510: 2671507c5cc2SCyrille Pitchen dd->caps.has_dma = 1; 2672507c5cc2SCyrille Pitchen dd->caps.has_dualbuff = 1; 2673507c5cc2SCyrille Pitchen dd->caps.has_sha224 = 1; 2674507c5cc2SCyrille Pitchen dd->caps.has_sha_384_512 = 1; 26757cee3508SCyrille Pitchen dd->caps.has_uihv = 1; 267681d8750bSCyrille Pitchen dd->caps.has_hmac = 1; 2677507c5cc2SCyrille Pitchen break; 2678141824d0SLeilei Zhao case 0x420: 2679141824d0SLeilei Zhao dd->caps.has_dma = 1; 2680141824d0SLeilei Zhao dd->caps.has_dualbuff = 1; 2681141824d0SLeilei Zhao dd->caps.has_sha224 = 1; 2682141824d0SLeilei Zhao dd->caps.has_sha_384_512 = 1; 26837cee3508SCyrille Pitchen dd->caps.has_uihv = 1; 2684141824d0SLeilei Zhao break; 2685d4905b38SNicolas Royer case 0x410: 2686d4905b38SNicolas Royer dd->caps.has_dma = 1; 2687d4905b38SNicolas Royer dd->caps.has_dualbuff = 1; 2688d4905b38SNicolas Royer dd->caps.has_sha224 = 1; 2689d4905b38SNicolas Royer dd->caps.has_sha_384_512 = 1; 2690d4905b38SNicolas Royer break; 2691d4905b38SNicolas Royer case 0x400: 2692d4905b38SNicolas Royer dd->caps.has_dma = 1; 2693d4905b38SNicolas Royer dd->caps.has_dualbuff = 1; 2694d4905b38SNicolas Royer dd->caps.has_sha224 = 1; 2695d4905b38SNicolas Royer break; 2696d4905b38SNicolas Royer case 0x320: 2697d4905b38SNicolas Royer break; 2698d4905b38SNicolas Royer default: 2699d4905b38SNicolas Royer dev_warn(dd->dev, 2700d4905b38SNicolas Royer "Unmanaged sha version, set minimum capabilities\n"); 2701d4905b38SNicolas Royer break; 2702d4905b38SNicolas Royer } 2703d4905b38SNicolas Royer } 2704d4905b38SNicolas Royer 2705abfe7ae4SNicolas Ferre #if defined(CONFIG_OF) 2706abfe7ae4SNicolas Ferre static const struct of_device_id atmel_sha_dt_ids[] = { 2707abfe7ae4SNicolas Ferre { .compatible = "atmel,at91sam9g46-sha" }, 2708abfe7ae4SNicolas Ferre { /* sentinel */ } 2709abfe7ae4SNicolas Ferre }; 2710abfe7ae4SNicolas Ferre 2711abfe7ae4SNicolas Ferre MODULE_DEVICE_TABLE(of, atmel_sha_dt_ids); 2712abfe7ae4SNicolas Ferre 2713abfe7ae4SNicolas Ferre static struct crypto_platform_data *atmel_sha_of_init(struct platform_device *pdev) 2714abfe7ae4SNicolas Ferre { 2715abfe7ae4SNicolas Ferre struct device_node *np = pdev->dev.of_node; 2716abfe7ae4SNicolas Ferre struct crypto_platform_data *pdata; 2717abfe7ae4SNicolas Ferre 2718abfe7ae4SNicolas Ferre if (!np) { 2719abfe7ae4SNicolas Ferre dev_err(&pdev->dev, "device node not found\n"); 2720abfe7ae4SNicolas Ferre return ERR_PTR(-EINVAL); 2721abfe7ae4SNicolas Ferre } 2722abfe7ae4SNicolas Ferre 2723abfe7ae4SNicolas Ferre pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); 272402684839SMarkus Elfring if (!pdata) 2725abfe7ae4SNicolas Ferre return ERR_PTR(-ENOMEM); 2726abfe7ae4SNicolas Ferre 2727abfe7ae4SNicolas Ferre pdata->dma_slave = devm_kzalloc(&pdev->dev, 2728abfe7ae4SNicolas Ferre sizeof(*(pdata->dma_slave)), 2729abfe7ae4SNicolas Ferre GFP_KERNEL); 273002684839SMarkus Elfring if (!pdata->dma_slave) 2731abfe7ae4SNicolas Ferre return ERR_PTR(-ENOMEM); 2732abfe7ae4SNicolas Ferre 2733abfe7ae4SNicolas Ferre return pdata; 2734abfe7ae4SNicolas Ferre } 2735abfe7ae4SNicolas Ferre #else /* CONFIG_OF */ 2736abfe7ae4SNicolas Ferre static inline struct crypto_platform_data *atmel_sha_of_init(struct platform_device *dev) 2737abfe7ae4SNicolas Ferre { 2738abfe7ae4SNicolas Ferre return ERR_PTR(-EINVAL); 2739abfe7ae4SNicolas Ferre } 2740abfe7ae4SNicolas Ferre #endif 2741abfe7ae4SNicolas Ferre 274249cfe4dbSGreg Kroah-Hartman static int atmel_sha_probe(struct platform_device *pdev) 2743ebc82efaSNicolas Royer { 2744ebc82efaSNicolas Royer struct atmel_sha_dev *sha_dd; 2745d4905b38SNicolas Royer struct crypto_platform_data *pdata; 2746ebc82efaSNicolas Royer struct device *dev = &pdev->dev; 2747ebc82efaSNicolas Royer struct resource *sha_res; 2748ebc82efaSNicolas Royer int err; 2749ebc82efaSNicolas Royer 2750b0e8b341SLABBE Corentin sha_dd = devm_kzalloc(&pdev->dev, sizeof(*sha_dd), GFP_KERNEL); 2751ebc82efaSNicolas Royer if (sha_dd == NULL) { 2752ebc82efaSNicolas Royer err = -ENOMEM; 2753ebc82efaSNicolas Royer goto sha_dd_err; 2754ebc82efaSNicolas Royer } 2755ebc82efaSNicolas Royer 2756ebc82efaSNicolas Royer sha_dd->dev = dev; 2757ebc82efaSNicolas Royer 2758ebc82efaSNicolas Royer platform_set_drvdata(pdev, sha_dd); 2759ebc82efaSNicolas Royer 2760ebc82efaSNicolas Royer INIT_LIST_HEAD(&sha_dd->list); 276162728e82SLeilei Zhao spin_lock_init(&sha_dd->lock); 2762ebc82efaSNicolas Royer 2763ebc82efaSNicolas Royer tasklet_init(&sha_dd->done_task, atmel_sha_done_task, 2764ebc82efaSNicolas Royer (unsigned long)sha_dd); 2765f56809c3SCyrille Pitchen tasklet_init(&sha_dd->queue_task, atmel_sha_queue_task, 2766f56809c3SCyrille Pitchen (unsigned long)sha_dd); 2767ebc82efaSNicolas Royer 2768ebc82efaSNicolas Royer crypto_init_queue(&sha_dd->queue, ATMEL_SHA_QUEUE_LENGTH); 2769ebc82efaSNicolas Royer 2770ebc82efaSNicolas Royer /* Get the base address */ 2771ebc82efaSNicolas Royer sha_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 2772ebc82efaSNicolas Royer if (!sha_res) { 2773ebc82efaSNicolas Royer dev_err(dev, "no MEM resource info\n"); 2774ebc82efaSNicolas Royer err = -ENODEV; 2775ebc82efaSNicolas Royer goto res_err; 2776ebc82efaSNicolas Royer } 2777ebc82efaSNicolas Royer sha_dd->phys_base = sha_res->start; 2778ebc82efaSNicolas Royer 2779ebc82efaSNicolas Royer /* Get the IRQ */ 2780ebc82efaSNicolas Royer sha_dd->irq = platform_get_irq(pdev, 0); 2781ebc82efaSNicolas Royer if (sha_dd->irq < 0) { 2782ebc82efaSNicolas Royer err = sha_dd->irq; 2783ebc82efaSNicolas Royer goto res_err; 2784ebc82efaSNicolas Royer } 2785ebc82efaSNicolas Royer 2786b0e8b341SLABBE Corentin err = devm_request_irq(&pdev->dev, sha_dd->irq, atmel_sha_irq, 2787b0e8b341SLABBE Corentin IRQF_SHARED, "atmel-sha", sha_dd); 2788ebc82efaSNicolas Royer if (err) { 2789ebc82efaSNicolas Royer dev_err(dev, "unable to request sha irq.\n"); 2790ebc82efaSNicolas Royer goto res_err; 2791ebc82efaSNicolas Royer } 2792ebc82efaSNicolas Royer 2793ebc82efaSNicolas Royer /* Initializing the clock */ 2794b0e8b341SLABBE Corentin sha_dd->iclk = devm_clk_get(&pdev->dev, "sha_clk"); 2795ebc82efaSNicolas Royer if (IS_ERR(sha_dd->iclk)) { 2796be208356SColin Ian King dev_err(dev, "clock initialization failed.\n"); 2797ebc82efaSNicolas Royer err = PTR_ERR(sha_dd->iclk); 2798b0e8b341SLABBE Corentin goto res_err; 2799ebc82efaSNicolas Royer } 2800ebc82efaSNicolas Royer 2801b0e8b341SLABBE Corentin sha_dd->io_base = devm_ioremap_resource(&pdev->dev, sha_res); 28029b52d55fSVladimir Zapolskiy if (IS_ERR(sha_dd->io_base)) { 2803ebc82efaSNicolas Royer dev_err(dev, "can't ioremap\n"); 28049b52d55fSVladimir Zapolskiy err = PTR_ERR(sha_dd->io_base); 2805b0e8b341SLABBE Corentin goto res_err; 2806ebc82efaSNicolas Royer } 2807ebc82efaSNicolas Royer 2808c033042aSCyrille Pitchen err = clk_prepare(sha_dd->iclk); 2809c033042aSCyrille Pitchen if (err) 2810c033042aSCyrille Pitchen goto res_err; 2811c033042aSCyrille Pitchen 2812d4905b38SNicolas Royer atmel_sha_hw_version_init(sha_dd); 2813d4905b38SNicolas Royer 2814d4905b38SNicolas Royer atmel_sha_get_cap(sha_dd); 2815d4905b38SNicolas Royer 2816d4905b38SNicolas Royer if (sha_dd->caps.has_dma) { 2817d4905b38SNicolas Royer pdata = pdev->dev.platform_data; 2818d4905b38SNicolas Royer if (!pdata) { 2819abfe7ae4SNicolas Ferre pdata = atmel_sha_of_init(pdev); 2820abfe7ae4SNicolas Ferre if (IS_ERR(pdata)) { 2821d4905b38SNicolas Royer dev_err(&pdev->dev, "platform data not available\n"); 2822abfe7ae4SNicolas Ferre err = PTR_ERR(pdata); 2823c033042aSCyrille Pitchen goto iclk_unprepare; 2824abfe7ae4SNicolas Ferre } 2825abfe7ae4SNicolas Ferre } 2826abfe7ae4SNicolas Ferre if (!pdata->dma_slave) { 2827d4905b38SNicolas Royer err = -ENXIO; 2828c033042aSCyrille Pitchen goto iclk_unprepare; 2829d4905b38SNicolas Royer } 2830d4905b38SNicolas Royer err = atmel_sha_dma_init(sha_dd, pdata); 2831d4905b38SNicolas Royer if (err) 2832d4905b38SNicolas Royer goto err_sha_dma; 2833abfe7ae4SNicolas Ferre 2834abfe7ae4SNicolas Ferre dev_info(dev, "using %s for DMA transfers\n", 2835abfe7ae4SNicolas Ferre dma_chan_name(sha_dd->dma_lch_in.chan)); 2836d4905b38SNicolas Royer } 2837d4905b38SNicolas Royer 2838ebc82efaSNicolas Royer spin_lock(&atmel_sha.lock); 2839ebc82efaSNicolas Royer list_add_tail(&sha_dd->list, &atmel_sha.dev_list); 2840ebc82efaSNicolas Royer spin_unlock(&atmel_sha.lock); 2841ebc82efaSNicolas Royer 2842ebc82efaSNicolas Royer err = atmel_sha_register_algs(sha_dd); 2843ebc82efaSNicolas Royer if (err) 2844ebc82efaSNicolas Royer goto err_algs; 2845ebc82efaSNicolas Royer 28461ca5b7d9SNicolas Ferre dev_info(dev, "Atmel SHA1/SHA256%s%s\n", 28471ca5b7d9SNicolas Ferre sha_dd->caps.has_sha224 ? "/SHA224" : "", 28481ca5b7d9SNicolas Ferre sha_dd->caps.has_sha_384_512 ? "/SHA384/SHA512" : ""); 2849ebc82efaSNicolas Royer 2850ebc82efaSNicolas Royer return 0; 2851ebc82efaSNicolas Royer 2852ebc82efaSNicolas Royer err_algs: 2853ebc82efaSNicolas Royer spin_lock(&atmel_sha.lock); 2854ebc82efaSNicolas Royer list_del(&sha_dd->list); 2855ebc82efaSNicolas Royer spin_unlock(&atmel_sha.lock); 2856d4905b38SNicolas Royer if (sha_dd->caps.has_dma) 2857d4905b38SNicolas Royer atmel_sha_dma_cleanup(sha_dd); 2858d4905b38SNicolas Royer err_sha_dma: 2859c033042aSCyrille Pitchen iclk_unprepare: 2860c033042aSCyrille Pitchen clk_unprepare(sha_dd->iclk); 2861ebc82efaSNicolas Royer res_err: 2862f56809c3SCyrille Pitchen tasklet_kill(&sha_dd->queue_task); 2863ebc82efaSNicolas Royer tasklet_kill(&sha_dd->done_task); 2864ebc82efaSNicolas Royer sha_dd_err: 2865ebc82efaSNicolas Royer dev_err(dev, "initialization failed.\n"); 2866ebc82efaSNicolas Royer 2867ebc82efaSNicolas Royer return err; 2868ebc82efaSNicolas Royer } 2869ebc82efaSNicolas Royer 287049cfe4dbSGreg Kroah-Hartman static int atmel_sha_remove(struct platform_device *pdev) 2871ebc82efaSNicolas Royer { 287222d96f04SGustavo A. R. Silva struct atmel_sha_dev *sha_dd; 2873ebc82efaSNicolas Royer 2874ebc82efaSNicolas Royer sha_dd = platform_get_drvdata(pdev); 2875ebc82efaSNicolas Royer if (!sha_dd) 2876ebc82efaSNicolas Royer return -ENODEV; 2877ebc82efaSNicolas Royer spin_lock(&atmel_sha.lock); 2878ebc82efaSNicolas Royer list_del(&sha_dd->list); 2879ebc82efaSNicolas Royer spin_unlock(&atmel_sha.lock); 2880ebc82efaSNicolas Royer 2881ebc82efaSNicolas Royer atmel_sha_unregister_algs(sha_dd); 2882ebc82efaSNicolas Royer 2883f56809c3SCyrille Pitchen tasklet_kill(&sha_dd->queue_task); 2884ebc82efaSNicolas Royer tasklet_kill(&sha_dd->done_task); 2885ebc82efaSNicolas Royer 2886d4905b38SNicolas Royer if (sha_dd->caps.has_dma) 2887d4905b38SNicolas Royer atmel_sha_dma_cleanup(sha_dd); 2888d4905b38SNicolas Royer 2889c033042aSCyrille Pitchen clk_unprepare(sha_dd->iclk); 2890c033042aSCyrille Pitchen 2891ebc82efaSNicolas Royer return 0; 2892ebc82efaSNicolas Royer } 2893ebc82efaSNicolas Royer 2894ebc82efaSNicolas Royer static struct platform_driver atmel_sha_driver = { 2895ebc82efaSNicolas Royer .probe = atmel_sha_probe, 289649cfe4dbSGreg Kroah-Hartman .remove = atmel_sha_remove, 2897ebc82efaSNicolas Royer .driver = { 2898ebc82efaSNicolas Royer .name = "atmel_sha", 2899abfe7ae4SNicolas Ferre .of_match_table = of_match_ptr(atmel_sha_dt_ids), 2900ebc82efaSNicolas Royer }, 2901ebc82efaSNicolas Royer }; 2902ebc82efaSNicolas Royer 2903ebc82efaSNicolas Royer module_platform_driver(atmel_sha_driver); 2904ebc82efaSNicolas Royer 2905d4905b38SNicolas Royer MODULE_DESCRIPTION("Atmel SHA (1/256/224/384/512) hw acceleration support."); 2906ebc82efaSNicolas Royer MODULE_LICENSE("GPL v2"); 2907ebc82efaSNicolas Royer MODULE_AUTHOR("Nicolas Royer - Eukréa Electromatique"); 2908