diff options
author | ian <ian@FreeBSD.org> | 2014-05-13 18:06:26 +0000 |
---|---|---|
committer | ian <ian@FreeBSD.org> | 2014-05-13 18:06:26 +0000 |
commit | 399f18336611368662b09e65882f98bf17a5587a (patch) | |
tree | 3ed47a96a6001c3efbae46873c17573b47209815 /sys/powerpc/powerpc | |
parent | 41e4178a5bf9750ed65445b40e81c0b5f56d0c4e (diff) | |
download | FreeBSD-src-399f18336611368662b09e65882f98bf17a5587a.zip FreeBSD-src-399f18336611368662b09e65882f98bf17a5587a.tar.gz |
MFC r256994, r257016, r257055, r257059, r257060, r257075
Add two new interfaces to ofw_bus:
- ofw_bus_map_intr()
Maps an (iparent, IRQ) tuple to a system-global interrupt number in some
platform dependent way. This is meant to be implemented as a replacement
for [FDT_]MAP_IRQ() that is an MI interface that knows about the bus
hierarchy.
- ofw_bus_config_intr()
Configures an interrupt (previously mapped) based on firmware sense flags.
This replaces manual interpretation of the sense field in bus drivers and
will, in a follow-up, allow that interpretation to be redirected to the PIC
drivers where it belongs. This will eventually replace the tables in
/sys/dev/fdt/fdt_ARCH.c
The PowerPC/AIM code has been converted to use these globally, with an
implementation in terms of MAP_IRQ() and powerpc_config_intr(), assuming
OpenPIC, at the bus root in nexus(4). The ofw_bus_config_intr() will shortly
be integrated into pic_if.m and bounced through nexus into the PIC tree.
Factor out MI portions of the PowerPC nexus device into /sys/dev/ofw. The
sparc64 driver will be modified to use this shortly.
Allow PIC drivers to translate firmware sense codes for themselves. This
is designed to replace the tables in dev/fdt/fdt_ARCH.c, but will not
happen quite yet.
Do not map IRQs twice. This fixes PowerPC/FDT systems with multiple PICs,
which would try to treat the previously-mapped interrupts from
fdt_decode_intr() as interrupt line numbers on the same parent PIC.
Remove some of the code required for supporting ssm(4) on SPARC in favor
of a more PowerPC/FDT-focused design. Whenever SPARC64 is integrated
into this rework, this should be (trivially) revisited.
Diffstat (limited to 'sys/powerpc/powerpc')
-rw-r--r-- | sys/powerpc/powerpc/intr_machdep.c | 46 | ||||
-rw-r--r-- | sys/powerpc/powerpc/nexus.c | 460 | ||||
-rw-r--r-- | sys/powerpc/powerpc/pic_if.m | 19 |
3 files changed, 75 insertions, 450 deletions
diff --git a/sys/powerpc/powerpc/intr_machdep.c b/sys/powerpc/powerpc/intr_machdep.c index 539d3f6..0b13191 100644 --- a/sys/powerpc/powerpc/intr_machdep.c +++ b/sys/powerpc/powerpc/intr_machdep.c @@ -102,6 +102,7 @@ struct powerpc_intr { cpuset_t cpu; enum intr_trigger trig; enum intr_polarity pol; + int fwcode; }; struct pic { @@ -427,6 +428,9 @@ powerpc_enable_intr(void) if (error) continue; + if (i->trig == -1) + PIC_TRANSLATE_CODE(i->pic, i->intline, i->fwcode, + &i->trig, &i->pol); if (i->trig != INTR_TRIGGER_CONFORM || i->pol != INTR_POLARITY_CONFORM) PIC_CONFIG(i->pic, i->intline, i->trig, i->pol); @@ -469,15 +473,21 @@ powerpc_setup_intr(const char *name, u_int irq, driver_filter_t filter, if (!cold) { error = powerpc_map_irq(i); - if (!error && (i->trig != INTR_TRIGGER_CONFORM || - i->pol != INTR_POLARITY_CONFORM)) - PIC_CONFIG(i->pic, i->intline, i->trig, i->pol); + if (!error) { + if (i->trig == -1) + PIC_TRANSLATE_CODE(i->pic, i->intline, + i->fwcode, &i->trig, &i->pol); + + if (i->trig != INTR_TRIGGER_CONFORM || + i->pol != INTR_POLARITY_CONFORM) + PIC_CONFIG(i->pic, i->intline, i->trig, i->pol); - if (!error && i->pic == root_pic) - PIC_BIND(i->pic, i->intline, i->cpu); + if (i->pic == root_pic) + PIC_BIND(i->pic, i->intline, i->cpu); - if (!error && enable) - PIC_ENABLE(i->pic, i->intline, i->vector); + if (enable) + PIC_ENABLE(i->pic, i->intline, i->vector); + } } return (error); } @@ -504,6 +514,28 @@ powerpc_bind_intr(u_int irq, u_char cpu) #endif int +powerpc_fw_config_intr(int irq, int sense_code) +{ + struct powerpc_intr *i; + + i = intr_lookup(irq); + if (i == NULL) + return (ENOMEM); + + i->trig = -1; + i->pol = INTR_POLARITY_CONFORM; + i->fwcode = sense_code; + + if (!cold && i->pic != NULL) { + PIC_TRANSLATE_CODE(i->pic, i->intline, i->fwcode, &i->trig, + &i->pol); + PIC_CONFIG(i->pic, i->intline, i->trig, i->pol); + } + + return (0); +} + +int powerpc_config_intr(int irq, enum intr_trigger trig, enum intr_polarity pol) { struct powerpc_intr *i; diff --git a/sys/powerpc/powerpc/nexus.c b/sys/powerpc/powerpc/nexus.c index 16b6c2d..f7100f1 100644 --- a/sys/powerpc/powerpc/nexus.c +++ b/sys/powerpc/powerpc/nexus.c @@ -49,6 +49,7 @@ __FBSDID("$FreeBSD$"); #include <dev/ofw/ofw_bus.h> #include <dev/ofw/ofw_bus_subr.h> +#include <dev/ofw/ofw_nexus.h> #include <dev/ofw/openfirm.h> #include <machine/bus.h> @@ -63,260 +64,45 @@ __FBSDID("$FreeBSD$"); * * Additionally, interrupt setup/teardown and some resource management are * done at this level. - * - * Maybe this code should get into dev/ofw to some extent, as some of it should - * work for all Open Firmware based machines... */ -struct nexus_devinfo { - struct ofw_bus_devinfo ndi_obdinfo; - struct resource_list ndi_rl; -}; - -struct nexus_softc { - uint32_t acells, scells; - struct rman sc_intr_rman; - struct rman sc_mem_rman; -}; - -static device_probe_t nexus_probe; -static device_attach_t nexus_attach; -static bus_print_child_t nexus_print_child; -static bus_add_child_t nexus_add_child; -static bus_probe_nomatch_t nexus_probe_nomatch; static bus_setup_intr_t nexus_setup_intr; static bus_teardown_intr_t nexus_teardown_intr; -static bus_alloc_resource_t nexus_alloc_resource; static bus_activate_resource_t nexus_activate_resource; static bus_deactivate_resource_t nexus_deactivate_resource; -static bus_adjust_resource_t nexus_adjust_resource; -static bus_release_resource_t nexus_release_resource; -static bus_get_resource_list_t nexus_get_resource_list; #ifdef SMP static bus_bind_intr_t nexus_bind_intr; #endif static bus_config_intr_t nexus_config_intr; -static ofw_bus_get_devinfo_t nexus_get_devinfo; - -static int nexus_inlist(const char *, const char *const *); -static struct nexus_devinfo * nexus_setup_dinfo(device_t, phandle_t); -static void nexus_destroy_dinfo(struct nexus_devinfo *); -static int nexus_print_res(struct nexus_devinfo *); +static ofw_bus_map_intr_t nexus_ofw_map_intr; +static ofw_bus_config_intr_t nexus_ofw_config_intr; static device_method_t nexus_methods[] = { - /* Device interface */ - DEVMETHOD(device_probe, nexus_probe), - DEVMETHOD(device_attach, nexus_attach), - DEVMETHOD(device_detach, bus_generic_detach), - DEVMETHOD(device_shutdown, bus_generic_shutdown), - DEVMETHOD(device_suspend, bus_generic_suspend), - DEVMETHOD(device_resume, bus_generic_resume), - /* Bus interface */ - DEVMETHOD(bus_print_child, nexus_print_child), - DEVMETHOD(bus_probe_nomatch, nexus_probe_nomatch), - DEVMETHOD(bus_read_ivar, bus_generic_read_ivar), - DEVMETHOD(bus_write_ivar, bus_generic_write_ivar), - DEVMETHOD(bus_add_child, nexus_add_child), - DEVMETHOD(bus_child_pnpinfo_str, ofw_bus_gen_child_pnpinfo_str), - DEVMETHOD(bus_alloc_resource, nexus_alloc_resource), DEVMETHOD(bus_activate_resource, nexus_activate_resource), DEVMETHOD(bus_deactivate_resource, nexus_deactivate_resource), - DEVMETHOD(bus_adjust_resource, nexus_adjust_resource), - DEVMETHOD(bus_release_resource, nexus_release_resource), DEVMETHOD(bus_setup_intr, nexus_setup_intr), DEVMETHOD(bus_teardown_intr, nexus_teardown_intr), - DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource), - DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource), - DEVMETHOD(bus_get_resource_list, nexus_get_resource_list), #ifdef SMP DEVMETHOD(bus_bind_intr, nexus_bind_intr), #endif DEVMETHOD(bus_config_intr, nexus_config_intr), /* ofw_bus interface */ - DEVMETHOD(ofw_bus_get_devinfo, nexus_get_devinfo), - DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat), - DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model), - DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name), - DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node), - DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type), + DEVMETHOD(ofw_bus_map_intr, nexus_ofw_map_intr), + DEVMETHOD(ofw_bus_config_intr, nexus_ofw_config_intr), DEVMETHOD_END }; static devclass_t nexus_devclass; -DEFINE_CLASS_0(nexus, nexus_driver, nexus_methods, sizeof(struct nexus_softc)); +DEFINE_CLASS_1(nexus, nexus_driver, nexus_methods, + sizeof(struct ofw_nexus_softc), ofw_nexus_driver); EARLY_DRIVER_MODULE(nexus, root, nexus_driver, nexus_devclass, 0, 0, BUS_PASS_BUS); MODULE_VERSION(nexus, 1); -static const char *const nexus_excl_name[] = { - "FJSV,system", - "aliases", - "associations", - "chosen", - "cmp", - "counter-timer", /* No separate device; handled by psycho/sbus */ - "failsafe", - "memory", - "openprom", - "options", - "packages", - "physical-memory", - "rsc", - "sgcn", - "todsg", - "virtual-memory", - NULL -}; - -static const char *const nexus_excl_type[] = { - "core", - "cpu", - NULL -}; - -extern struct bus_space_tag nexus_bustag; -extern struct bus_dma_tag nexus_dmatag; - -static int -nexus_inlist(const char *name, const char *const *list) -{ - int i; - - if (name == NULL) - return (0); - for (i = 0; list[i] != NULL; i++) - if (strcmp(name, list[i]) == 0) - return (1); - return (0); -} - -#define NEXUS_EXCLUDED(name, type) \ - (nexus_inlist((name), nexus_excl_name) || \ - ((type) != NULL && nexus_inlist((type), nexus_excl_type))) - -static int -nexus_probe(device_t dev) -{ - - /* Nexus does always match. */ - device_set_desc(dev, "Open Firmware Nexus device"); - return (0); -} - -static int -nexus_attach(device_t dev) -{ - struct nexus_devinfo *ndi; - struct nexus_softc *sc; - device_t cdev; - phandle_t node; - - sc = device_get_softc(dev); - - if (strcmp(device_get_name(device_get_parent(dev)), "root") == 0) { - node = OF_peer(0); - - sc->sc_intr_rman.rm_type = RMAN_ARRAY; - sc->sc_intr_rman.rm_descr = "Interrupts"; - sc->sc_mem_rman.rm_type = RMAN_ARRAY; - sc->sc_mem_rman.rm_descr = "Device Memory"; - if (rman_init(&sc->sc_intr_rman) != 0 || - rman_init(&sc->sc_mem_rman) != 0 || - rman_manage_region(&sc->sc_intr_rman, 0, ~0) != 0 || - rman_manage_region(&sc->sc_mem_rman, 0, BUS_SPACE_MAXADDR) - != 0) - panic("%s: failed to set up rmans.", __func__); - } else - node = ofw_bus_get_node(dev); - - /* - * Allow devices to identify. - */ - bus_generic_probe(dev); - - /* - * If no Open Firmware, bail early - */ - if (node == -1) - return (bus_generic_attach(dev)); - - /* - * Some important numbers - */ - sc->acells = 2; - OF_getencprop(node, "#address-cells", &sc->acells, sizeof(sc->acells)); - sc->scells = 1; - OF_getencprop(node, "#size-cells", &sc->scells, sizeof(sc->scells)); - - /* - * Now walk the OFW tree and attach top-level devices. - */ - for (node = OF_child(node); node > 0; node = OF_peer(node)) { - if ((ndi = nexus_setup_dinfo(dev, node)) == NULL) - continue; - cdev = device_add_child(dev, NULL, -1); - if (cdev == NULL) { - device_printf(dev, "<%s>: device_add_child failed\n", - ndi->ndi_obdinfo.obd_name); - nexus_destroy_dinfo(ndi); - continue; - } - device_set_ivars(cdev, ndi); - } - return (bus_generic_attach(dev)); -} - -static device_t -nexus_add_child(device_t dev, u_int order, const char *name, int unit) -{ - device_t cdev; - struct nexus_devinfo *ndi; - - cdev = device_add_child_ordered(dev, order, name, unit); - if (cdev == NULL) - return (NULL); - - ndi = malloc(sizeof(*ndi), M_DEVBUF, M_WAITOK | M_ZERO); - ndi->ndi_obdinfo.obd_node = -1; - resource_list_init(&ndi->ndi_rl); - device_set_ivars(cdev, ndi); - - return (cdev); -} - -static int -nexus_print_child(device_t bus, device_t child) -{ - int rv; - - rv = bus_print_child_header(bus, child); - rv += nexus_print_res(device_get_ivars(child)); - rv += bus_print_child_footer(bus, child); - return (rv); -} - -static void -nexus_probe_nomatch(device_t bus, device_t child) -{ - const char *name, *type; - - if (!bootverbose) - return; - - name = ofw_bus_get_name(child); - type = ofw_bus_get_type(child); - - device_printf(bus, "<%s>", - name != NULL ? name : "unknown"); - nexus_print_res(device_get_ivars(child)); - printf(" type %s (no driver attached)\n", - type != NULL ? type : "unknown"); -} - static int nexus_setup_intr(device_t bus __unused, device_t child, struct resource *r, int flags, driver_filter_t *filt, driver_intr_t *intr, void *arg, @@ -370,71 +156,20 @@ nexus_config_intr(device_t dev, int irq, enum intr_trigger trig, return (powerpc_config_intr(irq, trig, pol)); } -static struct resource * -nexus_alloc_resource(device_t bus, device_t child, int type, int *rid, - u_long start, u_long end, u_long count, u_int flags) +static int +nexus_ofw_map_intr(device_t dev, device_t child, phandle_t iparent, int irq) { - struct nexus_softc *sc; - struct rman *rm; - struct resource *rv; - struct resource_list_entry *rle; - device_t nexus; - int isdefault, passthrough; - - isdefault = (start == 0UL && end == ~0UL); - passthrough = (device_get_parent(child) != bus); - nexus = bus; - while (strcmp(device_get_name(device_get_parent(nexus)), "root") != 0) - nexus = device_get_parent(nexus); - sc = device_get_softc(nexus); - rle = NULL; - - if (!passthrough && isdefault) { - rle = resource_list_find(BUS_GET_RESOURCE_LIST(bus, child), - type, *rid); - if (rle == NULL) - return (NULL); - if (rle->res != NULL) - panic("%s: resource entry is busy", __func__); - start = rle->start; - count = ulmax(count, rle->count); - end = ulmax(rle->end, start + count - 1); - } - - switch (type) { - case SYS_RES_IRQ: - rm = &sc->sc_intr_rman; - break; - case SYS_RES_MEMORY: - rm = &sc->sc_mem_rman; - break; - default: - return (NULL); - } - - rv = rman_reserve_resource(rm, start, end, count, flags & ~RF_ACTIVE, - child); - if (rv == NULL) - return (NULL); - rman_set_rid(rv, *rid); - - if ((flags & RF_ACTIVE) != 0 && bus_activate_resource(child, type, - *rid, rv) != 0) { - rman_release_resource(rv); - return (NULL); - } - - if (!passthrough && rle != NULL) { - rle->res = rv; - rle->start = rman_get_start(rv); - rle->end = rman_get_end(rv); - rle->count = rle->end - rle->start + 1; - } - - return (rv); + return (MAP_IRQ(iparent, irq)); } static int +nexus_ofw_config_intr(device_t dev, device_t child, int irq, int sense) +{ + + return (powerpc_fw_config_intr(irq, sense)); +} + +static int nexus_activate_resource(device_t bus __unused, device_t child __unused, int type, int rid __unused, struct resource *r) { @@ -476,164 +211,3 @@ nexus_deactivate_resource(device_t bus __unused, device_t child __unused, return (rman_deactivate_resource(r)); } -static int -nexus_adjust_resource(device_t bus, device_t child __unused, int type, - struct resource *r, u_long start, u_long end) -{ - struct nexus_softc *sc; - struct rman *rm; - device_t nexus; - - nexus = bus; - while (strcmp(device_get_name(device_get_parent(nexus)), "root") != 0) - nexus = device_get_parent(nexus); - sc = device_get_softc(nexus); - switch (type) { - case SYS_RES_IRQ: - rm = &sc->sc_intr_rman; - break; - case SYS_RES_MEMORY: - rm = &sc->sc_mem_rman; - break; - default: - return (EINVAL); - } - if (rm == NULL) - return (ENXIO); - if (rman_is_region_manager(r, rm) == 0) - return (EINVAL); - return (rman_adjust_resource(r, start, end)); -} - -static int -nexus_release_resource(device_t bus __unused, device_t child, int type, - int rid, struct resource *r) -{ - int error; - - if ((rman_get_flags(r) & RF_ACTIVE) != 0) { - error = bus_deactivate_resource(child, type, rid, r); - if (error) - return (error); - } - return (rman_release_resource(r)); -} - -static struct resource_list * -nexus_get_resource_list(device_t bus __unused, device_t child) -{ - struct nexus_devinfo *ndi; - - ndi = device_get_ivars(child); - return (&ndi->ndi_rl); -} - -static const struct ofw_bus_devinfo * -nexus_get_devinfo(device_t bus __unused, device_t child) -{ - struct nexus_devinfo *ndi; - - ndi = device_get_ivars(child); - return (&ndi->ndi_obdinfo); -} - -static struct nexus_devinfo * -nexus_setup_dinfo(device_t dev, phandle_t node) -{ - struct nexus_softc *sc; - struct nexus_devinfo *ndi; - uint32_t *reg, *intr, icells; - uint64_t phys, size; - phandle_t iparent; - int i, j; - int nintr; - int nreg; - - sc = device_get_softc(dev); - - ndi = malloc(sizeof(*ndi), M_DEVBUF, M_WAITOK | M_ZERO); - if (ofw_bus_gen_setup_devinfo(&ndi->ndi_obdinfo, node) != 0) { - free(ndi, M_DEVBUF); - return (NULL); - } - if (NEXUS_EXCLUDED(ndi->ndi_obdinfo.obd_name, - ndi->ndi_obdinfo.obd_type)) { - ofw_bus_gen_destroy_devinfo(&ndi->ndi_obdinfo); - free(ndi, M_DEVBUF); - return (NULL); - } - - resource_list_init(&ndi->ndi_rl); - nreg = OF_getencprop_alloc(node, "reg", sizeof(*reg), (void **)®); - if (nreg == -1) - nreg = 0; - if (nreg % (sc->acells + sc->scells) != 0) { - if (bootverbose) - device_printf(dev, "Malformed reg property on <%s>\n", - ndi->ndi_obdinfo.obd_name); - nreg = 0; - } - - for (i = 0; i < nreg; i += sc->acells + sc->scells) { - phys = size = 0; - for (j = 0; j < sc->acells; j++) { - phys <<= 32; - phys |= reg[i + j]; - } - for (j = 0; j < sc->scells; j++) { - size <<= 32; - size |= reg[i + sc->acells + j]; - } - /* Skip the dummy reg property of glue devices like ssm(4). */ - if (size != 0) - resource_list_add(&ndi->ndi_rl, SYS_RES_MEMORY, i, - phys, phys + size - 1, size); - } - free(reg, M_OFWPROP); - - nintr = OF_getencprop_alloc(node, "interrupts", sizeof(*intr), - (void **)&intr); - if (nintr > 0) { - iparent = 0; - OF_searchprop(node, "interrupt-parent", &iparent, - sizeof(iparent)); - OF_searchprop(iparent, "#interrupt-cells", &icells, - sizeof(icells)); - for (i = 0; i < nintr; i+= icells) { - intr[i] = MAP_IRQ(iparent, intr[i]); - resource_list_add(&ndi->ndi_rl, SYS_RES_IRQ, i, intr[i], - intr[i], 1); - if (icells > 1) { - powerpc_config_intr(intr[i], (intr[i+1] & 1) ? - INTR_TRIGGER_LEVEL : INTR_TRIGGER_EDGE, - INTR_POLARITY_LOW); - } - } - free(intr, M_OFWPROP); - } - - return (ndi); -} - -static void -nexus_destroy_dinfo(struct nexus_devinfo *ndi) -{ - - resource_list_free(&ndi->ndi_rl); - ofw_bus_gen_destroy_devinfo(&ndi->ndi_obdinfo); - free(ndi, M_DEVBUF); -} - -static int -nexus_print_res(struct nexus_devinfo *ndi) -{ - int rv; - - rv = 0; - rv += resource_list_print_type(&ndi->ndi_rl, "mem", SYS_RES_MEMORY, - "%#lx"); - rv += resource_list_print_type(&ndi->ndi_rl, "irq", SYS_RES_IRQ, - "%ld"); - return (rv); -} - diff --git a/sys/powerpc/powerpc/pic_if.m b/sys/powerpc/powerpc/pic_if.m index e429d31..f42c31a 100644 --- a/sys/powerpc/powerpc/pic_if.m +++ b/sys/powerpc/powerpc/pic_if.m @@ -33,12 +33,31 @@ INTERFACE pic; +CODE { + static pic_translate_code_t pic_translate_code_default; + + static void pic_translate_code_default(device_t dev, u_int irq, + int code, enum intr_trigger *trig, enum intr_polarity *pol) + { + *trig = INTR_TRIGGER_CONFORM; + *pol = INTR_POLARITY_CONFORM; + } +}; + METHOD void bind { device_t dev; u_int irq; cpuset_t cpumask; }; +METHOD void translate_code { + device_t dev; + u_int irq; + int code; + enum intr_trigger *trig; + enum intr_polarity *pol; +} DEFAULT pic_translate_code_default; + METHOD void config { device_t dev; u_int irq; |