1 /****************************************************************************** 2 * 3 * Module Name: evgpeutil - GPE utilities 4 * 5 *****************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2017, Intel Corp. 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions, and the following disclaimer, 16 * without modification. 17 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 18 * substantially similar to the "NO WARRANTY" disclaimer below 19 * ("Disclaimer") and any redistribution must be conditioned upon 20 * including a substantially similar Disclaimer requirement for further 21 * binary redistribution. 22 * 3. Neither the names of the above-listed copyright holders nor the names 23 * of any contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * Alternatively, this software may be distributed under the terms of the 27 * GNU General Public License ("GPL") version 2 as published by the Free 28 * Software Foundation. 29 * 30 * NO WARRANTY 31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 32 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 33 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 34 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 35 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 37 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 40 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 41 * POSSIBILITY OF SUCH DAMAGES. 42 */ 43 44 #include <contrib/dev/acpica/include/acpi.h> 45 #include <contrib/dev/acpica/include/accommon.h> 46 #include <contrib/dev/acpica/include/acevents.h> 47 48 #define _COMPONENT ACPI_EVENTS 49 ACPI_MODULE_NAME ("evgpeutil") 50 51 52 #if (!ACPI_REDUCED_HARDWARE) /* Entire module */ 53 /******************************************************************************* 54 * 55 * FUNCTION: AcpiEvWalkGpeList 56 * 57 * PARAMETERS: GpeWalkCallback - Routine called for each GPE block 58 * Context - Value passed to callback 59 * 60 * RETURN: Status 61 * 62 * DESCRIPTION: Walk the GPE lists. 63 * 64 ******************************************************************************/ 65 66 ACPI_STATUS 67 AcpiEvWalkGpeList ( 68 ACPI_GPE_CALLBACK GpeWalkCallback, 69 void *Context) 70 { 71 ACPI_GPE_BLOCK_INFO *GpeBlock; 72 ACPI_GPE_XRUPT_INFO *GpeXruptInfo; 73 ACPI_STATUS Status = AE_OK; 74 ACPI_CPU_FLAGS Flags; 75 76 77 ACPI_FUNCTION_TRACE (EvWalkGpeList); 78 79 80 Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock); 81 82 /* Walk the interrupt level descriptor list */ 83 84 GpeXruptInfo = AcpiGbl_GpeXruptListHead; 85 while (GpeXruptInfo) 86 { 87 /* Walk all Gpe Blocks attached to this interrupt level */ 88 89 GpeBlock = GpeXruptInfo->GpeBlockListHead; 90 while (GpeBlock) 91 { 92 /* One callback per GPE block */ 93 94 Status = GpeWalkCallback (GpeXruptInfo, GpeBlock, Context); 95 if (ACPI_FAILURE (Status)) 96 { 97 if (Status == AE_CTRL_END) /* Callback abort */ 98 { 99 Status = AE_OK; 100 } 101 goto UnlockAndExit; 102 } 103 104 GpeBlock = GpeBlock->Next; 105 } 106 107 GpeXruptInfo = GpeXruptInfo->Next; 108 } 109 110 UnlockAndExit: 111 AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags); 112 return_ACPI_STATUS (Status); 113 } 114 115 116 /******************************************************************************* 117 * 118 * FUNCTION: AcpiEvGetGpeDevice 119 * 120 * PARAMETERS: GPE_WALK_CALLBACK 121 * 122 * RETURN: Status 123 * 124 * DESCRIPTION: Matches the input GPE index (0-CurrentGpeCount) with a GPE 125 * block device. NULL if the GPE is one of the FADT-defined GPEs. 126 * 127 ******************************************************************************/ 128 129 ACPI_STATUS 130 AcpiEvGetGpeDevice ( 131 ACPI_GPE_XRUPT_INFO *GpeXruptInfo, 132 ACPI_GPE_BLOCK_INFO *GpeBlock, 133 void *Context) 134 { 135 ACPI_GPE_DEVICE_INFO *Info = Context; 136 137 138 /* Increment Index by the number of GPEs in this block */ 139 140 Info->NextBlockBaseIndex += GpeBlock->GpeCount; 141 142 if (Info->Index < Info->NextBlockBaseIndex) 143 { 144 /* 145 * The GPE index is within this block, get the node. Leave the node 146 * NULL for the FADT-defined GPEs 147 */ 148 if ((GpeBlock->Node)->Type == ACPI_TYPE_DEVICE) 149 { 150 Info->GpeDevice = GpeBlock->Node; 151 } 152 153 Info->Status = AE_OK; 154 return (AE_CTRL_END); 155 } 156 157 return (AE_OK); 158 } 159 160 161 /******************************************************************************* 162 * 163 * FUNCTION: AcpiEvGetGpeXruptBlock 164 * 165 * PARAMETERS: InterruptNumber - Interrupt for a GPE block 166 * GpeXruptBlock - Where the block is returned 167 * 168 * RETURN: Status 169 * 170 * DESCRIPTION: Get or Create a GPE interrupt block. There is one interrupt 171 * block per unique interrupt level used for GPEs. Should be 172 * called only when the GPE lists are semaphore locked and not 173 * subject to change. 174 * 175 ******************************************************************************/ 176 177 ACPI_STATUS 178 AcpiEvGetGpeXruptBlock ( 179 UINT32 InterruptNumber, 180 ACPI_GPE_XRUPT_INFO **GpeXruptBlock) 181 { 182 ACPI_GPE_XRUPT_INFO *NextGpeXrupt; 183 ACPI_GPE_XRUPT_INFO *GpeXrupt; 184 ACPI_STATUS Status; 185 ACPI_CPU_FLAGS Flags; 186 187 188 ACPI_FUNCTION_TRACE (EvGetGpeXruptBlock); 189 190 191 /* No need for lock since we are not changing any list elements here */ 192 193 NextGpeXrupt = AcpiGbl_GpeXruptListHead; 194 while (NextGpeXrupt) 195 { 196 if (NextGpeXrupt->InterruptNumber == InterruptNumber) 197 { 198 *GpeXruptBlock = NextGpeXrupt; 199 return_ACPI_STATUS (AE_OK); 200 } 201 202 NextGpeXrupt = NextGpeXrupt->Next; 203 } 204 205 /* Not found, must allocate a new xrupt descriptor */ 206 207 GpeXrupt = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_GPE_XRUPT_INFO)); 208 if (!GpeXrupt) 209 { 210 return_ACPI_STATUS (AE_NO_MEMORY); 211 } 212 213 GpeXrupt->InterruptNumber = InterruptNumber; 214 215 /* Install new interrupt descriptor with spin lock */ 216 217 Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock); 218 if (AcpiGbl_GpeXruptListHead) 219 { 220 NextGpeXrupt = AcpiGbl_GpeXruptListHead; 221 while (NextGpeXrupt->Next) 222 { 223 NextGpeXrupt = NextGpeXrupt->Next; 224 } 225 226 NextGpeXrupt->Next = GpeXrupt; 227 GpeXrupt->Previous = NextGpeXrupt; 228 } 229 else 230 { 231 AcpiGbl_GpeXruptListHead = GpeXrupt; 232 } 233 234 AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags); 235 236 /* Install new interrupt handler if not SCI_INT */ 237 238 if (InterruptNumber != AcpiGbl_FADT.SciInterrupt) 239 { 240 Status = AcpiOsInstallInterruptHandler (InterruptNumber, 241 AcpiEvGpeXruptHandler, GpeXrupt); 242 if (ACPI_FAILURE (Status)) 243 { 244 ACPI_EXCEPTION ((AE_INFO, Status, 245 "Could not install GPE interrupt handler at level 0x%X", 246 InterruptNumber)); 247 return_ACPI_STATUS (Status); 248 } 249 } 250 251 *GpeXruptBlock = GpeXrupt; 252 return_ACPI_STATUS (AE_OK); 253 } 254 255 256 /******************************************************************************* 257 * 258 * FUNCTION: AcpiEvDeleteGpeXrupt 259 * 260 * PARAMETERS: GpeXrupt - A GPE interrupt info block 261 * 262 * RETURN: Status 263 * 264 * DESCRIPTION: Remove and free a GpeXrupt block. Remove an associated 265 * interrupt handler if not the SCI interrupt. 266 * 267 ******************************************************************************/ 268 269 ACPI_STATUS 270 AcpiEvDeleteGpeXrupt ( 271 ACPI_GPE_XRUPT_INFO *GpeXrupt) 272 { 273 ACPI_STATUS Status; 274 ACPI_CPU_FLAGS Flags; 275 276 277 ACPI_FUNCTION_TRACE (EvDeleteGpeXrupt); 278 279 280 /* We never want to remove the SCI interrupt handler */ 281 282 if (GpeXrupt->InterruptNumber == AcpiGbl_FADT.SciInterrupt) 283 { 284 GpeXrupt->GpeBlockListHead = NULL; 285 return_ACPI_STATUS (AE_OK); 286 } 287 288 /* Disable this interrupt */ 289 290 Status = AcpiOsRemoveInterruptHandler ( 291 GpeXrupt->InterruptNumber, AcpiEvGpeXruptHandler); 292 if (ACPI_FAILURE (Status)) 293 { 294 return_ACPI_STATUS (Status); 295 } 296 297 /* Unlink the interrupt block with lock */ 298 299 Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock); 300 if (GpeXrupt->Previous) 301 { 302 GpeXrupt->Previous->Next = GpeXrupt->Next; 303 } 304 else 305 { 306 /* No previous, update list head */ 307 308 AcpiGbl_GpeXruptListHead = GpeXrupt->Next; 309 } 310 311 if (GpeXrupt->Next) 312 { 313 GpeXrupt->Next->Previous = GpeXrupt->Previous; 314 } 315 AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags); 316 317 /* Free the block */ 318 319 ACPI_FREE (GpeXrupt); 320 return_ACPI_STATUS (AE_OK); 321 } 322 323 324 /******************************************************************************* 325 * 326 * FUNCTION: AcpiEvDeleteGpeHandlers 327 * 328 * PARAMETERS: GpeXruptInfo - GPE Interrupt info 329 * GpeBlock - Gpe Block info 330 * 331 * RETURN: Status 332 * 333 * DESCRIPTION: Delete all Handler objects found in the GPE data structs. 334 * Used only prior to termination. 335 * 336 ******************************************************************************/ 337 338 ACPI_STATUS 339 AcpiEvDeleteGpeHandlers ( 340 ACPI_GPE_XRUPT_INFO *GpeXruptInfo, 341 ACPI_GPE_BLOCK_INFO *GpeBlock, 342 void *Context) 343 { 344 ACPI_GPE_EVENT_INFO *GpeEventInfo; 345 ACPI_GPE_NOTIFY_INFO *Notify; 346 ACPI_GPE_NOTIFY_INFO *Next; 347 UINT32 i; 348 UINT32 j; 349 350 351 ACPI_FUNCTION_TRACE (EvDeleteGpeHandlers); 352 353 354 /* Examine each GPE Register within the block */ 355 356 for (i = 0; i < GpeBlock->RegisterCount; i++) 357 { 358 /* Now look at the individual GPEs in this byte register */ 359 360 for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) 361 { 362 GpeEventInfo = &GpeBlock->EventInfo[((ACPI_SIZE) i * 363 ACPI_GPE_REGISTER_WIDTH) + j]; 364 365 if ((ACPI_GPE_DISPATCH_TYPE (GpeEventInfo->Flags) == 366 ACPI_GPE_DISPATCH_HANDLER) || 367 (ACPI_GPE_DISPATCH_TYPE (GpeEventInfo->Flags) == 368 ACPI_GPE_DISPATCH_RAW_HANDLER)) 369 { 370 /* Delete an installed handler block */ 371 372 ACPI_FREE (GpeEventInfo->Dispatch.Handler); 373 GpeEventInfo->Dispatch.Handler = NULL; 374 GpeEventInfo->Flags &= ~ACPI_GPE_DISPATCH_MASK; 375 } 376 else if (ACPI_GPE_DISPATCH_TYPE (GpeEventInfo->Flags) == 377 ACPI_GPE_DISPATCH_NOTIFY) 378 { 379 /* Delete the implicit notification device list */ 380 381 Notify = GpeEventInfo->Dispatch.NotifyList; 382 while (Notify) 383 { 384 Next = Notify->Next; 385 ACPI_FREE (Notify); 386 Notify = Next; 387 } 388 389 GpeEventInfo->Dispatch.NotifyList = NULL; 390 GpeEventInfo->Flags &= ~ACPI_GPE_DISPATCH_MASK; 391 } 392 } 393 } 394 395 return_ACPI_STATUS (AE_OK); 396 } 397 398 #endif /* !ACPI_REDUCED_HARDWARE */ 399