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 */
}
}
----------------------------------------------------