Module Name:    src
Committed By:   gsutre
Date:           Sat Jul 10 21:31:00 UTC 2010

Modified Files:
        src/sys/dev/acpi/acpica: OsdHardware.c

Log Message:
AcpiOsDerivePciId: make sure that we only update the PCI bus number,
and that we do so only if it was succesfully derived.

ok jruoho@, kochi@


To generate a diff of this commit:
cvs rdiff -u -r1.5 -r1.6 src/sys/dev/acpi/acpica/OsdHardware.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/acpi/acpica/OsdHardware.c
diff -u src/sys/dev/acpi/acpica/OsdHardware.c:1.5 src/sys/dev/acpi/acpica/OsdHardware.c:1.6
--- src/sys/dev/acpi/acpica/OsdHardware.c:1.5	Tue Sep 15 19:41:30 2009
+++ src/sys/dev/acpi/acpica/OsdHardware.c	Sat Jul 10 21:31:00 2010
@@ -1,4 +1,4 @@
-/*	$NetBSD: OsdHardware.c,v 1.5 2009/09/15 19:41:30 drochner Exp $	*/
+/*	$NetBSD: OsdHardware.c,v 1.6 2010/07/10 21:31:00 gsutre Exp $	*/
 
 /*
  * Copyright 2001 Wasabi Systems, Inc.
@@ -44,13 +44,14 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: OsdHardware.c,v 1.5 2009/09/15 19:41:30 drochner Exp $");
+__KERNEL_RCSID(0, "$NetBSD: OsdHardware.c,v 1.6 2010/07/10 21:31:00 gsutre Exp $");
 
 #include <sys/param.h>
 #include <sys/device.h>
 
 #include <dev/acpi/acpica.h>
 #include <dev/acpi/acpivar.h>
+#include <dev/acpi/acpi_pci.h>
 
 #include <machine/acpi_machdep.h>
 
@@ -276,66 +277,99 @@
 	return AE_OK;
 }
 
-/* get PCI bus# from root bridge recursively */
-static int
-get_bus_number(
-    ACPI_HANDLE        rhandle,
-    ACPI_HANDLE        chandle,
-    ACPI_PCI_ID        **PciId)
+/*
+ * acpi_os_derive_pciid_rec:
+ *
+ *	Helper function for AcpiOsDerivePciId.  The parameters are:
+ *	- chandle:	a handle to the node whose PCI id shall be derived.
+ *	- rhandle:	a handle the PCI root bridge upstream of chandle.
+ *	- pciid:	where the derived PCI id is returned.
+ *
+ *	This function assumes that rhandle is a proper ancestor of chandle,
+ *	and that pciid has already been filled by ACPICA:
+ *	- segment# and bus# obtained from _SEG and _BBN on rhandle,
+ *	- device# and function# obtained from _ADR on the ACPI device node
+ *	  whose scope chandle is in).
+ */
+static ACPI_STATUS
+acpi_os_derive_pciid_rec(ACPI_HANDLE chandle, ACPI_HANDLE rhandle, ACPI_PCI_ID *pciid)
 {
-	ACPI_HANDLE handle;
+	ACPI_HANDLE phandle;
+	ACPI_INTEGER address;
+	ACPI_OBJECT_TYPE objtype;
 	ACPI_STATUS rv;
-	ACPI_OBJECT_TYPE type;
-	ACPI_PCI_ID *id;
-	ACPI_INTEGER v;
-	int bus;
+	uint16_t valb;
 
-	id = *PciId;
+	KASSERT(chandle != rhandle);
 
-	rv = AcpiGetParent(chandle, &handle);
-	if (ACPI_FAILURE(rv))
-		return 0;
+	/*
+	 * Get parent device node.  This is should not fail since chandle has
+	 * at least one ancestor that is a device node: rhandle.
+	 */
+	phandle = chandle;
+	do {
+		rv = AcpiGetParent(phandle, &phandle);
+		if (ACPI_FAILURE(rv))
+			return rv;
+		rv = AcpiGetType(phandle, &objtype);
+		if (ACPI_FAILURE(rv))
+			return rv;
+	}
+	while (objtype != ACPI_TYPE_DEVICE);
 
 	/*
-	 * When handle == rhandle, we have valid PciId->Bus
-	 * which was obtained from _BBN in evrgnini.c
-	 * so we don't have to reevaluate _BBN.
+	 * If the parent is rhandle then we have nothing to do since ACPICA
+	 * has pre-filled the PCI id to the best it could.
 	 */
-	if (handle != rhandle) {
-		bus = get_bus_number(rhandle, handle, PciId);
+	if (phandle == rhandle)
+		return AE_OK;
 
-		rv = AcpiGetType(handle, &type);
-		if (ACPI_FAILURE(rv) || type != ACPI_TYPE_DEVICE)
-			return bus;
+	/* Recursive call to get PCI id of the parent */
+	rv = acpi_os_derive_pciid_rec(phandle, rhandle, pciid);
+	if (ACPI_FAILURE(rv))
+		return rv;
 
-		rv = acpi_eval_integer(handle, METHOD_NAME__ADR, &v);
+	/*
+	 * If this is not an ACPI device, return the PCI id of its parent.
+	 */
+	rv = AcpiGetType(chandle, &objtype);
+	if (ACPI_FAILURE(rv))
+		return rv;
+	if (objtype != ACPI_TYPE_DEVICE)
+		return AE_OK;
 
-		if (ACPI_FAILURE(rv))
-			return bus;
+	/*
+	 * This is an ACPI device node.  Its parent device node is not a PCI
+	 * root bridge.  Check that it is a PCI-to-PCI bridge and get its
+	 * secondary bus#.
+	 */
+	rv = acpi_pcidev_ppb_downbus(pciid->Segment, pciid->Bus, pciid->Device,
+	    pciid->Function, &valb);
+	if (ACPI_FAILURE(rv))
+		return rv;
 
-		id->Bus = bus;
-		id->Device = ACPI_HIWORD((ACPI_INTEGER)v);
-		id->Function = ACPI_LOWORD((ACPI_INTEGER)v);
-
-		/* read HDR_TYPE register */
-		rv = AcpiOsReadPciConfiguration(id, 0x0e, &v, 8);
-		if (ACPI_SUCCESS(rv) &&
-			/* mask multifunction bit & check bridge type */
-			((v & 0x7f) == 1 || (v & 0x7f) == 2)) {
-			/* read SECONDARY_BUS register */
-			rv = AcpiOsReadPciConfiguration(id, 0x19, &v, 8);
-			if (ACPI_SUCCESS(rv))
-				id->Bus = v;
-		}
-	}
+	/* Get address (contains dev# and fun# for PCI devices). */
+	rv = acpi_eval_integer(chandle, METHOD_NAME__ADR, &address);
+	if (ACPI_FAILURE(rv))
+		return rv;
 
-	return id->Bus;
+	pciid->Bus = valb;
+	pciid->Device = ACPI_HIWORD(ACPI_LODWORD(address));
+	pciid->Function = ACPI_LOWORD(ACPI_LODWORD(address));
+	return AE_OK;
 }
 
 /*
  * AcpiOsDerivePciId:
  *
- * Derive correct PCI bus# by traversing bridges
+ *	Derive correct PCI bus# by traversing bridges.
+ *
+ *	In ACPICA release 20100331 (as well as older versions), the interface
+ *	of this function is not correctly documented in the ACPICA programmer
+ *	reference.  The correct interface parameters to this function are:
+ *	- rhandle:	a handle the PCI root bridge upstream of handle.
+ *	- chandle:	a handle to the PCI_Config operation region.
+ *	- PciId:	where the derived PCI id is returned.
  */
 void
 AcpiOsDerivePciId(
@@ -343,5 +377,16 @@
     ACPI_HANDLE        chandle,
     ACPI_PCI_ID        **PciId)
 {
-	(*PciId)->Bus = get_bus_number(rhandle, chandle, PciId);
+	ACPI_PCI_ID pciid;
+	ACPI_STATUS rv;
+
+	if (chandle == rhandle)
+		return;
+
+	pciid = **PciId;
+	rv = acpi_os_derive_pciid_rec(chandle, rhandle, &pciid);
+	if (ACPI_FAILURE(rv))
+		return;
+
+	(*PciId)->Bus = pciid.Bus;
 }

Reply via email to