From 16fb9b9f81d0535a2125779e955ada77b40340e1 Mon Sep 17 00:00:00 2001 From: Shawn Nematbakhsh Date: Tue, 21 Apr 2015 09:30:10 -0700 Subject: chromeec: ec_mec: Fix misaligned data access Long auto-increment access cannot be used when our initial address is misaligned or when our terminal address is misaligned on write operations. BUG=chrome-os-partner:38224 TEST=Verify host command functionality on cyan. BRANCH=None Change-Id: Ieba0e8e05dabd44a28c63d5d56a2a634c2d349bf Signed-off-by: Patrick Georgi Original-Commit-Id: a7237c8df027ae70a38478846ff3d5ce97543ff1 Original-Signed-off-by: Shawn Nematbakhsh Original-Change-Id: Id709ca92cc386f9ea5b2a1139733961e1bc59354 Original-Reviewed-on: https://chromium-review.googlesource.com/266653 Original-Reviewed-by: Duncan Laurie Reviewed-on: http://review.coreboot.org/9987 Reviewed-by: Paul Menzel Tested-by: build bot (Jenkins) Reviewed-by: Stefan Reinauer --- src/ec/google/chromeec/ec_mec.c | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/src/ec/google/chromeec/ec_mec.c b/src/ec/google/chromeec/ec_mec.c index 9836edad67..264a256036 100644 --- a/src/ec/google/chromeec/ec_mec.c +++ b/src/ec/google/chromeec/ec_mec.c @@ -76,12 +76,22 @@ void mec_io_bytes(int write, u16 port, unsigned int length, u8 *buf, u8 *csum) { int i = 0; int io_addr; + u8 access_mode, new_access_mode; if (length == 0) return; + /* + * Long access cannot be used on misaligned data since reading B0 loads + * the data register and writing B3 flushes it. + */ + if (port & 0x3) + access_mode = ACCESS_TYPE_BYTE; + else + access_mode = ACCESS_TYPE_LONG_AUTO_INCREMENT; + /* Initialize I/O at desired address */ - mec_emi_write_address(port, ACCESS_TYPE_LONG_AUTO_INCREMENT); + mec_emi_write_address(port, access_mode); /* Skip bytes in case of misaligned port */ io_addr = MEC_EMI_EC_DATA_B0 + (port & 0x3); @@ -94,11 +104,26 @@ void mec_io_bytes(int write, u16 port, unsigned int length, u8 *buf, u8 *csum) if (csum) *csum += buf[i]; + port++; /* Extra bounds check in case of misaligned length */ if (++i == length) return; } + /* + * Use long auto-increment access except for misaligned write, + * since writing B3 triggers the flush. + */ + if (length - i < 4 && write) + new_access_mode = ACCESS_TYPE_BYTE; + else + new_access_mode = ACCESS_TYPE_LONG_AUTO_INCREMENT; + if (new_access_mode != access_mode || + access_mode != ACCESS_TYPE_LONG_AUTO_INCREMENT) { + access_mode = new_access_mode; + mec_emi_write_address(port, access_mode); + } + /* Access [B0, B3] on each loop pass */ io_addr = MEC_EMI_EC_DATA_B0; } -- cgit v1.2.3