Exemplo n.º 1
0
static int
obio_attach(device_t dev)
{
	struct obio_softc *sc = device_get_softc(dev);

	sc->oba_st = mips_bus_space_generic;
	/*
	 * XXX
	 * Here and elsewhere using RBR as a base address because it kind of
	 * is, but that feels pretty sloppy.  Should consider adding a define
	 * that's more semantic, at least.
	 */
	sc->oba_addr = CVMX_MIO_UARTX_RBR(0);
	sc->oba_size = 0x10000;
	sc->oba_rman.rm_type = RMAN_ARRAY;
	sc->oba_rman.rm_descr = "OBIO I/O";
	if (rman_init(&sc->oba_rman) != 0 ||
	    rman_manage_region(&sc->oba_rman,
	    sc->oba_addr, sc->oba_addr + sc->oba_size) != 0)
		panic("obio_attach: failed to set up I/O rman");
	sc->oba_irq_rman.rm_type = RMAN_ARRAY;
	sc->oba_irq_rman.rm_descr = "OBIO IRQ";

	/* 
	 * This module is intended for UART purposes only and
	 * manages IRQs for UART0 and UART1.
	 */
	if (rman_init(&sc->oba_irq_rman) != 0 ||
	    rman_manage_region(&sc->oba_irq_rman, OCTEON_IRQ_UART0, OCTEON_IRQ_UART1) != 0)
		panic("obio_attach: failed to set up IRQ rman");

	device_add_child(dev, "uart", 1);  /* Setup Uart-1 first. */
	device_add_child(dev, "uart", 0);  /* Uart-0 next. So it is first in console list */
	bus_generic_probe(dev);
	bus_generic_attach(dev);
	return (0);
}
Exemplo n.º 2
0
static void
xlp_pci_init_resources(void)
{

	irq_rman.rm_start = 0;
	irq_rman.rm_end = 255;
	irq_rman.rm_type = RMAN_ARRAY;
	irq_rman.rm_descr = "PCI Mapped Interrupts";
	if (rman_init(&irq_rman)
	    || rman_manage_region(&irq_rman, 0, 255))
		panic("pci_init_resources irq_rman");

	port_rman.rm_start = 0;
	port_rman.rm_end = ~0ul;
	port_rman.rm_type = RMAN_ARRAY;
	port_rman.rm_descr = "I/O ports";
	if (rman_init(&port_rman)
	    || rman_manage_region(&port_rman, 0x14000000UL, 0x15ffffffUL))
		panic("pci_init_resources port_rman");

	mem_rman.rm_start = 0;
	mem_rman.rm_end = ~0ul;
	mem_rman.rm_type = RMAN_ARRAY;
	mem_rman.rm_descr = "I/O memory";
	if (rman_init(&mem_rman)
	    || rman_manage_region(&mem_rman, 0xd0000000ULL, 0xdfffffffULL))
		panic("pci_init_resources mem_rman");

	emul_rman.rm_start = 0;
	emul_rman.rm_end = ~0ul;
	emul_rman.rm_type = RMAN_ARRAY;
	emul_rman.rm_descr = "Emulated MEMIO";
	if (rman_init(&emul_rman)
	    || rman_manage_region(&emul_rman, 0x18000000ULL, 0x18ffffffULL))
		panic("pci_init_resources emul_rman");

}
Exemplo n.º 3
0
static int
obio_attach(device_t dev)
{
	struct obio_softc *sc = device_get_softc(dev);

	obio_bs_tag = arm_base_bs_tag;
	sc->oba_st = obio_bs_tag;
	sc->oba_rman.rm_type = RMAN_ARRAY;
	sc->oba_rman.rm_descr = "OBIO I/O";
	if (rman_init(&sc->oba_rman) != 0 ||
	    rman_manage_region(&sc->oba_rman,
	    IOP34X_UART0_VADDR, IOP34X_UART1_VADDR + 0x40) != 0)
		panic("obio_attach: failed to set up I/O rman");
	sc->oba_irq_rman.rm_type = RMAN_ARRAY;
	sc->oba_irq_rman.rm_descr = "OBIO IRQ";
	if (rman_init(&sc->oba_irq_rman) != 0 ||
	    rman_manage_region(&sc->oba_irq_rman, ICU_INT_UART0, ICU_INT_UART1) != 0)
		panic("obio_attach: failed to set up IRQ rman");
	device_add_child(dev, "uart", 0);
	device_add_child(dev, "uart", 1);
	bus_generic_probe(dev);
	bus_generic_attach(dev);
	return (0);
}
Exemplo n.º 4
0
int
obio_attach(device_t dev)
{
	struct obio_softc *sc = device_get_softc(dev);

	sc->oba_st = &obio_bs_tag;
	sc->oba_addr = IQ80321_OBIO_BASE;
	sc->oba_size = IQ80321_OBIO_SIZE;
	sc->oba_rman.rm_type = RMAN_ARRAY;
	sc->oba_rman.rm_descr = "OBIO I/O";
	if (rman_init(&sc->oba_rman) != 0 ||
	    rman_manage_region(&sc->oba_rman,
	    sc->oba_addr, sc->oba_addr + sc->oba_size) != 0)
		panic("obio_attach: failed to set up I/O rman");
	sc->oba_irq_rman.rm_type = RMAN_ARRAY;
	sc->oba_irq_rman.rm_descr = "OBIO IRQ";
	if (rman_init(&sc->oba_irq_rman) != 0 ||
	    rman_manage_region(&sc->oba_irq_rman, 28, 28) != 0)
		panic("obio_attach: failed to set up IRQ rman");
	device_add_child(dev, "uart", 0);
	bus_generic_probe(dev);
	bus_generic_attach(dev);
	return (0);
}
Exemplo n.º 5
0
static int
nexus_attach(device_t dev)
{

	mem_rman.rm_start = 0;
	mem_rman.rm_end = ~0ul;
	mem_rman.rm_type = RMAN_ARRAY;
	mem_rman.rm_descr = "I/O memory addresses";
	if (rman_init(&mem_rman) || rman_manage_region(&mem_rman, 0, ~0))
		panic("nexus_probe mem_rman");

	/*
	 * First, deal with the children we know about already
	 */
	bus_generic_probe(dev);
	bus_generic_attach(dev);

	return (0);
}
Exemplo n.º 6
0
static void
wiibus_init_device_resources(struct rman *rm, struct wiibus_devinfo *dinfo,
    unsigned int rid, uintptr_t addr, size_t len, unsigned int irq)

{

	if (!dinfo->di_init) {
		resource_list_init(&dinfo->di_resources);
		dinfo->di_init++;
	}
	if (addr) {
		rman_manage_region(rm, addr, addr + len - 1);
		resource_list_add(&dinfo->di_resources, SYS_RES_MEMORY, rid,
		    addr, addr + len, len);
	}
	if (irq)
		resource_list_add(&dinfo->di_resources, SYS_RES_IRQ, rid,
		    irq, irq, 1);
}
Exemplo n.º 7
0
/* Allocate region records for the given port, and add the port's memory
 * range to the mem_rman */
static int
chipc_rman_init_regions (struct chipc_softc *sc, bhnd_port_type type,
    u_int port)
{
	struct	chipc_region	*cr;
	rman_res_t		 start, end;
	u_int			 num_regions;
	int			 error;

	num_regions = bhnd_get_region_count(sc->dev, type, port);
	for (u_int region = 0; region < num_regions; region++) {
		/* Allocate new region record */
		cr = chipc_alloc_region(sc, type, port, region);
		if (cr == NULL)
			return (ENODEV);

		/* Can't manage regions that cannot be allocated */
		if (cr->cr_rid < 0) {
			BHND_DEBUG_DEV(sc->dev, "no rid for chipc region "
			    "%s%u.%u", bhnd_port_type_name(type), port, region);
			chipc_free_region(sc, cr);
			continue;
		}

		/* Add to rman's managed range */
		start = cr->cr_addr;
		end = cr->cr_end;
		if ((error = rman_manage_region(&sc->mem_rman, start, end))) {
			chipc_free_region(sc, cr);
			return (error);
		}

		/* Add to region list */
		STAILQ_INSERT_TAIL(&sc->mem_regions, cr, cr_link);
	}

	return (0);
}
Exemplo n.º 8
0
/*
 * Create an sgmap to manage a range of bus addresses which map
 * physical memory using a scatter-gather map.
 */
