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