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--