Furquan Shaikh (furquan@google.com) just uploaded a new patch set to gerrit, which you can find at https://review.coreboot.org/16258
-gerrit
commit 8127fc8ada122e29544c66b2c5fed3d25f8a7ce6 Author: Furquan Shaikh furquan@google.com Date: Thu Aug 18 21:39:14 2016 -0700
google/chromeec: Ensure data is ready before reading it
Before reading the data provided by EC to the host, ensure that data ready flag is set. Otherwise, it could result in reading stale/incorrect data from the data buffer.
BUG=chrome-os-partner:56395 BRANCH=None TEST=Verified that lidclose event is read correctly by host.
Change-Id: I88e345d64256af8325b3dbf670467d09f09420f0 Signed-off-by: Furquan Shaikh furquan@google.com --- src/ec/google/chromeec/ec_lpc.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-)
diff --git a/src/ec/google/chromeec/ec_lpc.c b/src/ec/google/chromeec/ec_lpc.c index 06b506b..47e0d77 100644 --- a/src/ec/google/chromeec/ec_lpc.c +++ b/src/ec/google/chromeec/ec_lpc.c @@ -96,6 +96,7 @@ static inline u8 write_byte(u8 val, u16 port) return byte; }
+#define MAX_EC_TIMEOUT_US 1000000 static int google_chromeec_wait_ready(u16 port) { u8 ec_status = read_byte(port); @@ -106,7 +107,6 @@ static int google_chromeec_wait_ready(u16 port) * (and the bus accessing/code execution) overhead will make the * timeout even longer. */ -#define MAX_EC_TIMEOUT_US 1000000
while (ec_status & (EC_LPC_CMDR_PENDING | EC_LPC_CMDR_BUSY)) { @@ -481,6 +481,24 @@ struct chip_operations ec_google_chromeec_ops = {
#endif /* __SMM__ */
+static int google_chromeec_data_ready(u16 port) +{ + u8 ec_status = read_byte(port); + u32 time_count = 0; + + /* + * One second is more than plenty for data to be copied into the data + * buffer. + */ + while (!(ec_status & (EC_LPC_CMDR_DATA))) { + udelay(1); + if (time_count++ == MAX_EC_TIMEOUT_US) + return -1; + ec_status = read_byte(port); + } + return 0; +} + u8 google_chromeec_get_event(void) { if (google_chromeec_wait_ready(EC_LPC_ADDR_ACPI_CMD)) { @@ -496,6 +514,11 @@ u8 google_chromeec_get_event(void) return 0; }
+ if (google_chromeec_data_ready(EC_LPC_ADDR_ACPI_CMD)) { + printk(BIOS_ERR, "Timeout waiting for data ready!\n"); + return 0; + } + /* Event (or 0 if none) is returned directly in the data byte */ return read_byte(EC_LPC_ADDR_ACPI_DATA); }