Module Name: src
Committed By: hsuenaga
Date: Wed Jun 3 04:20:02 UTC 2015
Modified Files:
src/sys/arch/arm/marvell: files.marvell mvsoc.c mvsocvar.h
src/sys/dev/marvell: files.armada
Added Files:
src/sys/dev/marvell: mvxpsec.c mvxpsecreg.h mvxpsecvar.h
Log Message:
add new cryptographic accelerator driver 'mvxpsec.'
this driver controls CESA unit as same as mvcesa, but uses DMA engines and
does CBC operations, HMAC operations by hardware. about 2 kbytes of data
are processed at one. supported algorithms are:
- DES-CBC, 3DES-CBC, AES-CBC
- HMAC-SHA1, HMAC-MD5
non-CBC algorithm such as AES-GCM is not supported by CESA's acceleration
engine. mvcesa is still useful to implement such algorithms as combination of
accelerated block cipher and software chaining.
To generate a diff of this commit:
cvs rdiff -u -r1.16 -r1.17 src/sys/arch/arm/marvell/files.marvell
cvs rdiff -u -r1.22 -r1.23 src/sys/arch/arm/marvell/mvsoc.c
cvs rdiff -u -r1.9 -r1.10 src/sys/arch/arm/marvell/mvsocvar.h
cvs rdiff -u -r1.2 -r1.3 src/sys/dev/marvell/files.armada
cvs rdiff -u -r0 -r1.1 src/sys/dev/marvell/mvxpsec.c \
src/sys/dev/marvell/mvxpsecreg.h src/sys/dev/marvell/mvxpsecvar.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/arch/arm/marvell/files.marvell
diff -u src/sys/arch/arm/marvell/files.marvell:1.16 src/sys/arch/arm/marvell/files.marvell:1.17
--- src/sys/arch/arm/marvell/files.marvell:1.16 Wed Jun 3 03:55:47 2015
+++ src/sys/arch/arm/marvell/files.marvell Wed Jun 3 04:20:02 2015
@@ -1,4 +1,4 @@
-# $NetBSD: files.marvell,v 1.16 2015/06/03 03:55:47 hsuenaga Exp $
+# $NetBSD: files.marvell,v 1.17 2015/06/03 04:20:02 hsuenaga Exp $
#
# Configuration info for Marvell System on Chip support
#
@@ -70,6 +70,9 @@ attach ehci at mvsoc with mvusb_mbus
# Cryptographic Engines and Security Accelerator
attach mvcesa at mvsoc with mvcesa_mbus
+# ARMADA XP Cryptographic Engines and Security Accelerator
+attach mvxpsec at mvsoc with mvxpsec_mbus
+
# TWSI Two-Wire Serial Interface
attach gttwsi at mvsoc with gttwsi_mbus
Index: src/sys/arch/arm/marvell/mvsoc.c
diff -u src/sys/arch/arm/marvell/mvsoc.c:1.22 src/sys/arch/arm/marvell/mvsoc.c:1.23
--- src/sys/arch/arm/marvell/mvsoc.c:1.22 Wed Jun 3 03:55:47 2015
+++ src/sys/arch/arm/marvell/mvsoc.c Wed Jun 3 04:20:02 2015
@@ -1,4 +1,4 @@
-/* $NetBSD: mvsoc.c,v 1.22 2015/06/03 03:55:47 hsuenaga Exp $ */
+/* $NetBSD: mvsoc.c,v 1.23 2015/06/03 04:20:02 hsuenaga Exp $ */
/*
* Copyright (c) 2007, 2008, 2013, 2014 KIYOHARA Takashi
* All rights reserved.
@@ -26,12 +26,13 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: mvsoc.c,v 1.22 2015/06/03 03:55:47 hsuenaga Exp $");
+__KERNEL_RCSID(0, "$NetBSD: mvsoc.c,v 1.23 2015/06/03 04:20:02 hsuenaga Exp $");
#include "opt_cputypes.h"
#include "opt_mvsoc.h"
#ifdef ARMADAXP
#include "mvxpe.h"
+#include "mvxpsec.h"
#endif
#include <sys/param.h>
@@ -274,6 +275,10 @@ static struct {
ARMADAXP_ATTR_PEX3_MEM, ARMADAXP_UNITID_PEX3 },
{ ARMADAXP_TAG_PEX3_IO,
ARMADAXP_ATTR_PEX3_IO, ARMADAXP_UNITID_PEX3 },
+ { ARMADAXP_TAG_CRYPT0,
+ ARMADAXP_ATTR_CRYPT0_NOSWAP, ARMADAXP_UNITID_CRYPT },
+ { ARMADAXP_TAG_CRYPT1,
+ ARMADAXP_ATTR_CRYPT1_NOSWAP, ARMADAXP_UNITID_CRYPT },
#endif
};
@@ -692,8 +697,13 @@ static const struct mvsoc_periph {
{ ARMADAXP(MV78130), "mvgbec", 1, ARMADAXP_GBE1_BASE,IRQ_DEFAULT },
{ ARMADAXP(MV78130), "mvgbec", 2, ARMADAXP_GBE2_BASE,IRQ_DEFAULT },
#endif
+#if NMVXPSEC > 0
+ { ARMADAXP(MV78130), "mvxpsec", 0, ARMADAXP_XPSEC0_BASE,ARMADAXP_IRQ_CESA0 },
+ { ARMADAXP(MV78130), "mvxpsec", 1, ARMADAXP_XPSEC1_BASE,ARMADAXP_IRQ_CESA1 },
+#else
{ ARMADAXP(MV78130), "mvcesa", 0, ARMADAXP_CESA0_BASE,ARMADAXP_IRQ_CESA0 },
{ ARMADAXP(MV78130), "mvcesa", 1, ARMADAXP_CESA1_BASE,ARMADAXP_IRQ_CESA1 },
+#endif
{ ARMADAXP(MV78160), "mvsoctmr",0,MVSOC_TMR_BASE, ARMADAXP_IRQ_TIMER0 },
{ ARMADAXP(MV78160), "com", 0, MVSOC_COM0_BASE, ARMADAXP_IRQ_UART0 },
@@ -728,8 +738,13 @@ static const struct mvsoc_periph {
{ ARMADAXP(MV78160), "mvgbec", 2, ARMADAXP_GBE2_BASE,IRQ_DEFAULT },
{ ARMADAXP(MV78160), "mvgbec", 3, ARMADAXP_GBE3_BASE,IRQ_DEFAULT },
#endif
+#if NMVXPSEC > 0
+ { ARMADAXP(MV78160), "mvxpsec", 0, ARMADAXP_XPSEC0_BASE,ARMADAXP_IRQ_CESA0 },
+ { ARMADAXP(MV78160), "mvxpsec", 1, ARMADAXP_XPSEC1_BASE,ARMADAXP_IRQ_CESA1 },
+#else
{ ARMADAXP(MV78160), "mvcesa", 0, ARMADAXP_CESA0_BASE,ARMADAXP_IRQ_CESA0 },
{ ARMADAXP(MV78160), "mvcesa", 1, ARMADAXP_CESA1_BASE,ARMADAXP_IRQ_CESA1 },
+#endif
{ ARMADAXP(MV78230), "mvsoctmr",0,MVSOC_TMR_BASE, ARMADAXP_IRQ_TIMER0 },
{ ARMADAXP(MV78230), "com", 0, MVSOC_COM0_BASE, ARMADAXP_IRQ_UART0 },
@@ -762,8 +777,13 @@ static const struct mvsoc_periph {
{ ARMADAXP(MV78230), "mvgbec", 1, ARMADAXP_GBE1_BASE,IRQ_DEFAULT },
{ ARMADAXP(MV78230), "mvgbec", 2, ARMADAXP_GBE2_BASE,IRQ_DEFAULT },
#endif
+#if NMVXPSEC > 0
+ { ARMADAXP(MV78230), "mvxpsec", 0, ARMADAXP_XPSEC0_BASE,ARMADAXP_IRQ_CESA0 },
+ { ARMADAXP(MV78230), "mvxpsec", 1, ARMADAXP_XPSEC1_BASE,ARMADAXP_IRQ_CESA1 },
+#else
{ ARMADAXP(MV78230), "mvcesa", 0, ARMADAXP_CESA0_BASE,ARMADAXP_IRQ_CESA0 },
{ ARMADAXP(MV78230), "mvcesa", 1, ARMADAXP_CESA1_BASE,ARMADAXP_IRQ_CESA1 },
+#endif
{ ARMADAXP(MV78260), "mvsoctmr",0,MVSOC_TMR_BASE, ARMADAXP_IRQ_TIMER0 },
{ ARMADAXP(MV78260), "com", 0, MVSOC_COM0_BASE, ARMADAXP_IRQ_UART0 },
@@ -798,8 +818,13 @@ static const struct mvsoc_periph {
{ ARMADAXP(MV78260), "mvgbec", 2, ARMADAXP_GBE2_BASE,IRQ_DEFAULT },
{ ARMADAXP(MV78260), "mvgbec", 3, ARMADAXP_GBE3_BASE,IRQ_DEFAULT },
#endif
+#if NMVXPSEC > 0
+ { ARMADAXP(MV78260), "mvxpsec", 0, ARMADAXP_XPSEC0_BASE,ARMADAXP_IRQ_CESA0 },
+ { ARMADAXP(MV78260), "mvxpsec", 1, ARMADAXP_XPSEC1_BASE,ARMADAXP_IRQ_CESA1 },
+#else
{ ARMADAXP(MV78260), "mvcesa", 0, ARMADAXP_CESA0_BASE,ARMADAXP_IRQ_CESA0 },
{ ARMADAXP(MV78260), "mvcesa", 1, ARMADAXP_CESA1_BASE,ARMADAXP_IRQ_CESA1 },
+#endif
{ ARMADAXP(MV78460), "mvsoctmr",0,MVSOC_TMR_BASE, ARMADAXP_IRQ_TIMER0 },
{ ARMADAXP(MV78460), "com", 0, MVSOC_COM0_BASE, ARMADAXP_IRQ_UART0 },
@@ -835,8 +860,13 @@ static const struct mvsoc_periph {
{ ARMADAXP(MV78460), "mvgbec", 2, ARMADAXP_GBE2_BASE,IRQ_DEFAULT },
{ ARMADAXP(MV78460), "mvgbec", 3, ARMADAXP_GBE3_BASE,IRQ_DEFAULT },
#endif
+#if NMVXPSEC > 0
+ { ARMADAXP(MV78460), "mvxpsec", 0, ARMADAXP_XPSEC0_BASE,ARMADAXP_IRQ_CESA0 },
+ { ARMADAXP(MV78460), "mvxpsec", 1, ARMADAXP_XPSEC1_BASE,ARMADAXP_IRQ_CESA1 },
+#else
{ ARMADAXP(MV78460), "mvcesa", 0, ARMADAXP_CESA0_BASE,ARMADAXP_IRQ_CESA0 },
{ ARMADAXP(MV78460), "mvcesa", 1, ARMADAXP_CESA1_BASE,ARMADAXP_IRQ_CESA1 },
+#endif
{ ARMADA370(MV6710), "mvsoctmr",0,MVSOC_TMR_BASE, ARMADAXP_IRQ_TIMER0 },
{ ARMADA370(MV6710), "com", 0, MVSOC_COM0_BASE, ARMADAXP_IRQ_UART0 },
@@ -861,8 +891,12 @@ static const struct mvsoc_periph {
{ ARMADA370(MV6710), "mvgbec", 0, ARMADAXP_GBE0_BASE,IRQ_DEFAULT },
{ ARMADA370(MV6710), "mvgbec", 1, ARMADAXP_GBE1_BASE,IRQ_DEFAULT },
#endif
+#if NMVXPSEC > 0
+ { ARMADA370(MV6710), "mvxpsec", 0, ARMADAXP_XPSEC0_BASE,ARMADAXP_IRQ_CESA0 },
+#else
{ ARMADA370(MV6710), "mvcesa", 0, ARMADAXP_CESA0_BASE,ARMADAXP_IRQ_CESA0 },
#endif
+#endif
};
Index: src/sys/arch/arm/marvell/mvsocvar.h
diff -u src/sys/arch/arm/marvell/mvsocvar.h:1.9 src/sys/arch/arm/marvell/mvsocvar.h:1.10
--- src/sys/arch/arm/marvell/mvsocvar.h:1.9 Wed Jun 3 03:04:21 2015
+++ src/sys/arch/arm/marvell/mvsocvar.h Wed Jun 3 04:20:02 2015
@@ -1,4 +1,4 @@
-/* $NetBSD: mvsocvar.h,v 1.9 2015/06/03 03:04:21 hsuenaga Exp $ */
+/* $NetBSD: mvsocvar.h,v 1.10 2015/06/03 04:20:02 hsuenaga Exp $ */
/*
* Copyright (c) 2007, 2010 KIYOHARA Takashi
* All rights reserved.
@@ -119,6 +119,8 @@ enum mvsoc_tags {
ARMADAXP_TAG_PEX2_IO,
ARMADAXP_TAG_PEX3_MEM,
ARMADAXP_TAG_PEX3_IO,
+ ARMADAXP_TAG_CRYPT0,
+ ARMADAXP_TAG_CRYPT1,
};
int mvsoc_target(int, uint32_t *, uint32_t *, uint32_t *, uint32_t *);
int mvsoc_target_dump(struct mvsoc_softc *);
Index: src/sys/dev/marvell/files.armada
diff -u src/sys/dev/marvell/files.armada:1.2 src/sys/dev/marvell/files.armada:1.3
--- src/sys/dev/marvell/files.armada:1.2 Wed Jun 3 03:55:47 2015
+++ src/sys/dev/marvell/files.armada Wed Jun 3 04:20:02 2015
@@ -1,4 +1,4 @@
-# $NetBSD: files.armada,v 1.2 2015/06/03 03:55:47 hsuenaga Exp $
+# $NetBSD: files.armada,v 1.3 2015/06/03 04:20:02 hsuenaga Exp $
# Configuration info for Marvell ARMADA integrated peripherals
# ARMADA XP Buffer Manger
@@ -9,3 +9,8 @@ file dev/marvell/mvxpbm.c
define mvxpe { [port = -1 ], [irq = -1] }
device mvxpe: mvxpbm, ether, ifnet, arp, mii
file dev/marvell/if_mvxpe.c mvxpe needs-flag
+
+# ARMADA XP Cryptographic Engines and Security Accelerator
+define mvxpsec { [port = -1 ], [irq = -1] }
+device mvxpsec: opencrypto
+file dev/marvell/mvxpsec.c mvxpsec needs-flag
Added files:
Index: src/sys/dev/marvell/mvxpsec.c
diff -u /dev/null src/sys/dev/marvell/mvxpsec.c:1.1
--- /dev/null Wed Jun 3 04:20:02 2015
+++ src/sys/dev/marvell/mvxpsec.c Wed Jun 3 04:20:02 2015
@@ -0,0 +1,3690 @@
+/* $NetBSD: mvxpsec.c,v 1.1 2015/06/03 04:20:02 hsuenaga Exp $ */
+/*
+ * Copyright (c) 2015 Internet Initiative Japan Inc.
+ * 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.
+ */
+/*
+ * Cryptographic Engine and Security Accelerator(MVXPSEC)
+ */
+#include <sys/cdefs.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/kernel.h>
+#include <sys/queue.h>
+#include <sys/conf.h>
+#include <sys/proc.h>
+#include <sys/bus.h>
+#include <sys/evcnt.h>
+#include <sys/device.h>
+#include <sys/endian.h>
+#include <sys/errno.h>
+#include <sys/kmem.h>
+#include <sys/mbuf.h>
+#include <sys/callout.h>
+#include <sys/pool.h>
+#include <sys/cprng.h>
+#include <sys/syslog.h>
+#include <sys/mutex.h>
+#include <sys/kthread.h>
+#include <sys/atomic.h>
+#include <sys/sha1.h>
+#include <sys/md5.h>
+
+#include <uvm/uvm_extern.h>
+
+#include <crypto/rijndael/rijndael.h>
+
+#include <opencrypto/cryptodev.h>
+#include <opencrypto/xform.h>
+
+#include <net/net_stats.h>
+
+#include <netinet/in_systm.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/ip6.h>
+
+#include <netipsec/esp_var.h>
+
+#include <arm/cpufunc.h>
+#include <arm/marvell/mvsocvar.h>
+#include <arm/marvell/armadaxpreg.h>
+#include <dev/marvell/marvellreg.h>
+#include <dev/marvell/marvellvar.h>
+#include <dev/marvell/mvxpsecreg.h>
+#include <dev/marvell/mvxpsecvar.h>
+
+#ifdef DEBUG
+#define STATIC __attribute__ ((noinline)) extern
+#define _STATIC __attribute__ ((noinline)) extern
+#define INLINE __attribute__ ((noinline)) extern
+#define _INLINE __attribute__ ((noinline)) extern
+#else
+#define STATIC static
+#define _STATIC __attribute__ ((unused)) static
+#define INLINE static inline
+#define _INLINE __attribute__ ((unused)) static inline
+#endif
+
+/*
+ * IRQ and SRAM spaces for each of unit
+ * XXX: move to attach_args
+ */
+struct {
+ int err_int;
+} mvxpsec_config[] = {
+ { .err_int = ARMADAXP_IRQ_CESA0_ERR, }, /* unit 0 */
+ { .err_int = ARMADAXP_IRQ_CESA1_ERR, }, /* unit 1 */
+};
+#define MVXPSEC_ERR_INT(sc) \
+ mvxpsec_config[device_unit((sc)->sc_dev)].err_int
+
+/*
+ * AES
+ */
+#define MAXBC (128/32)
+#define MAXKC (256/32)
+#define MAXROUNDS 14
+STATIC int mv_aes_ksched(uint8_t[4][MAXKC], int,
+ uint8_t[MAXROUNDS+1][4][MAXBC]);
+STATIC int mv_aes_deckey(uint8_t *, uint8_t *, int);
+
+/*
+ * device driver autoconf interface
+ */
+STATIC int mvxpsec_match(device_t, cfdata_t, void *);
+STATIC void mvxpsec_attach(device_t, device_t, void *);
+STATIC void mvxpsec_evcnt_attach(struct mvxpsec_softc *);
+
+/*
+ * register setup
+ */
+STATIC int mvxpsec_wininit(struct mvxpsec_softc *, enum marvell_tags *);
+
+/*
+ * timer(callout) interface
+ *
+ * XXX: callout is not MP safe...
+ */
+STATIC void mvxpsec_timer(void *);
+
+/*
+ * interrupt interface
+ */
+STATIC int mvxpsec_intr(void *);
+INLINE void mvxpsec_intr_cleanup(struct mvxpsec_softc *);
+STATIC int mvxpsec_eintr(void *);
+STATIC uint32_t mvxpsec_intr_ack(struct mvxpsec_softc *);
+STATIC uint32_t mvxpsec_eintr_ack(struct mvxpsec_softc *);
+INLINE void mvxpsec_intr_cnt(struct mvxpsec_softc *, int);
+
+/*
+ * memory allocators and VM management
+ */
+STATIC struct mvxpsec_devmem *mvxpsec_alloc_devmem(struct mvxpsec_softc *,
+ paddr_t, int);
+STATIC int mvxpsec_init_sram(struct mvxpsec_softc *);
+
+/*
+ * Low-level DMA interface
+ */
+STATIC int mvxpsec_init_dma(struct mvxpsec_softc *,
+ struct marvell_attach_args *);
+INLINE int mvxpsec_dma_wait(struct mvxpsec_softc *);
+INLINE int mvxpsec_acc_wait(struct mvxpsec_softc *);
+INLINE struct mvxpsec_descriptor_handle *mvxpsec_dma_getdesc(struct mvxpsec_softc *);
+_INLINE void mvxpsec_dma_putdesc(struct mvxpsec_softc *, struct mvxpsec_descriptor_handle *);
+INLINE void mvxpsec_dma_setup(struct mvxpsec_descriptor_handle *,
+ uint32_t, uint32_t, uint32_t);
+INLINE void mvxpsec_dma_cat(struct mvxpsec_softc *,
+ struct mvxpsec_descriptor_handle *, struct mvxpsec_descriptor_handle *);
+
+/*
+ * High-level DMA interface
+ */
+INLINE int mvxpsec_dma_copy0(struct mvxpsec_softc *,
+ mvxpsec_dma_ring *, uint32_t, uint32_t, uint32_t);
+INLINE int mvxpsec_dma_copy(struct mvxpsec_softc *,
+ mvxpsec_dma_ring *, uint32_t, uint32_t, uint32_t);
+INLINE int mvxpsec_dma_acc_activate(struct mvxpsec_softc *,
+ mvxpsec_dma_ring *);
+INLINE void mvxpsec_dma_finalize(struct mvxpsec_softc *,
+ mvxpsec_dma_ring *);
+INLINE void mvxpsec_dma_free(struct mvxpsec_softc *,
+ mvxpsec_dma_ring *);
+INLINE int mvxpsec_dma_copy_packet(struct mvxpsec_softc *, struct mvxpsec_packet *);
+INLINE int mvxpsec_dma_sync_packet(struct mvxpsec_softc *, struct mvxpsec_packet *);
+
+/*
+ * Session management interface (OpenCrypto)
+ */
+#define MVXPSEC_SESSION(sid) ((sid) & 0x0fffffff)
+#define MVXPSEC_SID(crd, sesn) (((crd) << 28) | ((sesn) & 0x0fffffff))
+/* pool management */
+STATIC int mvxpsec_session_ctor(void *, void *, int);
+STATIC void mvxpsec_session_dtor(void *, void *);
+STATIC int mvxpsec_packet_ctor(void *, void *, int);
+STATIC void mvxpsec_packet_dtor(void *, void *);
+
+/* session management */
+STATIC struct mvxpsec_session *mvxpsec_session_alloc(struct mvxpsec_softc *);
+STATIC void mvxpsec_session_dealloc(struct mvxpsec_session *);
+INLINE struct mvxpsec_session *mvxpsec_session_lookup(struct mvxpsec_softc *, int);
+INLINE int mvxpsec_session_ref(struct mvxpsec_session *);
+INLINE void mvxpsec_session_unref(struct mvxpsec_session *);
+
+/* packet management */
+STATIC struct mvxpsec_packet *mvxpsec_packet_alloc(struct mvxpsec_session *);
+INLINE void mvxpsec_packet_enqueue(struct mvxpsec_packet *);
+STATIC void mvxpsec_packet_dealloc(struct mvxpsec_packet *);
+STATIC int mvxpsec_done_packet(struct mvxpsec_packet *);
+
+/* session header manegement */
+STATIC int mvxpsec_header_finalize(struct mvxpsec_packet *);
+
+/* packet queue management */
+INLINE void mvxpsec_drop(struct mvxpsec_softc *, struct cryptop *, struct mvxpsec_packet *, int);
+STATIC int mvxpsec_dispatch_queue(struct mvxpsec_softc *);
+
+/* opencrypto opration */
+INLINE int mvxpsec_parse_crd(struct mvxpsec_packet *, struct cryptodesc *);
+INLINE int mvxpsec_parse_crp(struct mvxpsec_packet *);
+
+/* payload data management */
+INLINE int mvxpsec_packet_setcrp(struct mvxpsec_packet *, struct cryptop *);
+STATIC int mvxpsec_packet_setdata(struct mvxpsec_packet *, void *, uint32_t);
+STATIC int mvxpsec_packet_setmbuf(struct mvxpsec_packet *, struct mbuf *);
+STATIC int mvxpsec_packet_setuio(struct mvxpsec_packet *, struct uio *);
+STATIC int mvxpsec_packet_rdata(struct mvxpsec_packet *, int, int, void *);
+_STATIC int mvxpsec_packet_wdata(struct mvxpsec_packet *, int, int, void *);
+STATIC int mvxpsec_packet_write_iv(struct mvxpsec_packet *, void *, int);
+STATIC int mvxpsec_packet_copy_iv(struct mvxpsec_packet *, int, int);
+
+/* key pre-computation */
+STATIC int mvxpsec_key_precomp(int, void *, int, void *, void *);
+STATIC int mvxpsec_hmac_precomp(int, void *, int, void *, void *);
+
+/* crypto operation management */
+INLINE void mvxpsec_packet_reset_op(struct mvxpsec_packet *);
+INLINE void mvxpsec_packet_update_op_order(struct mvxpsec_packet *, int);
+
+/*
+ * parameter converters
+ */
+INLINE uint32_t mvxpsec_alg2acc(uint32_t alg);
+INLINE uint32_t mvxpsec_aesklen(int klen);
+
+/*
+ * string formatters
+ */
+_STATIC const char *s_ctrlreg(uint32_t);
+_STATIC const char *s_winreg(uint32_t);
+_STATIC const char *s_errreg(uint32_t);
+_STATIC const char *s_xpsecintr(uint32_t);
+_STATIC const char *s_ctlalg(uint32_t);
+_STATIC const char *s_xpsec_op(uint32_t);
+_STATIC const char *s_xpsec_enc(uint32_t);
+_STATIC const char *s_xpsec_mac(uint32_t);
+_STATIC const char *s_xpsec_frag(uint32_t);
+
+/*
+ * debugging supports
+ */
+#ifdef MVXPSEC_DEBUG
+_STATIC void mvxpsec_dump_dmaq(struct mvxpsec_descriptor_handle *);
+_STATIC void mvxpsec_dump_reg(struct mvxpsec_softc *);
+_STATIC void mvxpsec_dump_sram(const char *, struct mvxpsec_softc *, size_t);
+_STATIC void mvxpsec_dump_data(const char *, void *, size_t);
+
+_STATIC void mvxpsec_dump_packet(const char *, struct mvxpsec_packet *);
+_STATIC void mvxpsec_dump_packet_data(const char *, struct mvxpsec_packet *);
+_STATIC void mvxpsec_dump_packet_desc(const char *, struct mvxpsec_packet *);
+
+_STATIC void mvxpsec_dump_acc_config(const char *, uint32_t);
+_STATIC void mvxpsec_dump_acc_encdata(const char *, uint32_t, uint32_t);
+_STATIC void mvxpsec_dump_acc_enclen(const char *, uint32_t);
+_STATIC void mvxpsec_dump_acc_enckey(const char *, uint32_t);
+_STATIC void mvxpsec_dump_acc_enciv(const char *, uint32_t);
+_STATIC void mvxpsec_dump_acc_macsrc(const char *, uint32_t);
+_STATIC void mvxpsec_dump_acc_macdst(const char *, uint32_t);
+_STATIC void mvxpsec_dump_acc_maciv(const char *, uint32_t);
+#endif
+
+/*
+ * global configurations, params, work spaces, ...
+ *
+ * XXX: use sysctl for global configurations
+ */
+/* waiting for device */
+static int mvxpsec_wait_interval = 10; /* usec */
+static int mvxpsec_wait_retry = 100; /* times = wait for 1 [msec] */
+#ifdef MVXPSEC_DEBUG
+static uint32_t mvxpsec_debug = MVXPSEC_DEBUG; /* debug level */
+#endif
+
+/*
+ * Register accessors
+ */
+#define MVXPSEC_WRITE(sc, off, val) \
+ bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (off), (val))
+#define MVXPSEC_READ(sc, off) \
+ bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (off))
+
+/*
+ * device driver autoconf interface
+ */
+CFATTACH_DECL2_NEW(mvxpsec_mbus, sizeof(struct mvxpsec_softc),
+ mvxpsec_match, mvxpsec_attach, NULL, NULL, NULL, NULL);
+
+STATIC int
+mvxpsec_match(device_t dev, cfdata_t match, void *aux)
+{
+ struct marvell_attach_args *mva = aux;
+ uint32_t tag;
+ int window;
+
+ if (strcmp(mva->mva_name, match->cf_name) != 0)
+ return 0;
+ if (mva->mva_offset == MVA_OFFSET_DEFAULT)
+ return 0;
+
+ switch (mva->mva_unit) {
+ case 0:
+ tag = ARMADAXP_TAG_CRYPT0;
+ break;
+ case 1:
+ tag = ARMADAXP_TAG_CRYPT1;
+ break;
+ default:
+ aprint_error_dev(dev,
+ "unit %d is not supported\n", mva->mva_unit);
+ return 0;
+ }
+
+ window = mvsoc_target(tag, NULL, NULL, NULL, NULL);
+ if (window >= nwindow) {
+ aprint_error_dev(dev,
+ "Security Accelerator SRAM is not configured.\n");
+ return 0;
+ }
+
+ return 1;
+}
+
+STATIC void
+mvxpsec_attach(device_t parent, device_t self, void *aux)
+{
+ struct marvell_attach_args *mva = aux;
+ struct mvxpsec_softc *sc = device_private(self);
+ int v;
+ int i;
+
+ sc->sc_dev = self;
+
+ aprint_normal(": Marvell Crypto Engines and Security Accelerator\n");
+ aprint_naive("\n");
+#ifdef MVXPSEC_MULTI_PACKET
+ aprint_normal_dev(sc->sc_dev, "multi-packet chained mode enabled.\n");
+#else
+ aprint_normal_dev(sc->sc_dev, "multi-packet chained mode disabled.\n");
+#endif
+ aprint_normal_dev(sc->sc_dev,
+ "Max %d sessions.\n", MVXPSEC_MAX_SESSIONS);
+
+ /* mutex */
+ mutex_init(&sc->sc_session_mtx, MUTEX_DEFAULT, IPL_NET);
+ mutex_init(&sc->sc_dma_mtx, MUTEX_DEFAULT, IPL_NET);
+ mutex_init(&sc->sc_queue_mtx, MUTEX_DEFAULT, IPL_NET);
+
+ /* Packet queue */
+ SIMPLEQ_INIT(&sc->sc_wait_queue);
+ SIMPLEQ_INIT(&sc->sc_run_queue);
+ SLIST_INIT(&sc->sc_free_list);
+ sc->sc_wait_qlen = 0;
+#ifdef MVXPSEC_MULTI_PACKET
+ sc->sc_wait_qlimit = 16;
+#else
+ sc->sc_wait_qlimit = 0;
+#endif
+ sc->sc_free_qlen = 0;
+
+ /* Timer */
+ callout_init(&sc->sc_timeout, 0); /* XXX: use CALLOUT_MPSAFE */
+ callout_setfunc(&sc->sc_timeout, mvxpsec_timer, sc);
+
+ /* I/O */
+ sc->sc_iot = mva->mva_iot;
+ if (bus_space_subregion(mva->mva_iot, mva->mva_ioh,
+ mva->mva_offset, mva->mva_size, &sc->sc_ioh)) {
+ aprint_error_dev(self, "Cannot map registers\n");
+ return;
+ }
+
+ /* DMA */
+ sc->sc_dmat = mva->mva_dmat;
+ if (mvxpsec_init_dma(sc, mva) < 0)
+ return;
+
+ /* SRAM */
+ if (mvxpsec_init_sram(sc) < 0)
+ return;
+
+ /* Registers */
+ mvxpsec_wininit(sc, mva->mva_tags);
+
+ /* INTR */
+ MVXPSEC_WRITE(sc, MVXPSEC_INT_MASK, MVXPSEC_DEFAULT_INT);
+ MVXPSEC_WRITE(sc, MV_TDMA_ERR_MASK, MVXPSEC_DEFAULT_ERR);
+ sc->sc_done_ih =
+ marvell_intr_establish(mva->mva_irq, IPL_NET, mvxpsec_intr, sc);
+ /* XXX: sould pass error IRQ using mva */
+ sc->sc_error_ih = marvell_intr_establish(MVXPSEC_ERR_INT(sc),
+ IPL_NET, mvxpsec_eintr, sc);
+ aprint_normal_dev(self,
+ "Error Reporting IRQ %d\n", MVXPSEC_ERR_INT(sc));
+
+ /* Initialize TDMA (It's enabled here, but waiting for SA) */
+ if (mvxpsec_dma_wait(sc) < 0)
+ panic("%s: DMA DEVICE not responding\n", __func__);
+ MVXPSEC_WRITE(sc, MV_TDMA_CNT, 0);
+ MVXPSEC_WRITE(sc, MV_TDMA_SRC, 0);
+ MVXPSEC_WRITE(sc, MV_TDMA_DST, 0);
+ MVXPSEC_WRITE(sc, MV_TDMA_NXT, 0);
+ MVXPSEC_WRITE(sc, MV_TDMA_CUR, 0);
+ v = MVXPSEC_READ(sc, MV_TDMA_CONTROL);
+ v |= MV_TDMA_CONTROL_ENABLE;
+ MVXPSEC_WRITE(sc, MV_TDMA_CONTROL, v);
+
+ /* Initialize SA */
+ if (mvxpsec_acc_wait(sc) < 0)
+ panic("%s: MVXPSEC not responding\n", __func__);
+ v = MVXPSEC_READ(sc, MV_ACC_CONFIG);
+ v &= ~MV_ACC_CONFIG_STOP_ON_ERR;
+ v |= MV_ACC_CONFIG_MULT_PKT;
+ v |= MV_ACC_CONFIG_WAIT_TDMA;
+ v |= MV_ACC_CONFIG_ACT_TDMA;
+ MVXPSEC_WRITE(sc, MV_ACC_CONFIG, v);
+ MVXPSEC_WRITE(sc, MV_ACC_DESC, 0);
+ MVXPSEC_WRITE(sc, MV_ACC_COMMAND, MV_ACC_COMMAND_STOP);
+
+ /* Session */
+ sc->sc_session_pool =
+ pool_cache_init(sizeof(struct mvxpsec_session), 0, 0, 0,
+ "mvxpsecpl", NULL, IPL_NET,
+ mvxpsec_session_ctor, mvxpsec_session_dtor, sc);
+ pool_cache_sethiwat(sc->sc_session_pool, MVXPSEC_MAX_SESSIONS);
+ pool_cache_setlowat(sc->sc_session_pool, MVXPSEC_MAX_SESSIONS / 2);
+ sc->sc_last_session = NULL;
+
+ /* Pakcet */
+ sc->sc_packet_pool =
+ pool_cache_init(sizeof(struct mvxpsec_session), 0, 0, 0,
+ "mvxpsec_pktpl", NULL, IPL_NET,
+ mvxpsec_packet_ctor, mvxpsec_packet_dtor, sc);
+ pool_cache_sethiwat(sc->sc_packet_pool, MVXPSEC_MAX_SESSIONS);
+ pool_cache_setlowat(sc->sc_packet_pool, MVXPSEC_MAX_SESSIONS / 2);
+
+ /* Register to EVCNT framework */
+ mvxpsec_evcnt_attach(sc);
+
+ /* Register to Opencrypto */
+ for (i = 0; i < MVXPSEC_MAX_SESSIONS; i++) {
+ sc->sc_sessions[i] = NULL;
+ }
+ if (mvxpsec_register(sc))
+ panic("cannot initialize OpenCrypto module.\n");
+
+ return;
+}
+
+STATIC void
+mvxpsec_evcnt_attach(struct mvxpsec_softc *sc)
+{
+ struct mvxpsec_evcnt *sc_ev = &sc->sc_ev;
+
+ evcnt_attach_dynamic(&sc_ev->intr_all, EVCNT_TYPE_INTR,
+ NULL, device_xname(sc->sc_dev), "Main Intr.");
+ evcnt_attach_dynamic(&sc_ev->intr_auth, EVCNT_TYPE_INTR,
+ NULL, device_xname(sc->sc_dev), "Auth Intr.");
+ evcnt_attach_dynamic(&sc_ev->intr_des, EVCNT_TYPE_INTR,
+ NULL, device_xname(sc->sc_dev), "DES Intr.");
+ evcnt_attach_dynamic(&sc_ev->intr_aes_enc, EVCNT_TYPE_INTR,
+ NULL, device_xname(sc->sc_dev), "AES-Encrypt Intr.");
+ evcnt_attach_dynamic(&sc_ev->intr_aes_dec, EVCNT_TYPE_INTR,
+ NULL, device_xname(sc->sc_dev), "AES-Decrypt Intr.");
+ evcnt_attach_dynamic(&sc_ev->intr_enc, EVCNT_TYPE_INTR,
+ NULL, device_xname(sc->sc_dev), "Crypto Intr.");
+ evcnt_attach_dynamic(&sc_ev->intr_sa, EVCNT_TYPE_INTR,
+ NULL, device_xname(sc->sc_dev), "SA Intr.");
+ evcnt_attach_dynamic(&sc_ev->intr_acctdma, EVCNT_TYPE_INTR,
+ NULL, device_xname(sc->sc_dev), "AccTDMA Intr.");
+ evcnt_attach_dynamic(&sc_ev->intr_comp, EVCNT_TYPE_INTR,
+ NULL, device_xname(sc->sc_dev), "TDMA-Complete Intr.");
+ evcnt_attach_dynamic(&sc_ev->intr_own, EVCNT_TYPE_INTR,
+ NULL, device_xname(sc->sc_dev), "TDMA-Ownership Intr.");
+ evcnt_attach_dynamic(&sc_ev->intr_acctdma_cont, EVCNT_TYPE_INTR,
+ NULL, device_xname(sc->sc_dev), "AccTDMA-Continue Intr.");
+
+ evcnt_attach_dynamic(&sc_ev->session_new, EVCNT_TYPE_MISC,
+ NULL, device_xname(sc->sc_dev), "New-Session");
+ evcnt_attach_dynamic(&sc_ev->session_free, EVCNT_TYPE_MISC,
+ NULL, device_xname(sc->sc_dev), "Free-Session");
+
+ evcnt_attach_dynamic(&sc_ev->packet_ok, EVCNT_TYPE_MISC,
+ NULL, device_xname(sc->sc_dev), "Packet-OK");
+ evcnt_attach_dynamic(&sc_ev->packet_err, EVCNT_TYPE_MISC,
+ NULL, device_xname(sc->sc_dev), "Packet-ERR");
+
+ evcnt_attach_dynamic(&sc_ev->dispatch_packets, EVCNT_TYPE_MISC,
+ NULL, device_xname(sc->sc_dev), "Packet-Dispatch");
+ evcnt_attach_dynamic(&sc_ev->dispatch_queue, EVCNT_TYPE_MISC,
+ NULL, device_xname(sc->sc_dev), "Queue-Dispatch");
+ evcnt_attach_dynamic(&sc_ev->queue_full, EVCNT_TYPE_MISC,
+ NULL, device_xname(sc->sc_dev), "Queue-Full");
+ evcnt_attach_dynamic(&sc_ev->max_dispatch, EVCNT_TYPE_MISC,
+ NULL, device_xname(sc->sc_dev), "Max-Dispatch");
+ evcnt_attach_dynamic(&sc_ev->max_done, EVCNT_TYPE_MISC,
+ NULL, device_xname(sc->sc_dev), "Max-Done");
+}
+
+/*
+ * Register setup
+ */
+STATIC int mvxpsec_wininit(struct mvxpsec_softc *sc, enum marvell_tags *tags)
+{
+ device_t pdev = device_parent(sc->sc_dev);
+ uint64_t base;
+ uint32_t size, reg;
+ int window, target, attr, rv, i;
+
+ /* disable all window */
+ for (window = 0; window < MV_TDMA_NWINDOW; window++)
+ {
+ MVXPSEC_WRITE(sc, MV_TDMA_BAR(window), 0);
+ MVXPSEC_WRITE(sc, MV_TDMA_ATTR(window), 0);
+ }
+
+ for (window = 0, i = 0;
+ tags[i] != MARVELL_TAG_UNDEFINED && window < MV_TDMA_NWINDOW; i++) {
+ rv = marvell_winparams_by_tag(pdev, tags[i],
+ &target, &attr, &base, &size);
+ if (rv != 0 || size == 0)
+ continue;
+
+ if (base > 0xffffffffULL) {
+ aprint_error_dev(sc->sc_dev,
+ "can't remap window %d\n", window);
+ continue;
+ }
+
+ reg = MV_TDMA_BAR_BASE(base);
+ MVXPSEC_WRITE(sc, MV_TDMA_BAR(window), reg);
+
+ reg = MV_TDMA_ATTR_TARGET(target);
+ reg |= MV_TDMA_ATTR_ATTR(attr);
+ reg |= MV_TDMA_ATTR_SIZE(size);
+ reg |= MV_TDMA_ATTR_ENABLE;
+ MVXPSEC_WRITE(sc, MV_TDMA_ATTR(window), reg);
+
+ window++;
+ }
+
+ return 0;
+}
+
+/*
+ * Timer handling
+ */
+STATIC void
+mvxpsec_timer(void *aux)
+{
+ struct mvxpsec_softc *sc = aux;
+ struct mvxpsec_packet *mv_p;
+ uint32_t reg;
+ int ndone;
+ int refill;
+ int s;
+
+ /* IPL_SOFTCLOCK */
+
+ log(LOG_ERR, "%s: device timeout.\n", __func__);
+#ifdef MVXPSEC_DEBUG
+ mvxpsec_dump_reg(sc);
+#endif
+
+ s = splnet();
+ /* stop security accelerator */
+ MVXPSEC_WRITE(sc, MV_ACC_COMMAND, MV_ACC_COMMAND_STOP);
+
+ /* stop TDMA */
+ MVXPSEC_WRITE(sc, MV_TDMA_CONTROL, 0);
+
+ /* cleanup packet queue */
+ mutex_enter(&sc->sc_queue_mtx);
+ ndone = 0;
+ while ( (mv_p = SIMPLEQ_FIRST(&sc->sc_run_queue)) != NULL) {
+ SIMPLEQ_REMOVE_HEAD(&sc->sc_run_queue, queue);
+
+ mv_p->crp->crp_etype = EINVAL;
+ mvxpsec_done_packet(mv_p);
+ ndone++;
+ }
+ MVXPSEC_EVCNT_MAX(sc, max_done, ndone);
+ sc->sc_flags &= ~HW_RUNNING;
+ refill = (sc->sc_wait_qlen > 0) ? 1 : 0;
+ mutex_exit(&sc->sc_queue_mtx);
+
+ /* reenable TDMA */
+ if (mvxpsec_dma_wait(sc) < 0)
+ panic("%s: failed to reset DMA DEVICE. give up.", __func__);
+ MVXPSEC_WRITE(sc, MV_TDMA_CNT, 0);
+ MVXPSEC_WRITE(sc, MV_TDMA_SRC, 0);
+ MVXPSEC_WRITE(sc, MV_TDMA_DST, 0);
+ MVXPSEC_WRITE(sc, MV_TDMA_CUR, 0);
+ MVXPSEC_WRITE(sc, MV_TDMA_NXT, 0);
+ reg = MV_TDMA_DEFAULT_CONTROL;
+ reg |= MV_TDMA_CONTROL_ENABLE;
+ MVXPSEC_WRITE(sc, MV_TDMA_CONTROL, reg);
+
+ if (mvxpsec_acc_wait(sc) < 0)
+ panic("%s: failed to reset MVXPSEC. give up.", __func__);
+ reg = MV_ACC_CONFIG_MULT_PKT;
+ reg |= MV_ACC_CONFIG_WAIT_TDMA;
+ reg |= MV_ACC_CONFIG_ACT_TDMA;
+ MVXPSEC_WRITE(sc, MV_ACC_CONFIG, reg);
+ MVXPSEC_WRITE(sc, MV_ACC_DESC, 0);
+
+ if (refill) {
+ mutex_enter(&sc->sc_queue_mtx);
+ mvxpsec_dispatch_queue(sc);
+ mutex_exit(&sc->sc_queue_mtx);
+ }
+
+ crypto_unblock(sc->sc_cid, CRYPTO_SYMQ|CRYPTO_ASYMQ);
+ splx(s);
+}
+
+/*
+ * DMA handling
+ */
+
+/*
+ * Allocate kernel devmem and DMA safe memory with bus_dma API
+ * used for DMA descriptors.
+ *
+ * if phys != 0, assume phys is a DMA safe memory and bypass
+ * allocator.
+ */
+STATIC struct mvxpsec_devmem *
+mvxpsec_alloc_devmem(struct mvxpsec_softc *sc, paddr_t phys, int size)
+{
+ struct mvxpsec_devmem *devmem;
+ bus_dma_segment_t seg;
+ int rseg;
+ int err;
+
+ if (sc == NULL)
+ return NULL;
+
+ devmem = kmem_alloc(sizeof(*devmem), KM_NOSLEEP);
+ if (devmem == NULL) {
+ aprint_error_dev(sc->sc_dev, "can't alloc kmem\n");
+ return NULL;
+ }
+
+ devmem->size = size;
+
+ if (phys) {
+ seg.ds_addr = phys;
+ seg.ds_len = devmem->size;
+ rseg = 1;
+ err = 0;
+ }
+ else {
+ err = bus_dmamem_alloc(sc->sc_dmat,
+ devmem->size, PAGE_SIZE, 0,
+ &seg, MVXPSEC_DMA_MAX_SEGS, &rseg, BUS_DMA_NOWAIT);
+ }
+ if (err) {
+ aprint_error_dev(sc->sc_dev, "can't alloc DMA buffer\n");
+ goto fail_kmem_free;
+ }
+
+ err = bus_dmamem_map(sc->sc_dmat, &seg, rseg,
+ devmem->size, &devmem->kva, BUS_DMA_NOWAIT);
+ if (err) {
+ aprint_error_dev(sc->sc_dev, "can't map DMA buffer\n");
+ goto fail_dmamem_free;
+ }
+
+ err = bus_dmamap_create(sc->sc_dmat,
+ size, 1, size, 0, BUS_DMA_NOWAIT, &devmem->map);
+ if (err) {
+ aprint_error_dev(sc->sc_dev, "can't create DMA map\n");
+ goto fail_unmap;
+ }
+
+ err = bus_dmamap_load(sc->sc_dmat,
+ devmem->map, devmem->kva, devmem->size, NULL,
+ BUS_DMA_NOWAIT);
+ if (err) {
+ aprint_error_dev(sc->sc_dev,
+ "can't load DMA buffer VA:%p PA:0x%08x\n",
+ devmem->kva, (int)seg.ds_addr);
+ goto fail_destroy;
+ }
+
+ return devmem;
+
+fail_destroy:
+ bus_dmamap_destroy(sc->sc_dmat, devmem->map);
+fail_unmap:
+ bus_dmamem_unmap(sc->sc_dmat, devmem->kva, devmem->size);
+fail_dmamem_free:
+ bus_dmamem_free(sc->sc_dmat, &seg, rseg);
+fail_kmem_free:
+ kmem_free(devmem, sizeof(*devmem));
+
+ return NULL;
+}
+
+/*
+ * Get DMA Descriptor from (DMA safe) descriptor pool.
+ */
+INLINE struct mvxpsec_descriptor_handle *
+mvxpsec_dma_getdesc(struct mvxpsec_softc *sc)
+{
+ struct mvxpsec_descriptor_handle *entry;
+
+ /* must called with sc->sc_dma_mtx held */
+ KASSERT(mutex_owned(&sc->sc_dma_mtx));
+
+ if (sc->sc_desc_ring_prod == sc->sc_desc_ring_cons)
+ return NULL;
+
+ entry = &sc->sc_desc_ring[sc->sc_desc_ring_prod];
+ sc->sc_desc_ring_prod++;
+ if (sc->sc_desc_ring_prod >= sc->sc_desc_ring_size)
+ sc->sc_desc_ring_prod -= sc->sc_desc_ring_size;
+
+ return entry;
+}
+
+/*
+ * Put DMA Descriptor to descriptor pool.
+ */
+_INLINE void
+mvxpsec_dma_putdesc(struct mvxpsec_softc *sc,
+ struct mvxpsec_descriptor_handle *dh)
+{
+ /* must called with sc->sc_dma_mtx held */
+ KASSERT(mutex_owned(&sc->sc_dma_mtx));
+
+ sc->sc_desc_ring_cons++;
+ if (sc->sc_desc_ring_cons >= sc->sc_desc_ring_size)
+ sc->sc_desc_ring_cons -= sc->sc_desc_ring_size;
+
+ return;
+}
+
+/*
+ * Setup DMA Descriptor
+ * copy from 'src' to 'dst' by 'size' bytes.
+ * 'src' or 'dst' must be SRAM address.
+ */
+INLINE void
+mvxpsec_dma_setup(struct mvxpsec_descriptor_handle *dh,
+ uint32_t dst, uint32_t src, uint32_t size)
+{
+ struct mvxpsec_descriptor *desc;
+
+ desc = (struct mvxpsec_descriptor *)dh->_desc;
+
+ desc->tdma_dst = dst;
+ desc->tdma_src = src;
+ desc->tdma_word0 = size;
+ if (size != 0)
+ desc->tdma_word0 |= MV_TDMA_CNT_OWN;
+ /* size == 0 is owned by ACC, not TDMA */
+
+#ifdef MVXPSEC_DEBUG
+ mvxpsec_dump_dmaq(dh);
+#endif
+
+}
+
+/*
+ * Concat 2 DMA
+ */
+INLINE void
+mvxpsec_dma_cat(struct mvxpsec_softc *sc,
+ struct mvxpsec_descriptor_handle *dh1,
+ struct mvxpsec_descriptor_handle *dh2)
+{
+ ((struct mvxpsec_descriptor*)dh1->_desc)->tdma_nxt = dh2->phys_addr;
+ MVXPSEC_SYNC_DESC(sc, dh1, BUS_DMASYNC_PREWRITE);
+}
+
+/*
+ * Schedule DMA Copy
+ */
+INLINE int
+mvxpsec_dma_copy0(struct mvxpsec_softc *sc, mvxpsec_dma_ring *r,
+ uint32_t dst, uint32_t src, uint32_t size)
+{
+ struct mvxpsec_descriptor_handle *dh;
+
+ dh = mvxpsec_dma_getdesc(sc);
+ if (dh == NULL) {
+ log(LOG_ERR, "%s: descriptor full\n", __func__);
+ return -1;
+ }
+
+ mvxpsec_dma_setup(dh, dst, src, size);
+ if (r->dma_head == NULL) {
+ r->dma_head = dh;
+ r->dma_last = dh;
+ r->dma_size = 1;
+ }
+ else {
+ mvxpsec_dma_cat(sc, r->dma_last, dh);
+ r->dma_last = dh;
+ r->dma_size++;
+ }
+
+ return 0;
+}
+
+INLINE int
+mvxpsec_dma_copy(struct mvxpsec_softc *sc, mvxpsec_dma_ring *r,
+ uint32_t dst, uint32_t src, uint32_t size)
+{
+ if (size == 0) /* 0 is very special descriptor */
+ return 0;
+
+ return mvxpsec_dma_copy0(sc, r, dst, src, size);
+}
+
+/*
+ * Schedule ACC Activate
+ */
+INLINE int
+mvxpsec_dma_acc_activate(struct mvxpsec_softc *sc, mvxpsec_dma_ring *r)
+{
+ return mvxpsec_dma_copy0(sc, r, 0, 0, 0);
+}
+
+/*
+ * Finalize DMA setup
+ */
+INLINE void
+mvxpsec_dma_finalize(struct mvxpsec_softc *sc, mvxpsec_dma_ring *r)
+{
+ struct mvxpsec_descriptor_handle *dh;
+
+ dh = r->dma_last;
+ ((struct mvxpsec_descriptor*)dh->_desc)->tdma_nxt = 0;
+ MVXPSEC_SYNC_DESC(sc, dh, BUS_DMASYNC_PREWRITE);
+}
+
+/*
+ * Free entire DMA ring
+ */
+INLINE void
+mvxpsec_dma_free(struct mvxpsec_softc *sc, mvxpsec_dma_ring *r)
+{
+ sc->sc_desc_ring_cons += r->dma_size;
+ if (sc->sc_desc_ring_cons >= sc->sc_desc_ring_size)
+ sc->sc_desc_ring_cons -= sc->sc_desc_ring_size;
+ r->dma_head = NULL;
+ r->dma_last = NULL;
+ r->dma_size = 0;
+}
+
+/*
+ * create DMA descriptor chain for the packet
+ */
+INLINE int
+mvxpsec_dma_copy_packet(struct mvxpsec_softc *sc, struct mvxpsec_packet *mv_p)
+{
+ struct mvxpsec_session *mv_s = mv_p->mv_s;
+ uint32_t src, dst, len;
+ uint32_t pkt_off, pkt_off_r;
+ int err;
+ int i;
+
+ /* must called with sc->sc_dma_mtx held */
+ KASSERT(mutex_owned(&sc->sc_dma_mtx));
+
+ /*
+ * set offset for mem->device copy
+ *
+ * typical packet image:
+ *
+ * enc_ivoff
+ * mac_off
+ * |
+ * | enc_off
+ * | |
+ * v v
+ * +----+--------...
+ * |IV |DATA
+ * +----+--------...
+ */
+ pkt_off = 0;
+ if (mv_p->mac_off > 0)
+ pkt_off = mv_p->mac_off;
+ if ((mv_p->flags & CRP_EXT_IV) == 0 && pkt_off > mv_p->enc_ivoff)
+ pkt_off = mv_p->enc_ivoff;
+ if (mv_p->enc_off > 0 && pkt_off > mv_p->enc_off)
+ pkt_off = mv_p->enc_off;
+ pkt_off_r = pkt_off;
+
+ /* make DMA descriptors to copy packet header: DRAM -> SRAM */
+ dst = (uint32_t)MVXPSEC_SRAM_PKT_HDR_PA(sc);
+ src = (uint32_t)mv_p->pkt_header_map->dm_segs[0].ds_addr;
+ len = sizeof(mv_p->pkt_header);
+ err = mvxpsec_dma_copy(sc, &mv_p->dma_ring, dst, src, len);
+ if (__predict_false(err))
+ return err;
+
+ /*
+ * make DMA descriptors to copy session header: DRAM -> SRAM
+ * we can reuse session header on SRAM if session is not changed.
+ */
+ if (sc->sc_last_session != mv_s) {
+ dst = (uint32_t)MVXPSEC_SRAM_SESS_HDR_PA(sc);
+ src = (uint32_t)mv_s->session_header_map->dm_segs[0].ds_addr;
+ len = sizeof(mv_s->session_header);
+ err = mvxpsec_dma_copy(sc, &mv_p->dma_ring, dst, src, len);
+ if (__predict_false(err))
+ return err;
+ sc->sc_last_session = mv_s;
+ }
+
+ /* make DMA descriptor to copy payload data: DRAM -> SRAM */
+ dst = MVXPSEC_SRAM_PAYLOAD_PA(sc, 0);
+ for (i = 0; i < mv_p->data_map->dm_nsegs; i++) {
+ src = mv_p->data_map->dm_segs[i].ds_addr;
+ len = mv_p->data_map->dm_segs[i].ds_len;
+ if (pkt_off) {
+ if (len <= pkt_off) {
+ /* ignore the segment */
+ dst += len;
+ pkt_off -= len;
+ continue;
+ }
+ /* copy from the middle of the segment */
+ dst += pkt_off;
+ src += pkt_off;
+ len -= pkt_off;
+ pkt_off = 0;
+ }
+ err = mvxpsec_dma_copy(sc, &mv_p->dma_ring, dst, src, len);
+ if (__predict_false(err))
+ return err;
+ dst += len;
+ }
+
+ /* make special descriptor to activate security accelerator */
+ err = mvxpsec_dma_acc_activate(sc, &mv_p->dma_ring);
+ if (__predict_false(err))
+ return err;
+
+ /* make DMA descriptors to copy payload: SRAM -> DRAM */
+ src = (uint32_t)MVXPSEC_SRAM_PAYLOAD_PA(sc, 0);
+ for (i = 0; i < mv_p->data_map->dm_nsegs; i++) {
+ dst = (uint32_t)mv_p->data_map->dm_segs[i].ds_addr;
+ len = (uint32_t)mv_p->data_map->dm_segs[i].ds_len;
+ if (pkt_off_r) {
+ if (len <= pkt_off_r) {
+ /* ignore the segment */
+ src += len;
+ pkt_off_r -= len;
+ continue;
+ }
+ /* copy from the middle of the segment */
+ src += pkt_off_r;
+ dst += pkt_off_r;
+ len -= pkt_off_r;
+ pkt_off_r = 0;
+ }
+ err = mvxpsec_dma_copy(sc, &mv_p->dma_ring, dst, src, len);
+ if (__predict_false(err))
+ return err;
+ src += len;
+ }
+ KASSERT(pkt_off == 0);
+ KASSERT(pkt_off_r == 0);
+
+ /*
+ * make DMA descriptors to copy packet header: SRAM->DRAM
+ * if IV is present in the payload, no need to copy.
+ */
+ if (mv_p->flags & CRP_EXT_IV) {
+ dst = (uint32_t)mv_p->pkt_header_map->dm_segs[0].ds_addr;
+ src = (uint32_t)MVXPSEC_SRAM_PKT_HDR_PA(sc);
+ len = sizeof(mv_p->pkt_header);
+ err = mvxpsec_dma_copy(sc, &mv_p->dma_ring, dst, src, len);
+ if (__predict_false(err))
+ return err;
+ }
+
+ return 0;
+}
+
+INLINE int
+mvxpsec_dma_sync_packet(struct mvxpsec_softc *sc, struct mvxpsec_packet *mv_p)
+{
+ /* sync packet header */
+ bus_dmamap_sync(sc->sc_dmat,
+ mv_p->pkt_header_map, 0, sizeof(mv_p->pkt_header),
+ BUS_DMASYNC_PREWRITE);
+
+#ifdef MVXPSEC_DEBUG
+ /* sync session header */
+ if (mvxpsec_debug != 0) {
+ struct mvxpsec_session *mv_s = mv_p->mv_s;
+
+ /* only debug code touch the session header after newsession */
+ bus_dmamap_sync(sc->sc_dmat,
+ mv_s->session_header_map,
+ 0, sizeof(mv_s->session_header),
+ BUS_DMASYNC_PREWRITE);
+ }
+#endif
+
+ /* sync packet buffer */
+ bus_dmamap_sync(sc->sc_dmat,
+ mv_p->data_map, 0, mv_p->data_len,
+ BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
+
+ return 0;
+}
+
+/*
+ * Initialize MVXPSEC Internal SRAM
+ *
+ * - must be called after DMA initizlization.
+ * - make VM mapping for SRAM area on MBus.
+ */
+STATIC int
+mvxpsec_init_sram(struct mvxpsec_softc *sc)
+{
+ uint32_t tag, target, attr, base, size;
+ vaddr_t va;
+ int window;
+
+ switch (sc->sc_dev->dv_unit) {
+ case 0:
+ tag = ARMADAXP_TAG_CRYPT0;
+ break;
+ case 1:
+ tag = ARMADAXP_TAG_CRYPT1;
+ break;
+ default:
+ aprint_error_dev(sc->sc_dev, "no internal SRAM mapping\n");
+ return -1;
+ }
+
+ window = mvsoc_target(tag, &target, &attr, &base, &size);
+ if (window >= nwindow) {
+ aprint_error_dev(sc->sc_dev, "no internal SRAM mapping\n");
+ return -1;
+ }
+
+ if (sizeof(struct mvxpsec_crypt_sram) > size) {
+ aprint_error_dev(sc->sc_dev,
+ "SRAM Data Structure Excceeds SRAM window size.\n");
+ return -1;
+ }
+
+ aprint_normal_dev(sc->sc_dev,
+ "internal SRAM window at 0x%08x-0x%08x",
+ base, base + size - 1);
+ sc->sc_sram_pa = base;
+
+ /* get vmspace to read/write device internal SRAM */
+ va = uvm_km_alloc(kernel_map, PAGE_SIZE, PAGE_SIZE,
+ UVM_KMF_VAONLY | UVM_KMF_NOWAIT);
+ if (va == 0) {
+ aprint_error_dev(sc->sc_dev, "cannot map SRAM window\n");
+ sc->sc_sram_va = NULL;
+ aprint_normal("\n");
+ return 0;
+ }
+ /* XXX: not working. PMAP_NOCACHE is not affected? */
+ pmap_kenter_pa(va, base, VM_PROT_READ|VM_PROT_WRITE, PMAP_NOCACHE);
+ pmap_update(pmap_kernel());
+ sc->sc_sram_va = (void *)va;
+ aprint_normal(" va %p\n", sc->sc_sram_va);
+ memset(sc->sc_sram_va, 0xff, MV_ACC_SRAM_SIZE);
+
+ return 0;
+}
+
+/*
+ * Initialize TDMA engine.
+ */
+STATIC int
+mvxpsec_init_dma(struct mvxpsec_softc *sc, struct marvell_attach_args *mva)
+{
+ struct mvxpsec_descriptor_handle *dh;
+ uint8_t *va;
+ paddr_t pa;
+ off_t va_off, pa_off;
+ int i, n, seg, ndh;
+
+ /* Init Deviced's control parameters (disabled yet) */
+ MVXPSEC_WRITE(sc, MV_TDMA_CONTROL, MV_TDMA_DEFAULT_CONTROL);
+
+ /* Init Software DMA Handlers */
+ sc->sc_devmem_desc =
+ mvxpsec_alloc_devmem(sc, 0, PAGE_SIZE * MVXPSEC_DMA_DESC_PAGES);
+ if (sc->sc_devmem_desc == NULL)
+ panic("Cannot allocate memory\n");
+ ndh = (PAGE_SIZE / sizeof(struct mvxpsec_descriptor))
+ * MVXPSEC_DMA_DESC_PAGES;
+ sc->sc_desc_ring =
+ kmem_alloc(sizeof(struct mvxpsec_descriptor_handle) * ndh,
+ KM_NOSLEEP);
+ if (sc->sc_desc_ring == NULL)
+ panic("Cannot allocate memory\n");
+ aprint_normal_dev(sc->sc_dev, "%d DMA handles in %zu bytes array\n",
+ ndh, sizeof(struct mvxpsec_descriptor_handle) * ndh);
+
+ ndh = 0;
+ for (seg = 0; seg < devmem_nseg(sc->sc_devmem_desc); seg++) {
+ va = devmem_va(sc->sc_devmem_desc);
+ pa = devmem_pa(sc->sc_devmem_desc, seg);
+ n = devmem_palen(sc->sc_devmem_desc, seg) /
+ sizeof(struct mvxpsec_descriptor);
+ va_off = (PAGE_SIZE * seg);
+ pa_off = 0;
+ for (i = 0; i < n; i++) {
+ dh = &sc->sc_desc_ring[ndh];
+ dh->map = devmem_map(sc->sc_devmem_desc);
+ dh->off = va_off + pa_off;
+ dh->_desc = (void *)(va + va_off + pa_off);
+ dh->phys_addr = pa + pa_off;
+ pa_off += sizeof(struct mvxpsec_descriptor);
+ ndh++;
+ }
+ }
+ sc->sc_desc_ring_size = ndh;
+ sc->sc_desc_ring_prod = 0;
+ sc->sc_desc_ring_cons = sc->sc_desc_ring_size - 1;
+
+ return 0;
+}
+
+/*
+ * Wait for TDMA controller become idle
+ */
+INLINE int
+mvxpsec_dma_wait(struct mvxpsec_softc *sc)
+{
+ int retry = 0;
+
+ while (MVXPSEC_READ(sc, MV_TDMA_CONTROL) & MV_TDMA_CONTROL_ACT) {
+ delay(mvxpsec_wait_interval);
+ if (retry++ >= mvxpsec_wait_retry)
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * Wait for Security Accelerator become idle
+ */
+INLINE int
+mvxpsec_acc_wait(struct mvxpsec_softc *sc)
+{
+ int retry = 0;
+
+ while (MVXPSEC_READ(sc, MV_ACC_COMMAND) & MV_ACC_COMMAND_ACT) {
+ delay(mvxpsec_wait_interval);
+ if (++retry >= mvxpsec_wait_retry)
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * Entry of interrupt handler
+ *
+ * register this to kernel via marvell_intr_establish()
+ */
+int
+mvxpsec_intr(void *arg)
+{
+ struct mvxpsec_softc *sc = arg;
+ uint32_t v;
+
+ /* IPL_NET */
+ while ((v = mvxpsec_intr_ack(sc)) != 0) {
+ mvxpsec_intr_cnt(sc, v);
+ MVXPSEC_PRINTF(MVXPSEC_DEBUG_INTR, "MVXPSEC Intr 0x%08x\n", v);
+ MVXPSEC_PRINTF(MVXPSEC_DEBUG_INTR, "%s\n", s_xpsecintr(v));
+#ifdef MVXPSEC_DEBUG
+ mvxpsec_dump_reg(sc);
+#endif
+
+ /* call high-level handlers */
+ if (v & MVXPSEC_INT_ACCTDMA)
+ mvxpsec_done(sc);
+ }
+
+ return 0;
+}
+
+INLINE void
+mvxpsec_intr_cleanup(struct mvxpsec_softc *sc)
+{
+ struct mvxpsec_packet *mv_p;
+
+ /* must called with sc->sc_dma_mtx held */
+ KASSERT(mutex_owned(&sc->sc_dma_mtx));
+
+ /*
+ * there is only one intr for run_queue.
+ * no one touch sc_run_queue.
+ */
+ SIMPLEQ_FOREACH(mv_p, &sc->sc_run_queue, queue)
+ mvxpsec_dma_free(sc, &mv_p->dma_ring);
+}
+
+/*
+ * Acknowledge to interrupt
+ *
+ * read cause bits, clear it, and return it.
+ * NOTE: multiple cause bits may be returned at once.
+ */
+STATIC uint32_t
+mvxpsec_intr_ack(struct mvxpsec_softc *sc)
+{
+ uint32_t reg;
+
+ reg = MVXPSEC_READ(sc, MVXPSEC_INT_CAUSE);
+ reg &= MVXPSEC_DEFAULT_INT;
+ MVXPSEC_WRITE(sc, MVXPSEC_INT_CAUSE, ~reg);
+ MVXPSEC_PRINTF(MVXPSEC_DEBUG_INTR, "Int: %s\n", s_xpsecintr(reg));
+
+ return reg;
+}
+
+/*
+ * Entry of TDMA error interrupt handler
+ *
+ * register this to kernel via marvell_intr_establish()
+ */
+int
+mvxpsec_eintr(void *arg)
+{
+ struct mvxpsec_softc *sc = arg;
+ uint32_t err;
+
+ /* IPL_NET */
+again:
+ err = mvxpsec_eintr_ack(sc);
+ if (err == 0)
+ goto done;
+
+ log(LOG_ERR, "%s: DMA Error Interrupt: %s\n", __func__,
+ s_errreg(err));
+#ifdef MVXPSEC_DEBUG
+ mvxpsec_dump_reg(sc);
+#endif
+
+ goto again;
+done:
+ return 0;
+}
+
+/*
+ * Acknowledge to TDMA error interrupt
+ *
+ * read cause bits, clear it, and return it.
+ * NOTE: multiple cause bits may be returned at once.
+ */
+STATIC uint32_t
+mvxpsec_eintr_ack(struct mvxpsec_softc *sc)
+{
+ uint32_t reg;
+
+ reg = MVXPSEC_READ(sc, MV_TDMA_ERR_CAUSE);
+ reg &= MVXPSEC_DEFAULT_ERR;
+ MVXPSEC_WRITE(sc, MV_TDMA_ERR_CAUSE, ~reg);
+ MVXPSEC_PRINTF(MVXPSEC_DEBUG_INTR, "Int: %s\n", s_xpsecintr(reg));
+
+ return reg;
+}
+
+/*
+ * Interrupt statistics
+ *
+ * this is NOT a statistics of how may times the events 'occured'.
+ * this ONLY means how many times the events 'handled'.
+ */
+INLINE void
+mvxpsec_intr_cnt(struct mvxpsec_softc *sc, int cause)
+{
+ MVXPSEC_EVCNT_INCR(sc, intr_all);
+ if (cause & MVXPSEC_INT_AUTH)
+ MVXPSEC_EVCNT_INCR(sc, intr_auth);
+ if (cause & MVXPSEC_INT_DES)
+ MVXPSEC_EVCNT_INCR(sc, intr_des);
+ if (cause & MVXPSEC_INT_AES_ENC)
+ MVXPSEC_EVCNT_INCR(sc, intr_aes_enc);
+ if (cause & MVXPSEC_INT_AES_DEC)
+ MVXPSEC_EVCNT_INCR(sc, intr_aes_dec);
+ if (cause & MVXPSEC_INT_ENC)
+ MVXPSEC_EVCNT_INCR(sc, intr_enc);
+ if (cause & MVXPSEC_INT_SA)
+ MVXPSEC_EVCNT_INCR(sc, intr_sa);
+ if (cause & MVXPSEC_INT_ACCTDMA)
+ MVXPSEC_EVCNT_INCR(sc, intr_acctdma);
+ if (cause & MVXPSEC_INT_TDMA_COMP)
+ MVXPSEC_EVCNT_INCR(sc, intr_comp);
+ if (cause & MVXPSEC_INT_TDMA_OWN)
+ MVXPSEC_EVCNT_INCR(sc, intr_own);
+ if (cause & MVXPSEC_INT_ACCTDMA_CONT)
+ MVXPSEC_EVCNT_INCR(sc, intr_acctdma_cont);
+}
+
+/*
+ * Setup MVXPSEC header structure.
+ *
+ * the header contains descriptor of security accelerator,
+ * key material of chiphers, iv of ciphers and macs, ...
+ *
+ * the header is transfered to MVXPSEC Internal SRAM by TDMA,
+ * and parsed by MVXPSEC H/W.
+ */
+STATIC int
+mvxpsec_header_finalize(struct mvxpsec_packet *mv_p)
+{
+ struct mvxpsec_acc_descriptor *desc = &mv_p->pkt_header.desc;
+ int enc_start, enc_len, iv_offset;
+ int mac_start, mac_len, mac_offset;
+
+ /* offset -> device address */
+ enc_start = MVXPSEC_SRAM_PAYLOAD_DA(mv_p->enc_off);
+ enc_len = mv_p->enc_len;
+ if (mv_p->flags & CRP_EXT_IV)
+ iv_offset = mv_p->enc_ivoff;
+ else
+ iv_offset = MVXPSEC_SRAM_PAYLOAD_DA(mv_p->enc_ivoff);
+ mac_start = MVXPSEC_SRAM_PAYLOAD_DA(mv_p->mac_off);
+ mac_len = mv_p->mac_len;
+ mac_offset = MVXPSEC_SRAM_PAYLOAD_DA(mv_p->mac_dst);
+
+ MVXPSEC_PRINTF(MVXPSEC_DEBUG_OPENCRYPTO,
+ "PAYLOAD at 0x%08x\n", (int)MVXPSEC_SRAM_PAYLOAD_OFF);
+ MVXPSEC_PRINTF(MVXPSEC_DEBUG_OPENCRYPTO,
+ "ENC from 0x%08x\n", enc_start);
+ MVXPSEC_PRINTF(MVXPSEC_DEBUG_OPENCRYPTO,
+ "MAC from 0x%08x\n", mac_start);
+ MVXPSEC_PRINTF(MVXPSEC_DEBUG_OPENCRYPTO,
+ "MAC to 0x%08x\n", mac_offset);
+ MVXPSEC_PRINTF(MVXPSEC_DEBUG_OPENCRYPTO,
+ "ENC IV at 0x%08x\n", iv_offset);
+
+ /* setup device addresses in Security Accelerator Descriptors */
+ desc->acc_encdata = MV_ACC_DESC_ENC_DATA(enc_start, enc_start);
+ desc->acc_enclen = MV_ACC_DESC_ENC_LEN(enc_len);
+ if (desc->acc_config & MV_ACC_CRYPTO_DECRYPT)
+ desc->acc_enckey =
+ MV_ACC_DESC_ENC_KEY(MVXPSEC_SRAM_KEY_D_DA);
+ else
+ desc->acc_enckey =
+ MV_ACC_DESC_ENC_KEY(MVXPSEC_SRAM_KEY_DA);
+ desc->acc_enciv =
+ MV_ACC_DESC_ENC_IV(MVXPSEC_SRAM_IV_WORK_DA, iv_offset);
+
+ desc->acc_macsrc = MV_ACC_DESC_MAC_SRC(mac_start, mac_len);
+ desc->acc_macdst = MV_ACC_DESC_MAC_DST(mac_offset, mac_len);
+ desc->acc_maciv =
+ MV_ACC_DESC_MAC_IV(MVXPSEC_SRAM_MIV_IN_DA,
+ MVXPSEC_SRAM_MIV_OUT_DA);
+
+ return 0;
+}
+
+/*
+ * constractor of session structure.
+ *
+ * this constrator will be called by pool_cache framework.
+ */
+STATIC int
+mvxpsec_session_ctor(void *arg, void *obj, int flags)
+{
+ struct mvxpsec_softc *sc = arg;
+ struct mvxpsec_session *mv_s = obj;
+
+ /* pool is owned by softc */
+ mv_s->sc = sc;
+
+ /* Create and load DMA map for session header */
+ mv_s->session_header_map = 0;
+ if (bus_dmamap_create(sc->sc_dmat,
+ sizeof(mv_s->session_header), 1,
+ sizeof(mv_s->session_header), 0,
+ BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
+ &mv_s->session_header_map)) {
+ log(LOG_ERR, "%s: cannot create DMA map\n", __func__);
+ goto fail;
+ }
+ if (bus_dmamap_load(sc->sc_dmat, mv_s->session_header_map,
+ &mv_s->session_header, sizeof(mv_s->session_header),
+ NULL, BUS_DMA_NOWAIT)) {
+ log(LOG_ERR, "%s: cannot load header\n", __func__);
+ goto fail;
+ }
+
+ return 0;
+fail:
+ if (mv_s->session_header_map)
+ bus_dmamap_destroy(sc->sc_dmat, mv_s->session_header_map);
+ return ENOMEM;
+}
+
+/*
+ * destractor of session structure.
+ *
+ * this destrator will be called by pool_cache framework.
+ */
+STATIC void
+mvxpsec_session_dtor(void *arg, void *obj)
+{
+ struct mvxpsec_softc *sc = arg;
+ struct mvxpsec_session *mv_s = obj;
+
+ if (mv_s->sc != sc)
+ panic("inconsitent context\n");
+
+ bus_dmamap_destroy(sc->sc_dmat, mv_s->session_header_map);
+}
+
+/*
+ * constructor of packet structure.
+ */
+STATIC int
+mvxpsec_packet_ctor(void *arg, void *obj, int flags)
+{
+ struct mvxpsec_softc *sc = arg;
+ struct mvxpsec_packet *mv_p = obj;
+
+ mv_p->dma_ring.dma_head = NULL;
+ mv_p->dma_ring.dma_last = NULL;
+ mv_p->dma_ring.dma_size = 0;
+
+ /* Create and load DMA map for packet header */
+ mv_p->pkt_header_map = 0;
+ if (bus_dmamap_create(sc->sc_dmat,
+ sizeof(mv_p->pkt_header), 1, sizeof(mv_p->pkt_header), 0,
+ BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
+ &mv_p->pkt_header_map)) {
+ log(LOG_ERR, "%s: cannot create DMA map\n", __func__);
+ goto fail;
+ }
+ if (bus_dmamap_load(sc->sc_dmat, mv_p->pkt_header_map,
+ &mv_p->pkt_header, sizeof(mv_p->pkt_header),
+ NULL, BUS_DMA_NOWAIT)) {
+ log(LOG_ERR, "%s: cannot load header\n", __func__);
+ goto fail;
+ }
+
+ /* Create DMA map for session data. */
+ mv_p->data_map = 0;
+ if (bus_dmamap_create(sc->sc_dmat,
+ MVXPSEC_DMA_MAX_SIZE, MVXPSEC_DMA_MAX_SEGS, MVXPSEC_DMA_MAX_SIZE,
+ 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &mv_p->data_map)) {
+ log(LOG_ERR, "%s: cannot create DMA map\n", __func__);
+ goto fail;
+ }
+
+ return 0;
+fail:
+ if (mv_p->pkt_header_map)
+ bus_dmamap_destroy(sc->sc_dmat, mv_p->pkt_header_map);
+ if (mv_p->data_map)
+ bus_dmamap_destroy(sc->sc_dmat, mv_p->data_map);
+ return ENOMEM;
+}
+
+/*
+ * destractor of packet structure.
+ */
+STATIC void
+mvxpsec_packet_dtor(void *arg, void *obj)
+{
+ struct mvxpsec_softc *sc = arg;
+ struct mvxpsec_packet *mv_p = obj;
+
+ mutex_enter(&sc->sc_dma_mtx);
+ mvxpsec_dma_free(sc, &mv_p->dma_ring);
+ mutex_exit(&sc->sc_dma_mtx);
+ bus_dmamap_destroy(sc->sc_dmat, mv_p->pkt_header_map);
+ bus_dmamap_destroy(sc->sc_dmat, mv_p->data_map);
+}
+
+/*
+ * allocate new session struture.
+ */
+STATIC struct mvxpsec_session *
+mvxpsec_session_alloc(struct mvxpsec_softc *sc)
+{
+ struct mvxpsec_session *mv_s;
+
+ mv_s = pool_cache_get(sc->sc_session_pool, 0);
+ if (mv_s == NULL) {
+ log(LOG_ERR, "%s: cannot allocate memory\n", __func__);
+ return NULL;
+ }
+ mv_s->refs = 1; /* 0 means session is alredy invalid */
+ mv_s->sflags = 0;
+
+ return mv_s;
+}
+
+/*
+ * deallocate session structure.
+ */
+STATIC void
+mvxpsec_session_dealloc(struct mvxpsec_session *mv_s)
+{
+ struct mvxpsec_softc *sc = mv_s->sc;
+
+ mv_s->sflags |= DELETED;
+ mvxpsec_session_unref(mv_s);
+ crypto_unblock(sc->sc_cid, CRYPTO_SYMQ|CRYPTO_ASYMQ);
+
+ return;
+}
+
+STATIC int
+mvxpsec_session_ref(struct mvxpsec_session *mv_s)
+{
+ uint32_t refs;
+
+ if (mv_s->sflags & DELETED) {
+ log(LOG_ERR,
+ "%s: session is already deleted.\n", __func__);
+ return -1;
+ }
+
+ refs = atomic_inc_32_nv(&mv_s->refs);
+ if (refs == 1) {
+ /*
+ * a session with refs == 0 is
+ * already invalidated. revert it.
+ * XXX: use CAS ?
+ */
+ atomic_dec_32(&mv_s->refs);
+ log(LOG_ERR,
+ "%s: session is already invalidated.\n", __func__);
+ return -1;
+ }
+
+ return 0;
+}
+
+STATIC void
+mvxpsec_session_unref(struct mvxpsec_session *mv_s)
+{
+ uint32_t refs;
+
+ refs = atomic_dec_32_nv(&mv_s->refs);
+ if (refs == 0)
+ pool_cache_put(mv_s->sc->sc_session_pool, mv_s);
+}
+
+/*
+ * look for session is exist or not
+ */
+INLINE struct mvxpsec_session *
+mvxpsec_session_lookup(struct mvxpsec_softc *sc, int sid)
+{
+ struct mvxpsec_session *mv_s;
+ int session;
+
+ /* must called sc->sc_session_mtx held */
+ KASSERT(mutex_owned(&sc->sc_session_mtx));
+
+ session = MVXPSEC_SESSION(sid);
+ if (__predict_false(session > MVXPSEC_MAX_SESSIONS)) {
+ log(LOG_ERR, "%s: session number too large %d\n",
+ __func__, session);
+ return NULL;
+ }
+ if (__predict_false( (mv_s = sc->sc_sessions[session]) == NULL)) {
+ log(LOG_ERR, "%s: invalid session %d\n",
+ __func__, session);
+ return NULL;
+ }
+
+ KASSERT(mv_s->sid == session);
+
+ return mv_s;
+}
+
+/*
+ * allocation new packet structure.
+ */
+STATIC struct mvxpsec_packet *
+mvxpsec_packet_alloc(struct mvxpsec_session *mv_s)
+{
+ struct mvxpsec_softc *sc = mv_s->sc;
+ struct mvxpsec_packet *mv_p;
+
+ /* must be called mv_queue_mtx held. */
+ KASSERT(mutex_owned(&sc->sc_queue_mtx));
+ /* must be called mv_session_mtx held. */
+ KASSERT(mutex_owned(&sc->sc_session_mtx));
+
+ if (mvxpsec_session_ref(mv_s) < 0) {
+ log(LOG_ERR, "%s: invalid session.\n", __func__);
+ return NULL;
+ }
+
+ if ( (mv_p = SLIST_FIRST(&sc->sc_free_list)) != NULL) {
+ SLIST_REMOVE_HEAD(&sc->sc_free_list, free_list);
+ sc->sc_free_qlen--;
+ }
+ else {
+ mv_p = pool_cache_get(sc->sc_packet_pool, 0);
+ if (mv_p == NULL) {
+ log(LOG_ERR, "%s: cannot allocate memory\n",
+ __func__);
+ mvxpsec_session_unref(mv_s);
+ return NULL;
+ }
+ }
+ mv_p->mv_s = mv_s;
+ mv_p->flags = 0;
+ mv_p->data_ptr = NULL;
+
+ return mv_p;
+}
+
+/*
+ * free packet structure.
+ */
+STATIC void
+mvxpsec_packet_dealloc(struct mvxpsec_packet *mv_p)
+{
+ struct mvxpsec_session *mv_s = mv_p->mv_s;
+ struct mvxpsec_softc *sc = mv_s->sc;
+
+ /* must called with sc->sc_queue_mtx held */
+ KASSERT(mutex_owned(&sc->sc_queue_mtx));
+
+ if (mv_p->dma_ring.dma_size != 0) {
+ sc->sc_desc_ring_cons += mv_p->dma_ring.dma_size;
+ }
+ mv_p->dma_ring.dma_head = NULL;
+ mv_p->dma_ring.dma_last = NULL;
+ mv_p->dma_ring.dma_size = 0;
+
+ if (mv_p->data_map) {
+ if (mv_p->flags & RDY_DATA) {
+ bus_dmamap_unload(sc->sc_dmat, mv_p->data_map);
+ mv_p->flags &= ~RDY_DATA;
+ }
+ }
+
+ if (sc->sc_free_qlen > sc->sc_wait_qlimit)
+ pool_cache_put(sc->sc_packet_pool, mv_p);
+ else {
+ SLIST_INSERT_HEAD(&sc->sc_free_list, mv_p, free_list);
+ sc->sc_free_qlen++;
+ }
+ mvxpsec_session_unref(mv_s);
+}
+
+INLINE void
+mvxpsec_packet_enqueue(struct mvxpsec_packet *mv_p)
+{
+ struct mvxpsec_softc *sc = mv_p->mv_s->sc;
+ struct mvxpsec_packet *last_packet;
+ struct mvxpsec_descriptor_handle *cur_dma, *prev_dma;
+
+ /* must called with sc->sc_queue_mtx held */
+ KASSERT(mutex_owned(&sc->sc_queue_mtx));
+
+ if (sc->sc_wait_qlen == 0) {
+ SIMPLEQ_INSERT_TAIL(&sc->sc_wait_queue, mv_p, queue);
+ sc->sc_wait_qlen++;
+ mv_p->flags |= SETUP_DONE;
+ return;
+ }
+
+ last_packet = SIMPLEQ_LAST(&sc->sc_wait_queue, mvxpsec_packet, queue);
+ SIMPLEQ_INSERT_TAIL(&sc->sc_wait_queue, mv_p, queue);
+ sc->sc_wait_qlen++;
+
+ /* chain the DMA */
+ cur_dma = mv_p->dma_ring.dma_head;
+ prev_dma = last_packet->dma_ring.dma_last;
+ mvxpsec_dma_cat(sc, prev_dma, cur_dma);
+ mv_p->flags |= SETUP_DONE;
+}
+
+/*
+ * called by interrupt handler
+ */
+STATIC int
+mvxpsec_done_packet(struct mvxpsec_packet *mv_p)
+{
+ struct mvxpsec_session *mv_s = mv_p->mv_s;
+ struct mvxpsec_softc *sc = mv_s->sc;
+
+ KASSERT((mv_p->flags & RDY_DATA));
+ KASSERT((mv_p->flags & SETUP_DONE));
+
+ /* unload data */
+ bus_dmamap_sync(sc->sc_dmat, mv_p->data_map,
+ 0, mv_p->data_len,
+ BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
+ bus_dmamap_unload(sc->sc_dmat, mv_p->data_map);
+ mv_p->flags &= ~RDY_DATA;
+
+#ifdef MVXPSEC_DEBUG
+ if (mvxpsec_debug != 0) {
+ int s;
+
+ bus_dmamap_sync(sc->sc_dmat, mv_p->pkt_header_map,
+ 0, sizeof(mv_p->pkt_header),
+ BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
+ bus_dmamap_sync(sc->sc_dmat, mv_s->session_header_map,
+ 0, sizeof(mv_s->session_header),
+ BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
+
+ if (mvxpsec_debug & MVXPSEC_DEBUG_OPENCRYPTO) {
+ char buf[1500];
+ struct mbuf *m;
+ struct uio *uio;
+ size_t len;
+
+ switch (mv_p->data_type) {
+ case MVXPSEC_DATA_MBUF:
+ m = mv_p->data_mbuf;
+ len = m->m_pkthdr.len;
+ if (len > sizeof(buf))
+ len = sizeof(buf);
+ m_copydata(m, 0, len, buf);
+ break;
+ case MVXPSEC_DATA_UIO:
+ uio = mv_p->data_uio;
+ len = uio->uio_resid;
+ if (len > sizeof(buf))
+ len = sizeof(buf);
+ cuio_copydata(uio, 0, len, buf);
+ break;
+ default:
+ len = 0;
+ }
+ if (len > 0)
+ mvxpsec_dump_data(__func__, buf, len);
+ }
+
+ if (mvxpsec_debug & MVXPSEC_DEBUG_PAYLOAD) {
+ MVXPSEC_PRINTF(MVXPSEC_DEBUG_PAYLOAD,
+ "%s: session_descriptor:\n", __func__);
+ mvxpsec_dump_packet_desc(__func__, mv_p);
+ MVXPSEC_PRINTF(MVXPSEC_DEBUG_PAYLOAD,
+ "%s: session_data:\n", __func__);
+ mvxpsec_dump_packet_data(__func__, mv_p);
+ }
+
+ if (mvxpsec_debug & MVXPSEC_DEBUG_SRAM) {
+ MVXPSEC_PRINTF(MVXPSEC_DEBUG_SRAM,
+ "%s: SRAM\n", __func__);
+ mvxpsec_dump_sram(__func__, sc, 2000);
+ }
+
+ s = MVXPSEC_READ(sc, MV_ACC_STATUS);
+ if (s & MV_ACC_STATUS_MAC_ERR) {
+ MVXPSEC_PRINTF(MVXPSEC_DEBUG_INTR,
+ "%s: Message Authentication Failed.\n", __func__);
+ }
+ }
+#endif
+
+ /* copy back IV */
+ if (mv_p->flags & CRP_EXT_IV) {
+ memcpy(mv_p->ext_iv,
+ &mv_p->pkt_header.crp_iv_ext, mv_p->ext_ivlen);
+ mv_p->ext_iv = NULL;
+ mv_p->ext_ivlen = 0;
+ }
+
+ /* notify opencrypto */
+ mv_p->crp->crp_etype = 0;
+ crypto_done(mv_p->crp);
+ mv_p->crp = NULL;
+
+ /* unblock driver */
+ mvxpsec_packet_dealloc(mv_p);
+ crypto_unblock(sc->sc_cid, CRYPTO_SYMQ|CRYPTO_ASYMQ);
+
+ MVXPSEC_EVCNT_INCR(sc, packet_ok);
+
+ return 0;
+}
+
+
+/*
+ * Opencrypto API registration
+ */
+int
+mvxpsec_register(struct mvxpsec_softc *sc)
+{
+ int oplen = SRAM_PAYLOAD_SIZE;
+ int flags = 0;
+ int err;
+
+ sc->sc_nsessions = 0;
+ sc->sc_cid = crypto_get_driverid(0);
+ if (sc->sc_cid < 0) {
+ log(LOG_ERR,
+ "%s: crypto_get_driverid() failed.\n", __func__);
+ err = EINVAL;
+ goto done;
+ }
+
+ /* Ciphers */
+ err = crypto_register(sc->sc_cid, CRYPTO_DES_CBC, oplen, flags,
+ mvxpsec_newsession, mvxpsec_freesession, mvxpsec_dispatch, sc);
+ if (err)
+ goto done;
+
+ err = crypto_register(sc->sc_cid, CRYPTO_3DES_CBC, oplen, flags,
+ mvxpsec_newsession, mvxpsec_freesession, mvxpsec_dispatch, sc);
+ if (err)
+ goto done;
+
+ err = crypto_register(sc->sc_cid, CRYPTO_AES_CBC, oplen, flags,
+ mvxpsec_newsession, mvxpsec_freesession, mvxpsec_dispatch, sc);
+ if (err)
+ goto done;
+
+ /* MACs */
+ err = crypto_register(sc->sc_cid, CRYPTO_SHA1_HMAC_96,
+ oplen, flags,
+ mvxpsec_newsession, mvxpsec_freesession, mvxpsec_dispatch, sc);
+ if (err)
+ goto done;
+
+ err = crypto_register(sc->sc_cid, CRYPTO_MD5_HMAC_96,
+ oplen, flags,
+ mvxpsec_newsession, mvxpsec_freesession, mvxpsec_dispatch, sc);
+ if (err)
+ goto done;
+
+#ifdef DEBUG
+ log(LOG_DEBUG,
+ "%s: registered to opencrypto(max data = %d bytes)\n",
+ device_xname(sc->sc_dev), oplen);
+#endif
+
+ err = 0;
+done:
+ return err;
+}
+
+/*
+ * Create new opencrypto session
+ *
+ * - register cipher key, mac key.
+ * - initialize mac internal state.
+ */
+int
+mvxpsec_newsession(void *arg, uint32_t *sidp, struct cryptoini *cri)
+{
+ struct mvxpsec_softc *sc = arg;
+ struct mvxpsec_session *mv_s = NULL;
+ struct cryptoini *c;
+ static int hint = 0;
+ int session = -1;
+ int sid;
+ int err;
+ int i;
+
+ /* allocate driver session context */
+ mv_s = mvxpsec_session_alloc(sc);
+ if (mv_s == NULL)
+ return ENOMEM;
+
+ /*
+ * lookup opencrypto session table
+ *
+ * we have sc_session_mtx after here.
+ */
+ mutex_enter(&sc->sc_session_mtx);
+ if (sc->sc_nsessions >= MVXPSEC_MAX_SESSIONS) {
+ mutex_exit(&sc->sc_session_mtx);
+ log(LOG_ERR, "%s: too many IPsec SA(max %d)\n",
+ __func__, MVXPSEC_MAX_SESSIONS);
+ mvxpsec_session_dealloc(mv_s);
+ return ENOMEM;
+ }
+ for (i = hint; i < MVXPSEC_MAX_SESSIONS; i++) {
+ if (sc->sc_sessions[i])
+ continue;
+ session = i;
+ hint = session + 1;
+ break;
+ }
+ if (session < 0) {
+ for (i = 0; i < hint; i++) {
+ if (sc->sc_sessions[i])
+ continue;
+ session = i;
+ hint = session + 1;
+ break;
+ }
+ if (session < 0) {
+ mutex_exit(&sc->sc_session_mtx);
+ /* session full */
+ log(LOG_ERR, "%s: too many IPsec SA(max %d)\n",
+ __func__, MVXPSEC_MAX_SESSIONS);
+ mvxpsec_session_dealloc(mv_s);
+ hint = 0;
+ return ENOMEM;
+ }
+ }
+ if (hint >= MVXPSEC_MAX_SESSIONS)
+ hint = 0;
+ sc->sc_nsessions++;
+ sc->sc_sessions[session] = mv_s;
+#ifdef DEBUG
+ log(LOG_DEBUG, "%s: new session %d allocated\n", __func__, session);
+#endif
+
+ sid = MVXPSEC_SID(device_unit(sc->sc_dev), session);
+ mv_s->sid = sid;
+
+ /* setup the session key ... */
+ for (c = cri; c; c = c->cri_next) {
+ switch (c->cri_alg) {
+ case CRYPTO_DES_CBC:
+ case CRYPTO_3DES_CBC:
+ case CRYPTO_AES_CBC:
+ /* key */
+ if (mvxpsec_key_precomp(c->cri_alg,
+ c->cri_key, c->cri_klen,
+ &mv_s->session_header.crp_key,
+ &mv_s->session_header.crp_key_d)) {
+ log(LOG_ERR,
+ "%s: Invalid HMAC key for %s.\n",
+ __func__, s_ctlalg(c->cri_alg));
+ err = EINVAL;
+ goto fail;
+ }
+ if (mv_s->sflags & RDY_CRP_KEY) {
+ log(LOG_WARNING,
+ "%s: overwrite cipher: %s->%s.\n",
+ __func__,
+ s_ctlalg(mv_s->cipher_alg),
+ s_ctlalg(c->cri_alg));
+ }
+ mv_s->sflags |= RDY_CRP_KEY;
+ mv_s->enc_klen = c->cri_klen;
+ mv_s->cipher_alg = c->cri_alg;
+ /* create per session IV (compatible with KAME IPsec) */
+ cprng_fast(&mv_s->session_iv, sizeof(mv_s->session_iv));
+ mv_s->sflags |= RDY_CRP_IV;
+ break;
+ case CRYPTO_SHA1_HMAC_96:
+ case CRYPTO_MD5_HMAC_96:
+ /* key */
+ if (mvxpsec_hmac_precomp(c->cri_alg,
+ c->cri_key, c->cri_klen,
+ (uint32_t *)&mv_s->session_header.miv_in,
+ (uint32_t *)&mv_s->session_header.miv_out)) {
+ log(LOG_ERR,
+ "%s: Invalid MAC key\n", __func__);
+ err = EINVAL;
+ goto fail;
+ }
+ if (mv_s->sflags & RDY_MAC_KEY ||
+ mv_s->sflags & RDY_MAC_IV) {
+ log(LOG_ERR,
+ "%s: overwrite HMAC: %s->%s.\n",
+ __func__, s_ctlalg(mv_s->hmac_alg),
+ s_ctlalg(c->cri_alg));
+ }
+ mv_s->sflags |= RDY_MAC_KEY;
+ mv_s->sflags |= RDY_MAC_IV;
+
+ mv_s->mac_klen = c->cri_klen;
+ mv_s->hmac_alg = c->cri_alg;
+ break;
+ default:
+ log(LOG_ERR, "%s: Unknown algorithm %d\n",
+ __func__, c->cri_alg);
+ err = EINVAL;
+ goto fail;
+ }
+ }
+ MVXPSEC_PRINTF(MVXPSEC_DEBUG_OPENCRYPTO,
+ "H/W Crypto session (id:%u) added.\n", session);
+
+ *sidp = sid;
+ MVXPSEC_EVCNT_INCR(sc, session_new);
+ mutex_exit(&sc->sc_session_mtx);
+
+ /* sync session header(it's never touched after here) */
+ bus_dmamap_sync(sc->sc_dmat,
+ mv_s->session_header_map,
+ 0, sizeof(mv_s->session_header),
+ BUS_DMASYNC_PREWRITE);
+
+ return 0;
+
+fail:
+ sc->sc_nsessions--;
+ sc->sc_sessions[session] = NULL;
+ hint = session;
+ if (mv_s)
+ mvxpsec_session_dealloc(mv_s);
+ log(LOG_WARNING,
+ "%s: Failed to add H/W crypto sessoin (id:%u): err=%d\n",
+ __func__, session, err);
+
+ mutex_exit(&sc->sc_session_mtx);
+ return err;
+}
+
+/*
+ * remove opencrypto session
+ */
+int
+mvxpsec_freesession(void *arg, uint64_t tid)
+{
+ struct mvxpsec_softc *sc = arg;
+ struct mvxpsec_session *mv_s;
+ int session;
+ uint32_t sid = ((uint32_t)tid) & 0xffffffff;
+
+ session = MVXPSEC_SESSION(sid);
+ if (session < 0 || session >= MVXPSEC_MAX_SESSIONS) {
+ log(LOG_ERR, "%s: invalid session (id:%u)\n",
+ __func__, session);
+ return EINVAL;
+ }
+
+ mutex_enter(&sc->sc_session_mtx);
+ if ( (mv_s = sc->sc_sessions[session]) == NULL) {
+ mutex_exit(&sc->sc_session_mtx);
+#ifdef DEBUG
+ log(LOG_DEBUG, "%s: session %d already inactivated\n",
+ __func__, session);
+#endif
+ return ENOENT;
+ }
+ MVXPSEC_PRINTF(MVXPSEC_DEBUG_OPENCRYPTO,
+ "%s: inactivate session %d\n", __func__, session);
+
+ /* inactivate mvxpsec session */
+ sc->sc_sessions[session] = NULL;
+ sc->sc_nsessions--;
+ sc->sc_last_session = NULL;
+ mutex_exit(&sc->sc_session_mtx);
+
+ KASSERT(sc->sc_nsessions >= 0);
+ KASSERT(mv_s->sid == sid);
+
+ mvxpsec_session_dealloc(mv_s);
+ MVXPSEC_PRINTF(MVXPSEC_DEBUG_OPENCRYPTO,
+ "H/W Crypto session (id: %d) deleted.\n", session);
+
+ /* force unblock opencrypto */
+ crypto_unblock(sc->sc_cid, CRYPTO_SYMQ|CRYPTO_ASYMQ);
+
+ MVXPSEC_EVCNT_INCR(sc, session_free);
+
+ return 0;
+}
+
+/*
+ * process data with existing session
+ */
+int
+mvxpsec_dispatch(void *arg, struct cryptop *crp, int hint)
+{
+ struct mvxpsec_softc *sc = arg;
+ struct mvxpsec_session *mv_s;
+ struct mvxpsec_packet *mv_p;
+ int q_full;
+ int running;
+ int err;
+
+ mutex_enter(&sc->sc_queue_mtx);
+
+ /*
+ * lookup session
+ */
+ mutex_enter(&sc->sc_session_mtx);
+ mv_s = mvxpsec_session_lookup(sc, crp->crp_sid);
+ if (__predict_false(mv_s == NULL)) {
+ err = EINVAL;
+ mv_p = NULL;
+ mutex_exit(&sc->sc_session_mtx);
+ goto fail;
+ }
+ mv_p = mvxpsec_packet_alloc(mv_s);
+ if (__predict_false(mv_p == NULL)) {
+ mutex_exit(&sc->sc_session_mtx);
+ mutex_exit(&sc->sc_queue_mtx);
+ return ERESTART; /* => queued in opencrypto layer */
+ }
+ mutex_exit(&sc->sc_session_mtx);
+
+ /*
+ * check queue status
+ */
+#ifdef MVXPSEC_MULTI_PACKET
+ q_full = (sc->sc_wait_qlen >= sc->sc_wait_qlimit) ? 1 : 0;
+#else
+ q_full = (sc->sc_wait_qlen != 0) ? 1 : 0;
+#endif
+ running = (sc->sc_flags & HW_RUNNING) ? 1: 0;
+ if (q_full) {
+ /* input queue is full. */
+ if (!running && sc->sc_wait_qlen > 0)
+ mvxpsec_dispatch_queue(sc);
+ MVXPSEC_EVCNT_INCR(sc, queue_full);
+ mvxpsec_packet_dealloc(mv_p);
+ mutex_exit(&sc->sc_queue_mtx);
+ return ERESTART; /* => queued in opencrypto layer */
+ }
+
+ /*
+ * Load and setup packet data
+ */
+ err = mvxpsec_packet_setcrp(mv_p, crp);
+ if (__predict_false(err))
+ goto fail;
+
+ /*
+ * Setup DMA descriptor chains
+ */
+ mutex_enter(&sc->sc_dma_mtx);
+ err = mvxpsec_dma_copy_packet(sc, mv_p);
+ mutex_exit(&sc->sc_dma_mtx);
+ if (__predict_false(err))
+ goto fail;
+
+#ifdef MVXPSEC_DEBUG
+ mvxpsec_dump_packet(__func__, mv_p);
+#endif
+
+ /*
+ * Sync/inval the data cache
+ */
+ err = mvxpsec_dma_sync_packet(sc, mv_p);
+ if (__predict_false(err))
+ goto fail;
+
+ /*
+ * Enqueue the packet
+ */
+ MVXPSEC_EVCNT_INCR(sc, dispatch_packets);
+#ifdef MVXPSEC_MULTI_PACKET
+ mvxpsec_packet_enqueue(mv_p);
+ if (!running)
+ mvxpsec_dispatch_queue(sc);
+#else
+ SIMPLEQ_INSERT_TAIL(&sc->sc_wait_queue, mv_p, queue);
+ sc->sc_wait_qlen++;
+ mv_p->flags |= SETUP_DONE;
+ if (!running)
+ mvxpsec_dispatch_queue(sc);
+#endif
+ mutex_exit(&sc->sc_queue_mtx);
+ return 0;
+
+fail:
+ /* Drop the incoming packet */
+ mvxpsec_drop(sc, crp, mv_p, err);
+ mutex_exit(&sc->sc_queue_mtx);
+ return 0;
+}
+
+/*
+ * back the packet to the IP stack
+ */
+void
+mvxpsec_done(void *arg)
+{
+ struct mvxpsec_softc *sc = arg;
+ struct mvxpsec_packet *mv_p;
+ mvxpsec_queue_t ret_queue;
+ int ndone;
+
+ mutex_enter(&sc->sc_queue_mtx);
+
+ /* stop wdog timer */
+ callout_stop(&sc->sc_timeout);
+
+ /* refill MVXPSEC */
+ ret_queue = sc->sc_run_queue;
+ SIMPLEQ_INIT(&sc->sc_run_queue);
+ sc->sc_flags &= ~HW_RUNNING;
+ if (sc->sc_wait_qlen > 0)
+ mvxpsec_dispatch_queue(sc);
+
+ ndone = 0;
+ while ( (mv_p = SIMPLEQ_FIRST(&ret_queue)) != NULL) {
+ SIMPLEQ_REMOVE_HEAD(&ret_queue, queue);
+ mvxpsec_dma_free(sc, &mv_p->dma_ring);
+ mvxpsec_done_packet(mv_p);
+ ndone++;
+ }
+ MVXPSEC_EVCNT_MAX(sc, max_done, ndone);
+
+ mutex_exit(&sc->sc_queue_mtx);
+}
+
+/*
+ * drop the packet
+ */
+INLINE void
+mvxpsec_drop(struct mvxpsec_softc *sc, struct cryptop *crp,
+ struct mvxpsec_packet *mv_p, int err)
+{
+ /* must called with sc->sc_queue_mtx held */
+ KASSERT(mutex_owned(&sc->sc_queue_mtx));
+
+ if (mv_p)
+ mvxpsec_packet_dealloc(mv_p);
+ if (err < 0)
+ err = EINVAL;
+ crp->crp_etype = err;
+ crypto_done(crp);
+ MVXPSEC_EVCNT_INCR(sc, packet_err);
+
+ /* dispatch other packets in queue */
+ if (sc->sc_wait_qlen > 0 &&
+ !(sc->sc_flags & HW_RUNNING))
+ mvxpsec_dispatch_queue(sc);
+
+ /* unblock driver for dropped packet */
+ crypto_unblock(sc->sc_cid, CRYPTO_SYMQ|CRYPTO_ASYMQ);
+}
+
+/* move wait queue entry to run queue */
+STATIC int
+mvxpsec_dispatch_queue(struct mvxpsec_softc *sc)
+{
+ struct mvxpsec_packet *mv_p;
+ paddr_t head;
+ int ndispatch = 0;
+
+ /* must called with sc->sc_queue_mtx held */
+ KASSERT(mutex_owned(&sc->sc_queue_mtx));
+
+ /* check there is any task */
+ if (__predict_false(sc->sc_flags & HW_RUNNING)) {
+ log(LOG_WARNING,
+ "%s: another packet already exist.\n", __func__);
+ return 0;
+ }
+ if (__predict_false(SIMPLEQ_EMPTY(&sc->sc_wait_queue))) {
+ log(LOG_WARNING,
+ "%s: no waiting packet yet(qlen=%d).\n",
+ __func__, sc->sc_wait_qlen);
+ return 0;
+ }
+
+ /* move queue */
+ sc->sc_run_queue = sc->sc_wait_queue;
+ sc->sc_flags |= HW_RUNNING; /* dropped by intr or timeout */
+ SIMPLEQ_INIT(&sc->sc_wait_queue);
+ ndispatch = sc->sc_wait_qlen;
+ sc->sc_wait_qlen = 0;
+
+ /* get 1st DMA descriptor */
+ mv_p = SIMPLEQ_FIRST(&sc->sc_run_queue);
+ head = mv_p->dma_ring.dma_head->phys_addr;
+
+ /* terminate last DMA descriptor */
+ mv_p = SIMPLEQ_LAST(&sc->sc_run_queue, mvxpsec_packet, queue);
+ mvxpsec_dma_finalize(sc, &mv_p->dma_ring);
+
+ /* configure TDMA */
+ if (mvxpsec_dma_wait(sc) < 0) {
+ log(LOG_ERR, "%s: DMA DEVICE not responding", __func__);
+ callout_schedule(&sc->sc_timeout, hz);
+ return 0;
+ }
+ MVXPSEC_WRITE(sc, MV_TDMA_NXT, head);
+
+ /* trigger ACC */
+ if (mvxpsec_acc_wait(sc) < 0) {
+ log(LOG_ERR, "%s: MVXPSEC not responding", __func__);
+ callout_schedule(&sc->sc_timeout, hz);
+ return 0;
+ }
+ MVXPSEC_WRITE(sc, MV_ACC_COMMAND, MV_ACC_COMMAND_ACT);
+
+ MVXPSEC_EVCNT_MAX(sc, max_dispatch, ndispatch);
+ MVXPSEC_EVCNT_INCR(sc, dispatch_queue);
+ callout_schedule(&sc->sc_timeout, hz);
+ return 0;
+}
+
+/*
+ * process opencrypto operations(cryptop) for packets.
+ */
+INLINE int
+mvxpsec_parse_crd(struct mvxpsec_packet *mv_p, struct cryptodesc *crd)
+{
+ int ivlen;
+
+ KASSERT(mv_p->flags & RDY_DATA);
+
+ /* MAC & Ciphers: set data location and operation */
+ switch (crd->crd_alg) {
+ case CRYPTO_SHA1_HMAC_96:
+ mv_p->pkt_header.desc.acc_config |= MV_ACC_CRYPTO_MAC_96;
+ /* fall through */
+ case CRYPTO_SHA1_HMAC:
+ mv_p->mac_dst = crd->crd_inject;
+ mv_p->mac_off = crd->crd_skip;
+ mv_p->mac_len = crd->crd_len;
+ MV_ACC_CRYPTO_MAC_SET(mv_p->pkt_header.desc.acc_config,
+ MV_ACC_CRYPTO_MAC_HMAC_SHA1);
+ mvxpsec_packet_update_op_order(mv_p, MV_ACC_CRYPTO_OP_MAC);
+ /* No more setup for MAC */
+ return 0;
+ case CRYPTO_MD5_HMAC_96:
+ mv_p->pkt_header.desc.acc_config |= MV_ACC_CRYPTO_MAC_96;
+ /* fall through */
+ case CRYPTO_MD5_HMAC:
+ mv_p->mac_dst = crd->crd_inject;
+ mv_p->mac_off = crd->crd_skip;
+ mv_p->mac_len = crd->crd_len;
+ MV_ACC_CRYPTO_MAC_SET(mv_p->pkt_header.desc.acc_config,
+ MV_ACC_CRYPTO_MAC_HMAC_MD5);
+ mvxpsec_packet_update_op_order(mv_p, MV_ACC_CRYPTO_OP_MAC);
+ /* No more setup for MAC */
+ return 0;
+ case CRYPTO_DES_CBC:
+ mv_p->enc_ivoff = crd->crd_inject;
+ mv_p->enc_off = crd->crd_skip;
+ mv_p->enc_len = crd->crd_len;
+ ivlen = 8;
+ MV_ACC_CRYPTO_ENC_SET(mv_p->pkt_header.desc.acc_config,
+ MV_ACC_CRYPTO_ENC_DES);
+ mv_p->pkt_header.desc.acc_config |= MV_ACC_CRYPTO_CBC;
+ mvxpsec_packet_update_op_order(mv_p, MV_ACC_CRYPTO_OP_ENC);
+ break;
+ case CRYPTO_3DES_CBC:
+ mv_p->enc_ivoff = crd->crd_inject;
+ mv_p->enc_off = crd->crd_skip;
+ mv_p->enc_len = crd->crd_len;
+ ivlen = 8;
+ MV_ACC_CRYPTO_ENC_SET(mv_p->pkt_header.desc.acc_config,
+ MV_ACC_CRYPTO_ENC_3DES);
+ mv_p->pkt_header.desc.acc_config |= MV_ACC_CRYPTO_CBC;
+ mv_p->pkt_header.desc.acc_config |= MV_ACC_CRYPTO_3DES_EDE;
+ mvxpsec_packet_update_op_order(mv_p, MV_ACC_CRYPTO_OP_ENC);
+ break;
+ case CRYPTO_AES_CBC:
+ mv_p->enc_ivoff = crd->crd_inject;
+ mv_p->enc_off = crd->crd_skip;
+ mv_p->enc_len = crd->crd_len;
+ ivlen = 16;
+ MV_ACC_CRYPTO_ENC_SET(mv_p->pkt_header.desc.acc_config,
+ MV_ACC_CRYPTO_ENC_AES);
+ MV_ACC_CRYPTO_AES_KLEN_SET(
+ mv_p->pkt_header.desc.acc_config,
+ mvxpsec_aesklen(mv_p->mv_s->enc_klen));
+ mv_p->pkt_header.desc.acc_config |= MV_ACC_CRYPTO_CBC;
+ mvxpsec_packet_update_op_order(mv_p, MV_ACC_CRYPTO_OP_ENC);
+ break;
+ default:
+ log(LOG_ERR, "%s: Unknown algorithm %d\n",
+ __func__, crd->crd_alg);
+ return EINVAL;
+ }
+
+ /* Operations only for Cipher, not MAC */
+ if (crd->crd_flags & CRD_F_ENCRYPT) {
+ /* Ciphers: Originate IV for Encryption.*/
+ mv_p->pkt_header.desc.acc_config &= ~MV_ACC_CRYPTO_DECRYPT;
+ mv_p->flags |= DIR_ENCRYPT;
+
+ if (crd->crd_flags & CRD_F_IV_EXPLICIT) {
+ MVXPSEC_PRINTF(MVXPSEC_DEBUG_ENC_IV, "EXPLICIT IV\n");
+ mv_p->flags |= CRP_EXT_IV;
+ mvxpsec_packet_write_iv(mv_p, crd->crd_iv, ivlen);
+ mv_p->enc_ivoff = MVXPSEC_SRAM_IV_EXT_OFF;
+ }
+ else if (crd->crd_flags & CRD_F_IV_PRESENT) {
+ MVXPSEC_PRINTF(MVXPSEC_DEBUG_ENC_IV, "IV is present\n");
+ mvxpsec_packet_copy_iv(mv_p, crd->crd_inject, ivlen);
+ }
+ else {
+ MVXPSEC_PRINTF(MVXPSEC_DEBUG_ENC_IV, "Create New IV\n");
+ mvxpsec_packet_write_iv(mv_p, NULL, ivlen);
+ }
+ }
+ else {
+ /* Ciphers: IV is loadded from crd_inject when it's present */
+ mv_p->pkt_header.desc.acc_config |= MV_ACC_CRYPTO_DECRYPT;
+ mv_p->flags |= DIR_DECRYPT;
+
+ if (crd->crd_flags & CRD_F_IV_EXPLICIT) {
+#ifdef MVXPSEC_DEBUG
+ if (mvxpsec_debug & MVXPSEC_DEBUG_ENC_IV) {
+ MVXPSEC_PRINTF(MVXPSEC_DEBUG_ENC_IV,
+ "EXPLICIT IV(Decrypt)\n");
+ mvxpsec_dump_data(__func__, crd->crd_iv, ivlen);
+ }
+#endif
+ mv_p->flags |= CRP_EXT_IV;
+ mvxpsec_packet_write_iv(mv_p, crd->crd_iv, ivlen);
+ mv_p->enc_ivoff = MVXPSEC_SRAM_IV_EXT_OFF;
+ }
+ }
+
+ KASSERT(!((mv_p->flags & DIR_ENCRYPT) && (mv_p->flags & DIR_DECRYPT)));
+
+ return 0;
+}
+
+INLINE int
+mvxpsec_parse_crp(struct mvxpsec_packet *mv_p)
+{
+ struct cryptop *crp = mv_p->crp;
+ struct cryptodesc *crd;
+ int err;
+
+ KASSERT(crp);
+
+ mvxpsec_packet_reset_op(mv_p);
+
+ for (crd = crp->crp_desc; crd; crd = crd->crd_next) {
+ err = mvxpsec_parse_crd(mv_p, crd);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+INLINE int
+mvxpsec_packet_setcrp(struct mvxpsec_packet *mv_p, struct cryptop *crp)
+{
+ int err = EINVAL;
+
+ /* regiseter crp to the MVXPSEC packet */
+ if (crp->crp_flags & CRYPTO_F_IMBUF) {
+ err = mvxpsec_packet_setmbuf(mv_p,
+ (struct mbuf *)crp->crp_buf);
+ mv_p->crp = crp;
+ }
+ else if (crp->crp_flags & CRYPTO_F_IOV) {
+ err = mvxpsec_packet_setuio(mv_p,
+ (struct uio *)crp->crp_buf);
+ mv_p->crp = crp;
+ }
+ else {
+ err = mvxpsec_packet_setdata(mv_p,
+ (struct mbuf *)crp->crp_buf, crp->crp_ilen);
+ mv_p->crp = crp;
+ }
+ if (__predict_false(err))
+ return err;
+
+ /* parse crp and setup MVXPSEC registers/descriptors */
+ err = mvxpsec_parse_crp(mv_p);
+ if (__predict_false(err))
+ return err;
+
+ /* fixup data offset to fit MVXPSEC internal SRAM */
+ err = mvxpsec_header_finalize(mv_p);
+ if (__predict_false(err))
+ return err;
+
+ return 0;
+}
+
+/*
+ * load data for encrypt/decrypt/authentication
+ *
+ * data is raw kernel memory area.
+ */
+STATIC int
+mvxpsec_packet_setdata(struct mvxpsec_packet *mv_p,
+ void *data, uint32_t data_len)
+{
+ struct mvxpsec_session *mv_s = mv_p->mv_s;
+ struct mvxpsec_softc *sc = mv_s->sc;
+
+ if (bus_dmamap_load(sc->sc_dmat, mv_p->data_map, data, data_len,
+ NULL, BUS_DMA_NOWAIT)) {
+ log(LOG_ERR, "%s: cannot load data\n", __func__);
+ return -1;
+ }
+ mv_p->data_type = MVXPSEC_DATA_RAW;
+ mv_p->data_raw = data;
+ mv_p->data_len = data_len;
+ mv_p->flags |= RDY_DATA;
+
+ return 0;
+}
+
+/*
+ * load data for encrypt/decrypt/authentication
+ *
+ * data is mbuf based network data.
+ */
+STATIC int
+mvxpsec_packet_setmbuf(struct mvxpsec_packet *mv_p, struct mbuf *m)
+{
+ struct mvxpsec_session *mv_s = mv_p->mv_s;
+ struct mvxpsec_softc *sc = mv_s->sc;
+ size_t pktlen = 0;
+
+ if (__predict_true(m->m_flags & M_PKTHDR))
+ pktlen = m->m_pkthdr.len;
+ else {
+ struct mbuf *mp = m;
+
+ while (mp != NULL) {
+ pktlen += m->m_len;
+ mp = mp->m_next;
+ }
+ }
+ if (pktlen > SRAM_PAYLOAD_SIZE) {
+ extern percpu_t *espstat_percpu;
+ /* XXX:
+ * layer violation. opencrypto knows our max packet size
+ * from crypto_register(9) API.
+ */
+
+ _NET_STATINC(espstat_percpu, ESP_STAT_TOOBIG);
+ log(LOG_ERR,
+ "%s: ESP Packet too large: %zu [oct.] > %zu [oct.]\n",
+ device_xname(sc->sc_dev),
+ (size_t)pktlen, SRAM_PAYLOAD_SIZE);
+ mv_p->data_type = MVXPSEC_DATA_NONE;
+ mv_p->data_mbuf = NULL;
+ return -1;
+ }
+
+ if (bus_dmamap_load_mbuf(sc->sc_dmat, mv_p->data_map, m,
+ BUS_DMA_NOWAIT)) {
+ mv_p->data_type = MVXPSEC_DATA_NONE;
+ mv_p->data_mbuf = NULL;
+ log(LOG_ERR, "%s: cannot load mbuf\n", __func__);
+ return -1;
+ }
+
+ /* set payload buffer */
+ mv_p->data_type = MVXPSEC_DATA_MBUF;
+ mv_p->data_mbuf = m;
+ if (m->m_flags & M_PKTHDR) {
+ mv_p->data_len = m->m_pkthdr.len;
+ }
+ else {
+ mv_p->data_len = 0;
+ while (m) {
+ mv_p->data_len += m->m_len;
+ m = m->m_next;
+ }
+ }
+ mv_p->flags |= RDY_DATA;
+
+ return 0;
+}
+
+STATIC int
+mvxpsec_packet_setuio(struct mvxpsec_packet *mv_p, struct uio *uio)
+{
+ struct mvxpsec_session *mv_s = mv_p->mv_s;
+ struct mvxpsec_softc *sc = mv_s->sc;
+
+ if (uio->uio_resid > SRAM_PAYLOAD_SIZE) {
+ extern percpu_t *espstat_percpu;
+ /* XXX:
+ * layer violation. opencrypto knows our max packet size
+ * from crypto_register(9) API.
+ */
+
+ _NET_STATINC(espstat_percpu, ESP_STAT_TOOBIG);
+ log(LOG_ERR,
+ "%s: uio request too large: %zu [oct.] > %zu [oct.]\n",
+ device_xname(sc->sc_dev),
+ uio->uio_resid, SRAM_PAYLOAD_SIZE);
+ mv_p->data_type = MVXPSEC_DATA_NONE;
+ mv_p->data_mbuf = NULL;
+ return -1;
+ }
+
+ if (bus_dmamap_load_uio(sc->sc_dmat, mv_p->data_map, uio,
+ BUS_DMA_NOWAIT)) {
+ mv_p->data_type = MVXPSEC_DATA_NONE;
+ mv_p->data_mbuf = NULL;
+ log(LOG_ERR, "%s: cannot load uio buf\n", __func__);
+ return -1;
+ }
+
+ /* set payload buffer */
+ mv_p->data_type = MVXPSEC_DATA_UIO;
+ mv_p->data_uio = uio;
+ mv_p->data_len = uio->uio_resid;
+ mv_p->flags |= RDY_DATA;
+
+ return 0;
+}
+
+STATIC int
+mvxpsec_packet_rdata(struct mvxpsec_packet *mv_p,
+ int off, int len, void *cp)
+{
+ uint8_t *p;
+
+ if (mv_p->data_type == MVXPSEC_DATA_RAW) {
+ p = (uint8_t *)mv_p->data_raw + off;
+ memcpy(cp, p, len);
+ }
+ else if (mv_p->data_type == MVXPSEC_DATA_MBUF) {
+ m_copydata(mv_p->data_mbuf, off, len, cp);
+ }
+ else if (mv_p->data_type == MVXPSEC_DATA_UIO) {
+ cuio_copydata(mv_p->data_uio, off, len, cp);
+ }
+ else
+ return -1;
+
+ return 0;
+}
+
+STATIC int
+mvxpsec_packet_wdata(struct mvxpsec_packet *mv_p,
+ int off, int len, void *cp)
+{
+ uint8_t *p;
+
+ if (mv_p->data_type == MVXPSEC_DATA_RAW) {
+ p = (uint8_t *)mv_p->data_raw + off;
+ memcpy(p, cp, len);
+ }
+ else if (mv_p->data_type == MVXPSEC_DATA_MBUF) {
+ m_copyback(mv_p->data_mbuf, off, len, cp);
+ }
+ else if (mv_p->data_type == MVXPSEC_DATA_UIO) {
+ cuio_copyback(mv_p->data_uio, off, len, cp);
+ }
+ else
+ return -1;
+
+ return 0;
+}
+
+/*
+ * Set initial vector of cipher to the session.
+ */
+STATIC int
+mvxpsec_packet_write_iv(struct mvxpsec_packet *mv_p, void *iv, int ivlen)
+{
+ uint8_t ivbuf[16];
+
+ KASSERT(ivlen == 8 || ivlen == 16);
+
+ if (iv == NULL) {
+ if (mv_p->mv_s->sflags & RDY_CRP_IV) {
+ /* use per session IV (compatible with KAME IPsec) */
+ mv_p->pkt_header.crp_iv_work = mv_p->mv_s->session_iv;
+ mv_p->flags |= RDY_CRP_IV;
+ return 0;
+ }
+ cprng_fast(ivbuf, ivlen);
+ iv = ivbuf;
+ }
+ memcpy(&mv_p->pkt_header.crp_iv_work, iv, ivlen);
+ if (mv_p->flags & CRP_EXT_IV) {
+ memcpy(&mv_p->pkt_header.crp_iv_ext, iv, ivlen);
+ mv_p->ext_iv = iv;
+ mv_p->ext_ivlen = ivlen;
+ }
+ mv_p->flags |= RDY_CRP_IV;
+
+ return 0;
+}
+
+STATIC int
+mvxpsec_packet_copy_iv(struct mvxpsec_packet *mv_p, int off, int ivlen)
+{
+ mvxpsec_packet_rdata(mv_p, off, ivlen,
+ &mv_p->pkt_header.crp_iv_work);
+ mv_p->flags |= RDY_CRP_IV;
+
+ return 0;
+}
+
+/*
+ * set a encryption or decryption key to the session
+ *
+ * Input key material is big endian.
+ */
+STATIC int
+mvxpsec_key_precomp(int alg, void *keymat, int kbitlen,
+ void *key_encrypt, void *key_decrypt)
+{
+ uint32_t *kp = keymat;
+ uint32_t *ekp = key_encrypt;
+ uint32_t *dkp = key_decrypt;
+ int i;
+
+ switch (alg) {
+ case CRYPTO_DES_CBC:
+ if (kbitlen < 64 || (kbitlen % 8) != 0) {
+ log(LOG_WARNING,
+ "mvxpsec: invalid DES keylen %d\n", kbitlen);
+ return EINVAL;
+ }
+ for (i = 0; i < 2; i++)
+ dkp[i] = ekp[i] = kp[i];
+ for (; i < 8; i++)
+ dkp[i] = ekp[i] = 0;
+ break;
+ case CRYPTO_3DES_CBC:
+ if (kbitlen < 192 || (kbitlen % 8) != 0) {
+ log(LOG_WARNING,
+ "mvxpsec: invalid 3DES keylen %d\n", kbitlen);
+ return EINVAL;
+ }
+ for (i = 0; i < 8; i++)
+ dkp[i] = ekp[i] = kp[i];
+ break;
+ case CRYPTO_AES_CBC:
+ if (kbitlen < 128) {
+ log(LOG_WARNING,
+ "mvxpsec: invalid AES keylen %d\n", kbitlen);
+ return EINVAL;
+ }
+ else if (kbitlen < 192) {
+ /* AES-128 */
+ for (i = 0; i < 4; i++)
+ ekp[i] = kp[i];
+ for (; i < 8; i++)
+ ekp[i] = 0;
+ }
+ else if (kbitlen < 256) {
+ /* AES-192 */
+ for (i = 0; i < 6; i++)
+ ekp[i] = kp[i];
+ for (; i < 8; i++)
+ ekp[i] = 0;
+ }
+ else {
+ /* AES-256 */
+ for (i = 0; i < 8; i++)
+ ekp[i] = kp[i];
+ }
+ /* make decryption key */
+ mv_aes_deckey((uint8_t *)dkp, (uint8_t *)ekp, kbitlen);
+ break;
+ default:
+ for (i = 0; i < 8; i++)
+ ekp[0] = dkp[0] = 0;
+ break;
+ }
+
+#ifdef MVXPSEC_DEBUG
+ if (mvxpsec_debug & MVXPSEC_DEBUG_OPENCRYPTO) {
+ MVXPSEC_PRINTF(MVXPSEC_DEBUG_OPENCRYPTO,
+ "%s: keyregistered\n", __func__);
+ mvxpsec_dump_data(__func__, ekp, 32);
+ }
+#endif
+
+ return 0;
+}
+
+/*
+ * set MAC key to the session
+ *
+ * MAC engine has no register for key itself, but the engine has
+ * inner and outer IV register. software must compute IV before
+ * enable the engine.
+ *
+ * IV is a hash of ipad/opad. these are defined by FIPS-198a
+ * standard.
+ */
+STATIC int
+mvxpsec_hmac_precomp(int alg, void *key, int kbitlen,
+ void *iv_inner, void *iv_outer)
+{
+ SHA1_CTX sha1;
+ MD5_CTX md5;
+ uint8_t *key8 = key;
+ uint8_t kbuf[64];
+ uint8_t ipad[64];
+ uint8_t opad[64];
+ uint32_t *iv_in = iv_inner;
+ uint32_t *iv_out = iv_outer;
+ int kbytelen;
+ int i;
+#define HMAC_IPAD 0x36
+#define HMAC_OPAD 0x5c
+
+ kbytelen = kbitlen / 8;
+ KASSERT(kbitlen == kbytelen * 8);
+ if (kbytelen > 64) {
+ SHA1Init(&sha1);
+ SHA1Update(&sha1, key, kbytelen);
+ SHA1Final(kbuf, &sha1);
+ key8 = kbuf;
+ kbytelen = 64;
+ }
+
+ /* make initial 64 oct. string */
+ switch (alg) {
+ case CRYPTO_SHA1_HMAC_96:
+ case CRYPTO_SHA1_HMAC:
+ case CRYPTO_MD5_HMAC_96:
+ case CRYPTO_MD5_HMAC:
+ for (i = 0; i < kbytelen; i++) {
+ ipad[i] = (key8[i] ^ HMAC_IPAD);
+ opad[i] = (key8[i] ^ HMAC_OPAD);
+ }
+ for (; i < 64; i++) {
+ ipad[i] = HMAC_IPAD;
+ opad[i] = HMAC_OPAD;
+ }
+ break;
+ default:
+ break;
+ }
+#ifdef MVXPSEC_DEBUG
+ if (mvxpsec_debug & MVXPSEC_DEBUG_OPENCRYPTO) {
+ MVXPSEC_PRINTF(MVXPSEC_DEBUG_OPENCRYPTO,
+ "%s: HMAC-KEY Pre-comp:\n", __func__);
+ mvxpsec_dump_data(__func__, key, 64);
+ MVXPSEC_PRINTF(MVXPSEC_DEBUG_OPENCRYPTO,
+ "%s: ipad:\n", __func__);
+ mvxpsec_dump_data(__func__, ipad, sizeof(ipad));
+ MVXPSEC_PRINTF(MVXPSEC_DEBUG_OPENCRYPTO,
+ "%s: opad:\n", __func__);
+ mvxpsec_dump_data(__func__, opad, sizeof(opad));
+ }
+#endif
+
+ /* make iv from string */
+ switch (alg) {
+ case CRYPTO_SHA1_HMAC_96:
+ case CRYPTO_SHA1_HMAC:
+ MVXPSEC_PRINTF(MVXPSEC_DEBUG_OPENCRYPTO,
+ "%s: Generate iv_in(SHA1)\n", __func__);
+ SHA1Init(&sha1);
+ SHA1Update(&sha1, ipad, 64);
+ /* XXX: private state... (LE) */
+ iv_in[0] = htobe32(sha1.state[0]);
+ iv_in[1] = htobe32(sha1.state[1]);
+ iv_in[2] = htobe32(sha1.state[2]);
+ iv_in[3] = htobe32(sha1.state[3]);
+ iv_in[4] = htobe32(sha1.state[4]);
+
+ MVXPSEC_PRINTF(MVXPSEC_DEBUG_OPENCRYPTO,
+ "%s: Generate iv_out(SHA1)\n", __func__);
+ SHA1Init(&sha1);
+ SHA1Update(&sha1, opad, 64);
+ /* XXX: private state... (LE) */
+ iv_out[0] = htobe32(sha1.state[0]);
+ iv_out[1] = htobe32(sha1.state[1]);
+ iv_out[2] = htobe32(sha1.state[2]);
+ iv_out[3] = htobe32(sha1.state[3]);
+ iv_out[4] = htobe32(sha1.state[4]);
+ break;
+ case CRYPTO_MD5_HMAC_96:
+ case CRYPTO_MD5_HMAC:
+ MVXPSEC_PRINTF(MVXPSEC_DEBUG_OPENCRYPTO,
+ "%s: Generate iv_in(MD5)\n", __func__);
+ MD5Init(&md5);
+ MD5Update(&md5, ipad, sizeof(ipad));
+ /* XXX: private state... (LE) */
+ iv_in[0] = htobe32(md5.state[0]);
+ iv_in[1] = htobe32(md5.state[1]);
+ iv_in[2] = htobe32(md5.state[2]);
+ iv_in[3] = htobe32(md5.state[3]);
+ iv_in[4] = 0;
+
+ MVXPSEC_PRINTF(MVXPSEC_DEBUG_OPENCRYPTO,
+ "%s: Generate iv_out(MD5)\n", __func__);
+ MD5Init(&md5);
+ MD5Update(&md5, opad, sizeof(opad));
+ /* XXX: private state... (LE) */
+ iv_out[0] = htobe32(md5.state[0]);
+ iv_out[1] = htobe32(md5.state[1]);
+ iv_out[2] = htobe32(md5.state[2]);
+ iv_out[3] = htobe32(md5.state[3]);
+ iv_out[4] = 0;
+ break;
+ default:
+ break;
+ }
+
+#ifdef MVXPSEC_DEBUG
+ if (mvxpsec_debug & MVXPSEC_DEBUG_HASH_IV) {
+ MVXPSEC_PRINTF(MVXPSEC_DEBUG_HASH_IV,
+ "%s: HMAC IV-IN\n", __func__);
+ mvxpsec_dump_data(__func__, (uint8_t *)iv_in, 20);
+ MVXPSEC_PRINTF(MVXPSEC_DEBUG_HASH_IV,
+ "%s: HMAC IV-OUT\n", __func__);
+ mvxpsec_dump_data(__func__, (uint8_t *)iv_out, 20);
+ }
+#endif
+
+ return 0;
+#undef HMAC_IPAD
+#undef HMAC_OPAD
+}
+
+/*
+ * AES Support routine
+ */
+static uint8_t AES_SBOX[256] = {
+ 99, 124, 119, 123, 242, 107, 111, 197, 48, 1, 103, 43, 254, 215,
+ 171, 118, 202, 130, 201, 125, 250, 89, 71, 240, 173, 212, 162, 175,
+ 156, 164, 114, 192, 183, 253, 147, 38, 54, 63, 247, 204, 52, 165,
+ 229, 241, 113, 216, 49, 21, 4, 199, 35, 195, 24, 150, 5, 154,
+ 7, 18, 128, 226, 235, 39, 178, 117, 9, 131, 44, 26, 27, 110,
+ 90, 160, 82, 59, 214, 179, 41, 227, 47, 132, 83, 209, 0, 237,
+ 32, 252, 177, 91, 106, 203, 190, 57, 74, 76, 88, 207, 208, 239,
+ 170, 251, 67, 77, 51, 133, 69, 249, 2, 127, 80, 60, 159, 168,
+ 81, 163, 64, 143, 146, 157, 56, 245, 188, 182, 218, 33, 16, 255,
+ 243, 210, 205, 12, 19, 236, 95, 151, 68, 23, 196, 167, 126, 61,
+ 100, 93, 25, 115, 96, 129, 79, 220, 34, 42, 144, 136, 70, 238,
+ 184, 20, 222, 94, 11, 219, 224, 50, 58, 10, 73, 6, 36, 92,
+ 194, 211, 172, 98, 145, 149, 228, 121, 231, 200, 55, 109, 141, 213,
+ 78, 169, 108, 86, 244, 234, 101, 122, 174, 8, 186, 120, 37, 46,
+ 28, 166, 180, 198, 232, 221, 116, 31, 75, 189, 139, 138, 112, 62,
+ 181, 102, 72, 3, 246, 14, 97, 53, 87, 185, 134, 193, 29, 158,
+ 225, 248, 152, 17, 105, 217, 142, 148, 155, 30, 135, 233, 206, 85,
+ 40, 223, 140, 161, 137, 13, 191, 230, 66, 104, 65, 153, 45, 15,
+ 176, 84, 187, 22
+};
+
+static uint32_t AES_RCON[30] = {
+ 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8,
+ 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4,
+ 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91
+};
+
+STATIC int
+mv_aes_ksched(uint8_t k[4][MAXKC], int keyBits,
+ uint8_t W[MAXROUNDS+1][4][MAXBC])
+{
+ int KC, BC, ROUNDS;
+ int i, j, t, rconpointer = 0;
+ uint8_t tk[4][MAXKC];
+
+ switch (keyBits) {
+ case 128:
+ ROUNDS = 10;
+ KC = 4;
+ break;
+ case 192:
+ ROUNDS = 12;
+ KC = 6;
+ break;
+ case 256:
+ ROUNDS = 14;
+ KC = 8;
+ break;
+ default:
+ return (-1);
+ }
+ BC = 4; /* 128 bits */
+
+ for(j = 0; j < KC; j++)
+ for(i = 0; i < 4; i++)
+ tk[i][j] = k[i][j];
+ t = 0;
+
+ /* copy values into round key array */
+ for(j = 0; (j < KC) && (t < (ROUNDS+1)*BC); j++, t++)
+ for(i = 0; i < 4; i++) W[t / BC][i][t % BC] = tk[i][j];
+
+ while (t < (ROUNDS+1)*BC) { /* while not enough round key material calculated */
+ /* calculate new values */
+ for(i = 0; i < 4; i++)
+ tk[i][0] ^= AES_SBOX[tk[(i+1)%4][KC-1]];
+ tk[0][0] ^= AES_RCON[rconpointer++];
+
+ if (KC != 8)
+ for(j = 1; j < KC; j++)
+ for(i = 0; i < 4; i++)
+ tk[i][j] ^= tk[i][j-1];
+ else {
+ for(j = 1; j < KC/2; j++)
+ for(i = 0; i < 4; i++)
+ tk[i][j] ^= tk[i][j-1];
+ for(i = 0; i < 4; i++)
+ tk[i][KC/2] ^= AES_SBOX[tk[i][KC/2 - 1]];
+ for(j = KC/2 + 1; j < KC; j++)
+ for(i = 0; i < 4; i++)
+ tk[i][j] ^= tk[i][j-1];
+ }
+ /* copy values into round key array */
+ for(j = 0; (j < KC) && (t < (ROUNDS+1)*BC); j++, t++)
+ for(i = 0; i < 4; i++) W[t / BC][i][t % BC] = tk[i][j];
+ }
+
+ return 0;
+}
+
+STATIC int
+mv_aes_deckey(uint8_t *expandedKey, uint8_t *keyMaterial, int keyLen)
+{
+ uint8_t W[MAXROUNDS+1][4][MAXBC];
+ uint8_t k[4][MAXKC];
+ uint8_t j;
+ int i, rounds, KC;
+
+ if (expandedKey == NULL)
+ return -1;
+
+ if (!((keyLen == 128) || (keyLen == 192) || (keyLen == 256)))
+ return -1;
+
+ if (keyMaterial == NULL)
+ return -1;
+
+ /* initialize key schedule: */
+ for (i=0; i<keyLen/8; i++) {
+ j = keyMaterial[i];
+ k[i % 4][i / 4] = j;
+ }
+
+ mv_aes_ksched(k, keyLen, W);
+ switch (keyLen) {
+ case 128:
+ rounds = 10;
+ KC = 4;
+ break;
+ case 192:
+ rounds = 12;
+ KC = 6;
+ break;
+ case 256:
+ rounds = 14;
+ KC = 8;
+ break;
+ default:
+ return -1;
+ }
+
+ for(i=0; i<MAXBC; i++)
+ for(j=0; j<4; j++)
+ expandedKey[i*4+j] = W[rounds][j][i];
+ for(; i<KC; i++)
+ for(j=0; j<4; j++)
+ expandedKey[i*4+j] = W[rounds-1][j][i+MAXBC-KC];
+
+ return 0;
+}
+
+/*
+ * Clear cipher/mac operation state
+ */
+INLINE void
+mvxpsec_packet_reset_op(struct mvxpsec_packet *mv_p)
+{
+ mv_p->pkt_header.desc.acc_config = 0;
+ mv_p->enc_off = mv_p->enc_ivoff = mv_p->enc_len = 0;
+ mv_p->mac_off = mv_p->mac_dst = mv_p->mac_len = 0;
+}
+
+/*
+ * update MVXPSEC operation order
+ */
+INLINE void
+mvxpsec_packet_update_op_order(struct mvxpsec_packet *mv_p, int op)
+{
+ struct mvxpsec_acc_descriptor *acc_desc = &mv_p->pkt_header.desc;
+ uint32_t cur_op = acc_desc->acc_config & MV_ACC_CRYPTO_OP_MASK;
+
+ KASSERT(op == MV_ACC_CRYPTO_OP_MAC || op == MV_ACC_CRYPTO_OP_ENC);
+ KASSERT((op & MV_ACC_CRYPTO_OP_MASK) == op);
+
+ if (cur_op == 0)
+ acc_desc->acc_config |= op;
+ else if (cur_op == MV_ACC_CRYPTO_OP_MAC && op == MV_ACC_CRYPTO_OP_ENC) {
+ acc_desc->acc_config &= ~MV_ACC_CRYPTO_OP_MASK;
+ acc_desc->acc_config |= MV_ACC_CRYPTO_OP_MACENC;
+ /* MAC then ENC (= decryption) */
+ }
+ else if (cur_op == MV_ACC_CRYPTO_OP_ENC && op == MV_ACC_CRYPTO_OP_MAC) {
+ acc_desc->acc_config &= ~MV_ACC_CRYPTO_OP_MASK;
+ acc_desc->acc_config |= MV_ACC_CRYPTO_OP_ENCMAC;
+ /* ENC then MAC (= encryption) */
+ }
+ else {
+ log(LOG_ERR, "%s: multiple %s algorithm is not supported.\n",
+ __func__,
+ (op == MV_ACC_CRYPTO_OP_ENC) ? "encryption" : "authentication");
+ }
+}
+
+/*
+ * Parameter Conversions
+ */
+INLINE uint32_t
+mvxpsec_alg2acc(uint32_t alg)
+{
+ uint32_t reg;
+
+ switch (alg) {
+ case CRYPTO_DES_CBC:
+ reg = MV_ACC_CRYPTO_ENC_DES;
+ reg |= MV_ACC_CRYPTO_CBC;
+ break;
+ case CRYPTO_3DES_CBC:
+ reg = MV_ACC_CRYPTO_ENC_3DES;
+ reg |= MV_ACC_CRYPTO_3DES_EDE;
+ reg |= MV_ACC_CRYPTO_CBC;
+ break;
+ case CRYPTO_AES_CBC:
+ reg = MV_ACC_CRYPTO_ENC_AES;
+ reg |= MV_ACC_CRYPTO_CBC;
+ break;
+ case CRYPTO_SHA1_HMAC_96:
+ reg = MV_ACC_CRYPTO_MAC_HMAC_SHA1;
+ reg |= MV_ACC_CRYPTO_MAC_96;
+ break;
+ case CRYPTO_MD5_HMAC_96:
+ reg = MV_ACC_CRYPTO_MAC_HMAC_MD5;
+ reg |= MV_ACC_CRYPTO_MAC_96;
+ break;
+ default:
+ reg = 0;
+ break;
+ }
+
+ return reg;
+}
+
+INLINE uint32_t
+mvxpsec_aesklen(int klen)
+{
+ if (klen < 128)
+ return 0;
+ else if (klen < 192)
+ return MV_ACC_CRYPTO_AES_KLEN_128;
+ else if (klen < 256)
+ return MV_ACC_CRYPTO_AES_KLEN_192;
+ else
+ return MV_ACC_CRYPTO_AES_KLEN_256;
+
+ return 0;
+}
+
+/*
+ * String Conversions
+ */
+STATIC const char *
+s_errreg(uint32_t v)
+{
+ static char buf[80];
+
+ snprintf(buf, sizeof(buf),
+ "%sMiss %sDoubleHit %sBothHit %sDataError",
+ (v & MV_TDMA_ERRC_MISS) ? "+" : "-",
+ (v & MV_TDMA_ERRC_DHIT) ? "+" : "-",
+ (v & MV_TDMA_ERRC_BHIT) ? "+" : "-",
+ (v & MV_TDMA_ERRC_DERR) ? "+" : "-");
+
+ return (const char *)buf;
+}
+
+STATIC const char *
+s_winreg(uint32_t v)
+{
+ static char buf[80];
+
+ snprintf(buf, sizeof(buf),
+ "%s TGT 0x%x ATTR 0x%02x size %u(0x%04x)[64KB]",
+ (v & MV_TDMA_ATTR_ENABLE) ? "EN" : "DIS",
+ MV_TDMA_ATTR_GET_TARGET(v), MV_TDMA_ATTR_GET_ATTR(v),
+ MV_TDMA_ATTR_GET_SIZE(v), MV_TDMA_ATTR_GET_SIZE(v));
+
+ return (const char *)buf;
+}
+
+STATIC const char *
+s_ctrlreg(uint32_t reg)
+{
+ static char buf[80];
+
+ snprintf(buf, sizeof(buf),
+ "%s: %sFETCH DBURST-%u SBURST-%u %sOUTS %sCHAIN %sBSWAP %sACT",
+ (reg & MV_TDMA_CONTROL_ENABLE) ? "ENABLE" : "DISABLE",
+ (reg & MV_TDMA_CONTROL_FETCH) ? "+" : "-",
+ MV_TDMA_CONTROL_GET_DST_BURST(reg),
+ MV_TDMA_CONTROL_GET_SRC_BURST(reg),
+ (reg & MV_TDMA_CONTROL_OUTS_EN) ? "+" : "-",
+ (reg & MV_TDMA_CONTROL_CHAIN_DIS) ? "-" : "+",
+ (reg & MV_TDMA_CONTROL_BSWAP_DIS) ? "-" : "+",
+ (reg & MV_TDMA_CONTROL_ACT) ? "+" : "-");
+
+ return (const char *)buf;
+}
+
+_STATIC const char *
+s_xpsecintr(uint32_t v)
+{
+ static char buf[160];
+
+ snprintf(buf, sizeof(buf),
+ "%sAuth %sDES %sAES-ENC %sAES-DEC %sENC %sSA %sAccAndTDMA "
+ "%sTDMAComp %sTDMAOwn %sAccAndTDMA_Cont",
+ (v & MVXPSEC_INT_AUTH) ? "+" : "-",
+ (v & MVXPSEC_INT_DES) ? "+" : "-",
+ (v & MVXPSEC_INT_AES_ENC) ? "+" : "-",
+ (v & MVXPSEC_INT_AES_DEC) ? "+" : "-",
+ (v & MVXPSEC_INT_ENC) ? "+" : "-",
+ (v & MVXPSEC_INT_SA) ? "+" : "-",
+ (v & MVXPSEC_INT_ACCTDMA) ? "+" : "-",
+ (v & MVXPSEC_INT_TDMA_COMP) ? "+" : "-",
+ (v & MVXPSEC_INT_TDMA_OWN) ? "+" : "-",
+ (v & MVXPSEC_INT_ACCTDMA_CONT) ? "+" : "-");
+
+ return (const char *)buf;
+}
+
+STATIC const char *
+s_ctlalg(uint32_t alg)
+{
+ switch (alg) {
+ case CRYPTO_SHA1_HMAC_96:
+ return "HMAC-SHA1-96";
+ case CRYPTO_SHA1_HMAC:
+ return "HMAC-SHA1";
+ case CRYPTO_SHA1:
+ return "SHA1";
+ case CRYPTO_MD5_HMAC_96:
+ return "HMAC-MD5-96";
+ case CRYPTO_MD5_HMAC:
+ return "HMAC-MD5";
+ case CRYPTO_MD5:
+ return "MD5";
+ case CRYPTO_DES_CBC:
+ return "DES-CBC";
+ case CRYPTO_3DES_CBC:
+ return "3DES-CBC";
+ case CRYPTO_AES_CBC:
+ return "AES-CBC";
+ default:
+ break;
+ }
+
+ return "Unknown";
+}
+
+STATIC const char *
+s_xpsec_op(uint32_t reg)
+{
+ reg &= MV_ACC_CRYPTO_OP_MASK;
+ switch (reg) {
+ case MV_ACC_CRYPTO_OP_ENC:
+ return "ENC";
+ case MV_ACC_CRYPTO_OP_MAC:
+ return "MAC";
+ case MV_ACC_CRYPTO_OP_ENCMAC:
+ return "ENC-MAC";
+ case MV_ACC_CRYPTO_OP_MACENC:
+ return "MAC-ENC";
+ default:
+ break;
+ }
+
+ return "Unknown";
+
+}
+
+STATIC const char *
+s_xpsec_enc(uint32_t alg)
+{
+ alg <<= MV_ACC_CRYPTO_ENC_SHIFT;
+ switch (alg) {
+ case MV_ACC_CRYPTO_ENC_DES:
+ return "DES";
+ case MV_ACC_CRYPTO_ENC_3DES:
+ return "3DES";
+ case MV_ACC_CRYPTO_ENC_AES:
+ return "AES";
+ default:
+ break;
+ }
+
+ return "Unknown";
+}
+
+STATIC const char *
+s_xpsec_mac(uint32_t alg)
+{
+ alg <<= MV_ACC_CRYPTO_MAC_SHIFT;
+ switch (alg) {
+ case MV_ACC_CRYPTO_MAC_NONE:
+ return "Disabled";
+ case MV_ACC_CRYPTO_MAC_MD5:
+ return "MD5";
+ case MV_ACC_CRYPTO_MAC_SHA1:
+ return "SHA1";
+ case MV_ACC_CRYPTO_MAC_HMAC_MD5:
+ return "HMAC-MD5";
+ case MV_ACC_CRYPTO_MAC_HMAC_SHA1:
+ return "HMAC-SHA1";
+ default:
+ break;
+ }
+
+ return "Unknown";
+}
+
+STATIC const char *
+s_xpsec_frag(uint32_t frag)
+{
+ frag <<= MV_ACC_CRYPTO_FRAG_SHIFT;
+ switch (frag) {
+ case MV_ACC_CRYPTO_NOFRAG:
+ return "NoFragment";
+ case MV_ACC_CRYPTO_FRAG_FIRST:
+ return "FirstFragment";
+ case MV_ACC_CRYPTO_FRAG_MID:
+ return "MiddleFragment";
+ case MV_ACC_CRYPTO_FRAG_LAST:
+ return "LastFragment";
+ default:
+ break;
+ }
+
+ return "Unknown";
+}
+
+#ifdef MVXPSEC_DEBUG
+void
+mvxpsec_dump_reg(struct mvxpsec_softc *sc)
+{
+ uint32_t reg;
+ int i;
+
+ if ((mvxpsec_debug & MVXPSEC_DEBUG_DESC) == 0)
+ return;
+
+ printf("--- Interrupt Registers ---\n");
+ reg = MVXPSEC_READ(sc, MVXPSEC_INT_CAUSE);
+ printf("MVXPSEC INT CAUSE: 0x%08x\n", reg);
+ printf("MVXPSEC INT CAUSE: %s\n", s_xpsecintr(reg));
+ reg = MVXPSEC_READ(sc, MVXPSEC_INT_MASK);
+ printf("MVXPSEC INT MASK: 0x%08x\n", reg);
+ printf("MVXPSEC INT MASKE: %s\n", s_xpsecintr(reg));
+
+ printf("--- DMA Configuration Registers ---\n");
+ for (i = 0; i < MV_TDMA_NWINDOW; i++) {
+ reg = MVXPSEC_READ(sc, MV_TDMA_BAR(i));
+ printf("TDMA BAR%d: 0x%08x\n", i, reg);
+ reg = MVXPSEC_READ(sc, MV_TDMA_ATTR(i));
+ printf("TDMA ATTR%d: 0x%08x\n", i, reg);
+ printf(" -> %s\n", s_winreg(reg));
+ }
+
+ printf("--- DMA Control Registers ---\n");
+
+ reg = MVXPSEC_READ(sc, MV_TDMA_CONTROL);
+ printf("TDMA CONTROL: 0x%08x\n", reg);
+ printf(" -> %s\n", s_ctrlreg(reg));
+
+ printf("--- DMA Current Command Descriptors ---\n");
+
+ reg = MVXPSEC_READ(sc, MV_TDMA_ERR_CAUSE);
+ printf("TDMA ERR CAUSE: 0x%08x\n", reg);
+
+ reg = MVXPSEC_READ(sc, MV_TDMA_ERR_MASK);
+ printf("TDMA ERR MASK: 0x%08x\n", reg);
+
+ reg = MVXPSEC_READ(sc, MV_TDMA_CNT);
+ printf("TDMA DATA OWNER: %s\n",
+ (reg & MV_TDMA_CNT_OWN) ? "DMAC" : "CPU");
+ printf("TDMA DATA COUNT: %d(0x%x)\n",
+ (reg & ~MV_TDMA_CNT_OWN), (reg & ~MV_TDMA_CNT_OWN));
+
+ reg = MVXPSEC_READ(sc, MV_TDMA_SRC);
+ printf("TDMA DATA SRC: 0x%08x\n", reg);
+
+ reg = MVXPSEC_READ(sc, MV_TDMA_DST);
+ printf("TDMA DATA DST: 0x%08x\n", reg);
+
+ reg = MVXPSEC_READ(sc, MV_TDMA_NXT);
+ printf("TDMA DATA NXT: 0x%08x\n", reg);
+
+ reg = MVXPSEC_READ(sc, MV_TDMA_CUR);
+ printf("TDMA DATA CUR: 0x%08x\n", reg);
+
+ printf("--- ACC Command Register ---\n");
+ reg = MVXPSEC_READ(sc, MV_ACC_COMMAND);
+ printf("ACC COMMAND: 0x%08x\n", reg);
+ printf("ACC: %sACT %sSTOP\n",
+ (reg & MV_ACC_COMMAND_ACT) ? "+" : "-",
+ (reg & MV_ACC_COMMAND_STOP) ? "+" : "-");
+
+ reg = MVXPSEC_READ(sc, MV_ACC_CONFIG);
+ printf("ACC CONFIG: 0x%08x\n", reg);
+ reg = MVXPSEC_READ(sc, MV_ACC_DESC);
+ printf("ACC DESC: 0x%08x\n", reg);
+
+ printf("--- DES Key Register ---\n");
+ reg = MVXPSEC_READ(sc, MV_CE_DES_KEY0L);
+ printf("DES KEY0 Low: 0x%08x\n", reg);
+ reg = MVXPSEC_READ(sc, MV_CE_DES_KEY0H);
+ printf("DES KEY0 High: 0x%08x\n", reg);
+ reg = MVXPSEC_READ(sc, MV_CE_DES_KEY1L);
+ printf("DES KEY1 Low: 0x%08x\n", reg);
+ reg = MVXPSEC_READ(sc, MV_CE_DES_KEY1H);
+ printf("DES KEY1 High: 0x%08x\n", reg);
+ reg = MVXPSEC_READ(sc, MV_CE_DES_KEY2L);
+ printf("DES KEY2 Low: 0x%08x\n", reg);
+ reg = MVXPSEC_READ(sc, MV_CE_DES_KEY2H);
+ printf("DES KEY2 High: 0x%08x\n", reg);
+
+ printf("--- AES Key Register ---\n");
+ for (i = 0; i < 8; i++) {
+ reg = MVXPSEC_READ(sc, MV_CE_AES_EKEY(i));
+ printf("AES ENC KEY COL%d: %08x\n", i, reg);
+ }
+ for (i = 0; i < 8; i++) {
+ reg = MVXPSEC_READ(sc, MV_CE_AES_DKEY(i));
+ printf("AES DEC KEY COL%d: %08x\n", i, reg);
+ }
+
+ return;
+}
+
+STATIC void
+mvxpsec_dump_sram(const char *name, struct mvxpsec_softc *sc, size_t len)
+{
+ uint32_t reg;
+
+ if (sc->sc_sram_va == NULL)
+ return;
+
+ if (len == 0) {
+ printf("\n%s NO DATA(len=0)\n", name);
+ return;
+ }
+ else if (len > MV_ACC_SRAM_SIZE)
+ len = MV_ACC_SRAM_SIZE;
+
+ mutex_enter(&sc->sc_dma_mtx);
+ reg = MVXPSEC_READ(sc, MV_TDMA_CONTROL);
+ if (reg & MV_TDMA_CONTROL_ACT) {
+ printf("TDMA is active, cannot access SRAM\n");
+ mutex_exit(&sc->sc_dma_mtx);
+ return;
+ }
+ reg = MVXPSEC_READ(sc, MV_ACC_COMMAND);
+ if (reg & MV_ACC_COMMAND_ACT) {
+ printf("SA is active, cannot access SRAM\n");
+ mutex_exit(&sc->sc_dma_mtx);
+ return;
+ }
+
+ printf("%s: dump SRAM, %zu bytes\n", name, len);
+ mvxpsec_dump_data(name, sc->sc_sram_va, len);
+ mutex_exit(&sc->sc_dma_mtx);
+ return;
+}
+
+
+_STATIC void
+mvxpsec_dump_dmaq(struct mvxpsec_descriptor_handle *dh)
+{
+ struct mvxpsec_descriptor *d =
+ (struct mvxpsec_descriptor *)dh->_desc;
+
+ printf("--- DMA Command Descriptor ---\n");
+ printf("DESC: VA=%p PA=0x%08x\n",
+ d, (uint32_t)dh->phys_addr);
+ printf("DESC: WORD0 = 0x%08x\n", d->tdma_word0);
+ printf("DESC: SRC = 0x%08x\n", d->tdma_src);
+ printf("DESC: DST = 0x%08x\n", d->tdma_dst);
+ printf("DESC: NXT = 0x%08x\n", d->tdma_nxt);
+
+ return;
+}
+
+STATIC void
+mvxpsec_dump_data(const char *name, void *p, size_t len)
+{
+ uint8_t *data = p;
+ off_t off;
+
+ printf("%s: dump %p, %zu bytes", name, p, len);
+ if (p == NULL || len == 0) {
+ printf("\n%s: NO DATA\n", name);
+ return;
+ }
+ for (off = 0; off < len; off++) {
+ if ((off % 16) == 0) {
+ printf("\n%s: 0x%08x:", name, (uint32_t)off);
+ }
+ if ((off % 4) == 0) {
+ printf(" ");
+ }
+ printf("%02x", data[off]);
+ }
+ printf("\n");
+
+ return;
+}
+
+_STATIC void
+mvxpsec_dump_packet(const char *name, struct mvxpsec_packet *mv_p)
+{
+ struct mvxpsec_softc *sc = mv_p->mv_s->sc;
+
+ printf("%s: packet_data:\n", name);
+ mvxpsec_dump_packet_data(name, mv_p);
+
+ printf("%s: SRAM:\n", name);
+ mvxpsec_dump_sram(name, sc, 2000);
+
+ printf("%s: packet_descriptor:\n", name);
+ mvxpsec_dump_packet_desc(name, mv_p);
+}
+
+_STATIC void
+mvxpsec_dump_packet_data(const char *name, struct mvxpsec_packet *mv_p)
+{
+ static char buf[1500];
+ int len;
+
+ if (mv_p->data_type == MVXPSEC_DATA_MBUF) {
+ struct mbuf *m;
+
+ m = mv_p->data.mbuf;
+ len = m->m_pkthdr.len;
+ if (len > sizeof(buf))
+ len = sizeof(buf);
+ m_copydata(m, 0, len, buf);
+ }
+ else if (mv_p->data_type == MVXPSEC_DATA_UIO) {
+ struct uio *uio;
+
+ uio = mv_p->data.uio;
+ len = uio->uio_resid;
+ if (len > sizeof(buf))
+ len = sizeof(buf);
+ cuio_copydata(uio, 0, len, buf);
+ }
+ else if (mv_p->data_type == MVXPSEC_DATA_RAW) {
+ len = mv_p->data_len;
+ if (len > sizeof(buf))
+ len = sizeof(buf);
+ memcpy(buf, mv_p->data.raw, len);
+ }
+ else
+ return;
+ mvxpsec_dump_data(name, buf, len);
+
+ return;
+}
+
+_STATIC void
+mvxpsec_dump_packet_desc(const char *name, struct mvxpsec_packet *mv_p)
+{
+ uint32_t *words;
+
+ if (mv_p == NULL)
+ return;
+
+ words = &mv_p->pkt_header.desc.acc_desc_dword0;
+ mvxpsec_dump_acc_config(name, words[0]);
+ mvxpsec_dump_acc_encdata(name, words[1], words[2]);
+ mvxpsec_dump_acc_enclen(name, words[2]);
+ mvxpsec_dump_acc_enckey(name, words[3]);
+ mvxpsec_dump_acc_enciv(name, words[4]);
+ mvxpsec_dump_acc_macsrc(name, words[5]);
+ mvxpsec_dump_acc_macdst(name, words[6]);
+ mvxpsec_dump_acc_maciv(name, words[7]);
+
+ return;
+}
+
+_STATIC void
+mvxpsec_dump_acc_config(const char *name, uint32_t w)
+{
+ /* SA: Dword 0 */
+ printf("%s: Dword0=0x%08x\n", name, w);
+ printf("%s: OP = %s\n", name,
+ s_xpsec_op(MV_ACC_CRYPTO_OP(w)));
+ printf("%s: MAC = %s\n", name,
+ s_xpsec_mac(MV_ACC_CRYPTO_MAC(w)));
+ printf("%s: MAC_LEN = %s\n", name,
+ w & MV_ACC_CRYPTO_MAC_96 ? "96-bit" : "full-bit");
+ printf("%s: ENC = %s\n", name,
+ s_xpsec_enc(MV_ACC_CRYPTO_ENC(w)));
+ printf("%s: DIR = %s\n", name,
+ w & MV_ACC_CRYPTO_DECRYPT ? "decryption" : "encryption");
+ printf("%s: CHAIN = %s\n", name,
+ w & MV_ACC_CRYPTO_CBC ? "CBC" : "ECB");
+ printf("%s: 3DES = %s\n", name,
+ w & MV_ACC_CRYPTO_3DES_EDE ? "EDE" : "EEE");
+ printf("%s: FRAGMENT = %s\n", name,
+ s_xpsec_frag(MV_ACC_CRYPTO_FRAG(w)));
+ return;
+}
+
+STATIC void
+mvxpsec_dump_acc_encdata(const char *name, uint32_t w, uint32_t w2)
+{
+ /* SA: Dword 1 */
+ printf("%s: Dword1=0x%08x\n", name, w);
+ printf("%s: ENC SRC = 0x%x\n", name, MV_ACC_DESC_GET_VAL_1(w));
+ printf("%s: ENC DST = 0x%x\n", name, MV_ACC_DESC_GET_VAL_2(w));
+ printf("%s: ENC RANGE = 0x%x - 0x%x\n", name,
+ MV_ACC_DESC_GET_VAL_1(w),
+ MV_ACC_DESC_GET_VAL_1(w) + MV_ACC_DESC_GET_VAL_1(w2) - 1);
+ return;
+}
+
+STATIC void
+mvxpsec_dump_acc_enclen(const char *name, uint32_t w)
+{
+ /* SA: Dword 2 */
+ printf("%s: Dword2=0x%08x\n", name, w);
+ printf("%s: ENC LEN = %d\n", name,
+ MV_ACC_DESC_GET_VAL_1(w));
+ return;
+}
+
+STATIC void
+mvxpsec_dump_acc_enckey(const char *name, uint32_t w)
+{
+ /* SA: Dword 3 */
+ printf("%s: Dword3=0x%08x\n", name, w);
+ printf("%s: EKEY = 0x%x\n", name,
+ MV_ACC_DESC_GET_VAL_1(w));
+ return;
+}
+
+STATIC void
+mvxpsec_dump_acc_enciv(const char *name, uint32_t w)
+{
+ /* SA: Dword 4 */
+ printf("%s: Dword4=0x%08x\n", name, w);
+ printf("%s: EIV = 0x%x\n", name, MV_ACC_DESC_GET_VAL_1(w));
+ printf("%s: EIV_BUF = 0x%x\n", name, MV_ACC_DESC_GET_VAL_2(w));
+ return;
+}
+
+STATIC void
+mvxpsec_dump_acc_macsrc(const char *name, uint32_t w)
+{
+ /* SA: Dword 5 */
+ printf("%s: Dword5=0x%08x\n", name, w);
+ printf("%s: MAC_SRC = 0x%x\n", name,
+ MV_ACC_DESC_GET_VAL_1(w));
+ printf("%s: MAC_TOTAL_LEN = %d\n", name,
+ MV_ACC_DESC_GET_VAL_3(w));
+ printf("%s: MAC_RANGE = 0x%0x - 0x%0x\n", name,
+ MV_ACC_DESC_GET_VAL_1(w),
+ MV_ACC_DESC_GET_VAL_1(w) + MV_ACC_DESC_GET_VAL_3(w) - 1);
+ return;
+}
+
+STATIC void
+mvxpsec_dump_acc_macdst(const char *name, uint32_t w)
+{
+ /* SA: Dword 6 */
+ printf("%s: Dword6=0x%08x\n", name, w);
+ printf("%s: MAC_DST = 0x%x\n", name, MV_ACC_DESC_GET_VAL_1(w));
+ printf("%s: MAC_BLOCK_LEN = %d\n", name,
+ MV_ACC_DESC_GET_VAL_2(w));
+ return;
+}
+
+STATIC void
+mvxpsec_dump_acc_maciv(const char *name, uint32_t w)
+{
+ /* SA: Dword 7 */
+ printf("%s: Dword7=0x%08x\n", name, w);
+ printf("%s: MAC_INNER_IV = 0x%x\n", name,
+ MV_ACC_DESC_GET_VAL_1(w));
+ printf("%s: MAC_OUTER_IV = 0x%x\n", name,
+ MV_ACC_DESC_GET_VAL_2(w));
+ return;
+}
+#endif
+
Index: src/sys/dev/marvell/mvxpsecreg.h
diff -u /dev/null src/sys/dev/marvell/mvxpsecreg.h:1.1
--- /dev/null Wed Jun 3 04:20:02 2015
+++ src/sys/dev/marvell/mvxpsecreg.h Wed Jun 3 04:20:02 2015
@@ -0,0 +1,270 @@
+/* $NetBSD: mvxpsecreg.h,v 1.1 2015/06/03 04:20:02 hsuenaga Exp $ */
+/*
+ * Copyright (c) 2015 Internet Initiative Japan Inc.
+ * 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.
+ */
+/*
+ * Cryptographic Engine and Security Accelerator(CESA)
+ */
+
+#ifndef __MVXPSECREG_H__
+#define __MVXPSECREG_H__
+
+/* Security Accelerator */
+#define MV_ACC_COMMAND 0xDE00
+#define MV_ACC_COMMAND_ACT (0x01 << 0)
+#define MV_ACC_COMMAND_STOP (0x01 << 2)
+
+#define MV_ACC_DESC 0xDE04
+#define MV_ACC_DESC_MASK 0x0000ffff
+
+#define MV_ACC_CONFIG 0xDE08
+#define MV_ACC_CONFIG_STOP_ON_ERR (0x01 << 0)
+#define MV_ACC_CONFIG_WAIT_TDMA (0x01 << 7)
+#define MV_ACC_CONFIG_ACT_TDMA (0x01 << 9)
+#define MV_ACC_CONFIG_MULT_PKT (0x01 << 11)
+
+#define MV_ACC_STATUS 0xDE0C
+#define MV_ACC_STATUS_ACC_ACT (0x01 << 1)
+#define MV_ACC_STATUS_MAC_ERR (0x01 << 8)
+#define MV_ACC_STATUS_ACT_STATUS_MASK 0x0007ffff
+#define MV_ACC_STATUS_ACT_STATUS_SHIFT 13
+
+/* Security Accelerator Algorithms */
+/* XXX: simplify shift operation.... */
+#define MV_ACC_CRYPTO_OP_MASK 0x03
+#define MV_ACC_CRYPTO_OP_SHIFT 0
+#define MV_ACC_CRYPTO_OP_MAC (0x00 << MV_ACC_CRYPTO_OP_SHIFT)
+#define MV_ACC_CRYPTO_OP_ENC (0x01 << MV_ACC_CRYPTO_OP_SHIFT)
+#define MV_ACC_CRYPTO_OP_MACENC (0x02 << MV_ACC_CRYPTO_OP_SHIFT)
+#define MV_ACC_CRYPTO_OP_ENCMAC (0x03 << MV_ACC_CRYPTO_OP_SHIFT)
+#define MV_ACC_CRYPTO_OP(x) \
+ (((x) & (MV_ACC_CRYPTO_OP_MASK << MV_ACC_CRYPTO_OP_SHIFT)) \
+ >> MV_ACC_CRYPTO_OP_SHIFT)
+
+#define MV_ACC_CRYPTO_MAC_MASK 0x07
+#define MV_ACC_CRYPTO_MAC_SHIFT 4
+#define MV_ACC_CRYPTO_MAC_NONE 0
+#define MV_ACC_CRYPTO_MAC_SHA2 (0x01 << MV_ACC_CRYPTO_MAC_SHIFT)
+#define MV_ACC_CRYPTO_MAC_HMAC_SHA2 (0x03 << MV_ACC_CRYPTO_MAC_SHIFT)
+#define MV_ACC_CRYPTO_MAC_MD5 (0x04 << MV_ACC_CRYPTO_MAC_SHIFT)
+#define MV_ACC_CRYPTO_MAC_SHA1 (0x05 << MV_ACC_CRYPTO_MAC_SHIFT)
+#define MV_ACC_CRYPTO_MAC_HMAC_MD5 (0x06 << MV_ACC_CRYPTO_MAC_SHIFT)
+#define MV_ACC_CRYPTO_MAC_HMAC_SHA1 (0x07 << MV_ACC_CRYPTO_MAC_SHIFT)
+#define MV_ACC_CRYPTO_MAC(x) \
+ (((x) & (MV_ACC_CRYPTO_MAC_MASK << MV_ACC_CRYPTO_MAC_SHIFT)) \
+ >> MV_ACC_CRYPTO_MAC_SHIFT)
+#define MV_ACC_CRYPTO_MAC_SET(dst, x) \
+ do { \
+ (dst) &= ~(MV_ACC_CRYPTO_MAC_MASK << MV_ACC_CRYPTO_MAC_SHIFT);\
+ (dst) |= \
+ ((x) & (MV_ACC_CRYPTO_MAC_MASK << MV_ACC_CRYPTO_MAC_SHIFT)); \
+ } while(0);
+
+#define MV_ACC_CRYPTO_ENC_MASK 0x03
+#define MV_ACC_CRYPTO_ENC_SHIFT 8
+#define MV_ACC_CRYPTO_ENC_NOP (0x00 << MV_ACC_CRYPTO_ENC_SHIFT)
+#define MV_ACC_CRYPTO_ENC_DES (0x01 << MV_ACC_CRYPTO_ENC_SHIFT)
+#define MV_ACC_CRYPTO_ENC_3DES (0x02 << MV_ACC_CRYPTO_ENC_SHIFT)
+#define MV_ACC_CRYPTO_ENC_AES (0x03 << MV_ACC_CRYPTO_ENC_SHIFT)
+#define MV_ACC_CRYPTO_ENC(x) \
+ (((x) & (MV_ACC_CRYPTO_ENC_MASK << MV_ACC_CRYPTO_ENC_SHIFT)) \
+ >> MV_ACC_CRYPTO_ENC_SHIFT)
+#define MV_ACC_CRYPTO_ENC_SET(dst, x) \
+ do { \
+ (dst) &= ~(MV_ACC_CRYPTO_ENC_MASK << MV_ACC_CRYPTO_ENC_SHIFT);\
+ (dst) |= \
+ ((x) & (MV_ACC_CRYPTO_ENC_MASK << MV_ACC_CRYPTO_ENC_SHIFT));\
+ } while(0);
+
+/* this is not described in the document.... FUUUUUUUUUUUUCK! */
+#define MV_ACC_CRYPTO_AES_KLEN_MASK 0x03
+#define MV_ACC_CRYPTO_AES_KLEN_SHIFT 24
+#define MV_ACC_CRYPTO_AES_KLEN_128 \
+ (0x00 << MV_ACC_CRYPTO_AES_KLEN_SHIFT)
+#define MV_ACC_CRYPTO_AES_KLEN_192 \
+ (0x01 << MV_ACC_CRYPTO_AES_KLEN_SHIFT)
+#define MV_ACC_CRYPTO_AES_KLEN_256 \
+ (0x02 << MV_ACC_CRYPTO_AES_KLEN_SHIFT)
+#define MV_ACC_CRYPTO_AES_KLEN(x) \
+ (((x) & (MV_ACC_CRYPTO_AES_KLEN_MASK << MV_ACC_CRYPTO_AES_KLEN_SHIFT)) \
+ >> MV_ACC_CRYPTO_AES_KLEN_SHIFT)
+#define MV_ACC_CRYPTO_AES_KLEN_SET(dst, x) \
+ do { \
+ (dst) &= \
+ ~(MV_ACC_CRYPTO_AES_KLEN_MASK << MV_ACC_CRYPTO_AES_KLEN_SHIFT); \
+ (dst) |= \
+ ((x) & \
+ (MV_ACC_CRYPTO_AES_KLEN_MASK << MV_ACC_CRYPTO_AES_KLEN_SHIFT)); \
+ } while(0);
+
+#define MV_ACC_CRYPTO_MAC_96 __BIT(7)
+#define MV_ACC_CRYPTO_DECRYPT __BIT(12)
+#define MV_ACC_CRYPTO_CBC __BIT(16)
+#define MV_ACC_CRYPTO_3DES_EDE __BIT(20)
+
+/* Security Accelerator Descriptors */
+/* Algorithm names are defined in mviicesa.h */
+#define MV_ACC_CRYPTO_FRAG_MASK 0x03
+#define MV_ACC_CRYPTO_FRAG_SHIFT 30
+#define MV_ACC_CRYPTO_NOFRAG (0x00 << MV_ACC_CRYPTO_FRAG_SHIFT)
+#define MV_ACC_CRYPTO_FRAG_FIRST (0x01 << MV_ACC_CRYPTO_FRAG_SHIFT)
+#define MV_ACC_CRYPTO_FRAG_LAST (0x02 << MV_ACC_CRYPTO_FRAG_SHIFT)
+#define MV_ACC_CRYPTO_FRAG_MID (0x03 << MV_ACC_CRYPTO_FRAG_SHIFT)
+#define MV_ACC_CRYPTO_FRAG(x) \
+ (((x) & (MV_ACC_CRYPTO_FRAG_MASK << MV_ACC_CRYPTO_FRAG_SHIFT)) \
+ >> MV_ACC_CRYPTO_FRAG_SHIFT)
+
+#define MV_ACC_DESC_VAL_1(x) ((x) & 0x7ff)
+#define MV_ACC_DESC_VAL_2(x) (((x) & 0x7ff) << 16)
+#define MV_ACC_DESC_VAL_3(x) (((x) & 0xffff) << 16)
+#define MV_ACC_DESC_GET_VAL_1(x) ((x) & 0x7ff)
+#define MV_ACC_DESC_GET_VAL_2(x) (((x) & (0x7ff << 16)) >> 16)
+#define MV_ACC_DESC_GET_VAL_3(x) (((x) & (0xffff << 16)) >> 16)
+
+#define MV_ACC_DESC_ENC_DATA(src, dst) \
+ (MV_ACC_DESC_VAL_1(src) | MV_ACC_DESC_VAL_2(dst))
+#define MV_ACC_DESC_ENC_LEN(len) \
+ (MV_ACC_DESC_VAL_1(len))
+#define MV_ACC_DESC_ENC_KEY(key) \
+ (MV_ACC_DESC_VAL_1(key))
+#define MV_ACC_DESC_ENC_IV(iv_e, iv_d) \
+ (MV_ACC_DESC_VAL_1(iv_e) | MV_ACC_DESC_VAL_2(iv_d))
+
+#define MV_ACC_DESC_MAC_SRC(src, len) \
+ (MV_ACC_DESC_VAL_1(src) | MV_ACC_DESC_VAL_3(len))
+#define MV_ACC_DESC_MAC_DST(dst, len) \
+ (MV_ACC_DESC_VAL_1(dst) | MV_ACC_DESC_VAL_2(len))
+#define MV_ACC_DESC_MAC_IV(iv_in, iv_out) \
+ (MV_ACC_DESC_VAL_1(iv_in) | MV_ACC_DESC_VAL_2(iv_out))
+
+#define MV_ACC_SRAM_SIZE 2048
+
+/* Interrupt Cause */
+#define MVXPSEC_INT_CAUSE 0xDE20
+#define MVXPSEC_INT_MASK 0xDE24
+
+/* ENGINE interrupts */
+#define MVXPSEC_INT_AUTH __BIT(0)
+#define MVXPSEC_INT_DES __BIT(1)
+#define MVXPSEC_INT_AES_ENC __BIT(2)
+#define MVXPSEC_INT_AES_DEC __BIT(3)
+#define MVXPSEC_INT_ENC __BIT(4)
+#define MVXPSEC_INT_ENGINE \
+ (MVXPSEC_INT_AUTH | MVXPSEC_INT_ENC | \
+ MVXPSEC_INT_DES | MVXPSEC_INT_AES_ENC | MVXPSEC_INT_AES_DEC)
+
+/* Security Accelerator interrupts */
+#define MVXPSEC_INT_SA __BIT(5)
+#define MVXPSEC_INT_ACCTDMA __BIT(7)
+#define MVXPSEC_INT_ACCTDMA_CONT __BIT(11)
+#define MVXPSEC_INT_COAL __BIT(14)
+
+/* TDMA interrupts */
+#define MVXPSEC_INT_TDMA_COMP __BIT(9)
+#define MVXPSEC_INT_TDMA_OWN __BIT(10)
+
+#define MVXPSEC_INT_ACC \
+ (MVXPSEC_INT_SA | MVXPSEC_INT_ACCTDMA | MVXPSEC_INT_ACCTDMA_CONT)
+
+#define MVXPSEC_INT_TDMA \
+ (MVXPSEC_INT_TDMA_COMP | MVXPSEC_INT_TDMA_OWN)
+
+#define MVXPSEC_INT_ALL \
+ (MVXPSEC_INT_ENGINE | MVXPSEC_INT_ACC | MVXPSEC_INT_TDMA)
+
+/*
+ * TDMA Controllers
+ */
+/* TDMA Address */
+#define MV_TDMA_NWINDOW 4
+#define MV_TDMA_BAR(window) (0x0A00 + (window) * 8)
+#define MV_TDMA_BAR_BASE_MASK __BITS(31,16)
+#define MV_TDMA_BAR_BASE(base) ((base) & MV_TDMA_BAR_BASE_MASK)
+#define MV_TDMA_ATTR(window) (0x0A04 + (window) * 8)
+#define MV_TDMA_ATTR_SIZE_MASK __BITS(31,16)
+#define MV_TDMA_ATTR_ATTR_MASK __BITS(31,16)
+#define MV_TDMA_ATTR_ENABLE __BIT(0)
+#define MV_TDMA_ATTR_SIZE(size) ((((size - 1) >> 16) & 0xffff) << 16)
+#define MV_TDMA_ATTR_ATTR(attr) (((attr) & 0xff) << 8)
+#define MV_TDMA_ATTR_TARGET(target) (((target) & 0xf) << 4)
+#define MV_TDMA_ATTR_GET_SIZE(reg) (((reg) >> 16) & 0xffff)
+#define MV_TDMA_ATTR_GET_ATTR(reg) (((reg) >> 8) & 0xff)
+#define MV_TDMA_ATTR_GET_TARGET(reg) (((reg) >> 4) & 0xf)
+
+/* TDMA Control */
+#define MV_TDMA_CONTROL 0x0840
+
+#define MV_TDMA_CONTROL_DST_BURST_MASK __BITS(2,0)
+#define MV_TDMA_CONTROL_DST_BURST_32 0x3
+#define MV_TDMA_CONTROL_DST_BURST_128 0x4
+#define MV_TDMA_CONTROL_GET_DST_BURST(reg) \
+ ((uint32_t)(((reg) & MV_TDMA_CONTROL_DST_BURST_MASK) >> 0))
+#define MV_TDMA_CONTROL_OUTS_EN __BIT(4)
+#define MV_TDMA_CONTROL_SRC_BURST_MASK __BITS(8,6)
+#define MV_TDMA_CONTROL_SRC_BURST_32 (0x3 << 6)
+#define MV_TDMA_CONTROL_SRC_BURST_128 (0x4 << 6)
+#define MV_TDMA_CONTROL_GET_SRC_BURST(reg) \
+ ((uint32_t)(((reg) & MV_TDMA_CONTROL_SRC_BURST_MASK) >> 6))
+#define MV_TDMA_CONTROL_CHAIN_DIS __BIT(9)
+#define MV_TDMA_CONTROL_BSWAP_DIS __BIT(11)
+#define MV_TDMA_CONTROL_ENABLE __BIT(12)
+#define MV_TDMA_CONTROL_FETCH __BIT(13)
+#define MV_TDMA_CONTROL_ACT __BIT(14)
+#define MV_TDMA_CONTROL_OUTS_MODE_MASK __BITS(17,16)
+#define MV_TDMA_CONTROL_OUTS_MODE_4OUTS (3 << 16)
+
+/* TDMA Descriptor Registers */
+#define MV_TDMA_CNT 0x0800
+#define MV_TDMA_SRC 0x0810
+#define MV_TDMA_DST 0x0820
+#define MV_TDMA_NXT 0x0830
+#define MV_TDMA_CUR 0x0870
+
+#define MV_TDMA_CNT_OWN (1 << 31)
+
+/* TDMA Interrupt */
+#define MV_TDMA_ERR_CAUSE 0x08C8
+#define MV_TDMA_ERR_MASK 0x08CC
+
+#define MV_TDMA_ERRC_MISS 0x01
+#define MV_TDMA_ERRC_DHIT 0x02
+#define MV_TDMA_ERRC_BHIT 0x04
+#define MV_TDMA_ERRC_DERR 0x08
+#define MV_TDMA_ERRC_ALL \
+ (MV_TDMA_ERRC_MISS | MV_TDMA_ERRC_DHIT | MV_TDMA_ERRC_BHIT | \
+ MV_TDMA_ERRC_DERR)
+
+/* Crypto Engine Registers (just for debug) */
+#define MV_CE_DES_KEY0L 0xdd48
+#define MV_CE_DES_KEY0H 0xdd4c
+#define MV_CE_DES_KEY1L 0xdd50
+#define MV_CE_DES_KEY1H 0xdd54
+#define MV_CE_DES_KEY2L 0xdd60
+#define MV_CE_DES_KEY2H 0xdd64
+
+#define MV_CE_AES_EKEY(n) (0xdd80 + (4 * (7 - (n))))
+#define MV_CE_AES_DKEY(n) (0xddc0 + (4 * (7 - (n))))
+
+#endif /* __MVXPSECREG_H__ */
Index: src/sys/dev/marvell/mvxpsecvar.h
diff -u /dev/null src/sys/dev/marvell/mvxpsecvar.h:1.1
--- /dev/null Wed Jun 3 04:20:02 2015
+++ src/sys/dev/marvell/mvxpsecvar.h Wed Jun 3 04:20:02 2015
@@ -0,0 +1,511 @@
+/* $NetBSD: mvxpsecvar.h,v 1.1 2015/06/03 04:20:02 hsuenaga Exp $ */
+/*
+ * Copyright (c) 2015 Internet Initiative Japan Inc.
+ * 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.
+ */
+
+/*
+ * Cryptographic Engine and Security Accelerator(CESA)
+ */
+#ifndef __MVXPSECVAR_H__
+#define __MVXPSECVAR_H__
+#include <sys/device.h>
+#include <dev/marvell/mvxpsecreg.h>
+
+/*
+ * Compile time options
+ */
+/* use multi-packet chained mode */
+#define MVXPSEC_MULTI_PACKET
+#define MVXPSEC_EVENT_COUNTERS
+
+/*
+ * Memory management
+ */
+struct mvxpsec_devmem {
+ bus_dmamap_t map;
+ void *kva;
+ int size;
+};
+#define dm_paddr dm_segs[0].ds_addr
+#define devmem_va(x) ((x)->kva)
+#define devmem_nseg(x) ((x)->map->dm_nsegs)
+#define devmem_pa(x, s) ((x)->map->dm_segs[(s)].ds_addr)
+#define devmem_palen(x, s) ((x)->map->dm_segs[(s)].ds_len)
+#define devmem_size(x) ((x)->size)
+#define devmem_map(x) ((x)->map)
+
+/*
+ * DMA Descriptors
+ */
+struct mvxpsec_descriptor {
+ uint32_t tdma_word0;
+ uint32_t tdma_src;
+ uint32_t tdma_dst;
+ uint32_t tdma_nxt;
+} __attribute__((__packed__));
+
+struct mvxpsec_descriptor_handle {
+ bus_dmamap_t map;
+ paddr_t phys_addr;
+ int off;
+
+ void *_desc;
+
+ SIMPLEQ_ENTRY(mvxpsec_descriptor_handle) chain;
+};
+SIMPLEQ_HEAD(mvxpsec_descriptor_list, mvxpsec_descriptor_handle);
+
+struct mvxpsec_descriptor_ring {
+ struct mvxpsec_descriptor_handle *dma_head;
+ struct mvxpsec_descriptor_handle *dma_last;
+ int dma_size;
+};
+
+#define MVXPSEC_SYNC_DESC(sc, x, f) \
+ do { \
+ bus_dmamap_sync((sc)->sc_dmat, (x)->map, \
+ (x)->off, sizeof(struct mvxpsec_descriptor), (f)); \
+ } while (0);
+
+typedef struct mvxpsec_descriptor_ring mvxpsec_dma_ring;
+
+#define MV_TDMA_DEFAULT_CONTROL \
+ ( MV_TDMA_CONTROL_DST_BURST_32 | \
+ MV_TDMA_CONTROL_SRC_BURST_32 | \
+ MV_TDMA_CONTROL_OUTS_EN | \
+ MV_TDMA_CONTROL_OUTS_MODE_4OUTS | \
+ MV_TDMA_CONTROL_BSWAP_DIS )
+
+/*
+ * Security Accelerator Descriptors
+ */
+struct mvxpsec_acc_descriptor {
+ uint32_t acc_config;
+ uint32_t acc_encdata;
+ uint32_t acc_enclen;
+ uint32_t acc_enckey;
+ uint32_t acc_enciv;
+ uint32_t acc_macsrc;
+ uint32_t acc_macdst;
+ uint32_t acc_maciv;
+#define acc_desc_dword0 acc_config
+#define acc_desc_dword1 acc_encdata
+#define acc_desc_dword2 acc_enclen
+#define acc_desc_dword3 acc_enckey
+#define acc_desc_dword4 acc_enciv
+#define acc_desc_dword5 acc_macsrc
+#define acc_desc_dword6 acc_macdst
+#define acc_desc_dword7 acc_maciv
+} __attribute__((aligned(4)));
+
+struct mvxpsec_crp_key {
+ uint32_t crp_key32[8];
+} __attribute__((aligned(4)));
+
+struct mvxpsec_crp_iv {
+ uint32_t crp_iv32[4];
+} __attribute__((aligned(4)));
+
+struct mvxpsec_mac_iv {
+ uint32_t mac_iv32[5];
+ uint32_t mac_ivpad[1]; /* bit[2:0] = 0 */
+} __attribute__((aligned(8)));
+
+/* many pointer in the desc has a limitation of bit[2:0] = 0. */
+struct mvxpsec_packet_header {
+ struct mvxpsec_acc_descriptor desc; /* 32 oct. */
+ struct mvxpsec_crp_iv crp_iv_work; /* 16 oct. */
+ struct mvxpsec_crp_iv crp_iv_ext; /* 16 oct. */
+} __attribute__((aligned(4))); /* 64 oct. */
+
+struct mvxpsec_session_header {
+ struct mvxpsec_crp_key crp_key; /* 32 oct. */
+ struct mvxpsec_crp_key crp_key_d; /* 32 oct. */
+ struct mvxpsec_mac_iv miv_in; /* 24 oct. */
+ struct mvxpsec_mac_iv miv_out; /* 24 oct. */
+ uint8_t pad[16]; /* 16 oct. */
+} __attribute__((aligned(4))); /* 128 oct. */
+
+/*
+ * Usage of CESA internal SRAM
+ *
+ * +---------------+ MVXPSEC_SRAM_PKT_HDR_OFF(0)
+ * |Packet Header | contains per packet information (IV, ACC descriptor)
+ * | |
+ * | |
+ * +---------------+ MVXPSEC_SRAM_SESS_HDR_OFF
+ * |Session Header | contains per session information (Key, HMAC-iPad/oPad)
+ * | | may not DMA transfered if session is not changed.
+ * | |
+ * +---------------+ MVXPSEC_SRAM_PAYLOAD_OFF
+ * |Payload |
+ * | |
+ * . .
+ * . .
+ * . .
+ * | |
+ * +---------------+ MV_ACC_SRAM_SIZE(2048)
+ *
+ * The input data is transfered to SRAM from system DRAM using TDMA,
+ * and ACC is working on the SRAM. When ACC finished the work,
+ * TDMA returns the payload of SRAM to system DRAM.
+ *
+ * CPU can also access the SRAM via Mbus interface directly. This driver
+ * access the SRAM only for debugging.
+ *
+ */
+#define SRAM_PAYLOAD_SIZE \
+ (MV_ACC_SRAM_SIZE \
+ - sizeof(struct mvxpsec_packet_header) \
+ - sizeof(struct mvxpsec_session_header))
+struct mvxpsec_crypt_sram {
+ struct mvxpsec_packet_header packet_header; /* 64 oct. */
+ struct mvxpsec_session_header session_header; /* 128 oct. */
+ uint8_t payload[SRAM_PAYLOAD_SIZE];
+} __attribute__((aligned(8))); /* Max. 2048 oct. */
+#define MVXPSEC_SRAM_PKT_HDR_OFF \
+ (offsetof(struct mvxpsec_crypt_sram, packet_header))
+#define MVXPSEC_SRAM_DESC_OFF (MVXPSEC_SRAM_PKT_HDR_OFF + \
+ offsetof(struct mvxpsec_packet_header, desc))
+#define MVXPSEC_SRAM_IV_WORK_OFF (MVXPSEC_SRAM_PKT_HDR_OFF + \
+ offsetof(struct mvxpsec_packet_header, crp_iv_work))
+#define MVXPSEC_SRAM_IV_EXT_OFF (MVXPSEC_SRAM_PKT_HDR_OFF + \
+ offsetof(struct mvxpsec_packet_header, crp_iv_ext))
+
+#define MVXPSEC_SRAM_SESS_HDR_OFF \
+ (offsetof(struct mvxpsec_crypt_sram, session_header))
+#define MVXPSEC_SRAM_KEY_OFF (MVXPSEC_SRAM_SESS_HDR_OFF + \
+ offsetof(struct mvxpsec_session_header, crp_key))
+#define MVXPSEC_SRAM_KEY_D_OFF (MVXPSEC_SRAM_SESS_HDR_OFF + \
+ offsetof(struct mvxpsec_session_header, crp_key_d))
+#define MVXPSEC_SRAM_MIV_IN_OFF (MVXPSEC_SRAM_SESS_HDR_OFF + \
+ offsetof(struct mvxpsec_session_header, miv_in))
+#define MVXPSEC_SRAM_MIV_OUT_OFF (MVXPSEC_SRAM_SESS_HDR_OFF + \
+ offsetof(struct mvxpsec_session_header, miv_out))
+
+#define MVXPSEC_SRAM_PAYLOAD_OFF \
+ (offsetof(struct mvxpsec_crypt_sram, payload))
+
+/* CESA device address (CESA internal SRAM address space) */
+#define MVXPSEC_SRAM_DESC_DA MVXPSEC_SRAM_DESC_OFF
+#define MVXPSEC_SRAM_IV_WORK_DA MVXPSEC_SRAM_IV_WORK_OFF
+#define MVXPSEC_SRAM_IV_EXT_DA MVXPSEC_SRAM_IV_EXT_OFF
+#define MVXPSEC_SRAM_KEY_DA MVXPSEC_SRAM_KEY_OFF
+#define MVXPSEC_SRAM_KEY_D_DA MVXPSEC_SRAM_KEY_D_OFF
+#define MVXPSEC_SRAM_MIV_IN_DA MVXPSEC_SRAM_MIV_IN_OFF
+#define MVXPSEC_SRAM_MIV_OUT_DA MVXPSEC_SRAM_MIV_OUT_OFF
+#define MVXPSEC_SRAM_PAYLOAD_DA(offset) \
+ (MVXPSEC_SRAM_PAYLOAD_OFF + (offset))
+
+/*
+ * Session management
+ */
+enum mvxpsec_data_type {
+ MVXPSEC_DATA_NONE,
+ MVXPSEC_DATA_RAW,
+ MVXPSEC_DATA_MBUF,
+ MVXPSEC_DATA_UIO,
+ MVXPSEC_DATA_LAST,
+};
+
+/* session flags */
+#define RDY_DATA (1 << 0)
+#define RDY_CRP_KEY (1 << 1)
+#define RDY_CRP_IV (1 << 2)
+#define RDY_MAC_KEY (1 << 3)
+#define RDY_MAC_IV (1 << 4)
+#define CRP_EXT_IV (1 << 5)
+
+#define SETUP_DONE (1 << 10)
+#define DELETED (1 << 11)
+#define DIR_ENCRYPT (1 << 12)
+#define DIR_DECRYPT (1 << 13)
+
+#define HW_RUNNING (1 << 16)
+
+/* 64 peer * 2 way(in/out) * 2 family(inet/inet6) * 2 state(mature/dying) */
+#define MVXPSEC_MAX_SESSIONS 512
+
+struct mvxpsec_session {
+ struct mvxpsec_softc *sc;
+ uint32_t sid;
+
+ uint32_t sflags;
+ uint32_t refs;
+
+ /*
+ * Header of Security Accelerator
+ * - include key entity for ciphers
+ * - include iv for HMAC
+ */
+ bus_dmamap_t session_header_map;
+ struct mvxpsec_session_header session_header;
+
+ /* Key length for variable key length algorithm [bits] */
+ int enc_klen;
+ int mac_klen;
+
+ /* IV Store */
+ struct mvxpsec_crp_iv session_iv;
+
+ /* debug */
+ int cipher_alg;
+ int hmac_alg;
+};
+
+struct mvxpsec_packet {
+ struct mvxpsec_session *mv_s;
+ struct cryptop *crp;
+ int flags;
+
+ mvxpsec_dma_ring dma_ring;
+
+ bus_dmamap_t pkt_header_map;
+ struct mvxpsec_packet_header pkt_header;
+
+ bus_dmamap_t data_map;
+ enum mvxpsec_data_type data_type;
+ uint32_t data_len;
+ union {
+ /* payload buffer come from opencrypto API */
+ void *ptr;
+ void *raw;
+ struct mbuf *mbuf;
+ struct uio *uio;
+ } data;
+
+ /* IV place holder for EXPLICIT IV */
+ void *ext_iv;
+ int ext_ivlen;
+
+ uint32_t enc_off;
+ uint32_t enc_len;
+ uint32_t enc_ivoff;
+ uint32_t mac_off;
+ uint32_t mac_len;
+ uint32_t mac_dst;
+#define data_ptr data.ptr
+#define data_raw data.raw
+#define data_mbuf data.mbuf
+#define data_uio data.uio
+
+ /* list */
+ SIMPLEQ_ENTRY(mvxpsec_packet) queue;
+ SLIST_ENTRY(mvxpsec_packet) free_list;
+};
+typedef SIMPLEQ_HEAD(mvxpsec_packet_queue, mvxpsec_packet) mvxpsec_queue_t;
+typedef SLIST_HEAD(mvxpsec_packet_list, mvxpsec_packet) mvxpsec_list_t;
+
+/*
+ * DMA Configuration
+ */
+#define MVXPSEC_DMA_DESC_PAGES 16
+#define MVXPSEC_DMA_MAX_SEGS 30
+#define MVXPSEC_DMA_MAX_SIZE 2048 /* = SRAM size */
+
+/*
+ * Interrupt Configuration
+ */
+#define MVXPSEC_ALL_INT (0xffffffff)
+#define MVXPSEC_ALL_ERR (0xffffffff)
+#define MVXPSEC_DEFAULT_INT (MVXPSEC_INT_ACCTDMA)
+#define MVXPSEC_DEFAULT_ERR (MVXPSEC_ALL_ERR)
+
+/*
+ * QUEUE Configuration
+ */
+#define MVXPSEC_MAX_QLEN 512
+#define MVXPSEC_QLEN_HIWAT 256
+#define MVXPSEC_QLEN_DEF_LOWAT 16
+#define MVXPSEC_DEF_PENDING 0
+
+/*
+ * Event counters
+ */
+struct mvxpsec_evcnt {
+ /* interuprts */
+ struct evcnt intr_all;
+ struct evcnt intr_auth;
+ struct evcnt intr_des;
+ struct evcnt intr_aes_enc;
+ struct evcnt intr_aes_dec;
+ struct evcnt intr_enc;
+ struct evcnt intr_sa;
+ struct evcnt intr_acctdma;
+ struct evcnt intr_comp;
+ struct evcnt intr_own;
+ struct evcnt intr_acctdma_cont;
+
+ /* session counter */
+ struct evcnt session_new;
+ struct evcnt session_free;
+
+ /* packet counter */
+ struct evcnt packet_ok;
+ struct evcnt packet_err;
+
+ /* queue */
+ struct evcnt dispatch_packets;
+ struct evcnt dispatch_queue;
+ struct evcnt queue_full;
+ struct evcnt max_dispatch;
+ struct evcnt max_done;
+};
+#ifdef MVXPSEC_EVENT_COUNTERS
+#define MVXPSEC_EVCNT_INCR(sc, name) do { \
+ (sc)->sc_ev.name.ev_count++; \
+} while (/*CONSTCOND*/0)
+#define MVXPSEC_EVCNT_ADD(sc, name, val) do { \
+ (sc)->sc_ev.name.ev_count += (val); \
+} while (/*CONSTCOND*/0)
+#define MVXPSEC_EVCNT_MAX(sc, name, val) do { \
+ if ((val) > (sc)->sc_ev.name.ev_count) \
+ (sc)->sc_ev.name.ev_count = (val); \
+} while (/*CONSTCOND*/0)
+#else
+#define MVXPSEC_EVCNT_INCR(sc, name) /* nothing */
+#define MVXPSEC_EVCNT_ADD(sc, name, val) /* nothing */
+#define MVXPSEC_EVCNT_MAX(sc, name, val) /* nothing */
+#endif
+
+struct mvxpsec_softc {
+ device_t sc_dev;
+ uint32_t sc_cid;
+ bus_space_tag_t sc_iot;
+ bus_space_handle_t sc_ioh;
+ bus_dma_tag_t sc_dmat;
+
+ /* Memory Pools */
+ struct mvxpsec_devmem *sc_devmem_desc;
+ struct mvxpsec_devmem *sc_devmem_mmap;
+ pool_cache_t sc_session_pool;
+ pool_cache_t sc_packet_pool;
+
+ /* Event Counters */
+#ifdef MVXPSEC_EVENT_COUNTERS
+ struct mvxpsec_evcnt sc_ev;
+#endif
+
+ /* SRAM mappings */
+ paddr_t sc_sram_pa;
+ void * sc_sram_va;
+
+ /* Interrupts and Timers */
+ callout_t sc_timeout;
+ void * sc_done_ih;
+ void * sc_error_ih;
+
+ /* DMA Descriptors */
+ kmutex_t sc_dma_mtx;
+ struct mvxpsec_descriptor_handle *sc_desc_ring;
+ int sc_desc_ring_size;
+ int sc_desc_ring_prod;
+ int sc_desc_ring_cons;
+
+ /* Session */
+ kmutex_t sc_session_mtx;
+ struct mvxpsec_session *sc_sessions[MVXPSEC_MAX_SESSIONS];
+ int sc_nsessions;
+ struct mvxpsec_session *sc_last_session;
+
+ /* Packet queue */
+ kmutex_t sc_queue_mtx;
+ mvxpsec_queue_t sc_wait_queue;
+ int sc_wait_qlen;
+ int sc_wait_qlimit;
+ mvxpsec_queue_t sc_run_queue;
+ mvxpsec_list_t sc_free_list;
+ int sc_free_qlen;
+ uint32_t sc_flags;
+
+ /* Debug */
+ int sc_craft_conf;
+ int sc_craft_p0;
+};
+/* SRAM parameters accessor */
+#define MVXPSEC_SRAM_BASE(sc) ((sc)->sc_sram_pa)
+#define MVXPSEC_SRAM_SIZE(sc) (sizeof(struct mvxpsec_crypt_sram))
+#define MVXPSEC_SRAM_PA(sc, offset) \
+ (MVXPSEC_SRAM_BASE(sc) + (offset))
+#define MVXPSEC_SRAM_LIMIT(sc) \
+ (MVXPSEC_SRAM_BASE(sc) + MVXPSEC_SRAM_SIZE(sc))
+#define MVXPSEC_SRAM_PKT_HDR_PA(sc) \
+ MVXPSEC_SRAM_PA((sc), MVXPSEC_SRAM_PKT_HDR_OFF)
+#define MVXPSEC_SRAM_DESC_PA(sc) \
+ MVXPSEC_SRAM_PA((sc), MVXPSEC_SRAM_DESC_OFF)
+#define MVXPSEC_SRAM_IV_WORK_PA(sc) \
+ MVXPSEC_SRAM_PA((sc), MVXPSEC_SRAM_IV_WORK_OFF)
+#define MVXPSEC_SRAM_SESS_HDR_PA(sc) \
+ MVXPSEC_SRAM_PA((sc), MVXPSEC_SRAM_SESS_HDR_OFF)
+#define MVXPSEC_SRAM_KEY_PA(sc) \
+ MVXPSEC_SRAM_PA((sc), MVXPSEC_SRAM_KEY_OFF)
+#define MVXPSEC_SRAM_KEY_D_PA(sc) \
+ MVXPSEC_SRAM_PA((sc), MVXPSEC_SRAM_KEY_D_OFF)
+#define MVXPSEC_SRAM_MIV_IN_PA(sc) \
+ MVXPSEC_SRAM_PA((sc), MVXPSEC_SRAM_MIV_IN_OFF)
+#define MVXPSEC_SRAM_MIV_OUT_PA(sc) \
+ MVXPSEC_SRAM_PA((sc), MVXPSEC_SRAM_MIV_OUT_OFF)
+#define MVXPSEC_SRAM_PAYLOAD_PA(sc, offset) \
+ MVXPSEC_SRAM_PA((sc), MVXPSEC_SRAM_PAYLOAD_OFF + (offset))
+
+/*
+ * OpenCrypto API
+ */
+extern int mvxpsec_register(struct mvxpsec_softc *);
+extern int mvxpsec_newsession(void *, uint32_t *, struct cryptoini *);
+extern int mvxpsec_freesession(void *, uint64_t);
+extern int mvxpsec_dispatch(void *, struct cryptop *, int);
+extern void mvxpsec_done(void *);
+
+/* debug flags */
+#define MVXPSEC_DEBUG_DMA __BIT(0)
+#define MVXPSEC_DEBUG_IOCTL __BIT(1)
+#define MVXPSEC_DEBUG_INTR __BIT(2)
+#define MVXPSEC_DEBUG_SRAM __BIT(3)
+#define MVXPSEC_DEBUG_OPENCRYPTO __BIT(4)
+#define MVXPSEC_DEBUG_PAYLOAD __BIT(5)
+#define MVXPSEC_DEBUG_HASH_IV __BIT(6)
+#define MVXPSEC_DEBUG_HASH_VAL __BIT(7)
+#define MVXPSEC_DEBUG_DESC __BIT(8) /* descriptors and registers */
+#define MVXPSEC_DEBUG_INPUT __BIT(9)
+#define MVXPSEC_DEBUG_ENC_IV __BIT(10)
+#define MVXPSEC_DEBUG_QUEUE __BIT(11)
+
+#define MVXPSEC_DEBUG_ALL __BITS(11,0)
+
+#ifdef MVXPSEC_DEBUG
+#define MVXPSEC_PRINTF(level, fmt, ...) \
+ do { \
+ if (mvxpsec_debug & level) { \
+ printf("%s: ", __func__); \
+ printf((fmt), ##__VA_ARGS__); \
+ } \
+ } while (/*CONSTCOND*/0)
+#else
+#define MVXPSEC_PRINTF(level, fmt, ...) /* nothing */
+#endif
+
+
+#endif /* __MVXPSECVAR_H__ */