static int nexus_probe(device_t dev) { phandle_t root; phandle_t child; device_t cdev; struct nexus_devinfo *dinfo; struct nexus_softc *sc; char *name, *type; if ((root = OF_peer(0)) == -1) panic("nexus_probe: OF_peer failed."); 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 = "UPA 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, UPA_MEMSTART, UPA_MEMEND) != 0) panic("nexus_probe: failed to set up rmans"); for (child = OF_child(root); child != 0; child = OF_peer(child)) { if (child == -1) panic("nexus_probe(): OF_child failed."); if (OF_getprop_alloc(child, "name", 1, (void **)&name) == -1) continue; OF_getprop_alloc(child, "device_type", 1, (void **)&type); if (NEXUS_EXCLUDED(name, type)) { free(name, M_OFWPROP); if (type != NULL) free(type, M_OFWPROP); continue; } cdev = device_add_child(dev, NULL, -1); if (cdev != NULL) { dinfo = malloc(sizeof(*dinfo), M_NEXUS, M_WAITOK); dinfo->ndi_node = child; dinfo->ndi_name = name; dinfo->ndi_device_type = type; OF_getprop_alloc(child, "model", 1, (void **)&dinfo->ndi_model); dinfo->ndi_nreg = OF_getprop_alloc(child, "reg", sizeof(*dinfo->ndi_reg), (void **)&dinfo->ndi_reg); dinfo->ndi_ninterrupts = OF_getprop_alloc(child, "interrupts", sizeof(*dinfo->ndi_interrupts), (void **)&dinfo->ndi_interrupts); dinfo->ndi_bustag = &nexus_bustag; dinfo->ndi_dmatag = &nexus_dmatag; device_set_ivars(cdev, dinfo); } else free(name, M_OFWPROP); } device_set_desc(dev, "OpenFirmware Nexus device"); return (0); }
static struct nexus_devinfo * nexus_setup_dinfo(device_t dev, phandle_t node) { struct nexus_softc *sc; struct nexus_devinfo *ndi; uint32_t *reg, *intr, icells; uint64_t phys, size; phandle_t iparent; int i, j; int nintr; int nreg; sc = device_get_softc(dev); ndi = malloc(sizeof(*ndi), M_DEVBUF, M_WAITOK | M_ZERO); if (ofw_bus_gen_setup_devinfo(&ndi->ndi_obdinfo, node) != 0) { free(ndi, M_DEVBUF); return (NULL); } if (NEXUS_EXCLUDED(ndi->ndi_obdinfo.obd_name, ndi->ndi_obdinfo.obd_type)) { ofw_bus_gen_destroy_devinfo(&ndi->ndi_obdinfo); free(ndi, M_DEVBUF); return (NULL); } resource_list_init(&ndi->ndi_rl); nreg = OF_getprop_alloc(node, "reg", sizeof(*reg), (void **)®); if (nreg == -1) nreg = 0; for (i = 0; i < nreg; i += sc->acells + sc->scells) { phys = size = 0; for (j = 0; j < sc->acells; j++) { phys <<= 32; phys |= reg[i + j]; } for (j = 0; j < sc->scells; j++) { size <<= 32; size |= reg[i + sc->acells + j]; } /* Skip the dummy reg property of glue devices like ssm(4). */ if (size != 0) resource_list_add(&ndi->ndi_rl, SYS_RES_MEMORY, i, phys, phys + size - 1, size); } free(reg, M_OFWPROP); nintr = OF_getprop_alloc(node, "interrupts", sizeof(*intr), (void **)&intr); if (nintr > 0) { iparent = 0; OF_searchprop(node, "interrupt-parent", &iparent, sizeof(iparent)); OF_searchprop(iparent, "#interrupt-cells", &icells, sizeof(icells)); for (i = 0; i < nintr; i+= icells) { intr[i] = MAP_IRQ(iparent, intr[i]); resource_list_add(&ndi->ndi_rl, SYS_RES_IRQ, i, intr[i], intr[i], 1); if (icells > 1) { powerpc_config_intr(intr[i], (intr[i+1] & 1) ? INTR_TRIGGER_LEVEL : INTR_TRIGGER_EDGE, INTR_POLARITY_LOW); } } free(intr, M_OFWPROP); } return (ndi); }
static 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); 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); 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); } return (ndi); fail: nexus_destroy_dinfo(ndi); return (NULL); }