From: Sasha Levin <sashal@kernel.org>
To: patches@lists.linux.dev, stable@vger.kernel.org
Cc: "Ata İlhan Köktürk" <atailhan2006@gmail.com>,
"Rafael J. Wysocki" <rafael.j.wysocki@intel.com>,
"Sasha Levin" <sashal@kernel.org>,
rafael@kernel.org, linux-acpi@vger.kernel.org
Subject: [PATCH AUTOSEL 6.19-6.12] ACPI: battery: fix incorrect charging status when current is zero
Date: Wed, 11 Feb 2026 07:30:25 -0500 [thread overview]
Message-ID: <20260211123112.1330287-15-sashal@kernel.org> (raw)
In-Reply-To: <20260211123112.1330287-1-sashal@kernel.org>
From: Ata İlhan Köktürk <atailhan2006@gmail.com>
[ Upstream commit bb1256e0ddc7e9e406164319769b9f8d8389f056 ]
On some laptops, such as the Huawei Matebook series, the embedded
controller continues to report "Charging" status even when the
charge threshold is reached and no current is being drawn.
This incorrect reporting prevents the system from switching to battery
power profiles, leading to significantly higher power (e.g., 18W instead
of 7W during browsing) and missed remaining battery time estimation.
Validate the "Charging" state by checking if rate_now is zero. If the
hardware reports charging but the current is zero, report "Not Charging"
to user space.
Signed-off-by: Ata İlhan Köktürk <atailhan2006@gmail.com>
[ rjw: Whitespace fix, braces added to an inner if (), new comment rewrite ]
[ rjw: Changelog edits ]
Link: https://patch.msgid.link/20260129144856.43058-1-atailhan2006@gmail.com
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
Now I have a comprehensive picture. Let me compile my complete analysis.
---
## Complete Analysis: ACPI: battery: fix incorrect charging status when
current is zero
### 1. COMMIT MESSAGE ANALYSIS
The commit message clearly describes a **real-world hardware bug**
affecting the Huawei Matebook series. The symptoms are concrete and
user-visible:
- EC firmware continues reporting "Charging" even after the charge
threshold is reached and no current flows
- This causes userspace (power management daemons, UPower, etc.) to use
AC-plugged power profiles
- Result: 18W power draw during browsing instead of 7W (a 2.5x power
difference!)
- Missing "remaining battery time" estimation because system thinks it's
charging
The commit message uses the word "fix" in the subject, describes a clear
user-visible misbehavior, and was accepted by the ACPI subsystem
maintainer Rafael Wysocki who also made editorial improvements
(indicating active review).
### 2. CODE CHANGE ANALYSIS
The change is in `acpi_battery_get_property()` at the
`POWER_SUPPLY_PROP_STATUS` case. Let me examine the before and after:
**Before (line 213-214):**
```213:214:drivers/acpi/battery.c
else if (battery->state & ACPI_BATTERY_STATE_CHARGING)
val->intval = POWER_SUPPLY_STATUS_CHARGING;
```
When the EC sets the `ACPI_BATTERY_STATE_CHARGING` bit, the kernel
unconditionally reports `POWER_SUPPLY_STATUS_CHARGING` to userspace.
**After (from the diff):**
```c
else if (battery->state & ACPI_BATTERY_STATE_CHARGING)
/* Validate the status by checking the current.
*/
if (battery->rate_now !=
ACPI_BATTERY_VALUE_UNKNOWN &&
battery->rate_now == 0) {
/* On charge but no current (0W/0mA). */
val->intval =
POWER_SUPPLY_STATUS_NOT_CHARGING;
} else {
val->intval =
POWER_SUPPLY_STATUS_CHARGING;
}
```
The change adds a validation: when EC says "Charging" but current is
*confirmed zero* (`rate_now` is known AND equals 0), report
`NOT_CHARGING` instead.
**Safety guards in the condition:**
- `rate_now != ACPI_BATTERY_VALUE_UNKNOWN` — if rate is unknown
(0xFFFFFFFF), preserve original "Charging" behavior. This is
conservative.
- `rate_now == 0` — only triggers when current is truly zero, not
negative or any other value.
**Syntactic correctness of the if/else chain:**
The nested `if/else` with explicit braces is a complete statement, so
the outer `else if` chain parses correctly. The subsequent `else if
(CHARGE_LIMITING)` attaches to the outer chain, not the inner if. This
is safe and was explicitly reviewed by Rafael (who noted "braces added
to an inner if()").
### 3. PRECEDENT: EXACT SAME PATTERN EXISTS FOR DISCHARGING
This fix is the **direct mirror** of an existing, well-established
workaround. The `acpi_battery_handle_discharging()` function (added in
commit `19fffc8450d43`, v4.18, 2018) does the exact same thing for the
discharging case:
```183:195:drivers/acpi/battery.c
static int acpi_battery_handle_discharging(struct acpi_battery *battery)
{
/*
- Some devices wrongly report discharging if the battery's charge
level
- was above the device's start charging threshold atm the AC adapter
- was plugged in and the device thus did not start a new charge cycle.
*/
if ((battery_ac_is_broken || power_supply_is_system_supplied())
&&
battery->rate_now == 0)
return POWER_SUPPLY_STATUS_NOT_CHARGING;
return POWER_SUPPLY_STATUS_DISCHARGING;
}
```
The logic is analogous:
- **Discharging handler**: EC says "discharging" + AC connected +
current is 0 → report "Not Charging"
- **New charging fix**: EC says "charging" + current is 0 → report "Not
Charging"
The discharging handler has been in mainline since 2018 (v4.18) and is
well-proven. The new fix follows the identical reasoning.
### 4. CLASSIFICATION
This is a **hardware quirk/workaround** for buggy EC firmware behavior.
This falls squarely in the "quirks and workarounds" exception category
for stable trees. The pattern of ECs misreporting battery state is well-
documented in this driver (see the discharging handler, the
`battery_ac_is_broken` quirk, the notification delay quirk, etc.).
### 5. SCOPE AND RISK ASSESSMENT
- **Size**: ~7 lines of actual logic change in a single file
- **Files touched**: 1 (`drivers/acpi/battery.c`)
- **Risk**: Very low
- Only affects the `POWER_SUPPLY_PROP_STATUS` property report
- Only changes behavior when `rate_now` is known to be exactly 0
- When `rate_now` is unknown, behavior is unchanged
- No new APIs, no new module parameters, no new userspace interfaces
- Uses only existing constants and fields that have been present since
v4.18+
- The change is conservative — it only transforms "Charging" to "Not
Charging", not to anything unexpected
### 6. USER IMPACT
- **Directly affected**: Huawei Matebook series users (and potentially
other laptops with similar EC firmware behavior)
- **Severity of the bug**: Moderate-to-high — incorrect battery status
causes:
- 2.5x higher power consumption (power profiles stuck on AC mode)
- Missing battery time estimation
- Misleading UI indicators
- **Impact scope**: Anyone using ACPI battery reporting with charge
thresholds on affected hardware
### 7. DEPENDENCY CHECK
- `rate_now` field: present since the beginning of `struct acpi_battery`
- `ACPI_BATTERY_VALUE_UNKNOWN`: defined as `0xFFFFFFFF`, present since
early kernel versions
- `POWER_SUPPLY_STATUS_NOT_CHARGING`: present since v2.6.24+
- No dependency on other uncommitted patches
**Context differences for older stable trees:**
- **6.12.y+**: Applies cleanly (has
`ACPI_BATTERY_STATE_CHARGE_LIMITING`)
- **6.6.y and older**: Trivial context adjustment needed (missing the
`CHARGE_LIMITING` line), but the actual change is identical. The patch
would need a minor backport adaptation.
### 8. STABILITY INDICATORS
- Accepted by the ACPI subsystem maintainer (Rafael J. Wysocki) who
actively reviewed and polished the patch
- The Link points to patch.msgid.link, indicating it went through the
standard mailing list review process
- Rafael's edits (whitespace fix, braces, comment rewrite, changelog
edits) show careful review
### 9. POTENTIAL CONCERNS
- **Could this misfire?**: Only if a device reports `rate_now == 0`
while actually charging. But if current is truly zero, no charge is
flowing — so "Not Charging" is semantically correct regardless of what
the EC claims.
- **Could it break something?**: The only behavioral change is
"Charging" → "Not Charging" when current is confirmed zero. No
application should depend on "Charging" status when actual current is
zero.
- **Regression risk**: Extremely low given the conservative conditions.
### Summary
This commit fixes a real, user-reported hardware bug where incorrect
"Charging" status causes significantly higher power consumption (18W vs
7W) on Huawei Matebook laptops. The fix is small (7 lines), contained to
a single file, uses only existing APIs/fields, follows an identical
well-proven pattern already in the driver since 2018 (the discharging
handler), was reviewed by the subsystem maintainer, and has essentially
zero regression risk. It meets all stable kernel criteria: obviously
correct, fixes a real bug, small and contained, no new features.
**YES**
drivers/acpi/battery.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c
index 34181fa52e937..4b28ef79e6ac8 100644
--- a/drivers/acpi/battery.c
+++ b/drivers/acpi/battery.c
@@ -211,7 +211,14 @@ static int acpi_battery_get_property(struct power_supply *psy,
if (battery->state & ACPI_BATTERY_STATE_DISCHARGING)
val->intval = acpi_battery_handle_discharging(battery);
else if (battery->state & ACPI_BATTERY_STATE_CHARGING)
- val->intval = POWER_SUPPLY_STATUS_CHARGING;
+ /* Validate the status by checking the current. */
+ if (battery->rate_now != ACPI_BATTERY_VALUE_UNKNOWN &&
+ battery->rate_now == 0) {
+ /* On charge but no current (0W/0mA). */
+ val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
+ } else {
+ val->intval = POWER_SUPPLY_STATUS_CHARGING;
+ }
else if (battery->state & ACPI_BATTERY_STATE_CHARGE_LIMITING)
val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
else if (acpi_battery_is_charged(battery))
--
2.51.0
next prev parent reply other threads:[~2026-02-11 12:31 UTC|newest]
Thread overview: 35+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-02-11 12:30 [PATCH AUTOSEL 6.19-5.10] s390/perf: Disable register readout on sampling events Sasha Levin
2026-02-11 12:30 ` [PATCH AUTOSEL 6.19-5.10] arm64: Add support for TSV110 Spectre-BHB mitigation Sasha Levin
2026-02-11 12:30 ` [PATCH AUTOSEL 6.19-5.10] xenbus: Use .freeze/.thaw to handle xenbus devices Sasha Levin
2026-02-11 12:30 ` [PATCH AUTOSEL 6.19-5.10] s390/purgatory: Add -Wno-default-const-init-unsafe to KBUILD_CFLAGS Sasha Levin
2026-02-11 12:30 ` [PATCH AUTOSEL 6.19-6.18] s390/boot: " Sasha Levin
2026-02-11 12:30 ` [PATCH AUTOSEL 6.19-6.1] perf/arm-cmn: Support CMN-600AE Sasha Levin
2026-02-11 12:30 ` [PATCH AUTOSEL 6.19-6.18] ntfs: ->d_compare() must not block Sasha Levin
2026-02-11 12:30 ` [PATCH AUTOSEL 6.19-6.12] ACPI: x86: s2idle: Invoke Microsoft _DSM Function 9 (Turn On Display) Sasha Levin
2026-02-11 12:30 ` [PATCH AUTOSEL 6.19-6.12] block: decouple secure erase size limit from discard size limit Sasha Levin
2026-02-11 12:30 ` [PATCH AUTOSEL 6.19-5.10] sparc: don't reference obsolete termio struct for TC* constants Sasha Levin
2026-02-11 12:30 ` [PATCH AUTOSEL 6.19-5.10] EFI/CPER: don't go past the ARM processor CPER record buffer Sasha Levin
2026-02-11 12:30 ` [PATCH AUTOSEL 6.19] ACPI: scan: Use async schedule function in acpi_scan_clear_dep_fn() Sasha Levin
2026-02-11 12:30 ` [PATCH AUTOSEL 6.19-6.6] cpufreq: dt-platdev: Block the driver from probing on more QC platforms Sasha Levin
2026-02-11 12:30 ` [PATCH AUTOSEL 6.19-5.10] EFI/CPER: don't dump the entire memory region Sasha Levin
2026-02-11 12:30 ` Sasha Levin [this message]
2026-02-11 12:30 ` [PATCH AUTOSEL 6.19-6.18] rust: cpufreq: always inline functions using build_assert with arguments Sasha Levin
2026-02-11 12:30 ` [PATCH AUTOSEL 6.19-6.18] blk-mq-sched: unify elevators checking for async requests Sasha Levin
2026-02-11 12:30 ` [PATCH AUTOSEL 6.19-5.10] x86/xen/pvh: Enable PAE mode for 32-bit guest only when CONFIG_X86_PAE is set Sasha Levin
2026-02-11 12:30 ` [PATCH AUTOSEL 6.19-6.12] APEI/GHES: ARM processor Error: don't go past allocated memory Sasha Levin
2026-02-11 12:30 ` [PATCH AUTOSEL 6.19-6.18] md raid: fix hang when stopping arrays with metadata through dm-raid Sasha Levin
2026-02-11 12:30 ` [PATCH AUTOSEL 6.19-5.10] tools/power cpupower: Reset errno before strtoull() Sasha Levin
2026-02-11 12:30 ` [PATCH AUTOSEL 6.19-5.10] sparc: Synchronize user stack on fork and clone Sasha Levin
2026-02-11 12:30 ` [PATCH AUTOSEL 6.19-5.10] blk-mq-debugfs: add missing debugfs_mutex in blk_mq_debugfs_register_hctxs() Sasha Levin
2026-02-11 12:30 ` [PATCH AUTOSEL 6.19-5.10] rnbd-srv: Zero the rsp buffer before using it Sasha Levin
2026-02-11 12:30 ` [PATCH AUTOSEL 6.19-6.12] alpha: fix user-space corruption during memory compaction Sasha Levin
2026-02-11 12:30 ` [PATCH AUTOSEL 6.19-5.10] ACPICA: Abort AML bytecode execution when executing AML_FATAL_OP Sasha Levin
2026-02-11 12:30 ` [PATCH AUTOSEL 6.19] arm64: mte: Set TCMA1 whenever MTE is present in the kernel Sasha Levin
2026-02-11 12:30 ` [PATCH AUTOSEL 6.19-6.18] tools/cpupower: Fix inverted APERF capability check Sasha Levin
2026-02-11 12:30 ` [PATCH AUTOSEL 6.19-5.15] ACPI: processor: Fix NULL-pointer dereference in acpi_processor_errata_piix4() Sasha Levin
2026-02-11 12:30 ` [PATCH AUTOSEL 6.19-6.12] ACPI: resource: Add JWIPC JVC9100 to irq1_level_low_skip_override[] Sasha Levin
2026-02-11 12:30 ` [PATCH AUTOSEL 6.19-6.6] perf/cxlpmu: Replace IRQF_ONESHOT with IRQF_NO_THREAD Sasha Levin
2026-02-11 12:30 ` [PATCH AUTOSEL 6.19-6.6] md-cluster: fix NULL pointer dereference in process_metadata_update Sasha Levin
2026-02-11 12:30 ` [PATCH AUTOSEL 6.19-5.10] APEI/GHES: ensure that won't go past CPER allocated record Sasha Levin
2026-02-11 12:30 ` [PATCH AUTOSEL 6.19-6.12] powercap: intel_rapl: Add PL4 support for Ice Lake Sasha Levin
2026-02-11 12:30 ` [PATCH AUTOSEL 6.19-6.18] io_uring/timeout: annotate data race in io_flush_timeouts() Sasha Levin
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260211123112.1330287-15-sashal@kernel.org \
--to=sashal@kernel.org \
--cc=atailhan2006@gmail.com \
--cc=linux-acpi@vger.kernel.org \
--cc=patches@lists.linux.dev \
--cc=rafael.j.wysocki@intel.com \
--cc=rafael@kernel.org \
--cc=stable@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox