Subject: PCI Bridge bus number config by ACPI (a patch for
To: None <current-users@netbsd.org>
From: null <null@heita.net>
List: current-users
Date: 07/26/2004 03:23:47
Hi all,

  While I was installing -current (2.0G) on my used-notebook (NEC
PC-LM5005D, aka Lavie M), I noticed that, as usual, CardBus (Ricoh
5C476 PCI-CardBus bridge) configuation problem. PCIBIOS_BUS_FIXUP
didn't work for me, so I checked around and noticed that:

       o BIOS doesn't have "_32_" B(. Of course PCIBIOS_BUS_FIXUP
        won't work B(

       o Futhermore, the BIOS set PCI bridge bus number ONLY for root
         PCI bus.

  So I made some changes in sys/dev/acpi/acpi.c to configure the PCI
bridge bus numbers by ACPI, like the way of the PCIBIOS_BUS_FIXUP do
(scanning all busses recursively.)
Difference between the PCIBIOS_BUS_FIXUP and this is, referencing root
PCI bus numbers assigned in _BBN ACPI method and use the root bus
number as a start point of recursive bus scanning. If system has more
than one root PCI bus, the scanning is initiated for all the root PCI
busses.

  Following is a patch for the sys/dev/acpi/acpi.c.

  To use this, edit your config file as:
--------------------------
options	ACPI_PCI_FIXUP
options ACPI_PCI_BUS_FIXUP_BY_BBN
--------------------------

Wish this helps somebody B)

Regards,
	Motonori Hirano

----------------------------------------------------
Index: acpi.c
===================================================================
RCS file: /NetBSD/cvsroot/src/sys/dev/acpi/acpi.c,v
retrieving revision 1.66
diff -u -r1.66 acpi.c
--- acpi.c	7 Jun 2004 15:33:17 -0000	1.66
+++ acpi.c	25 Jul 2004 08:06:39 -0000
@@ -98,6 +98,15 @@
 
 #ifdef ACPI_PCI_FIXUP
 #include <dev/pci/pcidevs.h>
+#ifdef ACPI_PCI_BUS_FIXUP_BY_BBN
+#ifdef PCIBIOS_BUS_FIXUP
+
+ChokeMe Dont_define_PCIBIOS_BUS_FIXUP_with_me
+
+#endif /* PCIBIOS_BUS_FIXUP */
+
+#include <dev/pci/ppbreg.h>
+#endif /* ACPI_PCI_BUS_FIXUP_BY_BBN */
 #endif
 
 MALLOC_DECLARE(M_ACPI);
@@ -143,6 +152,15 @@
 static struct simplelock acpi_slock;
 static int acpi_locked;
 
+#if defined(ACPI_PCI_FIXUP) && defined(ACPI_PCI_BUS_FIXUP_BY_BBN)
+/*
+ * For count up of root PCI bus number.
+ */
+#define ROOT_PCI_BUS_MAX	16	/* too many? */
+static int root_bus_no = 0;
+static int root_bus[ROOT_PCI_BUS_MAX];
+#endif /* ACPI_PCI_FIXUP && ACPI_PCI_BUS_FIXUP_BY_BBN */
+
 /*
  * Prototypes.
  */
@@ -154,6 +172,10 @@
 static void		acpi_enable_fixed_events(struct acpi_softc *);
 #ifdef ACPI_PCI_FIXUP
 void			acpi_pci_fixup(struct acpi_softc *);
+#ifdef ACPI_PCI_BUS_FIXUP_BY_BBN
+static int		acpi_pci_bus_fixup_from_root(
+			    struct acpi_softc *, int);
+#endif /* ACPI_PCI_BUS_FIXUP_BY_BBN */
 #endif
 #if defined(ACPI_PCI_FIXUP) || defined(ACPI_ACTIVATE_DEV)
 static ACPI_STATUS	acpi_allocate_resources(ACPI_HANDLE handle);
@@ -1060,6 +1082,20 @@
 	sc->sc_pci_bus = 0;
 	AcpiWalkNamespace(ACPI_TYPE_DEVICE, parent, 100,
 	    acpi_pci_fixup_bus, sc, NULL);
+#ifdef ACPI_PCI_BUS_FIXUP_BY_BBN
+	if (root_bus_no > 0) {
+	    int i;
+	    for (i = 0; i < root_bus_no; i++) {
+		printf("%s: fixup PCI bridges' bus number on pci%d\n",
+		       sc->sc_dev.dv_xname, root_bus[i]);
+		(void)acpi_pci_bus_fixup_from_root(sc,
+		    root_bus[i]);
+	    }
+	} else {
+	    printf("%s: no root PCI bus??\n",
+		   sc->sc_dev.dv_xname);
+	}
+#endif /* ACPI_PCI_BUS_FIXUP_BY_BBN */
 }
 
 static uint
@@ -1144,6 +1180,141 @@
 	}
 }
 
