[PATCH] ACPI: TAD: report expired alarm status through RTC

raoxu <[email protected]> Fri, 31 Jul 2026 15:07:14 +0800
Newsgroups org.kernel.vger.linux-acpi,org.kernel.vger.linux-kernel,org.kernel.vger.stable
Message-ID <[email protected]>
From: Xu Rao <[email protected]>

acpi_tad_rtc_read_alarm() always sets rtc_wkalrm::pending to zero, so
RTC_WKALM_RD cannot report that a TAD alarm has expired.

ACPI 6.6, Section 9.17.5 defines _GWS as returning a DWORD bit field.
Bit 0 indicates that the selected timer has expired, bit 1 indicates
that it caused a platform wake, and bits 31:2 are reserved. Therefore,
only bit 0 maps to rtc_wkalrm::pending; converting the complete _GWS
value to bool would incorrectly treat the wake-source bit or a nonzero
reserved bit as an expired alarm.

Read _GWS for the AC timer, reject values wider than the specified
DWORD, and report its expired bit through rtc_wkalrm::pending. This
matches the existing read path, which reads the AC timer because alarms
programmed through the RTC interface set the AC and DC timers to the same
value.

Fixes: 7572dcabe38d ("ACPI: TAD: Add alarm support to the RTC class device interface")
Cc: [email protected]
Signed-off-by: Xu Rao <[email protected]>
---
 drivers/acpi/acpi_tad.c | 13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/drivers/acpi/acpi_tad.c b/drivers/acpi/acpi_tad.c
index fc43df083738..610840c6240d 100644
--- a/drivers/acpi/acpi_tad.c
+++ b/drivers/acpi/acpi_tad.c
@@ -51,6 +51,9 @@ MODULE_AUTHOR("Rafael J. Wysocki");
 #define ACPI_TAD_AC_TIMER	(u32)0
 #define ACPI_TAD_DC_TIMER	(u32)1

+/* ACPI TAD wake alarm status flags (ACPI 6.6, Section 9.17.5) */
+#define ACPI_TAD_WAKE_STATUS_EXPIRED	BIT(0)
+
 /* Special value for disabled timer or expired timer wake policy. */
 #define ACPI_TAD_WAKE_DISABLED	(~(u32)0)

@@ -709,6 +712,7 @@ static int acpi_tad_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *t)
 static int acpi_tad_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *t)
 {
 	unsigned long long retval;
+	unsigned long long status;
 	struct rtc_time tm_now;
 	struct acpi_tad_rt rt;
 	int ret;
@@ -740,7 +744,14 @@ static int acpi_tad_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *t)
 	if (retval > U32_MAX)
 		return -ENODATA;

-	t->pending = 0;
+	ret = __acpi_tad_wake_read(dev, "_GWS", ACPI_TAD_AC_TIMER, &status);
+	if (ret)
+		return ret;
+
+	if (status > U32_MAX)
+		return -ENODATA;
+
+	t->pending = !!(status & ACPI_TAD_WAKE_STATUS_EXPIRED);

 	if (retval != ACPI_TAD_WAKE_DISABLED) {
 		t->enabled = 1;
--
2.50.1