From f70d0d754f381735a67a42be91fa7253b19a5c8c Mon Sep 17 00:00:00 2001 From: Eygene Ryabinkin Date: Sun, 3 May 2009 22:00:20 +0400 Subject: [PATCH] ACPI: implement walking namespace tree without aliased nodes ...and use this function to probe acpi(4) children. The rationale is very simple: some BIOS vendors, in my case it was Asus, like to create aliased nodes in the namespaces that will be walked by the acpi bus method that attaches children to the bus. In my particular case, the problem lied in the Processor objects: ----- Scope (_PR) { Processor (P001, 0x01, 0x00000810, 0x06) {} Alias (P001, CPU1) } Scope (_PR) { Processor (P002, 0x02, 0x00000810, 0x06) {} Alias (P002, CPU2) } ----- The thing is that the simple walk routine treated CPU1 and CPU2 as real processors and order of attachment was P001, CPU1, P002, CPU2. Thus, the second CPU was never attached, first was attached twice and est (Enhanced SpeedStep cpufreq(4) driver) was failing to get _PSS (processor P-states) from the CPU1. I greatly doubt that some real devices will be ever created as aliases, since they should be real objects and not modified copies of other device instances. And since ASL Alias() semantics is to provide pseudonym, this modification should be "The Good Thing (tm)". Signed-off-by: Eygene Ryabinkin --- sys/contrib/dev/acpica/aclocal.h | 1 + sys/contrib/dev/acpica/acnamesp.h | 1 + sys/contrib/dev/acpica/acpixf.h | 9 +++++ sys/contrib/dev/acpica/excreate.c | 3 ++ sys/contrib/dev/acpica/nswalk.c | 10 ++++- sys/contrib/dev/acpica/nsxfeval.c | 69 ++++++++++++++++++++++++++++++++++--- sys/dev/acpica/acpi.c | 18 +++++---- 7 files changed, 96 insertions(+), 15 deletions(-) diff --git a/sys/contrib/dev/acpica/aclocal.h b/sys/contrib/dev/acpica/aclocal.h index ba1145e..73e1568 100644 --- a/sys/contrib/dev/acpica/aclocal.h +++ b/sys/contrib/dev/acpica/aclocal.h @@ -301,6 +301,7 @@ typedef struct acpi_namespace_node #define ANOBJ_METHOD_ARG 0x04 /* Node is a method argument */ #define ANOBJ_METHOD_LOCAL 0x08 /* Node is a method local */ #define ANOBJ_SUBTREE_HAS_INI 0x10 /* Used to optimize device initialization */ +#define ANOBJ_IS_ALIAS 0x20 /* Node is an alias to another one */ #define ANOBJ_IS_EXTERNAL 0x08 /* iASL only: This object created via External() */ #define ANOBJ_METHOD_NO_RETVAL 0x10 /* iASL only: Method has no return value */ diff --git a/sys/contrib/dev/acpica/acnamesp.h b/sys/contrib/dev/acpica/acnamesp.h index 8d07fb3..52a50bb 100644 --- a/sys/contrib/dev/acpica/acnamesp.h +++ b/sys/contrib/dev/acpica/acnamesp.h @@ -146,6 +146,7 @@ #define ACPI_NS_WALK_NO_UNLOCK 0 #define ACPI_NS_WALK_UNLOCK 0x01 #define ACPI_NS_WALK_TEMP_NODES 0x02 +#define ACPI_NS_WALK_SKIP_ALIASES 0x04 /* diff --git a/sys/contrib/dev/acpica/acpixf.h b/sys/contrib/dev/acpica/acpixf.h index f85fd67..3757ad0 100644 --- a/sys/contrib/dev/acpica/acpixf.h +++ b/sys/contrib/dev/acpica/acpixf.h @@ -238,6 +238,15 @@ AcpiWalkNamespace ( void **ReturnValue); ACPI_STATUS +AcpiWalkNamespaceNoAliases ( + ACPI_OBJECT_TYPE Type, + ACPI_HANDLE StartObject, + UINT32 MaxDepth, + ACPI_WALK_CALLBACK UserFunction, + void *Context, + void **ReturnValue); + +ACPI_STATUS AcpiGetDevices ( char *HID, ACPI_WALK_CALLBACK UserFunction, diff --git a/sys/contrib/dev/acpica/excreate.c b/sys/contrib/dev/acpica/excreate.c index d237dab..dba8312 100644 --- a/sys/contrib/dev/acpica/excreate.c +++ b/sys/contrib/dev/acpica/excreate.c @@ -221,6 +221,9 @@ AcpiExCreateAlias ( break; } + /* Mark object as alias, so alias creation could be detected */ + AliasNode->Flags |= ANOBJ_IS_ALIAS; + /* Since both operands are Nodes, we don't need to delete them */ return_ACPI_STATUS (Status); diff --git a/sys/contrib/dev/acpica/nswalk.c b/sys/contrib/dev/acpica/nswalk.c index a3ac86c..9cbc56d 100644 --- a/sys/contrib/dev/acpica/nswalk.c +++ b/sys/contrib/dev/acpica/nswalk.c @@ -208,8 +208,7 @@ AcpiNsGetNextNode ( * PARAMETERS: Type - ACPI_OBJECT_TYPE to search for * StartNode - Handle in namespace where search begins * MaxDepth - Depth to which search is to reach - * Flags - Whether to unlock the NS before invoking - * the callback routine + * Flags - Flags that modify walk parameters * UserFunction - Called when an object of "Type" is found * Context - Passed to user function * ReturnValue - from the UserFunction if terminated early. @@ -300,6 +299,13 @@ AcpiNsWalkNamespace ( Status = AE_CTRL_DEPTH; } + /* Skip nodes created by Alias() routines if it was requested */ + else if ((ChildNode->Flags & ANOBJ_IS_ALIAS) && + (Flags & ACPI_NS_WALK_SKIP_ALIASES)) + { + Status = AE_CTRL_DEPTH; + } + /* Type must match requested type */ else if (ChildType == Type) diff --git a/sys/contrib/dev/acpica/nsxfeval.c b/sys/contrib/dev/acpica/nsxfeval.c index 617002c..662a9df 100644 --- a/sys/contrib/dev/acpica/nsxfeval.c +++ b/sys/contrib/dev/acpica/nsxfeval.c @@ -122,6 +122,16 @@ #include #include +static ACPI_STATUS +_AcpiWalkNamespace ( + ACPI_OBJECT_TYPE Type, + ACPI_HANDLE StartObject, + UINT32 MaxDepth, + ACPI_WALK_CALLBACK UserFunction, + void *Context, + void **ReturnValue, + UINT32 AddFlags); + #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME ("nsxfeval") @@ -491,11 +501,62 @@ AcpiWalkNamespace ( void *Context, void **ReturnValue) { - ACPI_STATUS Status; + ACPI_FUNCTION_TRACE (AcpiWalkNamespace); + return _AcpiWalkNamespace(Type, StartObject, MaxDepth, + UserFunction, Context, ReturnValue, 0); +} - ACPI_FUNCTION_TRACE (AcpiWalkNamespace); +ACPI_EXPORT_SYMBOL (AcpiWalkNamespace) +/******************************************************************************* + * + * FUNCTION: AcpiWalkNamespaceNoAliases + * + * DESCRIPTION: The same as AcpiWalkNamespace, but skips nodes that were + * created as the result of an Alias function. + * + * NOTE: for parameters/semantics see AcpiWalkNamespace. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiWalkNamespaceNoAliases ( + ACPI_OBJECT_TYPE Type, + ACPI_HANDLE StartObject, + UINT32 MaxDepth, + ACPI_WALK_CALLBACK UserFunction, + void *Context, + void **ReturnValue) +{ + ACPI_FUNCTION_TRACE (AcpiWalkNamespaceNoAliases); + + return _AcpiWalkNamespace(Type, StartObject, MaxDepth, + UserFunction, Context, ReturnValue, ACPI_NS_WALK_SKIP_ALIASES); +} + +ACPI_EXPORT_SYMBOL (AcpiWalkNamespaceNoAliases) + +/******************************************************************************* + * + * FUNCTION: _AcpiWalkNamespace + * + * DESCRIPTION: Internal helper for AcpiWalkNamespace and + * AcpiWalkNamespaceNoAliases. + * + ******************************************************************************/ + +static ACPI_STATUS +_AcpiWalkNamespace ( + ACPI_OBJECT_TYPE Type, + ACPI_HANDLE StartObject, + UINT32 MaxDepth, + ACPI_WALK_CALLBACK UserFunction, + void *Context, + void **ReturnValue, + UINT32 AddFlags) +{ + ACPI_STATUS Status; /* Parameter validation */ @@ -519,15 +580,13 @@ AcpiWalkNamespace ( } Status = AcpiNsWalkNamespace (Type, StartObject, MaxDepth, - ACPI_NS_WALK_UNLOCK, + AddFlags | ACPI_NS_WALK_UNLOCK, UserFunction, Context, ReturnValue); (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE); return_ACPI_STATUS (Status); } -ACPI_EXPORT_SYMBOL (AcpiWalkNamespace) - /******************************************************************************* * diff --git a/sys/dev/acpica/acpi.c b/sys/dev/acpica/acpi.c index d79b413..18a9800 100644 --- a/sys/dev/acpica/acpi.c +++ b/sys/dev/acpica/acpi.c @@ -1528,7 +1528,7 @@ acpi_device_scan_children(device_t bus, device_t dev, int max_depth, ctx.user_fn = user_fn; ctx.arg = arg; ctx.parent = h; - return (AcpiWalkNamespace(ACPI_TYPE_ANY, h, max_depth, + return (AcpiWalkNamespaceNoAliases(ACPI_TYPE_ANY, h, max_depth, acpi_device_scan_cb, &ctx, NULL)); } @@ -1648,14 +1648,16 @@ acpi_probe_children(device_t bus) * Scan the namespace and insert placeholders for all the devices that * we find. We also probe/attach any early devices. * - * Note that we use AcpiWalkNamespace rather than AcpiGetDevices because - * we want to create nodes for all devices, not just those that are - * currently present. (This assumes that we don't want to create/remove - * devices as they appear, which might be smarter.) + * Note that we use AcpiWalkNamespaceNoAliases rather than + * AcpiGetDevices because we want to create nodes for all devices, + * not just those that are currently present. (This assumes that we + * don't want to create/remove devices as they appear, which might + * be smarter.) We avoid counting aliased nodes, because we generally + * want to attach only to a "genuine" devices. */ ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "namespace scan\n")); - AcpiWalkNamespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, 100, acpi_probe_child, - bus, NULL); + AcpiWalkNamespaceNoAliases(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, 100, + acpi_probe_child, bus, NULL); /* Pre-allocate resources for our rman from any sysresource devices. */ acpi_sysres_alloc(bus); @@ -2794,7 +2796,7 @@ acpi_wake_prep_walk(int sstate) ACPI_HANDLE sb_handle; if (ACPI_SUCCESS(AcpiGetHandle(ACPI_ROOT_OBJECT, "\\_SB_", &sb_handle))) - AcpiWalkNamespace(ACPI_TYPE_DEVICE, sb_handle, 100, + AcpiWalkNamespaceNoAliases(ACPI_TYPE_DEVICE, sb_handle, 100, acpi_wake_prep, &sstate, NULL); return (0); } -- 1.6.2.4