| .. | .. |
|---|
| 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 | } |
|---|