📄 hifn7751.c
字号:
/* $OpenBSD: hifn7751.c,v 1.120 2002/05/17 00:33:34 deraadt Exp $ *//* * Invertex AEON / Hifn 7751 driver * Copyright (c) 1999 Invertex Inc. All rights reserved. * Copyright (c) 1999 Theo de Raadt * Copyright (c) 2000-2001 Network Security Technologies, Inc. * http://www.netsec.net * Copyright (c) 2003 Hifn Inc. * * This driver is based on a previous driver by Invertex, for which they * requested: Please send any comments, feedback, bug-fixes, or feature * requests to software@invertex.com. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Effort sponsored in part by the Defense Advanced Research Projects * Agency (DARPA) and Air Force Research Laboratory, Air Force * Materiel Command, USAF, under agreement number F30602-01-2-0537. * *__FBSDID("$FreeBSD: src/sys/dev/hifn/hifn7751.c,v 1.30 2004/10/15 03:54:56 sam Exp $"); *//* * Driver for various Hifn encryption processors. */#include <linux/config.h>#include <linux/module.h>#include <linux/init.h>#include <linux/list.h>#include <linux/slab.h>#include <linux/wait.h>#include <linux/sched.h>#include <linux/pci.h>#include <linux/delay.h>#include <linux/interrupt.h>#include <linux/spinlock.h>#include <linux/random.h>#include <asm/io.h>#include <cryptodev.h>#include <uio.h>#include <hifn/hifn7751reg.h>#include <hifn/hifn7751var.h>#define KASSERT(c,p) if (!(c)) { printk p ; } else#if 1#define DPRINTF(a...) if (debug) { printk("hifn: " a); } else#else#define DPRINTF(a...)#endif#define device_printf(dev, a...) printk("hifn: " a)#define DELAY(x) udelay(x)#define bcopy(s,d,l) memcpy(d,s,l)#define bzero(p,l) memset(p,0,l)#define bcmp(x, y, l) memcmp(x,y,l)#define read_random(p,l) get_random_bytes(p,l)#define htole32(x) cpu_to_le32(x)#define htole16(x) cpu_to_le16(x)#define MIN(x,y) ((x) < (y) ? (x) : (y))#define pci_get_vendor(dev) ((dev)->vendor)#define pci_get_device(dev) ((dev)->device)static inline intpci_get_revid(struct pci_dev *dev){ u8 rid = 0; pci_read_config_byte(dev, PCI_REVISION_ID, &rid); return rid;}static struct hifn_stats hifnstats;#define hifn_debug debugstatic int debug = 0;MODULE_PARM(debug, "i");MODULE_PARM_DESC(debug, "Enable debug");static int hifn_maxbatch = 1;MODULE_PARM(hifn_maxbatch, "i");MODULE_PARM_DESC(hifn_maxbatch, "max ops to batch w/o interrupt");/* * Prototypes and count for the pci_device structure */static int hifn_probe(struct pci_dev *dev, const struct pci_device_id *ent);static void hifn_remove(struct pci_dev *dev);static void hifn_reset_board(struct hifn_softc *, int);static void hifn_reset_puc(struct hifn_softc *);static void hifn_puc_wait(struct hifn_softc *);static int hifn_enable_crypto(struct hifn_softc *);static void hifn_set_retry(struct hifn_softc *sc);static void hifn_init_dma(struct hifn_softc *);static void hifn_init_pci_registers(struct hifn_softc *);static int hifn_sramsize(struct hifn_softc *);static int hifn_dramsize(struct hifn_softc *);static int hifn_ramtype(struct hifn_softc *);static void hifn_sessions(struct hifn_softc *);static irqreturn_t hifn_intr(int irq, void *arg, struct pt_regs *regs);static u_int hifn_write_command(struct hifn_command *, u_int8_t *);static u_int32_t hifn_next_signature(u_int32_t a, u_int cnt);static int hifn_newsession(void *, u_int32_t *, struct cryptoini *);static int hifn_freesession(void *, u_int64_t);static int hifn_process(void *, struct cryptop *, int);static void hifn_callback(struct hifn_softc *, struct hifn_command *, u_int8_t *);static int hifn_crypto(struct hifn_softc *, struct hifn_command *, struct cryptop *, int);static int hifn_readramaddr(struct hifn_softc *, int, u_int8_t *);static int hifn_writeramaddr(struct hifn_softc *, int, u_int8_t *);static int hifn_dmamap_load_src(struct hifn_softc *, struct hifn_command *);static int hifn_dmamap_load_dst(struct hifn_softc *, struct hifn_command *);static int hifn_init_pubrng(struct hifn_softc *);static void hifn_rng(unsigned long arg);static void hifn_tick(unsigned long arg);static void hifn_abort(struct hifn_softc *);static void hifn_alloc_slot(struct hifn_softc *, int *, int *, int *, int *);static void hifn_write_reg_0(struct hifn_softc *, bus_size_t, u_int32_t);static void hifn_write_reg_1(struct hifn_softc *, bus_size_t, u_int32_t);static __inline u_int32_tREAD_REG_0(struct hifn_softc *sc, bus_size_t reg){ u_int32_t v = readl(sc->sc_bar0 + reg); sc->sc_bar0_lastreg = (bus_size_t) -1; return (v);}#define WRITE_REG_0(sc, reg, val) hifn_write_reg_0(sc, reg, val)static __inline u_int32_tREAD_REG_1(struct hifn_softc *sc, bus_size_t reg){ u_int32_t v = readl(sc->sc_bar1 + reg); sc->sc_bar1_lastreg = (bus_size_t) -1; return (v);}#define WRITE_REG_1(sc, reg, val) hifn_write_reg_1(sc, reg, val)/* * map in a given buffer (great on some arches :-) */static intpci_map_uio(struct hifn_softc *sc, struct hifn_operand *buf, struct uio *uio){ struct iovec *iov = uio->uio_iov; DPRINTF("%s()\n", __FUNCTION__); buf->mapsize = 0; for (buf->nsegs = 0; buf->nsegs < uio->uio_iovcnt; ) { buf->segs[buf->nsegs].ds_addr = pci_map_single(sc->sc_dev, iov->iov_base, iov->iov_len, PCI_DMA_BIDIRECTIONAL); buf->segs[buf->nsegs].ds_len = iov->iov_len; buf->mapsize += iov->iov_len; iov++; buf->nsegs++; } /* identify this buffer by the first segment */ buf->map = (void *) buf->segs[0].ds_addr; return(0);}static voidpci_sync_iov(struct hifn_softc *sc, struct hifn_operand *buf){ int i; DPRINTF("%s()\n", __FUNCTION__); for (i = 0; i < buf->nsegs; i++) pci_dma_sync_single(sc->sc_dev, buf->segs[i].ds_addr, buf->segs[i].ds_len, PCI_DMA_BIDIRECTIONAL);}static voidpci_unmap_iov(struct hifn_softc *sc, struct hifn_operand *buf){ int i; DPRINTF("%s()\n", __FUNCTION__); for (i = 0; i < buf->nsegs; i++) { pci_unmap_single(sc->sc_dev, buf->segs[i].ds_addr, buf->segs[i].ds_len, PCI_DMA_BIDIRECTIONAL); buf->segs[i].ds_addr = 0; buf->segs[i].ds_len = 0; } buf->nsegs = 0; buf->mapsize = 0; buf->map = 0;}static const char*hifn_partname(struct hifn_softc *sc){ /* XXX sprintf numbers when not decoded */ switch (pci_get_vendor(sc->sc_dev)) { case PCI_VENDOR_HIFN: switch (pci_get_device(sc->sc_dev)) { case PCI_PRODUCT_HIFN_6500: return "Hifn 6500"; case PCI_PRODUCT_HIFN_7751: return "Hifn 7751"; case PCI_PRODUCT_HIFN_7811: return "Hifn 7811"; case PCI_PRODUCT_HIFN_7951: return "Hifn 7951"; case PCI_PRODUCT_HIFN_7955: return "Hifn 7955"; case PCI_PRODUCT_HIFN_7956: return "Hifn 7956"; } return "Hifn unknown-part"; case PCI_VENDOR_INVERTEX: switch (pci_get_device(sc->sc_dev)) { case PCI_PRODUCT_INVERTEX_AEON: return "Invertex AEON"; } return "Invertex unknown-part"; case PCI_VENDOR_NETSEC: switch (pci_get_device(sc->sc_dev)) { case PCI_PRODUCT_NETSEC_7751: return "NetSec 7751"; } return "NetSec unknown-part"; } return "Unknown-vendor unknown-part";}/* * Attach an interface that successfully probed. */static inthifn_probe(struct pci_dev *dev, const struct pci_device_id *ent){ struct hifn_softc *sc; char rbase; u_int16_t ena, rev; int rseg, rc, mem_start, mem_len; static int num_chips = 0; DPRINTF("%s()\n", __FUNCTION__); if (pci_enable_device(dev) < 0) return(-ENODEV); if (!dev->irq) { printk("hifn: found device with no IRQ assigned. check BIOS settings!"); pci_disable_device(dev); return(-ENODEV); } sc = (struct hifn_softc *) kmalloc(sizeof(*sc), GFP_KERNEL); if (!sc) return(-ENOMEM); memset(sc, 0, sizeof(*sc)); sc->sc_dev = dev; sc->sc_irq = -1; sc->sc_cid = -1; sc->sc_num = num_chips++; pci_set_drvdata(sc->sc_dev, sc); spin_lock_init(&sc->sc_mtx); /* XXX handle power management */ /* * The 7951 and 795x have a random number generator and * public key support; note this. */ if (pci_get_vendor(dev) == PCI_VENDOR_HIFN && (pci_get_device(dev) == PCI_PRODUCT_HIFN_7951 || pci_get_device(dev) == PCI_PRODUCT_HIFN_7955 || pci_get_device(dev) == PCI_PRODUCT_HIFN_7956)) sc->sc_flags = HIFN_HAS_RNG | HIFN_HAS_PUBLIC; /* * The 7811 has a random number generator and * we also note it's identity 'cuz of some quirks. */ if (pci_get_vendor(dev) == PCI_VENDOR_HIFN && pci_get_device(dev) == PCI_PRODUCT_HIFN_7811) sc->sc_flags |= HIFN_IS_7811 | HIFN_HAS_RNG; /* * The 795x parts support AES. */ if (pci_get_vendor(dev) == PCI_VENDOR_HIFN && (pci_get_device(dev) == PCI_PRODUCT_HIFN_7955 || pci_get_device(dev) == PCI_PRODUCT_HIFN_7956)) sc->sc_flags |= HIFN_IS_7956 | HIFN_HAS_AES; /* * Setup PCI resources. Note that we record the bus * tag and handle for each register mapping, this is * used by the READ_REG_0, WRITE_REG_0, READ_REG_1, * and WRITE_REG_1 macros throughout the driver. */ mem_start = pci_resource_start(sc->sc_dev, 0); mem_len = pci_resource_len(sc->sc_dev, 0); sc->sc_bar0 = (unsigned long) ioremap(mem_start, mem_len); if (!sc->sc_bar0) { device_printf(dev, "cannot map bar%d register space\n", 0); goto fail; } sc->sc_bar0_lastreg = (bus_size_t) -1; mem_start = pci_resource_start(sc->sc_dev, 1); mem_len = pci_resource_len(sc->sc_dev, 1); sc->sc_bar1 = (unsigned long) ioremap(mem_start, mem_len); if (!sc->sc_bar1) { device_printf(dev, "cannot map bar%d register space\n", 1); goto fail; } sc->sc_bar1_lastreg = (bus_size_t) -1; hifn_set_retry(sc); /* * Setup the area where the Hifn DMA's descriptors * and associated data structures. */ sc->sc_dma = (struct hifn_dma *) pci_alloc_consistent(dev, sizeof(*sc->sc_dma), &sc->sc_dma_physaddr); if (!sc->sc_dma) { device_printf(dev, "cannot alloc sc_dma\n"); goto fail; } bzero(sc->sc_dma, sizeof(*sc->sc_dma)); /* * Reset the board and do the ``secret handshake'' * to enable the crypto support. Then complete the * initialization procedure by setting up the interrupt * and hooking in to the system crypto support so we'll * get used for system services like the crypto device, * IPsec, RNG device, etc. */ hifn_reset_board(sc, 0); if (hifn_enable_crypto(sc) != 0) { device_printf(dev, "crypto enabling failed\n"); goto fail; } hifn_reset_puc(sc); hifn_init_dma(sc); hifn_init_pci_registers(sc); pci_set_master(sc->sc_dev); /* XXX can't dynamically determine ram type for 795x; force dram */ if (sc->sc_flags & HIFN_IS_7956) sc->sc_drammodel = 1; else if (hifn_ramtype(sc)) goto fail; if (sc->sc_drammodel == 0) hifn_sramsize(sc); else hifn_dramsize(sc); /* * Workaround for NetSec 7751 rev A: half ram size because two * of the address lines were left floating */ if (pci_get_vendor(dev) == PCI_VENDOR_NETSEC && pci_get_device(dev) == PCI_PRODUCT_NETSEC_7751 && pci_get_revid(dev) == 0x61) /*XXX???*/ sc->sc_ramsize >>= 1; /* * Arrange the interrupt line. */ rc = request_irq(dev->irq, hifn_intr, SA_SHIRQ, "hifn", sc); if (rc) { device_printf(dev, "could not map interrupt: %d\n", rc); goto fail; } sc->sc_irq = dev->irq; hifn_sessions(sc); /* * NB: Keep only the low 16 bits; this masks the chip id * from the 7951. */ rev = READ_REG_1(sc, HIFN_1_REVID) & 0xffff; rseg = sc->sc_ramsize / 1024; rbase = 'K'; if (sc->sc_ramsize >= (1024 * 1024)) { rbase = 'M'; rseg /= 1024; } device_printf(sc->sc_dev, "%s, rev %u, %d%cB %cram\n", hifn_partname(sc), rev, rseg, rbase, sc->sc_drammodel ? 'd' : 's'); sc->sc_cid = crypto_get_driverid(0); if (sc->sc_cid < 0) { device_printf(dev, "could not get crypto driver id\n"); goto fail; } WRITE_REG_0(sc, HIFN_0_PUCNFG, READ_REG_0(sc, HIFN_0_PUCNFG) | HIFN_PUCNFG_CHIPID); ena = READ_REG_0(sc, HIFN_0_PUSTAT) & HIFN_PUSTAT_CHIPENA; switch (ena) { case HIFN_PUSTAT_ENA_2: crypto_register(sc->sc_cid, CRYPTO_3DES_CBC, 0, 0, hifn_newsession, hifn_freesession, hifn_process, sc); crypto_register(sc->sc_cid, CRYPTO_ARC4, 0, 0, hifn_newsession, hifn_freesession, hifn_process, sc); if (sc->sc_flags & HIFN_HAS_AES) crypto_register(sc->sc_cid, CRYPTO_AES_CBC, 0, 0, hifn_newsession, hifn_freesession, hifn_process, sc); /*FALLTHROUGH*/ case HIFN_PUSTAT_ENA_1: crypto_register(sc->sc_cid, CRYPTO_MD5, 0, 0, hifn_newsession, hifn_freesession, hifn_process, sc); crypto_register(sc->sc_cid, CRYPTO_SHA1, 0, 0, hifn_newsession, hifn_freesession, hifn_process, sc); crypto_register(sc->sc_cid, CRYPTO_MD5_HMAC, 0, 0, hifn_newsession, hifn_freesession, hifn_process, sc); crypto_register(sc->sc_cid, CRYPTO_SHA1_HMAC, 0, 0, hifn_newsession, hifn_freesession, hifn_process, sc); crypto_register(sc->sc_cid, CRYPTO_DES_CBC, 0, 0, hifn_newsession, hifn_freesession, hifn_process, sc); break; } if (sc->sc_flags & (HIFN_HAS_PUBLIC | HIFN_HAS_RNG)) hifn_init_pubrng(sc); init_timer(&sc->sc_tickto); sc->sc_tickto.function = hifn_tick; sc->sc_tickto.data = (unsigned long) sc; mod_timer(&sc->sc_tickto, jiffies + HZ); return (0);fail: if (sc->sc_cid >= 0) crypto_unregister_all(sc->sc_cid); if (sc->sc_irq != -1) free_irq(sc->sc_irq, sc); if (sc->sc_dma) { /* Turn off DMA polling */ WRITE_REG_1(sc, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MSTRESET | HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE); pci_free_consistent(sc->sc_dev, sizeof(*sc->sc_dma), sc->sc_dma, sc->sc_dma_physaddr); } kfree(sc); return (-ENXIO);}/* * Detach an interface that successfully probed. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -