Subject: acpi_ec locking
To: None <tech-kern@netbsd.org>
From: YAMAMOTO Takashi <yamt@mwd.biglobe.ne.jp>
List: tech-kern
Date: 11/03/2003 22:41:32
--NextPart-20031103223509-0079100
Content-Type: Text/Plain; charset=us-ascii

hi,

is attached diff correct?  ideas mostly taken from freebsd.
i don't see why AcpiGbl_GpeLock is needed here.

i guess _GLK handling should be in more generic place, though...

YAMAMOTO Takashi

--NextPart-20031103223509-0079100
Content-Type: Text/Plain; charset=us-ascii
Content-Disposition: attachment; filename="acpi_ec.diff"

Index: acpi_ec.c
===================================================================
--- acpi_ec.c	(revision 398)
+++ acpi_ec.c	(working copy)
@@ -207,6 +207,10 @@ struct acpi_ec_softc {
 	int		sc_flags;	/* see below */
 
 	uint32_t	sc_csrvalue;	/* saved control register */
+
+	struct lock	sc_lock;	/* serialize operations to this EC */
+	UINT32		sc_glkhandle;	/* global lock handle */
+	UINT32		sc_glk;		/* need global lock? */
 };
 
 static const char * const ec_hid[] = {
@@ -217,6 +221,12 @@ static const char * const ec_hid[] = {
 #define	EC_F_LOCKED	0x01		/* EC is locked */
 #define	EC_F_PENDQUERY	0x02		/* query is pending */
 
+/*
+ * how long to wait to acquire global lock.
+ * the value is taken from FreeBSD driver.
+ */
+#define	EC_LOCK_TIMEOUT	1000
+
 #define	EC_DATA_READ(sc)						\
 	bus_space_read_1((sc)->sc_data_st, (sc)->sc_data_sh, 0)
 #define	EC_DATA_WRITE(sc, v)						\
@@ -237,17 +247,35 @@ EcIsLocked(struct acpi_ec_softc *sc)
 static __inline void
 EcLock(struct acpi_ec_softc *sc)
 {
+	ACPI_STATUS status;
 
+	lockmgr(&sc->sc_lock, LK_EXCLUSIVE, NULL);
+	if (sc->sc_glk) {
+		status = AcpiAcquireGlobalLock(EC_LOCK_TIMEOUT,
+		    &sc->sc_glkhandle);
+		if (ACPI_FAILURE(status)) {
+			printf("%s: failed to acquire global lock\n",
+			    sc->sc_dev.dv_xname);
+			lockmgr(&sc->sc_lock, LK_RELEASE, NULL);
+			return;
+		}
+	}
 	sc->sc_flags |= EC_F_LOCKED;
-	AcpiOsAcquireLock (AcpiGbl_GpeLock, ACPI_NOT_ISR);
 }
 
 static __inline void
 EcUnlock(struct acpi_ec_softc *sc)
 {
+	ACPI_STATUS status;
 
-	AcpiOsReleaseLock (AcpiGbl_GpeLock, ACPI_NOT_ISR);
 	sc->sc_flags &= ~EC_F_LOCKED;
+	if (sc->sc_glk) {
+		status = AcpiReleaseGlobalLock(sc->sc_glkhandle);
+		if (ACPI_FAILURE(status))
+			printf("%s: failed to release global lock\n",
+			    sc->sc_dev.dv_xname);
+	}
+	lockmgr(&sc->sc_lock, LK_RELEASE, NULL);
 }
 
 typedef struct {
@@ -312,6 +340,8 @@ acpiec_attach(struct device *parent, str
 
 	printf(": ACPI Embedded Controller\n");
 
+	lockinit(&sc->sc_lock, PWAIT, "eclock", 0, 0);
+
 	sc->sc_node = aa->aa_node;
 
 	/* Parse our resources. */
@@ -366,6 +396,17 @@ acpiec_attach(struct device *parent, str
 	}
 
 	/*
+	 * evaluate _GLK to see if we should acquire global lock
+	 * when accessing the EC.
+	 */
+	if ((rv = acpi_eval_integer(sc->sc_node->ad_handle, "_GLK",
+	     &sc->sc_glk)) != AE_OK) {
+		printf("%s: unable to evaluate _GLK: %d\n",
+		    sc->sc_dev.dv_xname, rv);
+		sc->sc_glk = 0;
+	}
+
+	/*
 	 * Install a handler for this EC's GPE bit.  Note that EC SCIs are 
 	 * treated as both edge- and level-triggered interrupts; in other words
 	 * we clear the status bit immediately after getting an EC-SCI, then

--NextPart-20031103223509-0079100--