PERFORCE change 154123 for review

Nathan Whitehorn nwhitehorn at FreeBSD.org
Fri Dec 5 09:54:54 PST 2008


http://perforce.freebsd.org/chv.cgi?CH=154123

Change 154123 by nwhitehorn at nwhitehorn_trantor on 2008/12/05 17:54:14

	Expand the OFW PCI probing routines to do a regular PCI probe in
	addtion to asking the firmware. There can be devices even in Apple
	hardware that are not listed in the devtree (grackle_hb, for instance)
	and this also sets the stage for FDT support. Also add some
	pretty-printing of name and compat properties to the devinfo output.
	
	This commit also, and more importantly, fixes X11 on my Blue & White
	G3. Apparently X barfs if the OS's list of PCI devices doesn't match
	the ones that it finds? Unclear.
	
	MFp4: RSN

Affected files ...

.. //depot/projects/ppc-g5/sys/dev/ofw/ofw_bus_subr.c#4 edit
.. //depot/projects/ppc-g5/sys/dev/ofw/ofw_bus_subr.h#3 edit
.. //depot/projects/ppc-g5/sys/powerpc/ofw/ofw_pcibus.c#5 edit
.. //depot/projects/ppc-g5/sys/powerpc/powermac/macio.c#6 edit

Differences ...

==== //depot/projects/ppc-g5/sys/dev/ofw/ofw_bus_subr.c#4 (text+ko) ====

@@ -34,7 +34,9 @@
 #include <sys/systm.h>
 #include <sys/bus.h>
 #include <sys/errno.h>
+#include <sys/libkern.h>
 
+#include <dev/ofw/ofw_bus.h>
 #include <dev/ofw/ofw_bus_subr.h>
 #include <dev/ofw/openfirm.h>
 
@@ -72,6 +74,18 @@
 		free(obd->obd_type, M_OFWPROP);
 }
 
+int 
+ofw_bus_gen_child_location_str(device_t cbdev, device_t child, char *buf,
+    size_t buflen)
+{
+	strlcat(buf, "name=", buflen);
+	strlcat(buf, ofw_bus_get_name(child), buflen);
+
+	strlcat(buf, " compat=", buflen);
+	strlcat(buf, ofw_bus_get_compat(child), buflen);
+
+	return (0);
+};
 
 const char *
 ofw_bus_gen_get_compat(device_t bus, device_t dev)

==== //depot/projects/ppc-g5/sys/dev/ofw/ofw_bus_subr.h#3 (text+ko) ====

@@ -50,6 +50,9 @@
 int	ofw_bus_gen_setup_devinfo(struct ofw_bus_devinfo *, phandle_t);
 void	ofw_bus_gen_destroy_devinfo(struct ofw_bus_devinfo *);
 
+/* Helper method to append interesting OF properties to devinfo location */
+int	ofw_bus_gen_child_location_str(device_t, device_t, char *, size_t);
+
 /* Routines for processing firmware interrupt maps */
 
 void	ofw_bus_setup_iinfo(phandle_t, struct ofw_bus_iinfo *, int);

==== //depot/projects/ppc-g5/sys/powerpc/ofw/ofw_pcibus.c#5 (text+ko) ====

@@ -54,22 +54,24 @@
 
 typedef uint32_t ofw_pci_intr_t;
 
-/* Helper functions */
-static void ofw_pcibus_setup_device(device_t bridge, phandle_t dev, 
-    uint32_t clock, u_int busno, u_int slot, u_int func);
-
 /* Methods */
 static device_probe_t ofw_pcibus_probe;
 static device_attach_t ofw_pcibus_attach;
 static pci_assign_interrupt_t ofw_pcibus_assign_interrupt;
 static ofw_bus_get_devinfo_t ofw_pcibus_get_devinfo;
+static int ofw_pcibus_child_location_str_method(device_t cbdev, device_t child,
+    char *buf, size_t buflen);
 
