diff options
Diffstat (limited to 'sys')
39 files changed, 3601 insertions, 2311 deletions
diff --git a/sys/arm/arm/cpufunc.c b/sys/arm/arm/cpufunc.c index 6317769..df4f067 100644 --- a/sys/arm/arm/cpufunc.c +++ b/sys/arm/arm/cpufunc.c @@ -1211,7 +1211,7 @@ set_cpufuncs() #endif /* CPU_XSCALE_PXA2X0 */ #ifdef CPU_XSCALE_IXP425 if (cputype == CPU_ID_IXP425_533 || cputype == CPU_ID_IXP425_400 || - cputype == CPU_ID_IXP425_266) { + cputype == CPU_ID_IXP425_266 || cputype == CPU_ID_IXP435) { cpufuncs = xscale_cpufuncs; #if defined(PERFCTRS) diff --git a/sys/arm/arm/identcpu.c b/sys/arm/arm/identcpu.c index c8013b7..df67a8a 100644 --- a/sys/arm/arm/identcpu.c +++ b/sys/arm/arm/identcpu.c @@ -300,6 +300,10 @@ const struct cpuidtab cpuids[] = { { CPU_ID_IXP425_266, CPU_CLASS_XSCALE, "IXP425 266MHz", ixp425_steppings }, + /* XXX ixp435 steppings? */ + { CPU_ID_IXP435, CPU_CLASS_XSCALE, "IXP435", + ixp425_steppings }, + { CPU_ID_ARM1136JS, CPU_CLASS_ARM11J, "ARM1136J-S", generic_steppings }, { CPU_ID_ARM1136JSR1, CPU_CLASS_ARM11J, "ARM1136J-S R1", diff --git a/sys/arm/conf/AVILA b/sys/arm/conf/AVILA index 92bbed1..f727071 100644 --- a/sys/arm/conf/AVILA +++ b/sys/arm/conf/AVILA @@ -20,20 +20,18 @@ ident AVILA -options PHYSADDR=0x10000000 -options KERNPHYSADDR=0x10200000 -options KERNVIRTADDR=0xc0200000 # Used in ldscript.arm -options FLASHADDR=0x50000000 -options LOADERRAMADDR=0x00000000 -options STARTUP_PAGETABLE_ADDR=0x10000000 - +include "../xscale/ixp425/std.ixp425" +# NB: memory mapping is defined in std.avila include "../xscale/ixp425/std.avila" +options XSCALE_CACHE_READ_WRITE_ALLOCATE +#options ARM_USE_SMALL_ALLOC #To statically compile in device wiring instead of /boot/device.hints hints "AVILA.hints" #Default places to look for devices. makeoptions MODULES_OVERRIDE="" makeoptions DEBUG=-g #Build kernel with gdb(1) debug symbols makeoptions CONF_CFLAGS=-mcpu=xscale +makeoptions MODULES_OVERRIDE="" #options HZ=1000 options HZ=100 options DEVICE_POLLING @@ -42,34 +40,18 @@ options DEVICE_POLLING options KDB #options GDB options DDB #Enable the kernel debugger -#options INVARIANTS #Enable calls of extra sanity checking -#options INVARIANT_SUPPORT #Extra sanity checks of internal structures, required by INVARIANTS +options INVARIANTS #Enable calls of extra sanity checking +options INVARIANT_SUPPORT #Extra sanity checks of internal structures, required by INVARIANTS #options WITNESS #Enable checks to detect deadlocks and cycles #options WITNESS_SKIPSPIN #Don't run witness on spinlocks for speed #options DIAGNOSTIC options SCHED_4BSD #4BSD scheduler options INET #InterNETworking -options INET6 #IPv6 communications protocols options FFS #Berkeley Fast Filesystem options SOFTUPDATES #Enable FFS soft updates support -options UFS_ACL #Support for access control lists -options UFS_DIRHASH #Improve performance on big directories options NFSCLIENT #Network Filesystem Client -options NFSSERVER #Network Filesystem Server -options NFSLOCKD #Network Lock Manager options NFS_ROOT #NFS usable as /, requires NFSCLIENT -#options MSDOSFS #MSDOS Filesystem -options CD9660 #ISO 9660 Filesystem -#options PROCFS #Process filesystem (requires PSEUDOFS) -options PSEUDOFS #Pseudo-filesystem framework -options SCSI_DELAY=5000 #Delay (in ms) before probing SCSI -options KTRACE #ktrace(1) support -options SYSVSHM #SYSV-style shared memory -options SYSVMSG #SYSV-style message queues -options SYSVSEM #SYSV-style semaphores -options _KPOSIX_PRIORITY_SCHEDULING #Posix P1003_1B real-time extensions -options KBD_INSTALL_CDEV # install a CDEV entry in /dev options BOOTP options BOOTP_NFSROOT options BOOTP_NFSV3 @@ -106,7 +88,6 @@ device npe_fw device firmware device qmgr # Q Manager (required by npe) device miibus # NB: required by npe -device rl # RealTek 8129/8139 device ether device bpf @@ -114,37 +95,48 @@ device pty device loop device if_bridge -options XSCALE_CACHE_READ_WRITE_ALLOCATE device md device random # Entropy device -#options ARM_USE_SMALL_ALLOC - # Wireless NIC cards device wlan # 802.11 support +options IEEE80211_DEBUG device wlan_wep # 802.11 WEP support device wlan_ccmp # 802.11 CCMP support device wlan_tkip # 802.11 TKIP support device wlan_xauth + device ath # Atheros pci/cardbus NIC's -device ath_hal # Atheros HAL (Hardware Access Layer) -options AH_SUPPORT_AR5416 # enable AR5416 tx/rx descriptors -device ath_rate_sample # SampleRate tx rate control for ath options ATH_DEBUG +options ATH_DIAGAPI +#options ATH_TX99_DIAG +device ath_rate_sample # SampleRate tx rate control for ath -#device crypto -#device cryptodev -#device hifn # NB: Soekris minipci card known to work +#options AH_DEBUG +#options AH_ASSERT +#device ath_ar5210 +#device ath_ar5211 +device ath_ar5212 +device ath_rf2413 +device ath_rf2417 +device ath_rf2425 +device ath_rf5111 +device ath_rf5112 +device ath_rf5413 +# +device ath_ar5416 +options AH_SUPPORT_AR5416 +device ath_ar9160 device usb -options USB_DEBUG +#options USB_DEBUG device ohci device ehci device ugen -device umass -device scbus # SCSI bus (required for SCSI) -device da # Direct Access (disks) +#device umass +#device scbus # SCSI bus (required for SCSI) +#device da # Direct Access (disks) -device ural -device zyd -device wlan_amrr +#device ural +#device zyd +#device wlan_amrr diff --git a/sys/arm/conf/AVILA.hints b/sys/arm/conf/AVILA.hints index 3a1a6a7..ba3a04b 100644 --- a/sys/arm/conf/AVILA.hints +++ b/sys/arm/conf/AVILA.hints @@ -17,21 +17,22 @@ hint.uart.1.irq=13 # NPE Hardware Queue Manager hint.ixpqmgr.0.at="ixp0" -# NPE wireless NIC's, requires ixpqmgr +# NPE wired NIC's, requires ixpqmgr hint.npe.0.at="ixp0" -hint.npe.0.mac="A" -hint.npe.0.mii="A" +hint.npe.0.npeid="B" +hint.npe.0.mac="B" +hint.npe.0.mii="B" hint.npe.0.phy=0 hint.npe.1.at="ixp0" -hint.npe.1.mac="B" -# NB: on 2348 boards all PHY's are addressed through MAC A -hint.npe.1.mii="A" +hint.npe.1.npeid="C" +hint.npe.1.mac="C" +hint.npe.1.mii="B" hint.npe.1.phy=1 # CF IDE controller hint.ata_avila.0.at="ixp0" -# LED connected to gpio +# Front Panel LED hint.led_avila.0.at="ixp0" # Analog Devices AD7418 temperature sensor diff --git a/sys/arm/include/armreg.h b/sys/arm/include/armreg.h index 6ba8cf4..068073b 100644 --- a/sys/arm/include/armreg.h +++ b/sys/arm/include/armreg.h @@ -174,6 +174,7 @@ #define CPU_ID_IXP425_533 0x690541c0 #define CPU_ID_IXP425_400 0x690541d0 #define CPU_ID_IXP425_266 0x690541f0 +#define CPU_ID_IXP435 0x69054040 /* ARM3-specific coprocessor 15 registers */ #define ARM3_CP15_FLUSH 1 diff --git a/sys/arm/include/intr.h b/sys/arm/include/intr.h index d75f14e..619c5e1 100644 --- a/sys/arm/include/intr.h +++ b/sys/arm/include/intr.h @@ -39,6 +39,7 @@ #ifndef _MACHINE_INTR_H_ #define _MACHINE_INTR_H_ +/* XXX move to std.* files? */ #ifdef CPU_XSCALE_81342 #define NIRQ 128 #elif defined(CPU_XSCALE_PXA2X0) @@ -46,7 +47,8 @@ #define NIRQ IRQ_GPIO_MAX #elif defined(SOC_MV_DISCOVERY) #define NIRQ 96 -#elif defined(CPU_ARM9) || defined(SOC_MV_KIRKWOOD) +#elif defined(CPU_ARM9) || defined(SOC_MV_KIRKWOOD) || \ + defined(CPU_XSCALE_IXP435) #define NIRQ 64 #else #define NIRQ 32 diff --git a/sys/arm/xscale/ixp425/avila_ata.c b/sys/arm/xscale/ixp425/avila_ata.c index 31e3a85..337f43b 100644 --- a/sys/arm/xscale/ixp425/avila_ata.c +++ b/sys/arm/xscale/ixp425/avila_ata.c @@ -67,13 +67,64 @@ __FBSDID("$FreeBSD$"); #include <dev/ata/ata-all.h> #include <ata_if.h> -#define AVILA_IDE_GPIN 12 /* GPIO pin # */ -#define AVILA_IDE_IRQ IXP425_INT_GPIO_12 -#define AVILA_IDE_CTRL 0x06 /* control register */ +#define AVILA_IDE_CTRL 0x06 + +struct ata_config { + const char *desc; /* description for probe */ + uint8_t gpin; /* GPIO pin */ + uint8_t irq; /* IRQ */ + uint32_t base16; /* CS base addr for 16-bit */ + uint32_t size16; /* CS size for 16-bit */ + uint32_t off16; /* CS offset for 16-bit */ + uint32_t basealt; /* CS base addr for alt */ + uint32_t sizealt; /* CS size for alt */ + uint32_t offalt; /* CS offset for alt */ +}; -#define PRONGHORN_IDE_GPIN 0 /* GPIO pin # */ -#define PRONGHORN_IDE_IRQ IXP425_INT_GPIO_0 -#define PRONGHORN_IDE_CNTRL 0x06 /* control register */ +static const struct ata_config * +ata_getconfig(struct ixp425_softc *sa) +{ + static const struct ata_config configs[] = { + { .desc = "Gateworks Avila IDE/CF Controller", + .gpin = 12, + .irq = IXP425_INT_GPIO_12, + .base16 = IXP425_EXP_BUS_CS1_HWBASE, + .size16 = IXP425_EXP_BUS_CS1_SIZE, + .off16 = EXP_TIMING_CS1_OFFSET, + .basealt = IXP425_EXP_BUS_CS2_HWBASE, + .sizealt = IXP425_EXP_BUS_CS2_SIZE, + .offalt = EXP_TIMING_CS2_OFFSET, + }, + { .desc = "Gateworks Cambria IDE/CF Controller", + .gpin = 12, + .irq = IXP425_INT_GPIO_12, + .base16 = CAMBRIA_CFSEL0_HWBASE, + .size16 = CAMBRIA_CFSEL0_SIZE, + .off16 = EXP_TIMING_CS3_OFFSET, + .basealt = CAMBRIA_CFSEL1_HWBASE, + .sizealt = CAMBRIA_CFSEL1_SIZE, + .offalt = EXP_TIMING_CS4_OFFSET, + }, + { .desc = "ADI Pronghorn Metro IDE/CF Controller", + .gpin = 0, + .irq = IXP425_INT_GPIO_0, + .base16 = IXP425_EXP_BUS_CS3_HWBASE, + .size16 = IXP425_EXP_BUS_CS3_SIZE, + .off16 = EXP_TIMING_CS3_OFFSET, + .basealt = IXP425_EXP_BUS_CS4_HWBASE, + .sizealt = IXP425_EXP_BUS_CS4_SIZE, + .offalt = EXP_TIMING_CS4_OFFSET, + }, + }; + + /* XXX honor hint? (but then no multi-board support) */ + /* XXX total hack */ + if ((cpu_id() & CPU_ID_CPU_MASK) == CPU_ID_IXP435) + return &configs[1]; /* Cambria */ + if (EXP_BUS_READ_4(sa, EXP_TIMING_CS2_OFFSET) != 0) + return &configs[0]; /* Avila */ + return &configs[2]; /* Pronghorn */ +} struct ata_avila_softc { device_t sc_dev; @@ -105,14 +156,14 @@ static int ata_avila_probe(device_t dev) { struct ixp425_softc *sa = device_get_softc(device_get_parent(dev)); + const struct ata_config *config; - /* XXX any way to check? */ - if (EXP_BUS_READ_4(sa, EXP_TIMING_CS2_OFFSET) != 0) - device_set_desc_copy(dev, "Gateworks Avila IDE/CF Controller"); - else - device_set_desc_copy(dev, - "ADI Pronghorn Metro IDE/CF Controller"); - return 0; + config = ata_getconfig(sa); + if (config != NULL) { + device_set_desc_copy(dev, config->desc); + return 0; + } + return ENXIO; } static int @@ -120,41 +171,25 @@ ata_avila_attach(device_t dev) { struct ata_avila_softc *sc = device_get_softc(dev); struct ixp425_softc *sa = device_get_softc(device_get_parent(dev)); - u_int32_t alt_t_off, ide_gpin, ide_irq; + const struct ata_config *config; + + config = ata_getconfig(sa); + KASSERT(config != NULL, ("no board config")); sc->sc_dev = dev; /* NB: borrow from parent */ sc->sc_iot = sa->sc_iot; sc->sc_exp_ioh = sa->sc_exp_ioh; - if (EXP_BUS_READ_4(sc, EXP_TIMING_CS2_OFFSET) != 0) { - /* Avila board */ - if (bus_space_map(sc->sc_iot, IXP425_EXP_BUS_CS1_HWBASE, - IXP425_EXP_BUS_CS1_SIZE, 0, &sc->sc_ioh)) - panic("%s: unable to map Expansion Bus CS1 window", - __func__); - if (bus_space_map(sc->sc_iot, IXP425_EXP_BUS_CS2_HWBASE, - IXP425_EXP_BUS_CS2_SIZE, 0, &sc->sc_alt_ioh)) - panic("%s: unable to map Expansion Bus CS2 window", - __func__); - ide_gpin = AVILA_IDE_GPIN; - ide_irq = AVILA_IDE_IRQ; - sc->sc_16bit_off = EXP_TIMING_CS1_OFFSET; - alt_t_off = EXP_TIMING_CS2_OFFSET; - } else { - /* Pronghorn */ - if (bus_space_map(sc->sc_iot, IXP425_EXP_BUS_CS3_HWBASE, - IXP425_EXP_BUS_CS3_SIZE, 0, &sc->sc_ioh)) - panic("%s: unable to map Expansion Bus CS3 window", - __func__); - if (bus_space_map(sc->sc_iot, IXP425_EXP_BUS_CS4_HWBASE, - IXP425_EXP_BUS_CS4_SIZE, 0, &sc->sc_alt_ioh)) - panic("%s: unable to map Expansion Bus CS4 window", - __func__); - ide_gpin = PRONGHORN_IDE_GPIN; - ide_irq = PRONGHORN_IDE_IRQ; - sc->sc_16bit_off = EXP_TIMING_CS3_OFFSET; - alt_t_off = EXP_TIMING_CS4_OFFSET; - } + + if (bus_space_map(sc->sc_iot, config->base16, config->size16, + 0, &sc->sc_ioh)) + panic("%s: cannot map 16-bit window (0x%x/0x%x)", + __func__, config->base16, config->size16); + if (bus_space_map(sc->sc_iot, config->basealt, config->sizealt, + 0, &sc->sc_alt_ioh)) + panic("%s: cannot map alt window (0x%x/0x%x)", + __func__, config->basealt, config->sizealt); + sc->sc_16bit_off = config->off16; /* * Craft special resource for ATA bus space ops @@ -184,30 +219,30 @@ ata_avila_attach(device_t dev) rman_set_bushandle(&sc->sc_alt_ata, sc->sc_alt_ioh); GPIO_CONF_WRITE_4(sa, IXP425_GPIO_GPOER, - GPIO_CONF_READ_4(sa, IXP425_GPIO_GPOER) | (1<<ide_gpin)); + GPIO_CONF_READ_4(sa, IXP425_GPIO_GPOER) | (1<<config->gpin)); /* set interrupt type */ - GPIO_CONF_WRITE_4(sa, GPIO_TYPE_REG(ide_gpin), - (GPIO_CONF_READ_4(sa, GPIO_TYPE_REG(ide_gpin)) &~ - GPIO_TYPE(ide_gpin, GPIO_TYPE_MASK)) | - GPIO_TYPE(ide_gpin, GPIO_TYPE_EDG_RISING)); + GPIO_CONF_WRITE_4(sa, GPIO_TYPE_REG(config->gpin), + (GPIO_CONF_READ_4(sa, GPIO_TYPE_REG(config->gpin)) &~ + GPIO_TYPE(config->gpin, GPIO_TYPE_MASK)) | + GPIO_TYPE(config->gpin, GPIO_TYPE_EDG_RISING)); /* clear ISR */ - GPIO_CONF_WRITE_4(sa, IXP425_GPIO_GPISR, (1<<ide_gpin)); + GPIO_CONF_WRITE_4(sa, IXP425_GPIO_GPISR, (1<<config->gpin)); /* configure CS1/3 window, leaving timing unchanged */ EXP_BUS_WRITE_4(sc, sc->sc_16bit_off, EXP_BUS_READ_4(sc, sc->sc_16bit_off) | EXP_BYTE_EN | EXP_WR_EN | EXP_BYTE_RD16 | EXP_CS_EN); /* configure CS2/4 window, leaving timing unchanged */ - EXP_BUS_WRITE_4(sc, alt_t_off, - EXP_BUS_READ_4(sc, alt_t_off) | + EXP_BUS_WRITE_4(sc, config->offalt, + EXP_BUS_READ_4(sc, config->offalt) | EXP_BYTE_EN | EXP_WR_EN | EXP_BYTE_RD16 | EXP_CS_EN); /* setup interrupt */ sc->sc_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &sc->sc_rid, - ide_irq, ide_irq, 1, RF_ACTIVE); + config->irq, config->irq, 1, RF_ACTIVE); if (!sc->sc_irq) - panic("Unable to allocate irq %u.\n", ide_irq); + panic("Unable to allocate irq %u.\n", config->irq); bus_setup_intr(dev, sc->sc_irq, INTR_TYPE_BIO | INTR_MPSAFE | INTR_ENTROPY, NULL, ata_avila_intr, sc, &sc->sc_ih); @@ -230,9 +265,9 @@ ata_avila_detach(device_t dev) /* detach & delete all children */ if (device_get_children(dev, &children, &nc) == 0) { - if (nc > 0) - device_delete_child(dev, children[0]); - free(children, M_TEMP); + if (nc > 0) + device_delete_child(dev, children[0]); + free(children, M_TEMP); } bus_teardown_intr(dev, sc->sc_irq, sc->sc_ih); @@ -308,7 +343,7 @@ ata_avila_teardown_intr(device_t dev, device_t child, struct resource *irq, /* * Enable/disable 16-bit ops on the expansion bus. */ -static void __inline +static __inline void enable_16(struct ata_avila_softc *sc) { EXP_BUS_WRITE_4(sc, sc->sc_16bit_off, @@ -316,7 +351,7 @@ enable_16(struct ata_avila_softc *sc) DELAY(100); /* XXX? */ } -static void __inline +static __inline void disable_16(struct ata_avila_softc *sc) { DELAY(100); /* XXX? */ diff --git a/sys/arm/xscale/ixp425/avila_led.c b/sys/arm/xscale/ixp425/avila_led.c index 2493076..31558af 100644 --- a/sys/arm/xscale/ixp425/avila_led.c +++ b/sys/arm/xscale/ixp425/avila_led.c @@ -37,22 +37,19 @@ __FBSDID("$FreeBSD$"); #include <dev/led/led.h> #define GPIO_LED_STATUS 3 -#define GPIO_LED_STATUS_BIT (1U << GPIO_LED_STATUS) - -static struct cdev *gpioled; +#define GPIO_LED_STATUS_BIT (1U << GPIO_LED_STATUS) struct led_avila_softc { device_t sc_dev; bus_space_tag_t sc_iot; bus_space_handle_t sc_gpio_ioh; + struct cdev *sc_led; }; -static struct led_avila_softc *led_avila_sc = NULL; - static void -led_func(void *unused, int onoff) +led_func(void *arg, int onoff) { - struct led_avila_softc *sc = led_avila_sc; + struct led_avila_softc *sc = arg; uint32_t reg; reg = GPIO_CONF_READ_4(sc, IXP425_GPIO_GPOUTR); @@ -66,7 +63,7 @@ led_func(void *unused, int onoff) static int led_avila_probe(device_t dev) { - device_set_desc(dev, "Gateworks Avila GPIO connected LED"); + device_set_desc(dev, "Gateworks Avila Front Panel LED"); return (0); } @@ -75,31 +72,35 @@ led_avila_attach(device_t dev) { struct led_avila_softc *sc = device_get_softc(dev); struct ixp425_softc *sa = device_get_softc(device_get_parent(dev)); - void *led = NULL; - uint32_t reg; - - led_avila_sc = sc; sc->sc_dev = dev; sc->sc_iot = sa->sc_iot; sc->sc_gpio_ioh = sa->sc_gpio_ioh; /* Configure LED GPIO pin as output */ - reg = GPIO_CONF_READ_4(sc, IXP425_GPIO_GPOER); - reg &= ~GPIO_LED_STATUS_BIT; - GPIO_CONF_WRITE_4(sc, IXP425_GPIO_GPOER, reg); + GPIO_CONF_WRITE_4(sc, IXP425_GPIO_GPOER, + GPIO_CONF_READ_4(sc, IXP425_GPIO_GPOER) &~ GPIO_LED_STATUS_BIT); - gpioled = led_create(led_func, led, "gpioled"); + sc->sc_led = led_create(led_func, sc, "gpioled"); - /* Turn on LED */ - led_func(led, 1); + led_func(sc, 1); /* Turn on LED */ return (0); } +static void +led_avila_detach(device_t dev) +{ + struct led_avila_softc *sc = device_get_softc(dev); + + if (sc->sc_led != NULL) + led_destroy(sc->sc_led); +} + static device_method_t led_avila_methods[] = { DEVMETHOD(device_probe, led_avila_probe), DEVMETHOD(device_attach, led_avila_attach), + DEVMETHOD(device_detach, led_avila_detach), {0, 0}, }; diff --git a/sys/arm/xscale/ixp425/avila_machdep.c b/sys/arm/xscale/ixp425/avila_machdep.c index e9b53bb..181ccb4 100644 --- a/sys/arm/xscale/ixp425/avila_machdep.c +++ b/sys/arm/xscale/ixp425/avila_machdep.c @@ -95,6 +95,11 @@ __FBSDID("$FreeBSD$"); #include <arm/xscale/ixp425/ixp425reg.h> #include <arm/xscale/ixp425/ixp425var.h> +/* kernel text starts where we were loaded at boot */ +#define KERNEL_TEXT_OFF (KERNPHYSADDR - PHYSADDR) +#define KERNEL_TEXT_BASE (KERNBASE + KERNEL_TEXT_OFF) +#define KERNEL_TEXT_PHYS (PHYSADDR + KERNEL_TEXT_OFF) + #define KERNEL_PT_SYS 0 /* Page table for mapping proc0 zero page */ #define KERNEL_PT_IO 1 #define KERNEL_PT_IO_NUM 3 @@ -142,114 +147,109 @@ static struct trapframe proc0_tf; /* Static device mappings. */ static const struct pmap_devmap ixp425_devmap[] = { /* Physical/Virtual address for I/O space */ - { - IXP425_IO_VBASE, - IXP425_IO_HWBASE, - IXP425_IO_SIZE, - VM_PROT_READ|VM_PROT_WRITE, - PTE_NOCACHE, - }, + { IXP425_IO_VBASE, IXP425_IO_HWBASE, IXP425_IO_SIZE, + VM_PROT_READ|VM_PROT_WRITE, PTE_NOCACHE, }, /* Expansion Bus */ - { - IXP425_EXP_VBASE, - IXP425_EXP_HWBASE, - IXP425_EXP_SIZE, - VM_PROT_READ|VM_PROT_WRITE, - PTE_NOCACHE, - }, + { IXP425_EXP_VBASE, IXP425_EXP_HWBASE, IXP425_EXP_SIZE, + VM_PROT_READ|VM_PROT_WRITE, PTE_NOCACHE, }, /* IXP425 PCI Configuration */ - { - IXP425_PCI_VBASE, - IXP425_PCI_HWBASE, - IXP425_PCI_SIZE, - VM_PROT_READ|VM_PROT_WRITE, - PTE_NOCACHE, - }, + { IXP425_PCI_VBASE, IXP425_PCI_HWBASE, IXP425_PCI_SIZE, + VM_PROT_READ|VM_PROT_WRITE, PTE_NOCACHE, }, /* SDRAM Controller */ - { - IXP425_MCU_VBASE, - IXP425_MCU_HWBASE, - IXP425_MCU_SIZE, - VM_PROT_READ|VM_PROT_WRITE, - PTE_NOCACHE, - }, + { IXP425_MCU_VBASE, IXP425_MCU_HWBASE, IXP425_MCU_SIZE, + VM_PROT_READ|VM_PROT_WRITE, PTE_NOCACHE, }, /* PCI Memory Space */ - { - IXP425_PCI_MEM_VBASE, - IXP425_PCI_MEM_HWBASE, - IXP425_PCI_MEM_SIZE, - VM_PROT_READ|VM_PROT_WRITE, - PTE_NOCACHE, - }, + { IXP425_PCI_MEM_VBASE, IXP425_PCI_MEM_HWBASE, IXP425_PCI_MEM_SIZE, + VM_PROT_READ|VM_PROT_WRITE, PTE_NOCACHE, }, + + /* Q-Mgr Memory Space */ + { IXP425_QMGR_VBASE, IXP425_QMGR_HWBASE, IXP425_QMGR_SIZE, + VM_PROT_READ|VM_PROT_WRITE, PTE_NOCACHE, }, + /* NPE-A Memory Space */ - { - IXP425_NPE_A_VBASE, - IXP425_NPE_A_HWBASE, - IXP425_NPE_A_SIZE, - VM_PROT_READ|VM_PROT_WRITE, - PTE_NOCACHE, - }, + { IXP425_NPE_A_VBASE, IXP425_NPE_A_HWBASE, IXP425_NPE_A_SIZE, + VM_PROT_READ|VM_PROT_WRITE, PTE_NOCACHE, }, /* NPE-B Memory Space */ - { - IXP425_NPE_B_VBASE, - IXP425_NPE_B_HWBASE, - IXP425_NPE_B_SIZE, - VM_PROT_READ|VM_PROT_WRITE, - PTE_NOCACHE, - }, + { IXP425_NPE_B_VBASE, IXP425_NPE_B_HWBASE, IXP425_NPE_B_SIZE, + VM_PROT_READ|VM_PROT_WRITE, PTE_NOCACHE, }, /* NPE-C Memory Space */ - { - IXP425_NPE_C_VBASE, - IXP425_NPE_C_HWBASE, - IXP425_NPE_C_SIZE, - VM_PROT_READ|VM_PROT_WRITE, - PTE_NOCACHE, - }, - /* MAC-A Memory Space */ - { - IXP425_MAC_A_VBASE, - IXP425_MAC_A_HWBASE, - IXP425_MAC_A_SIZE, - VM_PROT_READ|VM_PROT_WRITE, - PTE_NOCACHE, - }, + { IXP425_NPE_C_VBASE, IXP425_NPE_C_HWBASE, IXP425_NPE_C_SIZE, + VM_PROT_READ|VM_PROT_WRITE, PTE_NOCACHE, }, + /* MAC-B Memory Space */ - { - IXP425_MAC_B_VBASE, - IXP425_MAC_B_HWBASE, - IXP425_MAC_B_SIZE, - VM_PROT_READ|VM_PROT_WRITE, - PTE_NOCACHE, - }, - /* Q-Mgr Memory Space */ - { - IXP425_QMGR_VBASE, - IXP425_QMGR_HWBASE, - IXP425_QMGR_SIZE, - VM_PROT_READ|VM_PROT_WRITE, - PTE_NOCACHE, - }, - - { - 0, - 0, - 0, - 0, - 0, - } + { IXP425_MAC_B_VBASE, IXP425_MAC_B_HWBASE, IXP425_MAC_B_SIZE, + VM_PROT_READ|VM_PROT_WRITE, PTE_NOCACHE, }, + /* MAC-C Memory Space */ + { IXP425_MAC_C_VBASE, IXP425_MAC_C_HWBASE, IXP425_MAC_C_SIZE, + VM_PROT_READ|VM_PROT_WRITE, PTE_NOCACHE, }, + + { 0 }, }; -#define SDRAM_START 0x10000000 +/* Static device mappings. */ +static const struct pmap_devmap ixp435_devmap[] = { + /* Physical/Virtual address for I/O space */ + { IXP425_IO_VBASE, IXP425_IO_HWBASE, IXP425_IO_SIZE, + VM_PROT_READ|VM_PROT_WRITE, PTE_NOCACHE, }, + + /* Expansion Bus */ + { IXP425_EXP_VBASE, IXP425_EXP_HWBASE, IXP425_EXP_SIZE, + VM_PROT_READ|VM_PROT_WRITE, PTE_NOCACHE, }, + + /* IXP425 PCI Configuration */ + { IXP425_PCI_VBASE, IXP425_PCI_HWBASE, IXP425_PCI_SIZE, + VM_PROT_READ|VM_PROT_WRITE, PTE_NOCACHE, }, + + /* DDRII Controller NB: mapped same place as IXP425 */ + { IXP425_MCU_VBASE, IXP435_MCU_HWBASE, IXP425_MCU_SIZE, + VM_PROT_READ|VM_PROT_WRITE, PTE_NOCACHE, }, + + /* PCI Memory Space */ + { IXP425_PCI_MEM_VBASE, IXP425_PCI_MEM_HWBASE, IXP425_PCI_MEM_SIZE, + VM_PROT_READ|VM_PROT_WRITE, PTE_NOCACHE, }, + + /* Q-Mgr Memory Space */ + { IXP425_QMGR_VBASE, IXP425_QMGR_HWBASE, IXP425_QMGR_SIZE, + VM_PROT_READ|VM_PROT_WRITE, PTE_NOCACHE, }, + + /* NPE-A Memory Space */ + { IXP425_NPE_A_VBASE, IXP425_NPE_A_HWBASE, IXP425_NPE_A_SIZE, + VM_PROT_READ|VM_PROT_WRITE, PTE_NOCACHE, }, + /* NPE-C Memory Space */ + { IXP425_NPE_C_VBASE, IXP425_NPE_C_HWBASE, IXP425_NPE_C_SIZE, + VM_PROT_READ|VM_PROT_WRITE, PTE_NOCACHE, }, + + /* MAC-C Memory Space */ + { IXP425_MAC_C_VBASE, IXP425_MAC_C_HWBASE, IXP425_MAC_C_SIZE, + VM_PROT_READ|VM_PROT_WRITE, PTE_NOCACHE, }, + /* MAC-B Memory Space */ + { IXP425_MAC_B_VBASE, IXP425_MAC_B_HWBASE, IXP425_MAC_B_SIZE, + VM_PROT_READ|VM_PROT_WRITE, PTE_NOCACHE, }, + /* MAC-A Memory Space */ + { IXP435_MAC_A_VBASE, IXP435_MAC_A_HWBASE, IXP435_MAC_A_SIZE, + VM_PROT_READ|VM_PROT_WRITE, PTE_NOCACHE, }, + + /* USB1 Memory Space */ + { IXP435_USB1_VBASE, IXP435_USB1_HWBASE, IXP435_USB1_SIZE, + VM_PROT_READ|VM_PROT_WRITE, PTE_NOCACHE, }, + /* USB2 Memory Space */ + { IXP435_USB2_VBASE, IXP435_USB2_HWBASE, IXP435_USB2_SIZE, + VM_PROT_READ|VM_PROT_WRITE, PTE_NOCACHE, }, + + { 0 } +}; extern vm_offset_t xscale_cache_clean_addr; void * initarm(void *arg, void *arg2) { +#define next_chunk2(a,b) (((a) + (b)) &~ ((b)-1)) +#define next_page(a) next_chunk2(a,PAGE_SIZE) struct pv_addr kernel_l1pt; int loop, i; u_int l1pagetable; @@ -260,25 +260,40 @@ initarm(void *arg, void *arg2) vm_offset_t lastaddr; uint32_t memsize; - set_cpufuncs(); + set_cpufuncs(); /* NB: sets cputype */ lastaddr = fake_preload_metadata(); pcpu_init(pcpup, 0, sizeof(struct pcpu)); PCPU_SET(curthread, &thread0); - freemempos = 0x10200000; - /* Define a macro to simplify memory allocation */ -#define valloc_pages(var, np) \ - alloc_pages((var).pv_pa, (np)); \ - (var).pv_va = (var).pv_pa + 0xb0000000; - -#define alloc_pages(var, np) \ - freemempos -= (np * PAGE_SIZE); \ - (var) = freemempos; \ - memset((char *)(var), 0, ((np) * PAGE_SIZE)); - + /* + * We allocate memory downwards from where we were loaded + * by RedBoot; first the L1 page table, then NUM_KERNEL_PTS + * entries in the L2 page table. Past that we re-align the + * allocation boundary so later data structures (stacks, etc) + * can be mapped with different attributes (write-back vs + * write-through). Note this leaves a gap for expansion + * (or might be repurposed). + */ + freemempos = KERNPHYSADDR; + + /* macros to simplify initial memory allocation */ +#define alloc_pages(var, np) do { \ + freemempos -= (np * PAGE_SIZE); \ + (var) = freemempos; \ + /* NB: this works because locore maps PA=VA */ \ + memset((char *)(var), 0, ((np) * PAGE_SIZE)); \ +} while (0) +#define valloc_pages(var, np) do { \ + alloc_pages((var).pv_pa, (np)); \ + (var).pv_va = (var).pv_pa + (KERNVIRTADDR - KERNPHYSADDR); \ +} while (0) + + /* force L1 page table alignment */ while (((freemempos - L1_TABLE_SIZE) & (L1_TABLE_SIZE - 1)) != 0) freemempos -= PAGE_SIZE; + /* allocate contiguous L1 page table */ valloc_pages(kernel_l1pt, L1_TABLE_SIZE / PAGE_SIZE); + /* now allocate L2 page tables; they are linked to L1 below */ for (loop = 0; loop < NUM_KERNEL_PTS; ++loop) { if (!(loop % (PAGE_SIZE / L2_TABLE_SIZE_REAL))) { valloc_pages(kernel_pt_table[loop], @@ -288,11 +303,18 @@ initarm(void *arg, void *arg2) (loop % (PAGE_SIZE / L2_TABLE_SIZE_REAL)) * L2_TABLE_SIZE_REAL; kernel_pt_table[loop].pv_va = - kernel_pt_table[loop].pv_pa + 0xb0000000; + kernel_pt_table[loop].pv_pa + + (KERNVIRTADDR - KERNPHYSADDR); } } - freemem_pt = freemempos; - freemempos = 0x10100000; + freemem_pt = freemempos; /* base of allocated pt's */ + + /* + * Re-align allocation boundary so we can map the area + * write-back instead of write-through for the stacks and + * related structures allocated below. + */ + freemempos = PHYSADDR + 0x100000; /* * Allocate a page for the system page mapped to V0x00000000 * This page will just contain the system vectors and can be @@ -308,30 +330,25 @@ initarm(void *arg, void *arg2) alloc_pages(minidataclean.pv_pa, 1); valloc_pages(msgbufpv, round_page(MSGBUF_SIZE) / PAGE_SIZE); #ifdef ARM_USE_SMALL_ALLOC +#error "I am broken" /* XXX save people grief */ freemempos -= PAGE_SIZE; freemem_pt = trunc_page(freemem_pt); freemem_after = freemempos - ((freemem_pt - 0x10100000) / PAGE_SIZE) * sizeof(struct arm_small_page); - arm_add_smallalloc_pages((void *)(freemem_after + 0xb0000000) + arm_add_smallalloc_pages((void *)(freemem_after + (KERNVIRTADDR - KERNPHYSADDR) , (void *)0xc0100000, freemem_pt - 0x10100000, 1); freemem_after -= ((freemem_after - 0x10001000) / PAGE_SIZE) * sizeof(struct arm_small_page); - arm_add_smallalloc_pages((void *)(freemem_after + 0xb0000000) + arm_add_smallalloc_pages((void *)(freemem_after + (KEYVIRTADDR - KERNPHYSADDR)) , (void *)0xc0001000, trunc_page(freemem_after) - 0x10001000, 0); freemempos = trunc_page(freemem_after); freemempos -= PAGE_SIZE; #endif - /* - * Allocate memory for the l1 and l2 page tables. The scheme to avoid - * wasting memory by allocating the l1pt on the first 16k memory was - * taken from NetBSD rpc_machdep.c. NKPT should be greater than 12 for - * this to work (which is supposed to be the case). - */ /* - * Now we start construction of the L1 page table - * We start by mapping the L2 page tables into the L1. - * This means that we can replace L1 mappings later on if necessary + * Now construct the L1 page table. First map the L2 + * page tables into the L1 so we can replace L1 mappings + * later on if necessary */ l1pagetable = kernel_l1pt.pv_va; @@ -339,30 +356,28 @@ initarm(void *arg, void *arg2) pmap_link_l2pt(l1pagetable, ARM_VECTORS_HIGH & ~(0x00100000 - 1), &kernel_pt_table[KERNEL_PT_SYS]); pmap_link_l2pt(l1pagetable, IXP425_IO_VBASE, - &kernel_pt_table[KERNEL_PT_IO]); + &kernel_pt_table[KERNEL_PT_IO]); pmap_link_l2pt(l1pagetable, IXP425_MCU_VBASE, - &kernel_pt_table[KERNEL_PT_IO + 1]); + &kernel_pt_table[KERNEL_PT_IO + 1]); pmap_link_l2pt(l1pagetable, IXP425_PCI_MEM_VBASE, - &kernel_pt_table[KERNEL_PT_IO + 2]); + &kernel_pt_table[KERNEL_PT_IO + 2]); pmap_link_l2pt(l1pagetable, KERNBASE, &kernel_pt_table[KERNEL_PT_BEFOREKERN]); - pmap_map_chunk(l1pagetable, KERNBASE, SDRAM_START, 0x100000, + pmap_map_chunk(l1pagetable, KERNBASE, PHYSADDR, 0x100000, VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE); - pmap_map_chunk(l1pagetable, KERNBASE + 0x100000, SDRAM_START + 0x100000, + pmap_map_chunk(l1pagetable, KERNBASE + 0x100000, PHYSADDR + 0x100000, 0x100000, VM_PROT_READ|VM_PROT_WRITE, PTE_PAGETABLE); - pmap_map_chunk(l1pagetable, KERNBASE + 0x200000, SDRAM_START + 0x200000, - (((uint32_t)(lastaddr) - KERNBASE - 0x200000) + L1_S_SIZE) & ~(L1_S_SIZE - 1), + pmap_map_chunk(l1pagetable, KERNEL_TEXT_BASE, KERNEL_TEXT_PHYS, + next_chunk2(((uint32_t)lastaddr) - KERNEL_TEXT_BASE, L1_S_SIZE), VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE); - freemem_after = ((int)lastaddr + PAGE_SIZE) & ~(PAGE_SIZE - 1); - afterkern = round_page(((vm_offset_t)lastaddr + L1_S_SIZE) & ~(L1_S_SIZE - - 1)); + freemem_after = next_page((int)lastaddr); + afterkern = round_page(next_chunk2((vm_offset_t)lastaddr, L1_S_SIZE)); for (i = 0; i < KERNEL_PT_AFKERNEL_NUM; i++) { pmap_link_l2pt(l1pagetable, afterkern + i * 0x00100000, &kernel_pt_table[KERNEL_PT_AFKERNEL + i]); } pmap_map_entry(l1pagetable, afterkern, minidataclean.pv_pa, VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE); - #ifdef ARM_USE_SMALL_ALLOC if ((freemem_after + 2 * PAGE_SIZE) <= afterkern) { @@ -380,7 +395,10 @@ initarm(void *arg, void *arg2) /* Map the vector page. */ pmap_map_entry(l1pagetable, ARM_VECTORS_HIGH, systempage.pv_pa, VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE); - pmap_devmap_bootstrap(l1pagetable, ixp425_devmap); + if (cpu_is_ixp43x()) + pmap_devmap_bootstrap(l1pagetable, ixp435_devmap); + else + pmap_devmap_bootstrap(l1pagetable, ixp425_devmap); /* * Give the XScale global cache clean code an appropriately * sized chunk of unmapped VA space starting at 0xff000000 @@ -392,6 +410,7 @@ initarm(void *arg, void *arg2) setttb(kernel_l1pt.pv_pa); cpu_tlb_flushID(); cpu_domains(DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2)); + /* * Pages were allocated during the secondary bootstrap for the * stacks for different CPU modes. @@ -400,16 +419,9 @@ initarm(void *arg, void *arg2) * Since the ARM stacks use STMFD etc. we must set r13 to the top end * of the stack memory. */ - - - set_stackptr(PSR_IRQ32_MODE, - irqstack.pv_va + IRQ_STACK_SIZE * PAGE_SIZE); - set_stackptr(PSR_ABT32_MODE, - abtstack.pv_va + ABT_STACK_SIZE * PAGE_SIZE); - set_stackptr(PSR_UND32_MODE, - undstack.pv_va + UND_STACK_SIZE * PAGE_SIZE); - - + set_stackptr(PSR_IRQ32_MODE, irqstack.pv_va + IRQ_STACK_SIZE*PAGE_SIZE); + set_stackptr(PSR_ABT32_MODE, abtstack.pv_va + ABT_STACK_SIZE*PAGE_SIZE); + set_stackptr(PSR_UND32_MODE, undstack.pv_va + UND_STACK_SIZE*PAGE_SIZE); /* * We must now clean the cache again.... @@ -422,21 +434,25 @@ initarm(void *arg, void *arg2) * this problem will not occur after initarm(). */ cpu_idcache_wbinv_all(); + /* ready to setup the console (XXX move earlier if possible) */ + cninit(); /* - * Fetch the SDRAM start/size from the ixp425 SDRAM configration - * registers. + * Fetch the RAM size from the MCU registers. The + * expansion bus was mapped above so we can now read 'em. */ - cninit(); - memsize = ixp425_sdram_size(); + if (cpu_is_ixp43x()) + memsize = ixp435_ddram_size(); + else + memsize = ixp425_sdram_size(); physmem = memsize / PAGE_SIZE; /* Set stack for exception handlers */ - + data_abort_handler_address = (u_int)data_abort_handler; prefetch_abort_handler_address = (u_int)prefetch_abort_handler; undefined_handler_address = (u_int)undefinedinstruction_bounce; undefined_init(); - + proc_linkup0(&proc0, &thread0); thread0.td_kstack = kernelstack.pv_va; thread0.td_pcb = (struct pcb *) @@ -444,38 +460,33 @@ initarm(void *arg, void *arg2) thread0.td_pcb->pcb_flags = 0; thread0.td_frame = &proc0_tf; pcpup->pc_curpcb = thread0.td_pcb; - - /* Enable MMU, I-cache, D-cache, write buffer. */ arm_vector_init(ARM_VECTORS_HIGH, ARM_VEC_ALL); - - pmap_curmaxkvaddr = afterkern + PAGE_SIZE; - dump_avail[0] = 0x10000000; - dump_avail[1] = 0x10000000 + memsize; + dump_avail[0] = PHYSADDR; + dump_avail[1] = PHYSADDR + memsize; dump_avail[2] = 0; dump_avail[3] = 0; - - pmap_bootstrap(pmap_curmaxkvaddr, - 0xd0000000, &kernel_l1pt); + + pmap_bootstrap(pmap_curmaxkvaddr, 0xd0000000, &kernel_l1pt); msgbufp = (void*)msgbufpv.pv_va; msgbufinit(msgbufp, MSGBUF_SIZE); mutex_init(); - + i = 0; #ifdef ARM_USE_SMALL_ALLOC - phys_avail[i++] = 0x10000000; - phys_avail[i++] = 0x10001000; /* + phys_avail[i++] = PHYSADDR; + phys_avail[i++] = PHYSADDR + PAGE_SIZE; /* *XXX: Gross hack to get our * pages in the vm_page_array . */ #endif - phys_avail[i++] = round_page(virtual_avail - KERNBASE + SDRAM_START); - phys_avail[i++] = trunc_page(0x10000000 + memsize - 1); + phys_avail[i++] = round_page(virtual_avail - KERNBASE + PHYSADDR); + phys_avail[i++] = trunc_page(PHYSADDR + memsize - 1); phys_avail[i++] = 0; phys_avail[i] = 0; - + /* Do basic tuning, hz etc */ init_param1(); init_param2(physmem); @@ -487,4 +498,6 @@ initarm(void *arg, void *arg2) return ((void *)(kernelstack.pv_va + USPACE_SVC_STACK_TOP - sizeof(struct pcb))); +#undef next_page +#undef next_chunk2 } diff --git a/sys/arm/xscale/ixp425/cambria_fled.c b/sys/arm/xscale/ixp425/cambria_fled.c new file mode 100644 index 0000000..ede1577 --- /dev/null +++ b/sys/arm/xscale/ixp425/cambria_fled.c @@ -0,0 +1,108 @@ +/*- + * Copyright (c) 2008 Sam Leffler. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); +/* + * Cambria Front Panel LED sitting on the I2C bus. + */ +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/module.h> +#include <sys/bus.h> + +#include <machine/bus.h> + +#include <dev/iicbus/iiconf.h> +#include <dev/led/led.h> + +#include "iicbus_if.h" + +#define IIC_M_WR 0 /* write operation */ +#define LED_ADDR 0xae /* slave address */ + +struct fled_softc { + struct cdev *sc_led; +}; + +static int +fled_probe(device_t dev) +{ + device_set_desc(dev, "Gateworks Cambria Front Panel LED"); + return 0; +} + +static void +fled_cb(void *arg, int onoff) +{ + uint8_t data[1]; + struct iic_msg msgs[1] = { + { LED_ADDR, IIC_M_WR, 1, data }, + }; + device_t dev = arg; + + data[0] = (onoff == 0); /* NB: low true */ + (void) iicbus_transfer(dev, msgs, 1); +} + +static int +fled_attach(device_t dev) +{ + struct fled_softc *sc = device_get_softc(dev); + + sc->sc_led = led_create(fled_cb, dev, "front"); + + return 0; +} + +static int +fled_detach(device_t dev) +{ + struct fled_softc *sc = device_get_softc(dev); + + if (sc->sc_led != NULL) + led_destroy(sc->sc_led); + + return 0; +} + +static device_method_t fled_methods[] = { + DEVMETHOD(device_probe, fled_probe), + DEVMETHOD(device_attach, fled_attach), + DEVMETHOD(device_detach, fled_detach), + + {0, 0}, +}; + +static driver_t fled_driver = { + "fled", + fled_methods, + sizeof(struct fled_softc), +}; +static devclass_t fled_devclass; + +DRIVER_MODULE(fled, iicbus, fled_driver, fled_devclass, 0, 0); +MODULE_VERSION(fled, 1); +MODULE_DEPEND(fled, iicbus, 1, 1, 1); diff --git a/sys/arm/xscale/ixp425/cambria_led.c b/sys/arm/xscale/ixp425/cambria_led.c new file mode 100644 index 0000000..c55e3cb --- /dev/null +++ b/sys/arm/xscale/ixp425/cambria_led.c @@ -0,0 +1,132 @@ +/*- + * Copyright (c) 2008 Sam Leffler. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * Gateworks Cambria Octal LED Latch driver. + */ +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/module.h> +#include <sys/bus.h> + +#include <machine/armreg.h> + +#include <arm/xscale/ixp425/ixp425reg.h> +#include <arm/xscale/ixp425/ixp425var.h> + +#include <dev/led/led.h> + +struct led_softc { + device_t sc_dev; + bus_space_tag_t sc_iot; + bus_space_handle_t sc_ioh; + struct cdev *sc_leds[8]; + uint8_t sc_latch; +}; + +static void +update_latch(struct led_softc *sc, int bit, int onoff) +{ + if (onoff) + sc->sc_latch &= ~bit; + else + sc->sc_latch |= bit; + bus_space_write_1(sc->sc_iot, sc->sc_ioh, 0, sc->sc_latch); +} +static void led_A(void *arg, int onoff) { update_latch(arg, 1<<0, onoff); } +static void led_B(void *arg, int onoff) { update_latch(arg, 1<<1, onoff); } +static void led_C(void *arg, int onoff) { update_latch(arg, 1<<2, onoff); } +static void led_D(void *arg, int onoff) { update_latch(arg, 1<<3, onoff); } +static void led_E(void *arg, int onoff) { update_latch(arg, 1<<4, onoff); } +static void led_F(void *arg, int onoff) { update_latch(arg, 1<<5, onoff); } +static void led_G(void *arg, int onoff) { update_latch(arg, 1<<6, onoff); } +static void led_H(void *arg, int onoff) { update_latch(arg, 1<<7, onoff); } + +static int +led_probe(device_t dev) +{ + device_set_desc(dev, "Gateworks Octal LED Latch"); + return (0); +} + +static int +led_attach(device_t dev) +{ + struct led_softc *sc = device_get_softc(dev); + struct ixp425_softc *sa = device_get_softc(device_get_parent(dev)); + + sc->sc_dev = dev; + sc->sc_iot = sa->sc_iot; + /* NB: write anywhere works, use first location */ + if (bus_space_map(sc->sc_iot, CAMBRIA_OCTAL_LED_HWBASE, sizeof(uint8_t), + 0, &sc->sc_ioh)) { + device_printf(dev, "cannot map LED latch (0x%lx)", + CAMBRIA_OCTAL_LED_HWBASE); + return ENXIO; + } + + sc->sc_leds[0] = led_create(led_A, sc, "A"); + sc->sc_leds[1] = led_create(led_B, sc, "B"); + sc->sc_leds[2] = led_create(led_C, sc, "C"); + sc->sc_leds[3] = led_create(led_D, sc, "D"); + sc->sc_leds[4] = led_create(led_E, sc, "E"); + sc->sc_leds[5] = led_create(led_F, sc, "F"); + sc->sc_leds[6] = led_create(led_G, sc, "G"); + sc->sc_leds[7] = led_create(led_H, sc, "H"); + + return 0; +} + +static void +led_detach(device_t dev) +{ + struct led_softc *sc = device_get_softc(dev); + int i; + + for (i = 0; i < 8; i++) { + struct cdev *led = sc->sc_leds[i]; + if (led != NULL) + led_destroy(led); + } +} + +static device_method_t led_methods[] = { + DEVMETHOD(device_probe, led_probe), + DEVMETHOD(device_attach, led_attach), + DEVMETHOD(device_attach, led_detach), + + {0, 0}, +}; + +static driver_t led_driver = { + "led_cambria", + led_methods, + sizeof(struct led_softc), +}; +static devclass_t led_devclass; +DRIVER_MODULE(led_cambria, ixp, led_driver, led_devclass, 0, 0); diff --git a/sys/arm/xscale/ixp425/files.avila b/sys/arm/xscale/ixp425/files.avila index 50910ce..a9b70dc 100644 --- a/sys/arm/xscale/ixp425/files.avila +++ b/sys/arm/xscale/ixp425/files.avila @@ -2,4 +2,6 @@ arm/xscale/ixp425/avila_machdep.c standard arm/xscale/ixp425/avila_ata.c optional avila_ata arm/xscale/ixp425/avila_led.c optional avila_led +arm/xscale/ixp425/cambria_led.c optional cambria_led +arm/xscale/ixp425/cambria_fled.c optional cambria_fled arm/xscale/ixp425/ixdp425_pci.c optional pci diff --git a/sys/arm/xscale/ixp425/files.ixp425 b/sys/arm/xscale/ixp425/files.ixp425 index d93524a..4299857 100644 --- a/sys/arm/xscale/ixp425/files.ixp425 +++ b/sys/arm/xscale/ixp425/files.ixp425 @@ -44,3 +44,5 @@ IxNpeMicrocode.dat optional npe_fw \ # Q-Manager support # arm/xscale/ixp425/ixp425_qmgr.c optional qmgr +# +arm/xscale/ixp425/ixp435_ehci.c optional ehci diff --git a/sys/arm/xscale/ixp425/if_npe.c b/sys/arm/xscale/ixp425/if_npe.c index 02af22f..52bea76 100644 --- a/sys/arm/xscale/ixp425/if_npe.c +++ b/sys/arm/xscale/ixp425/if_npe.c @@ -85,6 +85,8 @@ __FBSDID("$FreeBSD$"); #include <dev/mii/miivar.h> #include <arm/xscale/ixp425/if_npereg.h> +#include <machine/armreg.h> + #include "miibus_if.h" /* @@ -121,6 +123,7 @@ struct npe_softc { bus_space_handle_t sc_ioh; /* MAC register window */ device_t sc_mii; /* child miibus */ bus_space_handle_t sc_miih; /* MII register window */ + int sc_npeid; struct ixpnpe_softc *sc_npe; /* NPE support */ int sc_debug; /* DPRINTF* control */ int sc_tickinterval; @@ -143,7 +146,7 @@ struct npe_softc { }; /* - * Per-unit static configuration for IXP425. The tx and + * Static configuration for IXP425. The tx and * rx free Q id's are fixed by the NPE microcode. The * rx Q id's are programmed to be separate to simplify * multi-port processing. It may be better to handle @@ -154,39 +157,39 @@ struct npe_softc { * assumptions probably need to be handled through hints. */ static const struct { - const char *desc; /* device description */ - int npeid; /* NPE assignment */ - uint32_t imageid; /* NPE firmware image id */ - uint32_t regbase; - int regsize; + uint32_t imageid; /* default fw image */ + uint32_t macbase; uint32_t miibase; - int miisize; int phy; /* phy id */ uint8_t rx_qid; uint8_t rx_freeqid; uint8_t tx_qid; uint8_t tx_doneqid; -} npeconfig[NPE_PORTS_MAX] = { - { .desc = "IXP NPE-B", - .npeid = NPE_B, +} npeconfig[NPE_MAX] = { + [NPE_A] = { + .imageid = IXP425_NPE_A_IMAGEID, + .macbase = IXP435_MAC_A_HWBASE, + .miibase = IXP425_MAC_C_HWBASE, + .phy = 2, + .rx_qid = 4, + .rx_freeqid = 26, + .tx_qid = 23, + .tx_doneqid = 31 + }, + [NPE_B] = { .imageid = IXP425_NPE_B_IMAGEID, - .regbase = IXP425_MAC_A_HWBASE, - .regsize = IXP425_MAC_A_SIZE, - .miibase = IXP425_MAC_A_HWBASE, - .miisize = IXP425_MAC_A_SIZE, + .macbase = IXP425_MAC_B_HWBASE, + .miibase = IXP425_MAC_C_HWBASE, .phy = 0, .rx_qid = 4, .rx_freeqid = 27, .tx_qid = 24, .tx_doneqid = 31 }, - { .desc = "IXP NPE-C", - .npeid = NPE_C, + [NPE_C] = { .imageid = IXP425_NPE_C_IMAGEID, - .regbase = IXP425_MAC_B_HWBASE, - .regsize = IXP425_MAC_B_SIZE, - .miibase = IXP425_MAC_A_HWBASE, - .miisize = IXP425_MAC_A_SIZE, + .macbase = IXP425_MAC_C_HWBASE, + .miibase = IXP425_MAC_C_HWBASE, .phy = 1, .rx_qid = 12, .rx_freeqid = 28, @@ -219,6 +222,7 @@ WR4(struct npe_softc *sc, bus_size_t off, uint32_t val) static devclass_t npe_devclass; +static int override_npeid(device_t, const char *resname, int *val); static int npe_activate(device_t dev); static void npe_deactivate(device_t dev); static int npe_ifmedia_update(struct ifnet *ifp); @@ -238,6 +242,7 @@ static int npeioctl(struct ifnet * ifp, u_long, caddr_t); static int npe_setrxqosentry(struct npe_softc *, int classix, int trafclass, int qid); +static int npe_setfirewallmode(struct npe_softc *, int onoff); static int npe_updatestats(struct npe_softc *); #if 0 static int npe_getstats(struct npe_softc *); @@ -248,11 +253,11 @@ static int npe_setloopback(struct npe_softc *, int ena); /* NB: all tx done processing goes through one queue */ static int tx_doneqid = -1; -SYSCTL_NODE(_hw, OID_AUTO, npe, CTLFLAG_RD, 0, "IXP425 NPE driver parameters"); +SYSCTL_NODE(_hw, OID_AUTO, npe, CTLFLAG_RD, 0, "IXP4XX NPE driver parameters"); static int npe_debug = 0; SYSCTL_INT(_hw_npe, OID_AUTO, debug, CTLFLAG_RW, &npe_debug, - 0, "IXP425 NPE network interface debug msgs"); + 0, "IXP4XX NPE network interface debug msgs"); TUNABLE_INT("hw.npe.npe", &npe_debug); #define DPRINTF(sc, fmt, ...) do { \ if (sc->sc_debug) device_printf(sc->sc_dev, fmt, __VA_ARGS__); \ @@ -275,16 +280,38 @@ SYSCTL_INT(_hw_npe, OID_AUTO, txbuf, CTLFLAG_RD, &npe_txbuf, TUNABLE_INT("hw.npe.txbuf", &npe_txbuf); static int -npe_probe(device_t dev) +unit2npeid(int unit) { - int unit = device_get_unit(dev); + static const int npeidmap[2][3] = { + /* on 425 A is for HSS, B & C are for Ethernet */ + { NPE_B, NPE_C, -1 }, /* IXP425 */ + /* 435 only has A & C, order C then A */ + { NPE_C, NPE_A, -1 }, /* IXP435 */ + }; + /* XXX check feature register instead */ + return (unit < 3 ? npeidmap[ + (cpu_id() & CPU_ID_CPU_MASK) == CPU_ID_IXP435][unit] : -1); +} - if (unit >= NPE_PORTS_MAX) { - device_printf(dev, "unit %d not supported\n", unit); +static int +npe_probe(device_t dev) +{ + static const char *desc[NPE_MAX] = { + [NPE_A] = "IXP NPE-A", + [NPE_B] = "IXP NPE-B", + [NPE_C] = "IXP NPE-C" + }; + int npeid; + + npeid = -1; + if (!override_npeid(dev, "npeid", &npeid)) + npeid = unit2npeid(device_get_unit(dev)); + if (npeid == -1) { + device_printf(dev, "unit not supported\n"); return EINVAL; } /* XXX check feature register to see if enabled */ - device_set_desc(dev, npeconfig[unit].desc); + device_set_desc(dev, desc[npeid]); return 0; } @@ -295,7 +322,7 @@ npe_attach(device_t dev) struct ixp425_softc *sa = device_get_softc(device_get_parent(dev)); struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev); struct sysctl_oid *tree = device_get_sysctl_tree(dev); - struct ifnet *ifp = NULL; + struct ifnet *ifp; int error; u_char eaddr[6]; @@ -306,26 +333,23 @@ npe_attach(device_t dev) sc->sc_debug = npe_debug; sc->sc_tickinterval = npe_tickinterval; - sc->sc_npe = ixpnpe_attach(dev); - if (sc->sc_npe == NULL) { + ifp = if_alloc(IFT_ETHER); + if (ifp == NULL) { + device_printf(dev, "cannot allocate ifnet\n"); error = EIO; /* XXX */ goto out; } + /* NB: must be setup prior to invoking mii code */ + sc->sc_ifp = ifp; error = npe_activate(dev); - if (error) + if (error) { + device_printf(dev, "cannot activate npe\n"); goto out; + } npe_getmac(sc, eaddr); - /* NB: must be setup prior to invoking mii code */ - sc->sc_ifp = ifp = if_alloc(IFT_ETHER); - if (mii_phy_probe(dev, &sc->sc_mii, npe_ifmedia_update, npe_ifmedia_status)) { - device_printf(dev, "Cannot find my PHY.\n"); - error = ENXIO; - goto out; - } - ifp->if_softc = sc; if_initname(ifp, device_get_name(dev), device_get_unit(dev)); ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; @@ -350,9 +374,10 @@ npe_attach(device_t dev) ether_ifattach(ifp, eaddr); return 0; out: - npe_deactivate(dev); if (ifp != NULL) if_free(ifp); + NPE_LOCK_DESTROY(sc); + npe_deactivate(dev); return error; } @@ -373,8 +398,6 @@ npe_detach(device_t dev) } NPE_LOCK_DESTROY(sc); npe_deactivate(dev); - if (sc->sc_npe != NULL) - ixpnpe_detach(sc->sc_npe); return 0; } @@ -536,7 +559,6 @@ npe_dma_destroy(struct npe_softc *sc, struct npedma *dma) } bus_dmamap_unload(dma->buf_tag, dma->buf_map); bus_dmamem_free(dma->buf_tag, dma->hwbuf, dma->buf_map); - bus_dmamap_destroy(dma->buf_tag, dma->buf_map); } if (dma->buf != NULL) free(dma->buf, M_TEMP); @@ -548,7 +570,7 @@ npe_dma_destroy(struct npe_softc *sc, struct npedma *dma) } static int -override_addr(device_t dev, const char *resname, int *base, int *size) +override_addr(device_t dev, const char *resname, int *base) { int unit = device_get_unit(dev); const char *resval; @@ -558,12 +580,13 @@ override_addr(device_t dev, const char *resname, int *base, int *size) return 0; switch (resval[0]) { case 'A': - *base = IXP425_MAC_A_HWBASE; - *size = IXP425_MAC_A_SIZE; + *base = IXP435_MAC_A_HWBASE; break; case 'B': *base = IXP425_MAC_B_HWBASE; - *size = IXP425_MAC_B_SIZE; + break; + case 'C': + *base = IXP425_MAC_C_HWBASE; break; default: device_printf(dev, "Warning, bad value %s for " @@ -577,6 +600,30 @@ override_addr(device_t dev, const char *resname, int *base, int *size) } static int +override_npeid(device_t dev, const char *resname, int *npeid) +{ + int unit = device_get_unit(dev); + const char *resval; + + /* XXX warn for wrong hint type */ + if (resource_string_value("npe", unit, resname, &resval) != 0) + return 0; + switch (resval[0]) { + case 'A': *npeid = NPE_A; break; + case 'B': *npeid = NPE_B; break; + case 'C': *npeid = NPE_C; break; + default: + device_printf(dev, "Warning, bad value %s for " + "npe.%d.%s ignored\n", resval, unit, resname); + return 0; + } + if (bootverbose) + device_printf(dev, "using npe.%d.%s=%s override\n", + unit, resname, resval); + return 1; +} + +static int override_unit(device_t dev, const char *resname, int *val, int min, int max) { int unit = device_get_unit(dev); @@ -598,12 +645,81 @@ override_unit(device_t dev, const char *resname, int *val, int min, int max) } static int +override_imageid(device_t dev, const char *resname, uint32_t *val) +{ + int unit = device_get_unit(dev); + int resval; + + if (resource_int_value("npe", unit, resname, &resval) != 0) + return 0; + /* XXX validate */ + if (bootverbose) + device_printf(dev, "using npe.%d.%s=0x%x override\n", + unit, resname, resval); + *val = resval; + return 1; +} + +static void +npe_mac_reset(struct npe_softc *sc) +{ + /* + * Reset MAC core. + */ + WR4(sc, NPE_MAC_CORE_CNTRL, NPE_CORE_RESET); + DELAY(NPE_MAC_RESET_DELAY); + /* configure MAC to generate MDC clock */ + WR4(sc, NPE_MAC_CORE_CNTRL, NPE_CORE_MDC_EN); +} + +static int npe_activate(device_t dev) { struct npe_softc * sc = device_get_softc(dev); - int unit = device_get_unit(dev); - int error, i, regbase, regsize, miibase, miisize; - uint32_t imageid; + int error, i, macbase, miibase; + uint32_t imageid, msg[2]; + + /* + * Setup NEP ID, MAC, and MII bindings. We allow override + * via hints to handle unexpected board configs. + */ + if (!override_npeid(dev, "npeid", &sc->sc_npeid)) + sc->sc_npeid = unit2npeid(device_get_unit(dev)); + sc->sc_npe = ixpnpe_attach(dev, sc->sc_npeid); + if (sc->sc_npe == NULL) { + device_printf(dev, "cannot attach ixpnpe\n"); + return EIO; /* XXX */ + } + + /* MAC */ + if (!override_addr(dev, "mac", &macbase)) + macbase = npeconfig[sc->sc_npeid].macbase; + device_printf(sc->sc_dev, "MAC at 0x%x\n", macbase); + if (bus_space_map(sc->sc_iot, macbase, IXP425_REG_SIZE, 0, &sc->sc_ioh)) { + device_printf(dev, "cannot map mac registers 0x%x:0x%x\n", + macbase, IXP425_REG_SIZE); + return ENOMEM; + } + + /* PHY */ + if (!override_unit(dev, "phy", &sc->sc_phy, 0, MII_NPHY-1)) + sc->sc_phy = npeconfig[sc->sc_npeid].phy; + if (!override_addr(dev, "mii", &miibase)) + miibase = npeconfig[sc->sc_npeid].miibase; + device_printf(sc->sc_dev, "MII at 0x%x\n", miibase); + if (miibase != macbase) { + /* + * PHY is mapped through a different MAC, setup an + * additional mapping for frobbing the PHY registers. + */ + if (bus_space_map(sc->sc_iot, miibase, IXP425_REG_SIZE, 0, &sc->sc_miih)) { + device_printf(dev, + "cannot map MII registers 0x%x:0x%x\n", + miibase, IXP425_REG_SIZE); + return ENOMEM; + } + } else + sc->sc_miih = sc->sc_ioh; /* * Load NPE firmware and start it running. We assume @@ -611,47 +727,38 @@ npe_activate(device_t dev) * the firmware image starting with the expected version * and then bump the minor version up to the max. */ - imageid = npeconfig[unit].imageid; + if (!override_imageid(dev, "imageid", &imageid)) + imageid = npeconfig[sc->sc_npeid].imageid; for (;;) { error = ixpnpe_init(sc->sc_npe, "npe_fw", imageid); if (error == 0) break; /* ESRCH is returned when the requested image is not present */ - if (error != ESRCH) + if (error != ESRCH) { + device_printf(dev, "cannot init NPE (error %d)\n", + error); return error; + } /* bump the minor version up to the max possible */ - if (NPEIMAGE_MINOR(imageid) == 0xff) + if (NPEIMAGE_MINOR(imageid) == 0xff) { + device_printf(dev, "cannot locate firmware " + "(imageid 0x%08x)\n", imageid); return error; + } imageid++; } - - if (!override_addr(dev, "mac", ®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 d41905d..01d8c44 100644 --- a/sys/arm/xscale/ixp425/if_npereg.h +++ b/sys/arm/xscale/ixp425/if_npereg.h @@ -84,12 +84,6 @@ struct npehwbuf { } ix_ne[NPE_MAXSEG]; }; -/* NPE ID's */ -#define NPE_A 0 -#define NPE_B 1 -#define NPE_C 2 -#define NPE_MAX (NPE_C+1) - #define NPE_PORTS_MAX 2 /* logical ports */ #define NPE_FRAME_SIZE_DEFAULT 1536 #define NPE_FRAME_SIZE_MAX (65536-64) diff --git a/sys/arm/xscale/ixp425/ixp425.c b/sys/arm/xscale/ixp425/ixp425.c index af87503..d8b2a3f 100644 --- a/sys/arm/xscale/ixp425/ixp425.c +++ b/sys/arm/xscale/ixp425/ixp425.c @@ -58,59 +58,16 @@ __FBSDID("$FreeBSD$"); volatile uint32_t intr_enabled; uint32_t intr_steer = 0; +/* ixp43x et. al have +32 IRQ's */ +volatile uint32_t intr_enabled2; +uint32_t intr_steer2 = 0; + struct ixp425_softc *ixp425_softc = NULL; static int ixp425_probe(device_t); static void ixp425_identify(driver_t *, device_t); static int ixp425_attach(device_t); -static struct { - uint32_t hwbase; - uint32_t size; - uint32_t vbase; -} hwvtrans[] = { - { IXP425_IO_HWBASE, IXP425_IO_SIZE, IXP425_IO_VBASE }, - { IXP425_EXP_HWBASE, IXP425_EXP_SIZE, IXP425_EXP_VBASE }, - { IXP425_PCI_HWBASE, IXP425_PCI_SIZE, IXP425_PCI_VBASE }, - { IXP425_PCI_MEM_HWBASE,IXP425_PCI_MEM_SIZE, IXP425_PCI_MEM_VBASE }, -#if 0 - { IXP425_PCI_IO_HWBASE, IXP425_PCI_IO_SIZE, IXP425_PCI_IO_VBASE }, -#endif - { IXP425_MCU_HWBASE, IXP425_MCU_SIZE, IXP425_MCU_VBASE }, - { IXP425_QMGR_HWBASE, IXP425_QMGR_SIZE, IXP425_QMGR_VBASE }, - { IXP425_NPE_A_HWBASE, IXP425_NPE_A_SIZE, IXP425_NPE_A_VBASE }, - { IXP425_NPE_B_HWBASE, IXP425_NPE_B_SIZE, IXP425_NPE_B_VBASE }, - { IXP425_NPE_C_HWBASE, IXP425_NPE_C_SIZE, IXP425_NPE_C_VBASE }, - { IXP425_MAC_A_HWBASE, IXP425_MAC_A_SIZE, IXP425_MAC_A_VBASE }, - { IXP425_MAC_B_HWBASE, IXP425_MAC_B_SIZE, IXP425_MAC_B_VBASE }, - /* Gateworks Avila IDE/CF is mapped here */ - { IXP425_EXP_BUS_CS1_HWBASE, IXP425_EXP_BUS_SIZE, - IXP425_EXP_BUS_CS1_VBASE }, - { IXP425_EXP_BUS_CS2_HWBASE, IXP425_EXP_BUS_SIZE, - IXP425_EXP_BUS_CS2_VBASE }, - /* ADI Pronghorn Metro IDE/CF is mapped here */ - { IXP425_EXP_BUS_CS3_HWBASE, IXP425_EXP_BUS_SIZE, - IXP425_EXP_BUS_CS3_VBASE }, - { IXP425_EXP_BUS_CS4_HWBASE, IXP425_EXP_BUS_SIZE, - IXP425_EXP_BUS_CS4_VBASE }, -}; - -int -getvbase(uint32_t hwbase, uint32_t size, uint32_t *vbase) -{ - int i; - - for (i = 0; i < sizeof hwvtrans / sizeof *hwvtrans; i++) { - if (hwbase >= hwvtrans[i].hwbase && - hwbase + size <= hwvtrans[i].hwbase + hwvtrans[i].size) { - *vbase = hwbase - hwvtrans[i].hwbase + hwvtrans[i].vbase; - return (0); - } - } - - return (ENOENT); -} - struct arm32_dma_range * bus_dma_get_range(void) { @@ -146,11 +103,16 @@ arm_mask_irq(uintptr_t nb) int i; i = disable_interrupts(I32_bit); - intr_enabled &= ~(1 << nb); - ixp425_set_intrmask(); + if (nb < 32) { + intr_enabled &= ~(1 << nb); + ixp425_set_intrmask(); + } else { + intr_enabled2 &= ~(1 << (nb - 32)); + ixp435_set_intrmask(); + } restore_interrupts(i); /*XXX; If it's a GPIO interrupt, ACK it know. Can it be a problem ?*/ - if ((1 << nb) & IXP425_INT_GPIOMASK) + if (nb < 32 && ((1 << nb) & IXP425_INT_GPIOMASK)) IXPREG(IXP425_GPIO_VBASE + IXP425_GPIO_GPISR) = ixp425_irq2gpio_bit(nb); } @@ -161,8 +123,13 @@ arm_unmask_irq(uintptr_t nb) int i; i = disable_interrupts(I32_bit); - intr_enabled |= (1 << nb); - ixp425_set_intrmask(); + if (nb < 32) { + intr_enabled |= (1 << nb); + ixp425_set_intrmask(); + } else { + intr_enabled2 |= (1 << (nb - 32)); + ixp435_set_intrmask(); + } restore_interrupts(i); } @@ -172,13 +139,21 @@ ixp425_irq_read(void) return IXPREG(IXP425_INT_STATUS) & intr_enabled; } +static __inline uint32_t +ixp435_irq_read(void) +{ + return IXPREG(IXP435_INT_STATUS2) & intr_enabled2; +} + int arm_get_next_irq(void) { - int irq; + uint32_t irq; if ((irq = ixp425_irq_read())) return (ffs(irq) - 1); + if (cpu_is_ixp43x() && (irq = ixp435_irq_read())) + return (32 + ffs(irq) - 1); return (-1); } @@ -206,7 +181,7 @@ ixp425_identify(driver_t *driver, device_t parent) static int ixp425_probe(device_t dev) { - device_set_desc(dev, "Intel IXP425"); + device_set_desc(dev, "Intel IXP4XX"); return (0); } @@ -217,29 +192,34 @@ ixp425_attach(device_t dev) sc = device_get_softc(dev); sc->sc_iot = &ixp425_bs_tag; - KASSERT(ixp425_softc == NULL, ("ixp425_attach called twice?")); + KASSERT(ixp425_softc == NULL, ("%s called twice?", __func__)); ixp425_softc = sc; intr_enabled = 0; ixp425_set_intrmask(); ixp425_set_intrsteer(); + if (cpu_is_ixp43x()) { + intr_enabled2 = 0; + ixp435_set_intrmask(); + ixp435_set_intrsteer(); + } if (bus_dma_tag_create(NULL, 1, 0, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, 0xffffffff, 0xff, 0xffffffff, 0, NULL, NULL, &sc->sc_dmat)) - panic("couldn't create the IXP425 dma tag !"); + panic("%s: failed to create dma tag", __func__); sc->sc_irq_rman.rm_type = RMAN_ARRAY; - sc->sc_irq_rman.rm_descr = "IXP425 IRQs"; + sc->sc_irq_rman.rm_descr = "IXP4XX IRQs"; if (rman_init(&sc->sc_irq_rman) != 0 || - rman_manage_region(&sc->sc_irq_rman, 0, 31) != 0) - panic("ixp425_attach: failed to set up IRQ rman"); + rman_manage_region(&sc->sc_irq_rman, 0, cpu_is_ixp43x() ? 63 : 31) != 0) + panic("%s: failed to set up IRQ rman", __func__); sc->sc_mem_rman.rm_type = RMAN_ARRAY; - sc->sc_mem_rman.rm_descr = "IXP425 Memory"; + sc->sc_mem_rman.rm_descr = "IXP4XX Memory"; if (rman_init(&sc->sc_mem_rman) != 0 || rman_manage_region(&sc->sc_mem_rman, 0, ~0) != 0) - panic("ixp425_attach: failed to set up memory rman"); + panic("%s: failed to set up memory rman", __func__); BUS_ADD_CHILD(dev, 0, "pcib", 0); BUS_ADD_CHILD(dev, 0, "ixpclk", 0); @@ -252,10 +232,10 @@ ixp425_attach(device_t dev) if (bus_space_map(sc->sc_iot, IXP425_GPIO_HWBASE, IXP425_GPIO_SIZE, 0, &sc->sc_gpio_ioh)) - panic("ixp425_attach: unable to map GPIO registers"); + panic("%s: unable to map GPIO registers", __func__); if (bus_space_map(sc->sc_iot, IXP425_EXP_HWBASE, IXP425_EXP_SIZE, 0, &sc->sc_exp_ioh)) - panic("ixp425_attach: unable to map Expansion Bus registers"); + panic("%s: unable to map Expansion Bus registers", __func__); bus_generic_probe(dev); bus_generic_attach(dev); @@ -317,6 +297,44 @@ ixp425_read_ivar(device_t bus, device_t child, int which, u_char *result) return EINVAL; } +/* + * NB: This table handles P->V translations for regions mapped + * through bus_alloc_resource. Anything done with bus_space_map + * is handled elsewhere and does not require an entry here. + * + * XXX getvbase is also used by uart_cpu_getdev (hence public) + */ +static const struct { + uint32_t hwbase; + uint32_t size; + uint32_t vbase; +} hwvtrans[] = { + { IXP425_IO_HWBASE, IXP425_IO_SIZE, IXP425_IO_VBASE }, + { IXP425_PCI_HWBASE, IXP425_PCI_SIZE, IXP425_PCI_VBASE }, + { IXP425_PCI_MEM_HWBASE,IXP425_PCI_MEM_SIZE, IXP425_PCI_MEM_VBASE }, + /* NB: needed only for uart_cpu_getdev */ + { IXP425_UART0_HWBASE, IXP425_REG_SIZE, IXP425_UART0_VBASE }, + { IXP425_UART1_HWBASE, IXP425_REG_SIZE, IXP425_UART1_VBASE }, + /* NB: need for ixp435 ehci controllers */ + { IXP435_USB1_HWBASE, IXP435_USB1_SIZE, IXP435_USB1_VBASE }, + { IXP435_USB2_HWBASE, IXP435_USB2_SIZE, IXP435_USB2_VBASE }, +}; + +int +getvbase(uint32_t hwbase, uint32_t size, uint32_t *vbase) +{ + int i; + + for (i = 0; i < sizeof hwvtrans / sizeof *hwvtrans; i++) { + if (hwbase >= hwvtrans[i].hwbase && + hwbase + size <= hwvtrans[i].hwbase + hwvtrans[i].size) { + *vbase = hwbase - hwvtrans[i].hwbase + hwvtrans[i].vbase; + return (0); + } + } + return (ENOENT); +} + static struct resource * ixp425_alloc_resource(device_t dev, device_t child, int type, int *rid, u_long start, u_long end, u_long count, u_int flags) @@ -346,8 +364,12 @@ ixp425_alloc_resource(device_t dev, device_t child, int type, int *rid, start = addr; end = start + 0x1000; /* XXX */ } - if (getvbase(start, end - start, &vbase)) + if (getvbase(start, end - start, &vbase) != 0) { + /* likely means above table needs to be updated */ + device_printf(dev, "%s: no mapping for 0x%lx:0x%lx\n", + __func__, start, end-start); return NULL; + } rv = rman_reserve_resource(rmanp, start, end, count, flags, child); if (rv != NULL) { @@ -366,22 +388,43 @@ ixp425_alloc_resource(device_t dev, device_t child, int type, int *rid, return rv; } +static __inline void +get_masks(struct resource *res, uint32_t *mask, uint32_t *mask2) +{ + int i; + + *mask = 0; + for (i = rman_get_start(res); i < 32 && i <= rman_get_end(res); i++) + *mask |= 1 << i; + *mask2 = 0; + for (; i <= rman_get_end(res); i++) + *mask2 |= 1 << (i - 32); +} + +static __inline void +update_masks(uint32_t mask, uint32_t mask2) +{ + + intr_enabled = mask; + ixp425_set_intrmask(); + if (cpu_is_ixp43x()) { + intr_enabled2 = mask2; + ixp435_set_intrmask(); + } +} + static int ixp425_setup_intr(device_t dev, device_t child, - struct resource *ires, int flags, driver_filter_t *filt, + struct resource *res, int flags, driver_filter_t *filt, driver_intr_t *intr, void *arg, void **cookiep) { - uint32_t mask; - int i; + uint32_t mask, mask2; - BUS_SETUP_INTR(device_get_parent(dev), child, ires, flags, filt, intr, + BUS_SETUP_INTR(device_get_parent(dev), child, res, flags, filt, intr, arg, cookiep); - mask = 0; - for (i = rman_get_start(ires); i <= rman_get_end(ires); i++) - mask |= 1 << i; - intr_enabled |= mask; - ixp425_set_intrmask(); + get_masks(res, &mask, &mask2); + update_masks(intr_enabled | mask, intr_enabled2 | mask2); return (0); } @@ -390,14 +433,10 @@ static int ixp425_teardown_intr(device_t dev, device_t child, struct resource *res, void *cookie) { - uint32_t mask; - int i; + uint32_t mask, mask2; - mask = 0; - for (i = rman_get_start(res); i <= rman_get_end(res); i++) - mask |= 1 << i; - intr_enabled &= ~mask; - ixp425_set_intrmask(); + get_masks(res, &mask, &mask2); + update_masks(intr_enabled &~ mask, intr_enabled2 &~ mask2); return (BUS_TEARDOWN_INTR(device_get_parent(dev), child, res, cookie)); } diff --git a/sys/arm/xscale/ixp425/ixp425_iic.c b/sys/arm/xscale/ixp425/ixp425_iic.c index 38a86a6..080ebf6 100644 --- a/sys/arm/xscale/ixp425/ixp425_iic.c +++ b/sys/arm/xscale/ixp425/ixp425_iic.c @@ -63,7 +63,7 @@ static struct ixpiic_softc *ixpiic_sc = NULL; static int ixpiic_probe(device_t dev) { - device_set_desc(dev, "IXP425 GPIO-Based I2C Interface"); + device_set_desc(dev, "IXP4XX GPIO-Based I2C Interface"); return (0); } diff --git a/sys/arm/xscale/ixp425/ixp425_intr.h b/sys/arm/xscale/ixp425/ixp425_intr.h index 27217f4..b7724ff 100644 --- a/sys/arm/xscale/ixp425/ixp425_intr.h +++ b/sys/arm/xscale/ixp425/ixp425_intr.h @@ -69,81 +69,21 @@ ixp425_set_intrsteer(void) IXPREG(IXP425_INT_SELECT) = intr_steer & IXP425_INT_HWMASK; } -#define INT_SWMASK \ - ((1U << IXP425_INT_bit31) | (1U << IXP425_INT_bit30) | \ - (1U << IXP425_INT_bit14) | (1U << IXP425_INT_bit11)) +extern __volatile uint32_t intr_enabled2; +extern uint32_t intr_steer2; -#if 0 static __inline void __attribute__((__unused__)) -ixp425_splx(int new) +ixp435_set_intrmask(void) { - extern __volatile uint32_t intr_enabled; - extern __volatile int current_spl_level; - extern __volatile int ixp425_ipending; - extern void ixp425_do_pending(void); - int oldirqstate, hwpend; - - /* Don't let the compiler re-order this code with preceding code */ - __insn_barrier(); - - current_spl_level = new; - - hwpend = (ixp425_ipending & IXP425_INT_HWMASK) & ~new; - if (hwpend != 0) { - oldirqstate = disable_interrupts(I32_bit); - intr_enabled |= hwpend; - ixp425_set_intrmask(); - restore_interrupts(oldirqstate); - } - - if ((ixp425_ipending & INT_SWMASK) & ~new) - ixp425_do_pending(); + IXPREG(IXP435_INT_ENABLE2) = intr_enabled2 & IXP435_INT_HWMASK; } -static __inline int __attribute__((__unused__)) -ixp425_splraise(int ipl) +static __inline void +ixp435_set_intrsteer(void) { - extern __volatile int current_spl_level; - extern int ixp425_imask[]; - int old; - - old = current_spl_level; - current_spl_level |= ixp425_imask[ipl]; - - /* Don't let the compiler re-order this code with subsequent code */ - __insn_barrier(); - - return (old); + IXPREG(IXP435_INT_SELECT2) = intr_steer2 & IXP435_INT_HWMASK; } -static __inline int __attribute__((__unused__)) -ixp425_spllower(int ipl) -{ - extern __volatile int current_spl_level; - extern int ixp425_imask[]; - int old = current_spl_level; - - ixp425_splx(ixp425_imask[ipl]); - return(old); -} - -#endif -#if !defined(EVBARM_SPL_NOINLINE) - -#define splx(new) ixp425_splx(new) -#define _spllower(ipl) ixp425_spllower(ipl) -#define _splraise(ipl) ixp425_splraise(ipl) -void _setsoftintr(int); - -#else - -int _splraise(int); -int _spllower(int); -void splx(int); -void _setsoftintr(int); - -#endif /* ! EVBARM_SPL_NOINLINE */ - #endif /* _LOCORE */ #endif /* _IXP425_INTR_H_ */ diff --git a/sys/arm/xscale/ixp425/ixp425_mem.c b/sys/arm/xscale/ixp425/ixp425_mem.c index 7312d0f..0458a83 100644 --- a/sys/arm/xscale/ixp425/ixp425_mem.c +++ b/sys/arm/xscale/ixp425/ixp425_mem.c @@ -62,11 +62,10 @@ static uint32_t sdram_other[] = { 0, 0 }; -#define MCU_REG_READ(x) (*(volatile uint32_t *)(IXP425_MCU_VBASE + (x))) - uint32_t ixp425_sdram_size(void) { +#define MCU_REG_READ(x) (*(volatile uint32_t *)(IXP425_MCU_VBASE + (x))) uint32_t size, sdr_config; sdr_config = MCU_REG_READ(MCU_SDR_CONFIG); @@ -82,4 +81,22 @@ ixp425_sdram_size(void) } return (size); +#undef MCU_REG_READ +} + +uint32_t +ixp435_ddram_size(void) +{ +#define MCU_REG_READ(x) (*(volatile uint32_t *)(IXP425_MCU_VBASE + (x))) + uint32_t sbr0; + + /* + * Table 198, page 516 shows DDR-I/II SDRAM bank sizes + * for SBR0 and SBR1. The manual states both banks must + * be programmed to be the same size. We just assume + * it's done right and calculate 2x for the memory size. + */ + sbr0 = MCU_REG_READ(MCU_DDR_SBR0); + return 2 * 16*(sbr0 & 0x7f) * 1024 * 1024; +#undef MCU_REG_READ } diff --git a/sys/arm/xscale/ixp425/ixp425_npe.c b/sys/arm/xscale/ixp425/ixp425_npe.c index a35a4ad..ea1928a 100644 --- a/sys/arm/xscale/ixp425/ixp425_npe.c +++ b/sys/arm/xscale/ixp425/ixp425_npe.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2006 Sam Leffler, Errno Consulting + * Copyright (c) 2006-2008 Sam Leffler, Errno Consulting * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -103,23 +103,23 @@ __FBSDID("$FreeBSD$"); #include <arm/xscale/ixp425/ixp425_npevar.h> struct ixpnpe_softc { - device_t sc_dev; - bus_space_tag_t sc_iot; - bus_space_handle_t sc_ioh; - bus_size_t sc_size; /* size of mapped register window */ - struct resource *sc_irq; /* IRQ resource */ - void *sc_ih; /* interrupt handler */ - struct mtx sc_mtx; /* mailbox lock */ - uint32_t sc_msg[2]; /* reply msg collected in ixpnpe_intr */ - int sc_msgwaiting; /* sc_msg holds valid data */ - - int validImage; /* valid ucode image loaded */ - int started; /* NPE is started */ - uint8_t functionalityId;/* ucode functionality ID */ - int insMemSize; /* size of instruction memory */ - int dataMemSize; /* size of data memory */ - uint32_t savedExecCount; - uint32_t savedEcsDbgCtxtReg2; + device_t sc_dev; + bus_space_tag_t sc_iot; + bus_space_handle_t sc_ioh; + bus_size_t sc_size; /* size of mapped register window */ + struct resource *sc_irq; /* IRQ resource */ + void *sc_ih; /* interrupt handler */ + struct mtx sc_mtx; /* mailbox lock */ + uint32_t sc_msg[2]; /* reply msg collected in ixpnpe_intr */ + int sc_msgwaiting; /* sc_msg holds valid data */ + + int validImage; /* valid ucode image loaded */ + int started; /* NPE is started */ + uint8_t functionalityId;/* ucode functionality ID */ + int insMemSize; /* size of instruction memory */ + int dataMemSize; /* size of data memory */ + uint32_t savedExecCount; + uint32_t savedEcsDbgCtxtReg2; }; #define IX_NPEDL_NPEIMAGE_FIELD_MASK 0xff @@ -144,42 +144,42 @@ struct ixpnpe_softc { #define IX_NPEDL_STATE_INFO_ENTRY_SIZE 2 typedef struct { - uint32_t type; - uint32_t offset; + uint32_t type; + uint32_t offset; } IxNpeDlNpeMgrDownloadMapBlockEntry; typedef union { - IxNpeDlNpeMgrDownloadMapBlockEntry block; - uint32_t eodmMarker; + IxNpeDlNpeMgrDownloadMapBlockEntry block; + uint32_t eodmMarker; } IxNpeDlNpeMgrDownloadMapEntry; typedef struct { - /* 1st entry in the download map (there may be more than one) */ - IxNpeDlNpeMgrDownloadMapEntry entry[1]; + /* 1st entry in the download map (there may be more than one) */ + IxNpeDlNpeMgrDownloadMapEntry entry[1]; } IxNpeDlNpeMgrDownloadMap; /* used to access an instruction or data block in a microcode image */ typedef struct { - uint32_t npeMemAddress; - uint32_t size; - uint32_t data[1]; + uint32_t npeMemAddress; + uint32_t size; + uint32_t data[1]; } IxNpeDlNpeMgrCodeBlock; /* used to access each Context Reg entry state-information block */ typedef struct { - uint32_t addressInfo; - uint32_t value; + uint32_t addressInfo; + uint32_t value; } IxNpeDlNpeMgrStateInfoCtxtRegEntry; /* used to access a state-information block in a microcode image */ typedef struct { - uint32_t size; - IxNpeDlNpeMgrStateInfoCtxtRegEntry ctxtRegEntry[1]; + uint32_t size; + IxNpeDlNpeMgrStateInfoCtxtRegEntry ctxtRegEntry[1]; } IxNpeDlNpeMgrStateInfoBlock; static int npe_debug = 0; SYSCTL_INT(_debug, OID_AUTO, ixp425npe, CTLFLAG_RW, &npe_debug, - 0, "IXP425 NPE debug msgs"); + 0, "IXP4XX NPE debug msgs"); TUNABLE_INT("debug.ixp425npe", &npe_debug); #define DPRINTF(dev, fmt, ...) do { \ if (npe_debug) device_printf(dev, fmt, __VA_ARGS__); \ @@ -233,116 +233,140 @@ static void ixpnpe_intr(void *arg); static uint32_t npe_reg_read(struct ixpnpe_softc *sc, bus_size_t off) { - uint32_t v = bus_space_read_4(sc->sc_iot, sc->sc_ioh, off); - DPRINTFn(9, sc->sc_dev, "%s(0x%lx) => 0x%x\n", __func__, off, v); - return v; + uint32_t v = bus_space_read_4(sc->sc_iot, sc->sc_ioh, off); + DPRINTFn(9, sc->sc_dev, "%s(0x%lx) => 0x%x\n", __func__, off, v); + return v; } static void npe_reg_write(struct ixpnpe_softc *sc, bus_size_t off, uint32_t val) { - DPRINTFn(9, sc->sc_dev, "%s(0x%lx, 0x%x)\n", __func__, off, val); - bus_space_write_4(sc->sc_iot, sc->sc_ioh, off, val); + DPRINTFn(9, sc->sc_dev, "%s(0x%lx, 0x%x)\n", __func__, off, val); + bus_space_write_4(sc->sc_iot, sc->sc_ioh, off, val); } struct ixpnpe_softc * -ixpnpe_attach(device_t dev) +ixpnpe_attach(device_t dev, int npeid) { - struct ixp425_softc *sa = device_get_softc(device_get_parent(dev)); - struct ixpnpe_softc *sc; - bus_addr_t base; - int rid, irq; - - /* XXX M_BUS */ - sc = malloc(sizeof(struct ixpnpe_softc), M_TEMP, M_WAITOK | M_ZERO); - sc->sc_dev = dev; - sc->sc_iot = sa->sc_iot; - mtx_init(&sc->sc_mtx, device_get_nameunit(dev), "npe driver", MTX_DEF); - - if (device_get_unit(dev) == 0) { - base = IXP425_NPE_B_HWBASE; - sc->sc_size = IXP425_NPE_B_SIZE; - irq = IXP425_INT_NPE_B; - - /* size of instruction memory */ - sc->insMemSize = IX_NPEDL_INS_MEMSIZE_WORDS_NPEB; - /* size of data memory */ - sc->dataMemSize = IX_NPEDL_DATA_MEMSIZE_WORDS_NPEB; - } else { - base = IXP425_NPE_C_HWBASE; - sc->sc_size = IXP425_NPE_C_SIZE; - irq = IXP425_INT_NPE_C; - - /* size of instruction memory */ - sc->insMemSize = IX_NPEDL_INS_MEMSIZE_WORDS_NPEC; - /* size of data memory */ - sc->dataMemSize = IX_NPEDL_DATA_MEMSIZE_WORDS_NPEC; - } - if (bus_space_map(sc->sc_iot, base, sc->sc_size, 0, &sc->sc_ioh)) - panic("%s: Cannot map registers", device_get_name(dev)); - - /* - * Setup IRQ and handler for NPE message support. - */ - rid = 0; - sc->sc_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, - irq, irq, 1, RF_ACTIVE); - if (!sc->sc_irq) - panic("%s: Unable to allocate irq %u", device_get_name(dev), irq); - /* XXX could be a source of entropy */ - bus_setup_intr(dev, sc->sc_irq, INTR_TYPE_NET | INTR_MPSAFE, - NULL, ixpnpe_intr, sc, &sc->sc_ih); - /* enable output fifo interrupts (NB: must also set OFIFO Write Enable) */ - npe_reg_write(sc, IX_NPECTL, - npe_reg_read(sc, IX_NPECTL) | (IX_NPECTL_OFE | IX_NPECTL_OFWE)); - - return sc; + struct npeconfig { + uint32_t base; + uint32_t size; + int irq; + uint32_t ins_memsize; + uint32_t data_memsize; + }; + static const struct npeconfig npeconfigs[NPE_MAX] = { + [NPE_A] = { + .base = IXP425_NPE_A_HWBASE, + .size = IXP425_NPE_A_SIZE, + .irq = IXP425_INT_NPE_A, + .ins_memsize = IX_NPEDL_INS_MEMSIZE_WORDS_NPEA, + .data_memsize = IX_NPEDL_DATA_MEMSIZE_WORDS_NPEA + }, + [NPE_B] = { + .base = IXP425_NPE_B_HWBASE, + .size = IXP425_NPE_B_SIZE, + .irq = IXP425_INT_NPE_B, + .ins_memsize = IX_NPEDL_INS_MEMSIZE_WORDS_NPEB, + .data_memsize = IX_NPEDL_DATA_MEMSIZE_WORDS_NPEB + }, + [NPE_C] = { + .base = IXP425_NPE_C_HWBASE, + .size = IXP425_NPE_C_SIZE, + .irq = IXP425_INT_NPE_C, + .ins_memsize = IX_NPEDL_INS_MEMSIZE_WORDS_NPEC, + .data_memsize = IX_NPEDL_DATA_MEMSIZE_WORDS_NPEC + }, + }; + struct ixp425_softc *sa = device_get_softc(device_get_parent(dev)); + struct ixpnpe_softc *sc; + const struct npeconfig *config; + int rid; + + if (npeid >= NPE_MAX) { + device_printf(dev, "%s: bad npeid %d\n", __func__, npeid); + return NULL; + } + config = &npeconfigs[npeid]; + + /* XXX M_BUS */ + sc = malloc(sizeof(struct ixpnpe_softc), M_TEMP, M_WAITOK | M_ZERO); + sc->sc_dev = dev; + sc->sc_iot = sa->sc_iot; + mtx_init(&sc->sc_mtx, device_get_nameunit(dev), "npe driver", MTX_DEF); + + sc->sc_size = config->size; + sc->insMemSize = config->ins_memsize; /* size of instruction memory */ + sc->dataMemSize = config->data_memsize; /* size of data memory */ + + if (bus_space_map(sc->sc_iot, config->base, sc->sc_size, 0, &sc->sc_ioh)) + panic("%s: Cannot map registers", device_get_name(dev)); + + /* + * Setup IRQ and handler for NPE message support. + */ + rid = 0; + sc->sc_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, + config->irq, config->irq, 1, RF_ACTIVE); + if (sc->sc_irq == NULL) + panic("%s: Unable to allocate irq %u", device_get_name(dev), + config->irq); + /* XXX could be a source of entropy */ + bus_setup_intr(dev, sc->sc_irq, INTR_TYPE_NET | INTR_MPSAFE, + NULL, ixpnpe_intr, sc, &sc->sc_ih); + /* + * Enable output fifo interrupts (NB: must also set OFIFO Write Enable) + */ + npe_reg_write(sc, IX_NPECTL, + npe_reg_read(sc, IX_NPECTL) | (IX_NPECTL_OFE | IX_NPECTL_OFWE)); + + return sc; } void ixpnpe_detach(struct ixpnpe_softc *sc) { - /* disable output fifo interrupts */ - npe_reg_write(sc, IX_NPECTL, - npe_reg_read(sc, IX_NPECTL) &~ (IX_NPECTL_OFE | IX_NPECTL_OFWE)); - - bus_teardown_intr(sc->sc_dev, sc->sc_irq, sc->sc_ih); - bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_size); - mtx_destroy(&sc->sc_mtx); - free(sc, M_TEMP); + /* disable output fifo interrupts */ + npe_reg_write(sc, IX_NPECTL, + npe_reg_read(sc, IX_NPECTL) &~ (IX_NPECTL_OFE | IX_NPECTL_OFWE)); + + bus_teardown_intr(sc->sc_dev, sc->sc_irq, sc->sc_ih); + bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_size); + mtx_destroy(&sc->sc_mtx); + free(sc, M_TEMP); } int ixpnpe_stopandreset(struct ixpnpe_softc *sc) { - int error; - - mtx_lock(&sc->sc_mtx); - error = npe_cpu_stop(sc); /* stop NPE */ - if (error == 0) - error = npe_cpu_reset(sc); /* reset it */ - if (error == 0) - sc->started = 0; /* mark stopped */ - mtx_unlock(&sc->sc_mtx); - - DPRINTF(sc->sc_dev, "%s: error %d\n", __func__, error); - return error; + int error; + + mtx_lock(&sc->sc_mtx); + error = npe_cpu_stop(sc); /* stop NPE */ + if (error == 0) + error = npe_cpu_reset(sc); /* reset it */ + if (error == 0) + sc->started = 0; /* mark stopped */ + mtx_unlock(&sc->sc_mtx); + + DPRINTF(sc->sc_dev, "%s: error %d\n", __func__, error); + return error; } static int ixpnpe_start_locked(struct ixpnpe_softc *sc) { - int error; + int error; - if (!sc->started) { - error = npe_cpu_start(sc); - if (error == 0) - sc->started = 1; - } else - error = 0; + if (!sc->started) { + error = npe_cpu_start(sc); + if (error == 0) + sc->started = 1; + } else + error = 0; - DPRINTF(sc->sc_dev, "%s: error %d\n", __func__, error); - return error; + DPRINTF(sc->sc_dev, "%s: error %d\n", __func__, error); + return error; } int @@ -359,16 +383,16 @@ ixpnpe_start(struct ixpnpe_softc *sc) int ixpnpe_stop(struct ixpnpe_softc *sc) { - int error; + int error; - mtx_lock(&sc->sc_mtx); - error = npe_cpu_stop(sc); - if (error == 0) - sc->started = 0; - mtx_unlock(&sc->sc_mtx); + mtx_lock(&sc->sc_mtx); + error = npe_cpu_stop(sc); + if (error == 0) + sc->started = 0; + mtx_unlock(&sc->sc_mtx); - DPRINTF(sc->sc_dev, "%s: error %d\n", __func__, error); - return error; + DPRINTF(sc->sc_dev, "%s: error %d\n", __func__, error); + return error; } /* @@ -381,9 +405,9 @@ ixpnpe_stop(struct ixpnpe_softc *sc) * NPE Image Header definition, used in new NPE Image Library format */ typedef struct { - uint32_t marker; - uint32_t id; - uint32_t size; + uint32_t marker; + uint32_t id; + uint32_t size; } IxNpeDlImageMgrImageHeader; static int @@ -391,202 +415,218 @@ npe_findimage(struct ixpnpe_softc *sc, const uint32_t *imageLibrary, uint32_t imageId, const uint32_t **imagePtr, uint32_t *imageSize) { - const IxNpeDlImageMgrImageHeader *image; - uint32_t offset = 0; - - while (imageLibrary[offset] == NPE_IMAGE_MARKER) { - image = (const IxNpeDlImageMgrImageHeader *)&imageLibrary[offset]; - offset += sizeof(IxNpeDlImageMgrImageHeader)/sizeof(uint32_t); - - DPRINTF(sc->sc_dev, "%s: off %u mark 0x%x id 0x%x size %u\n", - __func__, offset, image->marker, image->id, image->size); - if (image->id == imageId) { - *imagePtr = imageLibrary + offset; - *imageSize = image->size; - return 0; - } - /* 2 consecutive NPE_IMAGE_MARKER's indicates end of library */ - if (image->id == NPE_IMAGE_MARKER) { - DPRINTF(sc->sc_dev, - "imageId 0x%08x not found in image library header\n", imageId); - /* reached end of library, image not found */ - return ESRCH; - } - offset += image->size; - } - return ESRCH; + const IxNpeDlImageMgrImageHeader *image; + uint32_t offset = 0; + + while (imageLibrary[offset] == NPE_IMAGE_MARKER) { + image = (const IxNpeDlImageMgrImageHeader *) + &imageLibrary[offset]; + offset += sizeof(IxNpeDlImageMgrImageHeader)/sizeof(uint32_t); + + DPRINTF(sc->sc_dev, "%s: off %u mark 0x%x id 0x%x size %u\n", + __func__, offset, image->marker, image->id, image->size); + if (image->id == imageId) { + *imagePtr = imageLibrary + offset; + *imageSize = image->size; + return 0; + } + /* 2 consecutive NPE_IMAGE_MARKER's indicates end of library */ + if (image->id == NPE_IMAGE_MARKER) { + DPRINTF(sc->sc_dev, "imageId 0x%08x not found in " + "image library header\n", imageId); + /* reached end of library, image not found */ + return ESRCH; + } + offset += image->size; + } + return ESRCH; } int ixpnpe_init(struct ixpnpe_softc *sc, const char *imageName, uint32_t imageId) { - uint32_t imageSize; - const uint32_t *imageCodePtr; - const struct firmware *fw; - int error; + static const char *devname[4] = + { "IXP425", "IXP435/IXP465", "DeviceID#2", "DeviceID#3" }; + uint32_t imageSize; + const uint32_t *imageCodePtr; + const struct firmware *fw; + int error; - DPRINTF(sc->sc_dev, "load %s, imageId 0x%08x\n", imageName, imageId); + DPRINTF(sc->sc_dev, "load %s, imageId 0x%08x\n", imageName, imageId); #if 0 - IxFeatureCtrlDeviceId devid = IX_NPEDL_DEVICEID_FROM_IMAGEID_GET(imageId); - /* - * Checking if image being loaded is meant for device that is running. - * Image is forward compatible. i.e Image built for IXP42X should run - * on IXP46X but not vice versa. - */ - if (devid > (ixFeatureCtrlDeviceRead() & IX_FEATURE_CTRL_DEVICE_TYPE_MASK)) - return EINVAL; + IxFeatureCtrlDeviceId devid = IX_NPEDL_DEVICEID_FROM_IMAGEID_GET(imageId); + /* + * Checking if image being loaded is meant for device that is running. + * Image is forward compatible. i.e Image built for IXP42X should run + * on IXP46X but not vice versa. + */ + if (devid > (ixFeatureCtrlDeviceRead() & IX_FEATURE_CTRL_DEVICE_TYPE_MASK)) + return EINVAL; #endif - error = ixpnpe_stopandreset(sc); /* stop and reset the NPE */ - if (error != 0) - return error; + error = ixpnpe_stopandreset(sc); /* stop and reset the NPE */ + if (error != 0) + return error; + + fw = firmware_get(imageName); + if (fw == NULL) + return ENOENT; + + /* Locate desired image in files w/ combined images */ + error = npe_findimage(sc, fw->data, imageId, &imageCodePtr, &imageSize); + if (error != 0) + goto done; + + device_printf(sc->sc_dev, + "load fw image %s.NPE-%c Func 0x%x Rev %u.%u\n", + devname[NPEIMAGE_DEVID(imageId)], 'A' + NPEIMAGE_NPEID(imageId), + NPEIMAGE_FUNCID(imageId), NPEIMAGE_MAJOR(imageId), + NPEIMAGE_MINOR(imageId)); - fw = firmware_get(imageName); - if (fw == NULL) - return ENOENT; - - /* Locate desired image in files w/ combined images */ - error = npe_findimage(sc, fw->data, imageId, &imageCodePtr, &imageSize); - if (error != 0) - goto done; - - /* - * If download was successful, store image Id in list of - * currently loaded images. If a critical error occured - * during download, record that the NPE has an invalid image - */ - mtx_lock(&sc->sc_mtx); - error = npe_load_image(sc, imageCodePtr, 1 /*VERIFY*/); - if (error == 0) { - sc->validImage = 1; - error = ixpnpe_start_locked(sc); - } else { - sc->validImage = 0; - } - sc->functionalityId = IX_NPEDL_FUNCTIONID_FROM_IMAGEID_GET(imageId); - mtx_unlock(&sc->sc_mtx); + /* + * If download was successful, store image Id in list of + * currently loaded images. If a critical error occured + * during download, record that the NPE has an invalid image + */ + mtx_lock(&sc->sc_mtx); + error = npe_load_image(sc, imageCodePtr, 1 /*VERIFY*/); + if (error == 0) { + sc->validImage = 1; + error = ixpnpe_start_locked(sc); + } else { + sc->validImage = 0; + } + sc->functionalityId = IX_NPEDL_FUNCTIONID_FROM_IMAGEID_GET(imageId); + mtx_unlock(&sc->sc_mtx); done: - firmware_put(fw, FIRMWARE_UNLOAD); - DPRINTF(sc->sc_dev, "%s: error %d\n", __func__, error); - return error; + firmware_put(fw, FIRMWARE_UNLOAD); + DPRINTF(sc->sc_dev, "%s: error %d\n", __func__, error); + return error; } int ixpnpe_getfunctionality(struct ixpnpe_softc *sc) { - return (sc->validImage ? sc->functionalityId : 0); + return (sc->validImage ? sc->functionalityId : 0); } static int npe_checkbits(struct ixpnpe_softc *sc, uint32_t reg, uint32_t expectedBitsSet) { - uint32_t val; + uint32_t val; - val = npe_reg_read(sc, reg); - DPRINTFn(5, sc->sc_dev, "%s(0x%x, 0x%x) => 0x%x (%u)\n", - __func__, reg, expectedBitsSet, val, - (val & expectedBitsSet) == expectedBitsSet); - return ((val & expectedBitsSet) == expectedBitsSet); + val = npe_reg_read(sc, reg); + DPRINTFn(5, sc->sc_dev, "%s(0x%x, 0x%x) => 0x%x (%u)\n", + __func__, reg, expectedBitsSet, val, + (val & expectedBitsSet) == expectedBitsSet); + return ((val & expectedBitsSet) == expectedBitsSet); } static int npe_isstopped(struct ixpnpe_softc *sc) { - return npe_checkbits(sc, - IX_NPEDL_REG_OFFSET_EXCTL, IX_NPEDL_EXCTL_STATUS_STOP); + return npe_checkbits(sc, + IX_NPEDL_REG_OFFSET_EXCTL, IX_NPEDL_EXCTL_STATUS_STOP); } static int npe_load_ins(struct ixpnpe_softc *sc, const IxNpeDlNpeMgrCodeBlock *bp, int verify) { - uint32_t npeMemAddress; - int i, blockSize; - - npeMemAddress = bp->npeMemAddress; - blockSize = bp->size; /* NB: instruction/data count */ - if (npeMemAddress + blockSize > sc->insMemSize) { - device_printf(sc->sc_dev, "Block size too big for NPE memory\n"); - return EINVAL; /* XXX */ - } - for (i = 0; i < blockSize; i++, npeMemAddress++) { - if (npe_ins_write(sc, npeMemAddress, bp->data[i], verify) != 0) { - device_printf(sc->sc_dev, "NPE instruction write failed"); - return EIO; + uint32_t npeMemAddress; + int i, blockSize; + + npeMemAddress = bp->npeMemAddress; + blockSize = bp->size; /* NB: instruction/data count */ + if (npeMemAddress + blockSize > sc->insMemSize) { + device_printf(sc->sc_dev, + "Block size %u too big for NPE memory\n", blockSize); + return EINVAL; /* XXX */ + } + for (i = 0; i < blockSize; i++, npeMemAddress++) { + if (npe_ins_write(sc, npeMemAddress, bp->data[i], verify) != 0) { + device_printf(sc->sc_dev, + "NPE instruction write failed"); + return EIO; + } } - } - return 0; + return 0; } static int npe_load_data(struct ixpnpe_softc *sc, const IxNpeDlNpeMgrCodeBlock *bp, int verify) { - uint32_t npeMemAddress; - int i, blockSize; - - npeMemAddress = bp->npeMemAddress; - blockSize = bp->size; /* NB: instruction/data count */ - if (npeMemAddress + blockSize > sc->dataMemSize) { - device_printf(sc->sc_dev, "Block size too big for NPE memory\n"); - return EINVAL; - } - for (i = 0; i < blockSize; i++, npeMemAddress++) { - if (npe_data_write(sc, npeMemAddress, bp->data[i], verify) != 0) { - device_printf(sc->sc_dev, "NPE data write failed\n"); - return EIO; + uint32_t npeMemAddress; + int i, blockSize; + + npeMemAddress = bp->npeMemAddress; + blockSize = bp->size; /* NB: instruction/data count */ + if (npeMemAddress + blockSize > sc->dataMemSize) { + device_printf(sc->sc_dev, + "Block size %u too big for NPE memory\n", blockSize); + return EINVAL; } - } - return 0; + for (i = 0; i < blockSize; i++, npeMemAddress++) { + if (npe_data_write(sc, npeMemAddress, bp->data[i], verify) != 0) { + device_printf(sc->sc_dev, "NPE data write failed\n"); + return EIO; + } + } + return 0; } static int npe_load_stateinfo(struct ixpnpe_softc *sc, const IxNpeDlNpeMgrStateInfoBlock *bp, int verify) { - int i, nentries, error; - - npe_cpu_step_save(sc); - - /* for each state-info context register entry in block */ - nentries = bp->size / IX_NPEDL_STATE_INFO_ENTRY_SIZE; - error = 0; - for (i = 0; i < nentries; i++) { - /* each state-info entry is 2 words (address, value) in length */ - uint32_t regVal = bp->ctxtRegEntry[i].value; - uint32_t addrInfo = bp->ctxtRegEntry[i].addressInfo; - - uint32_t reg = (addrInfo & IX_NPEDL_MASK_STATE_ADDR_CTXT_REG); - uint32_t cNum = (addrInfo & IX_NPEDL_MASK_STATE_ADDR_CTXT_NUM) >> - IX_NPEDL_OFFSET_STATE_ADDR_CTXT_NUM; - - /* error-check Context Register No. and Context Number values */ - if (!(0 <= reg && reg < IX_NPEDL_CTXT_REG_MAX)) { - device_printf(sc->sc_dev, "invalid Context Register %u\n", reg); - error = EINVAL; - break; - } - if (!(0 <= cNum && cNum < IX_NPEDL_CTXT_NUM_MAX)) { - device_printf(sc->sc_dev, "invalid Context Number %u\n", cNum); - error = EINVAL; - break; - } - /* NOTE that there is no STEVT register for Context 0 */ - if (cNum == 0 && reg == IX_NPEDL_CTXT_REG_STEVT) { - device_printf(sc->sc_dev, "no STEVT for Context 0\n"); - error = EINVAL; - break; - } + int i, nentries, error; + + npe_cpu_step_save(sc); - if (npe_ctx_reg_write(sc, cNum, reg, regVal, verify) != 0) { - device_printf(sc->sc_dev, "write of state-info to NPE failed\n"); - error = EIO; - break; + /* for each state-info context register entry in block */ + nentries = bp->size / IX_NPEDL_STATE_INFO_ENTRY_SIZE; + error = 0; + for (i = 0; i < nentries; i++) { + /* each state-info entry is 2 words (address, value) */ + uint32_t regVal = bp->ctxtRegEntry[i].value; + uint32_t addrInfo = bp->ctxtRegEntry[i].addressInfo; + + uint32_t reg = (addrInfo & IX_NPEDL_MASK_STATE_ADDR_CTXT_REG); + uint32_t cNum = (addrInfo & IX_NPEDL_MASK_STATE_ADDR_CTXT_NUM) >> + IX_NPEDL_OFFSET_STATE_ADDR_CTXT_NUM; + + /* error-check Context Register No. and Context Number values */ + if (!(0 <= reg && reg < IX_NPEDL_CTXT_REG_MAX)) { + device_printf(sc->sc_dev, + "invalid Context Register %u\n", reg); + error = EINVAL; + break; + } + if (!(0 <= cNum && cNum < IX_NPEDL_CTXT_NUM_MAX)) { + device_printf(sc->sc_dev, + "invalid Context Number %u\n", cNum); + error = EINVAL; + break; + } + /* NOTE that there is no STEVT register for Context 0 */ + if (cNum == 0 && reg == IX_NPEDL_CTXT_REG_STEVT) { + device_printf(sc->sc_dev, + "no STEVT for Context 0\n"); + error = EINVAL; + break; + } + + if (npe_ctx_reg_write(sc, cNum, reg, regVal, verify) != 0) { + device_printf(sc->sc_dev, + "write of state-info to NPE failed\n"); + error = EIO; + break; + } } - } - npe_cpu_step_restore(sc); - return error; + npe_cpu_step_restore(sc); + return error; } static int @@ -594,79 +634,84 @@ npe_load_image(struct ixpnpe_softc *sc, const uint32_t *imageCodePtr, int verify) { #define EOM(marker) ((marker) == IX_NPEDL_END_OF_DOWNLOAD_MAP) - const IxNpeDlNpeMgrDownloadMap *downloadMap; - int i, error; - - if (!npe_isstopped(sc)) { /* verify NPE is stopped */ - device_printf(sc->sc_dev, "cannot load image, NPE not stopped\n"); - return EIO; - } - - /* - * Read Download Map, checking each block type and calling - * appropriate function to perform download - */ - error = 0; - downloadMap = (const IxNpeDlNpeMgrDownloadMap *) imageCodePtr; - for (i = 0; !EOM(downloadMap->entry[i].eodmMarker); i++) { - /* calculate pointer to block to be downloaded */ - const uint32_t *bp = imageCodePtr + downloadMap->entry[i].block.offset; - switch (downloadMap->entry[i].block.type) { - case IX_NPEDL_BLOCK_TYPE_INSTRUCTION: - error = npe_load_ins(sc, - (const IxNpeDlNpeMgrCodeBlock *) bp, verify); - DPRINTF(sc->sc_dev, "%s: inst, error %d\n", __func__, error); - break; - case IX_NPEDL_BLOCK_TYPE_DATA: - error = npe_load_data(sc, - (const IxNpeDlNpeMgrCodeBlock *) bp, verify); - DPRINTF(sc->sc_dev, "%s: data, error %d\n", __func__, error); - break; - case IX_NPEDL_BLOCK_TYPE_STATE: - error = npe_load_stateinfo(sc, - (const IxNpeDlNpeMgrStateInfoBlock *) bp, verify); - DPRINTF(sc->sc_dev, "%s: state, error %d\n", __func__, error); - break; - default: - device_printf(sc->sc_dev, - "unknown block type 0x%x in download map\n", - downloadMap->entry[i].block.type); - error = EIO; /* XXX */ - break; + const IxNpeDlNpeMgrDownloadMap *downloadMap; + int i, error; + + if (!npe_isstopped(sc)) { /* verify NPE is stopped */ + device_printf(sc->sc_dev, + "cannot load image, NPE not stopped\n"); + return EIO; } - if (error != 0) - break; - } - return error; + + /* + * Read Download Map, checking each block type and calling + * appropriate function to perform download + */ + error = 0; + downloadMap = (const IxNpeDlNpeMgrDownloadMap *) imageCodePtr; + for (i = 0; !EOM(downloadMap->entry[i].eodmMarker); i++) { + /* calculate pointer to block to be downloaded */ + const uint32_t *bp = imageCodePtr + + downloadMap->entry[i].block.offset; + switch (downloadMap->entry[i].block.type) { + case IX_NPEDL_BLOCK_TYPE_INSTRUCTION: + error = npe_load_ins(sc, + (const IxNpeDlNpeMgrCodeBlock *) bp, verify); + DPRINTF(sc->sc_dev, "%s: inst, error %d\n", + __func__, error); + break; + case IX_NPEDL_BLOCK_TYPE_DATA: + error = npe_load_data(sc, + (const IxNpeDlNpeMgrCodeBlock *) bp, verify); + DPRINTF(sc->sc_dev, "%s: data, error %d\n", + __func__, error); + break; + case IX_NPEDL_BLOCK_TYPE_STATE: + error = npe_load_stateinfo(sc, + (const IxNpeDlNpeMgrStateInfoBlock *) bp, verify); + DPRINTF(sc->sc_dev, "%s: state, error %d\n", + __func__, error); + break; + default: + device_printf(sc->sc_dev, + "unknown block type 0x%x in download map\n", + downloadMap->entry[i].block.type); + error = EIO; /* XXX */ + break; + } + if (error != 0) + break; + } + return error; #undef EOM } /* contains Reset values for Context Store Registers */ static const struct { - uint32_t regAddr; - uint32_t regResetVal; + uint32_t regAddr; + uint32_t regResetVal; } ixNpeDlEcsRegResetValues[] = { - { IX_NPEDL_ECS_BG_CTXT_REG_0, IX_NPEDL_ECS_BG_CTXT_REG_0_RESET }, - { IX_NPEDL_ECS_BG_CTXT_REG_1, IX_NPEDL_ECS_BG_CTXT_REG_1_RESET }, - { IX_NPEDL_ECS_BG_CTXT_REG_2, IX_NPEDL_ECS_BG_CTXT_REG_2_RESET }, - { IX_NPEDL_ECS_PRI_1_CTXT_REG_0, IX_NPEDL_ECS_PRI_1_CTXT_REG_0_RESET }, - { IX_NPEDL_ECS_PRI_1_CTXT_REG_1, IX_NPEDL_ECS_PRI_1_CTXT_REG_1_RESET }, - { IX_NPEDL_ECS_PRI_1_CTXT_REG_2, IX_NPEDL_ECS_PRI_1_CTXT_REG_2_RESET }, - { IX_NPEDL_ECS_PRI_2_CTXT_REG_0, IX_NPEDL_ECS_PRI_2_CTXT_REG_0_RESET }, - { IX_NPEDL_ECS_PRI_2_CTXT_REG_1, IX_NPEDL_ECS_PRI_2_CTXT_REG_1_RESET }, - { IX_NPEDL_ECS_PRI_2_CTXT_REG_2, IX_NPEDL_ECS_PRI_2_CTXT_REG_2_RESET }, - { IX_NPEDL_ECS_DBG_CTXT_REG_0, IX_NPEDL_ECS_DBG_CTXT_REG_0_RESET }, - { IX_NPEDL_ECS_DBG_CTXT_REG_1, IX_NPEDL_ECS_DBG_CTXT_REG_1_RESET }, - { IX_NPEDL_ECS_DBG_CTXT_REG_2, IX_NPEDL_ECS_DBG_CTXT_REG_2_RESET }, - { IX_NPEDL_ECS_INSTRUCT_REG, IX_NPEDL_ECS_INSTRUCT_REG_RESET } + { IX_NPEDL_ECS_BG_CTXT_REG_0, IX_NPEDL_ECS_BG_CTXT_REG_0_RESET }, + { IX_NPEDL_ECS_BG_CTXT_REG_1, IX_NPEDL_ECS_BG_CTXT_REG_1_RESET }, + { IX_NPEDL_ECS_BG_CTXT_REG_2, IX_NPEDL_ECS_BG_CTXT_REG_2_RESET }, + { IX_NPEDL_ECS_PRI_1_CTXT_REG_0, IX_NPEDL_ECS_PRI_1_CTXT_REG_0_RESET }, + { IX_NPEDL_ECS_PRI_1_CTXT_REG_1, IX_NPEDL_ECS_PRI_1_CTXT_REG_1_RESET }, + { IX_NPEDL_ECS_PRI_1_CTXT_REG_2, IX_NPEDL_ECS_PRI_1_CTXT_REG_2_RESET }, + { IX_NPEDL_ECS_PRI_2_CTXT_REG_0, IX_NPEDL_ECS_PRI_2_CTXT_REG_0_RESET }, + { IX_NPEDL_ECS_PRI_2_CTXT_REG_1, IX_NPEDL_ECS_PRI_2_CTXT_REG_1_RESET }, + { IX_NPEDL_ECS_PRI_2_CTXT_REG_2, IX_NPEDL_ECS_PRI_2_CTXT_REG_2_RESET }, + { IX_NPEDL_ECS_DBG_CTXT_REG_0, IX_NPEDL_ECS_DBG_CTXT_REG_0_RESET }, + { IX_NPEDL_ECS_DBG_CTXT_REG_1, IX_NPEDL_ECS_DBG_CTXT_REG_1_RESET }, + { IX_NPEDL_ECS_DBG_CTXT_REG_2, IX_NPEDL_ECS_DBG_CTXT_REG_2_RESET }, + { IX_NPEDL_ECS_INSTRUCT_REG, IX_NPEDL_ECS_INSTRUCT_REG_RESET } }; /* contains Reset values for Context Store Registers */ static const uint32_t ixNpeDlCtxtRegResetValues[] = { - IX_NPEDL_CTXT_REG_RESET_STEVT, - IX_NPEDL_CTXT_REG_RESET_STARTPC, - IX_NPEDL_CTXT_REG_RESET_REGMAP, - IX_NPEDL_CTXT_REG_RESET_CINDEX, + IX_NPEDL_CTXT_REG_RESET_STEVT, + IX_NPEDL_CTXT_REG_RESET_STARTPC, + IX_NPEDL_CTXT_REG_RESET_REGMAP, + IX_NPEDL_CTXT_REG_RESET_CINDEX, }; #define IX_NPEDL_RESET_NPE_PARITY 0x0800 @@ -677,212 +722,215 @@ static int npe_cpu_reset(struct ixpnpe_softc *sc) { #define N(a) (sizeof(a) / sizeof(a[0])) - struct ixp425_softc *sa = device_get_softc(device_get_parent(sc->sc_dev)); - uint32_t ctxtReg; /* identifies Context Store reg (0-3) */ - uint32_t regAddr; - uint32_t regVal; - uint32_t resetNpeParity; - uint32_t ixNpeConfigCtrlRegVal; - int i, error = 0; - - /* pre-store the NPE Config Control Register Value */ - ixNpeConfigCtrlRegVal = npe_reg_read(sc, IX_NPEDL_REG_OFFSET_CTL); - ixNpeConfigCtrlRegVal |= 0x3F000000; - - /* disable the parity interrupt */ - npe_reg_write(sc, IX_NPEDL_REG_OFFSET_CTL, - (ixNpeConfigCtrlRegVal & IX_NPEDL_PARITY_BIT_MASK)); - DPRINTFn(2, sc->sc_dev, "%s: dis parity int, CTL => 0x%x\n", - __func__, ixNpeConfigCtrlRegVal & IX_NPEDL_PARITY_BIT_MASK); - - npe_cpu_step_save(sc); - - /* - * Clear the FIFOs. - */ - while (npe_checkbits(sc, - IX_NPEDL_REG_OFFSET_WFIFO, IX_NPEDL_MASK_WFIFO_VALID)) { - /* read from the Watch-point FIFO until empty */ - (void) npe_reg_read(sc, IX_NPEDL_REG_OFFSET_WFIFO); - } - - while (npe_checkbits(sc, - IX_NPEDL_REG_OFFSET_STAT, IX_NPEDL_MASK_STAT_OFNE)) { - /* read from the outFIFO until empty */ - (void) npe_reg_read(sc, IX_NPEDL_REG_OFFSET_FIFO); - } - - while (npe_checkbits(sc, - IX_NPEDL_REG_OFFSET_STAT, IX_NPEDL_MASK_STAT_IFNE)) { + struct ixp425_softc *sa = + device_get_softc(device_get_parent(sc->sc_dev)); + uint32_t ctxtReg; /* identifies Context Store reg (0-3) */ + uint32_t regAddr; + uint32_t regVal; + uint32_t resetNpeParity; + uint32_t ixNpeConfigCtrlRegVal; + int i, error = 0; + + /* pre-store the NPE Config Control Register Value */ + ixNpeConfigCtrlRegVal = npe_reg_read(sc, IX_NPEDL_REG_OFFSET_CTL); + ixNpeConfigCtrlRegVal |= 0x3F000000; + + /* disable the parity interrupt */ + npe_reg_write(sc, IX_NPEDL_REG_OFFSET_CTL, + (ixNpeConfigCtrlRegVal & IX_NPEDL_PARITY_BIT_MASK)); + DPRINTFn(2, sc->sc_dev, "%s: dis parity int, CTL => 0x%x\n", + __func__, ixNpeConfigCtrlRegVal & IX_NPEDL_PARITY_BIT_MASK); + + npe_cpu_step_save(sc); + /* - * Step execution of the NPE intruction to read inFIFO using - * the Debug Executing Context stack. + * Clear the FIFOs. */ - error = npe_cpu_step(sc, IX_NPEDL_INSTR_RD_FIFO, 0, 0); - if (error != 0) { - DPRINTF(sc->sc_dev, "%s: cannot step (1), error %u\n", - __func__, error); - npe_cpu_step_restore(sc); - return error; + while (npe_checkbits(sc, + IX_NPEDL_REG_OFFSET_WFIFO, IX_NPEDL_MASK_WFIFO_VALID)) { + /* read from the Watch-point FIFO until empty */ + (void) npe_reg_read(sc, IX_NPEDL_REG_OFFSET_WFIFO); } - } - - /* - * Reset the mailbox reg - */ - /* ...from XScale side */ - npe_reg_write(sc, IX_NPEDL_REG_OFFSET_MBST, IX_NPEDL_REG_RESET_MBST); - /* ...from NPE side */ - error = npe_cpu_step(sc, IX_NPEDL_INSTR_RESET_MBOX, 0, 0); - if (error != 0) { - DPRINTF(sc->sc_dev, "%s: cannot step (2), error %u\n", __func__, error); - npe_cpu_step_restore(sc); - return error; - } - - /* - * Reset the physical registers in the NPE register file: - * Note: no need to save/restore REGMAP for Context 0 here - * since all Context Store regs are reset in subsequent code. - */ - for (regAddr = 0; - regAddr < IX_NPEDL_TOTAL_NUM_PHYS_REG && error == 0; - regAddr++) { - /* for each physical register in the NPE reg file, write 0 : */ - error = npe_physical_reg_write(sc, regAddr, 0, TRUE); + + while (npe_checkbits(sc, + IX_NPEDL_REG_OFFSET_STAT, IX_NPEDL_MASK_STAT_OFNE)) { + /* read from the outFIFO until empty */ + (void) npe_reg_read(sc, IX_NPEDL_REG_OFFSET_FIFO); + } + + while (npe_checkbits(sc, + IX_NPEDL_REG_OFFSET_STAT, IX_NPEDL_MASK_STAT_IFNE)) { + /* + * Step execution of the NPE intruction to read inFIFO using + * the Debug Executing Context stack. + */ + error = npe_cpu_step(sc, IX_NPEDL_INSTR_RD_FIFO, 0, 0); + if (error != 0) { + DPRINTF(sc->sc_dev, "%s: cannot step (1), error %u\n", + __func__, error); + npe_cpu_step_restore(sc); + return error; + } + } + + /* + * Reset the mailbox reg + */ + /* ...from XScale side */ + npe_reg_write(sc, IX_NPEDL_REG_OFFSET_MBST, IX_NPEDL_REG_RESET_MBST); + /* ...from NPE side */ + error = npe_cpu_step(sc, IX_NPEDL_INSTR_RESET_MBOX, 0, 0); if (error != 0) { - DPRINTF(sc->sc_dev, "%s: cannot write phy reg, error %u\n", - __func__, error); - npe_cpu_step_restore(sc); - return error; /* abort reset */ + DPRINTF(sc->sc_dev, "%s: cannot step (2), error %u\n", + __func__, error); + npe_cpu_step_restore(sc); + return error; } - } - - /* - * Reset the context store: - */ - for (i = IX_NPEDL_CTXT_NUM_MIN; i <= IX_NPEDL_CTXT_NUM_MAX; i++) { - /* set each context's Context Store registers to reset values: */ - for (ctxtReg = 0; ctxtReg < IX_NPEDL_CTXT_REG_MAX; ctxtReg++) { - /* NOTE that there is no STEVT register for Context 0 */ - if (!(i == 0 && ctxtReg == IX_NPEDL_CTXT_REG_STEVT)) { - regVal = ixNpeDlCtxtRegResetValues[ctxtReg]; - error = npe_ctx_reg_write(sc, i, ctxtReg, regVal, TRUE); + + /* + * Reset the physical registers in the NPE register file: + * Note: no need to save/restore REGMAP for Context 0 here + * since all Context Store regs are reset in subsequent code. + */ + for (regAddr = 0; + regAddr < IX_NPEDL_TOTAL_NUM_PHYS_REG && error == 0; + regAddr++) { + /* for each physical register in the NPE reg file, write 0 : */ + error = npe_physical_reg_write(sc, regAddr, 0, TRUE); if (error != 0) { - DPRINTF(sc->sc_dev, "%s: cannot write ctx reg, error %u\n", - __func__, error); - npe_cpu_step_restore(sc); - return error; /* abort reset */ + DPRINTF(sc->sc_dev, "%s: cannot write phy reg," + "error %u\n", __func__, error); + npe_cpu_step_restore(sc); + return error; /* abort reset */ + } + } + + /* + * Reset the context store: + */ + for (i = IX_NPEDL_CTXT_NUM_MIN; i <= IX_NPEDL_CTXT_NUM_MAX; i++) { + /* set each context's Context Store registers to reset values */ + for (ctxtReg = 0; ctxtReg < IX_NPEDL_CTXT_REG_MAX; ctxtReg++) { + /* NOTE that there is no STEVT register for Context 0 */ + if (i == 0 && ctxtReg == IX_NPEDL_CTXT_REG_STEVT) + continue; + regVal = ixNpeDlCtxtRegResetValues[ctxtReg]; + error = npe_ctx_reg_write(sc, i, ctxtReg, + regVal, TRUE); + if (error != 0) { + DPRINTF(sc->sc_dev, "%s: cannot write ctx reg," + "error %u\n", __func__, error); + npe_cpu_step_restore(sc); + return error; /* abort reset */ + } } - } } - } - - npe_cpu_step_restore(sc); - - /* write Reset values to Execution Context Stack registers */ - for (i = 0; i < N(ixNpeDlEcsRegResetValues); i++) - npe_ecs_reg_write(sc, - ixNpeDlEcsRegResetValues[i].regAddr, - ixNpeDlEcsRegResetValues[i].regResetVal); - - /* clear the profile counter */ - npe_issue_cmd(sc, IX_NPEDL_EXCTL_CMD_CLR_PROFILE_CNT); - - /* clear registers EXCT, AP0, AP1, AP2 and AP3 */ - for (regAddr = IX_NPEDL_REG_OFFSET_EXCT; - regAddr <= IX_NPEDL_REG_OFFSET_AP3; - regAddr += sizeof(uint32_t)) - npe_reg_write(sc, regAddr, 0); - - /* Reset the Watch-count register */ - npe_reg_write(sc, IX_NPEDL_REG_OFFSET_WC, 0); - - /* - * WR IXA00055043 - Remove IMEM Parity Introduced by NPE Reset Operation - */ - - /* - * Reset the NPE and its coprocessor - to reset internal - * states and remove parity error. Note this makes no - * sense based on the documentation. The feature control - * register always reads back as 0 on the ixp425 and further - * the bit definition of NPEA/NPEB is off by 1 according to - * the Intel documention--so we're blindly following the - * Intel code w/o any real understanding. - */ - regVal = EXP_BUS_READ_4(sa, EXP_FCTRL_OFFSET); - DPRINTFn(2, sc->sc_dev, "%s: FCTRL 0x%x\n", __func__, regVal); - resetNpeParity = - IX_NPEDL_RESET_NPE_PARITY << (1 + device_get_unit(sc->sc_dev)); - DPRINTFn(2, sc->sc_dev, "%s: FCTRL fuse parity, write 0x%x\n", - __func__, regVal | resetNpeParity); - EXP_BUS_WRITE_4(sa, EXP_FCTRL_OFFSET, regVal | resetNpeParity); - - /* un-fuse and un-reset the NPE & coprocessor */ - DPRINTFn(2, sc->sc_dev, "%s: FCTRL unfuse parity, write 0x%x\n", - __func__, regVal & resetNpeParity); - EXP_BUS_WRITE_4(sa, EXP_FCTRL_OFFSET, regVal &~ resetNpeParity); - - /* - * Call NpeMgr function to stop the NPE again after the Feature Control - * has unfused and Un-Reset the NPE and its associated Coprocessors. - */ - error = npe_cpu_stop(sc); - - /* restore NPE configuration bus Control Register - Parity Settings */ - npe_reg_write(sc, IX_NPEDL_REG_OFFSET_CTL, - (ixNpeConfigCtrlRegVal & IX_NPEDL_CONFIG_CTRL_REG_MASK)); - DPRINTFn(2, sc->sc_dev, "%s: restore CTL => 0x%x\n", - __func__, npe_reg_read(sc, IX_NPEDL_REG_OFFSET_CTL)); - - return error; + + npe_cpu_step_restore(sc); + + /* write Reset values to Execution Context Stack registers */ + for (i = 0; i < N(ixNpeDlEcsRegResetValues); i++) + npe_ecs_reg_write(sc, + ixNpeDlEcsRegResetValues[i].regAddr, + ixNpeDlEcsRegResetValues[i].regResetVal); + + /* clear the profile counter */ + npe_issue_cmd(sc, IX_NPEDL_EXCTL_CMD_CLR_PROFILE_CNT); + + /* clear registers EXCT, AP0, AP1, AP2 and AP3 */ + for (regAddr = IX_NPEDL_REG_OFFSET_EXCT; + regAddr <= IX_NPEDL_REG_OFFSET_AP3; + regAddr += sizeof(uint32_t)) + npe_reg_write(sc, regAddr, 0); + + /* Reset the Watch-count register */ + npe_reg_write(sc, IX_NPEDL_REG_OFFSET_WC, 0); + + /* + * WR IXA00055043 - Remove IMEM Parity Introduced by NPE Reset Operation + */ + + /* + * Reset the NPE and its coprocessor - to reset internal + * states and remove parity error. Note this makes no + * sense based on the documentation. The feature control + * register always reads back as 0 on the ixp425 and further + * the bit definition of NPEA/NPEB is off by 1 according to + * the Intel documention--so we're blindly following the + * Intel code w/o any real understanding. + */ + regVal = EXP_BUS_READ_4(sa, EXP_FCTRL_OFFSET); + DPRINTFn(2, sc->sc_dev, "%s: FCTRL 0x%x\n", __func__, regVal); + resetNpeParity = + IX_NPEDL_RESET_NPE_PARITY << (1 + device_get_unit(sc->sc_dev)); + DPRINTFn(2, sc->sc_dev, "%s: FCTRL fuse parity, write 0x%x\n", + __func__, regVal | resetNpeParity); + EXP_BUS_WRITE_4(sa, EXP_FCTRL_OFFSET, regVal | resetNpeParity); + + /* un-fuse and un-reset the NPE & coprocessor */ + DPRINTFn(2, sc->sc_dev, "%s: FCTRL unfuse parity, write 0x%x\n", + __func__, regVal & resetNpeParity); + EXP_BUS_WRITE_4(sa, EXP_FCTRL_OFFSET, regVal &~ resetNpeParity); + + /* + * Call NpeMgr function to stop the NPE again after the Feature Control + * has unfused and Un-Reset the NPE and its associated Coprocessors. + */ + error = npe_cpu_stop(sc); + + /* restore NPE configuration bus Control Register - Parity Settings */ + npe_reg_write(sc, IX_NPEDL_REG_OFFSET_CTL, + (ixNpeConfigCtrlRegVal & IX_NPEDL_CONFIG_CTRL_REG_MASK)); + DPRINTFn(2, sc->sc_dev, "%s: restore CTL => 0x%x\n", + __func__, npe_reg_read(sc, IX_NPEDL_REG_OFFSET_CTL)); + + return error; #undef N } static int npe_cpu_start(struct ixpnpe_softc *sc) { - uint32_t ecsRegVal; - - /* - * Ensure only Background Context Stack Level is Active by turning off - * the Active bit in each of the other Executing Context Stack levels. - */ - ecsRegVal = npe_ecs_reg_read(sc, IX_NPEDL_ECS_PRI_1_CTXT_REG_0); - ecsRegVal &= ~IX_NPEDL_MASK_ECS_REG_0_ACTIVE; - npe_ecs_reg_write(sc, IX_NPEDL_ECS_PRI_1_CTXT_REG_0, ecsRegVal); - - ecsRegVal = npe_ecs_reg_read(sc, IX_NPEDL_ECS_PRI_2_CTXT_REG_0); - ecsRegVal &= ~IX_NPEDL_MASK_ECS_REG_0_ACTIVE; - npe_ecs_reg_write(sc, IX_NPEDL_ECS_PRI_2_CTXT_REG_0, ecsRegVal); - - ecsRegVal = npe_ecs_reg_read(sc, IX_NPEDL_ECS_DBG_CTXT_REG_0); - ecsRegVal &= ~IX_NPEDL_MASK_ECS_REG_0_ACTIVE; - npe_ecs_reg_write(sc, IX_NPEDL_ECS_DBG_CTXT_REG_0, ecsRegVal); - - /* clear the pipeline */ - npe_issue_cmd(sc, IX_NPEDL_EXCTL_CMD_NPE_CLR_PIPE); - - /* start NPE execution by issuing command through EXCTL register on NPE */ - npe_issue_cmd(sc, IX_NPEDL_EXCTL_CMD_NPE_START); - - /* - * Check execution status of NPE to verify operation was successful. - */ - return npe_checkbits(sc, - IX_NPEDL_REG_OFFSET_EXCTL, IX_NPEDL_EXCTL_STATUS_RUN) ? 0 : EIO; + uint32_t ecsRegVal; + + /* + * Ensure only Background Context Stack Level is Active by turning off + * the Active bit in each of the other Executing Context Stack levels. + */ + ecsRegVal = npe_ecs_reg_read(sc, IX_NPEDL_ECS_PRI_1_CTXT_REG_0); + ecsRegVal &= ~IX_NPEDL_MASK_ECS_REG_0_ACTIVE; + npe_ecs_reg_write(sc, IX_NPEDL_ECS_PRI_1_CTXT_REG_0, ecsRegVal); + + ecsRegVal = npe_ecs_reg_read(sc, IX_NPEDL_ECS_PRI_2_CTXT_REG_0); + ecsRegVal &= ~IX_NPEDL_MASK_ECS_REG_0_ACTIVE; + npe_ecs_reg_write(sc, IX_NPEDL_ECS_PRI_2_CTXT_REG_0, ecsRegVal); + + ecsRegVal = npe_ecs_reg_read(sc, IX_NPEDL_ECS_DBG_CTXT_REG_0); + ecsRegVal &= ~IX_NPEDL_MASK_ECS_REG_0_ACTIVE; + npe_ecs_reg_write(sc, IX_NPEDL_ECS_DBG_CTXT_REG_0, ecsRegVal); + + /* clear the pipeline */ + npe_issue_cmd(sc, IX_NPEDL_EXCTL_CMD_NPE_CLR_PIPE); + + /* start NPE execution by issuing cmd through EXCTL register on NPE */ + npe_issue_cmd(sc, IX_NPEDL_EXCTL_CMD_NPE_START); + + /* + * Check execution status of NPE to verify operation was successful. + */ + return npe_checkbits(sc, + IX_NPEDL_REG_OFFSET_EXCTL, IX_NPEDL_EXCTL_STATUS_RUN) ? 0 : EIO; } static int npe_cpu_stop(struct ixpnpe_softc *sc) { - /* stop NPE execution by issuing command through EXCTL register on NPE */ - npe_issue_cmd(sc, IX_NPEDL_EXCTL_CMD_NPE_STOP); + /* stop NPE execution by issuing cmd through EXCTL register on NPE */ + npe_issue_cmd(sc, IX_NPEDL_EXCTL_CMD_NPE_STOP); - /* verify that NPE Stop was successful */ - return npe_checkbits(sc, - IX_NPEDL_REG_OFFSET_EXCTL, IX_NPEDL_EXCTL_STATUS_STOP) ? 0 : EIO; + /* verify that NPE Stop was successful */ + return npe_checkbits(sc, + IX_NPEDL_REG_OFFSET_EXCTL, IX_NPEDL_EXCTL_STATUS_STOP) ? 0 : EIO; } #define IX_NPEDL_REG_SIZE_BYTE 8 @@ -904,100 +952,105 @@ static void npe_cmd_issue_write(struct ixpnpe_softc *sc, uint32_t cmd, uint32_t addr, uint32_t data) { - npe_reg_write(sc, IX_NPEDL_REG_OFFSET_EXDATA, data); - npe_reg_write(sc, IX_NPEDL_REG_OFFSET_EXAD, addr); - npe_reg_write(sc, IX_NPEDL_REG_OFFSET_EXCTL, cmd); + npe_reg_write(sc, IX_NPEDL_REG_OFFSET_EXDATA, data); + npe_reg_write(sc, IX_NPEDL_REG_OFFSET_EXAD, addr); + npe_reg_write(sc, IX_NPEDL_REG_OFFSET_EXCTL, cmd); } static uint32_t npe_cmd_issue_read(struct ixpnpe_softc *sc, uint32_t cmd, uint32_t addr) { - uint32_t data; - int i; - - npe_reg_write(sc, IX_NPEDL_REG_OFFSET_EXAD, addr); - npe_reg_write(sc, IX_NPEDL_REG_OFFSET_EXCTL, cmd); - for (i = 0; i <= IX_NPEDL_DELAY_READ_CYCLES; i++) - data = npe_reg_read(sc, IX_NPEDL_REG_OFFSET_EXDATA); - return data; + uint32_t data; + int i; + + npe_reg_write(sc, IX_NPEDL_REG_OFFSET_EXAD, addr); + npe_reg_write(sc, IX_NPEDL_REG_OFFSET_EXCTL, cmd); + for (i = 0; i <= IX_NPEDL_DELAY_READ_CYCLES; i++) + data = npe_reg_read(sc, IX_NPEDL_REG_OFFSET_EXDATA); + return data; } static int npe_ins_write(struct ixpnpe_softc *sc, uint32_t addr, uint32_t data, int verify) { - DPRINTFn(4, sc->sc_dev, "%s(0x%x, 0x%x)\n", __func__, addr, data); - npe_cmd_issue_write(sc, IX_NPEDL_EXCTL_CMD_WR_INS_MEM, addr, data); - if (verify) { - uint32_t rdata; - - /* - * Write invalid data to this reg, so we can see if we're reading - * the EXDATA register too early. - */ - npe_reg_write(sc, IX_NPEDL_REG_OFFSET_EXDATA, ~data); - - /* Disabled since top 3 MSB are not used for Azusa hardware Refer WR:IXA00053900*/ - data &= IX_NPEDL_MASK_UNUSED_IMEM_BITS; - - rdata = npe_cmd_issue_read(sc, IX_NPEDL_EXCTL_CMD_RD_INS_MEM, addr); - rdata &= IX_NPEDL_MASK_UNUSED_IMEM_BITS; - - if (data != rdata) - return EIO; - } - return 0; + DPRINTFn(4, sc->sc_dev, "%s(0x%x, 0x%x)\n", __func__, addr, data); + npe_cmd_issue_write(sc, IX_NPEDL_EXCTL_CMD_WR_INS_MEM, addr, data); + if (verify) { + uint32_t rdata; + + /* + * Write invalid data to this reg, so we can see if we're + * reading the EXDATA register too early. + */ + npe_reg_write(sc, IX_NPEDL_REG_OFFSET_EXDATA, ~data); + + /* + * Disabled since top 3 MSB are not used for Azusa + * hardware Refer WR:IXA00053900 + */ + data &= IX_NPEDL_MASK_UNUSED_IMEM_BITS; + + rdata = npe_cmd_issue_read(sc, IX_NPEDL_EXCTL_CMD_RD_INS_MEM, + addr); + rdata &= IX_NPEDL_MASK_UNUSED_IMEM_BITS; + + if (data != rdata) + return EIO; + } + return 0; } static int npe_data_write(struct ixpnpe_softc *sc, uint32_t addr, uint32_t data, int verify) { - DPRINTFn(4, sc->sc_dev, "%s(0x%x, 0x%x)\n", __func__, addr, data); - npe_cmd_issue_write(sc, IX_NPEDL_EXCTL_CMD_WR_DATA_MEM, addr, data); - if (verify) { - /* - * Write invalid data to this reg, so we can see if we're reading - * the EXDATA register too early. - */ - npe_reg_write(sc, IX_NPEDL_REG_OFFSET_EXDATA, ~data); - if (data != npe_cmd_issue_read(sc, IX_NPEDL_EXCTL_CMD_RD_DATA_MEM, addr)) - return EIO; - } - return 0; + DPRINTFn(4, sc->sc_dev, "%s(0x%x, 0x%x)\n", __func__, addr, data); + npe_cmd_issue_write(sc, IX_NPEDL_EXCTL_CMD_WR_DATA_MEM, addr, data); + if (verify) { + /* + * Write invalid data to this reg, so we can see if we're + * reading the EXDATA register too early. + */ + npe_reg_write(sc, IX_NPEDL_REG_OFFSET_EXDATA, ~data); + if (data != npe_cmd_issue_read(sc, IX_NPEDL_EXCTL_CMD_RD_DATA_MEM, addr)) + return EIO; + } + return 0; } static void npe_ecs_reg_write(struct ixpnpe_softc *sc, uint32_t reg, uint32_t data) { - npe_cmd_issue_write(sc, IX_NPEDL_EXCTL_CMD_WR_ECS_REG, reg, data); + npe_cmd_issue_write(sc, IX_NPEDL_EXCTL_CMD_WR_ECS_REG, reg, data); } static uint32_t npe_ecs_reg_read(struct ixpnpe_softc *sc, uint32_t reg) { - return npe_cmd_issue_read(sc, IX_NPEDL_EXCTL_CMD_RD_ECS_REG, reg); + return npe_cmd_issue_read(sc, IX_NPEDL_EXCTL_CMD_RD_ECS_REG, reg); } static void npe_issue_cmd(struct ixpnpe_softc *sc, uint32_t command) { - npe_reg_write(sc, IX_NPEDL_REG_OFFSET_EXCTL, command); + npe_reg_write(sc, IX_NPEDL_REG_OFFSET_EXCTL, command); } static void npe_cpu_step_save(struct ixpnpe_softc *sc) { - /* turn off the halt bit by clearing Execution Count register. */ - /* save reg contents 1st and restore later */ - sc->savedExecCount = npe_reg_read(sc, IX_NPEDL_REG_OFFSET_EXCT); - npe_reg_write(sc, IX_NPEDL_REG_OFFSET_EXCT, 0); - - /* ensure that IF and IE are on (temporarily), so that we don't end up - * stepping forever */ - sc->savedEcsDbgCtxtReg2 = npe_ecs_reg_read(sc, IX_NPEDL_ECS_DBG_CTXT_REG_2); - - npe_ecs_reg_write(sc, IX_NPEDL_ECS_DBG_CTXT_REG_2, - (sc->savedEcsDbgCtxtReg2 | IX_NPEDL_MASK_ECS_DBG_REG_2_IF | - IX_NPEDL_MASK_ECS_DBG_REG_2_IE)); + /* turn off the halt bit by clearing Execution Count register. */ + /* save reg contents 1st and restore later */ + sc->savedExecCount = npe_reg_read(sc, IX_NPEDL_REG_OFFSET_EXCT); + npe_reg_write(sc, IX_NPEDL_REG_OFFSET_EXCT, 0); + + /* ensure that IF and IE are on (temporarily), so that we don't end up + * stepping forever */ + sc->savedEcsDbgCtxtReg2 = npe_ecs_reg_read(sc, + IX_NPEDL_ECS_DBG_CTXT_REG_2); + + npe_ecs_reg_write(sc, IX_NPEDL_ECS_DBG_CTXT_REG_2, + (sc->savedEcsDbgCtxtReg2 | IX_NPEDL_MASK_ECS_DBG_REG_2_IF | + IX_NPEDL_MASK_ECS_DBG_REG_2_IE)); } static int @@ -1005,69 +1058,70 @@ npe_cpu_step(struct ixpnpe_softc *sc, uint32_t npeInstruction, uint32_t ctxtNum, uint32_t ldur) { #define IX_NPE_DL_MAX_NUM_OF_RETRIES 1000000 - uint32_t ecsDbgRegVal; - uint32_t oldWatchcount, newWatchcount; - int tries; - - /* set the Active bit, and the LDUR, in the debug level */ - ecsDbgRegVal = IX_NPEDL_MASK_ECS_REG_0_ACTIVE | - (ldur << IX_NPEDL_OFFSET_ECS_REG_0_LDUR); - - npe_ecs_reg_write(sc, IX_NPEDL_ECS_DBG_CTXT_REG_0, ecsDbgRegVal); - - /* - * Set CCTXT at ECS DEBUG L3 to specify in which context to execute the - * instruction, and set SELCTXT at ECS DEBUG Level to specify which context - * store to access. - * Debug ECS Level Reg 1 has form 0x000n000n, where n = context number - */ - ecsDbgRegVal = (ctxtNum << IX_NPEDL_OFFSET_ECS_REG_1_CCTXT) | - (ctxtNum << IX_NPEDL_OFFSET_ECS_REG_1_SELCTXT); - - npe_ecs_reg_write(sc, IX_NPEDL_ECS_DBG_CTXT_REG_1, ecsDbgRegVal); - - /* clear the pipeline */ - npe_issue_cmd(sc, IX_NPEDL_EXCTL_CMD_NPE_CLR_PIPE); - - /* load NPE instruction into the instruction register */ - npe_ecs_reg_write(sc, IX_NPEDL_ECS_INSTRUCT_REG, npeInstruction); - - /* we need this value later to wait for completion of NPE execution step */ - oldWatchcount = npe_reg_read(sc, IX_NPEDL_REG_OFFSET_WC); - - /* issue a Step One command via the Execution Control register */ - npe_issue_cmd(sc, IX_NPEDL_EXCTL_CMD_NPE_STEP); - - /* - * Force the XScale to wait until the NPE has finished execution step - * NOTE that this delay will be very small, just long enough to allow a - * single NPE instruction to complete execution; if instruction execution - * is not completed before timeout retries, exit the while loop. - */ - newWatchcount = npe_reg_read(sc, IX_NPEDL_REG_OFFSET_WC); - for (tries = 0; tries < IX_NPE_DL_MAX_NUM_OF_RETRIES && - newWatchcount == oldWatchcount; tries++) { - /* Watch Count register increments when NPE completes an instruction */ + uint32_t ecsDbgRegVal; + uint32_t oldWatchcount, newWatchcount; + int tries; + + /* set the Active bit, and the LDUR, in the debug level */ + ecsDbgRegVal = IX_NPEDL_MASK_ECS_REG_0_ACTIVE | + (ldur << IX_NPEDL_OFFSET_ECS_REG_0_LDUR); + + npe_ecs_reg_write(sc, IX_NPEDL_ECS_DBG_CTXT_REG_0, ecsDbgRegVal); + + /* + * Set CCTXT at ECS DEBUG L3 to specify in which context to execute the + * instruction, and set SELCTXT at ECS DEBUG Level to specify which + * context store to access. + * Debug ECS Level Reg 1 has form 0x000n000n, where n = context number + */ + ecsDbgRegVal = (ctxtNum << IX_NPEDL_OFFSET_ECS_REG_1_CCTXT) | + (ctxtNum << IX_NPEDL_OFFSET_ECS_REG_1_SELCTXT); + + npe_ecs_reg_write(sc, IX_NPEDL_ECS_DBG_CTXT_REG_1, ecsDbgRegVal); + + /* clear the pipeline */ + npe_issue_cmd(sc, IX_NPEDL_EXCTL_CMD_NPE_CLR_PIPE); + + /* load NPE instruction into the instruction register */ + npe_ecs_reg_write(sc, IX_NPEDL_ECS_INSTRUCT_REG, npeInstruction); + + /* need this value later to wait for completion of NPE execution step */ + oldWatchcount = npe_reg_read(sc, IX_NPEDL_REG_OFFSET_WC); + + /* issue a Step One command via the Execution Control register */ + npe_issue_cmd(sc, IX_NPEDL_EXCTL_CMD_NPE_STEP); + + /* + * Force the XScale to wait until the NPE has finished execution step + * NOTE that this delay will be very small, just long enough to allow a + * single NPE instruction to complete execution; if instruction + * execution is not completed before timeout retries, exit the while + * loop. + */ newWatchcount = npe_reg_read(sc, IX_NPEDL_REG_OFFSET_WC); - } - return (tries < IX_NPE_DL_MAX_NUM_OF_RETRIES) ? 0 : EIO; + for (tries = 0; tries < IX_NPE_DL_MAX_NUM_OF_RETRIES && + newWatchcount == oldWatchcount; tries++) { + /* Watch Count register incr's when NPE completes an inst */ + newWatchcount = npe_reg_read(sc, IX_NPEDL_REG_OFFSET_WC); + } + return (tries < IX_NPE_DL_MAX_NUM_OF_RETRIES) ? 0 : EIO; #undef IX_NPE_DL_MAX_NUM_OF_RETRIES } static void npe_cpu_step_restore(struct ixpnpe_softc *sc) { - /* clear active bit in debug level */ - npe_ecs_reg_write(sc, IX_NPEDL_ECS_DBG_CTXT_REG_0, 0); + /* clear active bit in debug level */ + npe_ecs_reg_write(sc, IX_NPEDL_ECS_DBG_CTXT_REG_0, 0); - /* clear the pipeline */ - npe_issue_cmd(sc, IX_NPEDL_EXCTL_CMD_NPE_CLR_PIPE); + /* clear the pipeline */ + npe_issue_cmd(sc, IX_NPEDL_EXCTL_CMD_NPE_CLR_PIPE); - /* restore Execution Count register contents. */ - npe_reg_write(sc, IX_NPEDL_REG_OFFSET_EXCT, sc->savedExecCount); + /* restore Execution Count register contents. */ + npe_reg_write(sc, IX_NPEDL_REG_OFFSET_EXCT, sc->savedExecCount); - /* restore IF and IE bits to original values */ - npe_ecs_reg_write(sc, IX_NPEDL_ECS_DBG_CTXT_REG_2, sc->savedEcsDbgCtxtReg2); + /* restore IF and IE bits to original values */ + npe_ecs_reg_write(sc, IX_NPEDL_ECS_DBG_CTXT_REG_2, sc->savedEcsDbgCtxtReg2); } static int @@ -1075,111 +1129,118 @@ npe_logical_reg_read(struct ixpnpe_softc *sc, uint32_t regAddr, uint32_t regSize, uint32_t ctxtNum, uint32_t *regVal) { - uint32_t npeInstruction, mask; - int error; - - switch (regSize) { - case IX_NPEDL_REG_SIZE_BYTE: - npeInstruction = IX_NPEDL_INSTR_RD_REG_BYTE; - mask = 0xff; - break; - case IX_NPEDL_REG_SIZE_SHORT: - npeInstruction = IX_NPEDL_INSTR_RD_REG_SHORT; - mask = 0xffff; - break; - case IX_NPEDL_REG_SIZE_WORD: - npeInstruction = IX_NPEDL_INSTR_RD_REG_WORD; - mask = 0xffffffff; - break; - default: - return EINVAL; - } - - /* make regAddr be the SRC and DEST operands (e.g. movX d0, d0) */ - npeInstruction |= (regAddr << IX_NPEDL_OFFSET_INSTR_SRC) | - (regAddr << IX_NPEDL_OFFSET_INSTR_DEST); - - /* step execution of NPE intruction using Debug Executing Context stack */ - error = npe_cpu_step(sc, npeInstruction, ctxtNum, IX_NPEDL_RD_INSTR_LDUR); - if (error != 0) { - DPRINTF(sc->sc_dev, "%s(0x%x, %u, %u), cannot step, error %d\n", - __func__, regAddr, regSize, ctxtNum, error); - return error; - } - /* read value of register from Execution Data register */ - *regVal = npe_reg_read(sc, IX_NPEDL_REG_OFFSET_EXDATA); + uint32_t npeInstruction, mask; + int error; + + switch (regSize) { + case IX_NPEDL_REG_SIZE_BYTE: + npeInstruction = IX_NPEDL_INSTR_RD_REG_BYTE; + mask = 0xff; + break; + case IX_NPEDL_REG_SIZE_SHORT: + npeInstruction = IX_NPEDL_INSTR_RD_REG_SHORT; + mask = 0xffff; + break; + case IX_NPEDL_REG_SIZE_WORD: + npeInstruction = IX_NPEDL_INSTR_RD_REG_WORD; + mask = 0xffffffff; + break; + default: + return EINVAL; + } - /* align value from left to right */ - *regVal = (*regVal >> (IX_NPEDL_REG_SIZE_WORD - regSize)) & mask; + /* make regAddr be the SRC and DEST operands (e.g. movX d0, d0) */ + npeInstruction |= (regAddr << IX_NPEDL_OFFSET_INSTR_SRC) | + (regAddr << IX_NPEDL_OFFSET_INSTR_DEST); - return 0; + /* step execution of NPE inst using Debug Executing Context stack */ + error = npe_cpu_step(sc, npeInstruction, ctxtNum, + IX_NPEDL_RD_INSTR_LDUR); + if (error != 0) { + DPRINTF(sc->sc_dev, "%s(0x%x, %u, %u), cannot step, error %d\n", + __func__, regAddr, regSize, ctxtNum, error); + return error; + } + /* read value of register from Execution Data register */ + *regVal = npe_reg_read(sc, IX_NPEDL_REG_OFFSET_EXDATA); + + /* align value from left to right */ + *regVal = (*regVal >> (IX_NPEDL_REG_SIZE_WORD - regSize)) & mask; + + return 0; } static int npe_logical_reg_write(struct ixpnpe_softc *sc, uint32_t regAddr, uint32_t regVal, uint32_t regSize, uint32_t ctxtNum, int verify) { - int error; - - DPRINTFn(4, sc->sc_dev, "%s(0x%x, 0x%x, %u, %u)\n", - __func__, regAddr, regVal, regSize, ctxtNum); - if (regSize == IX_NPEDL_REG_SIZE_WORD) { - /* NPE register addressing is left-to-right: e.g. |d0|d1|d2|d3| */ - /* Write upper half-word (short) to |d0|d1| */ - error = npe_logical_reg_write(sc, regAddr, - regVal >> IX_NPEDL_REG_SIZE_SHORT, - IX_NPEDL_REG_SIZE_SHORT, ctxtNum, verify); - if (error != 0) - return error; - - /* Write lower half-word (short) to |d2|d3| */ - error = npe_logical_reg_write(sc, - regAddr + sizeof(uint16_t), - regVal & 0xffff, - IX_NPEDL_REG_SIZE_SHORT, ctxtNum, verify); - } else { - uint32_t npeInstruction; + int error; + + DPRINTFn(4, sc->sc_dev, "%s(0x%x, 0x%x, %u, %u)\n", + __func__, regAddr, regVal, regSize, ctxtNum); + if (regSize == IX_NPEDL_REG_SIZE_WORD) { + /* + * NPE register addressing is left-to-right: e.g. |d0|d1|d2|d3| + * Write upper half-word (short) to |d0|d1| + */ + error = npe_logical_reg_write(sc, regAddr, + regVal >> IX_NPEDL_REG_SIZE_SHORT, + IX_NPEDL_REG_SIZE_SHORT, ctxtNum, verify); + if (error != 0) + return error; + + /* Write lower half-word (short) to |d2|d3| */ + error = npe_logical_reg_write(sc, + regAddr + sizeof(uint16_t), + regVal & 0xffff, + IX_NPEDL_REG_SIZE_SHORT, ctxtNum, verify); + } else { + uint32_t npeInstruction; + + switch (regSize) { + case IX_NPEDL_REG_SIZE_BYTE: + npeInstruction = IX_NPEDL_INSTR_WR_REG_BYTE; + regVal &= 0xff; + break; + case IX_NPEDL_REG_SIZE_SHORT: + npeInstruction = IX_NPEDL_INSTR_WR_REG_SHORT; + regVal &= 0xffff; + break; + default: + return EINVAL; + } + /* fill dest operand field of inst with dest reg addr */ + npeInstruction |= (regAddr << IX_NPEDL_OFFSET_INSTR_DEST); + + /* fill src operand field of inst with least-sig 5 bits of val*/ + npeInstruction |= + ((regVal & IX_NPEDL_MASK_IMMED_INSTR_SRC_DATA) << + IX_NPEDL_OFFSET_INSTR_SRC); + + /* fill coprocessor field of inst with most-sig 11 bits of val*/ + npeInstruction |= + ((regVal & IX_NPEDL_MASK_IMMED_INSTR_COPROC_DATA) << + IX_NPEDL_DISPLACE_IMMED_INSTR_COPROC_DATA); + + /* step execution of NPE intruction using Debug ECS */ + error = npe_cpu_step(sc, npeInstruction, + ctxtNum, IX_NPEDL_WR_INSTR_LDUR); + } + if (error != 0) { + DPRINTF(sc->sc_dev, "%s(0x%x, 0x%x, %u, %u), error %u " + "writing reg\n", __func__, regAddr, regVal, regSize, + ctxtNum, error); + return error; + } + if (verify) { + uint32_t retRegVal; - switch (regSize) { - case IX_NPEDL_REG_SIZE_BYTE: - npeInstruction = IX_NPEDL_INSTR_WR_REG_BYTE; - regVal &= 0xff; - break; - case IX_NPEDL_REG_SIZE_SHORT: - npeInstruction = IX_NPEDL_INSTR_WR_REG_SHORT; - regVal &= 0xffff; - break; - default: - return EINVAL; + error = npe_logical_reg_read(sc, regAddr, regSize, ctxtNum, + &retRegVal); + if (error == 0 && regVal != retRegVal) + error = EIO; /* XXX ambiguous */ } - /* fill dest operand field of instruction with destination reg addr */ - npeInstruction |= (regAddr << IX_NPEDL_OFFSET_INSTR_DEST); - - /* fill src operand field of instruction with least-sig 5 bits of val*/ - npeInstruction |= ((regVal & IX_NPEDL_MASK_IMMED_INSTR_SRC_DATA) << - IX_NPEDL_OFFSET_INSTR_SRC); - - /* fill coprocessor field of instruction with most-sig 11 bits of val*/ - npeInstruction |= ((regVal & IX_NPEDL_MASK_IMMED_INSTR_COPROC_DATA) << - IX_NPEDL_DISPLACE_IMMED_INSTR_COPROC_DATA); - - /* step execution of NPE intruction using Debug ECS */ - error = npe_cpu_step(sc, npeInstruction, - ctxtNum, IX_NPEDL_WR_INSTR_LDUR); - } - if (error != 0) { - DPRINTF(sc->sc_dev, "%s(0x%x, 0x%x, %u, %u), error %u writing reg\n", - __func__, regAddr, regVal, regSize, ctxtNum, error); return error; - } - if (verify) { - uint32_t retRegVal; - - error = npe_logical_reg_read(sc, regAddr, regSize, ctxtNum, &retRegVal); - if (error == 0 && regVal != retRegVal) - error = EIO; /* XXX ambiguous */ - } - return error; } /* @@ -1193,57 +1254,61 @@ static int npe_physical_reg_write(struct ixpnpe_softc *sc, uint32_t regAddr, uint32_t regValue, int verify) { - int error; - - /* - * Set REGMAP for context 0 to (regAddr >> 1) to choose which pair (0-16) - * of physical registers to write . - */ - error = npe_logical_reg_write(sc, IX_NPEDL_CTXT_REG_ADDR_REGMAP, - (regAddr >> IX_NPEDL_OFFSET_PHYS_REG_ADDR_REGMAP), - IX_NPEDL_REG_SIZE_SHORT, 0, verify); - if (error == 0) { - /* regAddr = 0 or 4 */ - regAddr = (regAddr & IX_NPEDL_MASK_PHYS_REG_ADDR_LOGICAL_ADDR) * - sizeof(uint32_t); - error = npe_logical_reg_write(sc, regAddr, regValue, - IX_NPEDL_REG_SIZE_WORD, 0, verify); - } - return error; + int error; + + /* + * Set REGMAP for context 0 to (regAddr >> 1) to choose which pair + * (0-16) of physical registers to write . + */ + error = npe_logical_reg_write(sc, IX_NPEDL_CTXT_REG_ADDR_REGMAP, + (regAddr >> IX_NPEDL_OFFSET_PHYS_REG_ADDR_REGMAP), + IX_NPEDL_REG_SIZE_SHORT, 0, verify); + if (error == 0) { + /* regAddr = 0 or 4 */ + regAddr = (regAddr & IX_NPEDL_MASK_PHYS_REG_ADDR_LOGICAL_ADDR) * + sizeof(uint32_t); + error = npe_logical_reg_write(sc, regAddr, regValue, + IX_NPEDL_REG_SIZE_WORD, 0, verify); + } + return error; } static int npe_ctx_reg_write(struct ixpnpe_softc *sc, uint32_t ctxtNum, uint32_t ctxtReg, uint32_t ctxtRegVal, int verify) { - DPRINTFn(4, sc->sc_dev, "%s(%u, %u, %u)\n", - __func__, ctxtNum, ctxtReg, ctxtRegVal); - /* - * Context 0 has no STARTPC. Instead, this value is used to set - * NextPC for Background ECS, to set where NPE starts executing code - */ - if (ctxtNum == 0 && ctxtReg == IX_NPEDL_CTXT_REG_STARTPC) { - /* read BG_CTXT_REG_0, update NEXTPC bits, and write back to reg */ - uint32_t v = npe_ecs_reg_read(sc, IX_NPEDL_ECS_BG_CTXT_REG_0); - v &= ~IX_NPEDL_MASK_ECS_REG_0_NEXTPC; - v |= (ctxtRegVal << IX_NPEDL_OFFSET_ECS_REG_0_NEXTPC) & - IX_NPEDL_MASK_ECS_REG_0_NEXTPC; - - npe_ecs_reg_write(sc, IX_NPEDL_ECS_BG_CTXT_REG_0, v); - return 0; - } else { - static const struct { - uint32_t regAddress; - uint32_t regSize; - } regAccInfo[IX_NPEDL_CTXT_REG_MAX] = { - { IX_NPEDL_CTXT_REG_ADDR_STEVT, IX_NPEDL_REG_SIZE_BYTE }, - { IX_NPEDL_CTXT_REG_ADDR_STARTPC, IX_NPEDL_REG_SIZE_SHORT }, - { IX_NPEDL_CTXT_REG_ADDR_REGMAP, IX_NPEDL_REG_SIZE_SHORT }, - { IX_NPEDL_CTXT_REG_ADDR_CINDEX, IX_NPEDL_REG_SIZE_BYTE } - }; - return npe_logical_reg_write(sc, regAccInfo[ctxtReg].regAddress, - ctxtRegVal, regAccInfo[ctxtReg].regSize, ctxtNum, verify); - } + DPRINTFn(4, sc->sc_dev, "%s(%u, %u, %u)\n", + __func__, ctxtNum, ctxtReg, ctxtRegVal); + /* + * Context 0 has no STARTPC. Instead, this value is used to set + * NextPC for Background ECS, to set where NPE starts executing code + */ + if (ctxtNum == 0 && ctxtReg == IX_NPEDL_CTXT_REG_STARTPC) { + /* read BG_CTXT_REG_0, update NEXTPC bits, & write back to reg*/ + uint32_t v = npe_ecs_reg_read(sc, IX_NPEDL_ECS_BG_CTXT_REG_0); + v &= ~IX_NPEDL_MASK_ECS_REG_0_NEXTPC; + v |= (ctxtRegVal << IX_NPEDL_OFFSET_ECS_REG_0_NEXTPC) & + IX_NPEDL_MASK_ECS_REG_0_NEXTPC; + + npe_ecs_reg_write(sc, IX_NPEDL_ECS_BG_CTXT_REG_0, v); + return 0; + } else { + static const struct { + uint32_t regAddress; + uint32_t regSize; + } regAccInfo[IX_NPEDL_CTXT_REG_MAX] = { + { IX_NPEDL_CTXT_REG_ADDR_STEVT, + IX_NPEDL_REG_SIZE_BYTE }, + { IX_NPEDL_CTXT_REG_ADDR_STARTPC, + IX_NPEDL_REG_SIZE_SHORT }, + { IX_NPEDL_CTXT_REG_ADDR_REGMAP, + IX_NPEDL_REG_SIZE_SHORT }, + { IX_NPEDL_CTXT_REG_ADDR_CINDEX, + IX_NPEDL_REG_SIZE_BYTE } + }; + return npe_logical_reg_write(sc, regAccInfo[ctxtReg].regAddress, + ctxtRegVal, regAccInfo[ctxtReg].regSize, ctxtNum, verify); + } } /* @@ -1252,145 +1317,173 @@ npe_ctx_reg_write(struct ixpnpe_softc *sc, uint32_t ctxtNum, #define IX_NPEMH_MAXTRIES 100000 static int -ixpnpe_ofifo_wait(struct ixpnpe_softc *sc) +ofifo_wait(struct ixpnpe_softc *sc) { - int i; - - for (i = 0; i < IX_NPEMH_MAXTRIES; i++) { - if (npe_reg_read(sc, IX_NPESTAT) & IX_NPESTAT_OFNE) - return 1; - DELAY(10); - } - device_printf(sc->sc_dev, "%s: timeout, last status 0x%x\n", - __func__, npe_reg_read(sc, IX_NPESTAT)); - return 0; + int i; + + for (i = 0; i < IX_NPEMH_MAXTRIES; i++) { + if (npe_reg_read(sc, IX_NPESTAT) & IX_NPESTAT_OFNE) + return 1; + DELAY(10); + } + device_printf(sc->sc_dev, "%s: timeout, last status 0x%x\n", + __func__, npe_reg_read(sc, IX_NPESTAT)); + return 0; +} + +static int +getmsg(struct ixpnpe_softc *sc, uint32_t msg[2]) +{ + mtx_assert(&sc->sc_mtx, MA_OWNED); + + if (!ofifo_wait(sc)) + return EAGAIN; + msg[0] = npe_reg_read(sc, IX_NPEFIFO); + DPRINTF(sc->sc_dev, "%s: msg0 0x%x\n", __func__, msg[0]); + if (!ofifo_wait(sc)) + return EAGAIN; + msg[1] = npe_reg_read(sc, IX_NPEFIFO); + DPRINTF(sc->sc_dev, "%s: msg1 0x%x\n", __func__, msg[1]); + return 0; } static void ixpnpe_intr(void *arg) { - struct ixpnpe_softc *sc = arg; - uint32_t status; - - status = npe_reg_read(sc, IX_NPESTAT); - if ((status & IX_NPESTAT_OFINT) == 0) { - /* NB: should not happen */ - device_printf(sc->sc_dev, "%s: status 0x%x\n", __func__, status); - /* XXX must silence interrupt? */ - return; - } - /* - * A message is waiting in the output FIFO, copy it so - * the interrupt will be silenced; then signal anyone - * waiting to collect the result. - */ - sc->sc_msgwaiting = -1; /* NB: error indicator */ - if (ixpnpe_ofifo_wait(sc)) { - sc->sc_msg[0] = npe_reg_read(sc, IX_NPEFIFO); - if (ixpnpe_ofifo_wait(sc)) { - sc->sc_msg[1] = npe_reg_read(sc, IX_NPEFIFO); - sc->sc_msgwaiting = 1; /* successful fetch */ + struct ixpnpe_softc *sc = arg; + uint32_t status; + + mtx_lock(&sc->sc_mtx); + status = npe_reg_read(sc, IX_NPESTAT); + DPRINTF(sc->sc_dev, "%s: status 0x%x\n", __func__, status); + if ((status & IX_NPESTAT_OFINT) == 0) { + /* NB: should not happen */ + device_printf(sc->sc_dev, "%s: status 0x%x\n", + __func__, status); + /* XXX must silence interrupt? */ + mtx_unlock(&sc->sc_mtx); + return; } - } - wakeup_one(sc); + /* + * A message is waiting in the output FIFO, copy it so + * the interrupt will be silenced. + */ + if (getmsg(sc, sc->sc_msg) == 0) + sc->sc_msgwaiting = 1; + mtx_unlock(&sc->sc_mtx); } static int -ixpnpe_ififo_wait(struct ixpnpe_softc *sc) +ififo_wait(struct ixpnpe_softc *sc) { - int i; - - for (i = 0; i < IX_NPEMH_MAXTRIES; i++) { - if (npe_reg_read(sc, IX_NPESTAT) & IX_NPESTAT_IFNF) - return 1; - DELAY(10); - } - return 0; + int i; + + for (i = 0; i < IX_NPEMH_MAXTRIES; i++) { + if (npe_reg_read(sc, IX_NPESTAT) & IX_NPESTAT_IFNF) + return 1; + DELAY(10); + } + device_printf(sc->sc_dev, "%s: timeout, last status 0x%x\n", + __func__, npe_reg_read(sc, IX_NPESTAT)); + return 0; } static int -ixpnpe_sendmsg_locked(struct ixpnpe_softc *sc, const uint32_t msg[2]) +putmsg(struct ixpnpe_softc *sc, const uint32_t msg[2]) { - int error = 0; - - mtx_assert(&sc->sc_mtx, MA_OWNED); + mtx_assert(&sc->sc_mtx, MA_OWNED); - sc->sc_msgwaiting = 0; - if (ixpnpe_ififo_wait(sc)) { + DPRINTF(sc->sc_dev, "%s: msg 0x%x:0x%x\n", __func__, msg[0], msg[1]); + if (!ififo_wait(sc)) + return EIO; npe_reg_write(sc, IX_NPEFIFO, msg[0]); - if (ixpnpe_ififo_wait(sc)) - npe_reg_write(sc, IX_NPEFIFO, msg[1]); - else - error = EIO; - } else - error = EIO; - - if (error) - device_printf(sc->sc_dev, "input FIFO timeout, msg [0x%x,0x%x]\n", - msg[0], msg[1]); - return error; + if (!ififo_wait(sc)) + return EIO; + npe_reg_write(sc, IX_NPEFIFO, msg[1]); + + return 0; } -static int -ixpnpe_recvmsg_locked(struct ixpnpe_softc *sc, uint32_t msg[2]) +/* + * Send a msg to the NPE and wait for a reply. We spin as + * we may be called early with interrupts not properly setup. + */ +int +ixpnpe_sendandrecvmsg_sync(struct ixpnpe_softc *sc, + const uint32_t send[2], uint32_t recv[2]) { - mtx_assert(&sc->sc_mtx, MA_OWNED); + int error; + + mtx_lock(&sc->sc_mtx); + error = putmsg(sc, send); + if (error == 0) + error = getmsg(sc, recv); + mtx_unlock(&sc->sc_mtx); - if (!sc->sc_msgwaiting) - msleep(sc, &sc->sc_mtx, 0, "npemh", 0); - bcopy(sc->sc_msg, msg, sizeof(sc->sc_msg)); - /* NB: sc_msgwaiting != 1 means the ack fetch failed */ - return sc->sc_msgwaiting != 1 ? EIO : 0; + return error; } /* - * Send a msg to the NPE and wait for a reply. We use the - * private mutex and sleep until an interrupt is received - * signalling the availability of data in the output FIFO - * so the caller cannot be holding a mutex. May be better - * piggyback on the caller's mutex instead but that would - * make other locking confusing. + * Send a msg to the NPE w/o waiting for a reply. */ int -ixpnpe_sendandrecvmsg(struct ixpnpe_softc *sc, - const uint32_t send[2], uint32_t recv[2]) +ixpnpe_sendmsg_async(struct ixpnpe_softc *sc, const uint32_t msg[2]) { - int error; + int error; - mtx_lock(&sc->sc_mtx); - error = ixpnpe_sendmsg_locked(sc, send); - if (error == 0) - error = ixpnpe_recvmsg_locked(sc, recv); - mtx_unlock(&sc->sc_mtx); + mtx_lock(&sc->sc_mtx); + error = putmsg(sc, msg); + mtx_unlock(&sc->sc_mtx); - return error; + return error; } -/* XXX temporary, not reliable */ +static int +recvmsg_locked(struct ixpnpe_softc *sc, uint32_t msg[2]) +{ + mtx_assert(&sc->sc_mtx, MA_OWNED); + + DPRINTF(sc->sc_dev, "%s: msgwaiting %d\n", __func__, sc->sc_msgwaiting); + if (sc->sc_msgwaiting) { + msg[0] = sc->sc_msg[0]; + msg[1] = sc->sc_msg[1]; + sc->sc_msgwaiting = 0; + return 0; + } + return EAGAIN; +} +/* + * Receive any msg previously received from the NPE. If nothing + * is available we return EAGAIN and the caller is required to + * do a synchronous receive or try again later. + */ int -ixpnpe_sendmsg(struct ixpnpe_softc *sc, const uint32_t msg[2]) +ixpnpe_recvmsg_async(struct ixpnpe_softc *sc, uint32_t msg[2]) { - int error; + int error; - mtx_lock(&sc->sc_mtx); - error = ixpnpe_sendmsg_locked(sc, msg); - mtx_unlock(&sc->sc_mtx); + mtx_lock(&sc->sc_mtx); + error = recvmsg_locked(sc, msg); + mtx_unlock(&sc->sc_mtx); - return error; + return error; } +/* + * Receive a msg from the NPE. If one was received asynchronously + * then it's returned; otherwise we poll synchronously. + */ int -ixpnpe_recvmsg(struct ixpnpe_softc *sc, uint32_t msg[2]) +ixpnpe_recvmsg_sync(struct ixpnpe_softc *sc, uint32_t msg[2]) { - int error; + int error; - mtx_lock(&sc->sc_mtx); - if (sc->sc_msgwaiting) - bcopy(sc->sc_msg, msg, sizeof(sc->sc_msg)); - /* NB: sc_msgwaiting != 1 means the ack fetch failed */ - error = sc->sc_msgwaiting != 1 ? EIO : 0; - mtx_unlock(&sc->sc_mtx); + mtx_lock(&sc->sc_mtx); + error = recvmsg_locked(sc, msg); + if (error == EAGAIN) + error = getmsg(sc, msg); + mtx_unlock(&sc->sc_mtx); - return error; + return error; } diff --git a/sys/arm/xscale/ixp425/ixp425_npevar.h b/sys/arm/xscale/ixp425/ixp425_npevar.h index 6d365fc..286f216 100644 --- a/sys/arm/xscale/ixp425/ixp425_npevar.h +++ b/sys/arm/xscale/ixp425/ixp425_npevar.h @@ -95,11 +95,18 @@ #define NPEFW_B_DMA 0x01020100 /* DMA only */ /* XXX ... more not include */ -#define IXP425_NPE_B_IMAGEID 0x01000200 -#define IXP425_NPE_C_IMAGEID 0x02000200 +/* NPE ID's */ +#define NPE_A 0 +#define NPE_B 1 +#define NPE_C 2 +#define NPE_MAX (NPE_C+1) + +#define IXP425_NPE_A_IMAGEID 0x10820200 +#define IXP425_NPE_B_IMAGEID 0x01020201 +#define IXP425_NPE_C_IMAGEID 0x02050201 struct ixpnpe_softc; -struct ixpnpe_softc *ixpnpe_attach(device_t); +struct ixpnpe_softc *ixpnpe_attach(device_t, int npeid); void ixpnpe_detach(struct ixpnpe_softc *); int ixpnpe_stopandreset(struct ixpnpe_softc *); int ixpnpe_start(struct ixpnpe_softc *); @@ -108,8 +115,9 @@ int ixpnpe_init(struct ixpnpe_softc *, const char *imageName, uint32_t imageId); int ixpnpe_getfunctionality(struct ixpnpe_softc *sc); -int ixpnpe_sendmsg(struct ixpnpe_softc *, const uint32_t msg[2]); -int ixpnpe_recvmsg(struct ixpnpe_softc *, uint32_t msg[2]); -int ixpnpe_sendandrecvmsg(struct ixpnpe_softc *, const uint32_t send[2], - uint32_t recv[2]); +int ixpnpe_sendmsg_async(struct ixpnpe_softc *, const uint32_t msg[2]); +int ixpnpe_recvmsg_async(struct ixpnpe_softc *, uint32_t msg[2]); +int ixpnpe_sendandrecvmsg_sync(struct ixpnpe_softc *, + const uint32_t send[2], uint32_t recv[2]); +int ixpnpe_recvmsg_sync(struct ixpnpe_softc *, uint32_t msg[2]); #endif /* _IXP425_NPEVAR_H_ */ diff --git a/sys/arm/xscale/ixp425/ixp425_pci.c b/sys/arm/xscale/ixp425/ixp425_pci.c index aa40b90..d89c975 100644 --- a/sys/arm/xscale/ixp425/ixp425_pci.c +++ b/sys/arm/xscale/ixp425/ixp425_pci.c @@ -89,8 +89,7 @@ static pcib_route_interrupt_t ixppcib_route_interrupt; static int ixppcib_probe(device_t dev) { - - device_set_desc(dev, "IXP425 PCI Bus"); + device_set_desc(dev, "IXP4XX PCI Bus"); return (0); } @@ -130,8 +129,8 @@ ixppcib_attach(device_t dev) if (sc->sc_mem == NULL) panic("cannot allocate PCI MEM space"); -#define AHB_OFFSET 0x10000000UL - if (bus_dma_tag_create(NULL, 1, 0, AHB_OFFSET + 64 * 1024 * 1024, + /* NB: PCI dma window is 64M so anything above must be bounced */ + if (bus_dma_tag_create(NULL, 1, 0, IXP425_AHB_OFFSET + 64 * 1024 * 1024, BUS_SPACE_MAXADDR, NULL, NULL, 0xffffffff, 0xff, 0xffffffff, 0, NULL, NULL, &sc->sc_dmat)) panic("couldn't create the PCI dma tag !"); @@ -153,7 +152,7 @@ ixppcib_attach(device_t dev) /* Initialize memory and i/o rmans. */ sc->sc_io_rman.rm_type = RMAN_ARRAY; - sc->sc_io_rman.rm_descr = "IXP425 PCI I/O Ports"; + sc->sc_io_rman.rm_descr = "IXP4XX PCI I/O Ports"; if (rman_init(&sc->sc_io_rman) != 0 || rman_manage_region(&sc->sc_io_rman, 0, IXP425_PCI_IO_SIZE) != 0) { @@ -161,7 +160,7 @@ ixppcib_attach(device_t dev) } sc->sc_mem_rman.rm_type = RMAN_ARRAY; - sc->sc_mem_rman.rm_descr = "IXP425 PCI Memory"; + sc->sc_mem_rman.rm_descr = "IXP4XX PCI Memory"; if (rman_init(&sc->sc_mem_rman) != 0 || rman_manage_region(&sc->sc_mem_rman, IXP425_PCI_MEM_HWBASE, IXP425_PCI_MEM_HWBASE + IXP425_PCI_MEM_SIZE) != 0) { @@ -173,20 +172,20 @@ ixppcib_attach(device_t dev) * begin at the physical memory start + OFFSET */ PCI_CSR_WRITE_4(sc, PCI_AHBMEMBASE, - (AHB_OFFSET & 0xFF000000) + - ((AHB_OFFSET & 0xFF000000) >> 8) + - ((AHB_OFFSET & 0xFF000000) >> 16) + - ((AHB_OFFSET & 0xFF000000) >> 24) + + (IXP425_AHB_OFFSET & 0xFF000000) + + ((IXP425_AHB_OFFSET & 0xFF000000) >> 8) + + ((IXP425_AHB_OFFSET & 0xFF000000) >> 16) + + ((IXP425_AHB_OFFSET & 0xFF000000) >> 24) + 0x00010203); #define IXPPCIB_WRITE_CONF(sc, reg, val) \ ixp425_pci_conf_reg_write(sc, reg, val) /* Write Mapping registers PCI Configuration Registers */ /* Base Address 0 - 3 */ - IXPPCIB_WRITE_CONF(sc, PCI_MAPREG_BAR0, AHB_OFFSET + 0x00000000); - IXPPCIB_WRITE_CONF(sc, PCI_MAPREG_BAR1, AHB_OFFSET + 0x01000000); - IXPPCIB_WRITE_CONF(sc, PCI_MAPREG_BAR2, AHB_OFFSET + 0x02000000); - IXPPCIB_WRITE_CONF(sc, PCI_MAPREG_BAR3, AHB_OFFSET + 0x03000000); + IXPPCIB_WRITE_CONF(sc, PCI_MAPREG_BAR0, IXP425_AHB_OFFSET + 0x00000000); + IXPPCIB_WRITE_CONF(sc, PCI_MAPREG_BAR1, IXP425_AHB_OFFSET + 0x01000000); + IXPPCIB_WRITE_CONF(sc, PCI_MAPREG_BAR2, IXP425_AHB_OFFSET + 0x02000000); + IXPPCIB_WRITE_CONF(sc, PCI_MAPREG_BAR3, IXP425_AHB_OFFSET + 0x03000000); /* Base Address 4 */ IXPPCIB_WRITE_CONF(sc, PCI_MAPREG_BAR4, 0xffffffff); diff --git a/sys/arm/xscale/ixp425/ixp425_qmgr.c b/sys/arm/xscale/ixp425/ixp425_qmgr.c index 4188169..4229466 100644 --- a/sys/arm/xscale/ixp425/ixp425_qmgr.c +++ b/sys/arm/xscale/ixp425/ixp425_qmgr.c @@ -161,7 +161,7 @@ struct ixpqmgr_softc { static int qmgr_debug = 0; SYSCTL_INT(_debug, OID_AUTO, qmgr, CTLFLAG_RW, &qmgr_debug, - 0, "IXP425 Q-Manager debug msgs"); + 0, "IXP4XX Q-Manager debug msgs"); TUNABLE_INT("debug.qmgr", &qmgr_debug); #define DPRINTF(dev, fmt, ...) do { \ if (qmgr_debug) printf(fmt, __VA_ARGS__); \ @@ -204,7 +204,7 @@ aqm_reg_write(struct ixpqmgr_softc *sc, bus_size_t off, uint32_t val) static int ixpqmgr_probe(device_t dev) { - device_set_desc(dev, "IXP425 Q-Manager"); + device_set_desc(dev, "IXP4XX Q-Manager"); return 0; } diff --git a/sys/arm/xscale/ixp425/ixp425_timer.c b/sys/arm/xscale/ixp425/ixp425_timer.c index e7717d0..e0b70e9 100644 --- a/sys/arm/xscale/ixp425/ixp425_timer.c +++ b/sys/arm/xscale/ixp425/ixp425_timer.c @@ -86,14 +86,14 @@ static struct timecounter ixp425_timer_timecounter = { NULL, /* no poll_pps */ ~0u, /* counter_mask */ COUNTS_PER_SEC, /* frequency */ - "IXP425 Timer", /* name */ + "IXP4XX Timer", /* name */ 1000, /* quality */ }; static int ixpclk_probe(device_t dev) { - device_set_desc(dev, "IXP425 Timer"); + device_set_desc(dev, "IXP4XX Timer"); return (0); } diff --git a/sys/arm/xscale/ixp425/ixp425_wdog.c b/sys/arm/xscale/ixp425/ixp425_wdog.c index 9db9cce..156378d 100644 --- a/sys/arm/xscale/ixp425/ixp425_wdog.c +++ b/sys/arm/xscale/ixp425/ixp425_wdog.c @@ -25,7 +25,7 @@ __FBSDID("$FreeBSD$"); /* - * IXP425 Watchdog Timer Support. + * IXP4XX Watchdog Timer Support. */ #include <sys/param.h> #include <sys/systm.h> @@ -88,7 +88,7 @@ ixp425_watchdog(void *arg, u_int cmd, int *error) static int ixpwdog_probe(device_t dev) { - device_set_desc(dev, "IXP425 Watchdog Timer"); + device_set_desc(dev, "IXP4XX Watchdog Timer"); return (0); } diff --git a/sys/arm/xscale/ixp425/ixp425reg.h b/sys/arm/xscale/ixp425/ixp425reg.h index c7b7206..4b2af08 100644 --- a/sys/arm/xscale/ixp425/ixp425reg.h +++ b/sys/arm/xscale/ixp425/ixp425reg.h @@ -64,31 +64,52 @@ * * 4000 0000 --------------------------- * SDRAM - * 1000 0000 --------------------------- + * 0000 0000 --------------------------- */ /* - * Virtual memory map for the Intel IXP425 integrated devices + * Virtual memory map for the Intel IXP425/IXP435 integrated devices */ /* * FFFF FFFF --------------------------- * + * Global cache clean area + * FF00 0000 --------------------------- + * * FC00 0000 --------------------------- * PCI Data (memory space) - * F800 0000 --------------------------- + * F800 0000 --------------------------- IXP425_PCI_MEM_VBASE * * F020 1000 --------------------------- - * SDRAM Controller - * F020 0000 --------------------------- + * SDRAM/DDR Memory Controller + * F020 0000 --------------------------- IXP425_MCU_VBASE * - * F001 2000 --------------------------- - * PCI Configuration and Status Registers - * F001 1000 --------------------------- - * Expansion bus Configuration Registers - * F001 0000 --------------------------- - * System and Peripheral Registers - * VA F000 0000 = PA C800 0000 (SIZE 0x10000) - * F000 0000 --------------------------- + * F001 7000 EHCI USB 2 (IXP435) + * F001 6000 EHCI USB 1 (IXP435) + * F020 6000 --------------------------- + * Queue manager + * F001 2000 --------------------------- IXP425_QMGR_VBASE + * PCI Configuration and Status + * F001 1000 --------------------------- IXP425_PCI_VBASE + * Expansion Bus Configuration + * F001 0000 --------------------------- IXP425_EXP_VBASE + * F000 F000 Expansion Bus Chip Select 4 + * F000 E000 Expansion Bus Chip Select 3 + * F000 D000 Expansion Bus Chip Select 2 + * F000 C000 Expansion Bus Chip Select 1 + * F000 B000 USB (option on IXP425) + * F000 A000 MAC-B (IXP425) | MAC-C (IXP435) + * F000 9000 MAC-A + * F000 8000 NPE-C + * F000 7000 NPE-B (IXP425) + * F000 6000 NPE-A + * F000 5000 Timers + * F000 4000 GPIO Controller + * F000 3000 Interrupt Controller + * F000 2000 Performance Monitor Controller (PMC) + * F000 1000 UART 1 (IXP425) + * F000 0000 UART 0 + * F000 0000 --------------------------- IXP425_IO_VBASE * * 0000 0000 --------------------------- * @@ -111,9 +132,10 @@ #define IXP425_NPE_A_OFFSET 0x00006000UL /* Not User Programmable */ #define IXP425_NPE_B_OFFSET 0x00007000UL /* Not User Programmable */ #define IXP425_NPE_C_OFFSET 0x00008000UL /* Not User Programmable */ -#define IXP425_MAC_A_OFFSET 0x00009000UL -#define IXP425_MAC_B_OFFSET 0x0000a000UL +#define IXP425_MAC_B_OFFSET 0x00009000UL /* Ethernet MAC on NPE-B */ +#define IXP425_MAC_C_OFFSET 0x0000a000UL /* Ethernet MAC on NPE-C */ #define IXP425_USB_OFFSET 0x0000b000UL +#define IXP435_MAC_A_OFFSET 0x0000c000UL /* Ethernet MAC on NPE-A */ #define IXP425_REG_SIZE 0x1000 @@ -142,7 +164,6 @@ /* * Timers - * */ #define IXP425_TIMER_HWBASE (IXP425_IO_HWBASE + IXP425_TIMER_OFFSET) #define IXP425_TIMER_VBASE (IXP425_IO_VBASE + IXP425_TIMER_OFFSET) @@ -224,6 +245,18 @@ #define IXP425_INT_NPE_B 1 /* NPE B */ #define IXP425_INT_NPE_A 0 /* NPE A */ +/* NB: IXP435 has an additional 32 IRQ's */ +#define IXP435_INT_STATUS2 (IXP425_IRQ_VBASE + 0x20) +#define IXP435_INT_ENABLE2 (IXP425_IRQ_VBASE + 0x24) +#define IXP435_INT_SELECT2 (IXP425_IRQ_VBASE + 0x28) +#define IXP435_IRQ_STATUS2 (IXP425_IRQ_VBASE + 0x2C) +#define IXP435_FIQ_STATUS2 (IXP425_IRQ_VBASE + 0x30) + +#define IXP435_INT_USB0 32 /* USB Host 2.0 Host 0 */ +#define IXP435_INT_USB1 33 /* USB Host 2.0 Host 1 */ +#define IXP435_INT_QMGR_PER 60 /* Queue manager parity error */ +#define IXP435_INT_ECC 61 /* Single or multi-bit ECC error */ + /* * software interrupt */ @@ -239,6 +272,11 @@ (1 << IXP425_INT_bit11))) #define IXP425_INT_GPIOMASK (0x3ff800c0u) +#define IXP435_INT_HWMASK ((1 << (IXP435_INT_USB0 - 32)) | \ + (1 << (IXP435_INT_USB1 - 32)) | \ + (1 << (IXP435_INT_QMGR_PER - 32)) | \ + (1 << (IXP435_INT_ECC - 32))) + /* * GPIO */ @@ -383,6 +421,8 @@ /* 0xf0011000 */ #define IXP425_PCI_SIZE IXP425_REG_SIZE /* 0x1000 */ +#define IXP425_AHB_OFFSET 0x00000000UL /* AHB bus */ + /* * Mapping registers of IXP425 PCI Configuration */ @@ -491,6 +531,28 @@ #define MCU_SDR_IR 0x08 /* + * IXP435 DDR MCU Registers + */ +#define IXP435_MCU_HWBASE 0xcc00e500UL +#define MCU_DDR_SDIR 0x00 /* DDR SDAM Initialization Reg*/ +#define MCU_DDR_SDCR0 0x04 /* DDR SDRAM Control Reg 0 */ +#define MCU_DDR_SDCR1 0x08 /* DDR SDRAM Control Reg 1 */ +#define MCU_DDR_SDBR 0x0c /* SDRAM Base Register */ +#define MCU_DDR_SBR0 0x10 /* SDRAM Boundary Register 0 */ +#define MCU_DDR_SBR1 0x14 /* SDRAM Boundary Register 1 */ +#define MCU_DDR_ECCR 0x1c /* ECC Control Register */ +#define MCU_DDR_ELOG0 0x20 /* ECC Log Register 0 */ +#define MCU_DDR_ELOG1 0x24 /* ECC Log Register 1 */ +#define MCU_DDR_ECAR0 0x28 /* ECC Address Register 0 */ +#define MCU_DDR_ECAR1 0x2c /* ECC Address Register 1 */ +#define MCU_DDR_ECTST 0x30 /* ECC Test Register */ +#define MCU_DDR_MCISR 0x34 /* MC Interrupt Status Reg */ +#define MCU_DDR_MPTCR 0x3c /* MC Port Transaction Cnt Reg*/ +#define MCU_DDR_RFR 0x48 /* Refresh Frequency Register */ +#define MCU_DDR_SDPR(n) (0x50+(n)*4) /* SDRAM Page Register 0-7 */ +/* NB: RCVDLY at 0x1050 and LEGOVERIDE at 0x1074 */ + +/* * Performance Monitoring Unit (CP14) * * CP14.0.1 Performance Monitor Control Register(PMNC) @@ -549,14 +611,18 @@ #define IXP425_NPE_C_VBASE (IXP425_IO_VBASE + IXP425_NPE_C_OFFSET) #define IXP425_NPE_C_SIZE 0x1000 /* Actually only 256 bytes */ -#define IXP425_MAC_A_HWBASE (IXP425_IO_HWBASE + IXP425_MAC_A_OFFSET) -#define IXP425_MAC_A_VBASE (IXP425_IO_VBASE + IXP425_MAC_A_OFFSET) -#define IXP425_MAC_A_SIZE 0x1000 /* Actually only 256 bytes */ - #define IXP425_MAC_B_HWBASE (IXP425_IO_HWBASE + IXP425_MAC_B_OFFSET) #define IXP425_MAC_B_VBASE (IXP425_IO_VBASE + IXP425_MAC_B_OFFSET) #define IXP425_MAC_B_SIZE 0x1000 /* Actually only 256 bytes */ +#define IXP425_MAC_C_HWBASE (IXP425_IO_HWBASE + IXP425_MAC_C_OFFSET) +#define IXP425_MAC_C_VBASE (IXP425_IO_VBASE + IXP425_MAC_C_OFFSET) +#define IXP425_MAC_C_SIZE 0x1000 /* Actually only 256 bytes */ + +#define IXP435_MAC_A_HWBASE (IXP425_IO_HWBASE + IXP435_MAC_A_OFFSET) +#define IXP435_MAC_A_VBASE (IXP425_IO_VBASE + IXP435_MAC_A_OFFSET) +#define IXP435_MAC_A_SIZE 0x1000 /* Actually only 256 bytes */ + /* * Expansion Bus Data Space. */ @@ -565,7 +631,6 @@ #define IXP425_EXP_BUS_CSx_HWBASE(i) \ (IXP425_EXP_BUS_HWBASE + (i)*IXP425_EXP_BUS_SIZE) - #define IXP425_EXP_BUS_CSx_VBASE(i) \ (IXP425_MAC_B_VBASE + (i)*IXP425_MAC_B_SIZE) @@ -588,4 +653,26 @@ #define IXP425_EXP_BUS_CS6_HWBASE IXP425_EXP_BUS_CSx_HWBASE(6) #define IXP425_EXP_BUS_CS7_HWBASE IXP425_EXP_BUS_CSx_HWBASE(7) +/* + * IXP435/Gateworks Cambria + */ +#define CAMBRIA_GPS_HWBASE 0x53FC0000UL /* optional GPS Serial Port */ +#define CAMBRIA_GPS_SIZE 0x40000 +#define CAMBRIA_RS485_HWBASE 0x53F80000UL /* optional RS485 Serial Port */ +#define CAMBRIA_RS485_SIZE 0x40000 +#define CAMBRIA_OCTAL_LED_HWBASE 0x53F40000UL /* Octal Status LED Latch */ +#define CAMBRIA_OCTAL_LED_SIZE 0x1000 +#define CAMBRIA_CFSEL1_HWBASE 0x53E40000UL /* Compact Flash Socket Sel 0 */ +#define CAMBRIA_CFSEL1_SIZE 0x40000 +#define CAMBRIA_CFSEL0_HWBASE 0x53E00000UL /* Compact Flash Socket Sel 1 */ +#define CAMBRIA_CFSEL0_SIZE 0x40000 + +#define IXP435_USB1_HWBASE 0xcd000000UL /* USB host controller 1 */ +#define IXP435_USB1_VBASE (IXP425_QMGR_VBASE + IXP425_QMGR_SIZE) +#define IXP435_USB1_SIZE 0x1000 /* NB: only uses 0x300 */ + +#define IXP435_USB2_HWBASE 0xce000000UL /* USB host controller 2 */ +#define IXP435_USB2_VBASE (IXP435_USB1_VBASE + IXP435_USB1_SIZE) +#define IXP435_USB2_SIZE 0x1000 /* NB: only uses 0x300 */ + #endif /* _IXP425REG_H_ */ diff --git a/sys/arm/xscale/ixp425/ixp425var.h b/sys/arm/xscale/ixp425/ixp425var.h index 7503741..87986be 100644 --- a/sys/arm/xscale/ixp425/ixp425var.h +++ b/sys/arm/xscale/ixp425/ixp425var.h @@ -47,6 +47,10 @@ #include <dev/pci/pcivar.h> #include <sys/rman.h> +/* NB: cputype is setup by set_cpufuncs */ +#define cpu_is_ixp43x() (cputype == CPU_ID_IXP435) +#define cpu_is_ixp46x() (cputype == CPU_ID_IXP465) + struct ixp425_softc { device_t sc_dev; bus_space_tag_t sc_iot; @@ -94,6 +98,7 @@ void ixp425_io_bs_init(bus_space_tag_t, void *); void ixp425_mem_bs_init(bus_space_tag_t, void *); uint32_t ixp425_sdram_size(void); +uint32_t ixp435_ddram_size(void); int ixp425_md_route_interrupt(device_t, device_t, int); void ixp425_md_attach(device_t); diff --git a/sys/arm/xscale/ixp425/ixp435_ehci.c b/sys/arm/xscale/ixp425/ixp435_ehci.c new file mode 100644 index 0000000..b74f73c --- /dev/null +++ b/sys/arm/xscale/ixp425/ixp435_ehci.c @@ -0,0 +1,357 @@ +/*- + * Copyright (c) 2008 Sam Leffler. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * IXP435 attachment driver for the USB Enhanced Host Controller. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "opt_bus.h" + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/module.h> +#include <sys/lock.h> +#include <sys/mutex.h> +#include <sys/bus.h> +#include <sys/endian.h> +#include <sys/queue.h> +#include <sys/lockmgr.h> +#include <sys/rman.h> + +#include <machine/bus.h> +#include <machine/resource.h> + +#include <dev/usb/usb.h> +#include <dev/usb/usbdi.h> +#include <dev/usb/usbdivar.h> +#include <dev/usb/usb_mem.h> + +#include <dev/usb/ehcireg.h> +#include <dev/usb/ehcivar.h> + +#include <arm/xscale/ixp425/ixp425reg.h> +#include <arm/xscale/ixp425/ixp425var.h> + +#define EHCI_VENDORID_IXP4XX 0x42fa05 +#define EHCI_HC_DEVSTR "IXP4XX Integrated USB 2.0 controller" + +struct ixp_ehci_softc { + ehci_softc_t base; /* storage for EHCI code */ + bus_space_tag_t iot; + bus_space_handle_t ioh; + struct bus_space tag; /* tag for private bus space ops */ +}; + +static int ehci_ixp_detach(device_t self); + +static uint8_t ehci_bs_r_1(void *, bus_space_handle_t, bus_size_t); +static void ehci_bs_w_1(void *, bus_space_handle_t, bus_size_t, u_int8_t); +static uint16_t ehci_bs_r_2(void *, bus_space_handle_t, bus_size_t); +static void ehci_bs_w_2(void *, bus_space_handle_t, bus_size_t, uint16_t); +static uint32_t ehci_bs_r_4(void *, bus_space_handle_t, bus_size_t); +static void ehci_bs_w_4(void *, bus_space_handle_t, bus_size_t, uint32_t); + +static int +ehci_ixp_suspend(device_t self) +{ + ehci_softc_t *sc; + int err; + + err = bus_generic_suspend(self); + if (err == 0) { + sc = device_get_softc(self); + ehci_power(PWR_SUSPEND, sc); + } + return err; +} + +static int +ehci_ixp_resume(device_t self) +{ + ehci_softc_t *sc = device_get_softc(self); + + ehci_power(PWR_RESUME, sc); + bus_generic_resume(self); + return 0; +} + +static int +ehci_ixp_shutdown(device_t self) +{ + ehci_softc_t *sc; + int err; + + err = bus_generic_shutdown(self); + if (err == 0) { + sc = device_get_softc(self); + ehci_shutdown(sc); + } + return err; +} + +static int +ehci_ixp_probe(device_t self) +{ + device_set_desc(self, EHCI_HC_DEVSTR); + return BUS_PROBE_DEFAULT; +} + +static int +ehci_ixp_attach(device_t self) +{ + struct ixp_ehci_softc *isc = device_get_softc(self); + ehci_softc_t *sc = &isc->base; + int err, rid; + + sc->sc_bus.usbrev = USBREV_2_0; + + /* NB: hints fix the memory location and irq */ + + rid = 0; + sc->io_res = bus_alloc_resource_any(self, SYS_RES_MEMORY, + &rid, RF_ACTIVE); + if (sc->io_res == NULL) { + device_printf(self, "Could not map memory\n"); + return ENXIO; + } + + /* + * Craft special resource for bus space ops that handle + * byte-alignment of non-word addresses. Also, since + * we're already intercepting bus space ops we handle + * the register window offset that could otherwise be + * done with bus_space_subregion. + */ + isc->iot = rman_get_bustag(sc->io_res); + isc->tag.bs_cookie = isc->iot; + /* read single */ + isc->tag.bs_r_1 = ehci_bs_r_1, + isc->tag.bs_r_2 = ehci_bs_r_2, + isc->tag.bs_r_4 = ehci_bs_r_4, + /* write (single) */ + isc->tag.bs_w_1 = ehci_bs_w_1, + isc->tag.bs_w_2 = ehci_bs_w_2, + isc->tag.bs_w_4 = ehci_bs_w_4, + + sc->iot = &isc->tag; + sc->ioh = rman_get_bushandle(sc->io_res); + sc->sc_size = IXP435_USB1_SIZE - 0x100; + + rid = 0; + sc->irq_res = bus_alloc_resource_any(self, SYS_RES_IRQ, + &rid, RF_ACTIVE); + if (sc->irq_res == NULL) { + device_printf(self, "Could not allocate irq\n"); + ehci_ixp_detach(self); + return ENXIO; + } + sc->sc_bus.bdev = device_add_child(self, "usb", -1); + if (!sc->sc_bus.bdev) { + device_printf(self, "Could not add USB device\n"); + ehci_ixp_detach(self); + return ENOMEM; + } + device_set_ivars(sc->sc_bus.bdev, &sc->sc_bus); + + sprintf(sc->sc_vendor, "Intel"); + sc->sc_id_vendor = EHCI_VENDORID_IXP4XX; + + err = bus_setup_intr(self, sc->irq_res, INTR_TYPE_BIO, + NULL, (driver_intr_t*)ehci_intr, sc, &sc->ih); + if (err) { + device_printf(self, "Could not setup irq, %d\n", err); + sc->ih = NULL; + ehci_ixp_detach(self); + return ENXIO; + } + + /* There are no companion USB controllers */ + sc->sc_ncomp = 0; + + /* Allocate a parent dma tag for DMA maps */ + err = bus_dma_tag_create(bus_get_dma_tag(self), 1, 0, + BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, + BUS_SPACE_MAXSIZE_32BIT, USB_DMA_NSEG, BUS_SPACE_MAXSIZE_32BIT, 0, + NULL, NULL, &sc->sc_bus.parent_dmatag); + if (err) { + device_printf(self, "Could not allocate parent DMA tag (%d)\n", + err); + ehci_ixp_detach(self); + return ENXIO; + } + + /* Allocate a dma tag for transfer buffers */ + err = bus_dma_tag_create(sc->sc_bus.parent_dmatag, 1, 0, + BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, + BUS_SPACE_MAXSIZE_32BIT, USB_DMA_NSEG, BUS_SPACE_MAXSIZE_32BIT, 0, + busdma_lock_mutex, &Giant, &sc->sc_bus.buffer_dmatag); + if (err) { + device_printf(self, "Could not allocate buffer DMA tag (%d)\n", + err); + ehci_ixp_detach(self); + return ENXIO; + } + + /* + * Arrange to force Host mode, select big-endian byte alignment, + * and arrange to not terminate reset operations (the adapter + * will ignore it if we do but might as well save a reg write). + * Also, the controller has an embedded Transaction Translator + * which means port speed must be read from the Port Status + * register following a port enable. + */ + sc->sc_flags |= EHCI_SCFLG_SETMODE + | EHCI_SCFLG_NORESTERM + | EHCI_SCFLG_FORCESPEED + | EHCI_SCFLG_BIGEDESC + ; + err = ehci_init(sc); + if (!err) { + sc->sc_flags |= EHCI_SCFLG_DONEINIT; + err = device_probe_and_attach(sc->sc_bus.bdev); + } + + if (err) { + device_printf(self, "USB init failed err=%d\n", err); + ehci_ixp_detach(self); + return EIO; + } + return 0; +} + +static int +ehci_ixp_detach(device_t self) +{ + struct ixp_ehci_softc *isc = device_get_softc(self); + ehci_softc_t *sc = &isc->base; + int err; + + if (sc->sc_flags & EHCI_SCFLG_DONEINIT) { + ehci_detach(sc, 0); + sc->sc_flags &= ~EHCI_SCFLG_DONEINIT; + } + + /* + * Disable interrupts that might have been switched on in ehci_init() + */ + if (sc->iot && sc->ioh) + bus_space_write_4(sc->iot, sc->ioh, EHCI_USBINTR, 0); + if (sc->sc_bus.parent_dmatag != NULL) + bus_dma_tag_destroy(sc->sc_bus.parent_dmatag); + if (sc->sc_bus.buffer_dmatag != NULL) + bus_dma_tag_destroy(sc->sc_bus.buffer_dmatag); + + if (sc->irq_res && sc->ih) { + err = bus_teardown_intr(self, sc->irq_res, sc->ih); + + if (err) + device_printf(self, "Could not tear down irq, %d\n", + err); + sc->ih = NULL; + } + if (sc->sc_bus.bdev != NULL) { + device_delete_child(self, sc->sc_bus.bdev); + sc->sc_bus.bdev = NULL; + } + if (sc->irq_res != NULL) { + bus_release_resource(self, SYS_RES_IRQ, 0, sc->irq_res); + sc->irq_res = NULL; + } + if (sc->io_res != NULL) { + bus_release_resource(self, SYS_RES_MEMORY, 0, sc->io_res); + sc->io_res = NULL; + } + sc->iot = 0; + sc->ioh = 0; + return 0; +} + +/* + * Bus space accessors for PIO operations. + */ + +static uint8_t +ehci_bs_r_1(void *t, bus_space_handle_t h, bus_size_t o) +{ + return bus_space_read_1((bus_space_tag_t) t, h, + 0x100 + (o &~ 3) + (3 - (o & 3))); +} + +static void +ehci_bs_w_1(void *t, bus_space_handle_t h, bus_size_t o, u_int8_t v) +{ + panic("%s", __func__); +} + +static uint16_t +ehci_bs_r_2(void *t, bus_space_handle_t h, bus_size_t o) +{ + return bus_space_read_2((bus_space_tag_t) t, h, + 0x100 + (o &~ 3) + (2 - (o & 3))); +} + +static void +ehci_bs_w_2(void *t, bus_space_handle_t h, bus_size_t o, uint16_t v) +{ + panic("%s", __func__); +} + +static uint32_t +ehci_bs_r_4(void *t, bus_space_handle_t h, bus_size_t o) +{ + return bus_space_read_4((bus_space_tag_t) t, h, 0x100 + o); +} + +static void +ehci_bs_w_4(void *t, bus_space_handle_t h, bus_size_t o, uint32_t v) +{ + bus_space_write_4((bus_space_tag_t) t, h, 0x100 + o, v); +} + +static device_method_t ehci_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, ehci_ixp_probe), + DEVMETHOD(device_attach, ehci_ixp_attach), + DEVMETHOD(device_detach, ehci_ixp_detach), + DEVMETHOD(device_suspend, ehci_ixp_suspend), + DEVMETHOD(device_resume, ehci_ixp_resume), + DEVMETHOD(device_shutdown, ehci_ixp_shutdown), + + /* Bus interface */ + DEVMETHOD(bus_print_child, bus_generic_print_child), + + {0, 0} +}; + +static driver_t ehci_driver = { + "ehci", + ehci_methods, + sizeof(struct ixp_ehci_softc), +}; +static devclass_t ehci_devclass; +DRIVER_MODULE(ehci, ixp, ehci_driver, ehci_devclass, 0, 0); diff --git a/sys/arm/xscale/ixp425/std.avila b/sys/arm/xscale/ixp425/std.avila index b69a65e..77036ee 100644 --- a/sys/arm/xscale/ixp425/std.avila +++ b/sys/arm/xscale/ixp425/std.avila @@ -1,6 +1,22 @@ -#GW2348-4 board configuration #$FreeBSD$ -include "../xscale/ixp425/std.ixp425" + +# +# Gateworks GW23XX board configuration +# files "../xscale/ixp425/files.avila" -makeoptions KERNPHYSADDR=0x10200000 +# +# Physical memory starts at 0. We assume images are loaded at +# 0x200000, e.g. from redboot with load -b 0x200000 kernel. +# +# Redboot is expected to handle unmapping the flash memory that +# appears at 0 on boot. Likewise we expect the expansion bus to +# be remapped away from 0. +# +options PHYSADDR=0x00000000 +options KERNPHYSADDR=0x00200000 +makeoptions KERNPHYSADDR=0x00200000 +options KERNVIRTADDR=0xc0200000 # Used in ldscript.arm makeoptions KERNVIRTADDR=0xc0200000 +options FLASHADDR=0x50000000 +options LOADERRAMADDR=0x00000000 +options STARTUP_PAGETABLE_ADDR=0x00000000 diff --git a/sys/arm/xscale/ixp425/std.ixp435 b/sys/arm/xscale/ixp425/std.ixp435 new file mode 100644 index 0000000..2cc099a --- /dev/null +++ b/sys/arm/xscale/ixp425/std.ixp435 @@ -0,0 +1,8 @@ +#XScale IXP435 generic configuration +#$FreeBSD$ + +files "../xscale/ixp425/files.ixp425" +include "../xscale/std.xscale" +cpu CPU_XSCALE_IXP435 +cpu CPU_XSCALE_IXP425 +makeoption ARM_BIG_ENDIAN diff --git a/sys/conf/files b/sys/conf/files index d09ead4..8c2316fa 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -1476,6 +1476,7 @@ dev/ubsec/ubsec.c optional ubsec # # USB support dev/usb/ehci.c optional ehci +dev/usb/ehci_ddb.c optional ehci dev/usb/ehci_pci.c optional ehci pci dev/usb/hid.c optional usb dev/usb/if_aue.c optional aue diff --git a/sys/conf/options.arm b/sys/conf/options.arm index 6c8732c..2985e00 100644 --- a/sys/conf/options.arm +++ b/sys/conf/options.arm @@ -15,6 +15,7 @@ CPU_XSCALE_80219 opt_global.h CPU_XSCALE_80321 opt_global.h CPU_XSCALE_81342 opt_global.h CPU_XSCALE_IXP425 opt_global.h +CPU_XSCALE_IXP435 opt_global.h CPU_XSCALE_PXA2X0 opt_global.h FLASHADDR opt_global.h KERNPHYSADDR opt_global.h diff --git a/sys/contrib/dev/npe/IxNpeMicrocode.dat.uu b/sys/contrib/dev/npe/IxNpeMicrocode.dat.uu index c83422b..0f380cd 100644 --- a/sys/contrib/dev/npe/IxNpeMicrocode.dat.uu +++ b/sys/contrib/dev/npe/IxNpeMicrocode.dat.uu @@ -1,129 +1,209 @@ -$FreeBSD$ - begin 644 IxNpeMicrocode.dat -M_NWP#1"``@$```NL``````````L````!```%7@````$```MB`````0``"Z(` -M```!```+I0````\````````%41``?A`0`/SP$`!TH!!.O@$%J/R```#YT``` -M=O`0`'0`$`*^`1"$``L0`H@/$`+!_A`"Q?T0`H8#$`*"`A`"__H`6(``$(@` -M"Q`"P?<0A$&'$`*V`A`"__00```+`"@`"P`2__$);(H@#Y#`$`^H0!`0`KX` -M$$0`"P'4P```38<(`"V'!``UAP0`&8<$`"&'!`!1AP0`78<$$$1^<`'8P``0 -M`8L1$`&3$1`!FQ$%!(I0!2@0@`4X$I`%1!2@!4`6L`5L&,`%:!K0$`!^$A`" -M_?402``+#`#```0`Q``)#((0"2A(0!`"O@$)!'=`$`,^`0F,@A`)J$A`$`*^ -M`0F$=U`0`SX!$$1T\`'DX``0`KX!$`&]T1`!N=$0`3?1$`$_T1``=!(0`OW[ -M$``UD!`"O@$01'Z`!X3\`!!&O@$!\.``$`&#T1`!B]$0`9K!$$63T@`(_"$0 -M`'X2$`+Y^A!(Z@`"`.````AQ@!`!Z\\03``+!:C\@```?@``$'8`$`-_H1`! -MRAT0`KX#`##J`!`!Z@D018H'``1V0!``R@<0`S8&$$0`"P`$=S`0`P`!$`!W -M0``JO@D01``+``1W,!`#``$)*&A`$PF^$!``=T`)!SX!"32*(`DH:,`)#(I0 -M"0<^`1`!F@D0`:(%"37F'`DUYA8)->X`$`#:!Q`"N`80`9H($$7*"0``=V`` -M,=H*$)<^%@DH:(`)#:88"27*!A`!D`@0`.0`"22C$`D$D1$0`=`($`#10!`! -MT`H0`8H=$`,^E!!$``L``'=@$)<^`044A"`0`9H%$`&2(1`!BB`0``2P$(*^ -MA044A"`0`<H&$`&2(1`!BB`0@50`$`%6"1`!2`$0`$@`$`'0`Q`!DF`0`9IA -M$`'2"Q`!DF(0`=H,$`&L9A!%T@T0(.P'$`*V9Q!$:@``P.P'$`!K'A`!*`D0 -M`6H#$`!I1A`"N$L0`)CP$$2<D`,@Q0`0`:@C$`&B(!`!$@(0`)57$`";'1`" -MME\0`%``$`&D!A``Q(`0`\#@$`&J(1`!HB`0`)57$`";'1`"ME`0`,1/$`#$ -M&A`!JB$0`:(@$`"55Q``FQT0`K9)$`#$3Q``Q!H0`:HA$`&B(!``E5<0`)L= -M$`*V0A``Q$\0`,0:$`&J(1`!HB`0`)57$`";'1`"MCL0`,1/$`#$&A`!JB$0 -M`:(@$`"55Q``FQT0`K8T$`#$3Q``Q!H0`:HA$`&B(!``E5<0`)L=$`*V+1`` -MQ$\0`,0:$`&J(1`!HB`0`)57$`";'1`"MB80`,1/$`#$&A`!JB$0`:(@$`"5 -M5Q``FQT0`K8?$`#$3Q``Q!H0`:HA$`&B(!``E5<0`)L=$`*V&!!$``L`'&GP -M$`%H`!`!$@D0```+$`!3(Q`!4@@0`%.`$`%2`A`"OA80`%``$`%0!1``;B80 -M`K@#$`%L`!`"__00`1("$```"Q``4H00`5("$`+_[Q`!K&@0`O^9$``19Q`" -M^>@0`&X6$`+WYA``;B00`6XG$`!2`!`!4@(0`9H%$`$$"1``V4$0`)S7$`+[ -M01!%V`H`!'<P$`,``0DH:4`3":X`$)1Q$`DEAV0)!'=`"3WN``5//@$0@$46 -M`#+W91``:#`0`"@C$`!H-Q`"MDT0`$6&$`*X1Q!%*`,`&$3S$``%1!`!D`,0 -M`40#$$11XP,,Q$`0`%'J$``&@1``1`D`))(@$`&8(A`!D`@0`!;``""2D!`` -M``L0```+$`%:!!`!R`D01JXM``#0!Q`"N`T0`<@("2AI(!,)IA@));X8"26F -M$`DEK@@)):8`"26F!`DEK@P)):X0"26N%`D'/A40`(B2$`'("`DH:(`3":88 -M"26^&`DEIA`)!SX!$$6:"0``::`)*"E`"0S:80D<["`)):80"26N"`DEI@`) -M):8$"26N#`DEKA`)):X4"0<^`1``Z@`0`>P($`%H`Q`!H@D)*&A`$`!F!!,) -MIB`))*,0"01W0!`#?O$#&-'`$`&B@!`!*`(0`.(1$`'B@!`"O@40`2@"$``` -M"Q``:880`OFW$`#J`!`!B@D0`>H)$`'L"!`!:`,0`O[G$`!%1!`"OE40EJ#D -M!1",(!``1``0`$&$$`&(81`!!@@&-<=$!C22(`8TFB`0`=-1$`&0'Q`!VU$0 -M`%'Z$``0IA`"N,,01:`"`L#0@!`#P,`0`:J!$`&B@!``FU<0`)4]$`*V(A`` -MT$\01-`:`L#0`A`!JH$0`:*`$`";5Q``E3T0`K8:$`#03Q!$T!H"P-`"$`&J -M@1`!HH`0`)M7$`"5/1`"MA(0`-!/$$30&@+`T`(0`:J!$`&B@!``FU<0`)4] -M$`*V"A``T$\01-`:`L#0`A`!JH$0`:*`$`";5Q``E3T0`K8"$`!B'!`!D!\0 -M`9I=$``BA1``8A80`KB7$`&J'A`!E%P0`&@6$`*X#1``6!80`K8)$`#B"!`` -ME3<0`)L=$`*V!Q``+K,0`"UW$`*XGQ`"O@,0`!=7$`*XG!!,``L`,-@'&$#< -M#0``U`T0`O>M$`!2%A`"N(40`:`!$`#0@!`#P,`0`:*!$`&J@!``E1<0`)M= -M$`*V/!``T$\0`-`:$`&B@1`!JH`0`)47$`";71`"MC40`-!/$`#0&A`!HH$0 -M`:J`$`"5%Q``FUT0`K8N$`#03Q``T!H0`:*!$`&J@!``E1<0`)M=$`*V)Q`` -MT$\0`-`:$`&B@1`!JH`0`)47$`";71`"MB`0`-!/$`#0&A`!HH$0`:J`$`"5 -M%Q``FUT0`K89$`#03Q``T!H0`:*!$`&J@!``E1<0`)M=$`*V$A``T$\0`-`: -M$`&B@1`!JH`0`)47$`";71`"M@L0`-!/$`#0&A`!HH$0`:J`$`"5%Q``FUT0 -M`K8$$`!D"!`!9&80`KX$$`%D9A``9`<0`K9%$`!PT`8UQT00`:I3$`!D`!!% -M9&`!`.@'$$:X`P``1$00`KX-$-CIUQ`"N`L0`$2$$`*^"1"6H$`%$(P@$`!! -MC!`!B&$0`'$0!C7'1!``1A(0`K8R$`*6`Q`!1&<%4W_V$`&H`P8,DB`&$(@@ -M$`#1^A!$B)4`_,GS!BZX#A``J)<0`KHH$$1%%`(8U<80`K@*$`!4,Q``!*00 -ME41G!5%281``0880`WD]$`%08!`#?SL0`-44$`!!AA`"N`401``+``!%-!"4 -M``L%441G$`#5ZA``U$80FK8S!B*^,A``27`0`KX$$`!)@!``4?H0`$F>$`!$ -M-!`"OA40`$E`$`*^$Q``25`0`KX1$`!)8!`"O@\0`$D@$`*^#1``23`0`KX' -M$`!),!`"OB,0`$D0$`!$-!`"O@80`$D0$$0`"P``1300E``+!5%$9Q!$``L` -M'$?P!C1&$@8T<.`&-``+$`*^`1`"E@(0`WW[!@R2(!`"O`(&(KX*$`!@,!`` -M(",&+&`W$`*V!A!$``L"&-7&$`*X"1"4190%441G$`#5ZA"8%$0%$(P@$``` -M"P51U&`0`W[[$$0`"P``1300E``+!5%$9Q``U180`O?U!B+_]!!(``L`'$?P -M``1W``8T1A(&-'#@!C0`"Q`"O@$0`I8"$`-]^Q!$``L``'?@$`,^`1"4``L% -M$(P@$$@`"P`$=P```$4P!5%$9Q"(``L`,``+$`*\`@8@``L0`W[=!120(!`` -M``L02:"``Q30P`"$Y7`%3*43$$:V!P``Y5,02.47'_SE+P,4Y$$0`2#@$`*^ -M!0`<80,0`W?R$`!AZA``8($0`!,!$`!0"1`!JH`0```+$`#J$1`!ZH`0`W_I -M$`!V(`"W!`$0`9+!$`&:P!`!Y,,0D*40!4!00!`!+*40@*"P`#ZX`@`0``L0 -M@%_C$$7:`0``=]`0`QX!$$1V$`6H_!`0`P(!$XVF!`FH72`0D'=0"8<^`0FU -MY@`)M(H@";2J(`FTDB`%$)`@";2:(!`!A($0`>H?$`#,!Q`"MA`0`,@'$`*V -M#A`!G!L)C*M0$`"<=Q`"NGH0`)QP$`!=A!`!W(`0`(AW$`"(?A``C%(0`<P< -M$`#-P!`"OAT0@``+`+:^8@F,JU`0`(Q1$`"L<!``;800`>R`$`#-P!`"OA03 -MC:8`":A<P`F$=U`0`SX!$`&8'`FUY@`)M(@@";7^'!``R`<`MO?W$`"(UQ`` -MB-X0`)A2$$78'```=]`0`QX!$`!V$!`#`@$3C;X<$$6J'P`@R`<0`KH.$``M -M<!!$;R```&WS$`!L!Q`"M@D0`"]B$`!L`!``K%<)J"Y>$`'L'0F<A#`)A'=0 -M$$<^%A``[4`0`*Q7":@N7A`![!T)G(0P"81W4!`#/@\0`"9X$`!GZA``9A$0 -M`#$P";7'Q!``)3<0`KH2$$@E,@!@Q`(`8.`"$`*^#!`#?Y,0@``+`+:^(PF] -M_AP)N*0`$`&L'1``H#`0`.`\$$2%<0*`Q`<0`OWK$``Q(`FUQ\0`M`]Q$`*Z -M"A"03T(0`$P1$`*V!A``3$<0`K@%$`!P,`503``%0&`0!5!,$A"`B7(01OG` -M$`&8'!``=A`0`)C3$`-YKA!,``L`!'8P`"3-\0`<3?D0D#!@!5``"Q`#)`00 -M1``+``1V,!`#)`$0`'80$(,"`1.-I@@0`:H!":A<0`FDZ@001``+`"C\$`F$ -M=U`0`O_/$`&J&1"```L`M.H1$`'J&1`"_^\0A``+`#P`"P8K.`$`4&`0`*AW -M(!"3/@$%%)0@$(100`"U@*`0```+$`!!C!`!P*``4&`0`!6$H1"0D!<&&)`> -M$`!W$`5,<1`&)8<D!5R:(!``P4(01'94`H#$!Q`"O`80`%@F$`+5YQ`#.`$0 -M`'<@$)-_]!!$4$`"(,0`$`"0%P88D!X0`O_W$$0`"P``=U`0D``+!5R:(!`` -M``L0`%@F$`,X`044E"`0```+$`&`H!````L0`$&&$`*X`P5,``L0`O_U!5R: -M(!"$``L`,%@F$`+_S`5,P4`01``+``!WX!"7/@$%$)0@$`!'$`511J<01<"@ -M``!W4!"3?_<01``+``1W,!`#``$3":90"2A80!``=T`)!SX!"32:(!``D#`` -M,-H'$`*V'@`YVH`0`80C$`!>&A``7N,015Z%`OC4`!``%O$0`*00$`*V"1`` -M#/<0`KH'$`&@H!````L0`:3#$`'0PQ`!Y(,0`KX$$``,\!`!P(,0`("0$`$: -MY1``X``01*$W`!Q;[A``'M(0`%_Z$``P\!`!T;\0`,07$$0`"P`$=B`0`WW6 -M`!1V,!`#?_L&"*H@$$0`"P+XX4`0`)%P$`-W_!``[!80`K8%$`&:R08P``L0 -M`-H1$`':R1!%FL(`'-&#$`#1AQ`"N`,0`-H1$`':PA!%FL8`(.P&$`*V`Q`` -MVA$0`=K&$`#L)A!&N`X`#.V&$`-WYQ`!FL`0`.UV$`*V!A`!FL$0```+$`#: -M$1`!VL$0`W_?$`#:$1`!VL`0`W_<$`&:PP8P[$80`K8$$`#:$1`!VL,0`W_6 -M$$6:Q``,[880`K8$$`#:$1`!VL00`W_0$$6:Q0`@[`80`WG-$`#:$1`!VL40 -M`W_*$$0`"P``R7`0`SX!$`$44!`!%E@0`%0L$`!6+!`!5%`0`598$`$40!`! -M%D@0`%0L$`!6+!`!5$`0159(`P#1L!`!D9`0`,DA$`"05Q`#??``,W_L``1V -M\!`#/@$/A:8$$`,^`0^%I@@01``+``1VX!`#/@$/B>8$$`,^`1`!H@$/B*H@ -M$$1@&@+LT0`0`!,!$`!0"1`!D9`0`>H"$$?`@!`!D@00```+$`'2`A!&_^H0 -M`>0,$`'H#1`!Z@<01O_F$`'J!1``3``0`0X!$`#(`!``S$H0`,PJ$$;WWQ`" -M/J$02'XP``!VP`,`U;`0`<FP`"L^`1!&_]@0`>H%$`"=,!!,R```0,V``!S1 -MP`,$U8`0`<P;$`'1L!`!7@$0`%X'$$;WS0!`S3`0`-@`$``:X!``C-(0`-@0 -M$`':`Q!$``L`!'<P$(``"Q`#/@$3":84"2AG0`D$=T`0`SX!$`&:`PD]YA00 -M`'$0"37'1!``7A(0`%@1$`':`P`P&-<0`K8($`!>!Q`"^>X02<P;`"#-P@,$ -MU8`0`<VP$`*^#!`!S!L02)!P`"#1P@,$U8`0`=&P$`#,<A``6AH0`=H#$`!> -M!Q`"^=\01O^D$``,T!``#,(0`$Q*$`!W4!``#F`0`$TG$`!/+A``DI40`#!P -M$`'341``#'(0`WGY$$;_EP,4R,`01>H%``3-0!`"/E802``+``3,P`+XR4`0 -M`CY2$`$@!!``3M`0`&!7$$;YBP,4R,`0`-(`$``P<!`!TU$01$ZP`OC)0!`` -M,'`0`=-1$$;_@@,`R9`016=0`P#((!!%[5`#',D@$`'I41`!95`01O]Z$``` -M"Q"$``L`$``+$$;_=@,<R$`0`>M0$$;_<P!LU'`011X`!@#14!``6!`0`!\W -M$$;W;1`!9@`02&87`!11#@!PU9X&(%A.!@QTX`8RO@$01#:``##X0!``=/`0 -M`KX!$``VD!``N+`0`#[`$`!T@!!&_UT##,A`$`!D`!``Y#H0`(DQ$`'L01`! -M:D00`6A%$$;_50,<R+`0`6=0$$;_4@,<R*`026=0`QS)```TV;`01=E0`"#, -M`!!%Z@4"P,@`$$8^(!`!H@$0`-P`$$@?(``TV;`#',D`$`"8\A`!V5`01O]! -M`P#)H!`!9D`01O\^$`'D`1!$``L`!'<P$(,^`0D-IA0`*.5`$`"D=PDH)GX0 -M`(TR$`!F,1``9^H0`#$P"26'1`D$=T`0`SX!"3WF%``PS!<0`:0!$`+][Q`# -MP.`0`>0!$$0`"P`$=S`0@SX!"0VF%``HY4`0`*1W"2@F?@D$C3(0`'=`"3WF -M%!`#/@$).*8`$`#,%Q``,3`)-<=$`#&D`1`"_?`0`\#@$$;_*1!&_RP01O\O -M$$;_/!!&_WP01O^'$$;_CQ!&_P\01O\.$$;_#1!&_PP01O^O$$;_"A!&_[40 -M1O^W$$;_!Q!&_P801O\%$$;_DA!&_P,01O^-$$;_P1!&_X<0`'3@$$:^`0`4 -M=P`0`'3P$$:^`0`0=U`0`#60$`*^`1"`=A`0`P(!$$0`"P,@T8`3C::`":A8 -M0`FDVA`)A'=0$`,^`0"T``L01``+``1V\!`#/@$0A``+`#@`"Q!$``L#(-'` -M#X6'A!`#/@$/A8>`$$0`"P`(=F`0`SX!$`!TX!!*O@$`4/D0``AV@!``=/`0 -M2KX!`'#X8``(=D`0`#60$$:^`0+\T<`0`9J`$(@`"P`HVA$0A=J``#@`"Q!$ -M``L`"'9@$`-_SQ````L0```+````````!@(````````````````````````` +M_NWP#1""`@````])``````````\````!```'1`````$```[-`````0``#MT` +M```!```.]0````$```]"`````0``#T4````/````````!S,0`'X0$`#\\!`` +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`<H3$`*^`P`PZ@`0`>H+$$6*"0`$=D`0`,H'$`,V +M!A!$``L`!'<P$`,``1``=T``*KX)$$0`"P`$=S`0`P`!"2AH0!,)M@@0`'=` +M"0<^`0DTBB`)*&C`"0R*4`D'/@$0`9H+$`&B!PDU[@0)->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<Q``4=H0`5`)$`!N)A!&N#$``-4A$`'4!Q`! +MXA<0`>@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$`%<!!!%:@<`!'<P +M$`,``1!%$`D``&F`"2@H@1,)K@@)):84"26V'`DEO@`));X$"26^"`DEO@P0 +M`%`'$`*V!1``4?H0`%`)$``P@`DDV@`)/>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$PD<I3`0`.0\"3BH``DEIN`) +M):;D$`!@!Q`"M@40190%$"#0`!``:!()))*0"26^'!``:#(0`00-!4PQ0`DE +MIV0)/>X("0<^)@D<S"(0`,P\"3BH`!``8`<0`K@"$`+_]@DEIV0)):=D$`&4 +M!1!$:#(0(-``"222D!`"_^\``-2"$$1-A``$4^`0`O]7`!Q%@!!&_U(``-0` +M$$1$`!`"_SP0`9H'$`$$#1``V4$0`)S7$`+Z?Q!%V`X`!'<P$`,``0DH:4`3 +M":X($)1Q$`DEAV0)!'=`"3WN"`5//@$0@$46`#+VHQ``:#`0`"@C$`!H-Q`" +MME$012@'`!A$\Q``!400`9`%$`%$!Q`!*`P0`00&$`!H!Q`"M@,0`$4D$`*^ +M`A``12P0`40&$$11XP/HQ$`0`%'J$``&@1``1`D`))(@$`&8(A`!D`P0`!;` +M`""2D!`!E`<0`5H($`$H"1``B+$0``M!$`!("1`!R`T01JXM``#0!Q`"N`T0 +M`<@,"2AI(!,)K@`));80"26F&`DEKA`)):8$"26F"`DEKA0)):X8"26N'`D' +M/A40`(B2$`'(#`DH:(`3":X`"26V$`DEIA@)!SX!$$6:"P``::`)*"E`"0S: +M80D<["`)):88"26N$`DEI@0)):8("26N%`DEKA@)):X<"0<^`1``Z@`0`>P, +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:#``<V?,0 +M`(C2$`",TA``B'<0`(A^$`",4A`!S!P0`-5&$`*X/1``5480`K8F$$RD\`(` +MX``!_.6#$"#8`!`!VB,0`.7J$`"A,1`!F,`0`-QS$`#<0A``F/H0`%B&$`*W +MU1``I+`0`&1C$`!D*A``91<0`!LN$`#8@Q``V?H0`=@:$`",41``U280`K@2 +M"8RK4!``[4`0`*Q7":@N7@F%[!T01(S1!`#4!A`"N`,0`<R`$`,^'A``S$(0 +M`<R`$`,^+!``V``0`O_N$(``"P"VOZ<0`1P,$```"Q``7"80`K8"$`!<(1!$ +M``L`!%Q!":@<X`F,ZH$)A-46$$:V!`0`U`80`SCK$`,^MP0`U`80`SA5$`,^ +M*`F,JU`0`(Q1$`',@!``S<`0`K]:$`&:'0FUQR0)M<<D";7')`FXI``0`:P= +M$$2<=P`8S,`0`KN5";W^'!``9#(0`.S"$("$T0"TH#`0`(S1$`#(PA`"OV,0 +M`9H=";7')`FUQR0)M<<D";BD``FUK!T01)QW`!C,P!`"NX0)O?X<$`!D0A`` +M[1(0@(31`+2@,!``C-$0`,D2$`*_4A`!(`P0`9H=";22(`FUYB@)M<<D";7' +M*!`!U#T0`&`'$`*V%!``8"80`K8/$`!@(A``8>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<<H$`'4 +M/1``8`<0`K86$`!@)A`"MA$0`&`B$`!AZA``8`<0`K8#$``Q``FT``L)M?X$ +M";7^"`FU_@P)M?X0$`&@$Q`!I!00`:@5$`&L&!`!FAT0`KX)$`!AZA``,0`) +MM``+";2B(`FTJB`)M)(@$`&:'1``K+`0D(31$`#2$!`"_\\?_,SA$`",T1`` +MG'<0`KLF$`'M,1``TA80`K@G!1"0(`FLJB`0`.(`$`$F#!`!S(`02*L1``#K +M@0`8S.`01(S1``3(`@F-ZA\0@KC3$`*^OP``S8(0`<TQ$`",T1``S.$0`)QW +M$`*[$!``TA80`K@.!1"0(`FLJB`0`.(`$`$F#!`!S(`02*L1``#K`0`8S.`0 +M1(S1``#)@@F-ZA\0@KB^$`*^JA`!X3$0`>4Q$`'I,1`![3$%$)`@":RJ(!`` +MX@`0`28,$`',@!!(JQ$``.O!`!C,X!!$C-$`!,A""8WJ'Q""N*T0`KZ9";6: +M'0FTT@`)M<<D";7'*`FTHB`)M*H@$)'@/1`!Y#X0`2`,$`'H/Q``8`<0`K89 +M$`!@)A`"MA`0`&`B$`!AZA``8`<0`K8#$``Q``FT``L0`(31";7^!`FU_@@0 +M`:P2$$6@$Q54[*<0`:04$`&H%1`"O@P0`&'J$`!@$A``8`<0`K8#$``Q``FT +M``L)M*H@$$2$T154[*<)M*(@";2J(!``8#T01KA+`!SEAQ``8@T01K8T$!SI +M-Q!&MD80).EW$$:V1!````L01KXN$`#,0@FUFAT)M-(0";7')`FUQR@)M*(@ +M";2J(!"1X#T0`>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`<R`$$BK$0``Z^$`&,S@$$2,T0`$R&() +MC>H?$(*X.1`"OB4``,WB$`'-,1``C-$0`,SA$`"<=Q`"NG80`-(6$`*X#@40 +MD"`)K*H@$`#B`!`!)@P0`<R`$$BK$0``ZV$`&,S@$$2,T0``R>()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<P`F$=U`0`SX!$`&8'`FUY@`) +MM(@@";7^'!``R`<`MO?W$`"(UQ``B-X0`)A2$$78'```=]`0`QX!$`!V$!`# +M`@$3C;X<$`#M0!``K%<)J"Y>$`'L'0F<A#`)A'=0$`,^#Q``)G@0`&?J$`!F +M$1``,3`)M<?$$``E-Q`"NA(02"4R`&#$`@!@X`(0`KX,$`-^)Q"```L`MKXC +M";W^'`FXI``0`:P=$`"@,!``X#P01(5Q`P#$!Q`"_>L0`#$@";7'Q`"T#W$0 +M`KH*$)!/0A``3!$0`K8&$`!,1Q`"N`40`'`P!5!,``5`8!`%4$P2$(")<A!& +M^=`0`9@<$`!V$!``F-,0`WF^$$P`"P`$=C``),WQ`!Q-^1"0,&`%4``+$`,D +M!!!$``L`!'8P$`,D`1``=A`0@P(!$XVF"!`!J@$)J%Q`":3J!!!$``L`*/P0 +M"81W4!`"_\\0`:H5$(``"P"TZA$0`>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<D!5R:(!"$P4(01'94`P#$!Q`"O`8`$%@F`+;5[A`#.`$`J'<@$)-_ +M]!!$4$`"H,0`$`"0%P88D!X0`O_W!4S!0!!$``L``'?@$)<^`040E"`0`$<0 +M!5%&IQ!%P*```'=0$)-_]Q!$``L`!'<P$`,``1,)IE`)*%A`$`!W0`D'/@$) +M-)H@$`"0,``PV@<0`K8>`#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@`<T8,0`-&'$`*X`Q``VA$0`=K"$$6:Q@`@ +M[`80`K8#$`#:$1`!VL80`.PF$$:X#@`,[880`W?G$`&:P!``[780`K8&$`&: +MP1````L0`-H1$`':P1`#?]\0`-H1$`':P!`#?]P0`9K#!C#L1A`"M@00`-H1 +M$`':PQ`#?]8019K$``SMAA`"M@00`-H1$`':Q!`#?]`019K%`"#L!A`#><T0 +M`-H1$`':Q1`#?\H01``+``#)<!`#/@$0`110$`$66!``5"P0`%8L$`%44!`! +M5E@0`11`$`$62!``5"P0`%8L$`%40!!%5D@#V-"P$`&1D!``R2$0`)!7$`-] +M\``S?^P`!';P$`,^`0^%I@00`SX!#X6F"!!$``L`!';@$`,^`0^)Y@00`SX! +M$`&B`0^(JB`01&`:`[S1`!``$P$0`%`)$`&1D!`!Z@(01\"`$`&2!!````L0 +M`=("$$;_ZA`!Y`P0`>@-$`'J!Q!&_^80`>H%$`!,`!`!#@$0`,@`$`#,2A`` +MS"H01O??$`(^R1!&_]T0`>H%$`"=,!!,R```',TP`!S1,`/@U4`0`<P;$`'1 +ML!`!7@$0`%X'$$;WT@`<S.`0`-@`$``:X!``C-(0`-@0$`':`Q!$``L`!'<P +M$(``"Q`#/@$3":84"2AG0`D$=T`0`SX!$`&:`PD]YA00`'$0"37'1!``7A(0 +M`%@1$`':`P`P&-<0`K8($`!>!Q`"^>X02<P;``#,`@/@U4`0`<VP$`*^#!`! +MS!L02)!P``#0`@/@U4`0`=&P$`#,<A``6AH0`=H#$`!>!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`-(`$``P<!`!TU$01$ZP`\S)0!``,'`0`=-1$$;_AP/8 +MR)`016=0`]3)(!!%[5`#^,E@$`'I41`!95`01O]_`^#(0!``5Q`0`!<S$`!7 +MRA!%5D`#R,@`$`!6\!``%S,0``JQ$``*L1!%E$`#^,A`$`'40!!&_W$#^,@` +M$`'K4!!$;/,#^,D`$`'M4!!&_VL"`,@`$`"),1`![$`01O]G`V#(`!`"OAH# +MB,@`$`*^&`"LU,`011X`!@#14!``6!`0`!\W$$;W71`!9@`02&87`!11#@"P +MU&X&(%A.!@QTX`8RO@$01#:``$CXH!``=/`0`KX!$``VD!``N+`0`#[`$`!T +M@!!&_TT"`,@`$`'J!1``%R`0`%0`$`#4*A``B+$0``\P$`!,`!``3@<0`K@" +M$`!,$!``S"H01CX_$$;_/P/HR$`0`&0`$`#D.A``B3$0`>Q!$`%J1!`!:$40 +M1O\W`_C(<!``9A<0`&;^$`%G4!!&_S(#^,CP$`%G4!!&_R\#^,C@$$EG4`/X +MR4``4-@0$$794``@S``01>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`!'<P$(,^`0D-IA0`*.5`$`"D=PDH)GX0`(TR$`!F,1``9^H0 +M`#$P"26'1`D$=T`0`SX!"3WF%``PS!<0`:0!$`+][Q`#P.`0`>0!$$0`"P`$ +M=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```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` @@ -168,6 +248,13 @@ M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` +M1````````!>?&H0``````````!>?&H3_____```````````````````````? +M`>(`$0`````````_`=L`,P`````````O`=@`(@`$```````````````````` +M`````````````````````````````````````````````````"U"!6P5`2U$ +M`DHP``%!`U@"`"U#`&TD`"U`!9`B`"U(``"````/``"``"U%!@LO``````"` +M`#6"!;U\`#6&`SX7!@````"```````"````/``"``#6&!?1,`P`/`````0`` +M%``>8```'KP5`````````!4``````!\$````````']`````````?W``````` +M`!^,```````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` @@ -191,6 +278,13 @@ M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` +M`````````````````````````````````````````!0(````````%!`````` +M```4&````````!0@````````%"@````````4,````````!0X````````%$`` +M```````42````````!10````````%%@````````48````````!1H```````` +M%'`````````4>````````!2`````````%(@````````4D````````!28```` +M````%*`````````4J````````!2P````````%+@````````4P````````!3( +M````````%-`````````4V````````!3@````````%.@````````4\``````` +M`!3X```````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` @@ -206,21 +300,7 @@ M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` -M````````````````````````````````````````````````!````````!>? -M&H0``````````!>?&H3_____```````````````````````?`7H`$0`````` -M```_`7,`,P`````````O`7``(@`$```````````````````````````````` -M`````````````````````````````````````"U"`V<5`2U$`80P``%!`L(" -M`"U#`&TD`"U``Z,B`"U(``"``"U'!1U&`2U%!!XO``````"``#6"`]!\`#6& -M`J@7!@````"```````"````/``"``#6&!`=,`P`/`````0``$``7P```&`P1 -M`````````!$``````!@L````````&.P````````8^````````!BL```````` M```````````````````````````````````````````````````````````` -M````````````````````````````````````````````$`@````````0$``` -M`````!`8````````$"`````````0*````````!`P````````$#@````````0 -M0````````!!(````````$%`````````06````````!!@````````$&@````` -M```0<````````!!X````````$(`````````0B````````!"0````````$)@` -M```````0H````````!"H````````$+`````````0N````````!#````````` -M$,@````````0T````````!#8````````$.`````````0Z````````!#P```` -M````$/@````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` @@ -252,144 +332,191 @@ M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` +M```````````````````````````````````````5````%4```!6````5P``` +M%@```!9````6@```%L```!<````70```%X```!?````8`````````!A````` +M````&(`````````8P````````!D`````````&4`````````9@````````!G` +M``````8<!B`&)`8M!FX&;@:#!HL&F0:?!KT&RP;3!M@&VP;L!N\&HP:G!J4& +M"0;Q```'B`````X```````````````````````````````````````````*P +M`J<"L0```I4"E0*=```"L@*H`K(`````!Y@````6```````````````````` +M`&```7`````````````````````````````````````````````````````` +M``````````````````````````````7N````````!Z\```!+``````````!@ +M``'P`!@``&```:`````````````````````````````````````````````` +M``````````"JJ@,``````````0````````````````````#S```````````` +M````"````````````````````````````````````````````&`````````` +M8`````````!@`````````&``````````8`````````!@`````````&`````` +M````8``````````("`0`#`@$```````````````````````````````````` +M``````````````````````````````````"!`````K````$```````(````` +M``*!!>X8````````````````@@(````'^P````$`@@(````'_0````(`$2(S +M(C-$5?[M\`T!`@(!```/20`````````/`````0``!T0````!```.S0````$` +M``[=`````0``#O4````!```/0@````$```]%````#P````````<S$`!^$!`` +M_/`0`'2@$$Z^`06H_(```/G0``1V<!``=``0`KX!$`*($!`"@@(0`O_^`%B` +M``!8@@``.L7[$``$`!``!!(0`$6,$`!$AQ`"O`(0`O_Y$`+%]!`"Q?,0`L7R +M!C+_\0ELBB`/D,`0#ZA`$!`"O@`01``+`=3```!-AP@`+8<$`#6'!``9AP0` +M(8<$`%&'!`!=AP001'YP`=C``!`!BQ$0`9,1$`&;$04$BE`%*!"`!3@2D`5$ +M%*`%0!:P!6P8P`5H&M`0`'X2$`+]]1!(``L,`,``!`#$``D,@A`)*$A`$`*^ +M`0D$=T`0`SX!"8R"$`FH2$`0`KX!"81W4!`#/@$01'3P`>3@`!`"O@$0`;W1 +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<H+``!WT``QV@P0ESX6"2AH@`D-K@`))<H($`&0#!`` +MY``))*,0"021$1`!T`P0`-%`$`'0#A`!BA,0`S]6$$0`"P``=]`0ESX!!12$ +M(!`!F@<0`9(A$`&*(!``!+`0@K]'!12$(!`!R@@0`9(A$`&*(!"!5`00`58- +M$`%(!1``2``0`=`%$`&:8A`!DF$0`=H/$`&:8!`!T@X0`:QF$`':#1!$E)`0 +M(.P'$`*V81!$:@``P.P'$`!K'A`!*`T0`6H'$`!I1A`"N$$0`:0($`#$@!`# +MP.`0`:HA$`&B(!``E5<0`)L=$`*V5!``Q$\0`,0:$`&J(1`!HB`0`)57$`"; +M'1`"MDT0`,1/$`#$&A`!JB$0`:(@$`"55Q``FQT0`K9&$`#$3Q``Q!H0`:HA +M$`&B(!``E5<0`)L=$`*V/Q``Q$\0`,0:$`&J(1`!HB`0`)57$`";'1`"MC@0 +M`,1/$`#$&A`!JB$0`:(@$`"55Q``FQT0`K8Q$`#$3Q``Q!H0`:HA$`&B(!`` +ME5<0`)L=$`*V*A``Q$\0`,0:$`&J(1`!HB`0`)57$`";'1`"MB,0`,1/$`#$ +M&A`!JB$0`:(@$`"55Q``FQT0`K8<$$0`"P`<:?`0`6@$$`!30!`!4@80`1(- +M$```"Q``4R,0`5(,$`#L`!`![`<0`%``$`%0"1`"OMT0`%``$`%0"1``;B80 +M`K@#$`%L!!`"__(0`1(&$```"Q``4H00`5(&$`+_[1`!K&@0`O^?$`!30!`! +M4@80`&Y&$`+Y\!`!FV,01$4@$"#8!Q!&N,7__-7`$`&;81``1``0`1``$`!N +MAA`"M@40`%`6$`*X`Q``12`0`-1!$`%$#!`!VA\0`1(&$$0`"P``4HP0`5(& +M$$1$`!`<V3<01K:P$"39=Q!&MJX`P-@'$$:ZJ``(4F`01!!P``11\Q``$H(0 +M`%``$`'0"1`!VA\0`40;$`!1\!``$7,0`%':$`%0"1``;B801K@Q``#5(1`! +MU`<0`>(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<!`!Z!$0`)30$`%<!!`!TAD0`9(.$`&:#Q``D+`0 +M`)30$`'2'!`!W!H0`&LP$$5J!P``=H`0`P`!$$40"0``:>`)*"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/<Y:`0`(51$`'$#@DH*U`)#:X($`!-AA"6N!,)'*4P$`#D/`DXJ``) +M):;@"26FY!``8`<0`K8%$$64!1`@T``0`&@2"222D`DEOAP0`&@R$`$$#05, +M,4`)):=D"3WN"`D'/B8)',PB$`#,/`DXJ``0`&`'$`*X`A`"__8)):=D"26G +M9!`!E`401&@R$"#0``DDDI`0`O_O``#4@A!$380`!%/@$`+_5P`<18`01O]2 +M``#4`!!$1``0`O\\$`&:!Q`!!`T0`-E!$`"<UQ`"^G\01=@.``!V@!`#``$) +M*&E`$PFN"!"4<1`))8=D"01W0`D][@@%3SX!$(!%%@`R]J,0`&@P$``H(Q`` +M:#<0`K91$$4H!P`81/,0``5$$`&0!1`!1`<0`2@,$`$$!A``:`<0`K8#$`!% +M)!`"O@(0`$4L$`%$!A!$4>,#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<Q``8D(0`"<:$`!FAA`"MD(0`61@$$74'@$`Z`<01K@#``!$1!`" +MO@T0V.G7$`*X"Q``1(00`KX)$):B0@40C"`0`$&,$`&(81``<1`&-<=$$`!& +M$A`"MC00`HX#$`%$9P53?_80`:@#!@R2(`80B"`0`-'Z$$2(E0#\R?,&+K@0 +M$`"HEQ`"NBH01$44`AC5QA`"N`P0`:P>$`!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!(Y1<?_.4O`_#D01`!(.`0`KX%`!QA`Q`#=_(0 +M`&'J$`!@@1``$P$0`%`)$`&J@!````L0`.H1$`'J@!`#?^D0`':@`+<$`1`! +MDL$0`9K`$`'DPQ"0I1`%0%!`$`$LI1"`H+``/K@"`!``"Q"`7^,01=H!``1V +MP!`#(`$01':0!:C\$!`#`@$3C:8$":A=(!"0=U`)ASX!";7F``FTBB`)M*H@ +M";22(`40D"`)M)H@$`&$@1``S`<0`K8X$`#(!Q`"MC80`%H6$`*YN!!%6@P` +M'-GS$`"(TA``C-(0`(AW$`"(?A``C%(0`<P<$`#51A`"N#T0`%5&$`*V)A!, +MI/`"`.```?SE@Q`@V``0`=HC$`#EZA``H3$0`9C`$`#<<Q``W$(0`)CZ$`!8 +MAA`"M]40`*2P$`!D8Q``9"H0`&47$``;+A``V(,0`-GZ$`'8&A``C%$0`-4F +M$`*X$@F,JU`0`.U`$`"L5PFH+EX)A>P=$$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<<D";7')`FUQR0)N*0` +M$`&L'1!$G'<`&,S`$`*[E0F]_AP0`&0R$`#LPA"`A-$`M*`P$`",T1``R,(0 +M`K]C$`&:'0FUQR0)M<<D";7')`FXI``)M:P=$$2<=P`8S,`0`KN$";W^'!`` +M9$(0`.T2$("$T0"TH#`0`(S1$`#)$A`"OU(0`2`,$`&:'0FTDB`)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``<Z8<0`&8-$$:V+1`< +M[3<01K8_$"3M=Q!&MCT0```+$$:^)Q``S$(0`2`,";22(`FUYB@)M<<D";7' +M*!`!U#T0`&`'$`*V%A``8"80`K81$`!@(A``8>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`<R`$$BK +M$0``ZX$`&,S@$$2,T0`$R`()C>H?$(*XTQ`"OK\``,V"$`'-,1``C-$0`,SA +M$`"<=Q`"NQ`0`-(6$`*X#@40D"`)K*H@$`#B`!`!)@P0`<R`$$BK$0``ZP$` +M&,S@$$2,T0``R8()C>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`<Y8<0`&(-$$:V +M-!`<Z3<01K9&$"3I=Q!&MD00```+$$:^+A``S$()M9H=";32$`FUQR0)M<<H +M";2B(`FTJB`0D>`]$`'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')`5<FB`0A,%"$$1VQ`,`Q`<0`KP&`!!8)@"VS>X0`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-,``<T3`#X-5`$`', +M&Q`!T;`0`5X!$`!>!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`<P;$$B0<```T`(#X-5`$`'1L!``S'(0`%H:$`':`Q``7@<0`OG?$$;_ +MJ1``#-`0``S"$`!,2A``=U`0``Y@$`!-)Q``3RX0`)*5$``P<!`!TU$0``QR +M$`-Y^1!&_YP#\,C`$$7J!0`$S4`0`CZ#$$@`"P`$S,`#S,E`$`(^?Q`!(`00 +M`$[0$`!@5Q!&^9`#\,C`$`#2`!``,'`0`=-1$$1.L`/,R4`0`#!P$`'341!& +M_X<#V,B0$$5G4`/4R2`01>U0`_C)8!`!Z5$0`650$$;_?P/@R$`0`%<0$``7 +M,Q``5\H0159``\C(`!``5O`0`!<S$``*L1``"K$0191``_C(0!`!U$`01O]Q +M`_C(`!`!ZU`01&SS`_C)`!`![5`01O]K`@#(`!``B3$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````````````````````````````$0```!%````1@```$<```!(````20``` -M$H```!+````3````$T```!.````3P```%``````````40````````!2````` -M````%,`````````5`````````!5`````````%8`````````5P``````$+P0S -M!#<$102&!(8$FP0<!!P$'`0<!,`$'`3(!,L$'`0<!!P$J@0<!*<$W`2C```` M```````````````````````````````````````````````````````````` -M``!@``%P```````````````````````````````````````````````````` -M``````````7N````````!@,````^``````````!@``'P`!@``&```:`````` -M````````````````````````````_```````````"``````````````````` -M`````````````````````````&``````````8`````````!@`````````&`` -M````````8`````````!@`````````&``````````8``````````("`0`#`@$ M```````````````````````````````````````````````````````````` -M`````````````````0```````@````(8`;L%[A@```````````````"``@$` -M``9"`````0"``@$```9$````!0`1(C,B,T15R`#!_!<`````````_NWP#0$` -M`@$```NL``````````L````!```%7@````$```MB`````0``"Z(````!```+ -MI0````\````````%41``?A`0`/SP$`!TH!!.O@$%J/R```#YT``$=G`0`'0` -M$`*^`1"$``L0`H@/$`+!_A`"Q?T0`H8#$`*"`A`"__H`6(``$(@`"Q`"P?<0 -MA$&'$`*V`A`"__00```+`"@`"P`2__$);(H@#Y#`$`^H0!`0`KX`$$0`"P'4 -MP```38<(`"V'!``UAP0`&8<$`"&'!`!1AP0`78<$$$1^<`'8P``0`8L1$`&3 -M$1`!FQ$%!(I0!2@0@`4X$I`%1!2@!4`6L`5L&,`%:!K0$`!^$A`"_?402``+ -M#`#```0`Q``)#((0"2A(0!`"O@$)!'=`$`,^`0F,@A`)J$A`$`*^`0F$=U`0 -M`SX!$$1T\`'DX``0`KX!$`&]T1`!N=$0`3?1$`$_T1``=!(0`OW[$``UD!`" -MO@$01'Z`!X3\`!!&O@$!\.``$`&#T1`!B]$0`9K!$$63T@`(_"$0`'X2$`+Y -M^A!(Z@`"`.````AQ@!`!Z\\03``+!:C\@```?@``$'8`$`-_H1`!RAT0`KX# -M`##J`!`!Z@D018H'``!V8!``R@<0`S8&$$0`"P``=H`0`P`!$`!W0``JO@D0 -M1``+``!V@!`#``$)*&A`$PF^$!``=T`)!SX!"32*(`DH:,`)#(I0"0<^`1`! -MF@D0`:(%"37F'`DUYA8)->X`$`#:!Q`"N`80`9H($$7*"0``=]``,=H*$)<^ -M%@DH:(`)#:88"27*!A`!D`@0`.0`"22C$`D$D1$0`=`($`#10!`!T`H0`8H= -M$`,^E!!$``L``'?0$)<^`044A"`0`9H%$`&2(1`!BB`0``2P$(*^A044A"`0 -M`<H&$`&2(1`!BB`0@50`$`%6"1`!2`$0`$@`$`'0`Q`!DF`0`9IA$`'2"Q`! -MDF(0`=H,$`&L9A!%T@T0(.P'$`*V9Q!$:@``P.P'$`!K'A`!*`D0`6H#$`!I -M1A`"N$L0`)CP$$2<D`,@Q0`0`:@C$`&B(!`!$@(0`)57$`";'1`"ME\0`%$0 -M$`&D!A``Q(`0`\#@$`&J(1`!HB`0`)57$`";'1`"ME`0`,1/$`#$&A`!JB$0 -M`:(@$`"55Q``FQT0`K9)$`#$3Q``Q!H0`:HA$`&B(!``E5<0`)L=$`*V0A`` -MQ$\0`,0:$`&J(1`!HB`0`)57$`";'1`"MCL0`,1/$`#$&A`!JB$0`:(@$`"5 -M5Q``FQT0`K8T$`#$3Q``Q!H0`:HA$`&B(!``E5<0`)L=$`*V+1``Q$\0`,0: -M$`&J(1`!HB`0`)57$`";'1`"MB80`,1/$`#$&A`!JB$0`:(@$`"55Q``FQT0 -M`K8?$`#$3Q``Q!H0`:HA$`&B(!``E5<0`)L=$`*V&!!$``L`'&GP$`%H`!`! -M$@D0```+$`!3(Q`!4@@0`%.`$`%2`A`"OA80`%``$`%0!1``;B80`K@#$`%L -M`!`"__00`1("$```"Q``4H00`5("$`+_[Q`!K&@0`O^9$``19Q`"^>@0`&X6 -M$`+WYA``;B00`6XG$`!2`!`!4@(0`9H%$`$$"1``V4$0`)S7$`+[01!%V`H` -M`':`$`,``0DH:4`3":X`$)1Q$`DEAV0)!'=`"3WN``5//@$0@$46`#+W91`` -M:#`0`"@C$`!H-Q`"MDT0`$6&$`*X1Q!%*`,`&$3S$``%1!`!D`,0`40#$$11 -MXP,,Q$`0`%'J$``&@1``1`D`))(@$`&8(A`!D`@0`!;``""2D!````L0```+ -M$`%:!!`!R`D01JXM``#0!Q`"N`T0`<@("2AI(!,)IA@));X8"26F$`DEK@@) -M):8`"26F!`DEK@P)):X0"26N%`D'/A40`(B2$`'("`DH:(`3":88"26^&`DE -MIA`)!SX!$$6:"0``::`)*"E`"0S:80D<["`)):80"26N"`DEI@`)):8$"26N -M#`DEKA`)):X4"0<^`1``Z@`0`>P($`%H`Q`!H@D)*&A`$`!F%!,)IB`))*,0 -M"01W0!`#?O$#&-'`$`&B@!`!*`(0`.(1$`'B@!`"O@40`2@"$```"Q``:880 -M`OFW$`#J`!`!B@D0`>H)$`'L"!`!:`,0`O[G$`!%1!`"OE40EJ+D!1",(!`` -M1``0`$&$$`&(81`!!@@&-<=$!C22(`8TFB`0`=-1$`&0'Q`!VU$0`%'Z$``0 -MIA`"N,,01:`"`L#0@!`#P,`0`:J!$`&B@!``FU<0`)4]$`*V(A``T$\01-`: -M`L#0`A`!JH$0`:*`$`";5Q``E3T0`K8:$`#03Q!$T!H"P-`"$`&J@1`!HH`0 -M`)M7$`"5/1`"MA(0`-!/$$30&@+`T`(0`:J!$`&B@!``FU<0`)4]$`*V"A`` -MT$\01-`:`L#0`A`!JH$0`:*`$`";5Q``E3T0`K8"$`!B'!`!D!\0`9I=$``B -MA1``8A80`KB7$`&J'A`!E%P0`&@6$`*X#1``6!80`K8)$`#B"!``E3<0`)L= -M$`*V!Q``+K,0`"UW$`*XGQ`"O@,0`!=7$`*XG!!,``L`,-@'&$#<#0``U`T0 -M`O>M$`!2%A`"N(40`:`!$`#0@!`#P,`0`:*!$`&J@!``E1<0`)M=$`*V/!`` -MT$\0`-`:$`&B@1`!JH`0`)47$`";71`"MC40`-!/$`#0&A`!HH$0`:J`$`"5 -M%Q``FUT0`K8N$`#03Q``T!H0`:*!$`&J@!``E1<0`)M=$`*V)Q``T$\0`-`: -M$`&B@1`!JH`0`)47$`";71`"MB`0`-!/$`#0&A`!HH$0`:J`$`"5%Q``FUT0 -M`K89$`#03Q``T!H0`:*!$`&J@!``E1<0`)M=$`*V$A``T$\0`-`:$`&B@1`! -MJH`0`)47$`";71`"M@L0`-!/$`#0&A`!HH$0`:J`$`"5%Q``FUT0`K8$$`!D -M"!`!9&80`KX$$`%D9A``91<0`K9%$`!PT`8UQT00`:I3$`!E$!!%9&`!`.@' -M$$:X`P``1$00`KX-$-CIUQ`"N`L0`$2$$`*^"1"6HD`%$(P@$`!!C!`!B&$0 -M`'$0!C7'1!``1A(0`K8R$`*.`Q`!1&<%4W_V$`&H`P8,DB`&$(@@$`#1^A!$ -MB)4`_,GS!BZX#A``J)<0`KHH$$1%%`(8U<80`K@*$`!4,Q``!*00E41G!5%2 -M81``0880`WD]$`%08!`#?SL0`-44$`!!AA`"N`401``+``!%-!"4``L%441G -M$`#5ZA``U$80FK8S!B*^,A``27`0`KX$$`!)@!``4?H0`$F>$`!$-!`"OA40 -M`$E`$`*^$Q``25`0`KX1$`!)8!`"O@\0`$D@$`*^#1``23`0`KX'$`!),!`" -MOB,0`$D0$`!$-!`"O@80`$D0$$0`"P``1300E``+!5%$9Q!$``L`'$?P!C1& -M$@8T<.`&-``+$`*^`1`"C@(0`WW[!@R2(!`"O`(&(KX*$`!@,!``(",&+&`W -M$`*V!A!$``L"&-7&$`*X"1"4190%441G$`#5ZA"8%$0%$(P@$```"P51U&`0 -M`W[[$$0`"P``1300E``+!5%$9Q``U180`O?U!B+_]!!(``L`'$?P``!V,`8T -M1A(&-'#@!C0`"Q`"O@$0`HX"$`-]^Q!$``L`!';0$`,^`1"4``L%$(P@$$@` -M"P``=C```$4P!5%$9Q"(``L`,``+$`*\`@8@``L0`W[=!120(!````L02:"` -M`Q30P`"$Y7`%3*43$$:V!P``Y5,02.47'_SE+P,4Y$$0`2#@$`*^!0`<80,0 -M`W?R$`!AZA``8($0`!,!$`!0"1`!JH`0```+$`#J$1`!ZH`0`W_I$`!VH`"W -M!`$0`9+!$`&:P!`!Y,,0D*40!4!00!`!+*40@*"P`#ZX`@`0``L0@%_C$$7: -M`0`$=L`0`R`!$$1VD`6H_!`0`P(!$XVF!`FH72`0D'=0"8<^`0FUY@`)M(H@ -M";2J(`FTDB`%$)`@";2:(!`!A($0`>H?$`#,!Q`"MA`0`,@'$`*V#A`!G!L) -MC*M0$`"<=Q`"NGH0`)QP$`!=A!`!W(`0`(AW$`"(?A``C%(0`<P<$`#-P!`" -MOAT0@``+`+:^8@F,JU`0`(Q1$`"L<!``;800`>R`$`#-P!`"OA03C:8`":A< -MP`F$=U`0`SX!$`&8'`FUY@`)M(@@";7^'!``R`<`MO?W$`"(UQ``B-X0`)A2 -M$$78'``$=L`0`R`!$`!VD!`#`@$3C;X<$$6J'P`@R`<0`KH.$``M<!!$;R`` -M`&WS$`!L!Q`"M@D0`"]B$`!L`!``K%<)J"Y>$`'L'0F<A#`)A'=0$$<^%A`` -M[4`0`*Q7":@N7A`![!T)G(0P"81W4!`#/@\0`"9X$`!GZA``9A$0`#$P";7' -MQ!``)3<0`KH2$$@E,@!@Q`(`8.`"$`*^#!`#?Y,0@``+`+:^(PF]_AP)N*0` -M$`&L'1``H#`0`.`\$$2%<0*`Q`<0`OWK$``Q(`FUQ\0`M`]Q$`*Z"A"03T(0 -M`$P1$`*V!A``3$<0`K@%$`!P,`503``%0&`0!5!,$A"`B7(01OG`$`&8'!`` -M=I`0`)C3$`-YKA!,``L``'90`"3-\0`<3?D0D#!@!5``"Q`#*@001``+``!V -M4!`#*@$0`':0$(,"`1.-I@@0`:H!":A<0`FDZA001``+`"C\$`F$=U`0`O_/ -M$`&J&1"```L`M.H1$`'J&1`"_^\0A``+`#P`"P8K.`$`4&`0`*AV(!"3/@$% -M%)0@$(100`"U@*`0```+$`!!C!`!P*``4&`0`!6$H1"0D!<&&)`>$`!W$`5, -M<1`&)8<D!5R:(!``P4(01';$`H#$!Q`"O`80`%@F$`+-YQ`#.`$0`'8@$)-_ -M]!!$4$`"(,0`$`"0%P88D!X0`O_W$$0`"P``=\`0D``+!5R:(!````L0`%@F -M$`,X`044E"`0```+$`&`H!````L0`$&&$`*X`P5,``L0`O_U!5R:(!"$``L` -M,%@F$`+_S`5,P4`01``+``1VT!"7/@$%$)0@$`!'$`511J<01<"@``!WP!"3 -M?_<01``+``!V@!`#``$3":90"2A80!``=T`)!SX!"32:(!``D#``,-H'$`*V -M'@`YVH`0`80C$`!>&A``7N,015Z%`OC4`!``%O$0`*00$`*V"1``#/<0`KH' -M$`&@H!````L0`:3#$`'0PQ`!Y(,0`KX$$``,\!`!P(,0`("0$`$:Y1``X``0 -M1*$W`!Q;[A``'M(0`%_Z$``P\!`!T;\0`,07$$0`"P``=D`0`WW6`!1VL!`# -M?_L&"*H@$$0`"P+XX4`0`)%P$`-W_!``[!80`K8%$`&:R08P``L0`-H1$`': -MR1!%FL(`'-&#$`#1AQ`"N`,0`-H1$`':PA!%FL8`(.P&$`*V`Q``VA$0`=K& -M$`#L)A!&N`X`#.V&$`-WYQ`!FL`0`.UV$`*V!A`!FL$0```+$`#:$1`!VL$0 -M`W_?$`#:$1`!VL`0`W_<$`&:PP8P[$80`K8$$`#:$1`!VL,0`W_6$$6:Q``, -M[880`K8$$`#:$1`!VL00`W_0$$6:Q0`@[`80`WG-$`#:$1`!VL40`W_*$$0` -M"P``R7`0`SX!$`$44!`!%E@0`%0L$`!6+!`!5%`0`598$`$40!`!%D@0`%0L -M$`!6+!`!5$`0159(`P#1L!`!D9`0`,DA$`"05Q`#??``,W_L``!W(!`#/@$/ -MA:8$$`,^`0^%I@@01``+``!W$!`#/@$/B>8$$`,^`1`!H@$/B*H@$$1@&@+L -MT0`0`!,!$`!0"1`!D9`0`>H"$$?`@!`!D@00```+$`'2`A!&_^H0`>0,$`'H -M#1`!Z@<01O_F$`'J!1``3``0`0X!$`#(`!``S$H0`,PJ$$;WWQ`"/J$02'XP -M``1V0`,`U;`0`<FP`"L^`1!&_]@0`>H%$`"=,!!,R```0,V``!S1P`,$U8`0 -M`<P;$`'1L!`!7@$0`%X'$$;WS0!`S3`0`-@`$``:X!``C-(0`-@0$`':`Q!$ -M``L``':`$(``"Q`#/@$3":84"2AG0`D$=T`0`SX!$`&:`PD]YA00`'$0"37' -M1!``7A(0`%@1$`':`P`P&-<0`K8($`!>!Q`"^>X02<P;`"#-P@,$U8`0`<VP -M$`*^#!`!S!L02)!P`"#1P@,$U8`0`=&P$`#,<A``6AH0`=H#$`!>!Q`"^=\0 -M1O^D$``,T!``#,(0`$Q*$`!W4!``#F`0`$TG$`!/+A``DI40`#!P$`'341`` -M#'(0`WGY$$;_EP,4R,`01>H%``3-0!`"/E802``+``3,P`+XR4`0`CY2$`$@ -M!!``3M`0`&!7$$;YBP,4R,`0`-(`$``P<!`!TU$01$ZP`OC)0!``,'`0`=-1 -M$$;_@@,`R9`016=0`P#((!!%[5`#',D@$`'I41`!95`01O]Z$```"Q"$``L` -M$``+$$;_=@,<R$`0`>M0$$;_<P!LU'`011X``P!``6!`0`!\W$$;W;1`! -M9@`02&87`!!0/@!PU9X&(%A.!@QTX`8RO@$01#:``##X0!``=/`0`KX!$``V -MD!``N+`0`#[`$`!T@!!&_UT##,A`$`!D`!``Y#H0`(DQ$`'L01`!:D00`6A% -M$$;_50,<R+`0`6=0$$;_4@,<R*`026=0`QS)```TV;`01=E0`"#,`!!%Z@4" -MP,@`$$8^(!`!H@$0`-P`$$@?(``TV;`#',D`$`"8\A`!V5`01O]!`P#)H!`! -M9D`01O\^$`'D`1!$``L``':`$(,^`0D-IA0`*.5`$`"D=PDH)GX0`(TR$`!F -M,1``9^H0`#$P"26'1`D$=T`0`SX!"3WF%``PS!<0`:0!$`+][Q`#P.`0`>0! -M$$0`"P``=H`0@SX!"0VF%``HY4`0`*1W"2@F?@D$C3(0`'=`"3WF%!`#/@$) -M.*8`$`#,%Q``,3`)-<=$`#&D`1`"_?`0`\#@$$;_*1!&_RP01O\O$$;_/!!& -M_WP01O^'$$;_CQ!&_P\01O\.$$;_#1!&_PP01O^O$$;_"A!&_[401O^W$$;_ -M!Q!&_P801O\%$$;_DA!&_P,01O^-$$;_P1!&_X<0`'3@$$:^`0`0=C`0`'3P -M$$:^`0`0=\`0`#60$`*^`1"`=I`0`P(!$$0`"P,@T8`3C::`":A80`FDVA`) -MA'=0$`,^`0"T``L01``+``!W(!`#/@$0A``+`#@`"Q!$``L#(-'`#X6'A!`# -M/@$/A8>`$$0`"P`(=N`0`SX!$`!TX!!*O@$`4/D0``AW0!``=/`02KX!`'#X -M8``(=L`0`#60$$:^`0+\T<`0`9J`$(@`"P`HVA$0A=J``#@`"Q!$``L`"';@ -M$`-_SQ````L0```+````````!@(````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` @@ -469,23 +596,17 @@ M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` +M`````$0````````8GQN$```````````8GQN$_____P`````````````````` +M````'P'B`!$`````````/P';`#,`````````+P'8`"(`!``````````````` +M```````````````````````````````````````````````````````M0@5L +M'`$M1`)*`P`!00-8"@`M0P!M!@`M0`60!``M2```@```#P``@``M108+$@`` +M````@``U@@6]?``UA@,^'@8`````@```````@```#P``@``UA@7T9`,`#P`` +M``$``!0`'F```!Z\%0`````````5```````?!````````!_0````````']P` +M```````?C``````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` -M````````````````````````````````````````!````````!B?&X0````` -M`````!B?&X3_____```````````````````````?`7H`$0`````````_`7,` -M,P`````````O`7``(@`$```````````````````````````````````````` -M`````````````````````````````"U"`V<<`2U$`80#``%!`L(*`"U#`&T& -M`"U``Z,$`"U(``"``"U'!1U.`2U%!!X2``````"``#6"`]!\`#6&`J@>!@`` -M``"```````"````/``"``#6&!`=D`P`/`````0``$``7P```&`P1```````` -M`!$``````!@L````````&.P````````8^````````!BL```````````````` M```````````````````````````````````````````````````````````` -M````````````````````````````````````$`@````````0$````````!`8 -M````````$"`````````0*````````!`P````````$#@````````00``````` -M`!!(````````$%`````````06````````!!@````````$&@````````0<``` -M`````!!X````````$(`````````0B````````!"0````````$)@````````0 -MH````````!"H````````$+`````````0N````````!#`````````$,@````` -M```0T````````!#8````````$.`````````0Z````````!#P````````$/@` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` @@ -505,6 +626,13 @@ M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````4"````````!00 +M````````%!@````````4(````````!0H````````%#`````````4.``````` +M`!1`````````%$@````````44````````!18````````%&`````````4:``` +M`````!1P````````%'@````````4@````````!2(````````%)`````````4 +MF````````!2@````````%*@````````4L````````!2X````````%,`````` +M```4R````````!30````````%-@````````4X````````!3H````````%/`` +M```````4^``````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` @@ -520,142 +648,239 @@ M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` -M````````````````````$0```!%````1@```$<```!(````20```$H```!+` -M```3````$T```!.````3P```%``````````40````````!2`````````%,`` -M```````5`````````!5`````````%8`````````5P``````$+P0S!#<$102& -M!(8$FP0<!!P$'`0<!,`$'`3(!,L$'`0<!!P$J@0<!*<$W`2C```````````` -M``````````````````````````````````````````````````````!@``&` M```````````````````````````````````````````````````````````` -M``7N````````!@,````^``````````!@``'P`!@``&```;`````````````` -M````````````````````_```````````"``````````````````````````` -M`````````````````&``````````8`````````!@`````````&`````````` -M8`````````!@`````````&``````````8``````````("`0`#`@$```````` M```````````````````````````````````````````````````````````` -M`````!```0```````@````(8`;L%[A@```````````````$``@$```9"```` -M`0$``@$```9$````!0`1(C,B,T15R`"1_!<!````````_NWP#0(``@$```NL -M``````````L````!```%7@````$```MB`````0``"Z(````!```+I0````\` -M```````%41``?A`0`/SP$`!TH!!.O@$%J/R```#YT``$=G`0`'0`$`*^`1"$ -M``L0`H@/$`+!_A`"Q?T0`H8#$`*"`A`"__H`6(``$(@`"Q`"P?<0A$&'$`*V -M`A`"__00```+`"@`"P`2__$);(H@#Y#`$`^H0!`0`KX`$$0`"P'4P```38<( -M`"V'!``UAP0`&8<$`"&'!`!1AP0`78<$$$1^<`'8P``0`8L1$`&3$1`!FQ$% -M!(I0!2@0@`4X$I`%1!2@!4`6L`5L&,`%:!K0$`!^$A`"_?402``+#`#```0` -MQ``)#((0"2A(0!`"O@$)!'=`$`,^`0F,@A`)J$A`$`*^`0F$=U`0`SX!$$1T -M\`'DX``0`KX!$`&]T1`!N=$0`3?1$`$_T1``=!(0`OW[$``UD!`"O@$01'Z` -M!X3\`!!&O@$!\.``$`&#T1`!B]$0`9K!$$63T@`(_"$0`'X2$`+Y^A!(Z@`" -M`.````AQ@!`!Z\\03``+!:C\@```?@``$'8`$`-_H1`!RAT0`KX#`##J`!`! -MZ@D018H'``!V8!``R@<0`S8&$$0`"P``=H`0`P`!$`!W0``JO@D01``+``!V -M@!`#``$)*&A`$PF^$!``=T`)!SX!"32*(`DH:,`)#(I0"0<^`1`!F@D0`:(% -M"37F'`DUYA8)->X`$`#:!Q`"N`80`9H($$7*"0``=]``,=H*$)<^%@DH:(`) -M#:88"27*!A`!D`@0`.0`"22C$`D$D1$0`=`($`#10!`!T`H0`8H=$`,^E!!$ -M``L``'?0$)<^`044A"`0`9H%$`&2(1`!BB`0``2P$(*^A044A"`0`<H&$`&2 -M(1`!BB`0@50`$`%6"1`!2`$0`$@`$`'0`Q`!DF`0`9IA$`'2"Q`!DF(0`=H, -M$`&L9A!%T@T0(.P'$`*V9Q!$:@``P.P'$`!K'A`!*`D0`6H#$`!I1A`"N$L0 -M`)CP$$2<D`,@Q0`0`:@C$`&B(!`!$@(0`)57$`";'1`"ME\0`%$@$`&D!A`` -MQ(`0`\#@$`&J(1`!HB`0`)57$`";'1`"ME`0`,1/$`#$&A`!JB$0`:(@$`"5 -M5Q``FQT0`K9)$`#$3Q``Q!H0`:HA$`&B(!``E5<0`)L=$`*V0A``Q$\0`,0: -M$`&J(1`!HB`0`)57$`";'1`"MCL0`,1/$`#$&A`!JB$0`:(@$`"55Q``FQT0 -M`K8T$`#$3Q``Q!H0`:HA$`&B(!``E5<0`)L=$`*V+1``Q$\0`,0:$`&J(1`! -MHB`0`)57$`";'1`"MB80`,1/$`#$&A`!JB$0`:(@$`"55Q``FQT0`K8?$`#$ -M3Q``Q!H0`:HA$`&B(!``E5<0`)L=$`*V&!!$``L`'&GP$`%H`!`!$@D0```+ -M$`!3(Q`!4@@0`%.`$`%2`A`"OA80`%``$`%0!1``;B80`K@#$`%L`!`"__00 -M`1("$```"Q``4H00`5("$`+_[Q`!K&@0`O^9$``19Q`"^>@0`&X6$`+WYA`` -M;B00`6XG$`!2`!`!4@(0`9H%$`$$"1``V4$0`)S7$`+[01!%V`H``':`$`,` -M`0DH:4`3":X`$)1Q$`DEAV0)!'=`"3WN``5//@$0@$46`#+W91``:#`0`"@C -M$`!H-Q`"MDT0`$6&$`*X1Q!%*`,`&$3S$``%1!`!D`,0`40#$$11XP,,Q$`0 -M`%'J$``&@1``1`D`))(@$`&8(A`!D`@0`!;``""2D!````L0```+$`%:!!`! -MR`D01JXM``#0!Q`"N`T0`<@("2AI(!,)IA@));X8"26F$`DEK@@)):8`"26F -M!`DEK@P)):X0"26N%`D'/A40`(B2$`'("`DH:(`3":88"26^&`DEIA`)!SX! -M$$6:"0``::`)*"E`"0S:80D<["`)):80"26N"`DEI@`)):8$"26N#`DEKA`) -M):X4"0<^`1``Z@`0`>P($`%H`Q`!H@D)*&A`$`!F)!,)IB`))*,0"01W0!`# -M?O$#&-'`$`&B@!`!*`(0`.(1$`'B@!`"O@40`2@"$```"Q``:880`OFW$`#J -M`!`!B@D0`>H)$`'L"!`!:`,0`O[G$`!%1!`"OE40EJ+D!1",(!``1``0`$&$ -M$`&(81`!!@@&-<=$!C22(`8TFB`0`=-1$`&0'Q`!VU$0`%'Z$``0IA`"N,,0 -M1:`"`L#0@!`#P,`0`:J!$`&B@!``FU<0`)4]$`*V(A``T$\01-`:`L#0`A`! -MJH$0`:*`$`";5Q``E3T0`K8:$`#03Q!$T!H"P-`"$`&J@1`!HH`0`)M7$`"5 -M/1`"MA(0`-!/$$30&@+`T`(0`:J!$`&B@!``FU<0`)4]$`*V"A``T$\01-`: -M`L#0`A`!JH$0`:*`$`";5Q``E3T0`K8"$`!B'!`!D!\0`9I=$``BA1``8A80 -M`KB7$`&J'A`!E%P0`&@6$`*X#1``6!80`K8)$`#B"!``E3<0`)L=$`*V!Q`` -M+K,0`"UW$`*XGQ`"O@,0`!=7$`*XG!!,``L`,-@'&$#<#0``U`T0`O>M$`!2 -M%A`"N(40`:`!$`#0@!`#P,`0`:*!$`&J@!``E1<0`)M=$`*V/!``T$\0`-`: -M$`&B@1`!JH`0`)47$`";71`"MC40`-!/$`#0&A`!HH$0`:J`$`"5%Q``FUT0 -M`K8N$`#03Q``T!H0`:*!$`&J@!``E1<0`)M=$`*V)Q``T$\0`-`:$`&B@1`! -MJH`0`)47$`";71`"MB`0`-!/$`#0&A`!HH$0`:J`$`"5%Q``FUT0`K89$`#0 -M3Q``T!H0`:*!$`&J@!``E1<0`)M=$`*V$A``T$\0`-`:$`&B@1`!JH`0`)47 -M$`";71`"M@L0`-!/$`#0&A`!HH$0`:J`$`"5%Q``FUT0`K8$$`!D"!`!9&80 -M`KX$$`%D9A``92<0`K9%$`!PT`8UQT00`:I3$`!E(!!%9&`!`.@'$$:X`P`` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M````````````````````````````````````````````%0```!5````5@``` +M%<```!8````60```%H```!;````7````%T```!>````7P```&``````````8 +M0````````!B`````````&,`````````9`````````!E`````````&8`````` +M```9P``````&'`8@!B0&+09N!FX&@P:+!ID&GP:]!LL&TP;8!ML&[`;O!J,& +MIP:E!@D&\0``!X@````.```````````````````````````````````````` +M```"L`*G`K$```*5`I4"G0```K("J`*R``````>8````%@`````````````` +M``````!@``&````````````````````````````````````````````````` +M```````````````````````````````````%[@````````>O````2P`````` +M````8``!\``8``!@``&P```````````````````````````````````````` +M````````````````JJH#``````````$`````````````````````\P`````` +M``````````@```````````````````````````````````````````!@```` +M`````&``````````8`````````!@`````````&``````````8`````````!@ +M`````````&``````````"`@$``P(!``````````````````````````````` +M````````````````````````````````````````@0````*P$``!```````" +M```````"@07N&````````````````0("`0``!_L````!`0("`0``!_T````" +M`!$B,R(S1%7^[?`-`@4"`0``#KX`````````%P````$```>>`````0``#",` +M```!```,+P````$```XH`````0``#D0````!```.@P````$```Z&`````0`` +M#HH````!```.F@````$```ZU````#P````````>%$`!^$!``_/`0`'2@$$Z^ +M`06H_(```/G0``1V<!``=``0`KX!$`*($!`"@@(0`O_^`%B```!8@@``.L7[ +M$``$`!``!!(0`$6,$`!$AQ`"O`(0`O_Y$`+%]!`"Q?,0`L7R!C+_\0ELBB`/ +MD,`0#ZA`$!`"O@`01``+`=3```!-AP@`+8<$`#6'!``9AP0`(8<$`%&'!`!= +MAP001'YP`=C``!`!BQ$0`9,1$`&;$04$BE`%*!"`!3@2D`5$%*`%0!:P!6P8 +MP`5H&M`0`'X2$`+]]1!(``L,`,``!`#$``D,@A`)*$A`$`*^`0D$=T`0`SX! +M"8R"$`FH2$`0`KX!"81W4!`#/@$01'3P`>3@`!`"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`<P=!"6K;P1-HV\$/>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=$`)%<A"*_S`$3:9@!"6F9`0_ +M/@$$-)(@!%":(!`!H@00`:H%$`"3%1``FU40`:)@$`&J81`!X@00`>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[\$`"-<!!$08<`!'<0$`*Z%Q`"0U`0`KX5"A"2 +M(`H0FB`0`:)@$`&J81``DQ40`)M5$`'3<1``3"P0`=MQ$`!,+`H0DB`*$)H@ +M$`&B8!`!JF$0`),5$`";51`!TW$0`$PL$`';<1`"1R,0`$42$`*Z"0HUIA`* +M-:84"C6F&`HUJ@<*0``+"@SJ$1`!Z@<0`W_C$`)%%A"*_M80`(UP$`&2!!!% +MF@4`!'<0$`*^#PH0DB`*$)H@"A"B(`H0JB`0`=-Q$`!,+!`!VW$0`$PL$`'C +M<1``3"P0`>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<D"C6')`HUAR0*#SX9$`&$HA!% +M/J$%J/R`$`#H`!``*_(0`&KS$`*X!Q`!BS$0`:("$`&J`Q`!D@`0`9H!$`*^ +M$1``H#`0`"/Q$``Q4!`!:=$0`#]1$`&+,1`!H@(0`:H#$`&2`!`!F@$0`KX& +M$`&+,0H0DB`*$)H@"A"B(`H0JB`*-(J5"D&+,1`!DS$*-(K5$`&+,0HTDQ4* +M-(M5"@Q_$A`#>?,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<P/"C6F$`HUIA0*-:88"C6F'`H//@$0`9(`$`&:`0H0HB`*$*H@$`#] +M@0H0HI4*$*K5$`'C,1`!ZS$0B-2!`#Q73!!(A+```'=@!:C\@``XE-<0`O@, +M`!-^"Q,H8$`)#:Z0"01W0!"+/@$%$(`@"32J(!`!A`()*&$P"0WJBPD'/@$) +M-(@@$$6/+`.,Y$`0`'!`"37')`DUUR00A'!0"37'Y`DTJB`)*`I0"0RK4!`! +MR(P`/$DF"0<V`@`7/@$0B$B&"32B(!"&MA``,>(@$$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<Q``(U$0`&`)$`'@C1``:D<01:K@!`3@`!`!ZH40`.%. +M$``@9!``(F00`>"<$`*^!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$`"<T@FH%MX)C:X$"9R@D!`"O@$)N*H`$`#@/!"`,5`)I8?$"81W4`F][@00 +M`SH0$`,^`0"T``L0CCY1$`"8TQ`"N`<0`%&&$`*X-A`"/D(0`&@F$`+W_A`" +MOA00`)"Q$`"<\Q`"]]L0`O_C`+28LA``D+$0`O_7$(!VD!`#/@$3C:X`":A7 +M(`F$=U`0`SX!$`!P0`FUQP0)M=\0`+0`"Q`"_\P0CCXV$$6B'P`HU$<0`18= +M$`*V!Q``8!80`K@/$``7(!``:480`K8"$``7,!"`=I`0`SX!$XVN`!``,+`) +MI8>$":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=$`*^`P`PZ@`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`<P<$`#-P!`"OAT0@``+ -M`+:^8@F,JU`0`(Q1$`"L<!``;800`>R`$`#-P!`"OA03C:8`":A<P`F$=U`0 -M`SX!$`&8'`FUY@`)M(@@";7^'!``R`<`MO?W$`"(UQ``B-X0`)A2$$78'``$ -M=L`0`R`!$`!VD!`#`@$3C;X<$$6J'P`@R`<0`KH.$``M<!!$;R```&WS$`!L -M!Q`"M@D0`"]B$`!L`!``K%<)J"Y>$`'L'0F<A#`)A'=0$$<^%A``[4`0`*Q7 -M":@N7A`![!T)G(0P"81W4!`#/@\0`"9X$`!GZA``9A$0`#$P";7'Q!``)3<0 -M`KH2$$@E,@!@Q`(`8.`"$`*^#!`#?Y,0@``+`+:^(PF]_AP)N*0`$`&L'1`` -MH#`0`.`\$$2%<0*`Q`<0`OWK$``Q(`FUQ\0`M`]Q$`*Z"A"03T(0`$P1$`*V -M!A``3$<0`K@%$`!P,`503``%0&`0!5!,$A"`B7(01OG`$`&8'!``=I`0`)C3 -M$`-YKA!,``L``'90`"3-\0`<3?D0D#!@!5``"Q`#*@001``+``!V4!`#*@$0 -M`':0$(,"`1.-I@@0`:H!":A<0`FDZB001``+`"C\$`F$=U`0`O_/$`&J&1"` -M``L`M.H1$`'J&1`"_^\0A``+`#P`"P8K.`$`4&`0`*AV(!"3/@$%%)0@$(10 -M0`"U@*`0```+$`!!C!`!P*``4&`0`!6$H1"0D!<&&)`>$`!W$`5,<1`&)8<D -M!5R:(!``P4(01';$`H#$!Q`"O`80`%@F$`+-YQ`#.`$0`'8@$)-_]!!$4$`" -M(,0`$`"0%P88D!X0`O_W$$0`"P``=\`0D``+!5R:(!````L0`%@F$`,X`044 -ME"`0```+$`&`H!````L0`$&&$`*X`P5,``L0`O_U!5R:(!"$``L`,%@F$`+_ -MS`5,P4`01``+``1VT!"7/@$%$)0@$`!'$`511J<01<"@``!WP!"3?_<01``+ -M``!V@!`#``$3":90"2A80!``=T`)!SX!"32:(!``D#``,-H'$`*V'@`YVH`0 -M`80C$`!>&A``7N,015Z%`OC4`!``%O$0`*00$`*V"1``#/<0`KH'$`&@H!`` -M``L0`:3#$`'0PQ`!Y(,0`KX$$``,\!`!P(,0`("0$`$:Y1``X``01*$W`!Q; -M[A``'M(0`%_Z$``P\!`!T;\0`,07$$0`"P``=D`0`WW6`!1VL!`#?_L&"*H@ -M$$0`"P+XX4`0`)%P$`-W_!``[!80`K8%$`&:R08P``L0`-H1$`':R1!%FL(` -M'-&#$`#1AQ`"N`,0`-H1$`':PA!%FL8`(.P&$`*V`Q``VA$0`=K&$`#L)A!& -MN`X`#.V&$`-WYQ`!FL`0`.UV$`*V!A`!FL$0```+$`#:$1`!VL$0`W_?$`#: -M$1`!VL`0`W_<$`&:PP8P[$80`K8$$`#:$1`!VL,0`W_6$$6:Q``,[880`K8$ -M$`#:$1`!VL00`W_0$$6:Q0`@[`80`WG-$`#:$1`!VL40`W_*$$0`"P``R7`0 -M`SX!$`$44!`!%E@0`%0L$`!6+!`!5%`0`598$`$40!`!%D@0`%0L$`!6+!`! -M5$`0159(`P#1L!`!D9`0`,DA$`"05Q`#??``,W_L``!W(!`#/@$/A:8$$`,^ -M`0^%I@@01``+``!W$!`#/@$/B>8$$`,^`1`!H@$/B*H@$$1@&@+LT0`0`!,! -M$`!0"1`!D9`0`>H"$$?`@!`!D@00```+$`'2`A!&_^H0`>0,$`'H#1`!Z@<0 -M1O_F$`'J!1``3``0`0X!$`#(`!``S$H0`,PJ$$;WWQ`"/J$02'XP``1V0`,` -MU;`0`<FP`"L^`1!&_]@0`>H%$`"=,!!,R```0,V``!S1P`,$U8`0`<P;$`'1 -ML!`!7@$0`%X'$$;WS0!`S3`0`-@`$``:X!``C-(0`-@0$`':`Q!$``L``':` -M$(``"Q`#/@$3":84"2AG0`D$=T`0`SX!$`&:`PD]YA00`'$0"37'1!``7A(0 -M`%@1$`':`P`P&-<0`K8($`!>!Q`"^>X02<P;`"#-P@,$U8`0`<VP$`*^#!`! -MS!L02)!P`"#1P@,$U8`0`=&P$`#,<A``6AH0`=H#$`!>!Q`"^=\01O^D$``, -MT!``#,(0`$Q*$`!W4!``#F`0`$TG$`!/+A``DI40`#!P$`'341``#'(0`WGY -M$$;_EP,4R,`01>H%``3-0!`"/E802``+``3,P`+XR4`0`CY2$`$@!!``3M`0 -M`&!7$$;YBP,4R,`0`-(`$``P<!`!TU$01$ZP`OC)0!``,'`0`=-1$$;_@@,` -MR9`016=0`P#((!!%[5`#',D@$`'I41`!95`01O]Z$```"Q"$``L`$``+$$;_ -M=@,<R$`0`>M0$$;_<P!LU'`011X``P!``6!`0`!\W$$;W;1`!9@`02&87 -M`!!0/@!PU9X&(%A.!@QTX`8RO@$01#:``##X0!``=/`0`KX!$``VD!``N+`0 -M`#[`$`!T@!!&_UT##,A`$`!D`!``Y#H0`(DQ$`'L01`!:D00`6A%$$;_50,< -MR+`0`6=0$$;_4@,<R*`026=0`QS)```TV;`01=E0`"#,`!!%Z@4"P,@`$$8^ -M(!`!H@$0`-P`$$@?(``TV;`#',D`$`"8\A`!V5`01O]!`P#)H!`!9D`01O\^ -M$`'D`1!$``L``':`$(,^`0D-IA0`*.5`$`"D=PDH)GX0`(TR$`!F,1``9^H0 -M`#$P"26'1`D$=T`0`SX!"3WF%``PS!<0`:0!$`+][Q`#P.`0`>0!$$0`"P`` -M=H`0@SX!"0VF%``HY4`0`*1W"2@F?@D$C3(0`'=`"3WF%!`#/@$).*8`$`#, -M%Q``,3`)-<=$`#&D`1`"_?`0`\#@$$;_*1!&_RP01O\O$$;_/!!&_WP01O^' -M$$;_CQ!&_P\01O\.$$;_#1!&_PP01O^O$$;_"A!&_[401O^W$$;_!Q!&_P80 -M1O\%$$;_DA!&_P,01O^-$$;_P1!&_X<0`'3@$$:^`0`0=C`0`'3P$$:^`0`0 -M=\`0`#60$`*^`1"`=I`0`P(!$$0`"P,@T8`3C::`":A80`FDVA`)A'=0$`,^ -M`0"T``L01``+``!W(!`#/@$0A``+`#@`"Q!$``L#(-'`#X6'A!`#/@$/A8>` -M$$0`"P`(=N`0`SX!$`!TX!!*O@$`4/D0``AW0!``=/`02KX!`'#X8``(=L`0 -M`#60$$:^`0+\T<`0`9J`$(@`"P`HVA$0A=J``#@`"Q!$``L`"';@$`-_SQ`` -M``L0```+````````!@(````````````````````````````````````````` +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`<R`$`"(=Q``B'X0`(Q2$`','!``S<`0`KX6$(``"P"VODL3C:8`":A<P`F$ +M=U`0`SX!$`&8'`FUY@`)M(@@";7^'!``R`<`MO?W$`"(UQ``B-X0`)A2$$78 +M'``$=L`0`R`!$`!VD!`#`@$3C;X<$`#M0!``K%<)J"Y>$`'L'0F<A#`)A'=0 +M$`,^#Q``)G@0`&?J$`!F$1``,3`)M<?$$``E-Q`"NA(02"4R`&#$`@!@X`(0 +M`KX,$`-_K1"```L`MKXC";W^'`FXI``0`:P=$`"@,!``X#P01(5Q`OC$!Q`" +M_>L0`#$@";7'Q`"T#W$0`KH*$)!/0A``3!$0`K8&$`!,1Q`"N`40`'`P!5!, +M``5`8!`%4$P2$(")<A!&^=`0`9@<$`!VD!``F-,0`WF^$$P`"P``=E``),WQ +M`!Q-^1"0,&`%4``+$`,J!!!$``L``'90$`,J`1``=I`0@P(!$XVF"!`!J@$) +MJ%Q`":3J)!!$``L`*/P0"81W4!`"_\\0`:H9$(``"P"TZA$0`>H9$`+_[P8K +M.`$`J'8@$),^`044E"`0`%!`$`&`H!`!A*$0`)`7!AB0'A``=Q`%3'$0!B6' +M)`5<FB`0A,%"$$1VQ`+XQ`<0`KP&`!!8)@"VS>X0`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$``P<!`!TU$01O_1`UC)D!!%9U`#6,@@$$7M4`-TR0`0`>E1$`%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$$;_<Q!&_\,01O]Q$$;_<!!&_V\0 +M1O]N$$;_;1!&_VP01O^F$$;_:A!&_Z$01O_!$```"Q````L````````$@P`` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` @@ -727,6 +952,14 @@ M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` +M``````````Q$````````&9\<A!W>````````&9\<A/____\````!```````` +M`````````!\!I@`1`````````#\!GP`S`````````"\!G``B``0``````/\! +M+``S`````````#\!*``S``$`!P`````````````````````````````````` +M+4(&31P!+40%&P,``4$%Q`H`+4,$8@8`+4`&<00`+4@``(````\``(``+44& +M[!(``````(``-8(&GGP`-88%JAX&,<<#OC(",2X#S!<"``\``(``-88&U60# +M``\````!```3P!J````:S!3`````````%,``````&NP````````;K``````` +M`!NT````````&VP``````````````````!Q`$H`````````````````````` +M`````````````````````````````````````!R,$H`2@!*````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` @@ -738,24 +971,21 @@ M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` -M````````````````````````````````!````````!F?'(0``````````!F? -M'(3_____```````````````````````?`7H`$0`````````_`7,`,P`````` -M```O`7``(@`$```````````````````````````````````````````````` -M`````````````````````"U"`V<<`2U$`80#``%!`L(*`"U#`&T&`"U``Z,$ -M`"U(``"``"U'!1U.`2U%!!X2``````"``#6"`]!\`#6&`J@>!@````"````` -M``"````/``"``#6&!`=D`P`/`````0``$``7P```&`P1`````````!$````` -M`!@L````````&.P````````8^````````!BL```````````````````````` +M````````````````````````````````````````!(0````*`.4`Y@`````` +M]0#V`0H!"P%/`5`!90%F`8L!C`&O`;$!YP'G`A8"%@``!*````'W`````!`` +M````````$$`````````0@````````!#`````````$0`````````10``````` +M`!&`````````$<`````````````````````````````````````````````` M```````````````````````````````````````````````````````````` -M````````````````````````````$`@````````0$````````!`8```````` -M$"`````````0*````````!`P````````$#@````````00````````!!(```` -M````$%`````````06````````!!@````````$&@````````0<````````!!X -M````````$(`````````0B````````!"0````````$)@````````0H``````` -M`!"H````````$+`````````0N````````!#`````````$,@````````0T``` -M`````!#8````````$.`````````0Z````````!#P````````$/@````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` +M```````3R````````!/0````````$]@````````3X````````!/H```````` +M$_`````````3^````````!0`````````%`@````````4$````````!08```` +M````%"`````````4*````````!0P````````%#@````````40````````!1( +M````````%%`````````46````````!1@````````%&@````````4<``````` +M`!1X````````%(`````````4B````````!20````````%)@````````4H``` +M`````!2H````````%+`````````4N``````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` @@ -784,20 +1014,23 @@ M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` +M`````````!3````5````%4```!6````5P```%@```!9````6@```%L```!<` +M```70```%X```!?`````````&``````````80````````!B`````````&,`` +M```````9`````````!E`````````&8``````!OT'`0;J!NH'!0<%!QH&Z@;J +M!NH&Z@<[!NH&Z@;J!NH&Z@;J!R4&Z@<B!T,```:8````&@`````````````` +M`````````````````````````````````````````````````&```9`````` +M````````````````````````````````````````````````````````!>X` +M```````&LP```#T``````````&```?``&```8``!P``````````````````` +M``````````````2E```````````(```````````````````````````````` +M````````````8`````````!@`````````&``````````8`````````!@```` +M`````&``````````8`````````!@``````````@(!``,"`0````````````` M```````````````````````````````````````````````````````````` +M(``!```````"```````%[A@````````````"!0(!```&\0````$"!0(!```& +M\P````(`$2(S(C-$50``!P`````.________________________________ +M________________________________``````````````</````&1*``#$` M```````````````````````````````````````````````````````````` -M````````````$0```!%````1@```$<```!(````20```$H```!+````3```` -M$T```!.````3P```%``````````40````````!2`````````%,`````````5 -M`````````!5`````````%8`````````5P``````$+P0S!#<$102&!(8$FP0< -M!!P$'`0<!,`$'`3(!,L$'`0<!!P$J@0<!*<$W`2C```````````````````` -M``````````````````````````````````````````````!@``&0```````` -M``````````````````````````````````````````````````````7N```` -M````!@,````^``````````!@``'P`!@``&```<`````````````````````` -M````````````_```````````"``````````````````````````````````` -M`````````&``````````8`````````!@`````````&``````````8``````` -M``!@`````````&``````````8``````````("`0`#`@$```````````````` -M`````````````````````````````````````````````````````````"`` -M`0```````@````(8`;L%[A@```````````````(``@$```9"`````0(``@$` -C``9$````!0`1(C,B,T15R`"A_!<"````````_NWP#?[M\`T` +M````````````````````````````````````````WJV^[]ZMON_>K;[OWJV^ +M[]ZMON\```<I````!P````````````````````!@``'@`````&```=#^[?`- +$_NWP#0`` ` end diff --git a/sys/dev/usb/ehci.c b/sys/dev/usb/ehci.c index e9b2cb8..529ba1b 100644 --- a/sys/dev/usb/ehci.c +++ b/sys/dev/usb/ehci.c @@ -99,7 +99,6 @@ int ehcidebug = 0; SYSCTL_NODE(_hw_usb, OID_AUTO, ehci, CTLFLAG_RW, 0, "USB ehci"); SYSCTL_INT(_hw_usb_ehci, OID_AUTO, debug, CTLFLAG_RW, &ehcidebug, 0, "ehci debug level"); -#define bitmask_snprintf(q,f,b,l) snprintf((b), (l), "%b", (q), (f)) #else #define DPRINTF(x) #define DPRINTFN(n,x) @@ -221,34 +220,20 @@ static usbd_status ehci_device_request(usbd_xfer_handle xfer); static usbd_status ehci_device_setintr(ehci_softc_t *, ehci_soft_qh_t *, int ival); -static void ehci_add_qh(ehci_soft_qh_t *, ehci_soft_qh_t *); +static void ehci_add_qh(ehci_softc_t *, ehci_soft_qh_t *, + ehci_soft_qh_t *); static void ehci_rem_qh(ehci_softc_t *, ehci_soft_qh_t *, ehci_soft_qh_t *); -static void ehci_activate_qh(ehci_soft_qh_t *, ehci_soft_qtd_t *); +static void ehci_activate_qh(ehci_softc_t *sc, ehci_soft_qh_t *, + ehci_soft_qtd_t *); static void ehci_sync_hc(ehci_softc_t *); static void ehci_close_pipe(usbd_pipe_handle, ehci_soft_qh_t *); static void ehci_abort_xfer(usbd_xfer_handle, usbd_status); -#ifdef EHCI_DEBUG -static void ehci_dump_regs(ehci_softc_t *); -void ehci_dump(void); -static ehci_softc_t *theehci; -static void ehci_dump_link(ehci_link_t, int); -static void ehci_dump_sqtds(ehci_soft_qtd_t *); -static void ehci_dump_sqtd(ehci_soft_qtd_t *); -static void ehci_dump_qtd(ehci_qtd_t *); -static void ehci_dump_sqh(ehci_soft_qh_t *); -#ifdef notyet -static void ehci_dump_sitd(struct ehci_soft_itd *); -static void ehci_dump_itd(struct ehci_soft_itd *); -#endif -#ifdef DIAGNOSTIC -static void ehci_dump_exfer(struct ehci_xfer *); -#endif -#endif +ehci_softc_t *theehci; -#define EHCI_NULL htole32(EHCI_LINK_TERMINATE) +#define EHCI_NULL(sc) htohc32(sc, EHCI_LINK_TERMINATE) #define EHCI_INTR_ENDPT 1 @@ -344,17 +329,26 @@ ehci_hcreset(ehci_softc_t *sc) * Table 2-9 in the EHCI spec says this will result * in undefined behavior. */ - printf("%s: stop timeout\n", - device_get_nameunit(sc->sc_bus.bdev)); + device_printf(sc->sc_bus.bdev, "stop timeout\n"); EOWRITE4(sc, EHCI_USBCMD, EHCI_CMD_HCRESET); for (i = 0; i < 100; i++) { usb_delay_ms(&sc->sc_bus, 1); hcr = EOREAD4(sc, EHCI_USBCMD) & EHCI_CMD_HCRESET; if (!hcr) { - if (sc->sc_flags & EHCI_SCFLG_SETMODE) - EOWRITE4(sc, 0x68, 0x3); - + if (sc->sc_flags & EHCI_SCFLG_SETMODE) { + /* + * Force USBMODE as requested. Controllers + * may have multiple operating modes. + */ + uint32_t usbmode = EOREAD4(sc, EHCI_USBMODE); + if (sc->sc_flags & EHCI_SCFLG_SETMODE) { + usbmode = (usbmode &~ EHCI_UM_CM) | EHCI_UM_CM_HOST; + device_printf(sc->sc_bus.bdev, + "set host controller mode\n"); + } + EOWRITE4(sc, EHCI_USBMODE, usbmode); + } return (USBD_NORMAL_COMPLETION); } } @@ -377,10 +371,12 @@ ehci_init(ehci_softc_t *sc) theehci = sc; #endif + /* NB: must handle byte-order manually before ehci_hcreset */ + sc->sc_offs = EREAD1(sc, EHCI_CAPLENGTH); version = EREAD2(sc, EHCI_HCIVERSION); - printf("%s: EHCI version %x.%x\n", device_get_nameunit(sc->sc_bus.bdev), + device_printf(sc->sc_bus.bdev, "EHCI version %x.%x\n", version >> 8, version & 0xff); sparams = EREAD4(sc, EHCI_HCSPARAMS); @@ -435,7 +431,7 @@ ehci_init(ehci_softc_t *sc) sc->sc_flist = KERNADDR(&sc->sc_fldma, 0); for (i = 0; i < sc->sc_flsize; i++) { - sc->sc_flist[i] = EHCI_NULL; + sc->sc_flist[i] = EHCI_NULL(sc); } EOWRITE4(sc, EHCI_PERIODICLISTBASE, DMAADDR(&sc->sc_fldma, 0)); @@ -450,11 +446,6 @@ ehci_init(ehci_softc_t *sc) sc->sc_bus.methods = &ehci_bus_methods; sc->sc_bus.pipe_size = sizeof(struct ehci_pipe); -#if defined(__NetBSD__) || defined(__OpenBSD__) - sc->sc_powerhook = powerhook_establish(ehci_power, sc); - sc->sc_shutdownhook = shutdownhook_establish(ehci_shutdown, sc); -#endif - sc->sc_eintrs = EHCI_NORMAL_INTRS; /* @@ -476,27 +467,26 @@ ehci_init(ehci_softc_t *sc) sqh = sc->sc_islots[i].sqh; if (i == 0) { /* The last (1ms) QH terminates. */ - sqh->qh.qh_link = EHCI_NULL; + sqh->qh.qh_link = EHCI_NULL(sc); sqh->next = NULL; } else { /* Otherwise the next QH has half the poll interval */ sqh->next = sc->sc_islots[EHCI_IQHIDX(lev - 1, i + 1)].sqh; - sqh->qh.qh_link = htole32(sqh->next->physaddr | + sqh->qh.qh_link = htohc32(sc, sqh->next->physaddr | EHCI_LINK_QH); } - sqh->qh.qh_endp = htole32(EHCI_QH_SET_EPS(EHCI_QH_SPEED_HIGH)); - sqh->qh.qh_endphub = htole32(EHCI_QH_SET_MULT(1)); - sqh->qh.qh_curqtd = EHCI_NULL; - sqh->qh.qh_qtd.qtd_next = EHCI_NULL; - sqh->qh.qh_qtd.qtd_altnext = EHCI_NULL; - sqh->qh.qh_qtd.qtd_status = htole32(EHCI_QTD_HALTED); + sqh->qh.qh_endp = htohc32(sc, EHCI_QH_SET_EPS(EHCI_QH_SPEED_HIGH)); + sqh->qh.qh_endphub = htohc32(sc, EHCI_QH_SET_MULT(1)); + sqh->qh.qh_curqtd = EHCI_NULL(sc); + sqh->qh.qh_qtd.qtd_next = EHCI_NULL(sc); + sqh->qh.qh_qtd.qtd_altnext = EHCI_NULL(sc); + sqh->qh.qh_qtd.qtd_status = htohc32(sc, EHCI_QTD_HALTED); } /* Point the frame list at the last level (128ms). */ for (i = 0; i < sc->sc_flsize; i++) { - sc->sc_flist[i] = htole32(EHCI_LINK_QH | - sc->sc_islots[EHCI_IQHIDX(EHCI_IPOLLRATES - 1, - i)].sqh->physaddr); + sc->sc_flist[i] = htohc32(sc, EHCI_LINK_QH | + sc->sc_islots[EHCI_IQHIDX(EHCI_IPOLLRATES - 1, i)].sqh->physaddr); } /* Allocate dummy QH that starts the async list. */ @@ -507,19 +497,19 @@ ehci_init(ehci_softc_t *sc) } /* Fill the QH */ sqh->qh.qh_endp = - htole32(EHCI_QH_SET_EPS(EHCI_QH_SPEED_HIGH) | EHCI_QH_HRECL); + htohc32(sc, EHCI_QH_SET_EPS(EHCI_QH_SPEED_HIGH) | EHCI_QH_HRECL); sqh->qh.qh_link = - htole32(sqh->physaddr | EHCI_LINK_QH); - sqh->qh.qh_curqtd = EHCI_NULL; + htohc32(sc, sqh->physaddr | EHCI_LINK_QH); + sqh->qh.qh_curqtd = EHCI_NULL(sc); sqh->prev = sqh; /*It's a circular list.. */ sqh->next = sqh; /* Fill the overlay qTD */ - sqh->qh.qh_qtd.qtd_next = EHCI_NULL; - sqh->qh.qh_qtd.qtd_altnext = EHCI_NULL; - sqh->qh.qh_qtd.qtd_status = htole32(0); + sqh->qh.qh_qtd.qtd_next = EHCI_NULL(sc); + sqh->qh.qh_qtd.qtd_altnext = EHCI_NULL(sc); + sqh->qh.qh_qtd.qtd_status = htohc32(sc, 0); #ifdef EHCI_DEBUG if (ehcidebug) { - ehci_dump_sqh(sqh); + ehci_dump_sqh(sc, sqh); } #endif @@ -777,10 +767,10 @@ ehci_check_qh_intr(ehci_softc_t *sc, struct ehci_xfer *ex) * is a an error somewhere in the middle, or whether there was a * short packet (SPD and not ACTIVE). */ - if (le32toh(lsqtd->qtd.qtd_status) & EHCI_QTD_ACTIVE) { + if (hc32toh(sc, lsqtd->qtd.qtd_status) & EHCI_QTD_ACTIVE) { DPRINTFN(12, ("ehci_check_intr: active ex=%p\n", ex)); for (sqtd = ex->sqtdstart; sqtd != lsqtd; sqtd=sqtd->nextqtd) { - status = le32toh(sqtd->qtd.qtd_status); + status = hc32toh(sc, sqtd->qtd.qtd_status); /* If there's an active QTD the xfer isn't done. */ if (status & EHCI_QTD_ACTIVE) break; @@ -825,7 +815,7 @@ ehci_check_itd_intr(ehci_softc_t *sc, struct ehci_xfer *ex) * Step 1, check no active transfers in last itd, meaning we're finished */ for (i = 0; i < 8; i++) { - if (le32toh(itd->itd.itd_ctl[i]) & EHCI_ITD_ACTIVE) + if (hc32toh(sc, itd->itd.itd_ctl[i]) & EHCI_ITD_ACTIVE) break; } @@ -841,7 +831,7 @@ ehci_check_itd_intr(ehci_softc_t *sc, struct ehci_xfer *ex) for (itd = ex->itdstart; itd != ex->itdend; itd = itd->xfer_next) { for (i = 0; i < 8; i++) { - if (le32toh(itd->itd.itd_ctl[i]) & (EHCI_ITD_BUF_ERR | + if (hc32toh(sc, itd->itd.itd_ctl[i]) & (EHCI_ITD_BUF_ERR | EHCI_ITD_BABBLE | EHCI_ITD_ERROR)) break; } @@ -865,6 +855,7 @@ ehci_idone(struct ehci_xfer *ex) { usbd_xfer_handle xfer = &ex->xfer; struct ehci_pipe *epipe = (struct ehci_pipe *)xfer->pipe; + ehci_softc_t *sc = (ehci_softc_t *)epipe->pipe.device->bus; ehci_soft_qtd_t *sqtd, *lsqtd; u_int32_t status = 0, nstatus = 0; ehci_physaddr_t nextphys, altnextphys; @@ -878,7 +869,7 @@ ehci_idone(struct ehci_xfer *ex) splx(s); #ifdef EHCI_DEBUG printf("ehci_idone: ex is done!\n "); - ehci_dump_exfer(ex); + ehci_dump_exfer(sc, ex); #else printf("ehci_idone: ex=%p is done!\n", ex); #endif @@ -898,7 +889,7 @@ ehci_idone(struct ehci_xfer *ex) #ifdef EHCI_DEBUG DPRINTFN(/*10*/2, ("ehci_idone: xfer=%p, pipe=%p ready\n", xfer, epipe)); if (ehcidebug > 10) - ehci_dump_sqtds(ex->sqtdstart); + ehci_dump_sqtds(sc, ex->sqtdstart); #endif /* @@ -906,14 +897,14 @@ ehci_idone(struct ehci_xfer *ex) * of the qTDs we are about to free. This is probably only * necessary if the transfer is marked as HALTED. */ - nextphys = EHCI_LINK_ADDR(le32toh(epipe->sqh->qh.qh_qtd.qtd_next)); + nextphys = EHCI_LINK_ADDR(hc32toh(sc, epipe->sqh->qh.qh_qtd.qtd_next)); altnextphys = - EHCI_LINK_ADDR(le32toh(epipe->sqh->qh.qh_qtd.qtd_altnext)); + EHCI_LINK_ADDR(hc32toh(sc, epipe->sqh->qh.qh_qtd.qtd_altnext)); for (sqtd = ex->sqtdstart; sqtd != ex->sqtdend->nextqtd; sqtd = sqtd->nextqtd) { if (sqtd->physaddr == nextphys) { epipe->sqh->qh.qh_qtd.qtd_next = - htole32(ex->sqtdend->nextqtd->physaddr); + htohc32(sc, ex->sqtdend->nextqtd->physaddr); DPRINTFN(4, ("ehci_idone: updated overlay next ptr\n")); } @@ -921,7 +912,7 @@ ehci_idone(struct ehci_xfer *ex) DPRINTFN(4, ("ehci_idone: updated overlay altnext ptr\n")); epipe->sqh->qh.qh_qtd.qtd_altnext = - htole32(ex->sqtdend->nextqtd->physaddr); + htohc32(sc, ex->sqtdend->nextqtd->physaddr); } } @@ -964,7 +955,7 @@ ehci_idone(struct ehci_xfer *ex) if (nframes >= xfer->nframes) break; - status = le32toh(itd->itd.itd_ctl[i]); + status = hc32toh(sc, itd->itd.itd_ctl[i]); len = EHCI_ITD_GET_LEN(status); xfer->frlengths[nframes++] = len; actlen += len; @@ -984,7 +975,7 @@ ehci_idone(struct ehci_xfer *ex) actlen = 0; for (sqtd = ex->sqtdstart; sqtd != lsqtd->nextqtd; sqtd =sqtd->nextqtd) { - nstatus = le32toh(sqtd->qtd.qtd_status); + nstatus = hc32toh(sc, sqtd->qtd.qtd_status); if (nstatus & EHCI_QTD_ACTIVE) break; @@ -1001,24 +992,11 @@ ehci_idone(struct ehci_xfer *ex) "status=0x%x\n", xfer->length, actlen, cerr, status)); xfer->actlen = actlen; if ((status & EHCI_QTD_HALTED) != 0) { -#ifdef EHCI_DEBUG - char sbuf[128]; - - bitmask_snprintf((u_int32_t)status, - "\20\7HALTED\6BUFERR\5BABBLE\4XACTERR" - "\3MISSED\2SPLIT\1PING", sbuf, sizeof(sbuf)); - DPRINTFN(2, - ("ehci_idone: error, addr=%d, endpt=0x%02x, " - "status 0x%s\n", + ("ehci_idone: error, addr=%d, endpt=0x%02x, status %b\n", xfer->pipe->device->address, xfer->pipe->endpoint->edesc->bEndpointAddress, - sbuf)); - if (ehcidebug > 2) { - ehci_dump_sqh(epipe->sqh); - ehci_dump_sqtds(ex->sqtdstart); - } -#endif + status, EHCI_QTD_STATUS_BITS)); if ((status & EHCI_QTD_BABBLE) == 0 && cerr > 0) xfer->status = USBD_STALLED; else @@ -1026,6 +1004,12 @@ ehci_idone(struct ehci_xfer *ex) } else { xfer->status = USBD_NORMAL_COMPLETION; } +#ifdef EHCI_DEBUG + if (ehcidebug > 2) { + ehci_dump_sqh(sc, epipe->sqh); + ehci_dump_sqtds(sc, ex->sqtdstart); + } +#endif end: /* XXX transfer_complete memcpys out transfer data (for in endpoints) * during this call, before methods->done is called: dma sync required @@ -1102,12 +1086,6 @@ ehci_detach(struct ehci_softc *sc, int flags) (void) ehci_hcreset(sc); callout_stop(&sc->sc_tmo_intrlist); -#if defined(__NetBSD__) || defined(__OpenBSD__) - if (sc->sc_powerhook != NULL) - powerhook_disestablish(sc->sc_powerhook); - if (sc->sc_shutdownhook != NULL) - shutdownhook_disestablish(sc->sc_shutdownhook); -#endif usb_delay_ms(&sc->sc_bus, 300); /* XXX let stray task complete */ usb_freemem(&sc->sc_bus, &sc->sc_fldma); @@ -1337,6 +1315,7 @@ static void ehci_device_clear_toggle(usbd_pipe_handle pipe) { struct ehci_pipe *epipe = (struct ehci_pipe *)pipe; + ehci_softc_t *sc = (ehci_softc_t *)epipe->pipe.device->bus; DPRINTF(("ehci_device_clear_toggle: epipe=%p status=0x%x\n", epipe, epipe->sqh->qh.qh_qtd.qtd_status)); @@ -1345,9 +1324,9 @@ ehci_device_clear_toggle(usbd_pipe_handle pipe) usbd_dump_pipe(pipe); #endif KASSERT((epipe->sqh->qh.qh_qtd.qtd_status & - htole32(EHCI_QTD_ACTIVE)) == 0, + htohc32(sc, EHCI_QTD_ACTIVE)) == 0, ("ehci_device_clear_toggle: queue active")); - epipe->sqh->qh.qh_qtd.qtd_status &= htole32(~EHCI_QTD_TOGGLE_MASK); + epipe->sqh->qh.qh_qtd.qtd_status &= htohc32(sc, ~EHCI_QTD_TOGGLE_MASK); } static void @@ -1355,178 +1334,6 @@ ehci_noop(usbd_pipe_handle pipe) { } -#ifdef EHCI_DEBUG -void -ehci_dump_regs(ehci_softc_t *sc) -{ - int i; - printf("cmd=0x%08x, sts=0x%08x, ien=0x%08x\n", - EOREAD4(sc, EHCI_USBCMD), - EOREAD4(sc, EHCI_USBSTS), - EOREAD4(sc, EHCI_USBINTR)); - printf("frindex=0x%08x ctrdsegm=0x%08x periodic=0x%08x async=0x%08x\n", - EOREAD4(sc, EHCI_FRINDEX), - EOREAD4(sc, EHCI_CTRLDSSEGMENT), - EOREAD4(sc, EHCI_PERIODICLISTBASE), - EOREAD4(sc, EHCI_ASYNCLISTADDR)); - for (i = 1; i <= sc->sc_noport; i++) - printf("port %d status=0x%08x\n", i, - EOREAD4(sc, EHCI_PORTSC(i))); -} - -/* - * Unused function - this is meant to be called from a kernel - * debugger. - */ -void -ehci_dump() -{ - ehci_dump_regs(theehci); -} - -void -ehci_dump_link(ehci_link_t link, int type) -{ - link = le32toh(link); - printf("0x%08x", link); - if (link & EHCI_LINK_TERMINATE) - printf("<T>"); - else { - printf("<"); - if (type) { - switch (EHCI_LINK_TYPE(link)) { - case EHCI_LINK_ITD: printf("ITD"); break; - case EHCI_LINK_QH: printf("QH"); break; - case EHCI_LINK_SITD: printf("SITD"); break; - case EHCI_LINK_FSTN: printf("FSTN"); break; - } - } - printf(">"); - } -} - -void -ehci_dump_sqtds(ehci_soft_qtd_t *sqtd) -{ - int i; - u_int32_t stop; - - stop = 0; - for (i = 0; sqtd && i < 20 && !stop; sqtd = sqtd->nextqtd, i++) { - ehci_dump_sqtd(sqtd); - stop = sqtd->qtd.qtd_next & htole32(EHCI_LINK_TERMINATE); - } - if (sqtd) - printf("dump aborted, too many TDs\n"); -} - -void -ehci_dump_sqtd(ehci_soft_qtd_t *sqtd) -{ - printf("QTD(%p) at 0x%08x:\n", sqtd, sqtd->physaddr); - ehci_dump_qtd(&sqtd->qtd); -} - -void -ehci_dump_qtd(ehci_qtd_t *qtd) -{ - u_int32_t s; - char sbuf[128]; - - printf(" next="); ehci_dump_link(qtd->qtd_next, 0); - printf(" altnext="); ehci_dump_link(qtd->qtd_altnext, 0); - printf("\n"); - s = le32toh(qtd->qtd_status); - bitmask_snprintf(EHCI_QTD_GET_STATUS(s), - "\20\10ACTIVE\7HALTED\6BUFERR\5BABBLE\4XACTERR" - "\3MISSED\2SPLIT\1PING", sbuf, sizeof(sbuf)); - printf(" status=0x%08x: toggle=%d bytes=0x%x ioc=%d c_page=0x%x\n", - s, EHCI_QTD_GET_TOGGLE(s), EHCI_QTD_GET_BYTES(s), - EHCI_QTD_GET_IOC(s), EHCI_QTD_GET_C_PAGE(s)); - printf(" cerr=%d pid=%d stat=0x%s\n", EHCI_QTD_GET_CERR(s), - EHCI_QTD_GET_PID(s), sbuf); - for (s = 0; s < 5; s++) - printf(" buffer[%d]=0x%08x\n", s, le32toh(qtd->qtd_buffer[s])); -} - -void -ehci_dump_sqh(ehci_soft_qh_t *sqh) -{ - ehci_qh_t *qh = &sqh->qh; - u_int32_t endp, endphub; - - printf("QH(%p) at 0x%08x:\n", sqh, sqh->physaddr); - printf(" sqtd=%p inactivesqtd=%p\n", sqh->sqtd, sqh->inactivesqtd); - printf(" link="); ehci_dump_link(qh->qh_link, 1); printf("\n"); - endp = le32toh(qh->qh_endp); - printf(" endp=0x%08x\n", endp); - printf(" addr=0x%02x inact=%d endpt=%d eps=%d dtc=%d hrecl=%d\n", - EHCI_QH_GET_ADDR(endp), EHCI_QH_GET_INACT(endp), - EHCI_QH_GET_ENDPT(endp), EHCI_QH_GET_EPS(endp), - EHCI_QH_GET_DTC(endp), EHCI_QH_GET_HRECL(endp)); - printf(" mpl=0x%x ctl=%d nrl=%d\n", - EHCI_QH_GET_MPL(endp), EHCI_QH_GET_CTL(endp), - EHCI_QH_GET_NRL(endp)); - endphub = le32toh(qh->qh_endphub); - printf(" endphub=0x%08x\n", endphub); - printf(" smask=0x%02x cmask=0x%02x huba=0x%02x port=%d mult=%d\n", - EHCI_QH_GET_SMASK(endphub), EHCI_QH_GET_CMASK(endphub), - EHCI_QH_GET_HUBA(endphub), EHCI_QH_GET_PORT(endphub), - EHCI_QH_GET_MULT(endphub)); - printf(" curqtd="); ehci_dump_link(qh->qh_curqtd, 0); printf("\n"); - printf("Overlay qTD:\n"); - ehci_dump_qtd(&qh->qh_qtd); -} - -#ifdef notyet -void -ehci_dump_itd(struct ehci_soft_itd *itd) -{ - ehci_isoc_trans_t t; - ehci_isoc_bufr_ptr_t b, b2, b3; - int i; - - printf("ITD: next phys=%X\n", itd->itd.itd_next); - - for (i = 0; i < 8;i++) { - t = le32toh(itd->itd.itd_ctl[i]); - printf("ITDctl %d: stat=%X len=%X ioc=%X pg=%X offs=%X\n", i, - EHCI_ITD_GET_STATUS(t), EHCI_ITD_GET_LEN(t), - EHCI_ITD_GET_IOC(t), EHCI_ITD_GET_PG(t), - EHCI_ITD_GET_OFFS(t)); - } - printf("ITDbufr: "); - for (i = 0; i < 7; i++) - printf("%X,", EHCI_ITD_GET_BPTR(le32toh(itd->itd.itd_bufr[i]))); - - b = le32toh(itd->itd.itd_bufr[0]); - b2 = le32toh(itd->itd.itd_bufr[1]); - b3 = le32toh(itd->itd.itd_bufr[2]); - printf("\nep=%X daddr=%X dir=%d maxpkt=%X multi=%X\n", - EHCI_ITD_GET_EP(b), EHCI_ITD_GET_DADDR(b), EHCI_ITD_GET_DIR(b2), - EHCI_ITD_GET_MAXPKT(b2), EHCI_ITD_GET_MULTI(b3)); -} - -void -ehci_dump_sitd(struct ehci_soft_itd *itd) -{ - printf("SITD %p next=%p prev=%p xfernext=%p physaddr=%X slot=%d\n", - itd, itd->u.frame_list.next, itd->u.frame_list.prev, - itd->xfer_next, itd->physaddr, itd->slot); -} -#endif - -#ifdef DIAGNOSTIC -void -ehci_dump_exfer(struct ehci_xfer *ex) -{ - printf("ehci_dump_exfer: ex=%p sqtdstart=%p end=%p itdstart=%p " - "end=%p isdone=%d\n", ex, ex->sqtdstart, ex->sqtdend, ex->itdstart, - ex->itdend, ex->isdone); -} -#endif -#endif - usbd_status ehci_open(usbd_pipe_handle pipe) { @@ -1542,8 +1349,8 @@ ehci_open(usbd_pipe_handle pipe) int ival, speed, naks; int hshubaddr, hshubport; - DPRINTFN(1, ("ehci_open: pipe=%p, addr=%d, endpt=%d (%d)\n", - pipe, addr, ed->bEndpointAddress, sc->sc_addr)); + DPRINTFN(1, ("ehci_open: pipe=%p, xfertype=%d, addr=%d, endpt=%d (%d)\n", + pipe, addr, ed->bEndpointAddress, sc->sc_addr, xfertype)); if (dev->myhsport) { hshubaddr = dev->myhsport->parent->address; @@ -1595,7 +1402,7 @@ ehci_open(usbd_pipe_handle pipe) if (sqh == NULL) goto bad0; /* qh_link filled when the QH is added */ - sqh->qh.qh_endp = htole32( + sqh->qh.qh_endp = htohc32(sc, EHCI_QH_SET_ADDR(addr) | EHCI_QH_SET_ENDPT(UE_GET_ADDR(ed->bEndpointAddress)) | EHCI_QH_SET_EPS(speed) | @@ -1605,17 +1412,17 @@ ehci_open(usbd_pipe_handle pipe) EHCI_QH_CTL : 0) | EHCI_QH_SET_NRL(naks) ); - sqh->qh.qh_endphub = htole32( + sqh->qh.qh_endphub = htohc32(sc, EHCI_QH_SET_MULT(1) | EHCI_QH_SET_HUBA(hshubaddr) | EHCI_QH_SET_PORT(hshubport) | EHCI_QH_SET_CMASK(0x1c) | EHCI_QH_SET_SMASK(xfertype == UE_INTERRUPT ? 0x01 : 0) ); - sqh->qh.qh_curqtd = EHCI_NULL; + sqh->qh.qh_curqtd = EHCI_NULL(sc); /* The overlay qTD was already set up by ehci_alloc_sqh(). */ sqh->qh.qh_qtd.qtd_status = - htole32(EHCI_QTD_SET_TOGGLE(pipe->endpoint->savedtoggle)); + htohc32(sc, EHCI_QTD_SET_TOGGLE(pipe->endpoint->savedtoggle)); epipe->sqh = sqh; } else { sqh = NULL; @@ -1633,13 +1440,13 @@ ehci_open(usbd_pipe_handle pipe) goto bad1; pipe->methods = &ehci_device_ctrl_methods; s = splusb(); - ehci_add_qh(sqh, sc->sc_async_head); + ehci_add_qh(sc, sqh, sc->sc_async_head); splx(s); break; case UE_BULK: pipe->methods = &ehci_device_bulk_methods; s = splusb(); - ehci_add_qh(sqh, sc->sc_async_head); + ehci_add_qh(sc, sqh, sc->sc_async_head); splx(s); break; case UE_INTERRUPT: @@ -1683,7 +1490,7 @@ ehci_open(usbd_pipe_handle pipe) * If in the intr schedule it may not. */ void -ehci_add_qh(ehci_soft_qh_t *sqh, ehci_soft_qh_t *head) +ehci_add_qh(ehci_softc_t *sc, ehci_soft_qh_t *sqh, ehci_soft_qh_t *head) { SPLUSBCHECK; @@ -1693,12 +1500,12 @@ ehci_add_qh(ehci_soft_qh_t *sqh, ehci_soft_qh_t *head) head->next = sqh; if (sqh->next) sqh->next->prev = sqh; - head->qh.qh_link = htole32(sqh->physaddr | EHCI_LINK_QH); + head->qh.qh_link = htohc32(sc, sqh->physaddr | EHCI_LINK_QH); #ifdef EHCI_DEBUG if (ehcidebug > 5) { printf("ehci_add_qh:\n"); - ehci_dump_sqh(sqh); + ehci_dump_sqh(sc, sqh); } #endif } @@ -1721,9 +1528,9 @@ ehci_rem_qh(ehci_softc_t *sc, ehci_soft_qh_t *sqh, ehci_soft_qh_t *head) /* Restart a QH following the addition of a qTD. */ void -ehci_activate_qh(ehci_soft_qh_t *sqh, ehci_soft_qtd_t *sqtd) +ehci_activate_qh(ehci_softc_t *sc, ehci_soft_qh_t *sqh, ehci_soft_qtd_t *sqtd) { - KASSERT((sqtd->qtd.qtd_status & htole32(EHCI_QTD_ACTIVE)) == 0, + KASSERT((sqtd->qtd.qtd_status & htohc32(sc, EHCI_QTD_ACTIVE)) == 0, ("ehci_activate_qh: already active")); /* @@ -1734,23 +1541,23 @@ ehci_activate_qh(ehci_soft_qh_t *sqh, ehci_soft_qtd_t *sqtd) */ if (sqtd == sqh->sqtd) { /* Check that the hardware is in the state we expect. */ - if (EHCI_LINK_ADDR(le32toh(sqh->qh.qh_qtd.qtd_next)) != + if (EHCI_LINK_ADDR(hc32toh(sc, sqh->qh.qh_qtd.qtd_next)) != sqtd->physaddr) { #ifdef EHCI_DEBUG printf("ehci_activate_qh: unexpected next ptr\n"); - ehci_dump_sqh(sqh); - ehci_dump_sqtds(sqh->sqtd); + ehci_dump_sqh(sc, sqh); + ehci_dump_sqtds(sc, sqh->sqtd); #endif - sqh->qh.qh_qtd.qtd_next = htole32(sqtd->physaddr); - sqh->qh.qh_qtd.qtd_altnext = EHCI_NULL; + sqh->qh.qh_qtd.qtd_next = htohc32(sc, sqtd->physaddr); + sqh->qh.qh_qtd.qtd_altnext = EHCI_NULL(sc); } /* Ensure the flags are correct. */ - sqh->qh.qh_qtd.qtd_status &= htole32(EHCI_QTD_PINGSTATE | + sqh->qh.qh_qtd.qtd_status &= htohc32(sc, EHCI_QTD_PINGSTATE | EHCI_QTD_TOGGLE_MASK); } /* Now activate the qTD. */ - sqtd->qtd.qtd_status |= htole32(EHCI_QTD_ACTIVE); + sqtd->qtd.qtd_status |= htohc32(sc, EHCI_QTD_ACTIVE); } /* @@ -2471,16 +2278,16 @@ ehci_alloc_sqh(ehci_softc_t *sc) sqtd = ehci_alloc_sqtd(sc); if (sqtd == NULL) return (NULL); - sqtd->qtd.qtd_status = htole32(0); - sqtd->qtd.qtd_next = EHCI_NULL; - sqtd->qtd.qtd_altnext = EHCI_NULL; + sqtd->qtd.qtd_status = htohc32(sc, 0); + sqtd->qtd.qtd_next = EHCI_NULL(sc); + sqtd->qtd.qtd_altnext = EHCI_NULL(sc); sqh = sc->sc_freeqhs; sc->sc_freeqhs = sqh->next; /* The overlay QTD should begin zeroed. */ - sqh->qh.qh_qtd.qtd_next = htole32(sqtd->physaddr); - sqh->qh.qh_qtd.qtd_altnext = EHCI_NULL; + sqh->qh.qh_qtd.qtd_next = htohc32(sc, sqtd->physaddr); + sqh->qh.qh_qtd.qtd_altnext = EHCI_NULL(sc); sqh->qh.qh_qtd.qtd_status = 0; for (i = 0; i < EHCI_QTD_NBUFFERS; i++) { sqh->qh.qh_qtd.qtd_buffer[i] = 0; @@ -2534,8 +2341,8 @@ ehci_alloc_sqtd(ehci_softc_t *sc) s = splusb(); sqtd = sc->sc_freeqtds; sc->sc_freeqtds = sqtd->nextqtd; - sqtd->qtd.qtd_next = EHCI_NULL; - sqtd->qtd.qtd_altnext = EHCI_NULL; + sqtd->qtd.qtd_next = EHCI_NULL(sc); + sqtd->qtd.qtd_altnext = EHCI_NULL(sc); sqtd->qtd.qtd_status = 0; for (i = 0; i < EHCI_QTD_NBUFFERS; i++) { sqtd->qtd.qtd_buffer[i] = 0; @@ -2632,7 +2439,7 @@ ehci_alloc_sqtd_chain(struct ehci_pipe *epipe, ehci_softc_t *sc, segoff = 0; } - cur->qtd.qtd_buffer[i] = htole32(dataphys); + cur->qtd.qtd_buffer[i] = htohc32(sc, dataphys); cur->qtd.qtd_buffer_hi[i] = 0; curlen += pagelen; @@ -2667,18 +2474,18 @@ ehci_alloc_sqtd_chain(struct ehci_pipe *epipe, ehci_softc_t *sc, next = ehci_alloc_sqtd(sc); if (next == NULL) goto nomem; - nextphys = htole32(next->physaddr); + nextphys = htohc32(sc, next->physaddr); } else { next = NULL; - nextphys = EHCI_NULL; + nextphys = EHCI_NULL(sc); } cur->nextqtd = next; cur->qtd.qtd_next = nextphys; /* Make sure to stop after a short transfer. */ - cur->qtd.qtd_altnext = htole32(newinactive->physaddr); + cur->qtd.qtd_altnext = htohc32(sc, newinactive->physaddr); cur->qtd.qtd_status = - htole32(qtdstatus | EHCI_QTD_SET_BYTES(curlen)); + htohc32(sc, qtdstatus | EHCI_QTD_SET_BYTES(curlen)); cur->xfer = xfer; cur->len = curlen; DPRINTFN(10,("ehci_alloc_sqtd_chain: curlen=%d\n", curlen)); @@ -2700,7 +2507,7 @@ ehci_alloc_sqtd_chain(struct ehci_pipe *epipe, ehci_softc_t *sc, offset += curlen; cur = next; } - cur->qtd.qtd_status |= htole32(EHCI_QTD_IOC); + cur->qtd.qtd_status |= htohc32(sc, EHCI_QTD_IOC); *ep = cur; DPRINTFN(10,("ehci_alloc_sqtd_chain: return sqtd=%p sqtdend=%p\n", @@ -2829,7 +2636,7 @@ ehci_close_pipe(usbd_pipe_handle pipe, ehci_soft_qh_t *head) ehci_rem_qh(sc, sqh, head); splx(s); pipe->endpoint->savedtoggle = - EHCI_QTD_GET_TOGGLE(le32toh(sqh->qh.qh_qtd.qtd_status)); + EHCI_QTD_GET_TOGGLE(hc32toh(sc, sqh->qh.qh_qtd.qtd_status)); ehci_free_sqh(sc, epipe->sqh); } @@ -2938,7 +2745,7 @@ ehci_abort_xfer(usbd_xfer_handle xfer, usbd_status status) * the aborting xfer. (If there is something past us). * Hardware and software. */ - cur = EHCI_LINK_ADDR(le32toh(sqh->qh.qh_curqtd)); + cur = EHCI_LINK_ADDR(hc32toh(sc, sqh->qh.qh_curqtd)); hit = 0; /* If they initially point here. */ @@ -2946,7 +2753,7 @@ ehci_abort_xfer(usbd_xfer_handle xfer, usbd_status status) /* We will change them to point here */ snext = exfer->sqtdend->nextqtd; - next = htole32(snext->physaddr); + next = htohc32(sc, snext->physaddr); /* * Now loop through any qTDs before us and keep track of the pointer @@ -2955,9 +2762,9 @@ ehci_abort_xfer(usbd_xfer_handle xfer, usbd_status status) sqtd = sqh->sqtd; while (sqtd && sqtd != exfer->sqtdstart) { hit |= (cur == sqtd->physaddr); - if (EHCI_LINK_ADDR(le32toh(sqtd->qtd.qtd_next)) == us) + if (EHCI_LINK_ADDR(hc32toh(sc, sqtd->qtd.qtd_next)) == us) sqtd->qtd.qtd_next = next; - if (EHCI_LINK_ADDR(le32toh(sqtd->qtd.qtd_altnext)) == us) + if (EHCI_LINK_ADDR(hc32toh(sc, sqtd->qtd.qtd_altnext)) == us) sqtd->qtd.qtd_altnext = next; sqtd = sqtd->nextqtd; } @@ -2986,17 +2793,17 @@ ehci_abort_xfer(usbd_xfer_handle xfer, usbd_status status) * that we are removing. */ if (hit) { - sqh->qh.qh_qtd.qtd_next = htole32(snext->physaddr); - sqh->qh.qh_qtd.qtd_altnext = EHCI_NULL; + sqh->qh.qh_qtd.qtd_next = htohc32(sc, snext->physaddr); + sqh->qh.qh_qtd.qtd_altnext = EHCI_NULL(sc); sqh->qh.qh_qtd.qtd_status &= - htole32(EHCI_QTD_TOGGLE_MASK); + htohc32(sc, EHCI_QTD_TOGGLE_MASK); for (i = 0; i < EHCI_QTD_NBUFFERS; i++) { sqh->qh.qh_qtd.qtd_buffer[i] = 0; sqh->qh.qh_qtd.qtd_buffer_hi[i] = 0; } } } - ehci_add_qh(sqh, psqh); + ehci_add_qh(sc, sqh, psqh); /* * Step 5: Execute callback. */ @@ -3090,9 +2897,9 @@ ehci_abort_isoc_xfer(usbd_xfer_handle xfer, usbd_status status) for (itd = exfer->itdstart; itd != NULL; itd = itd->xfer_next) { for (i = 0; i < 8; i++) { - trans_status = le32toh(itd->itd.itd_ctl[i]); + trans_status = hc32toh(sc, itd->itd.itd_ctl[i]); trans_status &= ~EHCI_ITD_ACTIVE; - itd->itd.itd_ctl[i] = htole32(trans_status); + itd->itd.itd_ctl[i] = htohc32(sc, trans_status); } } @@ -3269,9 +3076,10 @@ ehci_device_request(usbd_xfer_handle xfer) err = USBD_NOMEM; goto bad1; } - newinactive->qtd.qtd_status = htole32(0); - newinactive->qtd.qtd_next = EHCI_NULL; - newinactive->qtd.qtd_altnext = EHCI_NULL; + newinactive->qtd.qtd_status = htohc32(sc, 0); + newinactive->qtd.qtd_next = EHCI_NULL(sc); + newinactive->qtd.qtd_altnext = EHCI_NULL(sc); + stat = ehci_alloc_sqtd(sc); if (stat == NULL) { err = USBD_NOMEM; @@ -3291,10 +3099,10 @@ ehci_device_request(usbd_xfer_handle xfer) NULL, newinactive, &next, &end); if (err) goto bad3; - end->qtd.qtd_status &= htole32(~EHCI_QTD_IOC); + end->qtd.qtd_status &= htohc32(sc, ~EHCI_QTD_IOC); end->nextqtd = stat; - end->qtd.qtd_next = htole32(stat->physaddr); - end->qtd.qtd_altnext = htole32(newinactive->physaddr); + end->qtd.qtd_next = htohc32(sc, stat->physaddr); + end->qtd.qtd_altnext = htohc32(sc, newinactive->physaddr); } else { next = stat; } @@ -3302,21 +3110,21 @@ ehci_device_request(usbd_xfer_handle xfer) memcpy(KERNADDR(&epipe->u.ctl.reqdma, 0), req, sizeof *req); /* Clear toggle, and do not activate until complete */ - setup->qtd.qtd_status = htole32( + setup->qtd.qtd_status = htohc32(sc, EHCI_QTD_SET_PID(EHCI_QTD_PID_SETUP) | EHCI_QTD_SET_CERR(3) | EHCI_QTD_SET_TOGGLE(0) | EHCI_QTD_SET_BYTES(sizeof *req) ); - setup->qtd.qtd_buffer[0] = htole32(DMAADDR(&epipe->u.ctl.reqdma, 0)); + setup->qtd.qtd_buffer[0] = htohc32(sc, DMAADDR(&epipe->u.ctl.reqdma, 0)); setup->qtd.qtd_buffer_hi[0] = 0; setup->nextqtd = next; - setup->qtd.qtd_next = htole32(next->physaddr); - setup->qtd.qtd_altnext = htole32(newinactive->physaddr); + setup->qtd.qtd_next = htohc32(sc, next->physaddr); + setup->qtd.qtd_altnext = htohc32(sc, newinactive->physaddr); setup->xfer = xfer; setup->len = sizeof *req; - stat->qtd.qtd_status = htole32( + stat->qtd.qtd_status = htohc32(sc, EHCI_QTD_ACTIVE | EHCI_QTD_SET_PID(isread ? EHCI_QTD_PID_OUT : EHCI_QTD_PID_IN) | EHCI_QTD_SET_CERR(3) | @@ -3326,16 +3134,16 @@ ehci_device_request(usbd_xfer_handle xfer) stat->qtd.qtd_buffer[0] = 0; /* XXX not needed? */ stat->qtd.qtd_buffer_hi[0] = 0; /* XXX not needed? */ stat->nextqtd = newinactive; - stat->qtd.qtd_next = htole32(newinactive->physaddr); - stat->qtd.qtd_altnext = htole32(newinactive->physaddr); + stat->qtd.qtd_next = htohc32(sc, newinactive->physaddr); + stat->qtd.qtd_altnext = htohc32(sc, newinactive->physaddr); stat->xfer = xfer; stat->len = 0; #ifdef EHCI_DEBUG if (ehcidebug > 5) { DPRINTF(("ehci_device_request:\n")); - ehci_dump_sqh(sqh); - ehci_dump_sqtds(setup); + ehci_dump_sqh(sc, sqh); + ehci_dump_sqtds(sc, setup); } #endif @@ -3350,7 +3158,7 @@ ehci_device_request(usbd_xfer_handle xfer) /* Activate the new qTD in the QH list. */ s = splusb(); - ehci_activate_qh(sqh, setup); + ehci_activate_qh(sc, sqh, setup); if (xfer->timeout && !sc->sc_bus.use_polling) { callout_reset(&xfer->timeout_handle, MS_TO_TICKS(xfer->timeout), ehci_timeout, xfer); @@ -3365,9 +3173,9 @@ ehci_device_request(usbd_xfer_handle xfer) EOREAD4(sc, EHCI_USBSTS))); delay(10000); ehci_dump_regs(sc); - ehci_dump_sqh(sc->sc_async_head); - ehci_dump_sqh(sqh); - ehci_dump_sqtds(setup); + ehci_dump_sqh(sc, sc->sc_async_head); + ehci_dump_sqh(sc, sqh); + ehci_dump_sqtds(sc, setup); } #endif @@ -3441,9 +3249,9 @@ ehci_device_bulk_start(usbd_xfer_handle xfer) usb_transfer_complete(xfer); return (err); } - newinactive->qtd.qtd_status = htole32(0); - newinactive->qtd.qtd_next = EHCI_NULL; - newinactive->qtd.qtd_altnext = EHCI_NULL; + newinactive->qtd.qtd_status = htohc32(sc, 0); + newinactive->qtd.qtd_next = EHCI_NULL(sc); + newinactive->qtd.qtd_altnext = EHCI_NULL(sc); err = ehci_alloc_sqtd_chain(epipe, sc, len, isread, xfer, sqh->inactivesqtd, newinactive, &data, &dataend); if (err) { @@ -3454,15 +3262,15 @@ ehci_device_bulk_start(usbd_xfer_handle xfer) return (err); } dataend->nextqtd = newinactive; - dataend->qtd.qtd_next = htole32(newinactive->physaddr); - dataend->qtd.qtd_altnext = htole32(newinactive->physaddr); + dataend->qtd.qtd_next = htohc32(sc, newinactive->physaddr); + dataend->qtd.qtd_altnext = htohc32(sc, newinactive->physaddr); sqh->inactivesqtd = newinactive; #ifdef EHCI_DEBUG if (ehcidebug > 5) { DPRINTF(("ehci_device_bulk_start: data(1)\n")); - ehci_dump_sqh(sqh); - ehci_dump_sqtds(data); + ehci_dump_sqh(sc, sqh); + ehci_dump_sqtds(sc, data); } #endif @@ -3477,7 +3285,7 @@ ehci_device_bulk_start(usbd_xfer_handle xfer) #endif s = splusb(); - ehci_activate_qh(sqh, data); + ehci_activate_qh(sc, sqh, data); if (xfer->timeout && !sc->sc_bus.use_polling) { callout_reset(&xfer->timeout_handle, MS_TO_TICKS(xfer->timeout), ehci_timeout, xfer); @@ -3497,8 +3305,8 @@ ehci_device_bulk_start(usbd_xfer_handle xfer) ehci_dump_sqh(sc->sc_async_head); #endif printf("sqh:\n"); - ehci_dump_sqh(sqh); - ehci_dump_sqtds(data); + ehci_dump_sqh(sc, sqh); + ehci_dump_sqtds(sc, data); } #endif @@ -3566,7 +3374,7 @@ ehci_device_setintr(ehci_softc_t *sc, ehci_soft_qh_t *sqh, int ival) sqh->islot = islot; isp = &sc->sc_islots[islot]; - ehci_add_qh(sqh, isp->sqh); + ehci_add_qh(sc, sqh, isp->sqh); return (USBD_NORMAL_COMPLETION); } @@ -3627,9 +3435,9 @@ ehci_device_intr_start(usbd_xfer_handle xfer) usb_transfer_complete(xfer); return (err); } - newinactive->qtd.qtd_status = htole32(0); - newinactive->qtd.qtd_next = EHCI_NULL; - newinactive->qtd.qtd_altnext = EHCI_NULL; + newinactive->qtd.qtd_status = htohc32(sc, 0); + newinactive->qtd.qtd_next = EHCI_NULL(sc); + newinactive->qtd.qtd_altnext = EHCI_NULL(sc); err = ehci_alloc_sqtd_chain(epipe, sc, len, isread, xfer, sqh->inactivesqtd, newinactive, &data, &dataend); if (err) { @@ -3639,15 +3447,15 @@ ehci_device_intr_start(usbd_xfer_handle xfer) return (err); } dataend->nextqtd = newinactive; - dataend->qtd.qtd_next = htole32(newinactive->physaddr); - dataend->qtd.qtd_altnext = htole32(newinactive->physaddr); + dataend->qtd.qtd_next = htohc32(sc, newinactive->physaddr); + dataend->qtd.qtd_altnext = htohc32(sc, newinactive->physaddr); sqh->inactivesqtd = newinactive; #ifdef EHCI_DEBUG if (ehcidebug > 5) { DPRINTF(("ehci_device_intr_start: data(1)\n")); - ehci_dump_sqh(sqh); - ehci_dump_sqtds(data); + ehci_dump_sqh(sc, sqh); + ehci_dump_sqtds(sc, data); } #endif @@ -3662,7 +3470,7 @@ ehci_device_intr_start(usbd_xfer_handle xfer) #endif s = splusb(); - ehci_activate_qh(sqh, data); + ehci_activate_qh(sc, sqh, data); if (xfer->timeout && !sc->sc_bus.use_polling) { callout_reset(&xfer->timeout_handle, MS_TO_TICKS(xfer->timeout), ehci_timeout, xfer); @@ -3678,8 +3486,8 @@ ehci_device_intr_start(usbd_xfer_handle xfer) DPRINTF(("ehci_device_intr_start: data(3)\n")); ehci_dump_regs(sc); printf("sqh:\n"); - ehci_dump_sqh(sqh); - ehci_dump_sqtds(data); + ehci_dump_sqh(sc, sqh); + ehci_dump_sqtds(sc, data); } #endif @@ -3750,9 +3558,9 @@ ehci_device_intr_done(usbd_xfer_handle xfer) xfer->status = err; return; } - newinactive->qtd.qtd_status = htole32(0); - newinactive->qtd.qtd_next = EHCI_NULL; - newinactive->qtd.qtd_altnext = EHCI_NULL; + newinactive->qtd.qtd_status = htohc32(sc, 0); + newinactive->qtd.qtd_next = EHCI_NULL(sc); + newinactive->qtd.qtd_altnext = EHCI_NULL(sc); err = ehci_alloc_sqtd_chain(epipe, sc, len, isread, xfer, sqh->inactivesqtd, newinactive, &data, &dataend); if (err) { @@ -3761,8 +3569,8 @@ ehci_device_intr_done(usbd_xfer_handle xfer) return; } dataend->nextqtd = newinactive; - dataend->qtd.qtd_next = htole32(newinactive->physaddr); - dataend->qtd.qtd_altnext = htole32(newinactive->physaddr); + dataend->qtd.qtd_next = htohc32(sc, newinactive->physaddr); + dataend->qtd.qtd_altnext = htohc32(sc, newinactive->physaddr); sqh->inactivesqtd = newinactive; /* Set up interrupt info. */ @@ -3777,7 +3585,7 @@ ehci_device_intr_done(usbd_xfer_handle xfer) #endif s = splusb(); - ehci_activate_qh(sqh, data); + ehci_activate_qh(sc, sqh, data); if (xfer->timeout && !sc->sc_bus.use_polling) { callout_reset(&xfer->timeout_handle, MS_TO_TICKS(xfer->timeout), ehci_timeout, xfer); @@ -3911,7 +3719,7 @@ ehci_device_isoc_start(usbd_xfer_handle xfer) if (prev != NULL) { prev->itd.itd_next = - htole32(itd->physaddr | EHCI_LINK_ITD); + htohc32(sc, itd->physaddr | EHCI_LINK_ITD); prev->xfer_next = itd; } else { start = itd; @@ -3933,7 +3741,7 @@ ehci_device_isoc_start(usbd_xfer_handle xfer) * offset is. Works out how many pages that is. */ - itd->itd.itd_ctl[j] = htole32 ( EHCI_ITD_ACTIVE | + itd->itd.itd_ctl[j] = htohc32(sc, EHCI_ITD_ACTIVE | EHCI_ITD_SET_LEN(xfer->frlengths[trans_count]) | EHCI_ITD_SET_PG(addr) | EHCI_ITD_SET_OFFS(EHCI_PAGE_OFFSET(DMAADDR(dma_buf, @@ -3944,7 +3752,7 @@ ehci_device_isoc_start(usbd_xfer_handle xfer) trans_count++; if (trans_count >= xfer->nframes) { /*Set IOC*/ - itd->itd.itd_ctl[j] |= htole32(EHCI_ITD_IOC); + itd->itd.itd_ctl[j] |= htohc32(sc, EHCI_ITD_IOC); } } @@ -3967,7 +3775,7 @@ ehci_device_isoc_start(usbd_xfer_handle xfer) int page = DMAADDR(dma_buf, page_offs); page = EHCI_PAGE(page); itd->itd.itd_bufr[j] = - htole32(EHCI_ITD_SET_BPTR(page) | EHCI_LINK_ITD); + htohc32(sc, EHCI_ITD_SET_BPTR(page) | EHCI_LINK_ITD); } /* @@ -3975,7 +3783,7 @@ ehci_device_isoc_start(usbd_xfer_handle xfer) */ k = epipe->pipe.endpoint->edesc->bEndpointAddress; - itd->itd.itd_bufr[0] |= htole32( + itd->itd.itd_bufr[0] |= htohc32(sc, EHCI_ITD_SET_EP(UE_GET_ADDR(k)) | EHCI_ITD_SET_DADDR(epipe->pipe.device->address)); @@ -3983,12 +3791,12 @@ ehci_device_isoc_start(usbd_xfer_handle xfer) ? 1 : 0; j = UE_GET_SIZE( UGETW(epipe->pipe.endpoint->edesc->wMaxPacketSize)); - itd->itd.itd_bufr[1] |= htole32(EHCI_ITD_SET_DIR(k) | + itd->itd.itd_bufr[1] |= htohc32(sc, EHCI_ITD_SET_DIR(k) | EHCI_ITD_SET_MAXPKT(UE_GET_SIZE(j))); /* FIXME: handle invalid trans */ itd->itd.itd_bufr[2] |= - htole32(EHCI_ITD_SET_MULTI(UE_GET_TRANS(j)+1)); + htohc32(sc, EHCI_ITD_SET_MULTI(UE_GET_TRANS(j)+1)); prev = itd; } /* End of frame */ @@ -4034,9 +3842,9 @@ ehci_device_isoc_start(usbd_xfer_handle xfer) if (itd->itd.itd_next == 0) /* FIXME: frindex table gets initialized to NULL * or EHCI_NULL? */ - itd->itd.itd_next = htole32(EHCI_NULL); + itd->itd.itd_next = EHCI_NULL(sc); - sc->sc_flist[frindex] = htole32(EHCI_LINK_ITD | itd->physaddr); + sc->sc_flist[frindex] = htohc32(sc, EHCI_LINK_ITD | itd->physaddr); itd->u.frame_list.next = sc->sc_softitds[frindex]; sc->sc_softitds[frindex] = itd; diff --git a/sys/dev/usb/ehci_ddb.c b/sys/dev/usb/ehci_ddb.c new file mode 100644 index 0000000..3ebd130 --- /dev/null +++ b/sys/dev/usb/ehci_ddb.c @@ -0,0 +1,255 @@ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "opt_ddb.h" + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/endian.h> +#include <sys/bus.h> +#include <sys/lock.h> +#include <sys/lockmgr.h> + +#include <machine/bus.h> +#include <machine/endian.h> + +#include <dev/usb/usb.h> +#include <dev/usb/usbdi.h> +#include <dev/usb/usbdivar.h> + +#include <dev/usb/ehcireg.h> +#include <dev/usb/ehcivar.h> + +#ifdef DDB +#include <ddb/ddb.h> +#include <ddb/db_sym.h> +#else +#define db_printf printf +#endif + +extern ehci_softc_t *theehci; /* XXX */ + +void +ehci_dump_regs(ehci_softc_t *sc) +{ + int i; + db_printf("cmd=0x%08x, sts=0x%08x, ien=0x%08x\n", + EOREAD4(sc, EHCI_USBCMD), + EOREAD4(sc, EHCI_USBSTS), + EOREAD4(sc, EHCI_USBINTR)); + db_printf("frindex=0x%08x ctrdsegm=0x%08x periodic=0x%08x async=0x%08x\n", + EOREAD4(sc, EHCI_FRINDEX), + EOREAD4(sc, EHCI_CTRLDSSEGMENT), + EOREAD4(sc, EHCI_PERIODICLISTBASE), + EOREAD4(sc, EHCI_ASYNCLISTADDR)); + for (i = 1; i <= sc->sc_noport; i++) + db_printf("port %d status=0x%08x\n", i, + EOREAD4(sc, EHCI_PORTSC(i))); +} + +static void +ehci_dump_link(ehci_softc_t *sc, ehci_link_t link, int type) +{ + link = hc32toh(sc, link); + db_printf("0x%08x", link); + if (link & EHCI_LINK_TERMINATE) + db_printf("<T>"); + else { + db_printf("<"); + if (type) { + switch (EHCI_LINK_TYPE(link)) { + case EHCI_LINK_ITD: db_printf("ITD"); break; + case EHCI_LINK_QH: db_printf("QH"); break; + case EHCI_LINK_SITD: db_printf("SITD"); break; + case EHCI_LINK_FSTN: db_printf("FSTN"); break; + } + } + db_printf(">"); + } +} + +void +ehci_dump_sqtds(ehci_softc_t *sc, ehci_soft_qtd_t *sqtd) +{ + int i; + u_int32_t stop; + + stop = 0; + for (i = 0; sqtd && i < 20 && !stop; sqtd = sqtd->nextqtd, i++) { + ehci_dump_sqtd(sc, sqtd); + stop = sqtd->qtd.qtd_next & htohc32(sc, EHCI_LINK_TERMINATE); + } + if (sqtd) + db_printf("dump aborted, too many TDs\n"); +} + +void +ehci_dump_qtd(ehci_softc_t *sc, ehci_qtd_t *qtd) +{ + u_int32_t s; + + db_printf(" next="); ehci_dump_link(sc, qtd->qtd_next, 0); + db_printf(" altnext="); ehci_dump_link(sc, qtd->qtd_altnext, 0); + db_printf("\n"); + s = hc32toh(sc, qtd->qtd_status); + db_printf(" status=0x%08x: toggle=%d bytes=0x%x ioc=%d c_page=0x%x\n", + s, EHCI_QTD_GET_TOGGLE(s), EHCI_QTD_GET_BYTES(s), + EHCI_QTD_GET_IOC(s), EHCI_QTD_GET_C_PAGE(s)); + db_printf(" cerr=%d pid=%d stat=%b\n", EHCI_QTD_GET_CERR(s), + EHCI_QTD_GET_PID(s), + EHCI_QTD_GET_STATUS(s), EHCI_QTD_STATUS_BITS); + for (s = 0; s < 5; s++) + db_printf(" buffer[%d]=0x%08x\n", s, hc32toh(sc, qtd->qtd_buffer[s])); +} + +void +ehci_dump_sqtd(ehci_softc_t *sc, ehci_soft_qtd_t *sqtd) +{ + db_printf("QTD(%p) at 0x%08x:\n", sqtd, sqtd->physaddr); + ehci_dump_qtd(sc, &sqtd->qtd); +} + +void +ehci_dump_sqh(ehci_softc_t *sc, ehci_soft_qh_t *sqh) +{ + ehci_qh_t *qh = &sqh->qh; + u_int32_t endp, endphub; + + db_printf("QH(%p) at 0x%08x:\n", sqh, sqh->physaddr); + db_printf(" sqtd=%p inactivesqtd=%p\n", sqh->sqtd, sqh->inactivesqtd); + db_printf(" link="); ehci_dump_link(sc, qh->qh_link, 1); db_printf("\n"); + endp = hc32toh(sc, qh->qh_endp); + db_printf(" endp=0x%08x\n", endp); + db_printf(" addr=0x%02x inact=%d endpt=%d eps=%d dtc=%d hrecl=%d\n", + EHCI_QH_GET_ADDR(endp), EHCI_QH_GET_INACT(endp), + EHCI_QH_GET_ENDPT(endp), EHCI_QH_GET_EPS(endp), + EHCI_QH_GET_DTC(endp), EHCI_QH_GET_HRECL(endp)); + db_printf(" mpl=0x%x ctl=%d nrl=%d\n", + EHCI_QH_GET_MPL(endp), EHCI_QH_GET_CTL(endp), + EHCI_QH_GET_NRL(endp)); + endphub = hc32toh(sc, qh->qh_endphub); + db_printf(" endphub=0x%08x\n", endphub); + db_printf(" smask=0x%02x cmask=0x%02x huba=0x%02x port=%d mult=%d\n", + EHCI_QH_GET_SMASK(endphub), EHCI_QH_GET_CMASK(endphub), + EHCI_QH_GET_HUBA(endphub), EHCI_QH_GET_PORT(endphub), + EHCI_QH_GET_MULT(endphub)); + db_printf(" curqtd="); ehci_dump_link(sc, qh->qh_curqtd, 0); db_printf("\n"); + db_printf("Overlay qTD:\n"); + ehci_dump_qtd(sc, &qh->qh_qtd); +} + +void +ehci_dump_itd(ehci_softc_t *sc, struct ehci_soft_itd *itd) +{ + ehci_isoc_trans_t t; + ehci_isoc_bufr_ptr_t b, b2, b3; + int i; + + db_printf("ITD: next phys=%X\n", itd->itd.itd_next); + + for (i = 0; i < 8;i++) { + t = hc32toh(sc, itd->itd.itd_ctl[i]); + db_printf("ITDctl %d: stat=%X len=%X ioc=%X pg=%X offs=%X\n", i, + EHCI_ITD_GET_STATUS(t), EHCI_ITD_GET_LEN(t), + EHCI_ITD_GET_IOC(t), EHCI_ITD_GET_PG(t), + EHCI_ITD_GET_OFFS(t)); + } + db_printf("ITDbufr: "); + for (i = 0; i < 7; i++) + db_printf("%X,", EHCI_ITD_GET_BPTR(hc32toh(sc, itd->itd.itd_bufr[i]))); + + b = hc32toh(sc, itd->itd.itd_bufr[0]); + b2 = hc32toh(sc, itd->itd.itd_bufr[1]); + b3 = hc32toh(sc, itd->itd.itd_bufr[2]); + db_printf("\nep=%X daddr=%X dir=%d maxpkt=%X multi=%X\n", + EHCI_ITD_GET_EP(b), EHCI_ITD_GET_DADDR(b), EHCI_ITD_GET_DIR(b2), + EHCI_ITD_GET_MAXPKT(b2), EHCI_ITD_GET_MULTI(b3)); +} + +void +ehci_dump_sitd(ehci_softc_t *sc, struct ehci_soft_itd *itd) +{ + db_printf("SITD %p next=%p prev=%p xfernext=%p physaddr=%X slot=%d\n", + itd, itd->u.frame_list.next, itd->u.frame_list.prev, + itd->xfer_next, itd->physaddr, itd->slot); +} + +void +ehci_dump_exfer(struct ehci_xfer *ex) +{ +#ifdef DIAGNOSTIC + db_printf("%p: sqtdstart %p end %p itdstart %p end %p isdone %d\n", + ex, ex->sqtdstart, ex->sqtdend, ex->itdstart, + ex->itdend, ex->isdone); +#else + db_printf("%p: sqtdstart %p end %p itdstart %p end %p\n", + ex, ex->sqtdstart, ex->sqtdend, ex->itdstart, ex->itdend); +#endif +} + +#ifdef DDB +DB_SHOW_COMMAND(ehci, db_show_ehci) +{ + if (!have_addr) { + db_printf("usage: show ehci <addr>\n"); + return; + } + ehci_dump_regs((ehci_softc_t *) addr); +} + +DB_SHOW_COMMAND(ehci_sqtds, db_show_ehci_sqtds) +{ + if (!have_addr) { + db_printf("usage: show ehci_sqtds <addr>\n"); + return; + } + ehci_dump_sqtds(theehci, (ehci_soft_qtd_t *) addr); +} + +DB_SHOW_COMMAND(ehci_qtd, db_show_ehci_qtd) +{ + if (!have_addr) { + db_printf("usage: show ehci_qtd <addr>\n"); + return; + } + ehci_dump_qtd(theehci, (ehci_qtd_t *) addr); +} + +DB_SHOW_COMMAND(ehci_sqh, db_show_ehci_sqh) +{ + if (!have_addr) { + db_printf("usage: show ehci_sqh <addr>\n"); + return; + } + ehci_dump_sqh(theehci, (ehci_soft_qh_t *) addr); +} + +DB_SHOW_COMMAND(ehci_itd, db_show_ehci_itd) +{ + if (!have_addr) { + db_printf("usage: show ehci_itd <addr>\n"); + return; + } + ehci_dump_itd(theehci, (struct ehci_soft_itd *) addr); +} + +DB_SHOW_COMMAND(ehci_sitd, db_show_ehci_sitd) +{ + if (!have_addr) { + db_printf("usage: show ehci_sitd <addr>\n"); + return; + } + ehci_dump_itd(theehci, (struct ehci_soft_itd *) addr); +} + +DB_SHOW_COMMAND(ehci_xfer, db_show_ehci_xfer) +{ + if (!have_addr) { + db_printf("usage: show ehci_xfer <addr>\n"); + return; + } + ehci_dump_exfer((struct ehci_xfer *) addr); +} +#endif /* DDB */ diff --git a/sys/dev/usb/ehci_pci.c b/sys/dev/usb/ehci_pci.c index 46d8e40..1ae2228 100644 --- a/sys/dev/usb/ehci_pci.c +++ b/sys/dev/usb/ehci_pci.c @@ -61,8 +61,10 @@ __FBSDID("$FreeBSD$"); #include <sys/bus.h> #include <sys/queue.h> #include <sys/lockmgr.h> -#include <machine/bus.h> #include <sys/rman.h> +#include <sys/endian.h> + +#include <machine/bus.h> #include <machine/resource.h> #include <dev/pci/pcivar.h> diff --git a/sys/dev/usb/ehcireg.h b/sys/dev/usb/ehcireg.h index 071ed7f..3c0f5e7 100644 --- a/sys/dev/usb/ehcireg.h +++ b/sys/dev/usb/ehcireg.h @@ -173,6 +173,15 @@ #define EHCI_PS_CS 0x00000001 /* RO connect status */ #define EHCI_PS_CLEAR (EHCI_PS_OCC|EHCI_PS_PEC|EHCI_PS_CSC) +#define EHCI_USBMODE 0x68 /* RW USB Device mode register */ +#define EHCI_UM_CM 0x00000003 /* R/WO Controller Mode */ +#define EHCI_UM_CM_IDLE 0x0 /* Idle */ +#define EHCI_UM_CM_HOST 0x3 /* Host Controller */ +#define EHCI_UM_ES 0x00000004 /* R/WO Endian Select */ +#define EHCI_UM_ES_LE 0x0 /* Little-endian byte alignment */ +#define EHCI_UM_ES_BE 0x4 /* Big-endian byte alignment */ +#define EHCI_UM_SDIS 0x00000010 /* R/WO Stream Disable Mode */ + #define EHCI_PORT_RESET_COMPLETE 2 /* ms */ #define EHCI_FLALIGN_ALIGN 0x1000 @@ -279,6 +288,9 @@ typedef struct { } ehci_qtd_t; #define EHCI_QTD_ALIGN 32 +#define EHCI_QTD_STATUS_BITS \ + "\20\10ACTIVE\7HALTED\6BUFERR\5BABBLE\4XACTERR\3MISSED\2SPLIT\1PING" + /* Queue Head */ typedef struct { ehci_link_t qh_link; diff --git a/sys/dev/usb/ehcivar.h b/sys/dev/usb/ehcivar.h index 55dd196..bf8fb67 100644 --- a/sys/dev/usb/ehcivar.h +++ b/sys/dev/usb/ehcivar.h @@ -125,6 +125,7 @@ struct ehci_soft_islot { #define EHCI_SCFLG_SETMODE 0x0004 /* set bridge mode again after init (Marvell) */ #define EHCI_SCFLG_FORCESPEED 0x0008 /* force speed (Marvell) */ #define EHCI_SCFLG_NORESTERM 0x0010 /* don't terminate reset sequence (Marvell) */ +#define EHCI_SCFLG_BIGEDESC 0x0020 /* big-endian byte order descriptors */ typedef struct ehci_softc { struct usbd_bus sc_bus; /* base device */ @@ -132,22 +133,16 @@ typedef struct ehci_softc { bus_space_tag_t iot; bus_space_handle_t ioh; bus_size_t sc_size; -#if defined(__FreeBSD__) void *ih; struct resource *io_res; struct resource *irq_res; -#endif u_int sc_offs; /* offset to operational regs */ char sc_vendor[32]; /* vendor string for root hub */ int sc_id_vendor; /* vendor ID for root hub */ u_int32_t sc_cmd; /* shadow of cmd reg during suspend */ -#if defined(__NetBSD__) || defined(__OpenBSD__) - void *sc_powerhook; /* cookie from power hook */ - void *sc_shutdownhook; /* cookie from shutdown hook */ -#endif u_int sc_ncomp; u_int sc_npcomp; @@ -156,9 +151,6 @@ typedef struct ehci_softc { usb_dma_t sc_fldma; ehci_link_t *sc_flist; u_int sc_flsize; -#ifndef __FreeBSD__ - u_int sc_rand; /* XXX need proper intr scheduling */ -#endif struct ehci_soft_islot sc_islots[EHCI_INTRQHS]; @@ -192,9 +184,6 @@ typedef struct ehci_softc { struct callout sc_tmo_intrlist; char sc_dying; -#if defined(__NetBSD__) - struct usb_dma_reserve sc_dma_reserve; -#endif } ehci_softc_t; #define EREAD1(sc, a) bus_space_read_1((sc)->iot, (sc)->ioh, (a)) @@ -210,14 +199,48 @@ typedef struct ehci_softc { #define EOWRITE2(sc, a, x) bus_space_write_2((sc)->iot, (sc)->ioh, (sc)->sc_offs+(a), (x)) #define EOWRITE4(sc, a, x) bus_space_write_4((sc)->iot, (sc)->ioh, (sc)->sc_offs+(a), (x)) +/* + * Handle byte order conversion between host and ``host controller''. + * Typically the latter is little-endian but some controllers require + * big-endian in which case we may need to manually swap. + */ +static __inline uint32_t +htohc32(const struct ehci_softc *sc, const uint32_t v) +{ + return sc->sc_flags & EHCI_SCFLG_BIGEDESC ? htobe32(v) : htole32(v); +} + +static __inline uint16_t +htohc16(const struct ehci_softc *sc, const uint16_t v) +{ + return sc->sc_flags & EHCI_SCFLG_BIGEDESC ? htobe16(v) : htole16(v); +} + +static __inline uint32_t +hc32toh(const struct ehci_softc *sc, const uint32_t v) +{ + return sc->sc_flags & EHCI_SCFLG_BIGEDESC ? be32toh(v) : le32toh(v); +} + +static __inline uint16_t +hc16toh(const struct ehci_softc *sc, const uint16_t v) +{ + return sc->sc_flags & EHCI_SCFLG_BIGEDESC ? be16toh(v) : le16toh(v); +} + usbd_status ehci_init(ehci_softc_t *); int ehci_intr(void *); int ehci_detach(ehci_softc_t *, int); -#if defined(__NetBSD__) || defined(__OpenBSD__) -int ehci_activate(device_t, enum devact); -#endif void ehci_power(int state, void *priv); void ehci_shutdown(void *v); #define MS_TO_TICKS(ms) ((ms) * hz / 1000) +void ehci_dump_regs(ehci_softc_t *); +void ehci_dump_sqtds(ehci_softc_t *, ehci_soft_qtd_t *); +void ehci_dump_qtd(ehci_softc_t *, ehci_qtd_t *); +void ehci_dump_sqtd(ehci_softc_t *, ehci_soft_qtd_t *); +void ehci_dump_sqh(ehci_softc_t *, ehci_soft_qh_t *); +void ehci_dump_itd(ehci_softc_t *, struct ehci_soft_itd *); +void ehci_dump_sitd(ehci_softc_t *, struct ehci_soft_itd *); +void ehci_dump_exfer(struct ehci_xfer *); diff --git a/sys/dev/usb/usbdi.h b/sys/dev/usb/usbdi.h index d5bb035..ef59039 100644 --- a/sys/dev/usb/usbdi.h +++ b/sys/dev/usb/usbdi.h @@ -256,7 +256,8 @@ struct usb_attach_arg { #define USBD_SHOW_DEVICE_CLASS 0x1 #define USBD_SHOW_INTERFACE_CLASS 0x2 -int usbd_driver_load(module_t mod, int what, void *arg); +struct module; +int usbd_driver_load(struct module *mod, int what, void *arg); static inline int usb_get_port(device_t dev) |