162306a36Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
262306a36Sopenharmony_ci/******************************************************************************
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Module Name: evevent - Fixed 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
1462306a36Sopenharmony_ci#define _COMPONENT          ACPI_EVENTS
1562306a36Sopenharmony_ciACPI_MODULE_NAME("evevent")
1662306a36Sopenharmony_ci#if (!ACPI_REDUCED_HARDWARE)	/* Entire module */
1762306a36Sopenharmony_ci/* Local prototypes */
1862306a36Sopenharmony_cistatic acpi_status acpi_ev_fixed_event_initialize(void);
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_cistatic u32 acpi_ev_fixed_event_dispatch(u32 event);
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci/*******************************************************************************
2362306a36Sopenharmony_ci *
2462306a36Sopenharmony_ci * FUNCTION:    acpi_ev_initialize_events
2562306a36Sopenharmony_ci *
2662306a36Sopenharmony_ci * PARAMETERS:  None
2762306a36Sopenharmony_ci *
2862306a36Sopenharmony_ci * RETURN:      Status
2962306a36Sopenharmony_ci *
3062306a36Sopenharmony_ci * DESCRIPTION: Initialize global data structures for ACPI events (Fixed, GPE)
3162306a36Sopenharmony_ci *
3262306a36Sopenharmony_ci ******************************************************************************/
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ciacpi_status acpi_ev_initialize_events(void)
3562306a36Sopenharmony_ci{
3662306a36Sopenharmony_ci	acpi_status status;
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE(ev_initialize_events);
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	/* If Hardware Reduced flag is set, there are no fixed events */
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci	if (acpi_gbl_reduced_hardware) {
4362306a36Sopenharmony_ci		return_ACPI_STATUS(AE_OK);
4462306a36Sopenharmony_ci	}
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci	/*
4762306a36Sopenharmony_ci	 * Initialize the Fixed and General Purpose Events. This is done prior to
4862306a36Sopenharmony_ci	 * enabling SCIs to prevent interrupts from occurring before the handlers
4962306a36Sopenharmony_ci	 * are installed.
5062306a36Sopenharmony_ci	 */
5162306a36Sopenharmony_ci	status = acpi_ev_fixed_event_initialize();
5262306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
5362306a36Sopenharmony_ci		ACPI_EXCEPTION((AE_INFO, status,
5462306a36Sopenharmony_ci				"Unable to initialize fixed events"));
5562306a36Sopenharmony_ci		return_ACPI_STATUS(status);
5662306a36Sopenharmony_ci	}
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	status = acpi_ev_gpe_initialize();
5962306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
6062306a36Sopenharmony_ci		ACPI_EXCEPTION((AE_INFO, status,
6162306a36Sopenharmony_ci				"Unable to initialize general purpose events"));
6262306a36Sopenharmony_ci		return_ACPI_STATUS(status);
6362306a36Sopenharmony_ci	}
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci	return_ACPI_STATUS(status);
6662306a36Sopenharmony_ci}
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci/*******************************************************************************
6962306a36Sopenharmony_ci *
7062306a36Sopenharmony_ci * FUNCTION:    acpi_ev_install_xrupt_handlers
7162306a36Sopenharmony_ci *
7262306a36Sopenharmony_ci * PARAMETERS:  None
7362306a36Sopenharmony_ci *
7462306a36Sopenharmony_ci * RETURN:      Status
7562306a36Sopenharmony_ci *
7662306a36Sopenharmony_ci * DESCRIPTION: Install interrupt handlers for the SCI and Global Lock
7762306a36Sopenharmony_ci *
7862306a36Sopenharmony_ci ******************************************************************************/
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ciacpi_status acpi_ev_install_xrupt_handlers(void)
8162306a36Sopenharmony_ci{
8262306a36Sopenharmony_ci	acpi_status status;
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE(ev_install_xrupt_handlers);
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	/* If Hardware Reduced flag is set, there is no ACPI h/w */
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	if (acpi_gbl_reduced_hardware) {
8962306a36Sopenharmony_ci		return_ACPI_STATUS(AE_OK);
9062306a36Sopenharmony_ci	}
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	/* Install the SCI handler */
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	status = acpi_ev_install_sci_handler();
9562306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
9662306a36Sopenharmony_ci		ACPI_EXCEPTION((AE_INFO, status,
9762306a36Sopenharmony_ci				"Unable to install System Control Interrupt handler"));
9862306a36Sopenharmony_ci		return_ACPI_STATUS(status);
9962306a36Sopenharmony_ci	}
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	/* Install the handler for the Global Lock */
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	status = acpi_ev_init_global_lock_handler();
10462306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
10562306a36Sopenharmony_ci		ACPI_EXCEPTION((AE_INFO, status,
10662306a36Sopenharmony_ci				"Unable to initialize Global Lock handler"));
10762306a36Sopenharmony_ci		return_ACPI_STATUS(status);
10862306a36Sopenharmony_ci	}
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	acpi_gbl_events_initialized = TRUE;
11162306a36Sopenharmony_ci	return_ACPI_STATUS(status);
11262306a36Sopenharmony_ci}
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci/*******************************************************************************
11562306a36Sopenharmony_ci *
11662306a36Sopenharmony_ci * FUNCTION:    acpi_ev_fixed_event_initialize
11762306a36Sopenharmony_ci *
11862306a36Sopenharmony_ci * PARAMETERS:  None
11962306a36Sopenharmony_ci *
12062306a36Sopenharmony_ci * RETURN:      Status
12162306a36Sopenharmony_ci *
12262306a36Sopenharmony_ci * DESCRIPTION: Install the fixed event handlers and disable all fixed events.
12362306a36Sopenharmony_ci *
12462306a36Sopenharmony_ci ******************************************************************************/
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_cistatic acpi_status acpi_ev_fixed_event_initialize(void)
12762306a36Sopenharmony_ci{
12862306a36Sopenharmony_ci	u32 i;
12962306a36Sopenharmony_ci	acpi_status status;
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	/*
13262306a36Sopenharmony_ci	 * Initialize the structure that keeps track of fixed event handlers and
13362306a36Sopenharmony_ci	 * disable all of the fixed events.
13462306a36Sopenharmony_ci	 */
13562306a36Sopenharmony_ci	for (i = 0; i < ACPI_NUM_FIXED_EVENTS; i++) {
13662306a36Sopenharmony_ci		acpi_gbl_fixed_event_handlers[i].handler = NULL;
13762306a36Sopenharmony_ci		acpi_gbl_fixed_event_handlers[i].context = NULL;
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci		/* Disable the fixed event */
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci		if (acpi_gbl_fixed_event_info[i].enable_register_id != 0xFF) {
14262306a36Sopenharmony_ci			status =
14362306a36Sopenharmony_ci			    acpi_write_bit_register(acpi_gbl_fixed_event_info
14462306a36Sopenharmony_ci						    [i].enable_register_id,
14562306a36Sopenharmony_ci						    ACPI_DISABLE_EVENT);
14662306a36Sopenharmony_ci			if (ACPI_FAILURE(status)) {
14762306a36Sopenharmony_ci				return (status);
14862306a36Sopenharmony_ci			}
14962306a36Sopenharmony_ci		}
15062306a36Sopenharmony_ci	}
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	return (AE_OK);
15362306a36Sopenharmony_ci}
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci/*******************************************************************************
15662306a36Sopenharmony_ci *
15762306a36Sopenharmony_ci * FUNCTION:    acpi_ev_fixed_event_detect
15862306a36Sopenharmony_ci *
15962306a36Sopenharmony_ci * PARAMETERS:  None
16062306a36Sopenharmony_ci *
16162306a36Sopenharmony_ci * RETURN:      INTERRUPT_HANDLED or INTERRUPT_NOT_HANDLED
16262306a36Sopenharmony_ci *
16362306a36Sopenharmony_ci * DESCRIPTION: Checks the PM status register for active fixed events
16462306a36Sopenharmony_ci *
16562306a36Sopenharmony_ci ******************************************************************************/
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ciu32 acpi_ev_fixed_event_detect(void)
16862306a36Sopenharmony_ci{
16962306a36Sopenharmony_ci	u32 int_status = ACPI_INTERRUPT_NOT_HANDLED;
17062306a36Sopenharmony_ci	u32 fixed_status;
17162306a36Sopenharmony_ci	u32 fixed_enable;
17262306a36Sopenharmony_ci	u32 i;
17362306a36Sopenharmony_ci	acpi_status status;
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	ACPI_FUNCTION_NAME(ev_fixed_event_detect);
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	/*
17862306a36Sopenharmony_ci	 * Read the fixed feature status and enable registers, as all the cases
17962306a36Sopenharmony_ci	 * depend on their values. Ignore errors here.
18062306a36Sopenharmony_ci	 */
18162306a36Sopenharmony_ci	status = acpi_hw_register_read(ACPI_REGISTER_PM1_STATUS, &fixed_status);
18262306a36Sopenharmony_ci	status |=
18362306a36Sopenharmony_ci	    acpi_hw_register_read(ACPI_REGISTER_PM1_ENABLE, &fixed_enable);
18462306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
18562306a36Sopenharmony_ci		return (int_status);
18662306a36Sopenharmony_ci	}
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	ACPI_DEBUG_PRINT((ACPI_DB_INTERRUPTS,
18962306a36Sopenharmony_ci			  "Fixed Event Block: Enable %08X Status %08X\n",
19062306a36Sopenharmony_ci			  fixed_enable, fixed_status));
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	/*
19362306a36Sopenharmony_ci	 * Check for all possible Fixed Events and dispatch those that are active
19462306a36Sopenharmony_ci	 */
19562306a36Sopenharmony_ci	for (i = 0; i < ACPI_NUM_FIXED_EVENTS; i++) {
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci		/* Both the status and enable bits must be on for this event */
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci		if ((fixed_status & acpi_gbl_fixed_event_info[i].
20062306a36Sopenharmony_ci		     status_bit_mask)
20162306a36Sopenharmony_ci		    && (fixed_enable & acpi_gbl_fixed_event_info[i].
20262306a36Sopenharmony_ci			enable_bit_mask)) {
20362306a36Sopenharmony_ci			/*
20462306a36Sopenharmony_ci			 * Found an active (signalled) event. Invoke global event
20562306a36Sopenharmony_ci			 * handler if present.
20662306a36Sopenharmony_ci			 */
20762306a36Sopenharmony_ci			acpi_fixed_event_count[i]++;
20862306a36Sopenharmony_ci			if (acpi_gbl_global_event_handler) {
20962306a36Sopenharmony_ci				acpi_gbl_global_event_handler
21062306a36Sopenharmony_ci				    (ACPI_EVENT_TYPE_FIXED, NULL, i,
21162306a36Sopenharmony_ci				     acpi_gbl_global_event_handler_context);
21262306a36Sopenharmony_ci			}
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci			int_status |= acpi_ev_fixed_event_dispatch(i);
21562306a36Sopenharmony_ci		}
21662306a36Sopenharmony_ci	}
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci	return (int_status);
21962306a36Sopenharmony_ci}
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci/*******************************************************************************
22262306a36Sopenharmony_ci *
22362306a36Sopenharmony_ci * FUNCTION:    acpi_ev_fixed_event_dispatch
22462306a36Sopenharmony_ci *
22562306a36Sopenharmony_ci * PARAMETERS:  event               - Event type
22662306a36Sopenharmony_ci *
22762306a36Sopenharmony_ci * RETURN:      INTERRUPT_HANDLED or INTERRUPT_NOT_HANDLED
22862306a36Sopenharmony_ci *
22962306a36Sopenharmony_ci * DESCRIPTION: Clears the status bit for the requested event, calls the
23062306a36Sopenharmony_ci *              handler that previously registered for the event.
23162306a36Sopenharmony_ci *              NOTE: If there is no handler for the event, the event is
23262306a36Sopenharmony_ci *              disabled to prevent further interrupts.
23362306a36Sopenharmony_ci *
23462306a36Sopenharmony_ci ******************************************************************************/
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_cistatic u32 acpi_ev_fixed_event_dispatch(u32 event)
23762306a36Sopenharmony_ci{
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	ACPI_FUNCTION_ENTRY();
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci	/* Clear the status bit */
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci	(void)acpi_write_bit_register(acpi_gbl_fixed_event_info[event].
24462306a36Sopenharmony_ci				      status_register_id, ACPI_CLEAR_STATUS);
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci	/*
24762306a36Sopenharmony_ci	 * Make sure that a handler exists. If not, report an error
24862306a36Sopenharmony_ci	 * and disable the event to prevent further interrupts.
24962306a36Sopenharmony_ci	 */
25062306a36Sopenharmony_ci	if (!acpi_gbl_fixed_event_handlers[event].handler) {
25162306a36Sopenharmony_ci		(void)acpi_write_bit_register(acpi_gbl_fixed_event_info[event].
25262306a36Sopenharmony_ci					      enable_register_id,
25362306a36Sopenharmony_ci					      ACPI_DISABLE_EVENT);
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci		ACPI_ERROR((AE_INFO,
25662306a36Sopenharmony_ci			    "No installed handler for fixed event - %s (%u), disabling",
25762306a36Sopenharmony_ci			    acpi_ut_get_event_name(event), event));
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci		return (ACPI_INTERRUPT_NOT_HANDLED);
26062306a36Sopenharmony_ci	}
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	/* Invoke the Fixed Event handler */
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	return ((acpi_gbl_fixed_event_handlers[event].
26562306a36Sopenharmony_ci		 handler) (acpi_gbl_fixed_event_handlers[event].context));
26662306a36Sopenharmony_ci}
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci/*******************************************************************************
26962306a36Sopenharmony_ci *
27062306a36Sopenharmony_ci * FUNCTION:    acpi_any_fixed_event_status_set
27162306a36Sopenharmony_ci *
27262306a36Sopenharmony_ci * PARAMETERS:  None
27362306a36Sopenharmony_ci *
27462306a36Sopenharmony_ci * RETURN:      TRUE or FALSE
27562306a36Sopenharmony_ci *
27662306a36Sopenharmony_ci * DESCRIPTION: Checks the PM status register for active fixed events
27762306a36Sopenharmony_ci *
27862306a36Sopenharmony_ci ******************************************************************************/
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ciu32 acpi_any_fixed_event_status_set(void)
28162306a36Sopenharmony_ci{
28262306a36Sopenharmony_ci	acpi_status status;
28362306a36Sopenharmony_ci	u32 in_status;
28462306a36Sopenharmony_ci	u32 in_enable;
28562306a36Sopenharmony_ci	u32 i;
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci	status = acpi_hw_register_read(ACPI_REGISTER_PM1_ENABLE, &in_enable);
28862306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
28962306a36Sopenharmony_ci		return (FALSE);
29062306a36Sopenharmony_ci	}
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	status = acpi_hw_register_read(ACPI_REGISTER_PM1_STATUS, &in_status);
29362306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
29462306a36Sopenharmony_ci		return (FALSE);
29562306a36Sopenharmony_ci	}
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	/*
29862306a36Sopenharmony_ci	 * Check for all possible Fixed Events and dispatch those that are active
29962306a36Sopenharmony_ci	 */
30062306a36Sopenharmony_ci	for (i = 0; i < ACPI_NUM_FIXED_EVENTS; i++) {
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci		/* Both the status and enable bits must be on for this event */
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci		if ((in_status & acpi_gbl_fixed_event_info[i].status_bit_mask) &&
30562306a36Sopenharmony_ci		    (in_enable & acpi_gbl_fixed_event_info[i].enable_bit_mask)) {
30662306a36Sopenharmony_ci			return (TRUE);
30762306a36Sopenharmony_ci		}
30862306a36Sopenharmony_ci	}
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	return (FALSE);
31162306a36Sopenharmony_ci}
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci#endif				/* !ACPI_REDUCED_HARDWARE */
314