diff options
author | Shawn Nematbakhsh <shawnn@chromium.org> | 2015-03-23 18:27:22 -0700 |
---|---|---|
committer | ChromeOS Commit Bot <chromeos-commit-bot@chromium.org> | 2015-03-25 20:09:52 +0000 |
commit | 6ee7b1e34eecd585074b4aae0347ed12f632ead0 (patch) | |
tree | ace73f958495a83b836505941318325fa71c71e7 /common | |
parent | 0f18989ef58a77800c1b393cf8223455f793d543 (diff) | |
download | chrome-ec-6ee7b1e34eecd585074b4aae0347ed12f632ead0.tar.gz |
ACPI: Support accessing memmap data over ACPI CMD / DATA portsstabilize-6915.B
Some platforms are unable to access the 900h-9ffh region over LPC and
must instead access memmap data through the ACPI CMD / DATA ports. To
avoid racing with data updates, disallow changes to multi-byte memmap
data while in burst mode.
Linux currently enables burst mode when accessing multi-byte data and
disables it immediately afterward, though the ACPI spec defines burst mode
in a more general way.
BUG=chrome-os-partner:38224
TEST=Manual on Samus. Undefine LPC_MEMMAP and modify asl to move memmap
data to ERAM at offset 0x20. Verify system boots cleanly and battery
status is updated immediately on plug / unplug.
BRANCH=None
Change-Id: Ib848bdb491fdfece96ad0cee7a44ba85b4a1a50b
Signed-off-by: Shawn Nematbakhsh <shawnn@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/262072
Reviewed-by: Randall Spangler <rspangler@chromium.org>
Reviewed-by: Duncan Laurie <dlaurie@chromium.org>
Diffstat (limited to 'common')
-rw-r--r-- | common/acpi.c | 51 | ||||
-rw-r--r-- | common/als.c | 9 | ||||
-rw-r--r-- | common/charge_state_v2.c | 18 | ||||
-rw-r--r-- | common/fan.c | 10 | ||||
-rw-r--r-- | common/host_command.c | 12 |
5 files changed, 90 insertions, 10 deletions
diff --git a/common/acpi.c b/common/acpi.c index 88c0a8351e..425f7e2337 100644 --- a/common/acpi.c +++ b/common/acpi.c @@ -7,9 +7,12 @@ #include "common.h" #include "console.h" #include "dptf.h" +#include "hooks.h" +#include "host_command.h" #include "lpc.h" #include "ec_commands.h" #include "pwm.h" +#include "timer.h" /* Console output macros */ #define CPUTS(outstr) cputs(CC_LPC, outstr) @@ -26,7 +29,20 @@ static int dptf_temp_sensor_id; /* last sensor ID written */ static int dptf_temp_threshold; /* last threshold written */ #endif -/* This handles AP writes to the EC via the ACPI I/O port. There are only a few +/* + * Deferred function to ensure that ACPI burst mode doesn't remain enabled + * indefinitely. + */ +static void acpi_unlock_memmap_deferred(void) +{ + lpc_clear_acpi_status_mask(EC_LPC_STATUS_BURST_MODE); + host_unlock_memmap(); + CPUTS("ACPI force unlock mutex, missed burst disable?"); +} +DECLARE_DEFERRED(acpi_unlock_memmap_deferred); + +/* + * This handles AP writes to the EC via the ACPI I/O port. There are only a few * ACPI commands (EC_CMD_ACPI_*), but they are all handled here. */ int acpi_ap_to_ec(int is_cmd, uint8_t value, uint8_t *resultptr) @@ -87,7 +103,15 @@ int acpi_ap_to_ec(int is_cmd, uint8_t value, uint8_t *resultptr) break; #endif default: - CPRINTS("ACPI read 0x%02x (ignored)", acpi_addr); + if (acpi_addr >= EC_ACPI_MEM_MAPPED_BEGIN && + acpi_addr < + EC_ACPI_MEM_MAPPED_BEGIN + EC_ACPI_MEM_MAPPED_SIZE) + result = *((uint8_t *)(lpc_get_memmap_range() + + acpi_addr - + EC_ACPI_MEM_MAPPED_BEGIN)); + else + CPRINTS("ACPI read 0x%02x (ignored)", + acpi_addr); break; } @@ -149,16 +173,31 @@ int acpi_ap_to_ec(int is_cmd, uint8_t value, uint8_t *resultptr) acpi_addr, data); break; } - -/* At the moment, ACPI implies LPC. */ -#ifdef CONFIG_LPC } else if (acpi_cmd == EC_CMD_ACPI_QUERY_EVENT && !acpi_data_count) { /* Clear and return the lowest host event */ int evt_index = lpc_query_host_event_state(); CPRINTS("ACPI query = %d", evt_index); *resultptr = evt_index; retval = 1; -#endif + } else if (acpi_cmd == EC_CMD_ACPI_BURST_ENABLE && !acpi_data_count) { + /* Enter burst mode */ + host_lock_memmap(); + lpc_set_acpi_status_mask(EC_LPC_STATUS_BURST_MODE); + + /* + * Unlock from deferred function in case burst mode is enabled + * for an extremely long time (ex. kernel bug / crash). + */ + hook_call_deferred(acpi_unlock_memmap_deferred, 1*SECOND); + + /* ACPI 5.0-12.3.3: Burst ACK */ + *resultptr = 0x90; + retval = 1; + } else if (acpi_cmd == EC_CMD_ACPI_BURST_DISABLE && !acpi_data_count) { + /* Leave burst mode */ + hook_call_deferred(acpi_unlock_memmap_deferred, -1); + lpc_clear_acpi_status_mask(EC_LPC_STATUS_BURST_MODE); + host_unlock_memmap(); } return retval; diff --git a/common/als.c b/common/als.c index e67eb03777..0ae06566aa 100644 --- a/common/als.c +++ b/common/als.c @@ -25,10 +25,15 @@ void als_task(void) { int i, val; uint16_t *mapped = (uint16_t *)host_get_memmap(EC_MEMMAP_ALS); + uint16_t als_data; while (1) { - for (i = 0; i < EC_ALS_ENTRIES && i < ALS_COUNT; i++) - mapped[i] = als_read(i, &val) == EC_SUCCESS ? val : 0; + for (i = 0; i < EC_ALS_ENTRIES && i < ALS_COUNT; i++) { + als_data = als_read(i, &val) == EC_SUCCESS ? val : 0; + host_lock_memmap(); + mapped[i] = als_data; + host_unlock_memmap(); + } task_wait_event(SECOND); } diff --git a/common/charge_state_v2.c b/common/charge_state_v2.c index 5eb37e83a0..7b20c52eef 100644 --- a/common/charge_state_v2.c +++ b/common/charge_state_v2.c @@ -112,6 +112,12 @@ static int update_static_battery_info(void) */ int rv; + /* + * We're updating multi-byte memmap vars, don't allow ACPI to do + * reads while we're updating. + */ + host_lock_memmap(); + /* Smart battery serial number is 16 bits */ batt_str = (char *)host_get_memmap(EC_MEMMAP_BATT_SERIAL); memset(batt_str, 0, EC_MEMMAP_TEXT_MAX); @@ -155,6 +161,9 @@ static int update_static_battery_info(void) *(int *)host_get_memmap(EC_MEMMAP_BATT_LFCC) = 0; *host_get_memmap(EC_MEMMAP_BATT_FLAG) = 0; + /* No more multi-byte memmap writes. */ + host_unlock_memmap(); + if (rv) problem(PR_STATIC_UPDATE, 0); else @@ -199,6 +208,12 @@ static void update_dynamic_battery_info(void) batt_present = 0; } + /* + * We're updating multi-byte memmap vars, don't allow ACPI to do + * reads while we're updating. + */ + host_lock_memmap(); + if (!(curr.batt.flags & BATT_FLAG_BAD_VOLTAGE)) *memmap_volt = curr.batt.voltage; @@ -225,6 +240,9 @@ static void update_dynamic_battery_info(void) send_batt_info_event++; } + /* No more multi-byte memmap writes. */ + host_unlock_memmap(); + if (curr.batt.is_present == BP_YES && !(curr.batt.flags & BATT_FLAG_BAD_STATE_OF_CHARGE) && curr.batt.state_of_charge <= BATTERY_LEVEL_CRITICAL) diff --git a/common/fan.c b/common/fan.c index 9196ddf36b..6cb64e777a 100644 --- a/common/fan.c +++ b/common/fan.c @@ -471,17 +471,23 @@ DECLARE_HOOK(HOOK_INIT, pwm_fan_init, HOOK_PRIO_DEFAULT); static void pwm_fan_second(void) { uint16_t *mapped = (uint16_t *)host_get_memmap(EC_MEMMAP_FAN); + uint16_t rpm; int stalled = 0; int fan; for (fan = 0; fan < CONFIG_FANS; fan++) { if (fan_is_stalled(fans[fan].ch)) { - mapped[fan] = EC_FAN_SPEED_STALLED; + rpm = EC_FAN_SPEED_STALLED; stalled = 1; cprints(CC_PWM, "Fan %d stalled!", fan); } else { - mapped[fan] = fan_get_rpm_actual(fans[fan].ch); + rpm = fan_get_rpm_actual(fans[fan].ch); } + + /* Lock ACPI read access to memmap during multi-byte write */ + host_lock_memmap(); + mapped[fan] = rpm; + host_unlock_memmap(); } /* diff --git a/common/host_command.c b/common/host_command.c index 51d1a9cf97..0a6226b59e 100644 --- a/common/host_command.c +++ b/common/host_command.c @@ -81,6 +81,18 @@ uint8_t *host_get_memmap(int offset) #endif } +static struct mutex memmap_write_mutex; + +void host_lock_memmap() +{ + mutex_lock(&memmap_write_mutex); +} + +void host_unlock_memmap() +{ + mutex_unlock(&memmap_write_mutex); +} + int host_get_vboot_mode(void) { return g_vboot_mode; |