xref: /openbmc/linux/drivers/acpi/acpica/evmisc.c (revision 612c2932)
195857638SErik Schmauss // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
295b482a8SLen Brown /******************************************************************************
395b482a8SLen Brown  *
495b482a8SLen Brown  * Module Name: evmisc - Miscellaneous event manager support functions
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("evmisc")
1795b482a8SLen Brown 
1895b482a8SLen Brown /* Local prototypes */
1995b482a8SLen Brown static void ACPI_SYSTEM_XFACE acpi_ev_notify_dispatch(void *context);
2095b482a8SLen Brown 
2195b482a8SLen Brown /*******************************************************************************
2295b482a8SLen Brown  *
2395b482a8SLen Brown  * FUNCTION:    acpi_ev_is_notify_object
2495b482a8SLen Brown  *
25ba494beeSBob Moore  * PARAMETERS:  node            - Node to check
2695b482a8SLen Brown  *
2795b482a8SLen Brown  * RETURN:      TRUE if notifies allowed on this object
2895b482a8SLen Brown  *
2995b482a8SLen Brown  * DESCRIPTION: Check type of node for a object that supports notifies.
3095b482a8SLen Brown  *
3195b482a8SLen Brown  *              TBD: This could be replaced by a flag bit in the node.
3295b482a8SLen Brown  *
3395b482a8SLen Brown  ******************************************************************************/
3495b482a8SLen Brown 
acpi_ev_is_notify_object(struct acpi_namespace_node * node)3595b482a8SLen Brown u8 acpi_ev_is_notify_object(struct acpi_namespace_node *node)
3695b482a8SLen Brown {
371fad8738SBob Moore 
3895b482a8SLen Brown 	switch (node->type) {
3995b482a8SLen Brown 	case ACPI_TYPE_DEVICE:
4095b482a8SLen Brown 	case ACPI_TYPE_PROCESSOR:
4195b482a8SLen Brown 	case ACPI_TYPE_THERMAL:
4295b482a8SLen Brown 		/*
4395b482a8SLen Brown 		 * These are the ONLY objects that can receive ACPI notifications
4495b482a8SLen Brown 		 */
4595b482a8SLen Brown 		return (TRUE);
4695b482a8SLen Brown 
4795b482a8SLen Brown 	default:
481d1ea1b7SChao Guan 
4995b482a8SLen Brown 		return (FALSE);
5095b482a8SLen Brown 	}
5195b482a8SLen Brown }
5295b482a8SLen Brown 
5395b482a8SLen Brown /*******************************************************************************
5495b482a8SLen Brown  *
5595b482a8SLen Brown  * FUNCTION:    acpi_ev_queue_notify_request
5695b482a8SLen Brown  *
57ba494beeSBob Moore  * PARAMETERS:  node            - NS node for the notified object
5895b482a8SLen Brown  *              notify_value    - Value from the Notify() request
5995b482a8SLen Brown  *
6095b482a8SLen Brown  * RETURN:      Status
6195b482a8SLen Brown  *
6295b482a8SLen Brown  * DESCRIPTION: Dispatch a device notification event to a previously
6395b482a8SLen Brown  *              installed handler.
6495b482a8SLen Brown  *
6595b482a8SLen Brown  ******************************************************************************/
6695b482a8SLen Brown 
6795b482a8SLen Brown acpi_status
acpi_ev_queue_notify_request(struct acpi_namespace_node * node,u32 notify_value)68f5c1e1c5SLv Zheng acpi_ev_queue_notify_request(struct acpi_namespace_node *node, u32 notify_value)
6995b482a8SLen Brown {
7095b482a8SLen Brown 	union acpi_operand_object *obj_desc;
7186ed4bc8SBob Moore 	union acpi_operand_object *handler_list_head = NULL;
7286ed4bc8SBob Moore 	union acpi_generic_state *info;
7386ed4bc8SBob Moore 	u8 handler_list_id = 0;
7495b482a8SLen Brown 	acpi_status status = AE_OK;
7595b482a8SLen Brown 
7695b482a8SLen Brown 	ACPI_FUNCTION_NAME(ev_queue_notify_request);
7795b482a8SLen Brown 
7886ed4bc8SBob Moore 	/* Are Notifies allowed on this object? */
7986ed4bc8SBob Moore 
8086ed4bc8SBob Moore 	if (!acpi_ev_is_notify_object(node)) {
8186ed4bc8SBob Moore 		return (AE_TYPE);
8286ed4bc8SBob Moore 	}
8386ed4bc8SBob Moore 
8486ed4bc8SBob Moore 	/* Get the correct notify list type (System or Device) */
8586ed4bc8SBob Moore 
8686ed4bc8SBob Moore 	if (notify_value <= ACPI_MAX_SYS_NOTIFY) {
8786ed4bc8SBob Moore 		handler_list_id = ACPI_SYSTEM_HANDLER_LIST;
8886ed4bc8SBob Moore 	} else {
8986ed4bc8SBob Moore 		handler_list_id = ACPI_DEVICE_HANDLER_LIST;
9086ed4bc8SBob Moore 	}
9186ed4bc8SBob Moore 
9286ed4bc8SBob Moore 	/* Get the notify object attached to the namespace Node */
9386ed4bc8SBob Moore 
9486ed4bc8SBob Moore 	obj_desc = acpi_ns_get_attached_object(node);
9586ed4bc8SBob Moore 	if (obj_desc) {
9686ed4bc8SBob Moore 
9786ed4bc8SBob Moore 		/* We have an attached object, Get the correct handler list */
9886ed4bc8SBob Moore 
9986ed4bc8SBob Moore 		handler_list_head =
10086ed4bc8SBob Moore 		    obj_desc->common_notify.notify_list[handler_list_id];
10186ed4bc8SBob Moore 	}
10286ed4bc8SBob Moore 
10395b482a8SLen Brown 	/*
10486ed4bc8SBob Moore 	 * If there is no notify handler (Global or Local)
10586ed4bc8SBob Moore 	 * for this object, just ignore the notify
10695b482a8SLen Brown 	 */
10786ed4bc8SBob Moore 	if (!acpi_gbl_global_notify[handler_list_id].handler
10886ed4bc8SBob Moore 	    && !handler_list_head) {
10986ed4bc8SBob Moore 		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
11086ed4bc8SBob Moore 				  "No notify handler for Notify, ignoring (%4.4s, %X) node %p\n",
11186ed4bc8SBob Moore 				  acpi_ut_get_node_name(node), notify_value,
11286ed4bc8SBob Moore 				  node));
11386ed4bc8SBob Moore 
11486ed4bc8SBob Moore 		return (AE_OK);
11586ed4bc8SBob Moore 	}
11686ed4bc8SBob Moore 
11786ed4bc8SBob Moore 	/* Setup notify info and schedule the notify dispatcher */
11886ed4bc8SBob Moore 
11986ed4bc8SBob Moore 	info = acpi_ut_create_generic_state();
12086ed4bc8SBob Moore 	if (!info) {
12186ed4bc8SBob Moore 		return (AE_NO_MEMORY);
12286ed4bc8SBob Moore 	}
12386ed4bc8SBob Moore 
12486ed4bc8SBob Moore 	info->common.descriptor_type = ACPI_DESC_TYPE_STATE_NOTIFY;
12586ed4bc8SBob Moore 
12686ed4bc8SBob Moore 	info->notify.node = node;
12786ed4bc8SBob Moore 	info->notify.value = (u16)notify_value;
12886ed4bc8SBob Moore 	info->notify.handler_list_id = handler_list_id;
12986ed4bc8SBob Moore 	info->notify.handler_list_head = handler_list_head;
13086ed4bc8SBob Moore 	info->notify.global = &acpi_gbl_global_notify[handler_list_id];
13186ed4bc8SBob Moore 
13295b482a8SLen Brown 	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
133ea143604SBob Moore 			  "Dispatching Notify on [%4.4s] (%s) Value 0x%2.2X (%s) Node %p\n",
134ea143604SBob Moore 			  acpi_ut_get_node_name(node),
135ea143604SBob Moore 			  acpi_ut_get_type_name(node->type), notify_value,
13606a63e33SBob Moore 			  acpi_ut_get_notify_name(notify_value, ACPI_TYPE_ANY),
13706a63e33SBob Moore 			  node));
13895b482a8SLen Brown 
1391fad8738SBob Moore 	status = acpi_os_execute(OSL_NOTIFY_HANDLER,
1401fad8738SBob Moore 				 acpi_ev_notify_dispatch, info);
14195b482a8SLen Brown 	if (ACPI_FAILURE(status)) {
14286ed4bc8SBob Moore 		acpi_ut_delete_generic_state(info);
14395b482a8SLen Brown 	}
14495b482a8SLen Brown 
14595b482a8SLen Brown 	return (status);
14695b482a8SLen Brown }
14795b482a8SLen Brown 
14895b482a8SLen Brown /*******************************************************************************
14995b482a8SLen Brown  *
15095b482a8SLen Brown  * FUNCTION:    acpi_ev_notify_dispatch
15195b482a8SLen Brown  *
152ba494beeSBob Moore  * PARAMETERS:  context         - To be passed to the notify handler
15395b482a8SLen Brown  *
15495b482a8SLen Brown  * RETURN:      None.
15595b482a8SLen Brown  *
15695b482a8SLen Brown  * DESCRIPTION: Dispatch a device notification event to a previously
15795b482a8SLen Brown  *              installed handler.
15895b482a8SLen Brown  *
15995b482a8SLen Brown  ******************************************************************************/
16095b482a8SLen Brown 
acpi_ev_notify_dispatch(void * context)16195b482a8SLen Brown static void ACPI_SYSTEM_XFACE acpi_ev_notify_dispatch(void *context)
16295b482a8SLen Brown {
16386ed4bc8SBob Moore 	union acpi_generic_state *info = (union acpi_generic_state *)context;
16495b482a8SLen Brown 	union acpi_operand_object *handler_obj;
16595b482a8SLen Brown 
16695b482a8SLen Brown 	ACPI_FUNCTION_ENTRY();
16795b482a8SLen Brown 
16886ed4bc8SBob Moore 	/* Invoke a global notify handler if installed */
16995b482a8SLen Brown 
17086ed4bc8SBob Moore 	if (info->notify.global->handler) {
17186ed4bc8SBob Moore 		info->notify.global->handler(info->notify.node,
17286ed4bc8SBob Moore 					     info->notify.value,
17386ed4bc8SBob Moore 					     info->notify.global->context);
17495b482a8SLen Brown 	}
17595b482a8SLen Brown 
17686ed4bc8SBob Moore 	/* Now invoke the local notify handler(s) if any are installed */
17795b482a8SLen Brown 
17886ed4bc8SBob Moore 	handler_obj = info->notify.handler_list_head;
17986ed4bc8SBob Moore 	while (handler_obj) {
18086ed4bc8SBob Moore 		handler_obj->notify.handler(info->notify.node,
18186ed4bc8SBob Moore 					    info->notify.value,
18286ed4bc8SBob Moore 					    handler_obj->notify.context);
18395b482a8SLen Brown 
18486ed4bc8SBob Moore 		handler_obj =
18586ed4bc8SBob Moore 		    handler_obj->notify.next[info->notify.handler_list_id];
18695b482a8SLen Brown 	}
18795b482a8SLen Brown 
18895b482a8SLen Brown 	/* All done with the info object */
18995b482a8SLen Brown 
19086ed4bc8SBob Moore 	acpi_ut_delete_generic_state(info);
19195b482a8SLen Brown }
19295b482a8SLen Brown 
19333620c54SBob Moore #if (!ACPI_REDUCED_HARDWARE)
19495b482a8SLen Brown /******************************************************************************
19595b482a8SLen Brown  *
19695b482a8SLen Brown  * FUNCTION:    acpi_ev_terminate
19795b482a8SLen Brown  *
19895b482a8SLen Brown  * PARAMETERS:  none
19995b482a8SLen Brown  *
20095b482a8SLen Brown  * RETURN:      none
20195b482a8SLen Brown  *
20295b482a8SLen Brown  * DESCRIPTION: Disable events and free memory allocated for table storage.
20395b482a8SLen Brown  *
20495b482a8SLen Brown  ******************************************************************************/
20595b482a8SLen Brown 
acpi_ev_terminate(void)20695b482a8SLen Brown void acpi_ev_terminate(void)
20795b482a8SLen Brown {
20895b482a8SLen Brown 	u32 i;
20995b482a8SLen Brown 	acpi_status status;
21095b482a8SLen Brown 
21195b482a8SLen Brown 	ACPI_FUNCTION_TRACE(ev_terminate);
21295b482a8SLen Brown 
21395b482a8SLen Brown 	if (acpi_gbl_events_initialized) {
21495b482a8SLen Brown 		/*
21595b482a8SLen Brown 		 * Disable all event-related functionality. In all cases, on error,
21695b482a8SLen Brown 		 * print a message but obviously we don't abort.
21795b482a8SLen Brown 		 */
21895b482a8SLen Brown 
21995b482a8SLen Brown 		/* Disable all fixed events */
22095b482a8SLen Brown 
22195b482a8SLen Brown 		for (i = 0; i < ACPI_NUM_FIXED_EVENTS; i++) {
22295b482a8SLen Brown 			status = acpi_disable_event(i, 0);
22395b482a8SLen Brown 			if (ACPI_FAILURE(status)) {
22495b482a8SLen Brown 				ACPI_ERROR((AE_INFO,
225f6a22b0bSBob Moore 					    "Could not disable fixed event %u",
22695b482a8SLen Brown 					    (u32) i));
22795b482a8SLen Brown 			}
22895b482a8SLen Brown 		}
22995b482a8SLen Brown 
23095b482a8SLen Brown 		/* Disable all GPEs in all GPE blocks */
23195b482a8SLen Brown 
23295b482a8SLen Brown 		status = acpi_ev_walk_gpe_list(acpi_hw_disable_gpe_block, NULL);
233edc5935eSBob Moore 		if (ACPI_FAILURE(status)) {
234edc5935eSBob Moore 			ACPI_EXCEPTION((AE_INFO, status,
235edc5935eSBob Moore 					"Could not disable GPEs in GPE block"));
236edc5935eSBob Moore 		}
23795b482a8SLen Brown 
23895b482a8SLen Brown 		status = acpi_ev_remove_global_lock_handler();
23995b482a8SLen Brown 		if (ACPI_FAILURE(status)) {
240edc5935eSBob Moore 			ACPI_EXCEPTION((AE_INFO, status,
24195b482a8SLen Brown 					"Could not remove Global Lock handler"));
24295b482a8SLen Brown 		}
24364f3af5fSTomasz Nowicki 
24464f3af5fSTomasz Nowicki 		acpi_gbl_events_initialized = FALSE;
24595b482a8SLen Brown 	}
24695b482a8SLen Brown 
247a2fd4b4bSLv Zheng 	/* Remove SCI handlers */
248a2fd4b4bSLv Zheng 
249a2fd4b4bSLv Zheng 	status = acpi_ev_remove_all_sci_handlers();
250a2fd4b4bSLv Zheng 	if (ACPI_FAILURE(status)) {
251a2fd4b4bSLv Zheng 		ACPI_ERROR((AE_INFO, "Could not remove SCI handler"));
252a2fd4b4bSLv Zheng 	}
253a2fd4b4bSLv Zheng 
25495b482a8SLen Brown 	/* Deallocate all handler objects installed within GPE info structs */
25595b482a8SLen Brown 
25695b482a8SLen Brown 	status = acpi_ev_walk_gpe_list(acpi_ev_delete_gpe_handlers, NULL);
257edc5935eSBob Moore 	if (ACPI_FAILURE(status)) {
258edc5935eSBob Moore 		ACPI_EXCEPTION((AE_INFO, status,
259edc5935eSBob Moore 				"Could not delete GPE handlers"));
260edc5935eSBob Moore 	}
26195b482a8SLen Brown 
26295b482a8SLen Brown 	/* Return to original mode if necessary */
26395b482a8SLen Brown 
26495b482a8SLen Brown 	if (acpi_gbl_original_mode == ACPI_SYS_MODE_LEGACY) {
26595b482a8SLen Brown 		status = acpi_disable();
26695b482a8SLen Brown 		if (ACPI_FAILURE(status)) {
26795b482a8SLen Brown 			ACPI_WARNING((AE_INFO, "AcpiDisable failed"));
26895b482a8SLen Brown 		}
26995b482a8SLen Brown 	}
27095b482a8SLen Brown 	return_VOID;
27195b482a8SLen Brown }
27233620c54SBob Moore 
27333620c54SBob Moore #endif				/* !ACPI_REDUCED_HARDWARE */
274