1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 2 /****************************************************************************** 3 * 4 * Module Name: evmisc - Miscellaneous event manager support functions 5 * 6 * Copyright (C) 2000 - 2021, Intel Corp. 7 * 8 *****************************************************************************/ 9 10 #include <acpi/acpi.h> 11 #include "accommon.h" 12 #include "acevents.h" 13 #include "acnamesp.h" 14 15 #define _COMPONENT ACPI_EVENTS 16 ACPI_MODULE_NAME("evmisc") 17 18 /* Local prototypes */ 19 static void ACPI_SYSTEM_XFACE acpi_ev_notify_dispatch(void *context); 20 21 /******************************************************************************* 22 * 23 * FUNCTION: acpi_ev_is_notify_object 24 * 25 * PARAMETERS: node - Node to check 26 * 27 * RETURN: TRUE if notifies allowed on this object 28 * 29 * DESCRIPTION: Check type of node for a object that supports notifies. 30 * 31 * TBD: This could be replaced by a flag bit in the node. 32 * 33 ******************************************************************************/ 34 35 u8 acpi_ev_is_notify_object(struct acpi_namespace_node *node) 36 { 37 38 switch (node->type) { 39 case ACPI_TYPE_DEVICE: 40 case ACPI_TYPE_PROCESSOR: 41 case ACPI_TYPE_THERMAL: 42 /* 43 * These are the ONLY objects that can receive ACPI notifications 44 */ 45 return (TRUE); 46 47 default: 48 49 return (FALSE); 50 } 51 } 52 53 /******************************************************************************* 54 * 55 * FUNCTION: acpi_ev_queue_notify_request 56 * 57 * PARAMETERS: node - NS node for the notified object 58 * notify_value - Value from the Notify() request 59 * 60 * RETURN: Status 61 * 62 * DESCRIPTION: Dispatch a device notification event to a previously 63 * installed handler. 64 * 65 ******************************************************************************/ 66 67 acpi_status 68 acpi_ev_queue_notify_request(struct acpi_namespace_node *node, u32 notify_value) 69 { 70 union acpi_operand_object *obj_desc; 71 union acpi_operand_object *handler_list_head = NULL; 72 union acpi_generic_state *info; 73 u8 handler_list_id = 0; 74 acpi_status status = AE_OK; 75 76 ACPI_FUNCTION_NAME(ev_queue_notify_request); 77 78 /* Are Notifies allowed on this object? */ 79 80 if (!acpi_ev_is_notify_object(node)) { 81 return (AE_TYPE); 82 } 83 84 /* Get the correct notify list type (System or Device) */ 85 86 if (notify_value <= ACPI_MAX_SYS_NOTIFY) { 87 handler_list_id = ACPI_SYSTEM_HANDLER_LIST; 88 } else { 89 handler_list_id = ACPI_DEVICE_HANDLER_LIST; 90 } 91 92 /* Get the notify object attached to the namespace Node */ 93 94 obj_desc = acpi_ns_get_attached_object(node); 95 if (obj_desc) { 96 97 /* We have an attached object, Get the correct handler list */ 98 99 handler_list_head = 100 obj_desc->common_notify.notify_list[handler_list_id]; 101 } 102 103 /* 104 * If there is no notify handler (Global or Local) 105 * for this object, just ignore the notify 106 */ 107 if (!acpi_gbl_global_notify[handler_list_id].handler 108 && !handler_list_head) { 109 ACPI_DEBUG_PRINT((ACPI_DB_INFO, 110 "No notify handler for Notify, ignoring (%4.4s, %X) node %p\n", 111 acpi_ut_get_node_name(node), notify_value, 112 node)); 113 114 return (AE_OK); 115 } 116 117 /* Setup notify info and schedule the notify dispatcher */ 118 119 info = acpi_ut_create_generic_state(); 120 if (!info) { 121 return (AE_NO_MEMORY); 122 } 123 124 info->common.descriptor_type = ACPI_DESC_TYPE_STATE_NOTIFY; 125 126 info->notify.node = node; 127 info->notify.value = (u16)notify_value; 128 info->notify.handler_list_id = handler_list_id; 129 info->notify.handler_list_head = handler_list_head; 130 info->notify.global = &acpi_gbl_global_notify[handler_list_id]; 131 132 ACPI_DEBUG_PRINT((ACPI_DB_INFO, 133 "Dispatching Notify on [%4.4s] (%s) Value 0x%2.2X (%s) Node %p\n", 134 acpi_ut_get_node_name(node), 135 acpi_ut_get_type_name(node->type), notify_value, 136 acpi_ut_get_notify_name(notify_value, ACPI_TYPE_ANY), 137 node)); 138 139 status = acpi_os_execute(OSL_NOTIFY_HANDLER, 140 acpi_ev_notify_dispatch, info); 141 if (ACPI_FAILURE(status)) { 142 acpi_ut_delete_generic_state(info); 143 } 144 145 return (status); 146 } 147 148 /******************************************************************************* 149 * 150 * FUNCTION: acpi_ev_notify_dispatch 151 * 152 * PARAMETERS: context - To be passed to the notify handler 153 * 154 * RETURN: None. 155 * 156 * DESCRIPTION: Dispatch a device notification event to a previously 157 * installed handler. 158 * 159 ******************************************************************************/ 160 161 static void ACPI_SYSTEM_XFACE acpi_ev_notify_dispatch(void *context) 162 { 163 union acpi_generic_state *info = (union acpi_generic_state *)context; 164 union acpi_operand_object *handler_obj; 165 166 ACPI_FUNCTION_ENTRY(); 167 168 /* Invoke a global notify handler if installed */ 169 170 if (info->notify.global->handler) { 171 info->notify.global->handler(info->notify.node, 172 info->notify.value, 173 info->notify.global->context); 174 } 175 176 /* Now invoke the local notify handler(s) if any are installed */ 177 178 handler_obj = info->notify.handler_list_head; 179 while (handler_obj) { 180 handler_obj->notify.handler(info->notify.node, 181 info->notify.value, 182 handler_obj->notify.context); 183 184 handler_obj = 185 handler_obj->notify.next[info->notify.handler_list_id]; 186 } 187 188 /* All done with the info object */ 189 190 acpi_ut_delete_generic_state(info); 191 } 192 193 #if (!ACPI_REDUCED_HARDWARE) 194 /****************************************************************************** 195 * 196 * FUNCTION: acpi_ev_terminate 197 * 198 * PARAMETERS: none 199 * 200 * RETURN: none 201 * 202 * DESCRIPTION: Disable events and free memory allocated for table storage. 203 * 204 ******************************************************************************/ 205 206 void acpi_ev_terminate(void) 207 { 208 u32 i; 209 acpi_status status; 210 211 ACPI_FUNCTION_TRACE(ev_terminate); 212 213 if (acpi_gbl_events_initialized) { 214 /* 215 * Disable all event-related functionality. In all cases, on error, 216 * print a message but obviously we don't abort. 217 */ 218 219 /* Disable all fixed events */ 220 221 for (i = 0; i < ACPI_NUM_FIXED_EVENTS; i++) { 222 status = acpi_disable_event(i, 0); 223 if (ACPI_FAILURE(status)) { 224 ACPI_ERROR((AE_INFO, 225 "Could not disable fixed event %u", 226 (u32) i)); 227 } 228 } 229 230 /* Disable all GPEs in all GPE blocks */ 231 232 status = acpi_ev_walk_gpe_list(acpi_hw_disable_gpe_block, NULL); 233 if (ACPI_FAILURE(status)) { 234 ACPI_EXCEPTION((AE_INFO, status, 235 "Could not disable GPEs in GPE block")); 236 } 237 238 status = acpi_ev_remove_global_lock_handler(); 239 if (ACPI_FAILURE(status)) { 240 ACPI_EXCEPTION((AE_INFO, status, 241 "Could not remove Global Lock handler")); 242 } 243 244 acpi_gbl_events_initialized = FALSE; 245 } 246 247 /* Remove SCI handlers */ 248 249 status = acpi_ev_remove_all_sci_handlers(); 250 if (ACPI_FAILURE(status)) { 251 ACPI_ERROR((AE_INFO, "Could not remove SCI handler")); 252 } 253 254 /* Deallocate all handler objects installed within GPE info structs */ 255 256 status = acpi_ev_walk_gpe_list(acpi_ev_delete_gpe_handlers, NULL); 257 if (ACPI_FAILURE(status)) { 258 ACPI_EXCEPTION((AE_INFO, status, 259 "Could not delete GPE handlers")); 260 } 261 262 /* Return to original mode if necessary */ 263 264 if (acpi_gbl_original_mode == ACPI_SYS_MODE_LEGACY) { 265 status = acpi_disable(); 266 if (ACPI_FAILURE(status)) { 267 ACPI_WARNING((AE_INFO, "AcpiDisable failed")); 268 } 269 } 270 return_VOID; 271 } 272 273 #endif /* !ACPI_REDUCED_HARDWARE */ 274