struct sgmap *
sgmap_map_create(bus_addr_t sba, bus_addr_t eba,
		 sgmap_map_callback *map, void *arg)
{
	struct sgmap *sgmap;
    
	sgmap = malloc(sizeof *sgmap, M_SGMAP, M_NOWAIT);
	if (!sgmap)
		return 0;


	sgmap->rm.rm_start = sba;
	sgmap->rm.rm_end = eba;
	sgmap->rm.rm_type = RMAN_ARRAY;
	sgmap->rm.rm_descr = "Scatter Gather Bus Addresses";
	rman_init(&sgmap->rm);
	rman_manage_region(&sgmap->rm, sba, eba);
	sgmap->map = map;
	sgmap->arg = arg;
	sgmap->sba = sba;
	sgmap->eba = eba;

	return sgmap;
}
Exemplo n.º 9
0
static int
pxa_smi_attach(device_t dev)
{
	int		error, i, dunit;
	const char	*dname;
	struct		pxa_smi_softc *sc;

	sc = (struct pxa_smi_softc *)device_get_softc(dev);

	error = bus_alloc_resources(dev, pxa_smi_spec, sc->ps_res);
	if (error) {
		device_printf(dev, "could not allocate resources\n");
		return (ENXIO);
	}

	sc->ps_mem.rm_type = RMAN_ARRAY;
	sc->ps_mem.rm_descr = device_get_nameunit(dev);
	if (rman_init(&sc->ps_mem) != 0)
		panic("pxa_smi_attach: failed to init mem rman");
	if (rman_manage_region(&sc->ps_mem, 0, PXA2X0_CS_SIZE * 6) != 0)
		panic("pxa_smi_attach: failed ot set up mem rman");

	sc->ps_bst = base_tag;
	sc->ps_base = rman_get_start(sc->ps_res[0]);

	i = 0;
	while (resource_find_match(&i, &dname, &dunit, "at",
	    device_get_nameunit(dev)) == 0) {
		pxa_smi_add_device(dev, dname, dunit);
	}

	bus_generic_probe(dev);
	bus_generic_attach(dev);

	return (0);
}
Exemplo n.º 10
0
static int
nexus_attach(device_t dev)
{
	phandle_t	root;
	phandle_t	child;
	struct		nexus_softc *sc;
	u_long		start, end;

	sc = device_get_softc(dev);

	start = 0;
	end = MAX_PICS*INTR_VECTORS - 1;

	sc->sc_rman.rm_start = start;
	sc->sc_rman.rm_end = end;
	sc->sc_rman.rm_type = RMAN_ARRAY;
	sc->sc_rman.rm_descr = "Interrupt request lines";
	if (rman_init(&sc->sc_rman) ||
	    rman_manage_region(&sc->sc_rman, start, end))
		panic("nexus_probe IRQ rman");

	if ((root = OF_peer(0)) == 0)
		return (bus_generic_attach(dev));
		
	/*
	 * Now walk the OFW tree to locate top-level devices
	 */
	for (child = OF_child(root); child != 0; child = OF_peer(child)) {
		if (child == -1)
			panic("nexus_probe(): OF_child failed.");
		(void)nexus_device_from_node(dev, child);

	}

	return (bus_generic_attach(dev));
}
Exemplo n.º 11
0
static int
fdtbus_attach(device_t dev)
{
	phandle_t root;
	phandle_t child;
	struct fdtbus_softc *sc;
	u_long start, end;
	int error;

	if ((root = OF_finddevice("/")) == -1)
		panic("fdtbus_attach: no root node.");

	sc = device_get_softc(dev);

	/*
	 * IRQ rman.
	 */
	start = 0;
	end = ~0;
	sc->sc_irq.rm_start = start;
	sc->sc_irq.rm_end = end;
	sc->sc_irq.rm_type = RMAN_ARRAY;
	sc->sc_irq.rm_descr = "Interrupt request lines";
	if ((error = rman_init(&sc->sc_irq)) != 0) {
		device_printf(dev, "could not init IRQ rman, error = %d\n",
		    error);
		return (error);
	}
	if ((error = rman_manage_region(&sc->sc_irq, start, end)) != 0) {
		device_printf(dev, "could not manage IRQ region, error = %d\n",
		    error);
		return (error);
	}

	/*
	 * Mem-mapped I/O space rman.
	 */
	start = 0;
	end = ~0ul;
	sc->sc_mem.rm_start = start;
	sc->sc_mem.rm_end = end;
	sc->sc_mem.rm_type = RMAN_ARRAY;
	sc->sc_mem.rm_descr = "I/O memory";
	if ((error = rman_init(&sc->sc_mem)) != 0) {
		device_printf(dev, "could not init I/O mem rman, error = %d\n",
		    error);
		return (error);
	}
	if ((error = rman_manage_region(&sc->sc_mem, start, end)) != 0) {
		device_printf(dev, "could not manage I/O mem region, "
		    "error = %d\n", error);
		return (error);
	}

	/*
	 * Walk the FDT root node and add top-level devices as our children.
	 */
	for (child = OF_child(root); child != 0; child = OF_peer(child)) {
		/* Check and process 'status' property. */
		if (!(fdt_is_enabled(child)))
			continue;

		newbus_device_from_fdt_node(dev, child);
	}

	return (bus_generic_attach(dev));
}
Exemplo n.º 12
0
static int
iobus_attach(device_t dev)
{
	struct iobus_softc *sc;
        struct iobus_devinfo *dinfo;
        phandle_t  root;
        phandle_t  child;
        device_t   cdev;
        char *name;
	u_int reg[2];
	int size;

	sc = device_get_softc(dev);
	sc->sc_node = ofw_bus_get_node(dev);

	/*
	 * Find the base addr/size of the iobus, and initialize the
	 * resource manager
	 */
	size = OF_getprop(sc->sc_node, "reg", reg, sizeof(reg));
	if (size == sizeof(reg)) {
		sc->sc_addr = reg[0];
		sc->sc_size = reg[1];
	} else {
		return (ENXIO);
	}

	sc->sc_mem_rman.rm_type = RMAN_ARRAY;
        sc->sc_mem_rman.rm_descr = "IOBus Device Memory";
        if (rman_init(&sc->sc_mem_rman) != 0) {
		device_printf(dev,
                    "failed to init mem range resources\n");
                return (ENXIO);
	}
	rman_manage_region(&sc->sc_mem_rman, 0, sc->sc_size);

        /*
         * Iterate through the sub-devices
         */
        root = sc->sc_node;

        for (child = OF_child(root); child != 0; child = OF_peer(child)) {
                OF_getprop_alloc(child, "name", 1, (void **)&name);

                cdev = device_add_child(dev, NULL, -1);
                if (cdev != NULL) {
                        dinfo = malloc(sizeof(*dinfo), M_IOBUS, M_WAITOK);
			memset(dinfo, 0, sizeof(*dinfo));
			resource_list_init(&dinfo->id_resources);
                        dinfo->id_node = child;
                        dinfo->id_name = name;
			iobus_add_intr(child, dinfo);
			iobus_add_reg(child, dinfo, sc->sc_addr);
                        device_set_ivars(cdev, dinfo);
                } else {
                        free(name, M_OFWPROP);
                }
        }

        return (bus_generic_attach(dev));
}
Exemplo n.º 13
0
void
nexus_init_resources(void)
{
	int irq;

	/*
	 * XXX working notes:
	 *
	 * - IRQ resource creation should be moved to the PIC/APIC driver.
	 * - DRQ resource creation should be moved to the DMAC driver.
	 * - The above should be sorted to probe earlier than any child busses.
	 *
	 * - Leave I/O and memory creation here, as child probes may need them.
	 *   (especially eg. ACPI)
	 */

	/*
	 * IRQ's are on the mainboard on old systems, but on the ISA part
	 * of PCI->ISA bridges.  There would be multiple sets of IRQs on
	 * multi-ISA-bus systems.  PCI interrupts are routed to the ISA
	 * component, so in a way, PCI can be a partial child of an ISA bus(!).
	 * APIC interrupts are global though.
	 */
	irq_rman.rm_start = 0;
	irq_rman.rm_type = RMAN_ARRAY;
	irq_rman.rm_descr = "Interrupt request lines";
	irq_rman.rm_end = NUM_IO_INTS - 1;
	if (rman_init(&irq_rman))
		panic("nexus_init_resources irq_rman");

	/*
	 * We search for regions of existing IRQs and add those to the IRQ
	 * resource manager.
	 */
	for (irq = 0; irq < NUM_IO_INTS; irq++)
		if (intr_lookup_source(irq) != NULL)
			if (rman_manage_region(&irq_rman, irq, irq) != 0)
				panic("nexus_init_resources irq_rman add");

	/*
	 * ISA DMA on PCI systems is implemented in the ISA part of each
	 * PCI->ISA bridge and the channels can be duplicated if there are
	 * multiple bridges.  (eg: laptops with docking stations)
	 */
	drq_rman.rm_start = 0;
#ifdef PC98
	drq_rman.rm_end = 3;
#else
	drq_rman.rm_end = 7;
#endif
	drq_rman.rm_type = RMAN_ARRAY;
	drq_rman.rm_descr = "DMA request lines";
	/* XXX drq 0 not available on some machines */
	if (rman_init(&drq_rman)
	    || rman_manage_region(&drq_rman,
				  drq_rman.rm_start, drq_rman.rm_end))
		panic("nexus_init_resources drq_rman");

	/*
	 * However, IO ports and Memory truely are global at this level,
	 * as are APIC interrupts (however many IO APICS there turn out
	 * to be on large systems..)
	 */
	port_rman.rm_start = 0;
	port_rman.rm_end = 0xffff;
	port_rman.rm_type = RMAN_ARRAY;
	port_rman.rm_descr = "I/O ports";
	if (rman_init(&port_rman)
	    || rman_manage_region(&port_rman, 0, 0xffff))
		panic("nexus_init_resources port_rman");

	mem_rman.rm_start = 0;
	mem_rman.rm_end = ~0ul;
	mem_rman.rm_type = RMAN_ARRAY;
	mem_rman.rm_descr = "I/O memory addresses";
	if (rman_init(&mem_rman)
	    || rman_manage_region(&mem_rman, 0, ~0))
		panic("nexus_init_resources mem_rman");
}
Exemplo n.º 14
0
Arquivo: sbus.c Projeto: 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);
}
Exemplo n.º 15
0
Arquivo: nexus.c Projeto: MarginC/kame
static int
nexus_probe(device_t dev)
{

	device_quiet(dev);	/* suppress attach message for neatness */

	/* 
	 * XXX working notes:
	 *
	 * - IRQ resource creation should be moved to the PIC/APIC driver.
	 * - DRQ resource creation should be moved to the DMAC driver.
	 * - The above should be sorted to probe earlier than any child busses.
	 *
	 * - Leave I/O and memory creation here, as child probes may need them.
	 *   (especially eg. ACPI)
	 */

	/*
	 * IRQ's are on the mainboard on old systems, but on the ISA part
	 * of PCI->ISA bridges.  There would be multiple sets of IRQs on
	 * multi-ISA-bus systems.  PCI interrupts are routed to the ISA
	 * component, so in a way, PCI can be a partial child of an ISA bus(!).
	 * APIC interrupts are global though.
	 *
	 * XXX We depend on the AT PIC driver correctly claiming IRQ 2
	 *     to prevent its reuse elsewhere in the !APIC_IO case.
	 */
	irq_rman.rm_start = 0;
	irq_rman.rm_type = RMAN_ARRAY;
	irq_rman.rm_descr = "Interrupt request lines";
#ifdef APIC_IO
	irq_rman.rm_end = APIC_INTMAPSIZE - 1;
#else
	irq_rman.rm_end = 15;
#endif
	if (rman_init(&irq_rman)
	    || rman_manage_region(&irq_rman,
				  irq_rman.rm_start, irq_rman.rm_end))
		panic("nexus_probe irq_rman");

	/*
	 * ISA DMA on PCI systems is implemented in the ISA part of each
	 * PCI->ISA bridge and the channels can be duplicated if there are
	 * multiple bridges.  (eg: laptops with docking stations)
	 */
	drq_rman.rm_start = 0;
#ifdef PC98
	drq_rman.rm_end = 3;
#else
	drq_rman.rm_end = 7;
#endif
	drq_rman.rm_type = RMAN_ARRAY;
	drq_rman.rm_descr = "DMA request lines";
	/* XXX drq 0 not available on some machines */
	if (rman_init(&drq_rman)
	    || rman_manage_region(&drq_rman,
				  drq_rman.rm_start, drq_rman.rm_end))
		panic("nexus_probe drq_rman");

	/*
	 * However, IO ports and Memory truely are global at this level,
	 * as are APIC interrupts (however many IO APICS there turn out
	 * to be on large systems..)
	 */
	port_rman.rm_start = 0;
	port_rman.rm_end = 0xffff;
	port_rman.rm_type = RMAN_ARRAY;
	port_rman.rm_descr = "I/O ports";
	if (rman_init(&port_rman)
	    || rman_manage_region(&port_rman, 0, 0xffff))
		panic("nexus_probe port_rman");

	mem_rman.rm_start = 0;
	mem_rman.rm_end = ~0u;
	mem_rman.rm_type = RMAN_ARRAY;
	mem_rman.rm_descr = "I/O memory addresses";
	if (rman_init(&mem_rman)
	    || rman_manage_region(&mem_rman, 0, ~0))
		panic("nexus_probe mem_rman");

	return 0;
}
Exemplo n.º 16
0
static int
lbc_attach(device_t dev)
{
	struct lbc_softc *sc;
	struct lbc_devinfo *di;
	struct rman *rm;
	u_long offset, start, size;
	device_t cdev;
	phandle_t node, child;
	pcell_t *ranges, *rangesptr;
	int tuple_size, tuples;
	int par_addr_cells;
	int bank, error, i;

	sc = device_get_softc(dev);
	sc->sc_dev = dev;

	sc->sc_mrid = 0;
	sc->sc_mres = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->sc_mrid,
	    RF_ACTIVE);
	if (sc->sc_mres == NULL)
		return (ENXIO);

	sc->sc_bst = rman_get_bustag(sc->sc_mres);
	sc->sc_bsh = rman_get_bushandle(sc->sc_mres);

	for (bank = 0; bank < LBC_DEV_MAX; bank++) {
		bus_space_write_4(sc->sc_bst, sc->sc_bsh, LBC85XX_BR(bank), 0);
		bus_space_write_4(sc->sc_bst, sc->sc_bsh, LBC85XX_OR(bank), 0);
	}

	/*
	 * Initialize configuration register:
	 * - enable Local Bus
	 * - set data buffer control signal function
	 * - disable parity byte select
	 * - set ECC parity type
	 * - set bus monitor timing and timer prescale
	 */
	bus_space_write_4(sc->sc_bst, sc->sc_bsh, LBC85XX_LBCR, 0);

	/*
	 * Initialize clock ratio register:
	 * - disable PLL bypass mode
	 * - configure LCLK delay cycles for the assertion of LALE
	 * - set system clock divider
	 */
	bus_space_write_4(sc->sc_bst, sc->sc_bsh, LBC85XX_LCRR, 0x00030008);

	bus_space_write_4(sc->sc_bst, sc->sc_bsh, LBC85XX_LTEDR, 0);
	bus_space_write_4(sc->sc_bst, sc->sc_bsh, LBC85XX_LTESR, ~0);
	bus_space_write_4(sc->sc_bst, sc->sc_bsh, LBC85XX_LTEIR, 0x64080001);

	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_MISC | INTR_MPSAFE, NULL, lbc_intr, sc,
		    &sc->sc_icookie);
		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;
		}
	}

	sc->sc_ltesr = ~0;

	rangesptr = NULL;

	rm = &sc->sc_rman;
	rm->rm_type = RMAN_ARRAY;
	rm->rm_descr = "Local Bus Space";
	rm->rm_start = 0UL;
	rm->rm_end = ~0UL;
	error = rman_init(rm);
	if (error)
		goto fail;

	error = rman_manage_region(rm, rm->rm_start, rm->rm_end);
	if (error) {
		rman_fini(rm);
		goto fail;
	}

	/*
	 * Process 'ranges' property.
	 */
	node = ofw_bus_get_node(dev);
	if ((fdt_addrsize_cells(node, &sc->sc_addr_cells,
	    &sc->sc_size_cells)) != 0) {
		error = ENXIO;
		goto fail;
	}

	par_addr_cells = fdt_parent_addr_cells(node);
	if (par_addr_cells > 2) {
		device_printf(dev, "unsupported parent #addr-cells\n");
		error = ERANGE;
		goto fail;
	}
	tuple_size = sizeof(pcell_t) * (sc->sc_addr_cells + par_addr_cells +
	    sc->sc_size_cells);

	tuples = OF_getprop_alloc(node, "ranges", tuple_size,
	    (void **)&ranges);
	if (tuples < 0) {
		device_printf(dev, "could not retrieve 'ranges' property\n");
		error = ENXIO;
		goto fail;
	}
	rangesptr = ranges;

	debugf("par addr_cells = %d, addr_cells = %d, size_cells = %d, "
	    "tuple_size = %d, tuples = %d\n", par_addr_cells,
	    sc->sc_addr_cells, sc->sc_size_cells, tuple_size, tuples);

	start = 0;
	size = 0;
	for (i = 0; i < tuples; i++) {

		/* The first cell is the bank (chip select) number. */
		bank = fdt_data_get((void *)ranges, 1);
		if (bank < 0 || bank > LBC_DEV_MAX) {
			device_printf(dev, "bank out of range: %d\n", bank);
			error = ERANGE;
			goto fail;
		}
		ranges += 1;

		/*
		 * Remaining cells of the child address define offset into
		 * this CS.
		 */
		offset = fdt_data_get((void *)ranges, sc->sc_addr_cells - 1);
		ranges += sc->sc_addr_cells - 1;

		/* Parent bus start address of this bank. */
		start = fdt_data_get((void *)ranges, par_addr_cells);
		ranges += par_addr_cells;

		size = fdt_data_get((void *)ranges, sc->sc_size_cells);
		ranges += sc->sc_size_cells;
		debugf("bank = %d, start = %lx, size = %lx\n", bank,
		    start, size);

		sc->sc_banks[bank].addr = start + offset;
		sc->sc_banks[bank].size = size;

		/*
		 * Attributes for the bank.
		 *
		 * XXX Note there are no DT bindings defined for them at the
		 * moment, so we need to provide some defaults.
		 */
		sc->sc_banks[bank].width = 16;
		sc->sc_banks[bank].msel = LBCRES_MSEL_GPCM;
		sc->sc_banks[bank].decc = LBCRES_DECC_DISABLED;
		sc->sc_banks[bank].atom = LBCRES_ATOM_DISABLED;
		sc->sc_banks[bank].wp = 0;
	}

	/*
	 * Initialize mem-mappings for the LBC banks (i.e. chip selects).
	 */
	error = lbc_banks_map(sc);
	if (error)
		goto fail;

	/*
	 * Walk the localbus and add direct subordinates as our children.
	 */
	for (child = OF_child(node); child != 0; child = OF_peer(child)) {

		di = malloc(sizeof(*di), M_LBC, M_WAITOK | M_ZERO);

		if (ofw_bus_gen_setup_devinfo(&di->di_ofw, child) != 0) {
			free(di, M_LBC);
			device_printf(dev, "could not set up devinfo\n");
			continue;
		}

		resource_list_init(&di->di_res);

		if (fdt_lbc_reg_decode(child, sc, di)) {
			device_printf(dev, "could not process 'reg' "
			    "property\n");
			ofw_bus_gen_destroy_devinfo(&di->di_ofw);
			free(di, M_LBC);
			continue;
		}

		fdt_lbc_fixup(child, sc, di);

		/* Add newbus device for this FDT node */
		cdev = device_add_child(dev, NULL, -1);
		if (cdev == NULL) {
			device_printf(dev, "could not add child: %s\n",
			    di->di_ofw.obd_name);
			resource_list_free(&di->di_res);
			ofw_bus_gen_destroy_devinfo(&di->di_ofw);
			free(di, M_LBC);
			continue;
		}
		debugf("added child name='%s', node=%p\n", di->di_ofw.obd_name,
		    (void *)child);
		device_set_ivars(cdev, di);
	}

	/*
	 * Enable the LBC.
	 */
	lbc_banks_enable(sc);

	free(rangesptr, M_OFWPROP);
	return (bus_generic_attach(dev));

