Skip to content

Commit 3bd554e

Browse files
Wer-Wolfrafaeljw
authored andcommitted
ACPI: SBS: Fix handling of Smart Battery Selectors
The "Smart Battery Selector" standard says that when writing SelectorState (0x1), the nibbles which should not be modified need to be masked with 0xff. This is necessary since in contrast to a "Smart Battery Manager", the last three nibbles are writable. Failing to do so might trigger the following cycle: 1. Host accidentally changes power source of the system (3rd nibble) when selecting a battery. 2. Power source is invalid, Selector changes to another power source. 3. Selector notifies host that it changed the power source. 4. Host re-reads some batteries. 5. goto 1 for each re-read battery. This loop might also be entered when a battery which is not present is selected for SMBus access. In the end some workqueues fill up, which causes the system to lockup upon suspend/shutdown. Fix this by correctly masking the value to be written, and avoid selecting batteries which are absent. Tested on a Acer Travelmate 4002WLMi. Signed-off-by: Armin Wolf <W_Armin@gmx.de> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
1 parent e5b492c commit 3bd554e

1 file changed

Lines changed: 18 additions & 9 deletions

File tree

drivers/acpi/sbs.c

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -473,23 +473,32 @@ static const struct device_attribute alarm_attr = {
473473
-------------------------------------------------------------------------- */
474474
static int acpi_battery_read(struct acpi_battery *battery)
475475
{
476-
int result = 0, saved_present = battery->present;
476+
int result, saved_present = battery->present;
477477
u16 state;
478478

479479
if (battery->sbs->manager_present) {
480480
result = acpi_smbus_read(battery->sbs->hc, SMBUS_READ_WORD,
481481
ACPI_SBS_MANAGER, 0x01, (u8 *)&state);
482-
if (!result)
483-
battery->present = state & (1 << battery->id);
484-
state &= 0x0fff;
482+
if (result)
483+
return result;
484+
485+
battery->present = state & (1 << battery->id);
486+
if (!battery->present)
487+
return 0;
488+
489+
/* Masking necessary for Smart Battery Selectors */
490+
state = 0x0fff;
485491
state |= 1 << (battery->id + 12);
486492
acpi_smbus_write(battery->sbs->hc, SMBUS_WRITE_WORD,
487493
ACPI_SBS_MANAGER, 0x01, (u8 *)&state, 2);
488-
} else if (battery->id == 0)
489-
battery->present = 1;
490-
491-
if (result || !battery->present)
492-
return result;
494+
} else {
495+
if (battery->id == 0) {
496+
battery->present = 1;
497+
} else {
498+
if (!battery->present)
499+
return 0;
500+
}
501+
}
493502

494503
if (saved_present != battery->present) {
495504
battery->update_time = 0;

0 commit comments

Comments
 (0)