Skip to content

Commit 17e8b76

Browse files
committed
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
2 parents f380846 + 1c53081 commit 17e8b76

File tree

1 file changed

+65
-26
lines changed

1 file changed

+65
-26
lines changed

drivers/thermal/intel/intel_hfi.c

Lines changed: 65 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include <linux/bitops.h>
2525
#include <linux/cpufeature.h>
2626
#include <linux/cpumask.h>
27+
#include <linux/delay.h>
2728
#include <linux/gfp.h>
2829
#include <linux/io.h>
2930
#include <linux/kernel.h>
@@ -347,6 +348,52 @@ static void init_hfi_instance(struct hfi_instance *hfi_instance)
347348
hfi_instance->data = hfi_instance->hdr + hfi_features.hdr_size;
348349
}
349350

351+
/* Caller must hold hfi_instance_lock. */
352+
static void hfi_enable(void)
353+
{
354+
u64 msr_val;
355+
356+
rdmsrl(MSR_IA32_HW_FEEDBACK_CONFIG, msr_val);
357+
msr_val |= HW_FEEDBACK_CONFIG_HFI_ENABLE_BIT;
358+
wrmsrl(MSR_IA32_HW_FEEDBACK_CONFIG, msr_val);
359+
}
360+
361+
static void hfi_set_hw_table(struct hfi_instance *hfi_instance)
362+
{
363+
phys_addr_t hw_table_pa;
364+
u64 msr_val;
365+
366+
hw_table_pa = virt_to_phys(hfi_instance->hw_table);
367+
msr_val = hw_table_pa | HW_FEEDBACK_PTR_VALID_BIT;
368+
wrmsrl(MSR_IA32_HW_FEEDBACK_PTR, msr_val);
369+
}
370+
371+
/* Caller must hold hfi_instance_lock. */
372+
static void hfi_disable(void)
373+
{
374+
u64 msr_val;
375+
int i;
376+
377+
rdmsrl(MSR_IA32_HW_FEEDBACK_CONFIG, msr_val);
378+
msr_val &= ~HW_FEEDBACK_CONFIG_HFI_ENABLE_BIT;
379+
wrmsrl(MSR_IA32_HW_FEEDBACK_CONFIG, msr_val);
380+
381+
/*
382+
* Wait for hardware to acknowledge the disabling of HFI. Some
383+
* processors may not do it. Wait for ~2ms. This is a reasonable
384+
* time for hardware to complete any pending actions on the HFI
385+
* memory.
386+
*/
387+
for (i = 0; i < 2000; i++) {
388+
rdmsrl(MSR_IA32_PACKAGE_THERM_STATUS, msr_val);
389+
if (msr_val & PACKAGE_THERM_STATUS_HFI_UPDATED)
390+
break;
391+
392+
udelay(1);
393+
cpu_relax();
394+
}
395+
}
396+
350397
/**
351398
* intel_hfi_online() - Enable HFI on @cpu
352399
* @cpu: CPU in which the HFI will be enabled
@@ -364,8 +411,6 @@ void intel_hfi_online(unsigned int cpu)
364411
{
365412
struct hfi_instance *hfi_instance;
366413
struct hfi_cpu_info *info;
367-
phys_addr_t hw_table_pa;
368-
u64 msr_val;
369414
u16 die_id;
370415

371416
/* Nothing to do if hfi_instances are missing. */
@@ -392,25 +437,26 @@ void intel_hfi_online(unsigned int cpu)
392437
/*
393438
* Now check if the HFI instance of the package/die of @cpu has been
394439
* initialized (by checking its header). In such case, all we have to
395-
* do is to add @cpu to this instance's cpumask.
440+
* do is to add @cpu to this instance's cpumask and enable the instance
441+
* if needed.
396442
*/
397443
mutex_lock(&hfi_instance_lock);
398-
if (hfi_instance->hdr) {
399-
cpumask_set_cpu(cpu, hfi_instance->cpus);
400-
goto unlock;
401-
}
444+
if (hfi_instance->hdr)
445+
goto enable;
402446

403447
/*
404448
* Hardware is programmed with the physical address of the first page
405449
* frame of the table. Hence, the allocated memory must be page-aligned.
450+
*
451+
* Some processors do not forget the initial address of the HFI table
452+
* even after having been reprogrammed. Keep using the same pages. Do
453+
* not free them.
406454
*/
407455
hfi_instance->hw_table = alloc_pages_exact(hfi_features.nr_table_pages,
408456
GFP_KERNEL | __GFP_ZERO);
409457
if (!hfi_instance->hw_table)
410458
goto unlock;
411459

412-
hw_table_pa = virt_to_phys(hfi_instance->hw_table);
413-
414460
/*
415461
* Allocate memory to keep a local copy of the table that
416462
* hardware generates.
@@ -420,31 +466,20 @@ void intel_hfi_online(unsigned int cpu)
420466
if (!hfi_instance->local_table)
421467
goto free_hw_table;
422468

423-
/*
424-
* Program the address of the feedback table of this die/package. On
425-
* some processors, hardware remembers the old address of the HFI table
426-
* even after having been reprogrammed and re-enabled. Thus, do not free
427-
* the pages allocated for the table or reprogram the hardware with a
428-
* new base address. Namely, program the hardware only once.
429-
*/
430-
msr_val = hw_table_pa | HW_FEEDBACK_PTR_VALID_BIT;
431-
wrmsrl(MSR_IA32_HW_FEEDBACK_PTR, msr_val);
432-
433469
init_hfi_instance(hfi_instance);
434470

435471
INIT_DELAYED_WORK(&hfi_instance->update_work, hfi_update_work_fn);
436472
raw_spin_lock_init(&hfi_instance->table_lock);
437473
raw_spin_lock_init(&hfi_instance->event_lock);
438474

475+
enable:
439476
cpumask_set_cpu(cpu, hfi_instance->cpus);
440477

441-
/*
442-
* Enable the hardware feedback interface and never disable it. See
443-
* comment on programming the address of the table.
444-
*/
445-
rdmsrl(MSR_IA32_HW_FEEDBACK_CONFIG, msr_val);
446-
msr_val |= HW_FEEDBACK_CONFIG_HFI_ENABLE_BIT;
447-
wrmsrl(MSR_IA32_HW_FEEDBACK_CONFIG, msr_val);
478+
/* Enable this HFI instance if this is its first online CPU. */
479+
if (cpumask_weight(hfi_instance->cpus) == 1) {
480+
hfi_set_hw_table(hfi_instance);
481+
hfi_enable();
482+
}
448483

449484
unlock:
450485
mutex_unlock(&hfi_instance_lock);
@@ -484,6 +519,10 @@ void intel_hfi_offline(unsigned int cpu)
484519

485520
mutex_lock(&hfi_instance_lock);
486521
cpumask_clear_cpu(cpu, hfi_instance->cpus);
522+
523+
if (!cpumask_weight(hfi_instance->cpus))
524+
hfi_disable();
525+
487526
mutex_unlock(&hfi_instance_lock);
488527
}
489528

0 commit comments

Comments
 (0)