Пример #1
0
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);
	}
}
Пример #2
0
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);
}
Пример #3
0
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);
}
Пример #4
0
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);
}