From d212022417b9a6ed5dd341c8440c4d5180d0a4a7 Mon Sep 17 00:00:00 2001 From: Sam Leffler Date: Sat, 13 Dec 2008 01:21:37 +0000 Subject: [PATCH 1/8] 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. --- sys/arm/arm/cpufunc.c | 2 +- sys/arm/arm/identcpu.c | 4 + sys/arm/conf/AVILA | 80 +- sys/arm/conf/AVILA.hints | 15 +- sys/arm/include/armreg.h | 1 + sys/arm/include/intr.h | 4 +- sys/arm/xscale/ixp425/avila_ata.c | 151 +- sys/arm/xscale/ixp425/avila_led.c | 37 +- sys/arm/xscale/ixp425/avila_machdep.c | 331 ++-- sys/arm/xscale/ixp425/cambria_fled.c | 108 ++ sys/arm/xscale/ixp425/cambria_led.c | 132 ++ sys/arm/xscale/ixp425/files.avila | 2 + sys/arm/xscale/ixp425/files.ixp425 | 2 + sys/arm/xscale/ixp425/if_npe.c | 368 +++-- sys/arm/xscale/ixp425/if_npereg.h | 6 - sys/arm/xscale/ixp425/ixp425.c | 203 ++- sys/arm/xscale/ixp425/ixp425_iic.c | 2 +- sys/arm/xscale/ixp425/ixp425_intr.h | 74 +- sys/arm/xscale/ixp425/ixp425_mem.c | 21 +- sys/arm/xscale/ixp425/ixp425_npe.c | 1723 +++++++++++---------- sys/arm/xscale/ixp425/ixp425_npevar.h | 22 +- sys/arm/xscale/ixp425/ixp425_pci.c | 27 +- sys/arm/xscale/ixp425/ixp425_qmgr.c | 4 +- sys/arm/xscale/ixp425/ixp425_timer.c | 4 +- sys/arm/xscale/ixp425/ixp425_wdog.c | 4 +- sys/arm/xscale/ixp425/ixp425reg.h | 129 +- sys/arm/xscale/ixp425/ixp425var.h | 5 + sys/arm/xscale/ixp425/ixp435_ehci.c | 357 +++++ sys/arm/xscale/ixp425/std.avila | 22 +- sys/arm/xscale/ixp425/std.ixp435 | 8 + sys/conf/files | 1 + sys/conf/options.arm | 1 + sys/contrib/dev/npe/IxNpeMicrocode.dat.uu | 1113 +++++++------ sys/dev/usb/ehci.c | 522 ++----- sys/dev/usb/ehci_ddb.c | 255 +++ sys/dev/usb/ehci_pci.c | 4 +- sys/dev/usb/ehcireg.h | 12 + sys/dev/usb/ehcivar.h | 53 +- sys/dev/usb/usbdi.h | 3 +- 39 files changed, 3551 insertions(+), 2261 deletions(-) create mode 100644 sys/arm/xscale/ixp425/cambria_fled.c create mode 100644 sys/arm/xscale/ixp425/cambria_led.c create mode 100644 sys/arm/xscale/ixp425/ixp435_ehci.c create mode 100644 sys/arm/xscale/ixp425/std.ixp435 create mode 100644 sys/dev/usb/ehci_ddb.c diff --git a/sys/arm/arm/cpufunc.c b/sys/arm/arm/cpufunc.c index 631776994bd4..df4f0679c65d 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 c8013b7bd801..df67a8a022ae 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 92bbed1b4147..f7270712d3d1 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 -#device crypto -#device cryptodev -#device hifn # NB: Soekris minipci card known to work +device ath # Atheros pci/cardbus NIC's +options ATH_DEBUG +options ATH_DIAGAPI +#options ATH_TX99_DIAG +device ath_rate_sample # SampleRate tx rate control for ath + +#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 3a1a6a7bf891..ba3a04b1fb26 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 6ba8cf437008..068073bd5a68 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 d75f14ed02a2..619c5e1c87a4 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 31e3a85a1672..337f43bb7ec3 100644 --- a/sys/arm/xscale/ixp425/avila_ata.c +++ b/sys/arm/xscale/ixp425/avila_ata.c @@ -67,13 +67,64 @@ __FBSDID("$FreeBSD$"); #include #include -#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 -#define PRONGHORN_IDE_GPIN 0 /* GPIO pin # */ -#define PRONGHORN_IDE_IRQ IXP425_INT_GPIO_0 -#define PRONGHORN_IDE_CNTRL 0x06 /* control register */ +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 */ +}; + +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<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<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 24930769a252..31558af70383 100644 --- a/sys/arm/xscale/ixp425/avila_led.c +++ b/sys/arm/xscale/ixp425/avila_led.c @@ -37,22 +37,19 @@ __FBSDID("$FreeBSD$"); #include #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 e9b53bbdf9e4..181ccb451581 100644 --- a/sys/arm/xscale/ixp425/avila_machdep.c +++ b/sys/arm/xscale/ixp425/avila_machdep.c @@ -95,6 +95,11 @@ __FBSDID("$FreeBSD$"); #include #include +/* 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, - }, - /* NPE-A Memory Space */ - { - IXP425_NPE_A_VBASE, - IXP425_NPE_A_HWBASE, - IXP425_NPE_A_SIZE, - VM_PROT_READ|VM_PROT_WRITE, - PTE_NOCACHE, - }, - /* NPE-B Memory Space */ - { - IXP425_NPE_B_VBASE, - IXP425_NPE_B_HWBASE, - IXP425_NPE_B_SIZE, - VM_PROT_READ|VM_PROT_WRITE, - PTE_NOCACHE, - }, - /* NPE-C Memory Space */ - { - IXP425_NPE_C_VBASE, - IXP425_NPE_C_HWBASE, - IXP425_NPE_C_SIZE, - VM_PROT_READ|VM_PROT_WRITE, - PTE_NOCACHE, - }, - /* MAC-A Memory Space */ - { - IXP425_MAC_A_VBASE, - IXP425_MAC_A_HWBASE, - IXP425_MAC_A_SIZE, - VM_PROT_READ|VM_PROT_WRITE, - PTE_NOCACHE, - }, - /* MAC-B Memory Space */ - { - IXP425_MAC_B_VBASE, - IXP425_MAC_B_HWBASE, - IXP425_MAC_B_SIZE, - VM_PROT_READ|VM_PROT_WRITE, - PTE_NOCACHE, - }, - /* Q-Mgr Memory Space */ - { - IXP425_QMGR_VBASE, - IXP425_QMGR_HWBASE, - IXP425_QMGR_SIZE, - VM_PROT_READ|VM_PROT_WRITE, - PTE_NOCACHE, - }, + { IXP425_PCI_MEM_VBASE, IXP425_PCI_MEM_HWBASE, IXP425_PCI_MEM_SIZE, + VM_PROT_READ|VM_PROT_WRITE, PTE_NOCACHE, }, - { - 0, - 0, - 0, - 0, - 0, - } + /* 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-B Memory Space */ + { IXP425_NPE_B_VBASE, IXP425_NPE_B_HWBASE, IXP425_NPE_B_SIZE, + VM_PROT_READ|VM_PROT_WRITE, PTE_NOCACHE, }, + /* NPE-C Memory Space */ + { IXP425_NPE_C_VBASE, IXP425_NPE_C_HWBASE, IXP425_NPE_C_SIZE, + VM_PROT_READ|VM_PROT_WRITE, PTE_NOCACHE, }, + + /* MAC-B Memory Space */ + { 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; + /* + * 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; -#define alloc_pages(var, np) \ - freemempos -= (np * PAGE_SIZE); \ - (var) = freemempos; \ - memset((char *)(var), 0, ((np) * PAGE_SIZE)); + /* 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(); - /* - * Fetch the SDRAM start/size from the ixp425 SDRAM configration - * registers. - */ + /* ready to setup the console (XXX move earlier if possible) */ cninit(); - memsize = ixp425_sdram_size(); + /* + * Fetch the RAM size from the MCU registers. The + * expansion bus was mapped above so we can now read 'em. + */ + 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 000000000000..ede1577c2263 --- /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 +__FBSDID("$FreeBSD$"); +/* + * Cambria Front Panel LED sitting on the I2C bus. + */ +#include +#include +#include +#include +#include + +#include + +#include +#include + +#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 000000000000..c55e3cb58bbc --- /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 +__FBSDID("$FreeBSD$"); + +/* + * Gateworks Cambria Octal LED Latch driver. + */ +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include + +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 50910ce6ab21..a9b70dc8a76e 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 d93524a93542..4299857e494f 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 02af22ff6606..52bea7657eca 100644 --- a/sys/arm/xscale/ixp425/if_npe.c +++ b/sys/arm/xscale/ixp425/if_npe.c @@ -85,6 +85,8 @@ __FBSDID("$FreeBSD$"); #include #include +#include + #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__); \ @@ -274,17 +279,39 @@ SYSCTL_INT(_hw_npe, OID_AUTO, txbuf, CTLFLAG_RD, &npe_txbuf, 0, "tx buffers allocated"); TUNABLE_INT("hw.npe.txbuf", &npe_txbuf); +static int +unit2npeid(int unit) +{ + 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); +} + static int npe_probe(device_t dev) { - int unit = device_get_unit(dev); + static const char *desc[NPE_MAX] = { + [NPE_A] = "IXP NPE-A", + [NPE_B] = "IXP NPE-B", + [NPE_C] = "IXP NPE-C" + }; + int npeid; - if (unit >= NPE_PORTS_MAX) { - device_printf(dev, "unit %d not supported\n", unit); + 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) - 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; + if (error) { + device_printf(dev, "cannot activate npe\n"); goto out; } + npe_getmac(sc, eaddr); + 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,13 +580,38 @@ 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 " + "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_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); @@ -597,13 +644,82 @@ override_unit(device_t dev, const char *resname, int *val, int min, int max) return 1; } +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", ®base, ®size)) { - 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 d41905d8840b..01d8c44474c0 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 af8750308459..d8b2a3f54ce4 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 int -ixp425_setup_intr(device_t dev, device_t child, - struct resource *ires, int flags, driver_filter_t *filt, - driver_intr_t *intr, void *arg, void **cookiep) +static __inline void +get_masks(struct resource *res, uint32_t *mask, uint32_t *mask2) { - uint32_t mask; int i; - BUS_SETUP_INTR(device_get_parent(dev), child, ires, flags, filt, intr, + *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 *res, int flags, driver_filter_t *filt, + driver_intr_t *intr, void *arg, void **cookiep) +{ + uint32_t mask, mask2; + + 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 38a86a6ad5ee..080ebf651d58 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 27217f467502..b7724ff7d4c7 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 7312d0fcb4c3..0458a8397040 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 a35a4ad2bcbf..ea1928a05e37 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 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 */ + 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; + 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; + 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; - /* 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 (npeid >= NPE_MAX) { + device_printf(dev, "%s: bad npeid %d\n", __func__, npeid); + return NULL; + } + config = &npeconfigs[npeid]; - if (device_get_unit(dev) == 0) { - base = IXP425_NPE_B_HWBASE; - sc->sc_size = IXP425_NPE_B_SIZE; - irq = IXP425_INT_NPE_B; + /* 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); - /* 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; + sc->sc_size = config->size; + sc->insMemSize = config->ins_memsize; /* size of instruction memory */ + sc->dataMemSize = config->data_memsize; /* size of data memory */ - /* 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)); + 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, - 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)); + /* + * 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; + 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)); + /* 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); + 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; + 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); + 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; + 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; + 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; + 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; + 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; + /* 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); + 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)); + + /* + * 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; + 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; + 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 */ } - } - return 0; + for (i = 0; i < blockSize; i++, npeMemAddress++) { + if (npe_ins_write(sc, npeMemAddress, bp->data[i], verify) != 0) { + device_printf(sc->sc_dev, + "NPE instruction write failed"); + return EIO; + } + } + return 0; } static int npe_load_data(struct ixpnpe_softc *sc, const IxNpeDlNpeMgrCodeBlock *bp, int verify) { - uint32_t npeMemAddress; - int i, blockSize; + 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; + 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); + 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; + /* 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; + 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; + } } - 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; + const IxNpeDlNpeMgrDownloadMap *downloadMap; + int i, error; - if (!npe_isstopped(sc)) { /* verify NPE is stopped */ - device_printf(sc->sc_dev, "cannot load image, NPE not stopped\n"); - return EIO; - } - - /* - * Read Download Map, checking each block type and calling - * appropriate function to perform download - */ - error = 0; - downloadMap = (const IxNpeDlNpeMgrDownloadMap *) imageCodePtr; - for (i = 0; !EOM(downloadMap->entry[i].eodmMarker); i++) { - /* calculate pointer to block to be downloaded */ - const uint32_t *bp = imageCodePtr + downloadMap->entry[i].block.offset; - switch (downloadMap->entry[i].block.type) { - case IX_NPEDL_BLOCK_TYPE_INSTRUCTION: - error = npe_load_ins(sc, - (const IxNpeDlNpeMgrCodeBlock *) bp, verify); - DPRINTF(sc->sc_dev, "%s: inst, error %d\n", __func__, error); - break; - case IX_NPEDL_BLOCK_TYPE_DATA: - error = npe_load_data(sc, - (const IxNpeDlNpeMgrCodeBlock *) bp, verify); - DPRINTF(sc->sc_dev, "%s: data, error %d\n", __func__, error); - break; - case IX_NPEDL_BLOCK_TYPE_STATE: - error = npe_load_stateinfo(sc, - (const IxNpeDlNpeMgrStateInfoBlock *) bp, verify); - DPRINTF(sc->sc_dev, "%s: state, error %d\n", __func__, error); - break; - default: - device_printf(sc->sc_dev, - "unknown block type 0x%x in download map\n", - downloadMap->entry[i].block.type); - error = EIO; /* XXX */ - break; + if (!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; + 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); + /* disable the parity interrupt */ + npe_reg_write(sc, IX_NPEDL_REG_OFFSET_CTL, + (ixNpeConfigCtrlRegVal & IX_NPEDL_PARITY_BIT_MASK)); + DPRINTFn(2, sc->sc_dev, "%s: dis parity int, CTL => 0x%x\n", + __func__, ixNpeConfigCtrlRegVal & IX_NPEDL_PARITY_BIT_MASK); + + npe_cpu_step_save(sc); - /* - * Clear the FIFOs. - */ - while (npe_checkbits(sc, - IX_NPEDL_REG_OFFSET_WFIFO, IX_NPEDL_MASK_WFIFO_VALID)) { - /* read from the Watch-point FIFO until empty */ - (void) npe_reg_read(sc, IX_NPEDL_REG_OFFSET_WFIFO); - } - - while (npe_checkbits(sc, - IX_NPEDL_REG_OFFSET_STAT, IX_NPEDL_MASK_STAT_OFNE)) { - /* read from the outFIFO until empty */ - (void) npe_reg_read(sc, IX_NPEDL_REG_OFFSET_FIFO); - } - - while (npe_checkbits(sc, - IX_NPEDL_REG_OFFSET_STAT, IX_NPEDL_MASK_STAT_IFNE)) { /* - * Step execution of the NPE intruction to read inFIFO using - * the Debug Executing Context stack. + * 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); - 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 */ + 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); } - } - - /* - * 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); + + 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 write ctx reg, error %u\n", - __func__, error); - npe_cpu_step_restore(sc); - return error; /* abort reset */ + DPRINTF(sc->sc_dev, "%s: cannot step (1), error %u\n", + __func__, error); + npe_cpu_step_restore(sc); + return error; } - } } - } + + /* + * Reset the mailbox reg + */ + /* ...from XScale side */ + npe_reg_write(sc, IX_NPEDL_REG_OFFSET_MBST, IX_NPEDL_REG_RESET_MBST); + /* ...from NPE side */ + error = npe_cpu_step(sc, IX_NPEDL_INSTR_RESET_MBOX, 0, 0); + if (error != 0) { + DPRINTF(sc->sc_dev, "%s: cannot step (2), error %u\n", + __func__, error); + npe_cpu_step_restore(sc); + return error; + } - npe_cpu_step_restore(sc); + /* + * Reset the physical registers in the NPE register file: + * Note: no need to save/restore REGMAP for Context 0 here + * since all Context Store regs are reset in subsequent code. + */ + for (regAddr = 0; + regAddr < IX_NPEDL_TOTAL_NUM_PHYS_REG && error == 0; + regAddr++) { + /* for each physical register in the NPE reg file, write 0 : */ + error = npe_physical_reg_write(sc, regAddr, 0, TRUE); + if (error != 0) { + DPRINTF(sc->sc_dev, "%s: cannot write phy reg," + "error %u\n", __func__, error); + npe_cpu_step_restore(sc); + return error; /* abort reset */ + } + } - /* 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); + /* + * 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 */ + } + } + } - /* 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); + npe_cpu_step_restore(sc); - /* 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 - */ + /* 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); - /* - * 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); + /* 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); - /* 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); + /* 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 + */ - /* - * 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); + /* + * 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); - /* 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)); + /* 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); - return error; + /* + * 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; + 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); + /* + * 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_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); + 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; + /* + * 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; + 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; + 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; + 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); + /* + * 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; + /* + * 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; + 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; + 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); + /* 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); + /* 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)); + 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; + 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); + /* 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); + 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); + /* + * 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); + 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); + /* 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); + /* 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); + /* 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); + /* 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 */ + /* + * 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; + 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; - } + 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); + /* 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); + /* 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; + /* align value from left to right */ + *regVal = (*regVal >> (IX_NPEDL_REG_SIZE_WORD - regSize)) & mask; - return 0; + 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; + 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; + 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; + /* 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; + 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); } - /* fill dest operand field of instruction with destination reg addr */ - npeInstruction |= (regAddr << IX_NPEDL_OFFSET_INSTR_DEST); + 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; - /* 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); + error = npe_logical_reg_read(sc, regAddr, regSize, ctxtNum, + &retRegVal); + if (error == 0 && regVal != retRegVal) + error = EIO; /* XXX ambiguous */ + } 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; + 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; + /* + * 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; + 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); - } + 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; + 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; + 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; + 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 */ + 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; + 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; + 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 (!ififo_wait(sc)) + return EIO; + npe_reg_write(sc, IX_NPEFIFO, msg[1]); - if (error) - device_printf(sc->sc_dev, "input FIFO timeout, msg [0x%x,0x%x]\n", - msg[0], msg[1]); - return error; -} - -static int -ixpnpe_recvmsg_locked(struct ixpnpe_softc *sc, uint32_t msg[2]) -{ - mtx_assert(&sc->sc_mtx, MA_OWNED); - - if (!sc->sc_msgwaiting) - msleep(sc, &sc->sc_mtx, 0, "npemh", 0); - bcopy(sc->sc_msg, msg, sizeof(sc->sc_msg)); - /* NB: sc_msgwaiting != 1 means the ack fetch failed */ - return sc->sc_msgwaiting != 1 ? EIO : 0; + return 0; } /* - * Send a msg to the NPE and wait for a reply. We use the - * private mutex and sleep until an interrupt is received - * signalling the availability of data in the output FIFO - * so the caller cannot be holding a mutex. May be better - * piggyback on the caller's mutex instead but that would - * make other locking confusing. + * 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(struct ixpnpe_softc *sc, +ixpnpe_sendandrecvmsg_sync(struct ixpnpe_softc *sc, const uint32_t send[2], uint32_t recv[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, send); + if (error == 0) + error = getmsg(sc, recv); + mtx_unlock(&sc->sc_mtx); - return error; + return error; } -/* XXX temporary, not reliable */ - +/* + * Send a msg to the NPE w/o waiting for a reply. + */ int -ixpnpe_sendmsg(struct ixpnpe_softc *sc, const uint32_t msg[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, msg); - mtx_unlock(&sc->sc_mtx); + mtx_lock(&sc->sc_mtx); + error = putmsg(sc, msg); + mtx_unlock(&sc->sc_mtx); - return error; + return error; } +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_recvmsg(struct ixpnpe_softc *sc, uint32_t msg[2]) +ixpnpe_recvmsg_async(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); + 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_sync(struct ixpnpe_softc *sc, uint32_t msg[2]) +{ + int error; + + mtx_lock(&sc->sc_mtx); + error = recvmsg_locked(sc, msg); + if (error == EAGAIN) + error = getmsg(sc, msg); + mtx_unlock(&sc->sc_mtx); + + return error; } diff --git a/sys/arm/xscale/ixp425/ixp425_npevar.h b/sys/arm/xscale/ixp425/ixp425_npevar.h index 6d365fcb1001..286f2169b248 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 aa40b90bc1e4..d89c97510b83 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 4188169e7657..42294669703d 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 e7717d0077fd..e0b70e94e3ac 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 9db9cce625bd..156378dc08d5 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 #include @@ -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 c7b72064863c..4b2af087e5dd 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 */ @@ -490,6 +530,28 @@ #define MCU_SDR_REFRESH 0x04 #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) * @@ -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 7503741a3fcb..87986be9a184 100644 --- a/sys/arm/xscale/ixp425/ixp425var.h +++ b/sys/arm/xscale/ixp425/ixp425var.h @@ -47,6 +47,10 @@ #include #include +/* 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 000000000000..b74f73c43b61 --- /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 +__FBSDID("$FreeBSD$"); + +#include "opt_bus.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include + +#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 b69a65ebfa49..77036ee65287 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 000000000000..2cc099a451eb --- /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 d09ead4a46b5..8c2316fa5141 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 6c8732c3dd50..2985e00bb6f3 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 c83422b912ad..0f380cd5a112 100644 --- a/sys/contrib/dev/npe/IxNpeMicrocode.dat.uu +++ b/sys/contrib/dev/npe/IxNpeMicrocode.dat.uu @@ -1,129 +1,170 @@ -$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`@0`&X6$`+WYA``;B00`6XG$`!2`!`!4@(0`9H%$`$$"1``V4$0`)S7$`+[ -M01!%V`H`!'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`R`$`#-P!`"OA03 -MC:8`":A$`'L'0F -M$`!W$`5,<1`&)8&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`H%$`"=,!!,R```0,V``!S1 -MP`,$U8`0`!Q`"^>X02 -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`-(`$``PM0$$;_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$`#\\!`` +M=*`03KX!!:C\@```^=```';P$`!T`!`"O@$0`H@0$`*"`A`"__X`6(```%B" +M```ZQ?L0``0`$``$$A``18P0`$2'$`*\`A`"__D0`L7T$`+%\Q`"Q?(&,O_Q +M"6R*(`^0P!`/J$`0$`*^`!!$``L!U,```$V'"``MAP0`-8<$`!F'!``AAP0` +M48<$`%V'!!!$?G`!V,``$`&+$1`!DQ$0`9L1!02*4`4H$(`%.!*0!404H`5` +M%K`%;!C`!6@:T!``?A(0`OWU$$@`"PP`P``$`,0`"0R"$`DH2$`0`KX!"01W +M0!`#/@$)C((0":A(0!`"O@$)A'=0$`,^`1!$=/`!Y.``$`*^`1`!O=$0`;G1 +M$`$WT1`!/]$0`'02$`+]^Q``-9`0`KX!$$1^@`>$_``01KX!`?#@`!`!@]$0 +M`8O1$`&:P1!%D](`"/PA$`!^$A`"^?H02.H``@#@```(<8`0`>O/$$P`"P6H +M_(```'X``!!V`!`#?Z$0`H+$$6*"0`$=D`0`,H'$`,V +M!A!$``L`!'8>"37N"!``V@<0 +M`K@&$`&:"A!%R@L``'=@`#':#!"7/A8)*&B`"0VN``DER@@0`9`,$`#D``DD +MHQ`)!)$1$`'0#!``T4`0`=`.$`&*$Q`#/U801``+``!W8!"7/@$%%(0@$`&: +M!Q`!DB$0`8H@$``$L!""OT<%%(0@$`'*"!`!DB$0`8H@$(%4!!`!5@T0`4@% +M$`!(`!`!T`40`9IB$`&281`!V@\0`9I@$`'2#A`!K&80`=H-$$24D!`@[`<0 +M`K9A$$1J``#`[`<0`&L>$`$H#1`!:@<0`&E&$`*X01`!I`@0`,2`$`/`X!`! +MJB$0`:(@$`"55Q``FQT0`K94$`#$3Q``Q!H0`:HA$`&B(!``E5<0`)L=$`*V +M31``Q$\0`,0:$`&J(1`!HB`0`)57$`";'1`"MD80`,1/$`#$&A`!JB$0`:(@ +M$`"55Q``FQT0`K8_$`#$3Q``Q!H0`:HA$`&B(!``E5<0`)L=$`*V.!``Q$\0 +M`,0:$`&J(1`!HB`0`)57$`";'1`"MC$0`,1/$`#$&A`!JB$0`:(@$`"55Q`` +MFQT0`K8J$`#$3Q``Q!H0`:HA$`&B(!``E5<0`)L=$`*V(Q``Q$\0`,0:$`&J +M(1`!HB`0`)57$`";'1`"MAP01``+`!QI\!`!:`00`%-`$`%2!A`!$@T0```+ +M$`!3(Q`!4@P0`.P`$`'L!Q``4``0`5`)$`*^W1``4``0`5`)$`!N)A`"N`,0 +M`6P$$`+_\A`!$@80```+$`!2A!`!4@80`O_M$`&L:!`"_Y\0`%-`$`%2!A`` +M;D80`OGP$`&;8Q!$12`0(-@'$$:XQ?_\U<`0`9MA$`!$`!`!$``0`&Z&$`*V +M!1``4!80`K@#$`!%(!``U$$0`40,$`':'Q`!$@801``+``!2C!`!4@801$0` +M$!S9-Q!&MK`0)-EW$$:VK@#`V`<01KJH``A28!!$$'``!%'S$``2@A``4``0 +M`=`)$`':'Q`!1!L0`%'P$``1@0$`&2#A`!F@\0`)"P$`"4T!`!TAH01=P6`XCD`!``4``0`!-@$`#0 +M.A``I)$0`:K@$`&:X1``D7`0`>@1$`!K(!``E-`0`=(9$`%X($`!W0!`!!@D01$0```!'@0D' +M/D(``-6!$`'4!Q`!XAH0`>@6$`&2!1````L0`-`4$$72%@-@Y``0`%``$``3 +M8!``T#H0`*21$`&2X!`!J.(0`=(7$$7H$`.(Y``0`%``$``38!``T#H0`*21 +M$`&JX!`!FN$0`)%P$`'H$1``E-`0`5P$$`'2&1`!D@X0`9H/$`"0L!``E-`0 +M`=(<$`'<&A``:S`016H'``1W,!`#``$011`)``!IX`DH*($3":X("26V&`DE +MMAP));X`"26^!`DEO@@));X,"26^$!`!F!H0`-P`"22:T!``4`<0`K8%$`!1 +MZA``4`D0`#"`"23:``D][@@0`'=`$`$&"1!$1````$>!"0<^`1`!(`P01:@) +M`]SEH!``A5$0`<0."2@K4`D-K@@0`$V&$):X$PDX("0<^)@DP, +M$`%H!Q`!H@L)*&A`$`!F!!,)IB`))*,0"01W0!`#?B8#]-'`$`&B@!`!*`80 +M`.(1$`'B@!``Z@`0`8H+$`'J"Q`![`P0`6@'$`+^(1``1400`KY&$):@RP40 +MC"`0`$0`$`!!A!`!B&$0`08(!C7'1`8TDB`&-)H@$`'341`!D!\0`=M1$`!1 +M^A``$*80`KBJ$$6@`@-`T(`0`\#`$`&J@1`!HH`0`)M7$`"5/1`"MB(0`-!/ +M$$30&@-`T`(0`:J!$`&B@!``FU<0`)4]$`*V&A``T$\01-`:`T#0`A`!JH$0 +M`:*`$`";5Q``E3T0`K82$`#03Q!$T!H#0-`"$`&J@1`!HH`0`)M7$`"5/1`" +MM@H0`-!/$$30&@-`T`(0`:J!$`&B@!``FU<0`)4]$`*V`A``8AP0`9`?$`&: +M71``(H40`&(6$`*X?A`!E%P03``+`##8!QA`W`T``-0-$`+WO!``4A80`KA[ +M!C2:(!`!HAT0`*K0$$0;/!`@V`<0`\#`$`*V=A`!H!D0`>M1$`'@8A``U``0 +M`'#`!C7'1!`"OC`0`K9N$`!%)!`!FAP0`-1`$`'<8A`!VU$0`>M1$`!PL`8U +MQT00`KXF$`+Y[Q`"N&,0`&?Z$``E7A``U#@0`'#0!C7'1!`!JE,0`KX,$`+Y +MYA`"^>T0`KA9$`!%)!``9_H0`"5>$`#4`!`!VU$0`'#`!C7'1!`!JE00`=QB +M$$6@``'\W?80`K@#$`"@]!`!X&(02*#P`@#0``'\W8,0`-WJ$`"0\1`!)H`0 +M`&)S$`!B0A``)QH0`&:&$`*V0A`!9&`01=0>`0#H!Q!&N`,``$1$$`*^#1#8 +MZ=<0`K@+$`!$A!`"O@D0EJ!"!1",(!``08P0`8AA$`!Q$`8UQT00`$82$`*V +M-!`"E@,0`41G!5-_]A`!J`,&#)(@!A"((!``T?H01(B5`/S)\P8NN!`0`*B7 +M$`*Z*A!$110"&-7&$`*X#!`!K!X0`%0S$``$I!"51&<0`)%Q!5%281``0880 +M`WE6$`%08!`#?U00`-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`"E@(0`WW[!@R2(!`"O`(&(KX*$`!@,!``(",&+&`W$`*V!A!$ +M``L"&-7&$`*X"1"4190%441G$`#5ZA"8%$0%$(P@$```"P51U&`0`W\4$$0` +M"P``1300E``+!5%$9Q``U180`O?U!B+_]`44D"`0```+$$F@@`/PT,``A.5P +M!4RE$Q!&M@<``.53$$CE%Q_\Y2\#\.1!$`$@X!`"O@4`'&$#$`-W\A``8>H0 +M`&"!$``3`1``4`D0`:J`$```"Q``ZA$0`>J`$`-_Z1``=B``MP0!$`&2P1`! +MFL`0`>3#$)"E$`5`4$`0`2RE$("@L``^N`(`$``+$(!?XQ!%V@$``'?0$`,> +M`1!$=A`%J/P0$`,"`1.-I@0)J%T@$)!W4`F'/@$)M>8`";2*(`FTJB`)M)(@ +M!1"0(`FTFB`0`82!$`#,!Q`"MC@0`,@'$`*V-A``6A80`KFX$$5:#``H0`&`'$`*V`Q``,0`)M``+ +M";7^!`FU_@@)M?X,$`&@$Q`!I!00`:@5$`&L%A`"O@80`&'J$``Q``FT``L) +MM*(@";2J(!"0A-$0`-(`$$1D-Q54X*T01KA$`!SIAQ``9@T01K8M$!SM-Q!& +MMC\0).UW$$:V/1````L01KXG$`#,0A`!(`P)M)(@";7F*`FUQR0)M<4Q$`'I,1`![3$%$)`@":RJ(!`` +MX@`0`28,$`',@!!(JQ$``.O!`!C,X!!$C-$`!,A""8WJ'Q""N*T0`KZ9";6: +M'0FTT@`)M<0^$`$@#!`!Z#\0`&`'$`*V&Q``8"80`K82$`!@(A``8>H0 +M`&`'$`*V`Q``,0`)M``+$`"$T0FU_@0)M?X(";7^#!`!K!(0`:`3$`&D%!!% +M["$55.RG$`&H%Q`"_]80`&'J$`!@$A``8`<0`K8#$``Q``FT``L)M*H@";2B +M(`FTA-$01>PA%53LIPFTJB`0`O_)'_S,@1``C-$0`)QW$`*ZC!`!Z3$0`-(6 +M$`*X)@40D"`)K*H@$`#B`!`!)@P0`H?$(*X.1`"OB4``,WB$`'-,1``C-$0`,SA$`"<=Q`"NG80`-(6$`*X#@40 +MD"`)K*H@$`#B`!`!)@P0`()C>H?$(*X +M)!`"OA`0`,0A$`'C,1`!Z3$%$)`@":RJ(!``X@`0`28,$`',@!!(JQ$`!.HA +M`!C,X!!$C-$`!,BB"8WJ'Q""N!03C:8`":A$`'L'0FL0`#$@";7'Q`"T#W$0 +M`KH*$)!/0A``3!$0`K8&$`!,1Q`"N`40`'`P!5!,``5`8!`%4$P2$(")H5$`+_[Q`!JA80@``+`+3J$1`!ZA80 +M`O_J!BLX`0"H=R`0DSX!!124(!``4$`0`8"@$`&$H1``D!<&&)`>$`!W$`5, +M<1`&)8`#G:@!`!A",0`%X:$`!>XQ!%7H4#S-0`$``6\1`` +MI!`0`K8)$``,]Q`"N@<0`:"@$```"Q`!I,,0`=##$`'D@Q`"O@00``SP$`'` +M@Q``@)`0`1KE$`#@`!!$H3<`'%ON$``>TA``7_H0`##P$`'1OQ``Q!<01``+ +M``1V(!`#?=8`%'8P$`-_^P8(JB`01``+`\SA0!``D7`0`W?\$`#L%A`"M@40 +M`9K)!C``"Q``VA$0`=K)$$6:P@`@-$`'J!Q!&_^80`>H%$`!,`!`!#@$0`,@`$`#,2A`` +MS"H01O??$`(^R1!&_]T0`>H%$`"=,!!,R```',TP`!S1,`/@U4`0`!Q`"^>X02!Q`"^=\01O^I$``, +MT!``#,(0`$Q*$`!W4!``#F`0`$TG$`!/+A``DI40`#!P$`'341``#'(0`WGY +M$$;_G`/PR,`01>H%``3-0!`"/H,02``+``3,P`/,R4`0`CY_$`$@!!``3M`0 +M`&!7$$;YD`/PR,`0`-(`$``PQ!$`%J1!`!:$40 +M1O\W`_C(H%`T#(`!!&/B40`:(!$`#<`!!('R``4-@0`_C) +M0!``F/(0`=E0$$;_'@/@R8`0`>I`$$;_&Q````L01O\9`]C(H!`!9D`01O\6 +M$`'D`1!$``L`!'0!$$0`"P`$ +M=S`0@SX!"0VF%``HY4`0`*1W"2@F?@D$C3(0`'=`"3WF%!`#/@$).*8`$`#, +M%Q``,3`)-<=$`#&D`1`"_?`0`\#@$$;_`1!&_P001O\'$$;_#Q!&_T\01O]: +M$$;_8A!&_VD01O]V$$;_>Q!&_Y@01O^E$$;_K!!&_[`01O^R$$;_PA!&_\00 +M1O]W$$;_>A!&_W<01O[:$$;_P1````L0```+````````!X<````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` @@ -206,21 +247,14 @@ 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````$/@````````````````````````````````````````````````````` +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```````````````````````````````````````````````````````````` @@ -244,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```````````````````````````````````````````````````````````` @@ -254,142 +295,8 @@ M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` -M````````````````````````````$0```!%````1@```$<```!(````20``` -M$H```!+````3````$T```!.````3P```%``````````40````````!2````` -M````%,`````````5`````````!5`````````%8`````````5P``````$+P0S -M!#<$102&!(8$FP0X`$`#:!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`@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`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$`'L'0F$`!W$`5, -M<1`&)8&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`H%$`"=,!!,R```0,V``!S1P`,$U8`0 -M`!Q`"^>X02!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`-(`$``PM0$$;_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```````````````````````````````````````````````````````````` @@ -425,6 +332,187 @@ M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` +M```````````````````````````````````````5````%4```!6````5P``` +M%@```!9````6@```%L```!<````70```%X```!?````8`````````!A````` +M````&(`````````8P````````!D`````````&4`````````9@````````!G` +M``````8X8````````````````@@(````'^P````$`@@(````'_0````(`$2(S +M(C-$5?[M\`T!`@(!```/20`````````/`````0``!T0````!```.S0````$` +M``[=`````0``#O4````!```/0@````$```]%````#P````````3@`!`"O@$0`;W1 +M$`&YT1`!-]$0`3_1$`!T$A`"_?L0`#60$`*^`1!$?H`'A/P`$$:^`0'PX``0 +M`8/1$`&+T1`!FL$019/2``C\(1``?A(0`OGZ$$CJ``(`X```"'&`$`'KSQ!, +M``L%J/R```!^```0=@`0`W^A$`'*$Q`"O@,`,.H`$`'J"Q!%B@D``'9@$`#* +M!Q`#-@801``+``!V@!`#``$0`'=``"J^"1!$``L``':`$`,``0DH:$`3";8( +M$`!W0`D'/@$)-(H@"2AHP`D,BE`)!SX!$`&:"Q`!H@<)->X$"37F'@DU[@@0 +M`-H'$`*X!A`!F@H01(7$`'H$!`!D@X0`9H/$`"0L!``E-`0`=(:$$7<%@.(Y``0`%``$``3 +M8!``T#H0`*21$`&JX!`!FN$0`)%P$`'H$1``:R`0`)30$`'2&1`!7`0016H' +M``!V@!`#``$011`)``!I@`DH*($3":X("26F%`DEMAP));X`"26^!`DEO@@) +M);X,$`!0!Q`"M@40`%'Z$`!0"1``,(`))-H`"3WN"!``=T`0`08)$$1$```` +M1X$)!SY"``#5@1`!U`<0`>(:$`'H%A`!D@40```+$`#0%!!%TA8#8.0`$`!0 +M`!``$V`0`-`Z$`"DD1`!DN`0`:CB$`'2%Q!%Z!`#B.0`$`!0`!``$V`0`-`Z +M$`"DD1`!JN`0`9KA$`"1`)*"B!$PFN"`DE +MMA@));8<"26^``DEO@0));X("26^#`DEOA`0`9@:$`#<``DDFM`0`%`'$`*V +M!1``4>H0`%`)$``P@`DDV@`)/>X($`!W0!`!!@D01$0```!'@0D'/@$0`2`, +M$$6H"0/,#Z,1`$`!1ZA``!H$0`$0)`"22(!`!F"(0`9`, +M$``6P``@DI`0`90'$`%:"!`!*`D0`(BQ$``+01``2`D0`<@-$$:N+0``T`<0 +M`K@-$`'(#`DH:2`3":X`"26V$`DEIA@)):X0"26F!`DEI@@)):X4"26N&`DE +MKAP)!SX5$`"(DA`!R`P)*&B`$PFN``DEMA`)):88"0<^`1!%F@L``&F@"2@I +M0`D,VF$)'.P@"26F&`DEKA`)):8$"26F"`DEKA0)):X8"26N'`D'/@$0`.H` +M$`'L#!`!:`<0`:(+"2AH0!``9A03":8@"22C$`D$=T`0`WXF`_31P!`!HH`0 +M`2@&$`#B$1`!XH`0`.H`$`&*"Q`!Z@L0`>P,$`%H!Q`"_B$0`$5$$`*^1A"6 +MHLL%$(P@$`!$`!``0800`8AA$`$&"`8UQT0&-)(@!C2:(!`!TU$0`9`?$`'; +M41``4?H0`!"F$`*XJA!%H`(#0-"`$`/`P!`!JH$0`:*`$`";5Q``E3T0`K8B +M$`#03Q!$T!H#0-`"$`&J@1`!HH`0`)M7$`"5/1`"MAH0`-!/$$30&@-`T`(0 +M`:J!$`&B@!``FU<0`)4]$`*V$A``T$\01-`:`T#0`A`!JH$0`:*`$`";5Q`` +ME3T0`K8*$`#03Q!$T!H#0-`"$`&J@1`!HH`0`)M7$`"5/1`"M@(0`&(<$`&0 +M'Q`!FET0`"*%$`!B%A`"N'X0`91<$$P`"P`PV`<80-P-``#4#1`"][P0`%(6 +M$`*X>P8TFB`0`:(=$`"JT!!$&SP0(-@'$`/`P!`"MG80`:`9$`'K41`!X&(0 +M`-0`$`!PP`8UQT00`KXP$`*V;A``1200`9H<$`#40!`!W&(0`=M1$`'K41`` +M<+`&-<=$$`*^)A`"^>\0`KAC$`!G^A``)5X0`-0X$`!PT`8UQT00`:I3$`*^ +M#!`"^>80`OGM$`*X61``1200`&?Z$``E7A``U``0`=M1$`!PP`8UQT00`:I4 +M$`'<8A!%H``!_-WV$`*X`Q``H/00`>!B$$B@\`(`T``!_-V#$`#=ZA``D/$0 +M`2:`$`!B$`!4,Q``!*00E41G$`"1<0514F$0 +M`$&&$`-Y5A`!4&`0`W]4$`#5%!``0880`K@%$$0`"P``1300E``+!5%$9Q`` +MU>H0`-1&$)JV,P8BOC(0`$EP$`*^!!``28`0`%'Z$`!)GA``1#00`KX5$`!) +M0!`"OA,0`$E0$`*^$1``26`0`KX/$`!)(!`"O@T0`$DP$`*^!Q``23`0`KXC +M$`!)$!``1#00`KX&$`!)$!!$``L``$4T$)0`"P511&<01``+`!Q'\`8T1A(& +M-'#@!C0`"Q`"O@$0`HX"$`-]^P8,DB`0`KP"!B*^"A``8#`0`"`C!BQ@-Q`" +MM@801``+`AC5QA`"N`D0E$64!5%$9Q``U>H0F!1$!1",(!````L%4=1@$`-_ +M%!!$``L``$4T$)0`"P511&<0`-46$`+W]08B__0%%)`@$```"Q!)H(`#\-#` +M`(3E<`5,I1,01K8'``#E4Q!(Y1P=$$2,T00`U`80`K@#$`',@!`#/AX0 +M`,Q"$`',@!`#/BP0`-@`$`+_[A"```L`MK^G$`$<#!````L0`%PF$`*V`A`` +M7"$01``+``1<00FH'.`)C.J!"835%A!&M@0$`-0&$`,XZQ`#/K<$`-0&$`,X +M51`#/B@)C*M0$`",41`!S(`0`,W`$`*_6A`!FAT)M<8H";7' +M)`FUQR@0`=0]$`!@!Q`"MA00`&`F$`*V#Q``8"(0`&'J$`!@!Q`"M@,0`#$` +M";0`"PFU_@0)M?X(";7^#!`!H!,0`:04$`&H%1`!K!80`KX&$`!AZA``,0`) +MM``+";2B(`FTJB`0D(31$`#2`!!$9#<55."M$$:X1``H0`&`'$`*V`Q``,0`)M``+ +M";7^!`FU_@@)M?X,";7^$!`!H!,0`:04$`&H%1`!K!@0`9H=$`*^"1``8>H0 +M`#$`";0`"PFTHB`)M*H@";22(!`!FAT0`*RP$)"$T1``TA`0`O_/'_S,X1`` +MC-$0`)QW$`*[)A`![3$0`-(6$`*X)P40D"`)K*H@$`#B`!`!)@P0`H?$(*XTQ`"OK\``,V"$`'-,1``C-$0`,SA +M$`"<=Q`"NQ`0`-(6$`*X#@40D"`)K*H@$`#B`!`!)@P0`H?$(*XOA`"OJH0`>$Q$`'E,1`!Z3$0`>TQ!1"0(`FL +MJB`0`.(`$`$F#!`!S(`02*L1``#KP0`8S.`01(S1``3(0@F-ZA\0@KBM$`*^ +MF0FUFAT)M-(`";7')`FUQR@)M*(@";2J(!"1X#T0`>0^$`$@#!`!Z#\0`&`' +M$`*V&1``8"80`K80$`!@(A``8>H0`&`'$`*V`Q``,0`)M``+$`"$T0FU_@0) +MM?X($`&L$A!%H!,55.RG$`&D%!`!J!40`KX,$`!AZA``8!(0`&`'$`*V`Q`` +M,0`)M``+";2J(!!$A-$55.RG";2B(`FTJB`0`&`]$$:X2P``]$`'D/A`!(`P0`>@_$`!@!Q`"MAL0`&`F$`*V$A``8"(0 +M`&'J$`!@!Q`"M@,0`#$`";0`"Q``A-$)M?X$";7^"`FU_@P0`:P2$`&@$Q`! +MI!001>PA%53LIQ`!J!<0`O_6$`!AZA``8!(0`&`'$`*V`Q``,0`)M``+";2J +M(`FTHB`)M(31$$7L(154[*<)M*H@$`+_R1_\S($0`(S1$`"<=Q`"NHP0`>DQ +M$`#2%A`"N"8%$)`@":RJ(!``X@`0`28,$`',@!!(JQ$``.OA`!C,X!!$C-$` +M!,AB"8WJ'Q""N#D0`KXE``#-XA`!S3$0`(S1$`#,X1``G'<0`KIV$`#2%A`" +MN`X%$)`@":RJ(!``X@`0`28,$`',@!!(JQ$``.MA`!C,X!!$C-$``,GB"8WJ +M'Q""N"00`KX0$`#$(1`!XS$0`>DQ!1"0(`FLJB`0`.(`$`$F#!`!S(`02*L1 +M``3J(0`8S.`01(S1``3(H@F-ZA\0@K@4$XVF``FH7,`)A'=0$`,^`1`!F!P) +MM>8`";2((`FU_AP0`,@'`+;W]Q``B-<0`(C>$`"84A!%V!P`!';`$`,@`1`` +M=I`0`P(!$XV^'!``[4`0`*Q7":@N7A`![!T)G(0P"81W4!`#/@\0`"9X$`!G +MZA``9A$0`#$P";7'Q!``)3<0`KH2$$@E,@!@Q`(`8.`"$`*^#!`#?B<0@``+ +M`+:^(PF]_AP)N*0`$`&L'1``H#`0`.`\$$2%<0,`Q`<0`OWK$``Q(`FUQ\0` +MM`]Q$`*Z"A"03T(0`$P1$`*V!A``3$<0`K@%$`!P,`503``%0&`0!5!,$A"` +MB7(01OG0$`&8'!``=I`0`)C3$`-YOA!,``L``'90`"3-\0`<3?D0D#!@!5`` +M"Q`#*@001``+``!V4!`#*@$0`':0$(,"`1.-I@@0`:H!":A<0`FDZA001``+ +M`"C\$`F$=U`0`O_/$`&J%1"```L`M.H1$`'J%1`"_^\0`:H6$(``"P"TZA$0 +M`>H6$`+_Z@8K.`$`J'8@$),^`044E"`0`%!`$`&`H!`!A*$0`)`7!AB0'A`` +M=Q`%3'$0!B6')`5X0`S@!`*AV +M(!"3?_001%!``J#$`!``D!<&&)`>$`+_]P5,P4`01``+``1VT!"7/@$%$)0@ +M$`!'$`511J<01<"@``!WP!"3?_<01``+``!V@!`#``$3":90"2A80!``=T`) +M!SX!"32:(!``D#``,-H'$`*V'@`YVH`0`80C$`!>&A``7N,015Z%`\S4`!`` +M%O$0`*00$`*V"1``#/<0`KH'$`&@H!````L0`:3#$`'0PQ`!Y(,0`KX$$``, +M\!`!P(,0`("0$`$:Y1``X``01*$W`!Q;[A``'M(0`%_Z$``P\!`!T;\0`,07 +M$$0`"P``=D`0`WW6`!1VL!`#?_L&"*H@$$0`"P/,X4`0`)%P$`-W_!``[!80 +M`K8%$`&:R08P``L0`-H1$`':R1!%FL(`'-&#$`#1AQ`"N`,0`-H1$`':PA!% +MFL8`(.P&$`*V`Q``VA$0`=K&$`#L)A!&N`X`#.V&$`-WYQ`!FL`0`.UV$`*V +M!A`!FL$0```+$`#:$1`!VL$0`W_?$`#:$1`!VL`0`W_<$`&:PP8P[$80`K8$ +M$`#:$1`!VL,0`W_6$$6:Q``,[880`K8$$`#:$1`!VL00`W_0$$6:Q0`@[`80 +M`WG-$`#:$1`!VL40`W_*$$0`"P``R7`0`SX!$`$44!`!%E@0`%0L$`!6+!`! +M5%`0`598$`$40!`!%D@0`%0L$`!6+!`!5$`0159(`]C0L!`!D9`0`,DA$`"0 +M5Q`#??``,W_L``!W(!`#/@$/A:8$$`,^`0^%I@@01``+``!W$!`#/@$/B>8$ +M$`,^`1`!H@$/B*H@$$1@&@.\T0`0`!,!$`!0"1`!D9`0`>H"$$?`@!`!D@00 +M```+$`'2`A!&_^H0`>0,$`'H#1`!Z@<01O_F$`'J!1``3``0`0X!$`#(`!`` +MS$H0`,PJ$$;WWQ`"/LD01O_=$`'J!1``G3`03,@``!S-,``!Q!&]](`',S@$`#8`!``&N`0`(S2$`#8$!`!V@,01``+ +M``!V@!"```L0`SX!$PFF%`DH9T`)!'=`$`,^`1`!F@,)/>84$`!Q$`DUQT00 +M`%X2$`!8$1`!V@,`,!C7$`*V"!``7@<0`OGN$$G,&P``S`(#X-5`$`'-L!`" +MO@P0`U0`_C)8!`!Z5$0`650$$;_?P/@R$`0`%<0$``7 +M,Q``5\H0159``\C(`!``5O`0`!Q`$$;_9P-@R``0 +M`KX:`XC(`!`"OA@`K-3`$$4>``!@T<`0`%@0$``?-Q!&]UT0`68`$$AF%P`0 +M4#X`L-1N!B!83@8,=.`&,KX!$$0V@`!(^*`0`'3P$`*^`1``-I`0`+BP$``^ +MP!``=(`01O]-`@#(`!`!Z@40`!<@$`!4`!``U"H0`(BQ$``/,!``3``0`$X' +M$`*X`A``3!`0`,PJ$$8^/Q!&_S\#Z,A`$`!D`!``Y#H0`(DQ$`'L01`!:D00 +M`6A%$$;_-P/XR'`0`&87$`!F_A`!9U`01O\R`_C(\!`!9U`01O\O`_C(X!!) +M9U`#^,E``%#8$!!%V5``(,P`$$7J!0-`R``01CXE$`&B`1``W``02!\@`%#8 +M$`/XR4`0`)CR$`'94!!&_QX#X,F`$`'J0!!&_QL0```+$$;_&0/8R*`0`69` +M$$;_%A`!Y`$01``+``!V@!"#/@$)#:84`"CE0!``I'<)*"9^$`"-,A``9C$0 +M`&?J$``Q,`DEAT0)!'=`$`,^`0D]YA0`,,P7$`&D`1`"_>\0`\#@$`'D`1!$ +M``L``':`$(,^`0D-IA0`*.5`$`"D=PDH)GX)!(TR$`!W0`D]YA00`SX!"3BF +M`!``S!<0`#$P"37'1``QI`$0`OWP$`/`X!!&_P$01O\$$$;_!Q!&_P\01O]/ +M$$;_6A!&_V(01O]I$$;_=A!&_WL01O^8$$;_I1!&_ZP01O^P$$;_LA!&_\(0 +M1O_$$$;_=Q!&_WH01O]W$$;^VA!&_\$0```+$```"P````````>'```````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` @@ -472,20 +560,7 @@ M```````````````````````````````````````````````````````````` 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```````````````````````````````````````````````````````````` @@ -520,142 +595,280 @@ M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` -M````````````````````$0```!%````1@```$<```!(````20```$H```!+` -M```3````$T```!.````3P```%``````````40````````!2`````````%,`` -M```````5`````````!5`````````%8`````````5P``````$+P0S!#<$102& -M!(8$FP0X`$`#:!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`@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```````````````````````````````````````````````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```````````````````````````````````````````````````````````` +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```````````````````````````````````````````````````````````` +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``1V3@`!`"O@$0`;W1$`&YT1`!-]$0 +M`3_1$`!T$A`"_?L0`#60$`*^`1!$?H`'A/P`$$:^`0'PX``0`8/1$`&+T1`! +MFL$019/2``C\(1``?A(0`OGZ$$CJ``(`X```"'&`$`'KSQ!,``L%J/R```!^ +M,```=V`0`SX$$$6$'@``=V`0`P0!`$B4(!`!JS$0`$&$$`!H&A``08\02!%0 +M'`#4#!P`Z`,`3)54$$6C,06X_(`0`$=,$$7$'@6H_(`0B(37$`*X`@`0``L0 +MC`2`$`/`X`1YKLP$::[0!`6FP`0)IL($;:?$!"&GQ`1]I\0$7:?$!%GF$`1) +MYA0$>:?$!&FGQ!`"OF`0`:K`"C6NS`HUKM`*-:[4"C6NV`H(+6`0`6X>$``Q +M<`I-I\0*$>80"A'F%`H1YA@*$>8<$`!M1A`"ME$0`/V!$$:_HQ`!JL`0`(D0 +M$`#)01``2"P#!*E0$`%N'A``,7`#,:?$$`*^1A`"/@<0BO_"$`*"!1``0800 +M1$&'!;C\CA`"O!$01J8+$`'2'!`!VAT0`>0<$$0'L``$=^`0`SX!$`&2'!`! +MFAT0`:0<$$0V,`6X_(``7.MP$`!Q$`,UAT0#%$@L$`#4@0`\5TP0B$PL`#S] +M@A"/P.`0`J8'$`'D'!!$![``!'?@$`,^`1`!I!P0`#8P`%SK<`"T<1`#-8=$ +M`Q1(+!`#P.`0200>`XC-```$=^`0`J8"$`,^`1`"AA00`#`@`R''9!``,"`# +M,8=$$$A$5P.(S0`0`#`@`S6'9`,T:8`0`'"0`S3J`!!&O`40`.@@`S2K4`,T +MZ@`#%SX$`%3L``,TJU`#%SX!`%SJ$!``2\,0`#`@`R''1!``_8$0`G_1$(K_ +M?!``C7`01$&'``1W\!`"N@80`D/0$`*^!`0U_G@0`D>U!%'^?!``1((0`KH$ +M!$V'9`0EAV0$/W_Y$`)%K!"*_VP0`(UP$`&2!!!%F@4`!'?P$`*^!@0TDB`$ +M4)H@$`'3<1`"1Z<0`=MQ$`!$@A`"N@80`:)@$`&J801,HI4$)*K5!#]_]1`" +M19D0`=($$`':!1"*_U<0`(UP$`)#KA!$1((`!'?P$`*Z(1`"AB(0`$1\$``. +M(1``S($0`H!$`'B`!`#/@$$4)H@!#22(!``1((0`KH( +M!"6K;P1-HV\$/)M5$`"3%1`!VF,0`=)B$`-_]A`!J@40`:($$`";51``DQ40 +M`=IA$`'28!`!J@$0`:(`$`'J!1`!X@00`8P=$`)%H%$`'3 +M<1`"?V(0`=MQ$`!$@A`"^^T0`O_-$`"-$`I!-A\*#SX!"D4$'A``1H`0``8B +M$``P,`I(``L0`#`@"DG'9!`"_Y00`(UP$$1!AP`$=Q`0`KH+$`)#9A`"O@D* +M$<=D$`!,+`H1QV00`$PL"A''9!``3"P*$<=D$`)'11``11(0`KH%"D!P,`HU +MAV0*-9]T"@]_\Q`"13P0BO[\$`"-MQ$`'B!A`!Z@<0`D<'$`!%$A`"N@P0`:)@$`&J80HTHI4*-*K5 +M$`&2!A`!F@<0`:)B"D&J8PHTHI4*-*K5"@]_YA`!T@00`=H%$`)$\A"*_K(0 +M`(UP$`'`'1`"0P@018`=``1W$!`"OA4*$)(@"A":(!`!H@`0`:H!$`"3%1`` +MFU40`=-Q$`!,+!`!VW$0`$PL"A"2(`H0FB`0`:("$`&J`Q``DQ40`)M5$`'3 +M<1``3"P0`=MQ$`)&V1``11(*0KH+"C628`HUFF$*-:)B"C6J8PH-TQ$0`=L1 +M$`'C$1`!ZQ$0`,$L$`-_X1!$A!```,'\$`'$'1`"1,D0BOZ'$`$HH!!$0<0% +MJ/R`$`!H&A``08\0`'\@"D"%$`HUAR0*-8?,0`SX!"A'F``H1Y@0*$>8("A'F#!``_8$0`$%'$`!!3!!& +MO"(0`82B$$4^H06H_(`0`'[Q$`&*!Q`"OA$*$)(@"A":(!`!HB`0`:HA$`"3 +M%1``FU40`=,Q$`';,0H0DB`*$)H@$`&B(!`!JB$0`),5$`";51`!TS$0`=LQ +M$`!_$@I"N@8*-:80"C6F%`HUIA@*-,H1"@]_ZA!%R@<%N/R`$`!!AA!&^;$` +M`'=@$(C4@0`\5TP`$)37$`,V`1!%HJ$`!'<0$`"%$!`#P.`01(40!:C\@!`` +MS``*0

