Merge branch 'thermal-intel'

Merge changes in thermal control drivers for Intel platforms for
6.8-rc1:

 - Make the Intel HFI thermal driver enable an HFI instance (eg. processor
   package) from its first online CPU and disable it when the last CPU in
   it goes offline (Ricardo Neri).

* thermal-intel:
  thermal: intel: hfi: Disable an HFI instance when all its CPUs go offline
  thermal: intel: hfi: Enable an HFI instance from its first online CPU
  thermal: intel: hfi: Refactor enabling code into helper functions
This commit is contained in:
Rafael J. Wysocki 2024-01-05 13:34:15 +01:00
commit 17e8b76491
1 changed files with 65 additions and 26 deletions

View File

@ -24,6 +24,7 @@
#include <linux/bitops.h>
#include <linux/cpufeature.h>
#include <linux/cpumask.h>
#include <linux/delay.h>
#include <linux/gfp.h>
#include <linux/io.h>
#include <linux/kernel.h>
@ -347,6 +348,52 @@ static void init_hfi_instance(struct hfi_instance *hfi_instance)
hfi_instance->data = hfi_instance->hdr + hfi_features.hdr_size;
}
/* Caller must hold hfi_instance_lock. */
static void hfi_enable(void)
{
u64 msr_val;
rdmsrl(MSR_IA32_HW_FEEDBACK_CONFIG, msr_val);
msr_val |= HW_FEEDBACK_CONFIG_HFI_ENABLE_BIT;
wrmsrl(MSR_IA32_HW_FEEDBACK_CONFIG, msr_val);
}
static void hfi_set_hw_table(struct hfi_instance *hfi_instance)
{
phys_addr_t hw_table_pa;
u64 msr_val;
hw_table_pa = virt_to_phys(hfi_instance->hw_table);
msr_val = hw_table_pa | HW_FEEDBACK_PTR_VALID_BIT;
wrmsrl(MSR_IA32_HW_FEEDBACK_PTR, msr_val);
}
/* Caller must hold hfi_instance_lock. */
static void hfi_disable(void)
{
u64 msr_val;
int i;
rdmsrl(MSR_IA32_HW_FEEDBACK_CONFIG, msr_val);
msr_val &= ~HW_FEEDBACK_CONFIG_HFI_ENABLE_BIT;
wrmsrl(MSR_IA32_HW_FEEDBACK_CONFIG, msr_val);
/*
* Wait for hardware to acknowledge the disabling of HFI. Some
* processors may not do it. Wait for ~2ms. This is a reasonable
* time for hardware to complete any pending actions on the HFI
* memory.
*/
for (i = 0; i < 2000; i++) {
rdmsrl(MSR_IA32_PACKAGE_THERM_STATUS, msr_val);
if (msr_val & PACKAGE_THERM_STATUS_HFI_UPDATED)
break;
udelay(1);
cpu_relax();
}
}
/**
* intel_hfi_online() - Enable HFI on @cpu
* @cpu: CPU in which the HFI will be enabled
@ -364,8 +411,6 @@ void intel_hfi_online(unsigned int cpu)
{
struct hfi_instance *hfi_instance;
struct hfi_cpu_info *info;
phys_addr_t hw_table_pa;
u64 msr_val;
u16 die_id;
/* Nothing to do if hfi_instances are missing. */
@ -392,25 +437,26 @@ void intel_hfi_online(unsigned int cpu)
/*
* Now check if the HFI instance of the package/die of @cpu has been
* initialized (by checking its header). In such case, all we have to
* do is to add @cpu to this instance's cpumask.
* do is to add @cpu to this instance's cpumask and enable the instance
* if needed.
*/
mutex_lock(&hfi_instance_lock);
if (hfi_instance->hdr) {
cpumask_set_cpu(cpu, hfi_instance->cpus);
goto unlock;
}
if (hfi_instance->hdr)
goto enable;
/*
* Hardware is programmed with the physical address of the first page
* frame of the table. Hence, the allocated memory must be page-aligned.
*
* Some processors do not forget the initial address of the HFI table
* even after having been reprogrammed. Keep using the same pages. Do
* not free them.
*/
hfi_instance->hw_table = alloc_pages_exact(hfi_features.nr_table_pages,
GFP_KERNEL | __GFP_ZERO);
if (!hfi_instance->hw_table)
goto unlock;
hw_table_pa = virt_to_phys(hfi_instance->hw_table);
/*
* Allocate memory to keep a local copy of the table that
* hardware generates.
@ -420,31 +466,20 @@ void intel_hfi_online(unsigned int cpu)
if (!hfi_instance->local_table)
goto free_hw_table;
/*
* Program the address of the feedback table of this die/package. On
* some processors, hardware remembers the old address of the HFI table
* even after having been reprogrammed and re-enabled. Thus, do not free
* the pages allocated for the table or reprogram the hardware with a
* new base address. Namely, program the hardware only once.
*/
msr_val = hw_table_pa | HW_FEEDBACK_PTR_VALID_BIT;
wrmsrl(MSR_IA32_HW_FEEDBACK_PTR, msr_val);
init_hfi_instance(hfi_instance);
INIT_DELAYED_WORK(&hfi_instance->update_work, hfi_update_work_fn);
raw_spin_lock_init(&hfi_instance->table_lock);
raw_spin_lock_init(&hfi_instance->event_lock);
enable:
cpumask_set_cpu(cpu, hfi_instance->cpus);
/*
* Enable the hardware feedback interface and never disable it. See
* comment on programming the address of the table.
*/
rdmsrl(MSR_IA32_HW_FEEDBACK_CONFIG, msr_val);
msr_val |= HW_FEEDBACK_CONFIG_HFI_ENABLE_BIT;
wrmsrl(MSR_IA32_HW_FEEDBACK_CONFIG, msr_val);
/* Enable this HFI instance if this is its first online CPU. */
if (cpumask_weight(hfi_instance->cpus) == 1) {
hfi_set_hw_table(hfi_instance);
hfi_enable();
}
unlock:
mutex_unlock(&hfi_instance_lock);
@ -484,6 +519,10 @@ void intel_hfi_offline(unsigned int cpu)
mutex_lock(&hfi_instance_lock);
cpumask_clear_cpu(cpu, hfi_instance->cpus);
if (!cpumask_weight(hfi_instance->cpus))
hfi_disable();
mutex_unlock(&hfi_instance_lock);
}