static int dma_attach(device_t dev) { struct dma_softc *dsc; struct lsi64854_softc *lsc; struct dma_devinfo *ddi; device_t cdev; const char *name; char *cabletype; uint32_t csr; phandle_t child, node; int error, i; dsc = device_get_softc(dev); lsc = &dsc->sc_lsi64854; name = ofw_bus_get_name(dev); node = ofw_bus_get_node(dev); dsc->sc_ign = sbus_get_ign(dev); dsc->sc_slot = sbus_get_slot(dev); i = 0; lsc->sc_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &i, RF_ACTIVE); if (lsc->sc_res == NULL) { device_printf(dev, "cannot allocate resources\n"); return (ENXIO); } if (strcmp(name, "espdma") == 0 || strcmp(name, "dma") == 0) lsc->sc_channel = L64854_CHANNEL_SCSI; else if (strcmp(name, "ledma") == 0) { /* * Check to see which cable type is currently active and * set the appropriate bit in the ledma csr so that it * gets used. If we didn't netboot, the PROM won't have * the "cable-selection" property; default to TP and then * the user can change it via a "media" option to ifconfig. */ csr = L64854_GCSR(lsc); if ((OF_getprop_alloc(node, "cable-selection", 1, (void **)&cabletype)) == -1) { /* assume TP if nothing there */ csr |= E_TP_AUI; } else { if (strcmp(cabletype, "aui") == 0) csr &= ~E_TP_AUI; else csr |= E_TP_AUI; free(cabletype, M_OFWPROP); } L64854_SCSR(lsc, csr); DELAY(20000); /* manual says we need a 20ms delay */ lsc->sc_channel = L64854_CHANNEL_ENET; } else { device_printf(dev, "unsupported DMA channel\n"); error = ENXIO; goto fail_lres; } error = bus_dma_tag_create( bus_get_dma_tag(dev), /* parent */ 1, 0, /* alignment, boundary */ BUS_SPACE_MAXADDR, /* lowaddr */ BUS_SPACE_MAXADDR, /* highaddr */ NULL, NULL, /* filter, filterarg */ BUS_SPACE_MAXSIZE_32BIT, /* maxsize */ 0, /* nsegments */ BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 0, /* flags */ NULL, NULL, /* no locking */ &lsc->sc_parent_dmat); if (error != 0) { device_printf(dev, "cannot allocate parent DMA tag\n"); goto fail_lres; } i = sbus_get_burstsz(dev); lsc->sc_burst = (i & SBUS_BURST_32) ? 32 : (i & SBUS_BURST_16) ? 16 : 0; lsc->sc_dev = dev; /* Attach children. */ i = 0; for (child = OF_child(node); child != 0; child = OF_peer(child)) { if ((ddi = dma_setup_dinfo(dev, dsc, child)) == NULL) continue; if (i != 0) { device_printf(dev, "<%s>: only one child per DMA channel supported\n", ddi->ddi_obdinfo.obd_name); dma_destroy_dinfo(ddi); continue; } if ((cdev = device_add_child(dev, NULL, -1)) == NULL) { device_printf(dev, "<%s>: device_add_child failed\n", ddi->ddi_obdinfo.obd_name); dma_destroy_dinfo(ddi); continue; } device_set_ivars(cdev, ddi); i++; } return (bus_generic_attach(dev)); fail_lres: bus_release_resource(dev, SYS_RES_MEMORY, rman_get_rid(lsc->sc_res), lsc->sc_res); return (error); }
static int esp_sbus_attach(device_t dev) { struct esp_softc *esc; struct ncr53c9x_softc *sc; struct lsi64854_softc *lsc; device_t *children; int error, i, nchildren; esc = device_get_softc(dev); sc = &esc->sc_ncr53c9x; lsc = NULL; esc->sc_dev = dev; sc->sc_freq = sbus_get_clockfreq(dev); if (strcmp(ofw_bus_get_name(dev), "SUNW,fas") == 0) { /* * Allocate space for DMA, in SUNW,fas there are no * separate DMA devices. */ lsc = malloc(sizeof (struct lsi64854_softc), M_DEVBUF, M_NOWAIT | M_ZERO); if (lsc == NULL) { device_printf(dev, "out of memory (lsi64854_softc)\n"); return (ENOMEM); } esc->sc_dma = lsc; /* * SUNW,fas have 2 register spaces: DMA (lsi64854) and * SCSI core (ncr53c9x). */ /* Allocate DMA registers. */ i = 0; if ((lsc->sc_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &i, RF_ACTIVE)) == NULL) { device_printf(dev, "cannot allocate DMA registers\n"); error = ENXIO; goto fail_sbus_lsc; } /* Create a parent DMA tag based on this bus. */ error = bus_dma_tag_create( bus_get_dma_tag(dev), /* parent */ 1, 0, /* alignment, boundary */ BUS_SPACE_MAXADDR, /* lowaddr */ BUS_SPACE_MAXADDR, /* highaddr */ NULL, NULL, /* filter, filterarg */ BUS_SPACE_MAXSIZE_32BIT, /* maxsize */ 0, /* nsegments */ BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 0, /* flags */ NULL, NULL, /* no locking */ &lsc->sc_parent_dmat); if (error != 0) { device_printf(dev, "cannot allocate parent DMA tag\n"); goto fail_sbus_lres; } i = sbus_get_burstsz(dev); #ifdef ESP_SBUS_DEBUG printf("%s: burst 0x%x\n", __func__, i); #endif lsc->sc_burst = (i & SBUS_BURST_32) ? 32 : (i & SBUS_BURST_16) ? 16 : 0; lsc->sc_channel = L64854_CHANNEL_SCSI; lsc->sc_client = sc; lsc->sc_dev = dev; /* * Allocate SCSI core registers. */ i = 1; if ((esc->sc_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &i, RF_ACTIVE)) == NULL) { device_printf(dev, "cannot allocate SCSI core registers\n"); error = ENXIO; goto fail_sbus_lpdma; } } else { /* * Search accompanying DMA engine. It should have been * already attached otherwise there isn't much we can do. */ if (device_get_children(device_get_parent(dev), &children, &nchildren) != 0) { device_printf(dev, "cannot determine siblings\n"); return (ENXIO); } for (i = 0; i < nchildren; i++) { if (device_is_attached(children[i]) && sbus_get_slot(children[i]) == sbus_get_slot(dev) && strcmp(ofw_bus_get_name(children[i]), "dma") == 0) { /* XXX hackery */ esc->sc_dma = (struct lsi64854_softc *) device_get_softc(children[i]); break; } } free(children, M_TEMP); if (esc->sc_dma == NULL) { device_printf(dev, "cannot find DMA engine\n"); return (ENXIO); } esc->sc_dma->sc_client = sc; /* * Allocate SCSI core registers. */ i = 0; if ((esc->sc_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &i, RF_ACTIVE)) == NULL) { device_printf(dev, "cannot allocate SCSI core registers\n"); return (ENXIO); } } error = espattach(esc, &esp_sbus_glue); if (error != 0) { device_printf(dev, "espattach failed\n"); goto fail_sbus_eres; } return (0); fail_sbus_eres: bus_release_resource(dev, SYS_RES_MEMORY, rman_get_rid(esc->sc_res), esc->sc_res); if (strcmp(ofw_bus_get_name(dev), "SUNW,fas") != 0) return (error); fail_sbus_lpdma: bus_dma_tag_destroy(lsc->sc_parent_dmat); fail_sbus_lres: bus_release_resource(dev, SYS_RES_MEMORY, rman_get_rid(lsc->sc_res), lsc->sc_res); fail_sbus_lsc: free(lsc, M_DEVBUF); return (error); }
static struct lebuffer_devinfo * lebuffer_setup_dinfo(device_t dev, phandle_t node) { struct lebuffer_devinfo *ldi; struct sbus_regs *reg; uint32_t base, iv, *intr; int i, nreg, nintr, slot, rslot; ldi = malloc(sizeof(*ldi), M_DEVBUF, M_WAITOK | M_ZERO); if (ofw_bus_gen_setup_devinfo(&ldi->ldi_obdinfo, node) != 0) { free(ldi, M_DEVBUF); return (NULL); } resource_list_init(&ldi->ldi_rl); slot = -1; nreg = OF_getprop_alloc(node, "reg", sizeof(*reg), (void **)®); if (nreg == -1) { device_printf(dev, "<%s>: incomplete\n", ldi->ldi_obdinfo.obd_name); goto fail; } for (i = 0; i < nreg; i++) { base = reg[i].sbr_offset; if (SBUS_ABS(base)) { rslot = SBUS_ABS_TO_SLOT(base); base = SBUS_ABS_TO_OFFSET(base); } else rslot = reg[i].sbr_slot; if (slot != -1 && slot != rslot) { device_printf(dev, "<%s>: multiple slots\n", ldi->ldi_obdinfo.obd_name); free(reg, M_OFWPROP); goto fail; } slot = rslot; resource_list_add(&ldi->ldi_rl, SYS_RES_MEMORY, i, base, base + reg[i].sbr_size, reg[i].sbr_size); } free(reg, M_OFWPROP); if (slot != sbus_get_slot(dev)) { device_printf(dev, "<%s>: parent and child slot do not match\n", ldi->ldi_obdinfo.obd_name); goto fail; } /* * The `interrupts' property contains the SBus interrupt level. */ nintr = OF_getprop_alloc(node, "interrupts", sizeof(*intr), (void **)&intr); if (nintr != -1) { for (i = 0; i < nintr; i++) { iv = intr[i]; /* * SBus card devices need the slot number encoded into * the vector as this is generally not done. */ if ((iv & INTMAP_OBIO_MASK) == 0) iv |= slot << 3; /* Set the IGN as appropriate. */ iv |= sbus_get_ign(dev) << INTMAP_IGN_SHIFT; resource_list_add(&ldi->ldi_rl, SYS_RES_IRQ, i, iv, iv, 1); } free(intr, M_OFWPROP); } return (ldi); fail: lebuffer_destroy_dinfo(ldi); return (NULL); }
static struct resource * sbus_alloc_resource(device_t bus, device_t child, int type, int *rid, rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) { struct sbus_softc *sc; struct rman *rm; struct resource *rv; struct resource_list *rl; struct resource_list_entry *rle; device_t schild; bus_addr_t toffs; bus_size_t tend; int i, slot; int isdefault, passthrough; isdefault = RMAN_IS_DEFAULT_RANGE(start, end); passthrough = (device_get_parent(child) != bus); rle = NULL; sc = device_get_softc(bus); rl = BUS_GET_RESOURCE_LIST(bus, child); switch (type) { case SYS_RES_IRQ: return (resource_list_alloc(rl, bus, child, type, rid, start, end, count, flags)); case SYS_RES_MEMORY: if (!passthrough) { rle = resource_list_find(rl, type, *rid); if (rle == NULL) return (NULL); if (rle->res != NULL) panic("%s: resource entry is busy", __func__); if (isdefault) { start = rle->start; count = ulmax(count, rle->count); end = ulmax(rle->end, start + count - 1); } } rm = NULL; schild = child; while (device_get_parent(schild) != bus) schild = device_get_parent(schild); slot = sbus_get_slot(schild); for (i = 0; i < sc->sc_nrange; i++) { if (sc->sc_rd[i].rd_slot != slot || start < sc->sc_rd[i].rd_coffset || start > sc->sc_rd[i].rd_cend) continue; /* Disallow cross-range allocations. */ if (end > sc->sc_rd[i].rd_cend) return (NULL); /* We've found the connection to the parent bus */ toffs = start - sc->sc_rd[i].rd_coffset; tend = end - sc->sc_rd[i].rd_coffset; rm = &sc->sc_rd[i].rd_rman; break; } if (rm == NULL) return (NULL); rv = rman_reserve_resource(rm, toffs, tend, count, flags & ~RF_ACTIVE, child); if (rv == NULL) return (NULL); rman_set_rid(rv, *rid); if ((flags & RF_ACTIVE) != 0 && bus_activate_resource(child, type, *rid, rv)) { rman_release_resource(rv); return (NULL); } if (!passthrough) rle->res = rv; return (rv); default: return (NULL); } }