static struct resource * sbus_alloc_resource(device_t bus, device_t child, int type, int *rid, u_long start, u_long end, u_long 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_space_handle_t bh; bus_addr_t toffs; bus_size_t tend; int i, slot; int isdefault, needactivate, passthrough; isdefault = (start == 0UL && end == ~0UL); needactivate = flags & RF_ACTIVE; 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; bh = toffs = tend = 0; 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; bh = sc->sc_rd[i].rd_bushandle; break; } if (rm == NULL) return (NULL); flags &= ~RF_ACTIVE; rv = rman_reserve_resource(rm, toffs, tend, count, flags, child); if (rv == NULL) return (NULL); rman_set_rid(rv, *rid); rman_set_bustag(rv, sc->sc_cbustag); rman_set_bushandle(rv, bh + rman_get_start(rv)); if (needactivate) { if (bus_activate_resource(child, type, *rid, rv)) { rman_release_resource(rv); return (NULL); } } if (!passthrough) rle->res = rv; return (rv); default: return (NULL); } }
static struct resource * fdtbus_alloc_resource(device_t bus, device_t child, int type, int *rid, u_long start, u_long end, u_long count, u_int flags) { struct fdtbus_softc *sc; struct resource *res; struct rman *rm; struct fdtbus_devinfo *di; struct resource_list_entry *rle; int needactivate; /* * Request for the default allocation with a given rid: use resource * list stored in the local device info. */ if ((start == 0UL) && (end == ~0UL)) { if ((di = device_get_ivars(child)) == NULL) return (NULL); if (type == SYS_RES_IOPORT) type = SYS_RES_MEMORY; rle = resource_list_find(&di->di_res, type, *rid); if (rle == NULL) { device_printf(bus, "no default resources for " "rid = %d, type = %d\n", *rid, type); return (NULL); } start = rle->start; end = rle->end; count = rle->count; } sc = device_get_softc(bus); needactivate = flags & RF_ACTIVE; flags &= ~RF_ACTIVE; switch (type) { case SYS_RES_IRQ: rm = &sc->sc_irq; break; case SYS_RES_IOPORT: case SYS_RES_MEMORY: rm = &sc->sc_mem; break; default: return (NULL); } res = rman_reserve_resource(rm, start, end, count, flags, child); if (res == NULL) { device_printf(bus, "failed to reserve resource %#lx - %#lx " "(%#lx)\n", start, end, count); return (NULL); } rman_set_rid(res, *rid); if (type == SYS_RES_IOPORT || type == SYS_RES_MEMORY) { /* XXX endianess should be set based on SOC node */ rman_set_bustag(res, fdtbus_bs_tag); rman_set_bushandle(res, rman_get_start(res)); } if (needactivate) if (bus_activate_resource(child, type, *rid, res)) { device_printf(child, "resource activation failed\n"); rman_release_resource(res); return (NULL); } return (res); }
int scc_bfe_attach(device_t dev, u_int ipc) { struct resource_list_entry *rle; struct scc_chan *ch; struct scc_class *cl; struct scc_mode *m; struct scc_softc *sc, *sc0; const char *sep; bus_space_handle_t bh; u_long base, size, start, sz; int c, error, mode, sysdev; /* * The sc_class field defines the type of SCC we're going to work * with and thus the size of the softc. Replace the generic softc * with one that matches the SCC now that we're certain we handle * the device. */ sc0 = device_get_softc(dev); cl = sc0->sc_class; if (cl->size > sizeof(*sc)) { sc = malloc(cl->size, M_SCC, M_WAITOK|M_ZERO); bcopy(sc0, sc, sizeof(*sc)); device_set_softc(dev, sc); } else sc = sc0; size = abs(cl->cl_range) << sc->sc_bas.regshft; mtx_init(&sc->sc_hwmtx, "scc_hwmtx", NULL, MTX_SPIN); /* * Re-allocate. We expect that the softc contains the information * collected by scc_bfe_probe() intact. */ sc->sc_rres = bus_alloc_resource(dev, sc->sc_rtype, &sc->sc_rrid, 0, ~0, cl->cl_channels * size, RF_ACTIVE); if (sc->sc_rres == NULL) return (ENXIO); sc->sc_bas.bsh = rman_get_bushandle(sc->sc_rres); sc->sc_bas.bst = rman_get_bustag(sc->sc_rres); /* * Allocate interrupt resources. There may be a different interrupt * per channel. We allocate them all... */ sc->sc_chan = malloc(sizeof(struct scc_chan) * cl->cl_channels, M_SCC, M_WAITOK | M_ZERO); for (c = 0; c < cl->cl_channels; c++) { ch = &sc->sc_chan[c]; /* * XXX temporary hack. If we have more than 1 interrupt * per channel, allocate the first for the channel. At * this time only the macio bus front-end has more than * 1 interrupt per channel and we don't use the 2nd and * 3rd, because we don't support DMA yet. */ ch->ch_irid = c * ipc; ch->ch_ires = bus_alloc_resource_any(dev, SYS_RES_IRQ, &ch->ch_irid, RF_ACTIVE | RF_SHAREABLE); if (ipc == 0) break; } /* * Create the control structures for our children. Probe devices * and query them to see if we can reset the hardware. */ sysdev = 0; base = rman_get_start(sc->sc_rres); sz = (size != 0) ? size : rman_get_size(sc->sc_rres); start = base + ((cl->cl_range < 0) ? size * (cl->cl_channels - 1) : 0); for (c = 0; c < cl->cl_channels; c++) { ch = &sc->sc_chan[c]; resource_list_init(&ch->ch_rlist); ch->ch_nr = c + 1; if (!SCC_ENABLED(sc, ch)) goto next; ch->ch_enabled = 1; resource_list_add(&ch->ch_rlist, sc->sc_rtype, 0, start, start + sz - 1, sz); rle = resource_list_find(&ch->ch_rlist, sc->sc_rtype, 0); rle->res = &ch->ch_rres; bus_space_subregion(rman_get_bustag(sc->sc_rres), rman_get_bushandle(sc->sc_rres), start - base, sz, &bh); rman_set_bushandle(rle->res, bh); rman_set_bustag(rle->res, rman_get_bustag(sc->sc_rres)); resource_list_add(&ch->ch_rlist, SYS_RES_IRQ, 0, c, c, 1); rle = resource_list_find(&ch->ch_rlist, SYS_RES_IRQ, 0); rle->res = (ch->ch_ires != NULL) ? ch->ch_ires : sc->sc_chan[0].ch_ires; for (mode = 0; mode < SCC_NMODES; mode++) { m = &ch->ch_mode[mode]; m->m_chan = ch; m->m_mode = 1U << mode; if ((cl->cl_modes & m->m_mode) == 0 || ch->ch_sysdev) continue; m->m_dev = device_add_child(dev, NULL, -1); device_set_ivars(m->m_dev, (void *)m); error = device_probe_child(dev, m->m_dev); if (!error) { m->m_probed = 1; m->m_sysdev = SERDEV_SYSDEV(m->m_dev) ? 1 : 0; ch->ch_sysdev |= m->m_sysdev; } } next: start += (cl->cl_range < 0) ? -size : size; sysdev |= ch->ch_sysdev; } /* * Have the hardware driver initialize the hardware. Tell it * whether or not a hardware reset should be performed. */ if (bootverbose) { device_printf(dev, "%sresetting hardware\n", (sysdev) ? "not " : ""); } error = SCC_ATTACH(sc, !sysdev); if (error) goto fail; /* * Setup our interrupt handler. Make it FAST under the assumption * that our children's are fast as well. We make it MPSAFE as soon * as a child sets up a MPSAFE interrupt handler. * Of course, if we can't setup a fast handler, we make it MPSAFE * right away. */ for (c = 0; c < cl->cl_channels; c++) { ch = &sc->sc_chan[c]; if (ch->ch_ires == NULL) continue; error = bus_setup_intr(dev, ch->ch_ires, INTR_TYPE_TTY, scc_bfe_intr, NULL, sc, &ch->ch_icookie); if (error) { error = bus_setup_intr(dev, ch->ch_ires, INTR_TYPE_TTY | INTR_MPSAFE, NULL, (driver_intr_t *)scc_bfe_intr, sc, &ch->ch_icookie); } else sc->sc_fastintr = 1; if (error) { device_printf(dev, "could not activate interrupt\n"); bus_release_resource(dev, SYS_RES_IRQ, ch->ch_irid, ch->ch_ires); ch->ch_ires = NULL; } } sc->sc_polled = 1; for (c = 0; c < cl->cl_channels; c++) { if (sc->sc_chan[0].ch_ires != NULL) sc->sc_polled = 0; } /* * Attach all child devices that were probed successfully. */ for (c = 0; c < cl->cl_channels; c++) { ch = &sc->sc_chan[c]; for (mode = 0; mode < SCC_NMODES; mode++) { m = &ch->ch_mode[mode]; if (!m->m_probed) continue; error = device_attach(m->m_dev); if (error) continue; m->m_attached = 1; } } if (bootverbose && (sc->sc_fastintr || sc->sc_polled)) { sep = ""; device_print_prettyname(dev); if (sc->sc_fastintr) { printf("%sfast interrupt", sep); sep = ", "; } if (sc->sc_polled) { printf("%spolled mode", sep); sep = ", "; } printf("\n"); } return (0); fail: for (c = 0; c < cl->cl_channels; c++) { ch = &sc->sc_chan[c]; if (ch->ch_ires == NULL) continue; bus_release_resource(dev, SYS_RES_IRQ, ch->ch_irid, ch->ch_ires); } bus_release_resource(dev, sc->sc_rtype, sc->sc_rrid, sc->sc_rres); return (error); }
int puc_bfe_attach(device_t dev) { char buffer[64]; struct puc_bar *bar; struct puc_port *port; struct puc_softc *sc; struct rman *rm; intptr_t res; bus_addr_t ofs, start; bus_size_t size; bus_space_handle_t bsh; bus_space_tag_t bst; int error, idx; sc = device_get_softc(dev); for (idx = 0; idx < PUC_PCI_BARS; idx++) sc->sc_bar[idx].b_rid = -1; do { sc->sc_ioport.rm_type = RMAN_ARRAY; error = rman_init(&sc->sc_ioport); if (!error) { sc->sc_iomem.rm_type = RMAN_ARRAY; error = rman_init(&sc->sc_iomem); if (!error) { sc->sc_irq.rm_type = RMAN_ARRAY; error = rman_init(&sc->sc_irq); if (!error) break; rman_fini(&sc->sc_iomem); } rman_fini(&sc->sc_ioport); } return (error); } while (0); snprintf(buffer, sizeof(buffer), "%s I/O port mapping", device_get_nameunit(dev)); sc->sc_ioport.rm_descr = strdup(buffer, M_PUC); snprintf(buffer, sizeof(buffer), "%s I/O memory mapping", device_get_nameunit(dev)); sc->sc_iomem.rm_descr = strdup(buffer, M_PUC); snprintf(buffer, sizeof(buffer), "%s port numbers", device_get_nameunit(dev)); sc->sc_irq.rm_descr = strdup(buffer, M_PUC); error = puc_config(sc, PUC_CFG_GET_NPORTS, 0, &res); KASSERT(error == 0, ("%s %d", __func__, __LINE__)); sc->sc_nports = (int)res; sc->sc_port = malloc(sc->sc_nports * sizeof(struct puc_port), M_PUC, M_WAITOK|M_ZERO); error = rman_manage_region(&sc->sc_irq, 1, sc->sc_nports); if (error) goto fail; error = puc_config(sc, PUC_CFG_SETUP, 0, &res); if (error) goto fail; for (idx = 0; idx < sc->sc_nports; idx++) { port = &sc->sc_port[idx]; port->p_nr = idx + 1; error = puc_config(sc, PUC_CFG_GET_TYPE, idx, &res); if (error) goto fail; port->p_type = res; error = puc_config(sc, PUC_CFG_GET_RID, idx, &res); if (error) goto fail; bar = puc_get_bar(sc, res); if (bar == NULL) { error = ENXIO; goto fail; } port->p_bar = bar; start = rman_get_start(bar->b_res); error = puc_config(sc, PUC_CFG_GET_OFS, idx, &res); if (error) goto fail; ofs = res; error = puc_config(sc, PUC_CFG_GET_LEN, idx, &res); if (error) goto fail; size = res; rm = (bar->b_type == SYS_RES_IOPORT) ? &sc->sc_ioport: &sc->sc_iomem; port->p_rres = rman_reserve_resource(rm, start + ofs, start + ofs + size - 1, size, 0, NULL); if (port->p_rres != NULL) { bsh = rman_get_bushandle(bar->b_res); bst = rman_get_bustag(bar->b_res); bus_space_subregion(bst, bsh, ofs, size, &bsh); rman_set_bushandle(port->p_rres, bsh); rman_set_bustag(port->p_rres, bst); } port->p_ires = rman_reserve_resource(&sc->sc_irq, port->p_nr, port->p_nr, 1, 0, NULL); if (port->p_ires == NULL) { error = ENXIO; goto fail; } error = puc_config(sc, PUC_CFG_GET_CLOCK, idx, &res); if (error) goto fail; port->p_rclk = res; port->p_dev = device_add_child(dev, NULL, -1); if (port->p_dev != NULL) device_set_ivars(port->p_dev, (void *)port); } error = puc_config(sc, PUC_CFG_GET_ILR, 0, &res); if (error) goto fail; sc->sc_ilr = res; if (bootverbose && sc->sc_ilr != 0) device_printf(dev, "using interrupt latch register\n"); sc->sc_irid = 0; sc->sc_ires = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->sc_irid, RF_ACTIVE|RF_SHAREABLE); if (sc->sc_ires != NULL) { error = bus_setup_intr(dev, sc->sc_ires, INTR_TYPE_TTY, puc_intr, NULL, sc, &sc->sc_icookie); if (error) error = bus_setup_intr(dev, sc->sc_ires, INTR_TYPE_TTY | INTR_MPSAFE, NULL, (driver_intr_t *)puc_intr, sc, &sc->sc_icookie); else sc->sc_fastintr = 1; if (error) { device_printf(dev, "could not activate interrupt\n"); bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irid, sc->sc_ires); sc->sc_ires = NULL; } } if (sc->sc_ires == NULL) { /* XXX no interrupt resource. Force polled mode. */ sc->sc_polled = 1; } /* Probe and attach our children. */ for (idx = 0; idx < sc->sc_nports; idx++) { port = &sc->sc_port[idx]; if (port->p_dev == NULL) continue; error = device_probe_and_attach(port->p_dev); if (error) { device_delete_child(dev, port->p_dev); port->p_dev = NULL; } } /* * If there are no serdev devices, then our interrupt handler * will do nothing. Tear it down. */ if (sc->sc_serdevs == 0UL) bus_teardown_intr(dev, sc->sc_ires, sc->sc_icookie); return (0); fail: for (idx = 0; idx < sc->sc_nports; idx++) { port = &sc->sc_port[idx]; if (port->p_dev != NULL) device_delete_child(dev, port->p_dev); if (port->p_rres != NULL) rman_release_resource(port->p_rres); if (port->p_ires != NULL) rman_release_resource(port->p_ires); } for (idx = 0; idx < PUC_PCI_BARS; idx++) { bar = &sc->sc_bar[idx]; if (bar->b_res != NULL) bus_release_resource(sc->sc_dev, bar->b_type, bar->b_rid, bar->b_res); } rman_fini(&sc->sc_irq); free(__DECONST(void *, sc->sc_irq.rm_descr), M_PUC); rman_fini(&sc->sc_iomem); free(__DECONST(void *, sc->sc_iomem.rm_descr), M_PUC); rman_fini(&sc->sc_ioport); free(__DECONST(void *, sc->sc_ioport.rm_descr), M_PUC); free(sc->sc_port, M_PUC); return (error); }