162306a36Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
262306a36Sopenharmony_ci/******************************************************************************
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Module Name: evgpeblk - GPE block creation and initialization.
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("evgpeblk")
1762306a36Sopenharmony_ci#if (!ACPI_REDUCED_HARDWARE)	/* Entire module */
1862306a36Sopenharmony_ci/* Local prototypes */
1962306a36Sopenharmony_cistatic acpi_status
2062306a36Sopenharmony_ciacpi_ev_install_gpe_block(struct acpi_gpe_block_info *gpe_block,
2162306a36Sopenharmony_ci			  u32 interrupt_number);
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_cistatic acpi_status
2462306a36Sopenharmony_ciacpi_ev_create_gpe_info_blocks(struct acpi_gpe_block_info *gpe_block);
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci/*******************************************************************************
2762306a36Sopenharmony_ci *
2862306a36Sopenharmony_ci * FUNCTION:    acpi_ev_install_gpe_block
2962306a36Sopenharmony_ci *
3062306a36Sopenharmony_ci * PARAMETERS:  gpe_block               - New GPE block
3162306a36Sopenharmony_ci *              interrupt_number        - Xrupt to be associated with this
3262306a36Sopenharmony_ci *                                        GPE block
3362306a36Sopenharmony_ci *
3462306a36Sopenharmony_ci * RETURN:      Status
3562306a36Sopenharmony_ci *
3662306a36Sopenharmony_ci * DESCRIPTION: Install new GPE block with mutex support
3762306a36Sopenharmony_ci *
3862306a36Sopenharmony_ci ******************************************************************************/
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_cistatic acpi_status
4162306a36Sopenharmony_ciacpi_ev_install_gpe_block(struct acpi_gpe_block_info *gpe_block,
4262306a36Sopenharmony_ci			  u32 interrupt_number)
4362306a36Sopenharmony_ci{
4462306a36Sopenharmony_ci	struct acpi_gpe_block_info *next_gpe_block;
4562306a36Sopenharmony_ci	struct acpi_gpe_xrupt_info *gpe_xrupt_block;
4662306a36Sopenharmony_ci	acpi_status status;
4762306a36Sopenharmony_ci	acpi_cpu_flags flags;
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE(ev_install_gpe_block);
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci	status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
5262306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
5362306a36Sopenharmony_ci		return_ACPI_STATUS(status);
5462306a36Sopenharmony_ci	}
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	status =
5762306a36Sopenharmony_ci	    acpi_ev_get_gpe_xrupt_block(interrupt_number, &gpe_xrupt_block);
5862306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
5962306a36Sopenharmony_ci		goto unlock_and_exit;
6062306a36Sopenharmony_ci	}
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci	/* Install the new block at the end of the list with lock */
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci	flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
6562306a36Sopenharmony_ci	if (gpe_xrupt_block->gpe_block_list_head) {
6662306a36Sopenharmony_ci		next_gpe_block = gpe_xrupt_block->gpe_block_list_head;
6762306a36Sopenharmony_ci		while (next_gpe_block->next) {
6862306a36Sopenharmony_ci			next_gpe_block = next_gpe_block->next;
6962306a36Sopenharmony_ci		}
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci		next_gpe_block->next = gpe_block;
7262306a36Sopenharmony_ci		gpe_block->previous = next_gpe_block;
7362306a36Sopenharmony_ci	} else {
7462306a36Sopenharmony_ci		gpe_xrupt_block->gpe_block_list_head = gpe_block;
7562306a36Sopenharmony_ci	}
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	gpe_block->xrupt_block = gpe_xrupt_block;
7862306a36Sopenharmony_ci	acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ciunlock_and_exit:
8162306a36Sopenharmony_ci	(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
8262306a36Sopenharmony_ci	return_ACPI_STATUS(status);
8362306a36Sopenharmony_ci}
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci/*******************************************************************************
8662306a36Sopenharmony_ci *
8762306a36Sopenharmony_ci * FUNCTION:    acpi_ev_delete_gpe_block
8862306a36Sopenharmony_ci *
8962306a36Sopenharmony_ci * PARAMETERS:  gpe_block           - Existing GPE block
9062306a36Sopenharmony_ci *
9162306a36Sopenharmony_ci * RETURN:      Status
9262306a36Sopenharmony_ci *
9362306a36Sopenharmony_ci * DESCRIPTION: Remove a GPE block
9462306a36Sopenharmony_ci *
9562306a36Sopenharmony_ci ******************************************************************************/
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ciacpi_status acpi_ev_delete_gpe_block(struct acpi_gpe_block_info *gpe_block)
9862306a36Sopenharmony_ci{
9962306a36Sopenharmony_ci	acpi_status status;
10062306a36Sopenharmony_ci	acpi_cpu_flags flags;
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE(ev_install_gpe_block);
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
10562306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
10662306a36Sopenharmony_ci		return_ACPI_STATUS(status);
10762306a36Sopenharmony_ci	}
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	/* Disable all GPEs in this block */
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	status =
11262306a36Sopenharmony_ci	    acpi_hw_disable_gpe_block(gpe_block->xrupt_block, gpe_block, NULL);
11362306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
11462306a36Sopenharmony_ci		return_ACPI_STATUS(status);
11562306a36Sopenharmony_ci	}
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	if (!gpe_block->previous && !gpe_block->next) {
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci		/* This is the last gpe_block on this interrupt */
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci		status = acpi_ev_delete_gpe_xrupt(gpe_block->xrupt_block);
12262306a36Sopenharmony_ci		if (ACPI_FAILURE(status)) {
12362306a36Sopenharmony_ci			goto unlock_and_exit;
12462306a36Sopenharmony_ci		}
12562306a36Sopenharmony_ci	} else {
12662306a36Sopenharmony_ci		/* Remove the block on this interrupt with lock */
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci		flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
12962306a36Sopenharmony_ci		if (gpe_block->previous) {
13062306a36Sopenharmony_ci			gpe_block->previous->next = gpe_block->next;
13162306a36Sopenharmony_ci		} else {
13262306a36Sopenharmony_ci			gpe_block->xrupt_block->gpe_block_list_head =
13362306a36Sopenharmony_ci			    gpe_block->next;
13462306a36Sopenharmony_ci		}
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci		if (gpe_block->next) {
13762306a36Sopenharmony_ci			gpe_block->next->previous = gpe_block->previous;
13862306a36Sopenharmony_ci		}
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci		acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
14162306a36Sopenharmony_ci	}
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	acpi_current_gpe_count -= gpe_block->gpe_count;
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	/* Free the gpe_block */
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	ACPI_FREE(gpe_block->register_info);
14862306a36Sopenharmony_ci	ACPI_FREE(gpe_block->event_info);
14962306a36Sopenharmony_ci	ACPI_FREE(gpe_block);
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ciunlock_and_exit:
15262306a36Sopenharmony_ci	status = acpi_ut_release_mutex(ACPI_MTX_EVENTS);
15362306a36Sopenharmony_ci	return_ACPI_STATUS(status);
15462306a36Sopenharmony_ci}
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci/*******************************************************************************
15762306a36Sopenharmony_ci *
15862306a36Sopenharmony_ci * FUNCTION:    acpi_ev_create_gpe_info_blocks
15962306a36Sopenharmony_ci *
16062306a36Sopenharmony_ci * PARAMETERS:  gpe_block   - New GPE block
16162306a36Sopenharmony_ci *
16262306a36Sopenharmony_ci * RETURN:      Status
16362306a36Sopenharmony_ci *
16462306a36Sopenharmony_ci * DESCRIPTION: Create the register_info and event_info blocks for this GPE block
16562306a36Sopenharmony_ci *
16662306a36Sopenharmony_ci ******************************************************************************/
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_cistatic acpi_status
16962306a36Sopenharmony_ciacpi_ev_create_gpe_info_blocks(struct acpi_gpe_block_info *gpe_block)
17062306a36Sopenharmony_ci{
17162306a36Sopenharmony_ci	struct acpi_gpe_register_info *gpe_register_info = NULL;
17262306a36Sopenharmony_ci	struct acpi_gpe_event_info *gpe_event_info = NULL;
17362306a36Sopenharmony_ci	struct acpi_gpe_event_info *this_event;
17462306a36Sopenharmony_ci	struct acpi_gpe_register_info *this_register;
17562306a36Sopenharmony_ci	u32 i;
17662306a36Sopenharmony_ci	u32 j;
17762306a36Sopenharmony_ci	acpi_status status;
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE(ev_create_gpe_info_blocks);
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	/* Allocate the GPE register information block */
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	gpe_register_info = ACPI_ALLOCATE_ZEROED((acpi_size)gpe_block->
18462306a36Sopenharmony_ci						 register_count *
18562306a36Sopenharmony_ci						 sizeof(struct
18662306a36Sopenharmony_ci							acpi_gpe_register_info));
18762306a36Sopenharmony_ci	if (!gpe_register_info) {
18862306a36Sopenharmony_ci		ACPI_ERROR((AE_INFO,
18962306a36Sopenharmony_ci			    "Could not allocate the GpeRegisterInfo table"));
19062306a36Sopenharmony_ci		return_ACPI_STATUS(AE_NO_MEMORY);
19162306a36Sopenharmony_ci	}
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	/*
19462306a36Sopenharmony_ci	 * Allocate the GPE event_info block. There are eight distinct GPEs
19562306a36Sopenharmony_ci	 * per register. Initialization to zeros is sufficient.
19662306a36Sopenharmony_ci	 */
19762306a36Sopenharmony_ci	gpe_event_info = ACPI_ALLOCATE_ZEROED((acpi_size)gpe_block->gpe_count *
19862306a36Sopenharmony_ci					      sizeof(struct
19962306a36Sopenharmony_ci						     acpi_gpe_event_info));
20062306a36Sopenharmony_ci	if (!gpe_event_info) {
20162306a36Sopenharmony_ci		ACPI_ERROR((AE_INFO,
20262306a36Sopenharmony_ci			    "Could not allocate the GpeEventInfo table"));
20362306a36Sopenharmony_ci		status = AE_NO_MEMORY;
20462306a36Sopenharmony_ci		goto error_exit;
20562306a36Sopenharmony_ci	}
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	/* Save the new Info arrays in the GPE block */
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	gpe_block->register_info = gpe_register_info;
21062306a36Sopenharmony_ci	gpe_block->event_info = gpe_event_info;
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	/*
21362306a36Sopenharmony_ci	 * Initialize the GPE Register and Event structures. A goal of these
21462306a36Sopenharmony_ci	 * tables is to hide the fact that there are two separate GPE register
21562306a36Sopenharmony_ci	 * sets in a given GPE hardware block, the status registers occupy the
21662306a36Sopenharmony_ci	 * first half, and the enable registers occupy the second half.
21762306a36Sopenharmony_ci	 */
21862306a36Sopenharmony_ci	this_register = gpe_register_info;
21962306a36Sopenharmony_ci	this_event = gpe_event_info;
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	for (i = 0; i < gpe_block->register_count; i++) {
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci		/* Init the register_info for this GPE register (8 GPEs) */
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci		this_register->base_gpe_number = (u16)
22662306a36Sopenharmony_ci		    (gpe_block->block_base_number +
22762306a36Sopenharmony_ci		     (i * ACPI_GPE_REGISTER_WIDTH));
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci		this_register->status_address.address = gpe_block->address + i;
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci		this_register->enable_address.address =
23262306a36Sopenharmony_ci		    gpe_block->address + i + gpe_block->register_count;
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci		this_register->status_address.space_id = gpe_block->space_id;
23562306a36Sopenharmony_ci		this_register->enable_address.space_id = gpe_block->space_id;
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci		/* Init the event_info for each GPE within this register */
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci		for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) {
24062306a36Sopenharmony_ci			this_event->gpe_number =
24162306a36Sopenharmony_ci			    (u8) (this_register->base_gpe_number + j);
24262306a36Sopenharmony_ci			this_event->register_info = this_register;
24362306a36Sopenharmony_ci			this_event++;
24462306a36Sopenharmony_ci		}
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci		/* Disable all GPEs within this register */
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci		status = acpi_hw_gpe_write(0x00, &this_register->enable_address);
24962306a36Sopenharmony_ci		if (ACPI_FAILURE(status)) {
25062306a36Sopenharmony_ci			goto error_exit;
25162306a36Sopenharmony_ci		}
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci		/* Clear any pending GPE events within this register */
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci		status = acpi_hw_gpe_write(0xFF, &this_register->status_address);
25662306a36Sopenharmony_ci		if (ACPI_FAILURE(status)) {
25762306a36Sopenharmony_ci			goto error_exit;
25862306a36Sopenharmony_ci		}
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci		this_register++;
26162306a36Sopenharmony_ci	}
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	return_ACPI_STATUS(AE_OK);
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_cierror_exit:
26662306a36Sopenharmony_ci	if (gpe_register_info) {
26762306a36Sopenharmony_ci		ACPI_FREE(gpe_register_info);
26862306a36Sopenharmony_ci	}
26962306a36Sopenharmony_ci	if (gpe_event_info) {
27062306a36Sopenharmony_ci		ACPI_FREE(gpe_event_info);
27162306a36Sopenharmony_ci	}
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	return_ACPI_STATUS(status);
27462306a36Sopenharmony_ci}
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci/*******************************************************************************
27762306a36Sopenharmony_ci *
27862306a36Sopenharmony_ci * FUNCTION:    acpi_ev_create_gpe_block
27962306a36Sopenharmony_ci *
28062306a36Sopenharmony_ci * PARAMETERS:  gpe_device          - Handle to the parent GPE block
28162306a36Sopenharmony_ci *              gpe_block_address   - Address and space_ID
28262306a36Sopenharmony_ci *              register_count      - Number of GPE register pairs in the block
28362306a36Sopenharmony_ci *              gpe_block_base_number - Starting GPE number for the block
28462306a36Sopenharmony_ci *              interrupt_number    - H/W interrupt for the block
28562306a36Sopenharmony_ci *              return_gpe_block    - Where the new block descriptor is returned
28662306a36Sopenharmony_ci *
28762306a36Sopenharmony_ci * RETURN:      Status
28862306a36Sopenharmony_ci *
28962306a36Sopenharmony_ci * DESCRIPTION: Create and Install a block of GPE registers. All GPEs within
29062306a36Sopenharmony_ci *              the block are disabled at exit.
29162306a36Sopenharmony_ci *              Note: Assumes namespace is locked.
29262306a36Sopenharmony_ci *
29362306a36Sopenharmony_ci ******************************************************************************/
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ciacpi_status
29662306a36Sopenharmony_ciacpi_ev_create_gpe_block(struct acpi_namespace_node *gpe_device,
29762306a36Sopenharmony_ci			 u64 address,
29862306a36Sopenharmony_ci			 u8 space_id,
29962306a36Sopenharmony_ci			 u32 register_count,
30062306a36Sopenharmony_ci			 u16 gpe_block_base_number,
30162306a36Sopenharmony_ci			 u32 interrupt_number,
30262306a36Sopenharmony_ci			 struct acpi_gpe_block_info **return_gpe_block)
30362306a36Sopenharmony_ci{
30462306a36Sopenharmony_ci	acpi_status status;
30562306a36Sopenharmony_ci	struct acpi_gpe_block_info *gpe_block;
30662306a36Sopenharmony_ci	struct acpi_gpe_walk_info walk_info;
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE(ev_create_gpe_block);
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	if (!register_count) {
31162306a36Sopenharmony_ci		return_ACPI_STATUS(AE_OK);
31262306a36Sopenharmony_ci	}
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	/* Validate the space_ID */
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	if ((space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) &&
31762306a36Sopenharmony_ci	    (space_id != ACPI_ADR_SPACE_SYSTEM_IO)) {
31862306a36Sopenharmony_ci		ACPI_ERROR((AE_INFO,
31962306a36Sopenharmony_ci			    "Unsupported address space: 0x%X", space_id));
32062306a36Sopenharmony_ci		return_ACPI_STATUS(AE_SUPPORT);
32162306a36Sopenharmony_ci	}
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci	if (space_id == ACPI_ADR_SPACE_SYSTEM_IO) {
32462306a36Sopenharmony_ci		status = acpi_hw_validate_io_block(address,
32562306a36Sopenharmony_ci						   ACPI_GPE_REGISTER_WIDTH,
32662306a36Sopenharmony_ci						   register_count);
32762306a36Sopenharmony_ci		if (ACPI_FAILURE(status))
32862306a36Sopenharmony_ci			return_ACPI_STATUS(status);
32962306a36Sopenharmony_ci	}
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	/* Allocate a new GPE block */
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	gpe_block = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_gpe_block_info));
33462306a36Sopenharmony_ci	if (!gpe_block) {
33562306a36Sopenharmony_ci		return_ACPI_STATUS(AE_NO_MEMORY);
33662306a36Sopenharmony_ci	}
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci	/* Initialize the new GPE block */
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	gpe_block->address = address;
34162306a36Sopenharmony_ci	gpe_block->space_id = space_id;
34262306a36Sopenharmony_ci	gpe_block->node = gpe_device;
34362306a36Sopenharmony_ci	gpe_block->gpe_count = (u16)(register_count * ACPI_GPE_REGISTER_WIDTH);
34462306a36Sopenharmony_ci	gpe_block->initialized = FALSE;
34562306a36Sopenharmony_ci	gpe_block->register_count = register_count;
34662306a36Sopenharmony_ci	gpe_block->block_base_number = gpe_block_base_number;
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	/*
34962306a36Sopenharmony_ci	 * Create the register_info and event_info sub-structures
35062306a36Sopenharmony_ci	 * Note: disables and clears all GPEs in the block
35162306a36Sopenharmony_ci	 */
35262306a36Sopenharmony_ci	status = acpi_ev_create_gpe_info_blocks(gpe_block);
35362306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
35462306a36Sopenharmony_ci		ACPI_FREE(gpe_block);
35562306a36Sopenharmony_ci		return_ACPI_STATUS(status);
35662306a36Sopenharmony_ci	}
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci	/* Install the new block in the global lists */
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci	status = acpi_ev_install_gpe_block(gpe_block, interrupt_number);
36162306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
36262306a36Sopenharmony_ci		ACPI_FREE(gpe_block->register_info);
36362306a36Sopenharmony_ci		ACPI_FREE(gpe_block->event_info);
36462306a36Sopenharmony_ci		ACPI_FREE(gpe_block);
36562306a36Sopenharmony_ci		return_ACPI_STATUS(status);
36662306a36Sopenharmony_ci	}
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci	acpi_gbl_all_gpes_initialized = FALSE;
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	/* Find all GPE methods (_Lxx or_Exx) for this block */
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci	walk_info.gpe_block = gpe_block;
37362306a36Sopenharmony_ci	walk_info.gpe_device = gpe_device;
37462306a36Sopenharmony_ci	walk_info.execute_by_owner_id = FALSE;
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci	(void)acpi_ns_walk_namespace(ACPI_TYPE_METHOD, gpe_device,
37762306a36Sopenharmony_ci				     ACPI_UINT32_MAX, ACPI_NS_WALK_NO_UNLOCK,
37862306a36Sopenharmony_ci				     acpi_ev_match_gpe_method, NULL, &walk_info,
37962306a36Sopenharmony_ci				     NULL);
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci	/* Return the new block */
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci	if (return_gpe_block) {
38462306a36Sopenharmony_ci		(*return_gpe_block) = gpe_block;
38562306a36Sopenharmony_ci	}
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT,
38862306a36Sopenharmony_ci			      "    Initialized GPE %02X to %02X [%4.4s] %u regs on interrupt 0x%X%s\n",
38962306a36Sopenharmony_ci			      (u32)gpe_block->block_base_number,
39062306a36Sopenharmony_ci			      (u32)(gpe_block->block_base_number +
39162306a36Sopenharmony_ci				    (gpe_block->gpe_count - 1)),
39262306a36Sopenharmony_ci			      gpe_device->name.ascii, gpe_block->register_count,
39362306a36Sopenharmony_ci			      interrupt_number,
39462306a36Sopenharmony_ci			      interrupt_number ==
39562306a36Sopenharmony_ci			      acpi_gbl_FADT.sci_interrupt ? " (SCI)" : ""));
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci	/* Update global count of currently available GPEs */
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	acpi_current_gpe_count += gpe_block->gpe_count;
40062306a36Sopenharmony_ci	return_ACPI_STATUS(AE_OK);
40162306a36Sopenharmony_ci}
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci/*******************************************************************************
40462306a36Sopenharmony_ci *
40562306a36Sopenharmony_ci * FUNCTION:    acpi_ev_initialize_gpe_block
40662306a36Sopenharmony_ci *
40762306a36Sopenharmony_ci * PARAMETERS:  acpi_gpe_callback
40862306a36Sopenharmony_ci *
40962306a36Sopenharmony_ci * RETURN:      Status
41062306a36Sopenharmony_ci *
41162306a36Sopenharmony_ci * DESCRIPTION: Initialize and enable a GPE block. Enable GPEs that have
41262306a36Sopenharmony_ci *              associated methods.
41362306a36Sopenharmony_ci *              Note: Assumes namespace is locked.
41462306a36Sopenharmony_ci *
41562306a36Sopenharmony_ci ******************************************************************************/
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ciacpi_status
41862306a36Sopenharmony_ciacpi_ev_initialize_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
41962306a36Sopenharmony_ci			     struct acpi_gpe_block_info *gpe_block,
42062306a36Sopenharmony_ci			     void *context)
42162306a36Sopenharmony_ci{
42262306a36Sopenharmony_ci	acpi_status status;
42362306a36Sopenharmony_ci	struct acpi_gpe_event_info *gpe_event_info;
42462306a36Sopenharmony_ci	u32 gpe_enabled_count;
42562306a36Sopenharmony_ci	u32 gpe_index;
42662306a36Sopenharmony_ci	u32 i;
42762306a36Sopenharmony_ci	u32 j;
42862306a36Sopenharmony_ci	u8 *is_polling_needed = context;
42962306a36Sopenharmony_ci	ACPI_ERROR_ONLY(u32 gpe_number);
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE(ev_initialize_gpe_block);
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci	/*
43462306a36Sopenharmony_ci	 * Ignore a null GPE block (e.g., if no GPE block 1 exists), and
43562306a36Sopenharmony_ci	 * any GPE blocks that have been initialized already.
43662306a36Sopenharmony_ci	 */
43762306a36Sopenharmony_ci	if (!gpe_block || gpe_block->initialized) {
43862306a36Sopenharmony_ci		return_ACPI_STATUS(AE_OK);
43962306a36Sopenharmony_ci	}
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci	/*
44262306a36Sopenharmony_ci	 * Enable all GPEs that have a corresponding method and have the
44362306a36Sopenharmony_ci	 * ACPI_GPE_CAN_WAKE flag unset. Any other GPEs within this block
44462306a36Sopenharmony_ci	 * must be enabled via the acpi_enable_gpe() interface.
44562306a36Sopenharmony_ci	 */
44662306a36Sopenharmony_ci	gpe_enabled_count = 0;
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci	for (i = 0; i < gpe_block->register_count; i++) {
44962306a36Sopenharmony_ci		for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) {
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci			/* Get the info block for this particular GPE */
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci			gpe_index = (i * ACPI_GPE_REGISTER_WIDTH) + j;
45462306a36Sopenharmony_ci			gpe_event_info = &gpe_block->event_info[gpe_index];
45562306a36Sopenharmony_ci			ACPI_ERROR_ONLY(gpe_number =
45662306a36Sopenharmony_ci					gpe_block->block_base_number +
45762306a36Sopenharmony_ci					gpe_index);
45862306a36Sopenharmony_ci			gpe_event_info->flags |= ACPI_GPE_INITIALIZED;
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci			/*
46162306a36Sopenharmony_ci			 * Ignore GPEs that have no corresponding _Lxx/_Exx method
46262306a36Sopenharmony_ci			 * and GPEs that are used for wakeup
46362306a36Sopenharmony_ci			 */
46462306a36Sopenharmony_ci			if ((ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) !=
46562306a36Sopenharmony_ci			     ACPI_GPE_DISPATCH_METHOD)
46662306a36Sopenharmony_ci			    || (gpe_event_info->flags & ACPI_GPE_CAN_WAKE)) {
46762306a36Sopenharmony_ci				continue;
46862306a36Sopenharmony_ci			}
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci			status = acpi_ev_add_gpe_reference(gpe_event_info, FALSE);
47162306a36Sopenharmony_ci			if (ACPI_FAILURE(status)) {
47262306a36Sopenharmony_ci				ACPI_EXCEPTION((AE_INFO, status,
47362306a36Sopenharmony_ci					"Could not enable GPE 0x%02X",
47462306a36Sopenharmony_ci					gpe_number));
47562306a36Sopenharmony_ci				continue;
47662306a36Sopenharmony_ci			}
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci			gpe_event_info->flags |= ACPI_GPE_AUTO_ENABLED;
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci			if (is_polling_needed &&
48162306a36Sopenharmony_ci			    ACPI_GPE_IS_POLLING_NEEDED(gpe_event_info)) {
48262306a36Sopenharmony_ci				*is_polling_needed = TRUE;
48362306a36Sopenharmony_ci			}
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci			gpe_enabled_count++;
48662306a36Sopenharmony_ci		}
48762306a36Sopenharmony_ci	}
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci	if (gpe_enabled_count) {
49062306a36Sopenharmony_ci		ACPI_INFO(("Enabled %u GPEs in block %02X to %02X",
49162306a36Sopenharmony_ci			   gpe_enabled_count, (u32)gpe_block->block_base_number,
49262306a36Sopenharmony_ci			   (u32)(gpe_block->block_base_number +
49362306a36Sopenharmony_ci				 (gpe_block->gpe_count - 1))));
49462306a36Sopenharmony_ci	}
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci	gpe_block->initialized = TRUE;
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci	return_ACPI_STATUS(AE_OK);
49962306a36Sopenharmony_ci}
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci#endif				/* !ACPI_REDUCED_HARDWARE */
502