2008-11-19 12:25:39 +00:00
|
|
|
/*-
|
|
|
|
* Driver for Hifn HIPP-I/II chipset
|
|
|
|
* Copyright (c) 2006 Michael Richardson <mcr@xelerance.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 by Hifn Inc.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Driver for various Hifn encryption processors.
|
|
|
|
*/
|
2011-03-19 17:40:02 +00:00
|
|
|
#include <linux/version.h>
|
2011-07-24 14:17:58 +00:00
|
|
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) && !defined(AUTOCONF_INCLUDED)
|
|
|
|
#include <linux/config.h>
|
2008-11-19 12:25:39 +00:00
|
|
|
#endif
|
|
|
|
#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 <linux/skbuff.h>
|
|
|
|
#include <linux/uio.h>
|
|
|
|
#include <linux/sysfs.h>
|
|
|
|
#include <linux/miscdevice.h>
|
|
|
|
#include <asm/io.h>
|
|
|
|
|
|
|
|
#include <cryptodev.h>
|
|
|
|
|
|
|
|
#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, },
|
2012-07-12 08:34:23 +00:00
|
|
|
{ 0 }, /* terminating entry */
|
2008-11-19 12:25:39 +00:00
|
|
|
};
|
|
|
|
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("BSD");
|
|
|
|
MODULE_AUTHOR("Michael Richardson <mcr@xelerance.com>");
|
|
|
|
MODULE_DESCRIPTION("OCF driver for hifn HIPP-I/II PCI crypto devices");
|