+#ifdef ACPI_PCI_BUS_FIXUP_BY_BBN
+static int
+acpi_pci_bus_fixup_from_root(struct acpi_softc *sc,
+				int bus)
+{
+    static int total_scanned_busses = 0;
+    static int bridge_cnt = 0;
+
+    ACPI_STATUS err;
+    ACPI_PCI_ID pid;
+    UINT32 class, id, bhlc;
+    int func, nfunc, device;
+
+    int bus_max = bus;
+    int bus_sub = 0;
+    int bridge = 0;
+    int maxdevs = 0;
+
+    if (++total_scanned_busses > 255) {
+	panic("acpi_pci_bus_fixup_from_root: too many PCI buses??");
+    }
+
+    /*
+     * XXX
+     * I think I can use pci_bus_maxdevs() here, since AcpiOs*Pci*()
+     * routines call pci_make_tag() things in themselves, but not
+     * sure..
+     */
+    maxdevs = pci_bus_maxdevs(sc->sc_pc, bus);
+
+    for (device = 0; device < maxdevs; device++) {
+	pid.Bus = bus;
+	pid.Device = device;
+	pid.Function = 0;
+
+	err = AcpiOsReadPciConfiguration(&pid, PCI_ID_REG, &id, 32);
+	if (err || PCI_VENDOR(id) == PCI_VENDOR_INVALID ||
+	    PCI_VENDOR(id) == 0) {
+	    continue;
+	}
+
+	err = AcpiOsReadPciConfiguration(&pid, PCI_BHLC_REG, &bhlc, 32);
+	if (err) {
+	    continue;
+	}
+	if (PCI_HDRTYPE_MULTIFN(bhlc)) {
+	    nfunc = 8;
+	} else {
+	    nfunc = 1;
+	}
+
+	for (func = 0; func < nfunc; func++) {
+	    pid.Function = func;
+
+	    err = AcpiOsReadPciConfiguration(&pid, PCI_ID_REG, &id, 32);
+	    if (err || PCI_VENDOR(id) == PCI_VENDOR_INVALID ||
+		PCI_VENDOR(id) == 0) {
+		continue;
+	    }
+
+	    err = AcpiOsReadPciConfiguration(&pid, PCI_CLASS_REG, &class, 32);
+	    if (err) {
+		continue;
+	    }
+
+	    if (PCI_CLASS(class) == PCI_CLASS_BRIDGE &&
+		(PCI_SUBCLASS(class) == PCI_SUBCLASS_BRIDGE_PCI ||
+		 PCI_SUBCLASS(class) == PCI_SUBCLASS_BRIDGE_CARDBUS)) {
+		/*
+		 * OK, let's fix the PCI bridge bus numbers up.
+		 */
+		UINT32 info; 
+		char devinfo[256];
+
+		/* Assign the bridge #. */
+		bridge = bridge_cnt++;
+
+		/* Assign the bridge's secondary bus #. */
+		bus_max++;
+		
+		err = AcpiOsReadPciConfiguration(&pid, PPB_REG_BUSINFO, &info, 32);
+		if (err) {
+		    continue;
+		}
+
+		/*
+		 * Step 1:
+		 *	set BUSINFO reg with subordinate # as 0xff.
+		 */
+		info &= 0xff000000;
+		info |= (bus | (bus_max << 8) | (0xff << 16));
+		err = AcpiOsWritePciConfiguration(&pid, PPB_REG_BUSINFO, info, 32);
+		if (err) {
+		    continue;
+		}
+
+		/*
+		 * Step 2:
+		 *	do me recursively.
+		 */
+		bus_sub = acpi_pci_bus_fixup_from_root(sc, bus_max);
+
+		/*
+		 * Step 3:
+		 *	set BUSINFO reg with final result.
+		 */
+		info &= 0xff000000;
+		info |= (bus | (bus_max << 8) | (bus_sub << 16));
+		err = AcpiOsWritePciConfiguration(&pid, PPB_REG_BUSINFO, info, 32);
+		if (err) {
+		    continue;
+		}
+
+		pci_devinfo((pcireg_t)id, (pcireg_t)class, 
+			    1, devinfo, sizeof(devinfo));
+		printf("%s: fixup PCI bridge bus number of [%s] at "
+		       "<pci%d dev %d function %d> to "
+		       "<primary:%d secondary:%d subordinate:%d (0x%06x)>\n",
+		       sc->sc_dev.dv_xname, devinfo,
+		       bus, device, func,
+		       bus, bus_max, bus_sub,
+		       info & 0x00ffffff);
+
+		/*
+		 * Step 4:
+		 *	update bus_max.
+		 */
+		bus_max = (bus_sub > bus_max) ? bus_sub : bus_max;
+	    }
+	}
+    }
+    return bus_max;
+}
+#endif /* ACPI_PCI_BUS_FIXUP_BY_BBN */
+
 ACPI_STATUS
 acpi_pci_fixup_bus(ACPI_HANDLE handle, UINT32 level, void *context,
 		   void **status)
@@ -1177,6 +1348,14 @@
 			    ACPI_LOWORD(val));
 #endif
 			sc->sc_pci_bus = ACPI_LOWORD(val);
+#ifdef ACPI_PCI_BUS_FIXUP_BY_BBN
+			if (root_bus_no > ROOT_PCI_BUS_MAX) {
+			    panic("ACPI_PCI_BUS_FIXUP_BY_BBN: "
+				  "too many root PCI bus??");
+			} else {
+			    root_bus[root_bus_no++] = ACPI_LOWORD(val);
+			}
+#endif /* ACPI_PCI_BUS_FIXUP_BY_BBN */
 		}
 	}
 
----------------------------------------------------