diff options
Diffstat (limited to 'drivers/acpi/events/evmisc.c')
-rw-r--r-- | drivers/acpi/events/evmisc.c | 201 |
1 files changed, 115 insertions, 86 deletions
diff --git a/drivers/acpi/events/evmisc.c b/drivers/acpi/events/evmisc.c index bf63edc6608d..1b784ffe54c3 100644 --- a/drivers/acpi/events/evmisc.c +++ b/drivers/acpi/events/evmisc.c | |||
@@ -5,7 +5,7 @@ | |||
5 | *****************************************************************************/ | 5 | *****************************************************************************/ |
6 | 6 | ||
7 | /* | 7 | /* |
8 | * Copyright (C) 2000 - 2006, R. Byron Moore | 8 | * Copyright (C) 2000 - 2007, R. Byron Moore |
9 | * All rights reserved. | 9 | * All rights reserved. |
10 | * | 10 | * |
11 | * Redistribution and use in source and binary forms, with or without | 11 | * Redistribution and use in source and binary forms, with or without |
@@ -63,14 +63,18 @@ static const char *acpi_notify_value_names[] = { | |||
63 | }; | 63 | }; |
64 | #endif | 64 | #endif |
65 | 65 | ||
66 | /* Pointer to FACS needed for the Global Lock */ | ||
67 | |||
68 | static struct acpi_table_facs *facs = NULL; | ||
69 | |||
66 | /* Local prototypes */ | 70 | /* Local prototypes */ |
67 | 71 | ||
68 | static void ACPI_SYSTEM_XFACE acpi_ev_notify_dispatch(void *context); | 72 | static void ACPI_SYSTEM_XFACE acpi_ev_notify_dispatch(void *context); |
69 | 73 | ||
70 | static void ACPI_SYSTEM_XFACE acpi_ev_global_lock_thread(void *context); | ||
71 | |||
72 | static u32 acpi_ev_global_lock_handler(void *context); | 74 | static u32 acpi_ev_global_lock_handler(void *context); |
73 | 75 | ||
76 | static acpi_status acpi_ev_remove_global_lock_handler(void); | ||
77 | |||
74 | /******************************************************************************* | 78 | /******************************************************************************* |
75 | * | 79 | * |
76 | * FUNCTION: acpi_ev_is_notify_object | 80 | * FUNCTION: acpi_ev_is_notify_object |
@@ -282,49 +286,19 @@ static void ACPI_SYSTEM_XFACE acpi_ev_notify_dispatch(void *context) | |||
282 | 286 | ||
283 | /******************************************************************************* | 287 | /******************************************************************************* |
284 | * | 288 | * |
285 | * FUNCTION: acpi_ev_global_lock_thread | ||
286 | * | ||
287 | * PARAMETERS: Context - From thread interface, not used | ||
288 | * | ||
289 | * RETURN: None | ||
290 | * | ||
291 | * DESCRIPTION: Invoked by SCI interrupt handler upon acquisition of the | ||
292 | * Global Lock. Simply signal all threads that are waiting | ||
293 | * for the lock. | ||
294 | * | ||
295 | ******************************************************************************/ | ||
296 | |||
297 | static void ACPI_SYSTEM_XFACE acpi_ev_global_lock_thread(void *context) | ||
298 | { | ||
299 | acpi_status status; | ||
300 | |||
301 | /* Signal threads that are waiting for the lock */ | ||
302 | |||
303 | if (acpi_gbl_global_lock_thread_count) { | ||
304 | |||
305 | /* Send sufficient units to the semaphore */ | ||
306 | |||
307 | status = | ||
308 | acpi_os_signal_semaphore(acpi_gbl_global_lock_semaphore, | ||
309 | acpi_gbl_global_lock_thread_count); | ||
310 | if (ACPI_FAILURE(status)) { | ||
311 | ACPI_ERROR((AE_INFO, | ||
312 | "Could not signal Global Lock semaphore")); | ||
313 | } | ||
314 | } | ||
315 | } | ||
316 | |||
317 | /******************************************************************************* | ||
318 | * | ||
319 | * FUNCTION: acpi_ev_global_lock_handler | 289 | * FUNCTION: acpi_ev_global_lock_handler |
320 | * | 290 | * |
321 | * PARAMETERS: Context - From thread interface, not used | 291 | * PARAMETERS: Context - From thread interface, not used |
322 | * | 292 | * |
323 | * RETURN: ACPI_INTERRUPT_HANDLED or ACPI_INTERRUPT_NOT_HANDLED | 293 | * RETURN: ACPI_INTERRUPT_HANDLED |
324 | * | 294 | * |
325 | * DESCRIPTION: Invoked directly from the SCI handler when a global lock | 295 | * DESCRIPTION: Invoked directly from the SCI handler when a global lock |
326 | * release interrupt occurs. Grab the global lock and queue | 296 | * release interrupt occurs. Attempt to acquire the global lock, |
327 | * the global lock thread for execution | 297 | * if successful, signal the thread waiting for the lock. |
298 | * | ||
299 | * NOTE: Assumes that the semaphore can be signaled from interrupt level. If | ||
300 | * this is not possible for some reason, a separate thread will have to be | ||
301 | * scheduled to do this. | ||
328 | * | 302 | * |
329 | ******************************************************************************/ | 303 | ******************************************************************************/ |
330 | 304 | ||
@@ -333,16 +307,24 @@ static u32 acpi_ev_global_lock_handler(void *context) | |||
333 | u8 acquired = FALSE; | 307 | u8 acquired = FALSE; |
334 | 308 | ||
335 | /* | 309 | /* |
336 | * Attempt to get the lock | 310 | * Attempt to get the lock. |
311 | * | ||
337 | * If we don't get it now, it will be marked pending and we will | 312 | * If we don't get it now, it will be marked pending and we will |
338 | * take another interrupt when it becomes free. | 313 | * take another interrupt when it becomes free. |
339 | */ | 314 | */ |
340 | ACPI_ACQUIRE_GLOBAL_LOCK(acpi_gbl_common_fACS.global_lock, acquired); | 315 | ACPI_ACQUIRE_GLOBAL_LOCK(facs, acquired); |
341 | if (acquired) { | 316 | if (acquired) { |
342 | 317 | ||
343 | /* Got the lock, now wake all threads waiting for it */ | 318 | /* Got the lock, now wake all threads waiting for it */ |
319 | |||
344 | acpi_gbl_global_lock_acquired = TRUE; | 320 | acpi_gbl_global_lock_acquired = TRUE; |
345 | acpi_ev_global_lock_thread(context); | 321 | /* Send a unit to the semaphore */ |
322 | |||
323 | if (ACPI_FAILURE(acpi_os_signal_semaphore( | ||
324 | acpi_gbl_global_lock_semaphore, 1))) { | ||
325 | ACPI_ERROR((AE_INFO, | ||
326 | "Could not signal Global Lock semaphore")); | ||
327 | } | ||
346 | } | 328 | } |
347 | 329 | ||
348 | return (ACPI_INTERRUPT_HANDLED); | 330 | return (ACPI_INTERRUPT_HANDLED); |
@@ -366,6 +348,13 @@ acpi_status acpi_ev_init_global_lock_handler(void) | |||
366 | 348 | ||
367 | ACPI_FUNCTION_TRACE(ev_init_global_lock_handler); | 349 | ACPI_FUNCTION_TRACE(ev_init_global_lock_handler); |
368 | 350 | ||
351 | status = | ||
352 | acpi_get_table_by_index(ACPI_TABLE_INDEX_FACS, | ||
353 | (struct acpi_table_header **)&facs); | ||
354 | if (ACPI_FAILURE(status)) { | ||
355 | return_ACPI_STATUS(status); | ||
356 | } | ||
357 | |||
369 | acpi_gbl_global_lock_present = TRUE; | 358 | acpi_gbl_global_lock_present = TRUE; |
370 | status = acpi_install_fixed_event_handler(ACPI_EVENT_GLOBAL, | 359 | status = acpi_install_fixed_event_handler(ACPI_EVENT_GLOBAL, |
371 | acpi_ev_global_lock_handler, | 360 | acpi_ev_global_lock_handler, |
@@ -389,6 +378,31 @@ acpi_status acpi_ev_init_global_lock_handler(void) | |||
389 | return_ACPI_STATUS(status); | 378 | return_ACPI_STATUS(status); |
390 | } | 379 | } |
391 | 380 | ||
381 | /******************************************************************************* | ||
382 | * | ||
383 | * FUNCTION: acpi_ev_remove_global_lock_handler | ||
384 | * | ||
385 | * PARAMETERS: None | ||
386 | * | ||
387 | * RETURN: Status | ||
388 | * | ||
389 | * DESCRIPTION: Remove the handler for the Global Lock | ||
390 | * | ||
391 | ******************************************************************************/ | ||
392 | |||
393 | static acpi_status acpi_ev_remove_global_lock_handler(void) | ||
394 | { | ||
395 | acpi_status status; | ||
396 | |||
397 | ACPI_FUNCTION_TRACE(ev_remove_global_lock_handler); | ||
398 | |||
399 | acpi_gbl_global_lock_present = FALSE; | ||
400 | status = acpi_remove_fixed_event_handler(ACPI_EVENT_GLOBAL, | ||
401 | acpi_ev_global_lock_handler); | ||
402 | |||
403 | return_ACPI_STATUS(status); | ||
404 | } | ||
405 | |||
392 | /****************************************************************************** | 406 | /****************************************************************************** |
393 | * | 407 | * |
394 | * FUNCTION: acpi_ev_acquire_global_lock | 408 | * FUNCTION: acpi_ev_acquire_global_lock |
@@ -399,6 +413,16 @@ acpi_status acpi_ev_init_global_lock_handler(void) | |||
399 | * | 413 | * |
400 | * DESCRIPTION: Attempt to gain ownership of the Global Lock. | 414 | * DESCRIPTION: Attempt to gain ownership of the Global Lock. |
401 | * | 415 | * |
416 | * MUTEX: Interpreter must be locked | ||
417 | * | ||
418 | * Note: The original implementation allowed multiple threads to "acquire" the | ||
419 | * Global Lock, and the OS would hold the lock until the last thread had | ||
420 | * released it. However, this could potentially starve the BIOS out of the | ||
421 | * lock, especially in the case where there is a tight handshake between the | ||
422 | * Embedded Controller driver and the BIOS. Therefore, this implementation | ||
423 | * allows only one thread to acquire the HW Global Lock at a time, and makes | ||
424 | * the global lock appear as a standard mutex on the OS side. | ||
425 | * | ||
402 | *****************************************************************************/ | 426 | *****************************************************************************/ |
403 | 427 | ||
404 | acpi_status acpi_ev_acquire_global_lock(u16 timeout) | 428 | acpi_status acpi_ev_acquire_global_lock(u16 timeout) |
@@ -408,53 +432,51 @@ acpi_status acpi_ev_acquire_global_lock(u16 timeout) | |||
408 | 432 | ||
409 | ACPI_FUNCTION_TRACE(ev_acquire_global_lock); | 433 | ACPI_FUNCTION_TRACE(ev_acquire_global_lock); |
410 | 434 | ||
411 | #ifndef ACPI_APPLICATION | 435 | /* |
412 | /* Make sure that we actually have a global lock */ | 436 | * Only one thread can acquire the GL at a time, the global_lock_mutex |
413 | 437 | * enforces this. This interface releases the interpreter if we must wait. | |
414 | if (!acpi_gbl_global_lock_present) { | 438 | */ |
415 | return_ACPI_STATUS(AE_NO_GLOBAL_LOCK); | 439 | status = acpi_ex_system_wait_mutex(acpi_gbl_global_lock_mutex, timeout); |
440 | if (ACPI_FAILURE(status)) { | ||
441 | return_ACPI_STATUS(status); | ||
416 | } | 442 | } |
417 | #endif | ||
418 | |||
419 | /* One more thread wants the global lock */ | ||
420 | |||
421 | acpi_gbl_global_lock_thread_count++; | ||
422 | 443 | ||
423 | /* | 444 | /* |
424 | * If we (OS side vs. BIOS side) have the hardware lock already, | 445 | * Make sure that a global lock actually exists. If not, just treat |
425 | * we are done | 446 | * the lock as a standard mutex. |
426 | */ | 447 | */ |
427 | if (acpi_gbl_global_lock_acquired) { | 448 | if (!acpi_gbl_global_lock_present) { |
449 | acpi_gbl_global_lock_acquired = TRUE; | ||
428 | return_ACPI_STATUS(AE_OK); | 450 | return_ACPI_STATUS(AE_OK); |
429 | } | 451 | } |
430 | 452 | ||
431 | /* We must acquire the actual hardware lock */ | 453 | /* Attempt to acquire the actual hardware lock */ |
432 | 454 | ||
433 | ACPI_ACQUIRE_GLOBAL_LOCK(acpi_gbl_common_fACS.global_lock, acquired); | 455 | ACPI_ACQUIRE_GLOBAL_LOCK(facs, acquired); |
434 | if (acquired) { | 456 | if (acquired) { |
435 | 457 | ||
436 | /* We got the lock */ | 458 | /* We got the lock */ |
437 | 459 | ||
438 | ACPI_DEBUG_PRINT((ACPI_DB_EXEC, | 460 | ACPI_DEBUG_PRINT((ACPI_DB_EXEC, |
439 | "Acquired the HW Global Lock\n")); | 461 | "Acquired hardware Global Lock\n")); |
440 | 462 | ||
441 | acpi_gbl_global_lock_acquired = TRUE; | 463 | acpi_gbl_global_lock_acquired = TRUE; |
442 | return_ACPI_STATUS(AE_OK); | 464 | return_ACPI_STATUS(AE_OK); |
443 | } | 465 | } |
444 | 466 | ||
445 | /* | 467 | /* |
446 | * Did not get the lock. The pending bit was set above, and we must now | 468 | * Did not get the lock. The pending bit was set above, and we must now |
447 | * wait until we get the global lock released interrupt. | 469 | * wait until we get the global lock released interrupt. |
448 | */ | 470 | */ |
449 | ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Waiting for the HW Global Lock\n")); | 471 | ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Waiting for hardware Global Lock\n")); |
450 | 472 | ||
451 | /* | 473 | /* |
452 | * Acquire the global lock semaphore first. | 474 | * Wait for handshake with the global lock interrupt handler. |
453 | * Since this wait will block, we must release the interpreter | 475 | * This interface releases the interpreter if we must wait. |
454 | */ | 476 | */ |
455 | status = | 477 | status = acpi_ex_system_wait_semaphore(acpi_gbl_global_lock_semaphore, |
456 | acpi_ex_system_wait_semaphore(acpi_gbl_global_lock_semaphore, | 478 | ACPI_WAIT_FOREVER); |
457 | timeout); | 479 | |
458 | return_ACPI_STATUS(status); | 480 | return_ACPI_STATUS(status); |
459 | } | 481 | } |
460 | 482 | ||
@@ -477,38 +499,39 @@ acpi_status acpi_ev_release_global_lock(void) | |||
477 | 499 | ||
478 | ACPI_FUNCTION_TRACE(ev_release_global_lock); | 500 | ACPI_FUNCTION_TRACE(ev_release_global_lock); |
479 | 501 | ||
480 | if (!acpi_gbl_global_lock_thread_count) { | 502 | /* Lock must be already acquired */ |
503 | |||
504 | if (!acpi_gbl_global_lock_acquired) { | ||
481 | ACPI_WARNING((AE_INFO, | 505 | ACPI_WARNING((AE_INFO, |
482 | "Cannot release HW Global Lock, it has not been acquired")); | 506 | "Cannot release the ACPI Global Lock, it has not been acquired")); |
483 | return_ACPI_STATUS(AE_NOT_ACQUIRED); | 507 | return_ACPI_STATUS(AE_NOT_ACQUIRED); |
484 | } | 508 | } |
485 | 509 | ||
486 | /* One fewer thread has the global lock */ | 510 | if (acpi_gbl_global_lock_present) { |
487 | 511 | ||
488 | acpi_gbl_global_lock_thread_count--; | 512 | /* Allow any thread to release the lock */ |
489 | if (acpi_gbl_global_lock_thread_count) { | ||
490 | 513 | ||
491 | /* There are still some threads holding the lock, cannot release */ | 514 | ACPI_RELEASE_GLOBAL_LOCK(facs, pending); |
492 | 515 | ||
493 | return_ACPI_STATUS(AE_OK); | 516 | /* |
517 | * If the pending bit was set, we must write GBL_RLS to the control | ||
518 | * register | ||
519 | */ | ||
520 | if (pending) { | ||
521 | status = | ||
522 | acpi_set_register(ACPI_BITREG_GLOBAL_LOCK_RELEASE, | ||
523 | 1); | ||
524 | } | ||
525 | |||
526 | ACPI_DEBUG_PRINT((ACPI_DB_EXEC, | ||
527 | "Released hardware Global Lock\n")); | ||
494 | } | 528 | } |
495 | 529 | ||
496 | /* | ||
497 | * No more threads holding lock, we can do the actual hardware | ||
498 | * release | ||
499 | */ | ||
500 | ACPI_RELEASE_GLOBAL_LOCK(acpi_gbl_common_fACS.global_lock, pending); | ||
501 | acpi_gbl_global_lock_acquired = FALSE; | 530 | acpi_gbl_global_lock_acquired = FALSE; |
502 | 531 | ||
503 | /* | 532 | /* Release the local GL mutex */ |
504 | * If the pending bit was set, we must write GBL_RLS to the control | ||
505 | * register | ||
506 | */ | ||
507 | if (pending) { | ||
508 | status = acpi_set_register(ACPI_BITREG_GLOBAL_LOCK_RELEASE, | ||
509 | 1, ACPI_MTX_LOCK); | ||
510 | } | ||
511 | 533 | ||
534 | acpi_os_release_mutex(acpi_gbl_global_lock_mutex); | ||
512 | return_ACPI_STATUS(status); | 535 | return_ACPI_STATUS(status); |
513 | } | 536 | } |
514 | 537 | ||
@@ -558,6 +581,12 @@ void acpi_ev_terminate(void) | |||
558 | if (ACPI_FAILURE(status)) { | 581 | if (ACPI_FAILURE(status)) { |
559 | ACPI_ERROR((AE_INFO, "Could not remove SCI handler")); | 582 | ACPI_ERROR((AE_INFO, "Could not remove SCI handler")); |
560 | } | 583 | } |
584 | |||
585 | status = acpi_ev_remove_global_lock_handler(); | ||
586 | if (ACPI_FAILURE(status)) { | ||
587 | ACPI_ERROR((AE_INFO, | ||
588 | "Could not remove Global Lock handler")); | ||
589 | } | ||
561 | } | 590 | } |
562 | 591 | ||
563 | /* Deallocate all handler objects installed within GPE info structs */ | 592 | /* Deallocate all handler objects installed within GPE info structs */ |