Fix for GPE livelock on HPs

Nate Lawson nate at root.org
Sat Jan 12 14:57:19 PST 2008


I've committed the below patch and want to MFC it to 7.0.  To do this, I
need people to test this quickly.  It probably has no effect in 6.x and
probably doesn't apply cleanly there.

Please try this patch if you have a laptop and 7.x.  If you have
-current, just cvsup.  I'd like to make sure there is no regression.
I'm already aware that it fixes things for some HP users.

Thanks for your time,
Nate

-------- Original Message --------
Subject: cvs commit: src/sys/dev/acpica/Osd OsdSchedule.c
src/sys/contrib/dev/acpica         evgpe.c
Date: Sat, 12 Jan 2008 22:13:18 +0000 (UTC)
From: Nate Lawson <njl at FreeBSD.org>
To: njl at FreeBSD.ORG

njl         2008-01-12 22:13:12 UTC

  FreeBSD src repository

  Modified files:
    sys/dev/acpica/Osd   OsdSchedule.c
  Modified files:        (Branch: INTEL)
    sys/contrib/dev/acpica evgpe.c
  Log:
  Fix GPE livelock that occurs on HP/Compaq laptops, mostly in the thermal
  zone code.  The GPE handler method (i.e. _L00) generates various Notify
  events that need to be run to completion before the GPE is re-enabled.
  In ACPI-CA, we queue an asynch callback at the same priority as a Notify
  so that it will only run after all Notify handlers have completed.  The
  callback re-enables the GPE afterwards.  We also changed the priority of
  Notifies to be the same as GPEs, given the possibility that another GPE
  could arrive before the Notifies have completed and we don't want it to
  get queued ahead of the rest.

  The ACPI-CA change was submitted by Alexey Starikovskiy (SUSE) and will
  appear in a later release.  Special thanks to him for helping track this
  bug down.

  MFC after:      1 week
  Tested by:      jhb, Yousif Hassan <yousif / alumni.jmu.edu>

  Revision  Changes    Path
  1.1.1.13  +19 -3     src/sys/contrib/dev/acpica/evgpe.c
  1.40      +7 -3      src/sys/dev/acpica/Osd/OsdSchedule.c


Index: src/sys/contrib/dev/acpica/evgpe.c
diff -u src/sys/contrib/dev/acpica/evgpe.c:1.1.1.12
src/sys/contrib/dev/acpica/evgpe.c:1.1.1.13
--- src/sys/contrib/dev/acpica/evgpe.c:1.1.1.12	Thu Mar 22 17:23:30 2007
+++ src/sys/contrib/dev/acpica/evgpe.c	Sat Jan 12 22:13:12 2008
@@ -123,6 +123,10 @@

 /* Local prototypes */

+static void
+AcpiEvAsynchEnableGpe (
+    void                    *Context);
+
 static void ACPI_SYSTEM_XFACE
 AcpiEvAsynchExecuteGpeMethod (
     void                    *Context);
@@ -684,14 +688,26 @@
         }
     }

-    if ((LocalGpeEventInfo.Flags & ACPI_GPE_XRUPT_TYPE_MASK) ==
+    /* Defer enabling of GPE until all notify handlers are done */
+    AcpiOsExecute(OSL_NOTIFY_HANDLER, AcpiEvAsynchEnableGpe, GpeEventInfo);
+    return_VOID;
+}
+
+static void
+AcpiEvAsynchEnableGpe (
+    void                    *Context)
+{
+    ACPI_GPE_EVENT_INFO     *GpeEventInfo = (void *) Context;
+    ACPI_STATUS             Status;
+
+    if ((GpeEventInfo->Flags & ACPI_GPE_XRUPT_TYPE_MASK) ==
             ACPI_GPE_LEVEL_TRIGGERED)
     {
         /*
          * GPE is level-triggered, we clear the GPE status bit after
          * handling the event.
          */
-        Status = AcpiHwClearGpe (&LocalGpeEventInfo);
+        Status = AcpiHwClearGpe (GpeEventInfo);
         if (ACPI_FAILURE (Status))
         {
             return_VOID;
@@ -700,7 +716,7 @@

     /* Enable this GPE */

-    (void) AcpiHwWriteGpeEnableReg (&LocalGpeEventInfo);
+    (void) AcpiHwWriteGpeEnableReg (GpeEventInfo);
     return_VOID;
 }

Index: src/sys/dev/acpica/Osd/OsdSchedule.c
diff -u src/sys/dev/acpica/Osd/OsdSchedule.c:1.39
src/sys/dev/acpica/Osd/OsdSchedule.c:1.40
--- src/sys/dev/acpica/Osd/OsdSchedule.c:1.39	Thu Mar 22 18:16:41 2007
+++ src/sys/dev/acpica/Osd/OsdSchedule.c	Sat Jan 12 22:13:12 2008
@@ -106,6 +106,13 @@
     at->at_context = Context;
     switch (Type) {
     case OSL_GPE_HANDLER:
+    case OSL_NOTIFY_HANDLER:
+	/*
+	 * Run GPEs and Notifies at the same priority.  This allows
+	 * Notifies that are generated by running a GPE's method (e.g., _L00)
+	 * to not be pre-empted by a later GPE that arrives during the
+	 * Notify handler execution.
+	 */
 	pri = 10;
 	break;
     case OSL_GLOBAL_LOCK_HANDLER:
@@ -113,9 +120,6 @@
     case OSL_EC_BURST_HANDLER:
 	pri = 5;
 	break;
-    case OSL_NOTIFY_HANDLER:
-	pri = 3;
-	break;
     case OSL_DEBUGGER_THREAD:
 	pri = 0;
 	break;


More information about the freebsd-current mailing list