fail:
	free(rangesptr, M_OFWPROP);
	bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_mrid, sc->sc_mres);
	return (error);
}
Exemplo n.º 17
0
static void
ps3bus_resources_init_by_type(struct rman *rm, int bus_index, int dev_index,
    uint64_t irq_type, uint64_t reg_type, struct ps3bus_devinfo *dinfo)
{
	uint64_t _irq_type, irq, outlet;
	uint64_t _reg_type, paddr, len;
	uint64_t ppe, junk;
	int i, result;
	int thread;

	resource_list_init(&dinfo->resources);

	lv1_get_logical_ppe_id(&ppe);
	thread = 32 - fls(mfctrl());

	/* Scan for interrupts */
	for (i = 0; i < 10; i++) {
		result = lv1_get_repository_node_value(PS3_LPAR_ID_PME,
		    (lv1_repository_string("bus") >> 32) | bus_index,
		    lv1_repository_string("dev") | dev_index,
		    lv1_repository_string("intr") | i, 0, &_irq_type, &irq);

		if (result != 0)
			break;

		if (_irq_type != irq_type)
			continue;

		lv1_construct_io_irq_outlet(irq, &outlet);
		lv1_connect_irq_plug_ext(ppe, thread, outlet, outlet,
		    0);
		resource_list_add(&dinfo->resources, SYS_RES_IRQ, i,
		    outlet, outlet, 1);
	}

	/* Scan for registers */
	for (i = 0; i < 10; i++) {
		result = lv1_get_repository_node_value(PS3_LPAR_ID_PME,
		    (lv1_repository_string("bus") >> 32) | bus_index,
		    lv1_repository_string("dev") | dev_index,
		    lv1_repository_string("reg") | i, 
		    lv1_repository_string("type"), &_reg_type, &junk);

		if (result != 0)
			break;

		if (_reg_type != reg_type)
			continue;

		result = lv1_get_repository_node_value(PS3_LPAR_ID_PME,
		    (lv1_repository_string("bus") >> 32) | bus_index,
		    lv1_repository_string("dev") | dev_index,
		    lv1_repository_string("reg") | i, 
		    lv1_repository_string("data"), &paddr, &len);

		result = lv1_map_device_mmio_region(dinfo->bus, dinfo->dev,
		    paddr, len, 12 /* log_2(4 KB) */, &paddr);

		if (result != 0) {
			printf("Mapping registers failed for device "
			    "%d.%d (%ld.%ld): %d\n", dinfo->bus, dinfo->dev,
			    dinfo->bustype, dinfo->devtype, result);
			break;
		}

		rman_manage_region(rm, paddr, paddr + len - 1);
		resource_list_add(&dinfo->resources, SYS_RES_MEMORY, i,
		    paddr, paddr + len, len);
	}
}
Exemplo n.º 18
0
static int
unin_chip_attach(device_t dev)
{
	struct unin_chip_softc *sc;
	struct unin_chip_devinfo *dinfo;
	phandle_t  root;
	phandle_t  child;
	phandle_t  iparent;
	device_t   cdev;
	cell_t     acells, scells;
	char compat[32];
	char name[32];
	u_int irq, reg[3];
	int error, i = 0;

	sc = device_get_softc(dev);
	root = ofw_bus_get_node(dev);

	if (OF_getprop(root, "reg", reg, sizeof(reg)) < 8)
		return (ENXIO);

	acells = scells = 1;
	OF_getprop(OF_parent(root), "#address-cells", &acells, sizeof(acells));
	OF_getprop(OF_parent(root), "#size-cells", &scells, sizeof(scells));

	i = 0;
	sc->sc_physaddr = reg[i++];
	if (acells == 2) {
		sc->sc_physaddr <<= 32;
		sc->sc_physaddr |= reg[i++];
	}
	sc->sc_size = reg[i++];
	if (scells == 2) {
		sc->sc_size <<= 32;
		sc->sc_size |= reg[i++];
	}

	sc->sc_mem_rman.rm_type = RMAN_ARRAY;
	sc->sc_mem_rman.rm_descr = "UniNorth Device Memory";

	error = rman_init(&sc->sc_mem_rman);

	if (error) {
		device_printf(dev, "rman_init() failed. error = %d\n", error);
		return (error);
	}

	error = rman_manage_region(&sc->sc_mem_rman, sc->sc_physaddr,
				   sc->sc_physaddr + sc->sc_size - 1);	
	if (error) {
		device_printf(dev,
			      "rman_manage_region() failed. error = %d\n",
			      error);
		return (error);
	}

	if (unin_chip == NULL)
		unin_chip = dev;

        /*
	 * Iterate through the sub-devices
	 */
	for (child = OF_child(root); child != 0; child = OF_peer(child)) {
		dinfo = malloc(sizeof(*dinfo), M_UNIN, M_WAITOK | M_ZERO);
		if (ofw_bus_gen_setup_devinfo(&dinfo->udi_obdinfo, child)
		    != 0)
		{
			free(dinfo, M_UNIN);
			continue;
		}

		resource_list_init(&dinfo->udi_resources);
		dinfo->udi_ninterrupts = 0;
		unin_chip_add_intr(child, dinfo);

		/*
		 * Some Apple machines do have a bug in OF, they miss
		 * the interrupt entries on the U3 I2C node. That means they
		 * do not have an entry with number of interrupts nor the
		 * entry of the interrupt parent handle.
		 * We define an interrupt and hardwire it to the /u3/mpic
		 * handle.
		 */

		if (OF_getprop(child, "name", name, sizeof(name)) <= 0)
			device_printf(dev, "device has no name!\n");
		if (dinfo->udi_ninterrupts == 0 &&
		    (strcmp(name, "i2c-bus") == 0 ||
		     strcmp(name, "i2c")  == 0)) {
			if (OF_getprop(child, "interrupt-parent", &iparent,
				       sizeof(iparent)) <= 0) {
				iparent = OF_finddevice("/u3/mpic");
				device_printf(dev, "Set /u3/mpic as iparent!\n");
			}
			/* Add an interrupt number 0 to the parent. */
			irq = MAP_IRQ(iparent, 0);
			resource_list_add(&dinfo->udi_resources, SYS_RES_IRQ,
					  dinfo->udi_ninterrupts, irq, irq, 1);
			dinfo->udi_interrupts[dinfo->udi_ninterrupts] = irq;
			dinfo->udi_ninterrupts++;
		}

		unin_chip_add_reg(child, dinfo);

		cdev = device_add_child(dev, NULL, -1);
		if (cdev == NULL) {
			device_printf(dev, "<%s>: device_add_child failed\n",
				      dinfo->udi_obdinfo.obd_name);
			resource_list_free(&dinfo->udi_resources);
			ofw_bus_gen_destroy_devinfo(&dinfo->udi_obdinfo);
			free(dinfo, M_UNIN);
			continue;
		}

		device_set_ivars(cdev, dinfo);
	}

	/*
	 * Only map the first page, since that is where the registers
	 * of interest lie.
	 */
	sc->sc_addr = (vm_offset_t)pmap_mapdev(sc->sc_physaddr, PAGE_SIZE);

	sc->sc_version = *(u_int *)sc->sc_addr;
	device_printf(dev, "Version %d\n", sc->sc_version);

	/*
	 * Enable the GMAC Ethernet cell and the integrated OpenPIC
	 * if Open Firmware says they are used.
	 */
	for (child = OF_child(root); child; child = OF_peer(child)) {
		memset(compat, 0, sizeof(compat));
		OF_getprop(child, "compatible", compat, sizeof(compat));
		if (strcmp(compat, "gmac") == 0)
			unin_enable_gmac(dev);
		if (strcmp(compat, "chrp,open-pic") == 0)
			unin_enable_mpic(dev);
	}
	
	/*
	 * GMAC lives under the PCI bus, so just check if enet is gmac.
	 */
	child = OF_finddevice("enet");
	memset(compat, 0, sizeof(compat));
	OF_getprop(child, "compatible", compat, sizeof(compat));
	if (strcmp(compat, "gmac") == 0)
		unin_enable_gmac(dev);

	return (bus_generic_attach(dev));
}
Exemplo n.º 19
0
static int
ebus_attach(device_t dev)
{
	struct ebus_softc *sc;
	struct ebus_devinfo *edi;
	struct ebus_rinfo *eri;
	struct resource *res;
	device_t cdev;
	phandle_t node;
	int i, rnum, rid;

	sc = device_get_softc(dev);

	node = ofw_bus_get_node(dev);
	sc->sc_nrange = OF_getprop_alloc(node, "ranges",
	    sizeof(*sc->sc_range), (void **)&sc->sc_range);
	if (sc->sc_nrange == -1) {
		printf("ebus_attach: could not get ranges property\n");
		return (ENXIO);
	}

	sc->sc_rinfo = malloc(sizeof(*sc->sc_rinfo) * sc->sc_nrange, M_DEVBUF,
	    M_WAITOK | M_ZERO);

	/* For every range, there must be a matching resource. */
	for (rnum = 0; rnum < sc->sc_nrange; rnum++) {
		eri = &sc->sc_rinfo[rnum];
		eri->eri_rtype = ofw_isa_range_restype(&sc->sc_range[rnum]);
		rid = PCIR_BAR(rnum);
		res = bus_alloc_resource_any(dev, eri->eri_rtype, &rid,
		    RF_ACTIVE);
		if (res == NULL) {
			printf("ebus_attach: failed to allocate range "
			    "resource!\n");
			goto fail;
		}
		eri->eri_res = res;
		eri->eri_rman.rm_type = RMAN_ARRAY;
		eri->eri_rman.rm_descr = "EBus range";
		if (rman_init(&eri->eri_rman) != 0) {
			printf("ebus_attach: failed to initialize rman!");
			goto fail;
		}
		if (rman_manage_region(&eri->eri_rman, rman_get_start(res),
		    rman_get_end(res)) != 0) {
			printf("ebus_attach: failed to register region!");
			rman_fini(&eri->eri_rman);
			goto fail;
		}
	}

	ofw_bus_setup_iinfo(node, &sc->sc_iinfo, sizeof(ofw_isa_intr_t));

	/*
	 * Now attach our children.
	 */
	for (node = OF_child(node); node > 0; node = OF_peer(node)) {
		if ((edi = ebus_setup_dinfo(dev, sc, node)) == NULL)
			continue;
		if ((cdev = device_add_child(dev, NULL, -1)) == NULL) {
			device_printf(dev, "<%s>: device_add_child failed\n",
			    edi->edi_obdinfo.obd_name);
			ebus_destroy_dinfo(edi);
			continue;
		}
		device_set_ivars(cdev, edi);
	}
	return (bus_generic_attach(dev));

fail:
	for (i = rnum; i >= 0; i--) {
		eri = &sc->sc_rinfo[i];
		if (i < rnum)
			rman_fini(&eri->eri_rman);
		if (eri->eri_res != 0) {
			bus_release_resource(dev, eri->eri_rtype,
			    PCIR_BAR(rnum), eri->eri_res);
		}
	}
	free(sc->sc_rinfo, M_DEVBUF);
	free(sc->sc_range, M_OFWPROP);
	return (ENXIO);
}
Exemplo n.º 20
0
static int 
ps3bus_attach(device_t self) 
{
	struct ps3bus_softc *sc;
	struct ps3bus_devinfo *dinfo;
	int bus_index, dev_index, result;
	uint64_t bustype, bus, devs;
	uint64_t dev, devtype;
	uint64_t junk;
	device_t cdev;

	sc = device_get_softc(self);
	sc->sc_mem_rman.rm_type = RMAN_ARRAY;
	sc->sc_mem_rman.rm_descr = "PS3Bus Memory Mapped I/O";
	sc->sc_intr_rman.rm_type = RMAN_ARRAY;
	sc->sc_intr_rman.rm_descr = "PS3Bus Interrupts";
	rman_init(&sc->sc_mem_rman);
	rman_init(&sc->sc_intr_rman);
	rman_manage_region(&sc->sc_intr_rman, 0, ~0);

	/* Get memory regions for DMA */
	mem_regions(&sc->regions, &sc->rcount, &sc->regions, &sc->rcount);

	/*
	 * Probe all the PS3's buses.
	 */

	for (bus_index = 0; bus_index < 5; bus_index++) {
		result = lv1_get_repository_node_value(PS3_LPAR_ID_PME,
		    (lv1_repository_string("bus") >> 32) | bus_index,
		    lv1_repository_string("type"), 0, 0, &bustype, &junk);

		if (result != 0)
			continue;

		result = lv1_get_repository_node_value(PS3_LPAR_ID_PME,
		    (lv1_repository_string("bus") >> 32) | bus_index,
		    lv1_repository_string("id"), 0, 0, &bus, &junk);

		if (result != 0)
			continue;

		result = lv1_get_repository_node_value(PS3_LPAR_ID_PME,
		    (lv1_repository_string("bus") >> 32) | bus_index,
		    lv1_repository_string("num_dev"), 0, 0, &devs, &junk);

		for (dev_index = 0; dev_index < devs; dev_index++) {
			result = lv1_get_repository_node_value(PS3_LPAR_ID_PME,
			    (lv1_repository_string("bus") >> 32) | bus_index,
			    lv1_repository_string("dev") | dev_index,
			    lv1_repository_string("type"), 0, &devtype, &junk);

			if (result != 0)
				continue;

			result = lv1_get_repository_node_value(PS3_LPAR_ID_PME,
			    (lv1_repository_string("bus") >> 32) | bus_index,
			    lv1_repository_string("dev") | dev_index,
			    lv1_repository_string("id"), 0, &dev, &junk);

			if (result != 0)
				continue;
			
			switch (devtype) {
			case PS3_DEVTYPE_USB:
				/* USB device has OHCI and EHCI USB host controllers */

				lv1_open_device(bus, dev, 0);

				/* OHCI host controller */

				dinfo = malloc(sizeof(*dinfo), M_PS3BUS,
				    M_WAITOK | M_ZERO);

				dinfo->bus = bus;
				dinfo->dev = dev;
				dinfo->bustype = bustype;
				dinfo->devtype = devtype;
				dinfo->busidx = bus_index;
				dinfo->devidx = dev_index;

				ps3bus_resources_init_by_type(&sc->sc_mem_rman, bus_index,
				    dev_index, OHCI_IRQ, OHCI_REG, dinfo);

				cdev = device_add_child(self, "ohci", -1);
				if (cdev == NULL) {
					device_printf(self,
					    "device_add_child failed\n");
					free(dinfo, M_PS3BUS);
					continue;
				}

				mtx_init(&dinfo->iommu_mtx, "iommu", NULL, MTX_DEF);
				device_set_ivars(cdev, dinfo);

				/* EHCI host controller */

				dinfo = malloc(sizeof(*dinfo), M_PS3BUS,
				    M_WAITOK | M_ZERO);

				dinfo->bus = bus;
				dinfo->dev = dev;
				dinfo->bustype = bustype;
				dinfo->devtype = devtype;
				dinfo->busidx = bus_index;
				dinfo->devidx = dev_index;

				ps3bus_resources_init_by_type(&sc->sc_mem_rman, bus_index,
				    dev_index, EHCI_IRQ, EHCI_REG, dinfo);

				cdev = device_add_child(self, "ehci", -1);
				if (cdev == NULL) {
					device_printf(self,
					    "device_add_child failed\n");
					free(dinfo, M_PS3BUS);
					continue;
				}

				mtx_init(&dinfo->iommu_mtx, "iommu", NULL, MTX_DEF);
				device_set_ivars(cdev, dinfo);
				break;
			default:
				dinfo = malloc(sizeof(*dinfo), M_PS3BUS,
				    M_WAITOK | M_ZERO);

				dinfo->bus = bus;
				dinfo->dev = dev;
				dinfo->bustype = bustype;
				dinfo->devtype = devtype;
				dinfo->busidx = bus_index;
				dinfo->devidx = dev_index;

				if (dinfo->bustype == PS3_BUSTYPE_SYSBUS ||
				    dinfo->bustype == PS3_BUSTYPE_STORAGE)
					lv1_open_device(bus, dev, 0);

				ps3bus_resources_init(&sc->sc_mem_rman, bus_index,
				    dev_index, dinfo);

				cdev = device_add_child(self, NULL, -1);
				if (cdev == NULL) {
					device_printf(self,
					    "device_add_child failed\n");
					free(dinfo, M_PS3BUS);
					continue;
				}

				mtx_init(&dinfo->iommu_mtx, "iommu", NULL, MTX_DEF);
				device_set_ivars(cdev, dinfo);
			}
		}
	}
	
	clock_register(self, 1000);

	return (bus_generic_attach(self));
}
Exemplo n.º 21
0
static int
at91_attach(device_t dev)
{
	struct at91_softc *sc = device_get_softc(dev);
	int i;

	at91_softc = sc;
	sc->sc_st = &at91_bs_tag;
	sc->sc_sh = AT91RM92_BASE;
	sc->dev = dev;
	if (bus_space_subregion(sc->sc_st, sc->sc_sh, AT91RM92_SYS_BASE,
	    AT91RM92_SYS_SIZE, &sc->sc_sys_sh) != 0)
		panic("Enable to map IRQ registers");
	sc->sc_irq_rman.rm_type = RMAN_ARRAY;
	sc->sc_irq_rman.rm_descr = "AT91 IRQs";
	sc->sc_mem_rman.rm_type = RMAN_ARRAY;
	sc->sc_mem_rman.rm_descr = "AT91 Memory";
#if 0
	sc->sc_usbmem_rman.rm_type = RMAN_ARRAY;
	sc->sc_usbmem_rman.rm_descr = "AT91RM9200 USB Memory-mapped regs";
#endif
	if (rman_init(&sc->sc_irq_rman) != 0 ||
	    rman_manage_region(&sc->sc_irq_rman, 1, 31) != 0)
		panic("at91_attach: failed to set up IRQ rman");
	if (rman_init(&sc->sc_mem_rman) != 0 ||
	    rman_manage_region(&sc->sc_mem_rman, 0xdff00000ul,
	    0xdffffffful) != 0)
		panic("at91_attach: failed to set up memory rman");
	if (rman_manage_region(&sc->sc_mem_rman, AT91RM92_OHCI_BASE,
	    AT91RM92_OHCI_BASE + AT91RM92_OHCI_SIZE - 1) != 0)
		panic("at91_attach: failed to set up ohci memory");

	for (i = 0; i < 32; i++) {
		bus_space_write_4(sc->sc_st, sc->sc_sys_sh, IC_SVR + 
		    i * 4, i);
		/* Priority. */
		bus_space_write_4(sc->sc_st, sc->sc_sys_sh, IC_SMR + i * 4,
		    irq_prio[i]);
		if (i < 8)
			bus_space_write_4(sc->sc_st, sc->sc_sys_sh, IC_EOICR,
			    1);
	}
	bus_space_write_4(sc->sc_st, sc->sc_sys_sh, IC_SPU, 32);
	/* No debug. */
	bus_space_write_4(sc->sc_st, sc->sc_sys_sh, IC_DCR, 0);
	/* Disable and clear all interrupts. */
	bus_space_write_4(sc->sc_st, sc->sc_sys_sh, IC_IDCR, 0xffffffff);
	bus_space_write_4(sc->sc_st, sc->sc_sys_sh, IC_ICCR, 0xffffffff);

	/* XXX */
	/* Disable all interrupts for RTC (0xe24 == RTC_IDR) */
	bus_space_write_4(sc->sc_st, sc->sc_sys_sh, 0xe24, 0xffffffff);
	/* DIsable all interrupts for DBGU */
	bus_space_write_4(sc->sc_st, sc->sc_sys_sh, 0x20c, 0xffffffff);
	/* Disable all interrupts for the SDRAM controller */
	bus_space_write_4(sc->sc_st, sc->sc_sys_sh, 0xfa8, 0xffffffff);

	at91_cpu_add_builtin_children(dev, sc);

	bus_generic_probe(dev);
	bus_generic_attach(dev);
	enable_interrupts(I32_bit | F32_bit);
	return (0);
}
Exemplo n.º 22
0
static int
zbpci_attach(device_t dev)
{
	int n, rid, size;
	vm_offset_t va;
	struct resource *res;
	
	/*
	 * Reserve the physical memory window used to map PCI I/O space.
	 */
	rid = 0;
	res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid,
				 PCI_IOSPACE_ADDR,
				 PCI_IOSPACE_ADDR + PCI_IOSPACE_SIZE - 1,
				 PCI_IOSPACE_SIZE, 0);
	if (res == NULL)
		panic("Cannot allocate resource for PCI I/O space mapping.");

	port_rman.rm_start = 0;
	port_rman.rm_end = PCI_IOSPACE_SIZE - 1;
	port_rman.rm_type = RMAN_ARRAY;
	port_rman.rm_descr = "PCI I/O ports";
	if (rman_init(&port_rman) != 0 ||
	    rman_manage_region(&port_rman, 0, PCI_IOSPACE_SIZE - 1) != 0)
		panic("%s: port_rman", __func__);

	/*
	 * Reserve the physical memory that is used to read/write to the
	 * pci config space but don't activate it. We are using a page worth
	 * of KVA as a window over this region.
	 */
	rid = 1;
	size = (PCI_BUSMAX + 1) * (PCI_SLOTMAX + 1) * (PCI_FUNCMAX + 1) * 256;
	res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, CFG_PADDR_BASE,
				 CFG_PADDR_BASE + size - 1, size, 0);
	if (res == NULL)
		panic("Cannot allocate resource for config space accesses.");

	/*
	 * Allocate the entire "match bit lanes" address space.
	 */
