[PATCH] ACPI: battery: Fix bogus cycle count values on systems without _BIX

Armin Wolf <[email protected]> Fri, 7 Aug 2026 01:38:17 +0200
Newsgroups gmane.linux.kernel,gmane.linux.acpi.devel
Message-ID <[email protected]>
Devices supporting only the legacy _BIF ACPI control method cannot
know the cycle count of the associated battery, so cycle_count always
remains 0. Claiming support for POWER_SUPPLY_PROP_CYCLE_COUNT on
such devices can thus mislead userspace applications and prevents
power supply extensions from supplying correct cycle count values.

Fix this by not claiming support for POWER_SUPPLY_PROP_CYCLE_COUNT
on devices without _BIX.

Signed-off-by: Armin Wolf <[email protected]>
---
 drivers/acpi/battery.c | 131 +++++++++++++++++++++++++++++++++++------
 1 file changed, 113 insertions(+), 18 deletions(-)

diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c
index 0084f308b790..b64f876f93cb 100644
--- a/drivers/acpi/battery.c
+++ b/drivers/acpi/battery.c
@@ -324,7 +324,9 @@ static int acpi_battery_get_property(struct power_supply *psy,
 	return ret;
 }
 
-static const enum power_supply_property charge_battery_props[] = {
+/* For devices supporting the _BIX ACPI control method */
+
+static const enum power_supply_property charge_battery_extended_props[] = {
 	POWER_SUPPLY_PROP_STATUS,
 	POWER_SUPPLY_PROP_PRESENT,
 	POWER_SUPPLY_PROP_TECHNOLOGY,
@@ -342,7 +344,7 @@ static const enum power_supply_property charge_battery_props[] = {
 	POWER_SUPPLY_PROP_SERIAL_NUMBER,
 };
 
-static const enum power_supply_property charge_battery_full_cap_broken_props[] = {
+static const enum power_supply_property charge_battery_full_cap_broken_extended_props[] = {
 	POWER_SUPPLY_PROP_STATUS,
 	POWER_SUPPLY_PROP_PRESENT,
 	POWER_SUPPLY_PROP_TECHNOLOGY,
@@ -356,7 +358,7 @@ static const enum power_supply_property charge_battery_full_cap_broken_props[] =
 	POWER_SUPPLY_PROP_SERIAL_NUMBER,
 };
 
-static const enum power_supply_property energy_battery_props[] = {
+static const enum power_supply_property energy_battery_extended_props[] = {
 	POWER_SUPPLY_PROP_STATUS,
 	POWER_SUPPLY_PROP_PRESENT,
 	POWER_SUPPLY_PROP_TECHNOLOGY,
@@ -374,7 +376,7 @@ static const enum power_supply_property energy_battery_props[] = {
 	POWER_SUPPLY_PROP_SERIAL_NUMBER,
 };
 
-static const enum power_supply_property energy_battery_full_cap_broken_props[] = {
+static const enum power_supply_property energy_battery_full_cap_broken_extended_props[] = {
 	POWER_SUPPLY_PROP_STATUS,
 	POWER_SUPPLY_PROP_PRESENT,
 	POWER_SUPPLY_PROP_TECHNOLOGY,
@@ -388,6 +390,68 @@ static const enum power_supply_property energy_battery_full_cap_broken_props[] =
 	POWER_SUPPLY_PROP_SERIAL_NUMBER,
 };
 
+/* For devices supporting only the _BIF ACPI control method */
+
+static const enum power_supply_property charge_battery_props[] = {
+	POWER_SUPPLY_PROP_STATUS,
+	POWER_SUPPLY_PROP_PRESENT,
+	POWER_SUPPLY_PROP_TECHNOLOGY,
+	POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
+	POWER_SUPPLY_PROP_VOLTAGE_NOW,
+	POWER_SUPPLY_PROP_CURRENT_NOW,
+	POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
+	POWER_SUPPLY_PROP_CHARGE_FULL,
+	POWER_SUPPLY_PROP_CHARGE_NOW,
+	POWER_SUPPLY_PROP_CAPACITY,
+	POWER_SUPPLY_PROP_CAPACITY_LEVEL,
+	POWER_SUPPLY_PROP_MODEL_NAME,
+	POWER_SUPPLY_PROP_MANUFACTURER,
+	POWER_SUPPLY_PROP_SERIAL_NUMBER,
+};
+
+static const enum power_supply_property charge_battery_full_cap_broken_props[] = {
+	POWER_SUPPLY_PROP_STATUS,
+	POWER_SUPPLY_PROP_PRESENT,
+	POWER_SUPPLY_PROP_TECHNOLOGY,
+	POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
+	POWER_SUPPLY_PROP_VOLTAGE_NOW,
+	POWER_SUPPLY_PROP_CURRENT_NOW,
+	POWER_SUPPLY_PROP_CHARGE_NOW,
+	POWER_SUPPLY_PROP_MODEL_NAME,
+	POWER_SUPPLY_PROP_MANUFACTURER,
+	POWER_SUPPLY_PROP_SERIAL_NUMBER,
+};
+
+static const enum power_supply_property energy_battery_props[] = {
+	POWER_SUPPLY_PROP_STATUS,
+	POWER_SUPPLY_PROP_PRESENT,
+	POWER_SUPPLY_PROP_TECHNOLOGY,
+	POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
+	POWER_SUPPLY_PROP_VOLTAGE_NOW,
+	POWER_SUPPLY_PROP_POWER_NOW,
+	POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN,
+	POWER_SUPPLY_PROP_ENERGY_FULL,
+	POWER_SUPPLY_PROP_ENERGY_NOW,
+	POWER_SUPPLY_PROP_CAPACITY,
+	POWER_SUPPLY_PROP_CAPACITY_LEVEL,
+	POWER_SUPPLY_PROP_MODEL_NAME,
+	POWER_SUPPLY_PROP_MANUFACTURER,
+	POWER_SUPPLY_PROP_SERIAL_NUMBER,
+};
+
+static const enum power_supply_property energy_battery_full_cap_broken_props[] = {
+	POWER_SUPPLY_PROP_STATUS,
+	POWER_SUPPLY_PROP_PRESENT,
+	POWER_SUPPLY_PROP_TECHNOLOGY,
+	POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
+	POWER_SUPPLY_PROP_VOLTAGE_NOW,
+	POWER_SUPPLY_PROP_POWER_NOW,
+	POWER_SUPPLY_PROP_ENERGY_NOW,
+	POWER_SUPPLY_PROP_MODEL_NAME,
+	POWER_SUPPLY_PROP_MANUFACTURER,
+	POWER_SUPPLY_PROP_SERIAL_NUMBER,
+};
+
 /* Battery Management */
 struct acpi_offsets {
 	size_t offset;		/* offset inside struct acpi_sbs_battery */
@@ -875,6 +939,7 @@ static void __exit battery_hook_exit(void)
 
 static int sysfs_add_battery(struct acpi_battery *battery)
 {
+	bool extended_info_available = test_bit(ACPI_BATTERY_XINFO_PRESENT, &battery->flags);
 	struct power_supply_config psy_cfg = {
 		.drv_data = battery,
 		.attr_grp = acpi_battery_groups,
@@ -888,25 +953,55 @@ static int sysfs_add_battery(struct acpi_battery *battery)
 
 	if (battery->power_unit == ACPI_BATTERY_POWER_UNIT_MA) {
 		if (full_cap_broken) {
-			battery->bat_desc.properties =
-			    charge_battery_full_cap_broken_props;
-			battery->bat_desc.num_properties =
-			    ARRAY_SIZE(charge_battery_full_cap_broken_props);
+			if (extended_info_available) {
+				battery->bat_desc.properties =
+					charge_battery_full_cap_broken_extended_props;
+				battery->bat_desc.num_properties =
+					ARRAY_SIZE(charge_battery_full_cap_broken_extended_props);
+			} else {
+				battery->bat_desc.properties =
+					charge_battery_full_cap_broken_props;
+				battery->bat_desc.num_properties =
+					ARRAY_SIZE(charge_battery_full_cap_broken_props);
+			}
 		} else {
-			battery->bat_desc.properties = charge_battery_props;
-			battery->bat_desc.num_properties =
-			    ARRAY_SIZE(charge_battery_props);
+			if (extended_info_available) {
+				battery->bat_desc.properties =
+					charge_battery_extended_props;
+				battery->bat_desc.num_properties =
+					ARRAY_SIZE(charge_battery_extended_props);
+			} else {
+				battery->bat_desc.properties =
+					charge_battery_props;
+				battery->bat_desc.num_properties =
+					ARRAY_SIZE(charge_battery_props);
+			}
 		}
 	} else {
 		if (full_cap_broken) {
-			battery->bat_desc.properties =
-			    energy_battery_full_cap_broken_props;
-			battery->bat_desc.num_properties =
-			    ARRAY_SIZE(energy_battery_full_cap_broken_props);
+			if (extended_info_available) {
+				battery->bat_desc.properties =
+					energy_battery_full_cap_broken_extended_props;
+				battery->bat_desc.num_properties =
+					ARRAY_SIZE(energy_battery_full_cap_broken_extended_props);
+			} else {
+				battery->bat_desc.properties =
+					energy_battery_full_cap_broken_props;
+				battery->bat_desc.num_properties =
+					ARRAY_SIZE(energy_battery_full_cap_broken_props);
+			}
 		} else {
-			battery->bat_desc.properties = energy_battery_props;
-			battery->bat_desc.num_properties =
-			    ARRAY_SIZE(energy_battery_props);
+			if (extended_info_available) {
+				battery->bat_desc.properties =
+					energy_battery_extended_props;
+				battery->bat_desc.num_properties =
+					ARRAY_SIZE(energy_battery_extended_props);
+			} else {
+				battery->bat_desc.properties =
+					energy_battery_props;
+				battery->bat_desc.num_properties =
+					ARRAY_SIZE(energy_battery_props);
+			}
 		}
 	}
 
-- 
2.39.5