Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 24 Jul 2026 04:35:08 +0000
From:      Olivier Certner <olce@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org
Cc:        Koine Yuusuke <koinec@yahoo.co.jp>
Subject:   git: 272c6a3c0af4 - stable/15 - x86/local_apic.c: Add support for installing a thermal interrupt handler
Message-ID:  <6a62eb7c.39f67.75edd18f@gitrepo.freebsd.org>

index | next in thread | raw e-mail

The branch stable/15 has been updated by olce:

URL: https://cgit.FreeBSD.org/src/commit/?id=272c6a3c0af4df9a9f7a94c7000bf7f2e6ce5e0e

commit 272c6a3c0af4df9a9f7a94c7000bf7f2e6ce5e0e
Author:     Koine Yuusuke <koinec@yahoo.co.jp>
AuthorDate: 2026-07-01 15:28:21 +0000
Commit:     Olivier Certner <olce@FreeBSD.org>
CommitDate: 2026-07-24 04:33:37 +0000

    x86/local_apic.c: Add support for installing a thermal interrupt handler
    
    The thermal interrupt is initially masked.
    
    Thermal interrupt handling is enabled by calling lapic_enable_thermal(),
    which installs a (single) handler.
    
    [olce: Wrote the commit message.]
    
    Reviewed by:    kib, olce
    MFC after:      2 weeks
    Differential Revision:  https://reviews.freebsd.org/D44454
    
    (cherry picked from commit 87ba088fa3108dd180008a04f25760ec71476c87)
---
 sys/amd64/amd64/apic_vector.S |  9 ++++++
 sys/x86/include/apicvar.h     | 12 ++++---
 sys/x86/x86/local_apic.c      | 74 +++++++++++++++++++++++++++++++++++++++++--
 3 files changed, 89 insertions(+), 6 deletions(-)

diff --git a/sys/amd64/amd64/apic_vector.S b/sys/amd64/amd64/apic_vector.S
index d3ff3c238b48..806e59f1d001 100644
--- a/sys/amd64/amd64/apic_vector.S
+++ b/sys/amd64/amd64/apic_vector.S
@@ -144,6 +144,15 @@ IDTVEC(spuriousint)
 	KMSAN_LEAVE
 	jmp	doreti
 
+/*
+ * Local APIC thermal interrupt handler.
+ */
+	INTR_HANDLER thermalint
+	KMSAN_ENTER
+	call	lapic_handle_thermal
+	KMSAN_LEAVE
+	jmp	doreti
+
 #ifdef XENHVM
 /*
  * Xen event channel upcall interrupt handler.
diff --git a/sys/x86/include/apicvar.h b/sys/x86/include/apicvar.h
index b905aee6a8ed..cf76977c959b 100644
--- a/sys/x86/include/apicvar.h
+++ b/sys/x86/include/apicvar.h
@@ -184,12 +184,12 @@ struct apic_enumerator {
 inthand_t
 	IDTVEC(apic_isr1), IDTVEC(apic_isr2), IDTVEC(apic_isr3),
 	IDTVEC(apic_isr4), IDTVEC(apic_isr5), IDTVEC(apic_isr6),
-	IDTVEC(apic_isr7), IDTVEC(cmcint), IDTVEC(errorint),
-	IDTVEC(spuriousint), IDTVEC(timerint),
+	IDTVEC(apic_isr7), IDTVEC(cmcint), IDTVEC(thermalint),
+	IDTVEC(errorint), IDTVEC(spuriousint), IDTVEC(timerint),
 	IDTVEC(apic_isr1_pti), IDTVEC(apic_isr2_pti), IDTVEC(apic_isr3_pti),
 	IDTVEC(apic_isr4_pti), IDTVEC(apic_isr5_pti), IDTVEC(apic_isr6_pti),
-	IDTVEC(apic_isr7_pti), IDTVEC(cmcint_pti), IDTVEC(errorint_pti),
-	IDTVEC(spuriousint_pti), IDTVEC(timerint_pti);
+	IDTVEC(apic_isr7_pti), IDTVEC(cmcint_pti), IDTVEC(thermalint_pti),
+	IDTVEC(errorint_pti), IDTVEC(spuriousint_pti), IDTVEC(timerint_pti);
 
 extern vm_paddr_t lapic_paddr;
 extern int *apic_cpuids;
@@ -198,6 +198,7 @@ extern int *apic_cpuids;
 extern void (*ipi_vectored)(u_int, int);
 
 typedef struct ioapic *ioapic_drv_t;
+typedef void (*lapic_thermal_handle_function)(int, void *);
 
 void	apic_register_enumerator(struct apic_enumerator *enumerator);
 ioapic_drv_t	ioapic_create(vm_paddr_t addr, int32_t apic_id, int intbase);
@@ -232,6 +233,8 @@ void	apic_enable_vector(u_int apic_id, u_int vector);
 void	apic_disable_vector(u_int apic_id, u_int vector);
 void	apic_free_vector(u_int apic_id, u_int vector, u_int irq);
 void	lapic_calibrate_timer(void);
+void	lapic_enable_thermal(lapic_thermal_handle_function thermfunc, void *value);
+void	lapic_disable_thermal(void);
 int	lapic_enable_pcint(void);
 void	lapic_disable_pcint(void);
 void	lapic_reenable_pcint(void);
@@ -256,6 +259,7 @@ int	lapic_set_lvt_polarity(u_int apic_id, u_int lvt,
 int	lapic_set_lvt_triggermode(u_int apic_id, u_int lvt,
 	    enum intr_trigger trigger);
 void	lapic_handle_cmc(void);
+void	lapic_handle_thermal(void);
 void	lapic_handle_error(void);
 void	lapic_handle_intr(int vector, struct trapframe *frame);
 void	lapic_handle_timer(struct trapframe *frame);
diff --git a/sys/x86/x86/local_apic.c b/sys/x86/x86/local_apic.c
index c7a967067e0d..f8810907127a 100644
--- a/sys/x86/x86/local_apic.c
+++ b/sys/x86/x86/local_apic.c
@@ -60,6 +60,7 @@
 #include <vm/pmap.h>
 
 #include <x86/apicreg.h>
+#include <machine/atomic.h>
 #include <machine/clock.h>
 #include <machine/cpufunc.h>
 #include <machine/cputypes.h>
@@ -313,6 +314,8 @@ static uint64_t lapic_ipi_wait_mult;
 static int __read_mostly lapic_ds_idle_timeout = 1000000;
 #endif
 unsigned int max_apic_id;
+static void *lapic_thermal_function_value;
+static lapic_thermal_handle_function lapic_thermal_function_ptr;
 static int pcint_refcnt = 0;
 
 SYSCTL_NODE(_hw, OID_AUTO, apic, CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
@@ -593,7 +596,9 @@ lapic_init(vm_paddr_t addr)
 	setidt(APIC_ERROR_INT, pti ? IDTVEC(errorint_pti) : IDTVEC(errorint),
 	    SDT_APIC, SEL_KPL, GSEL_APIC);
 
-	/* XXX: Thermal interrupt */
+	/* Thermal interrupt */
+	setidt(APIC_THERMAL_INT, pti ? IDTVEC(thermalint_pti) : IDTVEC(thermalint),
+	    SDT_APIC, SEL_KPL, GSEL_APIC);
 
 	/* Local APIC CMCI. */
 	setidt(APIC_CMC_INT, pti ? IDTVEC(cmcint_pti) : IDTVEC(cmcint),
@@ -920,7 +925,9 @@ lapic_setup(int boot)
 	    lapic_read32(LAPIC_LVT_ERROR)));
 	lapic_write32(LAPIC_ESR, 0);
 
