void * vbus_intr_establish(bus_space_tag_t t, bus_space_tag_t t0, int ihandle, int level, int flags, int (*handler)(void *), void *arg, const char *what) { uint64_t sysino = INTVEC(ihandle); struct intrhand *ih; int err; ih = bus_intr_allocate(t0, handler, arg, ihandle, level, NULL, NULL, what); if (ih == NULL) return (NULL); if (flags & BUS_INTR_ESTABLISH_MPSAFE) ih->ih_mpsafe = 1; intr_establish(ih->ih_pil, ih); ih->ih_ack = vbus_intr_ack; err = hv_intr_settarget(sysino, ih->ih_cpu->ci_upaid); if (err != H_EOK) return (NULL); /* Clear pending interrupts. */ err = hv_intr_setstate(sysino, INTR_IDLE); if (err != H_EOK) return (NULL); err = hv_intr_setenabled(sysino, INTR_ENABLED); if (err != H_EOK) return (NULL); return (ih); }
int vbus_intr_map(int node, int ino, uint64_t *sysino) { int *imap = NULL, nimap; int *reg = NULL, nreg; int *imap_mask; int parent; int address_cells, interrupt_cells; uint64_t devhandle; uint64_t devino; int len; int err; parent = OF_parent(node); address_cells = getpropint(parent, "#address-cells", 2); interrupt_cells = getpropint(parent, "#interrupt-cells", 1); KASSERT(interrupt_cells == 1); len = OF_getproplen(parent, "interrupt-map-mask"); if (len < (address_cells + interrupt_cells) * sizeof(int)) return (-1); imap_mask = malloc(len, M_DEVBUF, M_NOWAIT); if (imap_mask == NULL) return (-1); if (OF_getprop(parent, "interrupt-map-mask", imap_mask, len) != len) return (-1); getprop(parent, "interrupt-map", sizeof(int), &nimap, (void **)&imap); getprop(node, "reg", sizeof(*reg), &nreg, (void **)®); if (nreg < address_cells) return (-1); while (nimap >= address_cells + interrupt_cells + 2) { if (vbus_cmp_cells(imap, reg, imap_mask, address_cells) && vbus_cmp_cells(&imap[address_cells], &ino, &imap_mask[address_cells], interrupt_cells)) { node = imap[address_cells + interrupt_cells]; devino = imap[address_cells + interrupt_cells + 1]; free(reg, M_DEVBUF, 0); reg = NULL; getprop(node, "reg", sizeof(*reg), &nreg, (void **)®); devhandle = reg[0] & 0x0fffffff; err = hv_intr_devino_to_sysino(devhandle, devino, sysino); if (err != H_EOK) return (-1); KASSERT(*sysino == INTVEC(*sysino)); return (0); } imap += address_cells + interrupt_cells + 2; nimap -= address_cells + interrupt_cells + 2; } return (-1); }
void * vbus_intr_establish(bus_space_tag_t t, int ihandle, int level, int (*handler)(void *), void *arg, void (*fastvec)(void) /* ignored */) { uint64_t sysino = INTVEC(ihandle); struct intrhand *ih; int ino; int err; DPRINTF(VBUS_INTR, ("vbus_intr_establish()\n")); ino = INTINO(ihandle); ih = intrhand_alloc(); ih->ih_ivec = ihandle; ih->ih_fun = handler; ih->ih_arg = arg; ih->ih_pil = level; ih->ih_number = ino; ih->ih_pending = 0; intr_establish(ih->ih_pil, level != IPL_VM, ih); ih->ih_ack = vbus_intr_ack; err = hv_intr_settarget(sysino, cpus->ci_cpuid); if (err != H_EOK) { printf("hv_intr_settarget(%lu, %u) failed - err = %d\n", (long unsigned int)sysino, cpus->ci_cpuid, err); return (NULL); } /* Clear pending interrupts. */ err = hv_intr_setstate(sysino, INTR_IDLE); if (err != H_EOK) { printf("hv_intr_setstate(%lu, INTR_IDLE) failed - err = %d\n", (long unsigned int)sysino, err); return (NULL); } err = hv_intr_setenabled(sysino, INTR_ENABLED); if (err != H_EOK) { printf("hv_intr_setenabled(%lu) failed - err = %d\n", (long unsigned int)sysino, err); return (NULL); } return (ih); }
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_intr_t *intr, void *arg, void **cookiep) { struct sbus_softc *sc; struct sbus_clr *scl; bus_addr_t intrmapptr, intrclrptr, intrptr; u_int64_t intrmap; u_int32_t inr, slot; int error, i; long vec = rman_get_start(ires); sc = (struct sbus_softc *)device_get_softc(dev); scl = (struct sbus_clr *)malloc(sizeof(*scl), M_DEVBUF, M_NOWAIT); if (scl == NULL) return (NULL); intrptr = intrmapptr = intrclrptr = 0; intrmap = 0; inr = INTVEC(vec); if ((inr & INTMAP_OBIO_MASK) == 0) { /* * We're in an SBUS slot, register the map and clear * intr registers. */ slot = INTSLOT(vec); intrmapptr = SBR_SLOT0_INT_MAP + slot * 8; intrclrptr = SBR_SLOT0_INT_CLR + (slot * 8 * 8) + (INTPRI(vec) * 8); /* Enable the interrupt, insert IGN. */ intrmap = inr | sc->sc_ign; } else { intrptr = SBR_SCSI_INT_MAP; /* Insert IGN */ inr |= sc->sc_ign; for (i = 0; intrptr <= SBR_RESERVED_INT_MAP && INTVEC(intrmap = SYSIO_READ8(sc, intrptr)) != INTVEC(inr); intrptr += 8, i++) ; if (INTVEC(intrmap) == INTVEC(inr)) { /* Register the map and clear intr registers */ intrmapptr = intrptr; intrclrptr = SBR_SCSI_INT_CLR + i * 8; /* Enable the interrupt */ } else panic("sbus_setup_intr: IRQ not found!"); } scl->scl_sc = sc; scl->scl_arg = arg; scl->scl_handler = intr; scl->scl_clr = intrclrptr; /* Disable the interrupt while we fiddle with it */ SYSIO_WRITE8(sc, intrmapptr, intrmap); error = BUS_SETUP_INTR(device_get_parent(dev), child, ires, flags, sbus_intr_stub, scl, cookiep); if (error != 0) { free(scl, M_DEVBUF); return (error); } scl->scl_cookie = *cookiep; *cookiep = scl; /* * Clear the interrupt, it might have been triggered before it was * set up. */ SYSIO_WRITE8(sc, intrclrptr, 0); /* * Enable the interrupt and program the target module now we have the * handler installed. */ SYSIO_WRITE8(sc, intrmapptr, INTMAP_ENABLE(intrmap, PCPU_GET(mid))); return (error); }
static int sbus_probe(device_t dev) { struct sbus_softc *sc = device_get_softc(dev); struct sbus_devinfo *sdi; struct sbus_ranges *range; struct resource *res; device_t cdev; bus_addr_t phys; bus_size_t size; char *name, *cname, *t; phandle_t child, node = nexus_get_node(dev); u_int64_t mr; int intr, clock, rid, vec, i; t = nexus_get_device_type(dev); if (((t == NULL || strcmp(t, OFW_SBUS_TYPE) != 0)) && strcmp(nexus_get_name(dev), OFW_SBUS_NAME) != 0) return (ENXIO); device_set_desc(dev, "U2S UPA-SBus bridge"); if ((sc->sc_nreg = OF_getprop_alloc(node, "reg", sizeof(*sc->sc_reg), (void **)&sc->sc_reg)) == -1) { panic("sbus_probe: error getting reg property"); } if (sc->sc_nreg < 1) panic("sbus_probe: bogus properties"); phys = UPA_REG_PHYS(&sc->sc_reg[0]); size = UPA_REG_SIZE(&sc->sc_reg[0]); rid = 0; sc->sc_sysio_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, phys, phys + size - 1, size, RF_ACTIVE); if (sc->sc_sysio_res == NULL || rman_get_start(sc->sc_sysio_res) != phys) panic("sbus_probe: can't allocate device memory"); sc->sc_bustag = rman_get_bustag(sc->sc_sysio_res); sc->sc_bushandle = rman_get_bushandle(sc->sc_sysio_res); if (OF_getprop(node, "interrupts", &intr, sizeof(intr)) == -1) panic("sbus_probe: cannot get IGN"); sc->sc_ign = intr & INTMAP_IGN_MASK; /* Find interrupt group no */ sc->sc_cbustag = sbus_alloc_bustag(sc); /* * Record clock frequency for synchronous SCSI. * IS THIS THE CORRECT DEFAULT?? */ if (OF_getprop(node, "clock-frequency", &clock, sizeof(clock)) == -1) clock = 25000000; sc->sc_clockfreq = clock; clock /= 1000; device_printf(dev, "clock %d.%03d MHz\n", clock / 1000, clock % 1000); sc->sc_dmatag = nexus_get_dmatag(dev); if (bus_dma_tag_create(sc->sc_dmatag, 8, 1, 0, 0x3ffffffff, NULL, NULL, 0x3ffffffff, 0xff, 0xffffffff, 0, &sc->sc_cdmatag) != 0) panic("bus_dma_tag_create failed"); /* Customize the tag */ sc->sc_cdmatag->cookie = sc; sc->sc_cdmatag->dmamap_create = sbus_dmamap_create; sc->sc_cdmatag->dmamap_destroy = sbus_dmamap_destroy; sc->sc_cdmatag->dmamap_load = sbus_dmamap_load; sc->sc_cdmatag->dmamap_unload = sbus_dmamap_unload; sc->sc_cdmatag->dmamap_sync = sbus_dmamap_sync; sc->sc_cdmatag->dmamem_alloc = sbus_dmamem_alloc; sc->sc_cdmatag->dmamem_free = sbus_dmamem_free; /* XXX: register as root dma tag (kluge). */ sparc64_root_dma_tag = sc->sc_cdmatag; /* * 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", device_get_name(dev)); } sc->sc_rd = (struct sbus_rd *)malloc(sizeof(*sc->sc_rd) * sc->sc_nrange, M_DEVBUF, M_NOWAIT); if (sc->sc_rd == NULL) panic("sbus_probe: could not allocate rmans"); /* * Preallocate all space that the SBus bridge decodes, so that nothing * else gets in the way; set up rmans etc. */ 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; rid = 0; if ((res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, phys, phys + size - 1, size, RF_ACTIVE)) == NULL) panic("sbus_probe: could not allocate decoded range"); 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("psycho_probe: failed to set up memory rman"); 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); /* * Get the SBus burst transfer size if burst transfers are supported. * XXX: is the default correct? */ if (OF_getprop(node, "burst-sizes", &sc->sc_burst, sizeof(sc->sc_burst)) == -1 || sc->sc_burst == 0) sc->sc_burst = SBUS_BURST_DEF; /* initalise the IOMMU */ /* punch in our copies */ sc->sc_is.is_bustag = sc->sc_bustag; sc->sc_is.is_bushandle = sc->sc_bushandle; 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] = NULL; /* give us a nice name.. */ name = (char *)malloc(32, M_DEVBUF, M_NOWAIT); if (name == 0) panic("sbus_probe: couldn't malloc iommu name"); snprintf(name, 32, "%s dvma", device_get_name(dev)); /* * 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(name, &sc->sc_is, 0, -1, 1); /* Enable the over-temperature and power-fail intrrupts. */ rid = 0; mr = SYSIO_READ8(sc, SBR_THERM_INT_MAP); vec = INTVEC(mr); if ((sc->sc_ot_ires = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, vec, vec, 1, RF_ACTIVE)) == NULL) panic("sbus_probe: failed to get temperature interrupt"); bus_setup_intr(dev, sc->sc_ot_ires, INTR_TYPE_MISC | INTR_FAST, sbus_overtemp, sc, &sc->sc_ot_ihand); SYSIO_WRITE8(sc, SBR_THERM_INT_MAP, INTMAP_ENABLE(mr, PCPU_GET(mid))); rid = 0; mr = SYSIO_READ8(sc, SBR_POWER_INT_MAP); vec = INTVEC(mr); if ((sc->sc_pf_ires = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, vec, vec, 1, RF_ACTIVE)) == NULL) panic("sbus_probe: failed to get power fail interrupt"); bus_setup_intr(dev, sc->sc_pf_ires, INTR_TYPE_MISC | INTR_FAST, sbus_pwrfail, sc, &sc->sc_pf_ihand); SYSIO_WRITE8(sc, SBR_POWER_INT_MAP, INTMAP_ENABLE(mr, PCPU_GET(mid))); /* Initialize the counter-timer. */ sparc64_counter_init(sc->sc_bustag, sc->sc_bushandle, SBR_TC0); /* * Loop through ROM children, fixing any relative addresses * and then configuring each device. * `specials' is an array of device names that are treated * specially: */ for (child = OF_child(node); child != 0; child = OF_peer(child)) { if ((OF_getprop_alloc(child, "name", 1, (void **)&cname)) == -1) continue; if ((sdi = sbus_setup_dinfo(sc, child, cname)) == NULL) { device_printf(dev, "<%s>: incomplete\n", cname); free(cname, M_OFWPROP); continue; } if ((cdev = device_add_child(dev, NULL, -1)) == NULL) panic("sbus_probe: device_add_child failed"); device_set_ivars(cdev, sdi); } 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); /* * 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; /* initalise 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)); }