162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * sun4i-ss-cipher.c - hardware cryptographic accelerator for Allwinner A20 SoC 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2013-2015 Corentin LABBE <clabbe.montjoie@gmail.com> 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * This file add support for AES cipher with 128,192,256 bits 862306a36Sopenharmony_ci * keysize in CBC and ECB mode. 962306a36Sopenharmony_ci * Add support also for DES and 3DES in CBC and ECB mode. 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * You could find the datasheet in Documentation/arch/arm/sunxi.rst 1262306a36Sopenharmony_ci */ 1362306a36Sopenharmony_ci#include "sun4i-ss.h" 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_cistatic int noinline_for_stack sun4i_ss_opti_poll(struct skcipher_request *areq) 1662306a36Sopenharmony_ci{ 1762306a36Sopenharmony_ci struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq); 1862306a36Sopenharmony_ci struct sun4i_tfm_ctx *op = crypto_skcipher_ctx(tfm); 1962306a36Sopenharmony_ci struct sun4i_ss_ctx *ss = op->ss; 2062306a36Sopenharmony_ci unsigned int ivsize = crypto_skcipher_ivsize(tfm); 2162306a36Sopenharmony_ci struct sun4i_cipher_req_ctx *ctx = skcipher_request_ctx(areq); 2262306a36Sopenharmony_ci u32 mode = ctx->mode; 2362306a36Sopenharmony_ci /* when activating SS, the default FIFO space is SS_RX_DEFAULT(32) */ 2462306a36Sopenharmony_ci u32 rx_cnt = SS_RX_DEFAULT; 2562306a36Sopenharmony_ci u32 tx_cnt = 0; 2662306a36Sopenharmony_ci u32 spaces; 2762306a36Sopenharmony_ci u32 v; 2862306a36Sopenharmony_ci int err = 0; 2962306a36Sopenharmony_ci unsigned int i; 3062306a36Sopenharmony_ci unsigned int ileft = areq->cryptlen; 3162306a36Sopenharmony_ci unsigned int oleft = areq->cryptlen; 3262306a36Sopenharmony_ci unsigned int todo; 3362306a36Sopenharmony_ci unsigned long pi = 0, po = 0; /* progress for in and out */ 3462306a36Sopenharmony_ci bool miter_err; 3562306a36Sopenharmony_ci struct sg_mapping_iter mi, mo; 3662306a36Sopenharmony_ci unsigned int oi, oo; /* offset for in and out */ 3762306a36Sopenharmony_ci unsigned long flags; 3862306a36Sopenharmony_ci struct skcipher_alg *alg = crypto_skcipher_alg(tfm); 3962306a36Sopenharmony_ci struct sun4i_ss_alg_template *algt; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci if (!areq->cryptlen) 4262306a36Sopenharmony_ci return 0; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci if (!areq->src || !areq->dst) { 4562306a36Sopenharmony_ci dev_err_ratelimited(ss->dev, "ERROR: Some SGs are NULL\n"); 4662306a36Sopenharmony_ci return -EINVAL; 4762306a36Sopenharmony_ci } 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci if (areq->iv && ivsize > 0 && mode & SS_DECRYPTION) { 5062306a36Sopenharmony_ci scatterwalk_map_and_copy(ctx->backup_iv, areq->src, 5162306a36Sopenharmony_ci areq->cryptlen - ivsize, ivsize, 0); 5262306a36Sopenharmony_ci } 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_CRYPTO_DEV_SUN4I_SS_DEBUG)) { 5562306a36Sopenharmony_ci algt = container_of(alg, struct sun4i_ss_alg_template, alg.crypto); 5662306a36Sopenharmony_ci algt->stat_opti++; 5762306a36Sopenharmony_ci algt->stat_bytes += areq->cryptlen; 5862306a36Sopenharmony_ci } 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci spin_lock_irqsave(&ss->slock, flags); 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci for (i = 0; i < op->keylen / 4; i++) 6362306a36Sopenharmony_ci writesl(ss->base + SS_KEY0 + i * 4, &op->key[i], 1); 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci if (areq->iv) { 6662306a36Sopenharmony_ci for (i = 0; i < 4 && i < ivsize / 4; i++) { 6762306a36Sopenharmony_ci v = *(u32 *)(areq->iv + i * 4); 6862306a36Sopenharmony_ci writesl(ss->base + SS_IV0 + i * 4, &v, 1); 6962306a36Sopenharmony_ci } 7062306a36Sopenharmony_ci } 7162306a36Sopenharmony_ci writel(mode, ss->base + SS_CTL); 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci ileft = areq->cryptlen / 4; 7562306a36Sopenharmony_ci oleft = areq->cryptlen / 4; 7662306a36Sopenharmony_ci oi = 0; 7762306a36Sopenharmony_ci oo = 0; 7862306a36Sopenharmony_ci do { 7962306a36Sopenharmony_ci if (ileft) { 8062306a36Sopenharmony_ci sg_miter_start(&mi, areq->src, sg_nents(areq->src), 8162306a36Sopenharmony_ci SG_MITER_FROM_SG | SG_MITER_ATOMIC); 8262306a36Sopenharmony_ci if (pi) 8362306a36Sopenharmony_ci sg_miter_skip(&mi, pi); 8462306a36Sopenharmony_ci miter_err = sg_miter_next(&mi); 8562306a36Sopenharmony_ci if (!miter_err || !mi.addr) { 8662306a36Sopenharmony_ci dev_err_ratelimited(ss->dev, "ERROR: sg_miter return null\n"); 8762306a36Sopenharmony_ci err = -EINVAL; 8862306a36Sopenharmony_ci goto release_ss; 8962306a36Sopenharmony_ci } 9062306a36Sopenharmony_ci todo = min(rx_cnt, ileft); 9162306a36Sopenharmony_ci todo = min_t(size_t, todo, (mi.length - oi) / 4); 9262306a36Sopenharmony_ci if (todo) { 9362306a36Sopenharmony_ci ileft -= todo; 9462306a36Sopenharmony_ci writesl(ss->base + SS_RXFIFO, mi.addr + oi, todo); 9562306a36Sopenharmony_ci oi += todo * 4; 9662306a36Sopenharmony_ci } 9762306a36Sopenharmony_ci if (oi == mi.length) { 9862306a36Sopenharmony_ci pi += mi.length; 9962306a36Sopenharmony_ci oi = 0; 10062306a36Sopenharmony_ci } 10162306a36Sopenharmony_ci sg_miter_stop(&mi); 10262306a36Sopenharmony_ci } 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci spaces = readl(ss->base + SS_FCSR); 10562306a36Sopenharmony_ci rx_cnt = SS_RXFIFO_SPACES(spaces); 10662306a36Sopenharmony_ci tx_cnt = SS_TXFIFO_SPACES(spaces); 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci sg_miter_start(&mo, areq->dst, sg_nents(areq->dst), 10962306a36Sopenharmony_ci SG_MITER_TO_SG | SG_MITER_ATOMIC); 11062306a36Sopenharmony_ci if (po) 11162306a36Sopenharmony_ci sg_miter_skip(&mo, po); 11262306a36Sopenharmony_ci miter_err = sg_miter_next(&mo); 11362306a36Sopenharmony_ci if (!miter_err || !mo.addr) { 11462306a36Sopenharmony_ci dev_err_ratelimited(ss->dev, "ERROR: sg_miter return null\n"); 11562306a36Sopenharmony_ci err = -EINVAL; 11662306a36Sopenharmony_ci goto release_ss; 11762306a36Sopenharmony_ci } 11862306a36Sopenharmony_ci todo = min(tx_cnt, oleft); 11962306a36Sopenharmony_ci todo = min_t(size_t, todo, (mo.length - oo) / 4); 12062306a36Sopenharmony_ci if (todo) { 12162306a36Sopenharmony_ci oleft -= todo; 12262306a36Sopenharmony_ci readsl(ss->base + SS_TXFIFO, mo.addr + oo, todo); 12362306a36Sopenharmony_ci oo += todo * 4; 12462306a36Sopenharmony_ci } 12562306a36Sopenharmony_ci if (oo == mo.length) { 12662306a36Sopenharmony_ci oo = 0; 12762306a36Sopenharmony_ci po += mo.length; 12862306a36Sopenharmony_ci } 12962306a36Sopenharmony_ci sg_miter_stop(&mo); 13062306a36Sopenharmony_ci } while (oleft); 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci if (areq->iv) { 13362306a36Sopenharmony_ci if (mode & SS_DECRYPTION) { 13462306a36Sopenharmony_ci memcpy(areq->iv, ctx->backup_iv, ivsize); 13562306a36Sopenharmony_ci memzero_explicit(ctx->backup_iv, ivsize); 13662306a36Sopenharmony_ci } else { 13762306a36Sopenharmony_ci scatterwalk_map_and_copy(areq->iv, areq->dst, areq->cryptlen - ivsize, 13862306a36Sopenharmony_ci ivsize, 0); 13962306a36Sopenharmony_ci } 14062306a36Sopenharmony_ci } 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_cirelease_ss: 14362306a36Sopenharmony_ci writel(0, ss->base + SS_CTL); 14462306a36Sopenharmony_ci spin_unlock_irqrestore(&ss->slock, flags); 14562306a36Sopenharmony_ci return err; 14662306a36Sopenharmony_ci} 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_cistatic int noinline_for_stack sun4i_ss_cipher_poll_fallback(struct skcipher_request *areq) 14962306a36Sopenharmony_ci{ 15062306a36Sopenharmony_ci struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq); 15162306a36Sopenharmony_ci struct sun4i_tfm_ctx *op = crypto_skcipher_ctx(tfm); 15262306a36Sopenharmony_ci struct sun4i_cipher_req_ctx *ctx = skcipher_request_ctx(areq); 15362306a36Sopenharmony_ci int err; 15462306a36Sopenharmony_ci struct skcipher_alg *alg = crypto_skcipher_alg(tfm); 15562306a36Sopenharmony_ci struct sun4i_ss_alg_template *algt; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_CRYPTO_DEV_SUN4I_SS_DEBUG)) { 15862306a36Sopenharmony_ci algt = container_of(alg, struct sun4i_ss_alg_template, alg.crypto); 15962306a36Sopenharmony_ci algt->stat_fb++; 16062306a36Sopenharmony_ci } 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci skcipher_request_set_tfm(&ctx->fallback_req, op->fallback_tfm); 16362306a36Sopenharmony_ci skcipher_request_set_callback(&ctx->fallback_req, areq->base.flags, 16462306a36Sopenharmony_ci areq->base.complete, areq->base.data); 16562306a36Sopenharmony_ci skcipher_request_set_crypt(&ctx->fallback_req, areq->src, areq->dst, 16662306a36Sopenharmony_ci areq->cryptlen, areq->iv); 16762306a36Sopenharmony_ci if (ctx->mode & SS_DECRYPTION) 16862306a36Sopenharmony_ci err = crypto_skcipher_decrypt(&ctx->fallback_req); 16962306a36Sopenharmony_ci else 17062306a36Sopenharmony_ci err = crypto_skcipher_encrypt(&ctx->fallback_req); 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci return err; 17362306a36Sopenharmony_ci} 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci/* Generic function that support SG with size not multiple of 4 */ 17662306a36Sopenharmony_cistatic int sun4i_ss_cipher_poll(struct skcipher_request *areq) 17762306a36Sopenharmony_ci{ 17862306a36Sopenharmony_ci struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq); 17962306a36Sopenharmony_ci struct sun4i_tfm_ctx *op = crypto_skcipher_ctx(tfm); 18062306a36Sopenharmony_ci struct sun4i_ss_ctx *ss = op->ss; 18162306a36Sopenharmony_ci int no_chunk = 1; 18262306a36Sopenharmony_ci struct scatterlist *in_sg = areq->src; 18362306a36Sopenharmony_ci struct scatterlist *out_sg = areq->dst; 18462306a36Sopenharmony_ci unsigned int ivsize = crypto_skcipher_ivsize(tfm); 18562306a36Sopenharmony_ci struct sun4i_cipher_req_ctx *ctx = skcipher_request_ctx(areq); 18662306a36Sopenharmony_ci struct skcipher_alg *alg = crypto_skcipher_alg(tfm); 18762306a36Sopenharmony_ci struct sun4i_ss_alg_template *algt; 18862306a36Sopenharmony_ci u32 mode = ctx->mode; 18962306a36Sopenharmony_ci /* when activating SS, the default FIFO space is SS_RX_DEFAULT(32) */ 19062306a36Sopenharmony_ci u32 rx_cnt = SS_RX_DEFAULT; 19162306a36Sopenharmony_ci u32 tx_cnt = 0; 19262306a36Sopenharmony_ci u32 v; 19362306a36Sopenharmony_ci u32 spaces; 19462306a36Sopenharmony_ci int err = 0; 19562306a36Sopenharmony_ci unsigned int i; 19662306a36Sopenharmony_ci unsigned int ileft = areq->cryptlen; 19762306a36Sopenharmony_ci unsigned int oleft = areq->cryptlen; 19862306a36Sopenharmony_ci unsigned int todo; 19962306a36Sopenharmony_ci struct sg_mapping_iter mi, mo; 20062306a36Sopenharmony_ci unsigned long pi = 0, po = 0; /* progress for in and out */ 20162306a36Sopenharmony_ci bool miter_err; 20262306a36Sopenharmony_ci unsigned int oi, oo; /* offset for in and out */ 20362306a36Sopenharmony_ci unsigned int ob = 0; /* offset in buf */ 20462306a36Sopenharmony_ci unsigned int obo = 0; /* offset in bufo*/ 20562306a36Sopenharmony_ci unsigned int obl = 0; /* length of data in bufo */ 20662306a36Sopenharmony_ci unsigned long flags; 20762306a36Sopenharmony_ci bool need_fallback = false; 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci if (!areq->cryptlen) 21062306a36Sopenharmony_ci return 0; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci if (!areq->src || !areq->dst) { 21362306a36Sopenharmony_ci dev_err_ratelimited(ss->dev, "ERROR: Some SGs are NULL\n"); 21462306a36Sopenharmony_ci return -EINVAL; 21562306a36Sopenharmony_ci } 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci algt = container_of(alg, struct sun4i_ss_alg_template, alg.crypto); 21862306a36Sopenharmony_ci if (areq->cryptlen % algt->alg.crypto.base.cra_blocksize) 21962306a36Sopenharmony_ci need_fallback = true; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci /* 22262306a36Sopenharmony_ci * if we have only SGs with size multiple of 4, 22362306a36Sopenharmony_ci * we can use the SS optimized function 22462306a36Sopenharmony_ci */ 22562306a36Sopenharmony_ci while (in_sg && no_chunk == 1) { 22662306a36Sopenharmony_ci if ((in_sg->length | in_sg->offset) & 3u) 22762306a36Sopenharmony_ci no_chunk = 0; 22862306a36Sopenharmony_ci in_sg = sg_next(in_sg); 22962306a36Sopenharmony_ci } 23062306a36Sopenharmony_ci while (out_sg && no_chunk == 1) { 23162306a36Sopenharmony_ci if ((out_sg->length | out_sg->offset) & 3u) 23262306a36Sopenharmony_ci no_chunk = 0; 23362306a36Sopenharmony_ci out_sg = sg_next(out_sg); 23462306a36Sopenharmony_ci } 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci if (no_chunk == 1 && !need_fallback) 23762306a36Sopenharmony_ci return sun4i_ss_opti_poll(areq); 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci if (need_fallback) 24062306a36Sopenharmony_ci return sun4i_ss_cipher_poll_fallback(areq); 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci if (areq->iv && ivsize > 0 && mode & SS_DECRYPTION) { 24362306a36Sopenharmony_ci scatterwalk_map_and_copy(ctx->backup_iv, areq->src, 24462306a36Sopenharmony_ci areq->cryptlen - ivsize, ivsize, 0); 24562306a36Sopenharmony_ci } 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_CRYPTO_DEV_SUN4I_SS_DEBUG)) { 24862306a36Sopenharmony_ci algt->stat_req++; 24962306a36Sopenharmony_ci algt->stat_bytes += areq->cryptlen; 25062306a36Sopenharmony_ci } 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci spin_lock_irqsave(&ss->slock, flags); 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci for (i = 0; i < op->keylen / 4; i++) 25562306a36Sopenharmony_ci writesl(ss->base + SS_KEY0 + i * 4, &op->key[i], 1); 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci if (areq->iv) { 25862306a36Sopenharmony_ci for (i = 0; i < 4 && i < ivsize / 4; i++) { 25962306a36Sopenharmony_ci v = *(u32 *)(areq->iv + i * 4); 26062306a36Sopenharmony_ci writesl(ss->base + SS_IV0 + i * 4, &v, 1); 26162306a36Sopenharmony_ci } 26262306a36Sopenharmony_ci } 26362306a36Sopenharmony_ci writel(mode, ss->base + SS_CTL); 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci ileft = areq->cryptlen; 26662306a36Sopenharmony_ci oleft = areq->cryptlen; 26762306a36Sopenharmony_ci oi = 0; 26862306a36Sopenharmony_ci oo = 0; 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci while (oleft) { 27162306a36Sopenharmony_ci if (ileft) { 27262306a36Sopenharmony_ci sg_miter_start(&mi, areq->src, sg_nents(areq->src), 27362306a36Sopenharmony_ci SG_MITER_FROM_SG | SG_MITER_ATOMIC); 27462306a36Sopenharmony_ci if (pi) 27562306a36Sopenharmony_ci sg_miter_skip(&mi, pi); 27662306a36Sopenharmony_ci miter_err = sg_miter_next(&mi); 27762306a36Sopenharmony_ci if (!miter_err || !mi.addr) { 27862306a36Sopenharmony_ci dev_err_ratelimited(ss->dev, "ERROR: sg_miter return null\n"); 27962306a36Sopenharmony_ci err = -EINVAL; 28062306a36Sopenharmony_ci goto release_ss; 28162306a36Sopenharmony_ci } 28262306a36Sopenharmony_ci /* 28362306a36Sopenharmony_ci * todo is the number of consecutive 4byte word that we 28462306a36Sopenharmony_ci * can read from current SG 28562306a36Sopenharmony_ci */ 28662306a36Sopenharmony_ci todo = min(rx_cnt, ileft / 4); 28762306a36Sopenharmony_ci todo = min_t(size_t, todo, (mi.length - oi) / 4); 28862306a36Sopenharmony_ci if (todo && !ob) { 28962306a36Sopenharmony_ci writesl(ss->base + SS_RXFIFO, mi.addr + oi, 29062306a36Sopenharmony_ci todo); 29162306a36Sopenharmony_ci ileft -= todo * 4; 29262306a36Sopenharmony_ci oi += todo * 4; 29362306a36Sopenharmony_ci } else { 29462306a36Sopenharmony_ci /* 29562306a36Sopenharmony_ci * not enough consecutive bytes, so we need to 29662306a36Sopenharmony_ci * linearize in buf. todo is in bytes 29762306a36Sopenharmony_ci * After that copy, if we have a multiple of 4 29862306a36Sopenharmony_ci * we need to be able to write all buf in one 29962306a36Sopenharmony_ci * pass, so it is why we min() with rx_cnt 30062306a36Sopenharmony_ci */ 30162306a36Sopenharmony_ci todo = min(rx_cnt * 4 - ob, ileft); 30262306a36Sopenharmony_ci todo = min_t(size_t, todo, mi.length - oi); 30362306a36Sopenharmony_ci memcpy(ss->buf + ob, mi.addr + oi, todo); 30462306a36Sopenharmony_ci ileft -= todo; 30562306a36Sopenharmony_ci oi += todo; 30662306a36Sopenharmony_ci ob += todo; 30762306a36Sopenharmony_ci if (!(ob % 4)) { 30862306a36Sopenharmony_ci writesl(ss->base + SS_RXFIFO, ss->buf, 30962306a36Sopenharmony_ci ob / 4); 31062306a36Sopenharmony_ci ob = 0; 31162306a36Sopenharmony_ci } 31262306a36Sopenharmony_ci } 31362306a36Sopenharmony_ci if (oi == mi.length) { 31462306a36Sopenharmony_ci pi += mi.length; 31562306a36Sopenharmony_ci oi = 0; 31662306a36Sopenharmony_ci } 31762306a36Sopenharmony_ci sg_miter_stop(&mi); 31862306a36Sopenharmony_ci } 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci spaces = readl(ss->base + SS_FCSR); 32162306a36Sopenharmony_ci rx_cnt = SS_RXFIFO_SPACES(spaces); 32262306a36Sopenharmony_ci tx_cnt = SS_TXFIFO_SPACES(spaces); 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci if (!tx_cnt) 32562306a36Sopenharmony_ci continue; 32662306a36Sopenharmony_ci sg_miter_start(&mo, areq->dst, sg_nents(areq->dst), 32762306a36Sopenharmony_ci SG_MITER_TO_SG | SG_MITER_ATOMIC); 32862306a36Sopenharmony_ci if (po) 32962306a36Sopenharmony_ci sg_miter_skip(&mo, po); 33062306a36Sopenharmony_ci miter_err = sg_miter_next(&mo); 33162306a36Sopenharmony_ci if (!miter_err || !mo.addr) { 33262306a36Sopenharmony_ci dev_err_ratelimited(ss->dev, "ERROR: sg_miter return null\n"); 33362306a36Sopenharmony_ci err = -EINVAL; 33462306a36Sopenharmony_ci goto release_ss; 33562306a36Sopenharmony_ci } 33662306a36Sopenharmony_ci /* todo in 4bytes word */ 33762306a36Sopenharmony_ci todo = min(tx_cnt, oleft / 4); 33862306a36Sopenharmony_ci todo = min_t(size_t, todo, (mo.length - oo) / 4); 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci if (todo) { 34162306a36Sopenharmony_ci readsl(ss->base + SS_TXFIFO, mo.addr + oo, todo); 34262306a36Sopenharmony_ci oleft -= todo * 4; 34362306a36Sopenharmony_ci oo += todo * 4; 34462306a36Sopenharmony_ci if (oo == mo.length) { 34562306a36Sopenharmony_ci po += mo.length; 34662306a36Sopenharmony_ci oo = 0; 34762306a36Sopenharmony_ci } 34862306a36Sopenharmony_ci } else { 34962306a36Sopenharmony_ci /* 35062306a36Sopenharmony_ci * read obl bytes in bufo, we read at maximum for 35162306a36Sopenharmony_ci * emptying the device 35262306a36Sopenharmony_ci */ 35362306a36Sopenharmony_ci readsl(ss->base + SS_TXFIFO, ss->bufo, tx_cnt); 35462306a36Sopenharmony_ci obl = tx_cnt * 4; 35562306a36Sopenharmony_ci obo = 0; 35662306a36Sopenharmony_ci do { 35762306a36Sopenharmony_ci /* 35862306a36Sopenharmony_ci * how many bytes we can copy ? 35962306a36Sopenharmony_ci * no more than remaining SG size 36062306a36Sopenharmony_ci * no more than remaining buffer 36162306a36Sopenharmony_ci * no need to test against oleft 36262306a36Sopenharmony_ci */ 36362306a36Sopenharmony_ci todo = min_t(size_t, 36462306a36Sopenharmony_ci mo.length - oo, obl - obo); 36562306a36Sopenharmony_ci memcpy(mo.addr + oo, ss->bufo + obo, todo); 36662306a36Sopenharmony_ci oleft -= todo; 36762306a36Sopenharmony_ci obo += todo; 36862306a36Sopenharmony_ci oo += todo; 36962306a36Sopenharmony_ci if (oo == mo.length) { 37062306a36Sopenharmony_ci po += mo.length; 37162306a36Sopenharmony_ci sg_miter_next(&mo); 37262306a36Sopenharmony_ci oo = 0; 37362306a36Sopenharmony_ci } 37462306a36Sopenharmony_ci } while (obo < obl); 37562306a36Sopenharmony_ci /* bufo must be fully used here */ 37662306a36Sopenharmony_ci } 37762306a36Sopenharmony_ci sg_miter_stop(&mo); 37862306a36Sopenharmony_ci } 37962306a36Sopenharmony_ci if (areq->iv) { 38062306a36Sopenharmony_ci if (mode & SS_DECRYPTION) { 38162306a36Sopenharmony_ci memcpy(areq->iv, ctx->backup_iv, ivsize); 38262306a36Sopenharmony_ci memzero_explicit(ctx->backup_iv, ivsize); 38362306a36Sopenharmony_ci } else { 38462306a36Sopenharmony_ci scatterwalk_map_and_copy(areq->iv, areq->dst, areq->cryptlen - ivsize, 38562306a36Sopenharmony_ci ivsize, 0); 38662306a36Sopenharmony_ci } 38762306a36Sopenharmony_ci } 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_cirelease_ss: 39062306a36Sopenharmony_ci writel(0, ss->base + SS_CTL); 39162306a36Sopenharmony_ci spin_unlock_irqrestore(&ss->slock, flags); 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci return err; 39462306a36Sopenharmony_ci} 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci/* CBC AES */ 39762306a36Sopenharmony_ciint sun4i_ss_cbc_aes_encrypt(struct skcipher_request *areq) 39862306a36Sopenharmony_ci{ 39962306a36Sopenharmony_ci struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq); 40062306a36Sopenharmony_ci struct sun4i_tfm_ctx *op = crypto_skcipher_ctx(tfm); 40162306a36Sopenharmony_ci struct sun4i_cipher_req_ctx *rctx = skcipher_request_ctx(areq); 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci rctx->mode = SS_OP_AES | SS_CBC | SS_ENABLED | SS_ENCRYPTION | 40462306a36Sopenharmony_ci op->keymode; 40562306a36Sopenharmony_ci return sun4i_ss_cipher_poll(areq); 40662306a36Sopenharmony_ci} 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ciint sun4i_ss_cbc_aes_decrypt(struct skcipher_request *areq) 40962306a36Sopenharmony_ci{ 41062306a36Sopenharmony_ci struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq); 41162306a36Sopenharmony_ci struct sun4i_tfm_ctx *op = crypto_skcipher_ctx(tfm); 41262306a36Sopenharmony_ci struct sun4i_cipher_req_ctx *rctx = skcipher_request_ctx(areq); 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci rctx->mode = SS_OP_AES | SS_CBC | SS_ENABLED | SS_DECRYPTION | 41562306a36Sopenharmony_ci op->keymode; 41662306a36Sopenharmony_ci return sun4i_ss_cipher_poll(areq); 41762306a36Sopenharmony_ci} 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci/* ECB AES */ 42062306a36Sopenharmony_ciint sun4i_ss_ecb_aes_encrypt(struct skcipher_request *areq) 42162306a36Sopenharmony_ci{ 42262306a36Sopenharmony_ci struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq); 42362306a36Sopenharmony_ci struct sun4i_tfm_ctx *op = crypto_skcipher_ctx(tfm); 42462306a36Sopenharmony_ci struct sun4i_cipher_req_ctx *rctx = skcipher_request_ctx(areq); 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci rctx->mode = SS_OP_AES | SS_ECB | SS_ENABLED | SS_ENCRYPTION | 42762306a36Sopenharmony_ci op->keymode; 42862306a36Sopenharmony_ci return sun4i_ss_cipher_poll(areq); 42962306a36Sopenharmony_ci} 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ciint sun4i_ss_ecb_aes_decrypt(struct skcipher_request *areq) 43262306a36Sopenharmony_ci{ 43362306a36Sopenharmony_ci struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq); 43462306a36Sopenharmony_ci struct sun4i_tfm_ctx *op = crypto_skcipher_ctx(tfm); 43562306a36Sopenharmony_ci struct sun4i_cipher_req_ctx *rctx = skcipher_request_ctx(areq); 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci rctx->mode = SS_OP_AES | SS_ECB | SS_ENABLED | SS_DECRYPTION | 43862306a36Sopenharmony_ci op->keymode; 43962306a36Sopenharmony_ci return sun4i_ss_cipher_poll(areq); 44062306a36Sopenharmony_ci} 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci/* CBC DES */ 44362306a36Sopenharmony_ciint sun4i_ss_cbc_des_encrypt(struct skcipher_request *areq) 44462306a36Sopenharmony_ci{ 44562306a36Sopenharmony_ci struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq); 44662306a36Sopenharmony_ci struct sun4i_tfm_ctx *op = crypto_skcipher_ctx(tfm); 44762306a36Sopenharmony_ci struct sun4i_cipher_req_ctx *rctx = skcipher_request_ctx(areq); 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci rctx->mode = SS_OP_DES | SS_CBC | SS_ENABLED | SS_ENCRYPTION | 45062306a36Sopenharmony_ci op->keymode; 45162306a36Sopenharmony_ci return sun4i_ss_cipher_poll(areq); 45262306a36Sopenharmony_ci} 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ciint sun4i_ss_cbc_des_decrypt(struct skcipher_request *areq) 45562306a36Sopenharmony_ci{ 45662306a36Sopenharmony_ci struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq); 45762306a36Sopenharmony_ci struct sun4i_tfm_ctx *op = crypto_skcipher_ctx(tfm); 45862306a36Sopenharmony_ci struct sun4i_cipher_req_ctx *rctx = skcipher_request_ctx(areq); 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci rctx->mode = SS_OP_DES | SS_CBC | SS_ENABLED | SS_DECRYPTION | 46162306a36Sopenharmony_ci op->keymode; 46262306a36Sopenharmony_ci return sun4i_ss_cipher_poll(areq); 46362306a36Sopenharmony_ci} 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci/* ECB DES */ 46662306a36Sopenharmony_ciint sun4i_ss_ecb_des_encrypt(struct skcipher_request *areq) 46762306a36Sopenharmony_ci{ 46862306a36Sopenharmony_ci struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq); 46962306a36Sopenharmony_ci struct sun4i_tfm_ctx *op = crypto_skcipher_ctx(tfm); 47062306a36Sopenharmony_ci struct sun4i_cipher_req_ctx *rctx = skcipher_request_ctx(areq); 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci rctx->mode = SS_OP_DES | SS_ECB | SS_ENABLED | SS_ENCRYPTION | 47362306a36Sopenharmony_ci op->keymode; 47462306a36Sopenharmony_ci return sun4i_ss_cipher_poll(areq); 47562306a36Sopenharmony_ci} 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ciint sun4i_ss_ecb_des_decrypt(struct skcipher_request *areq) 47862306a36Sopenharmony_ci{ 47962306a36Sopenharmony_ci struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq); 48062306a36Sopenharmony_ci struct sun4i_tfm_ctx *op = crypto_skcipher_ctx(tfm); 48162306a36Sopenharmony_ci struct sun4i_cipher_req_ctx *rctx = skcipher_request_ctx(areq); 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci rctx->mode = SS_OP_DES | SS_ECB | SS_ENABLED | SS_DECRYPTION | 48462306a36Sopenharmony_ci op->keymode; 48562306a36Sopenharmony_ci return sun4i_ss_cipher_poll(areq); 48662306a36Sopenharmony_ci} 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci/* CBC 3DES */ 48962306a36Sopenharmony_ciint sun4i_ss_cbc_des3_encrypt(struct skcipher_request *areq) 49062306a36Sopenharmony_ci{ 49162306a36Sopenharmony_ci struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq); 49262306a36Sopenharmony_ci struct sun4i_tfm_ctx *op = crypto_skcipher_ctx(tfm); 49362306a36Sopenharmony_ci struct sun4i_cipher_req_ctx *rctx = skcipher_request_ctx(areq); 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci rctx->mode = SS_OP_3DES | SS_CBC | SS_ENABLED | SS_ENCRYPTION | 49662306a36Sopenharmony_ci op->keymode; 49762306a36Sopenharmony_ci return sun4i_ss_cipher_poll(areq); 49862306a36Sopenharmony_ci} 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ciint sun4i_ss_cbc_des3_decrypt(struct skcipher_request *areq) 50162306a36Sopenharmony_ci{ 50262306a36Sopenharmony_ci struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq); 50362306a36Sopenharmony_ci struct sun4i_tfm_ctx *op = crypto_skcipher_ctx(tfm); 50462306a36Sopenharmony_ci struct sun4i_cipher_req_ctx *rctx = skcipher_request_ctx(areq); 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci rctx->mode = SS_OP_3DES | SS_CBC | SS_ENABLED | SS_DECRYPTION | 50762306a36Sopenharmony_ci op->keymode; 50862306a36Sopenharmony_ci return sun4i_ss_cipher_poll(areq); 50962306a36Sopenharmony_ci} 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci/* ECB 3DES */ 51262306a36Sopenharmony_ciint sun4i_ss_ecb_des3_encrypt(struct skcipher_request *areq) 51362306a36Sopenharmony_ci{ 51462306a36Sopenharmony_ci struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq); 51562306a36Sopenharmony_ci struct sun4i_tfm_ctx *op = crypto_skcipher_ctx(tfm); 51662306a36Sopenharmony_ci struct sun4i_cipher_req_ctx *rctx = skcipher_request_ctx(areq); 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci rctx->mode = SS_OP_3DES | SS_ECB | SS_ENABLED | SS_ENCRYPTION | 51962306a36Sopenharmony_ci op->keymode; 52062306a36Sopenharmony_ci return sun4i_ss_cipher_poll(areq); 52162306a36Sopenharmony_ci} 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ciint sun4i_ss_ecb_des3_decrypt(struct skcipher_request *areq) 52462306a36Sopenharmony_ci{ 52562306a36Sopenharmony_ci struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq); 52662306a36Sopenharmony_ci struct sun4i_tfm_ctx *op = crypto_skcipher_ctx(tfm); 52762306a36Sopenharmony_ci struct sun4i_cipher_req_ctx *rctx = skcipher_request_ctx(areq); 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci rctx->mode = SS_OP_3DES | SS_ECB | SS_ENABLED | SS_DECRYPTION | 53062306a36Sopenharmony_ci op->keymode; 53162306a36Sopenharmony_ci return sun4i_ss_cipher_poll(areq); 53262306a36Sopenharmony_ci} 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ciint sun4i_ss_cipher_init(struct crypto_tfm *tfm) 53562306a36Sopenharmony_ci{ 53662306a36Sopenharmony_ci struct sun4i_tfm_ctx *op = crypto_tfm_ctx(tfm); 53762306a36Sopenharmony_ci struct sun4i_ss_alg_template *algt; 53862306a36Sopenharmony_ci const char *name = crypto_tfm_alg_name(tfm); 53962306a36Sopenharmony_ci int err; 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci memset(op, 0, sizeof(struct sun4i_tfm_ctx)); 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci algt = container_of(tfm->__crt_alg, struct sun4i_ss_alg_template, 54462306a36Sopenharmony_ci alg.crypto.base); 54562306a36Sopenharmony_ci op->ss = algt->ss; 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci op->fallback_tfm = crypto_alloc_skcipher(name, 0, CRYPTO_ALG_NEED_FALLBACK); 54862306a36Sopenharmony_ci if (IS_ERR(op->fallback_tfm)) { 54962306a36Sopenharmony_ci dev_err(op->ss->dev, "ERROR: Cannot allocate fallback for %s %ld\n", 55062306a36Sopenharmony_ci name, PTR_ERR(op->fallback_tfm)); 55162306a36Sopenharmony_ci return PTR_ERR(op->fallback_tfm); 55262306a36Sopenharmony_ci } 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci crypto_skcipher_set_reqsize(__crypto_skcipher_cast(tfm), 55562306a36Sopenharmony_ci sizeof(struct sun4i_cipher_req_ctx) + 55662306a36Sopenharmony_ci crypto_skcipher_reqsize(op->fallback_tfm)); 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci err = pm_runtime_resume_and_get(op->ss->dev); 55962306a36Sopenharmony_ci if (err < 0) 56062306a36Sopenharmony_ci goto error_pm; 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci return 0; 56362306a36Sopenharmony_cierror_pm: 56462306a36Sopenharmony_ci crypto_free_skcipher(op->fallback_tfm); 56562306a36Sopenharmony_ci return err; 56662306a36Sopenharmony_ci} 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_civoid sun4i_ss_cipher_exit(struct crypto_tfm *tfm) 56962306a36Sopenharmony_ci{ 57062306a36Sopenharmony_ci struct sun4i_tfm_ctx *op = crypto_tfm_ctx(tfm); 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci crypto_free_skcipher(op->fallback_tfm); 57362306a36Sopenharmony_ci pm_runtime_put(op->ss->dev); 57462306a36Sopenharmony_ci} 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci/* check and set the AES key, prepare the mode to be used */ 57762306a36Sopenharmony_ciint sun4i_ss_aes_setkey(struct crypto_skcipher *tfm, const u8 *key, 57862306a36Sopenharmony_ci unsigned int keylen) 57962306a36Sopenharmony_ci{ 58062306a36Sopenharmony_ci struct sun4i_tfm_ctx *op = crypto_skcipher_ctx(tfm); 58162306a36Sopenharmony_ci struct sun4i_ss_ctx *ss = op->ss; 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci switch (keylen) { 58462306a36Sopenharmony_ci case 128 / 8: 58562306a36Sopenharmony_ci op->keymode = SS_AES_128BITS; 58662306a36Sopenharmony_ci break; 58762306a36Sopenharmony_ci case 192 / 8: 58862306a36Sopenharmony_ci op->keymode = SS_AES_192BITS; 58962306a36Sopenharmony_ci break; 59062306a36Sopenharmony_ci case 256 / 8: 59162306a36Sopenharmony_ci op->keymode = SS_AES_256BITS; 59262306a36Sopenharmony_ci break; 59362306a36Sopenharmony_ci default: 59462306a36Sopenharmony_ci dev_dbg(ss->dev, "ERROR: Invalid keylen %u\n", keylen); 59562306a36Sopenharmony_ci return -EINVAL; 59662306a36Sopenharmony_ci } 59762306a36Sopenharmony_ci op->keylen = keylen; 59862306a36Sopenharmony_ci memcpy(op->key, key, keylen); 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci crypto_skcipher_clear_flags(op->fallback_tfm, CRYPTO_TFM_REQ_MASK); 60162306a36Sopenharmony_ci crypto_skcipher_set_flags(op->fallback_tfm, tfm->base.crt_flags & CRYPTO_TFM_REQ_MASK); 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci return crypto_skcipher_setkey(op->fallback_tfm, key, keylen); 60462306a36Sopenharmony_ci} 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci/* check and set the DES key, prepare the mode to be used */ 60762306a36Sopenharmony_ciint sun4i_ss_des_setkey(struct crypto_skcipher *tfm, const u8 *key, 60862306a36Sopenharmony_ci unsigned int keylen) 60962306a36Sopenharmony_ci{ 61062306a36Sopenharmony_ci struct sun4i_tfm_ctx *op = crypto_skcipher_ctx(tfm); 61162306a36Sopenharmony_ci int err; 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci err = verify_skcipher_des_key(tfm, key); 61462306a36Sopenharmony_ci if (err) 61562306a36Sopenharmony_ci return err; 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci op->keylen = keylen; 61862306a36Sopenharmony_ci memcpy(op->key, key, keylen); 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci crypto_skcipher_clear_flags(op->fallback_tfm, CRYPTO_TFM_REQ_MASK); 62162306a36Sopenharmony_ci crypto_skcipher_set_flags(op->fallback_tfm, tfm->base.crt_flags & CRYPTO_TFM_REQ_MASK); 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci return crypto_skcipher_setkey(op->fallback_tfm, key, keylen); 62462306a36Sopenharmony_ci} 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci/* check and set the 3DES key, prepare the mode to be used */ 62762306a36Sopenharmony_ciint sun4i_ss_des3_setkey(struct crypto_skcipher *tfm, const u8 *key, 62862306a36Sopenharmony_ci unsigned int keylen) 62962306a36Sopenharmony_ci{ 63062306a36Sopenharmony_ci struct sun4i_tfm_ctx *op = crypto_skcipher_ctx(tfm); 63162306a36Sopenharmony_ci int err; 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci err = verify_skcipher_des3_key(tfm, key); 63462306a36Sopenharmony_ci if (err) 63562306a36Sopenharmony_ci return err; 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci op->keylen = keylen; 63862306a36Sopenharmony_ci memcpy(op->key, key, keylen); 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci crypto_skcipher_clear_flags(op->fallback_tfm, CRYPTO_TFM_REQ_MASK); 64162306a36Sopenharmony_ci crypto_skcipher_set_flags(op->fallback_tfm, tfm->base.crt_flags & CRYPTO_TFM_REQ_MASK); 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci return crypto_skcipher_setkey(op->fallback_tfm, key, keylen); 64462306a36Sopenharmony_ci} 645