CHROMIUM: power: sbs-battery: Prevent CAPACITY_MODE races
A subset of smart battery commands return charge or energy depending on
the CAPACITY_MODE bit setting of BatteryMode(). In order to
unambiguously read a charge or energy value, it is necessary to ensure
that CAPACITY_MODE is set as desired, and not changed for the duration
of the attribute read.
BUG=chromium:686942
TEST=On kevin, spam reads to charge_full battery sysfs attribute while
performing suspend_stress_test, verify that the same value is always
returned.
Signed-off-by: Shawn Nematbakhsh <shawnn@chromium.org>
Change-Id: Ic39e8d7f982d7045a2da6bf6fe835c2c3434815c
Reviewed-on: https://chromium-review.googlesource.com/531760
Commit-Ready: Shawn N <shawnn@chromium.org>
Tested-by: Shawn N <shawnn@chromium.org>
Reviewed-by: Guenter Roeck <groeck@chromium.org>
diff --git a/drivers/power/sbs-battery.c b/drivers/power/sbs-battery.c
index 837f460..b9d1285 100644
--- a/drivers/power/sbs-battery.c
+++ b/drivers/power/sbs-battery.c
@@ -167,6 +167,7 @@
int poll_time;
struct delayed_work work;
int ignore_changes;
+ struct mutex mode_lock;
};
static char model_name[I2C_SMBUS_BLOCK_MAX + 1];
@@ -580,7 +581,13 @@
if (ret < 0)
break;
+ /* sbs_get_battery_capacity() will change the battery mode
+ * temporarily to read the requested attribute. Ensure we stay
+ * in the desired mode for the duration of the attribute read.
+ */
+ mutex_lock(&chip->mode_lock);
ret = sbs_get_battery_capacity(client, ret, psp, val);
+ mutex_unlock(&chip->mode_lock);
break;
case POWER_SUPPLY_PROP_SERIAL_NUMBER:
@@ -831,6 +838,7 @@
*/
chip->ignore_changes = 1;
chip->last_state = POWER_SUPPLY_STATUS_UNKNOWN;
+ mutex_init(&chip->mode_lock);
pdata = sbs_of_populate_pdata(client);