hifn7751.c revision 104477
1104477Ssam/* $FreeBSD: head/sys/dev/hifn/hifn7751.c 104477 2002-10-04 20:32:37Z sam $ */ 2104477Ssam/* $OpenBSD: hifn7751.c,v 1.120 2002/05/17 00:33:34 deraadt Exp $ */ 3104477Ssam 4104477Ssam/* 5104477Ssam * Invertex AEON / Hifn 7751 driver 6104477Ssam * Copyright (c) 1999 Invertex Inc. All rights reserved. 7104477Ssam * Copyright (c) 1999 Theo de Raadt 8104477Ssam * Copyright (c) 2000-2001 Network Security Technologies, Inc. 9104477Ssam * http://www.netsec.net 10104477Ssam * 11104477Ssam * This driver is based on a previous driver by Invertex, for which they 12104477Ssam * requested: Please send any comments, feedback, bug-fixes, or feature 13104477Ssam * requests to software@invertex.com. 14104477Ssam * 15104477Ssam * Redistribution and use in source and binary forms, with or without 16104477Ssam * modification, are permitted provided that the following conditions 17104477Ssam * are met: 18104477Ssam * 19104477Ssam * 1. Redistributions of source code must retain the above copyright 20104477Ssam * notice, this list of conditions and the following disclaimer. 21104477Ssam * 2. Redistributions in binary form must reproduce the above copyright 22104477Ssam * notice, this list of conditions and the following disclaimer in the 23104477Ssam * documentation and/or other materials provided with the distribution. 24104477Ssam * 3. The name of the author may not be used to endorse or promote products 25104477Ssam * derived from this software without specific prior written permission. 26104477Ssam * 27104477Ssam * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 28104477Ssam * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 29104477Ssam * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 30104477Ssam * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 31104477Ssam * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 32104477Ssam * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 33104477Ssam * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 34104477Ssam * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 35104477Ssam * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 36104477Ssam * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 37104477Ssam * 38104477Ssam * Effort sponsored in part by the Defense Advanced Research Projects 39104477Ssam * Agency (DARPA) and Air Force Research Laboratory, Air Force 40104477Ssam * Materiel Command, USAF, under agreement number F30602-01-2-0537. 41104477Ssam * 42104477Ssam */ 43104477Ssam 44104477Ssam#define HIFN_DEBUG 45104477Ssam 46104477Ssam/* 47104477Ssam * Driver for the Hifn 7751 encryption processor. 48104477Ssam */ 49104477Ssam 50104477Ssam#include <sys/param.h> 51104477Ssam#include <sys/systm.h> 52104477Ssam#include <sys/proc.h> 53104477Ssam#include <sys/errno.h> 54104477Ssam#include <sys/malloc.h> 55104477Ssam#include <sys/kernel.h> 56104477Ssam#include <sys/mbuf.h> 57104477Ssam#include <sys/lock.h> 58104477Ssam#include <sys/mutex.h> 59104477Ssam#include <sys/sysctl.h> 60104477Ssam 61104477Ssam#include <vm/vm.h> 62104477Ssam#include <vm/pmap.h> 63104477Ssam 64104477Ssam#include <machine/clock.h> 65104477Ssam#include <machine/bus.h> 66104477Ssam#include <machine/resource.h> 67104477Ssam#include <sys/bus.h> 68104477Ssam#include <sys/rman.h> 69104477Ssam 70104477Ssam#include <opencrypto/cryptodev.h> 71104477Ssam#include <sys/random.h> 72104477Ssam 73104477Ssam#include <pci/pcivar.h> 74104477Ssam#include <pci/pcireg.h> 75104477Ssam#include <dev/hifn/hifn7751reg.h> 76104477Ssam#include <dev/hifn/hifn7751var.h> 77104477Ssam 78104477Ssam/* 79104477Ssam * Prototypes and count for the pci_device structure 80104477Ssam */ 81104477Ssamstatic int hifn_probe(device_t); 82104477Ssamstatic int hifn_attach(device_t); 83104477Ssamstatic int hifn_detach(device_t); 84104477Ssamstatic int hifn_suspend(device_t); 85104477Ssamstatic int hifn_resume(device_t); 86104477Ssamstatic void hifn_shutdown(device_t); 87104477Ssam 88104477Ssamstatic device_method_t hifn_methods[] = { 89104477Ssam /* Device interface */ 90104477Ssam DEVMETHOD(device_probe, hifn_probe), 91104477Ssam DEVMETHOD(device_attach, hifn_attach), 92104477Ssam DEVMETHOD(device_detach, hifn_detach), 93104477Ssam DEVMETHOD(device_suspend, hifn_suspend), 94104477Ssam DEVMETHOD(device_resume, hifn_resume), 95104477Ssam DEVMETHOD(device_shutdown, hifn_shutdown), 96104477Ssam 97104477Ssam /* bus interface */ 98104477Ssam DEVMETHOD(bus_print_child, bus_generic_print_child), 99104477Ssam DEVMETHOD(bus_driver_added, bus_generic_driver_added), 100104477Ssam 101104477Ssam { 0, 0 } 102104477Ssam}; 103104477Ssamstatic driver_t hifn_driver = { 104104477Ssam "hifn", 105104477Ssam hifn_methods, 106104477Ssam sizeof (struct hifn_softc) 107104477Ssam}; 108104477Ssamstatic devclass_t hifn_devclass; 109104477Ssam 110104477SsamDRIVER_MODULE(hifn, pci, hifn_driver, hifn_devclass, 0, 0); 111104477Ssam 112104477Ssamstatic void hifn_reset_board(struct hifn_softc *, int); 113104477Ssamstatic void hifn_reset_puc(struct hifn_softc *); 114104477Ssamstatic void hifn_puc_wait(struct hifn_softc *); 115104477Ssamstatic int hifn_enable_crypto(struct hifn_softc *); 116104477Ssamstatic void hifn_set_retry(struct hifn_softc *sc); 117104477Ssamstatic void hifn_init_dma(struct hifn_softc *); 118104477Ssamstatic void hifn_init_pci_registers(struct hifn_softc *); 119104477Ssamstatic int hifn_sramsize(struct hifn_softc *); 120104477Ssamstatic int hifn_dramsize(struct hifn_softc *); 121104477Ssamstatic int hifn_ramtype(struct hifn_softc *); 122104477Ssamstatic void hifn_sessions(struct hifn_softc *); 123104477Ssamstatic void hifn_intr(void *); 124104477Ssamstatic u_int hifn_write_command(struct hifn_command *, u_int8_t *); 125104477Ssamstatic u_int32_t hifn_next_signature(u_int32_t a, u_int cnt); 126104477Ssamstatic int hifn_newsession(void *, u_int32_t *, struct cryptoini *); 127104477Ssamstatic int hifn_freesession(void *, u_int64_t); 128104477Ssamstatic int hifn_process(void *, struct cryptop *, int); 129104477Ssamstatic void hifn_callback(struct hifn_softc *, struct hifn_command *, u_int8_t *); 130104477Ssamstatic int hifn_crypto(struct hifn_softc *, struct hifn_command *, struct cryptop *, int); 131104477Ssamstatic int hifn_readramaddr(struct hifn_softc *, int, u_int8_t *); 132104477Ssamstatic int hifn_writeramaddr(struct hifn_softc *, int, u_int8_t *); 133104477Ssamstatic int hifn_dmamap_load_src(struct hifn_softc *, struct hifn_command *); 134104477Ssamstatic int hifn_dmamap_load_dst(struct hifn_softc *, struct hifn_command *); 135104477Ssamstatic int hifn_init_pubrng(struct hifn_softc *); 136104477Ssamstatic void hifn_rng(void *); 137104477Ssamstatic void hifn_tick(void *); 138104477Ssamstatic void hifn_abort(struct hifn_softc *); 139104477Ssamstatic void hifn_alloc_slot(struct hifn_softc *, int *, int *, int *, int *); 140104477Ssam 141104477Ssamstatic void hifn_write_reg_0(struct hifn_softc *, bus_size_t, u_int32_t); 142104477Ssamstatic void hifn_write_reg_1(struct hifn_softc *, bus_size_t, u_int32_t); 143104477Ssam 144104477Ssamstatic __inline__ u_int32_t 145104477SsamREAD_REG_0(struct hifn_softc *sc, bus_size_t reg) 146104477Ssam{ 147104477Ssam u_int32_t v = bus_space_read_4(sc->sc_st0, sc->sc_sh0, reg); 148104477Ssam sc->sc_bar0_lastreg = (bus_size_t) -1; 149104477Ssam return (v); 150104477Ssam} 151104477Ssam#define WRITE_REG_0(sc, reg, val) hifn_write_reg_0(sc, reg, val) 152104477Ssam 153104477Ssamstatic __inline__ u_int32_t 154104477SsamREAD_REG_1(struct hifn_softc *sc, bus_size_t reg) 155104477Ssam{ 156104477Ssam u_int32_t v = bus_space_read_4(sc->sc_st1, sc->sc_sh1, reg); 157104477Ssam sc->sc_bar1_lastreg = (bus_size_t) -1; 158104477Ssam return (v); 159104477Ssam} 160104477Ssam#define WRITE_REG_1(sc, reg, val) hifn_write_reg_1(sc, reg, val) 161104477Ssam 162104477Ssam#ifdef HIFN_DEBUG 163104477Ssamstatic int hifn_debug = 0; 164104477SsamSYSCTL_INT(_debug, OID_AUTO, hifn, CTLFLAG_RW, &hifn_debug, 165104477Ssam 0, "Hifn driver debugging printfs"); 166104477Ssam#endif 167104477Ssam 168104477Ssamstatic struct hifn_stats hifnstats; 169104477SsamSYSCTL_STRUCT(_kern, OID_AUTO, hifn_stats, CTLFLAG_RD, &hifnstats, 170104477Ssam hifn_stats, "Hifn driver statistics"); 171104477Ssamstatic int hifn_maxbatch = 2; /* XXX tune based on part+sys speed */ 172104477SsamSYSCTL_INT(_kern, OID_AUTO, hifn_maxbatch, CTLFLAG_RW, &hifn_maxbatch, 173104477Ssam 0, "Hifn driver: max ops to batch w/o interrupt"); 174104477Ssam 175104477Ssam/* 176104477Ssam * Probe for a supported device. The PCI vendor and device 177104477Ssam * IDs are used to detect devices we know how to handle. 178104477Ssam */ 179104477Ssamstatic int 180104477Ssamhifn_probe(device_t dev) 181104477Ssam{ 182104477Ssam if (pci_get_vendor(dev) == PCI_VENDOR_INVERTEX && 183104477Ssam pci_get_device(dev) == PCI_PRODUCT_INVERTEX_AEON) 184104477Ssam return (0); 185104477Ssam if (pci_get_vendor(dev) == PCI_VENDOR_HIFN && 186104477Ssam (pci_get_device(dev) == PCI_PRODUCT_HIFN_7751 || 187104477Ssam pci_get_device(dev) == PCI_PRODUCT_HIFN_7951 || 188104477Ssam pci_get_device(dev) == PCI_PRODUCT_HIFN_7811)) 189104477Ssam return (0); 190104477Ssam if (pci_get_vendor(dev) == PCI_VENDOR_NETSEC && 191104477Ssam pci_get_device(dev) == PCI_PRODUCT_NETSEC_7751) 192104477Ssam return (0); 193104477Ssam return (ENXIO); 194104477Ssam} 195104477Ssam 196104477Ssamstatic void 197104477Ssamhifn_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error) 198104477Ssam{ 199104477Ssam bus_addr_t *paddr = (bus_addr_t*) arg; 200104477Ssam *paddr = segs->ds_addr; 201104477Ssam} 202104477Ssam 203104477Ssamstatic const char* 204104477Ssamhifn_partname(struct hifn_softc *sc) 205104477Ssam{ 206104477Ssam /* XXX sprintf numbers when not decoded */ 207104477Ssam switch (pci_get_vendor(sc->sc_dev)) { 208104477Ssam case PCI_VENDOR_HIFN: 209104477Ssam switch (pci_get_device(sc->sc_dev)) { 210104477Ssam case PCI_PRODUCT_HIFN_6500: return "Hifn 6500"; 211104477Ssam case PCI_PRODUCT_HIFN_7751: return "Hifn 7751"; 212104477Ssam case PCI_PRODUCT_HIFN_7811: return "Hifn 7811"; 213104477Ssam case PCI_PRODUCT_HIFN_7951: return "Hifn 7951"; 214104477Ssam } 215104477Ssam return "Hifn unknown-part"; 216104477Ssam case PCI_VENDOR_INVERTEX: 217104477Ssam switch (pci_get_device(sc->sc_dev)) { 218104477Ssam case PCI_PRODUCT_INVERTEX_AEON: return "Invertex AEON"; 219104477Ssam } 220104477Ssam return "Invertex unknown-part"; 221104477Ssam case PCI_VENDOR_NETSEC: 222104477Ssam switch (pci_get_device(sc->sc_dev)) { 223104477Ssam case PCI_PRODUCT_NETSEC_7751: return "NetSec 7751"; 224104477Ssam } 225104477Ssam return "NetSec unknown-part"; 226104477Ssam } 227104477Ssam return "Unknown-vendor unknown-part"; 228104477Ssam} 229104477Ssam 230104477Ssam/* 231104477Ssam * Attach an interface that successfully probed. 232104477Ssam */ 233104477Ssamstatic int 234104477Ssamhifn_attach(device_t dev) 235104477Ssam{ 236104477Ssam struct hifn_softc *sc = device_get_softc(dev); 237104477Ssam u_int32_t cmd; 238104477Ssam caddr_t kva; 239104477Ssam int rseg, rid; 240104477Ssam char rbase; 241104477Ssam u_int16_t ena, rev; 242104477Ssam 243104477Ssam KASSERT(sc != NULL, ("hifn_attach: null software carrier!")); 244104477Ssam bzero(sc, sizeof (*sc)); 245104477Ssam sc->sc_dev = dev; 246104477Ssam 247104477Ssam mtx_init(&sc->sc_mtx, device_get_nameunit(dev), "crypto driver", MTX_DEF); 248104477Ssam 249104477Ssam /* XXX handle power management */ 250104477Ssam 251104477Ssam /* 252104477Ssam * The 7951 has a random number generator and 253104477Ssam * public key support; note this. 254104477Ssam */ 255104477Ssam if (pci_get_vendor(dev) == PCI_VENDOR_HIFN && 256104477Ssam pci_get_device(dev) == PCI_PRODUCT_HIFN_7951) 257104477Ssam sc->sc_flags = HIFN_HAS_RNG | HIFN_HAS_PUBLIC; 258104477Ssam /* 259104477Ssam * The 7811 has a random number generator and 260104477Ssam * we also note it's identity 'cuz of some quirks. 261104477Ssam */ 262104477Ssam if (pci_get_vendor(dev) == PCI_VENDOR_HIFN && 263104477Ssam pci_get_device(dev) == PCI_PRODUCT_HIFN_7811) 264104477Ssam sc->sc_flags |= HIFN_IS_7811 | HIFN_HAS_RNG; 265104477Ssam 266104477Ssam /* 267104477Ssam * Configure support for memory-mapped access to 268104477Ssam * registers and for DMA operations. 269104477Ssam */ 270104477Ssam#define PCIM_ENA (PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN) 271104477Ssam cmd = pci_read_config(dev, PCIR_COMMAND, 4); 272104477Ssam cmd |= PCIM_ENA; 273104477Ssam pci_write_config(dev, PCIR_COMMAND, cmd, 4); 274104477Ssam cmd = pci_read_config(dev, PCIR_COMMAND, 4); 275104477Ssam if ((cmd & PCIM_ENA) != PCIM_ENA) { 276104477Ssam device_printf(dev, "failed to enable %s\n", 277104477Ssam (cmd & PCIM_ENA) == 0 ? 278104477Ssam "memory mapping & bus mastering" : 279104477Ssam (cmd & PCIM_CMD_MEMEN) == 0 ? 280104477Ssam "memory mapping" : "bus mastering"); 281104477Ssam goto fail_pci; 282104477Ssam } 283104477Ssam#undef PCIM_ENA 284104477Ssam 285104477Ssam /* 286104477Ssam * Setup PCI resources. Note that we record the bus 287104477Ssam * tag and handle for each register mapping, this is 288104477Ssam * used by the READ_REG_0, WRITE_REG_0, READ_REG_1, 289104477Ssam * and WRITE_REG_1 macros throughout the driver. 290104477Ssam */ 291104477Ssam rid = HIFN_BAR0; 292104477Ssam sc->sc_bar0res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 293104477Ssam 0, ~0, 1, RF_ACTIVE); 294104477Ssam if (sc->sc_bar0res == NULL) { 295104477Ssam device_printf(dev, "cannot map bar%d register space\n", 0); 296104477Ssam goto fail_pci; 297104477Ssam } 298104477Ssam sc->sc_st0 = rman_get_bustag(sc->sc_bar0res); 299104477Ssam sc->sc_sh0 = rman_get_bushandle(sc->sc_bar0res); 300104477Ssam sc->sc_bar0_lastreg = (bus_size_t) -1; 301104477Ssam 302104477Ssam rid = HIFN_BAR1; 303104477Ssam sc->sc_bar1res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 304104477Ssam 0, ~0, 1, RF_ACTIVE); 305104477Ssam if (sc->sc_bar1res == NULL) { 306104477Ssam device_printf(dev, "cannot map bar%d register space\n", 1); 307104477Ssam goto fail_io0; 308104477Ssam } 309104477Ssam sc->sc_st1 = rman_get_bustag(sc->sc_bar1res); 310104477Ssam sc->sc_sh1 = rman_get_bushandle(sc->sc_bar1res); 311104477Ssam sc->sc_bar1_lastreg = (bus_size_t) -1; 312104477Ssam 313104477Ssam hifn_set_retry(sc); 314104477Ssam 315104477Ssam /* 316104477Ssam * Setup the area where the Hifn DMA's descriptors 317104477Ssam * and associated data structures. 318104477Ssam */ 319104477Ssam if (bus_dma_tag_create(NULL, /* parent */ 320104477Ssam 1, 0, /* alignment,boundary */ 321104477Ssam BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 322104477Ssam BUS_SPACE_MAXADDR, /* highaddr */ 323104477Ssam NULL, NULL, /* filter, filterarg */ 324104477Ssam HIFN_MAX_DMALEN, /* maxsize */ 325104477Ssam MAX_SCATTER, /* nsegments */ 326104477Ssam HIFN_MAX_SEGLEN, /* maxsegsize */ 327104477Ssam BUS_DMA_ALLOCNOW, /* flags */ 328104477Ssam &sc->sc_dmat)) { 329104477Ssam device_printf(dev, "cannot allocate DMA tag\n"); 330104477Ssam goto fail_io1; 331104477Ssam } 332104477Ssam if (bus_dmamap_create(sc->sc_dmat, BUS_DMA_NOWAIT, &sc->sc_dmamap)) { 333104477Ssam device_printf(dev, "cannot create dma map\n"); 334104477Ssam bus_dma_tag_destroy(sc->sc_dmat); 335104477Ssam goto fail_io1; 336104477Ssam } 337104477Ssam if (bus_dmamem_alloc(sc->sc_dmat, (void**) &kva, BUS_DMA_NOWAIT, &sc->sc_dmamap)) { 338104477Ssam device_printf(dev, "cannot alloc dma buffer\n"); 339104477Ssam bus_dmamap_destroy(sc->sc_dmat, sc->sc_dmamap); 340104477Ssam bus_dma_tag_destroy(sc->sc_dmat); 341104477Ssam goto fail_io1; 342104477Ssam } 343104477Ssam if (bus_dmamap_load(sc->sc_dmat, sc->sc_dmamap, kva, 344104477Ssam sizeof (*sc->sc_dma), 345104477Ssam hifn_dmamap_cb, &sc->sc_dma_physaddr, 346104477Ssam BUS_DMA_NOWAIT)) { 347104477Ssam device_printf(dev, "cannot load dma map\n"); 348104477Ssam bus_dmamem_free(sc->sc_dmat, kva, sc->sc_dmamap); 349104477Ssam bus_dmamap_destroy(sc->sc_dmat, sc->sc_dmamap); 350104477Ssam bus_dma_tag_destroy(sc->sc_dmat); 351104477Ssam goto fail_io1; 352104477Ssam } 353104477Ssam sc->sc_dma = (struct hifn_dma *)kva; 354104477Ssam bzero(sc->sc_dma, sizeof(*sc->sc_dma)); 355104477Ssam 356104477Ssam KASSERT(sc->sc_st0 != NULL, ("hifn_attach: null bar0 tag!")); 357104477Ssam KASSERT(sc->sc_sh0 != NULL, ("hifn_attach: null bar0 handle!")); 358104477Ssam KASSERT(sc->sc_st1 != NULL, ("hifn_attach: null bar1 tag!")); 359104477Ssam KASSERT(sc->sc_sh1 != NULL, ("hifn_attach: null bar1 handle!")); 360104477Ssam 361104477Ssam /* 362104477Ssam * Reset the board and do the ``secret handshake'' 363104477Ssam * to enable the crypto support. Then complete the 364104477Ssam * initialization procedure by setting up the interrupt 365104477Ssam * and hooking in to the system crypto support so we'll 366104477Ssam * get used for system services like the crypto device, 367104477Ssam * IPsec, RNG device, etc. 368104477Ssam */ 369104477Ssam hifn_reset_board(sc, 0); 370104477Ssam 371104477Ssam if (hifn_enable_crypto(sc) != 0) { 372104477Ssam device_printf(dev, "crypto enabling failed\n"); 373104477Ssam goto fail_mem; 374104477Ssam } 375104477Ssam hifn_reset_puc(sc); 376104477Ssam 377104477Ssam hifn_init_dma(sc); 378104477Ssam hifn_init_pci_registers(sc); 379104477Ssam 380104477Ssam if (hifn_ramtype(sc)) 381104477Ssam goto fail_mem; 382104477Ssam 383104477Ssam if (sc->sc_drammodel == 0) 384104477Ssam hifn_sramsize(sc); 385104477Ssam else 386104477Ssam hifn_dramsize(sc); 387104477Ssam 388104477Ssam /* 389104477Ssam * Workaround for NetSec 7751 rev A: half ram size because two 390104477Ssam * of the address lines were left floating 391104477Ssam */ 392104477Ssam if (pci_get_vendor(dev) == PCI_VENDOR_NETSEC && 393104477Ssam pci_get_device(dev) == PCI_PRODUCT_NETSEC_7751 && 394104477Ssam pci_get_revid(dev) == 0x61) /*XXX???*/ 395104477Ssam sc->sc_ramsize >>= 1; 396104477Ssam 397104477Ssam /* 398104477Ssam * Arrange the interrupt line. 399104477Ssam */ 400104477Ssam rid = 0; 401104477Ssam sc->sc_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 402104477Ssam 0, ~0, 1, RF_SHAREABLE|RF_ACTIVE); 403104477Ssam if (sc->sc_irq == NULL) { 404104477Ssam device_printf(dev, "could not map interrupt\n"); 405104477Ssam goto fail_mem; 406104477Ssam } 407104477Ssam /* 408104477Ssam * NB: Network code assumes we are blocked with splimp() 409104477Ssam * so make sure the IRQ is marked appropriately. 410104477Ssam */ 411104477Ssam if (bus_setup_intr(dev, sc->sc_irq, INTR_TYPE_NET, 412104477Ssam hifn_intr, sc, &sc->sc_intrhand)) { 413104477Ssam device_printf(dev, "could not setup interrupt\n"); 414104477Ssam goto fail_intr2; 415104477Ssam } 416104477Ssam 417104477Ssam hifn_sessions(sc); 418104477Ssam 419104477Ssam /* 420104477Ssam * NB: Keep only the low 16 bits; this masks the chip id 421104477Ssam * from the 7951. 422104477Ssam */ 423104477Ssam rev = READ_REG_1(sc, HIFN_1_REVID) & 0xffff; 424104477Ssam 425104477Ssam rseg = sc->sc_ramsize / 1024; 426104477Ssam rbase = 'K'; 427104477Ssam if (sc->sc_ramsize >= (1024 * 1024)) { 428104477Ssam rbase = 'M'; 429104477Ssam rseg /= 1024; 430104477Ssam } 431104477Ssam device_printf(sc->sc_dev, "%s, rev %u, %d%cB %cram, %u sessions\n", 432104477Ssam hifn_partname(sc), rev, 433104477Ssam rseg, rbase, sc->sc_drammodel ? 'd' : 's', 434104477Ssam sc->sc_maxses); 435104477Ssam 436104477Ssam sc->sc_cid = crypto_get_driverid(0); 437104477Ssam if (sc->sc_cid < 0) { 438104477Ssam device_printf(dev, "could not get crypto driver id\n"); 439104477Ssam goto fail_intr; 440104477Ssam } 441104477Ssam 442104477Ssam WRITE_REG_0(sc, HIFN_0_PUCNFG, 443104477Ssam READ_REG_0(sc, HIFN_0_PUCNFG) | HIFN_PUCNFG_CHIPID); 444104477Ssam ena = READ_REG_0(sc, HIFN_0_PUSTAT) & HIFN_PUSTAT_CHIPENA; 445104477Ssam 446104477Ssam switch (ena) { 447104477Ssam case HIFN_PUSTAT_ENA_2: 448104477Ssam crypto_register(sc->sc_cid, CRYPTO_3DES_CBC, 0, 0, 449104477Ssam hifn_newsession, hifn_freesession, hifn_process, sc); 450104477Ssam crypto_register(sc->sc_cid, CRYPTO_ARC4, 0, 0, 451104477Ssam hifn_newsession, hifn_freesession, hifn_process, sc); 452104477Ssam /*FALLTHROUGH*/ 453104477Ssam case HIFN_PUSTAT_ENA_1: 454104477Ssam crypto_register(sc->sc_cid, CRYPTO_MD5, 0, 0, 455104477Ssam hifn_newsession, hifn_freesession, hifn_process, sc); 456104477Ssam crypto_register(sc->sc_cid, CRYPTO_SHA1, 0, 0, 457104477Ssam hifn_newsession, hifn_freesession, hifn_process, sc); 458104477Ssam crypto_register(sc->sc_cid, CRYPTO_MD5_HMAC, 0, 0, 459104477Ssam hifn_newsession, hifn_freesession, hifn_process, sc); 460104477Ssam crypto_register(sc->sc_cid, CRYPTO_SHA1_HMAC, 0, 0, 461104477Ssam hifn_newsession, hifn_freesession, hifn_process, sc); 462104477Ssam crypto_register(sc->sc_cid, CRYPTO_DES_CBC, 0, 0, 463104477Ssam hifn_newsession, hifn_freesession, hifn_process, sc); 464104477Ssam break; 465104477Ssam } 466104477Ssam 467104477Ssam bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, 468104477Ssam BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 469104477Ssam 470104477Ssam if (sc->sc_flags & (HIFN_HAS_PUBLIC | HIFN_HAS_RNG)) 471104477Ssam hifn_init_pubrng(sc); 472104477Ssam 473104477Ssam callout_init(&sc->sc_tickto, 0); 474104477Ssam callout_reset(&sc->sc_tickto, hz, hifn_tick, sc); 475104477Ssam 476104477Ssam return (0); 477104477Ssam 478104477Ssamfail_intr: 479104477Ssam bus_teardown_intr(dev, sc->sc_irq, sc->sc_intrhand); 480104477Ssamfail_intr2: 481104477Ssam /* XXX don't store rid */ 482104477Ssam bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq); 483104477Ssamfail_mem: 484104477Ssam bus_dmamap_unload(sc->sc_dmat, sc->sc_dmamap); 485104477Ssam bus_dmamem_free(sc->sc_dmat, sc->sc_dma, sc->sc_dmamap); 486104477Ssam bus_dmamap_destroy(sc->sc_dmat, sc->sc_dmamap); 487104477Ssam bus_dma_tag_destroy(sc->sc_dmat); 488104477Ssam 489104477Ssam /* Turn off DMA polling */ 490104477Ssam WRITE_REG_1(sc, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MSTRESET | 491104477Ssam HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE); 492104477Ssamfail_io1: 493104477Ssam bus_release_resource(dev, SYS_RES_MEMORY, HIFN_BAR1, sc->sc_bar1res); 494104477Ssamfail_io0: 495104477Ssam bus_release_resource(dev, SYS_RES_MEMORY, HIFN_BAR0, sc->sc_bar0res); 496104477Ssamfail_pci: 497104477Ssam mtx_destroy(&sc->sc_mtx); 498104477Ssam return (ENXIO); 499104477Ssam} 500104477Ssam 501104477Ssam/* 502104477Ssam * Detach an interface that successfully probed. 503104477Ssam */ 504104477Ssamstatic int 505104477Ssamhifn_detach(device_t dev) 506104477Ssam{ 507104477Ssam struct hifn_softc *sc = device_get_softc(dev); 508104477Ssam 509104477Ssam KASSERT(sc != NULL, ("hifn_detach: null software carrier!")); 510104477Ssam 511104477Ssam HIFN_LOCK(sc); 512104477Ssam 513104477Ssam /*XXX other resources */ 514104477Ssam callout_stop(&sc->sc_tickto); 515104477Ssam callout_stop(&sc->sc_rngto); 516104477Ssam 517104477Ssam /* Turn off DMA polling */ 518104477Ssam WRITE_REG_1(sc, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MSTRESET | 519104477Ssam HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE); 520104477Ssam 521104477Ssam crypto_unregister_all(sc->sc_cid); 522104477Ssam 523104477Ssam bus_generic_detach(dev); /*XXX should be no children, right? */ 524104477Ssam 525104477Ssam bus_teardown_intr(dev, sc->sc_irq, sc->sc_intrhand); 526104477Ssam /* XXX don't store rid */ 527104477Ssam bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq); 528104477Ssam 529104477Ssam bus_dmamap_unload(sc->sc_dmat, sc->sc_dmamap); 530104477Ssam bus_dmamem_free(sc->sc_dmat, sc->sc_dma, sc->sc_dmamap); 531104477Ssam bus_dmamap_destroy(sc->sc_dmat, sc->sc_dmamap); 532104477Ssam bus_dma_tag_destroy(sc->sc_dmat); 533104477Ssam 534104477Ssam bus_release_resource(dev, SYS_RES_MEMORY, HIFN_BAR1, sc->sc_bar1res); 535104477Ssam bus_release_resource(dev, SYS_RES_MEMORY, HIFN_BAR0, sc->sc_bar0res); 536104477Ssam 537104477Ssam HIFN_UNLOCK(sc); 538104477Ssam 539104477Ssam mtx_destroy(&sc->sc_mtx); 540104477Ssam 541104477Ssam return (0); 542104477Ssam} 543104477Ssam 544104477Ssam/* 545104477Ssam * Stop all chip I/O so that the kernel's probe routines don't 546104477Ssam * get confused by errant DMAs when rebooting. 547104477Ssam */ 548104477Ssamstatic void 549104477Ssamhifn_shutdown(device_t dev) 550104477Ssam{ 551104477Ssam#ifdef notyet 552104477Ssam hifn_stop(device_get_softc(dev)); 553104477Ssam#endif 554104477Ssam} 555104477Ssam 556104477Ssam/* 557104477Ssam * Device suspend routine. Stop the interface and save some PCI 558104477Ssam * settings in case the BIOS doesn't restore them properly on 559104477Ssam * resume. 560104477Ssam */ 561104477Ssamstatic int 562104477Ssamhifn_suspend(device_t dev) 563104477Ssam{ 564104477Ssam struct hifn_softc *sc = device_get_softc(dev); 565104477Ssam#ifdef notyet 566104477Ssam int i; 567104477Ssam 568104477Ssam hifn_stop(sc); 569104477Ssam for (i = 0; i < 5; i++) 570104477Ssam sc->saved_maps[i] = pci_read_config(dev, PCIR_MAPS + i * 4, 4); 571104477Ssam sc->saved_biosaddr = pci_read_config(dev, PCIR_BIOS, 4); 572104477Ssam sc->saved_intline = pci_read_config(dev, PCIR_INTLINE, 1); 573104477Ssam sc->saved_cachelnsz = pci_read_config(dev, PCIR_CACHELNSZ, 1); 574104477Ssam sc->saved_lattimer = pci_read_config(dev, PCIR_LATTIMER, 1); 575104477Ssam#endif 576104477Ssam sc->sc_suspended = 1; 577104477Ssam 578104477Ssam return (0); 579104477Ssam} 580104477Ssam 581104477Ssam/* 582104477Ssam * Device resume routine. Restore some PCI settings in case the BIOS 583104477Ssam * doesn't, re-enable busmastering, and restart the interface if 584104477Ssam * appropriate. 585104477Ssam */ 586104477Ssamstatic int 587104477Ssamhifn_resume(device_t dev) 588104477Ssam{ 589104477Ssam struct hifn_softc *sc = device_get_softc(dev); 590104477Ssam#ifdef notyet 591104477Ssam int i; 592104477Ssam 593104477Ssam /* better way to do this? */ 594104477Ssam for (i = 0; i < 5; i++) 595104477Ssam pci_write_config(dev, PCIR_MAPS + i * 4, sc->saved_maps[i], 4); 596104477Ssam pci_write_config(dev, PCIR_BIOS, sc->saved_biosaddr, 4); 597104477Ssam pci_write_config(dev, PCIR_INTLINE, sc->saved_intline, 1); 598104477Ssam pci_write_config(dev, PCIR_CACHELNSZ, sc->saved_cachelnsz, 1); 599104477Ssam pci_write_config(dev, PCIR_LATTIMER, sc->saved_lattimer, 1); 600104477Ssam 601104477Ssam /* reenable busmastering */ 602104477Ssam pci_enable_busmaster(dev); 603104477Ssam pci_enable_io(dev, HIFN_RES); 604104477Ssam 605104477Ssam /* reinitialize interface if necessary */ 606104477Ssam if (ifp->if_flags & IFF_UP) 607104477Ssam rl_init(sc); 608104477Ssam#endif 609104477Ssam sc->sc_suspended = 0; 610104477Ssam 611104477Ssam return (0); 612104477Ssam} 613104477Ssam 614104477Ssamstatic int 615104477Ssamhifn_init_pubrng(struct hifn_softc *sc) 616104477Ssam{ 617104477Ssam u_int32_t r; 618104477Ssam int i; 619104477Ssam 620104477Ssam if ((sc->sc_flags & HIFN_IS_7811) == 0) { 621104477Ssam /* Reset 7951 public key/rng engine */ 622104477Ssam WRITE_REG_1(sc, HIFN_1_PUB_RESET, 623104477Ssam READ_REG_1(sc, HIFN_1_PUB_RESET) | HIFN_PUBRST_RESET); 624104477Ssam 625104477Ssam for (i = 0; i < 100; i++) { 626104477Ssam DELAY(1000); 627104477Ssam if ((READ_REG_1(sc, HIFN_1_PUB_RESET) & 628104477Ssam HIFN_PUBRST_RESET) == 0) 629104477Ssam break; 630104477Ssam } 631104477Ssam 632104477Ssam if (i == 100) { 633104477Ssam device_printf(sc->sc_dev, "public key init failed\n"); 634104477Ssam return (1); 635104477Ssam } 636104477Ssam } 637104477Ssam 638104477Ssam /* Enable the rng, if available */ 639104477Ssam if (sc->sc_flags & HIFN_HAS_RNG) { 640104477Ssam if (sc->sc_flags & HIFN_IS_7811) { 641104477Ssam r = READ_REG_1(sc, HIFN_1_7811_RNGENA); 642104477Ssam if (r & HIFN_7811_RNGENA_ENA) { 643104477Ssam r &= ~HIFN_7811_RNGENA_ENA; 644104477Ssam WRITE_REG_1(sc, HIFN_1_7811_RNGENA, r); 645104477Ssam } 646104477Ssam WRITE_REG_1(sc, HIFN_1_7811_RNGCFG, 647104477Ssam HIFN_7811_RNGCFG_DEFL); 648104477Ssam r |= HIFN_7811_RNGENA_ENA; 649104477Ssam WRITE_REG_1(sc, HIFN_1_7811_RNGENA, r); 650104477Ssam } else 651104477Ssam WRITE_REG_1(sc, HIFN_1_RNG_CONFIG, 652104477Ssam READ_REG_1(sc, HIFN_1_RNG_CONFIG) | 653104477Ssam HIFN_RNGCFG_ENA); 654104477Ssam 655104477Ssam sc->sc_rngfirst = 1; 656104477Ssam if (hz >= 100) 657104477Ssam sc->sc_rnghz = hz / 100; 658104477Ssam else 659104477Ssam sc->sc_rnghz = 1; 660104477Ssam callout_init(&sc->sc_rngto, 0); 661104477Ssam callout_reset(&sc->sc_rngto, sc->sc_rnghz, hifn_rng, sc); 662104477Ssam } 663104477Ssam 664104477Ssam /* Enable public key engine, if available */ 665104477Ssam if (sc->sc_flags & HIFN_HAS_PUBLIC) { 666104477Ssam WRITE_REG_1(sc, HIFN_1_PUB_IEN, HIFN_PUBIEN_DONE); 667104477Ssam sc->sc_dmaier |= HIFN_DMAIER_PUBDONE; 668104477Ssam WRITE_REG_1(sc, HIFN_1_DMA_IER, sc->sc_dmaier); 669104477Ssam } 670104477Ssam 671104477Ssam return (0); 672104477Ssam} 673104477Ssam 674104477Ssamstatic void 675104477Ssamhifn_rng(void *vsc) 676104477Ssam{ 677104477Ssam#define RANDOM_BITS(n) (n)*sizeof (u_int32_t), (n)*sizeof (u_int32_t)*NBBY, 0 678104477Ssam struct hifn_softc *sc = vsc; 679104477Ssam u_int32_t sts, num[2]; 680104477Ssam int i; 681104477Ssam 682104477Ssam if (sc->sc_flags & HIFN_IS_7811) { 683104477Ssam for (i = 0; i < 5; i++) { 684104477Ssam sts = READ_REG_1(sc, HIFN_1_7811_RNGSTS); 685104477Ssam if (sts & HIFN_7811_RNGSTS_UFL) { 686104477Ssam device_printf(sc->sc_dev, 687104477Ssam "RNG underflow: disabling\n"); 688104477Ssam return; 689104477Ssam } 690104477Ssam if ((sts & HIFN_7811_RNGSTS_RDY) == 0) 691104477Ssam break; 692104477Ssam 693104477Ssam /* 694104477Ssam * There are at least two words in the RNG FIFO 695104477Ssam * at this point. 696104477Ssam */ 697104477Ssam num[0] = READ_REG_1(sc, HIFN_1_7811_RNGDAT); 698104477Ssam num[1] = READ_REG_1(sc, HIFN_1_7811_RNGDAT); 699104477Ssam /* NB: discard first data read */ 700104477Ssam if (sc->sc_rngfirst) 701104477Ssam sc->sc_rngfirst = 0; 702104477Ssam else 703104477Ssam random_harvest(num, RANDOM_BITS(2), RANDOM_PURE); 704104477Ssam } 705104477Ssam } else { 706104477Ssam num[0] = READ_REG_1(sc, HIFN_1_RNG_DATA); 707104477Ssam 708104477Ssam /* NB: discard first data read */ 709104477Ssam if (sc->sc_rngfirst) 710104477Ssam sc->sc_rngfirst = 0; 711104477Ssam else 712104477Ssam random_harvest(num, RANDOM_BITS(1), RANDOM_PURE); 713104477Ssam } 714104477Ssam 715104477Ssam callout_reset(&sc->sc_rngto, sc->sc_rnghz, hifn_rng, sc); 716104477Ssam#undef RANDOM_BITS 717104477Ssam} 718104477Ssam 719104477Ssamstatic void 720104477Ssamhifn_puc_wait(struct hifn_softc *sc) 721104477Ssam{ 722104477Ssam int i; 723104477Ssam 724104477Ssam for (i = 5000; i > 0; i--) { 725104477Ssam DELAY(1); 726104477Ssam if (!(READ_REG_0(sc, HIFN_0_PUCTRL) & HIFN_PUCTRL_RESET)) 727104477Ssam break; 728104477Ssam } 729104477Ssam if (!i) 730104477Ssam device_printf(sc->sc_dev, "proc unit did not reset\n"); 731104477Ssam} 732104477Ssam 733104477Ssam/* 734104477Ssam * Reset the processing unit. 735104477Ssam */ 736104477Ssamstatic void 737104477Ssamhifn_reset_puc(struct hifn_softc *sc) 738104477Ssam{ 739104477Ssam /* Reset processing unit */ 740104477Ssam WRITE_REG_0(sc, HIFN_0_PUCTRL, HIFN_PUCTRL_DMAENA); 741104477Ssam hifn_puc_wait(sc); 742104477Ssam} 743104477Ssam 744104477Ssam/* 745104477Ssam * Set the Retry and TRDY registers; note that we set them to 746104477Ssam * zero because the 7811 locks up when forced to retry (section 747104477Ssam * 3.6 of "Specification Update SU-0014-04". Not clear if we 748104477Ssam * should do this for all Hifn parts, but it doesn't seem to hurt. 749104477Ssam */ 750104477Ssamstatic void 751104477Ssamhifn_set_retry(struct hifn_softc *sc) 752104477Ssam{ 753104477Ssam /* NB: RETRY only responds to 8-bit reads/writes */ 754104477Ssam pci_write_config(sc->sc_dev, HIFN_RETRY_TIMEOUT, 0, 1); 755104477Ssam pci_write_config(sc->sc_dev, HIFN_TRDY_TIMEOUT, 0, 4); 756104477Ssam} 757104477Ssam 758104477Ssam/* 759104477Ssam * Resets the board. Values in the regesters are left as is 760104477Ssam * from the reset (i.e. initial values are assigned elsewhere). 761104477Ssam */ 762104477Ssamstatic void 763104477Ssamhifn_reset_board(struct hifn_softc *sc, int full) 764104477Ssam{ 765104477Ssam u_int32_t reg; 766104477Ssam 767104477Ssam /* 768104477Ssam * Set polling in the DMA configuration register to zero. 0x7 avoids 769104477Ssam * resetting the board and zeros out the other fields. 770104477Ssam */ 771104477Ssam WRITE_REG_1(sc, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MSTRESET | 772104477Ssam HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE); 773104477Ssam 774104477Ssam /* 775104477Ssam * Now that polling has been disabled, we have to wait 1 ms 776104477Ssam * before resetting the board. 777104477Ssam */ 778104477Ssam DELAY(1000); 779104477Ssam 780104477Ssam /* Reset the DMA unit */ 781104477Ssam if (full) { 782104477Ssam WRITE_REG_1(sc, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MODE); 783104477Ssam DELAY(1000); 784104477Ssam } else { 785104477Ssam WRITE_REG_1(sc, HIFN_1_DMA_CNFG, 786104477Ssam HIFN_DMACNFG_MODE | HIFN_DMACNFG_MSTRESET); 787104477Ssam hifn_reset_puc(sc); 788104477Ssam } 789104477Ssam 790104477Ssam KASSERT(sc->sc_dma != NULL, ("hifn_reset_board: null DMA tag!")); 791104477Ssam bzero(sc->sc_dma, sizeof(*sc->sc_dma)); 792104477Ssam 793104477Ssam /* Bring dma unit out of reset */ 794104477Ssam WRITE_REG_1(sc, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MSTRESET | 795104477Ssam HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE); 796104477Ssam 797104477Ssam hifn_puc_wait(sc); 798104477Ssam hifn_set_retry(sc); 799104477Ssam 800104477Ssam if (sc->sc_flags & HIFN_IS_7811) { 801104477Ssam for (reg = 0; reg < 1000; reg++) { 802104477Ssam if (READ_REG_1(sc, HIFN_1_7811_MIPSRST) & 803104477Ssam HIFN_MIPSRST_CRAMINIT) 804104477Ssam break; 805104477Ssam DELAY(1000); 806104477Ssam } 807104477Ssam if (reg == 1000) 808104477Ssam printf(": cram init timeout\n"); 809104477Ssam } 810104477Ssam} 811104477Ssam 812104477Ssamstatic u_int32_t 813104477Ssamhifn_next_signature(u_int32_t a, u_int cnt) 814104477Ssam{ 815104477Ssam int i; 816104477Ssam u_int32_t v; 817104477Ssam 818104477Ssam for (i = 0; i < cnt; i++) { 819104477Ssam 820104477Ssam /* get the parity */ 821104477Ssam v = a & 0x80080125; 822104477Ssam v ^= v >> 16; 823104477Ssam v ^= v >> 8; 824104477Ssam v ^= v >> 4; 825104477Ssam v ^= v >> 2; 826104477Ssam v ^= v >> 1; 827104477Ssam 828104477Ssam a = (v & 1) ^ (a << 1); 829104477Ssam } 830104477Ssam 831104477Ssam return a; 832104477Ssam} 833104477Ssam 834104477Ssamstruct pci2id { 835104477Ssam u_short pci_vendor; 836104477Ssam u_short pci_prod; 837104477Ssam char card_id[13]; 838104477Ssam}; 839104477Ssamstatic struct pci2id pci2id[] = { 840104477Ssam { 841104477Ssam PCI_VENDOR_HIFN, 842104477Ssam PCI_PRODUCT_HIFN_7951, 843104477Ssam { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 844104477Ssam 0x00, 0x00, 0x00, 0x00, 0x00 } 845104477Ssam }, { 846104477Ssam PCI_VENDOR_NETSEC, 847104477Ssam PCI_PRODUCT_NETSEC_7751, 848104477Ssam { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 849104477Ssam 0x00, 0x00, 0x00, 0x00, 0x00 } 850104477Ssam }, { 851104477Ssam PCI_VENDOR_INVERTEX, 852104477Ssam PCI_PRODUCT_INVERTEX_AEON, 853104477Ssam { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 854104477Ssam 0x00, 0x00, 0x00, 0x00, 0x00 } 855104477Ssam }, { 856104477Ssam PCI_VENDOR_HIFN, 857104477Ssam PCI_PRODUCT_HIFN_7811, 858104477Ssam { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 859104477Ssam 0x00, 0x00, 0x00, 0x00, 0x00 } 860104477Ssam }, { 861104477Ssam /* 862104477Ssam * Other vendors share this PCI ID as well, such as 863104477Ssam * http://www.powercrypt.com, and obviously they also 864104477Ssam * use the same key. 865104477Ssam */ 866104477Ssam PCI_VENDOR_HIFN, 867104477Ssam PCI_PRODUCT_HIFN_7751, 868104477Ssam { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 869104477Ssam 0x00, 0x00, 0x00, 0x00, 0x00 } 870104477Ssam }, 871104477Ssam}; 872104477Ssam 873104477Ssam/* 874104477Ssam * Checks to see if crypto is already enabled. If crypto isn't enable, 875104477Ssam * "hifn_enable_crypto" is called to enable it. The check is important, 876104477Ssam * as enabling crypto twice will lock the board. 877104477Ssam */ 878104477Ssamstatic int 879104477Ssamhifn_enable_crypto(struct hifn_softc *sc) 880104477Ssam{ 881104477Ssam u_int32_t dmacfg, ramcfg, encl, addr, i; 882104477Ssam char *offtbl = NULL; 883104477Ssam 884104477Ssam for (i = 0; i < sizeof(pci2id)/sizeof(pci2id[0]); i++) { 885104477Ssam if (pci2id[i].pci_vendor == pci_get_vendor(sc->sc_dev) && 886104477Ssam pci2id[i].pci_prod == pci_get_device(sc->sc_dev)) { 887104477Ssam offtbl = pci2id[i].card_id; 888104477Ssam break; 889104477Ssam } 890104477Ssam } 891104477Ssam if (offtbl == NULL) { 892104477Ssam device_printf(sc->sc_dev, "Unknown card!\n"); 893104477Ssam return (1); 894104477Ssam } 895104477Ssam 896104477Ssam ramcfg = READ_REG_0(sc, HIFN_0_PUCNFG); 897104477Ssam dmacfg = READ_REG_1(sc, HIFN_1_DMA_CNFG); 898104477Ssam 899104477Ssam /* 900104477Ssam * The RAM config register's encrypt level bit needs to be set before 901104477Ssam * every read performed on the encryption level register. 902104477Ssam */ 903104477Ssam WRITE_REG_0(sc, HIFN_0_PUCNFG, ramcfg | HIFN_PUCNFG_CHIPID); 904104477Ssam 905104477Ssam encl = READ_REG_0(sc, HIFN_0_PUSTAT) & HIFN_PUSTAT_CHIPENA; 906104477Ssam 907104477Ssam /* 908104477Ssam * Make sure we don't re-unlock. Two unlocks kills chip until the 909104477Ssam * next reboot. 910104477Ssam */ 911104477Ssam if (encl == HIFN_PUSTAT_ENA_1 || encl == HIFN_PUSTAT_ENA_2) { 912104477Ssam#ifdef HIFN_DEBUG 913104477Ssam if (hifn_debug) 914104477Ssam device_printf(sc->sc_dev, 915104477Ssam "Strong crypto already enabled!\n"); 916104477Ssam#endif 917104477Ssam goto report; 918104477Ssam } 919104477Ssam 920104477Ssam if (encl != 0 && encl != HIFN_PUSTAT_ENA_0) { 921104477Ssam#ifdef HIFN_DEBUG 922104477Ssam if (hifn_debug) 923104477Ssam device_printf(sc->sc_dev, 924104477Ssam "Unknown encryption level 0x%x\n", encl); 925104477Ssam#endif 926104477Ssam return 1; 927104477Ssam } 928104477Ssam 929104477Ssam WRITE_REG_1(sc, HIFN_1_DMA_CNFG, HIFN_DMACNFG_UNLOCK | 930104477Ssam HIFN_DMACNFG_MSTRESET | HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE); 931104477Ssam DELAY(1000); 932104477Ssam addr = READ_REG_1(sc, HIFN_UNLOCK_SECRET1); 933104477Ssam DELAY(1000); 934104477Ssam WRITE_REG_1(sc, HIFN_UNLOCK_SECRET2, 0); 935104477Ssam DELAY(1000); 936104477Ssam 937104477Ssam for (i = 0; i <= 12; i++) { 938104477Ssam addr = hifn_next_signature(addr, offtbl[i] + 0x101); 939104477Ssam WRITE_REG_1(sc, HIFN_UNLOCK_SECRET2, addr); 940104477Ssam 941104477Ssam DELAY(1000); 942104477Ssam } 943104477Ssam 944104477Ssam WRITE_REG_0(sc, HIFN_0_PUCNFG, ramcfg | HIFN_PUCNFG_CHIPID); 945104477Ssam encl = READ_REG_0(sc, HIFN_0_PUSTAT) & HIFN_PUSTAT_CHIPENA; 946104477Ssam 947104477Ssam#ifdef HIFN_DEBUG 948104477Ssam if (hifn_debug) { 949104477Ssam if (encl != HIFN_PUSTAT_ENA_1 && encl != HIFN_PUSTAT_ENA_2) 950104477Ssam device_printf(sc->sc_dev, "Engine is permanently " 951104477Ssam "locked until next system reset!\n"); 952104477Ssam else 953104477Ssam device_printf(sc->sc_dev, "Engine enabled " 954104477Ssam "successfully!\n"); 955104477Ssam } 956104477Ssam#endif 957104477Ssam 958104477Ssamreport: 959104477Ssam WRITE_REG_0(sc, HIFN_0_PUCNFG, ramcfg); 960104477Ssam WRITE_REG_1(sc, HIFN_1_DMA_CNFG, dmacfg); 961104477Ssam 962104477Ssam switch (encl) { 963104477Ssam case HIFN_PUSTAT_ENA_1: 964104477Ssam case HIFN_PUSTAT_ENA_2: 965104477Ssam break; 966104477Ssam case HIFN_PUSTAT_ENA_0: 967104477Ssam default: 968104477Ssam device_printf(sc->sc_dev, "disabled"); 969104477Ssam break; 970104477Ssam } 971104477Ssam 972104477Ssam return 0; 973104477Ssam} 974104477Ssam 975104477Ssam/* 976104477Ssam * Give initial values to the registers listed in the "Register Space" 977104477Ssam * section of the HIFN Software Development reference manual. 978104477Ssam */ 979104477Ssamstatic void 980104477Ssamhifn_init_pci_registers(struct hifn_softc *sc) 981104477Ssam{ 982104477Ssam /* write fixed values needed by the Initialization registers */ 983104477Ssam WRITE_REG_0(sc, HIFN_0_PUCTRL, HIFN_PUCTRL_DMAENA); 984104477Ssam WRITE_REG_0(sc, HIFN_0_FIFOCNFG, HIFN_FIFOCNFG_THRESHOLD); 985104477Ssam WRITE_REG_0(sc, HIFN_0_PUIER, HIFN_PUIER_DSTOVER); 986104477Ssam 987104477Ssam /* write all 4 ring address registers */ 988104477Ssam WRITE_REG_1(sc, HIFN_1_DMA_CRAR, sc->sc_dma_physaddr + 989104477Ssam offsetof(struct hifn_dma, cmdr[0])); 990104477Ssam WRITE_REG_1(sc, HIFN_1_DMA_SRAR, sc->sc_dma_physaddr + 991104477Ssam offsetof(struct hifn_dma, srcr[0])); 992104477Ssam WRITE_REG_1(sc, HIFN_1_DMA_DRAR, sc->sc_dma_physaddr + 993104477Ssam offsetof(struct hifn_dma, dstr[0])); 994104477Ssam WRITE_REG_1(sc, HIFN_1_DMA_RRAR, sc->sc_dma_physaddr + 995104477Ssam offsetof(struct hifn_dma, resr[0])); 996104477Ssam 997104477Ssam DELAY(2000); 998104477Ssam 999104477Ssam /* write status register */ 1000104477Ssam WRITE_REG_1(sc, HIFN_1_DMA_CSR, 1001104477Ssam HIFN_DMACSR_D_CTRL_DIS | HIFN_DMACSR_R_CTRL_DIS | 1002104477Ssam HIFN_DMACSR_S_CTRL_DIS | HIFN_DMACSR_C_CTRL_DIS | 1003104477Ssam HIFN_DMACSR_D_ABORT | HIFN_DMACSR_D_DONE | HIFN_DMACSR_D_LAST | 1004104477Ssam HIFN_DMACSR_D_WAIT | HIFN_DMACSR_D_OVER | 1005104477Ssam HIFN_DMACSR_R_ABORT | HIFN_DMACSR_R_DONE | HIFN_DMACSR_R_LAST | 1006104477Ssam HIFN_DMACSR_R_WAIT | HIFN_DMACSR_R_OVER | 1007104477Ssam HIFN_DMACSR_S_ABORT | HIFN_DMACSR_S_DONE | HIFN_DMACSR_S_LAST | 1008104477Ssam HIFN_DMACSR_S_WAIT | 1009104477Ssam HIFN_DMACSR_C_ABORT | HIFN_DMACSR_C_DONE | HIFN_DMACSR_C_LAST | 1010104477Ssam HIFN_DMACSR_C_WAIT | 1011104477Ssam HIFN_DMACSR_ENGINE | 1012104477Ssam ((sc->sc_flags & HIFN_HAS_PUBLIC) ? 1013104477Ssam HIFN_DMACSR_PUBDONE : 0) | 1014104477Ssam ((sc->sc_flags & HIFN_IS_7811) ? 1015104477Ssam HIFN_DMACSR_ILLW | HIFN_DMACSR_ILLR : 0)); 1016104477Ssam 1017104477Ssam sc->sc_d_busy = sc->sc_r_busy = sc->sc_s_busy = sc->sc_c_busy = 0; 1018104477Ssam sc->sc_dmaier |= HIFN_DMAIER_R_DONE | HIFN_DMAIER_C_ABORT | 1019104477Ssam HIFN_DMAIER_D_OVER | HIFN_DMAIER_R_OVER | 1020104477Ssam HIFN_DMAIER_S_ABORT | HIFN_DMAIER_D_ABORT | HIFN_DMAIER_R_ABORT | 1021104477Ssam ((sc->sc_flags & HIFN_IS_7811) ? 1022104477Ssam HIFN_DMAIER_ILLW | HIFN_DMAIER_ILLR : 0); 1023104477Ssam sc->sc_dmaier &= ~HIFN_DMAIER_C_WAIT; 1024104477Ssam WRITE_REG_1(sc, HIFN_1_DMA_IER, sc->sc_dmaier); 1025104477Ssam 1026104477Ssam WRITE_REG_0(sc, HIFN_0_PUCNFG, HIFN_PUCNFG_COMPSING | 1027104477Ssam HIFN_PUCNFG_DRFR_128 | HIFN_PUCNFG_TCALLPHASES | 1028104477Ssam HIFN_PUCNFG_TCDRVTOTEM | HIFN_PUCNFG_BUS32 | 1029104477Ssam (sc->sc_drammodel ? HIFN_PUCNFG_DRAM : HIFN_PUCNFG_SRAM)); 1030104477Ssam 1031104477Ssam WRITE_REG_0(sc, HIFN_0_PUISR, HIFN_PUISR_DSTOVER); 1032104477Ssam WRITE_REG_1(sc, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MSTRESET | 1033104477Ssam HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE | HIFN_DMACNFG_LAST | 1034104477Ssam ((HIFN_POLL_FREQUENCY << 16 ) & HIFN_DMACNFG_POLLFREQ) | 1035104477Ssam ((HIFN_POLL_SCALAR << 8) & HIFN_DMACNFG_POLLINVAL)); 1036104477Ssam} 1037104477Ssam 1038104477Ssam/* 1039104477Ssam * The maximum number of sessions supported by the card 1040104477Ssam * is dependent on the amount of context ram, which 1041104477Ssam * encryption algorithms are enabled, and how compression 1042104477Ssam * is configured. This should be configured before this 1043104477Ssam * routine is called. 1044104477Ssam */ 1045104477Ssamstatic void 1046104477Ssamhifn_sessions(struct hifn_softc *sc) 1047104477Ssam{ 1048104477Ssam u_int32_t pucnfg; 1049104477Ssam int ctxsize; 1050104477Ssam 1051104477Ssam pucnfg = READ_REG_0(sc, HIFN_0_PUCNFG); 1052104477Ssam 1053104477Ssam if (pucnfg & HIFN_PUCNFG_COMPSING) { 1054104477Ssam if (pucnfg & HIFN_PUCNFG_ENCCNFG) 1055104477Ssam ctxsize = 128; 1056104477Ssam else 1057104477Ssam ctxsize = 512; 1058104477Ssam sc->sc_maxses = 1 + 1059104477Ssam ((sc->sc_ramsize - 32768) / ctxsize); 1060104477Ssam } else 1061104477Ssam sc->sc_maxses = sc->sc_ramsize / 16384; 1062104477Ssam 1063104477Ssam if (sc->sc_maxses > 2048) 1064104477Ssam sc->sc_maxses = 2048; 1065104477Ssam} 1066104477Ssam 1067104477Ssam/* 1068104477Ssam * Determine ram type (sram or dram). Board should be just out of a reset 1069104477Ssam * state when this is called. 1070104477Ssam */ 1071104477Ssamstatic int 1072104477Ssamhifn_ramtype(struct hifn_softc *sc) 1073104477Ssam{ 1074104477Ssam u_int8_t data[8], dataexpect[8]; 1075104477Ssam int i; 1076104477Ssam 1077104477Ssam for (i = 0; i < sizeof(data); i++) 1078104477Ssam data[i] = dataexpect[i] = 0x55; 1079104477Ssam if (hifn_writeramaddr(sc, 0, data)) 1080104477Ssam return (-1); 1081104477Ssam if (hifn_readramaddr(sc, 0, data)) 1082104477Ssam return (-1); 1083104477Ssam if (bcmp(data, dataexpect, sizeof(data)) != 0) { 1084104477Ssam sc->sc_drammodel = 1; 1085104477Ssam return (0); 1086104477Ssam } 1087104477Ssam 1088104477Ssam for (i = 0; i < sizeof(data); i++) 1089104477Ssam data[i] = dataexpect[i] = 0xaa; 1090104477Ssam if (hifn_writeramaddr(sc, 0, data)) 1091104477Ssam return (-1); 1092104477Ssam if (hifn_readramaddr(sc, 0, data)) 1093104477Ssam return (-1); 1094104477Ssam if (bcmp(data, dataexpect, sizeof(data)) != 0) { 1095104477Ssam sc->sc_drammodel = 1; 1096104477Ssam return (0); 1097104477Ssam } 1098104477Ssam 1099104477Ssam return (0); 1100104477Ssam} 1101104477Ssam 1102104477Ssam#define HIFN_SRAM_MAX (32 << 20) 1103104477Ssam#define HIFN_SRAM_STEP_SIZE 16384 1104104477Ssam#define HIFN_SRAM_GRANULARITY (HIFN_SRAM_MAX / HIFN_SRAM_STEP_SIZE) 1105104477Ssam 1106104477Ssamstatic int 1107104477Ssamhifn_sramsize(struct hifn_softc *sc) 1108104477Ssam{ 1109104477Ssam u_int32_t a; 1110104477Ssam u_int8_t data[8]; 1111104477Ssam u_int8_t dataexpect[sizeof(data)]; 1112104477Ssam int32_t i; 1113104477Ssam 1114104477Ssam for (i = 0; i < sizeof(data); i++) 1115104477Ssam data[i] = dataexpect[i] = i ^ 0x5a; 1116104477Ssam 1117104477Ssam for (i = HIFN_SRAM_GRANULARITY - 1; i >= 0; i--) { 1118104477Ssam a = i * HIFN_SRAM_STEP_SIZE; 1119104477Ssam bcopy(&i, data, sizeof(i)); 1120104477Ssam hifn_writeramaddr(sc, a, data); 1121104477Ssam } 1122104477Ssam 1123104477Ssam for (i = 0; i < HIFN_SRAM_GRANULARITY; i++) { 1124104477Ssam a = i * HIFN_SRAM_STEP_SIZE; 1125104477Ssam bcopy(&i, dataexpect, sizeof(i)); 1126104477Ssam if (hifn_readramaddr(sc, a, data) < 0) 1127104477Ssam return (0); 1128104477Ssam if (bcmp(data, dataexpect, sizeof(data)) != 0) 1129104477Ssam return (0); 1130104477Ssam sc->sc_ramsize = a + HIFN_SRAM_STEP_SIZE; 1131104477Ssam } 1132104477Ssam 1133104477Ssam return (0); 1134104477Ssam} 1135104477Ssam 1136104477Ssam/* 1137104477Ssam * XXX For dram boards, one should really try all of the 1138104477Ssam * HIFN_PUCNFG_DSZ_*'s. This just assumes that PUCNFG 1139104477Ssam * is already set up correctly. 1140104477Ssam */ 1141104477Ssamstatic int 1142104477Ssamhifn_dramsize(struct hifn_softc *sc) 1143104477Ssam{ 1144104477Ssam u_int32_t cnfg; 1145104477Ssam 1146104477Ssam cnfg = READ_REG_0(sc, HIFN_0_PUCNFG) & 1147104477Ssam HIFN_PUCNFG_DRAMMASK; 1148104477Ssam sc->sc_ramsize = 1 << ((cnfg >> 13) + 18); 1149104477Ssam return (0); 1150104477Ssam} 1151104477Ssam 1152104477Ssamstatic void 1153104477Ssamhifn_alloc_slot(struct hifn_softc *sc, int *cmdp, int *srcp, int *dstp, int *resp) 1154104477Ssam{ 1155104477Ssam struct hifn_dma *dma = sc->sc_dma; 1156104477Ssam 1157104477Ssam if (dma->cmdi == HIFN_D_CMD_RSIZE) { 1158104477Ssam dma->cmdi = 0; 1159104477Ssam dma->cmdr[HIFN_D_CMD_RSIZE].l = htole32(HIFN_D_VALID | 1160104477Ssam HIFN_D_JUMP | HIFN_D_MASKDONEIRQ); 1161104477Ssam HIFN_CMDR_SYNC(sc, HIFN_D_CMD_RSIZE, 1162104477Ssam BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); 1163104477Ssam } 1164104477Ssam *cmdp = dma->cmdi++; 1165104477Ssam dma->cmdk = dma->cmdi; 1166104477Ssam 1167104477Ssam if (dma->srci == HIFN_D_SRC_RSIZE) { 1168104477Ssam dma->srci = 0; 1169104477Ssam dma->srcr[HIFN_D_SRC_RSIZE].l = htole32(HIFN_D_VALID | 1170104477Ssam HIFN_D_JUMP | HIFN_D_MASKDONEIRQ); 1171104477Ssam HIFN_SRCR_SYNC(sc, HIFN_D_SRC_RSIZE, 1172104477Ssam BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); 1173104477Ssam } 1174104477Ssam *srcp = dma->srci++; 1175104477Ssam dma->srck = dma->srci; 1176104477Ssam 1177104477Ssam if (dma->dsti == HIFN_D_DST_RSIZE) { 1178104477Ssam dma->dsti = 0; 1179104477Ssam dma->dstr[HIFN_D_DST_RSIZE].l = htole32(HIFN_D_VALID | 1180104477Ssam HIFN_D_JUMP | HIFN_D_MASKDONEIRQ); 1181104477Ssam HIFN_DSTR_SYNC(sc, HIFN_D_DST_RSIZE, 1182104477Ssam BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); 1183104477Ssam } 1184104477Ssam *dstp = dma->dsti++; 1185104477Ssam dma->dstk = dma->dsti; 1186104477Ssam 1187104477Ssam if (dma->resi == HIFN_D_RES_RSIZE) { 1188104477Ssam dma->resi = 0; 1189104477Ssam dma->resr[HIFN_D_RES_RSIZE].l = htole32(HIFN_D_VALID | 1190104477Ssam HIFN_D_JUMP | HIFN_D_MASKDONEIRQ); 1191104477Ssam HIFN_RESR_SYNC(sc, HIFN_D_RES_RSIZE, 1192104477Ssam BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); 1193104477Ssam } 1194104477Ssam *resp = dma->resi++; 1195104477Ssam dma->resk = dma->resi; 1196104477Ssam} 1197104477Ssam 1198104477Ssamstatic int 1199104477Ssamhifn_writeramaddr(struct hifn_softc *sc, int addr, u_int8_t *data) 1200104477Ssam{ 1201104477Ssam struct hifn_dma *dma = sc->sc_dma; 1202104477Ssam hifn_base_command_t wc; 1203104477Ssam const u_int32_t masks = HIFN_D_VALID | HIFN_D_LAST | HIFN_D_MASKDONEIRQ; 1204104477Ssam int r, cmdi, resi, srci, dsti; 1205104477Ssam 1206104477Ssam wc.masks = htole16(3 << 13); 1207104477Ssam wc.session_num = htole16(addr >> 14); 1208104477Ssam wc.total_source_count = htole16(8); 1209104477Ssam wc.total_dest_count = htole16(addr & 0x3fff); 1210104477Ssam 1211104477Ssam hifn_alloc_slot(sc, &cmdi, &srci, &dsti, &resi); 1212104477Ssam 1213104477Ssam WRITE_REG_1(sc, HIFN_1_DMA_CSR, 1214104477Ssam HIFN_DMACSR_C_CTRL_ENA | HIFN_DMACSR_S_CTRL_ENA | 1215104477Ssam HIFN_DMACSR_D_CTRL_ENA | HIFN_DMACSR_R_CTRL_ENA); 1216104477Ssam 1217104477Ssam /* build write command */ 1218104477Ssam bzero(dma->command_bufs[cmdi], HIFN_MAX_COMMAND); 1219104477Ssam *(hifn_base_command_t *)dma->command_bufs[cmdi] = wc; 1220104477Ssam bcopy(data, &dma->test_src, sizeof(dma->test_src)); 1221104477Ssam 1222104477Ssam dma->srcr[srci].p = htole32(sc->sc_dma_physaddr 1223104477Ssam + offsetof(struct hifn_dma, test_src)); 1224104477Ssam dma->dstr[dsti].p = htole32(sc->sc_dma_physaddr 1225104477Ssam + offsetof(struct hifn_dma, test_dst)); 1226104477Ssam 1227104477Ssam dma->cmdr[cmdi].l = htole32(16 | masks); 1228104477Ssam dma->srcr[srci].l = htole32(8 | masks); 1229104477Ssam dma->dstr[dsti].l = htole32(4 | masks); 1230104477Ssam dma->resr[resi].l = htole32(4 | masks); 1231104477Ssam 1232104477Ssam bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, 1233104477Ssam BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1234104477Ssam 1235104477Ssam for (r = 10000; r >= 0; r--) { 1236104477Ssam DELAY(10); 1237104477Ssam bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, 1238104477Ssam BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 1239104477Ssam if ((dma->resr[resi].l & htole32(HIFN_D_VALID)) == 0) 1240104477Ssam break; 1241104477Ssam bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, 1242104477Ssam BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1243104477Ssam } 1244104477Ssam if (r == 0) { 1245104477Ssam device_printf(sc->sc_dev, "writeramaddr -- " 1246104477Ssam "result[%d](addr %d) still valid\n", resi, addr); 1247104477Ssam r = -1; 1248104477Ssam return (-1); 1249104477Ssam } else 1250104477Ssam r = 0; 1251104477Ssam 1252104477Ssam WRITE_REG_1(sc, HIFN_1_DMA_CSR, 1253104477Ssam HIFN_DMACSR_C_CTRL_DIS | HIFN_DMACSR_S_CTRL_DIS | 1254104477Ssam HIFN_DMACSR_D_CTRL_DIS | HIFN_DMACSR_R_CTRL_DIS); 1255104477Ssam 1256104477Ssam return (r); 1257104477Ssam} 1258104477Ssam 1259104477Ssamstatic int 1260104477Ssamhifn_readramaddr(struct hifn_softc *sc, int addr, u_int8_t *data) 1261104477Ssam{ 1262104477Ssam struct hifn_dma *dma = sc->sc_dma; 1263104477Ssam hifn_base_command_t rc; 1264104477Ssam const u_int32_t masks = HIFN_D_VALID | HIFN_D_LAST | HIFN_D_MASKDONEIRQ; 1265104477Ssam int r, cmdi, srci, dsti, resi; 1266104477Ssam 1267104477Ssam rc.masks = htole16(2 << 13); 1268104477Ssam rc.session_num = htole16(addr >> 14); 1269104477Ssam rc.total_source_count = htole16(addr & 0x3fff); 1270104477Ssam rc.total_dest_count = htole16(8); 1271104477Ssam 1272104477Ssam hifn_alloc_slot(sc, &cmdi, &srci, &dsti, &resi); 1273104477Ssam 1274104477Ssam WRITE_REG_1(sc, HIFN_1_DMA_CSR, 1275104477Ssam HIFN_DMACSR_C_CTRL_ENA | HIFN_DMACSR_S_CTRL_ENA | 1276104477Ssam HIFN_DMACSR_D_CTRL_ENA | HIFN_DMACSR_R_CTRL_ENA); 1277104477Ssam 1278104477Ssam bzero(dma->command_bufs[cmdi], HIFN_MAX_COMMAND); 1279104477Ssam *(hifn_base_command_t *)dma->command_bufs[cmdi] = rc; 1280104477Ssam 1281104477Ssam dma->srcr[srci].p = htole32(sc->sc_dma_physaddr + 1282104477Ssam offsetof(struct hifn_dma, test_src)); 1283104477Ssam dma->test_src = 0; 1284104477Ssam dma->dstr[dsti].p = htole32(sc->sc_dma_physaddr + 1285104477Ssam offsetof(struct hifn_dma, test_dst)); 1286104477Ssam dma->test_dst = 0; 1287104477Ssam dma->cmdr[cmdi].l = htole32(8 | masks); 1288104477Ssam dma->srcr[srci].l = htole32(8 | masks); 1289104477Ssam dma->dstr[dsti].l = htole32(8 | masks); 1290104477Ssam dma->resr[resi].l = htole32(HIFN_MAX_RESULT | masks); 1291104477Ssam 1292104477Ssam bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, 1293104477Ssam BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1294104477Ssam 1295104477Ssam for (r = 10000; r >= 0; r--) { 1296104477Ssam DELAY(10); 1297104477Ssam bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, 1298104477Ssam BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 1299104477Ssam if ((dma->resr[resi].l & htole32(HIFN_D_VALID)) == 0) 1300104477Ssam break; 1301104477Ssam bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, 1302104477Ssam BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1303104477Ssam } 1304104477Ssam if (r == 0) { 1305104477Ssam device_printf(sc->sc_dev, "readramaddr -- " 1306104477Ssam "result[%d](addr %d) still valid\n", resi, addr); 1307104477Ssam r = -1; 1308104477Ssam } else { 1309104477Ssam r = 0; 1310104477Ssam bcopy(&dma->test_dst, data, sizeof(dma->test_dst)); 1311104477Ssam } 1312104477Ssam 1313104477Ssam WRITE_REG_1(sc, HIFN_1_DMA_CSR, 1314104477Ssam HIFN_DMACSR_C_CTRL_DIS | HIFN_DMACSR_S_CTRL_DIS | 1315104477Ssam HIFN_DMACSR_D_CTRL_DIS | HIFN_DMACSR_R_CTRL_DIS); 1316104477Ssam 1317104477Ssam return (r); 1318104477Ssam} 1319104477Ssam 1320104477Ssam/* 1321104477Ssam * Initialize the descriptor rings. 1322104477Ssam */ 1323104477Ssamstatic void 1324104477Ssamhifn_init_dma(struct hifn_softc *sc) 1325104477Ssam{ 1326104477Ssam struct hifn_dma *dma = sc->sc_dma; 1327104477Ssam int i; 1328104477Ssam 1329104477Ssam hifn_set_retry(sc); 1330104477Ssam 1331104477Ssam /* initialize static pointer values */ 1332104477Ssam for (i = 0; i < HIFN_D_CMD_RSIZE; i++) 1333104477Ssam dma->cmdr[i].p = htole32(sc->sc_dma_physaddr + 1334104477Ssam offsetof(struct hifn_dma, command_bufs[i][0])); 1335104477Ssam for (i = 0; i < HIFN_D_RES_RSIZE; i++) 1336104477Ssam dma->resr[i].p = htole32(sc->sc_dma_physaddr + 1337104477Ssam offsetof(struct hifn_dma, result_bufs[i][0])); 1338104477Ssam 1339104477Ssam dma->cmdr[HIFN_D_CMD_RSIZE].p = 1340104477Ssam htole32(sc->sc_dma_physaddr + offsetof(struct hifn_dma, cmdr[0])); 1341104477Ssam dma->srcr[HIFN_D_SRC_RSIZE].p = 1342104477Ssam htole32(sc->sc_dma_physaddr + offsetof(struct hifn_dma, srcr[0])); 1343104477Ssam dma->dstr[HIFN_D_DST_RSIZE].p = 1344104477Ssam htole32(sc->sc_dma_physaddr + offsetof(struct hifn_dma, dstr[0])); 1345104477Ssam dma->resr[HIFN_D_RES_RSIZE].p = 1346104477Ssam htole32(sc->sc_dma_physaddr + offsetof(struct hifn_dma, resr[0])); 1347104477Ssam 1348104477Ssam dma->cmdu = dma->srcu = dma->dstu = dma->resu = 0; 1349104477Ssam dma->cmdi = dma->srci = dma->dsti = dma->resi = 0; 1350104477Ssam dma->cmdk = dma->srck = dma->dstk = dma->resk = 0; 1351104477Ssam} 1352104477Ssam 1353104477Ssam/* 1354104477Ssam * Writes out the raw command buffer space. Returns the 1355104477Ssam * command buffer size. 1356104477Ssam */ 1357104477Ssamstatic u_int 1358104477Ssamhifn_write_command(struct hifn_command *cmd, u_int8_t *buf) 1359104477Ssam{ 1360104477Ssam#define MIN(a,b) ((a)<(b)?(a):(b)) 1361104477Ssam u_int8_t *buf_pos; 1362104477Ssam hifn_base_command_t *base_cmd; 1363104477Ssam hifn_mac_command_t *mac_cmd; 1364104477Ssam hifn_crypt_command_t *cry_cmd; 1365104477Ssam int using_mac, using_crypt, len; 1366104477Ssam u_int32_t dlen, slen; 1367104477Ssam 1368104477Ssam buf_pos = buf; 1369104477Ssam using_mac = cmd->base_masks & HIFN_BASE_CMD_MAC; 1370104477Ssam using_crypt = cmd->base_masks & HIFN_BASE_CMD_CRYPT; 1371104477Ssam 1372104477Ssam base_cmd = (hifn_base_command_t *)buf_pos; 1373104477Ssam base_cmd->masks = htole16(cmd->base_masks); 1374104477Ssam slen = cmd->src_mapsize; 1375104477Ssam if (cmd->sloplen) 1376104477Ssam dlen = cmd->dst_mapsize - cmd->sloplen + sizeof(u_int32_t); 1377104477Ssam else 1378104477Ssam dlen = cmd->dst_mapsize; 1379104477Ssam base_cmd->total_source_count = htole16(slen & HIFN_BASE_CMD_LENMASK_LO); 1380104477Ssam base_cmd->total_dest_count = htole16(dlen & HIFN_BASE_CMD_LENMASK_LO); 1381104477Ssam dlen >>= 16; 1382104477Ssam slen >>= 16; 1383104477Ssam base_cmd->session_num = htole16(cmd->session_num | 1384104477Ssam ((slen << HIFN_BASE_CMD_SRCLEN_S) & HIFN_BASE_CMD_SRCLEN_M) | 1385104477Ssam ((dlen << HIFN_BASE_CMD_DSTLEN_S) & HIFN_BASE_CMD_DSTLEN_M)); 1386104477Ssam buf_pos += sizeof(hifn_base_command_t); 1387104477Ssam 1388104477Ssam if (using_mac) { 1389104477Ssam mac_cmd = (hifn_mac_command_t *)buf_pos; 1390104477Ssam dlen = cmd->maccrd->crd_len; 1391104477Ssam mac_cmd->source_count = htole16(dlen & 0xffff); 1392104477Ssam dlen >>= 16; 1393104477Ssam mac_cmd->masks = htole16(cmd->mac_masks | 1394104477Ssam ((dlen << HIFN_MAC_CMD_SRCLEN_S) & HIFN_MAC_CMD_SRCLEN_M)); 1395104477Ssam mac_cmd->header_skip = htole16(cmd->maccrd->crd_skip); 1396104477Ssam mac_cmd->reserved = 0; 1397104477Ssam buf_pos += sizeof(hifn_mac_command_t); 1398104477Ssam } 1399104477Ssam 1400104477Ssam if (using_crypt) { 1401104477Ssam cry_cmd = (hifn_crypt_command_t *)buf_pos; 1402104477Ssam dlen = cmd->enccrd->crd_len; 1403104477Ssam cry_cmd->source_count = htole16(dlen & 0xffff); 1404104477Ssam dlen >>= 16; 1405104477Ssam cry_cmd->masks = htole16(cmd->cry_masks | 1406104477Ssam ((dlen << HIFN_CRYPT_CMD_SRCLEN_S) & HIFN_CRYPT_CMD_SRCLEN_M)); 1407104477Ssam cry_cmd->header_skip = htole16(cmd->enccrd->crd_skip); 1408104477Ssam cry_cmd->reserved = 0; 1409104477Ssam buf_pos += sizeof(hifn_crypt_command_t); 1410104477Ssam } 1411104477Ssam 1412104477Ssam if (using_mac && cmd->mac_masks & HIFN_MAC_CMD_NEW_KEY) { 1413104477Ssam bcopy(cmd->mac, buf_pos, HIFN_MAC_KEY_LENGTH); 1414104477Ssam buf_pos += HIFN_MAC_KEY_LENGTH; 1415104477Ssam } 1416104477Ssam 1417104477Ssam if (using_crypt && cmd->cry_masks & HIFN_CRYPT_CMD_NEW_KEY) { 1418104477Ssam switch (cmd->cry_masks & HIFN_CRYPT_CMD_ALG_MASK) { 1419104477Ssam case HIFN_CRYPT_CMD_ALG_3DES: 1420104477Ssam bcopy(cmd->ck, buf_pos, HIFN_3DES_KEY_LENGTH); 1421104477Ssam buf_pos += HIFN_3DES_KEY_LENGTH; 1422104477Ssam break; 1423104477Ssam case HIFN_CRYPT_CMD_ALG_DES: 1424104477Ssam bcopy(cmd->ck, buf_pos, HIFN_DES_KEY_LENGTH); 1425104477Ssam buf_pos += cmd->cklen; 1426104477Ssam break; 1427104477Ssam case HIFN_CRYPT_CMD_ALG_RC4: 1428104477Ssam len = 256; 1429104477Ssam do { 1430104477Ssam int clen; 1431104477Ssam 1432104477Ssam clen = MIN(cmd->cklen, len); 1433104477Ssam bcopy(cmd->ck, buf_pos, clen); 1434104477Ssam len -= clen; 1435104477Ssam buf_pos += clen; 1436104477Ssam } while (len > 0); 1437104477Ssam bzero(buf_pos, 4); 1438104477Ssam buf_pos += 4; 1439104477Ssam break; 1440104477Ssam } 1441104477Ssam } 1442104477Ssam 1443104477Ssam if (using_crypt && cmd->cry_masks & HIFN_CRYPT_CMD_NEW_IV) { 1444104477Ssam bcopy(cmd->iv, buf_pos, HIFN_IV_LENGTH); 1445104477Ssam buf_pos += HIFN_IV_LENGTH; 1446104477Ssam } 1447104477Ssam 1448104477Ssam if ((cmd->base_masks & (HIFN_BASE_CMD_MAC|HIFN_BASE_CMD_CRYPT)) == 0) { 1449104477Ssam bzero(buf_pos, 8); 1450104477Ssam buf_pos += 8; 1451104477Ssam } 1452104477Ssam 1453104477Ssam return (buf_pos - buf); 1454104477Ssam#undef MIN 1455104477Ssam} 1456104477Ssam 1457104477Ssamstatic int 1458104477Ssamhifn_dmamap_aligned(struct hifn_operand *op) 1459104477Ssam{ 1460104477Ssam int i; 1461104477Ssam 1462104477Ssam for (i = 0; i < op->nsegs; i++) { 1463104477Ssam if (op->segs[i].ds_addr & 3) 1464104477Ssam return (0); 1465104477Ssam if ((i != (op->nsegs - 1)) && (op->segs[i].ds_len & 3)) 1466104477Ssam return (0); 1467104477Ssam } 1468104477Ssam return (1); 1469104477Ssam} 1470104477Ssam 1471104477Ssamstatic int 1472104477Ssamhifn_dmamap_load_dst(struct hifn_softc *sc, struct hifn_command *cmd) 1473104477Ssam{ 1474104477Ssam struct hifn_dma *dma = sc->sc_dma; 1475104477Ssam struct hifn_operand *dst = &cmd->dst; 1476104477Ssam u_int32_t p, l; 1477104477Ssam int idx, used = 0, i; 1478104477Ssam 1479104477Ssam idx = dma->dsti; 1480104477Ssam for (i = 0; i < dst->nsegs - 1; i++) { 1481104477Ssam dma->dstr[idx].p = htole32(dst->segs[i].ds_addr); 1482104477Ssam dma->dstr[idx].l = htole32(HIFN_D_VALID | 1483104477Ssam HIFN_D_MASKDONEIRQ | dst->segs[i].ds_len); 1484104477Ssam HIFN_DSTR_SYNC(sc, idx, 1485104477Ssam BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1486104477Ssam used++; 1487104477Ssam 1488104477Ssam if (++idx == HIFN_D_DST_RSIZE) { 1489104477Ssam dma->dstr[idx].l = htole32(HIFN_D_VALID | 1490104477Ssam HIFN_D_JUMP | HIFN_D_MASKDONEIRQ); 1491104477Ssam HIFN_DSTR_SYNC(sc, idx, 1492104477Ssam BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1493104477Ssam idx = 0; 1494104477Ssam } 1495104477Ssam } 1496104477Ssam 1497104477Ssam if (cmd->sloplen == 0) { 1498104477Ssam p = dst->segs[i].ds_addr; 1499104477Ssam l = HIFN_D_VALID | HIFN_D_MASKDONEIRQ | HIFN_D_LAST | 1500104477Ssam dst->segs[i].ds_len; 1501104477Ssam } else { 1502104477Ssam p = sc->sc_dma_physaddr + 1503104477Ssam offsetof(struct hifn_dma, slop[cmd->slopidx]); 1504104477Ssam l = HIFN_D_VALID | HIFN_D_MASKDONEIRQ | HIFN_D_LAST | 1505104477Ssam sizeof(u_int32_t); 1506104477Ssam 1507104477Ssam if ((dst->segs[i].ds_len - cmd->sloplen) != 0) { 1508104477Ssam dma->dstr[idx].p = htole32(dst->segs[i].ds_addr); 1509104477Ssam dma->dstr[idx].l = htole32(HIFN_D_VALID | 1510104477Ssam HIFN_D_MASKDONEIRQ | 1511104477Ssam (dst->segs[i].ds_len - cmd->sloplen)); 1512104477Ssam HIFN_DSTR_SYNC(sc, idx, 1513104477Ssam BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1514104477Ssam used++; 1515104477Ssam 1516104477Ssam if (++idx == HIFN_D_DST_RSIZE) { 1517104477Ssam dma->dstr[idx].l = htole32(HIFN_D_VALID | 1518104477Ssam HIFN_D_JUMP | HIFN_D_MASKDONEIRQ); 1519104477Ssam HIFN_DSTR_SYNC(sc, idx, 1520104477Ssam BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1521104477Ssam idx = 0; 1522104477Ssam } 1523104477Ssam } 1524104477Ssam } 1525104477Ssam dma->dstr[idx].p = htole32(p); 1526104477Ssam dma->dstr[idx].l = htole32(l); 1527104477Ssam HIFN_DSTR_SYNC(sc, idx, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1528104477Ssam used++; 1529104477Ssam 1530104477Ssam if (++idx == HIFN_D_DST_RSIZE) { 1531104477Ssam dma->dstr[idx].l = htole32(HIFN_D_VALID | HIFN_D_JUMP | 1532104477Ssam HIFN_D_MASKDONEIRQ); 1533104477Ssam HIFN_DSTR_SYNC(sc, idx, 1534104477Ssam BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1535104477Ssam idx = 0; 1536104477Ssam } 1537104477Ssam 1538104477Ssam dma->dsti = idx; 1539104477Ssam dma->dstu += used; 1540104477Ssam return (idx); 1541104477Ssam} 1542104477Ssam 1543104477Ssamstatic int 1544104477Ssamhifn_dmamap_load_src(struct hifn_softc *sc, struct hifn_command *cmd) 1545104477Ssam{ 1546104477Ssam struct hifn_dma *dma = sc->sc_dma; 1547104477Ssam struct hifn_operand *src = &cmd->src; 1548104477Ssam int idx, i; 1549104477Ssam u_int32_t last = 0; 1550104477Ssam 1551104477Ssam idx = dma->srci; 1552104477Ssam for (i = 0; i < src->nsegs; i++) { 1553104477Ssam if (i == src->nsegs - 1) 1554104477Ssam last = HIFN_D_LAST; 1555104477Ssam 1556104477Ssam dma->srcr[idx].p = htole32(src->segs[i].ds_addr); 1557104477Ssam dma->srcr[idx].l = htole32(src->segs[i].ds_len | 1558104477Ssam HIFN_D_VALID | HIFN_D_MASKDONEIRQ | last); 1559104477Ssam HIFN_SRCR_SYNC(sc, idx, 1560104477Ssam BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); 1561104477Ssam 1562104477Ssam if (++idx == HIFN_D_SRC_RSIZE) { 1563104477Ssam dma->srcr[idx].l = htole32(HIFN_D_VALID | 1564104477Ssam HIFN_D_JUMP | HIFN_D_MASKDONEIRQ); 1565104477Ssam HIFN_SRCR_SYNC(sc, HIFN_D_SRC_RSIZE, 1566104477Ssam BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); 1567104477Ssam idx = 0; 1568104477Ssam } 1569104477Ssam } 1570104477Ssam dma->srci = idx; 1571104477Ssam dma->srcu += src->nsegs; 1572104477Ssam return (idx); 1573104477Ssam} 1574104477Ssam 1575104477Ssamstatic void 1576104477Ssamhifn_op_cb(void* arg, bus_dma_segment_t *seg, int nsegs, bus_size_t mapsize, int error) 1577104477Ssam{ 1578104477Ssam struct hifn_operand *op = arg; 1579104477Ssam 1580104477Ssam KASSERT(nsegs <= MAX_SCATTER, 1581104477Ssam ("hifn_op_cb: too many DMA segments (%u > %u) " 1582104477Ssam "returned when mapping operand", nsegs, MAX_SCATTER)); 1583104477Ssam op->mapsize = mapsize; 1584104477Ssam op->nsegs = nsegs; 1585104477Ssam bcopy(seg, op->segs, nsegs * sizeof (seg[0])); 1586104477Ssam} 1587104477Ssam 1588104477Ssamstatic int 1589104477Ssamhifn_crypto( 1590104477Ssam struct hifn_softc *sc, 1591104477Ssam struct hifn_command *cmd, 1592104477Ssam struct cryptop *crp, 1593104477Ssam int hint) 1594104477Ssam{ 1595104477Ssam struct hifn_dma *dma = sc->sc_dma; 1596104477Ssam u_int32_t cmdlen; 1597104477Ssam int cmdi, resi, err = 0; 1598104477Ssam 1599104477Ssam /* 1600104477Ssam * need 1 cmd, and 1 res 1601104477Ssam * 1602104477Ssam * NB: check this first since it's easy. 1603104477Ssam */ 1604104477Ssam if ((dma->cmdu + 1) > HIFN_D_CMD_RSIZE || 1605104477Ssam (dma->resu + 1) > HIFN_D_RES_RSIZE) { 1606104477Ssam#ifdef HIFN_DEBUG 1607104477Ssam if (hifn_debug) { 1608104477Ssam device_printf(sc->sc_dev, 1609104477Ssam "cmd/result exhaustion, cmdu %u resu %u\n", 1610104477Ssam dma->cmdu, dma->resu); 1611104477Ssam } 1612104477Ssam#endif 1613104477Ssam hifnstats.hst_nomem_cr++; 1614104477Ssam return (ERESTART); 1615104477Ssam } 1616104477Ssam 1617104477Ssam if (bus_dmamap_create(sc->sc_dmat, BUS_DMA_NOWAIT, &cmd->src_map)) { 1618104477Ssam hifnstats.hst_nomem_map++; 1619104477Ssam return (ENOMEM); 1620104477Ssam } 1621104477Ssam 1622104477Ssam if (crp->crp_flags & CRYPTO_F_IMBUF) { 1623104477Ssam if (bus_dmamap_load_mbuf(sc->sc_dmat, cmd->src_map, 1624104477Ssam cmd->src_m, hifn_op_cb, &cmd->src, BUS_DMA_NOWAIT)) { 1625104477Ssam hifnstats.hst_nomem_load++; 1626104477Ssam err = ENOMEM; 1627104477Ssam goto err_srcmap1; 1628104477Ssam } 1629104477Ssam } else if (crp->crp_flags & CRYPTO_F_IOV) { 1630104477Ssam if (bus_dmamap_load_uio(sc->sc_dmat, cmd->src_map, 1631104477Ssam cmd->src_io, hifn_op_cb, &cmd->src, BUS_DMA_NOWAIT)) { 1632104477Ssam hifnstats.hst_nomem_load++; 1633104477Ssam err = ENOMEM; 1634104477Ssam goto err_srcmap1; 1635104477Ssam } 1636104477Ssam } else { 1637104477Ssam err = EINVAL; 1638104477Ssam goto err_srcmap1; 1639104477Ssam } 1640104477Ssam 1641104477Ssam if (hifn_dmamap_aligned(&cmd->src)) { 1642104477Ssam cmd->sloplen = cmd->src_mapsize & 3; 1643104477Ssam cmd->dst = cmd->src; 1644104477Ssam } else { 1645104477Ssam if (crp->crp_flags & CRYPTO_F_IOV) { 1646104477Ssam err = EINVAL; 1647104477Ssam goto err_srcmap; 1648104477Ssam } else if (crp->crp_flags & CRYPTO_F_IMBUF) { 1649104477Ssam int totlen, len; 1650104477Ssam struct mbuf *m, *m0, *mlast; 1651104477Ssam 1652104477Ssam KASSERT(cmd->dst_m == cmd->src_m, 1653104477Ssam ("hifn_crypto: dst_m initialized improperly")); 1654104477Ssam hifnstats.hst_unaligned++; 1655104477Ssam /* 1656104477Ssam * Source is not aligned on a longword boundary. 1657104477Ssam * Copy the data to insure alignment. If we fail 1658104477Ssam * to allocate mbufs or clusters while doing this 1659104477Ssam * we return ERESTART so the operation is requeued 1660104477Ssam * at the crypto later, but only if there are 1661104477Ssam * ops already posted to the hardware; otherwise we 1662104477Ssam * have no guarantee that we'll be re-entered. 1663104477Ssam */ 1664104477Ssam totlen = cmd->src_mapsize; 1665104477Ssam if (cmd->src_m->m_flags & M_PKTHDR) { 1666104477Ssam len = MHLEN; 1667104477Ssam MGETHDR(m0, M_DONTWAIT, MT_DATA); 1668104477Ssam } else { 1669104477Ssam len = MLEN; 1670104477Ssam MGET(m0, M_DONTWAIT, MT_DATA); 1671104477Ssam } 1672104477Ssam if (m0 == NULL) { 1673104477Ssam hifnstats.hst_nomem_mbuf++; 1674104477Ssam err = dma->cmdu ? ERESTART : ENOMEM; 1675104477Ssam goto err_srcmap; 1676104477Ssam } 1677104477Ssam if (len == MHLEN) { 1678104477Ssam M_COPY_PKTHDR(m0, cmd->src_m); 1679104477Ssam } 1680104477Ssam if (totlen >= MINCLSIZE) { 1681104477Ssam MCLGET(m0, M_DONTWAIT); 1682104477Ssam if ((m0->m_flags & M_EXT) == 0) { 1683104477Ssam hifnstats.hst_nomem_mcl++; 1684104477Ssam err = dma->cmdu ? ERESTART : ENOMEM; 1685104477Ssam m_freem(m0); 1686104477Ssam goto err_srcmap; 1687104477Ssam } 1688104477Ssam len = MCLBYTES; 1689104477Ssam } 1690104477Ssam totlen -= len; 1691104477Ssam m0->m_pkthdr.len = m0->m_len = len; 1692104477Ssam mlast = m0; 1693104477Ssam 1694104477Ssam while (totlen > 0) { 1695104477Ssam MGET(m, M_DONTWAIT, MT_DATA); 1696104477Ssam if (m == NULL) { 1697104477Ssam hifnstats.hst_nomem_mbuf++; 1698104477Ssam err = dma->cmdu ? ERESTART : ENOMEM; 1699104477Ssam m_freem(m0); 1700104477Ssam goto err_srcmap; 1701104477Ssam } 1702104477Ssam len = MLEN; 1703104477Ssam if (totlen >= MINCLSIZE) { 1704104477Ssam MCLGET(m, M_DONTWAIT); 1705104477Ssam if ((m->m_flags & M_EXT) == 0) { 1706104477Ssam hifnstats.hst_nomem_mcl++; 1707104477Ssam err = dma->cmdu ? ERESTART : ENOMEM; 1708104477Ssam mlast->m_next = m; 1709104477Ssam m_freem(m0); 1710104477Ssam goto err_srcmap; 1711104477Ssam } 1712104477Ssam len = MCLBYTES; 1713104477Ssam } 1714104477Ssam 1715104477Ssam m->m_len = len; 1716104477Ssam m0->m_pkthdr.len += len; 1717104477Ssam totlen -= len; 1718104477Ssam 1719104477Ssam mlast->m_next = m; 1720104477Ssam mlast = m; 1721104477Ssam } 1722104477Ssam cmd->dst_m = m0; 1723104477Ssam } 1724104477Ssam } 1725104477Ssam 1726104477Ssam if (cmd->dst_map == NULL) { 1727104477Ssam if (bus_dmamap_create(sc->sc_dmat, BUS_DMA_NOWAIT, &cmd->dst_map)) { 1728104477Ssam hifnstats.hst_nomem_map++; 1729104477Ssam err = ENOMEM; 1730104477Ssam goto err_srcmap; 1731104477Ssam } 1732104477Ssam if (crp->crp_flags & CRYPTO_F_IMBUF) { 1733104477Ssam if (bus_dmamap_load_mbuf(sc->sc_dmat, cmd->dst_map, 1734104477Ssam cmd->dst_m, hifn_op_cb, &cmd->dst, BUS_DMA_NOWAIT)) { 1735104477Ssam hifnstats.hst_nomem_map++; 1736104477Ssam err = ENOMEM; 1737104477Ssam goto err_dstmap1; 1738104477Ssam } 1739104477Ssam } else if (crp->crp_flags & CRYPTO_F_IOV) { 1740104477Ssam if (bus_dmamap_load_uio(sc->sc_dmat, cmd->dst_map, 1741104477Ssam cmd->dst_io, hifn_op_cb, &cmd->dst, BUS_DMA_NOWAIT)) { 1742104477Ssam hifnstats.hst_nomem_load++; 1743104477Ssam err = ENOMEM; 1744104477Ssam goto err_dstmap1; 1745104477Ssam } 1746104477Ssam } 1747104477Ssam } 1748104477Ssam 1749104477Ssam#ifdef HIFN_DEBUG 1750104477Ssam if (hifn_debug) { 1751104477Ssam device_printf(sc->sc_dev, 1752104477Ssam "Entering cmd: stat %8x ien %8x u %d/%d/%d/%d n %d/%d\n", 1753104477Ssam READ_REG_1(sc, HIFN_1_DMA_CSR), 1754104477Ssam READ_REG_1(sc, HIFN_1_DMA_IER), 1755104477Ssam dma->cmdu, dma->srcu, dma->dstu, dma->resu, 1756104477Ssam cmd->src_nsegs, cmd->dst_nsegs); 1757104477Ssam } 1758104477Ssam#endif 1759104477Ssam 1760104477Ssam if (cmd->src_map == cmd->dst_map) { 1761104477Ssam bus_dmamap_sync(sc->sc_dmat, cmd->src_map, 1762104477Ssam BUS_DMASYNC_PREWRITE|BUS_DMASYNC_PREREAD); 1763104477Ssam } else { 1764104477Ssam bus_dmamap_sync(sc->sc_dmat, cmd->src_map, 1765104477Ssam BUS_DMASYNC_PREWRITE); 1766104477Ssam bus_dmamap_sync(sc->sc_dmat, cmd->dst_map, 1767104477Ssam BUS_DMASYNC_PREREAD); 1768104477Ssam } 1769104477Ssam 1770104477Ssam /* 1771104477Ssam * need N src, and N dst 1772104477Ssam */ 1773104477Ssam if ((dma->srcu + cmd->src_nsegs) > HIFN_D_SRC_RSIZE || 1774104477Ssam (dma->dstu + cmd->dst_nsegs + 1) > HIFN_D_DST_RSIZE) { 1775104477Ssam#ifdef HIFN_DEBUG 1776104477Ssam if (hifn_debug) { 1777104477Ssam device_printf(sc->sc_dev, 1778104477Ssam "src/dst exhaustion, srcu %u+%u dstu %u+%u\n", 1779104477Ssam dma->srcu, cmd->src_nsegs, 1780104477Ssam dma->dstu, cmd->dst_nsegs); 1781104477Ssam } 1782104477Ssam#endif 1783104477Ssam hifnstats.hst_nomem_sd++; 1784104477Ssam err = ERESTART; 1785104477Ssam goto err_dstmap; 1786104477Ssam } 1787104477Ssam 1788104477Ssam if (dma->cmdi == HIFN_D_CMD_RSIZE) { 1789104477Ssam dma->cmdi = 0; 1790104477Ssam dma->cmdr[HIFN_D_CMD_RSIZE].l = htole32(HIFN_D_VALID | 1791104477Ssam HIFN_D_JUMP | HIFN_D_MASKDONEIRQ); 1792104477Ssam HIFN_CMDR_SYNC(sc, HIFN_D_CMD_RSIZE, 1793104477Ssam BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); 1794104477Ssam } 1795104477Ssam cmdi = dma->cmdi++; 1796104477Ssam cmdlen = hifn_write_command(cmd, dma->command_bufs[cmdi]); 1797104477Ssam HIFN_CMD_SYNC(sc, cmdi, BUS_DMASYNC_PREWRITE); 1798104477Ssam 1799104477Ssam /* .p for command/result already set */ 1800104477Ssam dma->cmdr[cmdi].l = htole32(cmdlen | HIFN_D_VALID | HIFN_D_LAST | 1801104477Ssam HIFN_D_MASKDONEIRQ); 1802104477Ssam HIFN_CMDR_SYNC(sc, cmdi, 1803104477Ssam BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); 1804104477Ssam dma->cmdu++; 1805104477Ssam if (sc->sc_c_busy == 0) { 1806104477Ssam WRITE_REG_1(sc, HIFN_1_DMA_CSR, HIFN_DMACSR_C_CTRL_ENA); 1807104477Ssam sc->sc_c_busy = 1; 1808104477Ssam } 1809104477Ssam 1810104477Ssam /* 1811104477Ssam * We don't worry about missing an interrupt (which a "command wait" 1812104477Ssam * interrupt salvages us from), unless there is more than one command 1813104477Ssam * in the queue. 1814104477Ssam */ 1815104477Ssam if (dma->cmdu > 1) { 1816104477Ssam sc->sc_dmaier |= HIFN_DMAIER_C_WAIT; 1817104477Ssam WRITE_REG_1(sc, HIFN_1_DMA_IER, sc->sc_dmaier); 1818104477Ssam } 1819104477Ssam 1820104477Ssam hifnstats.hst_ipackets++; 1821104477Ssam hifnstats.hst_ibytes += cmd->src_mapsize; 1822104477Ssam 1823104477Ssam hifn_dmamap_load_src(sc, cmd); 1824104477Ssam if (sc->sc_s_busy == 0) { 1825104477Ssam WRITE_REG_1(sc, HIFN_1_DMA_CSR, HIFN_DMACSR_S_CTRL_ENA); 1826104477Ssam sc->sc_s_busy = 1; 1827104477Ssam } 1828104477Ssam 1829104477Ssam /* 1830104477Ssam * Unlike other descriptors, we don't mask done interrupt from 1831104477Ssam * result descriptor. 1832104477Ssam */ 1833104477Ssam#ifdef HIFN_DEBUG 1834104477Ssam if (hifn_debug) 1835104477Ssam printf("load res\n"); 1836104477Ssam#endif 1837104477Ssam if (dma->resi == HIFN_D_RES_RSIZE) { 1838104477Ssam dma->resi = 0; 1839104477Ssam dma->resr[HIFN_D_RES_RSIZE].l = htole32(HIFN_D_VALID | 1840104477Ssam HIFN_D_JUMP | HIFN_D_MASKDONEIRQ); 1841104477Ssam HIFN_RESR_SYNC(sc, HIFN_D_RES_RSIZE, 1842104477Ssam BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1843104477Ssam } 1844104477Ssam resi = dma->resi++; 1845104477Ssam KASSERT(dma->hifn_commands[resi] == NULL, 1846104477Ssam ("hifn_crypto: command slot %u busy", resi)); 1847104477Ssam dma->hifn_commands[resi] = cmd; 1848104477Ssam HIFN_RES_SYNC(sc, resi, BUS_DMASYNC_PREREAD); 1849104477Ssam if ((hint & CRYPTO_HINT_MORE) && sc->sc_curbatch < hifn_maxbatch) { 1850104477Ssam dma->resr[resi].l = htole32(HIFN_MAX_RESULT | 1851104477Ssam HIFN_D_VALID | HIFN_D_LAST | HIFN_D_MASKDONEIRQ); 1852104477Ssam sc->sc_curbatch++; 1853104477Ssam if (sc->sc_curbatch > hifnstats.hst_maxbatch) 1854104477Ssam hifnstats.hst_maxbatch = sc->sc_curbatch; 1855104477Ssam hifnstats.hst_totbatch++; 1856104477Ssam } else { 1857104477Ssam dma->resr[resi].l = htole32(HIFN_MAX_RESULT | 1858104477Ssam HIFN_D_VALID | HIFN_D_LAST); 1859104477Ssam sc->sc_curbatch = 0; 1860104477Ssam } 1861104477Ssam HIFN_RESR_SYNC(sc, resi, 1862104477Ssam BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1863104477Ssam dma->resu++; 1864104477Ssam if (sc->sc_r_busy == 0) { 1865104477Ssam WRITE_REG_1(sc, HIFN_1_DMA_CSR, HIFN_DMACSR_R_CTRL_ENA); 1866104477Ssam sc->sc_r_busy = 1; 1867104477Ssam } 1868104477Ssam 1869104477Ssam if (cmd->sloplen) 1870104477Ssam cmd->slopidx = resi; 1871104477Ssam 1872104477Ssam hifn_dmamap_load_dst(sc, cmd); 1873104477Ssam 1874104477Ssam if (sc->sc_d_busy == 0) { 1875104477Ssam WRITE_REG_1(sc, HIFN_1_DMA_CSR, HIFN_DMACSR_D_CTRL_ENA); 1876104477Ssam sc->sc_d_busy = 1; 1877104477Ssam } 1878104477Ssam 1879104477Ssam#ifdef HIFN_DEBUG 1880104477Ssam if (hifn_debug) { 1881104477Ssam device_printf(sc->sc_dev, "command: stat %8x ier %8x\n", 1882104477Ssam READ_REG_1(sc, HIFN_1_DMA_CSR), 1883104477Ssam READ_REG_1(sc, HIFN_1_DMA_IER)); 1884104477Ssam } 1885104477Ssam#endif 1886104477Ssam 1887104477Ssam sc->sc_active = 5; 1888104477Ssam KASSERT(err == 0, ("hifn_crypto: success with error %u", err)); 1889104477Ssam return (err); /* success */ 1890104477Ssam 1891104477Ssamerr_dstmap: 1892104477Ssam if (cmd->src_map != cmd->dst_map) 1893104477Ssam bus_dmamap_unload(sc->sc_dmat, cmd->dst_map); 1894104477Ssamerr_dstmap1: 1895104477Ssam if (cmd->src_map != cmd->dst_map) 1896104477Ssam bus_dmamap_destroy(sc->sc_dmat, cmd->dst_map); 1897104477Ssamerr_srcmap: 1898104477Ssam if (crp->crp_flags & CRYPTO_F_IMBUF) { 1899104477Ssam if (cmd->src_m != cmd->dst_m) 1900104477Ssam m_freem(cmd->dst_m); 1901104477Ssam } 1902104477Ssam bus_dmamap_unload(sc->sc_dmat, cmd->src_map); 1903104477Ssamerr_srcmap1: 1904104477Ssam bus_dmamap_destroy(sc->sc_dmat, cmd->src_map); 1905104477Ssam return (err); 1906104477Ssam} 1907104477Ssam 1908104477Ssamstatic void 1909104477Ssamhifn_tick(void* vsc) 1910104477Ssam{ 1911104477Ssam struct hifn_softc *sc = vsc; 1912104477Ssam 1913104477Ssam HIFN_LOCK(sc); 1914104477Ssam if (sc->sc_active == 0) { 1915104477Ssam struct hifn_dma *dma = sc->sc_dma; 1916104477Ssam u_int32_t r = 0; 1917104477Ssam 1918104477Ssam if (dma->cmdu == 0 && sc->sc_c_busy) { 1919104477Ssam sc->sc_c_busy = 0; 1920104477Ssam r |= HIFN_DMACSR_C_CTRL_DIS; 1921104477Ssam } 1922104477Ssam if (dma->srcu == 0 && sc->sc_s_busy) { 1923104477Ssam sc->sc_s_busy = 0; 1924104477Ssam r |= HIFN_DMACSR_S_CTRL_DIS; 1925104477Ssam } 1926104477Ssam if (dma->dstu == 0 && sc->sc_d_busy) { 1927104477Ssam sc->sc_d_busy = 0; 1928104477Ssam r |= HIFN_DMACSR_D_CTRL_DIS; 1929104477Ssam } 1930104477Ssam if (dma->resu == 0 && sc->sc_r_busy) { 1931104477Ssam sc->sc_r_busy = 0; 1932104477Ssam r |= HIFN_DMACSR_R_CTRL_DIS; 1933104477Ssam } 1934104477Ssam if (r) 1935104477Ssam WRITE_REG_1(sc, HIFN_1_DMA_CSR, r); 1936104477Ssam } else 1937104477Ssam sc->sc_active--; 1938104477Ssam HIFN_UNLOCK(sc); 1939104477Ssam callout_reset(&sc->sc_tickto, hz, hifn_tick, sc); 1940104477Ssam} 1941104477Ssam 1942104477Ssamstatic void 1943104477Ssamhifn_intr(void *arg) 1944104477Ssam{ 1945104477Ssam struct hifn_softc *sc = arg; 1946104477Ssam struct hifn_dma *dma; 1947104477Ssam u_int32_t dmacsr, restart; 1948104477Ssam int i, u; 1949104477Ssam 1950104477Ssam HIFN_LOCK(sc); 1951104477Ssam dma = sc->sc_dma; 1952104477Ssam 1953104477Ssam dmacsr = READ_REG_1(sc, HIFN_1_DMA_CSR); 1954104477Ssam 1955104477Ssam#ifdef HIFN_DEBUG 1956104477Ssam if (hifn_debug) { 1957104477Ssam device_printf(sc->sc_dev, 1958104477Ssam "irq: stat %08x ien %08x damier %08x i %d/%d/%d/%d k %d/%d/%d/%d u %d/%d/%d/%d\n", 1959104477Ssam dmacsr, READ_REG_1(sc, HIFN_1_DMA_IER), sc->sc_dmaier, 1960104477Ssam dma->cmdi, dma->srci, dma->dsti, dma->resi, 1961104477Ssam dma->cmdk, dma->srck, dma->dstk, dma->resk, 1962104477Ssam dma->cmdu, dma->srcu, dma->dstu, dma->resu); 1963104477Ssam } 1964104477Ssam#endif 1965104477Ssam 1966104477Ssam /* Nothing in the DMA unit interrupted */ 1967104477Ssam if ((dmacsr & sc->sc_dmaier) == 0) { 1968104477Ssam hifnstats.hst_noirq++; 1969104477Ssam HIFN_UNLOCK(sc); 1970104477Ssam return; 1971104477Ssam } 1972104477Ssam 1973104477Ssam WRITE_REG_1(sc, HIFN_1_DMA_CSR, dmacsr & sc->sc_dmaier); 1974104477Ssam 1975104477Ssam if ((sc->sc_flags & HIFN_HAS_PUBLIC) && 1976104477Ssam (dmacsr & HIFN_DMACSR_PUBDONE)) 1977104477Ssam WRITE_REG_1(sc, HIFN_1_PUB_STATUS, 1978104477Ssam READ_REG_1(sc, HIFN_1_PUB_STATUS) | HIFN_PUBSTS_DONE); 1979104477Ssam 1980104477Ssam restart = dmacsr & (HIFN_DMACSR_D_OVER | HIFN_DMACSR_R_OVER); 1981104477Ssam if (restart) 1982104477Ssam device_printf(sc->sc_dev, "overrun %x\n", dmacsr); 1983104477Ssam 1984104477Ssam if (sc->sc_flags & HIFN_IS_7811) { 1985104477Ssam if (dmacsr & HIFN_DMACSR_ILLR) 1986104477Ssam device_printf(sc->sc_dev, "illegal read\n"); 1987104477Ssam if (dmacsr & HIFN_DMACSR_ILLW) 1988104477Ssam device_printf(sc->sc_dev, "illegal write\n"); 1989104477Ssam } 1990104477Ssam 1991104477Ssam restart = dmacsr & (HIFN_DMACSR_C_ABORT | HIFN_DMACSR_S_ABORT | 1992104477Ssam HIFN_DMACSR_D_ABORT | HIFN_DMACSR_R_ABORT); 1993104477Ssam if (restart) { 1994104477Ssam device_printf(sc->sc_dev, "abort, resetting.\n"); 1995104477Ssam hifnstats.hst_abort++; 1996104477Ssam hifn_abort(sc); 1997104477Ssam HIFN_UNLOCK(sc); 1998104477Ssam return; 1999104477Ssam } 2000104477Ssam 2001104477Ssam if ((dmacsr & HIFN_DMACSR_C_WAIT) && (dma->cmdu == 0)) { 2002104477Ssam /* 2003104477Ssam * If no slots to process and we receive a "waiting on 2004104477Ssam * command" interrupt, we disable the "waiting on command" 2005104477Ssam * (by clearing it). 2006104477Ssam */ 2007104477Ssam sc->sc_dmaier &= ~HIFN_DMAIER_C_WAIT; 2008104477Ssam WRITE_REG_1(sc, HIFN_1_DMA_IER, sc->sc_dmaier); 2009104477Ssam } 2010104477Ssam 2011104477Ssam /* clear the rings */ 2012104477Ssam i = dma->resk; u = dma->resu; 2013104477Ssam while (u != 0) { 2014104477Ssam HIFN_RESR_SYNC(sc, i, 2015104477Ssam BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 2016104477Ssam if (dma->resr[i].l & htole32(HIFN_D_VALID)) { 2017104477Ssam HIFN_RESR_SYNC(sc, i, 2018104477Ssam BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 2019104477Ssam break; 2020104477Ssam } 2021104477Ssam 2022104477Ssam if (i != HIFN_D_RES_RSIZE) { 2023104477Ssam struct hifn_command *cmd; 2024104477Ssam u_int8_t *macbuf = NULL; 2025104477Ssam 2026104477Ssam HIFN_RES_SYNC(sc, i, BUS_DMASYNC_POSTREAD); 2027104477Ssam cmd = dma->hifn_commands[i]; 2028104477Ssam KASSERT(cmd != NULL, 2029104477Ssam ("hifn_intr: null command slot %u", i)); 2030104477Ssam dma->hifn_commands[i] = NULL; 2031104477Ssam 2032104477Ssam if (cmd->base_masks & HIFN_BASE_CMD_MAC) { 2033104477Ssam macbuf = dma->result_bufs[i]; 2034104477Ssam macbuf += 12; 2035104477Ssam } 2036104477Ssam 2037104477Ssam hifn_callback(sc, cmd, macbuf); 2038104477Ssam hifnstats.hst_opackets++; 2039104477Ssam u--; 2040104477Ssam } 2041104477Ssam 2042104477Ssam if (++i == (HIFN_D_RES_RSIZE + 1)) 2043104477Ssam i = 0; 2044104477Ssam } 2045104477Ssam dma->resk = i; dma->resu = u; 2046104477Ssam 2047104477Ssam i = dma->srck; u = dma->srcu; 2048104477Ssam while (u != 0) { 2049104477Ssam if (i == HIFN_D_SRC_RSIZE) 2050104477Ssam i = 0; 2051104477Ssam HIFN_SRCR_SYNC(sc, i, 2052104477Ssam BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 2053104477Ssam if (dma->srcr[i].l & htole32(HIFN_D_VALID)) { 2054104477Ssam HIFN_SRCR_SYNC(sc, i, 2055104477Ssam BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 2056104477Ssam break; 2057104477Ssam } 2058104477Ssam i++, u--; 2059104477Ssam } 2060104477Ssam dma->srck = i; dma->srcu = u; 2061104477Ssam 2062104477Ssam i = dma->cmdk; u = dma->cmdu; 2063104477Ssam while (u != 0) { 2064104477Ssam HIFN_CMDR_SYNC(sc, i, 2065104477Ssam BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 2066104477Ssam if (dma->cmdr[i].l & htole32(HIFN_D_VALID)) { 2067104477Ssam HIFN_CMDR_SYNC(sc, i, 2068104477Ssam BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 2069104477Ssam break; 2070104477Ssam } 2071104477Ssam if (i != HIFN_D_CMD_RSIZE) { 2072104477Ssam u--; 2073104477Ssam HIFN_CMD_SYNC(sc, i, BUS_DMASYNC_POSTWRITE); 2074104477Ssam } 2075104477Ssam if (++i == (HIFN_D_CMD_RSIZE + 1)) 2076104477Ssam i = 0; 2077104477Ssam } 2078104477Ssam dma->cmdk = i; dma->cmdu = u; 2079104477Ssam 2080104477Ssam if (sc->sc_needwakeup) { /* XXX check high watermark */ 2081104477Ssam int wakeup = sc->sc_needwakeup & (CRYPTO_SYMQ|CRYPTO_ASYMQ); 2082104477Ssam#ifdef HIFN_DEBUG 2083104477Ssam if (hifn_debug) 2084104477Ssam device_printf(sc->sc_dev, 2085104477Ssam "wakeup crypto (%x) u %d/%d/%d/%d\n", 2086104477Ssam sc->sc_needwakeup, 2087104477Ssam dma->cmdu, dma->srcu, dma->dstu, dma->resu); 2088104477Ssam#endif 2089104477Ssam sc->sc_needwakeup &= ~wakeup; 2090104477Ssam crypto_unblock(sc->sc_cid, wakeup); 2091104477Ssam } 2092104477Ssam HIFN_UNLOCK(sc); 2093104477Ssam} 2094104477Ssam 2095104477Ssam/* 2096104477Ssam * Allocate a new 'session' and return an encoded session id. 'sidp' 2097104477Ssam * contains our registration id, and should contain an encoded session 2098104477Ssam * id on successful allocation. 2099104477Ssam */ 2100104477Ssamstatic int 2101104477Ssamhifn_newsession(void *arg, u_int32_t *sidp, struct cryptoini *cri) 2102104477Ssam{ 2103104477Ssam struct cryptoini *c; 2104104477Ssam struct hifn_softc *sc = arg; 2105104477Ssam int i, mac = 0, cry = 0; 2106104477Ssam 2107104477Ssam KASSERT(sc != NULL, ("hifn_newsession: null softc")); 2108104477Ssam if (sidp == NULL || cri == NULL || sc == NULL) 2109104477Ssam return (EINVAL); 2110104477Ssam 2111104477Ssam for (i = 0; i < sc->sc_maxses; i++) 2112104477Ssam if (sc->sc_sessions[i].hs_state == HS_STATE_FREE) 2113104477Ssam break; 2114104477Ssam if (i == sc->sc_maxses) 2115104477Ssam return (ENOMEM); 2116104477Ssam 2117104477Ssam for (c = cri; c != NULL; c = c->cri_next) { 2118104477Ssam switch (c->cri_alg) { 2119104477Ssam case CRYPTO_MD5: 2120104477Ssam case CRYPTO_SHA1: 2121104477Ssam case CRYPTO_MD5_HMAC: 2122104477Ssam case CRYPTO_SHA1_HMAC: 2123104477Ssam if (mac) 2124104477Ssam return (EINVAL); 2125104477Ssam mac = 1; 2126104477Ssam break; 2127104477Ssam case CRYPTO_DES_CBC: 2128104477Ssam case CRYPTO_3DES_CBC: 2129104477Ssam /* XXX this may read fewer, does it matter? */ 2130104477Ssam read_random(sc->sc_sessions[i].hs_iv, HIFN_IV_LENGTH); 2131104477Ssam /*FALLTHROUGH*/ 2132104477Ssam case CRYPTO_ARC4: 2133104477Ssam if (cry) 2134104477Ssam return (EINVAL); 2135104477Ssam cry = 1; 2136104477Ssam break; 2137104477Ssam default: 2138104477Ssam return (EINVAL); 2139104477Ssam } 2140104477Ssam } 2141104477Ssam if (mac == 0 && cry == 0) 2142104477Ssam return (EINVAL); 2143104477Ssam 2144104477Ssam *sidp = HIFN_SID(device_get_unit(sc->sc_dev), i); 2145104477Ssam sc->sc_sessions[i].hs_state = HS_STATE_USED; 2146104477Ssam 2147104477Ssam return (0); 2148104477Ssam} 2149104477Ssam 2150104477Ssam/* 2151104477Ssam * Deallocate a session. 2152104477Ssam * XXX this routine should run a zero'd mac/encrypt key into context ram. 2153104477Ssam * XXX to blow away any keys already stored there. 2154104477Ssam */ 2155104477Ssamstatic int 2156104477Ssamhifn_freesession(void *arg, u_int64_t tid) 2157104477Ssam{ 2158104477Ssam struct hifn_softc *sc = arg; 2159104477Ssam int session; 2160104477Ssam u_int32_t sid = ((u_int32_t) tid) & 0xffffffff; 2161104477Ssam 2162104477Ssam KASSERT(sc != NULL, ("hifn_freesession: null softc")); 2163104477Ssam if (sc == NULL) 2164104477Ssam return (EINVAL); 2165104477Ssam 2166104477Ssam session = HIFN_SESSION(sid); 2167104477Ssam if (session >= sc->sc_maxses) 2168104477Ssam return (EINVAL); 2169104477Ssam 2170104477Ssam bzero(&sc->sc_sessions[session], sizeof(sc->sc_sessions[session])); 2171104477Ssam return (0); 2172104477Ssam} 2173104477Ssam 2174104477Ssamstatic int 2175104477Ssamhifn_process(void *arg, struct cryptop *crp, int hint) 2176104477Ssam{ 2177104477Ssam struct hifn_softc *sc = arg; 2178104477Ssam struct hifn_command *cmd = NULL; 2179104477Ssam int session, err; 2180104477Ssam struct cryptodesc *crd1, *crd2, *maccrd, *enccrd; 2181104477Ssam 2182104477Ssam if (crp == NULL || crp->crp_callback == NULL) { 2183104477Ssam hifnstats.hst_invalid++; 2184104477Ssam return (EINVAL); 2185104477Ssam } 2186104477Ssam session = HIFN_SESSION(crp->crp_sid); 2187104477Ssam 2188104477Ssam if (sc == NULL || session >= sc->sc_maxses) { 2189104477Ssam err = EINVAL; 2190104477Ssam goto errout; 2191104477Ssam } 2192104477Ssam 2193104477Ssam cmd = malloc(sizeof(struct hifn_command), M_DEVBUF, M_NOWAIT | M_ZERO); 2194104477Ssam if (cmd == NULL) { 2195104477Ssam hifnstats.hst_nomem++; 2196104477Ssam err = ENOMEM; 2197104477Ssam goto errout; 2198104477Ssam } 2199104477Ssam 2200104477Ssam if (crp->crp_flags & CRYPTO_F_IMBUF) { 2201104477Ssam cmd->src_m = (struct mbuf *)crp->crp_buf; 2202104477Ssam cmd->dst_m = (struct mbuf *)crp->crp_buf; 2203104477Ssam } else if (crp->crp_flags & CRYPTO_F_IOV) { 2204104477Ssam cmd->src_io = (struct uio *)crp->crp_buf; 2205104477Ssam cmd->dst_io = (struct uio *)crp->crp_buf; 2206104477Ssam } else { 2207104477Ssam err = EINVAL; 2208104477Ssam goto errout; /* XXX we don't handle contiguous buffers! */ 2209104477Ssam } 2210104477Ssam 2211104477Ssam crd1 = crp->crp_desc; 2212104477Ssam if (crd1 == NULL) { 2213104477Ssam err = EINVAL; 2214104477Ssam goto errout; 2215104477Ssam } 2216104477Ssam crd2 = crd1->crd_next; 2217104477Ssam 2218104477Ssam if (crd2 == NULL) { 2219104477Ssam if (crd1->crd_alg == CRYPTO_MD5_HMAC || 2220104477Ssam crd1->crd_alg == CRYPTO_SHA1_HMAC || 2221104477Ssam crd1->crd_alg == CRYPTO_SHA1 || 2222104477Ssam crd1->crd_alg == CRYPTO_MD5) { 2223104477Ssam maccrd = crd1; 2224104477Ssam enccrd = NULL; 2225104477Ssam } else if (crd1->crd_alg == CRYPTO_DES_CBC || 2226104477Ssam crd1->crd_alg == CRYPTO_3DES_CBC || 2227104477Ssam crd1->crd_alg == CRYPTO_ARC4) { 2228104477Ssam if ((crd1->crd_flags & CRD_F_ENCRYPT) == 0) 2229104477Ssam cmd->base_masks |= HIFN_BASE_CMD_DECODE; 2230104477Ssam maccrd = NULL; 2231104477Ssam enccrd = crd1; 2232104477Ssam } else { 2233104477Ssam err = EINVAL; 2234104477Ssam goto errout; 2235104477Ssam } 2236104477Ssam } else { 2237104477Ssam if ((crd1->crd_alg == CRYPTO_MD5_HMAC || 2238104477Ssam crd1->crd_alg == CRYPTO_SHA1_HMAC || 2239104477Ssam crd1->crd_alg == CRYPTO_MD5 || 2240104477Ssam crd1->crd_alg == CRYPTO_SHA1) && 2241104477Ssam (crd2->crd_alg == CRYPTO_DES_CBC || 2242104477Ssam crd2->crd_alg == CRYPTO_3DES_CBC || 2243104477Ssam crd2->crd_alg == CRYPTO_ARC4) && 2244104477Ssam ((crd2->crd_flags & CRD_F_ENCRYPT) == 0)) { 2245104477Ssam cmd->base_masks = HIFN_BASE_CMD_DECODE; 2246104477Ssam maccrd = crd1; 2247104477Ssam enccrd = crd2; 2248104477Ssam } else if ((crd1->crd_alg == CRYPTO_DES_CBC || 2249104477Ssam crd1->crd_alg == CRYPTO_ARC4 || 2250104477Ssam crd1->crd_alg == CRYPTO_3DES_CBC) && 2251104477Ssam (crd2->crd_alg == CRYPTO_MD5_HMAC || 2252104477Ssam crd2->crd_alg == CRYPTO_SHA1_HMAC || 2253104477Ssam crd2->crd_alg == CRYPTO_MD5 || 2254104477Ssam crd2->crd_alg == CRYPTO_SHA1) && 2255104477Ssam (crd1->crd_flags & CRD_F_ENCRYPT)) { 2256104477Ssam enccrd = crd1; 2257104477Ssam maccrd = crd2; 2258104477Ssam } else { 2259104477Ssam /* 2260104477Ssam * We cannot order the 7751 as requested 2261104477Ssam */ 2262104477Ssam err = EINVAL; 2263104477Ssam goto errout; 2264104477Ssam } 2265104477Ssam } 2266104477Ssam 2267104477Ssam if (enccrd) { 2268104477Ssam cmd->enccrd = enccrd; 2269104477Ssam cmd->base_masks |= HIFN_BASE_CMD_CRYPT; 2270104477Ssam switch (enccrd->crd_alg) { 2271104477Ssam case CRYPTO_ARC4: 2272104477Ssam cmd->cry_masks |= HIFN_CRYPT_CMD_ALG_RC4; 2273104477Ssam if ((enccrd->crd_flags & CRD_F_ENCRYPT) 2274104477Ssam != sc->sc_sessions[session].hs_prev_op) 2275104477Ssam sc->sc_sessions[session].hs_state = 2276104477Ssam HS_STATE_USED; 2277104477Ssam break; 2278104477Ssam case CRYPTO_DES_CBC: 2279104477Ssam cmd->cry_masks |= HIFN_CRYPT_CMD_ALG_DES | 2280104477Ssam HIFN_CRYPT_CMD_MODE_CBC | 2281104477Ssam HIFN_CRYPT_CMD_NEW_IV; 2282104477Ssam break; 2283104477Ssam case CRYPTO_3DES_CBC: 2284104477Ssam cmd->cry_masks |= HIFN_CRYPT_CMD_ALG_3DES | 2285104477Ssam HIFN_CRYPT_CMD_MODE_CBC | 2286104477Ssam HIFN_CRYPT_CMD_NEW_IV; 2287104477Ssam break; 2288104477Ssam default: 2289104477Ssam err = EINVAL; 2290104477Ssam goto errout; 2291104477Ssam } 2292104477Ssam if (enccrd->crd_alg != CRYPTO_ARC4) { 2293104477Ssam if (enccrd->crd_flags & CRD_F_ENCRYPT) { 2294104477Ssam if (enccrd->crd_flags & CRD_F_IV_EXPLICIT) 2295104477Ssam bcopy(enccrd->crd_iv, cmd->iv, 2296104477Ssam HIFN_IV_LENGTH); 2297104477Ssam else 2298104477Ssam bcopy(sc->sc_sessions[session].hs_iv, 2299104477Ssam cmd->iv, HIFN_IV_LENGTH); 2300104477Ssam 2301104477Ssam if ((enccrd->crd_flags & CRD_F_IV_PRESENT) 2302104477Ssam == 0) { 2303104477Ssam if (crp->crp_flags & CRYPTO_F_IMBUF) 2304104477Ssam m_copyback(cmd->src_m, 2305104477Ssam enccrd->crd_inject, 2306104477Ssam HIFN_IV_LENGTH, cmd->iv); 2307104477Ssam else if (crp->crp_flags & CRYPTO_F_IOV) 2308104477Ssam cuio_copyback(cmd->src_io, 2309104477Ssam enccrd->crd_inject, 2310104477Ssam HIFN_IV_LENGTH, cmd->iv); 2311104477Ssam } 2312104477Ssam } else { 2313104477Ssam if (enccrd->crd_flags & CRD_F_IV_EXPLICIT) 2314104477Ssam bcopy(enccrd->crd_iv, cmd->iv, 2315104477Ssam HIFN_IV_LENGTH); 2316104477Ssam else if (crp->crp_flags & CRYPTO_F_IMBUF) 2317104477Ssam m_copydata(cmd->src_m, 2318104477Ssam enccrd->crd_inject, 2319104477Ssam HIFN_IV_LENGTH, cmd->iv); 2320104477Ssam else if (crp->crp_flags & CRYPTO_F_IOV) 2321104477Ssam cuio_copydata(cmd->src_io, 2322104477Ssam enccrd->crd_inject, 2323104477Ssam HIFN_IV_LENGTH, cmd->iv); 2324104477Ssam } 2325104477Ssam } 2326104477Ssam 2327104477Ssam cmd->ck = enccrd->crd_key; 2328104477Ssam cmd->cklen = enccrd->crd_klen >> 3; 2329104477Ssam 2330104477Ssam if (sc->sc_sessions[session].hs_state == HS_STATE_USED) 2331104477Ssam cmd->cry_masks |= HIFN_CRYPT_CMD_NEW_KEY; 2332104477Ssam } 2333104477Ssam 2334104477Ssam if (maccrd) { 2335104477Ssam cmd->maccrd = maccrd; 2336104477Ssam cmd->base_masks |= HIFN_BASE_CMD_MAC; 2337104477Ssam 2338104477Ssam switch (maccrd->crd_alg) { 2339104477Ssam case CRYPTO_MD5: 2340104477Ssam cmd->mac_masks |= HIFN_MAC_CMD_ALG_MD5 | 2341104477Ssam HIFN_MAC_CMD_RESULT | HIFN_MAC_CMD_MODE_HASH | 2342104477Ssam HIFN_MAC_CMD_POS_IPSEC; 2343104477Ssam break; 2344104477Ssam case CRYPTO_MD5_HMAC: 2345104477Ssam cmd->mac_masks |= HIFN_MAC_CMD_ALG_MD5 | 2346104477Ssam HIFN_MAC_CMD_RESULT | HIFN_MAC_CMD_MODE_HMAC | 2347104477Ssam HIFN_MAC_CMD_POS_IPSEC | HIFN_MAC_CMD_TRUNC; 2348104477Ssam break; 2349104477Ssam case CRYPTO_SHA1: 2350104477Ssam cmd->mac_masks |= HIFN_MAC_CMD_ALG_SHA1 | 2351104477Ssam HIFN_MAC_CMD_RESULT | HIFN_MAC_CMD_MODE_HASH | 2352104477Ssam HIFN_MAC_CMD_POS_IPSEC; 2353104477Ssam break; 2354104477Ssam case CRYPTO_SHA1_HMAC: 2355104477Ssam cmd->mac_masks |= HIFN_MAC_CMD_ALG_SHA1 | 2356104477Ssam HIFN_MAC_CMD_RESULT | HIFN_MAC_CMD_MODE_HMAC | 2357104477Ssam HIFN_MAC_CMD_POS_IPSEC | HIFN_MAC_CMD_TRUNC; 2358104477Ssam break; 2359104477Ssam } 2360104477Ssam 2361104477Ssam if ((maccrd->crd_alg == CRYPTO_SHA1_HMAC || 2362104477Ssam maccrd->crd_alg == CRYPTO_MD5_HMAC) && 2363104477Ssam sc->sc_sessions[session].hs_state == HS_STATE_USED) { 2364104477Ssam cmd->mac_masks |= HIFN_MAC_CMD_NEW_KEY; 2365104477Ssam bcopy(maccrd->crd_key, cmd->mac, maccrd->crd_klen >> 3); 2366104477Ssam bzero(cmd->mac + (maccrd->crd_klen >> 3), 2367104477Ssam HIFN_MAC_KEY_LENGTH - (maccrd->crd_klen >> 3)); 2368104477Ssam } 2369104477Ssam } 2370104477Ssam 2371104477Ssam cmd->crp = crp; 2372104477Ssam cmd->session_num = session; 2373104477Ssam cmd->softc = sc; 2374104477Ssam 2375104477Ssam err = hifn_crypto(sc, cmd, crp, hint); 2376104477Ssam if (!err) { 2377104477Ssam if (enccrd) 2378104477Ssam sc->sc_sessions[session].hs_prev_op = 2379104477Ssam enccrd->crd_flags & CRD_F_ENCRYPT; 2380104477Ssam if (sc->sc_sessions[session].hs_state == HS_STATE_USED) 2381104477Ssam sc->sc_sessions[session].hs_state = HS_STATE_KEY; 2382104477Ssam return 0; 2383104477Ssam } else if (err == ERESTART) { 2384104477Ssam /* 2385104477Ssam * There weren't enough resources to dispatch the request 2386104477Ssam * to the part. Notify the caller so they'll requeue this 2387104477Ssam * request and resubmit it again soon. 2388104477Ssam */ 2389104477Ssam#ifdef HIFN_DEBUG 2390104477Ssam if (hifn_debug) 2391104477Ssam device_printf(sc->sc_dev, "requeue request\n"); 2392104477Ssam#endif 2393104477Ssam free(cmd, M_DEVBUF); 2394104477Ssam sc->sc_needwakeup |= CRYPTO_SYMQ; 2395104477Ssam return (err); 2396104477Ssam } 2397104477Ssam 2398104477Ssamerrout: 2399104477Ssam if (cmd != NULL) 2400104477Ssam free(cmd, M_DEVBUF); 2401104477Ssam if (err == EINVAL) 2402104477Ssam hifnstats.hst_invalid++; 2403104477Ssam else 2404104477Ssam hifnstats.hst_nomem++; 2405104477Ssam crp->crp_etype = err; 2406104477Ssam crypto_done(crp); 2407104477Ssam return (err); 2408104477Ssam} 2409104477Ssam 2410104477Ssamstatic void 2411104477Ssamhifn_abort(struct hifn_softc *sc) 2412104477Ssam{ 2413104477Ssam struct hifn_dma *dma = sc->sc_dma; 2414104477Ssam struct hifn_command *cmd; 2415104477Ssam struct cryptop *crp; 2416104477Ssam int i, u; 2417104477Ssam 2418104477Ssam i = dma->resk; u = dma->resu; 2419104477Ssam while (u != 0) { 2420104477Ssam cmd = dma->hifn_commands[i]; 2421104477Ssam KASSERT(cmd != NULL, ("hifn_abort: null command slot %u", i)); 2422104477Ssam dma->hifn_commands[i] = NULL; 2423104477Ssam crp = cmd->crp; 2424104477Ssam 2425104477Ssam if ((dma->resr[i].l & htole32(HIFN_D_VALID)) == 0) { 2426104477Ssam /* Salvage what we can. */ 2427104477Ssam u_int8_t *macbuf; 2428104477Ssam 2429104477Ssam if (cmd->base_masks & HIFN_BASE_CMD_MAC) { 2430104477Ssam macbuf = dma->result_bufs[i]; 2431104477Ssam macbuf += 12; 2432104477Ssam } else 2433104477Ssam macbuf = NULL; 2434104477Ssam hifnstats.hst_opackets++; 2435104477Ssam hifn_callback(sc, cmd, macbuf); 2436104477Ssam } else { 2437104477Ssam if (cmd->src_map == cmd->dst_map) { 2438104477Ssam bus_dmamap_sync(sc->sc_dmat, cmd->src_map, 2439104477Ssam BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); 2440104477Ssam } else { 2441104477Ssam bus_dmamap_sync(sc->sc_dmat, cmd->src_map, 2442104477Ssam BUS_DMASYNC_POSTWRITE); 2443104477Ssam bus_dmamap_sync(sc->sc_dmat, cmd->dst_map, 2444104477Ssam BUS_DMASYNC_POSTREAD); 2445104477Ssam } 2446104477Ssam 2447104477Ssam if (cmd->src_m != cmd->dst_m) { 2448104477Ssam m_freem(cmd->src_m); 2449104477Ssam crp->crp_buf = (caddr_t)cmd->dst_m; 2450104477Ssam } 2451104477Ssam 2452104477Ssam /* non-shared buffers cannot be restarted */ 2453104477Ssam if (cmd->src_map != cmd->dst_map) { 2454104477Ssam /* 2455104477Ssam * XXX should be EAGAIN, delayed until 2456104477Ssam * after the reset. 2457104477Ssam */ 2458104477Ssam crp->crp_etype = ENOMEM; 2459104477Ssam bus_dmamap_unload(sc->sc_dmat, cmd->dst_map); 2460104477Ssam bus_dmamap_destroy(sc->sc_dmat, cmd->dst_map); 2461104477Ssam } else 2462104477Ssam crp->crp_etype = ENOMEM; 2463104477Ssam 2464104477Ssam bus_dmamap_unload(sc->sc_dmat, cmd->src_map); 2465104477Ssam bus_dmamap_destroy(sc->sc_dmat, cmd->src_map); 2466104477Ssam 2467104477Ssam free(cmd, M_DEVBUF); 2468104477Ssam if (crp->crp_etype != EAGAIN) 2469104477Ssam crypto_done(crp); 2470104477Ssam } 2471104477Ssam 2472104477Ssam if (++i == HIFN_D_RES_RSIZE) 2473104477Ssam i = 0; 2474104477Ssam u--; 2475104477Ssam } 2476104477Ssam dma->resk = i; dma->resu = u; 2477104477Ssam 2478104477Ssam /* Force upload of key next time */ 2479104477Ssam for (i = 0; i < sc->sc_maxses; i++) 2480104477Ssam if (sc->sc_sessions[i].hs_state == HS_STATE_KEY) 2481104477Ssam sc->sc_sessions[i].hs_state = HS_STATE_USED; 2482104477Ssam 2483104477Ssam hifn_reset_board(sc, 1); 2484104477Ssam hifn_init_dma(sc); 2485104477Ssam hifn_init_pci_registers(sc); 2486104477Ssam} 2487104477Ssam 2488104477Ssamstatic void 2489104477Ssamhifn_callback(struct hifn_softc *sc, struct hifn_command *cmd, u_int8_t *macbuf) 2490104477Ssam{ 2491104477Ssam struct hifn_dma *dma = sc->sc_dma; 2492104477Ssam struct cryptop *crp = cmd->crp; 2493104477Ssam struct cryptodesc *crd; 2494104477Ssam struct mbuf *m; 2495104477Ssam int totlen, i, u; 2496104477Ssam 2497104477Ssam if (cmd->src_map == cmd->dst_map) { 2498104477Ssam bus_dmamap_sync(sc->sc_dmat, cmd->src_map, 2499104477Ssam BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); 2500104477Ssam } else { 2501104477Ssam bus_dmamap_sync(sc->sc_dmat, cmd->src_map, 2502104477Ssam BUS_DMASYNC_POSTWRITE); 2503104477Ssam bus_dmamap_sync(sc->sc_dmat, cmd->dst_map, 2504104477Ssam BUS_DMASYNC_POSTREAD); 2505104477Ssam } 2506104477Ssam 2507104477Ssam if (crp->crp_flags & CRYPTO_F_IMBUF) { 2508104477Ssam if (cmd->src_m != cmd->dst_m) { 2509104477Ssam crp->crp_buf = (caddr_t)cmd->dst_m; 2510104477Ssam totlen = cmd->src_mapsize; 2511104477Ssam for (m = cmd->dst_m; m != NULL; m = m->m_next) { 2512104477Ssam if (totlen < m->m_len) { 2513104477Ssam m->m_len = totlen; 2514104477Ssam totlen = 0; 2515104477Ssam } else 2516104477Ssam totlen -= m->m_len; 2517104477Ssam } 2518104477Ssam cmd->dst_m->m_pkthdr.len = cmd->src_m->m_pkthdr.len; 2519104477Ssam m_freem(cmd->src_m); 2520104477Ssam } 2521104477Ssam } 2522104477Ssam 2523104477Ssam if (cmd->sloplen != 0) { 2524104477Ssam if (crp->crp_flags & CRYPTO_F_IMBUF) 2525104477Ssam m_copyback((struct mbuf *)crp->crp_buf, 2526104477Ssam cmd->src_mapsize - cmd->sloplen, 2527104477Ssam cmd->sloplen, (caddr_t)&dma->slop[cmd->slopidx]); 2528104477Ssam else if (crp->crp_flags & CRYPTO_F_IOV) 2529104477Ssam cuio_copyback((struct uio *)crp->crp_buf, 2530104477Ssam cmd->src_mapsize - cmd->sloplen, 2531104477Ssam cmd->sloplen, (caddr_t)&dma->slop[cmd->slopidx]); 2532104477Ssam } 2533104477Ssam 2534104477Ssam i = dma->dstk; u = dma->dstu; 2535104477Ssam while (u != 0) { 2536104477Ssam if (i == HIFN_D_DST_RSIZE) 2537104477Ssam i = 0; 2538104477Ssam bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, 2539104477Ssam BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 2540104477Ssam if (dma->dstr[i].l & htole32(HIFN_D_VALID)) { 2541104477Ssam bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, 2542104477Ssam BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 2543104477Ssam break; 2544104477Ssam } 2545104477Ssam i++, u--; 2546104477Ssam } 2547104477Ssam dma->dstk = i; dma->dstu = u; 2548104477Ssam 2549104477Ssam hifnstats.hst_obytes += cmd->dst_mapsize; 2550104477Ssam 2551104477Ssam if ((cmd->base_masks & (HIFN_BASE_CMD_CRYPT | HIFN_BASE_CMD_DECODE)) == 2552104477Ssam HIFN_BASE_CMD_CRYPT) { 2553104477Ssam for (crd = crp->crp_desc; crd; crd = crd->crd_next) { 2554104477Ssam if (crd->crd_alg != CRYPTO_DES_CBC && 2555104477Ssam crd->crd_alg != CRYPTO_3DES_CBC) 2556104477Ssam continue; 2557104477Ssam if (crp->crp_flags & CRYPTO_F_IMBUF) 2558104477Ssam m_copydata((struct mbuf *)crp->crp_buf, 2559104477Ssam crd->crd_skip + crd->crd_len - HIFN_IV_LENGTH, 2560104477Ssam HIFN_IV_LENGTH, 2561104477Ssam cmd->softc->sc_sessions[cmd->session_num].hs_iv); 2562104477Ssam else if (crp->crp_flags & CRYPTO_F_IOV) { 2563104477Ssam cuio_copydata((struct uio *)crp->crp_buf, 2564104477Ssam crd->crd_skip + crd->crd_len - HIFN_IV_LENGTH, 2565104477Ssam HIFN_IV_LENGTH, 2566104477Ssam cmd->softc->sc_sessions[cmd->session_num].hs_iv); 2567104477Ssam } 2568104477Ssam break; 2569104477Ssam } 2570104477Ssam } 2571104477Ssam 2572104477Ssam if (macbuf != NULL) { 2573104477Ssam for (crd = crp->crp_desc; crd; crd = crd->crd_next) { 2574104477Ssam int len; 2575104477Ssam 2576104477Ssam if (crd->crd_alg == CRYPTO_MD5) 2577104477Ssam len = 16; 2578104477Ssam else if (crd->crd_alg == CRYPTO_SHA1) 2579104477Ssam len = 20; 2580104477Ssam else if (crd->crd_alg == CRYPTO_MD5_HMAC || 2581104477Ssam crd->crd_alg == CRYPTO_SHA1_HMAC) 2582104477Ssam len = 12; 2583104477Ssam else 2584104477Ssam continue; 2585104477Ssam 2586104477Ssam if (crp->crp_flags & CRYPTO_F_IMBUF) 2587104477Ssam m_copyback((struct mbuf *)crp->crp_buf, 2588104477Ssam crd->crd_inject, len, macbuf); 2589104477Ssam else if ((crp->crp_flags & CRYPTO_F_IOV) && crp->crp_mac) 2590104477Ssam bcopy((caddr_t)macbuf, crp->crp_mac, len); 2591104477Ssam break; 2592104477Ssam } 2593104477Ssam } 2594104477Ssam 2595104477Ssam if (cmd->src_map != cmd->dst_map) { 2596104477Ssam bus_dmamap_unload(sc->sc_dmat, cmd->dst_map); 2597104477Ssam bus_dmamap_destroy(sc->sc_dmat, cmd->dst_map); 2598104477Ssam } 2599104477Ssam bus_dmamap_unload(sc->sc_dmat, cmd->src_map); 2600104477Ssam bus_dmamap_destroy(sc->sc_dmat, cmd->src_map); 2601104477Ssam free(cmd, M_DEVBUF); 2602104477Ssam crypto_done(crp); 2603104477Ssam} 2604104477Ssam 2605104477Ssam/* 2606104477Ssam * 7811 PB3 rev/2 parts lock-up on burst writes to Group 0 2607104477Ssam * and Group 1 registers; avoid conditions that could create 2608104477Ssam * burst writes by doing a read in between the writes. 2609104477Ssam * 2610104477Ssam * NB: The read we interpose is always to the same register; 2611104477Ssam * we do this because reading from an arbitrary (e.g. last) 2612104477Ssam * register may not always work. 2613104477Ssam */ 2614104477Ssamstatic void 2615104477Ssamhifn_write_reg_0(struct hifn_softc *sc, bus_size_t reg, u_int32_t val) 2616104477Ssam{ 2617104477Ssam if (sc->sc_flags & HIFN_IS_7811) { 2618104477Ssam if (sc->sc_bar0_lastreg == reg - 4) 2619104477Ssam bus_space_read_4(sc->sc_st0, sc->sc_sh0, HIFN_0_PUCNFG); 2620104477Ssam sc->sc_bar0_lastreg = reg; 2621104477Ssam } 2622104477Ssam bus_space_write_4(sc->sc_st0, sc->sc_sh0, reg, val); 2623104477Ssam} 2624104477Ssam 2625104477Ssamstatic void 2626104477Ssamhifn_write_reg_1(struct hifn_softc *sc, bus_size_t reg, u_int32_t val) 2627104477Ssam{ 2628104477Ssam if (sc->sc_flags & HIFN_IS_7811) { 2629104477Ssam if (sc->sc_bar1_lastreg == reg - 4) 2630104477Ssam bus_space_read_4(sc->sc_st1, sc->sc_sh1, HIFN_1_REVID); 2631104477Ssam sc->sc_bar1_lastreg = reg; 2632104477Ssam } 2633104477Ssam bus_space_write_4(sc->sc_st1, sc->sc_sh1, reg, val); 2634104477Ssam} 2635