diff options
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/fdt/fdtbus.c | 562 | ||||
-rw-r--r-- | sys/dev/ofw/ofw_nexus.c | 4 |
2 files changed, 11 insertions, 555 deletions
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], |