xref: /freebsd/sys/dev/safexcel/safexcel.c (revision 5bdb8b273aaf6aa1bf089071ce6d5c9e80657c52)
1b356ddf0SMark Johnston /*-
2b356ddf0SMark Johnston  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3b356ddf0SMark Johnston  *
4*5bdb8b27SMark Johnston  * Copyright (c) 2020, 2021 Rubicon Communications, LLC (Netgate)
5b356ddf0SMark Johnston  *
6b356ddf0SMark Johnston  * Redistribution and use in source and binary forms, with or without
7b356ddf0SMark Johnston  * modification, are permitted provided that the following conditions
8b356ddf0SMark Johnston  * are met:
9b356ddf0SMark Johnston  * 1. Redistributions of source code must retain the above copyright
10b356ddf0SMark Johnston  *    notice, this list of conditions and the following disclaimer.
11b356ddf0SMark Johnston  * 2. Redistributions in binary form must reproduce the above copyright
12b356ddf0SMark Johnston  *    notice, this list of conditions and the following disclaimer in the
13b356ddf0SMark Johnston  *    documentation and/or other materials provided with the distribution.
14b356ddf0SMark Johnston  *
15b356ddf0SMark Johnston  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16b356ddf0SMark Johnston  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17b356ddf0SMark Johnston  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18b356ddf0SMark Johnston  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19b356ddf0SMark Johnston  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20b356ddf0SMark Johnston  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21b356ddf0SMark Johnston  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22b356ddf0SMark Johnston  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23b356ddf0SMark Johnston  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24b356ddf0SMark Johnston  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25b356ddf0SMark Johnston  */
26b356ddf0SMark Johnston 
27b356ddf0SMark Johnston #include <sys/cdefs.h>
28b356ddf0SMark Johnston __FBSDID("$FreeBSD$");
29b356ddf0SMark Johnston 
30b356ddf0SMark Johnston #include <sys/param.h>
31b356ddf0SMark Johnston #include <sys/bus.h>
320371c3faSMark Johnston #include <sys/counter.h>
33b356ddf0SMark Johnston #include <sys/endian.h>
34b356ddf0SMark Johnston #include <sys/kernel.h>
35b356ddf0SMark Johnston #include <sys/lock.h>
36b356ddf0SMark Johnston #include <sys/malloc.h>
37b356ddf0SMark Johnston #include <sys/module.h>
38b356ddf0SMark Johnston #include <sys/mutex.h>
39b356ddf0SMark Johnston #include <sys/rman.h>
40e934d455SMark Johnston #include <sys/smp.h>
41b356ddf0SMark Johnston #include <sys/sglist.h>
42b356ddf0SMark Johnston #include <sys/sysctl.h>
43b356ddf0SMark Johnston 
44b356ddf0SMark Johnston #include <machine/atomic.h>
45b356ddf0SMark Johnston #include <machine/bus.h>
46b356ddf0SMark Johnston 
47b356ddf0SMark Johnston #include <crypto/rijndael/rijndael.h>
48b356ddf0SMark Johnston #include <opencrypto/cryptodev.h>
49b356ddf0SMark Johnston #include <opencrypto/xform.h>
50b356ddf0SMark Johnston 
51b356ddf0SMark Johnston #include <dev/ofw/ofw_bus.h>
52b356ddf0SMark Johnston #include <dev/ofw/ofw_bus_subr.h>
53b356ddf0SMark Johnston 
54b356ddf0SMark Johnston #include "cryptodev_if.h"
55b356ddf0SMark Johnston 
56b356ddf0SMark Johnston #include "safexcel_reg.h"
57b356ddf0SMark Johnston #include "safexcel_var.h"
58b356ddf0SMark Johnston 
59b356ddf0SMark Johnston /*
60b356ddf0SMark Johnston  * We only support the EIP97 for now.
61b356ddf0SMark Johnston  */
62b356ddf0SMark Johnston static struct ofw_compat_data safexcel_compat[] = {
63b356ddf0SMark Johnston 	{ "inside-secure,safexcel-eip97ies",	(uintptr_t)97 },
64b356ddf0SMark Johnston 	{ "inside-secure,safexcel-eip97",	(uintptr_t)97 },
65b356ddf0SMark Johnston 	{ NULL,					0 }
66b356ddf0SMark Johnston };
67b356ddf0SMark Johnston 
68b356ddf0SMark Johnston const struct safexcel_reg_offsets eip97_regs_offset = {
69b356ddf0SMark Johnston 	.hia_aic	= SAFEXCEL_EIP97_HIA_AIC_BASE,
70b356ddf0SMark Johnston 	.hia_aic_g	= SAFEXCEL_EIP97_HIA_AIC_G_BASE,
71b356ddf0SMark Johnston 	.hia_aic_r	= SAFEXCEL_EIP97_HIA_AIC_R_BASE,
72b356ddf0SMark Johnston 	.hia_aic_xdr	= SAFEXCEL_EIP97_HIA_AIC_xDR_BASE,
73b356ddf0SMark Johnston 	.hia_dfe	= SAFEXCEL_EIP97_HIA_DFE_BASE,
74b356ddf0SMark Johnston 	.hia_dfe_thr	= SAFEXCEL_EIP97_HIA_DFE_THR_BASE,
75b356ddf0SMark Johnston 	.hia_dse	= SAFEXCEL_EIP97_HIA_DSE_BASE,
76b356ddf0SMark Johnston 	.hia_dse_thr	= SAFEXCEL_EIP97_HIA_DSE_THR_BASE,
77b356ddf0SMark Johnston 	.hia_gen_cfg	= SAFEXCEL_EIP97_HIA_GEN_CFG_BASE,
78b356ddf0SMark Johnston 	.pe		= SAFEXCEL_EIP97_PE_BASE,
79b356ddf0SMark Johnston };
80b356ddf0SMark Johnston 
81b356ddf0SMark Johnston const struct safexcel_reg_offsets eip197_regs_offset = {
82b356ddf0SMark Johnston 	.hia_aic	= SAFEXCEL_EIP197_HIA_AIC_BASE,
83b356ddf0SMark Johnston 	.hia_aic_g	= SAFEXCEL_EIP197_HIA_AIC_G_BASE,
84b356ddf0SMark Johnston 	.hia_aic_r	= SAFEXCEL_EIP197_HIA_AIC_R_BASE,
85b356ddf0SMark Johnston 	.hia_aic_xdr	= SAFEXCEL_EIP197_HIA_AIC_xDR_BASE,
86b356ddf0SMark Johnston 	.hia_dfe	= SAFEXCEL_EIP197_HIA_DFE_BASE,
87b356ddf0SMark Johnston 	.hia_dfe_thr	= SAFEXCEL_EIP197_HIA_DFE_THR_BASE,
88b356ddf0SMark Johnston 	.hia_dse	= SAFEXCEL_EIP197_HIA_DSE_BASE,
89b356ddf0SMark Johnston 	.hia_dse_thr	= SAFEXCEL_EIP197_HIA_DSE_THR_BASE,
90b356ddf0SMark Johnston 	.hia_gen_cfg	= SAFEXCEL_EIP197_HIA_GEN_CFG_BASE,
91b356ddf0SMark Johnston 	.pe		= SAFEXCEL_EIP197_PE_BASE,
92b356ddf0SMark Johnston };
93b356ddf0SMark Johnston 
941a6ffed5SMark Johnston static struct safexcel_request *
951a6ffed5SMark Johnston safexcel_next_request(struct safexcel_ring *ring)
961a6ffed5SMark Johnston {
971a6ffed5SMark Johnston 	int i;
981a6ffed5SMark Johnston 
991a6ffed5SMark Johnston 	i = ring->cdr.read;
1001a6ffed5SMark Johnston 	KASSERT(i >= 0 && i < SAFEXCEL_RING_SIZE,
1011a6ffed5SMark Johnston 	    ("%s: out of bounds request index %d", __func__, i));
1021a6ffed5SMark Johnston 	return (&ring->requests[i]);
1031a6ffed5SMark Johnston }
1041a6ffed5SMark Johnston 
105b356ddf0SMark Johnston static struct safexcel_cmd_descr *
106b356ddf0SMark Johnston safexcel_cmd_descr_next(struct safexcel_cmd_descr_ring *ring)
107b356ddf0SMark Johnston {
108b356ddf0SMark Johnston 	struct safexcel_cmd_descr *cdesc;
109b356ddf0SMark Johnston 
110b356ddf0SMark Johnston 	if (ring->write == ring->read)
111b356ddf0SMark Johnston 		return (NULL);
112b356ddf0SMark Johnston 	cdesc = &ring->desc[ring->read];
113b356ddf0SMark Johnston 	ring->read = (ring->read + 1) % SAFEXCEL_RING_SIZE;
114b356ddf0SMark Johnston 	return (cdesc);
115b356ddf0SMark Johnston }
116b356ddf0SMark Johnston 
117b356ddf0SMark Johnston static struct safexcel_res_descr *
118b356ddf0SMark Johnston safexcel_res_descr_next(struct safexcel_res_descr_ring *ring)
119b356ddf0SMark Johnston {
120b356ddf0SMark Johnston 	struct safexcel_res_descr *rdesc;
121b356ddf0SMark Johnston 
122b356ddf0SMark Johnston 	if (ring->write == ring->read)
123b356ddf0SMark Johnston 		return (NULL);
124b356ddf0SMark Johnston 	rdesc = &ring->desc[ring->read];
125b356ddf0SMark Johnston 	ring->read = (ring->read + 1) % SAFEXCEL_RING_SIZE;
126b356ddf0SMark Johnston 	return (rdesc);
127b356ddf0SMark Johnston }
128b356ddf0SMark Johnston 
129b356ddf0SMark Johnston static struct safexcel_request *
130b356ddf0SMark Johnston safexcel_alloc_request(struct safexcel_softc *sc, struct safexcel_ring *ring)
131b356ddf0SMark Johnston {
1321a6ffed5SMark Johnston 	int i;
133b356ddf0SMark Johnston 
134b356ddf0SMark Johnston 	mtx_assert(&ring->mtx, MA_OWNED);
135b356ddf0SMark Johnston 
1361a6ffed5SMark Johnston 	i = ring->cdr.write;
1371a6ffed5SMark Johnston 	if ((i + 1) % SAFEXCEL_RING_SIZE == ring->cdr.read)
1381a6ffed5SMark Johnston 		return (NULL);
1391a6ffed5SMark Johnston 	return (&ring->requests[i]);
140b356ddf0SMark Johnston }
141b356ddf0SMark Johnston 
142b356ddf0SMark Johnston static void
143b356ddf0SMark Johnston safexcel_free_request(struct safexcel_ring *ring, struct safexcel_request *req)
144b356ddf0SMark Johnston {
145b356ddf0SMark Johnston 	struct safexcel_context_record *ctx;
146b356ddf0SMark Johnston 
147b356ddf0SMark Johnston 	mtx_assert(&ring->mtx, MA_OWNED);
148b356ddf0SMark Johnston 
149b356ddf0SMark Johnston 	if (req->dmap_loaded) {
150b356ddf0SMark Johnston 		bus_dmamap_unload(ring->data_dtag, req->dmap);
151b356ddf0SMark Johnston 		req->dmap_loaded = false;
152b356ddf0SMark Johnston 	}
153b356ddf0SMark Johnston 	ctx = (struct safexcel_context_record *)req->ctx.vaddr;
154b356ddf0SMark Johnston 	explicit_bzero(ctx->data, sizeof(ctx->data));
155b356ddf0SMark Johnston 	explicit_bzero(req->iv, sizeof(req->iv));
156b356ddf0SMark Johnston }
157b356ddf0SMark Johnston 
158b356ddf0SMark Johnston static void
159b356ddf0SMark Johnston safexcel_rdr_intr(struct safexcel_softc *sc, int ringidx)
160b356ddf0SMark Johnston {
1611a6ffed5SMark Johnston 	TAILQ_HEAD(, cryptop) cq;
1621a6ffed5SMark Johnston 	struct cryptop *crp, *tmp;
163b356ddf0SMark Johnston 	struct safexcel_cmd_descr *cdesc;
164b356ddf0SMark Johnston 	struct safexcel_res_descr *rdesc;
165b356ddf0SMark Johnston 	struct safexcel_request *req;
166b356ddf0SMark Johnston 	struct safexcel_ring *ring;
167092cf8d6SMark Johnston 	uint32_t blocked, error, i, ncdescs, nrdescs, nreqs;
168b356ddf0SMark Johnston 
169092cf8d6SMark Johnston 	blocked = 0;
170b356ddf0SMark Johnston 	ring = &sc->sc_ring[ringidx];
171b356ddf0SMark Johnston 
172b356ddf0SMark Johnston 	nreqs = SAFEXCEL_READ(sc,
173b356ddf0SMark Johnston 	    SAFEXCEL_HIA_RDR(sc, ringidx) + SAFEXCEL_HIA_xDR_PROC_COUNT);
174b356ddf0SMark Johnston 	nreqs >>= SAFEXCEL_xDR_PROC_xD_PKT_OFFSET;
175b356ddf0SMark Johnston 	nreqs &= SAFEXCEL_xDR_PROC_xD_PKT_MASK;
176b356ddf0SMark Johnston 	if (nreqs == 0) {
177b356ddf0SMark Johnston 		SAFEXCEL_DPRINTF(sc, 1,
178b356ddf0SMark Johnston 		    "zero pending requests on ring %d\n", ringidx);
1791a6ffed5SMark Johnston 		mtx_lock(&ring->mtx);
180b356ddf0SMark Johnston 		goto out;
181b356ddf0SMark Johnston 	}
182b356ddf0SMark Johnston 
1831a6ffed5SMark Johnston 	TAILQ_INIT(&cq);
1841a6ffed5SMark Johnston 
185b356ddf0SMark Johnston 	ring = &sc->sc_ring[ringidx];
186b356ddf0SMark Johnston 	bus_dmamap_sync(ring->rdr.dma.tag, ring->rdr.dma.map,
187b356ddf0SMark Johnston 	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
188b356ddf0SMark Johnston 	bus_dmamap_sync(ring->cdr.dma.tag, ring->cdr.dma.map,
189b356ddf0SMark Johnston 	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
190b356ddf0SMark Johnston 	bus_dmamap_sync(ring->dma_atok.tag, ring->dma_atok.map,
191b356ddf0SMark Johnston 	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
192b356ddf0SMark Johnston 
193b356ddf0SMark Johnston 	ncdescs = nrdescs = 0;
194b356ddf0SMark Johnston 	for (i = 0; i < nreqs; i++) {
1951a6ffed5SMark Johnston 		req = safexcel_next_request(ring);
196b356ddf0SMark Johnston 
197b356ddf0SMark Johnston 		bus_dmamap_sync(req->ctx.tag, req->ctx.map,
198b356ddf0SMark Johnston 		    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
199b356ddf0SMark Johnston 		bus_dmamap_sync(ring->data_dtag, req->dmap,
200b356ddf0SMark Johnston 		    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
201b356ddf0SMark Johnston 
202b356ddf0SMark Johnston 		ncdescs += req->cdescs;
203b356ddf0SMark Johnston 		while (req->cdescs-- > 0) {
204b356ddf0SMark Johnston 			cdesc = safexcel_cmd_descr_next(&ring->cdr);
205b356ddf0SMark Johnston 			KASSERT(cdesc != NULL,
206b356ddf0SMark Johnston 			    ("%s: missing control descriptor", __func__));
207b356ddf0SMark Johnston 			if (req->cdescs == 0)
208b356ddf0SMark Johnston 				KASSERT(cdesc->last_seg,
209b356ddf0SMark Johnston 				    ("%s: chain is not terminated", __func__));
210b356ddf0SMark Johnston 		}
211b356ddf0SMark Johnston 		nrdescs += req->rdescs;
212b356ddf0SMark Johnston 		while (req->rdescs-- > 0) {
213b356ddf0SMark Johnston 			rdesc = safexcel_res_descr_next(&ring->rdr);
214b356ddf0SMark Johnston 			error = rdesc->result_data.error_code;
215b356ddf0SMark Johnston 			if (error != 0) {
216b356ddf0SMark Johnston 				if (error == SAFEXCEL_RESULT_ERR_AUTH_FAILED &&
217b356ddf0SMark Johnston 				    req->crp->crp_etype == 0) {
218b356ddf0SMark Johnston 					req->crp->crp_etype = EBADMSG;
219b356ddf0SMark Johnston 				} else {
220b356ddf0SMark Johnston 					SAFEXCEL_DPRINTF(sc, 1,
221b356ddf0SMark Johnston 					    "error code %#x\n", error);
222b356ddf0SMark Johnston 					req->crp->crp_etype = EIO;
223b356ddf0SMark Johnston 				}
224b356ddf0SMark Johnston 			}
225b356ddf0SMark Johnston 		}
226b356ddf0SMark Johnston 
2271a6ffed5SMark Johnston 		TAILQ_INSERT_TAIL(&cq, req->crp, crp_next);
228b356ddf0SMark Johnston 	}
229b356ddf0SMark Johnston 
2301a6ffed5SMark Johnston 	mtx_lock(&ring->mtx);
231b356ddf0SMark Johnston 	if (nreqs != 0) {
2321a6ffed5SMark Johnston 		KASSERT(ring->queued >= nreqs,
2331a6ffed5SMark Johnston 		    ("%s: request count underflow, %d queued %d completed",
2341a6ffed5SMark Johnston 		    __func__, ring->queued, nreqs));
2351a6ffed5SMark Johnston 		ring->queued -= nreqs;
2361a6ffed5SMark Johnston 
237b356ddf0SMark Johnston 		SAFEXCEL_WRITE(sc,
238b356ddf0SMark Johnston 		    SAFEXCEL_HIA_RDR(sc, ringidx) + SAFEXCEL_HIA_xDR_PROC_COUNT,
239b356ddf0SMark Johnston 		    SAFEXCEL_xDR_PROC_xD_PKT(nreqs) |
240b356ddf0SMark Johnston 		    (sc->sc_config.rd_offset * nrdescs * sizeof(uint32_t)));
241092cf8d6SMark Johnston 		blocked = ring->blocked;
242092cf8d6SMark Johnston 		ring->blocked = 0;
243b356ddf0SMark Johnston 	}
244b356ddf0SMark Johnston out:
2451a6ffed5SMark Johnston 	if (ring->queued != 0) {
246b356ddf0SMark Johnston 		SAFEXCEL_WRITE(sc,
247b356ddf0SMark Johnston 		    SAFEXCEL_HIA_RDR(sc, ringidx) + SAFEXCEL_HIA_xDR_THRESH,
2481a6ffed5SMark Johnston 		    SAFEXCEL_HIA_CDR_THRESH_PKT_MODE | imin(ring->queued, 16));
249b356ddf0SMark Johnston 	}
250b356ddf0SMark Johnston 	mtx_unlock(&ring->mtx);
251092cf8d6SMark Johnston 
252092cf8d6SMark Johnston 	if (blocked)
253092cf8d6SMark Johnston 		crypto_unblock(sc->sc_cid, blocked);
2541a6ffed5SMark Johnston 
2551a6ffed5SMark Johnston 	TAILQ_FOREACH_SAFE(crp, &cq, crp_next, tmp)
2561a6ffed5SMark Johnston 		crypto_done(crp);
257b356ddf0SMark Johnston }
258b356ddf0SMark Johnston 
259b356ddf0SMark Johnston static void
260b356ddf0SMark Johnston safexcel_ring_intr(void *arg)
261b356ddf0SMark Johnston {
262b356ddf0SMark Johnston 	struct safexcel_softc *sc;
263b356ddf0SMark Johnston 	struct safexcel_intr_handle *ih;
264b356ddf0SMark Johnston 	uint32_t status, stat;
265b356ddf0SMark Johnston 	int ring;
266092cf8d6SMark Johnston 	bool rdrpending;
267b356ddf0SMark Johnston 
268b356ddf0SMark Johnston 	ih = arg;
269b356ddf0SMark Johnston 	sc = ih->sc;
270b356ddf0SMark Johnston 	ring = ih->ring;
271b356ddf0SMark Johnston 
272b356ddf0SMark Johnston 	status = SAFEXCEL_READ(sc, SAFEXCEL_HIA_AIC_R(sc) +
273b356ddf0SMark Johnston 	    SAFEXCEL_HIA_AIC_R_ENABLED_STAT(ring));
274b356ddf0SMark Johnston 	/* CDR interrupts */
275b356ddf0SMark Johnston 	if (status & SAFEXCEL_CDR_IRQ(ring)) {
276b356ddf0SMark Johnston 		stat = SAFEXCEL_READ(sc,
277b356ddf0SMark Johnston 		    SAFEXCEL_HIA_CDR(sc, ring) + SAFEXCEL_HIA_xDR_STAT);
278b356ddf0SMark Johnston 		SAFEXCEL_WRITE(sc,
279b356ddf0SMark Johnston 		    SAFEXCEL_HIA_CDR(sc, ring) + SAFEXCEL_HIA_xDR_STAT,
280b356ddf0SMark Johnston 		    stat & SAFEXCEL_CDR_INTR_MASK);
281b356ddf0SMark Johnston 	}
282b356ddf0SMark Johnston 	/* RDR interrupts */
283b356ddf0SMark Johnston 	rdrpending = false;
284b356ddf0SMark Johnston 	if (status & SAFEXCEL_RDR_IRQ(ring)) {
285b356ddf0SMark Johnston 		stat = SAFEXCEL_READ(sc,
286b356ddf0SMark Johnston 		    SAFEXCEL_HIA_RDR(sc, ring) + SAFEXCEL_HIA_xDR_STAT);
287b356ddf0SMark Johnston 		if ((stat & SAFEXCEL_xDR_ERR) == 0)
288b356ddf0SMark Johnston 			rdrpending = true;
289b356ddf0SMark Johnston 		SAFEXCEL_WRITE(sc,
290b356ddf0SMark Johnston 		    SAFEXCEL_HIA_RDR(sc, ring) + SAFEXCEL_HIA_xDR_STAT,
291b356ddf0SMark Johnston 		    stat & SAFEXCEL_RDR_INTR_MASK);
292b356ddf0SMark Johnston 	}
293b356ddf0SMark Johnston 	SAFEXCEL_WRITE(sc,
294b356ddf0SMark Johnston 	    SAFEXCEL_HIA_AIC_R(sc) + SAFEXCEL_HIA_AIC_R_ACK(ring),
295b356ddf0SMark Johnston 	    status);
296b356ddf0SMark Johnston 
297b356ddf0SMark Johnston 	if (rdrpending)
298b356ddf0SMark Johnston 		safexcel_rdr_intr(sc, ring);
299b356ddf0SMark Johnston }
300b356ddf0SMark Johnston 
301b356ddf0SMark Johnston static int
302b356ddf0SMark Johnston safexcel_configure(struct safexcel_softc *sc)
303b356ddf0SMark Johnston {
304b356ddf0SMark Johnston 	uint32_t i, mask, pemask, reg;
305b356ddf0SMark Johnston 	device_t dev;
306b356ddf0SMark Johnston 
307b356ddf0SMark Johnston 	if (sc->sc_type == 197) {
308b356ddf0SMark Johnston 		sc->sc_offsets = eip197_regs_offset;
309b356ddf0SMark Johnston 		pemask = SAFEXCEL_N_PES_MASK;
310b356ddf0SMark Johnston 	} else {
311b356ddf0SMark Johnston 		sc->sc_offsets = eip97_regs_offset;
312b356ddf0SMark Johnston 		pemask = EIP97_N_PES_MASK;
313b356ddf0SMark Johnston 	}
314b356ddf0SMark Johnston 
315b356ddf0SMark Johnston 	dev = sc->sc_dev;
316b356ddf0SMark Johnston 
317b356ddf0SMark Johnston 	/* Scan for valid ring interrupt controllers. */
318b356ddf0SMark Johnston 	for (i = 0; i < SAFEXCEL_MAX_RING_AIC; i++) {
319b356ddf0SMark Johnston 		reg = SAFEXCEL_READ(sc, SAFEXCEL_HIA_AIC_R(sc) +
320b356ddf0SMark Johnston 		    SAFEXCEL_HIA_AIC_R_VERSION(i));
321b356ddf0SMark Johnston 		if (SAFEXCEL_REG_LO16(reg) != EIP201_VERSION_LE)
322b356ddf0SMark Johnston 			break;
323b356ddf0SMark Johnston 	}
324b356ddf0SMark Johnston 	sc->sc_config.aic_rings = i;
325b356ddf0SMark Johnston 	if (sc->sc_config.aic_rings == 0)
326b356ddf0SMark Johnston 		return (-1);
327b356ddf0SMark Johnston 
328b356ddf0SMark Johnston 	reg = SAFEXCEL_READ(sc, SAFEXCEL_HIA_AIC_G(sc) + SAFEXCEL_HIA_OPTIONS);
329b356ddf0SMark Johnston 	/* Check for 64bit addressing. */
330b356ddf0SMark Johnston 	if ((reg & SAFEXCEL_OPT_ADDR_64) == 0)
331b356ddf0SMark Johnston 		return (-1);
332b356ddf0SMark Johnston 	/* Check alignment constraints (which we do not support). */
333b356ddf0SMark Johnston 	if (((reg & SAFEXCEL_OPT_TGT_ALIGN_MASK) >>
334b356ddf0SMark Johnston 	    SAFEXCEL_OPT_TGT_ALIGN_OFFSET) != 0)
335b356ddf0SMark Johnston 		return (-1);
336b356ddf0SMark Johnston 
337b356ddf0SMark Johnston 	sc->sc_config.hdw =
338b356ddf0SMark Johnston 	    (reg & SAFEXCEL_xDR_HDW_MASK) >> SAFEXCEL_xDR_HDW_OFFSET;
339b356ddf0SMark Johnston 	mask = (1 << sc->sc_config.hdw) - 1;
340b356ddf0SMark Johnston 
341b356ddf0SMark Johnston 	sc->sc_config.rings = reg & SAFEXCEL_N_RINGS_MASK;
342b356ddf0SMark Johnston 	/* Limit the number of rings to the number of the AIC Rings. */
343b356ddf0SMark Johnston 	sc->sc_config.rings = MIN(sc->sc_config.rings, sc->sc_config.aic_rings);
344b356ddf0SMark Johnston 
345b356ddf0SMark Johnston 	sc->sc_config.pes = (reg & pemask) >> SAFEXCEL_N_PES_OFFSET;
346b356ddf0SMark Johnston 
347b356ddf0SMark Johnston 	sc->sc_config.cd_size =
348b356ddf0SMark Johnston 	    sizeof(struct safexcel_cmd_descr) / sizeof(uint32_t);
349b356ddf0SMark Johnston 	sc->sc_config.cd_offset = (sc->sc_config.cd_size + mask) & ~mask;
350b356ddf0SMark Johnston 
351b356ddf0SMark Johnston 	sc->sc_config.rd_size =
352b356ddf0SMark Johnston 	    sizeof(struct safexcel_res_descr) / sizeof(uint32_t);
353b356ddf0SMark Johnston 	sc->sc_config.rd_offset = (sc->sc_config.rd_size + mask) & ~mask;
354b356ddf0SMark Johnston 
355b356ddf0SMark Johnston 	sc->sc_config.atok_offset =
356b356ddf0SMark Johnston 	    (SAFEXCEL_MAX_ATOKENS * sizeof(struct safexcel_instr) + mask) &
357b356ddf0SMark Johnston 	    ~mask;
358b356ddf0SMark Johnston 
359b356ddf0SMark Johnston 	return (0);
360b356ddf0SMark Johnston }
361b356ddf0SMark Johnston 
362b356ddf0SMark Johnston static void
363b356ddf0SMark Johnston safexcel_init_hia_bus_access(struct safexcel_softc *sc)
364b356ddf0SMark Johnston {
365b356ddf0SMark Johnston 	uint32_t version, val;
366b356ddf0SMark Johnston 
367b356ddf0SMark Johnston 	/* Determine endianness and configure byte swap. */
368b356ddf0SMark Johnston 	version = SAFEXCEL_READ(sc,
369b356ddf0SMark Johnston 	    SAFEXCEL_HIA_AIC(sc) + SAFEXCEL_HIA_VERSION);
370b356ddf0SMark Johnston 	val = SAFEXCEL_READ(sc, SAFEXCEL_HIA_AIC(sc) + SAFEXCEL_HIA_MST_CTRL);
371b356ddf0SMark Johnston 	if (SAFEXCEL_REG_HI16(version) == SAFEXCEL_HIA_VERSION_BE) {
372b356ddf0SMark Johnston 		val = SAFEXCEL_READ(sc,
373b356ddf0SMark Johnston 		    SAFEXCEL_HIA_AIC(sc) + SAFEXCEL_HIA_MST_CTRL);
374b356ddf0SMark Johnston 		val = val ^ (SAFEXCEL_MST_CTRL_NO_BYTE_SWAP >> 24);
375b356ddf0SMark Johnston 		SAFEXCEL_WRITE(sc,
376b356ddf0SMark Johnston 		    SAFEXCEL_HIA_AIC(sc) + SAFEXCEL_HIA_MST_CTRL,
377b356ddf0SMark Johnston 		    val);
378b356ddf0SMark Johnston 	}
379b356ddf0SMark Johnston 
380b356ddf0SMark Johnston 	/* Configure wr/rd cache values. */
381b356ddf0SMark Johnston 	SAFEXCEL_WRITE(sc, SAFEXCEL_HIA_GEN_CFG(sc) + SAFEXCEL_HIA_MST_CTRL,
382b356ddf0SMark Johnston 	    SAFEXCEL_MST_CTRL_RD_CACHE(RD_CACHE_4BITS) |
383b356ddf0SMark Johnston 	    SAFEXCEL_MST_CTRL_WD_CACHE(WR_CACHE_4BITS));
384b356ddf0SMark Johnston }
385b356ddf0SMark Johnston 
386b356ddf0SMark Johnston static void
387b356ddf0SMark Johnston safexcel_disable_global_interrupts(struct safexcel_softc *sc)
388b356ddf0SMark Johnston {
389b356ddf0SMark Johnston 	/* Disable and clear pending interrupts. */
390b356ddf0SMark Johnston 	SAFEXCEL_WRITE(sc,
391b356ddf0SMark Johnston 	    SAFEXCEL_HIA_AIC_G(sc) + SAFEXCEL_HIA_AIC_G_ENABLE_CTRL, 0);
392b356ddf0SMark Johnston 	SAFEXCEL_WRITE(sc,
393b356ddf0SMark Johnston 	    SAFEXCEL_HIA_AIC_G(sc) + SAFEXCEL_HIA_AIC_G_ACK,
394b356ddf0SMark Johnston 	    SAFEXCEL_AIC_G_ACK_ALL_MASK);
395b356ddf0SMark Johnston }
396b356ddf0SMark Johnston 
397b356ddf0SMark Johnston /*
398b356ddf0SMark Johnston  * Configure the data fetch engine.  This component parses command descriptors
399b356ddf0SMark Johnston  * and sets up DMA transfers from host memory to the corresponding processing
400b356ddf0SMark Johnston  * engine.
401b356ddf0SMark Johnston  */
402b356ddf0SMark Johnston static void
403b356ddf0SMark Johnston safexcel_configure_dfe_engine(struct safexcel_softc *sc, int pe)
404b356ddf0SMark Johnston {
405b356ddf0SMark Johnston 	/* Reset all DFE threads. */
406b356ddf0SMark Johnston 	SAFEXCEL_WRITE(sc,
407b356ddf0SMark Johnston 	    SAFEXCEL_HIA_DFE_THR(sc) + SAFEXCEL_HIA_DFE_THR_CTRL(pe),
408b356ddf0SMark Johnston 	    SAFEXCEL_DxE_THR_CTRL_RESET_PE);
409b356ddf0SMark Johnston 
410b356ddf0SMark Johnston 	/* Deassert the DFE reset. */
411b356ddf0SMark Johnston 	SAFEXCEL_WRITE(sc,
412b356ddf0SMark Johnston 	    SAFEXCEL_HIA_DFE_THR(sc) + SAFEXCEL_HIA_DFE_THR_CTRL(pe), 0);
413b356ddf0SMark Johnston 
414b356ddf0SMark Johnston 	/* DMA transfer size to use. */
415b356ddf0SMark Johnston 	SAFEXCEL_WRITE(sc, SAFEXCEL_HIA_DFE(sc) + SAFEXCEL_HIA_DFE_CFG(pe),
416b356ddf0SMark Johnston 	    SAFEXCEL_HIA_DFE_CFG_DIS_DEBUG |
417b356ddf0SMark Johnston 	    SAFEXCEL_HIA_DxE_CFG_MIN_DATA_SIZE(6) |
418b356ddf0SMark Johnston 	    SAFEXCEL_HIA_DxE_CFG_MAX_DATA_SIZE(9) |
419b356ddf0SMark Johnston 	    SAFEXCEL_HIA_DxE_CFG_MIN_CTRL_SIZE(6) |
420b356ddf0SMark Johnston 	    SAFEXCEL_HIA_DxE_CFG_MAX_CTRL_SIZE(7) |
421b356ddf0SMark Johnston 	    SAFEXCEL_HIA_DxE_CFG_DATA_CACHE_CTRL(RD_CACHE_3BITS) |
422b356ddf0SMark Johnston 	    SAFEXCEL_HIA_DxE_CFG_CTRL_CACHE_CTRL(RD_CACHE_3BITS));
423b356ddf0SMark Johnston 
424b356ddf0SMark Johnston 	/* Configure the PE DMA transfer thresholds. */
425b356ddf0SMark Johnston 	SAFEXCEL_WRITE(sc, SAFEXCEL_PE(sc) + SAFEXCEL_PE_IN_DBUF_THRES(pe),
426b356ddf0SMark Johnston 	    SAFEXCEL_PE_IN_xBUF_THRES_MIN(6) |
427b356ddf0SMark Johnston 	    SAFEXCEL_PE_IN_xBUF_THRES_MAX(9));
428b356ddf0SMark Johnston 	SAFEXCEL_WRITE(sc, SAFEXCEL_PE(sc) + SAFEXCEL_PE_IN_TBUF_THRES(pe),
429b356ddf0SMark Johnston 	    SAFEXCEL_PE_IN_xBUF_THRES_MIN(6) |
430b356ddf0SMark Johnston 	    SAFEXCEL_PE_IN_xBUF_THRES_MAX(7));
431b356ddf0SMark Johnston }
432b356ddf0SMark Johnston 
433b356ddf0SMark Johnston /*
434b356ddf0SMark Johnston  * Configure the data store engine.  This component parses result descriptors
435b356ddf0SMark Johnston  * and sets up DMA transfers from the processing engine to host memory.
436b356ddf0SMark Johnston  */
437b356ddf0SMark Johnston static int
438b356ddf0SMark Johnston safexcel_configure_dse(struct safexcel_softc *sc, int pe)
439b356ddf0SMark Johnston {
440b356ddf0SMark Johnston 	uint32_t val;
441b356ddf0SMark Johnston 	int count;
442b356ddf0SMark Johnston 
443b356ddf0SMark Johnston 	/* Disable and reset all DSE threads. */
444b356ddf0SMark Johnston 	SAFEXCEL_WRITE(sc,
445b356ddf0SMark Johnston 	    SAFEXCEL_HIA_DSE_THR(sc) + SAFEXCEL_HIA_DSE_THR_CTRL(pe),
446b356ddf0SMark Johnston 	    SAFEXCEL_DxE_THR_CTRL_RESET_PE);
447b356ddf0SMark Johnston 
448b356ddf0SMark Johnston 	/* Wait for a second for threads to go idle. */
449b356ddf0SMark Johnston 	for (count = 0;;) {
450b356ddf0SMark Johnston 		val = SAFEXCEL_READ(sc,
451b356ddf0SMark Johnston 		    SAFEXCEL_HIA_DSE_THR(sc) + SAFEXCEL_HIA_DSE_THR_STAT(pe));
452b356ddf0SMark Johnston 		if ((val & SAFEXCEL_DSE_THR_RDR_ID_MASK) ==
453b356ddf0SMark Johnston 		    SAFEXCEL_DSE_THR_RDR_ID_MASK)
454b356ddf0SMark Johnston 			break;
455b356ddf0SMark Johnston 		if (count++ > 10000) {
456b356ddf0SMark Johnston 			device_printf(sc->sc_dev, "DSE reset timeout\n");
457b356ddf0SMark Johnston 			return (-1);
458b356ddf0SMark Johnston 		}
459b356ddf0SMark Johnston 		DELAY(100);
460b356ddf0SMark Johnston 	}
461b356ddf0SMark Johnston 
462b356ddf0SMark Johnston 	/* Exit the reset state. */
463b356ddf0SMark Johnston 	SAFEXCEL_WRITE(sc,
464b356ddf0SMark Johnston 	    SAFEXCEL_HIA_DSE_THR(sc) + SAFEXCEL_HIA_DSE_THR_CTRL(pe), 0);
465b356ddf0SMark Johnston 
466b356ddf0SMark Johnston 	/* DMA transfer size to use */
467b356ddf0SMark Johnston 	SAFEXCEL_WRITE(sc, SAFEXCEL_HIA_DSE(sc) + SAFEXCEL_HIA_DSE_CFG(pe),
468b356ddf0SMark Johnston 	    SAFEXCEL_HIA_DSE_CFG_DIS_DEBUG |
469b356ddf0SMark Johnston 	    SAFEXCEL_HIA_DxE_CFG_MIN_DATA_SIZE(7) |
470b356ddf0SMark Johnston 	    SAFEXCEL_HIA_DxE_CFG_MAX_DATA_SIZE(8) |
471b356ddf0SMark Johnston 	    SAFEXCEL_HIA_DxE_CFG_DATA_CACHE_CTRL(WR_CACHE_3BITS) |
472b356ddf0SMark Johnston 	    SAFEXCEL_HIA_DSE_CFG_ALLWAYS_BUFFERABLE);
473b356ddf0SMark Johnston 
474b356ddf0SMark Johnston 	/* Configure the procesing engine thresholds */
475b356ddf0SMark Johnston 	SAFEXCEL_WRITE(sc,
476b356ddf0SMark Johnston 	    SAFEXCEL_PE(sc) + SAFEXCEL_PE_OUT_DBUF_THRES(pe),
477b356ddf0SMark Johnston 	    SAFEXCEL_PE_OUT_DBUF_THRES_MIN(7) |
478b356ddf0SMark Johnston 	    SAFEXCEL_PE_OUT_DBUF_THRES_MAX(8));
479b356ddf0SMark Johnston 
480b356ddf0SMark Johnston 	return (0);
481b356ddf0SMark Johnston }
482b356ddf0SMark Johnston 
483b356ddf0SMark Johnston static void
484b356ddf0SMark Johnston safexcel_hw_prepare_rings(struct safexcel_softc *sc)
485b356ddf0SMark Johnston {
486b356ddf0SMark Johnston 	int i;
487b356ddf0SMark Johnston 
488b356ddf0SMark Johnston 	for (i = 0; i < sc->sc_config.rings; i++) {
489b356ddf0SMark Johnston 		/*
490b356ddf0SMark Johnston 		 * Command descriptors.
491b356ddf0SMark Johnston 		 */
492b356ddf0SMark Johnston 
493b356ddf0SMark Johnston 		/* Clear interrupts for this ring. */
494b356ddf0SMark Johnston 		SAFEXCEL_WRITE(sc,
495b356ddf0SMark Johnston 		    SAFEXCEL_HIA_AIC_R(sc) + SAFEXCEL_HIA_AIC_R_ENABLE_CLR(i),
496b356ddf0SMark Johnston 		    SAFEXCEL_HIA_AIC_R_ENABLE_CLR_ALL_MASK);
497b356ddf0SMark Johnston 
498b356ddf0SMark Johnston 		/* Disable external triggering. */
499b356ddf0SMark Johnston 		SAFEXCEL_WRITE(sc,
500b356ddf0SMark Johnston 		    SAFEXCEL_HIA_CDR(sc, i) + SAFEXCEL_HIA_xDR_CFG, 0);
501b356ddf0SMark Johnston 
502b356ddf0SMark Johnston 		/* Clear the pending prepared counter. */
503b356ddf0SMark Johnston 		SAFEXCEL_WRITE(sc,
504b356ddf0SMark Johnston 		    SAFEXCEL_HIA_CDR(sc, i) + SAFEXCEL_HIA_xDR_PREP_COUNT,
505b356ddf0SMark Johnston 		    SAFEXCEL_xDR_PREP_CLR_COUNT);
506b356ddf0SMark Johnston 
507b356ddf0SMark Johnston 		/* Clear the pending processed counter. */
508b356ddf0SMark Johnston 		SAFEXCEL_WRITE(sc,
509b356ddf0SMark Johnston 		    SAFEXCEL_HIA_CDR(sc, i) + SAFEXCEL_HIA_xDR_PROC_COUNT,
510b356ddf0SMark Johnston 		    SAFEXCEL_xDR_PROC_CLR_COUNT);
511b356ddf0SMark Johnston 
512b356ddf0SMark Johnston 		SAFEXCEL_WRITE(sc,
513b356ddf0SMark Johnston 		    SAFEXCEL_HIA_CDR(sc, i) + SAFEXCEL_HIA_xDR_PREP_PNTR, 0);
514b356ddf0SMark Johnston 		SAFEXCEL_WRITE(sc,
515b356ddf0SMark Johnston 		    SAFEXCEL_HIA_CDR(sc, i) + SAFEXCEL_HIA_xDR_PROC_PNTR, 0);
516b356ddf0SMark Johnston 
517b356ddf0SMark Johnston 		SAFEXCEL_WRITE(sc,
518b356ddf0SMark Johnston 		    SAFEXCEL_HIA_CDR(sc, i) + SAFEXCEL_HIA_xDR_RING_SIZE,
519b356ddf0SMark Johnston 		    SAFEXCEL_RING_SIZE * sc->sc_config.cd_offset *
520b356ddf0SMark Johnston 		    sizeof(uint32_t));
521b356ddf0SMark Johnston 
522b356ddf0SMark Johnston 		/*
523b356ddf0SMark Johnston 		 * Result descriptors.
524b356ddf0SMark Johnston 		 */
525b356ddf0SMark Johnston 
526b356ddf0SMark Johnston 		/* Disable external triggering. */
527b356ddf0SMark Johnston 		SAFEXCEL_WRITE(sc,
528b356ddf0SMark Johnston 		    SAFEXCEL_HIA_RDR(sc, i) + SAFEXCEL_HIA_xDR_CFG, 0);
529b356ddf0SMark Johnston 
530b356ddf0SMark Johnston 		/* Clear the pending prepared counter. */
531b356ddf0SMark Johnston 		SAFEXCEL_WRITE(sc,
532b356ddf0SMark Johnston 		    SAFEXCEL_HIA_RDR(sc, i) + SAFEXCEL_HIA_xDR_PREP_COUNT,
533b356ddf0SMark Johnston 		    SAFEXCEL_xDR_PREP_CLR_COUNT);
534b356ddf0SMark Johnston 
535b356ddf0SMark Johnston 		/* Clear the pending processed counter. */
536b356ddf0SMark Johnston 		SAFEXCEL_WRITE(sc,
537b356ddf0SMark Johnston 		    SAFEXCEL_HIA_RDR(sc, i) + SAFEXCEL_HIA_xDR_PROC_COUNT,
538b356ddf0SMark Johnston 		    SAFEXCEL_xDR_PROC_CLR_COUNT);
539b356ddf0SMark Johnston 
540b356ddf0SMark Johnston 		SAFEXCEL_WRITE(sc,
541b356ddf0SMark Johnston 		    SAFEXCEL_HIA_RDR(sc, i) + SAFEXCEL_HIA_xDR_PREP_PNTR, 0);
542b356ddf0SMark Johnston 		SAFEXCEL_WRITE(sc,
543b356ddf0SMark Johnston 		    SAFEXCEL_HIA_RDR(sc, i) + SAFEXCEL_HIA_xDR_PROC_PNTR, 0);
544b356ddf0SMark Johnston 
545b356ddf0SMark Johnston 		/* Ring size. */
546b356ddf0SMark Johnston 		SAFEXCEL_WRITE(sc,
547b356ddf0SMark Johnston 		    SAFEXCEL_HIA_RDR(sc, i) + SAFEXCEL_HIA_xDR_RING_SIZE,
548b356ddf0SMark Johnston 		    SAFEXCEL_RING_SIZE * sc->sc_config.rd_offset *
549b356ddf0SMark Johnston 		    sizeof(uint32_t));
550b356ddf0SMark Johnston 	}
551b356ddf0SMark Johnston }
552b356ddf0SMark Johnston 
553b356ddf0SMark Johnston static void
554b356ddf0SMark Johnston safexcel_hw_setup_rings(struct safexcel_softc *sc)
555b356ddf0SMark Johnston {
556b356ddf0SMark Johnston 	struct safexcel_ring *ring;
557b356ddf0SMark Johnston 	uint32_t cd_size_rnd, mask, rd_size_rnd, val;
558b356ddf0SMark Johnston 	int i;
559b356ddf0SMark Johnston 
560b356ddf0SMark Johnston 	mask = (1 << sc->sc_config.hdw) - 1;
561b356ddf0SMark Johnston 	cd_size_rnd = (sc->sc_config.cd_size + mask) >> sc->sc_config.hdw;
562b356ddf0SMark Johnston 	val = (sizeof(struct safexcel_res_descr) -
563b356ddf0SMark Johnston 	    sizeof(struct safexcel_res_data)) / sizeof(uint32_t);
564b356ddf0SMark Johnston 	rd_size_rnd = (val + mask) >> sc->sc_config.hdw;
565b356ddf0SMark Johnston 
566b356ddf0SMark Johnston 	for (i = 0; i < sc->sc_config.rings; i++) {
567b356ddf0SMark Johnston 		ring = &sc->sc_ring[i];
568b356ddf0SMark Johnston 
569b356ddf0SMark Johnston 		/*
570b356ddf0SMark Johnston 		 * Command descriptors.
571b356ddf0SMark Johnston 		 */
572b356ddf0SMark Johnston 
573b356ddf0SMark Johnston 		/* Ring base address. */
574b356ddf0SMark Johnston 		SAFEXCEL_WRITE(sc, SAFEXCEL_HIA_CDR(sc, i) +
575b356ddf0SMark Johnston 		    SAFEXCEL_HIA_xDR_RING_BASE_ADDR_LO,
576b356ddf0SMark Johnston 		    SAFEXCEL_ADDR_LO(ring->cdr.dma.paddr));
577b356ddf0SMark Johnston 		SAFEXCEL_WRITE(sc, SAFEXCEL_HIA_CDR(sc, i) +
578b356ddf0SMark Johnston 		    SAFEXCEL_HIA_xDR_RING_BASE_ADDR_HI,
579b356ddf0SMark Johnston 		    SAFEXCEL_ADDR_HI(ring->cdr.dma.paddr));
580b356ddf0SMark Johnston 
581b356ddf0SMark Johnston 		SAFEXCEL_WRITE(sc,
582b356ddf0SMark Johnston 		    SAFEXCEL_HIA_CDR(sc, i) + SAFEXCEL_HIA_xDR_DESC_SIZE,
583b356ddf0SMark Johnston 		    SAFEXCEL_xDR_DESC_MODE_64BIT | SAFEXCEL_CDR_DESC_MODE_ADCP |
584b356ddf0SMark Johnston 		    (sc->sc_config.cd_offset << SAFEXCEL_xDR_DESC_xD_OFFSET) |
585b356ddf0SMark Johnston 		    sc->sc_config.cd_size);
586b356ddf0SMark Johnston 
587b356ddf0SMark Johnston 		SAFEXCEL_WRITE(sc,
588b356ddf0SMark Johnston 		    SAFEXCEL_HIA_CDR(sc, i) + SAFEXCEL_HIA_xDR_CFG,
589b356ddf0SMark Johnston 		    ((SAFEXCEL_FETCH_COUNT * (cd_size_rnd << sc->sc_config.hdw)) <<
590b356ddf0SMark Johnston 		      SAFEXCEL_xDR_xD_FETCH_THRESH) |
591b356ddf0SMark Johnston 		    (SAFEXCEL_FETCH_COUNT * sc->sc_config.cd_offset));
592b356ddf0SMark Johnston 
593b356ddf0SMark Johnston 		/* Configure DMA tx control. */
594b356ddf0SMark Johnston 		SAFEXCEL_WRITE(sc,
595b356ddf0SMark Johnston 		    SAFEXCEL_HIA_CDR(sc, i) + SAFEXCEL_HIA_xDR_DMA_CFG,
596b356ddf0SMark Johnston 		    SAFEXCEL_HIA_xDR_CFG_WR_CACHE(WR_CACHE_3BITS) |
597b356ddf0SMark Johnston 		    SAFEXCEL_HIA_xDR_CFG_RD_CACHE(RD_CACHE_3BITS));
598b356ddf0SMark Johnston 
599b356ddf0SMark Johnston 		/* Clear any pending interrupt. */
600b356ddf0SMark Johnston 		SAFEXCEL_WRITE(sc,
601b356ddf0SMark Johnston 		    SAFEXCEL_HIA_CDR(sc, i) + SAFEXCEL_HIA_xDR_STAT,
602b356ddf0SMark Johnston 		    SAFEXCEL_CDR_INTR_MASK);
603b356ddf0SMark Johnston 
604b356ddf0SMark Johnston 		/*
605b356ddf0SMark Johnston 		 * Result descriptors.
606b356ddf0SMark Johnston 		 */
607b356ddf0SMark Johnston 
608b356ddf0SMark Johnston 		/* Ring base address. */
609b356ddf0SMark Johnston 		SAFEXCEL_WRITE(sc, SAFEXCEL_HIA_RDR(sc, i) +
610b356ddf0SMark Johnston 		    SAFEXCEL_HIA_xDR_RING_BASE_ADDR_LO,
611b356ddf0SMark Johnston 		    SAFEXCEL_ADDR_LO(ring->rdr.dma.paddr));
612b356ddf0SMark Johnston 		SAFEXCEL_WRITE(sc, SAFEXCEL_HIA_RDR(sc, i) +
613b356ddf0SMark Johnston 		    SAFEXCEL_HIA_xDR_RING_BASE_ADDR_HI,
614b356ddf0SMark Johnston 		    SAFEXCEL_ADDR_HI(ring->rdr.dma.paddr));
615b356ddf0SMark Johnston 
616b356ddf0SMark Johnston 		SAFEXCEL_WRITE(sc,
617b356ddf0SMark Johnston 		    SAFEXCEL_HIA_RDR(sc, i) + SAFEXCEL_HIA_xDR_DESC_SIZE,
618b356ddf0SMark Johnston 		    SAFEXCEL_xDR_DESC_MODE_64BIT |
619b356ddf0SMark Johnston 		    (sc->sc_config.rd_offset << SAFEXCEL_xDR_DESC_xD_OFFSET) |
620b356ddf0SMark Johnston 		    sc->sc_config.rd_size);
621b356ddf0SMark Johnston 
622b356ddf0SMark Johnston 		SAFEXCEL_WRITE(sc,
623b356ddf0SMark Johnston 		    SAFEXCEL_HIA_RDR(sc, i) + SAFEXCEL_HIA_xDR_CFG,
624b356ddf0SMark Johnston 		    ((SAFEXCEL_FETCH_COUNT * (rd_size_rnd << sc->sc_config.hdw)) <<
625b356ddf0SMark Johnston 		    SAFEXCEL_xDR_xD_FETCH_THRESH) |
626b356ddf0SMark Johnston 		    (SAFEXCEL_FETCH_COUNT * sc->sc_config.rd_offset));
627b356ddf0SMark Johnston 
628b356ddf0SMark Johnston 		/* Configure DMA tx control. */
629b356ddf0SMark Johnston 		SAFEXCEL_WRITE(sc,
630b356ddf0SMark Johnston 		    SAFEXCEL_HIA_RDR(sc, i) + SAFEXCEL_HIA_xDR_DMA_CFG,
631b356ddf0SMark Johnston 		    SAFEXCEL_HIA_xDR_CFG_WR_CACHE(WR_CACHE_3BITS) |
632b356ddf0SMark Johnston 		    SAFEXCEL_HIA_xDR_CFG_RD_CACHE(RD_CACHE_3BITS) |
633b356ddf0SMark Johnston 		    SAFEXCEL_HIA_xDR_WR_RES_BUF | SAFEXCEL_HIA_xDR_WR_CTRL_BUF);
634b356ddf0SMark Johnston 
635b356ddf0SMark Johnston 		/* Clear any pending interrupt. */
636b356ddf0SMark Johnston 		SAFEXCEL_WRITE(sc,
637b356ddf0SMark Johnston 		    SAFEXCEL_HIA_RDR(sc, i) + SAFEXCEL_HIA_xDR_STAT,
638b356ddf0SMark Johnston 		    SAFEXCEL_RDR_INTR_MASK);
639b356ddf0SMark Johnston 
640b356ddf0SMark Johnston 		/* Enable ring interrupt. */
641b356ddf0SMark Johnston 		SAFEXCEL_WRITE(sc,
642b356ddf0SMark Johnston 		    SAFEXCEL_HIA_AIC_R(sc) + SAFEXCEL_HIA_AIC_R_ENABLE_CTRL(i),
643b356ddf0SMark Johnston 		    SAFEXCEL_RDR_IRQ(i));
644b356ddf0SMark Johnston 	}
645b356ddf0SMark Johnston }
646b356ddf0SMark Johnston 
647b356ddf0SMark Johnston /* Reset the command and result descriptor rings. */
648b356ddf0SMark Johnston static void
649b356ddf0SMark Johnston safexcel_hw_reset_rings(struct safexcel_softc *sc)
650b356ddf0SMark Johnston {
651b356ddf0SMark Johnston 	int i;
652b356ddf0SMark Johnston 
653b356ddf0SMark Johnston 	for (i = 0; i < sc->sc_config.rings; i++) {
654b356ddf0SMark Johnston 		/*
655b356ddf0SMark Johnston 		 * Result descriptor ring operations.
656b356ddf0SMark Johnston 		 */
657b356ddf0SMark Johnston 
658b356ddf0SMark Johnston 		/* Reset ring base address. */
659b356ddf0SMark Johnston 		SAFEXCEL_WRITE(sc, SAFEXCEL_HIA_RDR(sc, i) +
660b356ddf0SMark Johnston 		    SAFEXCEL_HIA_xDR_RING_BASE_ADDR_LO, 0);
661b356ddf0SMark Johnston 		SAFEXCEL_WRITE(sc, SAFEXCEL_HIA_RDR(sc, i) +
662b356ddf0SMark Johnston 		    SAFEXCEL_HIA_xDR_RING_BASE_ADDR_HI, 0);
663b356ddf0SMark Johnston 
664b356ddf0SMark Johnston 		/* Clear the pending prepared counter. */
665b356ddf0SMark Johnston 		SAFEXCEL_WRITE(sc,
666b356ddf0SMark Johnston 		    SAFEXCEL_HIA_RDR(sc, i) + SAFEXCEL_HIA_xDR_PREP_COUNT,
667b356ddf0SMark Johnston 		    SAFEXCEL_xDR_PREP_CLR_COUNT);
668b356ddf0SMark Johnston 
669b356ddf0SMark Johnston 		/* Clear the pending processed counter. */
670b356ddf0SMark Johnston 		SAFEXCEL_WRITE(sc,
671b356ddf0SMark Johnston 		    SAFEXCEL_HIA_RDR(sc, i) + SAFEXCEL_HIA_xDR_PROC_COUNT,
672b356ddf0SMark Johnston 		    SAFEXCEL_xDR_PROC_CLR_COUNT);
673b356ddf0SMark Johnston 
674b356ddf0SMark Johnston 		SAFEXCEL_WRITE(sc,
675b356ddf0SMark Johnston 		    SAFEXCEL_HIA_RDR(sc, i) + SAFEXCEL_HIA_xDR_PREP_PNTR, 0);
676b356ddf0SMark Johnston 		SAFEXCEL_WRITE(sc,
677b356ddf0SMark Johnston 		    SAFEXCEL_HIA_RDR(sc, i) + SAFEXCEL_HIA_xDR_PROC_PNTR, 0);
678b356ddf0SMark Johnston 
679b356ddf0SMark Johnston 		SAFEXCEL_WRITE(sc,
680b356ddf0SMark Johnston 		    SAFEXCEL_HIA_RDR(sc, i) + SAFEXCEL_HIA_xDR_RING_SIZE, 0);
681b356ddf0SMark Johnston 
682b356ddf0SMark Johnston 		/* Clear any pending interrupt. */
683b356ddf0SMark Johnston 		SAFEXCEL_WRITE(sc,
684b356ddf0SMark Johnston 		    SAFEXCEL_HIA_RDR(sc, i) + SAFEXCEL_HIA_xDR_STAT,
685b356ddf0SMark Johnston 		    SAFEXCEL_RDR_INTR_MASK);
686b356ddf0SMark Johnston 
687b356ddf0SMark Johnston 		/* Disable ring interrupt. */
688b356ddf0SMark Johnston 		SAFEXCEL_WRITE(sc,
689b356ddf0SMark Johnston 		    SAFEXCEL_HIA_AIC_R(sc) + SAFEXCEL_HIA_AIC_R_ENABLE_CLR(i),
690b356ddf0SMark Johnston 		    SAFEXCEL_RDR_IRQ(i));
691b356ddf0SMark Johnston 
692b356ddf0SMark Johnston 		/*
693b356ddf0SMark Johnston 		 * Command descriptor ring operations.
694b356ddf0SMark Johnston 		 */
695b356ddf0SMark Johnston 
696b356ddf0SMark Johnston 		/* Reset ring base address. */
697b356ddf0SMark Johnston 		SAFEXCEL_WRITE(sc, SAFEXCEL_HIA_CDR(sc, i) +
698b356ddf0SMark Johnston 		    SAFEXCEL_HIA_xDR_RING_BASE_ADDR_LO, 0);
699b356ddf0SMark Johnston 		SAFEXCEL_WRITE(sc, SAFEXCEL_HIA_CDR(sc, i) +
700b356ddf0SMark Johnston 		    SAFEXCEL_HIA_xDR_RING_BASE_ADDR_HI, 0);
701b356ddf0SMark Johnston 
702b356ddf0SMark Johnston 		/* Clear the pending prepared counter. */
703b356ddf0SMark Johnston 		SAFEXCEL_WRITE(sc,
704b356ddf0SMark Johnston 		    SAFEXCEL_HIA_CDR(sc, i) + SAFEXCEL_HIA_xDR_PREP_COUNT,
705b356ddf0SMark Johnston 		    SAFEXCEL_xDR_PREP_CLR_COUNT);
706b356ddf0SMark Johnston 
707b356ddf0SMark Johnston 		/* Clear the pending processed counter. */
708b356ddf0SMark Johnston 		SAFEXCEL_WRITE(sc,
709b356ddf0SMark Johnston 		    SAFEXCEL_HIA_CDR(sc, i) + SAFEXCEL_HIA_xDR_PROC_COUNT,
710b356ddf0SMark Johnston 		    SAFEXCEL_xDR_PROC_CLR_COUNT);
711b356ddf0SMark Johnston 
712b356ddf0SMark Johnston 		SAFEXCEL_WRITE(sc,
713b356ddf0SMark Johnston 		    SAFEXCEL_HIA_CDR(sc, i) + SAFEXCEL_HIA_xDR_PREP_PNTR, 0);
714b356ddf0SMark Johnston 		SAFEXCEL_WRITE(sc,
715b356ddf0SMark Johnston 		    SAFEXCEL_HIA_CDR(sc, i) + SAFEXCEL_HIA_xDR_PROC_PNTR, 0);
716b356ddf0SMark Johnston 
717b356ddf0SMark Johnston 		SAFEXCEL_WRITE(sc,
718b356ddf0SMark Johnston 		    SAFEXCEL_HIA_CDR(sc, i) + SAFEXCEL_HIA_xDR_RING_SIZE, 0);
719b356ddf0SMark Johnston 
720b356ddf0SMark Johnston 		/* Clear any pending interrupt. */
721b356ddf0SMark Johnston 		SAFEXCEL_WRITE(sc,
722b356ddf0SMark Johnston 		    SAFEXCEL_HIA_CDR(sc, i) + SAFEXCEL_HIA_xDR_STAT,
723b356ddf0SMark Johnston 		    SAFEXCEL_CDR_INTR_MASK);
724b356ddf0SMark Johnston 	}
725b356ddf0SMark Johnston }
726b356ddf0SMark Johnston 
727b356ddf0SMark Johnston static void
728b356ddf0SMark Johnston safexcel_enable_pe_engine(struct safexcel_softc *sc, int pe)
729b356ddf0SMark Johnston {
730b356ddf0SMark Johnston 	int i, ring_mask;
731b356ddf0SMark Johnston 
732b356ddf0SMark Johnston 	for (ring_mask = 0, i = 0; i < sc->sc_config.rings; i++) {
733b356ddf0SMark Johnston 		ring_mask <<= 1;
734b356ddf0SMark Johnston 		ring_mask |= 1;
735b356ddf0SMark Johnston 	}
736b356ddf0SMark Johnston 
737b356ddf0SMark Johnston 	/* Enable command descriptor rings. */
738b356ddf0SMark Johnston 	SAFEXCEL_WRITE(sc, SAFEXCEL_HIA_DFE_THR(sc) + SAFEXCEL_HIA_DFE_THR_CTRL(pe),
739b356ddf0SMark Johnston 	    SAFEXCEL_DxE_THR_CTRL_EN | ring_mask);
740b356ddf0SMark Johnston 
741b356ddf0SMark Johnston 	/* Enable result descriptor rings. */
742b356ddf0SMark Johnston 	SAFEXCEL_WRITE(sc, SAFEXCEL_HIA_DSE_THR(sc) + SAFEXCEL_HIA_DSE_THR_CTRL(pe),
743b356ddf0SMark Johnston 	    SAFEXCEL_DxE_THR_CTRL_EN | ring_mask);
744b356ddf0SMark Johnston 
745b356ddf0SMark Johnston 	/* Clear any HIA interrupt. */
746b356ddf0SMark Johnston 	SAFEXCEL_WRITE(sc, SAFEXCEL_HIA_AIC_G(sc) + SAFEXCEL_HIA_AIC_G_ACK,
747b356ddf0SMark Johnston 	    SAFEXCEL_AIC_G_ACK_HIA_MASK);
748b356ddf0SMark Johnston }
749b356ddf0SMark Johnston 
750b356ddf0SMark Johnston static void
751b356ddf0SMark Johnston safexcel_execute(struct safexcel_softc *sc, struct safexcel_ring *ring,
7521a6ffed5SMark Johnston     struct safexcel_request *req, int hint)
753b356ddf0SMark Johnston {
7541a6ffed5SMark Johnston 	int ringidx, ncdesc, nrdesc;
755b356ddf0SMark Johnston 	bool busy;
756b356ddf0SMark Johnston 
757b356ddf0SMark Johnston 	mtx_assert(&ring->mtx, MA_OWNED);
758b356ddf0SMark Johnston 
7591a6ffed5SMark Johnston 	if ((hint & CRYPTO_HINT_MORE) != 0) {
7601a6ffed5SMark Johnston 		ring->pending++;
7611a6ffed5SMark Johnston 		ring->pending_cdesc += req->cdescs;
7621a6ffed5SMark Johnston 		ring->pending_rdesc += req->rdescs;
7631a6ffed5SMark Johnston 		return;
764b356ddf0SMark Johnston 	}
765b356ddf0SMark Johnston 
7661a6ffed5SMark Johnston 	ringidx = req->ringidx;
7671a6ffed5SMark Johnston 
7681a6ffed5SMark Johnston 	busy = ring->queued != 0;
7691a6ffed5SMark Johnston 	ncdesc = ring->pending_cdesc + req->cdescs;
7701a6ffed5SMark Johnston 	nrdesc = ring->pending_rdesc + req->rdescs;
7711a6ffed5SMark Johnston 	ring->queued += ring->pending + 1;
7721a6ffed5SMark Johnston 
773b356ddf0SMark Johnston 	if (!busy) {
774b356ddf0SMark Johnston 		SAFEXCEL_WRITE(sc,
775b356ddf0SMark Johnston 		    SAFEXCEL_HIA_RDR(sc, ringidx) + SAFEXCEL_HIA_xDR_THRESH,
7761a6ffed5SMark Johnston 		    SAFEXCEL_HIA_CDR_THRESH_PKT_MODE | ring->queued);
777b356ddf0SMark Johnston 	}
778b356ddf0SMark Johnston 	SAFEXCEL_WRITE(sc,
779b356ddf0SMark Johnston 	    SAFEXCEL_HIA_RDR(sc, ringidx) + SAFEXCEL_HIA_xDR_PREP_COUNT,
7801a6ffed5SMark Johnston 	    nrdesc * sc->sc_config.rd_offset * sizeof(uint32_t));
781b356ddf0SMark Johnston 	SAFEXCEL_WRITE(sc,
782b356ddf0SMark Johnston 	    SAFEXCEL_HIA_CDR(sc, ringidx) + SAFEXCEL_HIA_xDR_PREP_COUNT,
7831a6ffed5SMark Johnston 	    ncdesc * sc->sc_config.cd_offset * sizeof(uint32_t));
7841a6ffed5SMark Johnston 
7851a6ffed5SMark Johnston 	ring->pending = ring->pending_cdesc = ring->pending_rdesc = 0;
786b356ddf0SMark Johnston }
787b356ddf0SMark Johnston 
788b356ddf0SMark Johnston static void
789b356ddf0SMark Johnston safexcel_init_rings(struct safexcel_softc *sc)
790b356ddf0SMark Johnston {
791b356ddf0SMark Johnston 	struct safexcel_cmd_descr *cdesc;
792b356ddf0SMark Johnston 	struct safexcel_ring *ring;
793b356ddf0SMark Johnston 	uint64_t atok;
794b356ddf0SMark Johnston 	int i, j;
795b356ddf0SMark Johnston 
796b356ddf0SMark Johnston 	for (i = 0; i < sc->sc_config.rings; i++) {
797b356ddf0SMark Johnston 		ring = &sc->sc_ring[i];
798b356ddf0SMark Johnston 
7998ba6acbbSMark Johnston 		snprintf(ring->lockname, sizeof(ring->lockname),
8008ba6acbbSMark Johnston 		    "safexcel_ring%d", i);
8018ba6acbbSMark Johnston 		mtx_init(&ring->mtx, ring->lockname, NULL, MTX_DEF);
802b356ddf0SMark Johnston 
8031a6ffed5SMark Johnston 		ring->pending = ring->pending_cdesc = ring->pending_rdesc = 0;
8041a6ffed5SMark Johnston 		ring->queued = 0;
805b356ddf0SMark Johnston 		ring->cdr.read = ring->cdr.write = 0;
806b356ddf0SMark Johnston 		ring->rdr.read = ring->rdr.write = 0;
807b356ddf0SMark Johnston 		for (j = 0; j < SAFEXCEL_RING_SIZE; j++) {
808b356ddf0SMark Johnston 			cdesc = &ring->cdr.desc[j];
809b356ddf0SMark Johnston 			atok = ring->dma_atok.paddr +
810b356ddf0SMark Johnston 			    sc->sc_config.atok_offset * j;
811b356ddf0SMark Johnston 			cdesc->atok_lo = SAFEXCEL_ADDR_LO(atok);
812b356ddf0SMark Johnston 			cdesc->atok_hi = SAFEXCEL_ADDR_HI(atok);
813b356ddf0SMark Johnston 		}
814b356ddf0SMark Johnston 	}
815b356ddf0SMark Johnston }
816b356ddf0SMark Johnston 
817b356ddf0SMark Johnston static void
818b356ddf0SMark Johnston safexcel_dma_alloc_mem_cb(void *arg, bus_dma_segment_t *segs, int nseg,
819b356ddf0SMark Johnston     int error)
820b356ddf0SMark Johnston {
821b356ddf0SMark Johnston 	struct safexcel_dma_mem *sdm;
822b356ddf0SMark Johnston 
823b356ddf0SMark Johnston 	if (error != 0)
824b356ddf0SMark Johnston 		return;
825b356ddf0SMark Johnston 
826b356ddf0SMark Johnston 	KASSERT(nseg == 1, ("%s: nsegs is %d", __func__, nseg));
827b356ddf0SMark Johnston 	sdm = arg;
828b356ddf0SMark Johnston 	sdm->paddr = segs->ds_addr;
829b356ddf0SMark Johnston }
830b356ddf0SMark Johnston 
831b356ddf0SMark Johnston static int
832b356ddf0SMark Johnston safexcel_dma_alloc_mem(struct safexcel_softc *sc, struct safexcel_dma_mem *sdm,
833b356ddf0SMark Johnston     bus_size_t size)
834b356ddf0SMark Johnston {
835b356ddf0SMark Johnston 	int error;
836b356ddf0SMark Johnston 
837b356ddf0SMark Johnston 	KASSERT(sdm->vaddr == NULL,
838b356ddf0SMark Johnston 	    ("%s: DMA memory descriptor in use.", __func__));
839b356ddf0SMark Johnston 
840b356ddf0SMark Johnston 	error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), /* parent */
841b356ddf0SMark Johnston 	    PAGE_SIZE, 0,		/* alignment, boundary */
842b356ddf0SMark Johnston 	    BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
843b356ddf0SMark Johnston 	    BUS_SPACE_MAXADDR,		/* highaddr */
844b356ddf0SMark Johnston 	    NULL, NULL,			/* filtfunc, filtfuncarg */
845b356ddf0SMark Johnston 	    size, 1,			/* maxsize, nsegments */
846b356ddf0SMark Johnston 	    size, BUS_DMA_COHERENT,	/* maxsegsz, flags */
847b356ddf0SMark Johnston 	    NULL, NULL,			/* lockfunc, lockfuncarg */
848b356ddf0SMark Johnston 	    &sdm->tag);			/* dmat */
849b356ddf0SMark Johnston 	if (error != 0) {
850b356ddf0SMark Johnston 		device_printf(sc->sc_dev,
851b356ddf0SMark Johnston 		    "failed to allocate busdma tag, error %d\n", error);
852b356ddf0SMark Johnston 		goto err1;
853b356ddf0SMark Johnston 	}
854b356ddf0SMark Johnston 
855b356ddf0SMark Johnston 	error = bus_dmamem_alloc(sdm->tag, (void **)&sdm->vaddr,
856b356ddf0SMark Johnston 	    BUS_DMA_WAITOK | BUS_DMA_ZERO | BUS_DMA_COHERENT, &sdm->map);
857b356ddf0SMark Johnston 	if (error != 0) {
858b356ddf0SMark Johnston 		device_printf(sc->sc_dev,
859b356ddf0SMark Johnston 		    "failed to allocate DMA safe memory, error %d\n", error);
860b356ddf0SMark Johnston 		goto err2;
861b356ddf0SMark Johnston 	}
862b356ddf0SMark Johnston 
863b356ddf0SMark Johnston 	error = bus_dmamap_load(sdm->tag, sdm->map, sdm->vaddr, size,
864b356ddf0SMark Johnston 	    safexcel_dma_alloc_mem_cb, sdm, BUS_DMA_NOWAIT);
865b356ddf0SMark Johnston 	if (error != 0) {
866b356ddf0SMark Johnston 		device_printf(sc->sc_dev,
867b356ddf0SMark Johnston 		    "cannot get address of the DMA memory, error %d\n", error);
868b356ddf0SMark Johnston 		goto err3;
869b356ddf0SMark Johnston 	}
870b356ddf0SMark Johnston 
871b356ddf0SMark Johnston 	return (0);
872b356ddf0SMark Johnston err3:
873b356ddf0SMark Johnston 	bus_dmamem_free(sdm->tag, sdm->vaddr, sdm->map);
874b356ddf0SMark Johnston err2:
875b356ddf0SMark Johnston 	bus_dma_tag_destroy(sdm->tag);
876b356ddf0SMark Johnston err1:
877b356ddf0SMark Johnston 	sdm->vaddr = NULL;
878b356ddf0SMark Johnston 
879b356ddf0SMark Johnston 	return (error);
880b356ddf0SMark Johnston }
881b356ddf0SMark Johnston 
882b356ddf0SMark Johnston static void
883b356ddf0SMark Johnston safexcel_dma_free_mem(struct safexcel_dma_mem *sdm)
884b356ddf0SMark Johnston {
885b356ddf0SMark Johnston 	bus_dmamap_unload(sdm->tag, sdm->map);
886b356ddf0SMark Johnston 	bus_dmamem_free(sdm->tag, sdm->vaddr, sdm->map);
887b356ddf0SMark Johnston 	bus_dma_tag_destroy(sdm->tag);
888b356ddf0SMark Johnston }
889b356ddf0SMark Johnston 
890b356ddf0SMark Johnston static void
891b356ddf0SMark Johnston safexcel_dma_free_rings(struct safexcel_softc *sc)
892b356ddf0SMark Johnston {
893b356ddf0SMark Johnston 	struct safexcel_ring *ring;
894b356ddf0SMark Johnston 	int i;
895b356ddf0SMark Johnston 
896b356ddf0SMark Johnston 	for (i = 0; i < sc->sc_config.rings; i++) {
897b356ddf0SMark Johnston 		ring = &sc->sc_ring[i];
898b356ddf0SMark Johnston 		safexcel_dma_free_mem(&ring->cdr.dma);
899b356ddf0SMark Johnston 		safexcel_dma_free_mem(&ring->dma_atok);
900b356ddf0SMark Johnston 		safexcel_dma_free_mem(&ring->rdr.dma);
901b356ddf0SMark Johnston 		bus_dma_tag_destroy(ring->data_dtag);
902b356ddf0SMark Johnston 		mtx_destroy(&ring->mtx);
903b356ddf0SMark Johnston 	}
904b356ddf0SMark Johnston }
905b356ddf0SMark Johnston 
906b356ddf0SMark Johnston static int
907b356ddf0SMark Johnston safexcel_dma_init(struct safexcel_softc *sc)
908b356ddf0SMark Johnston {
909b356ddf0SMark Johnston 	struct safexcel_ring *ring;
91039523b48SMark Johnston 	bus_size_t size;
91139523b48SMark Johnston 	int error, i;
912b356ddf0SMark Johnston 
913b356ddf0SMark Johnston 	for (i = 0; i < sc->sc_config.rings; i++) {
914b356ddf0SMark Johnston 		ring = &sc->sc_ring[i];
915b356ddf0SMark Johnston 
916b356ddf0SMark Johnston 		error = bus_dma_tag_create(
917b356ddf0SMark Johnston 		    bus_get_dma_tag(sc->sc_dev),/* parent */
918b356ddf0SMark Johnston 		    1, 0,			/* alignment, boundary */
919b356ddf0SMark Johnston 		    BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
920b356ddf0SMark Johnston 		    BUS_SPACE_MAXADDR,		/* highaddr */
921b356ddf0SMark Johnston 		    NULL, NULL,			/* filtfunc, filtfuncarg */
922b356ddf0SMark Johnston 		    SAFEXCEL_MAX_REQUEST_SIZE,	/* maxsize */
923b356ddf0SMark Johnston 		    SAFEXCEL_MAX_FRAGMENTS,	/* nsegments */
924b356ddf0SMark Johnston 		    SAFEXCEL_MAX_REQUEST_SIZE,	/* maxsegsz */
925b356ddf0SMark Johnston 		    BUS_DMA_COHERENT,		/* flags */
926b356ddf0SMark Johnston 		    NULL, NULL,			/* lockfunc, lockfuncarg */
927b356ddf0SMark Johnston 		    &ring->data_dtag);		/* dmat */
928b356ddf0SMark Johnston 		if (error != 0) {
929b356ddf0SMark Johnston 			device_printf(sc->sc_dev,
930b356ddf0SMark Johnston 			    "bus_dma_tag_create main failed; error %d\n", error);
931b356ddf0SMark Johnston 			return (error);
932b356ddf0SMark Johnston 		}
933b356ddf0SMark Johnston 
934b356ddf0SMark Johnston 		size = sizeof(uint32_t) * sc->sc_config.cd_offset *
935b356ddf0SMark Johnston 		    SAFEXCEL_RING_SIZE;
936b356ddf0SMark Johnston 		error = safexcel_dma_alloc_mem(sc, &ring->cdr.dma, size);
937b356ddf0SMark Johnston 		if (error != 0) {
938b356ddf0SMark Johnston 			device_printf(sc->sc_dev,
939b356ddf0SMark Johnston 			    "failed to allocate CDR DMA memory, error %d\n",
940b356ddf0SMark Johnston 			    error);
941b356ddf0SMark Johnston 			goto err;
942b356ddf0SMark Johnston 		}
943b356ddf0SMark Johnston 		ring->cdr.desc =
944b356ddf0SMark Johnston 		    (struct safexcel_cmd_descr *)ring->cdr.dma.vaddr;
945b356ddf0SMark Johnston 
946b356ddf0SMark Johnston 		/* Allocate additional CDR token memory. */
94739523b48SMark Johnston 		size = (bus_size_t)sc->sc_config.atok_offset *
94839523b48SMark Johnston 		    SAFEXCEL_RING_SIZE;
94939523b48SMark Johnston 		error = safexcel_dma_alloc_mem(sc, &ring->dma_atok, size);
950b356ddf0SMark Johnston 		if (error != 0) {
951b356ddf0SMark Johnston 			device_printf(sc->sc_dev,
952b356ddf0SMark Johnston 			    "failed to allocate atoken DMA memory, error %d\n",
953b356ddf0SMark Johnston 			    error);
954b356ddf0SMark Johnston 			goto err;
955b356ddf0SMark Johnston 		}
956b356ddf0SMark Johnston 
957b356ddf0SMark Johnston 		size = sizeof(uint32_t) * sc->sc_config.rd_offset *
958b356ddf0SMark Johnston 		    SAFEXCEL_RING_SIZE;
959b356ddf0SMark Johnston 		error = safexcel_dma_alloc_mem(sc, &ring->rdr.dma, size);
960b356ddf0SMark Johnston 		if (error) {
961b356ddf0SMark Johnston 			device_printf(sc->sc_dev,
962b356ddf0SMark Johnston 			    "failed to allocate RDR DMA memory, error %d\n",
963b356ddf0SMark Johnston 			    error);
964b356ddf0SMark Johnston 			goto err;
965b356ddf0SMark Johnston 		}
966b356ddf0SMark Johnston 		ring->rdr.desc =
967b356ddf0SMark Johnston 		    (struct safexcel_res_descr *)ring->rdr.dma.vaddr;
968b356ddf0SMark Johnston 	}
969b356ddf0SMark Johnston 
970b356ddf0SMark Johnston 	return (0);
971b356ddf0SMark Johnston err:
972b356ddf0SMark Johnston 	safexcel_dma_free_rings(sc);
973b356ddf0SMark Johnston 	return (error);
974b356ddf0SMark Johnston }
975b356ddf0SMark Johnston 
976b356ddf0SMark Johnston static void
977b356ddf0SMark Johnston safexcel_deinit_hw(struct safexcel_softc *sc)
978b356ddf0SMark Johnston {
979b356ddf0SMark Johnston 	safexcel_hw_reset_rings(sc);
980b356ddf0SMark Johnston 	safexcel_dma_free_rings(sc);
981b356ddf0SMark Johnston }
982b356ddf0SMark Johnston 
983b356ddf0SMark Johnston static int
984b356ddf0SMark Johnston safexcel_init_hw(struct safexcel_softc *sc)
985b356ddf0SMark Johnston {
986b356ddf0SMark Johnston 	int pe;
987b356ddf0SMark Johnston 
988b356ddf0SMark Johnston 	/* 23.3.7 Initialization */
989b356ddf0SMark Johnston 	if (safexcel_configure(sc) != 0)
990b356ddf0SMark Johnston 		return (EINVAL);
991b356ddf0SMark Johnston 
992b356ddf0SMark Johnston 	if (safexcel_dma_init(sc) != 0)
993b356ddf0SMark Johnston 		return (ENOMEM);
994b356ddf0SMark Johnston 
995b356ddf0SMark Johnston 	safexcel_init_rings(sc);
996b356ddf0SMark Johnston 
997b356ddf0SMark Johnston 	safexcel_init_hia_bus_access(sc);
998b356ddf0SMark Johnston 
999b356ddf0SMark Johnston 	/* 23.3.7.2 Disable EIP-97 global Interrupts */
1000b356ddf0SMark Johnston 	safexcel_disable_global_interrupts(sc);
1001b356ddf0SMark Johnston 
1002b356ddf0SMark Johnston 	for (pe = 0; pe < sc->sc_config.pes; pe++) {
1003b356ddf0SMark Johnston 		/* 23.3.7.3 Configure Data Fetch Engine */
1004b356ddf0SMark Johnston 		safexcel_configure_dfe_engine(sc, pe);
1005b356ddf0SMark Johnston 
1006b356ddf0SMark Johnston 		/* 23.3.7.4 Configure Data Store Engine */
1007b356ddf0SMark Johnston 		if (safexcel_configure_dse(sc, pe)) {
1008b356ddf0SMark Johnston 			safexcel_deinit_hw(sc);
1009b356ddf0SMark Johnston 			return (-1);
1010b356ddf0SMark Johnston 		}
1011b356ddf0SMark Johnston 
1012b356ddf0SMark Johnston 		/* 23.3.7.5 1. Protocol enables */
1013b356ddf0SMark Johnston 		SAFEXCEL_WRITE(sc,
1014b356ddf0SMark Johnston 		    SAFEXCEL_PE(sc) + SAFEXCEL_PE_EIP96_FUNCTION_EN(pe),
1015b356ddf0SMark Johnston 		    0xffffffff);
1016b356ddf0SMark Johnston 		SAFEXCEL_WRITE(sc,
1017b356ddf0SMark Johnston 		    SAFEXCEL_PE(sc) + SAFEXCEL_PE_EIP96_FUNCTION2_EN(pe),
1018b356ddf0SMark Johnston 		    0xffffffff);
1019b356ddf0SMark Johnston 	}
1020b356ddf0SMark Johnston 
1021b356ddf0SMark Johnston 	safexcel_hw_prepare_rings(sc);
1022b356ddf0SMark Johnston 
1023b356ddf0SMark Johnston 	/* 23.3.7.5 Configure the Processing Engine(s). */
1024b356ddf0SMark Johnston 	for (pe = 0; pe < sc->sc_config.pes; pe++)
1025b356ddf0SMark Johnston 		safexcel_enable_pe_engine(sc, pe);
1026b356ddf0SMark Johnston 
1027b356ddf0SMark Johnston 	safexcel_hw_setup_rings(sc);
1028b356ddf0SMark Johnston 
1029b356ddf0SMark Johnston 	return (0);
1030b356ddf0SMark Johnston }
1031b356ddf0SMark Johnston 
1032b356ddf0SMark Johnston static int
1033b356ddf0SMark Johnston safexcel_setup_dev_interrupts(struct safexcel_softc *sc)
1034b356ddf0SMark Johnston {
1035e934d455SMark Johnston 	int error, i, j;
1036b356ddf0SMark Johnston 
1037b356ddf0SMark Johnston 	for (i = 0; i < SAFEXCEL_MAX_RINGS && sc->sc_intr[i] != NULL; i++) {
1038b356ddf0SMark Johnston 		sc->sc_ih[i].sc = sc;
1039b356ddf0SMark Johnston 		sc->sc_ih[i].ring = i;
1040b356ddf0SMark Johnston 
1041b356ddf0SMark Johnston 		if (bus_setup_intr(sc->sc_dev, sc->sc_intr[i],
1042b356ddf0SMark Johnston 		    INTR_TYPE_NET | INTR_MPSAFE, NULL, safexcel_ring_intr,
1043b356ddf0SMark Johnston 		    &sc->sc_ih[i], &sc->sc_ih[i].handle)) {
1044b356ddf0SMark Johnston 			device_printf(sc->sc_dev,
1045b356ddf0SMark Johnston 			    "couldn't setup interrupt %d\n", i);
1046b356ddf0SMark Johnston 			goto err;
1047b356ddf0SMark Johnston 		}
1048e934d455SMark Johnston 
1049e934d455SMark Johnston 		error = bus_bind_intr(sc->sc_dev, sc->sc_intr[i], i % mp_ncpus);
1050e934d455SMark Johnston 		if (error != 0)
1051e934d455SMark Johnston 			device_printf(sc->sc_dev,
1052e934d455SMark Johnston 			    "failed to bind ring %d\n", error);
1053b356ddf0SMark Johnston 	}
1054b356ddf0SMark Johnston 
1055b356ddf0SMark Johnston 	return (0);
1056b356ddf0SMark Johnston 
1057b356ddf0SMark Johnston err:
1058b356ddf0SMark Johnston 	for (j = 0; j < i; j++)
1059b356ddf0SMark Johnston 		bus_teardown_intr(sc->sc_dev, sc->sc_intr[j],
1060b356ddf0SMark Johnston 		    sc->sc_ih[j].handle);
1061b356ddf0SMark Johnston 
1062b356ddf0SMark Johnston 	return (ENXIO);
1063b356ddf0SMark Johnston }
1064b356ddf0SMark Johnston 
1065b356ddf0SMark Johnston static void
1066b356ddf0SMark Johnston safexcel_teardown_dev_interrupts(struct safexcel_softc *sc)
1067b356ddf0SMark Johnston {
1068b356ddf0SMark Johnston 	int i;
1069b356ddf0SMark Johnston 
1070b356ddf0SMark Johnston 	for (i = 0; i < SAFEXCEL_MAX_RINGS; i++)
1071b356ddf0SMark Johnston 		bus_teardown_intr(sc->sc_dev, sc->sc_intr[i],
1072b356ddf0SMark Johnston 		    sc->sc_ih[i].handle);
1073b356ddf0SMark Johnston }
1074b356ddf0SMark Johnston 
1075b356ddf0SMark Johnston static int
1076b356ddf0SMark Johnston safexcel_alloc_dev_resources(struct safexcel_softc *sc)
1077b356ddf0SMark Johnston {
1078b356ddf0SMark Johnston 	char name[16];
1079b356ddf0SMark Johnston 	device_t dev;
1080b356ddf0SMark Johnston 	phandle_t node;
1081b356ddf0SMark Johnston 	int error, i, rid;
1082b356ddf0SMark Johnston 
1083b356ddf0SMark Johnston 	dev = sc->sc_dev;
1084b356ddf0SMark Johnston 	node = ofw_bus_get_node(dev);
1085b356ddf0SMark Johnston 
1086b356ddf0SMark Johnston 	rid = 0;
1087b356ddf0SMark Johnston 	sc->sc_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
1088b356ddf0SMark Johnston 	    RF_ACTIVE);
1089b356ddf0SMark Johnston 	if (sc->sc_res == NULL) {
1090b356ddf0SMark Johnston 		device_printf(dev, "couldn't allocate memory resources\n");
1091b356ddf0SMark Johnston 		return (ENXIO);
1092b356ddf0SMark Johnston 	}
1093b356ddf0SMark Johnston 
1094b356ddf0SMark Johnston 	for (i = 0; i < SAFEXCEL_MAX_RINGS; i++) {
1095b356ddf0SMark Johnston 		(void)snprintf(name, sizeof(name), "ring%d", i);
1096b356ddf0SMark Johnston 		error = ofw_bus_find_string_index(node, "interrupt-names", name,
1097b356ddf0SMark Johnston 		    &rid);
1098b356ddf0SMark Johnston 		if (error != 0)
1099b356ddf0SMark Johnston 			break;
1100b356ddf0SMark Johnston 
1101b356ddf0SMark Johnston 		sc->sc_intr[i] = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
1102b356ddf0SMark Johnston 		    RF_ACTIVE | RF_SHAREABLE);
1103b356ddf0SMark Johnston 		if (sc->sc_intr[i] == NULL) {
1104b356ddf0SMark Johnston 			error = ENXIO;
1105b356ddf0SMark Johnston 			goto out;
1106b356ddf0SMark Johnston 		}
1107b356ddf0SMark Johnston 	}
1108b356ddf0SMark Johnston 	if (i == 0) {
1109b356ddf0SMark Johnston 		device_printf(dev, "couldn't allocate interrupt resources\n");
1110b356ddf0SMark Johnston 		error = ENXIO;
1111b356ddf0SMark Johnston 		goto out;
1112b356ddf0SMark Johnston 	}
1113b356ddf0SMark Johnston 
1114b356ddf0SMark Johnston 	return (0);
1115b356ddf0SMark Johnston 
1116b356ddf0SMark Johnston out:
1117b356ddf0SMark Johnston 	for (i = 0; i < SAFEXCEL_MAX_RINGS && sc->sc_intr[i] != NULL; i++)
1118b356ddf0SMark Johnston 		bus_release_resource(dev, SYS_RES_IRQ,
1119b356ddf0SMark Johnston 		    rman_get_rid(sc->sc_intr[i]), sc->sc_intr[i]);
1120b356ddf0SMark Johnston 	bus_release_resource(dev, SYS_RES_MEMORY, rman_get_rid(sc->sc_res),
1121b356ddf0SMark Johnston 	    sc->sc_res);
1122b356ddf0SMark Johnston 	return (error);
1123b356ddf0SMark Johnston }
1124b356ddf0SMark Johnston 
1125b356ddf0SMark Johnston static void
1126b356ddf0SMark Johnston safexcel_free_dev_resources(struct safexcel_softc *sc)
1127b356ddf0SMark Johnston {
1128b356ddf0SMark Johnston 	int i;
1129b356ddf0SMark Johnston 
1130b356ddf0SMark Johnston 	for (i = 0; i < SAFEXCEL_MAX_RINGS && sc->sc_intr[i] != NULL; i++)
1131b356ddf0SMark Johnston 		bus_release_resource(sc->sc_dev, SYS_RES_IRQ,
1132b356ddf0SMark Johnston 		    rman_get_rid(sc->sc_intr[i]), sc->sc_intr[i]);
1133b356ddf0SMark Johnston 	if (sc->sc_res != NULL)
1134b356ddf0SMark Johnston 		bus_release_resource(sc->sc_dev, SYS_RES_MEMORY,
1135b356ddf0SMark Johnston 		    rman_get_rid(sc->sc_res), sc->sc_res);
1136b356ddf0SMark Johnston }
1137b356ddf0SMark Johnston 
1138b356ddf0SMark Johnston static int
1139b356ddf0SMark Johnston safexcel_probe(device_t dev)
1140b356ddf0SMark Johnston {
1141b356ddf0SMark Johnston 	struct safexcel_softc *sc;
1142b356ddf0SMark Johnston 
1143b356ddf0SMark Johnston 	if (!ofw_bus_status_okay(dev))
1144b356ddf0SMark Johnston 		return (ENXIO);
1145b356ddf0SMark Johnston 
1146b356ddf0SMark Johnston 	sc = device_get_softc(dev);
1147b356ddf0SMark Johnston 	sc->sc_type = ofw_bus_search_compatible(dev, safexcel_compat)->ocd_data;
1148b356ddf0SMark Johnston 	if (sc->sc_type == 0)
1149b356ddf0SMark Johnston 		return (ENXIO);
1150b356ddf0SMark Johnston 
1151b356ddf0SMark Johnston 	device_set_desc(dev, "SafeXcel EIP-97 crypto accelerator");
1152b356ddf0SMark Johnston 
1153b356ddf0SMark Johnston 	return (BUS_PROBE_DEFAULT);
1154b356ddf0SMark Johnston }
1155b356ddf0SMark Johnston 
1156b356ddf0SMark Johnston static int
1157b356ddf0SMark Johnston safexcel_attach(device_t dev)
1158b356ddf0SMark Johnston {
11590371c3faSMark Johnston 	struct sysctl_ctx_list *ctx;
11600371c3faSMark Johnston 	struct sysctl_oid *oid;
11610371c3faSMark Johnston 	struct sysctl_oid_list *children;
1162b356ddf0SMark Johnston 	struct safexcel_softc *sc;
1163b356ddf0SMark Johnston 	struct safexcel_request *req;
1164b356ddf0SMark Johnston 	struct safexcel_ring *ring;
1165b356ddf0SMark Johnston 	int i, j, ringidx;
1166b356ddf0SMark Johnston 
1167b356ddf0SMark Johnston 	sc = device_get_softc(dev);
1168b356ddf0SMark Johnston 	sc->sc_dev = dev;
1169b356ddf0SMark Johnston 	sc->sc_cid = -1;
1170b356ddf0SMark Johnston 
1171b356ddf0SMark Johnston 	if (safexcel_alloc_dev_resources(sc))
1172b356ddf0SMark Johnston 		goto err;
1173b356ddf0SMark Johnston 
1174b356ddf0SMark Johnston 	if (safexcel_setup_dev_interrupts(sc))
1175b356ddf0SMark Johnston 		goto err1;
1176b356ddf0SMark Johnston 
1177b356ddf0SMark Johnston 	if (safexcel_init_hw(sc))
1178b356ddf0SMark Johnston 		goto err2;
1179b356ddf0SMark Johnston 
1180b356ddf0SMark Johnston 	for (ringidx = 0; ringidx < sc->sc_config.rings; ringidx++) {
1181b356ddf0SMark Johnston 		ring = &sc->sc_ring[ringidx];
1182b356ddf0SMark Johnston 
1183b356ddf0SMark Johnston 		ring->cmd_data = sglist_alloc(SAFEXCEL_MAX_FRAGMENTS, M_WAITOK);
1184b356ddf0SMark Johnston 		ring->res_data = sglist_alloc(SAFEXCEL_MAX_FRAGMENTS, M_WAITOK);
1185b356ddf0SMark Johnston 
11861a6ffed5SMark Johnston 		for (i = 0; i < SAFEXCEL_RING_SIZE; i++) {
1187b356ddf0SMark Johnston 			req = &ring->requests[i];
1188b356ddf0SMark Johnston 			req->sc = sc;
1189e934d455SMark Johnston 			req->ringidx = ringidx;
1190b356ddf0SMark Johnston 			if (bus_dmamap_create(ring->data_dtag,
1191b356ddf0SMark Johnston 			    BUS_DMA_COHERENT, &req->dmap) != 0) {
1192b356ddf0SMark Johnston 				for (j = 0; j < i; j++)
1193b356ddf0SMark Johnston 					bus_dmamap_destroy(ring->data_dtag,
1194b356ddf0SMark Johnston 					    ring->requests[j].dmap);
1195b356ddf0SMark Johnston 				goto err2;
1196b356ddf0SMark Johnston 			}
1197b356ddf0SMark Johnston 			if (safexcel_dma_alloc_mem(sc, &req->ctx,
1198b356ddf0SMark Johnston 			    sizeof(struct safexcel_context_record)) != 0) {
1199b356ddf0SMark Johnston 				for (j = 0; j < i; j++) {
1200b356ddf0SMark Johnston 					bus_dmamap_destroy(ring->data_dtag,
1201b356ddf0SMark Johnston 					    ring->requests[j].dmap);
1202b356ddf0SMark Johnston 					safexcel_dma_free_mem(
1203b356ddf0SMark Johnston 					    &ring->requests[j].ctx);
1204b356ddf0SMark Johnston 				}
1205b356ddf0SMark Johnston 				goto err2;
1206b356ddf0SMark Johnston 			}
1207b356ddf0SMark Johnston 		}
1208b356ddf0SMark Johnston 	}
1209b356ddf0SMark Johnston 
12100371c3faSMark Johnston 	ctx = device_get_sysctl_ctx(dev);
12110371c3faSMark Johnston 	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
1212b356ddf0SMark Johnston 	    OID_AUTO, "debug", CTLFLAG_RWTUN, &sc->sc_debug, 0,
1213b356ddf0SMark Johnston 	    "Debug message verbosity");
1214b356ddf0SMark Johnston 
12150371c3faSMark Johnston 	oid = device_get_sysctl_tree(sc->sc_dev);
12160371c3faSMark Johnston 	children = SYSCTL_CHILDREN(oid);
12170371c3faSMark Johnston 	oid = SYSCTL_ADD_NODE(ctx, children, OID_AUTO, "stats",
12180371c3faSMark Johnston 	    CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "statistics");
12190371c3faSMark Johnston 	children = SYSCTL_CHILDREN(oid);
12200371c3faSMark Johnston 
12210371c3faSMark Johnston 	sc->sc_req_alloc_failures = counter_u64_alloc(M_WAITOK);
12220371c3faSMark Johnston 	SYSCTL_ADD_COUNTER_U64(ctx, children, OID_AUTO, "req_alloc_failures",
12230371c3faSMark Johnston 	    CTLFLAG_RD, &sc->sc_req_alloc_failures,
12240371c3faSMark Johnston 	    "Number of request allocation failures");
12250371c3faSMark Johnston 	sc->sc_cdesc_alloc_failures = counter_u64_alloc(M_WAITOK);
12260371c3faSMark Johnston 	SYSCTL_ADD_COUNTER_U64(ctx, children, OID_AUTO, "cdesc_alloc_failures",
12270371c3faSMark Johnston 	    CTLFLAG_RD, &sc->sc_cdesc_alloc_failures,
12280371c3faSMark Johnston 	    "Number of command descriptor ring overflows");
12290371c3faSMark Johnston 	sc->sc_rdesc_alloc_failures = counter_u64_alloc(M_WAITOK);
12300371c3faSMark Johnston 	SYSCTL_ADD_COUNTER_U64(ctx, children, OID_AUTO, "rdesc_alloc_failures",
12310371c3faSMark Johnston 	    CTLFLAG_RD, &sc->sc_rdesc_alloc_failures,
12320371c3faSMark Johnston 	    "Number of result descriptor ring overflows");
12330371c3faSMark Johnston 
1234b356ddf0SMark Johnston 	sc->sc_cid = crypto_get_driverid(dev, sizeof(struct safexcel_session),
1235b356ddf0SMark Johnston 	    CRYPTOCAP_F_HARDWARE);
1236b356ddf0SMark Johnston 	if (sc->sc_cid < 0)
1237b356ddf0SMark Johnston 		goto err2;
1238b356ddf0SMark Johnston 
1239b356ddf0SMark Johnston 	return (0);
1240b356ddf0SMark Johnston 
1241b356ddf0SMark Johnston err2:
1242b356ddf0SMark Johnston 	safexcel_teardown_dev_interrupts(sc);
1243b356ddf0SMark Johnston err1:
1244b356ddf0SMark Johnston 	safexcel_free_dev_resources(sc);
1245b356ddf0SMark Johnston err:
1246b356ddf0SMark Johnston 	return (ENXIO);
1247b356ddf0SMark Johnston }
1248b356ddf0SMark Johnston 
1249b356ddf0SMark Johnston static int
1250b356ddf0SMark Johnston safexcel_detach(device_t dev)
1251b356ddf0SMark Johnston {
1252b356ddf0SMark Johnston 	struct safexcel_ring *ring;
1253b356ddf0SMark Johnston 	struct safexcel_softc *sc;
1254b356ddf0SMark Johnston 	int i, ringidx;
1255b356ddf0SMark Johnston 
1256b356ddf0SMark Johnston 	sc = device_get_softc(dev);
1257b356ddf0SMark Johnston 
1258b356ddf0SMark Johnston 	if (sc->sc_cid >= 0)
1259b356ddf0SMark Johnston 		crypto_unregister_all(sc->sc_cid);
12600371c3faSMark Johnston 
12610371c3faSMark Johnston 	counter_u64_free(sc->sc_req_alloc_failures);
12620371c3faSMark Johnston 	counter_u64_free(sc->sc_cdesc_alloc_failures);
12630371c3faSMark Johnston 	counter_u64_free(sc->sc_rdesc_alloc_failures);
12640371c3faSMark Johnston 
1265b356ddf0SMark Johnston 	for (ringidx = 0; ringidx < sc->sc_config.rings; ringidx++) {
1266b356ddf0SMark Johnston 		ring = &sc->sc_ring[ringidx];
12671a6ffed5SMark Johnston 		for (i = 0; i < SAFEXCEL_RING_SIZE; i++) {
1268b356ddf0SMark Johnston 			bus_dmamap_destroy(ring->data_dtag,
1269b356ddf0SMark Johnston 			    ring->requests[i].dmap);
1270b356ddf0SMark Johnston 			safexcel_dma_free_mem(&ring->requests[i].ctx);
1271b356ddf0SMark Johnston 		}
1272b356ddf0SMark Johnston 		sglist_free(ring->cmd_data);
1273b356ddf0SMark Johnston 		sglist_free(ring->res_data);
1274b356ddf0SMark Johnston 	}
1275b356ddf0SMark Johnston 	safexcel_deinit_hw(sc);
1276b356ddf0SMark Johnston 	safexcel_teardown_dev_interrupts(sc);
1277b356ddf0SMark Johnston 	safexcel_free_dev_resources(sc);
1278b356ddf0SMark Johnston 
1279b356ddf0SMark Johnston 	return (0);
1280b356ddf0SMark Johnston }
1281b356ddf0SMark Johnston 
1282b356ddf0SMark Johnston /*
1283*5bdb8b27SMark Johnston  * Pre-compute the hash key used in GHASH, which is a block of zeroes encrypted
1284*5bdb8b27SMark Johnston  * using the cipher key.
1285*5bdb8b27SMark Johnston  */
1286*5bdb8b27SMark Johnston static void
1287*5bdb8b27SMark Johnston safexcel_setkey_ghash(const uint8_t *key, int klen, uint32_t *hashkey)
1288*5bdb8b27SMark Johnston {
1289*5bdb8b27SMark Johnston 	uint32_t ks[4 * (RIJNDAEL_MAXNR + 1)];
1290*5bdb8b27SMark Johnston 	uint8_t zeros[AES_BLOCK_LEN];
1291*5bdb8b27SMark Johnston 	int i, rounds;
1292*5bdb8b27SMark Johnston 
1293*5bdb8b27SMark Johnston 	memset(zeros, 0, sizeof(zeros));
1294*5bdb8b27SMark Johnston 
1295*5bdb8b27SMark Johnston 	rounds = rijndaelKeySetupEnc(ks, key, klen * NBBY);
1296*5bdb8b27SMark Johnston 	rijndaelEncrypt(ks, rounds, zeros, (uint8_t *)hashkey);
1297*5bdb8b27SMark Johnston 	for (i = 0; i < GMAC_BLOCK_LEN / sizeof(uint32_t); i++)
1298*5bdb8b27SMark Johnston 		hashkey[i] = htobe32(hashkey[i]);
1299*5bdb8b27SMark Johnston 
1300*5bdb8b27SMark Johnston 	explicit_bzero(ks, sizeof(ks));
1301*5bdb8b27SMark Johnston }
1302*5bdb8b27SMark Johnston 
1303*5bdb8b27SMark Johnston /*
1304*5bdb8b27SMark Johnston  * Pre-compute the combined CBC-MAC key, which consists of three keys K1, K2, K3
1305*5bdb8b27SMark Johnston  * in the hardware implementation.  K1 is the cipher key and comes last in the
1306*5bdb8b27SMark Johnston  * buffer since K2 and K3 have a fixed size of AES_BLOCK_LEN.  For now XCBC-MAC
1307*5bdb8b27SMark Johnston  * is not implemented so K2 and K3 are fixed.
1308*5bdb8b27SMark Johnston  */
1309*5bdb8b27SMark Johnston static void
1310*5bdb8b27SMark Johnston safexcel_setkey_xcbcmac(const uint8_t *key, int klen, uint32_t *hashkey)
1311*5bdb8b27SMark Johnston {
1312*5bdb8b27SMark Johnston 	int i, off;
1313*5bdb8b27SMark Johnston 
1314*5bdb8b27SMark Johnston 	memset(hashkey, 0, 2 * AES_BLOCK_LEN);
1315*5bdb8b27SMark Johnston 	off = 2 * AES_BLOCK_LEN / sizeof(uint32_t);
1316*5bdb8b27SMark Johnston 	for (i = 0; i < klen / sizeof(uint32_t); i++, key += 4)
1317*5bdb8b27SMark Johnston 		hashkey[i + off] = htobe32(le32dec(key));
1318*5bdb8b27SMark Johnston }
1319*5bdb8b27SMark Johnston 
1320*5bdb8b27SMark Johnston static void
1321*5bdb8b27SMark Johnston safexcel_setkey_hmac_digest(struct auth_hash *ahash, union authctx *ctx,
1322*5bdb8b27SMark Johnston     char *buf)
1323*5bdb8b27SMark Johnston {
1324*5bdb8b27SMark Johnston 	int hashwords, i;
1325*5bdb8b27SMark Johnston 
1326*5bdb8b27SMark Johnston 	switch (ahash->type) {
1327*5bdb8b27SMark Johnston 	case CRYPTO_SHA1_HMAC:
1328*5bdb8b27SMark Johnston 		hashwords = ahash->hashsize / sizeof(uint32_t);
1329*5bdb8b27SMark Johnston 		for (i = 0; i < hashwords; i++)
1330*5bdb8b27SMark Johnston 			((uint32_t *)buf)[i] = htobe32(ctx->sha1ctx.h.b32[i]);
1331*5bdb8b27SMark Johnston 		break;
1332*5bdb8b27SMark Johnston 	case CRYPTO_SHA2_224_HMAC:
1333*5bdb8b27SMark Johnston 		hashwords = auth_hash_hmac_sha2_256.hashsize / sizeof(uint32_t);
1334*5bdb8b27SMark Johnston 		for (i = 0; i < hashwords; i++)
1335*5bdb8b27SMark Johnston 			((uint32_t *)buf)[i] = htobe32(ctx->sha224ctx.state[i]);
1336*5bdb8b27SMark Johnston 		break;
1337*5bdb8b27SMark Johnston 	case CRYPTO_SHA2_256_HMAC:
1338*5bdb8b27SMark Johnston 		hashwords = ahash->hashsize / sizeof(uint32_t);
1339*5bdb8b27SMark Johnston 		for (i = 0; i < hashwords; i++)
1340*5bdb8b27SMark Johnston 			((uint32_t *)buf)[i] = htobe32(ctx->sha256ctx.state[i]);
1341*5bdb8b27SMark Johnston 		break;
1342*5bdb8b27SMark Johnston 	case CRYPTO_SHA2_384_HMAC:
1343*5bdb8b27SMark Johnston 		hashwords = auth_hash_hmac_sha2_512.hashsize / sizeof(uint64_t);
1344*5bdb8b27SMark Johnston 		for (i = 0; i < hashwords; i++)
1345*5bdb8b27SMark Johnston 			((uint64_t *)buf)[i] = htobe64(ctx->sha384ctx.state[i]);
1346*5bdb8b27SMark Johnston 		break;
1347*5bdb8b27SMark Johnston 	case CRYPTO_SHA2_512_HMAC:
1348*5bdb8b27SMark Johnston 		hashwords = ahash->hashsize / sizeof(uint64_t);
1349*5bdb8b27SMark Johnston 		for (i = 0; i < hashwords; i++)
1350*5bdb8b27SMark Johnston 			((uint64_t *)buf)[i] = htobe64(ctx->sha512ctx.state[i]);
1351*5bdb8b27SMark Johnston 		break;
1352*5bdb8b27SMark Johnston 	}
1353*5bdb8b27SMark Johnston }
1354*5bdb8b27SMark Johnston 
1355*5bdb8b27SMark Johnston /*
1356*5bdb8b27SMark Johnston  * Pre-compute the inner and outer digests used in the HMAC algorithm.
1357*5bdb8b27SMark Johnston  */
1358*5bdb8b27SMark Johnston static void
1359*5bdb8b27SMark Johnston safexcel_setkey_hmac(const struct crypto_session_params *csp,
1360*5bdb8b27SMark Johnston     const uint8_t *key, int klen, uint8_t *ipad, uint8_t *opad)
1361*5bdb8b27SMark Johnston {
1362*5bdb8b27SMark Johnston 	union authctx ctx;
1363*5bdb8b27SMark Johnston 	struct auth_hash *ahash;
1364*5bdb8b27SMark Johnston 
1365*5bdb8b27SMark Johnston 	ahash = crypto_auth_hash(csp);
1366*5bdb8b27SMark Johnston 	hmac_init_ipad(ahash, key, klen, &ctx);
1367*5bdb8b27SMark Johnston 	safexcel_setkey_hmac_digest(ahash, &ctx, ipad);
1368*5bdb8b27SMark Johnston 	hmac_init_opad(ahash, key, klen, &ctx);
1369*5bdb8b27SMark Johnston 	safexcel_setkey_hmac_digest(ahash, &ctx, opad);
1370*5bdb8b27SMark Johnston 	explicit_bzero(&ctx, ahash->ctxsize);
1371*5bdb8b27SMark Johnston }
1372*5bdb8b27SMark Johnston 
1373*5bdb8b27SMark Johnston static void
1374*5bdb8b27SMark Johnston safexcel_setkey_xts(const uint8_t *key, int klen, uint8_t *tweakkey)
1375*5bdb8b27SMark Johnston {
1376*5bdb8b27SMark Johnston 	memcpy(tweakkey, key + klen, klen);
1377*5bdb8b27SMark Johnston }
1378*5bdb8b27SMark Johnston 
1379*5bdb8b27SMark Johnston /*
1380*5bdb8b27SMark Johnston  * Populate a context record with paramters from a session.  Some consumers
1381*5bdb8b27SMark Johnston  * specify per-request keys, in which case the context must be re-initialized
1382*5bdb8b27SMark Johnston  * for each request.
1383b356ddf0SMark Johnston  */
1384b356ddf0SMark Johnston static int
1385*5bdb8b27SMark Johnston safexcel_set_context(struct safexcel_context_record *ctx, int op,
1386*5bdb8b27SMark Johnston     const uint8_t *ckey, const uint8_t *akey, struct safexcel_session *sess)
1387b356ddf0SMark Johnston {
1388b356ddf0SMark Johnston 	const struct crypto_session_params *csp;
1389b356ddf0SMark Johnston 	uint8_t *data;
1390*5bdb8b27SMark Johnston 	uint32_t ctrl0, ctrl1;
1391*5bdb8b27SMark Johnston 	int aklen, alg, cklen, off;
1392b356ddf0SMark Johnston 
1393*5bdb8b27SMark Johnston 	csp = crypto_get_params(sess->cses);
1394*5bdb8b27SMark Johnston 	aklen = csp->csp_auth_klen;
1395*5bdb8b27SMark Johnston 	cklen = csp->csp_cipher_klen;
1396*5bdb8b27SMark Johnston 	if (csp->csp_cipher_alg == CRYPTO_AES_XTS)
1397*5bdb8b27SMark Johnston 		cklen /= 2;
1398b356ddf0SMark Johnston 
1399*5bdb8b27SMark Johnston 	ctrl0 = sess->alg | sess->digest | sess->hash;
1400*5bdb8b27SMark Johnston 	ctrl1 = sess->mode;
1401*5bdb8b27SMark Johnston 
1402b356ddf0SMark Johnston 	data = (uint8_t *)ctx->data;
1403b356ddf0SMark Johnston 	if (csp->csp_cipher_alg != 0) {
1404*5bdb8b27SMark Johnston 		memcpy(data, ckey, cklen);
1405*5bdb8b27SMark Johnston 		off = cklen;
1406b356ddf0SMark Johnston 	} else if (csp->csp_auth_alg == CRYPTO_AES_NIST_GMAC) {
1407*5bdb8b27SMark Johnston 		memcpy(data, akey, aklen);
1408*5bdb8b27SMark Johnston 		off = aklen;
1409b356ddf0SMark Johnston 	} else {
1410b356ddf0SMark Johnston 		off = 0;
1411b356ddf0SMark Johnston 	}
1412b356ddf0SMark Johnston 
1413b356ddf0SMark Johnston 	switch (csp->csp_cipher_alg) {
1414b356ddf0SMark Johnston 	case CRYPTO_AES_NIST_GCM_16:
1415*5bdb8b27SMark Johnston 		safexcel_setkey_ghash(ckey, cklen, (uint32_t *)(data + off));
1416b356ddf0SMark Johnston 		off += GMAC_BLOCK_LEN;
1417b356ddf0SMark Johnston 		break;
1418b356ddf0SMark Johnston 	case CRYPTO_AES_CCM_16:
1419*5bdb8b27SMark Johnston 		safexcel_setkey_xcbcmac(ckey, cklen, (uint32_t *)(data + off));
1420*5bdb8b27SMark Johnston 		off += AES_BLOCK_LEN * 2 + cklen;
1421b356ddf0SMark Johnston 		break;
1422b356ddf0SMark Johnston 	case CRYPTO_AES_XTS:
1423*5bdb8b27SMark Johnston 		safexcel_setkey_xts(ckey, cklen, data + off);
1424*5bdb8b27SMark Johnston 		off += cklen;
1425b356ddf0SMark Johnston 		break;
1426b356ddf0SMark Johnston 	}
1427b356ddf0SMark Johnston 	switch (csp->csp_auth_alg) {
1428b356ddf0SMark Johnston 	case CRYPTO_AES_NIST_GMAC:
1429*5bdb8b27SMark Johnston 		safexcel_setkey_ghash(akey, aklen, (uint32_t *)(data + off));
1430b356ddf0SMark Johnston 		off += GMAC_BLOCK_LEN;
1431b356ddf0SMark Johnston 		break;
1432b356ddf0SMark Johnston 	case CRYPTO_SHA1_HMAC:
1433b356ddf0SMark Johnston 	case CRYPTO_SHA2_224_HMAC:
1434b356ddf0SMark Johnston 	case CRYPTO_SHA2_256_HMAC:
1435b356ddf0SMark Johnston 	case CRYPTO_SHA2_384_HMAC:
1436b356ddf0SMark Johnston 	case CRYPTO_SHA2_512_HMAC:
1437*5bdb8b27SMark Johnston 		safexcel_setkey_hmac(csp, akey, aklen,
1438*5bdb8b27SMark Johnston 		    data + off, data + off + sess->statelen);
1439*5bdb8b27SMark Johnston 		off += sess->statelen * 2;
1440b356ddf0SMark Johnston 		break;
1441b356ddf0SMark Johnston 	}
1442*5bdb8b27SMark Johnston 	ctrl0 |= SAFEXCEL_CONTROL0_SIZE(off / sizeof(uint32_t));
1443b356ddf0SMark Johnston 
1444b356ddf0SMark Johnston 	alg = csp->csp_cipher_alg;
1445b356ddf0SMark Johnston 	if (alg == 0)
1446b356ddf0SMark Johnston 		alg = csp->csp_auth_alg;
1447b356ddf0SMark Johnston 
1448b356ddf0SMark Johnston 	switch (alg) {
1449b356ddf0SMark Johnston 	case CRYPTO_AES_CCM_16:
1450*5bdb8b27SMark Johnston 		if (CRYPTO_OP_IS_ENCRYPT(op)) {
1451b356ddf0SMark Johnston 			ctrl0 |= SAFEXCEL_CONTROL0_TYPE_HASH_ENCRYPT_OUT |
1452b356ddf0SMark Johnston 			    SAFEXCEL_CONTROL0_KEY_EN;
1453b356ddf0SMark Johnston 		} else {
1454b356ddf0SMark Johnston 			ctrl0 |= SAFEXCEL_CONTROL0_TYPE_DECRYPT_HASH_IN |
1455b356ddf0SMark Johnston 			    SAFEXCEL_CONTROL0_KEY_EN;
1456b356ddf0SMark Johnston 		}
1457b356ddf0SMark Johnston 		ctrl1 |= SAFEXCEL_CONTROL1_IV0 | SAFEXCEL_CONTROL1_IV1 |
1458b356ddf0SMark Johnston 		    SAFEXCEL_CONTROL1_IV2 | SAFEXCEL_CONTROL1_IV3;
1459b356ddf0SMark Johnston 		break;
1460b356ddf0SMark Johnston 	case CRYPTO_AES_CBC:
1461b356ddf0SMark Johnston 	case CRYPTO_AES_ICM:
1462b356ddf0SMark Johnston 	case CRYPTO_AES_XTS:
1463*5bdb8b27SMark Johnston 		if (CRYPTO_OP_IS_ENCRYPT(op)) {
1464b356ddf0SMark Johnston 			ctrl0 |= SAFEXCEL_CONTROL0_TYPE_CRYPTO_OUT |
1465b356ddf0SMark Johnston 			    SAFEXCEL_CONTROL0_KEY_EN;
1466b356ddf0SMark Johnston 			if (csp->csp_auth_alg != 0)
1467b356ddf0SMark Johnston 				ctrl0 |=
1468b356ddf0SMark Johnston 				    SAFEXCEL_CONTROL0_TYPE_ENCRYPT_HASH_OUT;
1469b356ddf0SMark Johnston 		} else {
1470b356ddf0SMark Johnston 			ctrl0 |= SAFEXCEL_CONTROL0_TYPE_CRYPTO_IN |
1471b356ddf0SMark Johnston 			    SAFEXCEL_CONTROL0_KEY_EN;
1472b356ddf0SMark Johnston 			if (csp->csp_auth_alg != 0)
1473b356ddf0SMark Johnston 				ctrl0 |= SAFEXCEL_CONTROL0_TYPE_HASH_DECRYPT_IN;
1474b356ddf0SMark Johnston 		}
1475b356ddf0SMark Johnston 		break;
1476b356ddf0SMark Johnston 	case CRYPTO_AES_NIST_GCM_16:
1477b356ddf0SMark Johnston 	case CRYPTO_AES_NIST_GMAC:
1478*5bdb8b27SMark Johnston 		if (CRYPTO_OP_IS_ENCRYPT(op) || csp->csp_auth_alg != 0) {
1479b356ddf0SMark Johnston 			ctrl0 |= SAFEXCEL_CONTROL0_TYPE_CRYPTO_OUT |
1480b356ddf0SMark Johnston 			    SAFEXCEL_CONTROL0_KEY_EN |
1481b356ddf0SMark Johnston 			    SAFEXCEL_CONTROL0_TYPE_HASH_OUT;
1482b356ddf0SMark Johnston 		} else {
1483b356ddf0SMark Johnston 			ctrl0 |= SAFEXCEL_CONTROL0_TYPE_CRYPTO_IN |
1484b356ddf0SMark Johnston 			    SAFEXCEL_CONTROL0_KEY_EN |
1485b356ddf0SMark Johnston 			    SAFEXCEL_CONTROL0_TYPE_HASH_DECRYPT_IN;
1486b356ddf0SMark Johnston 		}
1487b356ddf0SMark Johnston 		if (csp->csp_cipher_alg == CRYPTO_AES_NIST_GCM_16) {
1488b356ddf0SMark Johnston 			ctrl1 |= SAFEXCEL_CONTROL1_COUNTER_MODE |
1489b356ddf0SMark Johnston 			    SAFEXCEL_CONTROL1_IV0 | SAFEXCEL_CONTROL1_IV1 |
1490b356ddf0SMark Johnston 			    SAFEXCEL_CONTROL1_IV2;
1491b356ddf0SMark Johnston 		}
1492b356ddf0SMark Johnston 		break;
1493b356ddf0SMark Johnston 	case CRYPTO_SHA1:
1494b356ddf0SMark Johnston 	case CRYPTO_SHA2_224:
1495b356ddf0SMark Johnston 	case CRYPTO_SHA2_256:
1496b356ddf0SMark Johnston 	case CRYPTO_SHA2_384:
1497b356ddf0SMark Johnston 	case CRYPTO_SHA2_512:
1498b356ddf0SMark Johnston 		ctrl0 |= SAFEXCEL_CONTROL0_RESTART_HASH;
1499b356ddf0SMark Johnston 		/* FALLTHROUGH */
1500b356ddf0SMark Johnston 	case CRYPTO_SHA1_HMAC:
1501b356ddf0SMark Johnston 	case CRYPTO_SHA2_224_HMAC:
1502b356ddf0SMark Johnston 	case CRYPTO_SHA2_256_HMAC:
1503b356ddf0SMark Johnston 	case CRYPTO_SHA2_384_HMAC:
1504b356ddf0SMark Johnston 	case CRYPTO_SHA2_512_HMAC:
1505b356ddf0SMark Johnston 		ctrl0 |= SAFEXCEL_CONTROL0_TYPE_HASH_OUT;
1506b356ddf0SMark Johnston 		break;
1507b356ddf0SMark Johnston 	}
1508b356ddf0SMark Johnston 
1509*5bdb8b27SMark Johnston 	ctx->control0 = ctrl0;
1510*5bdb8b27SMark Johnston 	ctx->control1 = ctrl1;
1511*5bdb8b27SMark Johnston 
1512*5bdb8b27SMark Johnston 	return (off);
1513b356ddf0SMark Johnston }
1514b356ddf0SMark Johnston 
1515b356ddf0SMark Johnston /*
1516b356ddf0SMark Johnston  * Construct a no-op instruction, used to pad input tokens.
1517b356ddf0SMark Johnston  */
1518b356ddf0SMark Johnston static void
1519b356ddf0SMark Johnston safexcel_instr_nop(struct safexcel_instr **instrp)
1520b356ddf0SMark Johnston {
1521b356ddf0SMark Johnston 	struct safexcel_instr *instr;
1522b356ddf0SMark Johnston 
1523b356ddf0SMark Johnston 	instr = *instrp;
1524b356ddf0SMark Johnston 	instr->opcode = SAFEXCEL_INSTR_OPCODE_INSERT;
1525b356ddf0SMark Johnston 	instr->length = (1 << 2);
1526b356ddf0SMark Johnston 	instr->status = 0;
1527b356ddf0SMark Johnston 	instr->instructions = 0;
1528b356ddf0SMark Johnston 
1529b356ddf0SMark Johnston 	*instrp = instr + 1;
1530b356ddf0SMark Johnston }
1531b356ddf0SMark Johnston 
1532b356ddf0SMark Johnston /*
1533b356ddf0SMark Johnston  * Insert the digest of the input payload.  This is typically the last
1534b356ddf0SMark Johnston  * instruction of a sequence.
1535b356ddf0SMark Johnston  */
1536b356ddf0SMark Johnston static void
1537b356ddf0SMark Johnston safexcel_instr_insert_digest(struct safexcel_instr **instrp, int len)
1538b356ddf0SMark Johnston {
1539b356ddf0SMark Johnston 	struct safexcel_instr *instr;
1540b356ddf0SMark Johnston 
1541b356ddf0SMark Johnston 	instr = *instrp;
1542b356ddf0SMark Johnston 	instr->opcode = SAFEXCEL_INSTR_OPCODE_INSERT;
1543b356ddf0SMark Johnston 	instr->length = len;
1544b356ddf0SMark Johnston 	instr->status = SAFEXCEL_INSTR_STATUS_LAST_HASH |
1545b356ddf0SMark Johnston 	    SAFEXCEL_INSTR_STATUS_LAST_PACKET;
1546b356ddf0SMark Johnston 	instr->instructions = SAFEXCEL_INSTR_DEST_OUTPUT |
1547b356ddf0SMark Johnston 	    SAFEXCEL_INSTR_INSERT_HASH_DIGEST;
1548b356ddf0SMark Johnston 
1549b356ddf0SMark Johnston 	*instrp = instr + 1;
1550b356ddf0SMark Johnston }
1551b356ddf0SMark Johnston 
1552b356ddf0SMark Johnston /*
1553b356ddf0SMark Johnston  * Retrieve and verify a digest.
1554b356ddf0SMark Johnston  */
1555b356ddf0SMark Johnston static void
1556b356ddf0SMark Johnston safexcel_instr_retrieve_digest(struct safexcel_instr **instrp, int len)
1557b356ddf0SMark Johnston {
1558b356ddf0SMark Johnston 	struct safexcel_instr *instr;
1559b356ddf0SMark Johnston 
1560b356ddf0SMark Johnston 	instr = *instrp;
1561b356ddf0SMark Johnston 	instr->opcode = SAFEXCEL_INSTR_OPCODE_RETRIEVE;
1562b356ddf0SMark Johnston 	instr->length = len;
1563b356ddf0SMark Johnston 	instr->status = SAFEXCEL_INSTR_STATUS_LAST_HASH |
1564b356ddf0SMark Johnston 	    SAFEXCEL_INSTR_STATUS_LAST_PACKET;
1565b356ddf0SMark Johnston 	instr->instructions = SAFEXCEL_INSTR_INSERT_HASH_DIGEST;
1566b356ddf0SMark Johnston 	instr++;
1567b356ddf0SMark Johnston 
1568b356ddf0SMark Johnston 	instr->opcode = SAFEXCEL_INSTR_OPCODE_VERIFY_FIELDS;
1569b356ddf0SMark Johnston 	instr->length = len | SAFEXCEL_INSTR_VERIFY_HASH;
1570b356ddf0SMark Johnston 	instr->status = SAFEXCEL_INSTR_STATUS_LAST_HASH |
1571b356ddf0SMark Johnston 	    SAFEXCEL_INSTR_STATUS_LAST_PACKET;
1572b356ddf0SMark Johnston 	instr->instructions = SAFEXCEL_INSTR_VERIFY_PADDING;
1573b356ddf0SMark Johnston 
1574b356ddf0SMark Johnston 	*instrp = instr + 1;
1575b356ddf0SMark Johnston }
1576b356ddf0SMark Johnston 
1577b356ddf0SMark Johnston static void
1578b356ddf0SMark Johnston safexcel_instr_temp_aes_block(struct safexcel_instr **instrp)
1579b356ddf0SMark Johnston {
1580b356ddf0SMark Johnston 	struct safexcel_instr *instr;
1581b356ddf0SMark Johnston 
1582b356ddf0SMark Johnston 	instr = *instrp;
1583b356ddf0SMark Johnston 	instr->opcode = SAFEXCEL_INSTR_OPCODE_INSERT_REMOVE_RESULT;
1584b356ddf0SMark Johnston 	instr->length = 0;
1585b356ddf0SMark Johnston 	instr->status = 0;
1586b356ddf0SMark Johnston 	instr->instructions = AES_BLOCK_LEN;
1587b356ddf0SMark Johnston 	instr++;
1588b356ddf0SMark Johnston 
1589b356ddf0SMark Johnston 	instr->opcode = SAFEXCEL_INSTR_OPCODE_INSERT;
1590b356ddf0SMark Johnston 	instr->length = AES_BLOCK_LEN;
1591b356ddf0SMark Johnston 	instr->status = 0;
1592b356ddf0SMark Johnston 	instr->instructions = SAFEXCEL_INSTR_DEST_OUTPUT |
1593b356ddf0SMark Johnston 	    SAFEXCEL_INSTR_DEST_CRYPTO;
1594b356ddf0SMark Johnston 
1595b356ddf0SMark Johnston 	*instrp = instr + 1;
1596b356ddf0SMark Johnston }
1597b356ddf0SMark Johnston 
1598b356ddf0SMark Johnston /*
1599b356ddf0SMark Johnston  * Handle a request for an unauthenticated block cipher.
1600b356ddf0SMark Johnston  */
1601b356ddf0SMark Johnston static void
1602b356ddf0SMark Johnston safexcel_instr_cipher(struct safexcel_request *req,
1603b356ddf0SMark Johnston     struct safexcel_instr *instr, struct safexcel_cmd_descr *cdesc)
1604b356ddf0SMark Johnston {
1605b356ddf0SMark Johnston 	struct cryptop *crp;
1606b356ddf0SMark Johnston 
1607b356ddf0SMark Johnston 	crp = req->crp;
1608b356ddf0SMark Johnston 
1609b356ddf0SMark Johnston 	/* Insert the payload. */
1610b356ddf0SMark Johnston 	instr->opcode = SAFEXCEL_INSTR_OPCODE_DIRECTION;
1611b356ddf0SMark Johnston 	instr->length = crp->crp_payload_length;
1612b356ddf0SMark Johnston 	instr->status = SAFEXCEL_INSTR_STATUS_LAST_PACKET |
1613b356ddf0SMark Johnston 	    SAFEXCEL_INSTR_STATUS_LAST_HASH;
1614b356ddf0SMark Johnston 	instr->instructions = SAFEXCEL_INSTR_INS_LAST |
1615b356ddf0SMark Johnston 	    SAFEXCEL_INSTR_DEST_CRYPTO | SAFEXCEL_INSTR_DEST_OUTPUT;
1616b356ddf0SMark Johnston 
1617b356ddf0SMark Johnston 	cdesc->additional_cdata_size = 1;
1618b356ddf0SMark Johnston }
1619b356ddf0SMark Johnston 
1620b356ddf0SMark Johnston static void
1621b356ddf0SMark Johnston safexcel_instr_eta(struct safexcel_request *req, struct safexcel_instr *instr,
1622b356ddf0SMark Johnston     struct safexcel_cmd_descr *cdesc)
1623b356ddf0SMark Johnston {
1624b356ddf0SMark Johnston 	const struct crypto_session_params *csp;
1625b356ddf0SMark Johnston 	struct cryptop *crp;
1626b356ddf0SMark Johnston 	struct safexcel_instr *start;
1627b356ddf0SMark Johnston 
1628b356ddf0SMark Johnston 	crp = req->crp;
1629b356ddf0SMark Johnston 	csp = crypto_get_params(crp->crp_session);
1630b356ddf0SMark Johnston 	start = instr;
1631b356ddf0SMark Johnston 
1632b356ddf0SMark Johnston 	/* Insert the AAD. */
1633b356ddf0SMark Johnston 	instr->opcode = SAFEXCEL_INSTR_OPCODE_DIRECTION;
1634b356ddf0SMark Johnston 	instr->length = crp->crp_aad_length;
1635b356ddf0SMark Johnston 	instr->status = crp->crp_payload_length == 0 ?
1636b356ddf0SMark Johnston 	    SAFEXCEL_INSTR_STATUS_LAST_HASH : 0;
1637b356ddf0SMark Johnston 	instr->instructions = SAFEXCEL_INSTR_INS_LAST |
1638b356ddf0SMark Johnston 	    SAFEXCEL_INSTR_DEST_HASH;
1639b356ddf0SMark Johnston 	instr++;
1640b356ddf0SMark Johnston 
1641b356ddf0SMark Johnston 	/* Encrypt any data left in the request. */
1642b356ddf0SMark Johnston 	if (crp->crp_payload_length > 0) {
1643b356ddf0SMark Johnston 		instr->opcode = SAFEXCEL_INSTR_OPCODE_DIRECTION;
1644b356ddf0SMark Johnston 		instr->length = crp->crp_payload_length;
1645b356ddf0SMark Johnston 		instr->status = SAFEXCEL_INSTR_STATUS_LAST_HASH;
1646b356ddf0SMark Johnston 		instr->instructions = SAFEXCEL_INSTR_INS_LAST |
1647b356ddf0SMark Johnston 		    SAFEXCEL_INSTR_DEST_CRYPTO |
1648b356ddf0SMark Johnston 		    SAFEXCEL_INSTR_DEST_HASH |
1649b356ddf0SMark Johnston 		    SAFEXCEL_INSTR_DEST_OUTPUT;
1650b356ddf0SMark Johnston 		instr++;
1651b356ddf0SMark Johnston 	}
1652b356ddf0SMark Johnston 
1653b356ddf0SMark Johnston 	/*
1654b356ddf0SMark Johnston 	 * Compute the digest, or extract it and place it in the output stream.
1655b356ddf0SMark Johnston 	 */
1656b356ddf0SMark Johnston 	if (CRYPTO_OP_IS_ENCRYPT(crp->crp_op))
1657b356ddf0SMark Johnston 		safexcel_instr_insert_digest(&instr, req->sess->digestlen);
1658b356ddf0SMark Johnston 	else
1659b356ddf0SMark Johnston 		safexcel_instr_retrieve_digest(&instr, req->sess->digestlen);
1660b356ddf0SMark Johnston 	cdesc->additional_cdata_size = instr - start;
1661b356ddf0SMark Johnston }
1662b356ddf0SMark Johnston 
1663b356ddf0SMark Johnston static void
1664b356ddf0SMark Johnston safexcel_instr_sha_hash(struct safexcel_request *req,
1665b356ddf0SMark Johnston     struct safexcel_instr *instr)
1666b356ddf0SMark Johnston {
1667b356ddf0SMark Johnston 	struct cryptop *crp;
1668b356ddf0SMark Johnston 	struct safexcel_instr *start;
1669b356ddf0SMark Johnston 
1670b356ddf0SMark Johnston 	crp = req->crp;
1671b356ddf0SMark Johnston 	start = instr;
1672b356ddf0SMark Johnston 
1673b356ddf0SMark Johnston 	/* Pass the input data to the hash engine. */
1674b356ddf0SMark Johnston 	instr->opcode = SAFEXCEL_INSTR_OPCODE_DIRECTION;
1675b356ddf0SMark Johnston 	instr->length = crp->crp_payload_length;
1676b356ddf0SMark Johnston 	instr->status = SAFEXCEL_INSTR_STATUS_LAST_HASH;
1677b356ddf0SMark Johnston 	instr->instructions = SAFEXCEL_INSTR_DEST_HASH;
1678b356ddf0SMark Johnston 	instr++;
1679b356ddf0SMark Johnston 
1680b356ddf0SMark Johnston 	/* Insert the hash result into the output stream. */
1681b356ddf0SMark Johnston 	safexcel_instr_insert_digest(&instr, req->sess->digestlen);
1682b356ddf0SMark Johnston 
1683b356ddf0SMark Johnston 	/* Pad the rest of the inline instruction space. */
1684b356ddf0SMark Johnston 	while (instr != start + SAFEXCEL_MAX_ITOKENS)
1685b356ddf0SMark Johnston 		safexcel_instr_nop(&instr);
1686b356ddf0SMark Johnston }
1687b356ddf0SMark Johnston 
1688b356ddf0SMark Johnston static void
1689b356ddf0SMark Johnston safexcel_instr_ccm(struct safexcel_request *req, struct safexcel_instr *instr,
1690b356ddf0SMark Johnston     struct safexcel_cmd_descr *cdesc)
1691b356ddf0SMark Johnston {
1692b356ddf0SMark Johnston 	struct cryptop *crp;
1693b356ddf0SMark Johnston 	struct safexcel_instr *start;
1694b356ddf0SMark Johnston 	uint8_t *a0, *b0, *alenp, L;
1695b356ddf0SMark Johnston 	int aalign, blen;
1696b356ddf0SMark Johnston 
1697b356ddf0SMark Johnston 	crp = req->crp;
1698b356ddf0SMark Johnston 	start = instr;
1699b356ddf0SMark Johnston 
1700b356ddf0SMark Johnston 	/*
1701b356ddf0SMark Johnston 	 * Construct two blocks, A0 and B0, used in encryption and
1702b356ddf0SMark Johnston 	 * authentication, respectively.  A0 is embedded in the token
1703b356ddf0SMark Johnston 	 * descriptor, and B0 is inserted directly into the data stream using
1704b356ddf0SMark Johnston 	 * instructions below.
1705b356ddf0SMark Johnston 	 *
1706b356ddf0SMark Johnston 	 * OCF seems to assume a 12-byte IV, fixing L (the payload length size)
1707b356ddf0SMark Johnston 	 * at 3 bytes due to the layout of B0.  This is fine since the driver
1708b356ddf0SMark Johnston 	 * has a maximum of 65535 bytes anyway.
1709b356ddf0SMark Johnston 	 */
1710b356ddf0SMark Johnston 	blen = AES_BLOCK_LEN;
1711b356ddf0SMark Johnston 	L = 3;
1712b356ddf0SMark Johnston 
1713b356ddf0SMark Johnston 	a0 = (uint8_t *)&cdesc->control_data.token[0];
1714b356ddf0SMark Johnston 	memset(a0, 0, blen);
1715b356ddf0SMark Johnston 	a0[0] = L - 1;
1716b356ddf0SMark Johnston 	memcpy(&a0[1], req->iv, AES_CCM_IV_LEN);
1717b356ddf0SMark Johnston 
1718b356ddf0SMark Johnston 	/*
1719b356ddf0SMark Johnston 	 * Insert B0 and the AAD length into the input stream.
1720b356ddf0SMark Johnston 	 */
1721b356ddf0SMark Johnston 	instr->opcode = SAFEXCEL_INSTR_OPCODE_INSERT;
1722b356ddf0SMark Johnston 	instr->length = blen + (crp->crp_aad_length > 0 ? 2 : 0);
1723b356ddf0SMark Johnston 	instr->status = 0;
1724b356ddf0SMark Johnston 	instr->instructions = SAFEXCEL_INSTR_DEST_HASH |
1725b356ddf0SMark Johnston 	    SAFEXCEL_INSTR_INSERT_IMMEDIATE;
1726b356ddf0SMark Johnston 	instr++;
1727b356ddf0SMark Johnston 
1728b356ddf0SMark Johnston 	b0 = (uint8_t *)instr;
1729b356ddf0SMark Johnston 	memset(b0, 0, blen);
1730b356ddf0SMark Johnston 	b0[0] =
173109676137SLi-Wen Hsu 	    (L - 1) | /* payload length size */
1732b356ddf0SMark Johnston 	    ((CCM_CBC_MAX_DIGEST_LEN - 2) / 2) << 3 /* digest length */ |
1733b356ddf0SMark Johnston 	    (crp->crp_aad_length > 0 ? 1 : 0) << 6 /* AAD present bit */;
1734b356ddf0SMark Johnston 	memcpy(&b0[1], req->iv, AES_CCM_IV_LEN);
1735b356ddf0SMark Johnston 	b0[14] = crp->crp_payload_length >> 8;
1736b356ddf0SMark Johnston 	b0[15] = crp->crp_payload_length & 0xff;
1737b356ddf0SMark Johnston 	instr += blen / sizeof(*instr);
1738b356ddf0SMark Johnston 
1739b356ddf0SMark Johnston 	/* Insert the AAD length and data into the input stream. */
1740b356ddf0SMark Johnston 	if (crp->crp_aad_length > 0) {
1741b356ddf0SMark Johnston 		alenp = (uint8_t *)instr;
1742b356ddf0SMark Johnston 		alenp[0] = crp->crp_aad_length >> 8;
1743b356ddf0SMark Johnston 		alenp[1] = crp->crp_aad_length & 0xff;
1744b356ddf0SMark Johnston 		alenp[2] = 0;
1745b356ddf0SMark Johnston 		alenp[3] = 0;
1746b356ddf0SMark Johnston 		instr++;
1747b356ddf0SMark Johnston 
1748b356ddf0SMark Johnston 		instr->opcode = SAFEXCEL_INSTR_OPCODE_DIRECTION;
1749b356ddf0SMark Johnston 		instr->length = crp->crp_aad_length;
1750b356ddf0SMark Johnston 		instr->status = 0;
1751b356ddf0SMark Johnston 		instr->instructions = SAFEXCEL_INSTR_DEST_HASH;
1752b356ddf0SMark Johnston 		instr++;
1753b356ddf0SMark Johnston 
1754b356ddf0SMark Johnston 		/* Insert zero padding. */
1755b356ddf0SMark Johnston 		aalign = (crp->crp_aad_length + 2) & (blen - 1);
1756b356ddf0SMark Johnston 		instr->opcode = SAFEXCEL_INSTR_OPCODE_INSERT;
1757b356ddf0SMark Johnston 		instr->length = aalign == 0 ? 0 :
1758b356ddf0SMark Johnston 		    blen - ((crp->crp_aad_length + 2) & (blen - 1));
1759b356ddf0SMark Johnston 		instr->status = crp->crp_payload_length == 0 ?
1760b356ddf0SMark Johnston 		    SAFEXCEL_INSTR_STATUS_LAST_HASH : 0;
1761b356ddf0SMark Johnston 		instr->instructions = SAFEXCEL_INSTR_DEST_HASH;
1762b356ddf0SMark Johnston 		instr++;
1763b356ddf0SMark Johnston 	}
1764b356ddf0SMark Johnston 
1765b356ddf0SMark Johnston 	safexcel_instr_temp_aes_block(&instr);
1766b356ddf0SMark Johnston 
1767b356ddf0SMark Johnston 	/* Insert the cipher payload into the input stream. */
1768b356ddf0SMark Johnston 	if (crp->crp_payload_length > 0) {
1769b356ddf0SMark Johnston 		instr->opcode = SAFEXCEL_INSTR_OPCODE_DIRECTION;
1770b356ddf0SMark Johnston 		instr->length = crp->crp_payload_length;
1771b356ddf0SMark Johnston 		instr->status = (crp->crp_payload_length & (blen - 1)) == 0 ?
1772b356ddf0SMark Johnston 		    SAFEXCEL_INSTR_STATUS_LAST_HASH : 0;
1773b356ddf0SMark Johnston 		instr->instructions = SAFEXCEL_INSTR_DEST_OUTPUT |
1774b356ddf0SMark Johnston 		    SAFEXCEL_INSTR_DEST_CRYPTO |
1775b356ddf0SMark Johnston 		    SAFEXCEL_INSTR_DEST_HASH |
1776b356ddf0SMark Johnston 		    SAFEXCEL_INSTR_INS_LAST;
1777b356ddf0SMark Johnston 		instr++;
1778b356ddf0SMark Johnston 
1779b356ddf0SMark Johnston 		/* Insert zero padding. */
1780b356ddf0SMark Johnston 		if (crp->crp_payload_length & (blen - 1)) {
1781b356ddf0SMark Johnston 			instr->opcode = SAFEXCEL_INSTR_OPCODE_INSERT;
1782b356ddf0SMark Johnston 			instr->length = blen -
1783b356ddf0SMark Johnston 			    (crp->crp_payload_length & (blen - 1));
1784b356ddf0SMark Johnston 			instr->status = SAFEXCEL_INSTR_STATUS_LAST_HASH;
1785b356ddf0SMark Johnston 			instr->instructions = SAFEXCEL_INSTR_DEST_HASH;
1786b356ddf0SMark Johnston 			instr++;
1787b356ddf0SMark Johnston 		}
1788b356ddf0SMark Johnston 	}
1789b356ddf0SMark Johnston 
1790b356ddf0SMark Johnston 	/*
1791b356ddf0SMark Johnston 	 * Compute the digest, or extract it and place it in the output stream.
1792b356ddf0SMark Johnston 	 */
1793b356ddf0SMark Johnston 	if (CRYPTO_OP_IS_ENCRYPT(crp->crp_op))
1794b356ddf0SMark Johnston 		safexcel_instr_insert_digest(&instr, req->sess->digestlen);
1795b356ddf0SMark Johnston 	else
1796b356ddf0SMark Johnston 		safexcel_instr_retrieve_digest(&instr, req->sess->digestlen);
1797b356ddf0SMark Johnston 
1798b356ddf0SMark Johnston 	cdesc->additional_cdata_size = instr - start;
1799b356ddf0SMark Johnston }
1800b356ddf0SMark Johnston 
1801b356ddf0SMark Johnston static void
1802b356ddf0SMark Johnston safexcel_instr_gcm(struct safexcel_request *req, struct safexcel_instr *instr,
1803b356ddf0SMark Johnston     struct safexcel_cmd_descr *cdesc)
1804b356ddf0SMark Johnston {
1805b356ddf0SMark Johnston 	struct cryptop *crp;
1806b356ddf0SMark Johnston 	struct safexcel_instr *start;
1807b356ddf0SMark Johnston 
1808b356ddf0SMark Johnston 	memcpy(cdesc->control_data.token, req->iv, AES_GCM_IV_LEN);
1809b356ddf0SMark Johnston 	cdesc->control_data.token[3] = htobe32(1);
1810b356ddf0SMark Johnston 
1811b356ddf0SMark Johnston 	crp = req->crp;
1812b356ddf0SMark Johnston 	start = instr;
1813b356ddf0SMark Johnston 
1814b356ddf0SMark Johnston 	/* Insert the AAD into the input stream. */
1815b356ddf0SMark Johnston 	instr->opcode = SAFEXCEL_INSTR_OPCODE_DIRECTION;
1816b356ddf0SMark Johnston 	instr->length = crp->crp_aad_length;
1817b356ddf0SMark Johnston 	instr->status = crp->crp_payload_length == 0 ?
1818b356ddf0SMark Johnston 	    SAFEXCEL_INSTR_STATUS_LAST_HASH : 0;
1819b356ddf0SMark Johnston 	instr->instructions = SAFEXCEL_INSTR_INS_LAST |
1820b356ddf0SMark Johnston 	    SAFEXCEL_INSTR_DEST_HASH;
1821b356ddf0SMark Johnston 	instr++;
1822b356ddf0SMark Johnston 
1823b356ddf0SMark Johnston 	safexcel_instr_temp_aes_block(&instr);
1824b356ddf0SMark Johnston 
1825b356ddf0SMark Johnston 	/* Insert the cipher payload into the input stream. */
1826b356ddf0SMark Johnston 	if (crp->crp_payload_length > 0) {
1827b356ddf0SMark Johnston 		instr->opcode = SAFEXCEL_INSTR_OPCODE_DIRECTION;
1828b356ddf0SMark Johnston 		instr->length = crp->crp_payload_length;
1829b356ddf0SMark Johnston 		instr->status = SAFEXCEL_INSTR_STATUS_LAST_HASH;
1830b356ddf0SMark Johnston 		instr->instructions = SAFEXCEL_INSTR_DEST_OUTPUT |
1831b356ddf0SMark Johnston 		    SAFEXCEL_INSTR_DEST_CRYPTO | SAFEXCEL_INSTR_DEST_HASH |
1832b356ddf0SMark Johnston 		    SAFEXCEL_INSTR_INS_LAST;
1833b356ddf0SMark Johnston 		instr++;
1834b356ddf0SMark Johnston 	}
1835b356ddf0SMark Johnston 
1836b356ddf0SMark Johnston 	/*
1837b356ddf0SMark Johnston 	 * Compute the digest, or extract it and place it in the output stream.
1838b356ddf0SMark Johnston 	 */
1839b356ddf0SMark Johnston 	if (CRYPTO_OP_IS_ENCRYPT(crp->crp_op))
1840b356ddf0SMark Johnston 		safexcel_instr_insert_digest(&instr, req->sess->digestlen);
1841b356ddf0SMark Johnston 	else
1842b356ddf0SMark Johnston 		safexcel_instr_retrieve_digest(&instr, req->sess->digestlen);
1843b356ddf0SMark Johnston 
1844b356ddf0SMark Johnston 	cdesc->additional_cdata_size = instr - start;
1845b356ddf0SMark Johnston }
1846b356ddf0SMark Johnston 
1847b356ddf0SMark Johnston static void
1848b356ddf0SMark Johnston safexcel_instr_gmac(struct safexcel_request *req, struct safexcel_instr *instr,
1849b356ddf0SMark Johnston     struct safexcel_cmd_descr *cdesc)
1850b356ddf0SMark Johnston {
1851b356ddf0SMark Johnston 	struct cryptop *crp;
1852b356ddf0SMark Johnston 	struct safexcel_instr *start;
1853b356ddf0SMark Johnston 
1854b356ddf0SMark Johnston 	memcpy(cdesc->control_data.token, req->iv, AES_GCM_IV_LEN);
1855b356ddf0SMark Johnston 	cdesc->control_data.token[3] = htobe32(1);
1856b356ddf0SMark Johnston 
1857b356ddf0SMark Johnston 	crp = req->crp;
1858b356ddf0SMark Johnston 	start = instr;
1859b356ddf0SMark Johnston 
1860b356ddf0SMark Johnston 	instr->opcode = SAFEXCEL_INSTR_OPCODE_DIRECTION;
1861b356ddf0SMark Johnston 	instr->length = crp->crp_payload_length;
1862b356ddf0SMark Johnston 	instr->status = SAFEXCEL_INSTR_STATUS_LAST_HASH;
1863b356ddf0SMark Johnston 	instr->instructions = SAFEXCEL_INSTR_INS_LAST |
1864b356ddf0SMark Johnston 	    SAFEXCEL_INSTR_DEST_HASH;
1865b356ddf0SMark Johnston 	instr++;
1866b356ddf0SMark Johnston 
1867b356ddf0SMark Johnston 	safexcel_instr_temp_aes_block(&instr);
1868b356ddf0SMark Johnston 
1869b356ddf0SMark Johnston 	safexcel_instr_insert_digest(&instr, req->sess->digestlen);
1870b356ddf0SMark Johnston 
1871b356ddf0SMark Johnston 	cdesc->additional_cdata_size = instr - start;
1872b356ddf0SMark Johnston }
1873b356ddf0SMark Johnston 
1874b356ddf0SMark Johnston static void
1875b356ddf0SMark Johnston safexcel_set_token(struct safexcel_request *req)
1876b356ddf0SMark Johnston {
1877b356ddf0SMark Johnston 	const struct crypto_session_params *csp;
1878*5bdb8b27SMark Johnston 	struct cryptop *crp;
1879b356ddf0SMark Johnston 	struct safexcel_cmd_descr *cdesc;
1880*5bdb8b27SMark Johnston 	struct safexcel_context_record *ctx;
1881*5bdb8b27SMark Johnston 	struct safexcel_context_template *ctxtmp;
1882b356ddf0SMark Johnston 	struct safexcel_instr *instr;
1883b356ddf0SMark Johnston 	struct safexcel_softc *sc;
1884*5bdb8b27SMark Johnston 	const uint8_t *akey, *ckey;
1885b356ddf0SMark Johnston 	int ringidx;
1886b356ddf0SMark Johnston 
1887*5bdb8b27SMark Johnston 	crp = req->crp;
1888*5bdb8b27SMark Johnston 	csp = crypto_get_params(crp->crp_session);
1889b356ddf0SMark Johnston 	cdesc = req->cdesc;
1890b356ddf0SMark Johnston 	sc = req->sc;
1891e934d455SMark Johnston 	ringidx = req->ringidx;
1892b356ddf0SMark Johnston 
1893*5bdb8b27SMark Johnston 	akey = crp->crp_auth_key;
1894*5bdb8b27SMark Johnston 	ckey = crp->crp_cipher_key;
1895*5bdb8b27SMark Johnston 	if (akey != NULL || ckey != NULL) {
1896*5bdb8b27SMark Johnston 		/*
1897*5bdb8b27SMark Johnston 		 * If we have a per-request key we have to generate the context
1898*5bdb8b27SMark Johnston 		 * record on the fly.
1899*5bdb8b27SMark Johnston 		 */
1900*5bdb8b27SMark Johnston 		if (akey == NULL)
1901*5bdb8b27SMark Johnston 			akey = csp->csp_auth_key;
1902*5bdb8b27SMark Johnston 		if (ckey == NULL)
1903*5bdb8b27SMark Johnston 			ckey = csp->csp_cipher_key;
1904*5bdb8b27SMark Johnston 		ctx = (struct safexcel_context_record *)req->ctx.vaddr;
1905*5bdb8b27SMark Johnston 		(void)safexcel_set_context(ctx, crp->crp_op, ckey, akey,
1906*5bdb8b27SMark Johnston 		    req->sess);
1907*5bdb8b27SMark Johnston 	} else {
1908*5bdb8b27SMark Johnston 		/*
1909*5bdb8b27SMark Johnston 		 * Use the context record template computed at session
1910*5bdb8b27SMark Johnston 		 * initialization time.
1911*5bdb8b27SMark Johnston 		 */
1912*5bdb8b27SMark Johnston 		ctxtmp = CRYPTO_OP_IS_ENCRYPT(crp->crp_op) ?
1913*5bdb8b27SMark Johnston 		    &req->sess->encctx : &req->sess->decctx;
1914*5bdb8b27SMark Johnston 		ctx = &ctxtmp->ctx;
1915*5bdb8b27SMark Johnston 		memcpy(req->ctx.vaddr + 2 * sizeof(uint32_t), ctx->data,
1916*5bdb8b27SMark Johnston 		    ctxtmp->len);
1917*5bdb8b27SMark Johnston 	}
1918*5bdb8b27SMark Johnston 	cdesc->control_data.control0 = ctx->control0;
1919*5bdb8b27SMark Johnston 	cdesc->control_data.control1 = ctx->control1;
1920b356ddf0SMark Johnston 
1921b356ddf0SMark Johnston 	/*
1922b356ddf0SMark Johnston 	 * For keyless hash operations, the token instructions can be embedded
1923b356ddf0SMark Johnston 	 * in the token itself.  Otherwise we use an additional token descriptor
1924b356ddf0SMark Johnston 	 * and the embedded instruction space is used to store the IV.
1925b356ddf0SMark Johnston 	 */
1926b356ddf0SMark Johnston 	if (csp->csp_cipher_alg == 0 &&
1927b356ddf0SMark Johnston 	    csp->csp_auth_alg != CRYPTO_AES_NIST_GMAC) {
1928b356ddf0SMark Johnston 		instr = (void *)cdesc->control_data.token;
1929b356ddf0SMark Johnston 	} else {
1930b356ddf0SMark Johnston 		instr = (void *)(sc->sc_ring[ringidx].dma_atok.vaddr +
1931b356ddf0SMark Johnston 		    sc->sc_config.atok_offset *
1932b356ddf0SMark Johnston 		    (cdesc - sc->sc_ring[ringidx].cdr.desc));
1933b356ddf0SMark Johnston 		cdesc->control_data.options |= SAFEXCEL_OPTION_4_TOKEN_IV_CMD;
1934b356ddf0SMark Johnston 	}
1935b356ddf0SMark Johnston 
1936b356ddf0SMark Johnston 	switch (csp->csp_cipher_alg) {
1937b356ddf0SMark Johnston 	case CRYPTO_AES_NIST_GCM_16:
1938b356ddf0SMark Johnston 		safexcel_instr_gcm(req, instr, cdesc);
1939b356ddf0SMark Johnston 		break;
1940b356ddf0SMark Johnston 	case CRYPTO_AES_CCM_16:
1941b356ddf0SMark Johnston 		safexcel_instr_ccm(req, instr, cdesc);
1942b356ddf0SMark Johnston 		break;
1943b356ddf0SMark Johnston 	case CRYPTO_AES_XTS:
1944b356ddf0SMark Johnston 		memcpy(cdesc->control_data.token, req->iv, AES_XTS_IV_LEN);
1945b356ddf0SMark Johnston 		memset(cdesc->control_data.token +
1946b356ddf0SMark Johnston 		    AES_XTS_IV_LEN / sizeof(uint32_t), 0, AES_XTS_IV_LEN);
1947b356ddf0SMark Johnston 
1948b356ddf0SMark Johnston 		safexcel_instr_cipher(req, instr, cdesc);
1949b356ddf0SMark Johnston 		break;
1950b356ddf0SMark Johnston 	case CRYPTO_AES_CBC:
1951b356ddf0SMark Johnston 	case CRYPTO_AES_ICM:
1952b356ddf0SMark Johnston 		memcpy(cdesc->control_data.token, req->iv, AES_BLOCK_LEN);
1953b356ddf0SMark Johnston 		if (csp->csp_auth_alg != 0)
1954b356ddf0SMark Johnston 			safexcel_instr_eta(req, instr, cdesc);
1955b356ddf0SMark Johnston 		else
1956b356ddf0SMark Johnston 			safexcel_instr_cipher(req, instr, cdesc);
1957b356ddf0SMark Johnston 		break;
1958b356ddf0SMark Johnston 	default:
1959b356ddf0SMark Johnston 		switch (csp->csp_auth_alg) {
1960b356ddf0SMark Johnston 		case CRYPTO_SHA1:
1961b356ddf0SMark Johnston 		case CRYPTO_SHA1_HMAC:
1962b356ddf0SMark Johnston 		case CRYPTO_SHA2_224:
1963b356ddf0SMark Johnston 		case CRYPTO_SHA2_224_HMAC:
1964b356ddf0SMark Johnston 		case CRYPTO_SHA2_256:
1965b356ddf0SMark Johnston 		case CRYPTO_SHA2_256_HMAC:
1966b356ddf0SMark Johnston 		case CRYPTO_SHA2_384:
1967b356ddf0SMark Johnston 		case CRYPTO_SHA2_384_HMAC:
1968b356ddf0SMark Johnston 		case CRYPTO_SHA2_512:
1969b356ddf0SMark Johnston 		case CRYPTO_SHA2_512_HMAC:
1970b356ddf0SMark Johnston 			safexcel_instr_sha_hash(req, instr);
1971b356ddf0SMark Johnston 			break;
1972b356ddf0SMark Johnston 		case CRYPTO_AES_NIST_GMAC:
1973b356ddf0SMark Johnston 			safexcel_instr_gmac(req, instr, cdesc);
1974b356ddf0SMark Johnston 			break;
1975b356ddf0SMark Johnston 		default:
1976b356ddf0SMark Johnston 			panic("unhandled auth request %d", csp->csp_auth_alg);
1977b356ddf0SMark Johnston 		}
1978b356ddf0SMark Johnston 		break;
1979b356ddf0SMark Johnston 	}
1980b356ddf0SMark Johnston }
1981b356ddf0SMark Johnston 
1982b356ddf0SMark Johnston static struct safexcel_res_descr *
1983b356ddf0SMark Johnston safexcel_res_descr_add(struct safexcel_ring *ring, bool first, bool last,
1984b356ddf0SMark Johnston     bus_addr_t data, uint32_t len)
1985b356ddf0SMark Johnston {
1986b356ddf0SMark Johnston 	struct safexcel_res_descr *rdesc;
1987b356ddf0SMark Johnston 	struct safexcel_res_descr_ring *rring;
1988b356ddf0SMark Johnston 
1989b356ddf0SMark Johnston 	mtx_assert(&ring->mtx, MA_OWNED);
1990b356ddf0SMark Johnston 
1991b356ddf0SMark Johnston 	rring = &ring->rdr;
1992b356ddf0SMark Johnston 	if ((rring->write + 1) % SAFEXCEL_RING_SIZE == rring->read)
1993b356ddf0SMark Johnston 		return (NULL);
1994b356ddf0SMark Johnston 
1995b356ddf0SMark Johnston 	rdesc = &rring->desc[rring->write];
1996b356ddf0SMark Johnston 	rring->write = (rring->write + 1) % SAFEXCEL_RING_SIZE;
1997b356ddf0SMark Johnston 
1998b356ddf0SMark Johnston 	rdesc->particle_size = len;
1999b356ddf0SMark Johnston 	rdesc->rsvd0 = 0;
2000b356ddf0SMark Johnston 	rdesc->descriptor_overflow = 0;
2001b356ddf0SMark Johnston 	rdesc->buffer_overflow = 0;
2002b356ddf0SMark Johnston 	rdesc->last_seg = last;
2003b356ddf0SMark Johnston 	rdesc->first_seg = first;
2004b356ddf0SMark Johnston 	rdesc->result_size =
2005b356ddf0SMark Johnston 	    sizeof(struct safexcel_res_data) / sizeof(uint32_t);
2006b356ddf0SMark Johnston 	rdesc->rsvd1 = 0;
2007b356ddf0SMark Johnston 	rdesc->data_lo = SAFEXCEL_ADDR_LO(data);
2008b356ddf0SMark Johnston 	rdesc->data_hi = SAFEXCEL_ADDR_HI(data);
2009b356ddf0SMark Johnston 
2010b356ddf0SMark Johnston 	if (first) {
2011b356ddf0SMark Johnston 		rdesc->result_data.packet_length = 0;
2012b356ddf0SMark Johnston 		rdesc->result_data.error_code = 0;
2013b356ddf0SMark Johnston 	}
2014b356ddf0SMark Johnston 
2015b356ddf0SMark Johnston 	return (rdesc);
2016b356ddf0SMark Johnston }
2017b356ddf0SMark Johnston 
2018b356ddf0SMark Johnston static struct safexcel_cmd_descr *
2019b356ddf0SMark Johnston safexcel_cmd_descr_add(struct safexcel_ring *ring, bool first, bool last,
2020b356ddf0SMark Johnston     bus_addr_t data, uint32_t seglen, uint32_t reqlen, bus_addr_t context)
2021b356ddf0SMark Johnston {
2022b356ddf0SMark Johnston 	struct safexcel_cmd_descr *cdesc;
2023b356ddf0SMark Johnston 	struct safexcel_cmd_descr_ring *cring;
2024b356ddf0SMark Johnston 
20253db2b0d5SMark Johnston 	KASSERT(reqlen <= SAFEXCEL_MAX_REQUEST_SIZE,
20263db2b0d5SMark Johnston 	    ("%s: request length %u too long", __func__, reqlen));
2027b356ddf0SMark Johnston 	mtx_assert(&ring->mtx, MA_OWNED);
2028b356ddf0SMark Johnston 
2029b356ddf0SMark Johnston 	cring = &ring->cdr;
2030b356ddf0SMark Johnston 	if ((cring->write + 1) % SAFEXCEL_RING_SIZE == cring->read)
2031b356ddf0SMark Johnston 		return (NULL);
2032b356ddf0SMark Johnston 
2033b356ddf0SMark Johnston 	cdesc = &cring->desc[cring->write];
2034b356ddf0SMark Johnston 	cring->write = (cring->write + 1) % SAFEXCEL_RING_SIZE;
2035b356ddf0SMark Johnston 
2036b356ddf0SMark Johnston 	cdesc->particle_size = seglen;
2037b356ddf0SMark Johnston 	cdesc->rsvd0 = 0;
2038b356ddf0SMark Johnston 	cdesc->last_seg = last;
2039b356ddf0SMark Johnston 	cdesc->first_seg = first;
2040b356ddf0SMark Johnston 	cdesc->additional_cdata_size = 0;
2041b356ddf0SMark Johnston 	cdesc->rsvd1 = 0;
2042b356ddf0SMark Johnston 	cdesc->data_lo = SAFEXCEL_ADDR_LO(data);
2043b356ddf0SMark Johnston 	cdesc->data_hi = SAFEXCEL_ADDR_HI(data);
2044b356ddf0SMark Johnston 	if (first) {
2045b356ddf0SMark Johnston 		cdesc->control_data.packet_length = reqlen;
2046b356ddf0SMark Johnston 		cdesc->control_data.options = SAFEXCEL_OPTION_IP |
2047b356ddf0SMark Johnston 		    SAFEXCEL_OPTION_CP | SAFEXCEL_OPTION_CTX_CTRL_IN_CMD |
2048b356ddf0SMark Johnston 		    SAFEXCEL_OPTION_RC_AUTO;
2049b356ddf0SMark Johnston 		cdesc->control_data.type = SAFEXCEL_TOKEN_TYPE_BYPASS;
2050b356ddf0SMark Johnston 		cdesc->control_data.context_lo = SAFEXCEL_ADDR_LO(context) |
2051b356ddf0SMark Johnston 		    SAFEXCEL_CONTEXT_SMALL;
2052b356ddf0SMark Johnston 		cdesc->control_data.context_hi = SAFEXCEL_ADDR_HI(context);
2053b356ddf0SMark Johnston 	}
2054b356ddf0SMark Johnston 
2055b356ddf0SMark Johnston 	return (cdesc);
2056b356ddf0SMark Johnston }
2057b356ddf0SMark Johnston 
2058b356ddf0SMark Johnston static void
2059b356ddf0SMark Johnston safexcel_cmd_descr_rollback(struct safexcel_ring *ring, int count)
2060b356ddf0SMark Johnston {
2061b356ddf0SMark Johnston 	struct safexcel_cmd_descr_ring *cring;
2062b356ddf0SMark Johnston 
2063b356ddf0SMark Johnston 	mtx_assert(&ring->mtx, MA_OWNED);
2064b356ddf0SMark Johnston 
2065b356ddf0SMark Johnston 	cring = &ring->cdr;
2066b356ddf0SMark Johnston 	cring->write -= count;
2067b356ddf0SMark Johnston 	if (cring->write < 0)
2068b356ddf0SMark Johnston 		cring->write += SAFEXCEL_RING_SIZE;
2069b356ddf0SMark Johnston }
2070b356ddf0SMark Johnston 
2071b356ddf0SMark Johnston static void
2072b356ddf0SMark Johnston safexcel_res_descr_rollback(struct safexcel_ring *ring, int count)
2073b356ddf0SMark Johnston {
2074b356ddf0SMark Johnston 	struct safexcel_res_descr_ring *rring;
2075b356ddf0SMark Johnston 
2076b356ddf0SMark Johnston 	mtx_assert(&ring->mtx, MA_OWNED);
2077b356ddf0SMark Johnston 
2078b356ddf0SMark Johnston 	rring = &ring->rdr;
2079b356ddf0SMark Johnston 	rring->write -= count;
2080b356ddf0SMark Johnston 	if (rring->write < 0)
2081b356ddf0SMark Johnston 		rring->write += SAFEXCEL_RING_SIZE;
2082b356ddf0SMark Johnston }
2083b356ddf0SMark Johnston 
2084b356ddf0SMark Johnston static void
2085b356ddf0SMark Johnston safexcel_append_segs(bus_dma_segment_t *segs, int nseg, struct sglist *sg,
2086b356ddf0SMark Johnston     int start, int len)
2087b356ddf0SMark Johnston {
2088b356ddf0SMark Johnston 	bus_dma_segment_t *seg;
2089b356ddf0SMark Johnston 	size_t seglen;
2090b356ddf0SMark Johnston 	int error, i;
2091b356ddf0SMark Johnston 
2092b356ddf0SMark Johnston 	for (i = 0; i < nseg && len > 0; i++) {
2093b356ddf0SMark Johnston 		seg = &segs[i];
2094b356ddf0SMark Johnston 
2095b356ddf0SMark Johnston 		if (seg->ds_len <= start) {
2096b356ddf0SMark Johnston 			start -= seg->ds_len;
2097b356ddf0SMark Johnston 			continue;
2098b356ddf0SMark Johnston 		}
2099b356ddf0SMark Johnston 
2100b356ddf0SMark Johnston 		seglen = MIN(len, seg->ds_len - start);
2101b356ddf0SMark Johnston 		error = sglist_append_phys(sg, seg->ds_addr + start, seglen);
2102b356ddf0SMark Johnston 		if (error != 0)
2103b356ddf0SMark Johnston 			panic("%s: ran out of segments: %d", __func__, error);
2104b356ddf0SMark Johnston 		len -= seglen;
2105b356ddf0SMark Johnston 		start = 0;
2106b356ddf0SMark Johnston 	}
2107b356ddf0SMark Johnston }
2108b356ddf0SMark Johnston 
2109b356ddf0SMark Johnston static void
2110b356ddf0SMark Johnston safexcel_create_chain_cb(void *arg, bus_dma_segment_t *segs, int nseg,
2111b356ddf0SMark Johnston     int error)
2112b356ddf0SMark Johnston {
2113b356ddf0SMark Johnston 	const struct crypto_session_params *csp;
2114b356ddf0SMark Johnston 	struct cryptop *crp;
2115b356ddf0SMark Johnston 	struct safexcel_cmd_descr *cdesc;
2116b356ddf0SMark Johnston 	struct safexcel_request *req;
2117b356ddf0SMark Johnston 	struct safexcel_ring *ring;
2118b356ddf0SMark Johnston 	struct safexcel_session *sess;
2119b356ddf0SMark Johnston 	struct sglist *sg;
2120b356ddf0SMark Johnston 	size_t inlen;
2121b356ddf0SMark Johnston 	int i;
2122b356ddf0SMark Johnston 	bool first, last;
2123b356ddf0SMark Johnston 
2124b356ddf0SMark Johnston 	req = arg;
2125b356ddf0SMark Johnston 	if (error != 0) {
2126b356ddf0SMark Johnston 		req->error = error;
2127b356ddf0SMark Johnston 		return;
2128b356ddf0SMark Johnston 	}
2129b356ddf0SMark Johnston 
2130b356ddf0SMark Johnston 	crp = req->crp;
2131b356ddf0SMark Johnston 	csp = crypto_get_params(crp->crp_session);
2132b356ddf0SMark Johnston 	sess = req->sess;
2133e934d455SMark Johnston 	ring = &req->sc->sc_ring[req->ringidx];
2134b356ddf0SMark Johnston 
2135b356ddf0SMark Johnston 	mtx_assert(&ring->mtx, MA_OWNED);
2136b356ddf0SMark Johnston 
2137b356ddf0SMark Johnston 	/*
2138b356ddf0SMark Johnston 	 * Set up descriptors for input and output data.
2139b356ddf0SMark Johnston 	 *
2140b356ddf0SMark Johnston 	 * The processing engine programs require that any AAD comes first,
2141b356ddf0SMark Johnston 	 * followed by the cipher plaintext, followed by the digest.  Some
2142b356ddf0SMark Johnston 	 * consumers place the digest first in the input buffer, in which case
2143b356ddf0SMark Johnston 	 * we have to create an extra descriptor.
2144b356ddf0SMark Johnston 	 *
2145b356ddf0SMark Johnston 	 * As an optimization, unmodified data is not passed to the output
2146b356ddf0SMark Johnston 	 * stream.
2147b356ddf0SMark Johnston 	 */
2148b356ddf0SMark Johnston 	sglist_reset(ring->cmd_data);
2149b356ddf0SMark Johnston 	sglist_reset(ring->res_data);
2150b356ddf0SMark Johnston 	if (crp->crp_aad_length != 0) {
2151b356ddf0SMark Johnston 		safexcel_append_segs(segs, nseg, ring->cmd_data,
2152b356ddf0SMark Johnston 		    crp->crp_aad_start, crp->crp_aad_length);
2153b356ddf0SMark Johnston 	}
2154b356ddf0SMark Johnston 	safexcel_append_segs(segs, nseg, ring->cmd_data,
2155b356ddf0SMark Johnston 	    crp->crp_payload_start, crp->crp_payload_length);
2156b356ddf0SMark Johnston 	if (csp->csp_cipher_alg != 0) {
2157b356ddf0SMark Johnston 		safexcel_append_segs(segs, nseg, ring->res_data,
2158b356ddf0SMark Johnston 		    crp->crp_payload_start, crp->crp_payload_length);
2159b356ddf0SMark Johnston 	}
2160b356ddf0SMark Johnston 	if (sess->digestlen > 0) {
2161b356ddf0SMark Johnston 		if ((crp->crp_op & CRYPTO_OP_VERIFY_DIGEST) != 0) {
2162b356ddf0SMark Johnston 			safexcel_append_segs(segs, nseg, ring->cmd_data,
2163b356ddf0SMark Johnston 			    crp->crp_digest_start, sess->digestlen);
2164b356ddf0SMark Johnston 		} else {
2165b356ddf0SMark Johnston 			safexcel_append_segs(segs, nseg, ring->res_data,
2166b356ddf0SMark Johnston 			    crp->crp_digest_start, sess->digestlen);
2167b356ddf0SMark Johnston 		}
2168b356ddf0SMark Johnston 	}
2169b356ddf0SMark Johnston 
2170b356ddf0SMark Johnston 	sg = ring->cmd_data;
2171b356ddf0SMark Johnston 	if (sg->sg_nseg == 0) {
2172b356ddf0SMark Johnston 		/*
2173b356ddf0SMark Johnston 		 * Fake a segment for the command descriptor if the input has
2174b356ddf0SMark Johnston 		 * length zero.  The EIP97 apparently does not handle
2175b356ddf0SMark Johnston 		 * zero-length packets properly since subsequent requests return
2176b356ddf0SMark Johnston 		 * bogus errors, so provide a dummy segment using the context
21771a6ffed5SMark Johnston 		 * descriptor.  Also, we must allocate at least one command ring
21781a6ffed5SMark Johnston 		 * entry per request to keep the request shadow ring in sync.
2179b356ddf0SMark Johnston 		 */
2180b356ddf0SMark Johnston 		(void)sglist_append_phys(sg, req->ctx.paddr, 1);
2181b356ddf0SMark Johnston 	}
2182b356ddf0SMark Johnston 	for (i = 0, inlen = 0; i < sg->sg_nseg; i++)
2183b356ddf0SMark Johnston 		inlen += sg->sg_segs[i].ss_len;
2184b356ddf0SMark Johnston 	for (i = 0; i < sg->sg_nseg; i++) {
2185b356ddf0SMark Johnston 		first = i == 0;
2186b356ddf0SMark Johnston 		last = i == sg->sg_nseg - 1;
2187b356ddf0SMark Johnston 
2188b356ddf0SMark Johnston 		cdesc = safexcel_cmd_descr_add(ring, first, last,
2189b356ddf0SMark Johnston 		    sg->sg_segs[i].ss_paddr, sg->sg_segs[i].ss_len,
2190b356ddf0SMark Johnston 		    (uint32_t)inlen, req->ctx.paddr);
2191b356ddf0SMark Johnston 		if (cdesc == NULL) {
2192b356ddf0SMark Johnston 			safexcel_cmd_descr_rollback(ring, i);
21930371c3faSMark Johnston 			counter_u64_add(req->sc->sc_cdesc_alloc_failures, 1);
2194b7e27af3SMark Johnston 			req->error = ERESTART;
2195b356ddf0SMark Johnston 			return;
2196b356ddf0SMark Johnston 		}
2197b356ddf0SMark Johnston 		if (i == 0)
2198b356ddf0SMark Johnston 			req->cdesc = cdesc;
2199b356ddf0SMark Johnston 	}
2200b356ddf0SMark Johnston 	req->cdescs = sg->sg_nseg;
2201b356ddf0SMark Johnston 
2202b356ddf0SMark Johnston 	sg = ring->res_data;
2203b356ddf0SMark Johnston 	if (sg->sg_nseg == 0) {
2204b356ddf0SMark Johnston 		/*
2205b356ddf0SMark Johnston 		 * We need a result descriptor even if the output stream will be
2206b356ddf0SMark Johnston 		 * empty, for example when verifying an AAD digest.
2207b356ddf0SMark Johnston 		 */
2208b356ddf0SMark Johnston 		sg->sg_segs[0].ss_paddr = 0;
2209b356ddf0SMark Johnston 		sg->sg_segs[0].ss_len = 0;
2210b356ddf0SMark Johnston 		sg->sg_nseg = 1;
2211b356ddf0SMark Johnston 	}
2212b356ddf0SMark Johnston 	for (i = 0; i < sg->sg_nseg; i++) {
2213b356ddf0SMark Johnston 		first = i == 0;
2214b356ddf0SMark Johnston 		last = i == sg->sg_nseg - 1;
2215b356ddf0SMark Johnston 
2216b356ddf0SMark Johnston 		if (safexcel_res_descr_add(ring, first, last,
2217b356ddf0SMark Johnston 		    sg->sg_segs[i].ss_paddr, sg->sg_segs[i].ss_len) == NULL) {
2218b356ddf0SMark Johnston 			safexcel_cmd_descr_rollback(ring,
2219b356ddf0SMark Johnston 			    ring->cmd_data->sg_nseg);
2220b356ddf0SMark Johnston 			safexcel_res_descr_rollback(ring, i);
22210371c3faSMark Johnston 			counter_u64_add(req->sc->sc_rdesc_alloc_failures, 1);
2222b7e27af3SMark Johnston 			req->error = ERESTART;
2223b356ddf0SMark Johnston 			return;
2224b356ddf0SMark Johnston 		}
2225b356ddf0SMark Johnston 	}
2226b356ddf0SMark Johnston 	req->rdescs = sg->sg_nseg;
2227b356ddf0SMark Johnston }
2228b356ddf0SMark Johnston 
2229b356ddf0SMark Johnston static int
2230b356ddf0SMark Johnston safexcel_create_chain(struct safexcel_ring *ring, struct safexcel_request *req)
2231b356ddf0SMark Johnston {
2232b356ddf0SMark Johnston 	int error;
2233b356ddf0SMark Johnston 
2234b356ddf0SMark Johnston 	req->error = 0;
2235b356ddf0SMark Johnston 	req->cdescs = req->rdescs = 0;
2236b356ddf0SMark Johnston 
2237b356ddf0SMark Johnston 	error = bus_dmamap_load_crp(ring->data_dtag, req->dmap, req->crp,
2238b356ddf0SMark Johnston 	    safexcel_create_chain_cb, req, BUS_DMA_NOWAIT);
2239b356ddf0SMark Johnston 	if (error == 0)
2240b356ddf0SMark Johnston 		req->dmap_loaded = true;
2241b356ddf0SMark Johnston 
2242b356ddf0SMark Johnston 	if (req->error != 0)
2243b356ddf0SMark Johnston 		error = req->error;
2244b356ddf0SMark Johnston 
2245b356ddf0SMark Johnston 	return (error);
2246b356ddf0SMark Johnston }
2247b356ddf0SMark Johnston 
2248b356ddf0SMark Johnston static bool
2249b356ddf0SMark Johnston safexcel_probe_cipher(const struct crypto_session_params *csp)
2250b356ddf0SMark Johnston {
2251b356ddf0SMark Johnston 	switch (csp->csp_cipher_alg) {
2252b356ddf0SMark Johnston 	case CRYPTO_AES_CBC:
2253b356ddf0SMark Johnston 	case CRYPTO_AES_ICM:
2254b356ddf0SMark Johnston 		if (csp->csp_ivlen != AES_BLOCK_LEN)
2255b356ddf0SMark Johnston 			return (false);
2256b356ddf0SMark Johnston 		break;
2257b356ddf0SMark Johnston 	case CRYPTO_AES_XTS:
2258b356ddf0SMark Johnston 		if (csp->csp_ivlen != AES_XTS_IV_LEN)
2259b356ddf0SMark Johnston 			return (false);
2260b356ddf0SMark Johnston 		break;
2261b356ddf0SMark Johnston 	default:
2262b356ddf0SMark Johnston 		return (false);
2263b356ddf0SMark Johnston 	}
2264b356ddf0SMark Johnston 
2265b356ddf0SMark Johnston 	return (true);
2266b356ddf0SMark Johnston }
2267b356ddf0SMark Johnston 
2268b356ddf0SMark Johnston /*
2269b356ddf0SMark Johnston  * Determine whether the driver can implement a session with the requested
2270b356ddf0SMark Johnston  * parameters.
2271b356ddf0SMark Johnston  */
2272b356ddf0SMark Johnston static int
2273b356ddf0SMark Johnston safexcel_probesession(device_t dev, const struct crypto_session_params *csp)
2274b356ddf0SMark Johnston {
2275b356ddf0SMark Johnston 	switch (csp->csp_mode) {
2276b356ddf0SMark Johnston 	case CSP_MODE_CIPHER:
2277b356ddf0SMark Johnston 		if (!safexcel_probe_cipher(csp))
2278b356ddf0SMark Johnston 			return (EINVAL);
2279b356ddf0SMark Johnston 		break;
2280b356ddf0SMark Johnston 	case CSP_MODE_DIGEST:
2281b356ddf0SMark Johnston 		switch (csp->csp_auth_alg) {
2282b356ddf0SMark Johnston 		case CRYPTO_AES_NIST_GMAC:
2283b356ddf0SMark Johnston 			if (csp->csp_ivlen != AES_GCM_IV_LEN)
2284b356ddf0SMark Johnston 				return (EINVAL);
2285b356ddf0SMark Johnston 			break;
2286b356ddf0SMark Johnston 		case CRYPTO_SHA1:
2287b356ddf0SMark Johnston 		case CRYPTO_SHA1_HMAC:
2288b356ddf0SMark Johnston 		case CRYPTO_SHA2_224:
2289b356ddf0SMark Johnston 		case CRYPTO_SHA2_224_HMAC:
2290b356ddf0SMark Johnston 		case CRYPTO_SHA2_256:
2291b356ddf0SMark Johnston 		case CRYPTO_SHA2_256_HMAC:
2292b356ddf0SMark Johnston 		case CRYPTO_SHA2_384:
2293b356ddf0SMark Johnston 		case CRYPTO_SHA2_384_HMAC:
2294b356ddf0SMark Johnston 		case CRYPTO_SHA2_512:
2295b356ddf0SMark Johnston 		case CRYPTO_SHA2_512_HMAC:
2296b356ddf0SMark Johnston 			break;
2297b356ddf0SMark Johnston 		default:
2298b356ddf0SMark Johnston 			return (EINVAL);
2299b356ddf0SMark Johnston 		}
2300b356ddf0SMark Johnston 		break;
2301b356ddf0SMark Johnston 	case CSP_MODE_AEAD:
2302b356ddf0SMark Johnston 		switch (csp->csp_cipher_alg) {
2303b356ddf0SMark Johnston 		case CRYPTO_AES_NIST_GCM_16:
2304b356ddf0SMark Johnston 			if (csp->csp_ivlen != AES_GCM_IV_LEN)
2305b356ddf0SMark Johnston 				return (EINVAL);
2306b356ddf0SMark Johnston 			break;
2307b356ddf0SMark Johnston 		case CRYPTO_AES_CCM_16:
2308b356ddf0SMark Johnston 			if (csp->csp_ivlen != AES_CCM_IV_LEN)
2309b356ddf0SMark Johnston 				return (EINVAL);
2310b356ddf0SMark Johnston 			break;
2311b356ddf0SMark Johnston 		default:
2312b356ddf0SMark Johnston 			return (EINVAL);
2313b356ddf0SMark Johnston 		}
2314b356ddf0SMark Johnston 		break;
2315b356ddf0SMark Johnston 	case CSP_MODE_ETA:
2316b356ddf0SMark Johnston 		if (!safexcel_probe_cipher(csp))
2317b356ddf0SMark Johnston 			return (EINVAL);
2318b356ddf0SMark Johnston 		switch (csp->csp_cipher_alg) {
2319b356ddf0SMark Johnston 		case CRYPTO_AES_CBC:
2320b356ddf0SMark Johnston 		case CRYPTO_AES_ICM:
2321b356ddf0SMark Johnston 			/*
2322b356ddf0SMark Johnston 			 * The EIP-97 does not support combining AES-XTS with
2323b356ddf0SMark Johnston 			 * hash operations.
2324b356ddf0SMark Johnston 			 */
2325b356ddf0SMark Johnston 			if (csp->csp_auth_alg != CRYPTO_SHA1_HMAC &&
2326b356ddf0SMark Johnston 			    csp->csp_auth_alg != CRYPTO_SHA2_224_HMAC &&
2327b356ddf0SMark Johnston 			    csp->csp_auth_alg != CRYPTO_SHA2_256_HMAC &&
2328b356ddf0SMark Johnston 			    csp->csp_auth_alg != CRYPTO_SHA2_384_HMAC &&
2329b356ddf0SMark Johnston 			    csp->csp_auth_alg != CRYPTO_SHA2_512_HMAC)
2330b356ddf0SMark Johnston 				return (EINVAL);
2331b356ddf0SMark Johnston 			break;
2332b356ddf0SMark Johnston 		default:
2333b356ddf0SMark Johnston 			return (EINVAL);
2334b356ddf0SMark Johnston 		}
2335b356ddf0SMark Johnston 		break;
2336b356ddf0SMark Johnston 	default:
2337b356ddf0SMark Johnston 		return (EINVAL);
2338b356ddf0SMark Johnston 	}
2339b356ddf0SMark Johnston 
2340b356ddf0SMark Johnston 	return (CRYPTODEV_PROBE_HARDWARE);
2341b356ddf0SMark Johnston }
2342b356ddf0SMark Johnston 
2343b356ddf0SMark Johnston static uint32_t
2344b356ddf0SMark Johnston safexcel_aes_algid(int keylen)
2345b356ddf0SMark Johnston {
2346b356ddf0SMark Johnston 	switch (keylen) {
2347b356ddf0SMark Johnston 	case 16:
2348b356ddf0SMark Johnston 		return (SAFEXCEL_CONTROL0_CRYPTO_ALG_AES128);
2349b356ddf0SMark Johnston 	case 24:
2350b356ddf0SMark Johnston 		return (SAFEXCEL_CONTROL0_CRYPTO_ALG_AES192);
2351b356ddf0SMark Johnston 	case 32:
2352b356ddf0SMark Johnston 		return (SAFEXCEL_CONTROL0_CRYPTO_ALG_AES256);
2353b356ddf0SMark Johnston 	default:
2354b356ddf0SMark Johnston 		panic("invalid AES key length %d", keylen);
2355b356ddf0SMark Johnston 	}
2356b356ddf0SMark Johnston }
2357b356ddf0SMark Johnston 
2358b356ddf0SMark Johnston static uint32_t
2359b356ddf0SMark Johnston safexcel_aes_ccm_hashid(int keylen)
2360b356ddf0SMark Johnston {
2361b356ddf0SMark Johnston 	switch (keylen) {
2362b356ddf0SMark Johnston 	case 16:
2363b356ddf0SMark Johnston 		return (SAFEXCEL_CONTROL0_HASH_ALG_XCBC128);
2364b356ddf0SMark Johnston 	case 24:
2365b356ddf0SMark Johnston 		return (SAFEXCEL_CONTROL0_HASH_ALG_XCBC192);
2366b356ddf0SMark Johnston 	case 32:
2367b356ddf0SMark Johnston 		return (SAFEXCEL_CONTROL0_HASH_ALG_XCBC256);
2368b356ddf0SMark Johnston 	default:
2369b356ddf0SMark Johnston 		panic("invalid AES key length %d", keylen);
2370b356ddf0SMark Johnston 	}
2371b356ddf0SMark Johnston }
2372b356ddf0SMark Johnston 
2373b356ddf0SMark Johnston static uint32_t
2374b356ddf0SMark Johnston safexcel_sha_hashid(int alg)
2375b356ddf0SMark Johnston {
2376b356ddf0SMark Johnston 	switch (alg) {
2377b356ddf0SMark Johnston 	case CRYPTO_SHA1:
2378b356ddf0SMark Johnston 	case CRYPTO_SHA1_HMAC:
2379b356ddf0SMark Johnston 		return (SAFEXCEL_CONTROL0_HASH_ALG_SHA1);
2380b356ddf0SMark Johnston 	case CRYPTO_SHA2_224:
2381b356ddf0SMark Johnston 	case CRYPTO_SHA2_224_HMAC:
2382b356ddf0SMark Johnston 		return (SAFEXCEL_CONTROL0_HASH_ALG_SHA224);
2383b356ddf0SMark Johnston 	case CRYPTO_SHA2_256:
2384b356ddf0SMark Johnston 	case CRYPTO_SHA2_256_HMAC:
2385b356ddf0SMark Johnston 		return (SAFEXCEL_CONTROL0_HASH_ALG_SHA256);
2386b356ddf0SMark Johnston 	case CRYPTO_SHA2_384:
2387b356ddf0SMark Johnston 	case CRYPTO_SHA2_384_HMAC:
2388b356ddf0SMark Johnston 		return (SAFEXCEL_CONTROL0_HASH_ALG_SHA384);
2389b356ddf0SMark Johnston 	case CRYPTO_SHA2_512:
2390b356ddf0SMark Johnston 	case CRYPTO_SHA2_512_HMAC:
2391b356ddf0SMark Johnston 		return (SAFEXCEL_CONTROL0_HASH_ALG_SHA512);
2392b356ddf0SMark Johnston 	default:
2393b356ddf0SMark Johnston 		__assert_unreachable();
2394b356ddf0SMark Johnston 	}
2395b356ddf0SMark Johnston }
2396b356ddf0SMark Johnston 
2397b356ddf0SMark Johnston static int
2398b356ddf0SMark Johnston safexcel_sha_hashlen(int alg)
2399b356ddf0SMark Johnston {
2400b356ddf0SMark Johnston 	switch (alg) {
2401b356ddf0SMark Johnston 	case CRYPTO_SHA1:
2402b356ddf0SMark Johnston 	case CRYPTO_SHA1_HMAC:
2403b356ddf0SMark Johnston 		return (SHA1_HASH_LEN);
2404b356ddf0SMark Johnston 	case CRYPTO_SHA2_224:
2405b356ddf0SMark Johnston 	case CRYPTO_SHA2_224_HMAC:
2406b356ddf0SMark Johnston 		return (SHA2_224_HASH_LEN);
2407b356ddf0SMark Johnston 	case CRYPTO_SHA2_256:
2408b356ddf0SMark Johnston 	case CRYPTO_SHA2_256_HMAC:
2409b356ddf0SMark Johnston 		return (SHA2_256_HASH_LEN);
2410b356ddf0SMark Johnston 	case CRYPTO_SHA2_384:
2411b356ddf0SMark Johnston 	case CRYPTO_SHA2_384_HMAC:
2412b356ddf0SMark Johnston 		return (SHA2_384_HASH_LEN);
2413b356ddf0SMark Johnston 	case CRYPTO_SHA2_512:
2414b356ddf0SMark Johnston 	case CRYPTO_SHA2_512_HMAC:
2415b356ddf0SMark Johnston 		return (SHA2_512_HASH_LEN);
2416b356ddf0SMark Johnston 	default:
2417b356ddf0SMark Johnston 		__assert_unreachable();
2418b356ddf0SMark Johnston 	}
2419b356ddf0SMark Johnston }
2420b356ddf0SMark Johnston 
2421b356ddf0SMark Johnston static int
2422b356ddf0SMark Johnston safexcel_sha_statelen(int alg)
2423b356ddf0SMark Johnston {
2424b356ddf0SMark Johnston 	switch (alg) {
2425b356ddf0SMark Johnston 	case CRYPTO_SHA1:
2426b356ddf0SMark Johnston 	case CRYPTO_SHA1_HMAC:
2427b356ddf0SMark Johnston 		return (SHA1_HASH_LEN);
2428b356ddf0SMark Johnston 	case CRYPTO_SHA2_224:
2429b356ddf0SMark Johnston 	case CRYPTO_SHA2_224_HMAC:
2430b356ddf0SMark Johnston 	case CRYPTO_SHA2_256:
2431b356ddf0SMark Johnston 	case CRYPTO_SHA2_256_HMAC:
2432b356ddf0SMark Johnston 		return (SHA2_256_HASH_LEN);
2433b356ddf0SMark Johnston 	case CRYPTO_SHA2_384:
2434b356ddf0SMark Johnston 	case CRYPTO_SHA2_384_HMAC:
2435b356ddf0SMark Johnston 	case CRYPTO_SHA2_512:
2436b356ddf0SMark Johnston 	case CRYPTO_SHA2_512_HMAC:
2437b356ddf0SMark Johnston 		return (SHA2_512_HASH_LEN);
2438b356ddf0SMark Johnston 	default:
2439b356ddf0SMark Johnston 		__assert_unreachable();
2440b356ddf0SMark Johnston 	}
2441b356ddf0SMark Johnston }
2442b356ddf0SMark Johnston 
2443b356ddf0SMark Johnston static int
2444b356ddf0SMark Johnston safexcel_newsession(device_t dev, crypto_session_t cses,
2445b356ddf0SMark Johnston     const struct crypto_session_params *csp)
2446b356ddf0SMark Johnston {
2447b356ddf0SMark Johnston 	struct safexcel_session *sess;
2448b356ddf0SMark Johnston 	struct safexcel_softc *sc;
2449b356ddf0SMark Johnston 
2450b356ddf0SMark Johnston 	sc = device_get_softc(dev);
2451b356ddf0SMark Johnston 	sess = crypto_get_driver_session(cses);
2452*5bdb8b27SMark Johnston 	sess->cses = cses;
2453b356ddf0SMark Johnston 
2454b356ddf0SMark Johnston 	switch (csp->csp_auth_alg) {
2455b356ddf0SMark Johnston 	case CRYPTO_SHA1:
2456b356ddf0SMark Johnston 	case CRYPTO_SHA2_224:
2457b356ddf0SMark Johnston 	case CRYPTO_SHA2_256:
2458b356ddf0SMark Johnston 	case CRYPTO_SHA2_384:
2459b356ddf0SMark Johnston 	case CRYPTO_SHA2_512:
2460b356ddf0SMark Johnston 		sess->digest = SAFEXCEL_CONTROL0_DIGEST_PRECOMPUTED;
2461b356ddf0SMark Johnston 		sess->hash = safexcel_sha_hashid(csp->csp_auth_alg);
2462b356ddf0SMark Johnston 		sess->digestlen = safexcel_sha_hashlen(csp->csp_auth_alg);
2463b356ddf0SMark Johnston 		sess->statelen = safexcel_sha_statelen(csp->csp_auth_alg);
2464b356ddf0SMark Johnston 		break;
2465b356ddf0SMark Johnston 	case CRYPTO_SHA1_HMAC:
2466b356ddf0SMark Johnston 	case CRYPTO_SHA2_224_HMAC:
2467b356ddf0SMark Johnston 	case CRYPTO_SHA2_256_HMAC:
2468b356ddf0SMark Johnston 	case CRYPTO_SHA2_384_HMAC:
2469b356ddf0SMark Johnston 	case CRYPTO_SHA2_512_HMAC:
2470b356ddf0SMark Johnston 		sess->digest = SAFEXCEL_CONTROL0_DIGEST_HMAC;
2471b356ddf0SMark Johnston 		sess->hash = safexcel_sha_hashid(csp->csp_auth_alg);
2472b356ddf0SMark Johnston 		sess->digestlen = safexcel_sha_hashlen(csp->csp_auth_alg);
2473b356ddf0SMark Johnston 		sess->statelen = safexcel_sha_statelen(csp->csp_auth_alg);
2474b356ddf0SMark Johnston 		break;
2475b356ddf0SMark Johnston 	case CRYPTO_AES_NIST_GMAC:
2476b356ddf0SMark Johnston 		sess->digest = SAFEXCEL_CONTROL0_DIGEST_GMAC;
2477b356ddf0SMark Johnston 		sess->digestlen = GMAC_DIGEST_LEN;
2478b356ddf0SMark Johnston 		sess->hash = SAFEXCEL_CONTROL0_HASH_ALG_GHASH;
2479b356ddf0SMark Johnston 		sess->alg = safexcel_aes_algid(csp->csp_auth_klen);
2480b356ddf0SMark Johnston 		sess->mode = SAFEXCEL_CONTROL1_CRYPTO_MODE_GCM;
2481b356ddf0SMark Johnston 		break;
2482b356ddf0SMark Johnston 	}
2483b356ddf0SMark Johnston 
2484b356ddf0SMark Johnston 	switch (csp->csp_cipher_alg) {
2485b356ddf0SMark Johnston 	case CRYPTO_AES_NIST_GCM_16:
2486b356ddf0SMark Johnston 		sess->digest = SAFEXCEL_CONTROL0_DIGEST_GMAC;
2487b356ddf0SMark Johnston 		sess->digestlen = GMAC_DIGEST_LEN;
2488b356ddf0SMark Johnston 		sess->hash = SAFEXCEL_CONTROL0_HASH_ALG_GHASH;
2489b356ddf0SMark Johnston 		sess->alg = safexcel_aes_algid(csp->csp_cipher_klen);
2490b356ddf0SMark Johnston 		sess->mode = SAFEXCEL_CONTROL1_CRYPTO_MODE_GCM;
2491b356ddf0SMark Johnston 		break;
2492b356ddf0SMark Johnston 	case CRYPTO_AES_CCM_16:
2493b356ddf0SMark Johnston 		sess->hash = safexcel_aes_ccm_hashid(csp->csp_cipher_klen);
2494b356ddf0SMark Johnston 		sess->digest = SAFEXCEL_CONTROL0_DIGEST_CCM;
2495b356ddf0SMark Johnston 		sess->digestlen = CCM_CBC_MAX_DIGEST_LEN;
2496b356ddf0SMark Johnston 		sess->alg = safexcel_aes_algid(csp->csp_cipher_klen);
2497b356ddf0SMark Johnston 		sess->mode = SAFEXCEL_CONTROL1_CRYPTO_MODE_CCM;
2498b356ddf0SMark Johnston 		break;
2499b356ddf0SMark Johnston 	case CRYPTO_AES_CBC:
2500b356ddf0SMark Johnston 		sess->alg = safexcel_aes_algid(csp->csp_cipher_klen);
2501b356ddf0SMark Johnston 		sess->mode = SAFEXCEL_CONTROL1_CRYPTO_MODE_CBC;
2502b356ddf0SMark Johnston 		break;
2503b356ddf0SMark Johnston 	case CRYPTO_AES_ICM:
2504b356ddf0SMark Johnston 		sess->alg = safexcel_aes_algid(csp->csp_cipher_klen);
2505b356ddf0SMark Johnston 		sess->mode = SAFEXCEL_CONTROL1_CRYPTO_MODE_CTR;
2506b356ddf0SMark Johnston 		break;
2507b356ddf0SMark Johnston 	case CRYPTO_AES_XTS:
2508b356ddf0SMark Johnston 		sess->alg = safexcel_aes_algid(csp->csp_cipher_klen / 2);
2509b356ddf0SMark Johnston 		sess->mode = SAFEXCEL_CONTROL1_CRYPTO_MODE_XTS;
2510b356ddf0SMark Johnston 		break;
2511b356ddf0SMark Johnston 	}
2512b356ddf0SMark Johnston 
2513b356ddf0SMark Johnston 	if (csp->csp_auth_mlen != 0)
2514b356ddf0SMark Johnston 		sess->digestlen = csp->csp_auth_mlen;
2515b356ddf0SMark Johnston 
2516*5bdb8b27SMark Johnston 	if ((csp->csp_cipher_alg == 0 || csp->csp_cipher_key != NULL) &&
2517*5bdb8b27SMark Johnston 	    (csp->csp_auth_alg == 0 || csp->csp_auth_key != NULL)) {
2518*5bdb8b27SMark Johnston 		sess->encctx.len = safexcel_set_context(&sess->encctx.ctx,
2519*5bdb8b27SMark Johnston 		    CRYPTO_OP_ENCRYPT, csp->csp_cipher_key, csp->csp_auth_key,
2520*5bdb8b27SMark Johnston 		    sess);
2521*5bdb8b27SMark Johnston 		sess->decctx.len = safexcel_set_context(&sess->decctx.ctx,
2522*5bdb8b27SMark Johnston 		    CRYPTO_OP_DECRYPT, csp->csp_cipher_key, csp->csp_auth_key,
2523*5bdb8b27SMark Johnston 		    sess);
2524*5bdb8b27SMark Johnston 	}
2525b356ddf0SMark Johnston 
2526b356ddf0SMark Johnston 	return (0);
2527b356ddf0SMark Johnston }
2528b356ddf0SMark Johnston 
2529b356ddf0SMark Johnston static int
2530b356ddf0SMark Johnston safexcel_process(device_t dev, struct cryptop *crp, int hint)
2531b356ddf0SMark Johnston {
2532b356ddf0SMark Johnston 	const struct crypto_session_params *csp;
2533b356ddf0SMark Johnston 	struct safexcel_request *req;
2534b356ddf0SMark Johnston 	struct safexcel_ring *ring;
2535b356ddf0SMark Johnston 	struct safexcel_session *sess;
2536b356ddf0SMark Johnston 	struct safexcel_softc *sc;
2537b356ddf0SMark Johnston 	int error;
2538b356ddf0SMark Johnston 
2539b356ddf0SMark Johnston 	sc = device_get_softc(dev);
2540b356ddf0SMark Johnston 	sess = crypto_get_driver_session(crp->crp_session);
2541b356ddf0SMark Johnston 	csp = crypto_get_params(crp->crp_session);
2542b356ddf0SMark Johnston 
2543b356ddf0SMark Johnston 	if (__predict_false(crypto_buffer_len(&crp->crp_buf) >
2544b356ddf0SMark Johnston 	    SAFEXCEL_MAX_REQUEST_SIZE)) {
2545b356ddf0SMark Johnston 		crp->crp_etype = E2BIG;
2546b356ddf0SMark Johnston 		crypto_done(crp);
2547b356ddf0SMark Johnston 		return (0);
2548b356ddf0SMark Johnston 	}
2549b356ddf0SMark Johnston 
2550e934d455SMark Johnston 	ring = &sc->sc_ring[curcpu % sc->sc_config.rings];
2551b356ddf0SMark Johnston 	mtx_lock(&ring->mtx);
2552b356ddf0SMark Johnston 	req = safexcel_alloc_request(sc, ring);
2553b356ddf0SMark Johnston 	if (__predict_false(req == NULL)) {
2554092cf8d6SMark Johnston 		ring->blocked = CRYPTO_SYMQ;
2555b356ddf0SMark Johnston 		mtx_unlock(&ring->mtx);
25560371c3faSMark Johnston 		counter_u64_add(sc->sc_req_alloc_failures, 1);
2557b356ddf0SMark Johnston 		return (ERESTART);
2558b356ddf0SMark Johnston 	}
2559b356ddf0SMark Johnston 
2560b356ddf0SMark Johnston 	req->crp = crp;
2561b356ddf0SMark Johnston 	req->sess = sess;
2562b356ddf0SMark Johnston 
2563b356ddf0SMark Johnston 	crypto_read_iv(crp, req->iv);
2564b356ddf0SMark Johnston 
2565b356ddf0SMark Johnston 	error = safexcel_create_chain(ring, req);
2566b356ddf0SMark Johnston 	if (__predict_false(error != 0)) {
2567b356ddf0SMark Johnston 		safexcel_free_request(ring, req);
2568b7e27af3SMark Johnston 		if (error == ERESTART)
2569b7e27af3SMark Johnston 			ring->blocked = CRYPTO_SYMQ;
2570b356ddf0SMark Johnston 		mtx_unlock(&ring->mtx);
2571b7e27af3SMark Johnston 		if (error != ERESTART) {
2572b356ddf0SMark Johnston 			crp->crp_etype = error;
2573b356ddf0SMark Johnston 			crypto_done(crp);
2574b356ddf0SMark Johnston 			return (0);
2575b7e27af3SMark Johnston 		} else {
2576b7e27af3SMark Johnston 			return (ERESTART);
2577b7e27af3SMark Johnston 		}
2578b356ddf0SMark Johnston 	}
2579b356ddf0SMark Johnston 
2580b356ddf0SMark Johnston 	safexcel_set_token(req);
2581b356ddf0SMark Johnston 
2582b356ddf0SMark Johnston 	bus_dmamap_sync(ring->data_dtag, req->dmap,
2583b356ddf0SMark Johnston 	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
2584b356ddf0SMark Johnston 	bus_dmamap_sync(req->ctx.tag, req->ctx.map,
2585b356ddf0SMark Johnston 	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
2586b356ddf0SMark Johnston 	bus_dmamap_sync(ring->cdr.dma.tag, ring->cdr.dma.map,
2587b356ddf0SMark Johnston 	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
2588b356ddf0SMark Johnston 	bus_dmamap_sync(ring->dma_atok.tag, ring->dma_atok.map,
2589b356ddf0SMark Johnston 	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
2590b356ddf0SMark Johnston 	bus_dmamap_sync(ring->rdr.dma.tag, ring->rdr.dma.map,
2591b356ddf0SMark Johnston 	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
2592b356ddf0SMark Johnston 
25931a6ffed5SMark Johnston 	safexcel_execute(sc, ring, req, hint);
2594b356ddf0SMark Johnston 
2595b356ddf0SMark Johnston 	mtx_unlock(&ring->mtx);
2596b356ddf0SMark Johnston 
2597b356ddf0SMark Johnston 	return (0);
2598b356ddf0SMark Johnston }
2599b356ddf0SMark Johnston 
2600b356ddf0SMark Johnston static device_method_t safexcel_methods[] = {
2601b356ddf0SMark Johnston 	/* Device interface */
2602b356ddf0SMark Johnston 	DEVMETHOD(device_probe,		safexcel_probe),
2603b356ddf0SMark Johnston 	DEVMETHOD(device_attach,	safexcel_attach),
2604b356ddf0SMark Johnston 	DEVMETHOD(device_detach,	safexcel_detach),
2605b356ddf0SMark Johnston 
2606b356ddf0SMark Johnston 	/* Cryptodev interface */
2607b356ddf0SMark Johnston 	DEVMETHOD(cryptodev_probesession, safexcel_probesession),
2608b356ddf0SMark Johnston 	DEVMETHOD(cryptodev_newsession,	safexcel_newsession),
2609b356ddf0SMark Johnston 	DEVMETHOD(cryptodev_process,	safexcel_process),
2610b356ddf0SMark Johnston 
2611b356ddf0SMark Johnston 	DEVMETHOD_END
2612b356ddf0SMark Johnston };
2613b356ddf0SMark Johnston 
2614b356ddf0SMark Johnston static devclass_t safexcel_devclass;
2615b356ddf0SMark Johnston 
2616b356ddf0SMark Johnston static driver_t safexcel_driver = {
2617b356ddf0SMark Johnston 	.name 		= "safexcel",
2618b356ddf0SMark Johnston 	.methods 	= safexcel_methods,
2619b356ddf0SMark Johnston 	.size		= sizeof(struct safexcel_softc),
2620b356ddf0SMark Johnston };
2621b356ddf0SMark Johnston 
2622b356ddf0SMark Johnston DRIVER_MODULE(safexcel, simplebus, safexcel_driver, safexcel_devclass, 0, 0);
2623b356ddf0SMark Johnston MODULE_VERSION(safexcel, 1);
2624b356ddf0SMark Johnston MODULE_DEPEND(safexcel, crypto, 1, 1, 1);
2625