Index: head/sys/dev/atkbdc/atkbdc_ebus.c =================================================================== --- head/sys/dev/atkbdc/atkbdc_ebus.c (revision 300172) +++ head/sys/dev/atkbdc/atkbdc_ebus.c (revision 300173) @@ -1,305 +1,305 @@ /*- * Copyright (c) 1999 Kazutaka YOKOTA * Copyright (c) 2005 Marius Strobl * 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 as * the first lines of this file unmodified. * 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 AUTHORS ``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 AUTHORS 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. * * from: FreeBSD: src/sys/isa/atkbdc_isa.c,v 1.31 2005/05/29 04:42:28 nyan */ #include __FBSDID("$FreeBSD$"); #include "opt_kbd.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static device_probe_t atkbdc_ebus_probe; static device_attach_t atkbdc_ebus_attach; static device_method_t atkbdc_ebus_methods[] = { DEVMETHOD(device_probe, atkbdc_ebus_probe), DEVMETHOD(device_attach, atkbdc_ebus_attach), DEVMETHOD(device_suspend, bus_generic_suspend), DEVMETHOD(device_resume, bus_generic_resume), DEVMETHOD(bus_print_child, atkbdc_print_child), DEVMETHOD(bus_read_ivar, atkbdc_read_ivar), DEVMETHOD(bus_write_ivar, atkbdc_write_ivar), DEVMETHOD(bus_get_resource_list,atkbdc_get_resource_list), DEVMETHOD(bus_alloc_resource, bus_generic_rl_alloc_resource), DEVMETHOD(bus_release_resource, bus_generic_rl_release_resource), DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource), DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource), DEVMETHOD(bus_delete_resource, bus_generic_rl_delete_resource), DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), { 0, 0 } }; static driver_t atkbdc_ebus_driver = { ATKBDC_DRIVER_NAME, atkbdc_ebus_methods, sizeof(atkbdc_softc_t *), }; DRIVER_MODULE(atkbdc, ebus, atkbdc_ebus_driver, atkbdc_devclass, 0, 0); static int atkbdc_ebus_probe(device_t dev) { struct resource *port0, *port1; rman_res_t count, start; int error, rid; if (strcmp(ofw_bus_get_name(dev), "8042") != 0) return (ENXIO); /* * On AXi and AXmp boards the NS16550 (used to connect keyboard/ * mouse) share their IRQ lines with the i8042. Any IRQ activity * (typically during attach) of the NS16550 used to connect the * keyboard when actually the PS/2 keyboard is selected in OFW * causes interaction with the OBP i8042 driver resulting in a * hang and vice versa. As RS232 keyboards and mice obviously * aren't meant to be used in parallel with PS/2 ones on these * boards don't attach to the i8042 in case the PS/2 keyboard * isn't selected in order to prevent such hangs. * Note that it's not sufficient here to rely on the '8042' node * only showing up when a PS/2 keyboard is actually connected as * the user still might have adjusted the 'keyboard' alias to * point to the RS232 keyboard. */ if ((!strcmp(sparc64_model, "SUNW,UltraAX-MP") || !strcmp(sparc64_model, "SUNW,UltraSPARC-IIi-Engine")) && OF_finddevice("keyboard") != ofw_bus_get_node(dev)) { device_disable(dev); return (ENXIO); } device_set_desc(dev, "Keyboard controller (i8042)"); /* * The '8042' node has two identical 8 addresses wide resources * which are apparently meant to be used one for the keyboard * half and the other one for the mouse half. To simplify matters * we use one for the command/data port resource and the other * one for the status port resource as the atkbdc(4) back-end * expects two struct resource rather than two bus space handles. */ rid = 0; if (bus_get_resource(dev, SYS_RES_MEMORY, rid, &start, &count) != 0) { device_printf(dev, "cannot determine command/data port resource\n"); return (ENXIO); } port0 = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, start, start, 1, RF_ACTIVE); if (port0 == NULL) { device_printf(dev, "cannot allocate command/data port resource\n"); return (ENXIO); } rid = 1; if (bus_get_resource(dev, SYS_RES_MEMORY, rid, &start, &count) != 0) { device_printf(dev, "cannot determine status port resource\n"); error = ENXIO; goto fail_port0; } start += KBD_STATUS_PORT; port1 = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, start, start, 1, RF_ACTIVE); if (port1 == NULL) { device_printf(dev, "cannot allocate status port resource\n"); error = ENXIO; goto fail_port0; } error = atkbdc_probe_unit(device_get_unit(dev), port0, port1); if (error != 0) device_printf(dev, "atkbdc_porbe_unit failed\n"); bus_release_resource(dev, SYS_RES_MEMORY, 1, port1); fail_port0: bus_release_resource(dev, SYS_RES_MEMORY, 0, port0); return (error); } static int atkbdc_ebus_attach(device_t dev) { atkbdc_softc_t *sc; atkbdc_device_t *adi; device_t cdev; phandle_t child; rman_res_t count, intr, start; int children, error, rid, unit; char *cname, *dname; unit = device_get_unit(dev); sc = *(atkbdc_softc_t **)device_get_softc(dev); if (sc == NULL) { /* * We have to maintain two copies of the kbdc_softc struct, * as the low-level console needs to have access to the * keyboard controller before kbdc is probed and attached. * kbdc_soft[] contains the default entry for that purpose. * See atkbdc.c. XXX */ sc = atkbdc_get_softc(unit); if (sc == NULL) return (ENOMEM); device_set_softc(dev, sc); } rid = 0; if (bus_get_resource(dev, SYS_RES_MEMORY, rid, &start, &count) != 0) { device_printf(dev, "cannot determine command/data port resource\n"); return (ENXIO); } sc->retry = 5000; sc->port0 = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, start, start, 1, RF_ACTIVE); if (sc->port0 == NULL) { device_printf(dev, "cannot allocate command/data port resource\n"); return (ENXIO); } rid = 1; if (bus_get_resource(dev, SYS_RES_MEMORY, rid, &start, &count) != 0) { device_printf(dev, "cannot determine status port resource\n"); error = ENXIO; goto fail_port0; } start += KBD_STATUS_PORT; sc->port1 = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, start, start, 1, RF_ACTIVE); if (sc->port1 == NULL) { device_printf(dev, "cannot allocate status port resource\n"); error = ENXIO; goto fail_port0; } error = atkbdc_attach_unit(unit, sc, sc->port0, sc->port1); if (error != 0) { device_printf(dev, "atkbdc_attach_unit failed\n"); goto fail_port1; } /* Attach children. */ children = 0; for (child = OF_child(ofw_bus_get_node(dev)); child != 0; child = OF_peer(child)) { if ((OF_getprop_alloc(child, "name", 1, (void **)&cname)) == -1) continue; if (children >= 2) { device_printf(dev, "<%s>: only two children per 8042 supported\n", cname); - free(cname, M_OFWPROP); + OF_prop_free(cname); continue; } adi = malloc(sizeof(struct atkbdc_device), M_ATKBDDEV, M_NOWAIT | M_ZERO); if (adi == NULL) { device_printf(dev, "<%s>: malloc failed\n", cname); - free(cname, M_OFWPROP); + OF_prop_free(cname); continue; } if (strcmp(cname, "kb_ps2") == 0) { adi->rid = KBDC_RID_KBD; dname = ATKBD_DRIVER_NAME; } else if (strcmp(cname, "kdmouse") == 0) { adi->rid = KBDC_RID_AUX; dname = PSM_DRIVER_NAME; } else { device_printf(dev, "<%s>: unknown device\n", cname); free(adi, M_ATKBDDEV); - free(cname, M_OFWPROP); + OF_prop_free(cname); continue; } intr = bus_get_resource_start(dev, SYS_RES_IRQ, adi->rid); if (intr == 0) { device_printf(dev, "<%s>: cannot determine interrupt resource\n", cname); free(adi, M_ATKBDDEV); - free(cname, M_OFWPROP); + OF_prop_free(cname); continue; } resource_list_init(&adi->resources); resource_list_add(&adi->resources, SYS_RES_IRQ, adi->rid, intr, intr, 1); if ((cdev = device_add_child(dev, dname, -1)) == NULL) { device_printf(dev, "<%s>: device_add_child failed\n", cname); resource_list_free(&adi->resources); free(adi, M_ATKBDDEV); - free(cname, M_OFWPROP); + OF_prop_free(cname); continue; } device_set_ivars(cdev, adi); children++; } error = bus_generic_attach(dev); if (error != 0) { device_printf(dev, "bus_generic_attach failed\n"); goto fail_port1; } return (0); fail_port1: bus_release_resource(dev, SYS_RES_MEMORY, 1, sc->port1); fail_port0: bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->port0); return (error); } Index: head/sys/dev/le/lebuffer_sbus.c =================================================================== --- head/sys/dev/le/lebuffer_sbus.c (revision 300172) +++ head/sys/dev/le/lebuffer_sbus.c (revision 300173) @@ -1,303 +1,303 @@ /*- * Copyright (c) 2006 Marius Strobl * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include struct lebuffer_devinfo { struct ofw_bus_devinfo ldi_obdinfo; struct resource_list ldi_rl; }; static devclass_t lebuffer_devclass; static device_probe_t lebuffer_probe; static device_attach_t lebuffer_attach; static device_detach_t lebuffer_detach; static bus_print_child_t lebuffer_print_child; static bus_probe_nomatch_t lebuffer_probe_nomatch; static bus_get_resource_list_t lebuffer_get_resource_list; static ofw_bus_get_devinfo_t lebuffer_get_devinfo; static struct lebuffer_devinfo *lebuffer_setup_dinfo(device_t, phandle_t); static void lebuffer_destroy_dinfo(struct lebuffer_devinfo *); static int lebuffer_print_res(struct lebuffer_devinfo *); static device_method_t lebuffer_methods[] = { /* Device interface */ DEVMETHOD(device_probe, lebuffer_probe), DEVMETHOD(device_attach, lebuffer_attach), DEVMETHOD(device_detach, lebuffer_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, lebuffer_print_child), DEVMETHOD(bus_probe_nomatch, lebuffer_probe_nomatch), DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), DEVMETHOD(bus_alloc_resource, bus_generic_rl_alloc_resource), DEVMETHOD(bus_adjust_resource, bus_generic_adjust_resource), DEVMETHOD(bus_release_resource, bus_generic_rl_release_resource), DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), DEVMETHOD(bus_get_resource_list, lebuffer_get_resource_list), DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource), /* ofw_bus interface */ DEVMETHOD(ofw_bus_get_devinfo, lebuffer_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), { 0, 0 } }; DEFINE_CLASS_0(lebuffer, lebuffer_driver, lebuffer_methods, 1); DRIVER_MODULE(lebuffer, sbus, lebuffer_driver, lebuffer_devclass, 0, 0); MODULE_DEPEND(lebuffer, sbus, 1, 1, 1); MODULE_VERSION(lebuffer, 1); static int lebuffer_probe(device_t dev) { const char *name; name = ofw_bus_get_name(dev); if (strcmp(name, "lebuffer") == 0) { device_set_desc_copy(dev, name); return (0); } return (ENXIO); } static int lebuffer_attach(device_t dev) { struct lebuffer_devinfo *ldi; device_t cdev; phandle_t child; int children; children = 0; for (child = OF_child(ofw_bus_get_node(dev)); child != 0; child = OF_peer(child)) { if ((ldi = lebuffer_setup_dinfo(dev, child)) == NULL) continue; if (children != 0) { device_printf(dev, "<%s>: only one child per buffer supported\n", ldi->ldi_obdinfo.obd_name); lebuffer_destroy_dinfo(ldi); continue; } if ((cdev = device_add_child(dev, NULL, -1)) == NULL) { device_printf(dev, "<%s>: device_add_child failed\n", ldi->ldi_obdinfo.obd_name); lebuffer_destroy_dinfo(ldi); continue; } device_set_ivars(cdev, ldi); children++; } return (bus_generic_attach(dev)); } static int lebuffer_detach(device_t dev) { device_t *children; int i, nchildren; bus_generic_detach(dev); if (device_get_children(dev, &children, &nchildren) == 0) { for (i = 0; i < nchildren; i++) { lebuffer_destroy_dinfo(device_get_ivars(children[i])); device_delete_child(dev, children[i]); } free(children, M_TEMP); } return (0); } static struct lebuffer_devinfo * lebuffer_setup_dinfo(device_t dev, phandle_t node) { struct lebuffer_devinfo *ldi; struct sbus_regs *reg; uint32_t base, iv, *intr; int i, nreg, nintr, slot, rslot; ldi = malloc(sizeof(*ldi), M_DEVBUF, M_WAITOK | M_ZERO); if (ofw_bus_gen_setup_devinfo(&ldi->ldi_obdinfo, node) != 0) { free(ldi, M_DEVBUF); return (NULL); } resource_list_init(&ldi->ldi_rl); slot = -1; nreg = OF_getprop_alloc(node, "reg", sizeof(*reg), (void **)®); if (nreg == -1) { device_printf(dev, "<%s>: incomplete\n", ldi->ldi_obdinfo.obd_name); goto fail; } for (i = 0; i < nreg; i++) { base = reg[i].sbr_offset; if (SBUS_ABS(base)) { rslot = SBUS_ABS_TO_SLOT(base); base = SBUS_ABS_TO_OFFSET(base); } else rslot = reg[i].sbr_slot; if (slot != -1 && slot != rslot) { device_printf(dev, "<%s>: multiple slots\n", ldi->ldi_obdinfo.obd_name); - free(reg, M_OFWPROP); + OF_prop_free(reg); goto fail; } slot = rslot; resource_list_add(&ldi->ldi_rl, SYS_RES_MEMORY, i, base, base + reg[i].sbr_size, reg[i].sbr_size); } - free(reg, M_OFWPROP); + OF_prop_free(reg); if (slot != sbus_get_slot(dev)) { device_printf(dev, "<%s>: parent and child slot do not match\n", ldi->ldi_obdinfo.obd_name); goto fail; } /* * The `interrupts' property contains the SBus interrupt level. */ nintr = OF_getprop_alloc(node, "interrupts", sizeof(*intr), (void **)&intr); if (nintr != -1) { for (i = 0; i < nintr; i++) { iv = intr[i]; /* * SBus card devices need the slot number encoded into * the vector as this is generally not done. */ if ((iv & INTMAP_OBIO_MASK) == 0) iv |= slot << 3; /* Set the IGN as appropriate. */ iv |= sbus_get_ign(dev) << INTMAP_IGN_SHIFT; resource_list_add(&ldi->ldi_rl, SYS_RES_IRQ, i, iv, iv, 1); } - free(intr, M_OFWPROP); + OF_prop_free(intr); } return (ldi); fail: lebuffer_destroy_dinfo(ldi); return (NULL); } static void lebuffer_destroy_dinfo(struct lebuffer_devinfo *dinfo) { resource_list_free(&dinfo->ldi_rl); ofw_bus_gen_destroy_devinfo(&dinfo->ldi_obdinfo); free(dinfo, M_DEVBUF); } static int lebuffer_print_child(device_t dev, device_t child) { int rv; rv = bus_print_child_header(dev, child); rv += lebuffer_print_res(device_get_ivars(child)); rv += bus_print_child_footer(dev, child); return (rv); } static void lebuffer_probe_nomatch(device_t dev, device_t child) { const char *type; device_printf(dev, "<%s>", ofw_bus_get_name(child)); lebuffer_print_res(device_get_ivars(child)); type = ofw_bus_get_type(child); printf(" type %s (no driver attached)\n", type != NULL ? type : "unknown"); } static struct resource_list * lebuffer_get_resource_list(device_t dev, device_t child) { struct lebuffer_devinfo *ldi; ldi = device_get_ivars(child); return (&ldi->ldi_rl); } static const struct ofw_bus_devinfo * lebuffer_get_devinfo(device_t bus, device_t child) { struct lebuffer_devinfo *ldi; ldi = device_get_ivars(child); return (&ldi->ldi_obdinfo); } static int lebuffer_print_res(struct lebuffer_devinfo *ldi) { int rv; rv = 0; rv += resource_list_print_type(&ldi->ldi_rl, "mem", SYS_RES_MEMORY, "%#jx"); rv += resource_list_print_type(&ldi->ldi_rl, "irq", SYS_RES_IRQ, "%jd"); return (rv); } Index: head/sys/sparc64/central/central.c =================================================================== --- head/sys/sparc64/central/central.c (revision 300172) +++ head/sys/sparc64/central/central.c (revision 300173) @@ -1,299 +1,299 @@ /*- * Copyright (c) 2003 Jake Burkholder. * 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 #include #include #include #include #include #include #include #include #include #include #include #include struct central_devinfo { struct ofw_bus_devinfo cdi_obdinfo; struct resource_list cdi_rl; }; struct central_softc { int sc_nrange; struct sbus_ranges *sc_ranges; }; static device_probe_t central_probe; static device_attach_t central_attach; static bus_print_child_t central_print_child; static bus_probe_nomatch_t central_probe_nomatch; static bus_alloc_resource_t central_alloc_resource; static bus_adjust_resource_t central_adjust_resource; static bus_get_resource_list_t central_get_resource_list; static ofw_bus_get_devinfo_t central_get_devinfo; static int central_print_res(struct central_devinfo *); static device_method_t central_methods[] = { /* Device interface */ DEVMETHOD(device_probe, central_probe), DEVMETHOD(device_attach, central_attach), DEVMETHOD(device_shutdown, bus_generic_shutdown), DEVMETHOD(device_suspend, bus_generic_suspend), DEVMETHOD(device_resume, bus_generic_resume), /* Bus interface */ DEVMETHOD(bus_print_child, central_print_child), DEVMETHOD(bus_probe_nomatch, central_probe_nomatch), DEVMETHOD(bus_alloc_resource, central_alloc_resource), DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), DEVMETHOD(bus_adjust_resource, central_adjust_resource), DEVMETHOD(bus_release_resource, bus_generic_rl_release_resource), DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource), DEVMETHOD(bus_get_resource_list, central_get_resource_list), DEVMETHOD(bus_child_pnpinfo_str, ofw_bus_gen_child_pnpinfo_str), /* ofw_bus interface */ DEVMETHOD(ofw_bus_get_devinfo, central_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_END }; static driver_t central_driver = { "central", central_methods, sizeof(struct central_softc), }; static devclass_t central_devclass; EARLY_DRIVER_MODULE(central, nexus, central_driver, central_devclass, 0, 0, BUS_PASS_BUS); MODULE_DEPEND(fhc, nexus, 1, 1, 1); MODULE_VERSION(central, 1); static int central_probe(device_t dev) { if (strcmp(ofw_bus_get_name(dev), "central") == 0) { device_set_desc(dev, "central"); return (0); } return (ENXIO); } static int central_attach(device_t dev) { struct central_devinfo *cdi; struct sbus_regs *reg; struct central_softc *sc; phandle_t child; phandle_t node; device_t cdev; int nreg; int i; sc = device_get_softc(dev); node = ofw_bus_get_node(dev); sc->sc_nrange = OF_getprop_alloc(node, "ranges", sizeof(*sc->sc_ranges), (void **)&sc->sc_ranges); if (sc->sc_nrange == -1) { device_printf(dev, "can't get ranges\n"); return (ENXIO); } for (child = OF_child(node); child != 0; child = OF_peer(child)) { cdi = malloc(sizeof(*cdi), M_DEVBUF, M_WAITOK | M_ZERO); if (ofw_bus_gen_setup_devinfo(&cdi->cdi_obdinfo, child) != 0) { free(cdi, M_DEVBUF); continue; } nreg = OF_getprop_alloc(child, "reg", sizeof(*reg), (void **)®); if (nreg == -1) { device_printf(dev, "<%s>: incomplete\n", cdi->cdi_obdinfo.obd_name); ofw_bus_gen_destroy_devinfo(&cdi->cdi_obdinfo); free(cdi, M_DEVBUF); continue; } resource_list_init(&cdi->cdi_rl); for (i = 0; i < nreg; i++) resource_list_add(&cdi->cdi_rl, SYS_RES_MEMORY, i, reg[i].sbr_offset, reg[i].sbr_offset + reg[i].sbr_size, reg[i].sbr_size); - free(reg, M_OFWPROP); + OF_prop_free(reg); cdev = device_add_child(dev, NULL, -1); if (cdev == NULL) { device_printf(dev, "<%s>: device_add_child failed\n", cdi->cdi_obdinfo.obd_name); resource_list_free(&cdi->cdi_rl); ofw_bus_gen_destroy_devinfo(&cdi->cdi_obdinfo); free(cdi, M_DEVBUF); continue; } device_set_ivars(cdev, cdi); } return (bus_generic_attach(dev)); } static int central_adjust_resource(device_t bus __unused, device_t child __unused, int type __unused, struct resource *r __unused, rman_res_t start __unused, rman_res_t end __unused) { return (ENXIO); } static int central_print_child(device_t dev, device_t child) { int rv; rv = bus_print_child_header(dev, child); rv += central_print_res(device_get_ivars(child)); rv += bus_print_child_footer(dev, child); return (rv); } static void central_probe_nomatch(device_t dev, device_t child) { const char *type; device_printf(dev, "<%s>", ofw_bus_get_name(child)); central_print_res(device_get_ivars(child)); type = ofw_bus_get_type(child); printf(" type %s (no driver attached)\n", type != NULL ? type : "unknown"); } static struct resource * central_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 resource_list *rl; struct resource_list_entry *rle; struct central_softc *sc; struct resource *res; bus_addr_t coffset; bus_addr_t cend; bus_addr_t phys; int isdefault; int passthrough; int i; isdefault = RMAN_IS_DEFAULT_RANGE(start, end); passthrough = (device_get_parent(child) != bus); res = NULL; rle = NULL; rl = BUS_GET_RESOURCE_LIST(bus, child); sc = device_get_softc(bus); switch (type) { case SYS_RES_IRQ: return (resource_list_alloc(rl, bus, child, type, rid, start, end, count, flags)); case SYS_RES_MEMORY: if (!passthrough) { rle = resource_list_find(rl, type, *rid); if (rle == NULL) return (NULL); if (rle->res != NULL) panic("%s: resource entry is busy", __func__); if (isdefault) { start = rle->start; count = ulmax(count, rle->count); end = ulmax(rle->end, start + count - 1); } } for (i = 0; i < sc->sc_nrange; i++) { coffset = sc->sc_ranges[i].coffset; cend = coffset + sc->sc_ranges[i].size - 1; if (start >= coffset && end <= cend) { start -= coffset; end -= coffset; phys = sc->sc_ranges[i].poffset | ((bus_addr_t)sc->sc_ranges[i].pspace << 32); res = bus_generic_alloc_resource(bus, child, type, rid, phys + start, phys + end, count, flags); if (!passthrough) rle->res = res; break; } } break; } return (res); } static struct resource_list * central_get_resource_list(device_t bus, device_t child) { struct central_devinfo *cdi; cdi = device_get_ivars(child); return (&cdi->cdi_rl); } static const struct ofw_bus_devinfo * central_get_devinfo(device_t bus, device_t child) { struct central_devinfo *cdi; cdi = device_get_ivars(child); return (&cdi->cdi_obdinfo); } static int central_print_res(struct central_devinfo *cdi) { return (resource_list_print_type(&cdi->cdi_rl, "mem", SYS_RES_MEMORY, "%#jx")); } Index: head/sys/sparc64/ebus/ebus.c =================================================================== --- head/sys/sparc64/ebus/ebus.c (revision 300172) +++ head/sys/sparc64/ebus/ebus.c (revision 300173) @@ -1,728 +1,728 @@ /*- * Copyright (c) 1999, 2000 Matthew R. Green * Copyright (c) 2009 by Marius Strobl * 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. 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 ``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. * * from: NetBSD: ebus.c,v 1.52 2008/05/29 14:51:26 mrg Exp */ /*- * Copyright (c) 2001 Thomas Moestl * 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. 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 ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); /* * Driver for JBus to EBus and PCI to EBus bridges */ #include #include #include #include #include #include #include #include #include #include #include #ifndef SUN4V #include #endif #include #include #include #include #include /* * The register, interrupt map and for the PCI variant also the ranges * properties are identical to the ISA ones. */ #include struct ebus_nexus_ranges { uint32_t child_hi; uint32_t child_lo; uint32_t phys_hi; uint32_t phys_lo; uint32_t size; }; struct ebus_devinfo { struct ofw_bus_devinfo edi_obdinfo; struct resource_list edi_rl; }; struct ebus_rinfo { int eri_rtype; struct rman eri_rman; struct resource *eri_res; }; struct ebus_softc { void *sc_range; struct ebus_rinfo *sc_rinfo; u_int sc_flags; #define EBUS_PCI (1 << 0) int sc_nrange; struct ofw_bus_iinfo sc_iinfo; #ifndef SUN4V uint32_t sc_ign; #endif }; static device_probe_t ebus_nexus_probe; static device_attach_t ebus_nexus_attach; static device_probe_t ebus_pci_probe; static device_attach_t ebus_pci_attach; static bus_print_child_t ebus_print_child; static bus_probe_nomatch_t ebus_probe_nomatch; static bus_alloc_resource_t ebus_alloc_resource; static bus_activate_resource_t ebus_activate_resource; static bus_adjust_resource_t ebus_adjust_resource; static bus_release_resource_t ebus_release_resource; static bus_setup_intr_t ebus_setup_intr; static bus_get_resource_list_t ebus_get_resource_list; static ofw_bus_get_devinfo_t ebus_get_devinfo; static int ebus_attach(device_t dev, struct ebus_softc *sc, phandle_t node); static struct ebus_devinfo *ebus_setup_dinfo(device_t dev, struct ebus_softc *sc, phandle_t node); static void ebus_destroy_dinfo(struct ebus_devinfo *edi); static int ebus_print_res(struct ebus_devinfo *edi); static devclass_t ebus_devclass; static device_method_t ebus_nexus_methods[] = { /* Device interface */ DEVMETHOD(device_probe, ebus_nexus_probe), DEVMETHOD(device_attach, ebus_nexus_attach), DEVMETHOD(device_shutdown, bus_generic_shutdown), DEVMETHOD(device_suspend, bus_generic_suspend), DEVMETHOD(device_resume, bus_generic_resume), /* Bus interface */ DEVMETHOD(bus_print_child, ebus_print_child), DEVMETHOD(bus_probe_nomatch, ebus_probe_nomatch), DEVMETHOD(bus_alloc_resource, ebus_alloc_resource), DEVMETHOD(bus_activate_resource, ebus_activate_resource), DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), DEVMETHOD(bus_adjust_resource, ebus_adjust_resource), DEVMETHOD(bus_release_resource, ebus_release_resource), DEVMETHOD(bus_setup_intr, ebus_setup_intr), DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource), DEVMETHOD(bus_get_resource_list, ebus_get_resource_list), DEVMETHOD(bus_child_pnpinfo_str, ofw_bus_gen_child_pnpinfo_str), /* ofw_bus interface */ DEVMETHOD(ofw_bus_get_devinfo, ebus_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_END }; static driver_t ebus_nexus_driver = { "ebus", ebus_nexus_methods, sizeof(struct ebus_softc), }; /* * NB: we rely on the interrupt controllers of the accompanying PCI-Express * bridge to be registered as the nexus variant of the EBus bridges doesn't * employ its own one. */ EARLY_DRIVER_MODULE(ebus, nexus, ebus_nexus_driver, ebus_devclass, 0, 0, BUS_PASS_BUS + 1); MODULE_DEPEND(ebus, nexus, 1, 1, 1); static device_method_t ebus_pci_methods[] = { /* Device interface */ DEVMETHOD(device_probe, ebus_pci_probe), DEVMETHOD(device_attach, ebus_pci_attach), DEVMETHOD(device_shutdown, bus_generic_shutdown), DEVMETHOD(device_suspend, bus_generic_suspend), DEVMETHOD(device_resume, bus_generic_resume), /* Bus interface */ DEVMETHOD(bus_print_child, ebus_print_child), DEVMETHOD(bus_probe_nomatch, ebus_probe_nomatch), DEVMETHOD(bus_alloc_resource, ebus_alloc_resource), DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), DEVMETHOD(bus_release_resource, ebus_release_resource), DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource), DEVMETHOD(bus_get_resource_list, ebus_get_resource_list), DEVMETHOD(bus_child_pnpinfo_str, ofw_bus_gen_child_pnpinfo_str), /* ofw_bus interface */ DEVMETHOD(ofw_bus_get_devinfo, ebus_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_END }; static driver_t ebus_pci_driver = { "ebus", ebus_pci_methods, sizeof(struct ebus_softc), }; EARLY_DRIVER_MODULE(ebus, pci, ebus_pci_driver, ebus_devclass, 0, 0, BUS_PASS_BUS); MODULE_DEPEND(ebus, pci, 1, 1, 1); MODULE_VERSION(ebus, 1); static int ebus_nexus_probe(device_t dev) { const char* compat; compat = ofw_bus_get_compat(dev); if (compat != NULL && strcmp(ofw_bus_get_name(dev), "ebus") == 0 && strcmp(compat, "jbus-ebus") == 0) { device_set_desc(dev, "JBus-EBus bridge"); return (BUS_PROBE_GENERIC); } return (ENXIO); } static int ebus_pci_probe(device_t dev) { if (pci_get_class(dev) != PCIC_BRIDGE || pci_get_vendor(dev) != 0x108e || strcmp(ofw_bus_get_name(dev), "ebus") != 0) return (ENXIO); if (pci_get_device(dev) == 0x1000) device_set_desc(dev, "PCI-EBus2 bridge"); else if (pci_get_device(dev) == 0x1100) device_set_desc(dev, "PCI-EBus3 bridge"); else return (ENXIO); return (BUS_PROBE_GENERIC); } static int ebus_nexus_attach(device_t dev) { struct ebus_softc *sc; phandle_t node; sc = device_get_softc(dev); node = ofw_bus_get_node(dev); #ifndef SUN4V if (OF_getprop(node, "portid", &sc->sc_ign, sizeof(sc->sc_ign)) == -1) { device_printf(dev, "could not determine IGN"); return (ENXIO); } #endif sc->sc_nrange = OF_getprop_alloc(node, "ranges", sizeof(struct ebus_nexus_ranges), &sc->sc_range); if (sc->sc_nrange == -1) { device_printf(dev, "could not get ranges property\n"); return (ENXIO); } return (ebus_attach(dev, sc, node)); } static int ebus_pci_attach(device_t dev) { struct ebus_softc *sc; struct ebus_rinfo *eri; struct resource *res; struct isa_ranges *range; phandle_t node; int i, rnum, rid; sc = device_get_softc(dev); sc->sc_flags |= EBUS_PCI; pci_write_config(dev, PCIR_COMMAND, pci_read_config(dev, PCIR_COMMAND, 2) | PCIM_CMD_SERRESPEN | PCIM_CMD_PERRESPEN | PCIM_CMD_BUSMASTEREN | PCIM_CMD_MEMEN, 2); pci_write_config(dev, PCIR_CACHELNSZ, 16 /* 64 bytes */, 1); pci_write_config(dev, PCIR_LATTIMER, 64 /* 64 PCI cycles */, 1); node = ofw_bus_get_node(dev); sc->sc_nrange = OF_getprop_alloc(node, "ranges", sizeof(struct isa_ranges), &sc->sc_range); if (sc->sc_nrange == -1) { device_printf(dev, "could not get ranges property\n"); return (ENXIO); } sc->sc_rinfo = malloc(sizeof(*sc->sc_rinfo) * sc->sc_nrange, M_DEVBUF, M_WAITOK | M_ZERO); /* For every range, there must be a matching resource. */ for (rnum = 0; rnum < sc->sc_nrange; rnum++) { eri = &sc->sc_rinfo[rnum]; range = &((struct isa_ranges *)sc->sc_range)[rnum]; eri->eri_rtype = ofw_isa_range_restype(range); rid = PCIR_BAR(rnum); res = bus_alloc_resource_any(dev, eri->eri_rtype, &rid, RF_ACTIVE); if (res == NULL) { device_printf(dev, "could not allocate range resource %d\n", rnum); goto fail; } if (rman_get_start(res) != ISA_RANGE_PHYS(range)) { device_printf(dev, "mismatch in start of range %d (0x%lx/0x%lx)\n", rnum, rman_get_start(res), ISA_RANGE_PHYS(range)); goto fail; } if (rman_get_size(res) != range->size) { device_printf(dev, "mismatch in size of range %d (0x%lx/0x%x)\n", rnum, rman_get_size(res), range->size); goto fail; } eri->eri_res = res; eri->eri_rman.rm_type = RMAN_ARRAY; eri->eri_rman.rm_descr = "EBus range"; if (rman_init_from_resource(&eri->eri_rman, res) != 0) { device_printf(dev, "could not initialize rman for range %d", rnum); goto fail; } } return (ebus_attach(dev, sc, node)); fail: for (i = rnum; i >= 0; i--) { eri = &sc->sc_rinfo[i]; if (i < rnum) rman_fini(&eri->eri_rman); if (eri->eri_res != NULL) { bus_release_resource(dev, eri->eri_rtype, PCIR_BAR(rnum), eri->eri_res); } } free(sc->sc_rinfo, M_DEVBUF); - free(sc->sc_range, M_OFWPROP); + OF_prop_free(sc->sc_range); return (ENXIO); } static int ebus_attach(device_t dev, struct ebus_softc *sc, phandle_t node) { struct ebus_devinfo *edi; device_t cdev; ofw_bus_setup_iinfo(node, &sc->sc_iinfo, sizeof(ofw_isa_intr_t)); /* * Now attach our children. */ for (node = OF_child(node); node > 0; node = OF_peer(node)) { if ((edi = ebus_setup_dinfo(dev, sc, node)) == NULL) continue; if ((cdev = device_add_child(dev, NULL, -1)) == NULL) { device_printf(dev, "<%s>: device_add_child failed\n", edi->edi_obdinfo.obd_name); ebus_destroy_dinfo(edi); continue; } device_set_ivars(cdev, edi); } return (bus_generic_attach(dev)); } static int ebus_print_child(device_t dev, device_t child) { int retval; retval = bus_print_child_header(dev, child); retval += ebus_print_res(device_get_ivars(child)); retval += bus_print_child_footer(dev, child); return (retval); } static void ebus_probe_nomatch(device_t dev, device_t child) { device_printf(dev, "<%s>", ofw_bus_get_name(child)); ebus_print_res(device_get_ivars(child)); printf(" (no driver attached)\n"); } static struct resource * ebus_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 ebus_softc *sc; struct resource_list *rl; struct resource_list_entry *rle = NULL; struct resource *res; struct ebus_rinfo *eri; struct ebus_nexus_ranges *enr; uint64_t cend, cstart, offset; int i, isdefault, passthrough, ridx; isdefault = RMAN_IS_DEFAULT_RANGE(start, end); passthrough = (device_get_parent(child) != bus); sc = device_get_softc(bus); rl = BUS_GET_RESOURCE_LIST(bus, child); switch (type) { case SYS_RES_MEMORY: KASSERT(!(isdefault && passthrough), ("%s: passthrough of default allocation", __func__)); if (!passthrough) { rle = resource_list_find(rl, type, *rid); if (rle == NULL) return (NULL); KASSERT(rle->res == NULL, ("%s: resource entry is busy", __func__)); if (isdefault) { start = rle->start; count = ulmax(count, rle->count); end = ulmax(rle->end, start + count - 1); } } res = NULL; if ((sc->sc_flags & EBUS_PCI) != 0) { /* * Map EBus ranges to PCI ranges. This may include * changing the allocation type. */ type = ofw_isa_range_map(sc->sc_range, sc->sc_nrange, &start, &end, &ridx); eri = &sc->sc_rinfo[ridx]; res = rman_reserve_resource(&eri->eri_rman, start, end, count, flags & ~RF_ACTIVE, child); if (res == NULL) return (NULL); rman_set_rid(res, *rid); if ((flags & RF_ACTIVE) != 0 && bus_activate_resource( child, type, *rid, res) != 0) { rman_release_resource(res); return (NULL); } } else { /* Map EBus ranges to nexus ranges. */ for (i = 0; i < sc->sc_nrange; i++) { enr = &((struct ebus_nexus_ranges *) sc->sc_range)[i]; cstart = (((uint64_t)enr->child_hi) << 32) | enr->child_lo; cend = cstart + enr->size - 1; if (start >= cstart && end <= cend) { offset = (((uint64_t)enr->phys_hi) << 32) | enr->phys_lo; start += offset - cstart; end += offset - cstart; res = bus_generic_alloc_resource(bus, child, type, rid, start, end, count, flags); break; } } } if (!passthrough) rle->res = res; return (res); case SYS_RES_IRQ: return (resource_list_alloc(rl, bus, child, type, rid, start, end, count, flags)); } return (NULL); } static int ebus_activate_resource(device_t bus, device_t child, int type, int rid, struct resource *res) { struct ebus_softc *sc; struct ebus_rinfo *eri; bus_space_tag_t bt; bus_space_handle_t bh; int i, rv; sc = device_get_softc(bus); if ((sc->sc_flags & EBUS_PCI) != 0 && type != SYS_RES_IRQ) { for (i = 0; i < sc->sc_nrange; i++) { eri = &sc->sc_rinfo[i]; if (rman_is_region_manager(res, &eri->eri_rman) != 0) { bt = rman_get_bustag(eri->eri_res); rv = bus_space_subregion(bt, rman_get_bushandle(eri->eri_res), rman_get_start(res) - rman_get_start(eri->eri_res), rman_get_size(res), &bh); if (rv != 0) return (rv); rman_set_bustag(res, bt); rman_set_bushandle(res, bh); return (rman_activate_resource(res)); } } return (EINVAL); } return (bus_generic_activate_resource(bus, child, type, rid, res)); } static int ebus_adjust_resource(device_t bus __unused, device_t child __unused, int type __unused, struct resource *res __unused, rman_res_t start __unused, rman_res_t end __unused) { return (ENXIO); } static int ebus_release_resource(device_t bus, device_t child, int type, int rid, struct resource *res) { struct ebus_softc *sc; struct resource_list *rl; struct resource_list_entry *rle; int passthrough, rv; passthrough = (device_get_parent(child) != bus); rl = BUS_GET_RESOURCE_LIST(bus, child); sc = device_get_softc(bus); if ((sc->sc_flags & EBUS_PCI) != 0 && type != SYS_RES_IRQ) { if ((rman_get_flags(res) & RF_ACTIVE) != 0 ){ rv = bus_deactivate_resource(child, type, rid, res); if (rv != 0) return (rv); } rv = rman_release_resource(res); if (rv != 0) return (rv); if (!passthrough) { rle = resource_list_find(rl, type, rid); KASSERT(rle != NULL, ("%s: resource entry not found!", __func__)); KASSERT(rle->res != NULL, ("%s: resource entry is not busy", __func__)); rle->res = NULL; } return (0); } return (resource_list_release(rl, bus, child, type, rid, res)); } static int ebus_setup_intr(device_t dev, device_t child, struct resource *ires, int flags, driver_filter_t *filt, driver_intr_t *intr, void *arg, void **cookiep) { #ifndef SUN4V struct ebus_softc *sc; u_long vec; sc = device_get_softc(dev); if ((sc->sc_flags & EBUS_PCI) == 0) { /* * Make sure the vector is fully specified. This isn't * necessarily the case with the PCI variant. */ vec = rman_get_start(ires); if (INTIGN(vec) != sc->sc_ign) { device_printf(dev, "invalid interrupt vector 0x%lx\n", vec); return (EINVAL); } /* * As we rely on the interrupt controllers of the * accompanying PCI-Express bridge ensure at least * something is registered for this vector. */ if (intr_vectors[vec].iv_ic == NULL) { device_printf(dev, "invalid interrupt controller for vector 0x%lx\n", vec); return (EINVAL); } } #endif return (bus_generic_setup_intr(dev, child, ires, flags, filt, intr, arg, cookiep)); } static struct resource_list * ebus_get_resource_list(device_t dev, device_t child) { struct ebus_devinfo *edi; edi = device_get_ivars(child); return (&edi->edi_rl); } static const struct ofw_bus_devinfo * ebus_get_devinfo(device_t bus, device_t dev) { struct ebus_devinfo *edi; edi = device_get_ivars(dev); return (&edi->edi_obdinfo); } static struct ebus_devinfo * ebus_setup_dinfo(device_t dev, struct ebus_softc *sc, phandle_t node) { struct isa_regs reg, *regs; ofw_isa_intr_t intr, *intrs; struct ebus_devinfo *edi; uint64_t start; uint32_t rintr; int i, nintr, nreg, rv; edi = malloc(sizeof(*edi), M_DEVBUF, M_ZERO | M_WAITOK); if (ofw_bus_gen_setup_devinfo(&edi->edi_obdinfo, node) != 0) { free(edi, M_DEVBUF); return (NULL); } resource_list_init(&edi->edi_rl); nreg = OF_getprop_alloc(node, "reg", sizeof(*regs), (void **)®s); if (nreg == -1) { device_printf(dev, "<%s>: incomplete\n", edi->edi_obdinfo.obd_name); ebus_destroy_dinfo(edi); return (NULL); } for (i = 0; i < nreg; i++) { start = ISA_REG_PHYS(regs + i); (void)resource_list_add(&edi->edi_rl, SYS_RES_MEMORY, i, start, start + regs[i].size - 1, regs[i].size); } - free(regs, M_OFWPROP); + OF_prop_free(regs); nintr = OF_getprop_alloc(node, "interrupts", sizeof(*intrs), (void **)&intrs); if (nintr == -1) return (edi); for (i = 0; i < nintr; i++) { rv = 0; if ((sc->sc_flags & EBUS_PCI) != 0) { rintr = ofw_isa_route_intr(dev, node, &sc->sc_iinfo, intrs[i]); } else { intr = intrs[i]; rv = ofw_bus_lookup_imap(node, &sc->sc_iinfo, ®, sizeof(reg), &intr, sizeof(intr), &rintr, sizeof(rintr), NULL); #ifndef SUN4V if (rv != 0) rintr = INTMAP_VEC(sc->sc_ign, rintr); #endif } if ((sc->sc_flags & EBUS_PCI) == 0 ? rv == 0 : rintr == PCI_INVALID_IRQ) { device_printf(dev, "<%s>: could not map EBus interrupt %d\n", edi->edi_obdinfo.obd_name, intrs[i]); continue; } (void)resource_list_add(&edi->edi_rl, SYS_RES_IRQ, i, rintr, rintr, 1); } - free(intrs, M_OFWPROP); + OF_prop_free(intrs); return (edi); } static void ebus_destroy_dinfo(struct ebus_devinfo *edi) { resource_list_free(&edi->edi_rl); ofw_bus_gen_destroy_devinfo(&edi->edi_obdinfo); free(edi, M_DEVBUF); } static int ebus_print_res(struct ebus_devinfo *edi) { int retval; retval = 0; retval += resource_list_print_type(&edi->edi_rl, "addr", SYS_RES_MEMORY, "%#jx"); retval += resource_list_print_type(&edi->edi_rl, "irq", SYS_RES_IRQ, "%jd"); return (retval); } Index: head/sys/sparc64/fhc/fhc.c =================================================================== --- head/sys/sparc64/fhc/fhc.c (revision 300172) +++ head/sys/sparc64/fhc/fhc.c (revision 300173) @@ -1,535 +1,535 @@ /*- * Copyright (c) 2003 Jake Burkholder. * Copyright (c) 2005 Marius Strobl * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include struct fhc_devinfo { struct ofw_bus_devinfo fdi_obdinfo; struct resource_list fdi_rl; }; struct fhc_softc { struct resource *sc_memres[FHC_NREG]; int sc_nrange; struct sbus_ranges *sc_ranges; int sc_ign; struct cdev *sc_led_dev; }; static device_probe_t fhc_probe; static device_attach_t fhc_attach; static bus_print_child_t fhc_print_child; static bus_probe_nomatch_t fhc_probe_nomatch; static bus_setup_intr_t fhc_setup_intr; static bus_alloc_resource_t fhc_alloc_resource; static bus_adjust_resource_t fhc_adjust_resource; static bus_get_resource_list_t fhc_get_resource_list; static ofw_bus_get_devinfo_t fhc_get_devinfo; static void fhc_intr_enable(void *); static void fhc_intr_disable(void *); static void fhc_intr_assign(void *); static void fhc_intr_clear(void *); static void fhc_led_func(void *, int); static int fhc_print_res(struct fhc_devinfo *); static device_method_t fhc_methods[] = { /* Device interface */ DEVMETHOD(device_probe, fhc_probe), DEVMETHOD(device_attach, fhc_attach), DEVMETHOD(device_shutdown, bus_generic_shutdown), DEVMETHOD(device_suspend, bus_generic_suspend), DEVMETHOD(device_resume, bus_generic_resume), /* Bus interface */ DEVMETHOD(bus_print_child, fhc_print_child), DEVMETHOD(bus_probe_nomatch, fhc_probe_nomatch), DEVMETHOD(bus_alloc_resource, fhc_alloc_resource), DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), DEVMETHOD(bus_adjust_resource, fhc_adjust_resource), DEVMETHOD(bus_release_resource, bus_generic_rl_release_resource), DEVMETHOD(bus_setup_intr, fhc_setup_intr), DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource), DEVMETHOD(bus_get_resource_list, fhc_get_resource_list), DEVMETHOD(bus_child_pnpinfo_str, ofw_bus_gen_child_pnpinfo_str), /* ofw_bus interface */ DEVMETHOD(ofw_bus_get_devinfo, fhc_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_END }; static driver_t fhc_driver = { "fhc", fhc_methods, sizeof(struct fhc_softc), }; static devclass_t fhc_devclass; EARLY_DRIVER_MODULE(fhc, central, fhc_driver, fhc_devclass, 0, 0, BUS_PASS_BUS); MODULE_DEPEND(fhc, central, 1, 1, 1); EARLY_DRIVER_MODULE(fhc, nexus, fhc_driver, fhc_devclass, 0, 0, BUS_PASS_BUS); MODULE_DEPEND(fhc, nexus, 1, 1, 1); MODULE_VERSION(fhc, 1); static const struct intr_controller fhc_ic = { fhc_intr_enable, fhc_intr_disable, fhc_intr_assign, fhc_intr_clear }; struct fhc_icarg { struct fhc_softc *fica_sc; struct resource *fica_memres; }; static int fhc_probe(device_t dev) { if (strcmp(ofw_bus_get_name(dev), "fhc") == 0) { device_set_desc(dev, "fhc"); return (0); } return (ENXIO); } static int fhc_attach(device_t dev) { char ledname[sizeof("boardXX")]; struct fhc_devinfo *fdi; struct fhc_icarg *fica; struct fhc_softc *sc; struct sbus_regs *reg; phandle_t child; phandle_t node; device_t cdev; uint32_t board; uint32_t ctrl; uint32_t *intr; uint32_t iv; char *name; int central; int error; int i; int j; sc = device_get_softc(dev); node = ofw_bus_get_node(dev); central = 0; if (strcmp(device_get_name(device_get_parent(dev)), "central") == 0) central = 1; for (i = 0; i < FHC_NREG; i++) { j = i; sc->sc_memres[i] = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &j, RF_ACTIVE); if (sc->sc_memres[i] == NULL) { device_printf(dev, "cannot allocate resource %d\n", i); error = ENXIO; goto fail_memres; } } if (central != 0) { board = bus_read_4(sc->sc_memres[FHC_INTERNAL], FHC_BSR); board = ((board >> 16) & 0x1) | ((board >> 12) & 0xe); } else { if (OF_getprop(node, "board#", &board, sizeof(board)) == -1) { device_printf(dev, "cannot get board number\n"); error = ENXIO; goto fail_memres; } } device_printf(dev, "board %d, ", board); if (OF_getprop_alloc(node, "board-model", 1, (void **)&name) != -1) { printf("model %s\n", name); - free(name, M_OFWPROP); + OF_prop_free(name); } else printf("model unknown\n"); for (i = FHC_FANFAIL; i <= FHC_TOD; i++) { bus_write_4(sc->sc_memres[i], FHC_ICLR, INTCLR_IDLE); (void)bus_read_4(sc->sc_memres[i], FHC_ICLR); } sc->sc_ign = board << 1; bus_write_4(sc->sc_memres[FHC_IGN], 0x0, sc->sc_ign); sc->sc_ign = bus_read_4(sc->sc_memres[FHC_IGN], 0x0); ctrl = bus_read_4(sc->sc_memres[FHC_INTERNAL], FHC_CTRL); if (central == 0) ctrl |= FHC_CTRL_IXIST; ctrl &= ~(FHC_CTRL_AOFF | FHC_CTRL_BOFF | FHC_CTRL_SLINE); bus_write_4(sc->sc_memres[FHC_INTERNAL], FHC_CTRL, ctrl); (void)bus_read_4(sc->sc_memres[FHC_INTERNAL], FHC_CTRL); sc->sc_nrange = OF_getprop_alloc(node, "ranges", sizeof(*sc->sc_ranges), (void **)&sc->sc_ranges); if (sc->sc_nrange == -1) { device_printf(dev, "cannot get ranges\n"); error = ENXIO; goto fail_memres; } /* * Apparently only the interrupt controller of boards hanging off * of central(4) is indented to be used, otherwise we would have * conflicts registering the interrupt controllers for all FHC * boards as the board number and thus the IGN isn't unique. */ if (central == 1) { /* * Hunt through all the interrupt mapping regs and register * our interrupt controller for the corresponding interrupt * vectors. We do this early in order to be able to catch * stray interrupts. */ for (i = FHC_FANFAIL; i <= FHC_TOD; i++) { fica = malloc(sizeof(*fica), M_DEVBUF, M_NOWAIT); if (fica == NULL) panic("%s: could not allocate interrupt " "controller argument", __func__); fica->fica_sc = sc; fica->fica_memres = sc->sc_memres[i]; #ifdef FHC_DEBUG device_printf(dev, "intr map %d: %#lx, clr: %#lx\n", i, (u_long)bus_read_4(fica->fica_memres, FHC_IMAP), (u_long)bus_read_4(fica->fica_memres, FHC_ICLR)); #endif /* * XXX we only pick the INO rather than the INR * from the IMR since the firmware may not provide * the IGN and the IGN is constant for all devices * on that FireHose controller. */ j = intr_controller_register(INTMAP_VEC(sc->sc_ign, INTINO(bus_read_4(fica->fica_memres, FHC_IMAP))), &fhc_ic, fica); if (j != 0) device_printf(dev, "could not register " "interrupt controller for map %d (%d)\n", i, j); } } else { snprintf(ledname, sizeof(ledname), "board%d", board); sc->sc_led_dev = led_create(fhc_led_func, sc, ledname); } for (child = OF_child(node); child != 0; child = OF_peer(child)) { fdi = malloc(sizeof(*fdi), M_DEVBUF, M_WAITOK | M_ZERO); if (ofw_bus_gen_setup_devinfo(&fdi->fdi_obdinfo, child) != 0) { free(fdi, M_DEVBUF); continue; } i = OF_getprop_alloc(child, "reg", sizeof(*reg), (void **)®); if (i == -1) { device_printf(dev, "<%s>: incomplete\n", fdi->fdi_obdinfo.obd_name); ofw_bus_gen_destroy_devinfo(&fdi->fdi_obdinfo); free(fdi, M_DEVBUF); continue; } resource_list_init(&fdi->fdi_rl); for (j = 0; j < i; j++) resource_list_add(&fdi->fdi_rl, SYS_RES_MEMORY, j, reg[j].sbr_offset, reg[j].sbr_offset + reg[j].sbr_size, reg[j].sbr_size); - free(reg, M_OFWPROP); + OF_prop_free(reg); if (central == 1) { i = OF_getprop_alloc(child, "interrupts", sizeof(*intr), (void **)&intr); if (i != -1) { for (j = 0; j < i; j++) { iv = INTMAP_VEC(sc->sc_ign, intr[j]); resource_list_add(&fdi->fdi_rl, SYS_RES_IRQ, j, iv, iv, 1); } - free(intr, M_OFWPROP); + OF_prop_free(intr); } } cdev = device_add_child(dev, NULL, -1); if (cdev == NULL) { device_printf(dev, "<%s>: device_add_child failed\n", fdi->fdi_obdinfo.obd_name); resource_list_free(&fdi->fdi_rl); ofw_bus_gen_destroy_devinfo(&fdi->fdi_obdinfo); free(fdi, M_DEVBUF); continue; } device_set_ivars(cdev, fdi); } return (bus_generic_attach(dev)); fail_memres: for (i = 0; i < FHC_NREG; i++) if (sc->sc_memres[i] != NULL) bus_release_resource(dev, SYS_RES_MEMORY, rman_get_rid(sc->sc_memres[i]), sc->sc_memres[i]); return (error); } static int fhc_print_child(device_t dev, device_t child) { int rv; rv = bus_print_child_header(dev, child); rv += fhc_print_res(device_get_ivars(child)); rv += bus_print_child_footer(dev, child); return (rv); } static void fhc_probe_nomatch(device_t dev, device_t child) { const char *type; device_printf(dev, "<%s>", ofw_bus_get_name(child)); fhc_print_res(device_get_ivars(child)); type = ofw_bus_get_type(child); printf(" type %s (no driver attached)\n", type != NULL ? type : "unknown"); } static void fhc_intr_enable(void *arg) { struct intr_vector *iv = arg; struct fhc_icarg *fica = iv->iv_icarg; bus_write_4(fica->fica_memres, FHC_IMAP, INTMAP_ENABLE(iv->iv_vec, iv->iv_mid)); (void)bus_read_4(fica->fica_memres, FHC_IMAP); } static void fhc_intr_disable(void *arg) { struct intr_vector *iv = arg; struct fhc_icarg *fica = iv->iv_icarg; bus_write_4(fica->fica_memres, FHC_IMAP, iv->iv_vec); (void)bus_read_4(fica->fica_memres, FHC_IMAP); } static void fhc_intr_assign(void *arg) { struct intr_vector *iv = arg; struct fhc_icarg *fica = iv->iv_icarg; bus_write_4(fica->fica_memres, FHC_IMAP, INTMAP_TID( bus_read_4(fica->fica_memres, FHC_IMAP), iv->iv_mid)); (void)bus_read_4(fica->fica_memres, FHC_IMAP); } static void fhc_intr_clear(void *arg) { struct intr_vector *iv = arg; struct fhc_icarg *fica = iv->iv_icarg; bus_write_4(fica->fica_memres, FHC_ICLR, INTCLR_IDLE); (void)bus_read_4(fica->fica_memres, FHC_ICLR); } static int fhc_setup_intr(device_t bus, device_t child, struct resource *r, int flags, driver_filter_t *filt, driver_intr_t *func, void *arg, void **cookiep) { struct fhc_softc *sc; u_long vec; sc = device_get_softc(bus); /* * Make sure the vector is fully specified and we registered * our interrupt controller for it. */ vec = rman_get_start(r); if (INTIGN(vec) != sc->sc_ign || intr_vectors[vec].iv_ic != &fhc_ic) { device_printf(bus, "invalid interrupt vector 0x%lx\n", vec); return (EINVAL); } return (bus_generic_setup_intr(bus, child, r, flags, filt, func, arg, cookiep)); } static struct resource * fhc_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 resource_list *rl; struct resource_list_entry *rle; struct fhc_softc *sc; struct resource *res; bus_addr_t coffset; bus_addr_t cend; bus_addr_t phys; int isdefault; int passthrough; int i; isdefault = RMAN_IS_DEFAULT_RANGE(start, end); passthrough = (device_get_parent(child) != bus); res = NULL; rle = NULL; rl = BUS_GET_RESOURCE_LIST(bus, child); sc = device_get_softc(bus); switch (type) { case SYS_RES_IRQ: return (resource_list_alloc(rl, bus, child, type, rid, start, end, count, flags)); case SYS_RES_MEMORY: if (!passthrough) { rle = resource_list_find(rl, type, *rid); if (rle == NULL) return (NULL); if (rle->res != NULL) panic("%s: resource entry is busy", __func__); if (isdefault) { start = rle->start; count = ulmax(count, rle->count); end = ulmax(rle->end, start + count - 1); } } for (i = 0; i < sc->sc_nrange; i++) { coffset = sc->sc_ranges[i].coffset; cend = coffset + sc->sc_ranges[i].size - 1; if (start >= coffset && end <= cend) { start -= coffset; end -= coffset; phys = sc->sc_ranges[i].poffset | ((bus_addr_t)sc->sc_ranges[i].pspace << 32); res = bus_generic_alloc_resource(bus, child, type, rid, phys + start, phys + end, count, flags); if (!passthrough) rle->res = res; break; } } break; } return (res); } static int fhc_adjust_resource(device_t bus __unused, device_t child __unused, int type __unused, struct resource *r __unused, rman_res_t start __unused, rman_res_t end __unused) { return (ENXIO); } static struct resource_list * fhc_get_resource_list(device_t bus, device_t child) { struct fhc_devinfo *fdi; fdi = device_get_ivars(child); return (&fdi->fdi_rl); } static const struct ofw_bus_devinfo * fhc_get_devinfo(device_t bus, device_t child) { struct fhc_devinfo *fdi; fdi = device_get_ivars(child); return (&fdi->fdi_obdinfo); } static void fhc_led_func(void *arg, int onoff) { struct fhc_softc *sc; uint32_t ctrl; sc = (struct fhc_softc *)arg; ctrl = bus_read_4(sc->sc_memres[FHC_INTERNAL], FHC_CTRL); if (onoff) ctrl |= FHC_CTRL_RLED; else ctrl &= ~FHC_CTRL_RLED; ctrl &= ~(FHC_CTRL_AOFF | FHC_CTRL_BOFF | FHC_CTRL_SLINE); bus_write_4(sc->sc_memres[FHC_INTERNAL], FHC_CTRL, ctrl); (void)bus_read_4(sc->sc_memres[FHC_INTERNAL], FHC_CTRL); } static int fhc_print_res(struct fhc_devinfo *fdi) { int rv; rv = 0; rv += resource_list_print_type(&fdi->fdi_rl, "mem", SYS_RES_MEMORY, "%#jx"); rv += resource_list_print_type(&fdi->fdi_rl, "irq", SYS_RES_IRQ, "%jd"); return (rv); } Index: head/sys/sparc64/isa/isa.c =================================================================== --- head/sys/sparc64/isa/isa.c (revision 300172) +++ head/sys/sparc64/isa/isa.c (revision 300173) @@ -1,361 +1,361 @@ /*- * Copyright (c) 1998 Doug Rabson * Copyright (c) 2001 Thomas Moestl * 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. * * from: FreeBSD: src/sys/alpha/isa/isa.c,v 1.26 2001/07/11 */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* There can be only one ISA bus, so it is safe to use globals. */ static u_int64_t isa_io_base; static u_int64_t isa_io_limit; static u_int64_t isa_mem_base; static u_int64_t isa_mem_limit; device_t isa_bus_device; static phandle_t isab_node; static struct isa_ranges *isab_ranges; static int isab_nrange; static struct ofw_bus_iinfo isa_iinfo; /* * XXX: This is really partly PCI-specific, but unfortunately is * differently enough to have to duplicate it here... */ #define ISAB_RANGE_PHYS(r) \ (((u_int64_t)(r)->phys_mid << 32) | (u_int64_t)(r)->phys_lo) #define ISAB_RANGE_SPACE(r) (((r)->phys_hi >> 24) & 0x03) #define ISAR_SPACE_IO 0x01 #define ISAR_SPACE_MEM 0x02 #define INRANGE(x, start, end) ((x) >= (start) && (x) <= (end)) static void isa_setup_children(device_t, phandle_t); void isa_init(device_t dev) { device_t bridge; int i; /* The parent of the bus must be a PCI-ISA bridge. */ bridge = device_get_parent(dev); isab_node = ofw_bus_get_node(bridge); isab_nrange = OF_getprop_alloc(isab_node, "ranges", sizeof(*isab_ranges), (void **)&isab_ranges); if (isab_nrange <= 0) panic("isa_init: cannot get bridge range property"); ofw_bus_setup_iinfo(isab_node, &isa_iinfo, sizeof(ofw_isa_intr_t)); isa_setup_children(dev, isab_node); for (i = isab_nrange - 1; i >= 0; i--) { switch(ISAB_RANGE_SPACE(&isab_ranges[i])) { case ISAR_SPACE_IO: /* This is probably always 0. */ isa_io_base = ISAB_RANGE_PHYS(&isab_ranges[i]); isa_io_limit = isab_ranges[i].size; break; case ISAR_SPACE_MEM: /* This is probably always 0. */ isa_mem_base = ISAB_RANGE_PHYS(&isab_ranges[i]); isa_mem_limit = isab_ranges[i].size; break; } } } static const struct { const char *const name; uint32_t id; } ofw_isa_pnp_map[] = { { "SUNW,lomh", 0x0000ae4e }, /* SUN0000 */ { "dma", 0x0002d041 }, /* PNP0200 */ { "floppy", 0x0007d041 }, /* PNP0700 */ { "rtc", 0x000bd041 }, /* PNP0B00 */ { "flashprom", 0x0100ae4e }, /* SUN0001 */ { "parallel", 0x0104d041 }, /* PNP0401 */ { "serial", 0x0105d041 }, /* PNP0501 */ { "su", 0x0105d041 }, /* PNP0501 */ { "i2c", 0x0200ae4e }, /* SUN0002 */ { "rmc-comm", 0x0300ae4e }, /* SUN0003 */ { "kb_ps2", 0x0303d041 }, /* PNP0303 */ { "kdmouse", 0x030fd041 }, /* PNP0F03 */ { "bscbus", 0x0400ae4e }, /* SUN0004 */ { "power", 0x0c0cd041 }, /* PNP0C0C */ { NULL, 0x0 } }; static void isa_setup_children(device_t dev, phandle_t parent) { struct isa_regs *regs; struct resource_list *rl; device_t cdev; u_int64_t end, start; ofw_isa_intr_t *intrs, rintr; phandle_t node; uint32_t *drqs, *regidx; int i, ndrq, nintr, nreg, nregidx, rid, rtype; char *name; /* * Loop through children and fake up PnP devices for them. * Their resources are added as fully mapped and specified because * adjusting the resources and the resource list entries respectively * in isa_alloc_resource() causes trouble with drivers which use * rman_get_start(), pass-through or allocate and release resources * multiple times, etc. Adjusting the resources might be better off * in a bus_activate_resource method but the common ISA code doesn't * allow for an isa_activate_resource(). */ for (node = OF_child(parent); node != 0; node = OF_peer(node)) { if ((OF_getprop_alloc(node, "name", 1, (void **)&name)) == -1) continue; /* * Keyboard and mouse controllers hang off of the `8042' * node but we have no real use for the `8042' itself. */ if (strcmp(name, "8042") == 0) { isa_setup_children(dev, node); - free(name, M_OFWPROP); + OF_prop_free(name); continue; } for (i = 0; ofw_isa_pnp_map[i].name != NULL; i++) if (strcmp(ofw_isa_pnp_map[i].name, name) == 0) break; if (ofw_isa_pnp_map[i].name == NULL) { device_printf(dev, "no PnP map entry for node " "0x%lx: %s\n", (unsigned long)node, name); - free(name, M_OFWPROP); + OF_prop_free(name); continue; } if ((cdev = BUS_ADD_CHILD(dev, ISA_ORDER_PNPBIOS, NULL, -1)) == NULL) panic("isa_setup_children: BUS_ADD_CHILD failed"); isa_set_logicalid(cdev, ofw_isa_pnp_map[i].id); isa_set_vendorid(cdev, ofw_isa_pnp_map[i].id); rl = BUS_GET_RESOURCE_LIST(dev, cdev); nreg = OF_getprop_alloc(node, "reg", sizeof(*regs), (void **)®s); for (i = 0; i < nreg; i++) { start = ISA_REG_PHYS(®s[i]); end = start + regs[i].size - 1; rtype = ofw_isa_range_map(isab_ranges, isab_nrange, &start, &end, NULL); rid = 0; while (resource_list_find(rl, rtype, rid) != NULL) rid++; bus_set_resource(cdev, rtype, rid, start, end - start + 1); } if (nreg == -1 && parent != isab_node) { /* * The "reg" property still might be an index into * the set of registers of the parent device like * with the nodes hanging off of the `8042' node. */ nregidx = OF_getprop_alloc(node, "reg", sizeof(*regidx), (void **)®idx); if (nregidx > 2) panic("isa_setup_children: impossible number " "of register indices"); if (nregidx != -1 && (nreg = OF_getprop_alloc(parent, "reg", sizeof(*regs), (void **)®s)) >= nregidx) { for (i = 0; i < nregidx; i++) { start = ISA_REG_PHYS(®s[regidx[i]]); end = start + regs[regidx[i]].size - 1; rtype = ofw_isa_range_map(isab_ranges, isab_nrange, &start, &end, NULL); rid = 0; while (resource_list_find(rl, rtype, rid) != NULL) rid++; bus_set_resource(cdev, rtype, rid, start, end - start + 1); } } if (regidx != NULL) - free(regidx, M_OFWPROP); + OF_prop_free(regidx); } if (regs != NULL) - free(regs, M_OFWPROP); + OF_prop_free(regs); nintr = OF_getprop_alloc(node, "interrupts", sizeof(*intrs), (void **)&intrs); for (i = 0; i < nintr; i++) { if (intrs[i] > 7) panic("isa_setup_children: intr too large"); rintr = ofw_isa_route_intr(device_get_parent(dev), node, &isa_iinfo, intrs[i]); if (rintr == PCI_INVALID_IRQ) { device_printf(dev, "could not map ISA " "interrupt %d for node 0x%lx: %s\n", intrs[i], (unsigned long)node, name); continue; } bus_set_resource(cdev, SYS_RES_IRQ, i, rintr, 1); } if (intrs != NULL) - free(intrs, M_OFWPROP); + OF_prop_free(intrs); ndrq = OF_getprop_alloc(node, "dma-channel", sizeof(*drqs), (void **)&drqs); for (i = 0; i < ndrq; i++) bus_set_resource(cdev, SYS_RES_DRQ, i, drqs[i], 1); if (drqs != NULL) - free(drqs, M_OFWPROP); + OF_prop_free(drqs); /* * Devices using DMA hang off of the `dma' node instead of * directly from the ISA bridge node. */ if (strcmp(name, "dma") == 0) isa_setup_children(dev, node); - free(name, M_OFWPROP); + OF_prop_free(name); } } struct resource * isa_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) { /* * Consider adding a resource definition. */ int passthrough = (device_get_parent(child) != bus); int isdefault = RMAN_IS_DEFAULT_RANGE(start, end); struct resource_list *rl; struct resource_list_entry *rle; u_long base, limit; rl = BUS_GET_RESOURCE_LIST(bus, child); if (!passthrough && !isdefault) { rle = resource_list_find(rl, type, *rid); if (!rle) { if (*rid < 0) return (NULL); switch (type) { case SYS_RES_IRQ: if (*rid >= ISA_NIRQ) return (NULL); break; case SYS_RES_DRQ: if (*rid >= ISA_NDRQ) return (NULL); break; case SYS_RES_MEMORY: if (*rid >= ISA_NMEM) return (NULL); break; case SYS_RES_IOPORT: if (*rid >= ISA_NPORT) return (NULL); break; default: return (NULL); } resource_list_add(rl, type, *rid, start, end, count); } } /* * Sanity check if the resource in the respective entry is fully * mapped and specified and its type allocable. A driver could * have added an out of range resource on its own. */ if (!passthrough) { if ((rle = resource_list_find(rl, type, *rid)) == NULL) return (NULL); base = limit = 0; switch (type) { case SYS_RES_MEMORY: base = isa_mem_base; limit = base + isa_mem_limit; break; case SYS_RES_IOPORT: base = isa_io_base; limit = base + isa_io_limit; break; case SYS_RES_IRQ: if (rle->start != rle->end || rle->start <= 7) return (NULL); break; case SYS_RES_DRQ: break; default: return (NULL); } if (type == SYS_RES_MEMORY || type == SYS_RES_IOPORT) { if (!INRANGE(rle->start, base, limit) || !INRANGE(rle->end, base, limit)) return (NULL); } } return (resource_list_alloc(rl, bus, child, type, rid, start, end, count, flags)); } int isa_release_resource(device_t bus, device_t child, int type, int rid, struct resource *res) { return (bus_generic_rl_release_resource(bus, child, type, rid, res)); } Index: head/sys/sparc64/pci/ofw_pci.c =================================================================== --- head/sys/sparc64/pci/ofw_pci.c (revision 300172) +++ head/sys/sparc64/pci/ofw_pci.c (revision 300173) @@ -1,406 +1,406 @@ /*- * Copyright (c) 1999, 2000 Matthew R. Green * Copyright (c) 2001 - 2003 by Thomas Moestl * Copyright (c) 2005 - 2015 by Marius Strobl * 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. 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 ``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. * * from: NetBSD: psycho.c,v 1.35 2001/09/10 16:17:06 eeh Exp */ #include __FBSDID("$FreeBSD$"); #include "opt_ofw_pci.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include int ofw_pci_attach_common(device_t dev, bus_dma_tag_t dmat, u_long iosize, u_long memsize) { struct ofw_pci_softc *sc; struct ofw_pci_ranges *range; phandle_t node; uint32_t prop_array[2]; u_int i, j, nrange; sc = device_get_softc(dev); node = ofw_bus_get_node(dev); sc->sc_node = node; sc->sc_pci_dmat = dmat; /* Initialize memory and I/O rmans. */ sc->sc_pci_io_rman.rm_type = RMAN_ARRAY; sc->sc_pci_io_rman.rm_descr = "PCI I/O Ports"; if (rman_init(&sc->sc_pci_io_rman) != 0 || rman_manage_region(&sc->sc_pci_io_rman, 0, iosize) != 0) { device_printf(dev, "failed to set up I/O rman\n"); return (ENXIO); } sc->sc_pci_mem_rman.rm_type = RMAN_ARRAY; sc->sc_pci_mem_rman.rm_descr = "PCI Memory"; if (rman_init(&sc->sc_pci_mem_rman) != 0 || rman_manage_region(&sc->sc_pci_mem_rman, 0, memsize) != 0) { device_printf(dev, "failed to set up memory rman\n"); return (ENXIO); } /* * Find the addresses of the various bus spaces. The physical * start addresses of the ranges are the configuration, I/O and * memory handles. There should not be multiple ones of one kind. */ nrange = OF_getprop_alloc(node, "ranges", sizeof(*range), (void **)&range); for (i = 0; i < nrange; i++) { j = OFW_PCI_RANGE_CS(&range[i]); if (sc->sc_pci_bh[j] != 0) { device_printf(dev, "duplicate range for space %d\n", j); - free(range, M_OFWPROP); + OF_prop_free(range); return (EINVAL); } sc->sc_pci_bh[j] = OFW_PCI_RANGE_PHYS(&range[i]); } - free(range, M_OFWPROP); + OF_prop_free(range); /* * Make sure that the expected ranges are actually present. * The OFW_PCI_CS_MEM64 one is not currently used. */ if (sc->sc_pci_bh[OFW_PCI_CS_CONFIG] == 0) { device_printf(dev, "missing CONFIG range\n"); return (ENXIO); } if (sc->sc_pci_bh[OFW_PCI_CS_IO] == 0) { device_printf(dev, "missing IO range\n"); return (ENXIO); } if (sc->sc_pci_bh[OFW_PCI_CS_MEM32] == 0) { device_printf(dev, "missing MEM32 range\n"); return (ENXIO); } /* Allocate our tags. */ sc->sc_pci_iot = sparc64_alloc_bus_tag(NULL, PCI_IO_BUS_SPACE); if (sc->sc_pci_iot == NULL) { device_printf(dev, "could not allocate PCI I/O tag\n"); return (ENXIO); } sc->sc_pci_cfgt = sparc64_alloc_bus_tag(NULL, PCI_CONFIG_BUS_SPACE); if (sc->sc_pci_cfgt == NULL) { device_printf(dev, "could not allocate PCI configuration space tag\n"); return (ENXIO); } /* * Get the bus range from the firmware. */ i = OF_getprop(node, "bus-range", (void *)prop_array, sizeof(prop_array)); if (i == -1) { device_printf(dev, "could not get bus-range\n"); return (ENXIO); } if (i != sizeof(prop_array)) { device_printf(dev, "broken bus-range (%d)", i); return (EINVAL); } sc->sc_pci_secbus = prop_array[0]; sc->sc_pci_subbus = prop_array[1]; if (bootverbose != 0) device_printf(dev, "bus range %u to %u; PCI bus %d\n", sc->sc_pci_secbus, sc->sc_pci_subbus, sc->sc_pci_secbus); ofw_bus_setup_iinfo(node, &sc->sc_pci_iinfo, sizeof(ofw_pci_intr_t)); return (0); } uint32_t ofw_pci_read_config_common(device_t dev, u_int regmax, u_long offset, u_int bus, u_int slot, u_int func, u_int reg, int width) { struct ofw_pci_softc *sc; bus_space_handle_t bh; uint32_t r, wrd; int i; uint16_t shrt; uint8_t byte; sc = device_get_softc(dev); if (bus < sc->sc_pci_secbus || bus > sc->sc_pci_subbus || slot > PCI_SLOTMAX || func > PCI_FUNCMAX || reg > regmax) return (-1); bh = sc->sc_pci_bh[OFW_PCI_CS_CONFIG]; switch (width) { case 1: i = bus_space_peek_1(sc->sc_pci_cfgt, bh, offset, &byte); r = byte; break; case 2: i = bus_space_peek_2(sc->sc_pci_cfgt, bh, offset, &shrt); r = shrt; break; case 4: i = bus_space_peek_4(sc->sc_pci_cfgt, bh, offset, &wrd); r = wrd; break; default: panic("%s: bad width %d", __func__, width); /* NOTREACHED */ } if (i) { #ifdef OFW_PCI_DEBUG printf("%s: read data error reading: %d.%d.%d: 0x%x\n", __func__, bus, slot, func, reg); #endif r = -1; } return (r); } void ofw_pci_write_config_common(device_t dev, u_int regmax, u_long offset, u_int bus, u_int slot, u_int func, u_int reg, uint32_t val, int width) { struct ofw_pci_softc *sc; bus_space_handle_t bh; sc = device_get_softc(dev); if (bus < sc->sc_pci_secbus || bus > sc->sc_pci_subbus || slot > PCI_SLOTMAX || func > PCI_FUNCMAX || reg > regmax) return; bh = sc->sc_pci_bh[OFW_PCI_CS_CONFIG]; switch (width) { case 1: bus_space_write_1(sc->sc_pci_cfgt, bh, offset, val); break; case 2: bus_space_write_2(sc->sc_pci_cfgt, bh, offset, val); break; case 4: bus_space_write_4(sc->sc_pci_cfgt, bh, offset, val); break; default: panic("%s: bad width %d", __func__, width); /* NOTREACHED */ } } ofw_pci_intr_t ofw_pci_route_interrupt_common(device_t bridge, device_t dev, int pin) { struct ofw_pci_softc *sc; struct ofw_pci_register reg; ofw_pci_intr_t pintr, mintr; sc = device_get_softc(bridge); pintr = pin; if (ofw_bus_lookup_imap(ofw_bus_get_node(dev), &sc->sc_pci_iinfo, ®, sizeof(reg), &pintr, sizeof(pintr), &mintr, sizeof(mintr), NULL) != 0) return (mintr); return (PCI_INVALID_IRQ); } void ofw_pci_dmamap_sync_stst_order_common(void) { static u_char buf[VIS_BLOCKSIZE] __aligned(VIS_BLOCKSIZE); register_t reg, s; s = intr_disable(); reg = rd(fprs); wr(fprs, reg | FPRS_FEF, 0); __asm __volatile("stda %%f0, [%0] %1" : : "r" (buf), "n" (ASI_BLK_COMMIT_S)); membar(Sync); wr(fprs, reg, 0); intr_restore(s); } int ofw_pci_read_ivar(device_t dev, device_t child __unused, int which, uintptr_t *result) { struct ofw_pci_softc *sc; switch (which) { case PCIB_IVAR_DOMAIN: *result = device_get_unit(dev); return (0); case PCIB_IVAR_BUS: sc = device_get_softc(dev); *result = sc->sc_pci_secbus; return (0); } return (ENOENT); } struct resource * ofw_pci_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 ofw_pci_softc *sc; struct resource *rv; struct rman *rm; sc = device_get_softc(bus); switch (type) { case SYS_RES_IRQ: /* * XXX: Don't accept blank ranges for now, only single * interrupts. The other case should not happen with * the MI PCI code ... * XXX: This may return a resource that is out of the * range that was specified. Is this correct ...? */ if (start != end) panic("%s: XXX: interrupt range", __func__); return (bus_generic_alloc_resource(bus, child, type, rid, start, end, count, flags)); case SYS_RES_MEMORY: rm = &sc->sc_pci_mem_rman; break; case SYS_RES_IOPORT: rm = &sc->sc_pci_io_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); } return (rv); } int ofw_pci_activate_resource(device_t bus, device_t child, int type, int rid, struct resource *r) { struct ofw_pci_softc *sc; struct bus_space_tag *tag; sc = device_get_softc(bus); switch (type) { case SYS_RES_IRQ: return (bus_generic_activate_resource(bus, child, type, rid, r)); case SYS_RES_MEMORY: tag = sparc64_alloc_bus_tag(r, PCI_MEMORY_BUS_SPACE); if (tag == NULL) return (ENOMEM); rman_set_bustag(r, tag); rman_set_bushandle(r, sc->sc_pci_bh[OFW_PCI_CS_MEM32] + rman_get_start(r)); break; case SYS_RES_IOPORT: rman_set_bustag(r, sc->sc_pci_iot); rman_set_bushandle(r, sc->sc_pci_bh[OFW_PCI_CS_IO] + rman_get_start(r)); break; } return (rman_activate_resource(r)); } int ofw_pci_adjust_resource(device_t bus, device_t child, int type, struct resource *r, rman_res_t start, rman_res_t end) { struct ofw_pci_softc *sc; struct rman *rm; sc = device_get_softc(bus); switch (type) { case SYS_RES_IRQ: return (bus_generic_adjust_resource(bus, child, type, r, start, end)); case SYS_RES_MEMORY: rm = &sc->sc_pci_mem_rman; break; case SYS_RES_IOPORT: rm = &sc->sc_pci_io_rman; break; default: return (EINVAL); } if (rman_is_region_manager(r, rm) == 0) return (EINVAL); return (rman_adjust_resource(r, start, end)); } bus_dma_tag_t ofw_pci_get_dma_tag(device_t bus, device_t child __unused) { struct ofw_pci_softc *sc; sc = device_get_softc(bus); return (sc->sc_pci_dmat); } phandle_t ofw_pci_get_node(device_t bus, device_t child __unused) { struct ofw_pci_softc *sc; sc = device_get_softc(bus); /* We only have one child, the PCI bus, which needs our own node. */ return (sc->sc_node); } Index: head/sys/sparc64/sbus/dma_sbus.c =================================================================== --- head/sys/sparc64/sbus/dma_sbus.c (revision 300172) +++ head/sys/sparc64/sbus/dma_sbus.c (revision 300173) @@ -1,415 +1,415 @@ /* $OpenBSD: dma_sbus.c,v 1.16 2008/06/26 05:42:18 ray Exp $ */ /* $NetBSD: dma_sbus.c,v 1.32 2008/04/28 20:23:57 martin Exp $ */ /*- * Copyright (c) 1998 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Paul Kranenburg. * * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. */ /*- * Copyright (c) 1994 Peter Galbavy. All rights reserved. * Copyright (c) 2005 Marius Strobl . All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include struct dma_devinfo { struct ofw_bus_devinfo ddi_obdinfo; struct resource_list ddi_rl; }; struct dma_softc { struct lsi64854_softc sc_lsi64854; /* base device */ int sc_ign; int sc_slot; }; static devclass_t dma_devclass; static device_probe_t dma_probe; static device_attach_t dma_attach; static bus_print_child_t dma_print_child; static bus_probe_nomatch_t dma_probe_nomatch; static bus_get_resource_list_t dma_get_resource_list; static ofw_bus_get_devinfo_t dma_get_devinfo; static struct dma_devinfo *dma_setup_dinfo(device_t, struct dma_softc *, phandle_t); static void dma_destroy_dinfo(struct dma_devinfo *); static int dma_print_res(struct dma_devinfo *); static device_method_t dma_methods[] = { /* Device interface */ DEVMETHOD(device_probe, dma_probe), DEVMETHOD(device_attach, dma_attach), DEVMETHOD(device_shutdown, bus_generic_shutdown), DEVMETHOD(device_suspend, bus_generic_suspend), DEVMETHOD(device_resume, bus_generic_resume), /* Bus interface */ DEVMETHOD(bus_print_child, dma_print_child), DEVMETHOD(bus_probe_nomatch, dma_probe_nomatch), DEVMETHOD(bus_alloc_resource, bus_generic_rl_alloc_resource), DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), DEVMETHOD(bus_adjust_resource, bus_generic_adjust_resource), DEVMETHOD(bus_release_resource, bus_generic_rl_release_resource), DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource), DEVMETHOD(bus_get_resource_list, dma_get_resource_list), DEVMETHOD(bus_child_pnpinfo_str, ofw_bus_gen_child_pnpinfo_str), /* ofw_bus interface */ DEVMETHOD(ofw_bus_get_devinfo, dma_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_END }; static driver_t dma_driver = { "dma", dma_methods, sizeof(struct dma_softc), }; /* * The probe order is handled by sbus(4) as we don't want the variants * with children to be attached earlier than the stand-alone controllers * in order to generally preserve the OFW device tree order. */ EARLY_DRIVER_MODULE(dma, sbus, dma_driver, dma_devclass, 0, 0, BUS_PASS_DEFAULT); MODULE_DEPEND(dma, sbus, 1, 1, 1); MODULE_VERSION(dma, 1); static int dma_probe(device_t dev) { const char *name; name = ofw_bus_get_name(dev); if (strcmp(name, "espdma") == 0 || strcmp(name, "dma") == 0 || strcmp(name, "ledma") == 0) { device_set_desc_copy(dev, name); return (0); } return (ENXIO); } static int dma_attach(device_t dev) { struct dma_softc *dsc; struct lsi64854_softc *lsc; struct dma_devinfo *ddi; device_t cdev; const char *name; char *cabletype; uint32_t csr; phandle_t child, node; int error, i; dsc = device_get_softc(dev); lsc = &dsc->sc_lsi64854; name = ofw_bus_get_name(dev); node = ofw_bus_get_node(dev); dsc->sc_ign = sbus_get_ign(dev); dsc->sc_slot = sbus_get_slot(dev); i = 0; lsc->sc_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &i, RF_ACTIVE); if (lsc->sc_res == NULL) { device_printf(dev, "cannot allocate resources\n"); return (ENXIO); } if (strcmp(name, "espdma") == 0 || strcmp(name, "dma") == 0) lsc->sc_channel = L64854_CHANNEL_SCSI; else if (strcmp(name, "ledma") == 0) { /* * Check to see which cable type is currently active and * set the appropriate bit in the ledma csr so that it * gets used. If we didn't netboot, the PROM won't have * the "cable-selection" property; default to TP and then * the user can change it via a "media" option to ifconfig. */ csr = L64854_GCSR(lsc); if ((OF_getprop_alloc(node, "cable-selection", 1, (void **)&cabletype)) == -1) { /* assume TP if nothing there */ csr |= E_TP_AUI; } else { if (strcmp(cabletype, "aui") == 0) csr &= ~E_TP_AUI; else csr |= E_TP_AUI; - free(cabletype, M_OFWPROP); + OF_prop_free(cabletype); } L64854_SCSR(lsc, csr); DELAY(20000); /* manual says we need a 20ms delay */ lsc->sc_channel = L64854_CHANNEL_ENET; } else { device_printf(dev, "unsupported DMA channel\n"); error = ENXIO; goto fail_lres; } error = bus_dma_tag_create( bus_get_dma_tag(dev), /* parent */ 1, 0, /* alignment, boundary */ BUS_SPACE_MAXADDR, /* lowaddr */ BUS_SPACE_MAXADDR, /* highaddr */ NULL, NULL, /* filter, filterarg */ BUS_SPACE_MAXSIZE, /* maxsize */ BUS_SPACE_UNRESTRICTED, /* nsegments */ BUS_SPACE_MAXSIZE, /* maxsegsize */ 0, /* flags */ NULL, NULL, /* no locking */ &lsc->sc_parent_dmat); if (error != 0) { device_printf(dev, "cannot allocate parent DMA tag\n"); goto fail_lres; } i = sbus_get_burstsz(dev); lsc->sc_burst = (i & SBUS_BURST_32) ? 32 : (i & SBUS_BURST_16) ? 16 : 0; lsc->sc_dev = dev; /* Attach children. */ i = 0; for (child = OF_child(node); child != 0; child = OF_peer(child)) { if ((ddi = dma_setup_dinfo(dev, dsc, child)) == NULL) continue; if (i != 0) { device_printf(dev, "<%s>: only one child per DMA channel supported\n", ddi->ddi_obdinfo.obd_name); dma_destroy_dinfo(ddi); continue; } if ((cdev = device_add_child(dev, NULL, -1)) == NULL) { device_printf(dev, "<%s>: device_add_child failed\n", ddi->ddi_obdinfo.obd_name); dma_destroy_dinfo(ddi); continue; } device_set_ivars(cdev, ddi); i++; } return (bus_generic_attach(dev)); fail_lres: bus_release_resource(dev, SYS_RES_MEMORY, rman_get_rid(lsc->sc_res), lsc->sc_res); return (error); } static struct dma_devinfo * dma_setup_dinfo(device_t dev, struct dma_softc *dsc, phandle_t node) { struct dma_devinfo *ddi; struct sbus_regs *reg; uint32_t base, iv, *intr; int i, nreg, nintr, slot, rslot; ddi = malloc(sizeof(*ddi), M_DEVBUF, M_WAITOK | M_ZERO); if (ofw_bus_gen_setup_devinfo(&ddi->ddi_obdinfo, node) != 0) { free(ddi, M_DEVBUF); return (NULL); } resource_list_init(&ddi->ddi_rl); slot = -1; nreg = OF_getprop_alloc(node, "reg", sizeof(*reg), (void **)®); if (nreg == -1) { device_printf(dev, "<%s>: incomplete\n", ddi->ddi_obdinfo.obd_name); goto fail; } for (i = 0; i < nreg; i++) { base = reg[i].sbr_offset; if (SBUS_ABS(base)) { rslot = SBUS_ABS_TO_SLOT(base); base = SBUS_ABS_TO_OFFSET(base); } else rslot = reg[i].sbr_slot; if (slot != -1 && slot != rslot) { device_printf(dev, "<%s>: multiple slots\n", ddi->ddi_obdinfo.obd_name); - free(reg, M_OFWPROP); + OF_prop_free(reg); goto fail; } slot = rslot; resource_list_add(&ddi->ddi_rl, SYS_RES_MEMORY, i, base, base + reg[i].sbr_size, reg[i].sbr_size); } - free(reg, M_OFWPROP); + OF_prop_free(reg); if (slot != dsc->sc_slot) { device_printf(dev, "<%s>: parent and child slot do not match\n", ddi->ddi_obdinfo.obd_name); goto fail; } /* * The `interrupts' property contains the SBus interrupt level. */ nintr = OF_getprop_alloc(node, "interrupts", sizeof(*intr), (void **)&intr); if (nintr != -1) { for (i = 0; i < nintr; i++) { iv = intr[i]; /* * SBus card devices need the slot number encoded into * the vector as this is generally not done. */ if ((iv & INTMAP_OBIO_MASK) == 0) iv |= slot << 3; /* Set the IGN as appropriate. */ iv |= dsc->sc_ign << INTMAP_IGN_SHIFT; resource_list_add(&ddi->ddi_rl, SYS_RES_IRQ, i, iv, iv, 1); } - free(intr, M_OFWPROP); + OF_prop_free(intr); } return (ddi); fail: dma_destroy_dinfo(ddi); return (NULL); } static void dma_destroy_dinfo(struct dma_devinfo *dinfo) { resource_list_free(&dinfo->ddi_rl); ofw_bus_gen_destroy_devinfo(&dinfo->ddi_obdinfo); free(dinfo, M_DEVBUF); } static int dma_print_child(device_t dev, device_t child) { int rv; rv = bus_print_child_header(dev, child); rv += dma_print_res(device_get_ivars(child)); rv += bus_print_child_footer(dev, child); return (rv); } static void dma_probe_nomatch(device_t dev, device_t child) { const char *type; device_printf(dev, "<%s>", ofw_bus_get_name(child)); dma_print_res(device_get_ivars(child)); type = ofw_bus_get_type(child); printf(" type %s (no driver attached)\n", type != NULL ? type : "unknown"); } static struct resource_list * dma_get_resource_list(device_t dev, device_t child) { struct dma_devinfo *ddi; ddi = device_get_ivars(child); return (&ddi->ddi_rl); } static const struct ofw_bus_devinfo * dma_get_devinfo(device_t bus, device_t child) { struct dma_devinfo *ddi; ddi = device_get_ivars(child); return (&ddi->ddi_obdinfo); } static int dma_print_res(struct dma_devinfo *ddi) { int rv; rv = 0; rv += resource_list_print_type(&ddi->ddi_rl, "mem", SYS_RES_MEMORY, "%#jx"); rv += resource_list_print_type(&ddi->ddi_rl, "irq", SYS_RES_IRQ, "%jd"); return (rv); } Index: head/sys/sparc64/sbus/sbus.c =================================================================== --- head/sys/sparc64/sbus/sbus.c (revision 300172) +++ head/sys/sparc64/sbus/sbus.c (revision 300173) @@ -1,936 +1,936 @@ /*- * Copyright (c) 1999-2002 Eduardo Horvath * 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. 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 ``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. * * from: NetBSD: sbus.c,v 1.50 2002/06/20 18:26:24 eeh Exp */ /*- * Copyright (c) 2002 by Thomas Moestl . * Copyright (c) 2005 Marius Strobl * 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. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); /* * SBus support. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include struct sbus_devinfo { int sdi_burstsz; int sdi_clockfreq; int sdi_slot; struct ofw_bus_devinfo sdi_obdinfo; struct resource_list sdi_rl; }; /* Range descriptor, allocated for each sc_range. */ struct sbus_rd { bus_addr_t rd_poffset; bus_addr_t rd_pend; int rd_slot; bus_addr_t rd_coffset; bus_addr_t rd_cend; struct rman rd_rman; bus_space_handle_t rd_bushandle; struct resource *rd_res; }; struct sbus_softc { device_t sc_dev; bus_dma_tag_t sc_cdmatag; int sc_clockfreq; /* clock frequency (in Hz) */ int sc_nrange; struct sbus_rd *sc_rd; int sc_burst; /* burst transfer sizes supp. */ struct resource *sc_sysio_res; int sc_ign; /* IGN for this sysio */ struct iommu_state sc_is; /* IOMMU state (iommuvar.h) */ struct resource *sc_ot_ires; void *sc_ot_ihand; struct resource *sc_pf_ires; void *sc_pf_ihand; }; #define SYSIO_READ8(sc, off) \ bus_read_8((sc)->sc_sysio_res, (off)) #define SYSIO_WRITE8(sc, off, v) \ bus_write_8((sc)->sc_sysio_res, (off), (v)) static device_probe_t sbus_probe; static device_attach_t sbus_attach; static bus_print_child_t sbus_print_child; static bus_probe_nomatch_t sbus_probe_nomatch; static bus_read_ivar_t sbus_read_ivar; static bus_get_resource_list_t sbus_get_resource_list; static bus_setup_intr_t sbus_setup_intr; static bus_alloc_resource_t sbus_alloc_resource; static bus_activate_resource_t sbus_activate_resource; static bus_adjust_resource_t sbus_adjust_resource; static bus_release_resource_t sbus_release_resource; static bus_get_dma_tag_t sbus_get_dma_tag; static ofw_bus_get_devinfo_t sbus_get_devinfo; static int sbus_inlist(const char *, const char *const *); static struct sbus_devinfo * sbus_setup_dinfo(device_t, struct sbus_softc *, phandle_t); static void sbus_destroy_dinfo(struct sbus_devinfo *); static void sbus_intr_enable(void *); static void sbus_intr_disable(void *); static void sbus_intr_assign(void *); static void sbus_intr_clear(void *); static int sbus_find_intrmap(struct sbus_softc *, u_int, bus_addr_t *, bus_addr_t *); static driver_intr_t sbus_overtemp; static driver_intr_t sbus_pwrfail; static int sbus_print_res(struct sbus_devinfo *); static device_method_t sbus_methods[] = { /* Device interface */ DEVMETHOD(device_probe, sbus_probe), DEVMETHOD(device_attach, sbus_attach), DEVMETHOD(device_shutdown, bus_generic_shutdown), DEVMETHOD(device_suspend, bus_generic_suspend), DEVMETHOD(device_resume, bus_generic_resume), /* Bus interface */ DEVMETHOD(bus_print_child, sbus_print_child), DEVMETHOD(bus_probe_nomatch, sbus_probe_nomatch), DEVMETHOD(bus_read_ivar, sbus_read_ivar), DEVMETHOD(bus_alloc_resource, sbus_alloc_resource), DEVMETHOD(bus_activate_resource, sbus_activate_resource), DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), DEVMETHOD(bus_adjust_resource, sbus_adjust_resource), DEVMETHOD(bus_release_resource, sbus_release_resource), DEVMETHOD(bus_setup_intr, sbus_setup_intr), DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource), DEVMETHOD(bus_get_resource_list, sbus_get_resource_list), DEVMETHOD(bus_child_pnpinfo_str, ofw_bus_gen_child_pnpinfo_str), DEVMETHOD(bus_get_dma_tag, sbus_get_dma_tag), /* ofw_bus interface */ DEVMETHOD(ofw_bus_get_devinfo, sbus_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_END }; static driver_t sbus_driver = { "sbus", sbus_methods, sizeof(struct sbus_softc), }; static devclass_t sbus_devclass; EARLY_DRIVER_MODULE(sbus, nexus, sbus_driver, sbus_devclass, NULL, NULL, BUS_PASS_BUS); MODULE_DEPEND(sbus, nexus, 1, 1, 1); MODULE_VERSION(sbus, 1); #define OFW_SBUS_TYPE "sbus" #define OFW_SBUS_NAME "sbus" static const struct intr_controller sbus_ic = { sbus_intr_enable, sbus_intr_disable, sbus_intr_assign, sbus_intr_clear }; struct sbus_icarg { struct sbus_softc *sica_sc; bus_addr_t sica_map; bus_addr_t sica_clr; }; static const char *const sbus_order_first[] = { "auxio", "dma", NULL }; static int sbus_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); } static int sbus_probe(device_t dev) { const char *t; t = ofw_bus_get_type(dev); if (((t == NULL || strcmp(t, OFW_SBUS_TYPE) != 0)) && strcmp(ofw_bus_get_name(dev), OFW_SBUS_NAME) != 0) return (ENXIO); device_set_desc(dev, "U2S UPA-SBus bridge"); return (0); } static int sbus_attach(device_t dev) { struct sbus_softc *sc; struct sbus_devinfo *sdi; struct sbus_icarg *sica; struct sbus_ranges *range; struct resource *res; struct resource_list *rl; device_t cdev; bus_addr_t intrclr, intrmap, phys; bus_size_t size; u_long vec; phandle_t child, node; uint32_t prop; int i, j; sc = device_get_softc(dev); sc->sc_dev = dev; node = ofw_bus_get_node(dev); i = 0; sc->sc_sysio_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &i, RF_ACTIVE); if (sc->sc_sysio_res == NULL) panic("%s: cannot allocate device memory", __func__); if (OF_getprop(node, "interrupts", &prop, sizeof(prop)) == -1) panic("%s: cannot get IGN", __func__); sc->sc_ign = INTIGN(prop); /* * Record clock frequency for synchronous SCSI. * IS THIS THE CORRECT DEFAULT?? */ if (OF_getprop(node, "clock-frequency", &prop, sizeof(prop)) == -1) prop = 25000000; sc->sc_clockfreq = prop; prop /= 1000; device_printf(dev, "clock %d.%03d MHz\n", prop / 1000, prop % 1000); /* * Collect address translations from the OBP. */ if ((sc->sc_nrange = OF_getprop_alloc(node, "ranges", sizeof(*range), (void **)&range)) == -1) { panic("%s: error getting ranges property", __func__); } sc->sc_rd = malloc(sizeof(*sc->sc_rd) * sc->sc_nrange, M_DEVBUF, M_NOWAIT | M_ZERO); if (sc->sc_rd == NULL) panic("%s: cannot allocate rmans", __func__); /* * Preallocate all space that the SBus bridge decodes, so that nothing * else gets in the way; set up rmans etc. */ rl = BUS_GET_RESOURCE_LIST(device_get_parent(dev), dev); for (i = 0; i < sc->sc_nrange; i++) { phys = range[i].poffset | ((bus_addr_t)range[i].pspace << 32); size = range[i].size; sc->sc_rd[i].rd_slot = range[i].cspace; sc->sc_rd[i].rd_coffset = range[i].coffset; sc->sc_rd[i].rd_cend = sc->sc_rd[i].rd_coffset + size; j = resource_list_add_next(rl, SYS_RES_MEMORY, phys, phys + size - 1, size); if ((res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &j, RF_ACTIVE)) == NULL) panic("%s: cannot allocate decoded range", __func__); sc->sc_rd[i].rd_bushandle = rman_get_bushandle(res); sc->sc_rd[i].rd_rman.rm_type = RMAN_ARRAY; sc->sc_rd[i].rd_rman.rm_descr = "SBus Device Memory"; if (rman_init(&sc->sc_rd[i].rd_rman) != 0 || rman_manage_region(&sc->sc_rd[i].rd_rman, 0, size) != 0) panic("%s: failed to set up memory rman", __func__); sc->sc_rd[i].rd_poffset = phys; sc->sc_rd[i].rd_pend = phys + size; sc->sc_rd[i].rd_res = res; } - free(range, M_OFWPROP); + OF_prop_free(range); /* * Get the SBus burst transfer size if burst transfers are supported. */ if (OF_getprop(node, "up-burst-sizes", &sc->sc_burst, sizeof(sc->sc_burst)) == -1 || sc->sc_burst == 0) sc->sc_burst = (SBUS_BURST64_DEF << SBUS_BURST64_SHIFT) | SBUS_BURST_DEF; /* initialise the IOMMU */ /* punch in our copies */ sc->sc_is.is_pmaxaddr = IOMMU_MAXADDR(SBUS_IOMMU_BITS); sc->sc_is.is_bustag = rman_get_bustag(sc->sc_sysio_res); sc->sc_is.is_bushandle = rman_get_bushandle(sc->sc_sysio_res); sc->sc_is.is_iommu = SBR_IOMMU; sc->sc_is.is_dtag = SBR_IOMMU_TLB_TAG_DIAG; sc->sc_is.is_ddram = SBR_IOMMU_TLB_DATA_DIAG; sc->sc_is.is_dqueue = SBR_IOMMU_QUEUE_DIAG; sc->sc_is.is_dva = SBR_IOMMU_SVADIAG; sc->sc_is.is_dtcmp = 0; sc->sc_is.is_sb[0] = SBR_STRBUF; sc->sc_is.is_sb[1] = 0; /* * Note: the SBus IOMMU ignores the high bits of an address, so a NULL * DMA pointer will be translated by the first page of the IOTSB. * To detect bugs we'll allocate and ignore the first entry. */ iommu_init(device_get_nameunit(dev), &sc->sc_is, 3, -1, 1); /* Create the DMA tag. */ if (bus_dma_tag_create(bus_get_dma_tag(dev), 8, 0, sc->sc_is.is_pmaxaddr, ~0, NULL, NULL, sc->sc_is.is_pmaxaddr, 0xff, 0xffffffff, 0, NULL, NULL, &sc->sc_cdmatag) != 0) panic("%s: bus_dma_tag_create failed", __func__); /* Customize the tag. */ sc->sc_cdmatag->dt_cookie = &sc->sc_is; sc->sc_cdmatag->dt_mt = &iommu_dma_methods; /* * Hunt through all the interrupt mapping regs and register our * interrupt controller for the corresponding interrupt vectors. * We do this early in order to be able to catch stray interrupts. */ for (i = 0; i <= SBUS_MAX_INO; i++) { if (sbus_find_intrmap(sc, i, &intrmap, &intrclr) == 0) continue; sica = malloc(sizeof(*sica), M_DEVBUF, M_NOWAIT); if (sica == NULL) panic("%s: could not allocate interrupt controller " "argument", __func__); sica->sica_sc = sc; sica->sica_map = intrmap; sica->sica_clr = intrclr; #ifdef SBUS_DEBUG device_printf(dev, "intr map (INO %d, %s) %#lx: %#lx, clr: %#lx\n", i, (i & INTMAP_OBIO_MASK) == 0 ? "SBus slot" : "OBIO", (u_long)intrmap, (u_long)SYSIO_READ8(sc, intrmap), (u_long)intrclr); #endif j = intr_controller_register(INTMAP_VEC(sc->sc_ign, i), &sbus_ic, sica); if (j != 0) device_printf(dev, "could not register interrupt " "controller for INO %d (%d)\n", i, j); } /* Enable the over-temperature and power-fail interrupts. */ i = 4; sc->sc_ot_ires = bus_alloc_resource_any(dev, SYS_RES_IRQ, &i, RF_ACTIVE); if (sc->sc_ot_ires == NULL || INTIGN(vec = rman_get_start(sc->sc_ot_ires)) != sc->sc_ign || INTVEC(SYSIO_READ8(sc, SBR_THERM_INT_MAP)) != vec || intr_vectors[vec].iv_ic != &sbus_ic || bus_setup_intr(dev, sc->sc_ot_ires, INTR_TYPE_MISC | INTR_BRIDGE, NULL, sbus_overtemp, sc, &sc->sc_ot_ihand) != 0) panic("%s: failed to set up temperature interrupt", __func__); i = 3; sc->sc_pf_ires = bus_alloc_resource_any(dev, SYS_RES_IRQ, &i, RF_ACTIVE); if (sc->sc_pf_ires == NULL || INTIGN(vec = rman_get_start(sc->sc_pf_ires)) != sc->sc_ign || INTVEC(SYSIO_READ8(sc, SBR_POWER_INT_MAP)) != vec || intr_vectors[vec].iv_ic != &sbus_ic || bus_setup_intr(dev, sc->sc_pf_ires, INTR_TYPE_MISC | INTR_BRIDGE, NULL, sbus_pwrfail, sc, &sc->sc_pf_ihand) != 0) panic("%s: failed to set up power fail interrupt", __func__); /* Initialize the counter-timer. */ sparc64_counter_init(device_get_nameunit(dev), rman_get_bustag(sc->sc_sysio_res), rman_get_bushandle(sc->sc_sysio_res), SBR_TC0); /* * Loop through ROM children, fixing any relative addresses * and then configuring each device. */ for (child = OF_child(node); child != 0; child = OF_peer(child)) { if ((sdi = sbus_setup_dinfo(dev, sc, child)) == NULL) continue; /* * For devices where there are variants that are actually * split into two SBus devices (as opposed to the first * half of the device being a SBus device and the second * half hanging off of the first one) like 'auxio' and * 'SUNW,fdtwo' or 'dma' and 'esp' probe the SBus device * which is a prerequisite to the driver attaching to the * second one with a lower order. Saves us from dealing * with different probe orders in the respective device * drivers which generally is more hackish. */ cdev = device_add_child_ordered(dev, (OF_child(child) == 0 && sbus_inlist(sdi->sdi_obdinfo.obd_name, sbus_order_first)) ? SBUS_ORDER_FIRST : SBUS_ORDER_NORMAL, NULL, -1); if (cdev == NULL) { device_printf(dev, "<%s>: device_add_child_ordered failed\n", sdi->sdi_obdinfo.obd_name); sbus_destroy_dinfo(sdi); continue; } device_set_ivars(cdev, sdi); } return (bus_generic_attach(dev)); } static struct sbus_devinfo * sbus_setup_dinfo(device_t dev, struct sbus_softc *sc, phandle_t node) { struct sbus_devinfo *sdi; struct sbus_regs *reg; u_int32_t base, iv, *intr; int i, nreg, nintr, slot, rslot; sdi = malloc(sizeof(*sdi), M_DEVBUF, M_ZERO | M_WAITOK); if (ofw_bus_gen_setup_devinfo(&sdi->sdi_obdinfo, node) != 0) { free(sdi, M_DEVBUF); return (NULL); } resource_list_init(&sdi->sdi_rl); slot = -1; nreg = OF_getprop_alloc(node, "reg", sizeof(*reg), (void **)®); if (nreg == -1) { if (sdi->sdi_obdinfo.obd_type == NULL || strcmp(sdi->sdi_obdinfo.obd_type, "hierarchical") != 0) { device_printf(dev, "<%s>: incomplete\n", sdi->sdi_obdinfo.obd_name); goto fail; } } else { for (i = 0; i < nreg; i++) { base = reg[i].sbr_offset; if (SBUS_ABS(base)) { rslot = SBUS_ABS_TO_SLOT(base); base = SBUS_ABS_TO_OFFSET(base); } else rslot = reg[i].sbr_slot; if (slot != -1 && slot != rslot) { device_printf(dev, "<%s>: multiple slots\n", sdi->sdi_obdinfo.obd_name); - free(reg, M_OFWPROP); + OF_prop_free(reg); goto fail; } slot = rslot; resource_list_add(&sdi->sdi_rl, SYS_RES_MEMORY, i, base, base + reg[i].sbr_size, reg[i].sbr_size); } - free(reg, M_OFWPROP); + OF_prop_free(reg); } sdi->sdi_slot = slot; /* * The `interrupts' property contains the SBus interrupt level. */ nintr = OF_getprop_alloc(node, "interrupts", sizeof(*intr), (void **)&intr); if (nintr != -1) { for (i = 0; i < nintr; i++) { iv = intr[i]; /* * SBus card devices need the slot number encoded into * the vector as this is generally not done. */ if ((iv & INTMAP_OBIO_MASK) == 0) iv |= slot << 3; iv = INTMAP_VEC(sc->sc_ign, iv); resource_list_add(&sdi->sdi_rl, SYS_RES_IRQ, i, iv, iv, 1); } - free(intr, M_OFWPROP); + OF_prop_free(intr); } if (OF_getprop(node, "burst-sizes", &sdi->sdi_burstsz, sizeof(sdi->sdi_burstsz)) == -1) sdi->sdi_burstsz = sc->sc_burst; else sdi->sdi_burstsz &= sc->sc_burst; if (OF_getprop(node, "clock-frequency", &sdi->sdi_clockfreq, sizeof(sdi->sdi_clockfreq)) == -1) sdi->sdi_clockfreq = sc->sc_clockfreq; return (sdi); fail: sbus_destroy_dinfo(sdi); return (NULL); } static void sbus_destroy_dinfo(struct sbus_devinfo *dinfo) { resource_list_free(&dinfo->sdi_rl); ofw_bus_gen_destroy_devinfo(&dinfo->sdi_obdinfo); free(dinfo, M_DEVBUF); } static int sbus_print_child(device_t dev, device_t child) { int rv; rv = bus_print_child_header(dev, child); rv += sbus_print_res(device_get_ivars(child)); rv += bus_print_child_footer(dev, child); return (rv); } static void sbus_probe_nomatch(device_t dev, device_t child) { const char *type; device_printf(dev, "<%s>", ofw_bus_get_name(child)); sbus_print_res(device_get_ivars(child)); type = ofw_bus_get_type(child); printf(" type %s (no driver attached)\n", type != NULL ? type : "unknown"); } static int sbus_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) { struct sbus_softc *sc; struct sbus_devinfo *dinfo; sc = device_get_softc(dev); if ((dinfo = device_get_ivars(child)) == NULL) return (ENOENT); switch (which) { case SBUS_IVAR_BURSTSZ: *result = dinfo->sdi_burstsz; break; case SBUS_IVAR_CLOCKFREQ: *result = dinfo->sdi_clockfreq; break; case SBUS_IVAR_IGN: *result = sc->sc_ign; break; case SBUS_IVAR_SLOT: *result = dinfo->sdi_slot; break; default: return (ENOENT); } return (0); } static struct resource_list * sbus_get_resource_list(device_t dev, device_t child) { struct sbus_devinfo *sdi; sdi = device_get_ivars(child); return (&sdi->sdi_rl); } static void sbus_intr_enable(void *arg) { struct intr_vector *iv = arg; struct sbus_icarg *sica = iv->iv_icarg; SYSIO_WRITE8(sica->sica_sc, sica->sica_map, INTMAP_ENABLE(iv->iv_vec, iv->iv_mid)); } static void sbus_intr_disable(void *arg) { struct intr_vector *iv = arg; struct sbus_icarg *sica = iv->iv_icarg; SYSIO_WRITE8(sica->sica_sc, sica->sica_map, iv->iv_vec); } static void sbus_intr_assign(void *arg) { struct intr_vector *iv = arg; struct sbus_icarg *sica = iv->iv_icarg; SYSIO_WRITE8(sica->sica_sc, sica->sica_map, INTMAP_TID( SYSIO_READ8(sica->sica_sc, sica->sica_map), iv->iv_mid)); } static void sbus_intr_clear(void *arg) { struct intr_vector *iv = arg; struct sbus_icarg *sica = iv->iv_icarg; SYSIO_WRITE8(sica->sica_sc, sica->sica_clr, INTCLR_IDLE); } static int sbus_find_intrmap(struct sbus_softc *sc, u_int ino, bus_addr_t *intrmapptr, bus_addr_t *intrclrptr) { bus_addr_t intrclr, intrmap; int i; if (ino > SBUS_MAX_INO) { device_printf(sc->sc_dev, "out of range INO %d requested\n", ino); return (0); } if ((ino & INTMAP_OBIO_MASK) == 0) { intrmap = SBR_SLOT0_INT_MAP + INTSLOT(ino) * 8; intrclr = SBR_SLOT0_INT_CLR + (INTSLOT(ino) * 8 * 8) + (INTPRI(ino) * 8); } else { intrclr = 0; for (i = 0, intrmap = SBR_SCSI_INT_MAP; intrmap <= SBR_RESERVED_INT_MAP; intrmap += 8, i++) { if (INTVEC(SYSIO_READ8(sc, intrmap)) == INTMAP_VEC(sc->sc_ign, ino)) { intrclr = SBR_SCSI_INT_CLR + i * 8; break; } } if (intrclr == 0) return (0); } if (intrmapptr != NULL) *intrmapptr = intrmap; if (intrclrptr != NULL) *intrclrptr = intrclr; return (1); } static int sbus_setup_intr(device_t dev, device_t child, struct resource *ires, int flags, driver_filter_t *filt, driver_intr_t *intr, void *arg, void **cookiep) { struct sbus_softc *sc; u_long vec; sc = device_get_softc(dev); /* * Make sure the vector is fully specified and we registered * our interrupt controller for it. */ vec = rman_get_start(ires); if (INTIGN(vec) != sc->sc_ign || intr_vectors[vec].iv_ic != &sbus_ic) { device_printf(dev, "invalid interrupt vector 0x%lx\n", vec); return (EINVAL); } return (bus_generic_setup_intr(dev, child, ires, flags, filt, intr, arg, cookiep)); } static struct resource * sbus_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 sbus_softc *sc; struct rman *rm; struct resource *rv; struct resource_list *rl; struct resource_list_entry *rle; device_t schild; bus_addr_t toffs; bus_size_t tend; int i, slot; int isdefault, passthrough; isdefault = RMAN_IS_DEFAULT_RANGE(start, end); passthrough = (device_get_parent(child) != bus); rle = NULL; sc = device_get_softc(bus); rl = BUS_GET_RESOURCE_LIST(bus, child); switch (type) { case SYS_RES_IRQ: return (resource_list_alloc(rl, bus, child, type, rid, start, end, count, flags)); case SYS_RES_MEMORY: if (!passthrough) { rle = resource_list_find(rl, type, *rid); if (rle == NULL) return (NULL); if (rle->res != NULL) panic("%s: resource entry is busy", __func__); if (isdefault) { start = rle->start; count = ulmax(count, rle->count); end = ulmax(rle->end, start + count - 1); } } rm = NULL; schild = child; while (device_get_parent(schild) != bus) schild = device_get_parent(schild); slot = sbus_get_slot(schild); for (i = 0; i < sc->sc_nrange; i++) { if (sc->sc_rd[i].rd_slot != slot || start < sc->sc_rd[i].rd_coffset || start > sc->sc_rd[i].rd_cend) continue; /* Disallow cross-range allocations. */ if (end > sc->sc_rd[i].rd_cend) return (NULL); /* We've found the connection to the parent bus */ toffs = start - sc->sc_rd[i].rd_coffset; tend = end - sc->sc_rd[i].rd_coffset; rm = &sc->sc_rd[i].rd_rman; break; } if (rm == NULL) return (NULL); rv = rman_reserve_resource(rm, toffs, tend, 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)) { rman_release_resource(rv); return (NULL); } if (!passthrough) rle->res = rv; return (rv); default: return (NULL); } } static int sbus_activate_resource(device_t bus, device_t child, int type, int rid, struct resource *r) { struct sbus_softc *sc; struct bus_space_tag *tag; int i; switch (type) { case SYS_RES_IRQ: return (bus_generic_activate_resource(bus, child, type, rid, r)); case SYS_RES_MEMORY: sc = device_get_softc(bus); for (i = 0; i < sc->sc_nrange; i++) { if (rman_is_region_manager(r, &sc->sc_rd[i].rd_rman) != 0) { tag = sparc64_alloc_bus_tag(r, SBUS_BUS_SPACE); if (tag == NULL) return (ENOMEM); rman_set_bustag(r, tag); rman_set_bushandle(r, sc->sc_rd[i].rd_bushandle + rman_get_start(r)); return (rman_activate_resource(r)); } } /* FALLTHROUGH */ default: return (EINVAL); } } static int sbus_adjust_resource(device_t bus, device_t child, int type, struct resource *r, rman_res_t start, rman_res_t end) { struct sbus_softc *sc; int i; if (type == SYS_RES_MEMORY) { sc = device_get_softc(bus); for (i = 0; i < sc->sc_nrange; i++) if (rman_is_region_manager(r, &sc->sc_rd[i].rd_rman) != 0) return (rman_adjust_resource(r, start, end)); return (EINVAL); } return (bus_generic_adjust_resource(bus, child, type, r, start, end)); } static int sbus_release_resource(device_t bus, device_t child, int type, int rid, struct resource *r) { struct resource_list *rl; struct resource_list_entry *rle; int error, passthrough; passthrough = (device_get_parent(child) != bus); rl = BUS_GET_RESOURCE_LIST(bus, child); if (type == SYS_RES_MEMORY) { if ((rman_get_flags(r) & RF_ACTIVE) != 0) { error = bus_deactivate_resource(child, type, rid, r); if (error) return (error); } error = rman_release_resource(r); if (error != 0) return (error); if (!passthrough) { rle = resource_list_find(rl, type, rid); KASSERT(rle != NULL, ("%s: resource entry not found!", __func__)); KASSERT(rle->res != NULL, ("%s: resource entry is not busy", __func__)); rle->res = NULL; } return (0); } return (resource_list_release(rl, bus, child, type, rid, r)); } static bus_dma_tag_t sbus_get_dma_tag(device_t bus, device_t child) { struct sbus_softc *sc; sc = device_get_softc(bus); return (sc->sc_cdmatag); } static const struct ofw_bus_devinfo * sbus_get_devinfo(device_t bus, device_t child) { struct sbus_devinfo *sdi; sdi = device_get_ivars(child); return (&sdi->sdi_obdinfo); } /* * Handle an overtemp situation. * * SPARCs have temperature sensors which generate interrupts * if the machine's temperature exceeds a certain threshold. * This handles the interrupt and powers off the machine. * The same needs to be done to PCI controller drivers. */ static void sbus_overtemp(void *arg __unused) { static int shutdown; /* As the interrupt is cleared we may be called multiple times. */ if (shutdown != 0) return; shutdown++; printf("DANGER: OVER TEMPERATURE detected\nShutting down NOW.\n"); shutdown_nice(RB_POWEROFF); } /* Try to shut down in time in case of power failure. */ static void sbus_pwrfail(void *arg __unused) { static int shutdown; /* As the interrupt is cleared we may be called multiple times. */ if (shutdown != 0) return; shutdown++; printf("Power failure detected\nShutting down NOW.\n"); shutdown_nice(RB_POWEROFF); } static int sbus_print_res(struct sbus_devinfo *sdi) { int rv; rv = 0; rv += resource_list_print_type(&sdi->sdi_rl, "mem", SYS_RES_MEMORY, "%#jx"); rv += resource_list_print_type(&sdi->sdi_rl, "irq", SYS_RES_IRQ, "%jd"); return (rv); } Index: head/sys/sparc64/sparc64/nexus.c =================================================================== --- head/sys/sparc64/sparc64/nexus.c (revision 300172) +++ head/sys/sparc64/sparc64/nexus.c (revision 300173) @@ -1,612 +1,612 @@ /*- * Copyright 1998 Massachusetts Institute of Technology * Copyright 2001 by Thomas Moestl . * Copyright 2006 by Marius Strobl . * All rights reserved. * * 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. * * from: FreeBSD: src/sys/i386/i386/nexus.c,v 1.43 2001/02/09 */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* * The nexus (which is a pseudo-bus actually) iterates over the nodes that * hang from the Open Firmware root node and adds them as devices to this bus * (except some special nodes which are excluded) so that drivers can be * attached to them. * * 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 { 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_describe_intr_t nexus_describe_intr; static bus_get_dma_tag_t nexus_get_dma_tag; static bus_get_bus_tag_t nexus_get_bus_tag; 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 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_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_describe_intr, nexus_describe_intr), DEVMETHOD(bus_get_dma_tag, nexus_get_dma_tag), DEVMETHOD(bus_get_bus_tag, nexus_get_bus_tag), /* 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_END }; static devclass_t nexus_devclass; DEFINE_CLASS_0(nexus, nexus_driver, nexus_methods, sizeof(struct nexus_softc)); 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; if (strcmp(device_get_name(device_get_parent(dev)), "root") == 0) { node = OF_peer(0); if (node == -1) panic("%s: OF_peer failed.", __func__); sc = device_get_softc(dev); 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, IV_MAX - 1) != 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); /* * 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; ndi->ndi_obdinfo.obd_name = strdup(name, M_OFWPROP); 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 *type; device_printf(bus, "<%s>", ofw_bus_get_name(child)); nexus_print_res(device_get_ivars(child)); type = ofw_bus_get_type(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, void **cookiep) { int error; if (r == NULL) panic("%s: NULL interrupt resource!", __func__); if ((rman_get_flags(r) & RF_SHAREABLE) == 0) flags |= INTR_EXCL; /* We depend here on rman_activate_resource() being idempotent. */ error = rman_activate_resource(r); if (error) return (error); error = inthand_add(device_get_nameunit(child), rman_get_start(r), filt, intr, arg, flags, cookiep); /* * XXX in case of the AFB/FFB interrupt and a Psycho, Sabre or U2S * bridge enable the interrupt in the respective bridge. */ return (error); } static int nexus_teardown_intr(device_t bus __unused, device_t child __unused, struct resource *r, void *ih) { inthand_remove(rman_get_start(r), ih); return (0); } #ifdef SMP static int nexus_bind_intr(device_t bus __unused, device_t child __unused, struct resource *r, int cpu) { return (intr_bind(rman_get_start(r), cpu)); } #endif static int nexus_describe_intr(device_t bus __unused, device_t child __unused, struct resource *r, void *cookie, const char *descr) { return (intr_describe(rman_get_start(r), cookie, descr)); } 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_softc *sc; struct rman *rm; struct resource *rv; struct resource_list_entry *rle; device_t nexus; int isdefault, passthrough; isdefault = RMAN_IS_DEFAULT_RANGE(start, end); 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) { 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__); if (isdefault) { 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->res = rv; rle->start = rman_get_start(rv); rle->end = rman_get_end(rv); rle->count = rle->end - rle->start + 1; } return (rv); } static int nexus_activate_resource(device_t bus __unused, device_t child __unused, int type, int rid __unused, struct resource *r) { if (type == SYS_RES_MEMORY) { rman_set_bustag(r, &nexus_bustag); rman_set_bushandle(r, rman_get_start(r)); } return (rman_activate_resource(r)); } static int nexus_deactivate_resource(device_t bus __unused, device_t child __unused, int type __unused, int rid __unused, struct resource *r) { return (rman_deactivate_resource(r)); } static int nexus_adjust_resource(device_t bus, device_t child __unused, int type, struct resource *r, rman_res_t start, rman_res_t 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 bus_dma_tag_t nexus_get_dma_tag(device_t bus __unused, device_t child __unused) { return (&nexus_dmatag); } static bus_space_tag_t nexus_get_bus_tag(device_t bus __unused, device_t child __unused) { return (&nexus_bustag); } 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_devinfo *ndi; struct nexus_regs *reg; bus_addr_t phys; bus_size_t size; uint32_t ign; uint32_t *intr; int i; int nintr; int nreg; 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_getprop_alloc(node, "reg", sizeof(*reg), (void **)®); if (nreg == -1) { device_printf(dev, "<%s>: incomplete\n", ndi->ndi_obdinfo.obd_name); goto fail; } for (i = 0; i < nreg; i++) { phys = NEXUS_REG_PHYS(®[i]); size = NEXUS_REG_SIZE(®[i]); /* 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); + OF_prop_free(reg); nintr = OF_getprop_alloc(node, "interrupts", sizeof(*intr), (void **)&intr); if (nintr > 0) { if (OF_getprop(node, PCPU_GET(impl) < CPU_IMPL_ULTRASPARCIII ? "upa-portid" : "portid", &ign, sizeof(ign)) <= 0) { device_printf(dev, "<%s>: could not determine portid\n", ndi->ndi_obdinfo.obd_name); - free(intr, M_OFWPROP); + OF_prop_free(intr); goto fail; } /* XXX 7-bit MID on Starfire */ ign = (ign << INTMAP_IGN_SHIFT) & INTMAP_IGN_MASK; for (i = 0; i < nintr; i++) { intr[i] |= ign; resource_list_add(&ndi->ndi_rl, SYS_RES_IRQ, i, intr[i], intr[i], 1); } - free(intr, M_OFWPROP); + OF_prop_free(intr); } return (ndi); fail: nexus_destroy_dinfo(ndi); return (NULL); } 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, "%#jx"); rv += resource_list_print_type(&ndi->ndi_rl, "irq", SYS_RES_IRQ, "%jd"); return (rv); } Index: head/sys/sparc64/sparc64/upa.c =================================================================== --- head/sys/sparc64/sparc64/upa.c (revision 300172) +++ head/sys/sparc64/sparc64/upa.c (revision 300173) @@ -1,595 +1,595 @@ /*- * Copyright (c) 2006 Marius Strobl * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #define UPA_NREG 3 #define UPA_CFG 0 #define UPA_IMR1 1 #define UPA_IMR2 2 /* UPA_CFG bank */ #define UPA_CFG_UPA0 0x00 /* UPA0 config register */ #define UPA_CFG_UPA1 0x08 /* UPA1 config register */ #define UPA_CFG_IF 0x10 /* interface config register */ #define UPA_CFG_IF_RST 0x00 #define UPA_CFG_IF_POK_RST 0x02 #define UPA_CFG_IF_POK 0x03 #define UPA_CFG_ESTAR 0x18 /* Estar config register */ #define UPA_CFG_ESTAR_SPEED_FULL 0x01 #define UPA_CFG_ESTAR_SPEED_1_2 0x02 #define UPA_CFG_ESTAR_SPEED_1_64 0x40 #define UPA_INO_BASE 0x2a #define UPA_INO_MAX 0x2b struct upa_regs { uint64_t phys; uint64_t size; }; struct upa_ranges { uint64_t child; uint64_t parent; uint64_t size; }; struct upa_devinfo { struct ofw_bus_devinfo udi_obdinfo; struct resource_list udi_rl; }; struct upa_softc { struct resource *sc_res[UPA_NREG]; bus_space_tag_t sc_bt[UPA_NREG]; bus_space_handle_t sc_bh[UPA_NREG]; uint32_t sc_ign; int sc_nrange; struct upa_ranges *sc_ranges; }; #define UPA_READ(sc, reg, off) \ bus_space_read_8((sc)->sc_bt[(reg)], (sc)->sc_bh[(reg)], (off)) #define UPA_WRITE(sc, reg, off, val) \ bus_space_write_8((sc)->sc_bt[(reg)], (sc)->sc_bh[(reg)], (off), (val)) static device_probe_t upa_probe; static device_attach_t upa_attach; static bus_print_child_t upa_print_child; static bus_probe_nomatch_t upa_probe_nomatch; static bus_alloc_resource_t upa_alloc_resource; static bus_adjust_resource_t upa_adjust_resource; static bus_setup_intr_t upa_setup_intr; static bus_get_resource_list_t upa_get_resource_list; static ofw_bus_get_devinfo_t upa_get_devinfo; static void upa_intr_enable(void *); static void upa_intr_disable(void *); static void upa_intr_assign(void *); static struct upa_devinfo *upa_setup_dinfo(device_t, struct upa_softc *, phandle_t, uint32_t); static void upa_destroy_dinfo(struct upa_devinfo *); static int upa_print_res(struct upa_devinfo *); static device_method_t upa_methods[] = { /* Device interface */ DEVMETHOD(device_probe, upa_probe), DEVMETHOD(device_attach, upa_attach), DEVMETHOD(device_shutdown, bus_generic_shutdown), DEVMETHOD(device_suspend, bus_generic_suspend), DEVMETHOD(device_resume, bus_generic_resume), /* Bus interface */ DEVMETHOD(bus_print_child, upa_print_child), DEVMETHOD(bus_probe_nomatch, upa_probe_nomatch), DEVMETHOD(bus_read_ivar, bus_generic_read_ivar), DEVMETHOD(bus_write_ivar, bus_generic_write_ivar), DEVMETHOD(bus_alloc_resource, upa_alloc_resource), DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), DEVMETHOD(bus_adjust_resource, upa_adjust_resource), DEVMETHOD(bus_release_resource, bus_generic_rl_release_resource), DEVMETHOD(bus_setup_intr, upa_setup_intr), DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource), DEVMETHOD(bus_get_resource_list, upa_get_resource_list), DEVMETHOD(bus_child_pnpinfo_str, ofw_bus_gen_child_pnpinfo_str), /* ofw_bus interface */ DEVMETHOD(ofw_bus_get_devinfo, upa_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_END }; static devclass_t upa_devclass; DEFINE_CLASS_0(upa, upa_driver, upa_methods, sizeof(struct upa_softc)); EARLY_DRIVER_MODULE(upa, nexus, upa_driver, upa_devclass, 0, 0, BUS_PASS_BUS); static const struct intr_controller upa_ic = { upa_intr_enable, upa_intr_disable, upa_intr_assign, /* The interrupts are pulse type and thus automatically cleared. */ NULL }; struct upa_icarg { struct upa_softc *uica_sc; u_int uica_imr; }; static int upa_probe(device_t dev) { const char* compat; compat = ofw_bus_get_compat(dev); if (compat != NULL && strcmp(ofw_bus_get_name(dev), "upa") == 0 && strcmp(compat, "upa64s") == 0) { device_set_desc(dev, "UPA bridge"); return (BUS_PROBE_DEFAULT); } return (ENXIO); } static int upa_attach(device_t dev) { struct upa_devinfo *udi; struct upa_icarg *uica; struct upa_softc *sc; phandle_t child, node; device_t cdev; uint32_t portid; int i, imr, j, rid; #if 1 device_t *children, schizo; rman_res_t scount, sstart, ucount, ustart; int nchildren; #endif sc = device_get_softc(dev); node = ofw_bus_get_node(dev); for (i = UPA_CFG; i <= UPA_IMR2; i++) { rid = i; /* * The UPA_IMR{1,2} resources are shared with that of the * Schizo PCI bus B CSR bank. */ #if 0 sc->sc_res[i] = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, ((i == UPA_IMR1 || i == UPA_IMR2) ? RF_SHAREABLE : 0) | RF_ACTIVE); if (sc->sc_res[i] == NULL) { device_printf(dev, "could not allocate resource %d\n", i); goto fail; } sc->sc_bt[i] = rman_get_bustag(sc->sc_res[i]); sc->sc_bh[i] = rman_get_bushandle(sc->sc_res[i]); #else /* * Workaround for the fact that rman(9) only allows to * share resources of the same size. */ if (i == UPA_IMR1 || i == UPA_IMR2) { if (bus_get_resource(dev, SYS_RES_MEMORY, i, &ustart, &ucount) != 0) { device_printf(dev, "could not determine UPA resource\n"); goto fail; } if (device_get_children(device_get_parent(dev), &children, &nchildren) != 0) { device_printf(dev, "could not get children\n"); goto fail; } schizo = NULL; for (j = 0; j < nchildren; j++) { if (ofw_bus_get_type(children[j]) != NULL && strcmp(ofw_bus_get_type(children[j]), "pci") == 0 && ofw_bus_get_compat(children[j]) != NULL && strcmp(ofw_bus_get_compat(children[j]), "pci108e,8001") == 0 && ((bus_get_resource_start(children[j], SYS_RES_MEMORY, 0) >> 20) & 1) == 1) { schizo = children[j]; break; } } free(children, M_TEMP); if (schizo == NULL) { device_printf(dev, "could not find Schizo\n"); goto fail; } if (bus_get_resource(schizo, SYS_RES_MEMORY, 0, &sstart, &scount) != 0) { device_printf(dev, "could not determine Schizo resource\n"); goto fail; } sc->sc_res[i] = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, sstart, sstart + scount - 1, scount, RF_SHAREABLE | RF_ACTIVE); } else sc->sc_res[i] = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (sc->sc_res[i] == NULL) { device_printf(dev, "could not allocate resource %d\n", i); goto fail; } sc->sc_bt[i] = rman_get_bustag(sc->sc_res[i]); sc->sc_bh[i] = rman_get_bushandle(sc->sc_res[i]); if (i == UPA_IMR1 || i == UPA_IMR2) bus_space_subregion(sc->sc_bt[i], sc->sc_bh[i], ustart - sstart, ucount, &sc->sc_bh[i]); #endif } if (OF_getprop(node, "portid", &sc->sc_ign, sizeof(sc->sc_ign)) == -1) { device_printf(dev, "could not determine IGN\n"); goto fail; } sc->sc_nrange = OF_getprop_alloc(node, "ranges", sizeof(*sc->sc_ranges), (void **)&sc->sc_ranges); if (sc->sc_nrange == -1) { device_printf(dev, "could not determine ranges\n"); goto fail; } /* * Hunt through all the interrupt mapping regs and register our * interrupt controller for the corresponding interrupt vectors. * We do this early in order to be able to catch stray interrupts. */ for (i = UPA_INO_BASE; i <= UPA_INO_MAX; i++) { imr = 0; for (j = UPA_IMR1; j <= UPA_IMR2; j++) { if (INTVEC(UPA_READ(sc, j, 0x0)) == INTMAP_VEC(sc->sc_ign, i)) { imr = j; break; } } if (imr == 0) continue; uica = malloc(sizeof(*uica), M_DEVBUF, M_NOWAIT); if (uica == NULL) panic("%s: could not allocate interrupt controller " "argument", __func__); uica->uica_sc = sc; uica->uica_imr = imr; #ifdef UPA_DEBUG device_printf(dev, "intr map (INO %d) IMR%d: %#lx\n", i, imr, (u_long)UPA_READ(sc, imr, 0x0)); #endif j = intr_controller_register(INTMAP_VEC(sc->sc_ign, i), &upa_ic, uica); if (j != 0) device_printf(dev, "could not register interrupt " "controller for INO %d (%d)\n", i, j); } /* Make sure the power level is appropriate for normal operation. */ if (UPA_READ(sc, UPA_CFG, UPA_CFG_IF) != UPA_CFG_IF_POK) { if (bootverbose) device_printf(dev, "applying power\n"); UPA_WRITE(sc, UPA_CFG, UPA_CFG_ESTAR, UPA_CFG_ESTAR_SPEED_1_2); UPA_WRITE(sc, UPA_CFG, UPA_CFG_ESTAR, UPA_CFG_ESTAR_SPEED_FULL); (void)UPA_READ(sc, UPA_CFG, UPA_CFG_ESTAR); UPA_WRITE(sc, UPA_CFG, UPA_CFG_IF, UPA_CFG_IF_POK_RST); (void)UPA_READ(sc, UPA_CFG, UPA_CFG_IF); DELAY(20000); UPA_WRITE(sc, UPA_CFG, UPA_CFG_IF, UPA_CFG_IF_POK); (void)UPA_READ(sc, UPA_CFG, UPA_CFG_IF); } for (child = OF_child(node); child != 0; child = OF_peer(child)) { /* * The `upa-portid' properties of the children are used as * index for the interrupt mapping registers. * The `upa-portid' properties are also used to make up the * INOs of the children as the values contained in their * `interrupts' properties are bogus. */ if (OF_getprop(child, "upa-portid", &portid, sizeof(portid)) == -1) { device_printf(dev, "could not determine upa-portid of child 0x%lx\n", (unsigned long)child); continue; } if (portid > 1) { device_printf(dev, "upa-portid %d of child 0x%lx invalid\n", portid, (unsigned long)child); continue; } if ((udi = upa_setup_dinfo(dev, sc, child, portid)) == NULL) continue; if ((cdev = device_add_child(dev, NULL, -1)) == NULL) { device_printf(dev, "<%s>: device_add_child failed\n", udi->udi_obdinfo.obd_name); upa_destroy_dinfo(udi); continue; } device_set_ivars(cdev, udi); } return (bus_generic_attach(dev)); fail: for (i = UPA_CFG; i <= UPA_IMR2 && sc->sc_res[i] != NULL; i++) bus_release_resource(dev, SYS_RES_MEMORY, rman_get_rid(sc->sc_res[i]), sc->sc_res[i]); return (ENXIO); } static int upa_print_child(device_t dev, device_t child) { int rv; rv = bus_print_child_header(dev, child); rv += upa_print_res(device_get_ivars(child)); rv += bus_print_child_footer(dev, child); return (rv); } static void upa_probe_nomatch(device_t dev, device_t child) { const char *type; device_printf(dev, "<%s>", ofw_bus_get_name(child)); upa_print_res(device_get_ivars(child)); type = ofw_bus_get_type(child); printf(" type %s (no driver attached)\n", type != NULL ? type : "unknown"); } static struct resource * upa_alloc_resource(device_t dev, device_t child, int type, int *rid, rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) { struct resource_list *rl; struct resource_list_entry *rle; struct upa_softc *sc; struct resource *rv; bus_addr_t cend, cstart; int i, isdefault, passthrough; isdefault = RMAN_IS_DEFAULT_RANGE(start, end); passthrough = (device_get_parent(child) != dev); sc = device_get_softc(dev); rl = BUS_GET_RESOURCE_LIST(dev, child); rle = NULL; switch (type) { case SYS_RES_IRQ: return (resource_list_alloc(rl, dev, child, type, rid, start, end, count, flags)); case SYS_RES_MEMORY: if (!passthrough) { rle = resource_list_find(rl, type, *rid); if (rle == NULL) return (NULL); if (rle->res != NULL) panic("%s: resource entry is busy", __func__); if (isdefault) { start = rle->start; count = ulmax(count, rle->count); end = ulmax(rle->end, start + count - 1); } } for (i = 0; i < sc->sc_nrange; i++) { cstart = sc->sc_ranges[i].child; cend = cstart + sc->sc_ranges[i].size - 1; if (start < cstart || start > cend) continue; if (end < cstart || end > cend) return (NULL); start += sc->sc_ranges[i].parent - cstart; end += sc->sc_ranges[i].parent - cstart; rv = bus_generic_alloc_resource(dev, child, type, rid, start, end, count, flags); if (!passthrough) rle->res = rv; return (rv); } /* FALLTHROUGH */ default: return (NULL); } } static void upa_intr_enable(void *arg) { struct intr_vector *iv = arg; struct upa_icarg *uica = iv->iv_icarg; UPA_WRITE(uica->uica_sc, uica->uica_imr, 0x0, INTMAP_ENABLE(iv->iv_vec, iv->iv_mid)); (void)UPA_READ(uica->uica_sc, uica->uica_imr, 0x0); } static void upa_intr_disable(void *arg) { struct intr_vector *iv = arg; struct upa_icarg *uica = iv->iv_icarg; UPA_WRITE(uica->uica_sc, uica->uica_imr, 0x0, iv->iv_vec); (void)UPA_READ(uica->uica_sc, uica->uica_imr, 0x0); } static void upa_intr_assign(void *arg) { struct intr_vector *iv = arg; struct upa_icarg *uica = iv->iv_icarg; UPA_WRITE(uica->uica_sc, uica->uica_imr, 0x0, INTMAP_TID( UPA_READ(uica->uica_sc, uica->uica_imr, 0x0), iv->iv_mid)); (void)UPA_READ(uica->uica_sc, uica->uica_imr, 0x0); } static int upa_setup_intr(device_t dev, device_t child, struct resource *ires, int flags, driver_filter_t *filt, driver_intr_t *func, void *arg, void **cookiep) { struct upa_softc *sc; u_long vec; sc = device_get_softc(dev); /* * Make sure the vector is fully specified and we registered * our interrupt controller for it. */ vec = rman_get_start(ires); if (INTIGN(vec) != sc->sc_ign || intr_vectors[vec].iv_ic != &upa_ic) { device_printf(dev, "invalid interrupt vector 0x%lx\n", vec); return (EINVAL); } return (bus_generic_setup_intr(dev, child, ires, flags, filt, func, arg, cookiep)); } static int upa_adjust_resource(device_t bus __unused, device_t child __unused, int type __unused, struct resource *r __unused, rman_res_t start __unused, rman_res_t end __unused) { return (ENXIO); } static struct resource_list * upa_get_resource_list(device_t dev, device_t child) { struct upa_devinfo *udi; udi = device_get_ivars(child); return (&udi->udi_rl); } static const struct ofw_bus_devinfo * upa_get_devinfo(device_t dev, device_t child) { struct upa_devinfo *udi; udi = device_get_ivars(child); return (&udi->udi_obdinfo); } static struct upa_devinfo * upa_setup_dinfo(device_t dev, struct upa_softc *sc, phandle_t node, uint32_t portid) { struct upa_devinfo *udi; struct upa_regs *reg; uint32_t intr; int i, nreg; udi = malloc(sizeof(*udi), M_DEVBUF, M_WAITOK | M_ZERO); if (ofw_bus_gen_setup_devinfo(&udi->udi_obdinfo, node) != 0) { free(udi, M_DEVBUF); return (NULL); } resource_list_init(&udi->udi_rl); nreg = OF_getprop_alloc(node, "reg", sizeof(*reg), (void **)®); if (nreg == -1) { device_printf(dev, "<%s>: incomplete\n", udi->udi_obdinfo.obd_name); goto fail; } for (i = 0; i < nreg; i++) resource_list_add(&udi->udi_rl, SYS_RES_MEMORY, i, reg[i].phys, reg[i].phys + reg[i].size - 1, reg[i].size); - free(reg, M_OFWPROP); + OF_prop_free(reg); intr = INTMAP_VEC(sc->sc_ign, (UPA_INO_BASE + portid)); resource_list_add(&udi->udi_rl, SYS_RES_IRQ, 0, intr, intr, 1); return (udi); fail: upa_destroy_dinfo(udi); return (NULL); } static void upa_destroy_dinfo(struct upa_devinfo *dinfo) { resource_list_free(&dinfo->udi_rl); ofw_bus_gen_destroy_devinfo(&dinfo->udi_obdinfo); free(dinfo, M_DEVBUF); } static int upa_print_res(struct upa_devinfo *udi) { int rv; rv = 0; rv += resource_list_print_type(&udi->udi_rl, "mem", SYS_RES_MEMORY, "%#jx"); rv += resource_list_print_type(&udi->udi_rl, "irq", SYS_RES_IRQ, "%jd"); return (rv); }