+static void ofw_pcibus_enum_devtree(device_t dev, u_int domain, u_int busno);
+static void ofw_pcibus_enum_bus(device_t dev, u_int domain, u_int busno);
+
 static device_method_t ofw_pcibus_methods[] = {
 	/* Device interface */
 	DEVMETHOD(device_probe,		ofw_pcibus_probe),
 	DEVMETHOD(device_attach,	ofw_pcibus_attach),
 
 	/* Bus interface */
+	DEVMETHOD(bus_child_location_str, ofw_pcibus_child_location_str_method),
 
 	/* PCI interface */
 	DEVMETHOD(pci_assign_interrupt, ofw_pcibus_assign_interrupt),
@@ -109,56 +111,75 @@
 	return (0);
 }
 
-/*
- * Perform miscellaneous setups the firmware usually does not do for us.
- */
-static void
-ofw_pcibus_setup_device(device_t bridge, phandle_t dev,  uint32_t clock, 
-    u_int busno, u_int slot, u_int func)
+static int
+ofw_pcibus_attach(device_t dev)
 {
-	int intline = PCI_INVALID_IRQ;
+	u_int busno, domain;
+
+	domain = pcib_get_domain(dev);
+	busno = pcib_get_bus(dev);
+	if (bootverbose)
+		device_printf(dev, "domain=%d, physical bus=%d\n",
+		    domain, busno);
+
+	/*
+	 * Attach those children represented in the device tree.
+	 */
+
+	ofw_pcibus_enum_devtree(dev, domain, busno);
 
 	/*
-	 * The preset in the intline register is usually wrong.  Reset
-	 * it to 255, so that the PCI code will reroute the interrupt if
-	 * needed.
+	 * We now attach any laggard devices. FDT, for instance, allows
+	 * the device tree to enumerate only some PCI devices. Apple's
+	 * OF device tree on some Grackle-based hardware can also miss
+	 * functions on multi-function cards.
 	 */
-	if (OF_getproplen(dev, "interrupts") > 0)
-		intline = 0;
-	PCIB_WRITE_CONFIG(bridge, busno, slot, func, PCIR_INTLINE,
-	    intline, 1);
+
+	ofw_pcibus_enum_bus(dev, domain, busno);
+
+	return (bus_generic_attach(dev));
 }
 
-static int
-ofw_pcibus_attach(device_t dev)
+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;
-	uint32_t clock;
-	u_int busno, domain, func, slot;
+	u_int func, slot;
+	int intline;
 
 	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);
 
-	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, child, clock, busno, slot, func);
+
+		/*
+		 * 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)
@@ -186,30 +207,118 @@
 			}
                 }
 	}
+}
+
+/*
+ * The following is an almost exact clone of pci_add_children(), with the
+ * addition that it (a) will not add children that have already been added,
+ * and (b) will set up the OFW devinfo to point to invalid values. This is
+ * to handle non-enumerated PCI children as exist in FDT and on the second
+ * function of the Rage 128 in my Blue & White G3.
+ */
 
