static void sbus_intr_clear(void *arg) { struct intr_vector *iv = arg; struct sbus_icarg *sica = iv->iv_icarg; SYSIO_WRITE8(sica->sica_sc, sica->sica_clr, INTCLR_IDLE); }
static void sbus_intr_disable(void *arg) { struct intr_vector *iv = arg; struct sbus_icarg *sica = iv->iv_icarg; SYSIO_WRITE8(sica->sica_sc, sica->sica_map, iv->iv_vec); }
/* Write to the correct clr register, and call the actual handler. */ static void sbus_intr_stub(void *arg) { struct sbus_clr *scl; scl = (struct sbus_clr *)arg; scl->scl_handler(scl->scl_arg); SYSIO_WRITE8(scl->scl_sc, scl->scl_clr, 0); }
static void sbus_intr_assign(void *arg) { struct intr_vector *iv = arg; struct sbus_icarg *sica = iv->iv_icarg; SYSIO_WRITE8(sica->sica_sc, sica->sica_map, INTMAP_TID( SYSIO_READ8(sica->sica_sc, sica->sica_map), iv->iv_mid)); }
static void sbus_intr_enable(void *arg) { struct intr_vector *iv = arg; struct sbus_icarg *sica = iv->iv_icarg; SYSIO_WRITE8(sica->sica_sc, sica->sica_map, INTMAP_ENABLE(iv->iv_vec, iv->iv_mid)); }
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); }