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