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

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

 



On Friday, January 07, 2011, Moore, Robert wrote:
> 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.

OK, thanks a lot!

> As always, it is a little tricky because of various Linux<->ACPICA divergences.

Understood.

Rafael

 
> >-----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