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