diff options
Diffstat (limited to 'drivers/thermal')
-rw-r--r-- | drivers/thermal/intel/intel_hfi.c | 22 |
1 files changed, 17 insertions, 5 deletions
diff --git a/drivers/thermal/intel/intel_hfi.c b/drivers/thermal/intel/intel_hfi.c index 65b902939e1f..90a11eef44f7 100644 --- a/drivers/thermal/intel/intel_hfi.c +++ b/drivers/thermal/intel/intel_hfi.c @@ -250,7 +250,7 @@ void intel_hfi_process_event(__u64 pkg_therm_status_msr_val) struct hfi_instance *hfi_instance; int cpu = smp_processor_id(); struct hfi_cpu_info *info; - u64 new_timestamp; + u64 new_timestamp, msr, hfi; if (!pkg_therm_status_msr_val) return; @@ -279,9 +279,21 @@ void intel_hfi_process_event(__u64 pkg_therm_status_msr_val) if (!raw_spin_trylock(&hfi_instance->event_lock)) return; - /* Skip duplicated updates. */ + rdmsrl(MSR_IA32_PACKAGE_THERM_STATUS, msr); + hfi = msr & PACKAGE_THERM_STATUS_HFI_UPDATED; + if (!hfi) { + raw_spin_unlock(&hfi_instance->event_lock); + return; + } + + /* + * Ack duplicate update. Since there is an active HFI + * status from HW, it must be a new event, not a case + * where a lagging CPU entered the locked region. + */ new_timestamp = *(u64 *)hfi_instance->hw_table; if (*hfi_instance->timestamp == new_timestamp) { + thermal_clear_package_intr_status(PACKAGE_LEVEL, PACKAGE_THERM_STATUS_HFI_UPDATED); raw_spin_unlock(&hfi_instance->event_lock); return; } @@ -295,15 +307,15 @@ void intel_hfi_process_event(__u64 pkg_therm_status_msr_val) memcpy(hfi_instance->local_table, hfi_instance->hw_table, hfi_features.nr_table_pages << PAGE_SHIFT); - raw_spin_unlock(&hfi_instance->table_lock); - raw_spin_unlock(&hfi_instance->event_lock); - /* * Let hardware know that we are done reading the HFI table and it is * free to update it again. */ thermal_clear_package_intr_status(PACKAGE_LEVEL, PACKAGE_THERM_STATUS_HFI_UPDATED); + raw_spin_unlock(&hfi_instance->table_lock); + raw_spin_unlock(&hfi_instance->event_lock); + queue_delayed_work(hfi_updates_wq, &hfi_instance->update_work, HFI_UPDATE_INTERVAL); } |