summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjkim <jkim@FreeBSD.org>2012-05-04 18:24:38 +0000
committerjkim <jkim@FreeBSD.org>2012-05-04 18:24:38 +0000
commitcbd8dc582eb04ebe1bde321b9235da1c1fa93c68 (patch)
treedd82e71a3e03c783522a8cbf3cbc8828b318c5db
parent6dac06847559a77b0b65d71ae92a248c9d3c5cd6 (diff)
downloadFreeBSD-src-cbd8dc582eb04ebe1bde321b9235da1c1fa93c68.zip
FreeBSD-src-cbd8dc582eb04ebe1bde321b9235da1c1fa93c68.tar.gz
Use MADT to match ACPI Processor objects to CPUs. MADT and DSDT/SSDTs may
list CPUs in different orders, especially for disabled logical cores. Now we match ACPI IDs from the MADT with Processor objects, strictly order CPUs accordingly, and ignore disabled cores. This prevents us from executing methods for other CPUs, e. g., _PSS for disabled logical core, which may not exist. Unfortunately, it is known that there are a few systems with buggy BIOSes that do not have unique ACPI IDs for MADT and Processor objects. To work around these problems
-rw-r--r--share/man/man4/acpi.47
-rw-r--r--sys/dev/acpica/acpi.c40
2 files changed, 44 insertions, 3 deletions
diff --git a/share/man/man4/acpi.4 b/share/man/man4/acpi.4
index faedb06..91b6517 100644
--- a/share/man/man4/acpi.4
+++ b/share/man/man4/acpi.4
@@ -25,7 +25,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd March 22, 2012
+.Dd May 4, 2012
.Dt ACPI 4
.Os
.Sh NAME
@@ -198,6 +198,11 @@ entry for access after boot.
Enables loading of a custom ACPI DSDT.
.It Va acpi_dsdt_name
Name of the DSDT table to load, if loading is enabled.
+.It Va debug.acpi.cpu_unordered
+Do not use the MADT to match ACPI processor objects to CPUs.
+This is needed on a few systems with a buggy BIOS that does not use
+consistent processor IDs.
+Default is 0 (disabled).
.It Va debug.acpi.disabled
Selectively disables portions of ACPI for debugging purposes.
.It Va debug.acpi.interpreter_slack
diff --git a/sys/dev/acpica/acpi.c b/sys/dev/acpica/acpi.c
index d1db7c9..a7a1d63 100644
--- a/sys/dev/acpica/acpi.c
+++ b/sys/dev/acpica/acpi.c
@@ -289,6 +289,13 @@ SYSCTL_INT(_debug_acpi, OID_AUTO, reset_clock, CTLFLAG_RW,
&acpi_reset_clock, 1, "Reset system clock while resuming.");
#endif
+/* Allow users to ignore processor orders in MADT. */
+static int acpi_cpu_unordered;
+TUNABLE_INT("debug.acpi.cpu_unordered", &acpi_cpu_unordered);
+SYSCTL_INT(_debug_acpi, OID_AUTO, cpu_unordered, CTLFLAG_RDTUN,
+ &acpi_cpu_unordered, 0,
+ "Do not use the MADT to match ACPI processor objects to CPUs.");
+
/* Allow users to override quirks. */
TUNABLE_INT("debug.acpi.quirks", &acpi_quirks);
@@ -1856,11 +1863,15 @@ static ACPI_STATUS
acpi_probe_child(ACPI_HANDLE handle, UINT32 level, void *context, void **status)
{
struct acpi_prw_data prw;
+ ACPI_BUFFER buf;
+ ACPI_OBJECT obj;
ACPI_OBJECT_TYPE type;
ACPI_HANDLE h;
+ struct pcpu *pc;
device_t bus, child;
char *handle_str;
- int order;
+ u_int cpuid;
+ int order, unit;
ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
@@ -1898,6 +1909,31 @@ acpi_probe_child(ACPI_HANDLE handle, UINT32 level, void *context, void **status)
case ACPI_TYPE_PROCESSOR:
case ACPI_TYPE_THERMAL:
case ACPI_TYPE_POWER:
+ unit = -1;
+ if (type == ACPI_TYPE_PROCESSOR && acpi_cpu_unordered == 0) {
+ ACPI_STATUS s;
+ buf.Pointer = &obj;
+ buf.Length = sizeof(obj);
+ s = AcpiEvaluateObject(handle, NULL, NULL, &buf);
+ if (ACPI_SUCCESS(s)) {
+ CPU_FOREACH(cpuid) {
+ pc = pcpu_find(cpuid);
+ if (pc->pc_acpi_id == obj.Processor.ProcId) {
+ unit = cpuid;
+ if (bootverbose)
+ printf("ACPI: %s (ACPI ID %u) -> cpu%d\n",
+ handle_str, obj.Processor.ProcId, unit);
+ break;
+ }
+ }
+ if (unit == -1) {
+ if (bootverbose)
+ printf("ACPI: %s (ACPI ID %u) ignored\n",
+ handle_str, obj.Processor.ProcId);
+ break;
+ }
+ }
+ }
/*
* Create a placeholder device for this node. Sort the
* placeholder so that the probe/attach passes will run
@@ -1908,7 +1944,7 @@ acpi_probe_child(ACPI_HANDLE handle, UINT32 level, void *context, void **status)
ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "scanning '%s'\n", handle_str));
order = level * 10 + ACPI_DEV_BASE_ORDER;
acpi_probe_order(handle, &order);
- child = BUS_ADD_CHILD(bus, order, NULL, -1);
+ child = BUS_ADD_CHILD(bus, order, NULL, unit);
if (child == NULL)
break;
OpenPOWER on IntegriCloud