Beispiel #1
0
int
pcib_host_res_decodes(struct pcib_host_resources *hr, int type, u_long start,
    u_long end, u_int flags)
{
	struct resource_list_entry *rle;
	int rid;

	if (bootverbose)
		device_printf(hr->hr_pcib, "decoding %d %srange %#lx-%#lx\n",
		    type, flags & RF_PREFETCHABLE ? "prefetchable ": "", start,
		    end);
	rid = resource_list_add_next(&hr->hr_rl, type, start, end,
	    end - start + 1);
	if (flags & RF_PREFETCHABLE) {
		KASSERT(type == SYS_RES_MEMORY,
		    ("only memory is prefetchable"));
		rle = resource_list_find(&hr->hr_rl, type, rid);
		rle->flags = RLE_PREFETCH;
	}
	return (0);
}
Beispiel #2
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));
}