1 /****************************************************************************** 2 * 3 * Module Name: evgpeutil - GPE utilities 4 * 5 *****************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2011, 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 45 #include "acpi.h" 46 #include "accommon.h" 47 #include "acevents.h" 48 49 #define _COMPONENT ACPI_EVENTS 50 ACPI_MODULE_NAME ("evgpeutil") 51 52 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: AcpiEvValidGpeEvent 119 * 120 * PARAMETERS: GpeEventInfo - Info for this GPE 121 * 122 * RETURN: TRUE if the GpeEvent is valid 123 * 124 * DESCRIPTION: Validate a GPE event. DO NOT CALL FROM INTERRUPT LEVEL. 125 * Should be called only when the GPE lists are semaphore locked 126 * and not subject to change. 127 * 128 ******************************************************************************/ 129 130 BOOLEAN 131 AcpiEvValidGpeEvent ( 132 ACPI_GPE_EVENT_INFO *GpeEventInfo) 133 { 134 ACPI_GPE_XRUPT_INFO *GpeXruptBlock; 135 ACPI_GPE_BLOCK_INFO *GpeBlock; 136 137 138 ACPI_FUNCTION_ENTRY (); 139 140 141 /* No need for spin lock since we are not changing any list elements */ 142 143 /* Walk the GPE interrupt levels */ 144 145 GpeXruptBlock = AcpiGbl_GpeXruptListHead; 146 while (GpeXruptBlock) 147 { 148 GpeBlock = GpeXruptBlock->GpeBlockListHead; 149 150 /* Walk the GPE blocks on this interrupt level */ 151 152 while (GpeBlock) 153 { 154 if ((&GpeBlock->EventInfo[0] <= GpeEventInfo) && 155 (&GpeBlock->EventInfo[GpeBlock->GpeCount] > GpeEventInfo)) 156 { 157 return (TRUE); 158 } 159 160 GpeBlock = GpeBlock->Next; 161 } 162 163 GpeXruptBlock = GpeXruptBlock->Next; 164 } 165 166 return (FALSE); 167 } 168 169 170 /******************************************************************************* 171 * 172 * FUNCTION: AcpiEvGetGpeDevice 173 * 174 * PARAMETERS: GPE_WALK_CALLBACK 175 * 176 * RETURN: Status 177 * 178 * DESCRIPTION: Matches the input GPE index (0-CurrentGpeCount) with a GPE 179 * block device. NULL if the GPE is one of the FADT-defined GPEs. 180 * 181 ******************************************************************************/ 182 183 ACPI_STATUS 184 AcpiEvGetGpeDevice ( 185 ACPI_GPE_XRUPT_INFO *GpeXruptInfo, 186 ACPI_GPE_BLOCK_INFO *GpeBlock, 187 void *Context) 188 { 189 ACPI_GPE_DEVICE_INFO *Info = Context; 190 191 192 /* Increment Index by the number of GPEs in this block */ 193 194 Info->NextBlockBaseIndex += GpeBlock->GpeCount; 195 196 if (Info->Index < Info->NextBlockBaseIndex) 197 { 198 /* 199 * The GPE index is within this block, get the node. Leave the node 200 * NULL for the FADT-defined GPEs 201 */ 202 if ((GpeBlock->Node)->Type == ACPI_TYPE_DEVICE) 203 { 204 Info->GpeDevice = GpeBlock->Node; 205 } 206 207 Info->Status = AE_OK; 208 return (AE_CTRL_END); 209 } 210 211 return (AE_OK); 212 } 213 214 215 /******************************************************************************* 216 * 217 * FUNCTION: AcpiEvGetGpeXruptBlock 218 * 219 * PARAMETERS: InterruptNumber - Interrupt for a GPE block 220 * 221 * RETURN: A GPE interrupt block 222 * 223 * DESCRIPTION: Get or Create a GPE interrupt block. There is one interrupt 224 * block per unique interrupt level used for GPEs. Should be 225 * called only when the GPE lists are semaphore locked and not 226 * subject to change. 227 * 228 ******************************************************************************/ 229 230 ACPI_GPE_XRUPT_INFO * 231 AcpiEvGetGpeXruptBlock ( 232 UINT32 InterruptNumber) 233 { 234 ACPI_GPE_XRUPT_INFO *NextGpeXrupt; 235 ACPI_GPE_XRUPT_INFO *GpeXrupt; 236 ACPI_STATUS Status; 237 ACPI_CPU_FLAGS Flags; 238 239 240 ACPI_FUNCTION_TRACE (EvGetGpeXruptBlock); 241 242 243 /* No need for lock since we are not changing any list elements here */ 244 245 NextGpeXrupt = AcpiGbl_GpeXruptListHead; 246 while (NextGpeXrupt) 247 { 248 if (NextGpeXrupt->InterruptNumber == InterruptNumber) 249 { 250 return_PTR (NextGpeXrupt); 251 } 252 253 NextGpeXrupt = NextGpeXrupt->Next; 254 } 255 256 /* Not found, must allocate a new xrupt descriptor */ 257 258 GpeXrupt = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_GPE_XRUPT_INFO)); 259 if (!GpeXrupt) 260 { 261 return_PTR (NULL); 262 } 263 264 GpeXrupt->InterruptNumber = InterruptNumber; 265 266 /* Install new interrupt descriptor with spin lock */ 267 268 Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock); 269 if (AcpiGbl_GpeXruptListHead) 270 { 271 NextGpeXrupt = AcpiGbl_GpeXruptListHead; 272 while (NextGpeXrupt->Next) 273 { 274 NextGpeXrupt = NextGpeXrupt->Next; 275 } 276 277 NextGpeXrupt->Next = GpeXrupt; 278 GpeXrupt->Previous = NextGpeXrupt; 279 } 280 else 281 { 282 AcpiGbl_GpeXruptListHead = GpeXrupt; 283 } 284 AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags); 285 286 /* Install new interrupt handler if not SCI_INT */ 287 288 if (InterruptNumber != AcpiGbl_FADT.SciInterrupt) 289 { 290 Status = AcpiOsInstallInterruptHandler (InterruptNumber, 291 AcpiEvGpeXruptHandler, GpeXrupt); 292 if (ACPI_FAILURE (Status)) 293 { 294 ACPI_ERROR ((AE_INFO, 295 "Could not install GPE interrupt handler at level 0x%X", 296 InterruptNumber)); 297 return_PTR (NULL); 298 } 299 } 300 301 return_PTR (GpeXrupt); 302 } 303 304 305 /******************************************************************************* 306 * 307 * FUNCTION: AcpiEvDeleteGpeXrupt 308 * 309 * PARAMETERS: GpeXrupt - A GPE interrupt info block 310 * 311 * RETURN: Status 312 * 313 * DESCRIPTION: Remove and free a GpeXrupt block. Remove an associated 314 * interrupt handler if not the SCI interrupt. 315 * 316 ******************************************************************************/ 317 318 ACPI_STATUS 319 AcpiEvDeleteGpeXrupt ( 320 ACPI_GPE_XRUPT_INFO *GpeXrupt) 321 { 322 ACPI_STATUS Status; 323 ACPI_CPU_FLAGS Flags; 324 325 326 ACPI_FUNCTION_TRACE (EvDeleteGpeXrupt); 327 328 329 /* We never want to remove the SCI interrupt handler */ 330 331 if (GpeXrupt->InterruptNumber == AcpiGbl_FADT.SciInterrupt) 332 { 333 GpeXrupt->GpeBlockListHead = NULL; 334 return_ACPI_STATUS (AE_OK); 335 } 336 337 /* Disable this interrupt */ 338 339 Status = AcpiOsRemoveInterruptHandler ( 340 GpeXrupt->InterruptNumber, AcpiEvGpeXruptHandler); 341 if (ACPI_FAILURE (Status)) 342 { 343 return_ACPI_STATUS (Status); 344 } 345 346 /* Unlink the interrupt block with lock */ 347 348 Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock); 349 if (GpeXrupt->Previous) 350 { 351 GpeXrupt->Previous->Next = GpeXrupt->Next; 352 } 353 else 354 { 355 /* No previous, update list head */ 356 357 AcpiGbl_GpeXruptListHead = GpeXrupt->Next; 358 } 359 360 if (GpeXrupt->Next) 361 { 362 GpeXrupt->Next->Previous = GpeXrupt->Previous; 363 } 364 AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags); 365 366 /* Free the block */ 367 368 ACPI_FREE (GpeXrupt); 369 return_ACPI_STATUS (AE_OK); 370 } 371 372 373 /******************************************************************************* 374 * 375 * FUNCTION: AcpiEvDeleteGpeHandlers 376 * 377 * PARAMETERS: GpeXruptInfo - GPE Interrupt info 378 * GpeBlock - Gpe Block info 379 * 380 * RETURN: Status 381 * 382 * DESCRIPTION: Delete all Handler objects found in the GPE data structs. 383 * Used only prior to termination. 384 * 385 ******************************************************************************/ 386 387 ACPI_STATUS 388 AcpiEvDeleteGpeHandlers ( 389 ACPI_GPE_XRUPT_INFO *GpeXruptInfo, 390 ACPI_GPE_BLOCK_INFO *GpeBlock, 391 void *Context) 392 { 393 ACPI_GPE_EVENT_INFO *GpeEventInfo; 394 UINT32 i; 395 UINT32 j; 396 397 398 ACPI_FUNCTION_TRACE (EvDeleteGpeHandlers); 399 400 401 /* Examine each GPE Register within the block */ 402 403 for (i = 0; i < GpeBlock->RegisterCount; i++) 404 { 405 /* Now look at the individual GPEs in this byte register */ 406 407 for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) 408 { 409 GpeEventInfo = &GpeBlock->EventInfo[((ACPI_SIZE) i * 410 ACPI_GPE_REGISTER_WIDTH) + j]; 411 412 if ((GpeEventInfo->Flags & ACPI_GPE_DISPATCH_MASK) == 413 ACPI_GPE_DISPATCH_HANDLER) 414 { 415 ACPI_FREE (GpeEventInfo->Dispatch.Handler); 416 GpeEventInfo->Dispatch.Handler = NULL; 417 GpeEventInfo->Flags &= ~ACPI_GPE_DISPATCH_MASK; 418 } 419 } 420 } 421 422 return_ACPI_STATUS (AE_OK); 423 } 424