xref: /openbmc/linux/drivers/acpi/acpica/evgpeblk.c (revision 612c2932)
195857638SErik Schmauss // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
295b482a8SLen Brown /******************************************************************************
395b482a8SLen Brown  *
495b482a8SLen Brown  * Module Name: evgpeblk - GPE block creation and initialization.
595b482a8SLen Brown  *
6*612c2932SBob Moore  * Copyright (C) 2000 - 2023, Intel Corp.
795b482a8SLen Brown  *
895857638SErik Schmauss  *****************************************************************************/
995b482a8SLen Brown 
1095b482a8SLen Brown #include <acpi/acpi.h>
11e2f7a777SLen Brown #include "accommon.h"
12e2f7a777SLen Brown #include "acevents.h"
13e2f7a777SLen Brown #include "acnamesp.h"
1495b482a8SLen Brown 
1595b482a8SLen Brown #define _COMPONENT          ACPI_EVENTS
1695b482a8SLen Brown ACPI_MODULE_NAME("evgpeblk")
1733620c54SBob Moore #if (!ACPI_REDUCED_HARDWARE)	/* Entire module */
1895b482a8SLen Brown /* Local prototypes */
1995b482a8SLen Brown static acpi_status
2095b482a8SLen Brown acpi_ev_install_gpe_block(struct acpi_gpe_block_info *gpe_block,
2195b482a8SLen Brown 			  u32 interrupt_number);
2295b482a8SLen Brown 
2395b482a8SLen Brown static acpi_status
2495b482a8SLen Brown acpi_ev_create_gpe_info_blocks(struct acpi_gpe_block_info *gpe_block);
2595b482a8SLen Brown 
2695b482a8SLen Brown /*******************************************************************************
2795b482a8SLen Brown  *
2895b482a8SLen Brown  * FUNCTION:    acpi_ev_install_gpe_block
2995b482a8SLen Brown  *
3095b482a8SLen Brown  * PARAMETERS:  gpe_block               - New GPE block
3195b482a8SLen Brown  *              interrupt_number        - Xrupt to be associated with this
3295b482a8SLen Brown  *                                        GPE block
3395b482a8SLen Brown  *
3495b482a8SLen Brown  * RETURN:      Status
3595b482a8SLen Brown  *
3695b482a8SLen Brown  * DESCRIPTION: Install new GPE block with mutex support
3795b482a8SLen Brown  *
3895b482a8SLen Brown  ******************************************************************************/
3995b482a8SLen Brown 
4095b482a8SLen Brown static acpi_status
acpi_ev_install_gpe_block(struct acpi_gpe_block_info * gpe_block,u32 interrupt_number)4195b482a8SLen Brown acpi_ev_install_gpe_block(struct acpi_gpe_block_info *gpe_block,
4295b482a8SLen Brown 			  u32 interrupt_number)
4395b482a8SLen Brown {
4495b482a8SLen Brown 	struct acpi_gpe_block_info *next_gpe_block;
4595b482a8SLen Brown 	struct acpi_gpe_xrupt_info *gpe_xrupt_block;
4695b482a8SLen Brown 	acpi_status status;
4795b482a8SLen Brown 	acpi_cpu_flags flags;
4895b482a8SLen Brown 
4995b482a8SLen Brown 	ACPI_FUNCTION_TRACE(ev_install_gpe_block);
5095b482a8SLen Brown 
5195b482a8SLen Brown 	status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
5295b482a8SLen Brown 	if (ACPI_FAILURE(status)) {
5395b482a8SLen Brown 		return_ACPI_STATUS(status);
5495b482a8SLen Brown 	}
5595b482a8SLen Brown 
564bec3d80SBob Moore 	status =
574bec3d80SBob Moore 	    acpi_ev_get_gpe_xrupt_block(interrupt_number, &gpe_xrupt_block);
584bec3d80SBob Moore 	if (ACPI_FAILURE(status)) {
5995b482a8SLen Brown 		goto unlock_and_exit;
6095b482a8SLen Brown 	}
6195b482a8SLen Brown 
6295b482a8SLen Brown 	/* Install the new block at the end of the list with lock */
6395b482a8SLen Brown 
6495b482a8SLen Brown 	flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
6595b482a8SLen Brown 	if (gpe_xrupt_block->gpe_block_list_head) {
6695b482a8SLen Brown 		next_gpe_block = gpe_xrupt_block->gpe_block_list_head;
6795b482a8SLen Brown 		while (next_gpe_block->next) {
6895b482a8SLen Brown 			next_gpe_block = next_gpe_block->next;
6995b482a8SLen Brown 		}
7095b482a8SLen Brown 
7195b482a8SLen Brown 		next_gpe_block->next = gpe_block;
7295b482a8SLen Brown 		gpe_block->previous = next_gpe_block;
7395b482a8SLen Brown 	} else {
7495b482a8SLen Brown 		gpe_xrupt_block->gpe_block_list_head = gpe_block;
7595b482a8SLen Brown 	}
7695b482a8SLen Brown 
7795b482a8SLen Brown 	gpe_block->xrupt_block = gpe_xrupt_block;
7895b482a8SLen Brown 	acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
7995b482a8SLen Brown 
8095b482a8SLen Brown unlock_and_exit:
814bec3d80SBob Moore 	(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
8295b482a8SLen Brown 	return_ACPI_STATUS(status);
8395b482a8SLen Brown }
8495b482a8SLen Brown 
8595b482a8SLen Brown /*******************************************************************************
8695b482a8SLen Brown  *
8795b482a8SLen Brown  * FUNCTION:    acpi_ev_delete_gpe_block
8895b482a8SLen Brown  *
8995b482a8SLen Brown  * PARAMETERS:  gpe_block           - Existing GPE block
9095b482a8SLen Brown  *
9195b482a8SLen Brown  * RETURN:      Status
9295b482a8SLen Brown  *
9395b482a8SLen Brown  * DESCRIPTION: Remove a GPE block
9495b482a8SLen Brown  *
9595b482a8SLen Brown  ******************************************************************************/
9695b482a8SLen Brown 
acpi_ev_delete_gpe_block(struct acpi_gpe_block_info * gpe_block)9795b482a8SLen Brown acpi_status acpi_ev_delete_gpe_block(struct acpi_gpe_block_info *gpe_block)
9895b482a8SLen Brown {
9995b482a8SLen Brown 	acpi_status status;
10095b482a8SLen Brown 	acpi_cpu_flags flags;
10195b482a8SLen Brown 
10295b482a8SLen Brown 	ACPI_FUNCTION_TRACE(ev_install_gpe_block);
10395b482a8SLen Brown 
10495b482a8SLen Brown 	status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
10595b482a8SLen Brown 	if (ACPI_FAILURE(status)) {
10695b482a8SLen Brown 		return_ACPI_STATUS(status);
10795b482a8SLen Brown 	}
10895b482a8SLen Brown 
10995b482a8SLen Brown 	/* Disable all GPEs in this block */
11095b482a8SLen Brown 
11195b482a8SLen Brown 	status =
11295b482a8SLen Brown 	    acpi_hw_disable_gpe_block(gpe_block->xrupt_block, gpe_block, NULL);
113edc5935eSBob Moore 	if (ACPI_FAILURE(status)) {
114edc5935eSBob Moore 		return_ACPI_STATUS(status);
115edc5935eSBob Moore 	}
11695b482a8SLen Brown 
11795b482a8SLen Brown 	if (!gpe_block->previous && !gpe_block->next) {
11895b482a8SLen Brown 
11995b482a8SLen Brown 		/* This is the last gpe_block on this interrupt */
12095b482a8SLen Brown 
12195b482a8SLen Brown 		status = acpi_ev_delete_gpe_xrupt(gpe_block->xrupt_block);
12295b482a8SLen Brown 		if (ACPI_FAILURE(status)) {
12395b482a8SLen Brown 			goto unlock_and_exit;
12495b482a8SLen Brown 		}
12595b482a8SLen Brown 	} else {
12695b482a8SLen Brown 		/* Remove the block on this interrupt with lock */
12795b482a8SLen Brown 
12895b482a8SLen Brown 		flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
12995b482a8SLen Brown 		if (gpe_block->previous) {
13095b482a8SLen Brown 			gpe_block->previous->next = gpe_block->next;
13195b482a8SLen Brown 		} else {
13295b482a8SLen Brown 			gpe_block->xrupt_block->gpe_block_list_head =
13395b482a8SLen Brown 			    gpe_block->next;
13495b482a8SLen Brown 		}
13595b482a8SLen Brown 
13695b482a8SLen Brown 		if (gpe_block->next) {
13795b482a8SLen Brown 			gpe_block->next->previous = gpe_block->previous;
13895b482a8SLen Brown 		}
1391fad8738SBob Moore 
14095b482a8SLen Brown 		acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
14195b482a8SLen Brown 	}
14295b482a8SLen Brown 
1430f849d2cSLin Ming 	acpi_current_gpe_count -= gpe_block->gpe_count;
14495b482a8SLen Brown 
14595b482a8SLen Brown 	/* Free the gpe_block */
14695b482a8SLen Brown 
14795b482a8SLen Brown 	ACPI_FREE(gpe_block->register_info);
14895b482a8SLen Brown 	ACPI_FREE(gpe_block->event_info);
14995b482a8SLen Brown 	ACPI_FREE(gpe_block);
15095b482a8SLen Brown 
15195b482a8SLen Brown unlock_and_exit:
15295b482a8SLen Brown 	status = acpi_ut_release_mutex(ACPI_MTX_EVENTS);
15395b482a8SLen Brown 	return_ACPI_STATUS(status);
15495b482a8SLen Brown }
15595b482a8SLen Brown 
15695b482a8SLen Brown /*******************************************************************************
15795b482a8SLen Brown  *
15895b482a8SLen Brown  * FUNCTION:    acpi_ev_create_gpe_info_blocks
15995b482a8SLen Brown  *
16095b482a8SLen Brown  * PARAMETERS:  gpe_block   - New GPE block
16195b482a8SLen Brown  *
16295b482a8SLen Brown  * RETURN:      Status
16395b482a8SLen Brown  *
16495b482a8SLen Brown  * DESCRIPTION: Create the register_info and event_info blocks for this GPE block
16595b482a8SLen Brown  *
16695b482a8SLen Brown  ******************************************************************************/
16795b482a8SLen Brown 
16895b482a8SLen Brown static acpi_status
acpi_ev_create_gpe_info_blocks(struct acpi_gpe_block_info * gpe_block)16995b482a8SLen Brown acpi_ev_create_gpe_info_blocks(struct acpi_gpe_block_info *gpe_block)
17095b482a8SLen Brown {
17195b482a8SLen Brown 	struct acpi_gpe_register_info *gpe_register_info = NULL;
17295b482a8SLen Brown 	struct acpi_gpe_event_info *gpe_event_info = NULL;
17395b482a8SLen Brown 	struct acpi_gpe_event_info *this_event;
17495b482a8SLen Brown 	struct acpi_gpe_register_info *this_register;
17595b482a8SLen Brown 	u32 i;
17695b482a8SLen Brown 	u32 j;
17795b482a8SLen Brown 	acpi_status status;
17895b482a8SLen Brown 
17995b482a8SLen Brown 	ACPI_FUNCTION_TRACE(ev_create_gpe_info_blocks);
18095b482a8SLen Brown 
18195b482a8SLen Brown 	/* Allocate the GPE register information block */
18295b482a8SLen Brown 
18395b482a8SLen Brown 	gpe_register_info = ACPI_ALLOCATE_ZEROED((acpi_size)gpe_block->
18495b482a8SLen Brown 						 register_count *
18595b482a8SLen Brown 						 sizeof(struct
18695b482a8SLen Brown 							acpi_gpe_register_info));
18795b482a8SLen Brown 	if (!gpe_register_info) {
18895b482a8SLen Brown 		ACPI_ERROR((AE_INFO,
18995b482a8SLen Brown 			    "Could not allocate the GpeRegisterInfo table"));
19095b482a8SLen Brown 		return_ACPI_STATUS(AE_NO_MEMORY);
19195b482a8SLen Brown 	}
19295b482a8SLen Brown 
19395b482a8SLen Brown 	/*
19495b482a8SLen Brown 	 * Allocate the GPE event_info block. There are eight distinct GPEs
19595b482a8SLen Brown 	 * per register. Initialization to zeros is sufficient.
19695b482a8SLen Brown 	 */
1970f849d2cSLin Ming 	gpe_event_info = ACPI_ALLOCATE_ZEROED((acpi_size)gpe_block->gpe_count *
19895b482a8SLen Brown 					      sizeof(struct
19995b482a8SLen Brown 						     acpi_gpe_event_info));
20095b482a8SLen Brown 	if (!gpe_event_info) {
20195b482a8SLen Brown 		ACPI_ERROR((AE_INFO,
20295b482a8SLen Brown 			    "Could not allocate the GpeEventInfo table"));
20395b482a8SLen Brown 		status = AE_NO_MEMORY;
20495b482a8SLen Brown 		goto error_exit;
20595b482a8SLen Brown 	}
20695b482a8SLen Brown 
20795b482a8SLen Brown 	/* Save the new Info arrays in the GPE block */
20895b482a8SLen Brown 
20995b482a8SLen Brown 	gpe_block->register_info = gpe_register_info;
21095b482a8SLen Brown 	gpe_block->event_info = gpe_event_info;
21195b482a8SLen Brown 
21295b482a8SLen Brown 	/*
21395b482a8SLen Brown 	 * Initialize the GPE Register and Event structures. A goal of these
21495b482a8SLen Brown 	 * tables is to hide the fact that there are two separate GPE register
21595b482a8SLen Brown 	 * sets in a given GPE hardware block, the status registers occupy the
21695b482a8SLen Brown 	 * first half, and the enable registers occupy the second half.
21795b482a8SLen Brown 	 */
21895b482a8SLen Brown 	this_register = gpe_register_info;
21995b482a8SLen Brown 	this_event = gpe_event_info;
22095b482a8SLen Brown 
22195b482a8SLen Brown 	for (i = 0; i < gpe_block->register_count; i++) {
22295b482a8SLen Brown 
22395b482a8SLen Brown 		/* Init the register_info for this GPE register (8 GPEs) */
22495b482a8SLen Brown 
2257505da4cSBob Moore 		this_register->base_gpe_number = (u16)
2267505da4cSBob Moore 		    (gpe_block->block_base_number +
22795b482a8SLen Brown 		     (i * ACPI_GPE_REGISTER_WIDTH));
22895b482a8SLen Brown 
2297505da4cSBob Moore 		this_register->status_address.address = gpe_block->address + i;
23095b482a8SLen Brown 
23195b482a8SLen Brown 		this_register->enable_address.address =
2327505da4cSBob Moore 		    gpe_block->address + i + gpe_block->register_count;
23395b482a8SLen Brown 
2347505da4cSBob Moore 		this_register->status_address.space_id = gpe_block->space_id;
2357505da4cSBob Moore 		this_register->enable_address.space_id = gpe_block->space_id;
23695b482a8SLen Brown 
23795b482a8SLen Brown 		/* Init the event_info for each GPE within this register */
23895b482a8SLen Brown 
23995b482a8SLen Brown 		for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) {
24095b482a8SLen Brown 			this_event->gpe_number =
24195b482a8SLen Brown 			    (u8) (this_register->base_gpe_number + j);
24295b482a8SLen Brown 			this_event->register_info = this_register;
24395b482a8SLen Brown 			this_event++;
24495b482a8SLen Brown 		}
24595b482a8SLen Brown 
24695b482a8SLen Brown 		/* Disable all GPEs within this register */
24795b482a8SLen Brown 
248f06011adSRafael J. Wysocki 		status = acpi_hw_gpe_write(0x00, &this_register->enable_address);
24995b482a8SLen Brown 		if (ACPI_FAILURE(status)) {
25095b482a8SLen Brown 			goto error_exit;
25195b482a8SLen Brown 		}
25295b482a8SLen Brown 
25395b482a8SLen Brown 		/* Clear any pending GPE events within this register */
25495b482a8SLen Brown 
255f06011adSRafael J. Wysocki 		status = acpi_hw_gpe_write(0xFF, &this_register->status_address);
25695b482a8SLen Brown 		if (ACPI_FAILURE(status)) {
25795b482a8SLen Brown 			goto error_exit;
25895b482a8SLen Brown 		}
25995b482a8SLen Brown 
26095b482a8SLen Brown 		this_register++;
26195b482a8SLen Brown 	}
26295b482a8SLen Brown 
26395b482a8SLen Brown 	return_ACPI_STATUS(AE_OK);
26495b482a8SLen Brown 
26595b482a8SLen Brown error_exit:
26695b482a8SLen Brown 	if (gpe_register_info) {
26795b482a8SLen Brown 		ACPI_FREE(gpe_register_info);
26895b482a8SLen Brown 	}
26995b482a8SLen Brown 	if (gpe_event_info) {
27095b482a8SLen Brown 		ACPI_FREE(gpe_event_info);
27195b482a8SLen Brown 	}
27295b482a8SLen Brown 
27395b482a8SLen Brown 	return_ACPI_STATUS(status);
27495b482a8SLen Brown }
27595b482a8SLen Brown 
27695b482a8SLen Brown /*******************************************************************************
27795b482a8SLen Brown  *
27895b482a8SLen Brown  * FUNCTION:    acpi_ev_create_gpe_block
27995b482a8SLen Brown  *
28095b482a8SLen Brown  * PARAMETERS:  gpe_device          - Handle to the parent GPE block
281ba494beeSBob Moore  *              gpe_block_address   - Address and space_ID
28295b482a8SLen Brown  *              register_count      - Number of GPE register pairs in the block
28395b482a8SLen Brown  *              gpe_block_base_number - Starting GPE number for the block
28495b482a8SLen Brown  *              interrupt_number    - H/W interrupt for the block
28595b482a8SLen Brown  *              return_gpe_block    - Where the new block descriptor is returned
28695b482a8SLen Brown  *
28795b482a8SLen Brown  * RETURN:      Status
28895b482a8SLen Brown  *
28995b482a8SLen Brown  * DESCRIPTION: Create and Install a block of GPE registers. All GPEs within
29095b482a8SLen Brown  *              the block are disabled at exit.
29195b482a8SLen Brown  *              Note: Assumes namespace is locked.
29295b482a8SLen Brown  *
29395b482a8SLen Brown  ******************************************************************************/
29495b482a8SLen Brown 
29595b482a8SLen Brown acpi_status
acpi_ev_create_gpe_block(struct acpi_namespace_node * gpe_device,u64 address,u8 space_id,u32 register_count,u16 gpe_block_base_number,u32 interrupt_number,struct acpi_gpe_block_info ** return_gpe_block)29695b482a8SLen Brown acpi_ev_create_gpe_block(struct acpi_namespace_node *gpe_device,
2977505da4cSBob Moore 			 u64 address,
2987505da4cSBob Moore 			 u8 space_id,
29995b482a8SLen Brown 			 u32 register_count,
3007505da4cSBob Moore 			 u16 gpe_block_base_number,
30195b482a8SLen Brown 			 u32 interrupt_number,
30295b482a8SLen Brown 			 struct acpi_gpe_block_info **return_gpe_block)
30395b482a8SLen Brown {
30495b482a8SLen Brown 	acpi_status status;
30595b482a8SLen Brown 	struct acpi_gpe_block_info *gpe_block;
306186c307fSBob Moore 	struct acpi_gpe_walk_info walk_info;
30795b482a8SLen Brown 
30895b482a8SLen Brown 	ACPI_FUNCTION_TRACE(ev_create_gpe_block);
30995b482a8SLen Brown 
31095b482a8SLen Brown 	if (!register_count) {
31195b482a8SLen Brown 		return_ACPI_STATUS(AE_OK);
31295b482a8SLen Brown 	}
31395b482a8SLen Brown 
31484b43284SRafael J. Wysocki 	/* Validate the space_ID */
31584b43284SRafael J. Wysocki 
31684b43284SRafael J. Wysocki 	if ((space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) &&
31784b43284SRafael J. Wysocki 	    (space_id != ACPI_ADR_SPACE_SYSTEM_IO)) {
31884b43284SRafael J. Wysocki 		ACPI_ERROR((AE_INFO,
31984b43284SRafael J. Wysocki 			    "Unsupported address space: 0x%X", space_id));
32084b43284SRafael J. Wysocki 		return_ACPI_STATUS(AE_SUPPORT);
32184b43284SRafael J. Wysocki 	}
32284b43284SRafael J. Wysocki 
32384b43284SRafael J. Wysocki 	if (space_id == ACPI_ADR_SPACE_SYSTEM_IO) {
32484b43284SRafael J. Wysocki 		status = acpi_hw_validate_io_block(address,
32584b43284SRafael J. Wysocki 						   ACPI_GPE_REGISTER_WIDTH,
32684b43284SRafael J. Wysocki 						   register_count);
32784b43284SRafael J. Wysocki 		if (ACPI_FAILURE(status))
32884b43284SRafael J. Wysocki 			return_ACPI_STATUS(status);
32984b43284SRafael J. Wysocki 	}
33084b43284SRafael J. Wysocki 
33195b482a8SLen Brown 	/* Allocate a new GPE block */
33295b482a8SLen Brown 
33395b482a8SLen Brown 	gpe_block = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_gpe_block_info));
33495b482a8SLen Brown 	if (!gpe_block) {
33595b482a8SLen Brown 		return_ACPI_STATUS(AE_NO_MEMORY);
33695b482a8SLen Brown 	}
33795b482a8SLen Brown 
33895b482a8SLen Brown 	/* Initialize the new GPE block */
33995b482a8SLen Brown 
3407505da4cSBob Moore 	gpe_block->address = address;
3417505da4cSBob Moore 	gpe_block->space_id = space_id;
34295b482a8SLen Brown 	gpe_block->node = gpe_device;
3430f849d2cSLin Ming 	gpe_block->gpe_count = (u16)(register_count * ACPI_GPE_REGISTER_WIDTH);
344da503373SLin Ming 	gpe_block->initialized = FALSE;
34595b482a8SLen Brown 	gpe_block->register_count = register_count;
34695b482a8SLen Brown 	gpe_block->block_base_number = gpe_block_base_number;
34795b482a8SLen Brown 
34895b482a8SLen Brown 	/*
34995b482a8SLen Brown 	 * Create the register_info and event_info sub-structures
35095b482a8SLen Brown 	 * Note: disables and clears all GPEs in the block
35195b482a8SLen Brown 	 */
35295b482a8SLen Brown 	status = acpi_ev_create_gpe_info_blocks(gpe_block);
35395b482a8SLen Brown 	if (ACPI_FAILURE(status)) {
35495b482a8SLen Brown 		ACPI_FREE(gpe_block);
35595b482a8SLen Brown 		return_ACPI_STATUS(status);
35695b482a8SLen Brown 	}
35795b482a8SLen Brown 
35895b482a8SLen Brown 	/* Install the new block in the global lists */
35995b482a8SLen Brown 
36095b482a8SLen Brown 	status = acpi_ev_install_gpe_block(gpe_block, interrupt_number);
36195b482a8SLen Brown 	if (ACPI_FAILURE(status)) {
362b739f106STomasz Nowicki 		ACPI_FREE(gpe_block->register_info);
363b739f106STomasz Nowicki 		ACPI_FREE(gpe_block->event_info);
36495b482a8SLen Brown 		ACPI_FREE(gpe_block);
36595b482a8SLen Brown 		return_ACPI_STATUS(status);
36695b482a8SLen Brown 	}
36795b482a8SLen Brown 
3683a37898dSLin Ming 	acpi_gbl_all_gpes_initialized = FALSE;
369a2100801SRafael J. Wysocki 
370186c307fSBob Moore 	/* Find all GPE methods (_Lxx or_Exx) for this block */
371186c307fSBob Moore 
372186c307fSBob Moore 	walk_info.gpe_block = gpe_block;
373186c307fSBob Moore 	walk_info.gpe_device = gpe_device;
374186c307fSBob Moore 	walk_info.execute_by_owner_id = FALSE;
37595b482a8SLen Brown 
376edc5935eSBob Moore 	(void)acpi_ns_walk_namespace(ACPI_TYPE_METHOD, gpe_device,
37795b482a8SLen Brown 				     ACPI_UINT32_MAX, ACPI_NS_WALK_NO_UNLOCK,
378edc5935eSBob Moore 				     acpi_ev_match_gpe_method, NULL, &walk_info,
379edc5935eSBob Moore 				     NULL);
38095b482a8SLen Brown 
38195b482a8SLen Brown 	/* Return the new block */
38295b482a8SLen Brown 
38395b482a8SLen Brown 	if (return_gpe_block) {
38495b482a8SLen Brown 		(*return_gpe_block) = gpe_block;
38595b482a8SLen Brown 	}
38695b482a8SLen Brown 
3873e5621a7SBob Moore 	ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT,
3887505da4cSBob Moore 			      "    Initialized GPE %02X to %02X [%4.4s] %u regs on interrupt 0x%X%s\n",
38995b482a8SLen Brown 			      (u32)gpe_block->block_base_number,
39095b482a8SLen Brown 			      (u32)(gpe_block->block_base_number +
3910f849d2cSLin Ming 				    (gpe_block->gpe_count - 1)),
39295b482a8SLen Brown 			      gpe_device->name.ascii, gpe_block->register_count,
3937505da4cSBob Moore 			      interrupt_number,
3947505da4cSBob Moore 			      interrupt_number ==
3957505da4cSBob Moore 			      acpi_gbl_FADT.sci_interrupt ? " (SCI)" : ""));
39695b482a8SLen Brown 
39795b482a8SLen Brown 	/* Update global count of currently available GPEs */
39895b482a8SLen Brown 
3990f849d2cSLin Ming 	acpi_current_gpe_count += gpe_block->gpe_count;
40095b482a8SLen Brown 	return_ACPI_STATUS(AE_OK);
40195b482a8SLen Brown }
40295b482a8SLen Brown 
40395b482a8SLen Brown /*******************************************************************************
40495b482a8SLen Brown  *
40595b482a8SLen Brown  * FUNCTION:    acpi_ev_initialize_gpe_block
40695b482a8SLen Brown  *
407da503373SLin Ming  * PARAMETERS:  acpi_gpe_callback
40895b482a8SLen Brown  *
40995b482a8SLen Brown  * RETURN:      Status
41095b482a8SLen Brown  *
411da503373SLin Ming  * DESCRIPTION: Initialize and enable a GPE block. Enable GPEs that have
412da503373SLin Ming  *              associated methods.
41395b482a8SLen Brown  *              Note: Assumes namespace is locked.
41495b482a8SLen Brown  *
41595b482a8SLen Brown  ******************************************************************************/
41695b482a8SLen Brown 
41795b482a8SLen Brown acpi_status
acpi_ev_initialize_gpe_block(struct acpi_gpe_xrupt_info * gpe_xrupt_info,struct acpi_gpe_block_info * gpe_block,void * context)418a2100801SRafael J. Wysocki acpi_ev_initialize_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
419a2100801SRafael J. Wysocki 			     struct acpi_gpe_block_info *gpe_block,
42087cd826bSErik Schmauss 			     void *context)
42195b482a8SLen Brown {
4220f849d2cSLin Ming 	acpi_status status;
42395b482a8SLen Brown 	struct acpi_gpe_event_info *gpe_event_info;
42495b482a8SLen Brown 	u32 gpe_enabled_count;
4250f849d2cSLin Ming 	u32 gpe_index;
42695b482a8SLen Brown 	u32 i;
42795b482a8SLen Brown 	u32 j;
42887cd826bSErik Schmauss 	u8 *is_polling_needed = context;
4290fe0bebfSErik Schmauss 	ACPI_ERROR_ONLY(u32 gpe_number);
43095b482a8SLen Brown 
43195b482a8SLen Brown 	ACPI_FUNCTION_TRACE(ev_initialize_gpe_block);
43295b482a8SLen Brown 
433a2100801SRafael J. Wysocki 	/*
434da503373SLin Ming 	 * Ignore a null GPE block (e.g., if no GPE block 1 exists), and
435da503373SLin Ming 	 * any GPE blocks that have been initialized already.
436a2100801SRafael J. Wysocki 	 */
437a2100801SRafael J. Wysocki 	if (!gpe_block || gpe_block->initialized) {
43895b482a8SLen Brown 		return_ACPI_STATUS(AE_OK);
43995b482a8SLen Brown 	}
44095b482a8SLen Brown 
44195b482a8SLen Brown 	/*
442a2100801SRafael J. Wysocki 	 * Enable all GPEs that have a corresponding method and have the
443da503373SLin Ming 	 * ACPI_GPE_CAN_WAKE flag unset. Any other GPEs within this block
444da503373SLin Ming 	 * must be enabled via the acpi_enable_gpe() interface.
44595b482a8SLen Brown 	 */
44695b482a8SLen Brown 	gpe_enabled_count = 0;
4470f849d2cSLin Ming 
44895b482a8SLen Brown 	for (i = 0; i < gpe_block->register_count; i++) {
4499630bdd9SRafael J. Wysocki 		for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) {
45095b482a8SLen Brown 
45195b482a8SLen Brown 			/* Get the info block for this particular GPE */
4520f849d2cSLin Ming 
4530f849d2cSLin Ming 			gpe_index = (i * ACPI_GPE_REGISTER_WIDTH) + j;
4549630bdd9SRafael J. Wysocki 			gpe_event_info = &gpe_block->event_info[gpe_index];
4550fe0bebfSErik Schmauss 			ACPI_ERROR_ONLY(gpe_number =
4560fe0bebfSErik Schmauss 					gpe_block->block_base_number +
4570fe0bebfSErik Schmauss 					gpe_index);
45887cd826bSErik Schmauss 			gpe_event_info->flags |= ACPI_GPE_INITIALIZED;
459ce43ace0SRafael J. Wysocki 
460bba63a29SLin Ming 			/*
461bba63a29SLin Ming 			 * Ignore GPEs that have no corresponding _Lxx/_Exx method
462ecc1165bSRafael J. Wysocki 			 * and GPEs that are used for wakeup
463bba63a29SLin Ming 			 */
464ecc1165bSRafael J. Wysocki 			if ((ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) !=
465ecc1165bSRafael J. Wysocki 			     ACPI_GPE_DISPATCH_METHOD)
466a2100801SRafael J. Wysocki 			    || (gpe_event_info->flags & ACPI_GPE_CAN_WAKE)) {
4679630bdd9SRafael J. Wysocki 				continue;
46895b482a8SLen Brown 			}
4699630bdd9SRafael J. Wysocki 
47044758bafSRafael J. Wysocki 			status = acpi_ev_add_gpe_reference(gpe_event_info, FALSE);
4710f849d2cSLin Ming 			if (ACPI_FAILURE(status)) {
4720f849d2cSLin Ming 				ACPI_EXCEPTION((AE_INFO, status,
4730f849d2cSLin Ming 					"Could not enable GPE 0x%02X",
474ecc1165bSRafael J. Wysocki 					gpe_number));
4750f849d2cSLin Ming 				continue;
4760f849d2cSLin Ming 			}
4770f849d2cSLin Ming 
4781312b7e0SRafael J. Wysocki 			gpe_event_info->flags |= ACPI_GPE_AUTO_ENABLED;
4791312b7e0SRafael J. Wysocki 
48087cd826bSErik Schmauss 			if (is_polling_needed &&
48187cd826bSErik Schmauss 			    ACPI_GPE_IS_POLLING_NEEDED(gpe_event_info)) {
48287cd826bSErik Schmauss 				*is_polling_needed = TRUE;
483ecc1165bSRafael J. Wysocki 			}
484ecc1165bSRafael J. Wysocki 
4859630bdd9SRafael J. Wysocki 			gpe_enabled_count++;
48695b482a8SLen Brown 		}
48795b482a8SLen Brown 	}
48895b482a8SLen Brown 
4899874647bSRafael J. Wysocki 	if (gpe_enabled_count) {
49005fb04b5SBob Moore 		ACPI_INFO(("Enabled %u GPEs in block %02X to %02X",
4913e5621a7SBob Moore 			   gpe_enabled_count, (u32)gpe_block->block_base_number,
4923e5621a7SBob Moore 			   (u32)(gpe_block->block_base_number +
4933e5621a7SBob Moore 				 (gpe_block->gpe_count - 1))));
494186c307fSBob Moore 	}
49595b482a8SLen Brown 
496a2100801SRafael J. Wysocki 	gpe_block->initialized = TRUE;
497a2100801SRafael J. Wysocki 
4989630bdd9SRafael J. Wysocki 	return_ACPI_STATUS(AE_OK);
49995b482a8SLen Brown }
50033620c54SBob Moore 
50133620c54SBob Moore #endif				/* !ACPI_REDUCED_HARDWARE */
502