Branch data Line data Source code
1 : : // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 2 : : /****************************************************************************** 3 : : * 4 : : * Module Name: evgpeutil - GPE utilities 5 : : * 6 : : * Copyright (C) 2000 - 2020, Intel Corp. 7 : : * 8 : : *****************************************************************************/ 9 : : 10 : : #include <acpi/acpi.h> 11 : : #include "accommon.h" 12 : : #include "acevents.h" 13 : : 14 : : #define _COMPONENT ACPI_EVENTS 15 : : ACPI_MODULE_NAME("evgpeutil") 16 : : 17 : : #if (!ACPI_REDUCED_HARDWARE) /* Entire module */ 18 : : /******************************************************************************* 19 : : * 20 : : * FUNCTION: acpi_ev_walk_gpe_list 21 : : * 22 : : * PARAMETERS: gpe_walk_callback - Routine called for each GPE block 23 : : * context - Value passed to callback 24 : : * 25 : : * RETURN: Status 26 : : * 27 : : * DESCRIPTION: Walk the GPE lists. 28 : : * 29 : : ******************************************************************************/ 30 : : acpi_status 31 : 78 : acpi_ev_walk_gpe_list(acpi_gpe_callback gpe_walk_callback, void *context) 32 : : { 33 : 78 : struct acpi_gpe_block_info *gpe_block; 34 : 78 : struct acpi_gpe_xrupt_info *gpe_xrupt_info; 35 : 78 : acpi_status status = AE_OK; 36 : 78 : acpi_cpu_flags flags; 37 : : 38 : 78 : ACPI_FUNCTION_TRACE(ev_walk_gpe_list); 39 : : 40 : 78 : flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); 41 : : 42 : : /* Walk the interrupt level descriptor list */ 43 : : 44 : 78 : gpe_xrupt_info = acpi_gbl_gpe_xrupt_list_head; 45 [ + + ]: 156 : while (gpe_xrupt_info) { 46 : : 47 : : /* Walk all Gpe Blocks attached to this interrupt level */ 48 : : 49 : 78 : gpe_block = gpe_xrupt_info->gpe_block_list_head; 50 [ + + ]: 156 : while (gpe_block) { 51 : : 52 : : /* One callback per GPE block */ 53 : : 54 : 78 : status = 55 : 78 : gpe_walk_callback(gpe_xrupt_info, gpe_block, 56 : : context); 57 [ - + ]: 78 : if (ACPI_FAILURE(status)) { 58 [ # # ]: 0 : if (status == AE_CTRL_END) { /* Callback abort */ 59 : 0 : status = AE_OK; 60 : : } 61 : 0 : goto unlock_and_exit; 62 : : } 63 : : 64 : 78 : gpe_block = gpe_block->next; 65 : : } 66 : : 67 : 78 : gpe_xrupt_info = gpe_xrupt_info->next; 68 : : } 69 : : 70 : 78 : unlock_and_exit: 71 : 78 : acpi_os_release_lock(acpi_gbl_gpe_lock, flags); 72 : 78 : return_ACPI_STATUS(status); 73 : : } 74 : : 75 : : /******************************************************************************* 76 : : * 77 : : * FUNCTION: acpi_ev_get_gpe_device 78 : : * 79 : : * PARAMETERS: GPE_WALK_CALLBACK 80 : : * 81 : : * RETURN: Status 82 : : * 83 : : * DESCRIPTION: Matches the input GPE index (0-current_gpe_count) with a GPE 84 : : * block device. NULL if the GPE is one of the FADT-defined GPEs. 85 : : * 86 : : ******************************************************************************/ 87 : : 88 : : acpi_status 89 : 0 : acpi_ev_get_gpe_device(struct acpi_gpe_xrupt_info *gpe_xrupt_info, 90 : : struct acpi_gpe_block_info *gpe_block, void *context) 91 : : { 92 : 0 : struct acpi_gpe_device_info *info = context; 93 : : 94 : : /* Increment Index by the number of GPEs in this block */ 95 : : 96 : 0 : info->next_block_base_index += gpe_block->gpe_count; 97 : : 98 [ # # ]: 0 : if (info->index < info->next_block_base_index) { 99 : : /* 100 : : * The GPE index is within this block, get the node. Leave the node 101 : : * NULL for the FADT-defined GPEs 102 : : */ 103 [ # # ]: 0 : if ((gpe_block->node)->type == ACPI_TYPE_DEVICE) { 104 : 0 : info->gpe_device = gpe_block->node; 105 : : } 106 : : 107 : 0 : info->status = AE_OK; 108 : 0 : return (AE_CTRL_END); 109 : : } 110 : : 111 : : return (AE_OK); 112 : : } 113 : : 114 : : /******************************************************************************* 115 : : * 116 : : * FUNCTION: acpi_ev_get_gpe_xrupt_block 117 : : * 118 : : * PARAMETERS: interrupt_number - Interrupt for a GPE block 119 : : * gpe_xrupt_block - Where the block is returned 120 : : * 121 : : * RETURN: Status 122 : : * 123 : : * DESCRIPTION: Get or Create a GPE interrupt block. There is one interrupt 124 : : * block per unique interrupt level used for GPEs. Should be 125 : : * called only when the GPE lists are semaphore locked and not 126 : : * subject to change. 127 : : * 128 : : ******************************************************************************/ 129 : : 130 : : acpi_status 131 : 78 : acpi_ev_get_gpe_xrupt_block(u32 interrupt_number, 132 : : struct acpi_gpe_xrupt_info **gpe_xrupt_block) 133 : : { 134 : 78 : struct acpi_gpe_xrupt_info *next_gpe_xrupt; 135 : 78 : struct acpi_gpe_xrupt_info *gpe_xrupt; 136 : 78 : acpi_status status; 137 : 78 : acpi_cpu_flags flags; 138 : : 139 : 78 : ACPI_FUNCTION_TRACE(ev_get_gpe_xrupt_block); 140 : : 141 : : /* No need for lock since we are not changing any list elements here */ 142 : : 143 : 78 : next_gpe_xrupt = acpi_gbl_gpe_xrupt_list_head; 144 [ - + ]: 78 : while (next_gpe_xrupt) { 145 [ # # ]: 0 : if (next_gpe_xrupt->interrupt_number == interrupt_number) { 146 : 0 : *gpe_xrupt_block = next_gpe_xrupt; 147 : 0 : return_ACPI_STATUS(AE_OK); 148 : : } 149 : : 150 : 0 : next_gpe_xrupt = next_gpe_xrupt->next; 151 : : } 152 : : 153 : : /* Not found, must allocate a new xrupt descriptor */ 154 : : 155 : 78 : gpe_xrupt = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_gpe_xrupt_info)); 156 [ + - ]: 78 : if (!gpe_xrupt) { 157 : : return_ACPI_STATUS(AE_NO_MEMORY); 158 : : } 159 : : 160 : 78 : gpe_xrupt->interrupt_number = interrupt_number; 161 : : 162 : : /* Install new interrupt descriptor with spin lock */ 163 : : 164 : 78 : flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); 165 [ - + ]: 78 : if (acpi_gbl_gpe_xrupt_list_head) { 166 : : next_gpe_xrupt = acpi_gbl_gpe_xrupt_list_head; 167 [ # # ]: 0 : while (next_gpe_xrupt->next) { 168 : : next_gpe_xrupt = next_gpe_xrupt->next; 169 : : } 170 : : 171 : 0 : next_gpe_xrupt->next = gpe_xrupt; 172 : 0 : gpe_xrupt->previous = next_gpe_xrupt; 173 : : } else { 174 : 78 : acpi_gbl_gpe_xrupt_list_head = gpe_xrupt; 175 : : } 176 : : 177 : 78 : acpi_os_release_lock(acpi_gbl_gpe_lock, flags); 178 : : 179 : : /* Install new interrupt handler if not SCI_INT */ 180 : : 181 [ - + ]: 78 : if (interrupt_number != acpi_gbl_FADT.sci_interrupt) { 182 : 0 : status = acpi_os_install_interrupt_handler(interrupt_number, 183 : : acpi_ev_gpe_xrupt_handler, 184 : : gpe_xrupt); 185 [ # # ]: 0 : if (ACPI_FAILURE(status)) { 186 : 0 : ACPI_EXCEPTION((AE_INFO, status, 187 : : "Could not install GPE interrupt handler at level 0x%X", 188 : : interrupt_number)); 189 : 0 : return_ACPI_STATUS(status); 190 : : } 191 : : } 192 : : 193 : 78 : *gpe_xrupt_block = gpe_xrupt; 194 : 78 : return_ACPI_STATUS(AE_OK); 195 : : } 196 : : 197 : : /******************************************************************************* 198 : : * 199 : : * FUNCTION: acpi_ev_delete_gpe_xrupt 200 : : * 201 : : * PARAMETERS: gpe_xrupt - A GPE interrupt info block 202 : : * 203 : : * RETURN: Status 204 : : * 205 : : * DESCRIPTION: Remove and free a gpe_xrupt block. Remove an associated 206 : : * interrupt handler if not the SCI interrupt. 207 : : * 208 : : ******************************************************************************/ 209 : : 210 : 0 : acpi_status acpi_ev_delete_gpe_xrupt(struct acpi_gpe_xrupt_info *gpe_xrupt) 211 : : { 212 : 0 : acpi_status status; 213 : 0 : acpi_cpu_flags flags; 214 : : 215 : 0 : ACPI_FUNCTION_TRACE(ev_delete_gpe_xrupt); 216 : : 217 : : /* We never want to remove the SCI interrupt handler */ 218 : : 219 [ # # ]: 0 : if (gpe_xrupt->interrupt_number == acpi_gbl_FADT.sci_interrupt) { 220 : 0 : gpe_xrupt->gpe_block_list_head = NULL; 221 : 0 : return_ACPI_STATUS(AE_OK); 222 : : } 223 : : 224 : : /* Disable this interrupt */ 225 : : 226 : 0 : status = 227 : 0 : acpi_os_remove_interrupt_handler(gpe_xrupt->interrupt_number, 228 : : acpi_ev_gpe_xrupt_handler); 229 [ # # ]: 0 : if (ACPI_FAILURE(status)) { 230 : : return_ACPI_STATUS(status); 231 : : } 232 : : 233 : : /* Unlink the interrupt block with lock */ 234 : : 235 : 0 : flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); 236 [ # # ]: 0 : if (gpe_xrupt->previous) { 237 : 0 : gpe_xrupt->previous->next = gpe_xrupt->next; 238 : : } else { 239 : : /* No previous, update list head */ 240 : : 241 : 0 : acpi_gbl_gpe_xrupt_list_head = gpe_xrupt->next; 242 : : } 243 : : 244 [ # # ]: 0 : if (gpe_xrupt->next) { 245 : 0 : gpe_xrupt->next->previous = gpe_xrupt->previous; 246 : : } 247 : 0 : acpi_os_release_lock(acpi_gbl_gpe_lock, flags); 248 : : 249 : : /* Free the block */ 250 : : 251 : 0 : ACPI_FREE(gpe_xrupt); 252 : 0 : return_ACPI_STATUS(AE_OK); 253 : : } 254 : : 255 : : /******************************************************************************* 256 : : * 257 : : * FUNCTION: acpi_ev_delete_gpe_handlers 258 : : * 259 : : * PARAMETERS: gpe_xrupt_info - GPE Interrupt info 260 : : * gpe_block - Gpe Block info 261 : : * 262 : : * RETURN: Status 263 : : * 264 : : * DESCRIPTION: Delete all Handler objects found in the GPE data structs. 265 : : * Used only prior to termination. 266 : : * 267 : : ******************************************************************************/ 268 : : 269 : : acpi_status 270 : 0 : acpi_ev_delete_gpe_handlers(struct acpi_gpe_xrupt_info *gpe_xrupt_info, 271 : : struct acpi_gpe_block_info *gpe_block, 272 : : void *context) 273 : : { 274 : 0 : struct acpi_gpe_event_info *gpe_event_info; 275 : 0 : struct acpi_gpe_notify_info *notify; 276 : 0 : struct acpi_gpe_notify_info *next; 277 : 0 : u32 i; 278 : 0 : u32 j; 279 : : 280 : 0 : ACPI_FUNCTION_TRACE(ev_delete_gpe_handlers); 281 : : 282 : : /* Examine each GPE Register within the block */ 283 : : 284 [ # # ]: 0 : for (i = 0; i < gpe_block->register_count; i++) { 285 : : 286 : : /* Now look at the individual GPEs in this byte register */ 287 : : 288 [ # # ]: 0 : for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) { 289 : 0 : gpe_event_info = &gpe_block->event_info[((acpi_size)i * 290 : : ACPI_GPE_REGISTER_WIDTH) 291 : 0 : + j]; 292 : : 293 : 0 : if ((ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) == 294 [ # # ]: 0 : ACPI_GPE_DISPATCH_HANDLER) || 295 : : (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) == 296 : : ACPI_GPE_DISPATCH_RAW_HANDLER)) { 297 : : 298 : : /* Delete an installed handler block */ 299 : : 300 : 0 : ACPI_FREE(gpe_event_info->dispatch.handler); 301 : 0 : gpe_event_info->dispatch.handler = NULL; 302 : 0 : gpe_event_info->flags &= 303 : : ~ACPI_GPE_DISPATCH_MASK; 304 [ # # ]: 0 : } else if (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) 305 : : == ACPI_GPE_DISPATCH_NOTIFY) { 306 : : 307 : : /* Delete the implicit notification device list */ 308 : : 309 : 0 : notify = gpe_event_info->dispatch.notify_list; 310 [ # # ]: 0 : while (notify) { 311 : 0 : next = notify->next; 312 : 0 : ACPI_FREE(notify); 313 : 0 : notify = next; 314 : : } 315 : : 316 : 0 : gpe_event_info->dispatch.notify_list = NULL; 317 : 0 : gpe_event_info->flags &= 318 : : ~ACPI_GPE_DISPATCH_MASK; 319 : : } 320 : : } 321 : : } 322 : : 323 : 0 : return_ACPI_STATUS(AE_OK); 324 : : } 325 : : 326 : : #endif /* !ACPI_REDUCED_HARDWARE */