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