/*- * Driver for Hifn HIPP-I/II chipset * Copyright (c) 2006 Michael Richardson * * 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 by Hifn Inc. * */ /* * Driver for various Hifn encryption processors. */ #include #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) && !defined(AUTOCONF_INCLUDED) #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "hifnHIPPreg.h" #include "hifnHIPPvar.h" #if 1 #define DPRINTF(a...) if (hipp_debug) { \ printk("%s: ", sc ? \ device_get_nameunit(sc->sc_dev) : "hifn"); \ printk(a); \ } else #else #define DPRINTF(a...) #endif typedef int bus_size_t; static inline int pci_get_revid(struct pci_dev *dev) { u8 rid = 0; pci_read_config_byte(dev, PCI_REVISION_ID, &rid); return rid; } #define debug hipp_debug int hipp_debug = 0; module_param(hipp_debug, int, 0644); MODULE_PARM_DESC(hipp_debug, "Enable debug"); int hipp_maxbatch = 1; module_param(hipp_maxbatch, int, 0644); MODULE_PARM_DESC(hipp_maxbatch, "max ops to batch w/o interrupt"); static int hipp_probe(struct pci_dev *dev, const struct pci_device_id *ent); static void hipp_remove(struct pci_dev *dev); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19) static irqreturn_t hipp_intr(int irq, void *arg); #else static irqreturn_t hipp_intr(int irq, void *arg, struct pt_regs *regs); #endif static int hipp_num_chips = 0; static struct hipp_softc *hipp_chip_idx[HIPP_MAX_CHIPS]; static int hipp_newsession(device_t, u_int32_t *, struct cryptoini *); static int hipp_freesession(device_t, u_int64_t); static int hipp_process(device_t, struct cryptop *, int); static device_method_t hipp_methods = { /* crypto device methods */ DEVMETHOD(cryptodev_newsession, hipp_newsession), DEVMETHOD(cryptodev_freesession,hipp_freesession), DEVMETHOD(cryptodev_process, hipp_process), }; static __inline u_int32_t READ_REG(struct hipp_softc *sc, unsigned int barno, bus_size_t reg) { u_int32_t v = readl(sc->sc_bar[barno] + reg); //sc->sc_bar0_lastreg = (bus_size_t) -1; return (v); } static __inline void WRITE_REG(struct hipp_softc *sc, unsigned int barno, bus_size_t reg, u_int32_t val) { writel(val, sc->sc_bar[barno] + reg); } #define READ_REG_0(sc, reg) READ_REG(sc, 0, reg) #define WRITE_REG_0(sc, reg, val) WRITE_REG(sc,0, reg, val) #define READ_REG_1(sc, reg) READ_REG(sc, 1, reg) #define WRITE_REG_1(sc, reg, val) WRITE_REG(sc,1, reg, val) static int hipp_newsession(device_t dev, u_int32_t *sidp, struct cryptoini *cri) { return EINVAL; } static int hipp_freesession(device_t dev, u_int64_t tid) { return EINVAL; } static int hipp_process(device_t dev, struct cryptop *crp, int hint) { return EINVAL; } static const char* hipp_partname(struct hipp_softc *sc, char buf[128], size_t blen) { char *n = NULL; switch (pci_get_vendor(sc->sc_pcidev)) { case PCI_VENDOR_HIFN: switch (pci_get_device(sc->sc_pcidev)) { case PCI_PRODUCT_HIFN_7855: n = "Hifn 7855"; case PCI_PRODUCT_HIFN_8155: n = "Hifn 8155"; case PCI_PRODUCT_HIFN_6500: n = "Hifn 6500"; } } if(n==NULL) { snprintf(buf, blen, "VID=%02x,PID=%02x", pci_get_vendor(sc->sc_pcidev), pci_get_device(sc->sc_pcidev)); } else { buf[0]='\0'; strncat(buf, n, blen); } return buf; } struct hipp_fs_entry { struct attribute attr; /* other stuff */ }; static ssize_t cryptoid_show(struct device *dev, struct device_attribute *attr, char *buf) { struct hipp_softc *sc; sc = pci_get_drvdata(to_pci_dev (dev)); return sprintf (buf, "%d\n", sc->sc_cid); } struct device_attribute hipp_dev_cryptoid = __ATTR_RO(cryptoid); /* * Attach an interface that successfully probed. */ static int hipp_probe(struct pci_dev *dev, const struct pci_device_id *ent) { struct hipp_softc *sc = NULL; int i; //char rbase; //u_int16_t ena; int rev; //int rseg; int rc; DPRINTF("%s()\n", __FUNCTION__); if (pci_enable_device(dev) < 0) return(-ENODEV); if (pci_set_mwi(dev)) return(-ENODEV); if (!dev->irq) { printk("hifn: found device with no IRQ assigned. check BIOS settings!"); pci_disable_device(dev); return(-ENODEV); } sc = (struct hipp_softc *) kmalloc(sizeof(*sc), GFP_KERNEL); if (!sc) return(-ENOMEM); memset(sc, 0, sizeof(*sc)); softc_device_init(sc, "hifn-hipp", hipp_num_chips, hipp_methods); sc->sc_pcidev = dev; sc->sc_irq = -1; sc->sc_cid = -1; sc->sc_num = hipp_num_chips++; if (sc->sc_num < HIPP_MAX_CHIPS) hipp_chip_idx[sc->sc_num] = sc; pci_set_drvdata(sc->sc_pcidev, sc); spin_lock_init(&sc->sc_mtx); /* * Setup PCI resources. * The READ_REG_0, WRITE_REG_0, READ_REG_1, * and WRITE_REG_1 macros throughout the driver are used * to permit better debugging. */ for(i=0; i<4; i++) { unsigned long mem_start, mem_len; mem_start = pci_resource_start(sc->sc_pcidev, i); mem_len = pci_resource_len(sc->sc_pcidev, i); sc->sc_barphy[i] = (caddr_t)mem_start; sc->sc_bar[i] = (ocf_iomem_t) ioremap(mem_start, mem_len); if (!sc->sc_bar[i]) { device_printf(sc->sc_dev, "cannot map bar%d register space\n", i); goto fail; } } //hipp_reset_board(sc, 0); pci_set_master(sc->sc_pcidev); /* * Arrange the interrupt line. */ rc = request_irq(dev->irq, hipp_intr, IRQF_SHARED, "hifn", sc); if (rc) { device_printf(sc->sc_dev, "could not map interrupt: %d\n", rc); goto fail; } sc->sc_irq = dev->irq; rev = READ_REG_1(sc, HIPP_1_REVID) & 0xffff; { char b[32]; device_printf(sc->sc_dev, "%s, rev %u", hipp_partname(sc, b, sizeof(b)), rev); } #if 0 if (sc->sc_flags & HIFN_IS_7956) printf(", pll=0x%x<%s clk, %ux mult>", sc->sc_pllconfig, sc->sc_pllconfig & HIFN_PLL_REF_SEL ? "ext" : "pci", 2 + 2*((sc->sc_pllconfig & HIFN_PLL_ND) >> 11)); #endif printf("\n"); sc->sc_cid = crypto_get_driverid(softc_get_device(sc),CRYPTOCAP_F_HARDWARE); if (sc->sc_cid < 0) { device_printf(sc->sc_dev, "could not get crypto driver id\n"); goto fail; } #if 0 /* cannot work with a non-GPL module */ /* make a sysfs entry to let the world know what entry we got */ sysfs_create_file(&sc->sc_pcidev->dev.kobj, &hipp_dev_cryptoid.attr); #endif #if 0 init_timer(&sc->sc_tickto); sc->sc_tickto.function = hifn_tick; sc->sc_tickto.data = (unsigned long) sc->sc_num; mod_timer(&sc->sc_tickto, jiffies + HZ); #endif #if 0 /* no code here yet ?? */ crypto_register(sc->sc_cid, CRYPTO_3DES_CBC, 0, 0); #endif 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 0 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_pcidev, sizeof(*sc->sc_dma), sc->sc_dma, sc->sc_dma_physaddr); } #endif kfree(sc); return (-ENXIO); } /* * Detach an interface that successfully probed. */ static void hipp_remove(struct pci_dev *dev) { struct hipp_softc *sc = pci_get_drvdata(dev); unsigned long l_flags; DPRINTF("%s()\n", __FUNCTION__); /* disable interrupts */ HIPP_LOCK(sc); #if 0 WRITE_REG_1(sc, HIFN_1_DMA_IER, 0); HIFN_UNLOCK(sc); /*XXX other resources */ del_timer_sync(&sc->sc_tickto); /* Turn off DMA polling */ WRITE_REG_1(sc, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MSTRESET | HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE); #endif crypto_unregister_all(sc->sc_cid); free_irq(sc->sc_irq, sc); #if 0 pci_free_consistent(sc->sc_pcidev, sizeof(*sc->sc_dma), sc->sc_dma, sc->sc_dma_physaddr); #endif } #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19) static irqreturn_t hipp_intr(int irq, void *arg) #else static irqreturn_t hipp_intr(int irq, void *arg, struct pt_regs *regs) #endif { struct hipp_softc *sc = arg; sc = sc; /* shut up compiler */ return IRQ_HANDLED; } static struct pci_device_id hipp_pci_tbl[] = { { PCI_VENDOR_HIFN, PCI_PRODUCT_HIFN_7855, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, { PCI_VENDOR_HIFN, PCI_PRODUCT_HIFN_8155, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, { 0 }, /* terminating entry */ }; MODULE_DEVICE_TABLE(pci, hipp_pci_tbl); static struct pci_driver hipp_driver = { .name = "hipp", .id_table = hipp_pci_tbl, .probe = hipp_probe, .remove = hipp_remove, /* add PM stuff here one day */ }; static int __init hipp_init (void) { struct hipp_softc *sc = NULL; int rc; DPRINTF("%s(%p)\n", __FUNCTION__, hipp_init); rc = pci_register_driver(&hipp_driver); pci_register_driver_compat(&hipp_driver, rc); return rc; } static void __exit hipp_exit (void) { pci_unregister_driver(&hipp_driver); } module_init(hipp_init); module_exit(hipp_exit); MODULE_LICENSE("Dual BSD/GPL"); MODULE_AUTHOR("Michael Richardson "); MODULE_DESCRIPTION("OCF driver for hifn HIPP-I/II PCI crypto devices");