Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 19 Jan 2010 20:23:20 +0000
From:      Peter Harrison <peter.piggybox@virgin.net>
To:        acpi@freebsd.org
Subject:   Problem installing patched acpi...
Message-ID:  <20100119202320.GA1311@ideapad.piggybox>

next in thread | raw e-mail | index | archive | help

--fUYQa+Pmc3FrFX/N
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

Hi list,

I'm running FreeBSD on a Lenovo S10e - successfully in the main on 7.2-RELEASE. The biggest issue was with the acpi, where it spams /var/log/messages continually (ie. several times a second):

Jan 19 20:14:32 ideapad kernel: ACPI Error (psparse-0633): Method parse/execution failed [\_TZ_.TZ00._TMP] (Node 0xc46c39a0), AE_NOT_EXIST
Jan 19 20:14:42 ideapad kernel: ACPI Error: No handler for Region [ERAM] (0xc46c5780) [EmbeddedControl] 20090521 evregion-430
Jan 19 20:14:42 ideapad kernel: ACPI Error: Region EmbeddedControl(3) has no handler 20090521 exfldio-382
Jan 19 20:14:42 ideapad kernel: ACPI Error (psparse-0633): Method parse/execution failed [\_TZ_.TZ00._TMP] (Node 0xc46c39a0), AE_NOT_EXIST

David Naylor on this list gave me the attached patch for acpi_ec.c which worked around this on 7.2-R, and which he told me applied OK to the then 8-CURRENT too.

I've now moved to 8.0-RELEASE and the patch still applies cleanly (cd /usr/src/sys/dev/acpica && patch < ~/acpi_ec.c.diff).

I can then rebuild acpi.ko (make clean; make depend; make; make install) successfully.

But it seems not to be included on boot - ie. I don't get the new sysctls and I still get the acpi errors in /var/log/messages.

What's changed in 8? Can anyone offer me some advice on how to resolve this?

Please copy me in as I'm not subscribed, and thanks for your help.


Peter Harrison.


--fUYQa+Pmc3FrFX/N
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="acpi_ec.c.diff.new"

--- acpi_ec.c~	2009-06-17 21:14:48.000000000 +0200
+++ acpi_ec.c	2009-06-19 14:40:02.000000000 +0200
@@ -168,7 +168,7 @@
 #define EC_LOCK_TIMEOUT	1000
 
 /* Default delay in microseconds between each run of the status polling loop. */
-#define EC_POLL_DELAY	5
+#define EC_POLL_DELAY	100
 
 /* Total time in ms spent waiting for a response from EC. */
 #define EC_TIMEOUT	750
@@ -184,13 +184,21 @@
 SYSCTL_DECL(_debug_acpi);
 SYSCTL_NODE(_debug_acpi, OID_AUTO, ec, CTLFLAG_RD, NULL, "EC debugging");
 
-static int	ec_burst_mode;
+static int	ec_burst_mode = FALSE;
 TUNABLE_INT("debug.acpi.ec.burst", &ec_burst_mode);
