diff options
| author | Peter Zijlstra <peterz@infradead.org> | 2017-05-31 11:52:03 -0400 |
|---|---|---|
| committer | Thomas Gleixner <tglx@linutronix.de> | 2017-06-04 15:55:53 -0400 |
| commit | bd9240a18edfbfa72e957fc2ba831cf1f13ea073 (patch) | |
| tree | d3a98afdc40e2c4c071e44751f8f095a4d19a6c3 | |
| parent | c6e9f42bbeecbc10cd4fbcca474b5859aba1de67 (diff) | |
x86/apic: Add TSC_DEADLINE quirk due to errata
Due to errata it is possible for the TSC_DEADLINE timer to misbehave
after using TSC_ADJUST. A microcode update is available to fix this
situation.
Avoid using the TSC_DEADLINE timer if it is affected by this issue and
report the required microcode version.
[ tglx: Renamed function to apic_check_deadline_errata() ]
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: kevin.b.stanton@intel.com
Link: http://lkml.kernel.org/r/20170531155306.050849877@infradead.org
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
| -rw-r--r-- | arch/x86/kernel/apic/apic.c | 79 |
1 files changed, 79 insertions, 0 deletions
diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index 87d721a1f3cc..3b215ff36016 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c | |||
| @@ -54,6 +54,8 @@ | |||
| 54 | #include <asm/mce.h> | 54 | #include <asm/mce.h> |
| 55 | #include <asm/tsc.h> | 55 | #include <asm/tsc.h> |
| 56 | #include <asm/hypervisor.h> | 56 | #include <asm/hypervisor.h> |
| 57 | #include <asm/cpu_device_id.h> | ||
| 58 | #include <asm/intel-family.h> | ||
| 57 | 59 | ||
| 58 | unsigned int num_processors; | 60 | unsigned int num_processors; |
| 59 | 61 | ||
| @@ -545,6 +547,81 @@ static struct clock_event_device lapic_clockevent = { | |||
| 545 | }; | 547 | }; |
| 546 | static DEFINE_PER_CPU(struct clock_event_device, lapic_events); | 548 | static DEFINE_PER_CPU(struct clock_event_device, lapic_events); |
| 547 | 549 | ||
| 550 | #define DEADLINE_MODEL_MATCH_FUNC(model, func) \ | ||
| 551 | { X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, (unsigned long)&func } | ||
| 552 | |||
| 553 | #define DEADLINE_MODEL_MATCH_REV(model, rev) \ | ||
| 554 | { X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, (unsigned long)rev } | ||
| 555 | |||
| 556 | static u32 hsx_deadline_rev(void) | ||
| 557 | { | ||
| 558 | switch (boot_cpu_data.x86_mask) { | ||
| 559 | case 0x02: return 0x3a; /* EP */ | ||
| 560 | case 0x04: return 0x0f; /* EX */ | ||
| 561 | } | ||
| 562 | |||
| 563 | return ~0U; | ||
| 564 | } | ||
| 565 | |||
| 566 | static u32 bdx_deadline_rev(void) | ||
| 567 | { | ||
| 568 | switch (boot_cpu_data.x86_mask) { | ||
| 569 | case 0x02: return 0x00000011; | ||
| 570 | case 0x03: return 0x0700000e; | ||
| 571 | case 0x04: return 0x0f00000c; | ||
| 572 | case 0x05: return 0x0e000003; | ||
| 573 | } | ||
| 574 | |||
| 575 | return ~0U; | ||
| 576 | } | ||
| 577 | |||
| 578 | static const struct x86_cpu_id deadline_match[] = { | ||
| 579 | DEADLINE_MODEL_MATCH_FUNC( INTEL_FAM6_HASWELL_X, hsx_deadline_rev), | ||
| 580 | DEADLINE_MODEL_MATCH_REV ( INTEL_FAM6_BROADWELL_X, 0x0b000020), | ||
| 581 | DEADLINE_MODEL_MATCH_FUNC( INTEL_FAM6_BROADWELL_XEON_D, bdx_deadline_rev), | ||
| 582 | DEADLINE_MODEL_MATCH_REV ( INTEL_FAM6_SKYLAKE_X, 0x02000014), | ||
| 583 | |||
| 584 | DEADLINE_MODEL_MATCH_REV ( INTEL_FAM6_HASWELL_CORE, 0x22), | ||
| 585 | DEADLINE_MODEL_MATCH_REV ( INTEL_FAM6_HASWELL_ULT, 0x20), | ||
| 586 | DEADLINE_MODEL_MATCH_REV ( INTEL_FAM6_HASWELL_GT3E, 0x17), | ||
| 587 | |||
| 588 | DEADLINE_MODEL_MATCH_REV ( INTEL_FAM6_BROADWELL_CORE, 0x25), | ||
| 589 | DEADLINE_MODEL_MATCH_REV ( INTEL_FAM6_BROADWELL_GT3E, 0x17), | ||
| 590 | |||
| 591 | DEADLINE_MODEL_MATCH_REV ( INTEL_FAM6_SKYLAKE_MOBILE, 0xb2), | ||
| 592 | DEADLINE_MODEL_MATCH_REV ( INTEL_FAM6_SKYLAKE_DESKTOP, 0xb2), | ||
| 593 | |||
| 594 | DEADLINE_MODEL_MATCH_REV ( INTEL_FAM6_KABYLAKE_MOBILE, 0x52), | ||
| 595 | DEADLINE_MODEL_MATCH_REV ( INTEL_FAM6_KABYLAKE_DESKTOP, 0x52), | ||
| 596 | |||
| 597 | {}, | ||
| 598 | }; | ||
| 599 | |||
| 600 | static void apic_check_deadline_errata(void) | ||
| 601 | { | ||
| 602 | const struct x86_cpu_id *m = x86_match_cpu(deadline_match); | ||
| 603 | u32 rev; | ||
| 604 | |||
| 605 | if (!m) | ||
| 606 | return; | ||
| 607 | |||
| 608 | /* | ||
| 609 | * Function pointers will have the MSB set due to address layout, | ||
| 610 | * immediate revisions will not. | ||
| 611 | */ | ||
| 612 | if ((long)m->driver_data < 0) | ||
| 613 | rev = ((u32 (*)(void))(m->driver_data))(); | ||
| 614 | else | ||
| 615 | rev = (u32)m->driver_data; | ||
| 616 | |||
| 617 | if (boot_cpu_data.microcode >= rev) | ||
| 618 | return; | ||
| 619 | |||
| 620 | setup_clear_cpu_cap(X86_FEATURE_TSC_DEADLINE_TIMER); | ||
| 621 | pr_err(FW_BUG "TSC_DEADLINE disabled due to Errata; " | ||
| 622 | "please update microcode to version: 0x%x (or later)\n", rev); | ||
| 623 | } | ||
| 624 | |||
| 548 | /* | 625 | /* |
| 549 | * Setup the local APIC timer for this CPU. Copy the initialized values | 626 | * Setup the local APIC timer for this CPU. Copy the initialized values |
| 550 | * of the boot CPU and register the clock event in the framework. | 627 | * of the boot CPU and register the clock event in the framework. |
| @@ -1780,6 +1857,8 @@ void __init init_apic_mappings(void) | |||
| 1780 | { | 1857 | { |
| 1781 | unsigned int new_apicid; | 1858 | unsigned int new_apicid; |
| 1782 | 1859 | ||
| 1860 | apic_check_deadline_errata(); | ||
| 1861 | |||
| 1783 | if (x2apic_mode) { | 1862 | if (x2apic_mode) { |
| 1784 | boot_cpu_physical_apicid = read_apic_id(); | 1863 | boot_cpu_physical_apicid = read_apic_id(); |
| 1785 | return; | 1864 | return; |
