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