Module Name:    src
Committed By:   kiyohara
Date:           Fri Jul 27 03:00:01 UTC 2012

Modified Files:
        src/sys/dev/marvell: files.discovery
Added Files:
        src/sys/dev/marvell: mvcesa.c mvcesareg.h

Log Message:
Add Marvell CESA(Cryptographic Engines and Security Accelerator) module driver.
But support only PIO-mode now.  Also AES-CBC not supported.
 Don't know how to process to AES CBC in PIO-mode. I haven't found IV registers.


To generate a diff of this commit:
cvs rdiff -u -r1.18 -r1.19 src/sys/dev/marvell/files.discovery
cvs rdiff -u -r0 -r1.1 src/sys/dev/marvell/mvcesa.c \
    src/sys/dev/marvell/mvcesareg.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/marvell/files.discovery
diff -u src/sys/dev/marvell/files.discovery:1.18 src/sys/dev/marvell/files.discovery:1.19
--- src/sys/dev/marvell/files.discovery:1.18	Sat Oct  2 05:53:37 2010
+++ src/sys/dev/marvell/files.discovery	Fri Jul 27 03:00:01 2012
@@ -1,4 +1,4 @@
-#	$NetBSD: files.discovery,v 1.18 2010/10/02 05:53:37 kiyohara Exp $
+#	$NetBSD: files.discovery,v 1.19 2012/07/27 03:00:01 kiyohara Exp $
 #
 # Config file and device description for machine-independent support for
 # the Marvell (formerly Galileo Technology) Discovery system controllers.
@@ -72,9 +72,9 @@ attach	ehci at gt with mvusb_gt
 file	dev/marvell/ehci_mv.c		mvusb_gt | mvusb_mbus
 
 # Cryptographic Engines and Security Accelerator
-#device	mvcesa: opencrypto
-#file	dev/marvell/mvcesa.c		mvcesa
-#attach	mvcesa at gt with mvcesa_gt
+device	mvcesa: opencrypto
+file	dev/marvell/mvcesa.c		mvcesa
+attach	mvcesa at gt with mvcesa_gt
 
 # Two-Wire Serial Interface
 device	gttwsi: i2cbus

Added files:

