From a1dafe857db56c35878c71560089a4694ac841fd Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 7 Jan 2015 15:31:28 +0800 Subject: [PATCH 01/44] iommu, x86: Restructure setup of the irq remapping feature enable_IR_x2apic() calls setup_irq_remapping_ops() which by default installs the intel dmar remapping ops and then calls the amd iommu irq remapping prepare callback to figure out whether we are running on an AMD machine with irq remapping hardware. Right after that it calls irq_remapping_prepare() which pointlessly checks: if (!remap_ops || !remap_ops->prepare) return -ENODEV; and then calls remap_ops->prepare() which is silly in the AMD case as it got called from setup_irq_remapping_ops() already a few microseconds ago. Simplify this and just collapse everything into irq_remapping_prepare(). The irq_remapping_prepare() remains still silly as it assigns blindly the intel ops, but that's not scope of this patch. The scope here is to move the preperatory work, i.e. memory allocations out of the atomic section which is required to enable irq remapping. Signed-off-by: Thomas Gleixner Tested-by: Borislav Petkov Acked-and-tested-by: Joerg Roedel Cc: Tony Luck Cc: iommu@lists.linux-foundation.org Cc: Joerg Roedel Cc: H. Peter Anvin Cc: Benjamin Herrenschmidt Cc: Yinghai Lu Cc: David Rientjes Cc: HATAYAMA Daisuke Cc: Jan Beulich Cc: Richard Weinberger Cc: Oren Twaig Cc: x86@kernel.org Link: http://lkml.kernel.org/r/20141205084147.232633738@linutronix.de Link: http://lkml.kernel.org/r/1420615903-28253-2-git-send-email-jiang.liu@linux.intel.com Signed-off-by: Jiang Liu Signed-off-by: Thomas Gleixner --- arch/x86/include/asm/irq_remapping.h | 2 -- arch/x86/kernel/apic/apic.c | 3 --- drivers/iommu/irq_remapping.c | 19 +++++++------------ 3 files changed, 7 insertions(+), 17 deletions(-) diff --git a/arch/x86/include/asm/irq_remapping.h b/arch/x86/include/asm/irq_remapping.h index b7747c4c2cf2..f1b619e5a50d 100644 --- a/arch/x86/include/asm/irq_remapping.h +++ b/arch/x86/include/asm/irq_remapping.h @@ -33,7 +33,6 @@ struct irq_cfg; #ifdef CONFIG_IRQ_REMAP -extern void setup_irq_remapping_ops(void); extern int irq_remapping_supported(void); extern void set_irq_remapping_broken(void); extern int irq_remapping_prepare(void); @@ -60,7 +59,6 @@ void irq_remap_modify_chip_defaults(struct irq_chip *chip); #else /* CONFIG_IRQ_REMAP */ -static inline void setup_irq_remapping_ops(void) { } static inline int irq_remapping_supported(void) { return 0; } static inline void set_irq_remapping_broken(void) { } static inline int irq_remapping_prepare(void) { return -ENODEV; } diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index 29b5b18afa27..141f1031013d 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c @@ -1597,9 +1597,6 @@ void __init enable_IR_x2apic(void) int ret, x2apic_enabled = 0; int hardware_init_ret; - /* Make sure irq_remap_ops are initialized */ - setup_irq_remapping_ops(); - hardware_init_ret = irq_remapping_prepare(); if (hardware_init_ret && !x2apic_supported()) return; diff --git a/drivers/iommu/irq_remapping.c b/drivers/iommu/irq_remapping.c index 89c4846683be..91d5884d3ed9 100644 --- a/drivers/iommu/irq_remapping.c +++ b/drivers/iommu/irq_remapping.c @@ -194,16 +194,6 @@ static __init int setup_irqremap(char *str) } early_param("intremap", setup_irqremap); -void __init setup_irq_remapping_ops(void) -{ - remap_ops = &intel_irq_remap_ops; - -#ifdef CONFIG_AMD_IOMMU - if (amd_iommu_irq_ops.prepare() == 0) - remap_ops = &amd_iommu_irq_ops; -#endif -} - void set_irq_remapping_broken(void) { irq_remap_broken = 1; @@ -222,9 +212,14 @@ int irq_remapping_supported(void) int __init irq_remapping_prepare(void) { - if (!remap_ops || !remap_ops->prepare) - return -ENODEV; + remap_ops = &intel_irq_remap_ops; +#ifdef CONFIG_AMD_IOMMU + if (amd_iommu_irq_ops.prepare() == 0) { + remap_ops = &amd_iommu_irq_ops; + return 0; + } +#endif return remap_ops->prepare(); } From 11190302400dc5825e429e79dda30d59c2d9525a Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 7 Jan 2015 15:31:29 +0800 Subject: [PATCH 02/44] iommu/vt-d: Move iommu preparatory allocations to irq_remap_ops.prepare The whole iommu setup for irq remapping is a convoluted mess. The iommu detect function gets called from mem_init() and the prepare callback gets called from enable_IR_x2apic() for unknown reasons. Of course AMD and Intel setup differs in nonsensical ways. Intels prepare callback is explicit while AMDs prepare callback is implicit in setup_irq_remapping_ops() just to be called in the prepare call again. Because all of this gets called from enable_IR_x2apic() and the dmar prepare function merily parses the ACPI tables, but does not allocate memory we end up with memory allocation from irq disabled context later on. AMDs iommu code at least allocates the required memory from the prepare function. That has issues as well, but thats not scope of this patch. The goal of this change is to distangle the allocation from the actual enablement. There is no point to allocate memory from irq disabled regions with GFP_ATOMIC just because it does not matter at that point in the boot stage. It matters with physical hotplug later on. There is another issue with the current setup. Due to the conversion to stacked irqdomains we end up with a call into the irqdomain allocation code from irq disabled context, but that code does GFP_KERNEL allocations rightfully as there is no reason to do preperatory allocations with GFP_ATOMIC. That change caused the allocator code to complain about GFP_KERNEL allocations invoked in atomic context. Boris provided a temporary hackaround which changed the GFP flags if irq_domain_add() got called from atomic context. Not pretty and we really dont want to get this into a mainline release for obvious reasons. Move the ACPI table parsing and the resulting memory allocations from the enable to the prepare function. That allows to get rid of the horrible hackaround in irq_domain_add() later. [Jiang] Rebased onto v3.19 Signed-off-by: Thomas Gleixner Tested-by: Borislav Petkov Acked-and-tested-by: Joerg Roedel Cc: Tony Luck Cc: iommu@lists.linux-foundation.org Cc: Benjamin Herrenschmidt Cc: Yinghai Lu Cc: x86@kernel.org Link: http://lkml.kernel.org/r/20141205084147.313026156@linutronix.de Link: http://lkml.kernel.org/r/1420615903-28253-3-git-send-email-jiang.liu@linux.intel.com Signed-off-by: Jiang Liu Signed-off-by: Thomas Gleixner --- drivers/iommu/intel_irq_remapping.c | 68 +++++++++++++++++++---------- 1 file changed, 46 insertions(+), 22 deletions(-) diff --git a/drivers/iommu/intel_irq_remapping.c b/drivers/iommu/intel_irq_remapping.c index a55b207b9425..2360cb6a8896 100644 --- a/drivers/iommu/intel_irq_remapping.c +++ b/drivers/iommu/intel_irq_remapping.c @@ -595,22 +595,57 @@ static int __init intel_irq_remapping_supported(void) return 1; } +static void __init intel_cleanup_irq_remapping(void) +{ + struct dmar_drhd_unit *drhd; + struct intel_iommu *iommu; + + for_each_iommu(iommu, drhd) { + if (ecap_ir_support(iommu->ecap)) { + iommu_disable_irq_remapping(iommu); + intel_teardown_irq_remapping(iommu); + } + } + + if (x2apic_supported()) + pr_warn("Failed to enable irq remapping. You are vulnerable to irq-injection attacks.\n"); +} + +static int __init intel_prepare_irq_remapping(void) +{ + struct dmar_drhd_unit *drhd; + struct intel_iommu *iommu; + + if (dmar_table_init() < 0) + return -1; + + if (parse_ioapics_under_ir() != 1) { + printk(KERN_INFO "Not enabling interrupt remapping\n"); + goto error; + } + + for_each_iommu(iommu, drhd) { + if (!ecap_ir_support(iommu->ecap)) + continue; + + /* Do the allocations early */ + if (intel_setup_irq_remapping(iommu)) + goto error; + } + return 0; +error: + intel_cleanup_irq_remapping(); + return -1; +} + static int __init intel_enable_irq_remapping(void) { struct dmar_drhd_unit *drhd; struct intel_iommu *iommu; - bool x2apic_present; int setup = 0; int eim = 0; - x2apic_present = x2apic_supported(); - - if (parse_ioapics_under_ir() != 1) { - printk(KERN_INFO "Not enable interrupt remapping\n"); - goto error; - } - - if (x2apic_present) { + if (x2apic_supported()) { pr_info("Queued invalidation will be enabled to support x2apic and Intr-remapping.\n"); eim = !dmar_x2apic_optout(); @@ -678,9 +713,6 @@ static int __init intel_enable_irq_remapping(void) if (!ecap_ir_support(iommu->ecap)) continue; - if (intel_setup_irq_remapping(iommu)) - goto error; - iommu_set_irq_remapping(iommu, eim); setup = 1; } @@ -702,15 +734,7 @@ static int __init intel_enable_irq_remapping(void) return eim ? IRQ_REMAP_X2APIC_MODE : IRQ_REMAP_XAPIC_MODE; error: - for_each_iommu(iommu, drhd) - if (ecap_ir_support(iommu->ecap)) { - iommu_disable_irq_remapping(iommu); - intel_teardown_irq_remapping(iommu); - } - - if (x2apic_present) - pr_warn("Failed to enable irq remapping. You are vulnerable to irq-injection attacks.\n"); - + intel_cleanup_irq_remapping(); return -1; } @@ -1200,7 +1224,7 @@ static int intel_alloc_hpet_msi(unsigned int irq, unsigned int id) struct irq_remap_ops intel_irq_remap_ops = { .supported = intel_irq_remapping_supported, - .prepare = dmar_table_init, + .prepare = intel_prepare_irq_remapping, .enable = intel_enable_irq_remapping, .disable = disable_irq_remapping, .reenable = reenable_irq_remapping, From e3a981d61d156c1a9ea0aac253d2d3f33c081906 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 7 Jan 2015 15:31:30 +0800 Subject: [PATCH 03/44] iommu/vt-d: Convert allocations to GFP_KERNEL No reason anymore to do GFP_ATOMIC allocations which are not harmful in the normal bootup case, but matter in the physical hotplug scenario. Signed-off-by: Thomas Gleixner Tested-by: Borislav Petkov Acked-and-tested-by: Joerg Roedel Cc: Tony Luck Cc: iommu@lists.linux-foundation.org Cc: Benjamin Herrenschmidt Cc: Yinghai Lu Cc: x86@kernel.org Link: http://lkml.kernel.org/r/20141205084147.472428339@linutronix.de Link: http://lkml.kernel.org/r/1420615903-28253-4-git-send-email-jiang.liu@linux.intel.com Signed-off-by: Jiang Liu Signed-off-by: Thomas Gleixner --- drivers/iommu/intel_irq_remapping.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/iommu/intel_irq_remapping.c b/drivers/iommu/intel_irq_remapping.c index 2360cb6a8896..1e7e09327753 100644 --- a/drivers/iommu/intel_irq_remapping.c +++ b/drivers/iommu/intel_irq_remapping.c @@ -481,11 +481,11 @@ static int intel_setup_irq_remapping(struct intel_iommu *iommu) if (iommu->ir_table) return 0; - ir_table = kzalloc(sizeof(struct ir_table), GFP_ATOMIC); + ir_table = kzalloc(sizeof(struct ir_table), GFP_KERNEL); if (!ir_table) return -ENOMEM; - pages = alloc_pages_node(iommu->node, GFP_ATOMIC | __GFP_ZERO, + pages = alloc_pages_node(iommu->node, GFP_KERNEL | __GFP_ZERO, INTR_REMAP_PAGE_ORDER); if (!pages) { From f7ccadac2d3fe373d14a5917c86c499770ebbffc Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 14 Jan 2015 18:31:33 +0100 Subject: [PATCH 04/44] x86/apic: Clear stale x2apic mode If x2apic got disabled on the kernel command line, then the following issue can happen: enable_IR_x2apic() .... x2apic_mode = 1; enable_x2apic(); if (x2apic_disabled) { __disable_x2apic(); return; } That leaves X2APIC disabled in hardware, but x2apic_mode stays 1. So all other code which checks x2apic_mode gets the wrong information. Set x2apic_mode to 0 after disabling it in hardware. This is just a hotfix. The proper solution is to rework this code so it has seperate functions for the initial setup on the boot processor and the secondary cpus, but that's beyond the scope of this fix. Signed-off-by: Thomas Gleixner Cc: Jiang Liu Cc: Tony Luck Cc: iommu@lists.linux-foundation.org Cc: H. Peter Anvin Cc: Joerg Roedel Cc: Benjamin Herrenschmidt Cc: Yinghai Lu Cc: Borislav Petkov Cc: David Rientjes Cc: HATAYAMA Daisuke Cc: Jan Beulich Cc: Richard Weinberger Cc: Oren Twaig --- arch/x86/kernel/apic/apic.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index 141f1031013d..8a81a681836e 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c @@ -1559,6 +1559,7 @@ void enable_x2apic(void) rdmsrl(MSR_IA32_APICBASE, msr); if (x2apic_disabled) { __disable_x2apic(msr); + x2apic_mode = 0; return; } From 2599094f6e381128cc274311758add604c1e108a Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Wed, 7 Jan 2015 15:31:31 +0800 Subject: [PATCH 05/44] x86/apic: Panic if kernel doesn't support x2apic but BIOS has enabled x2apic When kernel doesn't support X2APIC but BIOS has enabled X2APIC, system may panic or hang without useful messages. On the other hand, it's hard to dynamically disable X2APIC when CONFIG_X86_X2APIC is disabled. So panic with a clear message in such a case. Now system panics as below when X2APIC is disabled and interrupt remapping is enabled: [ 0.316118] LAPIC pending interrupts after 512 EOI [ 0.322126] ..TIMER: vector=0x30 apic1=0 pin1=2 apic2=-1 pin2=-1 [ 0.368655] Kernel panic - not syncing: timer doesn't work through Interrupt-remapped IO-APIC [ 0.378300] CPU: 0 PID: 1 Comm: swapper/0 Not tainted 3.18.0+ #340 [ 0.385300] Hardware name: Intel Corporation BRICKLAND/BRICKLAND, BIOS BRIVTIN1.86B.0051.L05.1406240953 06/24/2014 [ 0.396997] ffff88046dc03000 ffff88046c307dd8 ffffffff8179dada 00000000000043f2 [ 0.405629] ffffffff81a92158 ffff88046c307e58 ffffffff8179b757 0000000000000002 [ 0.414261] 0000000000000008 ffff88046c307e68 ffff88046c307e08 ffffffff813ad82b [ 0.422890] Call Trace: [ 0.425711] [] dump_stack+0x45/0x57 [ 0.431533] [] panic+0xc1/0x1f5 [ 0.436978] [] ? delay_tsc+0x3b/0x70 [ 0.442910] [] panic_if_irq_remap+0x1c/0x20 [ 0.449524] [] setup_IO_APIC+0x405/0x82e [ 0.464979] [] native_smp_prepare_cpus+0x2d9/0x31c [ 0.472274] [] kernel_init_freeable+0xd6/0x223 [ 0.479170] [] ? rest_init+0x80/0x80 [ 0.485099] [] kernel_init+0xe/0xf0 [ 0.490932] [] ret_from_fork+0x7c/0xb0 [ 0.497054] [] ? rest_init+0x80/0x80 [ 0.502983] ---[ end Kernel panic - not syncing: timer doesn't work through Interrupt-remapped IO-APIC System hangs as below when X2APIC and interrupt remapping are both disabled: [ 1.102782] pci 0000:00:02.0: System wakeup disabled by ACPI [ 1.109351] pci 0000:00:03.0: System wakeup disabled by ACPI [ 1.115915] pci 0000:00:03.2: System wakeup disabled by ACPI [ 1.122479] pci 0000:00:03.3: System wakeup disabled by ACPI [ 1.132274] pci 0000:00:1c.0: Enabling MPC IRBNCE [ 1.137620] pci 0000:00:1c.0: Intel PCH root port ACS workaround enabled [ 1.145239] pci 0000:00:1c.0: System wakeup disabled by ACPI [ 1.151790] pci 0000:00:1c.7: Enabling MPC IRBNCE [ 1.157128] pci 0000:00:1c.7: Intel PCH root port ACS workaround enabled [ 1.164748] pci 0000:00:1c.7: System wakeup disabled by ACPI [ 1.171447] pci 0000:00:1e.0: System wakeup disabled by ACPI [ 1.178612] acpiphp: Slot [8] registered [ 1.183095] pci 0000:00:02.0: PCI bridge to [bus 01] [ 1.188867] acpiphp: Slot [2] registered With this patch applied, the system panics in both cases with a proper panic message. Signed-off-by: Jiang Liu Cc: Tony Luck Cc: iommu@lists.linux-foundation.org Cc: H. Peter Anvin Cc: Joerg Roedel Cc: Benjamin Herrenschmidt Cc: Yinghai Lu Cc: Borislav Petkov Cc: David Rientjes Cc: HATAYAMA Daisuke Cc: Jan Beulich Cc: Richard Weinberger Cc: Oren Twaig Link: http://lkml.kernel.org/r/1420615903-28253-5-git-send-email-jiang.liu@linux.intel.com Signed-off-by: Thomas Gleixner --- arch/x86/kernel/apic/apic.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index 8a81a681836e..544673304de0 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c @@ -1598,6 +1598,14 @@ void __init enable_IR_x2apic(void) int ret, x2apic_enabled = 0; int hardware_init_ret; + if (!IS_ENABLED(CONFIG_X86_X2APIC)) { + u64 msr; + + rdmsrl(MSR_IA32_APICBASE, msr); + if (msr & X2APIC_ENABLE) + panic("BIOS has enabled x2apic but kernel doesn't support x2apic, please disable x2apic in BIOS.\n"); + } + hardware_init_ret = irq_remapping_prepare(); if (hardware_init_ret && !x2apic_supported()) return; From 7f530a2771fe7ea6a068340c9e22f814edfcc3c4 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Wed, 7 Jan 2015 15:31:32 +0800 Subject: [PATCH 06/44] x86/apic: Kill useless variable x2apic_enabled in function enable_IR_x2apic() Local variable x2apic_enabled has been assigned to but never referred, so kill it. Signed-off-by: Jiang Liu Cc: Tony Luck Cc: iommu@lists.linux-foundation.org Cc: H. Peter Anvin Cc: Joerg Roedel Cc: Benjamin Herrenschmidt Cc: Yinghai Lu Cc: Borislav Petkov Cc: David Rientjes Cc: HATAYAMA Daisuke Cc: Jan Beulich Cc: Richard Weinberger Cc: Oren Twaig Link: http://lkml.kernel.org/r/1420615903-28253-6-git-send-email-jiang.liu@linux.intel.com Signed-off-by: Thomas Gleixner --- arch/x86/kernel/apic/apic.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index 544673304de0..2dbd3a0ae9f1 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c @@ -1595,7 +1595,7 @@ int __init enable_IR(void) void __init enable_IR_x2apic(void) { unsigned long flags; - int ret, x2apic_enabled = 0; + int ret; int hardware_init_ret; if (!IS_ENABLED(CONFIG_X86_X2APIC)) { @@ -1653,8 +1653,6 @@ void __init enable_IR_x2apic(void) goto skip_x2apic; } - x2apic_enabled = 1; - if (x2apic_supported() && !x2apic_mode) { x2apic_mode = 1; enable_x2apic(); From 89356cf20ecb0b9975b1dad9ed605dd4c6e68bcd Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Wed, 7 Jan 2015 15:31:33 +0800 Subject: [PATCH 07/44] x86/apic: Correctly detect X2APIC status in function enable_IR() X2APIC will be disabled if user specifies "nox2apic" on kernel command line, even when x2apic_preenabled is true. So correctly detect X2APIC status by using x2apic_enabled() instead of x2apic_preenabled. Signed-off-by: Jiang Liu Cc: Tony Luck Cc: iommu@lists.linux-foundation.org Cc: H. Peter Anvin Cc: Joerg Roedel Cc: Benjamin Herrenschmidt Cc: Yinghai Lu Cc: Borislav Petkov Cc: David Rientjes Cc: HATAYAMA Daisuke Cc: Jan Beulich Cc: Richard Weinberger Cc: Oren Twaig Link: http://lkml.kernel.org/r/1420615903-28253-7-git-send-email-jiang.liu@linux.intel.com Signed-off-by: Thomas Gleixner --- arch/x86/kernel/apic/apic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index 2dbd3a0ae9f1..11358df3bd08 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c @@ -1581,7 +1581,7 @@ int __init enable_IR(void) return -1; } - if (!x2apic_preenabled && skip_ioapic_setup) { + if (!x2apic_enabled() && skip_ioapic_setup) { pr_info("Skipped enabling intr-remap because of skipping " "io-apic setup\n"); return -1; From 07806c50bddd2f0493f97584198733946952409c Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Wed, 7 Jan 2015 15:31:34 +0800 Subject: [PATCH 08/44] x86/apic: Refine enable_IR_x2apic() and related functions Refine enable_IR_x2apic() and related functions for better readability. [ tglx: Removed the XAPIC mode change and split it out into a seperate patch. Added comments. ] Signed-off-by: Jiang Liu Cc: Tony Luck Cc: iommu@lists.linux-foundation.org Cc: H. Peter Anvin Cc: Joerg Roedel Cc: Benjamin Herrenschmidt Cc: Yinghai Lu Cc: Borislav Petkov Cc: David Rientjes Cc: HATAYAMA Daisuke Cc: Jan Beulich Cc: Richard Weinberger Cc: Oren Twaig Link: http://lkml.kernel.org/r/1420615903-28253-8-git-send-email-jiang.liu@linux.intel.com Signed-off-by: Thomas Gleixner --- arch/x86/kernel/apic/apic.c | 94 +++++++++++++++++++------------------ 1 file changed, 48 insertions(+), 46 deletions(-) diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index 11358df3bd08..fa77be8d0b17 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c @@ -1573,7 +1573,7 @@ void enable_x2apic(void) } #endif /* CONFIG_X86_X2APIC */ -int __init enable_IR(void) +static int __init try_to_enable_IR(void) { #ifdef CONFIG_IRQ_REMAP if (!irq_remapping_supported()) { @@ -1586,17 +1586,51 @@ int __init enable_IR(void) "io-apic setup\n"); return -1; } - - return irq_remapping_enable(); #endif - return -1; + return irq_remapping_enable(); +} + +static __init void try_to_enable_x2apic(int ir_stat) +{ +#ifdef CONFIG_X86_X2APIC + if (!x2apic_supported()) + return; + + if (ir_stat < 0) { + /* IR is required if there is APIC ID > 255 even when running + * under KVM + */ + if (max_physical_apicid > 255 || + !hypervisor_x2apic_available()) { + pr_info("IRQ remapping doesn't support X2APIC mode, disable x2apic.\n"); + if (x2apic_preenabled) + disable_x2apic(); + return; + } + + /* + * without IR all CPUs can be addressed by IOAPIC/MSI + * only in physical mode + */ + x2apic_force_phys(); + + } else if (ir_stat == IRQ_REMAP_XAPIC_MODE) { + pr_info("x2apic not enabled, IRQ remapping is in xapic mode\n"); + return; + } + + if (!x2apic_mode) { + x2apic_mode = 1; + enable_x2apic(); + pr_info("Enabled x2apic\n"); + } +#endif } void __init enable_IR_x2apic(void) { unsigned long flags; - int ret; - int hardware_init_ret; + int ret, ir_stat; if (!IS_ENABLED(CONFIG_X86_X2APIC)) { u64 msr; @@ -1606,8 +1640,8 @@ void __init enable_IR_x2apic(void) panic("BIOS has enabled x2apic but kernel doesn't support x2apic, please disable x2apic in BIOS.\n"); } - hardware_init_ret = irq_remapping_prepare(); - if (hardware_init_ret && !x2apic_supported()) + ir_stat = irq_remapping_prepare(); + if (ir_stat < 0 && !x2apic_supported()) return; ret = save_ioapic_entries(); @@ -1622,45 +1656,13 @@ void __init enable_IR_x2apic(void) if (x2apic_preenabled && nox2apic) disable_x2apic(); + /* If irq_remapping_prepare() succeded, try to enable it */ + if (ir_stat >= 0) + ir_stat = try_to_enable_IR(); + /* ir_stat contains the remap mode or an error code */ + try_to_enable_x2apic(ir_stat); - if (hardware_init_ret) - ret = -1; - else - ret = enable_IR(); - - if (!x2apic_supported()) - goto skip_x2apic; - - if (ret < 0) { - /* IR is required if there is APIC ID > 255 even when running - * under KVM - */ - if (max_physical_apicid > 255 || - !hypervisor_x2apic_available()) { - if (x2apic_preenabled) - disable_x2apic(); - goto skip_x2apic; - } - /* - * without IR all CPUs can be addressed by IOAPIC/MSI - * only in physical mode - */ - x2apic_force_phys(); - } - - if (ret == IRQ_REMAP_XAPIC_MODE) { - pr_info("x2apic not enabled, IRQ remapping is in xapic mode\n"); - goto skip_x2apic; - } - - if (x2apic_supported() && !x2apic_mode) { - x2apic_mode = 1; - enable_x2apic(); - pr_info("Enabled x2apic\n"); - } - -skip_x2apic: - if (ret < 0) /* IR enabling failed */ + if (ir_stat < 0) restore_ioapic_entries(); legacy_pic->restore_mask(); local_irq_restore(flags); From ef1b2b8ad13858ab2f87c05261b8ce3253f90af9 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Wed, 7 Jan 2015 15:31:34 +0800 Subject: [PATCH 09/44] x86/apic: Handle XAPIC remap mode proper. If remapping is in XAPIC mode, the setup code just skips X2APIC initialization without checking max CPU APIC ID in system, which may cause problem if system has a CPU with APIC ID bigger than 255. Handle IR in XAPIC mode the same way as if remapping is disabled. [ tglx: Split out from previous patch ] Signed-off-by: Jiang Liu Cc: Tony Luck Cc: iommu@lists.linux-foundation.org Cc: H. Peter Anvin Cc: Joerg Roedel Cc: Benjamin Herrenschmidt Cc: Yinghai Lu Cc: Borislav Petkov Cc: David Rientjes Cc: HATAYAMA Daisuke Cc: Jan Beulich Cc: Richard Weinberger Cc: Oren Twaig Link: http://lkml.kernel.org/r/1420615903-28253-8-git-send-email-jiang.liu@linux.intel.com Signed-off-by: Thomas Gleixner --- arch/x86/kernel/apic/apic.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index fa77be8d0b17..04aec6bc7481 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c @@ -1596,7 +1596,7 @@ static __init void try_to_enable_x2apic(int ir_stat) if (!x2apic_supported()) return; - if (ir_stat < 0) { + if (ir_stat != IRQ_REMAP_X2APIC_MODE) { /* IR is required if there is APIC ID > 255 even when running * under KVM */ @@ -1613,10 +1613,6 @@ static __init void try_to_enable_x2apic(int ir_stat) * only in physical mode */ x2apic_force_phys(); - - } else if (ir_stat == IRQ_REMAP_XAPIC_MODE) { - pr_info("x2apic not enabled, IRQ remapping is in xapic mode\n"); - return; } if (!x2apic_mode) { From 2966d9566beb39c53477c96525820b9415de7a7d Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Wed, 7 Jan 2015 15:31:35 +0800 Subject: [PATCH 10/44] iommu/vt-d: Prepare for killing function irq_remapping_supported() Prepare for killing function irq_remapping_supported() by moving code from intel_irq_remapping_supported() into intel_prepare_irq_remapping(). Combined with patch from Joerg at https://lkml.org/lkml/2014/12/15/487, so assume an signed-off from Joerg. Signed-off-by: Jiang Liu Signed-off-by: Joerg Roedel Tested-by: Joerg Roedel Cc: Tony Luck Cc: iommu@lists.linux-foundation.org Cc: Benjamin Herrenschmidt Cc: Yinghai Lu Cc: Borislav Petkov Link: http://lkml.kernel.org/r/1420615903-28253-9-git-send-email-jiang.liu@linux.intel.com Signed-off-by: Thomas Gleixner --- drivers/iommu/intel_irq_remapping.c | 58 +++++++++++++---------------- 1 file changed, 25 insertions(+), 33 deletions(-) diff --git a/drivers/iommu/intel_irq_remapping.c b/drivers/iommu/intel_irq_remapping.c index 1e7e09327753..8ccc7aa7e43a 100644 --- a/drivers/iommu/intel_irq_remapping.c +++ b/drivers/iommu/intel_irq_remapping.c @@ -568,30 +568,6 @@ static int __init dmar_x2apic_optout(void) static int __init intel_irq_remapping_supported(void) { - struct dmar_drhd_unit *drhd; - struct intel_iommu *iommu; - - if (disable_irq_remap) - return 0; - if (irq_remap_broken) { - printk(KERN_WARNING - "This system BIOS has enabled interrupt remapping\n" - "on a chipset that contains an erratum making that\n" - "feature unstable. To maintain system stability\n" - "interrupt remapping is being disabled. Please\n" - "contact your BIOS vendor for an update\n"); - add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_STILL_OK); - disable_irq_remap = 1; - return 0; - } - - if (!dmar_ir_support()) - return 0; - - for_each_iommu(iommu, drhd) - if (!ecap_ir_support(iommu->ecap)) - return 0; - return 1; } @@ -616,26 +592,42 @@ static int __init intel_prepare_irq_remapping(void) struct dmar_drhd_unit *drhd; struct intel_iommu *iommu; + /* First check whether IRQ remapping should be enabled */ + if (disable_irq_remap) + return -ENODEV; + + if (irq_remap_broken) { + printk(KERN_WARNING + "This system BIOS has enabled interrupt remapping\n" + "on a chipset that contains an erratum making that\n" + "feature unstable. To maintain system stability\n" + "interrupt remapping is being disabled. Please\n" + "contact your BIOS vendor for an update\n"); + add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_STILL_OK); + disable_irq_remap = 1; + return -ENODEV; + } + if (dmar_table_init() < 0) - return -1; + return -ENODEV; + + if (!dmar_ir_support()) + return -ENODEV; if (parse_ioapics_under_ir() != 1) { printk(KERN_INFO "Not enabling interrupt remapping\n"); goto error; } - for_each_iommu(iommu, drhd) { - if (!ecap_ir_support(iommu->ecap)) - continue; - - /* Do the allocations early */ - if (intel_setup_irq_remapping(iommu)) + for_each_iommu(iommu, drhd) + if (!ecap_ir_support(iommu->ecap) || + intel_setup_irq_remapping(iommu)) goto error; - } return 0; + error: intel_cleanup_irq_remapping(); - return -1; + return -ENODEV; } static int __init intel_enable_irq_remapping(void) From 69cf1d8a1286a7bfbeec497b69c43cc7ebb2a787 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Wed, 7 Jan 2015 15:31:36 +0800 Subject: [PATCH 11/44] iommu/vt-d: Allocate IRQ remapping data structures only for all IOMMUs IRQ remapping is only supported when all IOMMUs in the system support it. So check if all IOMMUs in the system support IRQ remapping before doing the allocations. [Jiang] 1) Rebased to v3.19. 2) Remove redundant check of ecap_ir_support(iommu->ecap) in function intel_enable_irq_remapping(). Signed-off-by: Joerg Roedel Signed-off-by: Jiang Liu Tested-by: Joerg Roedel Cc: Tony Luck Cc: iommu@lists.linux-foundation.org Cc: Benjamin Herrenschmidt Cc: Yinghai Lu Cc: Borislav Petkov Link: http://lkml.kernel.org/r/1420615903-28253-10-git-send-email-jiang.liu@linux.intel.com Signed-off-by: Thomas Gleixner --- drivers/iommu/intel_irq_remapping.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/drivers/iommu/intel_irq_remapping.c b/drivers/iommu/intel_irq_remapping.c index 8ccc7aa7e43a..137663bd5da2 100644 --- a/drivers/iommu/intel_irq_remapping.c +++ b/drivers/iommu/intel_irq_remapping.c @@ -619,10 +619,16 @@ static int __init intel_prepare_irq_remapping(void) goto error; } + /* First make sure all IOMMUs support IRQ remapping */ for_each_iommu(iommu, drhd) - if (!ecap_ir_support(iommu->ecap) || - intel_setup_irq_remapping(iommu)) + if (!ecap_ir_support(iommu->ecap)) goto error; + + /* Do the allocations early */ + for_each_iommu(iommu, drhd) + if (intel_setup_irq_remapping(iommu)) + goto error; + return 0; error: @@ -673,16 +679,12 @@ static int __init intel_enable_irq_remapping(void) /* * check for the Interrupt-remapping support */ - for_each_iommu(iommu, drhd) { - if (!ecap_ir_support(iommu->ecap)) - continue; - + for_each_iommu(iommu, drhd) if (eim && !ecap_eim_support(iommu->ecap)) { printk(KERN_INFO "DRHD %Lx: EIM not supported by DRHD, " " ecap %Lx\n", drhd->reg_base_addr, iommu->ecap); goto error; } - } /* * Enable queued invalidation for all the DRHD's. @@ -702,9 +704,6 @@ static int __init intel_enable_irq_remapping(void) * Setup Interrupt-remapping for all the DRHD's now. */ for_each_iommu(iommu, drhd) { - if (!ecap_ir_support(iommu->ecap)) - continue; - iommu_set_irq_remapping(iommu, eim); setup = 1; } From 13d09b6603df9df3aa3e410bc2a876889a55c744 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Wed, 7 Jan 2015 15:31:37 +0800 Subject: [PATCH 12/44] iommu/vt-d: Allow IR works in XAPIC mode though CPU works in X2APIC mode Currently if CPU supports X2APIC, IR hardware must work in X2APIC mode or disabled. Change the code to support IR working in XAPIC mode when CPU supports X2APIC. Then the CPU APIC driver will decide how to handle such as configuration by: 1) Disabling X2APIC mode 2) Forcing X2APIC physical mode This change also fixes a live locking when 1) BIOS enables CPU X2APIC 2) DMAR table disables X2APIC mode or IR hardware doesn't support X2APIC with following messages: [ 37.863463] dmar: INTR-REMAP: Request device [[f0:1f.7] fault index 2 [ 37.863463] INTR-REMAP:[fault reason 36] Detected reserved fields in the IRTE entry [ 37.879372] dmar: INTR-REMAP: Request device [[f0:1f.7] fault index 2 [ 37.879372] INTR-REMAP:[fault reason 36] Detected reserved fields in the IRTE entry [ 37.895282] dmar: INTR-REMAP: Request device [[f0:1f.7] fault index 2 [ 37.895282] INTR-REMAP:[fault reason 36] Detected reserved fields in the IRTE entry [ 37.911192] dmar: INTR-REMAP: Request device [[f0:1f.7] fault index 2 Signed-off-by: Jiang Liu Tested-by: Joerg Roedel Cc: Tony Luck Cc: iommu@lists.linux-foundation.org Cc: Benjamin Herrenschmidt Cc: Yinghai Lu Cc: Borislav Petkov Link: http://lkml.kernel.org/r/1420615903-28253-11-git-send-email-jiang.liu@linux.intel.com Signed-off-by: Thomas Gleixner --- drivers/iommu/intel_irq_remapping.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/iommu/intel_irq_remapping.c b/drivers/iommu/intel_irq_remapping.c index 137663bd5da2..9d67c12c2ffb 100644 --- a/drivers/iommu/intel_irq_remapping.c +++ b/drivers/iommu/intel_irq_remapping.c @@ -32,8 +32,9 @@ struct hpet_scope { }; #define IR_X2APIC_MODE(mode) (mode ? (1 << 11) : 0) -#define IRTE_DEST(dest) ((x2apic_mode) ? dest : dest << 8) +#define IRTE_DEST(dest) ((eim_mode) ? dest : dest << 8) +static int __read_mostly eim_mode; static struct ioapic_scope ir_ioapic[MAX_IO_APICS]; static struct hpet_scope ir_hpet[MAX_HPET_TBS]; @@ -644,8 +645,6 @@ static int __init intel_enable_irq_remapping(void) int eim = 0; if (x2apic_supported()) { - pr_info("Queued invalidation will be enabled to support x2apic and Intr-remapping.\n"); - eim = !dmar_x2apic_optout(); if (!eim) printk(KERN_WARNING @@ -683,8 +682,11 @@ static int __init intel_enable_irq_remapping(void) if (eim && !ecap_eim_support(iommu->ecap)) { printk(KERN_INFO "DRHD %Lx: EIM not supported by DRHD, " " ecap %Lx\n", drhd->reg_base_addr, iommu->ecap); - goto error; + eim = 0; } + eim_mode = eim; + if (eim) + pr_info("Queued invalidation will be enabled to support x2apic and Intr-remapping.\n"); /* * Enable queued invalidation for all the DRHD's. From 5fcee53ce705d49c766f8a302c7e93bdfc33c124 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Wed, 7 Jan 2015 15:31:38 +0800 Subject: [PATCH 13/44] x86/apic: Only disable CPU x2apic mode when necessary When interrupt remapping hardware is not in X2APIC, CPU X2APIC mode will be disabled if: 1) Maximum CPU APIC ID is bigger than 255 2) hypervisior doesn't support x2apic mode. But we should only check whether hypervisor supports X2APIC mode when hypervisor(CONFIG_HYPERVISOR_GUEST) is enabled, otherwise X2APIC will always be disabled when CONFIG_HYPERVISOR_GUEST is disabled and IR doesn't work in X2APIC mode. Signed-off-by: Jiang Liu Tested-by: Joerg Roedel Cc: Tony Luck Cc: iommu@lists.linux-foundation.org Cc: H. Peter Anvin Cc: Benjamin Herrenschmidt Cc: Yinghai Lu Cc: Borislav Petkov Cc: David Rientjes Cc: HATAYAMA Daisuke Cc: Jan Beulich Cc: Richard Weinberger Cc: Oren Twaig Link: http://lkml.kernel.org/r/1420615903-28253-12-git-send-email-jiang.liu@linux.intel.com Signed-off-by: Thomas Gleixner --- arch/x86/kernel/apic/apic.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index 04aec6bc7481..2f16116ced90 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c @@ -1601,7 +1601,8 @@ static __init void try_to_enable_x2apic(int ir_stat) * under KVM */ if (max_physical_apicid > 255 || - !hypervisor_x2apic_available()) { + (IS_ENABLED(CONFIG_HYPERVISOR_GUEST) && + !hypervisor_x2apic_available())) { pr_info("IRQ remapping doesn't support X2APIC mode, disable x2apic.\n"); if (x2apic_preenabled) disable_x2apic(); From 84d0779304b5c45134311dfc31b5a2325ce3ad84 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Wed, 7 Jan 2015 15:31:39 +0800 Subject: [PATCH 14/44] iommu/amd: Check for irq-remap support amd_iommu_prepare() This allows to get rid of the irq_remapping_supported() function and all its call-backs into the Intel and AMD IOMMU drivers. Signed-off-by: Joerg Roedel Signed-off-by: Jiang Liu Tested-by: Joerg Roedel Cc: Tony Luck Cc: iommu@lists.linux-foundation.org Cc: Benjamin Herrenschmidt Cc: Yinghai Lu Cc: Borislav Petkov Link: http://lkml.kernel.org/r/1420615903-28253-13-git-send-email-jiang.liu@linux.intel.com Signed-off-by: Thomas Gleixner --- drivers/iommu/amd_iommu_init.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c index b0522f15730f..0039f87f48b8 100644 --- a/drivers/iommu/amd_iommu_init.c +++ b/drivers/iommu/amd_iommu_init.c @@ -2123,6 +2123,9 @@ static int __init iommu_go_to_state(enum iommu_init_state state) #ifdef CONFIG_IRQ_REMAP int __init amd_iommu_prepare(void) { + if (!amd_iommu_irq_remap) + return -1; + return iommu_go_to_state(IOMMU_ACPI_FINISHED); } From c392f56c946033bd136043079a62b9188888828d Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Wed, 7 Jan 2015 15:31:40 +0800 Subject: [PATCH 15/44] iommu/irq_remapping: Kill function irq_remapping_supported() and related code Simplify irq_remapping code by killing irq_remapping_supported() and related interfaces. Joerg posted a similar patch at https://lkml.org/lkml/2014/12/15/490, so assume an signed-off from Joerg. Signed-off-by: Jiang Liu Signed-off-by: Joerg Roedel Tested-by: Joerg Roedel Cc: Tony Luck Cc: iommu@lists.linux-foundation.org Cc: H. Peter Anvin Cc: Benjamin Herrenschmidt Cc: Yinghai Lu Cc: Borislav Petkov Cc: David Rientjes Cc: HATAYAMA Daisuke Cc: Jan Beulich Cc: Richard Weinberger Cc: Oren Twaig Link: http://lkml.kernel.org/r/1420615903-28253-14-git-send-email-jiang.liu@linux.intel.com Signed-off-by: Thomas Gleixner --- arch/x86/include/asm/irq_remapping.h | 2 -- arch/x86/kernel/apic/apic.c | 7 +------ drivers/iommu/amd_iommu.c | 1 - drivers/iommu/amd_iommu_init.c | 5 ----- drivers/iommu/amd_iommu_proto.h | 1 - drivers/iommu/intel_irq_remapping.c | 6 ------ drivers/iommu/irq_remapping.c | 14 +++----------- drivers/iommu/irq_remapping.h | 3 --- 8 files changed, 4 insertions(+), 35 deletions(-) diff --git a/arch/x86/include/asm/irq_remapping.h b/arch/x86/include/asm/irq_remapping.h index f1b619e5a50d..6224d316c405 100644 --- a/arch/x86/include/asm/irq_remapping.h +++ b/arch/x86/include/asm/irq_remapping.h @@ -33,7 +33,6 @@ struct irq_cfg; #ifdef CONFIG_IRQ_REMAP -extern int irq_remapping_supported(void); extern void set_irq_remapping_broken(void); extern int irq_remapping_prepare(void); extern int irq_remapping_enable(void); @@ -59,7 +58,6 @@ void irq_remap_modify_chip_defaults(struct irq_chip *chip); #else /* CONFIG_IRQ_REMAP */ -static inline int irq_remapping_supported(void) { return 0; } static inline void set_irq_remapping_broken(void) { } static inline int irq_remapping_prepare(void) { return -ENODEV; } static inline int irq_remapping_enable(void) { return -ENODEV; } diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index 2f16116ced90..35e6d09294ed 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c @@ -1575,12 +1575,7 @@ void enable_x2apic(void) static int __init try_to_enable_IR(void) { -#ifdef CONFIG_IRQ_REMAP - if (!irq_remapping_supported()) { - pr_debug("intr-remapping not supported\n"); - return -1; - } - +#ifdef CONFIG_X86_IO_APIC if (!x2apic_enabled() && skip_ioapic_setup) { pr_info("Skipped enabling intr-remap because of skipping " "io-apic setup\n"); diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c index 98024856df07..59de6364a910 100644 --- a/drivers/iommu/amd_iommu.c +++ b/drivers/iommu/amd_iommu.c @@ -4284,7 +4284,6 @@ static int alloc_hpet_msi(unsigned int irq, unsigned int id) } struct irq_remap_ops amd_iommu_irq_ops = { - .supported = amd_iommu_supported, .prepare = amd_iommu_prepare, .enable = amd_iommu_enable, .disable = amd_iommu_disable, diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c index 0039f87f48b8..970979ecbebb 100644 --- a/drivers/iommu/amd_iommu_init.c +++ b/drivers/iommu/amd_iommu_init.c @@ -2129,11 +2129,6 @@ int __init amd_iommu_prepare(void) return iommu_go_to_state(IOMMU_ACPI_FINISHED); } -int __init amd_iommu_supported(void) -{ - return amd_iommu_irq_remap ? 1 : 0; -} - int __init amd_iommu_enable(void) { int ret; diff --git a/drivers/iommu/amd_iommu_proto.h b/drivers/iommu/amd_iommu_proto.h index 95ed6deae47f..861af9d8338a 100644 --- a/drivers/iommu/amd_iommu_proto.h +++ b/drivers/iommu/amd_iommu_proto.h @@ -33,7 +33,6 @@ extern void amd_iommu_init_notifier(void); extern void amd_iommu_init_api(void); /* Needed for interrupt remapping */ -extern int amd_iommu_supported(void); extern int amd_iommu_prepare(void); extern int amd_iommu_enable(void); extern void amd_iommu_disable(void); diff --git a/drivers/iommu/intel_irq_remapping.c b/drivers/iommu/intel_irq_remapping.c index 9d67c12c2ffb..fb72bd5f438c 100644 --- a/drivers/iommu/intel_irq_remapping.c +++ b/drivers/iommu/intel_irq_remapping.c @@ -567,11 +567,6 @@ static int __init dmar_x2apic_optout(void) return dmar->flags & DMAR_X2APIC_OPT_OUT; } -static int __init intel_irq_remapping_supported(void) -{ - return 1; -} - static void __init intel_cleanup_irq_remapping(void) { struct dmar_drhd_unit *drhd; @@ -1216,7 +1211,6 @@ static int intel_alloc_hpet_msi(unsigned int irq, unsigned int id) } struct irq_remap_ops intel_irq_remap_ops = { - .supported = intel_irq_remapping_supported, .prepare = intel_prepare_irq_remapping, .enable = intel_enable_irq_remapping, .disable = disable_irq_remapping, diff --git a/drivers/iommu/irq_remapping.c b/drivers/iommu/irq_remapping.c index 91d5884d3ed9..e7449b42504d 100644 --- a/drivers/iommu/irq_remapping.c +++ b/drivers/iommu/irq_remapping.c @@ -199,19 +199,11 @@ void set_irq_remapping_broken(void) irq_remap_broken = 1; } -int irq_remapping_supported(void) -{ - if (disable_irq_remap) - return 0; - - if (!remap_ops || !remap_ops->supported) - return 0; - - return remap_ops->supported(); -} - int __init irq_remapping_prepare(void) { + if (disable_irq_remap) + return -ENOSYS; + remap_ops = &intel_irq_remap_ops; #ifdef CONFIG_AMD_IOMMU diff --git a/drivers/iommu/irq_remapping.h b/drivers/iommu/irq_remapping.h index fde250f86e60..a8edfea0ab5d 100644 --- a/drivers/iommu/irq_remapping.h +++ b/drivers/iommu/irq_remapping.h @@ -38,9 +38,6 @@ extern int no_x2apic_optout; extern int irq_remapping_enabled; struct irq_remap_ops { - /* Check whether Interrupt Remapping is supported */ - int (*supported)(void); - /* Initializes hardware and makes it ready for remapping interrupts */ int (*prepare)(void); From 30969e34ae6edf10a003f6c0be1fecf6dadcd421 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Wed, 7 Jan 2015 15:31:41 +0800 Subject: [PATCH 16/44] iommu/irq_remapping: Refine function irq_remapping_prepare() for maintenance Assign intel_irq_remap_ops to remap_ops only if intel_irq_remap_ops.prepare() succeeds. Signed-off-by: Jiang Liu Tested-by: Joerg Roedel Cc: Tony Luck Cc: iommu@lists.linux-foundation.org Cc: Benjamin Herrenschmidt Cc: Yinghai Lu Cc: Borislav Petkov Link: http://lkml.kernel.org/r/1420615903-28253-15-git-send-email-jiang.liu@linux.intel.com Signed-off-by: Thomas Gleixner --- drivers/iommu/irq_remapping.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/iommu/irq_remapping.c b/drivers/iommu/irq_remapping.c index e7449b42504d..7d85d2ba0e8b 100644 --- a/drivers/iommu/irq_remapping.c +++ b/drivers/iommu/irq_remapping.c @@ -204,15 +204,15 @@ int __init irq_remapping_prepare(void) if (disable_irq_remap) return -ENOSYS; - remap_ops = &intel_irq_remap_ops; - -#ifdef CONFIG_AMD_IOMMU - if (amd_iommu_irq_ops.prepare() == 0) { + if (intel_irq_remap_ops.prepare() == 0) + remap_ops = &intel_irq_remap_ops; + else if (IS_ENABLED(CONFIG_AMD_IOMMU) && + amd_iommu_irq_ops.prepare() == 0) remap_ops = &amd_iommu_irq_ops; - return 0; - } -#endif - return remap_ops->prepare(); + else + return -ENOSYS; + + return 0; } int __init irq_remapping_enable(void) From 7fa1c842caca3b1d8a55a64033403cab8ca8583a Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Wed, 7 Jan 2015 15:31:42 +0800 Subject: [PATCH 17/44] iommu/irq_remapping: Change variable disable_irq_remap to be static Change variable disable_irq_remap to be static and simplify the code. Signed-off-by: Jiang Liu Tested-by: Joerg Roedel Cc: Tony Luck Cc: iommu@lists.linux-foundation.org Cc: Benjamin Herrenschmidt Cc: Yinghai Lu Cc: Borislav Petkov Link: http://lkml.kernel.org/r/1420615903-28253-16-git-send-email-jiang.liu@linux.intel.com Signed-off-by: Thomas Gleixner --- drivers/iommu/amd_iommu_init.c | 6 +----- drivers/iommu/intel_irq_remapping.c | 5 ----- drivers/iommu/irq_remapping.c | 3 +-- drivers/iommu/irq_remapping.h | 2 -- 4 files changed, 2 insertions(+), 14 deletions(-) diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c index 970979ecbebb..e430dc8dffdf 100644 --- a/drivers/iommu/amd_iommu_init.c +++ b/drivers/iommu/amd_iommu_init.c @@ -2014,9 +2014,6 @@ static bool detect_ivrs(void) /* Make sure ACS will be enabled during PCI probe */ pci_request_acs(); - if (!disable_irq_remap) - amd_iommu_irq_remap = true; - return true; } @@ -2123,8 +2120,7 @@ static int __init iommu_go_to_state(enum iommu_init_state state) #ifdef CONFIG_IRQ_REMAP int __init amd_iommu_prepare(void) { - if (!amd_iommu_irq_remap) - return -1; + amd_iommu_irq_remap = true; return iommu_go_to_state(IOMMU_ACPI_FINISHED); } diff --git a/drivers/iommu/intel_irq_remapping.c b/drivers/iommu/intel_irq_remapping.c index fb72bd5f438c..14de1ab223c8 100644 --- a/drivers/iommu/intel_irq_remapping.c +++ b/drivers/iommu/intel_irq_remapping.c @@ -588,10 +588,6 @@ static int __init intel_prepare_irq_remapping(void) struct dmar_drhd_unit *drhd; struct intel_iommu *iommu; - /* First check whether IRQ remapping should be enabled */ - if (disable_irq_remap) - return -ENODEV; - if (irq_remap_broken) { printk(KERN_WARNING "This system BIOS has enabled interrupt remapping\n" @@ -600,7 +596,6 @@ static int __init intel_prepare_irq_remapping(void) "interrupt remapping is being disabled. Please\n" "contact your BIOS vendor for an update\n"); add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_STILL_OK); - disable_irq_remap = 1; return -ENODEV; } diff --git a/drivers/iommu/irq_remapping.c b/drivers/iommu/irq_remapping.c index 7d85d2ba0e8b..5585c4e17e39 100644 --- a/drivers/iommu/irq_remapping.c +++ b/drivers/iommu/irq_remapping.c @@ -17,12 +17,11 @@ #include "irq_remapping.h" int irq_remapping_enabled; - -int disable_irq_remap; int irq_remap_broken; int disable_sourceid_checking; int no_x2apic_optout; +static int disable_irq_remap; static struct irq_remap_ops *remap_ops; static int msi_alloc_remapped_irq(struct pci_dev *pdev, int irq, int nvec); diff --git a/drivers/iommu/irq_remapping.h b/drivers/iommu/irq_remapping.h index a8edfea0ab5d..c448eb48340a 100644 --- a/drivers/iommu/irq_remapping.h +++ b/drivers/iommu/irq_remapping.h @@ -31,7 +31,6 @@ struct cpumask; struct pci_dev; struct msi_msg; -extern int disable_irq_remap; extern int irq_remap_broken; extern int disable_sourceid_checking; extern int no_x2apic_optout; @@ -86,7 +85,6 @@ extern struct irq_remap_ops amd_iommu_irq_ops; #else /* CONFIG_IRQ_REMAP */ #define irq_remapping_enabled 0 -#define disable_irq_remap 1 #define irq_remap_broken 0 #endif /* CONFIG_IRQ_REMAP */ From e901176046e6729e002839d7296f27f17599ccb8 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Wed, 7 Jan 2015 15:31:43 +0800 Subject: [PATCH 18/44] iommu/irq_remapping: Normailize the way to detect whether IR is enabled Refine code by normailizing the way to detect whether IR is enabled. Signed-off-by: Jiang Liu Tested-by: Joerg Roedel Cc: Tony Luck Cc: iommu@lists.linux-foundation.org Cc: Benjamin Herrenschmidt Cc: Yinghai Lu Cc: Borislav Petkov Link: http://lkml.kernel.org/r/1420615903-28253-17-git-send-email-jiang.liu@linux.intel.com Signed-off-by: Thomas Gleixner --- drivers/iommu/irq_remapping.c | 38 +++++++++++++---------------------- 1 file changed, 14 insertions(+), 24 deletions(-) diff --git a/drivers/iommu/irq_remapping.c b/drivers/iommu/irq_remapping.c index 5585c4e17e39..390079ee1350 100644 --- a/drivers/iommu/irq_remapping.c +++ b/drivers/iommu/irq_remapping.c @@ -218,7 +218,7 @@ int __init irq_remapping_enable(void) { int ret; - if (!remap_ops || !remap_ops->enable) + if (!remap_ops->enable) return -ENODEV; ret = remap_ops->enable(); @@ -231,22 +231,16 @@ int __init irq_remapping_enable(void) void irq_remapping_disable(void) { - if (!irq_remapping_enabled || - !remap_ops || - !remap_ops->disable) - return; - - remap_ops->disable(); + if (irq_remapping_enabled && remap_ops->disable) + remap_ops->disable(); } int irq_remapping_reenable(int mode) { - if (!irq_remapping_enabled || - !remap_ops || - !remap_ops->reenable) - return 0; + if (irq_remapping_enabled && remap_ops->reenable) + return remap_ops->reenable(mode); - return remap_ops->reenable(mode); + return 0; } int __init irq_remap_enable_fault_handling(void) @@ -254,7 +248,7 @@ int __init irq_remap_enable_fault_handling(void) if (!irq_remapping_enabled) return 0; - if (!remap_ops || !remap_ops->enable_faulting) + if (!remap_ops->enable_faulting) return -ENODEV; return remap_ops->enable_faulting(); @@ -265,7 +259,7 @@ int setup_ioapic_remapped_entry(int irq, unsigned int destination, int vector, struct io_apic_irq_attr *attr) { - if (!remap_ops || !remap_ops->setup_ioapic_entry) + if (!remap_ops->setup_ioapic_entry) return -ENODEV; return remap_ops->setup_ioapic_entry(irq, entry, destination, @@ -275,8 +269,7 @@ int setup_ioapic_remapped_entry(int irq, static int set_remapped_irq_affinity(struct irq_data *data, const struct cpumask *mask, bool force) { - if (!config_enabled(CONFIG_SMP) || !remap_ops || - !remap_ops->set_affinity) + if (!config_enabled(CONFIG_SMP) || !remap_ops->set_affinity) return 0; return remap_ops->set_affinity(data, mask, force); @@ -286,10 +279,7 @@ void free_remapped_irq(int irq) { struct irq_cfg *cfg = irq_cfg(irq); - if (!remap_ops || !remap_ops->free_irq) - return; - - if (irq_remapped(cfg)) + if (irq_remapped(cfg) && remap_ops->free_irq) remap_ops->free_irq(irq); } @@ -301,13 +291,13 @@ void compose_remapped_msi_msg(struct pci_dev *pdev, if (!irq_remapped(cfg)) native_compose_msi_msg(pdev, irq, dest, msg, hpet_id); - else if (remap_ops && remap_ops->compose_msi_msg) + else if (remap_ops->compose_msi_msg) remap_ops->compose_msi_msg(pdev, irq, dest, msg, hpet_id); } static int msi_alloc_remapped_irq(struct pci_dev *pdev, int irq, int nvec) { - if (!remap_ops || !remap_ops->msi_alloc_irq) + if (!remap_ops->msi_alloc_irq) return -ENODEV; return remap_ops->msi_alloc_irq(pdev, irq, nvec); @@ -316,7 +306,7 @@ static int msi_alloc_remapped_irq(struct pci_dev *pdev, int irq, int nvec) static int msi_setup_remapped_irq(struct pci_dev *pdev, unsigned int irq, int index, int sub_handle) { - if (!remap_ops || !remap_ops->msi_setup_irq) + if (!remap_ops->msi_setup_irq) return -ENODEV; return remap_ops->msi_setup_irq(pdev, irq, index, sub_handle); @@ -326,7 +316,7 @@ int setup_hpet_msi_remapped(unsigned int irq, unsigned int id) { int ret; - if (!remap_ops || !remap_ops->alloc_hpet_msi) + if (!remap_ops->alloc_hpet_msi) return -ENODEV; ret = remap_ops->alloc_hpet_msi(irq, id); From 8d80696060eedf49c080c0f2cf39a20ae7e787f9 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 15 Jan 2015 21:22:09 +0000 Subject: [PATCH 19/44] x86/apic: Avoid open coded x2apic detection enable_IR_x2apic() grew a open coded x2apic detection. Implement a proper helper function which shares the code with the already existing x2apic_enabled(). Made it use rdmsrl_safe as suggested by Boris. Signed-off-by: Thomas Gleixner Cc: Borislav Petkov Cc: Jiang Liu Cc: Joerg Roedel Cc: Tony Luck Link: http://lkml.kernel.org/r/20150115211702.285038186@linutronix.de Signed-off-by: Thomas Gleixner --- arch/x86/include/asm/apic.h | 19 ++++++++++--------- arch/x86/kernel/apic/apic.c | 5 +---- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/arch/x86/include/asm/apic.h b/arch/x86/include/asm/apic.h index 465b309af254..1a8ba26c2fbd 100644 --- a/arch/x86/include/asm/apic.h +++ b/arch/x86/include/asm/apic.h @@ -108,6 +108,15 @@ extern u64 native_apic_icr_read(void); extern int x2apic_mode; +static inline bool apic_is_x2apic_enabled(void) +{ + u64 msr; + + if (rdmsrl_safe(MSR_IA32_APICBASE, &msr)) + return false; + return msr & X2APIC_ENABLE; +} + #ifdef CONFIG_X86_X2APIC /* * Make previous memory operations globally visible before @@ -175,15 +184,7 @@ extern void check_x2apic(void); extern void enable_x2apic(void); static inline int x2apic_enabled(void) { - u64 msr; - - if (!cpu_has_x2apic) - return 0; - - rdmsrl(MSR_IA32_APICBASE, msr); - if (msr & X2APIC_ENABLE) - return 1; - return 0; + return cpu_has_x2apic && apic_is_x2apic_enabled(); } #define x2apic_supported() (cpu_has_x2apic) diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index 35e6d09294ed..7ecfce13be05 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c @@ -1625,10 +1625,7 @@ void __init enable_IR_x2apic(void) int ret, ir_stat; if (!IS_ENABLED(CONFIG_X86_X2APIC)) { - u64 msr; - - rdmsrl(MSR_IA32_APICBASE, msr); - if (msr & X2APIC_ENABLE) + if (apic_is_x2apic_enabled()) panic("BIOS has enabled x2apic but kernel doesn't support x2apic, please disable x2apic in BIOS.\n"); } From 81a46dd8249d7fa72a8557e58a38aa984e6b5e16 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 15 Jan 2015 21:22:11 +0000 Subject: [PATCH 20/44] x86/apic: Make x2apic_mode depend on CONFIG_X86_X2APIC No point in having a static variable around which is always 0. Let the compiler optimize code out if disabled. Signed-off-by: Thomas Gleixner Acked-by: Borislav Petkov Cc: Jiang Liu Cc: Joerg Roedel Cc: Tony Luck Link: http://lkml.kernel.org/r/20150115211702.363274310@linutronix.de Signed-off-by: Thomas Gleixner --- arch/x86/include/asm/apic.h | 8 ++++---- arch/x86/kernel/apic/apic.c | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/x86/include/asm/apic.h b/arch/x86/include/asm/apic.h index 1a8ba26c2fbd..d2225fdc953e 100644 --- a/arch/x86/include/asm/apic.h +++ b/arch/x86/include/asm/apic.h @@ -106,8 +106,6 @@ extern u32 native_safe_apic_wait_icr_idle(void); extern void native_apic_icr_write(u32 low, u32 id); extern u64 native_apic_icr_read(void); -extern int x2apic_mode; - static inline bool apic_is_x2apic_enabled(void) { u64 msr; @@ -178,6 +176,7 @@ static inline u64 native_x2apic_icr_read(void) return val; } +extern int x2apic_mode; extern int x2apic_phys; extern int x2apic_preenabled; extern void check_x2apic(void); @@ -210,8 +209,9 @@ static inline void x2apic_force_phys(void) { } -#define x2apic_preenabled 0 -#define x2apic_supported() 0 +#define x2apic_mode (0) +#define x2apic_preenabled (0) +#define x2apic_supported() (0) #endif extern void enable_IR_x2apic(void); diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index 7ecfce13be05..a7d3b64ff3e5 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c @@ -161,8 +161,8 @@ static __init int setup_apicpmtimer(char *s) __setup("apicpmtimer", setup_apicpmtimer); #endif -int x2apic_mode; #ifdef CONFIG_X86_X2APIC +int x2apic_mode; /* x2apic enabled before OS handover */ int x2apic_preenabled; static int x2apic_disabled; From bfb050702990d6a2033d072cb2af583aee5c6fc5 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 15 Jan 2015 21:22:12 +0000 Subject: [PATCH 21/44] x86/apic: Move x2apic code to one place Having several disjunct pieces of code for x2apic support makes reading the code unnecessarily hard. Move it to one ifdeffed section. Signed-off-by: Thomas Gleixner Acked-by: Borislav Petkov Cc: Jiang Liu Cc: Joerg Roedel Cc: Tony Luck Link: http://lkml.kernel.org/r/20150115211702.445212133@linutronix.de Signed-off-by: Thomas Gleixner --- arch/x86/kernel/apic/apic.c | 58 ++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 30 deletions(-) diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index a7d3b64ff3e5..ff2a8b8ffa0a 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c @@ -134,9 +134,6 @@ static inline void imcr_apic_to_pic(void) */ static int force_enable_local_apic __initdata; -/* Control whether x2APIC mode is enabled or not */ -static bool nox2apic __initdata; - /* * APIC command line parameters */ @@ -161,33 +158,6 @@ static __init int setup_apicpmtimer(char *s) __setup("apicpmtimer", setup_apicpmtimer); #endif -#ifdef CONFIG_X86_X2APIC -int x2apic_mode; -/* x2apic enabled before OS handover */ -int x2apic_preenabled; -static int x2apic_disabled; -static int __init setup_nox2apic(char *str) -{ - if (x2apic_enabled()) { - int apicid = native_apic_msr_read(APIC_ID); - - if (apicid >= 255) { - pr_warning("Apicid: %08x, cannot enforce nox2apic\n", - apicid); - return 0; - } - - pr_warning("x2apic already enabled. will disable it\n"); - } else - setup_clear_cpu_cap(X86_FEATURE_X2APIC); - - nox2apic = true; - - return 0; -} -early_param("nox2apic", setup_nox2apic); -#endif - unsigned long mp_lapic_addr; int disable_apic; /* Disable local APIC timer from the kernel commandline or via dmi quirk */ @@ -1504,7 +1474,35 @@ void __init bsp_end_local_APIC_setup(void) } +/* Control whether x2APIC mode is enabled or not */ +static bool nox2apic __initdata; + #ifdef CONFIG_X86_X2APIC +int x2apic_mode; +/* x2apic enabled before OS handover */ +int x2apic_preenabled; +static int x2apic_disabled; +static int __init setup_nox2apic(char *str) +{ + if (x2apic_enabled()) { + int apicid = native_apic_msr_read(APIC_ID); + + if (apicid >= 255) { + pr_warning("Apicid: %08x, cannot enforce nox2apic\n", + apicid); + return 0; + } + + pr_warning("x2apic already enabled. will disable it\n"); + } else + setup_clear_cpu_cap(X86_FEATURE_X2APIC); + + nox2apic = true; + + return 0; +} +early_param("nox2apic", setup_nox2apic); + /* * Need to disable xapic and x2apic at the same time and then enable xapic mode */ From 2ca5b40479246087695d9e6343075b47ee6887ea Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 15 Jan 2015 21:22:14 +0000 Subject: [PATCH 22/44] x86/ioapic: Check x2apic really The x2apic_preenabled flag is just a horrible hack and if X2APIC support is disabled it does not reflect the actual hardware state. Check the hardware instead. Signed-off-by: Thomas Gleixner Cc: Jiang Liu Cc: Joerg Roedel Cc: Tony Luck Cc: Borislav Petkov Link: http://lkml.kernel.org/r/20150115211702.541280622@linutronix.de Signed-off-by: Thomas Gleixner --- arch/x86/include/asm/apic.h | 2 -- arch/x86/kernel/apic/apic.c | 4 +++- arch/x86/kernel/apic/io_apic.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/x86/include/asm/apic.h b/arch/x86/include/asm/apic.h index d2225fdc953e..392bbcf35471 100644 --- a/arch/x86/include/asm/apic.h +++ b/arch/x86/include/asm/apic.h @@ -178,7 +178,6 @@ static inline u64 native_x2apic_icr_read(void) extern int x2apic_mode; extern int x2apic_phys; -extern int x2apic_preenabled; extern void check_x2apic(void); extern void enable_x2apic(void); static inline int x2apic_enabled(void) @@ -210,7 +209,6 @@ static inline void x2apic_force_phys(void) } #define x2apic_mode (0) -#define x2apic_preenabled (0) #define x2apic_supported() (0) #endif diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index ff2a8b8ffa0a..08144f5c1236 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c @@ -1480,7 +1480,7 @@ static bool nox2apic __initdata; #ifdef CONFIG_X86_X2APIC int x2apic_mode; /* x2apic enabled before OS handover */ -int x2apic_preenabled; +static int x2apic_preenabled; static int x2apic_disabled; static int __init setup_nox2apic(char *str) { @@ -1569,6 +1569,8 @@ void enable_x2apic(void) wrmsrl(MSR_IA32_APICBASE, msr | X2APIC_ENABLE); } } +#else +#define x2apic_preenabled (0) #endif /* CONFIG_X86_X2APIC */ static int __init try_to_enable_IR(void) diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index 3f5f60406ab1..e5e00f509f03 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c @@ -2295,7 +2295,7 @@ static inline void __init check_timer(void) } local_irq_disable(); apic_printk(APIC_QUIET, KERN_INFO "..... failed :(.\n"); - if (x2apic_preenabled) + if (apic_is_x2apic_enabled()) apic_printk(APIC_QUIET, KERN_INFO "Perhaps problem with the pre-enabled x2apic mode\n" "Try booting with x2apic and interrupt-remapping disabled in the bios.\n"); From 9aa16365275a272283acbda665634ca3dc8b46fe Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 15 Jan 2015 21:22:16 +0000 Subject: [PATCH 23/44] x86/apic: Make disable x2apic work really If x2apic_preenabled is not enabled, then disable_x2apic() is not called from various places which results in x2apic_disabled not being set. So other code pathes can happily reenable the x2apic. Signed-off-by: Thomas Gleixner Cc: Jiang Liu Cc: Joerg Roedel Cc: Tony Luck Cc: Borislav Petkov Link: http://lkml.kernel.org/r/20150115211702.621431109@linutronix.de Signed-off-by: Thomas Gleixner --- arch/x86/kernel/apic/apic.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index 08144f5c1236..fdc6c60faa6b 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c @@ -1479,8 +1479,6 @@ static bool nox2apic __initdata; #ifdef CONFIG_X86_X2APIC int x2apic_mode; -/* x2apic enabled before OS handover */ -static int x2apic_preenabled; static int x2apic_disabled; static int __init setup_nox2apic(char *str) { @@ -1535,18 +1533,19 @@ static __init void disable_x2apic(void) setup_clear_cpu_cap(X86_FEATURE_X2APIC); } - x2apic_disabled = 1; x2apic_mode = 0; register_lapic_address(mp_lapic_addr); } + + x2apic_disabled = 1; } void check_x2apic(void) { if (x2apic_enabled()) { pr_info("x2apic enabled by BIOS, switching to x2apic ops\n"); - x2apic_preenabled = x2apic_mode = 1; + x2apic_mode = 1; } } @@ -1569,8 +1568,6 @@ void enable_x2apic(void) wrmsrl(MSR_IA32_APICBASE, msr | X2APIC_ENABLE); } } -#else -#define x2apic_preenabled (0) #endif /* CONFIG_X86_X2APIC */ static int __init try_to_enable_IR(void) @@ -1599,8 +1596,7 @@ static __init void try_to_enable_x2apic(int ir_stat) (IS_ENABLED(CONFIG_HYPERVISOR_GUEST) && !hypervisor_x2apic_available())) { pr_info("IRQ remapping doesn't support X2APIC mode, disable x2apic.\n"); - if (x2apic_preenabled) - disable_x2apic(); + disable_x2apic(); return; } @@ -1643,7 +1639,7 @@ void __init enable_IR_x2apic(void) legacy_pic->mask_all(); mask_ioapic_entries(); - if (x2apic_preenabled && nox2apic) + if (nox2apic) disable_x2apic(); /* If irq_remapping_prepare() succeded, try to enable it */ if (ir_stat >= 0) From d524165cb8dbb2ce5916cd7682236b9324ae2644 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 15 Jan 2015 21:22:17 +0000 Subject: [PATCH 24/44] x86/apic: Check x2apic early No point in delaying the x2apic detection for the CONFIG_X86_X2APIC=n case to enable_IR_x2apic(). We rather detect that before we try to setup anything there. Signed-off-by: Thomas Gleixner Cc: Jiang Liu Cc: Joerg Roedel Cc: Tony Luck Cc: Borislav Petkov Link: http://lkml.kernel.org/r/20150115211702.702479404@linutronix.de Signed-off-by: Thomas Gleixner --- arch/x86/include/asm/apic.h | 2 +- arch/x86/kernel/apic/apic.c | 34 ++++++++++++++++++++-------------- 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/arch/x86/include/asm/apic.h b/arch/x86/include/asm/apic.h index 392bbcf35471..ca8deb484d03 100644 --- a/arch/x86/include/asm/apic.h +++ b/arch/x86/include/asm/apic.h @@ -178,7 +178,7 @@ static inline u64 native_x2apic_icr_read(void) extern int x2apic_mode; extern int x2apic_phys; -extern void check_x2apic(void); +extern void __init check_x2apic(void); extern void enable_x2apic(void); static inline int x2apic_enabled(void) { diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index fdc6c60faa6b..d5c35346b556 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c @@ -1541,14 +1541,6 @@ static __init void disable_x2apic(void) x2apic_disabled = 1; } -void check_x2apic(void) -{ - if (x2apic_enabled()) { - pr_info("x2apic enabled by BIOS, switching to x2apic ops\n"); - x2apic_mode = 1; - } -} - void enable_x2apic(void) { u64 msr; @@ -1568,7 +1560,26 @@ void enable_x2apic(void) wrmsrl(MSR_IA32_APICBASE, msr | X2APIC_ENABLE); } } -#endif /* CONFIG_X86_X2APIC */ + +void __init check_x2apic(void) +{ + if (x2apic_enabled()) { + pr_info("x2apic enabled by BIOS, switching to x2apic ops\n"); + x2apic_mode = 1; + } +} +#else /* CONFIG_X86_X2APIC */ +static int __init validate_x2apic(void) +{ + if (!apic_is_x2apic_enabled()) + return 0; + /* + * Checkme: Can we simply turn off x2apic here instead of panic? + */ + panic("BIOS has enabled x2apic but kernel doesn't support x2apic, please disable x2apic in BIOS.\n"); +} +early_initcall(validate_x2apic); +#endif /* !CONFIG_X86_X2APIC */ static int __init try_to_enable_IR(void) { @@ -1620,11 +1631,6 @@ void __init enable_IR_x2apic(void) unsigned long flags; int ret, ir_stat; - if (!IS_ENABLED(CONFIG_X86_X2APIC)) { - if (apic_is_x2apic_enabled()) - panic("BIOS has enabled x2apic but kernel doesn't support x2apic, please disable x2apic in BIOS.\n"); - } - ir_stat = irq_remapping_prepare(); if (ir_stat < 0 && !x2apic_supported()) return; From 55eae7de727e9ecc814853ec364fbbb352c337df Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 15 Jan 2015 21:22:19 +0000 Subject: [PATCH 25/44] x86/x2apic: Move code in conditional region No point in having try_to_enable_x2apic() outside of the CONFIG_X86_X2APIC section and having inline functions and more ifdefs to deal with it. Move the code into the existing ifdef section and remove the inline cruft. Fixup the printk about not enabling interrupt remapping as suggested by Boris. Signed-off-by: Thomas Gleixner Cc: Jiang Liu Cc: Joerg Roedel Cc: Tony Luck Cc: Borislav Petkov Link: http://lkml.kernel.org/r/20150115211702.795388613@linutronix.de Signed-off-by: Thomas Gleixner --- arch/x86/include/asm/apic.h | 24 +++---------- arch/x86/kernel/apic/apic.c | 67 ++++++++++++++++++------------------- 2 files changed, 37 insertions(+), 54 deletions(-) diff --git a/arch/x86/include/asm/apic.h b/arch/x86/include/asm/apic.h index ca8deb484d03..951caa17d8ba 100644 --- a/arch/x86/include/asm/apic.h +++ b/arch/x86/include/asm/apic.h @@ -186,27 +186,11 @@ static inline int x2apic_enabled(void) } #define x2apic_supported() (cpu_has_x2apic) -static inline void x2apic_force_phys(void) -{ - x2apic_phys = 1; -} #else -static inline void disable_x2apic(void) -{ -} -static inline void check_x2apic(void) -{ -} -static inline void enable_x2apic(void) -{ -} -static inline int x2apic_enabled(void) -{ - return 0; -} -static inline void x2apic_force_phys(void) -{ -} +static inline void disable_x2apic(void) { } +static inline void check_x2apic(void) { } +static inline void enable_x2apic(void) { } +static inline int x2apic_enabled(void) { return 0; } #define x2apic_mode (0) #define x2apic_supported() (0) diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index d5c35346b556..bda56eea929c 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c @@ -1561,41 +1561,8 @@ void enable_x2apic(void) } } -void __init check_x2apic(void) -{ - if (x2apic_enabled()) { - pr_info("x2apic enabled by BIOS, switching to x2apic ops\n"); - x2apic_mode = 1; - } -} -#else /* CONFIG_X86_X2APIC */ -static int __init validate_x2apic(void) -{ - if (!apic_is_x2apic_enabled()) - return 0; - /* - * Checkme: Can we simply turn off x2apic here instead of panic? - */ - panic("BIOS has enabled x2apic but kernel doesn't support x2apic, please disable x2apic in BIOS.\n"); -} -early_initcall(validate_x2apic); -#endif /* !CONFIG_X86_X2APIC */ - -static int __init try_to_enable_IR(void) -{ -#ifdef CONFIG_X86_IO_APIC - if (!x2apic_enabled() && skip_ioapic_setup) { - pr_info("Skipped enabling intr-remap because of skipping " - "io-apic setup\n"); - return -1; - } -#endif - return irq_remapping_enable(); -} - static __init void try_to_enable_x2apic(int ir_stat) { -#ifdef CONFIG_X86_X2APIC if (!x2apic_supported()) return; @@ -1615,7 +1582,7 @@ static __init void try_to_enable_x2apic(int ir_stat) * without IR all CPUs can be addressed by IOAPIC/MSI * only in physical mode */ - x2apic_force_phys(); + x2apic_phys = 1; } if (!x2apic_mode) { @@ -1623,7 +1590,39 @@ static __init void try_to_enable_x2apic(int ir_stat) enable_x2apic(); pr_info("Enabled x2apic\n"); } +} + +void __init check_x2apic(void) +{ + if (x2apic_enabled()) { + pr_info("x2apic: enabled by BIOS, switching to x2apic ops\n"); + x2apic_mode = 1; + } +} +#else /* CONFIG_X86_X2APIC */ +static int __init validate_x2apic(void) +{ + if (!apic_is_x2apic_enabled()) + return 0; + /* + * Checkme: Can we simply turn off x2apic here instead of panic? + */ + panic("BIOS has enabled x2apic but kernel doesn't support x2apic, please disable x2apic in BIOS.\n"); +} +early_initcall(validate_x2apic); + +static inline void try_to_enable_x2apic(int ir_stat) { } +#endif /* !CONFIG_X86_X2APIC */ + +static int __init try_to_enable_IR(void) +{ +#ifdef CONFIG_X86_IO_APIC + if (!x2apic_enabled() && skip_ioapic_setup) { + pr_info("Not enabling interrupt remapping due to skipped IO-APIC setup\n"); + return -1; + } #endif + return irq_remapping_enable(); } void __init enable_IR_x2apic(void) From 62e61633daeb0b53f0506aa6e170e2e4cc75cd65 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 15 Jan 2015 21:22:21 +0000 Subject: [PATCH 26/44] x86/x2apic: Clarify remapping mode for x2apic enablement Rename the argument of try_to_enable_x2apic() so the purpose becomes more clear. Make the pr_warning more consistent and avoid the double print of "disabling". Signed-off-by: Thomas Gleixner Acked-by: Borislav Petkov Cc: Jiang Liu Cc: Joerg Roedel Cc: Tony Luck Link: http://lkml.kernel.org/r/20150115211702.876012628@linutronix.de Signed-off-by: Thomas Gleixner --- arch/x86/kernel/apic/apic.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index bda56eea929c..06b75216d171 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c @@ -1561,19 +1561,19 @@ void enable_x2apic(void) } } -static __init void try_to_enable_x2apic(int ir_stat) +static __init void try_to_enable_x2apic(int remap_mode) { if (!x2apic_supported()) return; - if (ir_stat != IRQ_REMAP_X2APIC_MODE) { + if (remap_mode != IRQ_REMAP_X2APIC_MODE) { /* IR is required if there is APIC ID > 255 even when running * under KVM */ if (max_physical_apicid > 255 || (IS_ENABLED(CONFIG_HYPERVISOR_GUEST) && !hypervisor_x2apic_available())) { - pr_info("IRQ remapping doesn't support X2APIC mode, disable x2apic.\n"); + pr_info("x2apic: IRQ remapping doesn't support X2APIC mode\n"); disable_x2apic(); return; } @@ -1611,7 +1611,7 @@ static int __init validate_x2apic(void) } early_initcall(validate_x2apic); -static inline void try_to_enable_x2apic(int ir_stat) { } +static inline void try_to_enable_x2apic(int remap_mode) { } #endif /* !CONFIG_X86_X2APIC */ static int __init try_to_enable_IR(void) From 12e189d3cfa4c64de758bde18626184bf32c65fc Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 15 Jan 2015 21:22:22 +0000 Subject: [PATCH 27/44] x86/x2apic: Add proper state tracking Having 3 different variables to track the state is just silly and error prone. Add a proper state tracking variable which covers the three possible states: ON/OFF/DISABLED. We cannot use x2apic_mode for this as this would require to change all users of x2apic_mode with explicit comparisons for a state value instead of treating it as boolean. Signed-off-by: Thomas Gleixner Acked-by: Borislav Petkov Cc: Jiang Liu Cc: Joerg Roedel Cc: Tony Luck Link: http://lkml.kernel.org/r/20150115211702.955392443@linutronix.de Signed-off-by: Thomas Gleixner --- arch/x86/kernel/apic/apic.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index 06b75216d171..b374b0de342b 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c @@ -1480,6 +1480,14 @@ static bool nox2apic __initdata; #ifdef CONFIG_X86_X2APIC int x2apic_mode; static int x2apic_disabled; + +enum { + X2APIC_OFF, + X2APIC_ON, + X2APIC_DISABLED, +}; +static int x2apic_state; + static int __init setup_nox2apic(char *str) { if (x2apic_enabled()) { @@ -1496,7 +1504,7 @@ static int __init setup_nox2apic(char *str) setup_clear_cpu_cap(X86_FEATURE_X2APIC); nox2apic = true; - + x2apic_state = X2APIC_DISABLED; return 0; } early_param("nox2apic", setup_nox2apic); @@ -1539,6 +1547,7 @@ static __init void disable_x2apic(void) } x2apic_disabled = 1; + x2apic_state = X2APIC_DISABLED; } void enable_x2apic(void) @@ -1559,6 +1568,7 @@ void enable_x2apic(void) printk_once(KERN_INFO "Enabling x2apic\n"); wrmsrl(MSR_IA32_APICBASE, msr | X2APIC_ENABLE); } + x2apic_state = X2APIC_ON; } static __init void try_to_enable_x2apic(int remap_mode) @@ -1597,6 +1607,9 @@ void __init check_x2apic(void) if (x2apic_enabled()) { pr_info("x2apic: enabled by BIOS, switching to x2apic ops\n"); x2apic_mode = 1; + x2apic_state = X2APIC_ON; + } else if (!cpu_has_x2apic) { + x2apic_state = X2APIC_DISABLED; } } #else /* CONFIG_X86_X2APIC */ From 44e25ff9e6912347a1a54c757fc75681d0dc42d0 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 15 Jan 2015 21:22:24 +0000 Subject: [PATCH 28/44] x86/x2apic: Disable x2apic from nox2apic setup There is no point in postponing the hardware disablement of x2apic. It can be disabled right away in the nox2apic setup function. Disable it right away and set the state to DISABLED . This allows to remove all the nox2apic conditionals all over the place. Signed-off-by: Thomas Gleixner Cc: Jiang Liu Cc: Joerg Roedel Cc: Tony Luck Cc: Borislav Petkov Link: http://lkml.kernel.org/r/20150115211703.051214090@linutronix.de Signed-off-by: Thomas Gleixner --- arch/x86/include/asm/apic.h | 1 - arch/x86/kernel/apic/apic.c | 59 +++++++++++++++---------------------- 2 files changed, 24 insertions(+), 36 deletions(-) diff --git a/arch/x86/include/asm/apic.h b/arch/x86/include/asm/apic.h index 951caa17d8ba..5d7488e9b66e 100644 --- a/arch/x86/include/asm/apic.h +++ b/arch/x86/include/asm/apic.h @@ -187,7 +187,6 @@ static inline int x2apic_enabled(void) #define x2apic_supported() (cpu_has_x2apic) #else -static inline void disable_x2apic(void) { } static inline void check_x2apic(void) { } static inline void enable_x2apic(void) { } static inline int x2apic_enabled(void) { return 0; } diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index b374b0de342b..90b8ac5df250 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c @@ -1474,12 +1474,8 @@ void __init bsp_end_local_APIC_setup(void) } -/* Control whether x2APIC mode is enabled or not */ -static bool nox2apic __initdata; - #ifdef CONFIG_X86_X2APIC int x2apic_mode; -static int x2apic_disabled; enum { X2APIC_OFF, @@ -1488,6 +1484,19 @@ enum { }; static int x2apic_state; +static inline void __x2apic_disable(void) +{ + u64 msr; + + rdmsrl(MSR_IA32_APICBASE, msr); + if (!(msr & X2APIC_ENABLE)) + return; + /* Disable xapic and x2apic first and then reenable xapic mode */ + wrmsrl(MSR_IA32_APICBASE, msr & ~(X2APIC_ENABLE | XAPIC_ENABLE)); + wrmsrl(MSR_IA32_APICBASE, msr & ~X2APIC_ENABLE); + printk_once(KERN_INFO "x2apic disabled\n"); +} + static int __init setup_nox2apic(char *str) { if (x2apic_enabled()) { @@ -1498,28 +1507,17 @@ static int __init setup_nox2apic(char *str) apicid); return 0; } - - pr_warning("x2apic already enabled. will disable it\n"); - } else - setup_clear_cpu_cap(X86_FEATURE_X2APIC); - - nox2apic = true; + pr_warning("x2apic already enabled.\n"); + __x2apic_disable(); + } + setup_clear_cpu_cap(X86_FEATURE_X2APIC); x2apic_state = X2APIC_DISABLED; + x2apic_mode = 0; return 0; } early_param("nox2apic", setup_nox2apic); -/* - * Need to disable xapic and x2apic at the same time and then enable xapic mode - */ -static inline void __disable_x2apic(u64 msr) -{ - wrmsrl(MSR_IA32_APICBASE, - msr & ~(X2APIC_ENABLE | XAPIC_ENABLE)); - wrmsrl(MSR_IA32_APICBASE, msr & ~X2APIC_ENABLE); -} - -static __init void disable_x2apic(void) +static __init void x2apic_disable(void) { u64 msr; @@ -1533,20 +1531,13 @@ static __init void disable_x2apic(void) if (x2apic_id >= 255) panic("Cannot disable x2apic, id: %08x\n", x2apic_id); - pr_info("Disabling x2apic\n"); - __disable_x2apic(msr); - - if (nox2apic) { - clear_cpu_cap(&cpu_data(0), X86_FEATURE_X2APIC); - setup_clear_cpu_cap(X86_FEATURE_X2APIC); - } + __x2apic_disable(); x2apic_mode = 0; register_lapic_address(mp_lapic_addr); } - x2apic_disabled = 1; x2apic_state = X2APIC_DISABLED; } @@ -1554,9 +1545,8 @@ void enable_x2apic(void) { u64 msr; - rdmsrl(MSR_IA32_APICBASE, msr); - if (x2apic_disabled) { - __disable_x2apic(msr); + if (x2apic_state == X2APIC_DISABLED) { + __x2apic_disable(); x2apic_mode = 0; return; } @@ -1564,6 +1554,7 @@ void enable_x2apic(void) if (!x2apic_mode) return; + rdmsrl(MSR_IA32_APICBASE, msr); if (!(msr & X2APIC_ENABLE)) { printk_once(KERN_INFO "Enabling x2apic\n"); wrmsrl(MSR_IA32_APICBASE, msr | X2APIC_ENABLE); @@ -1584,7 +1575,7 @@ static __init void try_to_enable_x2apic(int remap_mode) (IS_ENABLED(CONFIG_HYPERVISOR_GUEST) && !hypervisor_x2apic_available())) { pr_info("x2apic: IRQ remapping doesn't support X2APIC mode\n"); - disable_x2apic(); + x2apic_disable(); return; } @@ -1657,8 +1648,6 @@ void __init enable_IR_x2apic(void) legacy_pic->mask_all(); mask_ioapic_entries(); - if (nox2apic) - disable_x2apic(); /* If irq_remapping_prepare() succeded, try to enable it */ if (ir_stat >= 0) ir_stat = try_to_enable_IR(); From 659006bf3ae37a08706907ce1a36ddf57c9131d2 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 15 Jan 2015 21:22:26 +0000 Subject: [PATCH 29/44] x86/x2apic: Split enable and setup function enable_x2apic() is a convoluted unreadable mess because it is used for both enablement in early boot and for setup in cpu_init(). Split the code into x2apic_enable() for enablement and x2apic_setup() for setup of (secondary cpus). Make use of the new state tracking to simplify the logic. Signed-off-by: Thomas Gleixner Cc: Jiang Liu Cc: Joerg Roedel Cc: Tony Luck Cc: Borislav Petkov Link: http://lkml.kernel.org/r/20150115211703.129287153@linutronix.de Signed-off-by: Thomas Gleixner --- arch/x86/include/asm/apic.h | 4 +-- arch/x86/kernel/apic/apic.c | 63 ++++++++++++++++++++++-------------- arch/x86/kernel/cpu/common.c | 2 +- 3 files changed, 41 insertions(+), 28 deletions(-) diff --git a/arch/x86/include/asm/apic.h b/arch/x86/include/asm/apic.h index 5d7488e9b66e..ac60c603f8dd 100644 --- a/arch/x86/include/asm/apic.h +++ b/arch/x86/include/asm/apic.h @@ -179,7 +179,7 @@ static inline u64 native_x2apic_icr_read(void) extern int x2apic_mode; extern int x2apic_phys; extern void __init check_x2apic(void); -extern void enable_x2apic(void); +extern void x2apic_setup(void); static inline int x2apic_enabled(void) { return cpu_has_x2apic && apic_is_x2apic_enabled(); @@ -188,7 +188,7 @@ static inline int x2apic_enabled(void) #define x2apic_supported() (cpu_has_x2apic) #else static inline void check_x2apic(void) { } -static inline void enable_x2apic(void) { } +static inline void x2apic_setup(void) { } static inline int x2apic_enabled(void) { return 0; } #define x2apic_mode (0) diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index 90b8ac5df250..0ee96b9fe4e6 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c @@ -1488,6 +1488,9 @@ static inline void __x2apic_disable(void) { u64 msr; + if (cpu_has_apic) + return; + rdmsrl(MSR_IA32_APICBASE, msr); if (!(msr & X2APIC_ENABLE)) return; @@ -1497,6 +1500,17 @@ static inline void __x2apic_disable(void) printk_once(KERN_INFO "x2apic disabled\n"); } +static inline void __x2apic_enable(void) +{ + u64 msr; + + rdmsrl(MSR_IA32_APICBASE, msr); + if (msr & X2APIC_ENABLE) + return; + wrmsrl(MSR_IA32_APICBASE, msr | X2APIC_ENABLE); + printk_once(KERN_INFO "x2apic enabled\n"); +} + static int __init setup_nox2apic(char *str) { if (x2apic_enabled()) { @@ -1517,6 +1531,20 @@ static int __init setup_nox2apic(char *str) } early_param("nox2apic", setup_nox2apic); +/* Called from cpu_init() to enable x2apic on (secondary) cpus */ +void x2apic_setup(void) +{ + /* + * If x2apic is not in ON state, disable it if already enabled + * from BIOS. + */ + if (x2apic_state != X2APIC_ON) { + __x2apic_disable(); + return; + } + __x2apic_enable(); +} + static __init void x2apic_disable(void) { u64 msr; @@ -1541,30 +1569,19 @@ static __init void x2apic_disable(void) x2apic_state = X2APIC_DISABLED; } -void enable_x2apic(void) +static __init void x2apic_enable(void) { - u64 msr; - - if (x2apic_state == X2APIC_DISABLED) { - __x2apic_disable(); - x2apic_mode = 0; - return; - } - - if (!x2apic_mode) + if (x2apic_state != X2APIC_OFF) return; - rdmsrl(MSR_IA32_APICBASE, msr); - if (!(msr & X2APIC_ENABLE)) { - printk_once(KERN_INFO "Enabling x2apic\n"); - wrmsrl(MSR_IA32_APICBASE, msr | X2APIC_ENABLE); - } + x2apic_mode = 1; x2apic_state = X2APIC_ON; + __x2apic_enable(); } static __init void try_to_enable_x2apic(int remap_mode) { - if (!x2apic_supported()) + if (x2apic_state == X2APIC_DISABLED) return; if (remap_mode != IRQ_REMAP_X2APIC_MODE) { @@ -1585,12 +1602,7 @@ static __init void try_to_enable_x2apic(int remap_mode) */ x2apic_phys = 1; } - - if (!x2apic_mode) { - x2apic_mode = 1; - enable_x2apic(); - pr_info("Enabled x2apic\n"); - } + x2apic_enable(); } void __init check_x2apic(void) @@ -1616,6 +1628,7 @@ static int __init validate_x2apic(void) early_initcall(validate_x2apic); static inline void try_to_enable_x2apic(int remap_mode) { } +static inline void __x2apic_enable(void) { } #endif /* !CONFIG_X86_X2APIC */ static int __init try_to_enable_IR(void) @@ -2357,9 +2370,9 @@ static void lapic_resume(void) mask_ioapic_entries(); legacy_pic->mask_all(); - if (x2apic_mode) - enable_x2apic(); - else { + if (x2apic_mode) { + __x2apic_enable(); + } else { /* * Make sure the APICBASE points to the right address * diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index c6049650c093..cb5692551b98 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -1332,7 +1332,7 @@ void cpu_init(void) barrier(); x86_configure_nx(); - enable_x2apic(); + x2apic_setup(); /* * set up and load the per-CPU TSS From 6d2d49d2cd0199ce298d111ee7fd405af3344a70 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 15 Jan 2015 21:22:27 +0000 Subject: [PATCH 30/44] x86/x2apic: Use state information for disable Use the state information to simplify the disable logic further. Signed-off-by: Thomas Gleixner Acked-by: Borislav Petkov Cc: Jiang Liu Cc: Joerg Roedel Cc: Tony Luck Link: http://lkml.kernel.org/r/20150115211703.209387598@linutronix.de Signed-off-by: Thomas Gleixner --- arch/x86/kernel/apic/apic.c | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index 0ee96b9fe4e6..0c554f5d03a6 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c @@ -1547,26 +1547,20 @@ void x2apic_setup(void) static __init void x2apic_disable(void) { - u64 msr; + u32 x2apic_id; - if (!cpu_has_x2apic) - return; + if (x2apic_state != X2APIC_ON) + goto out; - rdmsrl(MSR_IA32_APICBASE, msr); - if (msr & X2APIC_ENABLE) { - u32 x2apic_id = read_apic_id(); - - if (x2apic_id >= 255) - panic("Cannot disable x2apic, id: %08x\n", x2apic_id); - - __x2apic_disable(); - - x2apic_mode = 0; - - register_lapic_address(mp_lapic_addr); - } + x2apic_id = read_apic_id(); + if (x2apic_id >= 255) + panic("Cannot disable x2apic, id: %08x\n", x2apic_id); + __x2apic_disable(); + register_lapic_address(mp_lapic_addr); +out: x2apic_state = X2APIC_DISABLED; + x2apic_mode = 0; } static __init void x2apic_enable(void) From f77aa308e5a6144a47311ad6905a1a72bc0014f9 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 15 Jan 2015 21:22:29 +0000 Subject: [PATCH 31/44] x86/smpboot: Move smpboot inlines to code No point for a separate header file. Signed-off-by: Thomas Gleixner Cc: Jiang Liu Cc: Joerg Roedel Cc: Tony Luck Cc: Borislav Petkov Link: http://lkml.kernel.org/r/20150115211703.304126687@linutronix.de Signed-off-by: Thomas Gleixner --- arch/x86/include/asm/smpboot_hooks.h | 68 ---------------------------- arch/x86/kernel/smpboot.c | 66 ++++++++++++++++++++++++++- 2 files changed, 65 insertions(+), 69 deletions(-) delete mode 100644 arch/x86/include/asm/smpboot_hooks.h diff --git a/arch/x86/include/asm/smpboot_hooks.h b/arch/x86/include/asm/smpboot_hooks.h deleted file mode 100644 index 0da7409f0bec..000000000000 --- a/arch/x86/include/asm/smpboot_hooks.h +++ /dev/null @@ -1,68 +0,0 @@ -/* two abstractions specific to kernel/smpboot.c, mainly to cater to visws - * which needs to alter them. */ - -static inline void smpboot_clear_io_apic_irqs(void) -{ -#ifdef CONFIG_X86_IO_APIC - io_apic_irqs = 0; -#endif -} - -static inline void smpboot_setup_warm_reset_vector(unsigned long start_eip) -{ - unsigned long flags; - - spin_lock_irqsave(&rtc_lock, flags); - CMOS_WRITE(0xa, 0xf); - spin_unlock_irqrestore(&rtc_lock, flags); - local_flush_tlb(); - pr_debug("1.\n"); - *((volatile unsigned short *)phys_to_virt(TRAMPOLINE_PHYS_HIGH)) = - start_eip >> 4; - pr_debug("2.\n"); - *((volatile unsigned short *)phys_to_virt(TRAMPOLINE_PHYS_LOW)) = - start_eip & 0xf; - pr_debug("3.\n"); -} - -static inline void smpboot_restore_warm_reset_vector(void) -{ - unsigned long flags; - - /* - * Install writable page 0 entry to set BIOS data area. - */ - local_flush_tlb(); - - /* - * Paranoid: Set warm reset code and vector here back - * to default values. - */ - spin_lock_irqsave(&rtc_lock, flags); - CMOS_WRITE(0, 0xf); - spin_unlock_irqrestore(&rtc_lock, flags); - - *((volatile u32 *)phys_to_virt(TRAMPOLINE_PHYS_LOW)) = 0; -} - -static inline void __init smpboot_setup_io_apic(void) -{ -#ifdef CONFIG_X86_IO_APIC - /* - * Here we can be sure that there is an IO-APIC in the system. Let's - * go and set it up: - */ - if (!skip_ioapic_setup && nr_ioapics) - setup_IO_APIC(); - else { - nr_ioapics = 0; - } -#endif -} - -static inline void smpboot_clear_io_apic(void) -{ -#ifdef CONFIG_X86_IO_APIC - nr_ioapics = 0; -#endif -} diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c index 6d7022c683e3..110ed1145e27 100644 --- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c @@ -73,7 +73,6 @@ #include #include #include -#include #include #include #include @@ -104,6 +103,71 @@ EXPORT_PER_CPU_SYMBOL(cpu_info); atomic_t init_deasserted; +static inline void smpboot_clear_io_apic_irqs(void) +{ +#ifdef CONFIG_X86_IO_APIC + io_apic_irqs = 0; +#endif +} + +static inline void smpboot_setup_warm_reset_vector(unsigned long start_eip) +{ + unsigned long flags; + + spin_lock_irqsave(&rtc_lock, flags); + CMOS_WRITE(0xa, 0xf); + spin_unlock_irqrestore(&rtc_lock, flags); + local_flush_tlb(); + pr_debug("1.\n"); + *((volatile unsigned short *)phys_to_virt(TRAMPOLINE_PHYS_HIGH)) = + start_eip >> 4; + pr_debug("2.\n"); + *((volatile unsigned short *)phys_to_virt(TRAMPOLINE_PHYS_LOW)) = + start_eip & 0xf; + pr_debug("3.\n"); +} + +static inline void smpboot_restore_warm_reset_vector(void) +{ + unsigned long flags; + + /* + * Install writable page 0 entry to set BIOS data area. + */ + local_flush_tlb(); + + /* + * Paranoid: Set warm reset code and vector here back + * to default values. + */ + spin_lock_irqsave(&rtc_lock, flags); + CMOS_WRITE(0, 0xf); + spin_unlock_irqrestore(&rtc_lock, flags); + + *((volatile u32 *)phys_to_virt(TRAMPOLINE_PHYS_LOW)) = 0; +} + +static inline void __init smpboot_setup_io_apic(void) +{ +#ifdef CONFIG_X86_IO_APIC + /* + * Here we can be sure that there is an IO-APIC in the system. Let's + * go and set it up: + */ + if (!skip_ioapic_setup && nr_ioapics) + setup_IO_APIC(); + else + nr_ioapics = 0; +#endif +} + +static inline void smpboot_clear_io_apic(void) +{ +#ifdef CONFIG_X86_IO_APIC + nr_ioapics = 0; +#endif +} + /* * Report back to the Boot Processor during boot time or to the caller processor * during CPU online. From 8686608336e11276d72d020cb0b67bee70d9a5cd Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 15 Jan 2015 21:22:30 +0000 Subject: [PATCH 32/44] x86/ioapic: Provide stub functions for IOAPIC%3Dn To avoid lots of ifdeffery provide proper stubs for setup_IO_APIC(), enable_IO_APIC() and setup_ioapic_dest(). Signed-off-by: Thomas Gleixner Acked-by: Borislav Petkov Cc: Jiang Liu Cc: Joerg Roedel Cc: Tony Luck Link: http://lkml.kernel.org/r/20150115211703.397170414@linutronix.de Signed-off-by: Thomas Gleixner --- arch/x86/include/asm/io_apic.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/x86/include/asm/io_apic.h b/arch/x86/include/asm/io_apic.h index bf006cce9418..2f91685fe1cd 100644 --- a/arch/x86/include/asm/io_apic.h +++ b/arch/x86/include/asm/io_apic.h @@ -279,6 +279,11 @@ static inline void disable_ioapic_support(void) { } #define native_ioapic_set_affinity NULL #define native_setup_ioapic_entry NULL #define native_eoi_ioapic_pin NULL + +static inline void setup_IO_APIC(void) { } +static inline void enable_IO_APIC(void) { } +static inline void setup_ioapic_dest(void) { } + #endif #endif /* _ASM_X86_IO_APIC_H */ From a46f5c89274245e42834dc976896444efd53ccdc Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 15 Jan 2015 21:22:32 +0000 Subject: [PATCH 33/44] x86/ioapic: Add proper checks to setp/enable_IO_APIC() No point to have the same checks at every call site. Add them to the functions, so they can be called unconditionally. Signed-off-by: Thomas Gleixner Acked-by: Borislav Petkov Cc: Jiang Liu Cc: Joerg Roedel Cc: Tony Luck Link: http://lkml.kernel.org/r/20150115211703.490719938@linutronix.de Signed-off-by: Thomas Gleixner --- arch/x86/kernel/apic/io_apic.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index e5e00f509f03..f4dc2462a1ac 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c @@ -1507,7 +1507,10 @@ void __init enable_IO_APIC(void) int i8259_apic, i8259_pin; int apic, pin; - if (!nr_legacy_irqs()) + if (skip_ioapic_setup) + nr_ioapics = 0; + + if (!nr_legacy_irqs() || !nr_ioapics) return; for_each_ioapic_pin(apic, pin) { @@ -2373,9 +2376,9 @@ void __init setup_IO_APIC(void) { int ioapic; - /* - * calling enable_IO_APIC() is moved to setup_local_APIC for BP - */ + if (skip_ioapic_setup || !nr_ioapics) + return; + io_apic_irqs = nr_legacy_irqs() ? ~PIC_IRQS : ~0UL; apic_printk(APIC_VERBOSE, "ENABLING IO-APIC IRQs\n"); From 35e4c6d30e6f69745d77afd5f63203ad440bed12 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 15 Jan 2015 21:22:34 +0000 Subject: [PATCH 34/44] x86/apic: Sanitize ioapic handling We have proper stubs for the IOAPIC=n case and the setup/enable function have the required checks inside now. Remove the ifdeffery and the copy&pasted conditionals. Signed-off-by: Thomas Gleixner C Acked-by: Borislav Petkov Cc: Jiang Liu Cc: Joerg Roedel Cc: Tony Luck Link: http://lkml.kernel.org/r/20150115211703.569830549@linutronix.de Signed-off-by: Thomas Gleixner --- arch/x86/kernel/apic/apic.c | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index 0c554f5d03a6..3b4bdd5da12e 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c @@ -1905,24 +1905,13 @@ int __init APIC_init_uniprocessor(void) physid_set_mask_of_physid(boot_cpu_physical_apicid, &phys_cpu_present_map); setup_local_APIC(); -#ifdef CONFIG_X86_IO_APIC - /* - * Now enable IO-APICs, actually call clear_IO_APIC - * We need clear_IO_APIC before enabling error vector - */ - if (!skip_ioapic_setup && nr_ioapics) - enable_IO_APIC(); -#endif + /* Enable IO-APICs before enabling error vector */ + enable_IO_APIC(); bsp_end_local_APIC_setup(); -#ifdef CONFIG_X86_IO_APIC - if (smp_found_config && !skip_ioapic_setup && nr_ioapics) + if (smp_found_config) setup_IO_APIC(); - else { - nr_ioapics = 0; - } -#endif x86_init.timers.setup_percpu_clockev(); return 0; From ef4c59a4b64c62f977187cae444aee25bebb02fe Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 15 Jan 2015 21:22:35 +0000 Subject: [PATCH 35/44] x86/smpboot: Cleanup ioapic handling smpboot is very creative with the ways to disable ioapic. smpboot_clear_io_apic() smpboot_clear_io_apic_irqs() and disable_ioapic_support() serve a similar purpose. smpboot_clear_io_apic_irqs() is the most useless of all functions as it clears a variable which has not been setup yet. Aside of that it has the same ifdef mess and conditionals around the ioapic related code, which can now be removed. Signed-off-by: Thomas Gleixner Acked-by: Borislav Petkov Cc: Jiang Liu Cc: Joerg Roedel Cc: Tony Luck Link: http://lkml.kernel.org/r/20150115211703.650280684@linutronix.de Signed-off-by: Thomas Gleixner --- arch/x86/kernel/smpboot.c | 47 ++++++--------------------------------- 1 file changed, 7 insertions(+), 40 deletions(-) diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c index 110ed1145e27..ca7f7b696f07 100644 --- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c @@ -103,13 +103,6 @@ EXPORT_PER_CPU_SYMBOL(cpu_info); atomic_t init_deasserted; -static inline void smpboot_clear_io_apic_irqs(void) -{ -#ifdef CONFIG_X86_IO_APIC - io_apic_irqs = 0; -#endif -} - static inline void smpboot_setup_warm_reset_vector(unsigned long start_eip) { unsigned long flags; @@ -147,27 +140,6 @@ static inline void smpboot_restore_warm_reset_vector(void) *((volatile u32 *)phys_to_virt(TRAMPOLINE_PHYS_LOW)) = 0; } -static inline void __init smpboot_setup_io_apic(void) -{ -#ifdef CONFIG_X86_IO_APIC - /* - * Here we can be sure that there is an IO-APIC in the system. Let's - * go and set it up: - */ - if (!skip_ioapic_setup && nr_ioapics) - setup_IO_APIC(); - else - nr_ioapics = 0; -#endif -} - -static inline void smpboot_clear_io_apic(void) -{ -#ifdef CONFIG_X86_IO_APIC - nr_ioapics = 0; -#endif -} - /* * Report back to the Boot Processor during boot time or to the caller processor * during CPU online. @@ -1019,9 +991,10 @@ void arch_disable_smp_support(void) */ static __init void disable_smp(void) { + disable_ioapic_support(); + init_cpu_present(cpumask_of(0)); init_cpu_possible(cpumask_of(0)); - smpboot_clear_io_apic_irqs(); if (smp_found_config) physid_set_mask_of_physid(boot_cpu_physical_apicid, &phys_cpu_present_map); @@ -1105,7 +1078,6 @@ static int __init smp_sanity_check(unsigned max_cpus) boot_cpu_physical_apicid); pr_err("... forcing use of dummy APIC emulation (tell your hw vendor)\n"); } - smpboot_clear_io_apic(); disable_ioapic_support(); return -1; } @@ -1117,7 +1089,7 @@ static int __init smp_sanity_check(unsigned max_cpus) */ if (!max_cpus) { pr_info("SMP mode deactivated\n"); - smpboot_clear_io_apic(); + disable_ioapic_support(); connect_bsp_APIC(); setup_local_APIC(); @@ -1191,18 +1163,15 @@ void __init native_smp_prepare_cpus(unsigned int max_cpus) else cpu0_logical_apicid = GET_APIC_LOGICAL_ID(apic_read(APIC_LDR)); - /* - * Enable IO APIC before setting up error vector - */ - if (!skip_ioapic_setup && nr_ioapics) - enable_IO_APIC(); + /* Enable IO APIC before setting up error vector */ + enable_IO_APIC(); bsp_end_local_APIC_setup(); - smpboot_setup_io_apic(); + setup_IO_APIC(); + /* * Set up local APIC timer on boot CPU. */ - pr_info("CPU%d: ", 0); print_cpu_info(&cpu_data(0)); x86_init.timers.setup_percpu_clockev(); @@ -1241,9 +1210,7 @@ void __init native_smp_cpus_done(unsigned int max_cpus) nmi_selftest(); impress_friends(); -#ifdef CONFIG_X86_IO_APIC setup_ioapic_dest(); -#endif mtrr_aps_init(); } From e714a91f92ca59f7e71e7332b8ec2aa2944f629e Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 15 Jan 2015 21:22:37 +0000 Subject: [PATCH 36/44] x86/apic: Move apic_init_uniprocessor code Move the code to a different place so we can make other functions inline. Preparatory patch for further cleanups. No change. Signed-off-by: Thomas Gleixner Acked-by: Borislav Petkov Cc: Jiang Liu Cc: Joerg Roedel Cc: Tony Luck Link: http://lkml.kernel.org/r/20150115211703.731329006@linutronix.de Signed-off-by: Thomas Gleixner --- arch/x86/kernel/apic/apic.c | 125 ++++++++++++++++++------------------ 1 file changed, 62 insertions(+), 63 deletions(-) diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index 3b4bdd5da12e..c681e9ba9e47 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c @@ -1852,71 +1852,8 @@ void __init register_lapic_address(unsigned long address) } } -/* - * This initializes the IO-APIC and APIC hardware if this is - * a UP kernel. - */ int apic_version[MAX_LOCAL_APIC]; -int __init APIC_init_uniprocessor(void) -{ - if (disable_apic) { - pr_info("Apic disabled\n"); - return -1; - } -#ifdef CONFIG_X86_64 - if (!cpu_has_apic) { - disable_apic = 1; - pr_info("Apic disabled by BIOS\n"); - return -1; - } -#else - if (!smp_found_config && !cpu_has_apic) - return -1; - - /* - * Complain if the BIOS pretends there is one. - */ - if (!cpu_has_apic && - APIC_INTEGRATED(apic_version[boot_cpu_physical_apicid])) { - pr_err("BIOS bug, local APIC 0x%x not detected!...\n", - boot_cpu_physical_apicid); - return -1; - } -#endif - - default_setup_apic_routing(); - - verify_local_APIC(); - connect_bsp_APIC(); - -#ifdef CONFIG_X86_64 - apic_write(APIC_ID, SET_APIC_ID(boot_cpu_physical_apicid)); -#else - /* - * Hack: In case of kdump, after a crash, kernel might be booting - * on a cpu with non-zero lapic id. But boot_cpu_physical_apicid - * might be zero if read from MP tables. Get it from LAPIC. - */ -# ifdef CONFIG_CRASH_DUMP - boot_cpu_physical_apicid = read_apic_id(); -# endif -#endif - physid_set_mask_of_physid(boot_cpu_physical_apicid, &phys_cpu_present_map); - setup_local_APIC(); - - /* Enable IO-APICs before enabling error vector */ - enable_IO_APIC(); - - bsp_end_local_APIC_setup(); - - if (smp_found_config) - setup_IO_APIC(); - - x86_init.timers.setup_percpu_clockev(); - return 0; -} - /* * Local APIC interrupts */ @@ -2268,6 +2205,68 @@ void __init apic_set_eoi_write(void (*eoi_write)(u32 reg, u32 v)) } } +/* + * This initializes the IO-APIC and APIC hardware if this is + * a UP kernel. + */ +int __init APIC_init_uniprocessor(void) +{ + if (disable_apic) { + pr_info("Apic disabled\n"); + return -1; + } +#ifdef CONFIG_X86_64 + if (!cpu_has_apic) { + disable_apic = 1; + pr_info("Apic disabled by BIOS\n"); + return -1; + } +#else + if (!smp_found_config && !cpu_has_apic) + return -1; + + /* + * Complain if the BIOS pretends there is one. + */ + if (!cpu_has_apic && + APIC_INTEGRATED(apic_version[boot_cpu_physical_apicid])) { + pr_err("BIOS bug, local APIC 0x%x not detected!...\n", + boot_cpu_physical_apicid); + return -1; + } +#endif + + default_setup_apic_routing(); + + verify_local_APIC(); + connect_bsp_APIC(); + +#ifdef CONFIG_X86_64 + apic_write(APIC_ID, SET_APIC_ID(boot_cpu_physical_apicid)); +#else + /* + * Hack: In case of kdump, after a crash, kernel might be booting + * on a cpu with non-zero lapic id. But boot_cpu_physical_apicid + * might be zero if read from MP tables. Get it from LAPIC. + */ +# ifdef CONFIG_CRASH_DUMP + boot_cpu_physical_apicid = read_apic_id(); +# endif +#endif + physid_set_mask_of_physid(boot_cpu_physical_apicid, &phys_cpu_present_map); + setup_local_APIC(); + + if (smp_found_config) + enable_IO_APIC(); + + bsp_end_local_APIC_setup(); + + setup_IO_APIC(); + + x86_init.timers.setup_percpu_clockev(); + return 0; +} + /* * Power management */ From 30b8b0066cafef274fc92462578ee346211ce7cb Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 15 Jan 2015 21:22:39 +0000 Subject: [PATCH 37/44] init: Get rid of x86isms The UP local API support can be set up from an early initcall. No need for horrible hackery in the init code. Signed-off-by: Thomas Gleixner Cc: Jiang Liu Cc: Joerg Roedel Cc: Tony Luck Cc: Borislav Petkov Link: http://lkml.kernel.org/r/20150115211703.827943883@linutronix.de Signed-off-by: Thomas Gleixner --- arch/x86/Kconfig | 4 ++++ arch/x86/kernel/apic/apic.c | 7 +++++++ include/linux/smp.h | 7 +++++++ init/main.c | 13 ------------- 4 files changed, 18 insertions(+), 13 deletions(-) diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index ba397bde7948..ffcc3ca5862a 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -855,6 +855,10 @@ config SCHED_MC source "kernel/Kconfig.preempt" +config UP_LATE_INIT + def_bool y + depends on X86_UP_APIC + config X86_UP_APIC bool "Local APIC support on uniprocessors" depends on X86_32 && !SMP && !X86_32_NON_STANDARD && !PCI_MSI diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index c681e9ba9e47..19f1bc714ee6 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c @@ -2267,6 +2267,13 @@ int __init APIC_init_uniprocessor(void) return 0; } +#ifdef CONFIG_UP_LATE_INIT +void __init up_late_init(void) +{ + APIC_init_uniprocessor(); +} +#endif + /* * Power management */ diff --git a/include/linux/smp.h b/include/linux/smp.h index 93dff5fff524..be91db2a7017 100644 --- a/include/linux/smp.h +++ b/include/linux/smp.h @@ -151,6 +151,13 @@ smp_call_function_any(const struct cpumask *mask, smp_call_func_t func, static inline void kick_all_cpus_sync(void) { } static inline void wake_up_all_idle_cpus(void) { } +#ifdef CONFIG_UP_LATE_INIT +extern void __init up_late_init(void); +static inline void smp_init(void) { up_late_init(); } +#else +static inline void smp_init(void) { } +#endif + #endif /* !SMP */ /* diff --git a/init/main.c b/init/main.c index 61b993767db5..179ada15d08a 100644 --- a/init/main.c +++ b/init/main.c @@ -87,10 +87,6 @@ #include #include -#ifdef CONFIG_X86_LOCAL_APIC -#include -#endif - static int kernel_init(void *); extern void init_IRQ(void); @@ -351,15 +347,6 @@ __setup("rdinit=", rdinit_setup); #ifndef CONFIG_SMP static const unsigned int setup_max_cpus = NR_CPUS; -#ifdef CONFIG_X86_LOCAL_APIC -static void __init smp_init(void) -{ - APIC_init_uniprocessor(); -} -#else -#define smp_init() do { } while (0) -#endif - static inline void setup_nr_cpu_ids(void) { } static inline void smp_prepare_cpus(unsigned int maxcpus) { } #endif From 05f7e46d2aac359b6bcfc06b302bdd03ca0bcada Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 15 Jan 2015 21:22:40 +0000 Subject: [PATCH 38/44] x86/smpboot: Move apic init code to apic.c We better provide proper functions which implement the required code flow in the apic code rather than letting the smpboot code open code it. That allows to make more functions static and confines the APIC functionality to apic.c where it belongs. Signed-off-by: Thomas Gleixner Acked-by: Borislav Petkov Cc: Jiang Liu Cc: Joerg Roedel Cc: Tony Luck Link: http://lkml.kernel.org/r/20150115211703.907616730@linutronix.de Signed-off-by: Thomas Gleixner --- arch/x86/include/asm/apic.h | 6 ++--- arch/x86/kernel/apic/apic.c | 51 +++++++++++++++++++++++++++++-------- arch/x86/kernel/smpboot.c | 27 +++----------------- 3 files changed, 47 insertions(+), 37 deletions(-) diff --git a/arch/x86/include/asm/apic.h b/arch/x86/include/asm/apic.h index ac60c603f8dd..92f34042be85 100644 --- a/arch/x86/include/asm/apic.h +++ b/arch/x86/include/asm/apic.h @@ -201,7 +201,6 @@ extern int get_physical_broadcast(void); extern int lapic_get_maxlvt(void); extern void clear_local_APIC(void); -extern void connect_bsp_APIC(void); extern void disconnect_bsp_APIC(int virt_wire_setup); extern void disable_local_APIC(void); extern void lapic_shutdown(void); @@ -209,8 +208,6 @@ extern int verify_local_APIC(void); extern void sync_Arb_IDs(void); extern void init_bsp_APIC(void); extern void setup_local_APIC(void); -extern void end_local_APIC_setup(void); -extern void bsp_end_local_APIC_setup(void); extern void init_apic_mappings(void); void register_lapic_address(unsigned long address); extern void setup_boot_APIC_clock(void); @@ -218,6 +215,9 @@ extern void setup_secondary_APIC_clock(void); extern int APIC_init_uniprocessor(void); extern int apic_force_enable(unsigned long addr); +extern int apic_bsp_setup(void); +extern void apic_ap_setup(void); + /* * On 32bit this is mach-xxx local */ diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index 19f1bc714ee6..0a4107013ada 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c @@ -1445,7 +1445,7 @@ void setup_local_APIC(void) #endif } -void end_local_APIC_setup(void) +static void end_local_APIC_setup(void) { lapic_setup_esr(); @@ -1462,16 +1462,13 @@ void end_local_APIC_setup(void) apic_pm_activate(); } -void __init bsp_end_local_APIC_setup(void) +/* + * APIC setup function for application processors. Called from smpboot.c + */ +void apic_ap_setup(void) { + setup_local_APIC(); end_local_APIC_setup(); - - /* - * Now that local APIC setup is completed for BP, configure the fault - * handling for interrupt remapping. - */ - irq_remap_enable_fault_handling(); - } #ifdef CONFIG_X86_X2APIC @@ -1958,7 +1955,7 @@ __visible void smp_trace_error_interrupt(struct pt_regs *regs) /** * connect_bsp_APIC - attach the APIC to the interrupt system */ -void __init connect_bsp_APIC(void) +static void __init connect_bsp_APIC(void) { #ifdef CONFIG_X86_32 if (pic_mode) { @@ -2205,6 +2202,40 @@ void __init apic_set_eoi_write(void (*eoi_write)(u32 reg, u32 v)) } } +static void __init bsp_end_local_APIC_setup(void) +{ + end_local_APIC_setup(); + /* + * Now that local APIC setup is completed for BP, configure the fault + * handling for interrupt remapping. + */ + irq_remap_enable_fault_handling(); +} + +/** + * apic_bsp_setup - Setup function for local apic and io-apic + * + * Returns: + * apic_id of BSP APIC + */ +int __init apic_bsp_setup(void) +{ + int id; + + connect_bsp_APIC(); + setup_local_APIC(); + + if (x2apic_mode) + id = apic_read(APIC_LDR); + else + id = GET_APIC_LOGICAL_ID(apic_read(APIC_LDR)); + + enable_IO_APIC(); + bsp_end_local_APIC_setup(); + setup_IO_APIC(); + return id; +} + /* * This initializes the IO-APIC and APIC hardware if this is * a UP kernel. diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c index ca7f7b696f07..d53870928824 100644 --- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c @@ -172,8 +172,7 @@ static void smp_callin(void) * CPU, first the APIC. (this is probably redundant on most * boards) */ - setup_local_APIC(); - end_local_APIC_setup(); + apic_ap_setup(); /* * Need to setup vector mappings before we enable interrupts. @@ -1078,7 +1077,6 @@ static int __init smp_sanity_check(unsigned max_cpus) boot_cpu_physical_apicid); pr_err("... forcing use of dummy APIC emulation (tell your hw vendor)\n"); } - disable_ioapic_support(); return -1; } @@ -1090,10 +1088,7 @@ static int __init smp_sanity_check(unsigned max_cpus) if (!max_cpus) { pr_info("SMP mode deactivated\n"); disable_ioapic_support(); - - connect_bsp_APIC(); - setup_local_APIC(); - bsp_end_local_APIC_setup(); + apic_bsp_setup(); return -1; } @@ -1151,23 +1146,7 @@ void __init native_smp_prepare_cpus(unsigned int max_cpus) /* Or can we switch back to PIC here? */ } - connect_bsp_APIC(); - - /* - * Switch from PIC to APIC mode. - */ - setup_local_APIC(); - - if (x2apic_mode) - cpu0_logical_apicid = apic_read(APIC_LDR); - else - cpu0_logical_apicid = GET_APIC_LOGICAL_ID(apic_read(APIC_LDR)); - - /* Enable IO APIC before setting up error vector */ - enable_IO_APIC(); - - bsp_end_local_APIC_setup(); - setup_IO_APIC(); + cpu0_logical_apicid = apic_bsp_setup(); /* * Set up local APIC timer on boot CPU. From 613c25efbdc763ee8b9d732368106d2456279356 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 15 Jan 2015 21:22:42 +0000 Subject: [PATCH 39/44] x86/smpboot: Sanitize uniprocessor init The UP related setups for local apic are mangled into smp_sanity_check(). That results in duplicate calls to disable_smp() and makes the code hard to follow. Let smp_sanity_check() return dedicated values for the various exit reasons and handle them at the call site. Signed-off-by: Thomas Gleixner Acked-by: Borislav Petkov Cc: Jiang Liu Cc: Joerg Roedel Cc: Tony Luck Link: http://lkml.kernel.org/r/20150115211703.987833932@linutronix.de Signed-off-by: Thomas Gleixner --- arch/x86/kernel/smpboot.c | 37 ++++++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c index d53870928824..fe8783d500c2 100644 --- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c @@ -990,6 +990,8 @@ void arch_disable_smp_support(void) */ static __init void disable_smp(void) { + pr_info("SMP disabled\n"); + disable_ioapic_support(); init_cpu_present(cpumask_of(0)); @@ -1003,6 +1005,13 @@ static __init void disable_smp(void) cpumask_set_cpu(0, cpu_core_mask(0)); } +enum { + SMP_OK, + SMP_NO_CONFIG, + SMP_NO_APIC, + SMP_FORCE_UP, +}; + /* * Various sanity checks. */ @@ -1050,10 +1059,7 @@ static int __init smp_sanity_check(unsigned max_cpus) if (!smp_found_config && !acpi_lapic) { preempt_enable(); pr_notice("SMP motherboard not detected\n"); - disable_smp(); - if (APIC_init_uniprocessor()) - pr_notice("Local APIC not detected. Using dummy APIC emulation.\n"); - return -1; + return SMP_NO_CONFIG; } /* @@ -1077,7 +1083,7 @@ static int __init smp_sanity_check(unsigned max_cpus) boot_cpu_physical_apicid); pr_err("... forcing use of dummy APIC emulation (tell your hw vendor)\n"); } - return -1; + return SMP_NO_APIC; } verify_local_APIC(); @@ -1087,12 +1093,10 @@ static int __init smp_sanity_check(unsigned max_cpus) */ if (!max_cpus) { pr_info("SMP mode deactivated\n"); - disable_ioapic_support(); - apic_bsp_setup(); - return -1; + return SMP_FORCE_UP; } - return 0; + return SMP_OK; } static void __init smp_cpu_index_default(void) @@ -1132,10 +1136,21 @@ void __init native_smp_prepare_cpus(unsigned int max_cpus) } set_cpu_sibling_map(0); - if (smp_sanity_check(max_cpus) < 0) { - pr_info("SMP disabled\n"); + switch (smp_sanity_check(max_cpus)) { + case SMP_NO_CONFIG: + disable_smp(); + if (APIC_init_uniprocessor()) + pr_notice("Local APIC not detected. Using dummy APIC emulation.\n"); + return; + case SMP_NO_APIC: disable_smp(); return; + case SMP_FORCE_UP: + disable_smp(); + apic_bsp_setup(); + return; + case SMP_OK: + break; } default_setup_apic_routing(); From 374aab339f10f0510cec0e79d752d31d84b08aa2 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 15 Jan 2015 21:22:44 +0000 Subject: [PATCH 40/44] x86/apic: Reuse apic_bsp_setup() for UP APIC setup Extend apic_bsp_setup() so the same code flow can be used for APIC_init_uniprocessor(). Folded Jiangs fix to provide proper ordering of the UP setup. Signed-off-by: Thomas Gleixner Cc: Jiang Liu Cc: Joerg Roedel Cc: Tony Luck Cc: Borislav Petkov Link: http://lkml.kernel.org/r/20150115211704.084765674@linutronix.de Signed-off-by: Thomas Gleixner --- arch/x86/include/asm/apic.h | 2 +- arch/x86/kernel/apic/apic.c | 53 +++++++++++++++---------------------- arch/x86/kernel/smpboot.c | 4 +-- 3 files changed, 25 insertions(+), 34 deletions(-) diff --git a/arch/x86/include/asm/apic.h b/arch/x86/include/asm/apic.h index 92f34042be85..92003f3c8a42 100644 --- a/arch/x86/include/asm/apic.h +++ b/arch/x86/include/asm/apic.h @@ -215,7 +215,7 @@ extern void setup_secondary_APIC_clock(void); extern int APIC_init_uniprocessor(void); extern int apic_force_enable(unsigned long addr); -extern int apic_bsp_setup(void); +extern int apic_bsp_setup(bool upmode); extern void apic_ap_setup(void); /* diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index 0a4107013ada..437c35bdddc8 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c @@ -2202,27 +2202,37 @@ void __init apic_set_eoi_write(void (*eoi_write)(u32 reg, u32 v)) } } -static void __init bsp_end_local_APIC_setup(void) +static void __init apic_bsp_up_setup(void) { - end_local_APIC_setup(); +#ifdef CONFIG_X86_64 + apic_write(APIC_ID, SET_APIC_ID(boot_cpu_physical_apicid)); +#else /* - * Now that local APIC setup is completed for BP, configure the fault - * handling for interrupt remapping. + * Hack: In case of kdump, after a crash, kernel might be booting + * on a cpu with non-zero lapic id. But boot_cpu_physical_apicid + * might be zero if read from MP tables. Get it from LAPIC. */ - irq_remap_enable_fault_handling(); +# ifdef CONFIG_CRASH_DUMP + boot_cpu_physical_apicid = read_apic_id(); +# endif +#endif + physid_set_mask_of_physid(boot_cpu_physical_apicid, &phys_cpu_present_map); } /** * apic_bsp_setup - Setup function for local apic and io-apic + * @upmode: Force UP mode (for APIC_init_uniprocessor) * * Returns: * apic_id of BSP APIC */ -int __init apic_bsp_setup(void) +int __init apic_bsp_setup(bool upmode) { int id; connect_bsp_APIC(); + if (upmode) + apic_bsp_up_setup(); setup_local_APIC(); if (x2apic_mode) @@ -2231,7 +2241,8 @@ int __init apic_bsp_setup(void) id = GET_APIC_LOGICAL_ID(apic_read(APIC_LDR)); enable_IO_APIC(); - bsp_end_local_APIC_setup(); + end_local_APIC_setup(); + irq_remap_enable_fault_handling(); setup_IO_APIC(); return id; } @@ -2267,32 +2278,12 @@ int __init APIC_init_uniprocessor(void) } #endif + if (!smp_found_config) + disable_ioapic_support(); + default_setup_apic_routing(); - verify_local_APIC(); - connect_bsp_APIC(); - -#ifdef CONFIG_X86_64 - apic_write(APIC_ID, SET_APIC_ID(boot_cpu_physical_apicid)); -#else - /* - * Hack: In case of kdump, after a crash, kernel might be booting - * on a cpu with non-zero lapic id. But boot_cpu_physical_apicid - * might be zero if read from MP tables. Get it from LAPIC. - */ -# ifdef CONFIG_CRASH_DUMP - boot_cpu_physical_apicid = read_apic_id(); -# endif -#endif - physid_set_mask_of_physid(boot_cpu_physical_apicid, &phys_cpu_present_map); - setup_local_APIC(); - - if (smp_found_config) - enable_IO_APIC(); - - bsp_end_local_APIC_setup(); - - setup_IO_APIC(); + apic_bsp_setup(true); x86_init.timers.setup_percpu_clockev(); return 0; diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c index fe8783d500c2..0a46e5e4fa1f 100644 --- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c @@ -1147,7 +1147,7 @@ void __init native_smp_prepare_cpus(unsigned int max_cpus) return; case SMP_FORCE_UP: disable_smp(); - apic_bsp_setup(); + apic_bsp_setup(false); return; case SMP_OK: break; @@ -1161,7 +1161,7 @@ void __init native_smp_prepare_cpus(unsigned int max_cpus) /* Or can we switch back to PIC here? */ } - cpu0_logical_apicid = apic_bsp_setup(); + cpu0_logical_apicid = apic_bsp_setup(false); /* * Set up local APIC timer on boot CPU. From 9c4d9c73dd380ecfe1893600174f96d0eb068997 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 15 Jan 2015 21:22:45 +0000 Subject: [PATCH 41/44] x86: Consolidate boot cpu timer setup Now that the APIC bringup is consolidated we can move the setup call for the percpu clock event device to apic_bsp_setup(). Signed-off-by: Thomas Gleixner Cc: Jiang Liu Cc: Joerg Roedel Cc: Tony Luck Cc: Borislav Petkov Link: http://lkml.kernel.org/r/20150115211704.162567839@linutronix.de Signed-off-by: Thomas Gleixner --- arch/x86/kernel/apic/apic.c | 4 ++-- arch/x86/kernel/smpboot.c | 4 ---- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index 437c35bdddc8..b665d241efad 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c @@ -2244,6 +2244,8 @@ int __init apic_bsp_setup(bool upmode) end_local_APIC_setup(); irq_remap_enable_fault_handling(); setup_IO_APIC(); + /* Setup local timer */ + x86_init.timers.setup_percpu_clockev(); return id; } @@ -2284,8 +2286,6 @@ int __init APIC_init_uniprocessor(void) default_setup_apic_routing(); verify_local_APIC(); apic_bsp_setup(true); - - x86_init.timers.setup_percpu_clockev(); return 0; } diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c index 0a46e5e4fa1f..febc6aabc72e 100644 --- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c @@ -1163,12 +1163,8 @@ void __init native_smp_prepare_cpus(unsigned int max_cpus) cpu0_logical_apicid = apic_bsp_setup(false); - /* - * Set up local APIC timer on boot CPU. - */ pr_info("CPU%d: ", 0); print_cpu_info(&cpu_data(0)); - x86_init.timers.setup_percpu_clockev(); if (is_uv_system()) uv_system_init(); From 2f82c9dc608a03913acc04e990b31fec22b2c0b7 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 22 Jan 2015 15:13:36 +0100 Subject: [PATCH 42/44] x86/acpi: Make acpi_[un]register_gsi_ioapic() depend on CONFIG_X86_LOCAL_APIC Get rid of the defined but not used warnings Signed-off-by: Thomas Gleixner Cc: Jiang Liu --- arch/x86/kernel/acpi/boot.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c index d1626364a28a..add9b3a4ba13 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -653,6 +653,7 @@ static int acpi_register_gsi_pic(struct device *dev, u32 gsi, return gsi; } +#ifdef CONFIG_X86_LOCAL_APIC static int acpi_register_gsi_ioapic(struct device *dev, u32 gsi, int trigger, int polarity) { @@ -675,6 +676,7 @@ static void acpi_unregister_gsi_ioapic(u32 gsi) mutex_unlock(&acpi_ioapic_lock); #endif } +#endif int (*__acpi_register_gsi)(struct device *dev, u32 gsi, int trigger, int polarity) = acpi_register_gsi_pic; From 3f4cb7c064847569c9a6b7ab5c6cf0f67c80c55a Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 23 Jan 2015 14:32:46 +0100 Subject: [PATCH 43/44] iommu/amd: Fix irq remapping detection logic Commit 7fa1c842caca "iommu/irq_remapping: Change variable disable_irq_remap to be static" returns unconditionally success from the irq remapping prepare callback if the iommu can be initialized. The change assumed that iommu_go_to_state(IOMMU_ACPI_FINISHED) returns a failure if irq remapping is not enabled, but thats not the case. The function returns success when the iommu is initialized to the point which is required for remapping to work. The actual state of the irq remapping feature is reflected in the status variable amd_iommu_irq_remap, which is not considered in the return value. The fix is simple: If the iommu_go_to_state() returns success, evaluate the remapping state amd_iommu_irq_remap and reflect it in the return value. Fixes: 7fa1c842caca iommu/irq_remapping: Change variable disable_irq_remap to be static Reported-and-tested-by: Borislav Petkov Signed-off-by: Thomas Gleixner Cc: Jiang Liu Cc: Joerg Roedel --- drivers/iommu/amd_iommu_init.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c index e430dc8dffdf..9a20248e7068 100644 --- a/drivers/iommu/amd_iommu_init.c +++ b/drivers/iommu/amd_iommu_init.c @@ -2120,9 +2120,14 @@ static int __init iommu_go_to_state(enum iommu_init_state state) #ifdef CONFIG_IRQ_REMAP int __init amd_iommu_prepare(void) { + int ret; + amd_iommu_irq_remap = true; - return iommu_go_to_state(IOMMU_ACPI_FINISHED); + ret = iommu_go_to_state(IOMMU_ACPI_FINISHED); + if (ret) + return ret; + return amd_iommu_irq_remap ? 0 : -ENODEV; } int __init amd_iommu_enable(void) From ba360f887a4130b06c55eb93bcb4ae373b262a1c Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sat, 24 Jan 2015 10:34:46 +0100 Subject: [PATCH 44/44] x86, init: Fix UP boot regression on x86_64 Commit 30b8b0066caf "init: Get rid of x86isms" broke the UP boot on x86_64. That happens because CONFIG_UP_LATE_INIT depends on CONFIG_X86_UP_APIC. X86_UP_APIC is a 32bit only config switch and therefor not set on 64bit UP builds. As a consequence the UP init of the local APIC and the IOAPIC is not called, which results in a boot failure. Make it depend on !SMP && X86_LOCAL_APIC instead. Fixes: 30b8b0066caf init: Get rid of x86isms Reported-by: Fengguang Wu Signed-off-by: Thomas Gleixner --- arch/x86/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index ffcc3ca5862a..04b8810a5489 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -857,7 +857,7 @@ source "kernel/Kconfig.preempt" config UP_LATE_INIT def_bool y - depends on X86_UP_APIC + depends on !SMP && X86_LOCAL_APIC config X86_UP_APIC bool "Local APIC support on uniprocessors"