Example #1
0
File: sbus.c Project: MarginC/kame
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);
}
Example #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);
	sc->sc_cbustag = sbus_alloc_bustag(sc);

	/*
	 * 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 = (struct sbus_rd *)malloc(sizeof(*sc->sc_rd) * sc->sc_nrange,
	    M_DEVBUF, M_NOWAIT);
	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_FAST,
	    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_FAST,
	    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));
}