summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorsam <sam@FreeBSD.org>2008-12-13 01:21:37 +0000
committersam <sam@FreeBSD.org>2008-12-13 01:21:37 +0000
commit9c1fcf4ecd098afcbade2f395ab1fadbbe5b4b76 (patch)
tree644eaeb5764c12410edfb611ec530ca2d197a365 /sys
parenta52a9748d1f9588ffe250473b5be61674d1f1cc6 (diff)
downloadFreeBSD-src-9c1fcf4ecd098afcbade2f395ab1fadbbe5b4b76.zip
FreeBSD-src-9c1fcf4ecd098afcbade2f395ab1fadbbe5b4b76.tar.gz
Merge WIP from p4:
o recognize ixp435 cpu o change memory layout for for ixp4xx to not assume memory is aliases to 0x10000000 (Cambria/ixp435 memory starts at zero) o handle 64 irqs for ixp435 o dual EHCI USB 2.0 controller integral to ixp435 o overhaul NPE code for ixp435 and better MAC+MII naming o updated NPE firmware (including NPE-A image for ixp435/ixp465) o Gateworks Cambria board support: - IDE compact flash - MCU - front panel LED on i2c bus - Octal LED latch Sanity-tested with NFS-root on Avila and Cambria boards. Requires pending boot2 mods for CF-boot on Cambria.
Diffstat (limited to 'sys')
-rw-r--r--sys/arm/arm/cpufunc.c2
-rw-r--r--sys/arm/arm/identcpu.c4
-rw-r--r--sys/arm/conf/AVILA76
-rw-r--r--sys/arm/conf/AVILA.hints15
-rw-r--r--sys/arm/include/armreg.h1
-rw-r--r--sys/arm/include/intr.h4
-rw-r--r--sys/arm/xscale/ixp425/avila_ata.c151
-rw-r--r--sys/arm/xscale/ixp425/avila_led.c37
-rw-r--r--sys/arm/xscale/ixp425/avila_machdep.c327
-rw-r--r--sys/arm/xscale/ixp425/cambria_fled.c108
-rw-r--r--sys/arm/xscale/ixp425/cambria_led.c132
-rw-r--r--sys/arm/xscale/ixp425/files.avila2
-rw-r--r--sys/arm/xscale/ixp425/files.ixp4252
-rw-r--r--sys/arm/xscale/ixp425/if_npe.c368
-rw-r--r--sys/arm/xscale/ixp425/if_npereg.h6
-rw-r--r--sys/arm/xscale/ixp425/ixp425.c199
-rw-r--r--sys/arm/xscale/ixp425/ixp425_iic.c2
-rw-r--r--sys/arm/xscale/ixp425/ixp425_intr.h74
-rw-r--r--sys/arm/xscale/ixp425/ixp425_mem.c21
-rw-r--r--sys/arm/xscale/ixp425/ixp425_npe.c1835
-rw-r--r--sys/arm/xscale/ixp425/ixp425_npevar.h22
-rw-r--r--sys/arm/xscale/ixp425/ixp425_pci.c27
-rw-r--r--sys/arm/xscale/ixp425/ixp425_qmgr.c4
-rw-r--r--sys/arm/xscale/ixp425/ixp425_timer.c4
-rw-r--r--sys/arm/xscale/ixp425/ixp425_wdog.c4
-rw-r--r--sys/arm/xscale/ixp425/ixp425reg.h129
-rw-r--r--sys/arm/xscale/ixp425/ixp425var.h5
-rw-r--r--sys/arm/xscale/ixp425/ixp435_ehci.c357
-rw-r--r--sys/arm/xscale/ixp425/std.avila22
-rw-r--r--sys/arm/xscale/ixp425/std.ixp4358
-rw-r--r--sys/conf/files1
-rw-r--r--sys/conf/options.arm1
-rw-r--r--sys/contrib/dev/npe/IxNpeMicrocode.dat.uu1113
-rw-r--r--sys/dev/usb/ehci.c522
-rw-r--r--sys/dev/usb/ehci_ddb.c255
-rw-r--r--sys/dev/usb/ehci_pci.c4
-rw-r--r--sys/dev/usb/ehcireg.h12
-rw-r--r--sys/dev/usb/ehcivar.h53
-rw-r--r--sys/dev/usb/usbdi.h3
39 files changed, 3601 insertions, 2311 deletions
diff --git a/sys/arm/arm/cpufunc.c b/sys/arm/arm/cpufunc.c
index 6317769..df4f067 100644
--- a/sys/arm/arm/cpufunc.c
+++ b/sys/arm/arm/cpufunc.c
@@ -1211,7 +1211,7 @@ set_cpufuncs()
#endif /* CPU_XSCALE_PXA2X0 */
#ifdef CPU_XSCALE_IXP425
if (cputype == CPU_ID_IXP425_533 || cputype == CPU_ID_IXP425_400 ||
- cputype == CPU_ID_IXP425_266) {
+ cputype == CPU_ID_IXP425_266 || cputype == CPU_ID_IXP435) {
cpufuncs = xscale_cpufuncs;
#if defined(PERFCTRS)
diff --git a/sys/arm/arm/identcpu.c b/sys/arm/arm/identcpu.c
index c8013b7..df67a8a 100644
--- a/sys/arm/arm/identcpu.c
+++ b/sys/arm/arm/identcpu.c
@@ -300,6 +300,10 @@ const struct cpuidtab cpuids[] = {
{ CPU_ID_IXP425_266, CPU_CLASS_XSCALE, "IXP425 266MHz",
ixp425_steppings },
+ /* XXX ixp435 steppings? */
+ { CPU_ID_IXP435, CPU_CLASS_XSCALE, "IXP435",
+ ixp425_steppings },
+
{ CPU_ID_ARM1136JS, CPU_CLASS_ARM11J, "ARM1136J-S",
generic_steppings },
{ CPU_ID_ARM1136JSR1, CPU_CLASS_ARM11J, "ARM1136J-S R1",
diff --git a/sys/arm/conf/AVILA b/sys/arm/conf/AVILA
index 92bbed1..f727071 100644
--- a/sys/arm/conf/AVILA
+++ b/sys/arm/conf/AVILA
@@ -20,20 +20,18 @@
ident AVILA
-options PHYSADDR=0x10000000
-options KERNPHYSADDR=0x10200000
-options KERNVIRTADDR=0xc0200000 # Used in ldscript.arm
-options FLASHADDR=0x50000000
-options LOADERRAMADDR=0x00000000
-options STARTUP_PAGETABLE_ADDR=0x10000000
-
+include "../xscale/ixp425/std.ixp425"
+# NB: memory mapping is defined in std.avila
include "../xscale/ixp425/std.avila"
+options XSCALE_CACHE_READ_WRITE_ALLOCATE
+#options ARM_USE_SMALL_ALLOC
#To statically compile in device wiring instead of /boot/device.hints
hints "AVILA.hints" #Default places to look for devices.
makeoptions MODULES_OVERRIDE=""
makeoptions DEBUG=-g #Build kernel with gdb(1) debug symbols
makeoptions CONF_CFLAGS=-mcpu=xscale
+makeoptions MODULES_OVERRIDE=""
#options HZ=1000
options HZ=100
options DEVICE_POLLING
@@ -42,34 +40,18 @@ options DEVICE_POLLING
options KDB
#options GDB
options DDB #Enable the kernel debugger
-#options INVARIANTS #Enable calls of extra sanity checking
-#options INVARIANT_SUPPORT #Extra sanity checks of internal structures, required by INVARIANTS
+options INVARIANTS #Enable calls of extra sanity checking
+options INVARIANT_SUPPORT #Extra sanity checks of internal structures, required by INVARIANTS
#options WITNESS #Enable checks to detect deadlocks and cycles
#options WITNESS_SKIPSPIN #Don't run witness on spinlocks for speed
#options DIAGNOSTIC
options SCHED_4BSD #4BSD scheduler
options INET #InterNETworking
-options INET6 #IPv6 communications protocols
options FFS #Berkeley Fast Filesystem
options SOFTUPDATES #Enable FFS soft updates support
-options UFS_ACL #Support for access control lists
-options UFS_DIRHASH #Improve performance on big directories
options NFSCLIENT #Network Filesystem Client
-options NFSSERVER #Network Filesystem Server
-options NFSLOCKD #Network Lock Manager
options NFS_ROOT #NFS usable as /, requires NFSCLIENT
-#options MSDOSFS #MSDOS Filesystem
-options CD9660 #ISO 9660 Filesystem
-#options PROCFS #Process filesystem (requires PSEUDOFS)
-options PSEUDOFS #Pseudo-filesystem framework
-options SCSI_DELAY=5000 #Delay (in ms) before probing SCSI
-options KTRACE #ktrace(1) support
-options SYSVSHM #SYSV-style shared memory
-options SYSVMSG #SYSV-style message queues
-options SYSVSEM #SYSV-style semaphores
-options _KPOSIX_PRIORITY_SCHEDULING #Posix P1003_1B real-time extensions
-options KBD_INSTALL_CDEV # install a CDEV entry in /dev
options BOOTP
options BOOTP_NFSROOT
options BOOTP_NFSV3
@@ -106,7 +88,6 @@ device npe_fw
device firmware
device qmgr # Q Manager (required by npe)
device miibus # NB: required by npe
-device rl # RealTek 8129/8139
device ether
device bpf
@@ -114,37 +95,48 @@ device pty
device loop
device if_bridge
-options XSCALE_CACHE_READ_WRITE_ALLOCATE
device md
device random # Entropy device
-#options ARM_USE_SMALL_ALLOC
-
# Wireless NIC cards
device wlan # 802.11 support
+options IEEE80211_DEBUG
device wlan_wep # 802.11 WEP support
device wlan_ccmp # 802.11 CCMP support
device wlan_tkip # 802.11 TKIP support
device wlan_xauth
+
device ath # Atheros pci/cardbus NIC's
-device ath_hal # Atheros HAL (Hardware Access Layer)
-options AH_SUPPORT_AR5416 # enable AR5416 tx/rx descriptors
-device ath_rate_sample # SampleRate tx rate control for ath
options ATH_DEBUG
+options ATH_DIAGAPI
+#options ATH_TX99_DIAG
+device ath_rate_sample # SampleRate tx rate control for ath
-#device crypto
-#device cryptodev
-#device hifn # NB: Soekris minipci card known to work
+#options AH_DEBUG
+#options AH_ASSERT
+#device ath_ar5210
+#device ath_ar5211
+device ath_ar5212
+device ath_rf2413
+device ath_rf2417
+device ath_rf2425
+device ath_rf5111
+device ath_rf5112
+device ath_rf5413
+#
+device ath_ar5416
+options AH_SUPPORT_AR5416
+device ath_ar9160
device usb
-options USB_DEBUG
+#options USB_DEBUG
device ohci
device ehci
device ugen
-device umass
-device scbus # SCSI bus (required for SCSI)
-device da # Direct Access (disks)
+#device umass
+#device scbus # SCSI bus (required for SCSI)
+#device da # Direct Access (disks)
-device ural
-device zyd
-device wlan_amrr
+#device ural
+#device zyd
+#device wlan_amrr
diff --git a/sys/arm/conf/AVILA.hints b/sys/arm/conf/AVILA.hints
index 3a1a6a7..ba3a04b 100644
--- a/sys/arm/conf/AVILA.hints
+++ b/sys/arm/conf/AVILA.hints
@@ -17,21 +17,22 @@ hint.uart.1.irq=13
# NPE Hardware Queue Manager
hint.ixpqmgr.0.at="ixp0"
-# NPE wireless NIC's, requires ixpqmgr
+# NPE wired NIC's, requires ixpqmgr
hint.npe.0.at="ixp0"
-hint.npe.0.mac="A"
-hint.npe.0.mii="A"
+hint.npe.0.npeid="B"
+hint.npe.0.mac="B"
+hint.npe.0.mii="B"
hint.npe.0.phy=0
hint.npe.1.at="ixp0"
-hint.npe.1.mac="B"
-# NB: on 2348 boards all PHY's are addressed through MAC A
-hint.npe.1.mii="A"
+hint.npe.1.npeid="C"
+hint.npe.1.mac="C"
+hint.npe.1.mii="B"
hint.npe.1.phy=1
# CF IDE controller
hint.ata_avila.0.at="ixp0"
-# LED connected to gpio
+# Front Panel LED
hint.led_avila.0.at="ixp0"
# Analog Devices AD7418 temperature sensor
diff --git a/sys/arm/include/armreg.h b/sys/arm/include/armreg.h
index 6ba8cf4..068073b 100644
--- a/sys/arm/include/armreg.h
+++ b/sys/arm/include/armreg.h
@@ -174,6 +174,7 @@
#define CPU_ID_IXP425_533 0x690541c0
#define CPU_ID_IXP425_400 0x690541d0
#define CPU_ID_IXP425_266 0x690541f0
+#define CPU_ID_IXP435 0x69054040
/* ARM3-specific coprocessor 15 registers */
#define ARM3_CP15_FLUSH 1
diff --git a/sys/arm/include/intr.h b/sys/arm/include/intr.h
index d75f14e..619c5e1 100644
--- a/sys/arm/include/intr.h
+++ b/sys/arm/include/intr.h
@@ -39,6 +39,7 @@
#ifndef _MACHINE_INTR_H_
#define _MACHINE_INTR_H_
+/* XXX move to std.* files? */
#ifdef CPU_XSCALE_81342
#define NIRQ 128
#elif defined(CPU_XSCALE_PXA2X0)
@@ -46,7 +47,8 @@
#define NIRQ IRQ_GPIO_MAX
#elif defined(SOC_MV_DISCOVERY)
#define NIRQ 96
-#elif defined(CPU_ARM9) || defined(SOC_MV_KIRKWOOD)
+#elif defined(CPU_ARM9) || defined(SOC_MV_KIRKWOOD) || \
+ defined(CPU_XSCALE_IXP435)
#define NIRQ 64
#else
#define NIRQ 32
diff --git a/sys/arm/xscale/ixp425/avila_ata.c b/sys/arm/xscale/ixp425/avila_ata.c
index 31e3a85..337f43b 100644
--- a/sys/arm/xscale/ixp425/avila_ata.c
+++ b/sys/arm/xscale/ixp425/avila_ata.c
@@ -67,13 +67,64 @@ __FBSDID("$FreeBSD$");
#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 0x06 /* control register */
+#define AVILA_IDE_CTRL 0x06
+
+struct ata_config {
+ const char *desc; /* description for probe */
+ uint8_t gpin; /* GPIO pin */
+ uint8_t irq; /* IRQ */
+ uint32_t base16; /* CS base addr for 16-bit */
+ uint32_t size16; /* CS size for 16-bit */
+ uint32_t off16; /* CS offset for 16-bit */
+ uint32_t basealt; /* CS base addr for alt */
+ uint32_t sizealt; /* CS size for alt */
+ uint32_t offalt; /* CS offset for alt */
+};
-#define PRONGHORN_IDE_GPIN 0 /* GPIO pin # */
-#define PRONGHORN_IDE_IRQ IXP425_INT_GPIO_0
-#define PRONGHORN_IDE_CNTRL 0x06 /* control register */
+static const struct ata_config *
+ata_getconfig(struct ixp425_softc *sa)
+{
+ static const struct ata_config configs[] = {
+ { .desc = "Gateworks Avila IDE/CF Controller",
+ .gpin = 12,
+ .irq = IXP425_INT_GPIO_12,
+ .base16 = IXP425_EXP_BUS_CS1_HWBASE,
+ .size16 = IXP425_EXP_BUS_CS1_SIZE,
+ .off16 = EXP_TIMING_CS1_OFFSET,
+ .basealt = IXP425_EXP_BUS_CS2_HWBASE,
+ .sizealt = IXP425_EXP_BUS_CS2_SIZE,
+ .offalt = EXP_TIMING_CS2_OFFSET,
+ },
+ { .desc = "Gateworks Cambria IDE/CF Controller",
+ .gpin = 12,
+ .irq = IXP425_INT_GPIO_12,
+ .base16 = CAMBRIA_CFSEL0_HWBASE,
+ .size16 = CAMBRIA_CFSEL0_SIZE,
+ .off16 = EXP_TIMING_CS3_OFFSET,
+ .basealt = CAMBRIA_CFSEL1_HWBASE,
+ .sizealt = CAMBRIA_CFSEL1_SIZE,
+ .offalt = EXP_TIMING_CS4_OFFSET,
+ },
+ { .desc = "ADI Pronghorn Metro IDE/CF Controller",
+ .gpin = 0,
+ .irq = IXP425_INT_GPIO_0,
+ .base16 = IXP425_EXP_BUS_CS3_HWBASE,
+ .size16 = IXP425_EXP_BUS_CS3_SIZE,
+ .off16 = EXP_TIMING_CS3_OFFSET,
+ .basealt = IXP425_EXP_BUS_CS4_HWBASE,
+ .sizealt = IXP425_EXP_BUS_CS4_SIZE,
+ .offalt = EXP_TIMING_CS4_OFFSET,
+ },
+ };
+
+ /* XXX honor hint? (but then no multi-board support) */
+ /* XXX total hack */
+ if ((cpu_id() & CPU_ID_CPU_MASK) == CPU_ID_IXP435)
+ return &configs[1]; /* Cambria */
+ if (EXP_BUS_READ_4(sa, EXP_TIMING_CS2_OFFSET) != 0)
+ return &configs[0]; /* Avila */
+ return &configs[2]; /* Pronghorn */
+}
struct ata_avila_softc {
device_t sc_dev;
@@ -105,14 +156,14 @@ static int
ata_avila_probe(device_t dev)
{
struct ixp425_softc *sa = device_get_softc(device_get_parent(dev));
+ const struct ata_config *config;
- /* XXX any way to check? */
- if (EXP_BUS_READ_4(sa, EXP_TIMING_CS2_OFFSET) != 0)
- device_set_desc_copy(dev, "Gateworks Avila IDE/CF Controller");
- else
- device_set_desc_copy(dev,
- "ADI Pronghorn Metro IDE/CF Controller");
- return 0;
+ config = ata_getconfig(sa);
+ if (config != NULL) {
+ device_set_desc_copy(dev, config->desc);
+ return 0;
+ }
+ return ENXIO;
}
static int
@@ -120,41 +171,25 @@ 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));
- u_int32_t alt_t_off, ide_gpin, ide_irq;
+ const struct ata_config *config;
+
+ config = ata_getconfig(sa);
+ KASSERT(config != NULL, ("no board config"));
sc->sc_dev = dev;
/* NB: borrow from parent */
sc->sc_iot = sa->sc_iot;
sc->sc_exp_ioh = sa->sc_exp_ioh;
- if (EXP_BUS_READ_4(sc, EXP_TIMING_CS2_OFFSET) != 0) {
- /* Avila board */
- 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__);
- if (bus_space_map(sc->sc_iot, IXP425_EXP_BUS_CS2_HWBASE,
- IXP425_EXP_BUS_CS2_SIZE, 0, &sc->sc_alt_ioh))
- panic("%s: unable to map Expansion Bus CS2 window",
- __func__);
- ide_gpin = AVILA_IDE_GPIN;
- ide_irq = AVILA_IDE_IRQ;
- sc->sc_16bit_off = EXP_TIMING_CS1_OFFSET;
- alt_t_off = EXP_TIMING_CS2_OFFSET;
- } else {
- /* Pronghorn */
- if (bus_space_map(sc->sc_iot, IXP425_EXP_BUS_CS3_HWBASE,
- IXP425_EXP_BUS_CS3_SIZE, 0, &sc->sc_ioh))
- panic("%s: unable to map Expansion Bus CS3 window",
- __func__);
- if (bus_space_map(sc->sc_iot, IXP425_EXP_BUS_CS4_HWBASE,
- IXP425_EXP_BUS_CS4_SIZE, 0, &sc->sc_alt_ioh))
- panic("%s: unable to map Expansion Bus CS4 window",
- __func__);
- ide_gpin = PRONGHORN_IDE_GPIN;
- ide_irq = PRONGHORN_IDE_IRQ;
- sc->sc_16bit_off = EXP_TIMING_CS3_OFFSET;
- alt_t_off = EXP_TIMING_CS4_OFFSET;
- }
+
+ if (bus_space_map(sc->sc_iot, config->base16, config->size16,
+ 0, &sc->sc_ioh))
+ panic("%s: cannot map 16-bit window (0x%x/0x%x)",
+ __func__, config->base16, config->size16);
+ if (bus_space_map(sc->sc_iot, config->basealt, config->sizealt,
+ 0, &sc->sc_alt_ioh))
+ panic("%s: cannot map alt window (0x%x/0x%x)",
+ __func__, config->basealt, config->sizealt);
+ sc->sc_16bit_off = config->off16;
/*
* Craft special resource for ATA bus space ops
@@ -184,30 +219,30 @@ ata_avila_attach(device_t dev)
rman_set_bushandle(&sc->sc_alt_ata, sc->sc_alt_ioh);
GPIO_CONF_WRITE_4(sa, IXP425_GPIO_GPOER,
- GPIO_CONF_READ_4(sa, IXP425_GPIO_GPOER) | (1<<ide_gpin));
+ GPIO_CONF_READ_4(sa, IXP425_GPIO_GPOER) | (1<<config->gpin));
/* set interrupt type */
- GPIO_CONF_WRITE_4(sa, GPIO_TYPE_REG(ide_gpin),
- (GPIO_CONF_READ_4(sa, GPIO_TYPE_REG(ide_gpin)) &~
- GPIO_TYPE(ide_gpin, GPIO_TYPE_MASK)) |
- GPIO_TYPE(ide_gpin, GPIO_TYPE_EDG_RISING));
+ GPIO_CONF_WRITE_4(sa, GPIO_TYPE_REG(config->gpin),
+ (GPIO_CONF_READ_4(sa, GPIO_TYPE_REG(config->gpin)) &~
+ GPIO_TYPE(config->gpin, GPIO_TYPE_MASK)) |
+ GPIO_TYPE(config->gpin, GPIO_TYPE_EDG_RISING));
/* clear ISR */
- GPIO_CONF_WRITE_4(sa, IXP425_GPIO_GPISR, (1<<ide_gpin));
+ GPIO_CONF_WRITE_4(sa, IXP425_GPIO_GPISR, (1<<config->gpin));
/* configure CS1/3 window, leaving timing unchanged */
EXP_BUS_WRITE_4(sc, sc->sc_16bit_off,
EXP_BUS_READ_4(sc, sc->sc_16bit_off) |
EXP_BYTE_EN | EXP_WR_EN | EXP_BYTE_RD16 | EXP_CS_EN);
/* configure CS2/4 window, leaving timing unchanged */
- EXP_BUS_WRITE_4(sc, alt_t_off,
- EXP_BUS_READ_4(sc, alt_t_off) |
+ EXP_BUS_WRITE_4(sc, config->offalt,
+ EXP_BUS_READ_4(sc, config->offalt) |
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,
- ide_irq, ide_irq, 1, RF_ACTIVE);
+ config->irq, config->irq, 1, RF_ACTIVE);
if (!sc->sc_irq)
- panic("Unable to allocate irq %u.\n", ide_irq);
+ panic("Unable to allocate irq %u.\n", config->irq);
bus_setup_intr(dev, sc->sc_irq,
INTR_TYPE_BIO | INTR_MPSAFE | INTR_ENTROPY,
NULL, ata_avila_intr, sc, &sc->sc_ih);
@@ -230,9 +265,9 @@ ata_avila_detach(device_t dev)
/* 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);
+ if (nc > 0)
+ device_delete_child(dev, children[0]);
+ free(children, M_TEMP);
}
bus_teardown_intr(dev, sc->sc_irq, sc->sc_ih);
@@ -308,7 +343,7 @@ ata_avila_teardown_intr(device_t dev, device_t child, struct resource *irq,
/*
* Enable/disable 16-bit ops on the expansion bus.
*/
-static void __inline
+static __inline void
enable_16(struct ata_avila_softc *sc)
{
EXP_BUS_WRITE_4(sc, sc->sc_16bit_off,
@@ -316,7 +351,7 @@ enable_16(struct ata_avila_softc *sc)
DELAY(100); /* XXX? */
}
-static void __inline
+static __inline void
disable_16(struct ata_avila_softc *sc)
{
DELAY(100); /* XXX? */
diff --git a/sys/arm/xscale/ixp425/avila_led.c b/sys/arm/xscale/ixp425/avila_led.c
index 2493076..31558af 100644
--- a/sys/arm/xscale/ixp425/avila_led.c
+++ b/sys/arm/xscale/ixp425/avila_led.c
@@ -37,22 +37,19 @@ __FBSDID("$FreeBSD$");
#include <dev/led/led.h>
#define GPIO_LED_STATUS 3
-#define GPIO_LED_STATUS_BIT (1U << GPIO_LED_STATUS)
-
-static struct cdev *gpioled;
+#define GPIO_LED_STATUS_BIT (1U << GPIO_LED_STATUS)
struct led_avila_softc {
device_t sc_dev;
bus_space_tag_t sc_iot;
bus_space_handle_t sc_gpio_ioh;
+ struct cdev *sc_led;
};
-static struct led_avila_softc *led_avila_sc = NULL;
-
static void
-led_func(void *unused, int onoff)
+led_func(void *arg, int onoff)
{
- struct led_avila_softc *sc = led_avila_sc;
+ struct led_avila_softc *sc = arg;
uint32_t reg;
reg = GPIO_CONF_READ_4(sc, IXP425_GPIO_GPOUTR);
@@ -66,7 +63,7 @@ led_func(void *unused, int onoff)
static int
led_avila_probe(device_t dev)
{
- device_set_desc(dev, "Gateworks Avila GPIO connected LED");
+ device_set_desc(dev, "Gateworks Avila Front Panel LED");
return (0);
}
@@ -75,31 +72,35 @@ led_avila_attach(device_t dev)
{
struct led_avila_softc *sc = device_get_softc(dev);
struct ixp425_softc *sa = device_get_softc(device_get_parent(dev));
- void *led = NULL;
- uint32_t reg;
-
- led_avila_sc = sc;
sc->sc_dev = dev;
sc->sc_iot = sa->sc_iot;
sc->sc_gpio_ioh = sa->sc_gpio_ioh;
/* Configure LED GPIO pin as output */
- reg = GPIO_CONF_READ_4(sc, IXP425_GPIO_GPOER);
- reg &= ~GPIO_LED_STATUS_BIT;
- GPIO_CONF_WRITE_4(sc, IXP425_GPIO_GPOER, reg);
+ GPIO_CONF_WRITE_4(sc, IXP425_GPIO_GPOER,
+ GPIO_CONF_READ_4(sc, IXP425_GPIO_GPOER) &~ GPIO_LED_STATUS_BIT);
- gpioled = led_create(led_func, led, "gpioled");
+ sc->sc_led = led_create(led_func, sc, "gpioled");
- /* Turn on LED */
- led_func(led, 1);
+ led_func(sc, 1); /* Turn on LED */
return (0);
}
+static void
+led_avila_detach(device_t dev)
+{
+ struct led_avila_softc *sc = device_get_softc(dev);
+
+ if (sc->sc_led != NULL)
+ led_destroy(sc->sc_led);
+}
+
static device_method_t led_avila_methods[] = {
DEVMETHOD(device_probe, led_avila_probe),
DEVMETHOD(device_attach, led_avila_attach),
+ DEVMETHOD(device_detach, led_avila_detach),
{0, 0},
};
diff --git a/sys/arm/xscale/ixp425/avila_machdep.c b/sys/arm/xscale/ixp425/avila_machdep.c
index e9b53bb..181ccb4 100644
--- a/sys/arm/xscale/ixp425/avila_machdep.c
+++ b/sys/arm/xscale/ixp425/avila_machdep.c
@@ -95,6 +95,11 @@ __FBSDID("$FreeBSD$");
#include <arm/xscale/ixp425/ixp425reg.h>
#include <arm/xscale/ixp425/ixp425var.h>
+/* kernel text starts where we were loaded at boot */
+#define KERNEL_TEXT_OFF (KERNPHYSADDR - PHYSADDR)
+#define KERNEL_TEXT_BASE (KERNBASE + KERNEL_TEXT_OFF)
+#define KERNEL_TEXT_PHYS (PHYSADDR + KERNEL_TEXT_OFF)
+
#define KERNEL_PT_SYS 0 /* Page table for mapping proc0 zero page */
#define KERNEL_PT_IO 1
#define KERNEL_PT_IO_NUM 3
@@ -142,114 +147,109 @@ 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,
- },
+ { 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_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,
- },
+ { 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,
- },
+ { 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,
- },
+ { IXP425_PCI_MEM_VBASE, IXP425_PCI_MEM_HWBASE, IXP425_PCI_MEM_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, },
+
/* NPE-A Memory Space */
- {
- IXP425_NPE_A_VBASE,
- IXP425_NPE_A_HWBASE,
- IXP425_NPE_A_SIZE,
- VM_PROT_READ|VM_PROT_WRITE,
- PTE_NOCACHE,
- },
+ { 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,
- },
+ { 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,
- },
+ { IXP425_NPE_C_VBASE, IXP425_NPE_C_HWBASE, IXP425_NPE_C_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,
- }
+ { IXP425_MAC_B_VBASE, IXP425_MAC_B_HWBASE, IXP425_MAC_B_SIZE,
+ VM_PROT_READ|VM_PROT_WRITE, PTE_NOCACHE, },
+ /* MAC-C Memory Space */
+ { IXP425_MAC_C_VBASE, IXP425_MAC_C_HWBASE, IXP425_MAC_C_SIZE,
+ VM_PROT_READ|VM_PROT_WRITE, PTE_NOCACHE, },
+
+ { 0 },
};
-#define SDRAM_START 0x10000000
+/* Static device mappings. */
+static const struct pmap_devmap ixp435_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, },
+
+ /* DDRII Controller NB: mapped same place as IXP425 */
+ { IXP425_MCU_VBASE, IXP435_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, },
+
+ /* Q-Mgr Memory Space */
+ { IXP425_QMGR_VBASE, IXP425_QMGR_HWBASE, IXP425_QMGR_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-C Memory Space */
+ { IXP425_NPE_C_VBASE, IXP425_NPE_C_HWBASE, IXP425_NPE_C_SIZE,
+ VM_PROT_READ|VM_PROT_WRITE, PTE_NOCACHE, },
+
+ /* MAC-C Memory Space */
+ { IXP425_MAC_C_VBASE, IXP425_MAC_C_HWBASE, IXP425_MAC_C_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, },
+ /* MAC-A Memory Space */
+ { IXP435_MAC_A_VBASE, IXP435_MAC_A_HWBASE, IXP435_MAC_A_SIZE,
+ VM_PROT_READ|VM_PROT_WRITE, PTE_NOCACHE, },
+
+ /* USB1 Memory Space */
+ { IXP435_USB1_VBASE, IXP435_USB1_HWBASE, IXP435_USB1_SIZE,
+ VM_PROT_READ|VM_PROT_WRITE, PTE_NOCACHE, },
+ /* USB2 Memory Space */
+ { IXP435_USB2_VBASE, IXP435_USB2_HWBASE, IXP435_USB2_SIZE,
+ VM_PROT_READ|VM_PROT_WRITE, PTE_NOCACHE, },
+
+ { 0 }
+};
extern vm_offset_t xscale_cache_clean_addr;
void *
initarm(void *arg, void *arg2)
{
+#define next_chunk2(a,b) (((a) + (b)) &~ ((b)-1))
+#define next_page(a) next_chunk2(a,PAGE_SIZE)
struct pv_addr kernel_l1pt;
int loop, i;
u_int l1pagetable;
@@ -260,25 +260,40 @@ initarm(void *arg, void *arg2)
vm_offset_t lastaddr;
uint32_t memsize;
- set_cpufuncs();
+ set_cpufuncs(); /* NB: sets cputype */
lastaddr = fake_preload_metadata();
pcpu_init(pcpup, 0, sizeof(struct pcpu));
PCPU_SET(curthread, &thread0);
- 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));
-
+ /*
+ * We allocate memory downwards from where we were loaded
+ * by RedBoot; first the L1 page table, then NUM_KERNEL_PTS
+ * entries in the L2 page table. Past that we re-align the
+ * allocation boundary so later data structures (stacks, etc)
+ * can be mapped with different attributes (write-back vs
+ * write-through). Note this leaves a gap for expansion
+ * (or might be repurposed).
+ */
+ freemempos = KERNPHYSADDR;
+
+ /* macros to simplify initial memory allocation */
+#define alloc_pages(var, np) do { \
+ freemempos -= (np * PAGE_SIZE); \
+ (var) = freemempos; \
+ /* NB: this works because locore maps PA=VA */ \
+ memset((char *)(var), 0, ((np) * PAGE_SIZE)); \
+} while (0)
+#define valloc_pages(var, np) do { \
+ alloc_pages((var).pv_pa, (np)); \
+ (var).pv_va = (var).pv_pa + (KERNVIRTADDR - KERNPHYSADDR); \
+} while (0)
+
+ /* force L1 page table alignment */
while (((freemempos - L1_TABLE_SIZE) & (L1_TABLE_SIZE - 1)) != 0)
freemempos -= PAGE_SIZE;
+ /* allocate contiguous L1 page table */
valloc_pages(kernel_l1pt, L1_TABLE_SIZE / PAGE_SIZE);
+ /* now allocate L2 page tables; they are linked to L1 below */
for (loop = 0; loop < NUM_KERNEL_PTS; ++loop) {
if (!(loop % (PAGE_SIZE / L2_TABLE_SIZE_REAL))) {
valloc_pages(kernel_pt_table[loop],
@@ -288,11 +303,18 @@ initarm(void *arg, void *arg2)
(loop % (PAGE_SIZE / L2_TABLE_SIZE_REAL)) *
L2_TABLE_SIZE_REAL;
kernel_pt_table[loop].pv_va =
- kernel_pt_table[loop].pv_pa + 0xb0000000;
+ kernel_pt_table[loop].pv_pa +
+ (KERNVIRTADDR - KERNPHYSADDR);
}
}
- freemem_pt = freemempos;
- freemempos = 0x10100000;
+ freemem_pt = freemempos; /* base of allocated pt's */
+
+ /*
+ * Re-align allocation boundary so we can map the area
+ * write-back instead of write-through for the stacks and
+ * related structures allocated below.
+ */
+ freemempos = PHYSADDR + 0x100000;
/*
* Allocate a page for the system page mapped to V0x00000000
* This page will just contain the system vectors and can be
@@ -308,30 +330,25 @@ initarm(void *arg, void *arg2)
alloc_pages(minidataclean.pv_pa, 1);
valloc_pages(msgbufpv, round_page(MSGBUF_SIZE) / PAGE_SIZE);
#ifdef ARM_USE_SMALL_ALLOC
+#error "I am broken" /* XXX save people grief */
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)
+ arm_add_smallalloc_pages((void *)(freemem_after + (KERNVIRTADDR - KERNPHYSADDR)
, (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)
+ arm_add_smallalloc_pages((void *)(freemem_after + (KEYVIRTADDR - KERNPHYSADDR))
, (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
+ * Now construct the L1 page table. First map the L2
+ * page tables into the L1 so we can replace L1 mappings
+ * later on if necessary
*/
l1pagetable = kernel_l1pt.pv_va;
@@ -339,30 +356,28 @@ initarm(void *arg, void *arg2)
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]);
+ &kernel_pt_table[KERNEL_PT_IO]);
pmap_link_l2pt(l1pagetable, IXP425_MCU_VBASE,
- &kernel_pt_table[KERNEL_PT_IO + 1]);
+ &kernel_pt_table[KERNEL_PT_IO + 1]);
pmap_link_l2pt(l1pagetable, IXP425_PCI_MEM_VBASE,
- &kernel_pt_table[KERNEL_PT_IO + 2]);
+ &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,
+ pmap_map_chunk(l1pagetable, KERNBASE, PHYSADDR, 0x100000,
VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE);
- pmap_map_chunk(l1pagetable, KERNBASE + 0x100000, SDRAM_START + 0x100000,
+ pmap_map_chunk(l1pagetable, KERNBASE + 0x100000, PHYSADDR + 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),
+ pmap_map_chunk(l1pagetable, KERNEL_TEXT_BASE, KERNEL_TEXT_PHYS,
+ next_chunk2(((uint32_t)lastaddr) - KERNEL_TEXT_BASE, L1_S_SIZE),
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));
+ freemem_after = next_page((int)lastaddr);
+ afterkern = round_page(next_chunk2((vm_offset_t)lastaddr, L1_S_SIZE));
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) {
@@ -380,7 +395,10 @@ initarm(void *arg, void *arg2)
/* 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);
+ if (cpu_is_ixp43x())
+ pmap_devmap_bootstrap(l1pagetable, ixp435_devmap);
+ else
+ pmap_devmap_bootstrap(l1pagetable, ixp425_devmap);
/*
* Give the XScale global cache clean code an appropriately
* sized chunk of unmapped VA space starting at 0xff000000
@@ -392,6 +410,7 @@ initarm(void *arg, void *arg2)
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.
@@ -400,16 +419,9 @@ initarm(void *arg, void *arg2)
* 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);
-
-
+ 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....
@@ -422,21 +434,25 @@ initarm(void *arg, void *arg2)
* this problem will not occur after initarm().
*/
cpu_idcache_wbinv_all();
+ /* ready to setup the console (XXX move earlier if possible) */
+ cninit();
/*
- * Fetch the SDRAM start/size from the ixp425 SDRAM configration
- * registers.
+ * Fetch the RAM size from the MCU registers. The
+ * expansion bus was mapped above so we can now read 'em.
*/
- cninit();
- memsize = ixp425_sdram_size();
+ if (cpu_is_ixp43x())
+ memsize = ixp435_ddram_size();
+ else
+ 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();
-
+
proc_linkup0(&proc0, &thread0);
thread0.td_kstack = kernelstack.pv_va;
thread0.td_pcb = (struct pcb *)
@@ -444,38 +460,33 @@ initarm(void *arg, void *arg2)
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[0] = PHYSADDR;
+ dump_avail[1] = PHYSADDR + memsize;
dump_avail[2] = 0;
dump_avail[3] = 0;
-
- pmap_bootstrap(pmap_curmaxkvaddr,
- 0xd0000000, &kernel_l1pt);
+
+ 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; /*
+ phys_avail[i++] = PHYSADDR;
+ phys_avail[i++] = PHYSADDR + PAGE_SIZE; /*
*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++] = round_page(virtual_avail - KERNBASE + PHYSADDR);
+ phys_avail[i++] = trunc_page(PHYSADDR + memsize - 1);
phys_avail[i++] = 0;
phys_avail[i] = 0;
-
+
/* Do basic tuning, hz etc */
init_param1();
init_param2(physmem);
@@ -487,4 +498,6 @@ initarm(void *arg, void *arg2)
return ((void *)(kernelstack.pv_va + USPACE_SVC_STACK_TOP -
sizeof(struct pcb)));
+#undef next_page
+#undef next_chunk2
}
diff --git a/sys/arm/xscale/ixp425/cambria_fled.c b/sys/arm/xscale/ixp425/cambria_fled.c
new file mode 100644
index 0000000..ede1577
--- /dev/null
+++ b/sys/arm/xscale/ixp425/cambria_fled.c
@@ -0,0 +1,108 @@
+/*-
+ * Copyright (c) 2008 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$");
+/*
+ * Cambria Front Panel LED sitting on the I2C bus.
+ */
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+
+#include <machine/bus.h>
+
+#include <dev/iicbus/iiconf.h>
+#include <dev/led/led.h>
+
+#include "iicbus_if.h"
+
+#define IIC_M_WR 0 /* write operation */
+#define LED_ADDR 0xae /* slave address */
+
+struct fled_softc {
+ struct cdev *sc_led;
+};
+
+static int
+fled_probe(device_t dev)
+{
+ device_set_desc(dev, "Gateworks Cambria Front Panel LED");
+ return 0;
+}
+
+static void
+fled_cb(void *arg, int onoff)
+{
+ uint8_t data[1];
+ struct iic_msg msgs[1] = {
+ { LED_ADDR, IIC_M_WR, 1, data },
+ };
+ device_t dev = arg;
+
+ data[0] = (onoff == 0); /* NB: low true */
+ (void) iicbus_transfer(dev, msgs, 1);
+}
+
+static int
+fled_attach(device_t dev)
+{
+ struct fled_softc *sc = device_get_softc(dev);
+
+ sc->sc_led = led_create(fled_cb, dev, "front");
+
+ return 0;
+}
+
+static int
+fled_detach(device_t dev)
+{
+ struct fled_softc *sc = device_get_softc(dev);
+
+ if (sc->sc_led != NULL)
+ led_destroy(sc->sc_led);
+
+ return 0;
+}
+
+static device_method_t fled_methods[] = {
+ DEVMETHOD(device_probe, fled_probe),
+ DEVMETHOD(device_attach, fled_attach),
+ DEVMETHOD(device_detach, fled_detach),
+
+ {0, 0},
+};
+
+static driver_t fled_driver = {
+ "fled",
+ fled_methods,
+ sizeof(struct fled_softc),
+};
+static devclass_t fled_devclass;
+
+DRIVER_MODULE(fled, iicbus, fled_driver, fled_devclass, 0, 0);
+MODULE_VERSION(fled, 1);
+MODULE_DEPEND(fled, iicbus, 1, 1, 1);
diff --git a/sys/arm/xscale/ixp425/cambria_led.c b/sys/arm/xscale/ixp425/cambria_led.c
new file mode 100644
index 0000000..c55e3cb
--- /dev/null
+++ b/sys/arm/xscale/ixp425/cambria_led.c
@@ -0,0 +1,132 @@
+/*-
+ * Copyright (c) 2008 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$");
+
+/*
+ * Gateworks Cambria Octal LED Latch driver.
+ */
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+
+#include <machine/armreg.h>
+
+#include <arm/xscale/ixp425/ixp425reg.h>
+#include <arm/xscale/ixp425/ixp425var.h>
+
+#include <dev/led/led.h>
+
+struct led_softc {
+ device_t sc_dev;
+ bus_space_tag_t sc_iot;
+ bus_space_handle_t sc_ioh;
+ struct cdev *sc_leds[8];
+ uint8_t sc_latch;
+};
+
+static void
+update_latch(struct led_softc *sc, int bit, int onoff)
+{
+ if (onoff)
+ sc->sc_latch &= ~bit;
+ else
+ sc->sc_latch |= bit;
+ bus_space_write_1(sc->sc_iot, sc->sc_ioh, 0, sc->sc_latch);
+}
+static void led_A(void *arg, int onoff) { update_latch(arg, 1<<0, onoff); }
+static void led_B(void *arg, int onoff) { update_latch(arg, 1<<1, onoff); }
+static void led_C(void *arg, int onoff) { update_latch(arg, 1<<2, onoff); }
+static void led_D(void *arg, int onoff) { update_latch(arg, 1<<3, onoff); }
+static void led_E(void *arg, int onoff) { update_latch(arg, 1<<4, onoff); }
+static void led_F(void *arg, int onoff) { update_latch(arg, 1<<5, onoff); }
+static void led_G(void *arg, int onoff) { update_latch(arg, 1<<6, onoff); }
+static void led_H(void *arg, int onoff) { update_latch(arg, 1<<7, onoff); }
+
+static int
+led_probe(device_t dev)
+{
+ device_set_desc(dev, "Gateworks Octal LED Latch");
+ return (0);
+}
+
+static int
+led_attach(device_t dev)
+{
+ struct led_softc *sc = device_get_softc(dev);
+ struct ixp425_softc *sa = device_get_softc(device_get_parent(dev));
+
+ sc->sc_dev = dev;
+ sc->sc_iot = sa->sc_iot;
+ /* NB: write anywhere works, use first location */
+ if (bus_space_map(sc->sc_iot, CAMBRIA_OCTAL_LED_HWBASE, sizeof(uint8_t),
+ 0, &sc->sc_ioh)) {
+ device_printf(dev, "cannot map LED latch (0x%lx)",
+ CAMBRIA_OCTAL_LED_HWBASE);
+ return ENXIO;
+ }
+
+ sc->sc_leds[0] = led_create(led_A, sc, "A");
+ sc->sc_leds[1] = led_create(led_B, sc, "B");
+ sc->sc_leds[2] = led_create(led_C, sc, "C");
+ sc->sc_leds[3] = led_create(led_D, sc, "D");
+ sc->sc_leds[4] = led_create(led_E, sc, "E");
+ sc->sc_leds[5] = led_create(led_F, sc, "F");
+ sc->sc_leds[6] = led_create(led_G, sc, "G");
+ sc->sc_leds[7] = led_create(led_H, sc, "H");
+
+ return 0;
+}
+
+static void
+led_detach(device_t dev)
+{
+ struct led_softc *sc = device_get_softc(dev);
+ int i;
+
+ for (i = 0; i < 8; i++) {
+ struct cdev *led = sc->sc_leds[i];
+ if (led != NULL)
+ led_destroy(led);
+ }
+}
+
+static device_method_t led_methods[] = {
+ DEVMETHOD(device_probe, led_probe),
+ DEVMETHOD(device_attach, led_attach),
+ DEVMETHOD(device_attach, led_detach),
+
+ {0, 0},
+};
+
+static driver_t led_driver = {
+ "led_cambria",
+ led_methods,
+ sizeof(struct led_softc),
+};
+static devclass_t led_devclass;
+DRIVER_MODULE(led_cambria, ixp, led_driver, led_devclass, 0, 0);
diff --git a/sys/arm/xscale/ixp425/files.avila b/sys/arm/xscale/ixp425/files.avila
index 50910ce..a9b70dc 100644
--- a/sys/arm/xscale/ixp425/files.avila
+++ b/sys/arm/xscale/ixp425/files.avila
@@ -2,4 +2,6 @@
arm/xscale/ixp425/avila_machdep.c standard
arm/xscale/ixp425/avila_ata.c optional avila_ata
arm/xscale/ixp425/avila_led.c optional avila_led
+arm/xscale/ixp425/cambria_led.c optional cambria_led
+arm/xscale/ixp425/cambria_fled.c optional cambria_fled
arm/xscale/ixp425/ixdp425_pci.c optional pci
diff --git a/sys/arm/xscale/ixp425/files.ixp425 b/sys/arm/xscale/ixp425/files.ixp425
index d93524a..4299857 100644
--- a/sys/arm/xscale/ixp425/files.ixp425
+++ b/sys/arm/xscale/ixp425/files.ixp425
@@ -44,3 +44,5 @@ IxNpeMicrocode.dat optional npe_fw \
# Q-Manager support
#
arm/xscale/ixp425/ixp425_qmgr.c optional qmgr
+#
+arm/xscale/ixp425/ixp435_ehci.c optional ehci
diff --git a/sys/arm/xscale/ixp425/if_npe.c b/sys/arm/xscale/ixp425/if_npe.c
index 02af22f..52bea76 100644
--- a/sys/arm/xscale/ixp425/if_npe.c
+++ b/sys/arm/xscale/ixp425/if_npe.c
@@ -85,6 +85,8 @@ __FBSDID("$FreeBSD$");
#include <dev/mii/miivar.h>
#include <arm/xscale/ixp425/if_npereg.h>
+#include <machine/armreg.h>
+
#include "miibus_if.h"
/*
@@ -121,6 +123,7 @@ struct npe_softc {
bus_space_handle_t sc_ioh; /* MAC register window */
device_t sc_mii; /* child miibus */
bus_space_handle_t sc_miih; /* MII register window */
+ int sc_npeid;
struct ixpnpe_softc *sc_npe; /* NPE support */
int sc_debug; /* DPRINTF* control */
int sc_tickinterval;
@@ -143,7 +146,7 @@ struct npe_softc {
};
/*
- * Per-unit static configuration for IXP425. The tx and
+ * 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
@@ -154,39 +157,39 @@ struct npe_softc {
* 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 imageid; /* default fw image */
+ uint32_t macbase;
uint32_t miibase;
- int miisize;
int phy; /* phy id */
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,
+} npeconfig[NPE_MAX] = {
+ [NPE_A] = {
+ .imageid = IXP425_NPE_A_IMAGEID,
+ .macbase = IXP435_MAC_A_HWBASE,
+ .miibase = IXP425_MAC_C_HWBASE,
+ .phy = 2,
+ .rx_qid = 4,
+ .rx_freeqid = 26,
+ .tx_qid = 23,
+ .tx_doneqid = 31
+ },
+ [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,
+ .macbase = IXP425_MAC_B_HWBASE,
+ .miibase = IXP425_MAC_C_HWBASE,
.phy = 0,
.rx_qid = 4,
.rx_freeqid = 27,
.tx_qid = 24,
.tx_doneqid = 31
},
- { .desc = "IXP NPE-C",
- .npeid = NPE_C,
+ [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,
+ .macbase = IXP425_MAC_C_HWBASE,
+ .miibase = IXP425_MAC_C_HWBASE,
.phy = 1,
.rx_qid = 12,
.rx_freeqid = 28,
@@ -219,6 +222,7 @@ WR4(struct npe_softc *sc, bus_size_t off, uint32_t val)
static devclass_t npe_devclass;
+static int override_npeid(device_t, const char *resname, int *val);
static int npe_activate(device_t dev);
static void npe_deactivate(device_t dev);
static int npe_ifmedia_update(struct ifnet *ifp);
@@ -238,6 +242,7 @@ 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_setfirewallmode(struct npe_softc *, int onoff);
static int npe_updatestats(struct npe_softc *);
#if 0
static int npe_getstats(struct npe_softc *);
@@ -248,11 +253,11 @@ static int npe_setloopback(struct npe_softc *, int ena);
/* 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");
+SYSCTL_NODE(_hw, OID_AUTO, npe, CTLFLAG_RD, 0, "IXP4XX 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");
+ 0, "IXP4XX 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__); \
@@ -275,16 +280,38 @@ SYSCTL_INT(_hw_npe, OID_AUTO, txbuf, CTLFLAG_RD, &npe_txbuf,
TUNABLE_INT("hw.npe.txbuf", &npe_txbuf);
static int
-npe_probe(device_t dev)
+unit2npeid(int unit)
{
- int unit = device_get_unit(dev);
+ static const int npeidmap[2][3] = {
+ /* on 425 A is for HSS, B & C are for Ethernet */
+ { NPE_B, NPE_C, -1 }, /* IXP425 */
+ /* 435 only has A & C, order C then A */
+ { NPE_C, NPE_A, -1 }, /* IXP435 */
+ };
+ /* XXX check feature register instead */
+ return (unit < 3 ? npeidmap[
+ (cpu_id() & CPU_ID_CPU_MASK) == CPU_ID_IXP435][unit] : -1);
+}
- if (unit >= NPE_PORTS_MAX) {
- device_printf(dev, "unit %d not supported\n", unit);
+static int
+npe_probe(device_t dev)
+{
+ static const char *desc[NPE_MAX] = {
+ [NPE_A] = "IXP NPE-A",
+ [NPE_B] = "IXP NPE-B",
+ [NPE_C] = "IXP NPE-C"
+ };
+ int npeid;
+
+ npeid = -1;
+ if (!override_npeid(dev, "npeid", &npeid))
+ npeid = unit2npeid(device_get_unit(dev));
+ if (npeid == -1) {
+ device_printf(dev, "unit not supported\n");
return EINVAL;
}
/* XXX check feature register to see if enabled */
- device_set_desc(dev, npeconfig[unit].desc);
+ device_set_desc(dev, desc[npeid]);
return 0;
}
@@ -295,7 +322,7 @@ npe_attach(device_t 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;
+ struct ifnet *ifp;
int error;
u_char eaddr[6];
@@ -306,26 +333,23 @@ npe_attach(device_t dev)
sc->sc_debug = npe_debug;
sc->sc_tickinterval = npe_tickinterval;
- sc->sc_npe = ixpnpe_attach(dev);
- if (sc->sc_npe == NULL) {
+ ifp = if_alloc(IFT_ETHER);
+ if (ifp == NULL) {
+ device_printf(dev, "cannot allocate ifnet\n");
error = EIO; /* XXX */
goto out;
}
+ /* NB: must be setup prior to invoking mii code */
+ sc->sc_ifp = ifp;
error = npe_activate(dev);
- if (error)
+ if (error) {
+ device_printf(dev, "cannot activate npe\n");
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_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
@@ -350,9 +374,10 @@ npe_attach(device_t dev)
ether_ifattach(ifp, eaddr);
return 0;
out:
- npe_deactivate(dev);
if (ifp != NULL)
if_free(ifp);
+ NPE_LOCK_DESTROY(sc);
+ npe_deactivate(dev);
return error;
}
@@ -373,8 +398,6 @@ npe_detach(device_t dev)
}
NPE_LOCK_DESTROY(sc);
npe_deactivate(dev);
- if (sc->sc_npe != NULL)
- ixpnpe_detach(sc->sc_npe);
return 0;
}
@@ -536,7 +559,6 @@ npe_dma_destroy(struct npe_softc *sc, struct npedma *dma)
}
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);
@@ -548,7 +570,7 @@ npe_dma_destroy(struct npe_softc *sc, struct npedma *dma)
}
static int
-override_addr(device_t dev, const char *resname, int *base, int *size)
+override_addr(device_t dev, const char *resname, int *base)
{
int unit = device_get_unit(dev);
const char *resval;
@@ -558,12 +580,13 @@ override_addr(device_t dev, const char *resname, int *base, int *size)
return 0;
switch (resval[0]) {
case 'A':
- *base = IXP425_MAC_A_HWBASE;
- *size = IXP425_MAC_A_SIZE;
+ *base = IXP435_MAC_A_HWBASE;
break;
case 'B':
*base = IXP425_MAC_B_HWBASE;
- *size = IXP425_MAC_B_SIZE;
+ break;
+ case 'C':
+ *base = IXP425_MAC_C_HWBASE;
break;
default:
device_printf(dev, "Warning, bad value %s for "
@@ -577,6 +600,30 @@ override_addr(device_t dev, const char *resname, int *base, int *size)
}
static int
+override_npeid(device_t dev, const char *resname, int *npeid)
+{
+ int unit = device_get_unit(dev);
+ const char *resval;
+
+ /* XXX warn for wrong hint type */
+ if (resource_string_value("npe", unit, resname, &resval) != 0)
+ return 0;
+ switch (resval[0]) {
+ case 'A': *npeid = NPE_A; break;
+ case 'B': *npeid = NPE_B; break;
+ case 'C': *npeid = NPE_C; break;
+ default:
+ device_printf(dev, "Warning, bad value %s for "
+ "npe.%d.%s ignored\n", resval, unit, resname);
+ return 0;
+ }
+ if (bootverbose)
+ device_printf(dev, "using npe.%d.%s=%s override\n",
+ unit, resname, resval);
+ return 1;
+}
+
+static int
override_unit(device_t dev, const char *resname, int *val, int min, int max)
{
int unit = device_get_unit(dev);
@@ -598,12 +645,81 @@ override_unit(device_t dev, const char *resname, int *val, int min, int max)
}
static int
+override_imageid(device_t dev, const char *resname, uint32_t *val)
+{
+ int unit = device_get_unit(dev);
+ int resval;
+
+ if (resource_int_value("npe", unit, resname, &resval) != 0)
+ return 0;
+ /* XXX validate */
+ if (bootverbose)
+ device_printf(dev, "using npe.%d.%s=0x%x override\n",
+ unit, resname, resval);
+ *val = resval;
+ return 1;
+}
+
+static void
+npe_mac_reset(struct npe_softc *sc)
+{
+ /*
+ * 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);
+}
+
+static int
npe_activate(device_t dev)
{
struct npe_softc * sc = device_get_softc(dev);
- int unit = device_get_unit(dev);
- int error, i, regbase, regsize, miibase, miisize;
- uint32_t imageid;
+ int error, i, macbase, miibase;
+ uint32_t imageid, msg[2];
+
+ /*
+ * Setup NEP ID, MAC, and MII bindings. We allow override
+ * via hints to handle unexpected board configs.
+ */
+ if (!override_npeid(dev, "npeid", &sc->sc_npeid))
+ sc->sc_npeid = unit2npeid(device_get_unit(dev));
+ sc->sc_npe = ixpnpe_attach(dev, sc->sc_npeid);
+ if (sc->sc_npe == NULL) {
+ device_printf(dev, "cannot attach ixpnpe\n");
+ return EIO; /* XXX */
+ }
+
+ /* MAC */
+ if (!override_addr(dev, "mac", &macbase))
+ macbase = npeconfig[sc->sc_npeid].macbase;
+ device_printf(sc->sc_dev, "MAC at 0x%x\n", macbase);
+ if (bus_space_map(sc->sc_iot, macbase, IXP425_REG_SIZE, 0, &sc->sc_ioh)) {
+ device_printf(dev, "cannot map mac registers 0x%x:0x%x\n",
+ macbase, IXP425_REG_SIZE);
+ return ENOMEM;
+ }
+
+ /* PHY */
+ if (!override_unit(dev, "phy", &sc->sc_phy, 0, MII_NPHY-1))
+ sc->sc_phy = npeconfig[sc->sc_npeid].phy;
+ if (!override_addr(dev, "mii", &miibase))
+ miibase = npeconfig[sc->sc_npeid].miibase;
+ device_printf(sc->sc_dev, "MII at 0x%x\n", miibase);
+ if (miibase != macbase) {
+ /*
+ * PHY is mapped through a different MAC, setup an
+ * additional mapping for frobbing the PHY registers.
+ */
+ if (bus_space_map(sc->sc_iot, miibase, IXP425_REG_SIZE, 0, &sc->sc_miih)) {
+ device_printf(dev,
+ "cannot map MII registers 0x%x:0x%x\n",
+ miibase, IXP425_REG_SIZE);
+ return ENOMEM;
+ }
+ } else
+ sc->sc_miih = sc->sc_ioh;
/*
* Load NPE firmware and start it running. We assume
@@ -611,47 +727,38 @@ npe_activate(device_t dev)
* the firmware image starting with the expected version
* and then bump the minor version up to the max.
*/
- imageid = npeconfig[unit].imageid;
+ if (!override_imageid(dev, "imageid", &imageid))
+ imageid = npeconfig[sc->sc_npeid].imageid;
for (;;) {
error = ixpnpe_init(sc->sc_npe, "npe_fw", imageid);
if (error == 0)
break;
/* ESRCH is returned when the requested image is not present */
- if (error != ESRCH)
+ if (error != ESRCH) {
+ device_printf(dev, "cannot init NPE (error %d)\n",
+ error);
return error;
+ }
/* bump the minor version up to the max possible */
- if (NPEIMAGE_MINOR(imageid) == 0xff)
+ if (NPEIMAGE_MINOR(imageid) == 0xff) {
+ device_printf(dev, "cannot locate firmware "
+ "(imageid 0x%08x)\n", imageid);
return error;
+ }
imageid++;
}
-
- if (!override_addr(dev, "mac", &regbase, &regsize)) {
- regbase = npeconfig[unit].regbase;
- regbase = npeconfig[unit].regsize;
- }
- if (bus_space_map(sc->sc_iot, regbase, regsize, 0, &sc->sc_ioh)) {
- device_printf(dev, "Cannot map registers 0x%x:0x%x\n",
- regbase, regsize);
- return ENOMEM;
+ /* NB: firmware should respond with a status msg */
+ if (ixpnpe_recvmsg_sync(sc->sc_npe, msg) != 0) {
+ device_printf(dev, "firmware did not respond as expected\n");
+ return EIO;
}
- if (!override_addr(dev, "mii", &miibase, &miisize)) {
- miibase = npeconfig[unit].miibase;
- miisize = npeconfig[unit].miisize;
+ /* probe for PHY */
+ if (mii_phy_probe(dev, &sc->sc_mii, npe_ifmedia_update, npe_ifmedia_status)) {
+ device_printf(dev, "cannot find PHY %d.\n", sc->sc_phy);
+ return ENXIO;
}
- if (miibase != regbase) {
- /*
- * PHY is mapped through a different MAC, setup an
- * additional mapping for frobbing the PHY registers.
- */
- if (bus_space_map(sc->sc_iot, miibase, miisize, 0, &sc->sc_miih)) {
- device_printf(dev,
- "Cannot map MII registers 0x%x:0x%x\n",
- miibase, 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;
@@ -685,8 +792,6 @@ npe_activate(device_t dev)
}
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
@@ -703,22 +808,24 @@ npe_activate(device_t dev)
* 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;
+ sc->rx_qid = npeconfig[sc->sc_npeid].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;
+ sc->rx_freeqid = npeconfig[sc->sc_npeid].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
+ /*
+ * Setup the NPE to direct all traffic to rx_qid.
+ * When QoS is enabled in the firmware there are
+ * 8 traffic classes; otherwise just 4.
+ */
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;
+ /* disable firewall mode just in case (should be off) */
+ npe_setfirewallmode(sc, 0);
+
+ sc->tx_qid = npeconfig[sc->sc_npeid].tx_qid;
+ sc->tx_doneqid = npeconfig[sc->sc_npeid].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,
@@ -726,16 +833,9 @@ device_printf(sc->sc_dev, "remember to fix rx q setup\n");
tx_doneqid = sc->tx_doneqid;
}
- /*
- * Setup phy port number. We allow override via hints
- * to handle different board configs.
- */
- if (!override_unit(dev, "phy", &sc->sc_phy, 0, MII_NPHY-1))
- sc->sc_phy = npeconfig[unit].phy;
-
- KASSERT(npes[npeconfig[unit].npeid] == NULL,
- ("npe %u already setup", npeconfig[unit].npeid));
- npes[npeconfig[unit].npeid] = sc;
+ KASSERT(npes[sc->sc_npeid] == NULL,
+ ("npe %u already setup", sc->sc_npeid));
+ npes[sc->sc_npeid] = sc;
return 0;
}
@@ -744,33 +844,26 @@ 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;
+ npes[sc->sc_npeid] = NULL;
/* XXX disable q's */
- if (sc->sc_npe != NULL)
+ if (sc->sc_npe != NULL) {
ixpnpe_stop(sc->sc_npe);
+ ixpnpe_detach(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)
+ if (sc->sc_mii != NULL)
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
}
/*
@@ -867,7 +960,7 @@ npe_tick(void *xsc)
* 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) {
+ if (ixpnpe_recvmsg_async(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);
@@ -1139,10 +1232,7 @@ 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);
+ npe_mac_reset(sc);
/* disable transmitter and reciver in the MAC */
WR4(sc, NPE_MAC_RX_CNTRL1,
@@ -1470,12 +1560,22 @@ npeioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
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[0] = (NPE_SETRXQOSENTRY << 24) | (sc->sc_npeid << 20) | classix;
msg[1] = (trafclass << 24) | (1 << 23) | (qid << 16) | (qid << 4);
- return ixpnpe_sendandrecvmsg(sc->sc_npe, msg, msg);
+ return ixpnpe_sendandrecvmsg_sync(sc->sc_npe, msg, msg);
+}
+
+static int
+npe_setfirewallmode(struct npe_softc *sc, int onoff)
+{
+ uint32_t msg[2];
+
+ /* XXX honor onoff */
+ msg[0] = (NPE_SETFIREWALLMODE << 24) | (sc->sc_npeid << 20);
+ msg[1] = 0;
+ return ixpnpe_sendandrecvmsg_sync(sc->sc_npe, msg, msg);
}
/*
@@ -1488,7 +1588,7 @@ npe_updatestats(struct npe_softc *sc)
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 */
+ return ixpnpe_sendmsg_async(sc->sc_npe, msg);
}
#if 0
@@ -1515,7 +1615,7 @@ npe_getimageid(struct npe_softc *sc)
msg[0] = NPE_GETSTATUS << NPE_MAC_MSGID_SHL;
msg[1] = 0;
- return ixpnpe_sendandrecvmsg(sc->sc_npe, msg, msg) == 0 ? msg[1] : 0;
+ return ixpnpe_sendandrecvmsg_sync(sc->sc_npe, msg, msg) == 0 ? msg[1] : 0;
}
/*
@@ -1528,7 +1628,7 @@ npe_setloopback(struct npe_softc *sc, int ena)
msg[0] = (NPE_SETLOOPBACK << NPE_MAC_MSGID_SHL) | (ena != 0);
msg[1] = 0;
- return ixpnpe_sendandrecvmsg(sc->sc_npe, msg, msg);
+ return ixpnpe_sendandrecvmsg_sync(sc->sc_npe, msg, msg);
}
#endif
@@ -1545,10 +1645,13 @@ npe_child_detached(device_t dev, device_t child)
/*
* MII bus support routines.
*/
+#define MII_RD4(sc, reg) bus_space_read_4(sc->sc_iot, sc->sc_miih, reg)
+#define MII_WR4(sc, reg, v) \
+ bus_space_write_4(sc->sc_iot, sc->sc_miih, reg, v)
+
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 */
@@ -1557,37 +1660,34 @@ npe_mii_mdio_read(struct npe_softc *sc, int reg)
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++) {
+ /* NB: typically this takes 25-30 trips */
+ for (i = 0; i < 1000; i++) {
v = npe_mii_mdio_read(sc, NPE_MAC_MDIO_CMD);
if ((v & NPE_MII_GO) == 0)
return 1;
+ DELAY(1);
}
+ device_printf(sc->sc_dev, "%s: timeout after ~1ms, cmd 0x%x\n",
+ __func__, v);
return 0; /* NB: timeout */
-#undef MAXTRIES
}
static int
@@ -1598,15 +1698,13 @@ npe_miibus_readreg(device_t dev, int phy, int reg)
if (phy != sc->sc_phy) /* XXX no auto-detect */
return 0xffff;
- v = (phy << NPE_MII_ADDR_SHL) | (reg << NPE_MII_REG_SHL)
- | NPE_MII_GO;
+ 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
diff --git a/sys/arm/xscale/ixp425/if_npereg.h b/sys/arm/xscale/ixp425/if_npereg.h
index d41905d..01d8c44 100644
--- a/sys/arm/xscale/ixp425/if_npereg.h
+++ b/sys/arm/xscale/ixp425/if_npereg.h
@@ -84,12 +84,6 @@ struct npehwbuf {
} 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)
diff --git a/sys/arm/xscale/ixp425/ixp425.c b/sys/arm/xscale/ixp425/ixp425.c
index af87503..d8b2a3f 100644
--- a/sys/arm/xscale/ixp425/ixp425.c
+++ b/sys/arm/xscale/ixp425/ixp425.c
@@ -58,59 +58,16 @@ __FBSDID("$FreeBSD$");
volatile uint32_t intr_enabled;
uint32_t intr_steer = 0;
+/* ixp43x et. al have +32 IRQ's */
+volatile uint32_t intr_enabled2;
+uint32_t intr_steer2 = 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 },
- { IXP425_EXP_BUS_CS2_HWBASE, IXP425_EXP_BUS_SIZE,
- IXP425_EXP_BUS_CS2_VBASE },
- /* ADI Pronghorn Metro IDE/CF is mapped here */
- { IXP425_EXP_BUS_CS3_HWBASE, IXP425_EXP_BUS_SIZE,
- IXP425_EXP_BUS_CS3_VBASE },
- { IXP425_EXP_BUS_CS4_HWBASE, IXP425_EXP_BUS_SIZE,
- IXP425_EXP_BUS_CS4_VBASE },
-};
-
-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)
{
@@ -146,11 +103,16 @@ arm_mask_irq(uintptr_t nb)
int i;
i = disable_interrupts(I32_bit);
- intr_enabled &= ~(1 << nb);
- ixp425_set_intrmask();
+ if (nb < 32) {
+ intr_enabled &= ~(1 << nb);
+ ixp425_set_intrmask();
+ } else {
+ intr_enabled2 &= ~(1 << (nb - 32));
+ ixp435_set_intrmask();
+ }
restore_interrupts(i);
/*XXX; If it's a GPIO interrupt, ACK it know. Can it be a problem ?*/
- if ((1 << nb) & IXP425_INT_GPIOMASK)
+ if (nb < 32 && ((1 << nb) & IXP425_INT_GPIOMASK))
IXPREG(IXP425_GPIO_VBASE + IXP425_GPIO_GPISR) =
ixp425_irq2gpio_bit(nb);
}
@@ -161,8 +123,13 @@ arm_unmask_irq(uintptr_t nb)
int i;
i = disable_interrupts(I32_bit);
- intr_enabled |= (1 << nb);
- ixp425_set_intrmask();
+ if (nb < 32) {
+ intr_enabled |= (1 << nb);
+ ixp425_set_intrmask();
+ } else {
+ intr_enabled2 |= (1 << (nb - 32));
+ ixp435_set_intrmask();
+ }
restore_interrupts(i);
}
@@ -172,13 +139,21 @@ ixp425_irq_read(void)
return IXPREG(IXP425_INT_STATUS) & intr_enabled;
}
+static __inline uint32_t
+ixp435_irq_read(void)
+{
+ return IXPREG(IXP435_INT_STATUS2) & intr_enabled2;
+}
+
int
arm_get_next_irq(void)
{
- int irq;
+ uint32_t irq;
if ((irq = ixp425_irq_read()))
return (ffs(irq) - 1);
+ if (cpu_is_ixp43x() && (irq = ixp435_irq_read()))
+ return (32 + ffs(irq) - 1);
return (-1);
}
@@ -206,7 +181,7 @@ ixp425_identify(driver_t *driver, device_t parent)
static int
ixp425_probe(device_t dev)
{
- device_set_desc(dev, "Intel IXP425");
+ device_set_desc(dev, "Intel IXP4XX");
return (0);
}
@@ -217,29 +192,34 @@ ixp425_attach(device_t dev)
sc = device_get_softc(dev);
sc->sc_iot = &ixp425_bs_tag;
- KASSERT(ixp425_softc == NULL, ("ixp425_attach called twice?"));
+ KASSERT(ixp425_softc == NULL, ("%s called twice?", __func__));
ixp425_softc = sc;
intr_enabled = 0;
ixp425_set_intrmask();
ixp425_set_intrsteer();
+ if (cpu_is_ixp43x()) {
+ intr_enabled2 = 0;
+ ixp435_set_intrmask();
+ ixp435_set_intrsteer();
+ }
if (bus_dma_tag_create(NULL, 1, 0, BUS_SPACE_MAXADDR_32BIT,
BUS_SPACE_MAXADDR, NULL, NULL, 0xffffffff, 0xff, 0xffffffff, 0,
NULL, NULL, &sc->sc_dmat))
- panic("couldn't create the IXP425 dma tag !");
+ panic("%s: failed to create dma tag", __func__);
sc->sc_irq_rman.rm_type = RMAN_ARRAY;
- sc->sc_irq_rman.rm_descr = "IXP425 IRQs";
+ sc->sc_irq_rman.rm_descr = "IXP4XX 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");
+ rman_manage_region(&sc->sc_irq_rman, 0, cpu_is_ixp43x() ? 63 : 31) != 0)
+ panic("%s: failed to set up IRQ rman", __func__);
sc->sc_mem_rman.rm_type = RMAN_ARRAY;
- sc->sc_mem_rman.rm_descr = "IXP425 Memory";
+ sc->sc_mem_rman.rm_descr = "IXP4XX 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 memory rman");
+ panic("%s: failed to set up memory rman", __func__);
BUS_ADD_CHILD(dev, 0, "pcib", 0);
BUS_ADD_CHILD(dev, 0, "ixpclk", 0);
@@ -252,10 +232,10 @@ ixp425_attach(device_t dev)
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");
+ panic("%s: unable to map GPIO registers", __func__);
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");
+ panic("%s: unable to map Expansion Bus registers", __func__);
bus_generic_probe(dev);
bus_generic_attach(dev);
@@ -317,6 +297,44 @@ ixp425_read_ivar(device_t bus, device_t child, int which, u_char *result)
return EINVAL;
}
+/*
+ * NB: This table handles P->V translations for regions mapped
+ * through bus_alloc_resource. Anything done with bus_space_map
+ * is handled elsewhere and does not require an entry here.
+ *
+ * XXX getvbase is also used by uart_cpu_getdev (hence public)
+ */
+static const struct {
+ uint32_t hwbase;
+ uint32_t size;
+ uint32_t vbase;
+} hwvtrans[] = {
+ { IXP425_IO_HWBASE, IXP425_IO_SIZE, IXP425_IO_VBASE },
+ { IXP425_PCI_HWBASE, IXP425_PCI_SIZE, IXP425_PCI_VBASE },
+ { IXP425_PCI_MEM_HWBASE,IXP425_PCI_MEM_SIZE, IXP425_PCI_MEM_VBASE },
+ /* NB: needed only for uart_cpu_getdev */
+ { IXP425_UART0_HWBASE, IXP425_REG_SIZE, IXP425_UART0_VBASE },
+ { IXP425_UART1_HWBASE, IXP425_REG_SIZE, IXP425_UART1_VBASE },
+ /* NB: need for ixp435 ehci controllers */
+ { IXP435_USB1_HWBASE, IXP435_USB1_SIZE, IXP435_USB1_VBASE },
+ { IXP435_USB2_HWBASE, IXP435_USB2_SIZE, IXP435_USB2_VBASE },
+};
+
+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);
+}
+
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)
@@ -346,8 +364,12 @@ ixp425_alloc_resource(device_t dev, device_t child, int type, int *rid,
start = addr;
end = start + 0x1000; /* XXX */
}
- if (getvbase(start, end - start, &vbase))
+ if (getvbase(start, end - start, &vbase) != 0) {
+ /* likely means above table needs to be updated */
+ device_printf(dev, "%s: no mapping for 0x%lx:0x%lx\n",
+ __func__, start, end-start);
return NULL;
+ }
rv = rman_reserve_resource(rmanp, start, end, count,
flags, child);
if (rv != NULL) {
@@ -366,22 +388,43 @@ ixp425_alloc_resource(device_t dev, device_t child, int type, int *rid,
return rv;
}
+static __inline void
+get_masks(struct resource *res, uint32_t *mask, uint32_t *mask2)
+{
+ int i;
+
+ *mask = 0;
+ for (i = rman_get_start(res); i < 32 && i <= rman_get_end(res); i++)
+ *mask |= 1 << i;
+ *mask2 = 0;
+ for (; i <= rman_get_end(res); i++)
+ *mask2 |= 1 << (i - 32);
+}
+
+static __inline void
+update_masks(uint32_t mask, uint32_t mask2)
+{
+
+ intr_enabled = mask;
+ ixp425_set_intrmask();
+ if (cpu_is_ixp43x()) {
+ intr_enabled2 = mask2;
+ ixp435_set_intrmask();
+ }
+}
+
static int
ixp425_setup_intr(device_t dev, device_t child,
- struct resource *ires, int flags, driver_filter_t *filt,
+ struct resource *res, int flags, driver_filter_t *filt,
driver_intr_t *intr, void *arg, void **cookiep)
{
- uint32_t mask;
- int i;
+ uint32_t mask, mask2;
- BUS_SETUP_INTR(device_get_parent(dev), child, ires, flags, filt, intr,
+ BUS_SETUP_INTR(device_get_parent(dev), child, res, flags, filt, 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();
+ get_masks(res, &mask, &mask2);
+ update_masks(intr_enabled | mask, intr_enabled2 | mask2);
return (0);
}
@@ -390,14 +433,10 @@ static int
ixp425_teardown_intr(device_t dev, device_t child, struct resource *res,
void *cookie)
{
- uint32_t mask;
- int i;
+ uint32_t mask, mask2;
- mask = 0;
- for (i = rman_get_start(res); i <= rman_get_end(res); i++)
- mask |= 1 << i;
- intr_enabled &= ~mask;
- ixp425_set_intrmask();
+ get_masks(res, &mask, &mask2);
+ update_masks(intr_enabled &~ mask, intr_enabled2 &~ mask2);
return (BUS_TEARDOWN_INTR(device_get_parent(dev), child, res, cookie));
}
diff --git a/sys/arm/xscale/ixp425/ixp425_iic.c b/sys/arm/xscale/ixp425/ixp425_iic.c
index 38a86a6..080ebf6 100644
--- a/sys/arm/xscale/ixp425/ixp425_iic.c
+++ b/sys/arm/xscale/ixp425/ixp425_iic.c
@@ -63,7 +63,7 @@ static struct ixpiic_softc *ixpiic_sc = NULL;
static int
ixpiic_probe(device_t dev)
{
- device_set_desc(dev, "IXP425 GPIO-Based I2C Interface");
+ device_set_desc(dev, "IXP4XX GPIO-Based I2C Interface");
return (0);
}
diff --git a/sys/arm/xscale/ixp425/ixp425_intr.h b/sys/arm/xscale/ixp425/ixp425_intr.h
index 27217f4..b7724ff 100644
--- a/sys/arm/xscale/ixp425/ixp425_intr.h
+++ b/sys/arm/xscale/ixp425/ixp425_intr.h
@@ -69,81 +69,21 @@ 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))
+extern __volatile uint32_t intr_enabled2;
+extern uint32_t intr_steer2;
-#if 0
static __inline void __attribute__((__unused__))
-ixp425_splx(int new)
+ixp435_set_intrmask(void)
{
- 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();
+ IXPREG(IXP435_INT_ENABLE2) = intr_enabled2 & IXP435_INT_HWMASK;
}
-static __inline int __attribute__((__unused__))
-ixp425_splraise(int ipl)
+static __inline void
+ixp435_set_intrsteer(void)
{
- 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);
+ IXPREG(IXP435_INT_SELECT2) = intr_steer2 & IXP435_INT_HWMASK;
}
-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
index 7312d0f..0458a83 100644
--- a/sys/arm/xscale/ixp425/ixp425_mem.c
+++ b/sys/arm/xscale/ixp425/ixp425_mem.c
@@ -62,11 +62,10 @@ static uint32_t sdram_other[] = {
0, 0
};
-#define MCU_REG_READ(x) (*(volatile uint32_t *)(IXP425_MCU_VBASE + (x)))
-
uint32_t
ixp425_sdram_size(void)
{
+#define MCU_REG_READ(x) (*(volatile uint32_t *)(IXP425_MCU_VBASE + (x)))
uint32_t size, sdr_config;
sdr_config = MCU_REG_READ(MCU_SDR_CONFIG);
@@ -82,4 +81,22 @@ ixp425_sdram_size(void)
}
return (size);
+#undef MCU_REG_READ
+}
+
+uint32_t
+ixp435_ddram_size(void)
+{
+#define MCU_REG_READ(x) (*(volatile uint32_t *)(IXP425_MCU_VBASE + (x)))
+ uint32_t sbr0;
+
+ /*
+ * Table 198, page 516 shows DDR-I/II SDRAM bank sizes
+ * for SBR0 and SBR1. The manual states both banks must
+ * be programmed to be the same size. We just assume
+ * it's done right and calculate 2x for the memory size.
+ */
+ sbr0 = MCU_REG_READ(MCU_DDR_SBR0);
+ return 2 * 16*(sbr0 & 0x7f) * 1024 * 1024;
+#undef MCU_REG_READ
}
diff --git a/sys/arm/xscale/ixp425/ixp425_npe.c b/sys/arm/xscale/ixp425/ixp425_npe.c
index a35a4ad..ea1928a 100644
--- a/sys/arm/xscale/ixp425/ixp425_npe.c
+++ b/sys/arm/xscale/ixp425/ixp425_npe.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2006 Sam Leffler, Errno Consulting
+ * Copyright (c) 2006-2008 Sam Leffler, Errno Consulting
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -103,23 +103,23 @@ __FBSDID("$FreeBSD$");
#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;
+ 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
@@ -144,42 +144,42 @@ struct ixpnpe_softc {
#define IX_NPEDL_STATE_INFO_ENTRY_SIZE 2
typedef struct {
- uint32_t type;
- uint32_t offset;
+ uint32_t type;
+ uint32_t offset;
} IxNpeDlNpeMgrDownloadMapBlockEntry;
typedef union {
- IxNpeDlNpeMgrDownloadMapBlockEntry block;
- uint32_t eodmMarker;
+ IxNpeDlNpeMgrDownloadMapBlockEntry block;
+ uint32_t eodmMarker;
} IxNpeDlNpeMgrDownloadMapEntry;
typedef struct {
- /* 1st entry in the download map (there may be more than one) */
- IxNpeDlNpeMgrDownloadMapEntry entry[1];
+ /* 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];
+ 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;
+ 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];
+ 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");
+ 0, "IXP4XX NPE debug msgs");
TUNABLE_INT("debug.ixp425npe", &npe_debug);
#define DPRINTF(dev, fmt, ...) do { \
if (npe_debug) device_printf(dev, fmt, __VA_ARGS__); \
@@ -233,116 +233,140 @@ 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;
+ 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);
+ 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)
+ixpnpe_attach(device_t dev, int npeid)
{
- 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,
- NULL, 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;
+ struct npeconfig {
+ uint32_t base;
+ uint32_t size;
+ int irq;
+ uint32_t ins_memsize;
+ uint32_t data_memsize;
+ };
+ static const struct npeconfig npeconfigs[NPE_MAX] = {
+ [NPE_A] = {
+ .base = IXP425_NPE_A_HWBASE,
+ .size = IXP425_NPE_A_SIZE,
+ .irq = IXP425_INT_NPE_A,
+ .ins_memsize = IX_NPEDL_INS_MEMSIZE_WORDS_NPEA,
+ .data_memsize = IX_NPEDL_DATA_MEMSIZE_WORDS_NPEA
+ },
+ [NPE_B] = {
+ .base = IXP425_NPE_B_HWBASE,
+ .size = IXP425_NPE_B_SIZE,
+ .irq = IXP425_INT_NPE_B,
+ .ins_memsize = IX_NPEDL_INS_MEMSIZE_WORDS_NPEB,
+ .data_memsize = IX_NPEDL_DATA_MEMSIZE_WORDS_NPEB
+ },
+ [NPE_C] = {
+ .base = IXP425_NPE_C_HWBASE,
+ .size = IXP425_NPE_C_SIZE,
+ .irq = IXP425_INT_NPE_C,
+ .ins_memsize = IX_NPEDL_INS_MEMSIZE_WORDS_NPEC,
+ .data_memsize = IX_NPEDL_DATA_MEMSIZE_WORDS_NPEC
+ },
+ };
+ struct ixp425_softc *sa = device_get_softc(device_get_parent(dev));
+ struct ixpnpe_softc *sc;
+ const struct npeconfig *config;
+ int rid;
+
+ if (npeid >= NPE_MAX) {
+ device_printf(dev, "%s: bad npeid %d\n", __func__, npeid);
+ return NULL;
+ }
+ config = &npeconfigs[npeid];
+
+ /* 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);
+
+ sc->sc_size = config->size;
+ sc->insMemSize = config->ins_memsize; /* size of instruction memory */
+ sc->dataMemSize = config->data_memsize; /* size of data memory */
+
+ if (bus_space_map(sc->sc_iot, config->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,
+ config->irq, config->irq, 1, RF_ACTIVE);
+ if (sc->sc_irq == NULL)
+ panic("%s: Unable to allocate irq %u", device_get_name(dev),
+ config->irq);
+ /* XXX could be a source of entropy */
+ bus_setup_intr(dev, sc->sc_irq, INTR_TYPE_NET | INTR_MPSAFE,
+ NULL, 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);
+ /* 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;
+ 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;
+ int error;
- if (!sc->started) {
- error = npe_cpu_start(sc);
- if (error == 0)
- sc->started = 1;
- } else
- error = 0;
+ 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;
+ DPRINTF(sc->sc_dev, "%s: error %d\n", __func__, error);
+ return error;
}
int
@@ -359,16 +383,16 @@ ixpnpe_start(struct ixpnpe_softc *sc)
int
ixpnpe_stop(struct ixpnpe_softc *sc)
{
- int error;
+ int error;
- mtx_lock(&sc->sc_mtx);
- error = npe_cpu_stop(sc);
- if (error == 0)
- sc->started = 0;
- mtx_unlock(&sc->sc_mtx);
+ 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;
+ DPRINTF(sc->sc_dev, "%s: error %d\n", __func__, error);
+ return error;
}
/*
@@ -381,9 +405,9 @@ ixpnpe_stop(struct ixpnpe_softc *sc)
* NPE Image Header definition, used in new NPE Image Library format
*/
typedef struct {
- uint32_t marker;
- uint32_t id;
- uint32_t size;
+ uint32_t marker;
+ uint32_t id;
+ uint32_t size;
} IxNpeDlImageMgrImageHeader;
static int
@@ -391,202 +415,218 @@ 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) {
- DPRINTF(sc->sc_dev,
- "imageId 0x%08x not found in image library header\n", imageId);
- /* reached end of library, image not found */
- return ESRCH;
- }
- offset += image->size;
- }
- return ESRCH;
+ 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) {
+ DPRINTF(sc->sc_dev, "imageId 0x%08x not found in "
+ "image library header\n", imageId);
+ /* reached end of library, image not found */
+ return ESRCH;
+ }
+ offset += image->size;
+ }
+ return ESRCH;
}
int
ixpnpe_init(struct ixpnpe_softc *sc, const char *imageName, uint32_t imageId)
{
- uint32_t imageSize;
- const uint32_t *imageCodePtr;
- const struct firmware *fw;
- int error;
+ static const char *devname[4] =
+ { "IXP425", "IXP435/IXP465", "DeviceID#2", "DeviceID#3" };
+ uint32_t imageSize;
+ const uint32_t *imageCodePtr;
+ const struct firmware *fw;
+ int error;
- DPRINTF(sc->sc_dev, "load %s, imageId 0x%08x\n", imageName, imageId);
+ 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;
+ 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;
+ 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;
+
+ device_printf(sc->sc_dev,
+ "load fw image %s.NPE-%c Func 0x%x Rev %u.%u\n",
+ devname[NPEIMAGE_DEVID(imageId)], 'A' + NPEIMAGE_NPEID(imageId),
+ NPEIMAGE_FUNCID(imageId), NPEIMAGE_MAJOR(imageId),
+ NPEIMAGE_MINOR(imageId));
- 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);
+ /*
+ * 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;
+ 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);
+ return (sc->validImage ? sc->functionalityId : 0);
}
static int
npe_checkbits(struct ixpnpe_softc *sc, uint32_t reg, uint32_t expectedBitsSet)
{
- uint32_t val;
+ 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);
+ 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);
+ 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;
+ 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 %u too big for NPE memory\n", blockSize);
+ 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;
+ 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;
+ 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 %u too big for NPE memory\n", blockSize);
+ return EINVAL;
}
- }
- return 0;
+ 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;
- }
+ int i, nentries, error;
+
+ npe_cpu_step_save(sc);
- 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;
+ /* 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) */
+ 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;
+ npe_cpu_step_restore(sc);
+ return error;
}
static int
@@ -594,79 +634,84 @@ 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;
+ 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;
}
- if (error != 0)
- break;
- }
- return error;
+
+ /*
+ * 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;
+ 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 }
+ { 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,
+ 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
@@ -677,212 +722,215 @@ 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)) {
+ 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);
+
/*
- * Step execution of the NPE intruction to read inFIFO using
- * the Debug Executing Context stack.
+ * Clear the FIFOs.
*/
- 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;
+ 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);
}
- }
-
- /*
- * 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);
+
+ 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 write phy reg, error %u\n",
- __func__, error);
- npe_cpu_step_restore(sc);
- return error; /* abort reset */
+ DPRINTF(sc->sc_dev, "%s: cannot step (2), error %u\n",
+ __func__, error);
+ npe_cpu_step_restore(sc);
+ return error;
}
- }
-
- /*
- * 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);
+
+ /*
+ * 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 ctx reg, error %u\n",
- __func__, error);
- npe_cpu_step_restore(sc);
- return error; /* abort reset */
+ 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)
+ continue;
+ 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;
+
+ 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;
+ 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 cmd 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);
+ /* stop NPE execution by issuing cmd 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;
+ /* 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
@@ -904,100 +952,105 @@ 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);
+ 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;
+ 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;
+ 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;
+ 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);
+ 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);
+ 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);
+ 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));
+ /* 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
@@ -1005,69 +1058,70 @@ 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 */
+ 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);
+
+ /* 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);
- }
- return (tries < IX_NPE_DL_MAX_NUM_OF_RETRIES) ? 0 : EIO;
+ for (tries = 0; tries < IX_NPE_DL_MAX_NUM_OF_RETRIES &&
+ newWatchcount == oldWatchcount; tries++) {
+ /* Watch Count register incr's when NPE completes an inst */
+ 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 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);
+ /* 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 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);
+ /* restore IF and IE bits to original values */
+ npe_ecs_reg_write(sc, IX_NPEDL_ECS_DBG_CTXT_REG_2, sc->savedEcsDbgCtxtReg2);
}
static int
@@ -1075,111 +1129,118 @@ 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);
+ 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;
+ }
- /* align value from left to right */
- *regVal = (*regVal >> (IX_NPEDL_REG_SIZE_WORD - regSize)) & mask;
+ /* 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);
- return 0;
+ /* step execution of NPE inst 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;
+ 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 inst with dest reg addr */
+ npeInstruction |= (regAddr << IX_NPEDL_OFFSET_INSTR_DEST);
+
+ /* fill src operand field of inst 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 inst 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;
- 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;
+ error = npe_logical_reg_read(sc, regAddr, regSize, ctxtNum,
+ &retRegVal);
+ if (error == 0 && regVal != retRegVal)
+ error = EIO; /* XXX ambiguous */
}
- /* 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;
}
/*
@@ -1193,57 +1254,61 @@ 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;
+ 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);
- }
+ 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, & 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);
+ }
}
/*
@@ -1252,145 +1317,173 @@ npe_ctx_reg_write(struct ixpnpe_softc *sc, uint32_t ctxtNum,
#define IX_NPEMH_MAXTRIES 100000
static int
-ixpnpe_ofifo_wait(struct ixpnpe_softc *sc)
+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;
+ 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 int
+getmsg(struct ixpnpe_softc *sc, uint32_t msg[2])
+{
+ mtx_assert(&sc->sc_mtx, MA_OWNED);
+
+ if (!ofifo_wait(sc))
+ return EAGAIN;
+ msg[0] = npe_reg_read(sc, IX_NPEFIFO);
+ DPRINTF(sc->sc_dev, "%s: msg0 0x%x\n", __func__, msg[0]);
+ if (!ofifo_wait(sc))
+ return EAGAIN;
+ msg[1] = npe_reg_read(sc, IX_NPEFIFO);
+ DPRINTF(sc->sc_dev, "%s: msg1 0x%x\n", __func__, msg[1]);
+ 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 */
+ struct ixpnpe_softc *sc = arg;
+ uint32_t status;
+
+ mtx_lock(&sc->sc_mtx);
+ status = npe_reg_read(sc, IX_NPESTAT);
+ DPRINTF(sc->sc_dev, "%s: status 0x%x\n", __func__, status);
+ 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? */
+ mtx_unlock(&sc->sc_mtx);
+ return;
}
- }
- wakeup_one(sc);
+ /*
+ * A message is waiting in the output FIFO, copy it so
+ * the interrupt will be silenced.
+ */
+ if (getmsg(sc, sc->sc_msg) == 0)
+ sc->sc_msgwaiting = 1;
+ mtx_unlock(&sc->sc_mtx);
}
static int
-ixpnpe_ififo_wait(struct ixpnpe_softc *sc)
+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;
+ int i;
+
+ for (i = 0; i < IX_NPEMH_MAXTRIES; i++) {
+ if (npe_reg_read(sc, IX_NPESTAT) & IX_NPESTAT_IFNF)
+ 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 int
-ixpnpe_sendmsg_locked(struct ixpnpe_softc *sc, const uint32_t msg[2])
+putmsg(struct ixpnpe_softc *sc, const uint32_t msg[2])
{
- int error = 0;
-
- mtx_assert(&sc->sc_mtx, MA_OWNED);
+ mtx_assert(&sc->sc_mtx, MA_OWNED);
- sc->sc_msgwaiting = 0;
- if (ixpnpe_ififo_wait(sc)) {
+ DPRINTF(sc->sc_dev, "%s: msg 0x%x:0x%x\n", __func__, msg[0], msg[1]);
+ if (!ififo_wait(sc))
+ return EIO;
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;
+ if (!ififo_wait(sc))
+ return EIO;
+ npe_reg_write(sc, IX_NPEFIFO, msg[1]);
+
+ return 0;
}
-static int
-ixpnpe_recvmsg_locked(struct ixpnpe_softc *sc, uint32_t msg[2])
+/*
+ * Send a msg to the NPE and wait for a reply. We spin as
+ * we may be called early with interrupts not properly setup.
+ */
+int
+ixpnpe_sendandrecvmsg_sync(struct ixpnpe_softc *sc,
+ const uint32_t send[2], uint32_t recv[2])
{
- mtx_assert(&sc->sc_mtx, MA_OWNED);
+ int error;
+
+ mtx_lock(&sc->sc_mtx);
+ error = putmsg(sc, send);
+ if (error == 0)
+ error = getmsg(sc, recv);
+ mtx_unlock(&sc->sc_mtx);
- 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;
+ return error;
}
/*
- * 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.
+ * Send a msg to the NPE w/o waiting for a reply.
*/
int
-ixpnpe_sendandrecvmsg(struct ixpnpe_softc *sc,
- const uint32_t send[2], uint32_t recv[2])
+ixpnpe_sendmsg_async(struct ixpnpe_softc *sc, const uint32_t msg[2])
{
- int error;
+ 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);
+ mtx_lock(&sc->sc_mtx);
+ error = putmsg(sc, msg);
+ mtx_unlock(&sc->sc_mtx);
- return error;
+ return error;
}
-/* XXX temporary, not reliable */
+static int
+recvmsg_locked(struct ixpnpe_softc *sc, uint32_t msg[2])
+{
+ mtx_assert(&sc->sc_mtx, MA_OWNED);
+
+ DPRINTF(sc->sc_dev, "%s: msgwaiting %d\n", __func__, sc->sc_msgwaiting);
+ if (sc->sc_msgwaiting) {
+ msg[0] = sc->sc_msg[0];
+ msg[1] = sc->sc_msg[1];
+ sc->sc_msgwaiting = 0;
+ return 0;
+ }
+ return EAGAIN;
+}
+/*
+ * Receive any msg previously received from the NPE. If nothing
+ * is available we return EAGAIN and the caller is required to
+ * do a synchronous receive or try again later.
+ */
int
-ixpnpe_sendmsg(struct ixpnpe_softc *sc, const uint32_t msg[2])
+ixpnpe_recvmsg_async(struct ixpnpe_softc *sc, uint32_t msg[2])
{
- int error;
+ int error;
- mtx_lock(&sc->sc_mtx);
- error = ixpnpe_sendmsg_locked(sc, msg);
- mtx_unlock(&sc->sc_mtx);
+ mtx_lock(&sc->sc_mtx);
+ error = recvmsg_locked(sc, msg);
+ mtx_unlock(&sc->sc_mtx);
- return error;
+ return error;
}
+/*
+ * Receive a msg from the NPE. If one was received asynchronously
+ * then it's returned; otherwise we poll synchronously.
+ */
int
-ixpnpe_recvmsg(struct ixpnpe_softc *sc, uint32_t msg[2])
+ixpnpe_recvmsg_sync(struct ixpnpe_softc *sc, uint32_t msg[2])
{
- int error;
+ 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);
+ mtx_lock(&sc->sc_mtx);
+ error = recvmsg_locked(sc, msg);
+ if (error == EAGAIN)
+ error = getmsg(sc, msg);
+ mtx_unlock(&sc->sc_mtx);
- return error;
+ return error;
}
diff --git a/sys/arm/xscale/ixp425/ixp425_npevar.h b/sys/arm/xscale/ixp425/ixp425_npevar.h
index 6d365fc..286f216 100644
--- a/sys/arm/xscale/ixp425/ixp425_npevar.h
+++ b/sys/arm/xscale/ixp425/ixp425_npevar.h
@@ -95,11 +95,18 @@
#define NPEFW_B_DMA 0x01020100 /* DMA only */
/* XXX ... more not include */
-#define IXP425_NPE_B_IMAGEID 0x01000200
-#define IXP425_NPE_C_IMAGEID 0x02000200
+/* NPE ID's */
+#define NPE_A 0
+#define NPE_B 1
+#define NPE_C 2
+#define NPE_MAX (NPE_C+1)
+
+#define IXP425_NPE_A_IMAGEID 0x10820200
+#define IXP425_NPE_B_IMAGEID 0x01020201
+#define IXP425_NPE_C_IMAGEID 0x02050201
struct ixpnpe_softc;
-struct ixpnpe_softc *ixpnpe_attach(device_t);
+struct ixpnpe_softc *ixpnpe_attach(device_t, int npeid);
void ixpnpe_detach(struct ixpnpe_softc *);
int ixpnpe_stopandreset(struct ixpnpe_softc *);
int ixpnpe_start(struct ixpnpe_softc *);
@@ -108,8 +115,9 @@ 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]);
+int ixpnpe_sendmsg_async(struct ixpnpe_softc *, const uint32_t msg[2]);
+int ixpnpe_recvmsg_async(struct ixpnpe_softc *, uint32_t msg[2]);
+int ixpnpe_sendandrecvmsg_sync(struct ixpnpe_softc *,
+ const uint32_t send[2], uint32_t recv[2]);
+int ixpnpe_recvmsg_sync(struct ixpnpe_softc *, uint32_t msg[2]);
#endif /* _IXP425_NPEVAR_H_ */
diff --git a/sys/arm/xscale/ixp425/ixp425_pci.c b/sys/arm/xscale/ixp425/ixp425_pci.c
index aa40b90..d89c975 100644
--- a/sys/arm/xscale/ixp425/ixp425_pci.c
+++ b/sys/arm/xscale/ixp425/ixp425_pci.c
@@ -89,8 +89,7 @@ static pcib_route_interrupt_t ixppcib_route_interrupt;
static int
ixppcib_probe(device_t dev)
{
-
- device_set_desc(dev, "IXP425 PCI Bus");
+ device_set_desc(dev, "IXP4XX PCI Bus");
return (0);
}
@@ -130,8 +129,8 @@ ixppcib_attach(device_t dev)
if (sc->sc_mem == NULL)
panic("cannot allocate PCI MEM space");
-#define AHB_OFFSET 0x10000000UL
- if (bus_dma_tag_create(NULL, 1, 0, AHB_OFFSET + 64 * 1024 * 1024,
+ /* NB: PCI dma window is 64M so anything above must be bounced */
+ if (bus_dma_tag_create(NULL, 1, 0, IXP425_AHB_OFFSET + 64 * 1024 * 1024,
BUS_SPACE_MAXADDR, NULL, NULL, 0xffffffff, 0xff, 0xffffffff, 0,
NULL, NULL, &sc->sc_dmat))
panic("couldn't create the PCI dma tag !");
@@ -153,7 +152,7 @@ ixppcib_attach(device_t 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";
+ sc->sc_io_rman.rm_descr = "IXP4XX 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) {
@@ -161,7 +160,7 @@ ixppcib_attach(device_t dev)
}
sc->sc_mem_rman.rm_type = RMAN_ARRAY;
- sc->sc_mem_rman.rm_descr = "IXP425 PCI Memory";
+ sc->sc_mem_rman.rm_descr = "IXP4XX 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) {
@@ -173,20 +172,20 @@ ixppcib_attach(device_t dev)
* begin at the physical memory start + OFFSET
*/
PCI_CSR_WRITE_4(sc, PCI_AHBMEMBASE,
- (AHB_OFFSET & 0xFF000000) +
- ((AHB_OFFSET & 0xFF000000) >> 8) +
- ((AHB_OFFSET & 0xFF000000) >> 16) +
- ((AHB_OFFSET & 0xFF000000) >> 24) +
+ (IXP425_AHB_OFFSET & 0xFF000000) +
+ ((IXP425_AHB_OFFSET & 0xFF000000) >> 8) +
+ ((IXP425_AHB_OFFSET & 0xFF000000) >> 16) +
+ ((IXP425_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);
+ IXPPCIB_WRITE_CONF(sc, PCI_MAPREG_BAR0, IXP425_AHB_OFFSET + 0x00000000);
+ IXPPCIB_WRITE_CONF(sc, PCI_MAPREG_BAR1, IXP425_AHB_OFFSET + 0x01000000);
+ IXPPCIB_WRITE_CONF(sc, PCI_MAPREG_BAR2, IXP425_AHB_OFFSET + 0x02000000);
+ IXPPCIB_WRITE_CONF(sc, PCI_MAPREG_BAR3, IXP425_AHB_OFFSET + 0x03000000);
/* Base Address 4 */
IXPPCIB_WRITE_CONF(sc, PCI_MAPREG_BAR4, 0xffffffff);
diff --git a/sys/arm/xscale/ixp425/ixp425_qmgr.c b/sys/arm/xscale/ixp425/ixp425_qmgr.c
index 4188169..4229466 100644
--- a/sys/arm/xscale/ixp425/ixp425_qmgr.c
+++ b/sys/arm/xscale/ixp425/ixp425_qmgr.c
@@ -161,7 +161,7 @@ struct ixpqmgr_softc {
static int qmgr_debug = 0;
SYSCTL_INT(_debug, OID_AUTO, qmgr, CTLFLAG_RW, &qmgr_debug,
- 0, "IXP425 Q-Manager debug msgs");
+ 0, "IXP4XX Q-Manager debug msgs");
TUNABLE_INT("debug.qmgr", &qmgr_debug);
#define DPRINTF(dev, fmt, ...) do { \
if (qmgr_debug) printf(fmt, __VA_ARGS__); \
@@ -204,7 +204,7 @@ aqm_reg_write(struct ixpqmgr_softc *sc, bus_size_t off, uint32_t val)
static int
ixpqmgr_probe(device_t dev)
{
- device_set_desc(dev, "IXP425 Q-Manager");
+ device_set_desc(dev, "IXP4XX Q-Manager");
return 0;
}
diff --git a/sys/arm/xscale/ixp425/ixp425_timer.c b/sys/arm/xscale/ixp425/ixp425_timer.c
index e7717d0..e0b70e9 100644
--- a/sys/arm/xscale/ixp425/ixp425_timer.c
+++ b/sys/arm/xscale/ixp425/ixp425_timer.c
@@ -86,14 +86,14 @@ static struct timecounter ixp425_timer_timecounter = {
NULL, /* no poll_pps */
~0u, /* counter_mask */
COUNTS_PER_SEC, /* frequency */
- "IXP425 Timer", /* name */
+ "IXP4XX Timer", /* name */
1000, /* quality */
};
static int
ixpclk_probe(device_t dev)
{
- device_set_desc(dev, "IXP425 Timer");
+ device_set_desc(dev, "IXP4XX Timer");
return (0);
}
diff --git a/sys/arm/xscale/ixp425/ixp425_wdog.c b/sys/arm/xscale/ixp425/ixp425_wdog.c
index 9db9cce..156378d 100644
--- a/sys/arm/xscale/ixp425/ixp425_wdog.c
+++ b/sys/arm/xscale/ixp425/ixp425_wdog.c
@@ -25,7 +25,7 @@
__FBSDID("$FreeBSD$");
/*
- * IXP425 Watchdog Timer Support.
+ * IXP4XX Watchdog Timer Support.
*/
#include <sys/param.h>
#include <sys/systm.h>
@@ -88,7 +88,7 @@ ixp425_watchdog(void *arg, u_int cmd, int *error)
static int
ixpwdog_probe(device_t dev)
{
- device_set_desc(dev, "IXP425 Watchdog Timer");
+ device_set_desc(dev, "IXP4XX Watchdog Timer");
return (0);
}
diff --git a/sys/arm/xscale/ixp425/ixp425reg.h b/sys/arm/xscale/ixp425/ixp425reg.h
index c7b7206..4b2af08 100644
--- a/sys/arm/xscale/ixp425/ixp425reg.h
+++ b/sys/arm/xscale/ixp425/ixp425reg.h
@@ -64,31 +64,52 @@
*
* 4000 0000 ---------------------------
* SDRAM
- * 1000 0000 ---------------------------
+ * 0000 0000 ---------------------------
*/
/*
- * Virtual memory map for the Intel IXP425 integrated devices
+ * Virtual memory map for the Intel IXP425/IXP435 integrated devices
*/
/*
* FFFF FFFF ---------------------------
*
+ * Global cache clean area
+ * FF00 0000 ---------------------------
+ *
* FC00 0000 ---------------------------
* PCI Data (memory space)
- * F800 0000 ---------------------------
+ * F800 0000 --------------------------- IXP425_PCI_MEM_VBASE
*
* F020 1000 ---------------------------
- * SDRAM Controller
- * F020 0000 ---------------------------
+ * SDRAM/DDR Memory Controller
+ * F020 0000 --------------------------- IXP425_MCU_VBASE
*
- * 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 ---------------------------
+ * F001 7000 EHCI USB 2 (IXP435)
+ * F001 6000 EHCI USB 1 (IXP435)
+ * F020 6000 ---------------------------
+ * Queue manager
+ * F001 2000 --------------------------- IXP425_QMGR_VBASE
+ * PCI Configuration and Status
+ * F001 1000 --------------------------- IXP425_PCI_VBASE
+ * Expansion Bus Configuration
+ * F001 0000 --------------------------- IXP425_EXP_VBASE
+ * F000 F000 Expansion Bus Chip Select 4
+ * F000 E000 Expansion Bus Chip Select 3
+ * F000 D000 Expansion Bus Chip Select 2
+ * F000 C000 Expansion Bus Chip Select 1
+ * F000 B000 USB (option on IXP425)
+ * F000 A000 MAC-B (IXP425) | MAC-C (IXP435)
+ * F000 9000 MAC-A
+ * F000 8000 NPE-C
+ * F000 7000 NPE-B (IXP425)
+ * F000 6000 NPE-A
+ * F000 5000 Timers
+ * F000 4000 GPIO Controller
+ * F000 3000 Interrupt Controller
+ * F000 2000 Performance Monitor Controller (PMC)
+ * F000 1000 UART 1 (IXP425)
+ * F000 0000 UART 0
+ * F000 0000 --------------------------- IXP425_IO_VBASE
*
* 0000 0000 ---------------------------
*
@@ -111,9 +132,10 @@
#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_MAC_B_OFFSET 0x00009000UL /* Ethernet MAC on NPE-B */
+#define IXP425_MAC_C_OFFSET 0x0000a000UL /* Ethernet MAC on NPE-C */
#define IXP425_USB_OFFSET 0x0000b000UL
+#define IXP435_MAC_A_OFFSET 0x0000c000UL /* Ethernet MAC on NPE-A */
#define IXP425_REG_SIZE 0x1000
@@ -142,7 +164,6 @@
/*
* Timers
- *
*/
#define IXP425_TIMER_HWBASE (IXP425_IO_HWBASE + IXP425_TIMER_OFFSET)
#define IXP425_TIMER_VBASE (IXP425_IO_VBASE + IXP425_TIMER_OFFSET)
@@ -224,6 +245,18 @@
#define IXP425_INT_NPE_B 1 /* NPE B */
#define IXP425_INT_NPE_A 0 /* NPE A */
+/* NB: IXP435 has an additional 32 IRQ's */
+#define IXP435_INT_STATUS2 (IXP425_IRQ_VBASE + 0x20)
+#define IXP435_INT_ENABLE2 (IXP425_IRQ_VBASE + 0x24)
+#define IXP435_INT_SELECT2 (IXP425_IRQ_VBASE + 0x28)
+#define IXP435_IRQ_STATUS2 (IXP425_IRQ_VBASE + 0x2C)
+#define IXP435_FIQ_STATUS2 (IXP425_IRQ_VBASE + 0x30)
+
+#define IXP435_INT_USB0 32 /* USB Host 2.0 Host 0 */
+#define IXP435_INT_USB1 33 /* USB Host 2.0 Host 1 */
+#define IXP435_INT_QMGR_PER 60 /* Queue manager parity error */
+#define IXP435_INT_ECC 61 /* Single or multi-bit ECC error */
+
/*
* software interrupt
*/
@@ -239,6 +272,11 @@
(1 << IXP425_INT_bit11)))
#define IXP425_INT_GPIOMASK (0x3ff800c0u)
+#define IXP435_INT_HWMASK ((1 << (IXP435_INT_USB0 - 32)) | \
+ (1 << (IXP435_INT_USB1 - 32)) | \
+ (1 << (IXP435_INT_QMGR_PER - 32)) | \
+ (1 << (IXP435_INT_ECC - 32)))
+
/*
* GPIO
*/
@@ -383,6 +421,8 @@
/* 0xf0011000 */
#define IXP425_PCI_SIZE IXP425_REG_SIZE /* 0x1000 */
+#define IXP425_AHB_OFFSET 0x00000000UL /* AHB bus */
+
/*
* Mapping registers of IXP425 PCI Configuration
*/
@@ -491,6 +531,28 @@
#define MCU_SDR_IR 0x08
/*
+ * IXP435 DDR MCU Registers
+ */
+#define IXP435_MCU_HWBASE 0xcc00e500UL
+#define MCU_DDR_SDIR 0x00 /* DDR SDAM Initialization Reg*/
+#define MCU_DDR_SDCR0 0x04 /* DDR SDRAM Control Reg 0 */
+#define MCU_DDR_SDCR1 0x08 /* DDR SDRAM Control Reg 1 */
+#define MCU_DDR_SDBR 0x0c /* SDRAM Base Register */
+#define MCU_DDR_SBR0 0x10 /* SDRAM Boundary Register 0 */
+#define MCU_DDR_SBR1 0x14 /* SDRAM Boundary Register 1 */
+#define MCU_DDR_ECCR 0x1c /* ECC Control Register */
+#define MCU_DDR_ELOG0 0x20 /* ECC Log Register 0 */
+#define MCU_DDR_ELOG1 0x24 /* ECC Log Register 1 */
+#define MCU_DDR_ECAR0 0x28 /* ECC Address Register 0 */
+#define MCU_DDR_ECAR1 0x2c /* ECC Address Register 1 */
+#define MCU_DDR_ECTST 0x30 /* ECC Test Register */
+#define MCU_DDR_MCISR 0x34 /* MC Interrupt Status Reg */
+#define MCU_DDR_MPTCR 0x3c /* MC Port Transaction Cnt Reg*/
+#define MCU_DDR_RFR 0x48 /* Refresh Frequency Register */
+#define MCU_DDR_SDPR(n) (0x50+(n)*4) /* SDRAM Page Register 0-7 */
+/* NB: RCVDLY at 0x1050 and LEGOVERIDE at 0x1074 */
+
+/*
* Performance Monitoring Unit (CP14)
*
* CP14.0.1 Performance Monitor Control Register(PMNC)
@@ -549,14 +611,18 @@
#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 */
+#define IXP425_MAC_C_HWBASE (IXP425_IO_HWBASE + IXP425_MAC_C_OFFSET)
+#define IXP425_MAC_C_VBASE (IXP425_IO_VBASE + IXP425_MAC_C_OFFSET)
+#define IXP425_MAC_C_SIZE 0x1000 /* Actually only 256 bytes */
+
+#define IXP435_MAC_A_HWBASE (IXP425_IO_HWBASE + IXP435_MAC_A_OFFSET)
+#define IXP435_MAC_A_VBASE (IXP425_IO_VBASE + IXP435_MAC_A_OFFSET)
+#define IXP435_MAC_A_SIZE 0x1000 /* Actually only 256 bytes */
+
/*
* Expansion Bus Data Space.
*/
@@ -565,7 +631,6 @@
#define IXP425_EXP_BUS_CSx_HWBASE(i) \
(IXP425_EXP_BUS_HWBASE + (i)*IXP425_EXP_BUS_SIZE)
-
#define IXP425_EXP_BUS_CSx_VBASE(i) \
(IXP425_MAC_B_VBASE + (i)*IXP425_MAC_B_SIZE)
@@ -588,4 +653,26 @@
#define IXP425_EXP_BUS_CS6_HWBASE IXP425_EXP_BUS_CSx_HWBASE(6)
#define IXP425_EXP_BUS_CS7_HWBASE IXP425_EXP_BUS_CSx_HWBASE(7)
+/*
+ * IXP435/Gateworks Cambria
+ */
+#define CAMBRIA_GPS_HWBASE 0x53FC0000UL /* optional GPS Serial Port */
+#define CAMBRIA_GPS_SIZE 0x40000
+#define CAMBRIA_RS485_HWBASE 0x53F80000UL /* optional RS485 Serial Port */
+#define CAMBRIA_RS485_SIZE 0x40000
+#define CAMBRIA_OCTAL_LED_HWBASE 0x53F40000UL /* Octal Status LED Latch */
+#define CAMBRIA_OCTAL_LED_SIZE 0x1000
+#define CAMBRIA_CFSEL1_HWBASE 0x53E40000UL /* Compact Flash Socket Sel 0 */
+#define CAMBRIA_CFSEL1_SIZE 0x40000
+#define CAMBRIA_CFSEL0_HWBASE 0x53E00000UL /* Compact Flash Socket Sel 1 */
+#define CAMBRIA_CFSEL0_SIZE 0x40000
+
+#define IXP435_USB1_HWBASE 0xcd000000UL /* USB host controller 1 */
+#define IXP435_USB1_VBASE (IXP425_QMGR_VBASE + IXP425_QMGR_SIZE)
+#define IXP435_USB1_SIZE 0x1000 /* NB: only uses 0x300 */
+
+#define IXP435_USB2_HWBASE 0xce000000UL /* USB host controller 2 */
+#define IXP435_USB2_VBASE (IXP435_USB1_VBASE + IXP435_USB1_SIZE)
+#define IXP435_USB2_SIZE 0x1000 /* NB: only uses 0x300 */
+
#endif /* _IXP425REG_H_ */
diff --git a/sys/arm/xscale/ixp425/ixp425var.h b/sys/arm/xscale/ixp425/ixp425var.h
index 7503741..87986be 100644
--- a/sys/arm/xscale/ixp425/ixp425var.h
+++ b/sys/arm/xscale/ixp425/ixp425var.h
@@ -47,6 +47,10 @@
#include <dev/pci/pcivar.h>
#include <sys/rman.h>
+/* NB: cputype is setup by set_cpufuncs */
+#define cpu_is_ixp43x() (cputype == CPU_ID_IXP435)
+#define cpu_is_ixp46x() (cputype == CPU_ID_IXP465)
+
struct ixp425_softc {
device_t sc_dev;
bus_space_tag_t sc_iot;
@@ -94,6 +98,7 @@ 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);
+uint32_t ixp435_ddram_size(void);
int ixp425_md_route_interrupt(device_t, device_t, int);
void ixp425_md_attach(device_t);
diff --git a/sys/arm/xscale/ixp425/ixp435_ehci.c b/sys/arm/xscale/ixp425/ixp435_ehci.c
new file mode 100644
index 0000000..b74f73c
--- /dev/null
+++ b/sys/arm/xscale/ixp425/ixp435_ehci.c
@@ -0,0 +1,357 @@
+/*-
+ * Copyright (c) 2008 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.
+ */
+
+/*
+ * IXP435 attachment driver for the USB Enhanced Host Controller.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_bus.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/queue.h>
+#include <sys/lockmgr.h>
+#include <sys/rman.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+
+#include <dev/usb/usb.h>
+#include <dev/usb/usbdi.h>
+#include <dev/usb/usbdivar.h>
+#include <dev/usb/usb_mem.h>
+
+#include <dev/usb/ehcireg.h>
+#include <dev/usb/ehcivar.h>
+
+#include <arm/xscale/ixp425/ixp425reg.h>
+#include <arm/xscale/ixp425/ixp425var.h>
+
+#define EHCI_VENDORID_IXP4XX 0x42fa05
+#define EHCI_HC_DEVSTR "IXP4XX Integrated USB 2.0 controller"
+
+struct ixp_ehci_softc {
+ ehci_softc_t base; /* storage for EHCI code */
+ bus_space_tag_t iot;
+ bus_space_handle_t ioh;
+ struct bus_space tag; /* tag for private bus space ops */
+};
+
+static int ehci_ixp_detach(device_t self);
+
+static uint8_t ehci_bs_r_1(void *, bus_space_handle_t, bus_size_t);
+static void ehci_bs_w_1(void *, bus_space_handle_t, bus_size_t, u_int8_t);
+static uint16_t ehci_bs_r_2(void *, bus_space_handle_t, bus_size_t);
+static void ehci_bs_w_2(void *, bus_space_handle_t, bus_size_t, uint16_t);
+static uint32_t ehci_bs_r_4(void *, bus_space_handle_t, bus_size_t);
+static void ehci_bs_w_4(void *, bus_space_handle_t, bus_size_t, uint32_t);
+
+static int
+ehci_ixp_suspend(device_t self)
+{
+ ehci_softc_t *sc;
+ int err;
+
+ err = bus_generic_suspend(self);
+ if (err == 0) {
+ sc = device_get_softc(self);
+ ehci_power(PWR_SUSPEND, sc);
+ }
+ return err;
+}
+
+static int
+ehci_ixp_resume(device_t self)
+{
+ ehci_softc_t *sc = device_get_softc(self);
+
+ ehci_power(PWR_RESUME, sc);
+ bus_generic_resume(self);
+ return 0;
+}
+
+static int
+ehci_ixp_shutdown(device_t self)
+{
+ ehci_softc_t *sc;
+ int err;
+
+ err = bus_generic_shutdown(self);
+ if (err == 0) {
+ sc = device_get_softc(self);
+ ehci_shutdown(sc);
+ }
+ return err;
+}
+
+static int
+ehci_ixp_probe(device_t self)
+{
+ device_set_desc(self, EHCI_HC_DEVSTR);
+ return BUS_PROBE_DEFAULT;
+}
+
+static int
+ehci_ixp_attach(device_t self)
+{
+ struct ixp_ehci_softc *isc = device_get_softc(self);
+ ehci_softc_t *sc = &isc->base;
+ int err, rid;
+
+ sc->sc_bus.usbrev = USBREV_2_0;
+
+ /* NB: hints fix the memory location and irq */
+
+ rid = 0;
+ sc->io_res = bus_alloc_resource_any(self, SYS_RES_MEMORY,
+ &rid, RF_ACTIVE);
+ if (sc->io_res == NULL) {
+ device_printf(self, "Could not map memory\n");
+ return ENXIO;
+ }
+
+ /*
+ * Craft special resource for bus space ops that handle
+ * byte-alignment of non-word addresses. Also, since
+ * we're already intercepting bus space ops we handle
+ * the register window offset that could otherwise be
+ * done with bus_space_subregion.
+ */
+ isc->iot = rman_get_bustag(sc->io_res);
+ isc->tag.bs_cookie = isc->iot;
+ /* read single */
+ isc->tag.bs_r_1 = ehci_bs_r_1,
+ isc->tag.bs_r_2 = ehci_bs_r_2,
+ isc->tag.bs_r_4 = ehci_bs_r_4,
+ /* write (single) */
+ isc->tag.bs_w_1 = ehci_bs_w_1,
+ isc->tag.bs_w_2 = ehci_bs_w_2,
+ isc->tag.bs_w_4 = ehci_bs_w_4,
+
+ sc->iot = &isc->tag;
+ sc->ioh = rman_get_bushandle(sc->io_res);
+ sc->sc_size = IXP435_USB1_SIZE - 0x100;
+
+ rid = 0;
+ sc->irq_res = bus_alloc_resource_any(self, SYS_RES_IRQ,
+ &rid, RF_ACTIVE);
+ if (sc->irq_res == NULL) {
+ device_printf(self, "Could not allocate irq\n");
+ ehci_ixp_detach(self);
+ return ENXIO;
+ }
+ sc->sc_bus.bdev = device_add_child(self, "usb", -1);
+ if (!sc->sc_bus.bdev) {
+ device_printf(self, "Could not add USB device\n");
+ ehci_ixp_detach(self);
+ return ENOMEM;
+ }
+ device_set_ivars(sc->sc_bus.bdev, &sc->sc_bus);
+
+ sprintf(sc->sc_vendor, "Intel");
+ sc->sc_id_vendor = EHCI_VENDORID_IXP4XX;
+
+ err = bus_setup_intr(self, sc->irq_res, INTR_TYPE_BIO,
+ NULL, (driver_intr_t*)ehci_intr, sc, &sc->ih);
+ if (err) {
+ device_printf(self, "Could not setup irq, %d\n", err);
+ sc->ih = NULL;
+ ehci_ixp_detach(self);
+ return ENXIO;
+ }
+
+ /* There are no companion USB controllers */
+ sc->sc_ncomp = 0;
+
+ /* Allocate a parent dma tag for DMA maps */
+ err = bus_dma_tag_create(bus_get_dma_tag(self), 1, 0,
+ BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
+ BUS_SPACE_MAXSIZE_32BIT, USB_DMA_NSEG, BUS_SPACE_MAXSIZE_32BIT, 0,
+ NULL, NULL, &sc->sc_bus.parent_dmatag);
+ if (err) {
+ device_printf(self, "Could not allocate parent DMA tag (%d)\n",
+ err);
+ ehci_ixp_detach(self);
+ return ENXIO;
+ }
+
+ /* Allocate a dma tag for transfer buffers */
+ err = bus_dma_tag_create(sc->sc_bus.parent_dmatag, 1, 0,
+ BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
+ BUS_SPACE_MAXSIZE_32BIT, USB_DMA_NSEG, BUS_SPACE_MAXSIZE_32BIT, 0,
+ busdma_lock_mutex, &Giant, &sc->sc_bus.buffer_dmatag);
+ if (err) {
+ device_printf(self, "Could not allocate buffer DMA tag (%d)\n",
+ err);
+ ehci_ixp_detach(self);
+ return ENXIO;
+ }
+
+ /*
+ * Arrange to force Host mode, select big-endian byte alignment,
+ * and arrange to not terminate reset operations (the adapter
+ * will ignore it if we do but might as well save a reg write).
+ * Also, the controller has an embedded Transaction Translator
+ * which means port speed must be read from the Port Status
+ * register following a port enable.
+ */
+ sc->sc_flags |= EHCI_SCFLG_SETMODE
+ | EHCI_SCFLG_NORESTERM
+ | EHCI_SCFLG_FORCESPEED
+ | EHCI_SCFLG_BIGEDESC
+ ;
+ err = ehci_init(sc);
+ if (!err) {
+ sc->sc_flags |= EHCI_SCFLG_DONEINIT;
+ err = device_probe_and_attach(sc->sc_bus.bdev);
+ }
+
+ if (err) {
+ device_printf(self, "USB init failed err=%d\n", err);
+ ehci_ixp_detach(self);
+ return EIO;
+ }
+ return 0;
+}
+
+static int
+ehci_ixp_detach(device_t self)
+{
+ struct ixp_ehci_softc *isc = device_get_softc(self);
+ ehci_softc_t *sc = &isc->base;
+ int err;
+
+ if (sc->sc_flags & EHCI_SCFLG_DONEINIT) {
+ ehci_detach(sc, 0);
+ sc->sc_flags &= ~EHCI_SCFLG_DONEINIT;
+ }
+
+ /*
+ * Disable interrupts that might have been switched on in ehci_init()
+ */
+ if (sc->iot && sc->ioh)
+ bus_space_write_4(sc->iot, sc->ioh, EHCI_USBINTR, 0);
+ if (sc->sc_bus.parent_dmatag != NULL)
+ bus_dma_tag_destroy(sc->sc_bus.parent_dmatag);
+ if (sc->sc_bus.buffer_dmatag != NULL)
+ bus_dma_tag_destroy(sc->sc_bus.buffer_dmatag);
+
+ if (sc->irq_res && sc->ih) {
+ err = bus_teardown_intr(self, sc->irq_res, sc->ih);
+
+ if (err)
+ device_printf(self, "Could not tear down irq, %d\n",
+ err);
+ sc->ih = NULL;
+ }
+ if (sc->sc_bus.bdev != NULL) {
+ device_delete_child(self, sc->sc_bus.bdev);
+ sc->sc_bus.bdev = NULL;
+ }
+ if (sc->irq_res != NULL) {
+ bus_release_resource(self, SYS_RES_IRQ, 0, sc->irq_res);
+ sc->irq_res = NULL;
+ }
+ if (sc->io_res != NULL) {
+ bus_release_resource(self, SYS_RES_MEMORY, 0, sc->io_res);
+ sc->io_res = NULL;
+ }
+ sc->iot = 0;
+ sc->ioh = 0;
+ return 0;
+}
+
+/*
+ * Bus space accessors for PIO operations.
+ */
+
+static uint8_t
+ehci_bs_r_1(void *t, bus_space_handle_t h, bus_size_t o)
+{
+ return bus_space_read_1((bus_space_tag_t) t, h,
+ 0x100 + (o &~ 3) + (3 - (o & 3)));
+}
+
+static void
+ehci_bs_w_1(void *t, bus_space_handle_t h, bus_size_t o, u_int8_t v)
+{
+ panic("%s", __func__);
+}
+
+static uint16_t
+ehci_bs_r_2(void *t, bus_space_handle_t h, bus_size_t o)
+{
+ return bus_space_read_2((bus_space_tag_t) t, h,
+ 0x100 + (o &~ 3) + (2 - (o & 3)));
+}
+
+static void
+ehci_bs_w_2(void *t, bus_space_handle_t h, bus_size_t o, uint16_t v)
+{
+ panic("%s", __func__);
+}
+
+static uint32_t
+ehci_bs_r_4(void *t, bus_space_handle_t h, bus_size_t o)
+{
+ return bus_space_read_4((bus_space_tag_t) t, h, 0x100 + o);
+}
+
+static void
+ehci_bs_w_4(void *t, bus_space_handle_t h, bus_size_t o, uint32_t v)
+{
+ bus_space_write_4((bus_space_tag_t) t, h, 0x100 + o, v);
+}
+
+static device_method_t ehci_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, ehci_ixp_probe),
+ DEVMETHOD(device_attach, ehci_ixp_attach),
+ DEVMETHOD(device_detach, ehci_ixp_detach),
+ DEVMETHOD(device_suspend, ehci_ixp_suspend),
+ DEVMETHOD(device_resume, ehci_ixp_resume),
+ DEVMETHOD(device_shutdown, ehci_ixp_shutdown),
+
+ /* Bus interface */
+ DEVMETHOD(bus_print_child, bus_generic_print_child),
+
+ {0, 0}
+};
+
+static driver_t ehci_driver = {
+ "ehci",
+ ehci_methods,
+ sizeof(struct ixp_ehci_softc),
+};
+static devclass_t ehci_devclass;
+DRIVER_MODULE(ehci, ixp, ehci_driver, ehci_devclass, 0, 0);
diff --git a/sys/arm/xscale/ixp425/std.avila b/sys/arm/xscale/ixp425/std.avila
index b69a65e..77036ee 100644
--- a/sys/arm/xscale/ixp425/std.avila
+++ b/sys/arm/xscale/ixp425/std.avila
@@ -1,6 +1,22 @@
-#GW2348-4 board configuration
#$FreeBSD$
-include "../xscale/ixp425/std.ixp425"
+
+#
+# Gateworks GW23XX board configuration
+#
files "../xscale/ixp425/files.avila"
-makeoptions KERNPHYSADDR=0x10200000
+#
+# Physical memory starts at 0. We assume images are loaded at
+# 0x200000, e.g. from redboot with load -b 0x200000 kernel.
+#
+# Redboot is expected to handle unmapping the flash memory that
+# appears at 0 on boot. Likewise we expect the expansion bus to
+# be remapped away from 0.
+#
+options PHYSADDR=0x00000000
+options KERNPHYSADDR=0x00200000
+makeoptions KERNPHYSADDR=0x00200000
+options KERNVIRTADDR=0xc0200000 # Used in ldscript.arm
makeoptions KERNVIRTADDR=0xc0200000
+options FLASHADDR=0x50000000
+options LOADERRAMADDR=0x00000000
+options STARTUP_PAGETABLE_ADDR=0x00000000
diff --git a/sys/arm/xscale/ixp425/std.ixp435 b/sys/arm/xscale/ixp425/std.ixp435
new file mode 100644
index 0000000..2cc099a
--- /dev/null
+++ b/sys/arm/xscale/ixp425/std.ixp435
@@ -0,0 +1,8 @@
+#XScale IXP435 generic configuration
+#$FreeBSD$
+
+files "../xscale/ixp425/files.ixp425"
+include "../xscale/std.xscale"
+cpu CPU_XSCALE_IXP435
+cpu CPU_XSCALE_IXP425
+makeoption ARM_BIG_ENDIAN
diff --git a/sys/conf/files b/sys/conf/files
index d09ead4..8c2316fa 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -1476,6 +1476,7 @@ dev/ubsec/ubsec.c optional ubsec
#
# USB support
dev/usb/ehci.c optional ehci
+dev/usb/ehci_ddb.c optional ehci
dev/usb/ehci_pci.c optional ehci pci
dev/usb/hid.c optional usb
dev/usb/if_aue.c optional aue
diff --git a/sys/conf/options.arm b/sys/conf/options.arm
index 6c8732c..2985e00 100644
--- a/sys/conf/options.arm
+++ b/sys/conf/options.arm
@@ -15,6 +15,7 @@ CPU_XSCALE_80219 opt_global.h
CPU_XSCALE_80321 opt_global.h
CPU_XSCALE_81342 opt_global.h
CPU_XSCALE_IXP425 opt_global.h
+CPU_XSCALE_IXP435 opt_global.h
CPU_XSCALE_PXA2X0 opt_global.h
FLASHADDR opt_global.h
KERNPHYSADDR opt_global.h
diff --git a/sys/contrib/dev/npe/IxNpeMicrocode.dat.uu b/sys/contrib/dev/npe/IxNpeMicrocode.dat.uu
index c83422b..0f380cd 100644
--- a/sys/contrib/dev/npe/IxNpeMicrocode.dat.uu
+++ b/sys/contrib/dev/npe/IxNpeMicrocode.dat.uu
@@ -1,129 +1,209 @@
-$FreeBSD$
-
begin 644 IxNpeMicrocode.dat
-M_NWP#1"``@$```NL``````````L````!```%7@````$```MB`````0``"Z(`
-M```!```+I0````\````````%41``?A`0`/SP$`!TH!!.O@$%J/R```#YT```
-M=O`0`'0`$`*^`1"$``L0`H@/$`+!_A`"Q?T0`H8#$`*"`A`"__H`6(``$(@`
-M"Q`"P?<0A$&'$`*V`A`"__00```+`"@`"P`2__$);(H@#Y#`$`^H0!`0`KX`
-M$$0`"P'4P```38<(`"V'!``UAP0`&8<$`"&'!`!1AP0`78<$$$1^<`'8P``0
-M`8L1$`&3$1`!FQ$%!(I0!2@0@`4X$I`%1!2@!4`6L`5L&,`%:!K0$`!^$A`"
-M_?402``+#`#```0`Q``)#((0"2A(0!`"O@$)!'=`$`,^`0F,@A`)J$A`$`*^
-M`0F$=U`0`SX!$$1T\`'DX``0`KX!$`&]T1`!N=$0`3?1$`$_T1``=!(0`OW[
-M$``UD!`"O@$01'Z`!X3\`!!&O@$!\.``$`&#T1`!B]$0`9K!$$63T@`(_"$0
-M`'X2$`+Y^A!(Z@`"`.````AQ@!`!Z\\03``+!:C\@```?@``$'8`$`-_H1`!
-MRAT0`KX#`##J`!`!Z@D018H'``1V0!``R@<0`S8&$$0`"P`$=S`0`P`!$`!W
-M0``JO@D01``+``1W,!`#``$)*&A`$PF^$!``=T`)!SX!"32*(`DH:,`)#(I0
-M"0<^`1`!F@D0`:(%"37F'`DUYA8)->X`$`#:!Q`"N`80`9H($$7*"0``=V``
-M,=H*$)<^%@DH:(`)#:88"27*!A`!D`@0`.0`"22C$`D$D1$0`=`($`#10!`!
-MT`H0`8H=$`,^E!!$``L``'=@$)<^`044A"`0`9H%$`&2(1`!BB`0``2P$(*^
-MA044A"`0`<H&$`&2(1`!BB`0@50`$`%6"1`!2`$0`$@`$`'0`Q`!DF`0`9IA
-M$`'2"Q`!DF(0`=H,$`&L9A!%T@T0(.P'$`*V9Q!$:@``P.P'$`!K'A`!*`D0
-M`6H#$`!I1A`"N$L0`)CP$$2<D`,@Q0`0`:@C$`&B(!`!$@(0`)57$`";'1`"
-MME\0`%``$`&D!A``Q(`0`\#@$`&J(1`!HB`0`)57$`";'1`"ME`0`,1/$`#$
-M&A`!JB$0`:(@$`"55Q``FQT0`K9)$`#$3Q``Q!H0`:HA$`&B(!``E5<0`)L=
-M$`*V0A``Q$\0`,0:$`&J(1`!HB`0`)57$`";'1`"MCL0`,1/$`#$&A`!JB$0
-M`:(@$`"55Q``FQT0`K8T$`#$3Q``Q!H0`:HA$`&B(!``E5<0`)L=$`*V+1``
-MQ$\0`,0:$`&J(1`!HB`0`)57$`";'1`"MB80`,1/$`#$&A`!JB$0`:(@$`"5
-M5Q``FQT0`K8?$`#$3Q``Q!H0`:HA$`&B(!``E5<0`)L=$`*V&!!$``L`'&GP
-M$`%H`!`!$@D0```+$`!3(Q`!4@@0`%.`$`%2`A`"OA80`%``$`%0!1``;B80
-M`K@#$`%L`!`"__00`1("$```"Q``4H00`5("$`+_[Q`!K&@0`O^9$``19Q`"
-M^>@0`&X6$`+WYA``;B00`6XG$`!2`!`!4@(0`9H%$`$$"1``V4$0`)S7$`+[
-M01!%V`H`!'<P$`,``0DH:4`3":X`$)1Q$`DEAV0)!'=`"3WN``5//@$0@$46
-M`#+W91``:#`0`"@C$`!H-Q`"MDT0`$6&$`*X1Q!%*`,`&$3S$``%1!`!D`,0
-M`40#$$11XP,,Q$`0`%'J$``&@1``1`D`))(@$`&8(A`!D`@0`!;``""2D!``
-M``L0```+$`%:!!`!R`D01JXM``#0!Q`"N`T0`<@("2AI(!,)IA@));X8"26F
-M$`DEK@@)):8`"26F!`DEK@P)):X0"26N%`D'/A40`(B2$`'("`DH:(`3":88
-M"26^&`DEIA`)!SX!$$6:"0``::`)*"E`"0S:80D<["`)):80"26N"`DEI@`)
-M):8$"26N#`DEKA`)):X4"0<^`1``Z@`0`>P($`%H`Q`!H@D)*&A`$`!F!!,)
-MIB`))*,0"01W0!`#?O$#&-'`$`&B@!`!*`(0`.(1$`'B@!`"O@40`2@"$```
-M"Q``:880`OFW$`#J`!`!B@D0`>H)$`'L"!`!:`,0`O[G$`!%1!`"OE40EJ#D
-M!1",(!``1``0`$&$$`&(81`!!@@&-<=$!C22(`8TFB`0`=-1$`&0'Q`!VU$0
-M`%'Z$``0IA`"N,,01:`"`L#0@!`#P,`0`:J!$`&B@!``FU<0`)4]$`*V(A``
-MT$\01-`:`L#0`A`!JH$0`:*`$`";5Q``E3T0`K8:$`#03Q!$T!H"P-`"$`&J
-M@1`!HH`0`)M7$`"5/1`"MA(0`-!/$$30&@+`T`(0`:J!$`&B@!``FU<0`)4]
-M$`*V"A``T$\01-`:`L#0`A`!JH$0`:*`$`";5Q``E3T0`K8"$`!B'!`!D!\0
-M`9I=$``BA1``8A80`KB7$`&J'A`!E%P0`&@6$`*X#1``6!80`K8)$`#B"!``
-ME3<0`)L=$`*V!Q``+K,0`"UW$`*XGQ`"O@,0`!=7$`*XG!!,``L`,-@'&$#<
-M#0``U`T0`O>M$`!2%A`"N(40`:`!$`#0@!`#P,`0`:*!$`&J@!``E1<0`)M=
-M$`*V/!``T$\0`-`:$`&B@1`!JH`0`)47$`";71`"MC40`-!/$`#0&A`!HH$0
-M`:J`$`"5%Q``FUT0`K8N$`#03Q``T!H0`:*!$`&J@!``E1<0`)M=$`*V)Q``
-MT$\0`-`:$`&B@1`!JH`0`)47$`";71`"MB`0`-!/$`#0&A`!HH$0`:J`$`"5
-M%Q``FUT0`K89$`#03Q``T!H0`:*!$`&J@!``E1<0`)M=$`*V$A``T$\0`-`:
-M$`&B@1`!JH`0`)47$`";71`"M@L0`-!/$`#0&A`!HH$0`:J`$`"5%Q``FUT0
-M`K8$$`!D"!`!9&80`KX$$`%D9A``9`<0`K9%$`!PT`8UQT00`:I3$`!D`!!%
-M9&`!`.@'$$:X`P``1$00`KX-$-CIUQ`"N`L0`$2$$`*^"1"6H$`%$(P@$`!!
-MC!`!B&$0`'$0!C7'1!``1A(0`K8R$`*6`Q`!1&<%4W_V$`&H`P8,DB`&$(@@
-M$`#1^A!$B)4`_,GS!BZX#A``J)<0`KHH$$1%%`(8U<80`K@*$`!4,Q``!*00
-ME41G!5%281``0880`WD]$`%08!`#?SL0`-44$`!!AA`"N`401``+``!%-!"4
-M``L%441G$`#5ZA``U$80FK8S!B*^,A``27`0`KX$$`!)@!``4?H0`$F>$`!$
-M-!`"OA40`$E`$`*^$Q``25`0`KX1$`!)8!`"O@\0`$D@$`*^#1``23`0`KX'
-M$`!),!`"OB,0`$D0$`!$-!`"O@80`$D0$$0`"P``1300E``+!5%$9Q!$``L`
-M'$?P!C1&$@8T<.`&-``+$`*^`1`"E@(0`WW[!@R2(!`"O`(&(KX*$`!@,!``
-M(",&+&`W$`*V!A!$``L"&-7&$`*X"1"4190%441G$`#5ZA"8%$0%$(P@$```
-M"P51U&`0`W[[$$0`"P``1300E``+!5%$9Q``U180`O?U!B+_]!!(``L`'$?P
-M``1W``8T1A(&-'#@!C0`"Q`"O@$0`I8"$`-]^Q!$``L``'?@$`,^`1"4``L%
-M$(P@$$@`"P`$=P```$4P!5%$9Q"(``L`,``+$`*\`@8@``L0`W[=!120(!``
-M``L02:"``Q30P`"$Y7`%3*43$$:V!P``Y5,02.47'_SE+P,4Y$$0`2#@$`*^
-M!0`<80,0`W?R$`!AZA``8($0`!,!$`!0"1`!JH`0```+$`#J$1`!ZH`0`W_I
-M$`!V(`"W!`$0`9+!$`&:P!`!Y,,0D*40!4!00!`!+*40@*"P`#ZX`@`0``L0
-M@%_C$$7:`0``=]`0`QX!$$1V$`6H_!`0`P(!$XVF!`FH72`0D'=0"8<^`0FU
-MY@`)M(H@";2J(`FTDB`%$)`@";2:(!`!A($0`>H?$`#,!Q`"MA`0`,@'$`*V
-M#A`!G!L)C*M0$`"<=Q`"NGH0`)QP$`!=A!`!W(`0`(AW$`"(?A``C%(0`<P<
-M$`#-P!`"OAT0@``+`+:^8@F,JU`0`(Q1$`"L<!``;800`>R`$`#-P!`"OA03
-MC:8`":A<P`F$=U`0`SX!$`&8'`FUY@`)M(@@";7^'!``R`<`MO?W$`"(UQ``
-MB-X0`)A2$$78'```=]`0`QX!$`!V$!`#`@$3C;X<$$6J'P`@R`<0`KH.$``M
-M<!!$;R```&WS$`!L!Q`"M@D0`"]B$`!L`!``K%<)J"Y>$`'L'0F<A#`)A'=0
-M$$<^%A``[4`0`*Q7":@N7A`![!T)G(0P"81W4!`#/@\0`"9X$`!GZA``9A$0
-M`#$P";7'Q!``)3<0`KH2$$@E,@!@Q`(`8.`"$`*^#!`#?Y,0@``+`+:^(PF]
-M_AP)N*0`$`&L'1``H#`0`.`\$$2%<0*`Q`<0`OWK$``Q(`FUQ\0`M`]Q$`*Z
-M"A"03T(0`$P1$`*V!A``3$<0`K@%$`!P,`503``%0&`0!5!,$A"`B7(01OG`
-M$`&8'!``=A`0`)C3$`-YKA!,``L`!'8P`"3-\0`<3?D0D#!@!5``"Q`#)`00
-M1``+``1V,!`#)`$0`'80$(,"`1.-I@@0`:H!":A<0`FDZ@001``+`"C\$`F$
-M=U`0`O_/$`&J&1"```L`M.H1$`'J&1`"_^\0A``+`#P`"P8K.`$`4&`0`*AW
-M(!"3/@$%%)0@$(100`"U@*`0```+$`!!C!`!P*``4&`0`!6$H1"0D!<&&)`>
-M$`!W$`5,<1`&)8<D!5R:(!``P4(01'94`H#$!Q`"O`80`%@F$`+5YQ`#.`$0
-M`'<@$)-_]!!$4$`"(,0`$`"0%P88D!X0`O_W$$0`"P``=U`0D``+!5R:(!``
-M``L0`%@F$`,X`044E"`0```+$`&`H!````L0`$&&$`*X`P5,``L0`O_U!5R:
-M(!"$``L`,%@F$`+_S`5,P4`01``+``!WX!"7/@$%$)0@$`!'$`511J<01<"@
-M``!W4!"3?_<01``+``1W,!`#``$3":90"2A80!``=T`)!SX!"32:(!``D#``
-M,-H'$`*V'@`YVH`0`80C$`!>&A``7N,015Z%`OC4`!``%O$0`*00$`*V"1``
-M#/<0`KH'$`&@H!````L0`:3#$`'0PQ`!Y(,0`KX$$``,\!`!P(,0`("0$`$:
-MY1``X``01*$W`!Q;[A``'M(0`%_Z$``P\!`!T;\0`,07$$0`"P`$=B`0`WW6
-M`!1V,!`#?_L&"*H@$$0`"P+XX4`0`)%P$`-W_!``[!80`K8%$`&:R08P``L0
-M`-H1$`':R1!%FL(`'-&#$`#1AQ`"N`,0`-H1$`':PA!%FL8`(.P&$`*V`Q``
-MVA$0`=K&$`#L)A!&N`X`#.V&$`-WYQ`!FL`0`.UV$`*V!A`!FL$0```+$`#:
-M$1`!VL$0`W_?$`#:$1`!VL`0`W_<$`&:PP8P[$80`K8$$`#:$1`!VL,0`W_6
-M$$6:Q``,[880`K8$$`#:$1`!VL00`W_0$$6:Q0`@[`80`WG-$`#:$1`!VL40
-M`W_*$$0`"P``R7`0`SX!$`$44!`!%E@0`%0L$`!6+!`!5%`0`598$`$40!`!
-M%D@0`%0L$`!6+!`!5$`0159(`P#1L!`!D9`0`,DA$`"05Q`#??``,W_L``1V
-M\!`#/@$/A:8$$`,^`0^%I@@01``+``1VX!`#/@$/B>8$$`,^`1`!H@$/B*H@
-M$$1@&@+LT0`0`!,!$`!0"1`!D9`0`>H"$$?`@!`!D@00```+$`'2`A!&_^H0
-M`>0,$`'H#1`!Z@<01O_F$`'J!1``3``0`0X!$`#(`!``S$H0`,PJ$$;WWQ`"
-M/J$02'XP``!VP`,`U;`0`<FP`"L^`1!&_]@0`>H%$`"=,!!,R```0,V``!S1
-MP`,$U8`0`<P;$`'1L!`!7@$0`%X'$$;WS0!`S3`0`-@`$``:X!``C-(0`-@0
-M$`':`Q!$``L`!'<P$(``"Q`#/@$3":84"2AG0`D$=T`0`SX!$`&:`PD]YA00
-M`'$0"37'1!``7A(0`%@1$`':`P`P&-<0`K8($`!>!Q`"^>X02<P;`"#-P@,$
-MU8`0`<VP$`*^#!`!S!L02)!P`"#1P@,$U8`0`=&P$`#,<A``6AH0`=H#$`!>
-M!Q`"^=\01O^D$``,T!``#,(0`$Q*$`!W4!``#F`0`$TG$`!/+A``DI40`#!P
-M$`'341``#'(0`WGY$$;_EP,4R,`01>H%``3-0!`"/E802``+``3,P`+XR4`0
-M`CY2$`$@!!``3M`0`&!7$$;YBP,4R,`0`-(`$``P<!`!TU$01$ZP`OC)0!``
-M,'`0`=-1$$;_@@,`R9`016=0`P#((!!%[5`#',D@$`'I41`!95`01O]Z$```
-M"Q"$``L`$``+$$;_=@,<R$`0`>M0$$;_<P!LU'`011X`!@#14!``6!`0`!\W
-M$$;W;1`!9@`02&87`!11#@!PU9X&(%A.!@QTX`8RO@$01#:``##X0!``=/`0
-M`KX!$``VD!``N+`0`#[`$`!T@!!&_UT##,A`$`!D`!``Y#H0`(DQ$`'L01`!
-M:D00`6A%$$;_50,<R+`0`6=0$$;_4@,<R*`026=0`QS)```TV;`01=E0`"#,
-M`!!%Z@4"P,@`$$8^(!`!H@$0`-P`$$@?(``TV;`#',D`$`"8\A`!V5`01O]!
-M`P#)H!`!9D`01O\^$`'D`1!$``L`!'<P$(,^`0D-IA0`*.5`$`"D=PDH)GX0
-M`(TR$`!F,1``9^H0`#$P"26'1`D$=T`0`SX!"3WF%``PS!<0`:0!$`+][Q`#
-MP.`0`>0!$$0`"P`$=S`0@SX!"0VF%``HY4`0`*1W"2@F?@D$C3(0`'=`"3WF
-M%!`#/@$).*8`$`#,%Q``,3`)-<=$`#&D`1`"_?`0`\#@$$;_*1!&_RP01O\O
-M$$;_/!!&_WP01O^'$$;_CQ!&_P\01O\.$$;_#1!&_PP01O^O$$;_"A!&_[40
-M1O^W$$;_!Q!&_P801O\%$$;_DA!&_P,01O^-$$;_P1!&_X<0`'3@$$:^`0`4
-M=P`0`'3P$$:^`0`0=U`0`#60$`*^`1"`=A`0`P(!$$0`"P,@T8`3C::`":A8
-M0`FDVA`)A'=0$`,^`0"T``L01``+``1V\!`#/@$0A``+`#@`"Q!$``L#(-'`
-M#X6'A!`#/@$/A8>`$$0`"P`(=F`0`SX!$`!TX!!*O@$`4/D0``AV@!``=/`0
-M2KX!`'#X8``(=D`0`#60$$:^`0+\T<`0`9J`$(@`"P`HVA$0A=J``#@`"Q!$
-M``L`"'9@$`-_SQ````L0```+````````!@(`````````````````````````
+M_NWP#1""`@````])``````````\````!```'1`````$```[-`````0``#MT`
+M```!```.]0````$```]"`````0``#T4````/````````!S,0`'X0$`#\\!``
+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
+M1O]W$$;_>A!&_W<01O[:$$;_P1````L0```+````````!X<`````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
@@ -168,6 +248,13 @@ M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
+M1````````!>?&H0``````````!>?&H3_____```````````````````````?
+M`>(`$0`````````_`=L`,P`````````O`=@`(@`$````````````````````
+M`````````````````````````````````````````````````"U"!6P5`2U$
+M`DHP``%!`U@"`"U#`&TD`"U`!9`B`"U(``"````/``"``"U%!@LO``````"`
+M`#6"!;U\`#6&`SX7!@````"```````"````/``"``#6&!?1,`P`/`````0``
+M%``>8```'KP5`````````!4``````!\$````````']`````````?W```````
+M`!^,````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
@@ -191,6 +278,13 @@ M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
+M`````````````````````````````````````````!0(````````%!``````
+M```4&````````!0@````````%"@````````4,````````!0X````````%$``
+M```````42````````!10````````%%@````````48````````!1H````````
+M%'`````````4>````````!2`````````%(@````````4D````````!28````
+M````%*`````````4J````````!2P````````%+@````````4P````````!3(
+M````````%-`````````4V````````!3@````````%.@````````4\```````
+M`!3X````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
@@ -206,21 +300,7 @@ M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````````!````````!>?
-M&H0``````````!>?&H3_____```````````````````````?`7H`$0``````
-M```_`7,`,P`````````O`7``(@`$````````````````````````````````
-M`````````````````````````````````````"U"`V<5`2U$`80P``%!`L("
-M`"U#`&TD`"U``Z,B`"U(``"``"U'!1U&`2U%!!XO``````"``#6"`]!\`#6&
-M`J@7!@````"```````"````/``"``#6&!`=,`P`/`````0``$``7P```&`P1
-M`````````!$``````!@L````````&.P````````8^````````!BL````````
M````````````````````````````````````````````````````````````
-M````````````````````````````````````````````$`@````````0$```
-M`````!`8````````$"`````````0*````````!`P````````$#@````````0
-M0````````!!(````````$%`````````06````````!!@````````$&@`````
-M```0<````````!!X````````$(`````````0B````````!"0````````$)@`
-M```````0H````````!"H````````$+`````````0N````````!#`````````
-M$,@````````0T````````!#8````````$.`````````0Z````````!#P````
-M````$/@`````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
@@ -252,144 +332,191 @@ M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
+M```````````````````````````````````````5````%4```!6````5P```
+M%@```!9````6@```%L```!<````70```%X```!?````8`````````!A`````
+M````&(`````````8P````````!D`````````&4`````````9@````````!G`
+M``````8<!B`&)`8M!FX&;@:#!HL&F0:?!KT&RP;3!M@&VP;L!N\&HP:G!J4&
+M"0;Q```'B`````X```````````````````````````````````````````*P
+M`J<"L0```I4"E0*=```"L@*H`K(`````!Y@````6````````````````````
+M`&```7``````````````````````````````````````````````````````
+M``````````````````````````````7N````````!Z\```!+``````````!@
+M``'P`!@``&```:``````````````````````````````````````````````
+M``````````"JJ@,``````````0````````````````````#S````````````
+M````"````````````````````````````````````````````&``````````
+M8`````````!@`````````&``````````8`````````!@`````````&``````
+M````8``````````("`0`#`@$````````````````````````````````````
+M``````````````````````````````````"!`````K````$```````(`````
+M``*!!>X8````````````````@@(````'^P````$`@@(````'_0````(`$2(S
+M(C-$5?[M\`T!`@(!```/20`````````/`````0``!T0````!```.S0````$`
+M``[=`````0``#O4````!```/0@````$```]%````#P````````<S$`!^$!``
+M_/`0`'2@$$Z^`06H_(```/G0``1V<!``=``0`KX!$`*($!`"@@(0`O_^`%B`
+M``!8@@``.L7[$``$`!``!!(0`$6,$`!$AQ`"O`(0`O_Y$`+%]!`"Q?,0`L7R
+M!C+_\0ELBB`/D,`0#ZA`$!`"O@`01``+`=3```!-AP@`+8<$`#6'!``9AP0`
+M(8<$`%&'!`!=AP001'YP`=C``!`!BQ$0`9,1$`&;$04$BE`%*!"`!3@2D`5$
+M%*`%0!:P!6P8P`5H&M`0`'X2$`+]]1!(``L,`,``!`#$``D,@A`)*$A`$`*^
+M`0D$=T`0`SX!"8R"$`FH2$`0`KX!"81W4!`#/@$01'3P`>3@`!`"O@$0`;W1
+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
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
-M````````````````````````````$0```!%````1@```$<```!(````20```
-M$H```!+````3````$T```!.````3P```%``````````40````````!2`````
-M````%,`````````5`````````!5`````````%8`````````5P``````$+P0S
-M!#<$102&!(8$FP0<!!P$'`0<!,`$'`3(!,L$'`0<!!P$J@0<!*<$W`2C````
M````````````````````````````````````````````````````````````
-M``!@``%P````````````````````````````````````````````````````
-M``````````7N````````!@,````^``````````!@``'P`!@``&```:``````
-M````````````````````````````_```````````"```````````````````
-M`````````````````````````&``````````8`````````!@`````````&``
-M````````8`````````!@`````````&``````````8``````````("`0`#`@$
M````````````````````````````````````````````````````````````
-M`````````````````0```````@````(8`;L%[A@```````````````"``@$`
-M``9"`````0"``@$```9$````!0`1(C,B,T15R`#!_!<`````````_NWP#0$`
-M`@$```NL``````````L````!```%7@````$```MB`````0``"Z(````!```+
-MI0````\````````%41``?A`0`/SP$`!TH!!.O@$%J/R```#YT``$=G`0`'0`
-M$`*^`1"$``L0`H@/$`+!_A`"Q?T0`H8#$`*"`A`"__H`6(``$(@`"Q`"P?<0
-MA$&'$`*V`A`"__00```+`"@`"P`2__$);(H@#Y#`$`^H0!`0`KX`$$0`"P'4
-MP```38<(`"V'!``UAP0`&8<$`"&'!`!1AP0`78<$$$1^<`'8P``0`8L1$`&3
-M$1`!FQ$%!(I0!2@0@`4X$I`%1!2@!4`6L`5L&,`%:!K0$`!^$A`"_?402``+
-M#`#```0`Q``)#((0"2A(0!`"O@$)!'=`$`,^`0F,@A`)J$A`$`*^`0F$=U`0
-M`SX!$$1T\`'DX``0`KX!$`&]T1`!N=$0`3?1$`$_T1``=!(0`OW[$``UD!`"
-MO@$01'Z`!X3\`!!&O@$!\.``$`&#T1`!B]$0`9K!$$63T@`(_"$0`'X2$`+Y
-M^A!(Z@`"`.````AQ@!`!Z\\03``+!:C\@```?@``$'8`$`-_H1`!RAT0`KX#
-M`##J`!`!Z@D018H'``!V8!``R@<0`S8&$$0`"P``=H`0`P`!$`!W0``JO@D0
-M1``+``!V@!`#``$)*&A`$PF^$!``=T`)!SX!"32*(`DH:,`)#(I0"0<^`1`!
-MF@D0`:(%"37F'`DUYA8)->X`$`#:!Q`"N`80`9H($$7*"0``=]``,=H*$)<^
-M%@DH:(`)#:88"27*!A`!D`@0`.0`"22C$`D$D1$0`=`($`#10!`!T`H0`8H=
-M$`,^E!!$``L``'?0$)<^`044A"`0`9H%$`&2(1`!BB`0``2P$(*^A044A"`0
-M`<H&$`&2(1`!BB`0@50`$`%6"1`!2`$0`$@`$`'0`Q`!DF`0`9IA$`'2"Q`!
-MDF(0`=H,$`&L9A!%T@T0(.P'$`*V9Q!$:@``P.P'$`!K'A`!*`D0`6H#$`!I
-M1A`"N$L0`)CP$$2<D`,@Q0`0`:@C$`&B(!`!$@(0`)57$`";'1`"ME\0`%$0
-M$`&D!A``Q(`0`\#@$`&J(1`!HB`0`)57$`";'1`"ME`0`,1/$`#$&A`!JB$0
-M`:(@$`"55Q``FQT0`K9)$`#$3Q``Q!H0`:HA$`&B(!``E5<0`)L=$`*V0A``
-MQ$\0`,0:$`&J(1`!HB`0`)57$`";'1`"MCL0`,1/$`#$&A`!JB$0`:(@$`"5
-M5Q``FQT0`K8T$`#$3Q``Q!H0`:HA$`&B(!``E5<0`)L=$`*V+1``Q$\0`,0:
-M$`&J(1`!HB`0`)57$`";'1`"MB80`,1/$`#$&A`!JB$0`:(@$`"55Q``FQT0
-M`K8?$`#$3Q``Q!H0`:HA$`&B(!``E5<0`)L=$`*V&!!$``L`'&GP$`%H`!`!
-M$@D0```+$`!3(Q`!4@@0`%.`$`%2`A`"OA80`%``$`%0!1``;B80`K@#$`%L
-M`!`"__00`1("$```"Q``4H00`5("$`+_[Q`!K&@0`O^9$``19Q`"^>@0`&X6
-M$`+WYA``;B00`6XG$`!2`!`!4@(0`9H%$`$$"1``V4$0`)S7$`+[01!%V`H`
-M`':`$`,``0DH:4`3":X`$)1Q$`DEAV0)!'=`"3WN``5//@$0@$46`#+W91``
-M:#`0`"@C$`!H-Q`"MDT0`$6&$`*X1Q!%*`,`&$3S$``%1!`!D`,0`40#$$11
-MXP,,Q$`0`%'J$``&@1``1`D`))(@$`&8(A`!D`@0`!;``""2D!````L0```+
-M$`%:!!`!R`D01JXM``#0!Q`"N`T0`<@("2AI(!,)IA@));X8"26F$`DEK@@)
-M):8`"26F!`DEK@P)):X0"26N%`D'/A40`(B2$`'("`DH:(`3":88"26^&`DE
-MIA`)!SX!$$6:"0``::`)*"E`"0S:80D<["`)):80"26N"`DEI@`)):8$"26N
-M#`DEKA`)):X4"0<^`1``Z@`0`>P($`%H`Q`!H@D)*&A`$`!F%!,)IB`))*,0
-M"01W0!`#?O$#&-'`$`&B@!`!*`(0`.(1$`'B@!`"O@40`2@"$```"Q``:880
-M`OFW$`#J`!`!B@D0`>H)$`'L"!`!:`,0`O[G$`!%1!`"OE40EJ+D!1",(!``
-M1``0`$&$$`&(81`!!@@&-<=$!C22(`8TFB`0`=-1$`&0'Q`!VU$0`%'Z$``0
-MIA`"N,,01:`"`L#0@!`#P,`0`:J!$`&B@!``FU<0`)4]$`*V(A``T$\01-`:
-M`L#0`A`!JH$0`:*`$`";5Q``E3T0`K8:$`#03Q!$T!H"P-`"$`&J@1`!HH`0
-M`)M7$`"5/1`"MA(0`-!/$$30&@+`T`(0`:J!$`&B@!``FU<0`)4]$`*V"A``
-MT$\01-`:`L#0`A`!JH$0`:*`$`";5Q``E3T0`K8"$`!B'!`!D!\0`9I=$``B
-MA1``8A80`KB7$`&J'A`!E%P0`&@6$`*X#1``6!80`K8)$`#B"!``E3<0`)L=
-M$`*V!Q``+K,0`"UW$`*XGQ`"O@,0`!=7$`*XG!!,``L`,-@'&$#<#0``U`T0
-M`O>M$`!2%A`"N(40`:`!$`#0@!`#P,`0`:*!$`&J@!``E1<0`)M=$`*V/!``
-MT$\0`-`:$`&B@1`!JH`0`)47$`";71`"MC40`-!/$`#0&A`!HH$0`:J`$`"5
-M%Q``FUT0`K8N$`#03Q``T!H0`:*!$`&J@!``E1<0`)M=$`*V)Q``T$\0`-`:
-M$`&B@1`!JH`0`)47$`";71`"MB`0`-!/$`#0&A`!HH$0`:J`$`"5%Q``FUT0
-M`K89$`#03Q``T!H0`:*!$`&J@!``E1<0`)M=$`*V$A``T$\0`-`:$`&B@1`!
-MJH`0`)47$`";71`"M@L0`-!/$`#0&A`!HH$0`:J`$`"5%Q``FUT0`K8$$`!D
-M"!`!9&80`KX$$`%D9A``91<0`K9%$`!PT`8UQT00`:I3$`!E$!!%9&`!`.@'
-M$$:X`P``1$00`KX-$-CIUQ`"N`L0`$2$$`*^"1"6HD`%$(P@$`!!C!`!B&$0
-M`'$0!C7'1!``1A(0`K8R$`*.`Q`!1&<%4W_V$`&H`P8,DB`&$(@@$`#1^A!$
-MB)4`_,GS!BZX#A``J)<0`KHH$$1%%`(8U<80`K@*$`!4,Q``!*00E41G!5%2
-M81``0880`WD]$`%08!`#?SL0`-44$`!!AA`"N`401``+``!%-!"4``L%441G
-M$`#5ZA``U$80FK8S!B*^,A``27`0`KX$$`!)@!``4?H0`$F>$`!$-!`"OA40
-M`$E`$`*^$Q``25`0`KX1$`!)8!`"O@\0`$D@$`*^#1``23`0`KX'$`!),!`"
-MOB,0`$D0$`!$-!`"O@80`$D0$$0`"P``1300E``+!5%$9Q!$``L`'$?P!C1&
-M$@8T<.`&-``+$`*^`1`"C@(0`WW[!@R2(!`"O`(&(KX*$`!@,!``(",&+&`W
-M$`*V!A!$``L"&-7&$`*X"1"4190%441G$`#5ZA"8%$0%$(P@$```"P51U&`0
-M`W[[$$0`"P``1300E``+!5%$9Q``U180`O?U!B+_]!!(``L`'$?P``!V,`8T
-M1A(&-'#@!C0`"Q`"O@$0`HX"$`-]^Q!$``L`!';0$`,^`1"4``L%$(P@$$@`
-M"P``=C```$4P!5%$9Q"(``L`,``+$`*\`@8@``L0`W[=!120(!````L02:"`
-M`Q30P`"$Y7`%3*43$$:V!P``Y5,02.47'_SE+P,4Y$$0`2#@$`*^!0`<80,0
-M`W?R$`!AZA``8($0`!,!$`!0"1`!JH`0```+$`#J$1`!ZH`0`W_I$`!VH`"W
-M!`$0`9+!$`&:P!`!Y,,0D*40!4!00!`!+*40@*"P`#ZX`@`0``L0@%_C$$7:
-M`0`$=L`0`R`!$$1VD`6H_!`0`P(!$XVF!`FH72`0D'=0"8<^`0FUY@`)M(H@
-M";2J(`FTDB`%$)`@";2:(!`!A($0`>H?$`#,!Q`"MA`0`,@'$`*V#A`!G!L)
-MC*M0$`"<=Q`"NGH0`)QP$`!=A!`!W(`0`(AW$`"(?A``C%(0`<P<$`#-P!`"
-MOAT0@``+`+:^8@F,JU`0`(Q1$`"L<!``;800`>R`$`#-P!`"OA03C:8`":A<
-MP`F$=U`0`SX!$`&8'`FUY@`)M(@@";7^'!``R`<`MO?W$`"(UQ``B-X0`)A2
-M$$78'``$=L`0`R`!$`!VD!`#`@$3C;X<$$6J'P`@R`<0`KH.$``M<!!$;R``
-M`&WS$`!L!Q`"M@D0`"]B$`!L`!``K%<)J"Y>$`'L'0F<A#`)A'=0$$<^%A``
-M[4`0`*Q7":@N7A`![!T)G(0P"81W4!`#/@\0`"9X$`!GZA``9A$0`#$P";7'
-MQ!``)3<0`KH2$$@E,@!@Q`(`8.`"$`*^#!`#?Y,0@``+`+:^(PF]_AP)N*0`
-M$`&L'1``H#`0`.`\$$2%<0*`Q`<0`OWK$``Q(`FUQ\0`M`]Q$`*Z"A"03T(0
-M`$P1$`*V!A``3$<0`K@%$`!P,`503``%0&`0!5!,$A"`B7(01OG`$`&8'!``
-M=I`0`)C3$`-YKA!,``L``'90`"3-\0`<3?D0D#!@!5``"Q`#*@001``+``!V
-M4!`#*@$0`':0$(,"`1.-I@@0`:H!":A<0`FDZA001``+`"C\$`F$=U`0`O_/
-M$`&J&1"```L`M.H1$`'J&1`"_^\0A``+`#P`"P8K.`$`4&`0`*AV(!"3/@$%
-M%)0@$(100`"U@*`0```+$`!!C!`!P*``4&`0`!6$H1"0D!<&&)`>$`!W$`5,
-M<1`&)8<D!5R:(!``P4(01';$`H#$!Q`"O`80`%@F$`+-YQ`#.`$0`'8@$)-_
-M]!!$4$`"(,0`$`"0%P88D!X0`O_W$$0`"P``=\`0D``+!5R:(!````L0`%@F
-M$`,X`044E"`0```+$`&`H!````L0`$&&$`*X`P5,``L0`O_U!5R:(!"$``L`
-M,%@F$`+_S`5,P4`01``+``1VT!"7/@$%$)0@$`!'$`511J<01<"@``!WP!"3
-M?_<01``+``!V@!`#``$3":90"2A80!``=T`)!SX!"32:(!``D#``,-H'$`*V
-M'@`YVH`0`80C$`!>&A``7N,015Z%`OC4`!``%O$0`*00$`*V"1``#/<0`KH'
-M$`&@H!````L0`:3#$`'0PQ`!Y(,0`KX$$``,\!`!P(,0`("0$`$:Y1``X``0
-M1*$W`!Q;[A``'M(0`%_Z$``P\!`!T;\0`,07$$0`"P``=D`0`WW6`!1VL!`#
-M?_L&"*H@$$0`"P+XX4`0`)%P$`-W_!``[!80`K8%$`&:R08P``L0`-H1$`':
-MR1!%FL(`'-&#$`#1AQ`"N`,0`-H1$`':PA!%FL8`(.P&$`*V`Q``VA$0`=K&
-M$`#L)A!&N`X`#.V&$`-WYQ`!FL`0`.UV$`*V!A`!FL$0```+$`#:$1`!VL$0
-M`W_?$`#:$1`!VL`0`W_<$`&:PP8P[$80`K8$$`#:$1`!VL,0`W_6$$6:Q``,
-M[880`K8$$`#:$1`!VL00`W_0$$6:Q0`@[`80`WG-$`#:$1`!VL40`W_*$$0`
-M"P``R7`0`SX!$`$44!`!%E@0`%0L$`!6+!`!5%`0`598$`$40!`!%D@0`%0L
-M$`!6+!`!5$`0159(`P#1L!`!D9`0`,DA$`"05Q`#??``,W_L``!W(!`#/@$/
-MA:8$$`,^`0^%I@@01``+``!W$!`#/@$/B>8$$`,^`1`!H@$/B*H@$$1@&@+L
-MT0`0`!,!$`!0"1`!D9`0`>H"$$?`@!`!D@00```+$`'2`A!&_^H0`>0,$`'H
-M#1`!Z@<01O_F$`'J!1``3``0`0X!$`#(`!``S$H0`,PJ$$;WWQ`"/J$02'XP
-M``1V0`,`U;`0`<FP`"L^`1!&_]@0`>H%$`"=,!!,R```0,V``!S1P`,$U8`0
-M`<P;$`'1L!`!7@$0`%X'$$;WS0!`S3`0`-@`$``:X!``C-(0`-@0$`':`Q!$
-M``L``':`$(``"Q`#/@$3":84"2AG0`D$=T`0`SX!$`&:`PD]YA00`'$0"37'
-M1!``7A(0`%@1$`':`P`P&-<0`K8($`!>!Q`"^>X02<P;`"#-P@,$U8`0`<VP
-M$`*^#!`!S!L02)!P`"#1P@,$U8`0`=&P$`#,<A``6AH0`=H#$`!>!Q`"^=\0
-M1O^D$``,T!``#,(0`$Q*$`!W4!``#F`0`$TG$`!/+A``DI40`#!P$`'341``
-M#'(0`WGY$$;_EP,4R,`01>H%``3-0!`"/E802``+``3,P`+XR4`0`CY2$`$@
-M!!``3M`0`&!7$$;YBP,4R,`0`-(`$``P<!`!TU$01$ZP`OC)0!``,'`0`=-1
-M$$;_@@,`R9`016=0`P#((!!%[5`#',D@$`'I41`!95`01O]Z$```"Q"$``L`
-M$``+$$;_=@,<R$`0`>M0$$;_<P!LU'`011X``&#1P!``6!`0`!\W$$;W;1`!
-M9@`02&87`!!0/@!PU9X&(%A.!@QTX`8RO@$01#:``##X0!``=/`0`KX!$``V
-MD!``N+`0`#[`$`!T@!!&_UT##,A`$`!D`!``Y#H0`(DQ$`'L01`!:D00`6A%
-M$$;_50,<R+`0`6=0$$;_4@,<R*`026=0`QS)```TV;`01=E0`"#,`!!%Z@4"
-MP,@`$$8^(!`!H@$0`-P`$$@?(``TV;`#',D`$`"8\A`!V5`01O]!`P#)H!`!
-M9D`01O\^$`'D`1!$``L``':`$(,^`0D-IA0`*.5`$`"D=PDH)GX0`(TR$`!F
-M,1``9^H0`#$P"26'1`D$=T`0`SX!"3WF%``PS!<0`:0!$`+][Q`#P.`0`>0!
-M$$0`"P``=H`0@SX!"0VF%``HY4`0`*1W"2@F?@D$C3(0`'=`"3WF%!`#/@$)
-M.*8`$`#,%Q``,3`)-<=$`#&D`1`"_?`0`\#@$$;_*1!&_RP01O\O$$;_/!!&
-M_WP01O^'$$;_CQ!&_P\01O\.$$;_#1!&_PP01O^O$$;_"A!&_[401O^W$$;_
-M!Q!&_P801O\%$$;_DA!&_P,01O^-$$;_P1!&_X<0`'3@$$:^`0`0=C`0`'3P
-M$$:^`0`0=\`0`#60$`*^`1"`=I`0`P(!$$0`"P,@T8`3C::`":A80`FDVA`)
-MA'=0$`,^`0"T``L01``+``!W(!`#/@$0A``+`#@`"Q!$``L#(-'`#X6'A!`#
-M/@$/A8>`$$0`"P`(=N`0`SX!$`!TX!!*O@$`4/D0``AW0!``=/`02KX!`'#X
-M8``(=L`0`#60$$:^`0+\T<`0`9J`$(@`"P`HVA$0A=J``#@`"Q!$``L`"';@
-M$`-_SQ````L0```+````````!@(`````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
@@ -469,23 +596,17 @@ M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
+M`````$0````````8GQN$```````````8GQN$_____P``````````````````
+M````'P'B`!$`````````/P';`#,`````````+P'8`"(`!```````````````
+M```````````````````````````````````````````````````````M0@5L
+M'`$M1`)*`P`!00-8"@`M0P!M!@`M0`60!``M2```@```#P``@``M108+$@``
+M````@``U@@6]?``UA@,^'@8`````@```````@```#P``@``UA@7T9`,`#P``
+M``$``!0`'F```!Z\%0`````````5```````?!````````!_0````````']P`
+M```````?C```````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
-M````````````````````````````````````````!````````!B?&X0`````
-M`````!B?&X3_____```````````````````````?`7H`$0`````````_`7,`
-M,P`````````O`7``(@`$````````````````````````````````````````
-M`````````````````````````````"U"`V<<`2U$`80#``%!`L(*`"U#`&T&
-M`"U``Z,$`"U(``"``"U'!1U.`2U%!!X2``````"``#6"`]!\`#6&`J@>!@``
-M``"```````"````/``"``#6&!`=D`P`/`````0``$``7P```&`P1````````
-M`!$``````!@L````````&.P````````8^````````!BL````````````````
M````````````````````````````````````````````````````````````
-M````````````````````````````````````$`@````````0$````````!`8
-M````````$"`````````0*````````!`P````````$#@````````00```````
-M`!!(````````$%`````````06````````!!@````````$&@````````0<```
-M`````!!X````````$(`````````0B````````!"0````````$)@````````0
-MH````````!"H````````$+`````````0N````````!#`````````$,@`````
-M```0T````````!#8````````$.`````````0Z````````!#P````````$/@`
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
@@ -505,6 +626,13 @@ M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
+M```````````````````````````````````````````````4"````````!00
+M````````%!@````````4(````````!0H````````%#`````````4.```````
+M`!1`````````%$@````````44````````!18````````%&`````````4:```
+M`````!1P````````%'@````````4@````````!2(````````%)`````````4
+MF````````!2@````````%*@````````4L````````!2X````````%,``````
+M```4R````````!30````````%-@````````4X````````!3H````````%/``
+M```````4^```````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
@@ -520,142 +648,239 @@ M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
-M````````````````````$0```!%````1@```$<```!(````20```$H```!+`
-M```3````$T```!.````3P```%``````````40````````!2`````````%,``
-M```````5`````````!5`````````%8`````````5P``````$+P0S!#<$102&
-M!(8$FP0<!!P$'`0<!,`$'`3(!,L$'`0<!!P$J@0<!*<$W`2C````````````
-M``````````````````````````````````````````````````````!@``&`
M````````````````````````````````````````````````````````````
-M``7N````````!@,````^``````````!@``'P`!@``&```;``````````````
-M````````````````````_```````````"```````````````````````````
-M`````````````````&``````````8`````````!@`````````&``````````
-M8`````````!@`````````&``````````8``````````("`0`#`@$````````
M````````````````````````````````````````````````````````````
-M`````!```0```````@````(8`;L%[A@```````````````$``@$```9"````
-M`0$``@$```9$````!0`1(C,B,T15R`"1_!<!````````_NWP#0(``@$```NL
-M``````````L````!```%7@````$```MB`````0``"Z(````!```+I0````\`
-M```````%41``?A`0`/SP$`!TH!!.O@$%J/R```#YT``$=G`0`'0`$`*^`1"$
-M``L0`H@/$`+!_A`"Q?T0`H8#$`*"`A`"__H`6(``$(@`"Q`"P?<0A$&'$`*V
-M`A`"__00```+`"@`"P`2__$);(H@#Y#`$`^H0!`0`KX`$$0`"P'4P```38<(
-M`"V'!``UAP0`&8<$`"&'!`!1AP0`78<$$$1^<`'8P``0`8L1$`&3$1`!FQ$%
-M!(I0!2@0@`4X$I`%1!2@!4`6L`5L&,`%:!K0$`!^$A`"_?402``+#`#```0`
-MQ``)#((0"2A(0!`"O@$)!'=`$`,^`0F,@A`)J$A`$`*^`0F$=U`0`SX!$$1T
-M\`'DX``0`KX!$`&]T1`!N=$0`3?1$`$_T1``=!(0`OW[$``UD!`"O@$01'Z`
-M!X3\`!!&O@$!\.``$`&#T1`!B]$0`9K!$$63T@`(_"$0`'X2$`+Y^A!(Z@`"
-M`.````AQ@!`!Z\\03``+!:C\@```?@``$'8`$`-_H1`!RAT0`KX#`##J`!`!
-MZ@D018H'``!V8!``R@<0`S8&$$0`"P``=H`0`P`!$`!W0``JO@D01``+``!V
-M@!`#``$)*&A`$PF^$!``=T`)!SX!"32*(`DH:,`)#(I0"0<^`1`!F@D0`:(%
-M"37F'`DUYA8)->X`$`#:!Q`"N`80`9H($$7*"0``=]``,=H*$)<^%@DH:(`)
-M#:88"27*!A`!D`@0`.0`"22C$`D$D1$0`=`($`#10!`!T`H0`8H=$`,^E!!$
-M``L``'?0$)<^`044A"`0`9H%$`&2(1`!BB`0``2P$(*^A044A"`0`<H&$`&2
-M(1`!BB`0@50`$`%6"1`!2`$0`$@`$`'0`Q`!DF`0`9IA$`'2"Q`!DF(0`=H,
-M$`&L9A!%T@T0(.P'$`*V9Q!$:@``P.P'$`!K'A`!*`D0`6H#$`!I1A`"N$L0
-M`)CP$$2<D`,@Q0`0`:@C$`&B(!`!$@(0`)57$`";'1`"ME\0`%$@$`&D!A``
-MQ(`0`\#@$`&J(1`!HB`0`)57$`";'1`"ME`0`,1/$`#$&A`!JB$0`:(@$`"5
-M5Q``FQT0`K9)$`#$3Q``Q!H0`:HA$`&B(!``E5<0`)L=$`*V0A``Q$\0`,0:
-M$`&J(1`!HB`0`)57$`";'1`"MCL0`,1/$`#$&A`!JB$0`:(@$`"55Q``FQT0
-M`K8T$`#$3Q``Q!H0`:HA$`&B(!``E5<0`)L=$`*V+1``Q$\0`,0:$`&J(1`!
-MHB`0`)57$`";'1`"MB80`,1/$`#$&A`!JB$0`:(@$`"55Q``FQT0`K8?$`#$
-M3Q``Q!H0`:HA$`&B(!``E5<0`)L=$`*V&!!$``L`'&GP$`%H`!`!$@D0```+
-M$`!3(Q`!4@@0`%.`$`%2`A`"OA80`%``$`%0!1``;B80`K@#$`%L`!`"__00
-M`1("$```"Q``4H00`5("$`+_[Q`!K&@0`O^9$``19Q`"^>@0`&X6$`+WYA``
-M;B00`6XG$`!2`!`!4@(0`9H%$`$$"1``V4$0`)S7$`+[01!%V`H``':`$`,`
-M`0DH:4`3":X`$)1Q$`DEAV0)!'=`"3WN``5//@$0@$46`#+W91``:#`0`"@C
-M$`!H-Q`"MDT0`$6&$`*X1Q!%*`,`&$3S$``%1!`!D`,0`40#$$11XP,,Q$`0
-M`%'J$``&@1``1`D`))(@$`&8(A`!D`@0`!;``""2D!````L0```+$`%:!!`!
-MR`D01JXM``#0!Q`"N`T0`<@("2AI(!,)IA@));X8"26F$`DEK@@)):8`"26F
-M!`DEK@P)):X0"26N%`D'/A40`(B2$`'("`DH:(`3":88"26^&`DEIA`)!SX!
-M$$6:"0``::`)*"E`"0S:80D<["`)):80"26N"`DEI@`)):8$"26N#`DEKA`)
-M):X4"0<^`1``Z@`0`>P($`%H`Q`!H@D)*&A`$`!F)!,)IB`))*,0"01W0!`#
-M?O$#&-'`$`&B@!`!*`(0`.(1$`'B@!`"O@40`2@"$```"Q``:880`OFW$`#J
-M`!`!B@D0`>H)$`'L"!`!:`,0`O[G$`!%1!`"OE40EJ+D!1",(!``1``0`$&$
-M$`&(81`!!@@&-<=$!C22(`8TFB`0`=-1$`&0'Q`!VU$0`%'Z$``0IA`"N,,0
-M1:`"`L#0@!`#P,`0`:J!$`&B@!``FU<0`)4]$`*V(A``T$\01-`:`L#0`A`!
-MJH$0`:*`$`";5Q``E3T0`K8:$`#03Q!$T!H"P-`"$`&J@1`!HH`0`)M7$`"5
-M/1`"MA(0`-!/$$30&@+`T`(0`:J!$`&B@!``FU<0`)4]$`*V"A``T$\01-`:
-M`L#0`A`!JH$0`:*`$`";5Q``E3T0`K8"$`!B'!`!D!\0`9I=$``BA1``8A80
-M`KB7$`&J'A`!E%P0`&@6$`*X#1``6!80`K8)$`#B"!``E3<0`)L=$`*V!Q``
-M+K,0`"UW$`*XGQ`"O@,0`!=7$`*XG!!,``L`,-@'&$#<#0``U`T0`O>M$`!2
-M%A`"N(40`:`!$`#0@!`#P,`0`:*!$`&J@!``E1<0`)M=$`*V/!``T$\0`-`:
-M$`&B@1`!JH`0`)47$`";71`"MC40`-!/$`#0&A`!HH$0`:J`$`"5%Q``FUT0
-M`K8N$`#03Q``T!H0`:*!$`&J@!``E1<0`)M=$`*V)Q``T$\0`-`:$`&B@1`!
-MJH`0`)47$`";71`"MB`0`-!/$`#0&A`!HH$0`:J`$`"5%Q``FUT0`K89$`#0
-M3Q``T!H0`:*!$`&J@!``E1<0`)M=$`*V$A``T$\0`-`:$`&B@1`!JH`0`)47
-M$`";71`"M@L0`-!/$`#0&A`!HH$0`:J`$`"5%Q``FUT0`K8$$`!D"!`!9&80
-M`KX$$`%D9A``92<0`K9%$`!PT`8UQT00`:I3$`!E(!!%9&`!`.@'$$:X`P``
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````%0```!5````5@```
+M%<```!8````60```%H```!;````7````%T```!>````7P```&``````````8
+M0````````!B`````````&,`````````9`````````!E`````````&8``````
+M```9P``````&'`8@!B0&+09N!FX&@P:+!ID&GP:]!LL&TP;8!ML&[`;O!J,&
+MIP:E!@D&\0``!X@````.````````````````````````````````````````
+M```"L`*G`K$```*5`I4"G0```K("J`*R``````>8````%@``````````````
+M``````!@``&`````````````````````````````````````````````````
+M```````````````````````````````````%[@````````>O````2P``````
+M````8``!\``8``!@``&P````````````````````````````````````````
+M````````````````JJH#``````````$`````````````````````\P``````
+M``````````@```````````````````````````````````````````!@````
+M`````&``````````8`````````!@`````````&``````````8`````````!@
+M`````````&``````````"`@$``P(!```````````````````````````````
+M````````````````````````````````````````@0````*P$``!```````"
+M```````"@07N&````````````````0("`0``!_L````!`0("`0``!_T````"
+M`!$B,R(S1%7^[?`-`@4"`0``#KX`````````%P````$```>>`````0``#",`
+M```!```,+P````$```XH`````0``#D0````!```.@P````$```Z&`````0``
+M#HH````!```.F@````$```ZU````#P````````>%$`!^$!``_/`0`'2@$$Z^
+M`06H_(```/G0``1V<!``=``0`KX!$`*($!`"@@(0`O_^`%B```!8@@``.L7[
+M$``$`!``!!(0`$6,$`!$AQ`"O`(0`O_Y$`+%]!`"Q?,0`L7R!C+_\0ELBB`/
+MD,`0#ZA`$!`"O@`01``+`=3```!-AP@`+8<$`#6'!``9AP0`(8<$`%&'!`!=
+MAP001'YP`=C``!`!BQ$0`9,1$`&;$04$BE`%*!"`!3@2D`5$%*`%0!:P!6P8
+MP`5H&M`0`'X2$`+]]1!(``L,`,``!`#$``D,@A`)*$A`$`*^`0D$=T`0`SX!
+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
-M1!``1A(0`K8R$`*.`Q`!1&<%4W_V$`&H`P8,DB`&$(@@$`#1^A!$B)4`_,GS
+M1!``1A(0`K8R$`*.`Q`!1&<%4W_V$`&H`@8,DB`&$(@@$`#1^A!$B)4`_,GS
M!BZX#A``J)<0`KHH$$1%%`(8U<80`K@*$`!4,Q``!*00E41G!5%281``0880
-M`WD]$`%08!`#?SL0`-44$`!!AA`"N`401``+``!%-!"4``L%441G$`#5ZA``
+M`WF[$`%08!`#?[D0`-44$`!!AA`"N`401``+``!%-!"4``L%441G$`#5ZA``
MU$80FK8S!B*^,A``27`0`KX$$`!)@!``4?H0`$F>$`!$-!`"OA40`$E`$`*^
M$Q``25`0`KX1$`!)8!`"O@\0`$D@$`*^#1``23`0`KX'$`!),!`"OB,0`$D0
M$`!$-!`"O@80`$D0$$0`"P``1300E``+!5%$9Q!$``L`'$?P!C1&$@8T<.`&
M-``+$`*^`1`"C@(0`WW[!@R2(!`"O`(&(KX*$`!@,!``(",&+&`W$`*V!A!$
-M``L"&-7&$`*X"1"4190%441G$`#5ZA"8%$0%$(P@$```"P51U&`0`W[[$$0`
-M"P``1300E``+!5%$9Q``U180`O?U!B+_]!!(``L`'$?P``!V,`8T1A(&-'#@
-M!C0`"Q`"O@$0`HX"$`-]^Q!$``L`!';0$`,^`1"4``L%$(P@$$@`"P``=C``
-M`$4P!5%$9Q"(``L`,``+$`*\`@8@``L0`W[=!120(!````L02:"``Q30P`"$
-MY7`%3*43$$:V!P``Y5,02.47'_SE+P,4Y$$0`2#@$`*^!0`<80,0`W?R$`!A
-MZA``8($0`!,!$`!0"1`!JH`0```+$`#J$1`!ZH`0`W_I$`!VH`"W!`$0`9+!
-M$`&:P!`!Y,,0D*40!4!00!`!+*40@*"P`#ZX`@`0``L0@%_C$$7:`0`$=L`0
-M`R`!$$1VD`6H_!`0`P(!$XVF!`FH72`0D'=0"8<^`0FUY@`)M(H@";2J(`FT
-MDB`%$)`@";2:(!`!A($0`>H?$`#,!Q`"MA`0`,@'$`*V#A`!G!L)C*M0$`"<
-M=Q`"NGH0`)QP$`!=A!`!W(`0`(AW$`"(?A``C%(0`<P<$`#-P!`"OAT0@``+
-M`+:^8@F,JU`0`(Q1$`"L<!``;800`>R`$`#-P!`"OA03C:8`":A<P`F$=U`0
-M`SX!$`&8'`FUY@`)M(@@";7^'!``R`<`MO?W$`"(UQ``B-X0`)A2$$78'``$
-M=L`0`R`!$`!VD!`#`@$3C;X<$$6J'P`@R`<0`KH.$``M<!!$;R```&WS$`!L
-M!Q`"M@D0`"]B$`!L`!``K%<)J"Y>$`'L'0F<A#`)A'=0$$<^%A``[4`0`*Q7
-M":@N7A`![!T)G(0P"81W4!`#/@\0`"9X$`!GZA``9A$0`#$P";7'Q!``)3<0
-M`KH2$$@E,@!@Q`(`8.`"$`*^#!`#?Y,0@``+`+:^(PF]_AP)N*0`$`&L'1``
-MH#`0`.`\$$2%<0*`Q`<0`OWK$``Q(`FUQ\0`M`]Q$`*Z"A"03T(0`$P1$`*V
-M!A``3$<0`K@%$`!P,`503``%0&`0!5!,$A"`B7(01OG`$`&8'!``=I`0`)C3
-M$`-YKA!,``L``'90`"3-\0`<3?D0D#!@!5``"Q`#*@001``+``!V4!`#*@$0
-M`':0$(,"`1.-I@@0`:H!":A<0`FDZB001``+`"C\$`F$=U`0`O_/$`&J&1"`
-M``L`M.H1$`'J&1`"_^\0A``+`#P`"P8K.`$`4&`0`*AV(!"3/@$%%)0@$(10
-M0`"U@*`0```+$`!!C!`!P*``4&`0`!6$H1"0D!<&&)`>$`!W$`5,<1`&)8<D
-M!5R:(!``P4(01';$`H#$!Q`"O`80`%@F$`+-YQ`#.`$0`'8@$)-_]!!$4$`"
-M(,0`$`"0%P88D!X0`O_W$$0`"P``=\`0D``+!5R:(!````L0`%@F$`,X`044
-ME"`0```+$`&`H!````L0`$&&$`*X`P5,``L0`O_U!5R:(!"$``L`,%@F$`+_
-MS`5,P4`01``+``1VT!"7/@$%$)0@$`!'$`511J<01<"@``!WP!"3?_<01``+
-M``!V@!`#``$3":90"2A80!``=T`)!SX!"32:(!``D#``,-H'$`*V'@`YVH`0
-M`80C$`!>&A``7N,015Z%`OC4`!``%O$0`*00$`*V"1``#/<0`KH'$`&@H!``
-M``L0`:3#$`'0PQ`!Y(,0`KX$$``,\!`!P(,0`("0$`$:Y1``X``01*$W`!Q;
-M[A``'M(0`%_Z$``P\!`!T;\0`,07$$0`"P``=D`0`WW6`!1VL!`#?_L&"*H@
-M$$0`"P+XX4`0`)%P$`-W_!``[!80`K8%$`&:R08P``L0`-H1$`':R1!%FL(`
-M'-&#$`#1AQ`"N`,0`-H1$`':PA!%FL8`(.P&$`*V`Q``VA$0`=K&$`#L)A!&
-MN`X`#.V&$`-WYQ`!FL`0`.UV$`*V!A`!FL$0```+$`#:$1`!VL$0`W_?$`#:
-M$1`!VL`0`W_<$`&:PP8P[$80`K8$$`#:$1`!VL,0`W_6$$6:Q``,[880`K8$
-M$`#:$1`!VL00`W_0$$6:Q0`@[`80`WG-$`#:$1`!VL40`W_*$$0`"P``R7`0
-M`SX!$`$44!`!%E@0`%0L$`!6+!`!5%`0`598$`$40!`!%D@0`%0L$`!6+!`!
-M5$`0159(`P#1L!`!D9`0`,DA$`"05Q`#??``,W_L``!W(!`#/@$/A:8$$`,^
-M`0^%I@@01``+``!W$!`#/@$/B>8$$`,^`1`!H@$/B*H@$$1@&@+LT0`0`!,!
-M$`!0"1`!D9`0`>H"$$?`@!`!D@00```+$`'2`A!&_^H0`>0,$`'H#1`!Z@<0
-M1O_F$`'J!1``3``0`0X!$`#(`!``S$H0`,PJ$$;WWQ`"/J$02'XP``1V0`,`
-MU;`0`<FP`"L^`1!&_]@0`>H%$`"=,!!,R```0,V``!S1P`,$U8`0`<P;$`'1
-ML!`!7@$0`%X'$$;WS0!`S3`0`-@`$``:X!``C-(0`-@0$`':`Q!$``L``':`
-M$(``"Q`#/@$3":84"2AG0`D$=T`0`SX!$`&:`PD]YA00`'$0"37'1!``7A(0
-M`%@1$`':`P`P&-<0`K8($`!>!Q`"^>X02<P;`"#-P@,$U8`0`<VP$`*^#!`!
-MS!L02)!P`"#1P@,$U8`0`=&P$`#,<A``6AH0`=H#$`!>!Q`"^=\01O^D$``,
-MT!``#,(0`$Q*$`!W4!``#F`0`$TG$`!/+A``DI40`#!P$`'341``#'(0`WGY
-M$$;_EP,4R,`01>H%``3-0!`"/E802``+``3,P`+XR4`0`CY2$`$@!!``3M`0
-M`&!7$$;YBP,4R,`0`-(`$``P<!`!TU$01$ZP`OC)0!``,'`0`=-1$$;_@@,`
-MR9`016=0`P#((!!%[5`#',D@$`'I41`!95`01O]Z$```"Q"$``L`$``+$$;_
-M=@,<R$`0`>M0$$;_<P!LU'`011X``&#1P!``6!`0`!\W$$;W;1`!9@`02&87
-M`!!0/@!PU9X&(%A.!@QTX`8RO@$01#:``##X0!``=/`0`KX!$``VD!``N+`0
-M`#[`$`!T@!!&_UT##,A`$`!D`!``Y#H0`(DQ$`'L01`!:D00`6A%$$;_50,<
-MR+`0`6=0$$;_4@,<R*`026=0`QS)```TV;`01=E0`"#,`!!%Z@4"P,@`$$8^
-M(!`!H@$0`-P`$$@?(``TV;`#',D`$`"8\A`!V5`01O]!`P#)H!`!9D`01O\^
-M$`'D`1!$``L``':`$(,^`0D-IA0`*.5`$`"D=PDH)GX0`(TR$`!F,1``9^H0
-M`#$P"26'1`D$=T`0`SX!"3WF%``PS!<0`:0!$`+][Q`#P.`0`>0!$$0`"P``
-M=H`0@SX!"0VF%``HY4`0`*1W"2@F?@D$C3(0`'=`"3WF%!`#/@$).*8`$`#,
-M%Q``,3`)-<=$`#&D`1`"_?`0`\#@$$;_*1!&_RP01O\O$$;_/!!&_WP01O^'
-M$$;_CQ!&_P\01O\.$$;_#1!&_PP01O^O$$;_"A!&_[401O^W$$;_!Q!&_P80
-M1O\%$$;_DA!&_P,01O^-$$;_P1!&_X<0`'3@$$:^`0`0=C`0`'3P$$:^`0`0
-M=\`0`#60$`*^`1"`=I`0`P(!$$0`"P,@T8`3C::`":A80`FDVA`)A'=0$`,^
-M`0"T``L01``+``!W(!`#/@$0A``+`#@`"Q!$``L#(-'`#X6'A!`#/@$/A8>`
-M$$0`"P`(=N`0`SX!$`!TX!!*O@$`4/D0``AW0!``=/`02KX!`'#X8``(=L`0
-M`#60$$:^`0+\T<`0`9J`$(@`"P`HVA$0A=J``#@`"Q!$``L`"';@$`-_SQ``
-M``L0```+````````!@(`````````````````````````````````````````
+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
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
@@ -727,6 +952,14 @@ M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
+M``````````Q$````````&9\<A!W>````````&9\<A/____\````!````````
+M`````````!\!I@`1`````````#\!GP`S`````````"\!G``B``0``````/\!
+M+``S`````````#\!*``S``$`!P``````````````````````````````````
+M+4(&31P!+40%&P,``4$%Q`H`+4,$8@8`+4`&<00`+4@``(````\``(``+44&
+M[!(``````(``-8(&GGP`-88%JAX&,<<#OC(",2X#S!<"``\``(``-88&U60#
+M``\````!```3P!J````:S!3`````````%,``````&NP````````;K```````
+M`!NT````````&VP``````````````````!Q`$H``````````````````````
+M`````````````````````````````````````!R,$H`2@!*`````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
@@ -738,24 +971,21 @@ M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
-M````````````````````````````````!````````!F?'(0``````````!F?
-M'(3_____```````````````````````?`7H`$0`````````_`7,`,P``````
-M```O`7``(@`$````````````````````````````````````````````````
-M`````````````````````"U"`V<<`2U$`80#``%!`L(*`"U#`&T&`"U``Z,$
-M`"U(``"``"U'!1U.`2U%!!X2``````"``#6"`]!\`#6&`J@>!@````"`````
-M``"````/``"``#6&!`=D`P`/`````0``$``7P```&`P1`````````!$`````
-M`!@L````````&.P````````8^````````!BL````````````````````````
+M````````````````````````````````````````!(0````*`.4`Y@``````
+M]0#V`0H!"P%/`5`!90%F`8L!C`&O`;$!YP'G`A8"%@``!*````'W`````!``
+M````````$$`````````0@````````!#`````````$0`````````10```````
+M`!&`````````$<``````````````````````````````````````````````
M````````````````````````````````````````````````````````````
-M````````````````````````````$`@````````0$````````!`8````````
-M$"`````````0*````````!`P````````$#@````````00````````!!(````
-M````$%`````````06````````!!@````````$&@````````0<````````!!X
-M````````$(`````````0B````````!"0````````$)@````````0H```````
-M`!"H````````$+`````````0N````````!#`````````$,@````````0T```
-M`````!#8````````$.`````````0Z````````!#P````````$/@`````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
+M```````3R````````!/0````````$]@````````3X````````!/H````````
+M$_`````````3^````````!0`````````%`@````````4$````````!08````
+M````%"`````````4*````````!0P````````%#@````````40````````!1(
+M````````%%`````````46````````!1@````````%&@````````4<```````
+M`!1X````````%(`````````4B````````!20````````%)@````````4H```
+M`````!2H````````%+`````````4N```````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
@@ -784,20 +1014,23 @@ M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
+M`````````!3````5````%4```!6````5P```%@```!9````6@```%L```!<`
+M```70```%X```!?`````````&``````````80````````!B`````````&,``
+M```````9`````````!E`````````&8``````!OT'`0;J!NH'!0<%!QH&Z@;J
+M!NH&Z@<[!NH&Z@;J!NH&Z@;J!R4&Z@<B!T,```:8````&@``````````````
+M`````````````````````````````````````````````````&```9``````
+M````````````````````````````````````````````````````````!>X`
+M```````&LP```#T``````````&```?``&```8``!P```````````````````
+M``````````````2E```````````(````````````````````````````````
+M````````````8`````````!@`````````&``````````8`````````!@````
+M`````&``````````8`````````!@``````````@(!``,"`0`````````````
M````````````````````````````````````````````````````````````
+M(``!```````"```````%[A@````````````"!0(!```&\0````$"!0(!```&
+M\P````(`$2(S(C-$50``!P`````.________________________________
+M________________________________``````````````</````&1*``#$`
M````````````````````````````````````````````````````````````
-M````````````$0```!%````1@```$<```!(````20```$H```!+````3````
-M$T```!.````3P```%``````````40````````!2`````````%,`````````5
-M`````````!5`````````%8`````````5P``````$+P0S!#<$102&!(8$FP0<
-M!!P$'`0<!,`$'`3(!,L$'`0<!!P$J@0<!*<$W`2C````````````````````
-M``````````````````````````````````````````````!@``&0````````
-M``````````````````````````````````````````````````````7N````
-M````!@,````^``````````!@``'P`!@``&```<``````````````````````
-M````````````_```````````"```````````````````````````````````
-M`````````&``````````8`````````!@`````````&``````````8```````
-M``!@`````````&``````````8``````````("`0`#`@$````````````````
-M`````````````````````````````````````````````````````````"``
-M`0```````@````(8`;L%[A@```````````````(``@$```9"`````0(``@$`
-C``9$````!0`1(C,B,T15R`"A_!<"````````_NWP#?[M\`T`
+M````````````````````````````````````````WJV^[]ZMON_>K;[OWJV^
+M[]ZMON\```<I````!P````````````````````!@``'@`````&```=#^[?`-
+$_NWP#0``
`
end
diff --git a/sys/dev/usb/ehci.c b/sys/dev/usb/ehci.c
index e9b2cb8..529ba1b 100644
--- a/sys/dev/usb/ehci.c
+++ b/sys/dev/usb/ehci.c
@@ -99,7 +99,6 @@ int ehcidebug = 0;
SYSCTL_NODE(_hw_usb, OID_AUTO, ehci, CTLFLAG_RW, 0, "USB ehci");
SYSCTL_INT(_hw_usb_ehci, OID_AUTO, debug, CTLFLAG_RW,
&ehcidebug, 0, "ehci debug level");
-#define bitmask_snprintf(q,f,b,l) snprintf((b), (l), "%b", (q), (f))
#else
#define DPRINTF(x)
#define DPRINTFN(n,x)
@@ -221,34 +220,20 @@ static usbd_status ehci_device_request(usbd_xfer_handle xfer);
static usbd_status ehci_device_setintr(ehci_softc_t *, ehci_soft_qh_t *,
int ival);
-static void ehci_add_qh(ehci_soft_qh_t *, ehci_soft_qh_t *);
+static void ehci_add_qh(ehci_softc_t *, ehci_soft_qh_t *,
+ ehci_soft_qh_t *);
static void ehci_rem_qh(ehci_softc_t *, ehci_soft_qh_t *,
ehci_soft_qh_t *);
-static void ehci_activate_qh(ehci_soft_qh_t *, ehci_soft_qtd_t *);
+static void ehci_activate_qh(ehci_softc_t *sc, ehci_soft_qh_t *,
+ ehci_soft_qtd_t *);
static void ehci_sync_hc(ehci_softc_t *);
static void ehci_close_pipe(usbd_pipe_handle, ehci_soft_qh_t *);
static void ehci_abort_xfer(usbd_xfer_handle, usbd_status);
-#ifdef EHCI_DEBUG
-static void ehci_dump_regs(ehci_softc_t *);
-void ehci_dump(void);
-static ehci_softc_t *theehci;
-static void ehci_dump_link(ehci_link_t, int);
-static void ehci_dump_sqtds(ehci_soft_qtd_t *);
-static void ehci_dump_sqtd(ehci_soft_qtd_t *);
-static void ehci_dump_qtd(ehci_qtd_t *);
-static void ehci_dump_sqh(ehci_soft_qh_t *);
-#ifdef notyet
-static void ehci_dump_sitd(struct ehci_soft_itd *);
-static void ehci_dump_itd(struct ehci_soft_itd *);
-#endif
-#ifdef DIAGNOSTIC
-static void ehci_dump_exfer(struct ehci_xfer *);
-#endif
-#endif
+ehci_softc_t *theehci;
-#define EHCI_NULL htole32(EHCI_LINK_TERMINATE)
+#define EHCI_NULL(sc) htohc32(sc, EHCI_LINK_TERMINATE)
#define EHCI_INTR_ENDPT 1
@@ -344,17 +329,26 @@ ehci_hcreset(ehci_softc_t *sc)
* Table 2-9 in the EHCI spec says this will result
* in undefined behavior.
*/
- printf("%s: stop timeout\n",
- device_get_nameunit(sc->sc_bus.bdev));
+ device_printf(sc->sc_bus.bdev, "stop timeout\n");
EOWRITE4(sc, EHCI_USBCMD, EHCI_CMD_HCRESET);
for (i = 0; i < 100; i++) {
usb_delay_ms(&sc->sc_bus, 1);
hcr = EOREAD4(sc, EHCI_USBCMD) & EHCI_CMD_HCRESET;
if (!hcr) {
- if (sc->sc_flags & EHCI_SCFLG_SETMODE)
- EOWRITE4(sc, 0x68, 0x3);
-
+ if (sc->sc_flags & EHCI_SCFLG_SETMODE) {
+ /*
+ * Force USBMODE as requested. Controllers
+ * may have multiple operating modes.
+ */
+ uint32_t usbmode = EOREAD4(sc, EHCI_USBMODE);
+ if (sc->sc_flags & EHCI_SCFLG_SETMODE) {
+ usbmode = (usbmode &~ EHCI_UM_CM) | EHCI_UM_CM_HOST;
+ device_printf(sc->sc_bus.bdev,
+ "set host controller mode\n");
+ }
+ EOWRITE4(sc, EHCI_USBMODE, usbmode);
+ }
return (USBD_NORMAL_COMPLETION);
}
}
@@ -377,10 +371,12 @@ ehci_init(ehci_softc_t *sc)
theehci = sc;
#endif
+ /* NB: must handle byte-order manually before ehci_hcreset */
+
sc->sc_offs = EREAD1(sc, EHCI_CAPLENGTH);
version = EREAD2(sc, EHCI_HCIVERSION);
- printf("%s: EHCI version %x.%x\n", device_get_nameunit(sc->sc_bus.bdev),
+ device_printf(sc->sc_bus.bdev, "EHCI version %x.%x\n",
version >> 8, version & 0xff);
sparams = EREAD4(sc, EHCI_HCSPARAMS);
@@ -435,7 +431,7 @@ ehci_init(ehci_softc_t *sc)
sc->sc_flist = KERNADDR(&sc->sc_fldma, 0);
for (i = 0; i < sc->sc_flsize; i++) {
- sc->sc_flist[i] = EHCI_NULL;
+ sc->sc_flist[i] = EHCI_NULL(sc);
}
EOWRITE4(sc, EHCI_PERIODICLISTBASE, DMAADDR(&sc->sc_fldma, 0));
@@ -450,11 +446,6 @@ ehci_init(ehci_softc_t *sc)
sc->sc_bus.methods = &ehci_bus_methods;
sc->sc_bus.pipe_size = sizeof(struct ehci_pipe);
-#if defined(__NetBSD__) || defined(__OpenBSD__)
- sc->sc_powerhook = powerhook_establish(ehci_power, sc);
- sc->sc_shutdownhook = shutdownhook_establish(ehci_shutdown, sc);
-#endif
-
sc->sc_eintrs = EHCI_NORMAL_INTRS;
/*
@@ -476,27 +467,26 @@ ehci_init(ehci_softc_t *sc)
sqh = sc->sc_islots[i].sqh;
if (i == 0) {
/* The last (1ms) QH terminates. */
- sqh->qh.qh_link = EHCI_NULL;
+ sqh->qh.qh_link = EHCI_NULL(sc);
sqh->next = NULL;
} else {
/* Otherwise the next QH has half the poll interval */
sqh->next =
sc->sc_islots[EHCI_IQHIDX(lev - 1, i + 1)].sqh;
- sqh->qh.qh_link = htole32(sqh->next->physaddr |
+ sqh->qh.qh_link = htohc32(sc, sqh->next->physaddr |
EHCI_LINK_QH);
}
- sqh->qh.qh_endp = htole32(EHCI_QH_SET_EPS(EHCI_QH_SPEED_HIGH));
- sqh->qh.qh_endphub = htole32(EHCI_QH_SET_MULT(1));
- sqh->qh.qh_curqtd = EHCI_NULL;
- sqh->qh.qh_qtd.qtd_next = EHCI_NULL;
- sqh->qh.qh_qtd.qtd_altnext = EHCI_NULL;
- sqh->qh.qh_qtd.qtd_status = htole32(EHCI_QTD_HALTED);
+ sqh->qh.qh_endp = htohc32(sc, EHCI_QH_SET_EPS(EHCI_QH_SPEED_HIGH));
+ sqh->qh.qh_endphub = htohc32(sc, EHCI_QH_SET_MULT(1));
+ sqh->qh.qh_curqtd = EHCI_NULL(sc);
+ sqh->qh.qh_qtd.qtd_next = EHCI_NULL(sc);
+ sqh->qh.qh_qtd.qtd_altnext = EHCI_NULL(sc);
+ sqh->qh.qh_qtd.qtd_status = htohc32(sc, EHCI_QTD_HALTED);
}
/* Point the frame list at the last level (128ms). */
for (i = 0; i < sc->sc_flsize; i++) {
- sc->sc_flist[i] = htole32(EHCI_LINK_QH |
- sc->sc_islots[EHCI_IQHIDX(EHCI_IPOLLRATES - 1,
- i)].sqh->physaddr);
+ sc->sc_flist[i] = htohc32(sc, EHCI_LINK_QH |
+ sc->sc_islots[EHCI_IQHIDX(EHCI_IPOLLRATES - 1, i)].sqh->physaddr);
}
/* Allocate dummy QH that starts the async list. */
@@ -507,19 +497,19 @@ ehci_init(ehci_softc_t *sc)
}
/* Fill the QH */
sqh->qh.qh_endp =
- htole32(EHCI_QH_SET_EPS(EHCI_QH_SPEED_HIGH) | EHCI_QH_HRECL);
+ htohc32(sc, EHCI_QH_SET_EPS(EHCI_QH_SPEED_HIGH) | EHCI_QH_HRECL);
sqh->qh.qh_link =
- htole32(sqh->physaddr | EHCI_LINK_QH);
- sqh->qh.qh_curqtd = EHCI_NULL;
+ htohc32(sc, sqh->physaddr | EHCI_LINK_QH);
+ sqh->qh.qh_curqtd = EHCI_NULL(sc);
sqh->prev = sqh; /*It's a circular list.. */
sqh->next = sqh;
/* Fill the overlay qTD */
- sqh->qh.qh_qtd.qtd_next = EHCI_NULL;
- sqh->qh.qh_qtd.qtd_altnext = EHCI_NULL;
- sqh->qh.qh_qtd.qtd_status = htole32(0);
+ sqh->qh.qh_qtd.qtd_next = EHCI_NULL(sc);
+ sqh->qh.qh_qtd.qtd_altnext = EHCI_NULL(sc);
+ sqh->qh.qh_qtd.qtd_status = htohc32(sc, 0);
#ifdef EHCI_DEBUG
if (ehcidebug) {
- ehci_dump_sqh(sqh);
+ ehci_dump_sqh(sc, sqh);
}
#endif
@@ -777,10 +767,10 @@ ehci_check_qh_intr(ehci_softc_t *sc, struct ehci_xfer *ex)
* is a an error somewhere in the middle, or whether there was a
* short packet (SPD and not ACTIVE).
*/
- if (le32toh(lsqtd->qtd.qtd_status) & EHCI_QTD_ACTIVE) {
+ if (hc32toh(sc, lsqtd->qtd.qtd_status) & EHCI_QTD_ACTIVE) {
DPRINTFN(12, ("ehci_check_intr: active ex=%p\n", ex));
for (sqtd = ex->sqtdstart; sqtd != lsqtd; sqtd=sqtd->nextqtd) {
- status = le32toh(sqtd->qtd.qtd_status);
+ status = hc32toh(sc, sqtd->qtd.qtd_status);
/* If there's an active QTD the xfer isn't done. */
if (status & EHCI_QTD_ACTIVE)
break;
@@ -825,7 +815,7 @@ ehci_check_itd_intr(ehci_softc_t *sc, struct ehci_xfer *ex)
* Step 1, check no active transfers in last itd, meaning we're finished
*/
for (i = 0; i < 8; i++) {
- if (le32toh(itd->itd.itd_ctl[i]) & EHCI_ITD_ACTIVE)
+ if (hc32toh(sc, itd->itd.itd_ctl[i]) & EHCI_ITD_ACTIVE)
break;
}
@@ -841,7 +831,7 @@ ehci_check_itd_intr(ehci_softc_t *sc, struct ehci_xfer *ex)
for (itd = ex->itdstart; itd != ex->itdend; itd = itd->xfer_next) {
for (i = 0; i < 8; i++) {
- if (le32toh(itd->itd.itd_ctl[i]) & (EHCI_ITD_BUF_ERR |
+ if (hc32toh(sc, itd->itd.itd_ctl[i]) & (EHCI_ITD_BUF_ERR |
EHCI_ITD_BABBLE | EHCI_ITD_ERROR))
break;
}
@@ -865,6 +855,7 @@ ehci_idone(struct ehci_xfer *ex)
{
usbd_xfer_handle xfer = &ex->xfer;
struct ehci_pipe *epipe = (struct ehci_pipe *)xfer->pipe;
+ ehci_softc_t *sc = (ehci_softc_t *)epipe->pipe.device->bus;
ehci_soft_qtd_t *sqtd, *lsqtd;
u_int32_t status = 0, nstatus = 0;
ehci_physaddr_t nextphys, altnextphys;
@@ -878,7 +869,7 @@ ehci_idone(struct ehci_xfer *ex)
splx(s);
#ifdef EHCI_DEBUG
printf("ehci_idone: ex is done!\n ");
- ehci_dump_exfer(ex);
+ ehci_dump_exfer(sc, ex);
#else
printf("ehci_idone: ex=%p is done!\n", ex);
#endif
@@ -898,7 +889,7 @@ ehci_idone(struct ehci_xfer *ex)
#ifdef EHCI_DEBUG
DPRINTFN(/*10*/2, ("ehci_idone: xfer=%p, pipe=%p ready\n", xfer, epipe));
if (ehcidebug > 10)
- ehci_dump_sqtds(ex->sqtdstart);
+ ehci_dump_sqtds(sc, ex->sqtdstart);
#endif
/*
@@ -906,14 +897,14 @@ ehci_idone(struct ehci_xfer *ex)
* of the qTDs we are about to free. This is probably only
* necessary if the transfer is marked as HALTED.
*/
- nextphys = EHCI_LINK_ADDR(le32toh(epipe->sqh->qh.qh_qtd.qtd_next));
+ nextphys = EHCI_LINK_ADDR(hc32toh(sc, epipe->sqh->qh.qh_qtd.qtd_next));
altnextphys =
- EHCI_LINK_ADDR(le32toh(epipe->sqh->qh.qh_qtd.qtd_altnext));
+ EHCI_LINK_ADDR(hc32toh(sc, epipe->sqh->qh.qh_qtd.qtd_altnext));
for (sqtd = ex->sqtdstart; sqtd != ex->sqtdend->nextqtd;
sqtd = sqtd->nextqtd) {
if (sqtd->physaddr == nextphys) {
epipe->sqh->qh.qh_qtd.qtd_next =
- htole32(ex->sqtdend->nextqtd->physaddr);
+ htohc32(sc, ex->sqtdend->nextqtd->physaddr);
DPRINTFN(4, ("ehci_idone: updated overlay next ptr\n"));
}
@@ -921,7 +912,7 @@ ehci_idone(struct ehci_xfer *ex)
DPRINTFN(4,
("ehci_idone: updated overlay altnext ptr\n"));
epipe->sqh->qh.qh_qtd.qtd_altnext =
- htole32(ex->sqtdend->nextqtd->physaddr);
+ htohc32(sc, ex->sqtdend->nextqtd->physaddr);
}
}
@@ -964,7 +955,7 @@ ehci_idone(struct ehci_xfer *ex)
if (nframes >= xfer->nframes)
break;
- status = le32toh(itd->itd.itd_ctl[i]);
+ status = hc32toh(sc, itd->itd.itd_ctl[i]);
len = EHCI_ITD_GET_LEN(status);
xfer->frlengths[nframes++] = len;
actlen += len;
@@ -984,7 +975,7 @@ ehci_idone(struct ehci_xfer *ex)
actlen = 0;
for (sqtd = ex->sqtdstart; sqtd != lsqtd->nextqtd;
sqtd =sqtd->nextqtd) {
- nstatus = le32toh(sqtd->qtd.qtd_status);
+ nstatus = hc32toh(sc, sqtd->qtd.qtd_status);
if (nstatus & EHCI_QTD_ACTIVE)
break;
@@ -1001,24 +992,11 @@ ehci_idone(struct ehci_xfer *ex)
"status=0x%x\n", xfer->length, actlen, cerr, status));
xfer->actlen = actlen;
if ((status & EHCI_QTD_HALTED) != 0) {
-#ifdef EHCI_DEBUG
- char sbuf[128];
-
- bitmask_snprintf((u_int32_t)status,
- "\20\7HALTED\6BUFERR\5BABBLE\4XACTERR"
- "\3MISSED\2SPLIT\1PING", sbuf, sizeof(sbuf));
-
DPRINTFN(2,
- ("ehci_idone: error, addr=%d, endpt=0x%02x, "
- "status 0x%s\n",
+ ("ehci_idone: error, addr=%d, endpt=0x%02x, status %b\n",
xfer->pipe->device->address,
xfer->pipe->endpoint->edesc->bEndpointAddress,
- sbuf));
- if (ehcidebug > 2) {
- ehci_dump_sqh(epipe->sqh);
- ehci_dump_sqtds(ex->sqtdstart);
- }
-#endif
+ status, EHCI_QTD_STATUS_BITS));
if ((status & EHCI_QTD_BABBLE) == 0 && cerr > 0)
xfer->status = USBD_STALLED;
else
@@ -1026,6 +1004,12 @@ ehci_idone(struct ehci_xfer *ex)
} else {
xfer->status = USBD_NORMAL_COMPLETION;
}
+#ifdef EHCI_DEBUG
+ if (ehcidebug > 2) {
+ ehci_dump_sqh(sc, epipe->sqh);
+ ehci_dump_sqtds(sc, ex->sqtdstart);
+ }
+#endif
end:
/* XXX transfer_complete memcpys out transfer data (for in endpoints)
* during this call, before methods->done is called: dma sync required
@@ -1102,12 +1086,6 @@ ehci_detach(struct ehci_softc *sc, int flags)
(void) ehci_hcreset(sc);
callout_stop(&sc->sc_tmo_intrlist);
-#if defined(__NetBSD__) || defined(__OpenBSD__)
- if (sc->sc_powerhook != NULL)
- powerhook_disestablish(sc->sc_powerhook);
- if (sc->sc_shutdownhook != NULL)
- shutdownhook_disestablish(sc->sc_shutdownhook);
-#endif
usb_delay_ms(&sc->sc_bus, 300); /* XXX let stray task complete */
usb_freemem(&sc->sc_bus, &sc->sc_fldma);
@@ -1337,6 +1315,7 @@ static void
ehci_device_clear_toggle(usbd_pipe_handle pipe)
{
struct ehci_pipe *epipe = (struct ehci_pipe *)pipe;
+ ehci_softc_t *sc = (ehci_softc_t *)epipe->pipe.device->bus;
DPRINTF(("ehci_device_clear_toggle: epipe=%p status=0x%x\n",
epipe, epipe->sqh->qh.qh_qtd.qtd_status));
@@ -1345,9 +1324,9 @@ ehci_device_clear_toggle(usbd_pipe_handle pipe)
usbd_dump_pipe(pipe);
#endif
KASSERT((epipe->sqh->qh.qh_qtd.qtd_status &
- htole32(EHCI_QTD_ACTIVE)) == 0,
+ htohc32(sc, EHCI_QTD_ACTIVE)) == 0,
("ehci_device_clear_toggle: queue active"));
- epipe->sqh->qh.qh_qtd.qtd_status &= htole32(~EHCI_QTD_TOGGLE_MASK);
+ epipe->sqh->qh.qh_qtd.qtd_status &= htohc32(sc, ~EHCI_QTD_TOGGLE_MASK);
}
static void
@@ -1355,178 +1334,6 @@ ehci_noop(usbd_pipe_handle pipe)
{
}
-#ifdef EHCI_DEBUG
-void
-ehci_dump_regs(ehci_softc_t *sc)
-{
- int i;
- printf("cmd=0x%08x, sts=0x%08x, ien=0x%08x\n",
- EOREAD4(sc, EHCI_USBCMD),
- EOREAD4(sc, EHCI_USBSTS),
- EOREAD4(sc, EHCI_USBINTR));
- printf("frindex=0x%08x ctrdsegm=0x%08x periodic=0x%08x async=0x%08x\n",
- EOREAD4(sc, EHCI_FRINDEX),
- EOREAD4(sc, EHCI_CTRLDSSEGMENT),
- EOREAD4(sc, EHCI_PERIODICLISTBASE),
- EOREAD4(sc, EHCI_ASYNCLISTADDR));
- for (i = 1; i <= sc->sc_noport; i++)
- printf("port %d status=0x%08x\n", i,
- EOREAD4(sc, EHCI_PORTSC(i)));
-}
-
-/*
- * Unused function - this is meant to be called from a kernel
- * debugger.
- */
-void
-ehci_dump()
-{
- ehci_dump_regs(theehci);
-}
-
-void
-ehci_dump_link(ehci_link_t link, int type)
-{
- link = le32toh(link);
- printf("0x%08x", link);
- if (link & EHCI_LINK_TERMINATE)
- printf("<T>");
- else {
- printf("<");
- if (type) {
- switch (EHCI_LINK_TYPE(link)) {
- case EHCI_LINK_ITD: printf("ITD"); break;
- case EHCI_LINK_QH: printf("QH"); break;
- case EHCI_LINK_SITD: printf("SITD"); break;
- case EHCI_LINK_FSTN: printf("FSTN"); break;
- }
- }
- printf(">");
- }
-}
-
-void
-ehci_dump_sqtds(ehci_soft_qtd_t *sqtd)
-{
- int i;
- u_int32_t stop;
-
- stop = 0;
- for (i = 0; sqtd && i < 20 && !stop; sqtd = sqtd->nextqtd, i++) {
- ehci_dump_sqtd(sqtd);
- stop = sqtd->qtd.qtd_next & htole32(EHCI_LINK_TERMINATE);
- }
- if (sqtd)
- printf("dump aborted, too many TDs\n");
-}
-
-void
-ehci_dump_sqtd(ehci_soft_qtd_t *sqtd)
-{
- printf("QTD(%p) at 0x%08x:\n", sqtd, sqtd->physaddr);
- ehci_dump_qtd(&sqtd->qtd);
-}
-
-void
-ehci_dump_qtd(ehci_qtd_t *qtd)
-{
- u_int32_t s;
- char sbuf[128];
-
- printf(" next="); ehci_dump_link(qtd->qtd_next, 0);
- printf(" altnext="); ehci_dump_link(qtd->qtd_altnext, 0);
- printf("\n");
- s = le32toh(qtd->qtd_status);
- bitmask_snprintf(EHCI_QTD_GET_STATUS(s),
- "\20\10ACTIVE\7HALTED\6BUFERR\5BABBLE\4XACTERR"
- "\3MISSED\2SPLIT\1PING", sbuf, sizeof(sbuf));
- printf(" status=0x%08x: toggle=%d bytes=0x%x ioc=%d c_page=0x%x\n",
- s, EHCI_QTD_GET_TOGGLE(s), EHCI_QTD_GET_BYTES(s),
- EHCI_QTD_GET_IOC(s), EHCI_QTD_GET_C_PAGE(s));
- printf(" cerr=%d pid=%d stat=0x%s\n", EHCI_QTD_GET_CERR(s),
- EHCI_QTD_GET_PID(s), sbuf);
- for (s = 0; s < 5; s++)
- printf(" buffer[%d]=0x%08x\n", s, le32toh(qtd->qtd_buffer[s]));
-}
-
-void
-ehci_dump_sqh(ehci_soft_qh_t *sqh)
-{
- ehci_qh_t *qh = &sqh->qh;
- u_int32_t endp, endphub;
-
- printf("QH(%p) at 0x%08x:\n", sqh, sqh->physaddr);
- printf(" sqtd=%p inactivesqtd=%p\n", sqh->sqtd, sqh->inactivesqtd);
- printf(" link="); ehci_dump_link(qh->qh_link, 1); printf("\n");
- endp = le32toh(qh->qh_endp);
- printf(" endp=0x%08x\n", endp);
- printf(" addr=0x%02x inact=%d endpt=%d eps=%d dtc=%d hrecl=%d\n",
- EHCI_QH_GET_ADDR(endp), EHCI_QH_GET_INACT(endp),
- EHCI_QH_GET_ENDPT(endp), EHCI_QH_GET_EPS(endp),
- EHCI_QH_GET_DTC(endp), EHCI_QH_GET_HRECL(endp));
- printf(" mpl=0x%x ctl=%d nrl=%d\n",
- EHCI_QH_GET_MPL(endp), EHCI_QH_GET_CTL(endp),
- EHCI_QH_GET_NRL(endp));
- endphub = le32toh(qh->qh_endphub);
- printf(" endphub=0x%08x\n", endphub);
- printf(" smask=0x%02x cmask=0x%02x huba=0x%02x port=%d mult=%d\n",
- EHCI_QH_GET_SMASK(endphub), EHCI_QH_GET_CMASK(endphub),
- EHCI_QH_GET_HUBA(endphub), EHCI_QH_GET_PORT(endphub),
- EHCI_QH_GET_MULT(endphub));
- printf(" curqtd="); ehci_dump_link(qh->qh_curqtd, 0); printf("\n");
- printf("Overlay qTD:\n");
- ehci_dump_qtd(&qh->qh_qtd);
-}
-
-#ifdef notyet
-void
-ehci_dump_itd(struct ehci_soft_itd *itd)
-{
- ehci_isoc_trans_t t;
- ehci_isoc_bufr_ptr_t b, b2, b3;
- int i;
-
- printf("ITD: next phys=%X\n", itd->itd.itd_next);
-
- for (i = 0; i < 8;i++) {
- t = le32toh(itd->itd.itd_ctl[i]);
- printf("ITDctl %d: stat=%X len=%X ioc=%X pg=%X offs=%X\n", i,
- EHCI_ITD_GET_STATUS(t), EHCI_ITD_GET_LEN(t),
- EHCI_ITD_GET_IOC(t), EHCI_ITD_GET_PG(t),
- EHCI_ITD_GET_OFFS(t));
- }
- printf("ITDbufr: ");
- for (i = 0; i < 7; i++)
- printf("%X,", EHCI_ITD_GET_BPTR(le32toh(itd->itd.itd_bufr[i])));
-
- b = le32toh(itd->itd.itd_bufr[0]);
- b2 = le32toh(itd->itd.itd_bufr[1]);
- b3 = le32toh(itd->itd.itd_bufr[2]);
- printf("\nep=%X daddr=%X dir=%d maxpkt=%X multi=%X\n",
- EHCI_ITD_GET_EP(b), EHCI_ITD_GET_DADDR(b), EHCI_ITD_GET_DIR(b2),
- EHCI_ITD_GET_MAXPKT(b2), EHCI_ITD_GET_MULTI(b3));
-}
-
-void
-ehci_dump_sitd(struct ehci_soft_itd *itd)
-{
- printf("SITD %p next=%p prev=%p xfernext=%p physaddr=%X slot=%d\n",
- itd, itd->u.frame_list.next, itd->u.frame_list.prev,
- itd->xfer_next, itd->physaddr, itd->slot);
-}
-#endif
-
-#ifdef DIAGNOSTIC
-void
-ehci_dump_exfer(struct ehci_xfer *ex)
-{
- printf("ehci_dump_exfer: ex=%p sqtdstart=%p end=%p itdstart=%p "
- "end=%p isdone=%d\n", ex, ex->sqtdstart, ex->sqtdend, ex->itdstart,
- ex->itdend, ex->isdone);
-}
-#endif
-#endif
-
usbd_status
ehci_open(usbd_pipe_handle pipe)
{
@@ -1542,8 +1349,8 @@ ehci_open(usbd_pipe_handle pipe)
int ival, speed, naks;
int hshubaddr, hshubport;
- DPRINTFN(1, ("ehci_open: pipe=%p, addr=%d, endpt=%d (%d)\n",
- pipe, addr, ed->bEndpointAddress, sc->sc_addr));
+ DPRINTFN(1, ("ehci_open: pipe=%p, xfertype=%d, addr=%d, endpt=%d (%d)\n",
+ pipe, addr, ed->bEndpointAddress, sc->sc_addr, xfertype));
if (dev->myhsport) {
hshubaddr = dev->myhsport->parent->address;
@@ -1595,7 +1402,7 @@ ehci_open(usbd_pipe_handle pipe)
if (sqh == NULL)
goto bad0;
/* qh_link filled when the QH is added */
- sqh->qh.qh_endp = htole32(
+ sqh->qh.qh_endp = htohc32(sc,
EHCI_QH_SET_ADDR(addr) |
EHCI_QH_SET_ENDPT(UE_GET_ADDR(ed->bEndpointAddress)) |
EHCI_QH_SET_EPS(speed) |
@@ -1605,17 +1412,17 @@ ehci_open(usbd_pipe_handle pipe)
EHCI_QH_CTL : 0) |
EHCI_QH_SET_NRL(naks)
);
- sqh->qh.qh_endphub = htole32(
+ sqh->qh.qh_endphub = htohc32(sc,
EHCI_QH_SET_MULT(1) |
EHCI_QH_SET_HUBA(hshubaddr) |
EHCI_QH_SET_PORT(hshubport) |
EHCI_QH_SET_CMASK(0x1c) |
EHCI_QH_SET_SMASK(xfertype == UE_INTERRUPT ? 0x01 : 0)
);
- sqh->qh.qh_curqtd = EHCI_NULL;
+ sqh->qh.qh_curqtd = EHCI_NULL(sc);
/* The overlay qTD was already set up by ehci_alloc_sqh(). */
sqh->qh.qh_qtd.qtd_status =
- htole32(EHCI_QTD_SET_TOGGLE(pipe->endpoint->savedtoggle));
+ htohc32(sc, EHCI_QTD_SET_TOGGLE(pipe->endpoint->savedtoggle));
epipe->sqh = sqh;
} else {
sqh = NULL;
@@ -1633,13 +1440,13 @@ ehci_open(usbd_pipe_handle pipe)
goto bad1;
pipe->methods = &ehci_device_ctrl_methods;
s = splusb();
- ehci_add_qh(sqh, sc->sc_async_head);
+ ehci_add_qh(sc, sqh, sc->sc_async_head);
splx(s);
break;
case UE_BULK:
pipe->methods = &ehci_device_bulk_methods;
s = splusb();
- ehci_add_qh(sqh, sc->sc_async_head);
+ ehci_add_qh(sc, sqh, sc->sc_async_head);
splx(s);
break;
case UE_INTERRUPT:
@@ -1683,7 +1490,7 @@ ehci_open(usbd_pipe_handle pipe)
* If in the intr schedule it may not.
*/
void
-ehci_add_qh(ehci_soft_qh_t *sqh, ehci_soft_qh_t *head)
+ehci_add_qh(ehci_softc_t *sc, ehci_soft_qh_t *sqh, ehci_soft_qh_t *head)
{
SPLUSBCHECK;
@@ -1693,12 +1500,12 @@ ehci_add_qh(ehci_soft_qh_t *sqh, ehci_soft_qh_t *head)
head->next = sqh;
if (sqh->next)
sqh->next->prev = sqh;
- head->qh.qh_link = htole32(sqh->physaddr | EHCI_LINK_QH);
+ head->qh.qh_link = htohc32(sc, sqh->physaddr | EHCI_LINK_QH);
#ifdef EHCI_DEBUG
if (ehcidebug > 5) {
printf("ehci_add_qh:\n");
- ehci_dump_sqh(sqh);
+ ehci_dump_sqh(sc, sqh);
}
#endif
}
@@ -1721,9 +1528,9 @@ ehci_rem_qh(ehci_softc_t *sc, ehci_soft_qh_t *sqh, ehci_soft_qh_t *head)
/* Restart a QH following the addition of a qTD. */
void
-ehci_activate_qh(ehci_soft_qh_t *sqh, ehci_soft_qtd_t *sqtd)
+ehci_activate_qh(ehci_softc_t *sc, ehci_soft_qh_t *sqh, ehci_soft_qtd_t *sqtd)
{
- KASSERT((sqtd->qtd.qtd_status & htole32(EHCI_QTD_ACTIVE)) == 0,
+ KASSERT((sqtd->qtd.qtd_status & htohc32(sc, EHCI_QTD_ACTIVE)) == 0,
("ehci_activate_qh: already active"));
/*
@@ -1734,23 +1541,23 @@ ehci_activate_qh(ehci_soft_qh_t *sqh, ehci_soft_qtd_t *sqtd)
*/
if (sqtd == sqh->sqtd) {
/* Check that the hardware is in the state we expect. */
- if (EHCI_LINK_ADDR(le32toh(sqh->qh.qh_qtd.qtd_next)) !=
+ if (EHCI_LINK_ADDR(hc32toh(sc, sqh->qh.qh_qtd.qtd_next)) !=
sqtd->physaddr) {
#ifdef EHCI_DEBUG
printf("ehci_activate_qh: unexpected next ptr\n");
- ehci_dump_sqh(sqh);
- ehci_dump_sqtds(sqh->sqtd);
+ ehci_dump_sqh(sc, sqh);
+ ehci_dump_sqtds(sc, sqh->sqtd);
#endif
- sqh->qh.qh_qtd.qtd_next = htole32(sqtd->physaddr);
- sqh->qh.qh_qtd.qtd_altnext = EHCI_NULL;
+ sqh->qh.qh_qtd.qtd_next = htohc32(sc, sqtd->physaddr);
+ sqh->qh.qh_qtd.qtd_altnext = EHCI_NULL(sc);
}
/* Ensure the flags are correct. */
- sqh->qh.qh_qtd.qtd_status &= htole32(EHCI_QTD_PINGSTATE |
+ sqh->qh.qh_qtd.qtd_status &= htohc32(sc, EHCI_QTD_PINGSTATE |
EHCI_QTD_TOGGLE_MASK);
}
/* Now activate the qTD. */
- sqtd->qtd.qtd_status |= htole32(EHCI_QTD_ACTIVE);
+ sqtd->qtd.qtd_status |= htohc32(sc, EHCI_QTD_ACTIVE);
}
/*
@@ -2471,16 +2278,16 @@ ehci_alloc_sqh(ehci_softc_t *sc)
sqtd = ehci_alloc_sqtd(sc);
if (sqtd == NULL)
return (NULL);
- sqtd->qtd.qtd_status = htole32(0);
- sqtd->qtd.qtd_next = EHCI_NULL;
- sqtd->qtd.qtd_altnext = EHCI_NULL;
+ sqtd->qtd.qtd_status = htohc32(sc, 0);
+ sqtd->qtd.qtd_next = EHCI_NULL(sc);
+ sqtd->qtd.qtd_altnext = EHCI_NULL(sc);
sqh = sc->sc_freeqhs;
sc->sc_freeqhs = sqh->next;
/* The overlay QTD should begin zeroed. */
- sqh->qh.qh_qtd.qtd_next = htole32(sqtd->physaddr);
- sqh->qh.qh_qtd.qtd_altnext = EHCI_NULL;
+ sqh->qh.qh_qtd.qtd_next = htohc32(sc, sqtd->physaddr);
+ sqh->qh.qh_qtd.qtd_altnext = EHCI_NULL(sc);
sqh->qh.qh_qtd.qtd_status = 0;
for (i = 0; i < EHCI_QTD_NBUFFERS; i++) {
sqh->qh.qh_qtd.qtd_buffer[i] = 0;
@@ -2534,8 +2341,8 @@ ehci_alloc_sqtd(ehci_softc_t *sc)
s = splusb();
sqtd = sc->sc_freeqtds;
sc->sc_freeqtds = sqtd->nextqtd;
- sqtd->qtd.qtd_next = EHCI_NULL;
- sqtd->qtd.qtd_altnext = EHCI_NULL;
+ sqtd->qtd.qtd_next = EHCI_NULL(sc);
+ sqtd->qtd.qtd_altnext = EHCI_NULL(sc);
sqtd->qtd.qtd_status = 0;
for (i = 0; i < EHCI_QTD_NBUFFERS; i++) {
sqtd->qtd.qtd_buffer[i] = 0;
@@ -2632,7 +2439,7 @@ ehci_alloc_sqtd_chain(struct ehci_pipe *epipe, ehci_softc_t *sc,
segoff = 0;
}
- cur->qtd.qtd_buffer[i] = htole32(dataphys);
+ cur->qtd.qtd_buffer[i] = htohc32(sc, dataphys);
cur->qtd.qtd_buffer_hi[i] = 0;
curlen += pagelen;
@@ -2667,18 +2474,18 @@ ehci_alloc_sqtd_chain(struct ehci_pipe *epipe, ehci_softc_t *sc,
next = ehci_alloc_sqtd(sc);
if (next == NULL)
goto nomem;
- nextphys = htole32(next->physaddr);
+ nextphys = htohc32(sc, next->physaddr);
} else {
next = NULL;
- nextphys = EHCI_NULL;
+ nextphys = EHCI_NULL(sc);
}
cur->nextqtd = next;
cur->qtd.qtd_next = nextphys;
/* Make sure to stop after a short transfer. */
- cur->qtd.qtd_altnext = htole32(newinactive->physaddr);
+ cur->qtd.qtd_altnext = htohc32(sc, newinactive->physaddr);
cur->qtd.qtd_status =
- htole32(qtdstatus | EHCI_QTD_SET_BYTES(curlen));
+ htohc32(sc, qtdstatus | EHCI_QTD_SET_BYTES(curlen));
cur->xfer = xfer;
cur->len = curlen;
DPRINTFN(10,("ehci_alloc_sqtd_chain: curlen=%d\n", curlen));
@@ -2700,7 +2507,7 @@ ehci_alloc_sqtd_chain(struct ehci_pipe *epipe, ehci_softc_t *sc,
offset += curlen;
cur = next;
}
- cur->qtd.qtd_status |= htole32(EHCI_QTD_IOC);
+ cur->qtd.qtd_status |= htohc32(sc, EHCI_QTD_IOC);
*ep = cur;
DPRINTFN(10,("ehci_alloc_sqtd_chain: return sqtd=%p sqtdend=%p\n",
@@ -2829,7 +2636,7 @@ ehci_close_pipe(usbd_pipe_handle pipe, ehci_soft_qh_t *head)
ehci_rem_qh(sc, sqh, head);
splx(s);
pipe->endpoint->savedtoggle =
- EHCI_QTD_GET_TOGGLE(le32toh(sqh->qh.qh_qtd.qtd_status));
+ EHCI_QTD_GET_TOGGLE(hc32toh(sc, sqh->qh.qh_qtd.qtd_status));
ehci_free_sqh(sc, epipe->sqh);
}
@@ -2938,7 +2745,7 @@ ehci_abort_xfer(usbd_xfer_handle xfer, usbd_status status)
* the aborting xfer. (If there is something past us).
* Hardware and software.
*/
- cur = EHCI_LINK_ADDR(le32toh(sqh->qh.qh_curqtd));
+ cur = EHCI_LINK_ADDR(hc32toh(sc, sqh->qh.qh_curqtd));
hit = 0;
/* If they initially point here. */
@@ -2946,7 +2753,7 @@ ehci_abort_xfer(usbd_xfer_handle xfer, usbd_status status)
/* We will change them to point here */
snext = exfer->sqtdend->nextqtd;
- next = htole32(snext->physaddr);
+ next = htohc32(sc, snext->physaddr);
/*
* Now loop through any qTDs before us and keep track of the pointer
@@ -2955,9 +2762,9 @@ ehci_abort_xfer(usbd_xfer_handle xfer, usbd_status status)
sqtd = sqh->sqtd;
while (sqtd && sqtd != exfer->sqtdstart) {
hit |= (cur == sqtd->physaddr);
- if (EHCI_LINK_ADDR(le32toh(sqtd->qtd.qtd_next)) == us)
+ if (EHCI_LINK_ADDR(hc32toh(sc, sqtd->qtd.qtd_next)) == us)
sqtd->qtd.qtd_next = next;
- if (EHCI_LINK_ADDR(le32toh(sqtd->qtd.qtd_altnext)) == us)
+ if (EHCI_LINK_ADDR(hc32toh(sc, sqtd->qtd.qtd_altnext)) == us)
sqtd->qtd.qtd_altnext = next;
sqtd = sqtd->nextqtd;
}
@@ -2986,17 +2793,17 @@ ehci_abort_xfer(usbd_xfer_handle xfer, usbd_status status)
* that we are removing.
*/
if (hit) {
- sqh->qh.qh_qtd.qtd_next = htole32(snext->physaddr);
- sqh->qh.qh_qtd.qtd_altnext = EHCI_NULL;
+ sqh->qh.qh_qtd.qtd_next = htohc32(sc, snext->physaddr);
+ sqh->qh.qh_qtd.qtd_altnext = EHCI_NULL(sc);
sqh->qh.qh_qtd.qtd_status &=
- htole32(EHCI_QTD_TOGGLE_MASK);
+ htohc32(sc, EHCI_QTD_TOGGLE_MASK);
for (i = 0; i < EHCI_QTD_NBUFFERS; i++) {
sqh->qh.qh_qtd.qtd_buffer[i] = 0;
sqh->qh.qh_qtd.qtd_buffer_hi[i] = 0;
}
}
}
- ehci_add_qh(sqh, psqh);
+ ehci_add_qh(sc, sqh, psqh);
/*
* Step 5: Execute callback.
*/
@@ -3090,9 +2897,9 @@ ehci_abort_isoc_xfer(usbd_xfer_handle xfer, usbd_status status)
for (itd = exfer->itdstart; itd != NULL; itd = itd->xfer_next) {
for (i = 0; i < 8; i++) {
- trans_status = le32toh(itd->itd.itd_ctl[i]);
+ trans_status = hc32toh(sc, itd->itd.itd_ctl[i]);
trans_status &= ~EHCI_ITD_ACTIVE;
- itd->itd.itd_ctl[i] = htole32(trans_status);
+ itd->itd.itd_ctl[i] = htohc32(sc, trans_status);
}
}
@@ -3269,9 +3076,10 @@ ehci_device_request(usbd_xfer_handle xfer)
err = USBD_NOMEM;
goto bad1;
}
- newinactive->qtd.qtd_status = htole32(0);
- newinactive->qtd.qtd_next = EHCI_NULL;
- newinactive->qtd.qtd_altnext = EHCI_NULL;
+ newinactive->qtd.qtd_status = htohc32(sc, 0);
+ newinactive->qtd.qtd_next = EHCI_NULL(sc);
+ newinactive->qtd.qtd_altnext = EHCI_NULL(sc);
+
stat = ehci_alloc_sqtd(sc);
if (stat == NULL) {
err = USBD_NOMEM;
@@ -3291,10 +3099,10 @@ ehci_device_request(usbd_xfer_handle xfer)
NULL, newinactive, &next, &end);
if (err)
goto bad3;
- end->qtd.qtd_status &= htole32(~EHCI_QTD_IOC);
+ end->qtd.qtd_status &= htohc32(sc, ~EHCI_QTD_IOC);
end->nextqtd = stat;
- end->qtd.qtd_next = htole32(stat->physaddr);
- end->qtd.qtd_altnext = htole32(newinactive->physaddr);
+ end->qtd.qtd_next = htohc32(sc, stat->physaddr);
+ end->qtd.qtd_altnext = htohc32(sc, newinactive->physaddr);
} else {
next = stat;
}
@@ -3302,21 +3110,21 @@ ehci_device_request(usbd_xfer_handle xfer)
memcpy(KERNADDR(&epipe->u.ctl.reqdma, 0), req, sizeof *req);
/* Clear toggle, and do not activate until complete */
- setup->qtd.qtd_status = htole32(
+ setup->qtd.qtd_status = htohc32(sc,
EHCI_QTD_SET_PID(EHCI_QTD_PID_SETUP) |
EHCI_QTD_SET_CERR(3) |
EHCI_QTD_SET_TOGGLE(0) |
EHCI_QTD_SET_BYTES(sizeof *req)
);
- setup->qtd.qtd_buffer[0] = htole32(DMAADDR(&epipe->u.ctl.reqdma, 0));
+ setup->qtd.qtd_buffer[0] = htohc32(sc, DMAADDR(&epipe->u.ctl.reqdma, 0));
setup->qtd.qtd_buffer_hi[0] = 0;
setup->nextqtd = next;
- setup->qtd.qtd_next = htole32(next->physaddr);
- setup->qtd.qtd_altnext = htole32(newinactive->physaddr);
+ setup->qtd.qtd_next = htohc32(sc, next->physaddr);
+ setup->qtd.qtd_altnext = htohc32(sc, newinactive->physaddr);
setup->xfer = xfer;
setup->len = sizeof *req;
- stat->qtd.qtd_status = htole32(
+ stat->qtd.qtd_status = htohc32(sc,
EHCI_QTD_ACTIVE |
EHCI_QTD_SET_PID(isread ? EHCI_QTD_PID_OUT : EHCI_QTD_PID_IN) |
EHCI_QTD_SET_CERR(3) |
@@ -3326,16 +3134,16 @@ ehci_device_request(usbd_xfer_handle xfer)
stat->qtd.qtd_buffer[0] = 0; /* XXX not needed? */
stat->qtd.qtd_buffer_hi[0] = 0; /* XXX not needed? */
stat->nextqtd = newinactive;
- stat->qtd.qtd_next = htole32(newinactive->physaddr);
- stat->qtd.qtd_altnext = htole32(newinactive->physaddr);
+ stat->qtd.qtd_next = htohc32(sc, newinactive->physaddr);
+ stat->qtd.qtd_altnext = htohc32(sc, newinactive->physaddr);
stat->xfer = xfer;
stat->len = 0;
#ifdef EHCI_DEBUG
if (ehcidebug > 5) {
DPRINTF(("ehci_device_request:\n"));
- ehci_dump_sqh(sqh);
- ehci_dump_sqtds(setup);
+ ehci_dump_sqh(sc, sqh);
+ ehci_dump_sqtds(sc, setup);
}
#endif
@@ -3350,7 +3158,7 @@ ehci_device_request(usbd_xfer_handle xfer)
/* Activate the new qTD in the QH list. */
s = splusb();
- ehci_activate_qh(sqh, setup);
+ ehci_activate_qh(sc, sqh, setup);
if (xfer->timeout && !sc->sc_bus.use_polling) {
callout_reset(&xfer->timeout_handle, MS_TO_TICKS(xfer->timeout),
ehci_timeout, xfer);
@@ -3365,9 +3173,9 @@ ehci_device_request(usbd_xfer_handle xfer)
EOREAD4(sc, EHCI_USBSTS)));
delay(10000);
ehci_dump_regs(sc);
- ehci_dump_sqh(sc->sc_async_head);
- ehci_dump_sqh(sqh);
- ehci_dump_sqtds(setup);
+ ehci_dump_sqh(sc, sc->sc_async_head);
+ ehci_dump_sqh(sc, sqh);
+ ehci_dump_sqtds(sc, setup);
}
#endif
@@ -3441,9 +3249,9 @@ ehci_device_bulk_start(usbd_xfer_handle xfer)
usb_transfer_complete(xfer);
return (err);
}
- newinactive->qtd.qtd_status = htole32(0);
- newinactive->qtd.qtd_next = EHCI_NULL;
- newinactive->qtd.qtd_altnext = EHCI_NULL;
+ newinactive->qtd.qtd_status = htohc32(sc, 0);
+ newinactive->qtd.qtd_next = EHCI_NULL(sc);
+ newinactive->qtd.qtd_altnext = EHCI_NULL(sc);
err = ehci_alloc_sqtd_chain(epipe, sc, len, isread, xfer,
sqh->inactivesqtd, newinactive, &data, &dataend);
if (err) {
@@ -3454,15 +3262,15 @@ ehci_device_bulk_start(usbd_xfer_handle xfer)
return (err);
}
dataend->nextqtd = newinactive;
- dataend->qtd.qtd_next = htole32(newinactive->physaddr);
- dataend->qtd.qtd_altnext = htole32(newinactive->physaddr);
+ dataend->qtd.qtd_next = htohc32(sc, newinactive->physaddr);
+ dataend->qtd.qtd_altnext = htohc32(sc, newinactive->physaddr);
sqh->inactivesqtd = newinactive;
#ifdef EHCI_DEBUG
if (ehcidebug > 5) {
DPRINTF(("ehci_device_bulk_start: data(1)\n"));
- ehci_dump_sqh(sqh);
- ehci_dump_sqtds(data);
+ ehci_dump_sqh(sc, sqh);
+ ehci_dump_sqtds(sc, data);
}
#endif
@@ -3477,7 +3285,7 @@ ehci_device_bulk_start(usbd_xfer_handle xfer)
#endif
s = splusb();
- ehci_activate_qh(sqh, data);
+ ehci_activate_qh(sc, sqh, data);
if (xfer->timeout && !sc->sc_bus.use_polling) {
callout_reset(&xfer->timeout_handle, MS_TO_TICKS(xfer->timeout),
ehci_timeout, xfer);
@@ -3497,8 +3305,8 @@ ehci_device_bulk_start(usbd_xfer_handle xfer)
ehci_dump_sqh(sc->sc_async_head);
#endif
printf("sqh:\n");
- ehci_dump_sqh(sqh);
- ehci_dump_sqtds(data);
+ ehci_dump_sqh(sc, sqh);
+ ehci_dump_sqtds(sc, data);
}
#endif
@@ -3566,7 +3374,7 @@ ehci_device_setintr(ehci_softc_t *sc, ehci_soft_qh_t *sqh, int ival)
sqh->islot = islot;
isp = &sc->sc_islots[islot];
- ehci_add_qh(sqh, isp->sqh);
+ ehci_add_qh(sc, sqh, isp->sqh);
return (USBD_NORMAL_COMPLETION);
}
@@ -3627,9 +3435,9 @@ ehci_device_intr_start(usbd_xfer_handle xfer)
usb_transfer_complete(xfer);
return (err);
}
- newinactive->qtd.qtd_status = htole32(0);
- newinactive->qtd.qtd_next = EHCI_NULL;
- newinactive->qtd.qtd_altnext = EHCI_NULL;
+ newinactive->qtd.qtd_status = htohc32(sc, 0);
+ newinactive->qtd.qtd_next = EHCI_NULL(sc);
+ newinactive->qtd.qtd_altnext = EHCI_NULL(sc);
err = ehci_alloc_sqtd_chain(epipe, sc, len, isread, xfer,
sqh->inactivesqtd, newinactive, &data, &dataend);
if (err) {
@@ -3639,15 +3447,15 @@ ehci_device_intr_start(usbd_xfer_handle xfer)
return (err);
}
dataend->nextqtd = newinactive;
- dataend->qtd.qtd_next = htole32(newinactive->physaddr);
- dataend->qtd.qtd_altnext = htole32(newinactive->physaddr);
+ dataend->qtd.qtd_next = htohc32(sc, newinactive->physaddr);
+ dataend->qtd.qtd_altnext = htohc32(sc, newinactive->physaddr);
sqh->inactivesqtd = newinactive;
#ifdef EHCI_DEBUG
if (ehcidebug > 5) {
DPRINTF(("ehci_device_intr_start: data(1)\n"));
- ehci_dump_sqh(sqh);
- ehci_dump_sqtds(data);
+ ehci_dump_sqh(sc, sqh);
+ ehci_dump_sqtds(sc, data);
}
#endif
@@ -3662,7 +3470,7 @@ ehci_device_intr_start(usbd_xfer_handle xfer)
#endif
s = splusb();
- ehci_activate_qh(sqh, data);
+ ehci_activate_qh(sc, sqh, data);
if (xfer->timeout && !sc->sc_bus.use_polling) {
callout_reset(&xfer->timeout_handle, MS_TO_TICKS(xfer->timeout),
ehci_timeout, xfer);
@@ -3678,8 +3486,8 @@ ehci_device_intr_start(usbd_xfer_handle xfer)
DPRINTF(("ehci_device_intr_start: data(3)\n"));
ehci_dump_regs(sc);
printf("sqh:\n");
- ehci_dump_sqh(sqh);
- ehci_dump_sqtds(data);
+ ehci_dump_sqh(sc, sqh);
+ ehci_dump_sqtds(sc, data);
}
#endif
@@ -3750,9 +3558,9 @@ ehci_device_intr_done(usbd_xfer_handle xfer)
xfer->status = err;
return;
}
- newinactive->qtd.qtd_status = htole32(0);
- newinactive->qtd.qtd_next = EHCI_NULL;
- newinactive->qtd.qtd_altnext = EHCI_NULL;
+ newinactive->qtd.qtd_status = htohc32(sc, 0);
+ newinactive->qtd.qtd_next = EHCI_NULL(sc);
+ newinactive->qtd.qtd_altnext = EHCI_NULL(sc);
err = ehci_alloc_sqtd_chain(epipe, sc, len, isread, xfer,
sqh->inactivesqtd, newinactive, &data, &dataend);
if (err) {
@@ -3761,8 +3569,8 @@ ehci_device_intr_done(usbd_xfer_handle xfer)
return;
}
dataend->nextqtd = newinactive;
- dataend->qtd.qtd_next = htole32(newinactive->physaddr);
- dataend->qtd.qtd_altnext = htole32(newinactive->physaddr);
+ dataend->qtd.qtd_next = htohc32(sc, newinactive->physaddr);
+ dataend->qtd.qtd_altnext = htohc32(sc, newinactive->physaddr);
sqh->inactivesqtd = newinactive;
/* Set up interrupt info. */
@@ -3777,7 +3585,7 @@ ehci_device_intr_done(usbd_xfer_handle xfer)
#endif
s = splusb();
- ehci_activate_qh(sqh, data);
+ ehci_activate_qh(sc, sqh, data);
if (xfer->timeout && !sc->sc_bus.use_polling) {
callout_reset(&xfer->timeout_handle,
MS_TO_TICKS(xfer->timeout), ehci_timeout, xfer);
@@ -3911,7 +3719,7 @@ ehci_device_isoc_start(usbd_xfer_handle xfer)
if (prev != NULL) {
prev->itd.itd_next =
- htole32(itd->physaddr | EHCI_LINK_ITD);
+ htohc32(sc, itd->physaddr | EHCI_LINK_ITD);
prev->xfer_next = itd;
} else {
start = itd;
@@ -3933,7 +3741,7 @@ ehci_device_isoc_start(usbd_xfer_handle xfer)
* offset is. Works out how many pages that is.
*/
- itd->itd.itd_ctl[j] = htole32 ( EHCI_ITD_ACTIVE |
+ itd->itd.itd_ctl[j] = htohc32(sc, EHCI_ITD_ACTIVE |
EHCI_ITD_SET_LEN(xfer->frlengths[trans_count]) |
EHCI_ITD_SET_PG(addr) |
EHCI_ITD_SET_OFFS(EHCI_PAGE_OFFSET(DMAADDR(dma_buf,
@@ -3944,7 +3752,7 @@ ehci_device_isoc_start(usbd_xfer_handle xfer)
trans_count++;
if (trans_count >= xfer->nframes) { /*Set IOC*/
- itd->itd.itd_ctl[j] |= htole32(EHCI_ITD_IOC);
+ itd->itd.itd_ctl[j] |= htohc32(sc, EHCI_ITD_IOC);
}
}
@@ -3967,7 +3775,7 @@ ehci_device_isoc_start(usbd_xfer_handle xfer)
int page = DMAADDR(dma_buf, page_offs);
page = EHCI_PAGE(page);
itd->itd.itd_bufr[j] =
- htole32(EHCI_ITD_SET_BPTR(page) | EHCI_LINK_ITD);
+ htohc32(sc, EHCI_ITD_SET_BPTR(page) | EHCI_LINK_ITD);
}
/*
@@ -3975,7 +3783,7 @@ ehci_device_isoc_start(usbd_xfer_handle xfer)
*/
k = epipe->pipe.endpoint->edesc->bEndpointAddress;
- itd->itd.itd_bufr[0] |= htole32(
+ itd->itd.itd_bufr[0] |= htohc32(sc,
EHCI_ITD_SET_EP(UE_GET_ADDR(k)) |
EHCI_ITD_SET_DADDR(epipe->pipe.device->address));
@@ -3983,12 +3791,12 @@ ehci_device_isoc_start(usbd_xfer_handle xfer)
? 1 : 0;
j = UE_GET_SIZE(
UGETW(epipe->pipe.endpoint->edesc->wMaxPacketSize));
- itd->itd.itd_bufr[1] |= htole32(EHCI_ITD_SET_DIR(k) |
+ itd->itd.itd_bufr[1] |= htohc32(sc, EHCI_ITD_SET_DIR(k) |
EHCI_ITD_SET_MAXPKT(UE_GET_SIZE(j)));
/* FIXME: handle invalid trans */
itd->itd.itd_bufr[2] |=
- htole32(EHCI_ITD_SET_MULTI(UE_GET_TRANS(j)+1));
+ htohc32(sc, EHCI_ITD_SET_MULTI(UE_GET_TRANS(j)+1));
prev = itd;
} /* End of frame */
@@ -4034,9 +3842,9 @@ ehci_device_isoc_start(usbd_xfer_handle xfer)
if (itd->itd.itd_next == 0)
/* FIXME: frindex table gets initialized to NULL
* or EHCI_NULL? */
- itd->itd.itd_next = htole32(EHCI_NULL);
+ itd->itd.itd_next = EHCI_NULL(sc);
- sc->sc_flist[frindex] = htole32(EHCI_LINK_ITD | itd->physaddr);
+ sc->sc_flist[frindex] = htohc32(sc, EHCI_LINK_ITD | itd->physaddr);
itd->u.frame_list.next = sc->sc_softitds[frindex];
sc->sc_softitds[frindex] = itd;
diff --git a/sys/dev/usb/ehci_ddb.c b/sys/dev/usb/ehci_ddb.c
new file mode 100644
index 0000000..3ebd130
--- /dev/null
+++ b/sys/dev/usb/ehci_ddb.c
@@ -0,0 +1,255 @@
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_ddb.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/endian.h>
+#include <sys/bus.h>
+#include <sys/lock.h>
+#include <sys/lockmgr.h>
+
+#include <machine/bus.h>
+#include <machine/endian.h>
+
+#include <dev/usb/usb.h>
+#include <dev/usb/usbdi.h>
+#include <dev/usb/usbdivar.h>
+
+#include <dev/usb/ehcireg.h>
+#include <dev/usb/ehcivar.h>
+
+#ifdef DDB
+#include <ddb/ddb.h>
+#include <ddb/db_sym.h>
+#else
+#define db_printf printf
+#endif
+
+extern ehci_softc_t *theehci; /* XXX */
+
+void
+ehci_dump_regs(ehci_softc_t *sc)
+{
+ int i;
+ db_printf("cmd=0x%08x, sts=0x%08x, ien=0x%08x\n",
+ EOREAD4(sc, EHCI_USBCMD),
+ EOREAD4(sc, EHCI_USBSTS),
+ EOREAD4(sc, EHCI_USBINTR));
+ db_printf("frindex=0x%08x ctrdsegm=0x%08x periodic=0x%08x async=0x%08x\n",
+ EOREAD4(sc, EHCI_FRINDEX),
+ EOREAD4(sc, EHCI_CTRLDSSEGMENT),
+ EOREAD4(sc, EHCI_PERIODICLISTBASE),
+ EOREAD4(sc, EHCI_ASYNCLISTADDR));
+ for (i = 1; i <= sc->sc_noport; i++)
+ db_printf("port %d status=0x%08x\n", i,
+ EOREAD4(sc, EHCI_PORTSC(i)));
+}
+
+static void
+ehci_dump_link(ehci_softc_t *sc, ehci_link_t link, int type)
+{
+ link = hc32toh(sc, link);
+ db_printf("0x%08x", link);
+ if (link & EHCI_LINK_TERMINATE)
+ db_printf("<T>");
+ else {
+ db_printf("<");
+ if (type) {
+ switch (EHCI_LINK_TYPE(link)) {
+ case EHCI_LINK_ITD: db_printf("ITD"); break;
+ case EHCI_LINK_QH: db_printf("QH"); break;
+ case EHCI_LINK_SITD: db_printf("SITD"); break;
+ case EHCI_LINK_FSTN: db_printf("FSTN"); break;
+ }
+ }
+ db_printf(">");
+ }
+}
+
+void
+ehci_dump_sqtds(ehci_softc_t *sc, ehci_soft_qtd_t *sqtd)
+{
+ int i;
+ u_int32_t stop;
+
+ stop = 0;
+ for (i = 0; sqtd && i < 20 && !stop; sqtd = sqtd->nextqtd, i++) {
+ ehci_dump_sqtd(sc, sqtd);
+ stop = sqtd->qtd.qtd_next & htohc32(sc, EHCI_LINK_TERMINATE);
+ }
+ if (sqtd)
+ db_printf("dump aborted, too many TDs\n");
+}
+
+void
+ehci_dump_qtd(ehci_softc_t *sc, ehci_qtd_t *qtd)
+{
+ u_int32_t s;
+
+ db_printf(" next="); ehci_dump_link(sc, qtd->qtd_next, 0);
+ db_printf(" altnext="); ehci_dump_link(sc, qtd->qtd_altnext, 0);
+ db_printf("\n");
+ s = hc32toh(sc, qtd->qtd_status);
+ db_printf(" status=0x%08x: toggle=%d bytes=0x%x ioc=%d c_page=0x%x\n",
+ s, EHCI_QTD_GET_TOGGLE(s), EHCI_QTD_GET_BYTES(s),
+ EHCI_QTD_GET_IOC(s), EHCI_QTD_GET_C_PAGE(s));
+ db_printf(" cerr=%d pid=%d stat=%b\n", EHCI_QTD_GET_CERR(s),
+ EHCI_QTD_GET_PID(s),
+ EHCI_QTD_GET_STATUS(s), EHCI_QTD_STATUS_BITS);
+ for (s = 0; s < 5; s++)
+ db_printf(" buffer[%d]=0x%08x\n", s, hc32toh(sc, qtd->qtd_buffer[s]));
+}
+
+void
+ehci_dump_sqtd(ehci_softc_t *sc, ehci_soft_qtd_t *sqtd)
+{
+ db_printf("QTD(%p) at 0x%08x:\n", sqtd, sqtd->physaddr);
+ ehci_dump_qtd(sc, &sqtd->qtd);
+}
+
+void
+ehci_dump_sqh(ehci_softc_t *sc, ehci_soft_qh_t *sqh)
+{
+ ehci_qh_t *qh = &sqh->qh;
+ u_int32_t endp, endphub;
+
+ db_printf("QH(%p) at 0x%08x:\n", sqh, sqh->physaddr);
+ db_printf(" sqtd=%p inactivesqtd=%p\n", sqh->sqtd, sqh->inactivesqtd);
+ db_printf(" link="); ehci_dump_link(sc, qh->qh_link, 1); db_printf("\n");
+ endp = hc32toh(sc, qh->qh_endp);
+ db_printf(" endp=0x%08x\n", endp);
+ db_printf(" addr=0x%02x inact=%d endpt=%d eps=%d dtc=%d hrecl=%d\n",
+ EHCI_QH_GET_ADDR(endp), EHCI_QH_GET_INACT(endp),
+ EHCI_QH_GET_ENDPT(endp), EHCI_QH_GET_EPS(endp),
+ EHCI_QH_GET_DTC(endp), EHCI_QH_GET_HRECL(endp));
+ db_printf(" mpl=0x%x ctl=%d nrl=%d\n",
+ EHCI_QH_GET_MPL(endp), EHCI_QH_GET_CTL(endp),
+ EHCI_QH_GET_NRL(endp));
+ endphub = hc32toh(sc, qh->qh_endphub);
+ db_printf(" endphub=0x%08x\n", endphub);
+ db_printf(" smask=0x%02x cmask=0x%02x huba=0x%02x port=%d mult=%d\n",
+ EHCI_QH_GET_SMASK(endphub), EHCI_QH_GET_CMASK(endphub),
+ EHCI_QH_GET_HUBA(endphub), EHCI_QH_GET_PORT(endphub),
+ EHCI_QH_GET_MULT(endphub));
+ db_printf(" curqtd="); ehci_dump_link(sc, qh->qh_curqtd, 0); db_printf("\n");
+ db_printf("Overlay qTD:\n");
+ ehci_dump_qtd(sc, &qh->qh_qtd);
+}
+
+void
+ehci_dump_itd(ehci_softc_t *sc, struct ehci_soft_itd *itd)
+{
+ ehci_isoc_trans_t t;
+ ehci_isoc_bufr_ptr_t b, b2, b3;
+ int i;
+
+ db_printf("ITD: next phys=%X\n", itd->itd.itd_next);
+
+ for (i = 0; i < 8;i++) {
+ t = hc32toh(sc, itd->itd.itd_ctl[i]);
+ db_printf("ITDctl %d: stat=%X len=%X ioc=%X pg=%X offs=%X\n", i,
+ EHCI_ITD_GET_STATUS(t), EHCI_ITD_GET_LEN(t),
+ EHCI_ITD_GET_IOC(t), EHCI_ITD_GET_PG(t),
+ EHCI_ITD_GET_OFFS(t));
+ }
+ db_printf("ITDbufr: ");
+ for (i = 0; i < 7; i++)
+ db_printf("%X,", EHCI_ITD_GET_BPTR(hc32toh(sc, itd->itd.itd_bufr[i])));
+
+ b = hc32toh(sc, itd->itd.itd_bufr[0]);
+ b2 = hc32toh(sc, itd->itd.itd_bufr[1]);
+ b3 = hc32toh(sc, itd->itd.itd_bufr[2]);
+ db_printf("\nep=%X daddr=%X dir=%d maxpkt=%X multi=%X\n",
+ EHCI_ITD_GET_EP(b), EHCI_ITD_GET_DADDR(b), EHCI_ITD_GET_DIR(b2),
+ EHCI_ITD_GET_MAXPKT(b2), EHCI_ITD_GET_MULTI(b3));
+}
+
+void
+ehci_dump_sitd(ehci_softc_t *sc, struct ehci_soft_itd *itd)
+{
+ db_printf("SITD %p next=%p prev=%p xfernext=%p physaddr=%X slot=%d\n",
+ itd, itd->u.frame_list.next, itd->u.frame_list.prev,
+ itd->xfer_next, itd->physaddr, itd->slot);
+}
+
+void
+ehci_dump_exfer(struct ehci_xfer *ex)
+{
+#ifdef DIAGNOSTIC
+ db_printf("%p: sqtdstart %p end %p itdstart %p end %p isdone %d\n",
+ ex, ex->sqtdstart, ex->sqtdend, ex->itdstart,
+ ex->itdend, ex->isdone);
+#else
+ db_printf("%p: sqtdstart %p end %p itdstart %p end %p\n",
+ ex, ex->sqtdstart, ex->sqtdend, ex->itdstart, ex->itdend);
+#endif
+}
+
+#ifdef DDB
+DB_SHOW_COMMAND(ehci, db_show_ehci)
+{
+ if (!have_addr) {
+ db_printf("usage: show ehci <addr>\n");
+ return;
+ }
+ ehci_dump_regs((ehci_softc_t *) addr);
+}
+
+DB_SHOW_COMMAND(ehci_sqtds, db_show_ehci_sqtds)
+{
+ if (!have_addr) {
+ db_printf("usage: show ehci_sqtds <addr>\n");
+ return;
+ }
+ ehci_dump_sqtds(theehci, (ehci_soft_qtd_t *) addr);
+}
+
+DB_SHOW_COMMAND(ehci_qtd, db_show_ehci_qtd)
+{
+ if (!have_addr) {
+ db_printf("usage: show ehci_qtd <addr>\n");
+ return;
+ }
+ ehci_dump_qtd(theehci, (ehci_qtd_t *) addr);
+}
+
+DB_SHOW_COMMAND(ehci_sqh, db_show_ehci_sqh)
+{
+ if (!have_addr) {
+ db_printf("usage: show ehci_sqh <addr>\n");
+ return;
+ }
+ ehci_dump_sqh(theehci, (ehci_soft_qh_t *) addr);
+}
+
+DB_SHOW_COMMAND(ehci_itd, db_show_ehci_itd)
+{
+ if (!have_addr) {
+ db_printf("usage: show ehci_itd <addr>\n");
+ return;
+ }
+ ehci_dump_itd(theehci, (struct ehci_soft_itd *) addr);
+}
+
+DB_SHOW_COMMAND(ehci_sitd, db_show_ehci_sitd)
+{
+ if (!have_addr) {
+ db_printf("usage: show ehci_sitd <addr>\n");
+ return;
+ }
+ ehci_dump_itd(theehci, (struct ehci_soft_itd *) addr);
+}
+
+DB_SHOW_COMMAND(ehci_xfer, db_show_ehci_xfer)
+{
+ if (!have_addr) {
+ db_printf("usage: show ehci_xfer <addr>\n");
+ return;
+ }
+ ehci_dump_exfer((struct ehci_xfer *) addr);
+}
+#endif /* DDB */
diff --git a/sys/dev/usb/ehci_pci.c b/sys/dev/usb/ehci_pci.c
index 46d8e40..1ae2228 100644
--- a/sys/dev/usb/ehci_pci.c
+++ b/sys/dev/usb/ehci_pci.c
@@ -61,8 +61,10 @@ __FBSDID("$FreeBSD$");
#include <sys/bus.h>
#include <sys/queue.h>
#include <sys/lockmgr.h>
-#include <machine/bus.h>
#include <sys/rman.h>
+#include <sys/endian.h>
+
+#include <machine/bus.h>
#include <machine/resource.h>
#include <dev/pci/pcivar.h>
diff --git a/sys/dev/usb/ehcireg.h b/sys/dev/usb/ehcireg.h
index 071ed7f..3c0f5e7 100644
--- a/sys/dev/usb/ehcireg.h
+++ b/sys/dev/usb/ehcireg.h
@@ -173,6 +173,15 @@
#define EHCI_PS_CS 0x00000001 /* RO connect status */
#define EHCI_PS_CLEAR (EHCI_PS_OCC|EHCI_PS_PEC|EHCI_PS_CSC)
+#define EHCI_USBMODE 0x68 /* RW USB Device mode register */
+#define EHCI_UM_CM 0x00000003 /* R/WO Controller Mode */
+#define EHCI_UM_CM_IDLE 0x0 /* Idle */
+#define EHCI_UM_CM_HOST 0x3 /* Host Controller */
+#define EHCI_UM_ES 0x00000004 /* R/WO Endian Select */
+#define EHCI_UM_ES_LE 0x0 /* Little-endian byte alignment */
+#define EHCI_UM_ES_BE 0x4 /* Big-endian byte alignment */
+#define EHCI_UM_SDIS 0x00000010 /* R/WO Stream Disable Mode */
+
#define EHCI_PORT_RESET_COMPLETE 2 /* ms */
#define EHCI_FLALIGN_ALIGN 0x1000
@@ -279,6 +288,9 @@ typedef struct {
} ehci_qtd_t;
#define EHCI_QTD_ALIGN 32
+#define EHCI_QTD_STATUS_BITS \
+ "\20\10ACTIVE\7HALTED\6BUFERR\5BABBLE\4XACTERR\3MISSED\2SPLIT\1PING"
+
/* Queue Head */
typedef struct {
ehci_link_t qh_link;
diff --git a/sys/dev/usb/ehcivar.h b/sys/dev/usb/ehcivar.h
index 55dd196..bf8fb67 100644
--- a/sys/dev/usb/ehcivar.h
+++ b/sys/dev/usb/ehcivar.h
@@ -125,6 +125,7 @@ struct ehci_soft_islot {
#define EHCI_SCFLG_SETMODE 0x0004 /* set bridge mode again after init (Marvell) */
#define EHCI_SCFLG_FORCESPEED 0x0008 /* force speed (Marvell) */
#define EHCI_SCFLG_NORESTERM 0x0010 /* don't terminate reset sequence (Marvell) */
+#define EHCI_SCFLG_BIGEDESC 0x0020 /* big-endian byte order descriptors */
typedef struct ehci_softc {
struct usbd_bus sc_bus; /* base device */
@@ -132,22 +133,16 @@ typedef struct ehci_softc {
bus_space_tag_t iot;
bus_space_handle_t ioh;
bus_size_t sc_size;
-#if defined(__FreeBSD__)
void *ih;
struct resource *io_res;
struct resource *irq_res;
-#endif
u_int sc_offs; /* offset to operational regs */
char sc_vendor[32]; /* vendor string for root hub */
int sc_id_vendor; /* vendor ID for root hub */
u_int32_t sc_cmd; /* shadow of cmd reg during suspend */
-#if defined(__NetBSD__) || defined(__OpenBSD__)
- void *sc_powerhook; /* cookie from power hook */
- void *sc_shutdownhook; /* cookie from shutdown hook */
-#endif
u_int sc_ncomp;
u_int sc_npcomp;
@@ -156,9 +151,6 @@ typedef struct ehci_softc {
usb_dma_t sc_fldma;
ehci_link_t *sc_flist;
u_int sc_flsize;
-#ifndef __FreeBSD__
- u_int sc_rand; /* XXX need proper intr scheduling */
-#endif
struct ehci_soft_islot sc_islots[EHCI_INTRQHS];
@@ -192,9 +184,6 @@ typedef struct ehci_softc {
struct callout sc_tmo_intrlist;
char sc_dying;
-#if defined(__NetBSD__)
- struct usb_dma_reserve sc_dma_reserve;
-#endif
} ehci_softc_t;
#define EREAD1(sc, a) bus_space_read_1((sc)->iot, (sc)->ioh, (a))
@@ -210,14 +199,48 @@ typedef struct ehci_softc {
#define EOWRITE2(sc, a, x) bus_space_write_2((sc)->iot, (sc)->ioh, (sc)->sc_offs+(a), (x))
#define EOWRITE4(sc, a, x) bus_space_write_4((sc)->iot, (sc)->ioh, (sc)->sc_offs+(a), (x))
+/*
+ * Handle byte order conversion between host and ``host controller''.
+ * Typically the latter is little-endian but some controllers require
+ * big-endian in which case we may need to manually swap.
+ */
+static __inline uint32_t
+htohc32(const struct ehci_softc *sc, const uint32_t v)
+{
+ return sc->sc_flags & EHCI_SCFLG_BIGEDESC ? htobe32(v) : htole32(v);
+}
+
+static __inline uint16_t
+htohc16(const struct ehci_softc *sc, const uint16_t v)
+{
+ return sc->sc_flags & EHCI_SCFLG_BIGEDESC ? htobe16(v) : htole16(v);
+}
+
+static __inline uint32_t
+hc32toh(const struct ehci_softc *sc, const uint32_t v)
+{
+ return sc->sc_flags & EHCI_SCFLG_BIGEDESC ? be32toh(v) : le32toh(v);
+}
+
+static __inline uint16_t
+hc16toh(const struct ehci_softc *sc, const uint16_t v)
+{
+ return sc->sc_flags & EHCI_SCFLG_BIGEDESC ? be16toh(v) : le16toh(v);
+}
+
usbd_status ehci_init(ehci_softc_t *);
int ehci_intr(void *);
int ehci_detach(ehci_softc_t *, int);
-#if defined(__NetBSD__) || defined(__OpenBSD__)
-int ehci_activate(device_t, enum devact);
-#endif
void ehci_power(int state, void *priv);
void ehci_shutdown(void *v);
#define MS_TO_TICKS(ms) ((ms) * hz / 1000)
+void ehci_dump_regs(ehci_softc_t *);
+void ehci_dump_sqtds(ehci_softc_t *, ehci_soft_qtd_t *);
+void ehci_dump_qtd(ehci_softc_t *, ehci_qtd_t *);
+void ehci_dump_sqtd(ehci_softc_t *, ehci_soft_qtd_t *);
+void ehci_dump_sqh(ehci_softc_t *, ehci_soft_qh_t *);
+void ehci_dump_itd(ehci_softc_t *, struct ehci_soft_itd *);
+void ehci_dump_sitd(ehci_softc_t *, struct ehci_soft_itd *);
+void ehci_dump_exfer(struct ehci_xfer *);
diff --git a/sys/dev/usb/usbdi.h b/sys/dev/usb/usbdi.h
index d5bb035..ef59039 100644
--- a/sys/dev/usb/usbdi.h
+++ b/sys/dev/usb/usbdi.h
@@ -256,7 +256,8 @@ struct usb_attach_arg {
#define USBD_SHOW_DEVICE_CLASS 0x1
#define USBD_SHOW_INTERFACE_CLASS 0x2
-int usbd_driver_load(module_t mod, int what, void *arg);
+struct module;
+int usbd_driver_load(struct module *mod, int what, void *arg);
static inline int
usb_get_port(device_t dev)
OpenPOWER on IntegriCloud