From 1dc346e61e32457cc3bc2aafd1f34193228e65d6 Mon Sep 17 00:00:00 2001 From: Matt DeVillier Date: Wed, 25 Mar 2026 15:22:23 -0500 Subject: [PATCH] cpu/intel/haswell: Add option-backed PL1/PL2 overrides and package limit lock Add option variables to allow user override of PL1/PL2 via CMOS/CFR, which can be exposed by mainboards. Add the ability to lock the power levels set to prevent the OS/userspace tools from meddling. Add a CFR form for the lock option which mainboards can use. TEST=build/boot google/beltino with PL1/2 and lock options exposed, verify changes reflected in cbmem and by reading MSR/MCHBAR. Change-Id: I3db0a44c1e8982348026fa9e66123fd41a0f9884 Signed-off-by: Matt DeVillier Reviewed-on: https://review.coreboot.org/c/coreboot/+/91876 Reviewed-by: Angel Pons Tested-by: build bot (Jenkins) --- src/cpu/intel/haswell/cfr.h | 16 ++++++++++++++++ src/cpu/intel/haswell/haswell.h | 1 + src/cpu/intel/haswell/haswell_init.c | 24 ++++++++++++++++++++---- 3 files changed, 37 insertions(+), 4 deletions(-) create mode 100644 src/cpu/intel/haswell/cfr.h diff --git a/src/cpu/intel/haswell/cfr.h b/src/cpu/intel/haswell/cfr.h new file mode 100644 index 0000000000..2c92c1540a --- /dev/null +++ b/src/cpu/intel/haswell/cfr.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef _CPU_INTEL_HASWELL_CFR_H_ +#define _CPU_INTEL_HASWELL_CFR_H_ + +#include + +static const struct sm_object cpu_power_limit_lock = SM_DECLARE_BOOL({ + .opt_name = "cpu_power_limit_lock", + .ui_name = "CPU power limit lock", + .ui_helptext = "Lock CPU package power limits after programming.\n" + "This prevents the power limits from being changed by the OS or runtime tools.\n", + .default_value = false, +}); + +#endif /* _CPU_INTEL_HASWELL_CFR_H_ */ diff --git a/src/cpu/intel/haswell/haswell.h b/src/cpu/intel/haswell/haswell.h index b8cc98a570..946a3c71df 100644 --- a/src/cpu/intel/haswell/haswell.h +++ b/src/cpu/intel/haswell/haswell.h @@ -84,6 +84,7 @@ #define PKG_POWER_LIMIT_CLAMP (1 << 16) #define PKG_POWER_LIMIT_TIME_SHIFT 17 #define PKG_POWER_LIMIT_TIME_MASK 0x7f +#define PKG_POWER_LIMIT_LOCK (1U << 31) #define MSR_VR_CURRENT_CONFIG 0x601 #define MSR_VR_MISC_CONFIG 0x603 diff --git a/src/cpu/intel/haswell/haswell_init.c b/src/cpu/intel/haswell/haswell_init.c index 7d58795db0..11f8f1df9d 100644 --- a/src/cpu/intel/haswell/haswell_init.c +++ b/src/cpu/intel/haswell/haswell_init.c @@ -2,6 +2,7 @@ #include #include + #include #include #include @@ -12,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -260,6 +262,7 @@ void set_power_limits(u8 power_limit_1_time) msr_t limit; unsigned int power_unit; unsigned int tdp, min_power, max_power, max_time; + unsigned int pl1, pl2; u8 power_limit_1_val; if (power_limit_1_time >= ARRAY_SIZE(power_limit_time_sec_to_msr)) @@ -292,17 +295,30 @@ void set_power_limits(u8 power_limit_1_time) power_limit_1_val = power_limit_time_sec_to_msr[power_limit_1_time]; - /* Set long term power limit to TDP */ + const unsigned int pl1_override_w = get_uint_option("tdp_pl1_override", 0); + const unsigned int pl2_override_w = get_uint_option("tdp_pl2_override", 0); + + /* Set long term power limit to TDP if not overridden */ limit.lo = 0; - limit.lo |= tdp & PKG_POWER_LIMIT_MASK; + pl1 = pl1_override_w ? (pl1_override_w * power_unit) : tdp; + printk(BIOS_DEBUG, "CPU PL1 = %u Watts\n", pl1 / power_unit); + limit.lo |= pl1 & PKG_POWER_LIMIT_MASK; limit.lo |= PKG_POWER_LIMIT_EN; limit.lo |= (power_limit_1_val & PKG_POWER_LIMIT_TIME_MASK) << PKG_POWER_LIMIT_TIME_SHIFT; - /* Set short term power limit to 1.25 * TDP */ + /* Set short term power limit to 1.25 * TDP if not overridden */ limit.hi = 0; - limit.hi |= ((tdp * 125) / 100) & PKG_POWER_LIMIT_MASK; + pl2 = pl2_override_w ? (pl2_override_w * power_unit) : ((tdp * 125) / 100); + if (pl2 < pl1) + pl2 = pl1; + printk(BIOS_DEBUG, "CPU PL2 = %u Watts\n", pl2 / power_unit); + limit.hi |= pl2 & PKG_POWER_LIMIT_MASK; limit.hi |= PKG_POWER_LIMIT_EN; + if (get_uint_option("cpu_power_limit_lock", 0)) { + limit.hi |= PKG_POWER_LIMIT_LOCK; + printk(BIOS_DEBUG, "Locking package power limits\n"); + } /* Power limit 2 time is only programmable on server SKU */ wrmsr(MSR_PKG_POWER_LIMIT, limit);