#if _BYTE_ORDER == _BIG_ENDIAN
	rid = 2;
	res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 
				 PCI_MATCH_BIT_LANES_START,
				 PCI_MATCH_BIT_LANES_END,
				 PCI_MATCH_BIT_LANES_SIZE, 0);
	if (res == NULL)
		panic("Cannot allocate resource for pci match bit lanes.");
#endif	/* _BYTE_ORDER ==_BIG_ENDIAN */

	/*
	 * Allocate KVA for accessing PCI config space.
	 */
	va = kva_alloc(PAGE_SIZE * mp_ncpus);
	if (va == 0) {
		device_printf(dev, "Cannot allocate virtual addresses for "
				   "config space access.\n");
		return (ENOMEM);
	}

	for (n = 0; n < mp_ncpus; ++n)
		zbpci_config_space[n].vaddr = va + n * PAGE_SIZE;

	/*
	 * Sibyte has the PCI bus hierarchy rooted at bus 0 and HT-PCI
	 * hierarchy rooted at bus 1.
	 */
	if (device_add_child(dev, "pci", 0) == NULL)
		panic("zbpci_attach: could not add pci bus 0.\n");

	if (device_add_child(dev, "pci", 1) == NULL)
		panic("zbpci_attach: could not add pci bus 1.\n");

	if (bootverbose)
		device_printf(dev, "attached.\n");

	return (bus_generic_attach(dev));
}
Exemplo n.º 23
0
static int
thunder_pem_attach(device_t dev)
{
	devclass_t pci_class;
	device_t parent;
	struct thunder_pem_softc *sc;
	int error;
	int rid;
	int tuple;
	uint64_t base, size;
	struct rman *rman;

	sc = device_get_softc(dev);
	sc->dev = dev;

	/* Allocate memory for resource */
	pci_class = devclass_find("pci");
	parent = device_get_parent(dev);
	if (device_get_devclass(parent) == pci_class)
		rid = PCIR_BAR(0);
	else
		rid = RID_PEM_SPACE;

	sc->reg = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
	    &rid, RF_ACTIVE);
	if (sc->reg == NULL) {
		device_printf(dev, "Failed to allocate resource\n");
		return (ENXIO);
	}
	sc->reg_bst = rman_get_bustag(sc->reg);
	sc->reg_bsh = rman_get_bushandle(sc->reg);

	/* Map SLI, do it only once */
	if (!sli0_s2m_regx_base) {
		bus_space_map(sc->reg_bst, SLIX_S2M_REGX_ACC,
		    SLIX_S2M_REGX_ACC_SIZE, 0, &sli0_s2m_regx_base);
	}
	if (!sli1_s2m_regx_base) {
		bus_space_map(sc->reg_bst, SLIX_S2M_REGX_ACC +
		    SLIX_S2M_REGX_ACC_SPACING, SLIX_S2M_REGX_ACC_SIZE, 0,
		    &sli1_s2m_regx_base);
	}

	if ((sli0_s2m_regx_base == 0) || (sli1_s2m_regx_base == 0)) {
		device_printf(dev,
		    "bus_space_map failed to map slix_s2m_regx_base\n");
		goto fail;
	}

	/* Identify PEM */
	if (thunder_pem_identify(dev) != 0)
		goto fail;

	/* Initialize rman and allocate regions */
	sc->mem_rman.rm_type = RMAN_ARRAY;
	sc->mem_rman.rm_descr = "PEM PCIe Memory";
	error = rman_init(&sc->mem_rman);
	if (error != 0) {
		device_printf(dev, "memory rman_init() failed. error = %d\n",
		    error);
		goto fail;
	}
	sc->io_rman.rm_type = RMAN_ARRAY;
	sc->io_rman.rm_descr = "PEM PCIe IO";
	error = rman_init(&sc->io_rman);
	if (error != 0) {
		device_printf(dev, "IO rman_init() failed. error = %d\n",
		    error);
		goto fail_mem;
	}

	/*
	 * We ignore the values that may have been provided in FDT
	 * and configure ranges according to the below formula
	 * for all types of devices. This is because some DTBs provided
	 * by EFI do not have proper ranges property or don't have them
	 * at all.
	 */
	/* Fill memory window */
	sc->ranges[0].pci_base = PCI_MEMORY_BASE;
	sc->ranges[0].size = PCI_MEMORY_SIZE;
	sc->ranges[0].phys_base = sc->sli_window_base + SLI_PCI_OFFSET +
	    sc->ranges[0].pci_base;
	sc->ranges[0].flags = SYS_RES_MEMORY;

	/* Fill IO window */
	sc->ranges[1].pci_base = PCI_IO_BASE;
	sc->ranges[1].size = PCI_IO_SIZE;
	sc->ranges[1].phys_base = sc->sli_window_base + SLI_PCI_OFFSET +
	    sc->ranges[1].pci_base;
	sc->ranges[1].flags = SYS_RES_IOPORT;

	for (tuple = 0; tuple < MAX_RANGES_TUPLES; tuple++) {
		base = sc->ranges[tuple].pci_base;
		size = sc->ranges[tuple].size;
		if (size == 0)
			continue; /* empty range element */

		rman = thunder_pem_rman(sc, sc->ranges[tuple].flags);
		if (rman != NULL)
			error = rman_manage_region(rman, base,
			    base + size - 1);
		else
			error = EINVAL;
		if (error) {
			device_printf(dev,
			    "rman_manage_region() failed. error = %d\n", error);
			rman_fini(&sc->mem_rman);
			return (error);
		}
		if (bootverbose) {
			device_printf(dev,
			    "\tPCI addr: 0x%jx, CPU addr: 0x%jx, Size: 0x%jx, Flags:0x%jx\n",
			    sc->ranges[tuple].pci_base,
			    sc->ranges[tuple].phys_base,
			    sc->ranges[tuple].size,
			    sc->ranges[tuple].flags);
		}
	}

	if (thunder_pem_init(sc)) {
		device_printf(dev, "Failure during PEM init\n");
		goto fail_io;
	}

	device_add_child(dev, "pci", -1);

	return (bus_generic_attach(dev));

