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);