-SYSCTL_INT(_debug_acpi_ec, OID_AUTO, burst, CTLFLAG_RW, &ec_burst_mode, 0,
+SYSCTL_INT(_debug_acpi_ec, OID_AUTO, burst, CTLFLAG_RW, &ec_burst_mode, FALSE,
     "Enable use of burst mode (faster for nearly all systems)");
-static int	ec_polled_mode;
+static int	ec_delay = 0;
+TUNABLE_INT("debug.acpi.ec.delay", &ec_delay);
+SYSCTL_INT(_debug_acpi_ec, OID_AUTO, delay, CTLFLAG_RW, &ec_delay, 0,
+    "Delay after waiting for responce (GPE and polled mode)");
+static int	ec_gpe_mode = FALSE;
+TUNABLE_INT("debug.acpi.ec.gpe", &ec_gpe_mode);
+SYSCTL_INT(_debug_acpi_ec, OID_AUTO, gpe, CTLFLAG_RW, &ec_gpe_mode, FALSE,
+    "Disable adaptive GPE switching (to polled mode)");
+static int	ec_polled_mode = FALSE;
 TUNABLE_INT("debug.acpi.ec.polled", &ec_polled_mode);
-SYSCTL_INT(_debug_acpi_ec, OID_AUTO, polled, CTLFLAG_RW, &ec_polled_mode, 0,
+SYSCTL_INT(_debug_acpi_ec, OID_AUTO, polled, CTLFLAG_RW, &ec_polled_mode, FALSE,
     "Force use of polled mode (only if interrupt mode doesn't work)");
 static int	ec_timeout = EC_TIMEOUT;
 TUNABLE_INT("debug.acpi.ec.timeout", &ec_timeout);
@@ -794,6 +802,7 @@
     EC_STATUS ec_status;
 
     status = AE_NO_HARDWARE_RESPONSE;
+
     ec_status = EC_GET_CSR(sc);
     if (sc->ec_burstactive && !(ec_status & EC_FLAG_BURST_MODE)) {
 	CTR1(KTR_ACPI, "ec burst disabled in waitevent (%s)", msg);
@@ -810,56 +819,36 @@
 EcWaitEvent(struct acpi_ec_softc *sc, EC_EVENT Event, u_int gen_count)
 {
     ACPI_STATUS	Status;
-    int		count, i, slp_ival;
+    int		count, i, req_ticks, cur_ticks;
 
     ACPI_SERIAL_ASSERT(ec);
     Status = AE_NO_HARDWARE_RESPONSE;
     int need_poll = cold || rebooting || ec_polled_mode || sc->ec_suspending;
-    /*
-     * The main CPU should be much faster than the EC.  So the status should
-     * be "not ready" when we start waiting.  But if the main CPU is really
-     * slow, it's possible we see the current "ready" response.  Since that
-     * can't be distinguished from the previous response in polled mode,
-     * this is a potential issue.  We really should have interrupts enabled
-     * during boot so there is no ambiguity in polled mode.
-     *
-     * If this occurs, we add an additional delay before actually entering
-     * the status checking loop, hopefully to allow the EC to go to work
-     * and produce a non-stale status.
-     */
-    if (need_poll) {
-	static int	once;
-
-	if (EcCheckStatus(sc, "pre-check", Event) == AE_OK) {
-	    if (!once) {
-		device_printf(sc->ec_dev,
-		    "warning: EC done before starting event wait\n");
-		once = 1;
-	    }
-	    AcpiOsStall(10);
-	}
-    }
 
     /* Wait for event by polling or GPE (interrupt). */
     if (need_poll) {
 	count = (ec_timeout * 1000) / EC_POLL_DELAY;
 	if (count == 0)
 	    count = 1;
+
+	/* The EC is slow, give it some time to catch up to us */
+	AcpiOsStall(100);
 	for (i = 0; i < count; i++) {
 	    Status = EcCheckStatus(sc, "poll", Event);
 	    if (Status == AE_OK)
 		break;
 	    AcpiOsStall(EC_POLL_DELAY);
 	}
+
+	if (Status != AE_OK)
+	    device_printf(sc->ec_dev, "wait timed out [polling mode]\n");
     } else {
-	slp_ival = hz / 1000;
-	if (slp_ival != 0) {
-	    count = ec_timeout;
-	} else {
-	    /* hz has less than 1 ms resolution so scale timeout. */
-	    slp_ival = 1;
-	    count = ec_timeout / (1000 / hz);
-	}
+	/* How many ticks should we sleep for (max) */
+	req_ticks = hz < 1000 ? (ec_timeout * hz) / 1000
+	    : (ec_timeout * 1000) / hz;
+	/* Make sure we sleep for at least one tick, from now */
+	cur_ticks = (volatile int)ticks;
+	req_ticks = cur_ticks + (req_ticks ? req_ticks : 1) + 1;
 
 	/*
 	 * Wait for the GPE to signal the status changed, checking the
@@ -867,38 +856,42 @@
 	 * GPE for an event we're not interested in here (i.e., SCI for
 	 * EC query).
 	 */
-	for (i = 0; i < count; i++) {
-	    if (gen_count != sc->ec_gencount) {
-		/*
-		 * Record new generation count.  It's possible the GPE was
-		 * just to notify us that a query is needed and we need to
-		 * wait for a second GPE to signal the completion of the
-		 * event we are actually waiting for.
-		 */
-		gen_count = sc->ec_gencount;
-		Status = EcCheckStatus(sc, "sleep", Event);
-		if (Status == AE_OK)
-		    break;
-	    }
-	    tsleep(&sc->ec_gencount, PZERO, "ecgpe", slp_ival);
+	while ((int)(req_ticks - cur_ticks) > 0) {
+	    /* If we have not received a signal then wait for one */
+	    if (gen_count == sc->ec_gencount)
+		tsleep(&sc->ec_gencount, PZERO, "ecgpe", req_ticks - cur_ticks);
+
+	    /*
+	     * Record new generation count.  It's possible the GPE was
+	     * just to notify us that a query is needed and we need to
+	     * wait for a second GPE to signal the completion of the
+	     * event we are actually waiting for.
+	     */
+	    gen_count = sc->ec_gencount;
+	    Status = EcCheckStatus(sc, "sleep", Event);
+	    if (Status == AE_OK)
+	        break;
+
+	    /* Update current tick (so we always have a consistant value */
+	    cur_ticks = (volatile int)ticks;
 	}
 
 	/*
-	 * We finished waiting for the GPE and it never arrived.  Try to
-	 * read the register once and trust whatever value we got.  This is
-	 * the best we can do at this point.  Then, force polled mode on
-	 * since this system doesn't appear to generate GPEs.
+	 * We finished waiting for the GPE and it never arrived.  The register
+	 * has been read on a timeout so no need to re-read it.  Force polled
+	 * mode on since this system doesn't appear to generate GPEs.
 	 */
 	if (Status != AE_OK) {
-	    Status = EcCheckStatus(sc, "sleep_end", Event);
-	    device_printf(sc->ec_dev,
-		"wait timed out (%sresponse), forcing polled mode\n",
-		Status == AE_OK ? "" : "no ");
-	    ec_polled_mode = TRUE;
+	    device_printf(sc->ec_dev, "wait timed out [GPE mode]%s\n",
+		ec_gpe_mode ? "" : ", forcing polled mode");
+	    ec_polled_mode = TRUE && !ec_gpe_mode;
 	}
     }
     if (Status != AE_OK)
 	    CTR0(KTR_ACPI, "error: ec wait timed out");
+    else if (ec_delay);
+	/* Give the EC a chance to recover from all its hard work!!! */
+	AcpiOsStall(ec_delay);
     return (Status);
 }
 

--fUYQa+Pmc3FrFX/N--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20100119202320.GA1311>