Re: [PATCH v3 10/16] x86/virt/tdx: Drop the outdated requirement that TDX be enabled in IRQ context

From: Sean Christopherson

Date: Tue Feb 17 2026 - 10:25:34 EST


On Tue, Feb 17, 2026, Kai Huang wrote:
> On Fri, 2026-02-13 at 17:26 -0800, Sean Christopherson wrote:
> > Remove TDX's outdated requirement that per-CPU enabling be done via IPI
> > function call, which was a stale artifact leftover from early versions of
> > the TDX enablement series. The requirement that IRQs be disabled should
> > have been dropped as part of the revamped series that relied on a the KVM
> > rework to enable VMX at module load.
> >
> > In other words, the kernel's "requirement" was never a requirement at all,
> > but instead a reflection of how KVM enabled VMX (via IPI callback) when
> > the TDX subsystem code was merged.
> >
> > Note, accessing per-CPU information is safe even without disabling IRQs,
> > as tdx_online_cpu() is invoked via a cpuhp callback, i.e. from a per-CPU
> > thread.
> >
> > Link: https://lore.kernel.org/all/ZyJOiPQnBz31qLZ7@xxxxxxxxxx
> > Signed-off-by: Sean Christopherson <seanjc@xxxxxxxxxx>
> >
>
> Hi Sean,
>
> The first call of tdx_cpu_enable() will also call into
> try_init_module_global() (in order to do TDH_SYS_INIT), which also has a
> lockdep_assert_irqs_disabled() + a raw spinlock to make sure TDH_SYS_INIT is
> only called once when tdx_cpu_enable() are called from IRQ disabled context.
>
> This patch only changes tdx_cpu_enable() but doesn't change
> try_init_module_global(), thus the first call of tdx_cpu_enable() will still
> trigger the lockdep_assert_irqs_disabled() failure warning.
>
> I've tried this series on my local and I did see such WARNING during
> boot[*]. We need to fix that too.
>
> But hmm, Chao's "Runtime TDX module update" series actually needs to call
> tdx_cpu_enable() when IRQ disabled, IIUC, since it is called via
> stop_machine_cpuslocked():
>
> https://lore.kernel.org/kvm/20260212143606.534586-18-chao.gao@xxxxxxxxx/
>
> Maybe we can just keep tdx_cpu_enabled() as-is?

Can't we simply delete the lockdep assert there as well? It should be totally
fine to have a function that can be called from task or IRQ context, so long as
the function is prepared for that possibility. I.e. just because it _can_ be
called from IRQ context doesn't mean it _must_ be called from IRQ context.

E.g. as a fixup

diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c
index bdee937b84d4..f8f5e046159b 100644
--- a/arch/x86/virt/vmx/tdx/tdx.c
+++ b/arch/x86/virt/vmx/tdx/tdx.c
@@ -106,8 +106,7 @@ static __always_inline int sc_retry_prerr(sc_func_t func,

/*
* Do the module global initialization once and return its result.
- * It can be done on any cpu. It's always called with interrupts
- * disabled.
+ * It can be done on any cpu, and from task or IRQ context.
*/
static int try_init_module_global(void)
{
@@ -116,8 +115,6 @@ static int try_init_module_global(void)
static bool sysinit_done;
static int sysinit_ret;

- lockdep_assert_irqs_disabled();
-
raw_spin_lock(&sysinit_lock);

if (sysinit_done)