Skip to content

Commit 930d06b

Browse files
spandruvadarafaeljw
authored andcommitted
thermal: intel: Protect clearing of thermal status bits
The clearing of the package thermal status is done by Read-Modify-Write operation. This may result in clearing of some new status bits which are being or about to be processed. For example, while clearing of HFI status, after read of thermal status register, a new thermal status bit is set by the hardware. But during write back, the newly generated status bit will be set to 0 or cleared. So, it is not safe to do read-modify-write. Since thermal status Read-Write bits can be set to only 0 not 1, it is safe to set all other bits to 1 which are not getting cleared. Create a common interface for clearing package thermal status bits. Use this interface to replace existing code to clear thermal package status bits. It is safe to call from different CPUs without protection as there is no read-modify-write. Also wrmsrl results in just single instruction. For example while CPU 0 and CPU 3 are clearing bit 1 and 3 respectively. If CPU 3 wins the race, it will write 0x4000aa2, then CPU 1 will write 0x4000aa8. The bits which are not part of clear are set to 1. The default mask for bits, which can be written here is 0x4000aaa. Signed-off-by: Srinivas Pandruvada <[email protected]> Reviewed-by: Ricardo Neri <[email protected]> Signed-off-by: Rafael J. Wysocki <[email protected]>
1 parent 6fe1e64 commit 930d06b

File tree

4 files changed

+22
-24
lines changed

4 files changed

+22
-24
lines changed

drivers/thermal/intel/intel_hfi.c

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,7 @@
4242

4343
#include "../thermal_core.h"
4444
#include "intel_hfi.h"
45-
46-
#define THERM_STATUS_CLEAR_PKG_MASK (BIT(1) | BIT(3) | BIT(5) | BIT(7) | \
47-
BIT(9) | BIT(11) | BIT(26))
45+
#include "thermal_interrupt.h"
4846

4947
/* Hardware Feedback Interface MSR configuration bits */
5048
#define HW_FEEDBACK_PTR_VALID_BIT BIT(0)
@@ -304,9 +302,7 @@ void intel_hfi_process_event(__u64 pkg_therm_status_msr_val)
304302
* Let hardware know that we are done reading the HFI table and it is
305303
* free to update it again.
306304
*/
307-
pkg_therm_status_msr_val &= THERM_STATUS_CLEAR_PKG_MASK &
308-
~PACKAGE_THERM_STATUS_HFI_UPDATED;
309-
wrmsrl(MSR_IA32_PACKAGE_THERM_STATUS, pkg_therm_status_msr_val);
305+
thermal_clear_package_intr_status(PACKAGE_LEVEL, PACKAGE_THERM_STATUS_HFI_UPDATED);
310306

311307
queue_delayed_work(hfi_updates_wq, &hfi_instance->update_work,
312308
HFI_UPDATE_INTERVAL);

drivers/thermal/intel/therm_throt.c

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -190,32 +190,33 @@ static const struct attribute_group thermal_attr_group = {
190190
};
191191
#endif /* CONFIG_SYSFS */
192192

193-
#define CORE_LEVEL 0
194-
#define PACKAGE_LEVEL 1
195-
196193
#define THERM_THROT_POLL_INTERVAL HZ
197194
#define THERM_STATUS_PROCHOT_LOG BIT(1)
198195

199196
#define THERM_STATUS_CLEAR_CORE_MASK (BIT(1) | BIT(3) | BIT(5) | BIT(7) | BIT(9) | BIT(11) | BIT(13) | BIT(15))
200197
#define THERM_STATUS_CLEAR_PKG_MASK (BIT(1) | BIT(3) | BIT(5) | BIT(7) | BIT(9) | BIT(11) | BIT(26))
201198

