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