-	/* XXX: Thermal LVT */
+	/* Thermal LVT */
+	lapic_write32(LAPIC_LVT_THERMAL, lvt_mode(la, APIC_LVT_THERMAL,
+	    lapic_read32(LAPIC_LVT_THERMAL)));
 
 	/* Program the CMCI LVT entry if present. */
 	if (maxlvt >= APIC_LVT_CMCI) {
@@ -1613,6 +1620,69 @@ lapic_enable_mca_elvt(void)
 	return (APIC_ELVT_MCA);
 }
 
+void
+lapic_handle_thermal(void)
+{
+	lapic_thermal_handle_function func;
+
+	func = (lapic_thermal_handle_function)atomic_load_acq_ptr(
+	    (void *)&lapic_thermal_function_ptr);
+
+	if (func != NULL)
+		func(PCPU_GET(cpuid), lapic_thermal_function_value);
+
+	lapic_eoi();
+}
+
+static void
+lapic_update_thermal(void *dummy __unused)
+{
+	struct lapic *la;
+
+	la = &lapics[lapic_id()];
+	lapic_write32(LAPIC_LVT_THERMAL, lvt_mode(la, APIC_LVT_THERMAL,
+	    lapic_read32(LAPIC_LVT_THERMAL)));
+}
+
+void
+lapic_enable_thermal(lapic_thermal_handle_function thermfunc, void *value)
+{
+#ifdef DEV_ATPIC
+	/* Fail if the local APIC is not present. */
+	if (!x2apic_mode && lapic_map == NULL)
+		return;
+#endif
+
+	lapic_thermal_function_value = value;
+	atomic_store_rel_ptr((uintptr_t *)&lapic_thermal_function_ptr,
+	    (uintptr_t)thermfunc);
+
+	lvts[APIC_LVT_THERMAL].lvt_masked = 0;
+
+	MPASS(mp_ncpus == 1 || smp_started);
+	smp_rendezvous(NULL, lapic_update_thermal, NULL, NULL);
+}
+
+void
+lapic_disable_thermal(void)
+{
+#ifdef DEV_ATPIC
+	/* Fail if the local APIC is not present. */
+	if (!x2apic_mode && lapic_map == NULL)
+		return;
+#endif
+
+	lvts[APIC_LVT_THERMAL].lvt_masked = 1;
+
+#ifdef SMP
+	KASSERT(mp_ncpus == 1 || smp_started, ("thermal driver unloaded too early"));
+#endif
+	smp_rendezvous(NULL, lapic_update_thermal, NULL, NULL);
+
+	atomic_store_rel_ptr((uintptr_t *)&lapic_thermal_function_ptr,
+	    (uintptr_t)NULL);
+}
+
 void
 lapic_handle_error(void)
 {


home | help

Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?6a62eb7c.39f67.75edd18f>