hifn7751.c revision 213091
1104477Ssam/* $OpenBSD: hifn7751.c,v 1.120 2002/05/17 00:33:34 deraadt Exp $ */ 2104477Ssam 3139749Simp/*- 4104477Ssam * Invertex AEON / Hifn 7751 driver 5104477Ssam * Copyright (c) 1999 Invertex Inc. All rights reserved. 6104477Ssam * Copyright (c) 1999 Theo de Raadt 7104477Ssam * Copyright (c) 2000-2001 Network Security Technologies, Inc. 8104477Ssam * http://www.netsec.net 9120915Ssam * Copyright (c) 2003 Hifn Inc. 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 43119418Sobrien#include <sys/cdefs.h> 44119418Sobrien__FBSDID("$FreeBSD: head/sys/dev/hifn/hifn7751.c 213091 2010-09-24 04:46:46Z gonzo $"); 45119418Sobrien 46104477Ssam/* 47120915Ssam * Driver for various Hifn encryption processors. 48104477Ssam */ 49112124Ssam#include "opt_hifn.h" 50104477Ssam 51104477Ssam#include <sys/param.h> 52104477Ssam#include <sys/systm.h> 53104477Ssam#include <sys/proc.h> 54104477Ssam#include <sys/errno.h> 55104477Ssam#include <sys/malloc.h> 56104477Ssam#include <sys/kernel.h> 57129879Sphk#include <sys/module.h> 58104477Ssam#include <sys/mbuf.h> 59104477Ssam#include <sys/lock.h> 60104477Ssam#include <sys/mutex.h> 61104477Ssam#include <sys/sysctl.h> 62104477Ssam 63104477Ssam#include <vm/vm.h> 64104477Ssam#include <vm/pmap.h> 65104477Ssam 66104477Ssam#include <machine/bus.h> 67104477Ssam#include <machine/resource.h> 68104477Ssam#include <sys/bus.h> 69104477Ssam#include <sys/rman.h> 70104477Ssam 71104477Ssam#include <opencrypto/cryptodev.h> 72104477Ssam#include <sys/random.h> 73167755Ssam#include <sys/kobj.h> 74104477Ssam 75167755Ssam#include "cryptodev_if.h" 76167755Ssam 77119280Simp#include <dev/pci/pcivar.h> 78119280Simp#include <dev/pci/pcireg.h> 79112124Ssam 80112124Ssam#ifdef HIFN_RNDTEST 81112124Ssam#include <dev/rndtest/rndtest.h> 82112124Ssam#endif 83104477Ssam#include <dev/hifn/hifn7751reg.h> 84104477Ssam#include <dev/hifn/hifn7751var.h> 85104477Ssam 86167755Ssam#ifdef HIFN_VULCANDEV 87167755Ssam#include <sys/conf.h> 88167755Ssam#include <sys/uio.h> 89167755Ssam 90167755Ssamstatic struct cdevsw vulcanpk_cdevsw; /* forward declaration */ 91167755Ssam#endif 92167755Ssam 93104477Ssam/* 94104477Ssam * Prototypes and count for the pci_device structure 95104477Ssam */ 96104477Ssamstatic int hifn_probe(device_t); 97104477Ssamstatic int hifn_attach(device_t); 98104477Ssamstatic int hifn_detach(device_t); 99104477Ssamstatic int hifn_suspend(device_t); 100104477Ssamstatic int hifn_resume(device_t); 101188178Simpstatic int hifn_shutdown(device_t); 102104477Ssam 103167755Ssamstatic int hifn_newsession(device_t, u_int32_t *, struct cryptoini *); 104167755Ssamstatic int hifn_freesession(device_t, u_int64_t); 105167755Ssamstatic int hifn_process(device_t, struct cryptop *, int); 106167755Ssam 107104477Ssamstatic device_method_t hifn_methods[] = { 108104477Ssam /* Device interface */ 109104477Ssam DEVMETHOD(device_probe, hifn_probe), 110104477Ssam DEVMETHOD(device_attach, hifn_attach), 111104477Ssam DEVMETHOD(device_detach, hifn_detach), 112104477Ssam DEVMETHOD(device_suspend, hifn_suspend), 113104477Ssam DEVMETHOD(device_resume, hifn_resume), 114104477Ssam DEVMETHOD(device_shutdown, hifn_shutdown), 115104477Ssam 116104477Ssam /* bus interface */ 117104477Ssam DEVMETHOD(bus_print_child, bus_generic_print_child), 118104477Ssam DEVMETHOD(bus_driver_added, bus_generic_driver_added), 119104477Ssam 120167755Ssam /* crypto device methods */ 121167755Ssam DEVMETHOD(cryptodev_newsession, hifn_newsession), 122167755Ssam DEVMETHOD(cryptodev_freesession,hifn_freesession), 123167755Ssam DEVMETHOD(cryptodev_process, hifn_process), 124167755Ssam 125104477Ssam { 0, 0 } 126104477Ssam}; 127104477Ssamstatic driver_t hifn_driver = { 128104477Ssam "hifn", 129104477Ssam hifn_methods, 130104477Ssam sizeof (struct hifn_softc) 131104477Ssam}; 132104477Ssamstatic devclass_t hifn_devclass; 133104477Ssam 134104477SsamDRIVER_MODULE(hifn, pci, hifn_driver, hifn_devclass, 0, 0); 135105251SmarkmMODULE_DEPEND(hifn, crypto, 1, 1, 1); 136112124Ssam#ifdef HIFN_RNDTEST 137112124SsamMODULE_DEPEND(hifn, rndtest, 1, 1, 1); 138112124Ssam#endif 139104477Ssam 140104477Ssamstatic void hifn_reset_board(struct hifn_softc *, int); 141104477Ssamstatic void hifn_reset_puc(struct hifn_softc *); 142104477Ssamstatic void hifn_puc_wait(struct hifn_softc *); 143104477Ssamstatic int hifn_enable_crypto(struct hifn_softc *); 144104477Ssamstatic void hifn_set_retry(struct hifn_softc *sc); 145104477Ssamstatic void hifn_init_dma(struct hifn_softc *); 146104477Ssamstatic void hifn_init_pci_registers(struct hifn_softc *); 147104477Ssamstatic int hifn_sramsize(struct hifn_softc *); 148104477Ssamstatic int hifn_dramsize(struct hifn_softc *); 149104477Ssamstatic int hifn_ramtype(struct hifn_softc *); 150104477Ssamstatic void hifn_sessions(struct hifn_softc *); 151104477Ssamstatic void hifn_intr(void *); 152104477Ssamstatic u_int hifn_write_command(struct hifn_command *, u_int8_t *); 153104477Ssamstatic u_int32_t hifn_next_signature(u_int32_t a, u_int cnt); 154104477Ssamstatic void hifn_callback(struct hifn_softc *, struct hifn_command *, u_int8_t *); 155104477Ssamstatic int hifn_crypto(struct hifn_softc *, struct hifn_command *, struct cryptop *, int); 156104477Ssamstatic int hifn_readramaddr(struct hifn_softc *, int, u_int8_t *); 157104477Ssamstatic int hifn_writeramaddr(struct hifn_softc *, int, u_int8_t *); 158104477Ssamstatic int hifn_dmamap_load_src(struct hifn_softc *, struct hifn_command *); 159104477Ssamstatic int hifn_dmamap_load_dst(struct hifn_softc *, struct hifn_command *); 160104477Ssamstatic int hifn_init_pubrng(struct hifn_softc *); 161104477Ssamstatic void hifn_rng(void *); 162104477Ssamstatic void hifn_tick(void *); 163104477Ssamstatic void hifn_abort(struct hifn_softc *); 164104477Ssamstatic void hifn_alloc_slot(struct hifn_softc *, int *, int *, int *, int *); 165104477Ssam 166104477Ssamstatic void hifn_write_reg_0(struct hifn_softc *, bus_size_t, u_int32_t); 167104477Ssamstatic void hifn_write_reg_1(struct hifn_softc *, bus_size_t, u_int32_t); 168104477Ssam 169131575Sstefanfstatic __inline u_int32_t 170104477SsamREAD_REG_0(struct hifn_softc *sc, bus_size_t reg) 171104477Ssam{ 172104477Ssam u_int32_t v = bus_space_read_4(sc->sc_st0, sc->sc_sh0, reg); 173104477Ssam sc->sc_bar0_lastreg = (bus_size_t) -1; 174104477Ssam return (v); 175104477Ssam} 176104477Ssam#define WRITE_REG_0(sc, reg, val) hifn_write_reg_0(sc, reg, val) 177104477Ssam 178131575Sstefanfstatic __inline u_int32_t 179104477SsamREAD_REG_1(struct hifn_softc *sc, bus_size_t reg) 180104477Ssam{ 181104477Ssam u_int32_t v = bus_space_read_4(sc->sc_st1, sc->sc_sh1, reg); 182104477Ssam sc->sc_bar1_lastreg = (bus_size_t) -1; 183104477Ssam return (v); 184104477Ssam} 185104477Ssam#define WRITE_REG_1(sc, reg, val) hifn_write_reg_1(sc, reg, val) 186104477Ssam 187109596SsamSYSCTL_NODE(_hw, OID_AUTO, hifn, CTLFLAG_RD, 0, "Hifn driver parameters"); 188109596Ssam 189104477Ssam#ifdef HIFN_DEBUG 190104477Ssamstatic int hifn_debug = 0; 191109596SsamSYSCTL_INT(_hw_hifn, OID_AUTO, debug, CTLFLAG_RW, &hifn_debug, 192109596Ssam 0, "control debugging msgs"); 193104477Ssam#endif 194104477Ssam 195104477Ssamstatic struct hifn_stats hifnstats; 196109596SsamSYSCTL_STRUCT(_hw_hifn, OID_AUTO, stats, CTLFLAG_RD, &hifnstats, 197109596Ssam hifn_stats, "driver statistics"); 198112121Ssamstatic int hifn_maxbatch = 1; 199109596SsamSYSCTL_INT(_hw_hifn, OID_AUTO, maxbatch, CTLFLAG_RW, &hifn_maxbatch, 200109596Ssam 0, "max ops to batch w/o interrupt"); 201104477Ssam 202104477Ssam/* 203104477Ssam * Probe for a supported device. The PCI vendor and device 204104477Ssam * IDs are used to detect devices we know how to handle. 205104477Ssam */ 206104477Ssamstatic int 207104477Ssamhifn_probe(device_t dev) 208104477Ssam{ 209104477Ssam if (pci_get_vendor(dev) == PCI_VENDOR_INVERTEX && 210104477Ssam pci_get_device(dev) == PCI_PRODUCT_INVERTEX_AEON) 211143161Simp return (BUS_PROBE_DEFAULT); 212104477Ssam if (pci_get_vendor(dev) == PCI_VENDOR_HIFN && 213104477Ssam (pci_get_device(dev) == PCI_PRODUCT_HIFN_7751 || 214104477Ssam pci_get_device(dev) == PCI_PRODUCT_HIFN_7951 || 215120915Ssam pci_get_device(dev) == PCI_PRODUCT_HIFN_7955 || 216120915Ssam pci_get_device(dev) == PCI_PRODUCT_HIFN_7956 || 217104477Ssam pci_get_device(dev) == PCI_PRODUCT_HIFN_7811)) 218143161Simp return (BUS_PROBE_DEFAULT); 219104477Ssam if (pci_get_vendor(dev) == PCI_VENDOR_NETSEC && 220104477Ssam pci_get_device(dev) == PCI_PRODUCT_NETSEC_7751) 221143161Simp return (BUS_PROBE_DEFAULT); 222104477Ssam return (ENXIO); 223104477Ssam} 224104477Ssam 225104477Ssamstatic void 226104477Ssamhifn_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error) 227104477Ssam{ 228104477Ssam bus_addr_t *paddr = (bus_addr_t*) arg; 229104477Ssam *paddr = segs->ds_addr; 230104477Ssam} 231104477Ssam 232104477Ssamstatic const char* 233104477Ssamhifn_partname(struct hifn_softc *sc) 234104477Ssam{ 235104477Ssam /* XXX sprintf numbers when not decoded */ 236104477Ssam switch (pci_get_vendor(sc->sc_dev)) { 237104477Ssam case PCI_VENDOR_HIFN: 238104477Ssam switch (pci_get_device(sc->sc_dev)) { 239104477Ssam case PCI_PRODUCT_HIFN_6500: return "Hifn 6500"; 240104477Ssam case PCI_PRODUCT_HIFN_7751: return "Hifn 7751"; 241104477Ssam case PCI_PRODUCT_HIFN_7811: return "Hifn 7811"; 242104477Ssam case PCI_PRODUCT_HIFN_7951: return "Hifn 7951"; 243120915Ssam case PCI_PRODUCT_HIFN_7955: return "Hifn 7955"; 244120915Ssam case PCI_PRODUCT_HIFN_7956: return "Hifn 7956"; 245104477Ssam } 246104477Ssam return "Hifn unknown-part"; 247104477Ssam case PCI_VENDOR_INVERTEX: 248104477Ssam switch (pci_get_device(sc->sc_dev)) { 249104477Ssam case PCI_PRODUCT_INVERTEX_AEON: return "Invertex AEON"; 250104477Ssam } 251104477Ssam return "Invertex unknown-part"; 252104477Ssam case PCI_VENDOR_NETSEC: 253104477Ssam switch (pci_get_device(sc->sc_dev)) { 254104477Ssam case PCI_PRODUCT_NETSEC_7751: return "NetSec 7751"; 255104477Ssam } 256104477Ssam return "NetSec unknown-part"; 257104477Ssam } 258104477Ssam return "Unknown-vendor unknown-part"; 259104477Ssam} 260104477Ssam 261112124Ssamstatic void 262112124Ssamdefault_harvest(struct rndtest_state *rsp, void *buf, u_int count) 263112124Ssam{ 264112124Ssam random_harvest(buf, count, count*NBBY, 0, RANDOM_PURE); 265112124Ssam} 266112124Ssam 267140480Ssamstatic u_int 268140480Ssamcheckmaxmin(device_t dev, const char *what, u_int v, u_int min, u_int max) 269140480Ssam{ 270140480Ssam if (v > max) { 271140480Ssam device_printf(dev, "Warning, %s %u out of range, " 272140480Ssam "using max %u\n", what, v, max); 273140480Ssam v = max; 274140480Ssam } else if (v < min) { 275140480Ssam device_printf(dev, "Warning, %s %u out of range, " 276140480Ssam "using min %u\n", what, v, min); 277140480Ssam v = min; 278140480Ssam } 279140480Ssam return v; 280140480Ssam} 281140480Ssam 282104477Ssam/* 283140480Ssam * Select PLL configuration for 795x parts. This is complicated in 284140480Ssam * that we cannot determine the optimal parameters without user input. 285140480Ssam * The reference clock is derived from an external clock through a 286140480Ssam * multiplier. The external clock is either the host bus (i.e. PCI) 287140480Ssam * or an external clock generator. When using the PCI bus we assume 288140480Ssam * the clock is either 33 or 66 MHz; for an external source we cannot 289140480Ssam * tell the speed. 290140480Ssam * 291140480Ssam * PLL configuration is done with a string: "pci" for PCI bus, or "ext" 292140480Ssam * for an external source, followed by the frequency. We calculate 293140480Ssam * the appropriate multiplier and PLL register contents accordingly. 294140480Ssam * When no configuration is given we default to "pci66" since that 295140480Ssam * always will allow the card to work. If a card is using the PCI 296140480Ssam * bus clock and in a 33MHz slot then it will be operating at half 297140480Ssam * speed until the correct information is provided. 298167755Ssam * 299167755Ssam * We use a default setting of "ext66" because according to Mike Ham 300167755Ssam * of HiFn, almost every board in existence has an external crystal 301167755Ssam * populated at 66Mhz. Using PCI can be a problem on modern motherboards, 302167755Ssam * because PCI33 can have clocks from 0 to 33Mhz, and some have 303167755Ssam * non-PCI-compliant spread-spectrum clocks, which can confuse the pll. 304140480Ssam */ 305140480Ssamstatic void 306140480Ssamhifn_getpllconfig(device_t dev, u_int *pll) 307140480Ssam{ 308140480Ssam const char *pllspec; 309140480Ssam u_int freq, mul, fl, fh; 310140480Ssam u_int32_t pllconfig; 311140480Ssam char *nxt; 312140480Ssam 313140480Ssam if (resource_string_value("hifn", device_get_unit(dev), 314140480Ssam "pllconfig", &pllspec)) 315167755Ssam pllspec = "ext66"; 316140480Ssam fl = 33, fh = 66; 317140480Ssam pllconfig = 0; 318140480Ssam if (strncmp(pllspec, "ext", 3) == 0) { 319140480Ssam pllspec += 3; 320140480Ssam pllconfig |= HIFN_PLL_REF_SEL; 321140480Ssam switch (pci_get_device(dev)) { 322140480Ssam case PCI_PRODUCT_HIFN_7955: 323140480Ssam case PCI_PRODUCT_HIFN_7956: 324140480Ssam fl = 20, fh = 100; 325140480Ssam break; 326140480Ssam#ifdef notyet 327140480Ssam case PCI_PRODUCT_HIFN_7954: 328140480Ssam fl = 20, fh = 66; 329140480Ssam break; 330140480Ssam#endif 331140480Ssam } 332140480Ssam } else if (strncmp(pllspec, "pci", 3) == 0) 333140480Ssam pllspec += 3; 334140480Ssam freq = strtoul(pllspec, &nxt, 10); 335140480Ssam if (nxt == pllspec) 336140480Ssam freq = 66; 337140480Ssam else 338140480Ssam freq = checkmaxmin(dev, "frequency", freq, fl, fh); 339140480Ssam /* 340140480Ssam * Calculate multiplier. We target a Fck of 266 MHz, 341140480Ssam * allowing only even values, possibly rounded down. 342140480Ssam * Multipliers > 8 must set the charge pump current. 343140480Ssam */ 344140480Ssam mul = checkmaxmin(dev, "PLL divisor", (266 / freq) &~ 1, 2, 12); 345140480Ssam pllconfig |= (mul / 2 - 1) << HIFN_PLL_ND_SHIFT; 346140480Ssam if (mul > 8) 347140480Ssam pllconfig |= HIFN_PLL_IS; 348140480Ssam *pll = pllconfig; 349140480Ssam} 350140480Ssam 351140480Ssam/* 352104477Ssam * Attach an interface that successfully probed. 353104477Ssam */ 354104477Ssamstatic int 355104477Ssamhifn_attach(device_t dev) 356104477Ssam{ 357104477Ssam struct hifn_softc *sc = device_get_softc(dev); 358104477Ssam u_int32_t cmd; 359104477Ssam caddr_t kva; 360104477Ssam int rseg, rid; 361104477Ssam char rbase; 362104477Ssam u_int16_t ena, rev; 363104477Ssam 364104477Ssam KASSERT(sc != NULL, ("hifn_attach: null software carrier!")); 365104477Ssam bzero(sc, sizeof (*sc)); 366104477Ssam sc->sc_dev = dev; 367104477Ssam 368115748Ssam mtx_init(&sc->sc_mtx, device_get_nameunit(dev), "hifn driver", MTX_DEF); 369104477Ssam 370104477Ssam /* XXX handle power management */ 371104477Ssam 372104477Ssam /* 373120915Ssam * The 7951 and 795x have a random number generator and 374104477Ssam * public key support; note this. 375104477Ssam */ 376104477Ssam if (pci_get_vendor(dev) == PCI_VENDOR_HIFN && 377120915Ssam (pci_get_device(dev) == PCI_PRODUCT_HIFN_7951 || 378120915Ssam pci_get_device(dev) == PCI_PRODUCT_HIFN_7955 || 379120915Ssam pci_get_device(dev) == PCI_PRODUCT_HIFN_7956)) 380104477Ssam sc->sc_flags = HIFN_HAS_RNG | HIFN_HAS_PUBLIC; 381104477Ssam /* 382104477Ssam * The 7811 has a random number generator and 383104477Ssam * we also note it's identity 'cuz of some quirks. 384104477Ssam */ 385104477Ssam if (pci_get_vendor(dev) == PCI_VENDOR_HIFN && 386104477Ssam pci_get_device(dev) == PCI_PRODUCT_HIFN_7811) 387104477Ssam sc->sc_flags |= HIFN_IS_7811 | HIFN_HAS_RNG; 388104477Ssam 389104477Ssam /* 390120915Ssam * The 795x parts support AES. 391120915Ssam */ 392120915Ssam if (pci_get_vendor(dev) == PCI_VENDOR_HIFN && 393120915Ssam (pci_get_device(dev) == PCI_PRODUCT_HIFN_7955 || 394140480Ssam pci_get_device(dev) == PCI_PRODUCT_HIFN_7956)) { 395120915Ssam sc->sc_flags |= HIFN_IS_7956 | HIFN_HAS_AES; 396140480Ssam /* 397140480Ssam * Select PLL configuration. This depends on the 398140480Ssam * bus and board design and must be manually configured 399140480Ssam * if the default setting is unacceptable. 400140480Ssam */ 401140480Ssam hifn_getpllconfig(dev, &sc->sc_pllconfig); 402140480Ssam } 403120915Ssam 404120915Ssam /* 405104477Ssam * Configure support for memory-mapped access to 406104477Ssam * registers and for DMA operations. 407104477Ssam */ 408104477Ssam#define PCIM_ENA (PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN) 409104477Ssam cmd = pci_read_config(dev, PCIR_COMMAND, 4); 410104477Ssam cmd |= PCIM_ENA; 411104477Ssam pci_write_config(dev, PCIR_COMMAND, cmd, 4); 412104477Ssam cmd = pci_read_config(dev, PCIR_COMMAND, 4); 413104477Ssam if ((cmd & PCIM_ENA) != PCIM_ENA) { 414104477Ssam device_printf(dev, "failed to enable %s\n", 415104477Ssam (cmd & PCIM_ENA) == 0 ? 416104477Ssam "memory mapping & bus mastering" : 417104477Ssam (cmd & PCIM_CMD_MEMEN) == 0 ? 418104477Ssam "memory mapping" : "bus mastering"); 419104477Ssam goto fail_pci; 420104477Ssam } 421104477Ssam#undef PCIM_ENA 422104477Ssam 423104477Ssam /* 424104477Ssam * Setup PCI resources. Note that we record the bus 425104477Ssam * tag and handle for each register mapping, this is 426104477Ssam * used by the READ_REG_0, WRITE_REG_0, READ_REG_1, 427104477Ssam * and WRITE_REG_1 macros throughout the driver. 428104477Ssam */ 429104477Ssam rid = HIFN_BAR0; 430127135Snjl sc->sc_bar0res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 431127135Snjl RF_ACTIVE); 432104477Ssam if (sc->sc_bar0res == NULL) { 433104477Ssam device_printf(dev, "cannot map bar%d register space\n", 0); 434104477Ssam goto fail_pci; 435104477Ssam } 436104477Ssam sc->sc_st0 = rman_get_bustag(sc->sc_bar0res); 437104477Ssam sc->sc_sh0 = rman_get_bushandle(sc->sc_bar0res); 438104477Ssam sc->sc_bar0_lastreg = (bus_size_t) -1; 439104477Ssam 440104477Ssam rid = HIFN_BAR1; 441127135Snjl sc->sc_bar1res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 442127135Snjl RF_ACTIVE); 443104477Ssam if (sc->sc_bar1res == NULL) { 444104477Ssam device_printf(dev, "cannot map bar%d register space\n", 1); 445104477Ssam goto fail_io0; 446104477Ssam } 447104477Ssam sc->sc_st1 = rman_get_bustag(sc->sc_bar1res); 448104477Ssam sc->sc_sh1 = rman_get_bushandle(sc->sc_bar1res); 449104477Ssam sc->sc_bar1_lastreg = (bus_size_t) -1; 450104477Ssam 451104477Ssam hifn_set_retry(sc); 452104477Ssam 453104477Ssam /* 454104477Ssam * Setup the area where the Hifn DMA's descriptors 455104477Ssam * and associated data structures. 456104477Ssam */ 457104477Ssam if (bus_dma_tag_create(NULL, /* parent */ 458104477Ssam 1, 0, /* alignment,boundary */ 459104477Ssam BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 460104477Ssam BUS_SPACE_MAXADDR, /* highaddr */ 461104477Ssam NULL, NULL, /* filter, filterarg */ 462104477Ssam HIFN_MAX_DMALEN, /* maxsize */ 463104477Ssam MAX_SCATTER, /* nsegments */ 464104477Ssam HIFN_MAX_SEGLEN, /* maxsegsize */ 465104477Ssam BUS_DMA_ALLOCNOW, /* flags */ 466117126Sscottl NULL, /* lockfunc */ 467117126Sscottl NULL, /* lockarg */ 468104477Ssam &sc->sc_dmat)) { 469104477Ssam device_printf(dev, "cannot allocate DMA tag\n"); 470104477Ssam goto fail_io1; 471104477Ssam } 472104477Ssam if (bus_dmamap_create(sc->sc_dmat, BUS_DMA_NOWAIT, &sc->sc_dmamap)) { 473104477Ssam device_printf(dev, "cannot create dma map\n"); 474104477Ssam bus_dma_tag_destroy(sc->sc_dmat); 475104477Ssam goto fail_io1; 476104477Ssam } 477104477Ssam if (bus_dmamem_alloc(sc->sc_dmat, (void**) &kva, BUS_DMA_NOWAIT, &sc->sc_dmamap)) { 478104477Ssam device_printf(dev, "cannot alloc dma buffer\n"); 479104477Ssam bus_dmamap_destroy(sc->sc_dmat, sc->sc_dmamap); 480104477Ssam bus_dma_tag_destroy(sc->sc_dmat); 481104477Ssam goto fail_io1; 482104477Ssam } 483104477Ssam if (bus_dmamap_load(sc->sc_dmat, sc->sc_dmamap, kva, 484104477Ssam sizeof (*sc->sc_dma), 485104477Ssam hifn_dmamap_cb, &sc->sc_dma_physaddr, 486104477Ssam BUS_DMA_NOWAIT)) { 487104477Ssam device_printf(dev, "cannot load dma map\n"); 488104477Ssam bus_dmamem_free(sc->sc_dmat, kva, sc->sc_dmamap); 489104477Ssam bus_dmamap_destroy(sc->sc_dmat, sc->sc_dmamap); 490104477Ssam bus_dma_tag_destroy(sc->sc_dmat); 491104477Ssam goto fail_io1; 492104477Ssam } 493104477Ssam sc->sc_dma = (struct hifn_dma *)kva; 494104477Ssam bzero(sc->sc_dma, sizeof(*sc->sc_dma)); 495104477Ssam 496123824Ssam KASSERT(sc->sc_st0 != 0, ("hifn_attach: null bar0 tag!")); 497123824Ssam KASSERT(sc->sc_sh0 != 0, ("hifn_attach: null bar0 handle!")); 498123824Ssam KASSERT(sc->sc_st1 != 0, ("hifn_attach: null bar1 tag!")); 499123824Ssam KASSERT(sc->sc_sh1 != 0, ("hifn_attach: null bar1 handle!")); 500104477Ssam 501104477Ssam /* 502104477Ssam * Reset the board and do the ``secret handshake'' 503104477Ssam * to enable the crypto support. Then complete the 504104477Ssam * initialization procedure by setting up the interrupt 505104477Ssam * and hooking in to the system crypto support so we'll 506104477Ssam * get used for system services like the crypto device, 507104477Ssam * IPsec, RNG device, etc. 508104477Ssam */ 509104477Ssam hifn_reset_board(sc, 0); 510104477Ssam 511104477Ssam if (hifn_enable_crypto(sc) != 0) { 512104477Ssam device_printf(dev, "crypto enabling failed\n"); 513104477Ssam goto fail_mem; 514104477Ssam } 515104477Ssam hifn_reset_puc(sc); 516104477Ssam 517104477Ssam hifn_init_dma(sc); 518104477Ssam hifn_init_pci_registers(sc); 519104477Ssam 520120915Ssam /* XXX can't dynamically determine ram type for 795x; force dram */ 521120915Ssam if (sc->sc_flags & HIFN_IS_7956) 522120915Ssam sc->sc_drammodel = 1; 523120915Ssam else if (hifn_ramtype(sc)) 524104477Ssam goto fail_mem; 525104477Ssam 526104477Ssam if (sc->sc_drammodel == 0) 527104477Ssam hifn_sramsize(sc); 528104477Ssam else 529104477Ssam hifn_dramsize(sc); 530104477Ssam 531104477Ssam /* 532104477Ssam * Workaround for NetSec 7751 rev A: half ram size because two 533104477Ssam * of the address lines were left floating 534104477Ssam */ 535104477Ssam if (pci_get_vendor(dev) == PCI_VENDOR_NETSEC && 536104477Ssam pci_get_device(dev) == PCI_PRODUCT_NETSEC_7751 && 537104477Ssam pci_get_revid(dev) == 0x61) /*XXX???*/ 538104477Ssam sc->sc_ramsize >>= 1; 539104477Ssam 540104477Ssam /* 541104477Ssam * Arrange the interrupt line. 542104477Ssam */ 543104477Ssam rid = 0; 544127135Snjl sc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 545127135Snjl RF_SHAREABLE|RF_ACTIVE); 546104477Ssam if (sc->sc_irq == NULL) { 547104477Ssam device_printf(dev, "could not map interrupt\n"); 548104477Ssam goto fail_mem; 549104477Ssam } 550104477Ssam /* 551104477Ssam * NB: Network code assumes we are blocked with splimp() 552104477Ssam * so make sure the IRQ is marked appropriately. 553104477Ssam */ 554115748Ssam if (bus_setup_intr(dev, sc->sc_irq, INTR_TYPE_NET | INTR_MPSAFE, 555166901Spiso NULL, hifn_intr, sc, &sc->sc_intrhand)) { 556104477Ssam device_printf(dev, "could not setup interrupt\n"); 557104477Ssam goto fail_intr2; 558104477Ssam } 559104477Ssam 560104477Ssam hifn_sessions(sc); 561104477Ssam 562104477Ssam /* 563104477Ssam * NB: Keep only the low 16 bits; this masks the chip id 564104477Ssam * from the 7951. 565104477Ssam */ 566104477Ssam rev = READ_REG_1(sc, HIFN_1_REVID) & 0xffff; 567104477Ssam 568104477Ssam rseg = sc->sc_ramsize / 1024; 569104477Ssam rbase = 'K'; 570104477Ssam if (sc->sc_ramsize >= (1024 * 1024)) { 571104477Ssam rbase = 'M'; 572104477Ssam rseg /= 1024; 573104477Ssam } 574140480Ssam device_printf(sc->sc_dev, "%s, rev %u, %d%cB %cram", 575104477Ssam hifn_partname(sc), rev, 576136526Ssam rseg, rbase, sc->sc_drammodel ? 'd' : 's'); 577140480Ssam if (sc->sc_flags & HIFN_IS_7956) 578140480Ssam printf(", pll=0x%x<%s clk, %ux mult>", 579140480Ssam sc->sc_pllconfig, 580140480Ssam sc->sc_pllconfig & HIFN_PLL_REF_SEL ? "ext" : "pci", 581140480Ssam 2 + 2*((sc->sc_pllconfig & HIFN_PLL_ND) >> 11)); 582140480Ssam printf("\n"); 583104477Ssam 584167755Ssam sc->sc_cid = crypto_get_driverid(dev, CRYPTOCAP_F_HARDWARE); 585104477Ssam if (sc->sc_cid < 0) { 586104477Ssam device_printf(dev, "could not get crypto driver id\n"); 587104477Ssam goto fail_intr; 588104477Ssam } 589104477Ssam 590104477Ssam WRITE_REG_0(sc, HIFN_0_PUCNFG, 591104477Ssam READ_REG_0(sc, HIFN_0_PUCNFG) | HIFN_PUCNFG_CHIPID); 592104477Ssam ena = READ_REG_0(sc, HIFN_0_PUSTAT) & HIFN_PUSTAT_CHIPENA; 593104477Ssam 594104477Ssam switch (ena) { 595104477Ssam case HIFN_PUSTAT_ENA_2: 596167755Ssam crypto_register(sc->sc_cid, CRYPTO_3DES_CBC, 0, 0); 597167755Ssam crypto_register(sc->sc_cid, CRYPTO_ARC4, 0, 0); 598120915Ssam if (sc->sc_flags & HIFN_HAS_AES) 599167755Ssam crypto_register(sc->sc_cid, CRYPTO_AES_CBC, 0, 0); 600104477Ssam /*FALLTHROUGH*/ 601104477Ssam case HIFN_PUSTAT_ENA_1: 602167755Ssam crypto_register(sc->sc_cid, CRYPTO_MD5, 0, 0); 603167755Ssam crypto_register(sc->sc_cid, CRYPTO_SHA1, 0, 0); 604167755Ssam crypto_register(sc->sc_cid, CRYPTO_MD5_HMAC, 0, 0); 605167755Ssam crypto_register(sc->sc_cid, CRYPTO_SHA1_HMAC, 0, 0); 606167755Ssam crypto_register(sc->sc_cid, CRYPTO_DES_CBC, 0, 0); 607104477Ssam break; 608104477Ssam } 609104477Ssam 610104477Ssam bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, 611104477Ssam BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 612104477Ssam 613104477Ssam if (sc->sc_flags & (HIFN_HAS_PUBLIC | HIFN_HAS_RNG)) 614104477Ssam hifn_init_pubrng(sc); 615104477Ssam 616119137Ssam callout_init(&sc->sc_tickto, CALLOUT_MPSAFE); 617104477Ssam callout_reset(&sc->sc_tickto, hz, hifn_tick, sc); 618104477Ssam 619104477Ssam return (0); 620104477Ssam 621104477Ssamfail_intr: 622104477Ssam bus_teardown_intr(dev, sc->sc_irq, sc->sc_intrhand); 623104477Ssamfail_intr2: 624104477Ssam /* XXX don't store rid */ 625104477Ssam bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq); 626104477Ssamfail_mem: 627104477Ssam bus_dmamap_unload(sc->sc_dmat, sc->sc_dmamap); 628104477Ssam bus_dmamem_free(sc->sc_dmat, sc->sc_dma, sc->sc_dmamap); 629104477Ssam bus_dmamap_destroy(sc->sc_dmat, sc->sc_dmamap); 630104477Ssam bus_dma_tag_destroy(sc->sc_dmat); 631104477Ssam 632104477Ssam /* Turn off DMA polling */ 633104477Ssam WRITE_REG_1(sc, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MSTRESET | 634104477Ssam HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE); 635104477Ssamfail_io1: 636104477Ssam bus_release_resource(dev, SYS_RES_MEMORY, HIFN_BAR1, sc->sc_bar1res); 637104477Ssamfail_io0: 638104477Ssam bus_release_resource(dev, SYS_RES_MEMORY, HIFN_BAR0, sc->sc_bar0res); 639104477Ssamfail_pci: 640104477Ssam mtx_destroy(&sc->sc_mtx); 641104477Ssam return (ENXIO); 642104477Ssam} 643104477Ssam 644104477Ssam/* 645104477Ssam * Detach an interface that successfully probed. 646104477Ssam */ 647104477Ssamstatic int 648104477Ssamhifn_detach(device_t dev) 649104477Ssam{ 650104477Ssam struct hifn_softc *sc = device_get_softc(dev); 651104477Ssam 652104477Ssam KASSERT(sc != NULL, ("hifn_detach: null software carrier!")); 653104477Ssam 654115748Ssam /* disable interrupts */ 655115748Ssam WRITE_REG_1(sc, HIFN_1_DMA_IER, 0); 656104477Ssam 657104477Ssam /*XXX other resources */ 658104477Ssam callout_stop(&sc->sc_tickto); 659104477Ssam callout_stop(&sc->sc_rngto); 660115848Ssam#ifdef HIFN_RNDTEST 661115848Ssam if (sc->sc_rndtest) 662115862Ssam rndtest_detach(sc->sc_rndtest); 663115848Ssam#endif 664104477Ssam 665104477Ssam /* Turn off DMA polling */ 666104477Ssam WRITE_REG_1(sc, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MSTRESET | 667104477Ssam HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE); 668104477Ssam 669104477Ssam crypto_unregister_all(sc->sc_cid); 670104477Ssam 671104477Ssam bus_generic_detach(dev); /*XXX should be no children, right? */ 672104477Ssam 673104477Ssam bus_teardown_intr(dev, sc->sc_irq, sc->sc_intrhand); 674104477Ssam /* XXX don't store rid */ 675104477Ssam bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq); 676104477Ssam 677104477Ssam bus_dmamap_unload(sc->sc_dmat, sc->sc_dmamap); 678104477Ssam bus_dmamem_free(sc->sc_dmat, sc->sc_dma, sc->sc_dmamap); 679104477Ssam bus_dmamap_destroy(sc->sc_dmat, sc->sc_dmamap); 680104477Ssam bus_dma_tag_destroy(sc->sc_dmat); 681104477Ssam 682104477Ssam bus_release_resource(dev, SYS_RES_MEMORY, HIFN_BAR1, sc->sc_bar1res); 683104477Ssam bus_release_resource(dev, SYS_RES_MEMORY, HIFN_BAR0, sc->sc_bar0res); 684104477Ssam 685104477Ssam mtx_destroy(&sc->sc_mtx); 686104477Ssam 687104477Ssam return (0); 688104477Ssam} 689104477Ssam 690104477Ssam/* 691104477Ssam * Stop all chip I/O so that the kernel's probe routines don't 692104477Ssam * get confused by errant DMAs when rebooting. 693104477Ssam */ 694188178Simpstatic int 695104477Ssamhifn_shutdown(device_t dev) 696104477Ssam{ 697104477Ssam#ifdef notyet 698104477Ssam hifn_stop(device_get_softc(dev)); 699104477Ssam#endif 700188178Simp return (0); 701104477Ssam} 702104477Ssam 703104477Ssam/* 704104477Ssam * Device suspend routine. Stop the interface and save some PCI 705104477Ssam * settings in case the BIOS doesn't restore them properly on 706104477Ssam * resume. 707104477Ssam */ 708104477Ssamstatic int 709104477Ssamhifn_suspend(device_t dev) 710104477Ssam{ 711104477Ssam struct hifn_softc *sc = device_get_softc(dev); 712104477Ssam#ifdef notyet 713104477Ssam hifn_stop(sc); 714104477Ssam#endif 715104477Ssam sc->sc_suspended = 1; 716104477Ssam 717104477Ssam return (0); 718104477Ssam} 719104477Ssam 720104477Ssam/* 721104477Ssam * Device resume routine. Restore some PCI settings in case the BIOS 722104477Ssam * doesn't, re-enable busmastering, and restart the interface if 723104477Ssam * appropriate. 724104477Ssam */ 725104477Ssamstatic int 726104477Ssamhifn_resume(device_t dev) 727104477Ssam{ 728104477Ssam struct hifn_softc *sc = device_get_softc(dev); 729104477Ssam#ifdef notyet 730104477Ssam /* reenable busmastering */ 731104477Ssam pci_enable_busmaster(dev); 732104477Ssam pci_enable_io(dev, HIFN_RES); 733104477Ssam 734104477Ssam /* reinitialize interface if necessary */ 735104477Ssam if (ifp->if_flags & IFF_UP) 736104477Ssam rl_init(sc); 737104477Ssam#endif 738104477Ssam sc->sc_suspended = 0; 739104477Ssam 740104477Ssam return (0); 741104477Ssam} 742104477Ssam 743104477Ssamstatic int 744104477Ssamhifn_init_pubrng(struct hifn_softc *sc) 745104477Ssam{ 746104477Ssam u_int32_t r; 747104477Ssam int i; 748104477Ssam 749112124Ssam#ifdef HIFN_RNDTEST 750112124Ssam sc->sc_rndtest = rndtest_attach(sc->sc_dev); 751112124Ssam if (sc->sc_rndtest) 752112124Ssam sc->sc_harvest = rndtest_harvest; 753112124Ssam else 754112124Ssam sc->sc_harvest = default_harvest; 755112124Ssam#else 756112124Ssam sc->sc_harvest = default_harvest; 757112124Ssam#endif 758104477Ssam if ((sc->sc_flags & HIFN_IS_7811) == 0) { 759104477Ssam /* Reset 7951 public key/rng engine */ 760104477Ssam WRITE_REG_1(sc, HIFN_1_PUB_RESET, 761104477Ssam READ_REG_1(sc, HIFN_1_PUB_RESET) | HIFN_PUBRST_RESET); 762104477Ssam 763104477Ssam for (i = 0; i < 100; i++) { 764104477Ssam DELAY(1000); 765104477Ssam if ((READ_REG_1(sc, HIFN_1_PUB_RESET) & 766104477Ssam HIFN_PUBRST_RESET) == 0) 767104477Ssam break; 768104477Ssam } 769104477Ssam 770104477Ssam if (i == 100) { 771104477Ssam device_printf(sc->sc_dev, "public key init failed\n"); 772104477Ssam return (1); 773104477Ssam } 774104477Ssam } 775104477Ssam 776104477Ssam /* Enable the rng, if available */ 777104477Ssam if (sc->sc_flags & HIFN_HAS_RNG) { 778104477Ssam if (sc->sc_flags & HIFN_IS_7811) { 779104477Ssam r = READ_REG_1(sc, HIFN_1_7811_RNGENA); 780104477Ssam if (r & HIFN_7811_RNGENA_ENA) { 781104477Ssam r &= ~HIFN_7811_RNGENA_ENA; 782104477Ssam WRITE_REG_1(sc, HIFN_1_7811_RNGENA, r); 783104477Ssam } 784104477Ssam WRITE_REG_1(sc, HIFN_1_7811_RNGCFG, 785104477Ssam HIFN_7811_RNGCFG_DEFL); 786104477Ssam r |= HIFN_7811_RNGENA_ENA; 787104477Ssam WRITE_REG_1(sc, HIFN_1_7811_RNGENA, r); 788104477Ssam } else 789104477Ssam WRITE_REG_1(sc, HIFN_1_RNG_CONFIG, 790104477Ssam READ_REG_1(sc, HIFN_1_RNG_CONFIG) | 791104477Ssam HIFN_RNGCFG_ENA); 792104477Ssam 793104477Ssam sc->sc_rngfirst = 1; 794104477Ssam if (hz >= 100) 795104477Ssam sc->sc_rnghz = hz / 100; 796104477Ssam else 797104477Ssam sc->sc_rnghz = 1; 798119137Ssam callout_init(&sc->sc_rngto, CALLOUT_MPSAFE); 799104477Ssam callout_reset(&sc->sc_rngto, sc->sc_rnghz, hifn_rng, sc); 800104477Ssam } 801104477Ssam 802104477Ssam /* Enable public key engine, if available */ 803104477Ssam if (sc->sc_flags & HIFN_HAS_PUBLIC) { 804104477Ssam WRITE_REG_1(sc, HIFN_1_PUB_IEN, HIFN_PUBIEN_DONE); 805104477Ssam sc->sc_dmaier |= HIFN_DMAIER_PUBDONE; 806104477Ssam WRITE_REG_1(sc, HIFN_1_DMA_IER, sc->sc_dmaier); 807167755Ssam#ifdef HIFN_VULCANDEV 808167755Ssam sc->sc_pkdev = make_dev(&vulcanpk_cdevsw, 0, 809167755Ssam UID_ROOT, GID_WHEEL, 0666, 810167755Ssam "vulcanpk"); 811167755Ssam sc->sc_pkdev->si_drv1 = sc; 812167755Ssam#endif 813104477Ssam } 814104477Ssam 815104477Ssam return (0); 816104477Ssam} 817104477Ssam 818104477Ssamstatic void 819104477Ssamhifn_rng(void *vsc) 820104477Ssam{ 821104477Ssam#define RANDOM_BITS(n) (n)*sizeof (u_int32_t), (n)*sizeof (u_int32_t)*NBBY, 0 822104477Ssam struct hifn_softc *sc = vsc; 823104477Ssam u_int32_t sts, num[2]; 824104477Ssam int i; 825104477Ssam 826104477Ssam if (sc->sc_flags & HIFN_IS_7811) { 827167755Ssam /* ONLY VALID ON 7811!!!! */ 828104477Ssam for (i = 0; i < 5; i++) { 829104477Ssam sts = READ_REG_1(sc, HIFN_1_7811_RNGSTS); 830104477Ssam if (sts & HIFN_7811_RNGSTS_UFL) { 831104477Ssam device_printf(sc->sc_dev, 832104477Ssam "RNG underflow: disabling\n"); 833104477Ssam return; 834104477Ssam } 835104477Ssam if ((sts & HIFN_7811_RNGSTS_RDY) == 0) 836104477Ssam break; 837104477Ssam 838104477Ssam /* 839104477Ssam * There are at least two words in the RNG FIFO 840104477Ssam * at this point. 841104477Ssam */ 842104477Ssam num[0] = READ_REG_1(sc, HIFN_1_7811_RNGDAT); 843104477Ssam num[1] = READ_REG_1(sc, HIFN_1_7811_RNGDAT); 844104477Ssam /* NB: discard first data read */ 845104477Ssam if (sc->sc_rngfirst) 846104477Ssam sc->sc_rngfirst = 0; 847104477Ssam else 848112124Ssam (*sc->sc_harvest)(sc->sc_rndtest, 849112124Ssam num, sizeof (num)); 850104477Ssam } 851104477Ssam } else { 852104477Ssam num[0] = READ_REG_1(sc, HIFN_1_RNG_DATA); 853104477Ssam 854104477Ssam /* NB: discard first data read */ 855104477Ssam if (sc->sc_rngfirst) 856104477Ssam sc->sc_rngfirst = 0; 857104477Ssam else 858112124Ssam (*sc->sc_harvest)(sc->sc_rndtest, 859112124Ssam num, sizeof (num[0])); 860104477Ssam } 861104477Ssam 862104477Ssam callout_reset(&sc->sc_rngto, sc->sc_rnghz, hifn_rng, sc); 863104477Ssam#undef RANDOM_BITS 864104477Ssam} 865104477Ssam 866104477Ssamstatic void 867104477Ssamhifn_puc_wait(struct hifn_softc *sc) 868104477Ssam{ 869104477Ssam int i; 870167755Ssam int reg = HIFN_0_PUCTRL; 871104477Ssam 872167755Ssam if (sc->sc_flags & HIFN_IS_7956) { 873167755Ssam reg = HIFN_0_PUCTRL2; 874167755Ssam } 875167755Ssam 876104477Ssam for (i = 5000; i > 0; i--) { 877104477Ssam DELAY(1); 878167755Ssam if (!(READ_REG_0(sc, reg) & HIFN_PUCTRL_RESET)) 879104477Ssam break; 880104477Ssam } 881104477Ssam if (!i) 882104477Ssam device_printf(sc->sc_dev, "proc unit did not reset\n"); 883104477Ssam} 884104477Ssam 885104477Ssam/* 886104477Ssam * Reset the processing unit. 887104477Ssam */ 888104477Ssamstatic void 889104477Ssamhifn_reset_puc(struct hifn_softc *sc) 890104477Ssam{ 891104477Ssam /* Reset processing unit */ 892167755Ssam int reg = HIFN_0_PUCTRL; 893167755Ssam 894167755Ssam if (sc->sc_flags & HIFN_IS_7956) { 895167755Ssam reg = HIFN_0_PUCTRL2; 896167755Ssam } 897167755Ssam WRITE_REG_0(sc, reg, HIFN_PUCTRL_DMAENA); 898167755Ssam 899104477Ssam hifn_puc_wait(sc); 900104477Ssam} 901104477Ssam 902104477Ssam/* 903104477Ssam * Set the Retry and TRDY registers; note that we set them to 904104477Ssam * zero because the 7811 locks up when forced to retry (section 905104477Ssam * 3.6 of "Specification Update SU-0014-04". Not clear if we 906104477Ssam * should do this for all Hifn parts, but it doesn't seem to hurt. 907104477Ssam */ 908104477Ssamstatic void 909104477Ssamhifn_set_retry(struct hifn_softc *sc) 910104477Ssam{ 911104477Ssam /* NB: RETRY only responds to 8-bit reads/writes */ 912104477Ssam pci_write_config(sc->sc_dev, HIFN_RETRY_TIMEOUT, 0, 1); 913104477Ssam pci_write_config(sc->sc_dev, HIFN_TRDY_TIMEOUT, 0, 4); 914104477Ssam} 915104477Ssam 916104477Ssam/* 917104477Ssam * Resets the board. Values in the regesters are left as is 918104477Ssam * from the reset (i.e. initial values are assigned elsewhere). 919104477Ssam */ 920104477Ssamstatic void 921104477Ssamhifn_reset_board(struct hifn_softc *sc, int full) 922104477Ssam{ 923104477Ssam u_int32_t reg; 924104477Ssam 925104477Ssam /* 926104477Ssam * Set polling in the DMA configuration register to zero. 0x7 avoids 927104477Ssam * resetting the board and zeros out the other fields. 928104477Ssam */ 929104477Ssam WRITE_REG_1(sc, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MSTRESET | 930104477Ssam HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE); 931104477Ssam 932104477Ssam /* 933104477Ssam * Now that polling has been disabled, we have to wait 1 ms 934104477Ssam * before resetting the board. 935104477Ssam */ 936104477Ssam DELAY(1000); 937104477Ssam 938104477Ssam /* Reset the DMA unit */ 939104477Ssam if (full) { 940104477Ssam WRITE_REG_1(sc, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MODE); 941104477Ssam DELAY(1000); 942104477Ssam } else { 943104477Ssam WRITE_REG_1(sc, HIFN_1_DMA_CNFG, 944104477Ssam HIFN_DMACNFG_MODE | HIFN_DMACNFG_MSTRESET); 945104477Ssam hifn_reset_puc(sc); 946104477Ssam } 947104477Ssam 948104477Ssam KASSERT(sc->sc_dma != NULL, ("hifn_reset_board: null DMA tag!")); 949104477Ssam bzero(sc->sc_dma, sizeof(*sc->sc_dma)); 950104477Ssam 951104477Ssam /* Bring dma unit out of reset */ 952104477Ssam WRITE_REG_1(sc, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MSTRESET | 953104477Ssam HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE); 954104477Ssam 955104477Ssam hifn_puc_wait(sc); 956104477Ssam hifn_set_retry(sc); 957104477Ssam 958104477Ssam if (sc->sc_flags & HIFN_IS_7811) { 959104477Ssam for (reg = 0; reg < 1000; reg++) { 960104477Ssam if (READ_REG_1(sc, HIFN_1_7811_MIPSRST) & 961104477Ssam HIFN_MIPSRST_CRAMINIT) 962104477Ssam break; 963104477Ssam DELAY(1000); 964104477Ssam } 965104477Ssam if (reg == 1000) 966104477Ssam printf(": cram init timeout\n"); 967167755Ssam } else { 968167755Ssam /* set up DMA configuration register #2 */ 969167755Ssam /* turn off all PK and BAR0 swaps */ 970167755Ssam WRITE_REG_1(sc, HIFN_1_DMA_CNFG2, 971167755Ssam (3 << HIFN_DMACNFG2_INIT_WRITE_BURST_SHIFT)| 972167755Ssam (3 << HIFN_DMACNFG2_INIT_READ_BURST_SHIFT)| 973167755Ssam (2 << HIFN_DMACNFG2_TGT_WRITE_BURST_SHIFT)| 974167755Ssam (2 << HIFN_DMACNFG2_TGT_READ_BURST_SHIFT)); 975104477Ssam } 976167755Ssam 977104477Ssam} 978104477Ssam 979104477Ssamstatic u_int32_t 980104477Ssamhifn_next_signature(u_int32_t a, u_int cnt) 981104477Ssam{ 982104477Ssam int i; 983104477Ssam u_int32_t v; 984104477Ssam 985104477Ssam for (i = 0; i < cnt; i++) { 986104477Ssam 987104477Ssam /* get the parity */ 988104477Ssam v = a & 0x80080125; 989104477Ssam v ^= v >> 16; 990104477Ssam v ^= v >> 8; 991104477Ssam v ^= v >> 4; 992104477Ssam v ^= v >> 2; 993104477Ssam v ^= v >> 1; 994104477Ssam 995104477Ssam a = (v & 1) ^ (a << 1); 996104477Ssam } 997104477Ssam 998104477Ssam return a; 999104477Ssam} 1000104477Ssam 1001104477Ssamstruct pci2id { 1002104477Ssam u_short pci_vendor; 1003104477Ssam u_short pci_prod; 1004104477Ssam char card_id[13]; 1005104477Ssam}; 1006104477Ssamstatic struct pci2id pci2id[] = { 1007104477Ssam { 1008104477Ssam PCI_VENDOR_HIFN, 1009104477Ssam PCI_PRODUCT_HIFN_7951, 1010104477Ssam { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 1011104477Ssam 0x00, 0x00, 0x00, 0x00, 0x00 } 1012104477Ssam }, { 1013120915Ssam PCI_VENDOR_HIFN, 1014120915Ssam PCI_PRODUCT_HIFN_7955, 1015120915Ssam { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 1016120915Ssam 0x00, 0x00, 0x00, 0x00, 0x00 } 1017120915Ssam }, { 1018120915Ssam PCI_VENDOR_HIFN, 1019120915Ssam PCI_PRODUCT_HIFN_7956, 1020120915Ssam { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 1021120915Ssam 0x00, 0x00, 0x00, 0x00, 0x00 } 1022120915Ssam }, { 1023104477Ssam PCI_VENDOR_NETSEC, 1024104477Ssam PCI_PRODUCT_NETSEC_7751, 1025104477Ssam { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 1026104477Ssam 0x00, 0x00, 0x00, 0x00, 0x00 } 1027104477Ssam }, { 1028104477Ssam PCI_VENDOR_INVERTEX, 1029104477Ssam PCI_PRODUCT_INVERTEX_AEON, 1030104477Ssam { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 1031104477Ssam 0x00, 0x00, 0x00, 0x00, 0x00 } 1032104477Ssam }, { 1033104477Ssam PCI_VENDOR_HIFN, 1034104477Ssam PCI_PRODUCT_HIFN_7811, 1035104477Ssam { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 1036104477Ssam 0x00, 0x00, 0x00, 0x00, 0x00 } 1037104477Ssam }, { 1038104477Ssam /* 1039104477Ssam * Other vendors share this PCI ID as well, such as 1040104477Ssam * http://www.powercrypt.com, and obviously they also 1041104477Ssam * use the same key. 1042104477Ssam */ 1043104477Ssam PCI_VENDOR_HIFN, 1044104477Ssam PCI_PRODUCT_HIFN_7751, 1045104477Ssam { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 1046104477Ssam 0x00, 0x00, 0x00, 0x00, 0x00 } 1047104477Ssam }, 1048104477Ssam}; 1049104477Ssam 1050104477Ssam/* 1051104477Ssam * Checks to see if crypto is already enabled. If crypto isn't enable, 1052104477Ssam * "hifn_enable_crypto" is called to enable it. The check is important, 1053104477Ssam * as enabling crypto twice will lock the board. 1054104477Ssam */ 1055104477Ssamstatic int 1056104477Ssamhifn_enable_crypto(struct hifn_softc *sc) 1057104477Ssam{ 1058104477Ssam u_int32_t dmacfg, ramcfg, encl, addr, i; 1059104477Ssam char *offtbl = NULL; 1060104477Ssam 1061104477Ssam for (i = 0; i < sizeof(pci2id)/sizeof(pci2id[0]); i++) { 1062104477Ssam if (pci2id[i].pci_vendor == pci_get_vendor(sc->sc_dev) && 1063104477Ssam pci2id[i].pci_prod == pci_get_device(sc->sc_dev)) { 1064104477Ssam offtbl = pci2id[i].card_id; 1065104477Ssam break; 1066104477Ssam } 1067104477Ssam } 1068104477Ssam if (offtbl == NULL) { 1069104477Ssam device_printf(sc->sc_dev, "Unknown card!\n"); 1070104477Ssam return (1); 1071104477Ssam } 1072104477Ssam 1073104477Ssam ramcfg = READ_REG_0(sc, HIFN_0_PUCNFG); 1074104477Ssam dmacfg = READ_REG_1(sc, HIFN_1_DMA_CNFG); 1075104477Ssam 1076104477Ssam /* 1077104477Ssam * The RAM config register's encrypt level bit needs to be set before 1078104477Ssam * every read performed on the encryption level register. 1079104477Ssam */ 1080104477Ssam WRITE_REG_0(sc, HIFN_0_PUCNFG, ramcfg | HIFN_PUCNFG_CHIPID); 1081104477Ssam 1082104477Ssam encl = READ_REG_0(sc, HIFN_0_PUSTAT) & HIFN_PUSTAT_CHIPENA; 1083104477Ssam 1084104477Ssam /* 1085104477Ssam * Make sure we don't re-unlock. Two unlocks kills chip until the 1086104477Ssam * next reboot. 1087104477Ssam */ 1088104477Ssam if (encl == HIFN_PUSTAT_ENA_1 || encl == HIFN_PUSTAT_ENA_2) { 1089104477Ssam#ifdef HIFN_DEBUG 1090104477Ssam if (hifn_debug) 1091104477Ssam device_printf(sc->sc_dev, 1092104477Ssam "Strong crypto already enabled!\n"); 1093104477Ssam#endif 1094104477Ssam goto report; 1095104477Ssam } 1096104477Ssam 1097104477Ssam if (encl != 0 && encl != HIFN_PUSTAT_ENA_0) { 1098104477Ssam#ifdef HIFN_DEBUG 1099104477Ssam if (hifn_debug) 1100104477Ssam device_printf(sc->sc_dev, 1101104477Ssam "Unknown encryption level 0x%x\n", encl); 1102104477Ssam#endif 1103104477Ssam return 1; 1104104477Ssam } 1105104477Ssam 1106104477Ssam WRITE_REG_1(sc, HIFN_1_DMA_CNFG, HIFN_DMACNFG_UNLOCK | 1107104477Ssam HIFN_DMACNFG_MSTRESET | HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE); 1108104477Ssam DELAY(1000); 1109104477Ssam addr = READ_REG_1(sc, HIFN_UNLOCK_SECRET1); 1110104477Ssam DELAY(1000); 1111104477Ssam WRITE_REG_1(sc, HIFN_UNLOCK_SECRET2, 0); 1112104477Ssam DELAY(1000); 1113104477Ssam 1114104477Ssam for (i = 0; i <= 12; i++) { 1115104477Ssam addr = hifn_next_signature(addr, offtbl[i] + 0x101); 1116104477Ssam WRITE_REG_1(sc, HIFN_UNLOCK_SECRET2, addr); 1117104477Ssam 1118104477Ssam DELAY(1000); 1119104477Ssam } 1120104477Ssam 1121104477Ssam WRITE_REG_0(sc, HIFN_0_PUCNFG, ramcfg | HIFN_PUCNFG_CHIPID); 1122104477Ssam encl = READ_REG_0(sc, HIFN_0_PUSTAT) & HIFN_PUSTAT_CHIPENA; 1123104477Ssam 1124104477Ssam#ifdef HIFN_DEBUG 1125104477Ssam if (hifn_debug) { 1126104477Ssam if (encl != HIFN_PUSTAT_ENA_1 && encl != HIFN_PUSTAT_ENA_2) 1127104477Ssam device_printf(sc->sc_dev, "Engine is permanently " 1128104477Ssam "locked until next system reset!\n"); 1129104477Ssam else 1130104477Ssam device_printf(sc->sc_dev, "Engine enabled " 1131104477Ssam "successfully!\n"); 1132104477Ssam } 1133104477Ssam#endif 1134104477Ssam 1135104477Ssamreport: 1136104477Ssam WRITE_REG_0(sc, HIFN_0_PUCNFG, ramcfg); 1137104477Ssam WRITE_REG_1(sc, HIFN_1_DMA_CNFG, dmacfg); 1138104477Ssam 1139104477Ssam switch (encl) { 1140104477Ssam case HIFN_PUSTAT_ENA_1: 1141104477Ssam case HIFN_PUSTAT_ENA_2: 1142104477Ssam break; 1143104477Ssam case HIFN_PUSTAT_ENA_0: 1144104477Ssam default: 1145104477Ssam device_printf(sc->sc_dev, "disabled"); 1146104477Ssam break; 1147104477Ssam } 1148104477Ssam 1149104477Ssam return 0; 1150104477Ssam} 1151104477Ssam 1152104477Ssam/* 1153104477Ssam * Give initial values to the registers listed in the "Register Space" 1154104477Ssam * section of the HIFN Software Development reference manual. 1155104477Ssam */ 1156104477Ssamstatic void 1157104477Ssamhifn_init_pci_registers(struct hifn_softc *sc) 1158104477Ssam{ 1159104477Ssam /* write fixed values needed by the Initialization registers */ 1160104477Ssam WRITE_REG_0(sc, HIFN_0_PUCTRL, HIFN_PUCTRL_DMAENA); 1161104477Ssam WRITE_REG_0(sc, HIFN_0_FIFOCNFG, HIFN_FIFOCNFG_THRESHOLD); 1162104477Ssam WRITE_REG_0(sc, HIFN_0_PUIER, HIFN_PUIER_DSTOVER); 1163104477Ssam 1164104477Ssam /* write all 4 ring address registers */ 1165104477Ssam WRITE_REG_1(sc, HIFN_1_DMA_CRAR, sc->sc_dma_physaddr + 1166104477Ssam offsetof(struct hifn_dma, cmdr[0])); 1167104477Ssam WRITE_REG_1(sc, HIFN_1_DMA_SRAR, sc->sc_dma_physaddr + 1168104477Ssam offsetof(struct hifn_dma, srcr[0])); 1169104477Ssam WRITE_REG_1(sc, HIFN_1_DMA_DRAR, sc->sc_dma_physaddr + 1170104477Ssam offsetof(struct hifn_dma, dstr[0])); 1171104477Ssam WRITE_REG_1(sc, HIFN_1_DMA_RRAR, sc->sc_dma_physaddr + 1172104477Ssam offsetof(struct hifn_dma, resr[0])); 1173104477Ssam 1174104477Ssam DELAY(2000); 1175104477Ssam 1176104477Ssam /* write status register */ 1177104477Ssam WRITE_REG_1(sc, HIFN_1_DMA_CSR, 1178104477Ssam HIFN_DMACSR_D_CTRL_DIS | HIFN_DMACSR_R_CTRL_DIS | 1179104477Ssam HIFN_DMACSR_S_CTRL_DIS | HIFN_DMACSR_C_CTRL_DIS | 1180104477Ssam HIFN_DMACSR_D_ABORT | HIFN_DMACSR_D_DONE | HIFN_DMACSR_D_LAST | 1181104477Ssam HIFN_DMACSR_D_WAIT | HIFN_DMACSR_D_OVER | 1182104477Ssam HIFN_DMACSR_R_ABORT | HIFN_DMACSR_R_DONE | HIFN_DMACSR_R_LAST | 1183104477Ssam HIFN_DMACSR_R_WAIT | HIFN_DMACSR_R_OVER | 1184104477Ssam HIFN_DMACSR_S_ABORT | HIFN_DMACSR_S_DONE | HIFN_DMACSR_S_LAST | 1185104477Ssam HIFN_DMACSR_S_WAIT | 1186104477Ssam HIFN_DMACSR_C_ABORT | HIFN_DMACSR_C_DONE | HIFN_DMACSR_C_LAST | 1187104477Ssam HIFN_DMACSR_C_WAIT | 1188104477Ssam HIFN_DMACSR_ENGINE | 1189104477Ssam ((sc->sc_flags & HIFN_HAS_PUBLIC) ? 1190104477Ssam HIFN_DMACSR_PUBDONE : 0) | 1191104477Ssam ((sc->sc_flags & HIFN_IS_7811) ? 1192104477Ssam HIFN_DMACSR_ILLW | HIFN_DMACSR_ILLR : 0)); 1193104477Ssam 1194104477Ssam sc->sc_d_busy = sc->sc_r_busy = sc->sc_s_busy = sc->sc_c_busy = 0; 1195104477Ssam sc->sc_dmaier |= HIFN_DMAIER_R_DONE | HIFN_DMAIER_C_ABORT | 1196104477Ssam HIFN_DMAIER_D_OVER | HIFN_DMAIER_R_OVER | 1197104477Ssam HIFN_DMAIER_S_ABORT | HIFN_DMAIER_D_ABORT | HIFN_DMAIER_R_ABORT | 1198104477Ssam ((sc->sc_flags & HIFN_IS_7811) ? 1199104477Ssam HIFN_DMAIER_ILLW | HIFN_DMAIER_ILLR : 0); 1200104477Ssam sc->sc_dmaier &= ~HIFN_DMAIER_C_WAIT; 1201104477Ssam WRITE_REG_1(sc, HIFN_1_DMA_IER, sc->sc_dmaier); 1202104477Ssam 1203104477Ssam 1204120915Ssam if (sc->sc_flags & HIFN_IS_7956) { 1205140480Ssam u_int32_t pll; 1206140480Ssam 1207120915Ssam WRITE_REG_0(sc, HIFN_0_PUCNFG, HIFN_PUCNFG_COMPSING | 1208120915Ssam HIFN_PUCNFG_TCALLPHASES | 1209120915Ssam HIFN_PUCNFG_TCDRVTOTEM | HIFN_PUCNFG_BUS32); 1210140480Ssam 1211140480Ssam /* turn off the clocks and insure bypass is set */ 1212140480Ssam pll = READ_REG_1(sc, HIFN_1_PLL); 1213140480Ssam pll = (pll &~ (HIFN_PLL_PK_CLK_SEL | HIFN_PLL_PE_CLK_SEL)) 1214167755Ssam | HIFN_PLL_BP | HIFN_PLL_MBSET; 1215140480Ssam WRITE_REG_1(sc, HIFN_1_PLL, pll); 1216140480Ssam DELAY(10*1000); /* 10ms */ 1217167755Ssam 1218140480Ssam /* change configuration */ 1219140480Ssam pll = (pll &~ HIFN_PLL_CONFIG) | sc->sc_pllconfig; 1220140480Ssam WRITE_REG_1(sc, HIFN_1_PLL, pll); 1221140480Ssam DELAY(10*1000); /* 10ms */ 1222167755Ssam 1223140480Ssam /* disable bypass */ 1224140480Ssam pll &= ~HIFN_PLL_BP; 1225140480Ssam WRITE_REG_1(sc, HIFN_1_PLL, pll); 1226140480Ssam /* enable clocks with new configuration */ 1227140480Ssam pll |= HIFN_PLL_PK_CLK_SEL | HIFN_PLL_PE_CLK_SEL; 1228140480Ssam WRITE_REG_1(sc, HIFN_1_PLL, pll); 1229120915Ssam } else { 1230120915Ssam WRITE_REG_0(sc, HIFN_0_PUCNFG, HIFN_PUCNFG_COMPSING | 1231120915Ssam HIFN_PUCNFG_DRFR_128 | HIFN_PUCNFG_TCALLPHASES | 1232120915Ssam HIFN_PUCNFG_TCDRVTOTEM | HIFN_PUCNFG_BUS32 | 1233120915Ssam (sc->sc_drammodel ? HIFN_PUCNFG_DRAM : HIFN_PUCNFG_SRAM)); 1234120915Ssam } 1235120915Ssam 1236104477Ssam WRITE_REG_0(sc, HIFN_0_PUISR, HIFN_PUISR_DSTOVER); 1237104477Ssam WRITE_REG_1(sc, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MSTRESET | 1238104477Ssam HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE | HIFN_DMACNFG_LAST | 1239104477Ssam ((HIFN_POLL_FREQUENCY << 16 ) & HIFN_DMACNFG_POLLFREQ) | 1240104477Ssam ((HIFN_POLL_SCALAR << 8) & HIFN_DMACNFG_POLLINVAL)); 1241104477Ssam} 1242104477Ssam 1243104477Ssam/* 1244104477Ssam * The maximum number of sessions supported by the card 1245104477Ssam * is dependent on the amount of context ram, which 1246104477Ssam * encryption algorithms are enabled, and how compression 1247104477Ssam * is configured. This should be configured before this 1248104477Ssam * routine is called. 1249104477Ssam */ 1250104477Ssamstatic void 1251104477Ssamhifn_sessions(struct hifn_softc *sc) 1252104477Ssam{ 1253104477Ssam u_int32_t pucnfg; 1254104477Ssam int ctxsize; 1255104477Ssam 1256104477Ssam pucnfg = READ_REG_0(sc, HIFN_0_PUCNFG); 1257104477Ssam 1258104477Ssam if (pucnfg & HIFN_PUCNFG_COMPSING) { 1259104477Ssam if (pucnfg & HIFN_PUCNFG_ENCCNFG) 1260104477Ssam ctxsize = 128; 1261104477Ssam else 1262104477Ssam ctxsize = 512; 1263120915Ssam /* 1264120915Ssam * 7955/7956 has internal context memory of 32K 1265120915Ssam */ 1266120915Ssam if (sc->sc_flags & HIFN_IS_7956) 1267120915Ssam sc->sc_maxses = 32768 / ctxsize; 1268120915Ssam else 1269120915Ssam sc->sc_maxses = 1 + 1270120915Ssam ((sc->sc_ramsize - 32768) / ctxsize); 1271104477Ssam } else 1272104477Ssam sc->sc_maxses = sc->sc_ramsize / 16384; 1273104477Ssam 1274104477Ssam if (sc->sc_maxses > 2048) 1275104477Ssam sc->sc_maxses = 2048; 1276104477Ssam} 1277104477Ssam 1278104477Ssam/* 1279104477Ssam * Determine ram type (sram or dram). Board should be just out of a reset 1280104477Ssam * state when this is called. 1281104477Ssam */ 1282104477Ssamstatic int 1283104477Ssamhifn_ramtype(struct hifn_softc *sc) 1284104477Ssam{ 1285104477Ssam u_int8_t data[8], dataexpect[8]; 1286104477Ssam int i; 1287104477Ssam 1288104477Ssam for (i = 0; i < sizeof(data); i++) 1289104477Ssam data[i] = dataexpect[i] = 0x55; 1290104477Ssam if (hifn_writeramaddr(sc, 0, data)) 1291104477Ssam return (-1); 1292104477Ssam if (hifn_readramaddr(sc, 0, data)) 1293104477Ssam return (-1); 1294104477Ssam if (bcmp(data, dataexpect, sizeof(data)) != 0) { 1295104477Ssam sc->sc_drammodel = 1; 1296104477Ssam return (0); 1297104477Ssam } 1298104477Ssam 1299104477Ssam for (i = 0; i < sizeof(data); i++) 1300104477Ssam data[i] = dataexpect[i] = 0xaa; 1301104477Ssam if (hifn_writeramaddr(sc, 0, data)) 1302104477Ssam return (-1); 1303104477Ssam if (hifn_readramaddr(sc, 0, data)) 1304104477Ssam return (-1); 1305104477Ssam if (bcmp(data, dataexpect, sizeof(data)) != 0) { 1306104477Ssam sc->sc_drammodel = 1; 1307104477Ssam return (0); 1308104477Ssam } 1309104477Ssam 1310104477Ssam return (0); 1311104477Ssam} 1312104477Ssam 1313104477Ssam#define HIFN_SRAM_MAX (32 << 20) 1314104477Ssam#define HIFN_SRAM_STEP_SIZE 16384 1315104477Ssam#define HIFN_SRAM_GRANULARITY (HIFN_SRAM_MAX / HIFN_SRAM_STEP_SIZE) 1316104477Ssam 1317104477Ssamstatic int 1318104477Ssamhifn_sramsize(struct hifn_softc *sc) 1319104477Ssam{ 1320104477Ssam u_int32_t a; 1321104477Ssam u_int8_t data[8]; 1322104477Ssam u_int8_t dataexpect[sizeof(data)]; 1323104477Ssam int32_t i; 1324104477Ssam 1325104477Ssam for (i = 0; i < sizeof(data); i++) 1326104477Ssam data[i] = dataexpect[i] = i ^ 0x5a; 1327104477Ssam 1328104477Ssam for (i = HIFN_SRAM_GRANULARITY - 1; i >= 0; i--) { 1329104477Ssam a = i * HIFN_SRAM_STEP_SIZE; 1330104477Ssam bcopy(&i, data, sizeof(i)); 1331104477Ssam hifn_writeramaddr(sc, a, data); 1332104477Ssam } 1333104477Ssam 1334104477Ssam for (i = 0; i < HIFN_SRAM_GRANULARITY; i++) { 1335104477Ssam a = i * HIFN_SRAM_STEP_SIZE; 1336104477Ssam bcopy(&i, dataexpect, sizeof(i)); 1337104477Ssam if (hifn_readramaddr(sc, a, data) < 0) 1338104477Ssam return (0); 1339104477Ssam if (bcmp(data, dataexpect, sizeof(data)) != 0) 1340104477Ssam return (0); 1341104477Ssam sc->sc_ramsize = a + HIFN_SRAM_STEP_SIZE; 1342104477Ssam } 1343104477Ssam 1344104477Ssam return (0); 1345104477Ssam} 1346104477Ssam 1347104477Ssam/* 1348104477Ssam * XXX For dram boards, one should really try all of the 1349104477Ssam * HIFN_PUCNFG_DSZ_*'s. This just assumes that PUCNFG 1350104477Ssam * is already set up correctly. 1351104477Ssam */ 1352104477Ssamstatic int 1353104477Ssamhifn_dramsize(struct hifn_softc *sc) 1354104477Ssam{ 1355104477Ssam u_int32_t cnfg; 1356104477Ssam 1357120915Ssam if (sc->sc_flags & HIFN_IS_7956) { 1358120915Ssam /* 1359120915Ssam * 7955/7956 have a fixed internal ram of only 32K. 1360120915Ssam */ 1361120915Ssam sc->sc_ramsize = 32768; 1362120915Ssam } else { 1363120915Ssam cnfg = READ_REG_0(sc, HIFN_0_PUCNFG) & 1364120915Ssam HIFN_PUCNFG_DRAMMASK; 1365120915Ssam sc->sc_ramsize = 1 << ((cnfg >> 13) + 18); 1366120915Ssam } 1367104477Ssam return (0); 1368104477Ssam} 1369104477Ssam 1370104477Ssamstatic void 1371104477Ssamhifn_alloc_slot(struct hifn_softc *sc, int *cmdp, int *srcp, int *dstp, int *resp) 1372104477Ssam{ 1373104477Ssam struct hifn_dma *dma = sc->sc_dma; 1374104477Ssam 1375213091Sgonzo if (sc->sc_cmdi == HIFN_D_CMD_RSIZE) { 1376213091Sgonzo sc->sc_cmdi = 0; 1377104477Ssam dma->cmdr[HIFN_D_CMD_RSIZE].l = htole32(HIFN_D_VALID | 1378104477Ssam HIFN_D_JUMP | HIFN_D_MASKDONEIRQ); 1379104477Ssam HIFN_CMDR_SYNC(sc, HIFN_D_CMD_RSIZE, 1380104477Ssam BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); 1381104477Ssam } 1382213091Sgonzo *cmdp = sc->sc_cmdi++; 1383213091Sgonzo sc->sc_cmdk = sc->sc_cmdi; 1384104477Ssam 1385213091Sgonzo if (sc->sc_srci == HIFN_D_SRC_RSIZE) { 1386213091Sgonzo sc->sc_srci = 0; 1387104477Ssam dma->srcr[HIFN_D_SRC_RSIZE].l = htole32(HIFN_D_VALID | 1388104477Ssam HIFN_D_JUMP | HIFN_D_MASKDONEIRQ); 1389104477Ssam HIFN_SRCR_SYNC(sc, HIFN_D_SRC_RSIZE, 1390104477Ssam BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); 1391104477Ssam } 1392213091Sgonzo *srcp = sc->sc_srci++; 1393213091Sgonzo sc->sc_srck = sc->sc_srci; 1394104477Ssam 1395213091Sgonzo if (sc->sc_dsti == HIFN_D_DST_RSIZE) { 1396213091Sgonzo sc->sc_dsti = 0; 1397104477Ssam dma->dstr[HIFN_D_DST_RSIZE].l = htole32(HIFN_D_VALID | 1398104477Ssam HIFN_D_JUMP | HIFN_D_MASKDONEIRQ); 1399104477Ssam HIFN_DSTR_SYNC(sc, HIFN_D_DST_RSIZE, 1400104477Ssam BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); 1401104477Ssam } 1402213091Sgonzo *dstp = sc->sc_dsti++; 1403213091Sgonzo sc->sc_dstk = sc->sc_dsti; 1404104477Ssam 1405213091Sgonzo if (sc->sc_resi == HIFN_D_RES_RSIZE) { 1406213091Sgonzo sc->sc_resi = 0; 1407104477Ssam dma->resr[HIFN_D_RES_RSIZE].l = htole32(HIFN_D_VALID | 1408104477Ssam HIFN_D_JUMP | HIFN_D_MASKDONEIRQ); 1409104477Ssam HIFN_RESR_SYNC(sc, HIFN_D_RES_RSIZE, 1410104477Ssam BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); 1411104477Ssam } 1412213091Sgonzo *resp = sc->sc_resi++; 1413213091Sgonzo sc->sc_resk = sc->sc_resi; 1414104477Ssam} 1415104477Ssam 1416104477Ssamstatic int 1417104477Ssamhifn_writeramaddr(struct hifn_softc *sc, int addr, u_int8_t *data) 1418104477Ssam{ 1419104477Ssam struct hifn_dma *dma = sc->sc_dma; 1420104477Ssam hifn_base_command_t wc; 1421104477Ssam const u_int32_t masks = HIFN_D_VALID | HIFN_D_LAST | HIFN_D_MASKDONEIRQ; 1422104477Ssam int r, cmdi, resi, srci, dsti; 1423104477Ssam 1424104477Ssam wc.masks = htole16(3 << 13); 1425104477Ssam wc.session_num = htole16(addr >> 14); 1426104477Ssam wc.total_source_count = htole16(8); 1427104477Ssam wc.total_dest_count = htole16(addr & 0x3fff); 1428104477Ssam 1429104477Ssam hifn_alloc_slot(sc, &cmdi, &srci, &dsti, &resi); 1430104477Ssam 1431104477Ssam WRITE_REG_1(sc, HIFN_1_DMA_CSR, 1432104477Ssam HIFN_DMACSR_C_CTRL_ENA | HIFN_DMACSR_S_CTRL_ENA | 1433104477Ssam HIFN_DMACSR_D_CTRL_ENA | HIFN_DMACSR_R_CTRL_ENA); 1434104477Ssam 1435104477Ssam /* build write command */ 1436104477Ssam bzero(dma->command_bufs[cmdi], HIFN_MAX_COMMAND); 1437104477Ssam *(hifn_base_command_t *)dma->command_bufs[cmdi] = wc; 1438104477Ssam bcopy(data, &dma->test_src, sizeof(dma->test_src)); 1439104477Ssam 1440104477Ssam dma->srcr[srci].p = htole32(sc->sc_dma_physaddr 1441104477Ssam + offsetof(struct hifn_dma, test_src)); 1442104477Ssam dma->dstr[dsti].p = htole32(sc->sc_dma_physaddr 1443104477Ssam + offsetof(struct hifn_dma, test_dst)); 1444104477Ssam 1445104477Ssam dma->cmdr[cmdi].l = htole32(16 | masks); 1446104477Ssam dma->srcr[srci].l = htole32(8 | masks); 1447104477Ssam dma->dstr[dsti].l = htole32(4 | masks); 1448104477Ssam dma->resr[resi].l = htole32(4 | masks); 1449104477Ssam 1450104477Ssam bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, 1451104477Ssam BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1452104477Ssam 1453104477Ssam for (r = 10000; r >= 0; r--) { 1454104477Ssam DELAY(10); 1455104477Ssam bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, 1456104477Ssam BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 1457104477Ssam if ((dma->resr[resi].l & htole32(HIFN_D_VALID)) == 0) 1458104477Ssam break; 1459104477Ssam bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, 1460104477Ssam BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1461104477Ssam } 1462104477Ssam if (r == 0) { 1463104477Ssam device_printf(sc->sc_dev, "writeramaddr -- " 1464104477Ssam "result[%d](addr %d) still valid\n", resi, addr); 1465104477Ssam r = -1; 1466104477Ssam return (-1); 1467104477Ssam } else 1468104477Ssam r = 0; 1469104477Ssam 1470104477Ssam WRITE_REG_1(sc, HIFN_1_DMA_CSR, 1471104477Ssam HIFN_DMACSR_C_CTRL_DIS | HIFN_DMACSR_S_CTRL_DIS | 1472104477Ssam HIFN_DMACSR_D_CTRL_DIS | HIFN_DMACSR_R_CTRL_DIS); 1473104477Ssam 1474104477Ssam return (r); 1475104477Ssam} 1476104477Ssam 1477104477Ssamstatic int 1478104477Ssamhifn_readramaddr(struct hifn_softc *sc, int addr, u_int8_t *data) 1479104477Ssam{ 1480104477Ssam struct hifn_dma *dma = sc->sc_dma; 1481104477Ssam hifn_base_command_t rc; 1482104477Ssam const u_int32_t masks = HIFN_D_VALID | HIFN_D_LAST | HIFN_D_MASKDONEIRQ; 1483104477Ssam int r, cmdi, srci, dsti, resi; 1484104477Ssam 1485104477Ssam rc.masks = htole16(2 << 13); 1486104477Ssam rc.session_num = htole16(addr >> 14); 1487104477Ssam rc.total_source_count = htole16(addr & 0x3fff); 1488104477Ssam rc.total_dest_count = htole16(8); 1489104477Ssam 1490104477Ssam hifn_alloc_slot(sc, &cmdi, &srci, &dsti, &resi); 1491104477Ssam 1492104477Ssam WRITE_REG_1(sc, HIFN_1_DMA_CSR, 1493104477Ssam HIFN_DMACSR_C_CTRL_ENA | HIFN_DMACSR_S_CTRL_ENA | 1494104477Ssam HIFN_DMACSR_D_CTRL_ENA | HIFN_DMACSR_R_CTRL_ENA); 1495104477Ssam 1496104477Ssam bzero(dma->command_bufs[cmdi], HIFN_MAX_COMMAND); 1497104477Ssam *(hifn_base_command_t *)dma->command_bufs[cmdi] = rc; 1498104477Ssam 1499104477Ssam dma->srcr[srci].p = htole32(sc->sc_dma_physaddr + 1500104477Ssam offsetof(struct hifn_dma, test_src)); 1501104477Ssam dma->test_src = 0; 1502104477Ssam dma->dstr[dsti].p = htole32(sc->sc_dma_physaddr + 1503104477Ssam offsetof(struct hifn_dma, test_dst)); 1504104477Ssam dma->test_dst = 0; 1505104477Ssam dma->cmdr[cmdi].l = htole32(8 | masks); 1506104477Ssam dma->srcr[srci].l = htole32(8 | masks); 1507104477Ssam dma->dstr[dsti].l = htole32(8 | masks); 1508104477Ssam dma->resr[resi].l = htole32(HIFN_MAX_RESULT | masks); 1509104477Ssam 1510104477Ssam bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, 1511104477Ssam BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1512104477Ssam 1513104477Ssam for (r = 10000; r >= 0; r--) { 1514104477Ssam DELAY(10); 1515104477Ssam bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, 1516104477Ssam BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 1517104477Ssam if ((dma->resr[resi].l & htole32(HIFN_D_VALID)) == 0) 1518104477Ssam break; 1519104477Ssam bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, 1520104477Ssam BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1521104477Ssam } 1522104477Ssam if (r == 0) { 1523104477Ssam device_printf(sc->sc_dev, "readramaddr -- " 1524104477Ssam "result[%d](addr %d) still valid\n", resi, addr); 1525104477Ssam r = -1; 1526104477Ssam } else { 1527104477Ssam r = 0; 1528104477Ssam bcopy(&dma->test_dst, data, sizeof(dma->test_dst)); 1529104477Ssam } 1530104477Ssam 1531104477Ssam WRITE_REG_1(sc, HIFN_1_DMA_CSR, 1532104477Ssam HIFN_DMACSR_C_CTRL_DIS | HIFN_DMACSR_S_CTRL_DIS | 1533104477Ssam HIFN_DMACSR_D_CTRL_DIS | HIFN_DMACSR_R_CTRL_DIS); 1534104477Ssam 1535104477Ssam return (r); 1536104477Ssam} 1537104477Ssam 1538104477Ssam/* 1539104477Ssam * Initialize the descriptor rings. 1540104477Ssam */ 1541104477Ssamstatic void 1542104477Ssamhifn_init_dma(struct hifn_softc *sc) 1543104477Ssam{ 1544104477Ssam struct hifn_dma *dma = sc->sc_dma; 1545104477Ssam int i; 1546104477Ssam 1547104477Ssam hifn_set_retry(sc); 1548104477Ssam 1549104477Ssam /* initialize static pointer values */ 1550104477Ssam for (i = 0; i < HIFN_D_CMD_RSIZE; i++) 1551104477Ssam dma->cmdr[i].p = htole32(sc->sc_dma_physaddr + 1552104477Ssam offsetof(struct hifn_dma, command_bufs[i][0])); 1553104477Ssam for (i = 0; i < HIFN_D_RES_RSIZE; i++) 1554104477Ssam dma->resr[i].p = htole32(sc->sc_dma_physaddr + 1555104477Ssam offsetof(struct hifn_dma, result_bufs[i][0])); 1556104477Ssam 1557104477Ssam dma->cmdr[HIFN_D_CMD_RSIZE].p = 1558104477Ssam htole32(sc->sc_dma_physaddr + offsetof(struct hifn_dma, cmdr[0])); 1559104477Ssam dma->srcr[HIFN_D_SRC_RSIZE].p = 1560104477Ssam htole32(sc->sc_dma_physaddr + offsetof(struct hifn_dma, srcr[0])); 1561104477Ssam dma->dstr[HIFN_D_DST_RSIZE].p = 1562104477Ssam htole32(sc->sc_dma_physaddr + offsetof(struct hifn_dma, dstr[0])); 1563104477Ssam dma->resr[HIFN_D_RES_RSIZE].p = 1564104477Ssam htole32(sc->sc_dma_physaddr + offsetof(struct hifn_dma, resr[0])); 1565104477Ssam 1566213091Sgonzo sc->sc_cmdu = sc->sc_srcu = sc->sc_dstu = sc->sc_resu = 0; 1567213091Sgonzo sc->sc_cmdi = sc->sc_srci = sc->sc_dsti = sc->sc_resi = 0; 1568213091Sgonzo sc->sc_cmdk = sc->sc_srck = sc->sc_dstk = sc->sc_resk = 0; 1569104477Ssam} 1570104477Ssam 1571104477Ssam/* 1572104477Ssam * Writes out the raw command buffer space. Returns the 1573104477Ssam * command buffer size. 1574104477Ssam */ 1575104477Ssamstatic u_int 1576104477Ssamhifn_write_command(struct hifn_command *cmd, u_int8_t *buf) 1577104477Ssam{ 1578104477Ssam u_int8_t *buf_pos; 1579104477Ssam hifn_base_command_t *base_cmd; 1580104477Ssam hifn_mac_command_t *mac_cmd; 1581104477Ssam hifn_crypt_command_t *cry_cmd; 1582120915Ssam int using_mac, using_crypt, len, ivlen; 1583104477Ssam u_int32_t dlen, slen; 1584104477Ssam 1585104477Ssam buf_pos = buf; 1586104477Ssam using_mac = cmd->base_masks & HIFN_BASE_CMD_MAC; 1587104477Ssam using_crypt = cmd->base_masks & HIFN_BASE_CMD_CRYPT; 1588104477Ssam 1589104477Ssam base_cmd = (hifn_base_command_t *)buf_pos; 1590104477Ssam base_cmd->masks = htole16(cmd->base_masks); 1591104477Ssam slen = cmd->src_mapsize; 1592104477Ssam if (cmd->sloplen) 1593104477Ssam dlen = cmd->dst_mapsize - cmd->sloplen + sizeof(u_int32_t); 1594104477Ssam else 1595104477Ssam dlen = cmd->dst_mapsize; 1596104477Ssam base_cmd->total_source_count = htole16(slen & HIFN_BASE_CMD_LENMASK_LO); 1597104477Ssam base_cmd->total_dest_count = htole16(dlen & HIFN_BASE_CMD_LENMASK_LO); 1598104477Ssam dlen >>= 16; 1599104477Ssam slen >>= 16; 1600136526Ssam base_cmd->session_num = htole16( 1601104477Ssam ((slen << HIFN_BASE_CMD_SRCLEN_S) & HIFN_BASE_CMD_SRCLEN_M) | 1602104477Ssam ((dlen << HIFN_BASE_CMD_DSTLEN_S) & HIFN_BASE_CMD_DSTLEN_M)); 1603104477Ssam buf_pos += sizeof(hifn_base_command_t); 1604104477Ssam 1605104477Ssam if (using_mac) { 1606104477Ssam mac_cmd = (hifn_mac_command_t *)buf_pos; 1607104477Ssam dlen = cmd->maccrd->crd_len; 1608104477Ssam mac_cmd->source_count = htole16(dlen & 0xffff); 1609104477Ssam dlen >>= 16; 1610104477Ssam mac_cmd->masks = htole16(cmd->mac_masks | 1611104477Ssam ((dlen << HIFN_MAC_CMD_SRCLEN_S) & HIFN_MAC_CMD_SRCLEN_M)); 1612104477Ssam mac_cmd->header_skip = htole16(cmd->maccrd->crd_skip); 1613104477Ssam mac_cmd->reserved = 0; 1614104477Ssam buf_pos += sizeof(hifn_mac_command_t); 1615104477Ssam } 1616104477Ssam 1617104477Ssam if (using_crypt) { 1618104477Ssam cry_cmd = (hifn_crypt_command_t *)buf_pos; 1619104477Ssam dlen = cmd->enccrd->crd_len; 1620104477Ssam cry_cmd->source_count = htole16(dlen & 0xffff); 1621104477Ssam dlen >>= 16; 1622104477Ssam cry_cmd->masks = htole16(cmd->cry_masks | 1623104477Ssam ((dlen << HIFN_CRYPT_CMD_SRCLEN_S) & HIFN_CRYPT_CMD_SRCLEN_M)); 1624104477Ssam cry_cmd->header_skip = htole16(cmd->enccrd->crd_skip); 1625104477Ssam cry_cmd->reserved = 0; 1626104477Ssam buf_pos += sizeof(hifn_crypt_command_t); 1627104477Ssam } 1628104477Ssam 1629104477Ssam if (using_mac && cmd->mac_masks & HIFN_MAC_CMD_NEW_KEY) { 1630104477Ssam bcopy(cmd->mac, buf_pos, HIFN_MAC_KEY_LENGTH); 1631104477Ssam buf_pos += HIFN_MAC_KEY_LENGTH; 1632104477Ssam } 1633104477Ssam 1634104477Ssam if (using_crypt && cmd->cry_masks & HIFN_CRYPT_CMD_NEW_KEY) { 1635104477Ssam switch (cmd->cry_masks & HIFN_CRYPT_CMD_ALG_MASK) { 1636104477Ssam case HIFN_CRYPT_CMD_ALG_3DES: 1637104477Ssam bcopy(cmd->ck, buf_pos, HIFN_3DES_KEY_LENGTH); 1638104477Ssam buf_pos += HIFN_3DES_KEY_LENGTH; 1639104477Ssam break; 1640104477Ssam case HIFN_CRYPT_CMD_ALG_DES: 1641104477Ssam bcopy(cmd->ck, buf_pos, HIFN_DES_KEY_LENGTH); 1642120915Ssam buf_pos += HIFN_DES_KEY_LENGTH; 1643104477Ssam break; 1644104477Ssam case HIFN_CRYPT_CMD_ALG_RC4: 1645104477Ssam len = 256; 1646104477Ssam do { 1647104477Ssam int clen; 1648104477Ssam 1649104477Ssam clen = MIN(cmd->cklen, len); 1650104477Ssam bcopy(cmd->ck, buf_pos, clen); 1651104477Ssam len -= clen; 1652104477Ssam buf_pos += clen; 1653104477Ssam } while (len > 0); 1654104477Ssam bzero(buf_pos, 4); 1655104477Ssam buf_pos += 4; 1656104477Ssam break; 1657120915Ssam case HIFN_CRYPT_CMD_ALG_AES: 1658120915Ssam /* 1659120915Ssam * AES keys are variable 128, 192 and 1660120915Ssam * 256 bits (16, 24 and 32 bytes). 1661120915Ssam */ 1662120915Ssam bcopy(cmd->ck, buf_pos, cmd->cklen); 1663120915Ssam buf_pos += cmd->cklen; 1664120915Ssam break; 1665104477Ssam } 1666104477Ssam } 1667104477Ssam 1668104477Ssam if (using_crypt && cmd->cry_masks & HIFN_CRYPT_CMD_NEW_IV) { 1669120915Ssam switch (cmd->cry_masks & HIFN_CRYPT_CMD_ALG_MASK) { 1670120915Ssam case HIFN_CRYPT_CMD_ALG_AES: 1671120915Ssam ivlen = HIFN_AES_IV_LENGTH; 1672120915Ssam break; 1673120915Ssam default: 1674120915Ssam ivlen = HIFN_IV_LENGTH; 1675120915Ssam break; 1676120915Ssam } 1677120915Ssam bcopy(cmd->iv, buf_pos, ivlen); 1678120915Ssam buf_pos += ivlen; 1679104477Ssam } 1680104477Ssam 1681104477Ssam if ((cmd->base_masks & (HIFN_BASE_CMD_MAC|HIFN_BASE_CMD_CRYPT)) == 0) { 1682104477Ssam bzero(buf_pos, 8); 1683104477Ssam buf_pos += 8; 1684104477Ssam } 1685104477Ssam 1686104477Ssam return (buf_pos - buf); 1687104477Ssam} 1688104477Ssam 1689104477Ssamstatic int 1690104477Ssamhifn_dmamap_aligned(struct hifn_operand *op) 1691104477Ssam{ 1692104477Ssam int i; 1693104477Ssam 1694104477Ssam for (i = 0; i < op->nsegs; i++) { 1695104477Ssam if (op->segs[i].ds_addr & 3) 1696104477Ssam return (0); 1697104477Ssam if ((i != (op->nsegs - 1)) && (op->segs[i].ds_len & 3)) 1698104477Ssam return (0); 1699104477Ssam } 1700104477Ssam return (1); 1701104477Ssam} 1702104477Ssam 1703167755Ssamstatic __inline int 1704167755Ssamhifn_dmamap_dstwrap(struct hifn_softc *sc, int idx) 1705167755Ssam{ 1706167755Ssam struct hifn_dma *dma = sc->sc_dma; 1707167755Ssam 1708167755Ssam if (++idx == HIFN_D_DST_RSIZE) { 1709167755Ssam dma->dstr[idx].l = htole32(HIFN_D_VALID | HIFN_D_JUMP | 1710167755Ssam HIFN_D_MASKDONEIRQ); 1711167755Ssam HIFN_DSTR_SYNC(sc, idx, 1712167755Ssam BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1713167755Ssam idx = 0; 1714167755Ssam } 1715167755Ssam return (idx); 1716167755Ssam} 1717167755Ssam 1718104477Ssamstatic int 1719104477Ssamhifn_dmamap_load_dst(struct hifn_softc *sc, struct hifn_command *cmd) 1720104477Ssam{ 1721104477Ssam struct hifn_dma *dma = sc->sc_dma; 1722104477Ssam struct hifn_operand *dst = &cmd->dst; 1723104477Ssam u_int32_t p, l; 1724104477Ssam int idx, used = 0, i; 1725104477Ssam 1726213091Sgonzo idx = sc->sc_dsti; 1727104477Ssam for (i = 0; i < dst->nsegs - 1; i++) { 1728104477Ssam dma->dstr[idx].p = htole32(dst->segs[i].ds_addr); 1729104477Ssam dma->dstr[idx].l = htole32(HIFN_D_VALID | 1730104477Ssam HIFN_D_MASKDONEIRQ | dst->segs[i].ds_len); 1731104477Ssam HIFN_DSTR_SYNC(sc, idx, 1732104477Ssam BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1733104477Ssam used++; 1734104477Ssam 1735167755Ssam idx = hifn_dmamap_dstwrap(sc, idx); 1736104477Ssam } 1737104477Ssam 1738104477Ssam if (cmd->sloplen == 0) { 1739104477Ssam p = dst->segs[i].ds_addr; 1740104477Ssam l = HIFN_D_VALID | HIFN_D_MASKDONEIRQ | HIFN_D_LAST | 1741104477Ssam dst->segs[i].ds_len; 1742104477Ssam } else { 1743104477Ssam p = sc->sc_dma_physaddr + 1744104477Ssam offsetof(struct hifn_dma, slop[cmd->slopidx]); 1745104477Ssam l = HIFN_D_VALID | HIFN_D_MASKDONEIRQ | HIFN_D_LAST | 1746104477Ssam sizeof(u_int32_t); 1747104477Ssam 1748104477Ssam if ((dst->segs[i].ds_len - cmd->sloplen) != 0) { 1749104477Ssam dma->dstr[idx].p = htole32(dst->segs[i].ds_addr); 1750104477Ssam dma->dstr[idx].l = htole32(HIFN_D_VALID | 1751104477Ssam HIFN_D_MASKDONEIRQ | 1752104477Ssam (dst->segs[i].ds_len - cmd->sloplen)); 1753104477Ssam HIFN_DSTR_SYNC(sc, idx, 1754104477Ssam BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1755104477Ssam used++; 1756104477Ssam 1757167755Ssam idx = hifn_dmamap_dstwrap(sc, idx); 1758104477Ssam } 1759104477Ssam } 1760104477Ssam dma->dstr[idx].p = htole32(p); 1761104477Ssam dma->dstr[idx].l = htole32(l); 1762104477Ssam HIFN_DSTR_SYNC(sc, idx, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1763104477Ssam used++; 1764104477Ssam 1765167755Ssam idx = hifn_dmamap_dstwrap(sc, idx); 1766104477Ssam 1767213091Sgonzo sc->sc_dsti = idx; 1768213091Sgonzo sc->sc_dstu += used; 1769104477Ssam return (idx); 1770104477Ssam} 1771104477Ssam 1772167755Ssamstatic __inline int 1773167755Ssamhifn_dmamap_srcwrap(struct hifn_softc *sc, int idx) 1774167755Ssam{ 1775167755Ssam struct hifn_dma *dma = sc->sc_dma; 1776167755Ssam 1777167755Ssam if (++idx == HIFN_D_SRC_RSIZE) { 1778167755Ssam dma->srcr[idx].l = htole32(HIFN_D_VALID | 1779167755Ssam HIFN_D_JUMP | HIFN_D_MASKDONEIRQ); 1780167755Ssam HIFN_SRCR_SYNC(sc, HIFN_D_SRC_RSIZE, 1781167755Ssam BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); 1782167755Ssam idx = 0; 1783167755Ssam } 1784167755Ssam return (idx); 1785167755Ssam} 1786167755Ssam 1787104477Ssamstatic int 1788104477Ssamhifn_dmamap_load_src(struct hifn_softc *sc, struct hifn_command *cmd) 1789104477Ssam{ 1790104477Ssam struct hifn_dma *dma = sc->sc_dma; 1791104477Ssam struct hifn_operand *src = &cmd->src; 1792104477Ssam int idx, i; 1793104477Ssam u_int32_t last = 0; 1794104477Ssam 1795213091Sgonzo idx = sc->sc_srci; 1796104477Ssam for (i = 0; i < src->nsegs; i++) { 1797104477Ssam if (i == src->nsegs - 1) 1798104477Ssam last = HIFN_D_LAST; 1799104477Ssam 1800104477Ssam dma->srcr[idx].p = htole32(src->segs[i].ds_addr); 1801104477Ssam dma->srcr[idx].l = htole32(src->segs[i].ds_len | 1802104477Ssam HIFN_D_VALID | HIFN_D_MASKDONEIRQ | last); 1803104477Ssam HIFN_SRCR_SYNC(sc, idx, 1804104477Ssam BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); 1805104477Ssam 1806167755Ssam idx = hifn_dmamap_srcwrap(sc, idx); 1807104477Ssam } 1808213091Sgonzo sc->sc_srci = idx; 1809213091Sgonzo sc->sc_srcu += src->nsegs; 1810104477Ssam return (idx); 1811104477Ssam} 1812104477Ssam 1813104477Ssamstatic void 1814104477Ssamhifn_op_cb(void* arg, bus_dma_segment_t *seg, int nsegs, bus_size_t mapsize, int error) 1815104477Ssam{ 1816104477Ssam struct hifn_operand *op = arg; 1817104477Ssam 1818104477Ssam KASSERT(nsegs <= MAX_SCATTER, 1819104477Ssam ("hifn_op_cb: too many DMA segments (%u > %u) " 1820104477Ssam "returned when mapping operand", nsegs, MAX_SCATTER)); 1821104477Ssam op->mapsize = mapsize; 1822104477Ssam op->nsegs = nsegs; 1823104477Ssam bcopy(seg, op->segs, nsegs * sizeof (seg[0])); 1824104477Ssam} 1825104477Ssam 1826104477Ssamstatic int 1827104477Ssamhifn_crypto( 1828104477Ssam struct hifn_softc *sc, 1829104477Ssam struct hifn_command *cmd, 1830104477Ssam struct cryptop *crp, 1831104477Ssam int hint) 1832104477Ssam{ 1833104477Ssam struct hifn_dma *dma = sc->sc_dma; 1834167755Ssam u_int32_t cmdlen, csr; 1835104477Ssam int cmdi, resi, err = 0; 1836104477Ssam 1837104477Ssam /* 1838104477Ssam * need 1 cmd, and 1 res 1839104477Ssam * 1840104477Ssam * NB: check this first since it's easy. 1841104477Ssam */ 1842115748Ssam HIFN_LOCK(sc); 1843213091Sgonzo if ((sc->sc_cmdu + 1) > HIFN_D_CMD_RSIZE || 1844213091Sgonzo (sc->sc_resu + 1) > HIFN_D_RES_RSIZE) { 1845104477Ssam#ifdef HIFN_DEBUG 1846104477Ssam if (hifn_debug) { 1847104477Ssam device_printf(sc->sc_dev, 1848104477Ssam "cmd/result exhaustion, cmdu %u resu %u\n", 1849213091Sgonzo sc->sc_cmdu, sc->sc_resu); 1850104477Ssam } 1851104477Ssam#endif 1852104477Ssam hifnstats.hst_nomem_cr++; 1853115748Ssam HIFN_UNLOCK(sc); 1854104477Ssam return (ERESTART); 1855104477Ssam } 1856104477Ssam 1857104477Ssam if (bus_dmamap_create(sc->sc_dmat, BUS_DMA_NOWAIT, &cmd->src_map)) { 1858104477Ssam hifnstats.hst_nomem_map++; 1859115748Ssam HIFN_UNLOCK(sc); 1860104477Ssam return (ENOMEM); 1861104477Ssam } 1862104477Ssam 1863104477Ssam if (crp->crp_flags & CRYPTO_F_IMBUF) { 1864104477Ssam if (bus_dmamap_load_mbuf(sc->sc_dmat, cmd->src_map, 1865104477Ssam cmd->src_m, hifn_op_cb, &cmd->src, BUS_DMA_NOWAIT)) { 1866104477Ssam hifnstats.hst_nomem_load++; 1867104477Ssam err = ENOMEM; 1868104477Ssam goto err_srcmap1; 1869104477Ssam } 1870104477Ssam } else if (crp->crp_flags & CRYPTO_F_IOV) { 1871104477Ssam if (bus_dmamap_load_uio(sc->sc_dmat, cmd->src_map, 1872104477Ssam cmd->src_io, hifn_op_cb, &cmd->src, BUS_DMA_NOWAIT)) { 1873104477Ssam hifnstats.hst_nomem_load++; 1874104477Ssam err = ENOMEM; 1875104477Ssam goto err_srcmap1; 1876104477Ssam } 1877104477Ssam } else { 1878104477Ssam err = EINVAL; 1879104477Ssam goto err_srcmap1; 1880104477Ssam } 1881104477Ssam 1882104477Ssam if (hifn_dmamap_aligned(&cmd->src)) { 1883104477Ssam cmd->sloplen = cmd->src_mapsize & 3; 1884104477Ssam cmd->dst = cmd->src; 1885104477Ssam } else { 1886104477Ssam if (crp->crp_flags & CRYPTO_F_IOV) { 1887104477Ssam err = EINVAL; 1888104477Ssam goto err_srcmap; 1889104477Ssam } else if (crp->crp_flags & CRYPTO_F_IMBUF) { 1890104477Ssam int totlen, len; 1891104477Ssam struct mbuf *m, *m0, *mlast; 1892104477Ssam 1893104477Ssam KASSERT(cmd->dst_m == cmd->src_m, 1894104477Ssam ("hifn_crypto: dst_m initialized improperly")); 1895104477Ssam hifnstats.hst_unaligned++; 1896104477Ssam /* 1897104477Ssam * Source is not aligned on a longword boundary. 1898104477Ssam * Copy the data to insure alignment. If we fail 1899104477Ssam * to allocate mbufs or clusters while doing this 1900104477Ssam * we return ERESTART so the operation is requeued 1901104477Ssam * at the crypto later, but only if there are 1902104477Ssam * ops already posted to the hardware; otherwise we 1903104477Ssam * have no guarantee that we'll be re-entered. 1904104477Ssam */ 1905104477Ssam totlen = cmd->src_mapsize; 1906104477Ssam if (cmd->src_m->m_flags & M_PKTHDR) { 1907104477Ssam len = MHLEN; 1908111119Simp MGETHDR(m0, M_DONTWAIT, MT_DATA); 1909111119Simp if (m0 && !m_dup_pkthdr(m0, cmd->src_m, M_DONTWAIT)) { 1910108466Ssam m_free(m0); 1911108466Ssam m0 = NULL; 1912108466Ssam } 1913104477Ssam } else { 1914104477Ssam len = MLEN; 1915111119Simp MGET(m0, M_DONTWAIT, MT_DATA); 1916104477Ssam } 1917104477Ssam if (m0 == NULL) { 1918104477Ssam hifnstats.hst_nomem_mbuf++; 1919213091Sgonzo err = sc->sc_cmdu ? ERESTART : ENOMEM; 1920104477Ssam goto err_srcmap; 1921104477Ssam } 1922104477Ssam if (totlen >= MINCLSIZE) { 1923111119Simp MCLGET(m0, M_DONTWAIT); 1924104477Ssam if ((m0->m_flags & M_EXT) == 0) { 1925104477Ssam hifnstats.hst_nomem_mcl++; 1926213091Sgonzo err = sc->sc_cmdu ? ERESTART : ENOMEM; 1927104477Ssam m_freem(m0); 1928104477Ssam goto err_srcmap; 1929104477Ssam } 1930104477Ssam len = MCLBYTES; 1931104477Ssam } 1932104477Ssam totlen -= len; 1933104477Ssam m0->m_pkthdr.len = m0->m_len = len; 1934104477Ssam mlast = m0; 1935104477Ssam 1936104477Ssam while (totlen > 0) { 1937111119Simp MGET(m, M_DONTWAIT, MT_DATA); 1938104477Ssam if (m == NULL) { 1939104477Ssam hifnstats.hst_nomem_mbuf++; 1940213091Sgonzo err = sc->sc_cmdu ? ERESTART : ENOMEM; 1941104477Ssam m_freem(m0); 1942104477Ssam goto err_srcmap; 1943104477Ssam } 1944104477Ssam len = MLEN; 1945104477Ssam if (totlen >= MINCLSIZE) { 1946111119Simp MCLGET(m, M_DONTWAIT); 1947104477Ssam if ((m->m_flags & M_EXT) == 0) { 1948104477Ssam hifnstats.hst_nomem_mcl++; 1949213091Sgonzo err = sc->sc_cmdu ? ERESTART : ENOMEM; 1950104477Ssam mlast->m_next = m; 1951104477Ssam m_freem(m0); 1952104477Ssam goto err_srcmap; 1953104477Ssam } 1954104477Ssam len = MCLBYTES; 1955104477Ssam } 1956104477Ssam 1957104477Ssam m->m_len = len; 1958104477Ssam m0->m_pkthdr.len += len; 1959104477Ssam totlen -= len; 1960104477Ssam 1961104477Ssam mlast->m_next = m; 1962104477Ssam mlast = m; 1963104477Ssam } 1964104477Ssam cmd->dst_m = m0; 1965104477Ssam } 1966104477Ssam } 1967104477Ssam 1968104477Ssam if (cmd->dst_map == NULL) { 1969104477Ssam if (bus_dmamap_create(sc->sc_dmat, BUS_DMA_NOWAIT, &cmd->dst_map)) { 1970104477Ssam hifnstats.hst_nomem_map++; 1971104477Ssam err = ENOMEM; 1972104477Ssam goto err_srcmap; 1973104477Ssam } 1974104477Ssam if (crp->crp_flags & CRYPTO_F_IMBUF) { 1975104477Ssam if (bus_dmamap_load_mbuf(sc->sc_dmat, cmd->dst_map, 1976104477Ssam cmd->dst_m, hifn_op_cb, &cmd->dst, BUS_DMA_NOWAIT)) { 1977104477Ssam hifnstats.hst_nomem_map++; 1978104477Ssam err = ENOMEM; 1979104477Ssam goto err_dstmap1; 1980104477Ssam } 1981104477Ssam } else if (crp->crp_flags & CRYPTO_F_IOV) { 1982104477Ssam if (bus_dmamap_load_uio(sc->sc_dmat, cmd->dst_map, 1983104477Ssam cmd->dst_io, hifn_op_cb, &cmd->dst, BUS_DMA_NOWAIT)) { 1984104477Ssam hifnstats.hst_nomem_load++; 1985104477Ssam err = ENOMEM; 1986104477Ssam goto err_dstmap1; 1987104477Ssam } 1988104477Ssam } 1989104477Ssam } 1990104477Ssam 1991104477Ssam#ifdef HIFN_DEBUG 1992104477Ssam if (hifn_debug) { 1993104477Ssam device_printf(sc->sc_dev, 1994104477Ssam "Entering cmd: stat %8x ien %8x u %d/%d/%d/%d n %d/%d\n", 1995104477Ssam READ_REG_1(sc, HIFN_1_DMA_CSR), 1996104477Ssam READ_REG_1(sc, HIFN_1_DMA_IER), 1997213091Sgonzo sc->sc_cmdu, sc->sc_srcu, sc->sc_dstu, sc->sc_resu, 1998104477Ssam cmd->src_nsegs, cmd->dst_nsegs); 1999104477Ssam } 2000104477Ssam#endif 2001104477Ssam 2002104477Ssam if (cmd->src_map == cmd->dst_map) { 2003104477Ssam bus_dmamap_sync(sc->sc_dmat, cmd->src_map, 2004104477Ssam BUS_DMASYNC_PREWRITE|BUS_DMASYNC_PREREAD); 2005104477Ssam } else { 2006104477Ssam bus_dmamap_sync(sc->sc_dmat, cmd->src_map, 2007104477Ssam BUS_DMASYNC_PREWRITE); 2008104477Ssam bus_dmamap_sync(sc->sc_dmat, cmd->dst_map, 2009104477Ssam BUS_DMASYNC_PREREAD); 2010104477Ssam } 2011104477Ssam 2012104477Ssam /* 2013104477Ssam * need N src, and N dst 2014104477Ssam */ 2015213091Sgonzo if ((sc->sc_srcu + cmd->src_nsegs) > HIFN_D_SRC_RSIZE || 2016213091Sgonzo (sc->sc_dstu + cmd->dst_nsegs + 1) > HIFN_D_DST_RSIZE) { 2017104477Ssam#ifdef HIFN_DEBUG 2018104477Ssam if (hifn_debug) { 2019104477Ssam device_printf(sc->sc_dev, 2020104477Ssam "src/dst exhaustion, srcu %u+%u dstu %u+%u\n", 2021213091Sgonzo sc->sc_srcu, cmd->src_nsegs, 2022213091Sgonzo sc->sc_dstu, cmd->dst_nsegs); 2023104477Ssam } 2024104477Ssam#endif 2025104477Ssam hifnstats.hst_nomem_sd++; 2026104477Ssam err = ERESTART; 2027104477Ssam goto err_dstmap; 2028104477Ssam } 2029104477Ssam 2030213091Sgonzo if (sc->sc_cmdi == HIFN_D_CMD_RSIZE) { 2031213091Sgonzo sc->sc_cmdi = 0; 2032104477Ssam dma->cmdr[HIFN_D_CMD_RSIZE].l = htole32(HIFN_D_VALID | 2033104477Ssam HIFN_D_JUMP | HIFN_D_MASKDONEIRQ); 2034104477Ssam HIFN_CMDR_SYNC(sc, HIFN_D_CMD_RSIZE, 2035104477Ssam BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); 2036104477Ssam } 2037213091Sgonzo cmdi = sc->sc_cmdi++; 2038104477Ssam cmdlen = hifn_write_command(cmd, dma->command_bufs[cmdi]); 2039104477Ssam HIFN_CMD_SYNC(sc, cmdi, BUS_DMASYNC_PREWRITE); 2040104477Ssam 2041104477Ssam /* .p for command/result already set */ 2042104477Ssam dma->cmdr[cmdi].l = htole32(cmdlen | HIFN_D_VALID | HIFN_D_LAST | 2043104477Ssam HIFN_D_MASKDONEIRQ); 2044104477Ssam HIFN_CMDR_SYNC(sc, cmdi, 2045104477Ssam BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); 2046213091Sgonzo sc->sc_cmdu++; 2047104477Ssam 2048104477Ssam /* 2049104477Ssam * We don't worry about missing an interrupt (which a "command wait" 2050104477Ssam * interrupt salvages us from), unless there is more than one command 2051104477Ssam * in the queue. 2052104477Ssam */ 2053213091Sgonzo if (sc->sc_cmdu > 1) { 2054104477Ssam sc->sc_dmaier |= HIFN_DMAIER_C_WAIT; 2055104477Ssam WRITE_REG_1(sc, HIFN_1_DMA_IER, sc->sc_dmaier); 2056104477Ssam } 2057104477Ssam 2058104477Ssam hifnstats.hst_ipackets++; 2059104477Ssam hifnstats.hst_ibytes += cmd->src_mapsize; 2060104477Ssam 2061104477Ssam hifn_dmamap_load_src(sc, cmd); 2062104477Ssam 2063104477Ssam /* 2064104477Ssam * Unlike other descriptors, we don't mask done interrupt from 2065104477Ssam * result descriptor. 2066104477Ssam */ 2067104477Ssam#ifdef HIFN_DEBUG 2068104477Ssam if (hifn_debug) 2069104477Ssam printf("load res\n"); 2070104477Ssam#endif 2071213091Sgonzo if (sc->sc_resi == HIFN_D_RES_RSIZE) { 2072213091Sgonzo sc->sc_resi = 0; 2073104477Ssam dma->resr[HIFN_D_RES_RSIZE].l = htole32(HIFN_D_VALID | 2074104477Ssam HIFN_D_JUMP | HIFN_D_MASKDONEIRQ); 2075104477Ssam HIFN_RESR_SYNC(sc, HIFN_D_RES_RSIZE, 2076104477Ssam BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 2077104477Ssam } 2078213091Sgonzo resi = sc->sc_resi++; 2079213091Sgonzo KASSERT(sc->sc_hifn_commands[resi] == NULL, 2080104477Ssam ("hifn_crypto: command slot %u busy", resi)); 2081213091Sgonzo sc->sc_hifn_commands[resi] = cmd; 2082104477Ssam HIFN_RES_SYNC(sc, resi, BUS_DMASYNC_PREREAD); 2083104477Ssam if ((hint & CRYPTO_HINT_MORE) && sc->sc_curbatch < hifn_maxbatch) { 2084104477Ssam dma->resr[resi].l = htole32(HIFN_MAX_RESULT | 2085104477Ssam HIFN_D_VALID | HIFN_D_LAST | HIFN_D_MASKDONEIRQ); 2086104477Ssam sc->sc_curbatch++; 2087104477Ssam if (sc->sc_curbatch > hifnstats.hst_maxbatch) 2088104477Ssam hifnstats.hst_maxbatch = sc->sc_curbatch; 2089104477Ssam hifnstats.hst_totbatch++; 2090104477Ssam } else { 2091104477Ssam dma->resr[resi].l = htole32(HIFN_MAX_RESULT | 2092104477Ssam HIFN_D_VALID | HIFN_D_LAST); 2093104477Ssam sc->sc_curbatch = 0; 2094104477Ssam } 2095104477Ssam HIFN_RESR_SYNC(sc, resi, 2096104477Ssam BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 2097213091Sgonzo sc->sc_resu++; 2098104477Ssam 2099104477Ssam if (cmd->sloplen) 2100104477Ssam cmd->slopidx = resi; 2101104477Ssam 2102104477Ssam hifn_dmamap_load_dst(sc, cmd); 2103104477Ssam 2104167755Ssam csr = 0; 2105167755Ssam if (sc->sc_c_busy == 0) { 2106167755Ssam csr |= HIFN_DMACSR_C_CTRL_ENA; 2107167755Ssam sc->sc_c_busy = 1; 2108167755Ssam } 2109167755Ssam if (sc->sc_s_busy == 0) { 2110167755Ssam csr |= HIFN_DMACSR_S_CTRL_ENA; 2111167755Ssam sc->sc_s_busy = 1; 2112167755Ssam } 2113167755Ssam if (sc->sc_r_busy == 0) { 2114167755Ssam csr |= HIFN_DMACSR_R_CTRL_ENA; 2115167755Ssam sc->sc_r_busy = 1; 2116167755Ssam } 2117104477Ssam if (sc->sc_d_busy == 0) { 2118167755Ssam csr |= HIFN_DMACSR_D_CTRL_ENA; 2119104477Ssam sc->sc_d_busy = 1; 2120104477Ssam } 2121167755Ssam if (csr) 2122167755Ssam WRITE_REG_1(sc, HIFN_1_DMA_CSR, csr); 2123104477Ssam 2124104477Ssam#ifdef HIFN_DEBUG 2125104477Ssam if (hifn_debug) { 2126104477Ssam device_printf(sc->sc_dev, "command: stat %8x ier %8x\n", 2127104477Ssam READ_REG_1(sc, HIFN_1_DMA_CSR), 2128104477Ssam READ_REG_1(sc, HIFN_1_DMA_IER)); 2129104477Ssam } 2130104477Ssam#endif 2131104477Ssam 2132104477Ssam sc->sc_active = 5; 2133115748Ssam HIFN_UNLOCK(sc); 2134104477Ssam KASSERT(err == 0, ("hifn_crypto: success with error %u", err)); 2135104477Ssam return (err); /* success */ 2136104477Ssam 2137104477Ssamerr_dstmap: 2138104477Ssam if (cmd->src_map != cmd->dst_map) 2139104477Ssam bus_dmamap_unload(sc->sc_dmat, cmd->dst_map); 2140104477Ssamerr_dstmap1: 2141104477Ssam if (cmd->src_map != cmd->dst_map) 2142104477Ssam bus_dmamap_destroy(sc->sc_dmat, cmd->dst_map); 2143104477Ssamerr_srcmap: 2144104477Ssam if (crp->crp_flags & CRYPTO_F_IMBUF) { 2145104477Ssam if (cmd->src_m != cmd->dst_m) 2146104477Ssam m_freem(cmd->dst_m); 2147104477Ssam } 2148104477Ssam bus_dmamap_unload(sc->sc_dmat, cmd->src_map); 2149104477Ssamerr_srcmap1: 2150104477Ssam bus_dmamap_destroy(sc->sc_dmat, cmd->src_map); 2151115748Ssam HIFN_UNLOCK(sc); 2152104477Ssam return (err); 2153104477Ssam} 2154104477Ssam 2155104477Ssamstatic void 2156104477Ssamhifn_tick(void* vsc) 2157104477Ssam{ 2158104477Ssam struct hifn_softc *sc = vsc; 2159104477Ssam 2160104477Ssam HIFN_LOCK(sc); 2161104477Ssam if (sc->sc_active == 0) { 2162104477Ssam u_int32_t r = 0; 2163104477Ssam 2164213091Sgonzo if (sc->sc_cmdu == 0 && sc->sc_c_busy) { 2165104477Ssam sc->sc_c_busy = 0; 2166104477Ssam r |= HIFN_DMACSR_C_CTRL_DIS; 2167104477Ssam } 2168213091Sgonzo if (sc->sc_srcu == 0 && sc->sc_s_busy) { 2169104477Ssam sc->sc_s_busy = 0; 2170104477Ssam r |= HIFN_DMACSR_S_CTRL_DIS; 2171104477Ssam } 2172213091Sgonzo if (sc->sc_dstu == 0 && sc->sc_d_busy) { 2173104477Ssam sc->sc_d_busy = 0; 2174104477Ssam r |= HIFN_DMACSR_D_CTRL_DIS; 2175104477Ssam } 2176213091Sgonzo if (sc->sc_resu == 0 && sc->sc_r_busy) { 2177104477Ssam sc->sc_r_busy = 0; 2178104477Ssam r |= HIFN_DMACSR_R_CTRL_DIS; 2179104477Ssam } 2180104477Ssam if (r) 2181104477Ssam WRITE_REG_1(sc, HIFN_1_DMA_CSR, r); 2182104477Ssam } else 2183104477Ssam sc->sc_active--; 2184104477Ssam HIFN_UNLOCK(sc); 2185104477Ssam callout_reset(&sc->sc_tickto, hz, hifn_tick, sc); 2186104477Ssam} 2187104477Ssam 2188104477Ssamstatic void 2189104477Ssamhifn_intr(void *arg) 2190104477Ssam{ 2191104477Ssam struct hifn_softc *sc = arg; 2192104477Ssam struct hifn_dma *dma; 2193104477Ssam u_int32_t dmacsr, restart; 2194104477Ssam int i, u; 2195104477Ssam 2196115748Ssam dmacsr = READ_REG_1(sc, HIFN_1_DMA_CSR); 2197115748Ssam 2198115748Ssam /* Nothing in the DMA unit interrupted */ 2199115748Ssam if ((dmacsr & sc->sc_dmaier) == 0) 2200115748Ssam return; 2201115748Ssam 2202104477Ssam HIFN_LOCK(sc); 2203115748Ssam 2204104477Ssam dma = sc->sc_dma; 2205104477Ssam 2206104477Ssam#ifdef HIFN_DEBUG 2207104477Ssam if (hifn_debug) { 2208104477Ssam device_printf(sc->sc_dev, 2209104477Ssam "irq: stat %08x ien %08x damier %08x i %d/%d/%d/%d k %d/%d/%d/%d u %d/%d/%d/%d\n", 2210104477Ssam dmacsr, READ_REG_1(sc, HIFN_1_DMA_IER), sc->sc_dmaier, 2211213091Sgonzo sc->sc_cmdi, sc->sc_srci, sc->sc_dsti, sc->sc_resi, 2212213091Sgonzo sc->sc_cmdk, sc->sc_srck, sc->sc_dstk, sc->sc_resk, 2213213091Sgonzo sc->sc_cmdu, sc->sc_srcu, sc->sc_dstu, sc->sc_resu); 2214104477Ssam } 2215104477Ssam#endif 2216104477Ssam 2217104477Ssam WRITE_REG_1(sc, HIFN_1_DMA_CSR, dmacsr & sc->sc_dmaier); 2218104477Ssam 2219104477Ssam if ((sc->sc_flags & HIFN_HAS_PUBLIC) && 2220104477Ssam (dmacsr & HIFN_DMACSR_PUBDONE)) 2221104477Ssam WRITE_REG_1(sc, HIFN_1_PUB_STATUS, 2222104477Ssam READ_REG_1(sc, HIFN_1_PUB_STATUS) | HIFN_PUBSTS_DONE); 2223104477Ssam 2224104477Ssam restart = dmacsr & (HIFN_DMACSR_D_OVER | HIFN_DMACSR_R_OVER); 2225104477Ssam if (restart) 2226104477Ssam device_printf(sc->sc_dev, "overrun %x\n", dmacsr); 2227104477Ssam 2228104477Ssam if (sc->sc_flags & HIFN_IS_7811) { 2229104477Ssam if (dmacsr & HIFN_DMACSR_ILLR) 2230104477Ssam device_printf(sc->sc_dev, "illegal read\n"); 2231104477Ssam if (dmacsr & HIFN_DMACSR_ILLW) 2232104477Ssam device_printf(sc->sc_dev, "illegal write\n"); 2233104477Ssam } 2234104477Ssam 2235104477Ssam restart = dmacsr & (HIFN_DMACSR_C_ABORT | HIFN_DMACSR_S_ABORT | 2236104477Ssam HIFN_DMACSR_D_ABORT | HIFN_DMACSR_R_ABORT); 2237104477Ssam if (restart) { 2238104477Ssam device_printf(sc->sc_dev, "abort, resetting.\n"); 2239104477Ssam hifnstats.hst_abort++; 2240104477Ssam hifn_abort(sc); 2241104477Ssam HIFN_UNLOCK(sc); 2242104477Ssam return; 2243104477Ssam } 2244104477Ssam 2245213091Sgonzo if ((dmacsr & HIFN_DMACSR_C_WAIT) && (sc->sc_cmdu == 0)) { 2246104477Ssam /* 2247104477Ssam * If no slots to process and we receive a "waiting on 2248104477Ssam * command" interrupt, we disable the "waiting on command" 2249104477Ssam * (by clearing it). 2250104477Ssam */ 2251104477Ssam sc->sc_dmaier &= ~HIFN_DMAIER_C_WAIT; 2252104477Ssam WRITE_REG_1(sc, HIFN_1_DMA_IER, sc->sc_dmaier); 2253104477Ssam } 2254104477Ssam 2255104477Ssam /* clear the rings */ 2256213091Sgonzo i = sc->sc_resk; u = sc->sc_resu; 2257104477Ssam while (u != 0) { 2258104477Ssam HIFN_RESR_SYNC(sc, i, 2259104477Ssam BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 2260104477Ssam if (dma->resr[i].l & htole32(HIFN_D_VALID)) { 2261104477Ssam HIFN_RESR_SYNC(sc, i, 2262104477Ssam BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 2263104477Ssam break; 2264104477Ssam } 2265104477Ssam 2266104477Ssam if (i != HIFN_D_RES_RSIZE) { 2267104477Ssam struct hifn_command *cmd; 2268104477Ssam u_int8_t *macbuf = NULL; 2269104477Ssam 2270104477Ssam HIFN_RES_SYNC(sc, i, BUS_DMASYNC_POSTREAD); 2271213091Sgonzo cmd = sc->sc_hifn_commands[i]; 2272104477Ssam KASSERT(cmd != NULL, 2273104477Ssam ("hifn_intr: null command slot %u", i)); 2274213091Sgonzo sc->sc_hifn_commands[i] = NULL; 2275104477Ssam 2276104477Ssam if (cmd->base_masks & HIFN_BASE_CMD_MAC) { 2277104477Ssam macbuf = dma->result_bufs[i]; 2278104477Ssam macbuf += 12; 2279104477Ssam } 2280104477Ssam 2281104477Ssam hifn_callback(sc, cmd, macbuf); 2282104477Ssam hifnstats.hst_opackets++; 2283104477Ssam u--; 2284104477Ssam } 2285104477Ssam 2286104477Ssam if (++i == (HIFN_D_RES_RSIZE + 1)) 2287104477Ssam i = 0; 2288104477Ssam } 2289213091Sgonzo sc->sc_resk = i; sc->sc_resu = u; 2290104477Ssam 2291213091Sgonzo i = sc->sc_srck; u = sc->sc_srcu; 2292104477Ssam while (u != 0) { 2293104477Ssam if (i == HIFN_D_SRC_RSIZE) 2294104477Ssam i = 0; 2295104477Ssam HIFN_SRCR_SYNC(sc, i, 2296104477Ssam BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 2297104477Ssam if (dma->srcr[i].l & htole32(HIFN_D_VALID)) { 2298104477Ssam HIFN_SRCR_SYNC(sc, i, 2299104477Ssam BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 2300104477Ssam break; 2301104477Ssam } 2302104477Ssam i++, u--; 2303104477Ssam } 2304213091Sgonzo sc->sc_srck = i; sc->sc_srcu = u; 2305104477Ssam 2306213091Sgonzo i = sc->sc_cmdk; u = sc->sc_cmdu; 2307104477Ssam while (u != 0) { 2308104477Ssam HIFN_CMDR_SYNC(sc, i, 2309104477Ssam BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 2310104477Ssam if (dma->cmdr[i].l & htole32(HIFN_D_VALID)) { 2311104477Ssam HIFN_CMDR_SYNC(sc, i, 2312104477Ssam BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 2313104477Ssam break; 2314104477Ssam } 2315104477Ssam if (i != HIFN_D_CMD_RSIZE) { 2316104477Ssam u--; 2317104477Ssam HIFN_CMD_SYNC(sc, i, BUS_DMASYNC_POSTWRITE); 2318104477Ssam } 2319104477Ssam if (++i == (HIFN_D_CMD_RSIZE + 1)) 2320104477Ssam i = 0; 2321104477Ssam } 2322213091Sgonzo sc->sc_cmdk = i; sc->sc_cmdu = u; 2323104477Ssam 2324115748Ssam HIFN_UNLOCK(sc); 2325115748Ssam 2326104477Ssam if (sc->sc_needwakeup) { /* XXX check high watermark */ 2327104477Ssam int wakeup = sc->sc_needwakeup & (CRYPTO_SYMQ|CRYPTO_ASYMQ); 2328104477Ssam#ifdef HIFN_DEBUG 2329104477Ssam if (hifn_debug) 2330104477Ssam device_printf(sc->sc_dev, 2331104477Ssam "wakeup crypto (%x) u %d/%d/%d/%d\n", 2332104477Ssam sc->sc_needwakeup, 2333213091Sgonzo sc->sc_cmdu, sc->sc_srcu, sc->sc_dstu, sc->sc_resu); 2334104477Ssam#endif 2335104477Ssam sc->sc_needwakeup &= ~wakeup; 2336104477Ssam crypto_unblock(sc->sc_cid, wakeup); 2337104477Ssam } 2338104477Ssam} 2339104477Ssam 2340104477Ssam/* 2341104477Ssam * Allocate a new 'session' and return an encoded session id. 'sidp' 2342104477Ssam * contains our registration id, and should contain an encoded session 2343104477Ssam * id on successful allocation. 2344104477Ssam */ 2345104477Ssamstatic int 2346167755Ssamhifn_newsession(device_t dev, u_int32_t *sidp, struct cryptoini *cri) 2347104477Ssam{ 2348167755Ssam struct hifn_softc *sc = device_get_softc(dev); 2349104477Ssam struct cryptoini *c; 2350136526Ssam int mac = 0, cry = 0, sesn; 2351136532Ssam struct hifn_session *ses = NULL; 2352104477Ssam 2353104477Ssam KASSERT(sc != NULL, ("hifn_newsession: null softc")); 2354104477Ssam if (sidp == NULL || cri == NULL || sc == NULL) 2355104477Ssam return (EINVAL); 2356104477Ssam 2357167755Ssam HIFN_LOCK(sc); 2358136526Ssam if (sc->sc_sessions == NULL) { 2359136526Ssam ses = sc->sc_sessions = (struct hifn_session *)malloc( 2360136526Ssam sizeof(*ses), M_DEVBUF, M_NOWAIT); 2361167755Ssam if (ses == NULL) { 2362167755Ssam HIFN_UNLOCK(sc); 2363136526Ssam return (ENOMEM); 2364167755Ssam } 2365136526Ssam sesn = 0; 2366136526Ssam sc->sc_nsessions = 1; 2367136526Ssam } else { 2368136526Ssam for (sesn = 0; sesn < sc->sc_nsessions; sesn++) { 2369136526Ssam if (!sc->sc_sessions[sesn].hs_used) { 2370136526Ssam ses = &sc->sc_sessions[sesn]; 2371136526Ssam break; 2372136526Ssam } 2373136526Ssam } 2374104477Ssam 2375136526Ssam if (ses == NULL) { 2376136526Ssam sesn = sc->sc_nsessions; 2377136526Ssam ses = (struct hifn_session *)malloc((sesn + 1) * 2378136526Ssam sizeof(*ses), M_DEVBUF, M_NOWAIT); 2379167755Ssam if (ses == NULL) { 2380167755Ssam HIFN_UNLOCK(sc); 2381136526Ssam return (ENOMEM); 2382167755Ssam } 2383136526Ssam bcopy(sc->sc_sessions, ses, sesn * sizeof(*ses)); 2384136526Ssam bzero(sc->sc_sessions, sesn * sizeof(*ses)); 2385136526Ssam free(sc->sc_sessions, M_DEVBUF); 2386136526Ssam sc->sc_sessions = ses; 2387136526Ssam ses = &sc->sc_sessions[sesn]; 2388136526Ssam sc->sc_nsessions++; 2389136526Ssam } 2390136526Ssam } 2391167755Ssam HIFN_UNLOCK(sc); 2392167755Ssam 2393136526Ssam bzero(ses, sizeof(*ses)); 2394136526Ssam ses->hs_used = 1; 2395136526Ssam 2396104477Ssam for (c = cri; c != NULL; c = c->cri_next) { 2397104477Ssam switch (c->cri_alg) { 2398104477Ssam case CRYPTO_MD5: 2399104477Ssam case CRYPTO_SHA1: 2400104477Ssam case CRYPTO_MD5_HMAC: 2401104477Ssam case CRYPTO_SHA1_HMAC: 2402104477Ssam if (mac) 2403104477Ssam return (EINVAL); 2404104477Ssam mac = 1; 2405158705Spjd ses->hs_mlen = c->cri_mlen; 2406158705Spjd if (ses->hs_mlen == 0) { 2407158705Spjd switch (c->cri_alg) { 2408158705Spjd case CRYPTO_MD5: 2409158705Spjd case CRYPTO_MD5_HMAC: 2410158705Spjd ses->hs_mlen = 16; 2411158705Spjd break; 2412158705Spjd case CRYPTO_SHA1: 2413158705Spjd case CRYPTO_SHA1_HMAC: 2414158705Spjd ses->hs_mlen = 20; 2415158705Spjd break; 2416158705Spjd } 2417158705Spjd } 2418104477Ssam break; 2419104477Ssam case CRYPTO_DES_CBC: 2420104477Ssam case CRYPTO_3DES_CBC: 2421120915Ssam case CRYPTO_AES_CBC: 2422104477Ssam /* XXX this may read fewer, does it matter? */ 2423136526Ssam read_random(ses->hs_iv, 2424120915Ssam c->cri_alg == CRYPTO_AES_CBC ? 2425120915Ssam HIFN_AES_IV_LENGTH : HIFN_IV_LENGTH); 2426104477Ssam /*FALLTHROUGH*/ 2427104477Ssam case CRYPTO_ARC4: 2428104477Ssam if (cry) 2429104477Ssam return (EINVAL); 2430104477Ssam cry = 1; 2431104477Ssam break; 2432104477Ssam default: 2433104477Ssam return (EINVAL); 2434104477Ssam } 2435104477Ssam } 2436104477Ssam if (mac == 0 && cry == 0) 2437104477Ssam return (EINVAL); 2438104477Ssam 2439136526Ssam *sidp = HIFN_SID(device_get_unit(sc->sc_dev), sesn); 2440104477Ssam 2441104477Ssam return (0); 2442104477Ssam} 2443104477Ssam 2444104477Ssam/* 2445104477Ssam * Deallocate a session. 2446104477Ssam * XXX this routine should run a zero'd mac/encrypt key into context ram. 2447104477Ssam * XXX to blow away any keys already stored there. 2448104477Ssam */ 2449104477Ssamstatic int 2450167755Ssamhifn_freesession(device_t dev, u_int64_t tid) 2451104477Ssam{ 2452167755Ssam struct hifn_softc *sc = device_get_softc(dev); 2453167755Ssam int session, error; 2454116924Ssam u_int32_t sid = CRYPTO_SESID2LID(tid); 2455104477Ssam 2456104477Ssam KASSERT(sc != NULL, ("hifn_freesession: null softc")); 2457104477Ssam if (sc == NULL) 2458104477Ssam return (EINVAL); 2459104477Ssam 2460167755Ssam HIFN_LOCK(sc); 2461104477Ssam session = HIFN_SESSION(sid); 2462167755Ssam if (session < sc->sc_nsessions) { 2463167755Ssam bzero(&sc->sc_sessions[session], sizeof(struct hifn_session)); 2464167755Ssam error = 0; 2465167755Ssam } else 2466167755Ssam error = EINVAL; 2467167755Ssam HIFN_UNLOCK(sc); 2468104477Ssam 2469167755Ssam return (error); 2470104477Ssam} 2471104477Ssam 2472104477Ssamstatic int 2473167755Ssamhifn_process(device_t dev, struct cryptop *crp, int hint) 2474104477Ssam{ 2475167755Ssam struct hifn_softc *sc = device_get_softc(dev); 2476104477Ssam struct hifn_command *cmd = NULL; 2477120915Ssam int session, err, ivlen; 2478104477Ssam struct cryptodesc *crd1, *crd2, *maccrd, *enccrd; 2479104477Ssam 2480104477Ssam if (crp == NULL || crp->crp_callback == NULL) { 2481104477Ssam hifnstats.hst_invalid++; 2482104477Ssam return (EINVAL); 2483104477Ssam } 2484104477Ssam session = HIFN_SESSION(crp->crp_sid); 2485104477Ssam 2486136526Ssam if (sc == NULL || session >= sc->sc_nsessions) { 2487104477Ssam err = EINVAL; 2488104477Ssam goto errout; 2489104477Ssam } 2490104477Ssam 2491104477Ssam cmd = malloc(sizeof(struct hifn_command), M_DEVBUF, M_NOWAIT | M_ZERO); 2492104477Ssam if (cmd == NULL) { 2493104477Ssam hifnstats.hst_nomem++; 2494104477Ssam err = ENOMEM; 2495104477Ssam goto errout; 2496104477Ssam } 2497104477Ssam 2498104477Ssam if (crp->crp_flags & CRYPTO_F_IMBUF) { 2499104477Ssam cmd->src_m = (struct mbuf *)crp->crp_buf; 2500104477Ssam cmd->dst_m = (struct mbuf *)crp->crp_buf; 2501104477Ssam } else if (crp->crp_flags & CRYPTO_F_IOV) { 2502104477Ssam cmd->src_io = (struct uio *)crp->crp_buf; 2503104477Ssam cmd->dst_io = (struct uio *)crp->crp_buf; 2504104477Ssam } else { 2505104477Ssam err = EINVAL; 2506104477Ssam goto errout; /* XXX we don't handle contiguous buffers! */ 2507104477Ssam } 2508104477Ssam 2509104477Ssam crd1 = crp->crp_desc; 2510104477Ssam if (crd1 == NULL) { 2511104477Ssam err = EINVAL; 2512104477Ssam goto errout; 2513104477Ssam } 2514104477Ssam crd2 = crd1->crd_next; 2515104477Ssam 2516104477Ssam if (crd2 == NULL) { 2517104477Ssam if (crd1->crd_alg == CRYPTO_MD5_HMAC || 2518104477Ssam crd1->crd_alg == CRYPTO_SHA1_HMAC || 2519104477Ssam crd1->crd_alg == CRYPTO_SHA1 || 2520104477Ssam crd1->crd_alg == CRYPTO_MD5) { 2521104477Ssam maccrd = crd1; 2522104477Ssam enccrd = NULL; 2523104477Ssam } else if (crd1->crd_alg == CRYPTO_DES_CBC || 2524104477Ssam crd1->crd_alg == CRYPTO_3DES_CBC || 2525120915Ssam crd1->crd_alg == CRYPTO_AES_CBC || 2526104477Ssam crd1->crd_alg == CRYPTO_ARC4) { 2527104477Ssam if ((crd1->crd_flags & CRD_F_ENCRYPT) == 0) 2528104477Ssam cmd->base_masks |= HIFN_BASE_CMD_DECODE; 2529104477Ssam maccrd = NULL; 2530104477Ssam enccrd = crd1; 2531104477Ssam } else { 2532104477Ssam err = EINVAL; 2533104477Ssam goto errout; 2534104477Ssam } 2535104477Ssam } else { 2536104477Ssam if ((crd1->crd_alg == CRYPTO_MD5_HMAC || 2537104477Ssam crd1->crd_alg == CRYPTO_SHA1_HMAC || 2538104477Ssam crd1->crd_alg == CRYPTO_MD5 || 2539104477Ssam crd1->crd_alg == CRYPTO_SHA1) && 2540104477Ssam (crd2->crd_alg == CRYPTO_DES_CBC || 2541104477Ssam crd2->crd_alg == CRYPTO_3DES_CBC || 2542120915Ssam crd2->crd_alg == CRYPTO_AES_CBC || 2543104477Ssam crd2->crd_alg == CRYPTO_ARC4) && 2544104477Ssam ((crd2->crd_flags & CRD_F_ENCRYPT) == 0)) { 2545104477Ssam cmd->base_masks = HIFN_BASE_CMD_DECODE; 2546104477Ssam maccrd = crd1; 2547104477Ssam enccrd = crd2; 2548104477Ssam } else if ((crd1->crd_alg == CRYPTO_DES_CBC || 2549104477Ssam crd1->crd_alg == CRYPTO_ARC4 || 2550120915Ssam crd1->crd_alg == CRYPTO_3DES_CBC || 2551120915Ssam crd1->crd_alg == CRYPTO_AES_CBC) && 2552104477Ssam (crd2->crd_alg == CRYPTO_MD5_HMAC || 2553104477Ssam crd2->crd_alg == CRYPTO_SHA1_HMAC || 2554104477Ssam crd2->crd_alg == CRYPTO_MD5 || 2555104477Ssam crd2->crd_alg == CRYPTO_SHA1) && 2556104477Ssam (crd1->crd_flags & CRD_F_ENCRYPT)) { 2557104477Ssam enccrd = crd1; 2558104477Ssam maccrd = crd2; 2559104477Ssam } else { 2560104477Ssam /* 2561104477Ssam * We cannot order the 7751 as requested 2562104477Ssam */ 2563104477Ssam err = EINVAL; 2564104477Ssam goto errout; 2565104477Ssam } 2566104477Ssam } 2567104477Ssam 2568104477Ssam if (enccrd) { 2569104477Ssam cmd->enccrd = enccrd; 2570104477Ssam cmd->base_masks |= HIFN_BASE_CMD_CRYPT; 2571104477Ssam switch (enccrd->crd_alg) { 2572104477Ssam case CRYPTO_ARC4: 2573104477Ssam cmd->cry_masks |= HIFN_CRYPT_CMD_ALG_RC4; 2574104477Ssam break; 2575104477Ssam case CRYPTO_DES_CBC: 2576104477Ssam cmd->cry_masks |= HIFN_CRYPT_CMD_ALG_DES | 2577104477Ssam HIFN_CRYPT_CMD_MODE_CBC | 2578104477Ssam HIFN_CRYPT_CMD_NEW_IV; 2579104477Ssam break; 2580104477Ssam case CRYPTO_3DES_CBC: 2581104477Ssam cmd->cry_masks |= HIFN_CRYPT_CMD_ALG_3DES | 2582104477Ssam HIFN_CRYPT_CMD_MODE_CBC | 2583104477Ssam HIFN_CRYPT_CMD_NEW_IV; 2584104477Ssam break; 2585120915Ssam case CRYPTO_AES_CBC: 2586120915Ssam cmd->cry_masks |= HIFN_CRYPT_CMD_ALG_AES | 2587120915Ssam HIFN_CRYPT_CMD_MODE_CBC | 2588120915Ssam HIFN_CRYPT_CMD_NEW_IV; 2589120915Ssam break; 2590104477Ssam default: 2591104477Ssam err = EINVAL; 2592104477Ssam goto errout; 2593104477Ssam } 2594104477Ssam if (enccrd->crd_alg != CRYPTO_ARC4) { 2595120915Ssam ivlen = ((enccrd->crd_alg == CRYPTO_AES_CBC) ? 2596120915Ssam HIFN_AES_IV_LENGTH : HIFN_IV_LENGTH); 2597104477Ssam if (enccrd->crd_flags & CRD_F_ENCRYPT) { 2598104477Ssam if (enccrd->crd_flags & CRD_F_IV_EXPLICIT) 2599120915Ssam bcopy(enccrd->crd_iv, cmd->iv, ivlen); 2600104477Ssam else 2601104477Ssam bcopy(sc->sc_sessions[session].hs_iv, 2602120915Ssam cmd->iv, ivlen); 2603104477Ssam 2604104477Ssam if ((enccrd->crd_flags & CRD_F_IV_PRESENT) 2605104477Ssam == 0) { 2606159242Spjd crypto_copyback(crp->crp_flags, 2607159242Spjd crp->crp_buf, enccrd->crd_inject, 2608159242Spjd ivlen, cmd->iv); 2609104477Ssam } 2610104477Ssam } else { 2611104477Ssam if (enccrd->crd_flags & CRD_F_IV_EXPLICIT) 2612120915Ssam bcopy(enccrd->crd_iv, cmd->iv, ivlen); 2613159242Spjd else { 2614159242Spjd crypto_copydata(crp->crp_flags, 2615159242Spjd crp->crp_buf, enccrd->crd_inject, 2616159242Spjd ivlen, cmd->iv); 2617159242Spjd } 2618104477Ssam } 2619104477Ssam } 2620104477Ssam 2621125330Sphk if (enccrd->crd_flags & CRD_F_KEY_EXPLICIT) 2622125330Sphk cmd->cry_masks |= HIFN_CRYPT_CMD_NEW_KEY; 2623104477Ssam cmd->ck = enccrd->crd_key; 2624104477Ssam cmd->cklen = enccrd->crd_klen >> 3; 2625136526Ssam cmd->cry_masks |= HIFN_CRYPT_CMD_NEW_KEY; 2626104477Ssam 2627120915Ssam /* 2628120915Ssam * Need to specify the size for the AES key in the masks. 2629120915Ssam */ 2630120915Ssam if ((cmd->cry_masks & HIFN_CRYPT_CMD_ALG_MASK) == 2631120915Ssam HIFN_CRYPT_CMD_ALG_AES) { 2632120915Ssam switch (cmd->cklen) { 2633120915Ssam case 16: 2634120915Ssam cmd->cry_masks |= HIFN_CRYPT_CMD_KSZ_128; 2635120915Ssam break; 2636120915Ssam case 24: 2637120915Ssam cmd->cry_masks |= HIFN_CRYPT_CMD_KSZ_192; 2638120915Ssam break; 2639120915Ssam case 32: 2640120915Ssam cmd->cry_masks |= HIFN_CRYPT_CMD_KSZ_256; 2641120915Ssam break; 2642120915Ssam default: 2643120915Ssam err = EINVAL; 2644120915Ssam goto errout; 2645120915Ssam } 2646120915Ssam } 2647104477Ssam } 2648104477Ssam 2649104477Ssam if (maccrd) { 2650104477Ssam cmd->maccrd = maccrd; 2651104477Ssam cmd->base_masks |= HIFN_BASE_CMD_MAC; 2652104477Ssam 2653104477Ssam switch (maccrd->crd_alg) { 2654104477Ssam case CRYPTO_MD5: 2655104477Ssam cmd->mac_masks |= HIFN_MAC_CMD_ALG_MD5 | 2656104477Ssam HIFN_MAC_CMD_RESULT | HIFN_MAC_CMD_MODE_HASH | 2657104477Ssam HIFN_MAC_CMD_POS_IPSEC; 2658104477Ssam break; 2659104477Ssam case CRYPTO_MD5_HMAC: 2660104477Ssam cmd->mac_masks |= HIFN_MAC_CMD_ALG_MD5 | 2661104477Ssam HIFN_MAC_CMD_RESULT | HIFN_MAC_CMD_MODE_HMAC | 2662104477Ssam HIFN_MAC_CMD_POS_IPSEC | HIFN_MAC_CMD_TRUNC; 2663104477Ssam break; 2664104477Ssam case CRYPTO_SHA1: 2665104477Ssam cmd->mac_masks |= HIFN_MAC_CMD_ALG_SHA1 | 2666104477Ssam HIFN_MAC_CMD_RESULT | HIFN_MAC_CMD_MODE_HASH | 2667104477Ssam HIFN_MAC_CMD_POS_IPSEC; 2668104477Ssam break; 2669104477Ssam case CRYPTO_SHA1_HMAC: 2670104477Ssam cmd->mac_masks |= HIFN_MAC_CMD_ALG_SHA1 | 2671104477Ssam HIFN_MAC_CMD_RESULT | HIFN_MAC_CMD_MODE_HMAC | 2672104477Ssam HIFN_MAC_CMD_POS_IPSEC | HIFN_MAC_CMD_TRUNC; 2673104477Ssam break; 2674104477Ssam } 2675104477Ssam 2676136526Ssam if (maccrd->crd_alg == CRYPTO_SHA1_HMAC || 2677136526Ssam maccrd->crd_alg == CRYPTO_MD5_HMAC) { 2678104477Ssam cmd->mac_masks |= HIFN_MAC_CMD_NEW_KEY; 2679104477Ssam bcopy(maccrd->crd_key, cmd->mac, maccrd->crd_klen >> 3); 2680104477Ssam bzero(cmd->mac + (maccrd->crd_klen >> 3), 2681104477Ssam HIFN_MAC_KEY_LENGTH - (maccrd->crd_klen >> 3)); 2682104477Ssam } 2683104477Ssam } 2684104477Ssam 2685104477Ssam cmd->crp = crp; 2686104477Ssam cmd->session_num = session; 2687104477Ssam cmd->softc = sc; 2688104477Ssam 2689104477Ssam err = hifn_crypto(sc, cmd, crp, hint); 2690104477Ssam if (!err) { 2691104477Ssam return 0; 2692104477Ssam } else if (err == ERESTART) { 2693104477Ssam /* 2694104477Ssam * There weren't enough resources to dispatch the request 2695104477Ssam * to the part. Notify the caller so they'll requeue this 2696104477Ssam * request and resubmit it again soon. 2697104477Ssam */ 2698104477Ssam#ifdef HIFN_DEBUG 2699104477Ssam if (hifn_debug) 2700104477Ssam device_printf(sc->sc_dev, "requeue request\n"); 2701104477Ssam#endif 2702104477Ssam free(cmd, M_DEVBUF); 2703104477Ssam sc->sc_needwakeup |= CRYPTO_SYMQ; 2704104477Ssam return (err); 2705104477Ssam } 2706104477Ssam 2707104477Ssamerrout: 2708104477Ssam if (cmd != NULL) 2709104477Ssam free(cmd, M_DEVBUF); 2710104477Ssam if (err == EINVAL) 2711104477Ssam hifnstats.hst_invalid++; 2712104477Ssam else 2713104477Ssam hifnstats.hst_nomem++; 2714104477Ssam crp->crp_etype = err; 2715104477Ssam crypto_done(crp); 2716104477Ssam return (err); 2717104477Ssam} 2718104477Ssam 2719104477Ssamstatic void 2720104477Ssamhifn_abort(struct hifn_softc *sc) 2721104477Ssam{ 2722104477Ssam struct hifn_dma *dma = sc->sc_dma; 2723104477Ssam struct hifn_command *cmd; 2724104477Ssam struct cryptop *crp; 2725104477Ssam int i, u; 2726104477Ssam 2727213091Sgonzo i = sc->sc_resk; u = sc->sc_resu; 2728104477Ssam while (u != 0) { 2729213091Sgonzo cmd = sc->sc_hifn_commands[i]; 2730104477Ssam KASSERT(cmd != NULL, ("hifn_abort: null command slot %u", i)); 2731213091Sgonzo sc->sc_hifn_commands[i] = NULL; 2732104477Ssam crp = cmd->crp; 2733104477Ssam 2734104477Ssam if ((dma->resr[i].l & htole32(HIFN_D_VALID)) == 0) { 2735104477Ssam /* Salvage what we can. */ 2736104477Ssam u_int8_t *macbuf; 2737104477Ssam 2738104477Ssam if (cmd->base_masks & HIFN_BASE_CMD_MAC) { 2739104477Ssam macbuf = dma->result_bufs[i]; 2740104477Ssam macbuf += 12; 2741104477Ssam } else 2742104477Ssam macbuf = NULL; 2743104477Ssam hifnstats.hst_opackets++; 2744104477Ssam hifn_callback(sc, cmd, macbuf); 2745104477Ssam } else { 2746104477Ssam if (cmd->src_map == cmd->dst_map) { 2747104477Ssam bus_dmamap_sync(sc->sc_dmat, cmd->src_map, 2748104477Ssam BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); 2749104477Ssam } else { 2750104477Ssam bus_dmamap_sync(sc->sc_dmat, cmd->src_map, 2751104477Ssam BUS_DMASYNC_POSTWRITE); 2752104477Ssam bus_dmamap_sync(sc->sc_dmat, cmd->dst_map, 2753104477Ssam BUS_DMASYNC_POSTREAD); 2754104477Ssam } 2755104477Ssam 2756104477Ssam if (cmd->src_m != cmd->dst_m) { 2757104477Ssam m_freem(cmd->src_m); 2758104477Ssam crp->crp_buf = (caddr_t)cmd->dst_m; 2759104477Ssam } 2760104477Ssam 2761104477Ssam /* non-shared buffers cannot be restarted */ 2762104477Ssam if (cmd->src_map != cmd->dst_map) { 2763104477Ssam /* 2764104477Ssam * XXX should be EAGAIN, delayed until 2765104477Ssam * after the reset. 2766104477Ssam */ 2767104477Ssam crp->crp_etype = ENOMEM; 2768104477Ssam bus_dmamap_unload(sc->sc_dmat, cmd->dst_map); 2769104477Ssam bus_dmamap_destroy(sc->sc_dmat, cmd->dst_map); 2770104477Ssam } else 2771104477Ssam crp->crp_etype = ENOMEM; 2772104477Ssam 2773104477Ssam bus_dmamap_unload(sc->sc_dmat, cmd->src_map); 2774104477Ssam bus_dmamap_destroy(sc->sc_dmat, cmd->src_map); 2775104477Ssam 2776104477Ssam free(cmd, M_DEVBUF); 2777104477Ssam if (crp->crp_etype != EAGAIN) 2778104477Ssam crypto_done(crp); 2779104477Ssam } 2780104477Ssam 2781104477Ssam if (++i == HIFN_D_RES_RSIZE) 2782104477Ssam i = 0; 2783104477Ssam u--; 2784104477Ssam } 2785213091Sgonzo sc->sc_resk = i; sc->sc_resu = u; 2786104477Ssam 2787104477Ssam hifn_reset_board(sc, 1); 2788104477Ssam hifn_init_dma(sc); 2789104477Ssam hifn_init_pci_registers(sc); 2790104477Ssam} 2791104477Ssam 2792104477Ssamstatic void 2793104477Ssamhifn_callback(struct hifn_softc *sc, struct hifn_command *cmd, u_int8_t *macbuf) 2794104477Ssam{ 2795104477Ssam struct hifn_dma *dma = sc->sc_dma; 2796104477Ssam struct cryptop *crp = cmd->crp; 2797104477Ssam struct cryptodesc *crd; 2798104477Ssam struct mbuf *m; 2799120915Ssam int totlen, i, u, ivlen; 2800104477Ssam 2801104477Ssam if (cmd->src_map == cmd->dst_map) { 2802104477Ssam bus_dmamap_sync(sc->sc_dmat, cmd->src_map, 2803104477Ssam BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); 2804104477Ssam } else { 2805104477Ssam bus_dmamap_sync(sc->sc_dmat, cmd->src_map, 2806104477Ssam BUS_DMASYNC_POSTWRITE); 2807104477Ssam bus_dmamap_sync(sc->sc_dmat, cmd->dst_map, 2808104477Ssam BUS_DMASYNC_POSTREAD); 2809104477Ssam } 2810104477Ssam 2811104477Ssam if (crp->crp_flags & CRYPTO_F_IMBUF) { 2812104477Ssam if (cmd->src_m != cmd->dst_m) { 2813104477Ssam crp->crp_buf = (caddr_t)cmd->dst_m; 2814104477Ssam totlen = cmd->src_mapsize; 2815104477Ssam for (m = cmd->dst_m; m != NULL; m = m->m_next) { 2816104477Ssam if (totlen < m->m_len) { 2817104477Ssam m->m_len = totlen; 2818104477Ssam totlen = 0; 2819104477Ssam } else 2820104477Ssam totlen -= m->m_len; 2821104477Ssam } 2822104477Ssam cmd->dst_m->m_pkthdr.len = cmd->src_m->m_pkthdr.len; 2823104477Ssam m_freem(cmd->src_m); 2824104477Ssam } 2825104477Ssam } 2826104477Ssam 2827104477Ssam if (cmd->sloplen != 0) { 2828159242Spjd crypto_copyback(crp->crp_flags, crp->crp_buf, 2829159242Spjd cmd->src_mapsize - cmd->sloplen, cmd->sloplen, 2830159242Spjd (caddr_t)&dma->slop[cmd->slopidx]); 2831104477Ssam } 2832104477Ssam 2833213091Sgonzo i = sc->sc_dstk; u = sc->sc_dstu; 2834104477Ssam while (u != 0) { 2835104477Ssam if (i == HIFN_D_DST_RSIZE) 2836104477Ssam i = 0; 2837104477Ssam bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, 2838104477Ssam BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 2839104477Ssam if (dma->dstr[i].l & htole32(HIFN_D_VALID)) { 2840104477Ssam bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, 2841104477Ssam BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 2842104477Ssam break; 2843104477Ssam } 2844104477Ssam i++, u--; 2845104477Ssam } 2846213091Sgonzo sc->sc_dstk = i; sc->sc_dstu = u; 2847104477Ssam 2848104477Ssam hifnstats.hst_obytes += cmd->dst_mapsize; 2849104477Ssam 2850104477Ssam if ((cmd->base_masks & (HIFN_BASE_CMD_CRYPT | HIFN_BASE_CMD_DECODE)) == 2851104477Ssam HIFN_BASE_CMD_CRYPT) { 2852104477Ssam for (crd = crp->crp_desc; crd; crd = crd->crd_next) { 2853104477Ssam if (crd->crd_alg != CRYPTO_DES_CBC && 2854120915Ssam crd->crd_alg != CRYPTO_3DES_CBC && 2855120915Ssam crd->crd_alg != CRYPTO_AES_CBC) 2856104477Ssam continue; 2857120915Ssam ivlen = ((crd->crd_alg == CRYPTO_AES_CBC) ? 2858120915Ssam HIFN_AES_IV_LENGTH : HIFN_IV_LENGTH); 2859159242Spjd crypto_copydata(crp->crp_flags, crp->crp_buf, 2860159242Spjd crd->crd_skip + crd->crd_len - ivlen, ivlen, 2861159242Spjd cmd->softc->sc_sessions[cmd->session_num].hs_iv); 2862104477Ssam break; 2863104477Ssam } 2864104477Ssam } 2865104477Ssam 2866104477Ssam if (macbuf != NULL) { 2867104477Ssam for (crd = crp->crp_desc; crd; crd = crd->crd_next) { 2868105275Ssam int len; 2869104477Ssam 2870158705Spjd if (crd->crd_alg != CRYPTO_MD5 && 2871158705Spjd crd->crd_alg != CRYPTO_SHA1 && 2872158705Spjd crd->crd_alg != CRYPTO_MD5_HMAC && 2873158705Spjd crd->crd_alg != CRYPTO_SHA1_HMAC) { 2874104477Ssam continue; 2875158705Spjd } 2876158705Spjd len = cmd->softc->sc_sessions[cmd->session_num].hs_mlen; 2877159242Spjd crypto_copyback(crp->crp_flags, crp->crp_buf, 2878159242Spjd crd->crd_inject, len, macbuf); 2879104477Ssam break; 2880104477Ssam } 2881104477Ssam } 2882104477Ssam 2883104477Ssam if (cmd->src_map != cmd->dst_map) { 2884104477Ssam bus_dmamap_unload(sc->sc_dmat, cmd->dst_map); 2885104477Ssam bus_dmamap_destroy(sc->sc_dmat, cmd->dst_map); 2886104477Ssam } 2887104477Ssam bus_dmamap_unload(sc->sc_dmat, cmd->src_map); 2888104477Ssam bus_dmamap_destroy(sc->sc_dmat, cmd->src_map); 2889104477Ssam free(cmd, M_DEVBUF); 2890104477Ssam crypto_done(crp); 2891104477Ssam} 2892104477Ssam 2893104477Ssam/* 2894104477Ssam * 7811 PB3 rev/2 parts lock-up on burst writes to Group 0 2895104477Ssam * and Group 1 registers; avoid conditions that could create 2896104477Ssam * burst writes by doing a read in between the writes. 2897104477Ssam * 2898104477Ssam * NB: The read we interpose is always to the same register; 2899104477Ssam * we do this because reading from an arbitrary (e.g. last) 2900104477Ssam * register may not always work. 2901104477Ssam */ 2902104477Ssamstatic void 2903104477Ssamhifn_write_reg_0(struct hifn_softc *sc, bus_size_t reg, u_int32_t val) 2904104477Ssam{ 2905104477Ssam if (sc->sc_flags & HIFN_IS_7811) { 2906104477Ssam if (sc->sc_bar0_lastreg == reg - 4) 2907104477Ssam bus_space_read_4(sc->sc_st0, sc->sc_sh0, HIFN_0_PUCNFG); 2908104477Ssam sc->sc_bar0_lastreg = reg; 2909104477Ssam } 2910104477Ssam bus_space_write_4(sc->sc_st0, sc->sc_sh0, reg, val); 2911104477Ssam} 2912104477Ssam 2913104477Ssamstatic void 2914104477Ssamhifn_write_reg_1(struct hifn_softc *sc, bus_size_t reg, u_int32_t val) 2915104477Ssam{ 2916104477Ssam if (sc->sc_flags & HIFN_IS_7811) { 2917104477Ssam if (sc->sc_bar1_lastreg == reg - 4) 2918104477Ssam bus_space_read_4(sc->sc_st1, sc->sc_sh1, HIFN_1_REVID); 2919104477Ssam sc->sc_bar1_lastreg = reg; 2920104477Ssam } 2921104477Ssam bus_space_write_4(sc->sc_st1, sc->sc_sh1, reg, val); 2922104477Ssam} 2923167755Ssam 2924167755Ssam#ifdef HIFN_VULCANDEV 2925167755Ssam/* 2926167755Ssam * this code provides support for mapping the PK engine's register 2927167755Ssam * into a userspace program. 2928167755Ssam * 2929167755Ssam */ 2930167755Ssamstatic int 2931201223Srnolandvulcanpk_mmap(struct cdev *dev, vm_ooffset_t offset, 2932201223Srnoland vm_paddr_t *paddr, int nprot, vm_memattr_t *memattr) 2933167755Ssam{ 2934167755Ssam struct hifn_softc *sc; 2935167755Ssam vm_paddr_t pd; 2936167755Ssam void *b; 2937167755Ssam 2938167755Ssam sc = dev->si_drv1; 2939167755Ssam 2940167755Ssam pd = rman_get_start(sc->sc_bar1res); 2941167755Ssam b = rman_get_virtual(sc->sc_bar1res); 2942167755Ssam 2943167755Ssam#if 0 2944201223Srnoland printf("vpk mmap: %p(%016llx) offset=%lld\n", b, 2945201223Srnoland (unsigned long long)pd, offset); 2946167755Ssam hexdump(b, HIFN_1_PUB_MEMEND, "vpk", 0); 2947167755Ssam#endif 2948167755Ssam 2949167755Ssam if (offset == 0) { 2950167755Ssam *paddr = pd; 2951167755Ssam return (0); 2952167755Ssam } 2953167755Ssam return (-1); 2954167755Ssam} 2955167755Ssam 2956167755Ssamstatic struct cdevsw vulcanpk_cdevsw = { 2957167755Ssam .d_version = D_VERSION, 2958167755Ssam .d_mmap = vulcanpk_mmap, 2959167755Ssam .d_name = "vulcanpk", 2960167755Ssam}; 2961167755Ssam#endif /* HIFN_VULCANDEV */ 2962