Ejemplo n.º 1
0
static int
ofw_pcibus_attach(device_t dev)
{
	device_t pcib;
	struct ofw_pci_register pcir;
	struct ofw_pcibus_devinfo *dinfo;
	phandle_t node, child;
	uint32_t clock;
	u_int busno, domain, func, slot;

	pcib = device_get_parent(dev);
	domain = pcib_get_domain(dev);
	busno = pcib_get_bus(dev);
	if (bootverbose)
		device_printf(dev, "domain=%d, physical bus=%d\n",
		    domain, busno);
	node = ofw_bus_get_node(dev);

	/*
	 * Add the PCI side of the host-PCI bridge itself to the bus.
	 * Note that we exclude the host-PCIe bridges here as these
	 * have no configuration space implemented themselves.
	 */
	if (strcmp(device_get_name(device_get_parent(pcib)), "nexus") == 0 &&
	    ofw_bus_get_type(pcib) != NULL &&
	    strcmp(ofw_bus_get_type(pcib), OFW_TYPE_PCIE) != 0 &&
	    (dinfo = (struct ofw_pcibus_devinfo *)pci_read_device(pcib,
	    domain, busno, 0, 0, sizeof(*dinfo))) != NULL) {
		if (ofw_bus_gen_setup_devinfo(&dinfo->opd_obdinfo, node) != 0)
			pci_freecfg((struct pci_devinfo *)dinfo);
		else
			pci_add_child(dev, (struct pci_devinfo *)dinfo);
	}

	if (OF_getprop(ofw_bus_get_node(pcib), "clock-frequency", &clock,
	    sizeof(clock)) == -1)
		clock = 33000000;
	for (child = OF_child(node); child != 0; child = OF_peer(child)) {
		if (OF_getprop(child, "reg", &pcir, sizeof(pcir)) == -1)
			continue;
		slot = OFW_PCI_PHYS_HI_DEVICE(pcir.phys_hi);
		func = OFW_PCI_PHYS_HI_FUNCTION(pcir.phys_hi);
		/* Some OFW device trees contain dupes. */
		if (pci_find_dbsf(domain, busno, slot, func) != NULL)
			continue;
		ofw_pcibus_setup_device(pcib, clock, busno, slot, func);
		dinfo = (struct ofw_pcibus_devinfo *)pci_read_device(pcib,
		    domain, busno, slot, func, sizeof(*dinfo));
		if (dinfo == NULL)
			continue;
		if (ofw_bus_gen_setup_devinfo(&dinfo->opd_obdinfo, child) !=
		    0) {
			pci_freecfg((struct pci_devinfo *)dinfo);
			continue;
		}
		pci_add_child(dev, (struct pci_devinfo *)dinfo);
	}

	return (bus_generic_attach(dev));
}
Ejemplo n.º 2
0
int
ofw_pci_orb_callback(phandle_t node, u_int8_t *pintptr, int pintsz,
    u_int8_t *pregptr, int pregsz, u_int8_t **rintr, int *terminate)
{
	struct ofw_pci_register preg;
	u_int32_t pintr, intr;
	char type[32];

	if (pintsz != sizeof(u_int32_t))
		return (-1);
	bcopy(pintptr, &pintr, sizeof(pintr));
	if ((pci_quirks & OPQ_NO_SWIZZLE) == 0 && pregsz >= sizeof(preg) &&
	    OF_getprop(node, "device_type", type, sizeof(type)) != -1 &&
	    strcmp(type, OFW_PCI_PCIBUS) == 0 && pintr >= 1 && pintr <= 4) {
		/*
		 * Handle a quirk found on some Netra t1 models: there exist
		 * PCI bridges without interrupt maps, where we apparently must
		 * do the PCI swizzle and continue to map on at the parent.
		 */
		bcopy(pregptr, &preg, sizeof(preg));
		intr = (OFW_PCI_PHYS_HI_DEVICE(preg.phys_hi) + pintr + 3) %
		    4 + 1;
		*rintr = malloc(sizeof(intr), M_OFWPROP, M_WAITOK);
		bcopy(&intr, *rintr, sizeof(intr));
		*terminate = 0;
		return (sizeof(intr));
	}
	return (-1);
}
Ejemplo n.º 3
0
phandle_t
ofw_pci_find_node(int bus, int slot, int func)
{
	phandle_t node, bnode;
	struct ofw_pci_register pcir;

	/*
	 * Retrieve the bus node from the mapping that was created on
	 * initialization. The bus numbers the firmware uses cannot be trusted,
	 * so they might have needed to be changed and this is necessary.
	 */
	if (bus >= pci_bus_map_sz)
		return (0);
	bnode = pci_bus_map[bus];
	if (bnode == 0)
		return (0);
	for (node = OF_child(bnode); node != 0 && node != -1;
	     node = OF_peer(node)) {
		if (OF_getprop(node, "reg", &pcir, sizeof(pcir)) == -1)
			continue;
		if (OFW_PCI_PHYS_HI_DEVICE(pcir.phys_hi) == slot &&
		    OFW_PCI_PHYS_HI_FUNCTION(pcir.phys_hi) == func)
			return (node);
	}
	return (0);
}
Ejemplo n.º 4
0
void
genppc_pci_ofmethod_decompose_tag(void *v, pcitag_t tag, int *bp, int *dp,
    int *fp)
{

	if (bp != NULL)
		*bp = OFW_PCI_PHYS_HI_BUS(tag);
	if (dp != NULL)
		*dp = OFW_PCI_PHYS_HI_DEVICE(tag);
	if (fp != NULL)
		*fp = OFW_PCI_PHYS_HI_FUNCTION(tag);
	return;
}
Ejemplo n.º 5
0
static void
ofw_pcibus_enum_devtree(device_t dev, u_int domain, u_int busno)
{
	device_t pcib;
	struct ofw_pci_register pcir;
	struct ofw_pcibus_devinfo *dinfo;
	phandle_t node, child;
	u_int func, slot;
	int intline;

	pcib = device_get_parent(dev);
	node = ofw_bus_get_node(dev);

	for (child = OF_child(node); child != 0; child = OF_peer(child)) {
		if (OF_getprop(child, "reg", &pcir, sizeof(pcir)) == -1)
			continue;
		slot = OFW_PCI_PHYS_HI_DEVICE(pcir.phys_hi);
		func = OFW_PCI_PHYS_HI_FUNCTION(pcir.phys_hi);

		/* Some OFW device trees contain dupes. */
		if (pci_find_dbsf(domain, busno, slot, func) != NULL)
			continue;

		/*
		 * The preset in the intline register is usually bogus.  Reset
		 * it such that the PCI code will reroute the interrupt if
		 * needed.
		 */

		intline = PCI_INVALID_IRQ;
		if (OF_getproplen(child, "interrupts") > 0)
			intline = 0;
		PCIB_WRITE_CONFIG(pcib, busno, slot, func, PCIR_INTLINE,
		    intline, 1);

		/*
		 * Now set up the PCI and OFW bus layer devinfo and add it
		 * to the PCI bus.
		 */

		dinfo = (struct ofw_pcibus_devinfo *)pci_read_device(pcib,
		    domain, busno, slot, func, sizeof(*dinfo));
		if (dinfo == NULL)
			continue;
		if (ofw_bus_gen_setup_devinfo(&dinfo->opd_obdinfo, child) !=
		    0) {
			pci_freecfg((struct pci_devinfo *)dinfo);
			continue;
		}
		dinfo->opd_dma_tag = NULL;
		pci_add_child(dev, (struct pci_devinfo *)dinfo);

		/*
		 * Some devices don't have an intpin set, but do have
		 * interrupts. These are fully specified, and set in the
		 * interrupts property, so add that value to the device's
		 * resource list.
		 */
		if (dinfo->opd_dinfo.cfg.intpin == 0)
			ofw_bus_intr_to_rl(dev, child,
				&dinfo->opd_dinfo.resources, NULL);
	}
}
Ejemplo n.º 6
0
/*
 * Walk the PCI bus hierarchy, starting with the root PCI bus and descending
 * through bridges, and initialize the interrupt line and latency timer
 * configuration registers of attached devices using firmware information,
 * as well as the the bus numbers and ranges of the bridges.
 */
