diff options
author | Victor Prupis <vprupis@google.com> | 2016-09-02 16:32:35 -0700 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2016-09-23 12:22:13 -0700 |
commit | 62bb88c730d196c2dff9a86018271ced0673e3fd (patch) | |
tree | 6e087479eb8653e8b25ade174cfd2861a5d49a1a | |
parent | 1ae3ffc6080ed23beb7d57b57b825ad2b8aba172 (diff) | |
download | chrome-ec-62bb88c730d196c2dff9a86018271ced0673e3fd.tar.gz |
pi2usb9281: Prevent race condition in RMW control register
Added unlocked versions of register access,
modified RMW functions to use unlocked versions
and made them locked themselves.
BRANCH=master
BUG=chrome-os-partner:49182
TEST=DUT boots successfully
Change-Id: Ifd16abc349cc731aeed78b12989595214e65cea2
Signed-off-by: Victor Prupis <vprupis@google.com>
Reviewed-on: https://chromium-review.googlesource.com/377151
Commit-Ready: Shawn N <shawnn@chromium.org>
Reviewed-by: Shawn N <shawnn@chromium.org>
-rw-r--r-- | driver/usb_switch_pi3usb9281.c | 94 |
1 files changed, 69 insertions, 25 deletions
diff --git a/driver/usb_switch_pi3usb9281.c b/driver/usb_switch_pi3usb9281.c index e97a04f8db..39b037cf49 100644 --- a/driver/usb_switch_pi3usb9281.c +++ b/driver/usb_switch_pi3usb9281.c @@ -61,14 +61,18 @@ static void unselect_chip(int port) mutex_unlock(chip->mux_lock); } -static uint8_t pi3usb9281_read(int port, uint8_t reg) +static uint8_t pi3usb9281_do_read(int port, uint8_t reg, int with_lock) { struct pi3usb9281_config *chip = &pi3usb9281_chips[port]; int res, val; - select_chip(port); + if (with_lock) + select_chip(port); + res = i2c_read8(chip->i2c_port, PI3USB9281_I2C_ADDR, reg, &val); - unselect_chip(port); + + if (with_lock) + unselect_chip(port); if (res) return 0xee; @@ -76,26 +80,56 @@ static uint8_t pi3usb9281_read(int port, uint8_t reg) return val; } -static int pi3usb9281_write(int port, uint8_t reg, uint8_t val) +static uint8_t pi3usb9281_read_u(int port, uint8_t reg) +{ + return pi3usb9281_do_read(port, reg, 0); +} + +static uint8_t pi3usb9281_read(int port, uint8_t reg) +{ + return pi3usb9281_do_read(port, reg, 1); +} + +static int pi3usb9281_do_write( + int port, uint8_t reg, uint8_t val, int with_lock) { struct pi3usb9281_config *chip = &pi3usb9281_chips[port]; int res; - select_chip(port); + if (with_lock) + select_chip(port); + res = i2c_write8(chip->i2c_port, PI3USB9281_I2C_ADDR, reg, val); - unselect_chip(port); + + if (with_lock) + unselect_chip(port); if (res) CPRINTS("PI3USB9281 I2C write failed"); return res; } +static int pi3usb9281_write(int port, uint8_t reg, uint8_t val) +{ + return pi3usb9281_do_write(port, reg, val, 1); +} + /* Write control register, taking care to correctly set reserved bits. */ -static int pi3usb9281_write_ctrl(int port, uint8_t ctrl) +static int pi3usb9281_do_write_ctrl(int port, uint8_t ctrl, int with_lock) { - return pi3usb9281_write(port, PI3USB9281_REG_CONTROL, + return pi3usb9281_do_write(port, PI3USB9281_REG_CONTROL, (ctrl & PI3USB9281_CTRL_MASK) | - PI3USB9281_CTRL_RSVD_1); + PI3USB9281_CTRL_RSVD_1, with_lock); +} + +static int pi3usb9281_write_ctrl(int port, uint8_t ctrl) +{ + return pi3usb9281_do_write_ctrl(port, ctrl, 1); +} + +static int pi3usb9281_write_ctrl_u(int port, uint8_t ctrl) +{ + return pi3usb9281_do_write_ctrl(port, ctrl, 0); } static int pi3usb9281_set_interrupt_mask(int port, uint8_t mask) @@ -190,17 +224,22 @@ static int pi3usb9281_reset(int port) static int pi3usb9281_set_switch_manual(int port, int val) { - uint8_t ctrl = pi3usb9281_read(port, PI3USB9281_REG_CONTROL); + int res = EC_ERROR_UNKNOWN; + uint8_t ctrl; - if (ctrl == 0xee) - return EC_ERROR_UNKNOWN; + select_chip(port); + ctrl = pi3usb9281_read_u(port, PI3USB9281_REG_CONTROL); - if (val) - ctrl &= ~PI3USB9281_CTRL_AUTO; - else - ctrl |= PI3USB9281_CTRL_AUTO; + if (ctrl != 0xee) { + if (val) + ctrl &= ~PI3USB9281_CTRL_AUTO; + else + ctrl |= PI3USB9281_CTRL_AUTO; + res = pi3usb9281_write_ctrl_u(port, ctrl); + } - return pi3usb9281_write_ctrl(port, ctrl); + unselect_chip(port); + return res; } static int pi3usb9281_set_pins(int port, uint8_t val) @@ -210,17 +249,22 @@ static int pi3usb9281_set_pins(int port, uint8_t val) static int pi3usb9281_set_switches(int port, int open) { - uint8_t ctrl = pi3usb9281_read(port, PI3USB9281_REG_CONTROL); + int res = EC_ERROR_UNKNOWN; + uint8_t ctrl; - if (ctrl == 0xee) - return EC_ERROR_UNKNOWN; + select_chip(port); + ctrl = pi3usb9281_read_u(port, PI3USB9281_REG_CONTROL); - if (open) - ctrl &= ~PI3USB9281_CTRL_SWITCH_AUTO; - else - ctrl |= PI3USB9281_CTRL_SWITCH_AUTO; + if (ctrl != 0xee) { + if (open) + ctrl &= ~PI3USB9281_CTRL_SWITCH_AUTO; + else + ctrl |= PI3USB9281_CTRL_SWITCH_AUTO; + res = pi3usb9281_write_ctrl_u(port, ctrl); + } - return pi3usb9281_write_ctrl(port, ctrl); + unselect_chip(port); + return res; } void usb_charger_set_switches(int port, enum usb_switch setting) |