Home | History | Annotate | Line # | Download | only in marvell
mvcesa.c revision 1.1.4.2
      1 /*	$NetBSD: mvcesa.c,v 1.1.4.2 2012/10/30 17:21:18 yamt Exp $	*/
      2 /*
      3  * Copyright (c) 2008 KIYOHARA Takashi
      4  * All rights reserved.
      5  *
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions
      8  * are met:
      9  * 1. Redistributions of source code must retain the above copyright
     10  *    notice, this list of conditions and the following disclaimer.
     11  * 2. Redistributions in binary form must reproduce the above copyright
     12  *    notice, this list of conditions and the following disclaimer in the
     13  *    documentation and/or other materials provided with the distribution.
     14  *
     15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     17  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     18  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
     19  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     20  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
     21  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
     23  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
     24  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     25  * POSSIBILITY OF SUCH DAMAGE.
     26  */
     27 
     28 #include <sys/cdefs.h>
     29 __KERNEL_RCSID(0, "$NetBSD: mvcesa.c,v 1.1.4.2 2012/10/30 17:21:18 yamt Exp $");
     30 
     31 #include <sys/param.h>
     32 #include <sys/bus.h>
     33 #include <sys/cprng.h>
     34 #include <sys/device.h>
     35 #include <sys/endian.h>
     36 #include <sys/errno.h>
     37 #include <sys/mbuf.h>
     38 #include <sys/md5.h>
     39 #include <sys/uio.h>
     40 #include <sys/sha1.h>
     41 
     42 #include <opencrypto/cryptodev.h>
     43 #include <opencrypto/xform.h>
     44 
     45 #include <dev/marvell/marvellreg.h>
     46 #include <dev/marvell/marvellvar.h>
     47 #include <dev/marvell/mvcesareg.h>
     48 
     49 #include "locators.h"
     50 
     51 #define MVCESA_SESSION(sid)		((sid) & 0x0fffffff)
     52 #define MVCESA_SID(crd, sesn)		(((crd) << 28) | ((sesn) & 0x0fffffff))
     53 
     54 
     55 struct mvcesa_session {
     56 	int ses_used;
     57 
     58 	int ses_klen;
     59 	uint32_t ses_iv[4];
     60 	uint32_t ses_key[8];
     61 
     62 	uint32_t ses_hminner[5];	/* HMAC inner state */
     63 	uint32_t ses_hmouter[5];	/* HMAC outer state */
     64 };
     65 
     66 struct mvcesa_softc {
     67 	device_t sc_dev;
     68 
     69 	bus_space_tag_t sc_iot;
     70 	bus_space_handle_t sc_ioh;
     71 	bus_dma_tag_t sc_dmat;
     72 
     73 	int sc_cid;
     74 	int sc_nsessions;
     75 	struct mvcesa_session *sc_sessions;
     76 };
     77 
     78 static int mvcesa_match(device_t, cfdata_t, void *);
     79 static void mvcesa_attach(device_t, device_t, void *);
     80 
     81 static int mvcesa_intr(void *);
     82 
     83 static int mvcesa_newsession(void *, u_int32_t *, struct cryptoini *);
     84 static int mvcesa_freesession(void *, u_int64_t);
     85 static int mvcesa_process(void *, struct cryptop *, int);
     86 
     87 static int mvcesa_authentication(struct mvcesa_softc *, struct mvcesa_session *,
     88 				 uint32_t, uint32_t *, uint32_t *, uint64_t,
     89 				 int, int, char *, struct mbuf *, struct uio *);
     90 static int mvcesa_des_encdec(struct mvcesa_softc *, struct mvcesa_session *,
     91 			     uint32_t, uint32_t, uint32_t, uint32_t *, int, int,
     92 			     char *, struct mbuf *, struct uio *);
     93 
     94 
     95 CFATTACH_DECL_NEW(mvcesa_gt, sizeof(struct mvcesa_softc),
     96     mvcesa_match, mvcesa_attach, NULL, NULL);
     97 CFATTACH_DECL_NEW(mvcesa_mbus, sizeof(struct mvcesa_softc),
     98     mvcesa_match, mvcesa_attach, NULL, NULL);
     99 
    100 
    101 /* ARGSUSED */
    102 static int
    103 mvcesa_match(device_t parent, cfdata_t match, void *aux)
    104 {
    105 	struct marvell_attach_args *mva = aux;
    106 
    107 	if (strcmp(mva->mva_name, match->cf_name) != 0)
    108 		return 0;
    109 	if (mva->mva_offset == MVA_OFFSET_DEFAULT ||
    110 	    mva->mva_irq == MVA_IRQ_DEFAULT)
    111 		return 0;
    112 
    113 	mva->mva_size = MVCESA_SIZE;
    114 	return 1;
    115 }
    116 
    117 /* ARGSUSED */
    118 static void
    119 mvcesa_attach(device_t parent, device_t self, void *aux)
    120 {
    121 	struct mvcesa_softc *sc = device_private(self);
    122 	struct marvell_attach_args *mva = aux;
    123 
    124 	aprint_normal(
    125 	    ": Marvell Cryptographic Engines and Security Accelerator\n");
    126 	aprint_naive("\n");
    127 
    128 	sc->sc_dev = self;
    129 	sc->sc_iot = mva->mva_iot;
    130         /* Map I/O registers */
    131 	if (bus_space_subregion(mva->mva_iot, mva->mva_ioh, mva->mva_offset,
    132 	    mva->mva_size, &sc->sc_ioh)) {
    133 		aprint_error_dev(self, "can't map registers\n");
    134 		return;
    135 	}
    136 	sc->sc_dmat = mva->mva_dmat;
    137 
    138 	sc->sc_nsessions = 0;
    139 
    140 	/* Setup Opencrypto stuff */
    141 	sc->sc_cid = crypto_get_driverid(0);
    142 	if (sc->sc_cid < 0) {
    143 		aprint_error_dev(self, "couldn't get crypto driver id\n");
    144 		return;
    145 	}
    146 	crypto_register(sc->sc_cid, CRYPTO_DES_CBC, 0, 0,
    147 	    mvcesa_newsession, mvcesa_freesession, mvcesa_process, sc);
    148 	crypto_register(sc->sc_cid, CRYPTO_3DES_CBC, 0, 0,
    149 	    mvcesa_newsession, mvcesa_freesession, mvcesa_process, sc);
    150 #if __DMA_notyet__
    151 /*
    152  * Don't know how to process to AES CBC in PIO-mode.
    153  * I havn't found IV registers.
    154  */
    155 	crypto_register(sc->sc_cid, CRYPTO_AES_CBC, 0, 0,
    156 	    mvcesa_newsession, mvcesa_freesession, mvcesa_process, sc);
    157 #endif
    158 	crypto_register(sc->sc_cid, CRYPTO_SHA1, 0, 0,
    159 	    mvcesa_newsession, mvcesa_freesession, mvcesa_process, sc);
    160 	crypto_register(sc->sc_cid, CRYPTO_SHA1_HMAC, 0, 0,
    161 	    mvcesa_newsession, mvcesa_freesession, mvcesa_process, sc);
    162 	crypto_register(sc->sc_cid, CRYPTO_MD5, 0, 0,
    163 	    mvcesa_newsession, mvcesa_freesession, mvcesa_process, sc);
    164 	crypto_register(sc->sc_cid, CRYPTO_MD5_HMAC, 0, 0,
    165 	    mvcesa_newsession, mvcesa_freesession, mvcesa_process, sc);
    166 
    167 	/* Clear and establish interrupt */
    168 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVCESA_IC, 0);
    169 	marvell_intr_establish(mva->mva_irq, IPL_NET, mvcesa_intr, sc);
    170 
    171 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVCESA_IM, 0);
    172 }
    173 
    174 
    175 static int
    176 mvcesa_intr(void *arg)
    177 {
    178 #if 0
    179 	struct mvcesa_softc *sc = (struct mvcesa_softc *)arg;
    180 #endif
    181 	int handled = 0;
    182 
    183 	return handled;
    184 }
    185 
    186 
    187 /*
    188  * Opencrypto functions
    189  */
    190 /*
    191  * Allocate a new 'session' and return an encoded session id.  'sidp'
    192  * contains our registration id, and should contain an encoded session
    193  * id on successful allocation.
    194  */
    195 static int
    196 mvcesa_newsession(void *arg, u_int32_t *sidp, struct cryptoini *cri)
    197 {
    198 	struct mvcesa_softc *sc = (struct mvcesa_softc *)arg;
    199 	struct cryptoini *c;
    200 	struct mvcesa_session *ses = NULL;
    201 	int sesn, count, enc, mac, i;
    202 
    203 	KASSERT(sc != NULL /*, ("mvcesa_newsession: null softc")*/);
    204 	if (sidp == NULL || cri == NULL || sc == NULL)
    205 		return EINVAL;
    206 
    207 	for (sesn = 0; sesn < sc->sc_nsessions; sesn++)
    208 		if (sc->sc_sessions[sesn].ses_used == 0) {
    209 			ses = sc->sc_sessions + sesn;
    210 			break;
    211 		}
    212 
    213 	if (ses == NULL) {
    214 		sesn = sc->sc_nsessions;
    215 		ses = malloc((sesn + 1) * sizeof(*ses), M_DEVBUF, M_NOWAIT);
    216 		if (ses == NULL)
    217 			return ENOMEM;
    218 		if (sesn != 0) {
    219 			memcpy(ses, sc->sc_sessions, sesn * sizeof(*ses));
    220 			memset(sc->sc_sessions, 0, sesn * sizeof(*ses));
    221 			free(sc->sc_sessions, M_DEVBUF);
    222 		}
    223 		sc->sc_sessions = ses;
    224 		ses = sc->sc_sessions + sesn;
    225 		sc->sc_nsessions++;
    226 	}
    227 	memset(ses, 0, sizeof(*ses));
    228 
    229 	count = 0;
    230 	enc = mac = 0;
    231 	for (c = cri; c != NULL; c = c->cri_next) {
    232 		switch (c->cri_alg) {
    233 		case CRYPTO_DES_CBC:
    234 		case CRYPTO_3DES_CBC:
    235 			if (enc)
    236 				return EINVAL;
    237 			enc = 1;
    238 
    239 			cprng_fast(ses->ses_iv,
    240 			    c->cri_alg == CRYPTO_AES_CBC ? 16 : 8);
    241 
    242 			/* Go ahead and compute key in CESA's byte order */
    243 			ses->ses_klen = c->cri_klen;
    244 			memcpy(ses->ses_key, c->cri_key, c->cri_klen / 8);
    245 			switch (c->cri_alg) {
    246 			case CRYPTO_3DES_CBC:
    247 				ses->ses_key[5] = htobe32(ses->ses_key[5]);
    248 				ses->ses_key[4] = htobe32(ses->ses_key[4]);
    249 				ses->ses_key[3] = htobe32(ses->ses_key[3]);
    250 				ses->ses_key[2] = htobe32(ses->ses_key[2]);
    251 
    252 				/* FALLTHROUGH */
    253 			case CRYPTO_DES_CBC:
    254 				ses->ses_key[1] = htobe32(ses->ses_key[1]);
    255 				ses->ses_key[0] = htobe32(ses->ses_key[0]);
    256 			}
    257 			break;
    258 
    259 		case CRYPTO_SHA1_HMAC:
    260 		case CRYPTO_MD5_HMAC:
    261 		{
    262 			MD5_CTX md5ctx;
    263 			SHA1_CTX sha1ctx;
    264 			int klen_bytes = c->cri_klen / 8;
    265 
    266 			KASSERT(c->cri_klen == 512);
    267 
    268 			for (i = 0; i < klen_bytes; i++)
    269 				c->cri_key[i] ^= HMAC_IPAD_VAL;
    270 			if (c->cri_alg == CRYPTO_MD5_HMAC_96) {
    271 				MD5Init(&md5ctx);
    272 				MD5Update(&md5ctx, c->cri_key, klen_bytes);
    273 				MD5Update(&md5ctx, hmac_ipad_buffer,
    274 				    HMAC_BLOCK_LEN - klen_bytes);
    275 				memcpy(ses->ses_hminner, md5ctx.state,
    276 				    sizeof(md5ctx.state));
    277 			} else {
    278 				SHA1Init(&sha1ctx);
    279 				SHA1Update(&sha1ctx, c->cri_key, klen_bytes);
    280 				SHA1Update(&sha1ctx, hmac_ipad_buffer,
    281 				    HMAC_BLOCK_LEN - klen_bytes);
    282 				memcpy(ses->ses_hminner, sha1ctx.state,
    283 				    sizeof(sha1ctx.state));
    284 			}
    285 
    286 			for (i = 0; i < klen_bytes; i++)
    287 				c->cri_key[i] ^=
    288 				    (HMAC_IPAD_VAL ^ HMAC_OPAD_VAL);
    289 			if (c->cri_alg == CRYPTO_MD5_HMAC_96) {
    290 				MD5Init(&md5ctx);
    291 				MD5Update(&md5ctx, c->cri_key, klen_bytes);
    292 				MD5Update(&md5ctx, hmac_opad_buffer,
    293 				    HMAC_BLOCK_LEN - klen_bytes);
    294 				memcpy(ses->ses_hmouter, md5ctx.state,
    295 				    sizeof(md5ctx.state));
    296 			} else {
    297 				SHA1Init(&sha1ctx);
    298 				SHA1Update(&sha1ctx, c->cri_key, klen_bytes);
    299 				SHA1Update(&sha1ctx, hmac_opad_buffer,
    300 				    HMAC_BLOCK_LEN - klen_bytes);
    301 				memcpy(ses->ses_hmouter, sha1ctx.state,
    302 				    sizeof(sha1ctx.state));
    303 			}
    304 
    305 			for (i = 0; i < klen_bytes; i++)
    306 				c->cri_key[i] ^= HMAC_OPAD_VAL;
    307 		}
    308 			/* FALLTHROUGH */
    309 
    310 		case CRYPTO_SHA1:
    311 		case CRYPTO_MD5:
    312 			if (mac)
    313 				return EINVAL;
    314 			mac = 1;
    315 		}
    316 		count++;
    317 	}
    318 	if (count > 2) {
    319 		mvcesa_freesession(sc, sesn);
    320 		return EINVAL;
    321 	}
    322 
    323 	*sidp = MVCESA_SID(device_unit(sc->sc_dev), sesn);
    324 	ses->ses_used = 1;
    325 
    326 	return 0;
    327 }
    328 
    329 /*
    330  * Deallocate a session.
    331  */
    332 static int
    333 mvcesa_freesession(void *arg, u_int64_t tid)
    334 {
    335 	struct mvcesa_softc *sc = (struct mvcesa_softc *)arg;
    336 	int session;
    337 	uint32_t sid = ((uint32_t)tid) & 0xffffffff;
    338 
    339 	KASSERT(sc != NULL /*, ("mvcesa_freesession: null softc")*/);
    340 
    341 	session = MVCESA_SESSION(sid);
    342 	if (session >= sc->sc_nsessions)
    343 		return EINVAL;
    344 
    345 	memset(&sc->sc_sessions[session], 0, sizeof(sc->sc_sessions[session]));
    346 	return (0);
    347 }
    348 
    349 static int
    350 mvcesa_process(void *arg, struct cryptop *crp, int hint)
    351 {
    352 	struct mvcesa_softc *sc = (struct mvcesa_softc *)arg;
    353 	struct mvcesa_session *ses;
    354 	struct cryptodesc *crd;
    355 	struct mbuf *m = NULL;
    356 	struct uio *uio = NULL;
    357 	int session;
    358 	char *buf = NULL;
    359 
    360 	KASSERT(sc != NULL /*, ("mvcesa_process: null softc")*/);
    361 
    362 	if (crp == NULL)
    363 		return EINVAL;
    364 	if (crp->crp_callback == NULL || sc == NULL) {
    365 		crp->crp_etype = EINVAL;
    366 		goto done;
    367 	}
    368 
    369 	session = MVCESA_SESSION(crp->crp_sid);
    370 	if (session >= sc->sc_nsessions) {
    371 		crp->crp_etype = ENOENT;
    372 		goto done;
    373 	}
    374 	ses = &sc->sc_sessions[session];
    375 
    376 	if (crp->crp_flags & CRYPTO_F_IMBUF)
    377 		m = (struct mbuf *)crp->crp_buf;
    378 	else if (crp->crp_flags & CRYPTO_F_IOV)
    379 		uio = (struct uio *)crp->crp_buf;
    380 	else
    381 		buf = (char *)crp->crp_buf;
    382 
    383 	if (0 /* DMA support */) {
    384 		/* not yet... */
    385 
    386 		goto done;
    387 	}
    388 
    389 	/* PIO operation */
    390 
    391 	for (crd = crp->crp_desc; crd; crd = crd->crd_next) {
    392 		switch (crd->crd_alg) {
    393 		case CRYPTO_DES_CBC:
    394 		case CRYPTO_3DES_CBC:
    395 		{
    396 			uint32_t alg, mode, dir, *iv, ivbuf[2];
    397 
    398 			mode = MVCESA_DESE_C_DESMODE_CBC;
    399 			if (crd->crd_alg == CRYPTO_DES_CBC)
    400 				alg = MVCESA_DESE_C_ALGORITHM_DES;
    401 			else {	/* CRYPTO_3DES_CBC */
    402 				alg = MVCESA_DESE_C_ALGORITHM_3DES;
    403 				mode |= MVCESA_DESE_C_3DESMODE_EDE;
    404 			}
    405 			if (crd->crd_flags & CRD_F_ENCRYPT) {
    406 				dir = MVCESA_DESE_C_DIRECTION_ENC;
    407 				if (crd->crd_flags & CRD_F_IV_EXPLICIT)
    408 					iv = (uint32_t *)crd->crd_iv;
    409 				else
    410 					iv = ses->ses_iv;
    411 				if (!(crd->crd_flags & CRD_F_IV_PRESENT)) {
    412 					if (m != NULL)
    413 						m_copyback(m, crd->crd_inject,
    414 						    8, iv);
    415 					else if (uio != NULL)
    416 						cuio_copyback(uio,
    417 						    crd->crd_inject, 8, iv);
    418 				}
    419 			} else {
    420 				dir = MVCESA_DESE_C_DIRECTION_DEC;
    421 				if (crd->crd_flags & CRD_F_IV_EXPLICIT)
    422 					iv = (uint32_t *)crd->crd_iv;
    423 				else {
    424 					if (m != NULL)
    425 						m_copydata(m, crd->crd_inject,
    426 						    8, ivbuf);
    427 					else if (uio != NULL)
    428 						cuio_copydata(uio,
    429 						    crd->crd_inject, 8, ivbuf);
    430 					iv = ivbuf;
    431 				}
    432 			}
    433 
    434 			crp->crp_etype = mvcesa_des_encdec(sc, ses,
    435 			    alg, mode, dir, iv, crd->crd_skip, crd->crd_len,
    436 			    buf, m, uio);
    437 			break;
    438 		}
    439 
    440 		case CRYPTO_SHA1:
    441 		case CRYPTO_SHA1_HMAC:
    442 		case CRYPTO_MD5:
    443 		case CRYPTO_MD5_HMAC:
    444 		{
    445 			uint64_t bits;
    446 			uint32_t alg, *iv = NULL, digest[512 / 8 / 4], dlen;
    447 
    448 			if (crd->crd_alg == CRYPTO_SHA1 ||
    449 			    crd->crd_alg == CRYPTO_SHA1_HMAC) {
    450 				alg = MVCESA_SHA1MD5I_AC_ALGORITHM_SHA1;
    451 				dlen = 160;
    452 			} else {	/* CRYPTO_MD5 || CRYPTO_MD5_HMAC */
    453 				alg = MVCESA_SHA1MD5I_AC_ALGORITHM_MD5;
    454 				dlen = 128;
    455 			}
    456 			bits = crd->crd_len << 3;
    457 			if (crd->crd_alg == CRYPTO_SHA1_HMAC ||
    458 			    crd->crd_alg == CRYPTO_MD5_HMAC) {
    459 				iv = ses->ses_hminner;
    460 				bits += 512;
    461 			}
    462 
    463 			crp->crp_etype = mvcesa_authentication(sc, ses,
    464 			    alg, iv, digest, bits, crd->crd_skip, crd->crd_len,
    465 			    buf, m, uio);
    466 			if (crp->crp_etype != 0)
    467 				break;
    468 
    469 			if (crd->crd_alg == CRYPTO_SHA1_HMAC ||
    470 			    crd->crd_alg == CRYPTO_MD5_HMAC)
    471 				crp->crp_etype = mvcesa_authentication(sc,
    472 				    ses, alg, ses->ses_hmouter, digest,
    473 				    512 + dlen, 0, dlen, (char *)digest, NULL,
    474 				    NULL);
    475 			if (crp->crp_etype != 0)
    476 				break;
    477 
    478 			/* Inject the authentication data */
    479 			if (buf != NULL)
    480 				memcpy(buf + crd->crd_inject, digest, dlen / 8);
    481 			else if (m != NULL)
    482 				m_copyback(m, crd->crd_inject, dlen / 8,
    483 				    digest);
    484 			else if (uio != NULL)
    485 				memcpy(crp->crp_mac, digest, dlen / 8);
    486 		}
    487 		}
    488 		if (crp->crp_etype != 0)
    489 			break;
    490 	}
    491 
    492 done:
    493 	DPRINTF(("request %08x done\n", (uint32_t)crp));
    494 	crypto_done(crp);
    495 	return 0;
    496 }
    497 
    498 
    499 static int
    500 mvcesa_authentication(struct mvcesa_softc *sc, struct mvcesa_session *ses,
    501 		      uint32_t alg, uint32_t *iv, uint32_t *digest,
    502 		      uint64_t bits, int skip, int len, char *buf,
    503 		      struct mbuf *m, struct uio *uio)
    504 {
    505 	uint32_t cmd, bswp, data = 0;
    506 	int dlen, off, i, s;
    507 
    508 	/*
    509 	 * SHA/MD5 algorithms work in 512-bit chunks, equal to 16 words.
    510 	 */
    511 
    512 	KASSERT(!(len & (512 - 1)) || bits != 0);
    513 	KASSERT(buf != NULL || m != NULL || uio != NULL);
    514 
    515 	cmd = bus_space_read_4(sc->sc_iot, sc->sc_ioh, MVCESA_SHA1MD5I_AC);
    516 	if (!(cmd & MVCESA_SHA1MD5I_AC_TERMINATION))
    517 		return ERESTART;
    518 
    519 	bswp = 0;
    520 	if (alg == MVCESA_SHA1MD5I_AC_ALGORITHM_SHA1) {
    521 		dlen = 160;
    522 		bits = htobe64(bits);
    523 #if BYTE_ORDER == LITTLE_ENDIAN
    524 		bswp = MVCESA_SHA1MD5I_AC_DATABYTESWAP |
    525 		    MVCESA_SHA1MD5I_AC_IVBYTESWAP;
    526 #endif
    527 	} else {	/* MVCESA_SHA1MD5I_AC_ALGORITHM_MD5 */
    528 		dlen = 128;
    529 		bits = htole64(bits);
    530 #if BYTE_ORDER == BIG_ENDIAN
    531 		bswp = MVCESA_SHA1MD5I_AC_DATABYTESWAP |
    532 		    MVCESA_SHA1MD5I_AC_IVBYTESWAP;
    533 #endif
    534 	}
    535 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVCESA_SHA1MD5I_AC,
    536 	    alg | bswp | MVCESA_SHA1MD5I_AC_MODE_USEIV);
    537 
    538 	if (iv != NULL)
    539 		bus_space_write_region_4(sc->sc_iot, sc->sc_ioh,
    540 		    MVCESA_SHA1MD5I_IVDA, iv, dlen / 4);
    541 
    542 	off = i = 0;
    543 	while (1 /* CONSTCOND */) {
    544 		data = 0;
    545 		if (buf != NULL)
    546 			for (i = 0; i < 512 / 8 && off + i < len; i += s) {
    547 				s = min(sizeof(data), len - off - i);
    548 				memcpy(&data, buf + skip + off + i, s);
    549 				if (s == sizeof(data))
    550 					bus_space_write_4(sc->sc_iot,
    551 					    sc->sc_ioh, MVCESA_SHA1MD5I_DI,
    552 					    data);
    553 			}
    554 		else if (m != NULL)
    555 			for (i = 0; i < 512 / 8 && off + i < len; i += s) {
    556 				s = min(sizeof(data), len - off - i);
    557 				m_copydata(m, skip + off + i, s, &data);
    558 				if (s == sizeof(data))
    559 					bus_space_write_4(sc->sc_iot,
    560 					    sc->sc_ioh, MVCESA_SHA1MD5I_DI,
    561 					    data);
    562 			}
    563 		else if (uio != NULL)
    564 			for (i = 0; i < 512 / 8 && off + i < len; i += s) {
    565 				s = min(sizeof(data), len - off - i);
    566 				cuio_copydata(uio, skip + off + i, s, &data);
    567 				if (s == sizeof(data))
    568 					bus_space_write_4(sc->sc_iot,
    569 					    sc->sc_ioh, MVCESA_SHA1MD5I_DI,
    570 					    data);
    571 			}
    572 
    573 		off += i;
    574 		if (i < 512 / 8)
    575 			break;
    576 
    577 		do {
    578 			cmd = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
    579 			    MVCESA_SHA1MD5I_AC);
    580 		} while (!(cmd & MVCESA_SHA1MD5I_AC_TERMINATION));
    581 
    582 		bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVCESA_SHA1MD5I_AC,
    583 		    alg | bswp | MVCESA_SHA1MD5I_AC_MODE_CONTINUE);
    584 	}
    585 
    586 	if (i < 512 / 8) {
    587 		*((char *)&data + (i % 4)) = 0x80;
    588 		bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVCESA_SHA1MD5I_DI,
    589 		    data);
    590 		i = (i & ~3) + 4;
    591 
    592 		/* Do pad to 512 bits, if chunk size is more than 448 bits. */
    593 		if (i > 448 / 8) {
    594 			for (; i < 512 / 8; i += 4)
    595 				bus_space_write_4(sc->sc_iot, sc->sc_ioh,
    596 				    MVCESA_SHA1MD5I_DI, 0);
    597 			do {
    598 				cmd = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
    599 				    MVCESA_SHA1MD5I_AC);
    600 			} while (!(cmd & MVCESA_SHA1MD5I_AC_TERMINATION));
    601 			i = 0;
    602 		}
    603 		for (; i < 448 / 8; i += 4)
    604 			bus_space_write_4(sc->sc_iot, sc->sc_ioh,
    605 			    MVCESA_SHA1MD5I_DI, 0);
    606 
    607 		/* Set total bits */
    608 		bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVCESA_SHA1MD5I_BCL,
    609 		    bits & 0xffffffff);
    610 		bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVCESA_SHA1MD5I_BCH,
    611 		    bits >> 32);
    612 		do {
    613 			cmd = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
    614 			    MVCESA_SHA1MD5I_AC);
    615 		} while (!(cmd & MVCESA_SHA1MD5I_AC_TERMINATION));
    616 	}
    617 
    618 	if (digest != NULL) {
    619 		/* Read digest */
    620 		bus_space_read_region_4(sc->sc_iot, sc->sc_ioh,
    621 		    MVCESA_SHA1MD5I_IVDA, digest, dlen / 8 / 4);
    622 #if BYTE_ORDER == LITTLE_ENDIAN
    623 		if (alg == MVCESA_SHA1MD5I_AC_ALGORITHM_SHA1)
    624 			for (i = 0; i < dlen / 8 / 4; i++)
    625 				digest[i] = be32toh(digest[i]);
    626 #else
    627 		if (alg == MVCESA_SHA1MD5I_AC_ALGORITHM_MD5)
    628 			for (i = 0; i < dlen / 8 / 4; i++)
    629 				digest[i] = le32toh(digest[i]);
    630 #endif
    631 	}
    632 	return 0;
    633 }
    634 
    635 static int
    636 mvcesa_des_encdec(struct mvcesa_softc *sc, struct mvcesa_session *ses,
    637 		  uint32_t alg, uint32_t mode, uint32_t dir, uint32_t *iv,
    638 		  int skip, int len, char *buf, struct mbuf *m, struct uio *uio)
    639 {
    640 	uint64_t iblk, oblk;
    641 	uint32_t cmd, bswp = 0;
    642 	int i, o, s;
    643 
    644 	KASSERT(buf != NULL || m != NULL || uio != NULL);
    645 
    646 	cmd = bus_space_read_4(sc->sc_iot, sc->sc_ioh, MVCESA_DESE_C);
    647 	if (!(cmd & MVCESA_DESE_C_TERMINATION))
    648 		return ERESTART;
    649 
    650 #if BYTE_ORDER == LITTLE_ENDIAN
    651 	bswp = MVCESA_DESE_C_DATABYTESWAP | MVCESA_DESE_C_IVBYTESWAP   |
    652 	    MVCESA_DESE_C_OUTBYTESWAP;
    653 #endif
    654 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVCESA_DESE_C,
    655 	    dir | alg | mode | bswp | MVCESA_DESE_C_ALLTERMINATION);
    656 
    657 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVCESA_DESE_K0L,
    658 	    ses->ses_key[1]);
    659 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVCESA_DESE_K0H,
    660 	    ses->ses_key[0]);
    661 	if (alg == MVCESA_DESE_C_ALGORITHM_3DES) {
    662 		bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVCESA_DESE_K1L,
    663 		    ses->ses_key[3]);
    664 		bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVCESA_DESE_K1H,
    665 		    ses->ses_key[2]);
    666 		bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVCESA_DESE_K2L,
    667 		    ses->ses_key[5]);
    668 		bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVCESA_DESE_K2H,
    669 		    ses->ses_key[4]);
    670 	}
    671 
    672 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVCESA_DESE_IVL, iv[1]);
    673 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVCESA_DESE_IVH, iv[0]);
    674 
    675 	i = o = 0;
    676 	while (i < len) {
    677 		s = min(sizeof(iblk), len - i);
    678 		iblk = 0;
    679 
    680 		if (buf != NULL)
    681 			memcpy(&iblk, buf + skip + i, s);
    682 		else if (m != NULL)
    683 			m_copydata(m, skip + i, s, &iblk);
    684 		else if (uio != NULL)
    685 			cuio_copydata(uio, skip + i, s, &iblk);
    686 
    687 		/*
    688 		 * We have the pipeline that two data enters.
    689 		 */
    690 
    691 		while (1 /* CONSTCOND */) {
    692 			cmd = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
    693 			    MVCESA_DESE_C);
    694 			if (cmd & MVCESA_DESE_C_ALLTERMINATION)
    695 				/* Engine is ready.  Can write two data. */
    696 				break;
    697 			if (cmd & MVCESA_DESE_C_READALLOW) {
    698 				oblk = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
    699 				    MVCESA_DESE_DOH);
    700 				/* XXXX: needs barrier? */
    701 				oblk |= (uint64_t)bus_space_read_4(sc->sc_iot,
    702 				    sc->sc_ioh, MVCESA_DESE_DOL) << 32;
    703 
    704 				if (buf != NULL)
    705 					memcpy(buf + skip + o, &oblk,
    706 					    sizeof(oblk));
    707 				else if (m != NULL)
    708 					m_copydata(m, skip + o, sizeof(oblk),
    709 					    &oblk);
    710 				else if (uio != NULL)
    711 					cuio_copyback(uio, skip + o,
    712 					    sizeof(oblk), &oblk);
    713 				o += sizeof(oblk);
    714 
    715 				/* Can write one data */
    716 				break;
    717 			}
    718 		}
    719 
    720 		/*
    721 		 * Encryption/Decription calculation time is 9 cycles in DES
    722 		 * mode and 25 cycles in 3DES mode.
    723 		 */
    724 		bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVCESA_DESE_DBL,
    725 		    iblk >> 32);
    726 		/* XXXX: needs barrier? */
    727 		bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVCESA_DESE_DBH,
    728 		    iblk & 0xffffffff);
    729 		i += s;
    730 	}
    731 
    732 	while (1 /* CONSTCOND */) {
    733 		cmd = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
    734 		    MVCESA_DESE_C);
    735 		if (cmd & (MVCESA_DESE_C_READALLOW |
    736 					MVCESA_DESE_C_ALLTERMINATION)) {
    737 			oblk = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
    738 			    MVCESA_DESE_DOH);
    739 			/* XXXX: needs barrier? */
    740 			oblk |= (uint64_t)bus_space_read_4(sc->sc_iot,
    741 			    sc->sc_ioh, MVCESA_DESE_DOL) << 32;
    742 
    743 			if (cmd & MVCESA_DESE_C_ALLTERMINATION) {
    744 				/* We can read IV from Data Out Registers. */
    745 				if (dir == MVCESA_DESE_C_DIRECTION_ENC)
    746 					o -= sizeof(oblk);
    747 				else
    748 					break;
    749 			}
    750 			if (buf != NULL)
    751 				memcpy(buf + skip + o, &oblk, sizeof(oblk));
    752 			else if (m != NULL)
    753 				m_copydata(m, skip + o, sizeof(oblk), &oblk);
    754 			else if (uio != NULL)
    755 				cuio_copyback(uio, skip + o, sizeof(oblk),
    756 				    &oblk);
    757 			o += sizeof(oblk);
    758 			if (cmd & MVCESA_DESE_C_ALLTERMINATION)
    759 				break;
    760 		}
    761 	}
    762 
    763 	if (dir == MVCESA_DESE_C_DIRECTION_ENC)
    764 		memcpy(ses->ses_iv, iv, sizeof(ses->ses_iv));
    765 
    766 	return 0;
    767 }
    768