As part of a revamp of the PM1/GPE code, I write this diff to look for
authorderaadt <deraadt@openbsd.org>
Fri, 6 Aug 2010 14:20:14 +0000 (14:20 +0000)
committerderaadt <deraadt@openbsd.org>
Fri, 6 Aug 2010 14:20:14 +0000 (14:20 +0000)
unmanaged EN & STS bits in the PM1 register at interrupt time and report
them.  As a side effect this splits the STS acknowledgement into two writes
(for power, and sleep) instead of one. The printf that is added (to spot
unmanaged STS bits) has not yet been triggered as far as we know.

Before the "write to PM1 registers at the right offset" diff went in, this
was not neccessary.  But newer thinkpads do not have a working soft power
button without this diff.

We have no idea why.
ok mlarkin kettenis

sys/dev/acpi/acpi.c

index b460ffd..273a35c 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: acpi.c,v 1.203 2010/08/05 17:26:57 deraadt Exp $ */
+/* $OpenBSD: acpi.c,v 1.204 2010/08/06 14:20:14 deraadt Exp $ */
 /*
  * Copyright (c) 2005 Thorsten Lockert <tholo@sigmasoft.com>
  * Copyright (c) 2005 Jordan Hargrave <jordan@openbsd.org>
@@ -1354,17 +1354,31 @@ acpi_interrupt(void *arg)
        en  = acpi_read_pmreg(sc, ACPIREG_PM1_EN, 0);
        if (sts & en) {
                dnprintf(10,"GEN interrupt: %.4x\n", sts & en);
-               acpi_write_pmreg(sc, ACPIREG_PM1_EN, 0, en & ~sts);
+               sts &= en;
                if (sts & ACPI_PM1_PWRBTN_STS) {
+                       /* Mask and acknowledge */
+                       en &= ~ACPI_PM1_PWRBTN_EN;
+                       acpi_write_pmreg(sc, ACPIREG_PM1_EN, 0, en);
                        acpi_write_pmreg(sc, ACPIREG_PM1_STS, 0,
                            ACPI_PM1_PWRBTN_STS);
+                       sts &= ~ACPI_PM1_PWRBTN_STS;
                        sc->sc_powerbtn = 1;
                }
                if (sts & ACPI_PM1_SLPBTN_STS) {
+                       /* Mask and acknowledge */
+                       en &= ~ACPI_PM1_SLPBTN_EN;
+                       acpi_write_pmreg(sc, ACPIREG_PM1_EN, 0, en);
                        acpi_write_pmreg(sc, ACPIREG_PM1_STS, 0,
                            ACPI_PM1_SLPBTN_STS);
+                       sts &= ~ACPI_PM1_SLPBTN_STS;
                        sc->sc_sleepbtn = 1;
                }
+               if (sts) {
+                       printf("%s: PM1 stuck (en 0x%x st 0x%x), clearing\n",
+                           sc->sc_dev.dv_xname, en, sts);
+                       acpi_write_pmreg(sc, ACPIREG_PM1_EN, 0, en & ~sts);
+                       acpi_write_pmreg(sc, ACPIREG_PM1_STS, 0, sts);
+               }
                processed = 1;
        }