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