Module Name: src
Committed By: riastradh
Date: Sat Jun 13 18:57:54 UTC 2020
Modified Files:
src/sys/arch/arm/sunxi: sun8i_crypto.c sun8i_crypto.h
Log Message:
Rework sun8i crypto.
- Preallocate tasks and DMA maps together for now, for 4k transfers.
- Confine setup of the task descriptor to a single function, without
bus_dmamap_t as an input; just use the preallocated DMA maps.
- Take the DMA map part out of sun8i_crypto_buf.
=> Not much left here, just a dmamem segment and kva mapping.
This should make it easier to use with opencrypto.
To generate a diff of this commit:
cvs rdiff -u -r1.15 -r1.16 src/sys/arch/arm/sunxi/sun8i_crypto.c
cvs rdiff -u -r1.1 -r1.2 src/sys/arch/arm/sunxi/sun8i_crypto.h
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.15 src/sys/arch/arm/sunxi/sun8i_crypto.c:1.16
--- src/sys/arch/arm/sunxi/sun8i_crypto.c:1.15 Sat Jun 13 18:54:38 2020
+++ src/sys/arch/arm/sunxi/sun8i_crypto.c Sat Jun 13 18:57:54 2020
@@ -1,4 +1,4 @@
-/* $NetBSD: sun8i_crypto.c,v 1.15 2020/06/13 18:54:38 riastradh Exp $ */
+/* $NetBSD: sun8i_crypto.c,v 1.16 2020/06/13 18:57:54 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.15 2020/06/13 18:54:38 riastradh Exp $");
+__KERNEL_RCSID(1, "$NetBSD: sun8i_crypto.c,v 1.16 2020/06/13 18:57:54 riastradh Exp $");
#include <sys/types.h>
#include <sys/param.h>
@@ -72,7 +72,6 @@ struct sun8i_crypto_task;
struct sun8i_crypto_buf {
bus_dma_segment_t cb_seg[1];
int cb_nsegs;
- bus_dmamap_t cb_map;
void *cb_kva;
};
@@ -81,6 +80,7 @@ struct sun8i_crypto_softc {
bus_space_tag_t sc_bst;
bus_space_handle_t sc_bsh;
bus_dma_tag_t sc_dmat;
+ struct pool_cache *sc_taskpool;
kmutex_t sc_lock;
struct sun8i_crypto_chan {
struct sun8i_crypto_task *cc_task;
@@ -113,13 +113,32 @@ struct sun8i_crypto_softc {
};
struct sun8i_crypto_task {
- struct sun8i_crypto_buf ct_buf;
+ struct sun8i_crypto_buf ct_descbuf;
struct sun8i_crypto_taskdesc *ct_desc;
+ bus_dmamap_t ct_descmap;
+ bus_dmamap_t ct_keymap;
+ bus_dmamap_t ct_ivmap;
+ bus_dmamap_t ct_ctrmap;
+ bus_dmamap_t ct_srcmap;
+ bus_dmamap_t ct_dstmap;
+ uint32_t ct_nbytes;
+ int ct_flags;
+#define TASK_KEY __BIT(0)
+#define TASK_IV __BIT(1)
+#define TASK_CTR __BIT(2)
+#define TASK_SRC __BIT(3)
+#define TASK_BYTES __BIT(4) /* datalen is in bytes, not words */
void (*ct_callback)(struct sun8i_crypto_softc *,
struct sun8i_crypto_task *, void *, int);
void *ct_cookie;
};
+#define SUN8I_CRYPTO_MAXDMASIZE PAGE_SIZE
+#define SUN8I_CRYPTO_MAXDMASEGSIZE PAGE_SIZE
+
+CTASSERT(SUN8I_CRYPTO_MAXDMASIZE <= SUN8I_CRYPTO_MAXDATALEN);
+CTASSERT(SUN8I_CRYPTO_MAXDMASEGSIZE <= SUN8I_CRYPTO_MAXSEGLEN);
+
/*
* Forward declarations
*/
@@ -127,33 +146,27 @@ struct sun8i_crypto_task {
static int sun8i_crypto_match(device_t, cfdata_t, void *);
static void sun8i_crypto_attach(device_t, device_t, void *);
+static int sun8i_crypto_task_ctor(void *, void *, int);
+static void sun8i_crypto_task_dtor(void *, void *);
static struct sun8i_crypto_task *
sun8i_crypto_task_get(struct sun8i_crypto_softc *,
void (*)(struct sun8i_crypto_softc *,
struct sun8i_crypto_task *, void *, int),
- void *);
+ void *, int);
static void sun8i_crypto_task_put(struct sun8i_crypto_softc *,
struct sun8i_crypto_task *);
-static void sun8i_crypto_task_reset(struct sun8i_crypto_task *);
-static void sun8i_crypto_task_set_key(struct sun8i_crypto_task *,
- bus_dmamap_t);
-static void sun8i_crypto_task_set_iv(struct sun8i_crypto_task *,
- bus_dmamap_t);
-static void sun8i_crypto_task_set_ctr(struct sun8i_crypto_task *,
- bus_dmamap_t);
-static void sun8i_crypto_task_set_input(struct sun8i_crypto_task *,
- bus_dmamap_t);
-static void sun8i_crypto_task_set_output(struct sun8i_crypto_task *,
- bus_dmamap_t);
+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 void sun8i_crypto_task_scatter(struct sun8i_crypto_adrlen *,
- bus_dmamap_t);
-
-static int sun8i_crypto_submit_trng(struct sun8i_crypto_softc *,
+static int sun8i_crypto_task_load_trng(struct sun8i_crypto_softc *,
struct sun8i_crypto_task *, uint32_t);
-static int sun8i_crypto_submit_aesecb(struct sun8i_crypto_softc *,
+static int sun8i_crypto_task_load_aesecb(struct sun8i_crypto_softc *,
struct sun8i_crypto_task *, uint32_t, uint32_t, uint32_t);
+
static int sun8i_crypto_submit(struct sun8i_crypto_softc *,
struct sun8i_crypto_task *);
@@ -165,7 +178,7 @@ static void sun8i_crypto_chan_done(struc
int);
static int sun8i_crypto_allocbuf(struct sun8i_crypto_softc *, size_t,
- struct sun8i_crypto_buf *);
+ struct sun8i_crypto_buf *, int);
static void sun8i_crypto_freebuf(struct sun8i_crypto_softc *, size_t,
struct sun8i_crypto_buf *);
@@ -234,6 +247,9 @@ sun8i_crypto_attach(device_t parent, dev
sc->sc_dev = self;
sc->sc_dmat = faa->faa_dmat;
sc->sc_bst = faa->faa_bst;
+ sc->sc_taskpool = pool_cache_init(sizeof(struct sun8i_crypto_task),
+ 0, 0, 0, "sun8icry", NULL, IPL_VM,
+ &sun8i_crypto_task_ctor, &sun8i_crypto_task_dtor, sc);
mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_VM);
callout_init(&sc->sc_timeout, CALLOUT_MPSAFE);
callout_setfunc(&sc->sc_timeout, &sun8i_crypto_timeout, sc);
@@ -313,102 +329,238 @@ sun8i_crypto_attach(device_t parent, dev
config_interrupts(self, sun8i_crypto_selftest);
}
-/*
- * Task allocation
- */
-
-static struct sun8i_crypto_task *
-sun8i_crypto_task_get(struct sun8i_crypto_softc *sc,
- void (*callback)(struct sun8i_crypto_softc *, struct sun8i_crypto_task *,
- void *, int),
- void *cookie)
+static int
+sun8i_crypto_task_ctor(void *cookie, void *vtask, int pflags)
{
- struct sun8i_crypto_task *task;
+ struct sun8i_crypto_softc *sc = cookie;
+ struct sun8i_crypto_task *task = vtask;
+ int dmaflags = (pflags & PR_WAITOK) ? BUS_DMA_WAITOK : BUS_DMA_NOWAIT;
int error;
- /* Allocate a task. */
- task = kmem_zalloc(sizeof(*task), KM_SLEEP);
-
- /* Allocate a buffer for the descriptor. */
+ /* Create a DMA buffer for the task descriptor. */
error = sun8i_crypto_allocbuf(sc, sizeof(*task->ct_desc),
- &task->ct_buf);
+ &task->ct_descbuf, dmaflags);
if (error)
goto fail0;
+ task->ct_desc = task->ct_descbuf.cb_kva;
- /* Initialize the task object and return it. */
- task->ct_desc = task->ct_buf.cb_kva;
- task->ct_callback = callback;
- task->ct_cookie = cookie;
- return task;
+ /* 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;
+ 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;
+
+ /* 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;
+ error = bus_dmamap_create(sc->sc_dmat, SUN8I_CRYPTO_MAXIVBYTES, 1,
+ SUN8I_CRYPTO_MAXIVBYTES, 0, dmaflags, &task->ct_ivmap);
+ if (error)
+ goto fail4;
+ error = bus_dmamap_create(sc->sc_dmat, SUN8I_CRYPTO_MAXCTRBYTES, 1,
+ SUN8I_CRYPTO_MAXCTRBYTES, 0, dmaflags, &task->ct_ctrmap);
+ if (error)
+ goto fail5;
-fail1: __unused
- sun8i_crypto_freebuf(sc, sizeof(*task->ct_desc), &task->ct_buf);
-fail0: kmem_free(task, sizeof(*task));
- return NULL;
+ /* 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;
+ 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;
+
+ /* Success! */
+ return 0;
+
+fail8: __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);
+fail1: sun8i_crypto_freebuf(sc, sizeof(*task->ct_desc), &task->ct_descbuf);
+fail0: return error;
}
static void
-sun8i_crypto_task_put(struct sun8i_crypto_softc *sc,
- struct sun8i_crypto_task *task)
+sun8i_crypto_task_dtor(void *cookie, void *vtask)
{
+ struct sun8i_crypto_softc *sc = cookie;
+ struct sun8i_crypto_task *task = vtask;
+
+ /* XXX Zero the bounce buffers if there are any. */
- sun8i_crypto_freebuf(sc, sizeof(*task->ct_desc), &task->ct_buf);
- kmem_free(task, sizeof(*task));
+ bus_dmamap_destroy(sc->sc_dmat, task->ct_dstmap);
+ bus_dmamap_destroy(sc->sc_dmat, task->ct_srcmap);
+ bus_dmamap_destroy(sc->sc_dmat, task->ct_ctrmap);
+ bus_dmamap_destroy(sc->sc_dmat, task->ct_ivmap);
+ 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, sizeof(*task->ct_desc), &task->ct_descbuf);
}
/*
- * Task descriptor setup
+ * sun8i_crypto_task_get(sc, callback, cookie, pflags)
*
- * WARNING: Task descriptor fields are little-endian, not host-endian.
+ * Allocate a task that will call callback(sc, task, cookie,
+ * error) when done. pflags is PR_WAITOK or PR_NOWAIT; if
+ * PR_NOWAIT, may fail and return NULL. No further allocation is
+ * needed to submit the task if this succeeds (although task
+ * submission may still fail if all channels are busy).
*/
-
-static void
-sun8i_crypto_task_reset(struct sun8i_crypto_task *task)
+static struct sun8i_crypto_task *
+sun8i_crypto_task_get(struct sun8i_crypto_softc *sc,
+ void (*callback)(struct sun8i_crypto_softc *, struct sun8i_crypto_task *,
+ void *, int),
+ void *cookie, int pflags)
{
+ struct sun8i_crypto_task *task;
+
+ /* Allocate a task, or fail if we can't. */
+ task = pool_cache_get(sc->sc_taskpool, pflags);
+ if (task == NULL)
+ return NULL;
- memset(task->ct_desc, 0, sizeof(*task->ct_desc));
+ /* Set up flags and the callback. */
+ task->ct_flags = 0;
+ task->ct_callback = callback;
+ task->ct_cookie = cookie;
+ return task;
}
+/*
+ * sun8i_crypto_task_invalid(sc, task, cookie, error)
+ *
+ * Callback for a task not currently in use, to detect errors.
+ */
static void
-sun8i_crypto_task_set_key(struct sun8i_crypto_task *task, bus_dmamap_t map)
+sun8i_crypto_task_invalid(struct sun8i_crypto_softc *sc,
+ struct sun8i_crypto_task *task, void *cookie, int error)
{
+ void (*callback)(struct sun8i_crypto_softc *,
+ struct sun8i_crypto_task *, void *, int) = cookie;
- KASSERT(map->dm_nsegs == 1);
- task->ct_desc->td_keydesc = htole32(map->dm_segs[0].ds_addr);
+ panic("task for callback %p used after free", callback);
}
-static void __unused /* XXX opencrypto(9) */
-sun8i_crypto_task_set_iv(struct sun8i_crypto_task *task, bus_dmamap_t map)
+/*
+ * sun8i_crypto_task_put(sc, task)
+ *
+ * Free a task obtained with sun8i_crypto_task_get.
+ */
+static void
+sun8i_crypto_task_put(struct sun8i_crypto_softc *sc,
+ struct sun8i_crypto_task *task)
{
- KASSERT(map->dm_nsegs == 1);
- task->ct_desc->td_ivdesc = htole32(map->dm_segs[0].ds_addr);
+ task->ct_cookie = task->ct_callback;
+ task->ct_callback = &sun8i_crypto_task_invalid;
+ pool_cache_put(sc->sc_taskpool, task);
}
-static void __unused /* XXX opencrypto(9) */
-sun8i_crypto_task_set_ctr(struct sun8i_crypto_task *task, bus_dmamap_t map)
+/*
+ * sun8i_crypto_task_load(sc, task, nbytes, tdqc, tdqs, tdqa)
+ *
+ * Set up the task descriptor after the relevant DMA maps have
+ * been loaded for a transfer of nbytes. bus_dmamap_sync matches
+ * 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
+sun8i_crypto_task_load(struct sun8i_crypto_softc *sc,
+ struct sun8i_crypto_task *task, uint32_t nbytes,
+ uint32_t tdqc, uint32_t tdqs, uint32_t tdqa)
{
+ struct sun8i_crypto_taskdesc *desc = task->ct_desc;
+ int error;
- KASSERT(map->dm_nsegs == 1);
- task->ct_desc->td_ctrdesc = htole32(map->dm_segs[0].ds_addr);
-}
+ KASSERT(tdqs == 0 || tdqa == 0);
+ KASSERT(nbytes % 4 == 0);
-static void
-sun8i_crypto_task_set_input(struct sun8i_crypto_task *task, bus_dmamap_t map)
-{
+ memset(desc, 0, sizeof(*desc));
- sun8i_crypto_task_scatter(task->ct_desc->td_src, map);
-}
+ desc->td_tdqc = htole32(tdqc);
+ desc->td_tdqs = htole32(tdqs);
+ desc->td_tdqa = htole32(tdqa);
-static void
-sun8i_crypto_task_set_output(struct sun8i_crypto_task *task, bus_dmamap_t map)
-{
+ if (task->ct_flags & TASK_KEY) {
+ bus_dmamap_t keymap = task->ct_keymap;
+ KASSERT(keymap->dm_nsegs == 1);
+ desc->td_keydesc = htole32(keymap->dm_segs[0].ds_addr);
+ bus_dmamap_sync(sc->sc_dmat, keymap, 0,
+ keymap->dm_segs[0].ds_len, BUS_DMASYNC_PREWRITE);
+ }
+ if (task->ct_flags & TASK_IV) {
+ bus_dmamap_t ivmap = task->ct_ivmap;
+ KASSERT(ivmap->dm_nsegs == 1);
+ desc->td_ivdesc = htole32(ivmap->dm_segs[0].ds_addr);
+ bus_dmamap_sync(sc->sc_dmat, ivmap, 0,
+ ivmap->dm_segs[0].ds_len, BUS_DMASYNC_PREWRITE);
+ }
+ if (task->ct_flags & TASK_CTR) {
+ bus_dmamap_t ctrmap = task->ct_ctrmap;
+ 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);
+ }
+
+ if (task->ct_flags & TASK_BYTES)
+ desc->td_datalen = htole32(nbytes);
+ else
+ desc->td_datalen = htole32(nbytes/4);
+
+ 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,
+ nbytes);
+ if (error)
+ return error;
+ bus_dmamap_sync(sc->sc_dmat, srcmap, 0, nbytes,
+ BUS_DMASYNC_PREWRITE);
+ }
+
+ error = sun8i_crypto_task_scatter(desc->td_dst, task->ct_dstmap,
+ nbytes);
+ if (error)
+ return error;
+ bus_dmamap_sync(sc->sc_dmat, task->ct_dstmap, 0, nbytes,
+ BUS_DMASYNC_PREREAD);
- sun8i_crypto_task_scatter(task->ct_desc->td_dst, map);
+ task->ct_nbytes = nbytes;
+
+ /* Success! */
+ return 0;
}
-static void
-sun8i_crypto_task_scatter(struct sun8i_crypto_adrlen *adrlen, bus_dmamap_t map)
+/*
+ * sun8i_crypto_task_scatter(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,
+ uint32_t nbytes __diagused)
{
uint32_t total __diagused = 0;
unsigned i;
@@ -429,120 +581,90 @@ sun8i_crypto_task_scatter(struct sun8i_c
KASSERT(adrlen[i].len == 0);
}
- /* Verify the total size matches the DMA map. */
- KASSERT(total == map->dm_mapsize);
+ /* Verify the total size matches the transfer length. */
+ KASSERT(total == nbytes);
+
+ /* Success! */
+ return 0;
}
/*
- * Task submission
+ * sun8i_crypto_task_load_trng(task, nbytes)
*
- * WARNING: Task descriptor fields are little-endian, not host-endian.
+ * Set up the task descriptor for a transfer of nbytes from the
+ * TRNG.
*/
-
static int
-sun8i_crypto_submit_trng(struct sun8i_crypto_softc *sc,
- struct sun8i_crypto_task *task, uint32_t datalen)
+sun8i_crypto_task_load_trng(struct sun8i_crypto_softc *sc,
+ struct sun8i_crypto_task *task, uint32_t nbytes)
{
- struct sun8i_crypto_taskdesc *desc = task->ct_desc;
uint32_t tdqc = 0;
- uint32_t total __diagused;
- unsigned i __diagused;
-
- /* Data length must be a multiple of 4 because...reasons. */
- KASSERT((datalen % 4) == 0);
- /* All of the sources should be empty. */
- for (total = 0, i = 0; i < SUN8I_CRYPTO_MAXSEGS; i++)
- KASSERT(le32toh(task->ct_desc->td_src[i].len) == 0);
-
- /* Verify the total output length -- should be datalen/4. */
- for (total = 0, i = 0; i < SUN8I_CRYPTO_MAXSEGS; i++) {
- uint32_t len = le32toh(task->ct_desc->td_dst[i].len);
- KASSERT(len <= UINT32_MAX - total);
- total += len;
- }
- KASSERT(total == datalen/4);
-
- /* Verify the key, IV, and CTR are unset. */
- KASSERT(desc->td_keydesc == 0);
- KASSERT(desc->td_ivdesc == 0);
- KASSERT(desc->td_ctrdesc == 0);
+ /* Caller must provide dst only. */
+ KASSERT((task->ct_flags & TASK_KEY) == 0);
+ KASSERT((task->ct_flags & TASK_IV) == 0);
+ KASSERT((task->ct_flags & TASK_CTR) == 0);
+ 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);
- desc->td_tdqc = htole32(tdqc);
- desc->td_tdqs = 0; /* no symmetric crypto */
- desc->td_tdqa = 0; /* no asymmetric crypto */
- /* Set the data length for the output. */
- desc->td_datalen = htole32(datalen/4);
-
- /* Submit! */
- return sun8i_crypto_submit(sc, task);
+ /* Fill in the descriptor. */
+ return sun8i_crypto_task_load(sc, task, nbytes, tdqc, 0, 0);
}
static int
-sun8i_crypto_submit_aesecb(struct sun8i_crypto_softc *sc,
+sun8i_crypto_task_load_aesecb(struct sun8i_crypto_softc *sc,
struct sun8i_crypto_task *task,
- uint32_t datalen, uint32_t keysize, uint32_t dir)
+ uint32_t nbytes, uint32_t keysize, uint32_t dir)
{
- struct sun8i_crypto_taskdesc *desc = task->ct_desc;
uint32_t tdqc = 0, tdqs = 0;
- uint32_t total __diagused;
- unsigned i __diagused;
- /*
- * Data length must be a multiple of 4 because...reasons.
- *
- * WARNING: For `AES-CTS' (maybe that means AES-XTS?), datalen
- * is in units of bytes, not units of words -- but everything
- * _else_ is in units of words. This routine applies only to
- * AES-ECB for the self-test.
- */
- KASSERT((datalen % 4) == 0);
-
- /* Verify the total input length -- should be datalen/4. */
- for (total = 0, i = 0; i < SUN8I_CRYPTO_MAXSEGS; i++) {
- uint32_t len = le32toh(task->ct_desc->td_src[i].len);
- KASSERT(len <= UINT32_MAX - total);
- total += len;
- }
- KASSERT(total == datalen/4);
-
- /* Verify the total output length -- should be datalen/4. */
- for (total = 0, i = 0; i < SUN8I_CRYPTO_MAXSEGS; i++) {
- uint32_t len = le32toh(task->ct_desc->td_dst[i].len);
- KASSERT(len <= UINT32_MAX - total);
- total += len;
- }
- KASSERT(total == datalen/4);
+ /* Caller must provide key, src, and dst only. */
+ KASSERT(task->ct_flags & TASK_KEY);
+ KASSERT((task->ct_flags & TASK_IV) == 0);
+ KASSERT((task->ct_flags & TASK_CTR) == 0);
+ 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);
- desc->td_tdqc = htole32(tdqc);
+
+#ifdef DIAGNOSTIC
+ switch (keysize) {
+ case SUN8I_CRYPTO_TDQS_AES_KEYSIZE_128:
+ KASSERT(task->ct_keymap->dm_segs[0].ds_len == 16);
+ break;
+ case SUN8I_CRYPTO_TDQS_AES_KEYSIZE_192:
+ KASSERT(task->ct_keymap->dm_segs[0].ds_len == 24);
+ break;
+ case SUN8I_CRYPTO_TDQS_AES_KEYSIZE_256:
+ KASSERT(task->ct_keymap->dm_segs[0].ds_len == 32);
+ break;
+ }
+#endif
/* Set up the symmetric control word. */
tdqs |= __SHIFTIN(SUN8I_CRYPTO_TDQS_SKEY_SELECT_SS_KEYx,
SUN8I_CRYPTO_TDQS_SKEY_SELECT);
tdqs |= __SHIFTIN(SUN8I_CRYPTO_TDQS_OP_MODE_ECB,
SUN8I_CRYPTO_TDQS_OP_MODE);
- tdqs |= __SHIFTIN(SUN8I_CRYPTO_TDQS_AES_KEYSIZE_128,
- SUN8I_CRYPTO_TDQS_AES_KEYSIZE);
- desc->td_tdqs = htole32(tdqs);
-
- desc->td_tdqa = 0; /* no asymmetric crypto */
+ tdqs |= __SHIFTIN(keysize, SUN8I_CRYPTO_TDQS_AES_KEYSIZE);
- /* Set the data length for the output. */
- desc->td_datalen = htole32(datalen/4);
-
- /* Submit! */
- return sun8i_crypto_submit(sc, task);
+ /* Fill in the descriptor. */
+ return sun8i_crypto_task_load(sc, task, nbytes, tdqc, tdqs, 0);
}
+/*
+ * sun8i_crypto_submit(sc, task)
+ *
+ * Submit a task to the crypto engine after it has been loaded
+ * with sun8i_crypto_task_load. On success, guarantees to
+ * eventually call the task's callback.
+ */
static int
sun8i_crypto_submit(struct sun8i_crypto_softc *sc,
struct sun8i_crypto_task *task)
@@ -571,8 +693,11 @@ sun8i_crypto_submit(struct sun8i_crypto_
*/
task->ct_desc->td_cid = htole32(i);
- /* Prepare to send the descriptor to the device by DMA. */
- bus_dmamap_sync(sc->sc_dmat, task->ct_buf.cb_map, 0,
+ /*
+ * Prepare to send the descriptor to the device by DMA.
+ * Matches POSTWRITE in sun8i_crypto_chan_done.
+ */
+ bus_dmamap_sync(sc->sc_dmat, task->ct_descmap, 0,
sizeof(*task->ct_desc), BUS_DMASYNC_PREWRITE);
/* Confirm we're ready to go. */
@@ -590,7 +715,7 @@ sun8i_crypto_submit(struct sun8i_crypto_
/* Set the task descriptor queue address. */
sun8i_crypto_write(sc, SUN8I_CRYPTO_TDQ,
- task->ct_buf.cb_map->dm_segs[0].ds_addr);
+ task->ct_descmap->dm_segs[0].ds_addr);
/* Notify the engine to load it, and wait for acknowledgement. */
sun8i_crypto_write(sc, SUN8I_CRYPTO_TLR, SUN8I_CRYPTO_TLR_LOAD);
@@ -612,10 +737,14 @@ sun8i_crypto_submit(struct sun8i_crypto_
DELAY(1);
}
- /* Loaded up and ready to go. Start a timer ticking. */
+ /*
+ * Loaded up and ready to go. Start a timer ticking if it's
+ * not already.
+ */
sc->sc_chan[i].cc_task = task;
sc->sc_chan[i].cc_starttime = getticks();
- callout_schedule(&sc->sc_timeout, SUN8I_CRYPTO_TIMEOUT);
+ if (!callout_pending(&sc->sc_timeout))
+ callout_schedule(&sc->sc_timeout, SUN8I_CRYPTO_TIMEOUT);
/* XXX Consider polling if cold to get entropy earlier. */
@@ -624,6 +753,14 @@ out: /* Done! */
return error;
}
+/*
+ * sun8i_crypto_timeout(cookie)
+ *
+ * Timeout handler. Schedules work in a thread to cancel all
+ * pending tasks that were started long enough ago we're bored of
+ * waiting for them, and reschedules another timeout unless the
+ * channels are all idle.
+ */
static void
sun8i_crypto_timeout(void *cookie)
{
@@ -651,6 +788,13 @@ sun8i_crypto_timeout(void *cookie)
out: mutex_exit(&sc->sc_lock);
}
+/*
+ * sun8i_crypto_intr(cookie)
+ *
+ * Device interrupt handler. Find what channels have completed,
+ * whether with success or with failure, and schedule work in
+ * thread context to invoke the appropriate callbacks.
+ */
static int
sun8i_crypto_intr(void *cookie)
{
@@ -683,6 +827,12 @@ sun8i_crypto_intr(void *cookie)
return __SHIFTOUT(isr, SUN8I_CRYPTO_ISR_DONE) != 0;
}
+/*
+ * sun8i_crypto_schedule_worker(sc)
+ *
+ * Ensure that crypto engine thread context work to invoke task
+ * callbacks will run promptly. Idempotent.
+ */
static void
sun8i_crypto_schedule_worker(struct sun8i_crypto_softc *sc)
{
@@ -696,6 +846,13 @@ sun8i_crypto_schedule_worker(struct sun8
}
}
+/*
+ * sun8i_crypto_worker(wk, cookie)
+ *
+ * Thread-context worker: Invoke all task callbacks for which the
+ * device has notified us of completion or for which we gave up
+ * waiting.
+ */
static void
sun8i_crypto_worker(struct work *wk, void *cookie)
{
@@ -770,10 +927,17 @@ sun8i_crypto_worker(struct work *wk, voi
mutex_exit(&sc->sc_lock);
}
+/*
+ * sun8i_crypto_chan_done(sc, i, error)
+ *
+ * Notify the callback for the task on channel i, if there is one,
+ * of the specified error, or 0 for success.
+ */
static void
sun8i_crypto_chan_done(struct sun8i_crypto_softc *sc, unsigned i, int error)
{
struct sun8i_crypto_task *task;
+ uint32_t nbytes;
uint32_t icr;
KASSERT(mutex_owned(&sc->sc_lock));
@@ -792,10 +956,34 @@ sun8i_crypto_chan_done(struct sun8i_cryp
SUN8I_CRYPTO_ICR_INTR_EN);
sun8i_crypto_write(sc, SUN8I_CRYPTO_ICR, icr);
- /* Finished sending the descriptor to the device by DMA. */
- bus_dmamap_sync(sc->sc_dmat, task->ct_buf.cb_map, 0,
+ /*
+ * Finished sending the descriptor to the device by DMA.
+ * Matches PREWRITE in sun8i_crypto_task_submit.
+ */
+ bus_dmamap_sync(sc->sc_dmat, task->ct_descmap, 0,
sizeof(*task->ct_desc), BUS_DMASYNC_POSTWRITE);
+ /*
+ * Finished with all the other bits of DMA too. Matches
+ * sun8i_crypto_task_load.
+ */
+ nbytes = task->ct_nbytes;
+ bus_dmamap_sync(sc->sc_dmat, task->ct_dstmap, 0, nbytes,
+ BUS_DMASYNC_POSTREAD);
+ if (task->ct_flags & TASK_SRC)
+ bus_dmamap_sync(sc->sc_dmat, task->ct_srcmap, 0, nbytes,
+ 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);
+ 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);
+ if (task->ct_flags & TASK_KEY)
+ /* XXX Can we zero the bounce buffer if there is one? */
+ bus_dmamap_sync(sc->sc_dmat, task->ct_keymap, 0,
+ task->ct_keymap->dm_segs[0].ds_len, BUS_DMASYNC_POSTWRITE);
+
/* Temporarily release the lock to invoke the callback. */
mutex_exit(&sc->sc_lock);
(*task->ct_callback)(sc, task, task->ct_cookie, error);
@@ -803,81 +991,84 @@ sun8i_crypto_chan_done(struct sun8i_cryp
}
/*
- * DMA buffers
+ * sun8i_crypto_allocbuf(sc, size, buf, dmaflags)
+ *
+ * Allocate a single-segment DMA-safe buffer and map it into KVA.
+ * May fail if dmaflags is BUS_DMA_NOWAIT.
*/
-
static int
sun8i_crypto_allocbuf(struct sun8i_crypto_softc *sc, size_t size,
- struct sun8i_crypto_buf *buf)
+ struct sun8i_crypto_buf *buf, int dmaflags)
{
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, BUS_DMA_WAITOK);
+ __arraycount(buf->cb_seg), &buf->cb_nsegs, dmaflags);
if (error)
goto fail0;
/* Map the buffer into kernel virtual address space. */
error = bus_dmamem_map(sc->sc_dmat, buf->cb_seg, buf->cb_nsegs,
- size, &buf->cb_kva, BUS_DMA_WAITOK);
+ size, &buf->cb_kva, dmaflags);
if (error)
goto fail1;
- /* Create a DMA map for the buffer. */
- error = bus_dmamap_create(sc->sc_dmat, size, 1, size, 0,
- BUS_DMA_WAITOK, &buf->cb_map);
- if (error)
- goto fail2;
-
- /* Load the buffer into the DMA map. */
- error = bus_dmamap_load(sc->sc_dmat, buf->cb_map, buf->cb_kva, size,
- NULL, BUS_DMA_WAITOK);
- if (error)
- goto fail3;
-
/* Success! */
return 0;
-fail4: __unused
- bus_dmamap_unload(sc->sc_dmat, buf->cb_map);
-fail3: bus_dmamap_destroy(sc->sc_dmat, buf->cb_map);
-fail2: bus_dmamem_unmap(sc->sc_dmat, buf->cb_kva, size);
+fail2: __unused
+ bus_dmamem_unmap(sc->sc_dmat, buf->cb_kva, size);
fail1: bus_dmamem_free(sc->sc_dmat, buf->cb_seg, buf->cb_nsegs);
fail0: return error;
}
+/*
+ * sun8i_crypto_freebuf(sc, buf)
+ *
+ * Unmap buf and free it.
+ */
static void
sun8i_crypto_freebuf(struct sun8i_crypto_softc *sc, size_t size,
struct sun8i_crypto_buf *buf)
{
- bus_dmamap_unload(sc->sc_dmat, buf->cb_map);
- bus_dmamap_destroy(sc->sc_dmat, buf->cb_map);
bus_dmamem_unmap(sc->sc_dmat, buf->cb_kva, size);
bus_dmamem_free(sc->sc_dmat, buf->cb_seg, buf->cb_nsegs);
}
/*
- * Crypto Engine - TRNG
+ * sun8i_crypto_rng_attach(sc)
+ *
+ * Attach an rndsource for the crypto engine's TRNG.
*/
-
static void
sun8i_crypto_rng_attach(struct sun8i_crypto_softc *sc)
{
device_t self = sc->sc_dev;
struct sun8i_crypto_rng *rng = &sc->sc_rng;
+ struct sun8i_crypto_task *task;
int error;
/* Preallocate a buffer to reuse. */
- error = sun8i_crypto_allocbuf(sc, SUN8I_CRYPTO_RNGBYTES, &rng->cr_buf);
+ error = sun8i_crypto_allocbuf(sc, SUN8I_CRYPTO_RNGBYTES, &rng->cr_buf,
+ BUS_DMA_WAITOK);
if (error)
goto fail0;
/* Create a task to reuse. */
- rng->cr_task = sun8i_crypto_task_get(sc, sun8i_crypto_rng_done, rng);
- if (rng->cr_task == NULL)
+ task = rng->cr_task = sun8i_crypto_task_get(sc, sun8i_crypto_rng_done,
+ rng, PR_WAITOK);
+ if (rng->cr_task == NULL) {
+ error = ENOMEM;
goto fail1;
+ }
+
+ /* 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)
+ goto fail2;
/*
* Attach the rndsource. This is _not_ marked as RND_TYPE_RNG
@@ -893,17 +1084,25 @@ sun8i_crypto_rng_attach(struct sun8i_cry
/* Success! */
return;
-fail2: __unused
- sun8i_crypto_task_put(sc, rng->cr_task);
+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);
}
+/*
+ * sun8i_crypto_rng_get(nbytes, cookie)
+ *
+ * On-demand rndsource callback: try to gather nbytes of entropy
+ * and enter them into the pool ASAP.
+ */
static void
sun8i_crypto_rng_get(size_t nbytes, void *cookie)
{
struct sun8i_crypto_softc *sc = cookie;
struct sun8i_crypto_rng *rng = &sc->sc_rng;
+ struct sun8i_crypto_task *task = rng->cr_task;
bool pending;
int error;
@@ -918,17 +1117,13 @@ sun8i_crypto_rng_get(size_t nbytes, void
if (pending)
return;
- /* Prepare for a DMA read into the buffer. */
- bus_dmamap_sync(sc->sc_dmat, rng->cr_buf.cb_map,
- 0, SUN8I_CRYPTO_RNGBYTES, BUS_DMASYNC_PREREAD);
-
- /* Set the task up for TRNG to our buffer. */
- sun8i_crypto_task_reset(rng->cr_task);
- sun8i_crypto_task_set_output(rng->cr_task, rng->cr_buf.cb_map);
+ /* Load the task descriptor. */
+ error = sun8i_crypto_task_load_trng(sc, task, SUN8I_CRYPTO_RNGBYTES);
+ if (error)
+ goto fail;
- /* Submit the TRNG task. */
- error = sun8i_crypto_submit_trng(sc, rng->cr_task,
- SUN8I_CRYPTO_RNGBYTES);
+ /* Submit! */
+ error = sun8i_crypto_submit(sc, task);
if (error)
goto fail;
@@ -950,10 +1145,6 @@ sun8i_crypto_rng_done(struct sun8i_crypt
KASSERT(rng == &sc->sc_rng);
- /* Finished the DMA read into the buffer. */
- bus_dmamap_sync(sc->sc_dmat, rng->cr_buf.cb_map,
- 0, SUN8I_CRYPTO_RNGBYTES, BUS_DMASYNC_POSTREAD);
-
/* If anything went wrong, forget about it. */
if (error)
goto out;
@@ -1001,73 +1192,84 @@ static const uint8_t selftest_output[16]
static void
sun8i_crypto_selftest(device_t self)
{
- const size_t datalen = sizeof selftest_input;
+ const size_t keybytes = sizeof selftest_key;
+ const size_t nbytes = sizeof selftest_input;
struct sun8i_crypto_softc *sc = device_private(self);
struct sun8i_crypto_selftest *selftest = &sc->sc_selftest;
+ struct sun8i_crypto_task *task;
int error;
CTASSERT(sizeof selftest_input == sizeof selftest_output);
/* Allocate an input buffer. */
- error = sun8i_crypto_allocbuf(sc, sizeof selftest_input,
- &selftest->cs_in);
+ error = sun8i_crypto_allocbuf(sc, nbytes, &selftest->cs_in,
+ BUS_DMA_WAITOK);
if (error)
goto fail0;
/* Allocate a key buffer. */
- error = sun8i_crypto_allocbuf(sc, sizeof selftest_key,
- &selftest->cs_key);
+ error = sun8i_crypto_allocbuf(sc, keybytes, &selftest->cs_key,
+ BUS_DMA_WAITOK);
if (error)
goto fail1;
/* Allocate an output buffer. */
- error = sun8i_crypto_allocbuf(sc, sizeof selftest_output,
- &selftest->cs_out);
+ error = sun8i_crypto_allocbuf(sc, nbytes, &selftest->cs_out,
+ BUS_DMA_WAITOK);
if (error)
goto fail2;
/* Allocate a task descriptor. */
- selftest->cs_task = sun8i_crypto_task_get(sc,
- sun8i_crypto_selftest_done, selftest);
- if (selftest->cs_task == NULL)
+ task = selftest->cs_task = sun8i_crypto_task_get(sc,
+ sun8i_crypto_selftest_done, selftest, PR_WAITOK);
+ if (selftest->cs_task == NULL) {
+ error = ENOMEM;
goto fail3;
+ }
/* Copy the input and key into their buffers. */
- memcpy(selftest->cs_in.cb_kva, selftest_input, sizeof selftest_input);
- memcpy(selftest->cs_key.cb_kva, selftest_key, sizeof selftest_key);
+ memcpy(selftest->cs_in.cb_kva, selftest_input, nbytes);
+ memcpy(selftest->cs_key.cb_kva, selftest_key, keybytes);
- /* Prepare for a DMA write from the input and key buffers. */
- bus_dmamap_sync(sc->sc_dmat, selftest->cs_in.cb_map, 0,
- sizeof selftest_input, BUS_DMASYNC_PREWRITE);
- bus_dmamap_sync(sc->sc_dmat, selftest->cs_key.cb_map, 0,
- sizeof selftest_key, BUS_DMASYNC_PREWRITE);
-
- /* Prepare for a DMA read into the output buffer. */
- bus_dmamap_sync(sc->sc_dmat, selftest->cs_out.cb_map, 0,
- sizeof selftest_output, BUS_DMASYNC_PREREAD);
+ /* Load the key, src, and dst for DMA transfers. */
+ error = bus_dmamap_load(sc->sc_dmat, task->ct_keymap,
+ selftest->cs_key.cb_kva, keybytes, NULL, BUS_DMA_WAITOK);
+ if (error)
+ goto fail4;
+ task->ct_flags |= TASK_KEY;
- /* Set up the task descriptor. */
- sun8i_crypto_task_reset(selftest->cs_task);
- sun8i_crypto_task_set_key(selftest->cs_task, selftest->cs_key.cb_map);
- sun8i_crypto_task_set_input(selftest->cs_task, selftest->cs_in.cb_map);
- sun8i_crypto_task_set_output(selftest->cs_task,
- selftest->cs_out.cb_map);
+ error = bus_dmamap_load(sc->sc_dmat, task->ct_srcmap,
+ selftest->cs_in.cb_kva, nbytes, NULL, BUS_DMA_WAITOK);
+ if (error)
+ goto fail5;
+ task->ct_flags |= TASK_SRC;
- /* Submit the AES-128 ECB task. */
- error = sun8i_crypto_submit_aesecb(sc, selftest->cs_task, datalen,
+ error = bus_dmamap_load(sc->sc_dmat, task->ct_dstmap,
+ selftest->cs_out.cb_kva, nbytes, NULL, BUS_DMA_WAITOK);
+ if (error)
+ goto fail6;
+
+ /* Set up the task descriptor. */
+ sun8i_crypto_task_load_aesecb(sc, task, nbytes,
SUN8I_CRYPTO_TDQS_AES_KEYSIZE_128, SUN8I_CRYPTO_TDQC_OP_DIR_ENC);
+
+ /* Submit! */
+ error = sun8i_crypto_submit(sc, task);
if (error)
- goto fail4;
+ goto fail7;
device_printf(sc->sc_dev, "AES-128 self-test initiated\n");
/* Success! */
return;
-fail4: sun8i_crypto_task_put(sc, selftest->cs_task);
-fail3: sun8i_crypto_freebuf(sc, sizeof selftest_output, &selftest->cs_out);
-fail2: sun8i_crypto_freebuf(sc, sizeof selftest_key, &selftest->cs_key);
-fail1: sun8i_crypto_freebuf(sc, sizeof selftest_input, &selftest->cs_in);
+fail7: bus_dmamap_unload(sc->sc_dmat, task->ct_dstmap);
+fail6: bus_dmamap_unload(sc->sc_dmat, task->ct_srcmap);
+fail5: bus_dmamap_unload(sc->sc_dmat, task->ct_keymap);
+fail4: sun8i_crypto_task_put(sc, task);
+fail3: sun8i_crypto_freebuf(sc, nbytes, &selftest->cs_out);
+fail2: sun8i_crypto_freebuf(sc, keybytes, &selftest->cs_key);
+fail1: sun8i_crypto_freebuf(sc, nbytes, &selftest->cs_in);
fail0: aprint_error_dev(self, "failed to run self-test, error=%d\n", error);
}
@@ -1098,22 +1300,13 @@ static void
sun8i_crypto_selftest_done(struct sun8i_crypto_softc *sc,
struct sun8i_crypto_task *task, void *cookie, int error)
{
+ const size_t keybytes = sizeof selftest_key;
+ const size_t nbytes = sizeof selftest_input;
struct sun8i_crypto_selftest *selftest = cookie;
bool ok = true;
KASSERT(selftest == &sc->sc_selftest);
- /*
- * Finished the DMA read into the output buffer, and finished
- * the DMA writes from the key buffer and input buffer.
- */
- bus_dmamap_sync(sc->sc_dmat, selftest->cs_out.cb_map, 0,
- sizeof selftest_output, BUS_DMASYNC_POSTREAD);
- bus_dmamap_sync(sc->sc_dmat, selftest->cs_key.cb_map, 0,
- sizeof selftest_key, BUS_DMASYNC_POSTWRITE);
- bus_dmamap_sync(sc->sc_dmat, selftest->cs_in.cb_map, 0,
- sizeof selftest_input, BUS_DMASYNC_POSTWRITE);
-
/* If anything went wrong, fail now. */
if (error) {
device_printf(sc->sc_dev, "self-test error=%d\n", error);
@@ -1124,21 +1317,24 @@ sun8i_crypto_selftest_done(struct sun8i_
* Verify the input and key weren't clobbered, and verify the
* output matches what we expect.
*/
- ok &= sun8i_crypto_selftest_check(sc, "input clobbered",
- sizeof selftest_input, selftest_input, selftest->cs_in.cb_kva);
- ok &= sun8i_crypto_selftest_check(sc, "key clobbered",
- sizeof selftest_key, selftest_key, selftest->cs_key.cb_kva);
- ok &= sun8i_crypto_selftest_check(sc, "output mismatch",
- sizeof selftest_output, selftest_output, selftest->cs_out.cb_kva);
+ ok &= sun8i_crypto_selftest_check(sc, "input clobbered", nbytes,
+ selftest_input, selftest->cs_in.cb_kva);
+ ok &= sun8i_crypto_selftest_check(sc, "key clobbered", keybytes,
+ selftest_key, selftest->cs_key.cb_kva);
+ ok &= sun8i_crypto_selftest_check(sc, "output mismatch", nbytes,
+ selftest_output, selftest->cs_out.cb_kva);
/* XXX Disable the RNG and other stuff if this fails... */
if (ok)
device_printf(sc->sc_dev, "AES-128 self-test passed\n");
-out: sun8i_crypto_task_put(sc, task);
- sun8i_crypto_freebuf(sc, sizeof selftest_output, &selftest->cs_out);
- sun8i_crypto_freebuf(sc, sizeof selftest_key, &selftest->cs_key);
- sun8i_crypto_freebuf(sc, sizeof selftest_input, &selftest->cs_in);
+out: bus_dmamap_unload(sc->sc_dmat, task->ct_dstmap);
+ bus_dmamap_unload(sc->sc_dmat, task->ct_srcmap);
+ bus_dmamap_unload(sc->sc_dmat, task->ct_keymap);
+ sun8i_crypto_task_put(sc, task);
+ sun8i_crypto_freebuf(sc, nbytes, &selftest->cs_out);
+ sun8i_crypto_freebuf(sc, keybytes, &selftest->cs_key);
+ sun8i_crypto_freebuf(sc, nbytes, &selftest->cs_in);
}
/*
@@ -1194,6 +1390,7 @@ sun8i_crypto_sysctl_rng(SYSCTLFN_ARGS)
struct sysctlnode node = *rnode;
struct sun8i_crypto_softc *sc = node.sysctl_data;
struct sun8i_crypto_userreq *req;
+ struct sun8i_crypto_task *task;
size_t size;
int error;
@@ -1222,30 +1419,34 @@ sun8i_crypto_sysctl_rng(SYSCTLFN_ARGS)
req->cu_cancel = false;
/* Allocate a buffer for the RNG output. */
- error = sun8i_crypto_allocbuf(sc, size, &req->cu_buf);
+ error = sun8i_crypto_allocbuf(sc, size, &req->cu_buf, BUS_DMA_NOWAIT);
if (error)
goto out0;
/* Allocate a task. */
- req->cu_task = sun8i_crypto_task_get(sc, sun8i_crypto_sysctl_rng_done,
- req);
- if (req->cu_task == NULL)
+ task = req->cu_task = sun8i_crypto_task_get(sc,
+ sun8i_crypto_sysctl_rng_done, req, PR_NOWAIT);
+ if (task == NULL) {
+ error = ENOMEM;
goto out1;
-
- /* Prepare for a DMA read into the buffer. */
- bus_dmamap_sync(sc->sc_dmat, req->cu_buf.cb_map, 0, size,
- BUS_DMASYNC_PREREAD);
+ }
/* Set the task up for TRNG to our buffer. */
- sun8i_crypto_task_reset(req->cu_task);
- sun8i_crypto_task_set_output(req->cu_task, req->cu_buf.cb_map);
+ error = bus_dmamap_load(sc->sc_dmat, task->ct_dstmap,
+ req->cu_buf.cb_kva, SUN8I_CRYPTO_RNGBYTES, NULL, BUS_DMA_NOWAIT);
+ if (error)
+ goto out2;
+ error = sun8i_crypto_task_load_trng(sc, task, SUN8I_CRYPTO_RNGBYTES);
+ if (error)
+ goto out3;
- /* Submit the TRNG task. */
- error = sun8i_crypto_submit_trng(sc, req->cu_task, size);
+ /* Submit! */
+ error = sun8i_crypto_submit(sc, task);
if (error) {
+ /* Make sure we don't restart the syscall -- just fail. */
if (error == ERESTART)
error = EBUSY;
- goto out2;
+ goto out3;
}
/* Wait for the request to complete. */
@@ -1278,11 +1479,7 @@ sun8i_crypto_sysctl_rng(SYSCTLFN_ARGS)
/* Check for error from the device. */
error = req->cu_error;
if (error)
- goto out2;
-
- /* Finished the DMA read into the buffer. */
- bus_dmamap_sync(sc->sc_dmat, req->cu_buf.cb_map, 0, req->cu_size,
- BUS_DMASYNC_POSTREAD);
+ goto out3;
/* Copy out the data. */
node.sysctl_data = req->cu_buf.cb_kva;
@@ -1293,7 +1490,8 @@ sun8i_crypto_sysctl_rng(SYSCTLFN_ARGS)
explicit_memset(req->cu_buf.cb_kva, 0, size);
/* Clean up. */
-out2: sun8i_crypto_task_put(sc, req->cu_task);
+out3: bus_dmamap_unload(sc->sc_dmat, task->ct_dstmap);
+out2: sun8i_crypto_task_put(sc, task);
out1: sun8i_crypto_freebuf(sc, req->cu_size, &req->cu_buf);
out0: cv_destroy(&req->cu_cv);
mutex_destroy(&req->cu_lock);
@@ -1327,7 +1525,8 @@ sun8i_crypto_sysctl_rng_done(struct sun8
return;
/* Clean up after the main thread cancelled. */
- sun8i_crypto_task_put(sc, req->cu_task);
+ bus_dmamap_unload(sc->sc_dmat, task->ct_dstmap);
+ sun8i_crypto_task_put(sc, task);
sun8i_crypto_freebuf(sc, req->cu_size, &req->cu_buf);
cv_destroy(&req->cu_cv);
mutex_destroy(&req->cu_lock);
Index: src/sys/arch/arm/sunxi/sun8i_crypto.h
diff -u src/sys/arch/arm/sunxi/sun8i_crypto.h:1.1 src/sys/arch/arm/sunxi/sun8i_crypto.h:1.2
--- src/sys/arch/arm/sunxi/sun8i_crypto.h:1.1 Mon Dec 9 04:51:03 2019
+++ src/sys/arch/arm/sunxi/sun8i_crypto.h Sat Jun 13 18:57:54 2020
@@ -1,4 +1,4 @@
-/* $NetBSD: sun8i_crypto.h,v 1.1 2019/12/09 04:51:03 riastradh Exp $ */
+/* $NetBSD: sun8i_crypto.h,v 1.2 2020/06/13 18:57:54 riastradh Exp $ */
/*-
* Copyright (c) 2019 The NetBSD Foundation, Inc.
@@ -125,9 +125,20 @@
#define SUN8I_CRYPTO_ESR_CHAN_DATALENERR __BIT(1)
#define SUN8I_CRYPTO_ESR_CHAN_KEYSRAMERR __BIT(2)
+#define SUN8I_CRYPTO_MAXKEYBYTES 256 /* e.g. 2048-bit RSA */
+#define SUN8I_CRYPTO_MAXIVBYTES 64 /* e.g. SHA-512 */
+#define SUN8I_CRYPTO_MAXCTRBYTES 16 /* e.g. AES */
+
+/*
+ * Eight src segments and eight dst segments per task. The datalen
+ * field, measured either in bytes or words, is 32 bits. Each segment
+ * length is measured in words and is also 32 bits. We never do very
+ * long transfers anyway so rounding the maximum size down to 2^32 - 1
+ * is not a real limitation.
+ */
#define SUN8I_CRYPTO_MAXSEGS 8
-#define SUN8I_CRYPTO_MAXSEGSIZE UINT32_MAX
-#define SUN8I_CRYPTO_MAXSIZE UINT32_MAX /* datalen */
+#define SUN8I_CRYPTO_MAXSEGLEN UINT32_MAX
+#define SUN8I_CRYPTO_MAXDATALEN UINT32_MAX
struct sun8i_crypto_taskdesc {
uint32_t td_cid; /* task channel id */