Example #1
0
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);
}
Example #2
0
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 **)&reg);
	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 **)&reg);
			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);
}
Example #3
0
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);
}
Example #4
0
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);
}
Example #5
0
File: sbus.c Project: MarginC/kame
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);
}
Example #6
0
File: sbus.c Project: MarginC/kame
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);
}
Example #7
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));
}