From: Guenter Roeck <linux@roeck-us.net>
To: linux-hwmon@vger.kernel.org
Cc: Guenter Roeck <linux@roeck-us.net>, Sashiko <sashiko-bot@kernel.org>
Subject: [PATCH 3/3] hwmon: (acpi_power_meter) Check for 32-bit and 64-bit unknown ACPI values
Date: Sat, 31 Oct 2026 09:54:47 -0700 [thread overview]
Message-ID: <20261031165447.1771473-4-linux@roeck-us.net> (raw)
In-Reply-To: <20261031165447.1771473-1-linux@roeck-us.net>
According to the ACPI specification (Section 10.4), ACPI Power Meter
objects (_PMC capability fields, _PMM, _GHL, _PAI) report unknown or
unavailable integer values using an integer with all bits set, which can
be either U32_MAX (0xffffffff) or U64_MAX (0xffffffffffffffff) depending
on the DSDT revision.
Currently, only hwmon_power_average checks both 32-bit and 64-bit
unknown sentinels:
- power1_cap_hyst_show() only compares res->caps.hysteresis against the
32-bit UNKNOWN_HYSTERESIS (0xffffffff), so a 64-bit U64_MAX sentinel
bypasses the check, overflows when multiplied by 1000, and emits a
bogus number instead of "unknown".
- power1_accuracy_show() does not check for unknown sentinels at all,
formatting 0xffffffff as "4294967.295%".
- power_meter_read() does not check min_avg_interval, max_avg_interval,
avg_interval, min_cap, max_cap, or cap for unknown sentinels, exposing
scaled or overflowed values (or negative values when cast to signed
long) to userspace instead of returning -ENODATA.
- get_power_alarm_state() does not check whether resource->cap is
unknown before comparing resource->power > resource->cap.
- update_meter() passes an unknown caps.sampling_time directly to
msecs_to_jiffies(), caching sensor readings for weeks on 64-bit builds.
Introduce acpi_power_meter_is_unknown() to check for both U32_MAX and
U64_MAX, and use it across sysfs attribute handlers and meter updates:
- Return -ENODATA in power_meter_read() when numeric power, interval, or
cap attributes report an unknown value.
- Emit "unknown" in power1_cap_hyst_show() and power1_accuracy_show()
when hysteresis or accuracy is unknown.
- Avoid comparing against an unknown cap in get_power_alarm_state(),
returning 0 (no alarm, no error) unless a hardware capping
notification was latched.
- Skip the sampling_time cache window in update_meter() when
sampling_time is unknown.
Reported-by: Sashiko <sashiko-bot@kernel.org>
Fixes: de584afa5e18 ("hwmon driver for ACPI 4.0 power meters")
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
---
drivers/hwmon/acpi_power_meter.c | 49 ++++++++++++++++++++++----------
1 file changed, 34 insertions(+), 15 deletions(-)
diff --git a/drivers/hwmon/acpi_power_meter.c b/drivers/hwmon/acpi_power_meter.c
index 1f1d58995693..b28ca6acf630 100644
--- a/drivers/hwmon/acpi_power_meter.c
+++ b/drivers/hwmon/acpi_power_meter.c
@@ -30,13 +30,6 @@
#define POWER_METER_CAN_CAP (1 << 2)
#define POWER_METER_CAN_NOTIFY (1 << 3)
#define POWER_METER_IS_BATTERY (1 << 8)
-#define UNKNOWN_HYSTERESIS 0xFFFFFFFF
-/*
- * ACPI integers can either be 32-bit or 64-bit wide, so
- * we have to check for both values.
- */
-#define UNKNOWN_POWER_32 U32_MAX
-#define UNKNOWN_POWER_64 U64_MAX
#define METER_NOTIFY_CONFIG 0x80
#define METER_NOTIFY_TRIP 0x81
@@ -54,6 +47,15 @@ static bool force_cap_on;
static DEFINE_MUTEX(acpi_notify_lock);
+/*
+ * ACPI integers can either be 32-bit or 64-bit wide, so
+ * we have to check for both values.
+ */
+static bool acpi_power_meter_is_unknown(u64 val)
+{
+ return val == U32_MAX || val == U64_MAX;
+}
+
static int can_cap_in_hardware(void)
{
return force_cap_on || cap_in_hardware;
@@ -179,9 +181,10 @@ static int update_meter(struct acpi_power_meter_resource *resource)
acpi_status status;
unsigned long local_jiffies = jiffies;
- if (time_before(local_jiffies, resource->sensors_last_updated +
+ if (!acpi_power_meter_is_unknown(resource->caps.sampling_time) &&
+ time_before(local_jiffies, resource->sensors_last_updated +
msecs_to_jiffies(resource->caps.sampling_time)) &&
- resource->sensors_valid)
+ resource->sensors_valid)
return 0;
status = acpi_evaluate_integer(resource->acpi_dev->handle, "_PMM",
@@ -387,9 +390,7 @@ static bool get_power_alarm_state(struct acpi_power_meter_resource *resource)
resource->power_alarm = false;
ret = update_meter(resource);
- if (ret ||
- resource->power == UNKNOWN_POWER_32 ||
- resource->power == UNKNOWN_POWER_64)
+ if (ret || acpi_power_meter_is_unknown(resource->power))
return alarm;
/* need to update cap if not to support the notification. */
@@ -399,6 +400,9 @@ static bool get_power_alarm_state(struct acpi_power_meter_resource *resource)
return false;
}
+ if (acpi_power_meter_is_unknown(resource->cap))
+ return alarm;
+
resource->power_alarm = resource->power > resource->cap;
return alarm || resource->power_alarm;
}
@@ -460,26 +464,36 @@ static int power_meter_read(struct device *dev, enum hwmon_sensor_types type,
ret = update_meter(res);
if (ret)
return ret;
- if (res->power == UNKNOWN_POWER_32 || res->power == UNKNOWN_POWER_64)
+ if (acpi_power_meter_is_unknown(res->power))
return -ENODATA;
*val = res->power * 1000;
break;
case hwmon_power_average_interval_min:
+ if (acpi_power_meter_is_unknown(res->caps.min_avg_interval))
+ return -ENODATA;
*val = res->caps.min_avg_interval;
break;
case hwmon_power_average_interval_max:
+ if (acpi_power_meter_is_unknown(res->caps.max_avg_interval))
+ return -ENODATA;
*val = res->caps.max_avg_interval;
break;
case hwmon_power_average_interval:
ret = update_avg_interval(res);
if (ret)
return ret;
- *val = (res)->avg_interval;
+ if (acpi_power_meter_is_unknown(res->avg_interval))
+ return -ENODATA;
+ *val = res->avg_interval;
break;
case hwmon_power_cap_min:
+ if (acpi_power_meter_is_unknown(res->caps.min_cap))
+ return -ENODATA;
*val = res->caps.min_cap * 1000;
break;
case hwmon_power_cap_max:
+ if (acpi_power_meter_is_unknown(res->caps.max_cap))
+ return -ENODATA;
*val = res->caps.max_cap * 1000;
break;
case hwmon_power_alarm:
@@ -489,6 +503,8 @@ static int power_meter_read(struct device *dev, enum hwmon_sensor_types type,
ret = update_cap(res);
if (ret)
return ret;
+ if (acpi_power_meter_is_unknown(res->cap))
+ return -ENODATA;
*val = res->cap * 1000;
break;
default:
@@ -614,7 +630,7 @@ static ssize_t power1_cap_hyst_show(struct device *dev,
guard(mutex)(&res->lock);
- if (res->caps.hysteresis == UNKNOWN_HYSTERESIS)
+ if (acpi_power_meter_is_unknown(res->caps.hysteresis))
return sysfs_emit(buf, "unknown\n");
return sysfs_emit(buf, "%llu\n", res->caps.hysteresis * 1000);
@@ -629,6 +645,9 @@ static ssize_t power1_accuracy_show(struct device *dev,
guard(mutex)(&res->lock);
+ if (acpi_power_meter_is_unknown(res->caps.accuracy))
+ return sysfs_emit(buf, "unknown\n");
+
acc = res->caps.accuracy;
return sysfs_emit(buf, "%u.%u%%\n", acc / 1000, acc % 1000);
}
--
2.45.2
next prev parent reply other threads:[~2026-10-31 16:54 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-31 16:54 [PATCH 0/3] hwmon: (acpi_power_meter) Fix locking and unknown value handling Guenter Roeck
2026-10-31 16:54 ` [PATCH 1/3] hwmon: (acpi_power_meter) Fix missing locking in sysfs show callbacks and resume Guenter Roeck
2026-10-31 16:58 ` sashiko-bot
2026-10-31 16:54 ` [PATCH 2/3] hwmon: (acpi_power_meter) Prevent spurious power alarm when power is unknown Guenter Roeck
2026-10-31 17:02 ` sashiko-bot
2026-10-31 16:54 ` Guenter Roeck [this message]
2026-10-31 17:02 ` [PATCH 3/3] hwmon: (acpi_power_meter) Check for 32-bit and 64-bit unknown ACPI values sashiko-bot
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=20261031165447.1771473-4-linux@roeck-us.net \
--to=linux@roeck-us.net \
--cc=linux-hwmon@vger.kernel.org \
--cc=sashiko-bot@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