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