|
24 | 24 | #include <linux/bitops.h>
|
25 | 25 | #include <linux/cpufeature.h>
|
26 | 26 | #include <linux/cpumask.h>
|
| 27 | +#include <linux/delay.h> |
27 | 28 | #include <linux/gfp.h>
|
28 | 29 | #include <linux/io.h>
|
29 | 30 | #include <linux/kernel.h>
|
@@ -367,6 +368,32 @@ static void hfi_set_hw_table(struct hfi_instance *hfi_instance)
|
367 | 368 | wrmsrl(MSR_IA32_HW_FEEDBACK_PTR, msr_val);
|
368 | 369 | }
|
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 | + |
370 | 397 | /**
|
371 | 398 | * intel_hfi_online() - Enable HFI on @cpu
|
372 | 399 | * @cpu: CPU in which the HFI will be enabled
|
@@ -420,6 +447,10 @@ void intel_hfi_online(unsigned int cpu)
|
420 | 447 | /*
|
421 | 448 | * Hardware is programmed with the physical address of the first page
|
422 | 449 | * 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. |
423 | 454 | */
|
424 | 455 | hfi_instance->hw_table = alloc_pages_exact(hfi_features.nr_table_pages,
|
425 | 456 | GFP_KERNEL | __GFP_ZERO);
|
@@ -488,6 +519,10 @@ void intel_hfi_offline(unsigned int cpu)
|
488 | 519 |
|
489 | 520 | mutex_lock(&hfi_instance_lock);
|
490 | 521 | cpumask_clear_cpu(cpu, hfi_instance->cpus);
|
| 522 | + |
| 523 | + if (!cpumask_weight(hfi_instance->cpus)) |
| 524 | + hfi_disable(); |
| 525 | + |
491 | 526 | mutex_unlock(&hfi_instance_lock);
|
492 | 527 | }
|
493 | 528 |
|
|
0 commit comments