diff options
author | Mulin Chao <mlchao@nuvoton.com> | 2016-02-04 10:30:38 +0800 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2016-02-04 19:15:06 -0800 |
commit | ff52ac20c1603317f601af73076179da06b3a909 (patch) | |
tree | 984260df4443044e9c268f415c3afd34e0fa85ce | |
parent | 1b9e6b2375ec2a2d2dc95968aa78d1c64faa1d2a (diff) | |
download | chrome-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.c | 26 |
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); } } |