xref: /freebsd/sys/dev/sec/sec.c (revision 29fe41ddd714bae92a09fd4098fad614945bedf5)
102b553caSRafal Jaworowski /*-
2718cf2ccSPedro F. Giffuni  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3718cf2ccSPedro F. Giffuni  *
402b553caSRafal Jaworowski  * Copyright (C) 2008-2009 Semihalf, Piotr Ziecik
502b553caSRafal Jaworowski  * All rights reserved.
602b553caSRafal Jaworowski  *
702b553caSRafal Jaworowski  * Redistribution and use in source and binary forms, with or without
802b553caSRafal Jaworowski  * modification, are permitted provided that the following conditions
902b553caSRafal Jaworowski  * are met:
1002b553caSRafal Jaworowski  * 1. Redistributions of source code must retain the above copyright
1102b553caSRafal Jaworowski  *    notice, this list of conditions and the following disclaimer.
1202b553caSRafal Jaworowski  * 2. Redistributions in binary form must reproduce the above copyright
1302b553caSRafal Jaworowski  *    notice, this list of conditions and the following disclaimer in the
1402b553caSRafal Jaworowski  *    documentation and/or other materials provided with the distribution.
1502b553caSRafal Jaworowski  *
1602b553caSRafal Jaworowski  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1702b553caSRafal Jaworowski  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1802b553caSRafal Jaworowski  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
1902b553caSRafal Jaworowski  * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2002b553caSRafal Jaworowski  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
2102b553caSRafal Jaworowski  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
2202b553caSRafal Jaworowski  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
2302b553caSRafal Jaworowski  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
2402b553caSRafal Jaworowski  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
2502b553caSRafal Jaworowski  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2602b553caSRafal Jaworowski  */
2702b553caSRafal Jaworowski 
2802b553caSRafal Jaworowski /*
2902b553caSRafal Jaworowski  * Freescale integrated Security Engine (SEC) driver. Currently SEC 2.0 and
3002b553caSRafal Jaworowski  * 3.0 are supported.
3102b553caSRafal Jaworowski  */
3202b553caSRafal Jaworowski 
3302b553caSRafal Jaworowski #include <sys/cdefs.h>
3402b553caSRafal Jaworowski __FBSDID("$FreeBSD$");
3502b553caSRafal Jaworowski 
3602b553caSRafal Jaworowski #include <sys/param.h>
3702b553caSRafal Jaworowski #include <sys/systm.h>
3802b553caSRafal Jaworowski #include <sys/bus.h>
3902b553caSRafal Jaworowski #include <sys/endian.h>
4002b553caSRafal Jaworowski #include <sys/kernel.h>
4102b553caSRafal Jaworowski #include <sys/lock.h>
4202b553caSRafal Jaworowski #include <sys/malloc.h>
4302b553caSRafal Jaworowski #include <sys/mbuf.h>
4402b553caSRafal Jaworowski #include <sys/module.h>
4502b553caSRafal Jaworowski #include <sys/mutex.h>
4602b553caSRafal Jaworowski #include <sys/random.h>
4702b553caSRafal Jaworowski #include <sys/rman.h>
4802b553caSRafal Jaworowski 
4938f004fbSJustin Hibbits #include <machine/_inttypes.h>
5002b553caSRafal Jaworowski #include <machine/bus.h>
5102b553caSRafal Jaworowski #include <machine/resource.h>
5202b553caSRafal Jaworowski 
5302b553caSRafal Jaworowski #include <opencrypto/cryptodev.h>
54c0341432SJohn Baldwin #include <opencrypto/xform_auth.h>
5502b553caSRafal Jaworowski #include "cryptodev_if.h"
5602b553caSRafal Jaworowski 
57d1d3233eSRafal Jaworowski #include <dev/ofw/ofw_bus_subr.h>
5802b553caSRafal Jaworowski #include <dev/sec/sec.h>
5902b553caSRafal Jaworowski 
6002b553caSRafal Jaworowski static int	sec_probe(device_t dev);
6102b553caSRafal Jaworowski static int	sec_attach(device_t dev);
6202b553caSRafal Jaworowski static int	sec_detach(device_t dev);
6302b553caSRafal Jaworowski static int	sec_suspend(device_t dev);
6402b553caSRafal Jaworowski static int	sec_resume(device_t dev);
65661ee6eeSRafal Jaworowski static int	sec_shutdown(device_t dev);
6602b553caSRafal Jaworowski static void	sec_primary_intr(void *arg);
6702b553caSRafal Jaworowski static void	sec_secondary_intr(void *arg);
6802b553caSRafal Jaworowski static int	sec_setup_intr(struct sec_softc *sc, struct resource **ires,
6902b553caSRafal Jaworowski     void **ihand, int *irid, driver_intr_t handler, const char *iname);
7002b553caSRafal Jaworowski static void	sec_release_intr(struct sec_softc *sc, struct resource *ires,
7102b553caSRafal Jaworowski     void *ihand, int irid, const char *iname);
7202b553caSRafal Jaworowski static int	sec_controller_reset(struct sec_softc *sc);
7302b553caSRafal Jaworowski static int	sec_channel_reset(struct sec_softc *sc, int channel, int full);
7402b553caSRafal Jaworowski static int	sec_init(struct sec_softc *sc);
7502b553caSRafal Jaworowski static int	sec_alloc_dma_mem(struct sec_softc *sc,
7602b553caSRafal Jaworowski     struct sec_dma_mem *dma_mem, bus_size_t size);
7702b553caSRafal Jaworowski static int	sec_desc_map_dma(struct sec_softc *sc,
78c0341432SJohn Baldwin     struct sec_dma_mem *dma_mem, struct cryptop *crp, bus_size_t size,
7902b553caSRafal Jaworowski     struct sec_desc_map_info *sdmi);
8002b553caSRafal Jaworowski static void	sec_free_dma_mem(struct sec_dma_mem *dma_mem);
8102b553caSRafal Jaworowski static void	sec_enqueue(struct sec_softc *sc);
8202b553caSRafal Jaworowski static int	sec_enqueue_desc(struct sec_softc *sc, struct sec_desc *desc,
8302b553caSRafal Jaworowski     int channel);
8402b553caSRafal Jaworowski static int	sec_eu_channel(struct sec_softc *sc, int eu);
8502b553caSRafal Jaworowski static int	sec_make_pointer(struct sec_softc *sc, struct sec_desc *desc,
86c0341432SJohn Baldwin     u_int n, struct cryptop *crp, bus_size_t doffset, bus_size_t dsize);
8702b553caSRafal Jaworowski static int	sec_make_pointer_direct(struct sec_softc *sc,
8802b553caSRafal Jaworowski     struct sec_desc *desc, u_int n, bus_addr_t data, bus_size_t dsize);
89c0341432SJohn Baldwin static int	sec_probesession(device_t dev,
90c0341432SJohn Baldwin     const struct crypto_session_params *csp);
911b0909d5SConrad Meyer static int	sec_newsession(device_t dev, crypto_session_t cses,
92c0341432SJohn Baldwin     const struct crypto_session_params *csp);
9302b553caSRafal Jaworowski static int	sec_process(device_t dev, struct cryptop *crp, int hint);
9402b553caSRafal Jaworowski static int	sec_build_common_ns_desc(struct sec_softc *sc,
95c0341432SJohn Baldwin     struct sec_desc *desc, const struct crypto_session_params *csp,
96c0341432SJohn Baldwin     struct cryptop *crp);
9702b553caSRafal Jaworowski static int	sec_build_common_s_desc(struct sec_softc *sc,
98c0341432SJohn Baldwin     struct sec_desc *desc, const struct crypto_session_params *csp,
99c0341432SJohn Baldwin     struct cryptop *crp);
10002b553caSRafal Jaworowski 
10102b553caSRafal Jaworowski static struct sec_desc *sec_find_desc(struct sec_softc *sc, bus_addr_t paddr);
10202b553caSRafal Jaworowski 
10302b553caSRafal Jaworowski /* AESU */
104c0341432SJohn Baldwin static bool	sec_aesu_newsession(const struct crypto_session_params *csp);
10502b553caSRafal Jaworowski static int	sec_aesu_make_desc(struct sec_softc *sc,
106c0341432SJohn Baldwin     const struct crypto_session_params *csp, struct sec_desc *desc,
107c0341432SJohn Baldwin     struct cryptop *crp);
10802b553caSRafal Jaworowski 
10902b553caSRafal Jaworowski /* DEU */
110c0341432SJohn Baldwin static bool	sec_deu_newsession(const struct crypto_session_params *csp);
11102b553caSRafal Jaworowski static int	sec_deu_make_desc(struct sec_softc *sc,
112c0341432SJohn Baldwin     const struct crypto_session_params *csp, struct sec_desc *desc,
113c0341432SJohn Baldwin     struct cryptop *crp);
11402b553caSRafal Jaworowski 
11502b553caSRafal Jaworowski /* MDEU */
116c0341432SJohn Baldwin static bool	sec_mdeu_can_handle(u_int alg);
117c0341432SJohn Baldwin static int	sec_mdeu_config(const struct crypto_session_params *csp,
11802b553caSRafal Jaworowski     u_int *eu, u_int *mode, u_int *hashlen);
119c0341432SJohn Baldwin static bool	sec_mdeu_newsession(const struct crypto_session_params *csp);
12002b553caSRafal Jaworowski static int	sec_mdeu_make_desc(struct sec_softc *sc,
121c0341432SJohn Baldwin     const struct crypto_session_params *csp, struct sec_desc *desc,
122c0341432SJohn Baldwin     struct cryptop *crp);
12302b553caSRafal Jaworowski 
12402b553caSRafal Jaworowski static device_method_t sec_methods[] = {
12502b553caSRafal Jaworowski 	/* Device interface */
12602b553caSRafal Jaworowski 	DEVMETHOD(device_probe,		sec_probe),
12702b553caSRafal Jaworowski 	DEVMETHOD(device_attach,	sec_attach),
12802b553caSRafal Jaworowski 	DEVMETHOD(device_detach,	sec_detach),
12902b553caSRafal Jaworowski 
13002b553caSRafal Jaworowski 	DEVMETHOD(device_suspend,	sec_suspend),
13102b553caSRafal Jaworowski 	DEVMETHOD(device_resume,	sec_resume),
13202b553caSRafal Jaworowski 	DEVMETHOD(device_shutdown,	sec_shutdown),
13302b553caSRafal Jaworowski 
13402b553caSRafal Jaworowski 	/* Crypto methods */
135c0341432SJohn Baldwin 	DEVMETHOD(cryptodev_probesession, sec_probesession),
13602b553caSRafal Jaworowski 	DEVMETHOD(cryptodev_newsession,	sec_newsession),
13702b553caSRafal Jaworowski 	DEVMETHOD(cryptodev_process,	sec_process),
13802b553caSRafal Jaworowski 
1394b7ec270SMarius Strobl 	DEVMETHOD_END
14002b553caSRafal Jaworowski };
14102b553caSRafal Jaworowski static driver_t sec_driver = {
14202b553caSRafal Jaworowski 	"sec",
14302b553caSRafal Jaworowski 	sec_methods,
14402b553caSRafal Jaworowski 	sizeof(struct sec_softc),
14502b553caSRafal Jaworowski };
14602b553caSRafal Jaworowski 
14702b553caSRafal Jaworowski static devclass_t sec_devclass;
148d1d3233eSRafal Jaworowski DRIVER_MODULE(sec, simplebus, sec_driver, sec_devclass, 0, 0);
14902b553caSRafal Jaworowski MODULE_DEPEND(sec, crypto, 1, 1, 1);
15002b553caSRafal Jaworowski 
15102b553caSRafal Jaworowski static struct sec_eu_methods sec_eus[] = {
15202b553caSRafal Jaworowski 	{
15302b553caSRafal Jaworowski 		sec_aesu_newsession,
15402b553caSRafal Jaworowski 		sec_aesu_make_desc,
15502b553caSRafal Jaworowski 	},
15602b553caSRafal Jaworowski 	{
15702b553caSRafal Jaworowski 		sec_deu_newsession,
15802b553caSRafal Jaworowski 		sec_deu_make_desc,
15902b553caSRafal Jaworowski 	},
16002b553caSRafal Jaworowski 	{
16102b553caSRafal Jaworowski 		sec_mdeu_newsession,
16202b553caSRafal Jaworowski 		sec_mdeu_make_desc,
16302b553caSRafal Jaworowski 	},
16402b553caSRafal Jaworowski 	{ NULL, NULL }
16502b553caSRafal Jaworowski };
16602b553caSRafal Jaworowski 
16702b553caSRafal Jaworowski static inline void
16802b553caSRafal Jaworowski sec_sync_dma_mem(struct sec_dma_mem *dma_mem, bus_dmasync_op_t op)
16902b553caSRafal Jaworowski {
17002b553caSRafal Jaworowski 
17102b553caSRafal Jaworowski 	/* Sync only if dma memory is valid */
17202b553caSRafal Jaworowski 	if (dma_mem->dma_vaddr != NULL)
17302b553caSRafal Jaworowski 		bus_dmamap_sync(dma_mem->dma_tag, dma_mem->dma_map, op);
17402b553caSRafal Jaworowski }
17502b553caSRafal Jaworowski 
17602b553caSRafal Jaworowski static inline void *
17702b553caSRafal Jaworowski sec_get_pointer_data(struct sec_desc *desc, u_int n)
17802b553caSRafal Jaworowski {
17902b553caSRafal Jaworowski 
18002b553caSRafal Jaworowski 	return (desc->sd_ptr_dmem[n].dma_vaddr);
18102b553caSRafal Jaworowski }
18202b553caSRafal Jaworowski 
18302b553caSRafal Jaworowski static int
18402b553caSRafal Jaworowski sec_probe(device_t dev)
18502b553caSRafal Jaworowski {
18602b553caSRafal Jaworowski 	struct sec_softc *sc;
18702b553caSRafal Jaworowski 	uint64_t id;
18802b553caSRafal Jaworowski 
189add35ed5SIan Lepore 	if (!ofw_bus_status_okay(dev))
190add35ed5SIan Lepore 		return (ENXIO);
191add35ed5SIan Lepore 
192d1d3233eSRafal Jaworowski 	if (!ofw_bus_is_compatible(dev, "fsl,sec2.0"))
19302b553caSRafal Jaworowski 		return (ENXIO);
19402b553caSRafal Jaworowski 
19502b553caSRafal Jaworowski 	sc = device_get_softc(dev);
19602b553caSRafal Jaworowski 
19702b553caSRafal Jaworowski 	sc->sc_rrid = 0;
198d1d3233eSRafal Jaworowski 	sc->sc_rres = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->sc_rrid,
199d1d3233eSRafal Jaworowski 	    RF_ACTIVE);
20002b553caSRafal Jaworowski 
20102b553caSRafal Jaworowski 	if (sc->sc_rres == NULL)
20202b553caSRafal Jaworowski 		return (ENXIO);
20302b553caSRafal Jaworowski 
20402b553caSRafal Jaworowski 	sc->sc_bas.bsh = rman_get_bushandle(sc->sc_rres);
20502b553caSRafal Jaworowski 	sc->sc_bas.bst = rman_get_bustag(sc->sc_rres);
20602b553caSRafal Jaworowski 
20702b553caSRafal Jaworowski 	id = SEC_READ(sc, SEC_ID);
20802b553caSRafal Jaworowski 
20902b553caSRafal Jaworowski 	bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_rrid, sc->sc_rres);
21002b553caSRafal Jaworowski 
21102b553caSRafal Jaworowski 	switch (id) {
21202b553caSRafal Jaworowski 	case SEC_20_ID:
21302b553caSRafal Jaworowski 		device_set_desc(dev, "Freescale Security Engine 2.0");
21402b553caSRafal Jaworowski 		sc->sc_version = 2;
21502b553caSRafal Jaworowski 		break;
21602b553caSRafal Jaworowski 	case SEC_30_ID:
21702b553caSRafal Jaworowski 		device_set_desc(dev, "Freescale Security Engine 3.0");
21802b553caSRafal Jaworowski 		sc->sc_version = 3;
21902b553caSRafal Jaworowski 		break;
2201aba5158SRafal Jaworowski 	case SEC_31_ID:
2211aba5158SRafal Jaworowski 		device_set_desc(dev, "Freescale Security Engine 3.1");
2221aba5158SRafal Jaworowski 		sc->sc_version = 3;
2231aba5158SRafal Jaworowski 		break;
22402b553caSRafal Jaworowski 	default:
2252afca094SJustin Hibbits 		device_printf(dev, "unknown SEC ID 0x%016"PRIx64"!\n", id);
22602b553caSRafal Jaworowski 		return (ENXIO);
22702b553caSRafal Jaworowski 	}
22802b553caSRafal Jaworowski 
22902b553caSRafal Jaworowski 	return (0);
23002b553caSRafal Jaworowski }
23102b553caSRafal Jaworowski 
23202b553caSRafal Jaworowski static int
23302b553caSRafal Jaworowski sec_attach(device_t dev)
23402b553caSRafal Jaworowski {
23502b553caSRafal Jaworowski 	struct sec_softc *sc;
23602b553caSRafal Jaworowski 	struct sec_hw_lt *lt;
23702b553caSRafal Jaworowski 	int error = 0;
23802b553caSRafal Jaworowski 	int i;
23902b553caSRafal Jaworowski 
24002b553caSRafal Jaworowski 	sc = device_get_softc(dev);
24102b553caSRafal Jaworowski 	sc->sc_dev = dev;
24202b553caSRafal Jaworowski 	sc->sc_blocked = 0;
24302b553caSRafal Jaworowski 	sc->sc_shutdown = 0;
24402b553caSRafal Jaworowski 
2451b0909d5SConrad Meyer 	sc->sc_cid = crypto_get_driverid(dev, sizeof(struct sec_session),
2461b0909d5SConrad Meyer 	    CRYPTOCAP_F_HARDWARE);
24702b553caSRafal Jaworowski 	if (sc->sc_cid < 0) {
24802b553caSRafal Jaworowski 		device_printf(dev, "could not get crypto driver ID!\n");
24902b553caSRafal Jaworowski 		return (ENXIO);
25002b553caSRafal Jaworowski 	}
25102b553caSRafal Jaworowski 
25202b553caSRafal Jaworowski 	/* Init locks */
25302b553caSRafal Jaworowski 	mtx_init(&sc->sc_controller_lock, device_get_nameunit(dev),
25402b553caSRafal Jaworowski 	    "SEC Controller lock", MTX_DEF);
25502b553caSRafal Jaworowski 	mtx_init(&sc->sc_descriptors_lock, device_get_nameunit(dev),
25602b553caSRafal Jaworowski 	    "SEC Descriptors lock", MTX_DEF);
25702b553caSRafal Jaworowski 
25802b553caSRafal Jaworowski 	/* Allocate I/O memory for SEC registers */
25902b553caSRafal Jaworowski 	sc->sc_rrid = 0;
260d1d3233eSRafal Jaworowski 	sc->sc_rres = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->sc_rrid,
261d1d3233eSRafal Jaworowski 	    RF_ACTIVE);
26202b553caSRafal Jaworowski 
26302b553caSRafal Jaworowski 	if (sc->sc_rres == NULL) {
26402b553caSRafal Jaworowski 		device_printf(dev, "could not allocate I/O memory!\n");
26502b553caSRafal Jaworowski 		goto fail1;
26602b553caSRafal Jaworowski 	}
26702b553caSRafal Jaworowski 
26802b553caSRafal Jaworowski 	sc->sc_bas.bsh = rman_get_bushandle(sc->sc_rres);
26902b553caSRafal Jaworowski 	sc->sc_bas.bst = rman_get_bustag(sc->sc_rres);
27002b553caSRafal Jaworowski 
27102b553caSRafal Jaworowski 	/* Setup interrupts */
27202b553caSRafal Jaworowski 	sc->sc_pri_irid = 0;
27302b553caSRafal Jaworowski 	error = sec_setup_intr(sc, &sc->sc_pri_ires, &sc->sc_pri_ihand,
27402b553caSRafal Jaworowski 	    &sc->sc_pri_irid, sec_primary_intr, "primary");
27502b553caSRafal Jaworowski 
27602b553caSRafal Jaworowski 	if (error)
27702b553caSRafal Jaworowski 		goto fail2;
27802b553caSRafal Jaworowski 
279d1d3233eSRafal Jaworowski 
280d1d3233eSRafal Jaworowski 	if (sc->sc_version == 3) {
28102b553caSRafal Jaworowski 		sc->sc_sec_irid = 1;
28202b553caSRafal Jaworowski 		error = sec_setup_intr(sc, &sc->sc_sec_ires, &sc->sc_sec_ihand,
28302b553caSRafal Jaworowski 		    &sc->sc_sec_irid, sec_secondary_intr, "secondary");
28402b553caSRafal Jaworowski 
28502b553caSRafal Jaworowski 		if (error)
28602b553caSRafal Jaworowski 			goto fail3;
287d1d3233eSRafal Jaworowski 	}
28802b553caSRafal Jaworowski 
28902b553caSRafal Jaworowski 	/* Alloc DMA memory for descriptors and link tables */
29002b553caSRafal Jaworowski 	error = sec_alloc_dma_mem(sc, &(sc->sc_desc_dmem),
29102b553caSRafal Jaworowski 	    SEC_DESCRIPTORS * sizeof(struct sec_hw_desc));
29202b553caSRafal Jaworowski 
29302b553caSRafal Jaworowski 	if (error)
29402b553caSRafal Jaworowski 		goto fail4;
29502b553caSRafal Jaworowski 
29602b553caSRafal Jaworowski 	error = sec_alloc_dma_mem(sc, &(sc->sc_lt_dmem),
29702b553caSRafal Jaworowski 	    (SEC_LT_ENTRIES + 1) * sizeof(struct sec_hw_lt));
29802b553caSRafal Jaworowski 
29902b553caSRafal Jaworowski 	if (error)
30002b553caSRafal Jaworowski 		goto fail5;
30102b553caSRafal Jaworowski 
30202b553caSRafal Jaworowski 	/* Fill in descriptors and link tables */
30302b553caSRafal Jaworowski 	for (i = 0; i < SEC_DESCRIPTORS; i++) {
30402b553caSRafal Jaworowski 		sc->sc_desc[i].sd_desc =
30502b553caSRafal Jaworowski 		    (struct sec_hw_desc*)(sc->sc_desc_dmem.dma_vaddr) + i;
30602b553caSRafal Jaworowski 		sc->sc_desc[i].sd_desc_paddr = sc->sc_desc_dmem.dma_paddr +
30702b553caSRafal Jaworowski 		    (i * sizeof(struct sec_hw_desc));
30802b553caSRafal Jaworowski 	}
30902b553caSRafal Jaworowski 
31002b553caSRafal Jaworowski 	for (i = 0; i < SEC_LT_ENTRIES + 1; i++) {
31102b553caSRafal Jaworowski 		sc->sc_lt[i].sl_lt =
31202b553caSRafal Jaworowski 		    (struct sec_hw_lt*)(sc->sc_lt_dmem.dma_vaddr) + i;
31302b553caSRafal Jaworowski 		sc->sc_lt[i].sl_lt_paddr = sc->sc_lt_dmem.dma_paddr +
31402b553caSRafal Jaworowski 		    (i * sizeof(struct sec_hw_lt));
31502b553caSRafal Jaworowski 	}
31602b553caSRafal Jaworowski 
31702b553caSRafal Jaworowski 	/* Last entry in link table is used to create a circle */
31802b553caSRafal Jaworowski 	lt = sc->sc_lt[SEC_LT_ENTRIES].sl_lt;
31902b553caSRafal Jaworowski 	lt->shl_length = 0;
32002b553caSRafal Jaworowski 	lt->shl_r = 0;
32102b553caSRafal Jaworowski 	lt->shl_n = 1;
32202b553caSRafal Jaworowski 	lt->shl_ptr = sc->sc_lt[0].sl_lt_paddr;
32302b553caSRafal Jaworowski 
32402b553caSRafal Jaworowski 	/* Init descriptor and link table queues pointers */
32502b553caSRafal Jaworowski 	SEC_CNT_INIT(sc, sc_free_desc_get_cnt, SEC_DESCRIPTORS);
32602b553caSRafal Jaworowski 	SEC_CNT_INIT(sc, sc_free_desc_put_cnt, SEC_DESCRIPTORS);
32702b553caSRafal Jaworowski 	SEC_CNT_INIT(sc, sc_ready_desc_get_cnt, SEC_DESCRIPTORS);
32802b553caSRafal Jaworowski 	SEC_CNT_INIT(sc, sc_ready_desc_put_cnt, SEC_DESCRIPTORS);
32902b553caSRafal Jaworowski 	SEC_CNT_INIT(sc, sc_queued_desc_get_cnt, SEC_DESCRIPTORS);
33002b553caSRafal Jaworowski 	SEC_CNT_INIT(sc, sc_queued_desc_put_cnt, SEC_DESCRIPTORS);
33102b553caSRafal Jaworowski 	SEC_CNT_INIT(sc, sc_lt_alloc_cnt, SEC_LT_ENTRIES);
33202b553caSRafal Jaworowski 	SEC_CNT_INIT(sc, sc_lt_free_cnt, SEC_LT_ENTRIES);
33302b553caSRafal Jaworowski 
33402b553caSRafal Jaworowski 	/* Create masks for fast checks */
33502b553caSRafal Jaworowski 	sc->sc_int_error_mask = 0;
33602b553caSRafal Jaworowski 	for (i = 0; i < SEC_CHANNELS; i++)
33702b553caSRafal Jaworowski 		sc->sc_int_error_mask |= (~0ULL & SEC_INT_CH_ERR(i));
33802b553caSRafal Jaworowski 
33902b553caSRafal Jaworowski 	switch (sc->sc_version) {
34002b553caSRafal Jaworowski 	case 2:
34102b553caSRafal Jaworowski 		sc->sc_channel_idle_mask =
34202b553caSRafal Jaworowski 		    (SEC_CHAN_CSR2_FFLVL_M << SEC_CHAN_CSR2_FFLVL_S) |
34302b553caSRafal Jaworowski 		    (SEC_CHAN_CSR2_MSTATE_M << SEC_CHAN_CSR2_MSTATE_S) |
34402b553caSRafal Jaworowski 		    (SEC_CHAN_CSR2_PSTATE_M << SEC_CHAN_CSR2_PSTATE_S) |
34502b553caSRafal Jaworowski 		    (SEC_CHAN_CSR2_GSTATE_M << SEC_CHAN_CSR2_GSTATE_S);
34602b553caSRafal Jaworowski 		break;
34702b553caSRafal Jaworowski 	case 3:
34802b553caSRafal Jaworowski 		sc->sc_channel_idle_mask =
34902b553caSRafal Jaworowski 		    (SEC_CHAN_CSR3_FFLVL_M << SEC_CHAN_CSR3_FFLVL_S) |
35002b553caSRafal Jaworowski 		    (SEC_CHAN_CSR3_MSTATE_M << SEC_CHAN_CSR3_MSTATE_S) |
35102b553caSRafal Jaworowski 		    (SEC_CHAN_CSR3_PSTATE_M << SEC_CHAN_CSR3_PSTATE_S) |
35202b553caSRafal Jaworowski 		    (SEC_CHAN_CSR3_GSTATE_M << SEC_CHAN_CSR3_GSTATE_S);
35302b553caSRafal Jaworowski 		break;
35402b553caSRafal Jaworowski 	}
35502b553caSRafal Jaworowski 
35602b553caSRafal Jaworowski 	/* Init hardware */
35702b553caSRafal Jaworowski 	error = sec_init(sc);
35802b553caSRafal Jaworowski 
35902b553caSRafal Jaworowski 	if (error)
36002b553caSRafal Jaworowski 		goto fail6;
36102b553caSRafal Jaworowski 
36202b553caSRafal Jaworowski 	return (0);
36302b553caSRafal Jaworowski 
36402b553caSRafal Jaworowski fail6:
36502b553caSRafal Jaworowski 	sec_free_dma_mem(&(sc->sc_lt_dmem));
36602b553caSRafal Jaworowski fail5:
36702b553caSRafal Jaworowski 	sec_free_dma_mem(&(sc->sc_desc_dmem));
36802b553caSRafal Jaworowski fail4:
36902b553caSRafal Jaworowski 	sec_release_intr(sc, sc->sc_sec_ires, sc->sc_sec_ihand,
37002b553caSRafal Jaworowski 	    sc->sc_sec_irid, "secondary");
37102b553caSRafal Jaworowski fail3:
37202b553caSRafal Jaworowski 	sec_release_intr(sc, sc->sc_pri_ires, sc->sc_pri_ihand,
37302b553caSRafal Jaworowski 	    sc->sc_pri_irid, "primary");
37402b553caSRafal Jaworowski fail2:
37502b553caSRafal Jaworowski 	bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_rrid, sc->sc_rres);
37602b553caSRafal Jaworowski fail1:
37702b553caSRafal Jaworowski 	mtx_destroy(&sc->sc_controller_lock);
37802b553caSRafal Jaworowski 	mtx_destroy(&sc->sc_descriptors_lock);
37902b553caSRafal Jaworowski 
38002b553caSRafal Jaworowski 	return (ENXIO);
38102b553caSRafal Jaworowski }
38202b553caSRafal Jaworowski 
38302b553caSRafal Jaworowski static int
38402b553caSRafal Jaworowski sec_detach(device_t dev)
38502b553caSRafal Jaworowski {
38602b553caSRafal Jaworowski 	struct sec_softc *sc = device_get_softc(dev);
38702b553caSRafal Jaworowski 	int i, error, timeout = SEC_TIMEOUT;
38802b553caSRafal Jaworowski 
38902b553caSRafal Jaworowski 	/* Prepare driver to shutdown */
39002b553caSRafal Jaworowski 	SEC_LOCK(sc, descriptors);
39102b553caSRafal Jaworowski 	sc->sc_shutdown = 1;
39202b553caSRafal Jaworowski 	SEC_UNLOCK(sc, descriptors);
39302b553caSRafal Jaworowski 
39402b553caSRafal Jaworowski 	/* Wait until all queued processing finishes */
39502b553caSRafal Jaworowski 	while (1) {
39602b553caSRafal Jaworowski 		SEC_LOCK(sc, descriptors);
39702b553caSRafal Jaworowski 		i = SEC_READY_DESC_CNT(sc) + SEC_QUEUED_DESC_CNT(sc);
39802b553caSRafal Jaworowski 		SEC_UNLOCK(sc, descriptors);
39902b553caSRafal Jaworowski 
40002b553caSRafal Jaworowski 		if (i == 0)
40102b553caSRafal Jaworowski 			break;
40202b553caSRafal Jaworowski 
40302b553caSRafal Jaworowski 		if (timeout < 0) {
40402b553caSRafal Jaworowski 			device_printf(dev, "queue flush timeout!\n");
40502b553caSRafal Jaworowski 
40602b553caSRafal Jaworowski 			/* DMA can be still active - stop it */
40702b553caSRafal Jaworowski 			for (i = 0; i < SEC_CHANNELS; i++)
40802b553caSRafal Jaworowski 				sec_channel_reset(sc, i, 1);
40902b553caSRafal Jaworowski 
41002b553caSRafal Jaworowski 			break;
41102b553caSRafal Jaworowski 		}
41202b553caSRafal Jaworowski 
41302b553caSRafal Jaworowski 		timeout -= 1000;
41402b553caSRafal Jaworowski 		DELAY(1000);
41502b553caSRafal Jaworowski 	}
41602b553caSRafal Jaworowski 
41702b553caSRafal Jaworowski 	/* Disable interrupts */
41802b553caSRafal Jaworowski 	SEC_WRITE(sc, SEC_IER, 0);
41902b553caSRafal Jaworowski 
42002b553caSRafal Jaworowski 	/* Unregister from OCF */
42102b553caSRafal Jaworowski 	crypto_unregister_all(sc->sc_cid);
42202b553caSRafal Jaworowski 
42302b553caSRafal Jaworowski 	/* Free DMA memory */
42402b553caSRafal Jaworowski 	for (i = 0; i < SEC_DESCRIPTORS; i++)
42502b553caSRafal Jaworowski 		SEC_DESC_FREE_POINTERS(&(sc->sc_desc[i]));
42602b553caSRafal Jaworowski 
42702b553caSRafal Jaworowski 	sec_free_dma_mem(&(sc->sc_lt_dmem));
42802b553caSRafal Jaworowski 	sec_free_dma_mem(&(sc->sc_desc_dmem));
42902b553caSRafal Jaworowski 
43002b553caSRafal Jaworowski 	/* Release interrupts */
43102b553caSRafal Jaworowski 	sec_release_intr(sc, sc->sc_pri_ires, sc->sc_pri_ihand,
43202b553caSRafal Jaworowski 	    sc->sc_pri_irid, "primary");
43302b553caSRafal Jaworowski 	sec_release_intr(sc, sc->sc_sec_ires, sc->sc_sec_ihand,
43402b553caSRafal Jaworowski 	    sc->sc_sec_irid, "secondary");
43502b553caSRafal Jaworowski 
43602b553caSRafal Jaworowski 	/* Release memory */
43702b553caSRafal Jaworowski 	if (sc->sc_rres) {
43802b553caSRafal Jaworowski 		error = bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_rrid,
43902b553caSRafal Jaworowski 		    sc->sc_rres);
44002b553caSRafal Jaworowski 		if (error)
44102b553caSRafal Jaworowski 			device_printf(dev, "bus_release_resource() failed for"
44202b553caSRafal Jaworowski 			    " I/O memory, error %d\n", error);
44302b553caSRafal Jaworowski 
44402b553caSRafal Jaworowski 		sc->sc_rres = NULL;
44502b553caSRafal Jaworowski 	}
44602b553caSRafal Jaworowski 
44702b553caSRafal Jaworowski 	mtx_destroy(&sc->sc_controller_lock);
44802b553caSRafal Jaworowski 	mtx_destroy(&sc->sc_descriptors_lock);
44902b553caSRafal Jaworowski 
45002b553caSRafal Jaworowski 	return (0);
45102b553caSRafal Jaworowski }
45202b553caSRafal Jaworowski 
45302b553caSRafal Jaworowski static int
45402b553caSRafal Jaworowski sec_suspend(device_t dev)
45502b553caSRafal Jaworowski {
45602b553caSRafal Jaworowski 
45702b553caSRafal Jaworowski 	return (0);
45802b553caSRafal Jaworowski }
45902b553caSRafal Jaworowski 
46002b553caSRafal Jaworowski static int
46102b553caSRafal Jaworowski sec_resume(device_t dev)
46202b553caSRafal Jaworowski {
46302b553caSRafal Jaworowski 
46402b553caSRafal Jaworowski 	return (0);
46502b553caSRafal Jaworowski }
46602b553caSRafal Jaworowski 
467661ee6eeSRafal Jaworowski static int
46802b553caSRafal Jaworowski sec_shutdown(device_t dev)
46902b553caSRafal Jaworowski {
470661ee6eeSRafal Jaworowski 
471661ee6eeSRafal Jaworowski 	return (0);
47202b553caSRafal Jaworowski }
47302b553caSRafal Jaworowski 
47402b553caSRafal Jaworowski static int
47502b553caSRafal Jaworowski sec_setup_intr(struct sec_softc *sc, struct resource **ires, void **ihand,
47602b553caSRafal Jaworowski     int *irid, driver_intr_t handler, const char *iname)
47702b553caSRafal Jaworowski {
47802b553caSRafal Jaworowski 	int error;
47902b553caSRafal Jaworowski 
48002b553caSRafal Jaworowski 	(*ires) = bus_alloc_resource_any(sc->sc_dev, SYS_RES_IRQ, irid,
48102b553caSRafal Jaworowski 	    RF_ACTIVE);
48202b553caSRafal Jaworowski 
48302b553caSRafal Jaworowski 	if ((*ires) == NULL) {
48402b553caSRafal Jaworowski 		device_printf(sc->sc_dev, "could not allocate %s IRQ\n", iname);
48502b553caSRafal Jaworowski 		return (ENXIO);
48602b553caSRafal Jaworowski 	}
48702b553caSRafal Jaworowski 
48802b553caSRafal Jaworowski 	error = bus_setup_intr(sc->sc_dev, *ires, INTR_MPSAFE | INTR_TYPE_NET,
48902b553caSRafal Jaworowski 	    NULL, handler, sc, ihand);
49002b553caSRafal Jaworowski 
49102b553caSRafal Jaworowski 	if (error) {
49202b553caSRafal Jaworowski 		device_printf(sc->sc_dev, "failed to set up %s IRQ\n", iname);
49302b553caSRafal Jaworowski 		if (bus_release_resource(sc->sc_dev, SYS_RES_IRQ, *irid, *ires))
49402b553caSRafal Jaworowski 			device_printf(sc->sc_dev, "could not release %s IRQ\n",
49502b553caSRafal Jaworowski 			    iname);
49602b553caSRafal Jaworowski 
49702b553caSRafal Jaworowski 		(*ires) = NULL;
49802b553caSRafal Jaworowski 		return (error);
49902b553caSRafal Jaworowski 	}
50002b553caSRafal Jaworowski 
50102b553caSRafal Jaworowski 	return (0);
50202b553caSRafal Jaworowski }
50302b553caSRafal Jaworowski 
50402b553caSRafal Jaworowski static void
50502b553caSRafal Jaworowski sec_release_intr(struct sec_softc *sc, struct resource *ires, void *ihand,
50602b553caSRafal Jaworowski     int irid, const char *iname)
50702b553caSRafal Jaworowski {
50802b553caSRafal Jaworowski 	int error;
50902b553caSRafal Jaworowski 
51002b553caSRafal Jaworowski 	if (ires == NULL)
51102b553caSRafal Jaworowski 		return;
51202b553caSRafal Jaworowski 
51302b553caSRafal Jaworowski 	error = bus_teardown_intr(sc->sc_dev, ires, ihand);
51402b553caSRafal Jaworowski 	if (error)
51502b553caSRafal Jaworowski 		device_printf(sc->sc_dev, "bus_teardown_intr() failed for %s"
51602b553caSRafal Jaworowski 		    " IRQ, error %d\n", iname, error);
51702b553caSRafal Jaworowski 
51802b553caSRafal Jaworowski 	error = bus_release_resource(sc->sc_dev, SYS_RES_IRQ, irid, ires);
51902b553caSRafal Jaworowski 	if (error)
52002b553caSRafal Jaworowski 		device_printf(sc->sc_dev, "bus_release_resource() failed for %s"
52102b553caSRafal Jaworowski 		    " IRQ, error %d\n", iname, error);
52202b553caSRafal Jaworowski }
52302b553caSRafal Jaworowski 
52402b553caSRafal Jaworowski static void
52502b553caSRafal Jaworowski sec_primary_intr(void *arg)
52602b553caSRafal Jaworowski {
527c0341432SJohn Baldwin 	struct sec_session *ses;
52802b553caSRafal Jaworowski 	struct sec_softc *sc = arg;
52902b553caSRafal Jaworowski 	struct sec_desc *desc;
530c0341432SJohn Baldwin 	struct cryptop *crp;
53102b553caSRafal Jaworowski 	uint64_t isr;
532c0341432SJohn Baldwin 	uint8_t hash[HASH_MAX_LEN];
53302b553caSRafal Jaworowski 	int i, wakeup = 0;
53402b553caSRafal Jaworowski 
53502b553caSRafal Jaworowski 	SEC_LOCK(sc, controller);
53602b553caSRafal Jaworowski 
53702b553caSRafal Jaworowski 	/* Check for errors */
53802b553caSRafal Jaworowski 	isr = SEC_READ(sc, SEC_ISR);
53902b553caSRafal Jaworowski 	if (isr & sc->sc_int_error_mask) {
54002b553caSRafal Jaworowski 		/* Check each channel for error */
54102b553caSRafal Jaworowski 		for (i = 0; i < SEC_CHANNELS; i++) {
54202b553caSRafal Jaworowski 			if ((isr & SEC_INT_CH_ERR(i)) == 0)
54302b553caSRafal Jaworowski 				continue;
54402b553caSRafal Jaworowski 
54502b553caSRafal Jaworowski 			device_printf(sc->sc_dev,
54602b553caSRafal Jaworowski 			    "I/O error on channel %i!\n", i);
54702b553caSRafal Jaworowski 
54802b553caSRafal Jaworowski 			/* Find and mark problematic descriptor */
54902b553caSRafal Jaworowski 			desc = sec_find_desc(sc, SEC_READ(sc,
55002b553caSRafal Jaworowski 			    SEC_CHAN_CDPR(i)));
55102b553caSRafal Jaworowski 
55202b553caSRafal Jaworowski 			if (desc != NULL)
55302b553caSRafal Jaworowski 				desc->sd_error = EIO;
55402b553caSRafal Jaworowski 
55502b553caSRafal Jaworowski 			/* Do partial channel reset */
55602b553caSRafal Jaworowski 			sec_channel_reset(sc, i, 0);
55702b553caSRafal Jaworowski 		}
55802b553caSRafal Jaworowski 	}
55902b553caSRafal Jaworowski 
56002b553caSRafal Jaworowski 	/* ACK interrupt */
56102b553caSRafal Jaworowski 	SEC_WRITE(sc, SEC_ICR, 0xFFFFFFFFFFFFFFFFULL);
56202b553caSRafal Jaworowski 
56302b553caSRafal Jaworowski 	SEC_UNLOCK(sc, controller);
56402b553caSRafal Jaworowski 	SEC_LOCK(sc, descriptors);
56502b553caSRafal Jaworowski 
56602b553caSRafal Jaworowski 	/* Handle processed descriptors */
56702b553caSRafal Jaworowski 	SEC_DESC_SYNC(sc, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
56802b553caSRafal Jaworowski 
56902b553caSRafal Jaworowski 	while (SEC_QUEUED_DESC_CNT(sc) > 0) {
57002b553caSRafal Jaworowski 		desc = SEC_GET_QUEUED_DESC(sc);
57102b553caSRafal Jaworowski 
57202b553caSRafal Jaworowski 		if (desc->sd_desc->shd_done != 0xFF && desc->sd_error == 0) {
57302b553caSRafal Jaworowski 			SEC_PUT_BACK_QUEUED_DESC(sc);
57402b553caSRafal Jaworowski 			break;
57502b553caSRafal Jaworowski 		}
57602b553caSRafal Jaworowski 
57702b553caSRafal Jaworowski 		SEC_DESC_SYNC_POINTERS(desc, BUS_DMASYNC_PREREAD |
57802b553caSRafal Jaworowski 		    BUS_DMASYNC_PREWRITE);
57902b553caSRafal Jaworowski 
580c0341432SJohn Baldwin 		crp = desc->sd_crp;
581c0341432SJohn Baldwin 		crp->crp_etype = desc->sd_error;
582c0341432SJohn Baldwin 		if (crp->crp_etype == 0) {
583c0341432SJohn Baldwin 			ses = crypto_get_driver_session(crp->crp_session);
584c0341432SJohn Baldwin 			if (ses->ss_mlen != 0) {
585c0341432SJohn Baldwin 				if (crp->crp_op & CRYPTO_OP_VERIFY_DIGEST) {
586c0341432SJohn Baldwin 					crypto_copydata(crp,
587c0341432SJohn Baldwin 					    crp->crp_digest_start,
588c0341432SJohn Baldwin 					    ses->ss_mlen, hash);
589c0341432SJohn Baldwin 					if (timingsafe_bcmp(
590c0341432SJohn Baldwin 					    desc->sd_desc->shd_digest,
591c0341432SJohn Baldwin 					    hash, ses->ss_mlen) != 0)
592c0341432SJohn Baldwin 						crp->crp_etype = EBADMSG;
593c0341432SJohn Baldwin 				} else
594c0341432SJohn Baldwin 					crypto_copyback(crp,
595c0341432SJohn Baldwin 					    crp->crp_digest_start,
596c0341432SJohn Baldwin 					    ses->ss_mlen,
597c0341432SJohn Baldwin 					    desc->sd_desc->shd_digest);
598c0341432SJohn Baldwin 			}
599c0341432SJohn Baldwin 		}
60002b553caSRafal Jaworowski 		crypto_done(desc->sd_crp);
60102b553caSRafal Jaworowski 
60202b553caSRafal Jaworowski 		SEC_DESC_FREE_POINTERS(desc);
60302b553caSRafal Jaworowski 		SEC_DESC_FREE_LT(sc, desc);
60402b553caSRafal Jaworowski 		SEC_DESC_QUEUED2FREE(sc);
60502b553caSRafal Jaworowski 	}
60602b553caSRafal Jaworowski 
60702b553caSRafal Jaworowski 	SEC_DESC_SYNC(sc, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
60802b553caSRafal Jaworowski 
60902b553caSRafal Jaworowski 	if (!sc->sc_shutdown) {
61002b553caSRafal Jaworowski 		wakeup = sc->sc_blocked;
61102b553caSRafal Jaworowski 		sc->sc_blocked = 0;
61202b553caSRafal Jaworowski 	}
61302b553caSRafal Jaworowski 
61402b553caSRafal Jaworowski 	SEC_UNLOCK(sc, descriptors);
61502b553caSRafal Jaworowski 
61602b553caSRafal Jaworowski 	/* Enqueue ready descriptors in hardware */
61702b553caSRafal Jaworowski 	sec_enqueue(sc);
61802b553caSRafal Jaworowski 
61902b553caSRafal Jaworowski 	if (wakeup)
62002b553caSRafal Jaworowski 		crypto_unblock(sc->sc_cid, wakeup);
62102b553caSRafal Jaworowski }
62202b553caSRafal Jaworowski 
62302b553caSRafal Jaworowski static void
62402b553caSRafal Jaworowski sec_secondary_intr(void *arg)
62502b553caSRafal Jaworowski {
62602b553caSRafal Jaworowski 	struct sec_softc *sc = arg;
62702b553caSRafal Jaworowski 
62802b553caSRafal Jaworowski 	device_printf(sc->sc_dev, "spurious secondary interrupt!\n");
62902b553caSRafal Jaworowski 	sec_primary_intr(arg);
63002b553caSRafal Jaworowski }
63102b553caSRafal Jaworowski 
63202b553caSRafal Jaworowski static int
63302b553caSRafal Jaworowski sec_controller_reset(struct sec_softc *sc)
63402b553caSRafal Jaworowski {
63502b553caSRafal Jaworowski 	int timeout = SEC_TIMEOUT;
63602b553caSRafal Jaworowski 
63702b553caSRafal Jaworowski 	/* Reset Controller */
63802b553caSRafal Jaworowski 	SEC_WRITE(sc, SEC_MCR, SEC_MCR_SWR);
63902b553caSRafal Jaworowski 
64002b553caSRafal Jaworowski 	while (SEC_READ(sc, SEC_MCR) & SEC_MCR_SWR) {
64102b553caSRafal Jaworowski 		DELAY(1000);
64202b553caSRafal Jaworowski 		timeout -= 1000;
64302b553caSRafal Jaworowski 
64402b553caSRafal Jaworowski 		if (timeout < 0) {
64502b553caSRafal Jaworowski 			device_printf(sc->sc_dev, "timeout while waiting for "
64602b553caSRafal Jaworowski 			    "device reset!\n");
64702b553caSRafal Jaworowski 			return (ETIMEDOUT);
64802b553caSRafal Jaworowski 		}
64902b553caSRafal Jaworowski 	}
65002b553caSRafal Jaworowski 
65102b553caSRafal Jaworowski 	return (0);
65202b553caSRafal Jaworowski }
65302b553caSRafal Jaworowski 
65402b553caSRafal Jaworowski static int
65502b553caSRafal Jaworowski sec_channel_reset(struct sec_softc *sc, int channel, int full)
65602b553caSRafal Jaworowski {
65702b553caSRafal Jaworowski 	int timeout = SEC_TIMEOUT;
65802b553caSRafal Jaworowski 	uint64_t bit = (full) ? SEC_CHAN_CCR_R : SEC_CHAN_CCR_CON;
65902b553caSRafal Jaworowski 	uint64_t reg;
66002b553caSRafal Jaworowski 
66102b553caSRafal Jaworowski 	/* Reset Channel */
66202b553caSRafal Jaworowski 	reg = SEC_READ(sc, SEC_CHAN_CCR(channel));
66302b553caSRafal Jaworowski 	SEC_WRITE(sc, SEC_CHAN_CCR(channel), reg | bit);
66402b553caSRafal Jaworowski 
66502b553caSRafal Jaworowski 	while (SEC_READ(sc, SEC_CHAN_CCR(channel)) & bit) {
66602b553caSRafal Jaworowski 		DELAY(1000);
66702b553caSRafal Jaworowski 		timeout -= 1000;
66802b553caSRafal Jaworowski 
66902b553caSRafal Jaworowski 		if (timeout < 0) {
67002b553caSRafal Jaworowski 			device_printf(sc->sc_dev, "timeout while waiting for "
67102b553caSRafal Jaworowski 			    "channel reset!\n");
67202b553caSRafal Jaworowski 			return (ETIMEDOUT);
67302b553caSRafal Jaworowski 		}
67402b553caSRafal Jaworowski 	}
67502b553caSRafal Jaworowski 
67602b553caSRafal Jaworowski 	if (full) {
67702b553caSRafal Jaworowski 		reg = SEC_CHAN_CCR_CDIE | SEC_CHAN_CCR_NT | SEC_CHAN_CCR_BS;
67802b553caSRafal Jaworowski 
67902b553caSRafal Jaworowski 		switch(sc->sc_version) {
68002b553caSRafal Jaworowski 		case 2:
68102b553caSRafal Jaworowski 			reg |= SEC_CHAN_CCR_CDWE;
68202b553caSRafal Jaworowski 			break;
68302b553caSRafal Jaworowski 		case 3:
68402b553caSRafal Jaworowski 			reg |= SEC_CHAN_CCR_AWSE | SEC_CHAN_CCR_WGN;
68502b553caSRafal Jaworowski 			break;
68602b553caSRafal Jaworowski 		}
68702b553caSRafal Jaworowski 
68802b553caSRafal Jaworowski 		SEC_WRITE(sc, SEC_CHAN_CCR(channel), reg);
68902b553caSRafal Jaworowski 	}
69002b553caSRafal Jaworowski 
69102b553caSRafal Jaworowski 	return (0);
69202b553caSRafal Jaworowski }
69302b553caSRafal Jaworowski 
69402b553caSRafal Jaworowski static int
69502b553caSRafal Jaworowski sec_init(struct sec_softc *sc)
69602b553caSRafal Jaworowski {
69702b553caSRafal Jaworowski 	uint64_t reg;
69802b553caSRafal Jaworowski 	int error, i;
69902b553caSRafal Jaworowski 
70002b553caSRafal Jaworowski 	/* Reset controller twice to clear all pending interrupts */
70102b553caSRafal Jaworowski 	error = sec_controller_reset(sc);
70202b553caSRafal Jaworowski 	if (error)
70302b553caSRafal Jaworowski 		return (error);
70402b553caSRafal Jaworowski 
70502b553caSRafal Jaworowski 	error = sec_controller_reset(sc);
70602b553caSRafal Jaworowski 	if (error)
70702b553caSRafal Jaworowski 		return (error);
70802b553caSRafal Jaworowski 
70902b553caSRafal Jaworowski 	/* Reset channels */
71002b553caSRafal Jaworowski 	for (i = 0; i < SEC_CHANNELS; i++) {
71102b553caSRafal Jaworowski 		error = sec_channel_reset(sc, i, 1);
71202b553caSRafal Jaworowski 		if (error)
71302b553caSRafal Jaworowski 			return (error);
71402b553caSRafal Jaworowski 	}
71502b553caSRafal Jaworowski 
71602b553caSRafal Jaworowski 	/* Enable Interrupts */
71702b553caSRafal Jaworowski 	reg = SEC_INT_ITO;
71802b553caSRafal Jaworowski 	for (i = 0; i < SEC_CHANNELS; i++)
71902b553caSRafal Jaworowski 		reg |= SEC_INT_CH_DN(i) | SEC_INT_CH_ERR(i);
72002b553caSRafal Jaworowski 
72102b553caSRafal Jaworowski 	SEC_WRITE(sc, SEC_IER, reg);
72202b553caSRafal Jaworowski 
72302b553caSRafal Jaworowski 	return (error);
72402b553caSRafal Jaworowski }
72502b553caSRafal Jaworowski 
72602b553caSRafal Jaworowski static void
72702b553caSRafal Jaworowski sec_alloc_dma_mem_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error)
72802b553caSRafal Jaworowski {
72902b553caSRafal Jaworowski 	struct sec_dma_mem *dma_mem = arg;
73002b553caSRafal Jaworowski 
73102b553caSRafal Jaworowski 	if (error)
73202b553caSRafal Jaworowski 		return;
73302b553caSRafal Jaworowski 
73402b553caSRafal Jaworowski 	KASSERT(nseg == 1, ("Wrong number of segments, should be 1"));
73502b553caSRafal Jaworowski 	dma_mem->dma_paddr = segs->ds_addr;
73602b553caSRafal Jaworowski }
73702b553caSRafal Jaworowski 
73802b553caSRafal Jaworowski static void
73902b553caSRafal Jaworowski sec_dma_map_desc_cb(void *arg, bus_dma_segment_t *segs, int nseg,
74002b553caSRafal Jaworowski     int error)
74102b553caSRafal Jaworowski {
74202b553caSRafal Jaworowski 	struct sec_desc_map_info *sdmi = arg;
74302b553caSRafal Jaworowski 	struct sec_softc *sc = sdmi->sdmi_sc;
74402b553caSRafal Jaworowski 	struct sec_lt *lt = NULL;
74502b553caSRafal Jaworowski 	bus_addr_t addr;
74602b553caSRafal Jaworowski 	bus_size_t size;
74702b553caSRafal Jaworowski 	int i;
74802b553caSRafal Jaworowski 
74902b553caSRafal Jaworowski 	SEC_LOCK_ASSERT(sc, descriptors);
75002b553caSRafal Jaworowski 
75102b553caSRafal Jaworowski 	if (error)
75202b553caSRafal Jaworowski 		return;
75302b553caSRafal Jaworowski 
75402b553caSRafal Jaworowski 	for (i = 0; i < nseg; i++) {
75502b553caSRafal Jaworowski 		addr = segs[i].ds_addr;
75602b553caSRafal Jaworowski 		size = segs[i].ds_len;
75702b553caSRafal Jaworowski 
75802b553caSRafal Jaworowski 		/* Skip requested offset */
75902b553caSRafal Jaworowski 		if (sdmi->sdmi_offset >= size) {
76002b553caSRafal Jaworowski 			sdmi->sdmi_offset -= size;
76102b553caSRafal Jaworowski 			continue;
76202b553caSRafal Jaworowski 		}
76302b553caSRafal Jaworowski 
76402b553caSRafal Jaworowski 		addr += sdmi->sdmi_offset;
76502b553caSRafal Jaworowski 		size -= sdmi->sdmi_offset;
76602b553caSRafal Jaworowski 		sdmi->sdmi_offset = 0;
76702b553caSRafal Jaworowski 
76802b553caSRafal Jaworowski 		/* Do not link more than requested */
76902b553caSRafal Jaworowski 		if (sdmi->sdmi_size < size)
77002b553caSRafal Jaworowski 			size = sdmi->sdmi_size;
77102b553caSRafal Jaworowski 
77202b553caSRafal Jaworowski 		lt = SEC_ALLOC_LT_ENTRY(sc);
77302b553caSRafal Jaworowski 		lt->sl_lt->shl_length = size;
77402b553caSRafal Jaworowski 		lt->sl_lt->shl_r = 0;
77502b553caSRafal Jaworowski 		lt->sl_lt->shl_n = 0;
77602b553caSRafal Jaworowski 		lt->sl_lt->shl_ptr = addr;
77702b553caSRafal Jaworowski 
77802b553caSRafal Jaworowski 		if (sdmi->sdmi_lt_first == NULL)
77902b553caSRafal Jaworowski 			sdmi->sdmi_lt_first = lt;
78002b553caSRafal Jaworowski 
78102b553caSRafal Jaworowski 		sdmi->sdmi_lt_used += 1;
78202b553caSRafal Jaworowski 
78302b553caSRafal Jaworowski 		if ((sdmi->sdmi_size -= size) == 0)
78402b553caSRafal Jaworowski 			break;
78502b553caSRafal Jaworowski 	}
78602b553caSRafal Jaworowski 
78702b553caSRafal Jaworowski 	sdmi->sdmi_lt_last = lt;
78802b553caSRafal Jaworowski }
78902b553caSRafal Jaworowski 
79002b553caSRafal Jaworowski static int
79102b553caSRafal Jaworowski sec_alloc_dma_mem(struct sec_softc *sc, struct sec_dma_mem *dma_mem,
79202b553caSRafal Jaworowski     bus_size_t size)
79302b553caSRafal Jaworowski {
79402b553caSRafal Jaworowski 	int error;
79502b553caSRafal Jaworowski 
79602b553caSRafal Jaworowski 	if (dma_mem->dma_vaddr != NULL)
79702b553caSRafal Jaworowski 		return (EBUSY);
79802b553caSRafal Jaworowski 
79902b553caSRafal Jaworowski 	error = bus_dma_tag_create(NULL,	/* parent */
80002b553caSRafal Jaworowski 		SEC_DMA_ALIGNMENT, 0,		/* alignment, boundary */
80102b553caSRafal Jaworowski 		BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
80202b553caSRafal Jaworowski 		BUS_SPACE_MAXADDR,		/* highaddr */
80302b553caSRafal Jaworowski 		NULL, NULL,			/* filtfunc, filtfuncarg */
80402b553caSRafal Jaworowski 		size, 1,			/* maxsize, nsegments */
80502b553caSRafal Jaworowski 		size, 0,			/* maxsegsz, flags */
80602b553caSRafal Jaworowski 		NULL, NULL,			/* lockfunc, lockfuncarg */
80702b553caSRafal Jaworowski 		&(dma_mem->dma_tag));		/* dmat */
80802b553caSRafal Jaworowski 
80902b553caSRafal Jaworowski 	if (error) {
81002b553caSRafal Jaworowski 		device_printf(sc->sc_dev, "failed to allocate busdma tag, error"
81102b553caSRafal Jaworowski 		    " %i!\n", error);
81202b553caSRafal Jaworowski 		goto err1;
81302b553caSRafal Jaworowski 	}
81402b553caSRafal Jaworowski 
81502b553caSRafal Jaworowski 	error = bus_dmamem_alloc(dma_mem->dma_tag, &(dma_mem->dma_vaddr),
81602b553caSRafal Jaworowski 	    BUS_DMA_NOWAIT | BUS_DMA_ZERO, &(dma_mem->dma_map));
81702b553caSRafal Jaworowski 
81802b553caSRafal Jaworowski 	if (error) {
81902b553caSRafal Jaworowski 		device_printf(sc->sc_dev, "failed to allocate DMA safe"
82002b553caSRafal Jaworowski 		    " memory, error %i!\n", error);
82102b553caSRafal Jaworowski 		goto err2;
82202b553caSRafal Jaworowski 	}
82302b553caSRafal Jaworowski 
82402b553caSRafal Jaworowski 	error = bus_dmamap_load(dma_mem->dma_tag, dma_mem->dma_map,
82502b553caSRafal Jaworowski 		    dma_mem->dma_vaddr, size, sec_alloc_dma_mem_cb, dma_mem,
82602b553caSRafal Jaworowski 		    BUS_DMA_NOWAIT);
82702b553caSRafal Jaworowski 
82802b553caSRafal Jaworowski 	if (error) {
82902b553caSRafal Jaworowski 		device_printf(sc->sc_dev, "cannot get address of the DMA"
83002b553caSRafal Jaworowski 		    " memory, error %i\n", error);
83102b553caSRafal Jaworowski 		goto err3;
83202b553caSRafal Jaworowski 	}
83302b553caSRafal Jaworowski 
83402b553caSRafal Jaworowski 	dma_mem->dma_is_map = 0;
83502b553caSRafal Jaworowski 	return (0);
83602b553caSRafal Jaworowski 
83702b553caSRafal Jaworowski err3:
83802b553caSRafal Jaworowski 	bus_dmamem_free(dma_mem->dma_tag, dma_mem->dma_vaddr, dma_mem->dma_map);
83902b553caSRafal Jaworowski err2:
84002b553caSRafal Jaworowski 	bus_dma_tag_destroy(dma_mem->dma_tag);
84102b553caSRafal Jaworowski err1:
84202b553caSRafal Jaworowski 	dma_mem->dma_vaddr = NULL;
84302b553caSRafal Jaworowski 	return(error);
84402b553caSRafal Jaworowski }
84502b553caSRafal Jaworowski 
84602b553caSRafal Jaworowski static int
847c0341432SJohn Baldwin sec_desc_map_dma(struct sec_softc *sc, struct sec_dma_mem *dma_mem,
848c0341432SJohn Baldwin     struct cryptop *crp, bus_size_t size, struct sec_desc_map_info *sdmi)
84902b553caSRafal Jaworowski {
85002b553caSRafal Jaworowski 	int error;
85102b553caSRafal Jaworowski 
85202b553caSRafal Jaworowski 	if (dma_mem->dma_vaddr != NULL)
85302b553caSRafal Jaworowski 		return (EBUSY);
85402b553caSRafal Jaworowski 
855c0341432SJohn Baldwin 	switch (crp->crp_buf_type) {
856c0341432SJohn Baldwin 	case CRYPTO_BUF_CONTIG:
85702b553caSRafal Jaworowski 		break;
858c0341432SJohn Baldwin 	case CRYPTO_BUF_UIO:
85902b553caSRafal Jaworowski 		size = SEC_FREE_LT_CNT(sc) * SEC_MAX_DMA_BLOCK_SIZE;
86002b553caSRafal Jaworowski 		break;
861c0341432SJohn Baldwin 	case CRYPTO_BUF_MBUF:
862c0341432SJohn Baldwin 		size = m_length(crp->crp_mbuf, NULL);
86302b553caSRafal Jaworowski 		break;
86402b553caSRafal Jaworowski 	default:
86502b553caSRafal Jaworowski 		return (EINVAL);
86602b553caSRafal Jaworowski 	}
86702b553caSRafal Jaworowski 
86802b553caSRafal Jaworowski 	error = bus_dma_tag_create(NULL,	/* parent */
86902b553caSRafal Jaworowski 		SEC_DMA_ALIGNMENT, 0,		/* alignment, boundary */
87002b553caSRafal Jaworowski 		BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
87102b553caSRafal Jaworowski 		BUS_SPACE_MAXADDR,		/* highaddr */
87202b553caSRafal Jaworowski 		NULL, NULL,			/* filtfunc, filtfuncarg */
87302b553caSRafal Jaworowski 		size,				/* maxsize */
87402b553caSRafal Jaworowski 		SEC_FREE_LT_CNT(sc),		/* nsegments */
87502b553caSRafal Jaworowski 		SEC_MAX_DMA_BLOCK_SIZE, 0,	/* maxsegsz, flags */
87602b553caSRafal Jaworowski 		NULL, NULL,			/* lockfunc, lockfuncarg */
87702b553caSRafal Jaworowski 		&(dma_mem->dma_tag));		/* dmat */
87802b553caSRafal Jaworowski 
87902b553caSRafal Jaworowski 	if (error) {
88002b553caSRafal Jaworowski 		device_printf(sc->sc_dev, "failed to allocate busdma tag, error"
88102b553caSRafal Jaworowski 		    " %i!\n", error);
88202b553caSRafal Jaworowski 		dma_mem->dma_vaddr = NULL;
88302b553caSRafal Jaworowski 		return (error);
88402b553caSRafal Jaworowski 	}
88502b553caSRafal Jaworowski 
88602b553caSRafal Jaworowski 	error = bus_dmamap_create(dma_mem->dma_tag, 0, &(dma_mem->dma_map));
88702b553caSRafal Jaworowski 
88802b553caSRafal Jaworowski 	if (error) {
88902b553caSRafal Jaworowski 		device_printf(sc->sc_dev, "failed to create DMA map, error %i!"
89002b553caSRafal Jaworowski 		    "\n", error);
89102b553caSRafal Jaworowski 		bus_dma_tag_destroy(dma_mem->dma_tag);
89202b553caSRafal Jaworowski 		return (error);
89302b553caSRafal Jaworowski 	}
89402b553caSRafal Jaworowski 
895c0341432SJohn Baldwin 	error = bus_dmamap_load_crp(dma_mem->dma_tag, dma_mem->dma_map, crp,
896c0341432SJohn Baldwin 	    sec_dma_map_desc_cb, sdmi, BUS_DMA_NOWAIT);
89702b553caSRafal Jaworowski 
89802b553caSRafal Jaworowski 	if (error) {
89902b553caSRafal Jaworowski 		device_printf(sc->sc_dev, "cannot get address of the DMA"
90002b553caSRafal Jaworowski 		    " memory, error %i!\n", error);
90102b553caSRafal Jaworowski 		bus_dmamap_destroy(dma_mem->dma_tag, dma_mem->dma_map);
90202b553caSRafal Jaworowski 		bus_dma_tag_destroy(dma_mem->dma_tag);
90302b553caSRafal Jaworowski 		return (error);
90402b553caSRafal Jaworowski 	}
90502b553caSRafal Jaworowski 
90602b553caSRafal Jaworowski 	dma_mem->dma_is_map = 1;
907c0341432SJohn Baldwin 	dma_mem->dma_vaddr = crp;
90802b553caSRafal Jaworowski 
90902b553caSRafal Jaworowski 	return (0);
91002b553caSRafal Jaworowski }
91102b553caSRafal Jaworowski 
91202b553caSRafal Jaworowski static void
91302b553caSRafal Jaworowski sec_free_dma_mem(struct sec_dma_mem *dma_mem)
91402b553caSRafal Jaworowski {
91502b553caSRafal Jaworowski 
91602b553caSRafal Jaworowski 	/* Check for double free */
91702b553caSRafal Jaworowski 	if (dma_mem->dma_vaddr == NULL)
91802b553caSRafal Jaworowski 		return;
91902b553caSRafal Jaworowski 
92002b553caSRafal Jaworowski 	bus_dmamap_unload(dma_mem->dma_tag, dma_mem->dma_map);
92102b553caSRafal Jaworowski 
92202b553caSRafal Jaworowski 	if (dma_mem->dma_is_map)
92302b553caSRafal Jaworowski 		bus_dmamap_destroy(dma_mem->dma_tag, dma_mem->dma_map);
92402b553caSRafal Jaworowski 	else
92502b553caSRafal Jaworowski 		bus_dmamem_free(dma_mem->dma_tag, dma_mem->dma_vaddr,
92602b553caSRafal Jaworowski 		    dma_mem->dma_map);
92702b553caSRafal Jaworowski 
92802b553caSRafal Jaworowski 	bus_dma_tag_destroy(dma_mem->dma_tag);
92902b553caSRafal Jaworowski 	dma_mem->dma_vaddr = NULL;
93002b553caSRafal Jaworowski }
93102b553caSRafal Jaworowski 
93202b553caSRafal Jaworowski static int
93302b553caSRafal Jaworowski sec_eu_channel(struct sec_softc *sc, int eu)
93402b553caSRafal Jaworowski {
93502b553caSRafal Jaworowski 	uint64_t reg;
93602b553caSRafal Jaworowski 	int channel = 0;
93702b553caSRafal Jaworowski 
93802b553caSRafal Jaworowski 	SEC_LOCK_ASSERT(sc, controller);
93902b553caSRafal Jaworowski 
94002b553caSRafal Jaworowski 	reg = SEC_READ(sc, SEC_EUASR);
94102b553caSRafal Jaworowski 
94202b553caSRafal Jaworowski 	switch (eu) {
94302b553caSRafal Jaworowski 	case SEC_EU_AFEU:
94402b553caSRafal Jaworowski 		channel = SEC_EUASR_AFEU(reg);
94502b553caSRafal Jaworowski 		break;
94602b553caSRafal Jaworowski 	case SEC_EU_DEU:
94702b553caSRafal Jaworowski 		channel = SEC_EUASR_DEU(reg);
94802b553caSRafal Jaworowski 		break;
94902b553caSRafal Jaworowski 	case SEC_EU_MDEU_A:
95002b553caSRafal Jaworowski 	case SEC_EU_MDEU_B:
95102b553caSRafal Jaworowski 		channel = SEC_EUASR_MDEU(reg);
95202b553caSRafal Jaworowski 		break;
95302b553caSRafal Jaworowski 	case SEC_EU_RNGU:
95402b553caSRafal Jaworowski 		channel = SEC_EUASR_RNGU(reg);
95502b553caSRafal Jaworowski 		break;
95602b553caSRafal Jaworowski 	case SEC_EU_PKEU:
95702b553caSRafal Jaworowski 		channel = SEC_EUASR_PKEU(reg);
95802b553caSRafal Jaworowski 		break;
95902b553caSRafal Jaworowski 	case SEC_EU_AESU:
96002b553caSRafal Jaworowski 		channel = SEC_EUASR_AESU(reg);
96102b553caSRafal Jaworowski 		break;
96202b553caSRafal Jaworowski 	case SEC_EU_KEU:
96302b553caSRafal Jaworowski 		channel = SEC_EUASR_KEU(reg);
96402b553caSRafal Jaworowski 		break;
96502b553caSRafal Jaworowski 	case SEC_EU_CRCU:
96602b553caSRafal Jaworowski 		channel = SEC_EUASR_CRCU(reg);
96702b553caSRafal Jaworowski 		break;
96802b553caSRafal Jaworowski 	}
96902b553caSRafal Jaworowski 
97002b553caSRafal Jaworowski 	return (channel - 1);
97102b553caSRafal Jaworowski }
97202b553caSRafal Jaworowski 
97302b553caSRafal Jaworowski static int
97402b553caSRafal Jaworowski sec_enqueue_desc(struct sec_softc *sc, struct sec_desc *desc, int channel)
97502b553caSRafal Jaworowski {
97602b553caSRafal Jaworowski 	u_int fflvl = SEC_MAX_FIFO_LEVEL;
97702b553caSRafal Jaworowski 	uint64_t reg;
97802b553caSRafal Jaworowski 	int i;
97902b553caSRafal Jaworowski 
98002b553caSRafal Jaworowski 	SEC_LOCK_ASSERT(sc, controller);
98102b553caSRafal Jaworowski 
98202b553caSRafal Jaworowski 	/* Find free channel if have not got one */
98302b553caSRafal Jaworowski 	if (channel < 0) {
98402b553caSRafal Jaworowski 		for (i = 0; i < SEC_CHANNELS; i++) {
98502b553caSRafal Jaworowski 			reg = SEC_READ(sc, SEC_CHAN_CSR(channel));
98602b553caSRafal Jaworowski 
98702b553caSRafal Jaworowski 			if ((reg & sc->sc_channel_idle_mask) == 0) {
98802b553caSRafal Jaworowski 				channel = i;
98902b553caSRafal Jaworowski 				break;
99002b553caSRafal Jaworowski 			}
99102b553caSRafal Jaworowski 		}
99202b553caSRafal Jaworowski 	}
99302b553caSRafal Jaworowski 
99402b553caSRafal Jaworowski 	/* There is no free channel */
99502b553caSRafal Jaworowski 	if (channel < 0)
99602b553caSRafal Jaworowski 		return (-1);
99702b553caSRafal Jaworowski 
99802b553caSRafal Jaworowski 	/* Check FIFO level on selected channel */
99902b553caSRafal Jaworowski 	reg = SEC_READ(sc, SEC_CHAN_CSR(channel));
100002b553caSRafal Jaworowski 
100102b553caSRafal Jaworowski 	switch(sc->sc_version) {
100202b553caSRafal Jaworowski 	case 2:
100302b553caSRafal Jaworowski 		fflvl = (reg >> SEC_CHAN_CSR2_FFLVL_S) & SEC_CHAN_CSR2_FFLVL_M;
100402b553caSRafal Jaworowski 		break;
100502b553caSRafal Jaworowski 	case 3:
100602b553caSRafal Jaworowski 		fflvl = (reg >> SEC_CHAN_CSR3_FFLVL_S) & SEC_CHAN_CSR3_FFLVL_M;
100702b553caSRafal Jaworowski 		break;
100802b553caSRafal Jaworowski 	}
100902b553caSRafal Jaworowski 
101002b553caSRafal Jaworowski 	if (fflvl >= SEC_MAX_FIFO_LEVEL)
101102b553caSRafal Jaworowski 		return (-1);
101202b553caSRafal Jaworowski 
101302b553caSRafal Jaworowski 	/* Enqueue descriptor in channel */
101402b553caSRafal Jaworowski 	SEC_WRITE(sc, SEC_CHAN_FF(channel), desc->sd_desc_paddr);
101502b553caSRafal Jaworowski 
101602b553caSRafal Jaworowski 	return (channel);
101702b553caSRafal Jaworowski }
101802b553caSRafal Jaworowski 
101902b553caSRafal Jaworowski static void
102002b553caSRafal Jaworowski sec_enqueue(struct sec_softc *sc)
102102b553caSRafal Jaworowski {
102202b553caSRafal Jaworowski 	struct sec_desc *desc;
102302b553caSRafal Jaworowski 	int ch0, ch1;
102402b553caSRafal Jaworowski 
102502b553caSRafal Jaworowski 	SEC_LOCK(sc, descriptors);
102602b553caSRafal Jaworowski 	SEC_LOCK(sc, controller);
102702b553caSRafal Jaworowski 
102802b553caSRafal Jaworowski 	while (SEC_READY_DESC_CNT(sc) > 0) {
102902b553caSRafal Jaworowski 		desc = SEC_GET_READY_DESC(sc);
103002b553caSRafal Jaworowski 
103102b553caSRafal Jaworowski 		ch0 = sec_eu_channel(sc, desc->sd_desc->shd_eu_sel0);
103202b553caSRafal Jaworowski 		ch1 = sec_eu_channel(sc, desc->sd_desc->shd_eu_sel1);
103302b553caSRafal Jaworowski 
103402b553caSRafal Jaworowski 		/*
103502b553caSRafal Jaworowski 		 * Both EU are used by the same channel.
103602b553caSRafal Jaworowski 		 * Enqueue descriptor in channel used by busy EUs.
103702b553caSRafal Jaworowski 		 */
103802b553caSRafal Jaworowski 		if (ch0 >= 0 && ch0 == ch1) {
103902b553caSRafal Jaworowski 			if (sec_enqueue_desc(sc, desc, ch0) >= 0) {
104002b553caSRafal Jaworowski 				SEC_DESC_READY2QUEUED(sc);
104102b553caSRafal Jaworowski 				continue;
104202b553caSRafal Jaworowski 			}
104302b553caSRafal Jaworowski 		}
104402b553caSRafal Jaworowski 
104502b553caSRafal Jaworowski 		/*
104602b553caSRafal Jaworowski 		 * Only one EU is free.
104702b553caSRafal Jaworowski 		 * Enqueue descriptor in channel used by busy EU.
104802b553caSRafal Jaworowski 		 */
104902b553caSRafal Jaworowski 		if ((ch0 >= 0 && ch1 < 0) || (ch1 >= 0 && ch0 < 0)) {
105002b553caSRafal Jaworowski 			if (sec_enqueue_desc(sc, desc, (ch0 >= 0) ? ch0 : ch1)
105102b553caSRafal Jaworowski 			    >= 0) {
105202b553caSRafal Jaworowski 				SEC_DESC_READY2QUEUED(sc);
105302b553caSRafal Jaworowski 				continue;
105402b553caSRafal Jaworowski 			}
105502b553caSRafal Jaworowski 		}
105602b553caSRafal Jaworowski 
105702b553caSRafal Jaworowski 		/*
105802b553caSRafal Jaworowski 		 * Both EU are free.
105902b553caSRafal Jaworowski 		 * Enqueue descriptor in first free channel.
106002b553caSRafal Jaworowski 		 */
106102b553caSRafal Jaworowski 		if (ch0 < 0 && ch1 < 0) {
106202b553caSRafal Jaworowski 			if (sec_enqueue_desc(sc, desc, -1) >= 0) {
106302b553caSRafal Jaworowski 				SEC_DESC_READY2QUEUED(sc);
106402b553caSRafal Jaworowski 				continue;
106502b553caSRafal Jaworowski 			}
106602b553caSRafal Jaworowski 		}
106702b553caSRafal Jaworowski 
106802b553caSRafal Jaworowski 		/* Current descriptor can not be queued at the moment */
106902b553caSRafal Jaworowski 		SEC_PUT_BACK_READY_DESC(sc);
107002b553caSRafal Jaworowski 		break;
107102b553caSRafal Jaworowski 	}
107202b553caSRafal Jaworowski 
107302b553caSRafal Jaworowski 	SEC_UNLOCK(sc, controller);
107402b553caSRafal Jaworowski 	SEC_UNLOCK(sc, descriptors);
107502b553caSRafal Jaworowski }
107602b553caSRafal Jaworowski 
107702b553caSRafal Jaworowski static struct sec_desc *
107802b553caSRafal Jaworowski sec_find_desc(struct sec_softc *sc, bus_addr_t paddr)
107902b553caSRafal Jaworowski {
108002b553caSRafal Jaworowski 	struct sec_desc *desc = NULL;
108102b553caSRafal Jaworowski 	int i;
108202b553caSRafal Jaworowski 
108302b553caSRafal Jaworowski 	SEC_LOCK_ASSERT(sc, descriptors);
108402b553caSRafal Jaworowski 
108502b553caSRafal Jaworowski 	for (i = 0; i < SEC_CHANNELS; i++) {
108602b553caSRafal Jaworowski 		if (sc->sc_desc[i].sd_desc_paddr == paddr) {
108702b553caSRafal Jaworowski 			desc = &(sc->sc_desc[i]);
108802b553caSRafal Jaworowski 			break;
108902b553caSRafal Jaworowski 		}
109002b553caSRafal Jaworowski 	}
109102b553caSRafal Jaworowski 
109202b553caSRafal Jaworowski 	return (desc);
109302b553caSRafal Jaworowski }
109402b553caSRafal Jaworowski 
109502b553caSRafal Jaworowski static int
109602b553caSRafal Jaworowski sec_make_pointer_direct(struct sec_softc *sc, struct sec_desc *desc, u_int n,
109702b553caSRafal Jaworowski     bus_addr_t data, bus_size_t dsize)
109802b553caSRafal Jaworowski {
109902b553caSRafal Jaworowski 	struct sec_hw_desc_ptr *ptr;
110002b553caSRafal Jaworowski 
110102b553caSRafal Jaworowski 	SEC_LOCK_ASSERT(sc, descriptors);
110202b553caSRafal Jaworowski 
110302b553caSRafal Jaworowski 	ptr = &(desc->sd_desc->shd_pointer[n]);
110402b553caSRafal Jaworowski 	ptr->shdp_length = dsize;
110502b553caSRafal Jaworowski 	ptr->shdp_extent = 0;
110602b553caSRafal Jaworowski 	ptr->shdp_j = 0;
110702b553caSRafal Jaworowski 	ptr->shdp_ptr = data;
110802b553caSRafal Jaworowski 
110902b553caSRafal Jaworowski 	return (0);
111002b553caSRafal Jaworowski }
111102b553caSRafal Jaworowski 
111202b553caSRafal Jaworowski static int
111302b553caSRafal Jaworowski sec_make_pointer(struct sec_softc *sc, struct sec_desc *desc,
1114c0341432SJohn Baldwin     u_int n, struct cryptop *crp, bus_size_t doffset, bus_size_t dsize)
111502b553caSRafal Jaworowski {
111602b553caSRafal Jaworowski 	struct sec_desc_map_info sdmi = { sc, dsize, doffset, NULL, NULL, 0 };
111702b553caSRafal Jaworowski 	struct sec_hw_desc_ptr *ptr;
111802b553caSRafal Jaworowski 	int error;
111902b553caSRafal Jaworowski 
112002b553caSRafal Jaworowski 	SEC_LOCK_ASSERT(sc, descriptors);
112102b553caSRafal Jaworowski 
1122c0341432SJohn Baldwin 	error = sec_desc_map_dma(sc, &(desc->sd_ptr_dmem[n]), crp, dsize,
1123c0341432SJohn Baldwin 	    &sdmi);
112402b553caSRafal Jaworowski 
112502b553caSRafal Jaworowski 	if (error)
112602b553caSRafal Jaworowski 		return (error);
112702b553caSRafal Jaworowski 
112802b553caSRafal Jaworowski 	sdmi.sdmi_lt_last->sl_lt->shl_r = 1;
112902b553caSRafal Jaworowski 	desc->sd_lt_used += sdmi.sdmi_lt_used;
113002b553caSRafal Jaworowski 
113102b553caSRafal Jaworowski 	ptr = &(desc->sd_desc->shd_pointer[n]);
113202b553caSRafal Jaworowski 	ptr->shdp_length = dsize;
113302b553caSRafal Jaworowski 	ptr->shdp_extent = 0;
113402b553caSRafal Jaworowski 	ptr->shdp_j = 1;
113502b553caSRafal Jaworowski 	ptr->shdp_ptr = sdmi.sdmi_lt_first->sl_lt_paddr;
113602b553caSRafal Jaworowski 
113702b553caSRafal Jaworowski 	return (0);
113802b553caSRafal Jaworowski }
113902b553caSRafal Jaworowski 
1140c0341432SJohn Baldwin static bool
1141c0341432SJohn Baldwin sec_cipher_supported(const struct crypto_session_params *csp)
114202b553caSRafal Jaworowski {
114302b553caSRafal Jaworowski 
1144c0341432SJohn Baldwin 	switch (csp->csp_cipher_alg) {
1145c0341432SJohn Baldwin 	case CRYPTO_AES_CBC:
1146c0341432SJohn Baldwin 		/* AESU */
1147c0341432SJohn Baldwin 		if (csp->csp_ivlen != AES_BLOCK_LEN)
1148c0341432SJohn Baldwin 			return (false);
1149c0341432SJohn Baldwin 		break;
1150c0341432SJohn Baldwin 	case CRYPTO_DES_CBC:
1151c0341432SJohn Baldwin 	case CRYPTO_3DES_CBC:
1152c0341432SJohn Baldwin 		/* DEU */
1153c0341432SJohn Baldwin 		if (csp->csp_ivlen != DES_BLOCK_LEN)
1154c0341432SJohn Baldwin 			return (false);
1155c0341432SJohn Baldwin 		break;
1156c0341432SJohn Baldwin 	default:
1157c0341432SJohn Baldwin 		return (false);
115802b553caSRafal Jaworowski 	}
115902b553caSRafal Jaworowski 
1160c0341432SJohn Baldwin 	if (csp->csp_cipher_klen == 0 || csp->csp_cipher_klen > SEC_MAX_KEY_LEN)
1161c0341432SJohn Baldwin 		return (false);
116202b553caSRafal Jaworowski 
1163c0341432SJohn Baldwin 	return (true);
116402b553caSRafal Jaworowski }
116502b553caSRafal Jaworowski 
1166c0341432SJohn Baldwin static bool
1167c0341432SJohn Baldwin sec_auth_supported(struct sec_softc *sc,
1168c0341432SJohn Baldwin     const struct crypto_session_params *csp)
116902b553caSRafal Jaworowski {
117002b553caSRafal Jaworowski 
1171c0341432SJohn Baldwin 	switch (csp->csp_auth_alg) {
1172c0341432SJohn Baldwin 	case CRYPTO_SHA2_384_HMAC:
1173c0341432SJohn Baldwin 	case CRYPTO_SHA2_512_HMAC:
1174c0341432SJohn Baldwin 		if (sc->sc_version < 3)
1175c0341432SJohn Baldwin 			return (false);
1176c0341432SJohn Baldwin 		/* FALLTHROUGH */
1177c0341432SJohn Baldwin 	case CRYPTO_MD5_HMAC:
1178c0341432SJohn Baldwin 	case CRYPTO_SHA1_HMAC:
1179c0341432SJohn Baldwin 	case CRYPTO_SHA2_256_HMAC:
1180c0341432SJohn Baldwin 		if (csp->csp_auth_klen > SEC_MAX_KEY_LEN)
1181c0341432SJohn Baldwin 			return (false);
1182c0341432SJohn Baldwin 		break;
1183c0341432SJohn Baldwin 	case CRYPTO_MD5:
1184c0341432SJohn Baldwin 	case CRYPTO_SHA1:
1185c0341432SJohn Baldwin 		break;
1186c0341432SJohn Baldwin 	default:
1187c0341432SJohn Baldwin 		return (false);
118802b553caSRafal Jaworowski 	}
1189c0341432SJohn Baldwin 	return (true);
119002b553caSRafal Jaworowski }
119102b553caSRafal Jaworowski 
119202b553caSRafal Jaworowski static int
1193c0341432SJohn Baldwin sec_probesession(device_t dev, const struct crypto_session_params *csp)
119402b553caSRafal Jaworowski {
119502b553caSRafal Jaworowski 	struct sec_softc *sc = device_get_softc(dev);
1196c0341432SJohn Baldwin 
1197c0341432SJohn Baldwin 	if (csp->csp_flags != 0)
1198c0341432SJohn Baldwin 		return (EINVAL);
1199c0341432SJohn Baldwin 	switch (csp->csp_mode) {
1200c0341432SJohn Baldwin 	case CSP_MODE_DIGEST:
1201c0341432SJohn Baldwin 		if (!sec_auth_supported(sc, csp))
1202c0341432SJohn Baldwin 			return (EINVAL);
1203c0341432SJohn Baldwin 		break;
1204c0341432SJohn Baldwin 	case CSP_MODE_CIPHER:
1205c0341432SJohn Baldwin 		if (!sec_cipher_supported(csp))
1206c0341432SJohn Baldwin 			return (EINVAL);
1207c0341432SJohn Baldwin 		break;
1208c0341432SJohn Baldwin 	case CSP_MODE_ETA:
1209c0341432SJohn Baldwin 		if (!sec_auth_supported(sc, csp) || !sec_cipher_supported(csp))
1210c0341432SJohn Baldwin 			return (EINVAL);
1211c0341432SJohn Baldwin 		break;
1212c0341432SJohn Baldwin 	default:
1213c0341432SJohn Baldwin 		return (EINVAL);
1214c0341432SJohn Baldwin 	}
1215c0341432SJohn Baldwin 	return (CRYPTODEV_PROBE_HARDWARE);
1216c0341432SJohn Baldwin }
1217c0341432SJohn Baldwin 
1218c0341432SJohn Baldwin static int
1219c0341432SJohn Baldwin sec_newsession(device_t dev, crypto_session_t cses,
1220c0341432SJohn Baldwin     const struct crypto_session_params *csp)
1221c0341432SJohn Baldwin {
122202b553caSRafal Jaworowski 	struct sec_eu_methods *eu = sec_eus;
122302b553caSRafal Jaworowski 	struct sec_session *ses;
122402b553caSRafal Jaworowski 
12251b0909d5SConrad Meyer 	ses = crypto_get_driver_session(cses);
122602b553caSRafal Jaworowski 
122702b553caSRafal Jaworowski 	/* Find EU for this session */
122802b553caSRafal Jaworowski 	while (eu->sem_make_desc != NULL) {
1229c0341432SJohn Baldwin 		if (eu->sem_newsession(csp))
123002b553caSRafal Jaworowski 			break;
123102b553caSRafal Jaworowski 		eu++;
123202b553caSRafal Jaworowski 	}
1233c0341432SJohn Baldwin 	KASSERT(eu->sem_make_desc != NULL, ("failed to find eu for session"));
123402b553caSRafal Jaworowski 
123502b553caSRafal Jaworowski 	/* Save cipher key */
1236c0341432SJohn Baldwin 	if (csp->csp_cipher_key != NULL)
1237c0341432SJohn Baldwin 		memcpy(ses->ss_key, csp->csp_cipher_key, csp->csp_cipher_klen);
123802b553caSRafal Jaworowski 
123902b553caSRafal Jaworowski 	/* Save digest key */
1240c0341432SJohn Baldwin 	if (csp->csp_auth_key != NULL)
1241c0341432SJohn Baldwin 		memcpy(ses->ss_mkey, csp->csp_auth_key, csp->csp_auth_klen);
1242c0341432SJohn Baldwin 
1243c0341432SJohn Baldwin 	if (csp->csp_auth_alg != 0) {
1244c0341432SJohn Baldwin 		if (csp->csp_auth_mlen == 0)
1245c0341432SJohn Baldwin 			ses->ss_mlen = crypto_auth_hash(csp)->hashsize;
1246c0341432SJohn Baldwin 		else
1247c0341432SJohn Baldwin 			ses->ss_mlen = csp->csp_auth_mlen;
124802b553caSRafal Jaworowski 	}
124902b553caSRafal Jaworowski 
125002b553caSRafal Jaworowski 	return (0);
125102b553caSRafal Jaworowski }
125202b553caSRafal Jaworowski 
125302b553caSRafal Jaworowski static int
125402b553caSRafal Jaworowski sec_process(device_t dev, struct cryptop *crp, int hint)
125502b553caSRafal Jaworowski {
125602b553caSRafal Jaworowski 	struct sec_softc *sc = device_get_softc(dev);
125702b553caSRafal Jaworowski 	struct sec_desc *desc = NULL;
1258c0341432SJohn Baldwin 	const struct crypto_session_params *csp;
125902b553caSRafal Jaworowski 	struct sec_session *ses;
1260c0341432SJohn Baldwin 	int error = 0;
126102b553caSRafal Jaworowski 
12621b0909d5SConrad Meyer 	ses = crypto_get_driver_session(crp->crp_session);
1263c0341432SJohn Baldwin 	csp = crypto_get_params(crp->crp_session);
126402b553caSRafal Jaworowski 
126502b553caSRafal Jaworowski 	/* Check for input length */
126602b553caSRafal Jaworowski 	if (crp->crp_ilen > SEC_MAX_DMA_BLOCK_SIZE) {
126702b553caSRafal Jaworowski 		crp->crp_etype = E2BIG;
126802b553caSRafal Jaworowski 		crypto_done(crp);
126902b553caSRafal Jaworowski 		return (0);
127002b553caSRafal Jaworowski 	}
127102b553caSRafal Jaworowski 
127202b553caSRafal Jaworowski 	SEC_LOCK(sc, descriptors);
127302b553caSRafal Jaworowski 	SEC_DESC_SYNC(sc, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
127402b553caSRafal Jaworowski 
127502b553caSRafal Jaworowski 	/* Block driver if there is no free descriptors or we are going down */
127602b553caSRafal Jaworowski 	if (SEC_FREE_DESC_CNT(sc) == 0 || sc->sc_shutdown) {
127702b553caSRafal Jaworowski 		sc->sc_blocked |= CRYPTO_SYMQ;
127802b553caSRafal Jaworowski 		SEC_UNLOCK(sc, descriptors);
127902b553caSRafal Jaworowski 		return (ERESTART);
128002b553caSRafal Jaworowski 	}
128102b553caSRafal Jaworowski 
128202b553caSRafal Jaworowski 	/* Prepare descriptor */
128302b553caSRafal Jaworowski 	desc = SEC_GET_FREE_DESC(sc);
128402b553caSRafal Jaworowski 	desc->sd_lt_used = 0;
128502b553caSRafal Jaworowski 	desc->sd_error = 0;
128602b553caSRafal Jaworowski 	desc->sd_crp = crp;
128702b553caSRafal Jaworowski 
1288*29fe41ddSJohn Baldwin 	if (csp->csp_cipher_alg != 0)
1289*29fe41ddSJohn Baldwin 		crypto_read_iv(crp, desc->sd_desc->shd_iv);
129002b553caSRafal Jaworowski 
1291c0341432SJohn Baldwin 	if (crp->crp_cipher_key != NULL)
1292c0341432SJohn Baldwin 		memcpy(ses->ss_key, crp->crp_cipher_key, csp->csp_cipher_klen);
129302b553caSRafal Jaworowski 
1294c0341432SJohn Baldwin 	if (crp->crp_auth_key != NULL)
1295c0341432SJohn Baldwin 		memcpy(ses->ss_mkey, crp->crp_auth_key, csp->csp_auth_klen);
129602b553caSRafal Jaworowski 
1297c0341432SJohn Baldwin 	memcpy(desc->sd_desc->shd_key, ses->ss_key, csp->csp_cipher_klen);
1298c0341432SJohn Baldwin 	memcpy(desc->sd_desc->shd_mkey, ses->ss_mkey, csp->csp_auth_klen);
129902b553caSRafal Jaworowski 
1300c0341432SJohn Baldwin 	error = ses->ss_eu->sem_make_desc(sc, csp, desc, crp);
130102b553caSRafal Jaworowski 
130202b553caSRafal Jaworowski 	if (error) {
130302b553caSRafal Jaworowski 		SEC_DESC_FREE_POINTERS(desc);
130402b553caSRafal Jaworowski 		SEC_DESC_PUT_BACK_LT(sc, desc);
130502b553caSRafal Jaworowski 		SEC_PUT_BACK_FREE_DESC(sc);
130602b553caSRafal Jaworowski 		SEC_UNLOCK(sc, descriptors);
130702b553caSRafal Jaworowski 		crp->crp_etype = error;
130802b553caSRafal Jaworowski 		crypto_done(crp);
130902b553caSRafal Jaworowski 		return (0);
131002b553caSRafal Jaworowski 	}
131102b553caSRafal Jaworowski 
131202b553caSRafal Jaworowski 	/*
131302b553caSRafal Jaworowski 	 * Skip DONE interrupt if this is not last request in burst, but only
131402b553caSRafal Jaworowski 	 * if we are running on SEC 3.X. On SEC 2.X we have to enable DONE
131502b553caSRafal Jaworowski 	 * signaling on each descriptor.
131602b553caSRafal Jaworowski 	 */
131702b553caSRafal Jaworowski 	if ((hint & CRYPTO_HINT_MORE) && sc->sc_version == 3)
131802b553caSRafal Jaworowski 		desc->sd_desc->shd_dn = 0;
131902b553caSRafal Jaworowski 	else
132002b553caSRafal Jaworowski 		desc->sd_desc->shd_dn = 1;
132102b553caSRafal Jaworowski 
132202b553caSRafal Jaworowski 	SEC_DESC_SYNC(sc, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
132302b553caSRafal Jaworowski 	SEC_DESC_SYNC_POINTERS(desc, BUS_DMASYNC_POSTREAD |
132402b553caSRafal Jaworowski 	    BUS_DMASYNC_POSTWRITE);
132502b553caSRafal Jaworowski 	SEC_DESC_FREE2READY(sc);
132602b553caSRafal Jaworowski 	SEC_UNLOCK(sc, descriptors);
132702b553caSRafal Jaworowski 
132802b553caSRafal Jaworowski 	/* Enqueue ready descriptors in hardware */
132902b553caSRafal Jaworowski 	sec_enqueue(sc);
133002b553caSRafal Jaworowski 
133102b553caSRafal Jaworowski 	return (0);
133202b553caSRafal Jaworowski }
133302b553caSRafal Jaworowski 
133402b553caSRafal Jaworowski static int
133502b553caSRafal Jaworowski sec_build_common_ns_desc(struct sec_softc *sc, struct sec_desc *desc,
1336c0341432SJohn Baldwin     const struct crypto_session_params *csp, struct cryptop *crp)
133702b553caSRafal Jaworowski {
133802b553caSRafal Jaworowski 	struct sec_hw_desc *hd = desc->sd_desc;
133902b553caSRafal Jaworowski 	int error;
134002b553caSRafal Jaworowski 
134102b553caSRafal Jaworowski 	hd->shd_desc_type = SEC_DT_COMMON_NONSNOOP;
134202b553caSRafal Jaworowski 	hd->shd_eu_sel1 = SEC_EU_NONE;
134302b553caSRafal Jaworowski 	hd->shd_mode1 = 0;
134402b553caSRafal Jaworowski 
134502b553caSRafal Jaworowski 	/* Pointer 0: NULL */
134602b553caSRafal Jaworowski 	error = sec_make_pointer_direct(sc, desc, 0, 0, 0);
134702b553caSRafal Jaworowski 	if (error)
134802b553caSRafal Jaworowski 		return (error);
134902b553caSRafal Jaworowski 
135002b553caSRafal Jaworowski 	/* Pointer 1: IV IN */
135102b553caSRafal Jaworowski 	error = sec_make_pointer_direct(sc, desc, 1, desc->sd_desc_paddr +
1352c0341432SJohn Baldwin 	    offsetof(struct sec_hw_desc, shd_iv), csp->csp_ivlen);
135302b553caSRafal Jaworowski 	if (error)
135402b553caSRafal Jaworowski 		return (error);
135502b553caSRafal Jaworowski 
135602b553caSRafal Jaworowski 	/* Pointer 2: Cipher Key */
135702b553caSRafal Jaworowski 	error = sec_make_pointer_direct(sc, desc, 2, desc->sd_desc_paddr +
1358c0341432SJohn Baldwin 	    offsetof(struct sec_hw_desc, shd_key), csp->csp_cipher_klen);
135902b553caSRafal Jaworowski  	if (error)
136002b553caSRafal Jaworowski 		return (error);
136102b553caSRafal Jaworowski 
136202b553caSRafal Jaworowski 	/* Pointer 3: Data IN */
1363c0341432SJohn Baldwin 	error = sec_make_pointer(sc, desc, 3, crp, crp->crp_payload_start,
1364c0341432SJohn Baldwin 	    crp->crp_payload_length);
136502b553caSRafal Jaworowski 	if (error)
136602b553caSRafal Jaworowski 		return (error);
136702b553caSRafal Jaworowski 
136802b553caSRafal Jaworowski 	/* Pointer 4: Data OUT */
1369c0341432SJohn Baldwin 	error = sec_make_pointer(sc, desc, 4, crp, crp->crp_payload_start,
1370c0341432SJohn Baldwin 	    crp->crp_payload_length);
137102b553caSRafal Jaworowski 	if (error)
137202b553caSRafal Jaworowski 		return (error);
137302b553caSRafal Jaworowski 
137402b553caSRafal Jaworowski 	/* Pointer 5: IV OUT (Not used: NULL) */
137502b553caSRafal Jaworowski 	error = sec_make_pointer_direct(sc, desc, 5, 0, 0);
137602b553caSRafal Jaworowski 	if (error)
137702b553caSRafal Jaworowski 		return (error);
137802b553caSRafal Jaworowski 
137902b553caSRafal Jaworowski 	/* Pointer 6: NULL */
138002b553caSRafal Jaworowski 	error = sec_make_pointer_direct(sc, desc, 6, 0, 0);
138102b553caSRafal Jaworowski 
138202b553caSRafal Jaworowski 	return (error);
138302b553caSRafal Jaworowski }
138402b553caSRafal Jaworowski 
138502b553caSRafal Jaworowski static int
138602b553caSRafal Jaworowski sec_build_common_s_desc(struct sec_softc *sc, struct sec_desc *desc,
1387c0341432SJohn Baldwin     const struct crypto_session_params *csp, struct cryptop *crp)
138802b553caSRafal Jaworowski {
138902b553caSRafal Jaworowski 	struct sec_hw_desc *hd = desc->sd_desc;
139002b553caSRafal Jaworowski 	u_int eu, mode, hashlen;
139102b553caSRafal Jaworowski 	int error;
139202b553caSRafal Jaworowski 
1393c0341432SJohn Baldwin 	error = sec_mdeu_config(csp, &eu, &mode, &hashlen);
139402b553caSRafal Jaworowski 	if (error)
139502b553caSRafal Jaworowski 		return (error);
139602b553caSRafal Jaworowski 
139702b553caSRafal Jaworowski 	hd->shd_desc_type = SEC_DT_HMAC_SNOOP;
139802b553caSRafal Jaworowski 	hd->shd_eu_sel1 = eu;
139902b553caSRafal Jaworowski 	hd->shd_mode1 = mode;
140002b553caSRafal Jaworowski 
140102b553caSRafal Jaworowski 	/* Pointer 0: HMAC Key */
140202b553caSRafal Jaworowski 	error = sec_make_pointer_direct(sc, desc, 0, desc->sd_desc_paddr +
1403c0341432SJohn Baldwin 	    offsetof(struct sec_hw_desc, shd_mkey), csp->csp_auth_klen);
140402b553caSRafal Jaworowski 	if (error)
140502b553caSRafal Jaworowski 		return (error);
140602b553caSRafal Jaworowski 
140702b553caSRafal Jaworowski 	/* Pointer 1: HMAC-Only Data IN */
1408c0341432SJohn Baldwin 	error = sec_make_pointer(sc, desc, 1, crp, crp->crp_aad_start,
1409c0341432SJohn Baldwin 	    crp->crp_aad_length);
141002b553caSRafal Jaworowski 	if (error)
141102b553caSRafal Jaworowski 		return (error);
141202b553caSRafal Jaworowski 
141302b553caSRafal Jaworowski 	/* Pointer 2: Cipher Key */
141402b553caSRafal Jaworowski 	error = sec_make_pointer_direct(sc, desc, 2, desc->sd_desc_paddr +
1415c0341432SJohn Baldwin 	    offsetof(struct sec_hw_desc, shd_key), csp->csp_cipher_klen);
141602b553caSRafal Jaworowski  	if (error)
141702b553caSRafal Jaworowski 		return (error);
141802b553caSRafal Jaworowski 
141902b553caSRafal Jaworowski 	/* Pointer 3: IV IN */
142002b553caSRafal Jaworowski 	error = sec_make_pointer_direct(sc, desc, 3, desc->sd_desc_paddr +
1421c0341432SJohn Baldwin 	    offsetof(struct sec_hw_desc, shd_iv), csp->csp_ivlen);
142202b553caSRafal Jaworowski 	if (error)
142302b553caSRafal Jaworowski 		return (error);
142402b553caSRafal Jaworowski 
142502b553caSRafal Jaworowski 	/* Pointer 4: Data IN */
1426c0341432SJohn Baldwin 	error = sec_make_pointer(sc, desc, 4, crp, crp->crp_payload_start,
1427c0341432SJohn Baldwin 	    crp->crp_payload_length);
142802b553caSRafal Jaworowski 	if (error)
142902b553caSRafal Jaworowski 		return (error);
143002b553caSRafal Jaworowski 
143102b553caSRafal Jaworowski 	/* Pointer 5: Data OUT */
1432c0341432SJohn Baldwin 	error = sec_make_pointer(sc, desc, 5, crp, crp->crp_payload_start,
1433c0341432SJohn Baldwin 	    crp->crp_payload_length);
143402b553caSRafal Jaworowski 	if (error)
143502b553caSRafal Jaworowski 		return (error);
143602b553caSRafal Jaworowski 
143702b553caSRafal Jaworowski 	/* Pointer 6: HMAC OUT */
1438c0341432SJohn Baldwin 	error = sec_make_pointer_direct(sc, desc, 6, desc->sd_desc_paddr +
1439c0341432SJohn Baldwin 	    offsetof(struct sec_hw_desc, shd_digest), hashlen);
144002b553caSRafal Jaworowski 
144102b553caSRafal Jaworowski 	return (error);
144202b553caSRafal Jaworowski }
144302b553caSRafal Jaworowski 
144402b553caSRafal Jaworowski /* AESU */
144502b553caSRafal Jaworowski 
1446c0341432SJohn Baldwin static bool
1447c0341432SJohn Baldwin sec_aesu_newsession(const struct crypto_session_params *csp)
144802b553caSRafal Jaworowski {
144902b553caSRafal Jaworowski 
1450c0341432SJohn Baldwin 	return (csp->csp_cipher_alg == CRYPTO_AES_CBC);
145102b553caSRafal Jaworowski }
145202b553caSRafal Jaworowski 
145302b553caSRafal Jaworowski static int
1454c0341432SJohn Baldwin sec_aesu_make_desc(struct sec_softc *sc,
1455c0341432SJohn Baldwin     const struct crypto_session_params *csp, struct sec_desc *desc,
1456c0341432SJohn Baldwin     struct cryptop *crp)
145702b553caSRafal Jaworowski {
145802b553caSRafal Jaworowski 	struct sec_hw_desc *hd = desc->sd_desc;
145902b553caSRafal Jaworowski 	int error;
146002b553caSRafal Jaworowski 
146102b553caSRafal Jaworowski 	hd->shd_eu_sel0 = SEC_EU_AESU;
146202b553caSRafal Jaworowski 	hd->shd_mode0 = SEC_AESU_MODE_CBC;
146302b553caSRafal Jaworowski 
1464c0341432SJohn Baldwin 	if (CRYPTO_OP_IS_ENCRYPT(crp->crp_op)) {
146502b553caSRafal Jaworowski 		hd->shd_mode0 |= SEC_AESU_MODE_ED;
146602b553caSRafal Jaworowski 		hd->shd_dir = 0;
146702b553caSRafal Jaworowski 	} else
146802b553caSRafal Jaworowski 		hd->shd_dir = 1;
146902b553caSRafal Jaworowski 
1470c0341432SJohn Baldwin 	if (csp->csp_mode == CSP_MODE_ETA)
1471c0341432SJohn Baldwin 		error = sec_build_common_s_desc(sc, desc, csp, crp);
147202b553caSRafal Jaworowski 	else
1473c0341432SJohn Baldwin 		error = sec_build_common_ns_desc(sc, desc, csp, crp);
147402b553caSRafal Jaworowski 
147502b553caSRafal Jaworowski 	return (error);
147602b553caSRafal Jaworowski }
147702b553caSRafal Jaworowski 
147802b553caSRafal Jaworowski /* DEU */
147902b553caSRafal Jaworowski 
1480c0341432SJohn Baldwin static bool
1481c0341432SJohn Baldwin sec_deu_newsession(const struct crypto_session_params *csp)
148202b553caSRafal Jaworowski {
148302b553caSRafal Jaworowski 
1484c0341432SJohn Baldwin 	switch (csp->csp_cipher_alg) {
148502b553caSRafal Jaworowski 	case CRYPTO_DES_CBC:
148602b553caSRafal Jaworowski 	case CRYPTO_3DES_CBC:
1487c0341432SJohn Baldwin 		return (true);
148802b553caSRafal Jaworowski 	default:
1489c0341432SJohn Baldwin 		return (false);
149002b553caSRafal Jaworowski 	}
149102b553caSRafal Jaworowski }
149202b553caSRafal Jaworowski 
149302b553caSRafal Jaworowski static int
1494c0341432SJohn Baldwin sec_deu_make_desc(struct sec_softc *sc, const struct crypto_session_params *csp,
1495c0341432SJohn Baldwin     struct sec_desc *desc, struct cryptop *crp)
149602b553caSRafal Jaworowski {
149702b553caSRafal Jaworowski 	struct sec_hw_desc *hd = desc->sd_desc;
149802b553caSRafal Jaworowski 	int error;
149902b553caSRafal Jaworowski 
150002b553caSRafal Jaworowski 	hd->shd_eu_sel0 = SEC_EU_DEU;
150102b553caSRafal Jaworowski 	hd->shd_mode0 = SEC_DEU_MODE_CBC;
150202b553caSRafal Jaworowski 
1503c0341432SJohn Baldwin 	switch (csp->csp_cipher_alg) {
150402b553caSRafal Jaworowski 	case CRYPTO_3DES_CBC:
150502b553caSRafal Jaworowski 		hd->shd_mode0 |= SEC_DEU_MODE_TS;
150602b553caSRafal Jaworowski 		break;
150702b553caSRafal Jaworowski 	case CRYPTO_DES_CBC:
150802b553caSRafal Jaworowski 		break;
150902b553caSRafal Jaworowski 	default:
151002b553caSRafal Jaworowski 		return (EINVAL);
151102b553caSRafal Jaworowski 	}
151202b553caSRafal Jaworowski 
1513c0341432SJohn Baldwin 	if (CRYPTO_OP_IS_ENCRYPT(crp->crp_op)) {
151402b553caSRafal Jaworowski 		hd->shd_mode0 |= SEC_DEU_MODE_ED;
151502b553caSRafal Jaworowski 		hd->shd_dir = 0;
151602b553caSRafal Jaworowski 	} else
151702b553caSRafal Jaworowski 		hd->shd_dir = 1;
151802b553caSRafal Jaworowski 
1519c0341432SJohn Baldwin 	if (csp->csp_mode == CSP_MODE_ETA)
1520c0341432SJohn Baldwin 		error = sec_build_common_s_desc(sc, desc, csp, crp);
152102b553caSRafal Jaworowski 	else
1522c0341432SJohn Baldwin 		error = sec_build_common_ns_desc(sc, desc, csp, crp);
152302b553caSRafal Jaworowski 
152402b553caSRafal Jaworowski 	return (error);
152502b553caSRafal Jaworowski }
152602b553caSRafal Jaworowski 
152702b553caSRafal Jaworowski /* MDEU */
152802b553caSRafal Jaworowski 
1529c0341432SJohn Baldwin static bool
153002b553caSRafal Jaworowski sec_mdeu_can_handle(u_int alg)
153102b553caSRafal Jaworowski {
153202b553caSRafal Jaworowski 	switch (alg) {
153302b553caSRafal Jaworowski 	case CRYPTO_MD5:
153402b553caSRafal Jaworowski 	case CRYPTO_SHA1:
153502b553caSRafal Jaworowski 	case CRYPTO_MD5_HMAC:
153602b553caSRafal Jaworowski 	case CRYPTO_SHA1_HMAC:
153702b553caSRafal Jaworowski 	case CRYPTO_SHA2_256_HMAC:
153802b553caSRafal Jaworowski 	case CRYPTO_SHA2_384_HMAC:
153902b553caSRafal Jaworowski 	case CRYPTO_SHA2_512_HMAC:
1540c0341432SJohn Baldwin 		return (true);
154102b553caSRafal Jaworowski 	default:
1542c0341432SJohn Baldwin 		return (false);
154302b553caSRafal Jaworowski 	}
154402b553caSRafal Jaworowski }
154502b553caSRafal Jaworowski 
154602b553caSRafal Jaworowski static int
1547c0341432SJohn Baldwin sec_mdeu_config(const struct crypto_session_params *csp, u_int *eu, u_int *mode,
1548c0341432SJohn Baldwin     u_int *hashlen)
154902b553caSRafal Jaworowski {
155002b553caSRafal Jaworowski 
155102b553caSRafal Jaworowski 	*mode = SEC_MDEU_MODE_PD | SEC_MDEU_MODE_INIT;
155202b553caSRafal Jaworowski 	*eu = SEC_EU_NONE;
155302b553caSRafal Jaworowski 
1554c0341432SJohn Baldwin 	switch (csp->csp_auth_alg) {
155502b553caSRafal Jaworowski 	case CRYPTO_MD5_HMAC:
155602b553caSRafal Jaworowski 		*mode |= SEC_MDEU_MODE_HMAC;
155702b553caSRafal Jaworowski 		/* FALLTHROUGH */
155802b553caSRafal Jaworowski 	case CRYPTO_MD5:
155902b553caSRafal Jaworowski 		*eu = SEC_EU_MDEU_A;
156002b553caSRafal Jaworowski 		*mode |= SEC_MDEU_MODE_MD5;
156102b553caSRafal Jaworowski 		*hashlen = MD5_HASH_LEN;
156202b553caSRafal Jaworowski 		break;
156302b553caSRafal Jaworowski 	case CRYPTO_SHA1_HMAC:
156402b553caSRafal Jaworowski 		*mode |= SEC_MDEU_MODE_HMAC;
156502b553caSRafal Jaworowski 		/* FALLTHROUGH */
156602b553caSRafal Jaworowski 	case CRYPTO_SHA1:
156702b553caSRafal Jaworowski 		*eu = SEC_EU_MDEU_A;
156802b553caSRafal Jaworowski 		*mode |= SEC_MDEU_MODE_SHA1;
156902b553caSRafal Jaworowski 		*hashlen = SHA1_HASH_LEN;
157002b553caSRafal Jaworowski 		break;
157102b553caSRafal Jaworowski 	case CRYPTO_SHA2_256_HMAC:
157202b553caSRafal Jaworowski 		*mode |= SEC_MDEU_MODE_HMAC | SEC_MDEU_MODE_SHA256;
157302b553caSRafal Jaworowski 		*eu = SEC_EU_MDEU_A;
157402b553caSRafal Jaworowski 		break;
157502b553caSRafal Jaworowski 	case CRYPTO_SHA2_384_HMAC:
157602b553caSRafal Jaworowski 		*mode |= SEC_MDEU_MODE_HMAC | SEC_MDEU_MODE_SHA384;
157702b553caSRafal Jaworowski 		*eu = SEC_EU_MDEU_B;
157802b553caSRafal Jaworowski 		break;
157902b553caSRafal Jaworowski 	case CRYPTO_SHA2_512_HMAC:
158002b553caSRafal Jaworowski 		*mode |= SEC_MDEU_MODE_HMAC | SEC_MDEU_MODE_SHA512;
158102b553caSRafal Jaworowski 		*eu = SEC_EU_MDEU_B;
158202b553caSRafal Jaworowski 		break;
158302b553caSRafal Jaworowski 	default:
158402b553caSRafal Jaworowski 		return (EINVAL);
158502b553caSRafal Jaworowski 	}
158602b553caSRafal Jaworowski 
158702b553caSRafal Jaworowski 	if (*mode & SEC_MDEU_MODE_HMAC)
158802b553caSRafal Jaworowski 		*hashlen = SEC_HMAC_HASH_LEN;
158902b553caSRafal Jaworowski 
159002b553caSRafal Jaworowski 	return (0);
159102b553caSRafal Jaworowski }
159202b553caSRafal Jaworowski 
1593c0341432SJohn Baldwin static bool
1594c0341432SJohn Baldwin sec_mdeu_newsession(const struct crypto_session_params *csp)
159502b553caSRafal Jaworowski {
159602b553caSRafal Jaworowski 
1597c0341432SJohn Baldwin 	return (sec_mdeu_can_handle(csp->csp_auth_alg));
159802b553caSRafal Jaworowski }
159902b553caSRafal Jaworowski 
160002b553caSRafal Jaworowski static int
1601c0341432SJohn Baldwin sec_mdeu_make_desc(struct sec_softc *sc,
1602c0341432SJohn Baldwin     const struct crypto_session_params *csp,
1603c0341432SJohn Baldwin     struct sec_desc *desc, struct cryptop *crp)
160402b553caSRafal Jaworowski {
160502b553caSRafal Jaworowski 	struct sec_hw_desc *hd = desc->sd_desc;
160602b553caSRafal Jaworowski 	u_int eu, mode, hashlen;
160702b553caSRafal Jaworowski 	int error;
160802b553caSRafal Jaworowski 
1609c0341432SJohn Baldwin 	error = sec_mdeu_config(csp, &eu, &mode, &hashlen);
161002b553caSRafal Jaworowski 	if (error)
161102b553caSRafal Jaworowski 		return (error);
161202b553caSRafal Jaworowski 
161302b553caSRafal Jaworowski 	hd->shd_desc_type = SEC_DT_COMMON_NONSNOOP;
161402b553caSRafal Jaworowski 	hd->shd_eu_sel0 = eu;
161502b553caSRafal Jaworowski 	hd->shd_mode0 = mode;
161602b553caSRafal Jaworowski 	hd->shd_eu_sel1 = SEC_EU_NONE;
161702b553caSRafal Jaworowski 	hd->shd_mode1 = 0;
161802b553caSRafal Jaworowski 
161902b553caSRafal Jaworowski 	/* Pointer 0: NULL */
162002b553caSRafal Jaworowski 	error = sec_make_pointer_direct(sc, desc, 0, 0, 0);
162102b553caSRafal Jaworowski 	if (error)
162202b553caSRafal Jaworowski 		return (error);
162302b553caSRafal Jaworowski 
162402b553caSRafal Jaworowski 	/* Pointer 1: Context In (Not used: NULL) */
162502b553caSRafal Jaworowski 	error = sec_make_pointer_direct(sc, desc, 1, 0, 0);
162602b553caSRafal Jaworowski 	if (error)
162702b553caSRafal Jaworowski 		return (error);
162802b553caSRafal Jaworowski 
162902b553caSRafal Jaworowski 	/* Pointer 2: HMAC Key (or NULL, depending on digest type) */
163002b553caSRafal Jaworowski 	if (hd->shd_mode0 & SEC_MDEU_MODE_HMAC)
163102b553caSRafal Jaworowski 		error = sec_make_pointer_direct(sc, desc, 2,
163202b553caSRafal Jaworowski 		    desc->sd_desc_paddr + offsetof(struct sec_hw_desc,
1633c0341432SJohn Baldwin 		    shd_mkey), csp->csp_auth_klen);
163402b553caSRafal Jaworowski 	else
163502b553caSRafal Jaworowski 		error = sec_make_pointer_direct(sc, desc, 2, 0, 0);
163602b553caSRafal Jaworowski 
163702b553caSRafal Jaworowski 	if (error)
163802b553caSRafal Jaworowski 		return (error);
163902b553caSRafal Jaworowski 
164002b553caSRafal Jaworowski 	/* Pointer 3: Input Data */
1641c0341432SJohn Baldwin 	error = sec_make_pointer(sc, desc, 3, crp, crp->crp_payload_start,
1642c0341432SJohn Baldwin 	    crp->crp_payload_length);
164302b553caSRafal Jaworowski 	if (error)
164402b553caSRafal Jaworowski 		return (error);
164502b553caSRafal Jaworowski 
164602b553caSRafal Jaworowski 	/* Pointer 4: NULL */
164702b553caSRafal Jaworowski 	error = sec_make_pointer_direct(sc, desc, 4, 0, 0);
164802b553caSRafal Jaworowski 	if (error)
164902b553caSRafal Jaworowski 		return (error);
165002b553caSRafal Jaworowski 
165102b553caSRafal Jaworowski 	/* Pointer 5: Hash out */
1652c0341432SJohn Baldwin 	error = sec_make_pointer_direct(sc, desc, 5, desc->sd_desc_paddr +
1653c0341432SJohn Baldwin 	    offsetof(struct sec_hw_desc, shd_digest), hashlen);
165402b553caSRafal Jaworowski 	if (error)
165502b553caSRafal Jaworowski 		return (error);
165602b553caSRafal Jaworowski 
165702b553caSRafal Jaworowski 	/* Pointer 6: NULL */
165802b553caSRafal Jaworowski 	error = sec_make_pointer_direct(sc, desc, 6, 0, 0);
165902b553caSRafal Jaworowski 
166002b553caSRafal Jaworowski 	return (0);
166102b553caSRafal Jaworowski }
1662