diff options
author | jkim <jkim@FreeBSD.org> | 2012-02-16 00:24:10 +0000 |
---|---|---|
committer | jkim <jkim@FreeBSD.org> | 2012-02-16 00:24:10 +0000 |
commit | a6dfe3119152f97e640cc135d963b9f7c95c84ef (patch) | |
tree | 71526afe7e3c45a4c88ba7b5d8d57d1e469feec2 /source/components/hardware | |
parent | 4cca06feceaf26d2d8b24e1d834b5ab61208d3fa (diff) | |
download | FreeBSD-src-a6dfe3119152f97e640cc135d963b9f7c95c84ef.zip FreeBSD-src-a6dfe3119152f97e640cc135d963b9f7c95c84ef.tar.gz |
Import ACPICA 20120215.
Diffstat (limited to 'source/components/hardware')
-rw-r--r-- | source/components/hardware/hwacpi.c | 209 | ||||
-rw-r--r-- | source/components/hardware/hwesleep.c | 263 | ||||
-rw-r--r-- | source/components/hardware/hwgpe.c | 543 | ||||
-rw-r--r-- | source/components/hardware/hwpci.c | 459 | ||||
-rw-r--r-- | source/components/hardware/hwregs.c | 741 | ||||
-rw-r--r-- | source/components/hardware/hwsleep.c | 384 | ||||
-rw-r--r-- | source/components/hardware/hwtimer.c | 218 | ||||
-rw-r--r-- | source/components/hardware/hwvalid.c | 368 | ||||
-rw-r--r-- | source/components/hardware/hwxface.c | 617 | ||||
-rw-r--r-- | source/components/hardware/hwxfsleep.c | 474 |
10 files changed, 4276 insertions, 0 deletions
diff --git a/source/components/hardware/hwacpi.c b/source/components/hardware/hwacpi.c new file mode 100644 index 0000000..d9f16ef --- /dev/null +++ b/source/components/hardware/hwacpi.c @@ -0,0 +1,209 @@ + +/****************************************************************************** + * + * Module Name: hwacpi - ACPI Hardware Initialization/Mode Interface + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2012, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#define __HWACPI_C__ + +#include "acpi.h" +#include "accommon.h" + + +#define _COMPONENT ACPI_HARDWARE + ACPI_MODULE_NAME ("hwacpi") + + +#if (!ACPI_REDUCED_HARDWARE) /* Entire module */ +/****************************************************************************** + * + * FUNCTION: AcpiHwSetMode + * + * PARAMETERS: Mode - SYS_MODE_ACPI or SYS_MODE_LEGACY + * + * RETURN: Status + * + * DESCRIPTION: Transitions the system into the requested mode. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiHwSetMode ( + UINT32 Mode) +{ + + ACPI_STATUS Status; + UINT32 Retry; + + + ACPI_FUNCTION_TRACE (HwSetMode); + + /* + * ACPI 2.0 clarified that if SMI_CMD in FADT is zero, + * system does not support mode transition. + */ + if (!AcpiGbl_FADT.SmiCommand) + { + ACPI_ERROR ((AE_INFO, "No SMI_CMD in FADT, mode transition failed")); + return_ACPI_STATUS (AE_NO_HARDWARE_RESPONSE); + } + + /* + * ACPI 2.0 clarified the meaning of ACPI_ENABLE and ACPI_DISABLE + * in FADT: If it is zero, enabling or disabling is not supported. + * As old systems may have used zero for mode transition, + * we make sure both the numbers are zero to determine these + * transitions are not supported. + */ + if (!AcpiGbl_FADT.AcpiEnable && !AcpiGbl_FADT.AcpiDisable) + { + ACPI_ERROR ((AE_INFO, + "No ACPI mode transition supported in this system " + "(enable/disable both zero)")); + return_ACPI_STATUS (AE_OK); + } + + switch (Mode) + { + case ACPI_SYS_MODE_ACPI: + + /* BIOS should have disabled ALL fixed and GP events */ + + Status = AcpiHwWritePort (AcpiGbl_FADT.SmiCommand, + (UINT32) AcpiGbl_FADT.AcpiEnable, 8); + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Attempting to enable ACPI mode\n")); + break; + + case ACPI_SYS_MODE_LEGACY: + + /* + * BIOS should clear all fixed status bits and restore fixed event + * enable bits to default + */ + Status = AcpiHwWritePort (AcpiGbl_FADT.SmiCommand, + (UINT32) AcpiGbl_FADT.AcpiDisable, 8); + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, + "Attempting to enable Legacy (non-ACPI) mode\n")); + break; + + default: + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + if (ACPI_FAILURE (Status)) + { + ACPI_EXCEPTION ((AE_INFO, Status, + "Could not write ACPI mode change")); + return_ACPI_STATUS (Status); + } + + /* + * Some hardware takes a LONG time to switch modes. Give them 3 sec to + * do so, but allow faster systems to proceed more quickly. + */ + Retry = 3000; + while (Retry) + { + if (AcpiHwGetMode() == Mode) + { + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Mode %X successfully enabled\n", + Mode)); + return_ACPI_STATUS (AE_OK); + } + AcpiOsStall(1000); + Retry--; + } + + ACPI_ERROR ((AE_INFO, "Hardware did not change modes")); + return_ACPI_STATUS (AE_NO_HARDWARE_RESPONSE); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiHwGetMode + * + * PARAMETERS: none + * + * RETURN: SYS_MODE_ACPI or SYS_MODE_LEGACY + * + * DESCRIPTION: Return current operating state of system. Determined by + * querying the SCI_EN bit. + * + ******************************************************************************/ + +UINT32 +AcpiHwGetMode ( + void) +{ + ACPI_STATUS Status; + UINT32 Value; + + + ACPI_FUNCTION_TRACE (HwGetMode); + + + /* + * ACPI 2.0 clarified that if SMI_CMD in FADT is zero, + * system does not support mode transition. + */ + if (!AcpiGbl_FADT.SmiCommand) + { + return_UINT32 (ACPI_SYS_MODE_ACPI); + } + + Status = AcpiReadBitRegister (ACPI_BITREG_SCI_ENABLE, &Value); + if (ACPI_FAILURE (Status)) + { + return_UINT32 (ACPI_SYS_MODE_LEGACY); + } + + if (Value) + { + return_UINT32 (ACPI_SYS_MODE_ACPI); + } + else + { + return_UINT32 (ACPI_SYS_MODE_LEGACY); + } +} + +#endif /* !ACPI_REDUCED_HARDWARE */ diff --git a/source/components/hardware/hwesleep.c b/source/components/hardware/hwesleep.c new file mode 100644 index 0000000..e95647e --- /dev/null +++ b/source/components/hardware/hwesleep.c @@ -0,0 +1,263 @@ +/****************************************************************************** + * + * Name: hwesleep.c - ACPI Hardware Sleep/Wake Support functions for the + * extended FADT-V5 sleep registers. + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2012, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" + +#define _COMPONENT ACPI_HARDWARE + ACPI_MODULE_NAME ("hwesleep") + + +/******************************************************************************* + * + * FUNCTION: AcpiHwExecuteSleepMethod + * + * PARAMETERS: MethodName - Pathname of method to execute + * IntegerArgument - Argument to pass to the method + * + * RETURN: None + * + * DESCRIPTION: Execute a sleep/wake related method with one integer argument + * and no return value. + * + ******************************************************************************/ + +void +AcpiHwExecuteSleepMethod ( + char *MethodName, + UINT32 IntegerArgument) +{ + ACPI_OBJECT_LIST ArgList; + ACPI_OBJECT Arg; + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (HwExecuteSleepMethod); + + + /* One argument, IntegerArgument; No return value expected */ + + ArgList.Count = 1; + ArgList.Pointer = &Arg; + Arg.Type = ACPI_TYPE_INTEGER; + Arg.Integer.Value = (UINT64) IntegerArgument; + + Status = AcpiEvaluateObject (NULL, MethodName, &ArgList, NULL); + if (ACPI_FAILURE (Status) && Status != AE_NOT_FOUND) + { + ACPI_EXCEPTION ((AE_INFO, Status, "While executing method %s", + MethodName)); + } + + return_VOID; +} + + +/******************************************************************************* + * + * FUNCTION: AcpiHwExtendedSleep + * + * PARAMETERS: SleepState - Which sleep state to enter + * + * RETURN: Status + * + * DESCRIPTION: Enter a system sleep state via the extended FADT sleep + * registers (V5 FADT). + * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED + * + ******************************************************************************/ + +ACPI_STATUS +AcpiHwExtendedSleep ( + UINT8 SleepState) +{ + ACPI_STATUS Status; + UINT8 SleepTypeValue; + UINT64 SleepStatus; + + + ACPI_FUNCTION_TRACE (HwExtendedSleep); + + + /* Extended sleep registers must be valid */ + + if (!AcpiGbl_FADT.SleepControl.Address || + !AcpiGbl_FADT.SleepStatus.Address) + { + return_ACPI_STATUS (AE_NOT_EXIST); + } + + /* Clear wake status (WAK_STS) */ + + Status = AcpiWrite (ACPI_X_WAKE_STATUS, &AcpiGbl_FADT.SleepStatus); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + AcpiGbl_SystemAwakeAndRunning = FALSE; + + /* Execute the _GTS method (Going To Sleep) */ + + AcpiHwExecuteSleepMethod (METHOD_NAME__GTS, SleepState); + + /* Flush caches, as per ACPI specification */ + + ACPI_FLUSH_CPU_CACHE (); + + /* + * Set the SLP_TYP and SLP_EN bits. + * + * Note: We only use the first value returned by the \_Sx method + * (AcpiGbl_SleepTypeA) - As per ACPI specification. + */ + ACPI_DEBUG_PRINT ((ACPI_DB_INIT, + "Entering sleep state [S%u]\n", SleepState)); + + SleepTypeValue = ((AcpiGbl_SleepTypeA << ACPI_X_SLEEP_TYPE_POSITION) & + ACPI_X_SLEEP_TYPE_MASK); + + Status = AcpiWrite ((SleepTypeValue | ACPI_X_SLEEP_ENABLE), + &AcpiGbl_FADT.SleepControl); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* Wait for transition back to Working State */ + + do + { + Status = AcpiRead (&SleepStatus, &AcpiGbl_FADT.SleepStatus); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + } while (!(((UINT8) SleepStatus) & ACPI_X_WAKE_STATUS)); + + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiHwExtendedWakePrep + * + * PARAMETERS: SleepState - Which sleep state we just exited + * + * RETURN: Status + * + * DESCRIPTION: Perform first part of OS-independent ACPI cleanup after + * a sleep. Called with interrupts ENABLED. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiHwExtendedWakePrep ( + UINT8 SleepState) +{ + ACPI_STATUS Status; + UINT8 SleepTypeValue; + + + ACPI_FUNCTION_TRACE (HwExtendedWakePrep); + + + Status = AcpiGetSleepTypeData (ACPI_STATE_S0, + &AcpiGbl_SleepTypeA, &AcpiGbl_SleepTypeB); + if (ACPI_SUCCESS (Status)) + { + SleepTypeValue = ((AcpiGbl_SleepTypeA << ACPI_X_SLEEP_TYPE_POSITION) & + ACPI_X_SLEEP_TYPE_MASK); + + (void) AcpiWrite ((SleepTypeValue | ACPI_X_SLEEP_ENABLE), + &AcpiGbl_FADT.SleepControl); + } + + AcpiHwExecuteSleepMethod (METHOD_NAME__BFS, SleepState); + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiHwExtendedWake + * + * PARAMETERS: SleepState - Which sleep state we just exited + * + * RETURN: Status + * + * DESCRIPTION: Perform OS-independent ACPI cleanup after a sleep + * Called with interrupts ENABLED. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiHwExtendedWake ( + UINT8 SleepState) +{ + ACPI_FUNCTION_TRACE (HwExtendedWake); + + + /* Ensure EnterSleepStatePrep -> EnterSleepState ordering */ + + AcpiGbl_SleepTypeA = ACPI_SLEEP_TYPE_INVALID; + + /* Execute the wake methods */ + + AcpiHwExecuteSleepMethod (METHOD_NAME__SST, ACPI_SST_WAKING); + AcpiHwExecuteSleepMethod (METHOD_NAME__WAK, SleepState); + + /* + * Some BIOS code assumes that WAK_STS will be cleared on resume + * and use it to determine whether the system is rebooting or + * resuming. Clear WAK_STS for compatibility. + */ + (void) AcpiWrite (ACPI_X_WAKE_STATUS, &AcpiGbl_FADT.SleepStatus); + AcpiGbl_SystemAwakeAndRunning = TRUE; + + AcpiHwExecuteSleepMethod (METHOD_NAME__SST, ACPI_SST_WORKING); + return_ACPI_STATUS (AE_OK); +} diff --git a/source/components/hardware/hwgpe.c b/source/components/hardware/hwgpe.c new file mode 100644 index 0000000..c94f17b --- /dev/null +++ b/source/components/hardware/hwgpe.c @@ -0,0 +1,543 @@ + +/****************************************************************************** + * + * Module Name: hwgpe - Low level GPE enable/disable/clear functions + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2012, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acevents.h" + +#define _COMPONENT ACPI_HARDWARE + ACPI_MODULE_NAME ("hwgpe") + +#if (!ACPI_REDUCED_HARDWARE) /* Entire module */ + +/* Local prototypes */ + +static ACPI_STATUS +AcpiHwEnableWakeupGpeBlock ( + ACPI_GPE_XRUPT_INFO *GpeXruptInfo, + ACPI_GPE_BLOCK_INFO *GpeBlock, + void *Context); + + +/****************************************************************************** + * + * FUNCTION: AcpiHwGetGpeRegisterBit + * + * PARAMETERS: GpeEventInfo - Info block for the GPE + * GpeRegisterInfo - Info block for the GPE register + * + * RETURN: Register mask with a one in the GPE bit position + * + * DESCRIPTION: Compute the register mask for this GPE. One bit is set in the + * correct position for the input GPE. + * + ******************************************************************************/ + +UINT32 +AcpiHwGetGpeRegisterBit ( + ACPI_GPE_EVENT_INFO *GpeEventInfo, + ACPI_GPE_REGISTER_INFO *GpeRegisterInfo) +{ + + return ((UINT32) 1 << + (GpeEventInfo->GpeNumber - GpeRegisterInfo->BaseGpeNumber)); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiHwLowSetGpe + * + * PARAMETERS: GpeEventInfo - Info block for the GPE to be disabled + * Action - Enable or disable + * + * RETURN: Status + * + * DESCRIPTION: Enable or disable a single GPE in the parent enable register. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiHwLowSetGpe ( + ACPI_GPE_EVENT_INFO *GpeEventInfo, + UINT32 Action) +{ + ACPI_GPE_REGISTER_INFO *GpeRegisterInfo; + ACPI_STATUS Status; + UINT32 EnableMask; + UINT32 RegisterBit; + + + ACPI_FUNCTION_ENTRY (); + + + /* Get the info block for the entire GPE register */ + + GpeRegisterInfo = GpeEventInfo->RegisterInfo; + if (!GpeRegisterInfo) + { + return (AE_NOT_EXIST); + } + + /* Get current value of the enable register that contains this GPE */ + + Status = AcpiHwRead (&EnableMask, &GpeRegisterInfo->EnableAddress); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* Set or clear just the bit that corresponds to this GPE */ + + RegisterBit = AcpiHwGetGpeRegisterBit (GpeEventInfo, GpeRegisterInfo); + switch (Action) + { + case ACPI_GPE_CONDITIONAL_ENABLE: + + /* Only enable if the EnableForRun bit is set */ + + if (!(RegisterBit & GpeRegisterInfo->EnableForRun)) + { + return (AE_BAD_PARAMETER); + } + + /*lint -fallthrough */ + + case ACPI_GPE_ENABLE: + ACPI_SET_BIT (EnableMask, RegisterBit); + break; + + case ACPI_GPE_DISABLE: + ACPI_CLEAR_BIT (EnableMask, RegisterBit); + break; + + default: + ACPI_ERROR ((AE_INFO, "Invalid GPE Action, %u\n", Action)); + return (AE_BAD_PARAMETER); + } + + /* Write the updated enable mask */ + + Status = AcpiHwWrite (EnableMask, &GpeRegisterInfo->EnableAddress); + return (Status); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiHwClearGpe + * + * PARAMETERS: GpeEventInfo - Info block for the GPE to be cleared + * + * RETURN: Status + * + * DESCRIPTION: Clear the status bit for a single GPE. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiHwClearGpe ( + ACPI_GPE_EVENT_INFO *GpeEventInfo) +{ + ACPI_GPE_REGISTER_INFO *GpeRegisterInfo; + ACPI_STATUS Status; + UINT32 RegisterBit; + + + ACPI_FUNCTION_ENTRY (); + + /* Get the info block for the entire GPE register */ + + GpeRegisterInfo = GpeEventInfo->RegisterInfo; + if (!GpeRegisterInfo) + { + return (AE_NOT_EXIST); + } + + /* + * Write a one to the appropriate bit in the status register to + * clear this GPE. + */ + RegisterBit = AcpiHwGetGpeRegisterBit (GpeEventInfo, GpeRegisterInfo); + + Status = AcpiHwWrite (RegisterBit, + &GpeRegisterInfo->StatusAddress); + + return (Status); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiHwGetGpeStatus + * + * PARAMETERS: GpeEventInfo - Info block for the GPE to queried + * EventStatus - Where the GPE status is returned + * + * RETURN: Status + * + * DESCRIPTION: Return the status of a single GPE. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiHwGetGpeStatus ( + ACPI_GPE_EVENT_INFO *GpeEventInfo, + ACPI_EVENT_STATUS *EventStatus) +{ + UINT32 InByte; + UINT32 RegisterBit; + ACPI_GPE_REGISTER_INFO *GpeRegisterInfo; + ACPI_EVENT_STATUS LocalEventStatus = 0; + ACPI_STATUS Status; + + + ACPI_FUNCTION_ENTRY (); + + + if (!EventStatus) + { + return (AE_BAD_PARAMETER); + } + + /* Get the info block for the entire GPE register */ + + GpeRegisterInfo = GpeEventInfo->RegisterInfo; + + /* Get the register bitmask for this GPE */ + + RegisterBit = AcpiHwGetGpeRegisterBit (GpeEventInfo, GpeRegisterInfo); + + /* GPE currently enabled? (enabled for runtime?) */ + + if (RegisterBit & GpeRegisterInfo->EnableForRun) + { + LocalEventStatus |= ACPI_EVENT_FLAG_ENABLED; + } + + /* GPE enabled for wake? */ + + if (RegisterBit & GpeRegisterInfo->EnableForWake) + { + LocalEventStatus |= ACPI_EVENT_FLAG_WAKE_ENABLED; + } + + /* GPE currently active (status bit == 1)? */ + + Status = AcpiHwRead (&InByte, &GpeRegisterInfo->StatusAddress); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + if (RegisterBit & InByte) + { + LocalEventStatus |= ACPI_EVENT_FLAG_SET; + } + + /* Set return value */ + + (*EventStatus) = LocalEventStatus; + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiHwDisableGpeBlock + * + * PARAMETERS: GpeXruptInfo - GPE Interrupt info + * GpeBlock - Gpe Block info + * + * RETURN: Status + * + * DESCRIPTION: Disable all GPEs within a single GPE block + * + ******************************************************************************/ + +ACPI_STATUS +AcpiHwDisableGpeBlock ( + ACPI_GPE_XRUPT_INFO *GpeXruptInfo, + ACPI_GPE_BLOCK_INFO *GpeBlock, + void *Context) +{ + UINT32 i; + ACPI_STATUS Status; + + + /* Examine each GPE Register within the block */ + + for (i = 0; i < GpeBlock->RegisterCount; i++) + { + /* Disable all GPEs in this register */ + + Status = AcpiHwWrite (0x00, &GpeBlock->RegisterInfo[i].EnableAddress); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + } + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiHwClearGpeBlock + * + * PARAMETERS: GpeXruptInfo - GPE Interrupt info + * GpeBlock - Gpe Block info + * + * RETURN: Status + * + * DESCRIPTION: Clear status bits for all GPEs within a single GPE block + * + ******************************************************************************/ + +ACPI_STATUS +AcpiHwClearGpeBlock ( + ACPI_GPE_XRUPT_INFO *GpeXruptInfo, + ACPI_GPE_BLOCK_INFO *GpeBlock, + void *Context) +{ + UINT32 i; + ACPI_STATUS Status; + + + /* Examine each GPE Register within the block */ + + for (i = 0; i < GpeBlock->RegisterCount; i++) + { + /* Clear status on all GPEs in this register */ + + Status = AcpiHwWrite (0xFF, &GpeBlock->RegisterInfo[i].StatusAddress); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + } + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiHwEnableRuntimeGpeBlock + * + * PARAMETERS: GpeXruptInfo - GPE Interrupt info + * GpeBlock - Gpe Block info + * + * RETURN: Status + * + * DESCRIPTION: Enable all "runtime" GPEs within a single GPE block. Includes + * combination wake/run GPEs. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiHwEnableRuntimeGpeBlock ( + ACPI_GPE_XRUPT_INFO *GpeXruptInfo, + ACPI_GPE_BLOCK_INFO *GpeBlock, + void *Context) +{ + UINT32 i; + ACPI_STATUS Status; + + + /* NOTE: assumes that all GPEs are currently disabled */ + + /* Examine each GPE Register within the block */ + + for (i = 0; i < GpeBlock->RegisterCount; i++) + { + if (!GpeBlock->RegisterInfo[i].EnableForRun) + { + continue; + } + + /* Enable all "runtime" GPEs in this register */ + + Status = AcpiHwWrite (GpeBlock->RegisterInfo[i].EnableForRun, + &GpeBlock->RegisterInfo[i].EnableAddress); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + } + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiHwEnableWakeupGpeBlock + * + * PARAMETERS: GpeXruptInfo - GPE Interrupt info + * GpeBlock - Gpe Block info + * + * RETURN: Status + * + * DESCRIPTION: Enable all "wake" GPEs within a single GPE block. Includes + * combination wake/run GPEs. + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiHwEnableWakeupGpeBlock ( + ACPI_GPE_XRUPT_INFO *GpeXruptInfo, + ACPI_GPE_BLOCK_INFO *GpeBlock, + void *Context) +{ + UINT32 i; + ACPI_STATUS Status; + + + /* Examine each GPE Register within the block */ + + for (i = 0; i < GpeBlock->RegisterCount; i++) + { + if (!GpeBlock->RegisterInfo[i].EnableForWake) + { + continue; + } + + /* Enable all "wake" GPEs in this register */ + + Status = AcpiHwWrite (GpeBlock->RegisterInfo[i].EnableForWake, + &GpeBlock->RegisterInfo[i].EnableAddress); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + } + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiHwDisableAllGpes + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Disable and clear all GPEs in all GPE blocks + * + ******************************************************************************/ + +ACPI_STATUS +AcpiHwDisableAllGpes ( + void) +{ + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (HwDisableAllGpes); + + + Status = AcpiEvWalkGpeList (AcpiHwDisableGpeBlock, NULL); + Status = AcpiEvWalkGpeList (AcpiHwClearGpeBlock, NULL); + return_ACPI_STATUS (Status); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiHwEnableAllRuntimeGpes + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Enable all "runtime" GPEs, in all GPE blocks + * + ******************************************************************************/ + +ACPI_STATUS +AcpiHwEnableAllRuntimeGpes ( + void) +{ + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (HwEnableAllRuntimeGpes); + + + Status = AcpiEvWalkGpeList (AcpiHwEnableRuntimeGpeBlock, NULL); + return_ACPI_STATUS (Status); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiHwEnableAllWakeupGpes + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Enable all "wakeup" GPEs, in all GPE blocks + * + ******************************************************************************/ + +ACPI_STATUS +AcpiHwEnableAllWakeupGpes ( + void) +{ + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (HwEnableAllWakeupGpes); + + + Status = AcpiEvWalkGpeList (AcpiHwEnableWakeupGpeBlock, NULL); + return_ACPI_STATUS (Status); +} + +#endif /* !ACPI_REDUCED_HARDWARE */ diff --git a/source/components/hardware/hwpci.c b/source/components/hardware/hwpci.c new file mode 100644 index 0000000..065e42d --- /dev/null +++ b/source/components/hardware/hwpci.c @@ -0,0 +1,459 @@ +/******************************************************************************* + * + * Module Name: hwpci - Obtain PCI bus, device, and function numbers + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2012, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#define __HWPCI_C__ + +#include "acpi.h" +#include "accommon.h" + + +#define _COMPONENT ACPI_NAMESPACE + ACPI_MODULE_NAME ("hwpci") + + +/* PCI configuration space values */ + +#define PCI_CFG_HEADER_TYPE_REG 0x0E +#define PCI_CFG_PRIMARY_BUS_NUMBER_REG 0x18 +#define PCI_CFG_SECONDARY_BUS_NUMBER_REG 0x19 + +/* PCI header values */ + +#define PCI_HEADER_TYPE_MASK 0x7F +#define PCI_TYPE_BRIDGE 0x01 +#define PCI_TYPE_CARDBUS_BRIDGE 0x02 + +typedef struct acpi_pci_device +{ + ACPI_HANDLE Device; + struct acpi_pci_device *Next; + +} ACPI_PCI_DEVICE; + + +/* Local prototypes */ + +static ACPI_STATUS +AcpiHwBuildPciList ( + ACPI_HANDLE RootPciDevice, + ACPI_HANDLE PciRegion, + ACPI_PCI_DEVICE **ReturnListHead); + +static ACPI_STATUS +AcpiHwProcessPciList ( + ACPI_PCI_ID *PciId, + ACPI_PCI_DEVICE *ListHead); + +static void +AcpiHwDeletePciList ( + ACPI_PCI_DEVICE *ListHead); + +static ACPI_STATUS +AcpiHwGetPciDeviceInfo ( + ACPI_PCI_ID *PciId, + ACPI_HANDLE PciDevice, + UINT16 *BusNumber, + BOOLEAN *IsBridge); + + +/******************************************************************************* + * + * FUNCTION: AcpiHwDerivePciId + * + * PARAMETERS: PciId - Initial values for the PCI ID. May be + * modified by this function. + * RootPciDevice - A handle to a PCI device object. This + * object must be a PCI Root Bridge having a + * _HID value of either PNP0A03 or PNP0A08 + * PciRegion - A handle to a PCI configuration space + * Operation Region being initialized + * + * RETURN: Status + * + * DESCRIPTION: This function derives a full PCI ID for a PCI device, + * consisting of a Segment number, Bus number, Device number, + * and function code. + * + * The PCI hardware dynamically configures PCI bus numbers + * depending on the bus topology discovered during system + * initialization. This function is invoked during configuration + * of a PCI_Config Operation Region in order to (possibly) update + * the Bus/Device/Function numbers in the PciId with the actual + * values as determined by the hardware and operating system + * configuration. + * + * The PciId parameter is initially populated during the Operation + * Region initialization. This function is then called, and is + * will make any necessary modifications to the Bus, Device, or + * Function number PCI ID subfields as appropriate for the + * current hardware and OS configuration. + * + * NOTE: Created 08/2010. Replaces the previous OSL AcpiOsDerivePciId + * interface since this feature is OS-independent. This module + * specifically avoids any use of recursion by building a local + * temporary device list. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiHwDerivePciId ( + ACPI_PCI_ID *PciId, + ACPI_HANDLE RootPciDevice, + ACPI_HANDLE PciRegion) +{ + ACPI_STATUS Status; + ACPI_PCI_DEVICE *ListHead = NULL; + + + ACPI_FUNCTION_TRACE (HwDerivePciId); + + + if (!PciId) + { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + /* Build a list of PCI devices, from PciRegion up to RootPciDevice */ + + Status = AcpiHwBuildPciList (RootPciDevice, PciRegion, &ListHead); + if (ACPI_SUCCESS (Status)) + { + /* Walk the list, updating the PCI device/function/bus numbers */ + + Status = AcpiHwProcessPciList (PciId, ListHead); + } + + /* Always delete the list */ + + AcpiHwDeletePciList (ListHead); + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiHwBuildPciList + * + * PARAMETERS: RootPciDevice - A handle to a PCI device object. This + * object is guaranteed to be a PCI Root + * Bridge having a _HID value of either + * PNP0A03 or PNP0A08 + * PciRegion - A handle to the PCI configuration space + * Operation Region + * ReturnListHead - Where the PCI device list is returned + * + * RETURN: Status + * + * DESCRIPTION: Builds a list of devices from the input PCI region up to the + * Root PCI device for this namespace subtree. + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiHwBuildPciList ( + ACPI_HANDLE RootPciDevice, + ACPI_HANDLE PciRegion, + ACPI_PCI_DEVICE **ReturnListHead) +{ + ACPI_HANDLE CurrentDevice; + ACPI_HANDLE ParentDevice; + ACPI_STATUS Status; + ACPI_PCI_DEVICE *ListElement; + ACPI_PCI_DEVICE *ListHead = NULL; + + + /* + * Ascend namespace branch until the RootPciDevice is reached, building + * a list of device nodes. Loop will exit when either the PCI device is + * found, or the root of the namespace is reached. + */ + CurrentDevice = PciRegion; + while (1) + { + Status = AcpiGetParent (CurrentDevice, &ParentDevice); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* Finished when we reach the PCI root device (PNP0A03 or PNP0A08) */ + + if (ParentDevice == RootPciDevice) + { + *ReturnListHead = ListHead; + return (AE_OK); + } + + ListElement = ACPI_ALLOCATE (sizeof (ACPI_PCI_DEVICE)); + if (!ListElement) + { + return (AE_NO_MEMORY); + } + + /* Put new element at the head of the list */ + + ListElement->Next = ListHead; + ListElement->Device = ParentDevice; + ListHead = ListElement; + + CurrentDevice = ParentDevice; + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiHwProcessPciList + * + * PARAMETERS: PciId - Initial values for the PCI ID. May be + * modified by this function. + * ListHead - Device list created by + * AcpiHwBuildPciList + * + * RETURN: Status + * + * DESCRIPTION: Walk downward through the PCI device list, getting the device + * info for each, via the PCI configuration space and updating + * the PCI ID as necessary. Deletes the list during traversal. + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiHwProcessPciList ( + ACPI_PCI_ID *PciId, + ACPI_PCI_DEVICE *ListHead) +{ + ACPI_STATUS Status = AE_OK; + ACPI_PCI_DEVICE *Info; + UINT16 BusNumber; + BOOLEAN IsBridge = TRUE; + + + ACPI_FUNCTION_NAME (HwProcessPciList); + + + ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION, + "Input PciId: Seg %4.4X Bus %4.4X Dev %4.4X Func %4.4X\n", + PciId->Segment, PciId->Bus, PciId->Device, PciId->Function)); + + BusNumber = PciId->Bus; + + /* + * Descend down the namespace tree, collecting PCI device, function, + * and bus numbers. BusNumber is only important for PCI bridges. + * Algorithm: As we descend the tree, use the last valid PCI device, + * function, and bus numbers that are discovered, and assign them + * to the PCI ID for the target device. + */ + Info = ListHead; + while (Info) + { + Status = AcpiHwGetPciDeviceInfo (PciId, Info->Device, + &BusNumber, &IsBridge); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + Info = Info->Next; + } + + ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION, + "Output PciId: Seg %4.4X Bus %4.4X Dev %4.4X Func %4.4X " + "Status %X BusNumber %X IsBridge %X\n", + PciId->Segment, PciId->Bus, PciId->Device, PciId->Function, + Status, BusNumber, IsBridge)); + + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiHwDeletePciList + * + * PARAMETERS: ListHead - Device list created by + * AcpiHwBuildPciList + * + * RETURN: None + * + * DESCRIPTION: Free the entire PCI list. + * + ******************************************************************************/ + +static void +AcpiHwDeletePciList ( + ACPI_PCI_DEVICE *ListHead) +{ + ACPI_PCI_DEVICE *Next; + ACPI_PCI_DEVICE *Previous; + + + Next = ListHead; + while (Next) + { + Previous = Next; + Next = Previous->Next; + ACPI_FREE (Previous); + } +} + + +/******************************************************************************* + * + * FUNCTION: AcpiHwGetPciDeviceInfo + * + * PARAMETERS: PciId - Initial values for the PCI ID. May be + * modified by this function. + * PciDevice - Handle for the PCI device object + * BusNumber - Where a PCI bridge bus number is returned + * IsBridge - Return value, indicates if this PCI + * device is a PCI bridge + * + * RETURN: Status + * + * DESCRIPTION: Get the device info for a single PCI device object. Get the + * _ADR (contains PCI device and function numbers), and for PCI + * bridge devices, get the bus number from PCI configuration + * space. + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiHwGetPciDeviceInfo ( + ACPI_PCI_ID *PciId, + ACPI_HANDLE PciDevice, + UINT16 *BusNumber, + BOOLEAN *IsBridge) +{ + ACPI_STATUS Status; + ACPI_OBJECT_TYPE ObjectType; + UINT64 ReturnValue; + UINT64 PciValue; + + + /* We only care about objects of type Device */ + + Status = AcpiGetType (PciDevice, &ObjectType); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + if (ObjectType != ACPI_TYPE_DEVICE) + { + return (AE_OK); + } + + /* We need an _ADR. Ignore device if not present */ + + Status = AcpiUtEvaluateNumericObject (METHOD_NAME__ADR, + PciDevice, &ReturnValue); + if (ACPI_FAILURE (Status)) + { + return (AE_OK); + } + + /* + * From _ADR, get the PCI Device and Function and + * update the PCI ID. + */ + PciId->Device = ACPI_HIWORD (ACPI_LODWORD (ReturnValue)); + PciId->Function = ACPI_LOWORD (ACPI_LODWORD (ReturnValue)); + + /* + * If the previous device was a bridge, use the previous + * device bus number + */ + if (*IsBridge) + { + PciId->Bus = *BusNumber; + } + + /* + * Get the bus numbers from PCI Config space: + * + * First, get the PCI HeaderType + */ + *IsBridge = FALSE; + Status = AcpiOsReadPciConfiguration (PciId, + PCI_CFG_HEADER_TYPE_REG, &PciValue, 8); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* We only care about bridges (1=PciBridge, 2=CardBusBridge) */ + + PciValue &= PCI_HEADER_TYPE_MASK; + + if ((PciValue != PCI_TYPE_BRIDGE) && + (PciValue != PCI_TYPE_CARDBUS_BRIDGE)) + { + return (AE_OK); + } + + /* Bridge: Get the Primary BusNumber */ + + Status = AcpiOsReadPciConfiguration (PciId, + PCI_CFG_PRIMARY_BUS_NUMBER_REG, &PciValue, 8); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + *IsBridge = TRUE; + PciId->Bus = (UINT16) PciValue; + + /* Bridge: Get the Secondary BusNumber */ + + Status = AcpiOsReadPciConfiguration (PciId, + PCI_CFG_SECONDARY_BUS_NUMBER_REG, &PciValue, 8); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + *BusNumber = (UINT16) PciValue; + return (AE_OK); +} diff --git a/source/components/hardware/hwregs.c b/source/components/hardware/hwregs.c new file mode 100644 index 0000000..6d89883 --- /dev/null +++ b/source/components/hardware/hwregs.c @@ -0,0 +1,741 @@ + +/******************************************************************************* + * + * Module Name: hwregs - Read/write access functions for the various ACPI + * control and status registers. + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2012, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#define __HWREGS_C__ + +#include "acpi.h" +#include "accommon.h" +#include "acevents.h" + +#define _COMPONENT ACPI_HARDWARE + ACPI_MODULE_NAME ("hwregs") + + +#if (!ACPI_REDUCED_HARDWARE) + +/* Local Prototypes */ + +static ACPI_STATUS +AcpiHwReadMultiple ( + UINT32 *Value, + ACPI_GENERIC_ADDRESS *RegisterA, + ACPI_GENERIC_ADDRESS *RegisterB); + +static ACPI_STATUS +AcpiHwWriteMultiple ( + UINT32 Value, + ACPI_GENERIC_ADDRESS *RegisterA, + ACPI_GENERIC_ADDRESS *RegisterB); + +#endif /* !ACPI_REDUCED_HARDWARE */ + +/****************************************************************************** + * + * FUNCTION: AcpiHwValidateRegister + * + * PARAMETERS: Reg - GAS register structure + * MaxBitWidth - Max BitWidth supported (32 or 64) + * Address - Pointer to where the gas->address + * is returned + * + * RETURN: Status + * + * DESCRIPTION: Validate the contents of a GAS register. Checks the GAS + * pointer, Address, SpaceId, BitWidth, and BitOffset. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiHwValidateRegister ( + ACPI_GENERIC_ADDRESS *Reg, + UINT8 MaxBitWidth, + UINT64 *Address) +{ + + /* Must have a valid pointer to a GAS structure */ + + if (!Reg) + { + return (AE_BAD_PARAMETER); + } + + /* + * Copy the target address. This handles possible alignment issues. + * Address must not be null. A null address also indicates an optional + * ACPI register that is not supported, so no error message. + */ + ACPI_MOVE_64_TO_64 (Address, &Reg->Address); + if (!(*Address)) + { + return (AE_BAD_ADDRESS); + } + + /* Validate the SpaceID */ + + if ((Reg->SpaceId != ACPI_ADR_SPACE_SYSTEM_MEMORY) && + (Reg->SpaceId != ACPI_ADR_SPACE_SYSTEM_IO)) + { + ACPI_ERROR ((AE_INFO, + "Unsupported address space: 0x%X", Reg->SpaceId)); + return (AE_SUPPORT); + } + + /* Validate the BitWidth */ + + if ((Reg->BitWidth != 8) && + (Reg->BitWidth != 16) && + (Reg->BitWidth != 32) && + (Reg->BitWidth != MaxBitWidth)) + { + ACPI_ERROR ((AE_INFO, + "Unsupported register bit width: 0x%X", Reg->BitWidth)); + return (AE_SUPPORT); + } + + /* Validate the BitOffset. Just a warning for now. */ + + if (Reg->BitOffset != 0) + { + ACPI_WARNING ((AE_INFO, + "Unsupported register bit offset: 0x%X", Reg->BitOffset)); + } + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiHwRead + * + * PARAMETERS: Value - Where the value is returned + * Reg - GAS register structure + * + * RETURN: Status + * + * DESCRIPTION: Read from either memory or IO space. This is a 32-bit max + * version of AcpiRead, used internally since the overhead of + * 64-bit values is not needed. + * + * LIMITATIONS: <These limitations also apply to AcpiHwWrite> + * BitWidth must be exactly 8, 16, or 32. + * SpaceID must be SystemMemory or SystemIO. + * BitOffset and AccessWidth are currently ignored, as there has + * not been a need to implement these. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiHwRead ( + UINT32 *Value, + ACPI_GENERIC_ADDRESS *Reg) +{ + UINT64 Address; + UINT64 Value64; + ACPI_STATUS Status; + + + ACPI_FUNCTION_NAME (HwRead); + + + /* Validate contents of the GAS register */ + + Status = AcpiHwValidateRegister (Reg, 32, &Address); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* Initialize entire 32-bit return value to zero */ + + *Value = 0; + + /* + * Two address spaces supported: Memory or IO. PCI_Config is + * not supported here because the GAS structure is insufficient + */ + if (Reg->SpaceId == ACPI_ADR_SPACE_SYSTEM_MEMORY) + { + Status = AcpiOsReadMemory ((ACPI_PHYSICAL_ADDRESS) + Address, &Value64, Reg->BitWidth); + + *Value = (UINT32) Value64; + } + else /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */ + { + Status = AcpiHwReadPort ((ACPI_IO_ADDRESS) + Address, Value, Reg->BitWidth); + } + + ACPI_DEBUG_PRINT ((ACPI_DB_IO, + "Read: %8.8X width %2d from %8.8X%8.8X (%s)\n", + *Value, Reg->BitWidth, ACPI_FORMAT_UINT64 (Address), + AcpiUtGetRegionName (Reg->SpaceId))); + + return (Status); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiHwWrite + * + * PARAMETERS: Value - Value to be written + * Reg - GAS register structure + * + * RETURN: Status + * + * DESCRIPTION: Write to either memory or IO space. This is a 32-bit max + * version of AcpiWrite, used internally since the overhead of + * 64-bit values is not needed. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiHwWrite ( + UINT32 Value, + ACPI_GENERIC_ADDRESS *Reg) +{ + UINT64 Address; + ACPI_STATUS Status; + + + ACPI_FUNCTION_NAME (HwWrite); + + + /* Validate contents of the GAS register */ + + Status = AcpiHwValidateRegister (Reg, 32, &Address); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* + * Two address spaces supported: Memory or IO. PCI_Config is + * not supported here because the GAS structure is insufficient + */ + if (Reg->SpaceId == ACPI_ADR_SPACE_SYSTEM_MEMORY) + { + Status = AcpiOsWriteMemory ((ACPI_PHYSICAL_ADDRESS) + Address, (UINT64) Value, Reg->BitWidth); + } + else /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */ + { + Status = AcpiHwWritePort ((ACPI_IO_ADDRESS) + Address, Value, Reg->BitWidth); + } + + ACPI_DEBUG_PRINT ((ACPI_DB_IO, + "Wrote: %8.8X width %2d to %8.8X%8.8X (%s)\n", + Value, Reg->BitWidth, ACPI_FORMAT_UINT64 (Address), + AcpiUtGetRegionName (Reg->SpaceId))); + + return (Status); +} + + +#if (!ACPI_REDUCED_HARDWARE) +/******************************************************************************* + * + * FUNCTION: AcpiHwClearAcpiStatus + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Clears all fixed and general purpose status bits + * + ******************************************************************************/ + +ACPI_STATUS +AcpiHwClearAcpiStatus ( + void) +{ + ACPI_STATUS Status; + ACPI_CPU_FLAGS LockFlags = 0; + + + ACPI_FUNCTION_TRACE (HwClearAcpiStatus); + + + ACPI_DEBUG_PRINT ((ACPI_DB_IO, "About to write %04X to %8.8X%8.8X\n", + ACPI_BITMASK_ALL_FIXED_STATUS, + ACPI_FORMAT_UINT64 (AcpiGbl_XPm1aStatus.Address))); + + LockFlags = AcpiOsAcquireLock (AcpiGbl_HardwareLock); + + /* Clear the fixed events in PM1 A/B */ + + Status = AcpiHwRegisterWrite (ACPI_REGISTER_PM1_STATUS, + ACPI_BITMASK_ALL_FIXED_STATUS); + if (ACPI_FAILURE (Status)) + { + goto UnlockAndExit; + } + + /* Clear the GPE Bits in all GPE registers in all GPE blocks */ + + Status = AcpiEvWalkGpeList (AcpiHwClearGpeBlock, NULL); + +UnlockAndExit: + AcpiOsReleaseLock (AcpiGbl_HardwareLock, LockFlags); + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiHwGetBitRegisterInfo + * + * PARAMETERS: RegisterId - Index of ACPI Register to access + * + * RETURN: The bitmask to be used when accessing the register + * + * DESCRIPTION: Map RegisterId into a register bitmask. + * + ******************************************************************************/ + +ACPI_BIT_REGISTER_INFO * +AcpiHwGetBitRegisterInfo ( + UINT32 RegisterId) +{ + ACPI_FUNCTION_ENTRY (); + + + if (RegisterId > ACPI_BITREG_MAX) + { + ACPI_ERROR ((AE_INFO, "Invalid BitRegister ID: 0x%X", RegisterId)); + return (NULL); + } + + return (&AcpiGbl_BitRegisterInfo[RegisterId]); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiHwWritePm1Control + * + * PARAMETERS: Pm1aControl - Value to be written to PM1A control + * Pm1bControl - Value to be written to PM1B control + * + * RETURN: Status + * + * DESCRIPTION: Write the PM1 A/B control registers. These registers are + * different than than the PM1 A/B status and enable registers + * in that different values can be written to the A/B registers. + * Most notably, the SLP_TYP bits can be different, as per the + * values returned from the _Sx predefined methods. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiHwWritePm1Control ( + UINT32 Pm1aControl, + UINT32 Pm1bControl) +{ + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (HwWritePm1Control); + + + Status = AcpiHwWrite (Pm1aControl, &AcpiGbl_FADT.XPm1aControlBlock); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + if (AcpiGbl_FADT.XPm1bControlBlock.Address) + { + Status = AcpiHwWrite (Pm1bControl, &AcpiGbl_FADT.XPm1bControlBlock); + } + return_ACPI_STATUS (Status); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiHwRegisterRead + * + * PARAMETERS: RegisterId - ACPI Register ID + * ReturnValue - Where the register value is returned + * + * RETURN: Status and the value read. + * + * DESCRIPTION: Read from the specified ACPI register + * + ******************************************************************************/ + +ACPI_STATUS +AcpiHwRegisterRead ( + UINT32 RegisterId, + UINT32 *ReturnValue) +{ + UINT32 Value = 0; + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (HwRegisterRead); + + + switch (RegisterId) + { + case ACPI_REGISTER_PM1_STATUS: /* PM1 A/B: 16-bit access each */ + + Status = AcpiHwReadMultiple (&Value, + &AcpiGbl_XPm1aStatus, + &AcpiGbl_XPm1bStatus); + break; + + + case ACPI_REGISTER_PM1_ENABLE: /* PM1 A/B: 16-bit access each */ + + Status = AcpiHwReadMultiple (&Value, + &AcpiGbl_XPm1aEnable, + &AcpiGbl_XPm1bEnable); + break; + + + case ACPI_REGISTER_PM1_CONTROL: /* PM1 A/B: 16-bit access each */ + + Status = AcpiHwReadMultiple (&Value, + &AcpiGbl_FADT.XPm1aControlBlock, + &AcpiGbl_FADT.XPm1bControlBlock); + + /* + * Zero the write-only bits. From the ACPI specification, "Hardware + * Write-Only Bits": "Upon reads to registers with write-only bits, + * software masks out all write-only bits." + */ + Value &= ~ACPI_PM1_CONTROL_WRITEONLY_BITS; + break; + + + case ACPI_REGISTER_PM2_CONTROL: /* 8-bit access */ + + Status = AcpiHwRead (&Value, &AcpiGbl_FADT.XPm2ControlBlock); + break; + + + case ACPI_REGISTER_PM_TIMER: /* 32-bit access */ + + Status = AcpiHwRead (&Value, &AcpiGbl_FADT.XPmTimerBlock); + break; + + + case ACPI_REGISTER_SMI_COMMAND_BLOCK: /* 8-bit access */ + + Status = AcpiHwReadPort (AcpiGbl_FADT.SmiCommand, &Value, 8); + break; + + + default: + ACPI_ERROR ((AE_INFO, "Unknown Register ID: 0x%X", + RegisterId)); + Status = AE_BAD_PARAMETER; + break; + } + + if (ACPI_SUCCESS (Status)) + { + *ReturnValue = Value; + } + + return_ACPI_STATUS (Status); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiHwRegisterWrite + * + * PARAMETERS: RegisterId - ACPI Register ID + * Value - The value to write + * + * RETURN: Status + * + * DESCRIPTION: Write to the specified ACPI register + * + * NOTE: In accordance with the ACPI specification, this function automatically + * preserves the value of the following bits, meaning that these bits cannot be + * changed via this interface: + * + * PM1_CONTROL[0] = SCI_EN + * PM1_CONTROL[9] + * PM1_STATUS[11] + * + * ACPI References: + * 1) Hardware Ignored Bits: When software writes to a register with ignored + * bit fields, it preserves the ignored bit fields + * 2) SCI_EN: OSPM always preserves this bit position + * + ******************************************************************************/ + +ACPI_STATUS +AcpiHwRegisterWrite ( + UINT32 RegisterId, + UINT32 Value) +{ + ACPI_STATUS Status; + UINT32 ReadValue; + + + ACPI_FUNCTION_TRACE (HwRegisterWrite); + + + switch (RegisterId) + { + case ACPI_REGISTER_PM1_STATUS: /* PM1 A/B: 16-bit access each */ + /* + * Handle the "ignored" bit in PM1 Status. According to the ACPI + * specification, ignored bits are to be preserved when writing. + * Normally, this would mean a read/modify/write sequence. However, + * preserving a bit in the status register is different. Writing a + * one clears the status, and writing a zero preserves the status. + * Therefore, we must always write zero to the ignored bit. + * + * This behavior is clarified in the ACPI 4.0 specification. + */ + Value &= ~ACPI_PM1_STATUS_PRESERVED_BITS; + + Status = AcpiHwWriteMultiple (Value, + &AcpiGbl_XPm1aStatus, + &AcpiGbl_XPm1bStatus); + break; + + + case ACPI_REGISTER_PM1_ENABLE: /* PM1 A/B: 16-bit access each */ + + Status = AcpiHwWriteMultiple (Value, + &AcpiGbl_XPm1aEnable, + &AcpiGbl_XPm1bEnable); + break; + + + case ACPI_REGISTER_PM1_CONTROL: /* PM1 A/B: 16-bit access each */ + + /* + * Perform a read first to preserve certain bits (per ACPI spec) + * Note: This includes SCI_EN, we never want to change this bit + */ + Status = AcpiHwReadMultiple (&ReadValue, + &AcpiGbl_FADT.XPm1aControlBlock, + &AcpiGbl_FADT.XPm1bControlBlock); + if (ACPI_FAILURE (Status)) + { + goto Exit; + } + + /* Insert the bits to be preserved */ + + ACPI_INSERT_BITS (Value, ACPI_PM1_CONTROL_PRESERVED_BITS, ReadValue); + + /* Now we can write the data */ + + Status = AcpiHwWriteMultiple (Value, + &AcpiGbl_FADT.XPm1aControlBlock, + &AcpiGbl_FADT.XPm1bControlBlock); + break; + + + case ACPI_REGISTER_PM2_CONTROL: /* 8-bit access */ + + /* + * For control registers, all reserved bits must be preserved, + * as per the ACPI spec. + */ + Status = AcpiHwRead (&ReadValue, &AcpiGbl_FADT.XPm2ControlBlock); + if (ACPI_FAILURE (Status)) + { + goto Exit; + } + + /* Insert the bits to be preserved */ + + ACPI_INSERT_BITS (Value, ACPI_PM2_CONTROL_PRESERVED_BITS, ReadValue); + + Status = AcpiHwWrite (Value, &AcpiGbl_FADT.XPm2ControlBlock); + break; + + + case ACPI_REGISTER_PM_TIMER: /* 32-bit access */ + + Status = AcpiHwWrite (Value, &AcpiGbl_FADT.XPmTimerBlock); + break; + + + case ACPI_REGISTER_SMI_COMMAND_BLOCK: /* 8-bit access */ + + /* SMI_CMD is currently always in IO space */ + + Status = AcpiHwWritePort (AcpiGbl_FADT.SmiCommand, Value, 8); + break; + + + default: + ACPI_ERROR ((AE_INFO, "Unknown Register ID: 0x%X", + RegisterId)); + Status = AE_BAD_PARAMETER; + break; + } + +Exit: + return_ACPI_STATUS (Status); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiHwReadMultiple + * + * PARAMETERS: Value - Where the register value is returned + * RegisterA - First ACPI register (required) + * RegisterB - Second ACPI register (optional) + * + * RETURN: Status + * + * DESCRIPTION: Read from the specified two-part ACPI register (such as PM1 A/B) + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiHwReadMultiple ( + UINT32 *Value, + ACPI_GENERIC_ADDRESS *RegisterA, + ACPI_GENERIC_ADDRESS *RegisterB) +{ + UINT32 ValueA = 0; + UINT32 ValueB = 0; + ACPI_STATUS Status; + + + /* The first register is always required */ + + Status = AcpiHwRead (&ValueA, RegisterA); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* Second register is optional */ + + if (RegisterB->Address) + { + Status = AcpiHwRead (&ValueB, RegisterB); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + } + + /* + * OR the two return values together. No shifting or masking is necessary, + * because of how the PM1 registers are defined in the ACPI specification: + * + * "Although the bits can be split between the two register blocks (each + * register block has a unique pointer within the FADT), the bit positions + * are maintained. The register block with unimplemented bits (that is, + * those implemented in the other register block) always returns zeros, + * and writes have no side effects" + */ + *Value = (ValueA | ValueB); + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiHwWriteMultiple + * + * PARAMETERS: Value - The value to write + * RegisterA - First ACPI register (required) + * RegisterB - Second ACPI register (optional) + * + * RETURN: Status + * + * DESCRIPTION: Write to the specified two-part ACPI register (such as PM1 A/B) + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiHwWriteMultiple ( + UINT32 Value, + ACPI_GENERIC_ADDRESS *RegisterA, + ACPI_GENERIC_ADDRESS *RegisterB) +{ + ACPI_STATUS Status; + + + /* The first register is always required */ + + Status = AcpiHwWrite (Value, RegisterA); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* + * Second register is optional + * + * No bit shifting or clearing is necessary, because of how the PM1 + * registers are defined in the ACPI specification: + * + * "Although the bits can be split between the two register blocks (each + * register block has a unique pointer within the FADT), the bit positions + * are maintained. The register block with unimplemented bits (that is, + * those implemented in the other register block) always returns zeros, + * and writes have no side effects" + */ + if (RegisterB->Address) + { + Status = AcpiHwWrite (Value, RegisterB); + } + + return (Status); +} + +#endif /* !ACPI_REDUCED_HARDWARE */ diff --git a/source/components/hardware/hwsleep.c b/source/components/hardware/hwsleep.c new file mode 100644 index 0000000..0d31143 --- /dev/null +++ b/source/components/hardware/hwsleep.c @@ -0,0 +1,384 @@ +/****************************************************************************** + * + * Name: hwsleep.c - ACPI Hardware Sleep/Wake Support functions for the + * original/legacy sleep/PM registers. + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2012, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" + +#define _COMPONENT ACPI_HARDWARE + ACPI_MODULE_NAME ("hwsleep") + + +#if (!ACPI_REDUCED_HARDWARE) /* Entire module */ +/******************************************************************************* + * + * FUNCTION: AcpiHwLegacySleep + * + * PARAMETERS: SleepState - Which sleep state to enter + * + * RETURN: Status + * + * DESCRIPTION: Enter a system sleep state via the legacy FADT PM registers + * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED + * + ******************************************************************************/ + +ACPI_STATUS +AcpiHwLegacySleep ( + UINT8 SleepState) +{ + ACPI_BIT_REGISTER_INFO *SleepTypeRegInfo; + ACPI_BIT_REGISTER_INFO *SleepEnableRegInfo; + UINT32 Pm1aControl; + UINT32 Pm1bControl; + UINT32 InValue; + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (HwLegacySleep); + + + SleepTypeRegInfo = AcpiHwGetBitRegisterInfo (ACPI_BITREG_SLEEP_TYPE); + SleepEnableRegInfo = AcpiHwGetBitRegisterInfo (ACPI_BITREG_SLEEP_ENABLE); + + /* Clear wake status */ + + Status = AcpiWriteBitRegister (ACPI_BITREG_WAKE_STATUS, ACPI_CLEAR_STATUS); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* Clear all fixed and general purpose status bits */ + + Status = AcpiHwClearAcpiStatus (); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + if (SleepState != ACPI_STATE_S5) + { + /* + * Disable BM arbitration. This feature is contained within an + * optional register (PM2 Control), so ignore a BAD_ADDRESS + * exception. + */ + Status = AcpiWriteBitRegister (ACPI_BITREG_ARB_DISABLE, 1); + if (ACPI_FAILURE (Status) && (Status != AE_BAD_ADDRESS)) + { + return_ACPI_STATUS (Status); + } + } + + /* + * 1) Disable/Clear all GPEs + * 2) Enable all wakeup GPEs + */ + Status = AcpiHwDisableAllGpes (); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + AcpiGbl_SystemAwakeAndRunning = FALSE; + + Status = AcpiHwEnableAllWakeupGpes (); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* Execute the _GTS method (Going To Sleep) */ + + AcpiHwExecuteSleepMethod (METHOD_NAME__GTS, SleepState); + + /* Get current value of PM1A control */ + + Status = AcpiHwRegisterRead (ACPI_REGISTER_PM1_CONTROL, + &Pm1aControl); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + ACPI_DEBUG_PRINT ((ACPI_DB_INIT, + "Entering sleep state [S%u]\n", SleepState)); + + /* Clear the SLP_EN and SLP_TYP fields */ + + Pm1aControl &= ~(SleepTypeRegInfo->AccessBitMask | + SleepEnableRegInfo->AccessBitMask); + Pm1bControl = Pm1aControl; + + /* Insert the SLP_TYP bits */ + + Pm1aControl |= (AcpiGbl_SleepTypeA << SleepTypeRegInfo->BitPosition); + Pm1bControl |= (AcpiGbl_SleepTypeB << SleepTypeRegInfo->BitPosition); + + /* + * We split the writes of SLP_TYP and SLP_EN to workaround + * poorly implemented hardware. + */ + + /* Write #1: write the SLP_TYP data to the PM1 Control registers */ + + Status = AcpiHwWritePm1Control (Pm1aControl, Pm1bControl); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* Insert the sleep enable (SLP_EN) bit */ + + Pm1aControl |= SleepEnableRegInfo->AccessBitMask; + Pm1bControl |= SleepEnableRegInfo->AccessBitMask; + + /* Flush caches, as per ACPI specification */ + + ACPI_FLUSH_CPU_CACHE (); + + /* Write #2: Write both SLP_TYP + SLP_EN */ + + Status = AcpiHwWritePm1Control (Pm1aControl, Pm1bControl); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + if (SleepState > ACPI_STATE_S3) + { + /* + * We wanted to sleep > S3, but it didn't happen (by virtue of the + * fact that we are still executing!) + * + * Wait ten seconds, then try again. This is to get S4/S5 to work on + * all machines. + * + * We wait so long to allow chipsets that poll this reg very slowly + * to still read the right value. Ideally, this block would go + * away entirely. + */ + AcpiOsStall (10000000); + + Status = AcpiHwRegisterWrite (ACPI_REGISTER_PM1_CONTROL, + SleepEnableRegInfo->AccessBitMask); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + } + + /* Wait for transition back to Working State */ + + do + { + Status = AcpiReadBitRegister (ACPI_BITREG_WAKE_STATUS, &InValue); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + } while (!InValue); + + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiHwLegacyWakePrep + * + * PARAMETERS: SleepState - Which sleep state we just exited + * + * RETURN: Status + * + * DESCRIPTION: Perform the first state of OS-independent ACPI cleanup after a + * sleep. + * Called with interrupts ENABLED. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiHwLegacyWakePrep ( + UINT8 SleepState) +{ + ACPI_STATUS Status; + ACPI_BIT_REGISTER_INFO *SleepTypeRegInfo; + ACPI_BIT_REGISTER_INFO *SleepEnableRegInfo; + UINT32 Pm1aControl; + UINT32 Pm1bControl; + + + ACPI_FUNCTION_TRACE (HwLegacyWakePrep); + + /* + * Set SLP_TYPE and SLP_EN to state S0. + * This is unclear from the ACPI Spec, but it is required + * by some machines. + */ + Status = AcpiGetSleepTypeData (ACPI_STATE_S0, + &AcpiGbl_SleepTypeA, &AcpiGbl_SleepTypeB); + if (ACPI_SUCCESS (Status)) + { + SleepTypeRegInfo = + AcpiHwGetBitRegisterInfo (ACPI_BITREG_SLEEP_TYPE); + SleepEnableRegInfo = + AcpiHwGetBitRegisterInfo (ACPI_BITREG_SLEEP_ENABLE); + + /* Get current value of PM1A control */ + + Status = AcpiHwRegisterRead (ACPI_REGISTER_PM1_CONTROL, + &Pm1aControl); + if (ACPI_SUCCESS (Status)) + { + /* Clear the SLP_EN and SLP_TYP fields */ + + Pm1aControl &= ~(SleepTypeRegInfo->AccessBitMask | + SleepEnableRegInfo->AccessBitMask); + Pm1bControl = Pm1aControl; + + /* Insert the SLP_TYP bits */ + + Pm1aControl |= (AcpiGbl_SleepTypeA << + SleepTypeRegInfo->BitPosition); + Pm1bControl |= (AcpiGbl_SleepTypeB << + SleepTypeRegInfo->BitPosition); + + /* Write the control registers and ignore any errors */ + + (void) AcpiHwWritePm1Control (Pm1aControl, Pm1bControl); + } + } + + AcpiHwExecuteSleepMethod (METHOD_NAME__BFS, SleepState); + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiHwLegacyWake + * + * PARAMETERS: SleepState - Which sleep state we just exited + * + * RETURN: Status + * + * DESCRIPTION: Perform OS-independent ACPI cleanup after a sleep + * Called with interrupts ENABLED. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiHwLegacyWake ( + UINT8 SleepState) +{ + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (HwLegacyWake); + + + /* Ensure EnterSleepStatePrep -> EnterSleepState ordering */ + + AcpiGbl_SleepTypeA = ACPI_SLEEP_TYPE_INVALID; + AcpiHwExecuteSleepMethod (METHOD_NAME__SST, ACPI_SST_WAKING); + + /* + * GPEs must be enabled before _WAK is called as GPEs + * might get fired there + * + * Restore the GPEs: + * 1) Disable/Clear all GPEs + * 2) Enable all runtime GPEs + */ + Status = AcpiHwDisableAllGpes (); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + Status = AcpiHwEnableAllRuntimeGpes (); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* + * Now we can execute _WAK, etc. Some machines require that the GPEs + * are enabled before the wake methods are executed. + */ + AcpiHwExecuteSleepMethod (METHOD_NAME__WAK, SleepState); + + /* + * Some BIOS code assumes that WAK_STS will be cleared on resume + * and use it to determine whether the system is rebooting or + * resuming. Clear WAK_STS for compatibility. + */ + (void) AcpiWriteBitRegister (ACPI_BITREG_WAKE_STATUS, ACPI_CLEAR_STATUS); + AcpiGbl_SystemAwakeAndRunning = TRUE; + + /* Enable power button */ + + (void) AcpiWriteBitRegister( + AcpiGbl_FixedEventInfo[ACPI_EVENT_POWER_BUTTON].EnableRegisterId, + ACPI_ENABLE_EVENT); + + (void) AcpiWriteBitRegister( + AcpiGbl_FixedEventInfo[ACPI_EVENT_POWER_BUTTON].StatusRegisterId, + ACPI_CLEAR_STATUS); + + /* + * Enable BM arbitration. This feature is contained within an + * optional register (PM2 Control), so ignore a BAD_ADDRESS + * exception. + */ + Status = AcpiWriteBitRegister (ACPI_BITREG_ARB_DISABLE, 0); + if (ACPI_FAILURE (Status) && (Status != AE_BAD_ADDRESS)) + { + return_ACPI_STATUS (Status); + } + + AcpiHwExecuteSleepMethod (METHOD_NAME__SST, ACPI_SST_WORKING); + return_ACPI_STATUS (Status); +} + +#endif /* !ACPI_REDUCED_HARDWARE */ diff --git a/source/components/hardware/hwtimer.c b/source/components/hardware/hwtimer.c new file mode 100644 index 0000000..15dc58f --- /dev/null +++ b/source/components/hardware/hwtimer.c @@ -0,0 +1,218 @@ + +/****************************************************************************** + * + * Name: hwtimer.c - ACPI Power Management Timer Interface + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2012, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" + +#define _COMPONENT ACPI_HARDWARE + ACPI_MODULE_NAME ("hwtimer") + + +#if (!ACPI_REDUCED_HARDWARE) /* Entire module */ +/****************************************************************************** + * + * FUNCTION: AcpiGetTimerResolution + * + * PARAMETERS: Resolution - Where the resolution is returned + * + * RETURN: Status and timer resolution + * + * DESCRIPTION: Obtains resolution of the ACPI PM Timer (24 or 32 bits). + * + ******************************************************************************/ + +ACPI_STATUS +AcpiGetTimerResolution ( + UINT32 *Resolution) +{ + ACPI_FUNCTION_TRACE (AcpiGetTimerResolution); + + + if (!Resolution) + { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + if ((AcpiGbl_FADT.Flags & ACPI_FADT_32BIT_TIMER) == 0) + { + *Resolution = 24; + } + else + { + *Resolution = 32; + } + + return_ACPI_STATUS (AE_OK); +} + +ACPI_EXPORT_SYMBOL (AcpiGetTimerResolution) + + +/****************************************************************************** + * + * FUNCTION: AcpiGetTimer + * + * PARAMETERS: Ticks - Where the timer value is returned + * + * RETURN: Status and current timer value (ticks) + * + * DESCRIPTION: Obtains current value of ACPI PM Timer (in ticks). + * + ******************************************************************************/ + +ACPI_STATUS +AcpiGetTimer ( + UINT32 *Ticks) +{ + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (AcpiGetTimer); + + + if (!Ticks) + { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + Status = AcpiHwRead (Ticks, &AcpiGbl_FADT.XPmTimerBlock); + + return_ACPI_STATUS (Status); +} + +ACPI_EXPORT_SYMBOL (AcpiGetTimer) + + +/****************************************************************************** + * + * FUNCTION: AcpiGetTimerDuration + * + * PARAMETERS: StartTicks - Starting timestamp + * EndTicks - End timestamp + * TimeElapsed - Where the elapsed time is returned + * + * RETURN: Status and TimeElapsed + * + * DESCRIPTION: Computes the time elapsed (in microseconds) between two + * PM Timer time stamps, taking into account the possibility of + * rollovers, the timer resolution, and timer frequency. + * + * The PM Timer's clock ticks at roughly 3.6 times per + * _microsecond_, and its clock continues through Cx state + * transitions (unlike many CPU timestamp counters) -- making it + * a versatile and accurate timer. + * + * Note that this function accommodates only a single timer + * rollover. Thus for 24-bit timers, this function should only + * be used for calculating durations less than ~4.6 seconds + * (~20 minutes for 32-bit timers) -- calculations below: + * + * 2**24 Ticks / 3,600,000 Ticks/Sec = 4.66 sec + * 2**32 Ticks / 3,600,000 Ticks/Sec = 1193 sec or 19.88 minutes + * + ******************************************************************************/ + +ACPI_STATUS +AcpiGetTimerDuration ( + UINT32 StartTicks, + UINT32 EndTicks, + UINT32 *TimeElapsed) +{ + ACPI_STATUS Status; + UINT32 DeltaTicks; + UINT64 Quotient; + + + ACPI_FUNCTION_TRACE (AcpiGetTimerDuration); + + + if (!TimeElapsed) + { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + /* + * Compute Tick Delta: + * Handle (max one) timer rollovers on 24-bit versus 32-bit timers. + */ + if (StartTicks < EndTicks) + { + DeltaTicks = EndTicks - StartTicks; + } + else if (StartTicks > EndTicks) + { + if ((AcpiGbl_FADT.Flags & ACPI_FADT_32BIT_TIMER) == 0) + { + /* 24-bit Timer */ + + DeltaTicks = (((0x00FFFFFF - StartTicks) + EndTicks) & 0x00FFFFFF); + } + else + { + /* 32-bit Timer */ + + DeltaTicks = (0xFFFFFFFF - StartTicks) + EndTicks; + } + } + else /* StartTicks == EndTicks */ + { + *TimeElapsed = 0; + return_ACPI_STATUS (AE_OK); + } + + /* + * Compute Duration (Requires a 64-bit multiply and divide): + * + * TimeElapsed = (DeltaTicks * 1000000) / PM_TIMER_FREQUENCY; + */ + Status = AcpiUtShortDivide (((UINT64) DeltaTicks) * 1000000, + PM_TIMER_FREQUENCY, &Quotient, NULL); + + *TimeElapsed = (UINT32) Quotient; + return_ACPI_STATUS (Status); +} + +ACPI_EXPORT_SYMBOL (AcpiGetTimerDuration) + +#endif /* !ACPI_REDUCED_HARDWARE */ diff --git a/source/components/hardware/hwvalid.c b/source/components/hardware/hwvalid.c new file mode 100644 index 0000000..4462434 --- /dev/null +++ b/source/components/hardware/hwvalid.c @@ -0,0 +1,368 @@ + +/****************************************************************************** + * + * Module Name: hwvalid - I/O request validation + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2012, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#define __HWVALID_C__ + +#include "acpi.h" +#include "accommon.h" + +#define _COMPONENT ACPI_HARDWARE + ACPI_MODULE_NAME ("hwvalid") + +/* Local prototypes */ + +static ACPI_STATUS +AcpiHwValidateIoRequest ( + ACPI_IO_ADDRESS Address, + UINT32 BitWidth); + + +/* + * Protected I/O ports. Some ports are always illegal, and some are + * conditionally illegal. This table must remain ordered by port address. + * + * The table is used to implement the Microsoft port access rules that + * first appeared in Windows XP. Some ports are always illegal, and some + * ports are only illegal if the BIOS calls _OSI with a WinXP string or + * later (meaning that the BIOS itelf is post-XP.) + * + * This provides ACPICA with the desired port protections and + * Microsoft compatibility. + * + * Description of port entries: + * DMA: DMA controller + * PIC0: Programmable Interrupt Controller (8259A) + * PIT1: System Timer 1 + * PIT2: System Timer 2 failsafe + * RTC: Real-time clock + * CMOS: Extended CMOS + * DMA1: DMA 1 page registers + * DMA1L: DMA 1 Ch 0 low page + * DMA2: DMA 2 page registers + * DMA2L: DMA 2 low page refresh + * ARBC: Arbitration control + * SETUP: Reserved system board setup + * POS: POS channel select + * PIC1: Cascaded PIC + * IDMA: ISA DMA + * ELCR: PIC edge/level registers + * PCI: PCI configuration space + */ +static const ACPI_PORT_INFO AcpiProtectedPorts[] = +{ + {"DMA", 0x0000, 0x000F, ACPI_OSI_WIN_XP}, + {"PIC0", 0x0020, 0x0021, ACPI_ALWAYS_ILLEGAL}, + {"PIT1", 0x0040, 0x0043, ACPI_OSI_WIN_XP}, + {"PIT2", 0x0048, 0x004B, ACPI_OSI_WIN_XP}, + {"RTC", 0x0070, 0x0071, ACPI_OSI_WIN_XP}, + {"CMOS", 0x0074, 0x0076, ACPI_OSI_WIN_XP}, + {"DMA1", 0x0081, 0x0083, ACPI_OSI_WIN_XP}, + {"DMA1L", 0x0087, 0x0087, ACPI_OSI_WIN_XP}, + {"DMA2", 0x0089, 0x008B, ACPI_OSI_WIN_XP}, + {"DMA2L", 0x008F, 0x008F, ACPI_OSI_WIN_XP}, + {"ARBC", 0x0090, 0x0091, ACPI_OSI_WIN_XP}, + {"SETUP", 0x0093, 0x0094, ACPI_OSI_WIN_XP}, + {"POS", 0x0096, 0x0097, ACPI_OSI_WIN_XP}, + {"PIC1", 0x00A0, 0x00A1, ACPI_ALWAYS_ILLEGAL}, + {"IDMA", 0x00C0, 0x00DF, ACPI_OSI_WIN_XP}, + {"ELCR", 0x04D0, 0x04D1, ACPI_ALWAYS_ILLEGAL}, + {"PCI", 0x0CF8, 0x0CFF, ACPI_OSI_WIN_XP} +}; + +#define ACPI_PORT_INFO_ENTRIES ACPI_ARRAY_LENGTH (AcpiProtectedPorts) + + +/****************************************************************************** + * + * FUNCTION: AcpiHwValidateIoRequest + * + * PARAMETERS: Address Address of I/O port/register + * BitWidth Number of bits (8,16,32) + * + * RETURN: Status + * + * DESCRIPTION: Validates an I/O request (address/length). Certain ports are + * always illegal and some ports are only illegal depending on + * the requests the BIOS AML code makes to the predefined + * _OSI method. + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiHwValidateIoRequest ( + ACPI_IO_ADDRESS Address, + UINT32 BitWidth) +{ + UINT32 i; + UINT32 ByteWidth; + ACPI_IO_ADDRESS LastAddress; + const ACPI_PORT_INFO *PortInfo; + + + ACPI_FUNCTION_TRACE (HwValidateIoRequest); + + + /* Supported widths are 8/16/32 */ + + if ((BitWidth != 8) && + (BitWidth != 16) && + (BitWidth != 32)) + { + ACPI_ERROR ((AE_INFO, + "Bad BitWidth parameter: %8.8X", BitWidth)); + return (AE_BAD_PARAMETER); + } + + PortInfo = AcpiProtectedPorts; + ByteWidth = ACPI_DIV_8 (BitWidth); + LastAddress = Address + ByteWidth - 1; + + ACPI_DEBUG_PRINT ((ACPI_DB_IO, "Address %p LastAddress %p Length %X", + ACPI_CAST_PTR (void, Address), ACPI_CAST_PTR (void, LastAddress), + ByteWidth)); + + /* Maximum 16-bit address in I/O space */ + + if (LastAddress > ACPI_UINT16_MAX) + { + ACPI_ERROR ((AE_INFO, + "Illegal I/O port address/length above 64K: %p/0x%X", + ACPI_CAST_PTR (void, Address), ByteWidth)); + return_ACPI_STATUS (AE_LIMIT); + } + + /* Exit if requested address is not within the protected port table */ + + if (Address > AcpiProtectedPorts[ACPI_PORT_INFO_ENTRIES - 1].End) + { + return_ACPI_STATUS (AE_OK); + } + + /* Check request against the list of protected I/O ports */ + + for (i = 0; i < ACPI_PORT_INFO_ENTRIES; i++, PortInfo++) + { + /* + * Check if the requested address range will write to a reserved + * port. Four cases to consider: + * + * 1) Address range is contained completely in the port address range + * 2) Address range overlaps port range at the port range start + * 3) Address range overlaps port range at the port range end + * 4) Address range completely encompasses the port range + */ + if ((Address <= PortInfo->End) && (LastAddress >= PortInfo->Start)) + { + /* Port illegality may depend on the _OSI calls made by the BIOS */ + + if (AcpiGbl_OsiData >= PortInfo->OsiDependency) + { + ACPI_DEBUG_PRINT ((ACPI_DB_IO, + "Denied AML access to port 0x%p/%X (%s 0x%.4X-0x%.4X)", + ACPI_CAST_PTR (void, Address), ByteWidth, PortInfo->Name, + PortInfo->Start, PortInfo->End)); + + return_ACPI_STATUS (AE_AML_ILLEGAL_ADDRESS); + } + } + + /* Finished if address range ends before the end of this port */ + + if (LastAddress <= PortInfo->End) + { + break; + } + } + + return_ACPI_STATUS (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiHwReadPort + * + * PARAMETERS: Address Address of I/O port/register to read + * Value Where value is placed + * Width Number of bits + * + * RETURN: Status and value read from port + * + * DESCRIPTION: Read data from an I/O port or register. This is a front-end + * to AcpiOsReadPort that performs validation on both the port + * address and the length. + * + *****************************************************************************/ + +ACPI_STATUS +AcpiHwReadPort ( + ACPI_IO_ADDRESS Address, + UINT32 *Value, + UINT32 Width) +{ + ACPI_STATUS Status; + UINT32 OneByte; + UINT32 i; + + + /* Truncate address to 16 bits if requested */ + + if (AcpiGbl_TruncateIoAddresses) + { + Address &= ACPI_UINT16_MAX; + } + + /* Validate the entire request and perform the I/O */ + + Status = AcpiHwValidateIoRequest (Address, Width); + if (ACPI_SUCCESS (Status)) + { + Status = AcpiOsReadPort (Address, Value, Width); + return (Status); + } + + if (Status != AE_AML_ILLEGAL_ADDRESS) + { + return (Status); + } + + /* + * There has been a protection violation within the request. Fall + * back to byte granularity port I/O and ignore the failing bytes. + * This provides Windows compatibility. + */ + for (i = 0, *Value = 0; i < Width; i += 8) + { + /* Validate and read one byte */ + + if (AcpiHwValidateIoRequest (Address, 8) == AE_OK) + { + Status = AcpiOsReadPort (Address, &OneByte, 8); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + *Value |= (OneByte << i); + } + + Address++; + } + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: AcpiHwWritePort + * + * PARAMETERS: Address Address of I/O port/register to write + * Value Value to write + * Width Number of bits + * + * RETURN: Status + * + * DESCRIPTION: Write data to an I/O port or register. This is a front-end + * to AcpiOsWritePort that performs validation on both the port + * address and the length. + * + *****************************************************************************/ + +ACPI_STATUS +AcpiHwWritePort ( + ACPI_IO_ADDRESS Address, + UINT32 Value, + UINT32 Width) +{ + ACPI_STATUS Status; + UINT32 i; + + + /* Truncate address to 16 bits if requested */ + + if (AcpiGbl_TruncateIoAddresses) + { + Address &= ACPI_UINT16_MAX; + } + + /* Validate the entire request and perform the I/O */ + + Status = AcpiHwValidateIoRequest (Address, Width); + if (ACPI_SUCCESS (Status)) + { + Status = AcpiOsWritePort (Address, Value, Width); + return (Status); + } + + if (Status != AE_AML_ILLEGAL_ADDRESS) + { + return (Status); + } + + /* + * There has been a protection violation within the request. Fall + * back to byte granularity port I/O and ignore the failing bytes. + * This provides Windows compatibility. + */ + for (i = 0; i < Width; i += 8) + { + /* Validate and write one byte */ + + if (AcpiHwValidateIoRequest (Address, 8) == AE_OK) + { + Status = AcpiOsWritePort (Address, (Value >> i) & 0xFF, 8); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + } + + Address++; + } + + return (AE_OK); +} + + diff --git a/source/components/hardware/hwxface.c b/source/components/hardware/hwxface.c new file mode 100644 index 0000000..3fec9b5 --- /dev/null +++ b/source/components/hardware/hwxface.c @@ -0,0 +1,617 @@ + +/****************************************************************************** + * + * Module Name: hwxface - Public ACPICA hardware interfaces + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2012, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" +#include "acnamesp.h" + +#define _COMPONENT ACPI_HARDWARE + ACPI_MODULE_NAME ("hwxface") + + +/****************************************************************************** + * + * FUNCTION: AcpiReset + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Set reset register in memory or IO space. Note: Does not + * support reset register in PCI config space, this must be + * handled separately. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiReset ( + void) +{ + ACPI_GENERIC_ADDRESS *ResetReg; + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (AcpiReset); + + + ResetReg = &AcpiGbl_FADT.ResetRegister; + + /* Check if the reset register is supported */ + + if (!(AcpiGbl_FADT.Flags & ACPI_FADT_RESET_REGISTER) || + !ResetReg->Address) + { + return_ACPI_STATUS (AE_NOT_EXIST); + } + + if (ResetReg->SpaceId == ACPI_ADR_SPACE_SYSTEM_IO) + { + /* + * For I/O space, write directly to the OSL. This bypasses the port + * validation mechanism, which may block a valid write to the reset + * register. + */ + Status = AcpiOsWritePort ((ACPI_IO_ADDRESS) ResetReg->Address, + AcpiGbl_FADT.ResetValue, ResetReg->BitWidth); + } + else + { + /* Write the reset value to the reset register */ + + Status = AcpiHwWrite (AcpiGbl_FADT.ResetValue, ResetReg); + } + + return_ACPI_STATUS (Status); +} + +ACPI_EXPORT_SYMBOL (AcpiReset) + + +/****************************************************************************** + * + * FUNCTION: AcpiRead + * + * PARAMETERS: Value - Where the value is returned + * Reg - GAS register structure + * + * RETURN: Status + * + * DESCRIPTION: Read from either memory or IO space. + * + * LIMITATIONS: <These limitations also apply to AcpiWrite> + * BitWidth must be exactly 8, 16, 32, or 64. + * SpaceID must be SystemMemory or SystemIO. + * BitOffset and AccessWidth are currently ignored, as there has + * not been a need to implement these. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiRead ( + UINT64 *ReturnValue, + ACPI_GENERIC_ADDRESS *Reg) +{ + UINT32 Value; + UINT32 Width; + UINT64 Address; + ACPI_STATUS Status; + + + ACPI_FUNCTION_NAME (AcpiRead); + + + if (!ReturnValue) + { + return (AE_BAD_PARAMETER); + } + + /* Validate contents of the GAS register. Allow 64-bit transfers */ + + Status = AcpiHwValidateRegister (Reg, 64, &Address); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* Initialize entire 64-bit return value to zero */ + + *ReturnValue = 0; + Value = 0; + + /* + * Two address spaces supported: Memory or IO. PCI_Config is + * not supported here because the GAS structure is insufficient + */ + if (Reg->SpaceId == ACPI_ADR_SPACE_SYSTEM_MEMORY) + { + Status = AcpiOsReadMemory ((ACPI_PHYSICAL_ADDRESS) + Address, ReturnValue, Reg->BitWidth); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + } + else /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */ + { + Width = Reg->BitWidth; + if (Width == 64) + { + Width = 32; /* Break into two 32-bit transfers */ + } + + Status = AcpiHwReadPort ((ACPI_IO_ADDRESS) + Address, &Value, Width); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + *ReturnValue = Value; + + if (Reg->BitWidth == 64) + { + /* Read the top 32 bits */ + + Status = AcpiHwReadPort ((ACPI_IO_ADDRESS) + (Address + 4), &Value, 32); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + *ReturnValue |= ((UINT64) Value << 32); + } + } + + ACPI_DEBUG_PRINT ((ACPI_DB_IO, + "Read: %8.8X%8.8X width %2d from %8.8X%8.8X (%s)\n", + ACPI_FORMAT_UINT64 (*ReturnValue), Reg->BitWidth, + ACPI_FORMAT_UINT64 (Address), + AcpiUtGetRegionName (Reg->SpaceId))); + + return (Status); +} + +ACPI_EXPORT_SYMBOL (AcpiRead) + + +/****************************************************************************** + * + * FUNCTION: AcpiWrite + * + * PARAMETERS: Value - Value to be written + * Reg - GAS register structure + * + * RETURN: Status + * + * DESCRIPTION: Write to either memory or IO space. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiWrite ( + UINT64 Value, + ACPI_GENERIC_ADDRESS *Reg) +{ + UINT32 Width; + UINT64 Address; + ACPI_STATUS Status; + + + ACPI_FUNCTION_NAME (AcpiWrite); + + + /* Validate contents of the GAS register. Allow 64-bit transfers */ + + Status = AcpiHwValidateRegister (Reg, 64, &Address); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + /* + * Two address spaces supported: Memory or IO. PCI_Config is + * not supported here because the GAS structure is insufficient + */ + if (Reg->SpaceId == ACPI_ADR_SPACE_SYSTEM_MEMORY) + { + Status = AcpiOsWriteMemory ((ACPI_PHYSICAL_ADDRESS) + Address, Value, Reg->BitWidth); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + } + else /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */ + { + Width = Reg->BitWidth; + if (Width == 64) + { + Width = 32; /* Break into two 32-bit transfers */ + } + + Status = AcpiHwWritePort ((ACPI_IO_ADDRESS) + Address, ACPI_LODWORD (Value), Width); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + + if (Reg->BitWidth == 64) + { + Status = AcpiHwWritePort ((ACPI_IO_ADDRESS) + (Address + 4), ACPI_HIDWORD (Value), 32); + if (ACPI_FAILURE (Status)) + { + return (Status); + } + } + } + + ACPI_DEBUG_PRINT ((ACPI_DB_IO, + "Wrote: %8.8X%8.8X width %2d to %8.8X%8.8X (%s)\n", + ACPI_FORMAT_UINT64 (Value), Reg->BitWidth, + ACPI_FORMAT_UINT64 (Address), + AcpiUtGetRegionName (Reg->SpaceId))); + + return (Status); +} + +ACPI_EXPORT_SYMBOL (AcpiWrite) + + +#if (!ACPI_REDUCED_HARDWARE) +/******************************************************************************* + * + * FUNCTION: AcpiReadBitRegister + * + * PARAMETERS: RegisterId - ID of ACPI Bit Register to access + * ReturnValue - Value that was read from the register, + * normalized to bit position zero. + * + * RETURN: Status and the value read from the specified Register. Value + * returned is normalized to bit0 (is shifted all the way right) + * + * DESCRIPTION: ACPI BitRegister read function. Does not acquire the HW lock. + * + * SUPPORTS: Bit fields in PM1 Status, PM1 Enable, PM1 Control, and + * PM2 Control. + * + * Note: The hardware lock is not required when reading the ACPI bit registers + * since almost all of them are single bit and it does not matter that + * the parent hardware register can be split across two physical + * registers. The only multi-bit field is SLP_TYP in the PM1 control + * register, but this field does not cross an 8-bit boundary (nor does + * it make much sense to actually read this field.) + * + ******************************************************************************/ + +ACPI_STATUS +AcpiReadBitRegister ( + UINT32 RegisterId, + UINT32 *ReturnValue) +{ + ACPI_BIT_REGISTER_INFO *BitRegInfo; + UINT32 RegisterValue; + UINT32 Value; + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE_U32 (AcpiReadBitRegister, RegisterId); + + + /* Get the info structure corresponding to the requested ACPI Register */ + + BitRegInfo = AcpiHwGetBitRegisterInfo (RegisterId); + if (!BitRegInfo) + { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + /* Read the entire parent register */ + + Status = AcpiHwRegisterRead (BitRegInfo->ParentRegister, + &RegisterValue); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* Normalize the value that was read, mask off other bits */ + + Value = ((RegisterValue & BitRegInfo->AccessBitMask) + >> BitRegInfo->BitPosition); + + ACPI_DEBUG_PRINT ((ACPI_DB_IO, + "BitReg %X, ParentReg %X, Actual %8.8X, ReturnValue %8.8X\n", + RegisterId, BitRegInfo->ParentRegister, RegisterValue, Value)); + + *ReturnValue = Value; + return_ACPI_STATUS (AE_OK); +} + +ACPI_EXPORT_SYMBOL (AcpiReadBitRegister) + + +/******************************************************************************* + * + * FUNCTION: AcpiWriteBitRegister + * + * PARAMETERS: RegisterId - ID of ACPI Bit Register to access + * Value - Value to write to the register, in bit + * position zero. The bit is automaticallly + * shifted to the correct position. + * + * RETURN: Status + * + * DESCRIPTION: ACPI Bit Register write function. Acquires the hardware lock + * since most operations require a read/modify/write sequence. + * + * SUPPORTS: Bit fields in PM1 Status, PM1 Enable, PM1 Control, and + * PM2 Control. + * + * Note that at this level, the fact that there may be actually two + * hardware registers (A and B - and B may not exist) is abstracted. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiWriteBitRegister ( + UINT32 RegisterId, + UINT32 Value) +{ + ACPI_BIT_REGISTER_INFO *BitRegInfo; + ACPI_CPU_FLAGS LockFlags; + UINT32 RegisterValue; + ACPI_STATUS Status = AE_OK; + + + ACPI_FUNCTION_TRACE_U32 (AcpiWriteBitRegister, RegisterId); + + + /* Get the info structure corresponding to the requested ACPI Register */ + + BitRegInfo = AcpiHwGetBitRegisterInfo (RegisterId); + if (!BitRegInfo) + { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + LockFlags = AcpiOsAcquireLock (AcpiGbl_HardwareLock); + + /* + * At this point, we know that the parent register is one of the + * following: PM1 Status, PM1 Enable, PM1 Control, or PM2 Control + */ + if (BitRegInfo->ParentRegister != ACPI_REGISTER_PM1_STATUS) + { + /* + * 1) Case for PM1 Enable, PM1 Control, and PM2 Control + * + * Perform a register read to preserve the bits that we are not + * interested in + */ + Status = AcpiHwRegisterRead (BitRegInfo->ParentRegister, + &RegisterValue); + if (ACPI_FAILURE (Status)) + { + goto UnlockAndExit; + } + + /* + * Insert the input bit into the value that was just read + * and write the register + */ + ACPI_REGISTER_INSERT_VALUE (RegisterValue, BitRegInfo->BitPosition, + BitRegInfo->AccessBitMask, Value); + + Status = AcpiHwRegisterWrite (BitRegInfo->ParentRegister, + RegisterValue); + } + else + { + /* + * 2) Case for PM1 Status + * + * The Status register is different from the rest. Clear an event + * by writing 1, writing 0 has no effect. So, the only relevant + * information is the single bit we're interested in, all others + * should be written as 0 so they will be left unchanged. + */ + RegisterValue = ACPI_REGISTER_PREPARE_BITS (Value, + BitRegInfo->BitPosition, BitRegInfo->AccessBitMask); + + /* No need to write the register if value is all zeros */ + + if (RegisterValue) + { + Status = AcpiHwRegisterWrite (ACPI_REGISTER_PM1_STATUS, + RegisterValue); + } + } + + ACPI_DEBUG_PRINT ((ACPI_DB_IO, + "BitReg %X, ParentReg %X, Value %8.8X, Actual %8.8X\n", + RegisterId, BitRegInfo->ParentRegister, Value, RegisterValue)); + + +UnlockAndExit: + + AcpiOsReleaseLock (AcpiGbl_HardwareLock, LockFlags); + return_ACPI_STATUS (Status); +} + +ACPI_EXPORT_SYMBOL (AcpiWriteBitRegister) + +#endif /* !ACPI_REDUCED_HARDWARE */ + + +/******************************************************************************* + * + * FUNCTION: AcpiGetSleepTypeData + * + * PARAMETERS: SleepState - Numeric sleep state + * *SleepTypeA - Where SLP_TYPa is returned + * *SleepTypeB - Where SLP_TYPb is returned + * + * RETURN: Status - ACPI status + * + * DESCRIPTION: Obtain the SLP_TYPa and SLP_TYPb values for the requested sleep + * state. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiGetSleepTypeData ( + UINT8 SleepState, + UINT8 *SleepTypeA, + UINT8 *SleepTypeB) +{ + ACPI_STATUS Status = AE_OK; + ACPI_EVALUATE_INFO *Info; + + + ACPI_FUNCTION_TRACE (AcpiGetSleepTypeData); + + + /* Validate parameters */ + + if ((SleepState > ACPI_S_STATES_MAX) || + !SleepTypeA || + !SleepTypeB) + { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + /* Allocate the evaluation information block */ + + Info = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EVALUATE_INFO)); + if (!Info) + { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + Info->Pathname = ACPI_CAST_PTR (char, AcpiGbl_SleepStateNames[SleepState]); + + /* Evaluate the namespace object containing the values for this state */ + + Status = AcpiNsEvaluate (Info); + if (ACPI_FAILURE (Status)) + { + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "%s while evaluating SleepState [%s]\n", + AcpiFormatException (Status), Info->Pathname)); + + goto Cleanup; + } + + /* Must have a return object */ + + if (!Info->ReturnObject) + { + ACPI_ERROR ((AE_INFO, "No Sleep State object returned from [%s]", + Info->Pathname)); + Status = AE_NOT_EXIST; + } + + /* It must be of type Package */ + + else if (Info->ReturnObject->Common.Type != ACPI_TYPE_PACKAGE) + { + ACPI_ERROR ((AE_INFO, "Sleep State return object is not a Package")); + Status = AE_AML_OPERAND_TYPE; + } + + /* + * The package must have at least two elements. NOTE (March 2005): This + * goes against the current ACPI spec which defines this object as a + * package with one encoded DWORD element. However, existing practice + * by BIOS vendors seems to be to have 2 or more elements, at least + * one per sleep type (A/B). + */ + else if (Info->ReturnObject->Package.Count < 2) + { + ACPI_ERROR ((AE_INFO, + "Sleep State return package does not have at least two elements")); + Status = AE_AML_NO_OPERAND; + } + + /* The first two elements must both be of type Integer */ + + else if (((Info->ReturnObject->Package.Elements[0])->Common.Type + != ACPI_TYPE_INTEGER) || + ((Info->ReturnObject->Package.Elements[1])->Common.Type + != ACPI_TYPE_INTEGER)) + { + ACPI_ERROR ((AE_INFO, + "Sleep State return package elements are not both Integers " + "(%s, %s)", + AcpiUtGetObjectTypeName (Info->ReturnObject->Package.Elements[0]), + AcpiUtGetObjectTypeName (Info->ReturnObject->Package.Elements[1]))); + Status = AE_AML_OPERAND_TYPE; + } + else + { + /* Valid _Sx_ package size, type, and value */ + + *SleepTypeA = (UINT8) + (Info->ReturnObject->Package.Elements[0])->Integer.Value; + *SleepTypeB = (UINT8) + (Info->ReturnObject->Package.Elements[1])->Integer.Value; + } + + if (ACPI_FAILURE (Status)) + { + ACPI_EXCEPTION ((AE_INFO, Status, + "While evaluating SleepState [%s], bad Sleep object %p type %s", + Info->Pathname, Info->ReturnObject, + AcpiUtGetObjectTypeName (Info->ReturnObject))); + } + + AcpiUtRemoveReference (Info->ReturnObject); + +Cleanup: + ACPI_FREE (Info); + return_ACPI_STATUS (Status); +} + +ACPI_EXPORT_SYMBOL (AcpiGetSleepTypeData) diff --git a/source/components/hardware/hwxfsleep.c b/source/components/hardware/hwxfsleep.c new file mode 100644 index 0000000..39bf122 --- /dev/null +++ b/source/components/hardware/hwxfsleep.c @@ -0,0 +1,474 @@ +/****************************************************************************** + * + * Name: hwxfsleep.c - ACPI Hardware Sleep/Wake External Interfaces + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2012, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpi.h" +#include "accommon.h" + +#define _COMPONENT ACPI_HARDWARE + ACPI_MODULE_NAME ("hwxfsleep") + +/* Local prototypes */ + +static ACPI_STATUS +AcpiHwSleepDispatch ( + UINT8 SleepState, + UINT32 FunctionId); + +/* + * Dispatch table used to efficiently branch to the various sleep + * functions. + */ +#define ACPI_SLEEP_FUNCTION_ID 0 +#define ACPI_WAKE_PREP_FUNCTION_ID 1 +#define ACPI_WAKE_FUNCTION_ID 2 + +/* Legacy functions are optional, based upon ACPI_REDUCED_HARDWARE */ + +static ACPI_SLEEP_FUNCTIONS AcpiSleepDispatch[] = +{ + {ACPI_HW_OPTIONAL_FUNCTION (AcpiHwLegacySleep), AcpiHwExtendedSleep}, + {ACPI_HW_OPTIONAL_FUNCTION (AcpiHwLegacyWakePrep), AcpiHwExtendedWakePrep}, + {ACPI_HW_OPTIONAL_FUNCTION (AcpiHwLegacyWake), AcpiHwExtendedWake} +}; + + +/* + * These functions are removed for the ACPI_REDUCED_HARDWARE case: + * AcpiSetFirmwareWakingVector + * AcpiSetFirmwareWakingVector64 + * AcpiEnterSleepStateS4bios + */ + +#if (!ACPI_REDUCED_HARDWARE) +/******************************************************************************* + * + * FUNCTION: AcpiSetFirmwareWakingVector + * + * PARAMETERS: PhysicalAddress - 32-bit physical address of ACPI real mode + * entry point. + * + * RETURN: Status + * + * DESCRIPTION: Sets the 32-bit FirmwareWakingVector field of the FACS + * + ******************************************************************************/ + +ACPI_STATUS +AcpiSetFirmwareWakingVector ( + UINT32 PhysicalAddress) +{ + ACPI_FUNCTION_TRACE (AcpiSetFirmwareWakingVector); + + + /* Set the 32-bit vector */ + + AcpiGbl_FACS->FirmwareWakingVector = PhysicalAddress; + + /* Clear the 64-bit vector if it exists */ + + if ((AcpiGbl_FACS->Length > 32) && (AcpiGbl_FACS->Version >= 1)) + { + AcpiGbl_FACS->XFirmwareWakingVector = 0; + } + + return_ACPI_STATUS (AE_OK); +} + +ACPI_EXPORT_SYMBOL (AcpiSetFirmwareWakingVector) + + +#if ACPI_MACHINE_WIDTH == 64 +/******************************************************************************* + * + * FUNCTION: AcpiSetFirmwareWakingVector64 + * + * PARAMETERS: PhysicalAddress - 64-bit physical address of ACPI protected + * mode entry point. + * + * RETURN: Status + * + * DESCRIPTION: Sets the 64-bit X_FirmwareWakingVector field of the FACS, if + * it exists in the table. This function is intended for use with + * 64-bit host operating systems. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiSetFirmwareWakingVector64 ( + UINT64 PhysicalAddress) +{ + ACPI_FUNCTION_TRACE (AcpiSetFirmwareWakingVector64); + + + /* Determine if the 64-bit vector actually exists */ + + if ((AcpiGbl_FACS->Length <= 32) || (AcpiGbl_FACS->Version < 1)) + { + return_ACPI_STATUS (AE_NOT_EXIST); + } + + /* Clear 32-bit vector, set the 64-bit X_ vector */ + + AcpiGbl_FACS->FirmwareWakingVector = 0; + AcpiGbl_FACS->XFirmwareWakingVector = PhysicalAddress; + return_ACPI_STATUS (AE_OK); +} + +ACPI_EXPORT_SYMBOL (AcpiSetFirmwareWakingVector64) +#endif + + +/******************************************************************************* + * + * FUNCTION: AcpiEnterSleepStateS4bios + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Perform a S4 bios request. + * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED + * + ******************************************************************************/ + +ACPI_STATUS +AcpiEnterSleepStateS4bios ( + void) +{ + UINT32 InValue; + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (AcpiEnterSleepStateS4bios); + + + /* Clear the wake status bit (PM1) */ + + Status = AcpiWriteBitRegister (ACPI_BITREG_WAKE_STATUS, ACPI_CLEAR_STATUS); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + Status = AcpiHwClearAcpiStatus (); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* + * 1) Disable/Clear all GPEs + * 2) Enable all wakeup GPEs + */ + Status = AcpiHwDisableAllGpes (); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + AcpiGbl_SystemAwakeAndRunning = FALSE; + + Status = AcpiHwEnableAllWakeupGpes (); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + ACPI_FLUSH_CPU_CACHE (); + + Status = AcpiHwWritePort (AcpiGbl_FADT.SmiCommand, + (UINT32) AcpiGbl_FADT.S4BiosRequest, 8); + + do { + AcpiOsStall(1000); + Status = AcpiReadBitRegister (ACPI_BITREG_WAKE_STATUS, &InValue); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + } while (!InValue); + + return_ACPI_STATUS (AE_OK); +} + +ACPI_EXPORT_SYMBOL (AcpiEnterSleepStateS4bios) + +#endif /* !ACPI_REDUCED_HARDWARE */ + + +/******************************************************************************* + * + * FUNCTION: AcpiHwSleepDispatch + * + * PARAMETERS: SleepState - Which sleep state to enter/exit + * FunctionId - Sleep, WakePrep, or Wake + * + * RETURN: Status from the invoked sleep handling function. + * + * DESCRIPTION: Dispatch a sleep/wake request to the appropriate handling + * function. + * + ******************************************************************************/ + +static ACPI_STATUS +AcpiHwSleepDispatch ( + UINT8 SleepState, + UINT32 FunctionId) +{ + ACPI_STATUS Status; + ACPI_SLEEP_FUNCTIONS *SleepFunctions = &AcpiSleepDispatch[FunctionId]; + + +#if (!ACPI_REDUCED_HARDWARE) + + /* + * If the Hardware Reduced flag is set (from the FADT), we must + * use the extended sleep registers + */ + if (AcpiGbl_ReducedHardware || + AcpiGbl_FADT.SleepControl.Address) + { + Status = SleepFunctions->ExtendedFunction (SleepState); + } + else + { + /* Legacy sleep */ + + Status = SleepFunctions->LegacyFunction (SleepState); + } + + return (Status); + +#else + /* + * For the case where reduced-hardware-only code is being generated, + * we know that only the extended sleep registers are available + */ + Status = SleepFunctions->ExtendedFunction (SleepState); + return (Status); + +#endif /* !ACPI_REDUCED_HARDWARE */ +} + + +/******************************************************************************* + * + * FUNCTION: AcpiEnterSleepStatePrep + * + * PARAMETERS: SleepState - Which sleep state to enter + * + * RETURN: Status + * + * DESCRIPTION: Prepare to enter a system sleep state. + * This function must execute with interrupts enabled. + * We break sleeping into 2 stages so that OSPM can handle + * various OS-specific tasks between the two steps. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiEnterSleepStatePrep ( + UINT8 SleepState) +{ + ACPI_STATUS Status; + ACPI_OBJECT_LIST ArgList; + ACPI_OBJECT Arg; + UINT32 SstValue; + + + ACPI_FUNCTION_TRACE (AcpiEnterSleepStatePrep); + + + /* _PSW methods could be run here to enable wake-on keyboard, LAN, etc. */ + + Status = AcpiGetSleepTypeData (SleepState, + &AcpiGbl_SleepTypeA, &AcpiGbl_SleepTypeB); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + + /* Execute the _PTS method (Prepare To Sleep) */ + + ArgList.Count = 1; + ArgList.Pointer = &Arg; + Arg.Type = ACPI_TYPE_INTEGER; + Arg.Integer.Value = SleepState; + + Status = AcpiEvaluateObject (NULL, METHOD_NAME__PTS, &ArgList, NULL); + if (ACPI_FAILURE (Status) && Status != AE_NOT_FOUND) + { + return_ACPI_STATUS (Status); + } + + /* Setup the argument to the _SST method (System STatus) */ + + switch (SleepState) + { + case ACPI_STATE_S0: + SstValue = ACPI_SST_WORKING; + break; + + case ACPI_STATE_S1: + case ACPI_STATE_S2: + case ACPI_STATE_S3: + SstValue = ACPI_SST_SLEEPING; + break; + + case ACPI_STATE_S4: + SstValue = ACPI_SST_SLEEP_CONTEXT; + break; + + default: + SstValue = ACPI_SST_INDICATOR_OFF; /* Default is off */ + break; + } + + /* + * Set the system indicators to show the desired sleep state. + * _SST is an optional method (return no error if not found) + */ + AcpiHwExecuteSleepMethod (METHOD_NAME__SST, SstValue); + return_ACPI_STATUS (AE_OK); +} + +ACPI_EXPORT_SYMBOL (AcpiEnterSleepStatePrep) + + +/******************************************************************************* + * + * FUNCTION: AcpiEnterSleepState + * + * PARAMETERS: SleepState - Which sleep state to enter + * + * RETURN: Status + * + * DESCRIPTION: Enter a system sleep state + * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED + * + ******************************************************************************/ + +ACPI_STATUS +AcpiEnterSleepState ( + UINT8 SleepState) +{ + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (AcpiEnterSleepState); + + + if ((AcpiGbl_SleepTypeA > ACPI_SLEEP_TYPE_MAX) || + (AcpiGbl_SleepTypeB > ACPI_SLEEP_TYPE_MAX)) + { + ACPI_ERROR ((AE_INFO, "Sleep values out of range: A=0x%X B=0x%X", + AcpiGbl_SleepTypeA, AcpiGbl_SleepTypeB)); + return_ACPI_STATUS (AE_AML_OPERAND_VALUE); + } + + Status = AcpiHwSleepDispatch (SleepState, ACPI_SLEEP_FUNCTION_ID); + return_ACPI_STATUS (Status); +} + +ACPI_EXPORT_SYMBOL (AcpiEnterSleepState) + + +/******************************************************************************* + * + * FUNCTION: AcpiLeaveSleepStatePrep + * + * PARAMETERS: SleepState - Which sleep state we are exiting + * + * RETURN: Status + * + * DESCRIPTION: Perform the first state of OS-independent ACPI cleanup after a + * sleep. Called with interrupts DISABLED. + * We break wake/resume into 2 stages so that OSPM can handle + * various OS-specific tasks between the two steps. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiLeaveSleepStatePrep ( + UINT8 SleepState) +{ + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (AcpiLeaveSleepStatePrep); + + + Status = AcpiHwSleepDispatch (SleepState, ACPI_WAKE_PREP_FUNCTION_ID); + return_ACPI_STATUS (Status); +} + +ACPI_EXPORT_SYMBOL (AcpiLeaveSleepStatePrep) + + +/******************************************************************************* + * + * FUNCTION: AcpiLeaveSleepState + * + * PARAMETERS: SleepState - Which sleep state we are exiting + * + * RETURN: Status + * + * DESCRIPTION: Perform OS-independent ACPI cleanup after a sleep + * Called with interrupts ENABLED. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiLeaveSleepState ( + UINT8 SleepState) +{ + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE (AcpiLeaveSleepState); + + + Status = AcpiHwSleepDispatch (SleepState, ACPI_WAKE_FUNCTION_ID); + return_ACPI_STATUS (Status); +} + +ACPI_EXPORT_SYMBOL (AcpiLeaveSleepState) |