summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMulin Chao <mlchao@nuvoton.com>2016-02-04 10:30:38 +0800
committerchrome-bot <chrome-bot@chromium.org>2016-02-04 19:15:06 -0800
commitff52ac20c1603317f601af73076179da06b3a909 (patch)
tree984260df4443044e9c268f415c3afd34e0fa85ce
parent1b9e6b2375ec2a2d2dc95968aa78d1c64faa1d2a (diff)
downloadchrome-ec-stabilize-smaug-7897.B.tar.gz
common: Fix sleep mask for multi-port lock.stabilize-smaug-7897.B
This change use a simple counter to to prevent ec enter sleep if there's any i2c port active. Once there's no i2c port active, we enable sleep bit of i2c in i2c_lock() func. Please note FW disables interrupt during changing counter to prevent preemptive conditions. Modified sources: 1. common/i2c.c: Fix sleep mask for multi-port lock. BUG=crbug.com/537759 TEST=make buildall -j; test on wheatley when CONFIG_LOW_POWER_S0 is deifned. BRANCH=none Change-Id: I17c226108fee0e5d656fa157808179898f9a8dbf Signed-off-by: Mulin Chao <mlchao@nuvoton.com> Reviewed-on: https://chromium-review.googlesource.com/325256 Reviewed-by: Randall Spangler <rspangler@chromium.org>
-rw-r--r--common/i2c.c26
1 files changed, 18 insertions, 8 deletions
diff --git a/common/i2c.c b/common/i2c.c
index 6e8bf10c4e..c06df9d784 100644
--- a/common/i2c.c
+++ b/common/i2c.c
@@ -33,6 +33,7 @@
#endif
static struct mutex port_mutex[I2C_CONTROLLER_COUNT];
+static uint32_t i2c_port_active_count;
int i2c_xfer(int port, int slave_addr, const uint8_t *out, int out_size,
uint8_t *in, int in_size, int flags)
@@ -57,18 +58,27 @@ void i2c_lock(int port, int lock)
ASSERT(port != -1);
#endif
if (lock) {
- /*
- * Don't allow deep sleep when I2C port is locked
- * TODO(crbug.com/537759): Fix sleep mask for multi-port lock.
- */
+ mutex_lock(port_mutex + port);
+
+ /* Disable interrupt during changing counter for preemption. */
+ interrupt_disable();
+
+ i2c_port_active_count++;
+ /* Ec cannot enter sleep if there's any i2c port active. */
disable_sleep(SLEEP_MASK_I2C_MASTER);
- mutex_lock(port_mutex + port);
+ interrupt_enable();
} else {
- mutex_unlock(port_mutex + port);
+ interrupt_disable();
+
+ i2c_port_active_count--;
+ /* Once there is no i2c port active, enable sleep bit of i2c. */
+ if (!i2c_port_active_count)
+ enable_sleep(SLEEP_MASK_I2C_MASTER);
- /* Allow deep sleep again after I2C port is unlocked */
- enable_sleep(SLEEP_MASK_I2C_MASTER);
+ interrupt_enable();
+
+ mutex_unlock(port_mutex + port);
}
}