diff options
Diffstat (limited to 'drivers/thermal/intel/therm_throt.c')
| -rw-r--r-- | drivers/thermal/intel/therm_throt.c | 73 | 
1 files changed, 66 insertions, 7 deletions
diff --git a/drivers/thermal/intel/therm_throt.c b/drivers/thermal/intel/therm_throt.c index 2e22bb82b738..e69868e868eb 100644 --- a/drivers/thermal/intel/therm_throt.c +++ b/drivers/thermal/intel/therm_throt.c @@ -193,8 +193,67 @@ static const struct attribute_group thermal_attr_group = {  #define THERM_THROT_POLL_INTERVAL	HZ  #define THERM_STATUS_PROCHOT_LOG	BIT(1) -#define THERM_STATUS_CLEAR_CORE_MASK (BIT(1) | BIT(3) | BIT(5) | BIT(7) | BIT(9) | BIT(11) | BIT(13) | BIT(15)) -#define THERM_STATUS_CLEAR_PKG_MASK  (BIT(1) | BIT(3) | BIT(5) | BIT(7) | BIT(9) | BIT(11)) +static u64 therm_intr_core_clear_mask; +static u64 therm_intr_pkg_clear_mask; + +static void thermal_intr_init_core_clear_mask(void) +{ +	if (therm_intr_core_clear_mask) +		return; + +	/* +	 * Reference: Intel SDM  Volume 4 +	 * "Table 2-2. IA-32 Architectural MSRs", MSR 0x19C +	 * IA32_THERM_STATUS. +	 */ + +	/* +	 * Bit 1, 3, 5: CPUID.01H:EDX[22] = 1. This driver will not +	 * enable interrupts, when 0 as it checks for X86_FEATURE_ACPI. +	 */ +	therm_intr_core_clear_mask = (BIT(1) | BIT(3) | BIT(5)); + +	/* +	 * Bit 7 and 9: Thermal Threshold #1 and #2 log +	 * If CPUID.01H:ECX[8] = 1 +	 */ +	if (boot_cpu_has(X86_FEATURE_TM2)) +		therm_intr_core_clear_mask |= (BIT(7) | BIT(9)); + +	/* Bit 11: Power Limitation log (R/WC0) If CPUID.06H:EAX[4] = 1 */ +	if (boot_cpu_has(X86_FEATURE_PLN)) +		therm_intr_core_clear_mask |= BIT(11); + +	/* +	 * Bit 13: Current Limit log (R/WC0) If CPUID.06H:EAX[7] = 1 +	 * Bit 15: Cross Domain Limit log (R/WC0) If CPUID.06H:EAX[7] = 1 +	 */ +	if (boot_cpu_has(X86_FEATURE_HWP)) +		therm_intr_core_clear_mask |= (BIT(13) | BIT(15)); +} + +static void thermal_intr_init_pkg_clear_mask(void) +{ +	if (therm_intr_pkg_clear_mask) +		return; + +	/* +	 * Reference: Intel SDM  Volume 4 +	 * "Table 2-2. IA-32 Architectural MSRs", MSR 0x1B1 +	 * IA32_PACKAGE_THERM_STATUS. +	 */ + +	/* All bits except BIT 26 depend on CPUID.06H: EAX[6] = 1 */ +	if (boot_cpu_has(X86_FEATURE_PTS)) +		therm_intr_pkg_clear_mask = (BIT(1) | BIT(3) | BIT(5) | BIT(7) | BIT(9) | BIT(11)); + +	/* +	 * Intel SDM Volume 2A: Thermal and Power Management Leaf +	 * Bit 26: CPUID.06H: EAX[19] = 1 +	 */ +	if (boot_cpu_has(X86_FEATURE_HFI)) +		therm_intr_pkg_clear_mask |= BIT(26); +}  /*   * Clear the bits in package thermal status register for bit = 1 @@ -207,13 +266,10 @@ void thermal_clear_package_intr_status(int level, u64 bit_mask)  	if (level == CORE_LEVEL) {  		msr  = MSR_IA32_THERM_STATUS; -		msr_val = THERM_STATUS_CLEAR_CORE_MASK; +		msr_val = therm_intr_core_clear_mask;  	} else {  		msr  = MSR_IA32_PACKAGE_THERM_STATUS; -		msr_val = THERM_STATUS_CLEAR_PKG_MASK; -		if (boot_cpu_has(X86_FEATURE_HFI)) -			msr_val |= BIT(26); - +		msr_val = therm_intr_pkg_clear_mask;  	}  	msr_val &= ~bit_mask; @@ -708,6 +764,9 @@ void intel_init_thermal(struct cpuinfo_x86 *c)  	h = THERMAL_APIC_VECTOR | APIC_DM_FIXED | APIC_LVT_MASKED;  	apic_write(APIC_LVTTHMR, h); +	thermal_intr_init_core_clear_mask(); +	thermal_intr_init_pkg_clear_mask(); +  	rdmsr(MSR_IA32_THERM_INTERRUPT, l, h);  	if (cpu_has(c, X86_FEATURE_PLN) && !int_pln_enable)  		wrmsr(MSR_IA32_THERM_INTERRUPT,  |