xserver: Branch 'master'

Matthias Hopf mhopf at kemper.freedesktop.org
Wed Jul 4 11:12:17 PDT 2007


 hw/xfree86/os-support/bus/altixPCI.c |  144 ++++++++++++-----------------------
 hw/xfree86/os-support/bus/linuxPci.c |   60 ++++++++++++++
 2 files changed, 110 insertions(+), 94 deletions(-)

New commits:
diff-tree 16e429bcbf2f62cfc58162ab2857afb7376dda41 (from f106c04b627d9f57b38627971dc79c75129e66d6)
Author: Jonathan Lim <jlim at sgi.com>
Date:   Wed Jul 4 20:08:49 2007 +0200

    Bug 5000: Fix domain support for SGI Altix

diff --git a/hw/xfree86/os-support/bus/altixPCI.c b/hw/xfree86/os-support/bus/altixPCI.c
index 7a72ec6..bab255e 100644
--- a/hw/xfree86/os-support/bus/altixPCI.c
+++ b/hw/xfree86/os-support/bus/altixPCI.c
@@ -11,75 +11,6 @@
 #include "xf86.h"
 #include "Pci.h"
 
-/*
- * get_dev_on_bus - Return the first device we find on segnum, busnum
- *
- * Walk all the PCI devices and return the first one found on segnum, busnum.
- * There may be a better way to do this in some xf86* function I don't know
- * about.
- */
-static pciDevice *get_dev_on_bus(unsigned int segnum, unsigned int busnum)
-{
-	pciDevice **pdev = xf86scanpci(0);
-	int i;
-
-	for (i = 0; pdev[i] != NULL; i++)
-		if (PCI_DOM_FROM_TAG(pdev[i]->tag) == segnum &&
-		    pdev[i]->busnum == busnum)
-			return pdev[i];
-	/* Should never get here... */
-	ErrorF("No PCI device found on %04x:%02x??", segnum, busnum);
-	return NULL;
-}
-
-/*
- * get_bridge_info - fill in the bridge info for bus_info based on pdev
- *
- * Find the parent bus for pdev if it exists, otherwise assume pdev *is*
- * the parent bus.  We need this on Altix because our bridges are transparent.
- */
-static void get_bridge_info(pciBusInfo_t *bus_info, pciDevice *pdev)
-{
-	unsigned int parent_segnum, segnum = PCI_DOM_FROM_TAG(pdev->tag);
-	unsigned int parent_busnum, parent_nodombus, busnum = pdev->busnum;
-	unsigned int nodombus = PCI_BUS_NO_DOMAIN(PCI_BUS_FROM_TAG(pdev->tag));
-	char bridge_path[] = "/sys/class/pci_bus/0000:00/bridge";
-	char bridge_target[] = "../../../devices/pci0000:00";
-
-	/* Path to this device's bridge */
-	sprintf(bridge_path, "/sys/class/pci_bus/%04x:%02x/bridge", segnum,
-		nodombus);
-
-	if (readlink(bridge_path, bridge_target, strlen(bridge_target)) < 0) {
-		perror("failed to dereference bridge link");
- 		ErrorF("failed to dereference bridge link, aborting\n");
-		exit(-1);
-	}
-
-	sscanf(bridge_target, "../../../devices/pci%04x:%02x", &parent_segnum,
-	       &parent_nodombus);
-
-	parent_busnum = PCI_MAKE_BUS(parent_segnum, parent_nodombus);
-
-	/*
-	 * If there's no bridge or the bridge points to the device, use
-	 * pdev as the bridge
-	 */
-	if (segnum == parent_segnum && busnum == parent_busnum) {
-		bus_info->bridge = pdev;
-		bus_info->secondary = FALSE;
-		bus_info->primary_bus = busnum;
-	} else {
-		bus_info->bridge = get_dev_on_bus(parent_segnum,
-						  parent_busnum);
-		bus_info->secondary = TRUE;
-		bus_info->primary_bus = parent_busnum;
-	}
-	pdev->businfo = bus_info;
-	pdev->pci_base_class = PCI_CLASS_DISPLAY;
-	pdev->pci_sub_class = PCI_SUBCLASS_PREHISTORIC_VGA;
-}
-
 void xf86PreScanAltix(void)
 {
 	/* Nothing to see here... */
@@ -88,36 +19,65 @@ void xf86PreScanAltix(void)
 void xf86PostScanAltix(void)
 {
 	pciConfigPtr *pdev;
-	pciBusInfo_t *bus_info;
-	int prevBusNum, curBusNum, idx;
+	int idx, free_idx;
 
 	/*
-	 * Altix PCI bridges are invisible to userspace, so we make each device
-	 * look like it's its own bridge unless it actually has a parent (as in
-	 * the case of PCI to PCI bridges).
+	 * Some altix pci chipsets do not expose themselves as host
+	 * bridges.
+	 *
+	 * Walk the devices looking for buses for which there is not a
+	 * corresponding pciDevice entry (ie. pciBusInfo[]->bridge is NULL).
+	 *
+	 * It is assumed that this indicates a root bridge for which we will
+	 * construct a fake pci host bridge device.
 	 */
-	bus_info = pciBusInfo[0];
+
 	pdev = xf86scanpci(0);
-	prevBusNum = curBusNum = pdev[0]->busnum;
-	bus_info = pciBusInfo[curBusNum];
-	bus_info->bridge = pdev[0];
-	bus_info->secondary = FALSE;
-	bus_info->primary_bus = curBusNum;
-
-	/* Walk all the PCI devices, assigning their bridge info */
-	for (idx = 0; pdev[idx] != NULL; idx++) {
-		if (pdev[idx]->busnum == prevBusNum)
-			continue; /* Already fixed up this bus */
+	for (idx = 0; pdev[idx] != NULL; idx++)
+		;
 
-		curBusNum = pdev[idx]->busnum;
-		bus_info = pciBusInfo[curBusNum];
+	free_idx = idx;
+
+	for (idx = 0; idx < free_idx; idx++) {
+		pciConfigPtr dev, fakedev;
+		pciBusInfo_t *businfo;
+
+		dev = pdev[idx];
+		businfo = pciBusInfo[dev->busnum];
+
+		if (! businfo) {
+			/* device has no bus ... should this be an error? */
+			continue;
+		}
+
+		if (businfo->bridge) {
+			/* bus has a device ... no need for fixup */
+			continue;
+		}
+
+		if (free_idx >= MAX_PCI_DEVICES)
+			FatalError("SN: No room for fake root bridge device\n");
 
 		/*
-		 * Fill in bus_info for pdev.  The bridge field will either
-		 * be pdev[idx] or a device on the parent bus.
+		 * Construct a fake device and stick it at the end of the
+		 * pdev array.  Make it look like a host bridge.
 		 */
-		get_bridge_info(bus_info, pdev[idx]);
-		prevBusNum = curBusNum;
+		fakedev = xnfcalloc(1, sizeof(pciDevice));
+		fakedev->tag = PCI_MAKE_TAG(dev->busnum, 0, 0);;
+		fakedev->busnum = dev->busnum;
+		fakedev->devnum = 0;
+		fakedev->funcnum = 0;
+		fakedev->fakeDevice = 1;
+		/* should figure out a better DEVID */
+		fakedev->pci_device_vendor = DEVID(VENDOR_GENERIC, CHIP_VGA);
+		fakedev->pci_base_class = PCI_CLASS_BRIDGE;
+
+		businfo->secondary = 0;
+		businfo->primary_bus = dev->busnum;
+		businfo->bridge = fakedev;
+
+		fakedev->businfo = businfo;
+
+		pdev[free_idx++] = fakedev;
 	}
-	return;
 }
diff --git a/hw/xfree86/os-support/bus/linuxPci.c b/hw/xfree86/os-support/bus/linuxPci.c
index 3d8266e..9a9a99d 100644
--- a/hw/xfree86/os-support/bus/linuxPci.c
+++ b/hw/xfree86/os-support/bus/linuxPci.c
@@ -658,7 +658,7 @@ linuxOpenLegacy(PCITAG Tag, char *name)
 	    return fd;
 	}
 
-	pBusInfo = pciBusInfo[bus];
+	pBusInfo = pciBusInfo[PCI_BUS_FROM_TAG(Tag)];
 	if (!pBusInfo || (bridge == pBusInfo->bridge) ||
 		!(bridge = pBusInfo->bridge)) {
 	    xfree(path);
@@ -1074,7 +1074,63 @@ ia64linuxPciFindNext(void)
 	}
 
 	if (sscanf(entry->d_name, "%02x . %01x", &dev, &func) == 2) {
-	    pciDeviceTag = PCI_MAKE_TAG(PCI_MAKE_BUS(domain, bus), dev, func);
+	    CARD32 tmp;
+	    int sec_bus, pri_bus;
+	    unsigned char base_class, sub_class;
+
+	    int pciBusNum = PCI_MAKE_BUS(domain, bus);
+	    pciDeviceTag = PCI_MAKE_TAG(pciBusNum, dev, func);
+
+	    /*
+	     * Before checking for a specific devid, look for enabled
+	     * PCI to PCI bridge devices.  If one is found, create and
+	     * initialize a bus info record (if one does not already exist).
+	     */
+	    tmp = pciReadLong(pciDeviceTag, PCI_CLASS_REG);
+	    base_class = PCI_CLASS_EXTRACT(tmp);
+	    sub_class = PCI_SUBCLASS_EXTRACT(tmp);
+	    if ((base_class == PCI_CLASS_BRIDGE) &&
+		((sub_class == PCI_SUBCLASS_BRIDGE_PCI) ||
+		 (sub_class == PCI_SUBCLASS_BRIDGE_CARDBUS))) {
+		tmp = pciReadLong(pciDeviceTag, PCI_PCI_BRIDGE_BUS_REG);
+		sec_bus = PCI_SECONDARY_BUS_EXTRACT(tmp, pciDeviceTag);
+		pri_bus = PCI_PRIMARY_BUS_EXTRACT(tmp, pciDeviceTag);
+#ifdef DEBUGPCI
+		ErrorF("ia64linuxPciFindNext: pri_bus %d sec_bus %d\n",
+		       pri_bus, sec_bus);
+#endif
+		if (pciBusNum != pri_bus) {
+		    /* Some bridges do not implement the primary bus register */
+		    if ((PCI_BUS_NO_DOMAIN(pri_bus) != 0) ||
+			(sub_class != PCI_SUBCLASS_BRIDGE_CARDBUS))
+			xf86Msg(X_WARNING,
+				"ia64linuxPciFindNext:  primary bus mismatch on PCI"
+				" bridge 0x%08lx (0x%02x, 0x%02x)\n",
+				pciDeviceTag, pciBusNum, pri_bus);
+		    pri_bus = pciBusNum;
+	        }
+		if ((pri_bus < sec_bus) && (sec_bus < pciMaxBusNum) &&
+		    pciBusInfo[pri_bus]) {
+		    /*
+		     * Found a secondary PCI bus
+		     */
+		    if (!pciBusInfo[sec_bus]) {
+			pciBusInfo[sec_bus] = xnfalloc(sizeof(pciBusInfo_t));
+
+			/* Copy parents settings... */
+			*pciBusInfo[sec_bus] = *pciBusInfo[pri_bus];
+		    }
+
+		    /* ...but not everything same as parent */
+		    pciBusInfo[sec_bus]->primary_bus = pri_bus;
+		    pciBusInfo[sec_bus]->secondary = TRUE;
+		    pciBusInfo[sec_bus]->numDevices = 32;
+
+		    if (pciNumBuses <= sec_bus)
+			pciNumBuses = sec_bus + 1;
+		}
+	    }
+
 	    devid = pciReadLong(pciDeviceTag, PCI_ID_REG);
 	    if ((devid & pciDevidMask) == pciDevid)
 		/* Yes - Return it.  Otherwise, next device */


More information about the xorg-commit mailing list