(@$$5DE@`,Z6`0B#$P"37G +M)!``9=H02&7Z`!#H/@`82)<%4>@#!1"`(!`"MD`0`$D6$`*V#`DTHB`0`80" +M$(EBEQ!%XB``$.E`!5'H`Q`!2``%$(`@$``Q,`DUYR0)/>Z4$(`,0``QHI@0 +M`:J9$$7DF``$=J`0B$V3`#B8$!``2(80`K8@$`!)%A`"N`,0`*-0$`'BF!`` +MJ1(0`>B2$$7DF`"`['`012*6`D#E`!``8]H02&/Z`8#L_@)$Y`X0`6R:$`!B +M*A!$)Q$!_.'P$``K"<$`*^!A``J3`0`.E!$`'HDA``31,0`4R8`$BH(!``=H`0 +M`.F&$(,X"A!&OA,%4&`@!1"L(!!%8```*.A`$('H`P`P?B``.)EP$`*^\!,) +MMIP)*&;`"01W0!"//@$%$*0@%#6@D0DT?@`)->;@`#``"Q!%X.(`!':@$(A( +M1@40@"`0`S85$`!F`!`!9IH0`SX!$$6$`@`XY:`%4>0#$`%(``40@"`0@':` +M$`,^`1,)OH@)*&=`"01W0!`#/@$0`'#`"37')``P?B``.)@0$$1^(``$=J`0 +M`&G`$`&L`A`!:)L0`>R:$(,^`1``=H`0`SX#$`"@$A`!X)`3";:8"2AFP!`` +M=T`)!SX!$`&BF`DU]I@)-((@"32J(!``H!<0`OWU$`"!$A``@3<0C($^!1"$ +M(!``I!(0`*T1$`#H"1`!ZH<0`.```$B((!`!XI@0`,F&$(*X!!"-ZB`%4<`B +M$(``"Q,)IIP0`8R:$`#)0!``B!<)*`H>$`"`4A`!P)D)'(QP"01W0`D]YIP0 +M`SX!$`&BAA`!!)L0@(!P$`#`/!``#E$01$P)`D#,!PDXA@`0`KH)$``(*!`` +M2>H0`$@1$``P0`DUQP002`9"`$#,`@!`P`(0`*07$`!^'A``,#`)-<<$$``_ +M\Q`"M@D02*07`@#@@`)`P(`0`KP%$$6KWP(`X`<0`>L?$`+]_1"!S)H`,`11 +M$`%$FQ"*/!40`8"9$$6DD0`$=J`0`(`3$(,X#A``I3,0`:*&$`+YK!`!C)H0 +MB&%&$`,V-Q``3\P0BC@($`!@1A`#.'H0`&$6$`*V;!`#/E00`':`$`-_OQ`` +M14(0`42;$(GBFQ`!+)D0`8",$`&*F040I"`0`,E'$(:Z!!!$R4(`$.'0$`*^ +M&Q`!H(L0`0*:`$B$(!`!J.(0`,46$`*X!0`HJ%$0`>CA$`$LF!`!H(H0`.E` +M$`"H4A``J'<0`*A^$`")4!``*A\0`6KA$`",4A``B%40`,P7$`*\!A!$;20` +M`$%&$`*X`A``;"00`,@($(G@XP51;.`%$*@@$(G*F1`!HIL`.)E0$`/`X!`` +MHQ401`)X$`#L`!`!;7$0`'`P$`%O<1``S#P0`$/,$`!#ZA``,!`0`>-Q$`!" +M)Q`"N@\0`.H`$`&LF!`!`)<0`.M!$`#J.A``0?H0`KH%$`%J>A`!;'D0`6YX +M$`"K51`!ZG\0`G^Z$`,^"A`"?[@%$(@@$`"C%1`!C$(0`'$0$`'C<1``X!(0 +M`>"2$`+_ZA!%BH8`&.A0!1"`(!`!()D%4>@#$`!)0Q``84P01"!$``1@)!`! +M8``0`80"!1"`(!"`=H`0`SX!$PFNE!!$=T```&=`"2@G,`D'/@$0`'!0"37' +M)``P?B``.)@0$(RM=040@"`0`:*+!5'L`A!%X@``!'<@$`,^`1!$``L`!':@ +M$`,^`1"`=H`0`WZ7!1"`(!!$3"``1.GP$`'H`P513``%$(`@$`!^(``XF!`0 +M`O_L$`(^=A``VT`0`:*/$`&L@1!%X@@`$-0W$`*X`Q`!;AT0`CYN$%FL@0`X +MU:<`0.PN`!#53@`,U6<0`O?Z`!#51Q`"N`80`6@<$`'L'Q``:!80`K@K$`(^ +M81``W4`0`&@F$`*V!!!$480`*-1'$`*V+Q``F-,0CC9C$`!VD!"#/@$`J)3P +M$`"$":A6*A``7``)A'=0$`,^`0"VO@L0`*`0$`&;D1`!J]$0`&80$`";5Q`" +MN`00`&02$`+Y^A``9@`0`!TP$$0`"P`$=S`0`SX!$(!VD!`#/@$3C:X($`&B +M"0FH5D`0`";D":2C$`F$=U`0@SX!`+;_BQ"(G3`%3'9P!12,(!"(=Q0`%(PW +M$(LV`1`!DF$0`2A@$`"D\!`#P.`01)DP``!WL!`#&@$%%*`@$`"DT!`!JL`% +M39C"$`'J"1`#P.`0`H)$$6*!P``=F`0`,H'$`,V!A!$ +M``L``':`$`,``1``=T``*KX)$$0`"P``=H`0`P`!"2AH0!,)OA`0`'=`"0<^ +M`0DTBB`)*&C`"0R*4`D'/@$0`9H)$`&B!0DUYAP)->86"37N`!``V@<0`K@& +M$`&:"!!%R@D``'?0`#':"A"7/A8)*&B`"0VF&`DER@80`9`($`#D``DDHQ`) +M!)$1$`'0"!``T4`0`=`*$`&*'1`#/C\01``+``!WT!"7/@$%%(0@$`&:!1`! +MDB$0`8H@$``$L!""OC`%%(0@$`'*!A`!DB$0`8H@$(%4`!`!5@D0`4@!$`!( +M`!`!T`,0`9)@$`&:81`!T@L0`9)B$`':#!`!K&801=(-$"#L!Q`"MAD01&H` +M`,#L!Q``:QX0`2@)$`%J`Q!$``L`'&GP$`%H`!`!$@D0```+$`!3(Q`!4@@0 +M`KX/$`!0`!`!4`40`&XF$`*X`Q`!;``0`O_V$`$2`A````L0`%*$$`%2`A`" +M__$0`:QH$`+_YQ`"O@$0`9H%$`$$"1``V4$0`)S7$`+[EA!%V`H``':`$`,` +M`0DH:4`3":X`$)1Q$`DEAV0)!'=`"3WN``5//@$0@$46`#+WNA``:#`0`"@C +M$`!H-Q`"MD8012@#`!A$\Q``!400`9`#$`%$`Q!$4>,#9,1`$`!1ZA``!H$0 +M`$0)`"22(!`!F"(0`9`($``6P``@DI`0```+$```"Q`!6@00`<@)$$:N+0`` +MT`<0`K@-$`'("`DH:2`3":88"26^&`DEIA`)):X("26F``DEI@0)):X,"26N +M$`DEKA0)!SX5$`"(DA`!R`@)*&B`$PFF&`DEOA@)):80"0<^`1!%F@D``&F@ +M"2@I0`D,VF$)'.P@"26F$`DEK@@)):8`"26F!`DEK@P)):X0"26N%`D'/@$0 +M`.H`$`'L"!`!:`,0`:()"2AH0!``9B03":8@"22C$`D$=T`0`W](`W#1P!`! +MHH`0`2@"$`#B$1`!XH`0`.H`$`&*"1`!Z@D0`>P($`%H`Q`"_T,0EJ)F!1", +M(!``1``0`$&$$`&(81`!!@8&-)H@!C22(!`!VU$0`=-1!C7'1!``E)`0`:H> +M$`&0'Q``:!80`K@-$`!8%A`"M@D0`.(($`"5-Q``FQT0`K8'$``NLQ``+7<0 +M`KA2$`*^`Q``%U<0`KA/$`!PT`8UQT00`:I3$`!E(!!%9&`!`.@'$$:X`P`` M1$00`KX-$-CIUQ`"N`L0`$2$$`*^"1"6HD`%$(P@$`!!C!`!B&$0`'$0!C7' -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`R`$`#-P!`"OA03C:8`":A$`'L'0F$`!W$`5,<1`&)8&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`H%$`"=,!!,R```0,V``!S1P`,$U8`0`!Q`"^>X02!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`-(`$``PM0$$;_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```+````````!@(````````````````````````````````````````` +M``L"&-7&$`*X"1"4190%441G$`#5ZA"8%$0%$(P@$```"P51U&`0`W]Y$$0` +M"P``1300E``+!5%$9Q``U180`O?U!B+_]`44D"`0```+$$F@@`-LT,``A.5P +M!4RE$Q!&M@<``.53$$CE%Q_\Y2\#;.1!$`$@X!`"O@4`'&$#$`-W\A``8>H0 +M`&"!$``3`1``4`D0`:J`$```"Q``ZA$0`>J`$`-_Z1``=J``MP0!$`&2P1`! +MFL`0`>3#$)"E$`5`4$`0`2RE$("@L``^N`(`$``+$(!?XQ!%V@$`!';`$`,@ +M`1!$=I`%J/P0$`,"`1.-I@0)J%T@$)!W4`F'/@$)M>8`";2*(`FTJB`)M)(@ +M!1"0(`FTFB`0`82!$`#,!Q`"M@X0`,@'$`*V#!`!G!L)C*M0$`"<=Q`"NF$0 +M`$`'L'0FL0`#$@";7'Q`"T#W$0`KH*$)!/0A``3!$0`K8&$`!,1Q`"N`40`'`P!5!, +M``5`8!`%4$P2$(")H9$`+_[P8K +M.`$`J'8@$),^`044E"`0`%!`$`&`H!`!A*$0`)`7!AB0'A``=Q`%3'$0!B6' +M)`5X0`S@!`*AV(!"3?_001%!` +M`IC$`!``D!<&&)`>$`+_]P5,P4`01``+``1VT!"7/@$%$)0@$`!'$`511J<0 +M1<"@``!WP!"3?_<01``+``!V@!`#``$3":90"2A80!``=T`)!SX!"32:(!`` +MD#``,-H'$`*V'@`YVH`0`80C$`!>&A``7N,015Z%`U#4`!``%O$0`*00$`*V +M"1``#/<0`KH'$`&@H!````L0`:3#$`'0PQ`!Y(,0`KX$$``,\!`!P(,0`("0 +M$`$:Y1``X``01*$W`!Q;[A``'M(0`%_Z$``P\!`!T;\0`,07$$0`"P``=D`0 +M`WW6`!1VL!`#?_L&"*H@$$0`"P-0X4`0`)%P$`-W_!``[!80`K8%$`&:R08P +M``L0`-H1$`':R1!%FL(`'-&#$`#1AQ`"N`,0`-H1$`':PA!%FL8`(.P&$`*V +M`Q``VA$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 +M`W_6$$6:Q``,[880`K8$$`#:$1`!VL00`W_0$$6:Q0`@[`80`WG-$`#:$1`! +MVL40`W_*$$0`"P``R7`0`SX!$`$44!`!%E@0`%0L$`!6+!`!5%`0`598$`$4 +M0!`!%D@0`%0L$`!6+!`!5$`0159(`UC1L!`!D9`0`,DA$`"05Q`#??``,W_L +M``!W(!`#/@$/A:8$$`,^`0^%I@@01``+``!W$!`#/@$/B>8$$`,^`1`!H@$/ +MB*H@$$1@&@-$T0`0`!,!$`!0"1`!D9`0`>H"$$?`@!`!D@00```+$`'2`A!& +M_^H0`>0,$`'H#1`!Z@<01O_F`VS(P!!%Z@4`!,U`$`(^/A!(``L`!,S``U#) +M0!`"/CH0`2`$$`!.T!``8%<01OG:`VS(P!``T@`0`#!P$`'341!$3K`#4,E` +M$``PE1$`%E4!!&_\D# +M=,A`$`'K4!!&_\8`R-30$$4>``!@T<`0`%@0$``?-Q!&]\`0`68`$$AF%P`0 +M4#X`S-1^!B!83@8,=.`&,KX!$$0V@`"@^;`0`'3P$`*^`1``-I`0`+BP$``^ +MP!``=(`01O^P`V3(0!``9``0`.0Z$`"),1`![$$0`6I$$`%H11!&_Z@#6,F@ +M$`%F0!!&_Z40`>0!$$0`"P``=H`0@SX!"0VF%``HY4`0`*1W"2@F?A``C3(0 +M`&8Q$`!GZA``,3`))8=$"01W0!`#/@$)/>84`##,%Q`!I`$0`OWO$`/`X!`! +MY`$01``+``!V@!"#/@$)#:84`"CE0!``I'<)*"9^"02-,A``=T`)/>84$`,^ +M`0DXI@`0`,P7$``Q,`DUQT0`,:0!$`+]\!`#P.`01O^0$$;_DQ!&_WL01O]Z +M$$;_E!!&_Y\01O^G$$;_=A!&_W401O]T$$;_!@````"````` -M``"````/``"``#6&!`=D`P`/`````0``$``7P```&`P1`````````!$````` -M`!@L````````&.P````````8^````````!BL```````````````````````` 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``````````Q$````````&9\````````&9\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________________________________``````````````K;[OWJV^ +M[]ZMON\```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(""); - 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 000000000000..3ebd1302a37c --- /dev/null +++ b/sys/dev/usb/ehci_ddb.c @@ -0,0 +1,255 @@ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_ddb.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include + +#ifdef DDB +#include +#include +#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(""); + 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 \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 \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 \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 \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 \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 \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 \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 46d8e404e126..1ae22289811b 100644 --- a/sys/dev/usb/ehci_pci.c +++ b/sys/dev/usb/ehci_pci.c @@ -61,8 +61,10 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include #include +#include + +#include #include #include diff --git a/sys/dev/usb/ehcireg.h b/sys/dev/usb/ehcireg.h index 071ed7fdc6d2..3c0f5e71771a 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 55dd19694c0b..bf8fb67d6c13 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 d5bb0352cc41..ef5903944a7a 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) From 1020645aae9419f6d8063ec1cbc1bb7761691b9f Mon Sep 17 00:00:00 2001 From: Sam Leffler Date: Sat, 13 Dec 2008 02:53:12 +0000 Subject: [PATCH 2/8] nanobsd glue for building Avila and Cambria CF images --- .../nanobsd/gateworks/Files/root/.profile | 15 + .../gateworks/Files/usr/local/bin/netperf | Bin 0 -> 98992 bytes .../gateworks/Files/usr/local/bin/netserver | Bin 0 -> 103372 bytes tools/tools/nanobsd/gateworks/G2348 | 120 ++++++ tools/tools/nanobsd/gateworks/G2358 | 121 ++++++ tools/tools/nanobsd/gateworks/avila | 351 ++++++++++++++++++ tools/tools/nanobsd/gateworks/cambria | 351 ++++++++++++++++++ tools/tools/nanobsd/gateworks/cfg/motd | 1 + tools/tools/nanobsd/gateworks/cfg/rc.conf | 24 ++ .../nanobsd/gateworks/cfg/ssh/sshd_config | 126 +++++++ 10 files changed, 1109 insertions(+) create mode 100644 tools/tools/nanobsd/gateworks/Files/root/.profile create mode 100755 tools/tools/nanobsd/gateworks/Files/usr/local/bin/netperf create mode 100755 tools/tools/nanobsd/gateworks/Files/usr/local/bin/netserver create mode 100644 tools/tools/nanobsd/gateworks/G2348 create mode 100644 tools/tools/nanobsd/gateworks/G2358 create mode 100644 tools/tools/nanobsd/gateworks/avila create mode 100644 tools/tools/nanobsd/gateworks/cambria create mode 100644 tools/tools/nanobsd/gateworks/cfg/motd create mode 100644 tools/tools/nanobsd/gateworks/cfg/rc.conf create mode 100644 tools/tools/nanobsd/gateworks/cfg/ssh/sshd_config diff --git a/tools/tools/nanobsd/gateworks/Files/root/.profile b/tools/tools/nanobsd/gateworks/Files/root/.profile new file mode 100644 index 000000000000..e1efe6b71f3d --- /dev/null +++ b/tools/tools/nanobsd/gateworks/Files/root/.profile @@ -0,0 +1,15 @@ +# $FreeBSD: src/etc/root/dot.profile,v 1.21 2007/05/29 06:33:10 dougb Exp $ +# +PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/games:/usr/local/sbin:/usr/local/bin:~/bin +export PATH +HOME=/root; export HOME +TERM=${TERM:-cons25}; export TERM +PAGER=more; export PAGER + +#set -o vi +set -o emacs +if [ `id -u` = 0 ]; then + PS1="`hostname -s`# " +else + PS1="`hostname -s`% " +fi diff --git a/tools/tools/nanobsd/gateworks/Files/usr/local/bin/netperf b/tools/tools/nanobsd/gateworks/Files/usr/local/bin/netperf new file mode 100755 index 0000000000000000000000000000000000000000..16c93749e21f74660114b1d238927b3fd4f1828c GIT binary patch literal 98992 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 HEx-Q%`hZ@ZP_sp4-Jw)ie?|uL8 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 z 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 h /dev/null 2>&1 ; then + true + else + chflags -R noschg ${LOCAL_DIR}/ + rm -rf ${LOCAL_DIR}/ + fi + for f in bin etc lib libdata libexec sbin share; do + mkdir -p ${LOCAL_DIR}/$f + done +} +NANO_CUSTOMIZE="$NANO_CUSTOMIZE clean_usr_local" + +cust_install_machine_files() +{ + echo "cd ${NANO_TOOLS}/${NANO_NAME}/Files" + cd ${NANO_TOOLS}/${NANO_NAME}/Files + find . -print | grep -Ev '/(CVS|\.svn)' | cpio -dumpv ${NANO_WORLDDIR} +} +NANO_CUSTOMIZE="$NANO_CUSTOMIZE cust_install_files cust_install_machine_files" + +buildenv() +{ + cd ${NANO_SRC} + env TARGET_ARCH=${NANO_ARCH} __MAKE_CONF=${NANO_MAKE_CONF} \ + DESTDIR=${NANO_WORLDDIR} make buildenv +} + +net80211_tools() +{ + for f in wlanstats wlanwds wlanwatch; do + echo "(cd tools/tools/net80211/$f; make $1)"; + done | buildenv +} +net80211_clean_tools() +{ + net80211_tools "clean" +} +net80211_build_tools() +{ + net80211_tools "" +} +net80211_install_tools() +{ + net80211_tools "install" +} +NANO_CUSTOMIZE="$NANO_CUSTOMIZE net80211_clean_tools" +NANO_CUSTOMIZE="$NANO_CUSTOMIZE net80211_build_tools" +NANO_CUSTOMIZE="$NANO_CUSTOMIZE net80211_install_tools" + +ath_clean_tools() +{ + echo "cd tools/tools/ath; make clean" | buildenv +} +ath_build_tools() +{ + echo "cd tools/tools/ath; make" | buildenv +} +ath_install_tools() +{ + echo "cd tools/tools/ath; make install" | buildenv +} +NANO_CUSTOMIZE="$NANO_CUSTOMIZE ath_clean_tools" +NANO_CUSTOMIZE="$NANO_CUSTOMIZE ath_build_tools" +NANO_CUSTOMIZE="$NANO_CUSTOMIZE ath_install_tools" + +NANO_MAKEFS="makefs -B big \ + -o bsize=4096,fsize=512,density=8192,optimization=space" +export NANO_MAKEFS + +# NB: leave c++ enabled so devd can be built +CONF_BUILD=" +WITHOUT_ACPI=true +WITHOUT_ATM=true +WITHOUT_AUDIT=true +WITHOUT_BIND_DNSSEC=true +WITHOUT_BIND_ETC=true +WITHOUT_BIND_LIBS_LWRES=true +WITHOUT_BLUETOOTH=true +WITHOUT_CALENDAR=true +WITHOUT_CDDL=true +WITHOUT_CVS=true +WITHOUT_DICT=true +WITHOUT_EXAMPLES=true +WITHOUT_FORTRAN=true +WITHOUT_GAMES=true +WITHOUT_GCOV=true +WITHOUT_GPIB=true +WITHOUT_HTML=true +WITHOUT_I4B=true +WITHOUT_INET6=true +WITHOUT_INFO=true +WITHOUT_IPFILTER=true +WITHOUT_IPX=true +WITHOUT_KERBEROS=true +WITHOUT_LIBKSE=true +WITHOUT_LOCALES=true +WITHOUT_LPR=true +WITHOUT_MAN=true +WITHOUT_NETCAT=true +WITHOUT_NIS=true +WITHOUT_NLS=true +WITHOUT_NS_CACHING=true +WITHOUT_OBJC=true +WITHOUT_PROFILE=true +WITHOUT_RCMDS=true +WITHOUT_RCS=true +WITHOUT_RESCUE=true +WITHOUT_SENDMAIL=true +WITHOUT_SHAREDOCS=true +WITHOUT_SSP=true +WITHOUT_SYSCONS=true +WITHOUT_TCSH=true +" +CONF_INSTALL="$CONF_BUILD +WITHOUT_TOOLCHAIN=true +WITHOUT_INSTALLLIB=true +" + +# NB: override to suppress install of kernel.symbols +install_kernel() +{ + pprint 2 "install kernel" + pprint 3 "log: ${MAKEOBJDIRPREFIX}/_.ik" + + cd ${NANO_SRC} + env TARGET_ARCH=${NANO_ARCH} ${NANO_PMAKE} installkernel \ + INSTALL_NODEBUG=true \ + DESTDIR=${NANO_WORLDDIR} \ + __MAKE_CONF=${NANO_MAKE_CONF} KERNCONF=`basename ${NANO_KERNEL}` \ + > ${MAKEOBJDIRPREFIX}/_.ik 2>&1 +} + +# NB: override to force / on s1 instead of s1a +setup_nanobsd_etc() +{ + pprint 2 "configure nanobsd /etc" + + ( + cd ${NANO_WORLDDIR} + + # create diskless marker file + touch etc/diskless + + # Make root filesystem R/O by default + echo "root_rw_mount=NO" >> etc/defaults/rc.conf + + # save config file for scripts + echo "NANO_DRIVE=${NANO_DRIVE}" > etc/nanobsd.conf + + echo "/dev/${NANO_DRIVE}s1 / ufs ro 1 1" > etc/fstab + echo "/dev/${NANO_DRIVE}s3 /cfg ufs rw,noauto 2 2" >> etc/fstab + mkdir -p cfg + ) +} + +create_arm_diskimage() +{ + pprint 2 "build diskimage" + pprint 3 "log: ${MAKEOBJDIRPREFIX}/_.di" + + ( + echo "NANO_MEDIASIZE: $NANO_MEDIASIZE" + echo "NANO_IMAGES: $NANO_IMAGES" + echo "NANO_SECTS: $NANO_SECTS" + echo "NANO_HEADS: $NANO_HEADS" + echo "NANO_CODESIZE: $NANO_CODESIZE" + echo "NANO_CONFSIZE: $NANO_CONFSIZE" + echo "NANO_DATASIZE: $NANO_DATASIZE" + + echo $NANO_MEDIASIZE $NANO_IMAGES \ + $NANO_SECTS $NANO_HEADS \ + $NANO_CODESIZE $NANO_CONFSIZE $NANO_DATASIZE | + awk ' + { + printf "# %s\n", $0 + + # size of cylinder in sectors + cs = $3 * $4 + + # number of full cylinders on media + cyl = int ($1 / cs) + + # output fdisk geometry spec, truncate cyls to 1023 + if (cyl <= 1023) + print "g c" cyl " h" $4 " s" $3 + else + print "g c" 1023 " h" $4 " s" $3 + + if ($7 > 0) { + # size of data partition in full cylinders + dsl = int (($7 + cs - 1) / cs) + } else { + dsl = 0; + } + + # size of config partition in full cylinders + csl = int (($6 + cs - 1) / cs) + + if ($5 == 0) { + # size of image partition(s) in full cylinders + isl = int ((cyl - dsl - csl) / $2) + } else { + isl = int (($5 + cs - 1) / cs) + } + + # First image partition start at second track + print "p 1 165 " $3, isl * cs - $3 + c = isl * cs; + + # Second image partition (if any) also starts offset one + # track to keep them identical. + if ($2 > 1) { + print "p 2 165 " $3 + c, isl * cs - $3 + c += isl * cs; + } + + # Config partition starts at cylinder boundary. + print "p 3 165 " c, csl * cs + c += csl * cs + + # Data partition (if any) starts at cylinder boundary. + if ($7 > 0) { + print "p 4 165 " c, dsl * cs + } else if ($7 < 0 && $1 > c) { + print "p 4 165 " c, $1 - c + } else if ($1 < c) { + print "Disk space overcommitted by", \ + c - $1, "sectors" > "/dev/stderr" + exit 2 + } + + # Force slice 1 to be marked active. This is necessary + # for booting the image from a USB device to work. + print "a 1" + } + ' > ${MAKEOBJDIRPREFIX}/_.fdisk + + IMG=${NANO_DISKIMGDIR}/${NANO_IMGNAME} + BS=${NANO_SECTS}b + + if [ "${NANO_MD_BACKING}" = "swap" ] ; then + MD=`mdconfig -a -t swap -s ${NANO_MEDIASIZE} -x ${NANO_SECTS} \ + -y ${NANO_HEADS}` + else + echo ""; echo "Creating md backing file ${IMG} ..." + _c=`expr ${NANO_MEDIASIZE} / ${NANO_SECTS}` + pprint 2 "dd if=/dev/zero of=${IMG} bs=${BS} count=${_c}" + dd if=/dev/zero of=${IMG} bs=${BS} count=${_c} + pprint 2 "mdconfig -a -t vnode -f ${IMG} -x ${NANO_SECTS} -y ${NANO_HEADS}" + MD=`mdconfig -a -t vnode -f ${IMG} -x ${NANO_SECTS} \ + -y ${NANO_HEADS}` + fi + + trap "mdconfig -d -u $MD" 1 2 15 EXIT + + echo ""; echo "Write partition table ..." + FDISK=${MAKEOBJDIRPREFIX}/_.fdisk + pprint 2 "fdisk -i -f ${FDISK} ${MD}" + fdisk -i -f ${FDISK} ${MD} + pprint 2 "fdisk ${MD}" + fdisk ${MD} + + # Create first image + IMG1=${NANO_DISKIMGDIR}/_.disk.image1 + echo ""; echo "Create first image ${IMG1} ..." + SIZE=`awk '/^p 1/ { print $5 "b" }' ${FDISK}` + pprint 2 "${NANO_MAKEFS} -s ${SIZE} ${IMG1} ${NANO_WORLDDIR}" + ${NANO_MAKEFS} -s ${SIZE} ${IMG1} ${NANO_WORLDDIR} + pprint 2 "dd if=${IMG1} of=/dev/${MD}s1 bs=${BS}" + dd if=${IMG1} of=/dev/${MD}s1 bs=${BS} + + if [ $NANO_IMAGES -gt 1 -a $NANO_INIT_IMG2 -gt 0 ] ; then + IMG2=${NANO_DISKIMGDIR}/_.disk.image2 + echo ""; echo "Create second image ${IMG2}..." + for f in ${NANO_WORLDDIR}/etc/fstab ${NANO_WORLDDIR}/conf/base/etc/fstab + do + sed -i "" "s/${NANO_DRIVE}s1/${NANO_DRIVE}s2/g" $f + done + + SIZE=`awk '/^p 2/ { print $5 "b" }' ${FDISK}` + pprint 2 "${NANO_MAKEFS} -s ${SIZE} ${IMG2} ${NANO_WORLDDIR}" + ${NANO_MAKEFS} -s ${SIZE} ${IMG2} ${NANO_WORLDDIR} + pprint 2 "dd if=${IMG2} of=/dev/${MD}s2 bs=${BS}" + dd if=${IMG2} of=/dev/${MD}s2 bs=${BS} + fi + + # Create Config slice + CFG=${NANO_DISKIMGDIR}/_.disk.cfg + echo ""; echo "Creating config partition ${CFG}..." + SIZE=`awk '/^p 3/ { print $5 "b" }' ${FDISK}` + # XXX: fill from where ? + pprint 2 "${NANO_MAKEFS} -s ${SIZE} ${CFG} ${NANO_CFGDIR}" + ${NANO_MAKEFS} -s ${SIZE} ${CFG} ${NANO_CFGDIR} + pprint 2 "dd if=${CFG} of=/dev/${MD}s3 bs=${BS}" + dd if=${CFG} of=/dev/${MD}s3 bs=${BS} + pprint 2 "rm ${CFG}" + rm ${CFG}; CFG= # NB: disable printing below + + # Create Data slice, if any. + if [ $NANO_DATASIZE -gt 0 ] ; then + DATA=${NANO_DISKIMGDIR}/_.disk.data + echo ""; echo "Creating data partition ${DATA}..." + SIZE=`awk '/^p 4/ { print $5 "b" }' ${FDISK}` + # XXX: fill from where ? + pprint 2 "${NANO_MAKEFS} -s ${SIZE} ${DATA} /var/empty" + ${NANO_MAKEFS} -s ${SIZE} ${DATA} /var/empty + pprint 2 "dd if=${DATA} of=/dev/${MD}s4 bs=${BS}" + dd if=${DATA} of=/dev/${MD}s4 bs=${BS} + pprint 2 "rm ${DATA}" + rm ${DATA}; DATA= # NB: disable printing below + fi + + if [ "${NANO_MD_BACKING}" = "swap" ] ; then + echo "Writing out _.disk.full..." + dd if=/dev/${MD} of=${IMG} bs=${BS} + fi + + echo "" + echo "Completed images in:" + echo "" + echo "Full disk: ${IMG}" + echo "Primary partition: ${IMG1}" + test "${IMG2}" && echo "2ndary partition: ${IMG2}" + test "${CFG}" && echo "/cfg partition: ${CFG}" + test "${DATA}" && echo "/data partition: ${DATA}" + echo "" + echo "Use dd if= of=/dev/ bs=${BS} to transfer an" + echo "image to bootable media /dev/." + ) > ${MAKEOBJDIRPREFIX}/_.di 2>&1 +} diff --git a/tools/tools/nanobsd/gateworks/cambria b/tools/tools/nanobsd/gateworks/cambria new file mode 100644 index 000000000000..94aba60fb713 --- /dev/null +++ b/tools/tools/nanobsd/gateworks/cambria @@ -0,0 +1,351 @@ +NANO_NAME="cambria" +NANO_SRC="/usr/sam/base/projects/cambria" +NANO_KERNEL="G2358" + +NANO_CFGDIR=${NANO_SRC}/${NANO_TOOLS}/gateworks/cfg +test -d ${NANO_CFGDIR} || NANO_CFGDIR=/var/empty +NANO_PMAKE="make" # NB: disable -j 3 + +NANO_ARCH=arm +TARGET_CPUTYPE=xscale; export TARGET_CPUTYPE # XXX +TARGET_BIG_ENDIAN=true; export TARGET_BIG_ENDIAN # XXX + +NANO_IMAGES=1 +FlashDevice Sandisk 64 + +NANO_CUSTOMIZE="cust_allow_ssh_root" + +clean_usr_local() +{ + LOCAL_DIR=${NANO_WORLDDIR}/usr/local + pprint 2 "Clean and create world directory (${LOCAL_DIR})" + if rm -rf ${LOCAL_DIR}/ > /dev/null 2>&1 ; then + true + else + chflags -R noschg ${LOCAL_DIR}/ + rm -rf ${LOCAL_DIR}/ + fi + for f in bin etc lib libdata libexec sbin share; do + mkdir -p ${LOCAL_DIR}/$f + done +} +NANO_CUSTOMIZE="$NANO_CUSTOMIZE clean_usr_local" + +cust_install_machine_files() +{ + echo "cd ${NANO_TOOLS}/gateworks/Files" + cd ${NANO_TOOLS}/gateworks/Files + find . -print | grep -Ev '/(CVS|\.svn)' | cpio -dumpv ${NANO_WORLDDIR} +} +NANO_CUSTOMIZE="$NANO_CUSTOMIZE cust_install_files cust_install_machine_files" + +buildenv() +{ + cd ${NANO_SRC} + env TARGET_ARCH=${NANO_ARCH} __MAKE_CONF=${NANO_MAKE_CONF} \ + DESTDIR=${NANO_WORLDDIR} make buildenv +} + +net80211_tools() +{ + for f in wlanstats wlanwds wlanwatch; do + echo "(cd tools/tools/net80211/$f; make $1)"; + done | buildenv +} +net80211_clean_tools() +{ + net80211_tools "clean" +} +net80211_build_tools() +{ + net80211_tools "" +} +net80211_install_tools() +{ + net80211_tools "install" +} +NANO_CUSTOMIZE="$NANO_CUSTOMIZE net80211_clean_tools" +NANO_CUSTOMIZE="$NANO_CUSTOMIZE net80211_build_tools" +NANO_CUSTOMIZE="$NANO_CUSTOMIZE net80211_install_tools" + +ath_clean_tools() +{ + echo "cd tools/tools/ath; make clean" | buildenv +} +ath_build_tools() +{ + echo "cd tools/tools/ath; make" | buildenv +} +ath_install_tools() +{ + echo "cd tools/tools/ath; make install" | buildenv +} +NANO_CUSTOMIZE="$NANO_CUSTOMIZE ath_clean_tools" +NANO_CUSTOMIZE="$NANO_CUSTOMIZE ath_build_tools" +NANO_CUSTOMIZE="$NANO_CUSTOMIZE ath_install_tools" + +NANO_MAKEFS="makefs -B big \ + -o bsize=4096,fsize=512,density=8192,optimization=space" +export NANO_MAKEFS + +# NB: leave c++ enabled so devd can be built +CONF_BUILD=" +WITHOUT_ACPI=true +WITHOUT_ATM=true +WITHOUT_AUDIT=true +WITHOUT_BIND_DNSSEC=true +WITHOUT_BIND_ETC=true +WITHOUT_BIND_LIBS_LWRES=true +WITHOUT_BLUETOOTH=true +WITHOUT_CALENDAR=true +WITHOUT_CDDL=true +WITHOUT_CVS=true +WITHOUT_DICT=true +WITHOUT_EXAMPLES=true +WITHOUT_FORTRAN=true +WITHOUT_GAMES=true +WITHOUT_GCOV=true +WITHOUT_GPIB=true +WITHOUT_HTML=true +WITHOUT_I4B=true +WITHOUT_INET6=true +WITHOUT_INFO=true +WITHOUT_IPFILTER=true +WITHOUT_IPX=true +WITHOUT_KERBEROS=true +WITHOUT_LIBKSE=true +WITHOUT_LOCALES=true +WITHOUT_LPR=true +WITHOUT_MAN=true +WITHOUT_NETCAT=true +WITHOUT_NIS=true +WITHOUT_NLS=true +WITHOUT_NS_CACHING=true +WITHOUT_OBJC=true +WITHOUT_PROFILE=true +WITHOUT_RCMDS=true +WITHOUT_RCS=true +WITHOUT_RESCUE=true +WITHOUT_SENDMAIL=true +WITHOUT_SHAREDOCS=true +WITHOUT_SSP=true +WITHOUT_SYSCONS=true +WITHOUT_TCSH=true +" +CONF_INSTALL="$CONF_BUILD +WITHOUT_TOOLCHAIN=true +WITHOUT_INSTALLLIB=true +" + +# NB: override to suppress install of kernel.symbols +install_kernel() +{ + pprint 2 "install kernel" + pprint 3 "log: ${MAKEOBJDIRPREFIX}/_.ik" + + cd ${NANO_SRC} + env TARGET_ARCH=${NANO_ARCH} ${NANO_PMAKE} installkernel \ + INSTALL_NODEBUG=true \ + DESTDIR=${NANO_WORLDDIR} \ + __MAKE_CONF=${NANO_MAKE_CONF} KERNCONF=`basename ${NANO_KERNEL}` \ + > ${MAKEOBJDIRPREFIX}/_.ik 2>&1 +} + +# NB: override to force / on s1 instead of s1a +setup_nanobsd_etc() +{ + pprint 2 "configure nanobsd /etc" + + ( + cd ${NANO_WORLDDIR} + + # create diskless marker file + touch etc/diskless + + # Make root filesystem R/O by default + echo "root_rw_mount=NO" >> etc/defaults/rc.conf + + # save config file for scripts + echo "NANO_DRIVE=${NANO_DRIVE}" > etc/nanobsd.conf + + echo "/dev/${NANO_DRIVE}s1 / ufs ro 1 1" > etc/fstab + echo "/dev/${NANO_DRIVE}s3 /cfg ufs rw,noauto 2 2" >> etc/fstab + mkdir -p cfg + ) +} + +create_arm_diskimage() +{ + pprint 2 "build diskimage" + pprint 3 "log: ${MAKEOBJDIRPREFIX}/_.di" + + ( + echo "NANO_MEDIASIZE: $NANO_MEDIASIZE" + echo "NANO_IMAGES: $NANO_IMAGES" + echo "NANO_SECTS: $NANO_SECTS" + echo "NANO_HEADS: $NANO_HEADS" + echo "NANO_CODESIZE: $NANO_CODESIZE" + echo "NANO_CONFSIZE: $NANO_CONFSIZE" + echo "NANO_DATASIZE: $NANO_DATASIZE" + + echo $NANO_MEDIASIZE $NANO_IMAGES \ + $NANO_SECTS $NANO_HEADS \ + $NANO_CODESIZE $NANO_CONFSIZE $NANO_DATASIZE | + awk ' + { + printf "# %s\n", $0 + + # size of cylinder in sectors + cs = $3 * $4 + + # number of full cylinders on media + cyl = int ($1 / cs) + + # output fdisk geometry spec, truncate cyls to 1023 + if (cyl <= 1023) + print "g c" cyl " h" $4 " s" $3 + else + print "g c" 1023 " h" $4 " s" $3 + + if ($7 > 0) { + # size of data partition in full cylinders + dsl = int (($7 + cs - 1) / cs) + } else { + dsl = 0; + } + + # size of config partition in full cylinders + csl = int (($6 + cs - 1) / cs) + + if ($5 == 0) { + # size of image partition(s) in full cylinders + isl = int ((cyl - dsl - csl) / $2) + } else { + isl = int (($5 + cs - 1) / cs) + } + + # First image partition start at second track + print "p 1 165 " $3, isl * cs - $3 + c = isl * cs; + + # Second image partition (if any) also starts offset one + # track to keep them identical. + if ($2 > 1) { + print "p 2 165 " $3 + c, isl * cs - $3 + c += isl * cs; + } + + # Config partition starts at cylinder boundary. + print "p 3 165 " c, csl * cs + c += csl * cs + + # Data partition (if any) starts at cylinder boundary. + if ($7 > 0) { + print "p 4 165 " c, dsl * cs + } else if ($7 < 0 && $1 > c) { + print "p 4 165 " c, $1 - c + } else if ($1 < c) { + print "Disk space overcommitted by", \ + c - $1, "sectors" > "/dev/stderr" + exit 2 + } + + # Force slice 1 to be marked active. This is necessary + # for booting the image from a USB device to work. + print "a 1" + } + ' > ${MAKEOBJDIRPREFIX}/_.fdisk + + IMG=${NANO_DISKIMGDIR}/${NANO_IMGNAME} + BS=${NANO_SECTS}b + + if [ "${NANO_MD_BACKING}" = "swap" ] ; then + MD=`mdconfig -a -t swap -s ${NANO_MEDIASIZE} -x ${NANO_SECTS} \ + -y ${NANO_HEADS}` + else + echo ""; echo "Creating md backing file ${IMG} ..." + _c=`expr ${NANO_MEDIASIZE} / ${NANO_SECTS}` + pprint 2 "dd if=/dev/zero of=${IMG} bs=${BS} count=${_c}" + dd if=/dev/zero of=${IMG} bs=${BS} count=${_c} + pprint 2 "mdconfig -a -t vnode -f ${IMG} -x ${NANO_SECTS} -y ${NANO_HEADS}" + MD=`mdconfig -a -t vnode -f ${IMG} -x ${NANO_SECTS} \ + -y ${NANO_HEADS}` + fi + + trap "mdconfig -d -u $MD" 1 2 15 EXIT + + echo ""; echo "Write partition table ..." + FDISK=${MAKEOBJDIRPREFIX}/_.fdisk + pprint 2 "fdisk -i -f ${FDISK} ${MD}" + fdisk -i -f ${FDISK} ${MD} + pprint 2 "fdisk ${MD}" + fdisk ${MD} + + # Create first image + IMG1=${NANO_DISKIMGDIR}/_.disk.image1 + echo ""; echo "Create first image ${IMG1} ..." + SIZE=`awk '/^p 1/ { print $5 "b" }' ${FDISK}` + pprint 2 "${NANO_MAKEFS} -s ${SIZE} ${IMG1} ${NANO_WORLDDIR}" + ${NANO_MAKEFS} -s ${SIZE} ${IMG1} ${NANO_WORLDDIR} + pprint 2 "dd if=${IMG1} of=/dev/${MD}s1 bs=${BS}" + dd if=${IMG1} of=/dev/${MD}s1 bs=${BS} + + if [ $NANO_IMAGES -gt 1 -a $NANO_INIT_IMG2 -gt 0 ] ; then + IMG2=${NANO_DISKIMGDIR}/_.disk.image2 + echo ""; echo "Create second image ${IMG2}..." + for f in ${NANO_WORLDDIR}/etc/fstab ${NANO_WORLDDIR}/conf/base/etc/fstab + do + sed -i "" "s/${NANO_DRIVE}s1/${NANO_DRIVE}s2/g" $f + done + + SIZE=`awk '/^p 2/ { print $5 "b" }' ${FDISK}` + pprint 2 "${NANO_MAKEFS} -s ${SIZE} ${IMG2} ${NANO_WORLDDIR}" + ${NANO_MAKEFS} -s ${SIZE} ${IMG2} ${NANO_WORLDDIR} + pprint 2 "dd if=${IMG2} of=/dev/${MD}s2 bs=${BS}" + dd if=${IMG2} of=/dev/${MD}s2 bs=${BS} + fi + + # Create Config slice + CFG=${NANO_DISKIMGDIR}/_.disk.cfg + echo ""; echo "Creating config partition ${CFG}..." + SIZE=`awk '/^p 3/ { print $5 "b" }' ${FDISK}` + # XXX: fill from where ? + pprint 2 "${NANO_MAKEFS} -s ${SIZE} ${CFG} ${NANO_CFGDIR}" + ${NANO_MAKEFS} -s ${SIZE} ${CFG} ${NANO_CFGDIR} + pprint 2 "dd if=${CFG} of=/dev/${MD}s3 bs=${BS}" + dd if=${CFG} of=/dev/${MD}s3 bs=${BS} + pprint 2 "rm ${CFG}" + rm ${CFG}; CFG= # NB: disable printing below + + # Create Data slice, if any. + if [ $NANO_DATASIZE -gt 0 ] ; then + DATA=${NANO_DISKIMGDIR}/_.disk.data + echo ""; echo "Creating data partition ${DATA}..." + SIZE=`awk '/^p 4/ { print $5 "b" }' ${FDISK}` + # XXX: fill from where ? + pprint 2 "${NANO_MAKEFS} -s ${SIZE} ${DATA} /var/empty" + ${NANO_MAKEFS} -s ${SIZE} ${DATA} /var/empty + pprint 2 "dd if=${DATA} of=/dev/${MD}s4 bs=${BS}" + dd if=${DATA} of=/dev/${MD}s4 bs=${BS} + pprint 2 "rm ${DATA}" + rm ${DATA}; DATA= # NB: disable printing below + fi + + if [ "${NANO_MD_BACKING}" = "swap" ] ; then + echo "Writing out _.disk.full..." + dd if=/dev/${MD} of=${IMG} bs=${BS} + fi + + echo "" + echo "Completed images in:" + echo "" + echo "Full disk: ${IMG}" + echo "Primary partition: ${IMG1}" + test "${IMG2}" && echo "2ndary partition: ${IMG2}" + test "${CFG}" && echo "/cfg partition: ${CFG}" + test "${DATA}" && echo "/data partition: ${DATA}" + echo "" + echo "Use dd if= of=/dev/ bs=${BS} to transfer an" + echo "image to bootable media /dev/." + ) > ${MAKEOBJDIRPREFIX}/_.di 2>&1 +} diff --git a/tools/tools/nanobsd/gateworks/cfg/motd b/tools/tools/nanobsd/gateworks/cfg/motd new file mode 100644 index 000000000000..e2aad3fed813 --- /dev/null +++ b/tools/tools/nanobsd/gateworks/cfg/motd @@ -0,0 +1 @@ +FreeBSD 7.1-PRERELEASE (G2348) #1: Fri Sep 26 14:37:41 PDT 2008 diff --git a/tools/tools/nanobsd/gateworks/cfg/rc.conf b/tools/tools/nanobsd/gateworks/cfg/rc.conf new file mode 100644 index 000000000000..54768310b404 --- /dev/null +++ b/tools/tools/nanobsd/gateworks/cfg/rc.conf @@ -0,0 +1,24 @@ +#!/bin/sh + +hostname="avila" +ifconfig_npe0="DHCP" +background_dhclient_npe0="YES" # Start dhcp client in the background. +#ifconfig_npe1="DHCP" +background_dhclient_npe1="YES" # Start dhcp client in the background. + +wlans_ath0="wlan0" + +sshd_enable="YES" +nfs_client_enable="YES" + +sendmail_enable="NO" # Run the sendmail inbound daemon (YES/NO). +sendmail_submit_enable="NO" # Start a localhost-only MTA for mail submission +sendmail_outbound_enable="NO" # Dequeue stuck mail (YES/NO). +sendmail_msp_queue_enable="NO" # Dequeue stuck clientmqueue mail (YES/NO). + +dumpdev="NO" # Device to crashdump to (device name, AUTO, or NO). +background_fsck="NO" + +harvest_interrupt="NO" # Entropy device harvests interrupt randomness +harvest_ethernet="NO" # Entropy device harvests ethernet randomness +harvest_p_to_p="NO" # Entropy device harvests point-to-point randomness diff --git a/tools/tools/nanobsd/gateworks/cfg/ssh/sshd_config b/tools/tools/nanobsd/gateworks/cfg/ssh/sshd_config new file mode 100644 index 000000000000..5abb75cb01c8 --- /dev/null +++ b/tools/tools/nanobsd/gateworks/cfg/ssh/sshd_config @@ -0,0 +1,126 @@ +# $OpenBSD: sshd_config,v 1.80 2008/07/02 02:24:18 djm Exp $ +# $FreeBSD: src/crypto/openssh/sshd_config,v 1.48 2008/08/01 02:48:36 des Exp $ + +# This is the sshd server system-wide configuration file. See +# sshd_config(5) for more information. + +# This sshd was compiled with PATH=/usr/bin:/bin:/usr/sbin:/sbin + +# The strategy used for options in the default sshd_config shipped with +# OpenSSH is to specify options with their default value where +# possible, but leave them commented. Uncommented options change a +# default value. + +# Note that some of FreeBSD's defaults differ from OpenBSD's, and +# FreeBSD has a few additional options. + +#VersionAddendum FreeBSD-20080801 + +#Port 22 +#Protocol 2 +#AddressFamily any +#ListenAddress 0.0.0.0 +#ListenAddress :: + +# Disable legacy (protocol version 1) support in the server for new +# installations. In future the default will change to require explicit +# activation of protocol 1 +Protocol 2 + +# HostKey for protocol version 1 +#HostKey /etc/ssh/ssh_host_key +# HostKeys for protocol version 2 +#HostKey /etc/ssh/ssh_host_rsa_key +#HostKey /etc/ssh/ssh_host_dsa_key + +# Lifetime and size of ephemeral version 1 server key +#KeyRegenerationInterval 1h +#ServerKeyBits 1024 + +# Logging +# obsoletes QuietMode and FascistLogging +#SyslogFacility AUTH +#LogLevel INFO + +# Authentication: + +#LoginGraceTime 2m +PermitRootLogin yes +#StrictModes yes +#MaxAuthTries 6 +#MaxSessions 10 + +#RSAAuthentication yes +#PubkeyAuthentication yes +#AuthorizedKeysFile .ssh/authorized_keys + +# For this to work you will also need host keys in /etc/ssh/ssh_known_hosts +#RhostsRSAAuthentication no +# similar for protocol version 2 +#HostbasedAuthentication no +# Change to yes if you don't trust ~/.ssh/known_hosts for +# RhostsRSAAuthentication and HostbasedAuthentication +#IgnoreUserKnownHosts no +# Don't read the user's ~/.rhosts and ~/.shosts files +#IgnoreRhosts yes + +# Change to yes to enable built-in password authentication. +PasswordAuthentication yes +PermitEmptyPasswords yes + +# Change to no to disable PAM authentication +ChallengeResponseAuthentication no + +# Kerberos options +#KerberosAuthentication no +#KerberosOrLocalPasswd yes +#KerberosTicketCleanup yes +#KerberosGetAFSToken no + +# GSSAPI options +#GSSAPIAuthentication no +#GSSAPICleanupCredentials yes + +# Set this to 'no' to disable PAM authentication, account processing, +# and session processing. If this is enabled, PAM authentication will +# be allowed through the ChallengeResponseAuthentication and +# PasswordAuthentication. Depending on your PAM configuration, +# PAM authentication via ChallengeResponseAuthentication may bypass +# the setting of "PermitRootLogin without-password". +# If you just want the PAM account and session checks to run without +# PAM authentication, then enable this but set PasswordAuthentication +# and ChallengeResponseAuthentication to 'no'. +#UsePAM yes + +#AllowAgentForwarding yes +#AllowTcpForwarding yes +#GatewayPorts no +#X11Forwarding yes +#X11DisplayOffset 10 +#X11UseLocalhost yes +#PrintMotd yes +#PrintLastLog yes +#TCPKeepAlive yes +#UseLogin no +#UsePrivilegeSeparation yes +#PermitUserEnvironment no +#Compression delayed +#ClientAliveInterval 0 +#ClientAliveCountMax 3 +#UseDNS yes +#PidFile /var/run/sshd.pid +#MaxStartups 10 +#PermitTunnel no +#ChrootDirectory none + +# no default banner path +#Banner none + +# override default of no subsystems +Subsystem sftp /usr/libexec/sftp-server + +# Example of overriding settings on a per-user basis +#Match User anoncvs +# X11Forwarding no +# AllowTcpForwarding no +# ForceCommand cvs server From 4173c226442a14082de1e4206fc333119f89683a Mon Sep 17 00:00:00 2001 From: Sam Leffler Date: Sat, 13 Dec 2008 02:56:08 +0000 Subject: [PATCH 3/8] merge WIP multi-board support; tested on Avila and Cambria, still needs Proghorn testing --- sys/boot/arm/ixp425/boot2/arm_init.S | 8 +- sys/boot/arm/ixp425/boot2/boot2.c | 2 +- sys/boot/arm/ixp425/boot2/ixp425_board.c | 218 +++++++++++++++-------- sys/boot/arm/ixp425/boot2/lib.h | 1 + 4 files changed, 154 insertions(+), 75 deletions(-) diff --git a/sys/boot/arm/ixp425/boot2/arm_init.S b/sys/boot/arm/ixp425/boot2/arm_init.S index 088f23dbb123..9ede9fc605fd 100644 --- a/sys/boot/arm/ixp425/boot2/arm_init.S +++ b/sys/boot/arm/ixp425/boot2/arm_init.S @@ -24,8 +24,9 @@ * $FreeBSD$ */ -start: +#include +ASENTRY_NP(start) /* Initialise bss and sp */ nop adr r1, .Lstart @@ -47,4 +48,9 @@ infiniteLoop: .word _edata .word _end .word BOOT_STACK + +ENTRY(cpu_id) + mrc p15, 0, r0, c0, c0, 0 + RET + /* End */ diff --git a/sys/boot/arm/ixp425/boot2/boot2.c b/sys/boot/arm/ixp425/boot2/boot2.c index 2cab16a0047d..8f99e0d9b9c1 100644 --- a/sys/boot/arm/ixp425/boot2/boot2.c +++ b/sys/boot/arm/ixp425/boot2/boot2.c @@ -163,7 +163,7 @@ main(void) p_memset((char *)dmadat, 0, 32 * 1024); bt = board_init(); - printf("FreeBSD ARM (%s) boot2 v%d.%d\n", bt, 0, 3); + printf("FreeBSD ARM (%s) boot2 v%d.%d\n", bt, 0, 4); autoboot = 1; diff --git a/sys/boot/arm/ixp425/boot2/ixp425_board.c b/sys/boot/arm/ixp425/boot2/ixp425_board.c index 985c0a52c82d..5c8d54cfc4c7 100644 --- a/sys/boot/arm/ixp425/boot2/ixp425_board.c +++ b/sys/boot/arm/ixp425/boot2/ixp425_board.c @@ -27,20 +27,35 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #include "lib.h" #include "cf_ata.h" +#include #include #include -static u_int8_t *ubase; +struct board_config { + const char *desc; + int (*probe)(int boardtype_hint); + void (*init)(void); +}; +/* set of registered boards */ +SET_DECLARE(boards, struct board_config); +#define BOARD_CONFIG(name, _desc) \ +static struct board_config name##config = { \ + .desc = _desc, \ + .probe = name##_probe, \ + .init = name##_init, \ +}; \ +DATA_SET(boards, name##config) -#define BOARD_AVILA 0 -#define BOARD_PRONGHORN 1 -static int board; +static u_int cputype; +#define cpu_is_ixp43x() (cputype == CPU_ID_IXP435) +static u_int8_t *ubase; static u_int8_t uart_getreg(u_int8_t *, int); static void uart_setreg(u_int8_t *, int, u_int8_t); @@ -57,32 +72,18 @@ static void cf_clr(void); const char * board_init(void) { - volatile u_int32_t *cs; - const char *bt = NULL; + struct board_config **pbp; - /* - * Redboot only configure the chip selects that are needed, so - * use that to figure out if it is an Avila or ADI board. The - * Avila boards use CS2 and ADI does not. - */ - cs = (u_int32_t *)(IXP425_EXP_HWBASE + EXP_TIMING_CS2_OFFSET); - if (*cs != 0) { - board = BOARD_AVILA; - bt = "Avila"; - } else { - board = BOARD_PRONGHORN; - bt = "Pronghorn Metro"; - } + cputype = cpu_id() & CPU_ID_CPU_MASK; - /* Config the serial port. RedBoot should do the rest. */ - if (board == BOARD_AVILA) - ubase = (u_int8_t *)(IXP425_UART0_HWBASE); - else - ubase = (u_int8_t *)(IXP425_UART1_HWBASE); - - cf_init(); - - return bt; + SET_FOREACH(pbp, boards) + /* XXX pass down redboot board type */ + if ((*pbp)->probe(0)) { + (*pbp)->init(); + return (*pbp)->desc; + } + /* XXX panic, unknown board type */ + return "???"; } /* @@ -228,6 +229,9 @@ struct { u_int8_t sectors; u_int32_t cylinders; + u_int32_t *cs1to; + u_int32_t *cs2to; + u_int8_t *cs1; u_int8_t *cs2; @@ -265,38 +269,21 @@ cf_init(void) #ifdef DEBUG int rval; #endif - volatile u_int32_t *cs; - - /* Setup the CF select timeing. Maybe already done by RedBoot? */ - if (board == BOARD_AVILA) { - cs = (u_int32_t *)(IXP425_EXP_HWBASE + EXP_TIMING_CS1_OFFSET); - *cs |= (EXP_BYTE_EN | EXP_WR_EN | EXP_BYTE_RD16 | EXP_CS_EN); - DPRINTF("t1 %x, ", *cs); - - cs = (u_int32_t *)(IXP425_EXP_HWBASE + EXP_TIMING_CS2_OFFSET); - *cs |= (EXP_BYTE_EN | EXP_WR_EN | EXP_BYTE_RD16 | EXP_CS_EN); - DPRINTF("t2 %x\n", *cs); - - dskinf.cs1 = (u_int8_t *)IXP425_EXP_BUS_CS1_HWBASE; - dskinf.cs2 = (u_int8_t *)IXP425_EXP_BUS_CS2_HWBASE; - } else { - cs = (u_int32_t *)(IXP425_EXP_HWBASE + EXP_TIMING_CS3_OFFSET); - *cs |= (EXP_BYTE_EN | EXP_WR_EN | EXP_BYTE_RD16 | EXP_CS_EN); - DPRINTF("t1 %x, ", *cs); - - cs = (u_int32_t *)(IXP425_EXP_HWBASE + EXP_TIMING_CS4_OFFSET); - *cs |= (EXP_BYTE_EN | EXP_WR_EN | EXP_BYTE_RD16 | EXP_CS_EN); - DPRINTF("t2 %x\n", *cs); - - dskinf.cs1 = (u_int8_t *)IXP425_EXP_BUS_CS3_HWBASE; - dskinf.cs2 = (u_int8_t *)IXP425_EXP_BUS_CS4_HWBASE; - } - DPRINTF("cs1 %x, cs2 %x\n", dskinf.cs1, dskinf.cs2); + /* NB: board init routines setup other parts of dskinf */ dskinf.use_stream8 = 0; dskinf.use_lba = 0; dskinf.debug = 1; + DPRINTF("cs1 %x, cs2 %x\n", dskinf.cs1, dskinf.cs2); + + /* Setup the CF window */ + *dskinf.cs1to |= (EXP_BYTE_EN | EXP_WR_EN | EXP_BYTE_RD16 | EXP_CS_EN); + DPRINTF("t1 %x, ", *dskinf.cs1to); + + *dskinf.cs2to |= (EXP_BYTE_EN | EXP_WR_EN | EXP_BYTE_RD16 | EXP_CS_EN); + DPRINTF("t2 %x\n", *dskinf.cs2to); + /* Detect if there is a disk. */ cfwrite8(CF_DRV_HEAD, CF_D_IBM); DELAY(1000); @@ -340,29 +327,24 @@ static void cfenable16(void) { u_int32_t val; - volatile u_int32_t *cs; - if (board == BOARD_AVILA) - cs = (u_int32_t *)(IXP425_EXP_HWBASE + EXP_TIMING_CS1_OFFSET); - else - cs = (u_int32_t *)(IXP425_EXP_HWBASE + EXP_TIMING_CS3_OFFSET); - val = *cs; - *cs = val & (~1); - DPRINTF("cfenable16: cs1 timing reg %x\n", *cs); + val = *dskinf.cs1to; + *dskinf.cs1to = val &~ EXP_BYTE_EN; +#if 0 + DPRINTF("%s: cs1 timing reg %x\n", *dskinf.cs1to, __func__); +#endif } static void cfdisable16(void) { u_int32_t val; - volatile u_int32_t *cs; - if (board == BOARD_AVILA) - cs = (u_int32_t *)(IXP425_EXP_HWBASE + EXP_TIMING_CS1_OFFSET); - else - cs = (u_int32_t *)(IXP425_EXP_HWBASE + EXP_TIMING_CS3_OFFSET); - val = *cs; - *cs = val | 1; + val = *dskinf.cs1to; + *dskinf.cs1to = val | EXP_BYTE_EN; +#if 0 + DPRINTF("%s: cs1 timing reg %x\n", *dskinf.cs1to, __func__); +#endif } static u_int8_t @@ -478,7 +460,8 @@ cfwait(u_int8_t mask) while (tout <= 5000000) { status = cfread8(CF_STATUS); if (status == 0xff) { - printf("cfwait: master: no status, reselecting\n"); + printf("%s: master: no status, reselecting\n", + __func__); cfwrite8(CF_DRV_HEAD, CF_D_IBM); DELAY(1); status = cfread8(CF_STATUS); @@ -487,10 +470,14 @@ cfwait(u_int8_t mask) return -1; dskinf.status = status; if (!(status & CF_S_BUSY)) { - if (status & CF_S_ERROR) + if (status & CF_S_ERROR) { dskinf.error = cfread8(CF_ERROR); + printf("%s: error, status 0x%x error 0x%x\n", + __func__, status, dskinf.error); + } if ((status & mask) == mask) { - DPRINTF("cfwait: tout %u\n", tout); + DPRINTF("%s: status 0x%x mask 0x%x tout %u\n", + __func__, status, mask, tout); return (status & CF_S_ERROR); } } @@ -695,3 +682,88 @@ avila_read(char *dest, unsigned source, unsigned length) return 0; } +/* + * Gateworks Avila Support. + */ +static int +avila_probe(int boardtype_hint) +{ + volatile u_int32_t *cs; + /* + * Redboot only configure the chip selects that are needed, so + * use that to figure out if it is an Avila or ADI board. The + * Avila boards use CS2 and ADI does not. + */ + cs = (u_int32_t *)(IXP425_EXP_HWBASE + EXP_TIMING_CS2_OFFSET); + return (*cs != 0); +} + +static void +avila_init(void) +{ + /* Config the serial port. RedBoot should do the rest. */ + ubase = (u_int8_t *)(IXP425_UART0_HWBASE); + + dskinf.cs1to = (u_int32_t *)(IXP425_EXP_HWBASE + EXP_TIMING_CS1_OFFSET); + dskinf.cs2to = (u_int32_t *)(IXP425_EXP_HWBASE + EXP_TIMING_CS2_OFFSET); + dskinf.cs1 = (u_int8_t *)IXP425_EXP_BUS_CS1_HWBASE; + dskinf.cs2 = (u_int8_t *)IXP425_EXP_BUS_CS2_HWBASE; + + cf_init(); +} +BOARD_CONFIG(avila, "Gateworks Avila"); + +/* + * Gateworks Cambria Support. + */ +static int +cambria_probe(int boardtype_hint) +{ + return cpu_is_ixp43x(); +} + +static void +cambria_init(void) +{ + /* Config the serial port. RedBoot should do the rest. */ + ubase = (u_int8_t *)(IXP425_UART0_HWBASE); + + dskinf.cs1to = (u_int32_t *)(IXP425_EXP_HWBASE + EXP_TIMING_CS3_OFFSET); + dskinf.cs2to = (u_int32_t *)(IXP425_EXP_HWBASE + EXP_TIMING_CS4_OFFSET); + dskinf.cs1 = (u_int8_t *)CAMBRIA_CFSEL0_HWBASE; + dskinf.cs2 = (u_int8_t *)CAMBRIA_CFSEL1_HWBASE; + + cf_init(); +} +BOARD_CONFIG(cambria, "Gateworks Cambria"); + +/* + * Pronghorn Metro Support. + */ +static int +pronghorn_probe(int boardtype_hint) +{ + volatile u_int32_t *cs; + /* + * Redboot only configure the chip selects that are needed, so + * use that to figure out if it is an Avila or ADI board. The + * Avila boards use CS2 and ADI does not. + */ + cs = (u_int32_t *)(IXP425_EXP_HWBASE + EXP_TIMING_CS2_OFFSET); + return (*cs == 0); +} + +static void +pronghorn_init(void) +{ + /* Config the serial port. RedBoot should do the rest. */ + ubase = (u_int8_t *)(IXP425_UART1_HWBASE); + + dskinf.cs1to = (u_int32_t *)(IXP425_EXP_HWBASE + EXP_TIMING_CS3_OFFSET); + dskinf.cs2to = (u_int32_t *)(IXP425_EXP_HWBASE + EXP_TIMING_CS4_OFFSET); + dskinf.cs1 = (u_int8_t *)IXP425_EXP_BUS_CS3_HWBASE; + dskinf.cs2 = (u_int8_t *)IXP425_EXP_BUS_CS4_HWBASE; + + cf_init(); +} +BOARD_CONFIG(pronghorn, "Pronghorn Metro"); diff --git a/sys/boot/arm/ixp425/boot2/lib.h b/sys/boot/arm/ixp425/boot2/lib.h index 7b39028556a5..1679e961ce2c 100644 --- a/sys/boot/arm/ixp425/boot2/lib.h +++ b/sys/boot/arm/ixp425/boot2/lib.h @@ -60,5 +60,6 @@ u_int32_t swap32(u_int32_t); const char *board_init(void); void clr_board(void); int avila_read(char*, unsigned, unsigned); +u_int cpu_id(void); #endif /* !ARM_BOOT_LIB_H */ From a965ad6a1ddb2347bc17a33bfec94834d50728ac Mon Sep 17 00:00:00 2001 From: Sam Leffler Date: Sat, 13 Dec 2008 04:51:58 +0000 Subject: [PATCH 4/8] fix comments --- tools/tools/nanobsd/gateworks/G2348 | 2 +- tools/tools/nanobsd/gateworks/G2358 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/tools/nanobsd/gateworks/G2348 b/tools/tools/nanobsd/gateworks/G2348 index 100fddd89a4d..5a57112c0d26 100644 --- a/tools/tools/nanobsd/gateworks/G2348 +++ b/tools/tools/nanobsd/gateworks/G2348 @@ -1,5 +1,5 @@ # -# Gateworks Avila XScale board +# Gateworks Avila IXP425 XScale board # kernel configuration file for FreeBSD/arm # # $FreeBSD$ diff --git a/tools/tools/nanobsd/gateworks/G2358 b/tools/tools/nanobsd/gateworks/G2358 index f48c36104c96..1d46ec5cda4a 100644 --- a/tools/tools/nanobsd/gateworks/G2358 +++ b/tools/tools/nanobsd/gateworks/G2358 @@ -1,5 +1,5 @@ # -# Gateworks Avila XScale board +# Gateworks Cambria IXP435 XScale board # kernel configuration file for FreeBSD/arm # # $FreeBSD$ From 9a6ff5b9514605c144fec16b0078f73e8bd343cf Mon Sep 17 00:00:00 2001 From: Sam Leffler Date: Sat, 13 Dec 2008 04:52:57 +0000 Subject: [PATCH 5/8] move common bits to a shared file --- tools/tools/nanobsd/gateworks/avila | 350 +------------------------- tools/tools/nanobsd/gateworks/cambria | 348 +------------------------ tools/tools/nanobsd/gateworks/common | 347 +++++++++++++++++++++++++ 3 files changed, 350 insertions(+), 695 deletions(-) create mode 100644 tools/tools/nanobsd/gateworks/common diff --git a/tools/tools/nanobsd/gateworks/avila b/tools/tools/nanobsd/gateworks/avila index ff717baccadc..4bfc0df7fa28 100644 --- a/tools/tools/nanobsd/gateworks/avila +++ b/tools/tools/nanobsd/gateworks/avila @@ -1,351 +1,5 @@ -NANO_NAME="gateworks" +NANO_NAME="avila" NANO_SRC="/usr/sam/base/projects/cambria" NANO_KERNEL="G2348" -NANO_CFGDIR=${NANO_SRC}/${NANO_TOOLS}/${NANO_NAME}/cfg -test -d ${NANO_CFGDIR} || NANO_CFGDIR=/var/empty -NANO_PMAKE="make" # NB: disable -j 3 - -NANO_ARCH=arm -TARGET_CPUTYPE=xscale; export TARGET_CPUTYPE # XXX -TARGET_BIG_ENDIAN=true; export TARGET_BIG_ENDIAN # XXX - -NANO_IMAGES=1 -FlashDevice Sandisk 64 - -NANO_CUSTOMIZE="cust_allow_ssh_root" - -clean_usr_local() -{ - LOCAL_DIR=${NANO_WORLDDIR}/usr/local - pprint 2 "Clean and create world directory (${LOCAL_DIR})" - if rm -rf ${LOCAL_DIR}/ > /dev/null 2>&1 ; then - true - else - chflags -R noschg ${LOCAL_DIR}/ - rm -rf ${LOCAL_DIR}/ - fi - for f in bin etc lib libdata libexec sbin share; do - mkdir -p ${LOCAL_DIR}/$f - done -} -NANO_CUSTOMIZE="$NANO_CUSTOMIZE clean_usr_local" - -cust_install_machine_files() -{ - echo "cd ${NANO_TOOLS}/${NANO_NAME}/Files" - cd ${NANO_TOOLS}/${NANO_NAME}/Files - find . -print | grep -Ev '/(CVS|\.svn)' | cpio -dumpv ${NANO_WORLDDIR} -} -NANO_CUSTOMIZE="$NANO_CUSTOMIZE cust_install_files cust_install_machine_files" - -buildenv() -{ - cd ${NANO_SRC} - env TARGET_ARCH=${NANO_ARCH} __MAKE_CONF=${NANO_MAKE_CONF} \ - DESTDIR=${NANO_WORLDDIR} make buildenv -} - -net80211_tools() -{ - for f in wlanstats wlanwds wlanwatch; do - echo "(cd tools/tools/net80211/$f; make $1)"; - done | buildenv -} -net80211_clean_tools() -{ - net80211_tools "clean" -} -net80211_build_tools() -{ - net80211_tools "" -} -net80211_install_tools() -{ - net80211_tools "install" -} -NANO_CUSTOMIZE="$NANO_CUSTOMIZE net80211_clean_tools" -NANO_CUSTOMIZE="$NANO_CUSTOMIZE net80211_build_tools" -NANO_CUSTOMIZE="$NANO_CUSTOMIZE net80211_install_tools" - -ath_clean_tools() -{ - echo "cd tools/tools/ath; make clean" | buildenv -} -ath_build_tools() -{ - echo "cd tools/tools/ath; make" | buildenv -} -ath_install_tools() -{ - echo "cd tools/tools/ath; make install" | buildenv -} -NANO_CUSTOMIZE="$NANO_CUSTOMIZE ath_clean_tools" -NANO_CUSTOMIZE="$NANO_CUSTOMIZE ath_build_tools" -NANO_CUSTOMIZE="$NANO_CUSTOMIZE ath_install_tools" - -NANO_MAKEFS="makefs -B big \ - -o bsize=4096,fsize=512,density=8192,optimization=space" -export NANO_MAKEFS - -# NB: leave c++ enabled so devd can be built -CONF_BUILD=" -WITHOUT_ACPI=true -WITHOUT_ATM=true -WITHOUT_AUDIT=true -WITHOUT_BIND_DNSSEC=true -WITHOUT_BIND_ETC=true -WITHOUT_BIND_LIBS_LWRES=true -WITHOUT_BLUETOOTH=true -WITHOUT_CALENDAR=true -WITHOUT_CDDL=true -WITHOUT_CVS=true -WITHOUT_DICT=true -WITHOUT_EXAMPLES=true -WITHOUT_FORTRAN=true -WITHOUT_GAMES=true -WITHOUT_GCOV=true -WITHOUT_GPIB=true -WITHOUT_HTML=true -WITHOUT_I4B=true -WITHOUT_INET6=true -WITHOUT_INFO=true -WITHOUT_IPFILTER=true -WITHOUT_IPX=true -WITHOUT_KERBEROS=true -WITHOUT_LIBKSE=true -WITHOUT_LOCALES=true -WITHOUT_LPR=true -WITHOUT_MAN=true -WITHOUT_NETCAT=true -WITHOUT_NIS=true -WITHOUT_NLS=true -WITHOUT_NS_CACHING=true -WITHOUT_OBJC=true -WITHOUT_PROFILE=true -WITHOUT_RCMDS=true -WITHOUT_RCS=true -WITHOUT_RESCUE=true -WITHOUT_SENDMAIL=true -WITHOUT_SHAREDOCS=true -WITHOUT_SSP=true -WITHOUT_SYSCONS=true -WITHOUT_TCSH=true -" -CONF_INSTALL="$CONF_BUILD -WITHOUT_TOOLCHAIN=true -WITHOUT_INSTALLLIB=true -" - -# NB: override to suppress install of kernel.symbols -install_kernel() -{ - pprint 2 "install kernel" - pprint 3 "log: ${MAKEOBJDIRPREFIX}/_.ik" - - cd ${NANO_SRC} - env TARGET_ARCH=${NANO_ARCH} ${NANO_PMAKE} installkernel \ - INSTALL_NODEBUG=true \ - DESTDIR=${NANO_WORLDDIR} \ - __MAKE_CONF=${NANO_MAKE_CONF} KERNCONF=`basename ${NANO_KERNEL}` \ - > ${MAKEOBJDIRPREFIX}/_.ik 2>&1 -} - -# NB: override to force / on s1 instead of s1a -setup_nanobsd_etc() -{ - pprint 2 "configure nanobsd /etc" - - ( - cd ${NANO_WORLDDIR} - - # create diskless marker file - touch etc/diskless - - # Make root filesystem R/O by default - echo "root_rw_mount=NO" >> etc/defaults/rc.conf - - # save config file for scripts - echo "NANO_DRIVE=${NANO_DRIVE}" > etc/nanobsd.conf - - echo "/dev/${NANO_DRIVE}s1 / ufs ro 1 1" > etc/fstab - echo "/dev/${NANO_DRIVE}s3 /cfg ufs rw,noauto 2 2" >> etc/fstab - mkdir -p cfg - ) -} - -create_arm_diskimage() -{ - pprint 2 "build diskimage" - pprint 3 "log: ${MAKEOBJDIRPREFIX}/_.di" - - ( - echo "NANO_MEDIASIZE: $NANO_MEDIASIZE" - echo "NANO_IMAGES: $NANO_IMAGES" - echo "NANO_SECTS: $NANO_SECTS" - echo "NANO_HEADS: $NANO_HEADS" - echo "NANO_CODESIZE: $NANO_CODESIZE" - echo "NANO_CONFSIZE: $NANO_CONFSIZE" - echo "NANO_DATASIZE: $NANO_DATASIZE" - - echo $NANO_MEDIASIZE $NANO_IMAGES \ - $NANO_SECTS $NANO_HEADS \ - $NANO_CODESIZE $NANO_CONFSIZE $NANO_DATASIZE | - awk ' - { - printf "# %s\n", $0 - - # size of cylinder in sectors - cs = $3 * $4 - - # number of full cylinders on media - cyl = int ($1 / cs) - - # output fdisk geometry spec, truncate cyls to 1023 - if (cyl <= 1023) - print "g c" cyl " h" $4 " s" $3 - else - print "g c" 1023 " h" $4 " s" $3 - - if ($7 > 0) { - # size of data partition in full cylinders - dsl = int (($7 + cs - 1) / cs) - } else { - dsl = 0; - } - - # size of config partition in full cylinders - csl = int (($6 + cs - 1) / cs) - - if ($5 == 0) { - # size of image partition(s) in full cylinders - isl = int ((cyl - dsl - csl) / $2) - } else { - isl = int (($5 + cs - 1) / cs) - } - - # First image partition start at second track - print "p 1 165 " $3, isl * cs - $3 - c = isl * cs; - - # Second image partition (if any) also starts offset one - # track to keep them identical. - if ($2 > 1) { - print "p 2 165 " $3 + c, isl * cs - $3 - c += isl * cs; - } - - # Config partition starts at cylinder boundary. - print "p 3 165 " c, csl * cs - c += csl * cs - - # Data partition (if any) starts at cylinder boundary. - if ($7 > 0) { - print "p 4 165 " c, dsl * cs - } else if ($7 < 0 && $1 > c) { - print "p 4 165 " c, $1 - c - } else if ($1 < c) { - print "Disk space overcommitted by", \ - c - $1, "sectors" > "/dev/stderr" - exit 2 - } - - # Force slice 1 to be marked active. This is necessary - # for booting the image from a USB device to work. - print "a 1" - } - ' > ${MAKEOBJDIRPREFIX}/_.fdisk - - IMG=${NANO_DISKIMGDIR}/${NANO_IMGNAME} - BS=${NANO_SECTS}b - - if [ "${NANO_MD_BACKING}" = "swap" ] ; then - MD=`mdconfig -a -t swap -s ${NANO_MEDIASIZE} -x ${NANO_SECTS} \ - -y ${NANO_HEADS}` - else - echo ""; echo "Creating md backing file ${IMG} ..." - _c=`expr ${NANO_MEDIASIZE} / ${NANO_SECTS}` - pprint 2 "dd if=/dev/zero of=${IMG} bs=${BS} count=${_c}" - dd if=/dev/zero of=${IMG} bs=${BS} count=${_c} - pprint 2 "mdconfig -a -t vnode -f ${IMG} -x ${NANO_SECTS} -y ${NANO_HEADS}" - MD=`mdconfig -a -t vnode -f ${IMG} -x ${NANO_SECTS} \ - -y ${NANO_HEADS}` - fi - - trap "mdconfig -d -u $MD" 1 2 15 EXIT - - echo ""; echo "Write partition table ..." - FDISK=${MAKEOBJDIRPREFIX}/_.fdisk - pprint 2 "fdisk -i -f ${FDISK} ${MD}" - fdisk -i -f ${FDISK} ${MD} - pprint 2 "fdisk ${MD}" - fdisk ${MD} - - # Create first image - IMG1=${NANO_DISKIMGDIR}/_.disk.image1 - echo ""; echo "Create first image ${IMG1} ..." - SIZE=`awk '/^p 1/ { print $5 "b" }' ${FDISK}` - pprint 2 "${NANO_MAKEFS} -s ${SIZE} ${IMG1} ${NANO_WORLDDIR}" - ${NANO_MAKEFS} -s ${SIZE} ${IMG1} ${NANO_WORLDDIR} - pprint 2 "dd if=${IMG1} of=/dev/${MD}s1 bs=${BS}" - dd if=${IMG1} of=/dev/${MD}s1 bs=${BS} - - if [ $NANO_IMAGES -gt 1 -a $NANO_INIT_IMG2 -gt 0 ] ; then - IMG2=${NANO_DISKIMGDIR}/_.disk.image2 - echo ""; echo "Create second image ${IMG2}..." - for f in ${NANO_WORLDDIR}/etc/fstab ${NANO_WORLDDIR}/conf/base/etc/fstab - do - sed -i "" "s/${NANO_DRIVE}s1/${NANO_DRIVE}s2/g" $f - done - - SIZE=`awk '/^p 2/ { print $5 "b" }' ${FDISK}` - pprint 2 "${NANO_MAKEFS} -s ${SIZE} ${IMG2} ${NANO_WORLDDIR}" - ${NANO_MAKEFS} -s ${SIZE} ${IMG2} ${NANO_WORLDDIR} - pprint 2 "dd if=${IMG2} of=/dev/${MD}s2 bs=${BS}" - dd if=${IMG2} of=/dev/${MD}s2 bs=${BS} - fi - - # Create Config slice - CFG=${NANO_DISKIMGDIR}/_.disk.cfg - echo ""; echo "Creating config partition ${CFG}..." - SIZE=`awk '/^p 3/ { print $5 "b" }' ${FDISK}` - # XXX: fill from where ? - pprint 2 "${NANO_MAKEFS} -s ${SIZE} ${CFG} ${NANO_CFGDIR}" - ${NANO_MAKEFS} -s ${SIZE} ${CFG} ${NANO_CFGDIR} - pprint 2 "dd if=${CFG} of=/dev/${MD}s3 bs=${BS}" - dd if=${CFG} of=/dev/${MD}s3 bs=${BS} - pprint 2 "rm ${CFG}" - rm ${CFG}; CFG= # NB: disable printing below - - # Create Data slice, if any. - if [ $NANO_DATASIZE -gt 0 ] ; then - DATA=${NANO_DISKIMGDIR}/_.disk.data - echo ""; echo "Creating data partition ${DATA}..." - SIZE=`awk '/^p 4/ { print $5 "b" }' ${FDISK}` - # XXX: fill from where ? - pprint 2 "${NANO_MAKEFS} -s ${SIZE} ${DATA} /var/empty" - ${NANO_MAKEFS} -s ${SIZE} ${DATA} /var/empty - pprint 2 "dd if=${DATA} of=/dev/${MD}s4 bs=${BS}" - dd if=${DATA} of=/dev/${MD}s4 bs=${BS} - pprint 2 "rm ${DATA}" - rm ${DATA}; DATA= # NB: disable printing below - fi - - if [ "${NANO_MD_BACKING}" = "swap" ] ; then - echo "Writing out _.disk.full..." - dd if=/dev/${MD} of=${IMG} bs=${BS} - fi - - echo "" - echo "Completed images in:" - echo "" - echo "Full disk: ${IMG}" - echo "Primary partition: ${IMG1}" - test "${IMG2}" && echo "2ndary partition: ${IMG2}" - test "${CFG}" && echo "/cfg partition: ${CFG}" - test "${DATA}" && echo "/data partition: ${DATA}" - echo "" - echo "Use dd if= of=/dev/ bs=${BS} to transfer an" - echo "image to bootable media /dev/." - ) > ${MAKEOBJDIRPREFIX}/_.di 2>&1 -} +. common diff --git a/tools/tools/nanobsd/gateworks/cambria b/tools/tools/nanobsd/gateworks/cambria index 94aba60fb713..63d373590cec 100644 --- a/tools/tools/nanobsd/gateworks/cambria +++ b/tools/tools/nanobsd/gateworks/cambria @@ -2,350 +2,4 @@ NANO_NAME="cambria" NANO_SRC="/usr/sam/base/projects/cambria" NANO_KERNEL="G2358" -NANO_CFGDIR=${NANO_SRC}/${NANO_TOOLS}/gateworks/cfg -test -d ${NANO_CFGDIR} || NANO_CFGDIR=/var/empty -NANO_PMAKE="make" # NB: disable -j 3 - -NANO_ARCH=arm -TARGET_CPUTYPE=xscale; export TARGET_CPUTYPE # XXX -TARGET_BIG_ENDIAN=true; export TARGET_BIG_ENDIAN # XXX - -NANO_IMAGES=1 -FlashDevice Sandisk 64 - -NANO_CUSTOMIZE="cust_allow_ssh_root" - -clean_usr_local() -{ - LOCAL_DIR=${NANO_WORLDDIR}/usr/local - pprint 2 "Clean and create world directory (${LOCAL_DIR})" - if rm -rf ${LOCAL_DIR}/ > /dev/null 2>&1 ; then - true - else - chflags -R noschg ${LOCAL_DIR}/ - rm -rf ${LOCAL_DIR}/ - fi - for f in bin etc lib libdata libexec sbin share; do - mkdir -p ${LOCAL_DIR}/$f - done -} -NANO_CUSTOMIZE="$NANO_CUSTOMIZE clean_usr_local" - -cust_install_machine_files() -{ - echo "cd ${NANO_TOOLS}/gateworks/Files" - cd ${NANO_TOOLS}/gateworks/Files - find . -print | grep -Ev '/(CVS|\.svn)' | cpio -dumpv ${NANO_WORLDDIR} -} -NANO_CUSTOMIZE="$NANO_CUSTOMIZE cust_install_files cust_install_machine_files" - -buildenv() -{ - cd ${NANO_SRC} - env TARGET_ARCH=${NANO_ARCH} __MAKE_CONF=${NANO_MAKE_CONF} \ - DESTDIR=${NANO_WORLDDIR} make buildenv -} - -net80211_tools() -{ - for f in wlanstats wlanwds wlanwatch; do - echo "(cd tools/tools/net80211/$f; make $1)"; - done | buildenv -} -net80211_clean_tools() -{ - net80211_tools "clean" -} -net80211_build_tools() -{ - net80211_tools "" -} -net80211_install_tools() -{ - net80211_tools "install" -} -NANO_CUSTOMIZE="$NANO_CUSTOMIZE net80211_clean_tools" -NANO_CUSTOMIZE="$NANO_CUSTOMIZE net80211_build_tools" -NANO_CUSTOMIZE="$NANO_CUSTOMIZE net80211_install_tools" - -ath_clean_tools() -{ - echo "cd tools/tools/ath; make clean" | buildenv -} -ath_build_tools() -{ - echo "cd tools/tools/ath; make" | buildenv -} -ath_install_tools() -{ - echo "cd tools/tools/ath; make install" | buildenv -} -NANO_CUSTOMIZE="$NANO_CUSTOMIZE ath_clean_tools" -NANO_CUSTOMIZE="$NANO_CUSTOMIZE ath_build_tools" -NANO_CUSTOMIZE="$NANO_CUSTOMIZE ath_install_tools" - -NANO_MAKEFS="makefs -B big \ - -o bsize=4096,fsize=512,density=8192,optimization=space" -export NANO_MAKEFS - -# NB: leave c++ enabled so devd can be built -CONF_BUILD=" -WITHOUT_ACPI=true -WITHOUT_ATM=true -WITHOUT_AUDIT=true -WITHOUT_BIND_DNSSEC=true -WITHOUT_BIND_ETC=true -WITHOUT_BIND_LIBS_LWRES=true -WITHOUT_BLUETOOTH=true -WITHOUT_CALENDAR=true -WITHOUT_CDDL=true -WITHOUT_CVS=true -WITHOUT_DICT=true -WITHOUT_EXAMPLES=true -WITHOUT_FORTRAN=true -WITHOUT_GAMES=true -WITHOUT_GCOV=true -WITHOUT_GPIB=true -WITHOUT_HTML=true -WITHOUT_I4B=true -WITHOUT_INET6=true -WITHOUT_INFO=true -WITHOUT_IPFILTER=true -WITHOUT_IPX=true -WITHOUT_KERBEROS=true -WITHOUT_LIBKSE=true -WITHOUT_LOCALES=true -WITHOUT_LPR=true -WITHOUT_MAN=true -WITHOUT_NETCAT=true -WITHOUT_NIS=true -WITHOUT_NLS=true -WITHOUT_NS_CACHING=true -WITHOUT_OBJC=true -WITHOUT_PROFILE=true -WITHOUT_RCMDS=true -WITHOUT_RCS=true -WITHOUT_RESCUE=true -WITHOUT_SENDMAIL=true -WITHOUT_SHAREDOCS=true -WITHOUT_SSP=true -WITHOUT_SYSCONS=true -WITHOUT_TCSH=true -" -CONF_INSTALL="$CONF_BUILD -WITHOUT_TOOLCHAIN=true -WITHOUT_INSTALLLIB=true -" - -# NB: override to suppress install of kernel.symbols -install_kernel() -{ - pprint 2 "install kernel" - pprint 3 "log: ${MAKEOBJDIRPREFIX}/_.ik" - - cd ${NANO_SRC} - env TARGET_ARCH=${NANO_ARCH} ${NANO_PMAKE} installkernel \ - INSTALL_NODEBUG=true \ - DESTDIR=${NANO_WORLDDIR} \ - __MAKE_CONF=${NANO_MAKE_CONF} KERNCONF=`basename ${NANO_KERNEL}` \ - > ${MAKEOBJDIRPREFIX}/_.ik 2>&1 -} - -# NB: override to force / on s1 instead of s1a -setup_nanobsd_etc() -{ - pprint 2 "configure nanobsd /etc" - - ( - cd ${NANO_WORLDDIR} - - # create diskless marker file - touch etc/diskless - - # Make root filesystem R/O by default - echo "root_rw_mount=NO" >> etc/defaults/rc.conf - - # save config file for scripts - echo "NANO_DRIVE=${NANO_DRIVE}" > etc/nanobsd.conf - - echo "/dev/${NANO_DRIVE}s1 / ufs ro 1 1" > etc/fstab - echo "/dev/${NANO_DRIVE}s3 /cfg ufs rw,noauto 2 2" >> etc/fstab - mkdir -p cfg - ) -} - -create_arm_diskimage() -{ - pprint 2 "build diskimage" - pprint 3 "log: ${MAKEOBJDIRPREFIX}/_.di" - - ( - echo "NANO_MEDIASIZE: $NANO_MEDIASIZE" - echo "NANO_IMAGES: $NANO_IMAGES" - echo "NANO_SECTS: $NANO_SECTS" - echo "NANO_HEADS: $NANO_HEADS" - echo "NANO_CODESIZE: $NANO_CODESIZE" - echo "NANO_CONFSIZE: $NANO_CONFSIZE" - echo "NANO_DATASIZE: $NANO_DATASIZE" - - echo $NANO_MEDIASIZE $NANO_IMAGES \ - $NANO_SECTS $NANO_HEADS \ - $NANO_CODESIZE $NANO_CONFSIZE $NANO_DATASIZE | - awk ' - { - printf "# %s\n", $0 - - # size of cylinder in sectors - cs = $3 * $4 - - # number of full cylinders on media - cyl = int ($1 / cs) - - # output fdisk geometry spec, truncate cyls to 1023 - if (cyl <= 1023) - print "g c" cyl " h" $4 " s" $3 - else - print "g c" 1023 " h" $4 " s" $3 - - if ($7 > 0) { - # size of data partition in full cylinders - dsl = int (($7 + cs - 1) / cs) - } else { - dsl = 0; - } - - # size of config partition in full cylinders - csl = int (($6 + cs - 1) / cs) - - if ($5 == 0) { - # size of image partition(s) in full cylinders - isl = int ((cyl - dsl - csl) / $2) - } else { - isl = int (($5 + cs - 1) / cs) - } - - # First image partition start at second track - print "p 1 165 " $3, isl * cs - $3 - c = isl * cs; - - # Second image partition (if any) also starts offset one - # track to keep them identical. - if ($2 > 1) { - print "p 2 165 " $3 + c, isl * cs - $3 - c += isl * cs; - } - - # Config partition starts at cylinder boundary. - print "p 3 165 " c, csl * cs - c += csl * cs - - # Data partition (if any) starts at cylinder boundary. - if ($7 > 0) { - print "p 4 165 " c, dsl * cs - } else if ($7 < 0 && $1 > c) { - print "p 4 165 " c, $1 - c - } else if ($1 < c) { - print "Disk space overcommitted by", \ - c - $1, "sectors" > "/dev/stderr" - exit 2 - } - - # Force slice 1 to be marked active. This is necessary - # for booting the image from a USB device to work. - print "a 1" - } - ' > ${MAKEOBJDIRPREFIX}/_.fdisk - - IMG=${NANO_DISKIMGDIR}/${NANO_IMGNAME} - BS=${NANO_SECTS}b - - if [ "${NANO_MD_BACKING}" = "swap" ] ; then - MD=`mdconfig -a -t swap -s ${NANO_MEDIASIZE} -x ${NANO_SECTS} \ - -y ${NANO_HEADS}` - else - echo ""; echo "Creating md backing file ${IMG} ..." - _c=`expr ${NANO_MEDIASIZE} / ${NANO_SECTS}` - pprint 2 "dd if=/dev/zero of=${IMG} bs=${BS} count=${_c}" - dd if=/dev/zero of=${IMG} bs=${BS} count=${_c} - pprint 2 "mdconfig -a -t vnode -f ${IMG} -x ${NANO_SECTS} -y ${NANO_HEADS}" - MD=`mdconfig -a -t vnode -f ${IMG} -x ${NANO_SECTS} \ - -y ${NANO_HEADS}` - fi - - trap "mdconfig -d -u $MD" 1 2 15 EXIT - - echo ""; echo "Write partition table ..." - FDISK=${MAKEOBJDIRPREFIX}/_.fdisk - pprint 2 "fdisk -i -f ${FDISK} ${MD}" - fdisk -i -f ${FDISK} ${MD} - pprint 2 "fdisk ${MD}" - fdisk ${MD} - - # Create first image - IMG1=${NANO_DISKIMGDIR}/_.disk.image1 - echo ""; echo "Create first image ${IMG1} ..." - SIZE=`awk '/^p 1/ { print $5 "b" }' ${FDISK}` - pprint 2 "${NANO_MAKEFS} -s ${SIZE} ${IMG1} ${NANO_WORLDDIR}" - ${NANO_MAKEFS} -s ${SIZE} ${IMG1} ${NANO_WORLDDIR} - pprint 2 "dd if=${IMG1} of=/dev/${MD}s1 bs=${BS}" - dd if=${IMG1} of=/dev/${MD}s1 bs=${BS} - - if [ $NANO_IMAGES -gt 1 -a $NANO_INIT_IMG2 -gt 0 ] ; then - IMG2=${NANO_DISKIMGDIR}/_.disk.image2 - echo ""; echo "Create second image ${IMG2}..." - for f in ${NANO_WORLDDIR}/etc/fstab ${NANO_WORLDDIR}/conf/base/etc/fstab - do - sed -i "" "s/${NANO_DRIVE}s1/${NANO_DRIVE}s2/g" $f - done - - SIZE=`awk '/^p 2/ { print $5 "b" }' ${FDISK}` - pprint 2 "${NANO_MAKEFS} -s ${SIZE} ${IMG2} ${NANO_WORLDDIR}" - ${NANO_MAKEFS} -s ${SIZE} ${IMG2} ${NANO_WORLDDIR} - pprint 2 "dd if=${IMG2} of=/dev/${MD}s2 bs=${BS}" - dd if=${IMG2} of=/dev/${MD}s2 bs=${BS} - fi - - # Create Config slice - CFG=${NANO_DISKIMGDIR}/_.disk.cfg - echo ""; echo "Creating config partition ${CFG}..." - SIZE=`awk '/^p 3/ { print $5 "b" }' ${FDISK}` - # XXX: fill from where ? - pprint 2 "${NANO_MAKEFS} -s ${SIZE} ${CFG} ${NANO_CFGDIR}" - ${NANO_MAKEFS} -s ${SIZE} ${CFG} ${NANO_CFGDIR} - pprint 2 "dd if=${CFG} of=/dev/${MD}s3 bs=${BS}" - dd if=${CFG} of=/dev/${MD}s3 bs=${BS} - pprint 2 "rm ${CFG}" - rm ${CFG}; CFG= # NB: disable printing below - - # Create Data slice, if any. - if [ $NANO_DATASIZE -gt 0 ] ; then - DATA=${NANO_DISKIMGDIR}/_.disk.data - echo ""; echo "Creating data partition ${DATA}..." - SIZE=`awk '/^p 4/ { print $5 "b" }' ${FDISK}` - # XXX: fill from where ? - pprint 2 "${NANO_MAKEFS} -s ${SIZE} ${DATA} /var/empty" - ${NANO_MAKEFS} -s ${SIZE} ${DATA} /var/empty - pprint 2 "dd if=${DATA} of=/dev/${MD}s4 bs=${BS}" - dd if=${DATA} of=/dev/${MD}s4 bs=${BS} - pprint 2 "rm ${DATA}" - rm ${DATA}; DATA= # NB: disable printing below - fi - - if [ "${NANO_MD_BACKING}" = "swap" ] ; then - echo "Writing out _.disk.full..." - dd if=/dev/${MD} of=${IMG} bs=${BS} - fi - - echo "" - echo "Completed images in:" - echo "" - echo "Full disk: ${IMG}" - echo "Primary partition: ${IMG1}" - test "${IMG2}" && echo "2ndary partition: ${IMG2}" - test "${CFG}" && echo "/cfg partition: ${CFG}" - test "${DATA}" && echo "/data partition: ${DATA}" - echo "" - echo "Use dd if= of=/dev/ bs=${BS} to transfer an" - echo "image to bootable media /dev/." - ) > ${MAKEOBJDIRPREFIX}/_.di 2>&1 -} +. common diff --git a/tools/tools/nanobsd/gateworks/common b/tools/tools/nanobsd/gateworks/common new file mode 100644 index 000000000000..76027911696e --- /dev/null +++ b/tools/tools/nanobsd/gateworks/common @@ -0,0 +1,347 @@ +NANO_CFGDIR=${NANO_SRC}/${NANO_TOOLS}/gateworks/cfg +test -d ${NANO_CFGDIR} || NANO_CFGDIR=/var/empty +NANO_PMAKE="make" # NB: disable -j 3 + +NANO_ARCH=arm +TARGET_CPUTYPE=xscale; export TARGET_CPUTYPE # XXX +TARGET_BIG_ENDIAN=true; export TARGET_BIG_ENDIAN # XXX + +NANO_IMAGES=1 +FlashDevice Sandisk 64 + +NANO_CUSTOMIZE="cust_allow_ssh_root" + +clean_usr_local() +{ + LOCAL_DIR=${NANO_WORLDDIR}/usr/local + pprint 2 "Clean and create world directory (${LOCAL_DIR})" + if rm -rf ${LOCAL_DIR}/ > /dev/null 2>&1 ; then + true + else + chflags -R noschg ${LOCAL_DIR}/ + rm -rf ${LOCAL_DIR}/ + fi + for f in bin etc lib libdata libexec sbin share; do + mkdir -p ${LOCAL_DIR}/$f + done +} +NANO_CUSTOMIZE="$NANO_CUSTOMIZE clean_usr_local" + +cust_install_machine_files() +{ + echo "cd ${NANO_TOOLS}/gateworks/Files" + cd ${NANO_TOOLS}/gateworks/Files + find . -print | grep -Ev '/(CVS|\.svn)' | cpio -dumpv ${NANO_WORLDDIR} +} +NANO_CUSTOMIZE="$NANO_CUSTOMIZE cust_install_files cust_install_machine_files" + +buildenv() +{ + cd ${NANO_SRC} + env TARGET_ARCH=${NANO_ARCH} __MAKE_CONF=${NANO_MAKE_CONF} \ + DESTDIR=${NANO_WORLDDIR} make buildenv +} + +net80211_tools() +{ + for f in wlanstats wlanwds wlanwatch; do + echo "(cd tools/tools/net80211/$f; make $1)"; + done | buildenv +} +net80211_clean_tools() +{ + net80211_tools "clean" +} +net80211_build_tools() +{ + net80211_tools "" +} +net80211_install_tools() +{ + net80211_tools "install" +} +NANO_CUSTOMIZE="$NANO_CUSTOMIZE net80211_clean_tools" +NANO_CUSTOMIZE="$NANO_CUSTOMIZE net80211_build_tools" +NANO_CUSTOMIZE="$NANO_CUSTOMIZE net80211_install_tools" + +ath_clean_tools() +{ + echo "cd tools/tools/ath; make clean" | buildenv +} +ath_build_tools() +{ + echo "cd tools/tools/ath; make" | buildenv +} +ath_install_tools() +{ + echo "cd tools/tools/ath; make install" | buildenv +} +NANO_CUSTOMIZE="$NANO_CUSTOMIZE ath_clean_tools" +NANO_CUSTOMIZE="$NANO_CUSTOMIZE ath_build_tools" +NANO_CUSTOMIZE="$NANO_CUSTOMIZE ath_install_tools" + +NANO_MAKEFS="makefs -B big \ + -o bsize=4096,fsize=512,density=8192,optimization=space" +export NANO_MAKEFS + +# NB: leave c++ enabled so devd can be built +CONF_BUILD=" +WITHOUT_ACPI=true +WITHOUT_ATM=true +WITHOUT_AUDIT=true +WITHOUT_BIND_DNSSEC=true +WITHOUT_BIND_ETC=true +WITHOUT_BIND_LIBS_LWRES=true +WITHOUT_BLUETOOTH=true +WITHOUT_CALENDAR=true +WITHOUT_CDDL=true +WITHOUT_CVS=true +WITHOUT_DICT=true +WITHOUT_EXAMPLES=true +WITHOUT_FORTRAN=true +WITHOUT_GAMES=true +WITHOUT_GCOV=true +WITHOUT_GPIB=true +WITHOUT_HTML=true +WITHOUT_I4B=true +WITHOUT_INET6=true +WITHOUT_INFO=true +WITHOUT_IPFILTER=true +WITHOUT_IPX=true +WITHOUT_KERBEROS=true +WITHOUT_LIBKSE=true +WITHOUT_LOCALES=true +WITHOUT_LPR=true +WITHOUT_MAN=true +WITHOUT_NETCAT=true +WITHOUT_NIS=true +WITHOUT_NLS=true +WITHOUT_NS_CACHING=true +WITHOUT_OBJC=true +WITHOUT_PROFILE=true +WITHOUT_RCMDS=true +WITHOUT_RCS=true +WITHOUT_RESCUE=true +WITHOUT_SENDMAIL=true +WITHOUT_SHAREDOCS=true +WITHOUT_SSP=true +WITHOUT_SYSCONS=true +WITHOUT_TCSH=true +" +CONF_INSTALL="$CONF_BUILD +WITHOUT_TOOLCHAIN=true +WITHOUT_INSTALLLIB=true +" + +# NB: override to suppress install of kernel.symbols +install_kernel() +{ + pprint 2 "install kernel" + pprint 3 "log: ${MAKEOBJDIRPREFIX}/_.ik" + + cd ${NANO_SRC} + env TARGET_ARCH=${NANO_ARCH} ${NANO_PMAKE} installkernel \ + INSTALL_NODEBUG=true \ + DESTDIR=${NANO_WORLDDIR} \ + __MAKE_CONF=${NANO_MAKE_CONF} KERNCONF=`basename ${NANO_KERNEL}` \ + > ${MAKEOBJDIRPREFIX}/_.ik 2>&1 +} + +# NB: override to force / on s1 instead of s1a +setup_nanobsd_etc() +{ + pprint 2 "configure nanobsd /etc" + + ( + cd ${NANO_WORLDDIR} + + # create diskless marker file + touch etc/diskless + + # Make root filesystem R/O by default + echo "root_rw_mount=NO" >> etc/defaults/rc.conf + + # save config file for scripts + echo "NANO_DRIVE=${NANO_DRIVE}" > etc/nanobsd.conf + + echo "/dev/${NANO_DRIVE}s1 / ufs ro 1 1" > etc/fstab + echo "/dev/${NANO_DRIVE}s3 /cfg ufs rw,noauto 2 2" >> etc/fstab + mkdir -p cfg + ) +} + +create_arm_diskimage() +{ + pprint 2 "build diskimage" + pprint 3 "log: ${MAKEOBJDIRPREFIX}/_.di" + + ( + echo "NANO_MEDIASIZE: $NANO_MEDIASIZE" + echo "NANO_IMAGES: $NANO_IMAGES" + echo "NANO_SECTS: $NANO_SECTS" + echo "NANO_HEADS: $NANO_HEADS" + echo "NANO_CODESIZE: $NANO_CODESIZE" + echo "NANO_CONFSIZE: $NANO_CONFSIZE" + echo "NANO_DATASIZE: $NANO_DATASIZE" + + echo $NANO_MEDIASIZE $NANO_IMAGES \ + $NANO_SECTS $NANO_HEADS \ + $NANO_CODESIZE $NANO_CONFSIZE $NANO_DATASIZE | + awk ' + { + printf "# %s\n", $0 + + # size of cylinder in sectors + cs = $3 * $4 + + # number of full cylinders on media + cyl = int ($1 / cs) + + # output fdisk geometry spec, truncate cyls to 1023 + if (cyl <= 1023) + print "g c" cyl " h" $4 " s" $3 + else + print "g c" 1023 " h" $4 " s" $3 + + if ($7 > 0) { + # size of data partition in full cylinders + dsl = int (($7 + cs - 1) / cs) + } else { + dsl = 0; + } + + # size of config partition in full cylinders + csl = int (($6 + cs - 1) / cs) + + if ($5 == 0) { + # size of image partition(s) in full cylinders + isl = int ((cyl - dsl - csl) / $2) + } else { + isl = int (($5 + cs - 1) / cs) + } + + # First image partition start at second track + print "p 1 165 " $3, isl * cs - $3 + c = isl * cs; + + # Second image partition (if any) also starts offset one + # track to keep them identical. + if ($2 > 1) { + print "p 2 165 " $3 + c, isl * cs - $3 + c += isl * cs; + } + + # Config partition starts at cylinder boundary. + print "p 3 165 " c, csl * cs + c += csl * cs + + # Data partition (if any) starts at cylinder boundary. + if ($7 > 0) { + print "p 4 165 " c, dsl * cs + } else if ($7 < 0 && $1 > c) { + print "p 4 165 " c, $1 - c + } else if ($1 < c) { + print "Disk space overcommitted by", \ + c - $1, "sectors" > "/dev/stderr" + exit 2 + } + + # Force slice 1 to be marked active. This is necessary + # for booting the image from a USB device to work. + print "a 1" + } + ' > ${MAKEOBJDIRPREFIX}/_.fdisk + + IMG=${NANO_DISKIMGDIR}/${NANO_IMGNAME} + BS=${NANO_SECTS}b + + if [ "${NANO_MD_BACKING}" = "swap" ] ; then + MD=`mdconfig -a -t swap -s ${NANO_MEDIASIZE} -x ${NANO_SECTS} \ + -y ${NANO_HEADS}` + else + echo ""; echo "Creating md backing file ${IMG} ..." + _c=`expr ${NANO_MEDIASIZE} / ${NANO_SECTS}` + pprint 2 "dd if=/dev/zero of=${IMG} bs=${BS} count=${_c}" + dd if=/dev/zero of=${IMG} bs=${BS} count=${_c} + pprint 2 "mdconfig -a -t vnode -f ${IMG} -x ${NANO_SECTS} -y ${NANO_HEADS}" + MD=`mdconfig -a -t vnode -f ${IMG} -x ${NANO_SECTS} \ + -y ${NANO_HEADS}` + fi + + trap "mdconfig -d -u $MD" 1 2 15 EXIT + + echo ""; echo "Write partition table ..." + FDISK=${MAKEOBJDIRPREFIX}/_.fdisk + pprint 2 "fdisk -i -f ${FDISK} ${MD}" + fdisk -i -f ${FDISK} ${MD} + pprint 2 "fdisk ${MD}" + fdisk ${MD} + + # Create first image + IMG1=${NANO_DISKIMGDIR}/_.disk.image1 + echo ""; echo "Create first image ${IMG1} ..." + SIZE=`awk '/^p 1/ { print $5 "b" }' ${FDISK}` + pprint 2 "${NANO_MAKEFS} -s ${SIZE} ${IMG1} ${NANO_WORLDDIR}" + ${NANO_MAKEFS} -s ${SIZE} ${IMG1} ${NANO_WORLDDIR} + pprint 2 "dd if=${IMG1} of=/dev/${MD}s1 bs=${BS}" + dd if=${IMG1} of=/dev/${MD}s1 bs=${BS} + + if [ $NANO_IMAGES -gt 1 -a $NANO_INIT_IMG2 -gt 0 ] ; then + IMG2=${NANO_DISKIMGDIR}/_.disk.image2 + echo ""; echo "Create second image ${IMG2}..." + for f in ${NANO_WORLDDIR}/etc/fstab ${NANO_WORLDDIR}/conf/base/etc/fstab + do + sed -i "" "s/${NANO_DRIVE}s1/${NANO_DRIVE}s2/g" $f + done + + SIZE=`awk '/^p 2/ { print $5 "b" }' ${FDISK}` + pprint 2 "${NANO_MAKEFS} -s ${SIZE} ${IMG2} ${NANO_WORLDDIR}" + ${NANO_MAKEFS} -s ${SIZE} ${IMG2} ${NANO_WORLDDIR} + pprint 2 "dd if=${IMG2} of=/dev/${MD}s2 bs=${BS}" + dd if=${IMG2} of=/dev/${MD}s2 bs=${BS} + fi + + # Create Config slice + CFG=${NANO_DISKIMGDIR}/_.disk.cfg + echo ""; echo "Creating config partition ${CFG}..." + SIZE=`awk '/^p 3/ { print $5 "b" }' ${FDISK}` + # XXX: fill from where ? + pprint 2 "${NANO_MAKEFS} -s ${SIZE} ${CFG} ${NANO_CFGDIR}" + ${NANO_MAKEFS} -s ${SIZE} ${CFG} ${NANO_CFGDIR} + pprint 2 "dd if=${CFG} of=/dev/${MD}s3 bs=${BS}" + dd if=${CFG} of=/dev/${MD}s3 bs=${BS} + pprint 2 "rm ${CFG}" + rm ${CFG}; CFG= # NB: disable printing below + + # Create Data slice, if any. + if [ $NANO_DATASIZE -gt 0 ] ; then + DATA=${NANO_DISKIMGDIR}/_.disk.data + echo ""; echo "Creating data partition ${DATA}..." + SIZE=`awk '/^p 4/ { print $5 "b" }' ${FDISK}` + # XXX: fill from where ? + pprint 2 "${NANO_MAKEFS} -s ${SIZE} ${DATA} /var/empty" + ${NANO_MAKEFS} -s ${SIZE} ${DATA} /var/empty + pprint 2 "dd if=${DATA} of=/dev/${MD}s4 bs=${BS}" + dd if=${DATA} of=/dev/${MD}s4 bs=${BS} + pprint 2 "rm ${DATA}" + rm ${DATA}; DATA= # NB: disable printing below + fi + + if [ "${NANO_MD_BACKING}" = "swap" ] ; then + echo "Writing out _.disk.full..." + dd if=/dev/${MD} of=${IMG} bs=${BS} + fi + + echo "" + echo "Completed images in:" + echo "" + echo "Full disk: ${IMG}" + echo "Primary partition: ${IMG1}" + test "${IMG2}" && echo "2ndary partition: ${IMG2}" + test "${CFG}" && echo "/cfg partition: ${CFG}" + test "${DATA}" && echo "/data partition: ${DATA}" + echo "" + echo "Use dd if= of=/dev/ bs=${BS} to transfer an" + echo "image to bootable media /dev/." + ) > ${MAKEOBJDIRPREFIX}/_.di 2>&1 +} From b4e11e4f1a67da12de368ad0d5c5d655833d4d7e Mon Sep 17 00:00:00 2001 From: Sam Leffler Date: Wed, 17 Dec 2008 00:53:59 +0000 Subject: [PATCH 6/8] seems I never committed these --- sys/arm/conf/CAMBRIA | 149 +++++++++++++++++++++++++++++++++++++ sys/arm/conf/CAMBRIA.hints | 54 ++++++++++++++ 2 files changed, 203 insertions(+) create mode 100644 sys/arm/conf/CAMBRIA create mode 100644 sys/arm/conf/CAMBRIA.hints diff --git a/sys/arm/conf/CAMBRIA b/sys/arm/conf/CAMBRIA new file mode 100644 index 000000000000..d131f3629368 --- /dev/null +++ b/sys/arm/conf/CAMBRIA @@ -0,0 +1,149 @@ +# CAMBRIA -- Gateworks Cambria 235x boards +# kernel configuration file for FreeBSD/arm +# +# For more information on this file, please read the handbook section on +# Kernel Configuration Files: +# +# http://www.FreeBSD.org/doc/en_US.ISO8859-1/books/handbook/kernelconfig-config.html +# +# The handbook is also available locally in /usr/share/doc/handbook +# if you've installed the doc distribution, otherwise always see the +# FreeBSD World Wide Web server (http://www.FreeBSD.org/) for the +# latest information. +# +# An exhaustive list of options and more detailed explanations of the +# device lines is also present in the ../../conf/NOTES and NOTES files. +# If you are in doubt as to the purpose or necessity of a line, check first +# in NOTES. +# +# $FreeBSD$ + +machine arm +ident CAMBRIA + +include "../xscale/ixp425/std.ixp435" +# 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 "CAMBRIA.hints" # Default places to look for devices. + +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 + +# Debugging for use in -current +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 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 PREEMPTION +options INET #InterNETworking +options FFS #Berkeley Fast Filesystem +options SOFTUPDATES #Enable FFS soft updates support +options NFSCLIENT #Network Filesystem Client +options NFS_ROOT #NFS usable as /, requires NFSCLIENT +options BOOTP +options BOOTP_NFSROOT +options BOOTP_NFSV3 +options BOOTP_WIRED_TO=npe0 +options BOOTP_COMPAT + +#options VERBOSE_SYSINIT +options VERBOSE_INIT_ARM + +#device saarm + +device pci +device uart + +# I2C Bus +device iicbus +device iicbb +device iic + +device ixpiic # I2C bus glue +device ixpwdog # watchdog timer +device ds1672 # DS1672 on I2C bus +device ad7418 # AD7418 on I2C bus + +device cambria_fled # Font Panel LED on I2C bus +device cambria_led # 8-LED latch + +device ata +device atadisk # ATA disk drives +device avila_ata # Gateworks CF/IDE support + +device npe # Network Processing Engine +device npe_fw +device firmware +device qmgr # Q Manager (required by npe) +device miibus # NB: required by npe +device ether +device bpf + +device pty +device loop +device if_bridge + +device md +device random # Entropy device + +# NB: 2 USB 2.0 ports standard +device usb +options USB_DEBUG +device ohci +device ehci +device ugen +device umass +device scbus # SCSI bus (required for SCSI) +device da # Direct Access (disks) + +# 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 +options ATH_DEBUG +options ATH_DIAGAPI +#options ATH_TX99_DIAG +device ath_rate_sample # SampleRate tx rate control for ath + +options AH_DEBUG +#options AH_ASSERT +options AH_PRIVATE_DIAG +#device ath_ar5210 +#device ath_ar5211 +# +device ath_ar5212 +#device ath_rf2413 +#device ath_rf2425 # NB:supports 2417 too +#device ath_rf5111 +device ath_rf5112 +device ath_rf5413 +# +#device ath_ar5416 +#options AH_SUPPORT_AR5416 # NB: for 11n descriptor format +#device ath_rf2133 +#device ath_ar9160 +#device ath_ar9280 +#device ath_rf9280 +#device ath_ar9285 + +device ural +device zyd +device wlan_amrr diff --git a/sys/arm/conf/CAMBRIA.hints b/sys/arm/conf/CAMBRIA.hints new file mode 100644 index 000000000000..208029f6fe54 --- /dev/null +++ b/sys/arm/conf/CAMBRIA.hints @@ -0,0 +1,54 @@ +# $FreeBSD$ + +# +# Device wiring for the Gateworks Cambria 2358. +# + +# DBGU is unit 0 +hint.uart.0.at="ixp0" +hint.uart.0.addr=0xc8000000 +hint.uart.0.irq=15 +hint.uart.0.flags=0x10 + +# NB: no UART1 on ixp436 + +# NPE Hardware Queue Manager +hint.ixpqmgr.0.at="ixp0" + +# NPE wired NIC's, requires ixpqmgr +hint.npe.0.at="ixp0" +hint.npe.0.npeid="C" +hint.npe.0.mac="C" +hint.npe.0.mii="C" +hint.npe.0.phy=1 +#hint.npe.1.at="ixp0" +#hint.npe.1.npeid="A" +#hint.npe.1.mac="A" +#hint.npe.1.mii="C" +#hint.npe.1.phy=2 + +# CF IDE controller +hint.ata_avila.0.at="ixp0" + +# Front Panel LED +hint.fled.0.at="iicbus0" +hint.fled.0.addr=0x5a + +# Octal LED Latch +hint.led_cambria.0.at="ixp0" + +# Analog Devices AD7418 temperature sensor +hint.ad7418.0.at="iicbus0" +hint.ad7418.0.addr=0x50 + +# Dallas Semiconductor DS1672 RTC +hint.ds1672.0.at="iicbus0" +hint.ds1672.0.addr=0xd0 + +# USB is part of the chip +hint.ehci.0.at="ixp0" +hint.ehci.0.addr=0xcd000000 +hint.ehci.0.irq=32 +hint.ehci.1.at="ixp0" +hint.ehci.1.addr=0xce000000 +hint.ehci.1.irq=33 From 656c23db6e0c4cef99dcee9f38b160f6168c95bd Mon Sep 17 00:00:00 2001 From: Sam Leffler Date: Fri, 19 Dec 2008 00:56:47 +0000 Subject: [PATCH 7/8] add delays around 16-bit enable/disable a la the driver; w/o this operation on my ixp435 Cambria board is unreliable --- sys/boot/arm/ixp425/boot2/ixp425_board.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sys/boot/arm/ixp425/boot2/ixp425_board.c b/sys/boot/arm/ixp425/boot2/ixp425_board.c index 5c8d54cfc4c7..50e317db9bdd 100644 --- a/sys/boot/arm/ixp425/boot2/ixp425_board.c +++ b/sys/boot/arm/ixp425/boot2/ixp425_board.c @@ -330,6 +330,7 @@ cfenable16(void) val = *dskinf.cs1to; *dskinf.cs1to = val &~ EXP_BYTE_EN; + DELAY(100); #if 0 DPRINTF("%s: cs1 timing reg %x\n", *dskinf.cs1to, __func__); #endif @@ -340,6 +341,7 @@ cfdisable16(void) { u_int32_t val; + DELAY(100); val = *dskinf.cs1to; *dskinf.cs1to = val | EXP_BYTE_EN; #if 0 From 768a45fb1b7e10160bb9130cb1391df7123b3e07 Mon Sep 17 00:00:00 2001 From: Sam Leffler Date: Sat, 20 Dec 2008 01:11:10 +0000 Subject: [PATCH 8/8] move cf size to target config files --- tools/tools/nanobsd/gateworks/avila | 3 +++ tools/tools/nanobsd/gateworks/cambria | 3 +++ tools/tools/nanobsd/gateworks/common | 3 --- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/tools/tools/nanobsd/gateworks/avila b/tools/tools/nanobsd/gateworks/avila index 4bfc0df7fa28..5d730ae24154 100644 --- a/tools/tools/nanobsd/gateworks/avila +++ b/tools/tools/nanobsd/gateworks/avila @@ -2,4 +2,7 @@ NANO_NAME="avila" NANO_SRC="/usr/sam/base/projects/cambria" NANO_KERNEL="G2348" +NANO_IMAGES=1 +FlashDevice Sandisk 64M + . common diff --git a/tools/tools/nanobsd/gateworks/cambria b/tools/tools/nanobsd/gateworks/cambria index 63d373590cec..85e14c456b87 100644 --- a/tools/tools/nanobsd/gateworks/cambria +++ b/tools/tools/nanobsd/gateworks/cambria @@ -2,4 +2,7 @@ NANO_NAME="cambria" NANO_SRC="/usr/sam/base/projects/cambria" NANO_KERNEL="G2358" +NANO_IMAGES=2 +FlashDevice Sandisk 64M + . common diff --git a/tools/tools/nanobsd/gateworks/common b/tools/tools/nanobsd/gateworks/common index 76027911696e..e1841209acef 100644 --- a/tools/tools/nanobsd/gateworks/common +++ b/tools/tools/nanobsd/gateworks/common @@ -6,9 +6,6 @@ NANO_ARCH=arm TARGET_CPUTYPE=xscale; export TARGET_CPUTYPE # XXX TARGET_BIG_ENDIAN=true; export TARGET_BIG_ENDIAN # XXX -NANO_IMAGES=1 -FlashDevice Sandisk 64 - NANO_CUSTOMIZE="cust_allow_ssh_root" clean_usr_local()