202-
static void clear_therm_status_log(int level)
199+
/*
200+
* Clear the bits in package thermal status register for bit = 1
201+
* in bitmask
202+
*/
203+
void thermal_clear_package_intr_status(int level, u64 bit_mask)
203204
{
205+
u64 msr_val;
204206
int msr;
205-
u64 mask, msr_val;
206207

207208
if (level == CORE_LEVEL) {
208209
msr = MSR_IA32_THERM_STATUS;
209-
mask = THERM_STATUS_CLEAR_CORE_MASK;
210+
msr_val = THERM_STATUS_CLEAR_CORE_MASK;
210211
} else {
211212
msr = MSR_IA32_PACKAGE_THERM_STATUS;
212-
mask = THERM_STATUS_CLEAR_PKG_MASK;
213+
msr_val = THERM_STATUS_CLEAR_PKG_MASK;
213214
}
214215

215-
rdmsrl(msr, msr_val);
216-
msr_val &= mask;
217-
wrmsrl(msr, msr_val & ~THERM_STATUS_PROCHOT_LOG);
216+
msr_val &= ~bit_mask;
217+
wrmsrl(msr, msr_val);
218218
}
219+
EXPORT_SYMBOL_GPL(thermal_clear_package_intr_status);
219220

220221
static void get_therm_status(int level, bool *proc_hot, u8 *temp)
221222
{
@@ -295,7 +296,7 @@ static void __maybe_unused throttle_active_work(struct work_struct *work)
295296
state->average = avg;
296297

297298
re_arm:
298-
clear_therm_status_log(state->level);
299+
thermal_clear_package_intr_status(state->level, THERM_STATUS_PROCHOT_LOG);
299300
schedule_delayed_work_on(this_cpu, &state->therm_work, THERM_THROT_POLL_INTERVAL);
300301
}
301302

drivers/thermal/intel/thermal_interrupt.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
#ifndef _INTEL_THERMAL_INTERRUPT_H
33
#define _INTEL_THERMAL_INTERRUPT_H
44

5+
#define CORE_LEVEL 0
6+
#define PACKAGE_LEVEL 1
7+
58
/* Interrupt Handler for package thermal thresholds */
69
extern int (*platform_thermal_package_notify)(__u64 msr_val);
710

@@ -15,4 +18,7 @@ extern bool (*platform_thermal_package_rate_control)(void);
1518
/* Handle HWP interrupt */
1619
extern void notify_hwp_interrupt(void);
1720

21+
/* Common function to clear Package thermal status register */
22+
extern void thermal_clear_package_intr_status(int level, u64 bit_mask);
23+
1824
#endif /* _INTEL_THERMAL_INTERRUPT_H */

drivers/thermal/intel/x86_pkg_temp_thermal.c

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,6 @@ static void pkg_temp_thermal_threshold_work_fn(struct work_struct *work)
265265
struct thermal_zone_device *tzone = NULL;
266266
int cpu = smp_processor_id();
267267
struct zone_device *zonedev;
268-
u64 msr_val, wr_val;
269268

270269
mutex_lock(&thermal_zone_mutex);
271270
raw_spin_lock_irq(&pkg_temp_lock);
@@ -279,12 +278,8 @@ static void pkg_temp_thermal_threshold_work_fn(struct work_struct *work)
279278
}
280279
zonedev->work_scheduled = false;
281280

282-
rdmsrl(MSR_IA32_PACKAGE_THERM_STATUS, msr_val);
283-
wr_val = msr_val & ~(THERM_LOG_THRESHOLD0 | THERM_LOG_THRESHOLD1);
284-
if (wr_val != msr_val) {
285-
wrmsrl(MSR_IA32_PACKAGE_THERM_STATUS, wr_val);
286-
tzone = zonedev->tzone;
287-
}
281+
thermal_clear_package_intr_status(PACKAGE_LEVEL, THERM_LOG_THRESHOLD0 | THERM_LOG_THRESHOLD1);
282+
tzone = zonedev->tzone;
288283

289284
enable_pkg_thres_interrupt();
290285
raw_spin_unlock_irq(&pkg_temp_lock);

0 commit comments

Comments
 (0)