Sync with HEAD (-D20101022). uebayasi-xip
authoruebayasi <uebayasi@NetBSD.org>
Fri, 22 Oct 2010 09:23:11 +0000
branchuebayasi-xip
changeset 280926 097f87bd35fc
parent 280925 e6010060be88
child 280927 e5c4adb42b6c
Sync with HEAD (-D20101022).
share/man/man9/man9.x86/Makefile
share/man/man9/man9.x86/nmi.9
share/man/man9/man9.x86/x86_msr_xcall.9
sys/arch/arm/marvell/files.marvell
sys/arch/arm/marvell/kirkwood.c
sys/arch/arm/marvell/kirkwoodreg.h
sys/arch/arm/marvell/mv78xx0reg.h
sys/arch/arm/marvell/mvsoc.c
sys/arch/arm/marvell/mvsoc_dma.c
sys/arch/arm/marvell/mvsoc_intr.c
sys/arch/arm/marvell/mvsoc_intr.h
sys/arch/arm/marvell/mvsoc_space.c
sys/arch/arm/marvell/mvsocgpp.c
sys/arch/arm/marvell/mvsocgppreg.h
sys/arch/arm/marvell/mvsocgppvar.h
sys/arch/arm/marvell/mvsocreg.h
sys/arch/arm/marvell/mvsoctmr.c
sys/arch/arm/marvell/mvsoctmrreg.h
sys/arch/arm/marvell/mvsocvar.h
sys/arch/arm/marvell/orion.c
sys/arch/arm/marvell/orionreg.h
sys/arch/arm/marvell/pci_machdep.c
sys/arch/evbarm/marvell/marvell_machdep.c
sys/arch/evbarm/marvell/marvell_start.S
sys/arch/evbarm/marvell/marvellreg.h
sys/arch/evbarm/marvell/marvellvar.h
sys/dev/filemon/filemon.c
sys/dev/filemon/filemon.h
sys/dev/filemon/filemon_wrapper.c
sys/dev/filemon/mknod-sh
sys/modules/compat_aoutm68k/Makefile
sys/modules/filemon/Makefile
sys/modules/npf/Makefile
sys/modules/swsensor/Makefile
sys/net/npf/Makefile
sys/net/npf/files.npf
sys/net/npf/npf.c
sys/net/npf/npf.h
sys/net/npf/npf_alg.c
sys/net/npf/npf_alg_icmp.c
sys/net/npf/npf_ctl.c
sys/net/npf/npf_handler.c
sys/net/npf/npf_impl.h
sys/net/npf/npf_inet.c
sys/net/npf/npf_instr.c
sys/net/npf/npf_mbuf.c
sys/net/npf/npf_nat.c
sys/net/npf/npf_ncode.h
sys/net/npf/npf_processor.c
sys/net/npf/npf_ruleset.c
sys/net/npf/npf_sendpkt.c
sys/net/npf/npf_session.c
sys/net/npf/npf_tableset.c
sys/rump/dev/lib/libnpf/Makefile
sys/rump/dev/lib/libnpf/component.c
sys/rump/dev/lib/libnpf/shlib_version
sys/rump/dev/lib/libscsipi/Makefile
sys/rump/dev/lib/libscsipi/SCSIPI.ioconf
sys/rump/dev/lib/libscsipi/component.c
sys/rump/dev/lib/libscsipi/opt/atapibus.h
sys/rump/dev/lib/libscsipi/opt/opt_compat_freebsd.h
sys/rump/dev/lib/libscsipi/opt/opt_scsi.h
sys/rump/dev/lib/libscsipi/opt/scsibus.h
sys/rump/dev/lib/libscsipi/opt/wd.h
sys/rump/dev/lib/libscsipi/shlib_version
sys/rump/dev/lib/libscsitest/Makefile
sys/rump/dev/lib/libscsitest/SCSITEST.ioconf
sys/rump/dev/lib/libscsitest/component.c
sys/rump/dev/lib/libscsitest/scsitest.c
sys/rump/dev/lib/libscsitest/shlib_version
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/share/man/man9/man9.x86/Makefile	Fri Oct 22 09:23:11 2010 +0000
@@ -0,0 +1,10 @@
+#	$NetBSD: Makefile,v 1.2.2.2 2010/10/22 09:23:11 uebayasi Exp $
+
+MAN=	nmi.9 x86_msr_xcall.9
+
+MANSUBDIR=/x86
+
+MLINKS+=nmi.9 nmi_establish.9
+MLINKS+=nmi.9 nmi_disestablish.9
+
+.include <bsd.man.mk>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/share/man/man9/man9.x86/nmi.9	Fri Oct 22 09:23:11 2010 +0000
@@ -0,0 +1,144 @@
+.\"     $NetBSD: nmi.9,v 1.2.2.2 2010/10/22 09:23:11 uebayasi Exp $
+.\"
+.\" Copyright (c) 2010 The NetBSD Foundation, Inc.
+.\" All rights reserved.
+.\"
+.\" This code is derived from software contributed to The NetBSD Foundation
+.\" by David Young.
+.\"
+.\" 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+.\" PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+.\" POSSIBILITY OF SUCH DAMAGE.
+.\"
+.Dd February 9, 2010
+.Dt NMI 9 x86
+.Os
+.Sh NAME
+.Nm nmi ,
+.Nm nmi_establish ,
+.Nm nmi_disestablish ,
+.Nd NMI
+.Sh SYNOPSIS
+.In x86/nmi.h
+.Ft nmi_handler_t *
+.Fn nmi_establish "int (*func)(const struct trapframe *, void *)" "void *arg"
+.Ft void
+.Fn nmi_disestablish "nmi_handler_t *handle"
+.Sh DESCRIPTION
+The
+.Nm
+interface lets the kernel establish handlers for x86 Non-Maskable
+Interrupts (NMIs).
+An NMI signals to the processor an exception on a processor, memory
+controller, or I/O bus that is irrecoverable or else needs attention
+at a high priority.
+A
+.Dq "debug switch"
+or a performance/watchdog timer may also trigger an NMI.
+.Pp
+An NMI handler will run to completion on the same processor where
+it began without being preempted by any thread or interrupt except
+for another NMI.
+An NMI handler must prepare for re-entry.
+An NMI handler may run simultaneously on more than one CPU.
+.Pp
+Synchronizing access to a shared data structure from
+an NMI handler is a different challenge than synchronizing access
+from hardware/software interrupt routines or from kernel threads.
+An NMI handler may not perform any operation that may sleep, acquire
+a mutex, or schedule a software interrupt.
+An NMI handler may use
+.Xr atomic_ops 3 .
+An NMI handler may reference per-CPU storage
+.Po
+.Xr percpu 9
+.Pc .
+.Pp
+An NMI handler may not write to the kernel message buffer.
+.Sh FUNCTIONS
+.Bl -tag -width compact
+.It Fn nmi_establish "func" "arg"
+Call this in thread context to establish a handler for non-maskable
+interrupts.
+Establish
+.Fa func
+as one of the handler functions to call when an NMI occurs.
+Where
+.Fa tf
+is a
+.Vt struct trapframe
+representation of the processor context where the NMI was received,
+and
+.Fa arg
+is the argument to
+.Fn nmi_establish ,
+the kernel will call
+.Fo (*func)
+.Fa tf
+.Fa arg
+.Fc
+every time an NMI occurs until the handler is removed with
+.Fn nmi_disestablish .
+.Fa func
+should return non-zero if it handled a condition that causes
+NMI, or zero if it did not.
+If, for a given NMI, all handlers return zero, the system will
+panic or enter the kernel debugger,
+.Xr ddb 4 .
+.Fn nmi_establish
+returns
+.Dv NULL
+on failure, and a handle for the NMI handler on success.
+.It Fn nmi_disestablish "handle"
+Call this in thread context to stop the kernel from calling an NMI
+handler.
+Indicate the handler to disestablish with the
+.Fa handle
+returned by
+.Fn nmi_establish .
+.El
+.Sh CODE REFERENCES
+This section describes places within the
+.Nx
+source tree where actual code implementing the
+.Nm
+interface
+can be found.
+All pathnames are relative to
+.Pa /usr/src .
+.Pp
+The
+.Nm
+interface is implemented within the file
+.Pa sys/arch/x86/x86/nmi.c .
+.\" .Sh EXAMPLES
+.Sh SEE ALSO
+.Xr atomic_ops 3 ,
+.Xr ddb 4
+.Sh HISTORY
+The
+.Nm
+interface first appeared in
+.Nx 6.0 .
+.Sh AUTHORS
+.An YAMAMOTO Takashi Aq yamt@NetBSD.org
+.\" .Sh CAVEATS
+.\" .Sh BUGS
+.\" .Sh SECURITY CONSIDERATIONS
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/share/man/man9/man9.x86/x86_msr_xcall.9	Fri Oct 22 09:23:11 2010 +0000
@@ -0,0 +1,97 @@
+.\" $NetBSD: x86_msr_xcall.9,v 1.3.2.2 2010/10/22 09:23:11 uebayasi Exp $
+.\"
+.\" Copyright (c) 2010 The NetBSD Foundation, Inc.
+.\" All rights reserved.
+.\"
+.\" This code is derived from software contributed to The NetBSD Foundation
+.\" by Jukka Ruohonen.
+.\"
+.\" 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+.\" PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+.\" POSSIBILITY OF SUCH DAMAGE.
+.\"
+.Dd August 21, 2010
+.Dt X86_MSR_XCALL 9 x86
+.Os
+.Sh NAME
+.Nm x86_msr_xcall
+.Nd MSR specific cross-call
+.Sh SYNOPSIS
+.In x86/cpu_msr.h
+.Ft void
+.Fn x86_msr_xcall "void *arg1" "void *arg1"
+.Sh DESCRIPTION
+The
+.Fn x86_msr_xcall
+function provides a x86-specific IPI handler suitable for use with the
+.Xr xcall 9
+interface.
+It can be used to ensure that a given
+.Tn MSR
+call is executed on all processors.
+The prototype follows the
+.Ft xcfunc_t
+function pointer type and the opaque
+.Fa arg1
+pointer is casted to the following structure:
+.Bd -literal -offset indent
+struct msr_rw_info {
+	int		msr_read;
+	int		msr_type;
+	uint64_t	msr_value;
+	uint64_t	msr_mask;
+};
+.Ed
+.Pp
+This structure must be filled prior to the call.
+Two fields are compulsory:
+.Fa msr_type
+is used as the address of the
+.Tn MSR
+and
+.Fa msr_value
+is the value to be written.
+If
+.Fa msr_read
+is not zero,
+.Fn x86_msr_xcall
+will first read from
+.Fa msr_type
+and then clear the mask specified in
+.Fa msr_mask
+before the write operation.
+.Sh EXAMPLES
+The following example writes a value zero to the
+.Tn MSR_THERM_CONTROL
+model-specific register on all processors in the system:
+.Bd -literal -offset indent
+struct msr_rw_info msr;
+uint64_t xc;
+
+msr.msr_value = 0;
+msr.msr_read = true;
+msr.msr_type = MSR_THERM_CONTROL;
+msr.msr_mask = 0x1e;
+
+xc = xc_broadcast(0, (xcfunc_t)x86_msr_xcall, &msr, NULL);
+xc_wait(xc);
+.Ed
+.Sh SEE ALSO
+.Xr xcall 9
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/arch/arm/marvell/files.marvell	Fri Oct 22 09:23:11 2010 +0000
@@ -0,0 +1,71 @@
+#       $NetBSD: files.marvell,v 1.2.4.2 2010/10/22 09:23:11 uebayasi Exp $
+#
+# Configuration info for Marvell System on Chip support
+#
+
+include "arch/arm/pic/files.pic"
+
+device	mvsoc { [unit = -1], [offset = -1], [irq = -1] } : bus_space_generic, pic
+attach	mvsoc at mainbus
+file	arch/arm/marvell/mvsoc.c		mvsoc
+file	arch/arm/marvell/mvsoc_space.c
+file	arch/arm/marvell/mvsoc_dma.c
+
+file	arch/arm/arm32/irq_dispatch.S
+
+defflag opt_mvsoc.h				ORION KIRKWOOD MV78XX0
+file	arch/arm/marvell/mvsoc_intr.c
+file	arch/arm/marvell/orion.c		orion
+file	arch/arm/marvell/kirkwood.c		kirkwood
+#file	arch/arm/marvell/mv78xx0.c		mv78xx0
+
+
+# Integrated peripherals
+include "dev/marvell/files.discovery"
+
+# Timers
+device	mvsoctmr
+attach	mvsoctmr at mvsoc
+file	arch/arm/marvell/mvsoctmr.c		mvsoctmr
+
+
+# PCI Express Interface
+attach	mvpex at mvsoc with mvpex_mbus
+
+# PCI Interface
+attach	gtpci at mvsoc with gtpci_mbus
+
+file	arch/arm/marvell/pci_machdep.c		mvpex | gtpci
+
+device	pchb
+attach	pchb at pci
+file	dev/marvell/pchb.c			pchb
+
+# Serial-ATA II Host Controller (SATAHC)
+attach	mvsata at mvsoc with mvsata_mbus
+
+# Gigabit Ethernet Controller Interface
+attach	mvgbec at mvsoc with mvgbec_mbus
+
+# USB 2.0 Interface
+attach	ehci at mvsoc with mvusb_mbus
+
+# Cryptographic Engines and Security Accelerator
+#attach	mvcesa at mvsoc with mvcesa_mbus
+
+# TWSI Two-Wire Serial Interface
+attach	gttwsi at mvsoc with gttwsi_mbus
+
+# UART Interface
+attach	com at mvsoc with mvuart_mbus
+
+# IDMA Controller and XOR Engine
+attach	gtidmac at mvsoc with gtidmac_mbus
+
+# General Purpose I/O Port Interface
+device	mvsocgpp: gpiobus, pic
+attach	mvsocgpp at mvsoc
+file	arch/arm/marvell/mvsocgpp.c		mvsocgpp	needs-flag
+
+# Secure Digital Input/Output (SDIO) Interface
+attach	mvsdio at mvsoc with mvsdio_mbus
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/arch/arm/marvell/kirkwood.c	Fri Oct 22 09:23:11 2010 +0000
@@ -0,0 +1,292 @@
+/*	$NetBSD: kirkwood.c,v 1.1.4.2 2010/10/22 09:23:11 uebayasi Exp $	*/
+/*
+ * Copyright (c) 2010 KIYOHARA Takashi
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: kirkwood.c,v 1.1.4.2 2010/10/22 09:23:11 uebayasi Exp $");
+
+#define _INTR_PRIVATE
+
+#include "mvsocgpp.h"
+
+#include <sys/param.h>
+#include <sys/bus.h>
+
+#include <machine/intr.h>
+
+#include <arm/pic/picvar.h>
+#include <arm/pic/picvar.h>
+
+#include <arm/marvell/mvsocreg.h>
+#include <arm/marvell/mvsocvar.h>
+#include <arm/marvell/kirkwoodreg.h>
+
+#include <dev/marvell/marvellreg.h>
+
+
+static void kirkwood_intr_init(void);
+
+static void kirkwood_pic_unblock_low_irqs(struct pic_softc *, size_t, uint32_t);
+static void kirkwood_pic_unblock_high_irqs(struct pic_softc *, size_t,
+					   uint32_t);
+static void kirkwood_pic_block_low_irqs(struct pic_softc *, size_t, uint32_t);
+static void kirkwood_pic_block_high_irqs(struct pic_softc *, size_t, uint32_t);
+static int kirkwood_pic_find_pending_high_irqs(struct pic_softc *);
+static void kirkwood_pic_establish_irq(struct pic_softc *, struct intrsource *);
+static void kirkwood_pic_source_name(struct pic_softc *, int, char *, size_t);
+
+static int kirkwood_find_pending_irqs(void);
+
+static const char * const sources[64] = {
+    "MainHighSum(0)",  "Bridge(1)",       "Host2CPU DB(2)",  "CPU2Host DB(3)",
+    "Reserved_4(4)",   "Xor0Chan0(5)",    "Xor0Chan1(6)",    "Xor1Chan0(7)",
+    "Xor1Chan1(8)",    "PEX0INT(9)",      "Reserved(10)",    "GbE0Sum(11)",
+    "GbE0Rx(12)",      "GbE0Tx(13)",      "GbE0Misc(14)",    "GbE1Sum(15)",
+    "GbE1Rx(16)",      "GbE1Tx(17)",      "GbE1Misc(18)",    "USB0Cnt(19)",
+    "Reserved(20)",    "Sata(21)",        "SecurityInt(22)", "SPIInt(23)",
+    "AudioINT(24)",    "Reserved(25)",    "TS0Int(26)",      "Reserved(27)",
+    "SDIOInt(28)",     "TWSI(29)",        "AVBInt(30)",      "TDMInt(31)"
+
+    "Reserved(32)",    "Uart0Int(33)",    "Uart1Int(34)",    "GPIOLo7_0(35)"
+    "GPIOLo8_15(36)",  "GPIOLo16_23(37)", "GPIOLo24_31(38)", "GPIOHi7_0(39)"
+    "GPIOHi8_15(40)",  "GPIOHi16_23(41)", "XOR0Err(42)",     "XOR1Err(43)"
+    "PEX0Err(44)",     "Reserved(45)",    "GbE0Err(46)",     "GbE1Err(47)"
+    "USBErr(48)",      "SecurityErr(49)", "AudioErr(50)",    "Reserved(51)"
+    "Reserved(52)",    "RTCInt(53)",      "Reserved(54)",    "Reserved(55)"
+    "Reserved(56)",    "Reserved(57)",    "Reserved(58)",    "Reserved(59)"
+    "Reserved(60)",    "Reserved(61)",    "Reserved(62)",    "Reserved(63)"
+};
+
+static struct pic_ops kirkwood_picops_low = {
+	.pic_unblock_irqs = kirkwood_pic_unblock_low_irqs,
+	.pic_block_irqs = kirkwood_pic_block_low_irqs,
+	.pic_establish_irq = kirkwood_pic_establish_irq,
+	.pic_source_name = kirkwood_pic_source_name,
+};
+static struct pic_ops kirkwood_picops_high = {
+	.pic_unblock_irqs = kirkwood_pic_unblock_high_irqs,
+	.pic_block_irqs = kirkwood_pic_block_high_irqs,
+	.pic_find_pending_irqs = kirkwood_pic_find_pending_high_irqs,
+	.pic_establish_irq = kirkwood_pic_establish_irq,
+	.pic_source_name = kirkwood_pic_source_name,
+};
+static struct pic_softc kirkwood_pic_low = {
+	.pic_ops = &kirkwood_picops_low,
+	.pic_maxsources = 32,
+	.pic_name = "kirkwood_low",
+};
+static struct pic_softc kirkwood_pic_high = {
+	.pic_ops = &kirkwood_picops_high,
+	.pic_maxsources = 32,
+	.pic_name = "kirkwood_high",
+};
+
+
+/*
+ * kirkwood_intr_bootstrap:
+ *
+ *	Initialize the rest of the interrupt subsystem, making it
+ *	ready to handle interrupts from devices.
+ */
+void
+kirkwood_intr_bootstrap(void)
+{
+	extern void (*mvsoc_intr_init)(void);
+
+	/* disable all interrupts */
+	write_mlmbreg(KIRKWOOD_MLMB_MIRQIMLR, 0);
+	write_mlmbreg(KIRKWOOD_MLMB_MIRQIMHR, 0);
+
+	/* disable all bridge interrupts */
+	write_mlmbreg(MVSOC_MLMB_MLMBIMR, 0);
+
+	mvsoc_intr_init = kirkwood_intr_init;
+
+#if NMVSOCGPP > 0
+	switch (mvsoc_model()) {
+	case MARVELL_KIRKWOOD_88F6180: gpp_npins = 30; break;
+	case MARVELL_KIRKWOOD_88F6192: gpp_npins = 36; break;
+	case MARVELL_KIRKWOOD_88F6281: gpp_npins = 50; break;
+	}
+	gpp_irqbase = 96;	/* Main Low(32) + High(32) + Bridge(32) */
+#endif
+}
+
+static void
+kirkwood_intr_init(void)
+{
+	extern struct pic_softc mvsoc_bridge_pic;
+	void *ih;
+
+	pic_add(&kirkwood_pic_low, 0);
+
+	pic_add(&kirkwood_pic_high, 32);
+	ih = intr_establish(KIRKWOOD_IRQ_HIGH, IPL_HIGH, IST_LEVEL_HIGH,
+	    pic_handle_intr, &kirkwood_pic_high);
+	KASSERT(ih != NULL);
+
+	pic_add(&mvsoc_bridge_pic, 64);
+	ih = intr_establish(KIRKWOOD_IRQ_BRIDGE, IPL_HIGH, IST_LEVEL_HIGH,
+	    pic_handle_intr, &mvsoc_bridge_pic);
+	KASSERT(ih != NULL);
+
+	find_pending_irqs = kirkwood_find_pending_irqs;
+}
+
+/* ARGSUSED */
+static void
+kirkwood_pic_unblock_low_irqs(struct pic_softc *pic, size_t irqbase,
+			      uint32_t irq_mask)
+{
+
+	write_mlmbreg(KIRKWOOD_MLMB_MIRQIMLR,
+	    read_mlmbreg(KIRKWOOD_MLMB_MIRQIMLR) | irq_mask);
+}
+
+/* ARGSUSED */
+static void
+kirkwood_pic_unblock_high_irqs(struct pic_softc *pic, size_t irqbase,
+			       uint32_t irq_mask)
+{
+
+	write_mlmbreg(KIRKWOOD_MLMB_MIRQIMHR,
+	    read_mlmbreg(KIRKWOOD_MLMB_MIRQIMHR) | irq_mask);
+}
+
+/* ARGSUSED */
+static void
+kirkwood_pic_block_low_irqs(struct pic_softc *pic, size_t irqbase,
+			    uint32_t irq_mask)
+{
+
+	write_mlmbreg(KIRKWOOD_MLMB_MIRQIMLR,
+	    read_mlmbreg(KIRKWOOD_MLMB_MIRQIMLR) & ~irq_mask);
+}
+
+/* ARGSUSED */
+static void
+kirkwood_pic_block_high_irqs(struct pic_softc *pic, size_t irqbase,
+			     uint32_t irq_mask)
+{
+
+	write_mlmbreg(KIRKWOOD_MLMB_MIRQIMHR,
+	    read_mlmbreg(KIRKWOOD_MLMB_MIRQIMHR) & ~irq_mask);
+}
+
+static int
+kirkwood_pic_find_pending_high_irqs(struct pic_softc *pic)
+{
+	uint32_t pending;
+
+	pending = read_mlmbreg(KIRKWOOD_MLMB_MICHR) &
+	    read_mlmbreg(KIRKWOOD_MLMB_MIRQIMHR);
+	if (pending == 0)
+		return 0;
+	pic_mark_pending_sources(pic, 0, pending);
+	return 1;
+}
+
+/* ARGSUSED */
+static void
+kirkwood_pic_establish_irq(struct pic_softc *pic, struct intrsource *is)
+{
+	/* Nothing */
+}
+
+static void
+kirkwood_pic_source_name(struct pic_softc *pic, int irq, char *buf, size_t len)
+{
+
+	strlcpy(buf, sources[pic->pic_irqbase + irq], len);
+}
+
+/*
+ * Called with interrupts disabled
+ */
+static int
+kirkwood_find_pending_irqs(void)
+{
+	uint32_t pending;
+
+	pending = read_mlmbreg(KIRKWOOD_MLMB_MICLR) &
+	    read_mlmbreg(KIRKWOOD_MLMB_MIRQIMLR);
+	if (pending == 0)
+		return 0;
+
+	return pic_mark_pending_sources(&kirkwood_pic_low, 0, pending);
+}
+
+/*
+ * Clock functions
+ */
+
+void
+kirkwood_getclks(bus_addr_t iobase)
+{
+	uint32_t reg;
+	uint16_t model;
+
+#define MHz	* 1000 * 1000
+
+	model = mvsoc_model();
+	if (model == MARVELL_KIRKWOOD_88F6281)
+		mvTclk = 200 MHz;
+	else		/* 166MHz */
+		mvTclk = 166666667;
+
+	reg = *(volatile uint32_t *)(iobase + KIRKWOOD_MPP_BASE +
+	    KIRKWOOD_MPP_SAMPLE_AT_RESET);
+	if (model == MARVELL_KIRKWOOD_88F6180) {
+		switch (reg & 0x0000001c) {
+		case 0x00000014: mvPclk =  600 MHz;
+		case 0x00000018: mvPclk =  800 MHz;
+		default:
+			panic("unknown mvPclk\n");
+		}
+		mvSysclk = 200 MHz;
+	} else {
+		switch (reg & 0x0040001a) {
+		case 0x00000008: mvPclk =  600 MHz; break;
+		case 0x00400008: mvPclk =  800 MHz; break;
+		case 0x0040000a: mvPclk = 1000 MHz; break;
+		case 0x00000012: mvPclk = 1200 MHz; break;
+		case 0x00000018: mvPclk = 1200 MHz; break;
+		default:
+			panic("unknown mvPclk\n");
+		}
+
+		switch (reg & 0x000001e0) {
+		case 0x00000060: mvSysclk = mvPclk * 2 / 5; break;
+		case 0x00000080: mvSysclk = mvPclk * 1 / 3; break;
+		case 0x000000c0: mvSysclk = mvPclk * 1 / 4; break;
+		default:
+			panic("unknown mvSysclk\n");
+		}
+	}
+
+#undef MHz
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/arch/arm/marvell/kirkwoodreg.h	Fri Oct 22 09:23:11 2010 +0000
@@ -0,0 +1,206 @@
+/*	$NetBSD: kirkwoodreg.h,v 1.1.4.2 2010/10/22 09:23:11 uebayasi Exp $	*/
+/*
+ * Copyright (c) 2007, 2008 KIYOHARA Takashi
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _KIRKWOODREG_H_
+#define _KIRKWOODREG_H_
+
+#include <arm/marvell/mvsocreg.h>
+#include <dev/marvell/mvgbereg.h>
+
+/*
+ *                MHz TCLK  GbE SATA  TDMI Audio MTS GPIO
+ * 6180:     600/800, 166,  x1,   -,    -,   o,   -,  30
+ * 6190:         600, 166, *x2,  x1,    -,   -,   -,  36	* GbEx1+100BTx1
+ * 6192:         800, 166,  x2,  x2,    o,   o,   o,  36
+ * 6281: 1.0/1.2/1.5, 200,  x2,  x2,    o,   o,   o,  50
+ */
+
+#define KIRKWOOD_UNITID_DDR		MVSOC_UNITID_DDR
+#define KIRKWOOD_UNITID_DEVBUS		MVSOC_UNITID_DEVBUS
+#define KIRKWOOD_UNITID_MLMB		MVSOC_UNITID_MLMB
+#define KIRKWOOD_UNITID_CRYPT		0x3	/* Cryptographic Engine reg */
+#define KIRKWOOD_UNITID_SA		0x3	/* Security Accelelerator reg */
+#define KIRKWOOD_UNITID_PEX		MVSOC_UNITID_PEX
+#define KIRKWOOD_UNITID_USB		0x5	/* USB registers */
+#define KIRKWOOD_UNITID_IDMA		0x6	/* IDMA registers */
+#define KIRKWOOD_UNITID_XOR		0x6	/* XOR registers */
+#define KIRKWOOD_UNITID_GBE		0x7	/* Gigabit Ethernet registers */
+#define KIRKWOOD_UNITID_SATA		0x8	/* SATA registers */
+#define KIRKWOOD_UNITID_SDIO		0x9	/* SDIO registers */
+#define KIRKWOOD_UNITID_AUDIO		0xa	/* Audio registers */
+#define KIRKWOOD_UNITID_MTS		0xb	/* MPEG Transport Stream reg */
+#define KIRKWOOD_UNITID_TDM		0xd	/* TDM registers */
+
+#define KIRKWOOD_ATTR_NAND		0x2f
+#define KIRKWOOD_ATTR_SPI		0x1e
+#define KIRKWOOD_ATTR_BOOTROM		0x1d
+#define KIRKWOOD_ATTR_PEX_MEM		0xe8
+#define KIRKWOOD_ATTR_PEX_IO		0xe0
+#define KIRKWOOD_ATTR_CRYPT		0x00
+
+#define KIRKWOOD_IRQ_HIGH		0	/* High interrupt */
+#define KIRKWOOD_IRQ_BRIDGE		1	/* Mbus-L to Mbus Bridge */
+#define KIRKWOOD_IRQ_H2CPUDB		2	/* Doorbell interrupt */
+#define KIRKWOOD_IRQ_CPU2HDB		3	/* Doorbell interrupt */
+#define KIRKWOOD_IRQ_XOR0CHAN0		5	/* Xor 0 Channel0 */
+#define KIRKWOOD_IRQ_XOR0CHAN1		6	/* Xor 0 Channel1 */
+#define KIRKWOOD_IRQ_XOR1CHAN0		7	/* Xor 1 Channel0 */
+#define KIRKWOOD_IRQ_XOR1CHAN1		8	/* Xor 1 Channel1 */
+#define KIRKWOOD_IRQ_PEX0INT		9	/* PCI Express port0 INT A-D */
+#define KIRKWOOD_IRQ_GBE0SUM		11	/* GbE0 summary */
+#define KIRKWOOD_IRQ_GBE0RX		12	/* GbE0 receive interrupt */
+#define KIRKWOOD_IRQ_GBE0TX		13	/* GbE0 transmit interrupt */
+#define KIRKWOOD_IRQ_GBE0MISC		14	/* GbE0 miscellaneous intr */
+#define KIRKWOOD_IRQ_GBE1SUM		15	/* GbE1 summary */
+#define KIRKWOOD_IRQ_GBE1RX		16	/* GbE1 receive interrupt */
+#define KIRKWOOD_IRQ_GBE1TX		17	/* GbE1 transmit interrupt */
+#define KIRKWOOD_IRQ_GBE1MISC		18	/* GbE1 miscellaneous intr */
+#define KIRKWOOD_IRQ_USB0CNT		19	/* USB0 controller interrupt */
+#define KIRKWOOD_IRQ_SATA		21	/*Sata ports interrupt summary*/
+#define KIRKWOOD_IRQ_SECURITYINT	22	/* Security engine completion */
+#define KIRKWOOD_IRQ_SPIINT		23	/* SPI Interrupt */
+#define KIRKWOOD_IRQ_AUDIOINT		24	/* Audio interrupt */
+#define KIRKWOOD_IRQ_TS0INT		26	/* TS0 Interrupt */
+#define KIRKWOOD_IRQ_SDIOINT		28	/* SDIO Interrupt */
+#define KIRKWOOD_IRQ_TWSI		29	/* TWSI interrupt */
+#define KIRKWOOD_IRQ_AVBINT		30	/* AVB Interrupt */
+#define KIRKWOOD_IRQ_TDMINT		31	/* TDM Interrupt */
+#define KIRKWOOD_IRQ_UART0INT		33	/* UART0 */
+#define KIRKWOOD_IRQ_UART1INT		34	/* UART1 */
+#define KIRKWOOD_IRQ_GPIOLO7_0		35	/* GPIO Low[7:0] */
+#define KIRKWOOD_IRQ_GPIOLO8_15		36	/* GPIO Low[15:8] */
+#define KIRKWOOD_IRQ_GPIOLO16_23	37	/* GPIO Low[23:16] */
+#define KIRKWOOD_IRQ_GPIOLO24_31	38	/* GPIO Low[31:24] */
+#define KIRKWOOD_IRQ_GPIOHI7_0		39	/* GPIO High[7:0] */
+#define KIRKWOOD_IRQ_GPIOHI8_15		40	/* GPIO High[15:8] */
+#define KIRKWOOD_IRQ_GPIOHI16_23	41	/* GPIO High[23:16] */
+#define KIRKWOOD_IRQ_XOR0ERR		42	/* XOR0 error */
+#define KIRKWOOD_IRQ_XOR1ERR		43	/* XOR1 error */
+#define KIRKWOOD_IRQ_PEX0ERR		44	/* PCI Express0 error */
+#define KIRKWOOD_IRQ_GBE0ERR		46	/* GbE port0 error */
+#define KIRKWOOD_IRQ_GBE1ERR		47	/* GbE port1 error */
+#define KIRKWOOD_IRQ_USBERR		48	/* USB error */
+#define KIRKWOOD_IRQ_SECURITYERR	49	/* Cryptographic engine error */
+#define KIRKWOOD_IRQ_AUDIOERR		50	/* Audio error */
+#define KIRKWOOD_IRQ_RTCINT		53	/* Real time clock interrupt */
+
+
+/*
+ * Physical address of integrated peripherals
+ */
+
+#define KIRKWOOD_UNITID2PHYS(uid)	((KIRKWOOD_UNITID_ ## uid) << 16)
+
+/*
+ * Pin Multiplexing Interface Registers
+ */
+#define KIRKWOOD_MPP_BASE		(MVSOC_DEVBUS_BASE + 0x0000)
+#define KIRKWOOD_MPP_SIZE		   0x40		/* XXXX */
+#define KIRKWOOD_MPP_MPPC0R		   0x00
+#define KIRKWOOD_MPP_MPPC1R		   0x04
+#define KIRKWOOD_MPP_MPPC2R		   0x08
+#define KIRKWOOD_MPP_MPPC3R		   0x0c
+#define KIRKWOOD_MPP_MPPC4R		   0x10
+#define KIRKWOOD_MPP_MPPC5R		   0x14
+#define KIRKWOOD_MPP_MPPC6R		   0x18
+#define KIRKWOOD_MPP_SAMPLE_AT_RESET	   0x30
+
+/*
+ * Real-Time Clock Unit Registers
+ */
+#define KIRKWOOD_RTC_BASE		(MVSOC_DEVBUS_BASE + 0x0300)
+
+/*
+ * Serial Peripheral Interface Registers
+ */
+#define KIRKWOOD_SPI_BASE		(MVSOC_DEVBUS_BASE + 0x0600)
+
+/*
+ * Mbus-L to Mbus Bridge Registers
+ */
+/* CPU Address Map Registers */
+#define KIRKWOOD_MLMB_NWINDOW		8
+#define KIRKWOOD_MLMB_NREMAP		4
+
+/* Main Interrupt Controller Registers */
+#define KIRKWOOD_MLMB_MICLR		  0x200	/*Main Interrupt Cause Low reg*/
+#define KIRKWOOD_MLMB_MIRQIMLR		  0x204	/*Main IRQ Interrupt Low Mask*/
+#define KIRKWOOD_MLMB_MFIQIMLR		  0x208	/*Main FIQ Interrupt Low Mask*/
+#define KIRKWOOD_MLMB_EIMLR		  0x20c	/*Endpoint Interrupt Low Mask*/
+#define KIRKWOOD_MLMB_MICHR		  0x210	/*Main Intr Cause High reg*/
+#define KIRKWOOD_MLMB_MIRQIMHR		  0x214	/*Main IRQ Interrupt High Mask*/
+#define KIRKWOOD_MLMB_MFIQIMHR		  0x218	/*Main FIQ Interrupt High Mask*/
+#define KIRKWOOD_MLMB_EIMHR		  0x21c	/*Endpoint Interrupt High Mask*/
+
+
+/*
+ * Cryptographic Engine and Security Accelerator Registers
+ */
+#define KIRKWOOD_CESA_BASE	(KIRKWOOD_UNITID2PHYS(CRYPT))	/* 0x30000 */
+
+/*
+ * USB 2.0 Interface Registers
+ */
+#define KIRKWOOD_USB_BASE	(KIRKWOOD_UNITID2PHYS(USB))	/* 0x50000 */
+
+/*
+ * IDMA Controller and XOR Engine Registers
+ */
+#define KIRKWOOD_IDMAC_BASE	(KIRKWOOD_UNITID2PHYS(IDMA))	/* 0x60000 */
+
+/*
+ * Gigabit Ethernet Registers
+ */
+#define KIRKWOOD_GBE0_BASE	(KIRKWOOD_UNITID2PHYS(GBE))	/* 0x70000 */
+#define KIRKWOOD_GBE1_BASE	(KIRKWOOD_GBE0_BASE + MVGBE_SIZE)
+
+/*
+ * Serial-ATA Host Controller (SATAHC) Registers
+ */
+#define KIRKWOOD_SATAHC_BASE	(KIRKWOOD_UNITID2PHYS(SATA))	/* 0x80000 */
+
+/*
+ * Secure Digital Input/Output (SDIO) Interface Registers
+ */
+#define KIRKWOOD_SDIO_BASE	(KIRKWOOD_UNITID2PHYS(SDIO))	/* 0x90000 */
+
+/*
+ * Audio (I2S/S/PDIF) Interface Registers
+ */
+#define KIRKWOOD_AUDIO_BASE	(KIRKWOOD_UNITID2PHYS(AUDIOSDIO))/* 0xa0000 */
+
+/*
+ * MPEG-2 Transport Stream (TS) Interface Registers
+ */
+#define KIRKWOOD_MTS_BASE	(KIRKWOOD_UNITID2PHYS(MTS))	/* 0xb0000 */
+
+/*
+ * Time Division Multiplexing (TDM) Unit Registers
+ */
+#define KIRKWOOD_TDM_BASE	(KIRKWOOD_UNITID2PHYS(TDM))	/* 0xd0000 */
+
+#endif	/* _KIRKWOODREG_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/arch/arm/marvell/mv78xx0reg.h	Fri Oct 22 09:23:11 2010 +0000
@@ -0,0 +1,206 @@
+/*	$NetBSD: mv78xx0reg.h,v 1.1.4.2 2010/10/22 09:23:11 uebayasi Exp $	*/
+/*
+ * Copyright (c) 2010 KIYOHARA Takashi
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _MV78XX0REG_H_
+#define _MV78XX0REG_H_
+
+#include <arm/marvell/mvsocreg.h>
+
+/*
+ *              MHz  PCIe  GbE  SATA TDMI  COM
+ * MV76100:    800, 2      x2,   x1,   -,  x3
+ * MV78100:    1.2, 2 x4,  x2,   x2,  x2,  x4
+ * MV78200: 1.0 x2, 2 x4,  x4,   x2,  x2,  x4
+ */
+
+#define MV78XX0_UNITID_DDR		MVSOC_UNITID_DDR
+#define MV78XX0_UNITID_DEVBUS		MVSOC_UNITID_DEVBUS
+#define MV78XX0_UNITID_LMB		MVSOC_UNITID_LMB
+#define MV78XX0_UNITID_GBE23		0x3	/* Gigabit Ethernet registers */
+#define MV78XX0_UNITID_PEX		MVSOC_UNITID_PEX
+#define MV78XX0_UNITID_USB		0x5	/* USB registers */
+#define MV78XX0_UNITID_IDMA		0x6	/* IDMA registers */
+#define MV78XX0_UNITID_XOR		0x6	/* XOR registers */
+#define MV78XX0_UNITID_GBE01		0x7	/* Gigabit Ethernet registers */
+#define MV78XX0_UNITID_CRYPT		0x9	/* Cryptographic Engine reg */
+#define MV78XX0_UNITID_SA		0x9	/* Security Accelelerator reg */
+#define MV78XX0_UNITID_SATA		0xa	/* SATA registers */
+#define MV78XX0_UNITID_TDM		0xb	/* TDM registers */
+
+#define MV78XX0_ATTR_DEVICE_CS0		0x3e
+#define MV78XX0_ATTR_DEVICE_CS1		0x3d
+#define MV78XX0_ATTR_DEVICE_CS2		0x3b
+#define MV78XX0_ATTR_DEVICE_CS2		0x37
+#define MV78XX0_ATTR_BOOT_CS		0x2f
+#define MV78XX0_ATTR_SPI		0x1f
+#define MV78XX0_ATTR_PEX_IO		0xe0	/* PCIe x4 Port 0.0 */
+#define MV78XX0_ATTR_PEX_MEM		0xe8
+#define MV78XX0_ATTR_PEX1_IO		0xe0	/* PCIe x1 Port 1 */
+#define MV78XX0_ATTR_PEX1_MEM		0xe8
+#define MV78XX0_ATTR_PEX_0_IO		0xe0	/* PCIe x1 Port 0.0 */
+#define MV78XX0_ATTR_PEX_0_MEM		0xe8
+#define MV78XX0_ATTR_PEX_1_IO		0xd0	/* PCIe x1 Port 0.1 */
+#define MV78XX0_ATTR_PEX_1_MEM		0xd8
+#define MV78XX0_ATTR_PEX_2_IO		0xb0	/* PCIe x1 Port 0.2 */
+#define MV78XX0_ATTR_PEX_2_MEM		0xb8
+#define MV78XX0_ATTR_PEX_3_IO		0x70	/* PCIe x1 Port 0.3 */
+#define MV78XX0_ATTR_PEX_3_MEM		0x78
+
+#define MV78XX0_IRQ_ERRSUM		0	/* Sum of Main Intr Err Cause */
+#define MV78XX0_IRQ_SPI			1	/* SPI */
+#define MV78XX0_IRQ_TWSI0		2	/* TWSI0 */
+#define MV78XX0_IRQ_TWSI1		3	/* TWSI1 */
+#define MV78XX0_IRQ_IDMA0		4	/* IDMA Channel0 completion */
+#define MV78XX0_IRQ_IDMA1		5	/* IDMA Channel1 completion */
+#define MV78XX0_IRQ_IDMA2		6	/* IDMA Channel2 completion */
+#define MV78XX0_IRQ_IDMA3		7	/* IDMA Channel3 completion */
+#define MV78XX0_IRQ_TIMER0		8	/* Timer0 */
+#define MV78XX0_IRQ_TIMER1		9	/* Timer1 */
+#define MV78XX0_IRQ_TIMER2		10	/* Timer2 */
+#define MV78XX0_IRQ_TIMER3		11	/* Timer3 */
+#define MV78XX0_IRQ_UART0		12	/* UART0 */
+#define MV78XX0_IRQ_UART1		13	/* UART1 */
+#define MV78XX0_IRQ_UART2		14	/* UART2 */
+#define MV78XX0_IRQ_UART3		15	/* UART3 */
+#define MV78XX0_IRQ_USB0		16	/* USB0 */
+#define MV78XX0_IRQ_USB1		17	/* USB1 */
+#define MV78XX0_IRQ_USB2		18	/* USB2 */
+#define MV78XX0_IRQ_CRYPTO		19	/* Crypto engine completion */
+#define MV78XX0_IRQ_XOR0		22	/* XOR engine 0 completion */
+#define MV78XX0_IRQ_XOR1		23	/* XOR engine 1 completion */
+#define MV78XX0_IRQ_SATA		26	/* SATA ports */
+#define MV78XX0_IRQ_TDMI_INT		27	/* TDM */
+#define MV78XX0_IRQ_PEX00INTA		32	/* PCIe Port0.0 INTA/B/C/D */
+#define MV78XX0_IRQ_PEX01INTA		33	/* PCIe Port0.1 INTA/B/C/D */
+#define MV78XX0_IRQ_PEX02INTA		34	/* PCIe Port0.2 INTA/B/C/D */
+#define MV78XX0_IRQ_PEX03INTA		35	/* PCIe Port0.3 INTA/B/C/D */
+#define MV78XX0_IRQ_PEX10INTA		36	/* PCIe Port1.0 INTA/B/C/D */
+#define MV78XX0_IRQ_PEX11INTA		37	/* PCIe Port1.1 INTA/B/C/D */
+#define MV78XX0_IRQ_PEX12INTA		38	/* PCIe Port1.2 INTA/B/C/D */
+#define MV78XX0_IRQ_PEX13INTA		39	/* PCIe Port1.3 INTA/B/C/D */
+#define MV78XX0_IRQ_GE00SUM		40	/* Gigabit Ethernet Port0 sum */
+#define MV78XX0_IRQ_GE00RX		41	/* Gigabit Ethernet Port0 Rx */
+#define MV78XX0_IRQ_GE00TX		42	/* Gigabit Ethernet Port0 Tx */
+#define MV78XX0_IRQ_GE00MISC		43	/* Gigabit Ethernet Port0 misc*/
+#define MV78XX0_IRQ_GE01SUM		44	/* Gigabit Ethernet Port1 sum */
+#define MV78XX0_IRQ_GE01RX		45	/* Gigabit Ethernet Port1 Rx */
+#define MV78XX0_IRQ_GE01TX		46	/* Gigabit Ethernet Port1 Tx */
+#define MV78XX0_IRQ_GE01MISC		47	/* Gigabit Ethernet Port1 misc*/
+#define MV78XX0_IRQ_GE10SUM		48	/* Gigabit Ethernet Port2 sum */
+#define MV78XX0_IRQ_GE10RX		49	/* Gigabit Ethernet Port2 Rx */
+#define MV78XX0_IRQ_GE10TX		50	/* Gigabit Ethernet Port2 Tx */
+#define MV78XX0_IRQ_GE10MISC		51	/* Gigabit Ethernet Port2 misc*/
+#define MV78XX0_IRQ_GE11SUM		52	/* Gigabit Ethernet Port3 sum */
+#define MV78XX0_IRQ_GE11RX		53	/* Gigabit Ethernet Port3 Rx */
+#define MV78XX0_IRQ_GE11TX		54	/* Gigabit Ethernet Port3 Tx */
+#define MV78XX0_IRQ_GE11MISC		55	/* Gigabit Ethernet Port3 misc*/
+#define MV78XX0_IRQ_GPIO0_7		56	/* GPIO[7:0] */
+#define MV78XX0_IRQ_GPIO8_15		57	/* GPIO[15:8] */
+#define MV78XX0_IRQ_GPIO16_23		58	/* GPIO[23:16] */
+#define MV78XX0_IRQ_GPIO24_31		59	/* GPIO[31:24] */
+#define MV78XX0_IRQ_DB_IN		60 /*Summary of Inbound Doorbell Cause*/
+#define MV78XX0_IRQ_DB_OUT		61/*Summary of Outbound Doorbell Cause*/
+
+
+/*
+ * Physical address of integrated peripherals
+ */
+
+#undef UNITID2PHYS
+#define UNITID2PHYS(uid)	((MV78XX0_UNITID_ ## uid) << 16)
+
+/*
+ * General Purpose Port Registers
+ */
+#define MV78XX0_GPP_BASE		(MVSOC_DEVBUS_BASE + 0x0100)
+#define MV78XX0_GPP_SIZE		  0x100
+
+/*
+ * UART Interface Registers
+ */
+					/* NS16550 compatible */
+#define MV78XX0_COM2_BASE		(MVSOC_DEVBUS_BASE + 0x2200)
+#define MV78XX0_COM3_BASE		(MVSOC_DEVBUS_BASE + 0x2300)
+
+/*
+ * Mbus-L to Mbus Bridge Registers
+ */
+/* CPU Address Map Registers */
+#define MV78XX0_MLMB_NWINDOW		14
+#define MV78XX0_MLMB_NREMAP		8
+
+/* Main Interrupt Controller Registers */
+#define MV78XX0_MLMB_MICLR		  0x200	/*Main Interrupt Cause Low reg*/
+#define MV78XX0_MLMB_MIRQIMLR		  0x204	/* Main IRQ Interrupt Mask */
+#define MV78XX0_MLMB_MFIQIMLR		  0x208	/* Main FIQ Interrupt Mask */
+#define MV78XX0_MLMB_EIMLR		  0x20c	/* Endpoint Interrupt Mask */
+#define MV78XX0_MLMB_MICHR		  0x210	/* Main Intr Cause High reg */
+#define MV78XX0_MLMB_MIRQIMHR		  0x214 /*Main IRQ Interrupt High Mask*/
+#define MV78XX0_MLMB_MFIQIMHR		  0x218 /*Main FIQ Interrupt High Mask*/
+#define MV78XX0_MLMB_EIMHR		  0x21c	/*Endpoint Interrupt High Mask*/
+
+/* CPU Timers Registers */
+/*   see oriontmrreg.h */
+
+
+/*
+ * PCI Express Interface Registers
+ */
+#define MV78XX0_PEX_BASE	(UNITID2PHYS(PEX))	/* 0x40000 */
+
+/*
+ * USB 2.0 Interface Registers
+ */
+#define MV78XX0_USB_BASE	(UNITID2PHYS(USB))	/* 0x50000 */
+
+/*
+ * IDMA Controller and XOR Engine Registers
+ */
+#define MV78XX0_IDMAC_BASE	(UNITID2PHYS(IDMA))	/* 0x60000 */
+
+/*
+ * Gigabit Ethernet Registers
+ */
+#define MV78XX0_GBE01_BASE	(UNITID2PHYS(GBE01))	/* 0x70000 */
+#define MV78XX0_GBE23_BASE	(UNITID2PHYS(GBE23))	/* 0x30000 */
+
+/*
+ * Cryptographic Engine and Security Accelerator Registers
+ */
+#define MV78XX0_CESA_BASE	(UNITID2PHYS(CRYPT))	/* 0x90000 */
+
+/*
+ * Serial-ATA Host Controller (SATAHC) Registers
+ */
+#define MV78XX0_SATAHC_BASE	(UNITID2PHYS(SATA))	/* 0xa0000 */
+
+/*
+ * Time Division Multiplexing (TDM) Unit Registers
+ */
+#define MV78XX0_TDM_BASE	(UNITID2PHYS(TDM))	/* 0xb0000 */
+
+#endif	/* _MV78XX0REG_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/arch/arm/marvell/mvsoc.c	Fri Oct 22 09:23:11 2010 +0000
@@ -0,0 +1,649 @@
+/*	$NetBSD: mvsoc.c,v 1.1.4.2 2010/10/22 09:23:11 uebayasi Exp $	*/
+/*
+ * Copyright (c) 2007, 2008 KIYOHARA Takashi
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: mvsoc.c,v 1.1.4.2 2010/10/22 09:23:11 uebayasi Exp $");
+
+#include "opt_cputypes.h"
+#include "opt_mvsoc.h"
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/device.h>
+#include <sys/errno.h>
+
+#include <dev/pci/pcidevs.h>
+#include <dev/pci/pcireg.h>
+#include <dev/marvell/marvellreg.h>
+#include <dev/marvell/marvellvar.h>
+
+#include <arm/marvell/mvsocreg.h>
+#include <arm/marvell/mvsocvar.h>
+#include <arm/marvell/orionreg.h>
+#include <arm/marvell/kirkwoodreg.h>
+
+#include "locators.h"
+
+
+static int mvsoc_match(device_t, struct cfdata *, void *);
+static void mvsoc_attach(device_t, device_t, void *);
+
+static int mvsoc_print(void *, const char *);
+static int mvsoc_search(device_t, cfdata_t, const int *, void *);
+
+uint32_t mvPclk, mvSysclk, mvTclk = 0;
+int nwindow = 0, nremap = 0;
+static vaddr_t regbase = 0xffffffff, dsc_base, pex_base;
+vaddr_t mlmb_base;
+
+void (*mvsoc_intr_init)(void);
+
+
+/* attributes */
+static struct {
+	int tag;
+	uint32_t attr;
+	uint32_t target;
+} mvsoc_tags[] = {
+	{ MARVELL_TAG_SDRAM_CS0,
+	  MARVELL_ATTR_SDRAM_CS0,	MVSOC_UNITID_DDR },
+	{ MARVELL_TAG_SDRAM_CS1,
+	  MARVELL_ATTR_SDRAM_CS1,	MVSOC_UNITID_DDR },
+	{ MARVELL_TAG_SDRAM_CS2,
+	  MARVELL_ATTR_SDRAM_CS2,	MVSOC_UNITID_DDR },
+	{ MARVELL_TAG_SDRAM_CS3,
+	  MARVELL_ATTR_SDRAM_CS3,	MVSOC_UNITID_DDR },
+
+#if defined(ORION)
+	{ ORION_TAG_DEVICE_CS0,
+	  ORION_ATTR_DEVICE_CS0,	MVSOC_UNITID_DEVBUS },
+	{ ORION_TAG_DEVICE_CS1,
+	  ORION_ATTR_DEVICE_CS1,	MVSOC_UNITID_DEVBUS },
+	{ ORION_TAG_DEVICE_CS2,
+	  ORION_ATTR_DEVICE_CS2,	MVSOC_UNITID_DEVBUS },
+	{ ORION_TAG_DEVICE_BOOTCS,
+	  ORION_ATTR_BOOT_CS,		MVSOC_UNITID_DEVBUS },
+	{ ORION_TAG_FLASH_CS,
+	  ORION_ATTR_FLASH_CS,		MVSOC_UNITID_DEVBUS },
+	{ ORION_TAG_PEX0_MEM,
+	  ORION_ATTR_PEX_MEM,		ORION_UNITID_PEX },
+	{ ORION_TAG_PEX0_IO,
+	  ORION_ATTR_PEX_IO,		ORION_UNITID_PEX },
+	{ ORION_TAG_PEX1_MEM,
+	  ORION_ATTR_PEX_MEM,		ORION_UNITID_PEX1 },
+	{ ORION_TAG_PEX1_IO,
+	  ORION_ATTR_PEX_IO,		ORION_UNITID_PEX1 },
+	{ ORION_TAG_PCI_MEM,
+	  ORION_ATTR_PCI_MEM,		ORION_UNITID_PCI },
+	{ ORION_TAG_PCI_IO,
+	  ORION_ATTR_PCI_IO,		ORION_UNITID_PCI },
+	{ ORION_TAG_CRYPT,
+	  ORION_ATTR_CRYPT,		ORION_UNITID_CRYPT },
+#endif
+
+#if defined(KIRKWOOD)
+	{ KIRKWOOD_TAG_NAND,
+	  KIRKWOOD_ATTR_NAND,		MVSOC_UNITID_DEVBUS },
+	{ KIRKWOOD_TAG_SPI,
+	  KIRKWOOD_ATTR_SPI,		MVSOC_UNITID_DEVBUS },
+	{ KIRKWOOD_TAG_BOOTROM,
+	  KIRKWOOD_ATTR_BOOTROM,	MVSOC_UNITID_DEVBUS },
+	{ KIRKWOOD_TAG_PEX_MEM,
+	  KIRKWOOD_ATTR_PEX_MEM,	KIRKWOOD_UNITID_PEX },
+	{ KIRKWOOD_TAG_PEX_IO,
+	  KIRKWOOD_ATTR_PEX_IO,		KIRKWOOD_UNITID_PEX },
+	{ KIRKWOOD_TAG_CRYPT,
+	  KIRKWOOD_ATTR_CRYPT,		KIRKWOOD_UNITID_CRYPT },
+#endif
+};
+
+#if defined(ORION)
+#define ORION_1(m)	MARVELL_ORION_1_ ## m
+#define ORION_2(m)	MARVELL_ORION_2_ ## m
+#endif
+#if defined(KIRKWOOD)
+#undef KIRKWOOD
+#define KIRKWOOD(m)	MARVELL_KIRKWOOD_ ## m
+#endif
+#if defined(MV78XX0)
+#undef MV78XX0
+#define MV78XX0(m)	MARVELL_MV78XX0_ ## m
+#endif
+static struct {
+	uint16_t model;
+	uint8_t rev;
+	const char *modelstr;
+	const char *revstr;
+	const char *typestr;
+} nametbl[] = {
+#if defined(ORION)
+	{ ORION_1(88F1181),	0, "MV88F1181", NULL,	"Orion1" },
+	{ ORION_1(88F5082),	2, "MV88F5082", "A2",	"Orion1" },
+	{ ORION_1(88F5180N),	3, "MV88F5180N","B1",	"Orion1" },
+	{ ORION_1(88F5181),	0, "MV88F5181",	"A0",	"Orion1" },
+	{ ORION_1(88F5181),	1, "MV88F5181",	"A1",	"Orion1" },
+	{ ORION_1(88F5181),	2, "MV88F5181",	"B0",	"Orion1" },
+	{ ORION_1(88F5181),	3, "MV88F5181",	"B1",	"Orion1" },
+	{ ORION_1(88F5181),	8, "MV88F5181L","A0",	"Orion1" },
+	{ ORION_1(88F5181),	9, "MV88F5181L","A1",	"Orion1" },
+	{ ORION_1(88F5182),	0, "MV88F5182",	"A0",	"Orion1" },
+	{ ORION_1(88F5182),	1, "MV88F5182",	"A1",	"Orion1" },
+	{ ORION_1(88F5182),	2, "MV88F5182",	"A2",	"Orion1" },
+	{ ORION_1(88F6082),	0, "MV88F6082",	"A0",	"Orion1" },
+	{ ORION_1(88F6082),	1, "MV88F6082",	"A1",	"Orion1" },
+	{ ORION_1(88F6183),	0, "MV88F6183",	"A0",	"Orion1" },
+	{ ORION_1(88F6183),	1, "MV88F6183",	"Z0",	"Orion1" },
+	{ ORION_1(88W8660),	0, "MV88W8660",	"A0",	"Orion1" },
+	{ ORION_1(88W8660),	1, "MV88W8660",	"A1",	"Orion1" },
+
+	{ ORION_2(88F1281),	0, "MV88F1281",	"A0",	"Orion2" },
+	{ ORION_2(88F5281),	0, "MV88F5281",	"A0",	"Orion2" },
+	{ ORION_2(88F5281),	1, "MV88F5281",	"B0",	"Orion2" },
+	{ ORION_2(88F5281),	2, "MV88F5281",	"C0",	"Orion2" },
+	{ ORION_2(88F5281),	3, "MV88F5281",	"C1",	"Orion2" },
+	{ ORION_2(88F5281),	4, "MV88F5281",	"D0",	"Orion2" },
+#endif
+
+#if defined(KIRKWOOD)
+	{ KIRKWOOD(88F6180),	2, "88F6180",	"A0",	"Kirkwood" },
+	{ KIRKWOOD(88F6192),	0, "88F619x",	"Z0",	"Kirkwood" },
+	{ KIRKWOOD(88F6192),	2, "88F619x",	"A0",	"Kirkwood" },
+	{ KIRKWOOD(88F6281),	0, "88F6281",	"Z0",	"Kirkwood" },
+	{ KIRKWOOD(88F6281),	2, "88F6281",	"A0",	"Kirkwood" },
+	{ KIRKWOOD(88F6281),	3, "88F6281",	"A1",	"Kirkwood" },
+#endif
+
+#if defined(MV78XX0)
+	{ MV78XX0(MV78100),	1, "MV78100",	"A0",  "Discovery Innovation" },
+	{ MV78XX0(MV78100),	2, "MV78100",	"A1",  "Discovery Innovation" },
+	{ MV78XX0(MV78200),	1, "MV78200",	"A0",  "Discovery Innovation" },
+#endif
+};
+
+#define OFFSET_DEFAULT	MVA_OFFSET_DEFAULT
+#define IRQ_DEFAULT	MVA_IRQ_DEFAULT
+static const struct mvsoc_periph {
+	int model;
+	const char *name;
+	int unit;
+	bus_size_t offset;
+	int irq;
+} mvsoc_periphs[] = {
+#if defined(ORION)
+    { ORION_1(88F1181),	"mvsoctmr",0, MVSOC_TMR_BASE,	IRQ_DEFAULT },
+    { ORION_1(88F1181),	"mvsocgpp",0, MVSOC_GPP_BASE,	ORION_IRQ_GPIO7_0 },
+    { ORION_1(88F1181),	"com",     0, MVSOC_COM0_BASE,	ORION_IRQ_UART0 },
+    { ORION_1(88F1181),	"com",     1, MVSOC_COM1_BASE,	ORION_IRQ_UART1 },
+    { ORION_1(88F1181),	"gttwsi",  0, MVSOC_TWSI_BASE,	ORION_IRQ_TWSI },
+    { ORION_1(88F1181),	"mvpex",   0, MVSOC_PEX_BASE,	ORION_IRQ_PEX0INT },
+    { ORION_1(88F1181),	"mvpex",   1, ORION_PEX1_BASE,	ORION_IRQ_PEX1INT },
+
+    { ORION_1(88F5082),	"mvsoctmr",0, MVSOC_TMR_BASE,	IRQ_DEFAULT },
+    { ORION_1(88F5082),	"mvsocgpp",0, MVSOC_GPP_BASE,	ORION_IRQ_GPIO7_0 },
+    { ORION_1(88F5082),	"com",     0, MVSOC_COM0_BASE,	ORION_IRQ_UART0 },
+    { ORION_1(88F5082),	"com",     1, MVSOC_COM1_BASE,	ORION_IRQ_UART1 },
+    { ORION_1(88F5082),	"ehci",    0, ORION_USB0_BASE,	ORION_IRQ_USBCNT0 },
+    { ORION_1(88F5082),	"ehci",    1, ORION_USB1_BASE,	ORION_IRQ_USBCNT1 },
+//  { ORION_1(88F5082),	"gtidmac", 0, ORION_IDMAC_BASE,	0 },
+    { ORION_1(88F5082),	"gttwsi",  0, MVSOC_TWSI_BASE,	ORION_IRQ_TWSI },
+    { ORION_1(88F5082),	"mvcesa",  0, ORION_CESA_BASE,	ORION_IRQ_SECURITYINTR},
+    { ORION_1(88F5082),	"mvgbec",  0, ORION_GBE_BASE,	IRQ_DEFAULT },
+    { ORION_1(88F5082),	"mvpex",   0, MVSOC_PEX_BASE,	ORION_IRQ_PEX0INT },
+    { ORION_1(88F5082),	"mvsata",  0, ORION_SATAHC_BASE,ORION_IRQ_SATAINTR },
+
+    { ORION_1(88F5180N),"mvsoctmr",0, MVSOC_TMR_BASE,	IRQ_DEFAULT },
+    { ORION_1(88F5180N),"mvsocgpp",0, MVSOC_GPP_BASE,	ORION_IRQ_GPIO7_0 },
+    { ORION_1(88F5180N),"com",     0, MVSOC_COM0_BASE,	ORION_IRQ_UART0 },
+    { ORION_1(88F5180N),"com",     1, MVSOC_COM1_BASE,	ORION_IRQ_UART1 },
+    { ORION_1(88F5180N),"ehci",    0, ORION_USB0_BASE,	ORION_IRQ_USBCNT0 },
+//  { ORION_1(88F5180N),"gtidmac", 0, ORION_IDMAC_BASE,	0 },
+    { ORION_1(88F5180N),"gtpci",   0, ORION_PCI_BASE,	ORION_IRQ_PEX0INT },
+    { ORION_1(88F5180N),"gttwsi",  0, MVSOC_TWSI_BASE,	ORION_IRQ_TWSI },
+    { ORION_1(88F5180N),"mvgbec",  0, ORION_GBE_BASE,	IRQ_DEFAULT },
+    { ORION_1(88F5180N),"mvpex",   0, MVSOC_PEX_BASE,	ORION_IRQ_PEX0INT },
+
+    { ORION_1(88F5181),	"mvsoctmr",0, MVSOC_TMR_BASE,	IRQ_DEFAULT },
+    { ORION_1(88F5181),	"mvsocgpp",0, MVSOC_GPP_BASE,	ORION_IRQ_GPIO7_0 },
+    { ORION_1(88F5181),	"com",     0, MVSOC_COM0_BASE,	ORION_IRQ_UART0 },
+    { ORION_1(88F5181),	"com",     1, MVSOC_COM1_BASE,	ORION_IRQ_UART1 },
+    { ORION_1(88F5181),	"ehci",    0, ORION_USB0_BASE,	ORION_IRQ_USBCNT0 },
+//  { ORION_1(88F5181),	"gtidmac", 0, ORION_IDMAC_BASE,	0 },
+    { ORION_1(88F5181),	"gtpci",   0, ORION_PCI_BASE,	ORION_IRQ_PEX0INT },
+    { ORION_1(88F5181),	"gttwsi",  0, MVSOC_TWSI_BASE,	ORION_IRQ_TWSI },
+    { ORION_1(88F5181),	"mvcesa",  0, ORION_CESA_BASE,	ORION_IRQ_SECURITYINTR},
+    { ORION_1(88F5181),	"mvgbec",  0, ORION_GBE_BASE,	IRQ_DEFAULT },
+    { ORION_1(88F5181),	"mvpex",   0, MVSOC_PEX_BASE,	ORION_IRQ_PEX0INT },
+
+    { ORION_1(88F5182),	"mvsoctmr",0, MVSOC_TMR_BASE,	IRQ_DEFAULT },
+    { ORION_1(88F5182),	"mvsocgpp",0, MVSOC_GPP_BASE,	ORION_IRQ_GPIO7_0 },
+    { ORION_1(88F5182),	"com",     0, MVSOC_COM0_BASE,	ORION_IRQ_UART0 },
+    { ORION_1(88F5182),	"com",     1, MVSOC_COM1_BASE,	ORION_IRQ_UART1 },
+    { ORION_1(88F5182),	"ehci",    0, ORION_USB0_BASE,	ORION_IRQ_USBCNT0 },
+    { ORION_1(88F5182),	"ehci",    1, ORION_USB1_BASE,	ORION_IRQ_USBCNT1 },
+//  { ORION_1(88F5182),	"gtidmac", 0, ORION_IDMAC_BASE,	0 },
+    { ORION_1(88F5182),	"gtpci",   0, ORION_PCI_BASE,	ORION_IRQ_PEX0INT },
+    { ORION_1(88F5182),	"gttwsi",  0, MVSOC_TWSI_BASE,	ORION_IRQ_TWSI },
+    { ORION_1(88F5182),	"mvgbec",  0, ORION_GBE_BASE,	IRQ_DEFAULT },
+    { ORION_1(88F5182),	"mvsata",  0, ORION_SATAHC_BASE,ORION_IRQ_SATAINTR },
+    { ORION_1(88F5182),	"mvpex",   0, MVSOC_PEX_BASE,	ORION_IRQ_PEX0INT },
+
+    { ORION_1(88F6082),	"mvsoctmr",0, MVSOC_TMR_BASE,	IRQ_DEFAULT },
+    { ORION_1(88F6082),	"mvsocgpp",0, MVSOC_GPP_BASE,	ORION_IRQ_GPIO7_0 },
+    { ORION_1(88F6082),	"com",     0, MVSOC_COM0_BASE,	ORION_IRQ_UART0 },
+    { ORION_1(88F6082),	"com",     1, MVSOC_COM1_BASE,	ORION_IRQ_UART1 },
+    { ORION_1(88F6082),	"ehci",    0, ORION_USB0_BASE,	ORION_IRQ_USBCNT0 },
+    { ORION_1(88F6082),	"gttwsi",  0, MVSOC_TWSI_BASE,	ORION_IRQ_TWSI },
+    { ORION_1(88F6082),	"mvcesa",  0, ORION_CESA_BASE,	ORION_IRQ_SECURITYINTR},
+    { ORION_1(88F6082),	"mvgbec",  0, ORION_GBE_BASE,	IRQ_DEFAULT },
+    { ORION_1(88F6082),	"mvsata",  0, ORION_SATAHC_BASE,ORION_IRQ_SATAINTR },
+    { ORION_1(88F6082),	"mvpex",   0, MVSOC_PEX_BASE,	ORION_IRQ_PEX0INT },
+
+    { ORION_1(88F6183),	"mvsoctmr",0, MVSOC_TMR_BASE,	IRQ_DEFAULT },
+    { ORION_1(88F6183),	"mvsocgpp",0, MVSOC_GPP_BASE,	ORION_IRQ_GPIO7_0 },
+    { ORION_1(88F6183),	"gttwsi",  0, MVSOC_TWSI_BASE,	ORION_IRQ_TWSI },
+    { ORION_1(88F6183),	"mvpex",   0, MVSOC_PEX_BASE,	ORION_IRQ_PEX0INT },
+
+    { ORION_1(88W8660),	"mvsoctmr",0, MVSOC_TMR_BASE,	IRQ_DEFAULT },
+    { ORION_1(88W8660),	"mvsocgpp",0, MVSOC_GPP_BASE,	ORION_IRQ_GPIO7_0 },
+    { ORION_1(88W8660),	"com",     0, MVSOC_COM0_BASE,	ORION_IRQ_UART0 },
+    { ORION_1(88W8660),	"com",     1, MVSOC_COM1_BASE,	ORION_IRQ_UART1 },
+    { ORION_1(88W8660),	"ehci",    0, ORION_USB0_BASE,	ORION_IRQ_USBCNT0 },
+//  { ORION_1(88W8660),	"gtidmac", 0, ORION_IDMAC_BASE,	0 },
+    { ORION_1(88W8660),	"gtpci",   0, ORION_PCI_BASE,	ORION_IRQ_PEX0INT },
+    { ORION_1(88W8660),	"gttwsi",  0, MVSOC_TWSI_BASE,	ORION_IRQ_TWSI },
+    { ORION_1(88W8660),	"mvgbec",  0, ORION_GBE_BASE,	IRQ_DEFAULT },
+    { ORION_1(88W8660),	"mvpex",   0, MVSOC_PEX_BASE,	ORION_IRQ_PEX0INT },
+
+    { ORION_2(88F1281),	"mvsoctmr",0, MVSOC_TMR_BASE,	IRQ_DEFAULT },
+    { ORION_2(88F1281),	"mvsocgpp",0, MVSOC_GPP_BASE,	ORION_IRQ_GPIO7_0 },
+    { ORION_2(88F1281),	"com",     0, MVSOC_COM0_BASE,	ORION_IRQ_UART0 },
+    { ORION_2(88F1281),	"com",     1, MVSOC_COM1_BASE,	ORION_IRQ_UART1 },
+    { ORION_2(88F1281),	"gttwsi",  0, MVSOC_TWSI_BASE,	ORION_IRQ_TWSI },
+    { ORION_2(88F1281),	"mvpex",   0, MVSOC_PEX_BASE,	ORION_IRQ_PEX0INT },
+    { ORION_2(88F1281),	"mvpex",   1, ORION_PEX1_BASE,	ORION_IRQ_PEX1INT },
+
+    { ORION_2(88F5281),	"mvsoctmr",0, MVSOC_TMR_BASE,	IRQ_DEFAULT },
+    { ORION_2(88F5281),	"mvsocgpp",0, MVSOC_GPP_BASE,	ORION_IRQ_GPIO7_0 },
+    { ORION_2(88F5281),	"com",     0, MVSOC_COM0_BASE,	ORION_IRQ_UART0 },
+    { ORION_2(88F5281),	"com",     1, MVSOC_COM1_BASE,	ORION_IRQ_UART1 },
+    { ORION_2(88F5281),	"ehci",    0, ORION_USB0_BASE,	ORION_IRQ_USBCNT0 },
+//  { ORION_2(88F5281),	"gtidmac", 0, ORION_IDMAC_BASE,	0 },
+    { ORION_2(88F5281),	"gtpci",   0, ORION_PCI_BASE,	ORION_IRQ_PEX0INT },
+    { ORION_2(88F5281),	"gttwsi",  0, MVSOC_TWSI_BASE,	ORION_IRQ_TWSI },
+    { ORION_2(88F5281),	"mvgbec",  0, ORION_GBE_BASE,	IRQ_DEFAULT },
+    { ORION_2(88F5281),	"mvpex",   0, MVSOC_PEX_BASE,	ORION_IRQ_PEX0INT },
+#endif
+
+#if defined(KIRKWOOD)
+    { KIRKWOOD(88F6180),"mvsoctmr",0, MVSOC_TMR_BASE,	IRQ_DEFAULT },
+    { KIRKWOOD(88F6180),"mvsocgpp",0, MVSOC_GPP_BASE,	KIRKWOOD_IRQ_GPIOLO7_0},
+    { KIRKWOOD(88F6180),"com",     0, MVSOC_COM0_BASE,	KIRKWOOD_IRQ_UART0INT },
+    { KIRKWOOD(88F6180),"com",     1, MVSOC_COM1_BASE,	KIRKWOOD_IRQ_UART1INT },
+    { KIRKWOOD(88F6180),"ehci",    0, KIRKWOOD_USB_BASE,KIRKWOOD_IRQ_USB0CNT },
+//  { KIRKWOOD(88F6180),"gtidmac", 0, KIRKWOOD_IDMAC_BASE,? },
+    { KIRKWOOD(88F6180),"gttwsi",  0, MVSOC_TWSI_BASE,	KIRKWOOD_IRQ_TWSI },
+    { KIRKWOOD(88F6180),"mvcesa",  0, KIRKWOOD_CESA_BASE,KIRKWOOD_IRQ_SECURITYINT},
+    { KIRKWOOD(88F6180),"mvgbec",  0, KIRKWOOD_GBE0_BASE,IRQ_DEFAULT },
+    { KIRKWOOD(88F6180),"mvpex",   0, MVSOC_PEX_BASE,	KIRKWOOD_IRQ_PEX0INT },
+    { KIRKWOOD(88F6180),"mvsdio",  0, KIRKWOOD_SDIO_BASE,KIRKWOOD_IRQ_SDIOINT },
+
+    { KIRKWOOD(88F6192),"mvsoctmr",0, MVSOC_TMR_BASE,	IRQ_DEFAULT },
+    { KIRKWOOD(88F6192),"mvsocgpp",0, MVSOC_GPP_BASE,	KIRKWOOD_IRQ_GPIOLO7_0},
+    { KIRKWOOD(88F6192),"com",     0, MVSOC_COM0_BASE,	KIRKWOOD_IRQ_UART0INT },
+    { KIRKWOOD(88F6192),"com",     1, MVSOC_COM1_BASE,	KIRKWOOD_IRQ_UART1INT },
+    { KIRKWOOD(88F6192),"ehci",    0, KIRKWOOD_USB_BASE,KIRKWOOD_IRQ_USB0CNT },
+//  { KIRKWOOD(88F6192),"gtidmac", 0, KIRKWOOD_IDMAC_BASE,? },
+    { KIRKWOOD(88F6192),"gttwsi",  0, MVSOC_TWSI_BASE,	KIRKWOOD_IRQ_TWSI },
+    { KIRKWOOD(88F6192),"mvcesa",  0, KIRKWOOD_CESA_BASE,KIRKWOOD_IRQ_SECURITYINT},
+    { KIRKWOOD(88F6192),"mvgbec",  0, KIRKWOOD_GBE0_BASE,IRQ_DEFAULT },
+    { KIRKWOOD(88F6192),"mvgbec",  1, KIRKWOOD_GBE1_BASE,IRQ_DEFAULT },
+    { KIRKWOOD(88F6192),"mvpex",   0, MVSOC_PEX_BASE,	KIRKWOOD_IRQ_PEX0INT },
+    { KIRKWOOD(88F6192),"mvsata",  0, KIRKWOOD_SATAHC_BASE,KIRKWOOD_IRQ_SATA },
+    { KIRKWOOD(88F6192),"mvsdio",  0, KIRKWOOD_SDIO_BASE,KIRKWOOD_IRQ_SDIOINT },
+
+    { KIRKWOOD(88F6281),"mvsoctmr",0, MVSOC_TMR_BASE,	IRQ_DEFAULT },
+    { KIRKWOOD(88F6281),"mvsocgpp",0, MVSOC_GPP_BASE,	KIRKWOOD_IRQ_GPIOLO7_0},
+    { KIRKWOOD(88F6281),"com",     0, MVSOC_COM0_BASE,	KIRKWOOD_IRQ_UART0INT },
+    { KIRKWOOD(88F6281),"com",     1, MVSOC_COM1_BASE,	KIRKWOOD_IRQ_UART1INT },
+    { KIRKWOOD(88F6281),"ehci",    0, KIRKWOOD_USB_BASE,KIRKWOOD_IRQ_USB0CNT },
+//  { KIRKWOOD(88F6281),"gtidmac", 0, KIRKWOOD_IDMAC_BASE,? },
+    { KIRKWOOD(88F6281),"gttwsi",  0, MVSOC_TWSI_BASE,	KIRKWOOD_IRQ_TWSI },
+    { KIRKWOOD(88F6281),"mvcesa",  0, KIRKWOOD_CESA_BASE,KIRKWOOD_IRQ_SECURITYINT},
+    { KIRKWOOD(88F6281),"mvgbec",  0, KIRKWOOD_GBE0_BASE,IRQ_DEFAULT },
+    { KIRKWOOD(88F6281),"mvgbec",  1, KIRKWOOD_GBE1_BASE,IRQ_DEFAULT },
+    { KIRKWOOD(88F6281),"mvpex",   0, MVSOC_PEX_BASE,	KIRKWOOD_IRQ_PEX0INT },
+    { KIRKWOOD(88F6281),"mvsata",  0, KIRKWOOD_SATAHC_BASE,KIRKWOOD_IRQ_SATA },
+    { KIRKWOOD(88F6281),"mvsdio",  0, KIRKWOOD_SDIO_BASE,KIRKWOOD_IRQ_SDIOINT },
+#endif
+
+#if defined(MV78XX0)
+    { MV78XX0(MV78100),	"mvsoctmr",0,MVSOC_TMR_BASE,	IRQ_DEFAULT },
+    { MV78XX0(MV78100),	"mvsocgpp",0,MVSOC_GPP_BASE,	MV78XX0_IRQ_GPIOLO7_0 },
+    { MV78XX0(MV78100),	"com",	0, MVSOC_COM0_BASE,	MV78XX0_IRQ_UART0INT },
+    { MV78XX0(MV78100),	"com",	1, MVSOC_COM1_BASE,	MV78XX0_IRQ_UART1INT },
+    { MV78XX0(MV78100),	"gttwsi",0,MVSOC_TWSI_BASE,	MV78XX0_IRQ_TWSI },
+      :
+
+    { MV78XX0(MV78200),	"mvsoctmr",0,MVSOC_TMR_BASE,	IRQ_DEFAULT },
+    { MV78XX0(MV78200),	"mvsocgpp",0,MVSOC_GPP_BASE,	MV78XX0_IRQ_GPIOLO7_0 },
+    { MV78XX0(MV78200),	"com",	0, MVSOC_COM0_BASE,	MV78XX0_IRQ_UART0INT },
+    { MV78XX0(MV78200),	"com",	1, MVSOC_COM1_BASE,	MV78XX0_IRQ_UART1INT },
+    { MV78XX0(MV78200),	"gttwsi",0,MVSOC_TWSI_BASE,	MV78XX0_IRQ_TWSI },
+      :
+#endif
+};
+
+
+CFATTACH_DECL_NEW(mvsoc, sizeof(struct mvsoc_softc),
+    mvsoc_match, mvsoc_attach, NULL, NULL);
+
+/* ARGSUSED */
+static int
+mvsoc_match(device_t parent, struct cfdata *match, void *aux)
+{
+
+	return 1;
+}
+
+/* ARGSUSED */
+static void
+mvsoc_attach(device_t parent, device_t self, void *aux)
+{
+	struct mvsoc_softc *sc = device_private(self);
+	struct marvell_attach_args mva;
+	uint16_t model;
+	uint8_t rev;
+	int i;
+
+	sc->sc_dev = self;
+	sc->sc_iot = &mvsoc_bs_tag;
+	sc->sc_addr = regbase;
+	sc->sc_dmat = &mvsoc_bus_dma_tag;
+	if (bus_space_map(sc->sc_iot, sc->sc_addr, 0x100000, 0, &sc->sc_ioh) !=
+	    0) {
+		aprint_error_dev(self, "can't map registers\n");
+		return;
+	}
+
+	model = mvsoc_model();
+	rev = mvsoc_rev();
+	for (i = 0; i < __arraycount(nametbl); i++)
+		if (nametbl[i].model == model && nametbl[i].rev == rev)
+			break;
+	if (i >= __arraycount(nametbl))
+		panic("unknown SoC: model 0x%04x, rev 0x%02x", model, rev);
+
+	aprint_normal(": Marvell %s %s%s  %s\n",
+	    nametbl[i].modelstr,
+	    nametbl[i].revstr != NULL ? "Rev. " : "",
+	    nametbl[i].revstr != NULL ? nametbl[i].revstr : "",
+	    nametbl[i].typestr);
+        aprint_normal("%s: CPU Clock %d.%03d MHz"
+	    "  SysClock %d.%03d MHz  TClock %d.%03d MHz\n",
+	    device_xname(self),
+	    mvPclk / 1000000, (mvPclk / 1000) % 1000,
+	    mvSysclk / 1000000, (mvSysclk / 1000) % 1000,
+	    mvTclk / 1000000, (mvTclk / 1000) % 1000);
+	aprint_naive("\n");
+
+	mvsoc_intr_init();
+
+	for (i = 0; i < __arraycount(mvsoc_periphs); i++) {
+		if (mvsoc_periphs[i].model != model)
+			continue;
+
+		mva.mva_name = mvsoc_periphs[i].name;
+		mva.mva_model = model;
+		mva.mva_revision = rev;
+		mva.mva_iot = sc->sc_iot;
+		mva.mva_ioh = sc->sc_ioh;
+		mva.mva_unit = mvsoc_periphs[i].unit;
+		mva.mva_addr = sc->sc_addr;
+		mva.mva_offset = mvsoc_periphs[i].offset;
+		mva.mva_size = 0;
+		mva.mva_dmat = sc->sc_dmat;
+		mva.mva_irq = mvsoc_periphs[i].irq;
+
+		config_found_sm_loc(sc->sc_dev, "mvsoc", NULL, &mva,
+		    mvsoc_print, mvsoc_search);
+	}
+}
+
+static int
+mvsoc_print(void *aux, const char *pnp)
+{
+	struct marvell_attach_args *mva = aux;
+
+	if (pnp)
+		aprint_normal("%s at %s unit %d",
+		    mva->mva_name, pnp, mva->mva_unit);
+	else {
+		if (mva->mva_unit != MVA_UNIT_DEFAULT)
+			aprint_normal(" unit %d", mva->mva_unit);
+		if (mva->mva_offset != MVA_OFFSET_DEFAULT) {
+			aprint_normal(" offset 0x%04lx", mva->mva_offset);
+			if (mva->mva_size > 0)
+				aprint_normal("-0x%04lx",
+				    mva->mva_offset + mva->mva_size - 1);
+		}
+		if (mva->mva_irq != MVA_IRQ_DEFAULT)
+			aprint_normal(" irq %d", mva->mva_irq);
+	}
+
+	return UNCONF;
+}
+
+/* ARGSUSED */
+static int
+mvsoc_search(device_t parent, cfdata_t cf, const int *ldesc, void *aux)
+{
+
+	return config_match(parent, cf, aux);
+}
+
+/* ARGSUSED */
+int
+marvell_winparams_by_tag(device_t dev, int tag, int *target, int *attribute,
+			 uint64_t *base, uint32_t *size)
+{
+	uint32_t base32;
+	int rv;
+
+	rv = mvsoc_target(tag, target, attribute, &base32, size);
+	*base = base32;
+	if (rv == -1)
+		return -1;
+	return 0;
+}
+
+
+/*
+ * These functions is called before bus_space is initialized.
+ */
+
+void
+mvsoc_bootstrap(bus_addr_t iobase)
+{
+
+	regbase = iobase;
+	dsc_base = iobase + MVSOC_DSC_BASE;
+	mlmb_base = iobase + MVSOC_MLMB_BASE;
+	pex_base = iobase + MVSOC_PEX_BASE;
+}
+
+/*
+ * We can read register of PCI configurations from (MVSOC_PEX_BASE + 0).
+ */
+uint16_t
+mvsoc_model()
+{
+	/*
+	 * We read product-id from vendor/device register of PCI-Express.
+	 */
+	uint32_t reg;
+	uint16_t model;
+
+	KASSERT(regbase != 0xffffffff);
+
+	reg = *(volatile uint32_t *)(pex_base + PCI_ID_REG);
+	model = PCI_PRODUCT(reg);
+
+#if defined(ORION)
+	if (model == PCI_PRODUCT_MARVELL_88F5182) {
+		reg = *(volatile uint32_t *)(regbase + ORION_PMI_BASE +
+		    ORION_PMI_SAMPLE_AT_RESET);
+		if ((reg & ORION_PMISMPL_TCLK_MASK) == 0)
+			model = PCI_PRODUCT_MARVELL_88F5082;
+	}
+#endif
+
+	return model;
+}
+
+uint8_t
+mvsoc_rev()
+{
+	uint32_t reg;
+	uint8_t rev;
+
+	KASSERT(regbase != 0xffffffff);
+
+	reg = *(volatile uint32_t *)(pex_base + PCI_CLASS_REG);
+	rev = PCI_REVISION(reg);
+
+	return rev;
+}
+
+
+int
+mvsoc_target(int tag, uint32_t *target, uint32_t *attr, uint32_t *base,
+	     uint32_t *size)
+{
+	int i;
+
+	KASSERT(regbase != 0xffffffff);
+
+	if (tag == MVSOC_TAG_INTERNALREG) {
+		if (target != NULL)
+			*target = 0;
+		if (attr != NULL)
+			*attr = 0;
+		if (base != NULL)
+			*base = read_mlmbreg(MVSOC_MLMB_IRBAR) &
+			    MVSOC_MLMB_IRBAR_BASE_MASK;
+		if (size != NULL)
+			*size = 0;
+
+		return 0;
+	}
+
+	/* sanity check */
+	for (i = 0; i < __arraycount(mvsoc_tags); i++)
+		if (mvsoc_tags[i].tag == tag)
+			break;
+	if (i >= __arraycount(mvsoc_tags))
+		return -1;
+
+	if (target != NULL)
+		*target = mvsoc_tags[i].target;
+	if (attr != NULL)
+		*attr = mvsoc_tags[i].attr;
+
+	if (mvsoc_tags[i].target == MVSOC_UNITID_DDR) {
+		/*
+		 * Read DDR SDRAM Controller Address Decode Registers
+		 */
+		uint32_t baseaddrreg, sizereg;
+		int cs = 0;
+
+		switch (mvsoc_tags[i].attr) {
+		case MARVELL_ATTR_SDRAM_CS0:
+			cs = 0;
+			break;
+		case MARVELL_ATTR_SDRAM_CS1:
+			cs = 1;
+			break;
+		case MARVELL_ATTR_SDRAM_CS2:
+			cs = 2;
+			break;
+		case MARVELL_ATTR_SDRAM_CS3:
+			cs = 3;
+			break;
+		}
+		sizereg = *(volatile uint32_t *)(dsc_base + MVSOC_DSC_CSSR(cs));
+		if (sizereg & MVSOC_DSC_CSSR_WINEN) {
+			baseaddrreg = *(volatile uint32_t *)(dsc_base +
+			    MVSOC_DSC_CSBAR(cs));
+
+			if (base != NULL)
+				*base = baseaddrreg & MVSOC_DSC_CSBAR_BASE_MASK;
+			if (size != NULL)
+				*size = (sizereg & MVSOC_DSC_CSSR_SIZE_MASK) +
+				    (~MVSOC_DSC_CSSR_SIZE_MASK + 1);
+		} else {
+			if (base != NULL)
+				*base = 0;
+			if (size != NULL)
+				*size = 0;
+		}
+		return 0;
+	} else {
+		/*
+		 * Read CPU Address Map Registers
+		 */
+		uint32_t basereg, ctrlreg, ta, tamask;
+
+		ta = MVSOC_MLMB_WCR_TARGET(mvsoc_tags[i].target) |
+		    MVSOC_MLMB_WCR_ATTR(mvsoc_tags[i].attr);
+		tamask = MVSOC_MLMB_WCR_TARGET(MVSOC_UNITID_MASK) |
+		    MVSOC_MLMB_WCR_ATTR(MARVELL_ATTR_MASK);
+
+		if (base != NULL)
+			*base = 0;
+		if (size != NULL)
+			*size = 0;
+
+		for (i = 0; i < nwindow; i++) {
+			ctrlreg = read_mlmbreg(MVSOC_MLMB_WCR(i));
+			if ((ctrlreg & tamask) != ta)
+				continue;
+			if (ctrlreg & MVSOC_MLMB_WCR_WINEN) {
+				basereg = read_mlmbreg(MVSOC_MLMB_WBR(i));
+
+				if (base != NULL)
+					*base =
+					    basereg & MVSOC_MLMB_WBR_BASE_MASK;
+				if (size != NULL)
+					*size = (ctrlreg &
+					    MVSOC_MLMB_WCR_SIZE_MASK) +
+					    (~MVSOC_MLMB_WCR_SIZE_MASK + 1);
+			}
+			break;
+		}
+		return i;
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/arch/arm/marvell/mvsoc_dma.c	Fri Oct 22 09:23:11 2010 +0000
@@ -0,0 +1,74 @@
+/*	$NetBSD: mvsoc_dma.c,v 1.1.4.2 2010/10/22 09:23:11 uebayasi Exp $ */
+
+/*
+ * Copyright (c) 2004 Jesse Off
+ * 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.
+ * 3. Neither the name of The Fujitsu Component Limited nor the name of
+ *    Genetec corporation may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY FUJITSU COMPONENT LIMITED AND GENETEC
+ * CORPORATION ``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 FUJITSU COMPONENT LIMITED OR GENETEC
+ * CORPORATION 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.
+ */
+
+/*
+ * bus_dma tag for MV88Fxx81 Orion
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: mvsoc_dma.c,v 1.1.4.2 2010/10/22 09:23:11 uebayasi Exp $");
+
+#define _ARM32_BUS_DMA_PRIVATE
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/device.h>
+#include <sys/systm.h>
+#include <sys/extent.h>
+
+#include <machine/bus.h>
+
+#include <arm/marvell/mvsocvar.h>
+
+struct arm32_bus_dma_tag mvsoc_bus_dma_tag = {
+	NULL,			/* _ranges: set by platform specific routine */
+	0,			/* _nranges */
+
+	NULL,			/* _cookie */
+
+	_bus_dmamap_create,
+	_bus_dmamap_destroy,
+	_bus_dmamap_load,
+	_bus_dmamap_load_mbuf,
+	_bus_dmamap_load_uio,
+	_bus_dmamap_load_raw,
+	_bus_dmamap_unload,
+	_bus_dmamap_sync,
+	NULL,			/* sync_post */
+
+	_bus_dmamem_alloc,
+	_bus_dmamem_free,
+	_bus_dmamem_map,
+	_bus_dmamem_unmap,
+	_bus_dmamem_mmap,
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/arch/arm/marvell/mvsoc_intr.c	Fri Oct 22 09:23:11 2010 +0000
@@ -0,0 +1,153 @@
+/*	$NetBSD: mvsoc_intr.c,v 1.1.4.2 2010/10/22 09:23:11 uebayasi Exp $	*/
+/*
+ * Copyright (c) 2010 KIYOHARA Takashi
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: mvsoc_intr.c,v 1.1.4.2 2010/10/22 09:23:11 uebayasi Exp $");
+
+#define _INTR_PRIVATE
+
+#include <sys/param.h>
+#include <sys/proc.h>
+
+#include <uvm/uvm_extern.h>
+
+#include <machine/intr.h>
+
+#include <arm/cpu.h>
+#include <arm/pic/picvar.h>
+#include <arm/marvell/mvsocreg.h>
+#include <arm/marvell/mvsocvar.h>
+
+
+static void mvsoc_bridge_pic_unblock_irqs(struct pic_softc *, size_t, uint32_t);
+static void mvsoc_bridge_pic_block_irqs(struct pic_softc *, size_t, uint32_t);
+static int mvsoc_bridge_pic_find_pending_irqs(struct pic_softc *);
+static void mvsoc_bridge_pic_establish_irq(struct pic_softc *,
+					   struct intrsource *);
+static void mvsoc_bridge_pic_source_name(struct pic_softc *, int, char *,
+					 size_t);
+
+static const char * const sources[] = {
+    "CPUSelfInt",      "CPUTimer0IntReq", "CPUTimer1IntReq", "CPUWDTimerIntReq",
+    "AccessErr",       "Bit64Err",
+};
+
+static struct pic_ops mvsoc_bridge_picops = {
+	.pic_unblock_irqs = mvsoc_bridge_pic_unblock_irqs,
+	.pic_block_irqs = mvsoc_bridge_pic_block_irqs,
+	.pic_find_pending_irqs = mvsoc_bridge_pic_find_pending_irqs,
+	.pic_establish_irq = mvsoc_bridge_pic_establish_irq,
+	.pic_source_name = mvsoc_bridge_pic_source_name,
+};
+
+struct pic_softc mvsoc_bridge_pic = {
+	.pic_ops = &mvsoc_bridge_picops,
+	.pic_maxsources = MVSOC_MLMB_MLMBI_NIRQ,
+	.pic_name = "mvsoc_bridge",
+};
+
+
+void
+mvsoc_irq_handler(void *frame)
+{
+	struct cpu_info * const ci = curcpu();
+	const int oldipl = ci->ci_cpl;
+	const uint32_t oldipl_mask = __BIT(oldipl);
+	int ipl_mask = 0;
+
+	uvmexp.intrs++;
+
+	ipl_mask = find_pending_irqs();
+
+	/*
+	 * Record the pending_ipls and deliver them if we can.
+	 */
+	if ((ipl_mask & ~oldipl_mask) > oldipl_mask)
+		pic_do_pending_ints(I32_bit, oldipl, frame);
+}
+
+/*
+ * Mbus-L to Mbus bridge
+ */
+
+void *
+mvsoc_bridge_intr_establish(int ih, int ipl, int (*ih_func)(void *), void *arg)
+{
+
+	return intr_establish(mvsoc_bridge_pic.pic_irqbase + ih, ipl, 0,
+	    ih_func, arg);
+}
+
+/* ARGSUSED */
+static void
+mvsoc_bridge_pic_unblock_irqs(struct pic_softc *pic, size_t irqbase,
+			      uint32_t irq_mask)
+{
+
+	write_mlmbreg(MVSOC_MLMB_MLMBICR,
+	    read_mlmbreg(MVSOC_MLMB_MLMBICR) & ~irq_mask);
+	write_mlmbreg(MVSOC_MLMB_MLMBIMR,
+	    read_mlmbreg(MVSOC_MLMB_MLMBIMR) | irq_mask);
+}
+
+/* ARGSUSED */
+static void
+mvsoc_bridge_pic_block_irqs(struct pic_softc *pic, size_t irqbase,
+			    uint32_t irq_mask)
+{
+
+	write_mlmbreg(MVSOC_MLMB_MLMBIMR,
+	    read_mlmbreg(MVSOC_MLMB_MLMBIMR) & ~irq_mask);
+}
+
+static int
+mvsoc_bridge_pic_find_pending_irqs(struct pic_softc *pic)
+{
+	uint32_t pending;
+
+	pending =
+	    read_mlmbreg(MVSOC_MLMB_MLMBICR) & read_mlmbreg(MVSOC_MLMB_MLMBIMR);
+	if (pending == 0)
+		return 0;
+	pic_mark_pending_sources(pic, 0, pending);
+	return 1;
+}
+
+/* ARGSUSED */
+static void
+mvsoc_bridge_pic_establish_irq(struct pic_softc *pic, struct intrsource *is)
+{
+	/* Nothing */
+}
+
+static void
+mvsoc_bridge_pic_source_name(struct pic_softc *pic, int irq, char *buf,
+			     size_t len)
+{
+
+	strlcpy(buf, sources[irq], len);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/arch/arm/marvell/mvsoc_intr.h	Fri Oct 22 09:23:11 2010 +0000
@@ -0,0 +1,49 @@
+/*	$NetBSD: mvsoc_intr.h,v 1.1.4.2 2010/10/22 09:23:11 uebayasi Exp $	*/
+/*
+ * Copyright (c) 2010 KIYOHARA Takashi
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _MVSOC_INTR_H_
+#define _MVSOC_INTR_H_
+
+#define ARM_IRQ_HANDLER	_C_LABEL(mvsoc_irq_handler)
+
+#ifndef _LOCORE
+int (*find_pending_irqs)(void);
+
+void mvsoc_irq_handler(void *);
+
+#include <arm/pic/picvar.h>
+
+static __inline void *
+marvell_intr_establish(int irq, int ipl, int (*func)(void *), void *arg)
+{
+
+	return intr_establish(irq, ipl, IST_LEVEL_HIGH, func, arg);
+}
+
+#endif	/* _LOCORE */
+
+#endif	/* _MVSOC_INTR_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/arch/arm/marvell/mvsoc_space.c	Fri Oct 22 09:23:11 2010 +0000
@@ -0,0 +1,320 @@
+/*	$NetBSD: mvsoc_space.c,v 1.1.4.2 2010/10/22 09:23:12 uebayasi Exp $	*/
+/*
+ * Copyright (c) 2007 KIYOHARA Takashi
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: mvsoc_space.c,v 1.1.4.2 2010/10/22 09:23:12 uebayasi Exp $");
+
+#include "opt_mvsoc.h"
+#include "mvpex.h"
+#include "gtpci.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+
+#include <uvm/uvm_extern.h>
+
+#include <machine/bus.h>
+
+#include <arm/marvell/mvsocreg.h>
+#include <arm/marvell/mvsocvar.h>
+
+
+/* Proto types for all the bus_space structure functions */
+bs_protos(mvsoc);
+bs_protos(generic);
+bs_protos(generic_armv4);
+bs_protos(bs_notimpl);
+
+#define MVSOC_BUS_SPACE_DEFAULT_FUNCS		\
+	/* mapping/unmapping */			\
+	mvsoc_bs_map,				\
+	mvsoc_bs_unmap,				\
+	mvsoc_bs_subregion,			\
+						\
+	/* allocation/deallocation */		\
+	mvsoc_bs_alloc,				\
+	mvsoc_bs_free,				\
+						\
+	/* get kernel virtual address */	\
+	mvsoc_bs_vaddr,				\
+						\
+	/* mmap bus space for userland */	\
+	bs_notimpl_bs_mmap,			\
+						\
+	/* barrier */				\
+	mvsoc_bs_barrier,			\
+						\
+	/* read (single) */			\
+	generic_bs_r_1,				\
+	generic_armv4_bs_r_2,			\
+	generic_bs_r_4,				\
+	bs_notimpl_bs_r_8,			\
+						\
+	/* read multiple */			\
+	generic_bs_rm_1,			\
+	generic_armv4_bs_rm_2,			\
+	generic_bs_rm_4,			\
+	bs_notimpl_bs_rm_8,			\
+						\
+	/* read region */			\
+	generic_bs_rr_1,			\
+	generic_armv4_bs_rr_2,			\
+	generic_bs_rr_4,			\
+	bs_notimpl_bs_rr_8,			\
+						\
+	/* write (single) */			\
+	generic_bs_w_1,				\
+	generic_armv4_bs_w_2,			\
+	generic_bs_w_4,				\
+	bs_notimpl_bs_w_8,			\
+						\
+	/* write multiple */			\
+	generic_bs_wm_1,			\
+	generic_armv4_bs_wm_2,			\
+	generic_bs_wm_4,			\
+	bs_notimpl_bs_wm_8,			\
+						\
+	/* write region */			\
+	generic_bs_wr_1,			\
+	generic_armv4_bs_wr_2,			\
+	generic_bs_wr_4,			\
+	bs_notimpl_bs_wr_8,			\
+						\
+	/* set multiple */			\
+	bs_notimpl_bs_sm_1,			\
+	bs_notimpl_bs_sm_2,			\
+	bs_notimpl_bs_sm_4,			\
+	bs_notimpl_bs_sm_8,			\
+						\
+	/* set region */			\
+	bs_notimpl_bs_sr_1,			\
+	generic_armv4_bs_sr_2,			\
+	generic_bs_sr_4,			\
+	bs_notimpl_bs_sr_8,			\
+						\
+	/* copy */				\
+	bs_notimpl_bs_c_1,			\
+	generic_armv4_bs_c_2,			\
+	bs_notimpl_bs_c_4,			\
+	bs_notimpl_bs_c_8,
+
+
+struct bus_space mvsoc_bs_tag = {
+	/* cookie */
+	(void *)0,
+
+	MVSOC_BUS_SPACE_DEFAULT_FUNCS
+};
+
+#if NMVPEX > 0
+#if defined(ORION)
+struct bus_space orion_pex0_mem_bs_tag = {
+	/* cookie */
+	(void *)ORION_TAG_PEX0_MEM,
+
+	MVSOC_BUS_SPACE_DEFAULT_FUNCS
+};
+struct bus_space orion_pex0_io_bs_tag = {
+	/* cookie */
+	(void *)ORION_TAG_PEX0_IO,
+
+	MVSOC_BUS_SPACE_DEFAULT_FUNCS
+};
+struct bus_space orion_pex1_mem_bs_tag = {
+	/* cookie */
+	(void *)ORION_TAG_PEX1_MEM,
+
+	MVSOC_BUS_SPACE_DEFAULT_FUNCS
+};
+struct bus_space orion_pex1_io_bs_tag = {
+	/* cookie */
+	(void *)ORION_TAG_PEX1_IO,
+
+	MVSOC_BUS_SPACE_DEFAULT_FUNCS
+};
+#endif
+
+#if defined(KIRKWOOD)
+struct bus_space kirkwood_pex_mem_bs_tag = {
+	/* cookie */
+	(void *)KIRKWOOD_TAG_PEX_MEM,
+
+	MVSOC_BUS_SPACE_DEFAULT_FUNCS
+};
+struct bus_space kirkwood_pex_io_bs_tag = {
+	/* cookie */
+	(void *)KIRKWOOD_TAG_PEX_IO,
+
+	MVSOC_BUS_SPACE_DEFAULT_FUNCS
+};
+#endif
+#endif
+
+#if NGTPCI > 0
+#if defined(ORION)
+struct bus_space orion_pci_mem_bs_tag = {
+	/* cookie */
+	(void *)ORION_TAG_PCI_MEM,
+
+	MVSOC_BUS_SPACE_DEFAULT_FUNCS
+};
+struct bus_space orion_pci_io_bs_tag = {
+	/* cookie */
+	(void *)ORION_TAG_PCI_IO,
+
+	MVSOC_BUS_SPACE_DEFAULT_FUNCS
+};
+#endif
+#endif
+
+
+int
+mvsoc_bs_map(void *space, bus_addr_t address, bus_size_t size, int flags,
+	     bus_space_handle_t *handlep)
+{
+	const struct pmap_devmap *pd;
+	paddr_t startpa, endpa, offset, pa;
+	pt_entry_t *pte;
+	vaddr_t va;
+	int tag = (int)space;
+
+	if (tag != 0) {
+		bus_addr_t remap;
+		uint32_t base;
+		int window;
+
+		window = mvsoc_target(tag, NULL, NULL, &base, NULL);
+		if (window == -1)
+			return ENOMEM;
+		if (window < nremap) {
+			remap = read_mlmbreg(MVSOC_MLMB_WRLR(window)) &
+			    MVSOC_MLMB_WRLR_REMAP_MASK;
+			remap |=
+			    (read_mlmbreg(MVSOC_MLMB_WRHR(window)) << 16) << 16;
+			address = address - remap + base;
+		}
+	}
+
+	if ((pd = pmap_devmap_find_pa(address, size)) != NULL) {
+		/* Device was statically mapped. */
+		*handlep = pd->pd_va + (address - pd->pd_pa);
+		return 0;
+	}
+
+	startpa = trunc_page(address);
+	endpa = round_page(address + size);
+	offset = address & PAGE_MASK;
+
+	/* XXX use extent manager to check duplicate mapping */
+
+	va = uvm_km_alloc(kernel_map, endpa - startpa, 0,
+	    UVM_KMF_VAONLY | UVM_KMF_NOWAIT);
+	if (va == 0x00000000)
+		return ENOMEM;
+
+	*handlep = va + offset;
+
+	/* Now map the pages */
+	for (pa = startpa; pa < endpa; pa += PAGE_SIZE, va += PAGE_SIZE) {
+		pmap_kenter_pa(va, pa, VM_PROT_READ | VM_PROT_WRITE, 0);
+		if ((flags & BUS_SPACE_MAP_CACHEABLE) == 0) {
+			pte = vtopte(va);
+			*pte &= ~L2_S_CACHE_MASK;
+			PTE_SYNC(pte);
+			/*
+			 * XXX: pmap_kenter_pa() also does PTE_SYNC(). a bit of
+			 *      waste.
+			 */
+		}
+	}
+	pmap_update(pmap_kernel());
+
+	return 0;
+}
+
+void
+mvsoc_bs_unmap(void *space, bus_space_handle_t handle, bus_size_t size)
+{
+	vaddr_t va, sz;
+
+	if (pmap_devmap_find_va(handle, size) != NULL)
+		/* Device was statically mapped; nothing to do. */
+		return;
+
+	va = trunc_page(handle);
+        sz = round_page(handle + size) - va;
+
+	pmap_kremove(va, sz);
+	pmap_update(pmap_kernel());
+	uvm_km_free(kernel_map, va, sz, UVM_KMF_VAONLY);
+}
+
+/* ARGSUSED */
+int
+mvsoc_bs_subregion(void *space, bus_space_handle_t handle,
+		       bus_size_t offset, bus_size_t size,
+		       bus_space_handle_t *nhandlep)
+{
+
+	*nhandlep = handle + offset;
+	return 0;
+}
+
+/* ARGSUSED */
+int
+mvsoc_bs_alloc(void *space, bus_addr_t reg_start, bus_addr_t reg_end,
+	       bus_size_t size, bus_size_t alignment, bus_size_t boundary,
+	       int flags, bus_addr_t *addrp, bus_space_handle_t *handlep)
+{
+
+	panic("%s(): not implemented\n", __func__);
+}
+
+/* ARGSUSED */
+void
+mvsoc_bs_free(void *space, bus_space_handle_t handle, bus_size_t size)
+{
+
+	panic("%s(): not implemented\n", __func__);
+}
+
+/* ARGSUSED */
+void
+mvsoc_bs_barrier(void *space, bus_space_handle_t handle, bus_size_t offset,
+		 bus_size_t length, int flags)
+{
+
+	/* Nothing to do. */
+}
+
+/* ARGSUSED */
+void *
+mvsoc_bs_vaddr(void *space, bus_space_handle_t handle)
+{
+
+	return (void *)handle;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/arch/arm/marvell/mvsocgpp.c	Fri Oct 22 09:23:11 2010 +0000
@@ -0,0 +1,455 @@
+/*	$NetBSD: mvsocgpp.c,v 1.1.4.2 2010/10/22 09:23:12 uebayasi Exp $	*/
+/*
+ * Copyright (c) 2008, 2010 KIYOHARA Takashi
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: mvsocgpp.c,v 1.1.4.2 2010/10/22 09:23:12 uebayasi Exp $");
+
+#include "gpio.h"
+
+#define _INTR_PRIVATE
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/device.h>
+#include <sys/errno.h>
+#include <sys/evcnt.h>
+#include <sys/gpio.h>
+#include <sys/kmem.h>
+
+#include <machine/intr.h>
+
+#include <arm/marvell/mvsocreg.h>
+#include <arm/marvell/mvsocvar.h>
+#include <arm/marvell/mvsocgppreg.h>
+#include <arm/marvell/mvsocgppvar.h>
+#include <arm/pic/picvar.h>
+
+#include <dev/marvell/marvellvar.h>
+
+#if NGPIO > 0
+#include <sys/gpio.h>
+#include <dev/gpio/gpiovar.h>
+#endif
+
+#define MVSOCGPP_DUMPREG
+
+#define MVSOCGPP_READ(sc, reg) \
+	bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg))
+#define MVSOCGPP_WRITE(sc, reg, val) \
+	bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
+
+struct mvsocgpp_softc {
+	device_t sc_dev;
+
+	bus_space_tag_t sc_iot;
+	bus_space_handle_t sc_ioh;
+
+	struct mvsocgpp_pic {
+		struct pic_softc gpio_pic;
+		int group;
+		uint32_t edge;
+		uint32_t level;
+	} *sc_pic;
+
+#if NGPIO > 0
+	struct gpio_chipset_tag sc_gpio_chipset;
+	gpio_pin_t *sc_pins;
+#endif
+};
+
+static int mvsocgpp_match(device_t, struct cfdata *, void *);
+static void mvsocgpp_attach(device_t, device_t, void *);
+
+#ifdef MVSOCGPP_DUMPREG
+static void mvsocgpp_dump_reg(struct mvsocgpp_softc *);
+#endif
+
+static void gpio_pic_unblock_irqs(struct pic_softc *, size_t, uint32_t);
+static void gpio_pic_block_irqs(struct pic_softc *, size_t, uint32_t);
+static int gpio_pic_find_pending_irqs(struct pic_softc *);
+static void gpio_pic_establish_irq(struct pic_softc *, struct intrsource *);
+
+static struct pic_ops gpio_pic_ops = {
+	.pic_unblock_irqs = gpio_pic_unblock_irqs,
+	.pic_block_irqs = gpio_pic_block_irqs,
+	.pic_find_pending_irqs = gpio_pic_find_pending_irqs,
+	.pic_establish_irq = gpio_pic_establish_irq,
+};
+
+static struct mvsocgpp_softc *mvsocgpp_softc;	/* One unit per One SoC */
+int gpp_irqbase = 0;
+int gpp_npins = 0;
+
+
+CFATTACH_DECL_NEW(mvsocgpp, sizeof(struct mvsocgpp_softc),
+    mvsocgpp_match, mvsocgpp_attach, NULL, NULL);
+
+
+/* ARGSUSED */
+static int
+mvsocgpp_match(device_t parent, struct cfdata *match, void *aux)
+{
+	struct marvell_attach_args *mva = aux;
+
+	if (strcmp(mva->mva_name, match->cf_name) != 0)
+		return 0;
+	if (mva->mva_offset == MVA_OFFSET_DEFAULT ||
+	    mva->mva_irq == MVA_IRQ_DEFAULT)
+		return 0;
+
+	mva->mva_size = MVSOC_GPP_SIZE;
+	return 1;
+}
+
+/* ARGSUSED */
+static void
+mvsocgpp_attach(device_t parent, device_t self, void *aux)
+{
+	struct mvsocgpp_softc *sc = device_private(self);
+	struct marvell_attach_args *mva = aux;
+	struct pic_softc *gpio_pic;
+#if NGPIO > 0
+	struct gpiobus_attach_args gba;
+	gpio_pin_t *pins;
+	uint32_t dir, valin, valout, polarity, mask;
+#endif
+	int i, j;
+	void *ih;
+
+	aprint_normal(": Marvell SoC General Purpose I/O Port Interface\n");
+	aprint_naive("\n");
+
+	sc->sc_dev = self;
+	sc->sc_iot = mva->mva_iot;
+	/* Map I/O registers for oriongpp */
+	if (bus_space_subregion(mva->mva_iot, mva->mva_ioh,
+				mva->mva_offset, mva->mva_size, &sc->sc_ioh)) {
+		aprint_error_dev(self, "can't map registers\n");
+		return;
+	}
+
+	if (gpp_npins > 0)
+		aprint_normal_dev(self, "%d gpio pins\n", gpp_npins);
+	else {
+		aprint_error_dev(self, "gpp_npins not initialized\n");
+		return;
+	}
+
+	mvsocgpp_softc = sc;
+
+	for (i = 0; i < gpp_npins; i += 32)
+		MVSOCGPP_WRITE(sc, MVSOCGPP_GPIOIC(i), 0);
+
+	sc->sc_pic =
+	    kmem_zalloc(sizeof(struct mvsocgpp_pic) * gpp_npins / 8, KM_SLEEP);
+	for (i = 0, j = 0; i < gpp_npins; i += 8, j++) {
+		gpio_pic = &(sc->sc_pic + j)->gpio_pic;
+		gpio_pic->pic_ops = &gpio_pic_ops;
+		snprintf(gpio_pic->pic_name, sizeof(gpio_pic->pic_name),
+		    "%s[%d:%d]", device_xname(self), i + 7, i);
+		gpio_pic->pic_maxsources =
+		    (gpp_npins - i) > 8 ? 8 : gpp_npins - i;
+		pic_add(gpio_pic, gpp_irqbase + i);
+		aprint_normal_dev(self, "interrupts %d..%d",
+		    gpp_irqbase + i, gpp_irqbase + i + 7);
+		ih = intr_establish(mva->mva_irq + j,
+		    IPL_HIGH, IST_LEVEL_HIGH, pic_handle_intr, gpio_pic);
+		aprint_normal(", intr %d\n", mva->mva_irq + j);
+
+		(sc->sc_pic + j)->group = j;
+	}
+
+#ifdef MVSOCGPP_DUMPREG
+	mvsocgpp_dump_reg(sc);
+#endif
+
+#if NGPIO > 0
+	sc->sc_pins = kmem_alloc(sizeof(gpio_pin_t) * gpp_npins, KM_SLEEP);
+
+	for (i = 0; i < gpp_npins; i += 32) {
+		dir = MVSOCGPP_READ(sc, MVSOCGPP_GPIODOEC(i));
+		valin = MVSOCGPP_READ(sc, MVSOCGPP_GPIODI(i));
+		valout = MVSOCGPP_READ(sc, MVSOCGPP_GPIODO(i));
+		polarity = MVSOCGPP_READ(sc, MVSOCGPP_GPIODIP(i));
+	}
+	for (i = 0, mask = 1; i < gpp_npins; i++, mask <<= 1) {
+		pins = &sc->sc_pins[i];
+		pins->pin_num = i;
+		pins->pin_caps =
+		    (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | GPIO_PIN_INVIN);
+		if(dir & mask) {
+			pins->pin_flags = GPIO_PIN_INPUT;
+			pins->pin_state =
+			    (valin & mask) ? GPIO_PIN_HIGH : GPIO_PIN_LOW;
+		} else {
+			pins->pin_flags = GPIO_PIN_OUTPUT;
+			pins->pin_state =
+			    (valout & mask) ? GPIO_PIN_HIGH : GPIO_PIN_LOW;
+		}
+	}
+	sc->sc_gpio_chipset.gp_cookie = sc;
+	sc->sc_gpio_chipset.gp_pin_read = mvsocgpp_pin_read;
+	sc->sc_gpio_chipset.gp_pin_write = mvsocgpp_pin_write;
+	sc->sc_gpio_chipset.gp_pin_ctl = mvsocgpp_pin_ctl;
+	gba.gba_gc = &sc->sc_gpio_chipset;
+	gba.gba_pins = sc->sc_pins;
+	gba.gba_npins = gpp_npins;
+	config_found_ia(self, "gpiobus", &gba, gpiobus_print);
+#endif
+}
+
+/*
+ * arch/arm/pic functions.
+ */
+
+static void
+gpio_pic_unblock_irqs(struct pic_softc *pic, size_t irqbase, uint32_t irq_mask)
+{
+	struct mvsocgpp_softc *sc = mvsocgpp_softc;
+	struct mvsocgpp_pic *mvsocgpp_pic = (struct mvsocgpp_pic *)pic;
+	uint32_t mask;
+	int pin = mvsocgpp_pic->group << 3;
+
+	MVSOCGPP_WRITE(sc, MVSOCGPP_GPIOIC(pin),
+	    MVSOCGPP_READ(sc, MVSOCGPP_GPIOIC(pin)) & ~irq_mask);
+	if (irq_mask & mvsocgpp_pic->edge) {
+		mask = MVSOCGPP_READ(sc, MVSOCGPP_GPIOIM(pin));
+		mask |= (irq_mask & mvsocgpp_pic->edge);
+		MVSOCGPP_WRITE(sc, MVSOCGPP_GPIOIM(pin), mask);
+	}
+	if (irq_mask & mvsocgpp_pic->level) {
+		mask = MVSOCGPP_READ(sc, MVSOCGPP_GPIOILM(pin));
+		mask |= (irq_mask & mvsocgpp_pic->level);
+		MVSOCGPP_WRITE(sc, MVSOCGPP_GPIOILM(pin), mask);
+	}
+}
+
+/* ARGSUSED */
+static void
+gpio_pic_block_irqs(struct pic_softc *pic, size_t irqbase, uint32_t irq_mask)
+{
+	struct mvsocgpp_softc *sc = mvsocgpp_softc;
+	struct mvsocgpp_pic *mvsocgpp_pic = (struct mvsocgpp_pic *)pic;
+	int pin = mvsocgpp_pic->group << 3;
+
+	MVSOCGPP_WRITE(sc, MVSOCGPP_GPIOIM(pin),
+	    MVSOCGPP_READ(sc, MVSOCGPP_GPIOIM(pin)) & ~irq_mask);
+	MVSOCGPP_WRITE(sc, MVSOCGPP_GPIOILM(pin),
+	    MVSOCGPP_READ(sc, MVSOCGPP_GPIOILM(pin)) & ~irq_mask);
+}
+
+static int
+gpio_pic_find_pending_irqs(struct pic_softc *pic)
+{
+	struct mvsocgpp_softc *sc = mvsocgpp_softc;
+	struct mvsocgpp_pic *mvsocgpp_pic = (struct mvsocgpp_pic *)pic;
+	uint32_t pending;
+	int pin = mvsocgpp_pic->group << 3;
+
+	pending = MVSOCGPP_READ(sc, MVSOCGPP_GPIOIC(pin));
+	pending &= (0xff << mvsocgpp_pic->group);
+	pending &= (MVSOCGPP_READ(sc, MVSOCGPP_GPIOIM(pin)) |
+		    MVSOCGPP_READ(sc, MVSOCGPP_GPIOILM(pin)));
+	if (pending == 0)
+		return 0;
+	pic_mark_pending_sources(pic, 0, pending);
+	return 1;
+}
+
+static void
+gpio_pic_establish_irq(struct pic_softc *pic, struct intrsource *is)
+{
+	struct mvsocgpp_softc *sc = mvsocgpp_softc;
+	struct mvsocgpp_pic *mvsocgpp_pic = (struct mvsocgpp_pic *)pic;
+	uint32_t im, ilm, mask;
+	int type, pin;
+
+	type = is->is_type;
+	pin = pic->pic_irqbase + is->is_irq - gpp_irqbase;
+	mask = MVSOCGPP_GPIOPIN(pin);
+
+	switch (type) {
+	case IST_LEVEL_LOW:
+	case IST_EDGE_FALLING:
+		mvsocgpp_pin_ctl(NULL, pin, GPIO_PIN_INPUT | GPIO_PIN_INVIN);
+		break;
+
+	case IST_LEVEL_HIGH:
+	case IST_EDGE_RISING:
+		mvsocgpp_pin_ctl(NULL, pin, GPIO_PIN_INPUT);
+		break;
+
+	default:
+		panic("unknwon interrupt type %d for pin %d.\n", type, pin);
+	}
+
+	im = MVSOCGPP_READ(sc, MVSOCGPP_GPIOIM(pin));
+	ilm = MVSOCGPP_READ(sc, MVSOCGPP_GPIOILM(pin));
+	switch (type) {
+	case IST_EDGE_FALLING:
+	case IST_EDGE_RISING:
+		im |= mask;
+		ilm &= ~mask;
+		mvsocgpp_pic->edge |= mask;
+		mvsocgpp_pic->level &= ~mask;
+		break;
+
+	case IST_LEVEL_LOW:
+	case IST_LEVEL_HIGH:
+		im &= ~mask;
+		ilm |= mask;
+		mvsocgpp_pic->edge &= ~mask;
+		mvsocgpp_pic->level |= mask;
+		break;
+	}
+	MVSOCGPP_WRITE(sc, MVSOCGPP_GPIOIM(pin), im);
+	MVSOCGPP_WRITE(sc, MVSOCGPP_GPIOILM(pin), ilm);
+}
+
+
+/*
+ * gpio(4) functions, and can call you.
+ */
+
+/* ARGSUSED */
+int
+mvsocgpp_pin_read(void *arg, int pin)
+{
+	struct mvsocgpp_softc *sc = mvsocgpp_softc;
+	uint32_t val;
+
+	KASSERT(sc != NULL);
+
+	val = MVSOCGPP_READ(sc, MVSOCGPP_GPIODI(pin));
+	return (val & MVSOCGPP_GPIOPIN(pin)) != 0;
+}
+
+/* ARGSUSED */
+void
+mvsocgpp_pin_write(void *arg, int pin, int value)
+{
+	struct mvsocgpp_softc *sc = mvsocgpp_softc;
+	uint32_t old, new, mask = MVSOCGPP_GPIOPIN(pin);
+
+	KASSERT(sc != NULL);
+
+	old = MVSOCGPP_READ(sc, MVSOCGPP_GPIODO(pin));
+	if (value)
+		new = old | mask;
+	else
+		new = old & ~mask;
+	if (new != old)
+		MVSOCGPP_WRITE(sc, MVSOCGPP_GPIODO(pin), new);
+}
+
+/* ARGSUSED */
+void
+mvsocgpp_pin_ctl(void *arg, int pin, int flags)
+{
+	struct mvsocgpp_softc *sc = mvsocgpp_softc;
+	uint32_t old, new, mask = MVSOCGPP_GPIOPIN(pin);
+
+	KASSERT(sc != NULL);
+
+	old = MVSOCGPP_READ(sc, MVSOCGPP_GPIODOEC(pin));
+	switch (flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) {
+	case GPIO_PIN_INPUT:
+		new = old | mask;
+		break;
+
+	case GPIO_PIN_OUTPUT:
+		new = old & ~mask;
+		break;
+
+	default:
+		return;
+	}
+	if (new != old)
+		MVSOCGPP_WRITE(sc, MVSOCGPP_GPIODOEC(pin), new);
+
+	/* Blink every 2^24 TCLK */
+	old = MVSOCGPP_READ(sc, MVSOCGPP_GPIOBE(pin));
+	if (flags & GPIO_PIN_PULSATE)
+		new = old | mask;
+	else
+		new = old & ~mask;
+	if (new != old)
+		MVSOCGPP_WRITE(sc, MVSOCGPP_GPIOBE(pin), new);
+
+	old = MVSOCGPP_READ(sc, MVSOCGPP_GPIODIP(pin));
+	if (flags & GPIO_PIN_INVIN)
+		new = old | mask;
+	else
+		new = old & ~mask;
+	if (new != old)
+		MVSOCGPP_WRITE(sc, MVSOCGPP_GPIODIP(pin), new);
+}
+
+
+#ifdef MVSOCGPP_DUMPREG
+static void
+mvsocgpp_dump_reg(struct mvsocgpp_softc *sc)
+{
+
+	aprint_normal_dev(sc->sc_dev, "  Data Out:                 \t0x%08x\n",
+	    MVSOCGPP_READ(sc, MVSOCGPP_GPIODO(0)));
+	aprint_normal_dev(sc->sc_dev, "  Data Out Enable Control:  \t0x%08x\n",
+	    MVSOCGPP_READ(sc, MVSOCGPP_GPIODOEC(0)));
+	aprint_normal_dev(sc->sc_dev, "  Data Blink Enable:        \t0x%08x\n",
+	    MVSOCGPP_READ(sc, MVSOCGPP_GPIOBE(0)));
+	aprint_normal_dev(sc->sc_dev, "  Data In Polarity:         \t0x%08x\n",
+	    MVSOCGPP_READ(sc, MVSOCGPP_GPIODIP(0)));
+	aprint_normal_dev(sc->sc_dev, "  Data In:                  \t0x%08x\n",
+	    MVSOCGPP_READ(sc, MVSOCGPP_GPIODI(0)));
+	aprint_normal_dev(sc->sc_dev, "  Interrupt Cause:          \t0x%08x\n",
+	    MVSOCGPP_READ(sc, MVSOCGPP_GPIOIC(0)));
+	aprint_normal_dev(sc->sc_dev, "  Interrupt Mask:           \t0x%08x\n",
+	    MVSOCGPP_READ(sc, MVSOCGPP_GPIOIM(0)));
+	aprint_normal_dev(sc->sc_dev, "  Interrupt Level Mask:     \t0x%08x\n",
+	    MVSOCGPP_READ(sc, MVSOCGPP_GPIOILM(0)));
+
+	if (gpp_npins <= 32)
+		return;
+
+	aprint_normal_dev(sc->sc_dev, "  High Data Out:            \t0x%08x\n",
+	    MVSOCGPP_READ(sc, MVSOCGPP_GPIODO(32)));
+	aprint_normal_dev(sc->sc_dev, "  High Data Out Enable Ctrl:\t0x%08x\n",
+	    MVSOCGPP_READ(sc, MVSOCGPP_GPIODOEC(32)));
+	aprint_normal_dev(sc->sc_dev, "  High Blink Enable:        \t0x%08x\n",
+	    MVSOCGPP_READ(sc, MVSOCGPP_GPIOBE(32)));
+	aprint_normal_dev(sc->sc_dev, "  High Data In Polarity:    \t0x%08x\n",
+	    MVSOCGPP_READ(sc, MVSOCGPP_GPIODIP(32)));
+	aprint_normal_dev(sc->sc_dev, "  High Data In:             \t0x%08x\n",
+	    MVSOCGPP_READ(sc, MVSOCGPP_GPIODI(32)));
+	aprint_normal_dev(sc->sc_dev, "  High Interrupt Cause:     \t0x%08x\n",
+	    MVSOCGPP_READ(sc, MVSOCGPP_GPIOIC(32)));
+	aprint_normal_dev(sc->sc_dev, "  High Interrupt Mask:      \t0x%08x\n",
+	    MVSOCGPP_READ(sc, MVSOCGPP_GPIOIM(32)));
+	aprint_normal_dev(sc->sc_dev, "  High Interrupt Level Mask:\t0x%08x\n",
+	    MVSOCGPP_READ(sc, MVSOCGPP_GPIOILM(32)));
+}
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/arch/arm/marvell/mvsocgppreg.h	Fri Oct 22 09:23:11 2010 +0000
@@ -0,0 +1,67 @@
+/*	$NetBSD: mvsocgppreg.h,v 1.1.4.2 2010/10/22 09:23:12 uebayasi Exp $	*/
+/*
+ * Copyright (c) 2008 KIYOHARA Takashi
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _MVSOCGPPREG_H_
+#define _MVSOCGPPREG_H_
+
+#define MVSOC_GPP_SIZE		0x100
+
+/*
+ * General Purpose Port Registers
+ */
+/* GPIO Register Map */
+					/* GPIO Data Out */
+#define MVSOCGPP_GPIODO(p)	((((p) & 0x20) << 1) + 0x00)
+					/* GPIO Data Out Enable Control */
+#define MVSOCGPP_GPIODOEC(p)	((((p) & 0x20) << 1) + 0x04)
+					/* GPIO Blink Enable Control */
+#define MVSOCGPP_GPIOBE(p)	((((p) & 0x20) << 1) + 0x08)
+					/* GPIO Data In Polarity */
+#define MVSOCGPP_GPIODIP(p)	((((p) & 0x20) << 1) + 0x0c)
+					/* GPIO Data In */
+#define MVSOCGPP_GPIODI(p)	((((p) & 0x20) << 1) + 0x10)
+					/* GPIO Interrupt Cause */
+#define MVSOCGPP_GPIOIC(p)	((((p) & 0x20) << 1) + 0x14)
+					/* GPIO Interrupt Mask */
+#define MVSOCGPP_GPIOIM(p)	((((p) & 0x20) << 1) + 0x18)
+					/* GPIO Interrupt Level Mask */
+#define MVSOCGPP_GPIOILM(p)	((((p) & 0x20) << 1) + 0x1c)
+
+#define MVSOCGPP_GPIOPIN(pin)		(1 << ((pin) & 0x1f))
+
+/* Out Enable */
+#define MVSOCGPP_GPIODOE_OUT		0
+#define MVSOCGPP_GPIODOE_IN		1
+
+/* Polarity */
+#define MVSOCGPP_GPIODIP_INVERT		1
+
+/* Interrupt Mask */
+#define MVSOCGPP_GPIOIM_EDGE		0
+#define MVSOCGPP_GPIOIM_LEVEL		1
+
+#endif	/* _ORIONPCIREG_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/arch/arm/marvell/mvsocgppvar.h	Fri Oct 22 09:23:11 2010 +0000
@@ -0,0 +1,45 @@
+/*	$NetBSD: mvsocgppvar.h,v 1.1.4.2 2010/10/22 09:23:12 uebayasi Exp $	*/
+/*
+ * Copyright (c) 2008, 2008 KIYOHARA Takashi
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _MVSOCGPPVAR_H_
+#define _MVSOCGPPVAR_H_
+
+
+static __inline void *
+mvsocgpp_intr_establish(int pin, int ipl, int type,
+			int (*func)(void *), void *arg)
+{
+
+	return intr_establish(gpp_irqbase + pin, ipl, type, func, arg);
+}
+#define mvsocgpp_intr_disestablish(ih)	intr_disestablish(ih)
+
+int mvsocgpp_pin_read(void *, int);
+void mvsocgpp_pin_write(void *, int, int);
+void mvsocgpp_pin_ctl(void *, int, int);
+
+#endif	/* _MVSOCGPPVAR_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/arch/arm/marvell/mvsocreg.h	Fri Oct 22 09:23:11 2010 +0000
@@ -0,0 +1,134 @@
+/*	$NetBSD: mvsocreg.h,v 1.1.4.2 2010/10/22 09:23:12 uebayasi Exp $	*/
+/*
+ * Copyright (c) 2007, 2008 KIYOHARA Takashi
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _MVSOCREG_H_
+#define _MVSOCREG_H_
+
+#define MVSOC_UNITID_MASK		0xf
+#define MVSOC_UNITID_DDR		0x0	/* DDR registers */
+#define MVSOC_UNITID_DEVBUS		0x1	/* Device Bus registers */
+#define MVSOC_UNITID_MLMB		0x2	/* Mbus-L to Mbus Bridge reg */
+#define MVSOC_UNITID_PEX		0x4	/* PCI Express Interface reg */
+
+
+/*
+ * Physical address of integrated peripherals
+ */
+
+#define UNITID2PHYS(uid)	((MVSOC_UNITID_ ## uid) << 16)
+
+/*
+ * DDR SDRAM Controller Registers
+ */
+#define MVSOC_DDR_BASE		(UNITID2PHYS(DDR))	/* 0x00000 */
+
+/* DDR SDRAM Contriller Address Decode Registers */
+#define MVSOC_DSC_BASE			0x01500	/* DDR SDRAM Ctrl Addr Reg */
+#define MVSOC_DSC_NCS			4
+#define MVSOC_DSC_CSBAR(x)		((x) * 8)
+#define MVSOC_DSC_CSBAR_BASE_MASK	0xff000000
+#define MVSOC_DSC_CSSR(x)		((x) * 8 + 4)
+#define MVSOC_DSC_CSSR_WINEN		0x00000001
+#define MVSOC_DSC_CSSR_SIZE_MASK	0xff000000
+
+
+/*
+ * Device Bus
+ */
+#define MVSOC_DEVBUS_BASE	(UNITID2PHYS(DEVBUS))	/* 0x10000 */
+
+/*
+ * General Purpose Port Registers
+ */
+#define MVSOC_GPP_BASE			(MVSOC_DEVBUS_BASE + 0x0100)
+
+/*
+ * Two-Wire Serial Interface Registers
+ */
+#define MVSOC_TWSI_BASE			(MVSOC_DEVBUS_BASE + 0x1000)
+
+/*
+ * UART Interface Registers
+ */
+					/* NS16550 compatible */
+#define MVSOC_COM0_BASE			(MVSOC_DEVBUS_BASE + 0x2000)
+#define MVSOC_COM1_BASE			(MVSOC_DEVBUS_BASE + 0x2100)
+
+/*
+ * Mbus-L to Mbus Bridge Registers
+ */
+#define MVSOC_MLMB_BASE		(UNITID2PHYS(MLMB))	/* 0x20000 */
+
+/* CPU Address Map Registers */
+#define MVSOC_MLMB_WCR(w)		  (((w) << 4) + 0x0)
+#define MVSOC_MLMB_WCR_WINEN			(1 << 0)
+#define MVSOC_MLMB_WCR_TARGET(t)		(((t) & 0xf) << 4)
+#define MVSOC_MLMB_WCR_ATTR(a)			(((a) & 0xff) << 8)
+#define MVSOC_MLMB_WCR_SIZE_MASK		0xffff0000
+#define MVSOC_MLMB_WCR_SIZE(s)		  (((s) - 1) & MVSOC_MLMB_WCR_SIZE_MASK)
+#define MVSOC_MLMB_WBR(w)		  (((w) << 4) + 0x4)
+#define MVSOC_MLMB_WBR_BASE_MASK		0xffff0000
+#define MVSOC_MLMB_WRLR(w)		  (((w) << 4) + 0x8)
+#define MVSOC_MLMB_WRLR_REMAP_MASK		0xffff0000
+#define MVSOC_MLMB_WRHR(w)		  (((w) << 4) + 0xc)
+#define MVSOC_MLMB_IRBAR		  0x080 /* Internal regs Base Address */
+#define MVSOC_MLMB_IRBAR_BASE_MASK	0xfff00000
+
+/* CPU Control and Status Registers */
+#define MVSOC_MLMB_CPUCR		  0x100	/* CPU Configuration Register */
+#define MVSOC_MLMB_CPUCSR		  0x104	/* CPU Control/Status Register*/
+#define MVSOC_MLMB_RSTOUTNMASKR		  0x108 /* RSTOUTn Mask Register */
+#define MVSOC_MLMB_SSRR			  0x10c	/* System Soft Reset Register */
+#define MVSOC_MLMB_MLMBICR		  0x110	/*Mb-L to Mb Bridge Intr Cause*/
+#define MVSOC_MLMB_MLMBIMR		  0x114	/*Mb-L to Mb Bridge Intr Mask */
+
+#define MVSOC_MLMB_L2CFG		  0x128	/* L2 Cache Config */
+
+#define MVSOC_TMR_BASE			(MVSOC_MLMB_BASE + 0x0300)
+
+/* CPU Doorbell Registers */
+#define MVSOC_MLMB_H2CDR		  0x400	/* Host-to-CPU Doorbell */
+#define MVSOC_MLMB_H2CDMR		  0x404	/* Host-to-CPU Doorbell Mask */
+#define MVSOC_MLMB_C2HDR		  0x408	/* CPU-to-Host Doorbell */
+#define MVSOC_MLMB_C2HDMR		  0x40c	/* CPU-to-Host Doorbell Mask */
+
+/* Local to System Bridge Interrupt {Cause,Mask} Register bits */
+#define MVSOC_MLMB_MLMBI_CPUSELFINT		0
+#define MVSOC_MLMB_MLMBI_CPUTIMER0INTREQ	1
+#define MVSOC_MLMB_MLMBI_CPUTIMER1INTREQ	2
+#define MVSOC_MLMB_MLMBI_CPUWDTIMERINTREQ	3
+#define MVSOC_MLMB_MLMBI_ACCESSERR		4
+#define MVSOC_MLMB_MLMBI_BIT64ERR		5
+
+#define MVSOC_MLMB_MLMBI_NIRQ			6
+
+/*
+ * PCI-Express Interface Registers
+ */
+#define MVSOC_PEX_BASE		(UNITID2PHYS(PEX))	/* 0x40000 */
+
+#endif	/* _MVSOCREG_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/arch/arm/marvell/mvsoctmr.c	Fri Oct 22 09:23:11 2010 +0000
@@ -0,0 +1,305 @@
+/*	$NetBSD: mvsoctmr.c,v 1.1.4.2 2010/10/22 09:23:12 uebayasi Exp $	*/
+/*
+ * Copyright (c) 2007, 2008 KIYOHARA Takashi
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: mvsoctmr.c,v 1.1.4.2 2010/10/22 09:23:12 uebayasi Exp $");
+
+#include <sys/param.h>
+#include <sys/atomic.h>
+#include <sys/bus.h>
+#include <sys/device.h>
+#include <sys/errno.h>
+#include <sys/kernel.h>
+#include <sys/time.h>
+#include <sys/timetc.h>
+#include <sys/systm.h>
+
+#include <machine/intr.h>
+
+#include <arm/cpufunc.h>
+
+#include <arm/marvell/mvsocreg.h>
+#include <arm/marvell/mvsocvar.h>
+#include <arm/marvell/mvsoctmrreg.h>
+
+#include <dev/marvell/marvellvar.h>
+
+
+struct mvsoctmr_softc {
+	device_t sc_dev;
+
+	bus_space_tag_t sc_iot;
+	bus_space_handle_t sc_ioh;
+};
+
+
+static int mvsoctmr_match(device_t, struct cfdata *, void *);
+static void mvsoctmr_attach(device_t, device_t, void *);
+
+static int clockhandler(void *);
+static int statclockhandler(void *);
+
+static u_int mvsoctmr_get_timecount(struct timecounter *);
+
+static void mvsoctmr_cntl(struct mvsoctmr_softc *, int, u_int, int, int);
+
+#ifndef STATHZ
+#define STATHZ	64
+#endif
+
+static struct mvsoctmr_softc *mvsoctmr_sc;
+static uint32_t clock_ticks, statclock_ticks;
+static struct timecounter mvsoctmr_timecounter = {
+	mvsoctmr_get_timecount,	/* get_timecount */
+	0,			/* no poll_pps */
+	~0u,			/* counter_mask */
+	0,			/* frequency  (set by cpu_initclocks()) */
+	"mvsoctmr",		/* name */
+	100,			/* quality */
+	NULL,			/* prev */
+	NULL,			/* next */
+};
+static volatile uint32_t mvsoctmr_base;
+
+CFATTACH_DECL_NEW(mvsoctmr, sizeof(struct mvsoctmr_softc),
+    mvsoctmr_match, mvsoctmr_attach, NULL, NULL);
+
+
+/* ARGSUSED */
+static int
+mvsoctmr_match(device_t parent, struct cfdata *match, void *aux)
+{
+	struct marvell_attach_args *mva = aux;
+
+	if (strcmp(mva->mva_name, match->cf_name) != 0)
+		return 0;
+	if (mva->mva_offset == MVA_OFFSET_DEFAULT)
+		return 0;
+
+	mva->mva_size = MVSOCTMR_SIZE;
+	return 1;
+}
+
+/* ARGSUSED */
+static void
+mvsoctmr_attach(device_t parent, device_t self, void *aux)
+{
+        struct mvsoctmr_softc *sc = device_private(self);
+	struct marvell_attach_args *mva = aux;
+
+	aprint_naive("\n");
+	aprint_normal(": Marvell SoC Timer\n");
+
+	if (mvsoctmr_sc == NULL)
+		mvsoctmr_sc = sc;
+
+	sc->sc_dev = self;
+	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))
+		panic("%s: Cannot map registers", device_xname(self));
+}
+
+/*
+ * clockhandler:
+ *
+ *	Handle the hardclock interrupt.
+ */
+static int
+clockhandler(void *arg)
+{
+	struct clockframe *frame = arg;
+
+	atomic_add_32(&mvsoctmr_base, clock_ticks);
+
+	hardclock(frame);
+
+	return 1;
+}
+
+/*
+ * statclockhandler:
+ *
+ *	Handle the statclock interrupt.
+ */
+static int
+statclockhandler(void *arg)
+{
+	struct clockframe *frame = arg;
+
+	statclock(frame);
+
+	return 1;
+}
+
+
+/*
+ * setstatclockrate:
+ *
+ *	Set the rate of the statistics clock.
+ *
+ *	We assume that hz is either stathz or profhz, and that neither
+ *	will change after being set by cpu_initclocks().  We could
+ *	recalculate the intervals here, but that would be a pain.
+ */
+/* ARGSUSED */
+void
+setstatclockrate(int newhz)
+{
+	struct mvsoctmr_softc *sc = mvsoctmr_sc;
+	const int en = 1, autoen = 1;
+
+	statclock_ticks = mvTclk / newhz;
+
+	mvsoctmr_cntl(sc, MVSOCTMR_TIMER1, statclock_ticks, en, autoen);
+}
+
+/*
+ * cpu_initclocks:
+ *
+ *	Initialize the clock and get them going.
+ */
+void
+cpu_initclocks()
+{
+	struct mvsoctmr_softc *sc;
+	void *clock_ih;
+	const int en = 1, autoen = 1;
+
+	sc = mvsoctmr_sc;
+	if (sc == NULL)
+		panic("cpu_initclocks: mvsoctmr not found");
+
+	stathz = profhz = STATHZ;
+	mvsoctmr_timecounter.tc_frequency = mvTclk;
+	clock_ticks = mvTclk / hz;
+
+	mvsoctmr_cntl(sc, MVSOCTMR_TIMER0, clock_ticks, en, autoen);
+
+	clock_ih = mvsoc_bridge_intr_establish(MVSOC_MLMB_MLMBI_CPUTIMER0INTREQ,
+	    IPL_CLOCK, clockhandler, NULL);
+	if (clock_ih == NULL)
+		panic("cpu_initclocks: unable to register timer interrupt");
+
+	if (stathz) {
+		setstatclockrate(stathz);
+		clock_ih = mvsoc_bridge_intr_establish(
+		    MVSOC_MLMB_MLMBI_CPUTIMER1INTREQ, IPL_HIGH,
+		    statclockhandler, NULL);
+		if (clock_ih == NULL)
+			panic("cpu_initclocks:"
+			    " unable to register statclock timer interrupt");
+	}
+
+	tc_init(&mvsoctmr_timecounter);
+}
+
+void
+delay(unsigned int n)
+{
+	struct mvsoctmr_softc *sc;
+	unsigned int cur_tick, initial_tick;
+	int remaining;
+
+	sc = mvsoctmr_sc;
+#ifdef DEBUG
+	if (sc == NULL) {
+		printf("%s: called before start mvsoctmr\n", __func__);
+		return;
+	}
+#endif
+
+	/*
+	 * Read the counter first, so that the rest of the setup overhead is
+	 * counted.
+	 */
+	initial_tick = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
+	    MVSOCTMR_TIMER(MVSOCTMR_TIMER0));
+
+	if (n <= UINT_MAX / mvTclk) {
+		/*
+		 * For unsigned arithmetic, division can be replaced with
+		 * multiplication with the inverse and a shift.
+		 */
+		remaining = n * mvTclk / 1000000;
+	} else {
+		/*
+		 * This is a very long delay.
+		 * Being slow here doesn't matter.
+		 */
+		remaining = (unsigned long long) n * mvTclk / 1000000;
+	}
+
+	while (remaining > 0) {
+		cur_tick = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
+		    MVSOCTMR_TIMER(MVSOCTMR_TIMER0));
+		if (cur_tick > initial_tick)
+			remaining -= clock_ticks - cur_tick + initial_tick;
+		else
+			remaining -= (initial_tick - cur_tick);
+		initial_tick = cur_tick;
+	}
+}
+
+static u_int
+mvsoctmr_get_timecount(struct timecounter *tc)
+{
+	struct mvsoctmr_softc *sc = mvsoctmr_sc;
+	uint32_t counter, base;
+	u_int intrstat;
+
+	intrstat = disable_interrupts(I32_bit);
+	base = mvsoctmr_base;
+	counter = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
+	    MVSOCTMR_TIMER(MVSOCTMR_TIMER0));
+	restore_interrupts(intrstat);
+
+	return base - counter;
+}
+
+
+static void
+mvsoctmr_cntl(struct mvsoctmr_softc *sc, int num, u_int ticks, int en,
+	      int autoen)
+{
+	uint32_t ctrl;
+
+	bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVSOCTMR_RELOAD(num),
+	    ticks);
+
+	bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVSOCTMR_TIMER(num), ticks);
+
+	ctrl = bus_space_read_4(sc->sc_iot, sc->sc_ioh, MVSOCTMR_CTCR);
+	if (en)
+		ctrl |= MVSOCTMR_CTCR_CPUTIMEREN(num);
+	else
+		ctrl &= ~MVSOCTMR_CTCR_CPUTIMEREN(num);
+	if (autoen)
+		ctrl |= MVSOCTMR_CTCR_CPUTIMERAUTO(num);
+	else
+		ctrl &= ~MVSOCTMR_CTCR_CPUTIMERAUTO(num);
+	bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVSOCTMR_CTCR, ctrl);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/arch/arm/marvell/mvsoctmrreg.h	Fri Oct 22 09:23:11 2010 +0000
@@ -0,0 +1,45 @@
+/*	$NetBSD: mvsoctmrreg.h,v 1.1.4.2 2010/10/22 09:23:12 uebayasi Exp $	*/
+/*
+ * Copyright (c) 2007 KIYOHARA Takashi
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _MVSOCTMRREG_H_
+#define _MVSOCTMRREG_H_
+
+#define MVSOCTMR_SIZE		0x100
+
+#define MVSOCTMR_CTCR		0x00		/* CPU Timers Control */
+#define MVSOCTMR_RELOAD(n)	(0x10 + (n) * 8)/* CPU Timer(n) Reload */
+#define MVSOCTMR_TIMER(n)	(0x14 + (n) * 8)/* CPU Timer(n) */
+
+#define MVSOCTMR_TIMER0		0
+#define MVSOCTMR_TIMER1		1
+#define MVSOCTMR_WATCHDOG	2
+
+
+/* CPU Timers Control Register (MVSOCTMR_CTCR) */
+#define MVSOCTMR_CTCR_CPUTIMEREN(n)	(1 << (n * 2))
+#define MVSOCTMR_CTCR_CPUTIMERAUTO(n)	(1 << (n * 2 + 1))
+
+#endif	/* !_MVSOCTMRREG_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/arch/arm/marvell/mvsocvar.h	Fri Oct 22 09:23:11 2010 +0000
@@ -0,0 +1,92 @@
+/*	$NetBSD: mvsocvar.h,v 1.1.4.2 2010/10/22 09:23:12 uebayasi Exp $	*/
+/*
+ * Copyright (c) 2007, 2010 KIYOHARA Takashi
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _MVSOCVAR_H_
+#define _MVSOCVAR_H_
+
+#include <machine/bus.h>
+
+struct mvsoc_softc {
+        device_t sc_dev;
+
+	bus_addr_t sc_addr;
+	bus_space_tag_t sc_iot;
+	bus_space_handle_t sc_ioh;
+	bus_dma_tag_t sc_dmat;
+};
+
+typedef int (*mvsoc_irq_handler_t)(void *);
+
+extern uint32_t mvPclk, mvSysclk, mvTclk;
+extern vaddr_t mlmb_base;
+extern int nwindow, nremap;
+extern int gpp_npins, gpp_irqbase;
+extern struct bus_space mvsoc_bs_tag;
+extern struct arm32_bus_dma_tag mvsoc_bus_dma_tag;
+
+#define read_mlmbreg(o)		(*(volatile uint32_t *)(mlmb_base + (o)))
+#define write_mlmbreg(o, v)	(*(volatile uint32_t *)(mlmb_base + (o)) = (v))
+
+void mvsoc_bootstrap(bus_addr_t);
+uint16_t mvsoc_model(void);
+uint8_t mvsoc_rev(void);
+void * mvsoc_bridge_intr_establish(int, int, int (*)(void *), void *);
+
+#include <dev/marvell/marvellvar.h>
+
+enum mvsoc_tags {
+	MVSOC_TAG_INTERNALREG  = MARVELL_TAG_MAX,
+
+	ORION_TAG_PEX0_MEM,
+	ORION_TAG_PEX0_IO,
+	ORION_TAG_PEX1_MEM,
+	ORION_TAG_PEX1_IO,
+	ORION_TAG_PCI_MEM,
+	ORION_TAG_PCI_IO,
+	ORION_TAG_DEVICE_CS0,
+	ORION_TAG_DEVICE_CS1,
+	ORION_TAG_DEVICE_CS2,
+	ORION_TAG_FLASH_CS,
+	ORION_TAG_DEVICE_BOOTCS,
+	ORION_TAG_CRYPT,
+
+	KIRKWOOD_TAG_PEX_MEM,
+	KIRKWOOD_TAG_PEX_IO,
+	KIRKWOOD_TAG_NAND,
+	KIRKWOOD_TAG_SPI,
+	KIRKWOOD_TAG_BOOTROM,
+	KIRKWOOD_TAG_CRYPT,
+};
+int mvsoc_target(int, uint32_t *, uint32_t *, uint32_t *, uint32_t *);
+
+void orion_getclks(bus_addr_t);
+void orion_intr_bootstrap(void);
+
+void kirkwood_getclks(bus_addr_t);
+void kirkwood_intr_bootstrap(void);
+
+#endif	/* _MVSOCVAR_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/arch/arm/marvell/orion.c	Fri Oct 22 09:23:11 2010 +0000
@@ -0,0 +1,257 @@
+/*	$NetBSD: orion.c,v 1.1.4.2 2010/10/22 09:23:12 uebayasi Exp $	*/
+/*
+ * Copyright (c) 2010 KIYOHARA Takashi
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: orion.c,v 1.1.4.2 2010/10/22 09:23:12 uebayasi Exp $");
+
+#define _INTR_PRIVATE
+
+#include "mvsocgpp.h"
+
+#include <sys/param.h>
+#include <sys/bus.h>
+
+#include <machine/intr.h>
+
+#include <arm/pic/picvar.h>
+#include <arm/pic/picvar.h>
+
+#include <arm/marvell/mvsocreg.h>
+#include <arm/marvell/mvsocvar.h>
+#include <arm/marvell/orionreg.h>
+
+#include <dev/marvell/marvellreg.h>
+
+
+static void orion_intr_init(void);
+
+static void orion_pic_unblock_irqs(struct pic_softc *, size_t, uint32_t);
+static void orion_pic_block_irqs(struct pic_softc *, size_t, uint32_t);
+static void orion_pic_establish_irq(struct pic_softc *, struct intrsource *);
+static void orion_pic_source_name(struct pic_softc *, int, char *, size_t);
+
+static int orion_find_pending_irqs(void);
+
+static const char * const sources[64] = {
+    "Bridge(0)",       "Host2CPU DB(1)",  "CPU2Host DB(2)",  "UART0(3)",
+    "UART1(4)",        "TWSI(5)",         "GPIO7_0(6)",      "GPIO15_8(7)",
+    "GPIO23_16(8)",    "GPIO31_24(9)",    "PEX0Err(10)",     "PEX0INT(11)",
+    "PEX1Err/USBCnt1", "PEX1INT(13)",     "DEVErr(14)",      "PCIErr(15)",
+    "USBBr(16)",       "USBCnt0(17)",     "GbERx(18)",       "GbETx(19)",
+    "GbEMisc(20)",     "GbESum(21)",      "GbEErr(22)",      "DMAErr(23)",
+    "IDMA0(24)",       "IDMA1(25)",       "IDMA2(26)",       "IDMA3(27)",
+    "SecIntr(28)",     "SataIntr(29)",    "XOR0(30)",        "XOR1(31)"
+};
+
+static struct pic_ops orion_picops = {
+	.pic_unblock_irqs = orion_pic_unblock_irqs,
+	.pic_block_irqs = orion_pic_block_irqs,
+	.pic_establish_irq = orion_pic_establish_irq,
+	.pic_source_name = orion_pic_source_name,
+};
+static struct pic_softc orion_pic = {
+	.pic_ops = &orion_picops,
+	.pic_maxsources = 32,
+	.pic_name = "orion_pic",
+};
+
+
+/*
+ * orion_intr_bootstrap:
+ *
+ *	Initialize the rest of the interrupt subsystem, making it
+ *	ready to handle interrupts from devices.
+ */
+void
+orion_intr_bootstrap()
+{
+	extern void (*mvsoc_intr_init)(void);
+
+	/* disable all interrupts */
+	write_mlmbreg(ORION_MLMB_MIRQIMR, 0);
+
+	/* disable all bridge interrupts */
+	write_mlmbreg(MVSOC_MLMB_MLMBIMR, 0);
+
+	mvsoc_intr_init = orion_intr_init;
+
+#if NMVSOCGPP > 0
+	gpp_npins = 32;
+	gpp_irqbase = 64;	/* Main(32) + Bridge(32) */
+#endif
+}
+
+static void
+orion_intr_init(void)
+{
+	extern struct pic_softc mvsoc_bridge_pic;
+	void *ih;
+
+	pic_add(&orion_pic, 0);
+
+	pic_add(&mvsoc_bridge_pic, 32);
+	ih = intr_establish(ORION_IRQ_BRIDGE, IPL_HIGH, IST_LEVEL_HIGH,
+	    pic_handle_intr, &mvsoc_bridge_pic);
+	KASSERT(ih != NULL);
+
+	find_pending_irqs = orion_find_pending_irqs;
+}
+
+/* ARGSUSED */
+static void
+orion_pic_unblock_irqs(struct pic_softc *pic, size_t irqbase, uint32_t irq_mask)
+{
+
+	write_mlmbreg(ORION_MLMB_MIRQIMR,
+	    read_mlmbreg(ORION_MLMB_MIRQIMR) | irq_mask);
+}
+
+/* ARGSUSED */
+static void
+orion_pic_block_irqs(struct pic_softc *pic, size_t irqbase, uint32_t irq_mask)
+{
+
+	write_mlmbreg(ORION_MLMB_MIRQIMR,
+	    read_mlmbreg(ORION_MLMB_MIRQIMR) & ~irq_mask);
+}
+
+/* ARGSUSED */
+static void
+orion_pic_establish_irq(struct pic_softc *pic, struct intrsource *is)
+{
+	/* Nothing */
+}
+
+static void
+orion_pic_source_name(struct pic_softc *pic, int irq, char *buf, size_t len)
+{
+
+	strlcpy(buf, sources[pic->pic_irqbase + irq], len);
+}
+
+/*
+ * Called with interrupts disabled
+ */
+static int
+orion_find_pending_irqs(void)
+{
+	uint32_t pending;
+
+	pending =
+	    read_mlmbreg(ORION_MLMB_MICR) & read_mlmbreg(ORION_MLMB_MIRQIMR);
+	if (pending == 0)
+		return 0;
+
+	return pic_mark_pending_sources(&orion_pic, 0, pending);
+}
+
+/*
+ * Clock functions
+ */
+
+void
+orion_getclks(bus_addr_t iobase)
+{
+	static struct {
+		int armddrclkval;
+		uint32_t pclk;
+		uint32_t sysclk;
+	} sysclktbl[] = {
+		{ ORION_PMISMPL_ARMDDRCLK_333_167, 333000000, 166666667 },
+		{ ORION_PMISMPL_ARMDDRCLK_400_200, 400000000, 200000000 },
+		{ ORION_PMISMPL_ARMDDRCLK_400_133, 400000000, 133333334 },
+		{ ORION_PMISMPL_ARMDDRCLK_500_167, 500000000, 166666667 },
+		{ ORION_PMISMPL_ARMDDRCLK_533_133, 533000000, 133333334 },
+		{ ORION_PMISMPL_ARMDDRCLK_600_200, 600000000, 200000000 },
+		{ ORION_PMISMPL_ARMDDRCLK_667_167, 667000000, 166666667 },
+		{ ORION_PMISMPL_ARMDDRCLK_800_200, 800000000, 200000000 },
+		{ ORION_PMISMPL_ARMDDRCLK_480_160, 480000000, 160000000 },
+		{ ORION_PMISMPL_ARMDDRCLK_550_183, 550000000, 183333334 },
+		{ ORION_PMISMPL_ARMDDRCLK_525_175, 525000000, 175000000 },
+		{ ORION_PMISMPL_ARMDDRCLK_466_233, 466000000, 233000000 },
+		{ ORION_PMISMPL_ARMDDRCLK_500_250, 500000000, 250000000 },
+		{ ORION_PMISMPL_ARMDDRCLK_533_266, 533000000, 266000000 },
+		{ ORION_PMISMPL_ARMDDRCLK_600_300, 600000000, 300000000 },
+		{ ORION_PMISMPL_ARMDDRCLK_450_150, 450000000, 150000000 },
+		{ ORION_PMISMPL_ARMDDRCLK_533_178, 533000000, 178000000 },
+		{ ORION_PMISMPL_ARMDDRCLK_575_192, 575000000, 192000000 },
+		{ ORION_PMISMPL_ARMDDRCLK_700_175, 700000000, 175000000 },
+		{ ORION_PMISMPL_ARMDDRCLK_733_183, 733000000, 183333334 },
+		{ ORION_PMISMPL_ARMDDRCLK_750_187, 750000000, 187000000 },
+		{ ORION_PMISMPL_ARMDDRCLK_775_194, 775000000, 194000000 },
+		{ ORION_PMISMPL_ARMDDRCLK_500_125, 500000000, 125000000 },
+		{ ORION_PMISMPL_ARMDDRCLK_500_100, 500000000, 100000000 },
+		{ ORION_PMISMPL_ARMDDRCLK_600_150, 600000000, 150000000 },
+
+		{ 0, 0, 0 },
+	};
+	uint32_t reg, armddrclk, tclk;
+	uint16_t model;
+	int armddrclk_shift, tclk_shift, i;
+
+	model = mvsoc_model();
+	if (model == MARVELL_ORION_1_88F1181 ||
+	    model == MARVELL_ORION_2_88F1281) {
+		armddrclk_shift = 6;
+		tclk_shift = 10;
+	} else {
+		armddrclk_shift = 4;
+		tclk_shift = 8;
+	}
+
+	reg = *(volatile uint32_t *)(iobase + ORION_PMI_BASE +
+	    ORION_PMI_SAMPLE_AT_RESET);
+	armddrclk = (reg >> armddrclk_shift) & ORION_PMISMPL_ARMDDRCLK_MASK;
+	if (model == PCI_PRODUCT_MARVELL_88F5281)
+		if (reg & ORION_PMISMPL_ARMDDRCLK_H_MASK)
+			armddrclk |= 0x00000010;	/* set to bit4 */
+	for (i = 0; sysclktbl[i].pclk != 0; i++)
+		if (armddrclk == sysclktbl[i].armddrclkval) {
+			mvPclk = sysclktbl[i].pclk;
+			mvSysclk = sysclktbl[i].sysclk;
+			break;
+		}
+
+	tclk = (reg >> tclk_shift) & ORION_PMISMPL_TCLK_MASK;
+	switch (tclk) {
+	case ORION_PMISMPL_TCLK_133:
+		mvTclk = 133333334;	/* 133MHz */
+		break;
+
+	case ORION_PMISMPL_TCLK_150:
+		mvTclk = 150000000;	/* 150MHz */
+		break;
+
+	case ORION_PMISMPL_TCLK_166:
+		mvTclk = 166666667;	/* 166MHz */
+		break;
+
+	default:
+		mvTclk = 100000000;	/* 100MHz */
+		break;
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/arch/arm/marvell/orionreg.h	Fri Oct 22 09:23:11 2010 +0000
@@ -0,0 +1,206 @@
+/*	$NetBSD: orionreg.h,v 1.1.4.2 2010/10/22 09:23:12 uebayasi Exp $	*/
+/*
+ * Copyright (c) 2007, 2008 KIYOHARA Takashi
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _ORIONREG_H_
+#define _ORIONREG_H_
+
+#include <arm/marvell/mvsocreg.h>
+
+/*
+ *        Ver  GbE SATA  USB  PCI PCIe IDMA XORE CESA
+ * 1181:    1   -,   -,   -,   -,  x2,   ?,   -,   -
+ * 1281:    2   -,   -,   -,   -,  x2,   ?,   -,   -
+ * 5082:    1  x1,  x1,  x2,   -,  x1,   o,   -,   o
+ * 5180N:   1  x1,   -,  x1,  x1,  x1,   o,   -,   -
+ * 5181:    1  x1,   -,  x1,  x1,  x1,   o,   -,   o
+ * 5182:    1  x1,  x1,  x2,  x1,  x1,   o,   o,   o
+ * 5281:    2  x1,   -,  x1,  x1,  x1,   o,   -,   -
+ * 6082:    1  x2?, x1,  x1,   -,  x1,   -,   -,   o
+ * 6183:    1   ?,   -,  x?,   ?,   ?,   ?,   -,   -
+ * 8660:    1  x1,   -,  x1,  x1,  x1,   o,   -,   -
+ */
+
+#define ORION_UNITID_DDR		MVSOC_UNITID_DDR
+#define ORION_UNITID_DEVBUS		MVSOC_UNITID_DEVBUS
+#define ORION_UNITID_MLMB		MVSOC_UNITID_MLMB
+#define ORION_UNITID_PEX1		0x3			/* 1181 only */
+#define ORION_UNITID_PCI		0x3	/* PCI registers */
+#define ORION_UNITID_PEX		MVSOC_UNITID_PEX
+#define ORION_UNITID_USB0		0x5	/* USB registers Port0 */
+#define ORION_UNITID_IDMA		0x6	/* IDMA registers */
+#define ORION_UNITID_XOR		0x6	/* XOR registers */
+#define ORION_UNITID_GBE		0x7	/* Gigabit Ethernet registers */
+#define ORION_UNITID_SATA		0x8	/* SATA registers */
+#define ORION_UNITID_CRYPT		0x9	/* Cryptographic Engine reg */
+#define ORION_UNITID_SA			0x9	/* Security Accelerator reg */
+#define ORION_UNITID_USB1		0xa	/* USB registers Port1 */
+
+#define ORION_ATTR_DEVICE_CS0		0x1e
+#define ORION_ATTR_DEVICE_CS1		0x1d
+#define ORION_ATTR_DEVICE_CS2		0x1b
+#define ORION_ATTR_FLASH_CS		0x1b
+#define ORION_ATTR_BOOT_CS		0x0f
+#define ORION_ATTR_PEX_CFG		0x79	/* bug workaround ?? */
+#define ORION_ATTR_PEX_MEM		0x59
+#define ORION_ATTR_PEX_IO		0x51
+#define ORION_ATTR_PCI_MEM		0x59
+#define ORION_ATTR_PCI_IO		0x51
+#define ORION_ATTR_CRYPT		0x00
+
+/*
+ * Interrupt numbers
+ */
+#define ORION_IRQ_BRIDGE		0	/* Local to System Bridge */
+#define ORION_IRQ_HOST2CPU		1	/* Doorbell (Host-to-CPU) */
+#define ORION_IRQ_CPU2HOST		2	/* Doorbell (CPU-to-Host) */
+#define ORION_IRQ_UART0			3
+#define ORION_IRQ_UART1			4
+#define ORION_IRQ_TWSI			5	/* Two-Wire Serial Interface */
+#define ORION_IRQ_GPIO7_0		6	/* GPIO[7:0] */
+#define ORION_IRQ_GPIO15_8		7	/* GPIO[15:8] */
+#define ORION_IRQ_GPIO23_16		8	/* GPIO[23:16] not 1181 */
+#define ORION_IRQ_GPIO31_24		9	/* GPIO[31:24] not 1181 */
+#define ORION_IRQ_PEX0ERR		10	/* PCI Express error */
+#define ORION_IRQ_PEX0INT		11	/* PCIe INTA, B, C, D message */
+#define ORION_IRQ_PEX1ERR		12			/* 1181 only */
+#define ORION_IRQ_USBCNT1		12	/* USB Port1 controller (5182)*/
+#define ORION_IRQ_PEX1INT		13			/* 1181 only */
+#define ORION_IRQ_DEVERR		14	/* Device bus error */
+#define ORION_IRQ_PCIERR		15	/* PCI error */
+#define ORION_IRQ_USBBR			16	/* USB bridge Port0 or1 error */
+#define ORION_IRQ_USBCNT0		17	/* USB Port0 controller */
+#define ORION_IRQ_GBERX			18	/* GbE receive interrupt */
+#define ORION_IRQ_GBETX			19	/* GbE transmit interrupt */
+#define ORION_IRQ_GBEMISC		20	/* GbE miscellaneous intr */
+#define ORION_IRQ_GBESUM		21	/* GbE summary */
+#define ORION_IRQ_GBEERR		22	/* GbE error */
+#define ORION_IRQ_DMAERR		23	/* DMA or XOR error */
+#define ORION_IRQ_IDMA0			24	/* IDMA Channel0 completion */
+#define ORION_IRQ_IDMA1			25	/* IDMA Channel1 completion */
+#define ORION_IRQ_IDMA2			26	/* IDMA Channel2 completion */
+#define ORION_IRQ_IDMA3			27	/* IDMA Channel3 completion */
+#define ORION_IRQ_SECURITYINTR		28	/* Security accelerator intr */
+#define ORION_IRQ_SATAINTR		29	/* Serial-ATA interrupt */
+#define ORION_IRQ_XOR0			30	/* XOR engine 0 interrupt */
+#define ORION_IRQ_XOR1			31	/* XOR engine 1 interrupt */
+
+
+/*
+ * Physical address of integrated peripherals
+ */
+
+#define ORION_UNITID2PHYS(uid)	((ORION_UNITID_ ## uid) << 16)
+
+/*
+ * Pin Multiplexing Interface Registers
+ */
+#define ORION_PMI_BASE			(MVSOC_DEVBUS_BASE + 0x0000)
+#define ORION_PMI_SIZE			  0x100		/* XXXX */
+#define ORION_PMI_MPPCR0		   0x00
+#define ORION_PMI_MPPCR1		   0x04
+#define ORION_PMI_MPPCR2		   0x50
+#define ORION_PMI_DEVMULTICR		   0x08
+#define ORION_PMI_SAMPLE_AT_RESET	   0x10
+#define ORION_PMISMPL_ARMDDRCLK_MASK		0x0f
+#define ORION_PMISMPL_ARMDDRCLK_H_MASK		(1 << 23)
+#define ORION_PMISMPL_ARMDDRCLK_333_167		0x00
+#define ORION_PMISMPL_ARMDDRCLK_400_200		0x01
+#define ORION_PMISMPL_ARMDDRCLK_400_133		0x02
+#define ORION_PMISMPL_ARMDDRCLK_500_167		0x03
+#define ORION_PMISMPL_ARMDDRCLK_533_133		0x04
+#define ORION_PMISMPL_ARMDDRCLK_600_200		0x05
+#define ORION_PMISMPL_ARMDDRCLK_667_167		0x06
+#define ORION_PMISMPL_ARMDDRCLK_800_200		0x07
+#define ORION_PMISMPL_ARMDDRCLK_480_160		0x0c
+#define ORION_PMISMPL_ARMDDRCLK_550_183		0x0d
+#define ORION_PMISMPL_ARMDDRCLK_525_175		0x0e
+#define ORION_PMISMPL_ARMDDRCLK_466_233		0x11
+#define ORION_PMISMPL_ARMDDRCLK_500_250		0x12
+#define ORION_PMISMPL_ARMDDRCLK_533_266		0x13
+#define ORION_PMISMPL_ARMDDRCLK_600_300		0x14
+#define ORION_PMISMPL_ARMDDRCLK_450_150		0x15
+#define ORION_PMISMPL_ARMDDRCLK_533_178		0x16
+#define ORION_PMISMPL_ARMDDRCLK_575_192		0x17
+#define ORION_PMISMPL_ARMDDRCLK_700_175		0x18
+#define ORION_PMISMPL_ARMDDRCLK_733_183		0x19
+#define ORION_PMISMPL_ARMDDRCLK_750_187		0x1a
+#define ORION_PMISMPL_ARMDDRCLK_775_194		0x1b
+#define ORION_PMISMPL_ARMDDRCLK_500_125		0x1c
+#define ORION_PMISMPL_ARMDDRCLK_500_100		0x1d
+#define ORION_PMISMPL_ARMDDRCLK_600_150		0x1e
+#define ORION_PMISMPL_TCLK_MASK			0x3
+#define ORION_PMISMPL_TCLK_133			0x0
+#define ORION_PMISMPL_TCLK_150			0x1
+#define ORION_PMISMPL_TCLK_166			0x2
+
+/*
+ * Mbus-L to Mbus Bridge Registers
+ */
+/* CPU Address Map Registers */
+#define ORION_MLMB_NWINDOW		8          
+#define ORION_MLMB_NREMAP		2
+
+/* Main Interrupt Controller Registers */
+#define ORION_MLMB_MICR			  0x200	/* Main Interrupt Cause reg */
+#define ORION_MLMB_MIRQIMR		  0x204	/* Main IRQ Interrupt Mask */
+#define ORION_MLMB_MFIQIMR		  0x208	/* Main FIQ Interrupt Mask */
+#define ORION_MLMB_EIMR			  0x20c	/* Endpoint Interrupt Mask */
+
+/*
+ * PCI Express Interface Registers
+ *   or PCI Interface Registers
+ */
+#define ORION_PEX1_BASE		(ORION_UNITID2PHYS(PEX1))	/* 0x30000 */
+#define ORION_PCI_BASE		(ORION_UNITID2PHYS(PCI))	/* 0x30000 */
+
+/*
+ * USB 2.0 Interface Registers
+ */
+#define ORION_USB0_BASE		(ORION_UNITID2PHYS(USB0))	/* 0x50000 */
+#define ORION_USB1_BASE		(ORION_UNITID2PHYS(USB1))	/* 0xa0000 */
+
+/*
+ * IDMA Controller and XOR Engine Registers
+ */
+#define ORION_IDMAC_BASE	(ORION_UNITID2PHYS(IDMA))	/* 0x60000 */
+
+/*
+ * Gigabit Ethernet Registers
+ */
+#define ORION_GBE_BASE		(ORION_UNITID2PHYS(GBE))	/* 0x70000 */
+
+/*
+ * Serial-ATA Host Controller (SATAHC) Registers
+ */
+#define ORION_SATAHC_BASE	(ORION_UNITID2PHYS(SATA))	/* 0x80000 */
+
+/*
+ * Cryptographic Engine and Security Accelerator Registers
+ */
+#define ORION_CESA_BASE		(ORION_UNITID2PHYS(CRYPT))	/* 0x90000 */
+
+#endif	/* _ORIONREG_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/arch/arm/marvell/pci_machdep.c	Fri Oct 22 09:23:11 2010 +0000
@@ -0,0 +1,419 @@
+/*	$NetBSD: pci_machdep.c,v 1.1.4.2 2010/10/22 09:23:12 uebayasi Exp $	*/
+/*
+ * Copyright (c) 2008 KIYOHARA Takashi
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: pci_machdep.c,v 1.1.4.2 2010/10/22 09:23:12 uebayasi Exp $");
+
+#include "opt_mvsoc.h"
+#include "gtpci.h"
+#include "mvpex.h"
+#include "pci.h"
+
+#include <sys/param.h>
+#include <sys/device.h>
+#include <sys/extent.h>
+
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pciconf.h>
+
+#include <arm/marvell/mvsocreg.h>
+#include <arm/marvell/mvsocvar.h>
+#include <arm/marvell/mvsocgppvar.h>
+#if NGTPCI > 0
+#include <dev/marvell/gtpcireg.h>
+#include <dev/marvell/gtpcivar.h>
+#endif
+#if NMVPEX > 0
+#include <dev/marvell/mvpexreg.h>
+#include <dev/marvell/mvpexvar.h>
+#endif
+
+#include <machine/pci_machdep.h>
+
+#if defined(ORION)
+#include <arm/marvell/orionreg.h>
+#endif
+#if defined(KIRKWOOD)
+#include <arm/marvell/kirkwoodreg.h>
+#endif
+#include <dev/marvell/marvellreg.h>
+
+
+#if NGTPCI > 0
+#if NGTPCI_MBUS > 0
+static pcireg_t gtpci_mbus_conf_read(void *, pcitag_t, int);
+static void gtpci_mbus_conf_write(void *, pcitag_t, int, pcireg_t);
+#endif
+static int gtpci_gpp_intr_map(struct pci_attach_args *, pci_intr_handle_t *);
+static const char *gtpci_gpp_intr_string(void *, pci_intr_handle_t);
+static const struct evcnt *gtpci_gpp_intr_evcnt(void *, pci_intr_handle_t);
+static void *gtpci_gpp_intr_establish(void *, pci_intr_handle_t, int, int (*)(void *), void *);
+static void gtpci_gpp_intr_disestablish(void *, void *);
+
+struct arm32_pci_chipset arm32_gtpci_chipset = {
+	NULL,	/* conf_v */
+	gtpci_attach_hook,
+	gtpci_bus_maxdevs,
+	gtpci_make_tag,
+	gtpci_decompose_tag,
+#if NGTPCI_MBUS > 0
+	gtpci_mbus_conf_read,		/* XXXX: always this functions */
+	gtpci_mbus_conf_write,
+#else
+	gtpci_conf_read,
+	gtpci_conf_write,
+#endif
+	NULL,	/* intr_v */
+	gtpci_gpp_intr_map,
+	gtpci_gpp_intr_string,
+	gtpci_gpp_intr_evcnt,
+	gtpci_gpp_intr_establish,
+	gtpci_gpp_intr_disestablish,
+#ifdef __HAVE_PCI_CONF_HOOK
+	gtpci_conf_hook,
+#endif
+};
+#endif
+
+#if NMVPEX > 0
+#if NMVPEX_MBUS > 0
+static pcireg_t mvpex_mbus_conf_read(void *, pcitag_t, int);
+#endif
+
+struct arm32_pci_chipset arm32_mvpex0_chipset = {
+	NULL,	/* conf_v */
+	mvpex_attach_hook,
+	mvpex_bus_maxdevs,
+	mvpex_make_tag,
+	mvpex_decompose_tag,
+#if NMVPEX_MBUS > 0
+	mvpex_mbus_conf_read,		/* XXXX: always this functions */
+#else
+	mvpex_conf_read,
+#endif
+	mvpex_conf_write,
+	NULL,	/* intr_v */
+	mvpex_intr_map,
+	mvpex_intr_string,
+	mvpex_intr_evcnt,
+	mvpex_intr_establish,
+	mvpex_intr_disestablish,
+#ifdef __HAVE_PCI_CONF_HOOK
+	mvpex_conf_hook,
+#endif
+};
+struct arm32_pci_chipset arm32_mvpex1_chipset = {
+	NULL,	/* conf_v */
+	mvpex_attach_hook,
+	mvpex_bus_maxdevs,
+	mvpex_make_tag,
+	mvpex_decompose_tag,
+#if NMVPEX_MBUS > 0
+	mvpex_mbus_conf_read,		/* XXXX: always this functions */
+#else
+	mvpex_conf_read,
+#endif
+	mvpex_conf_write,
+	NULL,	/* intr_v */
+	mvpex_intr_map,
+	mvpex_intr_string,
+	mvpex_intr_evcnt,
+	mvpex_intr_establish,
+	mvpex_intr_disestablish,
+#ifdef __HAVE_PCI_CONF_HOOK
+	mvpex_conf_hook,
+#endif
+};
+#endif
+
+
+void
+pci_conf_interrupt(pci_chipset_tag_t v, int bus, int dev, int pin, int swiz,
+		   int *iline)
+{
+
+	/* nothing */
+}
+
+
+#if NGTPCI > 0
+#if NGTPCI_MBUS > 0
+#define GTPCI_MBUS_CA		0x0c78	/* Configuration Address */
+#define GTPCI_MBUS_CD		0x0c7c	/* Configuration Data */
+
+static pcireg_t
+gtpci_mbus_conf_read(void *v, pcitag_t tag, int reg)
+{
+	struct gtpci_softc *sc = v;
+	const pcireg_t addr = tag | reg;
+
+	bus_space_write_4(sc->sc_iot, sc->sc_ioh, GTPCI_MBUS_CA,
+	    addr | GTPCI_CA_CONFIGEN);
+	if ((addr | GTPCI_CA_CONFIGEN) !=
+	    bus_space_read_4(sc->sc_iot, sc->sc_ioh, GTPCI_MBUS_CA))
+		return -1;
+
+	return bus_space_read_4(sc->sc_iot, sc->sc_ioh, GTPCI_MBUS_CD);
+}
+
+static void
+gtpci_mbus_conf_write(void *v, pcitag_t tag, int reg, pcireg_t data)
+{
+	struct gtpci_softc *sc = v;
+	pcireg_t addr = tag | (reg & 0xfc);
+
+	bus_space_write_4(sc->sc_iot, sc->sc_ioh, GTPCI_MBUS_CA,
+	    addr | GTPCI_CA_CONFIGEN);
+	if ((addr | GTPCI_CA_CONFIGEN) !=
+	    bus_space_read_4(sc->sc_iot, sc->sc_ioh, GTPCI_MBUS_CA))
+		return;
+
+	bus_space_write_4(sc->sc_iot, sc->sc_ioh, GTPCI_MBUS_CD, data);
+}
+#endif	/* NGTPCI_MBUS */
+
+/*
+ * We assume to use GPP interrupt as PCI interrupts.
+ *   pci_intr_map() shall returns number of GPP between 0 and 31.  However
+ *   returns 0xff, because we do not know the connected pin number for GPP
+ *   of your board.
+ *   pci_intr_string() shall returns string "gpp <num>".
+ *   pci_intr_establish() established interrupt in the pin of all GPP.
+ *   Moreover, the return value will be disregarded.  For instance, the
+ *   setting for interrupt is not done.
+ */
+
+/* ARGSUSED */
+static int
+gtpci_gpp_intr_map(struct pci_attach_args *pa, pci_intr_handle_t *ihp)
+{
+
+	*ihp = pa->pa_intrpin;
+	return 0;
+}
+
+/* ARGSUSED */
+static const char *
+gtpci_gpp_intr_string(void *v, pci_intr_handle_t pin)
+{
+	struct gtpci_softc *sc = v;
+	prop_array_t int2gpp;
+	prop_object_t gpp;
+	static char intrstr[8];
+
+	int2gpp = prop_dictionary_get(device_properties(sc->sc_dev), "int2gpp");
+	gpp = prop_array_get(int2gpp, pin);
+	sprintf(intrstr, "gpp %d", (int)prop_number_integer_value(gpp));
+
+	return intrstr;
+}
+
+/* ARGSUSED */
+static const struct evcnt *
+gtpci_gpp_intr_evcnt(void *v, pci_intr_handle_t pin)
+{
+
+	return NULL;
+}
+
+static void *
+gtpci_gpp_intr_establish(void *v, pci_intr_handle_t int_pin, int ipl,
+		         int (*intrhand)(void *), void *intrarg)
+{
+	struct gtpci_softc *sc = v;
+	prop_array_t int2gpp;
+	prop_object_t gpp;
+	int gpp_pin;
+
+	int2gpp = prop_dictionary_get(device_properties(sc->sc_dev), "int2gpp");
+	gpp = prop_array_get(int2gpp, int_pin);
+	gpp_pin = prop_number_integer_value(gpp);
+	return mvsocgpp_intr_establish(gpp_pin, ipl, 0, intrhand, intrarg);
+}
+
+static void
+gtpci_gpp_intr_disestablish(void *v, void *ih)
+{
+
+	mvsocgpp_intr_disestablish(ih);
+}
+#endif
+
+#if NMVPEX_MBUS > 0
+static pcireg_t
+mvpex_mbus_conf_read(void *v, pcitag_t tag, int reg)
+{
+	struct mvpex_softc *sc = v;
+	pcireg_t addr, data, pci_cs;
+	uint32_t stat;
+	int bus, dev, func, pexbus, pexdev;
+
+	mvpex_decompose_tag(v, tag, &bus, &dev, &func);
+
+	stat = bus_space_read_4(sc->sc_iot, sc->sc_ioh, MVPEX_STAT);
+	pexbus = MVPEX_STAT_PEXBUSNUM(stat);
+	pexdev = MVPEX_STAT_PEXDEVNUM(stat);
+	if (bus != pexbus || dev != pexdev)
+		if (stat & MVPEX_STAT_DLDOWN)
+			return -1;
+
+	if (bus == pexbus) {
+		if (pexdev == 0) {
+			if (dev != 1 && dev != pexdev)
+				return -1;
+		} else {
+			if (dev != 0 && dev != pexdev)
+				return -1;
+		}
+		if (func != 0)
+			return -1;
+	}
+
+	addr = ((reg & 0xf00) << 24)  | tag | (reg & 0xfc);
+
+#if defined(ORION)
+	/*
+	 * Guideline (GL# PCI Express-1) Erroneous Read Data on Configuration
+	 * This guideline is relevant for all devices except of the following
+	 * devices:
+	 *     88F5281-BO and above, and 88F5181L-A0 and above
+	 */
+	if ((bus != pexbus || dev != pexdev) &&
+	    !(sc->sc_model == MARVELL_ORION_2_88F5281 && sc->sc_rev == 1) &&
+	    !(sc->sc_model == MARVELL_ORION_1_88F5181 && sc->sc_rev == 8)) {
+
+		/* PCI-Express configuration read work-around */
+		/*
+		 * We will use one of the Punit (AHBToMbus) windows to
+		 * access the xbar and read the data from there
+		 *
+		 * Need to configure the 2 free Punit (AHB to MBus bridge)
+		 * address decoding windows:
+		 * Configure the flash Window to handle Configuration space
+		 * requests for PEX0/1:
+		 *
+		 * Configuration transactions from the CPU should write/read
+		 * the data to/from address of the form:
+		 *	addr[31:28]: 0x5 (for PEX0) or 0x6 (for PEX1)
+		 *	addr[27:24]: extended register number
+		 *	addr[23:16]: bus number
+		 *	addr[15:11]: device number
+		 *	addr[10: 8]: function number
+		 *	addr[ 7: 0]: register number
+		 */
+
+		struct mvsoc_softc *soc =
+		    device_private(device_parent(sc->sc_dev));;
+		bus_space_handle_t pcicfg_ioh;
+		uint32_t remapl, remaph, wc, pcicfg_addr, pcicfg_size;
+		int window, target, attr, base, size, s;
+		const int pex_pcicfg_tag =
+		    (sc->sc_model == MARVELL_ORION_1_88F1181) ?
+		    ORION_TAG_FLASH_CS : ORION_TAG_PEX0_MEM;
+
+		window = mvsoc_target(pex_pcicfg_tag,
+		    &target, &attr, &base, &size);
+		if (window >= nwindow) {
+			aprint_error_dev(sc->sc_dev,
+			    "can't read pcicfg space\n");
+			return -1;
+		}
+
+		s = splhigh();
+
+		remapl = remaph = 0;
+		if (window == 0 || window == 1) {
+			remapl = read_mlmbreg(MVSOC_MLMB_WRLR(window));
+			remaph = read_mlmbreg(MVSOC_MLMB_WRHR(window));
+		}
+
+		wc =
+		    MVSOC_MLMB_WCR_WINEN			|
+		    MVSOC_MLMB_WCR_ATTR(ORION_ATTR_PEX_CFG)	|
+		    MVSOC_MLMB_WCR_TARGET((soc->sc_addr + sc->sc_offset) >> 16);
+		if (sc->sc_model == MARVELL_ORION_1_88F1181) {
+			pcicfg_addr = base;
+			pcicfg_size = size;
+		} else if (sc->sc_model == MARVELL_ORION_1_88F5182) {
+#define PEX_PCICFG_RW_WA_BASE		0x50000000
+#define PEX_PCICFG_RW_WA_5182_BASE	0xf0000000
+#define PEX_PCICFG_RW_WA_SIZE		(16 * 1024 * 1024)
+			pcicfg_addr = PEX_PCICFG_RW_WA_5182_BASE;
+			pcicfg_size = PEX_PCICFG_RW_WA_SIZE;
+		} else {
+			pcicfg_addr = PEX_PCICFG_RW_WA_BASE;
+			pcicfg_size = PEX_PCICFG_RW_WA_SIZE;
+		}
+		write_mlmbreg(MVSOC_MLMB_WCR(window),
+		    wc | MVSOC_MLMB_WCR_SIZE(pcicfg_size));
+		write_mlmbreg(MVSOC_MLMB_WBR(window), pcicfg_addr);
+
+		if (window == 0 || window == 1) {
+			write_mlmbreg(MVSOC_MLMB_WRLR(window), pcicfg_addr);
+			write_mlmbreg(MVSOC_MLMB_WRHR(window), 0);
+		}
+
+		if (bus_space_map(sc->sc_iot, pcicfg_addr, pcicfg_size, 0,
+		    &pcicfg_ioh) == 0) {
+			data = bus_space_read_4(sc->sc_iot, pcicfg_ioh, addr);
+			bus_space_unmap(sc->sc_iot, pcicfg_ioh, pcicfg_size);
+		} else
+			data = -1;
+
+		write_mlmbreg(MVSOC_MLMB_WCR(window),
+		    MVSOC_MLMB_WCR_WINEN		|
+		    MVSOC_MLMB_WCR_ATTR(attr)		|
+		    MVSOC_MLMB_WCR_TARGET(target)	|
+		    MVSOC_MLMB_WCR_SIZE(size));
+		write_mlmbreg(MVSOC_MLMB_WBR(window), base);
+		if (window == 0 || window == 1) {
+			write_mlmbreg(MVSOC_MLMB_WRLR(window), remapl);
+			write_mlmbreg(MVSOC_MLMB_WRHR(window), remaph);
+		}
+
+		splx(s);
+#else
+	if (0) {
+#endif
+	} else {
+		bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVPEX_CA,
+		    addr | MVPEX_CA_CONFIGEN);
+		if ((addr | MVPEX_CA_CONFIGEN) !=
+		    bus_space_read_4(sc->sc_iot, sc->sc_ioh, MVPEX_CA))
+			return -1;
+
+		pci_cs = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
+		    PCI_COMMAND_STATUS_REG);
+		bus_space_write_4(sc->sc_iot, sc->sc_ioh,
+		    PCI_COMMAND_STATUS_REG, pci_cs | PCI_STATUS_MASTER_ABORT);
+
+		data = bus_space_read_4(sc->sc_iot, sc->sc_ioh, MVPEX_CD);
+	}
+
+	return data;
+}
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/arch/evbarm/marvell/marvell_machdep.c	Fri Oct 22 09:23:11 2010 +0000
@@ -0,0 +1,1001 @@
+/*	$NetBSD: marvell_machdep.c,v 1.1.4.2 2010/10/22 09:23:12 uebayasi Exp $ */
+/*
+ * Copyright (c) 2007, 2008, 2010 KIYOHARA Takashi
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: marvell_machdep.c,v 1.1.4.2 2010/10/22 09:23:12 uebayasi Exp $");
+
+#include "opt_evbarm_boardtype.h"
+#include "opt_ddb.h"
+#include "opt_pci.h"
+#include "opt_mvsoc.h"
+#include "com.h"
+#include "gtpci.h"
+#include "mvpex.h"
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/reboot.h>
+#include <sys/systm.h>
+#include <sys/termios.h>
+
+#include <prop/proplib.h>
+
+#include <dev/cons.h>
+#include <dev/md.h>
+
+#include <dev/marvell/marvellreg.h>
+#include <dev/marvell/marvellvar.h>
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
+
+#include <machine/autoconf.h>
+#include <machine/bootconfig.h>
+#include <machine/pci_machdep.h>
+
+#include <uvm/uvm_extern.h>
+
+#include <arm/db_machdep.h>
+#include <arm/undefined.h>
+#include <arm/arm32/machdep.h>
+
+#include <arm/marvell/mvsocreg.h>
+#include <arm/marvell/mvsocvar.h>
+#include <arm/marvell/orionreg.h>
+#include <arm/marvell/kirkwoodreg.h>
+#include <arm/marvell/mvsocgppvar.h>
+
+#include <evbarm/marvell/marvellreg.h>
+#include <evbarm/marvell/marvellvar.h>
+
+#include <ddb/db_extern.h>
+#include <ddb/db_sym.h>
+
+#include "ksyms.h"
+
+
+/* Kernel text starts 2MB in from the bottom of the kernel address space. */
+#define KERNEL_TEXT_BASE	(KERNEL_BASE + 0x00000000)
+#define KERNEL_VM_BASE		(KERNEL_BASE + 0x01000000)
+
+/*
+ * The range 0xc1000000 - 0xccffffff is available for kernel VM space
+ * Core-logic registers and I/O mappings occupy 0xfd000000 - 0xffffffff
+ */
+#define KERNEL_VM_SIZE		0x0c000000
+
+/*
+ * Address to call from cpu_reset() to reset the machine.
+ * This is machine architecture dependant as it varies depending
+ * on where the ROM appears when you turn the MMU off.
+ */
+
+u_int cpu_reset_address = 0xffff0000;
+
+/* Define various stack sizes in pages */
+#define IRQ_STACK_SIZE	1
+#define ABT_STACK_SIZE	1
+#ifdef IPKDB
+#define UND_STACK_SIZE	2
+#else
+#define UND_STACK_SIZE	1
+#endif
+
+BootConfig bootconfig;		/* Boot config storage */
+char *boot_args = NULL;
+
+vm_offset_t physical_start;
+vm_offset_t physical_freestart;
+vm_offset_t physical_freeend;
+vm_offset_t physical_end;
+u_int free_pages;
+int physmem = 0;
+
+/* Physical and virtual addresses for some global pages */
+pv_addr_t systempage;
+pv_addr_t irqstack;
+pv_addr_t undstack;
+pv_addr_t abtstack;
+pv_addr_t kernelstack;
+
+vm_offset_t msgbufphys;
+
+extern u_int data_abort_handler_address;
+extern u_int prefetch_abort_handler_address;
+extern u_int undefined_handler_address;
+
+extern char _end[];
+
+#define KERNEL_PT_SYS		0   /* Page table for mapping proc0 zero page */
+#define KERNEL_PT_KERNEL	1	/* Page table for mapping kernel */
+#define KERNEL_PT_KERNEL_NUM	4
+#define KERNEL_PT_VMDATA	(KERNEL_PT_KERNEL + KERNEL_PT_KERNEL_NUM)
+/* Page tables for mapping kernel VM */
+#define KERNEL_PT_VMDATA_NUM	4	/* start with 16MB of KVM */
+#define NUM_KERNEL_PTS		(KERNEL_PT_VMDATA + KERNEL_PT_VMDATA_NUM)
+
+pv_addr_t kernel_pt_table[NUM_KERNEL_PTS];
+
+/*
+ * Macros to translate between physical and virtual for a subset of the
+ * kernel address space.  *Not* for general use.
+ */
+#define KERNEL_BASE_PHYS	physical_start
+#define KERN_VTOPHYS(va) \
+	((paddr_t)((vaddr_t)va - KERNEL_BASE + KERNEL_BASE_PHYS))
+#define KERN_PHYSTOV(pa) \
+	((vaddr_t)((paddr_t)pa - KERNEL_BASE_PHYS + KERNEL_BASE))
+
+
+#include "com.h"
+#if NCOM > 0
+#include <dev/ic/comreg.h>
+#include <dev/ic/comvar.h>
+#endif
+
+#ifndef CONSPEED
+#define CONSPEED	B115200	/* It's a setting of the default of u-boot */
+#endif
+#ifndef CONMODE
+#define CONMODE ((TTYDEF_CFLAG & ~(CSIZE | CSTOPB | PARENB)) | CS8) /* 8N1 */
+
+int comcnspeed = CONSPEED;
+int comcnmode = CONMODE;
+#endif
+
+#include "opt_kgdb.h"
+#ifdef KGDB
+#include <sys/kgdb.h>
+#endif
+
+static void marvell_device_register(device_t, void *);
+#if NGTPCI > 0 || NMVPEX > 0
+static void marvell_startend_by_tag(int, uint64_t *, uint64_t *);
+#endif
+
+
+void
+cpu_reboot(int howto, char *bootstr)
+{
+
+	/*
+	 * If we are still cold then hit the air brakes
+	 * and crash to earth fast
+	 */
+	if (cold) {
+		doshutdownhooks();
+		printf("The operating system has halted.\r\n");
+		printf("Please press any key to reboot.\r\n");
+		cngetc();
+		printf("rebooting...\r\n");
+		cpu_reset();
+	}
+
+	/*
+	 * If RB_NOSYNC was not specified sync the discs.
+	 * Note: Unless cold is set to 1 here, syslogd will die during the
+	 * unmount.  It looks like syslogd is getting woken up only to find
+	 * that it cannot page part of the binary in as the filesystem has
+	 * been unmounted.
+	 */
+	if (!(howto & RB_NOSYNC))
+		bootsync();
+
+	/* Say NO to interrupts */
+	splhigh();
+
+	/* Do a dump if requested. */
+	if ((howto & (RB_DUMP | RB_HALT)) == RB_DUMP)
+		dumpsys();
+
+	/* Run any shutdown hooks */
+	doshutdownhooks();
+
+	/* Make sure IRQ's are disabled */
+	IRQdisable;
+
+	if (howto & RB_HALT) {
+		printf("The operating system has halted.\r\n");
+		printf("Please press any key to reboot.\r\n");
+		cngetc();
+	}
+
+	printf("rebooting...\r\n");
+	cpu_reset();
+
+	/*NOTREACHED*/
+}
+
+static inline
+pd_entry_t *
+read_ttb(void)
+{
+	long ttb;
+
+	__asm volatile("mrc	p15, 0, %0, c2, c0, 0" : "=r" (ttb));
+
+	return (pd_entry_t *)(ttb & ~((1<<14)-1));
+}
+
+/*
+ * Static device mappings. These peripheral registers are mapped at
+ * fixed virtual addresses very early in initarm() so that we can use
+ * them while booting the kernel, and stay at the same address
+ * throughout whole kernel's life time.
+ *
+ * We use this table twice; once with bootstrap page table, and once
+ * with kernel's page table which we build up in initarm().
+ *
+ * Since we map these registers into the bootstrap page table using
+ * pmap_devmap_bootstrap() which calls pmap_map_chunk(), we map
+ * registers segment-aligned and segment-rounded in order to avoid
+ * using the 2nd page tables.
+ */
+#define _A(a)	((a) & ~L1_S_OFFSET)
+#define _S(s)	(((s) + L1_S_SIZE - 1) & ~(L1_S_SIZE-1))
+
+static const struct pmap_devmap marvell_devmap[] = {
+	{
+		MARVELL_INTERREGS_VBASE,
+		_A(MARVELL_INTERREGS_PBASE),
+		_S(MARVELL_INTERREGS_SIZE),
+		VM_PROT_READ|VM_PROT_WRITE,
+		PTE_NOCACHE,
+	},
+
+	{ 0, 0, 0, 0, 0 }
+};
+
+#undef  _A
+#undef  _S
+
+
+/*
+ * u_int initarm(...)
+ *
+ * Initial entry point on startup. This gets called before main() is
+ * entered.
+ * It should be responsible for setting up everything that must be
+ * in place when main is called.
+ * This includes
+ *   Taking a copy of the boot configuration structure.
+ *   Initialising the physical console so characters can be printed.
+ *   Setting up page tables for the kernel
+ *   Relocating the kernel to the bottom of physical memory
+ */
+u_int
+initarm(void *arg)
+{
+	uint32_t target, attr, base, size;
+	u_int l1pagetable;
+	int loop, pt_index, cs, memtag = 0, iotag = 0, window;
+
+	/* map some peripheral registers */
+	pmap_devmap_bootstrap((vaddr_t)read_ttb(), marvell_devmap);
+
+	mvsoc_bootstrap(MARVELL_INTERREGS_VBASE);
+
+	/* Get ready for splfoo() */
+	switch (mvsoc_model()) {
+#ifdef ORION
+	case MARVELL_ORION_1_88F1181:
+	case MARVELL_ORION_1_88F5082:
+	case MARVELL_ORION_1_88F5180N:
+	case MARVELL_ORION_1_88F5181:
+	case MARVELL_ORION_1_88F5182:
+	case MARVELL_ORION_1_88F6082:
+	case MARVELL_ORION_1_88F6183:
+	case MARVELL_ORION_1_88W8660:
+	case MARVELL_ORION_2_88F1281:
+	case MARVELL_ORION_2_88F5281:
+		orion_intr_bootstrap();
+
+		memtag = ORION_TAG_PEX0_MEM;
+		iotag = ORION_TAG_PEX0_IO;
+		nwindow = ORION_MLMB_NWINDOW;
+		nremap = ORION_MLMB_NREMAP;
+
+		orion_getclks(MARVELL_INTERREGS_VBASE);
+		if (mvTclk == 166666667)	/* 166MHz */
+			mvTclk = 166664740;	/* ???? */
+		break;
+#endif	/* ORION */
+
+#ifdef KIRKWOOD
+	case MARVELL_KIRKWOOD_88F6180:
+	case MARVELL_KIRKWOOD_88F6192:
+	case MARVELL_KIRKWOOD_88F6281:
+		kirkwood_intr_bootstrap();
+
+		memtag = KIRKWOOD_TAG_PEX_MEM;
+		iotag = KIRKWOOD_TAG_PEX_IO;
+		nwindow = KIRKWOOD_MLMB_NWINDOW;
+		nremap = KIRKWOOD_MLMB_NREMAP;
+
+		kirkwood_getclks(MARVELL_INTERREGS_VBASE);
+		break;
+#endif	/* KIRKWOOD */
+
+#ifdef MV78XX0
+	case MARVELL_MV78XX0_MV78100:
+	case MARVELL_MV78XX0_MV78200:
+		mv78xx0_intr_bootstrap();
+
+		memtag = MV78XX0_TAG_PEX_MEM;
+		iotag = MV78XX0_TAG_PEX_IO;
+		nwindow = MV78XX0_MLMB_NWINDOW;
+		nremap = MV78XX0_MLMB_NREMAP;
+
+		mv78xx0_getclks(MARVELL_INTERREGS_VBASE);
+		break;
+#endif	/* MV78XX0 */
+
+	default:
+		/* We can't output console here yet... */
+		panic("unknown model...\n");
+
+		/* NOTREACHED */
+	}
+
+	/* Reset PCI-Express space to window register. */
+	window = mvsoc_target(memtag, &target, &attr, NULL, NULL);
+	write_mlmbreg(MVSOC_MLMB_WCR(window),
+	    MVSOC_MLMB_WCR_WINEN |
+	    MVSOC_MLMB_WCR_TARGET(target) |
+	    MVSOC_MLMB_WCR_ATTR(attr) |
+	    MVSOC_MLMB_WCR_SIZE(MARVELL_PEXMEM_SIZE));
+	write_mlmbreg(MVSOC_MLMB_WBR(window),
+	    MARVELL_PEXMEM_PBASE & MVSOC_MLMB_WBR_BASE_MASK);
+#ifdef PCI_NETBSD_CONFIGURE
+	if (window < nremap) {
+		write_mlmbreg(MVSOC_MLMB_WRLR(window),
+		    MARVELL_PEXMEM_PBASE & MVSOC_MLMB_WRLR_REMAP_MASK);
+		write_mlmbreg(MVSOC_MLMB_WRHR(window), 0);
+	}
+#endif
+	window = mvsoc_target(iotag, &target, &attr, NULL, NULL);
+	write_mlmbreg(MVSOC_MLMB_WCR(window),
+	    MVSOC_MLMB_WCR_WINEN |
+	    MVSOC_MLMB_WCR_TARGET(target) |
+	    MVSOC_MLMB_WCR_ATTR(attr) |
+	    MVSOC_MLMB_WCR_SIZE(MARVELL_PEXIO_SIZE));
+	write_mlmbreg(MVSOC_MLMB_WBR(window),
+	    MARVELL_PEXIO_PBASE & MVSOC_MLMB_WBR_BASE_MASK);
+#ifdef PCI_NETBSD_CONFIGURE
+	if (window < nremap) {
+		write_mlmbreg(MVSOC_MLMB_WRLR(window),
+		    MARVELL_PEXIO_PBASE & MVSOC_MLMB_WRLR_REMAP_MASK);
+		write_mlmbreg(MVSOC_MLMB_WRHR(window), 0);
+	}
+#endif
+
+	/*
+	 * Heads up ... Setup the CPU / MMU / TLB functions
+	 */
+	if (set_cpufuncs())
+		panic("cpu not recognized!");
+
+	/*
+	 * U-Boot doesn't use the virtual memory.
+	 *
+	 * Physical Address Range     Description
+	 * -----------------------    ----------------------------------
+	 * 0x00000000 - 0x0fffffff    SDRAM Bank 0 (max 256MB)
+	 * 0x10000000 - 0x1fffffff    SDRAM Bank 1 (max 256MB)
+	 * 0x20000000 - 0x2fffffff    SDRAM Bank 2 (max 256MB)
+	 * 0x30000000 - 0x3fffffff    SDRAM Bank 3 (max 256MB)
+	 * 0xf1000000 - 0xf10fffff    SoC Internal Registers
+	 */
+
+	cpu_domains((DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2)) | DOMAIN_CLIENT);
+
+	consinit();
+
+	/* Talk to the user */
+#define BDSTR(s)	_BDSTR(s)
+#define _BDSTR(s)	#s
+	printf("\nNetBSD/evbarm (" BDSTR(EVBARM_BOARDTYPE) ") booting ...\n");
+
+#ifdef VERBOSE_INIT_ARM
+	printf("initarm: Configuring system ...\n");
+#endif
+
+	bootconfig.dramblocks = 0;
+	physical_end = physmem = 0;
+	for (cs = MARVELL_TAG_SDRAM_CS0; cs <= MARVELL_TAG_SDRAM_CS3; cs++) {
+		mvsoc_target(cs, &target, &attr, &base, &size);
+		if (size == 0)
+			continue;
+
+		bootconfig.dram[bootconfig.dramblocks].address = base;
+		bootconfig.dram[bootconfig.dramblocks].pages = size / PAGE_SIZE;
+
+		if (base != physical_end)
+			panic("memory hole not support");
+
+		physical_end += size;
+		physmem += size / PAGE_SIZE;
+
+		bootconfig.dramblocks++;
+	}
+
+	/*
+	 * Set up the variables that define the availablilty of
+	 * physical memory.  For now, we're going to set
+	 * physical_freestart to 0xa0008000 (where the kernel
+	 * was loaded), and allocate the memory we need downwards.
+	 * If we get too close to the L1 table that we set up, we
+	 * will panic.  We will update physical_freestart and
+	 * physical_freeend later to reflect what pmap_bootstrap()
+	 * wants to see.
+	 *
+	 * XXX pmap_bootstrap() needs an enema.
+	 */
+	physical_start = bootconfig.dram[0].address;
+
+	/*
+	 * Our kernel is at the beginning of memory, so set our free space to
+	 * all the memory after the kernel.
+	 */
+	physical_freestart = KERN_VTOPHYS(round_page((vaddr_t)_end));
+	physical_freeend = physical_end;
+
+#ifdef VERBOSE_INIT_ARM
+	/* Tell the user about the memory */
+	printf("physmemory: %d pages at 0x%08lx -> 0x%08lx\n", physmem,
+	    physical_start, physical_end - 1);
+#endif
+
+	/*
+	 * Okay, the kernel starts 8kB in from the bottom of physical
+	 * memory.  We are going to allocate our bootstrap pages upwards
+	 * from physical_freestart.
+	 *
+	 * We need to allocate some fixed page tables to get the kernel
+	 * going.  We allocate one page directory and a number of page
+	 * tables and store the physical addresses in the kernel_pt_table
+	 * array.
+	 *
+	 * The kernel page directory must be on a 16K boundary.  The page
+	 * tables must be on 4K bounaries.  What we do is allocate the
+	 * page directory on the first 16K boundary that we encounter, and
+	 * the page tables on 4K boundaries otherwise.  Since we allocate
+	 * at least 3 L2 page tables, we are guaranteed to encounter at
+	 * least one 16K aligned region.
+	 */
+
+#ifdef VERBOSE_INIT_ARM
+	printf("Allocating page tables\n");
+#endif
+
+	free_pages = (physical_freeend - physical_freestart) / PAGE_SIZE;
+
+#ifdef VERBOSE_INIT_ARM
+	printf("freestart = 0x%08lx, free_pages = %d (0x%08x)\n",
+	    physical_freestart, free_pages, free_pages);
+#endif
+
+	/*
+	 * Define a macro to simplify memory allocation.  As we allocate the
+	 * memory, make sure that we don't walk over our temporary first level
+	 * translation table.
+	 */
+#define valloc_pages(var, np)						\
+	(var).pv_pa = physical_freestart;				\
+	physical_freestart += ((np) * PAGE_SIZE);			\
+	if (physical_freestart > (physical_freeend - L1_TABLE_SIZE))	\
+		panic("initarm: out of memory");			\
+	free_pages -= (np);						\
+	(var).pv_va = KERN_PHYSTOV((var).pv_pa);			\
+	memset((char *)(var).pv_va, 0, ((np) * PAGE_SIZE));
+
+	pt_index = 0;
+	kernel_l1pt.pv_pa = 0;
+	kernel_l1pt.pv_va = 0;
+	for (loop = 0; loop <= NUM_KERNEL_PTS; ++loop) {
+		/* Are we 16KB aligned for an L1 ? */
+		if ((physical_freestart & (L1_TABLE_SIZE - 1)) == 0 &&
+		    kernel_l1pt.pv_pa == 0) {
+			valloc_pages(kernel_l1pt, L1_TABLE_SIZE / PAGE_SIZE);
+		} else {
+			valloc_pages(kernel_pt_table[pt_index],
+			    L2_TABLE_SIZE / PAGE_SIZE);
+			++pt_index;
+		}
+	}
+
+	/* This should never be able to happen but better confirm that. */
+	if (!kernel_l1pt.pv_pa ||
+	    (kernel_l1pt.pv_pa & (L1_TABLE_SIZE - 1)) != 0)
+		panic("initarm: Failed to align the kernel page directory");
+
+	/*
+	 * Allocate a page for the system page mapped to V0x00000000
+	 * This page will just contain the system vectors and can be
+	 * shared by all processes.
+	 */
+	valloc_pages(systempage, 1);
+	systempage.pv_va = 0x00000000;
+
+	/* Allocate stacks for all modes */
+	valloc_pages(irqstack, IRQ_STACK_SIZE);
+	valloc_pages(abtstack, ABT_STACK_SIZE);
+	valloc_pages(undstack, UND_STACK_SIZE);
+	valloc_pages(kernelstack, UPAGES);
+
+#ifdef VERBOSE_INIT_ARM
+	printf("IRQ stack: p0x%08lx v0x%08lx\n", irqstack.pv_pa,
+	    irqstack.pv_va);
+	printf("ABT stack: p0x%08lx v0x%08lx\n", abtstack.pv_pa,
+	    abtstack.pv_va);
+	printf("UND stack: p0x%08lx v0x%08lx\n", undstack.pv_pa,
+	    undstack.pv_va);
+	printf("SVC stack: p0x%08lx v0x%08lx\n", kernelstack.pv_pa,
+	    kernelstack.pv_va);
+#endif
+
+	/* Allocate the message buffer. */
+	{
+		pv_addr_t msgbuf;
+
+		valloc_pages(msgbuf, round_page(MSGBUFSIZE) / PAGE_SIZE);
+		msgbufphys = msgbuf.pv_pa;
+	}
+
+	/*
+	 * Ok we have allocated physical pages for the primary kernel
+	 * page tables
+	 */
+
+#ifdef VERBOSE_INIT_ARM
+	printf("Creating L1 page table at 0x%08lx\n", kernel_l1pt.pv_pa);
+#endif
+
+	/*
+	 * Now we start construction of the L1 page table
+	 * We start by mapping the L2 page tables into the L1.
+	 * This means that we can replace L1 mappings later on if necessary
+	 */
+	l1pagetable = kernel_l1pt.pv_va;
+
+	/* Map the L2 pages tables in the L1 page table */
+	pmap_link_l2pt(l1pagetable, 0x00000000,
+	    &kernel_pt_table[KERNEL_PT_SYS]);
+	for (loop = 0; loop < KERNEL_PT_KERNEL_NUM; loop++)
+		pmap_link_l2pt(l1pagetable, KERNEL_BASE + loop * 0x00400000,
+		    &kernel_pt_table[KERNEL_PT_KERNEL + loop]);
+	for (loop = 0; loop < KERNEL_PT_VMDATA_NUM; loop++)
+		pmap_link_l2pt(l1pagetable, KERNEL_VM_BASE + loop * 0x00400000,
+		    &kernel_pt_table[KERNEL_PT_VMDATA + loop]);
+
+	/* update the top of the kernel VM */
+	pmap_curmaxkvaddr =
+	    KERNEL_VM_BASE + (KERNEL_PT_VMDATA_NUM * 0x00400000);
+
+#ifdef VERBOSE_INIT_ARM
+	printf("Mapping kernel\n");
+#endif
+
+	/* Now we fill in the L2 pagetable for the kernel static code/data */
+	{
+		extern char etext[], _end[];
+		size_t textsize = (uintptr_t)etext - KERNEL_TEXT_BASE;
+		size_t totalsize = (uintptr_t)_end - KERNEL_TEXT_BASE;
+		u_int logical;
+
+		textsize = (textsize + PGOFSET) & ~PGOFSET;
+		totalsize = (totalsize + PGOFSET) & ~PGOFSET;
+
+		logical = 0x00000000;	/* offset of kernel in RAM */
+
+		logical += pmap_map_chunk(l1pagetable, KERNEL_BASE + logical,
+		    physical_start + logical, textsize,
+		    VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE);
+		logical += pmap_map_chunk(l1pagetable, KERNEL_BASE + logical,
+		    physical_start + logical, totalsize - textsize,
+		    VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE);
+	}
+
+#ifdef VERBOSE_INIT_ARM
+	printf("Constructing L2 page tables\n");
+#endif
+
+	/* Map the stack pages */
+	pmap_map_chunk(l1pagetable, irqstack.pv_va, irqstack.pv_pa,
+	    IRQ_STACK_SIZE * PAGE_SIZE, VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE);
+	pmap_map_chunk(l1pagetable, abtstack.pv_va, abtstack.pv_pa,
+	    ABT_STACK_SIZE * PAGE_SIZE, VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE);
+	pmap_map_chunk(l1pagetable, undstack.pv_va, undstack.pv_pa,
+	    UND_STACK_SIZE * PAGE_SIZE, VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE);
+	pmap_map_chunk(l1pagetable, kernelstack.pv_va, kernelstack.pv_pa,
+	    UPAGES * PAGE_SIZE, VM_PROT_READ | VM_PROT_WRITE, PTE_CACHE);
+
+	pmap_map_chunk(l1pagetable, kernel_l1pt.pv_va, kernel_l1pt.pv_pa,
+	    L1_TABLE_SIZE, VM_PROT_READ | VM_PROT_WRITE, PTE_PAGETABLE);
+
+	for (loop = 0; loop < NUM_KERNEL_PTS; ++loop)
+		pmap_map_chunk(l1pagetable, kernel_pt_table[loop].pv_va,
+		    kernel_pt_table[loop].pv_pa, L2_TABLE_SIZE,
+		    VM_PROT_READ|VM_PROT_WRITE, PTE_PAGETABLE);
+
+	/* Map the vector page. */
+	pmap_map_entry(l1pagetable, ARM_VECTORS_LOW, systempage.pv_pa,
+	    VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE);
+
+	/*
+	 * Map integrated peripherals at same address in first level page
+	 * table so that we can continue to use console.
+	 */
+	pmap_devmap_bootstrap(l1pagetable, marvell_devmap);
+
+	/*
+	 * Now we have the real page tables in place so we can switch to them.
+	 * Once this is done we will be running with the REAL kernel page
+	 * tables.
+	 */
+
+	/* Switch tables */
+#ifdef VERBOSE_INIT_ARM
+	printf("switching to new L1 page table  @%#lx...", kernel_l1pt.pv_pa);
+#endif
+
+	cpu_setttb(kernel_l1pt.pv_pa);
+	cpu_tlb_flushID();
+	cpu_domains(DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2));
+
+	/*
+	 * Moved from cpu_startup() as data_abort_handler() references
+	 * this during uvm init.
+	 */
+	uvm_lwp_setuarea(&lwp0, kernelstack.pv_va);
+
+#ifdef VERBOSE_INIT_ARM
+	printf("bootstrap done.\n");
+#endif
+
+	arm32_vector_init(ARM_VECTORS_LOW, ARM_VEC_ALL);
+
+	/*
+	 * Pages were allocated during the secondary bootstrap for the
+	 * stacks for different CPU modes.
+	 * We must now set the r13 registers in the different CPU modes to
+	 * point to these stacks.
+	 * Since the ARM stacks use STMFD etc. we must set r13 to the top end
+	 * of the stack memory.
+	 */
+#ifdef VERBOSE_INIT_ARM
+	printf("init subsystems: stacks ");
+#endif
+
+	set_stackptr(PSR_IRQ32_MODE,
+	    irqstack.pv_va + IRQ_STACK_SIZE * PAGE_SIZE);
+	set_stackptr(PSR_ABT32_MODE,
+	    abtstack.pv_va + ABT_STACK_SIZE * PAGE_SIZE);
+	set_stackptr(PSR_UND32_MODE,
+	    undstack.pv_va + UND_STACK_SIZE * PAGE_SIZE);
+
+	/*
+	 * Well we should set a data abort handler.
+	 * Once things get going this will change as we will need a proper
+	 * handler.
+	 * Until then we will use a handler that just panics but tells us
+	 * why.
+	 * Initialisation of the vectors will just panic on a data abort.
+	 * This just fills in a slightly better one.
+	 */
+#ifdef VERBOSE_INIT_ARM
+	printf("vectors ");
+#endif
+	data_abort_handler_address = (u_int)data_abort_handler;
+	prefetch_abort_handler_address = (u_int)prefetch_abort_handler;
+	undefined_handler_address = (u_int)undefinedinstruction_bounce;
+
+	/* Initialise the undefined instruction handlers */
+#ifdef VERBOSE_INIT_ARM
+	printf("undefined ");
+#endif
+	undefined_init();
+
+	/* Load memory into UVM. */
+#ifdef VERBOSE_INIT_ARM
+	printf("page ");
+#endif
+	uvm_setpagesize();	/* initialize PAGE_SIZE-dependent variables */
+	uvm_page_physload(atop(physical_freestart), atop(physical_freeend),
+	    atop(physical_freestart), atop(physical_freeend),
+	    VM_FREELIST_DEFAULT);
+
+	/* Boot strap pmap telling it where the kernel page table is */
+#ifdef VERBOSE_INIT_ARM
+	printf("pmap ");
+#endif
+	pmap_bootstrap(KERNEL_VM_BASE, KERNEL_VM_BASE + KERNEL_VM_SIZE);
+
+#ifdef VERBOSE_INIT_ARM
+	printf("done.\n");
+#endif
+
+#ifdef __HAVE_MEMORY_DISK__
+	md_root_setconf(memory_disk, sizeof memory_disk);
+#endif
+
+#ifdef BOOTHOWTO
+	boothowto |= BOOTHOWTO;
+#endif
+
+#ifdef KGDB
+	if (boothowto & RB_KDB) {
+		kgdb_debug_init = 1;
+		kgdb_connect(1);
+	}
+#endif
+
+#if NKSYMS || defined(DDB) || defined(LKM)
+	/* Firmware doesn't load symbols. */
+	ksyms_init();
+#endif
+
+#ifdef DDB
+	db_machine_init();
+	if (boothowto & RB_KDB)
+		Debugger();
+#endif
+
+	/* we've a specific device_register routine */
+	evbarm_device_register = marvell_device_register;
+
+	/* We return the new stack pointer address */
+	return(kernelstack.pv_va + USPACE_SVC_STACK_TOP);
+}
+
+void
+consinit(void)
+{
+	static int consinit_called = 0;
+
+	if (consinit_called != 0)
+		return;
+
+	consinit_called = 1;
+
+#if NCOM > 0
+	{
+		extern int mvuart_cnattach(bus_space_tag_t, bus_addr_t, int,
+					   uint32_t, int);
+
+		if (mvuart_cnattach(&mvsoc_bs_tag, 
+		    MARVELL_INTERREGS_VBASE + MVSOC_COM0_BASE,
+		    comcnspeed, mvTclk, comcnmode))
+			panic("can't init serial console");
+	}
+#else
+	panic("serial console not configured");
+#endif
+}
+
+
+static void
+marvell_device_register(device_t dev, void *aux)
+{
+	prop_dictionary_t dict = device_properties(dev);
+
+#if NCOM > 0
+	if (device_is_a(dev, "com") &&
+	    device_is_a(device_parent(dev), "mvsoc"))
+		prop_dictionary_set_uint32(dict, "frequency", mvTclk);
+#endif
+	if (device_is_a(dev, "gtidmac")) {
+		prop_dictionary_set_uint32(dict,
+		    "dmb_speed", mvTclk * sizeof(uint32_t));	/* XXXXXX */
+		prop_dictionary_set_uint32(dict,
+		    "xore-irq-begin", ORION_IRQ_XOR0);
+	}
+#if NGTPCI > 0 && defined(ORION)
+	if (device_is_a(dev, "gtpci")) {
+		extern struct bus_space
+		    orion_pci_io_bs_tag, orion_pci_mem_bs_tag;
+		extern struct arm32_pci_chipset arm32_gtpci_chipset;
+
+		prop_data_t io_bs_tag, mem_bs_tag, pc;
+		prop_array_t int2gpp;
+		prop_number_t gpp;
+		uint64_t start, end;
+		int i, j;
+		static struct {
+			const char *boardtype;
+			int pin[PCI_INTERRUPT_PIN_MAX];
+		} hints[] = {
+			{ "kuronas_x4",
+			    { 11, PCI_INTERRUPT_PIN_NONE } },
+
+			{ NULL,
+			    { PCI_INTERRUPT_PIN_NONE } },
+		};
+
+		arm32_gtpci_chipset.pc_conf_v = device_private(dev);
+		arm32_gtpci_chipset.pc_intr_v = device_private(dev);
+
+		io_bs_tag = prop_data_create_data_nocopy(
+		    &orion_pci_io_bs_tag, sizeof(struct bus_space));
+		KASSERT(io_bs_tag != NULL);
+		prop_dictionary_set(dict, "io-bus-tag", io_bs_tag);
+		prop_object_release(io_bs_tag);
+		mem_bs_tag = prop_data_create_data_nocopy(
+		    &orion_pci_mem_bs_tag, sizeof(struct bus_space));
+		KASSERT(mem_bs_tag != NULL);
+		prop_dictionary_set(dict, "mem-bus-tag", mem_bs_tag);
+		prop_object_release(mem_bs_tag);
+
+		pc = prop_data_create_data_nocopy(&arm32_gtpci_chipset,
+		    sizeof(struct arm32_pci_chipset));
+		KASSERT(pc != NULL);
+		prop_dictionary_set(dict, "pci-chipset", pc);
+		prop_object_release(pc);
+
+		marvell_startend_by_tag(ORION_TAG_PCI_IO, &start, &end);
+		prop_dictionary_set_uint64(dict, "iostart", start);
+		prop_dictionary_set_uint64(dict, "ioend", end);
+		marvell_startend_by_tag(ORION_TAG_PCI_MEM, &start, &end);
+		prop_dictionary_set_uint64(dict, "memstart", start);
+		prop_dictionary_set_uint64(dict, "memend", end);
+		prop_dictionary_set_uint32(dict,
+		    "cache-line-size", arm_dcache_align);
+
+		/* Setup the hint for interrupt-pin. */
+#define BDSTR(s)		_BDSTR(s)
+#define _BDSTR(s)		#s
+#define THIS_BOARD(str)		(strcmp(str, BDSTR(EVBARM_BOARDTYPE)) == 0)
+		for (i = 0; hints[i].boardtype != NULL; i++)
+			if (THIS_BOARD(hints[i].boardtype))
+				break;
+		if (hints[i].boardtype == NULL)
+			return;
+
+		int2gpp =
+		    prop_array_create_with_capacity(PCI_INTERRUPT_PIN_MAX + 1);
+
+		/* first set dummy */
+		gpp = prop_number_create_integer(0);
+		prop_array_add(int2gpp, gpp);
+		prop_object_release(gpp);
+
+		for (j = 0; hints[i].pin[j] != PCI_INTERRUPT_PIN_NONE; j++) {
+			gpp = prop_number_create_integer(hints[i].pin[j]);
+			prop_array_add(int2gpp, gpp);
+			prop_object_release(gpp);
+		}
+		prop_dictionary_set(dict, "int2gpp", int2gpp);
+	}
+#endif	/* NGTPCI > 0 && defined(ORION) */
+#if NMVPEX > 0
+	if (device_is_a(dev, "mvpex")) {
+#ifdef ORION
+		extern struct bus_space
+		    orion_pex0_io_bs_tag, orion_pex0_mem_bs_tag,
+		    orion_pex1_io_bs_tag, orion_pex1_mem_bs_tag;
+#endif
+#ifdef KIRKWOOD
+		extern struct bus_space
+		    kirkwood_pex_io_bs_tag, kirkwood_pex_mem_bs_tag;
+#endif
+		extern struct arm32_pci_chipset
+		    arm32_mvpex0_chipset, arm32_mvpex1_chipset;
+
+		struct marvell_attach_args *mva = aux;
+		struct bus_space *mvpex_io_bs_tag, *mvpex_mem_bs_tag;
+		struct arm32_pci_chipset *arm32_mvpex_chipset;
+		prop_data_t io_bs_tag, mem_bs_tag, pc;
+		uint64_t start, end;
+		int iotag, memtag;
+
+		switch (mvsoc_model()) {
+#ifdef ORION
+		case MARVELL_ORION_1_88F5180N:
+		case MARVELL_ORION_1_88F5181:
+		case MARVELL_ORION_1_88F5182:
+		case MARVELL_ORION_1_88W8660:
+		case MARVELL_ORION_2_88F5281:
+			if (mva->mva_offset == MVSOC_PEX_BASE) {
+				mvpex_io_bs_tag = &orion_pex0_io_bs_tag;
+				mvpex_mem_bs_tag = &orion_pex0_mem_bs_tag;
+				arm32_mvpex_chipset = &arm32_mvpex0_chipset;
+				iotag = ORION_TAG_PEX0_IO;
+				memtag = ORION_TAG_PEX0_MEM;
+			} else {
+				mvpex_io_bs_tag = &orion_pex1_io_bs_tag;
+				mvpex_mem_bs_tag = &orion_pex1_mem_bs_tag;
+				arm32_mvpex_chipset = &arm32_mvpex1_chipset;
+				iotag = ORION_TAG_PEX1_IO;
+				memtag = ORION_TAG_PEX1_MEM;
+			}
+			break;
+#endif
+
+#ifdef KIRKWOOD
+		case MARVELL_KIRKWOOD_88F6180:
+		case MARVELL_KIRKWOOD_88F6192:
+		case MARVELL_KIRKWOOD_88F6281:
+			mvpex_io_bs_tag = &kirkwood_pex_io_bs_tag;
+			mvpex_mem_bs_tag = &kirkwood_pex_mem_bs_tag;
+			arm32_mvpex_chipset = &arm32_mvpex0_chipset;
+			iotag = KIRKWOOD_TAG_PEX_IO;
+			memtag = KIRKWOOD_TAG_PEX_MEM;
+			break;
+#endif
+
+		default:
+			return;
+		}
+
+		arm32_mvpex_chipset->pc_conf_v = device_private(dev);
+		arm32_mvpex_chipset->pc_intr_v = device_private(dev);
+
+		io_bs_tag = prop_data_create_data_nocopy(
+		    mvpex_io_bs_tag, sizeof(struct bus_space));
+		KASSERT(io_bs_tag != NULL);
+		prop_dictionary_set(dict, "io-bus-tag", io_bs_tag);
+		prop_object_release(io_bs_tag);
+		mem_bs_tag = prop_data_create_data_nocopy(
+		    mvpex_mem_bs_tag, sizeof(struct bus_space));
+		KASSERT(mem_bs_tag != NULL);
+		prop_dictionary_set(dict, "mem-bus-tag", mem_bs_tag);
+		prop_object_release(mem_bs_tag);
+
+		pc = prop_data_create_data_nocopy(arm32_mvpex_chipset,
+		    sizeof(struct arm32_pci_chipset));
+		KASSERT(pc != NULL);
+		prop_dictionary_set(dict, "pci-chipset", pc);
+		prop_object_release(pc);
+
+		marvell_startend_by_tag(iotag, &start, &end);
+		prop_dictionary_set_uint64(dict, "iostart", start);
+		prop_dictionary_set_uint64(dict, "ioend", end);
+		marvell_startend_by_tag(memtag, &start, &end);
+		prop_dictionary_set_uint64(dict, "memstart", start);
+		prop_dictionary_set_uint64(dict, "memend", end);
+		prop_dictionary_set_uint32(dict,
+		    "cache-line-size", arm_dcache_align);
+	}
+#endif
+}
+
+#if NGTPCI > 0 || NMVPEX > 0
+static void
+marvell_startend_by_tag(int tag, uint64_t *start, uint64_t *end)
+{
+	uint32_t base, size;
+	int win;
+
+	win = mvsoc_target(tag, NULL, NULL, &base, &size);
+	if (size != 0) {
+		if (win < nremap)
+			*start = read_mlmbreg(MVSOC_MLMB_WRLR(win)) |
+			    ((read_mlmbreg(MVSOC_MLMB_WRHR(win)) << 16) << 16);
+		else
+			*start = base;
+		*end = *start + size - 1;
+	}
+}
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/arch/evbarm/marvell/marvell_start.S	Fri Oct 22 09:23:11 2010 +0000
@@ -0,0 +1,206 @@
+/*	$NetBSD: marvell_start.S,v 1.1.4.2 2010/10/22 09:23:12 uebayasi Exp $ */
+/*
+ * Copyright (C) 2005, 2006 WIDE Project and SOUM Corporation.
+ * All rights reserved.
+ *
+ * Written by Takashi Kiyohara and Susumu Miki for WIDE Project and SOUM
+ * Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the name of SOUM Corporation
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT and SOUM CORPORATION ``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 PROJECT AND SOUM CORPORATION
+ * 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.
+ */
+/*
+ * Copyright (c) 2002, 2003  Genetec Corporation.  All rights reserved.
+ * Written by Hiroyuki Bessho for Genetec Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of Genetec Corporation may not be used to endorse or
+ *    promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY GENETEC CORPORATION ``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 GENETEC CORPORATION
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "opt_cputypes.h"
+#include <machine/asm.h>
+#include <arm/armreg.h>
+#include <arm/arm32/pte.h>
+#include <arm/arm32/pmap.h>		/* for PMAP_DOMAIN_KERNEL */
+
+#ifndef SDRAM_START
+#define SDRAM_START	0x00000000
+#endif
+
+/*
+ * CPWAIT -- Canonical method to wait for CP15 update.
+ * NOTE: Clobbers the specified temp reg.
+ * copied from arm/arm/cpufunc_asm_xscale.S
+ * XXX: better be in a common header file.
+ */
+#define	CPWAIT_BRANCH							 \
+	sub	pc, pc, #4
+
+#define	CPWAIT(tmp)							 \
+	mrc	p15, 0, tmp, c2, c0, 0	/* arbitrary read of CP15 */	;\
+	mov	tmp, tmp		/* wait for it to complete */	;\
+	CPWAIT_BRANCH			/* branch to next insn */
+
+/*
+ * Kernel start routine for Marvell boards
+ * this code is excuted at the very first after the kernel is loaded
+ * by U-Boot.
+ */
+	.text
+
+	.global	_C_LABEL(marvell_start)
+_C_LABEL(marvell_start):
+	/* The Loader for Marvell board is u-boot.  it's running on RAM */
+	/*
+	 *  Kernel is loaded in SDRAM (0x00200000..), and is expected to run
+	 *  in VA 0xc0200000..
+	 */
+
+#ifdef CPU_SHEEVA
+	mrc	p15, 0, r4, c0, c0, 0
+	and	r4, r4, #CPU_ID_CPU_MASK
+	adr	r5, sheeva_cores_start
+	adr	r6, sheeva_cores_end
+1:
+	cmp	r5, r6
+	beq	2f
+	ldmia	r5!, {r7}
+	cmp	r4, r7
+	bne	1b
+
+	/* Make sure L2 is disabled */
+	mrc	p15, 1, r0, c15, c1, 0	@ Get Marvell Extra Features Register
+	bic	r0, r0, #0x00400000	@ disable L2 cache
+	mcr	p15, 1, r0, c15, c1, 0
+2:
+#endif
+	/* save u-boot's args */
+	adr	r4, u_boot_args
+	nop
+	nop
+	nop
+	stmia	r4!, {r0, r1, r2, r3}
+	nop
+	nop
+	nop
+
+	/* build page table from scratch */
+	ldr	r0, Lstartup_pagetable		/* pagetable */
+	adr	r4, mmu_init_table
+	b	3f
+
+2:
+	str	r3, [r0, r2]
+	add	r2, r2, #4
+	add	r3, r3, #(L1_S_SIZE)
+	adds	r1, r1, #-1
+	bhi	2b
+3:
+	ldmia	r4!, {r1, r2, r3}	/* # of sections, VA, PA|attr */
+	cmp	r1, #0
+	bne	2b
+
+	mcr	p15, 0, r0, c2, c0, 0	/* Set TTB */
+	mcr	p15, 0, r0, c8, c7, 0	/* Flush TLB */
+	mov	r0, #0
+	mcr	p15, 0, r0, c7, c6, 0	/* Invalidate D cache */
+	mcr	p15, 0, r0, c7, c10, 4	/* Drain write-buffer */
+
+	/* Ensure safe Translation Table. */
+
+	/* Set the Domain Access register.  Very important! */
+        mov     r0, #((DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2)) | DOMAIN_CLIENT)
+	mcr	p15, 0, r0, c3, c0, 0
+
+	/* Enable MMU */
+	mrc	p15, 0, r0, c1, c0, 0
+	orr	r0, r0, #CPU_CONTROL_SYST_ENABLE
+	orr	r0, r0, #CPU_CONTROL_MMU_ENABLE
+	mcr	p15, 0, r0, c1, c0, 0
+	CPWAIT(r0)
+
+	/* Jump to kernel code in TRUE VA */
+	adr	r0, Lstart
+	ldr	pc, [r0]
+
+Lstart:
+	.word	start
+
+#ifndef STARTUP_PAGETABLE_ADDR
+#define STARTUP_PAGETABLE_ADDR 0x00004000	/* aligned 16kByte */
+#endif
+Lstartup_pagetable:
+	.word	STARTUP_PAGETABLE_ADDR
+
+	.globl	_C_LABEL(u_boot_args)
+u_boot_args:
+	.space	16			/* r0, r1, r2, r3 */
+
+#ifdef CPU_SHEEVA
+sheeva_cores_start:
+	.word	CPU_ID_MV88SV131
+	.word	CPU_ID_MV88FR571_VD		/* Is it Sheeva? */
+sheeva_cores_end:
+#endif
+
+#define MMU_INIT(va,pa,n_sec,attr) \
+	.word	n_sec					    ; \
+	.word	4 * ((va) >> L1_S_SHIFT)		    ; \
+	.word	(pa) | (attr)				    ;
+
+mmu_init_table:
+	/* fill all table VA==PA */
+	MMU_INIT(0x00000000, 0x00000000,
+	    1 << (32 - L1_S_SHIFT), L1_TYPE_S | L1_S_AP(AP_KRW))
+
+	/* map SDRAM VA==PA, WT cacheable */
+	MMU_INIT(SDRAM_START, SDRAM_START,
+	    128, L1_TYPE_S | L1_S_C | L1_S_AP(AP_KRW))
+
+	/* map VA 0xc0000000..0xc7ffffff to PA 0x00000000..0x07ffffff */
+	MMU_INIT(0xc0000000, SDRAM_START,
+	    128, L1_TYPE_S | L1_S_C | L1_S_AP(AP_KRW))
+
+	.word	0			/* end of table */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/arch/evbarm/marvell/marvellreg.h	Fri Oct 22 09:23:11 2010 +0000
@@ -0,0 +1,42 @@
+/*	$NetBSD: marvellreg.h,v 1.1.4.2 2010/10/22 09:23:12 uebayasi Exp $  */
+/*
+ * Copyright (c) 2007 KIYOHARA Takashi
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _EVBARM_MARVELLREG_H_
+#define _EVBARM_MARVELLREG_H_
+
+
+/*
+ * Logical mapping for onboard/integrated peripherals
+ * that are used while bootstrapping.
+ */
+#define MARVELL_PEXMEM_PBASE			0xe0000000
+#define MARVELL_PEXMEM_SIZE			0x08000000
+#define MARVELL_INTERREGS_PBASE			0xf1000000
+#define MARVELL_INTERREGS_SIZE			0x00100000
+#define MARVELL_PEXIO_PBASE			0xf2000000
+#define MARVELL_PEXIO_SIZE			0x00100000
+
+#endif /* _EVBARM_MARVELLREG_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/arch/evbarm/marvell/marvellvar.h	Fri Oct 22 09:23:11 2010 +0000
@@ -0,0 +1,40 @@
+/*	$NetBSD: marvellvar.h,v 1.1.4.2 2010/10/22 09:23:12 uebayasi Exp $ */
+/*
+ * Copyright (c) 2007 KIYOHARA Takashi
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _EVBARM_MARVELLVAR_H_
+#define _EVBARM_MARVELLVAR_H_
+
+/*
+ * Logical mapping for onboard/integrated peripherals
+ * that are used while bootstrapping.
+ *
+ * u-boot sets Internal Registers to 0xf1000000.
+ */
+#define MARVELL_PEXMEM_VBASE			0xe0000000
+#define MARVELL_INTERREGS_VBASE			0xf1000000
+#define MARVELL_PEXIO_VBASE			0xf2000000
+
+#endif /* _EVBARM_MARVELLVAR_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/dev/filemon/filemon.c	Fri Oct 22 09:23:11 2010 +0000
@@ -0,0 +1,366 @@
+/*
+ * Copyright (c) 2010, Juniper Networks, Inc.
+ *
+ * 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 COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: filemon.c,v 1.1.4.2 2010/10/22 09:23:12 uebayasi Exp $");
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/conf.h>
+#include <sys/file.h>
+#include <sys/filedesc.h>
+#include <sys/systm.h>
+#include <sys/buf.h>
+#include <sys/fcntl.h>
+#include <sys/rwlock.h>
+#include <sys/condvar.h>
+#include <sys/lwp.h>
+#include <sys/proc.h>
+#include <sys/kmem.h>
+#include <sys/syslog.h>
+
+#include "filemon.h"
+
+MODULE(MODULE_CLASS_DRIVER, filemon, NULL);
+
+static dev_type_open(filemon_open);
+
+static struct cdevsw filemon_cdevsw = {
+	.d_open = filemon_open,
+	.d_flag = D_MPSAFE,
+	.d_close = noclose,
+	.d_read = noread,
+	.d_write = nowrite,
+	.d_ioctl = noioctl,
+	.d_stop = nostop,
+	.d_tty = notty,
+	.d_poll = nopoll,
+	.d_mmap = nommap,
+	.d_kqfilter = nokqfilter,
+};
+
+static int filemon_ioctl(struct file *, u_long, void *);
+static int filemon_close(struct file *);
+
+static const struct fileops filemon_fileops = {
+	.fo_ioctl = filemon_ioctl,
+	.fo_close = filemon_close,
+	.fo_read = fbadop_read,
+	.fo_write = fbadop_write,
+	.fo_fcntl = fnullop_fcntl,
+	.fo_poll = fnullop_poll,
+	.fo_stat = fbadop_stat,
+	.fo_kqfilter = fnullop_kqfilter,
+};
+
+static krwlock_t filemon_mtx;
+
+static TAILQ_HEAD(, filemon) filemons_inuse =
+	TAILQ_HEAD_INITIALIZER(filemons_inuse);
+
+#ifdef DEBUG
+static int logLevel = LOG_DEBUG;
+#endif
+
+void
+filemon_output(struct filemon * filemon, char *msg, size_t len)
+{
+	struct uio auio;
+	struct iovec aiov;
+
+	if (filemon->fm_fp == NULL)
+		return;
+
+	aiov.iov_base = msg;
+	aiov.iov_len = len;
+	auio.uio_iov = &aiov;
+	auio.uio_iovcnt = 1;
+	auio.uio_resid = len;
+	auio.uio_rw = UIO_WRITE;
+	auio.uio_offset = (off_t) - 1;
+	uio_setup_sysspace(&auio);
+
+#ifdef DEBUG
+	{
+		char *cp;
+		int x = 16;
+
+		cp = strchr(msg, '\n');
+		if (cp && cp - msg <= 16)
+			x = (cp - msg) - 2;
+		log(logLevel, "filemont_output:('%.*s%s'", x,
+		    (x < 16) ? "..." : "", msg);
+	}
+#endif
+	(*filemon->fm_fp->f_ops->fo_write) (filemon->fm_fp,
+	    &(filemon->fm_fp->f_offset),
+	    &auio, curlwp->l_cred, FOF_UPDATE_OFFSET);
+}
+
+static void
+filemon_comment(struct filemon * filemon)
+{
+	int len;
+
+	len = snprintf(filemon->fm_msgbufr, sizeof(filemon->fm_msgbufr),
+	    "# filemon version 2\n# Target pid %d\nV 2\n",
+	    curproc->p_pid);
+
+	filemon_output(filemon, filemon->fm_msgbufr, len);
+}
+
+
+static struct filemon *
+filemon_pid_check(struct proc * p)
+{
+	struct filemon *filemon;
+
+	TAILQ_FOREACH(filemon, &filemons_inuse, fm_link) {
+		if (p->p_pid == filemon->fm_pid)
+			return (filemon);
+	}
+
+	if (p->p_pptr == NULL)
+		return (NULL);
+
+	return (filemon_pid_check(p->p_pptr));
+}
+
+/*
+ * return exclusive access to a filemon struct
+ */
+struct filemon *
+filemon_lookup(struct proc * p)
+{
+	struct filemon *filemon;
+
+	rw_enter(&filemon_mtx, RW_READER);
+	filemon = filemon_pid_check(p);
+	if (filemon) {
+		rw_enter(&filemon->fm_mtx, RW_WRITER);
+	}
+	rw_exit(&filemon_mtx);
+	return filemon;
+}
+
+static struct filemon *
+filemon_fp_data(struct file * fp, int lck)
+{
+	struct filemon *filemon;
+	
+	rw_enter(&filemon_mtx, RW_READER);
+	filemon = fp->f_data;
+	if (filemon && lck) {
+		rw_enter(&filemon->fm_mtx, lck);
+	}
+	rw_exit(&filemon_mtx);
+	return filemon;
+}
+
+static int n_open = 0;
+
+static int
+filemon_open(dev_t dev, int oflags __unused, int mode __unused,
+    struct lwp * l __unused)
+{
+	struct filemon *filemon;
+	struct file *fp;
+	int error, fd;
+
+	/* falloc() will use the descriptor for us. */
+	if ((error = fd_allocfile(&fp, &fd)) != 0)
+		return error;
+
+	filemon = kmem_alloc(sizeof(struct filemon), KM_SLEEP);
+	if (!filemon)
+		return ENOMEM;
+
+	rw_init(&filemon->fm_mtx);
+	filemon->fm_fd = -1;
+	filemon->fm_fp = NULL;
+	filemon->fm_pid = curproc->p_pid;
+
+	rw_enter(&filemon_mtx, RW_WRITER);
+	n_open++;
+
+	TAILQ_INSERT_TAIL(&filemons_inuse, filemon, fm_link);
+
+	rw_exit(&filemon_mtx);
+	return fd_clone(fp, fd, oflags, &filemon_fileops, filemon);
+}
+
+
+static int
+filemon_close(struct file * fp)
+{
+	struct filemon *filemon;
+
+#ifdef DEBUG
+	log(logLevel, "filemon_close()");
+#endif
+	/*
+	 * Follow the same lock order as filemon_lookup()
+	 * and filemon_fp_data() but hold exclusive access to
+	 * filemon_mtx until we are done.
+	 */
+	rw_enter(&filemon_mtx, RW_WRITER);
+	filemon = fp->f_data;
+	if (!filemon) {
+		rw_exit(&filemon_mtx);
+		return EBADF;
+	}
+	/* ensure that filemon_lookup() will now fail */
+	TAILQ_REMOVE(&filemons_inuse, filemon, fm_link);
+	n_open--;
+	/* ensure that filemon_fp_data() will now fail */
+	fp->f_data = NULL;
+
+	/*
+	 * once we have exclusive access, it should never be used again
+	 */
+	rw_enter(&filemon->fm_mtx, RW_WRITER);
+	if (filemon->fm_fp) {
+		fd_putfile(filemon->fm_fd);	/* release our reference */
+		filemon->fm_fp = NULL;
+	}
+	rw_exit(&filemon->fm_mtx);
+	rw_destroy(&filemon->fm_mtx);
+	kmem_free(filemon, sizeof(struct filemon));
+	rw_exit(&filemon_mtx);
+	return (0);
+}
+
+static int
+filemon_ioctl(struct file * fp, u_long cmd, void *data)
+{
+	int error = 0;
+	struct filemon *filemon;
+
+
+#ifdef DEBUG
+	log(logLevel, "filemon_ioctl(%lu)", cmd);;
+#endif
+
+	/*
+	 * this ensures we cannot get filemon if it is closing.
+	 */
+	filemon = filemon_fp_data(fp, RW_WRITER);
+	if (!filemon)
+		return EBADF;
+
+	switch (cmd) {
+	case FILEMON_SET_FD:
+		/* Set the output file descriptor. */
+		filemon->fm_fd = *((int *) data);
+		if ((filemon->fm_fp = fd_getfile(filemon->fm_fd)) == NULL) {
+			rw_exit(&filemon->fm_mtx);
+			return EBADF;
+		}
+		/* Write the file header. */
+		filemon_comment(filemon);
+		break;
+
+	case FILEMON_SET_PID:
+		/* Set the monitored process ID. */
+		filemon->fm_pid = *((pid_t *) data);
+		break;
+
+	default:
+		error = EINVAL;
+		break;
+	}
+
+	rw_exit(&filemon->fm_mtx);
+	return (error);
+}
+
+static void
+filemon_load(void *dummy __unused)
+{
+	rw_init(&filemon_mtx);
+
+	/* Install the syscall wrappers. */
+	filemon_wrapper_install();
+}
+
+
+static int
+filemon_unload(void)
+{
+	int error = 0;
+
+	rw_enter(&filemon_mtx, RW_WRITER);
+
+	if (TAILQ_FIRST(&filemons_inuse) != NULL)
+		error = EBUSY;
+	else {
+		/* Deinstall the syscall wrappers. */
+		filemon_wrapper_deinstall();
+	}
+	rw_exit(&filemon_mtx);
+
+	if (error == 0) {
+		rw_destroy(&filemon_mtx);
+	}
+	return (error);
+}
+
+static int
+filemon_modcmd(modcmd_t cmd, void *data)
+{
+	int error = 0;
+	int bmajor = -1;
+	int cmajor = -1;
+
+	switch (cmd) {
+	case MODULE_CMD_INIT:
+#ifdef DEBUG
+		logLevel = LOG_INFO;
+#endif
+
+		filemon_load(data);
+		error = devsw_attach("filemon", NULL, &bmajor,
+		    &filemon_cdevsw, &cmajor);
+		break;
+
+	case MODULE_CMD_FINI:
+		error = filemon_unload();
+		if (!error)
+			error = devsw_detach(NULL, &filemon_cdevsw);
+		break;
+
+	case MODULE_CMD_STAT:
+		log(LOG_INFO, "filemon: open=%d", n_open);
+		break;
+
+	default:
+		error = EOPNOTSUPP;
+		break;
+
+	}
+
+	return (error);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/dev/filemon/filemon.h	Fri Oct 22 09:23:11 2010 +0000
@@ -0,0 +1,52 @@
+/* $NetBSD: filemon.h,v 1.1.4.2 2010/10/22 09:23:13 uebayasi Exp $ */
+/*
+ * Copyright (c) 2010, Juniper Networks, Inc.
+ *
+ * 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 COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef FILEMON_SET_FD
+
+#ifndef _PATH_FILEMON
+#define _PATH_FILEMON "/dev/filemon"
+#endif
+#define FILEMON_SET_FD		_IOWR('S', 1, int)
+#define FILEMON_SET_PID		_IOWR('S', 2, pid_t)
+
+#ifdef _KERNEL
+struct filemon {
+	pid_t fm_pid;		/* The process ID being monitored. */
+	char fm_fname1[MAXPATHLEN];/* Temporary filename buffer. */
+	char fm_fname2[MAXPATHLEN];/* Temporary filename buffer. */
+	char fm_msgbufr[32 + 2 * MAXPATHLEN];	/* Output message buffer. */
+	int fm_fd;			/* Output fd */
+	struct file *fm_fp;	/* Output file pointer. */
+	krwlock_t fm_mtx;		/* Lock mutex for this filemon. */
+	TAILQ_ENTRY(filemon) fm_link;	/* Link into the in-use list. */
+};
+
+struct filemon * filemon_lookup(struct proc *);
+void filemon_output(struct filemon *, char *, size_t);
+void filemon_wrapper_install(void);
+void filemon_wrapper_deinstall(void);
+#endif
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/dev/filemon/filemon_wrapper.c	Fri Oct 22 09:23:11 2010 +0000
@@ -0,0 +1,385 @@
+/*
+ * Copyright (c) 2010, Juniper Networks, Inc.
+ *
+ * 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 COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: filemon_wrapper.c,v 1.1.4.2 2010/10/22 09:23:13 uebayasi Exp $");
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/fcntl.h>
+#include <sys/kernel.h>
+#include <sys/lwp.h>
+#include <sys/proc.h>
+#include <sys/syscall.h>
+#include <sys/syscallargs.h>
+
+#include "filemon.h"
+
+static int
+filemon_wrapper_chdir(struct lwp * l, const struct sys_chdir_args * uap,
+    register_t * retval)
+{
+	int ret;
+	int error;
+	size_t done;
+	size_t len;
+	struct filemon *filemon;
+	
+	if ((ret = sys_chdir(l, uap, retval)) == 0) {
+		filemon = filemon_lookup(curproc);
+
+		if (filemon) {
+
+			error = copyinstr(SCARG(uap, path), filemon->fm_fname1,
+			    sizeof(filemon->fm_fname1), &done);
+			if (error == 0) {
+				len = snprintf(filemon->fm_msgbufr,
+				    sizeof(filemon->fm_msgbufr),
+				    "C %d %s\n",
+				    curproc->p_pid, filemon->fm_fname1);
+
+				filemon_output(filemon, filemon->fm_msgbufr,
+				    len);
+			}
+			rw_exit(&filemon->fm_mtx);
+		}
+	}
+	return (ret);
+}
+
+static int
+filemon_wrapper_execve(struct lwp * l, struct sys_execve_args * uap,
+    register_t * retval)
+{
+	char fname[MAXPATHLEN];
+	int ret;
+	int error;
+	size_t done;
+	size_t len;
+	struct filemon *filemon;
+	
+	error = copyinstr(SCARG(uap, path), fname, sizeof(fname), &done);
+
+	if ((ret = sys_execve(l, uap, retval)) == 0 && error == 0) {
+		filemon = filemon_lookup(curproc);
+
+		if (filemon) {
+
+			len = snprintf(filemon->fm_msgbufr, sizeof(filemon->fm_msgbufr),
+			    "E %d %s\n",
+			    curproc->p_pid, fname);
+
+			filemon_output(filemon, filemon->fm_msgbufr, len);
+			rw_exit(&filemon->fm_mtx);
+		}
+	}
+	return (ret);
+}
+
+
+static int
+filemon_wrapper_fork(struct lwp * l, const void *v, register_t * retval)
+{
+	int ret;
+	size_t len;
+	struct filemon *filemon;
+
+	if ((ret = sys_fork(l, v, retval)) == 0) {
+		filemon = filemon_lookup(curproc);
+
+		if (filemon) {
+			len = snprintf(filemon->fm_msgbufr,
+			    sizeof(filemon->fm_msgbufr),
+			    "F %d %ld\n",
+			    curproc->p_pid, (long) retval[0]);
+
+			filemon_output(filemon, filemon->fm_msgbufr, len);
+
+			rw_exit(&filemon->fm_mtx);
+		}
+	}
+	return (ret);
+}
+
+static int
+filemon_wrapper_vfork(struct lwp * l, const void *v, register_t * retval)
+{
+	int ret;
+	size_t len;
+	struct filemon *filemon;
+
+	if ((ret = sys_vfork(l, v, retval)) == 0) {
+		filemon = filemon_lookup(curproc);
+
+		if (filemon) {
+			len = snprintf(filemon->fm_msgbufr,
+			    sizeof(filemon->fm_msgbufr),
+			    "F %d %ld\n",
+			    curproc->p_pid, (long) retval[0]);
+
+			filemon_output(filemon, filemon->fm_msgbufr, len);
+
+			rw_exit(&filemon->fm_mtx);
+		}
+	}
+	return (ret);
+}
+
+static int
+filemon_wrapper_open(struct lwp * l, struct sys_open_args * uap,
+    register_t * retval)
+{
+	int ret;
+	int error;
+	size_t done;
+	size_t len;
+	struct filemon *filemon;
+
+	if ((ret = sys_open(l, uap, retval)) == 0) {
+		filemon = filemon_lookup(curproc);
+
+		if (filemon) {
+			error = copyinstr(SCARG(uap, path), filemon->fm_fname1,
+			    sizeof(filemon->fm_fname1), &done);
+			if (error == 0) {
+				len = snprintf(filemon->fm_msgbufr,
+				    sizeof(filemon->fm_msgbufr),
+				    "%c %d %s\n",
+				    (SCARG(uap, flags) & O_ACCMODE) ? 'W' : 'R',
+				    curproc->p_pid, filemon->fm_fname1);
+
+				filemon_output(filemon, filemon->fm_msgbufr,
+				    len);
+			}
+			rw_exit(&filemon->fm_mtx);
+		}
+	}
+	return (ret);
+}
+
+static int
+filemon_wrapper_rename(struct lwp * l, struct sys_rename_args * uap,
+    register_t * retval)
+{
+	int ret;
+	int error;
+	size_t done;
+	size_t len;
+	struct filemon *filemon;
+
+	if ((ret = sys_rename(l, uap, retval)) == 0) {
+		filemon = filemon_lookup(curproc);
+
+		if (filemon) {
+			error = copyinstr(SCARG(uap, from), filemon->fm_fname1,
+			    sizeof(filemon->fm_fname1), &done);
+			if (error == 0) 
+				error = copyinstr(SCARG(uap, to),
+				    filemon->fm_fname2,
+				    sizeof(filemon->fm_fname2), &done);
+			if (error == 0) {
+				len = snprintf(filemon->fm_msgbufr,
+				    sizeof(filemon->fm_msgbufr),
+				    "M %d '%s' '%s'\n",
+				    curproc->p_pid, filemon->fm_fname1,
+				    filemon->fm_fname2);
+
+				filemon_output(filemon, filemon->fm_msgbufr,
+				    len);
+			}
+			rw_exit(&filemon->fm_mtx);
+		}
+	}
+	return (ret);
+}
+
+static int
+filemon_wrapper_link(struct lwp * l, struct sys_link_args * uap,
+    register_t * retval)
+{
+	int ret;
+	int error;
+	size_t done;
+	size_t len;
+	struct filemon *filemon;
+
+	if ((ret = sys_link(l, uap, retval)) == 0) {
+		filemon = filemon_lookup(curproc);
+
+		if (filemon) {
+			error = copyinstr(SCARG(uap, path),
+			    filemon->fm_fname1, sizeof(filemon->fm_fname1),
+			    &done);
+			if (error == 0)
+				error = copyinstr(SCARG(uap, link),
+				    filemon->fm_fname2,
+				    sizeof(filemon->fm_fname2), &done);
+			if (error == 0) {
+				len = snprintf(filemon->fm_msgbufr,
+				    sizeof(filemon->fm_msgbufr), "L %d '%s' '%s'\n",
+				    curproc->p_pid, filemon->fm_fname1,
+				    filemon->fm_fname2);
+
+				filemon_output(filemon, filemon->fm_msgbufr,
+				    len);
+			}
+			rw_exit(&filemon->fm_mtx);
+		}
+	}
+	return (ret);
+}
+
+static int
+filemon_wrapper_symlink(struct lwp * l, struct sys_symlink_args * uap,
+    register_t * retval)
+{
+	int ret;
+	int error;
+	size_t done;
+	size_t len;
+	struct filemon *filemon;
+
+	if ((ret = sys_symlink(l, uap, retval)) == 0) {
+		filemon = filemon_lookup(curproc);
+
+		if (filemon) {
+			error = copyinstr(SCARG(uap, path),
+			    filemon->fm_fname1,
+			    sizeof(filemon->fm_fname1), &done);
+			if (error == 0)
+				error = copyinstr(SCARG(uap, link),
+				    filemon->fm_fname2,
+				    sizeof(filemon->fm_fname2), &done);
+			if (error == 0) {
+				len = snprintf(filemon->fm_msgbufr,
+				    sizeof(filemon->fm_msgbufr),
+				    "L %d '%s' '%s'\n",
+				    curproc->p_pid, filemon->fm_fname1,
+				    filemon->fm_fname2);
+
+				filemon_output(filemon, filemon->fm_msgbufr,
+				    len);
+			}
+			rw_exit(&filemon->fm_mtx);
+		}
+	}
+	return (ret);
+}
+
+
+static void
+filemon_wrapper_sys_exit(struct lwp * l, struct sys_exit_args * uap,
+    register_t * retval)
+{
+	size_t len;
+	struct filemon *filemon;
+
+	filemon = filemon_lookup(curproc);
+
+	if (filemon) {
+		len = snprintf(filemon->fm_msgbufr,
+		    sizeof(filemon->fm_msgbufr), "X %d %d\n",
+		    curproc->p_pid, SCARG(uap, rval));
+
+		filemon_output(filemon, filemon->fm_msgbufr, len);
+
+		/* Check if the monitored process is about to exit. */
+		if (filemon->fm_pid == curproc->p_pid) {
+			len = snprintf(filemon->fm_msgbufr,
+			    sizeof(filemon->fm_msgbufr), "# Bye bye\n");
+
+			filemon_output(filemon, filemon->fm_msgbufr, len);
+		}
+		rw_exit(&filemon->fm_mtx);
+	}
+	sys_exit(l, uap, retval);
+}
+
+static int
+filemon_wrapper_unlink(struct lwp * l, struct sys_unlink_args * uap,
+    register_t * retval)
+{
+	int ret;
+	int error;
+	size_t done;
+	size_t len;
+	struct filemon *filemon;
+
+	if ((ret = sys_unlink(l, uap, retval)) == 0) {
+		filemon = filemon_lookup(curproc);
+
+		if (filemon) {
+			error = copyinstr(SCARG(uap, path),
+			    filemon->fm_fname1,
+			    sizeof(filemon->fm_fname1), &done);
+			if (error == 0) {
+				len = snprintf(filemon->fm_msgbufr,
+				    sizeof(filemon->fm_msgbufr),
+				    "D %d %s\n",
+				    curproc->p_pid, filemon->fm_fname1);
+
+				filemon_output(filemon, filemon->fm_msgbufr,
+				    len);
+			}
+			rw_exit(&filemon->fm_mtx);
+		}
+	}
+	return (ret);
+}
+
+
+void
+filemon_wrapper_install(void)
+{
+	struct sysent *sv_table = curproc->p_emul->e_sysent;
+
+	sv_table[SYS_chdir].sy_call = (sy_call_t *) filemon_wrapper_chdir;
+	sv_table[SYS_execve].sy_call = (sy_call_t *) filemon_wrapper_execve;
+	sv_table[SYS_exit].sy_call = (sy_call_t *) filemon_wrapper_sys_exit;
+	sv_table[SYS_fork].sy_call = (sy_call_t *) filemon_wrapper_fork;
+	sv_table[SYS_link].sy_call = (sy_call_t *) filemon_wrapper_link;
+	sv_table[SYS_open].sy_call = (sy_call_t *) filemon_wrapper_open;
+	sv_table[SYS_rename].sy_call = (sy_call_t *) filemon_wrapper_rename;
+	sv_table[SYS_symlink].sy_call = (sy_call_t *) filemon_wrapper_symlink;
+	sv_table[SYS_unlink].sy_call = (sy_call_t *) filemon_wrapper_unlink;
+	sv_table[SYS_vfork].sy_call = (sy_call_t *) filemon_wrapper_vfork;
+}
+
+void
+filemon_wrapper_deinstall(void)
+{
+	struct sysent *sv_table = curproc->p_emul->e_sysent;
+
+	sv_table[SYS_chdir].sy_call = (sy_call_t *) sys_chdir;
+	sv_table[SYS_execve].sy_call = (sy_call_t *) sys_execve;
+	sv_table[SYS_exit].sy_call = (sy_call_t *) sys_exit;
+	sv_table[SYS_fork].sy_call = (sy_call_t *) sys_fork;
+	sv_table[SYS_link].sy_call = (sy_call_t *) sys_link;
+	sv_table[SYS_open].sy_call = (sy_call_t *) sys_open;
+	sv_table[SYS_rename].sy_call = (sy_call_t *) sys_rename;
+	sv_table[SYS_symlink].sy_call = (sy_call_t *) sys_symlink;
+	sv_table[SYS_unlink].sy_call = (sy_call_t *) sys_unlink;
+	sv_table[SYS_vfork].sy_call = (sy_call_t *) sys_vfork;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/dev/filemon/mknod-sh	Fri Oct 22 09:23:11 2010 +0000
@@ -0,0 +1,22 @@
+#!/bin/sh
+
+# Note that filemon.kmod needs the 6.x version of modload.
+
+Error() {
+	echo "ERROR: $@" >&2; exit 1
+}
+
+major=`sysctl kern.drivers | tr ',' '\012' | sed -n '/filemon/s,.*\[\([0-9][0-9]*\).*,\1,p'`
+
+[ ${major:-0} -gt 0 ] || Error filemon not loaded
+dev=/dev/filemon
+
+if [ -c $dev ]; then
+   x=`'ls' -l $dev`
+   case "$x" in
+   *" $major,"*) exit 0;;
+   esac
+   rm -f $dev
+fi
+mknod -m 666 $dev c $major 0
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/modules/compat_aoutm68k/Makefile	Fri Oct 22 09:23:11 2010 +0000
@@ -0,0 +1,15 @@
+#	$NetBSD: Makefile,v 1.1.2.2 2010/10/22 09:23:13 uebayasi Exp $
+
+.include "../Makefile.inc"
+
+KMOD=	compat_aoutm68k
+
+CPPFLAGS+=	-DEXEC_AOUT -DCOREDUMP
+CPPFLAGS+=	-DSYSVSHM -DSYSVSEM -DSYSVMSG -DKTRACE
+CPPFLAGS+=	-DCOMPAT_43 -DCOMPAT_12 -DCOMPAT_13 -DCOMPAT_14
+CPPFLAGS+=	-DCOMPAT_AOUT_M68K
+
+.PATH:	${S}/compat/aoutm68k
+SRCS+=	aoutm68k_exec.c aoutm68k_mod.c aoutm68k_stat.c aoutm68k_sysent.c
+
+.include <bsd.kmodule.mk>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/modules/filemon/Makefile	Fri Oct 22 09:23:11 2010 +0000
@@ -0,0 +1,11 @@
+# $NetBSD: Makefile,v 1.1.4.2 2010/10/22 09:23:13 uebayasi Exp $
+
+.include "../Makefile.inc"
+
+.PATH: ${S}/dev/filemon
+
+KMOD = filemon
+SRCS = filemon.c filemon_wrapper.c
+NOMAN = no
+
+.include <bsd.kmodule.mk>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/modules/npf/Makefile	Fri Oct 22 09:23:11 2010 +0000
@@ -0,0 +1,13 @@
+# $NetBSD: Makefile,v 1.2.4.2 2010/10/22 09:23:13 uebayasi Exp $
+
+.include "../Makefile.inc"
+
+.PATH:		${S}/net/npf
+
+KMOD=		npf
+
+SRCS=		npf.c npf_ctl.c npf_handler.c npf_instr.c npf_mbuf.c
+SRCS+=		npf_processor.c npf_ruleset.c npf_tableset.c npf_inet.c
+SRCS+=		npf_session.c npf_nat.c npf_sendpkt.c npf_alg.c
+
+.include <bsd.kmodule.mk>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/modules/swsensor/Makefile	Fri Oct 22 09:23:11 2010 +0000
@@ -0,0 +1,11 @@
+# $NetBSD: Makefile,v 1.1.2.2 2010/10/22 09:23:14 uebayasi Exp $
+
+.include "../Makefile.inc"
+
+.PATH:	${S}/dev/sysmon
+
+KMOD=   swsensor
+
+SRCS=	swsensor.c
+
+.include <bsd.kmodule.mk>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/net/npf/Makefile	Fri Oct 22 09:23:11 2010 +0000
@@ -0,0 +1,9 @@
+# $NetBSD: Makefile,v 1.1.4.2 2010/10/22 09:23:14 uebayasi Exp $
+#
+# Public Domain.
+#
+
+INCSDIR=	/usr/include/net
+INCS=		npf.h npf_ncode.h
+
+.include <bsd.kinc.mk>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/net/npf/files.npf	Fri Oct 22 09:23:11 2010 +0000
@@ -0,0 +1,28 @@
+# $NetBSD: files.npf,v 1.2.4.2 2010/10/22 09:23:14 uebayasi Exp $
+#
+# Public Domain.
+#
+
+#
+# NPF pseudo device and modules.
+#
+
+defpseudo	npf:	ifnet
+
+# Core
+file	net/npf/npf.c				npf
+file	net/npf/npf_ctl.c			npf
+file	net/npf/npf_handler.c			npf
+file	net/npf/npf_instr.c			npf
+file	net/npf/npf_mbuf.c			npf
+file	net/npf/npf_processor.c			npf
+file	net/npf/npf_ruleset.c			npf
+file	net/npf/npf_tableset.c			npf
+file	net/npf/npf_inet.c			npf
+file	net/npf/npf_session.c			npf
+file	net/npf/npf_nat.c			npf
+file	net/npf/npf_alg.c			npf
+file	net/npf/npf_sendpkt.c			npf
+
+# ALGs
+file	net/npf/npf_alg_icmp.c			npf
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/net/npf/npf.c	Fri Oct 22 09:23:11 2010 +0000
@@ -0,0 +1,216 @@
+/*	$NetBSD: npf.c,v 1.1.4.2 2010/10/22 09:23:14 uebayasi Exp $	*/
+
+/*-
+ * Copyright (c) 2009-2010 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This material is based upon work partially supported by The
+ * NetBSD Foundation under a contract with Mindaugas Rasiukevicius.
+ *
+ * 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * NPF main: dynamic load/initialisation and unload routines.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: npf.c,v 1.1.4.2 2010/10/22 09:23:14 uebayasi Exp $");
+
+#include <sys/param.h>
+#include <sys/types.h>
+
+#include <sys/conf.h>
+#include <sys/kauth.h>
+#include <sys/lwp.h>
+#include <sys/module.h>
+#include <sys/socketvar.h>
+#include <sys/uio.h>
+
+#include "npf_impl.h"
+
+/*
+ * Module and device structures.
+ */
+MODULE(MODULE_CLASS_MISC, npf, NULL);
+
+void		npfattach(int);
+
+static int	npf_dev_open(dev_t, int, int, lwp_t *);
+static int	npf_dev_close(dev_t, int, int, lwp_t *);
+static int	npf_dev_ioctl(dev_t, u_long, void *, int, lwp_t *);
+static int	npf_dev_poll(dev_t, int, lwp_t *);
+static int	npf_dev_read(dev_t, struct uio *, int);
+
+const struct cdevsw npf_cdevsw = {
+	npf_dev_open, npf_dev_close, npf_dev_read, nowrite, npf_dev_ioctl,
+	nostop, notty, npf_dev_poll, nommap, nokqfilter, D_OTHER | D_MPSAFE
+};
+
+static int
+npf_init(void)
+{
+#ifdef _MODULE
+	devmajor_t bmajor = NODEVMAJOR, cmajor = NODEVMAJOR;
+#endif
+	int error;
+
+	/*
+	 * Initialise ruleset, tables and session structures.
+	 */
+
+	error = npf_ruleset_sysinit();
+	if (error)
+		return error;
+
+	error = npf_tableset_sysinit();
+	if (error) {
+		npf_ruleset_sysfini();
+		return error;
+	}
+
+	error = npf_session_sysinit();
+	if (error) {
+		npf_tableset_sysfini();
+		npf_ruleset_sysfini();
+		return error;
+	}
+	npf_nat_sysinit();
+	npf_alg_sysinit();
+
+#ifdef _MODULE
+	/* Attach /dev/npf device. */
+	error = devsw_attach("npf", NULL, &bmajor, &npf_cdevsw, &cmajor);
+	if (error) {
+		npf_nat_sysfini();
+		npf_session_sysfini();
+		npf_tableset_sysfini();
+		npf_ruleset_sysfini();
+	}
+#endif
+	return error;
+}
+
+static int
+npf_fini(void)
+{
+
+#ifdef _MODULE
+	/* At first, detach device and remove pfil hooks. */
+	devsw_detach(NULL, &npf_cdevsw);
+#endif
+	npf_nat_sysfini();
+	npf_alg_sysfini();
+	npf_session_sysfini();
+	npf_tableset_sysfini();
+	npf_ruleset_sysfini();
+
+	return 0;
+}
+
+/*
+ * Module interface.
+ */
+static int
+npf_modcmd(modcmd_t cmd, void *arg)
+{
+
+	switch (cmd) {
+	case MODULE_CMD_INIT:
+		return npf_init();
+	case MODULE_CMD_FINI:
+		return npf_fini();
+	default:
+		return ENOTTY;
+	}
+	return 0;
+}
+
+void
+npfattach(int nunits)
+{
+
+	/* Void. */
+}
+
+static int
+npf_dev_open(dev_t dev, int flag, int mode, lwp_t *l)
+{
+
+	/* Available only for super-user. */
+	if (kauth_authorize_generic(l->l_cred, KAUTH_GENERIC_ISSUSER, NULL)) {
+		return EPERM;
+	}
+	return 0;
+}
+
+static int
+npf_dev_close(dev_t dev, int flag, int mode, lwp_t *l)
+{
+
+	return 0;
+}
+
+static int
+npf_dev_ioctl(dev_t dev, u_long cmd, void *data, int flag, lwp_t *l)
+{
+	int error;
+
+	/* Available only for super-user. */
+	if (kauth_authorize_generic(l->l_cred, KAUTH_GENERIC_ISSUSER, NULL)) {
+		return EPERM;
+	}
+
+	switch (cmd) {
+	case IOC_NPF_VERSION:
+		*(int *)data = NPF_VERSION;
+		error = 0;
+		break;
+	case IOC_NPF_SWITCH:
+		error = npfctl_switch(data);
+		break;
+	case IOC_NPF_RELOAD:
+		error = npfctl_reload(cmd, data);
+		break;
+	case IOC_NPF_TABLE:
+		error = npfctl_table(data);
+		break;
+	default:
+		error = ENOTTY;
+		break;
+	}
+	return error;
+}
+
+static int
+npf_dev_poll(dev_t dev, int events, lwp_t *l)
+{
+
+	return ENOTSUP;
+}
+
+static int
+npf_dev_read(dev_t dev, struct uio *uio, int flag)
+{
+
+	return ENOTSUP;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/net/npf/npf.h	Fri Oct 22 09:23:11 2010 +0000
@@ -0,0 +1,188 @@
+/*	$NetBSD: npf.h,v 1.3.4.2 2010/10/22 09:23:14 uebayasi Exp $	*/
+
+/*-
+ * Copyright (c) 2009-2010 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This material is based upon work partially supported by The
+ * NetBSD Foundation under a contract with Mindaugas Rasiukevicius.
+ *
+ * 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Public NPF interfaces.
+ */
+
+#ifndef _NPF_H_
+#define _NPF_H_
+
+#include <sys/param.h>
+#include <sys/types.h>
+
+#include <sys/ioctl.h>
+#include <prop/proplib.h>
+
+#ifdef _NPF_TESTING
+#include "testing.h"
+#endif
+
+#define	NPF_VERSION		1
+
+/*
+ * Public declarations.
+ */
+
+struct npf_ruleset;
+struct npf_rule;
+struct npf_hook;
+
+typedef struct npf_ruleset	npf_ruleset_t;
+typedef struct npf_rule		npf_rule_t;
+typedef struct npf_hook		npf_hook_t;
+
+/*
+ * Public definitions.
+ */
+
+typedef void			nbuf_t;
+
+/*
+ * Packet information cache.
+ */
+
+#define	NPC_IP46	0x01	/* IPv4,6 packet with known protocol. */
+#define	NPC_IP6VER	0x02	/* If NPI_IP46, then: 0 - IPv4, 1 - IPv6. */
+#define	NPC_ADDRS	0x04	/* Known source and destination addresses. */
+#define	NPC_PORTS	0x08	/* Known ports (for TCP/UDP cases). */
+#define	NPC_ICMP	0x10	/* ICMP with known type and code. */
+#define	NPC_ICMP_ID	0x20	/* ICMP with query ID. */
+
+/* XXX: Optimise later, pack in unions, perhaps bitfields, etc. */
+typedef struct {
+	uint32_t		npc_info;
+	int			npc_dir;
+	/* NPC_IP46 */
+	uint8_t			npc_proto;
+	uint16_t		npc_hlen;
+	uint16_t		npc_ipsum;
+	/* NPC_ADDRS */
+	in_addr_t		npc_srcip;
+	in_addr_t		npc_dstip;
+	/* NPC_PORTS */
+	in_port_t		npc_sport;
+	in_port_t		npc_dport;
+	uint8_t			npc_tcp_flags;
+	/* NPC_ICMP */
+	uint8_t			npc_icmp_type;
+	uint8_t			npc_icmp_code;
+	uint16_t		npc_icmp_id;
+} npf_cache_t;
+
+static inline bool
+npf_iscached(const npf_cache_t *npc, const int inf)
+{
+
+	return __predict_true((npc->npc_info & inf) != 0);
+}
+
+#if defined(_KERNEL) || defined(_NPF_TESTING)
+
+/* Network buffer interface. */
+void *		nbuf_dataptr(void *);
+void *		nbuf_advance(nbuf_t **, void *, u_int);
+int		nbuf_advfetch(nbuf_t **, void **, u_int, size_t, void *);
+int		nbuf_fetch_datum(nbuf_t *, void *, size_t, void *);
+int		nbuf_store_datum(nbuf_t *, void *, size_t, void *);
+
+int		nbuf_add_tag(nbuf_t *, uint32_t, uint32_t);
+int		nbuf_find_tag(nbuf_t *, uint32_t, void **);
+
+/* Ruleset interface. */
+npf_rule_t *	npf_rule_alloc(int, pri_t, int, void *, size_t);
+void		npf_rule_free(npf_rule_t *);
+void		npf_activate_rule(npf_rule_t *);
+void		npf_deactivate_rule(npf_rule_t *);
+
+npf_hook_t *	npf_hook_register(npf_rule_t *,
+		    void (*)(const npf_cache_t *, void *), void *);
+void		npf_hook_unregister(npf_rule_t *, npf_hook_t *);
+
+#endif	/* _KERNEL */
+
+/* Rule attributes. */
+#define	NPF_RULE_PASS			0x0001
+#define	NPF_RULE_COUNT			0x0002
+#define	NPF_RULE_FINAL			0x0004
+#define	NPF_RULE_LOG			0x0008
+#define	NPF_RULE_DEFAULT		0x0010
+#define	NPF_RULE_KEEPSTATE		0x0020
+#define	NPF_RULE_RETRST			0x0040
+#define	NPF_RULE_RETICMP		0x0080
+
+#define	NPF_RULE_IN			0x1000
+#define	NPF_RULE_OUT			0x2000
+#define	NPF_RULE_DIMASK			0x3000
+
+/* Address translation types and flags. */
+#define	NPF_NATIN			1
+#define	NPF_NATOUT			2
+
+#define	NPF_NAT_PORTS			0x01
+#define	NPF_NAT_PORTMAP			0x02
+
+/* Table types. */
+#define	NPF_TABLE_HASH			1
+#define	NPF_TABLE_RBTREE		2
+
+/* Layers. */
+#define	NPF_LAYER_2			2
+#define	NPF_LAYER_3			3
+
+/* XXX mbuf.h: just for now. */
+#define	PACKET_TAG_NPF			10
+
+/*
+ * IOCTL structures.
+ */
+
+#define	NPF_IOCTL_TBLENT_ADD		1
+#define	NPF_IOCTL_TBLENT_REM		2
+
+typedef struct npf_ioctl_table {
+	int			nct_action;
+	u_int			nct_tid;
+	in_addr_t		nct_addr;
+	in_addr_t		nct_mask;
+	int			_reserved;
+} npf_ioctl_table_t;
+
+/*
+ * IOCTL operations.
+ */
+
+#define	IOC_NPF_VERSION		_IOR('N', 100, int)
+#define	IOC_NPF_SWITCH		_IOW('N', 101, int)
+#define	IOC_NPF_RELOAD		_IOW('N', 102, struct plistref)
+#define	IOC_NPF_TABLE		_IOW('N', 103, struct npf_ioctl_table)
+
+#endif	/* _NPF_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/net/npf/npf_alg.c	Fri Oct 22 09:23:11 2010 +0000
@@ -0,0 +1,168 @@
+/*	$NetBSD: npf_alg.c,v 1.1.4.2 2010/10/22 09:23:14 uebayasi Exp $	*/
+
+/*-
+ * Copyright (c) 2010 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This material is based upon work partially supported by The
+ * NetBSD Foundation under a contract with Mindaugas Rasiukevicius.
+ *
+ * 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * NPF interface for application level gateways (ALGs).
+ */
+
+#ifdef _KERNEL
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: npf_alg.c,v 1.1.4.2 2010/10/22 09:23:14 uebayasi Exp $");
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#endif
+
+#include <sys/kmem.h>
+#include <sys/pool.h>
+#include <net/pfil.h>
+
+#include "npf_impl.h"
+
+/* NAT ALG structure for registration. */
+struct npf_alg {
+	LIST_ENTRY(npf_alg)		na_entry;
+	void *				na_ptr;
+	npf_algfunc_t			na_match_func;
+	npf_algfunc_t			na_out_func;
+	npf_algfunc_t			na_in_func;
+	npf_algfunc_t			na_seid_func;
+};
+
+static LIST_HEAD(, npf_alg)		nat_alg_list;
+
+void
+npf_alg_sysinit(void)
+{
+
+	LIST_INIT(&nat_alg_list);
+}
+
+void
+npf_alg_sysfini(void)
+{
+
+	KASSERT(LIST_EMPTY(&nat_alg_list));
+}
+
+/*
+ * npf_alg_register: register application-level gateway.
+ *
+ * XXX: Protected by module lock, but unify serialisation later.
+ */
+npf_alg_t *
+npf_alg_register(npf_algfunc_t match, npf_algfunc_t out, npf_algfunc_t in,
+    npf_algfunc_t seid)
+{
+	npf_alg_t *alg;
+
+	alg = kmem_alloc(sizeof(npf_alg_t), KM_SLEEP);
+	alg->na_ptr = alg;
+	alg->na_match_func = match;
+	alg->na_out_func = out;
+	alg->na_in_func = in;
+	alg->na_seid_func = seid;
+	LIST_INSERT_HEAD(&nat_alg_list, alg, na_entry);
+	return alg;
+}
+
+/*
+ * npf_alg_unregister: unregister application-level gateway.
+ */
+int
+npf_alg_unregister(npf_alg_t *alg)
+{
+	npf_alg_t *it;
+
+	LIST_FOREACH(it, &nat_alg_list, na_entry) {
+		if (alg == it)
+			break;
+	}
+	if (it != NULL) {
+		LIST_REMOVE(alg, na_entry);
+	}
+	/* TODO: Flush relevant sessions. */
+	kmem_free(alg, sizeof(npf_alg_t));
+	return 0;
+}
+
+void
+npf_alg_match(npf_cache_t *npc, nbuf_t *nbuf, npf_nat_t *nt)
+{
+	npf_alg_t *alg;
+	npf_algfunc_t func;
+
+	LIST_FOREACH(alg, &nat_alg_list, na_entry) {
+		func = alg->na_match_func;
+		if (__predict_true(func != NULL)) {
+			func(npc, nbuf, nt);
+			return;
+		}
+	}
+}
+
+/*
+ * npf_alg_exec: execute in/out inspection hooks of each ALG.
+ */
+void
+npf_alg_exec(npf_cache_t *npc, nbuf_t *nbuf, npf_nat_t *nt, const int di)
+{
+	npf_alg_t *alg;
+
+	LIST_FOREACH(alg, &nat_alg_list, na_entry) {
+		if ((di & PFIL_OUT) != 0 && alg->na_out_func != NULL) {
+			(alg->na_out_func)(npc, nbuf, nt);
+			continue;
+		}
+		if ((di & PFIL_IN) != 0 && alg->na_in_func != NULL) {
+			(alg->na_in_func)(npc, nbuf, nt);
+			continue;
+		}
+	}
+}
+
+bool
+npf_alg_sessionid(npf_cache_t *npc, nbuf_t *nbuf, npf_cache_t *key)
+{
+	npf_alg_t *alg;
+	npf_algfunc_t func;
+
+	LIST_FOREACH(alg, &nat_alg_list, na_entry) {
+		func = alg->na_seid_func;
+		if (__predict_true(func == NULL)) {
+			continue;
+		}
+		if (func(npc, nbuf, key)) {
+			return true;
+		}
+	}
+	return false;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/net/npf/npf_alg_icmp.c	Fri Oct 22 09:23:11 2010 +0000
@@ -0,0 +1,326 @@
+/*	$NetBSD: npf_alg_icmp.c,v 1.3.4.2 2010/10/22 09:23:14 uebayasi Exp $	*/
+
+/*-
+ * Copyright (c) 2010 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This material is based upon work partially supported by The
+ * NetBSD Foundation under a contract with Mindaugas Rasiukevicius.
+ *
+ * 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * NPF ALG for ICMP and traceroute translations.
+ */
+
+#ifdef _KERNEL
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: npf_alg_icmp.c,v 1.3.4.2 2010/10/22 09:23:14 uebayasi Exp $");
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#endif
+#include <sys/module.h>
+#include <sys/pool.h>
+
+#include <netinet/in_systm.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/tcp.h>
+#include <netinet/udp.h>
+#include <netinet/ip_icmp.h>
+#include <net/pfil.h>
+
+#include "npf_impl.h"
+
+MODULE(MODULE_CLASS_MISC, npf_alg_icmp, "npf");
+
+/*
+ * Traceroute criteria.
+ *
+ * IANA assigned base port: 33434.  However, common practice is to increase
+ * the port, thus monitor [33434-33484] range.  Additional filter is TTL < 50.
+ */
+
+#define	TR_BASE_PORT	33434
+#define	TR_PORT_RANGE	33484
+#define	TR_MAX_TTL	50
+
+static npf_alg_t *	alg_icmp;
+
+static bool		npfa_icmp_match(npf_cache_t *, nbuf_t *, void *);
+static bool		npfa_icmp_natin(npf_cache_t *, nbuf_t *, void *);
+static bool		npfa_icmp_session(npf_cache_t *, nbuf_t *, void *);
+
+/*
+ * npf_alg_icmp_{init,fini,modcmd}: ICMP ALG initialization, destruction
+ * and module interface.
+ */
+
+static int
+npf_alg_icmp_init(void)
+{
+
+	alg_icmp = npf_alg_register(npfa_icmp_match, NULL,
+	    npfa_icmp_natin, npfa_icmp_session);
+	KASSERT(alg_icmp != NULL);
+	return 0;
+}
+
+static int
+npf_alg_icmp_fini(void)
+{
+
+	KASSERT(alg_icmp != NULL);
+	return npf_alg_unregister(alg_icmp);
+}
+
+static int
+npf_alg_icmp_modcmd(modcmd_t cmd, void *arg)
+{
+
+	switch (cmd) {
+	case MODULE_CMD_INIT:
+		return npf_alg_icmp_init();
+	case MODULE_CMD_FINI:
+		return npf_alg_icmp_fini();
+	default:
+		return ENOTTY;
+	}
+	return 0;
+}
+
+/*
+ * npfa_icmp_match: ALG matching inspector, determines ALG case and
+ * establishes a session for "backwards" stream.
+ */
+static bool
+npfa_icmp_match(npf_cache_t *npc, nbuf_t *nbuf, void *ntptr)
+{
+	const int proto = npc->npc_proto;
+	void *n_ptr = nbuf_dataptr(nbuf);
+	u_int offby;
+	uint8_t ttl;
+
+	/* Handle TCP/UDP traceroute - check for port range. */
+	if (proto != IPPROTO_TCP && proto != IPPROTO_UDP) {
+		return false;
+	}
+	KASSERT(npf_iscached(npc, NPC_PORTS));
+	in_port_t dport = ntohs(npc->npc_dport);
+	if (dport < TR_BASE_PORT || dport > TR_PORT_RANGE) {
+		return false;
+	}
+
+	/* Check for low TTL. */
+	offby = offsetof(struct ip, ip_ttl);
+	if (nbuf_advfetch(&nbuf, &n_ptr, offby, sizeof(uint8_t), &ttl))
+		return false;
+	if (ttl > TR_MAX_TTL)
+		return false;
+
+	/* Associate ALG with translation entry. */
+	npf_nat_t *nt = ntptr;
+	npf_nat_setalg(nt, alg_icmp, 0);
+	return true;
+}
+
+/*
+ * npf_icmp_uniqid: retrieve unique identifiers - either ICMP query ID
+ * or TCP/UDP ports of the original packet, which is embedded.
+ */
+static inline bool
+npf_icmp_uniqid(const int type, npf_cache_t *npc, nbuf_t *nbuf, void *n_ptr)
+{
+	u_int offby;
+
+	/* Per RFC 792. */
+	switch (type) {
+	case ICMP_UNREACH:
+	case ICMP_SOURCEQUENCH:
+	case ICMP_REDIRECT:
+	case ICMP_TIMXCEED:
+	case ICMP_PARAMPROB:
+		/* Should contain original IP header. */
+		offby = offsetof(struct icmp, icmp_ip);
+		if ((n_ptr = nbuf_advance(&nbuf, n_ptr, offby)) == NULL) {
+			return false;
+		}
+		/* Fetch into the cache. */
+		if (!npf_ip4_proto(npc, nbuf, n_ptr)) {
+			return false;
+		}
+		const int proto = npc->npc_proto;
+		if (proto != IPPROTO_TCP && proto != IPPROTO_UDP) {
+			return false;
+		}
+		if (!npf_fetch_ip4addrs(npc, nbuf, n_ptr)) {
+			return false;
+		}
+		if (!npf_fetch_ports(npc, nbuf, n_ptr, proto)) {
+			return false;
+		}
+		return true;
+
+	case ICMP_ECHOREPLY:
+	case ICMP_ECHO:
+	case ICMP_TSTAMP:
+	case ICMP_TSTAMPREPLY:
+	case ICMP_IREQ:
+	case ICMP_IREQREPLY:
+		/* Should contain ICMP query ID. */
+		offby = offsetof(struct icmp, icmp_id);
+		if (nbuf_advfetch(&nbuf, &n_ptr, offby, sizeof(uint16_t),
+		    &npc->npc_icmp_id)) {
+			return false;
+		}
+		npc->npc_info |= NPC_ICMP_ID;
+		return true;
+	default:
+		break;
+	}
+	/* No unique IDs. */
+	return false;
+}
+
+/*
+ * npfa_icmp_session: ALG session inspector, determines unique identifiers.
+ */
+static bool
+npfa_icmp_session(npf_cache_t *npc, nbuf_t *nbuf, void *keyptr)
+{
+	npf_cache_t *key = keyptr;
+	void *n_ptr;
+
+	/* ICMP? Get unique identifiers from ICMP packet. */
+	if (npc->npc_proto != IPPROTO_ICMP) {
+		return false;
+	}
+	KASSERT(npf_iscached(npc, NPC_IP46 | NPC_ICMP));
+	key->npc_info = NPC_ICMP;
+
+	/* Advance to ICMP header. */
+	n_ptr = nbuf_dataptr(nbuf);
+	if ((n_ptr = nbuf_advance(&nbuf, n_ptr, npc->npc_hlen)) == NULL) {
+		return false;
+	}
+
+	/* Fetch into the separate (key) cache. */
+	if (!npf_icmp_uniqid(npc->npc_icmp_type, key, nbuf, n_ptr)) {
+		return false;
+	}
+
+	if (npf_iscached(key, NPC_ICMP_ID)) {
+		/* Construct the key. */
+		key->npc_proto = npc->npc_proto;
+		key->npc_dir = npc->npc_dir;
+		/* Save IP addresses. */
+		key->npc_srcip = npc->npc_srcip;
+		key->npc_dstip = npc->npc_dstip;
+		key->npc_info |= NPC_IP46 | NPC_ADDRS | NPC_PORTS;
+		/* Fake ports with ICMP query IDs. */
+		key->npc_sport = key->npc_icmp_id;
+		key->npc_dport = key->npc_icmp_id;
+	} else {
+		in_addr_t addr;
+		in_port_t port;
+		/*
+		 * Embedded IP packet is the original of "forwards" stream.
+		 * We should imitate the "backwards" stream for inspection.
+		 */
+		KASSERT(npf_iscached(key, NPC_IP46 | NPC_ADDRS | NPC_PORTS));
+		addr = key->npc_srcip;
+		port = key->npc_sport;
+		key->npc_srcip = key->npc_dstip;
+		key->npc_dstip = addr;
+		key->npc_sport = key->npc_dport;
+		key->npc_dport = port;
+	}
+	return true;
+}
+
+/*
+ * npfa_icmp_natin: ALG inbound translation inspector, rewrite IP address
+ * in the IP header, which is embedded in ICMP packet.
+ */
+static bool
+npfa_icmp_natin(npf_cache_t *npc, nbuf_t *nbuf, void *ntptr)
+{
+	void *n_ptr = nbuf_dataptr(nbuf);
+	npf_cache_t enpc;
+	u_int offby;
+	uint16_t cksum;
+
+	/* XXX: Duplicated work. */
+	if (!npfa_icmp_session(npc, nbuf, &enpc)) {
+		return false;
+	}
+	KASSERT(npf_iscached(&enpc, NPC_IP46 | NPC_ADDRS | NPC_PORTS));
+
+	/* Advance to ICMP checksum and fetch it. */
+	offby = npc->npc_hlen + offsetof(struct icmp, icmp_cksum);
+	if (nbuf_advfetch(&nbuf, &n_ptr, offby, sizeof(uint16_t), &cksum)) {
+		return false;
+	}
+
+	/* Save the data for checksum update later. */
+	void *cnbuf = nbuf, *cnptr = n_ptr;
+	uint16_t ecksum = enpc.npc_ipsum;
+
+	/* Advance to the original IP header, which is embedded after ICMP. */
+	offby = offsetof(struct icmp, icmp_ip) -
+	    offsetof(struct icmp, icmp_cksum);
+	if ((n_ptr = nbuf_advance(&nbuf, n_ptr, offby)) == NULL) {
+		return false;
+	}
+
+	/*
+	 * Rewrite source IP address and port of the embedded IP header,
+	 * which represents original packet - therefore passing PFIL_OUT.
+	 */
+	npf_nat_t *nt = ntptr;
+	in_addr_t addr;
+	in_port_t port;
+
+	npf_nat_getorig(nt, &addr, &port);
+
+	if (!npf_rwrip(&enpc, nbuf, n_ptr, PFIL_OUT, addr)) {
+		return false;
+	}
+	if (!npf_rwrport(&enpc, nbuf, n_ptr, PFIL_OUT, port, addr)) {
+		return false;
+	}
+
+	/*
+	 * Fixup and update ICMP checksum.
+	 * Note: npf_rwrip() has updated the IP checksum.
+	 */
+	cksum = npf_fixup32_cksum(cksum, enpc.npc_srcip, addr);
+	cksum = npf_fixup16_cksum(cksum, enpc.npc_sport, port);
+	cksum = npf_fixup16_cksum(cksum, ecksum, enpc.npc_ipsum);
+	/* FIXME: Updated UDP/TCP checksum joins-in too., when != 0, sigh. */
+	if (nbuf_store_datum(cnbuf, cnptr, sizeof(uint16_t), &cksum)){
+		return false;
+	}
+	return true;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/net/npf/npf_ctl.c	Fri Oct 22 09:23:11 2010 +0000
@@ -0,0 +1,499 @@
+/*	$NetBSD: npf_ctl.c,v 1.2.4.2 2010/10/22 09:23:14 uebayasi Exp $	*/
+
+/*-
+ * Copyright (c) 2009-2010 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This material is based upon work partially supported by The
+ * NetBSD Foundation under a contract with Mindaugas Rasiukevicius.
+ *
+ * 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * NPF device control.
+ *
+ * Implementation of (re)loading, construction of tables and rules.
+ * NPF proplib(9) dictionary consumer.
+ *
+ * TODO:
+ * - Consider implementing 'sync' functionality.
+ */
+
+#ifdef _KERNEL
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: npf_ctl.c,v 1.2.4.2 2010/10/22 09:23:14 uebayasi Exp $");
+
+#include <sys/param.h>
+#include <sys/conf.h>
+#include <sys/kernel.h>
+#endif
+
+#include <prop/proplib.h>
+
+#include "npf_ncode.h"
+#include "npf_impl.h"
+
+/*
+ * npfctl_switch: enable or disable packet inspection.
+ */
+int
+npfctl_switch(void *data)
+{
+	const bool onoff = *(int *)data ? true : false;
+	int error;
+
+	if (onoff) {
+		/* Enable: add pfil hooks. */
+		error = npf_register_pfil();
+	} else {
+		/* Disable: remove pfil hooks. */
+		npf_unregister_pfil();
+		error = 0;
+	}
+	return error;
+}
+
+static int
+npf_mk_tables(npf_tableset_t *tblset, prop_array_t tables)
+{
+	prop_object_iterator_t it;
+	prop_dictionary_t tbldict;
+	prop_object_t obj;
+	int error = 0;
+
+	/* Tables - array. */
+	if (prop_object_type(tables) != PROP_TYPE_ARRAY)
+		return EINVAL;
+
+	it = prop_array_iterator(tables);
+	if (it == NULL)
+		return ENOMEM;
+
+	while ((tbldict = prop_object_iterator_next(it)) != NULL) {
+		prop_dictionary_t ent;
+		prop_object_iterator_t eit;
+		prop_array_t entries;
+		npf_table_t *t;
+		u_int tid;
+		int type;
+
+		/* Table - dictionary. */
+		if (prop_object_type(tbldict) != PROP_TYPE_DICTIONARY) {
+			error = EINVAL;
+			break;
+		}
+
+		/* Table ID and type. */
+		obj = prop_dictionary_get(tbldict, "id");
+		tid = (u_int)prop_number_integer_value(obj);
+		obj = prop_dictionary_get(tbldict, "type");
+		type = (int)prop_number_integer_value(obj);
+		/* Validate them. */
+		error = npf_table_check(tblset, tid, type);
+		if (error)
+			break;
+
+		/* Create and insert the table. */
+		t = npf_table_create(tid, type, 1024);	/* XXX */
+		if (t == NULL) {
+			error = ENOMEM;
+			break;
+		}
+		error = npf_tableset_insert(tblset, t);
+		KASSERT(error == 0);
+
+		/* Entries. */
+		entries = prop_dictionary_get(tbldict, "entries");
+		if (prop_object_type(entries) != PROP_TYPE_ARRAY) {
+			error = EINVAL;
+			break;
+		}
+		eit = prop_array_iterator(entries);
+		if (eit == NULL) {
+			error = ENOMEM;
+			break;
+		}
+		while ((ent = prop_object_iterator_next(eit)) != NULL) {
+			in_addr_t addr, mask;	/* XXX: IPv6 */
+
+			/* Address. */
+			obj = prop_dictionary_get(ent, "addr");
+			addr = (in_addr_t)prop_number_integer_value(obj);
+			/* Mask. */
+			obj = prop_dictionary_get(ent, "mask");
+			mask = (in_addr_t)prop_number_integer_value(obj);
+			/* Add a table entry. */
+			error = npf_table_add_v4cidr(tblset, tid, addr, mask);
+			if (error)
+				break;
+		}
+		prop_object_iterator_release(eit);
+		if (error)
+			break;
+	}
+	prop_object_iterator_release(it);
+	/*
+	 * Note: in a case of error, caller will free entire tableset.
+	 */
+	return error;
+}
+
+static void *
+npf_mk_ncode(const void *ncptr, size_t nc_size)
+{
+	int npf_err, errat;
+	void *nc;
+
+	/*
+	 * Allocate and copy n-code.
+	 *
+	 * XXX: Inefficient; consider extending proplib(9) to provide
+	 * interface for custom allocator and avoid copy.
+	 */
+	nc = npf_ncode_alloc(nc_size);
+	if (nc == NULL) {
+		return NULL;
+	}
+	memcpy(nc, ncptr, nc_size);
+	npf_err = npf_ncode_validate(nc, nc_size, &errat);
+	if (npf_err) {
+		npf_ncode_free(nc, nc_size);
+		/* TODO: return error details via proplib */
+		return NULL;
+	}
+	return nc;
+}
+
+static int
+npf_mk_singlerule(prop_dictionary_t rldict,
+    npf_ruleset_t *rlset, npf_rule_t **parent)
+{
+	npf_rule_t *rl;
+	prop_object_t obj;
+	int attr, ifidx;
+	pri_t pri;
+	size_t nc_size;
+	void *nc;
+
+	/* Rule - dictionary. */
+	if (prop_object_type(rldict) != PROP_TYPE_DICTIONARY)
+		return EINVAL;
+
+	/* Attributes (integer). */
+	obj = prop_dictionary_get(rldict, "attributes");
+	attr = prop_number_integer_value(obj);
+
+	/* Priority (integer). */
+	obj = prop_dictionary_get(rldict, "priority");
+	pri = prop_number_integer_value(obj);
+
+	/* Interface ID (integer). */
+	obj = prop_dictionary_get(rldict, "interface");
+	ifidx = prop_number_integer_value(obj);
+
+	/* N-code (binary data). */
+	obj = prop_dictionary_get(rldict, "ncode");
+	if (obj) {
+		const void *ncptr;
+
+		/* Perform n-code validation. */
+		nc_size = prop_data_size(obj);
+		ncptr = prop_data_data_nocopy(obj);
+		if (ncptr == NULL || nc_size > NPF_NCODE_LIMIT) {
+			return EINVAL;
+		}
+		nc = npf_mk_ncode(ncptr, nc_size);
+		if (nc == NULL) {
+			return EINVAL;
+		}
+	} else {
+		/* No n-code. */
+		nc = NULL;
+		nc_size = 0;
+	}
+
+	/* Allocate and setup NPF rule. */
+	rl = npf_rule_alloc(attr, pri, ifidx, nc, nc_size);
+	if (rl == NULL) {
+		if (nc) {
+			npf_ncode_free(nc, nc_size);	/* XXX */
+		}
+		return ENOMEM;
+	}
+	npf_ruleset_insert(rlset, rl);
+	if (parent) {
+		*parent = rl;
+	}
+	return 0;
+}
+
+static int
+npf_mk_rules(npf_ruleset_t *rlset, prop_array_t rules)
+{
+	prop_object_iterator_t it;
+	prop_dictionary_t rldict;
+	int error;
+
+	/* Ruleset - array. */
+	if (prop_object_type(rules) != PROP_TYPE_ARRAY)
+		return EINVAL;
+
+	it = prop_array_iterator(rules);
+	if (it == NULL)
+		return ENOMEM;
+
+	error = 0;
+	while ((rldict = prop_object_iterator_next(it)) != NULL) {
+		prop_object_iterator_t sit;
+		prop_array_t subrules;
+		prop_dictionary_t srldict;
+		npf_rule_t *myrl;
+
+		/* Generate a single rule. */
+		error = npf_mk_singlerule(rldict, rlset, &myrl);
+		if (error)
+			break;
+
+		/* Check for subrules. */
+		subrules = prop_dictionary_get(rldict, "subrules");
+		if (subrules == NULL) {
+			/* No subrules, next.. */
+			continue;
+		}
+		/* Generate subrules, if any. */
+		if (prop_object_type(subrules) != PROP_TYPE_ARRAY) {
+			error = EINVAL;
+			break;
+		}
+		sit = prop_array_iterator(subrules);
+		if (sit == NULL) {
+			error = ENOMEM;
+			break;
+		}
+		while ((srldict = prop_object_iterator_next(sit)) != NULL) {
+			/* For subrule, pass ruleset pointer of parent. */
+			error = npf_mk_singlerule(srldict,
+			    npf_rule_subset(myrl), NULL);
+			if (error)
+				break;
+		}
+		prop_object_iterator_release(sit);
+		if (error)
+			break;
+	}
+	prop_object_iterator_release(it);
+	/*
+	 * Note: in a case of error, caller will free entire ruleset.
+	 */
+	return error;
+}
+
+static int
+npf_mk_natlist(npf_ruleset_t *nset, prop_array_t natlist)
+{
+	prop_object_iterator_t it;
+	prop_dictionary_t natdict;
+	int error;
+
+	/* NAT policies - array. */
+	if (prop_object_type(natlist) != PROP_TYPE_ARRAY)
+		return EINVAL;
+
+	it = prop_array_iterator(natlist);
+	if (it == NULL)
+		return ENOMEM;
+
+	error = 0;
+	while ((natdict = prop_object_iterator_next(it)) != NULL) {
+		prop_object_t obj;
+		npf_natpolicy_t *np;
+		npf_rule_t *rl;
+		in_addr_t taddr;
+		in_port_t tport;
+		int type, flags;
+
+		/* NAT policy - dictionary. */
+		if (prop_object_type(natdict) != PROP_TYPE_DICTIONARY) {
+			error = EINVAL;
+			break;
+		}
+
+		/* Translation type. */
+		obj = prop_dictionary_get(natdict, "type");
+		type = prop_number_integer_value(obj);
+
+		/* Translation type. */
+		obj = prop_dictionary_get(natdict, "flags");
+		flags = prop_number_integer_value(obj);
+
+		/* Translation IP. */
+		obj = prop_dictionary_get(natdict, "translation_ip");
+		taddr = (in_addr_t)prop_number_integer_value(obj);
+
+		/* Translation port (for redirect case). */
+		obj = prop_dictionary_get(natdict, "translation_port");
+		tport = (in_addr_t)prop_number_integer_value(obj);
+
+		/*
+		 * NAT policies are standard rules, plus additional
+		 * information for translation.  Make a rule.
+		 */
+		error = npf_mk_singlerule(natdict, nset, &rl);
+		if (error)
+			break;
+
+		/* Allocate a new NAT policy and assign to the rule. */
+		np = npf_nat_newpolicy(type, flags, taddr, tport);
+		if (np == NULL) {
+			error = ENOMEM;
+			break;
+		}
+		npf_rule_setnat(rl, np);
+	}
+	prop_object_iterator_release(it);
+	/*
+	 * Note: in a case of error, caller will free entire NAT ruleset
+	 * with assigned NAT policies.
+	 */
+	return error;
+}
+
+/*
+ * npfctl_reload: store passed data i.e. update settings, create passed
+ * tables, rules and atomically activate all them.
+ */
+int
+npfctl_reload(u_long cmd, void *data)
+{
+	const struct plistref *pref = data;
+	npf_tableset_t *tblset = NULL;
+	npf_ruleset_t *rlset = NULL;
+	npf_ruleset_t *nset = NULL;
+	prop_dictionary_t dict;
+	prop_array_t natlist, tables, rules;
+	prop_object_t ver;
+	int error;
+
+	/* Retrieve the dictionary. */
+#ifdef _KERNEL
+	error = prop_dictionary_copyin_ioctl(pref, cmd, &dict);
+	if (error)
+		return error;
+#else
+	dict = prop_dictionary_internalize_from_file(data);
+	if (dict == NULL)
+		return EINVAL;
+#endif
+	/* Version. */
+	ver = prop_dictionary_get(dict, "version");
+	if (ver == NULL || prop_number_integer_value(ver) != NPF_VERSION) {
+		error = EINVAL;
+		goto fail;
+	}
+
+	/* XXX: Hard way for now. */
+	(void)npf_session_tracking(false);
+
+	/* NAT policies. */
+	nset = npf_ruleset_create();
+	natlist = prop_dictionary_get(dict, "translation");
+	error = npf_mk_natlist(nset, natlist);
+	if (error)
+		goto fail;
+
+	/* Tables. */
+	tblset = npf_tableset_create();
+	tables = prop_dictionary_get(dict, "tables");
+	error = npf_mk_tables(tblset, tables);
+	if (error)
+		goto fail;
+
+	/* Rules. */
+	rlset = npf_ruleset_create();
+	rules = prop_dictionary_get(dict, "rules");
+	error = npf_mk_rules(rlset, rules);
+	if (error)
+		goto fail;
+
+	/* Flush and reload NAT policies. */
+	npf_nat_reload(nset);
+
+	/*
+	 * Finally, reload the ruleset.  It will also reload the tableset.
+	 * Operation will be performed as a single transaction.
+	 */
+	npf_ruleset_reload(rlset, tblset);
+
+	(void)npf_session_tracking(true);
+
+	/* Done.  Since data is consumed now, we shall not destroy it. */
+	tblset = NULL;
+	rlset = NULL;
+	nset = NULL;
+fail:
+	prop_object_release(dict);
+	/*
+	 * Note: destroy rulesets first, to drop references to the tableset.
+	 */
+	KASSERT(error == 0 || (nset || rlset || tblset));
+	if (nset) {
+		npf_ruleset_destroy(nset);
+	}
+	if (rlset) {
+		npf_ruleset_destroy(rlset);
+	}
+	if (tblset) {
+		npf_tableset_destroy(tblset);
+	}
+	return error;
+}
+
+/*
+ * npfctl_table: add, remove or query entries in the specified table.
+ *
+ * For maximum performance, interface is avoiding proplib(3)'s overhead.
+ */
+int
+npfctl_table(void *data)
+{
+	npf_ioctl_table_t *nct = data;
+	int error;
+
+	switch (nct->nct_action) {
+	case NPF_IOCTL_TBLENT_ADD:
+		error = npf_table_add_v4cidr(NULL, nct->nct_tid,
+		    nct->nct_addr, nct->nct_mask);
+		break;
+	case NPF_IOCTL_TBLENT_REM:
+		error = npf_table_rem_v4cidr(NULL, nct->nct_tid,
+		    nct->nct_addr, nct->nct_mask);
+		break;
+	default:
+		/* XXX */
+		error = npf_table_match_v4addr(nct->nct_tid, nct->nct_addr);
+		if (error) {
+			error = EINVAL;
+		}
+	}
+	return error;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/net/npf/npf_handler.c	Fri Oct 22 09:23:11 2010 +0000
@@ -0,0 +1,227 @@
+/*	$NetBSD: npf_handler.c,v 1.3.2.2 2010/10/22 09:23:14 uebayasi Exp $	*/
+
+/*-
+ * Copyright (c) 2009-2010 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This material is based upon work partially supported by The
+ * NetBSD Foundation under a contract with Mindaugas Rasiukevicius.
+ *
+ * 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * NPF packet handler.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: npf_handler.c,v 1.3.2.2 2010/10/22 09:23:14 uebayasi Exp $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+
+#include <sys/mbuf.h>
+#include <sys/mutex.h>
+#include <net/if.h>
+#include <net/pfil.h>
+#include <sys/socketvar.h>
+
+#include "npf_impl.h"
+
+/*
+ * If npf_ph_if != NULL, pfil hooks are registers.  If NULL, not registered.
+ * Used to check the state.  Locked by: softnet_lock + KERNEL_LOCK (XXX).
+ */
+static struct pfil_head *	npf_ph_if = NULL;
+static struct pfil_head *	npf_ph_inet = NULL;
+
+static bool			default_pass = true;
+
+int	npf_packet_handler(void *, struct mbuf **, struct ifnet *, int);
+
+/*
+ * npf_ifhook: hook handling interface changes.
+ */
+static int
+npf_ifhook(void *arg, struct mbuf **mp, struct ifnet *ifp, int di)
+{
+
+	return 0;
+}
+
+/*
+ * npf_packet_handler: main packet handling routine for layer 3.
+ *
+ * Note: packet flow and inspection logic is in strict order.
+ */
+int
+npf_packet_handler(void *arg, struct mbuf **mp, struct ifnet *ifp, int di)
+{
+	nbuf_t *nbuf = *mp;
+	npf_cache_t npc;
+	npf_session_t *se;
+	npf_rule_t *rl;
+	bool keepstate;
+	int retfl, error;
+
+	/*
+	 * Initialise packet information cache.
+	 * Note: it is enough to clear the info bits.
+	 */
+	npc.npc_info = 0;
+	error = 0;
+	retfl = 0;
+
+	/* Inspect the list of sessions. */
+	se = npf_session_inspect(&npc, nbuf, ifp, di);
+
+	/* If "passing" session found - skip the ruleset inspection. */
+	if (se && npf_session_pass(se)) {
+		goto pass;
+	}
+
+	/* Inspect the ruleset using this packet. */
+	rl = npf_ruleset_inspect(&npc, nbuf, ifp, di, NPF_LAYER_3);
+	if (rl == NULL) {
+		if (default_pass) {
+			goto pass;
+		}
+		error = ENETUNREACH;
+		goto out;
+	}
+
+	/* Apply the rule. */
+	error = npf_rule_apply(&npc, rl, &keepstate, &retfl);
+	if (error) {
+		goto out;
+	}
+
+	/* Establish a "pass" session, if required. */
+	if (keepstate && !se) {
+		se = npf_session_establish(&npc, NULL, di);
+		if (se == NULL) {
+			error = ENOMEM;
+			goto out;
+		}
+		npf_session_setpass(se);
+	}
+pass:
+	KASSERT(error == 0);
+	/*
+	 * Perform NAT.
+	 */
+	error = npf_do_nat(&npc, se, nbuf, ifp, di);
+out:
+	/* Release reference on session. */
+	if (se != NULL) {
+		npf_session_release(se);
+	}
+
+	/*
+	 * If error is set - drop the packet.
+	 * Normally, ENETUNREACH is used for "block".
+	 */
+	if (error) {
+		/*
+		 * Depending on flags and protocol, return TCP reset (RST)
+		 * or ICMP destination unreachable
+		 */
+		if (retfl) {
+			npf_return_block(&npc, nbuf, retfl);
+		}
+		m_freem(*mp);
+		*mp = NULL;
+	} else {
+		/*
+		 * XXX: Disable for now, it will be set accordingly later,
+		 * for optimisations (to reduce inspection).
+		 */
+		(*mp)->m_flags &= ~M_CANFASTFWD;
+	}
+	return error;
+}
+
+/*
+ * npf_register_pfil: register pfil(9) hooks.
+ */
+int
+npf_register_pfil(void)
+{
+	int error;
+
+	mutex_enter(softnet_lock);
+	KERNEL_LOCK(1, NULL);
+
+	/* Check if pfil hooks are not already registered. */
+	if (npf_ph_if) {
+		error = EEXIST;
+		goto fail;
+	}
+
+	/* Capture point of any activity in interfaces and IP layer. */
+	npf_ph_if = pfil_head_get(PFIL_TYPE_IFNET, 0);
+	npf_ph_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
+	if (npf_ph_if == NULL || npf_ph_inet == NULL) {
+		npf_ph_if = NULL;
+		error = ENOENT;
+		goto fail;
+	}
+
+	/* Interface re-config or attach/detach hook. */
+	error = pfil_add_hook(npf_ifhook, NULL,
+	    PFIL_WAITOK | PFIL_IFADDR | PFIL_IFNET, npf_ph_if);
+	KASSERT(error == 0);
+
+	/* Packet IN/OUT handler on all interfaces and IP layer. */
+	error = pfil_add_hook(npf_packet_handler, NULL,
+	    PFIL_WAITOK | PFIL_ALL, npf_ph_inet);
+	KASSERT(error == 0);
+
+fail:
+	KERNEL_UNLOCK_ONE(NULL);
+	mutex_exit(softnet_lock);
+
+	return error;
+}
+
+/*
+ * npf_unregister: unregister pfil(9) hooks.
+ */
+void
+npf_unregister_pfil(void)
+{
+
+	mutex_enter(softnet_lock);
+	KERNEL_LOCK(1, NULL);
+
+	if (npf_ph_if) {
+		(void)pfil_remove_hook(npf_packet_handler, NULL,
+		    PFIL_ALL, npf_ph_inet);
+		(void)pfil_remove_hook(npf_ifhook, NULL,
+		    PFIL_IFADDR | PFIL_IFNET, npf_ph_if);
+
+		npf_ph_if = NULL;
+	}
+
+	KERNEL_UNLOCK_ONE(NULL);
+	mutex_exit(softnet_lock);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/net/npf/npf_impl.h	Fri Oct 22 09:23:11 2010 +0000
@@ -0,0 +1,213 @@
+/*	$NetBSD: npf_impl.h,v 1.3.4.2 2010/10/22 09:23:14 uebayasi Exp $	*/
+
+/*-
+ * Copyright (c) 2009-2010 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This material is based upon work partially supported by The
+ * NetBSD Foundation under a contract with Mindaugas Rasiukevicius.
+ *
+ * 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Private NPF structures and interfaces.
+ * For internal use within NPF core only.
+ */
+
+#ifndef _NPF_IMPL_H_
+#define _NPF_IMPL_H_
+
+#include <sys/rbtree.h>
+#include <sys/hash.h>
+#include <sys/queue.h>
+#include <sys/types.h>
+#include <sys/rwlock.h>
+
+#include "npf.h"
+#include "npf_ncode.h"
+
+#ifdef _NPF_TESTING
+#include "testing.h"
+#endif
+
+/*
+ * STRUCTURE DECLARATIONS.
+ *
+ * Note: ruleset interface declarations are public.
+ */
+
+struct npf_nat;
+struct npf_session;
+
+typedef struct npf_nat		npf_nat_t;
+typedef struct npf_alg		npf_alg_t;
+typedef struct npf_natpolicy	npf_natpolicy_t;
+typedef struct npf_session	npf_session_t;
+
+struct npf_tblent;
+struct npf_table;
+
+typedef struct npf_tblent	npf_tblent_t;
+typedef struct npf_table	npf_table_t;
+
+typedef npf_table_t *		npf_tableset_t;
+
+/*
+ * DEFINITIONS.
+ */
+
+typedef bool	(*npf_algfunc_t)(npf_cache_t *, void *, void *);
+
+#define	NPF_NCODE_LIMIT		1024
+#define	NPF_TABLE_SLOTS		32
+
+/*
+ * INTERFACES.
+ */
+
+/* NPF control. */
+int		npfctl_switch(void *);
+int		npfctl_reload(u_long, void *);
+int		npfctl_table(void *);
+
+/* Packet filter hooks. */
+int		npf_register_pfil(void);
+void		npf_unregister_pfil(void);
+
+/* Protocol helpers. */
+bool		npf_ip4_proto(npf_cache_t *, nbuf_t *, void *);
+bool		npf_fetch_ip4addrs(npf_cache_t *, nbuf_t *, void *);
+bool		npf_fetch_ports(npf_cache_t *, nbuf_t *, void *, const int);
+bool		npf_fetch_tcpfl(npf_cache_t *, nbuf_t *, void *);
+bool		npf_fetch_icmp(npf_cache_t *, nbuf_t *, void *);
+bool		npf_cache_all(npf_cache_t *, nbuf_t *);
+
+bool		npf_rwrport(npf_cache_t *, nbuf_t *, void *, const int,
+		    in_port_t, in_addr_t);
+bool		npf_rwrip(npf_cache_t *, nbuf_t *, void *, const int, in_addr_t);
+
+uint16_t	npf_fixup16_cksum(uint16_t, uint16_t, uint16_t);
+uint16_t	npf_fixup32_cksum(uint16_t, uint32_t, uint32_t);
+
+void		npf_return_block(npf_cache_t *, nbuf_t *, const int);
+
+/* Complex instructions. */
+int		npf_match_ether(nbuf_t *, int, int, uint16_t, uint32_t *);
+int		npf_match_ip4table(npf_cache_t *, nbuf_t *, void *,
+		    const int, const u_int);
+int		npf_match_ip4mask(npf_cache_t *, nbuf_t *, void *,
+		    const int, in_addr_t, in_addr_t);
+int		npf_match_tcp_ports(npf_cache_t *, nbuf_t *, void *,
+		    const int, const uint32_t);
+int		npf_match_udp_ports(npf_cache_t *, nbuf_t *, void *,
+		    const int, const uint32_t);
+int		npf_match_icmp4(npf_cache_t *, nbuf_t *, void *, const uint32_t);
+int		npf_match_tcpfl(npf_cache_t *, nbuf_t *, void *, const uint32_t);
+
+/* Tableset interface. */
+int		npf_tableset_sysinit(void);
+void		npf_tableset_sysfini(void);
+
+npf_tableset_t *npf_tableset_create(void);
+void		npf_tableset_destroy(npf_tableset_t *);
+int		npf_tableset_insert(npf_tableset_t *, npf_table_t *);
+npf_tableset_t *npf_tableset_reload(npf_tableset_t *);
+
+npf_table_t *	npf_table_create(u_int, int, size_t);
+void		npf_table_destroy(npf_table_t *);
+void		npf_table_ref(npf_table_t *);
+void		npf_table_unref(npf_table_t *);
+
+npf_table_t *	npf_table_get(npf_tableset_t *, u_int);
+void		npf_table_put(npf_table_t *);
+int		npf_table_check(npf_tableset_t *, u_int, int);
+int		npf_table_add_v4cidr(npf_tableset_t *, u_int,
+		    in_addr_t, in_addr_t);
+int		npf_table_rem_v4cidr(npf_tableset_t *, u_int,
+		    in_addr_t, in_addr_t);
+int		npf_table_match_v4addr(u_int, in_addr_t);
+
+/* Ruleset interface. */
+int		npf_ruleset_sysinit(void);
+void		npf_ruleset_sysfini(void);
+
+npf_ruleset_t *	npf_ruleset_create(void);
+void		npf_ruleset_destroy(npf_ruleset_t *);
+void		npf_ruleset_insert(npf_ruleset_t *, npf_rule_t *);
+void		npf_ruleset_reload(npf_ruleset_t *, npf_tableset_t *);
+
+npf_rule_t *	npf_ruleset_match(npf_ruleset_t *, npf_cache_t *, nbuf_t *,
+		    struct ifnet *, const int, const int);
+npf_rule_t *	npf_ruleset_inspect(npf_cache_t *, nbuf_t *,
+		    struct ifnet *, const int, const int);
+int		npf_rule_apply(const npf_cache_t *, npf_rule_t *, bool *, int *);
+npf_ruleset_t *	npf_rule_subset(npf_rule_t *);
+
+npf_natpolicy_t *npf_rule_getnat(const npf_rule_t *);
+void		npf_rule_setnat(npf_rule_t *, npf_natpolicy_t *);
+
+/* State handling interface. */
+int		npf_session_sysinit(void);
+void		npf_session_sysfini(void);
+int		npf_session_tracking(bool);
+
+npf_session_t *	npf_session_inspect(npf_cache_t *, nbuf_t *,
+		    struct ifnet *, const int);
+npf_session_t *	npf_session_establish(const npf_cache_t *,
+		    npf_nat_t *, const int);
+void		npf_session_release(npf_session_t *);
+bool		npf_session_pass(const npf_session_t *);
+void		npf_session_setpass(npf_session_t *);
+void		npf_session_link(npf_session_t *, npf_session_t *);
+npf_nat_t *	npf_session_retnat(npf_session_t *, const int, bool *);
+
+/* NAT. */
+void		npf_nat_sysinit(void);
+void		npf_nat_sysfini(void);
+npf_natpolicy_t *npf_nat_newpolicy(int, int, in_addr_t, in_port_t);
+void		npf_nat_freepolicy(npf_natpolicy_t *);
+void		npf_nat_flush(void);
+void		npf_nat_reload(npf_ruleset_t *);
+
+int		npf_do_nat(npf_cache_t *, npf_session_t *, nbuf_t *,
+		    struct ifnet *, const int);
+void		npf_nat_expire(npf_nat_t *);
+void		npf_nat_getorig(npf_nat_t *, in_addr_t *, in_port_t *);
+void		npf_nat_setalg(npf_nat_t *, npf_alg_t *, uintptr_t);
+
+/* ALG interface. */
+void		npf_alg_sysinit(void);
+void		npf_alg_sysfini(void);
+npf_alg_t *	npf_alg_register(npf_algfunc_t, npf_algfunc_t,
+		    npf_algfunc_t, npf_algfunc_t);
+int		npf_alg_unregister(npf_alg_t *);
+void		npf_alg_match(npf_cache_t *, nbuf_t *, npf_nat_t *);
+void		npf_alg_exec(npf_cache_t *, nbuf_t *, npf_nat_t *, const int );
+bool		npf_alg_sessionid(npf_cache_t *, nbuf_t *, npf_cache_t *);
+
+/* Debugging routines. */
+void		npf_rulenc_dump(npf_rule_t *);
+void		npf_sessions_dump(void);
+void		npf_nat_dump(npf_nat_t *);
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/net/npf/npf_inet.c	Fri Oct 22 09:23:11 2010 +0000
@@ -0,0 +1,386 @@
+/*	$NetBSD: npf_inet.c,v 1.3.4.2 2010/10/22 09:23:15 uebayasi Exp $	*/
+
+/*-
+ * Copyright (c) 2009-2010 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This material is based upon work partially supported by The
+ * NetBSD Foundation under a contract with Mindaugas Rasiukevicius.
+ *
+ * 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Various procotol related helper routines.
+ */
+
+#ifdef _KERNEL
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: npf_inet.c,v 1.3.4.2 2010/10/22 09:23:15 uebayasi Exp $");
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+
+#include <netinet/in_systm.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/tcp.h>
+#include <netinet/udp.h>
+#include <netinet/ip_icmp.h>
+
+#include <net/if.h>
+#include <net/ethertypes.h>
+#include <net/if_ether.h>
+#endif
+#include <net/pfil.h>
+
+#include "npf_impl.h"
+
+/*
+ * npf_fixup{16,32}_cksum: update IPv4 checksum.
+ */
+
+uint16_t
+npf_fixup16_cksum(uint16_t cksum, uint16_t odatum, uint16_t ndatum)
+{
+	uint32_t sum;
+
+	/*
+	 * RFC 1624:
+	 *	HC' = ~(~HC + ~m + m')
+	 */
+	sum = ~ntohs(cksum) & 0xffff;
+	sum += (~ntohs(odatum) & 0xffff) + ntohs(ndatum);
+	sum = (sum >> 16) + (sum & 0xffff);
+	sum += (sum >> 16);
+
+	return htons(~sum & 0xffff);
+}
+
+uint16_t
+npf_fixup32_cksum(uint16_t cksum, uint32_t odatum, uint32_t ndatum)
+{
+
+	cksum = npf_fixup16_cksum(cksum, odatum & 0xffff, ndatum & 0xffff);
+	cksum = npf_fixup16_cksum(cksum, odatum >> 16, ndatum >> 16);
+	return cksum;
+}
+
+/*
+ * npf_ip4_proto: check IPv4 header length and match protocol number.
+ *
+ * => Returns pointer to protocol header or NULL on failure.
+ * => Stores protocol number in the cache.
+ * => Updates nbuf pointer to header's nbuf.
+ */
+bool
+npf_ip4_proto(npf_cache_t *npc, nbuf_t *nbuf, void *n_ptr)
+{
+	u_int hlen, offby;
+	uint8_t val8;
+	int error;
+
+	/* IPv4 header: check IP version and header length. */
+	error = nbuf_fetch_datum(nbuf, n_ptr, sizeof(uint8_t), &val8);
+	if (error || (val8 >> 4) != IPVERSION)
+		return false;
+	hlen = (val8 & 0xf) << 2;
+	if (hlen < sizeof(struct ip))
+		return false;
+
+	/* IPv4 header: check fragment offset. */
+	offby = offsetof(struct ip, ip_off);
+	error = nbuf_advfetch(&nbuf, &n_ptr, offby, sizeof(uint8_t), &val8);
+	if (error || (val8 & ~htons(IP_DF | IP_RF)))
+		return false;
+
+	/* Get and match protocol. */
+	KASSERT(offsetof(struct ip, ip_p) > offby);
+	offby = offsetof(struct ip, ip_p) - offby;
+	if (nbuf_advfetch(&nbuf, &n_ptr, offby, sizeof(uint8_t), &val8))
+		return false;
+
+	/* IP checksum. */
+	offby = offsetof(struct ip, ip_sum) - offsetof(struct ip, ip_p);
+	if (nbuf_advfetch(&nbuf, &n_ptr, offby,
+	    sizeof(uint16_t), &npc->npc_ipsum))
+		return false;
+
+	/* Cache: IPv4, protocol, header length. */
+	npc->npc_info |= NPC_IP46;
+	npc->npc_proto = val8;
+	npc->npc_hlen = hlen;
+	return true;
+}
+
+/*
+ * npf_fetch_ip4addrs: fetch source and destination address from IPv4 header.
+ *
+ * => Stores both source and destination addresses into the cache.
+ */
+bool
+npf_fetch_ip4addrs(npf_cache_t *npc, nbuf_t *nbuf, void *n_ptr)
+{
+	in_addr_t *src = &npc->npc_srcip, *dst = &npc->npc_dstip;
+	u_int offby;
+
+	/* Source address. */
+	offby = offsetof(struct ip, ip_src);
+	if (nbuf_advfetch(&nbuf, &n_ptr, offby, sizeof(in_addr_t), src))
+		return false;
+
+	/* Destination address. */
+	offby = offsetof(struct ip, ip_dst) - offby;
+	if (nbuf_advfetch(&nbuf, &n_ptr, offby, sizeof(in_addr_t), dst))
+		return false;
+
+	/* Both addresses are cached. */
+	npc->npc_info |= NPC_ADDRS;
+	return true;
+}
+
+/*
+ * npf_fetch_ports: fetch ports from either TCP or UDP header.
+ *
+ * => Stores both source and destination ports into the cache.
+ */
+bool
+npf_fetch_ports(npf_cache_t *npc, nbuf_t *nbuf, void *n_ptr, const int proto)
+{
+	u_int dst_off;
+
+	/* Perform checks, advance to TCP/UDP header. */
+	if (!npf_iscached(npc, NPC_IP46) && !npf_ip4_proto(npc, nbuf, n_ptr))
+		return false;
+	n_ptr = nbuf_advance(&nbuf, n_ptr, npc->npc_hlen);
+	if (n_ptr == NULL || npc->npc_proto != proto)
+		return false;
+
+	/*
+	 * TCP/UDP header: fetch source and destination ports.  For both
+	 * protocols offset of the source port offset is 0.
+	 */
+	CTASSERT(offsetof(struct tcphdr, th_sport) == 0);
+	CTASSERT(offsetof(struct udphdr, uh_sport) == 0);
+	if (proto == IPPROTO_TCP) {
+		dst_off = offsetof(struct tcphdr, th_dport);
+	} else {
+		KASSERT(proto == IPPROTO_UDP);
+		dst_off = offsetof(struct udphdr, uh_dport);
+	}
+
+	if (nbuf_fetch_datum(nbuf, n_ptr, sizeof(in_port_t), &npc->npc_sport))
+		return false;
+	if ((n_ptr = nbuf_advance(&nbuf, n_ptr, dst_off)) == NULL)
+		return false;
+	if (nbuf_fetch_datum(nbuf, n_ptr, sizeof(in_port_t), &npc->npc_dport))
+		return false;
+
+	/* Both ports are cached. */
+	npc->npc_info |= NPC_PORTS;
+	return true;
+}
+
+/*
+ * npf_fetch_icmp: fetch ICMP code, type and possible query ID.
+ *
+ * => Stores both all fetched items into the cache.
+ */
+bool
+npf_fetch_icmp(npf_cache_t *npc, nbuf_t *nbuf, void *n_ptr)
+{
+	uint8_t *type = &npc->npc_icmp_type, *code = &npc->npc_icmp_code;
+	u_int offby;
+
+	KASSERT(npf_iscached(npc, NPC_IP46));
+
+	/* ICMP type. */
+	offby = npc->npc_hlen;
+	CTASSERT(offsetof(struct icmp, icmp_type) == 0);
+	if (nbuf_advfetch(&nbuf, &n_ptr, offby, sizeof(uint8_t), type))
+		return false;
+
+	/* ICMP code. */
+	offby = offsetof(struct icmp, icmp_code);
+	if (nbuf_advfetch(&nbuf, &n_ptr, offby, sizeof(uint8_t), code))
+		return false;
+
+	/* Mark as cached. */
+	npc->npc_info |= NPC_ICMP;
+	return true;
+}
+
+/*
+ * npf_fetch_tcpfl: fetch TCP flags and store into the cache.
+ */
+bool
+npf_fetch_tcpfl(npf_cache_t *npc, nbuf_t *nbuf, void *n_ptr)
+{
+	const u_int offby = npc->npc_hlen + offsetof(struct tcphdr, th_flags);
+	uint8_t *tcpfl = &npc->npc_tcp_flags;
+
+	if (nbuf_advfetch(&nbuf, &n_ptr, offby, sizeof(uint8_t), tcpfl)) {
+		return false;
+	}
+	return true;
+}
+
+/*
+ * npf_cache_all: general routine to cache all relevant IPv4 and
+ * TCP, UDP or ICMP data.
+ */
+bool
+npf_cache_all(npf_cache_t *npc, nbuf_t *nbuf)
+{
+	void *n_ptr = nbuf_dataptr(nbuf);
+
+	/* IPv4: get protocol, source and destination addresses. */
+	if (!npf_iscached(npc, NPC_IP46) && !npf_ip4_proto(npc, nbuf, n_ptr)) {
+		return false;
+	}
+	if (!npf_iscached(npc, NPC_ADDRS) &&
+	    !npf_fetch_ip4addrs(npc, nbuf, n_ptr)) {
+		return false;
+	}
+	switch (npc->npc_proto) {
+	case IPPROTO_TCP:
+		/* TCP flags. */
+		if (!npf_fetch_tcpfl(npc, nbuf, n_ptr)) {
+			return false;
+		}
+		/* FALLTHROUGH */
+
+	case IPPROTO_UDP:
+		/* Fetch TCP/UDP ports. */
+		return npf_fetch_ports(npc, nbuf, n_ptr, npc->npc_proto);
+
+	case IPPROTO_ICMP:
+		/* Fetch ICMP data. */
+		return npf_fetch_icmp(npc, nbuf, n_ptr);
+	}
+	return false;
+}
+
+/*
+ * npf_rwrport: rewrite required TCP/UDP port and update checksum.
+ */
+bool
+npf_rwrport(npf_cache_t *npc, nbuf_t *nbuf, void *n_ptr, const int di,
+    in_port_t port, in_addr_t naddr)
+{
+	const int proto = npc->npc_proto;
+	u_int offby, toff;
+	in_addr_t oaddr;
+	in_port_t oport;
+	uint16_t cksum;
+
+	KASSERT(npf_iscached(npc, NPC_PORTS));
+	KASSERT(proto == IPPROTO_TCP || proto == IPPROTO_UDP);
+
+	offby = npc->npc_hlen;
+
+	if (di == PFIL_OUT) {
+		/* Offset to the source port is zero. */
+		CTASSERT(offsetof(struct tcphdr, th_sport) == 0);
+		CTASSERT(offsetof(struct udphdr, uh_sport) == 0);
+		if (proto == IPPROTO_TCP) {
+			toff = offsetof(struct tcphdr, th_sum);
+		} else {
+			toff = offsetof(struct udphdr, uh_sum);
+		}
+		oaddr = npc->npc_srcip;
+		oport = npc->npc_sport;
+	} else {
+		/* Calculate offset to destination port and checksum. */
+		u_int poff;
+		if (proto == IPPROTO_TCP) {
+			poff = offsetof(struct tcphdr, th_dport);
+			toff = offsetof(struct tcphdr, th_sum) - poff;
+		} else {
+			poff = offsetof(struct udphdr, uh_dport);
+			toff = offsetof(struct udphdr, uh_sum) - poff;
+		}
+		oaddr = npc->npc_dstip;
+		oport = npc->npc_dport;
+		offby += poff;
+	}
+
+	/* Advance and rewrite port. */
+	if ((n_ptr = nbuf_advance(&nbuf, n_ptr, offby)) == NULL)
+		return false;
+	if (nbuf_store_datum(nbuf, n_ptr, sizeof(in_port_t), &port))
+		return false;
+
+	/* Advance and update TCP/UDP checksum. */
+	if (nbuf_advfetch(&nbuf, &n_ptr, toff, sizeof(uint16_t), &cksum)) {
+		return false;
+	}
+	if (__predict_true(cksum || proto == IPPROTO_TCP)) {
+		cksum = npf_fixup32_cksum(cksum, oaddr, naddr);
+		cksum = npf_fixup16_cksum(cksum, oport, port);
+		if (nbuf_store_datum(nbuf, n_ptr, sizeof(uint16_t), &cksum))
+			return false;
+	}
+	return true;
+}
+
+/*
+ * npf_rwrip: rewrite required IP address and update checksum.
+ */
+bool
+npf_rwrip(npf_cache_t *npc, nbuf_t *nbuf, void *n_ptr, const int di,
+    in_addr_t addr)
+{
+	u_int offby;
+	in_addr_t oaddr;
+
+	KASSERT(npf_iscached(npc, NPC_IP46 | NPC_ADDRS));
+
+	/* Advance to the checksum in IP header and fetch it. */
+	offby = offsetof(struct ip, ip_sum);
+	if ((n_ptr = nbuf_advance(&nbuf, n_ptr, offby)) == NULL)
+		return false;
+
+	if (di == PFIL_OUT) {
+		/* Rewrite source address, if outgoing. */
+		offby = offsetof(struct ip, ip_src) - offby;
+		oaddr = npc->npc_srcip;
+	} else {
+		/* Rewrite destination, if incoming. */
+		offby = offsetof(struct ip, ip_dst) - offby;
+		oaddr = npc->npc_dstip;
+	}
+
+	/* Write new IP checksum (it is acceptable to do this earlier). */
+	uint16_t cksum = npf_fixup32_cksum(npc->npc_ipsum, oaddr, addr);
+	if (nbuf_store_datum(nbuf, n_ptr, sizeof(uint16_t), &cksum))
+		return false;
+
+	/* Advance to address and rewrite it. */
+	if ((n_ptr = nbuf_advance(&nbuf, n_ptr, offby)) == NULL)
+		return false;
+	if (nbuf_store_datum(nbuf, n_ptr, sizeof(in_addr_t), &addr))
+		return false;
+
+	npc->npc_ipsum = cksum;
+	return true;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/net/npf/npf_instr.c	Fri Oct 22 09:23:11 2010 +0000
@@ -0,0 +1,230 @@
+/*	$NetBSD: npf_instr.c,v 1.3.4.2 2010/10/22 09:23:15 uebayasi Exp $	*/
+
+/*-
+ * Copyright (c) 2009-2010 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This material is based upon work partially supported by The
+ * NetBSD Foundation under a contract with Mindaugas Rasiukevicius.
+ *
+ * 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * NPF complex instructions.
+ */
+
+#ifdef _KERNEL
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: npf_instr.c,v 1.3.4.2 2010/10/22 09:23:15 uebayasi Exp $");
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+
+#include <net/if.h>
+#include <net/ethertypes.h>
+#include <net/if_ether.h>
+#include <netinet/in_systm.h>
+#include <netinet/in.h>
+#endif
+
+#include "npf_impl.h"
+
+#define	NPF_PORTRANGE_MATCH(r, p)	(p >= (r >> 16) && p <= (r & 0xffff))
+
+/*
+ * npf_match_ether: find and check Ethernet and possible VLAN headers.
+ *
+ * => Stores value in to advance to layer 3 header (usually, IPv4).
+ * => Returns zero on success or -1 on failure.
+ */
+int
+npf_match_ether(nbuf_t *nbuf, int sd, int _res, uint16_t ethertype, uint32_t *r)
+{
+	void *n_ptr = nbuf_dataptr(nbuf);
+	u_int offby;
+	uint16_t val16;
+	bool vlan;
+
+	vlan = false;
+	*r = 0;
+
+	/* Ethernet header: check EtherType. */
+	offby = offsetof(struct ether_header, ether_type);
+again:
+	if (nbuf_advfetch(&nbuf, &n_ptr, offby, sizeof(uint16_t), &val16)) {
+		return -1;
+	}
+	val16 = ntohs(val16);
+	*r += offby;
+
+	/* Handle VLAN tags. */
+	if (val16 == ETHERTYPE_VLAN && !vlan) {
+		offby = sizeof(uint32_t);
+		vlan = true;
+		goto again;
+	}
+	if (val16 != ETHERTYPE_IP) {
+		return -1;
+	}
+
+	*r += ETHER_TYPE_LEN;
+	return 0;
+}
+
+/*
+ * npf_match_ip4table: match IPv4 address against NPF table.
+ */
+int
+npf_match_ip4table(npf_cache_t *npc, nbuf_t *nbuf, void *n_ptr,
+    const int sd, const u_int tid)
+{
+	in_addr_t ip4addr;
+
+	if (!npf_iscached(npc, NPC_ADDRS)) {
+		if (!npf_fetch_ip4addrs(npc, nbuf, n_ptr)) {
+			return -1;
+		}
+		KASSERT(npf_iscached(npc, NPC_ADDRS));
+	}
+	ip4addr = sd ? npc->npc_srcip : npc->npc_dstip;
+
+	/* Match address against NPF table. */
+	return npf_table_match_v4addr(tid, ip4addr);
+}
+
+/*
+ * npf_match_ip4mask: match IPv4 address against netaddr/subnet.
+ */
+int
+npf_match_ip4mask(npf_cache_t *npc, nbuf_t *nbuf, void *n_ptr,
+    const int sd, in_addr_t netaddr, in_addr_t subnet)
+{
+	in_addr_t ip4addr;
+
+	if (!npf_iscached(npc, NPC_ADDRS)) {
+		if (!npf_fetch_ip4addrs(npc, nbuf, n_ptr)) {
+			return -1;
+		}
+		KASSERT(npf_iscached(npc, NPC_ADDRS));
+	}
+	ip4addr = sd ? npc->npc_srcip : npc->npc_dstip;
+
+	return (ip4addr & subnet) == netaddr ? 0 : -1;
+}
+
+/*
+ * npf_match_tcp_ports: match TCP port in header against the range.
+ */
+int
+npf_match_tcp_ports(npf_cache_t *npc, nbuf_t *nbuf, void *n_ptr,
+    const int sd, const uint32_t prange)
+{
+	in_port_t p;
+
+	if (!npf_iscached(npc, NPC_PORTS)) {
+		if (!npf_fetch_ports(npc, nbuf, n_ptr, IPPROTO_TCP)) {
+			return -1;
+		}
+		KASSERT(npf_iscached(npc, NPC_PORTS));
+	}
+	p = sd ? npc->npc_sport : npc->npc_dport;
+
+	/* Match against the port range. */
+	return NPF_PORTRANGE_MATCH(prange, p) ? 0 : -1;
+}
+
+/*
+ * npf_match_udp_ports: match UDP port in header against the range.
+ */
+int
+npf_match_udp_ports(npf_cache_t *npc, nbuf_t *nbuf, void *n_ptr,
+    const int sd, const uint32_t prange)
+{
+	in_port_t p;
+
+	if (!npf_iscached(npc, NPC_PORTS)) {
+		if (!npf_fetch_ports(npc, nbuf, n_ptr, IPPROTO_UDP)) {
+			return -1;
+		}
+		KASSERT(npf_iscached(npc, NPC_PORTS));
+	}
+	p = sd ? npc->npc_sport : npc->npc_dport;
+
+	/* Match against the port range. */
+	return NPF_PORTRANGE_MATCH(prange, p) ? 0 : -1;
+}
+
+/*
+ * npf_match_icmp4: match ICMPv4 packet.
+ */
+int
+npf_match_icmp4(npf_cache_t *npc, nbuf_t *nbuf, void *n_ptr, const uint32_t tc)
+{
+
+	if (!npf_iscached(npc, NPC_ICMP)) {
+		/* Perform checks, advance to ICMP header. */
+		if (!npf_iscached(npc, NPC_IP46) &&
+		    !npf_ip4_proto(npc, nbuf, n_ptr)) {
+			return -1;
+		}
+		n_ptr = nbuf_advance(&nbuf, n_ptr, npc->npc_hlen);
+		if (n_ptr == NULL || npc->npc_proto != IPPROTO_ICMP) {
+			return -1;
+		}
+		if (!npf_fetch_icmp(npc, nbuf, n_ptr)) {
+			return -1;
+		}
+		KASSERT(npf_iscached(npc, NPC_ICMP));
+	}
+	/* Match code/type, if required. */
+	if ((1 << 31) & tc) {
+		const uint8_t type = (tc >> 8) & 0xff;
+		if (type != npc->npc_icmp_type) {
+			return -1;
+		}
+	}
+	if ((1 << 30) & tc) {
+		const uint8_t code = tc & 0xff;
+		if (code != npc->npc_icmp_code) {
+			return -1;
+		}
+	}
+	return 0;
+}
+
+/*
+ * npf_match_tcpfl: match TCP flags.
+ */
+int
+npf_match_tcpfl(npf_cache_t *npc, nbuf_t *nbuf, void *n_ptr, const uint32_t fl)
+{
+	const uint8_t tcpfl = (fl >> 8) & 0xff, mask = fl & 0xff;
+
+	if (!npf_iscached(npc, NPC_IP46) && !npf_ip4_proto(npc, nbuf, n_ptr)) {
+		return -1;
+	}
+	if (!npf_fetch_tcpfl(npc, nbuf, n_ptr)) {
+		return -1;
+	}
+	return ((npc->npc_tcp_flags & mask) == tcpfl) ? 0 : -1;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/net/npf/npf_mbuf.c	Fri Oct 22 09:23:11 2010 +0000
@@ -0,0 +1,252 @@
+/*	$NetBSD: npf_mbuf.c,v 1.4.4.2 2010/10/22 09:23:15 uebayasi Exp $	*/
+
+/*-
+ * Copyright (c) 2009-2010 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This material is based upon work partially supported by The
+ * NetBSD Foundation under a contract with Mindaugas Rasiukevicius.
+ *
+ * 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * NPF network buffer management interface.
+ *
+ * Network buffer in NetBSD is mbuf.  Internal mbuf structures are
+ * abstracted within this source.
+ */
+
+#ifdef _KERNEL
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: npf_mbuf.c,v 1.4.4.2 2010/10/22 09:23:15 uebayasi Exp $");
+#endif
+
+#include <sys/param.h>
+#include <sys/mbuf.h>
+
+#include "npf_impl.h"
+
+/*
+ * nbuf_dataptr: return a pointer to data in nbuf.
+ */
+void *
+nbuf_dataptr(nbuf_t *nbuf)
+{
+	const struct mbuf *m = nbuf;
+
+	return mtod(m, void *);
+}
+
+/*
+ * nbuf_advance: advance in mbuf or chain by specified amount of bytes.
+ *
+ * => Returns new pointer to data in mbuf and NULL if offset gets invalid.
+ * => Sets nbuf to current (after advance) mbuf in the chain.
+ */
+void *
+nbuf_advance(nbuf_t **nbuf, void *n_ptr, u_int n)
+{
+	struct mbuf *m = *nbuf;
+	u_int off, wmark;
+	uint8_t *d;
+
+	/* Offset with amount to advance. */
+	off = (uintptr_t)n_ptr - mtod(m, uintptr_t) + n;
+	wmark = m->m_len;
+
+	/* Find the mbuf according to offset. */
+	while (__predict_false(wmark <= off)) {
+		m = m->m_next;
+		if (__predict_false(m == NULL)) {
+			/*
+			 * If out of chain, then offset is
+			 * higher than packet length.
+			 */
+			return NULL;
+		}
+		wmark += m->m_len;
+	}
+
+	/* Offset in mbuf data. */
+	d = mtod(m, uint8_t *);
+	KASSERT(off >= (wmark - m->m_len));
+	d += (off - (wmark - m->m_len));
+
+	*nbuf = (void *)m;
+	return d;
+}
+
+/*
+ * nbuf_rw_datum: read or write a datum of specified length at current
+ * offset in the nbuf chain and copy datum into passed buffer.
+ *
+ * => Datum is allowed to overlap between two or more mbufs.
+ * => Note: all data in nbuf is in network byte order.
+ * => Returns 0 on success, error code on failure.
+ *
+ * Note: this function must be static inline with constant operation
+ * parameter - we expect constant propagation.
+ */
+
+#define	NBUF_DATA_READ		0
+#define	NBUF_DATA_WRITE		1
+
+static inline int
+nbuf_rw_datum(const int wr, nbuf_t *nbuf, void *n_ptr, size_t len, void *buf)
+{
+	uint8_t *d = n_ptr, *b = buf;
+	struct mbuf *m = nbuf;
+	u_int off, wmark, end;
+
+	/* Current offset in mbuf. */
+	off = (uintptr_t)n_ptr - mtod(m, uintptr_t);
+	KASSERT(off < m->m_len);
+	wmark = m->m_len;
+
+	/* Is datum overlapping? */
+	end = off + len;
+	while (__predict_false(end > wmark)) {
+		u_int l;
+
+		/* Get the part of current mbuf. */
+		l = m->m_len - off;
+		KASSERT(l < len);
+		len -= l;
+		if (wr == NBUF_DATA_WRITE) {
+			while (l--)
+				*d++ = *b++;
+		} else {
+			KASSERT(wr == NBUF_DATA_READ);
+			while (l--)
+				*b++ = *d++;
+		}
+		KASSERT(len > 0);
+
+		/* Take next mbuf and continue. */
+		m = m->m_next;
+		if (__predict_false(m == NULL)) {
+			/*
+			 * If out of chain, then offset with datum
+			 * length exceed the packet length.
+			 */
+			return EINVAL;
+		}
+		wmark += m->m_len;
+		d = mtod(m, uint8_t *);
+		off = 0;
+	}
+	KASSERT(n_ptr == d || mtod(m, uint8_t *) == d);
+	KASSERT(len <= m->m_len);
+
+	/* Non-overlapping case: fetch the actual data. */
+	if (wr == NBUF_DATA_WRITE) {
+		while (len--)
+			*d++ = *b++;
+	} else {
+		KASSERT(wr == NBUF_DATA_READ);
+		while (len--)
+			*b++ = *d++;
+	}
+	return 0;
+}
+
+/*
+ * nbuf_{fetch|store}_datum: read/write absraction calls on nbuf_rw_datum().
+ */
+int
+nbuf_fetch_datum(nbuf_t *nbuf, void *n_ptr, size_t len, void *buf)
+{
+
+	return nbuf_rw_datum(NBUF_DATA_READ, nbuf, n_ptr, len, buf);
+}
+
+int
+nbuf_store_datum(nbuf_t *nbuf, void *n_ptr, size_t len, void *buf)
+{
+
+	return nbuf_rw_datum(NBUF_DATA_WRITE, nbuf, n_ptr, len, buf);
+}
+
+/*
+ * nbuf_advfetch: advance and fetch the datum.
+ */
+int
+nbuf_advfetch(nbuf_t **nbuf, void **n_ptr, u_int n, size_t len, void *buf)
+{
+	nbuf_t *orig_nbuf = *nbuf;
+	void *orig_nptr = *n_ptr;
+	int error;
+
+	*n_ptr = nbuf_advance(nbuf, *n_ptr, n);
+	if (__predict_false(*n_ptr != NULL)) {
+		error = nbuf_fetch_datum(*nbuf, *n_ptr, len, buf);
+	} else {
+		error = EINVAL;
+	}
+	if (__predict_false(error)) {
+		*nbuf = orig_nbuf;
+		*n_ptr = orig_nptr;
+	}
+	return error;
+}
+
+/*
+ * nbuf_add_tag: add a tag to specified network buffer.
+ *
+ * => Returns 0 on success, or errno on failure.
+ */
+int
+nbuf_add_tag(nbuf_t *nbuf, uint32_t key, uint32_t val)
+{
+	struct mbuf *m = nbuf;
+	struct m_tag *mt;
+	uint32_t *dat;
+
+	mt = m_tag_get(PACKET_TAG_NPF, sizeof(uint32_t), M_NOWAIT);
+	if (__predict_false(mt == NULL)) {
+		return ENOMEM;
+	}
+	dat = (uint32_t *)(mt + 1);
+	*dat = val;
+	m_tag_prepend(m, mt);
+	return 0;
+}
+
+/*
+ * nbuf_find_tag: find a tag in specified network buffer.
+ *
+ * => Returns 0 on success, or errno on failure.
+ */
+int
+nbuf_find_tag(nbuf_t *nbuf, uint32_t key, void **data)
+{
+	struct mbuf *m = nbuf;
+	struct m_tag *mt;
+
+	mt = m_tag_find(m, PACKET_TAG_NPF, NULL);
+	if (__predict_false(mt == NULL)) {
+		return EINVAL;
+	}
+	*data = (void *)(mt + 1);
+	return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/net/npf/npf_nat.c	Fri Oct 22 09:23:11 2010 +0000
@@ -0,0 +1,626 @@
+/*	$NetBSD: npf_nat.c,v 1.2.4.2 2010/10/22 09:23:15 uebayasi Exp $	*/
+
+/*-
+ * Copyright (c) 2010 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This material is based upon work partially supported by The
+ * NetBSD Foundation under a contract with Mindaugas Rasiukevicius.
+ *
+ * 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * NPF network address port translation (NAPT).
+ * Described in RFC 2663, RFC 3022.  Commonly just "NAT".
+ *
+ * Overview
+ *
+ *	There are few mechanisms: NAT policy, port map and translation.
+ *	NAT module has a separate ruleset, where rules contain associated
+ *	NAT policy, thus flexible filter criteria can be used.
+ *
+ * Translation types
+ *
+ *	There are two types of translation: outbound (NPF_NATOUT) and
+ *	inbound (NPF_NATIN).  It should not be confused with connection
+ *	direction.
+ *
+ *	Outbound NAT rewrites:
+ *	- Source on "forwards" stream.
+ *	- Destination on "backwards" stream.
+ *	Inbound NAT rewrites:
+ *	- Destination on "forwards" stream.
+ *	- Source on "backwards" stream.
+ *
+ *	It should be noted that bi-directional NAT is a combined outbound
+ *	and inbound translation, therefore constructed as two policies.
+ *
+ * NAT policies and port maps
+ *
+ *	NAT (translation) policy is applied when a packet matches the rule.
+ *	Apart from filter criteria, NAT policy has a translation IP address
+ *	and associated port map.  Port map is a bitmap used to reserve and
+ *	use unique TCP/UDP ports for translation.  Port maps are unique to
+ *	the IP addresses, therefore multiple NAT policies with the same IP
+ *	will share the same port map.
+ *
+ * NAT sessions and translation entries
+ *
+ *	NAT module relies on session management module.  Each "NAT" session
+ *	has an associated translation entry (npf_nat_t).  It contains saved
+ *	i.e. original IP address with port and translation port, allocated
+ *	from the port map.  Each NAT translation entry is associated with
+ *	the policy, which contains translation IP address.  Allocated port
+ *	is returned to the port map and translation entry destroyed when
+ *	"NAT" session expires.
+ */
+
+#ifdef _KERNEL
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: npf_nat.c,v 1.2.4.2 2010/10/22 09:23:15 uebayasi Exp $");
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#endif
+
+#include <sys/atomic.h>
+#include <sys/bitops.h>
+#include <sys/kmem.h>
+#include <sys/pool.h>
+#include <net/pfil.h>
+#include <netinet/in.h>
+
+#include "npf_impl.h"
+
+/*
+ * NPF portmap structure.
+ */
+typedef struct {
+	u_int				p_refcnt;
+	uint32_t			p_bitmap[0];
+} npf_portmap_t;
+
+/* Portmap range: [ 1024 .. 65535 ] */
+#define	PORTMAP_FIRST			(1024)
+#define	PORTMAP_SIZE			((65536 - PORTMAP_FIRST) / 32)
+#define	PORTMAP_FILLED			((uint32_t)~0)
+#define	PORTMAP_MASK			(31)
+#define	PORTMAP_SHIFT			(5)
+
+/* NAT policy structure. */
+struct npf_natpolicy {
+	LIST_ENTRY(npf_natpolicy)	n_entry;
+	int				n_type;
+	int				n_flags;
+	in_addr_t			n_taddr;
+	in_port_t			n_tport;
+	npf_portmap_t *			n_portmap;
+};
+
+/* NAT translation entry for a session. */ 
+struct npf_nat {
+	npf_natpolicy_t *		nt_natpolicy;
+	/* Original address and port (for backwards translation). */
+	in_addr_t			nt_oaddr;
+	in_port_t			nt_oport;
+	/* Translation port (for redirects). */
+	in_port_t			nt_tport;
+	/* ALG (if any) associated with this NAT entry. */
+	npf_alg_t *			nt_alg;
+	uintptr_t			nt_alg_arg;
+};
+
+static npf_ruleset_t *			nat_ruleset	__read_mostly;
+static LIST_HEAD(, npf_natpolicy)	nat_policy_list	__read_mostly;
+static pool_cache_t			nat_cache	__read_mostly;
+
+/*
+ * npf_nat_sys{init,fini}: initialise/destroy NAT subsystem structures.
+ */
+
+void
+npf_nat_sysinit(void)
+{
+
+	nat_cache = pool_cache_init(sizeof(npf_nat_t), coherency_unit,
+	    0, 0, "npfnatpl", NULL, IPL_NET, NULL, NULL, NULL);
+	KASSERT(nat_cache != NULL);
+	nat_ruleset = npf_ruleset_create();
+	LIST_INIT(&nat_policy_list);
+}
+
+void
+npf_nat_sysfini(void)
+{
+
+	/* Flush NAT policies. */
+	npf_nat_reload(NULL);
+	KASSERT(LIST_EMPTY(&nat_policy_list));
+	pool_cache_destroy(nat_cache);
+}
+
+/*
+ * npf_nat_newpolicy: create a new NAT policy.
+ *
+ * => Shares portmap if policy is on existing translation address.
+ * => XXX: serialise at upper layer.
+ */
+npf_natpolicy_t *
+npf_nat_newpolicy(int type, int flags, in_addr_t taddr, in_port_t tport)
+{
+	npf_natpolicy_t *np, *it;
+	npf_portmap_t *pm;
+
+	np = kmem_zalloc(sizeof(npf_natpolicy_t), KM_SLEEP);
+	if (np == NULL) {
+		return NULL;
+	}
+	KASSERT(type == NPF_NATIN || type == NPF_NATOUT);
+	np->n_type = type;
+	np->n_flags = flags;
+	np->n_taddr = taddr;
+	np->n_tport = tport;
+
+	pm = NULL;
+	if ((flags & NPF_NAT_PORTMAP) == 0) {
+		goto nopm;
+	}
+
+	/* Search for a NAT policy using the same translation address. */
+	LIST_FOREACH(it, &nat_policy_list, n_entry) {
+		if (it->n_taddr != np->n_taddr)
+			continue;
+		pm = it->n_portmap;
+		break;
+	}
+	if (pm == NULL) {
+		/* Allocate a new port map for the NAT policy. */
+		pm = kmem_zalloc(sizeof(npf_portmap_t) +
+		    (PORTMAP_SIZE * sizeof(uint32_t)), KM_SLEEP);
+		if (pm == NULL) {
+			kmem_free(np, sizeof(npf_natpolicy_t));
+			return NULL;
+		}
+		pm->p_refcnt = 1;
+		KASSERT((uintptr_t)pm->p_bitmap == (uintptr_t)pm + sizeof(*pm));
+	} else {
+		/* Share the port map. */
+		pm->p_refcnt++;
+	}
+nopm:
+	np->n_portmap = pm;
+	/*
+	 * Note: old policies with new might co-exist in the list,
+	 * while reload is in progress, but that is not an issue.
+	 */
+	LIST_INSERT_HEAD(&nat_policy_list, np, n_entry);
+	return np;
+}
+
+/*
+ * npf_nat_freepolicy: free NAT policy and, on last reference, free portmap.
+ *
+ * => Called from npf_rule_free() during the reload via npf_nat_reload().
+ */
+void
+npf_nat_freepolicy(npf_natpolicy_t *np)
+{
+	npf_portmap_t *pm = np->n_portmap;
+
+	LIST_REMOVE(np, n_entry);
+	if (pm && --pm->p_refcnt == 0) {
+		KASSERT((np->n_flags & NPF_NAT_PORTMAP) != 0);
+		kmem_free(pm, sizeof(npf_portmap_t) +
+		    (PORTMAP_SIZE * sizeof(uint32_t)));
+	}
+	kmem_free(np, sizeof(npf_natpolicy_t));
+}
+
+/*
+ * npf_nat_reload: activate new ruleset of NAT policies and destroy old.
+ *
+ * => Destruction of ruleset will perform npf_nat_freepolicy() for each policy.
+ */
+void
+npf_nat_reload(npf_ruleset_t *nset)
+{
+	npf_ruleset_t *oldnset;
+
+	oldnset = atomic_swap_ptr(&nat_ruleset, nset);
+	if (oldnset) {
+		npf_ruleset_destroy(oldnset);
+	}
+}
+
+/*
+ * npf_nat_getport: allocate and return a port in the NAT policy portmap.
+ *
+ * => Returns in network byte-order.
+ * => Zero indicates failure.
+ */
+static in_port_t
+npf_nat_getport(npf_natpolicy_t *np)
+{
+	npf_portmap_t *pm = np->n_portmap;
+	u_int n = PORTMAP_SIZE, idx, bit;
+	uint32_t map, nmap;
+
+	idx = arc4random() % PORTMAP_SIZE;
+	for (;;) {
+		KASSERT(idx < PORTMAP_SIZE);
+		map = pm->p_bitmap[idx];
+		if (__predict_false(map == PORTMAP_FILLED)) {
+			if (n-- == 0) {
+				/* No space. */
+				return 0;
+			}
+			/* This bitmap is filled, next. */
+			idx = (idx ? idx : PORTMAP_SIZE) - 1;
+			continue;
+		}
+		bit = ffs32(~map) - 1;
+		nmap = map | (1 << bit);
+		if (atomic_cas_32(&pm->p_bitmap[idx], map, nmap) == map) {
+			/* Success. */
+			break;
+		}
+	}
+	return htons(PORTMAP_FIRST + (idx << PORTMAP_SHIFT) + bit);
+}
+
+/*
+ * npf_nat_putport: return port as available in the NAT policy portmap.
+ *
+ * => Port should be in network byte-order.
+ */
+static void
+npf_nat_putport(npf_natpolicy_t *np, in_port_t port)
+{
+	npf_portmap_t *pm = np->n_portmap;
+	uint32_t map, nmap;
+	u_int idx, bit;
+
+	port = ntohs(port) - PORTMAP_FIRST;
+	idx = port >> PORTMAP_SHIFT;
+	bit = port & PORTMAP_MASK;
+	do {
+		map = pm->p_bitmap[idx];
+		KASSERT(map | (1 << bit));
+		nmap = map & ~(1 << bit);
+	} while (atomic_cas_32(&pm->p_bitmap[idx], map, nmap) != map);
+}
+
+/*
+ * npf_nat_inspect: inspect packet against NAT ruleset and return a policy.
+ */
+static npf_natpolicy_t *
+npf_nat_inspect(npf_cache_t *npc, nbuf_t *nbuf, struct ifnet *ifp, const int di)
+{
+	npf_rule_t *rl;
+
+	rl = npf_ruleset_match(nat_ruleset, npc, nbuf, ifp, di, NPF_LAYER_3);
+
+	return rl ? npf_rule_getnat(rl) : NULL;
+}
+
+/*
+ * npf_nat_create: create a new NAT translation entry.
+ */
+static npf_nat_t *
+npf_nat_create(npf_cache_t *npc, npf_natpolicy_t *np)
+{
+	const int proto = npc->npc_proto;
+	npf_nat_t *nt;
+
+	/* New NAT association. */
+	nt = pool_cache_get(nat_cache, PR_NOWAIT);
+	if (nt == NULL){
+		return NULL;
+	}
+	nt->nt_natpolicy = np;
+	nt->nt_alg = NULL;
+
+	/* Save the original address which may be rewritten. */
+	if (np->n_type == NPF_NATOUT) {
+		/* Source (local) for Outbound NAT. */
+		nt->nt_oaddr = npc->npc_srcip;
+	} else {
+		/* Destination (external) for Inbound NAT. */
+		KASSERT(np->n_type == NPF_NATIN);
+		nt->nt_oaddr = npc->npc_dstip;
+	}
+
+	/*
+	 * Port translation, if required, and if it is TCP/UDP.
+	 */
+	if ((np->n_flags & NPF_NAT_PORTS) == 0 ||
+	    (proto != IPPROTO_TCP && proto != IPPROTO_UDP)) {
+		nt->nt_oport = 0;
+		nt->nt_tport = 0;
+		return nt;
+	}
+	/* Save a relevant TCP/UDP port. */
+	KASSERT(npf_iscached(npc, NPC_PORTS));
+	if (np->n_type == NPF_NATOUT) {
+		nt->nt_oport = npc->npc_sport;
+	} else {
+		nt->nt_oport = npc->npc_dport;
+	}
+	/* Get a new port for translation. */
+	if ((np->n_flags & NPF_NAT_PORTMAP) != 0) {
+		nt->nt_tport = npf_nat_getport(np);
+	} else {
+		nt->nt_tport = np->n_tport;
+	}
+	return nt;
+}
+
+/*
+ * npf_nat_translate: perform address and/or port translation.
+ */
+static int
+npf_nat_translate(npf_cache_t *npc, nbuf_t *nbuf, npf_nat_t *nt,
+    const bool forw, const int di)
+{
+	const npf_natpolicy_t *np = nt->nt_natpolicy;
+	void *n_ptr = nbuf_dataptr(nbuf);
+	in_addr_t addr;
+	in_port_t port;
+
+	KASSERT(npf_iscached(npc, NPC_IP46 | NPC_ADDRS));
+
+	if (forw) {
+		/* "Forwards" stream: use translation address/port. */
+		KASSERT(
+		    (np->n_type == NPF_NATIN && di == PFIL_IN) ^
+		    (np->n_type == NPF_NATOUT && di == PFIL_OUT)
+		);
+		addr = np->n_taddr;
+		port = nt->nt_tport;
+	} else {
+		/* "Backwards" stream: use original address/port. */
+		KASSERT(
+		    (np->n_type == NPF_NATIN && di == PFIL_OUT) ^
+		    (np->n_type == NPF_NATOUT && di == PFIL_IN)
+		);
+		addr = nt->nt_oaddr;
+		port = nt->nt_oport;
+	}
+
+	/* Execute ALG hooks first. */
+	npf_alg_exec(npc, nbuf, nt, di);
+
+	/*
+	 * Address translation: rewrite source/destination address, depending
+	 * on direction (PFIL_OUT - for source, PFIL_IN - for destination).
+	 * Note: cache will be used in npf_rwrport(), update only in the end.
+	 */
+	if (!npf_rwrip(npc, nbuf, n_ptr, di, addr)) {
+		return EINVAL;
+	}
+	if ((np->n_flags & NPF_NAT_PORTS) == 0) {
+		/* Cache new address. */
+		if (di == PFIL_OUT) {
+			npc->npc_srcip = addr;
+		} else {
+			npc->npc_dstip = addr;
+		}
+		return 0;
+	}
+	switch (npc->npc_proto) {
+	case IPPROTO_TCP:
+	case IPPROTO_UDP:
+		KASSERT(npf_iscached(npc, NPC_PORTS));
+		/* Rewrite source/destination port. */
+		if (!npf_rwrport(npc, nbuf, n_ptr, di, port, addr)) {
+			return EINVAL;
+		}
+		break;
+	case IPPROTO_ICMP:
+		/* None. */
+		break;
+	default:
+		return ENOTSUP;
+	}
+	/* Cache new address and port. */
+	if (di == PFIL_OUT) {
+		npc->npc_srcip = addr;
+		npc->npc_sport = port;
+	} else {
+		npc->npc_dstip = addr;
+		npc->npc_dport = port;
+	}
+	return 0;
+}
+
+/*
+ * npf_do_nat:
+ *	- Inspect packet for a NAT policy, unless a session with a NAT
+ *	  association already exists.  In such case, determine whether is
+ *	  is a "forwards" or "backwards" stream.
+ *	- Perform translation: rewrite source address if "forwards" stream
+ *	  and destination address if "backwards".
+ *	- Establish sessions or, if already exists, associate a NAT policy.
+ */
+int
+npf_do_nat(npf_cache_t *npc, npf_session_t *se, nbuf_t *nbuf,
+    struct ifnet *ifp, const int di)
+{
+	npf_session_t *nse = NULL;
+	npf_natpolicy_t *np;
+	npf_nat_t *nt;
+	int error;
+	bool forw, new;
+
+	/* All relevant IPv4 data should be already cached. */
+	if (!npf_iscached(npc, NPC_IP46 | NPC_ADDRS)) {
+		return 0;
+	}
+
+	/*
+	 * Return the NAT entry associated with the session, if any.
+	 * Assumptions:
+	 * - If associated via linked session, then "forwards" stream.
+	 * - If associated directly, then "backwards" stream.
+	 */
+	if (se && (nt = npf_session_retnat(se, di, &forw)) != NULL) {
+		np = nt->nt_natpolicy;
+		new = false;
+		goto translate;
+	}
+
+	/* Inspect the packet for a NAT policy, if there is no session. */
+	np = npf_nat_inspect(npc, nbuf, ifp, di);
+	if (np == NULL) {
+		/* If packet does not match - done. */
+		return 0;
+	}
+	forw = true;
+
+	/* Create a new NAT translation entry. */
+	nt = npf_nat_create(npc, np);
+	if (nt == NULL) {
+		return ENOMEM;
+	}
+	new = true;
+
+	/*
+	 * If there is no local session (no "keep state" rule - unusual, but
+	 * possible configuration), establish one before translation.  Note
+	 * that it is not a "pass" session, therefore passing of "backwards"
+	 * stream depends on other, stateless filtering rules.
+	 */
+	if (se == NULL) {
+		nse = npf_session_establish(npc, NULL, di);
+		if (nse == NULL) {
+			error = ENOMEM;
+			goto out;
+		}
+		se = nse;
+	}
+translate:
+	/* Perform the translation. */
+	error = npf_nat_translate(npc, nbuf, nt, forw, di);
+	if (error) {
+		goto out;
+	}
+
+	if (__predict_false(new)) {
+		npf_session_t *natse;
+		/*
+		 * Establish a new NAT session using translated address and
+		 * associate NAT translation data with this session.
+		 *
+		 * Note: packet now has a translated address in the cache.
+		 */
+		natse = npf_session_establish(npc, nt, di);
+		if (natse == NULL) {
+			error = ENOMEM;
+			goto out;
+		}
+		/*
+		 * Link local session with NAT session, if no link already.
+		 */
+		npf_session_link(se, natse);
+		npf_session_release(natse);
+out:
+		if (error) {
+			if (nse != NULL) {
+				/* XXX: Expire it?? */
+			}
+			/* Will free the structure and return the port. */
+			npf_nat_expire(nt);
+		}
+		if (nse != NULL) {
+			npf_session_release(nse);
+		}
+	}
+	return error;
+}
+
+/*
+ * npf_nat_getorig: return original IP address and port from translation entry.
+ */
+void
+npf_nat_getorig(npf_nat_t *nt, in_addr_t *addr, in_port_t *port)
+{
+
+	*addr = nt->nt_oaddr;
+	*port = nt->nt_oport;
+}
+
+void
+npf_nat_setalg(npf_nat_t *nt, npf_alg_t *alg, uintptr_t arg)
+{
+
+	nt->nt_alg = alg;
+	nt->nt_alg_arg = arg;
+}
+
+/*
+ * npf_nat_expire: free NAT-related data structures on session expiration.
+ */
+void
+npf_nat_expire(npf_nat_t *nt)
+{
+	npf_natpolicy_t *np = nt->nt_natpolicy;
+
+	if ((np->n_flags & NPF_NAT_PORTMAP) != 0) {
+		KASSERT(nt->nt_tport != 0);
+		npf_nat_putport(np, nt->nt_tport);
+	}
+	pool_cache_put(nat_cache, nt);
+}
+
+#if defined(DDB) || defined(_NPF_TESTING)
+
+void
+npf_nat_dump(npf_nat_t *nt)
+{
+	npf_natpolicy_t *np;
+	struct in_addr ip;
+
+	if (nt) {
+		np = nt->nt_natpolicy;
+		goto skip;
+	}
+	LIST_FOREACH(np, &nat_policy_list, n_entry) {
+skip:
+		ip.s_addr = np->n_taddr;
+		printf("\tNAT policy: type = %d, flags = %d, taddr = %s\n",
+		    np->n_type, np->n_flags, inet_ntoa(ip));
+		if (nt == NULL) {
+			continue;
+		}
+		ip.s_addr = nt->nt_oaddr;
+		printf("\tNAT: original address %s, oport %d, tport = %d\n",
+		    inet_ntoa(ip), ntohs(nt->nt_oport), ntohs(nt->nt_tport));
+		if (nt->nt_alg) {
+			printf("\tNAT ALG = %p, ARG = %p\n",
+			    nt->nt_alg, (void *)nt->nt_alg_arg);
+		}
+		return;
+	}
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/net/npf/npf_ncode.h	Fri Oct 22 09:23:11 2010 +0000
@@ -0,0 +1,108 @@
+/*	$NetBSD: npf_ncode.h,v 1.2.4.2 2010/10/22 09:23:15 uebayasi Exp $	*/
+
+/*-
+ * Copyright (c) 2009-2010 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This material is based upon work partially supported by The
+ * NetBSD Foundation under a contract with Mindaugas Rasiukevicius.
+ *
+ * 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