162306a36Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
262306a36Sopenharmony_ci/******************************************************************************
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Module Name: evgpe - General Purpose Event handling and dispatch
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Copyright (C) 2000 - 2023, Intel Corp.
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci *****************************************************************************/
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <acpi/acpi.h>
1162306a36Sopenharmony_ci#include "accommon.h"
1262306a36Sopenharmony_ci#include "acevents.h"
1362306a36Sopenharmony_ci#include "acnamesp.h"
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#define _COMPONENT          ACPI_EVENTS
1662306a36Sopenharmony_ciACPI_MODULE_NAME("evgpe")
1762306a36Sopenharmony_ci#if (!ACPI_REDUCED_HARDWARE)	/* Entire module */
1862306a36Sopenharmony_ci/* Local prototypes */
1962306a36Sopenharmony_cistatic void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context);
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_cistatic void ACPI_SYSTEM_XFACE acpi_ev_asynch_enable_gpe(void *context);
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci/*******************************************************************************
2462306a36Sopenharmony_ci *
2562306a36Sopenharmony_ci * FUNCTION:    acpi_ev_update_gpe_enable_mask
2662306a36Sopenharmony_ci *
2762306a36Sopenharmony_ci * PARAMETERS:  gpe_event_info          - GPE to update
2862306a36Sopenharmony_ci *
2962306a36Sopenharmony_ci * RETURN:      Status
3062306a36Sopenharmony_ci *
3162306a36Sopenharmony_ci * DESCRIPTION: Updates GPE register enable mask based upon whether there are
3262306a36Sopenharmony_ci *              runtime references to this GPE
3362306a36Sopenharmony_ci *
3462306a36Sopenharmony_ci ******************************************************************************/
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ciacpi_status
3762306a36Sopenharmony_ciacpi_ev_update_gpe_enable_mask(struct acpi_gpe_event_info *gpe_event_info)
3862306a36Sopenharmony_ci{
3962306a36Sopenharmony_ci	struct acpi_gpe_register_info *gpe_register_info;
4062306a36Sopenharmony_ci	u32 register_bit;
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE(ev_update_gpe_enable_mask);
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci	gpe_register_info = gpe_event_info->register_info;
4562306a36Sopenharmony_ci	if (!gpe_register_info) {
4662306a36Sopenharmony_ci		return_ACPI_STATUS(AE_NOT_EXIST);
4762306a36Sopenharmony_ci	}
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci	register_bit = acpi_hw_get_gpe_register_bit(gpe_event_info);
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci	/* Clear the run bit up front */
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci	ACPI_CLEAR_BIT(gpe_register_info->enable_for_run, register_bit);
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	/* Set the mask bit only if there are references to this GPE */
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci	if (gpe_event_info->runtime_count) {
5862306a36Sopenharmony_ci		ACPI_SET_BIT(gpe_register_info->enable_for_run,
5962306a36Sopenharmony_ci			     (u8)register_bit);
6062306a36Sopenharmony_ci	}
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci	gpe_register_info->enable_mask = gpe_register_info->enable_for_run;
6362306a36Sopenharmony_ci	return_ACPI_STATUS(AE_OK);
6462306a36Sopenharmony_ci}
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci/*******************************************************************************
6762306a36Sopenharmony_ci *
6862306a36Sopenharmony_ci * FUNCTION:    acpi_ev_enable_gpe
6962306a36Sopenharmony_ci *
7062306a36Sopenharmony_ci * PARAMETERS:  gpe_event_info          - GPE to enable
7162306a36Sopenharmony_ci *
7262306a36Sopenharmony_ci * RETURN:      Status
7362306a36Sopenharmony_ci *
7462306a36Sopenharmony_ci * DESCRIPTION: Enable a GPE.
7562306a36Sopenharmony_ci *
7662306a36Sopenharmony_ci ******************************************************************************/
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ciacpi_status acpi_ev_enable_gpe(struct acpi_gpe_event_info *gpe_event_info)
7962306a36Sopenharmony_ci{
8062306a36Sopenharmony_ci	acpi_status status;
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE(ev_enable_gpe);
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	/* Enable the requested GPE */
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_ENABLE);
8762306a36Sopenharmony_ci	return_ACPI_STATUS(status);
8862306a36Sopenharmony_ci}
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci/*******************************************************************************
9162306a36Sopenharmony_ci *
9262306a36Sopenharmony_ci * FUNCTION:    acpi_ev_mask_gpe
9362306a36Sopenharmony_ci *
9462306a36Sopenharmony_ci * PARAMETERS:  gpe_event_info          - GPE to be blocked/unblocked
9562306a36Sopenharmony_ci *              is_masked               - Whether the GPE is masked or not
9662306a36Sopenharmony_ci *
9762306a36Sopenharmony_ci * RETURN:      Status
9862306a36Sopenharmony_ci *
9962306a36Sopenharmony_ci * DESCRIPTION: Unconditionally mask/unmask a GPE during runtime.
10062306a36Sopenharmony_ci *
10162306a36Sopenharmony_ci ******************************************************************************/
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ciacpi_status
10462306a36Sopenharmony_ciacpi_ev_mask_gpe(struct acpi_gpe_event_info *gpe_event_info, u8 is_masked)
10562306a36Sopenharmony_ci{
10662306a36Sopenharmony_ci	struct acpi_gpe_register_info *gpe_register_info;
10762306a36Sopenharmony_ci	u32 register_bit;
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE(ev_mask_gpe);
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	gpe_register_info = gpe_event_info->register_info;
11262306a36Sopenharmony_ci	if (!gpe_register_info) {
11362306a36Sopenharmony_ci		return_ACPI_STATUS(AE_NOT_EXIST);
11462306a36Sopenharmony_ci	}
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	register_bit = acpi_hw_get_gpe_register_bit(gpe_event_info);
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	/* Perform the action */
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	if (is_masked) {
12162306a36Sopenharmony_ci		if (register_bit & gpe_register_info->mask_for_run) {
12262306a36Sopenharmony_ci			return_ACPI_STATUS(AE_BAD_PARAMETER);
12362306a36Sopenharmony_ci		}
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci		(void)acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_DISABLE);
12662306a36Sopenharmony_ci		ACPI_SET_BIT(gpe_register_info->mask_for_run, (u8)register_bit);
12762306a36Sopenharmony_ci	} else {
12862306a36Sopenharmony_ci		if (!(register_bit & gpe_register_info->mask_for_run)) {
12962306a36Sopenharmony_ci			return_ACPI_STATUS(AE_BAD_PARAMETER);
13062306a36Sopenharmony_ci		}
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci		ACPI_CLEAR_BIT(gpe_register_info->mask_for_run,
13362306a36Sopenharmony_ci			       (u8)register_bit);
13462306a36Sopenharmony_ci		if (gpe_event_info->runtime_count
13562306a36Sopenharmony_ci		    && !gpe_event_info->disable_for_dispatch) {
13662306a36Sopenharmony_ci			(void)acpi_hw_low_set_gpe(gpe_event_info,
13762306a36Sopenharmony_ci						  ACPI_GPE_ENABLE);
13862306a36Sopenharmony_ci		}
13962306a36Sopenharmony_ci	}
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	return_ACPI_STATUS(AE_OK);
14262306a36Sopenharmony_ci}
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci/*******************************************************************************
14562306a36Sopenharmony_ci *
14662306a36Sopenharmony_ci * FUNCTION:    acpi_ev_add_gpe_reference
14762306a36Sopenharmony_ci *
14862306a36Sopenharmony_ci * PARAMETERS:  gpe_event_info          - Add a reference to this GPE
14962306a36Sopenharmony_ci *              clear_on_enable         - Clear GPE status before enabling it
15062306a36Sopenharmony_ci *
15162306a36Sopenharmony_ci * RETURN:      Status
15262306a36Sopenharmony_ci *
15362306a36Sopenharmony_ci * DESCRIPTION: Add a reference to a GPE. On the first reference, the GPE is
15462306a36Sopenharmony_ci *              hardware-enabled.
15562306a36Sopenharmony_ci *
15662306a36Sopenharmony_ci ******************************************************************************/
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ciacpi_status
15962306a36Sopenharmony_ciacpi_ev_add_gpe_reference(struct acpi_gpe_event_info *gpe_event_info,
16062306a36Sopenharmony_ci			  u8 clear_on_enable)
16162306a36Sopenharmony_ci{
16262306a36Sopenharmony_ci	acpi_status status = AE_OK;
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE(ev_add_gpe_reference);
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	if (gpe_event_info->runtime_count == ACPI_UINT8_MAX) {
16762306a36Sopenharmony_ci		return_ACPI_STATUS(AE_LIMIT);
16862306a36Sopenharmony_ci	}
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	gpe_event_info->runtime_count++;
17162306a36Sopenharmony_ci	if (gpe_event_info->runtime_count == 1) {
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci		/* Enable on first reference */
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci		if (clear_on_enable) {
17662306a36Sopenharmony_ci			(void)acpi_hw_clear_gpe(gpe_event_info);
17762306a36Sopenharmony_ci		}
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci		status = acpi_ev_update_gpe_enable_mask(gpe_event_info);
18062306a36Sopenharmony_ci		if (ACPI_SUCCESS(status)) {
18162306a36Sopenharmony_ci			status = acpi_ev_enable_gpe(gpe_event_info);
18262306a36Sopenharmony_ci		}
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci		if (ACPI_FAILURE(status)) {
18562306a36Sopenharmony_ci			gpe_event_info->runtime_count--;
18662306a36Sopenharmony_ci		}
18762306a36Sopenharmony_ci	}
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	return_ACPI_STATUS(status);
19062306a36Sopenharmony_ci}
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci/*******************************************************************************
19362306a36Sopenharmony_ci *
19462306a36Sopenharmony_ci * FUNCTION:    acpi_ev_remove_gpe_reference
19562306a36Sopenharmony_ci *
19662306a36Sopenharmony_ci * PARAMETERS:  gpe_event_info          - Remove a reference to this GPE
19762306a36Sopenharmony_ci *
19862306a36Sopenharmony_ci * RETURN:      Status
19962306a36Sopenharmony_ci *
20062306a36Sopenharmony_ci * DESCRIPTION: Remove a reference to a GPE. When the last reference is
20162306a36Sopenharmony_ci *              removed, the GPE is hardware-disabled.
20262306a36Sopenharmony_ci *
20362306a36Sopenharmony_ci ******************************************************************************/
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ciacpi_status
20662306a36Sopenharmony_ciacpi_ev_remove_gpe_reference(struct acpi_gpe_event_info *gpe_event_info)
20762306a36Sopenharmony_ci{
20862306a36Sopenharmony_ci	acpi_status status = AE_OK;
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE(ev_remove_gpe_reference);
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	if (!gpe_event_info->runtime_count) {
21362306a36Sopenharmony_ci		return_ACPI_STATUS(AE_LIMIT);
21462306a36Sopenharmony_ci	}
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	gpe_event_info->runtime_count--;
21762306a36Sopenharmony_ci	if (!gpe_event_info->runtime_count) {
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci		/* Disable on last reference */
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci		status = acpi_ev_update_gpe_enable_mask(gpe_event_info);
22262306a36Sopenharmony_ci		if (ACPI_SUCCESS(status)) {
22362306a36Sopenharmony_ci			status =
22462306a36Sopenharmony_ci			    acpi_hw_low_set_gpe(gpe_event_info,
22562306a36Sopenharmony_ci						ACPI_GPE_DISABLE);
22662306a36Sopenharmony_ci		}
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci		if (ACPI_FAILURE(status)) {
22962306a36Sopenharmony_ci			gpe_event_info->runtime_count++;
23062306a36Sopenharmony_ci		}
23162306a36Sopenharmony_ci	}
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	return_ACPI_STATUS(status);
23462306a36Sopenharmony_ci}
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci/*******************************************************************************
23762306a36Sopenharmony_ci *
23862306a36Sopenharmony_ci * FUNCTION:    acpi_ev_low_get_gpe_info
23962306a36Sopenharmony_ci *
24062306a36Sopenharmony_ci * PARAMETERS:  gpe_number          - Raw GPE number
24162306a36Sopenharmony_ci *              gpe_block           - A GPE info block
24262306a36Sopenharmony_ci *
24362306a36Sopenharmony_ci * RETURN:      A GPE event_info struct. NULL if not a valid GPE (The gpe_number
24462306a36Sopenharmony_ci *              is not within the specified GPE block)
24562306a36Sopenharmony_ci *
24662306a36Sopenharmony_ci * DESCRIPTION: Returns the event_info struct associated with this GPE. This is
24762306a36Sopenharmony_ci *              the low-level implementation of ev_get_gpe_event_info.
24862306a36Sopenharmony_ci *
24962306a36Sopenharmony_ci ******************************************************************************/
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_cistruct acpi_gpe_event_info *acpi_ev_low_get_gpe_info(u32 gpe_number,
25262306a36Sopenharmony_ci						     struct acpi_gpe_block_info
25362306a36Sopenharmony_ci						     *gpe_block)
25462306a36Sopenharmony_ci{
25562306a36Sopenharmony_ci	u32 gpe_index;
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	/*
25862306a36Sopenharmony_ci	 * Validate that the gpe_number is within the specified gpe_block.
25962306a36Sopenharmony_ci	 * (Two steps)
26062306a36Sopenharmony_ci	 */
26162306a36Sopenharmony_ci	if (!gpe_block || (gpe_number < gpe_block->block_base_number)) {
26262306a36Sopenharmony_ci		return (NULL);
26362306a36Sopenharmony_ci	}
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	gpe_index = gpe_number - gpe_block->block_base_number;
26662306a36Sopenharmony_ci	if (gpe_index >= gpe_block->gpe_count) {
26762306a36Sopenharmony_ci		return (NULL);
26862306a36Sopenharmony_ci	}
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci	return (&gpe_block->event_info[gpe_index]);
27162306a36Sopenharmony_ci}
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci/*******************************************************************************
27562306a36Sopenharmony_ci *
27662306a36Sopenharmony_ci * FUNCTION:    acpi_ev_get_gpe_event_info
27762306a36Sopenharmony_ci *
27862306a36Sopenharmony_ci * PARAMETERS:  gpe_device          - Device node. NULL for GPE0/GPE1
27962306a36Sopenharmony_ci *              gpe_number          - Raw GPE number
28062306a36Sopenharmony_ci *
28162306a36Sopenharmony_ci * RETURN:      A GPE event_info struct. NULL if not a valid GPE
28262306a36Sopenharmony_ci *
28362306a36Sopenharmony_ci * DESCRIPTION: Returns the event_info struct associated with this GPE.
28462306a36Sopenharmony_ci *              Validates the gpe_block and the gpe_number
28562306a36Sopenharmony_ci *
28662306a36Sopenharmony_ci *              Should be called only when the GPE lists are semaphore locked
28762306a36Sopenharmony_ci *              and not subject to change.
28862306a36Sopenharmony_ci *
28962306a36Sopenharmony_ci ******************************************************************************/
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_cistruct acpi_gpe_event_info *acpi_ev_get_gpe_event_info(acpi_handle gpe_device,
29262306a36Sopenharmony_ci						       u32 gpe_number)
29362306a36Sopenharmony_ci{
29462306a36Sopenharmony_ci	union acpi_operand_object *obj_desc;
29562306a36Sopenharmony_ci	struct acpi_gpe_event_info *gpe_info;
29662306a36Sopenharmony_ci	u32 i;
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci	ACPI_FUNCTION_ENTRY();
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	/* A NULL gpe_device means use the FADT-defined GPE block(s) */
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci	if (!gpe_device) {
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci		/* Examine GPE Block 0 and 1 (These blocks are permanent) */
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci		for (i = 0; i < ACPI_MAX_GPE_BLOCKS; i++) {
30762306a36Sopenharmony_ci			gpe_info = acpi_ev_low_get_gpe_info(gpe_number,
30862306a36Sopenharmony_ci							    acpi_gbl_gpe_fadt_blocks
30962306a36Sopenharmony_ci							    [i]);
31062306a36Sopenharmony_ci			if (gpe_info) {
31162306a36Sopenharmony_ci				return (gpe_info);
31262306a36Sopenharmony_ci			}
31362306a36Sopenharmony_ci		}
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci		/* The gpe_number was not in the range of either FADT GPE block */
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci		return (NULL);
31862306a36Sopenharmony_ci	}
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci	/* A Non-NULL gpe_device means this is a GPE Block Device */
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci	obj_desc =
32362306a36Sopenharmony_ci	    acpi_ns_get_attached_object((struct acpi_namespace_node *)
32462306a36Sopenharmony_ci					       gpe_device);
32562306a36Sopenharmony_ci	if (!obj_desc || !obj_desc->device.gpe_block) {
32662306a36Sopenharmony_ci		return (NULL);
32762306a36Sopenharmony_ci	}
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	return (acpi_ev_low_get_gpe_info
33062306a36Sopenharmony_ci		(gpe_number, obj_desc->device.gpe_block));
33162306a36Sopenharmony_ci}
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci/*******************************************************************************
33462306a36Sopenharmony_ci *
33562306a36Sopenharmony_ci * FUNCTION:    acpi_ev_gpe_detect
33662306a36Sopenharmony_ci *
33762306a36Sopenharmony_ci * PARAMETERS:  gpe_xrupt_list      - Interrupt block for this interrupt.
33862306a36Sopenharmony_ci *                                    Can have multiple GPE blocks attached.
33962306a36Sopenharmony_ci *
34062306a36Sopenharmony_ci * RETURN:      INTERRUPT_HANDLED or INTERRUPT_NOT_HANDLED
34162306a36Sopenharmony_ci *
34262306a36Sopenharmony_ci * DESCRIPTION: Detect if any GP events have occurred. This function is
34362306a36Sopenharmony_ci *              executed at interrupt level.
34462306a36Sopenharmony_ci *
34562306a36Sopenharmony_ci ******************************************************************************/
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ciu32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info *gpe_xrupt_list)
34862306a36Sopenharmony_ci{
34962306a36Sopenharmony_ci	struct acpi_gpe_block_info *gpe_block;
35062306a36Sopenharmony_ci	struct acpi_namespace_node *gpe_device;
35162306a36Sopenharmony_ci	struct acpi_gpe_register_info *gpe_register_info;
35262306a36Sopenharmony_ci	struct acpi_gpe_event_info *gpe_event_info;
35362306a36Sopenharmony_ci	u32 gpe_number;
35462306a36Sopenharmony_ci	u32 int_status = ACPI_INTERRUPT_NOT_HANDLED;
35562306a36Sopenharmony_ci	acpi_cpu_flags flags;
35662306a36Sopenharmony_ci	u32 i;
35762306a36Sopenharmony_ci	u32 j;
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	ACPI_FUNCTION_NAME(ev_gpe_detect);
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	/* Check for the case where there are no GPEs */
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	if (!gpe_xrupt_list) {
36462306a36Sopenharmony_ci		return (int_status);
36562306a36Sopenharmony_ci	}
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci	/*
36862306a36Sopenharmony_ci	 * We need to obtain the GPE lock for both the data structs and registers
36962306a36Sopenharmony_ci	 * Note: Not necessary to obtain the hardware lock, since the GPE
37062306a36Sopenharmony_ci	 * registers are owned by the gpe_lock.
37162306a36Sopenharmony_ci	 */
37262306a36Sopenharmony_ci	flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	/* Examine all GPE blocks attached to this interrupt level */
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci	gpe_block = gpe_xrupt_list->gpe_block_list_head;
37762306a36Sopenharmony_ci	while (gpe_block) {
37862306a36Sopenharmony_ci		gpe_device = gpe_block->node;
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci		/*
38162306a36Sopenharmony_ci		 * Read all of the 8-bit GPE status and enable registers in this GPE
38262306a36Sopenharmony_ci		 * block, saving all of them. Find all currently active GP events.
38362306a36Sopenharmony_ci		 */
38462306a36Sopenharmony_ci		for (i = 0; i < gpe_block->register_count; i++) {
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci			/* Get the next status/enable pair */
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci			gpe_register_info = &gpe_block->register_info[i];
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci			/*
39162306a36Sopenharmony_ci			 * Optimization: If there are no GPEs enabled within this
39262306a36Sopenharmony_ci			 * register, we can safely ignore the entire register.
39362306a36Sopenharmony_ci			 */
39462306a36Sopenharmony_ci			if (!(gpe_register_info->enable_for_run |
39562306a36Sopenharmony_ci			      gpe_register_info->enable_for_wake)) {
39662306a36Sopenharmony_ci				ACPI_DEBUG_PRINT((ACPI_DB_INTERRUPTS,
39762306a36Sopenharmony_ci						  "Ignore disabled registers for GPE %02X-%02X: "
39862306a36Sopenharmony_ci						  "RunEnable=%02X, WakeEnable=%02X\n",
39962306a36Sopenharmony_ci						  gpe_register_info->
40062306a36Sopenharmony_ci						  base_gpe_number,
40162306a36Sopenharmony_ci						  gpe_register_info->
40262306a36Sopenharmony_ci						  base_gpe_number +
40362306a36Sopenharmony_ci						  (ACPI_GPE_REGISTER_WIDTH - 1),
40462306a36Sopenharmony_ci						  gpe_register_info->
40562306a36Sopenharmony_ci						  enable_for_run,
40662306a36Sopenharmony_ci						  gpe_register_info->
40762306a36Sopenharmony_ci						  enable_for_wake));
40862306a36Sopenharmony_ci				continue;
40962306a36Sopenharmony_ci			}
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci			/* Now look at the individual GPEs in this byte register */
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci			for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) {
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci				/* Detect and dispatch one GPE bit */
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci				gpe_event_info =
41862306a36Sopenharmony_ci				    &gpe_block->
41962306a36Sopenharmony_ci				    event_info[((acpi_size)i *
42062306a36Sopenharmony_ci						ACPI_GPE_REGISTER_WIDTH) + j];
42162306a36Sopenharmony_ci				gpe_number =
42262306a36Sopenharmony_ci				    j + gpe_register_info->base_gpe_number;
42362306a36Sopenharmony_ci				acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
42462306a36Sopenharmony_ci				int_status |=
42562306a36Sopenharmony_ci				    acpi_ev_detect_gpe(gpe_device,
42662306a36Sopenharmony_ci						       gpe_event_info,
42762306a36Sopenharmony_ci						       gpe_number);
42862306a36Sopenharmony_ci				flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
42962306a36Sopenharmony_ci			}
43062306a36Sopenharmony_ci		}
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci		gpe_block = gpe_block->next;
43362306a36Sopenharmony_ci	}
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
43662306a36Sopenharmony_ci	return (int_status);
43762306a36Sopenharmony_ci}
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci/*******************************************************************************
44062306a36Sopenharmony_ci *
44162306a36Sopenharmony_ci * FUNCTION:    acpi_ev_asynch_execute_gpe_method
44262306a36Sopenharmony_ci *
44362306a36Sopenharmony_ci * PARAMETERS:  Context (gpe_event_info) - Info for this GPE
44462306a36Sopenharmony_ci *
44562306a36Sopenharmony_ci * RETURN:      None
44662306a36Sopenharmony_ci *
44762306a36Sopenharmony_ci * DESCRIPTION: Perform the actual execution of a GPE control method. This
44862306a36Sopenharmony_ci *              function is called from an invocation of acpi_os_execute and
44962306a36Sopenharmony_ci *              therefore does NOT execute at interrupt level - so that
45062306a36Sopenharmony_ci *              the control method itself is not executed in the context of
45162306a36Sopenharmony_ci *              an interrupt handler.
45262306a36Sopenharmony_ci *
45362306a36Sopenharmony_ci ******************************************************************************/
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_cistatic void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context)
45662306a36Sopenharmony_ci{
45762306a36Sopenharmony_ci	struct acpi_gpe_event_info *gpe_event_info = context;
45862306a36Sopenharmony_ci	acpi_status status = AE_OK;
45962306a36Sopenharmony_ci	struct acpi_evaluate_info *info;
46062306a36Sopenharmony_ci	struct acpi_gpe_notify_info *notify;
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE(ev_asynch_execute_gpe_method);
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci	/* Do the correct dispatch - normal method or implicit notify */
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	switch (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags)) {
46762306a36Sopenharmony_ci	case ACPI_GPE_DISPATCH_NOTIFY:
46862306a36Sopenharmony_ci		/*
46962306a36Sopenharmony_ci		 * Implicit notify.
47062306a36Sopenharmony_ci		 * Dispatch a DEVICE_WAKE notify to the appropriate handler.
47162306a36Sopenharmony_ci		 * NOTE: the request is queued for execution after this method
47262306a36Sopenharmony_ci		 * completes. The notify handlers are NOT invoked synchronously
47362306a36Sopenharmony_ci		 * from this thread -- because handlers may in turn run other
47462306a36Sopenharmony_ci		 * control methods.
47562306a36Sopenharmony_ci		 *
47662306a36Sopenharmony_ci		 * June 2012: Expand implicit notify mechanism to support
47762306a36Sopenharmony_ci		 * notifies on multiple device objects.
47862306a36Sopenharmony_ci		 */
47962306a36Sopenharmony_ci		notify = gpe_event_info->dispatch.notify_list;
48062306a36Sopenharmony_ci		while (ACPI_SUCCESS(status) && notify) {
48162306a36Sopenharmony_ci			status =
48262306a36Sopenharmony_ci			    acpi_ev_queue_notify_request(notify->device_node,
48362306a36Sopenharmony_ci							 ACPI_NOTIFY_DEVICE_WAKE);
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci			notify = notify->next;
48662306a36Sopenharmony_ci		}
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci		break;
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	case ACPI_GPE_DISPATCH_METHOD:
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci		/* Allocate the evaluation information block */
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci		info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info));
49562306a36Sopenharmony_ci		if (!info) {
49662306a36Sopenharmony_ci			status = AE_NO_MEMORY;
49762306a36Sopenharmony_ci		} else {
49862306a36Sopenharmony_ci			/*
49962306a36Sopenharmony_ci			 * Invoke the GPE Method (_Lxx, _Exx) i.e., evaluate the
50062306a36Sopenharmony_ci			 * _Lxx/_Exx control method that corresponds to this GPE
50162306a36Sopenharmony_ci			 */
50262306a36Sopenharmony_ci			info->prefix_node =
50362306a36Sopenharmony_ci			    gpe_event_info->dispatch.method_node;
50462306a36Sopenharmony_ci			info->flags = ACPI_IGNORE_RETURN_VALUE;
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci			status = acpi_ns_evaluate(info);
50762306a36Sopenharmony_ci			ACPI_FREE(info);
50862306a36Sopenharmony_ci		}
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci		if (ACPI_FAILURE(status)) {
51162306a36Sopenharmony_ci			ACPI_EXCEPTION((AE_INFO, status,
51262306a36Sopenharmony_ci					"while evaluating GPE method [%4.4s]",
51362306a36Sopenharmony_ci					acpi_ut_get_node_name(gpe_event_info->
51462306a36Sopenharmony_ci							      dispatch.
51562306a36Sopenharmony_ci							      method_node)));
51662306a36Sopenharmony_ci		}
51762306a36Sopenharmony_ci		break;
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci	default:
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci		goto error_exit;	/* Should never happen */
52262306a36Sopenharmony_ci	}
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci	/* Defer enabling of GPE until all notify handlers are done */
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci	status = acpi_os_execute(OSL_NOTIFY_HANDLER,
52762306a36Sopenharmony_ci				 acpi_ev_asynch_enable_gpe, gpe_event_info);
52862306a36Sopenharmony_ci	if (ACPI_SUCCESS(status)) {
52962306a36Sopenharmony_ci		return_VOID;
53062306a36Sopenharmony_ci	}
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_cierror_exit:
53362306a36Sopenharmony_ci	acpi_ev_asynch_enable_gpe(gpe_event_info);
53462306a36Sopenharmony_ci	return_VOID;
53562306a36Sopenharmony_ci}
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci/*******************************************************************************
53962306a36Sopenharmony_ci *
54062306a36Sopenharmony_ci * FUNCTION:    acpi_ev_asynch_enable_gpe
54162306a36Sopenharmony_ci *
54262306a36Sopenharmony_ci * PARAMETERS:  Context (gpe_event_info) - Info for this GPE
54362306a36Sopenharmony_ci *              Callback from acpi_os_execute
54462306a36Sopenharmony_ci *
54562306a36Sopenharmony_ci * RETURN:      None
54662306a36Sopenharmony_ci *
54762306a36Sopenharmony_ci * DESCRIPTION: Asynchronous clear/enable for GPE. This allows the GPE to
54862306a36Sopenharmony_ci *              complete (i.e., finish execution of Notify)
54962306a36Sopenharmony_ci *
55062306a36Sopenharmony_ci ******************************************************************************/
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_cistatic void ACPI_SYSTEM_XFACE acpi_ev_asynch_enable_gpe(void *context)
55362306a36Sopenharmony_ci{
55462306a36Sopenharmony_ci	struct acpi_gpe_event_info *gpe_event_info = context;
55562306a36Sopenharmony_ci	acpi_cpu_flags flags;
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci	flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
55862306a36Sopenharmony_ci	(void)acpi_ev_finish_gpe(gpe_event_info);
55962306a36Sopenharmony_ci	acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci	return;
56262306a36Sopenharmony_ci}
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci/*******************************************************************************
56662306a36Sopenharmony_ci *
56762306a36Sopenharmony_ci * FUNCTION:    acpi_ev_finish_gpe
56862306a36Sopenharmony_ci *
56962306a36Sopenharmony_ci * PARAMETERS:  gpe_event_info      - Info for this GPE
57062306a36Sopenharmony_ci *
57162306a36Sopenharmony_ci * RETURN:      Status
57262306a36Sopenharmony_ci *
57362306a36Sopenharmony_ci * DESCRIPTION: Clear/Enable a GPE. Common code that is used after execution
57462306a36Sopenharmony_ci *              of a GPE method or a synchronous or asynchronous GPE handler.
57562306a36Sopenharmony_ci *
57662306a36Sopenharmony_ci ******************************************************************************/
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_ciacpi_status acpi_ev_finish_gpe(struct acpi_gpe_event_info *gpe_event_info)
57962306a36Sopenharmony_ci{
58062306a36Sopenharmony_ci	acpi_status status;
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci	if ((gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK) ==
58362306a36Sopenharmony_ci	    ACPI_GPE_LEVEL_TRIGGERED) {
58462306a36Sopenharmony_ci		/*
58562306a36Sopenharmony_ci		 * GPE is level-triggered, we clear the GPE status bit after
58662306a36Sopenharmony_ci		 * handling the event.
58762306a36Sopenharmony_ci		 */
58862306a36Sopenharmony_ci		status = acpi_hw_clear_gpe(gpe_event_info);
58962306a36Sopenharmony_ci		if (ACPI_FAILURE(status)) {
59062306a36Sopenharmony_ci			return (status);
59162306a36Sopenharmony_ci		}
59262306a36Sopenharmony_ci	}
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci	/*
59562306a36Sopenharmony_ci	 * Enable this GPE, conditionally. This means that the GPE will
59662306a36Sopenharmony_ci	 * only be physically enabled if the enable_mask bit is set
59762306a36Sopenharmony_ci	 * in the event_info.
59862306a36Sopenharmony_ci	 */
59962306a36Sopenharmony_ci	(void)acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_CONDITIONAL_ENABLE);
60062306a36Sopenharmony_ci	gpe_event_info->disable_for_dispatch = FALSE;
60162306a36Sopenharmony_ci	return (AE_OK);
60262306a36Sopenharmony_ci}
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci/*******************************************************************************
60662306a36Sopenharmony_ci *
60762306a36Sopenharmony_ci * FUNCTION:    acpi_ev_detect_gpe
60862306a36Sopenharmony_ci *
60962306a36Sopenharmony_ci * PARAMETERS:  gpe_device          - Device node. NULL for GPE0/GPE1
61062306a36Sopenharmony_ci *              gpe_event_info      - Info for this GPE
61162306a36Sopenharmony_ci *              gpe_number          - Number relative to the parent GPE block
61262306a36Sopenharmony_ci *
61362306a36Sopenharmony_ci * RETURN:      INTERRUPT_HANDLED or INTERRUPT_NOT_HANDLED
61462306a36Sopenharmony_ci *
61562306a36Sopenharmony_ci * DESCRIPTION: Detect and dispatch a General Purpose Event to either a function
61662306a36Sopenharmony_ci *              (e.g. EC) or method (e.g. _Lxx/_Exx) handler.
61762306a36Sopenharmony_ci * NOTE:        GPE is W1C, so it is possible to handle a single GPE from both
61862306a36Sopenharmony_ci *              task and irq context in parallel as long as the process to
61962306a36Sopenharmony_ci *              detect and mask the GPE is atomic.
62062306a36Sopenharmony_ci *              However the atomicity of ACPI_GPE_DISPATCH_RAW_HANDLER is
62162306a36Sopenharmony_ci *              dependent on the raw handler itself.
62262306a36Sopenharmony_ci *
62362306a36Sopenharmony_ci ******************************************************************************/
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ciu32
62662306a36Sopenharmony_ciacpi_ev_detect_gpe(struct acpi_namespace_node *gpe_device,
62762306a36Sopenharmony_ci		   struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number)
62862306a36Sopenharmony_ci{
62962306a36Sopenharmony_ci	u32 int_status = ACPI_INTERRUPT_NOT_HANDLED;
63062306a36Sopenharmony_ci	u8 enabled_status_byte;
63162306a36Sopenharmony_ci	u64 status_reg;
63262306a36Sopenharmony_ci	u64 enable_reg;
63362306a36Sopenharmony_ci	u32 register_bit;
63462306a36Sopenharmony_ci	struct acpi_gpe_register_info *gpe_register_info;
63562306a36Sopenharmony_ci	struct acpi_gpe_handler_info *gpe_handler_info;
63662306a36Sopenharmony_ci	acpi_cpu_flags flags;
63762306a36Sopenharmony_ci	acpi_status status;
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE(ev_gpe_detect);
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_ci	flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci	if (!gpe_event_info) {
64462306a36Sopenharmony_ci		gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
64562306a36Sopenharmony_ci		if (!gpe_event_info)
64662306a36Sopenharmony_ci			goto error_exit;
64762306a36Sopenharmony_ci	}
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_ci	/* Get the info block for the entire GPE register */
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_ci	gpe_register_info = gpe_event_info->register_info;
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_ci	/* Get the register bitmask for this GPE */
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_ci	register_bit = acpi_hw_get_gpe_register_bit(gpe_event_info);
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci	/* GPE currently enabled (enable bit == 1)? */
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_ci	status = acpi_hw_gpe_read(&enable_reg, &gpe_register_info->enable_address);
66062306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
66162306a36Sopenharmony_ci		goto error_exit;
66262306a36Sopenharmony_ci	}
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci	/* GPE currently active (status bit == 1)? */
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_ci	status = acpi_hw_gpe_read(&status_reg, &gpe_register_info->status_address);
66762306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
66862306a36Sopenharmony_ci		goto error_exit;
66962306a36Sopenharmony_ci	}
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_ci	/* Check if there is anything active at all in this GPE */
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_ci	ACPI_DEBUG_PRINT((ACPI_DB_INTERRUPTS,
67462306a36Sopenharmony_ci			  "Read registers for GPE %02X: Status=%02X, Enable=%02X, "
67562306a36Sopenharmony_ci			  "RunEnable=%02X, WakeEnable=%02X\n",
67662306a36Sopenharmony_ci			  gpe_number,
67762306a36Sopenharmony_ci			  (u32)(status_reg & register_bit),
67862306a36Sopenharmony_ci			  (u32)(enable_reg & register_bit),
67962306a36Sopenharmony_ci			  gpe_register_info->enable_for_run,
68062306a36Sopenharmony_ci			  gpe_register_info->enable_for_wake));
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_ci	enabled_status_byte = (u8)(status_reg & enable_reg);
68362306a36Sopenharmony_ci	if (!(enabled_status_byte & register_bit)) {
68462306a36Sopenharmony_ci		goto error_exit;
68562306a36Sopenharmony_ci	}
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_ci	/* Invoke global event handler if present */
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci	acpi_gpe_count++;
69062306a36Sopenharmony_ci	if (acpi_gbl_global_event_handler) {
69162306a36Sopenharmony_ci		acpi_gbl_global_event_handler(ACPI_EVENT_TYPE_GPE,
69262306a36Sopenharmony_ci					      gpe_device, gpe_number,
69362306a36Sopenharmony_ci					      acpi_gbl_global_event_handler_context);
69462306a36Sopenharmony_ci	}
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_ci	/* Found an active GPE */
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci	if (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) ==
69962306a36Sopenharmony_ci	    ACPI_GPE_DISPATCH_RAW_HANDLER) {
70062306a36Sopenharmony_ci
70162306a36Sopenharmony_ci		/* Dispatch the event to a raw handler */
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_ci		gpe_handler_info = gpe_event_info->dispatch.handler;
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_ci		/*
70662306a36Sopenharmony_ci		 * There is no protection around the namespace node
70762306a36Sopenharmony_ci		 * and the GPE handler to ensure a safe destruction
70862306a36Sopenharmony_ci		 * because:
70962306a36Sopenharmony_ci		 * 1. The namespace node is expected to always
71062306a36Sopenharmony_ci		 *    exist after loading a table.
71162306a36Sopenharmony_ci		 * 2. The GPE handler is expected to be flushed by
71262306a36Sopenharmony_ci		 *    acpi_os_wait_events_complete() before the
71362306a36Sopenharmony_ci		 *    destruction.
71462306a36Sopenharmony_ci		 */
71562306a36Sopenharmony_ci		acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
71662306a36Sopenharmony_ci		int_status |=
71762306a36Sopenharmony_ci		    gpe_handler_info->address(gpe_device, gpe_number,
71862306a36Sopenharmony_ci					      gpe_handler_info->context);
71962306a36Sopenharmony_ci		flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
72062306a36Sopenharmony_ci	} else {
72162306a36Sopenharmony_ci		/* Dispatch the event to a standard handler or method. */
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_ci		int_status |= acpi_ev_gpe_dispatch(gpe_device,
72462306a36Sopenharmony_ci						   gpe_event_info, gpe_number);
72562306a36Sopenharmony_ci	}
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_cierror_exit:
72862306a36Sopenharmony_ci	acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
72962306a36Sopenharmony_ci	return (int_status);
73062306a36Sopenharmony_ci}
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_ci/*******************************************************************************
73362306a36Sopenharmony_ci *
73462306a36Sopenharmony_ci * FUNCTION:    acpi_ev_gpe_dispatch
73562306a36Sopenharmony_ci *
73662306a36Sopenharmony_ci * PARAMETERS:  gpe_device          - Device node. NULL for GPE0/GPE1
73762306a36Sopenharmony_ci *              gpe_event_info      - Info for this GPE
73862306a36Sopenharmony_ci *              gpe_number          - Number relative to the parent GPE block
73962306a36Sopenharmony_ci *
74062306a36Sopenharmony_ci * RETURN:      INTERRUPT_HANDLED or INTERRUPT_NOT_HANDLED
74162306a36Sopenharmony_ci *
74262306a36Sopenharmony_ci * DESCRIPTION: Dispatch a General Purpose Event to either a function (e.g. EC)
74362306a36Sopenharmony_ci *              or method (e.g. _Lxx/_Exx) handler.
74462306a36Sopenharmony_ci *
74562306a36Sopenharmony_ci ******************************************************************************/
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ciu32
74862306a36Sopenharmony_ciacpi_ev_gpe_dispatch(struct acpi_namespace_node *gpe_device,
74962306a36Sopenharmony_ci		     struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number)
75062306a36Sopenharmony_ci{
75162306a36Sopenharmony_ci	acpi_status status;
75262306a36Sopenharmony_ci	u32 return_value;
75362306a36Sopenharmony_ci
75462306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE(ev_gpe_dispatch);
75562306a36Sopenharmony_ci
75662306a36Sopenharmony_ci	/*
75762306a36Sopenharmony_ci	 * Always disable the GPE so that it does not keep firing before
75862306a36Sopenharmony_ci	 * any asynchronous activity completes (either from the execution
75962306a36Sopenharmony_ci	 * of a GPE method or an asynchronous GPE handler.)
76062306a36Sopenharmony_ci	 *
76162306a36Sopenharmony_ci	 * If there is no handler or method to run, just disable the
76262306a36Sopenharmony_ci	 * GPE and leave it disabled permanently to prevent further such
76362306a36Sopenharmony_ci	 * pointless events from firing.
76462306a36Sopenharmony_ci	 */
76562306a36Sopenharmony_ci	status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_DISABLE);
76662306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
76762306a36Sopenharmony_ci		ACPI_EXCEPTION((AE_INFO, status,
76862306a36Sopenharmony_ci				"Unable to disable GPE %02X", gpe_number));
76962306a36Sopenharmony_ci		return_UINT32(ACPI_INTERRUPT_NOT_HANDLED);
77062306a36Sopenharmony_ci	}
77162306a36Sopenharmony_ci
77262306a36Sopenharmony_ci	/*
77362306a36Sopenharmony_ci	 * If edge-triggered, clear the GPE status bit now. Note that
77462306a36Sopenharmony_ci	 * level-triggered events are cleared after the GPE is serviced.
77562306a36Sopenharmony_ci	 */
77662306a36Sopenharmony_ci	if ((gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK) ==
77762306a36Sopenharmony_ci	    ACPI_GPE_EDGE_TRIGGERED) {
77862306a36Sopenharmony_ci		status = acpi_hw_clear_gpe(gpe_event_info);
77962306a36Sopenharmony_ci		if (ACPI_FAILURE(status)) {
78062306a36Sopenharmony_ci			ACPI_EXCEPTION((AE_INFO, status,
78162306a36Sopenharmony_ci					"Unable to clear GPE %02X",
78262306a36Sopenharmony_ci					gpe_number));
78362306a36Sopenharmony_ci			(void)acpi_hw_low_set_gpe(gpe_event_info,
78462306a36Sopenharmony_ci						  ACPI_GPE_CONDITIONAL_ENABLE);
78562306a36Sopenharmony_ci			return_UINT32(ACPI_INTERRUPT_NOT_HANDLED);
78662306a36Sopenharmony_ci		}
78762306a36Sopenharmony_ci	}
78862306a36Sopenharmony_ci
78962306a36Sopenharmony_ci	gpe_event_info->disable_for_dispatch = TRUE;
79062306a36Sopenharmony_ci
79162306a36Sopenharmony_ci	/*
79262306a36Sopenharmony_ci	 * Dispatch the GPE to either an installed handler or the control
79362306a36Sopenharmony_ci	 * method associated with this GPE (_Lxx or _Exx). If a handler
79462306a36Sopenharmony_ci	 * exists, we invoke it and do not attempt to run the method.
79562306a36Sopenharmony_ci	 * If there is neither a handler nor a method, leave the GPE
79662306a36Sopenharmony_ci	 * disabled.
79762306a36Sopenharmony_ci	 */
79862306a36Sopenharmony_ci	switch (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags)) {
79962306a36Sopenharmony_ci	case ACPI_GPE_DISPATCH_HANDLER:
80062306a36Sopenharmony_ci
80162306a36Sopenharmony_ci		/* Invoke the installed handler (at interrupt level) */
80262306a36Sopenharmony_ci
80362306a36Sopenharmony_ci		return_value =
80462306a36Sopenharmony_ci		    gpe_event_info->dispatch.handler->address(gpe_device,
80562306a36Sopenharmony_ci							      gpe_number,
80662306a36Sopenharmony_ci							      gpe_event_info->
80762306a36Sopenharmony_ci							      dispatch.handler->
80862306a36Sopenharmony_ci							      context);
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_ci		/* If requested, clear (if level-triggered) and re-enable the GPE */
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_ci		if (return_value & ACPI_REENABLE_GPE) {
81362306a36Sopenharmony_ci			(void)acpi_ev_finish_gpe(gpe_event_info);
81462306a36Sopenharmony_ci		}
81562306a36Sopenharmony_ci		break;
81662306a36Sopenharmony_ci
81762306a36Sopenharmony_ci	case ACPI_GPE_DISPATCH_METHOD:
81862306a36Sopenharmony_ci	case ACPI_GPE_DISPATCH_NOTIFY:
81962306a36Sopenharmony_ci		/*
82062306a36Sopenharmony_ci		 * Execute the method associated with the GPE
82162306a36Sopenharmony_ci		 * NOTE: Level-triggered GPEs are cleared after the method completes.
82262306a36Sopenharmony_ci		 */
82362306a36Sopenharmony_ci		status = acpi_os_execute(OSL_GPE_HANDLER,
82462306a36Sopenharmony_ci					 acpi_ev_asynch_execute_gpe_method,
82562306a36Sopenharmony_ci					 gpe_event_info);
82662306a36Sopenharmony_ci		if (ACPI_FAILURE(status)) {
82762306a36Sopenharmony_ci			ACPI_EXCEPTION((AE_INFO, status,
82862306a36Sopenharmony_ci					"Unable to queue handler for GPE %02X - event disabled",
82962306a36Sopenharmony_ci					gpe_number));
83062306a36Sopenharmony_ci		}
83162306a36Sopenharmony_ci		break;
83262306a36Sopenharmony_ci
83362306a36Sopenharmony_ci	default:
83462306a36Sopenharmony_ci		/*
83562306a36Sopenharmony_ci		 * No handler or method to run!
83662306a36Sopenharmony_ci		 * 03/2010: This case should no longer be possible. We will not allow
83762306a36Sopenharmony_ci		 * a GPE to be enabled if it has no handler or method.
83862306a36Sopenharmony_ci		 */
83962306a36Sopenharmony_ci		ACPI_ERROR((AE_INFO,
84062306a36Sopenharmony_ci			    "No handler or method for GPE %02X, disabling event",
84162306a36Sopenharmony_ci			    gpe_number));
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_ci		break;
84462306a36Sopenharmony_ci	}
84562306a36Sopenharmony_ci
84662306a36Sopenharmony_ci	return_UINT32(ACPI_INTERRUPT_HANDLED);
84762306a36Sopenharmony_ci}
84862306a36Sopenharmony_ci
84962306a36Sopenharmony_ci#endif				/* !ACPI_REDUCED_HARDWARE */
850