svn commit: r186459 - in projects/cambria/sys/arm: conf
xscale/ixp425
Sam Leffler
sam at FreeBSD.org
Tue Dec 23 12:45:40 PST 2008
Author: sam
Date: Tue Dec 23 20:45:40 2008
New Revision: 186459
URL: http://svn.freebsd.org/changeset/base/186459
Log:
checkpoint NPE crypto support; this is just a shell of the driver but
compiles and doesn't affect the system so commit it to simplify merges
Added:
projects/cambria/sys/arm/xscale/ixp425/ixp4xx_crypto.c (contents, props changed)
Modified:
projects/cambria/sys/arm/conf/AVILA
projects/cambria/sys/arm/conf/AVILA.hints
projects/cambria/sys/arm/conf/CAMBRIA (contents, props changed)
projects/cambria/sys/arm/conf/CAMBRIA.hints (contents, props changed)
projects/cambria/sys/arm/xscale/ixp425/files.ixp425
Modified: projects/cambria/sys/arm/conf/AVILA
==============================================================================
--- projects/cambria/sys/arm/conf/AVILA Tue Dec 23 20:43:42 2008 (r186458)
+++ projects/cambria/sys/arm/conf/AVILA Tue Dec 23 20:45:40 2008 (r186459)
@@ -83,6 +83,10 @@ device ata
device atadisk # ATA disk drives
device avila_ata # Gateworks CF/IDE support
+device ixpcrypto # requires npe + qmgr
+device crypto
+device cryptodev
+
device npe # Network Processing Engine
device npe_fw
device firmware
Modified: projects/cambria/sys/arm/conf/AVILA.hints
==============================================================================
--- projects/cambria/sys/arm/conf/AVILA.hints Tue Dec 23 20:43:42 2008 (r186458)
+++ projects/cambria/sys/arm/conf/AVILA.hints Tue Dec 23 20:45:40 2008 (r186459)
@@ -29,6 +29,9 @@ hint.npe.1.mac="C"
hint.npe.1.mii="B"
hint.npe.1.phy=1
+# NPE crypto acceleration
+hint.ixpcrypto.0.at="ixp0"
+
# CF IDE controller
hint.ata_avila.0.at="ixp0"
Modified: projects/cambria/sys/arm/conf/CAMBRIA
==============================================================================
--- projects/cambria/sys/arm/conf/CAMBRIA Tue Dec 23 20:43:42 2008 (r186458)
+++ projects/cambria/sys/arm/conf/CAMBRIA Tue Dec 23 20:45:40 2008 (r186459)
@@ -84,6 +84,10 @@ device ata
device atadisk # ATA disk drives
device avila_ata # Gateworks CF/IDE support
+device ixpcrypto # requires npe + qmgr
+device crypto
+device cryptodev
+
device npe # Network Processing Engine
device npe_fw
device firmware
@@ -102,7 +106,7 @@ device random # Entrop
# NB: 2 USB 2.0 ports standard
device usb
options USB_EHCI_BIG_ENDIAN_DESC # handle big-endian byte order
-#options USB_DEBUG
+options USB_DEBUG
device ehci
device ugen
device umass
Modified: projects/cambria/sys/arm/conf/CAMBRIA.hints
==============================================================================
--- projects/cambria/sys/arm/conf/CAMBRIA.hints Tue Dec 23 20:43:42 2008 (r186458)
+++ projects/cambria/sys/arm/conf/CAMBRIA.hints Tue Dec 23 20:45:40 2008 (r186459)
@@ -27,6 +27,9 @@ hint.npe.0.phy=1
#hint.npe.1.mii="C"
#hint.npe.1.phy=2
+# NPE crypto acceleration
+hint.ixpcrypto.0.at="ixp0"
+
# CF IDE controller
hint.ata_avila.0.at="ixp0"
Modified: projects/cambria/sys/arm/xscale/ixp425/files.ixp425
==============================================================================
--- projects/cambria/sys/arm/xscale/ixp425/files.ixp425 Tue Dec 23 20:43:42 2008 (r186458)
+++ projects/cambria/sys/arm/xscale/ixp425/files.ixp425 Tue Dec 23 20:45:40 2008 (r186459)
@@ -44,5 +44,6 @@ IxNpeMicrocode.dat optional npe_fw \
# Q-Manager support
#
arm/xscale/ixp425/ixp425_qmgr.c optional qmgr
+arm/xscale/ixp425/ixp4xx_crypto.c optional ixpcrypto
#
-arm/xscale/ixp425/ixp435_ehci.c optional ehci
+dev/usb/ehci_ixp4xx.c optional ehci
Added: projects/cambria/sys/arm/xscale/ixp425/ixp4xx_crypto.c
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ projects/cambria/sys/arm/xscale/ixp425/ixp4xx_crypto.c Tue Dec 23 20:45:40 2008 (r186459)
@@ -0,0 +1,722 @@
+/*-
+ * Copyright (c) 2008 Sam Leffler. All rights reserved.
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``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 AUTHORS OR CONTRIBUTORS 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/lock.h>
+#include <sys/rwlock.h>
+#include <sys/malloc.h>
+#include <sys/sysctl.h>
+#include <sys/endian.h>
+
+#include <opencrypto/cryptodev.h>
+
+#include <sys/kobj.h>
+#include <sys/bus.h>
+#include "cryptodev_if.h"
+
+#include <arm/xscale/ixp425/ixp425reg.h>
+#include <arm/xscale/ixp425/ixp425var.h>
+#include <arm/xscale/ixp425/ixp425_qmgr.h>
+#include <arm/xscale/ixp425/ixp425_npevar.h>
+
+/*
+ * NPE crypto hw accelration Operation Opcode definition, by default
+ * the transfer mode = 0 (in-place) and Crypt direction = 0 (decrypt)
+ *
+ * NPE Crypto Hw Acceleration Operation Opcode bit field definition (pls
+ * refer to IxCryptoNpeOperationMode) for details :
+ *
+ * DATH CM0Vb
+ * D : Cryption Direction
+ * A : Hmac Enable
+ * T : Transfer Mode
+ * H : Hash Enable
+ * C : Crypt Enable
+ * M : CCM Enable
+ * V : Verification enable / Key Generation enable
+ */
+#define NPE_OP_HASH_GEN_ICV 0x50 /* hash */
+#define NPE_OP_HASH_VER_ICV 0x51 /* hash + ICV verification */
+#define NPE_OP_HMAC_GEN_ICV 0x10 /* HMAC + ICV generation */
+#define NPE_OP_HMAC_VER_ICV 0x11 /* HMAC + ICV verification */
+#define NPE_OP_CRYPT 0x48 /* Cryption operation */
+#define NPE_OP_CCM_GEN_MIC 0xCC /* CCM Encrypt with MIC Gen */
+#define NPE_OP_CCM_VER_MIC 0x4D /* CCM Decrypt with MIC Ver */
+#define NPE_OP_ENC_GEN_KEY 0xC9 /* Reverse AES key generation */
+#define NPE_OP_ENC_HMAC_GEN_ICV 0x98 /* Encrypt + HMAC */
+#define NPE_OP_HMAC_VER_ICV_DEC 0x19 /* reverse HMAC + Decrypt */
+/* modifiers or'd in */
+#define NPE_OP_CCM_ENA 0x04 /* CCM Enable */
+#define NPE_OP_CRYPT_ENA 0x08 /* Crypt enable mask */
+#define NPE_OP_TRANSFER_MODE 0x20 /* Transfer mode mask */
+#define NPE_OP_HMAC_DISABLE 0x40 /* HMAC enable mask */
+#define NPE_OP_CRYPT_DIR 0x80 /* Crypt direction mask */
+
+#define MOD_ECB 0x0000
+#define MOD_CTR 0x1000
+#define MOD_CBC_ENC 0x2000
+#define MOD_CBC_DEC 0x3000
+#define MOD_CCM_ENC 0x4000
+#define MOD_CCM_DEC 0x5000
+
+#define CIPH_DECR 0x0000
+#define CIPH_ENCR 0x0400
+
+#define MOD_DES 0x0000
+#define MOD_TDEA2 0x0100
+#define MOD_3DES 0x0200
+#define MOD_AES 0x0800
+#define MOD_AES128 (0x0800 | 4) /* 128-bit key = 4 words */
+#define MOD_AES192 (0x0900 | 6) /* 192-bit key = 6 words */
+#define MOD_AES256 (0x0a00 | 8) /* 256-bit key = 8 words */
+
+#define CTL_FLAG_UNUSED 0x0000
+#define CTL_FLAG_USED 0x1000
+#define CTL_FLAG_PERFORM_ABLK 0x0001
+#define CTL_FLAG_GEN_ICV 0x0002
+#define CTL_FLAG_GEN_REVAES 0x0004
+#define CTL_FLAG_PERFORM_AEAD 0x0008
+#define CTL_FLAG_MASK 0x000f
+
+#define NPE_MAXSEG 3 /* empirically selected */
+
+struct npehwbuf {
+ struct { /* NPE shared area, cacheline aligned */
+ uint32_t next; /* phys addr of next segment */
+ uint32_t len; /* buffer/segment length (bytes) */
+ uint32_t data; /* phys addr of data segment */
+ uint32_t pad[5]; /* pad to cacheline */
+ } ne[NPE_MAXSEG];
+};
+
+#define NPE_QM_Q_ADDR(e) ((e)&0xffffffff8) /* phys address */
+#define NPE_QM_Q_OK(e) (((e)&1) == 0) /* cmd status */
+
+struct npehwctx { /* h/w crypto context */
+ uint8_t op; /* npe operation */
+ uint8_t init_len;
+ uint16_t pad;
+ uint8_t iv[16]; /* IV for CBC or CTR IV for CTR */
+ union {
+ uint32_t icvAddr; /* address for ICV */
+ uint32_t revAesKeyaddr; /* address for Rev AES key */
+ } u;
+#define icv u.icvAddr
+#define rev_aes u.revAesKeyaddr
+ uint32_t src; /* phys addr of src data */
+ uint32_t dst; /* phys addr of dst data */
+ uint16_t hash_off; /* authentication start offset */
+ uint16_t hash_len; /* authentication data length */
+ uint16_t cipher_off; /* cipher start offset */
+ uint16_t cipher_len; /* cipher data length */
+ uint32_t aad_addr; /* Additional Auth Data addr for CCM */
+ uint32_t ctx; /* phys addr of NPE crypto context */
+};
+
+struct ixpcrypto_session {
+ TAILQ_ENTRY(ixpcrypto_session) next;
+ uint32_t id;
+ int inuse;
+ uint8_t authkey[32];
+ int authkey_len;
+ uint8_t cipherkey[32];
+ int cipherkey_len;
+ uint8_t iv[16];
+};
+
+struct npebuf {
+ struct npebuf *next; /* chain to next buffer */
+ bus_dmamap_t map; /* bus dma map for associated data */
+ struct npehwbuf *hw; /* associated h/w block */
+ uint32_t neaddr; /* phys address of hw->ne */
+ struct cryptop *crp; /* associated crypto operation */
+};
+
+struct ixpcrypto_softc {
+ device_t dev;
+ int debug; /* debug msg flags */
+ int32_t cid; /* crypto driver id */
+ uint32_t sid; /* next available session id */
+ struct rwlock sessions_lock; /* lock over session table */
+ TAILQ_HEAD(ixpcrypto_sessions_head, ixpcrypto_session) sessions;
+ struct ixpnpe_softc *npe; /* handle on NPE engine */
+ bus_dma_tag_t dtag; /* bus dma tag for mapped data */
+ struct npehwbuf *hwbuf; /* NPE h/w buffers */
+ bus_dma_tag_t buf_tag; /* tag+map for NPE cmd buffers */
+ bus_dmamap_t buf_map;
+ bus_addr_t buf_phys; /* phys addr of h/w buffers */
+ struct npebuf *buf; /* cmd buffers (1-1 w/ h/w) */
+ struct npebuf *free; /* list of free cmd buffers */
+ struct mtx mtx; /* lock over cmd buffer list */
+ int cmd_qid; /* qid for submitting cmds */
+ int cmddone_qid; /* qid cmds return on */
+};
+
+SYSCTL_NODE(_hw, OID_AUTO, ixpcrypto, CTLFLAG_RD, 0,
+ "IXP4XX Crypto driver parameters");
+
+static int ixpcrypto_debug = 0;
+SYSCTL_INT(_hw_ixpcrypto, OID_AUTO, debug, CTLFLAG_RW, &ixpcrypto_debug,
+ 0, "IXP4XX Crypto debug msgs");
+TUNABLE_INT("hw.ixpcrypto.npe", &ixpcrypto_debug);
+#define DPRINTF(sc, fmt, ...) do { \
+ if (sc->debug) device_printf(sc->dev, fmt, __VA_ARGS__); \
+} while (0)
+#define DPRINTFn(n, sc, fmt, ...) do { \
+ if (sc->debug >= n) device_printf(sc->dev, fmt, __VA_ARGS__); \
+} while (0)
+
+static int ixpcrypto_cmdbuf = 64; /* # cmd buffers to allocate */
+SYSCTL_INT(_hw_ixpcrypto, OID_AUTO, cmdbuf, CTLFLAG_RD, &ixpcrypto_cmdbuf,
+ 0, "cmd buffers allocated");
+TUNABLE_INT("hw.ixpcrypto.cmdbuf", &ixpcrypto_cmdbuf);
+
+static int ixpcrypto_dma_setup(struct ixpcrypto_softc *);
+static void ixpcrypto_dma_destroy(struct ixpcrypto_softc *);
+static int ixpcrypto_newsession(device_t, uint32_t *, struct cryptoini *);
+static int ixpcrypto_freesession(device_t, uint64_t);
+static void ixpcrypto_freesession_locked(struct ixpcrypto_softc *,
+ struct ixpcrypto_session *);
+static int ixpcrypto_process(device_t, struct cryptop *, int hint __unused);
+static void ixpcrypto_cmddone(int qid, void *arg);
+
+MALLOC_DEFINE(M_IXPCRYPTO, "ixpcrypto_data", "IXP Crypto Data");
+
+static int
+ixpcrypto_probe(device_t dev)
+{
+ int unit = device_get_unit(dev);
+
+ /* NB: this assumes we'll load firmware w/ crypto support */
+ if (unit != 0 || (ixp4xx_read_feature_bits() & EXP_FCTRL_NPEC) == 0)
+ return EINVAL;
+ device_set_desc_copy(dev, "IXP4XX Crypto");
+ return 0;
+}
+
+static int
+ixpcrypto_attach(device_t dev)
+{
+ struct ixpcrypto_softc *sc = device_get_softc(dev);
+ int error;
+
+ sc->dev = dev;
+ sc->debug = ixpcrypto_debug;
+
+ error = ixpcrypto_dma_setup(sc);
+ if (error != 0) {
+ device_printf(dev, "cannot setup dma (error %d)\n", error);
+ return error;
+ }
+
+ sc->npe = ixpnpe_attach(dev, NPE_C);
+ if (sc->npe == NULL) {
+ device_printf(dev, "cannot attach ixpnpe\n");
+ error = EIO; /* XXX */
+ goto bad;
+ }
+ error = ixpnpe_init(sc->npe);
+ if (error != 0) {
+ device_printf(dev, "cannot init NPE (error %d)\n", error);
+ goto bad;
+ }
+
+ sc->cmd_qid = 29;
+ ixpqmgr_qconfig(sc->cmd_qid, ixpcrypto_cmdbuf, 0,
+ ixpcrypto_cmdbuf, 0, NULL, sc);
+
+ sc->cmddone_qid = 30;
+ KASSERT(ixpcrypto_cmdbuf > 2*4, ("%d cmd buffers", ixpcrypto_cmdbuf));
+ ixpqmgr_qconfig(sc->cmddone_qid, ixpcrypto_cmdbuf/4, 0, 2,
+ IX_QMGR_Q_SOURCE_ID_NOT_E, ixpcrypto_cmddone, sc);
+
+ sc->cid = crypto_get_driverid(dev, CRYPTOCAP_F_HARDWARE);
+ if (sc->cid < 0) {
+ device_printf(dev, "Could not get crypto driver id.\n");
+ error = ENOMEM;
+ goto bad;
+ }
+
+ rw_init(&sc->sessions_lock, "ixpcrypto_lock");
+ TAILQ_INIT(&sc->sessions);
+ sc->sid = 1;
+
+ if (ixp4xx_read_feature_bits() & EXP_FCTRL_DES) {
+ crypto_register(sc->cid, CRYPTO_DES_CBC, 0, 0);
+ crypto_register(sc->cid, CRYPTO_3DES_CBC, 0, 0);
+ }
+ if (ixp4xx_read_feature_bits() & EXP_FCTRL_AES) {
+ crypto_register(sc->cid, CRYPTO_AES_CBC, 0, 0);
+#ifdef CRYPTO_AES_CTR_CBC
+ crypto_register(sc->cid, CRYPTO_AES_CTR_CBC, 0, 0);
+#endif
+ }
+ if (ixp4xx_read_feature_bits() & EXP_FCTRL_HASH) {
+ crypto_register(sc->cid, CRYPTO_MD5_HMAC, 0, 0);
+ crypto_register(sc->cid, CRYPTO_SHA1_HMAC, 0, 0);
+ }
+#if 0
+ /* XXX needs s/w assist */
+ crypto_register(sc->cid, CRYPTO_SHA2_256_HMAC, 0, 0);
+ crypto_register(sc->cid, CRYPTO_SHA2_384_HMAC, 0, 0);
+ crypto_register(sc->cid, CRYPTO_SHA2_512_HMAC, 0, 0);
+#endif
+ return 0;
+bad:
+ if (sc->npe != NULL)
+ ixpnpe_detach(sc->npe);
+ ixpcrypto_dma_destroy(sc);
+ return error;
+}
+
+static int
+ixpcrypto_detach(device_t dev)
+{
+ struct ixpcrypto_softc *sc = device_get_softc(dev);
+ struct ixpcrypto_session *ses;
+
+ rw_wlock(&sc->sessions_lock);
+ TAILQ_FOREACH(ses, &sc->sessions, next) {
+ if (ses->inuse) {
+ rw_wunlock(&sc->sessions_lock);
+ device_printf(dev,
+ "Cannot detach, sessions still active.\n");
+ return EBUSY;
+ }
+ }
+ while ((ses = TAILQ_FIRST(&sc->sessions)) != NULL) {
+ TAILQ_REMOVE(&sc->sessions, ses, next);
+ free(ses, M_IXPCRYPTO);
+ }
+ rw_destroy(&sc->sessions_lock);
+
+ crypto_unregister_all(sc->cid);
+#if 0
+ ixpnpe_stop(sc->npe);
+#endif
+ ixpnpe_detach(sc->npe);
+ ixpcrypto_dma_destroy(sc);
+ return 0;
+}
+
+static void
+npe_getaddr(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
+{
+ if (error == 0)
+ ((struct ixpcrypto_softc *)arg)->buf_phys = segs[0].ds_addr;
+}
+
+static int
+ixpcrypto_dma_setup(struct ixpcrypto_softc *sc)
+{
+ int error, i;
+
+ mtx_init(&sc->mtx, "ixpcrypto", NULL, MTX_DEF);
+
+ /* DMA tag for mapped mbufs */
+ error = bus_dma_tag_create(bus_get_dma_tag(device_get_parent(sc->dev)),
+ 1, 0, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
+ /* XXX 64K */
+ 64*1024, NPE_MAXSEG, 64*1024, 0, NULL, NULL, &sc->dtag);
+ if (error != 0) {
+ device_printf(sc->dev, "unable to create mbuf dma tag, "
+ "error %u\n", error);
+ return error;
+ }
+
+ /* DMA tag and map for the NPE buffers */
+ error = bus_dma_tag_create(bus_get_dma_tag(device_get_parent(sc->dev)),
+ sizeof(uint32_t), 0, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR,
+ NULL, NULL,
+ ixpcrypto_cmdbuf * sizeof(struct npehwbuf), 1,
+ ixpcrypto_cmdbuf * sizeof(struct npehwbuf), 0,
+ NULL, NULL, &sc->buf_tag);
+ if (error != 0) {
+ device_printf(sc->dev,
+ "unable to create npebuf dma tag, error %u\n", error);
+ return error;
+ }
+ /* XXX COHERENT for now */
+ if (bus_dmamem_alloc(sc->buf_tag, (void **)&sc->hwbuf,
+ BUS_DMA_NOWAIT | BUS_DMA_ZERO | BUS_DMA_COHERENT,
+ &sc->buf_map) != 0) {
+ device_printf(sc->dev,
+ "unable to allocate memory for h/w buffers, error %u\n",
+ error);
+ return error;
+ }
+ sc->buf = malloc(ixpcrypto_cmdbuf * sizeof(struct npebuf),
+ M_IXPCRYPTO, M_NOWAIT | M_ZERO);
+ if (sc->buf == NULL) {
+ device_printf(sc->dev,
+ "unable to allocate memory for s/w buffers\n");
+ return error;
+ }
+ if (bus_dmamap_load(sc->buf_tag, sc->buf_map,
+ sc->hwbuf, ixpcrypto_cmdbuf*sizeof(struct npehwbuf), npe_getaddr, sc, 0) != 0) {
+ device_printf(sc->dev,
+ "unable to map memory for h/w buffers, error %u\n", error);
+ return error;
+ }
+ /* NB: sc->buf_phys set by npe_getaddr */
+ for (i = 0; i < ixpcrypto_cmdbuf; i++) {
+ struct npebuf *npe = &sc->buf[i];
+ struct npehwbuf *hw = &sc->hwbuf[i];
+
+ /* calculate offset to shared area */
+ npe->neaddr = sc->buf_phys +
+ ((uintptr_t)hw - (uintptr_t)sc->hwbuf);
+ KASSERT((npe->neaddr & 0x1f) == 0,
+ ("ixpbuf misaligned, PA 0x%x", npe->neaddr));
+ error = bus_dmamap_create(sc->dtag, BUS_DMA_NOWAIT, &npe->map);
+ if (error != 0) {
+ device_printf(sc->dev,
+ "unable to create dmamap for buffer %u, "
+ "error %u\n", i, error);
+ return error;
+ }
+ npe->hw = hw;
+
+ npe->next = sc->free;
+ sc->free = npe;
+ }
+ bus_dmamap_sync(sc->buf_tag, sc->buf_map, BUS_DMASYNC_PREWRITE);
+ return 0;
+}
+
+static void
+ixpcrypto_dma_destroy(struct ixpcrypto_softc *sc)
+{
+ int i;
+
+ if (sc->hwbuf != NULL) {
+ for (i = 0; i < ixpcrypto_cmdbuf; i++) {
+ struct npebuf *npe = &sc->buf[i];
+ bus_dmamap_destroy(sc->dtag, npe->map);
+ }
+ bus_dmamap_unload(sc->buf_tag, sc->buf_map);
+ bus_dmamem_free(sc->buf_tag, sc->hwbuf, sc->buf_map);
+ }
+ if (sc->buf != NULL)
+ free(sc->buf, M_IXPCRYPTO);
+ if (sc->buf_tag)
+ bus_dma_tag_destroy(sc->buf_tag);
+ if (sc->dtag)
+ bus_dma_tag_destroy(sc->dtag);
+ mtx_destroy(&sc->mtx);
+}
+
+static int
+ixpcrypto_newsession(device_t dev, uint32_t *sidp, struct cryptoini *cri)
+{
+ struct ixpcrypto_softc *sc = device_get_softc(dev);
+ struct ixpcrypto_session *ses = NULL;
+ struct cryptoini *encini, *macini;
+
+ if (sidp == NULL || cri == NULL)
+ return EINVAL;
+
+ encini = macini = NULL;
+ for (; cri != NULL; cri = cri->cri_next) {
+ switch (cri->cri_alg) {
+ case CRYPTO_NULL_HMAC:
+ case CRYPTO_MD5_HMAC:
+ case CRYPTO_SHA1_HMAC:
+ case CRYPTO_SHA2_256_HMAC:
+ case CRYPTO_SHA2_384_HMAC:
+ case CRYPTO_SHA2_512_HMAC:
+ if (macini != NULL)
+ return EINVAL;
+ macini = cri;
+ break;
+ case CRYPTO_DES_CBC:
+ case CRYPTO_3DES_CBC:
+ case CRYPTO_AES_CBC:
+#ifdef CRYPTO_AES_CTR_CBC
+ case CRYPTO_AES_CTR_CBC:
+#endif
+ if (encini != NULL)
+ return EINVAL;
+ encini = cri;
+ break;
+ default:
+ return EINVAL;
+ }
+ }
+
+ /*
+ * Let's look for a free session structure.
+ */
+ rw_wlock(&sc->sessions_lock);
+ /*
+ * Free sessions goes first, so if first session is used, we need to
+ * allocate one.
+ */
+ ses = TAILQ_FIRST(&sc->sessions);
+ if (ses == NULL || ses->inuse) {
+ ses = malloc(sizeof(*ses), M_IXPCRYPTO, M_NOWAIT | M_ZERO);
+ if (ses == NULL) {
+ rw_wunlock(&sc->sessions_lock);
+ return ENOMEM;
+ }
+ ses->id = sc->sid++;
+ } else {
+ TAILQ_REMOVE(&sc->sessions, ses, next);
+ }
+ ses->inuse = 1;
+ TAILQ_INSERT_TAIL(&sc->sessions, ses, next);
+ rw_wunlock(&sc->sessions_lock);
+
+ *sidp = ses->id;
+ return 0;
+}
+
+static void
+ixpcrypto_freesession_locked(struct ixpcrypto_softc *sc,
+ struct ixpcrypto_session *ses)
+{
+ uint32_t sid = ses->id;
+
+ TAILQ_REMOVE(&sc->sessions, ses, next);
+ bzero(ses, sizeof(*ses));
+ ses->inuse = 0;
+ ses->id = sid;
+ TAILQ_INSERT_HEAD(&sc->sessions, ses, next);
+}
+
+static int
+ixpcrypto_freesession(device_t dev, uint64_t tid)
+{
+ struct ixpcrypto_softc *sc = device_get_softc(dev);
+ struct ixpcrypto_session *ses;
+ uint32_t sid = ((uint32_t)tid) & 0xffffffff;
+
+ rw_wlock(&sc->sessions_lock);
+ TAILQ_FOREACH_REVERSE(ses, &sc->sessions, ixpcrypto_sessions_head, next) {
+ if (ses->id == sid) {
+ ixpcrypto_freesession_locked(sc, ses);
+ rw_wunlock(&sc->sessions_lock);
+ return 0;
+ }
+ }
+ rw_wunlock(&sc->sessions_lock);
+ return EINVAL;
+}
+
+static void
+ixpcrypto_cb(void *arg,
+ bus_dma_segment_t *segs, int nsegs, bus_size_t len, int error)
+{
+ struct npebuf *npe = arg;
+ struct npehwbuf *hw;
+ uint32_t next;
+ int i;
+
+ if (error != 0)
+ return;
+ hw = npe->hw;
+ next = npe->neaddr + sizeof(hw->ne[0]);
+ for (i = 0; i < nsegs; i++) {
+ hw->ne[i].data = htobe32(segs[i].ds_addr);
+ hw->ne[i].len = htobe32((segs[i].ds_len<<16) | len);
+ hw->ne[i].next = htobe32(next);
+
+ len = 0; /* zero for segments > 1 */
+ next += sizeof(hw->ne[0]);
+ }
+ hw->ne[i-1].next = 0; /* zero last in chain */
+}
+
+static int
+ixpcrypto_process(device_t dev, struct cryptop *crp, int hint __unused)
+{
+ struct ixpcrypto_softc *sc = device_get_softc(dev);
+ struct ixpcrypto_session *ses = NULL;
+ struct cryptodesc *crd, *enccrd, *maccrd;
+ struct npebuf *npe;
+ int error = 0;
+
+ enccrd = maccrd = NULL;
+
+ /* Sanity check. */
+ if (crp == NULL)
+ return EINVAL;
+
+ if (crp->crp_callback == NULL || crp->crp_desc == NULL) {
+ error = EINVAL;
+ goto out;
+ }
+
+ for (crd = crp->crp_desc; crd != NULL; crd = crd->crd_next) {
+ switch (crd->crd_alg) {
+ case CRYPTO_NULL_HMAC:
+ case CRYPTO_MD5_HMAC:
+ case CRYPTO_SHA1_HMAC:
+#if 0
+ case CRYPTO_SHA2_256_HMAC:
+ case CRYPTO_SHA2_384_HMAC:
+ case CRYPTO_SHA2_512_HMAC:
+#endif
+ if (maccrd != NULL) {
+ error = EINVAL;
+ goto out;
+ }
+ maccrd = crd;
+ break;
+ case CRYPTO_AES_CBC:
+ if (enccrd != NULL) {
+ error = EINVAL;
+ goto out;
+ }
+ enccrd = crd;
+ break;
+ default:
+ return EINVAL;
+ }
+ }
+ if (enccrd == NULL || (enccrd->crd_len % AES_BLOCK_LEN) != 0) {
+ error = EINVAL;
+ goto out;
+ }
+
+ rw_rlock(&sc->sessions_lock);
+ TAILQ_FOREACH_REVERSE(ses, &sc->sessions, ixpcrypto_sessions_head, next) {
+ if (ses->id == (crp->crp_sid & 0xffffffff))
+ break;
+ }
+ rw_runlock(&sc->sessions_lock);
+ if (ses == NULL) {
+ error = EINVAL;
+ goto out;
+ }
+
+ mtx_lock(&sc->mtx);
+ npe = sc->free;
+ if (npe != NULL)
+ sc->free = npe->next;
+ mtx_unlock(&sc->mtx);
+ if (npe == NULL) {
+ error = ENOBUFS;
+ goto out;
+ }
+
+ npe->crp = crp;
+ if (crp->crp_flags & CRYPTO_F_IMBUF) {
+ error = bus_dmamap_load_mbuf(sc->dtag, npe->map,
+ (struct mbuf *) crp->crp_buf,
+ ixpcrypto_cb, npe, BUS_DMA_NOWAIT);
+ } else if (crp->crp_flags & CRYPTO_F_IOV) {
+ error = bus_dmamap_load_uio(sc->dtag, npe->map,
+ (struct uio *) crp->crp_buf,
+ ixpcrypto_cb, npe, BUS_DMA_NOWAIT);
+ } else
+ error = EINVAL;
+ if (error != 0) {
+ device_printf(sc->dev, "%s: error %u\n", __func__, error);
+ mtx_lock(&sc->mtx);
+ npe->next = sc->free;
+ sc->free = npe;
+ mtx_unlock(&sc->mtx);
+ goto out;
+ }
+
+ bus_dmamap_sync(sc->dtag, npe->map, BUS_DMASYNC_PREWRITE);
+ /* XXX flush descriptor instead of using uncached memory */
+
+ DPRINTF(sc, "%s: qwrite(%u, 0x%x) data %x len 0x%x\n",
+ __func__, sc->cmd_qid, npe->neaddr,
+ npe->hw->ne[0].data, npe->hw->ne[0].len);
+ /* stick it on the cmd q */
+ ixpqmgr_qwrite(sc->cmd_qid, npe->neaddr);
+ return 0;
+out:
+ crp->crp_etype = error;
+ crypto_done(crp);
+ return error;
+}
+
+static void
+ixpcrypto_cmddone(int qid, void *arg)
+{
+#define P2V(a, sc) \
+ &(sc)->buf[((a) - (sc)->buf_phys) / sizeof(struct npehwbuf)]
+ struct ixpcrypto_softc *sc = arg;
+ uint32_t entry;
+ struct npebuf *head;
+ struct npebuf **tail;
+ struct npebuf *npe;
+
+ head = NULL;
+ tail = &head;
+ while (ixpqmgr_qread(qid, &entry) == 0) {
+ npe = P2V(NPE_QM_Q_ADDR(entry), sc);
+
+ /* XXX optimize based on request */
+ bus_dmamap_sync(sc->dtag, npe->map,
+ BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
+
+ /* XXX copyback iv */
+ crypto_done(npe->crp);
+
+ *tail = npe;
+ tail = &npe->next;
+ }
+ mtx_lock(&sc->mtx);
+ *tail = sc->free;
+ sc->free = head;
+ mtx_unlock(&sc->mtx);
+#undef P2V
+}
+
+static device_method_t ixpcrypto_methods[] = {
+ DEVMETHOD(device_probe, ixpcrypto_probe),
+ DEVMETHOD(device_attach, ixpcrypto_attach),
+ DEVMETHOD(device_detach, ixpcrypto_detach),
+
+ DEVMETHOD(cryptodev_newsession, ixpcrypto_newsession),
+ DEVMETHOD(cryptodev_freesession,ixpcrypto_freesession),
+ DEVMETHOD(cryptodev_process, ixpcrypto_process),
+
+ {0, 0},
+};
+
+static driver_t ixpcrypto_driver = {
+ "ixpcrypto",
+ ixpcrypto_methods,
+ sizeof(struct ixpcrypto_softc),
+};
+static devclass_t ixpcrypto_devclass;
+
+DRIVER_MODULE(ixpcrypto, ixp, ixpcrypto_driver, ixpcrypto_devclass, 0, 0);
+MODULE_VERSION(ixpcrypto, 1);
+MODULE_DEPEND(ixpcrypto, ixpqmgr, 1, 1, 1);
+MODULE_DEPEND(ixpcrypto, crypto, 1, 1, 1);
More information about the svn-src-projects
mailing list