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);
+}

Reply via email to