Index: head/sys/mips/rmi/intr_machdep.c =================================================================== --- head/sys/mips/rmi/intr_machdep.c (revision 212101) +++ head/sys/mips/rmi/intr_machdep.c (revision 212102) @@ -1,250 +1,249 @@ /*- * Copyright (c) 2006-2009 RMI Corporation * Copyright (c) 2002-2004 Juli Mallett * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions, and the following disclaimer, * without modification, immediately at the beginning of the file. * 2. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include struct xlr_intrsrc { void (*busack)(int); /* Additional ack */ struct intr_event *ie; /* event corresponding to intr */ int irq; }; static struct xlr_intrsrc xlr_interrupts[XLR_MAX_INTR]; static mips_intrcnt_t mips_intr_counters[XLR_MAX_INTR]; static int intrcnt_index; void xlr_enable_irq(int irq) { + uint64_t eimr; - write_c0_eimr64(read_c0_eimr64() | (1ULL << irq)); + eimr = read_c0_eimr64(); + write_c0_eimr64(eimr | (1ULL << irq)); } void cpu_establish_softintr(const char *name, driver_filter_t * filt, void (*handler) (void *), void *arg, int irq, int flags, void **cookiep) { panic("Soft interrupts unsupported!\n"); } void cpu_establish_hardintr(const char *name, driver_filter_t * filt, void (*handler) (void *), void *arg, int irq, int flags, void **cookiep) { xlr_establish_intr(name, filt, handler, arg, irq, flags, cookiep, NULL); } static void xlr_post_filter(void *source) { struct xlr_intrsrc *src = source; if (src->busack) src->busack(src->irq); pic_ack(PIC_IRQ_TO_INTR(src->irq)); } static void xlr_pre_ithread(void *source) { struct xlr_intrsrc *src = source; if (src->busack) src->busack(src->irq); } static void xlr_post_ithread(void *source) { struct xlr_intrsrc *src = source; pic_ack(PIC_IRQ_TO_INTR(src->irq)); } void xlr_establish_intr(const char *name, driver_filter_t filt, driver_intr_t handler, void *arg, int irq, int flags, void **cookiep, void (*busack)(int)) { struct intr_event *ie; /* descriptor for the IRQ */ struct xlr_intrsrc *src = NULL; int errcode; if (irq < 0 || irq > XLR_MAX_INTR) panic("%s called for unknown hard intr %d", __func__, irq); /* * FIXME locking - not needed now, because we do this only on * startup from CPU0 */ - printf("[%s] Setup intr %d called on cpu %d (%d)\n", name, irq, - xlr_cpu_id(), PCPU_GET(cpuid)); - src = &xlr_interrupts[irq]; ie = src->ie; if (ie == NULL) { /* * PIC based interrupts need ack in PIC, and some SoC * components need additional acks (e.g. PCI) */ if (PIC_IRQ_IS_PICINTR(irq)) errcode = intr_event_create(&ie, src, 0, irq, xlr_pre_ithread, xlr_post_ithread, xlr_post_filter, NULL, "hard intr%d:", irq); else { if (filt == NULL) panic("Not supported - non filter percpu intr"); errcode = intr_event_create(&ie, src, 0, irq, NULL, NULL, NULL, NULL, "hard intr%d:", irq); } if (errcode) { printf("Could not create event for intr %d\n", irq); return; } src->irq = irq; src->busack = busack; src->ie = ie; } intr_event_add_handler(ie, name, filt, handler, arg, intr_priority(flags), flags, cookiep); xlr_enable_irq(irq); } void cpu_intr(struct trapframe *tf) { struct intr_event *ie; uint64_t eirr, eimr; int i; critical_enter(); /* find a list of enabled interrupts */ eirr = read_c0_eirr64(); eimr = read_c0_eimr64(); eirr &= eimr; if (eirr == 0) { critical_exit(); return; } /* * No need to clear the EIRR here as the handler writes to * compare which ACKs the interrupt. */ if (eirr & (1 << IRQ_TIMER)) { intr_event_handle(xlr_interrupts[IRQ_TIMER].ie, tf); critical_exit(); return; } /* FIXME sched pin >? LOCK>? */ for (i = sizeof(eirr) * 8 - 1; i >= 0; i--) { if ((eirr & (1ULL << i)) == 0) continue; ie = xlr_interrupts[i].ie; /* Don't account special IRQs */ switch (i) { case IRQ_IPI: case IRQ_MSGRING: break; default: mips_intrcnt_inc(mips_intr_counters[i]); } /* Ack the IRQ on the CPU */ write_c0_eirr64(1ULL << i); if (intr_event_handle(ie, tf) != 0) { printf("stray interrupt %d\n", i); } } critical_exit(); } void mips_intrcnt_setname(mips_intrcnt_t counter, const char *name) { int idx = counter - intrcnt; KASSERT(counter != NULL, ("mips_intrcnt_setname: NULL counter")); snprintf(intrnames + (MAXCOMLEN + 1) * idx, MAXCOMLEN + 1, "%-*s", MAXCOMLEN, name); } mips_intrcnt_t mips_intrcnt_create(const char* name) { mips_intrcnt_t counter = &intrcnt[intrcnt_index++]; mips_intrcnt_setname(counter, name); return counter; } void cpu_init_interrupts() { int i; char name[MAXCOMLEN + 1]; /* * Initialize all available vectors so spare IRQ * would show up in systat output */ for (i = 0; i < XLR_MAX_INTR; i++) { snprintf(name, MAXCOMLEN + 1, "int%d:", i); mips_intr_counters[i] = mips_intrcnt_create(name); } } Index: head/sys/mips/rmi/iodi.c =================================================================== --- head/sys/mips/rmi/iodi.c (revision 212101) +++ head/sys/mips/rmi/iodi.c (revision 212102) @@ -1,318 +1,319 @@ /*- * Copyright (c) 2003-2009 RMI Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of RMI Corporation, nor the names of its contributors, * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * RMI_BSD */ #include __FBSDID("$FreeBSD$"); #define __RMAN_RESOURCE_VISIBLE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* for DELAY */ #include #include #include #include #include #include #include #include #include extern bus_space_tag_t uart_bus_space_mem; static struct resource * iodi_alloc_resource(device_t, device_t, int, int *, u_long, u_long, u_long, u_int); static int iodi_activate_resource(device_t, device_t, int, int, struct resource *); static int iodi_setup_intr(device_t, device_t, struct resource *, int, driver_filter_t *, driver_intr_t *, void *, void **); struct iodi_softc *iodi_softc; /* There can be only one. */ /* * We will manage the Flash/PCMCIA devices in IODI for now. * The NOR flash, Compact flash etc. which can be connected on * various chip selects on the peripheral IO, should have a * separate bus later. */ static void bridge_pcmcia_ack(int irq) { xlr_reg_t *mmio = xlr_io_mmio(XLR_IO_FLASH_OFFSET); xlr_write_reg(mmio, 0x60, 0xffffffff); } static int iodi_setup_intr(device_t dev, device_t child, - struct resource *ires, int flags, driver_filter_t * filt, + struct resource *ires, int flags, driver_filter_t *filt, driver_intr_t *intr, void *arg, void **cookiep) { const char *name = device_get_name(child); if (strcmp(name, "uart") == 0) { /* FIXME uart 1? */ cpu_establish_hardintr("uart", filt, intr, arg, PIC_UART_0_IRQ, flags, cookiep); pic_setup_intr(PIC_IRT_UART_0_INDEX, PIC_UART_0_IRQ, 0x1, 0); } else if (strcmp(name, "rge") == 0 || strcmp(name, "nlge") == 0) { int irq; /* This is a hack to pass in the irq */ irq = (intptr_t)ires->__r_i; cpu_establish_hardintr("rge", filt, intr, arg, irq, flags, cookiep); pic_setup_intr(irq - PIC_IRQ_BASE, irq, 0x1, 0); } else if (strcmp(name, "ehci") == 0) { cpu_establish_hardintr("ehci", filt, intr, arg, PIC_USB_IRQ, flags, cookiep); pic_setup_intr(PIC_USB_IRQ - PIC_IRQ_BASE, PIC_USB_IRQ, 0x1, 0); } else if (strcmp(name, "ata") == 0) { xlr_establish_intr("ata", filt, intr, arg, PIC_PCMCIA_IRQ, flags, cookiep, bridge_pcmcia_ack); pic_setup_intr(PIC_PCMCIA_IRQ - PIC_IRQ_BASE, PIC_PCMCIA_IRQ, 0x1, 0); } return (0); } static struct resource * iodi_alloc_resource(device_t bus, device_t child, int type, int *rid, u_long start, u_long end, u_long count, u_int flags) { struct resource *res = malloc(sizeof(*res), M_DEVBUF, M_WAITOK); + const char *name = device_get_name(child); int unit; #ifdef DEBUG switch (type) { case SYS_RES_IRQ: device_printf(bus, "IRQ resource - for %s %lx-%lx\n", device_get_nameunit(child), start, end); break; case SYS_RES_IOPORT: device_printf(bus, "IOPORT resource - for %s %lx-%lx\n", device_get_nameunit(child), start, end); break; case SYS_RES_MEMORY: device_printf(bus, "MEMORY resource - for %s %lx-%lx\n", device_get_nameunit(child), start, end); break; } #endif - if (strcmp(device_get_name(child), "uart") == 0) { + if (strcmp(name, "uart") == 0) { if ((unit = device_get_unit(child)) == 0) { /* uart 0 */ res->r_bushandle = (xlr_io_base + XLR_IO_UART_0_OFFSET); } else if (unit == 1) { res->r_bushandle = (xlr_io_base + XLR_IO_UART_1_OFFSET); } else printf("%s: Unknown uart unit\n", __FUNCTION__); res->r_bustag = uart_bus_space_mem; - } else if (strcmp(device_get_name(child), "ehci") == 0) { + } else if (strcmp(name, "ehci") == 0) { res->r_bushandle = MIPS_PHYS_TO_KSEG1(0x1ef24000); res->r_bustag = rmi_pci_bus_space; - } else if (strcmp(device_get_name(child), "cfi") == 0) { + } else if (strcmp(name, "cfi") == 0) { res->r_bushandle = MIPS_PHYS_TO_KSEG1(0x1c000000); res->r_bustag = 0; - } else if (strcmp(device_get_name(child), "ata") == 0) { + } else if (strcmp(name, "ata") == 0) { res->r_bushandle = MIPS_PHYS_TO_KSEG1(0x1d000000); res->r_bustag = rmi_pci_bus_space; /* byte swapping (not really PCI) */ } /* res->r_start = *rid; */ return (res); } static int iodi_activate_resource(device_t bus, device_t child, int type, int rid, struct resource *r) { return (0); } /* prototypes */ static int iodi_probe(device_t); static int iodi_attach(device_t); static int iodi_detach(device_t); static void iodi_identify(driver_t *, device_t); int iodi_probe(device_t dev) { return 0; } void iodi_identify(driver_t * driver, device_t parent) { BUS_ADD_CHILD(parent, 0, "iodi", 0); } int iodi_attach(device_t dev) { device_t tmpd; int i; /* * Attach each devices */ device_add_child(dev, "uart", 0); device_add_child(dev, "xlr_i2c", 0); device_add_child(dev, "pcib", 0); if (xlr_board_info.usb) device_add_child(dev, "ehci", 0); if (xlr_board_info.cfi) device_add_child(dev, "cfi", 0); if (xlr_board_info.ata) device_add_child(dev, "ata", 0); if (xlr_board_info.gmac_block[0].enabled) { tmpd = device_add_child(dev, "rge", 0); device_set_ivars(tmpd, &xlr_board_info.gmac_block[0]); tmpd = device_add_child(dev, "rge", 1); device_set_ivars(tmpd, &xlr_board_info.gmac_block[0]); tmpd = device_add_child(dev, "rge", 2); device_set_ivars(tmpd, &xlr_board_info.gmac_block[0]); tmpd = device_add_child(dev, "rge", 3); device_set_ivars(tmpd, &xlr_board_info.gmac_block[0]); } if (xlr_board_info.gmac_block[1].enabled) { if (xlr_board_info.gmac_block[1].type == XLR_GMAC) { tmpd = device_add_child(dev, "rge", 4); device_set_ivars(tmpd, &xlr_board_info.gmac_block[1]); tmpd = device_add_child(dev, "rge", 5); device_set_ivars(tmpd, &xlr_board_info.gmac_block[1]); if (xlr_board_info.gmac_block[1].enabled & 0x4) { tmpd = device_add_child(dev, "rge", 6); device_set_ivars(tmpd, &xlr_board_info.gmac_block[1]); } if (xlr_board_info.gmac_block[1].enabled & 0x8) { tmpd = device_add_child(dev, "rge", 7); device_set_ivars(tmpd, &xlr_board_info.gmac_block[1]); } } else if (xlr_board_info.gmac_block[1].type == XLR_XGMAC) { #if 0 /* XGMAC not yet */ tmpd = device_add_child(dev, "rge", 4); device_set_ivars(tmpd, &xlr_board_info.gmac_block[1]); tmpd = device_add_child(dev, "rge", 5); device_set_ivars(tmpd, &xlr_board_info.gmac_block[1]); #endif } else device_printf(dev, "Unknown type of gmac 1\n"); } /* This is to add the new GMAC driver. The above adds the old driver, which has been retained for now as the new driver is stabilized. The new driver is enabled with "option nlge". Make sure that only one of rge or nlge is enabled in the conf file. */ for (i = 0; i < 3; i++) { if (xlr_board_info.gmac_block[i].enabled == 0) continue; tmpd = device_add_child(dev, "nlna", i); device_set_ivars(tmpd, &xlr_board_info.gmac_block[i]); } bus_generic_probe(dev); bus_generic_attach(dev); return 0; } int iodi_detach(device_t dev) { device_t nlna_dev; int error, i, ret; error = 0; ret = 0; for (i = 0; i < 3; i++) { nlna_dev = device_find_child(dev, "nlna", i); if (nlna_dev != NULL) error = bus_generic_detach(nlna_dev); if (error) ret = error; } return ret; } static device_method_t iodi_methods[] = { DEVMETHOD(device_probe, iodi_probe), DEVMETHOD(device_attach, iodi_attach), DEVMETHOD(device_detach, iodi_detach), DEVMETHOD(device_identify, iodi_identify), DEVMETHOD(bus_alloc_resource, iodi_alloc_resource), DEVMETHOD(bus_activate_resource, iodi_activate_resource), DEVMETHOD(bus_setup_intr, iodi_setup_intr), {0, 0}, }; static driver_t iodi_driver = { "iodi", iodi_methods, 1 /* no softc */ }; static devclass_t iodi_devclass; DRIVER_MODULE(iodi, nexus, iodi_driver, iodi_devclass, 0, 0); Index: head/sys/mips/rmi/pic.h =================================================================== --- head/sys/mips/rmi/pic.h (revision 212101) +++ head/sys/mips/rmi/pic.h (revision 212102) @@ -1,268 +1,268 @@ /*- * Copyright (c) 2003-2009 RMI Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of RMI Corporation, nor the names of its contributors, * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * RMI_BSD * $FreeBSD$ */ #ifndef _RMI_PIC_H_ #define _RMI_PIC_H_ #include #include #include #include #define PIC_IRT_WD_INDEX 0 #define PIC_IRT_TIMER_INDEX(i) (1 + (i)) #define PIC_IRT_UART_0_INDEX 9 #define PIC_IRT_UART_1_INDEX 10 #define PIC_IRT_I2C_0_INDEX 11 #define PIC_IRT_I2C_1_INDEX 12 #define PIC_IRT_PCMCIA_INDEX 13 #define PIC_IRT_GPIO_INDEX 14 #define PIC_IRT_HYPER_INDEX 15 #define PIC_IRT_PCIX_INDEX 16 #define PIC_IRT_GMAC0_INDEX 17 #define PIC_IRT_GMAC1_INDEX 18 #define PIC_IRT_GMAC2_INDEX 19 #define PIC_IRT_GMAC3_INDEX 20 #define PIC_IRT_XGS0_INDEX 21 #define PIC_IRT_XGS1_INDEX 22 #define PIC_IRT_HYPER_FATAL_INDEX 23 #define PIC_IRT_PCIX_FATAL_INDEX 24 #define PIC_IRT_BRIDGE_AERR_INDEX 25 #define PIC_IRT_BRIDGE_BERR_INDEX 26 #define PIC_IRT_BRIDGE_TB_INDEX 27 #define PIC_IRT_BRIDGE_AERR_NMI_INDEX 28 /* numbering for XLS */ #define PIC_IRT_BRIDGE_ERR_INDEX 25 #define PIC_IRT_PCIE_LINK0_INDEX 26 #define PIC_IRT_PCIE_LINK1_INDEX 27 #define PIC_IRT_PCIE_LINK2_INDEX 23 #define PIC_IRT_PCIE_LINK3_INDEX 24 #define PIC_IRT_PCIE_INT_INDEX 28 #define PIC_IRT_PCIE_FATAL_INDEX 29 #define PIC_IRT_GPIO_B_INDEX 30 #define PIC_IRT_USB_INDEX 31 #define PIC_NUM_IRTS 32 #define PIC_CLOCK_TIMER 7 #define PIC_CTRL 0x00 #define PIC_IPI 0x04 #define PIC_INT_ACK 0x06 #define WD_MAX_VAL_0 0x08 #define WD_MAX_VAL_1 0x09 #define WD_MASK_0 0x0a #define WD_MASK_1 0x0b #define WD_HEARBEAT_0 0x0c #define WD_HEARBEAT_1 0x0d #define PIC_IRT_0_BASE 0x40 #define PIC_IRT_1_BASE 0x80 #define PIC_TIMER_MAXVAL_0_BASE 0x100 #define PIC_TIMER_MAXVAL_1_BASE 0x110 #define PIC_TIMER_COUNT_0_BASE 0x120 #define PIC_TIMER_COUNT_1_BASE 0x130 #define PIC_IRT_0(picintr) (PIC_IRT_0_BASE + (picintr)) #define PIC_IRT_1(picintr) (PIC_IRT_1_BASE + (picintr)) #define PIC_TIMER_MAXVAL_0(i) (PIC_TIMER_MAXVAL_0_BASE + (i)) #define PIC_TIMER_MAXVAL_1(i) (PIC_TIMER_MAXVAL_1_BASE + (i)) #define PIC_TIMER_COUNT_0(i) (PIC_TIMER_COUNT_0_BASE + (i)) #define PIC_TIMER_COUNT_1(i) (PIC_TIMER_COUNT_0_BASE + (i)) #define PIC_TIMER_HZ 66000000U /* * We use a simple mapping form PIC interrupts to CPU IRQs. * The PIC interrupts 0-31 are mapped to CPU irq's 8-39. * this leaves the lower 0-7 for the cpu interrupts (like * count/compare, msgrng) and 40-63 for IPIs */ #define PIC_IRQ_BASE 8 #define PIC_INTR_TO_IRQ(i) (PIC_IRQ_BASE + (i)) #define PIC_IRQ_TO_INTR(i) ((i) - PIC_IRQ_BASE) #define PIC_WD_IRQ (PIC_IRQ_BASE + PIC_IRT_WD_INDEX) #define PIC_TIMER_IRQ(i) (PIC_IRQ_BASE + PIC_IRT_TIMER_INDEX(i)) #define PIC_CLOCK_IRQ PIC_TIMER_IRQ(PIC_CLOCK_TIMER) #define PIC_UART_0_IRQ (PIC_IRQ_BASE + PIC_IRT_UART_0_INDEX) #define PIC_UART_1_IRQ (PIC_IRQ_BASE + PIC_IRT_UART_1_INDEX) #define PIC_I2C_0_IRQ (PIC_IRQ_BASE + PIC_IRT_I2C_0_INDEX) #define PIC_I2C_1_IRQ (PIC_IRQ_BASE + PIC_IRT_I2C_1_INDEX) #define PIC_PCMCIA_IRQ (PIC_IRQ_BASE + PIC_IRT_PCMCIA_INDEX) #define PIC_GPIO_IRQ (PIC_IRQ_BASE + PIC_IRT_GPIO_INDEX) #define PIC_HYPER_IRQ (PIC_IRQ_BASE + PIC_IRT_HYPER_INDEX) #define PIC_PCIX_IRQ (PIC_IRQ_BASE + PIC_IRT_PCIX_INDEX) #define PIC_GMAC_0_IRQ (PIC_IRQ_BASE + PIC_IRT_GMAC0_INDEX) #define PIC_GMAC_1_IRQ (PIC_IRQ_BASE + PIC_IRT_GMAC1_INDEX) #define PIC_GMAC_2_IRQ (PIC_IRQ_BASE + PIC_IRT_GMAC2_INDEX) #define PIC_GMAC_3_IRQ (PIC_IRQ_BASE + PIC_IRT_GMAC3_INDEX) #define PIC_XGS_0_IRQ (PIC_IRQ_BASE + PIC_IRT_XGS0_INDEX) #define PIC_XGS_1_IRQ (PIC_IRQ_BASE + PIC_IRT_XGS1_INDEX) #define PIC_HYPER_FATAL_IRQ (PIC_IRQ_BASE + PIC_IRT_HYPER_FATAL_INDEX) #define PIC_PCIX_FATAL_IRQ (PIC_IRQ_BASE + PIC_IRT_PCIX_FATAL_INDEX) #define PIC_BRIDGE_AERR_IRQ (PIC_IRQ_BASE + PIC_IRT_BRIDGE_AERR_INDEX) #define PIC_BRIDGE_BERR_IRQ (PIC_IRQ_BASE + PIC_IRT_BRIDGE_BERR_INDEX) #define PIC_BRIDGE_TB_IRQ (PIC_IRQ_BASE + PIC_IRT_BRIDGE_TB_INDEX) #define PIC_BRIDGE_AERR_NMI_IRQ (PIC_IRQ_BASE + PIC_IRT_BRIDGE_AERR_NMI_INDEX) #define PIC_BRIDGE_ERR_IRQ (PIC_IRQ_BASE + PIC_IRT_BRIDGE_ERR_INDEX) #define PIC_PCIE_LINK0_IRQ (PIC_IRQ_BASE + PIC_IRT_PCIE_LINK0_INDEX) #define PIC_PCIE_LINK1_IRQ (PIC_IRQ_BASE + PIC_IRT_PCIE_LINK1_INDEX) #define PIC_PCIE_LINK2_IRQ (PIC_IRQ_BASE + PIC_IRT_PCIE_LINK2_INDEX) #define PIC_PCIE_LINK3_IRQ (PIC_IRQ_BASE + PIC_IRT_PCIE_LINK3_INDEX) #define PIC_PCIE_INT_IRQ (PIC_IRQ_BASE + PIC_IRT_PCIE_INT__INDEX) #define PIC_PCIE_FATAL_IRQ (PIC_IRQ_BASE + PIC_IRT_PCIE_FATAL_INDEX) #define PIC_GPIO_B_IRQ (PIC_IRQ_BASE + PIC_IRT_GPIO_B_INDEX) #define PIC_USB_IRQ (PIC_IRQ_BASE + PIC_IRT_USB_INDEX) #define PIC_IRQ_IS_PICINTR(irq) ((irq) >= PIC_IRQ_BASE && \ (irq) < PIC_IRQ_BASE + PIC_NUM_IRTS) #define PIC_IS_EDGE_TRIGGERED(i) ((i) >= PIC_IRT_TIMER_INDEX(0) && \ (i) <= PIC_IRT_TIMER_INDEX(7)) extern struct mtx xlr_pic_lock; static __inline uint32_t pic_read_control(void) { xlr_reg_t *mmio = xlr_io_mmio(XLR_IO_PIC_OFFSET); uint32_t reg; mtx_lock_spin(&xlr_pic_lock); xlr_read_reg(mmio, PIC_CTRL); mtx_unlock_spin(&xlr_pic_lock); return (reg); } static __inline void pic_write_control(uint32_t control) { xlr_reg_t *mmio = xlr_io_mmio(XLR_IO_PIC_OFFSET); mtx_lock_spin(&xlr_pic_lock); xlr_write_reg(mmio, PIC_CTRL, control); mtx_unlock_spin(&xlr_pic_lock); } static __inline void pic_update_control(__uint32_t control) { xlr_reg_t *mmio = xlr_io_mmio(XLR_IO_PIC_OFFSET); mtx_lock_spin(&xlr_pic_lock); xlr_write_reg(mmio, PIC_CTRL, (control | xlr_read_reg(mmio, PIC_CTRL))); mtx_unlock_spin(&xlr_pic_lock); } static __inline void pic_ack(int picintr) { xlr_reg_t *mmio = xlr_io_mmio(XLR_IO_PIC_OFFSET); - xlr_write_reg(mmio, PIC_INT_ACK, 1 << picintr); + xlr_write_reg(mmio, PIC_INT_ACK, 1U << picintr); } static __inline void pic_send_ipi(int cpu, int ipi) { xlr_reg_t *mmio = xlr_io_mmio(XLR_IO_PIC_OFFSET); int tid, pid; tid = cpu & 0x3; pid = (cpu >> 2) & 0x7; xlr_write_reg(mmio, PIC_IPI, (pid << 20) | (tid << 16) | ipi); } static __inline void pic_setup_intr(int picintr, int irq, uint32_t cpumask, int level) { xlr_reg_t *mmio = xlr_io_mmio(XLR_IO_PIC_OFFSET); mtx_lock_spin(&xlr_pic_lock); xlr_write_reg(mmio, PIC_IRT_0(picintr), cpumask); xlr_write_reg(mmio, PIC_IRT_1(picintr), ((1 << 31) | (level << 30) | (1 << 6) | irq)); mtx_unlock_spin(&xlr_pic_lock); } static __inline void pic_init_timer(int timer) { xlr_reg_t *mmio = xlr_io_mmio(XLR_IO_PIC_OFFSET); uint32_t val; mtx_lock_spin(&xlr_pic_lock); val = xlr_read_reg(mmio, PIC_CTRL); val |= (1 << (8 + timer)); xlr_write_reg(mmio, PIC_CTRL, val); mtx_unlock_spin(&xlr_pic_lock); } static __inline void pic_set_timer(int timer, uint64_t maxval) { xlr_reg_t *mmio = xlr_io_mmio(XLR_IO_PIC_OFFSET); xlr_write_reg(mmio, PIC_TIMER_MAXVAL_0(timer), (maxval & 0xffffffff)); xlr_write_reg(mmio, PIC_TIMER_MAXVAL_1(timer), (maxval >> 32) & 0xffffffff); } static __inline uint32_t pic_timer_count32(int timer) { xlr_reg_t *mmio = xlr_io_mmio(XLR_IO_PIC_OFFSET); return (xlr_read_reg(mmio, PIC_TIMER_COUNT_0(timer))); } /* * The timer can wrap 32 bits between the two reads, so we * need additional logic to detect that. */ static __inline uint64_t pic_timer_count(int timer) { xlr_reg_t *mmio = xlr_io_mmio(XLR_IO_PIC_OFFSET); uint32_t tu1, tu2, tl; tu1 = xlr_read_reg(mmio, PIC_TIMER_COUNT_1(timer)); tl = xlr_read_reg(mmio, PIC_TIMER_COUNT_0(timer)); tu2 = xlr_read_reg(mmio, PIC_TIMER_COUNT_1(timer)); if (tu2 != tu1) tl = xlr_read_reg(mmio, PIC_TIMER_COUNT_0(timer)); return (((uint64_t)tu2 << 32) | tl); } #endif /* _RMI_PIC_H_ */ Index: head/sys/mips/rmi/xlr_machdep.c =================================================================== --- head/sys/mips/rmi/xlr_machdep.c (revision 212101) +++ head/sys/mips/rmi/xlr_machdep.c (revision 212102) @@ -1,628 +1,631 @@ /*- * Copyright (c) 2006-2009 RMI Corporation * Copyright (c) 2002-2004 Juli Mallett * 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 AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include __FBSDID("$FreeBSD$"); #include "opt_ddb.h" #include #include #include #include #include #include #include #include #include #include #include #include /* cinit() */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include void mpwait(void); unsigned long xlr_io_base = (unsigned long)(DEFAULT_XLR_IO_BASE); /* 4KB static data aread to keep a copy of the bootload env until the dynamic kenv is setup */ char boot1_env[4096]; int rmi_spin_mutex_safe=0; struct mtx xlr_pic_lock; /* * Parameters from boot loader */ struct boot1_info xlr_boot1_info; int xlr_run_mode; int xlr_argc; int32_t *xlr_argv, *xlr_envp; uint64_t cpu_mask_info; uint32_t xlr_online_cpumask; uint32_t xlr_core_cpu_mask = 0x1; /* Core 0 thread 0 is always there */ int xlr_shtlb_enabled; int xlr_ncores; int xlr_threads_per_core; uint32_t xlr_hw_thread_mask; int xlr_cpuid_to_hwtid[MAXCPU]; int xlr_hwtid_to_cpuid[MAXCPU]; static void xlr_setup_mmu_split(void) { int mmu_setup; int val = 0; if (xlr_threads_per_core == 4 && xlr_shtlb_enabled == 0) return; /* no change from boot setup */ switch (xlr_threads_per_core) { case 1: val = 0; break; case 2: val = 2; break; case 4: val = 3; break; } mmu_setup = read_32bit_phnx_ctrl_reg(4, 0); mmu_setup = mmu_setup & ~0x06; mmu_setup |= (val << 1); /* turn on global mode */ if (xlr_shtlb_enabled) mmu_setup |= 0x01; write_32bit_phnx_ctrl_reg(4, 0, mmu_setup); } static void xlr_parse_mmu_options(void) { #ifdef notyet char *hw_env, *start, *end; #endif uint32_t cpu_map; uint8_t core0_thr_mask, core_thr_mask; int i, j, k; /* First check for the shared TLB setup */ xlr_shtlb_enabled = 0; #ifdef notyet /* * We don't support sharing TLB per core - TODO */ xlr_shtlb_enabled = 0; if ((hw_env = getenv("xlr.shtlb")) != NULL) { start = hw_env; tmp = strtoul(start, &end, 0); if (start != end) xlr_shtlb_enabled = (tmp != 0); else printf("Bad value for xlr.shtlb [%s]\n", hw_env); freeenv(hw_env); } #endif /* * XLR supports splitting the 64 TLB entries across one, two or four * threads (split mode). XLR also allows the 64 TLB entries to be shared * across all threads in the core using a global flag (shared TLB mode). * We will support 1/2/4 threads in split mode or shared mode. * */ xlr_ncores = 1; cpu_map = xlr_boot1_info.cpu_online_map; core0_thr_mask = cpu_map & 0xf; switch (core0_thr_mask) { case 1: xlr_threads_per_core = 1; break; case 3: xlr_threads_per_core = 2; break; case 0xf: xlr_threads_per_core = 4; break; default: goto unsupp; } /* Verify other cores CPU masks */ for (i = 1; i < XLR_MAX_CORES; i++) { core_thr_mask = (cpu_map >> (i*4)) & 0xf; if (core_thr_mask) { if (core_thr_mask != core0_thr_mask) goto unsupp; xlr_ncores++; } } /* setup hardware processor id to cpu id mapping */ xlr_hw_thread_mask = xlr_boot1_info.cpu_online_map; for (i = 0; i< MAXCPU; i++) xlr_cpuid_to_hwtid[i] = xlr_hwtid_to_cpuid [i] = -1; for (i = 0, k = 0; i < XLR_MAX_CORES; i++) { if (((cpu_map >> (i*4)) & 0xf) == 0) continue; for (j = 0; j < xlr_threads_per_core; j++) { xlr_cpuid_to_hwtid[k] = i*4 + j; xlr_hwtid_to_cpuid[i*4 + j] = k; k++; } } /* setup for the startup core */ xlr_setup_mmu_split(); return; unsupp: printf("ERROR : Unsupported CPU mask [use 1,2 or 4 threads per core].\n" "\tcore0 thread mask [%lx], boot cpu mask [%lx]\n" "\tUsing default, 16 TLB entries per CPU, split mode\n", (u_long)core0_thr_mask, (u_long)cpu_map); panic("Invalid CPU mask - halting.\n"); return; } static void xlr_set_boot_flags(void) { char *p; p = getenv("bootflags"); if (p == NULL) p = getenv("boot_flags"); /* old style */ if (p == NULL) return; for (; p && *p != '\0'; p++) { switch (*p) { case 'd': case 'D': boothowto |= RB_KDB; break; case 'g': case 'G': boothowto |= RB_GDB; break; case 'v': case 'V': boothowto |= RB_VERBOSE; break; case 's': /* single-user (default, supported for sanity) */ case 'S': boothowto |= RB_SINGLE; break; default: printf("Unrecognized boot flag '%c'.\n", *p); break; } } freeenv(p); return; } extern uint32_t _end; static void mips_init(void) { init_param1(); init_param2(physmem); mips_cpu_init(); + cpuinfo.cache_coherent_dma = TRUE; pmap_bootstrap(); #ifdef DDB kdb_init(); if (boothowto & RB_KDB) { kdb_enter("Boot flags requested debugger", NULL); } #endif mips_proc0_init(); mutex_init(); } u_int platform_get_timecount(struct timecounter *tc __unused) { return (0xffffffffU - pic_timer_count32(PIC_CLOCK_TIMER)); } static void xlr_pic_init(void) { struct timecounter pic_timecounter = { platform_get_timecount, /* get_timecount */ 0, /* no poll_pps */ ~0U, /* counter_mask */ PIC_TIMER_HZ, /* frequency */ "XLRPIC", /* name */ 2000, /* quality (adjusted in code) */ }; xlr_reg_t *mmio = xlr_io_mmio(XLR_IO_PIC_OFFSET); int i, level, irq; + write_c0_eimr64(0ULL); mtx_init(&xlr_pic_lock, "pic", NULL, MTX_SPIN); xlr_write_reg(mmio, PIC_CTRL, 0); /* Initialize all IRT entries */ for (i = 0; i < PIC_NUM_IRTS; i++) { irq = PIC_INTR_TO_IRQ(i); level = PIC_IS_EDGE_TRIGGERED(i); /* Bind all PIC irqs to cpu 0 */ xlr_write_reg(mmio, PIC_IRT_0(i), 0x01); /* * Use local scheduling and high polarity for all IRTs * Invalidate all IRTs, by default */ xlr_write_reg(mmio, PIC_IRT_1(i), (level << 30) | (1 << 6) | irq); } /* Setup timer 7 of PIC as a timestamp, no interrupts */ pic_init_timer(PIC_CLOCK_TIMER); pic_set_timer(PIC_CLOCK_TIMER, ~UINT64_C(0)); platform_timecounter = &pic_timecounter; } static void xlr_mem_init(void) { struct xlr_boot1_mem_map *boot_map; vm_size_t physsz = 0; int i, j; /* get physical memory info from boot loader */ boot_map = (struct xlr_boot1_mem_map *) (unsigned long)xlr_boot1_info.psb_mem_map; for (i = 0, j = 0; i < boot_map->num_entries; i++, j += 2) { if (boot_map->physmem_map[i].type == BOOT1_MEM_RAM) { if (j == 14) { printf("*** ERROR *** memory map too large ***\n"); break; } if (j == 0) { /* TODO FIXME */ /* start after kernel end */ phys_avail[0] = (vm_paddr_t) MIPS_KSEG0_TO_PHYS(&_end) + 0x20000; /* boot loader start */ /* HACK to Use bootloaders memory region */ /* TODO FIXME */ if (boot_map->physmem_map[0].size == 0x0c000000) { boot_map->physmem_map[0].size = 0x0ff00000; } phys_avail[1] = boot_map->physmem_map[0].addr + boot_map->physmem_map[0].size; printf("First segment: addr:%p -> %p \n", (void *)phys_avail[0], (void *)phys_avail[1]); } else { /* * Can't use this code yet, because most of the fixed allocations happen from * the biggest physical area. If we have more than 512M memory the kernel will try * to map from the second are which is not in KSEG0 and not mapped */ phys_avail[j] = (vm_paddr_t) boot_map->physmem_map[i].addr; phys_avail[j + 1] = phys_avail[j] + boot_map->physmem_map[i].size; if (phys_avail[j + 1] < phys_avail[j] ) { /* Houston we have an issue. Memory is * larger than possible. Its probably in * 64 bit > 4Gig and we are in 32 bit mode. */ phys_avail[j + 1] = 0xfffff000; printf("boot map size was %jx\n", (intmax_t)boot_map->physmem_map[i].size); boot_map->physmem_map[i].size = phys_avail[j + 1] - phys_avail[j]; printf("reduced to %jx\n", (intmax_t)boot_map->physmem_map[i].size); } printf("Next segment : addr:%p -> %p \n", (void *)phys_avail[j], (void *)phys_avail[j+1]); } physsz += boot_map->physmem_map[i].size; } } /* FIXME XLR TODO */ phys_avail[j] = phys_avail[j + 1] = 0; realmem = physmem = btoc(physsz); } void platform_start(__register_t a0 __unused, __register_t a1 __unused, __register_t a2 __unused, __register_t a3 __unused) { int i; #ifdef SMP uint32_t tmp; void (*wakeup) (void *, void *, unsigned int); #endif /* XXX FIXME the code below is not 64 bit clean */ /* Save boot loader and other stuff from scratch regs */ xlr_boot1_info = *(struct boot1_info *)(intptr_t)(int)read_c0_register32(MIPS_COP_0_OSSCRATCH, 0); cpu_mask_info = read_c0_register64(MIPS_COP_0_OSSCRATCH, 1); xlr_online_cpumask = read_c0_register32(MIPS_COP_0_OSSCRATCH, 2); xlr_run_mode = read_c0_register32(MIPS_COP_0_OSSCRATCH, 3); xlr_argc = read_c0_register32(MIPS_COP_0_OSSCRATCH, 4); /* * argv and envp are passed in array of 32bit pointers */ xlr_argv = (int32_t *)(intptr_t)(int)read_c0_register32(MIPS_COP_0_OSSCRATCH, 5); xlr_envp = (int32_t *)(intptr_t)(int)read_c0_register32(MIPS_COP_0_OSSCRATCH, 6); /* TODO: Verify the magic number here */ /* FIXMELATER: xlr_boot1_info.magic_number */ /* Initialize pcpu stuff */ mips_pcpu0_init(); /* initialize console so that we have printf */ boothowto |= (RB_SERIAL | RB_MULTIPLE); /* Use multiple consoles */ /* clockrate used by delay, so initialize it here */ cpu_clock = xlr_boot1_info.cpu_frequency / 1000000; /* * Note the time counter on CPU0 runs not at system clock speed, but * at PIC time counter speed (which is returned by * platform_get_frequency(). Thus we do not use * xlr_boot1_info.cpu_frequency here. */ mips_timer_early_init(xlr_boot1_info.cpu_frequency); /* Init console please */ cninit(); init_static_kenv(boot1_env, sizeof(boot1_env)); printf("Environment (from %d args):\n", xlr_argc - 1); if (xlr_argc == 1) printf("\tNone\n"); for (i = 1; i < xlr_argc; i++) { char *n, *arg; arg = (char *)(intptr_t)xlr_argv[i]; printf("\t%s\n", arg); n = strsep(&arg, "="); if (arg == NULL) setenv(n, "1"); else setenv(n, arg); } xlr_set_boot_flags(); xlr_parse_mmu_options(); xlr_mem_init(); /* Set up hz, among others. */ mips_init(); #ifdef SMP /* * If thread 0 of any core is not available then mark whole core as * not available */ tmp = xlr_boot1_info.cpu_online_map; for (i = 4; i < MAXCPU; i += 4) { if ((tmp & (0xf << i)) && !(tmp & (0x1 << i))) { /* * Oops.. thread 0 is not available. Disable whole * core */ tmp = tmp & ~(0xf << i); printf("WARNING: Core %d is disabled because thread 0" " of this core is not enabled.\n", i / 4); } } xlr_boot1_info.cpu_online_map = tmp; /* Wakeup Other cpus, and put them in bsd park code. */ wakeup = ((void (*) (void *, void *, unsigned int)) (unsigned long)(xlr_boot1_info.wakeup)); printf("Waking up CPUs 0x%jx.\n", (intmax_t)xlr_boot1_info.cpu_online_map & ~(0x1U)); if (xlr_boot1_info.cpu_online_map & ~(0x1U)) wakeup(mpwait, 0, (unsigned int)xlr_boot1_info.cpu_online_map); #endif /* xlr specific post initialization */ /* initialize other on chip stuff */ xlr_board_info_setup(); xlr_msgring_config(); xlr_pic_init(); xlr_msgring_cpu_init(); mips_timer_init_params(xlr_boot1_info.cpu_frequency, 0); printf("Platform specific startup now completes\n"); } void platform_cpu_init() { } void platform_identify(void) { printf("Board [%d:%d], processor 0x%08x\n", (int)xlr_boot1_info.board_major_version, (int)xlr_boot1_info.board_minor_version, mips_rd_prid()); } /* * XXX Maybe return the state of the watchdog in enter, and pass it to * exit? Like spl(). */ void platform_trap_enter(void) { } void platform_reset(void) { xlr_reg_t *mmio = xlr_io_mmio(XLR_IO_GPIO_OFFSET); /* write 1 to GPIO software reset register */ xlr_write_reg(mmio, 8, 1); } void platform_trap_exit(void) { } #ifdef SMP int xlr_ap_release[MAXCPU]; int platform_start_ap(int cpuid) { int hwid = xlr_cpuid_to_hwtid[cpuid]; if (xlr_boot1_info.cpu_online_map & (1<