* [PATCH v4 1/2] ACPI: TAD: introduce acpi_has_rtc()
2026-10-27 22:05 [PATCH v4 0/2] rtc: efi: defer to the ACPI TAD if it can drive the RTC Hamza Mahfooz
@ 2026-10-27 22:05 ` Hamza Mahfooz
2026-10-27 22:16 ` sashiko-bot
2026-10-27 22:05 ` [PATCH v4 2/2] rtc: efi: defer to the ACPI TAD if it can drive the RTC Hamza Mahfooz
1 sibling, 1 reply; 5+ messages in thread
From: Hamza Mahfooz @ 2026-10-27 22:05 UTC (permalink / raw)
To: linux-acpi, linux-rtc
Cc: Rafael J. Wysocki, Len Brown, Alexandre Belloni, Ard Biesheuvel,
Hamza Mahfooz
The same RTC may also be accessible by other means, like the EFI
GetTime() and SetTime() runtime services used by rtc-efi, which are best
avoided if there is a native ACPI interface to the RTC.
To allow other RTC drivers to stand down in that case, add an exported
helper, acpi_has_rtc(), that returns true if there is a TAD the driver
will register an RTC class device for.
The helper looks for a platform device matching the driver's ID table
whose _GCP indicates real time support, like acpi_tad_probe() checks,
instead of checking whether the driver has bound to such a device, so
that callers need not depend on the order in which drivers are probed.
Suggested-by: Ard Biesheuvel <ardb@kernel.org>
Reviewed-by: Ard Biesheuvel <ardb@kernel.org> (v3)
Signed-off-by: Hamza Mahfooz <hamzamahfooz@linux.microsoft.com>
---
drivers/acpi/acpi_tad.c | 48 ++++++++++++++++++++++++++++++++++++-----
include/linux/acpi.h | 6 ++++++
2 files changed, 49 insertions(+), 5 deletions(-)
diff --git a/drivers/acpi/acpi_tad.c b/drivers/acpi/acpi_tad.c
index 45459a4ca..a07f4f4fd 100644
--- a/drivers/acpi/acpi_tad.c
+++ b/drivers/acpi/acpi_tad.c
@@ -622,9 +622,52 @@ static const struct attribute_group acpi_tad_group = {
__ATTRIBUTE_GROUPS(acpi_tad);
+static const struct acpi_device_id acpi_tad_ids[] = {
+ {"ACPI000E", 0},
+ {}
+};
+
#ifdef CONFIG_RTC_CLASS
/* RTC class device interface */
+static int acpi_tad_rtc_match(struct device *dev, const void *data)
+{
+ unsigned long long caps;
+ acpi_status status;
+
+ if (!acpi_match_device(acpi_tad_ids, dev))
+ return 0;
+
+ status = acpi_evaluate_integer(ACPI_HANDLE(dev), "_GCP", NULL, &caps);
+
+ return ACPI_SUCCESS(status) && (caps & ACPI_TAD_RT);
+}
+
+/**
+ * acpi_has_rtc - Check if the RTC should be driven via the ACPI TAD
+ *
+ * Check if there is a TAD implementing the real time methods that this driver
+ * will register an RTC class device for.
+ *
+ * Return: %true if the RTC should be driven via the ACPI TAD, %false otherwise.
+ */
+bool acpi_has_rtc(void)
+{
+ struct device *dev;
+
+ if (acpi_disabled)
+ return false;
+
+ dev = bus_find_device(&platform_bus_type, NULL, NULL,
+ acpi_tad_rtc_match);
+ if (!dev)
+ return false;
+
+ put_device(dev);
+ return true;
+}
+EXPORT_SYMBOL_GPL(acpi_has_rtc);
+
static void acpi_tad_rt_to_tm(struct acpi_tad_rt *rt, struct rtc_time *tm)
{
tm->tm_year = rt->year - 1900;
@@ -894,11 +937,6 @@ static int acpi_tad_probe(struct platform_device *pdev)
return 0;
}
-static const struct acpi_device_id acpi_tad_ids[] = {
- {"ACPI000E", 0},
- {}
-};
-
static struct platform_driver acpi_tad_driver = {
.driver = {
.name = "acpi-tad",
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index ddacac812..74c60b8e8 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -1553,6 +1553,12 @@ extern bool acpi_has_watchdog(void);
static inline bool acpi_has_watchdog(void) { return false; }
#endif
+#if IS_REACHABLE(CONFIG_ACPI_TAD) && IS_ENABLED(CONFIG_RTC_CLASS)
+bool acpi_has_rtc(void);
+#else
+static inline bool acpi_has_rtc(void) { return false; }
+#endif
+
#ifdef CONFIG_ACPI_SPCR_TABLE
extern bool qdf2400_e44_present;
int acpi_parse_spcr(bool enable_earlycon, bool enable_console);
--
2.56.0
^ permalink raw reply related [flat|nested] 5+ messages in thread* [PATCH v4 2/2] rtc: efi: defer to the ACPI TAD if it can drive the RTC
2026-10-27 22:05 [PATCH v4 0/2] rtc: efi: defer to the ACPI TAD if it can drive the RTC Hamza Mahfooz
2026-10-27 22:05 ` [PATCH v4 1/2] ACPI: TAD: introduce acpi_has_rtc() Hamza Mahfooz
@ 2026-10-27 22:05 ` Hamza Mahfooz
2026-10-27 22:10 ` sashiko-bot
1 sibling, 1 reply; 5+ messages in thread
From: Hamza Mahfooz @ 2026-10-27 22:05 UTC (permalink / raw)
To: linux-acpi, linux-rtc
Cc: Rafael J. Wysocki, Len Brown, Alexandre Belloni, Ard Biesheuvel,
Hamza Mahfooz
EFI runtime services are best avoided where possible, and ACPI defines a
standard interface to the RTC in the form of the Time and Alarm Device
(TAD), which the acpi-tad driver has been exposing as an RTC class
device since commit 8a1e7f4b1764 ("ACPI: TAD: Add RTC class device
interface").
So, make rtc-efi decline to probe, before calling GetTime(), if
acpi_has_rtc() says that the RTC can be driven via the TAD.
Also, to ensure that acpi_has_rtc() is always reachable from rtc-efi
when ACPI_TAD is enabled, make RTC_DRV_EFI depend on
ACPI_TAD || !ACPI_TAD.
Suggested-by: Ard Biesheuvel <ardb@kernel.org>
Reviewed-by: Ard Biesheuvel <ardb@kernel.org>
Signed-off-by: Hamza Mahfooz <hamzamahfooz@linux.microsoft.com>
---
drivers/rtc/Kconfig | 5 +++++
drivers/rtc/rtc-efi.c | 4 ++++
2 files changed, 9 insertions(+)
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 1e863f1d3..5b7e9d2a8 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -1262,10 +1262,15 @@ config RTC_DRV_DA9063
config RTC_DRV_EFI
tristate "EFI RTC"
depends on EFI && !X86
+ depends on ACPI_TAD || !ACPI_TAD
help
If you say yes here you will get support for the EFI
Real Time Clock.
+ On ACPI systems, the ACPI Time and Alarm Device (TAD) driver
+ is used instead of this one if the TAD can drive the RTC (assuming
+ it's enabled).
+
This driver can also be built as a module. If so, the module
will be called rtc-efi.
diff --git a/drivers/rtc/rtc-efi.c b/drivers/rtc/rtc-efi.c
index b4f44999e..545b21b17 100644
--- a/drivers/rtc/rtc-efi.c
+++ b/drivers/rtc/rtc-efi.c
@@ -10,6 +10,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <linux/acpi.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/stringify.h>
@@ -192,6 +193,9 @@ static int __init efi_rtc_probe(struct platform_device *dev)
efi_time_t eft;
efi_time_cap_t cap;
+ if (acpi_has_rtc())
+ return -ENODEV;
+
/* First check if the RTC is usable */
if (efi.get_time(&eft, &cap) != EFI_SUCCESS)
return -ENODEV;
--
2.56.0
^ permalink raw reply related [flat|nested] 5+ messages in thread