void
ofw_pci_init(device_t dev, phandle_t bushdl, u_int32_t ign,
    struct ofw_pci_bdesc *obd)
{
	struct ofw_pci_register pcir;
	struct ofw_pci_bdesc subobd, *tobd;
	phandle_t node;
	char type[32];
	int i, intr, freemap;
	u_int slot, busno, func, sub, lat;

	/* Initialize the quirk list. */
	for (i = 0; i < OPQ_NENT; i++) {
		if (strcmp(sparc64_model, ofw_pci_quirks[i].opq_model) == 0) {
			pci_quirks = ofw_pci_quirks[i].opq_quirks;
			break;
		}
	}

	if ((node = OF_child(bushdl)) == 0)
		return;
	freemap = 0;
	busno = obd->obd_secbus;
	do {
		if (node == -1)
			panic("ofw_pci_init_intr: OF_child failed");
		if (OF_getprop(node, "device_type", type, sizeof(type)) == -1)
			type[0] = '\0';
		else
			type[sizeof(type) - 1] = '\0';
		if (OF_getprop(node, "reg", &pcir, sizeof(pcir)) == -1)
			panic("ofw_pci_init: OF_getprop failed");
		slot = OFW_PCI_PHYS_HI_DEVICE(pcir.phys_hi);
		func = OFW_PCI_PHYS_HI_FUNCTION(pcir.phys_hi);
		if (strcmp(type, OFW_PCI_PCIBUS) == 0) {
			/*
			 * This is a pci-pci bridge, initalize the bus number and
			 * recurse to initialize the child bus. The hierarchy is
			 * usually at most 2 levels deep, so recursion is
			 * feasible.
			 */
			subobd.obd_bus = busno;
			subobd.obd_slot = slot;
			subobd.obd_func = func;
			sub = ofw_pci_alloc_busno(node);
			subobd.obd_secbus = subobd.obd_subbus = sub;
			/* Assume this bridge is mostly standard conforming. */
			subobd.obd_init = ofw_pci_binit;
			subobd.obd_super = obd;
			/*
			 * Need to change all subordinate bus registers of the
			 * bridges above this one now so that configuration
			 * transactions will get through.
			 */
			for (tobd = obd; tobd != NULL; tobd = tobd->obd_super) {
				tobd->obd_subbus = sub;
				tobd->obd_init(dev, tobd);
			}
			subobd.obd_init(dev, &subobd);
#ifdef OFW_PCI_DEBUG
			device_printf(dev, "%s: descending to "
			    "subordinate PCI bus\n", __func__);
#endif /* OFW_PCI_DEBUG */
			ofw_pci_init(dev, node, ign, &subobd);
		} else {
			/*
			 * Initialize the latency timer register for
			 * busmaster devices to work properly. This is another
			 * task which the firmware does not always perform.
			 * The Min_Gnt register can be used to compute it's
			 * recommended value: it contains the desired latency
			 * in units of 1/4 us. To calculate the correct latency
			 * timer value, a bus clock of 33 and no wait states
			 * should be assumed.
			 */
			lat = PCIB_READ_CONFIG(dev, busno, slot, func,
			    PCIR_MINGNT, 1) * 33 / 4;
			if (lat != 0) {
#ifdef OFW_PCI_DEBUG
				printf("device %d/%d/%d: latency timer %d -> "
				    "%d\n", busno, slot, func,
				    PCIB_READ_CONFIG(dev, busno, slot, func,
					PCIR_LATTIMER, 1), lat);
#endif /* OFW_PCI_DEBUG */
				PCIB_WRITE_CONFIG(dev, busno, slot, func,
				    PCIR_LATTIMER, imin(lat, 255), 1);
			}

			/* Initialize the intline registers. */
			if ((intr = ofw_pci_route_intr(node, ign)) != 255) {
#ifdef OFW_PCI_DEBUG
				device_printf(dev, "%s: mapping intr for "
				    "%d/%d/%d to %d (preset was %d)\n",
				    __func__, busno, slot, func, intr,
				    (int)PCIB_READ_CONFIG(dev, busno, slot,
					func, PCIR_INTLINE, 1));
#endif /* OFW_PCI_DEBUG */
				PCIB_WRITE_CONFIG(dev, busno, slot, func,
				    PCIR_INTLINE, intr, 1);
			} else {
#ifdef OFW_PCI_DEBUG
				device_printf(dev, "%s: no interrupt "
				    "mapping found for %d/%d/%d (preset %d)\n",
				    __func__, busno, slot, func,
				    (int)PCIB_READ_CONFIG(dev, busno, slot,
					func, PCIR_INTLINE, 1));
#endif /* OFW_PCI_DEBUG */
				/*
				 * The firmware initializes to 0 instead of
				 * 255.
				 */
				PCIB_WRITE_CONFIG(dev, busno, slot, func,
				    PCIR_INTLINE, 255, 1);
			}
		}
	} while ((node = OF_peer(node)) != 0);
}