diff options
Diffstat (limited to 'sys/contrib/dev/acpica/evevent.c')
-rw-r--r-- | sys/contrib/dev/acpica/evevent.c | 650 |
1 files changed, 345 insertions, 305 deletions
diff --git a/sys/contrib/dev/acpica/evevent.c b/sys/contrib/dev/acpica/evevent.c index 20c9953..b11adce 100644 --- a/sys/contrib/dev/acpica/evevent.c +++ b/sys/contrib/dev/acpica/evevent.c @@ -1,8 +1,7 @@ /****************************************************************************** * - * Module Name: evevent - Fixed and General Purpose AcpiEvent - * handling and dispatch - * $Revision: 54 $ + * Module Name: evevent - Fixed and General Purpose Even handling and dispatch + * $Revision: 69 $ * *****************************************************************************/ @@ -10,7 +9,7 @@ * * 1. Copyright Notice * - * Some or all of this work - Copyright (c) 1999, 2000, 2001, Intel Corp. + * Some or all of this work - Copyright (c) 1999 - 2002, Intel Corp. * All rights reserved. * * 2. License @@ -121,7 +120,7 @@ #include "acnamesp.h" #define _COMPONENT ACPI_EVENTS - MODULE_NAME ("evevent") + ACPI_MODULE_NAME ("evevent") /******************************************************************************* @@ -132,9 +131,7 @@ * * RETURN: Status * - * DESCRIPTION: Ensures that the system control interrupt (SCI) is properly - * configured, disables SCI event sources, installs the SCI - * handler + * DESCRIPTION: Initialize global data structures for events. * ******************************************************************************/ @@ -145,7 +142,7 @@ AcpiEvInitialize ( ACPI_STATUS Status; - FUNCTION_TRACE ("EvInitialize"); + ACPI_FUNCTION_TRACE ("EvInitialize"); /* Make sure we have ACPI tables */ @@ -164,23 +161,55 @@ AcpiEvInitialize ( Status = AcpiEvFixedEventInitialize (); if (ACPI_FAILURE (Status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_FATAL, "Unable to initialize fixed events.\n")); + ACPI_DEBUG_PRINT ((ACPI_DB_FATAL, + "Unable to initialize fixed events, %s\n", + AcpiFormatException (Status))); return_ACPI_STATUS (Status); } Status = AcpiEvGpeInitialize (); if (ACPI_FAILURE (Status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_FATAL, "Unable to initialize general purpose events.\n")); + ACPI_DEBUG_PRINT ((ACPI_DB_FATAL, + "Unable to initialize general purpose events, %s\n", + AcpiFormatException (Status))); return_ACPI_STATUS (Status); } + return_ACPI_STATUS (Status); +} + + +/******************************************************************************* + * + * FUNCTION: AcpiEvHandlerInitialize + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Install handlers for the SCI, Global Lock, and GPEs. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiEvHandlerInitialize ( + void) +{ + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE ("EvInitialize"); + + /* Install the SCI handler */ Status = AcpiEvInstallSciHandler (); if (ACPI_FAILURE (Status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_FATAL, "Unable to install System Control Interrupt Handler\n")); + ACPI_DEBUG_PRINT ((ACPI_DB_FATAL, + "Unable to install System Control Interrupt Handler, %s\n", + AcpiFormatException (Status))); return_ACPI_STATUS (Status); } @@ -189,7 +218,9 @@ AcpiEvInitialize ( Status = AcpiEvInitGpeControlMethods (); if (ACPI_FAILURE (Status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_FATAL, "Unable to initialize Gpe control methods\n")); + ACPI_DEBUG_PRINT ((ACPI_DB_FATAL, + "Unable to initialize GPE control methods, %s\n", + AcpiFormatException (Status))); return_ACPI_STATUS (Status); } @@ -198,7 +229,9 @@ AcpiEvInitialize ( Status = AcpiEvInitGlobalLockHandler (); if (ACPI_FAILURE (Status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_FATAL, "Unable to initialize Global Lock handler\n")); + ACPI_DEBUG_PRINT ((ACPI_DB_FATAL, + "Unable to initialize Global Lock handler, %s\n", + AcpiFormatException (Status))); return_ACPI_STATUS (Status); } @@ -214,29 +247,34 @@ AcpiEvInitialize ( * * RETURN: Status * - * DESCRIPTION: Initialize the Fixed AcpiEvent data structures + * DESCRIPTION: Install the fixed event handlers and enable the fixed events. * ******************************************************************************/ ACPI_STATUS -AcpiEvFixedEventInitialize(void) +AcpiEvFixedEventInitialize ( + void) { NATIVE_UINT i; - /* Initialize the structure that keeps track of fixed event handlers */ - + /* + * Initialize the structure that keeps track of fixed event handlers + * and enable the fixed events. + */ for (i = 0; i < ACPI_NUM_FIXED_EVENTS; i++) { AcpiGbl_FixedEventHandlers[i].Handler = NULL; AcpiGbl_FixedEventHandlers[i].Context = NULL; - } - AcpiHwRegisterBitAccess (ACPI_WRITE, ACPI_MTX_LOCK, TMR_EN, 0); - AcpiHwRegisterBitAccess (ACPI_WRITE, ACPI_MTX_LOCK, GBL_EN, 0); - AcpiHwRegisterBitAccess (ACPI_WRITE, ACPI_MTX_LOCK, PWRBTN_EN, 0); - AcpiHwRegisterBitAccess (ACPI_WRITE, ACPI_MTX_LOCK, SLPBTN_EN, 0); - AcpiHwRegisterBitAccess (ACPI_WRITE, ACPI_MTX_LOCK, RTC_EN, 0); + /* Enable the fixed event */ + + if (AcpiGbl_FixedEventInfo[i].EnableRegisterId != 0xFF) + { + AcpiHwBitRegisterWrite (AcpiGbl_FixedEventInfo[i].EnableRegisterId, + 0, ACPI_MTX_LOCK); + } + } return (AE_OK); } @@ -255,57 +293,43 @@ AcpiEvFixedEventInitialize(void) ******************************************************************************/ UINT32 -AcpiEvFixedEventDetect (void) +AcpiEvFixedEventDetect ( + void) { - UINT32 IntStatus = INTERRUPT_NOT_HANDLED; - UINT32 StatusRegister; - UINT32 EnableRegister; + UINT32 IntStatus = ACPI_INTERRUPT_NOT_HANDLED; + UINT32 GpeStatus; + UINT32 GpeEnable; + NATIVE_UINT i; - PROC_NAME ("EvFixedEventDetect"); + ACPI_FUNCTION_NAME ("EvFixedEventDetect"); /* * Read the fixed feature status and enable registers, as all the cases * depend on their values. */ - StatusRegister = AcpiHwRegisterRead (ACPI_MTX_DO_NOT_LOCK, PM1_STS); - EnableRegister = AcpiHwRegisterRead (ACPI_MTX_DO_NOT_LOCK, PM1_EN); + GpeStatus = AcpiHwRegisterRead (ACPI_MTX_DO_NOT_LOCK, ACPI_REGISTER_PM1_STATUS); + GpeEnable = AcpiHwRegisterRead (ACPI_MTX_DO_NOT_LOCK, ACPI_REGISTER_PM1_ENABLE); ACPI_DEBUG_PRINT ((ACPI_DB_INTERRUPTS, "Fixed AcpiEvent Block: Enable %08X Status %08X\n", - EnableRegister, StatusRegister)); - - /* Power management timer roll over */ + GpeEnable, GpeStatus)); - if ((StatusRegister & ACPI_STATUS_PMTIMER) && - (EnableRegister & ACPI_ENABLE_PMTIMER)) - { - IntStatus |= AcpiEvFixedEventDispatch (ACPI_EVENT_PMTIMER); - } - - /* Global event (BIOS wants the global lock) */ - - if ((StatusRegister & ACPI_STATUS_GLOBAL) && - (EnableRegister & ACPI_ENABLE_GLOBAL)) - { - IntStatus |= AcpiEvFixedEventDispatch (ACPI_EVENT_GLOBAL); - } - - /* Power button event */ - - if ((StatusRegister & ACPI_STATUS_POWER_BUTTON) && - (EnableRegister & ACPI_ENABLE_POWER_BUTTON)) + /* + * Check for all possible Fixed Events and dispatch those that are active + */ + for (i = 0; i < ACPI_NUM_FIXED_EVENTS; i++) { - IntStatus |= AcpiEvFixedEventDispatch (ACPI_EVENT_POWER_BUTTON); - } + /* Both the status and enable bits must be on for this event */ - /* Sleep button event */ + if ((GpeStatus & AcpiGbl_FixedEventInfo[i].StatusBitMask) && + (GpeEnable & AcpiGbl_FixedEventInfo[i].EnableBitMask)) + { + /* Found an active (signalled) event */ - if ((StatusRegister & ACPI_STATUS_SLEEP_BUTTON) && - (EnableRegister & ACPI_ENABLE_SLEEP_BUTTON)) - { - IntStatus |= AcpiEvFixedEventDispatch (ACPI_EVENT_SLEEP_BUTTON); + IntStatus |= AcpiEvFixedEventDispatch (i); + } } return (IntStatus); @@ -329,42 +353,15 @@ UINT32 AcpiEvFixedEventDispatch ( UINT32 Event) { - UINT32 RegisterId; - FUNCTION_ENTRY (); + ACPI_FUNCTION_ENTRY (); /* Clear the status bit */ - switch (Event) - { - case ACPI_EVENT_PMTIMER: - RegisterId = TMR_STS; - break; - - case ACPI_EVENT_GLOBAL: - RegisterId = GBL_STS; - break; - - case ACPI_EVENT_POWER_BUTTON: - RegisterId = PWRBTN_STS; - break; - - case ACPI_EVENT_SLEEP_BUTTON: - RegisterId = SLPBTN_STS; - break; - - case ACPI_EVENT_RTC: - RegisterId = RTC_STS; - break; - - default: - return 0; - break; - } - - AcpiHwRegisterBitAccess (ACPI_WRITE, ACPI_MTX_DO_NOT_LOCK, RegisterId, 1); + AcpiHwBitRegisterWrite (AcpiGbl_FixedEventInfo[Event].StatusRegisterId, + 1, ACPI_MTX_DO_NOT_LOCK); /* * Make sure we've got a handler. If not, report an error. @@ -372,19 +369,17 @@ AcpiEvFixedEventDispatch ( */ if (NULL == AcpiGbl_FixedEventHandlers[Event].Handler) { - RegisterId = (PM1_EN | REGISTER_BIT_ID(RegisterId)); + AcpiHwBitRegisterWrite (AcpiGbl_FixedEventInfo[Event].EnableRegisterId, + 0, ACPI_MTX_DO_NOT_LOCK); - AcpiHwRegisterBitAccess (ACPI_WRITE, ACPI_MTX_DO_NOT_LOCK, - RegisterId, 0); - - REPORT_ERROR ( + ACPI_REPORT_ERROR ( ("EvGpeDispatch: No installed handler for fixed event [%08X]\n", Event)); - return (INTERRUPT_NOT_HANDLED); + return (ACPI_INTERRUPT_NOT_HANDLED); } - /* Invoke the handler */ + /* Invoke the Fixed Event handler */ return ((AcpiGbl_FixedEventHandlers[Event].Handler)( AcpiGbl_FixedEventHandlers[Event].Context)); @@ -406,145 +401,181 @@ AcpiEvFixedEventDispatch ( ACPI_STATUS AcpiEvGpeInitialize (void) { - UINT32 i; - UINT32 j; - UINT32 RegisterIndex; + NATIVE_UINT i; + NATIVE_UINT j; + NATIVE_UINT GpeBlock; + UINT32 GpeRegister; + UINT32 GpeNumberIndex; UINT32 GpeNumber; - UINT16 Gpe0RegisterCount; - UINT16 Gpe1RegisterCount; + ACPI_GPE_REGISTER_INFO *GpeRegisterInfo; + + ACPI_FUNCTION_TRACE ("EvGpeInitialize"); - FUNCTION_TRACE ("EvGpeInitialize"); /* - * Set up various GPE counts + * Initialize the GPE Block globals * - * You may ask,why are the GPE register block lengths divided by 2? - * From the ACPI 2.0 Spec, section, 4.7.1.6 General-Purpose Event - * Registers, we have, + * Why the GPE register block lengths divided by 2: From the ACPI Spec, + * section "General-Purpose Event Registers", we have: * * "Each register block contains two registers of equal length - * GPEx_STS and GPEx_EN (where x is 0 or 1). The length of the - * GPE0_STS and GPE0_EN registers is equal to half the GPE0_LEN - * The length of the GPE1_STS and GPE1_EN registers is equal to - * half the GPE1_LEN. If a generic register block is not supported - * then its respective block pointer and block length values in the - * FADT table contain zeros. The GPE0_LEN and GPE1_LEN do not need - * to be the same size." + * GPEx_STS and GPEx_EN (where x is 0 or 1). The length of the + * GPE0_STS and GPE0_EN registers is equal to half the GPE0_LEN + * The length of the GPE1_STS and GPE1_EN registers is equal to + * half the GPE1_LEN. If a generic register block is not supported + * then its respective block pointer and block length values in the + * FADT table contain zeros. The GPE0_LEN and GPE1_LEN do not need + * to be the same size." */ - Gpe0RegisterCount = (UINT16) DIV_2 (AcpiGbl_FADT->Gpe0BlkLen); - Gpe1RegisterCount = (UINT16) DIV_2 (AcpiGbl_FADT->Gpe1BlkLen); - AcpiGbl_GpeRegisterCount = Gpe0RegisterCount + Gpe1RegisterCount; + AcpiGbl_GpeBlockInfo[0].RegisterCount = (UINT16) ACPI_DIV_2 (AcpiGbl_FADT->Gpe0BlkLen); + AcpiGbl_GpeBlockInfo[1].RegisterCount = (UINT16) ACPI_DIV_2 (AcpiGbl_FADT->Gpe1BlkLen); + AcpiGbl_GpeBlockInfo[0].BlockAddress = (UINT16) ACPI_GET_ADDRESS (AcpiGbl_FADT->XGpe0Blk.Address); + AcpiGbl_GpeBlockInfo[1].BlockAddress = (UINT16) ACPI_GET_ADDRESS (AcpiGbl_FADT->XGpe1Blk.Address); + + AcpiGbl_GpeBlockInfo[0].BlockBaseNumber = 0; + AcpiGbl_GpeBlockInfo[1].BlockBaseNumber = AcpiGbl_FADT->Gpe1Base; + + AcpiGbl_GpeRegisterCount = AcpiGbl_GpeBlockInfo[0].RegisterCount + + AcpiGbl_GpeBlockInfo[1].RegisterCount; if (!AcpiGbl_GpeRegisterCount) { - REPORT_WARNING (("Zero GPEs are defined in the FADT\n")); + ACPI_REPORT_WARNING (("Zero GPEs are defined in the FADT\n")); return_ACPI_STATUS (AE_OK); } - /* - * Allocate the Gpe information block - */ - AcpiGbl_GpeRegisters = ACPI_MEM_CALLOCATE (AcpiGbl_GpeRegisterCount * - sizeof (ACPI_GPE_REGISTERS)); - if (!AcpiGbl_GpeRegisters) + /* Determine the maximum GPE number for this machine */ + + AcpiGbl_GpeNumberMax = ACPI_MUL_8 (AcpiGbl_GpeBlockInfo[0].RegisterCount) - 1; + + if (AcpiGbl_GpeBlockInfo[1].RegisterCount) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, - "Could not allocate the GpeRegisters block\n")); - return_ACPI_STATUS (AE_NO_MEMORY); + /* Check for GPE0/GPE1 overlap */ + + if (AcpiGbl_GpeNumberMax >= AcpiGbl_FADT->Gpe1Base) + { + ACPI_REPORT_ERROR (("GPE0 block overlaps the GPE1 block\n")); + return_ACPI_STATUS (AE_BAD_VALUE); + } + + /* GPE0 and GPE1 do not have to be contiguous in the GPE number space */ + + AcpiGbl_GpeNumberMax = AcpiGbl_FADT->Gpe1Base + (ACPI_MUL_8 (AcpiGbl_GpeBlockInfo[1].RegisterCount) - 1); + } + + /* Check for Max GPE number out-of-range */ + + if (AcpiGbl_GpeNumberMax > ACPI_GPE_MAX) + { + ACPI_REPORT_ERROR (("Maximum GPE number from FADT is too large: 0x%X\n", AcpiGbl_GpeNumberMax)); + return_ACPI_STATUS (AE_BAD_VALUE); } /* - * Allocate the Gpe dispatch handler block - * There are eight distinct GP events per register. - * Initialization to zeros is sufficient + * Allocate the GPE number-to-index translation table */ - AcpiGbl_GpeInfo = ACPI_MEM_CALLOCATE (MUL_8 (AcpiGbl_GpeRegisterCount) * - sizeof (ACPI_GPE_LEVEL_INFO)); - if (!AcpiGbl_GpeInfo) + AcpiGbl_GpeNumberToIndex = ACPI_MEM_CALLOCATE (sizeof (ACPI_GPE_INDEX_INFO) * + (AcpiGbl_GpeNumberMax + 1)); + if (!AcpiGbl_GpeNumberToIndex) { - ACPI_MEM_FREE (AcpiGbl_GpeRegisters); - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not allocate the GpeInfo block\n")); + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Could not allocate the GpeNumberToIndex table\n")); return_ACPI_STATUS (AE_NO_MEMORY); } - /* Set the Gpe validation table to GPE_INVALID */ + /* Set the Gpe index table to GPE_INVALID */ - MEMSET (AcpiGbl_GpeValid, (int) ACPI_GPE_INVALID, ACPI_NUM_GPE); + ACPI_MEMSET (AcpiGbl_GpeNumberToIndex, (int) ACPI_GPE_INVALID, + sizeof (ACPI_GPE_INDEX_INFO) * (AcpiGbl_GpeNumberMax + 1)); /* - * Initialize the Gpe information and validation blocks. A goal of these - * blocks is to hide the fact that there are two separate GPE register sets - * In a given block, the status registers occupy the first half, and - * the enable registers occupy the second half. + * Allocate the GPE register information block */ - - /* GPE Block 0 */ - - RegisterIndex = 0; - - for (i = 0; i < Gpe0RegisterCount; i++) + AcpiGbl_GpeRegisterInfo = ACPI_MEM_CALLOCATE (AcpiGbl_GpeRegisterCount * + sizeof (ACPI_GPE_REGISTER_INFO)); + if (!AcpiGbl_GpeRegisterInfo) { - AcpiGbl_GpeRegisters[RegisterIndex].StatusAddr = - (UINT16) (ACPI_GET_ADDRESS (AcpiGbl_FADT->XGpe0Blk.Address) + i); + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Could not allocate the GpeRegisterInfo table\n")); + goto ErrorExit1; + } - AcpiGbl_GpeRegisters[RegisterIndex].EnableAddr = - (UINT16) (ACPI_GET_ADDRESS (AcpiGbl_FADT->XGpe0Blk.Address) + i + Gpe0RegisterCount); + /* + * Allocate the GPE dispatch handler block. There are eight distinct GPEs + * per register. Initialization to zeros is sufficient. + */ + AcpiGbl_GpeNumberInfo = ACPI_MEM_CALLOCATE (ACPI_MUL_8 (AcpiGbl_GpeRegisterCount) * + sizeof (ACPI_GPE_NUMBER_INFO)); + if (!AcpiGbl_GpeNumberInfo) + { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not allocate the GpeNumberInfo table\n")); + goto ErrorExit2; + } - AcpiGbl_GpeRegisters[RegisterIndex].GpeBase = (UINT8) MUL_8 (i); + /* + * Initialize the GPE information and validation tables. A goal of these + * tables is to hide the fact that there are two separate GPE register sets + * in a given gpe hardware block, the status registers occupy the first half, + * and the enable registers occupy the second half. Another goal is to hide + * the fact that there may be multiple GPE hardware blocks. + */ + GpeRegister = 0; + GpeNumberIndex = 0; - for (j = 0; j < 8; j++) + for (GpeBlock = 0; GpeBlock < ACPI_MAX_GPE_BLOCKS; GpeBlock++) + { + for (i = 0; i < AcpiGbl_GpeBlockInfo[GpeBlock].RegisterCount; i++) { - GpeNumber = AcpiGbl_GpeRegisters[RegisterIndex].GpeBase + j; - AcpiGbl_GpeValid[GpeNumber] = (UINT8) RegisterIndex; - } + GpeRegisterInfo = &AcpiGbl_GpeRegisterInfo[GpeRegister]; - /* - * Clear the status/enable registers. Note that status registers - * are cleared by writing a '1', while enable registers are cleared - * by writing a '0'. - */ - AcpiOsWritePort (AcpiGbl_GpeRegisters[RegisterIndex].EnableAddr, 0x00, 8); - AcpiOsWritePort (AcpiGbl_GpeRegisters[RegisterIndex].StatusAddr, 0xFF, 8); + /* Init the Register info for this entire GPE register (8 GPEs) */ - RegisterIndex++; - } + GpeRegisterInfo->BaseGpeNumber = (UINT8) (AcpiGbl_GpeBlockInfo[GpeBlock].BlockBaseNumber + (ACPI_MUL_8 (i))); + GpeRegisterInfo->StatusAddr = (UINT16) (AcpiGbl_GpeBlockInfo[GpeBlock].BlockAddress + i); + GpeRegisterInfo->EnableAddr = (UINT16) (AcpiGbl_GpeBlockInfo[GpeBlock].BlockAddress + i + + AcpiGbl_GpeBlockInfo[GpeBlock].RegisterCount); - /* GPE Block 1 */ + /* Init the Index mapping info for each GPE number within this register */ - for (i = 0; i < Gpe1RegisterCount; i++) - { - AcpiGbl_GpeRegisters[RegisterIndex].StatusAddr = - (UINT16) (ACPI_GET_ADDRESS (AcpiGbl_FADT->XGpe1Blk.Address) + i); + for (j = 0; j < 8; j++) + { + GpeNumber = GpeRegisterInfo->BaseGpeNumber + j; + AcpiGbl_GpeNumberToIndex[GpeNumber].NumberIndex = (UINT8) GpeNumberIndex; - AcpiGbl_GpeRegisters[RegisterIndex].EnableAddr = - (UINT16) (ACPI_GET_ADDRESS (AcpiGbl_FADT->XGpe1Blk.Address) + i + Gpe1RegisterCount); + AcpiGbl_GpeNumberInfo[GpeNumberIndex].BitMask = AcpiGbl_DecodeTo8bit[i]; + GpeNumberIndex++; + } - AcpiGbl_GpeRegisters[RegisterIndex].GpeBase = - (UINT8) (AcpiGbl_FADT->Gpe1Base + MUL_8 (i)); + /* + * Clear the status/enable registers. Note that status registers + * are cleared by writing a '1', while enable registers are cleared + * by writing a '0'. + */ + AcpiOsWritePort (GpeRegisterInfo->EnableAddr, 0x00, 8); + AcpiOsWritePort (GpeRegisterInfo->StatusAddr, 0xFF, 8); - for (j = 0; j < 8; j++) - { - GpeNumber = AcpiGbl_GpeRegisters[RegisterIndex].GpeBase + j; - AcpiGbl_GpeValid[GpeNumber] = (UINT8) RegisterIndex; + GpeRegister++; } - - /* - * Clear the status/enable registers. Note that status registers - * are cleared by writing a '1', while enable registers are cleared - * by writing a '0'. - */ - AcpiOsWritePort (AcpiGbl_GpeRegisters[RegisterIndex].EnableAddr, 0x00, 8); - AcpiOsWritePort (AcpiGbl_GpeRegisters[RegisterIndex].StatusAddr, 0xFF, 8); - - RegisterIndex++; } ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "GPE registers: %X@%8.8X%8.8X (Blk0) %X@%8.8X%8.8X (Blk1)\n", - Gpe0RegisterCount, HIDWORD(AcpiGbl_FADT->XGpe0Blk.Address), LODWORD(AcpiGbl_FADT->XGpe0Blk.Address), - Gpe1RegisterCount, HIDWORD(AcpiGbl_FADT->XGpe1Blk.Address), LODWORD(AcpiGbl_FADT->XGpe1Blk.Address))); + AcpiGbl_GpeBlockInfo[0].RegisterCount, + ACPI_HIDWORD (AcpiGbl_FADT->XGpe0Blk.Address), ACPI_LODWORD (AcpiGbl_FADT->XGpe0Blk.Address), + AcpiGbl_GpeBlockInfo[1].RegisterCount, + ACPI_HIDWORD (AcpiGbl_FADT->XGpe1Blk.Address), ACPI_LODWORD (AcpiGbl_FADT->XGpe1Blk.Address))); return_ACPI_STATUS (AE_OK); + + + /* Error cleanup */ + +ErrorExit2: + ACPI_MEM_FREE (AcpiGbl_GpeRegisterInfo); + +ErrorExit1: + ACPI_MEM_FREE (AcpiGbl_GpeNumberToIndex); + return_ACPI_STATUS (AE_NO_MEMORY); } @@ -566,7 +597,7 @@ AcpiEvGpeInitialize (void) * Where: * L - means that the GPE is level triggered * E - means that the GPE is edge triggered - * nn - is the GPE number + * nn - is the GPE number [in HEX] * ******************************************************************************/ @@ -578,31 +609,34 @@ AcpiEvSaveMethodInfo ( void **ReturnValue) { UINT32 GpeNumber; + UINT32 GpeNumberIndex; NATIVE_CHAR Name[ACPI_NAME_SIZE + 1]; UINT8 Type; - PROC_NAME ("EvSaveMethodInfo"); + ACPI_FUNCTION_NAME ("EvSaveMethodInfo"); /* Extract the name from the object and convert to a string */ - MOVE_UNALIGNED32_TO_32 (Name, &((ACPI_NAMESPACE_NODE *) ObjHandle)->Name); + ACPI_MOVE_UNALIGNED32_TO_32 (Name, + &((ACPI_NAMESPACE_NODE *) ObjHandle)->Name); Name[ACPI_NAME_SIZE] = 0; /* - * Edge/Level determination is based on the 2nd INT8 of the method name + * Edge/Level determination is based on the 2nd character of the method name */ - if (Name[1] == 'L') + switch (Name[1]) { + case 'L': Type = ACPI_EVENT_LEVEL_TRIGGERED; - } - else if (Name[1] == 'E') - { + break; + + case 'E': Type = ACPI_EVENT_EDGE_TRIGGERED; - } - else - { + break; + + default: /* Unknown method type, just ignore it! */ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, @@ -611,9 +645,9 @@ AcpiEvSaveMethodInfo ( return (AE_OK); } - /* Convert the last two characters of the name to the Gpe Number */ + /* Convert the last two characters of the name to the GPE Number */ - GpeNumber = STRTOUL (&Name[2], NULL, 16); + GpeNumber = ACPI_STRTOUL (&Name[2], NULL, 16); if (GpeNumber == ACPI_UINT32_MAX) { /* Conversion failed; invalid method, just ignore it */ @@ -624,9 +658,10 @@ AcpiEvSaveMethodInfo ( return (AE_OK); } - /* Ensure that we have a valid GPE number */ + /* Get GPE index and ensure that we have a valid GPE number */ - if (AcpiGbl_GpeValid[GpeNumber] == ACPI_GPE_INVALID) + GpeNumberIndex = AcpiEvGetGpeNumberIndex (GpeNumber); + if (GpeNumberIndex == ACPI_GPE_INVALID) { /* Not valid, all we can do here is ignore it */ @@ -637,8 +672,8 @@ AcpiEvSaveMethodInfo ( * Now we can add this information to the GpeInfo block * for use during dispatch of this GPE. */ - AcpiGbl_GpeInfo [GpeNumber].Type = Type; - AcpiGbl_GpeInfo [GpeNumber].MethodHandle = ObjHandle; + AcpiGbl_GpeNumberInfo [GpeNumberIndex].Type = Type; + AcpiGbl_GpeNumberInfo [GpeNumberIndex].MethodHandle = ObjHandle; /* * Enable the GPE (SCIs should be disabled at this point) @@ -657,10 +692,9 @@ AcpiEvSaveMethodInfo ( * * PARAMETERS: None * - * RETURN: None + * RETURN: Status * * DESCRIPTION: Obtain the control methods associated with the GPEs. - * * NOTE: Must be called AFTER namespace initialization! * ******************************************************************************/ @@ -671,7 +705,7 @@ AcpiEvInitGpeControlMethods (void) ACPI_STATUS Status; - FUNCTION_TRACE ("EvInitGpeControlMethods"); + ACPI_FUNCTION_TRACE ("EvInitGpeControlMethods"); /* Get a permanent handle to the _GPE object */ @@ -700,21 +734,23 @@ AcpiEvInitGpeControlMethods (void) * * RETURN: INTERRUPT_HANDLED or INTERRUPT_NOT_HANDLED * - * DESCRIPTION: Detect if any GP events have occurred + * DESCRIPTION: Detect if any GP events have occurred. This function is + * executed at interrupt level. * ******************************************************************************/ UINT32 AcpiEvGpeDetect (void) { - UINT32 IntStatus = INTERRUPT_NOT_HANDLED; + UINT32 IntStatus = ACPI_INTERRUPT_NOT_HANDLED; UINT32 i; UINT32 j; UINT8 EnabledStatusByte; UINT8 BitMask; + ACPI_GPE_REGISTER_INFO *GpeRegisterInfo; - PROC_NAME ("EvGpeDetect"); + ACPI_FUNCTION_NAME ("EvGpeDetect"); /* @@ -724,23 +760,24 @@ AcpiEvGpeDetect (void) */ for (i = 0; i < AcpiGbl_GpeRegisterCount; i++) { - AcpiOsReadPort (AcpiGbl_GpeRegisters[i].StatusAddr, - &AcpiGbl_GpeRegisters[i].Status, 8); + GpeRegisterInfo = &AcpiGbl_GpeRegisterInfo[i]; - AcpiOsReadPort (AcpiGbl_GpeRegisters[i].EnableAddr, - &AcpiGbl_GpeRegisters[i].Enable, 8); + AcpiOsReadPort (GpeRegisterInfo->StatusAddr, + &GpeRegisterInfo->Status, 8); + + AcpiOsReadPort (GpeRegisterInfo->EnableAddr, + &GpeRegisterInfo->Enable, 8); ACPI_DEBUG_PRINT ((ACPI_DB_INTERRUPTS, "GPE block at %X - Enable %08X Status %08X\n", - AcpiGbl_GpeRegisters[i].EnableAddr, - AcpiGbl_GpeRegisters[i].Status, - AcpiGbl_GpeRegisters[i].Enable)); + GpeRegisterInfo->EnableAddr, + GpeRegisterInfo->Status, + GpeRegisterInfo->Enable)); /* First check if there is anything active at all in this register */ - EnabledStatusByte = (UINT8) (AcpiGbl_GpeRegisters[i].Status & - AcpiGbl_GpeRegisters[i].Enable); - + EnabledStatusByte = (UINT8) (GpeRegisterInfo->Status & + GpeRegisterInfo->Enable); if (!EnabledStatusByte) { /* No active GPEs in this register, move on */ @@ -761,7 +798,7 @@ AcpiEvGpeDetect (void) * or method. */ IntStatus |= AcpiEvGpeDispatch ( - AcpiGbl_GpeRegisters[i].GpeBase + j); + GpeRegisterInfo->BaseGpeNumber + j); } } } @@ -774,7 +811,7 @@ AcpiEvGpeDetect (void) * * FUNCTION: AcpiEvAsynchExecuteGpeMethod * - * PARAMETERS: GpeNumber - The 0-based Gpe number + * PARAMETERS: GpeNumber - The 0-based GPE number * * RETURN: None * @@ -790,37 +827,50 @@ static void AcpiEvAsynchExecuteGpeMethod ( void *Context) { - UINT32 GpeNumber = (UINT32) Context; - ACPI_GPE_LEVEL_INFO GpeInfo; + UINT32 GpeNumber = (UINT32) ACPI_TO_INTEGER (Context); + UINT32 GpeNumberIndex; + ACPI_GPE_NUMBER_INFO GpeInfo; - FUNCTION_TRACE ("EvAsynchExecuteGpeMethod"); + ACPI_FUNCTION_TRACE ("EvAsynchExecuteGpeMethod"); - /* - * Take a snapshot of the GPE info for this level - */ - AcpiUtAcquireMutex (ACPI_MTX_EVENTS); - GpeInfo = AcpiGbl_GpeInfo [GpeNumber]; - AcpiUtReleaseMutex (ACPI_MTX_EVENTS); + GpeNumberIndex = AcpiEvGetGpeNumberIndex (GpeNumber); + if (GpeNumberIndex == ACPI_GPE_INVALID) + { + return_VOID; + } /* - * Method Handler (_Lxx, _Exx): - * ---------------------------- - * Evaluate the _Lxx/_Exx control method that corresponds to this GPE. + * Take a snapshot of the GPE info for this level - we copy the + * info to prevent a race condition with RemoveHandler. */ + if (ACPI_FAILURE (AcpiUtAcquireMutex (ACPI_MTX_EVENTS))) + { + return_VOID; + } + + GpeInfo = AcpiGbl_GpeNumberInfo [GpeNumberIndex]; + if (ACPI_FAILURE (AcpiUtReleaseMutex (ACPI_MTX_EVENTS))) + { + return_VOID; + } + if (GpeInfo.MethodHandle) { + /* + * Invoke the GPE Method (_Lxx, _Exx): + * (Evaluate the _Lxx/_Exx control method that corresponds to this GPE.) + */ AcpiNsEvaluateByHandle (GpeInfo.MethodHandle, NULL, NULL); } - /* - * Level-Triggered? - * ---------------- - * If level-triggered we clear the GPE status bit after handling the event. - */ if (GpeInfo.Type & ACPI_EVENT_LEVEL_TRIGGERED) { + /* + * GPE is level-triggered, we clear the GPE status bit after handling + * the event. + */ AcpiHwClearGpe (GpeNumber); } @@ -828,7 +878,6 @@ AcpiEvAsynchExecuteGpeMethod ( * Enable the GPE. */ AcpiHwEnableGpe (GpeNumber); - return_VOID; } @@ -837,18 +886,13 @@ AcpiEvAsynchExecuteGpeMethod ( * * FUNCTION: AcpiEvGpeDispatch * - * PARAMETERS: GpeNumber - The 0-based Gpe number + * PARAMETERS: GpeNumber - The 0-based GPE number * * RETURN: INTERRUPT_HANDLED or INTERRUPT_NOT_HANDLED * - * DESCRIPTION: Handle and dispatch a General Purpose AcpiEvent. - * Clears the status bit for the requested event. - * - * TBD: [Investigate] is this still valid or necessary: - * The Gpe handler differs from the fixed events in that it clears the enable - * bit rather than the status bit to clear the interrupt. This allows - * software outside of interrupt context to determine what caused the SCI and - * dispatch the correct AML. + * DESCRIPTION: Dispatch a General Purpose Event to either a function (e.g. EC) + * or method (e.g. _Lxx/_Exx) handler. This function executes + * at interrupt level. * ******************************************************************************/ @@ -856,90 +900,86 @@ UINT32 AcpiEvGpeDispatch ( UINT32 GpeNumber) { - ACPI_GPE_LEVEL_INFO GpeInfo; + UINT32 GpeNumberIndex; + ACPI_GPE_NUMBER_INFO *GpeInfo; - FUNCTION_TRACE ("EvGpeDispatch"); + ACPI_FUNCTION_TRACE ("EvGpeDispatch"); - /* - * Valid GPE number? - */ - if (AcpiGbl_GpeValid[GpeNumber] == ACPI_GPE_INVALID) + GpeNumberIndex = AcpiEvGetGpeNumberIndex (GpeNumber); + if (GpeNumberIndex == ACPI_GPE_INVALID) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Invalid GPE bit [%X].\n", GpeNumber)); - return_VALUE (INTERRUPT_NOT_HANDLED); + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Invalid event, GPE[%X].\n", GpeNumber)); + return_VALUE (ACPI_INTERRUPT_NOT_HANDLED); } /* - * Disable the GPE. + * We don't have to worry about mutex on GpeInfo because we are + * executing at interrupt level. */ - AcpiHwDisableGpe (GpeNumber); - - GpeInfo = AcpiGbl_GpeInfo [GpeNumber]; + GpeInfo = &AcpiGbl_GpeNumberInfo [GpeNumberIndex]; /* - * Edge-Triggered? - * --------------- * If edge-triggered, clear the GPE status bit now. Note that * level-triggered events are cleared after the GPE is serviced. */ - if (GpeInfo.Type & ACPI_EVENT_EDGE_TRIGGERED) + if (GpeInfo->Type & ACPI_EVENT_EDGE_TRIGGERED) { AcpiHwClearGpe (GpeNumber); } - /* - * Function Handler (e.g. EC)? - */ - if (GpeInfo.Handler) - { - /* Invoke function handler (at interrupt level). */ - - GpeInfo.Handler (GpeInfo.Context); - - /* Level-Triggered? */ - - if (GpeInfo.Type & ACPI_EVENT_LEVEL_TRIGGERED) - { - AcpiHwClearGpe (GpeNumber); - } - - /* Enable GPE */ - - AcpiHwEnableGpe (GpeNumber); - } /* - * Method Handler (e.g. _Exx/_Lxx)? + * Dispatch the GPE to either an installed handler, or the control + * method associated with this GPE (_Lxx or _Exx). + * If a handler exists, we invoke it and do not attempt to run the method. + * If there is neither a handler nor a method, we disable the level to + * prevent further events from coming in here. */ - else if (GpeInfo.MethodHandle) + if (GpeInfo->Handler) + { + /* Invoke the installed handler (at interrupt level) */ + + GpeInfo->Handler (GpeInfo->Context); + } + else if (GpeInfo->MethodHandle) { - if (ACPI_FAILURE(AcpiOsQueueForExecution (OSD_PRIORITY_GPE, - AcpiEvAsynchExecuteGpeMethod, (void*) GpeNumber))) + /* + * Execute the method associated with the GPE. + */ + if (ACPI_FAILURE (AcpiOsQueueForExecution (OSD_PRIORITY_GPE, + AcpiEvAsynchExecuteGpeMethod, + ACPI_TO_POINTER (GpeNumber)))) { + ACPI_REPORT_ERROR (("AcpiEvGpeDispatch: Unable to queue handler for GPE[%X], disabling event\n", GpeNumber)); + /* - * Shoudn't occur, but if it does report an error. Note that - * the GPE will remain disabled until the ACPI Core Subsystem - * is restarted, or the handler is removed/reinstalled. + * Disable the GPE on error. The GPE will remain disabled until the ACPI + * Core Subsystem is restarted, or the handler is reinstalled. */ - REPORT_ERROR (("AcpiEvGpeDispatch: Unable to queue handler for GPE bit [%X]\n", GpeNumber)); + AcpiHwDisableGpe (GpeNumber); } } - - /* - * No Handler? Report an error and leave the GPE disabled. - */ else { - REPORT_ERROR (("AcpiEvGpeDispatch: No installed handler for GPE [%X]\n", GpeNumber)); + /* No handler or method to run! */ - /* Level-Triggered? */ + ACPI_REPORT_ERROR (("AcpiEvGpeDispatch: No handler or method for GPE[%X], disabling event\n", GpeNumber)); - if (GpeInfo.Type & ACPI_EVENT_LEVEL_TRIGGERED) - { - AcpiHwClearGpe (GpeNumber); - } + /* + * Disable the GPE. The GPE will remain disabled until the ACPI + * Core Subsystem is restarted, or the handler is reinstalled. + */ + AcpiHwDisableGpe (GpeNumber); + } + + /* + * It is now safe to clear level-triggered evnets. + */ + if (GpeInfo->Type & ACPI_EVENT_LEVEL_TRIGGERED) + { + AcpiHwClearGpe (GpeNumber); } - return_VALUE (INTERRUPT_HANDLED); + return_VALUE (ACPI_INTERRUPT_HANDLED); } |