Module Name: src Committed By: riastradh Date: Sat Jun 13 18:58:26 UTC 2020
Modified Files: src/sys/arch/arm/sunxi: sun8i_crypto.c Log Message: Draft opencrypto support for Allwinner Crypto Engine. XXX Can't handle nonzero crd_skip yet. To generate a diff of this commit: cvs rdiff -u -r1.16 -r1.17 src/sys/arch/arm/sunxi/sun8i_crypto.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/arch/arm/sunxi/sun8i_crypto.c diff -u src/sys/arch/arm/sunxi/sun8i_crypto.c:1.16 src/sys/arch/arm/sunxi/sun8i_crypto.c:1.17 --- src/sys/arch/arm/sunxi/sun8i_crypto.c:1.16 Sat Jun 13 18:57:54 2020 +++ src/sys/arch/arm/sunxi/sun8i_crypto.c Sat Jun 13 18:58:26 2020 @@ -1,4 +1,4 @@ -/* $NetBSD: sun8i_crypto.c,v 1.16 2020/06/13 18:57:54 riastradh Exp $ */ +/* $NetBSD: sun8i_crypto.c,v 1.17 2020/06/13 18:58:26 riastradh Exp $ */ /*- * Copyright (c) 2019 The NetBSD Foundation, Inc. @@ -43,7 +43,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(1, "$NetBSD: sun8i_crypto.c,v 1.16 2020/06/13 18:57:54 riastradh Exp $"); +__KERNEL_RCSID(1, "$NetBSD: sun8i_crypto.c,v 1.17 2020/06/13 18:58:26 riastradh Exp $"); #include <sys/types.h> #include <sys/param.h> @@ -51,16 +51,21 @@ __KERNEL_RCSID(1, "$NetBSD: sun8i_crypto #include <sys/bus.h> #include <sys/callout.h> #include <sys/conf.h> +#include <sys/cprng.h> #include <sys/device.h> #include <sys/kernel.h> #include <sys/kmem.h> +#include <sys/mbuf.h> #include <sys/mutex.h> #include <sys/rndsource.h> +#include <sys/sdt.h> #include <sys/sysctl.h> #include <sys/workqueue.h> #include <dev/fdt/fdtvar.h> +#include <opencrypto/cryptodev.h> + #include <arm/sunxi/sun8i_crypto.h> #define SUN8I_CRYPTO_TIMEOUT hz @@ -110,15 +115,22 @@ struct sun8i_crypto_softc { const struct sysctlnode *cy_root_node; const struct sysctlnode *cy_trng_node; } sc_sysctl; + struct sun8i_crypto_opencrypto { + uint32_t co_driverid; + } sc_opencrypto; }; struct sun8i_crypto_task { struct sun8i_crypto_buf ct_descbuf; struct sun8i_crypto_taskdesc *ct_desc; + struct sun8i_crypto_buf ct_ivbuf; + void *ct_iv; + struct sun8i_crypto_buf ct_ctrbuf; + void *ct_ctr; bus_dmamap_t ct_descmap; bus_dmamap_t ct_keymap; - bus_dmamap_t ct_ivmap; - bus_dmamap_t ct_ctrmap; + bus_dmamap_t ct_ivmap; /* IV input */ + bus_dmamap_t ct_ctrmap; /* updated IV output */ bus_dmamap_t ct_srcmap; bus_dmamap_t ct_dstmap; uint32_t ct_nbytes; @@ -159,8 +171,8 @@ static void sun8i_crypto_task_put(struct static int sun8i_crypto_task_load(struct sun8i_crypto_softc *, struct sun8i_crypto_task *, uint32_t, uint32_t, uint32_t, uint32_t); -static int sun8i_crypto_task_scatter(struct sun8i_crypto_adrlen *, - bus_dmamap_t, uint32_t); +static int sun8i_crypto_task_scatter(struct sun8i_crypto_task *, + struct sun8i_crypto_adrlen *, bus_dmamap_t, uint32_t); static int sun8i_crypto_task_load_trng(struct sun8i_crypto_softc *, struct sun8i_crypto_task *, uint32_t); @@ -196,19 +208,106 @@ static int sun8i_crypto_sysctl_rng(SYSCT static void sun8i_crypto_sysctl_rng_done(struct sun8i_crypto_softc *, struct sun8i_crypto_task *, void *, int); +static void sun8i_crypto_register(struct sun8i_crypto_softc *); +static void sun8i_crypto_register1(struct sun8i_crypto_softc *, uint32_t); +static int sun8i_crypto_newsession(void *, uint32_t *, + struct cryptoini *); +static int sun8i_crypto_freesession(void *, uint64_t); +static u_int sun8i_crypto_ivlen(const struct cryptodesc *); +static int sun8i_crypto_process(void *, struct cryptop *, int); +static void sun8i_crypto_callback(struct sun8i_crypto_softc *, + struct sun8i_crypto_task *, void *, int); + +/* + * Probes + */ + +SDT_PROBE_DEFINE2(sdt, sun8i_crypto, register, read, + "bus_size_t"/*reg*/, + "uint32_t"/*value*/); +SDT_PROBE_DEFINE2(sdt, sun8i_crypto, register, write, + "bus_size_t"/*reg*/, + "uint32_t"/*write*/); + +SDT_PROBE_DEFINE1(sdt, sun8i_crypto, task, ctor__success, + "struct sun8i_crypto_task *"/*task*/); +SDT_PROBE_DEFINE1(sdt, sun8i_crypto, task, ctor__failure, + "int"/*error*/); +SDT_PROBE_DEFINE1(sdt, sun8i_crypto, task, dtor, + "struct sun8i_crypto_task *"/*task*/); +SDT_PROBE_DEFINE1(sdt, sun8i_crypto, task, get, + "struct sun8i_crypto_task *"/*task*/); +SDT_PROBE_DEFINE1(sdt, sun8i_crypto, task, put, + "struct sun8i_crypto_task *"/*task*/); + +SDT_PROBE_DEFINE6(sdt, sun8i_crypto, task, load, + "struct sun8i_crypto_task *"/*task*/, + "uint32_t"/*tdqc*/, + "uint32_t"/*tdqs*/, + "uint32_t"/*tdqa*/, + "struct sun8i_crypto_taskdesc *"/*desc*/, + "int"/*error*/); +SDT_PROBE_DEFINE3(sdt, sun8i_crypto, task, misaligned, + "struct sun8i_crypto_task *"/*task*/, + "bus_addr_t"/*ds_addr*/, + "bus_size_t"/*ds_len*/); +SDT_PROBE_DEFINE2(sdt, sun8i_crypto, task, done, + "struct sun8i_crypto_task *"/*task*/, + "int"/*error*/); + +SDT_PROBE_DEFINE3(sdt, sun8i_crypto, engine, submit__failure, + "struct sun8i_crypto_softc *"/*sc*/, + "struct sun8i_crypto_task *"/*task*/, + "int"/*error*/); +SDT_PROBE_DEFINE3(sdt, sun8i_crypto, engine, submit__success, + "struct sun8i_crypto_softc *"/*sc*/, + "struct sun8i_crypto_task *"/*task*/, + "unsigned"/*chan*/); +SDT_PROBE_DEFINE3(sdt, sun8i_crypto, engine, intr, + "struct sun8i_crypto_softc *"/*sc*/, + "uint32_t"/*isr*/, + "uint32_t"/*esr*/); +SDT_PROBE_DEFINE3(sdt, sun8i_crypto, engine, done, + "struct sun8i_crypto_softc *"/*sc*/, + "unsigned"/*chan*/, + "int"/*error*/); + +SDT_PROBE_DEFINE3(sdt, sun8i_crypto, process, entry, + "struct sun8i_crypto_softc *"/*sc*/, + "struct cryptop *"/*crp*/, + "int"/*hint*/); +SDT_PROBE_DEFINE3(sdt, sun8i_crypto, process, busy, + "struct sun8i_crypto_softc *"/*sc*/, + "struct cryptop *"/*crp*/, + "int"/*hint*/); +SDT_PROBE_DEFINE4(sdt, sun8i_crypto, process, queued, + "struct sun8i_crypto_softc *"/*sc*/, + "struct cryptop *"/*crp*/, + "int"/*hint*/, + "struct sun8i_crypto_task *"/*task*/); +SDT_PROBE_DEFINE3(sdt, sun8i_crypto, process, done, + "struct sun8i_crypto_softc *"/*sc*/, + "struct cryptop *"/*crp*/, + "int"/*error*/); + /* * Register access */ static uint32_t -sun8i_crypto_read(struct sun8i_crypto_softc *sc, bus_addr_t reg) +sun8i_crypto_read(struct sun8i_crypto_softc *sc, bus_size_t reg) { - return bus_space_read_4(sc->sc_bst, sc->sc_bsh, reg); + uint32_t v = bus_space_read_4(sc->sc_bst, sc->sc_bsh, reg); + + SDT_PROBE2(sdt, sun8i_crypto, register, read, reg, v); + return v; } static void -sun8i_crypto_write(struct sun8i_crypto_softc *sc, bus_addr_t reg, uint32_t v) +sun8i_crypto_write(struct sun8i_crypto_softc *sc, bus_size_t reg, uint32_t v) { + + SDT_PROBE2(sdt, sun8i_crypto, register, write, reg, v); bus_space_write_4(sc->sc_bst, sc->sc_bsh, reg, v); } @@ -259,6 +358,13 @@ sun8i_crypto_attach(device_t parent, dev return; } + /* + * Prime the pool with enough tasks that each channel can be + * busy with a task as we prepare another task for when it's + * done. + */ + pool_cache_prime(sc->sc_taskpool, 2*SUN8I_CRYPTO_NCHAN); + /* Get and map device registers. */ if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) { aprint_error(": couldn't get registers\n"); @@ -327,6 +433,9 @@ sun8i_crypto_attach(device_t parent, dev /* Perform self-tests. */ config_interrupts(self, sun8i_crypto_selftest); + + /* Register opencrypto handlers. */ + sun8i_crypto_register(sc); } static int @@ -344,55 +453,71 @@ sun8i_crypto_task_ctor(void *cookie, voi goto fail0; task->ct_desc = task->ct_descbuf.cb_kva; + /* Create DMA buffers for the IV and CTR. */ + error = sun8i_crypto_allocbuf(sc, SUN8I_CRYPTO_MAXIVBYTES, + &task->ct_ivbuf, dmaflags); + if (error) + goto fail1; + task->ct_iv = task->ct_ivbuf.cb_kva; + error = sun8i_crypto_allocbuf(sc, SUN8I_CRYPTO_MAXCTRBYTES, + &task->ct_ctrbuf, dmaflags); + if (error) + goto fail2; + task->ct_ctr = task->ct_ctrbuf.cb_kva; + /* Create a DMA map for the task descriptor and preload it. */ error = bus_dmamap_create(sc->sc_dmat, sizeof(*task->ct_desc), 1, sizeof(*task->ct_desc), 0, dmaflags, &task->ct_descmap); if (error) - goto fail1; + goto fail3; error = bus_dmamap_load(sc->sc_dmat, task->ct_descmap, task->ct_desc, sizeof(*task->ct_desc), NULL, BUS_DMA_WAITOK); if (error) - goto fail2; + goto fail4; /* Create DMA maps for the key, IV, and CTR. */ error = bus_dmamap_create(sc->sc_dmat, SUN8I_CRYPTO_MAXKEYBYTES, 1, SUN8I_CRYPTO_MAXKEYBYTES, 0, dmaflags, &task->ct_keymap); if (error) - goto fail3; + goto fail5; error = bus_dmamap_create(sc->sc_dmat, SUN8I_CRYPTO_MAXIVBYTES, 1, SUN8I_CRYPTO_MAXIVBYTES, 0, dmaflags, &task->ct_ivmap); if (error) - goto fail4; + goto fail6; error = bus_dmamap_create(sc->sc_dmat, SUN8I_CRYPTO_MAXCTRBYTES, 1, SUN8I_CRYPTO_MAXCTRBYTES, 0, dmaflags, &task->ct_ctrmap); if (error) - goto fail5; + goto fail7; /* Create DMA maps for the src and dst scatter/gather vectors. */ error = bus_dmamap_create(sc->sc_dmat, SUN8I_CRYPTO_MAXDMASIZE, SUN8I_CRYPTO_MAXSEGS, SUN8I_CRYPTO_MAXDMASEGSIZE, 0, dmaflags, &task->ct_srcmap); if (error) - goto fail6; + goto fail8; error = bus_dmamap_create(sc->sc_dmat, SUN8I_CRYPTO_MAXDMASIZE, SUN8I_CRYPTO_MAXSEGS, SUN8I_CRYPTO_MAXDMASEGSIZE, 0, dmaflags, &task->ct_dstmap); if (error) - goto fail7; + goto fail9; /* Success! */ + SDT_PROBE1(sdt, sun8i_crypto, task, ctor__success, task); return 0; -fail8: __unused +fail10: __unused bus_dmamap_destroy(sc->sc_dmat, task->ct_dstmap); -fail7: bus_dmamap_destroy(sc->sc_dmat, task->ct_srcmap); -fail6: bus_dmamap_destroy(sc->sc_dmat, task->ct_ctrmap); -fail5: bus_dmamap_destroy(sc->sc_dmat, task->ct_ivmap); -fail4: bus_dmamap_destroy(sc->sc_dmat, task->ct_keymap); -fail3: bus_dmamap_unload(sc->sc_dmat, task->ct_descmap); -fail2: bus_dmamap_destroy(sc->sc_dmat, task->ct_descmap); +fail9: bus_dmamap_destroy(sc->sc_dmat, task->ct_srcmap); +fail8: bus_dmamap_destroy(sc->sc_dmat, task->ct_ctrmap); +fail7: bus_dmamap_destroy(sc->sc_dmat, task->ct_ivmap); +fail6: bus_dmamap_destroy(sc->sc_dmat, task->ct_keymap); +fail5: bus_dmamap_unload(sc->sc_dmat, task->ct_descmap); +fail4: bus_dmamap_destroy(sc->sc_dmat, task->ct_descmap); +fail3: sun8i_crypto_freebuf(sc, SUN8I_CRYPTO_MAXIVBYTES, &task->ct_ivbuf); +fail2: sun8i_crypto_freebuf(sc, SUN8I_CRYPTO_MAXCTRBYTES, &task->ct_ctrbuf); fail1: sun8i_crypto_freebuf(sc, sizeof(*task->ct_desc), &task->ct_descbuf); -fail0: return error; +fail0: SDT_PROBE1(sdt, sun8i_crypto, task, ctor__failure, error); + return error; } static void @@ -401,6 +526,8 @@ sun8i_crypto_task_dtor(void *cookie, voi struct sun8i_crypto_softc *sc = cookie; struct sun8i_crypto_task *task = vtask; + SDT_PROBE1(sdt, sun8i_crypto, task, dtor, task); + /* XXX Zero the bounce buffers if there are any. */ bus_dmamap_destroy(sc->sc_dmat, task->ct_dstmap); @@ -410,6 +537,8 @@ sun8i_crypto_task_dtor(void *cookie, voi bus_dmamap_destroy(sc->sc_dmat, task->ct_keymap); bus_dmamap_unload(sc->sc_dmat, task->ct_descmap); bus_dmamap_destroy(sc->sc_dmat, task->ct_descmap); + sun8i_crypto_freebuf(sc, SUN8I_CRYPTO_MAXIVBYTES, &task->ct_ivbuf); + sun8i_crypto_freebuf(sc, SUN8I_CRYPTO_MAXCTRBYTES, &task->ct_ctrbuf); sun8i_crypto_freebuf(sc, sizeof(*task->ct_desc), &task->ct_descbuf); } @@ -433,12 +562,14 @@ sun8i_crypto_task_get(struct sun8i_crypt /* Allocate a task, or fail if we can't. */ task = pool_cache_get(sc->sc_taskpool, pflags); if (task == NULL) - return NULL; + goto out; /* Set up flags and the callback. */ task->ct_flags = 0; task->ct_callback = callback; task->ct_cookie = cookie; + +out: SDT_PROBE1(sdt, sun8i_crypto, task, get, task); return task; } @@ -467,6 +598,8 @@ sun8i_crypto_task_put(struct sun8i_crypt struct sun8i_crypto_task *task) { + SDT_PROBE1(sdt, sun8i_crypto, task, put, task); + task->ct_cookie = task->ct_callback; task->ct_callback = &sun8i_crypto_task_invalid; pool_cache_put(sc->sc_taskpool, task); @@ -480,7 +613,6 @@ sun8i_crypto_task_put(struct sun8i_crypt * sun8i_crypto_chan_done. May fail if input is inadequately * aligned. * - * XXX Teach this to fail gracefully if any alignment is wrong. * XXX Teach this to support task chains. */ static int @@ -496,6 +628,9 @@ sun8i_crypto_task_load(struct sun8i_cryp memset(desc, 0, sizeof(*desc)); + /* Always enable interrupt for the task. */ + tdqc |= SUN8I_CRYPTO_TDQC_INTR_EN; + desc->td_tdqc = htole32(tdqc); desc->td_tdqs = htole32(tdqs); desc->td_tdqa = htole32(tdqa); @@ -519,7 +654,7 @@ sun8i_crypto_task_load(struct sun8i_cryp KASSERT(ctrmap->dm_nsegs == 1); desc->td_ctrdesc = htole32(ctrmap->dm_segs[0].ds_addr); bus_dmamap_sync(sc->sc_dmat, ctrmap, 0, - ctrmap->dm_segs[0].ds_len, BUS_DMASYNC_PREWRITE); + ctrmap->dm_segs[0].ds_len, BUS_DMASYNC_PREREAD); } if (task->ct_flags & TASK_BYTES) @@ -530,7 +665,7 @@ sun8i_crypto_task_load(struct sun8i_cryp if (task->ct_flags & TASK_SRC) { bus_dmamap_t srcmap = task->ct_srcmap; KASSERT(srcmap->dm_mapsize == task->ct_dstmap->dm_mapsize); - error = sun8i_crypto_task_scatter(desc->td_src, srcmap, + error = sun8i_crypto_task_scatter(task, desc->td_src, srcmap, nbytes); if (error) return error; @@ -538,36 +673,52 @@ sun8i_crypto_task_load(struct sun8i_cryp BUS_DMASYNC_PREWRITE); } - error = sun8i_crypto_task_scatter(desc->td_dst, task->ct_dstmap, + error = sun8i_crypto_task_scatter(task, desc->td_dst, task->ct_dstmap, nbytes); if (error) - return error; + goto out; bus_dmamap_sync(sc->sc_dmat, task->ct_dstmap, 0, nbytes, BUS_DMASYNC_PREREAD); task->ct_nbytes = nbytes; /* Success! */ - return 0; + error = 0; + +out: SDT_PROBE6(sdt, sun8i_crypto, task, load, + task, tdqc, tdqs, tdqa, desc, error); + return error; } /* - * sun8i_crypto_task_scatter(adrlen, map, nbytes) + * sun8i_crypto_task_scatter(task, adrlen, map, nbytes) * * Set up a task's scatter/gather vector -- src or dst -- with the * given DMA map for a transfer of nbytes. May fail if input is * inadequately aligned. */ static int -sun8i_crypto_task_scatter(struct sun8i_crypto_adrlen *adrlen, bus_dmamap_t map, +sun8i_crypto_task_scatter(struct sun8i_crypto_task *task, + struct sun8i_crypto_adrlen *adrlen, bus_dmamap_t map, uint32_t nbytes __diagused) { uint32_t total __diagused = 0; unsigned i; + /* + * Verify that the alignment is correct and initialize the + * scatter/gather vector. + */ KASSERT(map->dm_nsegs <= SUN8I_CRYPTO_MAXSEGS); for (i = 0; i < map->dm_nsegs; i++) { - KASSERT((map->dm_segs[i].ds_addr % 4) == 0); + if ((map->dm_segs[i].ds_addr % 4) | + (map->dm_segs[i].ds_len % 4)) { + SDT_PROBE3(sdt, sun8i_crypto, task, misaligned, + task, + map->dm_segs[i].ds_addr, + map->dm_segs[i].ds_len); + return EINVAL; + } KASSERT(map->dm_segs[i].ds_addr <= UINT32_MAX); KASSERT(map->dm_segs[i].ds_len <= UINT32_MAX - total); adrlen[i].adr = htole32(map->dm_segs[i].ds_addr); @@ -575,10 +726,10 @@ sun8i_crypto_task_scatter(struct sun8i_c total += map->dm_segs[i].ds_len; } - /* Verify the remainder are zero. */ + /* Set the remainder to zero. */ for (; i < SUN8I_CRYPTO_MAXSEGS; i++) { - KASSERT(adrlen[i].adr == 0); - KASSERT(adrlen[i].len == 0); + adrlen[i].adr = 0; + adrlen[i].len = 0; } /* Verify the total size matches the transfer length. */ @@ -607,7 +758,6 @@ sun8i_crypto_task_load_trng(struct sun8i KASSERT((task->ct_flags & TASK_SRC) == 0); /* Set up the task descriptor queue control words. */ - tdqc |= SUN8I_CRYPTO_TDQC_INTR_EN; tdqc |= __SHIFTIN(SUN8I_CRYPTO_TDQC_METHOD_TRNG, SUN8I_CRYPTO_TDQC_METHOD); @@ -629,9 +779,9 @@ sun8i_crypto_task_load_aesecb(struct sun KASSERT(task->ct_flags & TASK_SRC); /* Set up the task descriptor queue control word. */ - tdqc |= SUN8I_CRYPTO_TDQC_INTR_EN; tdqc |= __SHIFTIN(SUN8I_CRYPTO_TDQC_METHOD_AES, SUN8I_CRYPTO_TDQC_METHOD); + tdqc |= __SHIFTIN(dir, SUN8I_CRYPTO_TDQC_OP_DIR); #ifdef DIAGNOSTIC switch (keysize) { @@ -749,6 +899,12 @@ sun8i_crypto_submit(struct sun8i_crypto_ /* XXX Consider polling if cold to get entropy earlier. */ out: /* Done! */ + if (error) + SDT_PROBE3(sdt, sun8i_crypto, engine, submit__failure, + sc, task, error); + else + SDT_PROBE3(sdt, sun8i_crypto, engine, submit__success, + sc, task, i); mutex_exit(&sc->sc_lock); return error; } @@ -815,6 +971,8 @@ sun8i_crypto_intr(void *cookie) sun8i_crypto_write(sc, SUN8I_CRYPTO_ISR, isr); sun8i_crypto_write(sc, SUN8I_CRYPTO_ESR, esr); + SDT_PROBE3(sdt, sun8i_crypto, engine, intr, sc, isr, esr); + /* Start the worker if necessary. */ sun8i_crypto_schedule_worker(sc); @@ -942,6 +1100,8 @@ sun8i_crypto_chan_done(struct sun8i_cryp KASSERT(mutex_owned(&sc->sc_lock)); + SDT_PROBE3(sdt, sun8i_crypto, engine, done, sc, i, error); + /* Claim the task if there is one; bail if not. */ if ((task = sc->sc_chan[i].cc_task) == NULL) { device_printf(sc->sc_dev, "channel %u: no task but error=%d\n", @@ -975,7 +1135,7 @@ sun8i_crypto_chan_done(struct sun8i_cryp BUS_DMASYNC_POSTWRITE); if (task->ct_flags & TASK_CTR) bus_dmamap_sync(sc->sc_dmat, task->ct_ctrmap, 0, - task->ct_ctrmap->dm_segs[0].ds_len, BUS_DMASYNC_POSTWRITE); + task->ct_ctrmap->dm_segs[0].ds_len, BUS_DMASYNC_POSTREAD); if (task->ct_flags & TASK_IV) bus_dmamap_sync(sc->sc_dmat, task->ct_ivmap, 0, task->ct_ivmap->dm_segs[0].ds_len, BUS_DMASYNC_POSTWRITE); @@ -986,6 +1146,7 @@ sun8i_crypto_chan_done(struct sun8i_cryp /* Temporarily release the lock to invoke the callback. */ mutex_exit(&sc->sc_lock); + SDT_PROBE2(sdt, sun8i_crypto, task, done, task, error); (*task->ct_callback)(sc, task, task->ct_cookie, error); mutex_enter(&sc->sc_lock); } @@ -1003,8 +1164,8 @@ sun8i_crypto_allocbuf(struct sun8i_crypt int error; /* Allocate a DMA-safe buffer. */ - error = bus_dmamem_alloc(sc->sc_dmat, size, 0, 0, buf->cb_seg, - __arraycount(buf->cb_seg), &buf->cb_nsegs, dmaflags); + error = bus_dmamem_alloc(sc->sc_dmat, size, sizeof(uint32_t), 0, + buf->cb_seg, __arraycount(buf->cb_seg), &buf->cb_nsegs, dmaflags); if (error) goto fail0; @@ -1053,13 +1214,17 @@ sun8i_crypto_rng_attach(struct sun8i_cry /* Preallocate a buffer to reuse. */ error = sun8i_crypto_allocbuf(sc, SUN8I_CRYPTO_RNGBYTES, &rng->cr_buf, BUS_DMA_WAITOK); - if (error) + if (error) { + aprint_error_dev(self, "failed to allocate RNG buffer: %d\n", + error); goto fail0; + } /* Create a task to reuse. */ task = rng->cr_task = sun8i_crypto_task_get(sc, sun8i_crypto_rng_done, rng, PR_WAITOK); if (rng->cr_task == NULL) { + aprint_error_dev(self, "failed to allocate RNG task\n"); error = ENOMEM; goto fail1; } @@ -1067,8 +1232,11 @@ sun8i_crypto_rng_attach(struct sun8i_cry /* Preload the destination map. */ error = bus_dmamap_load(sc->sc_dmat, task->ct_dstmap, rng->cr_buf.cb_kva, SUN8I_CRYPTO_RNGBYTES, NULL, BUS_DMA_NOWAIT); - if (error) + if (error) { + aprint_error_dev(self, "failed to load RNG buffer: %d\n", + error); goto fail2; + } /* * Attach the rndsource. This is _not_ marked as RND_TYPE_RNG @@ -1088,7 +1256,7 @@ fail3: __unused bus_dmamap_unload(sc->sc_dmat, task->ct_dstmap); fail2: sun8i_crypto_task_put(sc, task); fail1: sun8i_crypto_freebuf(sc, SUN8I_CRYPTO_RNGBYTES, &rng->cr_buf); -fail0: aprint_error_dev(self, "failed to set up RNG, error=%d\n", error); +fail0: return; } /* @@ -1250,8 +1418,10 @@ sun8i_crypto_selftest(device_t self) goto fail6; /* Set up the task descriptor. */ - sun8i_crypto_task_load_aesecb(sc, task, nbytes, + error = sun8i_crypto_task_load_aesecb(sc, task, nbytes, SUN8I_CRYPTO_TDQS_AES_KEYSIZE_128, SUN8I_CRYPTO_TDQC_OP_DIR_ENC); + if (error) + goto fail7; /* Submit! */ error = sun8i_crypto_submit(sc, task); @@ -1532,3 +1702,717 @@ sun8i_crypto_sysctl_rng_done(struct sun8 mutex_destroy(&req->cu_lock); kmem_free(req, sizeof(*req)); } + +/* + * sun8i_crypto_register(sc) + * + * Register opencrypto algorithms supported by the crypto engine. + */ +static void +sun8i_crypto_register(struct sun8i_crypto_softc *sc) +{ + struct sun8i_crypto_opencrypto *co = &sc->sc_opencrypto; + + co->co_driverid = crypto_get_driverid(0); + if (co->co_driverid == (uint32_t)-1) { + aprint_error_dev(sc->sc_dev, + "failed to register crypto driver\n"); + return; + } + + sun8i_crypto_register1(sc, CRYPTO_AES_CBC); + sun8i_crypto_register1(sc, CRYPTO_AES_CTR); +#ifdef CRYPTO_AES_ECB + sun8i_crypto_register1(sc, CRYPTO_AES_ECB); +#endif +#ifdef CRYPTO_AES_XTS + sun8i_crypto_register1(sc, CRYPTO_AES_XTS); +#endif +#ifdef CRYPTO_DES_CBC + sun8i_crypto_register1(sc, CRYPTO_DES_CBC); +#endif +#ifdef CRYPTO_DES_ECB + sun8i_crypto_register1(sc, CRYPTO_DES_ECB); +#endif + sun8i_crypto_register1(sc, CRYPTO_3DES_CBC); +#ifdef CRYPTO_3DES_ECB + sun8i_crypto_register1(sc, CRYPTO_3DES_ECB); +#endif + + sun8i_crypto_register1(sc, CRYPTO_MD5); + sun8i_crypto_register1(sc, CRYPTO_SHA1); +#ifdef CRYPTO_SHA224 + sun8i_crypto_register1(sc, CRYPTO_SHA224); +#endif +#ifdef CRYPTO_SHA256 + sun8i_crypto_register1(sc, CRYPTO_SHA256); +#endif + + sun8i_crypto_register1(sc, CRYPTO_SHA1_HMAC); + sun8i_crypto_register1(sc, CRYPTO_SHA2_256_HMAC); + + //sun8i_crypto_kregister(sc, CRK_MOD_EXP); /* XXX unclear */ +} + +/* + * sun8i_crypto_register1(sc, alg) + * + * Register support for one algorithm alg using + * sun8i_crypto_newsession/freesession/process. + */ +static void +sun8i_crypto_register1(struct sun8i_crypto_softc *sc, uint32_t alg) +{ + + crypto_register(sc->sc_opencrypto.co_driverid, alg, 0, 0, + sun8i_crypto_newsession, + sun8i_crypto_freesession, + sun8i_crypto_process, + sc); +} + +/* + * sun8i_crypto_newsession(cookie, sidp, cri) + * + * Called by opencrypto to allocate a new session. We don't keep + * track of sessions, since there are no persistent keys in the + * hardware that we take advantage of, so this only validates the + * crypto operations and returns a zero session id. + */ +static int +sun8i_crypto_newsession(void *cookie, uint32_t *sidp, struct cryptoini *cri) +{ + + /* No composition of operations is supported here. */ + if (cri->cri_next) + return EINVAL; + + /* + * No variation of rounds is supported here. (XXX Unused and + * unimplemented in opencrypto(9) altogether? + */ + if (cri->cri_rnd) + return EINVAL; + + /* + * Validate per-algorithm key length. + * + * XXX Does opencrypto(9) do this internally? + */ + switch (cri->cri_alg) { + case CRYPTO_MD5: + case CRYPTO_SHA1: +#ifdef CRYPTO_SHA224 + case CRYPTO_SHA224: +#endif +#ifdef CRYPTO_SHA256 + case CRYPTO_SHA256: +#endif + if (cri->cri_klen) + return EINVAL; + break; + case CRYPTO_AES_CBC: +#ifdef CRYPTO_AES_ECB + case CRYPTO_AES_ECB: +#endif + switch (cri->cri_klen) { + case 128: + case 192: + case 256: + break; + default: + return EINVAL; + } + break; + case CRYPTO_AES_CTR: + /* + * opencrypto `AES-CTR' takes four bytes of the input + * block as the last four bytes of the key, for reasons + * that are not entirely clear. + */ + switch (cri->cri_klen) { + case 128 + 32: + case 192 + 32: + case 256 + 32: + break; + default: + return EINVAL; + } + break; +#ifdef CRYPTO_AES_XTS + case CRYPTO_AES_XTS: + switch (cri->cri_klen) { + case 256: + case 384: + case 512: + break; + default: + return EINVAL; + } + break; +#endif + case CRYPTO_DES_CBC: +#ifdef CRYPTO_DES_ECB + case CRYPTO_DES_ECB: +#endif + switch (cri->cri_klen) { + case 64: + break; + default: + return EINVAL; + } + break; + case CRYPTO_3DES_CBC: +#ifdef CRYPTO_3DES_ECB + case CRYPTO_3DES_ECB: +#endif + switch (cri->cri_klen) { + case 192: + break; + default: + return EINVAL; + } + break; + case CRYPTO_SHA1_HMAC: + /* + * XXX Unclear what the length limit is, but since HMAC + * behaves qualitatively different for a key of at + * least the full block size -- and is generally best + * to use with half the block size -- let's limit it to + * one block. + */ + if (cri->cri_klen % 8) + return EINVAL; + if (cri->cri_klen > 512) + return EINVAL; + break; + case CRYPTO_SHA2_256_HMAC: + if (cri->cri_klen % 8) + return EINVAL; + if (cri->cri_klen > 512) + return EINVAL; + break; + default: + panic("unsupported algorithm %d", cri->cri_alg); + } + + KASSERT(cri->cri_klen % 8 == 0); + + /* Success! */ + *sidp = 1; + return 0; +} + +/* + * sun8i_crypto_freesession(cookie, dsid) + * + * Called by opencrypto to free a session. We don't keep track of + * sessions, since there are no persistent keys in the hardware + * that we take advantage of, so this is a no-op. + * + * Note: dsid is actually a 64-bit quantity containing both the + * driver id in the high half and the session id in the low half. + */ +static int +sun8i_crypto_freesession(void *cookie, uint64_t dsid) +{ + + KASSERT((dsid & 0xffffffff) == 1); + + /* Success! */ + return 0; +} + +/* + * sun8i_crypto_ivlen(crd) + * + * Return the crypto engine's notion of `IV length', in bytes, for + * an opencrypto operation. + */ +static u_int +sun8i_crypto_ivlen(const struct cryptodesc *crd) +{ + + switch (crd->crd_alg) { + case CRYPTO_AES_CBC: + return 16; +#ifdef CRYPTO_AES_XTS + case CRYPTO_AES_XTS: + return 16; +#endif + case CRYPTO_AES_CTR: /* XXX opencrypto quirk */ + return 8; +#ifdef CRYPTO_DES_CBC + case CRYPTO_DES_CBC: + return 8; +#endif + case CRYPTO_3DES_CBC: + return 8; + case CRYPTO_MD5: + return 16; +#ifdef CRYPTO_SHA224 + case CRYPTO_SHA224: + return 32; +#endif +#ifdef CRYPTO_SHA256 + case CRYPTO_SHA256: + return 32; +#endif + case CRYPTO_SHA1_HMAC: + return 20; + case CRYPTO_SHA2_256_HMAC: + return 32; + default: + return 0; + } +} + +/* + * sun8i_crypto_process(cookie, crp, hint) + * + * Main opencrypto processing dispatch. + */ +static int +sun8i_crypto_process(void *cookie, struct cryptop *crp, int hint) +{ + struct sun8i_crypto_softc *sc = cookie; + struct sun8i_crypto_task *task; + struct cryptodesc *crd = crp->crp_desc; + unsigned klen, ivlen; + uint32_t tdqc = 0, tdqs = 0; + uint32_t dir, method, mode = 0, ctrwidth = 0, aeskeysize = 0; + const uint32_t tdqa = 0; + int error; + + SDT_PROBE3(sdt, sun8i_crypto, process, entry, sc, crp, hint); + + /* Reject compositions -- we do not handle them. */ + if (crd->crd_next != NULL) { + error = EOPNOTSUPP; + goto fail0; + } + + /* Reject transfers with nonsense skip. */ + if (crd->crd_skip < 0) { + error = EINVAL; + goto fail0; + } + + /* + * Actually just reject any nonzero skip, because it requires + * DMA segment bookkeeping that we don't do yet. + */ + if (crd->crd_skip) { + error = EOPNOTSUPP; + goto fail0; + } + + /* Reject large transfers. */ + if (crd->crd_len > SUN8I_CRYPTO_MAXDMASIZE) { + error = EFBIG; + goto fail0; + } + + /* Reject nonsense, unaligned, or mismatched lengths. */ + if (crd->crd_len < 0 || + crd->crd_len % 4 || + crd->crd_len != crp->crp_ilen) { + error = EINVAL; + goto fail0; + } + + /* Reject mismatched buffer lengths. */ + /* XXX Handle crd_skip. */ + if (crp->crp_flags & CRYPTO_F_IMBUF) { + struct mbuf *m = crp->crp_buf; + uint32_t nbytes = 0; + while (m != NULL) { + KASSERT(m->m_len >= 0); + if (m->m_len > crd->crd_len || + nbytes > crd->crd_len - m->m_len) { + error = EINVAL; + goto fail0; + } + nbytes += m->m_len; + m = m->m_next; + } + if (nbytes != crd->crd_len) { + error = EINVAL; + goto fail0; + } + } else if (crp->crp_flags & CRYPTO_F_IOV) { + struct uio *uio = crp->crp_buf; + if (uio->uio_resid != crd->crd_len) { + error = EINVAL; + goto fail0; + } + } + + /* Get a task, or fail with ERESTART if we can't. */ + task = sun8i_crypto_task_get(sc, &sun8i_crypto_callback, crp, + PR_NOWAIT); + if (task == NULL) { + /* + * Don't invoke crypto_done -- we are asking the + * opencrypto(9) machinery to queue the request and get + * back to us. + */ + SDT_PROBE3(sdt, sun8i_crypto, process, busy, sc, crp, hint); + return ERESTART; + } + + /* Load key in, if relevant. */ + klen = crd->crd_klen; + if (klen) { + if (crd->crd_alg == CRYPTO_AES_CTR) + /* AES-CTR is special -- see IV processing below. */ + klen -= 32; + error = bus_dmamap_load(sc->sc_dmat, task->ct_keymap, + crd->crd_key, klen/8, NULL, BUS_DMA_NOWAIT); + if (error) + goto fail1; + task->ct_flags |= TASK_KEY; + } + + /* Handle the IV, if relevant. */ + ivlen = sun8i_crypto_ivlen(crd); + if (ivlen) { + void *iv; + + /* + * If there's an explicit IV, use it; otherwise + * randomly generate one. + */ + if (crd->crd_flags & CRD_F_IV_EXPLICIT) { + iv = crd->crd_iv; + } else { + cprng_fast(task->ct_iv, ivlen); + iv = task->ct_iv; + } + + /* + * If the IV is not already present in the user's + * buffer, copy it over. + */ + if ((crd->crd_flags & CRD_F_IV_PRESENT) == 0) { + if (crp->crp_flags & CRYPTO_F_IMBUF) { + m_copyback(crp->crp_buf, crd->crd_inject, + ivlen, iv); + } else if (crp->crp_flags & CRYPTO_F_IOV) { + cuio_copyback(crp->crp_buf, crd->crd_inject, + ivlen, iv); + } else { + panic("invalid buffer type %x", + crp->crp_flags); + } + } + + /* + * opencrypto's idea of `AES-CTR' is special. + * + * - The low 4 bytes of the input block are drawn from + * an extra 4 bytes at the end of the key. + * + * - The next 8 bytes of the input block are drawn from + * the opencrypto iv. + * + * - The high 4 bytes are the big-endian block counter, + * which starts at 1 because why not. + */ + if (crd->crd_alg == CRYPTO_AES_CTR) { + uint8_t block[16]; + uint32_t blkno = 1; + + /* Format the initial input block. */ + memcpy(block, crd->crd_key + klen/8, 4); + memcpy(block + 4, iv, 8); + be32enc(block + 12, blkno); + + /* Copy it into the DMA buffer. */ + memcpy(task->ct_iv, block, 16); + iv = task->ct_iv; + ivlen = 16; + } + + /* Load the IV. */ + error = bus_dmamap_load(sc->sc_dmat, task->ct_ivmap, iv, ivlen, + NULL, BUS_DMA_NOWAIT); + if (error) + goto fail1; + task->ct_flags |= TASK_IV; + } + + /* Load the src and dst. */ + if (crp->crp_flags & CRYPTO_F_IMBUF) { + struct mbuf *m = crp->crp_buf; + + /* XXX Handle crd_skip. */ + KASSERT(crd->crd_skip == 0); + error = bus_dmamap_load_mbuf(sc->sc_dmat, task->ct_srcmap, m, + BUS_DMA_NOWAIT); + if (error) + goto fail1; + task->ct_flags |= TASK_SRC; + + /* XXX Handle crd_skip. */ + KASSERT(crd->crd_skip == 0); + error = bus_dmamap_load_mbuf(sc->sc_dmat, task->ct_dstmap, m, + BUS_DMA_NOWAIT); + if (error) + goto fail1; + } else if (crp->crp_flags & CRYPTO_F_IOV) { + struct uio *uio = crp->crp_buf; + + /* XXX Handle crd_skip. */ + KASSERT(crd->crd_skip == 0); + error = bus_dmamap_load_uio(sc->sc_dmat, task->ct_srcmap, uio, + BUS_DMA_NOWAIT); + if (error) + goto fail1; + task->ct_flags |= TASK_SRC; + + /* XXX Handle crd_skip. */ + KASSERT(crd->crd_skip == 0); + error = bus_dmamap_load_uio(sc->sc_dmat, task->ct_dstmap, uio, + BUS_DMA_NOWAIT); + if (error) + goto fail1; + } else { + panic("invalid buffer type %x", crp->crp_flags); + } + + /* Set the encryption direction. */ + if (crd->crd_flags & CRD_F_ENCRYPT) + dir = SUN8I_CRYPTO_TDQC_OP_DIR_ENC; + else + dir = SUN8I_CRYPTO_TDQC_OP_DIR_DEC; + tdqc |= __SHIFTIN(dir, SUN8I_CRYPTO_TDQC_OP_DIR); + + /* Set the method. */ + switch (crd->crd_alg) { + case CRYPTO_AES_CBC: + case CRYPTO_AES_CTR: +#ifdef CRYPTO_AES_ECB + case CRYPTO_AES_ECB: +#endif + method = SUN8I_CRYPTO_TDQC_METHOD_AES; + break; +#ifdef CRYPTO_AES_XTS + case CRYPTO_AES_XTS: + method = SUN8I_CRYPTO_TDQC_METHOD_AES; + break; +#endif + case CRYPTO_DES_CBC: +#ifdef CRYPTO_DES_ECB + case CRYPTO_DES_ECB: +#endif + method = SUN8I_CRYPTO_TDQC_METHOD_DES; + break; + case CRYPTO_3DES_CBC: +#ifdef CRYPTO_3DES_ECB + case CRYPTO_3DES_ECB: +#endif + method = SUN8I_CRYPTO_TDQC_METHOD_3DES; + break; + case CRYPTO_MD5: + method = SUN8I_CRYPTO_TDQC_METHOD_MD5; + break; + case CRYPTO_SHA1: + method = SUN8I_CRYPTO_TDQC_METHOD_SHA1; + break; +#ifdef CRYPTO_SHA224 + case CRYPTO_SHA224: + method = SUN8I_CRYPTO_TDQC_METHOD_SHA224; + break; +#endif +#ifdef CRYPTO_SHA256 + case CRYPTO_SHA256: + method = SUN8I_CRYPTO_TDQC_METHOD_SHA256; + break; +#endif + case CRYPTO_SHA1_HMAC: + method = SUN8I_CRYPTO_TDQC_METHOD_HMAC_SHA1; + break; + case CRYPTO_SHA2_256_HMAC: + method = SUN8I_CRYPTO_TDQC_METHOD_HMAC_SHA256; + break; + default: + panic("unknown algorithm %d", crd->crd_alg); + } + tdqc |= __SHIFTIN(method, SUN8I_CRYPTO_TDQC_METHOD); + + /* Set the key selector. No idea how to use the internal keys. */ + tdqs |= __SHIFTIN(SUN8I_CRYPTO_TDQS_SKEY_SELECT_SS_KEYx, + SUN8I_CRYPTO_TDQS_SKEY_SELECT); + + /* XXX Deal with AES_CTS_Last_Block_Flag. */ + + /* Set the mode. */ + switch (crd->crd_alg) { +#ifdef CRYPTO_AES_ECB + case CRYPTO_AES_ECB: + mode = SUN8I_CRYPTO_TDQS_OP_MODE_ECB; + break; +#endif +#ifdef CRYPTO_DES_ECB + case CRYPTO_DES_ECB: + mode = SUN8I_CRYPTO_TDQS_OP_MODE_ECB; + break; +#endif +#ifdef CRYPTO_3DES_ECB + case CRYPTO_3DES_ECB: + mode = SUN8I_CRYPTO_TDQS_OP_MODE_ECB; + break; +#endif + case CRYPTO_AES_CBC: + case CRYPTO_DES_CBC: + case CRYPTO_3DES_CBC: + mode = SUN8I_CRYPTO_TDQS_OP_MODE_CBC; + break; + case CRYPTO_AES_CTR: + mode = SUN8I_CRYPTO_TDQS_OP_MODE_CTR; + break; +#ifdef CRYPTO_AES_XTS + case CRYPTO_AES_XTS: + mode = SUN8I_CRYPTO_TDQS_OP_MODE_CTS; + break; +#endif + default: + panic("unknown algorithm %d", crd->crd_alg); + } + tdqs |= __SHIFTIN(mode, SUN8I_CRYPTO_TDQS_OP_MODE); + + /* Set the CTR width. */ + switch (crd->crd_alg) { + case CRYPTO_AES_CTR: + ctrwidth = SUN8I_CRYPTO_TDQS_CTR_WIDTH_32; + break; + } + tdqs |= __SHIFTIN(ctrwidth, SUN8I_CRYPTO_TDQS_CTR_WIDTH); + + /* Set the AES key size. */ + switch (crd->crd_alg) { + case CRYPTO_AES_CBC: +#ifdef CRYPTO_AES_ECB + case CRYPTO_AES_ECB: +#endif + switch (crd->crd_klen) { + case 128: + aeskeysize = SUN8I_CRYPTO_TDQS_AES_KEYSIZE_128; + break; + case 192: + aeskeysize = SUN8I_CRYPTO_TDQS_AES_KEYSIZE_192; + break; + case 256: + aeskeysize = SUN8I_CRYPTO_TDQS_AES_KEYSIZE_256; + break; + default: + panic("invalid AES key size in bits: %u", + crd->crd_klen); + } + break; + case CRYPTO_AES_CTR: + switch (crd->crd_klen) { + case 128 + 32: + aeskeysize = SUN8I_CRYPTO_TDQS_AES_KEYSIZE_128; + break; + case 192 + 32: + aeskeysize = SUN8I_CRYPTO_TDQS_AES_KEYSIZE_192; + break; + case 256 + 32: + aeskeysize = SUN8I_CRYPTO_TDQS_AES_KEYSIZE_256; + break; + default: + panic("invalid `AES-CTR' ` ``key'' size' in bits: %u", + crd->crd_klen); + } + break; +#ifdef CRYPTO_AES_XTS + case CRYPTO_AES_XTS: + switch (crd->crd_klen) { + case 256: + aeskeysize = SUN8I_CRYPTO_TDQS_AES_KEYSIZE_128; + break; + case 384: + aeskeysize = SUN8I_CRYPTO_TDQS_AES_KEYSIZE_192; + break; + case 512: + aeskeysize = SUN8I_CRYPTO_TDQS_AES_KEYSIZE_256; + break; + default: + panic("invalid AES-XTS key size in bits: %u", + crd->crd_klen); + } + break; +#endif + } + tdqs |= __SHIFTIN(aeskeysize, SUN8I_CRYPTO_TDQS_AES_KEYSIZE); + + /* Set up the task descriptor. */ + error = sun8i_crypto_task_load(sc, task, crd->crd_len, + tdqc, tdqs, tdqa); + if (error) + goto fail2; + + /* Submit! */ + error = sun8i_crypto_submit(sc, task); + if (error) + goto fail2; + + /* Success! */ + SDT_PROBE4(sdt, sun8i_crypto, process, queued, sc, crp, hint, task); + return 0; + +fail2: bus_dmamap_unload(sc->sc_dmat, task->ct_dstmap); +fail1: if (task->ct_flags & TASK_SRC) + bus_dmamap_unload(sc->sc_dmat, task->ct_srcmap); + if (task->ct_flags & TASK_CTR) + bus_dmamap_unload(sc->sc_dmat, task->ct_ctrmap); + if (task->ct_flags & TASK_IV) + bus_dmamap_unload(sc->sc_dmat, task->ct_ivmap); + if (task->ct_flags & TASK_KEY) + bus_dmamap_unload(sc->sc_dmat, task->ct_keymap); + sun8i_crypto_task_put(sc, task); +fail0: KASSERT(error); + KASSERT(error != ERESTART); + crp->crp_etype = error; + SDT_PROBE3(sdt, sun8i_crypto, process, done, sc, crp, error); + crypto_done(crp); + return 0; +} + +/* + * sun8i_crypto_callback(sc, task, cookie, error) + * + * Completion callback for a task submitted via opencrypto. + * Release the task and pass the error on to opencrypto with + * crypto_done. + */ +static void +sun8i_crypto_callback(struct sun8i_crypto_softc *sc, + struct sun8i_crypto_task *task, void *cookie, int error) +{ + struct cryptop *crp = cookie; + struct cryptodesc *crd = crp->crp_desc; + + KASSERT(error != ERESTART); + KASSERT(crd != NULL); + KASSERT(crd->crd_next == NULL); + + /* Return the number of bytes processed. */ + crp->crp_olen = error ? 0 : crp->crp_ilen; + + bus_dmamap_unload(sc->sc_dmat, task->ct_dstmap); + bus_dmamap_unload(sc->sc_dmat, task->ct_srcmap); + if (task->ct_flags & TASK_CTR) + bus_dmamap_unload(sc->sc_dmat, task->ct_ctrmap); + if (task->ct_flags & TASK_IV) + bus_dmamap_unload(sc->sc_dmat, task->ct_ivmap); + if (task->ct_flags & TASK_KEY) + bus_dmamap_unload(sc->sc_dmat, task->ct_keymap); + sun8i_crypto_task_put(sc, task); + KASSERT(error != ERESTART); + crp->crp_etype = error; + SDT_PROBE3(sdt, sun8i_crypto, process, done, sc, crp, error); + crypto_done(crp); +}