fail_io:
	rman_fini(&sc->io_rman);
fail_mem:
	rman_fini(&sc->mem_rman);
fail:
	bus_free_resource(dev, SYS_RES_MEMORY, sc->reg);
	return (ENXIO);
}
Exemplo n.º 24
0
static int
mvs_attach(device_t dev)
{
	struct mvs_controller *ctlr = device_get_softc(dev);
	device_t child;
	int	error, unit, i;
	uint32_t devid, revid;

	soc_id(&devid, &revid);
	ctlr->dev = dev;
	i = 0;
	while (mvs_ids[i].id != 0 &&
	    (mvs_ids[i].id != devid ||
	     mvs_ids[i].rev > revid))
		i++;
	ctlr->channels = mvs_ids[i].ports;
	ctlr->quirks = mvs_ids[i].quirks;
	resource_int_value(device_get_name(dev),
	    device_get_unit(dev), "ccc", &ctlr->ccc);
	ctlr->cccc = 8;
	resource_int_value(device_get_name(dev),
	    device_get_unit(dev), "cccc", &ctlr->cccc);
	if (ctlr->ccc == 0 || ctlr->cccc == 0) {
		ctlr->ccc = 0;
		ctlr->cccc = 0;
	}
	if (ctlr->ccc > 100000)
		ctlr->ccc = 100000;
	device_printf(dev,
	    "Gen-%s, %d %sGbps ports, Port Multiplier %s%s\n",
	    ((ctlr->quirks & MVS_Q_GENI) ? "I" :
	     ((ctlr->quirks & MVS_Q_GENII) ? "II" : "IIe")),
	    ctlr->channels,
	    ((ctlr->quirks & MVS_Q_GENI) ? "1.5" : "3"),
	    ((ctlr->quirks & MVS_Q_GENI) ?
	    "not supported" : "supported"),
	    ((ctlr->quirks & MVS_Q_GENIIE) ?
	    " with FBS" : ""));
	mtx_init(&ctlr->mtx, "MVS controller lock", NULL, MTX_DEF);
	/* We should have a memory BAR(0). */
	ctlr->r_rid = 0;
	if (!(ctlr->r_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
	    &ctlr->r_rid, RF_ACTIVE)))
		return ENXIO;
	if (ATA_INL(ctlr->r_mem, PORT_BASE(0) + SATA_PHYCFG_OFS) != 0)
		ctlr->quirks |= MVS_Q_SOC65;
	/* Setup our own memory management for channels. */
	ctlr->sc_iomem.rm_start = rman_get_start(ctlr->r_mem);
	ctlr->sc_iomem.rm_end = rman_get_end(ctlr->r_mem);
	ctlr->sc_iomem.rm_type = RMAN_ARRAY;
	ctlr->sc_iomem.rm_descr = "I/O memory addresses";
	if ((error = rman_init(&ctlr->sc_iomem)) != 0) {
		bus_release_resource(dev, SYS_RES_MEMORY, ctlr->r_rid, ctlr->r_mem);
		return (error);
	}
	if ((error = rman_manage_region(&ctlr->sc_iomem,
	    rman_get_start(ctlr->r_mem), rman_get_end(ctlr->r_mem))) != 0) {
		bus_release_resource(dev, SYS_RES_MEMORY, ctlr->r_rid, ctlr->r_mem);
		rman_fini(&ctlr->sc_iomem);
		return (error);
	}
	mvs_ctlr_setup(dev);
	/* Setup interrupts. */
	if (mvs_setup_interrupt(dev)) {
		bus_release_resource(dev, SYS_RES_MEMORY, ctlr->r_rid, ctlr->r_mem);
		rman_fini(&ctlr->sc_iomem);
		return ENXIO;
	}
	/* Attach all channels on this controller */
	for (unit = 0; unit < ctlr->channels; unit++) {
		child = device_add_child(dev, "mvsch", -1);
		if (child == NULL)
			device_printf(dev, "failed to add channel device\n");
		else
			device_set_ivars(child, (void *)(intptr_t)unit);
	}
	bus_generic_attach(dev);
	return 0;
}
Exemplo n.º 25
0
int
ofw_pci_init(device_t dev)
{
	struct		ofw_pci_softc *sc;
	phandle_t	node;
	u_int32_t	busrange[2];
	struct		ofw_pci_range *rp;
	int		error;

	node = ofw_bus_get_node(dev);
	sc = device_get_softc(dev);
	sc->sc_initialized = 1;

	if (OF_getprop(node, "reg", &sc->sc_pcir, sizeof(sc->sc_pcir)) == -1)
		return (ENXIO);

	if (OF_getprop(node, "bus-range", busrange, sizeof(busrange)) != 8)
		busrange[0] = 0;

	sc->sc_dev = dev;
	sc->sc_node = node;
	sc->sc_bus = busrange[0];

	if (sc->sc_quirks & OFW_PCI_QUIRK_RANGES_ON_CHILDREN) {
		phandle_t c;
		int n, i;
		
		sc->sc_nrange = 0;
		for (c = OF_child(node); c != 0; c = OF_peer(c)) {
			n = ofw_pci_nranges(c);
			if (n > 0)
				sc->sc_nrange += n;
		}
		if (sc->sc_nrange == 0)
			return (ENXIO);
		sc->sc_range = malloc(sc->sc_nrange * sizeof(sc->sc_range[0]),
		    M_DEVBUF, M_WAITOK);
		i = 0;
		for (c = OF_child(node); c != 0; c = OF_peer(c)) {
			n = ofw_pci_fill_ranges(c, &sc->sc_range[i]);
			if (n > 0)
				i += n;
		}
		KASSERT(i == sc->sc_nrange, ("range count mismatch"));
	} else {
		sc->sc_nrange = ofw_pci_nranges(node);
		if (sc->sc_nrange <= 0) {
			device_printf(dev, "could not get ranges\n");
			return (ENXIO);
		}
		sc->sc_range = malloc(sc->sc_nrange * sizeof(sc->sc_range[0]),
		    M_DEVBUF, M_WAITOK);
		ofw_pci_fill_ranges(node, sc->sc_range);
	}
		
	sc->sc_io_rman.rm_type = RMAN_ARRAY;
	sc->sc_io_rman.rm_descr = "PCI I/O Ports";
	error = rman_init(&sc->sc_io_rman);
	if (error) {
		device_printf(dev, "rman_init() failed. error = %d\n", error);
		return (error);
	}

	sc->sc_mem_rman.rm_type = RMAN_ARRAY;
	sc->sc_mem_rman.rm_descr = "PCI Memory";
	error = rman_init(&sc->sc_mem_rman);
	if (error) {
		device_printf(dev, "rman_init() failed. error = %d\n", error);
		return (error);
	}

	for (rp = sc->sc_range; rp < sc->sc_range + sc->sc_nrange &&
	       rp->pci_hi != 0; rp++) {
		error = 0;

		switch (rp->pci_hi & OFW_PCI_PHYS_HI_SPACEMASK) {
		case OFW_PCI_PHYS_HI_SPACE_CONFIG:
			break;
		case OFW_PCI_PHYS_HI_SPACE_IO:
			error = rman_manage_region(&sc->sc_io_rman, rp->pci,
			    rp->pci + rp->size - 1);
			break;
		case OFW_PCI_PHYS_HI_SPACE_MEM32:
		case OFW_PCI_PHYS_HI_SPACE_MEM64:
			error = rman_manage_region(&sc->sc_mem_rman, rp->pci,
			    rp->pci + rp->size - 1);
			break;
		}

		if (error) {
			device_printf(dev, 
			    "rman_manage_region(%x, %#jx, %#jx) failed. "
			    "error = %d\n", rp->pci_hi &
			    OFW_PCI_PHYS_HI_SPACEMASK, rp->pci,
			    rp->pci + rp->size - 1, error);
			return (error);
		}
	}

	ofw_bus_setup_iinfo(node, &sc->sc_pci_iinfo, sizeof(cell_t));

	return (error);
}
Exemplo n.º 26
0
static int
at91_attach(device_t dev)
{
	struct at91_softc *sc = device_get_softc(dev);
	int i;

	arm_post_filter = at91_eoi;

	at91_softc = sc;
	sc->sc_st = &at91_bs_tag;
	sc->sc_sh = AT91_BASE;
	sc->sc_aic_sh = AT91_BASE + AT91_SYS_BASE;
	sc->dev = dev;

	sc->sc_irq_rman.rm_type = RMAN_ARRAY;
	sc->sc_irq_rman.rm_descr = "AT91 IRQs";
	if (rman_init(&sc->sc_irq_rman) != 0 ||
	    rman_manage_region(&sc->sc_irq_rman, 1, 31) != 0)
		panic("at91_attach: failed to set up IRQ rman");

	sc->sc_mem_rman.rm_type = RMAN_ARRAY;
	sc->sc_mem_rman.rm_descr = "AT91 Memory";
	if (rman_init(&sc->sc_mem_rman) != 0)
		panic("at91_attach: failed to set up memory rman");
	/*
	 * Manage the physical space, defined as being everything that isn't
	 * DRAM.
	 */
	if (rman_manage_region(&sc->sc_mem_rman, 0, PHYSADDR - 1) != 0)
		panic("at91_attach: failed to set up memory rman");
	if (rman_manage_region(&sc->sc_mem_rman, PHYSADDR + (256 << 20),
	    0xfffffffful) != 0)
		panic("at91_attach: failed to set up memory rman");

	/*
	 * Setup the interrupt table.
	 */
	if (soc_info.soc_data == NULL || soc_info.soc_data->soc_irq_prio == NULL)
		panic("Interrupt priority table missing\n");
	for (i = 0; i < 32; i++) {
		bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_SVR +
		    i * 4, i);
		/* Priority. */
		bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_SMR + i * 4,
		    soc_info.soc_data->soc_irq_prio[i]);
		if (i < 8)
			bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_EOICR,
			    1);
	}

	bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_SPU, 32);
	/* No debug. */
	bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_DCR, 0);
	/* Disable and clear all interrupts. */
	bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_IDCR, 0xffffffff);
	bus_space_write_4(sc->sc_st, sc->sc_aic_sh, IC_ICCR, 0xffffffff);

        /*
         * Add this device's children...
         */
	at91_cpu_add_builtin_children(dev, soc_info.soc_data->soc_children);
	soc_info.soc_data->soc_clock_init();

	bus_generic_probe(dev);
	bus_generic_attach(dev);
	enable_interrupts(I32_bit | F32_bit);
	return (0);
}
Exemplo n.º 27
0
static int
ocpbus_attach(device_t dev)
{
	struct ocpbus_softc *sc;
	int error, i, tgt, law_max;
	uint32_t sr;
	u_long start, end;

	sc = device_get_softc(dev);

	ocpbus_mk_child(dev, OCPBUS_DEVTYPE_I2C, 0);
	ocpbus_mk_child(dev, OCPBUS_DEVTYPE_I2C, 1);
	ocpbus_mk_child(dev, OCPBUS_DEVTYPE_UART, 0);
	ocpbus_mk_child(dev, OCPBUS_DEVTYPE_UART, 1);
	ocpbus_mk_child(dev, OCPBUS_DEVTYPE_LBC, 0);
	ocpbus_mk_child(dev, OCPBUS_DEVTYPE_PCIB, 0);
	ocpbus_mk_child(dev, OCPBUS_DEVTYPE_PCIB, 1);
	ocpbus_mk_child(dev, OCPBUS_DEVTYPE_PCIB, 2);
	ocpbus_mk_child(dev, OCPBUS_DEVTYPE_TSEC, 0);
	ocpbus_mk_child(dev, OCPBUS_DEVTYPE_TSEC, 1);
	ocpbus_mk_child(dev, OCPBUS_DEVTYPE_TSEC, 2);
	ocpbus_mk_child(dev, OCPBUS_DEVTYPE_TSEC, 3);
	ocpbus_mk_child(dev, OCPBUS_DEVTYPE_PIC, 0);
	ocpbus_mk_child(dev, OCPBUS_DEVTYPE_QUICC, 0);
	ocpbus_mk_child(dev, OCPBUS_DEVTYPE_SEC, 0);

	/* Set up IRQ rman */
	start = 0;
	end = INTR_VECTORS - 1;
	sc->sc_irq.rm_start = start;
	sc->sc_irq.rm_end = end;
	sc->sc_irq.rm_type = RMAN_ARRAY;
	sc->sc_irq.rm_descr = "Interrupt request lines";
	if (rman_init(&sc->sc_irq) ||
	    rman_manage_region(&sc->sc_irq, start, end))
		panic("ocpbus_attach IRQ rman");

	/* Set up I/O mem rman */
	sc->sc_mem.rm_type = RMAN_ARRAY;
	sc->sc_mem.rm_descr = "OCPBus Device Memory";
	error = rman_init(&sc->sc_mem);
	if (error) {
		device_printf(dev, "rman_init() failed. error = %d\n", error);
		return (error);
	}

	error = rman_manage_region(&sc->sc_mem, CCSRBAR_VA,
	    CCSRBAR_VA + CCSRBAR_SIZE - 1);
	if (error) {
		device_printf(dev, "rman_manage_region() failed. error = %d\n",
		    error);
		return (error);
	}

	/*
	 * Clear local access windows. Skip DRAM entries, so we don't shoot
	 * ourselves in the foot.
	 */
	law_max = law_getmax();
	for (i = 0; i < law_max; i++) {
		sr = ccsr_read4(OCP85XX_LAWSR(i));
		if ((sr & 0x80000000) == 0)
			continue;
		tgt = (sr & 0x01f00000) >> 20;
		if (tgt == OCP85XX_TGTIF_RAM1 || tgt == OCP85XX_TGTIF_RAM2 ||
		    tgt == OCP85XX_TGTIF_RAM_INTL)
			continue;

		ccsr_write4(OCP85XX_LAWSR(i), sr & 0x7fffffff);
	}

	if (bootverbose)
		device_printf(dev, "PORDEVSR=%08x, PORDEVSR2=%08x\n",
		    ccsr_read4(OCP85XX_PORDEVSR),
		    ccsr_read4(OCP85XX_PORDEVSR2));

	for (i = PIC_IRQ_START; i < PIC_IRQ_START + 4; i++)
		powerpc_config_intr(i, INTR_TRIGGER_LEVEL, INTR_POLARITY_LOW);

	return (bus_generic_attach(dev));
}
Exemplo n.º 28
0
int
iq80321_attach(device_t dev)
{
	struct i80321_softc *sc = device_get_softc(dev);
	int b0u, b0l, b1u, b1l;
	vm_paddr_t memstart = 0;
	vm_size_t memsize = 0;
	int busno;

	/*
	 * Fill in the space tag for the i80321's own devices,
	 * and hand-craft the space handle for it (the device
	 * was mapped during early bootstrap).
	 */
	i80321_bs_init(&i80321_bs_tag, sc);
	sc->sc_st = &i80321_bs_tag;
	sc->sc_sh = IQ80321_80321_VBASE;
	sc->dev = dev;
	sc->sc_is_host = 1;

	/*
	 * Slice off a subregion for the Memory Controller -- we need it
	 * here in order read the memory size.
	 */
	if (bus_space_subregion(sc->sc_st, sc->sc_sh, VERDE_MCU_BASE,
	    VERDE_MCU_SIZE, &sc->sc_mcu_sh))
		panic("%s: unable to subregion MCU registers",
		    device_get_name(dev));

	if (bus_space_subregion(sc->sc_st, sc->sc_sh, VERDE_ATU_BASE,
	    VERDE_ATU_SIZE, &sc->sc_atu_sh))
		panic("%s: unable to subregion ATU registers",
		    device_get_name(dev));

	/*
	 * We have mapped the PCI I/O windows in the early
	 * bootstrap phase.
	 */
	sc->sc_iow_vaddr = IQ80321_IOW_VBASE;

	/*
	 * Check the configuration of the ATU to see if another BIOS
	 * has configured us.  If a PC BIOS didn't configure us, then:
	 * 	IQ80321: BAR0 00000000.0000000c BAR1 is 00000000.8000000c.
	 * 	IQ31244: BAR0 00000000.00000004 BAR1 is 00000000.0000000c.
	 * If a BIOS has configured us, at least one of those should be
	 * different.  This is pretty fragile, but it's not clear what
	 * would work better.
	 */
	b0l = bus_space_read_4(sc->sc_st, sc->sc_atu_sh, PCIR_BARS+0x0);
	b0u = bus_space_read_4(sc->sc_st, sc->sc_atu_sh, PCIR_BARS+0x4);
	b1l = bus_space_read_4(sc->sc_st, sc->sc_atu_sh, PCIR_BARS+0x8);
	b1u = bus_space_read_4(sc->sc_st, sc->sc_atu_sh, PCIR_BARS+0xc);

#ifdef VERBOSE_INIT_ARM	
	printf("i80321: BAR0 = %08x.%08x BAR1 = %08x.%08x\n",
		   b0l,b0u, b1l, b1u );
#endif

#define PCI_MAPREG_MEM_ADDR_MASK	0xfffffff0
	b0l &= PCI_MAPREG_MEM_ADDR_MASK;
	b0u &= PCI_MAPREG_MEM_ADDR_MASK;
	b1l &= PCI_MAPREG_MEM_ADDR_MASK;
	b1u &= PCI_MAPREG_MEM_ADDR_MASK;

#ifdef VERBOSE_INIT_ARM	
	printf("i80219: BAR0 = %08x.%08x BAR1 = %08x.%08x\n",
		   b0l,b0u, b1l, b1u );
#endif

	if ((b0u != b1u) || (b0l != 0) || ((b1l & ~0x80000000U) != 0))
		sc->sc_is_host = 0;
	else
		sc->sc_is_host = 1;

	/* FIXME: i force it's */	

#ifdef CPU_XSCALE_80219
	sc->sc_is_host = 1;
#endif
	
	i80321_sdram_bounds(sc->sc_st, sc->sc_mcu_sh, &memstart, &memsize);
	/*
	 * We set up the Inbound Windows as follows:
	 *
	 *	0	Access to i80321 PMMRs
	 *
	 *	1	Reserve space for private devices
	 *
	 *	2	RAM access
	 *
	 *	3	Unused.
	 *
	 * This chunk needs to be customized for each IOP321 application.
	 */
#if 0
	sc->sc_iwin[0].iwin_base_lo = VERDE_PMMR_BASE;
	sc->sc_iwin[0].iwin_base_hi = 0;
	sc->sc_iwin[0].iwin_xlate = VERDE_PMMR_BASE;
	sc->sc_iwin[0].iwin_size = VERDE_PMMR_SIZE;
#endif
	if (sc->sc_is_host) {
		
		/* Map PCI:Local 1:1. */
		sc->sc_iwin[1].iwin_base_lo = VERDE_OUT_XLATE_MEM_WIN0_BASE |
		    PCI_MAPREG_MEM_PREFETCHABLE_MASK |
		    PCI_MAPREG_MEM_TYPE_64BIT;
		sc->sc_iwin[1].iwin_base_hi = 0;
	} else {
		
		sc->sc_iwin[1].iwin_base_lo = 0;
		sc->sc_iwin[1].iwin_base_hi = 0;
	}
	sc->sc_iwin[1].iwin_xlate = VERDE_OUT_XLATE_MEM_WIN0_BASE;
	sc->sc_iwin[1].iwin_size = VERDE_OUT_XLATE_MEM_WIN_SIZE;
	
	if (sc->sc_is_host) {
		sc->sc_iwin[2].iwin_base_lo = memstart |
		    PCI_MAPREG_MEM_PREFETCHABLE_MASK |
		    PCI_MAPREG_MEM_TYPE_64BIT;
		sc->sc_iwin[2].iwin_base_hi = 0;
	} else {
		sc->sc_iwin[2].iwin_base_lo = 0;
		sc->sc_iwin[2].iwin_base_hi = 0;
	}
	sc->sc_iwin[2].iwin_xlate = memstart;
	sc->sc_iwin[2].iwin_size = memsize;

	if (sc->sc_is_host) {
		sc->sc_iwin[3].iwin_base_lo = 0 |
		    PCI_MAPREG_MEM_PREFETCHABLE_MASK |
		    PCI_MAPREG_MEM_TYPE_64BIT;
	} else {
		sc->sc_iwin[3].iwin_base_lo = 0;
	}
	sc->sc_iwin[3].iwin_base_hi = 0;
	sc->sc_iwin[3].iwin_xlate = 0;
	sc->sc_iwin[3].iwin_size = 0;
	
#ifdef 	VERBOSE_INIT_ARM
	printf("i80321: Reserve space for private devices (Inbound Window 1) \n hi:0x%08x lo:0x%08x xlate:0x%08x size:0x%08x\n",
		   sc->sc_iwin[1].iwin_base_hi,
		   sc->sc_iwin[1].iwin_base_lo,
		   sc->sc_iwin[1].iwin_xlate,
		   sc->sc_iwin[1].iwin_size
		);
	printf("i80321: RAM access (Inbound Window 2) \n hi:0x%08x lo:0x%08x xlate:0x%08x size:0x%08x\n",
		   sc->sc_iwin[2].iwin_base_hi,
		   sc->sc_iwin[2].iwin_base_lo,
		   sc->sc_iwin[2].iwin_xlate,
		   sc->sc_iwin[2].iwin_size
		);
#endif

	/*
	 * We set up the Outbound Windows as follows:
	 *
	 *	0	Access to private PCI space.
	 *
	 *	1	Unused.
	 */
#define PCI_MAPREG_MEM_ADDR(x) ((x) & 0xfffffff0)
	sc->sc_owin[0].owin_xlate_lo =
    	    PCI_MAPREG_MEM_ADDR(sc->sc_iwin[1].iwin_base_lo);
	sc->sc_owin[0].owin_xlate_hi = sc->sc_iwin[1].iwin_base_hi;
	/*
	 * Set the Secondary Outbound I/O window to map
	 * to PCI address 0 for all 64K of the I/O space.
	 */
	sc->sc_ioout_xlate = 0;
	i80321_attach(sc);
	i80321_dr.dr_sysbase = sc->sc_iwin[2].iwin_xlate;
	i80321_dr.dr_busbase = PCI_MAPREG_MEM_ADDR(sc->sc_iwin[2].iwin_base_lo);
	i80321_dr.dr_len = sc->sc_iwin[2].iwin_size;
	dma_range_init = 1;
	busno = bus_space_read_4(sc->sc_st, sc->sc_atu_sh, ATU_PCIXSR);
	busno = PCIXSR_BUSNO(busno);
	if (busno == 0xff)
		busno = 0;
	sc->sc_irq_rman.rm_type = RMAN_ARRAY;
	sc->sc_irq_rman.rm_descr = "i80321 IRQs";
	if (rman_init(&sc->sc_irq_rman) != 0 ||
	    rman_manage_region(&sc->sc_irq_rman, 0, 25) != 0)
		panic("i80321_attach: failed to set up IRQ rman");

	device_add_child(dev, "obio", 0);
	device_add_child(dev, "itimer", 0);
	device_add_child(dev, "iopwdog", 0);
#ifndef 	CPU_XSCALE_80219
	device_add_child(dev, "iqseg", 0);
#endif	
	device_add_child(dev, "pcib", busno);
	device_add_child(dev, "i80321_dma", 0);
	device_add_child(dev, "i80321_dma", 1);
#ifndef CPU_XSCALE_80219	
	device_add_child(dev, "i80321_aau", 0);
#endif
	bus_generic_probe(dev);
	bus_generic_attach(dev);

	return (0);
}
Exemplo n.º 29
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);
}
Exemplo n.º 30
0
static int
grackle_attach(device_t dev)
{
	struct		grackle_softc *sc;
	phandle_t	node;
	u_int32_t	busrange[2];
	struct		grackle_range *rp, *io, *mem[2];
	int		nmem, i, error;

	node = ofw_bus_get_node(dev);
	sc = device_get_softc(dev);

	if (OF_getprop(node, "bus-range", busrange, sizeof(busrange)) != 8)
		return (ENXIO);

	sc->sc_dev = dev;
	sc->sc_node = node;
	sc->sc_bus = busrange[0];

	/*
	 * The Grackle PCI config addr/data registers are actually in
	 * PCI space, but since they are needed to actually probe the
	 * PCI bus, use the fact that they are also available directly
	 * on the processor bus and map them
	 */
	sc->sc_addr = (vm_offset_t)pmap_mapdev(GRACKLE_ADDR, PAGE_SIZE);
	sc->sc_data = (vm_offset_t)pmap_mapdev(GRACKLE_DATA, PAGE_SIZE);

	bzero(sc->sc_range, sizeof(sc->sc_range));
	sc->sc_nrange = OF_getprop(node, "ranges", sc->sc_range,
	    sizeof(sc->sc_range));

	if (sc->sc_nrange == -1) {
		device_printf(dev, "could not get ranges\n");
		return (ENXIO);
	}

	sc->sc_range[6].pci_hi = 0;
	io = NULL;
	nmem = 0;

	for (rp = sc->sc_range; rp->pci_hi != 0; rp++) {
		switch (rp->pci_hi & OFW_PCI_PHYS_HI_SPACEMASK) {
		case OFW_PCI_PHYS_HI_SPACE_CONFIG:
			break;
		case OFW_PCI_PHYS_HI_SPACE_IO:
			io = rp;
			break;
		case OFW_PCI_PHYS_HI_SPACE_MEM32:
			mem[nmem] = rp;
			nmem++;
			break;
		case OFW_PCI_PHYS_HI_SPACE_MEM64:
			break;
		}
	}

	if (io == NULL) {
		device_printf(dev, "can't find io range\n");
		return (ENXIO);
	}
	sc->sc_io_rman.rm_type = RMAN_ARRAY;
	sc->sc_io_rman.rm_descr = "Grackle PCI I/O Ports";
	sc->sc_iostart = io->pci_iospace;
	if (rman_init(&sc->sc_io_rman) != 0 ||
	    rman_manage_region(&sc->sc_io_rman, io->pci_lo,
	    io->pci_lo + io->size_lo) != 0) {
		panic("grackle_attach: failed to set up I/O rman");
	}

	if (nmem == 0) {
		device_printf(dev, "can't find mem ranges\n");
		return (ENXIO);
	}
	sc->sc_mem_rman.rm_type = RMAN_ARRAY;
	sc->sc_mem_rman.rm_descr = "Grackle PCI Memory";
	error = rman_init(&sc->sc_mem_rman);
	if (error) {
		device_printf(dev, "rman_init() failed. error = %d\n", error);
		return (error);
	}
	for (i = 0; i < nmem; i++) {
		error = rman_manage_region(&sc->sc_mem_rman, mem[i]->pci_lo,
		    mem[i]->pci_lo + mem[i]->size_lo);
		if (error) {
			device_printf(dev, 
			    "rman_manage_region() failed. error = %d\n", error);
			return (error);
		}
	}

	ofw_bus_setup_iinfo(node, &sc->sc_pci_iinfo, sizeof(cell_t));

	device_add_child(dev, "pci", device_get_unit(dev));
	return (bus_generic_attach(dev));
}