RE: [PATCH] ACPI / ACPICA: Fix global lock acquisition

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Rafael,

We are integrating this change into ACPICA. So far, looks good, I like the solution. I will send you the integrated functions when I'm finished, for your review. As always, it is a little tricky because of various Linux<->ACPICA divergences.

Bob


>-----Original Message-----
>From: Rafael J. Wysocki [mailto:rjw@xxxxxxx]
>Sent: Tuesday, December 28, 2010 2:06 AM
>To: ACPI Devel Maling List
>Cc: Len Brown; Lin, Ming M; Moore, Robert; Thomas Renninger
>Subject: [PATCH] ACPI / ACPICA: Fix global lock acquisition
>
>From: Rafael J. Wysocki <rjw@xxxxxxx>
>
>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@xxxxxxx>
>---
> drivers/acpi/acpica/evmisc.c |   94 +++++++++++++++++++++++++-------------
>-----
> 1 file changed, 55 insertions(+), 39 deletions(-)
>
>Index: linux-2.6/drivers/acpi/acpica/evmisc.c
>===================================================================
>--- linux-2.6.orig/drivers/acpi/acpica/evmisc.c
>+++ linux-2.6/drivers/acpi/acpica/evmisc.c
>@@ -284,41 +284,41 @@ static void ACPI_SYSTEM_XFACE acpi_ev_no
>  * RETURN:      ACPI_INTERRUPT_HANDLED
>  *
>  * DESCRIPTION: Invoked directly from the SCI handler when a global lock
>- *              release interrupt occurs. Attempt to acquire the global
>lock,
>- *              if successful, signal the thread waiting for the lock.
>+ *              release interrupt occurs.  If there's a thread waiting for
>+ *              the global lock, signal it.
>  *
>  * NOTE: Assumes that the semaphore can be signaled from interrupt level.
>If
>  * this is not possible for some reason, a separate thread will have to be
>  * scheduled to do this.
>  *
>
>***************************************************************************
>***/
>+static u8 acpi_ev_global_lock_pending;
>+static spinlock_t _acpi_ev_global_lock_pending_lock;
>+#define acpi_ev_global_lock_pending_lock
>&_acpi_ev_global_lock_pending_lock
>
> static u32 acpi_ev_global_lock_handler(void *context)
> {
>-	u8 acquired = FALSE;
>+	acpi_status status;
>+	acpi_cpu_flags flags;
>
>-	/*
>-	 * Attempt to get the lock.
>-	 *
>-	 * If we don't get it now, it will be marked pending and we will
>-	 * take another interrupt when it becomes free.
>-	 */
>-	ACPI_ACQUIRE_GLOBAL_LOCK(acpi_gbl_FACS, acquired);
>-	if (acquired) {
>+	flags = acpi_os_acquire_lock(acpi_ev_global_lock_pending_lock);
>
>-		/* Got the lock, now wake all threads waiting for it */
>+	if (!acpi_ev_global_lock_pending) {
>+		goto out;
>+	}
>
>-		acpi_gbl_global_lock_acquired = TRUE;
>-		/* Send a unit to the semaphore */
>+	/* Send a unit to the semaphore */
>
>-		if (ACPI_FAILURE
>-		    (acpi_os_signal_semaphore
>-		     (acpi_gbl_global_lock_semaphore, 1))) {
>-			ACPI_ERROR((AE_INFO,
>-				    "Could not signal Global Lock semaphore"));
>-		}
>+	status = acpi_os_signal_semaphore(acpi_gbl_global_lock_semaphore, 1);
>+	if (ACPI_FAILURE(status)) {
>+		ACPI_ERROR((AE_INFO, "Could not signal Global Lock
>semaphore"));
> 	}
>
>+	acpi_ev_global_lock_pending = FALSE;
>+
>+ out:
>+	acpi_os_release_lock(acpi_ev_global_lock_pending_lock, flags);
>+
> 	return (ACPI_INTERRUPT_HANDLED);
> }
>
>@@ -415,6 +415,7 @@ static int acpi_ev_global_lock_acquired;
>
> acpi_status acpi_ev_acquire_global_lock(u16 timeout)
> {
>+	acpi_cpu_flags flags;
> 	acpi_status status = AE_OK;
> 	u8 acquired = FALSE;
>
>@@ -467,32 +468,47 @@ acpi_status acpi_ev_acquire_global_lock(
> 		return_ACPI_STATUS(AE_OK);
> 	}
>
>-	/* Attempt to acquire the actual hardware lock */
>+	flags = acpi_os_acquire_lock(acpi_ev_global_lock_pending_lock);
>+
>+	do {
>+
>+		/* Attempt to acquire the actual hardware lock */
>
>-	ACPI_ACQUIRE_GLOBAL_LOCK(acpi_gbl_FACS, acquired);
>-	if (acquired) {
>+		ACPI_ACQUIRE_GLOBAL_LOCK(acpi_gbl_FACS, acquired);
>+		if (acquired) {
>+			acpi_gbl_global_lock_acquired = TRUE;
>
>-		/* We got the lock */
>+			ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
>+					  "Acquired hardware Global Lock\n"));
>+			break;
>+		}
>+
>+		acpi_ev_global_lock_pending = TRUE;
>+
>+		acpi_os_release_lock(acpi_ev_global_lock_pending_lock, flags);
>
>+		/*
>+		 * Did not get the lock. The pending bit was set above, and we
>+		 * must wait until we get the global lock released interrupt.
>+		 */
> 		ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
>-				  "Acquired hardware Global Lock\n"));
>+				  "Waiting for hardware Global Lock\n"));
>
>-		acpi_gbl_global_lock_acquired = TRUE;
>-		return_ACPI_STATUS(AE_OK);
>-	}
>+		/*
>+		 * Wait for handshake with the global lock interrupt handler.
>+		 * This interface releases the interpreter if we must wait.
>+		 */
>+		status = acpi_ex_system_wait_semaphore(
>+						acpi_gbl_global_lock_semaphore,
>+						ACPI_WAIT_FOREVER);
>
>-	/*
>-	 * Did not get the lock. The pending bit was set above, and we must
>now
>-	 * wait until we get the global lock released interrupt.
>-	 */
>-	ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Waiting for hardware Global
>Lock\n"));
>+		flags = acpi_os_acquire_lock(acpi_ev_global_lock_pending_lock);
>
>-	/*
>-	 * Wait for handshake with the global lock interrupt handler.
>-	 * This interface releases the interpreter if we must wait.
>-	 */
>-	status =
>acpi_ex_system_wait_semaphore(acpi_gbl_global_lock_semaphore,
>-					       ACPI_WAIT_FOREVER);
>+	} while (ACPI_SUCCESS(status));
>+
>+	acpi_ev_global_lock_pending = FALSE;
>+
>+	acpi_os_release_lock(acpi_ev_global_lock_pending_lock, flags);
>
> 	return_ACPI_STATUS(status);
> }
--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux IBM ACPI]     [Linux Power Management]     [Linux Kernel]     [Linux Laptop]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Samba]     [Video 4 Linux]     [Device Mapper]     [Linux Resources]

  Powered by Linux