summaryrefslogtreecommitdiff
path: root/sys/arm
diff options
context:
space:
mode:
authorSam Leffler <sam@FreeBSD.org>2006-11-19 23:55:23 +0000
committerSam Leffler <sam@FreeBSD.org>2006-11-19 23:55:23 +0000
commite67f80fd20df72b1b4f58e48539848a8928ec049 (patch)
tree4b97f2dd56c6a38777b2af64468ef2b15f9e1d92 /sys/arm
parentfaad47108deed5fc9426219555ee251367d34953 (diff)
downloadsrc-test2-e67f80fd20df72b1b4f58e48539848a8928ec049.tar.gz
src-test2-e67f80fd20df72b1b4f58e48539848a8928ec049.zip
Notes
Diffstat (limited to 'sys/arm')
-rw-r--r--sys/arm/arm/cpufunc.c1
-rw-r--r--sys/arm/xscale/ixp425/avila_ata.c556
-rw-r--r--sys/arm/xscale/ixp425/avila_machdep.c545
-rw-r--r--sys/arm/xscale/ixp425/files.avila4
-rw-r--r--sys/arm/xscale/ixp425/files.ixp42541
-rw-r--r--sys/arm/xscale/ixp425/if_npe.c1673
-rw-r--r--sys/arm/xscale/ixp425/if_npereg.h288
-rw-r--r--sys/arm/xscale/ixp425/ixdp425_pci.c169
-rw-r--r--sys/arm/xscale/ixp425/ixdp425reg.h54
-rw-r--r--sys/arm/xscale/ixp425/ixp425.c369
-rw-r--r--sys/arm/xscale/ixp425/ixp425_a4x_io.S142
-rw-r--r--sys/arm/xscale/ixp425/ixp425_a4x_space.c116
-rw-r--r--sys/arm/xscale/ixp425/ixp425_iic.c193
-rw-r--r--sys/arm/xscale/ixp425/ixp425_intr.h149
-rw-r--r--sys/arm/xscale/ixp425/ixp425_mem.c85
-rw-r--r--sys/arm/xscale/ixp425/ixp425_npe.c1396
-rw-r--r--sys/arm/xscale/ixp425/ixp425_npereg.h434
-rw-r--r--sys/arm/xscale/ixp425/ixp425_npevar.h96
-rw-r--r--sys/arm/xscale/ixp425/ixp425_pci.c455
-rw-r--r--sys/arm/xscale/ixp425/ixp425_pci_asm.S102
-rw-r--r--sys/arm/xscale/ixp425/ixp425_pci_space.c496
-rw-r--r--sys/arm/xscale/ixp425/ixp425_qmgr.c1077
-rw-r--r--sys/arm/xscale/ixp425/ixp425_qmgr.h243
-rw-r--r--sys/arm/xscale/ixp425/ixp425_space.c215
-rw-r--r--sys/arm/xscale/ixp425/ixp425_timer.c267
-rw-r--r--sys/arm/xscale/ixp425/ixp425_wdog.c118
-rw-r--r--sys/arm/xscale/ixp425/ixp425reg.h582
-rw-r--r--sys/arm/xscale/ixp425/ixp425var.h99
-rw-r--r--sys/arm/xscale/ixp425/std.avila6
-rw-r--r--sys/arm/xscale/ixp425/std.ixp4256
-rw-r--r--sys/arm/xscale/ixp425/uart_bus_ixp425.c91
-rw-r--r--sys/arm/xscale/ixp425/uart_cpu_ixp425.c67
32 files changed, 10134 insertions, 1 deletions
diff --git a/sys/arm/arm/cpufunc.c b/sys/arm/arm/cpufunc.c
index 52f1abf12157..81922e62670b 100644
--- a/sys/arm/arm/cpufunc.c
+++ b/sys/arm/arm/cpufunc.c
@@ -1015,7 +1015,6 @@ set_cpufuncs()
#ifdef CPU_XSCALE_IXP425
if (cputype == CPU_ID_IXP425_533 || cputype == CPU_ID_IXP425_400 ||
cputype == CPU_ID_IXP425_266) {
- ixp425_icu_init();
cpufuncs = xscale_cpufuncs;
#if defined(PERFCTRS)
diff --git a/sys/arm/xscale/ixp425/avila_ata.c b/sys/arm/xscale/ixp425/avila_ata.c
new file mode 100644
index 000000000000..9c5f2c2f2e2e
--- /dev/null
+++ b/sys/arm/xscale/ixp425/avila_ata.c
@@ -0,0 +1,556 @@
+/*-
+ * Copyright (c) 2006 Sam Leffler, Errno Consulting
+ * 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,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ * redistribution must be conditioned upon including a substantially
+ * similar Disclaimer requirement for further binary redistribution.
+ *
+ * NO WARRANTY
+ * 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 NONINFRINGEMENT, MERCHANTIBILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Compact Flash Support for the Avila Gateworks XScale boards.
+ * There are 1 or 2 optional CF slots operated in "True IDE" mode.
+ * Registers are on the Expansion Bus connected to CS1. Interrupts
+ * are tied to GPIO pin 12. No DMA, just PIO.
+ *
+ * See also http://www.intel.com/design/network/applnots/302456.htm.
+ */
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/time.h>
+#include <sys/bus.h>
+#include <sys/resource.h>
+#include <sys/rman.h>
+#include <sys/sysctl.h>
+#include <sys/endian.h>
+
+#include <machine/bus.h>
+#include <machine/cpu.h>
+#include <machine/cpufunc.h>
+#include <machine/resource.h>
+#include <machine/intr.h>
+#include <arm/xscale/ixp425/ixp425reg.h>
+#include <arm/xscale/ixp425/ixp425var.h>
+
+#include <sys/ata.h>
+#include <sys/sema.h>
+#include <sys/taskqueue.h>
+#include <vm/uma.h>
+#include <dev/ata/ata-all.h>
+#include <ata_if.h>
+
+#define AVILA_IDE_GPIN 12 /* GPIO pin # */
+#define AVILA_IDE_IRQ IXP425_INT_GPIO_12
+#define AVILA_IDE_CTRL 0x1e /* control register */
+
+struct ata_avila_softc {
+ device_t sc_dev;
+ bus_space_tag_t sc_iot;
+ bus_space_handle_t sc_exp_ioh; /* Exp Bus config registers */
+ bus_space_handle_t sc_ioh; /* CS1 data registers */
+ struct bus_space sc_expbus_tag;
+ struct resource sc_ata; /* hand-crafted for ATA */
+ int sc_rid; /* rid for IRQ */
+ struct resource *sc_irq; /* IRQ resource */
+ void *sc_ih; /* interrupt handler */
+ struct {
+ void (*cb)(void *);
+ void *arg;
+ } sc_intr[1]; /* NB: 1/channel */
+};
+
+static void ata_avila_intr(void *);
+bs_protos(ata);
+static void ata_bs_rm_2_s(void *, bus_space_handle_t, bus_size_t,
+ u_int16_t *, bus_size_t);
+static void ata_bs_wm_2_s(void *, bus_space_handle_t, bus_size_t,
+ const u_int16_t *, bus_size_t);
+
+static int
+ata_avila_probe(device_t dev)
+{
+ /* XXX any way to check? */
+ device_set_desc_copy(dev, "Gateworks Avila IDE/CF Controller");
+ return 0;
+}
+
+static int
+ata_avila_attach(device_t dev)
+{
+ struct ata_avila_softc *sc = device_get_softc(dev);
+ struct ixp425_softc *sa = device_get_softc(device_get_parent(dev));
+
+ sc->sc_dev = dev;
+ /* NB: borrow from parent */
+ sc->sc_iot = sa->sc_iot;
+ sc->sc_exp_ioh = sa->sc_exp_ioh;
+ if (bus_space_map(sc->sc_iot,
+ IXP425_EXP_BUS_CS1_HWBASE, IXP425_EXP_BUS_CS1_SIZE, 0, &sc->sc_ioh))
+ panic("%s: unable to map Expansion Bus CS1 window", __func__);
+
+ /*
+ * Craft special resource for ATA bus space ops
+ * that go through the expansion bus and require
+ * special hackery to ena/dis 16-bit operations.
+ *
+ * XXX probably should just make this generic for
+ * accessing the expansion bus.
+ */
+ sc->sc_expbus_tag.bs_cookie = sc; /* NB: backpointer */
+ /* read single */
+ sc->sc_expbus_tag.bs_r_1 = ata_bs_r_1,
+ sc->sc_expbus_tag.bs_r_2 = ata_bs_r_2,
+ /* read multiple */
+ sc->sc_expbus_tag.bs_rm_2 = ata_bs_rm_2,
+ sc->sc_expbus_tag.bs_rm_2_s = ata_bs_rm_2_s,
+ /* write (single) */
+ sc->sc_expbus_tag.bs_w_1 = ata_bs_w_1,
+ sc->sc_expbus_tag.bs_w_2 = ata_bs_w_2,
+ /* write multiple */
+ sc->sc_expbus_tag.bs_wm_2 = ata_bs_wm_2,
+ sc->sc_expbus_tag.bs_wm_2_s = ata_bs_wm_2_s,
+
+ rman_set_bustag(&sc->sc_ata, &sc->sc_expbus_tag);
+ rman_set_bushandle(&sc->sc_ata, sc->sc_ioh);
+
+ GPIO_CONF_WRITE_4(sa, IXP425_GPIO_GPOER,
+ GPIO_CONF_READ_4(sa, IXP425_GPIO_GPOER) | (1<<AVILA_IDE_GPIN));
+ /* interrupt is active low */
+ GPIO_CONF_WRITE_4(sa, GPIO_TYPE_REG(AVILA_IDE_GPIN),
+ GPIO_CONF_READ_4(sa, GPIO_TYPE_REG(AVILA_IDE_GPIN) |
+ GPIO_TYPE(AVILA_IDE_GPIN, GPIO_TYPE_ACT_LOW)));
+
+ /* clear ISR */
+ GPIO_CONF_WRITE_4(sa, IXP425_GPIO_GPISR, (1<<AVILA_IDE_GPIN));
+
+ /* configure CS1 window, leaving timing unchanged */
+ EXP_BUS_WRITE_4(sc, EXP_TIMING_CS1_OFFSET,
+ EXP_BUS_READ_4(sc, EXP_TIMING_CS1_OFFSET) |
+ EXP_BYTE_EN | EXP_WR_EN | EXP_BYTE_RD16 | EXP_CS_EN);
+
+ /* setup interrupt */
+ sc->sc_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &sc->sc_rid,
+ AVILA_IDE_IRQ, AVILA_IDE_IRQ, 1, RF_ACTIVE);
+ if (!sc->sc_irq)
+ panic("Unable to allocate irq %u.\n", AVILA_IDE_IRQ);
+ bus_setup_intr(dev, sc->sc_irq,
+ INTR_TYPE_BIO | INTR_MPSAFE | INTR_ENTROPY,
+ ata_avila_intr, sc, &sc->sc_ih);
+
+ /* attach channel on this controller */
+ device_add_child(dev, "ata", devclass_find_free_unit(ata_devclass, 0));
+ bus_generic_attach(dev);
+
+ return 0;
+}
+
+static int
+ata_avila_detach(device_t dev)
+{
+ struct ata_avila_softc *sc = device_get_softc(dev);
+ device_t *children;
+ int nc;
+
+ /* XXX quiesce gpio? */
+
+ /* detach & delete all children */
+ if (device_get_children(dev, &children, &nc) == 0) {
+ if (nc > 0)
+ device_delete_child(dev, children[0]);
+ free(children, M_TEMP);
+ }
+
+ bus_teardown_intr(dev, sc->sc_irq, sc->sc_ih);
+ bus_release_resource(dev, SYS_RES_IRQ, sc->sc_rid, sc->sc_irq);
+
+ return 0;
+}
+
+static void
+ata_avila_intr(void *xsc)
+{
+ struct ata_avila_softc *sc = xsc;
+
+ if (sc->sc_intr[0].cb != NULL)
+ sc->sc_intr[0].cb(sc->sc_intr[0].arg);
+}
+
+static struct resource *
+ata_avila_alloc_resource(device_t dev, device_t child, int type, int *rid,
+ u_long start, u_long end, u_long count, u_int flags)
+{
+ struct ata_avila_softc *sc = device_get_softc(dev);
+
+ KASSERT(type == SYS_RES_IRQ && *rid == ATA_IRQ_RID,
+ ("type %u rid %u start %lu end %lu count %lu flags %u",
+ type, *rid, start, end, count, flags));
+
+ /* doesn't matter what we return so reuse the real thing */
+ return sc->sc_irq;
+}
+
+static int
+ata_avila_release_resource(device_t dev, device_t child, int type, int rid,
+ struct resource *r)
+{
+ KASSERT(type == SYS_RES_IRQ && rid == ATA_IRQ_RID,
+ ("type %u rid %u", type, rid));
+ return 0;
+}
+
+static int
+ata_avila_setup_intr(device_t dev, device_t child, struct resource *irq,
+ int flags, driver_intr_t *function, void *argument,
+ void **cookiep)
+{
+ struct ata_avila_softc *sc = device_get_softc(dev);
+ int unit = ((struct ata_channel *)device_get_softc(child))->unit;
+
+ KASSERT(unit == 0, ("unit %d", unit));
+ sc->sc_intr[unit].cb = function;
+ sc->sc_intr[unit].arg = argument;
+ *cookiep = sc;
+ return 0;
+}
+
+static int
+ata_avila_teardown_intr(device_t dev, device_t child, struct resource *irq,
+ void *cookie)
+{
+ struct ata_avila_softc *sc = device_get_softc(dev);
+ int unit = ((struct ata_channel *)device_get_softc(child))->unit;
+
+ KASSERT(unit == 0, ("unit %d", unit));
+ sc->sc_intr[unit].cb = NULL;
+ sc->sc_intr[unit].arg = NULL;
+ return 0;
+}
+
+/*
+ * Bus space accessors for CF-IDE PIO operations.
+ */
+
+/*
+ * Enable/disable 16-bit ops on the expansion bus.
+ */
+static void __inline
+enable_16(struct ata_avila_softc *sc)
+{
+ EXP_BUS_WRITE_4(sc, EXP_TIMING_CS1_OFFSET,
+ EXP_BUS_READ_4(sc, EXP_TIMING_CS1_OFFSET) &~ EXP_BYTE_EN);
+ DELAY(100); /* XXX? */
+}
+
+static void __inline
+disable_16(struct ata_avila_softc *sc)
+{
+ DELAY(100); /* XXX? */
+ EXP_BUS_WRITE_4(sc, EXP_TIMING_CS1_OFFSET,
+ EXP_BUS_READ_4(sc, EXP_TIMING_CS1_OFFSET) | EXP_BYTE_EN);
+}
+
+uint8_t
+ata_bs_r_1(void *t, bus_space_handle_t h, bus_size_t o)
+{
+ struct ata_avila_softc *sc = t;
+
+ return bus_space_read_1(sc->sc_iot, h, o);
+}
+
+void
+ata_bs_w_1(void *t, bus_space_handle_t h, bus_size_t o, u_int8_t v)
+{
+ struct ata_avila_softc *sc = t;
+
+ bus_space_write_1(sc->sc_iot, h, o, v);
+}
+
+uint16_t
+ata_bs_r_2(void *t, bus_space_handle_t h, bus_size_t o)
+{
+ struct ata_avila_softc *sc = t;
+ uint16_t v;
+
+ enable_16(sc);
+ v = bus_space_read_2(sc->sc_iot, h, o);
+ disable_16(sc);
+ return v;
+}
+
+void
+ata_bs_w_2(void *t, bus_space_handle_t h, bus_size_t o, uint16_t v)
+{
+ struct ata_avila_softc *sc = t;
+
+ enable_16(sc);
+ bus_space_write_2(sc->sc_iot, h, o, v);
+ disable_16(sc);
+}
+
+void
+ata_bs_rm_2(void *t, bus_space_handle_t h, bus_size_t o,
+ u_int16_t *d, bus_size_t c)
+{
+ struct ata_avila_softc *sc = t;
+
+ enable_16(sc);
+ bus_space_read_multi_2(sc->sc_iot, h, o, d, c);
+ disable_16(sc);
+}
+
+void
+ata_bs_wm_2(void *t, bus_space_handle_t h, bus_size_t o,
+ const u_int16_t *d, bus_size_t c)
+{
+ struct ata_avila_softc *sc = t;
+
+ enable_16(sc);
+ bus_space_write_multi_2(sc->sc_iot, h, o, d, c);
+ disable_16(sc);
+}
+
+/* XXX workaround ata driver by (incorrectly) byte swapping stream cases */
+
+void
+ata_bs_rm_2_s(void *t, bus_space_handle_t h, bus_size_t o,
+ u_int16_t *d, bus_size_t c)
+{
+ struct ata_avila_softc *sc = t;
+ uint16_t v;
+ bus_size_t i;
+
+ enable_16(sc);
+#if 1
+ for (i = 0; i < c; i++) {
+ v = bus_space_read_2(sc->sc_iot, h, o);
+ d[i] = bswap16(v);
+ }
+#else
+ bus_space_read_multi_stream_2(sc->sc_iot, h, o, d, c);
+#endif
+ disable_16(sc);
+}
+
+void
+ata_bs_wm_2_s(void *t, bus_space_handle_t h, bus_size_t o,
+ const u_int16_t *d, bus_size_t c)
+{
+ struct ata_avila_softc *sc = t;
+ bus_size_t i;
+
+ enable_16(sc);
+#if 1
+ for (i = 0; i < c; i++)
+ bus_space_write_2(sc->sc_iot, h, o, bswap16(d[i]));
+#else
+ bus_space_write_multi_stream_2(sc->sc_iot, h, o, d, c);
+#endif
+ disable_16(sc);
+}
+
+static device_method_t ata_avila_methods[] = {
+ /* device interface */
+ DEVMETHOD(device_probe, ata_avila_probe),
+ DEVMETHOD(device_attach, ata_avila_attach),
+ DEVMETHOD(device_detach, ata_avila_detach),
+ DEVMETHOD(device_shutdown, bus_generic_shutdown),
+ DEVMETHOD(device_suspend, bus_generic_suspend),
+ DEVMETHOD(device_resume, bus_generic_resume),
+
+ /* bus methods */
+ DEVMETHOD(bus_alloc_resource, ata_avila_alloc_resource),
+ DEVMETHOD(bus_release_resource, ata_avila_release_resource),
+ DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
+ DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
+ DEVMETHOD(bus_setup_intr, ata_avila_setup_intr),
+ DEVMETHOD(bus_teardown_intr, ata_avila_teardown_intr),
+
+ { 0, 0 }
+};
+
+devclass_t ata_avila_devclass;
+
+static driver_t ata_avila_driver = {
+ "ata_avila",
+ ata_avila_methods,
+ sizeof(struct ata_avila_softc),
+};
+
+DRIVER_MODULE(ata_avila, ixp, ata_avila_driver, ata_avila_devclass, 0, 0);
+MODULE_VERSION(ata_avila, 1);
+MODULE_DEPEND(ata_avila, ata, 1, 1, 1);
+
+static int
+avila_channel_probe(device_t dev)
+{
+ struct ata_channel *ch = device_get_softc(dev);
+
+ ch->unit = 0;
+ ch->flags |= ATA_USE_16BIT | ATA_NO_SLAVE;
+ device_set_desc_copy(dev, "ATA channel 0");
+
+ return ata_probe(dev);
+}
+
+static int
+avila_channel_attach(device_t dev)
+{
+ struct ata_avila_softc *sc = device_get_softc(device_get_parent(dev));
+ struct ata_channel *ch = device_get_softc(dev);
+ int i;
+
+ for (i = 0; i < ATA_MAX_RES; i++)
+ ch->r_io[i].res = &sc->sc_ata;
+
+ ch->r_io[ATA_DATA].offset = ATA_DATA;
+ ch->r_io[ATA_FEATURE].offset = ATA_FEATURE;
+ ch->r_io[ATA_COUNT].offset = ATA_COUNT;
+ ch->r_io[ATA_SECTOR].offset = ATA_SECTOR;
+ ch->r_io[ATA_CYL_LSB].offset = ATA_CYL_LSB;
+ ch->r_io[ATA_CYL_MSB].offset = ATA_CYL_MSB;
+ ch->r_io[ATA_DRIVE].offset = ATA_DRIVE;
+ ch->r_io[ATA_COMMAND].offset = ATA_COMMAND;
+ ch->r_io[ATA_ERROR].offset = ATA_FEATURE;
+ /* NB: should be used only for ATAPI devices */
+ ch->r_io[ATA_IREASON].offset = ATA_COUNT;
+ ch->r_io[ATA_STATUS].offset = ATA_COMMAND;
+ /* alias this; required by ata_generic_status */
+ ch->r_io[ATA_ALTSTAT].offset = ch->r_io[ATA_STATUS].offset;
+
+ /* NB: the control register is special */
+ ch->r_io[ATA_CONTROL].offset = AVILA_IDE_CTRL;
+
+ /* NB: by convention this points at the base of registers */
+ ch->r_io[ATA_IDX_ADDR].offset = 0;
+
+ ata_generic_hw(dev);
+ return ata_attach(dev);
+}
+
+/* XXX override ata_generic_reset to handle non-standard status */
+static void
+avila_channel_reset(device_t dev)
+{
+ struct ata_channel *ch = device_get_softc(dev);
+ u_int8_t ostat0 = 0, stat0 = 0;
+ u_int8_t err = 0, lsb = 0, msb = 0;
+ int mask = 0, timeout;
+
+ /* do we have any signs of ATA/ATAPI HW being present ? */
+ ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_D_LBA | ATA_MASTER);
+ DELAY(10);
+ ostat0 = ATA_IDX_INB(ch, ATA_STATUS);
+ if ((ostat0 & 0xf8) != 0xf8 && ostat0 != 0xa5) {
+ stat0 = ATA_S_BUSY;
+ mask |= 0x01;
+ }
+
+ if (bootverbose)
+ device_printf(dev, "%s: reset tp1 mask=%02x ostat0=%02x\n",
+ __func__, mask, ostat0);
+
+ /* if nothing showed up there is no need to get any further */
+ /* XXX SOS is that too strong?, we just might loose devices here */
+ ch->devices = 0;
+ if (!mask)
+ return;
+
+ /* reset (both) devices on this channel */
+ ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_D_LBA | ATA_MASTER);
+ DELAY(10);
+ ATA_IDX_OUTB(ch, ATA_CONTROL, ATA_A_IDS | ATA_A_RESET);
+ ata_udelay(10000);
+ ATA_IDX_OUTB(ch, ATA_CONTROL, ATA_A_IDS);
+ ata_udelay(100000);
+ ATA_IDX_INB(ch, ATA_ERROR);
+
+ /* wait for BUSY to go inactive */
+ for (timeout = 0; timeout < 310; timeout++) {
+ if ((mask & 0x01) && (stat0 & ATA_S_BUSY)) {
+ ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_MASTER);
+ DELAY(10);
+ err = ATA_IDX_INB(ch, ATA_ERROR);
+ lsb = ATA_IDX_INB(ch, ATA_CYL_LSB);
+ msb = ATA_IDX_INB(ch, ATA_CYL_MSB);
+ stat0 = ATA_IDX_INB(ch, ATA_STATUS);
+ if (bootverbose)
+ device_printf(dev,
+ "%s: stat0=0x%02x err=0x%02x lsb=0x%02x "
+ "msb=0x%02x\n", __func__,
+ stat0, err, lsb, msb);
+ if (stat0 == err && lsb == err && msb == err &&
+ timeout > (stat0 & ATA_S_BUSY ? 100 : 10))
+ mask &= ~0x01;
+ if (!(stat0 & ATA_S_BUSY)) {
+ if ((err & 0x7f) == ATA_E_ILI || err == 0) {
+ if (lsb == ATAPI_MAGIC_LSB &&
+ msb == ATAPI_MAGIC_MSB) {
+ ch->devices |= ATA_ATAPI_MASTER;
+ } else if (stat0 & ATA_S_READY) {
+ ch->devices |= ATA_ATA_MASTER;
+ }
+ } else if ((stat0 & 0x0f) &&
+ err == lsb && err == msb) {
+ stat0 |= ATA_S_BUSY;
+ }
+ }
+ }
+ if (mask == 0x00) /* nothing to wait for */
+ break;
+ /* wait for master */
+ if (!(stat0 & ATA_S_BUSY) || (stat0 == 0xff && timeout > 10))
+ break;
+ ata_udelay(100000);
+ }
+
+ if (bootverbose)
+ device_printf(dev, "%s: reset tp2 stat0=%02x devices=0x%b\n",
+ __func__, stat0, ch->devices,
+ "\20\4ATAPI_SLAVE\3ATAPI_MASTER\2ATA_SLAVE\1ATA_MASTER");
+}
+
+static device_method_t avila_channel_methods[] = {
+ /* device interface */
+ DEVMETHOD(device_probe, avila_channel_probe),
+ DEVMETHOD(device_attach, avila_channel_attach),
+ DEVMETHOD(device_detach, ata_detach),
+ DEVMETHOD(device_shutdown, bus_generic_shutdown),
+ DEVMETHOD(device_suspend, ata_suspend),
+ DEVMETHOD(device_resume, ata_resume),
+
+ DEVMETHOD(ata_reset, avila_channel_reset),
+
+ { 0, 0 }
+};
+
+driver_t avila_channel_driver = {
+ "ata",
+ avila_channel_methods,
+ sizeof(struct ata_channel),
+};
+DRIVER_MODULE(ata, ata_avila, avila_channel_driver, ata_devclass, 0, 0);
diff --git a/sys/arm/xscale/ixp425/avila_machdep.c b/sys/arm/xscale/ixp425/avila_machdep.c
new file mode 100644
index 000000000000..b6efecf51576
--- /dev/null
+++ b/sys/arm/xscale/ixp425/avila_machdep.c
@@ -0,0 +1,545 @@
+/* $NetBSD: hpc_machdep.c,v 1.70 2003/09/16 08:18:22 agc Exp $ */
+
+/*-
+ * Copyright (c) 1994-1998 Mark Brinicombe.
+ * Copyright (c) 1994 Brini.
+ * All rights reserved.
+ *
+ * This code is derived from software written for Brini by Mark Brinicombe
+ *
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Brini.
+ * 4. The name of the company nor the name of the author may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BRINI ``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 BRINI 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.
+ *
+ * RiscBSD kernel project
+ *
+ * machdep.c
+ *
+ * Machine dependant functions for kernel setup
+ *
+ * This file needs a lot of work.
+ *
+ * Created : 17/09/94
+ */
+
+#include "opt_msgbuf.h"
+#include "opt_ddb.h"
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#define _ARM32_BUS_DMA_PRIVATE
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/sysproto.h>
+#include <sys/signalvar.h>
+#include <sys/imgact.h>
+#include <sys/kernel.h>
+#include <sys/ktr.h>
+#include <sys/linker.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mutex.h>
+#include <sys/pcpu.h>
+#include <sys/proc.h>
+#include <sys/ptrace.h>
+#include <sys/cons.h>
+#include <sys/bio.h>
+#include <sys/bus.h>
+#include <sys/buf.h>
+#include <sys/exec.h>
+#include <sys/kdb.h>
+#include <sys/msgbuf.h>
+#include <machine/reg.h>
+#include <machine/cpu.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+#include <vm/vm.h>
+#include <vm/vm_object.h>
+#include <vm/vm_page.h>
+#include <vm/vm_pager.h>
+#include <vm/vm_map.h>
+#include <vm/vnode_pager.h>
+#include <machine/pmap.h>
+#include <machine/vmparam.h>
+#include <machine/pcb.h>
+#include <machine/undefined.h>
+#include <machine/machdep.h>
+#include <machine/metadata.h>
+#include <machine/armreg.h>
+#include <machine/bus.h>
+#include <sys/reboot.h>
+
+#include <arm/xscale/ixp425/ixp425reg.h>
+#include <arm/xscale/ixp425/ixp425var.h>
+
+#define KERNEL_PT_SYS 0 /* Page table for mapping proc0 zero page */
+#define KERNEL_PT_IO 1
+#define KERNEL_PT_IO_NUM 3
+#define KERNEL_PT_BEFOREKERN KERNEL_PT_IO + KERNEL_PT_IO_NUM
+#define KERNEL_PT_AFKERNEL KERNEL_PT_BEFOREKERN + 1 /* L2 table for mapping after kernel */
+#define KERNEL_PT_AFKERNEL_NUM 9
+
+/* this should be evenly divisable by PAGE_SIZE / L2_TABLE_SIZE_REAL (or 4) */
+#define NUM_KERNEL_PTS (KERNEL_PT_AFKERNEL + KERNEL_PT_AFKERNEL_NUM)
+
+/* 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
+
+extern u_int data_abort_handler_address;
+extern u_int prefetch_abort_handler_address;
+extern u_int undefined_handler_address;
+
+struct pv_addr kernel_pt_table[NUM_KERNEL_PTS];
+
+extern void *_end;
+
+extern vm_offset_t sa1_cache_clean_addr;
+
+extern int *end;
+
+struct pcpu __pcpu;
+struct pcpu *pcpup = &__pcpu;
+
+/* Physical and virtual addresses for some global pages */
+
+vm_paddr_t phys_avail[10];
+vm_paddr_t dump_avail[4];
+vm_offset_t physical_pages;
+vm_offset_t clean_sva, clean_eva;
+
+struct pv_addr systempage;
+struct pv_addr msgbufpv;
+struct pv_addr irqstack;
+struct pv_addr undstack;
+struct pv_addr abtstack;
+struct pv_addr kernelstack;
+struct pv_addr minidataclean;
+
+static struct trapframe proc0_tf;
+
+/* Static device mappings. */
+static const struct pmap_devmap ixp425_devmap[] = {
+ /* Physical/Virtual address for I/O space */
+ {
+ IXP425_IO_VBASE,
+ IXP425_IO_HWBASE,
+ IXP425_IO_SIZE,
+ VM_PROT_READ|VM_PROT_WRITE,
+ PTE_NOCACHE,
+ },
+
+ /* Expansion Bus */
+ {
+ IXP425_EXP_VBASE,
+ IXP425_EXP_HWBASE,
+ IXP425_EXP_SIZE,
+ VM_PROT_READ|VM_PROT_WRITE,
+ PTE_NOCACHE,
+ },
+
+ /* IXP425 PCI Configuration */
+ {
+ IXP425_PCI_VBASE,
+ IXP425_PCI_HWBASE,
+ IXP425_PCI_SIZE,
+ VM_PROT_READ|VM_PROT_WRITE,
+ PTE_NOCACHE,
+ },
+
+ /* SDRAM Controller */
+ {
+ IXP425_MCU_VBASE,
+ IXP425_MCU_HWBASE,
+ IXP425_MCU_SIZE,
+ VM_PROT_READ|VM_PROT_WRITE,
+ PTE_NOCACHE,
+ },
+
+ /* PCI Memory Space */
+ {
+ IXP425_PCI_MEM_VBASE,
+ IXP425_PCI_MEM_HWBASE,
+ IXP425_PCI_MEM_SIZE,
+ VM_PROT_READ|VM_PROT_WRITE,
+ PTE_NOCACHE,
+ },
+ /* NPE-A Memory Space */
+ {
+ IXP425_NPE_A_VBASE,
+ IXP425_NPE_A_HWBASE,
+ IXP425_NPE_A_SIZE,
+ VM_PROT_READ|VM_PROT_WRITE,
+ PTE_NOCACHE,
+ },
+ /* NPE-B Memory Space */
+ {
+ IXP425_NPE_B_VBASE,
+ IXP425_NPE_B_HWBASE,
+ IXP425_NPE_B_SIZE,
+ VM_PROT_READ|VM_PROT_WRITE,
+ PTE_NOCACHE,
+ },
+ /* NPE-C Memory Space */
+ {
+ IXP425_NPE_C_VBASE,
+ IXP425_NPE_C_HWBASE,
+ IXP425_NPE_C_SIZE,
+ VM_PROT_READ|VM_PROT_WRITE,
+ PTE_NOCACHE,
+ },
+ /* MAC-A Memory Space */
+ {
+ IXP425_MAC_A_VBASE,
+ IXP425_MAC_A_HWBASE,
+ IXP425_MAC_A_SIZE,
+ VM_PROT_READ|VM_PROT_WRITE,
+ PTE_NOCACHE,
+ },
+ /* MAC-B Memory Space */
+ {
+ IXP425_MAC_B_VBASE,
+ IXP425_MAC_B_HWBASE,
+ IXP425_MAC_B_SIZE,
+ VM_PROT_READ|VM_PROT_WRITE,
+ PTE_NOCACHE,
+ },
+ /* Q-Mgr Memory Space */
+ {
+ IXP425_QMGR_VBASE,
+ IXP425_QMGR_HWBASE,
+ IXP425_QMGR_SIZE,
+ VM_PROT_READ|VM_PROT_WRITE,
+ PTE_NOCACHE,
+ },
+
+ {
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ }
+};
+
+#define SDRAM_START 0x10000000
+
+#ifdef DDB
+extern vm_offset_t ksym_start, ksym_end;
+#endif
+
+extern vm_offset_t xscale_cache_clean_addr;
+
+void *
+initarm(void *arg, void *arg2)
+{
+ struct pv_addr kernel_l1pt;
+ int loop;
+ u_int l1pagetable;
+ vm_offset_t freemempos;
+ vm_offset_t freemem_pt;
+ vm_offset_t afterkern;
+ vm_offset_t freemem_after;
+ vm_offset_t lastaddr;
+#ifdef DDB
+ vm_offset_t zstart = 0, zend = 0;
+#endif
+ int i = 0;
+ uint32_t fake_preload[35];
+ uint32_t memsize;
+
+ i = 0;
+
+ set_cpufuncs();
+ fake_preload[i++] = MODINFO_NAME;
+ fake_preload[i++] = strlen("elf kernel") + 1;
+ strcpy((char*)&fake_preload[i++], "elf kernel");
+ i += 2;
+ fake_preload[i++] = MODINFO_TYPE;
+ fake_preload[i++] = strlen("elf kernel") + 1;
+ strcpy((char*)&fake_preload[i++], "elf kernel");
+ i += 2;
+ fake_preload[i++] = MODINFO_ADDR;
+ fake_preload[i++] = sizeof(vm_offset_t);
+ fake_preload[i++] = KERNBASE + 0x00200000;
+ fake_preload[i++] = MODINFO_SIZE;
+ fake_preload[i++] = sizeof(uint32_t);
+ fake_preload[i++] = (uint32_t)&end - KERNBASE - 0x00200000;
+#ifdef DDB
+ if (*(uint32_t *)KERNVIRTADDR == MAGIC_TRAMP_NUMBER) {
+ fake_preload[i++] = MODINFO_METADATA|MODINFOMD_SSYM;
+ fake_preload[i++] = sizeof(vm_offset_t);
+ fake_preload[i++] = *(uint32_t *)(KERNVIRTADDR + 4);
+ fake_preload[i++] = MODINFO_METADATA|MODINFOMD_ESYM;
+ fake_preload[i++] = sizeof(vm_offset_t);
+ fake_preload[i++] = *(uint32_t *)(KERNVIRTADDR + 8);
+ lastaddr = *(uint32_t *)(KERNVIRTADDR + 8);
+ zend = lastaddr;
+ zstart = *(uint32_t *)(KERNVIRTADDR + 4);
+ ksym_start = zstart;
+ ksym_end = zend;
+ } else
+#endif
+ lastaddr = (vm_offset_t)&end;
+
+ fake_preload[i++] = 0;
+ fake_preload[i] = 0;
+ preload_metadata = (void *)fake_preload;
+
+
+ pcpu_init(pcpup, 0, sizeof(struct pcpu));
+ PCPU_SET(curthread, &thread0);
+
+#define KERNEL_TEXT_BASE (KERNBASE + 0x00200000)
+ freemempos = 0x10200000;
+ /* Define a macro to simplify memory allocation */
+#define valloc_pages(var, np) \
+ alloc_pages((var).pv_pa, (np)); \
+ (var).pv_va = (var).pv_pa + 0xb0000000;
+
+#define alloc_pages(var, np) \
+ freemempos -= (np * PAGE_SIZE); \
+ (var) = freemempos; \
+ memset((char *)(var), 0, ((np) * PAGE_SIZE));
+
+ while (((freemempos - L1_TABLE_SIZE) & (L1_TABLE_SIZE - 1)) != 0)
+ freemempos -= PAGE_SIZE;
+ valloc_pages(kernel_l1pt, L1_TABLE_SIZE / PAGE_SIZE);
+ for (loop = 0; loop < NUM_KERNEL_PTS; ++loop) {
+ if (!(loop % (PAGE_SIZE / L2_TABLE_SIZE_REAL))) {
+ valloc_pages(kernel_pt_table[loop],
+ L2_TABLE_SIZE / PAGE_SIZE);
+ } else {
+ kernel_pt_table[loop].pv_pa = freemempos +
+ (loop % (PAGE_SIZE / L2_TABLE_SIZE_REAL)) *
+ L2_TABLE_SIZE_REAL;
+ kernel_pt_table[loop].pv_va =
+ kernel_pt_table[loop].pv_pa + 0xb0000000;
+ }
+ }
+ freemem_pt = freemempos;
+ freemempos = 0x10100000;
+ /*
+ * 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);
+
+ /* 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, KSTACK_PAGES);
+ alloc_pages(minidataclean.pv_pa, 1);
+ valloc_pages(msgbufpv, round_page(MSGBUF_SIZE) / PAGE_SIZE);
+#ifdef ARM_USE_SMALL_ALLOC
+ freemempos -= PAGE_SIZE;
+ freemem_pt = trunc_page(freemem_pt);
+ freemem_after = freemempos - ((freemem_pt - 0x10100000) /
+ PAGE_SIZE) * sizeof(struct arm_small_page);
+ arm_add_smallalloc_pages((void *)(freemem_after + 0xb0000000)
+ , (void *)0xc0100000, freemem_pt - 0x10100000, 1);
+ freemem_after -= ((freemem_after - 0x10001000) / PAGE_SIZE) *
+ sizeof(struct arm_small_page);
+ arm_add_smallalloc_pages((void *)(freemem_after + 0xb0000000)
+ , (void *)0xc0001000, trunc_page(freemem_after) - 0x10001000, 0);
+ freemempos = trunc_page(freemem_after);
+ freemempos -= PAGE_SIZE;
+#endif
+ /*
+ * Allocate memory for the l1 and l2 page tables. The scheme to avoid
+ * wasting memory by allocating the l1pt on the first 16k memory was
+ * taken from NetBSD rpc_machdep.c. NKPT should be greater than 12 for
+ * this to work (which is supposed to be the case).
+ */
+
+ /*
+ * 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, ARM_VECTORS_HIGH & ~(0x00100000 - 1),
+ &kernel_pt_table[KERNEL_PT_SYS]);
+ pmap_link_l2pt(l1pagetable, IXP425_IO_VBASE,
+ &kernel_pt_table[KERNEL_PT_IO]);
+ pmap_link_l2pt(l1pagetable, IXP425_MCU_VBASE,
+ &kernel_pt_table[KERNEL_PT_IO + 1]);
+ pmap_link_l2pt(l1pagetable, IXP425_PCI_MEM_VBASE,
+ &kernel_pt_table[KERNEL_PT_IO + 2]);
+ pmap_link_l2pt(l1pagetable, KERNBASE,
+ &kernel_pt_table[KERNEL_PT_BEFOREKERN]);
+ pmap_map_chunk(l1pagetable, KERNBASE, SDRAM_START, 0x100000,
+ VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE);
+ pmap_map_chunk(l1pagetable, KERNBASE + 0x100000, SDRAM_START + 0x100000,
+ 0x100000, VM_PROT_READ|VM_PROT_WRITE, PTE_PAGETABLE);
+ pmap_map_chunk(l1pagetable, KERNBASE + 0x200000, SDRAM_START + 0x200000,
+ (((uint32_t)(lastaddr) - KERNBASE - 0x200000) + L1_S_SIZE) & ~(L1_S_SIZE - 1),
+ VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE);
+ freemem_after = ((int)lastaddr + PAGE_SIZE) & ~(PAGE_SIZE - 1);
+ afterkern = round_page(((vm_offset_t)lastaddr + L1_S_SIZE) & ~(L1_S_SIZE
+ - 1));
+ for (i = 0; i < KERNEL_PT_AFKERNEL_NUM; i++) {
+ pmap_link_l2pt(l1pagetable, afterkern + i * 0x00100000,
+ &kernel_pt_table[KERNEL_PT_AFKERNEL + i]);
+ }
+ pmap_map_entry(l1pagetable, afterkern, minidataclean.pv_pa,
+ VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE);
+
+
+#ifdef ARM_USE_SMALL_ALLOC
+ if ((freemem_after + 2 * PAGE_SIZE) <= afterkern) {
+ arm_add_smallalloc_pages((void *)(freemem_after),
+ (void*)(freemem_after + PAGE_SIZE),
+ afterkern - (freemem_after + PAGE_SIZE), 0);
+
+ }
+#endif
+
+ /* Map the Mini-Data cache clean area. */
+ xscale_setup_minidata(l1pagetable, afterkern,
+ minidataclean.pv_pa);
+
+ /* Map the vector page. */
+ pmap_map_entry(l1pagetable, ARM_VECTORS_HIGH, systempage.pv_pa,
+ VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE);
+ pmap_devmap_bootstrap(l1pagetable, ixp425_devmap);
+ /*
+ * Give the XScale global cache clean code an appropriately
+ * sized chunk of unmapped VA space starting at 0xff000000
+ * (our device mappings end before this address).
+ */
+ xscale_cache_clean_addr = 0xff000000U;
+
+ cpu_domains((DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2)) | DOMAIN_CLIENT);
+ setttb(kernel_l1pt.pv_pa);
+ cpu_tlb_flushID();
+ cpu_domains(DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2));
+ /*
+ * 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.
+ */
+
+
+ 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);
+
+
+
+ /*
+ * We must now clean the cache again....
+ * Cleaning may be done by reading new data to displace any
+ * dirty data in the cache. This will have happened in setttb()
+ * but since we are boot strapping the addresses used for the read
+ * may have just been remapped and thus the cache could be out
+ * of sync. A re-clean after the switch will cure this.
+ * After booting there are no gross reloations of the kernel thus
+ * this problem will not occur after initarm().
+ */
+ cpu_idcache_wbinv_all();
+ /*
+ * Fetch the SDRAM start/size from the ixp425 SDRAM configration
+ * registers.
+ */
+ cninit();
+ memsize = ixp425_sdram_size();
+ physmem = memsize / PAGE_SIZE;
+
+ /* Set stack for exception handlers */
+
+ 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;
+ undefined_init();
+
+#ifdef KSE
+ proc_linkup(&proc0, &ksegrp0, &thread0);
+#else
+ proc_linkup(&proc0, &thread0);
+#endif
+ thread0.td_kstack = kernelstack.pv_va;
+ thread0.td_pcb = (struct pcb *)
+ (thread0.td_kstack + KSTACK_PAGES * PAGE_SIZE) - 1;
+ thread0.td_pcb->pcb_flags = 0;
+ thread0.td_frame = &proc0_tf;
+ pcpup->pc_curpcb = thread0.td_pcb;
+
+ /* Enable MMU, I-cache, D-cache, write buffer. */
+
+ arm_vector_init(ARM_VECTORS_HIGH, ARM_VEC_ALL);
+
+
+
+ pmap_curmaxkvaddr = afterkern + PAGE_SIZE;
+ dump_avail[0] = 0x10000000;
+ dump_avail[1] = 0x10000000 + memsize;
+ dump_avail[2] = 0;
+ dump_avail[3] = 0;
+
+ pmap_bootstrap(pmap_curmaxkvaddr,
+ 0xd0000000, &kernel_l1pt);
+ msgbufp = (void*)msgbufpv.pv_va;
+ msgbufinit(msgbufp, MSGBUF_SIZE);
+ mutex_init();
+
+ i = 0;
+#ifdef ARM_USE_SMALL_ALLOC
+ phys_avail[i++] = 0x10000000;
+ phys_avail[i++] = 0x10001000; /*
+ *XXX: Gross hack to get our
+ * pages in the vm_page_array
+ . */
+#endif
+ phys_avail[i++] = round_page(virtual_avail - KERNBASE + SDRAM_START);
+ phys_avail[i++] = trunc_page(0x10000000 + memsize - 1);
+ phys_avail[i++] = 0;
+ phys_avail[i] = 0;
+
+ /* Do basic tuning, hz etc */
+ init_param1();
+ init_param2(physmem);
+ kdb_init();
+ return ((void *)(kernelstack.pv_va + USPACE_SVC_STACK_TOP -
+ sizeof(struct pcb)));
+}
diff --git a/sys/arm/xscale/ixp425/files.avila b/sys/arm/xscale/ixp425/files.avila
new file mode 100644
index 000000000000..f5f2dbce95b4
--- /dev/null
+++ b/sys/arm/xscale/ixp425/files.avila
@@ -0,0 +1,4 @@
+#$FreeBSD$
+arm/xscale/ixp425/avila_machdep.c standard
+arm/xscale/ixp425/avila_ata.c optional avila_ata
+arm/xscale/ixp425/ixdp425_pci.c optional pci
diff --git a/sys/arm/xscale/ixp425/files.ixp425 b/sys/arm/xscale/ixp425/files.ixp425
new file mode 100644
index 000000000000..9304b7c6d330
--- /dev/null
+++ b/sys/arm/xscale/ixp425/files.ixp425
@@ -0,0 +1,41 @@
+#$FreeBSD$
+arm/arm/cpufunc_asm_xscale.S standard
+arm/arm/irq_dispatch.S standard
+arm/xscale/ixp425/ixp425.c standard
+arm/xscale/ixp425/ixp425_mem.c standard
+arm/xscale/ixp425/ixp425_space.c standard
+arm/xscale/ixp425/ixp425_timer.c standard
+arm/xscale/ixp425/ixp425_wdog.c optional ixpwdog
+arm/xscale/ixp425/ixp425_iic.c optional ixpiic
+arm/xscale/ixp425/ixp425_pci.c optional pci
+arm/xscale/ixp425/ixp425_pci_asm.S optional pci
+arm/xscale/ixp425/ixp425_pci_space.c optional pci
+arm/xscale/ixp425/uart_cpu_ixp425.c optional uart
+arm/xscale/ixp425/uart_bus_ixp425.c optional uart
+arm/xscale/ixp425/ixp425_a4x_space.c optional uart
+arm/xscale/ixp425/ixp425_a4x_io.S optional uart
+dev/uart/uart_dev_ns8250.c optional uart
+#
+# NPE-based Ethernet support (requires qmgr also). Note the
+# firmware images must be downloaded from the Intel web site.
+#
+arm/xscale/ixp425/if_npe.c optional npe
+arm/xscale/ixp425/ixp425_npe.c optional npe
+ixp425_npe_fw.c optional npe_fw \
+ compile-with "${AWK} -f $S/tools/fw_stub.awk IxNpeMicrocode.dat:npe_fw -mnpe -c${.TARGET}" \
+ no-implicit-rule before-depend local \
+ clean "ixp425_npe_fw.c"
+#
+# NB: ld encodes the path in the binary symbols generated for the
+# firmware image so link the file to the object directory to
+# get known values for reference in the _fw.c file.
+#
+IxNpeMicrocode.fwo optional npe_fw \
+ dependency "$S/arm/xscale/ixp425/IxNpeMicrocode.dat" \
+ compile-with "ln -sf $S/arm/xscale/ixp425/IxNpeMicrocode.dat ${.OBJDIR}; ${LD} -b binary -d -warn-common -r -d -o ${.TARGET} IxNpeMicrocode.dat" \
+ no-implicit-rule \
+ clean "IxNpeMicrocode.dat IxNpeMicrocode.fwo"
+#
+# Q-Manager support
+#
+arm/xscale/ixp425/ixp425_qmgr.c optional qmgr
diff --git a/sys/arm/xscale/ixp425/if_npe.c b/sys/arm/xscale/ixp425/if_npe.c
new file mode 100644
index 000000000000..c63fc986093b
--- /dev/null
+++ b/sys/arm/xscale/ixp425/if_npe.c
@@ -0,0 +1,1673 @@
+/*-
+ * Copyright (c) 2006 Sam Leffler. 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>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Intel XScale NPE Ethernet driver.
+ *
+ * This driver handles the two ports present on the IXP425.
+ * Packet processing is done by the Network Processing Engines
+ * (NPE's) that work together with a MAC and PHY. The MAC
+ * is also mapped to the XScale cpu; the PHY is accessed via
+ * the MAC. NPE-XScale communication happens through h/w
+ * queues managed by the Q Manager block.
+ *
+ * The code here replaces the ethAcc, ethMii, and ethDB classes
+ * in the Intel Access Library (IAL) and the OS-specific driver.
+ *
+ * XXX add vlan support
+ * XXX NPE-C port doesn't work yet
+ */
+#ifdef HAVE_KERNEL_OPTION_HEADERS
+#include "opt_device_polling.h"
+#endif
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/mbuf.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/rman.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/sysctl.h>
+#include <sys/endian.h>
+#include <machine/bus.h>
+
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+#include <net/if_mib.h>
+#include <net/if_types.h>
+
+#ifdef INET
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/in_var.h>
+#include <netinet/ip.h>
+#endif
+
+#include <net/bpf.h>
+#include <net/bpfdesc.h>
+
+#include <arm/xscale/ixp425/ixp425reg.h>
+#include <arm/xscale/ixp425/ixp425var.h>
+#include <arm/xscale/ixp425/ixp425_qmgr.h>
+#include <arm/xscale/ixp425/ixp425_npevar.h>
+
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+#include <arm/xscale/ixp425/if_npereg.h>
+
+#include "miibus_if.h"
+
+struct npebuf {
+ struct npebuf *ix_next; /* chain to next buffer */
+ void *ix_m; /* backpointer to mbuf */
+ bus_dmamap_t ix_map; /* bus dma map for associated data */
+ struct npehwbuf *ix_hw; /* associated h/w block */
+ uint32_t ix_neaddr; /* phys address of ix_hw */
+};
+
+struct npedma {
+ const char* name;
+ int nbuf; /* # npebuf's allocated */
+ bus_dma_tag_t mtag; /* bus dma tag for mbuf data */
+ struct npehwbuf *hwbuf; /* NPE h/w buffers */
+ bus_dma_tag_t buf_tag; /* tag+map for NPE buffers */
+ bus_dmamap_t buf_map;
+ bus_addr_t buf_phys; /* phys addr of buffers */
+ struct npebuf *buf; /* s/w buffers (1-1 w/ h/w) */
+};
+
+struct npe_softc {
+ /* XXX mii requires this be first; do not move! */
+ struct ifnet *sc_ifp; /* ifnet pointer */
+ struct mtx sc_mtx; /* basically a perimeter lock */
+ device_t sc_dev;
+ bus_space_tag_t sc_iot;
+ bus_space_handle_t sc_ioh; /* MAC register window */
+ device_t sc_mii; /* child miibus */
+ bus_space_handle_t sc_miih; /* MII register window */
+ struct ixpnpe_softc *sc_npe; /* NPE support */
+ int sc_debug; /* DPRINTF* control */
+ int sc_tickinterval;
+ struct callout tick_ch; /* Tick callout */
+ struct npedma txdma;
+ struct npebuf *tx_free; /* list of free tx buffers */
+ struct npedma rxdma;
+ bus_addr_t buf_phys; /* XXX for returning a value */
+ int rx_qid; /* rx qid */
+ int rx_freeqid; /* rx free buffers qid */
+ int tx_qid; /* tx qid */
+ int tx_doneqid; /* tx completed qid */
+ struct ifmib_iso_8802_3 mibdata;
+ bus_dma_tag_t sc_stats_tag; /* bus dma tag for stats block */
+ struct npestats *sc_stats;
+ bus_dmamap_t sc_stats_map;
+ bus_addr_t sc_stats_phys; /* phys addr of sc_stats */
+};
+
+/*
+ * Per-unit static configuration for IXP425. The tx and
+ * rx free Q id's are fixed by the NPE microcode. The
+ * rx Q id's are programmed to be separate to simplify
+ * multi-port processing. It may be better to handle
+ * all traffic through one Q (as done by the Intel drivers).
+ *
+ * Note that the PHY's are accessible only from MAC A
+ * on the IXP425. This and other platform-specific
+ * assumptions probably need to be handled through hints.
+ */
+static const struct {
+ const char *desc; /* device description */
+ int npeid; /* NPE assignment */
+ uint32_t imageid; /* NPE firmware image id */
+ uint32_t regbase;
+ int regsize;
+ uint32_t miibase;
+ int miisize;
+ uint8_t rx_qid;
+ uint8_t rx_freeqid;
+ uint8_t tx_qid;
+ uint8_t tx_doneqid;
+} npeconfig[NPE_PORTS_MAX] = {
+ { .desc = "IXP NPE-B",
+ .npeid = NPE_B,
+ .imageid = IXP425_NPE_B_IMAGEID,
+ .regbase = IXP425_MAC_A_HWBASE,
+ .regsize = IXP425_MAC_A_SIZE,
+ .miibase = IXP425_MAC_A_HWBASE,
+ .miisize = IXP425_MAC_A_SIZE,
+ .rx_qid = 4,
+ .rx_freeqid = 27,
+ .tx_qid = 24,
+ .tx_doneqid = 31
+ },
+ { .desc = "IXP NPE-C",
+ .npeid = NPE_C,
+ .imageid = IXP425_NPE_C_IMAGEID,
+ .regbase = IXP425_MAC_B_HWBASE,
+ .regsize = IXP425_MAC_B_SIZE,
+ .miibase = IXP425_MAC_A_HWBASE,
+ .miisize = IXP425_MAC_A_SIZE,
+ .rx_qid = 12,
+ .rx_freeqid = 28,
+ .tx_qid = 25,
+ .tx_doneqid = 31
+ },
+};
+static struct npe_softc *npes[NPE_MAX]; /* NB: indexed by npeid */
+
+static __inline uint32_t
+RD4(struct npe_softc *sc, bus_size_t off)
+{
+ return bus_space_read_4(sc->sc_iot, sc->sc_ioh, off);
+}
+
+static __inline void
+WR4(struct npe_softc *sc, bus_size_t off, uint32_t val)
+{
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, off, val);
+}
+
+#define NPE_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx)
+#define NPE_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx)
+#define NPE_LOCK_INIT(_sc) \
+ mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->sc_dev), \
+ MTX_NETWORK_LOCK, MTX_DEF)
+#define NPE_LOCK_DESTROY(_sc) mtx_destroy(&_sc->sc_mtx);
+#define NPE_ASSERT_LOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_OWNED);
+#define NPE_ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_NOTOWNED);
+
+static devclass_t npe_devclass;
+
+static int npe_activate(device_t dev);
+static void npe_deactivate(device_t dev);
+static int npe_ifmedia_update(struct ifnet *ifp);
+static void npe_ifmedia_status(struct ifnet *ifp, struct ifmediareq *ifmr);
+static void npe_setmac(struct npe_softc *sc, u_char *eaddr);
+static void npe_getmac(struct npe_softc *sc, u_char *eaddr);
+static void npe_txdone(int qid, void *arg);
+static int npe_rxbuf_init(struct npe_softc *, struct npebuf *,
+ struct mbuf *);
+static void npe_rxdone(int qid, void *arg);
+static void npeinit(void *);
+static void npestart_locked(struct ifnet *);
+static void npestart(struct ifnet *);
+static void npestop(struct npe_softc *);
+static void npewatchdog(struct ifnet *);
+static int npeioctl(struct ifnet * ifp, u_long, caddr_t);
+
+static int npe_setrxqosentry(struct npe_softc *, int classix,
+ int trafclass, int qid);
+static int npe_updatestats(struct npe_softc *);
+#if 0
+static int npe_getstats(struct npe_softc *);
+static uint32_t npe_getimageid(struct npe_softc *);
+static int npe_setloopback(struct npe_softc *, int ena);
+#endif
+
+/* NB: all tx done processing goes through one queue */
+static int tx_doneqid = -1;
+
+SYSCTL_NODE(_hw, OID_AUTO, npe, CTLFLAG_RD, 0, "IXP425 NPE driver parameters");
+
+static int npe_debug = 0;
+SYSCTL_INT(_hw_npe, OID_AUTO, debug, CTLFLAG_RW, &npe_debug,
+ 0, "IXP425 NPE network interface debug msgs");
+TUNABLE_INT("hw.npe.npe", &npe_debug);
+#define DPRINTF(sc, fmt, ...) do { \
+ if (sc->sc_debug) device_printf(sc->sc_dev, fmt, __VA_ARGS__); \
+} while (0)
+#define DPRINTFn(n, sc, fmt, ...) do { \
+ if (sc->sc_debug >= n) device_printf(sc->sc_dev, fmt, __VA_ARGS__);\
+} while (0)
+static int npe_tickinterval = 3; /* npe_tick frequency (secs) */
+SYSCTL_INT(_hw_npe, OID_AUTO, tickinterval, CTLFLAG_RD, &npe_tickinterval,
+ 0, "periodic work interval (secs)");
+TUNABLE_INT("hw.npe.tickinterval", &npe_tickinterval);
+
+static int npe_rxbuf = 64; /* # rx buffers to allocate */
+SYSCTL_INT(_hw_npe, OID_AUTO, rxbuf, CTLFLAG_RD, &npe_rxbuf,
+ 0, "rx buffers allocated");
+TUNABLE_INT("hw.npe.rxbuf", &npe_rxbuf);
+static int npe_txbuf = 128; /* # tx buffers to allocate */
+SYSCTL_INT(_hw_npe, OID_AUTO, txbuf, CTLFLAG_RD, &npe_txbuf,
+ 0, "tx buffers allocated");
+TUNABLE_INT("hw.npe.txbuf", &npe_txbuf);
+
+static int
+npe_probe(device_t dev)
+{
+ int unit = device_get_unit(dev);
+
+ if (unit >= NPE_PORTS_MAX) {
+ device_printf(dev, "unit %d not supported\n", unit);
+ return EINVAL;
+ }
+ /* XXX check feature register to see if enabled */
+ device_set_desc(dev, npeconfig[unit].desc);
+ return 0;
+}
+
+static int
+npe_attach(device_t dev)
+{
+ struct npe_softc *sc = device_get_softc(dev);
+ struct ixp425_softc *sa = device_get_softc(device_get_parent(dev));
+ struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev);
+ struct sysctl_oid *tree = device_get_sysctl_tree(dev);
+ struct ifnet *ifp = NULL;
+ int error;
+ u_char eaddr[6];
+
+ sc->sc_dev = dev;
+ sc->sc_iot = sa->sc_iot;
+ NPE_LOCK_INIT(sc);
+ callout_init_mtx(&sc->tick_ch, &sc->sc_mtx, 0);
+ sc->sc_debug = npe_debug;
+ sc->sc_tickinterval = npe_tickinterval;
+
+ sc->sc_npe = ixpnpe_attach(dev);
+ if (sc->sc_npe == NULL) {
+ error = EIO; /* XXX */
+ goto out;
+ }
+
+ error = npe_activate(dev);
+ if (error)
+ goto out;
+
+ npe_getmac(sc, eaddr);
+
+ /* NB: must be setup prior to invoking mii code */
+ sc->sc_ifp = ifp = if_alloc(IFT_ETHER);
+ if (mii_phy_probe(dev, &sc->sc_mii, npe_ifmedia_update, npe_ifmedia_status)) {
+ device_printf(dev, "Cannot find my PHY.\n");
+ error = ENXIO;
+ goto out;
+ }
+
+ ifp->if_softc = sc;
+ if_initname(ifp, device_get_name(dev), device_get_unit(dev));
+ ifp->if_mtu = ETHERMTU;
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+ ifp->if_start = npestart;
+ ifp->if_ioctl = npeioctl;
+ ifp->if_watchdog = npewatchdog;
+ ifp->if_init = npeinit;
+ IFQ_SET_MAXLEN(&ifp->if_snd, sc->txdma.nbuf - 1);
+ ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
+ IFQ_SET_READY(&ifp->if_snd);
+ ifp->if_timer = 0;
+ ifp->if_linkmib = &sc->mibdata;
+ ifp->if_linkmiblen = sizeof(sc->mibdata);
+ sc->mibdata.dot3Compliance = DOT3COMPLIANCE_STATS;
+#ifdef DEVICE_POLLING
+ ifp->if_capabilities |= IFCAP_POLLING;
+#endif
+
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "debug",
+ CTLFLAG_RW, &sc->sc_debug, 0, "control debugging printfs");
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "tickinterval",
+ CTLFLAG_RW, &sc->sc_tickinterval, 0, "periodic work frequency");
+
+ ether_ifattach(ifp, eaddr);
+ return 0;
+out:
+ npe_deactivate(dev);
+ if (ifp != NULL)
+ if_free(ifp);
+ return error;
+}
+
+static int
+npe_detach(device_t dev)
+{
+ struct npe_softc *sc = device_get_softc(dev);
+ struct ifnet *ifp = sc->sc_ifp;
+
+#ifdef DEVICE_POLLING
+ if (ifp->if_capenable & IFCAP_POLLING)
+ ether_poll_deregister(ifp);
+#endif
+ npestop(sc);
+ if (ifp != NULL) {
+ ether_ifdetach(ifp);
+ if_free(ifp);
+ }
+ NPE_LOCK_DESTROY(sc);
+ npe_deactivate(dev);
+ if (sc->sc_npe != NULL)
+ ixpnpe_detach(sc->sc_npe);
+ return 0;
+}
+
+/*
+ * Compute and install the multicast filter.
+ */
+static void
+npe_setmcast(struct npe_softc *sc)
+{
+ struct ifnet *ifp = sc->sc_ifp;
+ uint8_t mask[ETHER_ADDR_LEN], addr[ETHER_ADDR_LEN];
+ int i;
+
+ if (ifp->if_flags & IFF_PROMISC) {
+ memset(mask, 0, ETHER_ADDR_LEN);
+ memset(addr, 0, ETHER_ADDR_LEN);
+ } else if (ifp->if_flags & IFF_ALLMULTI) {
+ static const uint8_t allmulti[ETHER_ADDR_LEN] =
+ { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 };
+ memcpy(mask, allmulti, ETHER_ADDR_LEN);
+ memcpy(addr, allmulti, ETHER_ADDR_LEN);
+ } else {
+ uint8_t clr[ETHER_ADDR_LEN], set[ETHER_ADDR_LEN];
+ struct ifmultiaddr *ifma;
+ const uint8_t *mac;
+
+ memset(clr, 0, ETHER_ADDR_LEN);
+ memset(set, 0xff, ETHER_ADDR_LEN);
+
+ IF_ADDR_LOCK(ifp);
+ TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
+ if (ifma->ifma_addr->sa_family != AF_LINK)
+ continue;
+ mac = LLADDR((struct sockaddr_dl *) ifma->ifma_addr);
+ for (i = 0; i < ETHER_ADDR_LEN; i++) {
+ clr[i] |= mac[i];
+ set[i] &= mac[i];
+ }
+ }
+ IF_ADDR_UNLOCK(ifp);
+
+ for (i = 0; i < ETHER_ADDR_LEN; i++) {
+ mask[i] = set[i] | ~clr[i];
+ addr[i] = set[i];
+ }
+ }
+
+ /*
+ * Write the mask and address registers.
+ */
+ for (i = 0; i < ETHER_ADDR_LEN; i++) {
+ WR4(sc, NPE_MAC_ADDR_MASK(i), mask[i]);
+ WR4(sc, NPE_MAC_ADDR(i), addr[i]);
+ }
+}
+
+static void
+npe_getaddr(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
+{
+ struct npe_softc *sc;
+
+ if (error != 0)
+ return;
+ sc = (struct npe_softc *)arg;
+ sc->buf_phys = segs[0].ds_addr;
+}
+
+static int
+npe_dma_setup(struct npe_softc *sc, struct npedma *dma,
+ const char *name, int nbuf, int maxseg)
+{
+ int error, i;
+
+ memset(dma, 0, sizeof(dma));
+
+ dma->name = name;
+ dma->nbuf = nbuf;
+
+ /* DMA tag for mapped mbufs */
+ error = bus_dma_tag_create(NULL, 1, 0,
+ BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
+ MCLBYTES, maxseg, MCLBYTES, 0,
+ busdma_lock_mutex, &sc->sc_mtx, &dma->mtag);
+ if (error != 0) {
+ device_printf(sc->sc_dev, "unable to create %s mbuf dma tag, "
+ "error %u\n", dma->name, error);
+ return error;
+ }
+
+ /* DMA tag and map for the NPE buffers */
+ error = bus_dma_tag_create(NULL, sizeof(uint32_t), 0,
+ BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
+ nbuf * sizeof(struct npehwbuf), 1,
+ nbuf * sizeof(struct npehwbuf), 0,
+ busdma_lock_mutex, &sc->sc_mtx, &dma->buf_tag);
+ if (error != 0) {
+ device_printf(sc->sc_dev,
+ "unable to create %s npebuf dma tag, error %u\n",
+ dma->name, error);
+ return error;
+ }
+ /* XXX COHERENT for now */
+ if (bus_dmamem_alloc(dma->buf_tag, (void **)&dma->hwbuf,
+ BUS_DMA_NOWAIT | BUS_DMA_ZERO | BUS_DMA_COHERENT,
+ &dma->buf_map) != 0) {
+ device_printf(sc->sc_dev,
+ "unable to allocate memory for %s h/w buffers, error %u\n",
+ dma->name, error);
+ return error;
+ }
+ /* XXX M_TEMP */
+ dma->buf = malloc(nbuf * sizeof(struct npebuf), M_TEMP, M_NOWAIT | M_ZERO);
+ if (dma->buf == NULL) {
+ device_printf(sc->sc_dev,
+ "unable to allocate memory for %s s/w buffers\n",
+ dma->name);
+ return error;
+ }
+ if (bus_dmamap_load(dma->buf_tag, dma->buf_map,
+ dma->hwbuf, nbuf*sizeof(struct npehwbuf), npe_getaddr, sc, 0) != 0) {
+ device_printf(sc->sc_dev,
+ "unable to map memory for %s h/w buffers, error %u\n",
+ dma->name, error);
+ return error;
+ }
+ dma->buf_phys = sc->buf_phys;
+ for (i = 0; i < dma->nbuf; i++) {
+ struct npebuf *npe = &dma->buf[i];
+ struct npehwbuf *hw = &dma->hwbuf[i];
+
+ /* calculate offset to shared area */
+ npe->ix_neaddr = dma->buf_phys +
+ ((uintptr_t)hw - (uintptr_t)dma->hwbuf);
+ KASSERT((npe->ix_neaddr & 0x1f) == 0,
+ ("ixpbuf misaligned, PA 0x%x", npe->ix_neaddr));
+ error = bus_dmamap_create(dma->mtag, BUS_DMA_NOWAIT,
+ &npe->ix_map);
+ if (error != 0) {
+ device_printf(sc->sc_dev,
+ "unable to create dmamap for %s buffer %u, "
+ "error %u\n", dma->name, i, error);
+ return error;
+ }
+ npe->ix_hw = hw;
+ }
+ bus_dmamap_sync(dma->buf_tag, dma->buf_map, BUS_DMASYNC_PREWRITE);
+ return 0;
+}
+
+static void
+npe_dma_destroy(struct npe_softc *sc, struct npedma *dma)
+{
+ int i;
+
+ if (dma->hwbuf != NULL) {
+ for (i = 0; i < dma->nbuf; i++) {
+ struct npebuf *npe = &dma->buf[i];
+ bus_dmamap_destroy(dma->mtag, npe->ix_map);
+ }
+ bus_dmamap_unload(dma->buf_tag, dma->buf_map);
+ bus_dmamem_free(dma->buf_tag, dma->hwbuf, dma->buf_map);
+ bus_dmamap_destroy(dma->buf_tag, dma->buf_map);
+ }
+ if (dma->buf != NULL)
+ free(dma->buf, M_TEMP);
+ if (dma->buf_tag)
+ bus_dma_tag_destroy(dma->buf_tag);
+ if (dma->mtag)
+ bus_dma_tag_destroy(dma->mtag);
+ memset(dma, 0, sizeof(*dma));
+}
+
+static int
+npe_activate(device_t dev)
+{
+ struct npe_softc * sc = device_get_softc(dev);
+ int unit = device_get_unit(dev);
+ int error, i;
+
+ /* load NPE firmware and start it running */
+ error = ixpnpe_init(sc->sc_npe, "npe_fw", npeconfig[unit].imageid);
+ if (error != 0)
+ return error;
+
+ if (bus_space_map(sc->sc_iot, npeconfig[unit].regbase,
+ npeconfig[unit].regsize, 0, &sc->sc_ioh)) {
+ device_printf(dev, "Cannot map registers 0x%x:0x%x\n",
+ npeconfig[unit].regbase, npeconfig[unit].regsize);
+ return ENOMEM;
+ }
+
+ if (npeconfig[unit].miibase != npeconfig[unit].regbase) {
+ /*
+ * The PHY's are only accessible from one MAC (it appears)
+ * so for other MAC's setup an additional mapping for
+ * frobbing the PHY registers.
+ */
+ if (bus_space_map(sc->sc_iot, npeconfig[unit].miibase,
+ npeconfig[unit].miisize, 0, &sc->sc_miih)) {
+ device_printf(dev,
+ "Cannot map MII registers 0x%x:0x%x\n",
+ npeconfig[unit].miibase, npeconfig[unit].miisize);
+ return ENOMEM;
+ }
+ } else
+ sc->sc_miih = sc->sc_ioh;
+ error = npe_dma_setup(sc, &sc->txdma, "tx", npe_txbuf, NPE_MAXSEG);
+ if (error != 0)
+ return error;
+ error = npe_dma_setup(sc, &sc->rxdma, "rx", npe_rxbuf, 1);
+ if (error != 0)
+ return error;
+
+ /* setup statistics block */
+ error = bus_dma_tag_create(NULL, sizeof(uint32_t), 0,
+ BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
+ sizeof(struct npestats), 1, sizeof(struct npestats), 0,
+ busdma_lock_mutex, &sc->sc_mtx, &sc->sc_stats_tag);
+ if (error != 0) {
+ device_printf(sc->sc_dev, "unable to create stats tag, "
+ "error %u\n", error);
+ return error;
+ }
+ if (bus_dmamem_alloc(sc->sc_stats_tag, (void **)&sc->sc_stats,
+ BUS_DMA_NOWAIT, &sc->sc_stats_map) != 0) {
+ device_printf(sc->sc_dev,
+ "unable to allocate memory for stats block, error %u\n",
+ error);
+ return error;
+ }
+ if (bus_dmamap_load(sc->sc_stats_tag, sc->sc_stats_map,
+ sc->sc_stats, sizeof(struct npestats), npe_getaddr, sc, 0) != 0) {
+ device_printf(sc->sc_dev,
+ "unable to load memory for stats block, error %u\n",
+ error);
+ return error;
+ }
+ sc->sc_stats_phys = sc->buf_phys;
+
+ /* XXX disable half-bridge LEARNING+FILTERING feature */
+
+ /*
+ * Setup h/w rx/tx queues. There are four q's:
+ * rx inbound q of rx'd frames
+ * rx_free pool of ixpbuf's for receiving frames
+ * tx outbound q of frames to send
+ * tx_done q of tx frames that have been processed
+ *
+ * The NPE handles the actual tx/rx process and the q manager
+ * handles the queues. The driver just writes entries to the
+ * q manager mailbox's and gets callbacks when there are rx'd
+ * frames to process or tx'd frames to reap. These callbacks
+ * are controlled by the q configurations; e.g. we get a
+ * callback when tx_done has 2 or more frames to process and
+ * when the rx q has at least one frame. These setings can
+ * changed at the time the q is configured.
+ */
+ sc->rx_qid = npeconfig[unit].rx_qid;
+ ixpqmgr_qconfig(sc->rx_qid, npe_rxbuf, 0, 1,
+ IX_QMGR_Q_SOURCE_ID_NOT_E, npe_rxdone, sc);
+ sc->rx_freeqid = npeconfig[unit].rx_freeqid;
+ ixpqmgr_qconfig(sc->rx_freeqid, npe_rxbuf, 0, npe_rxbuf/2, 0, NULL, sc);
+ /* tell the NPE to direct all traffic to rx_qid */
+#if 0
+ for (i = 0; i < 8; i++)
+#else
+device_printf(sc->sc_dev, "remember to fix rx q setup\n");
+ for (i = 0; i < 4; i++)
+#endif
+ npe_setrxqosentry(sc, i, 0, sc->rx_qid);
+
+ sc->tx_qid = npeconfig[unit].tx_qid;
+ sc->tx_doneqid = npeconfig[unit].tx_doneqid;
+ ixpqmgr_qconfig(sc->tx_qid, npe_txbuf, 0, npe_txbuf, 0, NULL, sc);
+ if (tx_doneqid == -1) {
+ ixpqmgr_qconfig(sc->tx_doneqid, npe_txbuf, 0, 2,
+ IX_QMGR_Q_SOURCE_ID_NOT_E, npe_txdone, sc);
+ tx_doneqid = sc->tx_doneqid;
+ }
+
+ KASSERT(npes[npeconfig[unit].npeid] == NULL,
+ ("npe %u already setup", npeconfig[unit].npeid));
+ npes[npeconfig[unit].npeid] = sc;
+
+ return 0;
+}
+
+static void
+npe_deactivate(device_t dev)
+{
+ struct npe_softc *sc = device_get_softc(dev);
+ int unit = device_get_unit(dev);
+
+ npes[npeconfig[unit].npeid] = NULL;
+
+ /* XXX disable q's */
+ if (sc->sc_npe != NULL)
+ ixpnpe_stop(sc->sc_npe);
+ if (sc->sc_stats != NULL) {
+ bus_dmamap_unload(sc->sc_stats_tag, sc->sc_stats_map);
+ bus_dmamem_free(sc->sc_stats_tag, sc->sc_stats,
+ sc->sc_stats_map);
+ bus_dmamap_destroy(sc->sc_stats_tag, sc->sc_stats_map);
+ }
+ if (sc->sc_stats_tag != NULL)
+ bus_dma_tag_destroy(sc->sc_stats_tag);
+ npe_dma_destroy(sc, &sc->txdma);
+ npe_dma_destroy(sc, &sc->rxdma);
+ bus_generic_detach(sc->sc_dev);
+ if (sc->sc_mii)
+ device_delete_child(sc->sc_dev, sc->sc_mii);
+#if 0
+ /* XXX sc_ioh and sc_miih */
+ if (sc->mem_res)
+ bus_release_resource(dev, SYS_RES_IOPORT,
+ rman_get_rid(sc->mem_res), sc->mem_res);
+ sc->mem_res = 0;
+#endif
+}
+
+/*
+ * Change media according to request.
+ */
+static int
+npe_ifmedia_update(struct ifnet *ifp)
+{
+ struct npe_softc *sc = ifp->if_softc;
+ struct mii_data *mii;
+
+ mii = device_get_softc(sc->sc_mii);
+ NPE_LOCK(sc);
+ mii_mediachg(mii);
+ /* XXX push state ourself? */
+ NPE_UNLOCK(sc);
+ return (0);
+}
+
+/*
+ * Notify the world which media we're using.
+ */
+static void
+npe_ifmedia_status(struct ifnet *ifp, struct ifmediareq *ifmr)
+{
+ struct npe_softc *sc = ifp->if_softc;
+ struct mii_data *mii;
+
+ mii = device_get_softc(sc->sc_mii);
+ NPE_LOCK(sc);
+ mii_pollstat(mii);
+ ifmr->ifm_active = mii->mii_media_active;
+ ifmr->ifm_status = mii->mii_media_status;
+ NPE_UNLOCK(sc);
+}
+
+static void
+npe_addstats(struct npe_softc *sc)
+{
+#define MIBADD(x) sc->mibdata.x += be32toh(ns->x)
+ struct ifnet *ifp = sc->sc_ifp;
+ struct npestats *ns = sc->sc_stats;
+
+ MIBADD(dot3StatsAlignmentErrors);
+ MIBADD(dot3StatsFCSErrors);
+ MIBADD(dot3StatsSingleCollisionFrames);
+ MIBADD(dot3StatsMultipleCollisionFrames);
+ MIBADD(dot3StatsDeferredTransmissions);
+ MIBADD(dot3StatsLateCollisions);
+ MIBADD(dot3StatsExcessiveCollisions);
+ MIBADD(dot3StatsInternalMacTransmitErrors);
+ MIBADD(dot3StatsCarrierSenseErrors);
+ sc->mibdata.dot3StatsFrameTooLongs +=
+ be32toh(ns->RxLargeFramesDiscards)
+ + be32toh(ns->TxLargeFrameDiscards);
+ MIBADD(dot3StatsInternalMacReceiveErrors);
+ sc->mibdata.dot3StatsMissedFrames +=
+ be32toh(ns->RxOverrunDiscards)
+ + be32toh(ns->RxUnderflowEntryDiscards);
+
+ ifp->if_oerrors +=
+ be32toh(ns->dot3StatsInternalMacTransmitErrors)
+ + be32toh(ns->dot3StatsCarrierSenseErrors)
+ + be32toh(ns->TxVLANIdFilterDiscards)
+ ;
+ ifp->if_ierrors += be32toh(ns->dot3StatsFCSErrors)
+ + be32toh(ns->dot3StatsInternalMacReceiveErrors)
+ + be32toh(ns->RxOverrunDiscards)
+ + be32toh(ns->RxUnderflowEntryDiscards)
+ ;
+ ifp->if_collisions +=
+ be32toh(ns->dot3StatsSingleCollisionFrames)
+ + be32toh(ns->dot3StatsMultipleCollisionFrames)
+ ;
+#undef MIBADD
+}
+
+static void
+npe_tick(void *xsc)
+{
+#define ACK (NPE_RESETSTATS << NPE_MAC_MSGID_SHL)
+ struct npe_softc *sc = xsc;
+ struct mii_data *mii = device_get_softc(sc->sc_mii);
+ uint32_t msg[2];
+
+ NPE_ASSERT_LOCKED(sc);
+
+ /*
+ * NB: to avoid sleeping with the softc lock held we
+ * split the NPE msg processing into two parts. The
+ * request for statistics is sent w/o waiting for a
+ * reply and then on the next tick we retrieve the
+ * results. This works because npe_tick is the only
+ * code that talks via the mailbox's (except at setup).
+ * This likely can be handled better.
+ */
+ if (ixpnpe_recvmsg(sc->sc_npe, msg) == 0 && msg[0] == ACK) {
+ bus_dmamap_sync(sc->sc_stats_tag, sc->sc_stats_map,
+ BUS_DMASYNC_POSTREAD);
+ npe_addstats(sc);
+ }
+ npe_updatestats(sc);
+ mii_tick(mii);
+
+ /* schedule next poll */
+ callout_reset(&sc->tick_ch, sc->sc_tickinterval * hz, npe_tick, sc);
+#undef ACK
+}
+
+static void
+npe_setmac(struct npe_softc *sc, u_char *eaddr)
+{
+ WR4(sc, NPE_MAC_UNI_ADDR_1, eaddr[0]);
+ WR4(sc, NPE_MAC_UNI_ADDR_2, eaddr[1]);
+ WR4(sc, NPE_MAC_UNI_ADDR_3, eaddr[2]);
+ WR4(sc, NPE_MAC_UNI_ADDR_4, eaddr[3]);
+ WR4(sc, NPE_MAC_UNI_ADDR_5, eaddr[4]);
+ WR4(sc, NPE_MAC_UNI_ADDR_6, eaddr[5]);
+
+}
+
+static void
+npe_getmac(struct npe_softc *sc, u_char *eaddr)
+{
+ /* NB: the unicast address appears to be loaded from EEPROM on reset */
+ eaddr[0] = RD4(sc, NPE_MAC_UNI_ADDR_1) & 0xff;
+ eaddr[1] = RD4(sc, NPE_MAC_UNI_ADDR_2) & 0xff;
+ eaddr[2] = RD4(sc, NPE_MAC_UNI_ADDR_3) & 0xff;
+ eaddr[3] = RD4(sc, NPE_MAC_UNI_ADDR_4) & 0xff;
+ eaddr[4] = RD4(sc, NPE_MAC_UNI_ADDR_5) & 0xff;
+ eaddr[5] = RD4(sc, NPE_MAC_UNI_ADDR_6) & 0xff;
+}
+
+struct txdone {
+ struct npebuf *head;
+ struct npebuf **tail;
+ int count;
+};
+
+static __inline void
+npe_txdone_finish(struct npe_softc *sc, const struct txdone *td)
+{
+ struct ifnet *ifp = sc->sc_ifp;
+
+ NPE_LOCK(sc);
+ *td->tail = sc->tx_free;
+ sc->tx_free = td->head;
+ /*
+ * We're no longer busy, so clear the busy flag and call the
+ * start routine to xmit more packets.
+ */
+ ifp->if_opackets += td->count;
+ ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
+ ifp->if_timer = 0;
+ npestart_locked(ifp);
+ NPE_UNLOCK(sc);
+}
+
+/*
+ * Q manager callback on tx done queue. Reap mbufs
+ * and return tx buffers to the free list. Finally
+ * restart output. Note the microcode has only one
+ * txdone q wired into it so we must use the NPE ID
+ * returned with each npehwbuf to decide where to
+ * send buffers.
+ */
+static void
+npe_txdone(int qid, void *arg)
+{
+#define P2V(a, dma) \
+ &(dma)->buf[((a) - (dma)->buf_phys) / sizeof(struct npehwbuf)]
+ struct npe_softc *sc0 = arg;
+ struct npe_softc *sc;
+ struct npebuf *npe;
+ struct txdone *td, q[NPE_MAX];
+ uint32_t entry;
+
+ /* XXX no NPE-A support */
+ q[NPE_B].tail = &q[NPE_B].head; q[NPE_B].count = 0;
+ q[NPE_C].tail = &q[NPE_C].head; q[NPE_C].count = 0;
+ /* XXX max # at a time? */
+ while (ixpqmgr_qread(qid, &entry) == 0) {
+ DPRINTF(sc0, "%s: entry 0x%x NPE %u port %u\n",
+ __func__, entry, NPE_QM_Q_NPE(entry), NPE_QM_Q_PORT(entry));
+
+ sc = npes[NPE_QM_Q_NPE(entry)];
+ npe = P2V(NPE_QM_Q_ADDR(entry), &sc->txdma);
+ m_freem(npe->ix_m);
+ npe->ix_m = NULL;
+
+ td = &q[NPE_QM_Q_NPE(entry)];
+ *td->tail = npe;
+ td->tail = &npe->ix_next;
+ td->count++;
+ }
+
+ if (q[NPE_B].count)
+ npe_txdone_finish(npes[NPE_B], &q[NPE_B]);
+ if (q[NPE_C].count)
+ npe_txdone_finish(npes[NPE_C], &q[NPE_C]);
+#undef P2V
+}
+
+static int
+npe_rxbuf_init(struct npe_softc *sc, struct npebuf *npe, struct mbuf *m)
+{
+ bus_dma_segment_t segs[1];
+ struct npedma *dma = &sc->rxdma;
+ struct npehwbuf *hw;
+ int error, nseg;
+
+ if (m == NULL) {
+ m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
+ if (m == NULL)
+ return ENOBUFS;
+ }
+ KASSERT(m->m_ext.ext_size >= 1536 + ETHER_ALIGN,
+ ("ext_size %d", m->m_ext.ext_size));
+ m->m_pkthdr.len = m->m_len = 1536;
+ /* backload payload and align ip hdr */
+ m->m_data = m->m_ext.ext_buf + (m->m_ext.ext_size - (1536+ETHER_ALIGN));
+ error = bus_dmamap_load_mbuf_sg(dma->mtag, npe->ix_map, m,
+ segs, &nseg, 0);
+ if (error != 0) {
+ m_freem(m);
+ return error;
+ }
+ hw = npe->ix_hw;
+ hw->ix_ne[0].data = htobe32(segs[0].ds_addr);
+ /* NB: NPE requires length be a multiple of 64 */
+ /* NB: buffer length is shifted in word */
+ hw->ix_ne[0].len = htobe32(segs[0].ds_len << 16);
+ hw->ix_ne[0].next = 0;
+ npe->ix_m = m;
+ /* Flush the memory in the mbuf */
+ bus_dmamap_sync(dma->mtag, npe->ix_map, BUS_DMASYNC_PREREAD);
+ return 0;
+}
+
+/*
+ * RX q processing for a specific NPE. Claim entries
+ * from the hardware queue and pass the frames up the
+ * stack. Pass the rx buffers to the free list.
+ */
+static void
+npe_rxdone(int qid, void *arg)
+{
+#define P2V(a, dma) \
+ &(dma)->buf[((a) - (dma)->buf_phys) / sizeof(struct npehwbuf)]
+ struct npe_softc *sc = arg;
+ struct npedma *dma = &sc->rxdma;
+ uint32_t entry;
+
+ while (ixpqmgr_qread(qid, &entry) == 0) {
+ struct npebuf *npe = P2V(NPE_QM_Q_ADDR(entry), dma);
+ struct mbuf *m;
+
+ DPRINTF(sc, "%s: entry 0x%x neaddr 0x%x ne_len 0x%x\n",
+ __func__, entry, npe->ix_neaddr, npe->ix_hw->ix_ne[0].len);
+ /*
+ * Allocate a new mbuf to replenish the rx buffer.
+ * If doing so fails we drop the rx'd frame so we
+ * can reuse the previous mbuf. When we're able to
+ * allocate a new mbuf dispatch the mbuf w/ rx'd
+ * data up the stack and replace it with the newly
+ * allocated one.
+ */
+ m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
+ if (m != NULL) {
+ struct mbuf *mrx = npe->ix_m;
+ struct npehwbuf *hw = npe->ix_hw;
+ struct ifnet *ifp = sc->sc_ifp;
+
+ /* Flush mbuf memory for rx'd data */
+ bus_dmamap_sync(dma->mtag, npe->ix_map,
+ BUS_DMASYNC_POSTREAD);
+
+ /* XXX flush hw buffer; works now 'cuz coherent */
+ /* set m_len etc. per rx frame size */
+ mrx->m_len = be32toh(hw->ix_ne[0].len) & 0xffff;
+ mrx->m_pkthdr.len = mrx->m_len;
+ mrx->m_pkthdr.rcvif = ifp;
+ mrx->m_flags |= M_HASFCS;
+
+ ifp->if_ipackets++;
+ ifp->if_input(ifp, mrx);
+ } else {
+ /* discard frame and re-use mbuf */
+ m = npe->ix_m;
+ }
+ if (npe_rxbuf_init(sc, npe, m) == 0) {
+ /* return npe buf to rx free list */
+ ixpqmgr_qwrite(sc->rx_freeqid, npe->ix_neaddr);
+ } else {
+ /* XXX should not happen */
+ }
+ }
+#undef P2V
+}
+
+#ifdef DEVICE_POLLING
+static void
+npe_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
+{
+ struct npe_softc *sc = ifp->if_softc;
+
+ if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
+ npe_rxdone(sc->rx_qid, sc);
+ npe_txdone(sc->tx_doneqid, sc); /* XXX polls both NPE's */
+ }
+}
+#endif /* DEVICE_POLLING */
+
+static void
+npe_startxmit(struct npe_softc *sc)
+{
+ struct npedma *dma = &sc->txdma;
+ int i;
+
+ NPE_ASSERT_LOCKED(sc);
+ sc->tx_free = NULL;
+ for (i = 0; i < dma->nbuf; i++) {
+ struct npebuf *npe = &dma->buf[i];
+ if (npe->ix_m != NULL) {
+ /* NB: should not happen */
+ device_printf(sc->sc_dev,
+ "%s: free mbuf at entry %u\n", __func__, i);
+ m_freem(npe->ix_m);
+ }
+ npe->ix_m = NULL;
+ npe->ix_next = sc->tx_free;
+ sc->tx_free = npe;
+ }
+}
+
+static void
+npe_startrecv(struct npe_softc *sc)
+{
+ struct npedma *dma = &sc->rxdma;
+ struct npebuf *npe;
+ int i;
+
+ NPE_ASSERT_LOCKED(sc);
+ for (i = 0; i < dma->nbuf; i++) {
+ npe = &dma->buf[i];
+ npe_rxbuf_init(sc, npe, npe->ix_m);
+ /* set npe buf on rx free list */
+ ixpqmgr_qwrite(sc->rx_freeqid, npe->ix_neaddr);
+ }
+}
+
+/*
+ * Reset and initialize the chip
+ */
+static void
+npeinit_locked(void *xsc)
+{
+ struct npe_softc *sc = xsc;
+ struct ifnet *ifp = sc->sc_ifp;
+
+ NPE_ASSERT_LOCKED(sc);
+if (ifp->if_drv_flags & IFF_DRV_RUNNING) return;/*XXX*/
+
+ /*
+ * Reset MAC core.
+ */
+ WR4(sc, NPE_MAC_CORE_CNTRL, NPE_CORE_RESET);
+ DELAY(NPE_MAC_RESET_DELAY);
+ /* configure MAC to generate MDC clock */
+ WR4(sc, NPE_MAC_CORE_CNTRL, NPE_CORE_MDC_EN);
+
+ /* disable transmitter and reciver in the MAC */
+ WR4(sc, NPE_MAC_RX_CNTRL1,
+ RD4(sc, NPE_MAC_RX_CNTRL1) &~ NPE_RX_CNTRL1_RX_EN);
+ WR4(sc, NPE_MAC_TX_CNTRL1,
+ RD4(sc, NPE_MAC_TX_CNTRL1) &~ NPE_TX_CNTRL1_TX_EN);
+
+ /*
+ * Set the MAC core registers.
+ */
+ WR4(sc, NPE_MAC_INT_CLK_THRESH, 0x1); /* clock ratio: for ipx4xx */
+ WR4(sc, NPE_MAC_TX_CNTRL2, 0xf); /* max retries */
+ WR4(sc, NPE_MAC_RANDOM_SEED, 0x8); /* LFSR back-off seed */
+ /* thresholds determined by NPE firmware FS */
+ WR4(sc, NPE_MAC_THRESH_P_EMPTY, 0x12);
+ WR4(sc, NPE_MAC_THRESH_P_FULL, 0x30);
+ WR4(sc, NPE_MAC_BUF_SIZE_TX, 0x8); /* tx fifo threshold (bytes) */
+ WR4(sc, NPE_MAC_TX_DEFER, 0x15); /* for single deferral */
+ WR4(sc, NPE_MAC_RX_DEFER, 0x16); /* deferral on inter-frame gap*/
+ WR4(sc, NPE_MAC_TX_TWO_DEFER_1, 0x8); /* for 2-part deferral */
+ WR4(sc, NPE_MAC_TX_TWO_DEFER_2, 0x7); /* for 2-part deferral */
+ WR4(sc, NPE_MAC_SLOT_TIME, 0x80); /* assumes MII mode */
+
+ WR4(sc, NPE_MAC_TX_CNTRL1,
+ NPE_TX_CNTRL1_RETRY /* retry failed xmits */
+ | NPE_TX_CNTRL1_FCS_EN /* append FCS */
+ | NPE_TX_CNTRL1_2DEFER /* 2-part deferal */
+ | NPE_TX_CNTRL1_PAD_EN); /* pad runt frames */
+ /* XXX pad strip? */
+ WR4(sc, NPE_MAC_RX_CNTRL1,
+ NPE_RX_CNTRL1_CRC_EN /* include CRC/FCS */
+ | NPE_RX_CNTRL1_PAUSE_EN); /* ena pause frame handling */
+ WR4(sc, NPE_MAC_RX_CNTRL2, 0);
+
+ npe_setmac(sc, IF_LLADDR(ifp));
+ npe_setmcast(sc);
+
+ npe_startxmit(sc);
+ npe_startrecv(sc);
+
+ ifp->if_drv_flags |= IFF_DRV_RUNNING;
+ ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
+ ifp->if_timer = 0; /* just in case */
+
+ /* enable transmitter and reciver in the MAC */
+ WR4(sc, NPE_MAC_RX_CNTRL1,
+ RD4(sc, NPE_MAC_RX_CNTRL1) | NPE_RX_CNTRL1_RX_EN);
+ WR4(sc, NPE_MAC_TX_CNTRL1,
+ RD4(sc, NPE_MAC_TX_CNTRL1) | NPE_TX_CNTRL1_TX_EN);
+
+ callout_reset(&sc->tick_ch, sc->sc_tickinterval * hz, npe_tick, sc);
+}
+
+static void
+npeinit(void *xsc)
+{
+ struct npe_softc *sc = xsc;
+ NPE_LOCK(sc);
+ npeinit_locked(sc);
+ NPE_UNLOCK(sc);
+}
+
+/*
+ * Defragment an mbuf chain, returning at most maxfrags separate
+ * mbufs+clusters. If this is not possible NULL is returned and
+ * the original mbuf chain is left in it's present (potentially
+ * modified) state. We use two techniques: collapsing consecutive
+ * mbufs and replacing consecutive mbufs by a cluster.
+ */
+static struct mbuf *
+npe_defrag(struct mbuf *m0, int how, int maxfrags)
+{
+ struct mbuf *m, *n, *n2, **prev;
+ u_int curfrags;
+
+ /*
+ * Calculate the current number of frags.
+ */
+ curfrags = 0;
+ for (m = m0; m != NULL; m = m->m_next)
+ curfrags++;
+ /*
+ * First, try to collapse mbufs. Note that we always collapse
+ * towards the front so we don't need to deal with moving the
+ * pkthdr. This may be suboptimal if the first mbuf has much
+ * less data than the following.
+ */
+ m = m0;
+again:
+ for (;;) {
+ n = m->m_next;
+ if (n == NULL)
+ break;
+ if ((m->m_flags & M_RDONLY) == 0 &&
+ n->m_len < M_TRAILINGSPACE(m)) {
+ bcopy(mtod(n, void *), mtod(m, char *) + m->m_len,
+ n->m_len);
+ m->m_len += n->m_len;
+ m->m_next = n->m_next;
+ m_free(n);
+ if (--curfrags <= maxfrags)
+ return m0;
+ } else
+ m = n;
+ }
+ KASSERT(maxfrags > 1,
+ ("maxfrags %u, but normal collapse failed", maxfrags));
+ /*
+ * Collapse consecutive mbufs to a cluster.
+ */
+ prev = &m0->m_next; /* NB: not the first mbuf */
+ while ((n = *prev) != NULL) {
+ if ((n2 = n->m_next) != NULL &&
+ n->m_len + n2->m_len < MCLBYTES) {
+ m = m_getcl(how, MT_DATA, 0);
+ if (m == NULL)
+ goto bad;
+ bcopy(mtod(n, void *), mtod(m, void *), n->m_len);
+ bcopy(mtod(n2, void *), mtod(m, char *) + n->m_len,
+ n2->m_len);
+ m->m_len = n->m_len + n2->m_len;
+ m->m_next = n2->m_next;
+ *prev = m;
+ m_free(n);
+ m_free(n2);
+ if (--curfrags <= maxfrags) /* +1 cl -2 mbufs */
+ return m0;
+ /*
+ * Still not there, try the normal collapse
+ * again before we allocate another cluster.
+ */
+ goto again;
+ }
+ prev = &n->m_next;
+ }
+ /*
+ * No place where we can collapse to a cluster; punt.
+ * This can occur if, for example, you request 2 frags
+ * but the packet requires that both be clusters (we
+ * never reallocate the first mbuf to avoid moving the
+ * packet header).
+ */
+bad:
+ return NULL;
+}
+
+/*
+ * Dequeue packets and place on the h/w transmit queue.
+ */
+static void
+npestart_locked(struct ifnet *ifp)
+{
+ struct npe_softc *sc = ifp->if_softc;
+ struct npebuf *npe;
+ struct npehwbuf *hw;
+ struct mbuf *m, *n;
+ struct npedma *dma = &sc->txdma;
+ bus_dma_segment_t segs[NPE_MAXSEG];
+ int nseg, len, error, i;
+ uint32_t next;
+
+ NPE_ASSERT_LOCKED(sc);
+ /* XXX can this happen? */
+ if (ifp->if_drv_flags & IFF_DRV_OACTIVE)
+ return;
+
+ while (sc->tx_free != NULL) {
+ IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
+ if (m == NULL) {
+ /* XXX? */
+ ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
+ return;
+ }
+ npe = sc->tx_free;
+ error = bus_dmamap_load_mbuf_sg(dma->mtag, npe->ix_map,
+ m, segs, &nseg, 0);
+ if (error == EFBIG) {
+ n = npe_defrag(m, M_DONTWAIT, NPE_MAXSEG);
+ if (n == NULL) {
+ if_printf(ifp, "%s: too many fragments %u\n",
+ __func__, nseg);
+ m_freem(m);
+ return; /* XXX? */
+ }
+ m = n;
+ error = bus_dmamap_load_mbuf_sg(dma->mtag, npe->ix_map,
+ m, segs, &nseg, 0);
+ }
+ if (error != 0 || nseg == 0) {
+ if_printf(ifp, "%s: error %u nseg %u\n",
+ __func__, error, nseg);
+ m_freem(m);
+ return; /* XXX? */
+ }
+ sc->tx_free = npe->ix_next;
+
+ bus_dmamap_sync(dma->mtag, npe->ix_map, BUS_DMASYNC_PREWRITE);
+
+ /*
+ * Tap off here if there is a bpf listener.
+ */
+ BPF_MTAP(ifp, m);
+
+ npe->ix_m = m;
+ hw = npe->ix_hw;
+ len = m->m_pkthdr.len;
+ next = npe->ix_neaddr + sizeof(hw->ix_ne[0]);
+ for (i = 0; i < nseg; i++) {
+ hw->ix_ne[i].data = htobe32(segs[i].ds_addr);
+ hw->ix_ne[i].len = htobe32((segs[i].ds_len<<16) | len);
+ hw->ix_ne[i].next = htobe32(next);
+
+ len = 0; /* zero for segments > 1 */
+ next += sizeof(hw->ix_ne[0]);
+ }
+ hw->ix_ne[i-1].next = 0; /* zero last in chain */
+ /* XXX flush descriptor instead of using uncached memory */
+
+ DPRINTF(sc, "%s: qwrite(%u, 0x%x) ne_data %x ne_len 0x%x\n",
+ __func__, sc->tx_qid, npe->ix_neaddr,
+ hw->ix_ne[0].data, hw->ix_ne[0].len);
+ /* stick it on the tx q */
+ /* XXX add vlan priority */
+ ixpqmgr_qwrite(sc->tx_qid, npe->ix_neaddr);
+
+ ifp->if_timer = 5;
+ }
+ if (sc->tx_free == NULL)
+ ifp->if_drv_flags |= IFF_DRV_OACTIVE;
+}
+
+void
+npestart(struct ifnet *ifp)
+{
+ struct npe_softc *sc = ifp->if_softc;
+ NPE_LOCK(sc);
+ npestart_locked(ifp);
+ NPE_UNLOCK(sc);
+}
+
+static void
+npe_stopxmit(struct npe_softc *sc)
+{
+ struct npedma *dma = &sc->txdma;
+ int i;
+
+ NPE_ASSERT_LOCKED(sc);
+
+ /* XXX qmgr */
+ for (i = 0; i < dma->nbuf; i++) {
+ struct npebuf *npe = &dma->buf[i];
+
+ if (npe->ix_m != NULL) {
+ bus_dmamap_unload(dma->mtag, npe->ix_map);
+ m_freem(npe->ix_m);
+ npe->ix_m = NULL;
+ }
+ }
+}
+
+static void
+npe_stoprecv(struct npe_softc *sc)
+{
+ struct npedma *dma = &sc->rxdma;
+ int i;
+
+ NPE_ASSERT_LOCKED(sc);
+
+ /* XXX qmgr */
+ for (i = 0; i < dma->nbuf; i++) {
+ struct npebuf *npe = &dma->buf[i];
+
+ if (npe->ix_m != NULL) {
+ bus_dmamap_unload(dma->mtag, npe->ix_map);
+ m_freem(npe->ix_m);
+ npe->ix_m = NULL;
+ }
+ }
+}
+
+/*
+ * Turn off interrupts, and stop the nic.
+ */
+void
+npestop(struct npe_softc *sc)
+{
+ struct ifnet *ifp = sc->sc_ifp;
+
+ /* disable transmitter and reciver in the MAC */
+ WR4(sc, NPE_MAC_RX_CNTRL1,
+ RD4(sc, NPE_MAC_RX_CNTRL1) &~ NPE_RX_CNTRL1_RX_EN);
+ WR4(sc, NPE_MAC_TX_CNTRL1,
+ RD4(sc, NPE_MAC_TX_CNTRL1) &~ NPE_TX_CNTRL1_TX_EN);
+
+ ifp->if_timer = 0;
+ ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
+
+ callout_stop(&sc->tick_ch);
+
+ npe_stopxmit(sc);
+ npe_stoprecv(sc);
+ /* XXX go into loopback & drain q's? */
+ /* XXX but beware of disabling tx above */
+
+ /*
+ * The MAC core rx/tx disable may leave the MAC hardware in an
+ * unpredictable state. A hw reset is executed before resetting
+ * all the MAC parameters to a known value.
+ */
+ WR4(sc, NPE_MAC_CORE_CNTRL, NPE_CORE_RESET);
+ DELAY(NPE_MAC_RESET_DELAY);
+ WR4(sc, NPE_MAC_INT_CLK_THRESH, NPE_MAC_INT_CLK_THRESH_DEFAULT);
+ WR4(sc, NPE_MAC_CORE_CNTRL, NPE_CORE_MDC_EN);
+}
+
+void
+npewatchdog(struct ifnet *ifp)
+{
+ struct npe_softc *sc = ifp->if_softc;
+
+ NPE_LOCK(sc);
+ if_printf(ifp, "device timeout\n");
+ ifp->if_oerrors++;
+ npeinit_locked(sc);
+ NPE_UNLOCK(sc);
+}
+
+static int
+npeioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
+{
+ struct npe_softc *sc = ifp->if_softc;
+ struct mii_data *mii;
+ struct ifreq *ifr = (struct ifreq *)data;
+ int error = 0;
+#ifdef DEVICE_POLLING
+ int mask;
+#endif
+
+ switch (cmd) {
+ case SIOCSIFFLAGS:
+ NPE_LOCK(sc);
+ if ((ifp->if_flags & IFF_UP) == 0 &&
+ ifp->if_drv_flags & IFF_DRV_RUNNING) {
+ ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
+ npestop(sc);
+ } else {
+ /* reinitialize card on any parameter change */
+ npeinit_locked(sc);
+ }
+ NPE_UNLOCK(sc);
+ break;
+
+ case SIOCADDMULTI:
+ case SIOCDELMULTI:
+ /* update multicast filter list. */
+ NPE_LOCK(sc);
+ npe_setmcast(sc);
+ NPE_UNLOCK(sc);
+ error = 0;
+ break;
+
+ case SIOCSIFMEDIA:
+ case SIOCGIFMEDIA:
+ mii = device_get_softc(sc->sc_mii);
+ error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd);
+ break;
+
+#ifdef DEVICE_POLLING
+ case SIOCSIFCAP:
+ mask = ifp->if_capenable ^ ifr->ifr_reqcap;
+ if (mask & IFCAP_POLLING) {
+ if (ifr->ifr_reqcap & IFCAP_POLLING) {
+ error = ether_poll_register(npe_poll, ifp);
+ if (error)
+ return error;
+ NPE_LOCK(sc);
+ /* disable callbacks XXX txdone is shared */
+ ixpqmgr_notify_disable(sc->rx_qid);
+ ixpqmgr_notify_disable(sc->tx_doneqid);
+ ifp->if_capenable |= IFCAP_POLLING;
+ NPE_UNLOCK(sc);
+ } else {
+ error = ether_poll_deregister(ifp);
+ /* NB: always enable qmgr callbacks */
+ NPE_LOCK(sc);
+ /* enable qmgr callbacks */
+ ixpqmgr_notify_enable(sc->rx_qid,
+ IX_QMGR_Q_SOURCE_ID_NOT_E);
+ ixpqmgr_notify_enable(sc->tx_doneqid,
+ IX_QMGR_Q_SOURCE_ID_NOT_E);
+ ifp->if_capenable &= ~IFCAP_POLLING;
+ NPE_UNLOCK(sc);
+ }
+ }
+ break;
+#endif
+ default:
+ error = ether_ioctl(ifp, cmd, data);
+ break;
+ }
+ return error;
+}
+
+/*
+ * Setup a traffic class -> rx queue mapping.
+ */
+static int
+npe_setrxqosentry(struct npe_softc *sc, int classix, int trafclass, int qid)
+{
+ int npeid = npeconfig[device_get_unit(sc->sc_dev)].npeid;
+ uint32_t msg[2];
+
+ msg[0] = (NPE_SETRXQOSENTRY << 24) | (npeid << 20) | classix;
+ msg[1] = (trafclass << 24) | (1 << 23) | (qid << 16) | (qid << 4);
+ return ixpnpe_sendandrecvmsg(sc->sc_npe, msg, msg);
+}
+
+/*
+ * Update and reset the statistics in the NPE.
+ */
+static int
+npe_updatestats(struct npe_softc *sc)
+{
+ uint32_t msg[2];
+
+ msg[0] = NPE_RESETSTATS << NPE_MAC_MSGID_SHL;
+ msg[1] = sc->sc_stats_phys; /* physical address of stat block */
+ return ixpnpe_sendmsg(sc->sc_npe, msg); /* NB: no recv */
+}
+
+#if 0
+/*
+ * Get the current statistics block.
+ */
+static int
+npe_getstats(struct npe_softc *sc)
+{
+ uint32_t msg[2];
+
+ msg[0] = NPE_GETSTATS << NPE_MAC_MSGID_SHL;
+ msg[1] = sc->sc_stats_phys; /* physical address of stat block */
+ return ixpnpe_sendandrecvmsg(sc->sc_npe, msg, msg);
+}
+
+/*
+ * Query the image id of the loaded firmware.
+ */
+static uint32_t
+npe_getimageid(struct npe_softc *sc)
+{
+ uint32_t msg[2];
+
+ msg[0] = NPE_GETSTATUS << NPE_MAC_MSGID_SHL;
+ msg[1] = 0;
+ return ixpnpe_sendandrecvmsg(sc->sc_npe, msg, msg) == 0 ? msg[1] : 0;
+}
+
+/*
+ * Enable/disable loopback.
+ */
+static int
+npe_setloopback(struct npe_softc *sc, int ena)
+{
+ uint32_t msg[2];
+
+ msg[0] = (NPE_SETLOOPBACK << NPE_MAC_MSGID_SHL) | (ena != 0);
+ msg[1] = 0;
+ return ixpnpe_sendandrecvmsg(sc->sc_npe, msg, msg);
+}
+#endif
+
+static void
+npe_child_detached(device_t dev, device_t child)
+{
+ struct npe_softc *sc;
+
+ sc = device_get_softc(dev);
+ if (child == sc->sc_mii)
+ sc->sc_mii = NULL;
+}
+
+/*
+ * MII bus support routines.
+ *
+ * NB: ixp425 has one PHY per NPE
+ */
+static uint32_t
+npe_mii_mdio_read(struct npe_softc *sc, int reg)
+{
+#define MII_RD4(sc, reg) bus_space_read_4(sc->sc_iot, sc->sc_miih, reg)
+ uint32_t v;
+
+ /* NB: registers are known to be sequential */
+ v = (MII_RD4(sc, reg+0) & 0xff) << 0;
+ v |= (MII_RD4(sc, reg+4) & 0xff) << 8;
+ v |= (MII_RD4(sc, reg+8) & 0xff) << 16;
+ v |= (MII_RD4(sc, reg+12) & 0xff) << 24;
+ return v;
+#undef MII_RD4
+}
+
+static void
+npe_mii_mdio_write(struct npe_softc *sc, int reg, uint32_t cmd)
+{
+#define MII_WR4(sc, reg, v) \
+ bus_space_write_4(sc->sc_iot, sc->sc_miih, reg, v)
+
+ /* NB: registers are known to be sequential */
+ MII_WR4(sc, reg+0, cmd & 0xff);
+ MII_WR4(sc, reg+4, (cmd >> 8) & 0xff);
+ MII_WR4(sc, reg+8, (cmd >> 16) & 0xff);
+ MII_WR4(sc, reg+12, (cmd >> 24) & 0xff);
+#undef MII_WR4
+}
+
+static int
+npe_mii_mdio_wait(struct npe_softc *sc)
+{
+#define MAXTRIES 100 /* XXX */
+ uint32_t v;
+ int i;
+
+ for (i = 0; i < MAXTRIES; i++) {
+ v = npe_mii_mdio_read(sc, NPE_MAC_MDIO_CMD);
+ if ((v & NPE_MII_GO) == 0)
+ return 1;
+ }
+ return 0; /* NB: timeout */
+#undef MAXTRIES
+}
+
+static int
+npe_miibus_readreg(device_t dev, int phy, int reg)
+{
+ struct npe_softc *sc = device_get_softc(dev);
+ uint32_t v;
+
+ if (phy != device_get_unit(dev)) /* XXX */
+ return 0xffff;
+ v = (phy << NPE_MII_ADDR_SHL) | (reg << NPE_MII_REG_SHL)
+ | NPE_MII_GO;
+ npe_mii_mdio_write(sc, NPE_MAC_MDIO_CMD, v);
+ if (npe_mii_mdio_wait(sc))
+ v = npe_mii_mdio_read(sc, NPE_MAC_MDIO_STS);
+ else
+ v = 0xffff | NPE_MII_READ_FAIL;
+ return (v & NPE_MII_READ_FAIL) ? 0xffff : (v & 0xffff);
+#undef MAXTRIES
+}
+
+static void
+npe_miibus_writereg(device_t dev, int phy, int reg, int data)
+{
+ struct npe_softc *sc = device_get_softc(dev);
+ uint32_t v;
+
+ if (phy != device_get_unit(dev)) /* XXX */
+ return;
+ v = (phy << NPE_MII_ADDR_SHL) | (reg << NPE_MII_REG_SHL)
+ | data | NPE_MII_WRITE
+ | NPE_MII_GO;
+ npe_mii_mdio_write(sc, NPE_MAC_MDIO_CMD, v);
+ /* XXX complain about timeout */
+ (void) npe_mii_mdio_wait(sc);
+}
+
+static void
+npe_miibus_statchg(device_t dev)
+{
+ struct npe_softc *sc = device_get_softc(dev);
+ struct mii_data *mii = device_get_softc(sc->sc_mii);
+ uint32_t tx1, rx1;
+
+ /* sync MAC duplex state */
+ tx1 = RD4(sc, NPE_MAC_TX_CNTRL1);
+ rx1 = RD4(sc, NPE_MAC_RX_CNTRL1);
+ if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) {
+ tx1 &= ~NPE_TX_CNTRL1_DUPLEX;
+ rx1 |= NPE_RX_CNTRL1_PAUSE_EN;
+ } else {
+ tx1 |= NPE_TX_CNTRL1_DUPLEX;
+ rx1 &= ~NPE_RX_CNTRL1_PAUSE_EN;
+ }
+ WR4(sc, NPE_MAC_RX_CNTRL1, rx1);
+ WR4(sc, NPE_MAC_TX_CNTRL1, tx1);
+}
+
+static device_method_t npe_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, npe_probe),
+ DEVMETHOD(device_attach, npe_attach),
+ DEVMETHOD(device_detach, npe_detach),
+
+ /* Bus interface */
+ DEVMETHOD(bus_child_detached, npe_child_detached),
+
+ /* MII interface */
+ DEVMETHOD(miibus_readreg, npe_miibus_readreg),
+ DEVMETHOD(miibus_writereg, npe_miibus_writereg),
+ DEVMETHOD(miibus_statchg, npe_miibus_statchg),
+
+ { 0, 0 }
+};
+
+static driver_t npe_driver = {
+ "npe",
+ npe_methods,
+ sizeof(struct npe_softc),
+};
+
+DRIVER_MODULE(npe, ixp, npe_driver, npe_devclass, 0, 0);
+DRIVER_MODULE(miibus, npe, miibus_driver, miibus_devclass, 0, 0);
+MODULE_DEPEND(npe, ixpqmgr, 1, 1, 1);
+MODULE_DEPEND(npe, miibus, 1, 1, 1);
+MODULE_DEPEND(npe, ether, 1, 1, 1);
diff --git a/sys/arm/xscale/ixp425/if_npereg.h b/sys/arm/xscale/ixp425/if_npereg.h
new file mode 100644
index 000000000000..d41905d8840b
--- /dev/null
+++ b/sys/arm/xscale/ixp425/if_npereg.h
@@ -0,0 +1,288 @@
+/*-
+ * Copyright (c) 2006 Sam Leffler, Errno Consulting
+ * 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,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ * redistribution must be conditioned upon including a substantially
+ * similar Disclaimer requirement for further binary redistribution.
+ *
+ * NO WARRANTY
+ * 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 NONINFRINGEMENT, MERCHANTIBILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Copyright (c) 2001-2005, Intel Corporation.
+ * 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 Intel Corporation nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ *
+ * 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 ARM_XSCALE_IF_NPEREG_H
+#define ARM_XSCALE_IF_NPEREG_H
+
+/*
+ * NPE/NPE tx/rx descriptor format. This is just the area
+ * shared with ucode running in the NPE; the driver-specific
+ * state is defined in the driver. The shared area must be
+ * cacheline-aligned. We allocate NPE_MAXSEG "descriptors"
+ * per buffer; this allows us to do minimal s/g. The number
+ * of descriptors can be expanded but doing so uses memory
+ * so should be done with care.
+ *
+ * The driver sets up buffers in uncached memory.
+ */
+#define NPE_MAXSEG 3 /* empirically selected */
+
+struct npehwbuf {
+ struct { /* NPE shared area, cacheline aligned */
+ uint32_t next; /* phys addr of next segment */
+ uint32_t len; /* buffer/segment length (bytes) */
+ uint32_t data; /* phys addr of data segment */
+ uint32_t pad[5]; /* pad to cacheline */
+ } ix_ne[NPE_MAXSEG];
+};
+
+/* NPE ID's */
+#define NPE_A 0
+#define NPE_B 1
+#define NPE_C 2
+#define NPE_MAX (NPE_C+1)
+
+#define NPE_PORTS_MAX 2 /* logical ports */
+#define NPE_FRAME_SIZE_DEFAULT 1536
+#define NPE_FRAME_SIZE_MAX (65536-64)
+#define NPE_FRAME_SIZE_MIN 64
+
+/*
+ * Queue Manager-related definitions.
+ *
+ * These define the layout of 32-bit Q entries passed
+ * between the host cpu and the NPE's.
+ */
+#define NPE_QM_Q_NPE(e) (((e)>>0)&0x3) /* NPE ID */
+#define NPE_QM_Q_PORT(e) (((e)>>3)&0x1) /* Port ID */
+#define NPE_QM_Q_PRIO(e) (((e)>>0)&0x3) /* 802.1d priority */
+#define NPE_QM_Q_ADDR(e) ((e)&0xfffffffe0) /* phys address */
+
+/*
+ * Host->NPE requests written to the shared mailbox.
+ * The NPE writes the same value back as an ACK.
+ */
+#define NPE_GETSTATUS 0x00 /* get firmware revision */
+#define NPE_SETPORTADDRESS 0x01 /* set port id and mac address */
+#define NPE_GETMACADDRDB 0x02 /* upload filter database */
+#define NPE_SETMACADDRDB 0x03 /* download filter database */
+#define NPE_GETSTATS 0x04 /* get statistics */
+#define NPE_RESETSTATS 0x05 /* reset stats + return result */
+#define NPE_SETMAXFRAME 0x06 /* configure max tx/rx frame lengths */
+#define NPE_SETRXTAGMODE 0x07 /* configure VLAN rx operating mode */
+#define NPE_SETDEFRXVID 0x08 /* set def VLAN tag + traffic class */
+#define NPE_SETRXQOSENTRY 0x0b /* map user pri -> QoS class+rx qid */
+#define NPE_SETFIREWALLMODE 0x0e /* config firewall services */
+#define NPE_SETLOOPBACK 0x12 /* enable/disable loopback */
+/* ... XXX more */
+
+#define NPE_MAC_MSGID_SHL 24
+#define NPE_MAC_PORTID_SHL 16
+
+/*
+ * MAC register definitions; see section
+ * 15.2 of the Intel Developers Manual.
+ */
+#define NPE_MAC_TX_CNTRL1 0x000
+#define NPE_MAC_TX_CNTRL2 0x004
+#define NPE_MAC_RX_CNTRL1 0x010
+#define NPE_MAC_RX_CNTRL2 0x014
+#define NPE_MAC_RANDOM_SEED 0x020
+#define NPE_MAC_THRESH_P_EMPTY 0x030
+#define NPE_MAC_THRESH_P_FULL 0x038
+#define NPE_MAC_BUF_SIZE_TX 0x040
+#define NPE_MAC_TX_DEFER 0x050
+#define NPE_MAC_RX_DEFER 0x054
+#define NPE_MAC_TX_TWO_DEFER_1 0x060
+#define NPE_MAC_TX_TWO_DEFER_2 0x064
+#define NPE_MAC_SLOT_TIME 0x070
+#define NPE_MAC_MDIO_CMD_1 0x080
+#define NPE_MAC_MDIO_CMD_2 0x084
+#define NPE_MAC_MDIO_CMD_3 0x088
+#define NPE_MAC_MDIO_CMD_4 0x08c
+#define NPE_MAC_MDIO_STS_1 0x090
+#define NPE_MAC_MDIO_STS_2 0x094
+#define NPE_MAC_MDIO_STS_3 0x098
+#define NPE_MAC_MDIO_STS_4 0x09c
+#define NPE_MAC_ADDR_MASK_1 0x0A0
+#define NPE_MAC_ADDR_MASK_2 0x0A4
+#define NPE_MAC_ADDR_MASK_3 0x0A8
+#define NPE_MAC_ADDR_MASK_4 0x0AC
+#define NPE_MAC_ADDR_MASK_5 0x0B0
+#define NPE_MAC_ADDR_MASK_6 0x0B4
+#define NPE_MAC_ADDR_1 0x0C0
+#define NPE_MAC_ADDR_2 0x0C4
+#define NPE_MAC_ADDR_3 0x0C8
+#define NPE_MAC_ADDR_4 0x0CC
+#define NPE_MAC_ADDR_5 0x0D0
+#define NPE_MAC_ADDR_6 0x0D4
+#define NPE_MAC_INT_CLK_THRESH 0x0E0
+#define NPE_MAC_UNI_ADDR_1 0x0F0
+#define NPE_MAC_UNI_ADDR_2 0x0F4
+#define NPE_MAC_UNI_ADDR_3 0x0F8
+#define NPE_MAC_UNI_ADDR_4 0x0FC
+#define NPE_MAC_UNI_ADDR_5 0x100
+#define NPE_MAC_UNI_ADDR_6 0x104
+#define NPE_MAC_CORE_CNTRL 0x1FC
+
+#define NPE_MAC_ADDR_MASK(i) (NPE_MAC_ADDR_MASK_1 + ((i)<<2))
+#define NPE_MAC_ADDR(i) (NPE_MAC_ADDR_1 + ((i)<<2))
+#define NPE_MAC_UNI_ADDR(i) (NPE_MAC_UNI_ADDR_1 + ((i)<<2))
+
+/*
+ * Bit definitions
+ */
+
+/* TX Control Register 1*/
+#define NPE_TX_CNTRL1_TX_EN 0x01 /* enable TX engine */
+#define NPE_TX_CNTRL1_DUPLEX 0x02 /* select half duplex */
+#define NPE_TX_CNTRL1_RETRY 0x04 /* auto-retry on collision */
+#define NPE_TX_CNTRL1_PAD_EN 0x08 /* pad frames <64 bytes */
+#define NPE_TX_CNTRL1_FCS_EN 0x10 /* append FCS */
+#define NPE_TX_CNTRL1_2DEFER 0x20 /* select 2-part deferral */
+#define NPE_TX_CNTRL1_RMII 0x40
+
+/* TX Control Register 2 */
+#define NPE_TX_CNTRL2_RETRIES_MASK 0xf /* max retry count */
+
+/* RX Control Register 1 */
+#define NPE_RX_CNTRL1_RX_EN 0x01 /* enable RX engine */
+#define NPE_RX_CNTRL1_PADSTRIP_EN 0x02 /* strip frame padding */
+#define NPE_RX_CNTRL1_CRC_EN 0x04 /* include CRC in RX frame */
+#define NPE_RX_CNTRL1_PAUSE_EN 0x08 /* detect Pause frames */
+#define NPE_RX_CNTRL1_LOOP_EN 0x10 /* loopback tx/rx */
+#define NPE_RX_CNTRL1_ADDR_FLTR_EN 0x20 /* enable address filtering */
+#define NPE_RX_CNTRL1_RX_RUNT_EN 0x40 /* enable RX of runt frames */
+#define NPE_RX_CNTRL1_BCAST_DIS 0x80 /* discard broadcast frames */
+
+/* RX Control Register 2 */
+#define NPE_RX_CNTRL2_DEFER_EN 0x01
+
+/* Core Control Register */
+#define NPE_CORE_RESET 0x01 /* MAC reset state */
+#define NPE_CORE_RX_FIFO_FLUSH 0x02 /* flush RX FIFO */
+#define NPE_CORE_TX_FIFO_FLUSH 0x04 /* flush TX FIFO */
+#define NPE_CORE_SEND_JAM 0x08 /* send JAM on packet RX */
+#define NPE_CORE_MDC_EN 0x10 /* IXP42X drives MDC clock */
+
+/*
+ * Stat block returned by NPE with NPE_GETSTATS msg.
+ */
+struct npestats {
+ uint32_t dot3StatsAlignmentErrors;
+ uint32_t dot3StatsFCSErrors;
+ uint32_t dot3StatsInternalMacReceiveErrors;
+ uint32_t RxOverrunDiscards;
+ uint32_t RxLearnedEntryDiscards;
+ uint32_t RxLargeFramesDiscards;
+ uint32_t RxSTPBlockedDiscards;
+ uint32_t RxVLANTypeFilterDiscards;
+ uint32_t RxVLANIdFilterDiscards;
+ uint32_t RxInvalidSourceDiscards;
+ uint32_t RxBlackListDiscards;
+ uint32_t RxWhiteListDiscards;
+ uint32_t RxUnderflowEntryDiscards;
+ uint32_t dot3StatsSingleCollisionFrames;
+ uint32_t dot3StatsMultipleCollisionFrames;
+ uint32_t dot3StatsDeferredTransmissions;
+ uint32_t dot3StatsLateCollisions;
+ uint32_t dot3StatsExcessiveCollisions;
+ uint32_t dot3StatsInternalMacTransmitErrors;
+ uint32_t dot3StatsCarrierSenseErrors;
+ uint32_t TxLargeFrameDiscards;
+ uint32_t TxVLANIdFilterDiscards;
+};
+
+/*
+ * Default values
+ */
+#define NPE_MAC_INT_CLK_THRESH_DEFAULT 0x1
+
+#define NPE_MAC_RESET_DELAY 1
+
+/* This value applies to RMII */
+#define NPE_MAC_SLOT_TIME_RMII_DEFAULT 0xFF
+
+/*
+ * MII definitions - these have been verified against the LXT971 and LXT972 PHYs
+ */
+#define NPE_MII_REG_SHL 16
+#define NPE_MII_ADDR_SHL 21
+
+/* NB: shorthands for mii bus mdio routines */
+#define NPE_MAC_MDIO_CMD NPE_MAC_MDIO_CMD_1
+#define NPE_MAC_MDIO_STS NPE_MAC_MDIO_STS_1
+
+#define NPE_MII_GO (1<<31)
+#define NPE_MII_WRITE (1<<26)
+#define NPE_MII_TIMEOUT_10TH_SECS 5
+#define NPE_MII_10TH_SEC_IN_MILLIS 100
+#define NPE_MII_READ_FAIL (1<<31)
+
+#define NPE_MII_PHY_DEF_DELAY 300 /* max delay before link up, etc. */
+#define NPE_MII_PHY_NO_DELAY 0x0 /* do not delay */
+#define NPE_MII_PHY_NULL 0xff /* PHY is not present */
+#define NPE_MII_PHY_DEF_ADDR 0x0 /* default PHY's logical address */
+
+/* Register definition */
+#define NPE_MII_CTRL_REG 0x0 /* Control Register */
+#define NPE_MII_STAT_REG 0x1 /* Status Register */
+#define NPE_MII_PHY_ID1_REG 0x2 /* PHY identifier 1 Register */
+#define NPE_MII_PHY_ID2_REG 0x3 /* PHY identifier 2 Register */
+#define NPE_MII_AN_ADS_REG 0x4 /* Auto-Negotiation */
+ /* Advertisement Register */
+#define NPE_MII_AN_PRTN_REG 0x5 /* Auto-Negotiation */
+ /* partner ability Register */
+#define NPE_MII_AN_EXP_REG 0x6 /* Auto-Negotiation */
+ /* Expansion Register */
+#define NPE_MII_AN_NEXT_REG 0x7 /* Auto-Negotiation */
+ /* next-page transmit Register */
+#endif /* ARM_XSCALE_IF_NPEREG_H */
diff --git a/sys/arm/xscale/ixp425/ixdp425_pci.c b/sys/arm/xscale/ixp425/ixdp425_pci.c
new file mode 100644
index 000000000000..7504baa59fea
--- /dev/null
+++ b/sys/arm/xscale/ixp425/ixdp425_pci.c
@@ -0,0 +1,169 @@
+/* $NetBSD: ixdp425_pci.c,v 1.5 2005/12/11 12:17:09 christos Exp $ */
+/*
+ * Copyright (c) 2003
+ * Ichiro FUKUHARA <ichiro@ichiro.org>.
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ichiro FUKUHARA.
+ * 4. The name of the company nor the name of the author may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ICHIRO FUKUHARA ``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 ICHIRO FUKUHARA OR THE VOICES IN HIS HEAD BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#define _ARM32_BUS_DMA_PRIVATE
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/malloc.h>
+#include <sys/rman.h>
+#include <machine/bus.h>
+#include <machine/intr.h>
+
+#include <arm/xscale/ixp425/ixp425reg.h>
+#include <arm/xscale/ixp425/ixp425var.h>
+#include <arm/xscale/ixp425/ixp425_intr.h>
+#include <arm/xscale/ixp425/ixdp425reg.h>
+
+void
+ixp425_md_attach(device_t dev)
+{
+ struct ixp425_softc *sc = device_get_softc(device_get_parent(dev));
+ struct ixppcib_softc *pci_sc = device_get_softc(dev);
+ uint32_t reg;
+
+
+ /* PCI Reset Assert */
+ reg = GPIO_CONF_READ_4(sc, IXP425_GPIO_GPOUTR);
+ reg &= ~(1U << GPIO_PCI_RESET);
+ GPIO_CONF_WRITE_4(sc, IXP425_GPIO_GPOUTR, reg & ~(1U << GPIO_PCI_RESET));
+
+ /* PCI Clock Disable */
+ reg = GPIO_CONF_READ_4(sc, IXP425_GPIO_GPCLKR);
+ reg &= ~GPCLKR_MUX14;
+ GPIO_CONF_WRITE_4(sc, IXP425_GPIO_GPCLKR, reg & ~GPCLKR_MUX14);
+
+ /*
+ * set GPIO Direction
+ * Output: PCI_CLK, PCI_RESET
+ * Input: PCI_INTA, PCI_INTB, PCI_INTC, PCI_INTD
+ */
+ reg = GPIO_CONF_READ_4(sc, IXP425_GPIO_GPOER);
+ reg &= ~(1U << GPIO_PCI_CLK);
+ reg &= ~(1U << GPIO_PCI_RESET);
+ reg |= ((1U << GPIO_PCI_INTA) | (1U << GPIO_PCI_INTB) |
+ (1U << GPIO_PCI_INTC) | (1U << GPIO_PCI_INTD));
+ GPIO_CONF_WRITE_4(sc, IXP425_GPIO_GPOER, reg);
+
+ /*
+ * Set GPIO interrupt type
+ * PCI_INT_A, PCI_INTB, PCI_INT_C, PCI_INT_D: Active Low
+ */
+ reg = GPIO_CONF_READ_4(sc, GPIO_TYPE_REG(GPIO_PCI_INTA));
+ reg &= ~GPIO_TYPE(GPIO_PCI_INTA, GPIO_TYPE_MASK);
+ reg |= GPIO_TYPE(GPIO_PCI_INTA, GPIO_TYPE_ACT_LOW);
+ GPIO_CONF_WRITE_4(sc, GPIO_TYPE_REG(GPIO_PCI_INTA), reg);
+
+ reg = GPIO_CONF_READ_4(sc, GPIO_TYPE_REG(GPIO_PCI_INTB));
+ reg &= ~GPIO_TYPE(GPIO_PCI_INTB, GPIO_TYPE_MASK);
+ reg |= GPIO_TYPE(GPIO_PCI_INTB, GPIO_TYPE_ACT_LOW);
+ GPIO_CONF_WRITE_4(sc, GPIO_TYPE_REG(GPIO_PCI_INTB), reg);
+
+ reg = GPIO_CONF_READ_4(sc, GPIO_TYPE_REG(GPIO_PCI_INTC));
+ reg &= ~GPIO_TYPE(GPIO_PCI_INTC, GPIO_TYPE_MASK);
+ reg |= GPIO_TYPE(GPIO_PCI_INTC, GPIO_TYPE_ACT_LOW);
+ GPIO_CONF_WRITE_4(sc, GPIO_TYPE_REG(GPIO_PCI_INTC), reg);
+
+ reg = GPIO_CONF_READ_4(sc, GPIO_TYPE_REG(GPIO_PCI_INTD));
+ reg &= ~GPIO_TYPE(GPIO_PCI_INTD, GPIO_TYPE_MASK);
+ reg |= GPIO_TYPE(GPIO_PCI_INTD, GPIO_TYPE_ACT_LOW);
+ GPIO_CONF_WRITE_4(sc, GPIO_TYPE_REG(GPIO_PCI_INTD), reg);
+
+ /* clear ISR */
+ GPIO_CONF_WRITE_4(sc, IXP425_GPIO_GPISR,
+ (1U << GPIO_PCI_INTA) | (1U << GPIO_PCI_INTB) |
+ (1U << GPIO_PCI_INTC) | (1U << GPIO_PCI_INTD));
+
+ /* wait 1ms to satisfy "minimum reset assertion time" of the PCI spec */
+ DELAY(1000);
+ reg = GPIO_CONF_READ_4(sc, IXP425_GPIO_GPCLKR);
+ GPIO_CONF_WRITE_4(sc, IXP425_GPIO_GPCLKR, reg |
+ (0xf << GPCLKR_CLK0DC_SHIFT) | (0xf << GPCLKR_CLK0TC_SHIFT));
+
+ /* PCI Clock Enable */
+ reg = GPIO_CONF_READ_4(sc, IXP425_GPIO_GPCLKR);
+ reg |= GPCLKR_MUX14;
+ GPIO_CONF_WRITE_4(sc, IXP425_GPIO_GPCLKR, reg | GPCLKR_MUX14);
+
+ /*
+ * wait 100us to satisfy "minimum reset assertion time from clock stable
+ * requirement of the PCI spec
+ */
+ DELAY(100);
+ /* PCI Reset deassert */
+ reg = GPIO_CONF_READ_4(sc, IXP425_GPIO_GPOUTR);
+ reg |= 1U << GPIO_PCI_RESET;
+ GPIO_CONF_WRITE_4(sc, IXP425_GPIO_GPOUTR, reg | (1U << GPIO_PCI_RESET));
+ pci_sc->sc_irq_rman.rm_type = RMAN_ARRAY;
+ pci_sc->sc_irq_rman.rm_descr = "IXP425 PCI IRQs";
+ CTASSERT(PCI_INT_D < PCI_INT_A);
+ /* XXX this overlaps the irq's setup in ixp425_attach */
+ if (rman_init(&pci_sc->sc_irq_rman) != 0 ||
+ rman_manage_region(&pci_sc->sc_irq_rman, PCI_INT_D, PCI_INT_A) != 0)
+ panic("ixp425_md_attach: failed to set up IRQ rman");
+}
+
+#define IXP425_MAX_DEV 4
+#define IXP425_MAX_LINE 4
+
+int
+ixp425_md_route_interrupt(device_t bridge, device_t device, int pin)
+{
+ static int ixp425_pci_table[IXP425_MAX_DEV][IXP425_MAX_LINE] =
+ {
+ {PCI_INT_A, PCI_INT_B, PCI_INT_C, PCI_INT_D},
+ {PCI_INT_B, PCI_INT_C, PCI_INT_D, PCI_INT_A},
+ {PCI_INT_C, PCI_INT_D, PCI_INT_A, PCI_INT_B},
+ {PCI_INT_D, PCI_INT_A, PCI_INT_B, PCI_INT_C},
+ };
+ int dev;
+
+ dev = pci_get_slot(device);
+ if (bootverbose)
+ device_printf(bridge, "routing pin %d for %s\n", pin,
+ device_get_nameunit(device));
+ if (pin >= 1 && pin <= IXP425_MAX_LINE &&
+ dev >= 1 && dev <= IXP425_MAX_DEV) {
+ return (ixp425_pci_table[dev - 1][pin - 1]);
+ } else
+ printf("ixppcib: no mapping for %d/%d/%d\n",
+ pci_get_bus(device), dev, pci_get_function(device));
+
+ return (-1);
+}
diff --git a/sys/arm/xscale/ixp425/ixdp425reg.h b/sys/arm/xscale/ixp425/ixdp425reg.h
new file mode 100644
index 000000000000..06d7ae99f10c
--- /dev/null
+++ b/sys/arm/xscale/ixp425/ixdp425reg.h
@@ -0,0 +1,54 @@
+/* $NetBSD: ixdp425reg.h,v 1.6 2005/12/11 12:17:09 christos Exp $ */
+/*
+ * Copyright (c) 2003
+ * Ichiro FUKUHARA <ichiro@ichiro.org>.
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ichiro FUKUHARA.
+ * 4. The name of the company nor the name of the author may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ICHIRO FUKUHARA ``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 ICHIRO FUKUHARA OR THE VOICES IN HIS HEAD 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.
+ */
+
+/* $FreeBSD$ */
+#ifndef _IXDP425REG_H_
+#define _IXDP425REG_H_
+/* GPIOs */
+#define GPIO_PCI_CLK 14
+#define GPIO_PCI_RESET 13
+#define GPIO_PCI_INTA 11
+#define GPIO_PCI_INTB 10
+#define GPIO_PCI_INTC 9
+#define GPIO_PCI_INTD 8
+#define GPIO_I2C_SDA 7
+#define GPIO_I2C_SDA_BIT (1U << 7)
+#define GPIO_I2C_SCL 6
+#define GPIO_I2C_SCL_BIT (1U << 6)
+/* Interrupt */
+#define PCI_INT_A IXP425_INT_GPIO_11
+#define PCI_INT_B IXP425_INT_GPIO_10
+#define PCI_INT_C IXP425_INT_GPIO_9
+#define PCI_INT_D IXP425_INT_GPIO_8
+#endif /* _IXDP425REG_H_ */
diff --git a/sys/arm/xscale/ixp425/ixp425.c b/sys/arm/xscale/ixp425/ixp425.c
new file mode 100644
index 000000000000..48ac29ccf91f
--- /dev/null
+++ b/sys/arm/xscale/ixp425/ixp425.c
@@ -0,0 +1,369 @@
+/* $NetBSD: ixp425.c,v 1.10 2005/12/11 12:16:51 christos Exp $ */
+
+/*
+ * Copyright (c) 2003
+ * Ichiro FUKUHARA <ichiro@ichiro.org>.
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ichiro FUKUHARA.
+ * 4. The name of the company nor the name of the author may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ICHIRO FUKUHARA ``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 ICHIRO FUKUHARA OR THE VOICES IN HIS HEAD BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#define _ARM32_BUS_DMA_PRIVATE
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/malloc.h>
+#include <sys/rman.h>
+#include <machine/bus.h>
+#include <machine/intr.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+#include <arm/xscale/ixp425/ixp425reg.h>
+#include <arm/xscale/ixp425/ixp425var.h>
+#include <arm/xscale/ixp425/ixp425_intr.h>
+
+#include <dev/pci/pcireg.h>
+
+volatile uint32_t intr_enabled;
+uint32_t intr_steer = 0;
+
+struct ixp425_softc *ixp425_softc = NULL;
+
+static int ixp425_probe(device_t);
+static void ixp425_identify(driver_t *, device_t);
+static int ixp425_attach(device_t);
+
+static struct {
+ uint32_t hwbase;
+ uint32_t size;
+ uint32_t vbase;
+} hwvtrans[] = {
+ { IXP425_IO_HWBASE, IXP425_IO_SIZE, IXP425_IO_VBASE },
+ { IXP425_EXP_HWBASE, IXP425_EXP_SIZE, IXP425_EXP_VBASE },
+ { IXP425_PCI_HWBASE, IXP425_PCI_SIZE, IXP425_PCI_VBASE },
+ { IXP425_PCI_MEM_HWBASE,IXP425_PCI_MEM_SIZE, IXP425_PCI_MEM_VBASE },
+#if 0
+ { IXP425_PCI_IO_HWBASE, IXP425_PCI_IO_SIZE, IXP425_PCI_IO_VBASE },
+#endif
+ { IXP425_MCU_HWBASE, IXP425_MCU_SIZE, IXP425_MCU_VBASE },
+ { IXP425_QMGR_HWBASE, IXP425_QMGR_SIZE, IXP425_QMGR_VBASE },
+ { IXP425_NPE_A_HWBASE, IXP425_NPE_A_SIZE, IXP425_NPE_A_VBASE },
+ { IXP425_NPE_B_HWBASE, IXP425_NPE_B_SIZE, IXP425_NPE_B_VBASE },
+ { IXP425_NPE_C_HWBASE, IXP425_NPE_C_SIZE, IXP425_NPE_C_VBASE },
+ { IXP425_MAC_A_HWBASE, IXP425_MAC_A_SIZE, IXP425_MAC_A_VBASE },
+ { IXP425_MAC_B_HWBASE, IXP425_MAC_B_SIZE, IXP425_MAC_B_VBASE },
+ /* Gateworks Avila IDE/CF is mapped here */
+ { IXP425_EXP_BUS_CS1_HWBASE, IXP425_EXP_BUS_SIZE,
+ IXP425_EXP_BUS_CS1_VBASE },
+};
+
+static int
+getvbase(uint32_t hwbase, uint32_t size, uint32_t *vbase)
+{
+ int i;
+
+ for (i = 0; i < sizeof hwvtrans / sizeof *hwvtrans; i++) {
+ if (hwbase >= hwvtrans[i].hwbase &&
+ hwbase + size <= hwvtrans[i].hwbase + hwvtrans[i].size) {
+ *vbase = hwbase - hwvtrans[i].hwbase + hwvtrans[i].vbase;
+ return (0);
+ }
+ }
+
+ return (ENOENT);
+}
+
+struct arm32_dma_range *
+bus_dma_get_range(void)
+{
+ return (NULL);
+}
+
+int
+bus_dma_get_range_nb(void)
+{
+ return (0);
+}
+
+static __inline u_int32_t
+ixp425_irq2gpio_bit(int irq)
+{
+
+ static const uint8_t int2gpio[32] __attribute__ ((aligned(32))) = {
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* INT#0 -> INT#5 */
+ 0x00, 0x01, /* GPIO#0 -> GPIO#1 */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* INT#8 -> INT#13 */
+ 0xff, 0xff, 0xff, 0xff, 0xff, /* INT#14 -> INT#18 */
+ 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* GPIO#2 -> GPIO#7 */
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, /* GPIO#8 -> GPIO#12 */
+ 0xff, 0xff /* INT#30 -> INT#31 */
+ };
+
+ return (1U << int2gpio[irq]);
+}
+
+void
+arm_mask_irq(uintptr_t nb)
+{
+ intr_enabled &= ~(1 << nb);
+ ixp425_set_intrmask();
+ /*XXX; If it's a GPIO interrupt, ACK it know. Can it be a problem ?*/
+ if ((1 << nb) & IXP425_INT_GPIOMASK)
+ IXPREG(IXP425_GPIO_VBASE + IXP425_GPIO_GPISR) =
+ ixp425_irq2gpio_bit(nb);
+
+
+}
+
+void
+arm_unmask_irq(uintptr_t nb)
+{
+ intr_enabled |= (1 << nb);
+ ixp425_set_intrmask();
+}
+
+static __inline uint32_t
+ixp425_irq_read(void)
+{
+ return IXPREG(IXP425_INT_STATUS) & intr_enabled;
+}
+
+int
+arm_get_next_irq(void)
+{
+ int irq;
+
+ if ((irq = ixp425_irq_read()))
+ return (ffs(irq) - 1);
+ return (-1);
+}
+
+void
+cpu_reset(void)
+{
+
+ bus_space_write_4(&ixp425_bs_tag, IXP425_TIMER_VBASE,
+ IXP425_OST_WDOG_KEY, OST_WDOG_KEY_MAJICK);
+ bus_space_write_4(&ixp425_bs_tag, IXP425_TIMER_VBASE,
+ IXP425_OST_WDOG, 0);
+ bus_space_write_4(&ixp425_bs_tag, IXP425_TIMER_VBASE,
+ IXP425_OST_WDOG_ENAB, OST_WDOG_ENAB_RST_ENA |
+ OST_WDOG_ENAB_CNT_ENA);
+ printf("Reset failed!\n");
+ for(;;);
+}
+
+static void
+ixp425_identify(driver_t *driver, device_t parent)
+{
+ BUS_ADD_CHILD(parent, 0, "ixp", 0);
+}
+
+static int
+ixp425_probe(device_t dev)
+{
+ device_set_desc(dev, "Intel IXP425");
+ return (0);
+}
+
+static int
+ixp425_attach(device_t dev)
+{
+ struct ixp425_softc *sc;
+
+ sc = device_get_softc(dev);
+ sc->sc_iot = &ixp425_bs_tag;
+ KASSERT(ixp425_softc == NULL, ("ixp425_attach called twice?"));
+ ixp425_softc = sc;
+
+ intr_enabled = 0;
+ ixp425_set_intrmask();
+ ixp425_set_intrsteer();
+
+ sc->sc_irq_rman.rm_type = RMAN_ARRAY;
+ sc->sc_irq_rman.rm_descr = "IXP425 IRQs";
+ if (rman_init(&sc->sc_irq_rman) != 0 ||
+ rman_manage_region(&sc->sc_irq_rman, 0, 31) != 0)
+ panic("ixp425_attach: failed to set up IRQ rman");
+
+ sc->sc_mem_rman.rm_type = RMAN_ARRAY;
+ sc->sc_mem_rman.rm_descr = "IXP425 Memory";
+ if (rman_init(&sc->sc_mem_rman) != 0 ||
+ rman_manage_region(&sc->sc_mem_rman, 0, ~0) != 0)
+ panic("ixp425_attach: failed to set up IRQ rman");
+
+ device_add_child(dev, "pcib", 0);
+ device_add_child(dev, "ixpclk", 0);
+ device_add_child(dev, "ixpwdog", 0);
+ device_add_child(dev, "ixpiic", 0);
+ device_add_child(dev, "uart", 0);
+ /* XXX these are optional, what if they are not configured? */
+ device_add_child(dev, "ixpqmgr", 0);
+ device_add_child(dev, "npe", 0); /* NPE-B */
+ device_add_child(dev, "npe", 1); /* NPE-C */
+ device_add_child(dev, "ata_avila", 0); /* XXX */
+
+ if (bus_space_map(sc->sc_iot, IXP425_GPIO_HWBASE, IXP425_GPIO_SIZE,
+ 0, &sc->sc_gpio_ioh))
+ panic("ixp425_attach: unable to map GPIO registers");
+ if (bus_space_map(sc->sc_iot, IXP425_EXP_HWBASE, IXP425_EXP_SIZE,
+ 0, &sc->sc_exp_ioh))
+ panic("ixp425_attach: unable to map Expansion Bus registers");
+
+ bus_generic_probe(dev);
+ bus_generic_attach(dev);
+
+ return (0);
+}
+
+static struct resource *
+ixp425_alloc_resource(device_t dev, device_t child, int type, int *rid,
+ u_long start, u_long end, u_long count, u_int flags)
+{
+ struct ixp425_softc *sc = device_get_softc(dev);
+ struct rman *rmanp;
+ struct resource *rv;
+ uint32_t vbase;
+ int isuart = (start == 0 && end == ~0); /* XXX how to do this right? */
+
+ rv = NULL;
+
+ switch (type) {
+ case SYS_RES_IRQ:
+ rmanp = &sc->sc_irq_rman;
+ if (isuart) {
+ if (device_get_unit(dev) == 0)
+ start = IXP425_INT_UART0;
+ else
+ start = IXP425_INT_UART1;
+ end = start;
+ }
+ break;
+
+ case SYS_RES_MEMORY:
+ rmanp = &sc->sc_mem_rman;
+ if (isuart) {
+ if (device_get_unit(dev) == 0)
+ start = IXP425_UART0_HWBASE;
+ else
+ start = IXP425_UART1_HWBASE;
+ end = start + 0x1000;
+ }
+ if (getvbase(start, end - start, &vbase))
+ return (rv);
+ break;
+
+ default:
+ return (rv);
+ }
+
+ rv = rman_reserve_resource(rmanp, start, end, count, flags, child);
+ if (rv != NULL) {
+ rman_set_rid(rv, *rid);
+ if (type == SYS_RES_MEMORY) {
+ rman_set_bustag(rv,
+ isuart ? &ixp425_a4x_bs_tag : sc->sc_iot);
+ rman_set_bushandle(rv, vbase);
+ }
+ }
+
+ return (rv);
+}
+
+static int
+ixp425_setup_intr(device_t dev, device_t child,
+ struct resource *ires, int flags, driver_intr_t *intr, void *arg,
+ void **cookiep)
+{
+ uint32_t mask;
+ int i;
+
+ if (flags & INTR_TYPE_TTY) {
+ /* XXX: wrong. */
+ if (device_get_unit(dev) == 0)
+ rman_set_start(ires, IXP425_INT_UART0);
+ else
+ rman_set_start(ires, IXP425_INT_UART1);
+ rman_set_end(ires, rman_get_start(ires));
+ }
+ BUS_SETUP_INTR(device_get_parent(dev), child, ires, flags, intr, arg,
+ cookiep);
+
+ mask = 0;
+ for (i = rman_get_start(ires); i <= rman_get_end(ires); i++)
+ mask |= 1 << i;
+ intr_enabled |= mask;
+ ixp425_set_intrmask();
+
+ return (0);
+}
+
+static int
+ixp425_teardown_intr(device_t dev, device_t child, struct resource *res,
+ void *cookie)
+{
+ uint32_t mask;
+ int i;
+
+ mask = 0;
+ for (i = rman_get_start(res); i <= rman_get_end(res); i++)
+ mask |= 1 << i;
+ intr_enabled &= ~mask;
+ ixp425_set_intrmask();
+
+ return (BUS_TEARDOWN_INTR(device_get_parent(dev), child, res, cookie));
+}
+
+static device_method_t ixp425_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, ixp425_probe),
+ DEVMETHOD(device_attach, ixp425_attach),
+ DEVMETHOD(device_identify, ixp425_identify),
+
+ /* Bus interface */
+ DEVMETHOD(bus_alloc_resource, ixp425_alloc_resource),
+ DEVMETHOD(bus_setup_intr, ixp425_setup_intr),
+ DEVMETHOD(bus_teardown_intr, ixp425_teardown_intr),
+
+ {0, 0},
+};
+
+static driver_t ixp425_driver = {
+ "ixp",
+ ixp425_methods,
+ sizeof(struct ixp425_softc),
+};
+static devclass_t ixp425_devclass;
+
+DRIVER_MODULE(ixp, nexus, ixp425_driver, ixp425_devclass, 0, 0);
diff --git a/sys/arm/xscale/ixp425/ixp425_a4x_io.S b/sys/arm/xscale/ixp425/ixp425_a4x_io.S
new file mode 100644
index 000000000000..22ab1b3479b4
--- /dev/null
+++ b/sys/arm/xscale/ixp425/ixp425_a4x_io.S
@@ -0,0 +1,142 @@
+/* $NetBSD: ixp425_a4x_io.S,v 1.2 2005/12/11 12:16:51 christos Exp $ */
+
+/*
+ * Copyright 2003 Wasabi Systems, Inc.
+ * All rights reserved.
+ *
+ * Written by Steve C. Woodford for Wasabi Systems, 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed for the NetBSD Project by
+ * Wasabi Systems, Inc.
+ * 4. The name of Wasabi Systems, Inc. may not be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC
+ * 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.
+ */
+
+/*
+ * There are simple bus space functions for IO registers mapped at
+ * 32-bit aligned positions. offset is multiplied by 4.
+ *
+ * Based loosely on pxa2x0_a2x_io.S
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * bus_space I/O functions with offset*4
+ */
+
+/*
+ * Read single
+ */
+ENTRY(a4x_bs_r_1)
+ ldr r0, [r1, r2, LSL #2]
+ and r0, r0, #0xff
+ mov pc, lr
+
+ENTRY(a4x_bs_r_2)
+ ldr r0, [r1, r2, LSL #2]
+ mov r1, #0xff
+ orr r1, r1, r1, lsl #8
+ and r0, r0, r1
+ mov pc, lr
+
+ENTRY(a4x_bs_r_4)
+ ldr r0, [r1, r2, LSL #2]
+ mov pc, lr
+
+/*
+ * Write single
+ */
+ENTRY(a4x_bs_w_1)
+ and r3, r3, #0xff
+ str r3, [r1, r2, LSL #2]
+ mov pc, lr
+
+ENTRY(a4x_bs_w_2)
+ mov r0, #0xff
+ orr r0, r0, r0, lsl #8
+ and r3, r3, r0
+ str r3, [r1, r2, LSL #2]
+ mov pc, lr
+
+ENTRY(a4x_bs_w_4)
+ str r3, [r1, r2, LSL #2]
+ mov pc, lr
+
+/*
+ * Read multiple
+ */
+ENTRY(a4x_bs_rm_1)
+ add r0, r1, r2, lsl #2
+ ldr r2, [sp, #0]
+ mov r1, r3
+ teq r2, #0
+ moveq pc, lr
+1: ldr r3, [r0]
+ subs r2, r2, #1
+ strb r3, [r1], #1
+ bne 1b
+ mov pc, lr
+
+ENTRY(a4x_bs_rm_2)
+ add r0, r1, r2, lsl #2
+ ldr r2, [sp, #0]
+ mov r1, r3
+ teq r2, #0
+ moveq pc, lr
+1: ldr r3, [r0]
+ subs r2, r2, #1
+ strh r3, [r1], #2
+ bne 1b
+ mov pc, lr
+
+/*
+ * Write multiple
+ */
+ENTRY(a4x_bs_wm_1)
+ add r0, r1, r2, lsl #2
+ ldr r2, [sp, #0]
+ mov r1, r3
+ teq r2, #0
+ moveq pc, lr
+1: ldrb r3, [r1], #1
+ subs r2, r2, #1
+ str r3, [r0]
+ bne 1b
+ mov pc, lr
+
+ENTRY(a4x_bs_wm_2)
+ add r0, r1, r2, lsl #2
+ ldr r2, [sp, #0]
+ mov r1, r3
+ teq r2, #0
+ moveq pc, lr
+1: ldrh r3, [r1], #2
+ subs r2, r2, #1
+ str r3, [r0]
+ bne 1b
+ mov pc, lr
diff --git a/sys/arm/xscale/ixp425/ixp425_a4x_space.c b/sys/arm/xscale/ixp425/ixp425_a4x_space.c
new file mode 100644
index 000000000000..1a6e28fd50ea
--- /dev/null
+++ b/sys/arm/xscale/ixp425/ixp425_a4x_space.c
@@ -0,0 +1,116 @@
+/* $NetBSD: ixp425_a4x_space.c,v 1.2 2005/12/11 12:16:51 christos Exp $ */
+
+/*
+ * Copyright 2003 Wasabi Systems, Inc.
+ * All rights reserved.
+ *
+ * Written by Steve C. Woodford for Wasabi Systems, 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed for the NetBSD Project by
+ * Wasabi Systems, Inc.
+ * 4. The name of Wasabi Systems, Inc. may not be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC
+ * 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 space tag for 8/16-bit devices on 32-bit bus.
+ * all registers are located at the address of multiple of 4.
+ *
+ * Based on pxa2x0_a4x_space.c
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+
+#include <machine/pcb.h>
+
+#include <vm/vm.h>
+#include <vm/vm_kern.h>
+#include <vm/pmap.h>
+#include <vm/vm_page.h>
+#include <vm/vm_extern.h>
+
+#include <machine/bus.h>
+
+/* Prototypes for all the bus_space structure functions */
+bs_protos(ixp425);
+bs_protos(a4x);
+bs_protos(generic);
+bs_protos(generic_armv4);
+
+struct bus_space ixp425_a4x_bs_tag = {
+ /* cookie */
+ .bs_cookie = (void *) 0,
+
+ /* mapping/unmapping */
+ .bs_map = ixp425_bs_map,
+ .bs_unmap = ixp425_bs_unmap,
+ .bs_subregion = ixp425_bs_subregion,
+
+ /* allocation/deallocation */
+ .bs_alloc = ixp425_bs_alloc, /* XXX not implemented */
+ .bs_free = ixp425_bs_free, /* XXX not implemented */
+
+ /* barrier */
+ .bs_barrier = ixp425_bs_barrier,
+
+ /* read (single) */
+ .bs_r_1 = a4x_bs_r_1,
+ .bs_r_2 = a4x_bs_r_2,
+ .bs_r_4 = a4x_bs_r_4,
+
+ /* read multiple */
+ .bs_rm_1 = a4x_bs_rm_1,
+ .bs_rm_2 = a4x_bs_rm_2,
+
+ /* read region */
+ /* XXX not implemented */
+
+ /* write (single) */
+ .bs_w_1 = a4x_bs_w_1,
+ .bs_w_2 = a4x_bs_w_2,
+ .bs_w_4 = a4x_bs_w_4,
+
+ /* write multiple */
+ .bs_wm_1 = a4x_bs_wm_1,
+ .bs_wm_2 = a4x_bs_wm_2,
+
+ /* write region */
+ /* XXX not implemented */
+
+ /* set multiple */
+ /* XXX not implemented */
+
+ /* set region */
+ /* XXX not implemented */
+
+ /* copy */
+ /* XXX not implemented */
+};
diff --git a/sys/arm/xscale/ixp425/ixp425_iic.c b/sys/arm/xscale/ixp425/ixp425_iic.c
new file mode 100644
index 000000000000..9f8e35dd07d6
--- /dev/null
+++ b/sys/arm/xscale/ixp425/ixp425_iic.c
@@ -0,0 +1,193 @@
+/*
+ * Copyright (c) 2006 Kevin Lo. 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed for the NetBSD Project by
+ * Wasabi Systems, Inc.
+ * 4. The name of Wasabi Systems, Inc. may not be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/uio.h>
+
+#include <arm/xscale/ixp425/ixp425reg.h>
+#include <arm/xscale/ixp425/ixp425var.h>
+#include <arm/xscale/ixp425/ixdp425reg.h>
+
+#include <dev/iicbus/iiconf.h>
+#include <dev/iicbus/iicbus.h>
+
+#include "iicbb_if.h"
+
+#define I2C_DELAY 10
+
+/* bit clr/set shorthands */
+#define GPIO_CONF_CLR(sc, reg, mask) \
+ GPIO_CONF_WRITE_4(sc, reg, GPIO_CONF_READ_4(sc, reg) &~ (mask))
+#define GPIO_CONF_SET(sc, reg, mask) \
+ GPIO_CONF_WRITE_4(sc, reg, GPIO_CONF_READ_4(sc, reg) | (mask))
+
+struct ixpiic_softc {
+ device_t sc_dev;
+ bus_space_tag_t sc_iot;
+ bus_space_handle_t sc_gpio_ioh;
+
+ device_t iicbb;
+};
+
+static struct ixpiic_softc *ixpiic_sc = NULL;
+
+static int
+ixpiic_probe(device_t dev)
+{
+ device_set_desc(dev, "IXP425 GPIO-Based I2C Interface");
+ return (0);
+}
+
+static int
+ixpiic_attach(device_t dev)
+{
+ struct ixpiic_softc *sc = device_get_softc(dev);
+ struct ixp425_softc *sa = device_get_softc(device_get_parent(dev));
+
+ ixpiic_sc = sc;
+
+ sc->sc_dev = dev;
+ sc->sc_iot = sa->sc_iot;
+ sc->sc_gpio_ioh = sa->sc_gpio_ioh;
+
+ GPIO_CONF_SET(sc, IXP425_GPIO_GPOER,
+ GPIO_I2C_SCL_BIT | GPIO_I2C_SDA_BIT);
+ GPIO_CONF_CLR(sc, IXP425_GPIO_GPOUTR,
+ GPIO_I2C_SCL_BIT | GPIO_I2C_SDA_BIT);
+
+ /* add generic bit-banging code */
+ if ((sc->iicbb = device_add_child(dev, "iicbb", -1)) == NULL)
+ device_printf(dev, "could not add iicbb\n");
+
+ /* probe and attach the bit-banging code */
+ device_probe_and_attach(sc->iicbb);
+
+ return (0);
+}
+
+static int
+ixpiic_callback(device_t dev, int index, caddr_t *data)
+{
+ return (0);
+}
+
+static int
+ixpiic_getscl(device_t dev)
+{
+ struct ixpiic_softc *sc = ixpiic_sc;
+ uint32_t reg;
+
+ GPIO_CONF_SET(sc, IXP425_GPIO_GPOER, GPIO_I2C_SCL_BIT);
+
+ reg = GPIO_CONF_READ_4(sc, IXP425_GPIO_GPINR);
+ return (reg & GPIO_I2C_SCL_BIT);
+}
+
+static int
+ixpiic_getsda(device_t dev)
+{
+ struct ixpiic_softc *sc = ixpiic_sc;
+ uint32_t reg;
+
+ GPIO_CONF_SET(sc, IXP425_GPIO_GPOER, GPIO_I2C_SDA_BIT);
+
+ reg = GPIO_CONF_READ_4(sc, IXP425_GPIO_GPINR);
+ return (reg & GPIO_I2C_SDA_BIT);
+}
+
+static void
+ixpiic_setsda(device_t dev, char val)
+{
+ struct ixpiic_softc *sc = ixpiic_sc;
+
+ GPIO_CONF_CLR(sc, IXP425_GPIO_GPOUTR, GPIO_I2C_SDA_BIT);
+ if (val)
+ GPIO_CONF_SET(sc, IXP425_GPIO_GPOER, GPIO_I2C_SDA_BIT);
+ else
+ GPIO_CONF_CLR(sc, IXP425_GPIO_GPOER, GPIO_I2C_SDA_BIT);
+ DELAY(I2C_DELAY);
+}
+
+static void
+ixpiic_setscl(device_t dev, char val)
+{
+ struct ixpiic_softc *sc = ixpiic_sc;
+
+ GPIO_CONF_CLR(sc, IXP425_GPIO_GPOUTR, GPIO_I2C_SCL_BIT);
+ if (val)
+ GPIO_CONF_SET(sc, IXP425_GPIO_GPOER, GPIO_I2C_SCL_BIT);
+ else
+ GPIO_CONF_CLR(sc, IXP425_GPIO_GPOER, GPIO_I2C_SCL_BIT);
+ DELAY(I2C_DELAY);
+}
+
+static int
+ixpiic_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr)
+{
+ /* reset bus */
+ ixpiic_setsda(dev, 1);
+ ixpiic_setscl(dev, 1);
+
+ return (IIC_ENOADDR);
+}
+
+static device_method_t ixpiic_methods[] = {
+ /* device interface */
+ DEVMETHOD(device_probe, ixpiic_probe),
+ DEVMETHOD(device_attach, ixpiic_attach),
+
+ /* iicbb interface */
+ DEVMETHOD(iicbb_callback, ixpiic_callback),
+ DEVMETHOD(iicbb_setsda, ixpiic_setsda),
+ DEVMETHOD(iicbb_setscl, ixpiic_setscl),
+ DEVMETHOD(iicbb_getsda, ixpiic_getsda),
+ DEVMETHOD(iicbb_getscl, ixpiic_getscl),
+ DEVMETHOD(iicbb_reset, ixpiic_reset),
+
+ { 0, 0 }
+};
+
+static driver_t ixpiic_driver = {
+ "ixpiic",
+ ixpiic_methods,
+ sizeof(struct ixpiic_softc),
+};
+static devclass_t ixpiic_devclass;
+
+DRIVER_MODULE(ixpiic, ixp, ixpiic_driver, ixpiic_devclass, 0, 0);
diff --git a/sys/arm/xscale/ixp425/ixp425_intr.h b/sys/arm/xscale/ixp425/ixp425_intr.h
new file mode 100644
index 000000000000..27217f467502
--- /dev/null
+++ b/sys/arm/xscale/ixp425/ixp425_intr.h
@@ -0,0 +1,149 @@
+/* $NetBSD: ixp425_intr.h,v 1.6 2005/12/24 20:06:52 perry Exp $ */
+
+/*
+ * Copyright (c) 2001, 2002 Wasabi Systems, Inc.
+ * All rights reserved.
+ *
+ * Written by Jason R. Thorpe for Wasabi Systems, 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed for the NetBSD Project by
+ * Wasabi Systems, Inc.
+ * 4. The name of Wasabi Systems, Inc. may not be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC
+ * 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.
+ *
+ * $FreeBSD$
+ *
+ */
+
+#ifndef _IXP425_INTR_H_
+#define _IXP425_INTR_H_
+
+#define ARM_IRQ_HANDLER _C_LABEL(ixp425_intr_dispatch)
+
+#ifndef _LOCORE
+
+#include <machine/armreg.h>
+#include <machine/cpufunc.h>
+
+#include <arm/xscale/ixp425/ixp425reg.h>
+
+#define IXPREG(reg) *((__volatile u_int32_t*) (reg))
+
+void ixp425_do_pending(void);
+
+extern __volatile uint32_t intr_enabled;
+extern uint32_t intr_steer;
+
+static __inline void __attribute__((__unused__))
+ixp425_set_intrmask(void)
+{
+ IXPREG(IXP425_INT_ENABLE) = intr_enabled & IXP425_INT_HWMASK;
+}
+
+static __inline void
+ixp425_set_intrsteer(void)
+{
+ IXPREG(IXP425_INT_SELECT) = intr_steer & IXP425_INT_HWMASK;
+}
+
+#define INT_SWMASK \
+ ((1U << IXP425_INT_bit31) | (1U << IXP425_INT_bit30) | \
+ (1U << IXP425_INT_bit14) | (1U << IXP425_INT_bit11))
+
+#if 0
+static __inline void __attribute__((__unused__))
+ixp425_splx(int new)
+{
+ extern __volatile uint32_t intr_enabled;
+ extern __volatile int current_spl_level;
+ extern __volatile int ixp425_ipending;
+ extern void ixp425_do_pending(void);
+ int oldirqstate, hwpend;
+
+ /* Don't let the compiler re-order this code with preceding code */
+ __insn_barrier();
+
+ current_spl_level = new;
+
+ hwpend = (ixp425_ipending & IXP425_INT_HWMASK) & ~new;
+ if (hwpend != 0) {
+ oldirqstate = disable_interrupts(I32_bit);
+ intr_enabled |= hwpend;
+ ixp425_set_intrmask();
+ restore_interrupts(oldirqstate);
+ }
+
+ if ((ixp425_ipending & INT_SWMASK) & ~new)
+ ixp425_do_pending();
+}
+
+static __inline int __attribute__((__unused__))
+ixp425_splraise(int ipl)
+{
+ extern __volatile int current_spl_level;
+ extern int ixp425_imask[];
+ int old;
+
+ old = current_spl_level;
+ current_spl_level |= ixp425_imask[ipl];
+
+ /* Don't let the compiler re-order this code with subsequent code */
+ __insn_barrier();
+
+ return (old);
+}
+
+static __inline int __attribute__((__unused__))
+ixp425_spllower(int ipl)
+{
+ extern __volatile int current_spl_level;
+ extern int ixp425_imask[];
+ int old = current_spl_level;
+
+ ixp425_splx(ixp425_imask[ipl]);
+ return(old);
+}
+
+#endif
+#if !defined(EVBARM_SPL_NOINLINE)
+
+#define splx(new) ixp425_splx(new)
+#define _spllower(ipl) ixp425_spllower(ipl)
+#define _splraise(ipl) ixp425_splraise(ipl)
+void _setsoftintr(int);
+
+#else
+
+int _splraise(int);
+int _spllower(int);
+void splx(int);
+void _setsoftintr(int);
+
+#endif /* ! EVBARM_SPL_NOINLINE */
+
+#endif /* _LOCORE */
+
+#endif /* _IXP425_INTR_H_ */
diff --git a/sys/arm/xscale/ixp425/ixp425_mem.c b/sys/arm/xscale/ixp425/ixp425_mem.c
new file mode 100644
index 000000000000..df7f7e550545
--- /dev/null
+++ b/sys/arm/xscale/ixp425/ixp425_mem.c
@@ -0,0 +1,85 @@
+/* $NetBSD: ixp425_mem.c,v 1.2 2005/12/11 12:16:51 christos Exp $ */
+
+/*
+ * Copyright (c) 2003 Wasabi Systems, Inc.
+ * All rights reserved.
+ *
+ * Written by Steve C. Woodford for Wasabi Systems, 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed for the NetBSD Project by
+ * Wasabi Systems, Inc.
+ * 4. The name of Wasabi Systems, Inc. may not be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+
+#include <arm/xscale/ixp425/ixp425reg.h>
+#include <arm/xscale/ixp425/ixp425var.h>
+
+static uint32_t sdram_64bit[] = {
+ 0x00800000, /* 8M: One 2M x 32 chip */
+ 0x01000000, /* 16M: Two 2M x 32 chips */
+ 0x01000000, /* 16M: One 4M x 32 chip */
+ 0x02000000, /* 32M: Two 4M x 32 chips */
+ 0, 0, 0, 0
+};
+
+static uint32_t sdram_other[] = {
+ 0x02000000, /* 32M: Two 8M x 16 chips */
+ 0x04000000, /* 64M: Four 8M x 16 chips */
+ 0x04000000, /* 64M: Two 16M x 16 chips */
+ 0x08000000, /* 128M: Four 16M x 16 chips */
+ 0x08000000, /* 128M: Two 32M x 16 chips */
+ 0x10000000, /* 256M: Four 32M x 16 chips */
+ 0, 0
+};
+
+#define MCU_REG_READ(x) (*(volatile uint32_t *)(IXP425_MCU_VBASE + (x)))
+
+uint32_t
+ixp425_sdram_size(void)
+{
+ uint32_t size, sdr_config;
+
+ sdr_config = MCU_REG_READ(MCU_SDR_CONFIG);
+
+ if (sdr_config & MCU_SDR_CONFIG_64MBIT)
+ size = sdram_64bit[MCU_SDR_CONFIG_MCONF(sdr_config)];
+ else
+ size = sdram_other[MCU_SDR_CONFIG_MCONF(sdr_config)];
+
+ if (size == 0) {
+ printf("** SDR_CONFIG retuns unknown value, using 32M\n");
+ size = 32 * 1024 * 1024;
+ }
+
+ return (size);
+}
diff --git a/sys/arm/xscale/ixp425/ixp425_npe.c b/sys/arm/xscale/ixp425/ixp425_npe.c
new file mode 100644
index 000000000000..0d1626ba3fc0
--- /dev/null
+++ b/sys/arm/xscale/ixp425/ixp425_npe.c
@@ -0,0 +1,1396 @@
+/*-
+ * Copyright (c) 2006 Sam Leffler, Errno Consulting
+ * 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,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ * redistribution must be conditioned upon including a substantially
+ * similar Disclaimer requirement for further binary redistribution.
+ *
+ * NO WARRANTY
+ * 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 NONINFRINGEMENT, MERCHANTIBILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ */
+
+/*-
+ * Copyright (c) 2001-2005, Intel Corporation.
+ * 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 Intel Corporation nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ *
+ * 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>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Intel XScale Network Processing Engine (NPE) support.
+ *
+ * Each NPE has an ixpnpeX device associated with it that is
+ * attached at boot. Depending on the microcode loaded into
+ * an NPE there may be an Ethernet interface (npeX) or some
+ * other network interface (e.g. for ATM). This file has support
+ * for loading microcode images and the associated NPE CPU
+ * manipulations (start, stop, reset).
+ *
+ * The code here basically replaces the npeDl and npeMh classes
+ * in the Intel Access Library (IAL).
+ *
+ * NB: Microcode images are loaded with firmware(9). To
+ * include microcode in a static kernel include the
+ * ixpnpe_fw device. Otherwise the firmware will be
+ * automatically loaded from the filesystem.
+ */
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/time.h>
+#include <sys/bus.h>
+#include <sys/resource.h>
+#include <sys/rman.h>
+#include <sys/sysctl.h>
+
+#include <sys/linker.h>
+#include <sys/firmware.h>
+
+#include <machine/bus.h>
+#include <machine/cpu.h>
+#include <machine/cpufunc.h>
+#include <machine/resource.h>
+#include <machine/intr.h>
+#include <arm/xscale/ixp425/ixp425reg.h>
+#include <arm/xscale/ixp425/ixp425var.h>
+
+#include <arm/xscale/ixp425/ixp425_npereg.h>
+#include <arm/xscale/ixp425/ixp425_npevar.h>
+
+struct ixpnpe_softc {
+ device_t sc_dev;
+ bus_space_tag_t sc_iot;
+ bus_space_handle_t sc_ioh;
+ bus_size_t sc_size; /* size of mapped register window */
+ struct resource *sc_irq; /* IRQ resource */
+ void *sc_ih; /* interrupt handler */
+ struct mtx sc_mtx; /* mailbox lock */
+ uint32_t sc_msg[2]; /* reply msg collected in ixpnpe_intr */
+ int sc_msgwaiting; /* sc_msg holds valid data */
+
+ int validImage; /* valid ucode image loaded */
+ int started; /* NPE is started */
+ uint8_t functionalityId;/* ucode functionality ID */
+ int insMemSize; /* size of instruction memory */
+ int dataMemSize; /* size of data memory */
+ uint32_t savedExecCount;
+ uint32_t savedEcsDbgCtxtReg2;
+};
+
+#define IX_NPEDL_NPEIMAGE_FIELD_MASK 0xff
+
+/* used to read download map from version in microcode image */
+#define IX_NPEDL_BLOCK_TYPE_INSTRUCTION 0x00000000
+#define IX_NPEDL_BLOCK_TYPE_DATA 0x00000001
+#define IX_NPEDL_BLOCK_TYPE_STATE 0x00000002
+#define IX_NPEDL_END_OF_DOWNLOAD_MAP 0x0000000F
+
+/*
+ * masks used to extract address info from State information context
+ * register addresses as read from microcode image
+ */
+#define IX_NPEDL_MASK_STATE_ADDR_CTXT_REG 0x0000000F
+#define IX_NPEDL_MASK_STATE_ADDR_CTXT_NUM 0x000000F0
+
+/* LSB offset of Context Number field in State-Info Context Address */
+#define IX_NPEDL_OFFSET_STATE_ADDR_CTXT_NUM 4
+
+/* size (in words) of single State Information entry (ctxt reg address|data) */
+#define IX_NPEDL_STATE_INFO_ENTRY_SIZE 2
+
+typedef struct {
+ uint32_t type;
+ uint32_t offset;
+} IxNpeDlNpeMgrDownloadMapBlockEntry;
+
+typedef union {
+ IxNpeDlNpeMgrDownloadMapBlockEntry block;
+ uint32_t eodmMarker;
+} IxNpeDlNpeMgrDownloadMapEntry;
+
+typedef struct {
+ /* 1st entry in the download map (there may be more than one) */
+ IxNpeDlNpeMgrDownloadMapEntry entry[1];
+} IxNpeDlNpeMgrDownloadMap;
+
+/* used to access an instruction or data block in a microcode image */
+typedef struct {
+ uint32_t npeMemAddress;
+ uint32_t size;
+ uint32_t data[1];
+} IxNpeDlNpeMgrCodeBlock;
+
+/* used to access each Context Reg entry state-information block */
+typedef struct {
+ uint32_t addressInfo;
+ uint32_t value;
+} IxNpeDlNpeMgrStateInfoCtxtRegEntry;
+
+/* used to access a state-information block in a microcode image */
+typedef struct {
+ uint32_t size;
+ IxNpeDlNpeMgrStateInfoCtxtRegEntry ctxtRegEntry[1];
+} IxNpeDlNpeMgrStateInfoBlock;
+
+static int npe_debug = 0;
+SYSCTL_INT(_debug, OID_AUTO, ixp425npe, CTLFLAG_RW, &npe_debug,
+ 0, "IXP425 NPE debug msgs");
+TUNABLE_INT("debug.ixp425npe", &npe_debug);
+#define DPRINTF(dev, fmt, ...) do { \
+ if (npe_debug) device_printf(dev, fmt, __VA_ARGS__); \
+} while (0)
+#define DPRINTFn(n, dev, fmt, ...) do { \
+ if (npe_debug >= n) printf(fmt, __VA_ARGS__); \
+} while (0)
+
+static int npe_checkbits(struct ixpnpe_softc *, uint32_t reg, uint32_t);
+static int npe_isstopped(struct ixpnpe_softc *);
+static int npe_load_ins(struct ixpnpe_softc *,
+ const IxNpeDlNpeMgrCodeBlock *bp, int verify);
+static int npe_load_data(struct ixpnpe_softc *,
+ const IxNpeDlNpeMgrCodeBlock *bp, int verify);
+static int npe_load_stateinfo(struct ixpnpe_softc *,
+ const IxNpeDlNpeMgrStateInfoBlock *bp, int verify);
+static int npe_load_image(struct ixpnpe_softc *,
+ const uint32_t *imageCodePtr, int verify);
+static int npe_cpu_reset(struct ixpnpe_softc *);
+static int npe_cpu_start(struct ixpnpe_softc *);
+static int npe_cpu_stop(struct ixpnpe_softc *);
+static void npe_cmd_issue_write(struct ixpnpe_softc *,
+ uint32_t cmd, uint32_t addr, uint32_t data);
+static uint32_t npe_cmd_issue_read(struct ixpnpe_softc *,
+ uint32_t cmd, uint32_t addr);
+static int npe_ins_write(struct ixpnpe_softc *,
+ uint32_t addr, uint32_t data, int verify);
+static int npe_data_write(struct ixpnpe_softc *,
+ uint32_t addr, uint32_t data, int verify);
+static void npe_ecs_reg_write(struct ixpnpe_softc *,
+ uint32_t reg, uint32_t data);
+static uint32_t npe_ecs_reg_read(struct ixpnpe_softc *, uint32_t reg);
+static void npe_issue_cmd(struct ixpnpe_softc *, uint32_t command);
+static void npe_cpu_step_save(struct ixpnpe_softc *);
+static int npe_cpu_step(struct ixpnpe_softc *, uint32_t npeInstruction,
+ uint32_t ctxtNum, uint32_t ldur);
+static void npe_cpu_step_restore(struct ixpnpe_softc *);
+static int npe_logical_reg_read(struct ixpnpe_softc *,
+ uint32_t regAddr, uint32_t regSize,
+ uint32_t ctxtNum, uint32_t *regVal);
+static int npe_logical_reg_write(struct ixpnpe_softc *,
+ uint32_t regAddr, uint32_t regVal,
+ uint32_t regSize, uint32_t ctxtNum, int verify);
+static int npe_physical_reg_write(struct ixpnpe_softc *,
+ uint32_t regAddr, uint32_t regValue, int verify);
+static int npe_ctx_reg_write(struct ixpnpe_softc *, uint32_t ctxtNum,
+ uint32_t ctxtReg, uint32_t ctxtRegVal, int verify);
+
+static void ixpnpe_intr(void *arg);
+
+static uint32_t
+npe_reg_read(struct ixpnpe_softc *sc, bus_size_t off)
+{
+ uint32_t v = bus_space_read_4(sc->sc_iot, sc->sc_ioh, off);
+ DPRINTFn(9, sc->sc_dev, "%s(0x%lx) => 0x%x\n", __func__, off, v);
+ return v;
+}
+
+static void
+npe_reg_write(struct ixpnpe_softc *sc, bus_size_t off, uint32_t val)
+{
+ DPRINTFn(9, sc->sc_dev, "%s(0x%lx, 0x%x)\n", __func__, off, val);
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, off, val);
+}
+
+struct ixpnpe_softc *
+ixpnpe_attach(device_t dev)
+{
+ struct ixp425_softc *sa = device_get_softc(device_get_parent(dev));
+ struct ixpnpe_softc *sc;
+ bus_addr_t base;
+ int rid, irq;
+
+ /* XXX M_BUS */
+ sc = malloc(sizeof(struct ixpnpe_softc), M_TEMP, M_WAITOK | M_ZERO);
+ sc->sc_dev = dev;
+ sc->sc_iot = sa->sc_iot;
+ mtx_init(&sc->sc_mtx, device_get_nameunit(dev), "npe driver", MTX_DEF);
+
+ if (device_get_unit(dev) == 0) {
+ base = IXP425_NPE_B_HWBASE;
+ sc->sc_size = IXP425_NPE_B_SIZE;
+ irq = IXP425_INT_NPE_B;
+
+ /* size of instruction memory */
+ sc->insMemSize = IX_NPEDL_INS_MEMSIZE_WORDS_NPEB;
+ /* size of data memory */
+ sc->dataMemSize = IX_NPEDL_DATA_MEMSIZE_WORDS_NPEB;
+ } else {
+ base = IXP425_NPE_C_HWBASE;
+ sc->sc_size = IXP425_NPE_C_SIZE;
+ irq = IXP425_INT_NPE_C;
+
+ /* size of instruction memory */
+ sc->insMemSize = IX_NPEDL_INS_MEMSIZE_WORDS_NPEC;
+ /* size of data memory */
+ sc->dataMemSize = IX_NPEDL_DATA_MEMSIZE_WORDS_NPEC;
+ }
+ if (bus_space_map(sc->sc_iot, base, sc->sc_size, 0, &sc->sc_ioh))
+ panic("%s: Cannot map registers", device_get_name(dev));
+
+ /*
+ * Setup IRQ and handler for NPE message support.
+ */
+ rid = 0;
+ sc->sc_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid,
+ irq, irq, 1, RF_ACTIVE);
+ if (!sc->sc_irq)
+ panic("%s: Unable to allocate irq %u", device_get_name(dev), irq);
+ /* XXX could be a source of entropy */
+ bus_setup_intr(dev, sc->sc_irq, INTR_TYPE_NET | INTR_MPSAFE,
+ ixpnpe_intr, sc, &sc->sc_ih);
+ /* enable output fifo interrupts (NB: must also set OFIFO Write Enable) */
+ npe_reg_write(sc, IX_NPECTL,
+ npe_reg_read(sc, IX_NPECTL) | (IX_NPECTL_OFE | IX_NPECTL_OFWE));
+
+ return sc;
+}
+
+void
+ixpnpe_detach(struct ixpnpe_softc *sc)
+{
+ /* disable output fifo interrupts */
+ npe_reg_write(sc, IX_NPECTL,
+ npe_reg_read(sc, IX_NPECTL) &~ (IX_NPECTL_OFE | IX_NPECTL_OFWE));
+
+ bus_teardown_intr(sc->sc_dev, sc->sc_irq, sc->sc_ih);
+ bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_size);
+ mtx_destroy(&sc->sc_mtx);
+ free(sc, M_TEMP);
+}
+
+int
+ixpnpe_stopandreset(struct ixpnpe_softc *sc)
+{
+ int error;
+
+ mtx_lock(&sc->sc_mtx);
+ error = npe_cpu_stop(sc); /* stop NPE */
+ if (error == 0)
+ error = npe_cpu_reset(sc); /* reset it */
+ if (error == 0)
+ sc->started = 0; /* mark stopped */
+ mtx_unlock(&sc->sc_mtx);
+
+ DPRINTF(sc->sc_dev, "%s: error %d\n", __func__, error);
+ return error;
+}
+
+static int
+ixpnpe_start_locked(struct ixpnpe_softc *sc)
+{
+ int error;
+
+ if (!sc->started) {
+ error = npe_cpu_start(sc);
+ if (error == 0)
+ sc->started = 1;
+ } else
+ error = 0;
+
+ DPRINTF(sc->sc_dev, "%s: error %d\n", __func__, error);
+ return error;
+}
+
+int
+ixpnpe_start(struct ixpnpe_softc *sc)
+{
+ int ret;
+
+ mtx_lock(&sc->sc_mtx);
+ ret = ixpnpe_start_locked(sc);
+ mtx_unlock(&sc->sc_mtx);
+ return (ret);
+}
+
+int
+ixpnpe_stop(struct ixpnpe_softc *sc)
+{
+ int error;
+
+ mtx_lock(&sc->sc_mtx);
+ error = npe_cpu_stop(sc);
+ if (error == 0)
+ sc->started = 0;
+ mtx_unlock(&sc->sc_mtx);
+
+ DPRINTF(sc->sc_dev, "%s: error %d\n", __func__, error);
+ return error;
+}
+
+/*
+ * Indicates the start of an NPE Image, in new NPE Image Library format.
+ * 2 consecutive occurances indicates the end of the NPE Image Library
+ */
+#define NPE_IMAGE_MARKER 0xfeedf00d
+
+/*
+ * NPE Image Header definition, used in new NPE Image Library format
+ */
+typedef struct {
+ uint32_t marker;
+ uint32_t id;
+ uint32_t size;
+} IxNpeDlImageMgrImageHeader;
+
+static int
+npe_findimage(struct ixpnpe_softc *sc,
+ const uint32_t *imageLibrary, uint32_t imageId,
+ const uint32_t **imagePtr, uint32_t *imageSize)
+{
+ const IxNpeDlImageMgrImageHeader *image;
+ uint32_t offset = 0;
+
+ while (imageLibrary[offset] == NPE_IMAGE_MARKER) {
+ image = (const IxNpeDlImageMgrImageHeader *)&imageLibrary[offset];
+ offset += sizeof(IxNpeDlImageMgrImageHeader)/sizeof(uint32_t);
+
+ DPRINTF(sc->sc_dev, "%s: off %u mark 0x%x id 0x%x size %u\n",
+ __func__, offset, image->marker, image->id, image->size);
+ if (image->id == imageId) {
+ *imagePtr = imageLibrary + offset;
+ *imageSize = image->size;
+ return 0;
+ }
+ /* 2 consecutive NPE_IMAGE_MARKER's indicates end of library */
+ if (image->id == NPE_IMAGE_MARKER) {
+ device_printf(sc->sc_dev,
+ "imageId 0x%08x not found in image library header\n", imageId);
+ /* reached end of library, image not found */
+ return EIO;
+ }
+ offset += image->size;
+ }
+ return EIO;
+}
+
+int
+ixpnpe_init(struct ixpnpe_softc *sc, const char *imageName, uint32_t imageId)
+{
+ uint32_t imageSize;
+ const uint32_t *imageCodePtr;
+ struct firmware *fw;
+ int error;
+
+ DPRINTF(sc->sc_dev, "load %s, imageId 0x%08x\n", imageName, imageId);
+
+#if 0
+ IxFeatureCtrlDeviceId devid = IX_NPEDL_DEVICEID_FROM_IMAGEID_GET(imageId);
+ /*
+ * Checking if image being loaded is meant for device that is running.
+ * Image is forward compatible. i.e Image built for IXP42X should run
+ * on IXP46X but not vice versa.
+ */
+ if (devid > (ixFeatureCtrlDeviceRead() & IX_FEATURE_CTRL_DEVICE_TYPE_MASK))
+ return EINVAL;
+#endif
+ error = ixpnpe_stopandreset(sc); /* stop and reset the NPE */
+ if (error != 0)
+ return error;
+
+ fw = firmware_get(imageName);
+ if (fw == NULL)
+ return ENOENT;
+
+ /* Locate desired image in files w/ combined images */
+ error = npe_findimage(sc, fw->data, imageId, &imageCodePtr, &imageSize);
+ if (error != 0)
+ goto done;
+
+ /*
+ * If download was successful, store image Id in list of
+ * currently loaded images. If a critical error occured
+ * during download, record that the NPE has an invalid image
+ */
+ mtx_lock(&sc->sc_mtx);
+ error = npe_load_image(sc, imageCodePtr, 1 /*VERIFY*/);
+ if (error == 0) {
+ sc->validImage = 1;
+ error = ixpnpe_start_locked(sc);
+ } else {
+ sc->validImage = 0;
+ }
+ sc->functionalityId = IX_NPEDL_FUNCTIONID_FROM_IMAGEID_GET(imageId);
+ mtx_unlock(&sc->sc_mtx);
+done:
+ firmware_put(fw, FIRMWARE_UNLOAD);
+ DPRINTF(sc->sc_dev, "%s: error %d\n", __func__, error);
+ return error;
+}
+
+int
+ixpnpe_getfunctionality(struct ixpnpe_softc *sc)
+{
+ return (sc->validImage ? sc->functionalityId : 0);
+}
+
+static int
+npe_checkbits(struct ixpnpe_softc *sc, uint32_t reg, uint32_t expectedBitsSet)
+{
+ uint32_t val;
+
+ val = npe_reg_read(sc, reg);
+ DPRINTFn(5, sc->sc_dev, "%s(0x%x, 0x%x) => 0x%x (%u)\n",
+ __func__, reg, expectedBitsSet, val,
+ (val & expectedBitsSet) == expectedBitsSet);
+ return ((val & expectedBitsSet) == expectedBitsSet);
+}
+
+static int
+npe_isstopped(struct ixpnpe_softc *sc)
+{
+ return npe_checkbits(sc,
+ IX_NPEDL_REG_OFFSET_EXCTL, IX_NPEDL_EXCTL_STATUS_STOP);
+}
+
+static int
+npe_load_ins(struct ixpnpe_softc *sc,
+ const IxNpeDlNpeMgrCodeBlock *bp, int verify)
+{
+ uint32_t npeMemAddress;
+ int i, blockSize;
+
+ npeMemAddress = bp->npeMemAddress;
+ blockSize = bp->size; /* NB: instruction/data count */
+ if (npeMemAddress + blockSize > sc->insMemSize) {
+ device_printf(sc->sc_dev, "Block size too big for NPE memory\n");
+ return EINVAL; /* XXX */
+ }
+ for (i = 0; i < blockSize; i++, npeMemAddress++) {
+ if (npe_ins_write(sc, npeMemAddress, bp->data[i], verify) != 0) {
+ device_printf(sc->sc_dev, "NPE instruction write failed");
+ return EIO;
+ }
+ }
+ return 0;
+}
+
+static int
+npe_load_data(struct ixpnpe_softc *sc,
+ const IxNpeDlNpeMgrCodeBlock *bp, int verify)
+{
+ uint32_t npeMemAddress;
+ int i, blockSize;
+
+ npeMemAddress = bp->npeMemAddress;
+ blockSize = bp->size; /* NB: instruction/data count */
+ if (npeMemAddress + blockSize > sc->dataMemSize) {
+ device_printf(sc->sc_dev, "Block size too big for NPE memory\n");
+ return EINVAL;
+ }
+ for (i = 0; i < blockSize; i++, npeMemAddress++) {
+ if (npe_data_write(sc, npeMemAddress, bp->data[i], verify) != 0) {
+ device_printf(sc->sc_dev, "NPE data write failed\n");
+ return EIO;
+ }
+ }
+ return 0;
+}
+
+static int
+npe_load_stateinfo(struct ixpnpe_softc *sc,
+ const IxNpeDlNpeMgrStateInfoBlock *bp, int verify)
+{
+ int i, nentries, error;
+
+ npe_cpu_step_save(sc);
+
+ /* for each state-info context register entry in block */
+ nentries = bp->size / IX_NPEDL_STATE_INFO_ENTRY_SIZE;
+ error = 0;
+ for (i = 0; i < nentries; i++) {
+ /* each state-info entry is 2 words (address, value) in length */
+ uint32_t regVal = bp->ctxtRegEntry[i].value;
+ uint32_t addrInfo = bp->ctxtRegEntry[i].addressInfo;
+
+ uint32_t reg = (addrInfo & IX_NPEDL_MASK_STATE_ADDR_CTXT_REG);
+ uint32_t cNum = (addrInfo & IX_NPEDL_MASK_STATE_ADDR_CTXT_NUM) >>
+ IX_NPEDL_OFFSET_STATE_ADDR_CTXT_NUM;
+
+ /* error-check Context Register No. and Context Number values */
+ if (!(0 <= reg && reg < IX_NPEDL_CTXT_REG_MAX)) {
+ device_printf(sc->sc_dev, "invalid Context Register %u\n", reg);
+ error = EINVAL;
+ break;
+ }
+ if (!(0 <= cNum && cNum < IX_NPEDL_CTXT_NUM_MAX)) {
+ device_printf(sc->sc_dev, "invalid Context Number %u\n", cNum);
+ error = EINVAL;
+ break;
+ }
+ /* NOTE that there is no STEVT register for Context 0 */
+ if (cNum == 0 && reg == IX_NPEDL_CTXT_REG_STEVT) {
+ device_printf(sc->sc_dev, "no STEVT for Context 0\n");
+ error = EINVAL;
+ break;
+ }
+
+ if (npe_ctx_reg_write(sc, cNum, reg, regVal, verify) != 0) {
+ device_printf(sc->sc_dev, "write of state-info to NPE failed\n");
+ error = EIO;
+ break;
+ }
+ }
+
+ npe_cpu_step_restore(sc);
+ return error;
+}
+
+static int
+npe_load_image(struct ixpnpe_softc *sc,
+ const uint32_t *imageCodePtr, int verify)
+{
+#define EOM(marker) ((marker) == IX_NPEDL_END_OF_DOWNLOAD_MAP)
+ const IxNpeDlNpeMgrDownloadMap *downloadMap;
+ int i, error;
+
+ if (!npe_isstopped(sc)) { /* verify NPE is stopped */
+ device_printf(sc->sc_dev, "cannot load image, NPE not stopped\n");
+ return EIO;
+ }
+
+ /*
+ * Read Download Map, checking each block type and calling
+ * appropriate function to perform download
+ */
+ error = 0;
+ downloadMap = (const IxNpeDlNpeMgrDownloadMap *) imageCodePtr;
+ for (i = 0; !EOM(downloadMap->entry[i].eodmMarker); i++) {
+ /* calculate pointer to block to be downloaded */
+ const uint32_t *bp = imageCodePtr + downloadMap->entry[i].block.offset;
+ switch (downloadMap->entry[i].block.type) {
+ case IX_NPEDL_BLOCK_TYPE_INSTRUCTION:
+ error = npe_load_ins(sc,
+ (const IxNpeDlNpeMgrCodeBlock *) bp, verify);
+ DPRINTF(sc->sc_dev, "%s: inst, error %d\n", __func__, error);
+ break;
+ case IX_NPEDL_BLOCK_TYPE_DATA:
+ error = npe_load_data(sc,
+ (const IxNpeDlNpeMgrCodeBlock *) bp, verify);
+ DPRINTF(sc->sc_dev, "%s: data, error %d\n", __func__, error);
+ break;
+ case IX_NPEDL_BLOCK_TYPE_STATE:
+ error = npe_load_stateinfo(sc,
+ (const IxNpeDlNpeMgrStateInfoBlock *) bp, verify);
+ DPRINTF(sc->sc_dev, "%s: state, error %d\n", __func__, error);
+ break;
+ default:
+ device_printf(sc->sc_dev,
+ "unknown block type 0x%x in download map\n",
+ downloadMap->entry[i].block.type);
+ error = EIO; /* XXX */
+ break;
+ }
+ if (error != 0)
+ break;
+ }
+ return error;
+#undef EOM
+}
+
+/* contains Reset values for Context Store Registers */
+static const struct {
+ uint32_t regAddr;
+ uint32_t regResetVal;
+} ixNpeDlEcsRegResetValues[] = {
+ { IX_NPEDL_ECS_BG_CTXT_REG_0, IX_NPEDL_ECS_BG_CTXT_REG_0_RESET },
+ { IX_NPEDL_ECS_BG_CTXT_REG_1, IX_NPEDL_ECS_BG_CTXT_REG_1_RESET },
+ { IX_NPEDL_ECS_BG_CTXT_REG_2, IX_NPEDL_ECS_BG_CTXT_REG_2_RESET },
+ { IX_NPEDL_ECS_PRI_1_CTXT_REG_0, IX_NPEDL_ECS_PRI_1_CTXT_REG_0_RESET },
+ { IX_NPEDL_ECS_PRI_1_CTXT_REG_1, IX_NPEDL_ECS_PRI_1_CTXT_REG_1_RESET },
+ { IX_NPEDL_ECS_PRI_1_CTXT_REG_2, IX_NPEDL_ECS_PRI_1_CTXT_REG_2_RESET },
+ { IX_NPEDL_ECS_PRI_2_CTXT_REG_0, IX_NPEDL_ECS_PRI_2_CTXT_REG_0_RESET },
+ { IX_NPEDL_ECS_PRI_2_CTXT_REG_1, IX_NPEDL_ECS_PRI_2_CTXT_REG_1_RESET },
+ { IX_NPEDL_ECS_PRI_2_CTXT_REG_2, IX_NPEDL_ECS_PRI_2_CTXT_REG_2_RESET },
+ { IX_NPEDL_ECS_DBG_CTXT_REG_0, IX_NPEDL_ECS_DBG_CTXT_REG_0_RESET },
+ { IX_NPEDL_ECS_DBG_CTXT_REG_1, IX_NPEDL_ECS_DBG_CTXT_REG_1_RESET },
+ { IX_NPEDL_ECS_DBG_CTXT_REG_2, IX_NPEDL_ECS_DBG_CTXT_REG_2_RESET },
+ { IX_NPEDL_ECS_INSTRUCT_REG, IX_NPEDL_ECS_INSTRUCT_REG_RESET }
+};
+
+/* contains Reset values for Context Store Registers */
+static const uint32_t ixNpeDlCtxtRegResetValues[] = {
+ IX_NPEDL_CTXT_REG_RESET_STEVT,
+ IX_NPEDL_CTXT_REG_RESET_STARTPC,
+ IX_NPEDL_CTXT_REG_RESET_REGMAP,
+ IX_NPEDL_CTXT_REG_RESET_CINDEX,
+};
+
+#define IX_NPEDL_RESET_NPE_PARITY 0x0800
+#define IX_NPEDL_PARITY_BIT_MASK 0x3F00FFFF
+#define IX_NPEDL_CONFIG_CTRL_REG_MASK 0x3F3FFFFF
+
+static int
+npe_cpu_reset(struct ixpnpe_softc *sc)
+{
+#define N(a) (sizeof(a) / sizeof(a[0]))
+ struct ixp425_softc *sa = device_get_softc(device_get_parent(sc->sc_dev));
+ uint32_t ctxtReg; /* identifies Context Store reg (0-3) */
+ uint32_t regAddr;
+ uint32_t regVal;
+ uint32_t resetNpeParity;
+ uint32_t ixNpeConfigCtrlRegVal;
+ int i, error = 0;
+
+ /* pre-store the NPE Config Control Register Value */
+ ixNpeConfigCtrlRegVal = npe_reg_read(sc, IX_NPEDL_REG_OFFSET_CTL);
+ ixNpeConfigCtrlRegVal |= 0x3F000000;
+
+ /* disable the parity interrupt */
+ npe_reg_write(sc, IX_NPEDL_REG_OFFSET_CTL,
+ (ixNpeConfigCtrlRegVal & IX_NPEDL_PARITY_BIT_MASK));
+ DPRINTFn(2, sc->sc_dev, "%s: dis parity int, CTL => 0x%x\n",
+ __func__, ixNpeConfigCtrlRegVal & IX_NPEDL_PARITY_BIT_MASK);
+
+ npe_cpu_step_save(sc);
+
+ /*
+ * Clear the FIFOs.
+ */
+ while (npe_checkbits(sc,
+ IX_NPEDL_REG_OFFSET_WFIFO, IX_NPEDL_MASK_WFIFO_VALID)) {
+ /* read from the Watch-point FIFO until empty */
+ (void) npe_reg_read(sc, IX_NPEDL_REG_OFFSET_WFIFO);
+ }
+
+ while (npe_checkbits(sc,
+ IX_NPEDL_REG_OFFSET_STAT, IX_NPEDL_MASK_STAT_OFNE)) {
+ /* read from the outFIFO until empty */
+ (void) npe_reg_read(sc, IX_NPEDL_REG_OFFSET_FIFO);
+ }
+
+ while (npe_checkbits(sc,
+ IX_NPEDL_REG_OFFSET_STAT, IX_NPEDL_MASK_STAT_IFNE)) {
+ /*
+ * Step execution of the NPE intruction to read inFIFO using
+ * the Debug Executing Context stack.
+ */
+ error = npe_cpu_step(sc, IX_NPEDL_INSTR_RD_FIFO, 0, 0);
+ if (error != 0) {
+ DPRINTF(sc->sc_dev, "%s: cannot step (1), error %u\n",
+ __func__, error);
+ npe_cpu_step_restore(sc);
+ return error;
+ }
+ }
+
+ /*
+ * Reset the mailbox reg
+ */
+ /* ...from XScale side */
+ npe_reg_write(sc, IX_NPEDL_REG_OFFSET_MBST, IX_NPEDL_REG_RESET_MBST);
+ /* ...from NPE side */
+ error = npe_cpu_step(sc, IX_NPEDL_INSTR_RESET_MBOX, 0, 0);
+ if (error != 0) {
+ DPRINTF(sc->sc_dev, "%s: cannot step (2), error %u\n", __func__, error);
+ npe_cpu_step_restore(sc);
+ return error;
+ }
+
+ /*
+ * Reset the physical registers in the NPE register file:
+ * Note: no need to save/restore REGMAP for Context 0 here
+ * since all Context Store regs are reset in subsequent code.
+ */
+ for (regAddr = 0;
+ regAddr < IX_NPEDL_TOTAL_NUM_PHYS_REG && error == 0;
+ regAddr++) {
+ /* for each physical register in the NPE reg file, write 0 : */
+ error = npe_physical_reg_write(sc, regAddr, 0, TRUE);
+ if (error != 0) {
+ DPRINTF(sc->sc_dev, "%s: cannot write phy reg, error %u\n",
+ __func__, error);
+ npe_cpu_step_restore(sc);
+ return error; /* abort reset */
+ }
+ }
+
+ /*
+ * Reset the context store:
+ */
+ for (i = IX_NPEDL_CTXT_NUM_MIN; i <= IX_NPEDL_CTXT_NUM_MAX; i++) {
+ /* set each context's Context Store registers to reset values: */
+ for (ctxtReg = 0; ctxtReg < IX_NPEDL_CTXT_REG_MAX; ctxtReg++) {
+ /* NOTE that there is no STEVT register for Context 0 */
+ if (!(i == 0 && ctxtReg == IX_NPEDL_CTXT_REG_STEVT)) {
+ regVal = ixNpeDlCtxtRegResetValues[ctxtReg];
+ error = npe_ctx_reg_write(sc, i, ctxtReg, regVal, TRUE);
+ if (error != 0) {
+ DPRINTF(sc->sc_dev, "%s: cannot write ctx reg, error %u\n",
+ __func__, error);
+ npe_cpu_step_restore(sc);
+ return error; /* abort reset */
+ }
+ }
+ }
+ }
+
+ npe_cpu_step_restore(sc);
+
+ /* write Reset values to Execution Context Stack registers */
+ for (i = 0; i < N(ixNpeDlEcsRegResetValues); i++)
+ npe_ecs_reg_write(sc,
+ ixNpeDlEcsRegResetValues[i].regAddr,
+ ixNpeDlEcsRegResetValues[i].regResetVal);
+
+ /* clear the profile counter */
+ npe_issue_cmd(sc, IX_NPEDL_EXCTL_CMD_CLR_PROFILE_CNT);
+
+ /* clear registers EXCT, AP0, AP1, AP2 and AP3 */
+ for (regAddr = IX_NPEDL_REG_OFFSET_EXCT;
+ regAddr <= IX_NPEDL_REG_OFFSET_AP3;
+ regAddr += sizeof(uint32_t))
+ npe_reg_write(sc, regAddr, 0);
+
+ /* Reset the Watch-count register */
+ npe_reg_write(sc, IX_NPEDL_REG_OFFSET_WC, 0);
+
+ /*
+ * WR IXA00055043 - Remove IMEM Parity Introduced by NPE Reset Operation
+ */
+
+ /*
+ * Reset the NPE and its coprocessor - to reset internal
+ * states and remove parity error. Note this makes no
+ * sense based on the documentation. The feature control
+ * register always reads back as 0 on the ixp425 and further
+ * the bit definition of NPEA/NPEB is off by 1 according to
+ * the Intel documention--so we're blindly following the
+ * Intel code w/o any real understanding.
+ */
+ regVal = EXP_BUS_READ_4(sa, EXP_FCTRL_OFFSET);
+ DPRINTFn(2, sc->sc_dev, "%s: FCTRL 0x%x\n", __func__, regVal);
+ resetNpeParity =
+ IX_NPEDL_RESET_NPE_PARITY << (1 + device_get_unit(sc->sc_dev));
+ DPRINTFn(2, sc->sc_dev, "%s: FCTRL fuse parity, write 0x%x\n",
+ __func__, regVal | resetNpeParity);
+ EXP_BUS_WRITE_4(sa, EXP_FCTRL_OFFSET, regVal | resetNpeParity);
+
+ /* un-fuse and un-reset the NPE & coprocessor */
+ DPRINTFn(2, sc->sc_dev, "%s: FCTRL unfuse parity, write 0x%x\n",
+ __func__, regVal & resetNpeParity);
+ EXP_BUS_WRITE_4(sa, EXP_FCTRL_OFFSET, regVal &~ resetNpeParity);
+
+ /*
+ * Call NpeMgr function to stop the NPE again after the Feature Control
+ * has unfused and Un-Reset the NPE and its associated Coprocessors.
+ */
+ error = npe_cpu_stop(sc);
+
+ /* restore NPE configuration bus Control Register - Parity Settings */
+ npe_reg_write(sc, IX_NPEDL_REG_OFFSET_CTL,
+ (ixNpeConfigCtrlRegVal & IX_NPEDL_CONFIG_CTRL_REG_MASK));
+ DPRINTFn(2, sc->sc_dev, "%s: restore CTL => 0x%x\n",
+ __func__, npe_reg_read(sc, IX_NPEDL_REG_OFFSET_CTL));
+
+ return error;
+#undef N
+}
+
+static int
+npe_cpu_start(struct ixpnpe_softc *sc)
+{
+ uint32_t ecsRegVal;
+
+ /*
+ * Ensure only Background Context Stack Level is Active by turning off
+ * the Active bit in each of the other Executing Context Stack levels.
+ */
+ ecsRegVal = npe_ecs_reg_read(sc, IX_NPEDL_ECS_PRI_1_CTXT_REG_0);
+ ecsRegVal &= ~IX_NPEDL_MASK_ECS_REG_0_ACTIVE;
+ npe_ecs_reg_write(sc, IX_NPEDL_ECS_PRI_1_CTXT_REG_0, ecsRegVal);
+
+ ecsRegVal = npe_ecs_reg_read(sc, IX_NPEDL_ECS_PRI_2_CTXT_REG_0);
+ ecsRegVal &= ~IX_NPEDL_MASK_ECS_REG_0_ACTIVE;
+ npe_ecs_reg_write(sc, IX_NPEDL_ECS_PRI_2_CTXT_REG_0, ecsRegVal);
+
+ ecsRegVal = npe_ecs_reg_read(sc, IX_NPEDL_ECS_DBG_CTXT_REG_0);
+ ecsRegVal &= ~IX_NPEDL_MASK_ECS_REG_0_ACTIVE;
+ npe_ecs_reg_write(sc, IX_NPEDL_ECS_DBG_CTXT_REG_0, ecsRegVal);
+
+ /* clear the pipeline */
+ npe_issue_cmd(sc, IX_NPEDL_EXCTL_CMD_NPE_CLR_PIPE);
+
+ /* start NPE execution by issuing command through EXCTL register on NPE */
+ npe_issue_cmd(sc, IX_NPEDL_EXCTL_CMD_NPE_START);
+
+ /*
+ * Check execution status of NPE to verify operation was successful.
+ */
+ return npe_checkbits(sc,
+ IX_NPEDL_REG_OFFSET_EXCTL, IX_NPEDL_EXCTL_STATUS_RUN) ? 0 : EIO;
+}
+
+static int
+npe_cpu_stop(struct ixpnpe_softc *sc)
+{
+ /* stop NPE execution by issuing command through EXCTL register on NPE */
+ npe_issue_cmd(sc, IX_NPEDL_EXCTL_CMD_NPE_STOP);
+
+ /* verify that NPE Stop was successful */
+ return npe_checkbits(sc,
+ IX_NPEDL_REG_OFFSET_EXCTL, IX_NPEDL_EXCTL_STATUS_STOP) ? 0 : EIO;
+}
+
+#define IX_NPEDL_REG_SIZE_BYTE 8
+#define IX_NPEDL_REG_SIZE_SHORT 16
+#define IX_NPEDL_REG_SIZE_WORD 32
+
+/*
+ * Introduce extra read cycles after issuing read command to NPE
+ * so that we read the register after the NPE has updated it
+ * This is to overcome race condition between XScale and NPE
+ */
+#define IX_NPEDL_DELAY_READ_CYCLES 2
+/*
+ * To mask top three MSBs of 32bit word to download into NPE IMEM
+ */
+#define IX_NPEDL_MASK_UNUSED_IMEM_BITS 0x1FFFFFFF;
+
+static void
+npe_cmd_issue_write(struct ixpnpe_softc *sc,
+ uint32_t cmd, uint32_t addr, uint32_t data)
+{
+ npe_reg_write(sc, IX_NPEDL_REG_OFFSET_EXDATA, data);
+ npe_reg_write(sc, IX_NPEDL_REG_OFFSET_EXAD, addr);
+ npe_reg_write(sc, IX_NPEDL_REG_OFFSET_EXCTL, cmd);
+}
+
+static uint32_t
+npe_cmd_issue_read(struct ixpnpe_softc *sc, uint32_t cmd, uint32_t addr)
+{
+ uint32_t data;
+ int i;
+
+ npe_reg_write(sc, IX_NPEDL_REG_OFFSET_EXAD, addr);
+ npe_reg_write(sc, IX_NPEDL_REG_OFFSET_EXCTL, cmd);
+ for (i = 0; i <= IX_NPEDL_DELAY_READ_CYCLES; i++)
+ data = npe_reg_read(sc, IX_NPEDL_REG_OFFSET_EXDATA);
+ return data;
+}
+
+static int
+npe_ins_write(struct ixpnpe_softc *sc, uint32_t addr, uint32_t data, int verify)
+{
+ DPRINTFn(4, sc->sc_dev, "%s(0x%x, 0x%x)\n", __func__, addr, data);
+ npe_cmd_issue_write(sc, IX_NPEDL_EXCTL_CMD_WR_INS_MEM, addr, data);
+ if (verify) {
+ uint32_t rdata;
+
+ /*
+ * Write invalid data to this reg, so we can see if we're reading
+ * the EXDATA register too early.
+ */
+ npe_reg_write(sc, IX_NPEDL_REG_OFFSET_EXDATA, ~data);
+
+ /* Disabled since top 3 MSB are not used for Azusa hardware Refer WR:IXA00053900*/
+ data &= IX_NPEDL_MASK_UNUSED_IMEM_BITS;
+
+ rdata = npe_cmd_issue_read(sc, IX_NPEDL_EXCTL_CMD_RD_INS_MEM, addr);
+ rdata &= IX_NPEDL_MASK_UNUSED_IMEM_BITS;
+
+ if (data != rdata)
+ return EIO;
+ }
+ return 0;
+}
+
+static int
+npe_data_write(struct ixpnpe_softc *sc, uint32_t addr, uint32_t data, int verify)
+{
+ DPRINTFn(4, sc->sc_dev, "%s(0x%x, 0x%x)\n", __func__, addr, data);
+ npe_cmd_issue_write(sc, IX_NPEDL_EXCTL_CMD_WR_DATA_MEM, addr, data);
+ if (verify) {
+ /*
+ * Write invalid data to this reg, so we can see if we're reading
+ * the EXDATA register too early.
+ */
+ npe_reg_write(sc, IX_NPEDL_REG_OFFSET_EXDATA, ~data);
+ if (data != npe_cmd_issue_read(sc, IX_NPEDL_EXCTL_CMD_RD_DATA_MEM, addr))
+ return EIO;
+ }
+ return 0;
+}
+
+static void
+npe_ecs_reg_write(struct ixpnpe_softc *sc, uint32_t reg, uint32_t data)
+{
+ npe_cmd_issue_write(sc, IX_NPEDL_EXCTL_CMD_WR_ECS_REG, reg, data);
+}
+
+static uint32_t
+npe_ecs_reg_read(struct ixpnpe_softc *sc, uint32_t reg)
+{
+ return npe_cmd_issue_read(sc, IX_NPEDL_EXCTL_CMD_RD_ECS_REG, reg);
+}
+
+static void
+npe_issue_cmd(struct ixpnpe_softc *sc, uint32_t command)
+{
+ npe_reg_write(sc, IX_NPEDL_REG_OFFSET_EXCTL, command);
+}
+
+static void
+npe_cpu_step_save(struct ixpnpe_softc *sc)
+{
+ /* turn off the halt bit by clearing Execution Count register. */
+ /* save reg contents 1st and restore later */
+ sc->savedExecCount = npe_reg_read(sc, IX_NPEDL_REG_OFFSET_EXCT);
+ npe_reg_write(sc, IX_NPEDL_REG_OFFSET_EXCT, 0);
+
+ /* ensure that IF and IE are on (temporarily), so that we don't end up
+ * stepping forever */
+ sc->savedEcsDbgCtxtReg2 = npe_ecs_reg_read(sc, IX_NPEDL_ECS_DBG_CTXT_REG_2);
+
+ npe_ecs_reg_write(sc, IX_NPEDL_ECS_DBG_CTXT_REG_2,
+ (sc->savedEcsDbgCtxtReg2 | IX_NPEDL_MASK_ECS_DBG_REG_2_IF |
+ IX_NPEDL_MASK_ECS_DBG_REG_2_IE));
+}
+
+static int
+npe_cpu_step(struct ixpnpe_softc *sc, uint32_t npeInstruction,
+ uint32_t ctxtNum, uint32_t ldur)
+{
+#define IX_NPE_DL_MAX_NUM_OF_RETRIES 1000000
+ uint32_t ecsDbgRegVal;
+ uint32_t oldWatchcount, newWatchcount;
+ int tries;
+
+ /* set the Active bit, and the LDUR, in the debug level */
+ ecsDbgRegVal = IX_NPEDL_MASK_ECS_REG_0_ACTIVE |
+ (ldur << IX_NPEDL_OFFSET_ECS_REG_0_LDUR);
+
+ npe_ecs_reg_write(sc, IX_NPEDL_ECS_DBG_CTXT_REG_0, ecsDbgRegVal);
+
+ /*
+ * Set CCTXT at ECS DEBUG L3 to specify in which context to execute the
+ * instruction, and set SELCTXT at ECS DEBUG Level to specify which context
+ * store to access.
+ * Debug ECS Level Reg 1 has form 0x000n000n, where n = context number
+ */
+ ecsDbgRegVal = (ctxtNum << IX_NPEDL_OFFSET_ECS_REG_1_CCTXT) |
+ (ctxtNum << IX_NPEDL_OFFSET_ECS_REG_1_SELCTXT);
+
+ npe_ecs_reg_write(sc, IX_NPEDL_ECS_DBG_CTXT_REG_1, ecsDbgRegVal);
+
+ /* clear the pipeline */
+ npe_issue_cmd(sc, IX_NPEDL_EXCTL_CMD_NPE_CLR_PIPE);
+
+ /* load NPE instruction into the instruction register */
+ npe_ecs_reg_write(sc, IX_NPEDL_ECS_INSTRUCT_REG, npeInstruction);
+
+ /* we need this value later to wait for completion of NPE execution step */
+ oldWatchcount = npe_reg_read(sc, IX_NPEDL_REG_OFFSET_WC);
+
+ /* issue a Step One command via the Execution Control register */
+ npe_issue_cmd(sc, IX_NPEDL_EXCTL_CMD_NPE_STEP);
+
+ /*
+ * Force the XScale to wait until the NPE has finished execution step
+ * NOTE that this delay will be very small, just long enough to allow a
+ * single NPE instruction to complete execution; if instruction execution
+ * is not completed before timeout retries, exit the while loop.
+ */
+ newWatchcount = npe_reg_read(sc, IX_NPEDL_REG_OFFSET_WC);
+ for (tries = 0; tries < IX_NPE_DL_MAX_NUM_OF_RETRIES &&
+ newWatchcount == oldWatchcount; tries++) {
+ /* Watch Count register increments when NPE completes an instruction */
+ newWatchcount = npe_reg_read(sc, IX_NPEDL_REG_OFFSET_WC);
+ }
+ return (tries < IX_NPE_DL_MAX_NUM_OF_RETRIES) ? 0 : EIO;
+#undef IX_NPE_DL_MAX_NUM_OF_RETRIES
+}
+
+static void
+npe_cpu_step_restore(struct ixpnpe_softc *sc)
+{
+ /* clear active bit in debug level */
+ npe_ecs_reg_write(sc, IX_NPEDL_ECS_DBG_CTXT_REG_0, 0);
+
+ /* clear the pipeline */
+ npe_issue_cmd(sc, IX_NPEDL_EXCTL_CMD_NPE_CLR_PIPE);
+
+ /* restore Execution Count register contents. */
+ npe_reg_write(sc, IX_NPEDL_REG_OFFSET_EXCT, sc->savedExecCount);
+
+ /* restore IF and IE bits to original values */
+ npe_ecs_reg_write(sc, IX_NPEDL_ECS_DBG_CTXT_REG_2, sc->savedEcsDbgCtxtReg2);
+}
+
+static int
+npe_logical_reg_read(struct ixpnpe_softc *sc,
+ uint32_t regAddr, uint32_t regSize,
+ uint32_t ctxtNum, uint32_t *regVal)
+{
+ uint32_t npeInstruction, mask;
+ int error;
+
+ switch (regSize) {
+ case IX_NPEDL_REG_SIZE_BYTE:
+ npeInstruction = IX_NPEDL_INSTR_RD_REG_BYTE;
+ mask = 0xff;
+ break;
+ case IX_NPEDL_REG_SIZE_SHORT:
+ npeInstruction = IX_NPEDL_INSTR_RD_REG_SHORT;
+ mask = 0xffff;
+ break;
+ case IX_NPEDL_REG_SIZE_WORD:
+ npeInstruction = IX_NPEDL_INSTR_RD_REG_WORD;
+ mask = 0xffffffff;
+ break;
+ default:
+ return EINVAL;
+ }
+
+ /* make regAddr be the SRC and DEST operands (e.g. movX d0, d0) */
+ npeInstruction |= (regAddr << IX_NPEDL_OFFSET_INSTR_SRC) |
+ (regAddr << IX_NPEDL_OFFSET_INSTR_DEST);
+
+ /* step execution of NPE intruction using Debug Executing Context stack */
+ error = npe_cpu_step(sc, npeInstruction, ctxtNum, IX_NPEDL_RD_INSTR_LDUR);
+ if (error != 0) {
+ DPRINTF(sc->sc_dev, "%s(0x%x, %u, %u), cannot step, error %d\n",
+ __func__, regAddr, regSize, ctxtNum, error);
+ return error;
+ }
+ /* read value of register from Execution Data register */
+ *regVal = npe_reg_read(sc, IX_NPEDL_REG_OFFSET_EXDATA);
+
+ /* align value from left to right */
+ *regVal = (*regVal >> (IX_NPEDL_REG_SIZE_WORD - regSize)) & mask;
+
+ return 0;
+}
+
+static int
+npe_logical_reg_write(struct ixpnpe_softc *sc, uint32_t regAddr, uint32_t regVal,
+ uint32_t regSize, uint32_t ctxtNum, int verify)
+{
+ int error;
+
+ DPRINTFn(4, sc->sc_dev, "%s(0x%x, 0x%x, %u, %u)\n",
+ __func__, regAddr, regVal, regSize, ctxtNum);
+ if (regSize == IX_NPEDL_REG_SIZE_WORD) {
+ /* NPE register addressing is left-to-right: e.g. |d0|d1|d2|d3| */
+ /* Write upper half-word (short) to |d0|d1| */
+ error = npe_logical_reg_write(sc, regAddr,
+ regVal >> IX_NPEDL_REG_SIZE_SHORT,
+ IX_NPEDL_REG_SIZE_SHORT, ctxtNum, verify);
+ if (error != 0)
+ return error;
+
+ /* Write lower half-word (short) to |d2|d3| */
+ error = npe_logical_reg_write(sc,
+ regAddr + sizeof(uint16_t),
+ regVal & 0xffff,
+ IX_NPEDL_REG_SIZE_SHORT, ctxtNum, verify);
+ } else {
+ uint32_t npeInstruction;
+
+ switch (regSize) {
+ case IX_NPEDL_REG_SIZE_BYTE:
+ npeInstruction = IX_NPEDL_INSTR_WR_REG_BYTE;
+ regVal &= 0xff;
+ break;
+ case IX_NPEDL_REG_SIZE_SHORT:
+ npeInstruction = IX_NPEDL_INSTR_WR_REG_SHORT;
+ regVal &= 0xffff;
+ break;
+ default:
+ return EINVAL;
+ }
+ /* fill dest operand field of instruction with destination reg addr */
+ npeInstruction |= (regAddr << IX_NPEDL_OFFSET_INSTR_DEST);
+
+ /* fill src operand field of instruction with least-sig 5 bits of val*/
+ npeInstruction |= ((regVal & IX_NPEDL_MASK_IMMED_INSTR_SRC_DATA) <<
+ IX_NPEDL_OFFSET_INSTR_SRC);
+
+ /* fill coprocessor field of instruction with most-sig 11 bits of val*/
+ npeInstruction |= ((regVal & IX_NPEDL_MASK_IMMED_INSTR_COPROC_DATA) <<
+ IX_NPEDL_DISPLACE_IMMED_INSTR_COPROC_DATA);
+
+ /* step execution of NPE intruction using Debug ECS */
+ error = npe_cpu_step(sc, npeInstruction,
+ ctxtNum, IX_NPEDL_WR_INSTR_LDUR);
+ }
+ if (error != 0) {
+ DPRINTF(sc->sc_dev, "%s(0x%x, 0x%x, %u, %u), error %u writing reg\n",
+ __func__, regAddr, regVal, regSize, ctxtNum, error);
+ return error;
+ }
+ if (verify) {
+ uint32_t retRegVal;
+
+ error = npe_logical_reg_read(sc, regAddr, regSize, ctxtNum, &retRegVal);
+ if (error == 0 && regVal != retRegVal)
+ error = EIO; /* XXX ambiguous */
+ }
+ return error;
+}
+
+/*
+ * There are 32 physical registers used in an NPE. These are
+ * treated as 16 pairs of 32-bit registers. To write one of the pair,
+ * write the pair number (0-16) to the REGMAP for Context 0. Then write
+ * the value to register 0 or 4 in the regfile, depending on which
+ * register of the pair is to be written
+ */
+static int
+npe_physical_reg_write(struct ixpnpe_softc *sc,
+ uint32_t regAddr, uint32_t regValue, int verify)
+{
+ int error;
+
+ /*
+ * Set REGMAP for context 0 to (regAddr >> 1) to choose which pair (0-16)
+ * of physical registers to write .
+ */
+ error = npe_logical_reg_write(sc, IX_NPEDL_CTXT_REG_ADDR_REGMAP,
+ (regAddr >> IX_NPEDL_OFFSET_PHYS_REG_ADDR_REGMAP),
+ IX_NPEDL_REG_SIZE_SHORT, 0, verify);
+ if (error == 0) {
+ /* regAddr = 0 or 4 */
+ regAddr = (regAddr & IX_NPEDL_MASK_PHYS_REG_ADDR_LOGICAL_ADDR) *
+ sizeof(uint32_t);
+ error = npe_logical_reg_write(sc, regAddr, regValue,
+ IX_NPEDL_REG_SIZE_WORD, 0, verify);
+ }
+ return error;
+}
+
+static int
+npe_ctx_reg_write(struct ixpnpe_softc *sc, uint32_t ctxtNum,
+ uint32_t ctxtReg, uint32_t ctxtRegVal, int verify)
+{
+ DPRINTFn(4, sc->sc_dev, "%s(%u, %u, %u)\n",
+ __func__, ctxtNum, ctxtReg, ctxtRegVal);
+ /*
+ * Context 0 has no STARTPC. Instead, this value is used to set
+ * NextPC for Background ECS, to set where NPE starts executing code
+ */
+ if (ctxtNum == 0 && ctxtReg == IX_NPEDL_CTXT_REG_STARTPC) {
+ /* read BG_CTXT_REG_0, update NEXTPC bits, and write back to reg */
+ uint32_t v = npe_ecs_reg_read(sc, IX_NPEDL_ECS_BG_CTXT_REG_0);
+ v &= ~IX_NPEDL_MASK_ECS_REG_0_NEXTPC;
+ v |= (ctxtRegVal << IX_NPEDL_OFFSET_ECS_REG_0_NEXTPC) &
+ IX_NPEDL_MASK_ECS_REG_0_NEXTPC;
+
+ npe_ecs_reg_write(sc, IX_NPEDL_ECS_BG_CTXT_REG_0, v);
+ return 0;
+ } else {
+ static const struct {
+ uint32_t regAddress;
+ uint32_t regSize;
+ } regAccInfo[IX_NPEDL_CTXT_REG_MAX] = {
+ { IX_NPEDL_CTXT_REG_ADDR_STEVT, IX_NPEDL_REG_SIZE_BYTE },
+ { IX_NPEDL_CTXT_REG_ADDR_STARTPC, IX_NPEDL_REG_SIZE_SHORT },
+ { IX_NPEDL_CTXT_REG_ADDR_REGMAP, IX_NPEDL_REG_SIZE_SHORT },
+ { IX_NPEDL_CTXT_REG_ADDR_CINDEX, IX_NPEDL_REG_SIZE_BYTE }
+ };
+ return npe_logical_reg_write(sc, regAccInfo[ctxtReg].regAddress,
+ ctxtRegVal, regAccInfo[ctxtReg].regSize, ctxtNum, verify);
+ }
+}
+
+/*
+ * NPE Mailbox support.
+ */
+#define IX_NPEMH_MAXTRIES 100000
+
+static int
+ixpnpe_ofifo_wait(struct ixpnpe_softc *sc)
+{
+ int i;
+
+ for (i = 0; i < IX_NPEMH_MAXTRIES; i++) {
+ if (npe_reg_read(sc, IX_NPESTAT) & IX_NPESTAT_OFNE)
+ return 1;
+ DELAY(10);
+ }
+ device_printf(sc->sc_dev, "%s: timeout, last status 0x%x\n",
+ __func__, npe_reg_read(sc, IX_NPESTAT));
+ return 0;
+}
+
+static void
+ixpnpe_intr(void *arg)
+{
+ struct ixpnpe_softc *sc = arg;
+ uint32_t status;
+
+ status = npe_reg_read(sc, IX_NPESTAT);
+ if ((status & IX_NPESTAT_OFINT) == 0) {
+ /* NB: should not happen */
+ device_printf(sc->sc_dev, "%s: status 0x%x\n", __func__, status);
+ /* XXX must silence interrupt? */
+ return;
+ }
+ /*
+ * A message is waiting in the output FIFO, copy it so
+ * the interrupt will be silenced; then signal anyone
+ * waiting to collect the result.
+ */
+ sc->sc_msgwaiting = -1; /* NB: error indicator */
+ if (ixpnpe_ofifo_wait(sc)) {
+ sc->sc_msg[0] = npe_reg_read(sc, IX_NPEFIFO);
+ if (ixpnpe_ofifo_wait(sc)) {
+ sc->sc_msg[1] = npe_reg_read(sc, IX_NPEFIFO);
+ sc->sc_msgwaiting = 1; /* successful fetch */
+ }
+ }
+ wakeup_one(sc);
+}
+
+static int
+ixpnpe_ififo_wait(struct ixpnpe_softc *sc)
+{
+ int i;
+
+ for (i = 0; i < IX_NPEMH_MAXTRIES; i++) {
+ if (npe_reg_read(sc, IX_NPESTAT) & IX_NPESTAT_IFNF)
+ return 1;
+ DELAY(10);
+ }
+ return 0;
+}
+
+static int
+ixpnpe_sendmsg_locked(struct ixpnpe_softc *sc, const uint32_t msg[2])
+{
+ int error = 0;
+
+ mtx_assert(&sc->sc_mtx, MA_OWNED);
+
+ sc->sc_msgwaiting = 0;
+ if (ixpnpe_ififo_wait(sc)) {
+ npe_reg_write(sc, IX_NPEFIFO, msg[0]);
+ if (ixpnpe_ififo_wait(sc))
+ npe_reg_write(sc, IX_NPEFIFO, msg[1]);
+ else
+ error = EIO;
+ } else
+ error = EIO;
+
+ if (error)
+ device_printf(sc->sc_dev, "input FIFO timeout, msg [0x%x,0x%x]\n",
+ msg[0], msg[1]);
+ return error;
+}
+
+static int
+ixpnpe_recvmsg_locked(struct ixpnpe_softc *sc, uint32_t msg[2])
+{
+ mtx_assert(&sc->sc_mtx, MA_OWNED);
+
+ if (!sc->sc_msgwaiting)
+ msleep(sc, &sc->sc_mtx, 0, "npemh", 0);
+ bcopy(sc->sc_msg, msg, sizeof(sc->sc_msg));
+ /* NB: sc_msgwaiting != 1 means the ack fetch failed */
+ return sc->sc_msgwaiting != 1 ? EIO : 0;
+}
+
+/*
+ * Send a msg to the NPE and wait for a reply. We use the
+ * private mutex and sleep until an interrupt is received
+ * signalling the availability of data in the output FIFO
+ * so the caller cannot be holding a mutex. May be better
+ * piggyback on the caller's mutex instead but that would
+ * make other locking confusing.
+ */
+int
+ixpnpe_sendandrecvmsg(struct ixpnpe_softc *sc,
+ const uint32_t send[2], uint32_t recv[2])
+{
+ int error;
+
+ mtx_lock(&sc->sc_mtx);
+ error = ixpnpe_sendmsg_locked(sc, send);
+ if (error == 0)
+ error = ixpnpe_recvmsg_locked(sc, recv);
+ mtx_unlock(&sc->sc_mtx);
+
+ return error;
+}
+
+/* XXX temporary, not reliable */
+
+int
+ixpnpe_sendmsg(struct ixpnpe_softc *sc, const uint32_t msg[2])
+{
+ int error;
+
+ mtx_lock(&sc->sc_mtx);
+ error = ixpnpe_sendmsg_locked(sc, msg);
+ mtx_unlock(&sc->sc_mtx);
+
+ return error;
+}
+
+int
+ixpnpe_recvmsg(struct ixpnpe_softc *sc, uint32_t msg[2])
+{
+ int error;
+
+ mtx_lock(&sc->sc_mtx);
+ if (sc->sc_msgwaiting)
+ bcopy(sc->sc_msg, msg, sizeof(sc->sc_msg));
+ /* NB: sc_msgwaiting != 1 means the ack fetch failed */
+ error = sc->sc_msgwaiting != 1 ? EIO : 0;
+ mtx_unlock(&sc->sc_mtx);
+
+ return error;
+}
diff --git a/sys/arm/xscale/ixp425/ixp425_npereg.h b/sys/arm/xscale/ixp425/ixp425_npereg.h
new file mode 100644
index 000000000000..b3e684cbbe08
--- /dev/null
+++ b/sys/arm/xscale/ixp425/ixp425_npereg.h
@@ -0,0 +1,434 @@
+/*-
+ * Copyright (c) 2006 Sam Leffler, Errno Consulting
+ * 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,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ * redistribution must be conditioned upon including a substantially
+ * similar Disclaimer requirement for further binary redistribution.
+ *
+ * NO WARRANTY
+ * 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 NONINFRINGEMENT, MERCHANTIBILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ *
+ * $FreeBSD$
+ */
+
+/*-
+ * Copyright (c) 2001-2005, Intel Corporation.
+ * 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 Intel Corporation nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ *
+ * 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 _IXP425_NPEREG_H_
+#define _IXP425_NPEREG_H_
+
+/* signature found as 1st word in a microcode image library */
+#define IX_NPEDL_IMAGEMGR_SIGNATURE 0xDEADBEEF
+/* marks end of header in a microcode image library */
+#define IX_NPEDL_IMAGEMGR_END_OF_HEADER 0xFFFFFFFF
+
+/*
+ * Intel (R) IXP400 Software NPE Image ID Definition
+ *
+ * Definition of NPE Image ID to be passed to ixNpeDlNpeInitAndStart()
+ * as input of type uint32_t which has the following fields format:
+ *
+ * Field [Bit Location]
+ * -----------------------------------
+ * Device ID [31 - 28]
+ * NPE ID [27 - 24]
+ * NPE Functionality ID [23 - 16]
+ * Major Release Number [15 - 8]
+ * Minor Release Number [7 - 0]
+ */
+#define IX_NPEDL_NPEID_FROM_IMAGEID_GET(imageId) \
+ (((imageId) >> 24) & 0xf)
+#define IX_NPEDL_DEVICEID_FROM_IMAGEID_GET(imageId) \
+ (((imageId) >> 28) & 0xf)
+#define IX_NPEDL_FUNCTIONID_FROM_IMAGEID_GET(imageId) \
+ (((imageId) >> 16) & 0xff)
+#define IX_NPEDL_MAJOR_FROM_IMAGEID_GET(imageId) \
+ (((imageId) >> 8) & 0xff)
+#define IX_NPEDL_MINOR_FROM_IMAGEID_GET(imageId) \
+ (((imageId) >> 0) & 0xff)
+
+/*
+ * Instruction and Data Memory Size (in words) for each NPE
+ */
+#ifndef __ixp46X
+#define IX_NPEDL_INS_MEMSIZE_WORDS_NPEA 4096
+#define IX_NPEDL_INS_MEMSIZE_WORDS_NPEB 2048
+#define IX_NPEDL_INS_MEMSIZE_WORDS_NPEC 2048
+
+#define IX_NPEDL_DATA_MEMSIZE_WORDS_NPEA 2048
+#define IX_NPEDL_DATA_MEMSIZE_WORDS_NPEB 2048
+#define IX_NPEDL_DATA_MEMSIZE_WORDS_NPEC 2048
+#else
+#define IX_NPEDL_INS_MEMSIZE_WORDS_NPEA 4096
+#define IX_NPEDL_INS_MEMSIZE_WORDS_NPEB 4096
+#define IX_NPEDL_INS_MEMSIZE_WORDS_NPEC 4096
+
+#define IX_NPEDL_DATA_MEMSIZE_WORDS_NPEA 4096
+#define IX_NPEDL_DATA_MEMSIZE_WORDS_NPEB 4096
+#define IX_NPEDL_DATA_MEMSIZE_WORDS_NPEC 4096
+#endif
+
+/* BAR offsets */
+#define IX_NPEDL_REG_OFFSET_EXAD 0x00000000 /* Execution Address */
+#define IX_NPEDL_REG_OFFSET_EXDATA 0x00000004 /* Execution Data */
+#define IX_NPEDL_REG_OFFSET_EXCTL 0x00000008 /* Execution Control */
+#define IX_NPEDL_REG_OFFSET_EXCT 0x0000000C /* Execution Count */
+#define IX_NPEDL_REG_OFFSET_AP0 0x00000010 /* Action Point 0 */
+#define IX_NPEDL_REG_OFFSET_AP1 0x00000014 /* Action Point 1 */
+#define IX_NPEDL_REG_OFFSET_AP2 0x00000018 /* Action Point 2 */
+#define IX_NPEDL_REG_OFFSET_AP3 0x0000001C /* Action Point 3 */
+#define IX_NPEDL_REG_OFFSET_WFIFO 0x00000020 /* Watchpoint FIFO */
+#define IX_NPEDL_REG_OFFSET_WC 0x00000024 /* Watch Count */
+#define IX_NPEDL_REG_OFFSET_PROFCT 0x00000028 /* Profile Count */
+#define IX_NPEDL_REG_OFFSET_STAT 0x0000002C /* Messaging Status */
+#define IX_NPEDL_REG_OFFSET_CTL 0x00000030 /* Messaging Control */
+#define IX_NPEDL_REG_OFFSET_MBST 0x00000034 /* Mailbox Status */
+#define IX_NPEDL_REG_OFFSET_FIFO 0x00000038 /* Message FIFO */
+
+/*
+ * Reset value for Mailbox (MBST) register
+ * NOTE that if used, it should be complemented with an NPE intruction
+ * to clear the Mailbox at the NPE side as well
+ */
+#define IX_NPEDL_REG_RESET_MBST 0x0000F0F0
+
+#define IX_NPEDL_MASK_WFIFO_VALID 0x80000000 /* VALID bit */
+#define IX_NPEDL_MASK_STAT_OFNE 0x00010000 /* OFNE bit */
+#define IX_NPEDL_MASK_STAT_IFNE 0x00080000 /* IFNE bit */
+
+/*
+ * EXCTL (Execution Control) Register commands
+*/
+#define IX_NPEDL_EXCTL_CMD_NPE_STEP 0x01 /* Step 1 instruction */
+#define IX_NPEDL_EXCTL_CMD_NPE_START 0x02 /* Start execution */
+#define IX_NPEDL_EXCTL_CMD_NPE_STOP 0x03 /* Stop execution */
+#define IX_NPEDL_EXCTL_CMD_NPE_CLR_PIPE 0x04 /* Clear ins pipeline */
+
+/*
+ * Read/write operations use address in EXAD and data in EXDATA.
+ */
+#define IX_NPEDL_EXCTL_CMD_RD_INS_MEM 0x10 /* Read ins memory */
+#define IX_NPEDL_EXCTL_CMD_WR_INS_MEM 0x11 /* Write ins memory */
+#define IX_NPEDL_EXCTL_CMD_RD_DATA_MEM 0x12 /* Read data memory */
+#define IX_NPEDL_EXCTL_CMD_WR_DATA_MEM 0x13 /* Write data memory */
+#define IX_NPEDL_EXCTL_CMD_RD_ECS_REG 0x14 /* Read ECS register */
+#define IX_NPEDL_EXCTL_CMD_WR_ECS_REG 0x15 /* Write ECS register */
+
+#define IX_NPEDL_EXCTL_CMD_CLR_PROFILE_CNT 0x0C /* Clear Profile Count register */
+
+
+/*
+ * EXCTL (Execution Control) Register status bit masks
+ */
+#define IX_NPEDL_EXCTL_STATUS_RUN 0x80000000
+#define IX_NPEDL_EXCTL_STATUS_STOP 0x40000000
+#define IX_NPEDL_EXCTL_STATUS_CLEAR 0x20000000
+#define IX_NPEDL_EXCTL_STATUS_ECS_K 0x00800000 /* pipeline Klean */
+
+/*
+ * Executing Context Stack (ECS) level registers
+ */
+#define IX_NPEDL_ECS_BG_CTXT_REG_0 0x00 /* reg 0 @ bg ctx */
+#define IX_NPEDL_ECS_BG_CTXT_REG_1 0x01 /* reg 1 @ bg ctx */
+#define IX_NPEDL_ECS_BG_CTXT_REG_2 0x02 /* reg 2 @ bg ctx */
+
+#define IX_NPEDL_ECS_PRI_1_CTXT_REG_0 0x04 /* reg 0 @ pri 1 ctx */
+#define IX_NPEDL_ECS_PRI_1_CTXT_REG_1 0x05 /* reg 1 @ pri 1 ctx */
+#define IX_NPEDL_ECS_PRI_1_CTXT_REG_2 0x06 /* reg 2 @ pri 1 ctx */
+
+#define IX_NPEDL_ECS_PRI_2_CTXT_REG_0 0x08 /* reg 0 @ pri 2 ctx */
+#define IX_NPEDL_ECS_PRI_2_CTXT_REG_1 0x09 /* reg 1 @ pri 2 ctx */
+#define IX_NPEDL_ECS_PRI_2_CTXT_REG_2 0x0A /* reg 2 @ pri 2 ctx */
+
+#define IX_NPEDL_ECS_DBG_CTXT_REG_0 0x0C /* reg 0 @ debug ctx */
+#define IX_NPEDL_ECS_DBG_CTXT_REG_1 0x0D /* reg 1 @ debug ctx */
+#define IX_NPEDL_ECS_DBG_CTXT_REG_2 0x0E /* reg 2 @ debug ctx */
+
+#define IX_NPEDL_ECS_INSTRUCT_REG 0x11 /* Instruction reg */
+
+/*
+ * Execution Access register reset values
+ */
+#define IX_NPEDL_ECS_BG_CTXT_REG_0_RESET 0xA0000000
+#define IX_NPEDL_ECS_BG_CTXT_REG_1_RESET 0x01000000
+#define IX_NPEDL_ECS_BG_CTXT_REG_2_RESET 0x00008000
+#define IX_NPEDL_ECS_PRI_1_CTXT_REG_0_RESET 0x20000080
+#define IX_NPEDL_ECS_PRI_1_CTXT_REG_1_RESET 0x01000000
+#define IX_NPEDL_ECS_PRI_1_CTXT_REG_2_RESET 0x00008000
+#define IX_NPEDL_ECS_PRI_2_CTXT_REG_0_RESET 0x20000080
+#define IX_NPEDL_ECS_PRI_2_CTXT_REG_1_RESET 0x01000000
+#define IX_NPEDL_ECS_PRI_2_CTXT_REG_2_RESET 0x00008000
+#define IX_NPEDL_ECS_DBG_CTXT_REG_0_RESET 0x20000000
+#define IX_NPEDL_ECS_DBG_CTXT_REG_1_RESET 0x00000000
+#define IX_NPEDL_ECS_DBG_CTXT_REG_2_RESET 0x001E0000
+#define IX_NPEDL_ECS_INSTRUCT_REG_RESET 0x1003C00F
+
+/*
+ * Masks used to read/write particular bits in Execution Access registers
+ */
+
+#define IX_NPEDL_MASK_ECS_REG_0_ACTIVE 0x80000000 /* Active bit */
+#define IX_NPEDL_MASK_ECS_REG_0_NEXTPC 0x1FFF0000 /* NextPC bits */
+#define IX_NPEDL_MASK_ECS_REG_0_LDUR 0x00000700 /* LDUR bits */
+
+#define IX_NPEDL_MASK_ECS_REG_1_CCTXT 0x000F0000 /* NextPC bits */
+#define IX_NPEDL_MASK_ECS_REG_1_SELCTXT 0x0000000F
+
+#define IX_NPEDL_MASK_ECS_DBG_REG_2_IF 0x00100000 /* IF bit */
+#define IX_NPEDL_MASK_ECS_DBG_REG_2_IE 0x00080000 /* IE bit */
+
+
+/*
+ * Bit-Offsets from LSB of particular bit-fields in Execution Access registers.
+ */
+
+#define IX_NPEDL_OFFSET_ECS_REG_0_NEXTPC 16
+#define IX_NPEDL_OFFSET_ECS_REG_0_LDUR 8
+
+#define IX_NPEDL_OFFSET_ECS_REG_1_CCTXT 16
+#define IX_NPEDL_OFFSET_ECS_REG_1_SELCTXT 0
+
+/*
+ * NPE core & co-processor instruction templates to load into NPE Instruction
+ * Register, for read/write of NPE register file registers.
+ */
+
+/*
+ * Read an 8-bit NPE internal logical register
+ * and return the value in the EXDATA register (aligned to MSB).
+ * NPE Assembler instruction: "mov8 d0, d0 &&& DBG_WrExec"
+ */
+#define IX_NPEDL_INSTR_RD_REG_BYTE 0x0FC00000
+
+/*
+ * Read a 16-bit NPE internal logical register
+ * and return the value in the EXDATA register (aligned to MSB).
+ * NPE Assembler instruction: "mov16 d0, d0 &&& DBG_WrExec"
+ */
+#define IX_NPEDL_INSTR_RD_REG_SHORT 0x0FC08010
+
+/*
+ * Read a 16-bit NPE internal logical register
+ * and return the value in the EXDATA register.
+ * NPE Assembler instruction: "mov32 d0, d0 &&& DBG_WrExec"
+ */
+#define IX_NPEDL_INSTR_RD_REG_WORD 0x0FC08210
+
+/*
+ * Write an 8-bit NPE internal logical register.
+ * NPE Assembler instruction: "mov8 d0, #0"
+ */
+#define IX_NPEDL_INSTR_WR_REG_BYTE 0x00004000
+
+/*
+ * Write a 16-bit NPE internal logical register.
+ * NPE Assembler instruction: "mov16 d0, #0"
+ */
+#define IX_NPEDL_INSTR_WR_REG_SHORT 0x0000C000
+
+/*
+ * Write a 16-bit NPE internal logical register.
+ * NPE Assembler instruction: "cprd32 d0 &&& DBG_RdInFIFO"
+ */
+#define IX_NPEDL_INSTR_RD_FIFO 0x0F888220
+
+/*
+ * Reset Mailbox (MBST) register
+ * NPE Assembler instruction: "mov32 d0, d0 &&& DBG_ClearM"
+ */
+#define IX_NPEDL_INSTR_RESET_MBOX 0x0FAC8210
+
+
+/*
+ * Bit-offsets from LSB, of particular bit-fields in an NPE instruction
+ */
+#define IX_NPEDL_OFFSET_INSTR_SRC 4 /* src operand */
+#define IX_NPEDL_OFFSET_INSTR_DEST 9 /* dest operand */
+#define IX_NPEDL_OFFSET_INSTR_COPROC 18 /* coprocessor ins */
+
+/*
+ * Masks used to read/write particular bits of an NPE Instruction
+ */
+
+/**
+ * Mask the bits of 16-bit data value (least-sig 5 bits) to be used in
+ * SRC field of immediate-mode NPE instruction
+ */
+#define IX_NPEDL_MASK_IMMED_INSTR_SRC_DATA 0x1F
+
+/**
+ * Mask the bits of 16-bit data value (most-sig 11 bits) to be used in
+ * COPROC field of immediate-mode NPE instruction
+ */
+#define IX_NPEDL_MASK_IMMED_INSTR_COPROC_DATA 0xFFE0
+
+/**
+ * LSB offset of the bit-field of 16-bit data value (most-sig 11 bits)
+ * to be used in COPROC field of immediate-mode NPE instruction
+ */
+#define IX_NPEDL_OFFSET_IMMED_INSTR_COPROC_DATA 5
+
+/**
+ * Number of left-shifts required to align most-sig 11 bits of 16-bit
+ * data value into COPROC field of immediate-mode NPE instruction
+ */
+#define IX_NPEDL_DISPLACE_IMMED_INSTR_COPROC_DATA \
+ (IX_NPEDL_OFFSET_INSTR_COPROC - IX_NPEDL_OFFSET_IMMED_INSTR_COPROC_DATA)
+
+/**
+ * LDUR value used with immediate-mode NPE Instructions by the NpeDl
+ * for writing to NPE internal logical registers
+ */
+#define IX_NPEDL_WR_INSTR_LDUR 1
+
+/**
+ * LDUR value used with NON-immediate-mode NPE Instructions by the NpeDl
+ * for reading from NPE internal logical registers
+ */
+#define IX_NPEDL_RD_INSTR_LDUR 0
+
+
+/**
+ * NPE internal Context Store registers.
+ */
+typedef enum
+{
+ IX_NPEDL_CTXT_REG_STEVT = 0, /**< identifies STEVT */
+ IX_NPEDL_CTXT_REG_STARTPC, /**< identifies STARTPC */
+ IX_NPEDL_CTXT_REG_REGMAP, /**< identifies REGMAP */
+ IX_NPEDL_CTXT_REG_CINDEX, /**< identifies CINDEX */
+ IX_NPEDL_CTXT_REG_MAX /**< Total number of Context Store registers */
+} IxNpeDlCtxtRegNum;
+
+
+/*
+ * NPE Context Store register logical addresses
+ */
+#define IX_NPEDL_CTXT_REG_ADDR_STEVT 0x0000001B
+#define IX_NPEDL_CTXT_REG_ADDR_STARTPC 0x0000001C
+#define IX_NPEDL_CTXT_REG_ADDR_REGMAP 0x0000001E
+#define IX_NPEDL_CTXT_REG_ADDR_CINDEX 0x0000001F
+
+/*
+ * NPE Context Store register reset values
+ */
+
+/**
+ * Reset value of STEVT NPE internal Context Store register
+ * (STEVT = off, 0x80)
+ */
+#define IX_NPEDL_CTXT_REG_RESET_STEVT 0x80
+
+/**
+ * Reset value of STARTPC NPE internal Context Store register
+ * (STARTPC = 0x0000)
+ */
+#define IX_NPEDL_CTXT_REG_RESET_STARTPC 0x0000
+
+/**
+ * Reset value of REGMAP NPE internal Context Store register
+ * (REGMAP = d0->p0, d8->p2, d16->p4)
+ */
+#define IX_NPEDL_CTXT_REG_RESET_REGMAP 0x0820
+
+/**
+ * Reset value of CINDEX NPE internal Context Store register
+ * (CINDEX = 0)
+ */
+#define IX_NPEDL_CTXT_REG_RESET_CINDEX 0x00
+
+
+/*
+ * Numeric range of context levels available on an NPE
+ */
+#define IX_NPEDL_CTXT_NUM_MIN 0
+#define IX_NPEDL_CTXT_NUM_MAX 15
+
+
+/**
+ * Number of Physical registers currently supported
+ * Initial NPE implementations will have a 32-word register file.
+ * Later implementations may have a 64-word register file.
+ */
+#define IX_NPEDL_TOTAL_NUM_PHYS_REG 32
+
+/**
+ * LSB-offset of Regmap number in Physical NPE register address, used
+ * for Physical To Logical register address mapping in the NPE
+ */
+#define IX_NPEDL_OFFSET_PHYS_REG_ADDR_REGMAP 1
+
+/**
+ * Mask to extract a logical NPE register address from a physical
+ * register address, used for Physical To Logical address mapping
+ */
+#define IX_NPEDL_MASK_PHYS_REG_ADDR_LOGICAL_ADDR 0x1
+
+/*
+ * NPE Message/Mailbox interface.
+ */
+#define IX_NPESTAT IX_NPEDL_REG_OFFSET_STAT /* status register */
+#define IX_NPECTL IX_NPEDL_REG_OFFSET_CTL /* control register */
+#define IX_NPEFIFO IX_NPEDL_REG_OFFSET_FIFO /* FIFO register */
+
+/* control register */
+#define IX_NPECTL_OFE 0x00010000 /* output fifo enable */
+#define IX_NPECTL_IFE 0x00020000 /* input fifo enable */
+#define IX_NPECTL_OFWE 0x01000000 /* output fifo write enable */
+#define IX_NPECTL_IFWE 0x02000000 /* input fifo write enable */
+
+/* status register */
+#define IX_NPESTAT_OFNE 0x00010000 /* output fifo not empty */
+#define IX_NPESTAT_IFNF 0x00020000 /* input fifo not full */
+#define IX_NPESTAT_OFNF 0x00040000 /* output fifo not full */
+#define IX_NPESTAT_IFNE 0x00080000 /* input fifo not empty */
+#define IX_NPESTAT_MBINT 0x00100000 /* Mailbox interrupt */
+#define IX_NPESTAT_IFINT 0x00200000 /* input fifo interrupt */
+#define IX_NPESTAT_OFINT 0x00400000 /* output fifo interrupt */
+#define IX_NPESTAT_WFINT 0x00800000 /* watch fifo interrupt */
+#endif /* _IXP425_NPEREG_H_ */
diff --git a/sys/arm/xscale/ixp425/ixp425_npevar.h b/sys/arm/xscale/ixp425/ixp425_npevar.h
new file mode 100644
index 000000000000..c30ff5f55117
--- /dev/null
+++ b/sys/arm/xscale/ixp425/ixp425_npevar.h
@@ -0,0 +1,96 @@
+/*-
+ * Copyright (c) 2006 Sam Leffler. 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _IXP425_NPEVAR_H_
+#define _IXP425_NPEVAR_H_
+
+/*
+ * Intel (R) IXP400 Software NPE Image ID Definition
+ *
+ * Firmware Id's for current firmware image. These are typed by
+ * NPE ID and the feature set. Not all features are available
+ * on all NPE's.
+ *
+ * HSS-0: supports 32 channelized and 4 packetized.
+ * HSS-0 + ATM + SPHY:
+ * For HSS, 16/32 channelized and 4/0 packetized.
+ * For ATM, AAL5, AAL0 and OAM for UTOPIA SPHY, 1 logical port, 32 VCs.
+ * Fast Path support.
+ * HSS-0 + ATM + MPHY:
+ * For HSS, 16/32 channelized and 4/0 packetized.
+ * For ATM, AAL5, AAL0 and OAM for UTOPIA MPHY, 1 logical port, 32 VCs.
+ * Fast Path support.
+ * ATM-Only:
+ * AAL5, AAL0 and OAM for UTOPIA MPHY, 12 logical ports, 32 VCs.
+ * Fast Path support.
+ * HSS-2:
+ * HSS-0 and HSS-1.
+ * Each HSS port supports 32 channelized and 4 packetized.
+ * ETH: Ethernet Rx/Tx which includes:
+ * MAC_FILTERING, MAC_LEARNING, SPANNING_TREE, FIREWALL
+ * ETH+VLAN Ethernet Rx/Tx which includes:
+ * MAC_FILTERING, MAC_LEARNING, SPANNING_TREE, FIREWALL, VLAN_QOS
+ * ETH+VLAN+HDR: Ethernet Rx/Tx which includes:
+ * SPANNING_TREE, FIREWALL, VLAN_QOS, HEADER_CONVERSION
+ */
+/* XXX not right, revise */
+/* NPE A Firmware Image Id's */
+#define NPEFW_A_HSS0 0x00010000 /* HSS-0: 32 chan+4 packet */
+#define NPEFW_A_HSS0_ATM_S_1 0x00020000 /* HSS-0+ATM UTOPIA SPHY (1 port) */
+#define NPEFW_A_HSS0_ATM_M_1 0x00020000 /* HSS-0+ATM UTOPIA MPHY (1 port) */
+#define NPEFW_A_ATM_M_12 0x00040000 /* ATM UTOPIA MPHY (12 ports) */
+#define NPEFW_A_DMA 0x00150100 /* DMA only */
+#define NPEFW_A_HSS2 0x00090000 /* HSS-0 + HSS-1 */
+#define NPEFW_A_ETH 0x10800200 /* Basic Ethernet */
+#define NPEFW_A_ETH_VLAN 0x10810200 /* NPEFW_A_ETH + VLAN QoS */
+#define NPEFW_A_ETH_VLAN_HDR 0x10820200 /* NPEFW_A_ETH_VLAN + Hdr conv */
+/* XXX ... more not included */
+
+/* NPE B Firmware Image Id's */
+#define NPEFW_B_ETH 0x01000200 /* Basic Ethernet */
+#define NPEFW_B_ETH_VLAN 0x01010200 /* NPEFW_B_ETH + VLAN QoS */
+#define NPEFW_B_ETH_VLAN_HDR 0x01020201 /* NPEFW_B_ETH_VLAN + Hdr conv */
+#define NPEFW_B_DMA 0x01020100 /* DMA only */
+/* XXX ... more not include */
+
+#define IXP425_NPE_B_IMAGEID 0x01000200
+#define IXP425_NPE_C_IMAGEID 0x02000200
+
+struct ixpnpe_softc;
+struct ixpnpe_softc *ixpnpe_attach(device_t);
+void ixpnpe_detach(struct ixpnpe_softc *);
+int ixpnpe_stopandreset(struct ixpnpe_softc *);
+int ixpnpe_start(struct ixpnpe_softc *);
+int ixpnpe_stop(struct ixpnpe_softc *);
+int ixpnpe_init(struct ixpnpe_softc *,
+ const char *imageName, uint32_t imageId);
+int ixpnpe_getfunctionality(struct ixpnpe_softc *sc);
+
+int ixpnpe_sendmsg(struct ixpnpe_softc *, const uint32_t msg[2]);
+int ixpnpe_recvmsg(struct ixpnpe_softc *, uint32_t msg[2]);
+int ixpnpe_sendandrecvmsg(struct ixpnpe_softc *, const uint32_t send[2],
+ uint32_t recv[2]);
+#endif /* _IXP425_NPEVAR_H_ */
diff --git a/sys/arm/xscale/ixp425/ixp425_pci.c b/sys/arm/xscale/ixp425/ixp425_pci.c
new file mode 100644
index 000000000000..adb9b16d93eb
--- /dev/null
+++ b/sys/arm/xscale/ixp425/ixp425_pci.c
@@ -0,0 +1,455 @@
+/* $NetBSD: ixp425_pci.c,v 1.5 2006/04/10 03:36:03 simonb Exp $ */
+
+/*
+ * Copyright (c) 2003
+ * Ichiro FUKUHARA <ichiro@ichiro.org>.
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ichiro FUKUHARA.
+ * 4. The name of the company nor the name of the author may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ICHIRO FUKUHARA ``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 ICHIRO FUKUHARA OR THE VOICES IN HIS HEAD BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/rman.h>
+
+#include <machine/bus.h>
+#include <machine/cpu.h>
+#include <machine/pcb.h>
+#include <vm/vm.h>
+#include <vm/pmap.h>
+#include <vm/vm_extern.h>
+#include <machine/pmap.h>
+
+#include <arm/xscale/ixp425/ixp425reg.h>
+#include <arm/xscale/ixp425/ixp425var.h>
+
+#include <dev/pci/pcib_private.h>
+#include "pcib_if.h"
+
+#include <dev/pci/pcireg.h>
+extern struct ixp425_softc *ixp425_softc;
+
+#define PCI_CSR_WRITE_4(sc, reg, data) \
+ bus_write_4(sc->sc_csr, reg, data)
+
+#define PCI_CSR_READ_4(sc, reg) \
+ bus_read_4(sc->sc_csr, reg)
+
+#define PCI_CONF_LOCK(s) (s) = disable_interrupts(I32_bit)
+#define PCI_CONF_UNLOCK(s) restore_interrupts((s))
+
+static device_probe_t ixppcib_probe;
+static device_attach_t ixppcib_attach;
+static bus_read_ivar_t ixppcib_read_ivar;
+static bus_write_ivar_t ixppcib_write_ivar;
+static bus_setup_intr_t ixppcib_setup_intr;
+static bus_teardown_intr_t ixppcib_teardown_intr;
+static bus_alloc_resource_t ixppcib_alloc_resource;
+static bus_activate_resource_t ixppcib_activate_resource;
+static bus_deactivate_resource_t ixppcib_deactivate_resource;
+static bus_release_resource_t ixppcib_release_resource;
+static pcib_maxslots_t ixppcib_maxslots;
+static pcib_read_config_t ixppcib_read_config;
+static pcib_write_config_t ixppcib_write_config;
+static pcib_route_interrupt_t ixppcib_route_interrupt;
+
+static int
+ixppcib_probe(device_t dev)
+{
+
+ device_set_desc(dev, "IXP425 PCI Bus");
+ return (0);
+}
+
+static void
+ixp425_pci_conf_reg_write(struct ixppcib_softc *sc, uint32_t reg,
+ uint32_t data)
+{
+ PCI_CSR_WRITE_4(sc,
+ PCI_CRP_AD_CBE, ((reg & ~3) | COMMAND_CRP_WRITE));
+ PCI_CSR_WRITE_4(sc,
+ PCI_CRP_AD_WDATA, data);
+}
+
+static int
+ixppcib_attach(device_t dev)
+{
+ int rid;
+ struct ixppcib_softc *sc;
+
+ sc = device_get_softc(dev);
+
+ rid = 0;
+ sc->sc_csr = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid,
+ IXP425_PCI_HWBASE, IXP425_PCI_HWBASE + IXP425_PCI_SIZE,
+ IXP425_PCI_SIZE, RF_ACTIVE);
+ if (sc->sc_csr == NULL)
+ panic("cannot allocate PCI CSR registers");
+
+ ixp425_md_attach(dev);
+ /* always setup the base, incase another OS messes w/ it */
+ PCI_CSR_WRITE_4(sc, PCI_PCIMEMBASE, 0x48494a4b);
+
+ rid = 0;
+ sc->sc_mem = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid,
+ IXP425_PCI_MEM_HWBASE, IXP425_PCI_MEM_HWBASE + IXP425_PCI_MEM_SIZE,
+ IXP425_PCI_MEM_SIZE, RF_ACTIVE);
+ if (sc->sc_mem == NULL)
+ panic("cannot allocate PCI MEM space");
+
+ /*
+ * Initialize the bus space tags.
+ */
+ ixp425_io_bs_init(&sc->sc_pci_iot, sc);
+ ixp425_mem_bs_init(&sc->sc_pci_memt, sc);
+
+ sc->sc_dev = dev;
+
+ /* Initialize memory and i/o rmans. */
+ sc->sc_io_rman.rm_type = RMAN_ARRAY;
+ sc->sc_io_rman.rm_descr = "IXP425 PCI I/O Ports";
+ if (rman_init(&sc->sc_io_rman) != 0 ||
+ rman_manage_region(&sc->sc_io_rman, 0,
+ IXP425_PCI_IO_SIZE) != 0) {
+ panic("ixppcib_probe: failed to set up I/O rman");
+ }
+
+ sc->sc_mem_rman.rm_type = RMAN_ARRAY;
+ sc->sc_mem_rman.rm_descr = "IXP425 PCI Memory";
+ if (rman_init(&sc->sc_mem_rman) != 0 ||
+ rman_manage_region(&sc->sc_mem_rman, IXP425_PCI_MEM_HWBASE,
+ IXP425_PCI_MEM_HWBASE + IXP425_PCI_MEM_SIZE) != 0) {
+ panic("ixppcib_probe: failed to set up memory rman");
+ }
+
+ /*
+ * PCI->AHB address translation
+ * begin at the physical memory start + OFFSET
+ */
+#define AHB_OFFSET 0x10000000UL
+ PCI_CSR_WRITE_4(sc, PCI_AHBMEMBASE,
+ (AHB_OFFSET & 0xFF000000) +
+ ((AHB_OFFSET & 0xFF000000) >> 8) +
+ ((AHB_OFFSET & 0xFF000000) >> 16) +
+ ((AHB_OFFSET & 0xFF000000) >> 24) +
+ 0x00010203);
+
+#define IXPPCIB_WRITE_CONF(sc, reg, val) \
+ ixp425_pci_conf_reg_write(sc, reg, val)
+ /* Write Mapping registers PCI Configuration Registers */
+ /* Base Address 0 - 3 */
+ IXPPCIB_WRITE_CONF(sc, PCI_MAPREG_BAR0, AHB_OFFSET + 0x00000000);
+ IXPPCIB_WRITE_CONF(sc, PCI_MAPREG_BAR1, AHB_OFFSET + 0x01000000);
+ IXPPCIB_WRITE_CONF(sc, PCI_MAPREG_BAR2, AHB_OFFSET + 0x02000000);
+ IXPPCIB_WRITE_CONF(sc, PCI_MAPREG_BAR3, AHB_OFFSET + 0x03000000);
+
+ /* Base Address 4 */
+ IXPPCIB_WRITE_CONF(sc, PCI_MAPREG_BAR4, 0xffffffff);
+
+ /* Base Address 5 */
+ IXPPCIB_WRITE_CONF(sc, PCI_MAPREG_BAR5, 0x00000000);
+
+ /* Assert some PCI errors */
+ PCI_CSR_WRITE_4(sc, PCI_ISR, ISR_AHBE | ISR_PPE | ISR_PFE | ISR_PSE);
+
+#ifdef __ARMEB__
+ /*
+ * Set up byte lane swapping between little-endian PCI
+ * and the big-endian AHB bus
+ */
+ PCI_CSR_WRITE_4(sc, PCI_CSR, CSR_IC | CSR_ABE | CSR_PDS);
+#else
+ PCI_CSR_WRITE_4(sc, PCI_CSR, CSR_IC | CSR_ABE);
+#endif
+
+ /*
+ * Enable bus mastering and I/O,memory access
+ */
+ IXPPCIB_WRITE_CONF(sc, PCIR_COMMAND,
+ PCIM_CMD_MEMEN | PCIM_CMD_BUSMASTEREN);
+
+ /*
+ * Wait some more to ensure PCI devices have stabilised.
+ */
+ DELAY(50000);
+
+ device_add_child(dev, "pci", -1);
+ return (bus_generic_attach(dev));
+}
+
+static int
+ixppcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
+{
+ struct ixppcib_softc *sc;
+
+ sc = device_get_softc(dev);
+ switch (which) {
+ case PCIB_IVAR_BUS:
+ *result = sc->sc_bus;
+ return (0);
+ }
+
+ return (ENOENT);
+}
+
+static int
+ixppcib_write_ivar(device_t dev, device_t child, int which, uintptr_t value)
+{
+ struct ixppcib_softc *sc;
+
+ sc = device_get_softc(dev);
+ switch (which) {
+ case PCIB_IVAR_BUS:
+ sc->sc_bus = value;
+ return (0);
+ }
+
+ return (ENOENT);
+}
+
+static int
+ixppcib_setup_intr(device_t dev, device_t child, struct resource *ires,
+ int flags, driver_intr_t *intr, void *arg, void **cookiep)
+{
+
+ return (BUS_SETUP_INTR(device_get_parent(dev), child, ires, flags,
+ intr, arg, cookiep));
+}
+
+static int
+ixppcib_teardown_intr(device_t dev, device_t child, struct resource *vec,
+ void *cookie)
+{
+
+ return (BUS_TEARDOWN_INTR(device_get_parent(dev), child, vec, cookie));
+}
+
+static struct resource *
+ixppcib_alloc_resource(device_t bus, device_t child, int type, int *rid,
+ u_long start, u_long end, u_long count, u_int flags)
+{
+ bus_space_tag_t tag;
+ struct ixppcib_softc *sc = device_get_softc(bus);
+ struct rman *rmanp;
+ struct resource *rv;
+
+ tag = NULL; /* shut up stupid gcc */
+ rv = NULL;
+ switch (type) {
+ case SYS_RES_IRQ:
+ rmanp = &sc->sc_irq_rman;
+ break;
+
+ case SYS_RES_IOPORT:
+ rmanp = &sc->sc_io_rman;
+ tag = &sc->sc_pci_iot;
+ break;
+
+ case SYS_RES_MEMORY:
+ rmanp = &sc->sc_mem_rman;
+ tag = &sc->sc_pci_memt;
+ break;
+
+ default:
+ return (rv);
+ }
+
+ rv = rman_reserve_resource(rmanp, start, end, count, flags, child);
+ if (rv != NULL) {
+ rman_set_rid(rv, *rid);
+ if (type == SYS_RES_IOPORT) {
+ rman_set_bustag(rv, tag);
+ rman_set_bushandle(rv, rman_get_start(rv));
+ } else if (type == SYS_RES_MEMORY) {
+ rman_set_bustag(rv, tag);
+ rman_set_bushandle(rv, rman_get_bushandle(sc->sc_mem) +
+ (rman_get_start(rv) - IXP425_PCI_MEM_HWBASE));
+ }
+ }
+
+ return (rv);
+}
+
+static int
+ixppcib_activate_resource(device_t bus, device_t child, int type, int rid,
+ struct resource *r)
+{
+
+ device_printf(bus, "%s called activate_resource\n", device_get_nameunit(child));
+ return (ENXIO);
+}
+
+static int
+ixppcib_deactivate_resource(device_t bus, device_t child, int type, int rid,
+ struct resource *r)
+{
+
+ device_printf(bus, "%s called deactivate_resource\n", device_get_nameunit(child));
+ return (ENXIO);
+}
+
+static int
+ixppcib_release_resource(device_t bus, device_t child, int type, int rid,
+ struct resource *r)
+{
+
+ device_printf(bus, "%s called release_resource\n", device_get_nameunit(child));
+ return (ENXIO);
+}
+
+static void
+ixppcib_conf_setup(struct ixppcib_softc *sc, int bus, int slot, int func,
+ int reg)
+{
+ if (bus == 0) {
+ if (slot == 0 && func == 0) {
+ PCI_CSR_WRITE_4(sc, PCI_NP_AD, (reg & ~3));
+ } else {
+ bus &= 0xff;
+ slot &= 0x1f;
+ func &= 0x07;
+ /* configuration type 0 */
+ PCI_CSR_WRITE_4(sc, PCI_NP_AD, (1U << (32 - slot)) |
+ (func << 8) | (reg & ~3));
+ }
+ } else {
+ /* configuration type 1 */
+ PCI_CSR_WRITE_4(sc, PCI_NP_AD,
+ (bus << 16) | (slot << 11) |
+ (func << 8) | (reg & ~3) | 1);
+ }
+
+}
+
+static int
+ixppcib_maxslots(device_t dev)
+{
+
+ return (PCI_SLOTMAX);
+}
+
+static u_int32_t
+ixppcib_read_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg,
+ int bytes)
+{
+ struct ixppcib_softc *sc = device_get_softc(dev);
+ u_int32_t data, ret;
+
+ ixppcib_conf_setup(sc, bus, slot, func, reg & ~3);
+
+ PCI_CSR_WRITE_4(sc, PCI_NP_CBE, COMMAND_NP_CONF_READ);
+ ret = PCI_CSR_READ_4(sc, PCI_NP_RDATA);
+ ret >>= (reg & 3) * 8;
+ ret &= 0xffffffff >> ((4 - bytes) * 8);
+#if 0
+ device_printf(dev, "read config: %u:%u:%u %#x(%d) = %#x\n", bus, slot, func, reg, bytes, ret);
+#endif
+
+ /* check & clear PCI abort */
+ data = PCI_CSR_READ_4(sc, PCI_ISR);
+ if (data & ISR_PFE) {
+ PCI_CSR_WRITE_4(sc, PCI_ISR, ISR_PFE);
+ return (-1);
+ }
+ return (ret);
+}
+
+static const int byteenables[] = { 0, 0x10, 0x30, 0x70, 0xf0 };
+
+static void
+ixppcib_write_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg,
+ u_int32_t val, int bytes)
+{
+ struct ixppcib_softc *sc = device_get_softc(dev);
+ u_int32_t data;
+
+#if 0
+ device_printf(dev, "write config: %u:%u:%u %#x(%d) = %#x\n", bus, slot, func, reg, bytes, val);
+#endif
+
+ ixppcib_conf_setup(sc, bus, slot, func, reg & ~3);
+
+ /* Byte enables are active low, so not them first */
+ PCI_CSR_WRITE_4(sc, PCI_NP_CBE, COMMAND_NP_CONF_WRITE |
+ (~(byteenables[bytes] << (reg & 3)) & 0xf0));
+ PCI_CSR_WRITE_4(sc, PCI_NP_WDATA, val << ((reg & 3) * 8));
+
+ /* check & clear PCI abort */
+ data = PCI_CSR_READ_4(sc, PCI_ISR);
+ if (data & ISR_PFE)
+ PCI_CSR_WRITE_4(sc, PCI_ISR, ISR_PFE);
+}
+
+static int
+ixppcib_route_interrupt(device_t bridge, device_t device, int pin)
+{
+
+ return (ixp425_md_route_interrupt(bridge, device, pin));
+}
+
+static device_method_t ixppcib_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, ixppcib_probe),
+ DEVMETHOD(device_attach, ixppcib_attach),
+
+ /* Bus interface */
+ DEVMETHOD(bus_print_child, bus_generic_print_child),
+ DEVMETHOD(bus_read_ivar, ixppcib_read_ivar),
+ DEVMETHOD(bus_write_ivar, ixppcib_write_ivar),
+ DEVMETHOD(bus_setup_intr, ixppcib_setup_intr),
+ DEVMETHOD(bus_teardown_intr, ixppcib_teardown_intr),
+ DEVMETHOD(bus_alloc_resource, ixppcib_alloc_resource),
+ DEVMETHOD(bus_activate_resource, ixppcib_activate_resource),
+ DEVMETHOD(bus_deactivate_resource, ixppcib_deactivate_resource),
+ DEVMETHOD(bus_release_resource, ixppcib_release_resource),
+ /* DEVMETHOD(bus_get_dma_tag, ixppcib_get_dma_tag), */
+
+ /* pcib interface */
+ DEVMETHOD(pcib_maxslots, ixppcib_maxslots),
+ DEVMETHOD(pcib_read_config, ixppcib_read_config),
+ DEVMETHOD(pcib_write_config, ixppcib_write_config),
+ DEVMETHOD(pcib_route_interrupt, ixppcib_route_interrupt),
+
+ {0, 0},
+};
+
+static driver_t ixppcib_driver = {
+ "pcib",
+ ixppcib_methods,
+ sizeof(struct ixppcib_softc),
+};
+static devclass_t ixppcib_devclass;
+
+DRIVER_MODULE(ixppcib, ixp, ixppcib_driver, ixppcib_devclass, 0, 0);
diff --git a/sys/arm/xscale/ixp425/ixp425_pci_asm.S b/sys/arm/xscale/ixp425/ixp425_pci_asm.S
new file mode 100644
index 000000000000..f686d6577f09
--- /dev/null
+++ b/sys/arm/xscale/ixp425/ixp425_pci_asm.S
@@ -0,0 +1,102 @@
+/* $NetBSD: ixp425_pci_asm.S,v 1.2 2005/12/11 12:16:51 christos Exp $ */
+
+/*
+ * Copyright (c) 2003 Wasabi Systems, Inc.
+ * All rights reserved.
+ *
+ * Written by Jason R. Thorpe for Wasabi Systems, 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed for the NetBSD Project by
+ * Wasabi Systems, Inc.
+ * 4. The name of Wasabi Systems, Inc. may not be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC
+ * 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.
+ *
+ * $FreeBSD$
+ *
+ */
+
+#include <machine/asm.h>
+
+/*
+ * Bus space functions for IXP425 PCI space access. We have to swizzle
+ * the address for 1 and 2 byte accesses when in big-endian mode.
+ */
+
+/*
+ * read single
+ */
+
+ENTRY(ixp425_pci_mem_bs_r_1)
+#ifdef __ARMEB__
+ add r1, r1, r2
+ eor r1, r1, #0x3
+ ldrb r0, [r1]
+#else
+ ldrb r0, [r1, r2]
+#endif /* __ARMEB__ */
+ mov pc, lr
+
+ENTRY(ixp425_pci_mem_bs_r_2)
+#ifdef __ARMEB__
+ add r1, r1, r2
+ eor r1, r1, #0x2
+ ldrh r0, [r1]
+#else
+ ldrh r0, [r1, r2]
+#endif /* __ARMEB__ */
+ mov pc, lr
+
+ENTRY(ixp425_pci_mem_bs_r_4)
+ ldr r0, [r1, r2]
+ mov pc, lr
+
+/*
+ * write single
+ */
+
+ENTRY(ixp425_pci_mem_bs_w_1)
+#ifdef __ARMEB__
+ add r1, r1, r2
+ eor r1, r1, #0x3
+ strb r3, [r1]
+#else
+ strb r3, [r1, r2]
+#endif /* __ARMEB__ */
+ mov pc, lr
+
+ENTRY(ixp425_pci_mem_bs_w_2)
+#ifdef __ARMEB__
+ add r1, r1, r2
+ eor r1, r1, #0x2
+ strh r3, [r1]
+#else
+ strh r3, [r1, r2]
+#endif /* __ARMEB__ */
+ mov pc, lr
+
+ENTRY(ixp425_pci_mem_bs_w_4)
+ str r3, [r1, r2]
+ mov pc, lr
diff --git a/sys/arm/xscale/ixp425/ixp425_pci_space.c b/sys/arm/xscale/ixp425/ixp425_pci_space.c
new file mode 100644
index 000000000000..6ee2a1d33180
--- /dev/null
+++ b/sys/arm/xscale/ixp425/ixp425_pci_space.c
@@ -0,0 +1,496 @@
+/* $NetBSD: ixp425_pci_space.c,v 1.6 2006/04/10 03:36:03 simonb Exp $ */
+
+/*
+ * Copyright (c) 2003
+ * Ichiro FUKUHARA <ichiro@ichiro.org>.
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ichiro FUKUHARA.
+ * 4. The name of the company nor the name of the author may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ICHIRO FUKUHARA ``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 ICHIRO FUKUHARA OR THE VOICES IN HIS HEAD BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * bus_space PCI functions for ixp425
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+
+#include <machine/pcb.h>
+
+#include <vm/vm.h>
+#include <vm/vm_kern.h>
+#include <vm/pmap.h>
+#include <vm/vm_page.h>
+#include <vm/vm_extern.h>
+
+#include <machine/bus.h>
+
+#include <arm/xscale/ixp425/ixp425reg.h>
+#include <arm/xscale/ixp425/ixp425var.h>
+
+/*
+ * Macros to read/write registers
+*/
+#define CSR_READ_4(x) *(volatile uint32_t *) \
+ (IXP425_PCI_CSR_BASE + (x))
+#define CSR_WRITE_4(x, v) *(volatile uint32_t *) \
+ (IXP425_PCI_CSR_BASE + (x)) = (v)
+
+/* Proto types for all the bus_space structure functions */
+bs_protos(ixp425_pci);
+bs_protos(ixp425_pci_io);
+bs_protos(ixp425_pci_mem);
+
+/* special I/O functions */
+static u_int8_t _pci_io_bs_r_1(void *, bus_space_handle_t, bus_size_t);
+static u_int16_t _pci_io_bs_r_2(void *, bus_space_handle_t, bus_size_t);
+static u_int32_t _pci_io_bs_r_4(void *, bus_space_handle_t, bus_size_t);
+
+static void _pci_io_bs_w_1(void *, bus_space_handle_t, bus_size_t, u_int8_t);
+static void _pci_io_bs_w_2(void *, bus_space_handle_t, bus_size_t, u_int16_t);
+static void _pci_io_bs_w_4(void *, bus_space_handle_t, bus_size_t, u_int32_t);
+
+#ifdef __ARMEB__
+static u_int8_t _pci_io_bs_r_1_s(void *, bus_space_handle_t, bus_size_t);
+static u_int16_t _pci_io_bs_r_2_s(void *, bus_space_handle_t, bus_size_t);
+static u_int32_t _pci_io_bs_r_4_s(void *, bus_space_handle_t, bus_size_t);
+
+static void _pci_io_bs_w_1_s(void *, bus_space_handle_t, bus_size_t, u_int8_t);
+static void _pci_io_bs_w_2_s(void *, bus_space_handle_t, bus_size_t, u_int16_t);
+static void _pci_io_bs_w_4_s(void *, bus_space_handle_t, bus_size_t, u_int32_t);
+
+static u_int8_t _pci_mem_bs_r_1(void *, bus_space_handle_t, bus_size_t);
+static u_int16_t _pci_mem_bs_r_2(void *, bus_space_handle_t, bus_size_t);
+static u_int32_t _pci_mem_bs_r_4(void *, bus_space_handle_t, bus_size_t);
+
+static void _pci_mem_bs_w_1(void *, bus_space_handle_t, bus_size_t, u_int8_t);
+static void _pci_mem_bs_w_2(void *, bus_space_handle_t, bus_size_t, u_int16_t);
+static void _pci_mem_bs_w_4(void *, bus_space_handle_t, bus_size_t, u_int32_t);
+#endif
+
+struct bus_space ixp425_pci_io_bs_tag_template = {
+ /* mapping/unmapping */
+ .bs_map = ixp425_pci_io_bs_map,
+ .bs_unmap = ixp425_pci_io_bs_unmap,
+ .bs_subregion = ixp425_pci_bs_subregion,
+
+ .bs_alloc = ixp425_pci_io_bs_alloc,
+ .bs_free = ixp425_pci_io_bs_free,
+
+ /* barrier */
+ .bs_barrier = ixp425_pci_bs_barrier,
+
+ /*
+ * IXP425 processor does not have PCI I/O windows
+ */
+ /* read (single) */
+ .bs_r_1 = _pci_io_bs_r_1,
+ .bs_r_2 = _pci_io_bs_r_2,
+ .bs_r_4 = _pci_io_bs_r_4,
+
+ /* write (single) */
+ .bs_w_1 = _pci_io_bs_w_1,
+ .bs_w_2 = _pci_io_bs_w_2,
+ .bs_w_4 = _pci_io_bs_w_4,
+
+#ifdef __ARMEB__
+ .bs_r_1_s = _pci_io_bs_r_1_s,
+ .bs_r_2_s = _pci_io_bs_r_2_s,
+ .bs_r_4_s = _pci_io_bs_r_4_s,
+
+ .bs_w_1_s = _pci_io_bs_w_1_s,
+ .bs_w_2_s = _pci_io_bs_w_2_s,
+ .bs_w_4_s = _pci_io_bs_w_4_s,
+#else
+ .bs_r_1_s = _pci_io_bs_r_1,
+ .bs_r_2_s = _pci_io_bs_r_2,
+ .bs_r_4_s = _pci_io_bs_r_4,
+
+ .bs_w_1_s = _pci_io_bs_w_1,
+ .bs_w_2_s = _pci_io_bs_w_2,
+ .bs_w_4_s = _pci_io_bs_w_4,
+#endif
+};
+
+void
+ixp425_io_bs_init(bus_space_tag_t bs, void *cookie)
+{
+ *bs = ixp425_pci_io_bs_tag_template;
+ bs->bs_cookie = cookie;
+}
+
+struct bus_space ixp425_pci_mem_bs_tag_template = {
+ /* mapping/unmapping */
+ .bs_map = ixp425_pci_mem_bs_map,
+ .bs_unmap = ixp425_pci_mem_bs_unmap,
+ .bs_subregion = ixp425_pci_bs_subregion,
+
+ .bs_alloc = ixp425_pci_mem_bs_alloc,
+ .bs_free = ixp425_pci_mem_bs_free,
+
+ /* barrier */
+ .bs_barrier = ixp425_pci_bs_barrier,
+
+#ifdef __ARMEB__
+ /* read (single) */
+ .bs_r_1_s = _pci_mem_bs_r_1,
+ .bs_r_2_s = _pci_mem_bs_r_2,
+ .bs_r_4_s = _pci_mem_bs_r_4,
+
+ .bs_r_1 = ixp425_pci_mem_bs_r_1,
+ .bs_r_2 = ixp425_pci_mem_bs_r_2,
+ .bs_r_4 = ixp425_pci_mem_bs_r_4,
+
+ /* write (single) */
+ .bs_w_1_s = _pci_mem_bs_w_1,
+ .bs_w_2_s = _pci_mem_bs_w_2,
+ .bs_w_4_s = _pci_mem_bs_w_4,
+
+ .bs_w_1 = ixp425_pci_mem_bs_w_1,
+ .bs_w_2 = ixp425_pci_mem_bs_w_2,
+ .bs_w_4 = ixp425_pci_mem_bs_w_4,
+#else
+ /* read (single) */
+ .bs_r_1 = ixp425_pci_mem_bs_r_1,
+ .bs_r_2 = ixp425_pci_mem_bs_r_2,
+ .bs_r_4 = ixp425_pci_mem_bs_r_4,
+ .bs_r_1_s = ixp425_pci_mem_bs_r_1,
+ .bs_r_2_s = ixp425_pci_mem_bs_r_2,
+ .bs_r_4_s = ixp425_pci_mem_bs_r_4,
+
+ /* write (single) */
+ .bs_w_1 = ixp425_pci_mem_bs_w_1,
+ .bs_w_2 = ixp425_pci_mem_bs_w_2,
+ .bs_w_4 = ixp425_pci_mem_bs_w_4,
+ .bs_w_1_s = ixp425_pci_mem_bs_w_1,
+ .bs_w_2_s = ixp425_pci_mem_bs_w_2,
+ .bs_w_4_s = ixp425_pci_mem_bs_w_4,
+#endif
+};
+
+void
+ixp425_mem_bs_init(bus_space_tag_t bs, void *cookie)
+{
+ *bs = ixp425_pci_mem_bs_tag_template;
+ bs->bs_cookie = cookie;
+}
+
+/* common routine */
+int
+ixp425_pci_bs_subregion(void *t, bus_space_handle_t bsh, bus_size_t offset,
+ bus_size_t size, bus_space_handle_t *nbshp)
+{
+ *nbshp = bsh + offset;
+ return (0);
+}
+
+void
+ixp425_pci_bs_barrier(void *t, bus_space_handle_t bsh, bus_size_t offset,
+ bus_size_t len, int flags)
+{
+ /* NULL */
+}
+
+/* io bs */
+int
+ixp425_pci_io_bs_map(void *t, bus_addr_t bpa, bus_size_t size,
+ int cacheable, bus_space_handle_t *bshp)
+{
+ *bshp = bpa;
+ return (0);
+}
+
+void
+ixp425_pci_io_bs_unmap(void *t, bus_space_handle_t h, bus_size_t size)
+{
+ /* Nothing to do. */
+}
+
+int
+ixp425_pci_io_bs_alloc(void *t, bus_addr_t rstart, bus_addr_t rend,
+ bus_size_t size, bus_size_t alignment, bus_size_t boundary, int cacheable,
+ bus_addr_t *bpap, bus_space_handle_t *bshp)
+{
+ panic("ixp425_pci_io_bs_alloc(): not implemented\n");
+}
+
+void
+ixp425_pci_io_bs_free(void *t, bus_space_handle_t bsh, bus_size_t size)
+{
+ panic("ixp425_pci_io_bs_free(): not implemented\n");
+}
+
+/* special I/O functions */
+static __inline u_int32_t
+_bs_r(void *v, bus_space_handle_t ioh, bus_size_t off, u_int32_t be)
+{
+ u_int32_t data;
+
+ CSR_WRITE_4(PCI_NP_AD, (ioh + off) & ~3);
+ CSR_WRITE_4(PCI_NP_CBE, be | COMMAND_NP_IO_READ);
+ data = CSR_READ_4(PCI_NP_RDATA);
+ if (CSR_READ_4(PCI_ISR) & ISR_PFE)
+ CSR_WRITE_4(PCI_ISR, ISR_PFE);
+
+ return data;
+}
+
+static u_int8_t
+_pci_io_bs_r_1(void *v, bus_space_handle_t ioh, bus_size_t off)
+{
+ u_int32_t data, n, be;
+
+ n = (ioh + off) % 4;
+ be = (0xf & ~(1U << n)) << NP_CBE_SHIFT;
+ data = _bs_r(v, ioh, off, be);
+
+ return data >> (8 * n);
+}
+
+static u_int16_t
+_pci_io_bs_r_2(void *v, bus_space_handle_t ioh, bus_size_t off)
+{
+ u_int32_t data, n, be;
+
+ n = (ioh + off) % 4;
+ be = (0xf & ~((1U << n) | (1U << (n + 1)))) << NP_CBE_SHIFT;
+ data = _bs_r(v, ioh, off, be);
+
+ return data >> (8 * n);
+}
+
+static u_int32_t
+_pci_io_bs_r_4(void *v, bus_space_handle_t ioh, bus_size_t off)
+{
+ u_int32_t data;
+
+ data = _bs_r(v, ioh, off, 0);
+ return data;
+}
+
+#ifdef __ARMEB__
+static u_int8_t
+_pci_io_bs_r_1_s(void *v, bus_space_handle_t ioh, bus_size_t off)
+{
+ u_int32_t data, n, be;
+
+ n = (ioh + off) % 4;
+ be = (0xf & ~(1U << n)) << NP_CBE_SHIFT;
+ data = _bs_r(v, ioh, off, be);
+
+ return data >> (8 * n);
+}
+
+static u_int16_t
+_pci_io_bs_r_2_s(void *v, bus_space_handle_t ioh, bus_size_t off)
+{
+ u_int32_t data, n, be;
+
+ n = (ioh + off) % 4;
+ be = (0xf & ~((1U << n) | (1U << (n + 1)))) << NP_CBE_SHIFT;
+ data = _bs_r(v, ioh, off, be);
+
+ return data >> (8 * n);
+}
+
+static u_int32_t
+_pci_io_bs_r_4_s(void *v, bus_space_handle_t ioh, bus_size_t off)
+{
+ u_int32_t data;
+
+ data = _bs_r(v, ioh, off, 0);
+ return le32toh(data);
+}
+#endif /* __ARMEB__ */
+
+static __inline void
+_bs_w(void *v, bus_space_handle_t ioh, bus_size_t off,
+ u_int32_t be, u_int32_t data)
+{
+ CSR_WRITE_4(PCI_NP_AD, (ioh + off) & ~3);
+ CSR_WRITE_4(PCI_NP_CBE, be | COMMAND_NP_IO_WRITE);
+ CSR_WRITE_4(PCI_NP_WDATA, data);
+ if (CSR_READ_4(PCI_ISR) & ISR_PFE)
+ CSR_WRITE_4(PCI_ISR, ISR_PFE);
+}
+
+static void
+_pci_io_bs_w_1(void *v, bus_space_handle_t ioh, bus_size_t off,
+ u_int8_t val)
+{
+ u_int32_t data, n, be;
+
+ n = (ioh + off) % 4;
+ be = (0xf & ~(1U << n)) << NP_CBE_SHIFT;
+ data = val << (8 * n);
+ _bs_w(v, ioh, off, be, data);
+}
+
+static void
+_pci_io_bs_w_2(void *v, bus_space_handle_t ioh, bus_size_t off,
+ u_int16_t val)
+{
+ u_int32_t data, n, be;
+
+ n = (ioh + off) % 4;
+ be = (0xf & ~((1U << n) | (1U << (n + 1)))) << NP_CBE_SHIFT;
+ data = val << (8 * n);
+ _bs_w(v, ioh, off, be, data);
+}
+
+static void
+_pci_io_bs_w_4(void *v, bus_space_handle_t ioh, bus_size_t off,
+ u_int32_t val)
+{
+ _bs_w(v, ioh, off, 0, val);
+}
+
+#ifdef __ARMEB__
+static void
+_pci_io_bs_w_1_s(void *v, bus_space_handle_t ioh, bus_size_t off,
+ u_int8_t val)
+{
+ u_int32_t data, n, be;
+
+ n = (ioh + off) % 4;
+ be = (0xf & ~(1U << n)) << NP_CBE_SHIFT;
+ data = val << (8 * n);
+ _bs_w(v, ioh, off, be, data);
+}
+
+static void
+_pci_io_bs_w_2_s(void *v, bus_space_handle_t ioh, bus_size_t off,
+ u_int16_t val)
+{
+ u_int32_t data, n, be;
+
+ n = (ioh + off) % 4;
+ be = (0xf & ~((1U << n) | (1U << (n + 1)))) << NP_CBE_SHIFT;
+ data = val << (8 * n);
+ _bs_w(v, ioh, off, be, data);
+}
+
+static void
+_pci_io_bs_w_4_s(void *v, bus_space_handle_t ioh, bus_size_t off,
+ u_int32_t val)
+{
+ _bs_w(v, ioh, off, 0, htole32(val));
+}
+#endif /* __ARMEB__ */
+
+/* mem bs */
+int
+ixp425_pci_mem_bs_map(void *t, bus_addr_t bpa, bus_size_t size,
+ int cacheable, bus_space_handle_t *bshp)
+{
+ vm_paddr_t pa, endpa;
+
+ pa = trunc_page(bpa);
+ endpa = round_page(bpa + size);
+
+ *bshp = (vm_offset_t)pmap_mapdev(pa, endpa - pa);
+
+ return (0);
+}
+
+void
+ixp425_pci_mem_bs_unmap(void *t, bus_space_handle_t h, bus_size_t size)
+{
+ vm_offset_t va, endva;
+
+ va = trunc_page((vm_offset_t)t);
+ endva = va + round_page(size);
+
+ /* Free the kernel virtual mapping. */
+ kmem_free(kernel_map, va, endva - va);
+}
+
+int
+ixp425_pci_mem_bs_alloc(void *t, bus_addr_t rstart, bus_addr_t rend,
+ bus_size_t size, bus_size_t alignment, bus_size_t boundary, int cacheable,
+ bus_addr_t *bpap, bus_space_handle_t *bshp)
+{
+ panic("ixp425_mem_bs_alloc(): not implemented\n");
+}
+
+void
+ixp425_pci_mem_bs_free(void *t, bus_space_handle_t bsh, bus_size_t size)
+{
+ panic("ixp425_mem_bs_free(): not implemented\n");
+}
+
+#ifdef __ARMEB__
+static u_int8_t
+_pci_mem_bs_r_1(void *v, bus_space_handle_t ioh, bus_size_t off)
+{
+ return ixp425_pci_mem_bs_r_1(v, ioh, off);
+}
+
+static u_int16_t
+_pci_mem_bs_r_2(void *v, bus_space_handle_t ioh, bus_size_t off)
+{
+ return (ixp425_pci_mem_bs_r_2(v, ioh, off));
+}
+
+static u_int32_t
+_pci_mem_bs_r_4(void *v, bus_space_handle_t ioh, bus_size_t off)
+{
+ u_int32_t data;
+
+ data = ixp425_pci_mem_bs_r_4(v, ioh, off);
+ return (le32toh(data));
+}
+
+static void
+_pci_mem_bs_w_1(void *v, bus_space_handle_t ioh, bus_size_t off,
+ u_int8_t val)
+{
+ ixp425_pci_mem_bs_w_1(v, ioh, off, val);
+}
+
+static void
+_pci_mem_bs_w_2(void *v, bus_space_handle_t ioh, bus_size_t off,
+ u_int16_t val)
+{
+ ixp425_pci_mem_bs_w_2(v, ioh, off, val);
+}
+
+static void
+_pci_mem_bs_w_4(void *v, bus_space_handle_t ioh, bus_size_t off,
+ u_int32_t val)
+{
+ ixp425_pci_mem_bs_w_4(v, ioh, off, htole32(val));
+}
+#endif /* __ARMEB__ */
+
+/* End of ixp425_pci_space.c */
diff --git a/sys/arm/xscale/ixp425/ixp425_qmgr.c b/sys/arm/xscale/ixp425/ixp425_qmgr.c
new file mode 100644
index 000000000000..fcf2da257fad
--- /dev/null
+++ b/sys/arm/xscale/ixp425/ixp425_qmgr.c
@@ -0,0 +1,1077 @@
+/*-
+ * Copyright (c) 2006 Sam Leffler, Errno Consulting
+ * 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,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ * redistribution must be conditioned upon including a substantially
+ * similar Disclaimer requirement for further binary redistribution.
+ *
+ * NO WARRANTY
+ * 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 NONINFRINGEMENT, MERCHANTIBILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ */
+
+/*-
+ * Copyright (c) 2001-2005, Intel Corporation.
+ * 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 Intel Corporation nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ *
+ * 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>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Intel XScale Queue Manager support.
+ *
+ * Each IXP4XXX device has a hardware block that implements a priority
+ * queue manager that is shared between the XScale cpu and the backend
+ * devices (such as the NPE). Queues are accessed by reading/writing
+ * special memory locations. The queue contents are mapped into a shared
+ * SRAM region with entries managed in a circular buffer. The XScale
+ * processor can receive interrupts based on queue contents (a condition
+ * code determines when interrupts should be delivered).
+ *
+ * The code here basically replaces the qmgr class in the Intel Access
+ * Library (IAL).
+ */
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/time.h>
+#include <sys/bus.h>
+#include <sys/resource.h>
+#include <sys/rman.h>
+#include <sys/sysctl.h>
+
+#include <machine/bus.h>
+#include <machine/cpu.h>
+#include <machine/cpufunc.h>
+#include <machine/resource.h>
+#include <machine/intr.h>
+#include <arm/xscale/ixp425/ixp425reg.h>
+#include <arm/xscale/ixp425/ixp425var.h>
+
+#include <arm/xscale/ixp425/ixp425_qmgr.h>
+
+/*
+ * State per AQM hw queue.
+ * This structure holds q configuration and dispatch state.
+ */
+struct qmgrInfo {
+ int qSizeInWords; /* queue size in words */
+
+ uint32_t qOflowStatBitMask; /* overflow status mask */
+ int qWriteCount; /* queue write count */
+
+ bus_size_t qAccRegAddr; /* access register */
+ bus_size_t qUOStatRegAddr; /* status register */
+ bus_size_t qConfigRegAddr; /* config register */
+ int qSizeInEntries; /* queue size in entries */
+
+ uint32_t qUflowStatBitMask; /* underflow status mask */
+ int qReadCount; /* queue read count */
+
+ /* XXX union */
+ uint32_t qStatRegAddr;
+ uint32_t qStatBitsOffset;
+ uint32_t qStat0BitMask;
+ uint32_t qStat1BitMask;
+
+ uint32_t intRegCheckMask; /* interrupt reg check mask */
+ void (*cb)(int, void *); /* callback function */
+ void *cbarg; /* callback argument */
+ int priority; /* dispatch priority */
+#if 0
+ /* NB: needed only for A0 parts */
+ u_int statusWordOffset; /* status word offset */
+ uint32_t statusMask; /* status mask */
+ uint32_t statusCheckValue; /* status check value */
+#endif
+};
+
+struct ixpqmgr_softc {
+ device_t sc_dev;
+ bus_space_tag_t sc_iot;
+ bus_space_handle_t sc_ioh;
+ struct resource *sc_irq; /* IRQ resource */
+ void *sc_ih; /* interrupt handler */
+ int sc_rid; /* resource id for irq */
+
+ struct qmgrInfo qinfo[IX_QMGR_MAX_NUM_QUEUES];
+ /*
+ * This array contains a list of queue identifiers ordered by
+ * priority. The table is split logically between queue
+ * identifiers 0-31 and 32-63. To optimize lookups bit masks
+ * are kept for the first-32 and last-32 q's. When the
+ * table needs to be rebuilt mark rebuildTable and it'll
+ * happen after the next interrupt.
+ */
+ int priorityTable[IX_QMGR_MAX_NUM_QUEUES];
+ uint32_t lowPriorityTableFirstHalfMask;
+ uint32_t uppPriorityTableFirstHalfMask;
+ int rebuildTable; /* rebuild priorityTable */
+
+ uint32_t aqmFreeSramAddress; /* SRAM free space */
+};
+
+static int qmgr_debug = 0;
+SYSCTL_INT(_debug, OID_AUTO, qmgr, CTLFLAG_RW, &qmgr_debug,
+ 0, "IXP425 Q-Manager debug msgs");
+TUNABLE_INT("debug.qmgr", &qmgr_debug);
+#define DPRINTF(dev, fmt, ...) do { \
+ if (qmgr_debug) printf(fmt, __VA_ARGS__); \
+} while (0)
+#define DPRINTFn(n, dev, fmt, ...) do { \
+ if (qmgr_debug >= n) printf(fmt, __VA_ARGS__); \
+} while (0)
+
+static struct ixpqmgr_softc *ixpqmgr_sc = NULL;
+
+static void ixpqmgr_rebuild(struct ixpqmgr_softc *);
+static void ixpqmgr_intr(void *);
+
+static void aqm_int_enable(struct ixpqmgr_softc *sc, int qId);
+static void aqm_int_disable(struct ixpqmgr_softc *sc, int qId);
+static void aqm_qcfg(struct ixpqmgr_softc *sc, int qId, u_int ne, u_int nf);
+static void aqm_srcsel_write(struct ixpqmgr_softc *sc, int qId, int sourceId);
+static void aqm_reset(struct ixpqmgr_softc *sc);
+
+static void
+dummyCallback(int qId, void *arg)
+{
+ /* XXX complain */
+}
+
+static uint32_t
+aqm_reg_read(struct ixpqmgr_softc *sc, bus_size_t off)
+{
+ DPRINTFn(9, sc->sc_dev, "%s(0x%x)\n", __func__, (int)off);
+ return bus_space_read_4(sc->sc_iot, sc->sc_ioh, off);
+}
+
+static void
+aqm_reg_write(struct ixpqmgr_softc *sc, bus_size_t off, uint32_t val)
+{
+ DPRINTFn(9, sc->sc_dev, "%s(0x%x, 0x%x)\n", __func__, (int)off, val);
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, off, val);
+}
+
+static int
+ixpqmgr_probe(device_t dev)
+{
+ device_set_desc(dev, "IXP425 Q-Manager");
+ return 0;
+}
+
+static void
+ixpqmgr_attach(device_t dev)
+{
+ struct ixpqmgr_softc *sc = device_get_softc(dev);
+ struct ixp425_softc *sa = device_get_softc(device_get_parent(dev));
+ int i;
+
+ ixpqmgr_sc = sc;
+
+ sc->sc_dev = dev;
+ sc->sc_iot = sa->sc_iot;
+ if (bus_space_map(sc->sc_iot, IXP425_QMGR_HWBASE, IXP425_QMGR_SIZE,
+ 0, &sc->sc_ioh))
+ panic("%s: Cannot map registers", device_get_name(dev));
+
+ /* NB: we only use the lower 32 q's */
+ sc->sc_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &sc->sc_rid,
+ IXP425_INT_QUE1_32, IXP425_INT_QUE33_64, 2, RF_ACTIVE);
+ if (!sc->sc_irq)
+ panic("Unable to allocate the qmgr irqs.\n");
+ /* XXX could be a source of entropy */
+ bus_setup_intr(dev, sc->sc_irq, INTR_TYPE_NET | INTR_MPSAFE,
+ ixpqmgr_intr, NULL, &sc->sc_ih);
+
+ /* NB: softc is pre-zero'd */
+ for (i = 0; i < IX_QMGR_MAX_NUM_QUEUES; i++) {
+ struct qmgrInfo *qi = &sc->qinfo[i];
+
+ qi->cb = dummyCallback;
+ qi->priority = IX_QMGR_Q_PRIORITY_0; /* default priority */
+ /*
+ * There are two interrupt registers, 32 bits each. One
+ * for the lower queues(0-31) and one for the upper
+ * queues(32-63). Therefore need to mod by 32 i.e the
+ * min upper queue identifier.
+ */
+ qi->intRegCheckMask = (1<<(i%(IX_QMGR_MIN_QUEUPP_QID)));
+
+ /*
+ * Register addresses and bit masks are calculated and
+ * stored here to optimize QRead, QWrite and QStatusGet
+ * functions.
+ */
+
+ /* AQM Queue access reg addresses, per queue */
+ qi->qAccRegAddr = IX_QMGR_Q_ACCESS_ADDR_GET(i);
+ qi->qAccRegAddr = IX_QMGR_Q_ACCESS_ADDR_GET(i);
+ qi->qConfigRegAddr = IX_QMGR_Q_CONFIG_ADDR_GET(i);
+
+ /* AQM Queue lower-group (0-31), only */
+ if (i < IX_QMGR_MIN_QUEUPP_QID) {
+ /* AQM Q underflow/overflow status reg address, per queue */
+ qi->qUOStatRegAddr = IX_QMGR_QUEUOSTAT0_OFFSET +
+ ((i / IX_QMGR_QUEUOSTAT_NUM_QUE_PER_WORD) *
+ sizeof(uint32_t));
+
+ /* AQM Q underflow status bit masks for status reg per queue */
+ qi->qUflowStatBitMask =
+ (IX_QMGR_UNDERFLOW_BIT_OFFSET + 1) <<
+ ((i & (IX_QMGR_QUEUOSTAT_NUM_QUE_PER_WORD - 1)) *
+ (32 / IX_QMGR_QUEUOSTAT_NUM_QUE_PER_WORD));
+
+ /* AQM Q overflow status bit masks for status reg, per queue */
+ qi->qOflowStatBitMask =
+ (IX_QMGR_OVERFLOW_BIT_OFFSET + 1) <<
+ ((i & (IX_QMGR_QUEUOSTAT_NUM_QUE_PER_WORD - 1)) *
+ (32 / IX_QMGR_QUEUOSTAT_NUM_QUE_PER_WORD));
+
+ /* AQM Q lower-group (0-31) status reg addresses, per queue */
+ qi->qStatRegAddr = IX_QMGR_QUELOWSTAT0_OFFSET +
+ ((i / IX_QMGR_QUELOWSTAT_NUM_QUE_PER_WORD) *
+ sizeof(uint32_t));
+
+ /* AQM Q lower-group (0-31) status register bit offset */
+ qi->qStatBitsOffset =
+ (i & (IX_QMGR_QUELOWSTAT_NUM_QUE_PER_WORD - 1)) *
+ (32 / IX_QMGR_QUELOWSTAT_NUM_QUE_PER_WORD);
+ } else { /* AQM Q upper-group (32-63), only */
+ qi->qUOStatRegAddr = 0; /* XXX */
+
+ /* AQM Q upper-group (32-63) Nearly Empty status reg bitmasks */
+ qi->qStat0BitMask = (1 << (i - IX_QMGR_MIN_QUEUPP_QID));
+
+ /* AQM Q upper-group (32-63) Full status register bitmasks */
+ qi->qStat1BitMask = (1 << (i - IX_QMGR_MIN_QUEUPP_QID));
+ }
+ }
+
+ sc->aqmFreeSramAddress = 0x100; /* Q buffer space starts at 0x2100 */
+
+ ixpqmgr_rebuild(sc); /* build inital priority table */
+ aqm_reset(sc); /* reset h/w */
+}
+
+static void
+ixpqmgr_detach(device_t dev)
+{
+ struct ixpqmgr_softc *sc = device_get_softc(dev);
+
+ aqm_reset(sc); /* disable interrupts */
+ bus_teardown_intr(dev, sc->sc_irq, sc->sc_ih);
+ bus_release_resource(dev, SYS_RES_IRQ, sc->sc_rid, sc->sc_irq);
+ bus_space_unmap(sc->sc_iot, sc->sc_ioh, IXP425_QMGR_SIZE);
+}
+
+int
+ixpqmgr_qconfig(int qId, int qEntries, int ne, int nf, int srcSel,
+ void (*cb)(int, void *), void *cbarg)
+{
+ struct ixpqmgr_softc *sc = ixpqmgr_sc;
+ struct qmgrInfo *qi = &sc->qinfo[qId];
+
+ DPRINTF(sc->sc_dev, "%s(%u, %u, %u, %u, %u, %p, %p)\n",
+ __func__, qId, qEntries, ne, nf, srcSel, cb, cbarg);
+
+ /* NB: entry size is always 1 */
+ qi->qSizeInWords = qEntries;
+
+ qi->qReadCount = 0;
+ qi->qWriteCount = 0;
+ qi->qSizeInEntries = qEntries; /* XXX kept for code clarity */
+
+ if (cb == NULL) {
+ /* Reset to dummy callback */
+ qi->cb = dummyCallback;
+ qi->cbarg = 0;
+ } else {
+ qi->cb = cb;
+ qi->cbarg = cbarg;
+ }
+
+ /* Write the config register; NB must be AFTER qinfo setup */
+ aqm_qcfg(sc, qId, ne, nf);
+ /*
+ * Account for space just allocated to queue.
+ */
+ sc->aqmFreeSramAddress += (qi->qSizeInWords * sizeof(uint32_t));
+
+ /* Set the interupt source if this queue is in the range 0-31 */
+ if (qId < IX_QMGR_MIN_QUEUPP_QID)
+ aqm_srcsel_write(sc, qId, srcSel);
+
+ if (cb != NULL) /* Enable the interrupt */
+ aqm_int_enable(sc, qId);
+
+ sc->rebuildTable = TRUE;
+
+ return 0; /* XXX */
+}
+
+int
+ixpqmgr_qwrite(int qId, uint32_t entry)
+{
+ struct ixpqmgr_softc *sc = ixpqmgr_sc;
+ struct qmgrInfo *qi = &sc->qinfo[qId];
+
+ DPRINTFn(3, sc->sc_dev, "%s(%u, 0x%x) writeCount %u size %u\n",
+ __func__, qId, entry, qi->qWriteCount, qi->qSizeInEntries);
+
+ /* write the entry */
+ aqm_reg_write(sc, qi->qAccRegAddr, entry);
+
+ /* NB: overflow is available for lower queues only */
+ if (qId < IX_QMGR_MIN_QUEUPP_QID) {
+ int qSize = qi->qSizeInEntries;
+ /*
+ * Increment the current number of entries in the queue
+ * and check for overflow .
+ */
+ if (qi->qWriteCount++ == qSize) { /* check for overflow */
+ uint32_t status = aqm_reg_read(sc, qi->qUOStatRegAddr);
+ int qPtrs;
+
+ /*
+ * Read the status twice because the status may
+ * not be immediately ready after the write operation
+ */
+ if ((status & qi->qOflowStatBitMask) ||
+ ((status = aqm_reg_read(sc, qi->qUOStatRegAddr)) & qi->qOflowStatBitMask)) {
+ /*
+ * The queue is full, clear the overflow status bit if set.
+ */
+ aqm_reg_write(sc, qi->qUOStatRegAddr,
+ status & ~qi->qOflowStatBitMask);
+ qi->qWriteCount = qSize;
+ DPRINTFn(5, sc->sc_dev,
+ "%s(%u, 0x%x) Q full, overflow status cleared\n",
+ __func__, qId, entry);
+ return ENOSPC;
+ }
+ /*
+ * No overflow occured : someone is draining the queue
+ * and the current counter needs to be
+ * updated from the current number of entries in the queue
+ */
+
+ /* calculate number of words in q */
+ qPtrs = aqm_reg_read(sc, qi->qConfigRegAddr);
+ DPRINTFn(2, sc->sc_dev,
+ "%s(%u, 0x%x) Q full, no overflow status, qConfig 0x%x\n",
+ __func__, qId, entry, qPtrs);
+ qPtrs = (qPtrs - (qPtrs >> 7)) & 0x7f;
+
+ if (qPtrs == 0) {
+ /*
+ * The queue may be full at the time of the
+ * snapshot. Next access will check
+ * the overflow status again.
+ */
+ qi->qWriteCount = qSize;
+ } else {
+ /* convert the number of words to a number of entries */
+ qi->qWriteCount = qPtrs & (qSize - 1);
+ }
+ }
+ }
+ return 0;
+}
+
+int
+ixpqmgr_qread(int qId, uint32_t *entry)
+{
+ struct ixpqmgr_softc *sc = ixpqmgr_sc;
+ struct qmgrInfo *qi = &sc->qinfo[qId];
+ bus_size_t off = qi->qAccRegAddr;
+
+ *entry = aqm_reg_read(sc, off);
+
+ /*
+ * Reset the current read count : next access to the read function
+ * will force a underflow status check.
+ */
+ qi->qReadCount = 0;
+
+ /* Check if underflow occurred on the read */
+ if (*entry == 0 && qId < IX_QMGR_MIN_QUEUPP_QID) {
+ /* get the queue status */
+ uint32_t status = aqm_reg_read(sc, qi->qUOStatRegAddr);
+
+ if (status & qi->qUflowStatBitMask) { /* clear underflow status */
+ aqm_reg_write(sc, qi->qUOStatRegAddr,
+ status &~ qi->qUflowStatBitMask);
+ return ENOSPC;
+ }
+ }
+ return 0;
+}
+
+int
+ixpqmgr_qreadm(int qId, uint32_t n, uint32_t *p)
+{
+ struct ixpqmgr_softc *sc = ixpqmgr_sc;
+ struct qmgrInfo *qi = &sc->qinfo[qId];
+ uint32_t entry;
+ bus_size_t off = qi->qAccRegAddr;
+
+ entry = aqm_reg_read(sc, off);
+ while (--n) {
+ if (entry == 0) {
+ /* if we read a NULL entry, stop. We have underflowed */
+ break;
+ }
+ *p++ = entry; /* store */
+ entry = aqm_reg_read(sc, off);
+ }
+ *p = entry;
+
+ /*
+ * Reset the current read count : next access to the read function
+ * will force a underflow status check.
+ */
+ qi->qReadCount = 0;
+
+ /* Check if underflow occurred on the read */
+ if (entry == 0 && qId < IX_QMGR_MIN_QUEUPP_QID) {
+ /* get the queue status */
+ uint32_t status = aqm_reg_read(sc, qi->qUOStatRegAddr);
+
+ if (status & qi->qUflowStatBitMask) { /* clear underflow status */
+ aqm_reg_write(sc, qi->qUOStatRegAddr,
+ status &~ qi->qUflowStatBitMask);
+ return ENOSPC;
+ }
+ }
+ return 0;
+}
+
+uint32_t
+ixpqmgr_getqstatus(int qId)
+{
+#define QLOWSTATMASK \
+ ((1 << (32 / IX_QMGR_QUELOWSTAT_NUM_QUE_PER_WORD)) - 1)
+ struct ixpqmgr_softc *sc = ixpqmgr_sc;
+ const struct qmgrInfo *qi = &sc->qinfo[qId];
+ uint32_t status;
+
+ if (qId < IX_QMGR_MIN_QUEUPP_QID) {
+ /* read the status of a queue in the range 0-31 */
+ status = aqm_reg_read(sc, qi->qStatRegAddr);
+
+ /* mask out the status bits relevant only to this queue */
+ status = (status >> qi->qStatBitsOffset) & QLOWSTATMASK;
+ } else { /* read status of a queue in the range 32-63 */
+ status = 0;
+ if (aqm_reg_read(sc, IX_QMGR_QUEUPPSTAT0_OFFSET)&qi->qStat0BitMask)
+ status |= IX_QMGR_Q_STATUS_NE_BIT_MASK; /* nearly empty */
+ if (aqm_reg_read(sc, IX_QMGR_QUEUPPSTAT1_OFFSET)&qi->qStat1BitMask)
+ status |= IX_QMGR_Q_STATUS_F_BIT_MASK; /* full */
+ }
+ return status;
+#undef QLOWSTATMASK
+}
+
+uint32_t
+ixpqmgr_getqconfig(int qId)
+{
+ struct ixpqmgr_softc *sc = ixpqmgr_sc;
+
+ return aqm_reg_read(sc, IX_QMGR_Q_CONFIG_ADDR_GET(qId));
+}
+
+void
+ixpqmgr_dump(void)
+{
+ struct ixpqmgr_softc *sc = ixpqmgr_sc;
+ int i, a;
+
+ /* status registers */
+ printf("0x%04x: %08x %08x %08x %08x\n"
+ , 0x400
+ , aqm_reg_read(sc, 0x400)
+ , aqm_reg_read(sc, 0x400+4)
+ , aqm_reg_read(sc, 0x400+8)
+ , aqm_reg_read(sc, 0x400+12)
+ );
+ printf("0x%04x: %08x %08x %08x %08x\n"
+ , 0x410
+ , aqm_reg_read(sc, 0x410)
+ , aqm_reg_read(sc, 0x410+4)
+ , aqm_reg_read(sc, 0x410+8)
+ , aqm_reg_read(sc, 0x410+12)
+ );
+ printf("0x%04x: %08x %08x %08x %08x\n"
+ , 0x420
+ , aqm_reg_read(sc, 0x420)
+ , aqm_reg_read(sc, 0x420+4)
+ , aqm_reg_read(sc, 0x420+8)
+ , aqm_reg_read(sc, 0x420+12)
+ );
+ printf("0x%04x: %08x %08x %08x %08x\n"
+ , 0x430
+ , aqm_reg_read(sc, 0x430)
+ , aqm_reg_read(sc, 0x430+4)
+ , aqm_reg_read(sc, 0x430+8)
+ , aqm_reg_read(sc, 0x430+12)
+ );
+ /* q configuration registers */
+ for (a = 0x2000; a < 0x20ff; a += 32)
+ printf("0x%04x: %08x %08x %08x %08x %08x %08x %08x %08x\n"
+ , a
+ , aqm_reg_read(sc, a)
+ , aqm_reg_read(sc, a+4)
+ , aqm_reg_read(sc, a+8)
+ , aqm_reg_read(sc, a+12)
+ , aqm_reg_read(sc, a+16)
+ , aqm_reg_read(sc, a+20)
+ , aqm_reg_read(sc, a+24)
+ , aqm_reg_read(sc, a+28)
+ );
+ /* allocated SRAM */
+ for (i = 0x100; i < sc->aqmFreeSramAddress; i += 32) {
+ a = 0x2000 + i;
+ printf("0x%04x: %08x %08x %08x %08x %08x %08x %08x %08x\n"
+ , a
+ , aqm_reg_read(sc, a)
+ , aqm_reg_read(sc, a+4)
+ , aqm_reg_read(sc, a+8)
+ , aqm_reg_read(sc, a+12)
+ , aqm_reg_read(sc, a+16)
+ , aqm_reg_read(sc, a+20)
+ , aqm_reg_read(sc, a+24)
+ , aqm_reg_read(sc, a+28)
+ );
+ }
+ for (i = 0; i < 16; i++) {
+ printf("Q[%2d] config 0x%08x status 0x%02x "
+ "Q[%2d] config 0x%08x status 0x%02x\n"
+ , i, ixpqmgr_getqconfig(i), ixpqmgr_getqstatus(i)
+ , i+16, ixpqmgr_getqconfig(i+16), ixpqmgr_getqstatus(i+16)
+ );
+ }
+}
+
+void
+ixpqmgr_notify_enable(int qId, int srcSel)
+{
+ struct ixpqmgr_softc *sc = ixpqmgr_sc;
+#if 0
+ /* Calculate the checkMask and checkValue for this q */
+ aqm_calc_statuscheck(sc, qId, srcSel);
+#endif
+ /* Set the interupt source if this queue is in the range 0-31 */
+ if (qId < IX_QMGR_MIN_QUEUPP_QID)
+ aqm_srcsel_write(sc, qId, srcSel);
+
+ /* Enable the interrupt */
+ aqm_int_enable(sc, qId);
+}
+
+void
+ixpqmgr_notify_disable(int qId)
+{
+ struct ixpqmgr_softc *sc = ixpqmgr_sc;
+
+ aqm_int_disable(sc, qId);
+}
+
+/*
+ * Rebuild the priority table used by the dispatcher.
+ */
+static void
+ixpqmgr_rebuild(struct ixpqmgr_softc *sc)
+{
+ int q, pri;
+ int lowQuePriorityTableIndex, uppQuePriorityTableIndex;
+ struct qmgrInfo *qi;
+
+ sc->lowPriorityTableFirstHalfMask = 0;
+ sc->uppPriorityTableFirstHalfMask = 0;
+
+ lowQuePriorityTableIndex = 0;
+ uppQuePriorityTableIndex = 32;
+ for (pri = 0; pri < IX_QMGR_NUM_PRIORITY_LEVELS; pri++) {
+ /* low priority q's */
+ for (q = 0; q < IX_QMGR_MIN_QUEUPP_QID; q++) {
+ qi = &sc->qinfo[q];
+ if (qi->priority == pri) {
+ /*
+ * Build the priority table bitmask which match the
+ * queues of the first half of the priority table.
+ */
+ if (lowQuePriorityTableIndex < 16) {
+ sc->lowPriorityTableFirstHalfMask |=
+ qi->intRegCheckMask;
+ }
+ sc->priorityTable[lowQuePriorityTableIndex++] = q;
+ }
+ }
+ /* high priority q's */
+ for (; q < IX_QMGR_MAX_NUM_QUEUES; q++) {
+ qi = &sc->qinfo[q];
+ if (qi->priority == pri) {
+ /*
+ * Build the priority table bitmask which match the
+ * queues of the first half of the priority table .
+ */
+ if (uppQuePriorityTableIndex < 48) {
+ sc->uppPriorityTableFirstHalfMask |=
+ qi->intRegCheckMask;
+ }
+ sc->priorityTable[uppQuePriorityTableIndex++] = q;
+ }
+ }
+ }
+ sc->rebuildTable = FALSE;
+}
+
+/*
+ * Count the number of leading zero bits in a word,
+ * and return the same value than the CLZ instruction.
+ * Note this is similar to the standard ffs function but
+ * it counts zero's from the MSB instead of the LSB.
+ *
+ * word (in) return value (out)
+ * 0x80000000 0
+ * 0x40000000 1
+ * ,,, ,,,
+ * 0x00000002 30
+ * 0x00000001 31
+ * 0x00000000 32
+ *
+ * The C version of this function is used as a replacement
+ * for system not providing the equivalent of the CLZ
+ * assembly language instruction.
+ *
+ * Note that this version is big-endian
+ */
+static unsigned int
+_lzcount(uint32_t word)
+{
+ unsigned int lzcount = 0;
+
+ if (word == 0)
+ return 32;
+ while ((word & 0x80000000) == 0) {
+ word <<= 1;
+ lzcount++;
+ }
+ return lzcount;
+}
+
+static void
+ixpqmgr_intr(void *arg)
+{
+ struct ixpqmgr_softc *sc = ixpqmgr_sc;
+ uint32_t intRegVal; /* Interrupt reg val */
+ struct qmgrInfo *qi;
+ int priorityTableIndex; /* Priority table index */
+ int qIndex; /* Current queue being processed */
+
+ /* Read the interrupt register */
+ intRegVal = aqm_reg_read(sc, IX_QMGR_QINTREG0_OFFSET);
+ /* Write back to clear interrupt */
+ aqm_reg_write(sc, IX_QMGR_QINTREG0_OFFSET, intRegVal);
+
+ DPRINTFn(5, sc->sc_dev, "%s: ISR0 0x%x ISR1 0x%x\n",
+ __func__, intRegVal, aqm_reg_read(sc, IX_QMGR_QINTREG1_OFFSET));
+
+ /* No queue has interrupt register set */
+ if (intRegVal != 0) {
+ /* get the first queue Id from the interrupt register value */
+ qIndex = (32 - 1) - _lzcount(intRegVal);
+
+ DPRINTFn(2, sc->sc_dev, "%s: ISR0 0x%x qIndex %u\n",
+ __func__, intRegVal, qIndex);
+
+ /*
+ * Optimize for single callback case.
+ */
+ qi = &sc->qinfo[qIndex];
+ if (intRegVal == qi->intRegCheckMask) {
+ /*
+ * Only 1 queue event triggered a notification.
+ * Call the callback function for this queue
+ */
+ qi->cb(qIndex, qi->cbarg);
+ } else {
+ /*
+ * The event is triggered by more than 1 queue,
+ * the queue search will start from the beginning
+ * or the middle of the priority table.
+ *
+ * The search will end when all the bits of the interrupt
+ * register are cleared. There is no need to maintain
+ * a seperate value and test it at each iteration.
+ */
+ if (intRegVal & sc->lowPriorityTableFirstHalfMask) {
+ priorityTableIndex = 0;
+ } else {
+ priorityTableIndex = 16;
+ }
+ /*
+ * Iterate over the priority table until all the bits
+ * of the interrupt register are cleared.
+ */
+ do {
+ qIndex = sc->priorityTable[priorityTableIndex++];
+ qi = &sc->qinfo[qIndex];
+
+ /* If this queue caused this interrupt to be raised */
+ if (intRegVal & qi->intRegCheckMask) {
+ /* Call the callback function for this queue */
+ qi->cb(qIndex, qi->cbarg);
+ /* Clear the interrupt register bit */
+ intRegVal &= ~qi->intRegCheckMask;
+ }
+ } while (intRegVal);
+ }
+ }
+
+ /* Rebuild the priority table if needed */
+ if (sc->rebuildTable)
+ ixpqmgr_rebuild(sc);
+}
+
+#if 0
+/*
+ * Generate the parameters used to check if a Q's status matches
+ * the specified source select. We calculate which status word
+ * to check (statusWordOffset), the value to check the status
+ * against (statusCheckValue) and the mask (statusMask) to mask
+ * out all but the bits to check in the status word.
+ */
+static void
+aqm_calc_statuscheck(int qId, IxQMgrSourceId srcSel)
+{
+ struct qmgrInfo *qi = &qinfo[qId];
+ uint32_t shiftVal;
+
+ if (qId < IX_QMGR_MIN_QUEUPP_QID) {
+ switch (srcSel) {
+ case IX_QMGR_Q_SOURCE_ID_E:
+ qi->statusCheckValue = IX_QMGR_Q_STATUS_E_BIT_MASK;
+ qi->statusMask = IX_QMGR_Q_STATUS_E_BIT_MASK;
+ break;
+ case IX_QMGR_Q_SOURCE_ID_NE:
+ qi->statusCheckValue = IX_QMGR_Q_STATUS_NE_BIT_MASK;
+ qi->statusMask = IX_QMGR_Q_STATUS_NE_BIT_MASK;
+ break;
+ case IX_QMGR_Q_SOURCE_ID_NF:
+ qi->statusCheckValue = IX_QMGR_Q_STATUS_NF_BIT_MASK;
+ qi->statusMask = IX_QMGR_Q_STATUS_NF_BIT_MASK;
+ break;
+ case IX_QMGR_Q_SOURCE_ID_F:
+ qi->statusCheckValue = IX_QMGR_Q_STATUS_F_BIT_MASK;
+ qi->statusMask = IX_QMGR_Q_STATUS_F_BIT_MASK;
+ break;
+ case IX_QMGR_Q_SOURCE_ID_NOT_E:
+ qi->statusCheckValue = 0;
+ qi->statusMask = IX_QMGR_Q_STATUS_E_BIT_MASK;
+ break;
+ case IX_QMGR_Q_SOURCE_ID_NOT_NE:
+ qi->statusCheckValue = 0;
+ qi->statusMask = IX_QMGR_Q_STATUS_NE_BIT_MASK;
+ break;
+ case IX_QMGR_Q_SOURCE_ID_NOT_NF:
+ qi->statusCheckValue = 0;
+ qi->statusMask = IX_QMGR_Q_STATUS_NF_BIT_MASK;
+ break;
+ case IX_QMGR_Q_SOURCE_ID_NOT_F:
+ qi->statusCheckValue = 0;
+ qi->statusMask = IX_QMGR_Q_STATUS_F_BIT_MASK;
+ break;
+ default:
+ /* Should never hit */
+ IX_OSAL_ASSERT(0);
+ break;
+ }
+
+ /* One nibble of status per queue so need to shift the
+ * check value and mask out to the correct position.
+ */
+ shiftVal = (qId % IX_QMGR_QUELOWSTAT_NUM_QUE_PER_WORD) *
+ IX_QMGR_QUELOWSTAT_BITS_PER_Q;
+
+ /* Calculate the which status word to check from the qId,
+ * 8 Qs status per word
+ */
+ qi->statusWordOffset = qId / IX_QMGR_QUELOWSTAT_NUM_QUE_PER_WORD;
+
+ qi->statusCheckValue <<= shiftVal;
+ qi->statusMask <<= shiftVal;
+ } else {
+ /* One status word */
+ qi->statusWordOffset = 0;
+ /* Single bits per queue and int source bit hardwired NE,
+ * Qs start at 32.
+ */
+ qi->statusMask = 1 << (qId - IX_QMGR_MIN_QUEUPP_QID);
+ qi->statusCheckValue = qi->statusMask;
+ }
+}
+#endif
+
+static void
+aqm_int_enable(struct ixpqmgr_softc *sc, int qId)
+{
+ bus_size_t reg;
+ uint32_t v;
+
+ if (qId < IX_QMGR_MIN_QUEUPP_QID)
+ reg = IX_QMGR_QUEIEREG0_OFFSET;
+ else
+ reg = IX_QMGR_QUEIEREG1_OFFSET;
+ v = aqm_reg_read(sc, reg);
+ aqm_reg_write(sc, reg, v | (1 << (qId % IX_QMGR_MIN_QUEUPP_QID)));
+
+ DPRINTF(sc->sc_dev, "%s(%u) 0x%lx: 0x%x => 0x%x\n",
+ __func__, qId, reg, v, aqm_reg_read(sc, reg));
+}
+
+static void
+aqm_int_disable(struct ixpqmgr_softc *sc, int qId)
+{
+ bus_size_t reg;
+ uint32_t v;
+
+ if (qId < IX_QMGR_MIN_QUEUPP_QID)
+ reg = IX_QMGR_QUEIEREG0_OFFSET;
+ else
+ reg = IX_QMGR_QUEIEREG1_OFFSET;
+ v = aqm_reg_read(sc, reg);
+ aqm_reg_write(sc, reg, v &~ (1 << (qId % IX_QMGR_MIN_QUEUPP_QID)));
+
+ DPRINTF(sc->sc_dev, "%s(%u) 0x%lx: 0x%x => 0x%x\n",
+ __func__, qId, reg, v, aqm_reg_read(sc, reg));
+}
+
+static unsigned
+log2(unsigned n)
+{
+ unsigned count;
+ /*
+ * N.B. this function will return 0 if supplied 0.
+ */
+ for (count = 0; n/2; count++)
+ n /= 2;
+ return count;
+}
+
+static __inline unsigned
+toAqmEntrySize(int entrySize)
+{
+ /* entrySize 1("00"),2("01"),4("10") */
+ return log2(entrySize);
+}
+
+static __inline unsigned
+toAqmBufferSize(unsigned bufferSizeInWords)
+{
+ /* bufferSize 16("00"),32("01),64("10"),128("11") */
+ return log2(bufferSizeInWords / IX_QMGR_MIN_BUFFER_SIZE);
+}
+
+static __inline unsigned
+toAqmWatermark(int watermark)
+{
+ /*
+ * Watermarks 0("000"),1("001"),2("010"),4("011"),
+ * 8("100"),16("101"),32("110"),64("111")
+ */
+ return log2(2 * watermark);
+}
+
+static void
+aqm_qcfg(struct ixpqmgr_softc *sc, int qId, u_int ne, u_int nf)
+{
+ const struct qmgrInfo *qi = &sc->qinfo[qId];
+ uint32_t qCfg;
+ uint32_t baseAddress;
+
+ /* Build config register */
+ qCfg = ((toAqmEntrySize(1) & IX_QMGR_ENTRY_SIZE_MASK) <<
+ IX_QMGR_Q_CONFIG_ESIZE_OFFSET)
+ | ((toAqmBufferSize(qi->qSizeInWords) & IX_QMGR_SIZE_MASK) <<
+ IX_QMGR_Q_CONFIG_BSIZE_OFFSET);
+
+ /* baseAddress, calculated relative to start address */
+ baseAddress = sc->aqmFreeSramAddress;
+
+ /* base address must be word-aligned */
+ KASSERT((baseAddress % IX_QMGR_BASE_ADDR_16_WORD_ALIGN) == 0,
+ ("address not word-aligned"));
+
+ /* Now convert to a 16 word pointer as required by QUECONFIG register */
+ baseAddress >>= IX_QMGR_BASE_ADDR_16_WORD_SHIFT;
+ qCfg |= baseAddress << IX_QMGR_Q_CONFIG_BADDR_OFFSET;
+
+ /* set watermarks */
+ qCfg |= (toAqmWatermark(ne) << IX_QMGR_Q_CONFIG_NE_OFFSET)
+ | (toAqmWatermark(nf) << IX_QMGR_Q_CONFIG_NF_OFFSET);
+
+ DPRINTF(sc->sc_dev, "%s(%u, %u, %u) 0x%x => 0x%x @ 0x%x\n",
+ __func__, qId, ne, nf,
+ aqm_reg_read(sc, IX_QMGR_Q_CONFIG_ADDR_GET(qId)),
+ qCfg, IX_QMGR_Q_CONFIG_ADDR_GET(qId));
+
+ aqm_reg_write(sc, IX_QMGR_Q_CONFIG_ADDR_GET(qId), qCfg);
+}
+
+static void
+aqm_srcsel_write(struct ixpqmgr_softc *sc, int qId, int sourceId)
+{
+ bus_size_t off;
+ uint32_t v;
+
+ /*
+ * Calculate the register offset; multiple queues split across registers
+ */
+ off = IX_QMGR_INT0SRCSELREG0_OFFSET +
+ ((qId / IX_QMGR_INTSRC_NUM_QUE_PER_WORD) * sizeof(uint32_t));
+
+ v = aqm_reg_read(sc, off);
+ if (off == IX_QMGR_INT0SRCSELREG0_OFFSET && qId == 0) {
+ /* Queue 0 at INT0SRCSELREG should not corrupt the value bit-3 */
+ v |= 0x7;
+ } else {
+ const uint32_t bpq = 32 / IX_QMGR_INTSRC_NUM_QUE_PER_WORD;
+ uint32_t mask;
+ int qshift;
+
+ qshift = (qId & (IX_QMGR_INTSRC_NUM_QUE_PER_WORD-1)) * bpq;
+ mask = ((1 << bpq) - 1) << qshift; /* q's status mask */
+
+ /* merge sourceId */
+ v = (v &~ mask) | ((sourceId << qshift) & mask);
+ }
+
+ DPRINTF(sc->sc_dev, "%s(%u, %u) 0x%x => 0x%x @ 0x%lx\n",
+ __func__, qId, sourceId, aqm_reg_read(sc, off), v, off);
+ aqm_reg_write(sc, off, v);
+}
+
+/*
+ * Reset AQM registers to default values.
+ */
+static void
+aqm_reset(struct ixpqmgr_softc *sc)
+{
+ int i;
+
+ /* Reset queues 0..31 status registers 0..3 */
+ aqm_reg_write(sc, IX_QMGR_QUELOWSTAT0_OFFSET,
+ IX_QMGR_QUELOWSTAT_RESET_VALUE);
+ aqm_reg_write(sc, IX_QMGR_QUELOWSTAT1_OFFSET,
+ IX_QMGR_QUELOWSTAT_RESET_VALUE);
+ aqm_reg_write(sc, IX_QMGR_QUELOWSTAT2_OFFSET,
+ IX_QMGR_QUELOWSTAT_RESET_VALUE);
+ aqm_reg_write(sc, IX_QMGR_QUELOWSTAT3_OFFSET,
+ IX_QMGR_QUELOWSTAT_RESET_VALUE);
+
+ /* Reset underflow/overflow status registers 0..1 */
+ aqm_reg_write(sc, IX_QMGR_QUEUOSTAT0_OFFSET,
+ IX_QMGR_QUEUOSTAT_RESET_VALUE);
+ aqm_reg_write(sc, IX_QMGR_QUEUOSTAT1_OFFSET,
+ IX_QMGR_QUEUOSTAT_RESET_VALUE);
+
+ /* Reset queues 32..63 nearly empty status registers */
+ aqm_reg_write(sc, IX_QMGR_QUEUPPSTAT0_OFFSET,
+ IX_QMGR_QUEUPPSTAT0_RESET_VALUE);
+
+ /* Reset queues 32..63 full status registers */
+ aqm_reg_write(sc, IX_QMGR_QUEUPPSTAT1_OFFSET,
+ IX_QMGR_QUEUPPSTAT1_RESET_VALUE);
+
+ /* Reset int0 status flag source select registers 0..3 */
+ aqm_reg_write(sc, IX_QMGR_INT0SRCSELREG0_OFFSET,
+ IX_QMGR_INT0SRCSELREG_RESET_VALUE);
+ aqm_reg_write(sc, IX_QMGR_INT0SRCSELREG1_OFFSET,
+ IX_QMGR_INT0SRCSELREG_RESET_VALUE);
+ aqm_reg_write(sc, IX_QMGR_INT0SRCSELREG2_OFFSET,
+ IX_QMGR_INT0SRCSELREG_RESET_VALUE);
+ aqm_reg_write(sc, IX_QMGR_INT0SRCSELREG3_OFFSET,
+ IX_QMGR_INT0SRCSELREG_RESET_VALUE);
+
+ /* Reset queue interrupt enable register 0..1 */
+ aqm_reg_write(sc, IX_QMGR_QUEIEREG0_OFFSET,
+ IX_QMGR_QUEIEREG_RESET_VALUE);
+ aqm_reg_write(sc, IX_QMGR_QUEIEREG1_OFFSET,
+ IX_QMGR_QUEIEREG_RESET_VALUE);
+
+ /* Reset queue interrupt register 0..1 */
+ aqm_reg_write(sc, IX_QMGR_QINTREG0_OFFSET, IX_QMGR_QINTREG_RESET_VALUE);
+ aqm_reg_write(sc, IX_QMGR_QINTREG1_OFFSET, IX_QMGR_QINTREG_RESET_VALUE);
+
+ /* Reset queue configuration words 0..63 */
+ for (i = 0; i < IX_QMGR_MAX_NUM_QUEUES; i++)
+ aqm_reg_write(sc, sc->qinfo[i].qConfigRegAddr,
+ IX_QMGR_QUECONFIG_RESET_VALUE);
+
+ /* XXX zero SRAM to simplify debugging */
+ for (i = IX_QMGR_QUEBUFFER_SPACE_OFFSET;
+ i < IX_QMGR_AQM_SRAM_SIZE_IN_BYTES; i += sizeof(uint32_t))
+ aqm_reg_write(sc, i, 0);
+}
+
+static device_method_t ixpqmgr_methods[] = {
+ DEVMETHOD(device_probe, ixpqmgr_probe),
+ DEVMETHOD(device_attach, ixpqmgr_attach),
+ DEVMETHOD(device_detach, ixpqmgr_detach),
+
+ { 0, 0 }
+};
+
+static driver_t ixpqmgr_driver = {
+ "ixpqmgr",
+ ixpqmgr_methods,
+ sizeof(struct ixpqmgr_softc),
+};
+static devclass_t ixpqmgr_devclass;
+
+DRIVER_MODULE(ixpqmgr, ixp, ixpqmgr_driver, ixpqmgr_devclass, 0, 0);
diff --git a/sys/arm/xscale/ixp425/ixp425_qmgr.h b/sys/arm/xscale/ixp425/ixp425_qmgr.h
new file mode 100644
index 000000000000..af021d553990
--- /dev/null
+++ b/sys/arm/xscale/ixp425/ixp425_qmgr.h
@@ -0,0 +1,243 @@
+/*-
+ * Copyright (c) 2006 Sam Leffler, Errno Consulting
+ * 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,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ * redistribution must be conditioned upon including a substantially
+ * similar Disclaimer requirement for further binary redistribution.
+ *
+ * NO WARRANTY
+ * 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 NONINFRINGEMENT, MERCHANTIBILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ *
+ * $FreeBSD$
+ */
+
+/*-
+ * Copyright (c) 2001-2005, Intel Corporation.
+ * 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 Intel Corporation nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ *
+ * 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 ARM_XSCALE_IXP425_QMGR_H
+#define ARM_XSCALE_IXP425_QMGR_H
+
+#define IX_QMGR_MAX_NUM_QUEUES 64
+#define IX_QMGR_MIN_QUEUPP_QID 32
+
+#define IX_QMGR_MIN_ENTRY_SIZE_IN_WORDS 16
+
+/* Total size of SRAM */
+#define IX_QMGR_AQM_SRAM_SIZE_IN_BYTES 0x4000
+
+#define IX_QMGR_Q_PRIORITY_0 0
+#define IX_QMGR_Q_PRIORITY_1 1
+#define IX_QMGR_Q_PRIORITY_2 2
+#define IX_QMGR_NUM_PRIORITY_LEVELS 3 /* number of priority levels */
+
+#define IX_QMGR_Q_STATUS_E_BIT_MASK 0x1 /* Empty */
+#define IX_QMGR_Q_STATUS_NE_BIT_MASK 0x2 /* Nearly Empty */
+#define IX_QMGR_Q_STATUS_NF_BIT_MASK 0x4 /* Nearly Full */
+#define IX_QMGR_Q_STATUS_F_BIT_MASK 0x8 /* Full */
+#define IX_QMGR_Q_STATUS_UF_BIT_MASK 0x10 /* Underflow */
+#define IX_QMGR_Q_STATUS_OF_BIT_MASK 0x20 /* Overflow */
+
+#define IX_QMGR_Q_SOURCE_ID_E 0 /* Q Empty after last read */
+#define IX_QMGR_Q_SOURCE_ID_NE 1 /* Q Nearly Empty after last read */
+#define IX_QMGR_Q_SOURCE_ID_NF 2 /* Q Nearly Full after last write */
+#define IX_QMGR_Q_SOURCE_ID_F 3 /* Q Full after last write */
+#define IX_QMGR_Q_SOURCE_ID_NOT_E 4 /* Q !Empty after last write */
+#define IX_QMGR_Q_SOURCE_ID_NOT_NE 5 /* Q !Nearly Empty after last write */
+#define IX_QMGR_Q_SOURCE_ID_NOT_NF 6 /* Q !Nearly Full after last read */
+#define IX_QMGR_Q_SOURCE_ID_NOT_F 7 /* Q !Full after last read */
+
+#define IX_QMGR_UNDERFLOW_BIT_OFFSET 0x0 /* underflow bit mask */
+#define IX_QMGR_OVERFLOW_BIT_OFFSET 0x1 /* overflow bit mask */
+
+#define IX_QMGR_QUEACC0_OFFSET 0x0000 /* q 0 access register */
+#define IX_QMGR_QUEACC_SIZE 0x4/*words*/
+
+#define IX_QMGR_QUELOWSTAT0_OFFSET 0x400 /* Q status, q's 0-7 */
+#define IX_QMGR_QUELOWSTAT1_OFFSET 0x404 /* Q status, q's 8-15 */
+#define IX_QMGR_QUELOWSTAT2_OFFSET 0x408 /* Q status, q's 16-23 */
+#define IX_QMGR_QUELOWSTAT3_OFFSET 0x40c /* Q status, q's 24-31 */
+
+/* Queue status register Q status bits mask */
+#define IX_QMGR_QUELOWSTAT_QUE_STS_BITS_MASK 0xF
+/* Size of queue 0-31 status register */
+#define IX_QMGR_QUELOWSTAT_SIZE 0x4 /*words*/
+#define IX_QMGR_QUELOWSTAT_NUM_QUE_PER_WORD 8 /* # status/word */
+
+#define IX_QMGR_QUEUOSTAT0_OFFSET 0x410 /* Q UF/OF status, q's 0-15 */
+#define IX_QMGR_QUEUOSTAT1_OFFSET 0x414 /* Q UF/OF status, q's 16-31 */
+
+#define IX_QMGR_QUEUOSTAT_NUM_QUE_PER_WORD 16 /* # UF/OF status/word */
+
+#define IX_QMGR_QUEUPPSTAT0_OFFSET 0x418 /* NE status, q's 32-63 */
+#define IX_QMGR_QUEUPPSTAT1_OFFSET 0x41c /* F status, q's 32-63 */
+
+#define IX_QMGR_INT0SRCSELREG0_OFFSET 0x420 /* INT src select, q's 0-7 */
+#define IX_QMGR_INT0SRCSELREG1_OFFSET 0x424 /* INT src select, q's 8-15 */
+#define IX_QMGR_INT0SRCSELREG2_OFFSET 0x428 /* INT src select, q's 16-23 */
+#define IX_QMGR_INT0SRCSELREG3_OFFSET 0x42c /* INT src select, q's 24-31 */
+
+#define IX_QMGR_INTSRC_NUM_QUE_PER_WORD 8 /* # INT src select/word */
+
+#define IX_QMGR_QUEIEREG0_OFFSET 0x430 /* INT enable, q's 0-31 */
+#define IX_QMGR_QUEIEREG1_OFFSET 0x434 /* INT enable, q's 32-63 */
+#define IX_QMGR_QINTREG0_OFFSET 0x438 /* INT status, q's 0-31 */
+#define IX_QMGR_QINTREG1_OFFSET 0x43c /* INT status, q's 32-63 */
+
+#define IX_QMGR_QUECONFIG_BASE_OFFSET 0x2000 /* Q config register, q 0 */
+
+#define IX_QMGR_QUECONFIG_SIZE 0x100 /* total size of Q config regs*/
+
+#define IX_QMGR_QUEBUFFER_SPACE_OFFSET 0x2100 /* start of SRAM */
+
+/* Total bits in a word */
+#define BITS_PER_WORD 32
+
+/* Size of queue buffer space */
+#define IX_QMGR_QUE_BUFFER_SPACE_SIZE 0x1F00
+
+/*
+ * This macro will return the address of the access register for the
+ * queue specified by qId
+ */
+#define IX_QMGR_Q_ACCESS_ADDR_GET(qId)\
+ (((qId) * (IX_QMGR_QUEACC_SIZE * sizeof(uint32_t)))\
+ + IX_QMGR_QUEACC0_OFFSET)
+
+/*
+ * Bit location of bit-3 of INT0SRCSELREG0 register to enabled
+ * sticky interrupt register.
+ */
+#define IX_QMGR_INT0SRCSELREG0_BIT3 3
+
+/*
+ * These defines are the bit offsets of the various fields of
+ * the queue configuration register.
+ */
+#if 0
+#define IX_QMGR_Q_CONFIG_WRPTR_OFFSET 0x00
+#define IX_QMGR_Q_CONFIG_RDPTR_OFFSET 0x07
+#define IX_QMGR_Q_CONFIG_BADDR_OFFSET 0x0E
+#define IX_QMGR_Q_CONFIG_ESIZE_OFFSET 0x16
+#define IX_QMGR_Q_CONFIG_BSIZE_OFFSET 0x18
+#define IX_QMGR_Q_CONFIG_NE_OFFSET 0x1A
+#define IX_QMGR_Q_CONFIG_NF_OFFSET 0x1D
+
+#define IX_QMGR_NE_NF_CLEAR_MASK 0x03FFFFFF
+#define IX_QMGR_NE_MASK 0x7
+#define IX_QMGR_NF_MASK 0x7
+#define IX_QMGR_SIZE_MASK 0x3
+#define IX_QMGR_ENTRY_SIZE_MASK 0x3
+#define IX_QMGR_BADDR_MASK 0x003FC000
+#define IX_QMGR_RDPTR_MASK 0x7F
+#define IX_QMGR_WRPTR_MASK 0x7F
+#define IX_QMGR_RDWRPTR_MASK 0x00003FFF
+#else
+#define IX_QMGR_Q_CONFIG_WRPTR_OFFSET 0
+#define IX_QMGR_WRPTR_MASK 0x7F
+#define IX_QMGR_Q_CONFIG_RDPTR_OFFSET 7
+#define IX_QMGR_RDPTR_MASK 0x7F
+#define IX_QMGR_Q_CONFIG_BADDR_OFFSET 14
+#define IX_QMGR_BADDR_MASK 0x3FC000 /* XXX not used */
+#define IX_QMGR_Q_CONFIG_ESIZE_OFFSET 22
+#define IX_QMGR_ENTRY_SIZE_MASK 0x3
+#define IX_QMGR_Q_CONFIG_BSIZE_OFFSET 24
+#define IX_QMGR_SIZE_MASK 0x3
+#define IX_QMGR_Q_CONFIG_NE_OFFSET 26
+#define IX_QMGR_NE_MASK 0x7
+#define IX_QMGR_Q_CONFIG_NF_OFFSET 29
+#define IX_QMGR_NF_MASK 0x7
+
+#define IX_QMGR_RDWRPTR_MASK 0x00003FFF
+#define IX_QMGR_NE_NF_CLEAR_MASK 0x03FFFFFF
+#endif
+
+#define IX_QMGR_BASE_ADDR_16_WORD_ALIGN 64
+#define IX_QMGR_BASE_ADDR_16_WORD_SHIFT 6
+
+#define IX_QMGR_AQM_ADDRESS_SPACE_SIZE_IN_WORDS 0x1000
+
+/* Base address of AQM SRAM */
+#define IX_QMGR_AQM_SRAM_BASE_ADDRESS_OFFSET \
+((IX_QMGR_QUECONFIG_BASE_OFFSET) + (IX_QMGR_QUECONFIG_SIZE))
+
+/* Min buffer size used for generating buffer size in QUECONFIG */
+#define IX_QMGR_MIN_BUFFER_SIZE 16
+
+/* Reset values of QMgr hardware registers */
+#define IX_QMGR_QUELOWSTAT_RESET_VALUE 0x33333333
+#define IX_QMGR_QUEUOSTAT_RESET_VALUE 0x00000000
+#define IX_QMGR_QUEUPPSTAT0_RESET_VALUE 0xFFFFFFFF
+#define IX_QMGR_QUEUPPSTAT1_RESET_VALUE 0x00000000
+#define IX_QMGR_INT0SRCSELREG_RESET_VALUE 0x00000000
+#define IX_QMGR_QUEIEREG_RESET_VALUE 0x00000000
+#define IX_QMGR_QINTREG_RESET_VALUE 0xFFFFFFFF
+#define IX_QMGR_QUECONFIG_RESET_VALUE 0x00000000
+
+#define IX_QMGR_QUELOWSTAT_BITS_PER_Q \
+ (BITS_PER_WORD/IX_QMGR_QUELOWSTAT_NUM_QUE_PER_WORD)
+
+#define IX_QMGR_QUELOWSTAT_QID_MASK 0x7
+#define IX_QMGR_Q_CONFIG_ADDR_GET(qId)\
+ (((qId) * sizeof(uint32_t)) + IX_QMGR_QUECONFIG_BASE_OFFSET)
+
+#define IX_QMGR_ENTRY1_OFFSET 0
+#define IX_QMGR_ENTRY2_OFFSET 1
+#define IX_QMGR_ENTRY4_OFFSET 3
+
+int ixpqmgr_qconfig(int qId, int qSizeInWords, int ne, int nf, int srcSel,
+ void (*cb)(int, void *), void *cbarg);
+int ixpqmgr_qwrite(int qId, uint32_t entry);
+int ixpqmgr_qread(int qId, uint32_t *entry);
+int ixpqmgr_qreadm(int qId, uint32_t n, uint32_t *p);
+uint32_t ixpqmgr_getqstatus(int qId);
+uint32_t ixpqmgr_getqconfig(int qId);
+void ixpqmgr_notify_enable(int qId, int srcSel);
+void ixpqmgr_notify_disable(int qId);
+void ixpqmgr_dump(void);
+
+#endif /* ARM_XSCALE_IXP425_QMGR_H */
diff --git a/sys/arm/xscale/ixp425/ixp425_space.c b/sys/arm/xscale/ixp425/ixp425_space.c
new file mode 100644
index 000000000000..816ff5055680
--- /dev/null
+++ b/sys/arm/xscale/ixp425/ixp425_space.c
@@ -0,0 +1,215 @@
+/* $NetBSD: ixp425_space.c,v 1.6 2006/04/10 03:36:03 simonb Exp $ */
+
+/*
+ * Copyright (c) 2003
+ * Ichiro FUKUHARA <ichiro@ichiro.org>.
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ichiro FUKUHARA.
+ * 4. The name of the company nor the name of the author may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ICHIRO FUKUHARA ``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 ICHIRO FUKUHARA OR THE VOICES IN HIS HEAD BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * bus_space I/O functions for ixp425
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+
+#include <machine/pcb.h>
+
+#include <vm/vm.h>
+#include <vm/vm_kern.h>
+#include <vm/pmap.h>
+#include <vm/vm_page.h>
+#include <vm/vm_extern.h>
+
+#include <machine/bus.h>
+
+#include <arm/xscale/ixp425/ixp425reg.h>
+#include <arm/xscale/ixp425/ixp425var.h>
+
+/* Proto types for all the bus_space structure functions */
+bs_protos(ixp425);
+bs_protos(generic);
+bs_protos(generic_armv4);
+
+struct bus_space ixp425_bs_tag = {
+ /* cookie */
+ .bs_cookie = (void *) 0,
+
+ /* mapping/unmapping */
+ .bs_map = ixp425_bs_map,
+ .bs_unmap = ixp425_bs_unmap,
+ .bs_subregion = ixp425_bs_subregion,
+
+ /* allocation/deallocation */
+ .bs_alloc = ixp425_bs_alloc,
+ .bs_free = ixp425_bs_free,
+
+ /* barrier */
+ .bs_barrier = ixp425_bs_barrier,
+
+ /* read (single) */
+ .bs_r_1 = generic_bs_r_1,
+ .bs_r_2 = generic_armv4_bs_r_2,
+ .bs_r_4 = generic_bs_r_4,
+ .bs_r_8 = NULL,
+
+ /* read multiple */
+ .bs_rm_1 = generic_bs_rm_1,
+ .bs_rm_2 = generic_armv4_bs_rm_2,
+ .bs_rm_4 = generic_bs_rm_4,
+ .bs_rm_8 = NULL,
+
+ /* read region */
+ .bs_rr_1 = generic_bs_rr_1,
+ .bs_rr_2 = generic_armv4_bs_rr_2,
+ .bs_rr_4 = generic_bs_rr_4,
+ .bs_rr_8 = NULL,
+
+ /* write (single) */
+ .bs_w_1 = generic_bs_w_1,
+ .bs_w_2 = generic_armv4_bs_w_2,
+ .bs_w_4 = generic_bs_w_4,
+ .bs_w_8 = NULL,
+
+ /* write multiple */
+ .bs_wm_1 = generic_bs_wm_1,
+ .bs_wm_2 = generic_armv4_bs_wm_2,
+ .bs_wm_4 = generic_bs_wm_4,
+ .bs_wm_8 = NULL,
+
+ /* write region */
+ .bs_wr_1 = generic_bs_wr_1,
+ .bs_wr_2 = generic_armv4_bs_wr_2,
+ .bs_wr_4 = generic_bs_wr_4,
+ .bs_wr_8 = NULL,
+
+ /* set multiple */
+ /* XXX not implemented */
+
+ /* set region */
+ .bs_sr_1 = NULL,
+ .bs_sr_2 = generic_armv4_bs_sr_2,
+ .bs_sr_4 = generic_bs_sr_4,
+ .bs_sr_8 = NULL,
+
+ /* copy */
+ .bs_c_1 = NULL,
+ .bs_c_2 = generic_armv4_bs_c_2,
+ .bs_c_4 = NULL,
+ .bs_c_8 = NULL,
+};
+
+int
+ixp425_bs_map(void *t, bus_addr_t bpa, bus_size_t size,
+ int cacheable, bus_space_handle_t *bshp)
+{
+ const struct pmap_devmap *pd;
+ vm_paddr_t startpa, endpa, pa, offset;
+ vm_offset_t va;
+ pt_entry_t *pte;
+
+ if ((pd = pmap_devmap_find_pa(bpa, size)) != NULL) {
+ /* Device was statically mapped. */
+ *bshp = pd->pd_va + (bpa - pd->pd_pa);
+ return (0);
+ }
+
+ endpa = round_page(bpa + size);
+ offset = bpa & PAGE_MASK;
+ startpa = trunc_page(bpa);
+
+ va = kmem_alloc(kernel_map, endpa - startpa);
+ if (va == 0)
+ return (ENOMEM);
+
+ *bshp = va + offset;
+
+ for (pa = startpa; pa < endpa; pa += PAGE_SIZE, va += PAGE_SIZE) {
+ pmap_kenter(va, pa);
+ pte = vtopte(va);
+ *pte &= ~L2_S_CACHE_MASK;
+ PTE_SYNC(pte);
+ }
+
+ return (0);
+}
+
+void
+ixp425_bs_unmap(void *t, bus_space_handle_t h, bus_size_t size)
+{
+ vm_offset_t va, endva;
+
+ if (pmap_devmap_find_va((vm_offset_t)t, size) != NULL) {
+ /* Device was statically mapped; nothing to do. */
+ return;
+ }
+
+ endva = round_page((vm_offset_t)t + size);
+ va = trunc_page((vm_offset_t)t);
+
+ while (va < endva) {
+ pmap_kremove(va);
+ va += PAGE_SIZE;
+ }
+ kmem_free(kernel_map, va, endva - va);
+}
+
+int
+ixp425_bs_alloc(void *t, bus_addr_t rstart, bus_addr_t rend,
+ bus_size_t size, bus_size_t alignment, bus_size_t boundary, int cacheable,
+ bus_addr_t *bpap, bus_space_handle_t *bshp)
+{
+ panic("ixp425_bs_alloc(): not implemented");
+}
+
+void
+ixp425_bs_free(void *t, bus_space_handle_t bsh, bus_size_t size)
+{
+ panic("ixp425_bs_free(): not implemented");
+}
+
+int
+ixp425_bs_subregion(void *t, bus_space_handle_t bsh, bus_size_t offset,
+ bus_size_t size, bus_space_handle_t *nbshp)
+{
+ *nbshp = bsh + offset;
+ return (0);
+}
+
+void
+ixp425_bs_barrier(void *t, bus_space_handle_t bsh, bus_size_t offset,
+ bus_size_t len, int flags)
+{
+ /* Nothing to do. */
+}
diff --git a/sys/arm/xscale/ixp425/ixp425_timer.c b/sys/arm/xscale/ixp425/ixp425_timer.c
new file mode 100644
index 000000000000..0fa9d1f1419b
--- /dev/null
+++ b/sys/arm/xscale/ixp425/ixp425_timer.c
@@ -0,0 +1,267 @@
+/* $NetBSD: ixp425_timer.c,v 1.11 2006/04/10 03:36:03 simonb Exp $ */
+
+/*
+ * Copyright (c) 2003
+ * Ichiro FUKUHARA <ichiro@ichiro.org>.
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ichiro FUKUHARA.
+ * 4. The name of the company nor the name of the author may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ICHIRO FUKUHARA ``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 ICHIRO FUKUHARA OR THE VOICES IN HIS HEAD BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/time.h>
+#include <sys/bus.h>
+#include <sys/resource.h>
+#include <sys/rman.h>
+#include <sys/timetc.h>
+
+#include <machine/bus.h>
+#include <machine/cpu.h>
+#include <machine/cpufunc.h>
+#include <machine/frame.h>
+#include <machine/resource.h>
+#include <machine/intr.h>
+#include <arm/xscale/ixp425/ixp425reg.h>
+#include <arm/xscale/ixp425/ixp425var.h>
+
+static uint32_t counts_per_hz;
+
+/* callback functions for intr_functions */
+void ixpclk_intr(void *);
+
+struct ixpclk_softc {
+ device_t sc_dev;
+ bus_addr_t sc_baseaddr;
+ bus_space_tag_t sc_iot;
+ bus_space_handle_t sc_ioh;
+};
+
+static unsigned ixp425_timer_get_timecount(struct timecounter *tc);
+
+#ifndef IXP425_CLOCK_FREQ
+#define COUNTS_PER_SEC 66666600 /* 66MHz */
+#else
+#define COUNTS_PER_SEC IXP425_CLOCK_FREQ
+#endif
+#define COUNTS_PER_USEC ((COUNTS_PER_SEC / 1000000) + 1)
+
+static struct ixpclk_softc *ixpclk_sc = NULL;
+
+#define GET_TS_VALUE(sc) (*(volatile u_int32_t *) \
+ (IXP425_TIMER_VBASE + IXP425_OST_TS))
+
+static struct timecounter ixp425_timer_timecounter = {
+ ixp425_timer_get_timecount, /* get_timecount */
+ NULL, /* no poll_pps */
+ ~0u, /* counter_mask */
+ COUNTS_PER_SEC, /* frequency */
+ "IXP425 Timer", /* name */
+ 1000, /* quality */
+};
+
+static int
+ixpclk_probe(device_t dev)
+{
+ device_set_desc(dev, "IXP425 Timer");
+ return (0);
+}
+
+static int
+ixpclk_attach(device_t dev)
+{
+ struct ixpclk_softc *sc = device_get_softc(dev);
+ struct ixp425_softc *sa = device_get_softc(device_get_parent(dev));
+
+ ixpclk_sc = sc;
+
+ sc->sc_dev = dev;
+ sc->sc_iot = sa->sc_iot;
+ sc->sc_baseaddr = IXP425_TIMER_HWBASE;
+
+ if (bus_space_map(sc->sc_iot, sc->sc_baseaddr, 8, 0,
+ &sc->sc_ioh))
+ panic("%s: Cannot map registers", device_get_name(dev));
+
+ return (0);
+}
+
+static device_method_t ixpclk_methods[] = {
+ DEVMETHOD(device_probe, ixpclk_probe),
+ DEVMETHOD(device_attach, ixpclk_attach),
+ {0, 0},
+};
+
+static driver_t ixpclk_driver = {
+ "ixpclk",
+ ixpclk_methods,
+ sizeof(struct ixpclk_softc),
+};
+static devclass_t ixpclk_devclass;
+
+DRIVER_MODULE(ixpclk, ixp, ixpclk_driver, ixpclk_devclass, 0, 0);
+static unsigned
+ixp425_timer_get_timecount(struct timecounter *tc)
+{
+ uint32_t ret;
+
+ ret = GET_TS_VALUE(sc);
+ return (ret);
+}
+
+/*
+ * cpu_initclocks:
+ *
+ * Initialize the clock and get them going.
+ */
+void
+cpu_initclocks(void)
+{
+ struct ixpclk_softc* sc = ixpclk_sc;
+ struct resource *irq;
+ device_t dev = sc->sc_dev;
+ u_int oldirqstate;
+ int rid = 0;
+ void *ihl;
+
+ if (hz < 50 || COUNTS_PER_SEC % hz) {
+ printf("Cannot get %d Hz clock; using 100 Hz\n", hz);
+ hz = 100;
+ }
+ tick = 1000000 / hz; /* number of microseconds between interrupts */
+
+ /*
+ * We only have one timer available; stathz and profhz are
+ * always left as 0 (the upper-layer clock code deals with
+ * this situation).
+ */
+ if (stathz != 0)
+ printf("Cannot get %d Hz statclock\n", stathz);
+ stathz = 0;
+
+ if (profhz != 0)
+ printf("Cannot get %d Hz profclock\n", profhz);
+ profhz = 0;
+
+ /* Report the clock frequency. */
+
+ oldirqstate = disable_interrupts(I32_bit);
+
+ irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, IXP425_INT_TMR0,
+ IXP425_INT_TMR0, 1, RF_ACTIVE);
+ if (!irq)
+ panic("Unable to setup the clock irq handler.\n");
+ else
+ bus_setup_intr(dev, irq, INTR_TYPE_CLK | INTR_FAST,
+ ixpclk_intr, NULL, &ihl);
+
+ /* Set up the new clock parameters. */
+
+ /* clear interrupt */
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, IXP425_OST_STATUS,
+ OST_WARM_RESET | OST_WDOG_INT | OST_TS_INT |
+ OST_TIM1_INT | OST_TIM0_INT);
+
+ counts_per_hz = COUNTS_PER_SEC / hz;
+
+ /* reload value & Timer enable */
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, IXP425_OST_TIM0_RELOAD,
+ (counts_per_hz & TIMERRELOAD_MASK) | OST_TIMER_EN);
+
+ tc_init(&ixp425_timer_timecounter);
+ restore_interrupts(oldirqstate);
+ rid = 0;
+}
+
+
+/*
+ * DELAY:
+ *
+ * Delay for at least N microseconds.
+ */
+void
+DELAY(int n)
+{
+ u_int32_t first, last;
+ int usecs;
+
+ if (n == 0)
+ return;
+
+ /*
+ * Clamp the timeout at a maximum value (about 32 seconds with
+ * a 66MHz clock). *Nobody* should be delay()ing for anywhere
+ * near that length of time and if they are, they should be hung
+ * out to dry.
+ */
+ if (n >= (0x80000000U / COUNTS_PER_USEC))
+ usecs = (0x80000000U / COUNTS_PER_USEC) - 1;
+ else
+ usecs = n * COUNTS_PER_USEC;
+
+ /* Note: Timestamp timer counts *up*, unlike the other timers */
+ first = GET_TS_VALUE();
+
+ while (usecs > 0) {
+ last = GET_TS_VALUE();
+ usecs -= (int)(last - first);
+ first = last;
+ }
+}
+
+/*
+ * ixpclk_intr:
+ *
+ * Handle the hardclock interrupt.
+ */
+void
+ixpclk_intr(void *arg)
+{
+ struct ixpclk_softc* sc = ixpclk_sc;
+ struct trapframe *frame = arg;
+
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, IXP425_OST_STATUS,
+ OST_TIM0_INT);
+
+ hardclock(TRAPF_USERMODE(frame), TRAPF_PC(frame));
+}
+
+void
+cpu_startprofclock(void)
+{
+}
+
+void
+cpu_stopprofclock(void)
+{
+}
diff --git a/sys/arm/xscale/ixp425/ixp425_wdog.c b/sys/arm/xscale/ixp425/ixp425_wdog.c
new file mode 100644
index 000000000000..a94ef0a83c92
--- /dev/null
+++ b/sys/arm/xscale/ixp425/ixp425_wdog.c
@@ -0,0 +1,118 @@
+/*-
+ * Copyright (c) 2006 Sam Leffler. 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>
+__FBSDID("$FreeBSD$");
+
+/*
+ * IXP425 Watchdog Timer Support.
+ */
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/time.h>
+#include <sys/bus.h>
+#include <sys/resource.h>
+#include <sys/rman.h>
+#include <sys/watchdog.h>
+
+#include <machine/bus.h>
+#include <machine/cpu.h>
+#include <machine/cpufunc.h>
+#include <machine/frame.h>
+#include <machine/resource.h>
+#include <machine/intr.h>
+
+#include <arm/xscale/ixp425/ixp425reg.h>
+#include <arm/xscale/ixp425/ixp425var.h>
+
+struct ixpwdog_softc {
+ device_t sc_dev;
+};
+
+static __inline uint32_t
+RD4(struct ixpwdog_softc *sc, bus_size_t off)
+{
+ return bus_space_read_4(&ixp425_bs_tag, IXP425_TIMER_VBASE, off);
+}
+
+static __inline void
+WR4(struct ixpwdog_softc *sc, bus_size_t off, uint32_t val)
+{
+ bus_space_write_4(&ixp425_bs_tag, IXP425_TIMER_VBASE, off, val);
+}
+
+static void
+ixp425_watchdog(void *arg, u_int cmd, int *error)
+{
+ struct ixpwdog_softc *sc = arg;
+ u_int u = cmd & WD_INTERVAL;
+
+ WR4(sc, IXP425_OST_WDOG_KEY, OST_WDOG_KEY_MAJICK);
+ if (cmd && 4 <= u && u <= 35) {
+ WR4(sc, IXP425_OST_WDOG_ENAB, 0);
+ /* approximate 66.66MHz cycles */
+ WR4(sc, IXP425_OST_WDOG, 2<<(u - 4));
+ /* NB: reset on timer expiration */
+ WR4(sc, IXP425_OST_WDOG_ENAB,
+ OST_WDOG_ENAB_CNT_ENA | OST_WDOG_ENAB_RST_ENA);
+ *error = 0;
+ } else {
+ /* disable watchdog */
+ WR4(sc, IXP425_OST_WDOG_ENAB, 0);
+ }
+ WR4(sc, IXP425_OST_WDOG_KEY, 0);
+}
+
+static int
+ixpwdog_probe(device_t dev)
+{
+ device_set_desc(dev, "IXP425 Watchdog Timer");
+ return (0);
+}
+
+static int
+ixpwdog_attach(device_t dev)
+{
+ struct ixpwdog_softc *sc = device_get_softc(dev);
+
+ sc->sc_dev = dev;
+
+ EVENTHANDLER_REGISTER(watchdog_list, ixp425_watchdog, sc, 0);
+ return (0);
+}
+
+static device_method_t ixpwdog_methods[] = {
+ DEVMETHOD(device_probe, ixpwdog_probe),
+ DEVMETHOD(device_attach, ixpwdog_attach),
+ {0, 0},
+};
+
+static driver_t ixpwdog_driver = {
+ "ixpwdog",
+ ixpwdog_methods,
+ sizeof(struct ixpwdog_softc),
+};
+static devclass_t ixpwdog_devclass;
+DRIVER_MODULE(ixpwdog, ixp, ixpwdog_driver, ixpwdog_devclass, 0, 0);
diff --git a/sys/arm/xscale/ixp425/ixp425reg.h b/sys/arm/xscale/ixp425/ixp425reg.h
new file mode 100644
index 000000000000..55e1fd938c94
--- /dev/null
+++ b/sys/arm/xscale/ixp425/ixp425reg.h
@@ -0,0 +1,582 @@
+/* $NetBSD: ixp425reg.h,v 1.19 2005/12/11 12:16:51 christos Exp $ */
+/*
+ * Copyright (c) 2003
+ * Ichiro FUKUHARA <ichiro@ichiro.org>.
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ichiro FUKUHARA.
+ * 4. The name of the company nor the name of the author may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ICHIRO FUKUHARA ``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 ICHIRO FUKUHARA OR THE VOICES IN HIS HEAD 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.
+ *
+ * $FreeBSD$
+ *
+ */
+
+#ifndef _IXP425REG_H_
+#define _IXP425REG_H_
+
+/*
+ * Physical memory map for the Intel IXP425
+ */
+/*
+ * CC00 00FF ---------------------------
+ * SDRAM Configuration Registers
+ * CC00 0000 ---------------------------
+ *
+ * C800 BFFF ---------------------------
+ * System and Peripheral Registers
+ * C800 0000 ---------------------------
+ * Expansion Bus Configuration Registers
+ * C400 0000 ---------------------------
+ * PCI Configuration and Status Registers
+ * C000 0000 ---------------------------
+ *
+ * 6400 0000 ---------------------------
+ * Queue manager
+ * 6000 0000 ---------------------------
+ * Expansion Bus Data
+ * 5000 0000 ---------------------------
+ * PCI Data
+ * 4800 0000 ---------------------------
+ *
+ * 4000 0000 ---------------------------
+ * SDRAM
+ * 1000 0000 ---------------------------
+ */
+
+/*
+ * Virtual memory map for the Intel IXP425 integrated devices
+ */
+/*
+ * FFFF FFFF ---------------------------
+ *
+ * FC00 0000 ---------------------------
+ * PCI Data (memory space)
+ * F800 0000 ---------------------------
+ *
+ * F020 1000 ---------------------------
+ * SDRAM Controller
+ * F020 0000 ---------------------------
+ *
+ * F001 2000 ---------------------------
+ * PCI Configuration and Status Registers
+ * F001 1000 ---------------------------
+ * Expansion bus Configuration Registers
+ * F001 0000 ---------------------------
+ * System and Peripheral Registers
+ * VA F000 0000 = PA C800 0000 (SIZE 0x10000)
+ * F000 0000 ---------------------------
+ *
+ * 0000 0000 ---------------------------
+ *
+ */
+
+/* Physical/Virtual address for I/O space */
+
+#define IXP425_IO_VBASE 0xf0000000UL
+#define IXP425_IO_HWBASE 0xc8000000UL
+#define IXP425_IO_SIZE 0x00010000UL
+
+/* Offset */
+
+#define IXP425_UART0_OFFSET 0x00000000UL
+#define IXP425_UART1_OFFSET 0x00001000UL
+#define IXP425_PMC_OFFSET 0x00002000UL
+#define IXP425_INTR_OFFSET 0x00003000UL
+#define IXP425_GPIO_OFFSET 0x00004000UL
+#define IXP425_TIMER_OFFSET 0x00005000UL
+#define IXP425_NPE_A_OFFSET 0x00006000UL /* Not User Programmable */
+#define IXP425_NPE_B_OFFSET 0x00007000UL /* Not User Programmable */
+#define IXP425_NPE_C_OFFSET 0x00008000UL /* Not User Programmable */
+#define IXP425_MAC_A_OFFSET 0x00009000UL
+#define IXP425_MAC_B_OFFSET 0x0000a000UL
+#define IXP425_USB_OFFSET 0x0000b000UL
+
+#define IXP425_REG_SIZE 0x1000
+
+/*
+ * UART
+ * UART0 0xc8000000
+ * UART1 0xc8001000
+ *
+ */
+/* I/O space */
+#define IXP425_UART0_HWBASE (IXP425_IO_HWBASE + IXP425_UART0_OFFSET)
+#define IXP425_UART1_HWBASE (IXP425_IO_HWBASE + IXP425_UART1_OFFSET)
+
+#define IXP425_UART0_VBASE (IXP425_IO_VBASE + IXP425_UART0_OFFSET)
+ /* 0xf0000000 */
+#define IXP425_UART1_VBASE (IXP425_IO_VBASE + IXP425_UART1_OFFSET)
+ /* 0xf0001000 */
+
+#define IXP425_UART_FREQ 14745600
+
+#define IXP425_UART_IER 0x01 /* interrupt enable register */
+#define IXP425_UART_IER_RTOIE 0x10 /* receiver timeout interrupt enable */
+#define IXP425_UART_IER_UUE 0x40 /* UART Unit enable */
+
+/*#define IXP4XX_COM_NPORTS 8*/
+
+/*
+ * Timers
+ *
+ */
+#define IXP425_TIMER_HWBASE (IXP425_IO_HWBASE + IXP425_TIMER_OFFSET)
+#define IXP425_TIMER_VBASE (IXP425_IO_VBASE + IXP425_TIMER_OFFSET)
+
+#define IXP425_OST_TS 0x0000
+#define IXP425_OST_TIM0 0x0004
+#define IXP425_OST_TIM1 0x000C
+
+#define IXP425_OST_TIM0_RELOAD 0x0008
+#define IXP425_OST_TIM1_RELOAD 0x0010
+#define TIMERRELOAD_MASK 0xFFFFFFFC
+#define OST_ONESHOT_EN (1U << 1)
+#define OST_TIMER_EN (1U << 0)
+
+#define IXP425_OST_STATUS 0x0020
+#define OST_WARM_RESET (1U << 4)
+#define OST_WDOG_INT (1U << 3)
+#define OST_TS_INT (1U << 2)
+#define OST_TIM1_INT (1U << 1)
+#define OST_TIM0_INT (1U << 0)
+
+#define IXP425_OST_WDOG 0x0014
+#define IXP425_OST_WDOG_ENAB 0x0018
+#define IXP425_OST_WDOG_KEY 0x001c
+#define OST_WDOG_KEY_MAJICK 0x482e
+#define OST_WDOG_ENAB_RST_ENA (1u << 0)
+#define OST_WDOG_ENAB_INT_ENA (1u << 1)
+#define OST_WDOG_ENAB_CNT_ENA (1u << 2)
+
+/*
+ * Interrupt Controller Unit.
+ * PA 0xc8003000
+ */
+
+#define IXP425_IRQ_HWBASE IXP425_IO_HWBASE + IXP425_INTR_OFFSET
+#define IXP425_IRQ_VBASE IXP425_IO_VBASE + IXP425_INTR_OFFSET
+ /* 0xf0003000 */
+#define IXP425_IRQ_SIZE 0x00000020UL
+
+#define IXP425_INT_STATUS (IXP425_IRQ_VBASE + 0x00)
+#define IXP425_INT_ENABLE (IXP425_IRQ_VBASE + 0x04)
+#define IXP425_INT_SELECT (IXP425_IRQ_VBASE + 0x08)
+#define IXP425_IRQ_STATUS (IXP425_IRQ_VBASE + 0x0C)
+#define IXP425_FIQ_STATUS (IXP425_IRQ_VBASE + 0x10)
+#define IXP425_INT_PRTY (IXP425_IRQ_VBASE + 0x14)
+#define IXP425_IRQ_ENC (IXP425_IRQ_VBASE + 0x18)
+#define IXP425_FIQ_ENC (IXP425_IRQ_VBASE + 0x1C)
+
+#define IXP425_INT_SW1 31 /* SW Interrupt 1 */
+#define IXP425_INT_SW0 30 /* SW Interrupt 0 */
+#define IXP425_INT_GPIO_12 29 /* GPIO 12 */
+#define IXP425_INT_GPIO_11 28 /* GPIO 11 */
+#define IXP425_INT_GPIO_10 27 /* GPIO 11 */
+#define IXP425_INT_GPIO_9 26 /* GPIO 9 */
+#define IXP425_INT_GPIO_8 25 /* GPIO 8 */
+#define IXP425_INT_GPIO_7 24 /* GPIO 7 */
+#define IXP425_INT_GPIO_6 23 /* GPIO 6 */
+#define IXP425_INT_GPIO_5 22 /* GPIO 5 */
+#define IXP425_INT_GPIO_4 21 /* GPIO 4 */
+#define IXP425_INT_GPIO_3 20 /* GPIO 3 */
+#define IXP425_INT_GPIO_2 19 /* GPIO 2 */
+#define IXP425_INT_XSCALE_PMU 18 /* XScale PMU */
+#define IXP425_INT_AHB_PMU 17 /* AHB PMU */
+#define IXP425_INT_WDOG 16 /* Watchdog Timer */
+#define IXP425_INT_UART0 15 /* HighSpeed UART */
+#define IXP425_INT_STAMP 14 /* Timestamp Timer */
+#define IXP425_INT_UART1 13 /* Console UART */
+#define IXP425_INT_USB 12 /* USB */
+#define IXP425_INT_TMR1 11 /* General-Purpose Timer1 */
+#define IXP425_INT_PCIDMA2 10 /* PCI DMA Channel 2 */
+#define IXP425_INT_PCIDMA1 9 /* PCI DMA Channel 1 */
+#define IXP425_INT_PCIINT 8 /* PCI Interrupt */
+#define IXP425_INT_GPIO_1 7 /* GPIO 1 */
+#define IXP425_INT_GPIO_0 6 /* GPIO 0 */
+#define IXP425_INT_TMR0 5 /* General-Purpose Timer0 */
+#define IXP425_INT_QUE33_64 4 /* Queue Manager 33-64 */
+#define IXP425_INT_QUE1_32 3 /* Queue Manager 1-32 */
+#define IXP425_INT_NPE_C 2 /* NPE C */
+#define IXP425_INT_NPE_B 1 /* NPE B */
+#define IXP425_INT_NPE_A 0 /* NPE A */
+
+/*
+ * software interrupt
+ */
+#define IXP425_INT_bit31 31
+#define IXP425_INT_bit30 30
+#define IXP425_INT_bit14 14
+#define IXP425_INT_bit11 11
+
+#define IXP425_INT_HWMASK (0xffffffff & \
+ ~((1 << IXP425_INT_bit31) | \
+ (1 << IXP425_INT_bit30) | \
+ (1 << IXP425_INT_bit14) | \
+ (1 << IXP425_INT_bit11)))
+#define IXP425_INT_GPIOMASK (0x3ff800c0u)
+
+/*
+ * GPIO
+ */
+#define IXP425_GPIO_HWBASE IXP425_IO_HWBASE + IXP425_GPIO_OFFSET
+#define IXP425_GPIO_VBASE IXP425_IO_VBASE + IXP425_GPIO_OFFSET
+ /* 0xf0004000 */
+#define IXP425_GPIO_SIZE 0x00000020UL
+
+#define IXP425_GPIO_GPOUTR 0x00
+#define IXP425_GPIO_GPOER 0x04
+#define IXP425_GPIO_GPINR 0x08
+#define IXP425_GPIO_GPISR 0x0c
+#define IXP425_GPIO_GPIT1R 0x10
+#define IXP425_GPIO_GPIT2R 0x14
+#define IXP425_GPIO_GPCLKR 0x18
+# define GPCLKR_MUX14 (1U << 8)
+# define GPCLKR_CLK0TC_SHIFT 4
+# define GPCLKR_CLK0DC_SHIFT 0
+
+/* GPIO Output */
+#define GPOUT_ON 0x1
+#define GPOUT_OFF 0x0
+
+/* GPIO direction */
+#define GPOER_INPUT 0x1
+#define GPOER_OUTPUT 0x0
+
+/* GPIO Type bits */
+#define GPIO_TYPE_ACT_HIGH 0x0
+#define GPIO_TYPE_ACT_LOW 0x1
+#define GPIO_TYPE_EDG_RISING 0x2
+#define GPIO_TYPE_EDG_FALLING 0x3
+#define GPIO_TYPE_TRANSITIONAL 0x4
+#define GPIO_TYPE_MASK 0x7
+#define GPIO_TYPE(b,v) ((v) << (((b) & 0x7) * 3))
+#define GPIO_TYPE_REG(b) (((b)&8)?IXP425_GPIO_GPIT2R:IXP425_GPIO_GPIT1R)
+
+/*
+ * Expansion Bus Configuration Space.
+ */
+#define IXP425_EXP_HWBASE 0xc4000000UL
+#define IXP425_EXP_VBASE (IXP425_IO_VBASE + IXP425_IO_SIZE)
+ /* 0xf0010000 */
+#define IXP425_EXP_SIZE IXP425_REG_SIZE /* 0x1000 */
+
+/* offset */
+#define EXP_TIMING_CS0_OFFSET 0x0000
+#define EXP_TIMING_CS1_OFFSET 0x0004
+#define EXP_TIMING_CS2_OFFSET 0x0008
+#define EXP_TIMING_CS3_OFFSET 0x000c
+#define EXP_TIMING_CS4_OFFSET 0x0010
+#define EXP_TIMING_CS5_OFFSET 0x0014
+#define EXP_TIMING_CS6_OFFSET 0x0018
+#define EXP_TIMING_CS7_OFFSET 0x001c
+#define EXP_CNFG0_OFFSET 0x0020
+#define EXP_CNFG1_OFFSET 0x0024
+#define EXP_FCTRL_OFFSET 0x0028
+
+#define IXP425_EXP_RECOVERY_SHIFT 16
+#define IXP425_EXP_HOLD_SHIFT 20
+#define IXP425_EXP_STROBE_SHIFT 22
+#define IXP425_EXP_SETUP_SHIFT 26
+#define IXP425_EXP_ADDR_SHIFT 28
+#define IXP425_EXP_CS_EN (1U << 31)
+
+#define IXP425_EXP_RECOVERY_T(x) (((x) & 15) << IXP425_EXP_RECOVERY_SHIFT)
+#define IXP425_EXP_HOLD_T(x) (((x) & 3) << IXP425_EXP_HOLD_SHIFT)
+#define IXP425_EXP_STROBE_T(x) (((x) & 15) << IXP425_EXP_STROBE_SHIFT)
+#define IXP425_EXP_SETUP_T(x) (((x) & 3) << IXP425_EXP_SETUP_SHIFT)
+#define IXP425_EXP_ADDR_T(x) (((x) & 3) << IXP425_EXP_ADDR_SHIFT)
+
+/* EXP_CSn bits */
+#define EXP_BYTE_EN 0x00000001 /* bus uses only 8-bit data */
+#define EXP_WR_EN 0x00000002 /* ena writes to CS region */
+/* bit 2 is reserved */
+#define EXP_SPLT_EN 0x00000008 /* ena AHB split transfers */
+#define EXP_MUX_EN 0x00000010 /* multiplexed address/data */
+#define EXP_HRDY_POL 0x00000020 /* HPI|HRDY polarity */
+#define EXP_BYTE_RD16 0x00000040 /* byte rd access to word dev */
+#define EXP_CNFG 0x00003c00 /* device config size */
+#define EXP_SZ_512 (0 << 10)
+#define EXP_SZ_1K (1 << 10)
+#define EXP_SZ_2K (2 << 10)
+#define EXP_SZ_4K (3 << 10)
+#define EXP_SZ_8K (4 << 10)
+#define EXP_SZ_16K (5 << 10)
+#define EXP_SZ_32K (6 << 10)
+#define EXP_SZ_64K (7 << 10)
+#define EXP_SZ_128K (8 << 10)
+#define EXP_SZ_256K (9 << 10)
+#define EXP_SZ_512K (10 << 10)
+#define EXP_SZ_1M (11 << 10)
+#define EXP_SZ_2M (12 << 10)
+#define EXP_SZ_4M (13 << 10)
+#define EXP_SZ_8M (14 << 10)
+#define EXP_SZ_16M (15 << 10)
+#define EXP_CYC_TYPE 0x0000c000 /* bus cycle "type" */
+#define EXP_CYC_INTEL (0 << 14)
+#define EXP_CYC_MOTO (1 << 14)
+#define EXP_CYC_HPI (2 << 14)
+#define EXP_T5 0x000f0000 /* recovery timing */
+#define EXP_T4 0x00300000 /* hold timing */
+#define EXP_T3 0x03c00000 /* strobe timing */
+#define EXP_T2 0x0c000000 /* setup/chip select timing */
+#define EXP_T1 0x30000000 /* address timing */
+/* bit 30 is reserved */
+#define EXP_CS_EN 0x80000000 /* chip select enabled */
+
+/* EXP_CNFG0 bits */
+#define EXP_CNFG0_8BIT (1 << 0)
+#define EXP_CNFG0_PCI_HOST (1 << 1)
+#define EXP_CNFG0_PCI_ARB (1 << 2)
+#define EXP_CNFG0_PCI_66MHZ (1 << 4)
+#define EXP_CNFG0_MEM_MAP (1 << 31)
+
+/* EXP_CNFG1 bits */
+#define EXP_CNFG1_SW_INT0 (1 << 0)
+#define EXP_CNFG1_SW_INT1 (1 << 1)
+
+#define EXP_FCTRL_RCOMP (1<<0)
+#define EXP_FCTRL_USB (1<<1)
+#define EXP_FCTRL_HASH (1<<2)
+#define EXP_FCTRL_AES (1<<3)
+#define EXP_FCTRL_DES (1<<4)
+#define EXP_FCTRL_HDLC (1<<5)
+#define EXP_FCTRL_AAL (1<<6)
+#define EXP_FCTRL_HSS (1<<7)
+#define EXP_FCTRL_UTOPIA (1<<8)
+#define EXP_FCTRL_ETH0 (1<<9)
+#define EXP_FCTRL_ETH1 (1<<10)
+#define EXP_FCTRL_NPEA (1<<11)
+#define EXP_FCTRL_NPEB (1<<12)
+#define EXP_FCTRL_NPEC (1<<13)
+#define EXP_FCTRL_PCI (1<<14)
+/* XXX more stuff we don't care about */
+
+/*
+ * PCI
+ */
+#define IXP425_PCI_HWBASE 0xc0000000
+#define IXP425_PCI_VBASE (IXP425_EXP_VBASE + IXP425_EXP_SIZE)
+ /* 0xf0011000 */
+#define IXP425_PCI_SIZE IXP425_REG_SIZE /* 0x1000 */
+
+/*
+ * Mapping registers of IXP425 PCI Configuration
+ */
+/* PCI_ID_REG 0x00 */
+/* PCI_COMMAND_STATUS_REG 0x04 */
+/* PCI_CLASS_REG 0x08 */
+/* PCI_BHLC_REG 0x0c */
+#define PCI_MAPREG_BAR0 0x10 /* Base Address 0 */
+#define PCI_MAPREG_BAR1 0x14 /* Base Address 1 */
+#define PCI_MAPREG_BAR2 0x18 /* Base Address 2 */
+#define PCI_MAPREG_BAR3 0x1c /* Base Address 3 */
+#define PCI_MAPREG_BAR4 0x20 /* Base Address 4 */
+#define PCI_MAPREG_BAR5 0x24 /* Base Address 5 */
+/* PCI_SUBSYS_ID_REG 0x2c */
+/* PCI_INTERRUPT_REG 0x3c */
+#define PCI_RTOTTO 0x40
+
+/* PCI Controller CSR Base Address */
+#define IXP425_PCI_CSR_BASE IXP425_PCI_VBASE
+
+/* PCI Memory Space */
+#define IXP425_PCI_MEM_HWBASE 0x48000000UL
+#define IXP425_PCI_MEM_VBASE 0xf8000000UL
+#define IXP425_PCI_MEM_SIZE 0x04000000UL /* 64MB */
+
+/* PCI I/O Space */
+#define IXP425_PCI_IO_HWBASE 0x00000000UL
+#define IXP425_PCI_IO_SIZE 0x00100000UL /* 1Mbyte */
+
+/* PCI Controller Configuration Offset */
+#define PCI_NP_AD 0x00
+#define PCI_NP_CBE 0x04
+# define NP_CBE_SHIFT 4
+#define PCI_NP_WDATA 0x08
+#define PCI_NP_RDATA 0x0c
+#define PCI_CRP_AD_CBE 0x10
+#define PCI_CRP_AD_WDATA 0x14
+#define PCI_CRP_AD_RDATA 0x18
+#define PCI_CSR 0x1c
+# define CSR_PRST (1U << 16)
+# define CSR_IC (1U << 15)
+# define CSR_ABE (1U << 4)
+# define CSR_PDS (1U << 3)
+# define CSR_ADS (1U << 2)
+# define CSR_HOST (1U << 0)
+#define PCI_ISR 0x20
+# define ISR_AHBE (1U << 3)
+# define ISR_PPE (1U << 2)
+# define ISR_PFE (1U << 1)
+# define ISR_PSE (1U << 0)
+#define PCI_INTEN 0x24
+#define PCI_DMACTRL 0x28
+#define PCI_AHBMEMBASE 0x2c
+#define PCI_AHBIOBASE 0x30
+#define PCI_PCIMEMBASE 0x34
+#define PCI_AHBDOORBELL 0x38
+#define PCI_PCIDOORBELL 0x3c
+#define PCI_ATPDMA0_AHBADDR 0x40
+#define PCI_ATPDMA0_PCIADDR 0x44
+#define PCI_ATPDMA0_LENGTH 0x48
+#define PCI_ATPDMA1_AHBADDR 0x4c
+#define PCI_ATPDMA1_PCIADDR 0x50
+#define PCI_ATPDMA1_LENGTH 0x54
+#define PCI_PTADMA0_AHBADDR 0x58
+#define PCI_PTADMA0_PCIADDR 0x5c
+#define PCI_PTADMA0_LENGTH 0x60
+#define PCI_PTADMA1_AHBADDR 0x64
+#define PCI_PTADMA1_PCIADDR 0x68
+#define PCI_PTADMA1_LENGTH 0x6c
+
+/* PCI target(T)/initiator(I) Interface Commands for PCI_NP_CBE register */
+#define COMMAND_NP_IA 0x0 /* Interrupt Acknowledge (I)*/
+#define COMMAND_NP_SC 0x1 /* Special Cycle (I)*/
+#define COMMAND_NP_IO_READ 0x2 /* I/O Read (T)(I) */
+#define COMMAND_NP_IO_WRITE 0x3 /* I/O Write (T)(I) */
+#define COMMAND_NP_MEM_READ 0x6 /* Memory Read (T)(I) */
+#define COMMAND_NP_MEM_WRITE 0x7 /* Memory Write (T)(I) */
+#define COMMAND_NP_CONF_READ 0xa /* Configuration Read (T)(I) */
+#define COMMAND_NP_CONF_WRITE 0xb /* Configuration Write (T)(I) */
+
+/* PCI byte enables */
+#define BE_8BIT(a) ((0x10u << ((a) & 0x03)) ^ 0xf0)
+#define BE_16BIT(a) ((0x30u << ((a) & 0x02)) ^ 0xf0)
+#define BE_32BIT(a) 0x00
+
+/* PCI byte selects */
+#define READ_8BIT(v,a) ((u_int8_t)((v) >> (((a) & 3) * 8)))
+#define READ_16BIT(v,a) ((u_int16_t)((v) >> (((a) & 2) * 8)))
+#define WRITE_8BIT(v,a) (((u_int32_t)(v)) << (((a) & 3) * 8))
+#define WRITE_16BIT(v,a) (((u_int32_t)(v)) << (((a) & 2) * 8))
+
+/* PCI Controller Configuration Commands for PCI_CRP_AD_CBE */
+#define COMMAND_CRP_READ 0x00
+#define COMMAND_CRP_WRITE (1U << 16)
+
+/*
+ * SDRAM Configuration Register
+ */
+#define IXP425_MCU_HWBASE 0xcc000000UL
+#define IXP425_MCU_VBASE 0xf0200000UL
+#define IXP425_MCU_SIZE 0x1000 /* Actually only 256 bytes */
+#define MCU_SDR_CONFIG 0x00
+#define MCU_SDR_CONFIG_MCONF(x) ((x) & 0x7)
+#define MCU_SDR_CONFIG_64MBIT (1u << 5)
+#define MCU_SDR_REFRESH 0x04
+#define MCU_SDR_IR 0x08
+
+/*
+ * Performance Monitoring Unit (CP14)
+ *
+ * CP14.0.1 Performance Monitor Control Register(PMNC)
+ * CP14.1.1 Clock Counter(CCNT)
+ * CP14.4.1 Interrupt Enable Register(INTEN)
+ * CP14.5.1 Overflow Flag Register(FLAG)
+ * CP14.8.1 Event Selection Register(EVTSEL)
+ * CP14.0.2 Performance Counter Register 0(PMN0)
+ * CP14.1.2 Performance Counter Register 0(PMN1)
+ * CP14.2.2 Performance Counter Register 0(PMN2)
+ * CP14.3.2 Performance Counter Register 0(PMN3)
+ */
+
+#define PMNC_E 0x00000001 /* enable all counters */
+#define PMNC_P 0x00000002 /* reset all PMNs to 0 */
+#define PMNC_C 0x00000004 /* clock counter reset */
+#define PMNC_D 0x00000008 /* clock counter / 64 */
+
+#define INTEN_CC_IE 0x00000001 /* enable clock counter interrupt */
+#define INTEN_PMN0_IE 0x00000002 /* enable PMN0 interrupt */
+#define INTEN_PMN1_IE 0x00000004 /* enable PMN1 interrupt */
+#define INTEN_PMN2_IE 0x00000008 /* enable PMN2 interrupt */
+#define INTEN_PMN3_IE 0x00000010 /* enable PMN3 interrupt */
+
+#define FLAG_CC_IF 0x00000001 /* clock counter overflow */
+#define FLAG_PMN0_IF 0x00000002 /* PMN0 overflow */
+#define FLAG_PMN1_IF 0x00000004 /* PMN1 overflow */
+#define FLAG_PMN2_IF 0x00000008 /* PMN2 overflow */
+#define FLAG_PMN3_IF 0x00000010 /* PMN3 overflow */
+
+#define EVTSEL_EVCNT_MASK 0x0000000ff /* event to count for PMNs */
+#define PMNC_EVCNT0_SHIFT 0
+#define PMNC_EVCNT1_SHIFT 8
+#define PMNC_EVCNT2_SHIFT 16
+#define PMNC_EVCNT3_SHIFT 24
+
+/*
+ * Queue Manager
+ */
+#define IXP425_QMGR_HWBASE 0x60000000UL
+#define IXP425_QMGR_VBASE (IXP425_PCI_VBASE + IXP425_PCI_SIZE)
+#define IXP425_QMGR_SIZE 0x4000
+
+/*
+ * Network Processing Engines (NPE's) and associated Ethernet MAC's.
+ */
+#define IXP425_NPE_A_HWBASE (IXP425_IO_HWBASE + IXP425_NPE_A_OFFSET)
+#define IXP425_NPE_A_VBASE (IXP425_IO_VBASE + IXP425_NPE_A_OFFSET)
+#define IXP425_NPE_A_SIZE 0x1000 /* Actually only 256 bytes */
+
+#define IXP425_NPE_B_HWBASE (IXP425_IO_HWBASE + IXP425_NPE_B_OFFSET)
+#define IXP425_NPE_B_VBASE (IXP425_IO_VBASE + IXP425_NPE_B_OFFSET)
+#define IXP425_NPE_B_SIZE 0x1000 /* Actually only 256 bytes */
+
+#define IXP425_NPE_C_HWBASE (IXP425_IO_HWBASE + IXP425_NPE_C_OFFSET)
+#define IXP425_NPE_C_VBASE (IXP425_IO_VBASE + IXP425_NPE_C_OFFSET)
+#define IXP425_NPE_C_SIZE 0x1000 /* Actually only 256 bytes */
+
+#define IXP425_MAC_A_HWBASE (IXP425_IO_HWBASE + IXP425_MAC_A_OFFSET)
+#define IXP425_MAC_A_VBASE (IXP425_IO_VBASE + IXP425_MAC_A_OFFSET)
+#define IXP425_MAC_A_SIZE 0x1000 /* Actually only 256 bytes */
+
+#define IXP425_MAC_B_HWBASE (IXP425_IO_HWBASE + IXP425_MAC_B_OFFSET)
+#define IXP425_MAC_B_VBASE (IXP425_IO_VBASE + IXP425_MAC_B_OFFSET)
+#define IXP425_MAC_B_SIZE 0x1000 /* Actually only 256 bytes */
+
+/*
+ * Expansion Bus Data Space.
+ */
+#define IXP425_EXP_BUS_HWBASE 0x50000000UL
+#define IXP425_EXP_BUS_SIZE 0x01000000 /* max, typically smaller */
+
+#define IXP425_EXP_BUS_CSx_HWBASE(i) \
+ (IXP425_EXP_BUS_HWBASE + (i)*IXP425_EXP_BUS_SIZE)
+
+#define IXP425_EXP_BUS_CS1_HWBASE IXP425_EXP_BUS_CSx_HWBASE(1)
+#define IXP425_EXP_BUS_CS1_VBASE (IXP425_MAC_B_VBASE + IXP425_MAC_B_SIZE)
+#define IXP425_EXP_BUS_CS1_SIZE 0x1000
+
+/* NB: not mapped (yet) */
+#define IXP425_EXP_BUS_CS0_HWBASE IXP425_EXP_BUS_CSx_HWBASE(0)
+#define IXP425_EXP_BUS_CS2_HWBASE IXP425_EXP_BUS_CSx_HWBASE(2)
+#define IXP425_EXP_BUS_CS3_HWBASE IXP425_EXP_BUS_CSx_HWBASE(3)
+#define IXP425_EXP_BUS_CS4_HWBASE IXP425_EXP_BUS_CSx_HWBASE(4)
+#define IXP425_EXP_BUS_CS5_HWBASE IXP425_EXP_BUS_CSx_HWBASE(5)
+#define IXP425_EXP_BUS_CS6_HWBASE IXP425_EXP_BUS_CSx_HWBASE(6)
+#define IXP425_EXP_BUS_CS7_HWBASE IXP425_EXP_BUS_CSx_HWBASE(7)
+
+#endif /* _IXP425REG_H_ */
diff --git a/sys/arm/xscale/ixp425/ixp425var.h b/sys/arm/xscale/ixp425/ixp425var.h
new file mode 100644
index 000000000000..91a163cd72f1
--- /dev/null
+++ b/sys/arm/xscale/ixp425/ixp425var.h
@@ -0,0 +1,99 @@
+/* $NetBSD: ixp425var.h,v 1.10 2006/04/10 03:36:03 simonb Exp $ */
+
+/*
+ * Copyright (c) 2003
+ * Ichiro FUKUHARA <ichiro@ichiro.org>.
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Ichiro FUKUHARA.
+ * 4. The name of the company nor the name of the author may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ICHIRO FUKUHARA ``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 ICHIRO FUKUHARA OR THE VOICES IN HIS HEAD 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.
+ *
+ * $FreeBSD$
+ *
+ */
+
+#ifndef _IXP425VAR_H_
+#define _IXP425VAR_H_
+
+#include <sys/conf.h>
+#include <sys/queue.h>
+
+#include <machine/bus.h>
+
+#include <dev/pci/pcivar.h>
+#include <sys/rman.h>
+
+struct ixp425_softc {
+ device_t sc_dev;
+ bus_space_tag_t sc_iot;
+ bus_space_handle_t sc_gpio_ioh;
+ bus_space_handle_t sc_exp_ioh;
+
+ u_int32_t sc_intrmask;
+
+ struct rman sc_irq_rman;
+ struct rman sc_mem_rman;
+};
+
+struct ixppcib_softc {
+ device_t sc_dev;
+
+ u_int sc_bus;
+
+ struct resource *sc_csr;
+ struct resource *sc_mem;
+
+ struct rman sc_io_rman;
+ struct rman sc_mem_rman;
+ struct rman sc_irq_rman;
+
+ struct bus_space sc_pci_memt;
+ struct bus_space sc_pci_iot;
+};
+
+#define EXP_BUS_WRITE_4(sc, reg, data) \
+ bus_space_write_4(sc->sc_iot, sc->sc_exp_ioh, reg, data)
+#define EXP_BUS_READ_4(sc, reg) \
+ bus_space_read_4(sc->sc_iot, sc->sc_exp_ioh, reg)
+
+#define GPIO_CONF_WRITE_4(sc, reg, data) \
+ bus_space_write_4(sc->sc_iot, sc->sc_gpio_ioh, reg, data)
+#define GPIO_CONF_READ_4(sc, reg) \
+ bus_space_read_4(sc->sc_iot, sc->sc_gpio_ioh, reg)
+
+extern struct bus_space ixp425_bs_tag;
+extern struct bus_space ixp425_a4x_bs_tag;
+
+void ixp425_io_bs_init(bus_space_tag_t, void *);
+void ixp425_mem_bs_init(bus_space_tag_t, void *);
+
+uint32_t ixp425_sdram_size(void);
+
+int ixp425_md_route_interrupt(device_t, device_t, int);
+void ixp425_md_attach(device_t);
+
+#endif /* _IXP425VAR_H_ */
diff --git a/sys/arm/xscale/ixp425/std.avila b/sys/arm/xscale/ixp425/std.avila
new file mode 100644
index 000000000000..b69a65ebfa49
--- /dev/null
+++ b/sys/arm/xscale/ixp425/std.avila
@@ -0,0 +1,6 @@
+#GW2348-4 board configuration
+#$FreeBSD$
+include "../xscale/ixp425/std.ixp425"
+files "../xscale/ixp425/files.avila"
+makeoptions KERNPHYSADDR=0x10200000
+makeoptions KERNVIRTADDR=0xc0200000
diff --git a/sys/arm/xscale/ixp425/std.ixp425 b/sys/arm/xscale/ixp425/std.ixp425
new file mode 100644
index 000000000000..69cc2a148965
--- /dev/null
+++ b/sys/arm/xscale/ixp425/std.ixp425
@@ -0,0 +1,6 @@
+#XScale IXP425 generic configuration
+#$FreeBSD$
+files "../xscale/ixp425/files.ixp425"
+include "../xscale/std.xscale"
+cpu CPU_XSCALE_IXP425
+makeoption ARM_BIG_ENDIAN
diff --git a/sys/arm/xscale/ixp425/uart_bus_ixp425.c b/sys/arm/xscale/ixp425/uart_bus_ixp425.c
new file mode 100644
index 000000000000..a27557afbd98
--- /dev/null
+++ b/sys/arm/xscale/ixp425/uart_bus_ixp425.c
@@ -0,0 +1,91 @@
+/*-
+ * Copyright (c) 2006 Kevin Lo. 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>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <machine/resource.h>
+
+#include <dev/pci/pcivar.h>
+#include <dev/ic/ns16550.h>
+
+#include <dev/uart/uart.h>
+#include <dev/uart/uart_bus.h>
+#include <dev/uart/uart_cpu.h>
+
+#include <arm/xscale/ixp425/ixp425reg.h>
+#include <arm/xscale/ixp425/ixp425var.h>
+
+#include "uart_if.h"
+
+static int uart_ixp425_probe(device_t dev);
+
+static device_method_t uart_ixp425_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, uart_ixp425_probe),
+ DEVMETHOD(device_attach, uart_bus_attach),
+ DEVMETHOD(device_detach, uart_bus_detach),
+ { 0, 0 }
+};
+
+static driver_t uart_ixp425_driver = {
+ uart_driver_name,
+ uart_ixp425_methods,
+ sizeof(struct uart_softc),
+};
+
+extern SLIST_HEAD(uart_devinfo_list, uart_devinfo) uart_sysdevs;
+static int
+uart_ixp425_probe(device_t dev)
+{
+ struct uart_softc *sc;
+
+ sc = device_get_softc(dev);
+ sc->sc_sysdev = SLIST_FIRST(&uart_sysdevs);
+ sc->sc_class = &uart_ns8250_class;
+ bcopy(&sc->sc_sysdev->bas, &sc->sc_bas, sizeof(sc->sc_bas));
+ /*
+ * XXX set UART Unit Enable (0x40) AND
+ * receiver timeout int enable (0x10).
+ * The first turns on the UART. The second is necessary to get
+ * interrupts when the FIFO has data but is not full. Note that
+ * uart_ns8250 carefully avoids touching these bits so we can
+ * just set them here and proceed. But this is fragile...
+ */
+ bus_space_write_4(&ixp425_a4x_bs_tag,
+ device_get_unit(dev) == 0 ? IXP425_UART0_VBASE : IXP425_UART1_VBASE,
+ IXP425_UART_IER, IXP425_UART_IER_UUE | IXP425_UART_IER_RTOIE);
+ return(uart_bus_probe(dev, 0, IXP425_UART_FREQ, 0, 0));
+}
+
+
+DRIVER_MODULE(uart, ixp, uart_ixp425_driver, uart_devclass, 0, 0);
diff --git a/sys/arm/xscale/ixp425/uart_cpu_ixp425.c b/sys/arm/xscale/ixp425/uart_cpu_ixp425.c
new file mode 100644
index 000000000000..e691968538c6
--- /dev/null
+++ b/sys/arm/xscale/ixp425/uart_cpu_ixp425.c
@@ -0,0 +1,67 @@
+/*-
+ * Copyright (c) 2003 Marcel Moolenaar
+ * 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>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/cons.h>
+#include <machine/bus.h>
+
+#include <dev/uart/uart.h>
+#include <dev/uart/uart_cpu.h>
+
+#include <arm/xscale/ixp425/ixp425reg.h>
+#include <arm/xscale/ixp425/ixp425var.h>
+
+bus_space_tag_t uart_bus_space_io;
+bus_space_tag_t uart_bus_space_mem;
+
+int
+uart_cpu_eqres(struct uart_bas *b1, struct uart_bas *b2)
+{
+ return ((b1->bsh == b2->bsh && b1->bst == b2->bst) ? 1 : 0);
+}
+
+int
+uart_cpu_getdev(int devtype, struct uart_devinfo *di)
+{
+ di->ops = uart_ns8250_ops;
+ di->bas.chan = 0;
+ di->bas.bst = &ixp425_a4x_bs_tag;
+ di->bas.regshft = 0;
+ di->bas.rclk = IXP425_UART_FREQ;
+ di->baudrate = 115200;
+ di->databits = 8;
+ di->stopbits = 1;
+ di->parity = UART_PARITY_NONE;
+ uart_bus_space_io = &ixp425_a4x_bs_tag;
+ uart_bus_space_mem = NULL;
+ di->bas.bsh = IXP425_UART0_VBASE;
+ return (0);
+}