aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2011-01-06 17:32:23 -0500
committerLen Brown <len.brown@intel.com>2011-01-07 01:15:55 -0500
commit9cd031441a4fd09273b7c2beb337d0b2683d104c (patch)
tree4fa85046f3f061cc2f324183ba353ca0252f646f /drivers/acpi
parent3c0eee3fe6a3a1c745379547c7e7c904aa64f6d5 (diff)
ACPI / ACPICA: Fix global lock acquisition
There are two problems with the ACPICA's current implementation of the global lock acquisition. First, acpi_ev_global_lock_handler(), which in fact is an interface to the outside of the kernel, doesn't validate its input, so it only works correctly if the other side (i.e. the ACPI firmware) is fully specification-compliant (as far as the global lock is concerned). Unfortunately, that's known not to be the case on some systems (i.e. we get spurious global lock signaling interrupts without the pending flag set on some systems). Second, acpi_ev_global_lock_handler() attempts to acquire the global lock on behalf of a thread waiting for it without checking if there actually is such a thread. Both of these shortcomings need to be addressed to prevent all possible race conditions from happening. Rework acpi_ev_global_lock_handler() so that it doesn't try to acquire the global lock and make it signal the availability of the global lock to the waiting thread instead. Make sure that the availability of the global lock can only be signaled when there is a thread waiting for it and that it can't be signaled more than once in a row (to keep acpi_gbl_global_lock_semaphore in balance). Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/acpi')
-rw-r--r--drivers/acpi/acpica/evmisc.c94
1 files changed, 55 insertions, 39 deletions
diff --git a/drivers/acpi/acpica/evmisc.c b/drivers/acpi/acpica/evmisc.c
index fcaed9fb44ff..8e31bb5a973a 100644
--- a/drivers/acpi/acpica/evmisc.c
+++ b/drivers/acpi/acpica/evmisc.c
@@ -284,41 +284,41 @@ static void ACPI_SYSTEM_XFACE acpi_ev_notify_dispatch(void *context)
284 * RETURN: ACPI_INTERRUPT_HANDLED 284 * RETURN: ACPI_INTERRUPT_HANDLED
285 * 285 *
286 * DESCRIPTION: Invoked directly from the SCI handler when a global lock 286 * DESCRIPTION: Invoked directly from the SCI handler when a global lock
287 * release interrupt occurs. Attempt to acquire the global lock, 287 * release interrupt occurs. If there's a thread waiting for
288 * if successful, signal the thread waiting for the lock. 288 * the global lock, signal it.
289 * 289 *
290 * NOTE: Assumes that the semaphore can be signaled from interrupt level. If 290 * NOTE: Assumes that the semaphore can be signaled from interrupt level. If
291 * this is not possible for some reason, a separate thread will have to be 291 * this is not possible for some reason, a separate thread will have to be
292 * scheduled to do this. 292 * scheduled to do this.
293 * 293 *
294 ******************************************************************************/ 294 ******************************************************************************/
295static u8 acpi_ev_global_lock_pending;
296static spinlock_t _acpi_ev_global_lock_pending_lock;
297#define acpi_ev_global_lock_pending_lock &_acpi_ev_global_lock_pending_lock
295 298
296static u32 acpi_ev_global_lock_handler(void *context) 299static u32 acpi_ev_global_lock_handler(void *context)
297{ 300{
298 u8 acquired = FALSE; 301 acpi_status status;
302 acpi_cpu_flags flags;
299 303
300 /* 304 flags = acpi_os_acquire_lock(acpi_ev_global_lock_pending_lock);
301 * Attempt to get the lock.
302 *
303 * If we don't get it now, it will be marked pending and we will
304 * take another interrupt when it becomes free.
305 */
306 ACPI_ACQUIRE_GLOBAL_LOCK(acpi_gbl_FACS, acquired);
307 if (acquired) {
308 305
309 /* Got the lock, now wake all threads waiting for it */ 306 if (!acpi_ev_global_lock_pending) {
307 goto out;
308 }
310 309
311 acpi_gbl_global_lock_acquired = TRUE; 310 /* Send a unit to the semaphore */
312 /* Send a unit to the semaphore */
313 311
314 if (ACPI_FAILURE 312 status = acpi_os_signal_semaphore(acpi_gbl_global_lock_semaphore, 1);
315 (acpi_os_signal_semaphore 313 if (ACPI_FAILURE(status)) {
316 (acpi_gbl_global_lock_semaphore, 1))) { 314 ACPI_ERROR((AE_INFO, "Could not signal Global Lock semaphore"));
317 ACPI_ERROR((AE_INFO,
318 "Could not signal Global Lock semaphore"));
319 }
320 } 315 }
321 316
317 acpi_ev_global_lock_pending = FALSE;
318
319 out:
320 acpi_os_release_lock(acpi_ev_global_lock_pending_lock, flags);
321
322 return (ACPI_INTERRUPT_HANDLED); 322 return (ACPI_INTERRUPT_HANDLED);
323} 323}
324 324
@@ -415,6 +415,7 @@ static int acpi_ev_global_lock_acquired;
415 415
416acpi_status acpi_ev_acquire_global_lock(u16 timeout) 416acpi_status acpi_ev_acquire_global_lock(u16 timeout)
417{ 417{
418 acpi_cpu_flags flags;
418 acpi_status status = AE_OK; 419 acpi_status status = AE_OK;
419 u8 acquired = FALSE; 420 u8 acquired = FALSE;
420 421
@@ -467,32 +468,47 @@ acpi_status acpi_ev_acquire_global_lock(u16 timeout)
467 return_ACPI_STATUS(AE_OK); 468 return_ACPI_STATUS(AE_OK);
468 } 469 }
469 470
470 /* Attempt to acquire the actual hardware lock */ 471 flags = acpi_os_acquire_lock(acpi_ev_global_lock_pending_lock);
472
473 do {
474
475 /* Attempt to acquire the actual hardware lock */
476
477 ACPI_ACQUIRE_GLOBAL_LOCK(acpi_gbl_FACS, acquired);
478 if (acquired) {
479 acpi_gbl_global_lock_acquired = TRUE;
480
481 ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
482 "Acquired hardware Global Lock\n"));
483 break;
484 }
471 485
472 ACPI_ACQUIRE_GLOBAL_LOCK(acpi_gbl_FACS, acquired); 486 acpi_ev_global_lock_pending = TRUE;
473 if (acquired) {
474 487
475 /* We got the lock */ 488 acpi_os_release_lock(acpi_ev_global_lock_pending_lock, flags);
476 489
490 /*
491 * Did not get the lock. The pending bit was set above, and we
492 * must wait until we get the global lock released interrupt.
493 */
477 ACPI_DEBUG_PRINT((ACPI_DB_EXEC, 494 ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
478 "Acquired hardware Global Lock\n")); 495 "Waiting for hardware Global Lock\n"));
479 496
480 acpi_gbl_global_lock_acquired = TRUE; 497 /*
481 return_ACPI_STATUS(AE_OK); 498 * Wait for handshake with the global lock interrupt handler.
482 } 499 * This interface releases the interpreter if we must wait.
500 */
501 status = acpi_ex_system_wait_semaphore(
502 acpi_gbl_global_lock_semaphore,
503 ACPI_WAIT_FOREVER);
483 504
484 /* 505 flags = acpi_os_acquire_lock(acpi_ev_global_lock_pending_lock);
485 * Did not get the lock. The pending bit was set above, and we must now
486 * wait until we get the global lock released interrupt.
487 */
488 ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Waiting for hardware Global Lock\n"));
489 506
490 /* 507 } while (ACPI_SUCCESS(status));
491 * Wait for handshake with the global lock interrupt handler. 508
492 * This interface releases the interpreter if we must wait. 509 acpi_ev_global_lock_pending = FALSE;
493 */ 510
494 status = acpi_ex_system_wait_semaphore(acpi_gbl_global_lock_semaphore, 511 acpi_os_release_lock(acpi_ev_global_lock_pending_lock, flags);
495 ACPI_WAIT_FOREVER);
496 512
497 return_ACPI_STATUS(status); 513 return_ACPI_STATUS(status);
498} 514}