As can be seen from PR 6508, the current implementation of the
acpibat(4) notify stuff causes infinite recursion.  The AML for that
particular machine will execute a Notify(\_SC.BAT, 0x81) from the
_BST() method.  Since we always execute both _BST() and _BIF() from
the \_SC.BAT notify handler it's easy to see that things go wrong.
The fix is to only call _BST() if the notify value is 0x80 (or 0x00
for the "poll" case) and only call _BIF() if the notify value is 0x81.

This diff also simplifies the battery presence detect logic, which was
unecessaryly complex.

ok?


Index: acpibat.c
===================================================================
RCS file: /cvs/src/sys/dev/acpi/acpibat.c,v
retrieving revision 1.57
diff -u -p -r1.57 acpibat.c
--- acpibat.c   7 Aug 2010 16:55:38 -0000       1.57
+++ acpibat.c   7 Nov 2010 21:04:36 -0000
@@ -186,13 +186,6 @@ acpibat_refresh(void *arg)
                return;
        }
 
-       /*
-        * XXX don't really need _BIF but keep it here in case we
-        * miss an insertion/removal event
-        */
-       acpibat_getbif(sc);
-       acpibat_getbst(sc);
-
        /* _BIF values are static, sensor 0..3 */
        if (sc->sc_bif.bif_last_capacity == BIF_UNKNOWN) {
                sc->sc_sens[0].value = 0;
@@ -386,7 +379,8 @@ out:
        return (rv);
 }
 
-/* XXX it has been observed that some systems do not propagate battery
+/*
+ * XXX it has been observed that some systems do not propagate battery
  * insertion events up to the driver.  What seems to happen is that DSDT
  * does receive an interrupt however the originator bit is not set.
  * This seems to happen when one inserts a 100% full battery.  Removal
@@ -400,23 +394,25 @@ acpibat_notify(struct aml_node *node, in
 {
        struct acpibat_softc    *sc = arg;
        int64_t                 sta;
-       int                     present;
 
        dnprintf(10, "acpibat_notify: %.2x %s\n", notify_type,
            sc->sc_devnode->name);
 
        /* Check if installed state of battery has changed */
        if (aml_evalinteger(sc->sc_acpi, node, "_STA", 0, NULL, &sta) == 0) {
-               present = sta & STA_BATTERY;
-               if (!sc->sc_bat_present && present)
+               if (sta & STA_BATTERY)
                        sc->sc_bat_present = 1;
-               else if (sc->sc_bat_present && !present)
+               else
                        sc->sc_bat_present = 0;
        }
+
        switch (notify_type) {
+       case 0x00:      /* Poll sensors */
        case 0x80:      /* _BST changed */
+               acpibat_getbst(sc);
                break;
        case 0x81:      /* _BIF changed */
+               acpibat_getbif(sc);
                break;
        default:
                break;

Reply via email to