--- /dev/null
+From: Suresh Siddha <suresh.b.siddha@intel.com>
+Subject: x64, x2apic/intr-remap: add x2apic support, including enabling interrupt-remapping
+References: fate #303948 and fate #303984
+Patch-Mainline: queued for .28
+Commit-ID: 6e1cb38a2aef7680975e71f23de187859ee8b158
+
+Signed-off-by: Thomas Renninger <trenn@suse.de>
+
+x2apic support. Interrupt-remapping must be enabled before enabling x2apic,
+this is needed to ensure that IO interrupts continue to work properly after the
+cpu mode is changed to x2apic(which uses 32bit extended physical/cluster
+apic id).
+
+On systems where apicid's are > 255, BIOS can handover the control to OS in
+x2apic mode. Or if the OS handover was in legacy xapic mode, check
+if it is capable of x2apic mode. And if we succeed in enabling
+Interrupt-remapping, then we can enable x2apic mode in the CPU.
+
+Signed-off-by: Suresh Siddha <suresh.b.siddha@intel.com>
+Cc: akpm@linux-foundation.org
+Cc: arjan@linux.intel.com
+Cc: andi@firstfloor.org
+Cc: ebiederm@xmission.com
+Cc: jbarnes@virtuousgeek.org
+Cc: steiner@sgi.com
+Signed-off-by: Ingo Molnar <mingo@elte.hu>
+
+---
+ Documentation/kernel-parameters.txt | 2
+ arch/x86/kernel/acpi/boot.c | 2
+ arch/x86/kernel/apic_64.c | 154 +++++++++++++++++++++++++++++++++++-
+ arch/x86/kernel/cpu/common_64.c | 2
+ arch/x86/kernel/mpparse.c | 2
+ arch/x86/kernel/setup.c | 2
+ arch/x86/kernel/smpboot.c | 5 +
+ include/asm-x86/apic.h | 14 +--
+ 8 files changed, 172 insertions(+), 11 deletions(-)
+
+--- a/Documentation/kernel-parameters.txt
++++ b/Documentation/kernel-parameters.txt
+@@ -1428,6 +1428,8 @@ and is between 256 and 4096 characters.
+
+ nolapic_timer [X86-32,APIC] Do not use the local APIC timer.
+
++ nox2apic [X86-64,APIC] Do not enable x2APIC mode.
++
+ noltlbs [PPC] Do not use large page/tlb entries for kernel
+ lowmem mapping on PPC40x.
+
+--- a/arch/x86/kernel/acpi/boot.c
++++ b/arch/x86/kernel/acpi/boot.c
+@@ -1351,7 +1351,9 @@ static void __init acpi_process_madt(voi
+ acpi_ioapic = 1;
+
+ smp_found_config = 1;
++#ifdef CONFIG_X86_32
+ setup_apic_routing();
++#endif
+ }
+ }
+ if (error == -EINVAL) {
+--- a/arch/x86/kernel/apic_64.c
++++ b/arch/x86/kernel/apic_64.c
+@@ -27,6 +27,7 @@
+ #include <linux/clockchips.h>
+ #include <linux/acpi_pmtmr.h>
+ #include <linux/module.h>
++#include <linux/dmar.h>
+
+ #include <asm/atomic.h>
+ #include <asm/smp.h>
+@@ -39,6 +40,7 @@
+ #include <asm/proto.h>
+ #include <asm/timex.h>
+ #include <asm/apic.h>
++#include <asm/i8259.h>
+
+ #include <mach_ipi.h>
+ #include <mach_apic.h>
+@@ -46,8 +48,12 @@
+ static int disable_apic_timer __cpuinitdata;
+ static int apic_calibrate_pmtmr __initdata;
+ int disable_apic;
++int disable_x2apic;
+ int x2apic;
+
++/* x2apic enabled before OS handover */
++int x2apic_preenabled;
++
+ /* Local APIC timer works in C2 */
+ int local_apic_timer_c2_ok;
+ EXPORT_SYMBOL_GPL(local_apic_timer_c2_ok);
+@@ -898,6 +904,125 @@ void __cpuinit end_local_APIC_setup(void
+ apic_pm_activate();
+ }
+
++void check_x2apic(void)
++{
++ int msr, msr2;
++
++ rdmsr(MSR_IA32_APICBASE, msr, msr2);
++
++ if (msr & X2APIC_ENABLE) {
++ printk("x2apic enabled by BIOS, switching to x2apic ops\n");
++ x2apic_preenabled = x2apic = 1;
++ apic_ops = &x2apic_ops;
++ }
++}
++
++void enable_x2apic(void)
++{
++ int msr, msr2;
++
++ rdmsr(MSR_IA32_APICBASE, msr, msr2);
++ if (!(msr & X2APIC_ENABLE)) {
++ printk("Enabling x2apic\n");
++ wrmsr(MSR_IA32_APICBASE, msr | X2APIC_ENABLE, 0);
++ }
++}
++
++void enable_IR_x2apic(void)
++{
++#ifdef CONFIG_INTR_REMAP
++ int ret;
++ unsigned long flags;
++
++ if (!cpu_has_x2apic)
++ return;
++
++ if (!x2apic_preenabled && disable_x2apic) {
++ printk(KERN_INFO
++ "Skipped enabling x2apic and Interrupt-remapping "
++ "because of nox2apic\n");
++ return;
++ }
++
++ if (x2apic_preenabled && disable_x2apic)
++ panic("Bios already enabled x2apic, can't enforce nox2apic");
++
++ if (!x2apic_preenabled && skip_ioapic_setup) {
++ printk(KERN_INFO
++ "Skipped enabling x2apic and Interrupt-remapping "
++ "because of skipping io-apic setup\n");
++ return;
++ }
++
++ ret = dmar_table_init();
++ if (ret) {
++ printk(KERN_INFO
++ "dmar_table_init() failed with %d:\n", ret);
++
++ if (x2apic_preenabled)
++ panic("x2apic enabled by bios. But IR enabling failed");
++ else
++ printk(KERN_INFO
++ "Not enabling x2apic,Intr-remapping\n");
++ return;
++ }
++
++ local_irq_save(flags);
++ mask_8259A();
++ save_mask_IO_APIC_setup();
++
++ ret = enable_intr_remapping(1);
++
++ if (ret && x2apic_preenabled) {
++ local_irq_restore(flags);
++ panic("x2apic enabled by bios. But IR enabling failed");
++ }
++
++ if (ret)
++ goto end;
++
++ if (!x2apic) {
++ x2apic = 1;
++ apic_ops = &x2apic_ops;
++ enable_x2apic();
++ }
++end:
++ if (ret)
++ /*
++ * IR enabling failed
++ */
++ restore_IO_APIC_setup();
++ else
++ reinit_intr_remapped_IO_APIC(x2apic_preenabled);
++
++ unmask_8259A();
++ local_irq_restore(flags);
++
++ if (!ret) {
++ if (!x2apic_preenabled)
++ printk(KERN_INFO
++ "Enabled x2apic and interrupt-remapping\n");
++ else
++ printk(KERN_INFO
++ "Enabled Interrupt-remapping\n");
++ } else
++ printk(KERN_ERR
++ "Failed to enable Interrupt-remapping and x2apic\n");
++#else
++ if (!cpu_has_x2apic)
++ return;
++
++ if (x2apic_preenabled)
++ panic("x2apic enabled prior OS handover,"
++ " enable CONFIG_INTR_REMAP");
++
++ printk(KERN_INFO "Enable CONFIG_INTR_REMAP for enabling intr-remapping "
++ " and x2apic\n");
++#endif
++
++ return;
++}
++
+ /*
+ * Detect and enable local APICs on non-SMP boards.
+ * Original code written by Keir Fraser.
+@@ -945,6 +1070,11 @@ void __init early_init_lapic_mapping(voi
+ */
+ void __init init_apic_mappings(void)
+ {
++ if (x2apic) {
++ boot_cpu_physical_apicid = GET_APIC_ID(read_apic_id());
++ return;
++ }
++
+ /*
+ * If no local APIC can be found then set up a fake all
+ * zeroes page to simulate the local APIC and another
+@@ -983,6 +1113,9 @@ int __init APIC_init_uniprocessor(void)
+ return -1;
+ }
+
++ enable_IR_x2apic();
++ setup_apic_routing();
++
+ verify_local_APIC();
+
+ connect_bsp_APIC();
+@@ -1236,10 +1369,14 @@ static int lapic_resume(struct sys_devic
+ maxlvt = lapic_get_maxlvt();
+
+ local_irq_save(flags);
+- rdmsr(MSR_IA32_APICBASE, l, h);
+- l &= ~MSR_IA32_APICBASE_BASE;
+- l |= MSR_IA32_APICBASE_ENABLE | mp_lapic_addr;
+- wrmsr(MSR_IA32_APICBASE, l, h);
++ if (!x2apic) {
++ rdmsr(MSR_IA32_APICBASE, l, h);
++ l &= ~MSR_IA32_APICBASE_BASE;
++ l |= MSR_IA32_APICBASE_ENABLE | mp_lapic_addr;
++ wrmsr(MSR_IA32_APICBASE, l, h);
++ } else
++ enable_x2apic();
++
+ apic_write(APIC_LVTERR, ERROR_APIC_VECTOR | APIC_LVT_MASKED);
+ apic_write(APIC_ID, apic_pm_state.apic_id);
+ apic_write(APIC_DFR, apic_pm_state.apic_dfr);
+@@ -1379,6 +1516,15 @@ __cpuinit int apic_is_clustered_box(void
+ return (clusters > 2);
+ }
+
++static __init int setup_nox2apic(char *str)
++{
++ disable_x2apic = 1;
++ clear_cpu_cap(&boot_cpu_data, X86_FEATURE_X2APIC);
++ return 0;
++}
++early_param("nox2apic", setup_nox2apic);
++
++
+ /*
+ * APIC command line parameters
+ */
+--- a/arch/x86/kernel/cpu/common_64.c
++++ b/arch/x86/kernel/cpu/common_64.c
+@@ -636,6 +636,8 @@ void __cpuinit cpu_init(void)
+ barrier();
+
+ check_efer();
++ if (cpu != 0 && x2apic)
++ enable_x2apic();
+
+ /*
+ * set up and load the per-CPU TSS
+--- a/arch/x86/kernel/mpparse.c
++++ b/arch/x86/kernel/mpparse.c
+@@ -397,7 +397,9 @@ static int __init smp_read_mpc(struct mp
+ generic_bigsmp_probe();
+ #endif
+
++#ifdef CONFIG_X86_32
+ setup_apic_routing();
++#endif
+ if (!num_processors)
+ printk(KERN_ERR "MPTABLE: no processors registered!\n");
+ return num_processors;
+--- a/arch/x86/kernel/setup.c
++++ b/arch/x86/kernel/setup.c
+@@ -769,6 +769,8 @@ void __init setup_arch(char **cmdline_p)
+ #else
+ num_physpages = max_pfn;
+
++ if (cpu_has_x2apic)
++ check_x2apic();
+
+ /* How many end-of-memory variables you have, grandma! */
+ /* need this before calling reserve_initrd */
+--- a/arch/x86/kernel/smpboot.c
++++ b/arch/x86/kernel/smpboot.c
+@@ -1169,6 +1169,11 @@ void __init native_smp_prepare_cpus(unsi
+ current_thread_info()->cpu = 0; /* needed? */
+ set_cpu_sibling_map(0);
+
++#ifdef CONFIG_X86_64
++ enable_IR_x2apic();
++ setup_apic_routing();
++#endif
++
+ if (smp_sanity_check(max_cpus) < 0) {
+ printk(KERN_INFO "SMP disabled\n");
+ disable_smp();
+--- a/include/asm-x86/apic.h
++++ b/include/asm-x86/apic.h
+@@ -93,12 +93,13 @@ static inline u32 native_apic_msr_read(u
+ return low;
+ }
+
+-#ifdef CONFIG_X86_32
+-extern void apic_wait_icr_idle(void);
+-extern u32 safe_apic_wait_icr_idle(void);
+-extern void apic_icr_write(u32 low, u32 id);
+-#else
+-extern void x2apic_icr_write(u32 low, u32 id);
++#ifndef CONFIG_X86_32
++ extern int x2apic, x2apic_preenabled;
++ extern void check_x2apic(void);
++ extern void enable_x2apic(void);
++ extern void enable_IR_x2apic(void);
++ extern void x2apic_icr_write(u32 low, u32 id);
++#endif
+
+ struct apic_ops {
+ u32 (*read)(u32 reg);
+@@ -119,7 +120,6 @@ extern struct apic_ops *apic_ops;
+ #define apic_icr_write (apic_ops->icr_write)
+ #define apic_wait_icr_idle (apic_ops->wait_icr_idle)
+ #define safe_apic_wait_icr_idle (apic_ops->safe_wait_icr_idle)
+-#endif
+
+ extern int get_physical_broadcast(void);
+