-	return (bus_generic_attach(dev));
+static void
+ofw_pcibus_enum_bus(device_t dev, u_int domain, u_int busno)
+{
+	device_t pcib;
+	struct ofw_pcibus_devinfo *dinfo;
+	int maxslots;
+	int s, f, pcifunchigh;
+	uint8_t hdrtype;
+
+	KASSERT(dinfo_size >= sizeof(struct pci_devinfo),
+	    ("dinfo_size too small"));
+
+	pcib = device_get_parent(dev);
+
+	maxslots = PCIB_MAXSLOTS(pcib);
+	for (s = 0; s <= maxslots; s++) {
+		pcifunchigh = 0;
+		f = 0;
+		DELAY(1);
+		hdrtype = PCIB_READ_CONFIG(pcib, busno, s, f, PCIR_HDRTYPE, 1);
+		if ((hdrtype & PCIM_HDRTYPE) > PCI_MAXHDRTYPE)
+			continue;
+		if (hdrtype & PCIM_MFDEV)
+			pcifunchigh = PCI_FUNCMAX;
+		for (f = 0; f <= pcifunchigh; f++) {
+			/* Filter devices we have already added */
+			if (pci_find_dbsf(domain, busno, s, f) != NULL)
+				continue;
+
+			dinfo = (struct ofw_pcibus_devinfo *)pci_read_device(
+			    pcib, domain, busno, s, f, sizeof(*dinfo));
+			if (dinfo != NULL) {
+				dinfo->opd_obdinfo.obd_node = -1;
+
+				dinfo->opd_obdinfo.obd_name = NULL;
+				dinfo->opd_obdinfo.obd_compat = NULL;
+				dinfo->opd_obdinfo.obd_type = NULL;
+				dinfo->opd_obdinfo.obd_model = NULL;
+				pci_add_child(dev, (struct pci_devinfo *)dinfo);
+			}
+		}
+	}
 }
 
 static int
+ofw_pcibus_child_location_str_method(device_t cbdev, device_t child, char *buf,
+    size_t buflen)
+{
+	pci_child_location_str_method(cbdev, child, buf, buflen);
+
+	if (ofw_bus_get_node(child) != -1)  {
+		strlcat(buf, " ", buflen); /* Separate info */
+		ofw_bus_gen_child_location_str(cbdev, child, buf, buflen);
+	}
+
+	return (0);
+}
+	
+static int
 ofw_pcibus_assign_interrupt(device_t dev, device_t child)
 {
 	ofw_pci_intr_t intr;
+	phandle_t node;
 	int isz;
 
-	/* Any AAPL,interrupts property gets priority and is fully spec'ed */
+	node = ofw_bus_get_node(child);
+
+	if (node == -1) {
+		/* Non-firmware enumerated child, use standard routing */
+	
+		/*
+		 * XXX: Right now we don't have anything sensible to do here,
+		 * since the ofw_imap stuff relies on nodes have a reg
+		 * property. There exists ways around this, so the ePAPR
+		 * spec will need to be studied.
+		 */
+
+		return (0);
+
+#ifdef NOTYET
+		intr = pci_get_intpin(child);
+		return (PCIB_ROUTE_INTERRUPT(device_get_parent(dev), child, 
+		    intr));
+#endif
+	}
+	
+	/*
+	 * Any AAPL,interrupts property gets priority and is
+	 * fully specified (i.e. does not need routing)
+	 */
 
-	isz = OF_getprop(ofw_bus_get_node(child), "AAPL,interrupts", &intr, 
-	    sizeof(intr));
+	isz = OF_getprop(node, "AAPL,interrupts", &intr, sizeof(intr));
 	if (isz == sizeof(intr)) {
 		return (intr);
 	}
 
-	isz = OF_getprop(ofw_bus_get_node(child), "interrupts", &intr, 
-	    sizeof(intr));
+	isz = OF_getprop(node, "interrupts", &intr, sizeof(intr));
 	if (isz != sizeof(intr)) {
 		/* No property; our best guess is the intpin. */
 		intr = pci_get_intpin(child);
 	}
+	
 	/*
 	 * If we got intr from a property, it may or may not be an intpin.
 	 * For on-board devices, it frequently is not, and is completely out

==== //depot/projects/ppc-g5/sys/powerpc/powermac/macio.c#6 (text+ko) ====

@@ -107,6 +107,8 @@
         DEVMETHOD(bus_deactivate_resource, macio_deactivate_resource),
         DEVMETHOD(bus_get_resource_list, macio_get_resource_list),	
 
+	DEVMETHOD(bus_child_location_str, ofw_bus_gen_child_location_str),
+
 	/* ofw_bus interface */
 	DEVMETHOD(ofw_bus_get_devinfo,	macio_get_devinfo),
 	DEVMETHOD(ofw_bus_get_compat,	ofw_bus_gen_get_compat),


More information about the p4-projects mailing list