Index: src/sys/dev/marvell/mvcesa.c
diff -u /dev/null src/sys/dev/marvell/mvcesa.c:1.1
--- /dev/null	Fri Jul 27 03:00:02 2012
+++ src/sys/dev/marvell/mvcesa.c	Fri Jul 27 03:00:01 2012
@@ -0,0 +1,767 @@
+/*	$NetBSD: mvcesa.c,v 1.1 2012/07/27 03:00:01 kiyohara Exp $	*/
+/*
+ * Copyright (c) 2008 KIYOHARA Takashi
+ * 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 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.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: mvcesa.c,v 1.1 2012/07/27 03:00:01 kiyohara Exp $");
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/cprng.h>
+#include <sys/device.h>
+#include <sys/endian.h>
+#include <sys/errno.h>
+#include <sys/mbuf.h>
+#include <sys/md5.h>
+#include <sys/uio.h>
+#include <sys/sha1.h>
+
+#include <opencrypto/cryptodev.h>
+#include <opencrypto/xform.h>
+
+#include <dev/marvell/marvellreg.h>
+#include <dev/marvell/marvellvar.h>
+#include <dev/marvell/mvcesareg.h>
+
+#include "locators.h"
+
+#define MVCESA_SESSION(sid)		((sid) & 0x0fffffff)
+#define MVCESA_SID(crd, sesn)		(((crd) << 28) | ((sesn) & 0x0fffffff))
+
+
+struct mvcesa_session {
+	int ses_used;
+
+	int ses_klen;
+	uint32_t ses_iv[4];
+	uint32_t ses_key[8];
+
+	uint32_t ses_hminner[5];	/* HMAC inner state */
+	uint32_t ses_hmouter[5];	/* HMAC outer state */
+};
+
+struct mvcesa_softc {
+	device_t sc_dev;
+
+	bus_space_tag_t sc_iot;
+	bus_space_handle_t sc_ioh;
+	bus_dma_tag_t sc_dmat;
+
+	int sc_cid;
+	int sc_nsessions;
+	struct mvcesa_session *sc_sessions;
+};
+
+static int mvcesa_match(device_t, cfdata_t, void *);
+static void mvcesa_attach(device_t, device_t, void *);
+
+static int mvcesa_intr(void *);
+
+static int mvcesa_newsession(void *, u_int32_t *, struct cryptoini *);
+static int mvcesa_freesession(void *, u_int64_t);
+static int mvcesa_process(void *, struct cryptop *, int);
+
+static int mvcesa_authentication(struct mvcesa_softc *, struct mvcesa_session *,
+				 uint32_t, uint32_t *, uint32_t *, uint64_t,
+				 int, int, char *, struct mbuf *, struct uio *);
+static int mvcesa_des_encdec(struct mvcesa_softc *, struct mvcesa_session *,
+			     uint32_t, uint32_t, uint32_t, uint32_t *, int, int,
+			     char *, struct mbuf *, struct uio *);
+
+
+CFATTACH_DECL_NEW(mvcesa_gt, sizeof(struct mvcesa_softc),
+    mvcesa_match, mvcesa_attach, NULL, NULL);
+CFATTACH_DECL_NEW(mvcesa_mbus, sizeof(struct mvcesa_softc),
+    mvcesa_match, mvcesa_attach, NULL, NULL);
+
+
+/* ARGSUSED */
+static int
+mvcesa_match(device_t parent, cfdata_t match, void *aux)
+{
+	struct marvell_attach_args *mva = aux;
+
+	if (strcmp(mva->mva_name, match->cf_name) != 0)
+		return 0;
+	if (mva->mva_offset == MVA_OFFSET_DEFAULT ||
+	    mva->mva_irq == MVA_IRQ_DEFAULT)
+		return 0;
+
+	mva->mva_size = MVCESA_SIZE;
+	return 1;
+}
+
+/* ARGSUSED */
+static void
+mvcesa_attach(device_t parent, device_t self, void *aux)
+{
+	struct mvcesa_softc *sc = device_private(self);
+	struct marvell_attach_args *mva = aux;
+
+	aprint_normal(
+	    ": Marvell Cryptographic Engines and Security Accelerator\n");
+	aprint_naive("\n");
+
+	sc->sc_dev = self;
+	sc->sc_iot = mva->mva_iot;
+        /* Map I/O registers */
+	if (bus_space_subregion(mva->mva_iot, mva->mva_ioh, mva->mva_offset,
+	    mva->mva_size, &sc->sc_ioh)) {
+		aprint_error_dev(self, "can't map registers\n");
+		return;
+	}
+	sc->sc_dmat = mva->mva_dmat;
+
+	sc->sc_nsessions = 0;
+
+	/* Setup Opencrypto stuff */
+	sc->sc_cid = crypto_get_driverid(0);
+	if (sc->sc_cid < 0) {
+		aprint_error_dev(self, "couldn't get crypto driver id\n");
+		return;
+	}
+	crypto_register(sc->sc_cid, CRYPTO_DES_CBC, 0, 0,
+	    mvcesa_newsession, mvcesa_freesession, mvcesa_process, sc);
+	crypto_register(sc->sc_cid, CRYPTO_3DES_CBC, 0, 0,
+	    mvcesa_newsession, mvcesa_freesession, mvcesa_process, sc);
+#if __DMA_notyet__
+/*
+ * Don't know how to process to AES CBC in PIO-mode.
+ * I havn't found IV registers.
+ */
+	crypto_register(sc->sc_cid, CRYPTO_AES_CBC, 0, 0,
+	    mvcesa_newsession, mvcesa_freesession, mvcesa_process, sc);
+#endif
+	crypto_register(sc->sc_cid, CRYPTO_SHA1, 0, 0,
+	    mvcesa_newsession, mvcesa_freesession, mvcesa_process, sc);
+	crypto_register(sc->sc_cid, CRYPTO_SHA1_HMAC, 0, 0,
+	    mvcesa_newsession, mvcesa_freesession, mvcesa_process, sc);
+	crypto_register(sc->sc_cid, CRYPTO_MD5, 0, 0,
+	    mvcesa_newsession, mvcesa_freesession, mvcesa_process, sc);
+	crypto_register(sc->sc_cid, CRYPTO_MD5_HMAC, 0, 0,
+	    mvcesa_newsession, mvcesa_freesession, mvcesa_process, sc);
+
+	/* Clear and establish interrupt */
+	bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVCESA_IC, 0);
+	marvell_intr_establish(mva->mva_irq, IPL_NET, mvcesa_intr, sc);
+
+	bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVCESA_IM, 0);
+}
+
+
+static int
+mvcesa_intr(void *arg)
+{
+#if 0
+	struct mvcesa_softc *sc = (struct mvcesa_softc *)arg;
+#endif
+	int handled = 0;
+
+	return handled;
+}
+
+
+/*
+ * Opencrypto functions
+ */
+/*
+ * Allocate a new 'session' and return an encoded session id.  'sidp'
+ * contains our registration id, and should contain an encoded session
+ * id on successful allocation.
+ */
+static int
+mvcesa_newsession(void *arg, u_int32_t *sidp, struct cryptoini *cri)
+{
+	struct mvcesa_softc *sc = (struct mvcesa_softc *)arg;
+	struct cryptoini *c;
+	struct mvcesa_session *ses = NULL;
+	int sesn, count, enc, mac, i;
+
+	KASSERT(sc != NULL /*, ("mvcesa_newsession: null softc")*/);
+	if (sidp == NULL || cri == NULL || sc == NULL)
+		return EINVAL;
+
+	for (sesn = 0; sesn < sc->sc_nsessions; sesn++)
+		if (sc->sc_sessions[sesn].ses_used == 0) {
+			ses = sc->sc_sessions + sesn;
+			break;
+		}
+
+	if (ses == NULL) {
+		sesn = sc->sc_nsessions;
+		ses = malloc((sesn + 1) * sizeof(*ses), M_DEVBUF, M_NOWAIT);
+		if (ses == NULL)
+			return ENOMEM;
+		if (sesn != 0) {
+			memcpy(ses, sc->sc_sessions, sesn * sizeof(*ses));
+			memset(sc->sc_sessions, 0, sesn * sizeof(*ses));
+			free(sc->sc_sessions, M_DEVBUF);
+		}
+		sc->sc_sessions = ses;
+		ses = sc->sc_sessions + sesn;
+		sc->sc_nsessions++;
+	}
+	memset(ses, 0, sizeof(*ses));
+
+	count = 0;
+	enc = mac = 0;
+	for (c = cri; c != NULL; c = c->cri_next) {
+		switch (c->cri_alg) {
+		case CRYPTO_DES_CBC:
+		case CRYPTO_3DES_CBC:
+			if (enc)
+				return EINVAL;
+			enc = 1;
+
+			cprng_fast(ses->ses_iv,
+			    c->cri_alg == CRYPTO_AES_CBC ? 16 : 8);
+
+			/* Go ahead and compute key in CESA's byte order */
+			ses->ses_klen = c->cri_klen;
+			memcpy(ses->ses_key, c->cri_key, c->cri_klen / 8);
+			switch (c->cri_alg) {
+			case CRYPTO_3DES_CBC:
+				ses->ses_key[5] = htobe32(ses->ses_key[5]);
+				ses->ses_key[4] = htobe32(ses->ses_key[4]);
+				ses->ses_key[3] = htobe32(ses->ses_key[3]);
+				ses->ses_key[2] = htobe32(ses->ses_key[2]);
+
+				/* FALLTHROUGH */
+			case CRYPTO_DES_CBC:
+				ses->ses_key[1] = htobe32(ses->ses_key[1]);
+				ses->ses_key[0] = htobe32(ses->ses_key[0]);
+			}
+			break;
+
+		case CRYPTO_SHA1_HMAC:
+		case CRYPTO_MD5_HMAC:
+		{
+			MD5_CTX md5ctx;
+			SHA1_CTX sha1ctx;
+			int klen_bytes = c->cri_klen / 8;
+
+			KASSERT(c->cri_klen == 512);
+
+			for (i = 0; i < klen_bytes; i++)
+				c->cri_key[i] ^= HMAC_IPAD_VAL;
+			if (c->cri_alg == CRYPTO_MD5_HMAC_96) {
+				MD5Init(&md5ctx);
+				MD5Update(&md5ctx, c->cri_key, klen_bytes);
+				MD5Update(&md5ctx, hmac_ipad_buffer,
+				    HMAC_BLOCK_LEN - klen_bytes);
+				memcpy(ses->ses_hminner, md5ctx.state,
+				    sizeof(md5ctx.state));
+			} else {
+				SHA1Init(&sha1ctx);
+				SHA1Update(&sha1ctx, c->cri_key, klen_bytes);
+				SHA1Update(&sha1ctx, hmac_ipad_buffer,
+				    HMAC_BLOCK_LEN - klen_bytes);
+				memcpy(ses->ses_hminner, sha1ctx.state,
+				    sizeof(sha1ctx.state));
+			}
+
+			for (i = 0; i < klen_bytes; i++)
+				c->cri_key[i] ^=
+				    (HMAC_IPAD_VAL ^ HMAC_OPAD_VAL);
+			if (c->cri_alg == CRYPTO_MD5_HMAC_96) {
+				MD5Init(&md5ctx);
+				MD5Update(&md5ctx, c->cri_key, klen_bytes);
+				MD5Update(&md5ctx, hmac_opad_buffer,
+				    HMAC_BLOCK_LEN - klen_bytes);
+				memcpy(ses->ses_hmouter, md5ctx.state,
+				    sizeof(md5ctx.state));
+			} else {
+				SHA1Init(&sha1ctx);
+				SHA1Update(&sha1ctx, c->cri_key, klen_bytes);
+				SHA1Update(&sha1ctx, hmac_opad_buffer,
+				    HMAC_BLOCK_LEN - klen_bytes);
+				memcpy(ses->ses_hmouter, sha1ctx.state,
+				    sizeof(sha1ctx.state));
+			}
+
+			for (i = 0; i < klen_bytes; i++)
+				c->cri_key[i] ^= HMAC_OPAD_VAL;
+		}
+			/* FALLTHROUGH */
+
+		case CRYPTO_SHA1:
+		case CRYPTO_MD5:
+			if (mac)
+				return EINVAL;
+			mac = 1;
+		}
+		count++;
+	}
+	if (count > 2) {
+		mvcesa_freesession(sc, sesn);
+		return EINVAL;
+	}
+
+	*sidp = MVCESA_SID(device_unit(sc->sc_dev), sesn);
+	ses->ses_used = 1;
+
+	return 0;
+}
+
+/*
+ * Deallocate a session.
+ */
+static int
+mvcesa_freesession(void *arg, u_int64_t tid)
+{
+	struct mvcesa_softc *sc = (struct mvcesa_softc *)arg;
+	int session;
+	uint32_t sid = ((uint32_t)tid) & 0xffffffff;
+
+	KASSERT(sc != NULL /*, ("mvcesa_freesession: null softc")*/);
+
+	session = MVCESA_SESSION(sid);
+	if (session >= sc->sc_nsessions)
+		return EINVAL;
+
+	memset(&sc->sc_sessions[session], 0, sizeof(sc->sc_sessions[session]));
+	return (0);
+}
+
+static int
+mvcesa_process(void *arg, struct cryptop *crp, int hint)
+{
+	struct mvcesa_softc *sc = (struct mvcesa_softc *)arg;
+	struct mvcesa_session *ses;
+	struct cryptodesc *crd;
+	struct mbuf *m = NULL;
+	struct uio *uio = NULL;
+	int session;
+	char *buf = NULL;
+
+	KASSERT(sc != NULL /*, ("mvcesa_process: null softc")*/);
+
+	if (crp == NULL)
+		return EINVAL;
+	if (crp->crp_callback == NULL || sc == NULL) {
+		crp->crp_etype = EINVAL;
+		goto done;
+	}
+
+	session = MVCESA_SESSION(crp->crp_sid);
+	if (session >= sc->sc_nsessions) {
+		crp->crp_etype = ENOENT;
+		goto done;
+	}
+	ses = &sc->sc_sessions[session];
+
+	if (crp->crp_flags & CRYPTO_F_IMBUF)
+		m = (struct mbuf *)crp->crp_buf;
+	else if (crp->crp_flags & CRYPTO_F_IOV)
+		uio = (struct uio *)crp->crp_buf;
+	else
+		buf = (char *)crp->crp_buf;
+
+	if (0 /* DMA support */) {
+		/* not yet... */
+
+		goto done;
+	}
+
+	/* PIO operation */
+
+	for (crd = crp->crp_desc; crd; crd = crd->crd_next) {
+		switch (crd->crd_alg) {
+		case CRYPTO_DES_CBC:
+		case CRYPTO_3DES_CBC:
+		{
+			uint32_t alg, mode, dir, *iv, ivbuf[2];
+
+			mode = MVCESA_DESE_C_DESMODE_CBC;
+			if (crd->crd_alg == CRYPTO_DES_CBC)
+				alg = MVCESA_DESE_C_ALGORITHM_DES;
+			else {	/* CRYPTO_3DES_CBC */
+				alg = MVCESA_DESE_C_ALGORITHM_3DES;
+				mode |= MVCESA_DESE_C_3DESMODE_EDE;
+			}
+			if (crd->crd_flags & CRD_F_ENCRYPT) {
+				dir = MVCESA_DESE_C_DIRECTION_ENC;
+				if (crd->crd_flags & CRD_F_IV_EXPLICIT)
+					iv = (uint32_t *)crd->crd_iv;
+				else
+					iv = ses->ses_iv;
+				if (!(crd->crd_flags & CRD_F_IV_PRESENT)) {
+					if (m != NULL)
+						m_copyback(m, crd->crd_inject,
+						    8, iv);
+					else if (uio != NULL)
+						cuio_copyback(uio,
+						    crd->crd_inject, 8, iv);
+				}
+			} else {
+				dir = MVCESA_DESE_C_DIRECTION_DEC;
+				if (crd->crd_flags & CRD_F_IV_EXPLICIT)
+					iv = (uint32_t *)crd->crd_iv;
+				else {
+					if (m != NULL)
+						m_copydata(m, crd->crd_inject,
+						    8, ivbuf);
+					else if (uio != NULL)
+						cuio_copydata(uio,
+						    crd->crd_inject, 8, ivbuf);
+					iv = ivbuf;
+				}
+			}
+
+			crp->crp_etype = mvcesa_des_encdec(sc, ses,
+			    alg, mode, dir, iv, crd->crd_skip, crd->crd_len,
+			    buf, m, uio);
+			break;
+		}
+
+		case CRYPTO_SHA1:
+		case CRYPTO_SHA1_HMAC:
+		case CRYPTO_MD5:
+		case CRYPTO_MD5_HMAC:
+		{
+			uint64_t bits;
+			uint32_t alg, *iv = NULL, digest[512 / 8 / 4], dlen;
+
+			if (crd->crd_alg == CRYPTO_SHA1 ||
+			    crd->crd_alg == CRYPTO_SHA1_HMAC) {
+				alg = MVCESA_SHA1MD5I_AC_ALGORITHM_SHA1;
+				dlen = 160;
+			} else {	/* CRYPTO_MD5 || CRYPTO_MD5_HMAC */
+				alg = MVCESA_SHA1MD5I_AC_ALGORITHM_MD5;
+				dlen = 128;
+			}
+			bits = crd->crd_len << 3;
+			if (crd->crd_alg == CRYPTO_SHA1_HMAC ||
+			    crd->crd_alg == CRYPTO_MD5_HMAC) {
+				iv = ses->ses_hminner;
+				bits += 512;
+			}
+
+			crp->crp_etype = mvcesa_authentication(sc, ses,
+			    alg, iv, digest, bits, crd->crd_skip, crd->crd_len,
+			    buf, m, uio);
+			if (crp->crp_etype != 0)
+				break;
+
+			if (crd->crd_alg == CRYPTO_SHA1_HMAC ||
+			    crd->crd_alg == CRYPTO_MD5_HMAC)
+				crp->crp_etype = mvcesa_authentication(sc,
+				    ses, alg, ses->ses_hmouter, digest,
+				    512 + dlen, 0, dlen, (char *)digest, NULL,
+				    NULL);
+			if (crp->crp_etype != 0)
+				break;
+
+			/* Inject the authentication data */
+			if (buf != NULL)
+				memcpy(buf + crd->crd_inject, digest, dlen / 8);
+			else if (m != NULL)
+				m_copyback(m, crd->crd_inject, dlen / 8,
+				    digest);
+			else if (uio != NULL)
+				memcpy(crp->crp_mac, digest, dlen / 8);
+		}
+		}
+		if (crp->crp_etype != 0)
+			break;
+	}
+
+done:
+	DPRINTF(("request %08x done\n", (uint32_t)crp));
+	crypto_done(crp);
+	return 0;
+}
+
+
+static int
+mvcesa_authentication(struct mvcesa_softc *sc, struct mvcesa_session *ses,
+		      uint32_t alg, uint32_t *iv, uint32_t *digest,
+		      uint64_t bits, int skip, int len, char *buf,
+		      struct mbuf *m, struct uio *uio)
+{
+	uint32_t cmd, bswp, data = 0;
+	int dlen, off, i, s;
+
+	/*
+	 * SHA/MD5 algorithms work in 512-bit chunks, equal to 16 words.
+	 */
+
+	KASSERT(!(len & (512 - 1)) || bits != 0);
+	KASSERT(buf != NULL || m != NULL || uio != NULL);
+
+	cmd = bus_space_read_4(sc->sc_iot, sc->sc_ioh, MVCESA_SHA1MD5I_AC);
+	if (!(cmd & MVCESA_SHA1MD5I_AC_TERMINATION))
+		return ERESTART;
+
+	bswp = 0;
+	if (alg == MVCESA_SHA1MD5I_AC_ALGORITHM_SHA1) {
+		dlen = 160;
+		bits = htobe64(bits);
+#if BYTE_ORDER == LITTLE_ENDIAN
+		bswp = MVCESA_SHA1MD5I_AC_DATABYTESWAP |
+		    MVCESA_SHA1MD5I_AC_IVBYTESWAP;
+#endif
+	} else {	/* MVCESA_SHA1MD5I_AC_ALGORITHM_MD5 */
+		dlen = 128;
+		bits = htole64(bits);
+#if BYTE_ORDER == BIG_ENDIAN
+		bswp = MVCESA_SHA1MD5I_AC_DATABYTESWAP |
+		    MVCESA_SHA1MD5I_AC_IVBYTESWAP;
+#endif
+	}
+	bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVCESA_SHA1MD5I_AC,
+	    alg | bswp | MVCESA_SHA1MD5I_AC_MODE_USEIV);
+
+	if (iv != NULL)
+		bus_space_write_region_4(sc->sc_iot, sc->sc_ioh,
+		    MVCESA_SHA1MD5I_IVDA, iv, dlen / 4);
+
+	off = i = 0;
+	while (1 /* CONSTCOND */) {
+		data = 0;
+		if (buf != NULL)
+			for (i = 0; i < 512 / 8 && off + i < len; i += s) {
+				s = min(sizeof(data), len - off - i);
+				memcpy(&data, buf + skip + off + i, s);
+				if (s == sizeof(data))
+					bus_space_write_4(sc->sc_iot,
+					    sc->sc_ioh, MVCESA_SHA1MD5I_DI,
+					    data);
+			}
+		else if (m != NULL)
+			for (i = 0; i < 512 / 8 && off + i < len; i += s) {
+				s = min(sizeof(data), len - off - i);
+				m_copydata(m, skip + off + i, s, &data);
+				if (s == sizeof(data))
+					bus_space_write_4(sc->sc_iot,
+					    sc->sc_ioh, MVCESA_SHA1MD5I_DI,
+					    data);
+			}
+		else if (uio != NULL)
+			for (i = 0; i < 512 / 8 && off + i < len; i += s) {
+				s = min(sizeof(data), len - off - i);
+				cuio_copydata(uio, skip + off + i, s, &data);
+				if (s == sizeof(data))
+					bus_space_write_4(sc->sc_iot,
+					    sc->sc_ioh, MVCESA_SHA1MD5I_DI,
+					    data);
+			}
+
+		off += i;
+		if (i < 512 / 8)
+			break;
+
+		do {
+			cmd = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
+			    MVCESA_SHA1MD5I_AC);
+		} while (!(cmd & MVCESA_SHA1MD5I_AC_TERMINATION));
+
+		bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVCESA_SHA1MD5I_AC,
+		    alg | bswp | MVCESA_SHA1MD5I_AC_MODE_CONTINUE);
+	}
+
+	if (i < 512 / 8) {
+		*((char *)&data + (i % 4)) = 0x80;
+		bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVCESA_SHA1MD5I_DI,
+		    data);
+		i = (i & ~3) + 4;
+
+		/* Do pad to 512 bits, if chunk size is more than 448 bits. */
+		if (i > 448 / 8) {
+			for (; i < 512 / 8; i += 4)
+				bus_space_write_4(sc->sc_iot, sc->sc_ioh,
+				    MVCESA_SHA1MD5I_DI, 0);
+			do {
+				cmd = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
+				    MVCESA_SHA1MD5I_AC);
+			} while (!(cmd & MVCESA_SHA1MD5I_AC_TERMINATION));
+			i = 0;
+		}
+		for (; i < 448 / 8; i += 4)
+			bus_space_write_4(sc->sc_iot, sc->sc_ioh,
+			    MVCESA_SHA1MD5I_DI, 0);
+
+		/* Set total bits */
+		bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVCESA_SHA1MD5I_BCL,
+		    bits & 0xffffffff);
+		bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVCESA_SHA1MD5I_BCH,
+		    bits >> 32);
+		do {
+			cmd = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
+			    MVCESA_SHA1MD5I_AC);
+		} while (!(cmd & MVCESA_SHA1MD5I_AC_TERMINATION));
+	}
+
+	if (digest != NULL) {
+		/* Read digest */
+		bus_space_read_region_4(sc->sc_iot, sc->sc_ioh,
+		    MVCESA_SHA1MD5I_IVDA, digest, dlen / 8 / 4);
+#if BYTE_ORDER == LITTLE_ENDIAN
+		if (alg == MVCESA_SHA1MD5I_AC_ALGORITHM_SHA1)
+			for (i = 0; i < dlen / 8 / 4; i++)
+				digest[i] = be32toh(digest[i]);
+#else
+		if (alg == MVCESA_SHA1MD5I_AC_ALGORITHM_MD5)
+			for (i = 0; i < dlen / 8 / 4; i++)
+				digest[i] = le32toh(digest[i]);
+#endif
+	}
+	return 0;
+}
+
+static int
+mvcesa_des_encdec(struct mvcesa_softc *sc, struct mvcesa_session *ses,
+		  uint32_t alg, uint32_t mode, uint32_t dir, uint32_t *iv,
+		  int skip, int len, char *buf, struct mbuf *m, struct uio *uio)
+{
+	uint64_t iblk, oblk;
+	uint32_t cmd, bswp = 0;
+	int i, o, s;
+
+	KASSERT(buf != NULL || m != NULL || uio != NULL);
+
+	cmd = bus_space_read_4(sc->sc_iot, sc->sc_ioh, MVCESA_DESE_C);
+	if (!(cmd & MVCESA_DESE_C_TERMINATION))
+		return ERESTART;
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+	bswp = MVCESA_DESE_C_DATABYTESWAP | MVCESA_DESE_C_IVBYTESWAP   |
+	    MVCESA_DESE_C_OUTBYTESWAP;
+#endif
+	bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVCESA_DESE_C,
+	    dir | alg | mode | bswp | MVCESA_DESE_C_ALLTERMINATION);
+
+	bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVCESA_DESE_K0L,
+	    ses->ses_key[1]);
+	bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVCESA_DESE_K0H,
+	    ses->ses_key[0]);
+	if (alg == MVCESA_DESE_C_ALGORITHM_3DES) {
+		bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVCESA_DESE_K1L,
+		    ses->ses_key[3]);
+		bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVCESA_DESE_K1H,
+		    ses->ses_key[2]);
+		bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVCESA_DESE_K2L,
+		    ses->ses_key[5]);
+		bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVCESA_DESE_K2H,
+		    ses->ses_key[4]);
+	}
+
+	bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVCESA_DESE_IVL, iv[1]);
+	bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVCESA_DESE_IVH, iv[0]);
+
+	i = o = 0;
+	while (i < len) {
+		s = min(sizeof(iblk), len - i);
+		iblk = 0;
+
+		if (buf != NULL)
+			memcpy(&iblk, buf + skip + i, s);
+		else if (m != NULL)
+			m_copydata(m, skip + i, s, &iblk);
+		else if (uio != NULL)
+			cuio_copydata(uio, skip + i, s, &iblk);
+
+		/*
+		 * We have the pipeline that two data enters.
+		 */
+
+		while (1 /* CONSTCOND */) {
+			cmd = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
+			    MVCESA_DESE_C);
+			if (cmd & MVCESA_DESE_C_ALLTERMINATION)
+				/* Engine is ready.  Can write two data. */
+				break;
+			if (cmd & MVCESA_DESE_C_READALLOW) {
+				oblk = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
+				    MVCESA_DESE_DOH);
+				/* XXXX: needs barrier? */
+				oblk |= (uint64_t)bus_space_read_4(sc->sc_iot,
+				    sc->sc_ioh, MVCESA_DESE_DOL) << 32;
+
+				if (buf != NULL)
+					memcpy(buf + skip + o, &oblk,
+					    sizeof(oblk));
+				else if (m != NULL)
+					m_copydata(m, skip + o, sizeof(oblk),
+					    &oblk);
+				else if (uio != NULL)
+					cuio_copyback(uio, skip + o,
+					    sizeof(oblk), &oblk);
+				o += sizeof(oblk);
+
+				/* Can write one data */
+				break;
+			}
+		}
+
+		/*
+		 * Encryption/Decription calculation time is 9 cycles in DES
+		 * mode and 25 cycles in 3DES mode.
+		 */
+		bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVCESA_DESE_DBL,
+		    iblk >> 32);
+		/* XXXX: needs barrier? */
+		bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVCESA_DESE_DBH,
+		    iblk & 0xffffffff);
+		i += s;
+	}
+
+	while (1 /* CONSTCOND */) {
+		cmd = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
+		    MVCESA_DESE_C);
+		if (cmd & (MVCESA_DESE_C_READALLOW |
+					MVCESA_DESE_C_ALLTERMINATION)) {
+			oblk = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
+			    MVCESA_DESE_DOH);
+			/* XXXX: needs barrier? */
+			oblk |= (uint64_t)bus_space_read_4(sc->sc_iot,
+			    sc->sc_ioh, MVCESA_DESE_DOL) << 32;
+
+			if (cmd & MVCESA_DESE_C_ALLTERMINATION) {
+				/* We can read IV from Data Out Registers. */
+				if (dir == MVCESA_DESE_C_DIRECTION_ENC)
+					o -= sizeof(oblk);
+				else
+					break;
+			}
+			if (buf != NULL)
+				memcpy(buf + skip + o, &oblk, sizeof(oblk));
+			else if (m != NULL)
+				m_copydata(m, skip + o, sizeof(oblk), &oblk);
+			else if (uio != NULL)
+				cuio_copyback(uio, skip + o, sizeof(oblk),
+				    &oblk);
+			o += sizeof(oblk);
+			if (cmd & MVCESA_DESE_C_ALLTERMINATION)
+				break;
+		}
+	}
+
+	if (dir == MVCESA_DESE_C_DIRECTION_ENC)
+		memcpy(ses->ses_iv, iv, sizeof(ses->ses_iv));
+
+	return 0;
+}
Index: src/sys/dev/marvell/mvcesareg.h
diff -u /dev/null src/sys/dev/marvell/mvcesareg.h:1.1
--- /dev/null	Fri Jul 27 03:00:02 2012
+++ src/sys/dev/marvell/mvcesareg.h	Fri Jul 27 03:00:01 2012
@@ -0,0 +1,125 @@
+/*	$NetBSD: mvcesareg.h,v 1.1 2012/07/27 03:00:01 kiyohara Exp $	*/
+/*
+ * Copyright (c) 2008 KIYOHARA Takashi
+ * 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 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.
+ */
+#ifndef _MVCESAREG_H_
+#define _MVCESAREG_H_
+
+#define MVCESA_SIZE	0x10000
+
+
+/*
+ * Cryptographic Engine and Security Accelerator Registers
+ */
+/* DES Engine Registers */
+#define MVCESA_DESE_DOL		0xdd78	/* Data Out Low */
+#define MVCESA_DESE_DOH		0xdd7c	/* Data Out High */
+#define MVCESA_DESE_DBL		0xdd70	/* Data Buffer Low */
+#define MVCESA_DESE_DBH		0xdd74	/* Data Buffer High */
+#define MVCESA_DESE_IVL		0xdd40	/* Initial Value Low */
+#define MVCESA_DESE_IVH		0xdd44	/* Initial Value High */
+#define MVCESA_DESE_K0L		0xdd48	/* Key0 Low */
+#define MVCESA_DESE_K0H		0xdd4c	/* Key0 High */
+#define MVCESA_DESE_K1L		0xdd50	/* Key1 Low */
+#define MVCESA_DESE_K1H		0xdd54	/* Key1 High */
+#define MVCESA_DESE_K2L		0xdd60	/* Key2 Low */
+#define MVCESA_DESE_K2H		0xdd64	/* Key2 High */
+#define MVCESA_DESE_C		0xdd58	/* Command */
+#define MVCESA_DESE_C_DIRECTION_ENC	(0 << 0)
+#define MVCESA_DESE_C_DIRECTION_DEC	(1 << 0)
+#define MVCESA_DESE_C_ALGORITHM_DES	(0 << 1)
+#define MVCESA_DESE_C_ALGORITHM_3DES	(1 << 1)
+#define MVCESA_DESE_C_3DESMODE_EEE	(0 << 2)
+#define MVCESA_DESE_C_3DESMODE_EDE	(1 << 2)
+#define MVCESA_DESE_C_DESMODE_ECB	(0 << 3)
+#define MVCESA_DESE_C_DESMODE_CBC	(1 << 3)
+#define MVCESA_DESE_C_DATABYTESWAP	(1 << 4)
+#define MVCESA_DESE_C_IVBYTESWAP	(1 << 6)
+#define MVCESA_DESE_C_OUTBYTESWAP	(1 << 8)
+#define MVCESA_DESE_C_READALLOW		(1 << 29)
+#define MVCESA_DESE_C_ALLTERMINATION	(1 << 30)
+#define MVCESA_DESE_C_TERMINATION	(1 << 31)
+
+/* SHA-1 and MD5 Interface Registers */
+#define MVCESA_SHA1MD5I_DI	0xdd38	/* Data In */
+#define MVCESA_SHA1MD5I_BCL	0xdd20	/* Bit Count Low */
+#define MVCESA_SHA1MD5I_BCH	0xdd24	/* Bit Count High */
+#define MVCESA_SHA1MD5I_IVDA	0xdd00	/* Initial Value/Digest A */
+#define MVCESA_SHA1MD5I_IVDB	0xdd04	/* Initial Value/Digest B */
+#define MVCESA_SHA1MD5I_IVDC	0xdd08	/* Initial Value/Digest C */
+#define MVCESA_SHA1MD5I_IVDD	0xdd0c	/* Initial Value/Digest D */
+#define MVCESA_SHA1MD5I_IVDE	0xdd10	/* Initial Value/Digest E */
+#define MVCESA_SHA1MD5I_AC	0xdd18	/* Authentication Command */
+#define MVCESA_SHA1MD5I_AC_ALGORITHM_MD5	(0 << 0)
+#define MVCESA_SHA1MD5I_AC_ALGORITHM_SHA1	(1 << 0)
+#define MVCESA_SHA1MD5I_AC_MODE_USEIV		(0 << 1)
+#define MVCESA_SHA1MD5I_AC_MODE_CONTINUE	(1 << 1)
+#define MVCESA_SHA1MD5I_AC_DATABYTESWAP		(1 << 2)
+#define MVCESA_SHA1MD5I_AC_IVBYTESWAP		(1 << 4)
+#define MVCESA_SHA1MD5I_AC_TERMINATION		(1 << 31)
+
+/* AES Encryption/Decription Interface Registers */
+#define MVCESA_AES_ENCRYPTION	0xdd80
+#define MVCESA_AES_DECRYPTION	0xddc0
+#define MVCESA_AES_DIOC_OFF	  0x20	/* Data In/Out Column */
+#define MVCESA_AES_DIOC_MAX	3
+#define MVCESA_AES_KC_OFF	  0x00	/* Key Column */
+#define MVCESA_AES_KC_MAX	7
+#define MVCESA_AES_C		  0x30	/* Command */
+#define MVCESA_AES_C_AESKEYMODE_128		(0 << 0)
+#define MVCESA_AES_C_AESKEYMODE_192		(1 << 0)
+#define MVCESA_AES_C_AESKEYMODE_256		(2 << 0)
+#define MVCESA_AES_C_AESDECMAKEKEY		(1 << 2)
+#define MVCESA_AES_C_DATABYTESWAP		(1 << 4)
+#define MVCESA_AES_C_OUTBYTESWAP		(1 << 8)
+#define MVCESA_AES_C_TERMINATION		(1 << 31)
+
+#define MVCESA_AES_DIOC(c) \
+	(MVCESA_AES_DIOC_OFF + ((c) - MVCESA_AES_DIOC_MAX) * 4)
+#define MVCESA_AES_KC(c) \
+	(MVCESA_AES_KC_OFF + ((c) - MVCESA_AES_KC_MAX) * 4)
+
+
+/* Security Accelerator Registers */
+#define MVCESA_SA_C		0xde00	/* Command */
+#define MVCESA_SA_DPS0		0xde04	/* Descriptor Pointer Session 0 */
+#define MVCESA_SA_DPS1		0xde14	/* Descriptor Pointer Session 1 */
+#define MVCESA_SA_CFG		0xde08	/* Configuration */
+#define MVCESA_SA_S		0xde0c	/* Status */
+
+/* Interrupt Cause Registers */
+#define MVCESA_IC		0xde20	/* Interrupt Cause */
+#define MVCESA_IM		0xde24	/* Interrupt Mask */
+#define MVCESA_I_ZINT0			(1 << 0) /* auth termination */
+#define MVCESA_I_ZINT1			(1 << 1) /* DES */
+#define MVCESA_I_ZINT2			(1 << 2) /* AES encryption */
+#define MVCESA_I_ZINT3			(1 << 3) /* AES decryption */
+#define MVCESA_I_ZINT4			(1 << 4) /* enc termination */
+#define MVCESA_I_ACCINT0		(1 << 5) /* Security accelerator 0 */
+#define MVCESA_I_ACCINT1		(1 << 6) /* Security accelerator 1 */
+#define MVCESA_I_ACCANDIDMAINT0		(1 << 7) /* Acceleration and IDMA 0 */
+#define MVCESA_I_ACCANDIDMAINT1		(1 << 8) /* Acceleration and IDMA 1 */
+
+#endif	/* _MVCESAREG_H_ */

Reply via email to