diff options
author | ian <ian@FreeBSD.org> | 2014-05-13 18:14:31 +0000 |
---|---|---|
committer | ian <ian@FreeBSD.org> | 2014-05-13 18:14:31 +0000 |
commit | df87ef4409cb490afdc59c478977230d37fe06bc (patch) | |
tree | 078f5e95a03bf897594bab1202e256dc79cf1fb2 /sys | |
parent | 0c0ccc18b558b64b51e095ffa5f7841077e706a3 (diff) | |
download | FreeBSD-src-df87ef4409cb490afdc59c478977230d37fe06bc.zip FreeBSD-src-df87ef4409cb490afdc59c478977230d37fe06bc.tar.gz |
MFC r257114, r257118
Use common OFW root code to set up fdtbus. This is an almost purely
negative diff that should improve reliability somewhat. There should be
no differences in behavior -- please report any that crop up. This has been
tested on ARM and PPC systems.
Make sure to get the right node when looking up #interrupt-cells.
Diffstat (limited to 'sys')
-rw-r--r-- | sys/conf/files | 1 | ||||
-rw-r--r-- | sys/dev/fdt/fdtbus.c | 562 | ||||
-rw-r--r-- | sys/dev/ofw/ofw_nexus.c | 4 |
3 files changed, 12 insertions, 555 deletions
diff --git a/sys/conf/files b/sys/conf/files index 6961b1b..65937d4 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -1969,6 +1969,7 @@ dev/ofw/ofw_bus_subr.c optional fdt dev/ofw/ofw_fdt.c optional fdt dev/ofw/ofw_if.m optional fdt dev/ofw/ofw_iicbus.c optional fdt iicbus +dev/ofw/ofw_nexus.c optional fdt dev/ofw/openfirm.c optional fdt dev/ofw/openfirmio.c optional fdt dev/patm/if_patm.c optional patm pci diff --git a/sys/dev/fdt/fdtbus.c b/sys/dev/fdt/fdtbus.c index f113b8e..3a6659a 100644 --- a/sys/dev/fdt/fdtbus.c +++ b/sys/dev/fdt/fdtbus.c @@ -42,63 +42,20 @@ __FBSDID("$FreeBSD$"); #include <machine/fdt.h> #include <dev/ofw/openfirm.h> +#include <dev/ofw/ofw_nexus.h> -#include "fdt_common.h" #include "ofw_bus_if.h" -#ifdef DEBUG -#define debugf(fmt, args...) do { printf("%s(): ", __func__); \ - printf(fmt,##args); } while (0) -#else -#define debugf(fmt, args...) -#endif - -static MALLOC_DEFINE(M_FDTBUS, "fdtbus", "FDTbus devices information"); - -struct fdtbus_devinfo { - phandle_t di_node; - char *di_name; - char *di_type; - char *di_compat; - struct resource_list di_res; - - /* Interrupts sense-level info for this device */ - struct fdt_sense_level di_intr_sl[DI_MAX_INTR_NUM]; -}; - -struct fdtbus_softc { - struct rman sc_irq; - struct rman sc_mem; -}; - /* * Prototypes. */ static void fdtbus_identify(driver_t *, device_t); static int fdtbus_probe(device_t); -static int fdtbus_attach(device_t); -static int fdtbus_print_child(device_t, device_t); -static struct resource *fdtbus_alloc_resource(device_t, device_t, int, - int *, u_long, u_long, u_long, u_int); -static int fdtbus_release_resource(device_t, device_t, int, int, - struct resource *); static int fdtbus_activate_resource(device_t, device_t, int, int, struct resource *); static int fdtbus_deactivate_resource(device_t, device_t, int, int, struct resource *); -static int fdtbus_setup_intr(device_t, device_t, struct resource *, int, - driver_filter_t *, driver_intr_t *, void *, void **); - -static const char *fdtbus_ofw_get_name(device_t, device_t); -static phandle_t fdtbus_ofw_get_node(device_t, device_t); -static const char *fdtbus_ofw_get_type(device_t, device_t); -static const char *fdtbus_ofw_get_compat(device_t, device_t); - -/* - * Local routines. - */ -static void newbus_device_from_fdt_node(device_t, phandle_t); /* * Bus interface definition. @@ -107,47 +64,26 @@ static device_method_t fdtbus_methods[] = { /* Device interface */ DEVMETHOD(device_identify, fdtbus_identify), DEVMETHOD(device_probe, fdtbus_probe), - DEVMETHOD(device_attach, fdtbus_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, fdtbus_print_child), - DEVMETHOD(bus_alloc_resource, fdtbus_alloc_resource), - DEVMETHOD(bus_release_resource, fdtbus_release_resource), DEVMETHOD(bus_activate_resource, fdtbus_activate_resource), DEVMETHOD(bus_deactivate_resource, fdtbus_deactivate_resource), DEVMETHOD(bus_config_intr, bus_generic_config_intr), - DEVMETHOD(bus_setup_intr, fdtbus_setup_intr), + DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), - /* OFW bus interface */ - DEVMETHOD(ofw_bus_get_node, fdtbus_ofw_get_node), - DEVMETHOD(ofw_bus_get_name, fdtbus_ofw_get_name), - DEVMETHOD(ofw_bus_get_type, fdtbus_ofw_get_type), - DEVMETHOD(ofw_bus_get_compat, fdtbus_ofw_get_compat), - - { 0, 0 } -}; - -static driver_t fdtbus_driver = { - "fdtbus", - fdtbus_methods, - sizeof(struct fdtbus_softc) + DEVMETHOD_END }; devclass_t fdtbus_devclass; - +DEFINE_CLASS_1(fdtbus, fdtbus_driver, fdtbus_methods, + sizeof(struct ofw_nexus_softc), ofw_nexus_driver); DRIVER_MODULE(fdtbus, nexus, fdtbus_driver, fdtbus_devclass, 0, 0); static void fdtbus_identify(driver_t *driver, device_t parent) { - debugf("%s(driver=%p, parent=%p)\n", __func__, driver, parent); - if (device_find_child(parent, "fdtbus", -1) == NULL) BUS_ADD_CHILD(parent, 0, "fdtbus", -1); } @@ -156,462 +92,11 @@ static int fdtbus_probe(device_t dev) { - debugf("%s(dev=%p); pass=%u\n", __func__, dev, bus_current_pass); - device_set_desc(dev, "Flattened Device Tree"); return (BUS_PROBE_NOWILDCARD); } static int -fdtbus_attach(device_t dev) -{ - phandle_t root; - phandle_t child; - struct fdtbus_softc *sc; - u_long start, end; - int error; - - if ((root = OF_finddevice("/")) == -1) - panic("fdtbus_attach: no root node."); - - sc = device_get_softc(dev); - - /* - * IRQ rman. - */ - start = 0; - end = ~0; - sc->sc_irq.rm_start = start; - sc->sc_irq.rm_end = end; - sc->sc_irq.rm_type = RMAN_ARRAY; - sc->sc_irq.rm_descr = "Interrupt request lines"; - if ((error = rman_init(&sc->sc_irq)) != 0) { - device_printf(dev, "could not init IRQ rman, error = %d\n", - error); - return (error); - } - if ((error = rman_manage_region(&sc->sc_irq, start, end)) != 0) { - device_printf(dev, "could not manage IRQ region, error = %d\n", - error); - return (error); - } - - /* - * Mem-mapped I/O space rman. - */ - start = 0; - end = ~0ul; - sc->sc_mem.rm_start = start; - sc->sc_mem.rm_end = end; - sc->sc_mem.rm_type = RMAN_ARRAY; - sc->sc_mem.rm_descr = "I/O memory"; - if ((error = rman_init(&sc->sc_mem)) != 0) { - device_printf(dev, "could not init I/O mem rman, error = %d\n", - error); - return (error); - } - if ((error = rman_manage_region(&sc->sc_mem, start, end)) != 0) { - device_printf(dev, "could not manage I/O mem region, " - "error = %d\n", error); - return (error); - } - - /* - * Walk the FDT root node and add top-level devices as our children. - */ - for (child = OF_child(root); child != 0; child = OF_peer(child)) { - /* Check and process 'status' property. */ - if (!(fdt_is_enabled(child))) - continue; - - newbus_device_from_fdt_node(dev, child); - } - - return (bus_generic_attach(dev)); -} - -static int -fdtbus_print_child(device_t dev, device_t child) -{ - struct fdtbus_devinfo *di; - struct resource_list *rl; - int rv; - - di = device_get_ivars(child); - rl = &di->di_res; - - rv = 0; - rv += bus_print_child_header(dev, child); - rv += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#lx"); - rv += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%ld"); - rv += bus_print_child_footer(dev, child); - - return (rv); -} - -static void -newbus_device_destroy(device_t dev) -{ - struct fdtbus_devinfo *di; - - di = device_get_ivars(dev); - if (di == NULL) - return; - - free(di->di_name, M_OFWPROP); - free(di->di_type, M_OFWPROP); - free(di->di_compat, M_OFWPROP); - - resource_list_free(&di->di_res); - free(di, M_FDTBUS); -} - -static device_t -newbus_device_create(device_t dev_par, phandle_t node, char *name, char *type, - char *compat) -{ - device_t child; - struct fdtbus_devinfo *di; - - child = device_add_child(dev_par, NULL, -1); - if (child == NULL) { - free(name, M_OFWPROP); - free(type, M_OFWPROP); - free(compat, M_OFWPROP); - return (NULL); - } - - di = malloc(sizeof(*di), M_FDTBUS, M_WAITOK); - di->di_node = node; - di->di_name = name; - di->di_type = type; - di->di_compat = compat; - - resource_list_init(&di->di_res); - - if (fdt_reg_to_rl(node, &di->di_res)) { - device_printf(child, "could not process 'reg' property\n"); - newbus_device_destroy(child); - child = NULL; - goto out; - } - - if (fdt_intr_to_rl(node, &di->di_res, di->di_intr_sl)) { - device_printf(child, "could not process 'interrupts' " - "property\n"); - newbus_device_destroy(child); - child = NULL; - goto out; - } - - device_set_ivars(child, di); - debugf("added child name='%s', node=%p\n", name, (void *)node); - -out: - return (child); -} - -static device_t -newbus_pci_create(device_t dev_par, phandle_t dt_node, u_long par_base, - u_long par_size) -{ - pcell_t reg[3 + 2]; - device_t dev_child; - u_long start, end, count; - struct fdtbus_devinfo *di; - char *name, *type, *compat; - int len; - - OF_getprop_alloc(dt_node, "device_type", 1, (void **)&type); - if (!(type != NULL && strcmp(type, "pci") == 0)) { - /* Only process 'pci' subnodes. */ - free(type, M_OFWPROP); - return (NULL); - } - - OF_getprop_alloc(dt_node, "name", 1, (void **)&name); - OF_getprop_alloc(OF_parent(dt_node), "compatible", 1, - (void **)&compat); - - dev_child = device_add_child(dev_par, NULL, -1); - if (dev_child == NULL) { - free(name, M_OFWPROP); - free(type, M_OFWPROP); - free(compat, M_OFWPROP); - return (NULL); - } - - di = malloc(sizeof(*di), M_FDTBUS, M_WAITOK); - di->di_node = dt_node; - di->di_name = name; - di->di_type = type; - di->di_compat = compat; - - resource_list_init(&di->di_res); - - /* - * Produce and set SYS_RES_MEMORY resources. - */ - start = 0; - count = 0; - - len = OF_getprop(dt_node, "reg", ®, sizeof(reg)); - if (len > 0) { - if (fdt_data_verify((void *)®[1], 2) != 0) { - device_printf(dev_child, "'reg' address value out of " - "range\n"); - newbus_device_destroy(dev_child); - dev_child = NULL; - goto out; - } - start = fdt_data_get((void *)®[1], 2); - - if (fdt_data_verify((void *)®[3], 2) != 0) { - device_printf(dev_child, "'reg' size value out of " - "range\n"); - newbus_device_destroy(dev_child); - dev_child = NULL; - goto out; - } - count = fdt_data_get((void *)®[3], 2); - } - - /* Calculate address range relative to base. */ - par_base &= 0x000ffffful; - start &= 0x000ffffful; - start += par_base + fdt_immr_va; - if (count == 0) - count = par_size; - end = start + count - 1; - - debugf("start = 0x%08lx, end = 0x%08lx, count = 0x%08lx\n", - start, end, count); - - if (count > par_size) { - device_printf(dev_child, "'reg' size value out of range\n"); - newbus_device_destroy(dev_child); - dev_child = NULL; - goto out; - } - - resource_list_add(&di->di_res, SYS_RES_MEMORY, 0, start, end, count); - - /* - * Set SYS_RES_IRQ resources. - */ - if (fdt_intr_to_rl(OF_parent(dt_node), &di->di_res, di->di_intr_sl)) { - device_printf(dev_child, "could not process 'interrupts' " - "property\n"); - newbus_device_destroy(dev_child); - dev_child = NULL; - goto out; - } - - device_set_ivars(dev_child, di); - debugf("added child name='%s', node=%p\n", name, - (void *)dt_node); - -out: - return (dev_child); -} - -static void -pci_from_fdt_node(device_t dev_par, phandle_t dt_node, char *name, - char *type, char *compat) -{ - u_long reg_base, reg_size; - phandle_t dt_child; - - /* - * Retrieve 'reg' property. - */ - if (fdt_regsize(dt_node, ®_base, ®_size) != 0) { - device_printf(dev_par, "could not retrieve 'reg' prop\n"); - return; - } - - /* - * Walk the PCI node and instantiate newbus devices representing - * logical resources (bridges / ports). - */ - for (dt_child = OF_child(dt_node); dt_child != 0; - dt_child = OF_peer(dt_child)) { - - if (!(fdt_is_enabled(dt_child))) - continue; - - newbus_pci_create(dev_par, dt_child, reg_base, reg_size); - } -} - -/* - * These FDT nodes do not need a corresponding newbus device object. - */ -static char *fdt_devices_skip[] = { - "aliases", - "chosen", - "memory", - NULL -}; - -static void -newbus_device_from_fdt_node(device_t dev_par, phandle_t node) -{ - char *name, *type, *compat; - device_t child; - int i; - - OF_getprop_alloc(node, "name", 1, (void **)&name); - OF_getprop_alloc(node, "device_type", 1, (void **)&type); - OF_getprop_alloc(node, "compatible", 1, (void **)&compat); - - for (i = 0; fdt_devices_skip[i] != NULL; i++) - if (name != NULL && strcmp(name, fdt_devices_skip[i]) == 0) { - debugf("skipping instantiating FDT device='%s'\n", - name); - return; - } - - child = newbus_device_create(dev_par, node, name, type, compat); - if (type != NULL && strcmp(type, "pci") == 0) - pci_from_fdt_node(child, node, name, type, compat); -} - -static struct resource * -fdtbus_alloc_resource(device_t bus, device_t child, int type, int *rid, - u_long start, u_long end, u_long count, u_int flags) -{ - struct fdtbus_softc *sc; - struct resource *res; - struct rman *rm; - struct fdtbus_devinfo *di; - struct resource_list_entry *rle; - int needactivate; - - /* - * Request for the default allocation with a given rid: use resource - * list stored in the local device info. - */ - if ((start == 0UL) && (end == ~0UL)) { - if ((di = device_get_ivars(child)) == NULL) - return (NULL); - - if (type == SYS_RES_IOPORT) - type = SYS_RES_MEMORY; - - rle = resource_list_find(&di->di_res, type, *rid); - if (rle == NULL) { - device_printf(bus, "no default resources for " - "rid = %d, type = %d\n", *rid, type); - return (NULL); - } - start = rle->start; - end = rle->end; - count = rle->count; - } - - sc = device_get_softc(bus); - - needactivate = flags & RF_ACTIVE; - flags &= ~RF_ACTIVE; - - switch (type) { - case SYS_RES_IRQ: - rm = &sc->sc_irq; - break; - - case SYS_RES_IOPORT: - case SYS_RES_MEMORY: - rm = &sc->sc_mem; - break; - - default: - return (NULL); - } - - res = rman_reserve_resource(rm, start, end, count, flags, child); - if (res == NULL) { - device_printf(bus, "failed to reserve resource %#lx - %#lx " - "(%#lx)\n", start, end, count); - return (NULL); - } - - rman_set_rid(res, *rid); - - if (type == SYS_RES_IOPORT || type == SYS_RES_MEMORY) { - /* XXX endianess should be set based on SOC node */ - rman_set_bustag(res, fdtbus_bs_tag); - rman_set_bushandle(res, rman_get_start(res)); - } - - if (needactivate) - if (bus_activate_resource(child, type, *rid, res)) { - device_printf(child, "resource activation failed\n"); - rman_release_resource(res); - return (NULL); - } - - return (res); -} - -static int -fdtbus_release_resource(device_t bus, device_t child, int type, int rid, - struct resource *res) -{ - int err; - - if (rman_get_flags(res) & RF_ACTIVE) { - err = bus_deactivate_resource(child, type, rid, res); - if (err) - return (err); - } - - return (rman_release_resource(res)); -} - -static int -fdtbus_setup_intr(device_t bus, device_t child, struct resource *res, - int flags, driver_filter_t *filter, driver_intr_t *ihand, void *arg, - void **cookiep) -{ - struct fdtbus_devinfo *di; - enum intr_trigger trig; - enum intr_polarity pol; - int error, rid; - - if (res == NULL) - return (EINVAL); - - /* - * We are responsible for configuring the interrupts of our direct - * children. - */ - if (device_get_parent(child) == bus) { - di = device_get_ivars(child); - if (di == NULL) - return (ENXIO); - - rid = rman_get_rid(res); - if (rid >= DI_MAX_INTR_NUM) - return (ENOENT); - - trig = di->di_intr_sl[rid].trig; - pol = di->di_intr_sl[rid].pol; - if (trig != INTR_TRIGGER_CONFORM || - pol != INTR_POLARITY_CONFORM) { - error = bus_generic_config_intr(bus, - rman_get_start(res), trig, pol); - if (error) - return (error); - } - } - - error = bus_generic_setup_intr(bus, child, res, flags, filter, ihand, - arg, cookiep); - return (error); -} - -static int fdtbus_activate_resource(device_t bus, device_t child, int type, int rid, struct resource *res) { @@ -619,6 +104,10 @@ fdtbus_activate_resource(device_t bus, device_t child, int type, int rid, int error; if (type == SYS_RES_MEMORY || type == SYS_RES_IOPORT) { + /* XXX endianess should be set based on SOC node */ + rman_set_bustag(res, fdtbus_bs_tag); + rman_set_bushandle(res, rman_get_start(res)); + error = bus_space_map(rman_get_bustag(res), rman_get_bushandle(res), rman_get_size(res), 0, &p); if (error) @@ -637,36 +126,3 @@ fdtbus_deactivate_resource(device_t bus, device_t child, int type, int rid, return (rman_deactivate_resource(res)); } -static const char * -fdtbus_ofw_get_name(device_t bus, device_t dev) -{ - struct fdtbus_devinfo *di; - - return ((di = device_get_ivars(dev)) == NULL ? NULL : di->di_name); -} - -static phandle_t -fdtbus_ofw_get_node(device_t bus, device_t dev) -{ - struct fdtbus_devinfo *di; - - return ((di = device_get_ivars(dev)) == NULL ? 0 : di->di_node); -} - -static const char * -fdtbus_ofw_get_type(device_t bus, device_t dev) -{ - struct fdtbus_devinfo *di; - - return ((di = device_get_ivars(dev)) == NULL ? NULL : di->di_type); -} - -static const char * -fdtbus_ofw_get_compat(device_t bus, device_t dev) -{ - struct fdtbus_devinfo *di; - - return ((di = device_get_ivars(dev)) == NULL ? NULL : di->di_compat); -} - - diff --git a/sys/dev/ofw/ofw_nexus.c b/sys/dev/ofw/ofw_nexus.c index e531311..f602bfe 100644 --- a/sys/dev/ofw/ofw_nexus.c +++ b/sys/dev/ofw/ofw_nexus.c @@ -464,8 +464,8 @@ nexus_setup_dinfo(device_t dev, phandle_t node) iparent = 0; OF_searchencprop(node, "interrupt-parent", &iparent, sizeof(iparent)); - OF_searchencprop(iparent, "#interrupt-cells", &icells, - sizeof(icells)); + OF_searchencprop(OF_xref_phandle(iparent), "#interrupt-cells", + &icells, sizeof(icells)); for (i = 0; i < nintr; i+= icells) { intr[i] = ofw_bus_map_intr(dev, iparent, intr[i]); resource_list_add(&ndi->ndi_rl, SYS_RES_IRQ, i, intr[i], |