git: c18ec05395b3 - main - x86/local_apic.c: Fiddle with thermal LVT slot only if supported

From: Olivier Certner <olce_at_FreeBSD.org>
Date: Fri, 10 Jul 2026 15:30:39 UTC
The branch main has been updated by olce:

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

commit c18ec05395b36bdd12b0129533a553f27eb9b067
Author:     Olivier Certner <olce@FreeBSD.org>
AuthorDate: 2026-07-02 14:26:21 +0000
Commit:     Olivier Certner <olce@FreeBSD.org>
CommitDate: 2026-07-10 15:29:49 +0000

    x86/local_apic.c: Fiddle with thermal LVT slot only if supported
    
    The thermal LVT slot does not necessarily exist.
    
    According to Intel's Software Developers Manual, for Intel processors
    supporting 64-bit operation (amd64), probably even the earliest ones
    should have a local APIC with such a slot (the slot was introduced with
    Pentium 4 and Xeon processors according to the manual, and the 64-bit
    implementation in some later versions of them).  AMD's Architecture
    Programmer's Manual also seems to imply that all AMD processors
    supporting amd64 should have the slot too.  So this change may not be
    needed when i386's code is dropped, but it does not hurt to have it, and
    it might ease possible MFCs.
    
    Change the signature of lapic_enable_thermal() so that it can report
    failure (if there is no local APIC or if there is no thermal LVT slot).
    
    Reviewed by:    bnovkov, kib
    MFC after:      2 weeks
    Sponsored by:   The FreeBSD Foundation
    Differential Revision:  https://reviews.freebsd.org/D58086
---
 sys/x86/include/apicvar.h |  2 +-
 sys/x86/x86/local_apic.c  | 22 ++++++++++++++++------
 2 files changed, 17 insertions(+), 7 deletions(-)

diff --git a/sys/x86/include/apicvar.h b/sys/x86/include/apicvar.h
index 54ea5bc655e5..10dbc50a981b 100644
--- a/sys/x86/include/apicvar.h
+++ b/sys/x86/include/apicvar.h
@@ -236,7 +236,7 @@ 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_handler_t *func, void *func_arg);
+bool	lapic_enable_thermal(lapic_thermal_handler_t *func, void *func_arg);
 void	lapic_disable_thermal(void);
 int	lapic_enable_pcint(void);
 void	lapic_disable_pcint(void);
diff --git a/sys/x86/x86/local_apic.c b/sys/x86/x86/local_apic.c
index 73ddf9115e4c..aceb9a229c4f 100644
--- a/sys/x86/x86/local_apic.c
+++ b/sys/x86/x86/local_apic.c
@@ -807,9 +807,10 @@ lapic_dump(const char* str)
 	printf("\n  lint0: 0x%08x lint1: 0x%08x TPR: 0x%08x SVR: 0x%08x\n",
 	    lapic_read32(LAPIC_LVT_LINT0), lapic_read32(LAPIC_LVT_LINT1),
 	    lapic_read32(LAPIC_TPR), lapic_read32(LAPIC_SVR));
-	printf("  timer: 0x%08x therm: 0x%08x err: 0x%08x",
-	    lapic_read32(LAPIC_LVT_TIMER), lapic_read32(LAPIC_LVT_THERMAL),
+	printf("  timer: 0x%08x err: 0x%08x", lapic_read32(LAPIC_LVT_TIMER),
 	    lapic_read32(LAPIC_LVT_ERROR));
+	if (maxlvt >= APIC_LVT_THERMAL)
+		printf(" therm: 0x%08x", lapic_read32(LAPIC_LVT_THERMAL));
 	if (maxlvt >= APIC_LVT_PMC)
 		printf(" pmc: 0x%08x", lapic_read32(LAPIC_LVT_PCINT));
 	printf("\n");
@@ -935,8 +936,9 @@ lapic_setup(int boot)
 	lapic_write32(LAPIC_ESR, 0);
 
 	/* Thermal LVT */
-	lapic_write32(LAPIC_LVT_THERMAL, lvt_mode(la, APIC_LVT_THERMAL,
-	    lapic_read32(LAPIC_LVT_THERMAL)));
+	if (maxlvt >= APIC_LVT_THERMAL)
+		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) {
@@ -1663,15 +1665,18 @@ lapic_update_thermal(void *dummy __unused)
 	    lapic_read32(LAPIC_LVT_THERMAL)));
 }
 
-void
+bool
 lapic_enable_thermal(lapic_thermal_handler_t *func, void *func_arg)
 {
 #ifdef DEV_ATPIC
 	/* Fail if the local APIC is not present. */
 	if (!x2apic_mode && lapic_map == NULL)
-		return;
+		return (false);
 #endif
 
+	if (lapic_maxlvt() < APIC_LVT_THERMAL)
+		return (false);
+
 	lapic_thermal_function_arg = func_arg;
 	atomic_store_rel_ptr((uintptr_t *)&lapic_thermal_function,
 	    (uintptr_t)func);
@@ -1680,6 +1685,8 @@ lapic_enable_thermal(lapic_thermal_handler_t *func, void *func_arg)
 
 	MPASS(mp_ncpus == 1 || smp_started);
 	smp_rendezvous(NULL, lapic_update_thermal, NULL, NULL);
+
+	return (true);
 }
 
 void
@@ -1691,6 +1698,9 @@ lapic_disable_thermal(void)
 		return;
 #endif
 
+	if (lapic_maxlvt() < APIC_LVT_THERMAL)
+		return;
+
 	lvts[APIC_LVT_THERMAL].lvt_masked = 1;
 
 #ifdef SMP