| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154 |
- // SPDX-License-Identifier: GPL-2.0
- /*
- * StarFive AES acceleration driver
- *
- * Copyright (c) 2022 StarFive Technology
- */
- #include <crypto/engine.h>
- #include <crypto/gcm.h>
- #include <crypto/internal/aead.h>
- #include <crypto/internal/skcipher.h>
- #include <crypto/scatterwalk.h>
- #include "jh7110-cryp.h"
- #include <linux/err.h>
- #include <linux/iopoll.h>
- #include <linux/kernel.h>
- #include <linux/slab.h>
- #include <linux/string.h>
- #define STARFIVE_AES_REGS_OFFSET 0x100
- #define STARFIVE_AES_AESDIO0R (STARFIVE_AES_REGS_OFFSET + 0x0)
- #define STARFIVE_AES_KEY0 (STARFIVE_AES_REGS_OFFSET + 0x4)
- #define STARFIVE_AES_KEY1 (STARFIVE_AES_REGS_OFFSET + 0x8)
- #define STARFIVE_AES_KEY2 (STARFIVE_AES_REGS_OFFSET + 0xC)
- #define STARFIVE_AES_KEY3 (STARFIVE_AES_REGS_OFFSET + 0x10)
- #define STARFIVE_AES_KEY4 (STARFIVE_AES_REGS_OFFSET + 0x14)
- #define STARFIVE_AES_KEY5 (STARFIVE_AES_REGS_OFFSET + 0x18)
- #define STARFIVE_AES_KEY6 (STARFIVE_AES_REGS_OFFSET + 0x1C)
- #define STARFIVE_AES_KEY7 (STARFIVE_AES_REGS_OFFSET + 0x20)
- #define STARFIVE_AES_CSR (STARFIVE_AES_REGS_OFFSET + 0x24)
- #define STARFIVE_AES_IV0 (STARFIVE_AES_REGS_OFFSET + 0x28)
- #define STARFIVE_AES_IV1 (STARFIVE_AES_REGS_OFFSET + 0x2C)
- #define STARFIVE_AES_IV2 (STARFIVE_AES_REGS_OFFSET + 0x30)
- #define STARFIVE_AES_IV3 (STARFIVE_AES_REGS_OFFSET + 0x34)
- #define STARFIVE_AES_NONCE0 (STARFIVE_AES_REGS_OFFSET + 0x3C)
- #define STARFIVE_AES_NONCE1 (STARFIVE_AES_REGS_OFFSET + 0x40)
- #define STARFIVE_AES_NONCE2 (STARFIVE_AES_REGS_OFFSET + 0x44)
- #define STARFIVE_AES_NONCE3 (STARFIVE_AES_REGS_OFFSET + 0x48)
- #define STARFIVE_AES_ALEN0 (STARFIVE_AES_REGS_OFFSET + 0x4C)
- #define STARFIVE_AES_ALEN1 (STARFIVE_AES_REGS_OFFSET + 0x50)
- #define STARFIVE_AES_MLEN0 (STARFIVE_AES_REGS_OFFSET + 0x54)
- #define STARFIVE_AES_MLEN1 (STARFIVE_AES_REGS_OFFSET + 0x58)
- #define STARFIVE_AES_IVLEN (STARFIVE_AES_REGS_OFFSET + 0x5C)
- #define FLG_MODE_MASK GENMASK(2, 0)
- #define FLG_ENCRYPT BIT(4)
- /* Misc */
- #define CCM_B0_ADATA 0x40
- #define AES_BLOCK_32 (AES_BLOCK_SIZE / sizeof(u32))
- static inline int starfive_aes_wait_busy(struct starfive_cryp_dev *cryp)
- {
- u32 status;
- return readl_relaxed_poll_timeout(cryp->base + STARFIVE_AES_CSR, status,
- !(status & STARFIVE_AES_BUSY), 10, 100000);
- }
- static inline int starfive_aes_wait_keydone(struct starfive_cryp_dev *cryp)
- {
- u32 status;
- return readl_relaxed_poll_timeout(cryp->base + STARFIVE_AES_CSR, status,
- (status & STARFIVE_AES_KEY_DONE), 10, 100000);
- }
- static inline int starfive_aes_wait_gcmdone(struct starfive_cryp_dev *cryp)
- {
- u32 status;
- return readl_relaxed_poll_timeout(cryp->base + STARFIVE_AES_CSR, status,
- (status & STARFIVE_AES_GCM_DONE), 10, 100000);
- }
- static inline int is_gcm(struct starfive_cryp_dev *cryp)
- {
- return (cryp->flags & FLG_MODE_MASK) == STARFIVE_AES_MODE_GCM;
- }
- static inline bool is_encrypt(struct starfive_cryp_dev *cryp)
- {
- return cryp->flags & FLG_ENCRYPT;
- }
- static void starfive_aes_aead_hw_start(struct starfive_cryp_ctx *ctx, u32 hw_mode)
- {
- struct starfive_cryp_dev *cryp = ctx->cryp;
- unsigned int value;
- switch (hw_mode) {
- case STARFIVE_AES_MODE_GCM:
- value = readl(ctx->cryp->base + STARFIVE_AES_CSR);
- value |= STARFIVE_AES_GCM_START;
- writel(value, cryp->base + STARFIVE_AES_CSR);
- starfive_aes_wait_gcmdone(cryp);
- break;
- case STARFIVE_AES_MODE_CCM:
- value = readl(ctx->cryp->base + STARFIVE_AES_CSR);
- value |= STARFIVE_AES_CCM_START;
- writel(value, cryp->base + STARFIVE_AES_CSR);
- break;
- }
- }
- static inline void starfive_aes_set_alen(struct starfive_cryp_ctx *ctx)
- {
- struct starfive_cryp_dev *cryp = ctx->cryp;
- writel(upper_32_bits(cryp->assoclen), cryp->base + STARFIVE_AES_ALEN0);
- writel(lower_32_bits(cryp->assoclen), cryp->base + STARFIVE_AES_ALEN1);
- }
- static inline void starfive_aes_set_mlen(struct starfive_cryp_ctx *ctx)
- {
- struct starfive_cryp_dev *cryp = ctx->cryp;
- writel(upper_32_bits(cryp->total_in), cryp->base + STARFIVE_AES_MLEN0);
- writel(lower_32_bits(cryp->total_in), cryp->base + STARFIVE_AES_MLEN1);
- }
- static inline int starfive_aes_ccm_check_iv(const u8 *iv)
- {
- /* 2 <= L <= 8, so 1 <= L' <= 7. */
- if (iv[0] < 1 || iv[0] > 7)
- return -EINVAL;
- return 0;
- }
- static int starfive_aes_write_iv(struct starfive_cryp_ctx *ctx, u32 *iv)
- {
- struct starfive_cryp_dev *cryp = ctx->cryp;
- writel(iv[0], cryp->base + STARFIVE_AES_IV0);
- writel(iv[1], cryp->base + STARFIVE_AES_IV1);
- writel(iv[2], cryp->base + STARFIVE_AES_IV2);
- if (is_gcm(cryp)) {
- if (starfive_aes_wait_gcmdone(cryp))
- return -ETIMEDOUT;
- return 0;
- }
- writel(iv[3], cryp->base + STARFIVE_AES_IV3);
- return 0;
- }
- static inline void starfive_aes_get_iv(struct starfive_cryp_dev *cryp, u32 *iv)
- {
- iv[0] = readl(cryp->base + STARFIVE_AES_IV0);
- iv[1] = readl(cryp->base + STARFIVE_AES_IV1);
- iv[2] = readl(cryp->base + STARFIVE_AES_IV2);
- iv[3] = readl(cryp->base + STARFIVE_AES_IV3);
- }
- static inline void starfive_aes_write_nonce(struct starfive_cryp_ctx *ctx, u32 *nonce)
- {
- struct starfive_cryp_dev *cryp = ctx->cryp;
- writel(nonce[0], cryp->base + STARFIVE_AES_NONCE0);
- writel(nonce[1], cryp->base + STARFIVE_AES_NONCE1);
- writel(nonce[2], cryp->base + STARFIVE_AES_NONCE2);
- writel(nonce[3], cryp->base + STARFIVE_AES_NONCE3);
- }
- static int starfive_aes_write_key(struct starfive_cryp_ctx *ctx)
- {
- struct starfive_cryp_dev *cryp = ctx->cryp;
- u32 *key = (u32 *)ctx->key;
- if (ctx->keylen >= AES_KEYSIZE_128) {
- writel(key[0], cryp->base + STARFIVE_AES_KEY0);
- writel(key[1], cryp->base + STARFIVE_AES_KEY1);
- writel(key[2], cryp->base + STARFIVE_AES_KEY2);
- writel(key[3], cryp->base + STARFIVE_AES_KEY3);
- }
- if (ctx->keylen >= AES_KEYSIZE_192) {
- writel(key[4], cryp->base + STARFIVE_AES_KEY4);
- writel(key[5], cryp->base + STARFIVE_AES_KEY5);
- }
- if (ctx->keylen >= AES_KEYSIZE_256) {
- writel(key[6], cryp->base + STARFIVE_AES_KEY6);
- writel(key[7], cryp->base + STARFIVE_AES_KEY7);
- }
- if (starfive_aes_wait_keydone(cryp))
- return -ETIMEDOUT;
- return 0;
- }
- static int starfive_aes_ccm_init(struct starfive_cryp_ctx *ctx)
- {
- struct starfive_cryp_dev *cryp = ctx->cryp;
- u8 iv[AES_BLOCK_SIZE], b0[AES_BLOCK_SIZE];
- unsigned int textlen;
- memcpy(iv, cryp->req.areq->iv, AES_BLOCK_SIZE);
- memset(iv + AES_BLOCK_SIZE - 1 - iv[0], 0, iv[0] + 1);
- /* Build B0 */
- memcpy(b0, iv, AES_BLOCK_SIZE);
- b0[0] |= (8 * ((cryp->authsize - 2) / 2));
- if (cryp->assoclen)
- b0[0] |= CCM_B0_ADATA;
- textlen = cryp->total_in;
- b0[AES_BLOCK_SIZE - 2] = textlen >> 8;
- b0[AES_BLOCK_SIZE - 1] = textlen & 0xFF;
- starfive_aes_write_nonce(ctx, (u32 *)b0);
- return 0;
- }
- static int starfive_aes_hw_init(struct starfive_cryp_ctx *ctx)
- {
- struct starfive_cryp_request_ctx *rctx = ctx->rctx;
- struct starfive_cryp_dev *cryp = ctx->cryp;
- u32 hw_mode;
- /* reset */
- rctx->csr.aes.v = 0;
- rctx->csr.aes.aesrst = 1;
- writel(rctx->csr.aes.v, cryp->base + STARFIVE_AES_CSR);
- /* csr setup */
- hw_mode = cryp->flags & FLG_MODE_MASK;
- rctx->csr.aes.v = 0;
- switch (ctx->keylen) {
- case AES_KEYSIZE_128:
- rctx->csr.aes.keymode = STARFIVE_AES_KEYMODE_128;
- break;
- case AES_KEYSIZE_192:
- rctx->csr.aes.keymode = STARFIVE_AES_KEYMODE_192;
- break;
- case AES_KEYSIZE_256:
- rctx->csr.aes.keymode = STARFIVE_AES_KEYMODE_256;
- break;
- }
- rctx->csr.aes.mode = hw_mode;
- rctx->csr.aes.cmode = !is_encrypt(cryp);
- rctx->csr.aes.stmode = STARFIVE_AES_MODE_XFB_1;
- if (cryp->side_chan) {
- rctx->csr.aes.delay_aes = 1;
- rctx->csr.aes.vaes_start = 1;
- }
- writel(rctx->csr.aes.v, cryp->base + STARFIVE_AES_CSR);
- cryp->err = starfive_aes_write_key(ctx);
- if (cryp->err)
- return cryp->err;
- switch (hw_mode) {
- case STARFIVE_AES_MODE_GCM:
- starfive_aes_set_alen(ctx);
- starfive_aes_set_mlen(ctx);
- writel(GCM_AES_IV_SIZE, cryp->base + STARFIVE_AES_IVLEN);
- starfive_aes_aead_hw_start(ctx, hw_mode);
- starfive_aes_write_iv(ctx, (void *)cryp->req.areq->iv);
- break;
- case STARFIVE_AES_MODE_CCM:
- starfive_aes_set_alen(ctx);
- starfive_aes_set_mlen(ctx);
- starfive_aes_ccm_init(ctx);
- starfive_aes_aead_hw_start(ctx, hw_mode);
- break;
- case STARFIVE_AES_MODE_CBC:
- case STARFIVE_AES_MODE_CTR:
- starfive_aes_write_iv(ctx, (void *)cryp->req.sreq->iv);
- break;
- default:
- break;
- }
- return cryp->err;
- }
- static int starfive_aes_read_authtag(struct starfive_cryp_ctx *ctx)
- {
- struct starfive_cryp_dev *cryp = ctx->cryp;
- struct starfive_cryp_request_ctx *rctx = ctx->rctx;
- int i;
- if (starfive_aes_wait_busy(cryp))
- return dev_err_probe(cryp->dev, -ETIMEDOUT,
- "Timeout waiting for tag generation.");
- if ((cryp->flags & FLG_MODE_MASK) == STARFIVE_AES_MODE_GCM) {
- cryp->tag_out[0] = readl(cryp->base + STARFIVE_AES_NONCE0);
- cryp->tag_out[1] = readl(cryp->base + STARFIVE_AES_NONCE1);
- cryp->tag_out[2] = readl(cryp->base + STARFIVE_AES_NONCE2);
- cryp->tag_out[3] = readl(cryp->base + STARFIVE_AES_NONCE3);
- } else {
- for (i = 0; i < AES_BLOCK_32; i++)
- cryp->tag_out[i] = readl(cryp->base + STARFIVE_AES_AESDIO0R);
- }
- if (is_encrypt(cryp)) {
- scatterwalk_map_and_copy(cryp->tag_out, rctx->out_sg,
- cryp->total_in, cryp->authsize, 1);
- } else {
- if (crypto_memneq(cryp->tag_in, cryp->tag_out, cryp->authsize))
- return -EBADMSG;
- }
- return 0;
- }
- static void starfive_aes_finish_req(struct starfive_cryp_ctx *ctx)
- {
- struct starfive_cryp_dev *cryp = ctx->cryp;
- int err = cryp->err;
- if (!err && cryp->authsize)
- err = starfive_aes_read_authtag(ctx);
- if (!err && ((cryp->flags & FLG_MODE_MASK) == STARFIVE_AES_MODE_CBC ||
- (cryp->flags & FLG_MODE_MASK) == STARFIVE_AES_MODE_CTR))
- starfive_aes_get_iv(cryp, (void *)cryp->req.sreq->iv);
- if (cryp->authsize)
- crypto_finalize_aead_request(cryp->engine, cryp->req.areq, err);
- else
- crypto_finalize_skcipher_request(cryp->engine, cryp->req.sreq,
- err);
- }
- static int starfive_aes_gcm_write_adata(struct starfive_cryp_ctx *ctx)
- {
- struct starfive_cryp_dev *cryp = ctx->cryp;
- struct starfive_cryp_request_ctx *rctx = ctx->rctx;
- u32 *buffer;
- int total_len, loop;
- total_len = ALIGN(cryp->assoclen, AES_BLOCK_SIZE) / sizeof(unsigned int);
- buffer = (u32 *)rctx->adata;
- for (loop = 0; loop < total_len; loop += 4) {
- writel(*buffer, cryp->base + STARFIVE_AES_NONCE0);
- buffer++;
- writel(*buffer, cryp->base + STARFIVE_AES_NONCE1);
- buffer++;
- writel(*buffer, cryp->base + STARFIVE_AES_NONCE2);
- buffer++;
- writel(*buffer, cryp->base + STARFIVE_AES_NONCE3);
- buffer++;
- }
- if (starfive_aes_wait_gcmdone(cryp))
- return dev_err_probe(cryp->dev, -ETIMEDOUT,
- "Timeout processing gcm aad block");
- return 0;
- }
- static int starfive_aes_ccm_write_adata(struct starfive_cryp_ctx *ctx)
- {
- struct starfive_cryp_dev *cryp = ctx->cryp;
- struct starfive_cryp_request_ctx *rctx = ctx->rctx;
- u32 *buffer;
- u8 *ci;
- int total_len, loop;
- total_len = cryp->assoclen;
- ci = rctx->adata;
- writeb(*ci, cryp->base + STARFIVE_AES_AESDIO0R);
- ci++;
- writeb(*ci, cryp->base + STARFIVE_AES_AESDIO0R);
- ci++;
- total_len -= 2;
- buffer = (u32 *)ci;
- for (loop = 0; loop < 3; loop++, buffer++)
- writel(*buffer, cryp->base + STARFIVE_AES_AESDIO0R);
- total_len -= 12;
- while (total_len > 0) {
- for (loop = 0; loop < AES_BLOCK_32; loop++, buffer++)
- writel(*buffer, cryp->base + STARFIVE_AES_AESDIO0R);
- total_len -= AES_BLOCK_SIZE;
- }
- if (starfive_aes_wait_busy(cryp))
- return dev_err_probe(cryp->dev, -ETIMEDOUT,
- "Timeout processing ccm aad block");
- return 0;
- }
- static void starfive_aes_dma_done(void *param)
- {
- struct starfive_cryp_dev *cryp = param;
- complete(&cryp->dma_done);
- }
- static void starfive_aes_dma_init(struct starfive_cryp_dev *cryp)
- {
- cryp->cfg_in.direction = DMA_MEM_TO_DEV;
- cryp->cfg_in.src_addr_width = DMA_SLAVE_BUSWIDTH_16_BYTES;
- cryp->cfg_in.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
- cryp->cfg_in.src_maxburst = cryp->dma_maxburst;
- cryp->cfg_in.dst_maxburst = cryp->dma_maxburst;
- cryp->cfg_in.dst_addr = cryp->phys_base + STARFIVE_ALG_FIFO_OFFSET;
- dmaengine_slave_config(cryp->tx, &cryp->cfg_in);
- cryp->cfg_out.direction = DMA_DEV_TO_MEM;
- cryp->cfg_out.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
- cryp->cfg_out.dst_addr_width = DMA_SLAVE_BUSWIDTH_16_BYTES;
- cryp->cfg_out.src_maxburst = 4;
- cryp->cfg_out.dst_maxburst = 4;
- cryp->cfg_out.src_addr = cryp->phys_base + STARFIVE_ALG_FIFO_OFFSET;
- dmaengine_slave_config(cryp->rx, &cryp->cfg_out);
- init_completion(&cryp->dma_done);
- }
- static int starfive_aes_dma_xfer(struct starfive_cryp_dev *cryp,
- struct scatterlist *src,
- struct scatterlist *dst,
- int len)
- {
- struct dma_async_tx_descriptor *in_desc, *out_desc;
- union starfive_alg_cr alg_cr;
- int ret = 0, in_save, out_save;
- alg_cr.v = 0;
- alg_cr.start = 1;
- alg_cr.aes_dma_en = 1;
- writel(alg_cr.v, cryp->base + STARFIVE_ALG_CR_OFFSET);
- in_save = sg_dma_len(src);
- out_save = sg_dma_len(dst);
- writel(ALIGN(len, AES_BLOCK_SIZE), cryp->base + STARFIVE_DMA_IN_LEN_OFFSET);
- writel(ALIGN(len, AES_BLOCK_SIZE), cryp->base + STARFIVE_DMA_OUT_LEN_OFFSET);
- sg_dma_len(src) = ALIGN(len, AES_BLOCK_SIZE);
- sg_dma_len(dst) = ALIGN(len, AES_BLOCK_SIZE);
- out_desc = dmaengine_prep_slave_sg(cryp->rx, dst, 1, DMA_DEV_TO_MEM,
- DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
- if (!out_desc) {
- ret = -EINVAL;
- goto dma_err;
- }
- out_desc->callback = starfive_aes_dma_done;
- out_desc->callback_param = cryp;
- reinit_completion(&cryp->dma_done);
- dmaengine_submit(out_desc);
- dma_async_issue_pending(cryp->rx);
- in_desc = dmaengine_prep_slave_sg(cryp->tx, src, 1, DMA_MEM_TO_DEV,
- DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
- if (!in_desc) {
- ret = -EINVAL;
- goto dma_err;
- }
- dmaengine_submit(in_desc);
- dma_async_issue_pending(cryp->tx);
- if (!wait_for_completion_timeout(&cryp->dma_done,
- msecs_to_jiffies(1000)))
- ret = -ETIMEDOUT;
- dma_err:
- sg_dma_len(src) = in_save;
- sg_dma_len(dst) = out_save;
- alg_cr.v = 0;
- alg_cr.clear = 1;
- writel(alg_cr.v, cryp->base + STARFIVE_ALG_CR_OFFSET);
- return ret;
- }
- static int starfive_aes_map_sg(struct starfive_cryp_dev *cryp,
- struct scatterlist *src,
- struct scatterlist *dst)
- {
- struct scatterlist *stsg, *dtsg;
- struct scatterlist _src[2], _dst[2];
- unsigned int remain = cryp->total_in;
- unsigned int len, src_nents, dst_nents;
- int ret;
- if (src == dst) {
- for (stsg = src, dtsg = dst; remain > 0;
- stsg = sg_next(stsg), dtsg = sg_next(dtsg)) {
- src_nents = dma_map_sg(cryp->dev, stsg, 1, DMA_BIDIRECTIONAL);
- if (src_nents == 0)
- return dev_err_probe(cryp->dev, -ENOMEM,
- "dma_map_sg error\n");
- dst_nents = src_nents;
- len = min(sg_dma_len(stsg), remain);
- ret = starfive_aes_dma_xfer(cryp, stsg, dtsg, len);
- dma_unmap_sg(cryp->dev, stsg, 1, DMA_BIDIRECTIONAL);
- if (ret)
- return ret;
- remain -= len;
- }
- } else {
- for (stsg = src, dtsg = dst;;) {
- src_nents = dma_map_sg(cryp->dev, stsg, 1, DMA_TO_DEVICE);
- if (src_nents == 0)
- return dev_err_probe(cryp->dev, -ENOMEM,
- "dma_map_sg src error\n");
- dst_nents = dma_map_sg(cryp->dev, dtsg, 1, DMA_FROM_DEVICE);
- if (dst_nents == 0)
- return dev_err_probe(cryp->dev, -ENOMEM,
- "dma_map_sg dst error\n");
- len = min(sg_dma_len(stsg), sg_dma_len(dtsg));
- len = min(len, remain);
- ret = starfive_aes_dma_xfer(cryp, stsg, dtsg, len);
- dma_unmap_sg(cryp->dev, stsg, 1, DMA_TO_DEVICE);
- dma_unmap_sg(cryp->dev, dtsg, 1, DMA_FROM_DEVICE);
- if (ret)
- return ret;
- remain -= len;
- if (remain == 0)
- break;
- if (sg_dma_len(stsg) - len) {
- stsg = scatterwalk_ffwd(_src, stsg, len);
- dtsg = sg_next(dtsg);
- } else if (sg_dma_len(dtsg) - len) {
- dtsg = scatterwalk_ffwd(_dst, dtsg, len);
- stsg = sg_next(stsg);
- } else {
- stsg = sg_next(stsg);
- dtsg = sg_next(dtsg);
- }
- }
- }
- return 0;
- }
- static int starfive_aes_do_one_req(struct crypto_engine *engine, void *areq)
- {
- struct skcipher_request *req =
- container_of(areq, struct skcipher_request, base);
- struct starfive_cryp_ctx *ctx =
- crypto_skcipher_ctx(crypto_skcipher_reqtfm(req));
- struct starfive_cryp_request_ctx *rctx = skcipher_request_ctx(req);
- struct starfive_cryp_dev *cryp = ctx->cryp;
- int ret;
- cryp->req.sreq = req;
- cryp->total_in = req->cryptlen;
- cryp->total_out = req->cryptlen;
- cryp->assoclen = 0;
- cryp->authsize = 0;
- rctx->in_sg = req->src;
- rctx->out_sg = req->dst;
- ctx->rctx = rctx;
- ret = starfive_aes_hw_init(ctx);
- if (ret)
- return ret;
- if (!cryp->total_in)
- goto finish_req;
- starfive_aes_dma_init(cryp);
- ret = starfive_aes_map_sg(cryp, rctx->in_sg, rctx->out_sg);
- if (ret)
- return ret;
- finish_req:
- starfive_aes_finish_req(ctx);
- return 0;
- }
- static int starfive_aes_init_tfm(struct crypto_skcipher *tfm,
- const char *alg_name)
- {
- struct starfive_cryp_ctx *ctx = crypto_skcipher_ctx(tfm);
- ctx->cryp = starfive_cryp_find_dev(ctx);
- if (!ctx->cryp)
- return -ENODEV;
- ctx->skcipher_fbk = crypto_alloc_skcipher(alg_name, 0,
- CRYPTO_ALG_NEED_FALLBACK);
- if (IS_ERR(ctx->skcipher_fbk))
- return dev_err_probe(ctx->cryp->dev, PTR_ERR(ctx->skcipher_fbk),
- "%s() failed to allocate fallback for %s\n",
- __func__, alg_name);
- crypto_skcipher_set_reqsize(tfm, sizeof(struct starfive_cryp_request_ctx) +
- crypto_skcipher_reqsize(ctx->skcipher_fbk));
- return 0;
- }
- static void starfive_aes_exit_tfm(struct crypto_skcipher *tfm)
- {
- struct starfive_cryp_ctx *ctx = crypto_skcipher_ctx(tfm);
- crypto_free_skcipher(ctx->skcipher_fbk);
- }
- static int starfive_aes_aead_do_one_req(struct crypto_engine *engine, void *areq)
- {
- struct aead_request *req =
- container_of(areq, struct aead_request, base);
- struct starfive_cryp_ctx *ctx =
- crypto_aead_ctx(crypto_aead_reqtfm(req));
- struct starfive_cryp_dev *cryp = ctx->cryp;
- struct starfive_cryp_request_ctx *rctx = aead_request_ctx(req);
- struct scatterlist _src[2], _dst[2];
- int ret;
- cryp->req.areq = req;
- cryp->assoclen = req->assoclen;
- cryp->authsize = crypto_aead_authsize(crypto_aead_reqtfm(req));
- rctx->in_sg = scatterwalk_ffwd(_src, req->src, cryp->assoclen);
- if (req->src == req->dst)
- rctx->out_sg = rctx->in_sg;
- else
- rctx->out_sg = scatterwalk_ffwd(_dst, req->dst, cryp->assoclen);
- if (is_encrypt(cryp)) {
- cryp->total_in = req->cryptlen;
- cryp->total_out = req->cryptlen;
- } else {
- cryp->total_in = req->cryptlen - cryp->authsize;
- cryp->total_out = cryp->total_in;
- scatterwalk_map_and_copy(cryp->tag_in, req->src,
- cryp->total_in + cryp->assoclen,
- cryp->authsize, 0);
- }
- if (cryp->assoclen) {
- rctx->adata = kzalloc(cryp->assoclen + AES_BLOCK_SIZE, GFP_KERNEL);
- if (!rctx->adata)
- return dev_err_probe(cryp->dev, -ENOMEM,
- "Failed to alloc memory for adata");
- if (sg_copy_to_buffer(req->src, sg_nents_for_len(req->src, cryp->assoclen),
- rctx->adata, cryp->assoclen) != cryp->assoclen)
- return -EINVAL;
- }
- if (cryp->total_in)
- sg_zero_buffer(rctx->in_sg, sg_nents(rctx->in_sg),
- sg_dma_len(rctx->in_sg) - cryp->total_in,
- cryp->total_in);
- ctx->rctx = rctx;
- ret = starfive_aes_hw_init(ctx);
- if (ret)
- return ret;
- if (!cryp->assoclen)
- goto write_text;
- if ((cryp->flags & FLG_MODE_MASK) == STARFIVE_AES_MODE_CCM)
- ret = starfive_aes_ccm_write_adata(ctx);
- else
- ret = starfive_aes_gcm_write_adata(ctx);
- kfree(rctx->adata);
- if (ret)
- return ret;
- write_text:
- if (!cryp->total_in)
- goto finish_req;
- starfive_aes_dma_init(cryp);
- ret = starfive_aes_map_sg(cryp, rctx->in_sg, rctx->out_sg);
- if (ret)
- return ret;
- finish_req:
- starfive_aes_finish_req(ctx);
- return 0;
- }
- static int starfive_aes_aead_init_tfm(struct crypto_aead *tfm,
- const char *alg_name)
- {
- struct starfive_cryp_ctx *ctx = crypto_aead_ctx(tfm);
- ctx->cryp = starfive_cryp_find_dev(ctx);
- if (!ctx->cryp)
- return -ENODEV;
- ctx->aead_fbk = crypto_alloc_aead(alg_name, 0,
- CRYPTO_ALG_NEED_FALLBACK);
- if (IS_ERR(ctx->aead_fbk))
- return dev_err_probe(ctx->cryp->dev, PTR_ERR(ctx->aead_fbk),
- "%s() failed to allocate fallback for %s\n",
- __func__, alg_name);
- crypto_aead_set_reqsize(tfm, sizeof(struct starfive_cryp_request_ctx) +
- crypto_aead_reqsize(ctx->aead_fbk));
- return 0;
- }
- static void starfive_aes_aead_exit_tfm(struct crypto_aead *tfm)
- {
- struct starfive_cryp_ctx *ctx = crypto_aead_ctx(tfm);
- crypto_free_aead(ctx->aead_fbk);
- }
- static bool starfive_aes_check_unaligned(struct starfive_cryp_dev *cryp,
- struct scatterlist *src,
- struct scatterlist *dst)
- {
- struct scatterlist *tsg;
- int i;
- for_each_sg(src, tsg, sg_nents(src), i)
- if (!IS_ALIGNED(tsg->offset, sizeof(u32)) ||
- (!IS_ALIGNED(tsg->length, AES_BLOCK_SIZE) &&
- !sg_is_last(tsg)))
- return true;
- if (src != dst)
- for_each_sg(dst, tsg, sg_nents(dst), i)
- if (!IS_ALIGNED(tsg->offset, sizeof(u32)) ||
- (!IS_ALIGNED(tsg->length, AES_BLOCK_SIZE) &&
- !sg_is_last(tsg)))
- return true;
- return false;
- }
- static int starfive_aes_do_fallback(struct skcipher_request *req, bool enc)
- {
- struct starfive_cryp_ctx *ctx =
- crypto_skcipher_ctx(crypto_skcipher_reqtfm(req));
- struct skcipher_request *subreq = skcipher_request_ctx(req);
- skcipher_request_set_tfm(subreq, ctx->skcipher_fbk);
- skcipher_request_set_callback(subreq, req->base.flags,
- req->base.complete,
- req->base.data);
- skcipher_request_set_crypt(subreq, req->src, req->dst,
- req->cryptlen, req->iv);
- return enc ? crypto_skcipher_encrypt(subreq) :
- crypto_skcipher_decrypt(subreq);
- }
- static int starfive_aes_crypt(struct skcipher_request *req, unsigned long flags)
- {
- struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
- struct starfive_cryp_ctx *ctx = crypto_skcipher_ctx(tfm);
- struct starfive_cryp_dev *cryp = ctx->cryp;
- unsigned int blocksize_align = crypto_skcipher_blocksize(tfm) - 1;
- cryp->flags = flags;
- if ((cryp->flags & FLG_MODE_MASK) == STARFIVE_AES_MODE_ECB ||
- (cryp->flags & FLG_MODE_MASK) == STARFIVE_AES_MODE_CBC)
- if (req->cryptlen & blocksize_align)
- return -EINVAL;
- if (starfive_aes_check_unaligned(cryp, req->src, req->dst))
- return starfive_aes_do_fallback(req, is_encrypt(cryp));
- return crypto_transfer_skcipher_request_to_engine(cryp->engine, req);
- }
- static int starfive_aes_aead_do_fallback(struct aead_request *req, bool enc)
- {
- struct starfive_cryp_ctx *ctx =
- crypto_aead_ctx(crypto_aead_reqtfm(req));
- struct aead_request *subreq = aead_request_ctx(req);
- aead_request_set_tfm(subreq, ctx->aead_fbk);
- aead_request_set_callback(subreq, req->base.flags,
- req->base.complete,
- req->base.data);
- aead_request_set_crypt(subreq, req->src, req->dst,
- req->cryptlen, req->iv);
- aead_request_set_ad(subreq, req->assoclen);
- return enc ? crypto_aead_encrypt(subreq) :
- crypto_aead_decrypt(subreq);
- }
- static int starfive_aes_aead_crypt(struct aead_request *req, unsigned long flags)
- {
- struct starfive_cryp_ctx *ctx = crypto_aead_ctx(crypto_aead_reqtfm(req));
- struct starfive_cryp_dev *cryp = ctx->cryp;
- struct scatterlist *src, *dst, _src[2], _dst[2];
- cryp->flags = flags;
- /* aes-ccm does not support tag verification for non-aligned text,
- * use fallback for ccm decryption instead.
- */
- if (((cryp->flags & FLG_MODE_MASK) == STARFIVE_AES_MODE_CCM) &&
- !is_encrypt(cryp))
- return starfive_aes_aead_do_fallback(req, 0);
- src = scatterwalk_ffwd(_src, req->src, req->assoclen);
- if (req->src == req->dst)
- dst = src;
- else
- dst = scatterwalk_ffwd(_dst, req->dst, req->assoclen);
- if (starfive_aes_check_unaligned(cryp, src, dst))
- return starfive_aes_aead_do_fallback(req, is_encrypt(cryp));
- return crypto_transfer_aead_request_to_engine(cryp->engine, req);
- }
- static int starfive_aes_setkey(struct crypto_skcipher *tfm, const u8 *key,
- unsigned int keylen)
- {
- struct starfive_cryp_ctx *ctx = crypto_skcipher_ctx(tfm);
- if (!key || !keylen)
- return -EINVAL;
- if (keylen != AES_KEYSIZE_128 &&
- keylen != AES_KEYSIZE_192 &&
- keylen != AES_KEYSIZE_256)
- return -EINVAL;
- memcpy(ctx->key, key, keylen);
- ctx->keylen = keylen;
- return crypto_skcipher_setkey(ctx->skcipher_fbk, key, keylen);
- }
- static int starfive_aes_aead_setkey(struct crypto_aead *tfm, const u8 *key,
- unsigned int keylen)
- {
- struct starfive_cryp_ctx *ctx = crypto_aead_ctx(tfm);
- if (!key || !keylen)
- return -EINVAL;
- if (keylen != AES_KEYSIZE_128 &&
- keylen != AES_KEYSIZE_192 &&
- keylen != AES_KEYSIZE_256)
- return -EINVAL;
- memcpy(ctx->key, key, keylen);
- ctx->keylen = keylen;
- return crypto_aead_setkey(ctx->aead_fbk, key, keylen);
- }
- static int starfive_aes_gcm_setauthsize(struct crypto_aead *tfm,
- unsigned int authsize)
- {
- struct starfive_cryp_ctx *ctx = crypto_aead_ctx(tfm);
- int ret;
- ret = crypto_gcm_check_authsize(authsize);
- if (ret)
- return ret;
- return crypto_aead_setauthsize(ctx->aead_fbk, authsize);
- }
- static int starfive_aes_ccm_setauthsize(struct crypto_aead *tfm,
- unsigned int authsize)
- {
- struct starfive_cryp_ctx *ctx = crypto_aead_ctx(tfm);
- switch (authsize) {
- case 4:
- case 6:
- case 8:
- case 10:
- case 12:
- case 14:
- case 16:
- break;
- default:
- return -EINVAL;
- }
- return crypto_aead_setauthsize(ctx->aead_fbk, authsize);
- }
- static int starfive_aes_ecb_encrypt(struct skcipher_request *req)
- {
- return starfive_aes_crypt(req, STARFIVE_AES_MODE_ECB | FLG_ENCRYPT);
- }
- static int starfive_aes_ecb_decrypt(struct skcipher_request *req)
- {
- return starfive_aes_crypt(req, STARFIVE_AES_MODE_ECB);
- }
- static int starfive_aes_cbc_encrypt(struct skcipher_request *req)
- {
- return starfive_aes_crypt(req, STARFIVE_AES_MODE_CBC | FLG_ENCRYPT);
- }
- static int starfive_aes_cbc_decrypt(struct skcipher_request *req)
- {
- return starfive_aes_crypt(req, STARFIVE_AES_MODE_CBC);
- }
- static int starfive_aes_ctr_encrypt(struct skcipher_request *req)
- {
- return starfive_aes_crypt(req, STARFIVE_AES_MODE_CTR | FLG_ENCRYPT);
- }
- static int starfive_aes_ctr_decrypt(struct skcipher_request *req)
- {
- return starfive_aes_crypt(req, STARFIVE_AES_MODE_CTR);
- }
- static int starfive_aes_gcm_encrypt(struct aead_request *req)
- {
- return starfive_aes_aead_crypt(req, STARFIVE_AES_MODE_GCM | FLG_ENCRYPT);
- }
- static int starfive_aes_gcm_decrypt(struct aead_request *req)
- {
- return starfive_aes_aead_crypt(req, STARFIVE_AES_MODE_GCM);
- }
- static int starfive_aes_ccm_encrypt(struct aead_request *req)
- {
- int ret;
- ret = starfive_aes_ccm_check_iv(req->iv);
- if (ret)
- return ret;
- return starfive_aes_aead_crypt(req, STARFIVE_AES_MODE_CCM | FLG_ENCRYPT);
- }
- static int starfive_aes_ccm_decrypt(struct aead_request *req)
- {
- int ret;
- ret = starfive_aes_ccm_check_iv(req->iv);
- if (ret)
- return ret;
- return starfive_aes_aead_crypt(req, STARFIVE_AES_MODE_CCM);
- }
- static int starfive_aes_ecb_init_tfm(struct crypto_skcipher *tfm)
- {
- return starfive_aes_init_tfm(tfm, "ecb(aes-generic)");
- }
- static int starfive_aes_cbc_init_tfm(struct crypto_skcipher *tfm)
- {
- return starfive_aes_init_tfm(tfm, "cbc(aes-generic)");
- }
- static int starfive_aes_ctr_init_tfm(struct crypto_skcipher *tfm)
- {
- return starfive_aes_init_tfm(tfm, "ctr(aes-generic)");
- }
- static int starfive_aes_ccm_init_tfm(struct crypto_aead *tfm)
- {
- return starfive_aes_aead_init_tfm(tfm, "ccm_base(ctr(aes-generic),cbcmac(aes-generic))");
- }
- static int starfive_aes_gcm_init_tfm(struct crypto_aead *tfm)
- {
- return starfive_aes_aead_init_tfm(tfm, "gcm_base(ctr(aes-generic),ghash-generic)");
- }
- static struct skcipher_engine_alg skcipher_algs[] = {
- {
- .base.init = starfive_aes_ecb_init_tfm,
- .base.exit = starfive_aes_exit_tfm,
- .base.setkey = starfive_aes_setkey,
- .base.encrypt = starfive_aes_ecb_encrypt,
- .base.decrypt = starfive_aes_ecb_decrypt,
- .base.min_keysize = AES_MIN_KEY_SIZE,
- .base.max_keysize = AES_MAX_KEY_SIZE,
- .base.base = {
- .cra_name = "ecb(aes)",
- .cra_driver_name = "starfive-ecb-aes",
- .cra_priority = 200,
- .cra_flags = CRYPTO_ALG_ASYNC |
- CRYPTO_ALG_NEED_FALLBACK,
- .cra_blocksize = AES_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct starfive_cryp_ctx),
- .cra_alignmask = 0xf,
- .cra_module = THIS_MODULE,
- },
- .op = {
- .do_one_request = starfive_aes_do_one_req,
- },
- }, {
- .base.init = starfive_aes_cbc_init_tfm,
- .base.exit = starfive_aes_exit_tfm,
- .base.setkey = starfive_aes_setkey,
- .base.encrypt = starfive_aes_cbc_encrypt,
- .base.decrypt = starfive_aes_cbc_decrypt,
- .base.min_keysize = AES_MIN_KEY_SIZE,
- .base.max_keysize = AES_MAX_KEY_SIZE,
- .base.ivsize = AES_BLOCK_SIZE,
- .base.base = {
- .cra_name = "cbc(aes)",
- .cra_driver_name = "starfive-cbc-aes",
- .cra_priority = 200,
- .cra_flags = CRYPTO_ALG_ASYNC |
- CRYPTO_ALG_NEED_FALLBACK,
- .cra_blocksize = AES_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct starfive_cryp_ctx),
- .cra_alignmask = 0xf,
- .cra_module = THIS_MODULE,
- },
- .op = {
- .do_one_request = starfive_aes_do_one_req,
- },
- }, {
- .base.init = starfive_aes_ctr_init_tfm,
- .base.exit = starfive_aes_exit_tfm,
- .base.setkey = starfive_aes_setkey,
- .base.encrypt = starfive_aes_ctr_encrypt,
- .base.decrypt = starfive_aes_ctr_decrypt,
- .base.min_keysize = AES_MIN_KEY_SIZE,
- .base.max_keysize = AES_MAX_KEY_SIZE,
- .base.ivsize = AES_BLOCK_SIZE,
- .base.base = {
- .cra_name = "ctr(aes)",
- .cra_driver_name = "starfive-ctr-aes",
- .cra_priority = 200,
- .cra_flags = CRYPTO_ALG_ASYNC |
- CRYPTO_ALG_NEED_FALLBACK,
- .cra_blocksize = 1,
- .cra_ctxsize = sizeof(struct starfive_cryp_ctx),
- .cra_alignmask = 0xf,
- .cra_module = THIS_MODULE,
- },
- .op = {
- .do_one_request = starfive_aes_do_one_req,
- },
- },
- };
- static struct aead_engine_alg aead_algs[] = {
- {
- .base.setkey = starfive_aes_aead_setkey,
- .base.setauthsize = starfive_aes_gcm_setauthsize,
- .base.encrypt = starfive_aes_gcm_encrypt,
- .base.decrypt = starfive_aes_gcm_decrypt,
- .base.init = starfive_aes_gcm_init_tfm,
- .base.exit = starfive_aes_aead_exit_tfm,
- .base.ivsize = GCM_AES_IV_SIZE,
- .base.maxauthsize = AES_BLOCK_SIZE,
- .base.base = {
- .cra_name = "gcm(aes)",
- .cra_driver_name = "starfive-gcm-aes",
- .cra_priority = 200,
- .cra_flags = CRYPTO_ALG_ASYNC |
- CRYPTO_ALG_NEED_FALLBACK,
- .cra_blocksize = 1,
- .cra_ctxsize = sizeof(struct starfive_cryp_ctx),
- .cra_alignmask = 0xf,
- .cra_module = THIS_MODULE,
- },
- .op = {
- .do_one_request = starfive_aes_aead_do_one_req,
- },
- }, {
- .base.setkey = starfive_aes_aead_setkey,
- .base.setauthsize = starfive_aes_ccm_setauthsize,
- .base.encrypt = starfive_aes_ccm_encrypt,
- .base.decrypt = starfive_aes_ccm_decrypt,
- .base.init = starfive_aes_ccm_init_tfm,
- .base.exit = starfive_aes_aead_exit_tfm,
- .base.ivsize = AES_BLOCK_SIZE,
- .base.maxauthsize = AES_BLOCK_SIZE,
- .base.base = {
- .cra_name = "ccm(aes)",
- .cra_driver_name = "starfive-ccm-aes",
- .cra_priority = 200,
- .cra_flags = CRYPTO_ALG_ASYNC |
- CRYPTO_ALG_NEED_FALLBACK,
- .cra_blocksize = 1,
- .cra_ctxsize = sizeof(struct starfive_cryp_ctx),
- .cra_alignmask = 0xf,
- .cra_module = THIS_MODULE,
- },
- .op = {
- .do_one_request = starfive_aes_aead_do_one_req,
- },
- },
- };
- int starfive_aes_register_algs(void)
- {
- int ret;
- ret = crypto_engine_register_skciphers(skcipher_algs, ARRAY_SIZE(skcipher_algs));
- if (ret)
- return ret;
- ret = crypto_engine_register_aeads(aead_algs, ARRAY_SIZE(aead_algs));
- if (ret)
- crypto_engine_unregister_skciphers(skcipher_algs, ARRAY_SIZE(skcipher_algs));
- return ret;
- }
- void starfive_aes_unregister_algs(void)
- {
- crypto_engine_unregister_aeads(aead_algs, ARRAY_SIZE(aead_algs));
- crypto_engine_unregister_skciphers(skcipher_algs, ARRAY_SIZE(skcipher_algs));
- }
|