From ead772dd15412719e033617966ec7e3a14bd4d89 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 4 Jul 2022 13:38:12 +0200 Subject: [PATCH] Allow AddressSpaceHandler Install and _REG execution as 2 separate steps MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ACPI-2.0 says that the EC OpRegion handler must be available immediately (like the standard default OpRegion handlers): Quoting from the ACPI spec version 6.3: "6.5.4 _REG (Region) ... 2. OSPM must make Embedded Controller operation regions, accessed via the Embedded Controllers described in ECDT, available before executing any control method. These operation regions may become inaccessible after OSPM runs _REG(EmbeddedControl, 0)." So the OS must probe the ECDT described EC and install the OpRegion handler before calling AcpiEnableSubsystem() and AcpiInitializeObjects(). This is a problem because calling AcpiInstallAddressSpaceHandler() does not just install the OpRegion handler, it also runs the EC's _REG method. This _REG method may rely on initialization done by the _INI methods of one of the PCI / _SB root devices. For the other early/default OpRegion handlers the OpRegion handler install and the _REG execution is split into 2 separate steps: 1. AcpiEvInstallRegionHandlers(), called early from AcpiLoadTables() 2. AcpiEvInitializeOpRegions(), called from AcpiInitializeObjects() To fix the EC OpRegion issue, add 2 bew functions: 1. AcpiInstallAddressSpaceHandlerNo_Reg() 2. AcpiExecuteRegMethods() to allow doing things in 2 steps for other OpRegion handlers, like the EC handler, too. Note that the comment describing AcpiEvInstallRegionHandlers() even has an alinea describing this problem. Using the new methods allows users to avoid this problem. BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=214899 Reported-and-tested-by: Johannes Penßel Signed-off-by: Hans de Goede --- source/components/events/evxfregn.c | 101 ++++++++++++++++++++++++++-- source/include/acpixf.h | 15 +++++ 2 files changed, 110 insertions(+), 6 deletions(-) diff --git a/source/components/events/evxfregn.c b/source/components/events/evxfregn.c index ee44e10d57..b7f3d28d1d 100644 --- a/source/components/events/evxfregn.c +++ b/source/components/events/evxfregn.c @@ -163,13 +163,14 @@ /******************************************************************************* * - * FUNCTION: AcpiInstallAddressSpaceHandler + * FUNCTION: AcpiInstallAddressSpaceHandlerInternal * * PARAMETERS: Device - Handle for the device * SpaceId - The address space ID * Handler - Address of the handler * Setup - Address of the setup function * Context - Value passed to the handler on each access + * Run_Reg - Run _REG methods for this address space? * * RETURN: Status * @@ -180,16 +181,19 @@ * are executed here, and these methods can only be safely executed after * the default handlers have been installed and the hardware has been * initialized (via AcpiEnableSubsystem.) + * To avoid this problem pass FALSE for Run_Reg and later on call + * AcpiExecuteRegMethods() to execute _REG. * ******************************************************************************/ -ACPI_STATUS -AcpiInstallAddressSpaceHandler ( +static ACPI_STATUS +AcpiInstallAddressSpaceHandlerInternal ( ACPI_HANDLE Device, ACPI_ADR_SPACE_TYPE SpaceId, ACPI_ADR_SPACE_HANDLER Handler, ACPI_ADR_SPACE_SETUP Setup, - void *Context) + void *Context, + BOOLEAN Run_Reg) { ACPI_NAMESPACE_NODE *Node; ACPI_STATUS Status; @@ -231,16 +235,42 @@ AcpiInstallAddressSpaceHandler ( /* Run all _REG methods for this address space */ - AcpiEvExecuteRegMethods (Node, SpaceId, ACPI_REG_CONNECT); - + if (Run_Reg) + { + AcpiEvExecuteRegMethods (Node, SpaceId, ACPI_REG_CONNECT); + } UnlockAndExit: (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE); return_ACPI_STATUS (Status); } +ACPI_STATUS +AcpiInstallAddressSpaceHandler ( + ACPI_HANDLE Device, + ACPI_ADR_SPACE_TYPE SpaceId, + ACPI_ADR_SPACE_HANDLER Handler, + ACPI_ADR_SPACE_SETUP Setup, + void *Context) +{ + return AcpiInstallAddressSpaceHandlerInternal (Device, SpaceId, Handler, Setup, Context, TRUE); +} + ACPI_EXPORT_SYMBOL (AcpiInstallAddressSpaceHandler) +ACPI_STATUS +AcpiInstallAddressSpaceHandlerNo_Reg ( + ACPI_HANDLE Device, + ACPI_ADR_SPACE_TYPE SpaceId, + ACPI_ADR_SPACE_HANDLER Handler, + ACPI_ADR_SPACE_SETUP Setup, + void *Context) +{ + return AcpiInstallAddressSpaceHandlerInternal (Device, SpaceId, Handler, Setup, Context, FALSE); +} + +ACPI_EXPORT_SYMBOL (AcpiInstallAddressSpaceHandlerNo_Reg) + /******************************************************************************* * @@ -387,3 +417,62 @@ AcpiRemoveAddressSpaceHandler ( } ACPI_EXPORT_SYMBOL (AcpiRemoveAddressSpaceHandler) + + +/******************************************************************************* + * + * FUNCTION: AcpiExecuteRegMethods + * + * PARAMETERS: Device - Handle for the device + * SpaceId - The address space ID + * + * RETURN: Status + * + * DESCRIPTION: Execute _REG for all OpRegions of a given SpaceId. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiExecuteRegMethods ( + ACPI_HANDLE Device, + ACPI_ADR_SPACE_TYPE SpaceId) +{ + ACPI_NAMESPACE_NODE *Node; + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (AcpiExecuteRegMethods); + + + /* Parameter validation */ + + if (!Device) + { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* Convert and validate the device handle */ + + Node = AcpiNsValidateHandle (Device); + if (Node) + { + /* Run all _REG methods for this address space */ + + AcpiEvExecuteRegMethods (Node, SpaceId, ACPI_REG_CONNECT); + } + else + { + Status = AE_BAD_PARAMETER; + } + + (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE); + return_ACPI_STATUS (Status); +} + +ACPI_EXPORT_SYMBOL (AcpiExecuteRegMethods) diff --git a/source/include/acpixf.h b/source/include/acpixf.h index f62c16cbd4..a381026976 100644 --- a/source/include/acpixf.h +++ b/source/include/acpixf.h @@ -942,6 +942,21 @@ AcpiInstallAddressSpaceHandler ( ACPI_ADR_SPACE_SETUP Setup, void *Context)) +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiInstallAddressSpaceHandlerNo_Reg( + ACPI_HANDLE Device, + ACPI_ADR_SPACE_TYPE SpaceId, + ACPI_ADR_SPACE_HANDLER Handler, + ACPI_ADR_SPACE_SETUP Setup, + void *Context)) + +ACPI_EXTERNAL_RETURN_STATUS ( +ACPI_STATUS +AcpiExecuteRegMethods ( + ACPI_HANDLE Device, + ACPI_ADR_SPACE_TYPE SpaceId)) + ACPI_EXTERNAL_RETURN_STATUS ( ACPI_STATUS AcpiRemoveAddressSpaceHandler (