18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Cryptographic API. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Support for ATMEL DES/TDES HW acceleration. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright (c) 2012 Eukréa Electromatique - ATMEL 88c2ecf20Sopenharmony_ci * Author: Nicolas Royer <nicolas@eukrea.com> 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * Some ideas are from omap-aes.c drivers. 118c2ecf20Sopenharmony_ci */ 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <linux/kernel.h> 158c2ecf20Sopenharmony_ci#include <linux/module.h> 168c2ecf20Sopenharmony_ci#include <linux/slab.h> 178c2ecf20Sopenharmony_ci#include <linux/err.h> 188c2ecf20Sopenharmony_ci#include <linux/clk.h> 198c2ecf20Sopenharmony_ci#include <linux/io.h> 208c2ecf20Sopenharmony_ci#include <linux/hw_random.h> 218c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#include <linux/device.h> 248c2ecf20Sopenharmony_ci#include <linux/dmaengine.h> 258c2ecf20Sopenharmony_ci#include <linux/init.h> 268c2ecf20Sopenharmony_ci#include <linux/errno.h> 278c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 288c2ecf20Sopenharmony_ci#include <linux/irq.h> 298c2ecf20Sopenharmony_ci#include <linux/scatterlist.h> 308c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 318c2ecf20Sopenharmony_ci#include <linux/of_device.h> 328c2ecf20Sopenharmony_ci#include <linux/delay.h> 338c2ecf20Sopenharmony_ci#include <linux/crypto.h> 348c2ecf20Sopenharmony_ci#include <crypto/scatterwalk.h> 358c2ecf20Sopenharmony_ci#include <crypto/algapi.h> 368c2ecf20Sopenharmony_ci#include <crypto/internal/des.h> 378c2ecf20Sopenharmony_ci#include <crypto/internal/skcipher.h> 388c2ecf20Sopenharmony_ci#include "atmel-tdes-regs.h" 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci#define ATMEL_TDES_PRIORITY 300 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci/* TDES flags */ 438c2ecf20Sopenharmony_ci/* Reserve bits [17:16], [13:12], [2:0] for AES Mode Register */ 448c2ecf20Sopenharmony_ci#define TDES_FLAGS_ENCRYPT TDES_MR_CYPHER_ENC 458c2ecf20Sopenharmony_ci#define TDES_FLAGS_OPMODE_MASK (TDES_MR_OPMOD_MASK | TDES_MR_CFBS_MASK) 468c2ecf20Sopenharmony_ci#define TDES_FLAGS_ECB TDES_MR_OPMOD_ECB 478c2ecf20Sopenharmony_ci#define TDES_FLAGS_CBC TDES_MR_OPMOD_CBC 488c2ecf20Sopenharmony_ci#define TDES_FLAGS_OFB TDES_MR_OPMOD_OFB 498c2ecf20Sopenharmony_ci#define TDES_FLAGS_CFB64 (TDES_MR_OPMOD_CFB | TDES_MR_CFBS_64b) 508c2ecf20Sopenharmony_ci#define TDES_FLAGS_CFB32 (TDES_MR_OPMOD_CFB | TDES_MR_CFBS_32b) 518c2ecf20Sopenharmony_ci#define TDES_FLAGS_CFB16 (TDES_MR_OPMOD_CFB | TDES_MR_CFBS_16b) 528c2ecf20Sopenharmony_ci#define TDES_FLAGS_CFB8 (TDES_MR_OPMOD_CFB | TDES_MR_CFBS_8b) 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci#define TDES_FLAGS_MODE_MASK (TDES_FLAGS_OPMODE_MASK | TDES_FLAGS_ENCRYPT) 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci#define TDES_FLAGS_INIT BIT(3) 578c2ecf20Sopenharmony_ci#define TDES_FLAGS_FAST BIT(4) 588c2ecf20Sopenharmony_ci#define TDES_FLAGS_BUSY BIT(5) 598c2ecf20Sopenharmony_ci#define TDES_FLAGS_DMA BIT(6) 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci#define ATMEL_TDES_QUEUE_LENGTH 50 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci#define CFB8_BLOCK_SIZE 1 648c2ecf20Sopenharmony_ci#define CFB16_BLOCK_SIZE 2 658c2ecf20Sopenharmony_ci#define CFB32_BLOCK_SIZE 4 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_cistruct atmel_tdes_caps { 688c2ecf20Sopenharmony_ci bool has_dma; 698c2ecf20Sopenharmony_ci u32 has_cfb_3keys; 708c2ecf20Sopenharmony_ci}; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cistruct atmel_tdes_dev; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_cistruct atmel_tdes_ctx { 758c2ecf20Sopenharmony_ci struct atmel_tdes_dev *dd; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci int keylen; 788c2ecf20Sopenharmony_ci u32 key[DES3_EDE_KEY_SIZE / sizeof(u32)]; 798c2ecf20Sopenharmony_ci unsigned long flags; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci u16 block_size; 828c2ecf20Sopenharmony_ci}; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_cistruct atmel_tdes_reqctx { 858c2ecf20Sopenharmony_ci unsigned long mode; 868c2ecf20Sopenharmony_ci u8 lastc[DES_BLOCK_SIZE]; 878c2ecf20Sopenharmony_ci}; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_cistruct atmel_tdes_dma { 908c2ecf20Sopenharmony_ci struct dma_chan *chan; 918c2ecf20Sopenharmony_ci struct dma_slave_config dma_conf; 928c2ecf20Sopenharmony_ci}; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_cistruct atmel_tdes_dev { 958c2ecf20Sopenharmony_ci struct list_head list; 968c2ecf20Sopenharmony_ci unsigned long phys_base; 978c2ecf20Sopenharmony_ci void __iomem *io_base; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci struct atmel_tdes_ctx *ctx; 1008c2ecf20Sopenharmony_ci struct device *dev; 1018c2ecf20Sopenharmony_ci struct clk *iclk; 1028c2ecf20Sopenharmony_ci int irq; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci unsigned long flags; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci spinlock_t lock; 1078c2ecf20Sopenharmony_ci struct crypto_queue queue; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci struct tasklet_struct done_task; 1108c2ecf20Sopenharmony_ci struct tasklet_struct queue_task; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci struct skcipher_request *req; 1138c2ecf20Sopenharmony_ci size_t total; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci struct scatterlist *in_sg; 1168c2ecf20Sopenharmony_ci unsigned int nb_in_sg; 1178c2ecf20Sopenharmony_ci size_t in_offset; 1188c2ecf20Sopenharmony_ci struct scatterlist *out_sg; 1198c2ecf20Sopenharmony_ci unsigned int nb_out_sg; 1208c2ecf20Sopenharmony_ci size_t out_offset; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci size_t buflen; 1238c2ecf20Sopenharmony_ci size_t dma_size; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci void *buf_in; 1268c2ecf20Sopenharmony_ci int dma_in; 1278c2ecf20Sopenharmony_ci dma_addr_t dma_addr_in; 1288c2ecf20Sopenharmony_ci struct atmel_tdes_dma dma_lch_in; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci void *buf_out; 1318c2ecf20Sopenharmony_ci int dma_out; 1328c2ecf20Sopenharmony_ci dma_addr_t dma_addr_out; 1338c2ecf20Sopenharmony_ci struct atmel_tdes_dma dma_lch_out; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci struct atmel_tdes_caps caps; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci u32 hw_version; 1388c2ecf20Sopenharmony_ci}; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_cistruct atmel_tdes_drv { 1418c2ecf20Sopenharmony_ci struct list_head dev_list; 1428c2ecf20Sopenharmony_ci spinlock_t lock; 1438c2ecf20Sopenharmony_ci}; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_cistatic struct atmel_tdes_drv atmel_tdes = { 1468c2ecf20Sopenharmony_ci .dev_list = LIST_HEAD_INIT(atmel_tdes.dev_list), 1478c2ecf20Sopenharmony_ci .lock = __SPIN_LOCK_UNLOCKED(atmel_tdes.lock), 1488c2ecf20Sopenharmony_ci}; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_cistatic int atmel_tdes_sg_copy(struct scatterlist **sg, size_t *offset, 1518c2ecf20Sopenharmony_ci void *buf, size_t buflen, size_t total, int out) 1528c2ecf20Sopenharmony_ci{ 1538c2ecf20Sopenharmony_ci size_t count, off = 0; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci while (buflen && total) { 1568c2ecf20Sopenharmony_ci count = min((*sg)->length - *offset, total); 1578c2ecf20Sopenharmony_ci count = min(count, buflen); 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci if (!count) 1608c2ecf20Sopenharmony_ci return off; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci scatterwalk_map_and_copy(buf + off, *sg, *offset, count, out); 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci off += count; 1658c2ecf20Sopenharmony_ci buflen -= count; 1668c2ecf20Sopenharmony_ci *offset += count; 1678c2ecf20Sopenharmony_ci total -= count; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci if (*offset == (*sg)->length) { 1708c2ecf20Sopenharmony_ci *sg = sg_next(*sg); 1718c2ecf20Sopenharmony_ci if (*sg) 1728c2ecf20Sopenharmony_ci *offset = 0; 1738c2ecf20Sopenharmony_ci else 1748c2ecf20Sopenharmony_ci total = 0; 1758c2ecf20Sopenharmony_ci } 1768c2ecf20Sopenharmony_ci } 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci return off; 1798c2ecf20Sopenharmony_ci} 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_cistatic inline u32 atmel_tdes_read(struct atmel_tdes_dev *dd, u32 offset) 1828c2ecf20Sopenharmony_ci{ 1838c2ecf20Sopenharmony_ci return readl_relaxed(dd->io_base + offset); 1848c2ecf20Sopenharmony_ci} 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_cistatic inline void atmel_tdes_write(struct atmel_tdes_dev *dd, 1878c2ecf20Sopenharmony_ci u32 offset, u32 value) 1888c2ecf20Sopenharmony_ci{ 1898c2ecf20Sopenharmony_ci writel_relaxed(value, dd->io_base + offset); 1908c2ecf20Sopenharmony_ci} 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_cistatic void atmel_tdes_write_n(struct atmel_tdes_dev *dd, u32 offset, 1938c2ecf20Sopenharmony_ci const u32 *value, int count) 1948c2ecf20Sopenharmony_ci{ 1958c2ecf20Sopenharmony_ci for (; count--; value++, offset += 4) 1968c2ecf20Sopenharmony_ci atmel_tdes_write(dd, offset, *value); 1978c2ecf20Sopenharmony_ci} 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_cistatic struct atmel_tdes_dev *atmel_tdes_find_dev(struct atmel_tdes_ctx *ctx) 2008c2ecf20Sopenharmony_ci{ 2018c2ecf20Sopenharmony_ci struct atmel_tdes_dev *tdes_dd = NULL; 2028c2ecf20Sopenharmony_ci struct atmel_tdes_dev *tmp; 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci spin_lock_bh(&atmel_tdes.lock); 2058c2ecf20Sopenharmony_ci if (!ctx->dd) { 2068c2ecf20Sopenharmony_ci list_for_each_entry(tmp, &atmel_tdes.dev_list, list) { 2078c2ecf20Sopenharmony_ci tdes_dd = tmp; 2088c2ecf20Sopenharmony_ci break; 2098c2ecf20Sopenharmony_ci } 2108c2ecf20Sopenharmony_ci ctx->dd = tdes_dd; 2118c2ecf20Sopenharmony_ci } else { 2128c2ecf20Sopenharmony_ci tdes_dd = ctx->dd; 2138c2ecf20Sopenharmony_ci } 2148c2ecf20Sopenharmony_ci spin_unlock_bh(&atmel_tdes.lock); 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci return tdes_dd; 2178c2ecf20Sopenharmony_ci} 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_cistatic int atmel_tdes_hw_init(struct atmel_tdes_dev *dd) 2208c2ecf20Sopenharmony_ci{ 2218c2ecf20Sopenharmony_ci int err; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci err = clk_prepare_enable(dd->iclk); 2248c2ecf20Sopenharmony_ci if (err) 2258c2ecf20Sopenharmony_ci return err; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci if (!(dd->flags & TDES_FLAGS_INIT)) { 2288c2ecf20Sopenharmony_ci atmel_tdes_write(dd, TDES_CR, TDES_CR_SWRST); 2298c2ecf20Sopenharmony_ci dd->flags |= TDES_FLAGS_INIT; 2308c2ecf20Sopenharmony_ci } 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci return 0; 2338c2ecf20Sopenharmony_ci} 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_cistatic inline unsigned int atmel_tdes_get_version(struct atmel_tdes_dev *dd) 2368c2ecf20Sopenharmony_ci{ 2378c2ecf20Sopenharmony_ci return atmel_tdes_read(dd, TDES_HW_VERSION) & 0x00000fff; 2388c2ecf20Sopenharmony_ci} 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_cistatic int atmel_tdes_hw_version_init(struct atmel_tdes_dev *dd) 2418c2ecf20Sopenharmony_ci{ 2428c2ecf20Sopenharmony_ci int err; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci err = atmel_tdes_hw_init(dd); 2458c2ecf20Sopenharmony_ci if (err) 2468c2ecf20Sopenharmony_ci return err; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci dd->hw_version = atmel_tdes_get_version(dd); 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci dev_info(dd->dev, 2518c2ecf20Sopenharmony_ci "version: 0x%x\n", dd->hw_version); 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci clk_disable_unprepare(dd->iclk); 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci return 0; 2568c2ecf20Sopenharmony_ci} 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_cistatic void atmel_tdes_dma_callback(void *data) 2598c2ecf20Sopenharmony_ci{ 2608c2ecf20Sopenharmony_ci struct atmel_tdes_dev *dd = data; 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci /* dma_lch_out - completed */ 2638c2ecf20Sopenharmony_ci tasklet_schedule(&dd->done_task); 2648c2ecf20Sopenharmony_ci} 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_cistatic int atmel_tdes_write_ctrl(struct atmel_tdes_dev *dd) 2678c2ecf20Sopenharmony_ci{ 2688c2ecf20Sopenharmony_ci int err; 2698c2ecf20Sopenharmony_ci u32 valmr = TDES_MR_SMOD_PDC; 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci err = atmel_tdes_hw_init(dd); 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci if (err) 2748c2ecf20Sopenharmony_ci return err; 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci if (!dd->caps.has_dma) 2778c2ecf20Sopenharmony_ci atmel_tdes_write(dd, TDES_PTCR, 2788c2ecf20Sopenharmony_ci TDES_PTCR_TXTDIS | TDES_PTCR_RXTDIS); 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci /* MR register must be set before IV registers */ 2818c2ecf20Sopenharmony_ci if (dd->ctx->keylen > (DES_KEY_SIZE << 1)) { 2828c2ecf20Sopenharmony_ci valmr |= TDES_MR_KEYMOD_3KEY; 2838c2ecf20Sopenharmony_ci valmr |= TDES_MR_TDESMOD_TDES; 2848c2ecf20Sopenharmony_ci } else if (dd->ctx->keylen > DES_KEY_SIZE) { 2858c2ecf20Sopenharmony_ci valmr |= TDES_MR_KEYMOD_2KEY; 2868c2ecf20Sopenharmony_ci valmr |= TDES_MR_TDESMOD_TDES; 2878c2ecf20Sopenharmony_ci } else { 2888c2ecf20Sopenharmony_ci valmr |= TDES_MR_TDESMOD_DES; 2898c2ecf20Sopenharmony_ci } 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci valmr |= dd->flags & TDES_FLAGS_MODE_MASK; 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci atmel_tdes_write(dd, TDES_MR, valmr); 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci atmel_tdes_write_n(dd, TDES_KEY1W1R, dd->ctx->key, 2968c2ecf20Sopenharmony_ci dd->ctx->keylen >> 2); 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci if (dd->req->iv && (valmr & TDES_MR_OPMOD_MASK) != TDES_MR_OPMOD_ECB) 2998c2ecf20Sopenharmony_ci atmel_tdes_write_n(dd, TDES_IV1R, (void *)dd->req->iv, 2); 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci return 0; 3028c2ecf20Sopenharmony_ci} 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_cistatic int atmel_tdes_crypt_pdc_stop(struct atmel_tdes_dev *dd) 3058c2ecf20Sopenharmony_ci{ 3068c2ecf20Sopenharmony_ci int err = 0; 3078c2ecf20Sopenharmony_ci size_t count; 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci atmel_tdes_write(dd, TDES_PTCR, TDES_PTCR_TXTDIS|TDES_PTCR_RXTDIS); 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci if (dd->flags & TDES_FLAGS_FAST) { 3128c2ecf20Sopenharmony_ci dma_unmap_sg(dd->dev, dd->out_sg, 1, DMA_FROM_DEVICE); 3138c2ecf20Sopenharmony_ci dma_unmap_sg(dd->dev, dd->in_sg, 1, DMA_TO_DEVICE); 3148c2ecf20Sopenharmony_ci } else { 3158c2ecf20Sopenharmony_ci dma_sync_single_for_device(dd->dev, dd->dma_addr_out, 3168c2ecf20Sopenharmony_ci dd->dma_size, DMA_FROM_DEVICE); 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci /* copy data */ 3198c2ecf20Sopenharmony_ci count = atmel_tdes_sg_copy(&dd->out_sg, &dd->out_offset, 3208c2ecf20Sopenharmony_ci dd->buf_out, dd->buflen, dd->dma_size, 1); 3218c2ecf20Sopenharmony_ci if (count != dd->dma_size) { 3228c2ecf20Sopenharmony_ci err = -EINVAL; 3238c2ecf20Sopenharmony_ci pr_err("not all data converted: %zu\n", count); 3248c2ecf20Sopenharmony_ci } 3258c2ecf20Sopenharmony_ci } 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci return err; 3288c2ecf20Sopenharmony_ci} 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_cistatic int atmel_tdes_buff_init(struct atmel_tdes_dev *dd) 3318c2ecf20Sopenharmony_ci{ 3328c2ecf20Sopenharmony_ci int err = -ENOMEM; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci dd->buf_in = (void *)__get_free_pages(GFP_KERNEL, 0); 3358c2ecf20Sopenharmony_ci dd->buf_out = (void *)__get_free_pages(GFP_KERNEL, 0); 3368c2ecf20Sopenharmony_ci dd->buflen = PAGE_SIZE; 3378c2ecf20Sopenharmony_ci dd->buflen &= ~(DES_BLOCK_SIZE - 1); 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci if (!dd->buf_in || !dd->buf_out) { 3408c2ecf20Sopenharmony_ci dev_err(dd->dev, "unable to alloc pages.\n"); 3418c2ecf20Sopenharmony_ci goto err_alloc; 3428c2ecf20Sopenharmony_ci } 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci /* MAP here */ 3458c2ecf20Sopenharmony_ci dd->dma_addr_in = dma_map_single(dd->dev, dd->buf_in, 3468c2ecf20Sopenharmony_ci dd->buflen, DMA_TO_DEVICE); 3478c2ecf20Sopenharmony_ci if (dma_mapping_error(dd->dev, dd->dma_addr_in)) { 3488c2ecf20Sopenharmony_ci dev_err(dd->dev, "dma %zd bytes error\n", dd->buflen); 3498c2ecf20Sopenharmony_ci err = -EINVAL; 3508c2ecf20Sopenharmony_ci goto err_map_in; 3518c2ecf20Sopenharmony_ci } 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci dd->dma_addr_out = dma_map_single(dd->dev, dd->buf_out, 3548c2ecf20Sopenharmony_ci dd->buflen, DMA_FROM_DEVICE); 3558c2ecf20Sopenharmony_ci if (dma_mapping_error(dd->dev, dd->dma_addr_out)) { 3568c2ecf20Sopenharmony_ci dev_err(dd->dev, "dma %zd bytes error\n", dd->buflen); 3578c2ecf20Sopenharmony_ci err = -EINVAL; 3588c2ecf20Sopenharmony_ci goto err_map_out; 3598c2ecf20Sopenharmony_ci } 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci return 0; 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_cierr_map_out: 3648c2ecf20Sopenharmony_ci dma_unmap_single(dd->dev, dd->dma_addr_in, dd->buflen, 3658c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 3668c2ecf20Sopenharmony_cierr_map_in: 3678c2ecf20Sopenharmony_cierr_alloc: 3688c2ecf20Sopenharmony_ci free_page((unsigned long)dd->buf_out); 3698c2ecf20Sopenharmony_ci free_page((unsigned long)dd->buf_in); 3708c2ecf20Sopenharmony_ci if (err) 3718c2ecf20Sopenharmony_ci pr_err("error: %d\n", err); 3728c2ecf20Sopenharmony_ci return err; 3738c2ecf20Sopenharmony_ci} 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_cistatic void atmel_tdes_buff_cleanup(struct atmel_tdes_dev *dd) 3768c2ecf20Sopenharmony_ci{ 3778c2ecf20Sopenharmony_ci dma_unmap_single(dd->dev, dd->dma_addr_out, dd->buflen, 3788c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 3798c2ecf20Sopenharmony_ci dma_unmap_single(dd->dev, dd->dma_addr_in, dd->buflen, 3808c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 3818c2ecf20Sopenharmony_ci free_page((unsigned long)dd->buf_out); 3828c2ecf20Sopenharmony_ci free_page((unsigned long)dd->buf_in); 3838c2ecf20Sopenharmony_ci} 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_cistatic int atmel_tdes_crypt_pdc(struct atmel_tdes_dev *dd, 3868c2ecf20Sopenharmony_ci dma_addr_t dma_addr_in, 3878c2ecf20Sopenharmony_ci dma_addr_t dma_addr_out, int length) 3888c2ecf20Sopenharmony_ci{ 3898c2ecf20Sopenharmony_ci struct atmel_tdes_reqctx *rctx = skcipher_request_ctx(dd->req); 3908c2ecf20Sopenharmony_ci int len32; 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci dd->dma_size = length; 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci if (!(dd->flags & TDES_FLAGS_FAST)) { 3958c2ecf20Sopenharmony_ci dma_sync_single_for_device(dd->dev, dma_addr_in, length, 3968c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 3978c2ecf20Sopenharmony_ci } 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci switch (rctx->mode & TDES_FLAGS_OPMODE_MASK) { 4008c2ecf20Sopenharmony_ci case TDES_FLAGS_CFB8: 4018c2ecf20Sopenharmony_ci len32 = DIV_ROUND_UP(length, sizeof(u8)); 4028c2ecf20Sopenharmony_ci break; 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci case TDES_FLAGS_CFB16: 4058c2ecf20Sopenharmony_ci len32 = DIV_ROUND_UP(length, sizeof(u16)); 4068c2ecf20Sopenharmony_ci break; 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci default: 4098c2ecf20Sopenharmony_ci len32 = DIV_ROUND_UP(length, sizeof(u32)); 4108c2ecf20Sopenharmony_ci break; 4118c2ecf20Sopenharmony_ci } 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci atmel_tdes_write(dd, TDES_PTCR, TDES_PTCR_TXTDIS|TDES_PTCR_RXTDIS); 4148c2ecf20Sopenharmony_ci atmel_tdes_write(dd, TDES_TPR, dma_addr_in); 4158c2ecf20Sopenharmony_ci atmel_tdes_write(dd, TDES_TCR, len32); 4168c2ecf20Sopenharmony_ci atmel_tdes_write(dd, TDES_RPR, dma_addr_out); 4178c2ecf20Sopenharmony_ci atmel_tdes_write(dd, TDES_RCR, len32); 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci /* Enable Interrupt */ 4208c2ecf20Sopenharmony_ci atmel_tdes_write(dd, TDES_IER, TDES_INT_ENDRX); 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci /* Start DMA transfer */ 4238c2ecf20Sopenharmony_ci atmel_tdes_write(dd, TDES_PTCR, TDES_PTCR_TXTEN | TDES_PTCR_RXTEN); 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci return 0; 4268c2ecf20Sopenharmony_ci} 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_cistatic int atmel_tdes_crypt_dma(struct atmel_tdes_dev *dd, 4298c2ecf20Sopenharmony_ci dma_addr_t dma_addr_in, 4308c2ecf20Sopenharmony_ci dma_addr_t dma_addr_out, int length) 4318c2ecf20Sopenharmony_ci{ 4328c2ecf20Sopenharmony_ci struct atmel_tdes_reqctx *rctx = skcipher_request_ctx(dd->req); 4338c2ecf20Sopenharmony_ci struct scatterlist sg[2]; 4348c2ecf20Sopenharmony_ci struct dma_async_tx_descriptor *in_desc, *out_desc; 4358c2ecf20Sopenharmony_ci enum dma_slave_buswidth addr_width; 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci dd->dma_size = length; 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci if (!(dd->flags & TDES_FLAGS_FAST)) { 4408c2ecf20Sopenharmony_ci dma_sync_single_for_device(dd->dev, dma_addr_in, length, 4418c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 4428c2ecf20Sopenharmony_ci } 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci switch (rctx->mode & TDES_FLAGS_OPMODE_MASK) { 4458c2ecf20Sopenharmony_ci case TDES_FLAGS_CFB8: 4468c2ecf20Sopenharmony_ci addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; 4478c2ecf20Sopenharmony_ci break; 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci case TDES_FLAGS_CFB16: 4508c2ecf20Sopenharmony_ci addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; 4518c2ecf20Sopenharmony_ci break; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci default: 4548c2ecf20Sopenharmony_ci addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; 4558c2ecf20Sopenharmony_ci break; 4568c2ecf20Sopenharmony_ci } 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci dd->dma_lch_in.dma_conf.dst_addr_width = addr_width; 4598c2ecf20Sopenharmony_ci dd->dma_lch_out.dma_conf.src_addr_width = addr_width; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci dmaengine_slave_config(dd->dma_lch_in.chan, &dd->dma_lch_in.dma_conf); 4628c2ecf20Sopenharmony_ci dmaengine_slave_config(dd->dma_lch_out.chan, &dd->dma_lch_out.dma_conf); 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci dd->flags |= TDES_FLAGS_DMA; 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci sg_init_table(&sg[0], 1); 4678c2ecf20Sopenharmony_ci sg_dma_address(&sg[0]) = dma_addr_in; 4688c2ecf20Sopenharmony_ci sg_dma_len(&sg[0]) = length; 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci sg_init_table(&sg[1], 1); 4718c2ecf20Sopenharmony_ci sg_dma_address(&sg[1]) = dma_addr_out; 4728c2ecf20Sopenharmony_ci sg_dma_len(&sg[1]) = length; 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci in_desc = dmaengine_prep_slave_sg(dd->dma_lch_in.chan, &sg[0], 4758c2ecf20Sopenharmony_ci 1, DMA_MEM_TO_DEV, 4768c2ecf20Sopenharmony_ci DMA_PREP_INTERRUPT | DMA_CTRL_ACK); 4778c2ecf20Sopenharmony_ci if (!in_desc) 4788c2ecf20Sopenharmony_ci return -EINVAL; 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci out_desc = dmaengine_prep_slave_sg(dd->dma_lch_out.chan, &sg[1], 4818c2ecf20Sopenharmony_ci 1, DMA_DEV_TO_MEM, 4828c2ecf20Sopenharmony_ci DMA_PREP_INTERRUPT | DMA_CTRL_ACK); 4838c2ecf20Sopenharmony_ci if (!out_desc) 4848c2ecf20Sopenharmony_ci return -EINVAL; 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci out_desc->callback = atmel_tdes_dma_callback; 4878c2ecf20Sopenharmony_ci out_desc->callback_param = dd; 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci dmaengine_submit(out_desc); 4908c2ecf20Sopenharmony_ci dma_async_issue_pending(dd->dma_lch_out.chan); 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci dmaengine_submit(in_desc); 4938c2ecf20Sopenharmony_ci dma_async_issue_pending(dd->dma_lch_in.chan); 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci return 0; 4968c2ecf20Sopenharmony_ci} 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_cistatic int atmel_tdes_crypt_start(struct atmel_tdes_dev *dd) 4998c2ecf20Sopenharmony_ci{ 5008c2ecf20Sopenharmony_ci int err, fast = 0, in, out; 5018c2ecf20Sopenharmony_ci size_t count; 5028c2ecf20Sopenharmony_ci dma_addr_t addr_in, addr_out; 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci if ((!dd->in_offset) && (!dd->out_offset)) { 5058c2ecf20Sopenharmony_ci /* check for alignment */ 5068c2ecf20Sopenharmony_ci in = IS_ALIGNED((u32)dd->in_sg->offset, sizeof(u32)) && 5078c2ecf20Sopenharmony_ci IS_ALIGNED(dd->in_sg->length, dd->ctx->block_size); 5088c2ecf20Sopenharmony_ci out = IS_ALIGNED((u32)dd->out_sg->offset, sizeof(u32)) && 5098c2ecf20Sopenharmony_ci IS_ALIGNED(dd->out_sg->length, dd->ctx->block_size); 5108c2ecf20Sopenharmony_ci fast = in && out; 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci if (sg_dma_len(dd->in_sg) != sg_dma_len(dd->out_sg)) 5138c2ecf20Sopenharmony_ci fast = 0; 5148c2ecf20Sopenharmony_ci } 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci if (fast) { 5188c2ecf20Sopenharmony_ci count = min_t(size_t, dd->total, sg_dma_len(dd->in_sg)); 5198c2ecf20Sopenharmony_ci count = min_t(size_t, count, sg_dma_len(dd->out_sg)); 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci err = dma_map_sg(dd->dev, dd->in_sg, 1, DMA_TO_DEVICE); 5228c2ecf20Sopenharmony_ci if (!err) { 5238c2ecf20Sopenharmony_ci dev_err(dd->dev, "dma_map_sg() error\n"); 5248c2ecf20Sopenharmony_ci return -EINVAL; 5258c2ecf20Sopenharmony_ci } 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci err = dma_map_sg(dd->dev, dd->out_sg, 1, 5288c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 5298c2ecf20Sopenharmony_ci if (!err) { 5308c2ecf20Sopenharmony_ci dev_err(dd->dev, "dma_map_sg() error\n"); 5318c2ecf20Sopenharmony_ci dma_unmap_sg(dd->dev, dd->in_sg, 1, 5328c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 5338c2ecf20Sopenharmony_ci return -EINVAL; 5348c2ecf20Sopenharmony_ci } 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci addr_in = sg_dma_address(dd->in_sg); 5378c2ecf20Sopenharmony_ci addr_out = sg_dma_address(dd->out_sg); 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci dd->flags |= TDES_FLAGS_FAST; 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci } else { 5428c2ecf20Sopenharmony_ci /* use cache buffers */ 5438c2ecf20Sopenharmony_ci count = atmel_tdes_sg_copy(&dd->in_sg, &dd->in_offset, 5448c2ecf20Sopenharmony_ci dd->buf_in, dd->buflen, dd->total, 0); 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci addr_in = dd->dma_addr_in; 5478c2ecf20Sopenharmony_ci addr_out = dd->dma_addr_out; 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci dd->flags &= ~TDES_FLAGS_FAST; 5508c2ecf20Sopenharmony_ci } 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci dd->total -= count; 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci if (dd->caps.has_dma) 5558c2ecf20Sopenharmony_ci err = atmel_tdes_crypt_dma(dd, addr_in, addr_out, count); 5568c2ecf20Sopenharmony_ci else 5578c2ecf20Sopenharmony_ci err = atmel_tdes_crypt_pdc(dd, addr_in, addr_out, count); 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci if (err && (dd->flags & TDES_FLAGS_FAST)) { 5608c2ecf20Sopenharmony_ci dma_unmap_sg(dd->dev, dd->in_sg, 1, DMA_TO_DEVICE); 5618c2ecf20Sopenharmony_ci dma_unmap_sg(dd->dev, dd->out_sg, 1, DMA_TO_DEVICE); 5628c2ecf20Sopenharmony_ci } 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci return err; 5658c2ecf20Sopenharmony_ci} 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_cistatic void 5688c2ecf20Sopenharmony_ciatmel_tdes_set_iv_as_last_ciphertext_block(struct atmel_tdes_dev *dd) 5698c2ecf20Sopenharmony_ci{ 5708c2ecf20Sopenharmony_ci struct skcipher_request *req = dd->req; 5718c2ecf20Sopenharmony_ci struct atmel_tdes_reqctx *rctx = skcipher_request_ctx(req); 5728c2ecf20Sopenharmony_ci struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req); 5738c2ecf20Sopenharmony_ci unsigned int ivsize = crypto_skcipher_ivsize(skcipher); 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci if (req->cryptlen < ivsize) 5768c2ecf20Sopenharmony_ci return; 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci if (rctx->mode & TDES_FLAGS_ENCRYPT) { 5798c2ecf20Sopenharmony_ci scatterwalk_map_and_copy(req->iv, req->dst, 5808c2ecf20Sopenharmony_ci req->cryptlen - ivsize, ivsize, 0); 5818c2ecf20Sopenharmony_ci } else { 5828c2ecf20Sopenharmony_ci if (req->src == req->dst) 5838c2ecf20Sopenharmony_ci memcpy(req->iv, rctx->lastc, ivsize); 5848c2ecf20Sopenharmony_ci else 5858c2ecf20Sopenharmony_ci scatterwalk_map_and_copy(req->iv, req->src, 5868c2ecf20Sopenharmony_ci req->cryptlen - ivsize, 5878c2ecf20Sopenharmony_ci ivsize, 0); 5888c2ecf20Sopenharmony_ci } 5898c2ecf20Sopenharmony_ci} 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_cistatic void atmel_tdes_finish_req(struct atmel_tdes_dev *dd, int err) 5928c2ecf20Sopenharmony_ci{ 5938c2ecf20Sopenharmony_ci struct skcipher_request *req = dd->req; 5948c2ecf20Sopenharmony_ci struct atmel_tdes_reqctx *rctx = skcipher_request_ctx(req); 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci clk_disable_unprepare(dd->iclk); 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci dd->flags &= ~TDES_FLAGS_BUSY; 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci if (!err && (rctx->mode & TDES_FLAGS_OPMODE_MASK) != TDES_FLAGS_ECB) 6018c2ecf20Sopenharmony_ci atmel_tdes_set_iv_as_last_ciphertext_block(dd); 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci req->base.complete(&req->base, err); 6048c2ecf20Sopenharmony_ci} 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_cistatic int atmel_tdes_handle_queue(struct atmel_tdes_dev *dd, 6078c2ecf20Sopenharmony_ci struct skcipher_request *req) 6088c2ecf20Sopenharmony_ci{ 6098c2ecf20Sopenharmony_ci struct crypto_async_request *async_req, *backlog; 6108c2ecf20Sopenharmony_ci struct atmel_tdes_ctx *ctx; 6118c2ecf20Sopenharmony_ci struct atmel_tdes_reqctx *rctx; 6128c2ecf20Sopenharmony_ci unsigned long flags; 6138c2ecf20Sopenharmony_ci int err, ret = 0; 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci spin_lock_irqsave(&dd->lock, flags); 6168c2ecf20Sopenharmony_ci if (req) 6178c2ecf20Sopenharmony_ci ret = crypto_enqueue_request(&dd->queue, &req->base); 6188c2ecf20Sopenharmony_ci if (dd->flags & TDES_FLAGS_BUSY) { 6198c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dd->lock, flags); 6208c2ecf20Sopenharmony_ci return ret; 6218c2ecf20Sopenharmony_ci } 6228c2ecf20Sopenharmony_ci backlog = crypto_get_backlog(&dd->queue); 6238c2ecf20Sopenharmony_ci async_req = crypto_dequeue_request(&dd->queue); 6248c2ecf20Sopenharmony_ci if (async_req) 6258c2ecf20Sopenharmony_ci dd->flags |= TDES_FLAGS_BUSY; 6268c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dd->lock, flags); 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci if (!async_req) 6298c2ecf20Sopenharmony_ci return ret; 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci if (backlog) 6328c2ecf20Sopenharmony_ci backlog->complete(backlog, -EINPROGRESS); 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci req = skcipher_request_cast(async_req); 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci /* assign new request to device */ 6378c2ecf20Sopenharmony_ci dd->req = req; 6388c2ecf20Sopenharmony_ci dd->total = req->cryptlen; 6398c2ecf20Sopenharmony_ci dd->in_offset = 0; 6408c2ecf20Sopenharmony_ci dd->in_sg = req->src; 6418c2ecf20Sopenharmony_ci dd->out_offset = 0; 6428c2ecf20Sopenharmony_ci dd->out_sg = req->dst; 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci rctx = skcipher_request_ctx(req); 6458c2ecf20Sopenharmony_ci ctx = crypto_skcipher_ctx(crypto_skcipher_reqtfm(req)); 6468c2ecf20Sopenharmony_ci rctx->mode &= TDES_FLAGS_MODE_MASK; 6478c2ecf20Sopenharmony_ci dd->flags = (dd->flags & ~TDES_FLAGS_MODE_MASK) | rctx->mode; 6488c2ecf20Sopenharmony_ci dd->ctx = ctx; 6498c2ecf20Sopenharmony_ci ctx->dd = dd; 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci err = atmel_tdes_write_ctrl(dd); 6528c2ecf20Sopenharmony_ci if (!err) 6538c2ecf20Sopenharmony_ci err = atmel_tdes_crypt_start(dd); 6548c2ecf20Sopenharmony_ci if (err) { 6558c2ecf20Sopenharmony_ci /* des_task will not finish it, so do it here */ 6568c2ecf20Sopenharmony_ci atmel_tdes_finish_req(dd, err); 6578c2ecf20Sopenharmony_ci tasklet_schedule(&dd->queue_task); 6588c2ecf20Sopenharmony_ci } 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci return ret; 6618c2ecf20Sopenharmony_ci} 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_cistatic int atmel_tdes_crypt_dma_stop(struct atmel_tdes_dev *dd) 6648c2ecf20Sopenharmony_ci{ 6658c2ecf20Sopenharmony_ci int err = -EINVAL; 6668c2ecf20Sopenharmony_ci size_t count; 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci if (dd->flags & TDES_FLAGS_DMA) { 6698c2ecf20Sopenharmony_ci err = 0; 6708c2ecf20Sopenharmony_ci if (dd->flags & TDES_FLAGS_FAST) { 6718c2ecf20Sopenharmony_ci dma_unmap_sg(dd->dev, dd->out_sg, 1, DMA_FROM_DEVICE); 6728c2ecf20Sopenharmony_ci dma_unmap_sg(dd->dev, dd->in_sg, 1, DMA_TO_DEVICE); 6738c2ecf20Sopenharmony_ci } else { 6748c2ecf20Sopenharmony_ci dma_sync_single_for_device(dd->dev, dd->dma_addr_out, 6758c2ecf20Sopenharmony_ci dd->dma_size, DMA_FROM_DEVICE); 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci /* copy data */ 6788c2ecf20Sopenharmony_ci count = atmel_tdes_sg_copy(&dd->out_sg, &dd->out_offset, 6798c2ecf20Sopenharmony_ci dd->buf_out, dd->buflen, dd->dma_size, 1); 6808c2ecf20Sopenharmony_ci if (count != dd->dma_size) { 6818c2ecf20Sopenharmony_ci err = -EINVAL; 6828c2ecf20Sopenharmony_ci pr_err("not all data converted: %zu\n", count); 6838c2ecf20Sopenharmony_ci } 6848c2ecf20Sopenharmony_ci } 6858c2ecf20Sopenharmony_ci } 6868c2ecf20Sopenharmony_ci return err; 6878c2ecf20Sopenharmony_ci} 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_cistatic int atmel_tdes_crypt(struct skcipher_request *req, unsigned long mode) 6908c2ecf20Sopenharmony_ci{ 6918c2ecf20Sopenharmony_ci struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req); 6928c2ecf20Sopenharmony_ci struct atmel_tdes_ctx *ctx = crypto_skcipher_ctx(skcipher); 6938c2ecf20Sopenharmony_ci struct atmel_tdes_reqctx *rctx = skcipher_request_ctx(req); 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci switch (mode & TDES_FLAGS_OPMODE_MASK) { 6968c2ecf20Sopenharmony_ci case TDES_FLAGS_CFB8: 6978c2ecf20Sopenharmony_ci if (!IS_ALIGNED(req->cryptlen, CFB8_BLOCK_SIZE)) { 6988c2ecf20Sopenharmony_ci pr_err("request size is not exact amount of CFB8 blocks\n"); 6998c2ecf20Sopenharmony_ci return -EINVAL; 7008c2ecf20Sopenharmony_ci } 7018c2ecf20Sopenharmony_ci ctx->block_size = CFB8_BLOCK_SIZE; 7028c2ecf20Sopenharmony_ci break; 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci case TDES_FLAGS_CFB16: 7058c2ecf20Sopenharmony_ci if (!IS_ALIGNED(req->cryptlen, CFB16_BLOCK_SIZE)) { 7068c2ecf20Sopenharmony_ci pr_err("request size is not exact amount of CFB16 blocks\n"); 7078c2ecf20Sopenharmony_ci return -EINVAL; 7088c2ecf20Sopenharmony_ci } 7098c2ecf20Sopenharmony_ci ctx->block_size = CFB16_BLOCK_SIZE; 7108c2ecf20Sopenharmony_ci break; 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci case TDES_FLAGS_CFB32: 7138c2ecf20Sopenharmony_ci if (!IS_ALIGNED(req->cryptlen, CFB32_BLOCK_SIZE)) { 7148c2ecf20Sopenharmony_ci pr_err("request size is not exact amount of CFB32 blocks\n"); 7158c2ecf20Sopenharmony_ci return -EINVAL; 7168c2ecf20Sopenharmony_ci } 7178c2ecf20Sopenharmony_ci ctx->block_size = CFB32_BLOCK_SIZE; 7188c2ecf20Sopenharmony_ci break; 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci default: 7218c2ecf20Sopenharmony_ci if (!IS_ALIGNED(req->cryptlen, DES_BLOCK_SIZE)) { 7228c2ecf20Sopenharmony_ci pr_err("request size is not exact amount of DES blocks\n"); 7238c2ecf20Sopenharmony_ci return -EINVAL; 7248c2ecf20Sopenharmony_ci } 7258c2ecf20Sopenharmony_ci ctx->block_size = DES_BLOCK_SIZE; 7268c2ecf20Sopenharmony_ci break; 7278c2ecf20Sopenharmony_ci } 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci rctx->mode = mode; 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci if ((mode & TDES_FLAGS_OPMODE_MASK) != TDES_FLAGS_ECB && 7328c2ecf20Sopenharmony_ci !(mode & TDES_FLAGS_ENCRYPT) && req->src == req->dst) { 7338c2ecf20Sopenharmony_ci unsigned int ivsize = crypto_skcipher_ivsize(skcipher); 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci if (req->cryptlen >= ivsize) 7368c2ecf20Sopenharmony_ci scatterwalk_map_and_copy(rctx->lastc, req->src, 7378c2ecf20Sopenharmony_ci req->cryptlen - ivsize, 7388c2ecf20Sopenharmony_ci ivsize, 0); 7398c2ecf20Sopenharmony_ci } 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci return atmel_tdes_handle_queue(ctx->dd, req); 7428c2ecf20Sopenharmony_ci} 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_cistatic int atmel_tdes_dma_init(struct atmel_tdes_dev *dd) 7458c2ecf20Sopenharmony_ci{ 7468c2ecf20Sopenharmony_ci int ret; 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci /* Try to grab 2 DMA channels */ 7498c2ecf20Sopenharmony_ci dd->dma_lch_in.chan = dma_request_chan(dd->dev, "tx"); 7508c2ecf20Sopenharmony_ci if (IS_ERR(dd->dma_lch_in.chan)) { 7518c2ecf20Sopenharmony_ci ret = PTR_ERR(dd->dma_lch_in.chan); 7528c2ecf20Sopenharmony_ci goto err_dma_in; 7538c2ecf20Sopenharmony_ci } 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci dd->dma_lch_in.dma_conf.dst_addr = dd->phys_base + 7568c2ecf20Sopenharmony_ci TDES_IDATA1R; 7578c2ecf20Sopenharmony_ci dd->dma_lch_in.dma_conf.src_maxburst = 1; 7588c2ecf20Sopenharmony_ci dd->dma_lch_in.dma_conf.src_addr_width = 7598c2ecf20Sopenharmony_ci DMA_SLAVE_BUSWIDTH_4_BYTES; 7608c2ecf20Sopenharmony_ci dd->dma_lch_in.dma_conf.dst_maxburst = 1; 7618c2ecf20Sopenharmony_ci dd->dma_lch_in.dma_conf.dst_addr_width = 7628c2ecf20Sopenharmony_ci DMA_SLAVE_BUSWIDTH_4_BYTES; 7638c2ecf20Sopenharmony_ci dd->dma_lch_in.dma_conf.device_fc = false; 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci dd->dma_lch_out.chan = dma_request_chan(dd->dev, "rx"); 7668c2ecf20Sopenharmony_ci if (IS_ERR(dd->dma_lch_out.chan)) { 7678c2ecf20Sopenharmony_ci ret = PTR_ERR(dd->dma_lch_out.chan); 7688c2ecf20Sopenharmony_ci goto err_dma_out; 7698c2ecf20Sopenharmony_ci } 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci dd->dma_lch_out.dma_conf.src_addr = dd->phys_base + 7728c2ecf20Sopenharmony_ci TDES_ODATA1R; 7738c2ecf20Sopenharmony_ci dd->dma_lch_out.dma_conf.src_maxburst = 1; 7748c2ecf20Sopenharmony_ci dd->dma_lch_out.dma_conf.src_addr_width = 7758c2ecf20Sopenharmony_ci DMA_SLAVE_BUSWIDTH_4_BYTES; 7768c2ecf20Sopenharmony_ci dd->dma_lch_out.dma_conf.dst_maxburst = 1; 7778c2ecf20Sopenharmony_ci dd->dma_lch_out.dma_conf.dst_addr_width = 7788c2ecf20Sopenharmony_ci DMA_SLAVE_BUSWIDTH_4_BYTES; 7798c2ecf20Sopenharmony_ci dd->dma_lch_out.dma_conf.device_fc = false; 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci return 0; 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_cierr_dma_out: 7848c2ecf20Sopenharmony_ci dma_release_channel(dd->dma_lch_in.chan); 7858c2ecf20Sopenharmony_cierr_dma_in: 7868c2ecf20Sopenharmony_ci dev_err(dd->dev, "no DMA channel available\n"); 7878c2ecf20Sopenharmony_ci return ret; 7888c2ecf20Sopenharmony_ci} 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_cistatic void atmel_tdes_dma_cleanup(struct atmel_tdes_dev *dd) 7918c2ecf20Sopenharmony_ci{ 7928c2ecf20Sopenharmony_ci dma_release_channel(dd->dma_lch_in.chan); 7938c2ecf20Sopenharmony_ci dma_release_channel(dd->dma_lch_out.chan); 7948c2ecf20Sopenharmony_ci} 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_cistatic int atmel_des_setkey(struct crypto_skcipher *tfm, const u8 *key, 7978c2ecf20Sopenharmony_ci unsigned int keylen) 7988c2ecf20Sopenharmony_ci{ 7998c2ecf20Sopenharmony_ci struct atmel_tdes_ctx *ctx = crypto_skcipher_ctx(tfm); 8008c2ecf20Sopenharmony_ci int err; 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_ci err = verify_skcipher_des_key(tfm, key); 8038c2ecf20Sopenharmony_ci if (err) 8048c2ecf20Sopenharmony_ci return err; 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ci memcpy(ctx->key, key, keylen); 8078c2ecf20Sopenharmony_ci ctx->keylen = keylen; 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci return 0; 8108c2ecf20Sopenharmony_ci} 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_cistatic int atmel_tdes_setkey(struct crypto_skcipher *tfm, const u8 *key, 8138c2ecf20Sopenharmony_ci unsigned int keylen) 8148c2ecf20Sopenharmony_ci{ 8158c2ecf20Sopenharmony_ci struct atmel_tdes_ctx *ctx = crypto_skcipher_ctx(tfm); 8168c2ecf20Sopenharmony_ci int err; 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ci err = verify_skcipher_des3_key(tfm, key); 8198c2ecf20Sopenharmony_ci if (err) 8208c2ecf20Sopenharmony_ci return err; 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci memcpy(ctx->key, key, keylen); 8238c2ecf20Sopenharmony_ci ctx->keylen = keylen; 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_ci return 0; 8268c2ecf20Sopenharmony_ci} 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_cistatic int atmel_tdes_ecb_encrypt(struct skcipher_request *req) 8298c2ecf20Sopenharmony_ci{ 8308c2ecf20Sopenharmony_ci return atmel_tdes_crypt(req, TDES_FLAGS_ECB | TDES_FLAGS_ENCRYPT); 8318c2ecf20Sopenharmony_ci} 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_cistatic int atmel_tdes_ecb_decrypt(struct skcipher_request *req) 8348c2ecf20Sopenharmony_ci{ 8358c2ecf20Sopenharmony_ci return atmel_tdes_crypt(req, TDES_FLAGS_ECB); 8368c2ecf20Sopenharmony_ci} 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_cistatic int atmel_tdes_cbc_encrypt(struct skcipher_request *req) 8398c2ecf20Sopenharmony_ci{ 8408c2ecf20Sopenharmony_ci return atmel_tdes_crypt(req, TDES_FLAGS_CBC | TDES_FLAGS_ENCRYPT); 8418c2ecf20Sopenharmony_ci} 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_cistatic int atmel_tdes_cbc_decrypt(struct skcipher_request *req) 8448c2ecf20Sopenharmony_ci{ 8458c2ecf20Sopenharmony_ci return atmel_tdes_crypt(req, TDES_FLAGS_CBC); 8468c2ecf20Sopenharmony_ci} 8478c2ecf20Sopenharmony_cistatic int atmel_tdes_cfb_encrypt(struct skcipher_request *req) 8488c2ecf20Sopenharmony_ci{ 8498c2ecf20Sopenharmony_ci return atmel_tdes_crypt(req, TDES_FLAGS_CFB64 | TDES_FLAGS_ENCRYPT); 8508c2ecf20Sopenharmony_ci} 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_cistatic int atmel_tdes_cfb_decrypt(struct skcipher_request *req) 8538c2ecf20Sopenharmony_ci{ 8548c2ecf20Sopenharmony_ci return atmel_tdes_crypt(req, TDES_FLAGS_CFB64); 8558c2ecf20Sopenharmony_ci} 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_cistatic int atmel_tdes_cfb8_encrypt(struct skcipher_request *req) 8588c2ecf20Sopenharmony_ci{ 8598c2ecf20Sopenharmony_ci return atmel_tdes_crypt(req, TDES_FLAGS_CFB8 | TDES_FLAGS_ENCRYPT); 8608c2ecf20Sopenharmony_ci} 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_cistatic int atmel_tdes_cfb8_decrypt(struct skcipher_request *req) 8638c2ecf20Sopenharmony_ci{ 8648c2ecf20Sopenharmony_ci return atmel_tdes_crypt(req, TDES_FLAGS_CFB8); 8658c2ecf20Sopenharmony_ci} 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_cistatic int atmel_tdes_cfb16_encrypt(struct skcipher_request *req) 8688c2ecf20Sopenharmony_ci{ 8698c2ecf20Sopenharmony_ci return atmel_tdes_crypt(req, TDES_FLAGS_CFB16 | TDES_FLAGS_ENCRYPT); 8708c2ecf20Sopenharmony_ci} 8718c2ecf20Sopenharmony_ci 8728c2ecf20Sopenharmony_cistatic int atmel_tdes_cfb16_decrypt(struct skcipher_request *req) 8738c2ecf20Sopenharmony_ci{ 8748c2ecf20Sopenharmony_ci return atmel_tdes_crypt(req, TDES_FLAGS_CFB16); 8758c2ecf20Sopenharmony_ci} 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_cistatic int atmel_tdes_cfb32_encrypt(struct skcipher_request *req) 8788c2ecf20Sopenharmony_ci{ 8798c2ecf20Sopenharmony_ci return atmel_tdes_crypt(req, TDES_FLAGS_CFB32 | TDES_FLAGS_ENCRYPT); 8808c2ecf20Sopenharmony_ci} 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_cistatic int atmel_tdes_cfb32_decrypt(struct skcipher_request *req) 8838c2ecf20Sopenharmony_ci{ 8848c2ecf20Sopenharmony_ci return atmel_tdes_crypt(req, TDES_FLAGS_CFB32); 8858c2ecf20Sopenharmony_ci} 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_cistatic int atmel_tdes_ofb_encrypt(struct skcipher_request *req) 8888c2ecf20Sopenharmony_ci{ 8898c2ecf20Sopenharmony_ci return atmel_tdes_crypt(req, TDES_FLAGS_OFB | TDES_FLAGS_ENCRYPT); 8908c2ecf20Sopenharmony_ci} 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_cistatic int atmel_tdes_ofb_decrypt(struct skcipher_request *req) 8938c2ecf20Sopenharmony_ci{ 8948c2ecf20Sopenharmony_ci return atmel_tdes_crypt(req, TDES_FLAGS_OFB); 8958c2ecf20Sopenharmony_ci} 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_cistatic int atmel_tdes_init_tfm(struct crypto_skcipher *tfm) 8988c2ecf20Sopenharmony_ci{ 8998c2ecf20Sopenharmony_ci struct atmel_tdes_ctx *ctx = crypto_skcipher_ctx(tfm); 9008c2ecf20Sopenharmony_ci struct atmel_tdes_dev *dd; 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci crypto_skcipher_set_reqsize(tfm, sizeof(struct atmel_tdes_reqctx)); 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_ci dd = atmel_tdes_find_dev(ctx); 9058c2ecf20Sopenharmony_ci if (!dd) 9068c2ecf20Sopenharmony_ci return -ENODEV; 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_ci return 0; 9098c2ecf20Sopenharmony_ci} 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_cistatic void atmel_tdes_skcipher_alg_init(struct skcipher_alg *alg) 9128c2ecf20Sopenharmony_ci{ 9138c2ecf20Sopenharmony_ci alg->base.cra_priority = ATMEL_TDES_PRIORITY; 9148c2ecf20Sopenharmony_ci alg->base.cra_flags = CRYPTO_ALG_ASYNC; 9158c2ecf20Sopenharmony_ci alg->base.cra_ctxsize = sizeof(struct atmel_tdes_ctx); 9168c2ecf20Sopenharmony_ci alg->base.cra_module = THIS_MODULE; 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_ci alg->init = atmel_tdes_init_tfm; 9198c2ecf20Sopenharmony_ci} 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_cistatic struct skcipher_alg tdes_algs[] = { 9228c2ecf20Sopenharmony_ci{ 9238c2ecf20Sopenharmony_ci .base.cra_name = "ecb(des)", 9248c2ecf20Sopenharmony_ci .base.cra_driver_name = "atmel-ecb-des", 9258c2ecf20Sopenharmony_ci .base.cra_blocksize = DES_BLOCK_SIZE, 9268c2ecf20Sopenharmony_ci .base.cra_alignmask = 0x7, 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_ci .min_keysize = DES_KEY_SIZE, 9298c2ecf20Sopenharmony_ci .max_keysize = DES_KEY_SIZE, 9308c2ecf20Sopenharmony_ci .setkey = atmel_des_setkey, 9318c2ecf20Sopenharmony_ci .encrypt = atmel_tdes_ecb_encrypt, 9328c2ecf20Sopenharmony_ci .decrypt = atmel_tdes_ecb_decrypt, 9338c2ecf20Sopenharmony_ci}, 9348c2ecf20Sopenharmony_ci{ 9358c2ecf20Sopenharmony_ci .base.cra_name = "cbc(des)", 9368c2ecf20Sopenharmony_ci .base.cra_driver_name = "atmel-cbc-des", 9378c2ecf20Sopenharmony_ci .base.cra_blocksize = DES_BLOCK_SIZE, 9388c2ecf20Sopenharmony_ci .base.cra_alignmask = 0x7, 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_ci .min_keysize = DES_KEY_SIZE, 9418c2ecf20Sopenharmony_ci .max_keysize = DES_KEY_SIZE, 9428c2ecf20Sopenharmony_ci .ivsize = DES_BLOCK_SIZE, 9438c2ecf20Sopenharmony_ci .setkey = atmel_des_setkey, 9448c2ecf20Sopenharmony_ci .encrypt = atmel_tdes_cbc_encrypt, 9458c2ecf20Sopenharmony_ci .decrypt = atmel_tdes_cbc_decrypt, 9468c2ecf20Sopenharmony_ci}, 9478c2ecf20Sopenharmony_ci{ 9488c2ecf20Sopenharmony_ci .base.cra_name = "cfb(des)", 9498c2ecf20Sopenharmony_ci .base.cra_driver_name = "atmel-cfb-des", 9508c2ecf20Sopenharmony_ci .base.cra_blocksize = DES_BLOCK_SIZE, 9518c2ecf20Sopenharmony_ci .base.cra_alignmask = 0x7, 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_ci .min_keysize = DES_KEY_SIZE, 9548c2ecf20Sopenharmony_ci .max_keysize = DES_KEY_SIZE, 9558c2ecf20Sopenharmony_ci .ivsize = DES_BLOCK_SIZE, 9568c2ecf20Sopenharmony_ci .setkey = atmel_des_setkey, 9578c2ecf20Sopenharmony_ci .encrypt = atmel_tdes_cfb_encrypt, 9588c2ecf20Sopenharmony_ci .decrypt = atmel_tdes_cfb_decrypt, 9598c2ecf20Sopenharmony_ci}, 9608c2ecf20Sopenharmony_ci{ 9618c2ecf20Sopenharmony_ci .base.cra_name = "cfb8(des)", 9628c2ecf20Sopenharmony_ci .base.cra_driver_name = "atmel-cfb8-des", 9638c2ecf20Sopenharmony_ci .base.cra_blocksize = CFB8_BLOCK_SIZE, 9648c2ecf20Sopenharmony_ci .base.cra_alignmask = 0, 9658c2ecf20Sopenharmony_ci 9668c2ecf20Sopenharmony_ci .min_keysize = DES_KEY_SIZE, 9678c2ecf20Sopenharmony_ci .max_keysize = DES_KEY_SIZE, 9688c2ecf20Sopenharmony_ci .ivsize = DES_BLOCK_SIZE, 9698c2ecf20Sopenharmony_ci .setkey = atmel_des_setkey, 9708c2ecf20Sopenharmony_ci .encrypt = atmel_tdes_cfb8_encrypt, 9718c2ecf20Sopenharmony_ci .decrypt = atmel_tdes_cfb8_decrypt, 9728c2ecf20Sopenharmony_ci}, 9738c2ecf20Sopenharmony_ci{ 9748c2ecf20Sopenharmony_ci .base.cra_name = "cfb16(des)", 9758c2ecf20Sopenharmony_ci .base.cra_driver_name = "atmel-cfb16-des", 9768c2ecf20Sopenharmony_ci .base.cra_blocksize = CFB16_BLOCK_SIZE, 9778c2ecf20Sopenharmony_ci .base.cra_alignmask = 0x1, 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_ci .min_keysize = DES_KEY_SIZE, 9808c2ecf20Sopenharmony_ci .max_keysize = DES_KEY_SIZE, 9818c2ecf20Sopenharmony_ci .ivsize = DES_BLOCK_SIZE, 9828c2ecf20Sopenharmony_ci .setkey = atmel_des_setkey, 9838c2ecf20Sopenharmony_ci .encrypt = atmel_tdes_cfb16_encrypt, 9848c2ecf20Sopenharmony_ci .decrypt = atmel_tdes_cfb16_decrypt, 9858c2ecf20Sopenharmony_ci}, 9868c2ecf20Sopenharmony_ci{ 9878c2ecf20Sopenharmony_ci .base.cra_name = "cfb32(des)", 9888c2ecf20Sopenharmony_ci .base.cra_driver_name = "atmel-cfb32-des", 9898c2ecf20Sopenharmony_ci .base.cra_blocksize = CFB32_BLOCK_SIZE, 9908c2ecf20Sopenharmony_ci .base.cra_alignmask = 0x3, 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_ci .min_keysize = DES_KEY_SIZE, 9938c2ecf20Sopenharmony_ci .max_keysize = DES_KEY_SIZE, 9948c2ecf20Sopenharmony_ci .ivsize = DES_BLOCK_SIZE, 9958c2ecf20Sopenharmony_ci .setkey = atmel_des_setkey, 9968c2ecf20Sopenharmony_ci .encrypt = atmel_tdes_cfb32_encrypt, 9978c2ecf20Sopenharmony_ci .decrypt = atmel_tdes_cfb32_decrypt, 9988c2ecf20Sopenharmony_ci}, 9998c2ecf20Sopenharmony_ci{ 10008c2ecf20Sopenharmony_ci .base.cra_name = "ofb(des)", 10018c2ecf20Sopenharmony_ci .base.cra_driver_name = "atmel-ofb-des", 10028c2ecf20Sopenharmony_ci .base.cra_blocksize = DES_BLOCK_SIZE, 10038c2ecf20Sopenharmony_ci .base.cra_alignmask = 0x7, 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_ci .min_keysize = DES_KEY_SIZE, 10068c2ecf20Sopenharmony_ci .max_keysize = DES_KEY_SIZE, 10078c2ecf20Sopenharmony_ci .ivsize = DES_BLOCK_SIZE, 10088c2ecf20Sopenharmony_ci .setkey = atmel_des_setkey, 10098c2ecf20Sopenharmony_ci .encrypt = atmel_tdes_ofb_encrypt, 10108c2ecf20Sopenharmony_ci .decrypt = atmel_tdes_ofb_decrypt, 10118c2ecf20Sopenharmony_ci}, 10128c2ecf20Sopenharmony_ci{ 10138c2ecf20Sopenharmony_ci .base.cra_name = "ecb(des3_ede)", 10148c2ecf20Sopenharmony_ci .base.cra_driver_name = "atmel-ecb-tdes", 10158c2ecf20Sopenharmony_ci .base.cra_blocksize = DES_BLOCK_SIZE, 10168c2ecf20Sopenharmony_ci .base.cra_alignmask = 0x7, 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_ci .min_keysize = DES3_EDE_KEY_SIZE, 10198c2ecf20Sopenharmony_ci .max_keysize = DES3_EDE_KEY_SIZE, 10208c2ecf20Sopenharmony_ci .setkey = atmel_tdes_setkey, 10218c2ecf20Sopenharmony_ci .encrypt = atmel_tdes_ecb_encrypt, 10228c2ecf20Sopenharmony_ci .decrypt = atmel_tdes_ecb_decrypt, 10238c2ecf20Sopenharmony_ci}, 10248c2ecf20Sopenharmony_ci{ 10258c2ecf20Sopenharmony_ci .base.cra_name = "cbc(des3_ede)", 10268c2ecf20Sopenharmony_ci .base.cra_driver_name = "atmel-cbc-tdes", 10278c2ecf20Sopenharmony_ci .base.cra_blocksize = DES_BLOCK_SIZE, 10288c2ecf20Sopenharmony_ci .base.cra_alignmask = 0x7, 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_ci .min_keysize = DES3_EDE_KEY_SIZE, 10318c2ecf20Sopenharmony_ci .max_keysize = DES3_EDE_KEY_SIZE, 10328c2ecf20Sopenharmony_ci .setkey = atmel_tdes_setkey, 10338c2ecf20Sopenharmony_ci .encrypt = atmel_tdes_cbc_encrypt, 10348c2ecf20Sopenharmony_ci .decrypt = atmel_tdes_cbc_decrypt, 10358c2ecf20Sopenharmony_ci .ivsize = DES_BLOCK_SIZE, 10368c2ecf20Sopenharmony_ci}, 10378c2ecf20Sopenharmony_ci{ 10388c2ecf20Sopenharmony_ci .base.cra_name = "ofb(des3_ede)", 10398c2ecf20Sopenharmony_ci .base.cra_driver_name = "atmel-ofb-tdes", 10408c2ecf20Sopenharmony_ci .base.cra_blocksize = DES_BLOCK_SIZE, 10418c2ecf20Sopenharmony_ci .base.cra_alignmask = 0x7, 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_ci .min_keysize = DES3_EDE_KEY_SIZE, 10448c2ecf20Sopenharmony_ci .max_keysize = DES3_EDE_KEY_SIZE, 10458c2ecf20Sopenharmony_ci .setkey = atmel_tdes_setkey, 10468c2ecf20Sopenharmony_ci .encrypt = atmel_tdes_ofb_encrypt, 10478c2ecf20Sopenharmony_ci .decrypt = atmel_tdes_ofb_decrypt, 10488c2ecf20Sopenharmony_ci .ivsize = DES_BLOCK_SIZE, 10498c2ecf20Sopenharmony_ci}, 10508c2ecf20Sopenharmony_ci}; 10518c2ecf20Sopenharmony_ci 10528c2ecf20Sopenharmony_cistatic void atmel_tdes_queue_task(unsigned long data) 10538c2ecf20Sopenharmony_ci{ 10548c2ecf20Sopenharmony_ci struct atmel_tdes_dev *dd = (struct atmel_tdes_dev *)data; 10558c2ecf20Sopenharmony_ci 10568c2ecf20Sopenharmony_ci atmel_tdes_handle_queue(dd, NULL); 10578c2ecf20Sopenharmony_ci} 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_cistatic void atmel_tdes_done_task(unsigned long data) 10608c2ecf20Sopenharmony_ci{ 10618c2ecf20Sopenharmony_ci struct atmel_tdes_dev *dd = (struct atmel_tdes_dev *) data; 10628c2ecf20Sopenharmony_ci int err; 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_ci if (!(dd->flags & TDES_FLAGS_DMA)) 10658c2ecf20Sopenharmony_ci err = atmel_tdes_crypt_pdc_stop(dd); 10668c2ecf20Sopenharmony_ci else 10678c2ecf20Sopenharmony_ci err = atmel_tdes_crypt_dma_stop(dd); 10688c2ecf20Sopenharmony_ci 10698c2ecf20Sopenharmony_ci if (dd->total && !err) { 10708c2ecf20Sopenharmony_ci if (dd->flags & TDES_FLAGS_FAST) { 10718c2ecf20Sopenharmony_ci dd->in_sg = sg_next(dd->in_sg); 10728c2ecf20Sopenharmony_ci dd->out_sg = sg_next(dd->out_sg); 10738c2ecf20Sopenharmony_ci if (!dd->in_sg || !dd->out_sg) 10748c2ecf20Sopenharmony_ci err = -EINVAL; 10758c2ecf20Sopenharmony_ci } 10768c2ecf20Sopenharmony_ci if (!err) 10778c2ecf20Sopenharmony_ci err = atmel_tdes_crypt_start(dd); 10788c2ecf20Sopenharmony_ci if (!err) 10798c2ecf20Sopenharmony_ci return; /* DMA started. Not fininishing. */ 10808c2ecf20Sopenharmony_ci } 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_ci atmel_tdes_finish_req(dd, err); 10838c2ecf20Sopenharmony_ci atmel_tdes_handle_queue(dd, NULL); 10848c2ecf20Sopenharmony_ci} 10858c2ecf20Sopenharmony_ci 10868c2ecf20Sopenharmony_cistatic irqreturn_t atmel_tdes_irq(int irq, void *dev_id) 10878c2ecf20Sopenharmony_ci{ 10888c2ecf20Sopenharmony_ci struct atmel_tdes_dev *tdes_dd = dev_id; 10898c2ecf20Sopenharmony_ci u32 reg; 10908c2ecf20Sopenharmony_ci 10918c2ecf20Sopenharmony_ci reg = atmel_tdes_read(tdes_dd, TDES_ISR); 10928c2ecf20Sopenharmony_ci if (reg & atmel_tdes_read(tdes_dd, TDES_IMR)) { 10938c2ecf20Sopenharmony_ci atmel_tdes_write(tdes_dd, TDES_IDR, reg); 10948c2ecf20Sopenharmony_ci if (TDES_FLAGS_BUSY & tdes_dd->flags) 10958c2ecf20Sopenharmony_ci tasklet_schedule(&tdes_dd->done_task); 10968c2ecf20Sopenharmony_ci else 10978c2ecf20Sopenharmony_ci dev_warn(tdes_dd->dev, "TDES interrupt when no active requests.\n"); 10988c2ecf20Sopenharmony_ci return IRQ_HANDLED; 10998c2ecf20Sopenharmony_ci } 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_ci return IRQ_NONE; 11028c2ecf20Sopenharmony_ci} 11038c2ecf20Sopenharmony_ci 11048c2ecf20Sopenharmony_cistatic void atmel_tdes_unregister_algs(struct atmel_tdes_dev *dd) 11058c2ecf20Sopenharmony_ci{ 11068c2ecf20Sopenharmony_ci int i; 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(tdes_algs); i++) 11098c2ecf20Sopenharmony_ci crypto_unregister_skcipher(&tdes_algs[i]); 11108c2ecf20Sopenharmony_ci} 11118c2ecf20Sopenharmony_ci 11128c2ecf20Sopenharmony_cistatic int atmel_tdes_register_algs(struct atmel_tdes_dev *dd) 11138c2ecf20Sopenharmony_ci{ 11148c2ecf20Sopenharmony_ci int err, i, j; 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(tdes_algs); i++) { 11178c2ecf20Sopenharmony_ci atmel_tdes_skcipher_alg_init(&tdes_algs[i]); 11188c2ecf20Sopenharmony_ci 11198c2ecf20Sopenharmony_ci err = crypto_register_skcipher(&tdes_algs[i]); 11208c2ecf20Sopenharmony_ci if (err) 11218c2ecf20Sopenharmony_ci goto err_tdes_algs; 11228c2ecf20Sopenharmony_ci } 11238c2ecf20Sopenharmony_ci 11248c2ecf20Sopenharmony_ci return 0; 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_cierr_tdes_algs: 11278c2ecf20Sopenharmony_ci for (j = 0; j < i; j++) 11288c2ecf20Sopenharmony_ci crypto_unregister_skcipher(&tdes_algs[j]); 11298c2ecf20Sopenharmony_ci 11308c2ecf20Sopenharmony_ci return err; 11318c2ecf20Sopenharmony_ci} 11328c2ecf20Sopenharmony_ci 11338c2ecf20Sopenharmony_cistatic void atmel_tdes_get_cap(struct atmel_tdes_dev *dd) 11348c2ecf20Sopenharmony_ci{ 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_ci dd->caps.has_dma = 0; 11378c2ecf20Sopenharmony_ci dd->caps.has_cfb_3keys = 0; 11388c2ecf20Sopenharmony_ci 11398c2ecf20Sopenharmony_ci /* keep only major version number */ 11408c2ecf20Sopenharmony_ci switch (dd->hw_version & 0xf00) { 11418c2ecf20Sopenharmony_ci case 0x700: 11428c2ecf20Sopenharmony_ci dd->caps.has_dma = 1; 11438c2ecf20Sopenharmony_ci dd->caps.has_cfb_3keys = 1; 11448c2ecf20Sopenharmony_ci break; 11458c2ecf20Sopenharmony_ci case 0x600: 11468c2ecf20Sopenharmony_ci break; 11478c2ecf20Sopenharmony_ci default: 11488c2ecf20Sopenharmony_ci dev_warn(dd->dev, 11498c2ecf20Sopenharmony_ci "Unmanaged tdes version, set minimum capabilities\n"); 11508c2ecf20Sopenharmony_ci break; 11518c2ecf20Sopenharmony_ci } 11528c2ecf20Sopenharmony_ci} 11538c2ecf20Sopenharmony_ci 11548c2ecf20Sopenharmony_ci#if defined(CONFIG_OF) 11558c2ecf20Sopenharmony_cistatic const struct of_device_id atmel_tdes_dt_ids[] = { 11568c2ecf20Sopenharmony_ci { .compatible = "atmel,at91sam9g46-tdes" }, 11578c2ecf20Sopenharmony_ci { /* sentinel */ } 11588c2ecf20Sopenharmony_ci}; 11598c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, atmel_tdes_dt_ids); 11608c2ecf20Sopenharmony_ci#endif 11618c2ecf20Sopenharmony_ci 11628c2ecf20Sopenharmony_cistatic int atmel_tdes_probe(struct platform_device *pdev) 11638c2ecf20Sopenharmony_ci{ 11648c2ecf20Sopenharmony_ci struct atmel_tdes_dev *tdes_dd; 11658c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 11668c2ecf20Sopenharmony_ci struct resource *tdes_res; 11678c2ecf20Sopenharmony_ci int err; 11688c2ecf20Sopenharmony_ci 11698c2ecf20Sopenharmony_ci tdes_dd = devm_kmalloc(&pdev->dev, sizeof(*tdes_dd), GFP_KERNEL); 11708c2ecf20Sopenharmony_ci if (!tdes_dd) 11718c2ecf20Sopenharmony_ci return -ENOMEM; 11728c2ecf20Sopenharmony_ci 11738c2ecf20Sopenharmony_ci tdes_dd->dev = dev; 11748c2ecf20Sopenharmony_ci 11758c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, tdes_dd); 11768c2ecf20Sopenharmony_ci 11778c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&tdes_dd->list); 11788c2ecf20Sopenharmony_ci spin_lock_init(&tdes_dd->lock); 11798c2ecf20Sopenharmony_ci 11808c2ecf20Sopenharmony_ci tasklet_init(&tdes_dd->done_task, atmel_tdes_done_task, 11818c2ecf20Sopenharmony_ci (unsigned long)tdes_dd); 11828c2ecf20Sopenharmony_ci tasklet_init(&tdes_dd->queue_task, atmel_tdes_queue_task, 11838c2ecf20Sopenharmony_ci (unsigned long)tdes_dd); 11848c2ecf20Sopenharmony_ci 11858c2ecf20Sopenharmony_ci crypto_init_queue(&tdes_dd->queue, ATMEL_TDES_QUEUE_LENGTH); 11868c2ecf20Sopenharmony_ci 11878c2ecf20Sopenharmony_ci /* Get the base address */ 11888c2ecf20Sopenharmony_ci tdes_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 11898c2ecf20Sopenharmony_ci if (!tdes_res) { 11908c2ecf20Sopenharmony_ci dev_err(dev, "no MEM resource info\n"); 11918c2ecf20Sopenharmony_ci err = -ENODEV; 11928c2ecf20Sopenharmony_ci goto err_tasklet_kill; 11938c2ecf20Sopenharmony_ci } 11948c2ecf20Sopenharmony_ci tdes_dd->phys_base = tdes_res->start; 11958c2ecf20Sopenharmony_ci 11968c2ecf20Sopenharmony_ci /* Get the IRQ */ 11978c2ecf20Sopenharmony_ci tdes_dd->irq = platform_get_irq(pdev, 0); 11988c2ecf20Sopenharmony_ci if (tdes_dd->irq < 0) { 11998c2ecf20Sopenharmony_ci err = tdes_dd->irq; 12008c2ecf20Sopenharmony_ci goto err_tasklet_kill; 12018c2ecf20Sopenharmony_ci } 12028c2ecf20Sopenharmony_ci 12038c2ecf20Sopenharmony_ci err = devm_request_irq(&pdev->dev, tdes_dd->irq, atmel_tdes_irq, 12048c2ecf20Sopenharmony_ci IRQF_SHARED, "atmel-tdes", tdes_dd); 12058c2ecf20Sopenharmony_ci if (err) { 12068c2ecf20Sopenharmony_ci dev_err(dev, "unable to request tdes irq.\n"); 12078c2ecf20Sopenharmony_ci goto err_tasklet_kill; 12088c2ecf20Sopenharmony_ci } 12098c2ecf20Sopenharmony_ci 12108c2ecf20Sopenharmony_ci /* Initializing the clock */ 12118c2ecf20Sopenharmony_ci tdes_dd->iclk = devm_clk_get(&pdev->dev, "tdes_clk"); 12128c2ecf20Sopenharmony_ci if (IS_ERR(tdes_dd->iclk)) { 12138c2ecf20Sopenharmony_ci dev_err(dev, "clock initialization failed.\n"); 12148c2ecf20Sopenharmony_ci err = PTR_ERR(tdes_dd->iclk); 12158c2ecf20Sopenharmony_ci goto err_tasklet_kill; 12168c2ecf20Sopenharmony_ci } 12178c2ecf20Sopenharmony_ci 12188c2ecf20Sopenharmony_ci tdes_dd->io_base = devm_ioremap_resource(&pdev->dev, tdes_res); 12198c2ecf20Sopenharmony_ci if (IS_ERR(tdes_dd->io_base)) { 12208c2ecf20Sopenharmony_ci dev_err(dev, "can't ioremap\n"); 12218c2ecf20Sopenharmony_ci err = PTR_ERR(tdes_dd->io_base); 12228c2ecf20Sopenharmony_ci goto err_tasklet_kill; 12238c2ecf20Sopenharmony_ci } 12248c2ecf20Sopenharmony_ci 12258c2ecf20Sopenharmony_ci err = atmel_tdes_hw_version_init(tdes_dd); 12268c2ecf20Sopenharmony_ci if (err) 12278c2ecf20Sopenharmony_ci goto err_tasklet_kill; 12288c2ecf20Sopenharmony_ci 12298c2ecf20Sopenharmony_ci atmel_tdes_get_cap(tdes_dd); 12308c2ecf20Sopenharmony_ci 12318c2ecf20Sopenharmony_ci err = atmel_tdes_buff_init(tdes_dd); 12328c2ecf20Sopenharmony_ci if (err) 12338c2ecf20Sopenharmony_ci goto err_tasklet_kill; 12348c2ecf20Sopenharmony_ci 12358c2ecf20Sopenharmony_ci if (tdes_dd->caps.has_dma) { 12368c2ecf20Sopenharmony_ci err = atmel_tdes_dma_init(tdes_dd); 12378c2ecf20Sopenharmony_ci if (err) 12388c2ecf20Sopenharmony_ci goto err_buff_cleanup; 12398c2ecf20Sopenharmony_ci 12408c2ecf20Sopenharmony_ci dev_info(dev, "using %s, %s for DMA transfers\n", 12418c2ecf20Sopenharmony_ci dma_chan_name(tdes_dd->dma_lch_in.chan), 12428c2ecf20Sopenharmony_ci dma_chan_name(tdes_dd->dma_lch_out.chan)); 12438c2ecf20Sopenharmony_ci } 12448c2ecf20Sopenharmony_ci 12458c2ecf20Sopenharmony_ci spin_lock(&atmel_tdes.lock); 12468c2ecf20Sopenharmony_ci list_add_tail(&tdes_dd->list, &atmel_tdes.dev_list); 12478c2ecf20Sopenharmony_ci spin_unlock(&atmel_tdes.lock); 12488c2ecf20Sopenharmony_ci 12498c2ecf20Sopenharmony_ci err = atmel_tdes_register_algs(tdes_dd); 12508c2ecf20Sopenharmony_ci if (err) 12518c2ecf20Sopenharmony_ci goto err_algs; 12528c2ecf20Sopenharmony_ci 12538c2ecf20Sopenharmony_ci dev_info(dev, "Atmel DES/TDES\n"); 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_ci return 0; 12568c2ecf20Sopenharmony_ci 12578c2ecf20Sopenharmony_cierr_algs: 12588c2ecf20Sopenharmony_ci spin_lock(&atmel_tdes.lock); 12598c2ecf20Sopenharmony_ci list_del(&tdes_dd->list); 12608c2ecf20Sopenharmony_ci spin_unlock(&atmel_tdes.lock); 12618c2ecf20Sopenharmony_ci if (tdes_dd->caps.has_dma) 12628c2ecf20Sopenharmony_ci atmel_tdes_dma_cleanup(tdes_dd); 12638c2ecf20Sopenharmony_cierr_buff_cleanup: 12648c2ecf20Sopenharmony_ci atmel_tdes_buff_cleanup(tdes_dd); 12658c2ecf20Sopenharmony_cierr_tasklet_kill: 12668c2ecf20Sopenharmony_ci tasklet_kill(&tdes_dd->done_task); 12678c2ecf20Sopenharmony_ci tasklet_kill(&tdes_dd->queue_task); 12688c2ecf20Sopenharmony_ci 12698c2ecf20Sopenharmony_ci return err; 12708c2ecf20Sopenharmony_ci} 12718c2ecf20Sopenharmony_ci 12728c2ecf20Sopenharmony_cistatic int atmel_tdes_remove(struct platform_device *pdev) 12738c2ecf20Sopenharmony_ci{ 12748c2ecf20Sopenharmony_ci struct atmel_tdes_dev *tdes_dd; 12758c2ecf20Sopenharmony_ci 12768c2ecf20Sopenharmony_ci tdes_dd = platform_get_drvdata(pdev); 12778c2ecf20Sopenharmony_ci if (!tdes_dd) 12788c2ecf20Sopenharmony_ci return -ENODEV; 12798c2ecf20Sopenharmony_ci spin_lock(&atmel_tdes.lock); 12808c2ecf20Sopenharmony_ci list_del(&tdes_dd->list); 12818c2ecf20Sopenharmony_ci spin_unlock(&atmel_tdes.lock); 12828c2ecf20Sopenharmony_ci 12838c2ecf20Sopenharmony_ci atmel_tdes_unregister_algs(tdes_dd); 12848c2ecf20Sopenharmony_ci 12858c2ecf20Sopenharmony_ci tasklet_kill(&tdes_dd->done_task); 12868c2ecf20Sopenharmony_ci tasklet_kill(&tdes_dd->queue_task); 12878c2ecf20Sopenharmony_ci 12888c2ecf20Sopenharmony_ci if (tdes_dd->caps.has_dma) 12898c2ecf20Sopenharmony_ci atmel_tdes_dma_cleanup(tdes_dd); 12908c2ecf20Sopenharmony_ci 12918c2ecf20Sopenharmony_ci atmel_tdes_buff_cleanup(tdes_dd); 12928c2ecf20Sopenharmony_ci 12938c2ecf20Sopenharmony_ci return 0; 12948c2ecf20Sopenharmony_ci} 12958c2ecf20Sopenharmony_ci 12968c2ecf20Sopenharmony_cistatic struct platform_driver atmel_tdes_driver = { 12978c2ecf20Sopenharmony_ci .probe = atmel_tdes_probe, 12988c2ecf20Sopenharmony_ci .remove = atmel_tdes_remove, 12998c2ecf20Sopenharmony_ci .driver = { 13008c2ecf20Sopenharmony_ci .name = "atmel_tdes", 13018c2ecf20Sopenharmony_ci .of_match_table = of_match_ptr(atmel_tdes_dt_ids), 13028c2ecf20Sopenharmony_ci }, 13038c2ecf20Sopenharmony_ci}; 13048c2ecf20Sopenharmony_ci 13058c2ecf20Sopenharmony_cimodule_platform_driver(atmel_tdes_driver); 13068c2ecf20Sopenharmony_ci 13078c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Atmel DES/TDES hw acceleration support."); 13088c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 13098c2ecf20Sopenharmony_ciMODULE_AUTHOR("Nicolas Royer - Eukréa Electromatique"); 1310