From: tirthendu.sarkar@intel.com
To: Thomas Gleixner <tglx@linutronix.de>,
Ingo Molnar <mingo@redhat.com>, Borislav Petkov <bp@alien8.de>,
Dave Hansen <dave.hansen@linux.intel.com>,
x86@kernel.org
Cc: "H . Peter Anvin" <hpa@zytor.com>,
Jonathan Corbet <corbet@lwn.net>,
Andy Shevchenko <andriy.shevchenko@intel.com>,
linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: [PATCH] x86/time: Enable HPET under ACPI hardware-reduced mode with hpet=force
Date: Mon, 5 Oct 2026 03:55:50 -0400 [thread overview]
Message-ID: <20261005075550.463089-1-tirthendu.sarkar@intel.com> (raw)
From: Tirthendu Sarkar <tirthendu.sarkar@intel.com>
ACPI hardware-reduced platforms unconditionally stub
x86_init.timers.timer_init() to a noop, on the assumption that such
platforms never provide legacy timer hardware. That is not universally
true: virtualized/embedded x86 platforms can declare hardware-reduced
mode while still enumerating a genuine HPET via the standard ACPI HPET
table. On those, HPET never gets a chance to initialize at all,
regardless of whether one is present.
"hpet=force" is the existing opt-in for forcing HPET on in unusual
situations, but today its effect is limited to a later PCI-quirk
address override and bypassing the PC10-damaged auto-disable; it does
not reach this earlier stubbing. Passing it on such a platform
silently does nothing.
Let "hpet=force" call hpet_enable() when .timer_init() was stubbed by
ACPI hardware-reduced mode. This has to happen in x86_late_time_init()
rather than at the stub site: that decision runs from setup_arch(),
while "hpet=" is a __setup() handler and so is not parsed until
parse_args(), further into start_kernel().
Only hpet_enable() is wanted here, not hpet_time_init(), which also
falls back to the PIT and requests the legacy timer interrupt. Neither
has hardware behind it on such a platform, and the fallback is not
merely inert: the PIT clockevent it registers as global_clock_event
never ticks, and calibrate_APIC_clock() cross-checks the APIC timer
against jiffies advancing via exactly that clockevent, so the APIC
timer is marked CLOCK_EVT_FEAT_DUMMY and disabled as well ("APIC timer
disabled due to verification failure"). Where the APIC timer was the
only usable clockevent, that is a boot hang.
This covers hardware-reduced platforms that install their own
.timer_init() rather than being stubbed, too. Intel MID points
x86_init.acpi.reduced_hw_early_init() at a noop, so
acpi_generic_reduced_hw_init() never runs there and .timer_init() keeps
pointing at intel_mid_time_init(), which sets up the local APIC timer
only and never touches the HPET - even though Tangier does have one at
0xfed00000. None of the platform .timer_init() implementations enable
the HPET themselves, so it cannot end up registered twice.
The ACPI hardware-reduced check is still required: without it,
"hpet=force" on an ordinary platform would call hpet_enable() a second
time after hpet_time_init() already did, registering the clocksource
twice. Hyper-V guests run hardware-reduced too, so the path is
reachable there as well, but only ever behind the explicit opt-in.
Nothing changes for non-hardware-reduced platforms, or for
hardware-reduced platforms booted without "hpet=force". With
"hpet=force" but no usable HPET, hpet_enable() fails and nothing else
happens, matching today's outcome.
Also document the new behaviour under "hpet=", and fix that entry's
stale "[X86-32,HPET]" tag.
Signed-off-by: Tirthendu Sarkar <tirthendu.sarkar@intel.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>
---
Tested under QEMU on a hardware-reduced platform with no HPET table, and
with an HPET table describing an HPET that does not come up; neither falls
through to the PIT. Also forced the Intel MID boot path under QEMU
(hardware_subarch = X86_SUBARCH_INTEL_MID), which exercises that code path
but not real Merrifield/Moorefield silicon. On a hardware-reduced platform
with a genuine HPET, the HPET initializes and is confirmed to drive
timekeeping.
.../admin-guide/kernel-parameters.txt | 8 +++++--
arch/x86/include/asm/hpet.h | 1 +
arch/x86/kernel/time.c | 22 ++++++++++++++++++-
3 files changed, 28 insertions(+), 3 deletions(-)
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index 68647ff4bdd24..2722c74eb5a57 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -2033,12 +2033,16 @@ Kernel parameters
not exceed the maximum allowed hostname length (usually
64 characters) and will be truncated otherwise.
- hpet= [X86-32,HPET] option to control HPET usage
+ hpet= [X86,HPET] option to control HPET usage
Format: { enable (default) | disable | force |
verbose }
disable: disable HPET and use PIT instead
force: allow force enabled of undocumented chips (ICH4,
- VIA, nVidia)
+ VIA, nVidia). Also attempts HPET initialization
+ on ACPI hardware-reduced platforms, which
+ otherwise skip legacy timer init entirely. The
+ legacy PIT is never used as a fallback there,
+ since such platforms do not provide one.
verbose: show contents of HPET registers during setup
hpet_mmap= [X86, HPET_MMAP] Allow userspace to mmap HPET
diff --git a/arch/x86/include/asm/hpet.h b/arch/x86/include/asm/hpet.h
index ab0c78855ecb2..4cb8f6d2e13dc 100644
--- a/arch/x86/include/asm/hpet.h
+++ b/arch/x86/include/asm/hpet.h
@@ -97,6 +97,7 @@ static inline int hpet_enable(void) { return 0; }
static inline int is_hpet_enabled(void) { return 0; }
#define hpet_readl(a) 0
#define default_setup_hpet_msi NULL
+#define hpet_force_user false
#endif
#endif /* _ASM_X86_HPET_H */
diff --git a/arch/x86/kernel/time.c b/arch/x86/kernel/time.c
index 4061430ac74c5..5184493689396 100644
--- a/arch/x86/kernel/time.c
+++ b/arch/x86/kernel/time.c
@@ -10,13 +10,14 @@
*
*/
+#include <linux/acpi.h>
#include <linux/clocksource.h>
#include <linux/clockchips.h>
+#include <linux/export.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/i8253.h>
#include <linux/time.h>
-#include <linux/export.h>
#include <asm/vsyscall.h>
#include <asm/x86_init.h>
@@ -72,6 +73,25 @@ static __init void x86_late_time_init(void)
*/
x86_init.irqs.intr_mode_select();
+ /*
+ * ACPI hardware-reduced mode unconditionally stubs .timer_init() to
+ * a noop, on the assumption that no legacy timer exists. Some such
+ * platforms do provide a real HPET, so let "hpet=force" give it a
+ * chance to come up. Only hpet_enable() is wanted here, not
+ * hpet_time_init(): its PIT fallback and legacy timer interrupt have
+ * no hardware behind them on such platforms, and registering a PIT
+ * clockevent whose interrupt can never be delivered also fails the
+ * local APIC timer's calibration cross-check, disabling that too.
+ *
+ * This also covers hardware-reduced platforms that install their own
+ * .timer_init() rather than being stubbed (e.g. Intel MID, which
+ * sets up the local APIC timer only). None of them enable the HPET
+ * themselves, so it cannot end up registered twice.
+ */
+ if (IS_ENABLED(CONFIG_HPET_TIMER) && acpi_reduced_hardware() &&
+ hpet_force_user)
+ hpet_enable();
+
/* Setup the legacy timers */
x86_init.timers.timer_init();
--
2.52.0
reply other threads:[~2026-10-05 7:55 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
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=20261005075550.463089-1-tirthendu.sarkar@intel.com \
--to=tirthendu.sarkar@intel.com \
--cc=andriy.shevchenko@intel.com \
--cc=bp@alien8.de \
--cc=corbet@lwn.net \
--cc=dave.hansen@linux.intel.com \
--cc=hpa@zytor.com \
--cc=linux-doc@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=mingo@redhat.com \
--cc=tglx@linutronix.de \
--cc=x86@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