Index: head/sys/mips/mips/mips_pic.c =================================================================== --- head/sys/mips/mips/mips_pic.c (revision 297664) +++ head/sys/mips/mips/mips_pic.c (revision 297665) @@ -1,519 +1,418 @@ /*- * Copyright (c) 2015 Alexander Kabaev * Copyright (c) 2006 Oleksandr Tymoshenko * 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 "opt_platform.h" #include "opt_hwpmc_hooks.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef FDT #include #include #include #include #endif #include "pic_if.h" #define NHARD_IRQS 6 #define NSOFT_IRQS 2 #define NREAL_IRQS (NHARD_IRQS + NSOFT_IRQS) static int mips_pic_intr(void *); +struct mips_pic_irqsrc { + struct intr_irqsrc isrc; + struct resource *res; + u_int irq; +}; + struct mips_pic_softc { - device_t pic_dev; - struct intr_irqsrc * pic_irqs[NREAL_IRQS]; - struct mtx mutex; - uint32_t nirqs; + device_t pic_dev; + struct mips_pic_irqsrc pic_irqs[NREAL_IRQS]; + struct rman pic_irq_rman; + struct mtx mutex; + uint32_t nirqs; }; static struct mips_pic_softc *pic_sc; +#define PIC_INTR_ISRC(sc, irq) (&(sc)->pic_irqs[(irq)].isrc) + #ifdef FDT static struct ofw_compat_data compat_data[] = { {"mti,cpu-interrupt-controller", true}, {NULL, false} }; #endif #ifndef FDT static void mips_pic_identify(driver_t *drv, device_t parent) { BUS_ADD_CHILD(parent, 0, "cpupic", 0); } #endif static int mips_pic_probe(device_t dev) { #ifdef FDT if (!ofw_bus_status_okay(dev)) return (ENXIO); if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data) return (ENXIO); #endif device_set_desc(dev, "MIPS32 Interrupt Controller"); return (BUS_PROBE_DEFAULT); } static inline void pic_irq_unmask(struct mips_pic_softc *sc, u_int irq) { mips_wr_status(mips_rd_status() | ((1 << irq) << 8)); } static inline void pic_irq_mask(struct mips_pic_softc *sc, u_int irq) { mips_wr_status(mips_rd_status() & ~((1 << irq) << 8)); } #ifdef SMP static void mips_pic_init_secondary(device_t dev) { } #endif /* SMP */ static inline intptr_t pic_xref(device_t dev) { #ifdef FDT return (OF_xref_from_node(ofw_bus_get_node(dev))); #else return (0); #endif } static int +mips_pic_register_isrcs(struct mips_pic_softc *sc) +{ + int error; + uint32_t irq, i; + struct intr_irqsrc *isrc; + const char *name; + + name = device_get_nameunit(sc->pic_dev); + for (irq = 0; irq < sc->nirqs; irq++) { + sc->pic_irqs[irq].irq = irq; + sc->pic_irqs[irq].res = rman_reserve_resource(&sc->pic_irq_rman, + irq, irq, 1, RF_ACTIVE, sc->pic_dev); + if (sc->pic_irqs[irq].res == NULL) { + device_printf(sc->pic_dev, + "%s failed to alloc resource for irq %d", + __func__, irq); + return (ENOMEM); + } + isrc = PIC_INTR_ISRC(sc, irq); + error = intr_isrc_register(isrc, sc->pic_dev, 0, "%s", name); + if (error != 0) { + for (i = 0; i < irq; i++) { + intr_isrc_deregister(PIC_INTR_ISRC(sc, i)); + } + device_printf(sc->pic_dev, "%s failed", __func__); + return (error); + } + } + + return (0); +} + +static int mips_pic_attach(device_t dev) { struct mips_pic_softc *sc; intptr_t xref = pic_xref(dev); if (pic_sc) return (ENXIO); sc = device_get_softc(dev); sc->pic_dev = dev; pic_sc = sc; /* Initialize mutex */ mtx_init(&sc->mutex, "PIC lock", "", MTX_SPIN); /* Set the number of interrupts */ sc->nirqs = nitems(sc->pic_irqs); + /* Init the IRQ rman */ + sc->pic_irq_rman.rm_type = RMAN_ARRAY; + sc->pic_irq_rman.rm_descr = "MIPS PIC IRQs"; + if (rman_init(&sc->pic_irq_rman) != 0 || + rman_manage_region(&sc->pic_irq_rman, 0, sc->nirqs - 1) != 0) { + device_printf(dev, "failed to setup IRQ rman\n"); + goto cleanup; + } + + /* Register the interrupts */ + if (mips_pic_register_isrcs(sc) != 0) { + device_printf(dev, "could not register PIC ISRCs\n"); + goto cleanup; + } + /* * Now, when everything is initialized, it's right time to * register interrupt controller to interrupt framefork. */ if (intr_pic_register(dev, xref) != 0) { device_printf(dev, "could not register PIC\n"); goto cleanup; } /* Claim our root controller role */ if (intr_pic_claim_root(dev, xref, mips_pic_intr, sc, 0) != 0) { device_printf(dev, "could not set PIC as a root\n"); - intr_pic_unregister(dev, xref); + intr_pic_deregister(dev, xref); goto cleanup; } return (0); cleanup: return(ENXIO); } int mips_pic_intr(void *arg) { struct mips_pic_softc *sc = arg; register_t cause, status; - struct intr_irqsrc *isrc; int i, intr; cause = mips_rd_cause(); status = mips_rd_status(); intr = (cause & MIPS_INT_MASK) >> 8; /* * Do not handle masked interrupts. They were masked by * pre_ithread function (mips_mask_XXX_intr) and will be * unmasked once ithread is through with handler */ intr &= (status & MIPS_INT_MASK) >> 8; while ((i = fls(intr)) != 0) { i--; /* Get a 0-offset interrupt. */ intr &= ~(1 << i); - isrc = sc->pic_irqs[i]; - if (isrc == NULL) { + if (intr_isrc_dispatch(PIC_INTR_ISRC(sc, i), + curthread->td_intr_frame) != 0) { device_printf(sc->pic_dev, "Stray interrupt %u detected\n", i); pic_irq_mask(sc, i); continue; } - - intr_irq_dispatch(isrc, curthread->td_intr_frame); } KASSERT(i == 0, ("all interrupts handled")); #ifdef HWPMC_HOOKS if (pmc_hook && (PCPU_GET(curthread)->td_pflags & TDP_CALLCHAIN)) { struct trapframe *tf = PCPU_GET(curthread)->td_intr_frame; pmc_hook(PCPU_GET(curthread), PMC_FN_USER_CALLCHAIN, tf); } #endif return (FILTER_HANDLED); } -static int -pic_attach_isrc(struct mips_pic_softc *sc, struct intr_irqsrc *isrc, u_int irq) +static void +mips_pic_disable_intr(device_t dev, struct intr_irqsrc *isrc) { + u_int irq; - /* - * 1. The link between ISRC and controller must be set atomically. - * 2. Just do things only once in rare case when consumers - * of shared interrupt came here at the same moment. - */ - mtx_lock_spin(&sc->mutex); - if (sc->pic_irqs[irq] != NULL) { - mtx_unlock_spin(&sc->mutex); - return (sc->pic_irqs[irq] == isrc ? 0 : EEXIST); - } - sc->pic_irqs[irq] = isrc; - isrc->isrc_data = irq; - mtx_unlock_spin(&sc->mutex); - - if (irq < NSOFT_IRQS) - intr_irq_set_name(isrc, "sint%u", irq); - else if (irq < NREAL_IRQS) - intr_irq_set_name(isrc, "int%u", irq - NSOFT_IRQS); - else - panic("Invalid irq %u", irq); - return (0); + irq = ((struct mips_pic_irqsrc *)isrc)->irq; + pic_irq_mask(device_get_softc(dev), irq); } -static int -pic_detach_isrc(struct mips_pic_softc *sc, struct intr_irqsrc *isrc, u_int irq) +static void +mips_pic_enable_intr(device_t dev, struct intr_irqsrc *isrc) { + u_int irq; - mtx_lock_spin(&sc->mutex); - if (sc->pic_irqs[irq] != isrc) { - mtx_unlock_spin(&sc->mutex); - return (sc->pic_irqs[irq] == NULL ? 0 : EINVAL); - } - sc->pic_irqs[irq] = NULL; - isrc->isrc_data = 0; - mtx_unlock_spin(&sc->mutex); - - intr_irq_set_name(isrc, "%s", ""); - return (0); + irq = ((struct mips_pic_irqsrc *)isrc)->irq; + pic_irq_unmask(device_get_softc(dev), irq); } static int -pic_irq_from_nspc(struct mips_pic_softc *sc, u_int type, u_int num, u_int *irqp) +mips_pic_map_intr(device_t dev, struct intr_map_data *data, + struct intr_irqsrc **isrcp) { - - switch (type) { - case INTR_IRQ_NSPC_PLAIN: - *irqp = num; - return (*irqp < sc->nirqs ? 0 : EINVAL); - - case INTR_IRQ_NSPC_SWI: - *irqp = num; - return (num < NSOFT_IRQS ? 0 : EINVAL); - - case INTR_IRQ_NSPC_IRQ: - *irqp = num + NSOFT_IRQS; - return (num < NHARD_IRQS ? 0 : EINVAL); - - default: - return (EINVAL); - } -} - -static int -pic_map_nspc(struct mips_pic_softc *sc, struct intr_irqsrc *isrc, u_int *irqp) -{ - int error; - - error = pic_irq_from_nspc(sc, isrc->isrc_nspc_type, isrc->isrc_nspc_num, - irqp); - if (error != 0) - return (error); - return (pic_attach_isrc(sc, isrc, *irqp)); -} - #ifdef FDT -static int -pic_map_fdt(struct mips_pic_softc *sc, struct intr_irqsrc *isrc, u_int *irqp) -{ - u_int irq; - int error; + struct mips_pic_softc *sc; - irq = isrc->isrc_cells[0]; + sc = device_get_softc(dev); - if (irq >= sc->nirqs) + if (data == NULL || data->type != INTR_MAP_DATA_FDT || + data->fdt.ncells != 1 || data->fdt.cells[0] >= sc->nirqs) return (EINVAL); - error = pic_attach_isrc(sc, isrc, irq); - if (error != 0) - return (error); - - isrc->isrc_nspc_type = INTR_IRQ_NSPC_PLAIN; - isrc->isrc_nspc_num = irq; - isrc->isrc_trig = INTR_TRIGGER_CONFORM; - isrc->isrc_pol = INTR_POLARITY_CONFORM; - - *irqp = irq; + *isrcp = PIC_INTR_ISRC(sc, data->fdt.cells[0]); return (0); -} +#else + return (EINVAL); #endif - -static int -mips_pic_register(device_t dev, struct intr_irqsrc *isrc, boolean_t *is_percpu) -{ - struct mips_pic_softc *sc = device_get_softc(dev); - u_int irq; - int error; - - if (isrc->isrc_type == INTR_ISRCT_NAMESPACE) - error = pic_map_nspc(sc, isrc, &irq); -#ifdef FDT - else if (isrc->isrc_type == INTR_ISRCT_FDT) - error = pic_map_fdt(sc, isrc, &irq); -#endif - else - return (EINVAL); - - if (error == 0) - *is_percpu = TRUE; - return (error); } static void -mips_pic_enable_intr(device_t dev, struct intr_irqsrc *isrc) -{ - - if (isrc->isrc_trig == INTR_TRIGGER_CONFORM) - isrc->isrc_trig = INTR_TRIGGER_LEVEL; -} - -static void -mips_pic_enable_source(device_t dev, struct intr_irqsrc *isrc) -{ - struct mips_pic_softc *sc = device_get_softc(dev); - u_int irq = isrc->isrc_data; - - pic_irq_unmask(sc, irq); -} - -static void -mips_pic_disable_source(device_t dev, struct intr_irqsrc *isrc) -{ - struct mips_pic_softc *sc = device_get_softc(dev); - u_int irq = isrc->isrc_data; - - pic_irq_mask(sc, irq); -} - -static int -mips_pic_unregister(device_t dev, struct intr_irqsrc *isrc) -{ - struct mips_pic_softc *sc = device_get_softc(dev); - u_int irq = isrc->isrc_data; - - return (pic_detach_isrc(sc, isrc, irq)); -} - -static void mips_pic_pre_ithread(device_t dev, struct intr_irqsrc *isrc) { - mips_pic_disable_source(dev, isrc); + mips_pic_disable_intr(dev, isrc); } static void mips_pic_post_ithread(device_t dev, struct intr_irqsrc *isrc) { - mips_pic_enable_source(dev, isrc); + mips_pic_enable_intr(dev, isrc); } static void mips_pic_post_filter(device_t dev, struct intr_irqsrc *isrc) { } -#ifdef SMP -static int -mips_pic_bind(device_t dev, struct intr_irqsrc *isrc) -{ - return (EOPNOTSUPP); -} - -static void -mips_pic_ipi_send(device_t dev, struct intr_irqsrc *isrc, cpuset_t cpus) -{ -} -#endif - static device_method_t mips_pic_methods[] = { /* Device interface */ #ifndef FDT DEVMETHOD(device_identify, mips_pic_identify), #endif DEVMETHOD(device_probe, mips_pic_probe), DEVMETHOD(device_attach, mips_pic_attach), + /* Interrupt controller interface */ - DEVMETHOD(pic_disable_source, mips_pic_disable_source), + DEVMETHOD(pic_disable_intr, mips_pic_disable_intr), DEVMETHOD(pic_enable_intr, mips_pic_enable_intr), - DEVMETHOD(pic_enable_source, mips_pic_enable_source), - DEVMETHOD(pic_post_filter, mips_pic_post_filter), - DEVMETHOD(pic_post_ithread, mips_pic_post_ithread), + DEVMETHOD(pic_map_intr, mips_pic_map_intr), DEVMETHOD(pic_pre_ithread, mips_pic_pre_ithread), - DEVMETHOD(pic_register, mips_pic_register), - DEVMETHOD(pic_unregister, mips_pic_unregister), -#ifdef SMP - DEVMETHOD(pic_bind, mips_pic_bind), - DEVMETHOD(pic_init_secondary, mips_pic_init_secondary), - DEVMETHOD(pic_ipi_send, mips_pic_ipi_send), -#endif + DEVMETHOD(pic_post_ithread, mips_pic_post_ithread), + DEVMETHOD(pic_post_filter, mips_pic_post_filter), + { 0, 0 } }; static driver_t mips_pic_driver = { "cpupic", mips_pic_methods, sizeof(struct mips_pic_softc), }; static devclass_t mips_pic_devclass; #ifdef FDT EARLY_DRIVER_MODULE(cpupic, ofwbus, mips_pic_driver, mips_pic_devclass, 0, 0, BUS_PASS_INTERRUPT); #else EARLY_DRIVER_MODULE(cpupic, nexus, mips_pic_driver, mips_pic_devclass, 0, 0, BUS_PASS_INTERRUPT); #endif void cpu_init_interrupts(void) { } void cpu_establish_hardintr(const char *name, driver_filter_t *filt, void (*handler)(void*), void *arg, int irq, int flags, void **cookiep) { - u_int vec; int res; /* * We have 6 levels, but thats 0 - 5 (not including 6) */ if (irq < 0 || irq >= NHARD_IRQS) panic("%s called for unknown hard intr %d", __func__, irq); KASSERT(pic_sc != NULL, ("%s: no pic", __func__)); - vec = intr_namespace_map_irq(pic_sc->pic_dev, INTR_IRQ_NSPC_IRQ, irq); - KASSERT(vec != NIRQ, ("Unable to map hard IRQ %d\n", irq)); - res = intr_irq_add_handler(pic_sc->pic_dev, filt, handler, arg, vec, - flags, cookiep); + irq += NSOFT_IRQS; + res = intr_setup_irq(pic_sc->pic_dev, pic_sc->pic_irqs[irq].res, filt, + handler, arg, flags, cookiep); if (res != 0) panic("Unable to add hard IRQ %d handler", irq); - - (void)pic_irq_from_nspc(pic_sc, INTR_IRQ_NSPC_IRQ, irq, &vec); - KASSERT(pic_sc->pic_irqs[vec] != NULL, - ("Hard IRQ %d not registered\n", irq)); - intr_irq_set_name(pic_sc->pic_irqs[vec], "%s", name); } void cpu_establish_softintr(const char *name, driver_filter_t *filt, void (*handler)(void*), void *arg, int irq, int flags, void **cookiep) { - u_int vec; int res; if (irq < 0 || irq > NSOFT_IRQS) panic("%s called for unknown soft intr %d", __func__, irq); KASSERT(pic_sc != NULL, ("%s: no pic", __func__)); - vec = intr_namespace_map_irq(pic_sc->pic_dev, INTR_IRQ_NSPC_SWI, irq); - KASSERT(vec <= NIRQ, ("Unable to map soft IRQ %d\n", irq)); - intr_irq_add_handler(pic_sc->pic_dev, filt, handler, arg, vec, - flags, cookiep); + res = intr_setup_irq(pic_sc->pic_dev, pic_sc->pic_irqs[irq].res, filt, + handler, arg, flags, cookiep); if (res != 0) panic("Unable to add soft IRQ %d handler", irq); - - (void)pic_irq_from_nspc(pic_sc, INTR_IRQ_NSPC_SWI, irq, &vec); - KASSERT(pic_sc->pic_irqs[vec] != NULL, - ("Soft IRQ %d not registered\n", irq)); - intr_irq_set_name(pic_sc->pic_irqs[vec], "%s", name); } Index: head/sys/mips/mips/nexus.c =================================================================== --- head/sys/mips/mips/nexus.c (revision 297664) +++ head/sys/mips/mips/nexus.c (revision 297665) @@ -1,587 +1,586 @@ /*- * Copyright 1998 Massachusetts Institute of Technology * * Permission to use, copy, modify, and distribute this software and * its documentation for any purpose and without fee is hereby * granted, provided that both the above copyright notice and this * permission notice appear in all copies, that both the above * copyright notice and this permission notice appear in all * supporting documentation, and that the name of M.I.T. not be used * in advertising or publicity pertaining to distribution of the * software without specific, written prior permission. M.I.T. makes * no representations about the suitability of this software for any * purpose. It is provided "as is" without express or implied * warranty. * * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT * SHALL M.I.T. 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. * */ /* * This code implements a `root nexus' for MIPS Architecture * machines. The function of the root nexus is to serve as an * attachment point for both processors and buses, and to manage * resources which are common to all of them. In particular, * this code implements the core resource managers for interrupt * requests and memory address space. */ #include "opt_platform.h" #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef MIPS_INTRNG #include #else #include #endif #ifdef FDT #include #include "ofw_bus_if.h" #endif #undef NEXUS_DEBUG #ifdef NEXUS_DEBUG #define dprintf printf #else #define dprintf(x, arg...) #endif /* NEXUS_DEBUG */ #define NUM_MIPS_IRQS 6 static MALLOC_DEFINE(M_NEXUSDEV, "nexusdev", "Nexus device"); struct nexus_device { struct resource_list nx_resources; }; #define DEVTONX(dev) ((struct nexus_device *)device_get_ivars(dev)) static struct rman irq_rman; static struct rman mem_rman; static struct resource * nexus_alloc_resource(device_t, device_t, int, int *, rman_res_t, rman_res_t, rman_res_t, u_int); static device_t nexus_add_child(device_t, u_int, const char *, int); static int nexus_attach(device_t); static void nexus_delete_resource(device_t, device_t, int, int); static struct resource_list * nexus_get_reslist(device_t, device_t); static int nexus_get_resource(device_t, device_t, int, int, rman_res_t *, rman_res_t *); static int nexus_print_child(device_t, device_t); static int nexus_print_all_resources(device_t dev); static int nexus_probe(device_t); static int nexus_release_resource(device_t, device_t, int, int, struct resource *); static int nexus_set_resource(device_t, device_t, int, int, rman_res_t, rman_res_t); static int nexus_activate_resource(device_t, device_t, int, int, struct resource *); static int nexus_deactivate_resource(device_t, device_t, int, int, struct resource *); static void nexus_hinted_child(device_t, const char *, int); static int nexus_setup_intr(device_t dev, device_t child, struct resource *res, int flags, driver_filter_t *filt, driver_intr_t *intr, void *arg, void **cookiep); static int nexus_teardown_intr(device_t, device_t, struct resource *, void *); #ifdef MIPS_INTRNG #ifdef SMP static int nexus_bind_intr(device_t, device_t, struct resource *, int); #endif #ifdef FDT static int nexus_ofw_map_intr(device_t dev, device_t child, phandle_t iparent, int icells, pcell_t *intr); #endif static int nexus_describe_intr(device_t dev, device_t child, struct resource *irq, void *cookie, const char *descr); static int nexus_config_intr(device_t dev, int irq, enum intr_trigger trig, enum intr_polarity pol); #endif static device_method_t nexus_methods[] = { /* Device interface */ DEVMETHOD(device_probe, nexus_probe), DEVMETHOD(device_attach, nexus_attach), /* Bus interface */ DEVMETHOD(bus_add_child, nexus_add_child), DEVMETHOD(bus_alloc_resource, nexus_alloc_resource), DEVMETHOD(bus_delete_resource, nexus_delete_resource), DEVMETHOD(bus_get_resource, nexus_get_resource), DEVMETHOD(bus_get_resource_list, nexus_get_reslist), DEVMETHOD(bus_print_child, nexus_print_child), DEVMETHOD(bus_release_resource, nexus_release_resource), DEVMETHOD(bus_set_resource, nexus_set_resource), DEVMETHOD(bus_setup_intr, nexus_setup_intr), DEVMETHOD(bus_teardown_intr, nexus_teardown_intr), DEVMETHOD(bus_activate_resource,nexus_activate_resource), DEVMETHOD(bus_deactivate_resource, nexus_deactivate_resource), DEVMETHOD(bus_hinted_child, nexus_hinted_child), #ifdef MIPS_INTRNG DEVMETHOD(bus_config_intr, nexus_config_intr), DEVMETHOD(bus_describe_intr, nexus_describe_intr), #ifdef SMP DEVMETHOD(bus_bind_intr, nexus_bind_intr), #endif #ifdef FDT DEVMETHOD(ofw_bus_map_intr, nexus_ofw_map_intr), #endif #endif { 0, 0 } }; static driver_t nexus_driver = { "nexus", nexus_methods, 1 /* no softc */ }; static devclass_t nexus_devclass; static int nexus_probe(device_t dev) { device_set_desc(dev, "MIPS32 root nexus"); irq_rman.rm_start = 0; irq_rman.rm_end = NUM_MIPS_IRQS - 1; irq_rman.rm_type = RMAN_ARRAY; irq_rman.rm_descr = "Hardware IRQs"; if (rman_init(&irq_rman) != 0 || rman_manage_region(&irq_rman, 0, NUM_MIPS_IRQS - 1) != 0) { panic("%s: irq_rman", __func__); } mem_rman.rm_start = 0; mem_rman.rm_end = BUS_SPACE_MAXADDR; mem_rman.rm_type = RMAN_ARRAY; mem_rman.rm_descr = "Memory addresses"; if (rman_init(&mem_rman) != 0 || rman_manage_region(&mem_rman, 0, BUS_SPACE_MAXADDR) != 0) { panic("%s: mem_rman", __func__); } return (0); } static int nexus_attach(device_t dev) { bus_generic_probe(dev); bus_enumerate_hinted_children(dev); bus_generic_attach(dev); return (0); } static int nexus_print_child(device_t bus, device_t child) { int retval = 0; retval += bus_print_child_header(bus, child); retval += nexus_print_all_resources(child); if (device_get_flags(child)) retval += printf(" flags %#x", device_get_flags(child)); retval += printf(" on %s\n", device_get_nameunit(bus)); return (retval); } static int nexus_print_all_resources(device_t dev) { struct nexus_device *ndev = DEVTONX(dev); struct resource_list *rl = &ndev->nx_resources; int retval = 0; if (STAILQ_FIRST(rl)) retval += printf(" at"); retval += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#jx"); retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%jd"); return (retval); } static device_t nexus_add_child(device_t bus, u_int order, const char *name, int unit) { device_t child; struct nexus_device *ndev; ndev = malloc(sizeof(struct nexus_device), M_NEXUSDEV, M_NOWAIT|M_ZERO); if (!ndev) return (0); resource_list_init(&ndev->nx_resources); child = device_add_child_ordered(bus, order, name, unit); if (child == NULL) { device_printf(bus, "failed to add child: %s%d\n", name, unit); return (0); } /* should we free this in nexus_child_detached? */ device_set_ivars(child, ndev); return (child); } /* * Allocate a resource on behalf of child. NB: child is usually going to be a * child of one of our descendants, not a direct child of nexus0. * (Exceptions include footbridge.) */ static struct resource * nexus_alloc_resource(device_t bus, device_t child, int type, int *rid, rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) { struct nexus_device *ndev = DEVTONX(child); struct resource *rv; struct resource_list_entry *rle; struct rman *rm; int isdefault, needactivate, passthrough; dprintf("%s: entry (%p, %p, %d, %p, %p, %p, %jd, %d)\n", __func__, bus, child, type, rid, (void *)(intptr_t)start, (void *)(intptr_t)end, count, flags); dprintf("%s: requested rid is %d\n", __func__, *rid); isdefault = (RMAN_IS_DEFAULT_RANGE(start, end) && count == 1); needactivate = flags & RF_ACTIVE; passthrough = (device_get_parent(child) != bus); rle = NULL; /* * If this is an allocation of the "default" range for a given RID, * and we know what the resources for this device are (ie. they aren't * maintained by a child bus), then work out the start/end values. */ if (isdefault) { rle = resource_list_find(&ndev->nx_resources, type, *rid); if (rle == NULL) return (NULL); if (rle->res != NULL) { panic("%s: resource entry is busy", __func__); } start = rle->start; end = rle->end; count = rle->count; } switch (type) { case SYS_RES_IRQ: rm = &irq_rman; break; case SYS_RES_MEMORY: rm = &mem_rman; break; default: printf("%s: unknown resource type %d\n", __func__, type); return (0); } rv = rman_reserve_resource(rm, start, end, count, flags, child); if (rv == 0) { printf("%s: could not reserve resource for %s\n", __func__, device_get_nameunit(child)); return (0); } rman_set_rid(rv, *rid); if (needactivate) { if (bus_activate_resource(child, type, *rid, rv)) { printf("%s: could not activate resource\n", __func__); rman_release_resource(rv); return (0); } } return (rv); } static struct resource_list * nexus_get_reslist(device_t dev, device_t child) { struct nexus_device *ndev = DEVTONX(child); return (&ndev->nx_resources); } static int nexus_set_resource(device_t dev, device_t child, int type, int rid, rman_res_t start, rman_res_t count) { struct nexus_device *ndev = DEVTONX(child); struct resource_list *rl = &ndev->nx_resources; struct resource_list_entry *rle; dprintf("%s: entry (%p, %p, %d, %d, %p, %jd)\n", __func__, dev, child, type, rid, (void *)(intptr_t)start, count); rle = resource_list_add(rl, type, rid, start, start + count - 1, count); if (rle == NULL) return (ENXIO); return (0); } static int nexus_get_resource(device_t dev, device_t child, int type, int rid, rman_res_t *startp, rman_res_t *countp) { struct nexus_device *ndev = DEVTONX(child); struct resource_list *rl = &ndev->nx_resources; struct resource_list_entry *rle; rle = resource_list_find(rl, type, rid); if (!rle) return(ENOENT); if (startp) *startp = rle->start; if (countp) *countp = rle->count; return (0); } static void nexus_delete_resource(device_t dev, device_t child, int type, int rid) { struct nexus_device *ndev = DEVTONX(child); struct resource_list *rl = &ndev->nx_resources; dprintf("%s: entry\n", __func__); resource_list_delete(rl, type, rid); } static int nexus_release_resource(device_t bus, device_t child, int type, int rid, struct resource *r) { dprintf("%s: entry\n", __func__); if (rman_get_flags(r) & RF_ACTIVE) { int error = bus_deactivate_resource(child, type, rid, r); if (error) return error; } return (rman_release_resource(r)); } static int nexus_activate_resource(device_t bus, device_t child, int type, int rid, struct resource *r) { void *vaddr; vm_paddr_t paddr; vm_size_t psize; int err; /* * If this is a memory resource, use pmap_mapdev to map it. */ if (type == SYS_RES_MEMORY || type == SYS_RES_IOPORT) { paddr = rman_get_start(r); psize = rman_get_size(r); rman_set_bustag(r, mips_bus_space_generic); err = bus_space_map(rman_get_bustag(r), paddr, psize, 0, (bus_space_handle_t *)&vaddr); if (err != 0) { rman_deactivate_resource(r); return (err); } rman_set_virtual(r, vaddr); rman_set_bushandle(r, (bus_space_handle_t)(uintptr_t)vaddr); } return (rman_activate_resource(r)); } static int nexus_deactivate_resource(device_t bus, device_t child, int type, int rid, struct resource *r) { bus_space_handle_t vaddr; bus_size_t psize; vaddr = rman_get_bushandle(r); if (type == SYS_RES_MEMORY && vaddr != 0) { psize = (bus_size_t)rman_get_size(r); bus_space_unmap(rman_get_bustag(r), vaddr, psize); rman_set_virtual(r, NULL); rman_set_bushandle(r, 0); } return (rman_deactivate_resource(r)); } static int nexus_setup_intr(device_t dev, device_t child, struct resource *res, int flags, driver_filter_t *filt, driver_intr_t *intr, void *arg, void **cookiep) { - int irq; #ifdef MIPS_INTRNG - for (irq = rman_get_start(res); irq <= rman_get_end(res); irq++) { - intr_irq_add_handler(child, filt, intr, arg, irq, flags, - cookiep); - } + return (intr_setup_irq(child, res, filt, intr, arg, flags, cookiep)); #else + int irq; register_t s; s = intr_disable(); irq = rman_get_start(res); if (irq >= NUM_MIPS_IRQS) { intr_restore(s); return (0); } cpu_establish_hardintr(device_get_nameunit(child), filt, intr, arg, irq, flags, cookiep); intr_restore(s); -#endif + return (0); +#endif } static int nexus_teardown_intr(device_t dev, device_t child, struct resource *r, void *ih) { #ifdef MIPS_INTRNG - return (intr_irq_remove_handler(child, rman_get_start(r), ih)); + return (intr_teardown_irq(child, r, ih)); #else printf("Unimplemented %s at %s:%d\n", __func__, __FILE__, __LINE__); return (0); #endif } #ifdef MIPS_INTRNG static int nexus_config_intr(device_t dev, int irq, enum intr_trigger trig, enum intr_polarity pol) { - return (intr_irq_config(irq, trig, pol)); + device_printf(dev, "bus_config_intr is obsolete and not supported!\n"); + return (EOPNOTSUPP); } static int nexus_describe_intr(device_t dev, device_t child, struct resource *irq, void *cookie, const char *descr) { - return (intr_irq_describe(rman_get_start(irq), cookie, descr)); + return (intr_describe_irq(child, irq, cookie, descr)); } #ifdef SMP static int nexus_bind_intr(device_t dev, device_t child, struct resource *irq, int cpu) { - return (intr_irq_bind(rman_get_start(irq), cpu)); + return (intr_bind_irq(child, irq, cpu)); } #endif #ifdef FDT static int nexus_ofw_map_intr(device_t dev, device_t child, phandle_t iparent, int icells, pcell_t *intr) { return (intr_fdt_map_irq(iparent, intr, icells)); } #endif #endif /* MIPS_INTRNG */ static void nexus_hinted_child(device_t bus, const char *dname, int dunit) { device_t child; long maddr; int msize; int order; int result; int irq; int mem_hints_count; if ((resource_int_value(dname, dunit, "order", &order)) != 0) order = 1000; child = BUS_ADD_CHILD(bus, order, dname, dunit); if (child == NULL) return; /* * Set hard-wired resources for hinted child using * specific RIDs. */ mem_hints_count = 0; if (resource_long_value(dname, dunit, "maddr", &maddr) == 0) mem_hints_count++; if (resource_int_value(dname, dunit, "msize", &msize) == 0) mem_hints_count++; /* check if all info for mem resource has been provided */ if ((mem_hints_count > 0) && (mem_hints_count < 2)) { printf("Either maddr or msize hint is missing for %s%d\n", dname, dunit); } else if (mem_hints_count) { dprintf("%s: discovered hinted child %s at maddr %p(%d)\n", __func__, device_get_nameunit(child), (void *)(intptr_t)maddr, msize); result = bus_set_resource(child, SYS_RES_MEMORY, 0, maddr, msize); if (result != 0) { device_printf(bus, "warning: bus_set_resource() failed\n"); } } if (resource_int_value(dname, dunit, "irq", &irq) == 0) { result = bus_set_resource(child, SYS_RES_IRQ, 0, irq, 1); if (result != 0) device_printf(bus, "warning: bus_set_resource() failed\n"); } } EARLY_DRIVER_MODULE(nexus, root, nexus_driver, nexus_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_EARLY);