Date: Fri, 5 Dec 2008 17:54:53 GMT From: Nathan Whitehorn <nwhitehorn@FreeBSD.org> To: Perforce Change Reviews <perforce@freebsd.org> Subject: PERFORCE change 154123 for review Message-ID: <200812051754.mB5HsrKg017182@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=154123 Change 154123 by nwhitehorn@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),
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200812051754.mB5HsrKg017182>