/******************************************************************************1*2* Module Name: evgpeutil - GPE utilities3*4*****************************************************************************/56/*7* Copyright (C) 2000 - 2011, Intel Corp.8* All rights reserved.9*10* Redistribution and use in source and binary forms, with or without11* modification, are permitted provided that the following conditions12* are met:13* 1. Redistributions of source code must retain the above copyright14* notice, this list of conditions, and the following disclaimer,15* without modification.16* 2. Redistributions in binary form must reproduce at minimum a disclaimer17* substantially similar to the "NO WARRANTY" disclaimer below18* ("Disclaimer") and any redistribution must be conditioned upon19* including a substantially similar Disclaimer requirement for further20* binary redistribution.21* 3. Neither the names of the above-listed copyright holders nor the names22* of any contributors may be used to endorse or promote products derived23* from this software without specific prior written permission.24*25* Alternatively, this software may be distributed under the terms of the26* GNU General Public License ("GPL") version 2 as published by the Free27* Software Foundation.28*29* NO WARRANTY30* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS31* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT32* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR33* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT34* HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL35* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS36* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)37* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,38* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING39* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE40* POSSIBILITY OF SUCH DAMAGES.41*/4243#include <acpi/acpi.h>44#include "accommon.h"45#include "acevents.h"4647#define _COMPONENT ACPI_EVENTS48ACPI_MODULE_NAME("evgpeutil")4950/*******************************************************************************51*52* FUNCTION: acpi_ev_walk_gpe_list53*54* PARAMETERS: gpe_walk_callback - Routine called for each GPE block55* Context - Value passed to callback56*57* RETURN: Status58*59* DESCRIPTION: Walk the GPE lists.60*61******************************************************************************/62acpi_status63acpi_ev_walk_gpe_list(acpi_gpe_callback gpe_walk_callback, void *context)64{65struct acpi_gpe_block_info *gpe_block;66struct acpi_gpe_xrupt_info *gpe_xrupt_info;67acpi_status status = AE_OK;68acpi_cpu_flags flags;6970ACPI_FUNCTION_TRACE(ev_walk_gpe_list);7172flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);7374/* Walk the interrupt level descriptor list */7576gpe_xrupt_info = acpi_gbl_gpe_xrupt_list_head;77while (gpe_xrupt_info) {7879/* Walk all Gpe Blocks attached to this interrupt level */8081gpe_block = gpe_xrupt_info->gpe_block_list_head;82while (gpe_block) {8384/* One callback per GPE block */8586status =87gpe_walk_callback(gpe_xrupt_info, gpe_block,88context);89if (ACPI_FAILURE(status)) {90if (status == AE_CTRL_END) { /* Callback abort */91status = AE_OK;92}93goto unlock_and_exit;94}9596gpe_block = gpe_block->next;97}9899gpe_xrupt_info = gpe_xrupt_info->next;100}101102unlock_and_exit:103acpi_os_release_lock(acpi_gbl_gpe_lock, flags);104return_ACPI_STATUS(status);105}106107/*******************************************************************************108*109* FUNCTION: acpi_ev_valid_gpe_event110*111* PARAMETERS: gpe_event_info - Info for this GPE112*113* RETURN: TRUE if the gpe_event is valid114*115* DESCRIPTION: Validate a GPE event. DO NOT CALL FROM INTERRUPT LEVEL.116* Should be called only when the GPE lists are semaphore locked117* and not subject to change.118*119******************************************************************************/120121u8 acpi_ev_valid_gpe_event(struct acpi_gpe_event_info *gpe_event_info)122{123struct acpi_gpe_xrupt_info *gpe_xrupt_block;124struct acpi_gpe_block_info *gpe_block;125126ACPI_FUNCTION_ENTRY();127128/* No need for spin lock since we are not changing any list elements */129130/* Walk the GPE interrupt levels */131132gpe_xrupt_block = acpi_gbl_gpe_xrupt_list_head;133while (gpe_xrupt_block) {134gpe_block = gpe_xrupt_block->gpe_block_list_head;135136/* Walk the GPE blocks on this interrupt level */137138while (gpe_block) {139if ((&gpe_block->event_info[0] <= gpe_event_info) &&140(&gpe_block->event_info[gpe_block->gpe_count] >141gpe_event_info)) {142return (TRUE);143}144145gpe_block = gpe_block->next;146}147148gpe_xrupt_block = gpe_xrupt_block->next;149}150151return (FALSE);152}153154/*******************************************************************************155*156* FUNCTION: acpi_ev_get_gpe_device157*158* PARAMETERS: GPE_WALK_CALLBACK159*160* RETURN: Status161*162* DESCRIPTION: Matches the input GPE index (0-current_gpe_count) with a GPE163* block device. NULL if the GPE is one of the FADT-defined GPEs.164*165******************************************************************************/166167acpi_status168acpi_ev_get_gpe_device(struct acpi_gpe_xrupt_info *gpe_xrupt_info,169struct acpi_gpe_block_info *gpe_block, void *context)170{171struct acpi_gpe_device_info *info = context;172173/* Increment Index by the number of GPEs in this block */174175info->next_block_base_index += gpe_block->gpe_count;176177if (info->index < info->next_block_base_index) {178/*179* The GPE index is within this block, get the node. Leave the node180* NULL for the FADT-defined GPEs181*/182if ((gpe_block->node)->type == ACPI_TYPE_DEVICE) {183info->gpe_device = gpe_block->node;184}185186info->status = AE_OK;187return (AE_CTRL_END);188}189190return (AE_OK);191}192193/*******************************************************************************194*195* FUNCTION: acpi_ev_get_gpe_xrupt_block196*197* PARAMETERS: interrupt_number - Interrupt for a GPE block198*199* RETURN: A GPE interrupt block200*201* DESCRIPTION: Get or Create a GPE interrupt block. There is one interrupt202* block per unique interrupt level used for GPEs. Should be203* called only when the GPE lists are semaphore locked and not204* subject to change.205*206******************************************************************************/207208struct acpi_gpe_xrupt_info *acpi_ev_get_gpe_xrupt_block(u32 interrupt_number)209{210struct acpi_gpe_xrupt_info *next_gpe_xrupt;211struct acpi_gpe_xrupt_info *gpe_xrupt;212acpi_status status;213acpi_cpu_flags flags;214215ACPI_FUNCTION_TRACE(ev_get_gpe_xrupt_block);216217/* No need for lock since we are not changing any list elements here */218219next_gpe_xrupt = acpi_gbl_gpe_xrupt_list_head;220while (next_gpe_xrupt) {221if (next_gpe_xrupt->interrupt_number == interrupt_number) {222return_PTR(next_gpe_xrupt);223}224225next_gpe_xrupt = next_gpe_xrupt->next;226}227228/* Not found, must allocate a new xrupt descriptor */229230gpe_xrupt = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_gpe_xrupt_info));231if (!gpe_xrupt) {232return_PTR(NULL);233}234235gpe_xrupt->interrupt_number = interrupt_number;236237/* Install new interrupt descriptor with spin lock */238239flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);240if (acpi_gbl_gpe_xrupt_list_head) {241next_gpe_xrupt = acpi_gbl_gpe_xrupt_list_head;242while (next_gpe_xrupt->next) {243next_gpe_xrupt = next_gpe_xrupt->next;244}245246next_gpe_xrupt->next = gpe_xrupt;247gpe_xrupt->previous = next_gpe_xrupt;248} else {249acpi_gbl_gpe_xrupt_list_head = gpe_xrupt;250}251acpi_os_release_lock(acpi_gbl_gpe_lock, flags);252253/* Install new interrupt handler if not SCI_INT */254255if (interrupt_number != acpi_gbl_FADT.sci_interrupt) {256status = acpi_os_install_interrupt_handler(interrupt_number,257acpi_ev_gpe_xrupt_handler,258gpe_xrupt);259if (ACPI_FAILURE(status)) {260ACPI_ERROR((AE_INFO,261"Could not install GPE interrupt handler at level 0x%X",262interrupt_number));263return_PTR(NULL);264}265}266267return_PTR(gpe_xrupt);268}269270/*******************************************************************************271*272* FUNCTION: acpi_ev_delete_gpe_xrupt273*274* PARAMETERS: gpe_xrupt - A GPE interrupt info block275*276* RETURN: Status277*278* DESCRIPTION: Remove and free a gpe_xrupt block. Remove an associated279* interrupt handler if not the SCI interrupt.280*281******************************************************************************/282283acpi_status acpi_ev_delete_gpe_xrupt(struct acpi_gpe_xrupt_info *gpe_xrupt)284{285acpi_status status;286acpi_cpu_flags flags;287288ACPI_FUNCTION_TRACE(ev_delete_gpe_xrupt);289290/* We never want to remove the SCI interrupt handler */291292if (gpe_xrupt->interrupt_number == acpi_gbl_FADT.sci_interrupt) {293gpe_xrupt->gpe_block_list_head = NULL;294return_ACPI_STATUS(AE_OK);295}296297/* Disable this interrupt */298299status =300acpi_os_remove_interrupt_handler(gpe_xrupt->interrupt_number,301acpi_ev_gpe_xrupt_handler);302if (ACPI_FAILURE(status)) {303return_ACPI_STATUS(status);304}305306/* Unlink the interrupt block with lock */307308flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);309if (gpe_xrupt->previous) {310gpe_xrupt->previous->next = gpe_xrupt->next;311} else {312/* No previous, update list head */313314acpi_gbl_gpe_xrupt_list_head = gpe_xrupt->next;315}316317if (gpe_xrupt->next) {318gpe_xrupt->next->previous = gpe_xrupt->previous;319}320acpi_os_release_lock(acpi_gbl_gpe_lock, flags);321322/* Free the block */323324ACPI_FREE(gpe_xrupt);325return_ACPI_STATUS(AE_OK);326}327328/*******************************************************************************329*330* FUNCTION: acpi_ev_delete_gpe_handlers331*332* PARAMETERS: gpe_xrupt_info - GPE Interrupt info333* gpe_block - Gpe Block info334*335* RETURN: Status336*337* DESCRIPTION: Delete all Handler objects found in the GPE data structs.338* Used only prior to termination.339*340******************************************************************************/341342acpi_status343acpi_ev_delete_gpe_handlers(struct acpi_gpe_xrupt_info *gpe_xrupt_info,344struct acpi_gpe_block_info *gpe_block,345void *context)346{347struct acpi_gpe_event_info *gpe_event_info;348u32 i;349u32 j;350351ACPI_FUNCTION_TRACE(ev_delete_gpe_handlers);352353/* Examine each GPE Register within the block */354355for (i = 0; i < gpe_block->register_count; i++) {356357/* Now look at the individual GPEs in this byte register */358359for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) {360gpe_event_info = &gpe_block->event_info[((acpi_size) i *361ACPI_GPE_REGISTER_WIDTH)362+ j];363364if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) ==365ACPI_GPE_DISPATCH_HANDLER) {366ACPI_FREE(gpe_event_info->dispatch.handler);367gpe_event_info->dispatch.handler = NULL;368gpe_event_info->flags &=369~ACPI_GPE_DISPATCH_MASK;370}371}372}373374return_ACPI_STATUS(AE_OK);375}376377378