diff options
Diffstat (limited to 'arch/x86/kernel/apic/apic.c')
-rw-r--r-- | arch/x86/kernel/apic/apic.c | 80 |
1 files changed, 80 insertions, 0 deletions
diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index e7409468efc6..98b3dd8cf2bf 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. |
@@ -563,6 +640,7 @@ static void setup_APIC_timer(void) | |||
563 | levt->cpumask = cpumask_of(smp_processor_id()); | 640 | levt->cpumask = cpumask_of(smp_processor_id()); |
564 | 641 | ||
565 | if (this_cpu_has(X86_FEATURE_TSC_DEADLINE_TIMER)) { | 642 | if (this_cpu_has(X86_FEATURE_TSC_DEADLINE_TIMER)) { |
643 | levt->name = "lapic-deadline"; | ||
566 | levt->features &= ~(CLOCK_EVT_FEAT_PERIODIC | | 644 | levt->features &= ~(CLOCK_EVT_FEAT_PERIODIC | |
567 | CLOCK_EVT_FEAT_DUMMY); | 645 | CLOCK_EVT_FEAT_DUMMY); |
568 | levt->set_next_event = lapic_next_deadline; | 646 | levt->set_next_event = lapic_next_deadline; |
@@ -1779,6 +1857,8 @@ void __init init_apic_mappings(void) | |||
1779 | { | 1857 | { |
1780 | unsigned int new_apicid; | 1858 | unsigned int new_apicid; |
1781 | 1859 | ||
1860 | apic_check_deadline_errata(); | ||
1861 | |||
1782 | if (x2apic_mode) { | 1862 | if (x2apic_mode) { |
1783 | boot_cpu_physical_apicid = read_apic_id(); | 1863 | boot_cpu_physical_apicid = read_apic_id(); |
1784 | return; | 1864 | return; |