1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 2 /******************************************************************************* 3 * 4 * Module Name: evsci - System Control Interrupt configuration and 5 * legacy to ACPI mode state transition functions 6 * 7 ******************************************************************************/ 8 9 #include <acpi/acpi.h> 10 #include "accommon.h" 11 #include "acevents.h" 12 13 #define _COMPONENT ACPI_EVENTS 14 ACPI_MODULE_NAME("evsci") 15 #if (!ACPI_REDUCED_HARDWARE) /* Entire module */ 16 /* Local prototypes */ 17 static u32 ACPI_SYSTEM_XFACE acpi_ev_sci_xrupt_handler(void *context); 18 19 /******************************************************************************* 20 * 21 * FUNCTION: acpi_ev_sci_dispatch 22 * 23 * PARAMETERS: None 24 * 25 * RETURN: Status code indicates whether interrupt was handled. 26 * 27 * DESCRIPTION: Dispatch the SCI to all host-installed SCI handlers. 28 * 29 ******************************************************************************/ 30 31 u32 acpi_ev_sci_dispatch(void) 32 { 33 struct acpi_sci_handler_info *sci_handler; 34 acpi_cpu_flags flags; 35 u32 int_status = ACPI_INTERRUPT_NOT_HANDLED; 36 37 ACPI_FUNCTION_NAME(ev_sci_dispatch); 38 39 /* Are there any host-installed SCI handlers? */ 40 41 if (!acpi_gbl_sci_handler_list) { 42 return (int_status); 43 } 44 45 flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); 46 47 /* Invoke all host-installed SCI handlers */ 48 49 sci_handler = acpi_gbl_sci_handler_list; 50 while (sci_handler) { 51 52 /* Invoke the installed handler (at interrupt level) */ 53 54 int_status |= sci_handler->address(sci_handler->context); 55 56 sci_handler = sci_handler->next; 57 } 58 59 acpi_os_release_lock(acpi_gbl_gpe_lock, flags); 60 return (int_status); 61 } 62 63 /******************************************************************************* 64 * 65 * FUNCTION: acpi_ev_sci_xrupt_handler 66 * 67 * PARAMETERS: context - Calling Context 68 * 69 * RETURN: Status code indicates whether interrupt was handled. 70 * 71 * DESCRIPTION: Interrupt handler that will figure out what function or 72 * control method to call to deal with a SCI. 73 * 74 ******************************************************************************/ 75 76 static u32 ACPI_SYSTEM_XFACE acpi_ev_sci_xrupt_handler(void *context) 77 { 78 struct acpi_gpe_xrupt_info *gpe_xrupt_list = context; 79 u32 interrupt_handled = ACPI_INTERRUPT_NOT_HANDLED; 80 81 ACPI_FUNCTION_TRACE(ev_sci_xrupt_handler); 82 83 /* 84 * We are guaranteed by the ACPICA initialization/shutdown code that 85 * if this interrupt handler is installed, ACPI is enabled. 86 */ 87 88 /* 89 * Fixed Events: 90 * Check for and dispatch any Fixed Events that have occurred 91 */ 92 interrupt_handled |= acpi_ev_fixed_event_detect(); 93 94 /* 95 * General Purpose Events: 96 * Check for and dispatch any GPEs that have occurred 97 */ 98 interrupt_handled |= acpi_ev_gpe_detect(gpe_xrupt_list); 99 100 /* Invoke all host-installed SCI handlers */ 101 102 interrupt_handled |= acpi_ev_sci_dispatch(); 103 104 acpi_sci_count++; 105 return_UINT32(interrupt_handled); 106 } 107 108 /******************************************************************************* 109 * 110 * FUNCTION: acpi_ev_gpe_xrupt_handler 111 * 112 * PARAMETERS: context - Calling Context 113 * 114 * RETURN: Status code indicates whether interrupt was handled. 115 * 116 * DESCRIPTION: Handler for GPE Block Device interrupts 117 * 118 ******************************************************************************/ 119 120 u32 ACPI_SYSTEM_XFACE acpi_ev_gpe_xrupt_handler(void *context) 121 { 122 struct acpi_gpe_xrupt_info *gpe_xrupt_list = context; 123 u32 interrupt_handled = ACPI_INTERRUPT_NOT_HANDLED; 124 125 ACPI_FUNCTION_TRACE(ev_gpe_xrupt_handler); 126 127 /* 128 * We are guaranteed by the ACPICA initialization/shutdown code that 129 * if this interrupt handler is installed, ACPI is enabled. 130 */ 131 132 /* GPEs: Check for and dispatch any GPEs that have occurred */ 133 134 interrupt_handled |= acpi_ev_gpe_detect(gpe_xrupt_list); 135 return_UINT32(interrupt_handled); 136 } 137 138 /****************************************************************************** 139 * 140 * FUNCTION: acpi_ev_install_sci_handler 141 * 142 * PARAMETERS: none 143 * 144 * RETURN: Status 145 * 146 * DESCRIPTION: Installs SCI handler. 147 * 148 ******************************************************************************/ 149 150 u32 acpi_ev_install_sci_handler(void) 151 { 152 u32 status = AE_OK; 153 154 ACPI_FUNCTION_TRACE(ev_install_sci_handler); 155 156 status = 157 acpi_os_install_interrupt_handler((u32) acpi_gbl_FADT.sci_interrupt, 158 acpi_ev_sci_xrupt_handler, 159 acpi_gbl_gpe_xrupt_list_head); 160 return_ACPI_STATUS(status); 161 } 162 163 /****************************************************************************** 164 * 165 * FUNCTION: acpi_ev_remove_all_sci_handlers 166 * 167 * PARAMETERS: none 168 * 169 * RETURN: AE_OK if handler uninstalled, AE_ERROR if handler was not 170 * installed to begin with 171 * 172 * DESCRIPTION: Remove the SCI interrupt handler. No further SCIs will be 173 * taken. Remove all host-installed SCI handlers. 174 * 175 * Note: It doesn't seem important to disable all events or set the event 176 * enable registers to their original values. The OS should disable 177 * the SCI interrupt level when the handler is removed, so no more 178 * events will come in. 179 * 180 ******************************************************************************/ 181 182 acpi_status acpi_ev_remove_all_sci_handlers(void) 183 { 184 struct acpi_sci_handler_info *sci_handler; 185 acpi_cpu_flags flags; 186 acpi_status status; 187 188 ACPI_FUNCTION_TRACE(ev_remove_all_sci_handlers); 189 190 /* Just let the OS remove the handler and disable the level */ 191 192 status = 193 acpi_os_remove_interrupt_handler((u32) acpi_gbl_FADT.sci_interrupt, 194 acpi_ev_sci_xrupt_handler); 195 196 if (!acpi_gbl_sci_handler_list) { 197 return (status); 198 } 199 200 flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); 201 202 /* Free all host-installed SCI handlers */ 203 204 while (acpi_gbl_sci_handler_list) { 205 sci_handler = acpi_gbl_sci_handler_list; 206 acpi_gbl_sci_handler_list = sci_handler->next; 207 ACPI_FREE(sci_handler); 208 } 209 210 acpi_os_release_lock(acpi_gbl_gpe_lock, flags); 211 return_ACPI_STATUS(status); 212 } 213 214 #endif /* !ACPI_REDUCED_HARDWARE */ 215