.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * Local APIC handling, local APIC timers |
---|
3 | 4 | * |
---|
.. | .. |
---|
20 | 21 | #include <linux/acpi_pmtmr.h> |
---|
21 | 22 | #include <linux/clockchips.h> |
---|
22 | 23 | #include <linux/interrupt.h> |
---|
23 | | -#include <linux/bootmem.h> |
---|
| 24 | +#include <linux/memblock.h> |
---|
24 | 25 | #include <linux/ftrace.h> |
---|
25 | 26 | #include <linux/ioport.h> |
---|
26 | 27 | #include <linux/export.h> |
---|
.. | .. |
---|
39 | 40 | #include <asm/irq_remapping.h> |
---|
40 | 41 | #include <asm/perf_event.h> |
---|
41 | 42 | #include <asm/x86_init.h> |
---|
42 | | -#include <asm/pgalloc.h> |
---|
43 | 43 | #include <linux/atomic.h> |
---|
44 | 44 | #include <asm/barrier.h> |
---|
45 | 45 | #include <asm/mpspec.h> |
---|
46 | 46 | #include <asm/i8259.h> |
---|
47 | 47 | #include <asm/proto.h> |
---|
| 48 | +#include <asm/traps.h> |
---|
48 | 49 | #include <asm/apic.h> |
---|
| 50 | +#include <asm/acpi.h> |
---|
49 | 51 | #include <asm/io_apic.h> |
---|
50 | 52 | #include <asm/desc.h> |
---|
51 | 53 | #include <asm/hpet.h> |
---|
.. | .. |
---|
64 | 66 | unsigned disabled_cpus; |
---|
65 | 67 | |
---|
66 | 68 | /* Processor that is doing the boot up */ |
---|
67 | | -unsigned int boot_cpu_physical_apicid = -1U; |
---|
| 69 | +unsigned int boot_cpu_physical_apicid __ro_after_init = -1U; |
---|
68 | 70 | EXPORT_SYMBOL_GPL(boot_cpu_physical_apicid); |
---|
69 | 71 | |
---|
70 | | -u8 boot_cpu_apic_version; |
---|
| 72 | +u8 boot_cpu_apic_version __ro_after_init; |
---|
71 | 73 | |
---|
72 | 74 | /* |
---|
73 | 75 | * The highest APIC ID seen during enumeration. |
---|
.. | .. |
---|
84 | 86 | * disable_cpu_apicid=<int>, mostly used for the kdump 2nd kernel to |
---|
85 | 87 | * avoid undefined behaviour caused by sending INIT from AP to BSP. |
---|
86 | 88 | */ |
---|
87 | | -static unsigned int disabled_cpu_apicid __read_mostly = BAD_APICID; |
---|
| 89 | +static unsigned int disabled_cpu_apicid __ro_after_init = BAD_APICID; |
---|
88 | 90 | |
---|
89 | 91 | /* |
---|
90 | 92 | * This variable controls which CPUs receive external NMIs. By default, |
---|
91 | 93 | * external NMIs are delivered only to the BSP. |
---|
92 | 94 | */ |
---|
93 | | -static int apic_extnmi = APIC_EXTNMI_BSP; |
---|
| 95 | +static int apic_extnmi __ro_after_init = APIC_EXTNMI_BSP; |
---|
94 | 96 | |
---|
95 | 97 | /* |
---|
96 | 98 | * Map cpu index to physical APIC ID |
---|
.. | .. |
---|
113 | 115 | DEFINE_EARLY_PER_CPU_READ_MOSTLY(int, x86_cpu_to_logical_apicid, BAD_APICID); |
---|
114 | 116 | |
---|
115 | 117 | /* Local APIC was disabled by the BIOS and enabled by the kernel */ |
---|
116 | | -static int enabled_via_apicbase; |
---|
| 118 | +static int enabled_via_apicbase __ro_after_init; |
---|
117 | 119 | |
---|
118 | 120 | /* |
---|
119 | 121 | * Handle interrupt mode configuration register (IMCR). |
---|
.. | .. |
---|
166 | 168 | { |
---|
167 | 169 | apic_calibrate_pmtmr = 1; |
---|
168 | 170 | notsc_setup(NULL); |
---|
169 | | - return 0; |
---|
| 171 | + return 1; |
---|
170 | 172 | } |
---|
171 | 173 | __setup("apicpmtimer", setup_apicpmtimer); |
---|
172 | 174 | #endif |
---|
173 | 175 | |
---|
174 | | -unsigned long mp_lapic_addr; |
---|
175 | | -int disable_apic; |
---|
| 176 | +unsigned long mp_lapic_addr __ro_after_init; |
---|
| 177 | +int disable_apic __ro_after_init; |
---|
176 | 178 | /* Disable local APIC timer from the kernel commandline or via dmi quirk */ |
---|
177 | 179 | static int disable_apic_timer __initdata; |
---|
178 | 180 | /* Local APIC timer works in C2 */ |
---|
179 | | -int local_apic_timer_c2_ok; |
---|
| 181 | +int local_apic_timer_c2_ok __ro_after_init; |
---|
180 | 182 | EXPORT_SYMBOL_GPL(local_apic_timer_c2_ok); |
---|
181 | 183 | |
---|
182 | 184 | /* |
---|
183 | 185 | * Debug level, exported for io_apic.c |
---|
184 | 186 | */ |
---|
185 | | -int apic_verbosity; |
---|
| 187 | +int apic_verbosity __ro_after_init; |
---|
186 | 188 | |
---|
187 | | -int pic_mode; |
---|
| 189 | +int pic_mode __ro_after_init; |
---|
188 | 190 | |
---|
189 | 191 | /* Have we found an MP table */ |
---|
190 | | -int smp_found_config; |
---|
| 192 | +int smp_found_config __ro_after_init; |
---|
191 | 193 | |
---|
192 | 194 | static struct resource lapic_resource = { |
---|
193 | 195 | .name = "Local APIC", |
---|
194 | 196 | .flags = IORESOURCE_MEM | IORESOURCE_BUSY, |
---|
195 | 197 | }; |
---|
196 | 198 | |
---|
197 | | -unsigned int lapic_timer_frequency = 0; |
---|
| 199 | +unsigned int lapic_timer_period = 0; |
---|
198 | 200 | |
---|
199 | 201 | static void apic_pm_activate(void); |
---|
200 | 202 | |
---|
201 | | -static unsigned long apic_phys; |
---|
| 203 | +static unsigned long apic_phys __ro_after_init; |
---|
202 | 204 | |
---|
203 | 205 | /* |
---|
204 | 206 | * Get the LAPIC version |
---|
.. | .. |
---|
225 | 227 | if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD && |
---|
226 | 228 | boot_cpu_data.x86 >= 0xf) |
---|
227 | 229 | return 1; |
---|
| 230 | + |
---|
| 231 | + /* Hygon systems use modern APIC */ |
---|
| 232 | + if (boot_cpu_data.x86_vendor == X86_VENDOR_HYGON) |
---|
| 233 | + return 1; |
---|
| 234 | + |
---|
228 | 235 | return lapic_get_version() >= 0x14; |
---|
229 | 236 | } |
---|
230 | 237 | |
---|
.. | .. |
---|
403 | 410 | if (vector && !eilvt_entry_is_changeable(vector, new)) |
---|
404 | 411 | /* may not change if vectors are different */ |
---|
405 | 412 | return rsvd; |
---|
406 | | - rsvd = atomic_cmpxchg(&eilvt_offsets[offset], rsvd, new); |
---|
407 | | - } while (rsvd != new); |
---|
| 413 | + } while (!atomic_try_cmpxchg(&eilvt_offsets[offset], &rsvd, new)); |
---|
408 | 414 | |
---|
409 | | - rsvd &= ~APIC_EILVT_MASKED; |
---|
| 415 | + rsvd = new & ~APIC_EILVT_MASKED; |
---|
410 | 416 | if (rsvd && rsvd != vector) |
---|
411 | 417 | pr_info("LVT offset %d assigned for vector 0x%02x\n", |
---|
412 | 418 | offset, rsvd); |
---|
.. | .. |
---|
496 | 502 | if (evt->features & CLOCK_EVT_FEAT_DUMMY) |
---|
497 | 503 | return 0; |
---|
498 | 504 | |
---|
499 | | - __setup_APIC_LVTT(lapic_timer_frequency, oneshot, 1); |
---|
| 505 | + __setup_APIC_LVTT(lapic_timer_period, oneshot, 1); |
---|
500 | 506 | return 0; |
---|
501 | 507 | } |
---|
502 | 508 | |
---|
.. | .. |
---|
541 | 547 | }; |
---|
542 | 548 | static DEFINE_PER_CPU(struct clock_event_device, lapic_events); |
---|
543 | 549 | |
---|
544 | | -#define DEADLINE_MODEL_MATCH_FUNC(model, func) \ |
---|
545 | | - { X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, (unsigned long)&func } |
---|
546 | | - |
---|
547 | | -#define DEADLINE_MODEL_MATCH_REV(model, rev) \ |
---|
548 | | - { X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, (unsigned long)rev } |
---|
549 | | - |
---|
550 | | -static __init u32 hsx_deadline_rev(void) |
---|
551 | | -{ |
---|
552 | | - switch (boot_cpu_data.x86_stepping) { |
---|
553 | | - case 0x02: return 0x3a; /* EP */ |
---|
554 | | - case 0x04: return 0x0f; /* EX */ |
---|
555 | | - } |
---|
556 | | - |
---|
557 | | - return ~0U; |
---|
558 | | -} |
---|
559 | | - |
---|
560 | | -static __init u32 bdx_deadline_rev(void) |
---|
561 | | -{ |
---|
562 | | - switch (boot_cpu_data.x86_stepping) { |
---|
563 | | - case 0x02: return 0x00000011; |
---|
564 | | - case 0x03: return 0x0700000e; |
---|
565 | | - case 0x04: return 0x0f00000c; |
---|
566 | | - case 0x05: return 0x0e000003; |
---|
567 | | - } |
---|
568 | | - |
---|
569 | | - return ~0U; |
---|
570 | | -} |
---|
571 | | - |
---|
572 | | -static __init u32 skx_deadline_rev(void) |
---|
573 | | -{ |
---|
574 | | - switch (boot_cpu_data.x86_stepping) { |
---|
575 | | - case 0x03: return 0x01000136; |
---|
576 | | - case 0x04: return 0x02000014; |
---|
577 | | - } |
---|
578 | | - |
---|
579 | | - if (boot_cpu_data.x86_stepping > 4) |
---|
580 | | - return 0; |
---|
581 | | - |
---|
582 | | - return ~0U; |
---|
583 | | -} |
---|
584 | | - |
---|
585 | 550 | static const struct x86_cpu_id deadline_match[] __initconst = { |
---|
586 | | - DEADLINE_MODEL_MATCH_FUNC( INTEL_FAM6_HASWELL_X, hsx_deadline_rev), |
---|
587 | | - DEADLINE_MODEL_MATCH_REV ( INTEL_FAM6_BROADWELL_X, 0x0b000020), |
---|
588 | | - DEADLINE_MODEL_MATCH_FUNC( INTEL_FAM6_BROADWELL_XEON_D, bdx_deadline_rev), |
---|
589 | | - DEADLINE_MODEL_MATCH_FUNC( INTEL_FAM6_SKYLAKE_X, skx_deadline_rev), |
---|
| 551 | + X86_MATCH_INTEL_FAM6_MODEL_STEPPINGS(HASWELL_X, X86_STEPPINGS(0x2, 0x2), 0x3a), /* EP */ |
---|
| 552 | + X86_MATCH_INTEL_FAM6_MODEL_STEPPINGS(HASWELL_X, X86_STEPPINGS(0x4, 0x4), 0x0f), /* EX */ |
---|
590 | 553 | |
---|
591 | | - DEADLINE_MODEL_MATCH_REV ( INTEL_FAM6_HASWELL_CORE, 0x22), |
---|
592 | | - DEADLINE_MODEL_MATCH_REV ( INTEL_FAM6_HASWELL_ULT, 0x20), |
---|
593 | | - DEADLINE_MODEL_MATCH_REV ( INTEL_FAM6_HASWELL_GT3E, 0x17), |
---|
| 554 | + X86_MATCH_INTEL_FAM6_MODEL( BROADWELL_X, 0x0b000020), |
---|
594 | 555 | |
---|
595 | | - DEADLINE_MODEL_MATCH_REV ( INTEL_FAM6_BROADWELL_CORE, 0x25), |
---|
596 | | - DEADLINE_MODEL_MATCH_REV ( INTEL_FAM6_BROADWELL_GT3E, 0x17), |
---|
| 556 | + X86_MATCH_INTEL_FAM6_MODEL_STEPPINGS(BROADWELL_D, X86_STEPPINGS(0x2, 0x2), 0x00000011), |
---|
| 557 | + X86_MATCH_INTEL_FAM6_MODEL_STEPPINGS(BROADWELL_D, X86_STEPPINGS(0x3, 0x3), 0x0700000e), |
---|
| 558 | + X86_MATCH_INTEL_FAM6_MODEL_STEPPINGS(BROADWELL_D, X86_STEPPINGS(0x4, 0x4), 0x0f00000c), |
---|
| 559 | + X86_MATCH_INTEL_FAM6_MODEL_STEPPINGS(BROADWELL_D, X86_STEPPINGS(0x5, 0x5), 0x0e000003), |
---|
597 | 560 | |
---|
598 | | - DEADLINE_MODEL_MATCH_REV ( INTEL_FAM6_SKYLAKE_MOBILE, 0xb2), |
---|
599 | | - DEADLINE_MODEL_MATCH_REV ( INTEL_FAM6_SKYLAKE_DESKTOP, 0xb2), |
---|
| 561 | + X86_MATCH_INTEL_FAM6_MODEL_STEPPINGS(SKYLAKE_X, X86_STEPPINGS(0x3, 0x3), 0x01000136), |
---|
| 562 | + X86_MATCH_INTEL_FAM6_MODEL_STEPPINGS(SKYLAKE_X, X86_STEPPINGS(0x4, 0x4), 0x02000014), |
---|
| 563 | + X86_MATCH_INTEL_FAM6_MODEL_STEPPINGS(SKYLAKE_X, X86_STEPPINGS(0x5, 0xf), 0), |
---|
600 | 564 | |
---|
601 | | - DEADLINE_MODEL_MATCH_REV ( INTEL_FAM6_KABYLAKE_MOBILE, 0x52), |
---|
602 | | - DEADLINE_MODEL_MATCH_REV ( INTEL_FAM6_KABYLAKE_DESKTOP, 0x52), |
---|
| 565 | + X86_MATCH_INTEL_FAM6_MODEL( HASWELL, 0x22), |
---|
| 566 | + X86_MATCH_INTEL_FAM6_MODEL( HASWELL_L, 0x20), |
---|
| 567 | + X86_MATCH_INTEL_FAM6_MODEL( HASWELL_G, 0x17), |
---|
| 568 | + |
---|
| 569 | + X86_MATCH_INTEL_FAM6_MODEL( BROADWELL, 0x25), |
---|
| 570 | + X86_MATCH_INTEL_FAM6_MODEL( BROADWELL_G, 0x17), |
---|
| 571 | + |
---|
| 572 | + X86_MATCH_INTEL_FAM6_MODEL( SKYLAKE_L, 0xb2), |
---|
| 573 | + X86_MATCH_INTEL_FAM6_MODEL( SKYLAKE, 0xb2), |
---|
| 574 | + |
---|
| 575 | + X86_MATCH_INTEL_FAM6_MODEL( KABYLAKE_L, 0x52), |
---|
| 576 | + X86_MATCH_INTEL_FAM6_MODEL( KABYLAKE, 0x52), |
---|
603 | 577 | |
---|
604 | 578 | {}, |
---|
605 | 579 | }; |
---|
.. | .. |
---|
618 | 592 | if (!m) |
---|
619 | 593 | return true; |
---|
620 | 594 | |
---|
621 | | - /* |
---|
622 | | - * Function pointers will have the MSB set due to address layout, |
---|
623 | | - * immediate revisions will not. |
---|
624 | | - */ |
---|
625 | | - if ((long)m->driver_data < 0) |
---|
626 | | - rev = ((u32 (*)(void))(m->driver_data))(); |
---|
627 | | - else |
---|
628 | | - rev = (u32)m->driver_data; |
---|
| 595 | + rev = (u32)m->driver_data; |
---|
629 | 596 | |
---|
630 | 597 | if (boot_cpu_data.microcode >= rev) |
---|
631 | 598 | return true; |
---|
.. | .. |
---|
777 | 744 | |
---|
778 | 745 | res = (((u64)deltapm) * mult) >> 22; |
---|
779 | 746 | do_div(res, 1000000); |
---|
780 | | - pr_warning("APIC calibration not consistent " |
---|
781 | | - "with PM-Timer: %ldms instead of 100ms\n",(long)res); |
---|
| 747 | + pr_warn("APIC calibration not consistent " |
---|
| 748 | + "with PM-Timer: %ldms instead of 100ms\n", (long)res); |
---|
782 | 749 | |
---|
783 | 750 | /* Correct the lapic counter value */ |
---|
784 | 751 | res = (((u64)(*delta)) * pm_100ms); |
---|
.. | .. |
---|
800 | 767 | return 0; |
---|
801 | 768 | } |
---|
802 | 769 | |
---|
| 770 | +static int __init lapic_init_clockevent(void) |
---|
| 771 | +{ |
---|
| 772 | + if (!lapic_timer_period) |
---|
| 773 | + return -1; |
---|
| 774 | + |
---|
| 775 | + /* Calculate the scaled math multiplication factor */ |
---|
| 776 | + lapic_clockevent.mult = div_sc(lapic_timer_period/APIC_DIVISOR, |
---|
| 777 | + TICK_NSEC, lapic_clockevent.shift); |
---|
| 778 | + lapic_clockevent.max_delta_ns = |
---|
| 779 | + clockevent_delta2ns(0x7FFFFFFF, &lapic_clockevent); |
---|
| 780 | + lapic_clockevent.max_delta_ticks = 0x7FFFFFFF; |
---|
| 781 | + lapic_clockevent.min_delta_ns = |
---|
| 782 | + clockevent_delta2ns(0xF, &lapic_clockevent); |
---|
| 783 | + lapic_clockevent.min_delta_ticks = 0xF; |
---|
| 784 | + |
---|
| 785 | + return 0; |
---|
| 786 | +} |
---|
| 787 | + |
---|
| 788 | +bool __init apic_needs_pit(void) |
---|
| 789 | +{ |
---|
| 790 | + /* |
---|
| 791 | + * If the frequencies are not known, PIT is required for both TSC |
---|
| 792 | + * and apic timer calibration. |
---|
| 793 | + */ |
---|
| 794 | + if (!tsc_khz || !cpu_khz) |
---|
| 795 | + return true; |
---|
| 796 | + |
---|
| 797 | + /* Is there an APIC at all or is it disabled? */ |
---|
| 798 | + if (!boot_cpu_has(X86_FEATURE_APIC) || disable_apic) |
---|
| 799 | + return true; |
---|
| 800 | + |
---|
| 801 | + /* |
---|
| 802 | + * If interrupt delivery mode is legacy PIC or virtual wire without |
---|
| 803 | + * configuration, the local APIC timer wont be set up. Make sure |
---|
| 804 | + * that the PIT is initialized. |
---|
| 805 | + */ |
---|
| 806 | + if (apic_intr_mode == APIC_PIC || |
---|
| 807 | + apic_intr_mode == APIC_VIRTUAL_WIRE_NO_CONFIG) |
---|
| 808 | + return true; |
---|
| 809 | + |
---|
| 810 | + /* Virt guests may lack ARAT, but still have DEADLINE */ |
---|
| 811 | + if (!boot_cpu_has(X86_FEATURE_ARAT)) |
---|
| 812 | + return true; |
---|
| 813 | + |
---|
| 814 | + /* Deadline timer is based on TSC so no further PIT action required */ |
---|
| 815 | + if (boot_cpu_has(X86_FEATURE_TSC_DEADLINE_TIMER)) |
---|
| 816 | + return false; |
---|
| 817 | + |
---|
| 818 | + /* APIC timer disabled? */ |
---|
| 819 | + if (disable_apic_timer) |
---|
| 820 | + return true; |
---|
| 821 | + /* |
---|
| 822 | + * The APIC timer frequency is known already, no PIT calibration |
---|
| 823 | + * required. If unknown, let the PIT be initialized. |
---|
| 824 | + */ |
---|
| 825 | + return lapic_timer_period == 0; |
---|
| 826 | +} |
---|
| 827 | + |
---|
803 | 828 | static int __init calibrate_APIC_clock(void) |
---|
804 | 829 | { |
---|
805 | 830 | struct clock_event_device *levt = this_cpu_ptr(&lapic_events); |
---|
.. | .. |
---|
809 | 834 | long delta, deltatsc; |
---|
810 | 835 | int pm_referenced = 0; |
---|
811 | 836 | |
---|
812 | | - /** |
---|
813 | | - * check if lapic timer has already been calibrated by platform |
---|
814 | | - * specific routine, such as tsc calibration code. if so, we just fill |
---|
| 837 | + if (boot_cpu_has(X86_FEATURE_TSC_DEADLINE_TIMER)) |
---|
| 838 | + return 0; |
---|
| 839 | + |
---|
| 840 | + /* |
---|
| 841 | + * Check if lapic timer has already been calibrated by platform |
---|
| 842 | + * specific routine, such as tsc calibration code. If so just fill |
---|
815 | 843 | * in the clockevent structure and return. |
---|
816 | 844 | */ |
---|
817 | | - |
---|
818 | | - if (boot_cpu_has(X86_FEATURE_TSC_DEADLINE_TIMER)) { |
---|
819 | | - return 0; |
---|
820 | | - } else if (lapic_timer_frequency) { |
---|
| 845 | + if (!lapic_init_clockevent()) { |
---|
821 | 846 | apic_printk(APIC_VERBOSE, "lapic timer already calibrated %d\n", |
---|
822 | | - lapic_timer_frequency); |
---|
823 | | - lapic_clockevent.mult = div_sc(lapic_timer_frequency/APIC_DIVISOR, |
---|
824 | | - TICK_NSEC, lapic_clockevent.shift); |
---|
825 | | - lapic_clockevent.max_delta_ns = |
---|
826 | | - clockevent_delta2ns(0x7FFFFF, &lapic_clockevent); |
---|
827 | | - lapic_clockevent.max_delta_ticks = 0x7FFFFF; |
---|
828 | | - lapic_clockevent.min_delta_ns = |
---|
829 | | - clockevent_delta2ns(0xF, &lapic_clockevent); |
---|
830 | | - lapic_clockevent.min_delta_ticks = 0xF; |
---|
| 847 | + lapic_timer_period); |
---|
| 848 | + /* |
---|
| 849 | + * Direct calibration methods must have an always running |
---|
| 850 | + * local APIC timer, no need for broadcast timer. |
---|
| 851 | + */ |
---|
831 | 852 | lapic_clockevent.features &= ~CLOCK_EVT_FEAT_DUMMY; |
---|
832 | 853 | return 0; |
---|
833 | 854 | } |
---|
.. | .. |
---|
904 | 925 | pm_referenced = !calibrate_by_pmtimer(lapic_cal_pm2 - lapic_cal_pm1, |
---|
905 | 926 | &delta, &deltatsc); |
---|
906 | 927 | |
---|
907 | | - /* Calculate the scaled math multiplication factor */ |
---|
908 | | - lapic_clockevent.mult = div_sc(delta, TICK_NSEC * LAPIC_CAL_LOOPS, |
---|
909 | | - lapic_clockevent.shift); |
---|
910 | | - lapic_clockevent.max_delta_ns = |
---|
911 | | - clockevent_delta2ns(0x7FFFFFFF, &lapic_clockevent); |
---|
912 | | - lapic_clockevent.max_delta_ticks = 0x7FFFFFFF; |
---|
913 | | - lapic_clockevent.min_delta_ns = |
---|
914 | | - clockevent_delta2ns(0xF, &lapic_clockevent); |
---|
915 | | - lapic_clockevent.min_delta_ticks = 0xF; |
---|
916 | | - |
---|
917 | | - lapic_timer_frequency = (delta * APIC_DIVISOR) / LAPIC_CAL_LOOPS; |
---|
| 928 | + lapic_timer_period = (delta * APIC_DIVISOR) / LAPIC_CAL_LOOPS; |
---|
| 929 | + lapic_init_clockevent(); |
---|
918 | 930 | |
---|
919 | 931 | apic_printk(APIC_VERBOSE, "..... delta %ld\n", delta); |
---|
920 | 932 | apic_printk(APIC_VERBOSE, "..... mult: %u\n", lapic_clockevent.mult); |
---|
921 | 933 | apic_printk(APIC_VERBOSE, "..... calibration result: %u\n", |
---|
922 | | - lapic_timer_frequency); |
---|
| 934 | + lapic_timer_period); |
---|
923 | 935 | |
---|
924 | 936 | if (boot_cpu_has(X86_FEATURE_TSC)) { |
---|
925 | 937 | apic_printk(APIC_VERBOSE, "..... CPU clock speed is " |
---|
.. | .. |
---|
930 | 942 | |
---|
931 | 943 | apic_printk(APIC_VERBOSE, "..... host bus clock speed is " |
---|
932 | 944 | "%u.%04u MHz.\n", |
---|
933 | | - lapic_timer_frequency / (1000000 / HZ), |
---|
934 | | - lapic_timer_frequency % (1000000 / HZ)); |
---|
| 945 | + lapic_timer_period / (1000000 / HZ), |
---|
| 946 | + lapic_timer_period % (1000000 / HZ)); |
---|
935 | 947 | |
---|
936 | 948 | /* |
---|
937 | 949 | * Do a sanity check on the APIC calibration result |
---|
938 | 950 | */ |
---|
939 | | - if (lapic_timer_frequency < (1000000 / HZ)) { |
---|
| 951 | + if (lapic_timer_period < (1000000 / HZ)) { |
---|
940 | 952 | local_irq_enable(); |
---|
941 | | - pr_warning("APIC frequency too slow, disabling apic timer\n"); |
---|
| 953 | + pr_warn("APIC frequency too slow, disabling apic timer\n"); |
---|
942 | 954 | return -1; |
---|
943 | 955 | } |
---|
944 | 956 | |
---|
.. | .. |
---|
982 | 994 | local_irq_enable(); |
---|
983 | 995 | |
---|
984 | 996 | if (levt->features & CLOCK_EVT_FEAT_DUMMY) { |
---|
985 | | - pr_warning("APIC timer disabled due to verification failure\n"); |
---|
| 997 | + pr_warn("APIC timer disabled due to verification failure\n"); |
---|
986 | 998 | return -1; |
---|
987 | 999 | } |
---|
988 | 1000 | |
---|
.. | .. |
---|
1056 | 1068 | * spurious. |
---|
1057 | 1069 | */ |
---|
1058 | 1070 | if (!evt->event_handler) { |
---|
1059 | | - pr_warning("Spurious LAPIC timer interrupt on cpu %d\n", |
---|
1060 | | - smp_processor_id()); |
---|
| 1071 | + pr_warn("Spurious LAPIC timer interrupt on cpu %d\n", |
---|
| 1072 | + smp_processor_id()); |
---|
1061 | 1073 | /* Switch it off */ |
---|
1062 | 1074 | lapic_timer_shutdown(evt); |
---|
1063 | 1075 | return; |
---|
.. | .. |
---|
1079 | 1091 | * [ if a single-CPU system runs an SMP kernel then we call the local |
---|
1080 | 1092 | * interrupt as well. Thus we cannot inline the local irq ... ] |
---|
1081 | 1093 | */ |
---|
1082 | | -__visible void __irq_entry smp_apic_timer_interrupt(struct pt_regs *regs) |
---|
| 1094 | +DEFINE_IDTENTRY_SYSVEC(sysvec_apic_timer_interrupt) |
---|
1083 | 1095 | { |
---|
1084 | 1096 | struct pt_regs *old_regs = set_irq_regs(regs); |
---|
1085 | 1097 | |
---|
1086 | | - /* |
---|
1087 | | - * NOTE! We'd better ACK the irq immediately, |
---|
1088 | | - * because timer handling can be slow. |
---|
1089 | | - * |
---|
1090 | | - * update_process_times() expects us to have done irq_enter(). |
---|
1091 | | - * Besides, if we don't timer interrupts ignore the global |
---|
1092 | | - * interrupt lock, which is the WrongThing (tm) to do. |
---|
1093 | | - */ |
---|
1094 | | - entering_ack_irq(); |
---|
| 1098 | + ack_APIC_irq(); |
---|
1095 | 1099 | trace_local_timer_entry(LOCAL_TIMER_VECTOR); |
---|
1096 | 1100 | local_apic_timer_interrupt(); |
---|
1097 | 1101 | trace_local_timer_exit(LOCAL_TIMER_VECTOR); |
---|
1098 | | - exiting_irq(); |
---|
1099 | 1102 | |
---|
1100 | 1103 | set_irq_regs(old_regs); |
---|
1101 | 1104 | } |
---|
.. | .. |
---|
1185 | 1188 | } |
---|
1186 | 1189 | |
---|
1187 | 1190 | /** |
---|
| 1191 | + * apic_soft_disable - Clears and software disables the local APIC on hotplug |
---|
| 1192 | + * |
---|
| 1193 | + * Contrary to disable_local_APIC() this does not touch the enable bit in |
---|
| 1194 | + * MSR_IA32_APICBASE. Clearing that bit on systems based on the 3 wire APIC |
---|
| 1195 | + * bus would require a hardware reset as the APIC would lose track of bus |
---|
| 1196 | + * arbitration. On systems with FSB delivery APICBASE could be disabled, |
---|
| 1197 | + * but it has to be guaranteed that no interrupt is sent to the APIC while |
---|
| 1198 | + * in that state and it's not clear from the SDM whether it still responds |
---|
| 1199 | + * to INIT/SIPI messages. Stay on the safe side and use software disable. |
---|
| 1200 | + */ |
---|
| 1201 | +void apic_soft_disable(void) |
---|
| 1202 | +{ |
---|
| 1203 | + u32 value; |
---|
| 1204 | + |
---|
| 1205 | + clear_local_APIC(); |
---|
| 1206 | + |
---|
| 1207 | + /* Soft disable APIC (implies clearing of registers for 82489DX!). */ |
---|
| 1208 | + value = apic_read(APIC_SPIV); |
---|
| 1209 | + value &= ~APIC_SPIV_APIC_ENABLED; |
---|
| 1210 | + apic_write(APIC_SPIV, value); |
---|
| 1211 | +} |
---|
| 1212 | + |
---|
| 1213 | +/** |
---|
1188 | 1214 | * disable_local_APIC - clear and disable the local APIC |
---|
1189 | 1215 | */ |
---|
1190 | 1216 | void disable_local_APIC(void) |
---|
1191 | 1217 | { |
---|
1192 | | - unsigned int value; |
---|
1193 | | - |
---|
1194 | 1218 | /* APIC hasn't been mapped yet */ |
---|
1195 | 1219 | if (!x2apic_mode && !apic_phys) |
---|
1196 | 1220 | return; |
---|
1197 | 1221 | |
---|
1198 | | - clear_local_APIC(); |
---|
1199 | | - |
---|
1200 | | - /* |
---|
1201 | | - * Disable APIC (implies clearing of registers |
---|
1202 | | - * for 82489DX!). |
---|
1203 | | - */ |
---|
1204 | | - value = apic_read(APIC_SPIV); |
---|
1205 | | - value &= ~APIC_SPIV_APIC_ENABLED; |
---|
1206 | | - apic_write(APIC_SPIV, value); |
---|
| 1222 | + apic_soft_disable(); |
---|
1207 | 1223 | |
---|
1208 | 1224 | #ifdef CONFIG_X86_32 |
---|
1209 | 1225 | /* |
---|
.. | .. |
---|
1268 | 1284 | APIC_INT_LEVELTRIG | APIC_DM_INIT); |
---|
1269 | 1285 | } |
---|
1270 | 1286 | |
---|
1271 | | -enum apic_intr_mode_id apic_intr_mode; |
---|
| 1287 | +enum apic_intr_mode_id apic_intr_mode __ro_after_init; |
---|
1272 | 1288 | |
---|
1273 | | -static int __init apic_intr_mode_select(void) |
---|
| 1289 | +static int __init __apic_intr_mode_select(void) |
---|
1274 | 1290 | { |
---|
1275 | 1291 | /* Check kernel option */ |
---|
1276 | 1292 | if (disable_apic) { |
---|
.. | .. |
---|
1332 | 1348 | return APIC_SYMMETRIC_IO; |
---|
1333 | 1349 | } |
---|
1334 | 1350 | |
---|
| 1351 | +/* Select the interrupt delivery mode for the BSP */ |
---|
| 1352 | +void __init apic_intr_mode_select(void) |
---|
| 1353 | +{ |
---|
| 1354 | + apic_intr_mode = __apic_intr_mode_select(); |
---|
| 1355 | +} |
---|
| 1356 | + |
---|
1335 | 1357 | /* |
---|
1336 | 1358 | * An initial setup of the virtual wire mode. |
---|
1337 | 1359 | */ |
---|
.. | .. |
---|
1381 | 1403 | apic_write(APIC_LVT1, value); |
---|
1382 | 1404 | } |
---|
1383 | 1405 | |
---|
| 1406 | +static void __init apic_bsp_setup(bool upmode); |
---|
| 1407 | + |
---|
1384 | 1408 | /* Init the interrupt delivery mode for the BSP */ |
---|
1385 | 1409 | void __init apic_intr_mode_init(void) |
---|
1386 | 1410 | { |
---|
1387 | 1411 | bool upmode = IS_ENABLED(CONFIG_UP_LATE_INIT); |
---|
1388 | | - |
---|
1389 | | - apic_intr_mode = apic_intr_mode_select(); |
---|
1390 | 1412 | |
---|
1391 | 1413 | switch (apic_intr_mode) { |
---|
1392 | 1414 | case APIC_PIC: |
---|
.. | .. |
---|
1409 | 1431 | pr_info("APIC: Switch to symmetric I/O mode setup in no SMP routine\n"); |
---|
1410 | 1432 | break; |
---|
1411 | 1433 | } |
---|
| 1434 | + |
---|
| 1435 | + if (x86_platform.apic_post_init) |
---|
| 1436 | + x86_platform.apic_post_init(); |
---|
1412 | 1437 | |
---|
1413 | 1438 | apic_bsp_setup(upmode); |
---|
1414 | 1439 | } |
---|
.. | .. |
---|
1533 | 1558 | int cpu = smp_processor_id(); |
---|
1534 | 1559 | unsigned int value; |
---|
1535 | 1560 | |
---|
1536 | | - |
---|
1537 | 1561 | if (disable_apic) { |
---|
1538 | 1562 | disable_ioapic_support(); |
---|
1539 | 1563 | return; |
---|
.. | .. |
---|
1556 | 1580 | apic_write(APIC_ESR, 0); |
---|
1557 | 1581 | } |
---|
1558 | 1582 | #endif |
---|
1559 | | - perf_events_lapic_init(); |
---|
1560 | | - |
---|
1561 | 1583 | /* |
---|
1562 | 1584 | * Double-check whether this APIC is really registered. |
---|
1563 | 1585 | * This is meaningless in clustered apic mode, so we skip it. |
---|
.. | .. |
---|
1590 | 1612 | #endif |
---|
1591 | 1613 | |
---|
1592 | 1614 | /* |
---|
1593 | | - * Set Task Priority to 'accept all'. We never change this |
---|
1594 | | - * later on. |
---|
| 1615 | + * Set Task Priority to 'accept all except vectors 0-31'. An APIC |
---|
| 1616 | + * vector in the 16-31 range could be delivered if TPR == 0, but we |
---|
| 1617 | + * would think it's an exception and terrible things will happen. We |
---|
| 1618 | + * never change this later on. |
---|
1595 | 1619 | */ |
---|
1596 | 1620 | value = apic_read(APIC_TASKPRI); |
---|
1597 | 1621 | value &= ~APIC_TPRI_MASK; |
---|
| 1622 | + value |= 0x10; |
---|
1598 | 1623 | apic_write(APIC_TASKPRI, value); |
---|
1599 | 1624 | |
---|
1600 | 1625 | /* Clear eventually stale ISR/IRR bits */ |
---|
.. | .. |
---|
1643 | 1668 | */ |
---|
1644 | 1669 | value |= SPURIOUS_APIC_VECTOR; |
---|
1645 | 1670 | apic_write(APIC_SPIV, value); |
---|
| 1671 | + |
---|
| 1672 | + perf_events_lapic_init(); |
---|
1646 | 1673 | |
---|
1647 | 1674 | /* |
---|
1648 | 1675 | * Set up LVT0, LVT1: |
---|
.. | .. |
---|
1755 | 1782 | int apicid = native_apic_msr_read(APIC_ID); |
---|
1756 | 1783 | |
---|
1757 | 1784 | if (apicid >= 255) { |
---|
1758 | | - pr_warning("Apicid: %08x, cannot enforce nox2apic\n", |
---|
1759 | | - apicid); |
---|
| 1785 | + pr_warn("Apicid: %08x, cannot enforce nox2apic\n", |
---|
| 1786 | + apicid); |
---|
1760 | 1787 | return 0; |
---|
1761 | 1788 | } |
---|
1762 | | - pr_warning("x2apic already enabled.\n"); |
---|
| 1789 | + pr_warn("x2apic already enabled.\n"); |
---|
1763 | 1790 | __x2apic_disable(); |
---|
1764 | 1791 | } |
---|
1765 | 1792 | setup_clear_cpu_cap(X86_FEATURE_X2APIC); |
---|
.. | .. |
---|
1929 | 1956 | */ |
---|
1930 | 1957 | features = cpuid_edx(1); |
---|
1931 | 1958 | if (!(features & (1 << X86_FEATURE_APIC))) { |
---|
1932 | | - pr_warning("Could not enable APIC!\n"); |
---|
| 1959 | + pr_warn("Could not enable APIC!\n"); |
---|
1933 | 1960 | return -1; |
---|
1934 | 1961 | } |
---|
1935 | 1962 | set_cpu_cap(&boot_cpu_data, X86_FEATURE_APIC); |
---|
.. | .. |
---|
1986 | 2013 | (boot_cpu_data.x86 >= 15)) |
---|
1987 | 2014 | break; |
---|
1988 | 2015 | goto no_apic; |
---|
| 2016 | + case X86_VENDOR_HYGON: |
---|
| 2017 | + break; |
---|
1989 | 2018 | case X86_VENDOR_INTEL: |
---|
1990 | 2019 | if (boot_cpu_data.x86 == 6 || boot_cpu_data.x86 == 15 || |
---|
1991 | 2020 | (boot_cpu_data.x86 == 5 && boot_cpu_has(X86_FEATURE_APIC))) |
---|
.. | .. |
---|
2090 | 2119 | * Local APIC interrupts |
---|
2091 | 2120 | */ |
---|
2092 | 2121 | |
---|
2093 | | -/* |
---|
2094 | | - * This interrupt should _never_ happen with our APIC/SMP architecture |
---|
| 2122 | +/** |
---|
| 2123 | + * spurious_interrupt - Catch all for interrupts raised on unused vectors |
---|
| 2124 | + * @regs: Pointer to pt_regs on stack |
---|
| 2125 | + * @vector: The vector number |
---|
| 2126 | + * |
---|
| 2127 | + * This is invoked from ASM entry code to catch all interrupts which |
---|
| 2128 | + * trigger on an entry which is routed to the common_spurious idtentry |
---|
| 2129 | + * point. |
---|
| 2130 | + * |
---|
| 2131 | + * Also called from sysvec_spurious_apic_interrupt(). |
---|
2095 | 2132 | */ |
---|
2096 | | -__visible void __irq_entry smp_spurious_interrupt(struct pt_regs *regs) |
---|
| 2133 | +DEFINE_IDTENTRY_IRQ(spurious_interrupt) |
---|
2097 | 2134 | { |
---|
2098 | | - u8 vector = ~regs->orig_ax; |
---|
2099 | 2135 | u32 v; |
---|
2100 | 2136 | |
---|
2101 | | - entering_irq(); |
---|
2102 | 2137 | trace_spurious_apic_entry(vector); |
---|
2103 | 2138 | |
---|
2104 | 2139 | inc_irq_stat(irq_spurious_count); |
---|
.. | .. |
---|
2128 | 2163 | } |
---|
2129 | 2164 | out: |
---|
2130 | 2165 | trace_spurious_apic_exit(vector); |
---|
2131 | | - exiting_irq(); |
---|
| 2166 | +} |
---|
| 2167 | + |
---|
| 2168 | +DEFINE_IDTENTRY_SYSVEC(sysvec_spurious_apic_interrupt) |
---|
| 2169 | +{ |
---|
| 2170 | + __spurious_interrupt(regs, SPURIOUS_APIC_VECTOR); |
---|
2132 | 2171 | } |
---|
2133 | 2172 | |
---|
2134 | 2173 | /* |
---|
2135 | 2174 | * This interrupt should never happen with our APIC/SMP architecture |
---|
2136 | 2175 | */ |
---|
2137 | | -__visible void __irq_entry smp_error_interrupt(struct pt_regs *regs) |
---|
| 2176 | +DEFINE_IDTENTRY_SYSVEC(sysvec_error_interrupt) |
---|
2138 | 2177 | { |
---|
2139 | 2178 | static const char * const error_interrupt_reason[] = { |
---|
2140 | 2179 | "Send CS error", /* APIC Error Bit 0 */ |
---|
.. | .. |
---|
2148 | 2187 | }; |
---|
2149 | 2188 | u32 v, i = 0; |
---|
2150 | 2189 | |
---|
2151 | | - entering_irq(); |
---|
2152 | 2190 | trace_error_apic_entry(ERROR_APIC_VECTOR); |
---|
2153 | 2191 | |
---|
2154 | 2192 | /* First tickle the hardware, only then report what went on. -- REW */ |
---|
.. | .. |
---|
2172 | 2210 | apic_printk(APIC_DEBUG, KERN_CONT "\n"); |
---|
2173 | 2211 | |
---|
2174 | 2212 | trace_error_apic_exit(ERROR_APIC_VECTOR); |
---|
2175 | | - exiting_irq(); |
---|
2176 | 2213 | } |
---|
2177 | 2214 | |
---|
2178 | 2215 | /** |
---|
.. | .. |
---|
2287 | 2324 | #ifdef CONFIG_SMP |
---|
2288 | 2325 | /** |
---|
2289 | 2326 | * apic_id_is_primary_thread - Check whether APIC ID belongs to a primary thread |
---|
2290 | | - * @id: APIC ID to check |
---|
| 2327 | + * @apicid: APIC ID to check |
---|
2291 | 2328 | */ |
---|
2292 | 2329 | bool apic_id_is_primary_thread(unsigned int apicid) |
---|
2293 | 2330 | { |
---|
.. | .. |
---|
2360 | 2397 | disabled_cpu_apicid == apicid) { |
---|
2361 | 2398 | int thiscpu = num_processors + disabled_cpus; |
---|
2362 | 2399 | |
---|
2363 | | - pr_warning("APIC: Disabling requested cpu." |
---|
2364 | | - " Processor %d/0x%x ignored.\n", |
---|
2365 | | - thiscpu, apicid); |
---|
| 2400 | + pr_warn("APIC: Disabling requested cpu." |
---|
| 2401 | + " Processor %d/0x%x ignored.\n", thiscpu, apicid); |
---|
2366 | 2402 | |
---|
2367 | 2403 | disabled_cpus++; |
---|
2368 | 2404 | return -ENODEV; |
---|
.. | .. |
---|
2376 | 2412 | apicid != boot_cpu_physical_apicid) { |
---|
2377 | 2413 | int thiscpu = max + disabled_cpus - 1; |
---|
2378 | 2414 | |
---|
2379 | | - pr_warning( |
---|
2380 | | - "APIC: NR_CPUS/possible_cpus limit of %i almost" |
---|
| 2415 | + pr_warn("APIC: NR_CPUS/possible_cpus limit of %i almost" |
---|
2381 | 2416 | " reached. Keeping one slot for boot cpu." |
---|
2382 | 2417 | " Processor %d/0x%x ignored.\n", max, thiscpu, apicid); |
---|
2383 | 2418 | |
---|
.. | .. |
---|
2388 | 2423 | if (num_processors >= nr_cpu_ids) { |
---|
2389 | 2424 | int thiscpu = max + disabled_cpus; |
---|
2390 | 2425 | |
---|
2391 | | - pr_warning("APIC: NR_CPUS/possible_cpus limit of %i " |
---|
2392 | | - "reached. Processor %d/0x%x ignored.\n", |
---|
2393 | | - max, thiscpu, apicid); |
---|
| 2426 | + pr_warn("APIC: NR_CPUS/possible_cpus limit of %i reached. " |
---|
| 2427 | + "Processor %d/0x%x ignored.\n", max, thiscpu, apicid); |
---|
2394 | 2428 | |
---|
2395 | 2429 | disabled_cpus++; |
---|
2396 | 2430 | return -EINVAL; |
---|
.. | .. |
---|
2420 | 2454 | * Validate version |
---|
2421 | 2455 | */ |
---|
2422 | 2456 | if (version == 0x0) { |
---|
2423 | | - pr_warning("BIOS bug: APIC version is 0 for CPU %d/0x%x, fixing up to 0x10\n", |
---|
2424 | | - cpu, apicid); |
---|
| 2457 | + pr_warn("BIOS bug: APIC version is 0 for CPU %d/0x%x, fixing up to 0x10\n", |
---|
| 2458 | + cpu, apicid); |
---|
2425 | 2459 | version = 0x10; |
---|
2426 | 2460 | } |
---|
2427 | 2461 | |
---|
2428 | 2462 | if (version != boot_cpu_apic_version) { |
---|
2429 | | - pr_warning("BIOS bug: APIC version mismatch, boot CPU: %x, CPU %d: version %x\n", |
---|
| 2463 | + pr_warn("BIOS bug: APIC version mismatch, boot CPU: %x, CPU %d: version %x\n", |
---|
2430 | 2464 | boot_cpu_apic_version, cpu, version); |
---|
2431 | 2465 | } |
---|
2432 | 2466 | |
---|
.. | .. |
---|
2492 | 2526 | /** |
---|
2493 | 2527 | * apic_bsp_setup - Setup function for local apic and io-apic |
---|
2494 | 2528 | * @upmode: Force UP mode (for APIC_init_uniprocessor) |
---|
2495 | | - * |
---|
2496 | | - * Returns: |
---|
2497 | | - * apic_id of BSP APIC |
---|
2498 | 2529 | */ |
---|
2499 | | -void __init apic_bsp_setup(bool upmode) |
---|
| 2530 | +static void __init apic_bsp_setup(bool upmode) |
---|
2500 | 2531 | { |
---|
2501 | 2532 | connect_bsp_APIC(); |
---|
2502 | 2533 | if (upmode) |
---|
.. | .. |
---|
2583 | 2614 | #endif |
---|
2584 | 2615 | |
---|
2585 | 2616 | local_irq_save(flags); |
---|
| 2617 | + |
---|
| 2618 | + /* |
---|
| 2619 | + * Mask IOAPIC before disabling the local APIC to prevent stale IRR |
---|
| 2620 | + * entries on some implementations. |
---|
| 2621 | + */ |
---|
| 2622 | + mask_ioapic_entries(); |
---|
| 2623 | + |
---|
2586 | 2624 | disable_local_APIC(); |
---|
2587 | 2625 | |
---|
2588 | 2626 | irq_remapping_disable(); |
---|
.. | .. |
---|
2799 | 2837 | apic_verbosity = APIC_VERBOSE; |
---|
2800 | 2838 | #ifdef CONFIG_X86_64 |
---|
2801 | 2839 | else { |
---|
2802 | | - pr_warning("APIC Verbosity level %s not recognised" |
---|
| 2840 | + pr_warn("APIC Verbosity level %s not recognised" |
---|
2803 | 2841 | " use apic=verbose or apic=debug\n", arg); |
---|
2804 | 2842 | return -EINVAL; |
---|
2805 | 2843 | } |
---|