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