From: Sepherosa Ziehau Date: Sat, 16 Apr 2011 15:12:05 +0000 (+0800) Subject: acpi: Sync ec with FreeBSD 8 X-Git-Tag: v2.11.0~38 X-Git-Url: https://gitweb.dragonflybsd.org/dragonfly.git/commitdiff_plain/c4ab026d5e26738cd221c36248bcdbf55a4089c2 acpi: Sync ec with FreeBSD 8 --- diff --git a/sys/dev/acpica5/acpi_ec.c b/sys/dev/acpica5/acpi_ec.c index 87254b0e36..3f6de81da1 100644 --- a/sys/dev/acpica5/acpi_ec.c +++ b/sys/dev/acpica5/acpi_ec.c @@ -125,9 +125,6 @@ struct acpi_ec_params { int uid; }; -/* Indicate that this device has already been probed via ECDT. */ -#define DEV_ECDT(x) (acpi_get_magic(x) == (uintptr_t)&acpi_ec_devclass) - /* * Driver softc. */ @@ -152,7 +149,7 @@ struct acpi_ec_softc { int ec_glkhandle; int ec_burstactive; int ec_sci_pend; - u_int ec_gencount; + volatile u_int ec_gencount; int ec_suspending; }; @@ -164,7 +161,7 @@ struct acpi_ec_softc { #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 50 /* Total time in ms spent waiting for a response from EC. */ #define EC_TIMEOUT 750 @@ -223,7 +220,7 @@ static ACPI_STATUS EcSpaceSetup(ACPI_HANDLE Region, UINT32 Function, void *Context, void **return_Context); static ACPI_STATUS EcSpaceHandler(UINT32 Function, ACPI_PHYSICAL_ADDRESS Address, - UINT32 width, ACPI_INTEGER *Value, + UINT32 Width, UINT64 *Value, void *Context, void *RegionContext); static ACPI_STATUS EcWaitEvent(struct acpi_ec_softc *sc, EC_EVENT Event, u_int gen_count); @@ -231,16 +228,16 @@ static ACPI_STATUS EcCommand(struct acpi_ec_softc *sc, EC_COMMAND cmd); static ACPI_STATUS EcRead(struct acpi_ec_softc *sc, UINT8 Address, UINT8 *Data); static ACPI_STATUS EcWrite(struct acpi_ec_softc *sc, UINT8 Address, - UINT8 *Data); + UINT8 Data); static int acpi_ec_probe(device_t dev); static int acpi_ec_attach(device_t dev); static int acpi_ec_suspend(device_t dev); static int acpi_ec_resume(device_t dev); static int acpi_ec_shutdown(device_t dev); static int acpi_ec_read_method(device_t dev, u_int addr, - ACPI_INTEGER *val, int width); + UINT64 *val, int width); static int acpi_ec_write_method(device_t dev, u_int addr, - ACPI_INTEGER val, int width); + UINT64 val, int width); static device_method_t acpi_ec_methods[] = { /* Device interface */ @@ -329,7 +326,6 @@ acpi_ec_ecdt_probe(device_t parent) params->uid = ecdt->Uid; acpi_GetInteger(h, "_GLK", ¶ms->glk); acpi_set_private(child, params); - acpi_set_magic(child, (uintptr_t)&acpi_ec_devclass); /* Finish the attach process. */ if (device_probe_and_attach(child) != 0) @@ -345,6 +341,7 @@ acpi_ec_probe(device_t dev) ACPI_STATUS status; device_t peer; char desc[64]; + int ecdt; int ret; struct acpi_ec_params *params; static char *ec_ids[] = { "PNP0C09", NULL }; @@ -359,14 +356,14 @@ acpi_ec_probe(device_t dev) * duplicate probe. */ ret = ENXIO; - params = NULL; + ecdt = 0; buf.Pointer = NULL; buf.Length = ACPI_ALLOCATE_BUFFER; - if (DEV_ECDT(dev)) { - params = acpi_get_private(dev); + params = acpi_get_private(dev); + if (params != NULL) { + ecdt = 1; ret = 0; - } else if (!acpi_disabled("ec") && - ACPI_ID_PROBE(device_get_parent(dev), dev, ec_ids)) { + } else if (ACPI_ID_PROBE(device_get_parent(dev), dev, ec_ids)) { params = kmalloc(sizeof(struct acpi_ec_params), M_TEMP, M_WAITOK | M_ZERO); h = acpi_get_handle(dev); @@ -436,7 +433,7 @@ out: if (ret == 0) { ksnprintf(desc, sizeof(desc), "Embedded Controller: GPE %#x%s%s", params->gpe_bit, (params->glk) ? ", GLK" : "", - DEV_ECDT(dev) ? ", ECDT" : ""); + ecdt ? ", ECDT" : ""); device_set_desc_copy(dev, desc); } @@ -469,6 +466,7 @@ acpi_ec_attach(device_t dev) sc->ec_gpehandle = params->gpe_handle; sc->ec_uid = params->uid; sc->ec_suspending = FALSE; + acpi_set_private(dev, NULL); kfree(params, M_TEMP); /* Attach bus resources for data and command/status ports. */ @@ -517,8 +515,7 @@ acpi_ec_attach(device_t dev) goto error; } - /* Enable runtime GPEs done internally by AcpiEnableGpe() */ - + /* Enable runtime GPEs for the handler */ Status = AcpiEnableGpe(sc->ec_gpehandle, sc->ec_gpebit); if (ACPI_FAILURE(Status)) { device_printf(dev, "AcpiEnableGpe failed: %s\n", @@ -575,7 +572,7 @@ acpi_ec_shutdown(device_t dev) /* Methods to allow other devices (e.g., smbat) to read/write EC space. */ static int -acpi_ec_read_method(device_t dev, u_int addr, ACPI_INTEGER *val, int width) +acpi_ec_read_method(device_t dev, u_int addr, UINT64 *val, int width) { struct acpi_ec_softc *sc; ACPI_STATUS status; @@ -588,7 +585,7 @@ acpi_ec_read_method(device_t dev, u_int addr, ACPI_INTEGER *val, int width) } static int -acpi_ec_write_method(device_t dev, u_int addr, ACPI_INTEGER val, int width) +acpi_ec_write_method(device_t dev, u_int addr, UINT64 val, int width) { struct acpi_ec_softc *sc; ACPI_STATUS status; @@ -600,12 +597,30 @@ acpi_ec_write_method(device_t dev, u_int addr, ACPI_INTEGER val, int width) return (0); } +static ACPI_STATUS +EcCheckStatus(struct acpi_ec_softc *sc, const char *msg, EC_EVENT event) +{ + ACPI_STATUS status; + 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)) { + sc->ec_burstactive = FALSE; + } + if (EVENT_READY(event, ec_status)) { + status = AE_OK; + } + return (status); +} + static void EcGpeQueryHandler(void *Context) { struct acpi_ec_softc *sc = (struct acpi_ec_softc *)Context; UINT8 Data; ACPI_STATUS Status; + int retry; char qxx[5]; ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); @@ -626,7 +641,16 @@ EcGpeQueryHandler(void *Context) * that may arise from running the query from causing another query * to be queued, we clear the pending flag only after running it. */ - Status = EcCommand(sc, EC_COMMAND_QUERY); + for (retry = 0; retry < 2; retry++) { + Status = EcCommand(sc, EC_COMMAND_QUERY); + if (ACPI_SUCCESS(Status)) + break; + if (EcCheckStatus(sc, "retr_check", + EC_EVENT_INPUT_BUFFER_EMPTY) == AE_OK) + continue; + else + break; + } sc->ec_sci_pend = FALSE; if (ACPI_FAILURE(Status)) { EcUnlock(sc); @@ -644,9 +668,6 @@ EcGpeQueryHandler(void *Context) EcUnlock(sc); /* Ignore the value for "no outstanding event". (13.3.5) */ -#if 0 - CTR2(KTR_ACPI, "ec query ok,%s running _Q%02X", Data ? "" : " not", Data); -#endif if (Data == 0) return; @@ -658,15 +679,6 @@ EcGpeQueryHandler(void *Context) device_printf(sc->ec_dev, "evaluation of query method %s failed: %s\n", qxx, AcpiFormatException(Status)); } - - /* Reenable runtime GPE if its execution was deferred. */ - if (sc->ec_sci_pend) { - Status = AcpiFinishGpe(sc->ec_gpehandle, sc->ec_gpebit); - if (ACPI_FAILURE(Status)) { - device_printf(sc->ec_dev, "reenabling runtime GPE failed: %s\n", - AcpiFormatException(Status)); - } - } } /* @@ -681,9 +693,6 @@ EcGpeHandler(ACPI_HANDLE GpeDevice, UINT32 GpeNumber, void *Context) EC_STATUS EcStatus; KASSERT(Context != NULL, ("EcGpeHandler called with NULL")); -#if 0 - CTR0(KTR_ACPI, "ec gpe handler start"); -#endif /* * Notify EcWaitEvent() that the status register is now fresh. If we * didn't do this, it wouldn't be possible to distinguish an old IBE @@ -691,7 +700,7 @@ EcGpeHandler(ACPI_HANDLE GpeDevice, UINT32 GpeNumber, void *Context) * address and then data values.) */ atomic_add_int(&sc->ec_gencount, 1); - wakeup(&sc->ec_gencount); + wakeup(sc); /* * If the EC_SCI bit of the status register is set, queue a query handler. @@ -699,9 +708,6 @@ EcGpeHandler(ACPI_HANDLE GpeDevice, UINT32 GpeNumber, void *Context) */ EcStatus = EC_GET_CSR(sc); if ((EcStatus & EC_EVENT_SCI) && !sc->ec_sci_pend) { -#if 0 - CTR0(KTR_ACPI, "ec gpe queueing query handler"); -#endif Status = AcpiOsExecute(OSL_GPE_HANDLER, EcGpeQueryHandler, Context); if (ACPI_SUCCESS(Status)) sc->ec_sci_pend = TRUE; @@ -731,138 +737,98 @@ EcSpaceSetup(ACPI_HANDLE Region, UINT32 Function, void *Context, } static ACPI_STATUS -EcSpaceHandler(UINT32 Function, ACPI_PHYSICAL_ADDRESS Address, UINT32 width, - ACPI_INTEGER *Value, void *Context, void *RegionContext) +EcSpaceHandler(UINT32 Function, ACPI_PHYSICAL_ADDRESS Address, UINT32 Width, + UINT64 *Value, void *Context, void *RegionContext) { struct acpi_ec_softc *sc = (struct acpi_ec_softc *)Context; + ACPI_PHYSICAL_ADDRESS EcAddr; + UINT8 *EcData; ACPI_STATUS Status; - UINT8 EcAddr, EcData; - int i; ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, (UINT32)Address); - if (width % 8 != 0 || Value == NULL || Context == NULL) + if (Function != ACPI_READ && Function != ACPI_WRITE) return_ACPI_STATUS (AE_BAD_PARAMETER); - if (Address + (width / 8) - 1 > 0xFF) + if (Width % 8 != 0 || Value == NULL || Context == NULL) + return_ACPI_STATUS (AE_BAD_PARAMETER); + if (Address + Width / 8 > 256) return_ACPI_STATUS (AE_BAD_ADDRESS); - if (Function == ACPI_READ) - *Value = 0; - EcAddr = Address; - Status = AE_ERROR; - /* * If booting, check if we need to run the query handler. If so, we * we call it directly here since our thread taskq is not active yet. */ - if (cold || rebooting) { + if (cold || rebooting || sc->ec_suspending) { if ((EC_GET_CSR(sc) & EC_EVENT_SCI)) { -#if 0 - CTR0(KTR_ACPI, "ec running gpe handler directly"); -#endif EcGpeQueryHandler(sc); } } /* Serialize with EcGpeQueryHandler() at transaction granularity. */ Status = EcLock(sc); - if (ACPI_FAILURE(Status)) { + if (ACPI_FAILURE(Status)) return_ACPI_STATUS (Status); + + /* If we can't start burst mode, continue anyway. */ + Status = EcCommand(sc, EC_COMMAND_BURST_ENABLE); + if (ACPI_SUCCESS(Status)) { + if (EC_GET_DATA(sc) == EC_BURST_ACK) { + sc->ec_burstactive = TRUE; + } } - /* Perform the transaction(s), based on width. */ - for (i = 0; i < width; i += 8, EcAddr++) { + /* Perform the transaction(s), based on Width. */ + EcAddr = Address; + EcData = (UINT8 *)Value; + if (Function == ACPI_READ) + *Value = 0; + do { switch (Function) { case ACPI_READ: - Status = EcRead(sc, EcAddr, &EcData); - if (ACPI_SUCCESS(Status)) - *Value |= ((ACPI_INTEGER)EcData) << i; + Status = EcRead(sc, EcAddr, EcData); break; case ACPI_WRITE: - EcData = (UINT8)((*Value) >> i); - Status = EcWrite(sc, EcAddr, &EcData); - break; - default: - device_printf(sc->ec_dev, "invalid EcSpaceHandler function %d\n", - Function); - Status = AE_BAD_PARAMETER; + Status = EcWrite(sc, EcAddr, *EcData); break; } if (ACPI_FAILURE(Status)) break; + EcAddr++; + EcData++; + } while (EcAddr < Address + Width / 8); + + if (sc->ec_burstactive) { + sc->ec_burstactive = FALSE; + if (ACPI_SUCCESS(EcCommand(sc, EC_COMMAND_BURST_DISABLE))) { + } } EcUnlock(sc); return_ACPI_STATUS (Status); } -static ACPI_STATUS -EcCheckStatus(struct acpi_ec_softc *sc, const char *msg, EC_EVENT event) -{ - ACPI_STATUS status; - 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)) { -#if 0 - CTR1(KTR_ACPI, "ec burst disabled in waitevent (%s)", msg); -#endif - sc->ec_burstactive = FALSE; - } - if (EVENT_READY(event, ec_status)) { -#if 0 - CTR2(KTR_ACPI, "ec %s wait ready, status %#x", msg, ec_status); -#endif - status = AE_OK; - } - return (status); -} - static ACPI_STATUS EcWaitEvent(struct acpi_ec_softc *sc, EC_EVENT Event, u_int gen_count) { + static int no_intr = 0; ACPI_STATUS Status; - int count, i, slp_ival; + int count, i, need_poll, slp_ival; 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); - } - } + need_poll = cold || rebooting || ec_polled_mode || sc->ec_suspending; /* Wait for event by polling or GPE (interrupt). */ if (need_poll) { count = (ec_timeout * 1000) / EC_POLL_DELAY; if (count == 0) count = 1; + DELAY(10); for (i = 0; i < count; i++) { Status = EcCheckStatus(sc, "poll", Event); if (Status == AE_OK) break; - AcpiOsStall(EC_POLL_DELAY); + DELAY(EC_POLL_DELAY); } } else { slp_ival = hz / 1000; @@ -881,39 +847,38 @@ EcWaitEvent(struct acpi_ec_softc *sc, EC_EVENT Event, u_int gen_count) * 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; + if (gen_count == sc->ec_gencount) + tsleep(sc, 0, "ecgpe", slp_ival); + /* + * 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. + */ + Status = EcCheckStatus(sc, "sleep", Event); + if (Status == AE_OK) { + if (gen_count == sc->ec_gencount) + no_intr++; + else + no_intr = 0; + break; } - tsleep(&sc->ec_gencount, PZERO, "ecgpe", slp_ival); + gen_count = sc->ec_gencount; } /* * 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. + * the best we can do at this point. */ - if (Status != AE_OK) { + 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; - } } -#if 0 - if (Status != AE_OK) - CTR0(KTR_ACPI, "error: ec wait timed out"); -#endif + if (!need_poll && no_intr > 10) { + device_printf(sc->ec_dev, + "not getting interrupts, switched to polled mode\n"); + ec_polled_mode = 1; + } return (Status); } @@ -947,10 +912,15 @@ EcCommand(struct acpi_ec_softc *sc, EC_COMMAND cmd) return (AE_BAD_PARAMETER); } + /* + * Ensure empty input buffer before issuing command. + * Use generation count of zero to force a quick check. + */ + status = EcWaitEvent(sc, EC_EVENT_INPUT_BUFFER_EMPTY, 0); + if (ACPI_FAILURE(status)) + return (status); + /* Run the command and wait for the chosen event. */ -#if 0 - CTR1(KTR_ACPI, "ec running command %#x", cmd); -#endif gen_count = sc->ec_gencount; EC_SET_CSR(sc, cmd); status = EcWaitEvent(sc, event, gen_count); @@ -970,74 +940,40 @@ static ACPI_STATUS EcRead(struct acpi_ec_softc *sc, UINT8 Address, UINT8 *Data) { ACPI_STATUS status; - UINT8 data; u_int gen_count; + int retry; ACPI_SERIAL_ASSERT(ec); -#if 0 - CTR1(KTR_ACPI, "ec read from %#x", Address); -#endif - /* If we can't start burst mode, continue anyway. */ - status = EcCommand(sc, EC_COMMAND_BURST_ENABLE); - if (status == AE_OK) { - data = EC_GET_DATA(sc); - if (data == EC_BURST_ACK) { -#if 0 - CTR0(KTR_ACPI, "ec burst enabled"); -#endif - sc->ec_burstactive = TRUE; - } - } - - status = EcCommand(sc, EC_COMMAND_READ); - if (ACPI_FAILURE(status)) - return (status); - - gen_count = sc->ec_gencount; - EC_SET_DATA(sc, Address); - status = EcWaitEvent(sc, EC_EVENT_OUTPUT_BUFFER_FULL, gen_count); - if (ACPI_FAILURE(status)) { - device_printf(sc->ec_dev, "EcRead: failed waiting to get data\n"); - return (status); - } - *Data = EC_GET_DATA(sc); - if (sc->ec_burstactive) { - sc->ec_burstactive = FALSE; - status = EcCommand(sc, EC_COMMAND_BURST_DISABLE); + for (retry = 0; retry < 2; retry++) { + status = EcCommand(sc, EC_COMMAND_READ); if (ACPI_FAILURE(status)) return (status); -#if 0 - CTR0(KTR_ACPI, "ec disabled burst ok"); -#endif - } - return (AE_OK); + gen_count = sc->ec_gencount; + EC_SET_DATA(sc, Address); + status = EcWaitEvent(sc, EC_EVENT_OUTPUT_BUFFER_FULL, gen_count); + if (ACPI_FAILURE(status)) { + if (EcCheckStatus(sc, "retr_check", + EC_EVENT_INPUT_BUFFER_EMPTY) == AE_OK) + continue; + else + break; + } + *Data = EC_GET_DATA(sc); + return (AE_OK); + } + device_printf(sc->ec_dev, "EcRead: failed waiting to get data\n"); + return (status); } static ACPI_STATUS -EcWrite(struct acpi_ec_softc *sc, UINT8 Address, UINT8 *Data) +EcWrite(struct acpi_ec_softc *sc, UINT8 Address, UINT8 Data) { ACPI_STATUS status; - UINT8 data; u_int gen_count; ACPI_SERIAL_ASSERT(ec); -#if 0 - CTR2(KTR_ACPI, "ec write to %#x, data %#x", Address, *Data); -#endif - - /* If we can't start burst mode, continue anyway. */ - status = EcCommand(sc, EC_COMMAND_BURST_ENABLE); - if (status == AE_OK) { - data = EC_GET_DATA(sc); - if (data == EC_BURST_ACK) { -#if 0 - CTR0(KTR_ACPI, "ec burst enabled"); -#endif - sc->ec_burstactive = TRUE; - } - } status = EcCommand(sc, EC_COMMAND_WRITE); if (ACPI_FAILURE(status)) @@ -1047,27 +983,17 @@ EcWrite(struct acpi_ec_softc *sc, UINT8 Address, UINT8 *Data) EC_SET_DATA(sc, Address); status = EcWaitEvent(sc, EC_EVENT_INPUT_BUFFER_EMPTY, gen_count); if (ACPI_FAILURE(status)) { - device_printf(sc->ec_dev, "EcRead: failed waiting for sent address\n"); + device_printf(sc->ec_dev, "EcWrite: failed waiting for sent address\n"); return (status); } gen_count = sc->ec_gencount; - EC_SET_DATA(sc, *Data); + EC_SET_DATA(sc, Data); status = EcWaitEvent(sc, EC_EVENT_INPUT_BUFFER_EMPTY, gen_count); if (ACPI_FAILURE(status)) { device_printf(sc->ec_dev, "EcWrite: failed waiting for sent data\n"); return (status); } - if (sc->ec_burstactive) { - sc->ec_burstactive = FALSE; - status = EcCommand(sc, EC_COMMAND_BURST_DISABLE); - if (ACPI_FAILURE(status)) - return (status); -#if 0 - CTR0(KTR_ACPI, "ec disabled burst ok"); -#endif - } - return (AE_OK); }