Commit 9d43bade authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'x86-apic-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull x86 APIC updates from Ingo Molnar:
 "Continued fallout of the conversion of the x86 IRQ code to the
  hierarchical irqdomain framework: more cleanups, simplifications,
  memory allocation behavior enhancements, mainly in the interrupt
  remapping and APIC code"

* 'x86-apic-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (44 commits)
  x86, init: Fix UP boot regression on x86_64
  iommu/amd: Fix irq remapping detection logic
  x86/acpi: Make acpi_[un]register_gsi_ioapic() depend on CONFIG_X86_LOCAL_APIC
  x86: Consolidate boot cpu timer setup
  x86/apic: Reuse apic_bsp_setup() for UP APIC setup
  x86/smpboot: Sanitize uniprocessor init
  x86/smpboot: Move apic init code to apic.c
  init: Get rid of x86isms
  x86/apic: Move apic_init_uniprocessor code
  x86/smpboot: Cleanup ioapic handling
  x86/apic: Sanitize ioapic handling
  x86/ioapic: Add proper checks to setp/enable_IO_APIC()
  x86/ioapic: Provide stub functions for IOAPIC%3Dn
  x86/smpboot: Move smpboot inlines to code
  x86/x2apic: Use state information for disable
  x86/x2apic: Split enable and setup function
  x86/x2apic: Disable x2apic from nox2apic setup
  x86/x2apic: Add proper state tracking
  x86/x2apic: Clarify remapping mode for x2apic enablement
  x86/x2apic: Move code in conditional region
  ...
parents 0ba97bc4 ba360f88
...@@ -856,6 +856,10 @@ config SCHED_MC ...@@ -856,6 +856,10 @@ config SCHED_MC
source "kernel/Kconfig.preempt" source "kernel/Kconfig.preempt"
config UP_LATE_INIT
def_bool y
depends on !SMP && X86_LOCAL_APIC
config X86_UP_APIC config X86_UP_APIC
bool "Local APIC support on uniprocessors" bool "Local APIC support on uniprocessors"
depends on X86_32 && !SMP && !X86_32_NON_STANDARD depends on X86_32 && !SMP && !X86_32_NON_STANDARD
......
...@@ -106,7 +106,14 @@ extern u32 native_safe_apic_wait_icr_idle(void); ...@@ -106,7 +106,14 @@ extern u32 native_safe_apic_wait_icr_idle(void);
extern void native_apic_icr_write(u32 low, u32 id); extern void native_apic_icr_write(u32 low, u32 id);
extern u64 native_apic_icr_read(void); 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 #ifdef CONFIG_X86_X2APIC
/* /*
...@@ -169,48 +176,23 @@ static inline u64 native_x2apic_icr_read(void) ...@@ -169,48 +176,23 @@ static inline u64 native_x2apic_icr_read(void)
return val; return val;
} }
extern int x2apic_mode;
extern int x2apic_phys; extern int x2apic_phys;
extern int x2apic_preenabled; extern void __init check_x2apic(void);
extern void check_x2apic(void); extern void x2apic_setup(void);
extern void enable_x2apic(void);
static inline int x2apic_enabled(void) static inline int x2apic_enabled(void)
{ {
u64 msr; return cpu_has_x2apic && apic_is_x2apic_enabled();
if (!cpu_has_x2apic)
return 0;
rdmsrl(MSR_IA32_APICBASE, msr);
if (msr & X2APIC_ENABLE)
return 1;
return 0;
} }
#define x2apic_supported() (cpu_has_x2apic) #define x2apic_supported() (cpu_has_x2apic)
static inline void x2apic_force_phys(void)
{
x2apic_phys = 1;
}
#else #else
static inline void disable_x2apic(void) static inline void check_x2apic(void) { }
{ static inline void x2apic_setup(void) { }
} static inline int x2apic_enabled(void) { return 0; }
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)
{
}
#define x2apic_preenabled 0 #define x2apic_mode (0)
#define x2apic_supported() 0 #define x2apic_supported() (0)
#endif #endif
extern void enable_IR_x2apic(void); extern void enable_IR_x2apic(void);
...@@ -219,7 +201,6 @@ extern int get_physical_broadcast(void); ...@@ -219,7 +201,6 @@ extern int get_physical_broadcast(void);
extern int lapic_get_maxlvt(void); extern int lapic_get_maxlvt(void);
extern void clear_local_APIC(void); extern void clear_local_APIC(void);
extern void connect_bsp_APIC(void);
extern void disconnect_bsp_APIC(int virt_wire_setup); extern void disconnect_bsp_APIC(int virt_wire_setup);
extern void disable_local_APIC(void); extern void disable_local_APIC(void);
extern void lapic_shutdown(void); extern void lapic_shutdown(void);
...@@ -227,8 +208,6 @@ extern int verify_local_APIC(void); ...@@ -227,8 +208,6 @@ extern int verify_local_APIC(void);
extern void sync_Arb_IDs(void); extern void sync_Arb_IDs(void);
extern void init_bsp_APIC(void); extern void init_bsp_APIC(void);
extern void setup_local_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); extern void init_apic_mappings(void);
void register_lapic_address(unsigned long address); void register_lapic_address(unsigned long address);
extern void setup_boot_APIC_clock(void); extern void setup_boot_APIC_clock(void);
...@@ -236,6 +215,9 @@ extern void setup_secondary_APIC_clock(void); ...@@ -236,6 +215,9 @@ extern void setup_secondary_APIC_clock(void);
extern int APIC_init_uniprocessor(void); extern int APIC_init_uniprocessor(void);
extern int apic_force_enable(unsigned long addr); extern int apic_force_enable(unsigned long addr);
extern int apic_bsp_setup(bool upmode);
extern void apic_ap_setup(void);
/* /*
* On 32bit this is mach-xxx local * On 32bit this is mach-xxx local
*/ */
......
...@@ -279,6 +279,11 @@ static inline void disable_ioapic_support(void) { } ...@@ -279,6 +279,11 @@ static inline void disable_ioapic_support(void) { }
#define native_ioapic_set_affinity NULL #define native_ioapic_set_affinity NULL
#define native_setup_ioapic_entry NULL #define native_setup_ioapic_entry NULL
#define native_eoi_ioapic_pin 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
#endif /* _ASM_X86_IO_APIC_H */ #endif /* _ASM_X86_IO_APIC_H */
...@@ -33,8 +33,6 @@ struct irq_cfg; ...@@ -33,8 +33,6 @@ struct irq_cfg;
#ifdef CONFIG_IRQ_REMAP #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 void set_irq_remapping_broken(void);
extern int irq_remapping_prepare(void); extern int irq_remapping_prepare(void);
extern int irq_remapping_enable(void); extern int irq_remapping_enable(void);
...@@ -60,8 +58,6 @@ void irq_remap_modify_chip_defaults(struct irq_chip *chip); ...@@ -60,8 +58,6 @@ void irq_remap_modify_chip_defaults(struct irq_chip *chip);
#else /* CONFIG_IRQ_REMAP */ #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 void set_irq_remapping_broken(void) { }
static inline int irq_remapping_prepare(void) { return -ENODEV; } static inline int irq_remapping_prepare(void) { return -ENODEV; }
static inline int irq_remapping_enable(void) { return -ENODEV; } static inline int irq_remapping_enable(void) { return -ENODEV; }
......
/* 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
}
...@@ -653,6 +653,7 @@ static int acpi_register_gsi_pic(struct device *dev, u32 gsi, ...@@ -653,6 +653,7 @@ static int acpi_register_gsi_pic(struct device *dev, u32 gsi,
return gsi; return gsi;
} }
#ifdef CONFIG_X86_LOCAL_APIC
static int acpi_register_gsi_ioapic(struct device *dev, u32 gsi, static int acpi_register_gsi_ioapic(struct device *dev, u32 gsi,
int trigger, int polarity) int trigger, int polarity)
{ {
...@@ -675,6 +676,7 @@ static void acpi_unregister_gsi_ioapic(u32 gsi) ...@@ -675,6 +676,7 @@ static void acpi_unregister_gsi_ioapic(u32 gsi)
mutex_unlock(&acpi_ioapic_lock); mutex_unlock(&acpi_ioapic_lock);
#endif #endif
} }
#endif
int (*__acpi_register_gsi)(struct device *dev, u32 gsi, int (*__acpi_register_gsi)(struct device *dev, u32 gsi,
int trigger, int polarity) = acpi_register_gsi_pic; int trigger, int polarity) = acpi_register_gsi_pic;
......
This diff is collapsed.
...@@ -1507,7 +1507,10 @@ void __init enable_IO_APIC(void) ...@@ -1507,7 +1507,10 @@ void __init enable_IO_APIC(void)
int i8259_apic, i8259_pin; int i8259_apic, i8259_pin;
int apic, pin; int apic, pin;
if (!nr_legacy_irqs()) if (skip_ioapic_setup)
nr_ioapics = 0;
if (!nr_legacy_irqs() || !nr_ioapics)
return; return;
for_each_ioapic_pin(apic, pin) { for_each_ioapic_pin(apic, pin) {
...@@ -2295,7 +2298,7 @@ static inline void __init check_timer(void) ...@@ -2295,7 +2298,7 @@ static inline void __init check_timer(void)
} }
local_irq_disable(); local_irq_disable();
apic_printk(APIC_QUIET, KERN_INFO "..... failed :(.\n"); apic_printk(APIC_QUIET, KERN_INFO "..... failed :(.\n");
if (x2apic_preenabled) if (apic_is_x2apic_enabled())
apic_printk(APIC_QUIET, KERN_INFO apic_printk(APIC_QUIET, KERN_INFO
"Perhaps problem with the pre-enabled x2apic mode\n" "Perhaps problem with the pre-enabled x2apic mode\n"
"Try booting with x2apic and interrupt-remapping disabled in the bios.\n"); "Try booting with x2apic and interrupt-remapping disabled in the bios.\n");
...@@ -2373,9 +2376,9 @@ void __init setup_IO_APIC(void) ...@@ -2373,9 +2376,9 @@ void __init setup_IO_APIC(void)
{ {
int ioapic; int ioapic;
/* if (skip_ioapic_setup || !nr_ioapics)
* calling enable_IO_APIC() is moved to setup_local_APIC for BP return;
*/
io_apic_irqs = nr_legacy_irqs() ? ~PIC_IRQS : ~0UL; io_apic_irqs = nr_legacy_irqs() ? ~PIC_IRQS : ~0UL;
apic_printk(APIC_VERBOSE, "ENABLING IO-APIC IRQs\n"); apic_printk(APIC_VERBOSE, "ENABLING IO-APIC IRQs\n");
......
...@@ -1332,7 +1332,7 @@ void cpu_init(void) ...@@ -1332,7 +1332,7 @@ void cpu_init(void)
barrier(); barrier();
x86_configure_nx(); x86_configure_nx();
enable_x2apic(); x2apic_setup();
/* /*
* set up and load the per-CPU TSS * set up and load the per-CPU TSS
......
...@@ -73,7 +73,6 @@ ...@@ -73,7 +73,6 @@
#include <asm/setup.h> #include <asm/setup.h>
#include <asm/uv/uv.h> #include <asm/uv/uv.h>
#include <linux/mc146818rtc.h> #include <linux/mc146818rtc.h>
#include <asm/smpboot_hooks.h>
#include <asm/i8259.h> #include <asm/i8259.h>
#include <asm/realmode.h> #include <asm/realmode.h>
#include <asm/misc.h> #include <asm/misc.h>
...@@ -104,6 +103,43 @@ EXPORT_PER_CPU_SYMBOL(cpu_info); ...@@ -104,6 +103,43 @@ EXPORT_PER_CPU_SYMBOL(cpu_info);
atomic_t init_deasserted; atomic_t init_deasserted;
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;
}
/* /*
* Report back to the Boot Processor during boot time or to the caller processor * Report back to the Boot Processor during boot time or to the caller processor
* during CPU online. * during CPU online.
...@@ -136,8 +172,7 @@ static void smp_callin(void) ...@@ -136,8 +172,7 @@ static void smp_callin(void)
* CPU, first the APIC. (this is probably redundant on most * CPU, first the APIC. (this is probably redundant on most
* boards) * boards)
*/ */
setup_local_APIC(); apic_ap_setup();
end_local_APIC_setup();
/* /*
* Need to setup vector mappings before we enable interrupts. * Need to setup vector mappings before we enable interrupts.
...@@ -955,9 +990,12 @@ void arch_disable_smp_support(void) ...@@ -955,9 +990,12 @@ void arch_disable_smp_support(void)
*/ */
static __init void disable_smp(void) static __init void disable_smp(void)
{ {
pr_info("SMP disabled\n");
disable_ioapic_support();
init_cpu_present(cpumask_of(0)); init_cpu_present(cpumask_of(0));
init_cpu_possible(cpumask_of(0)); init_cpu_possible(cpumask_of(0));
smpboot_clear_io_apic_irqs();
if (smp_found_config) if (smp_found_config)
physid_set_mask_of_physid(boot_cpu_physical_apicid, &phys_cpu_present_map); physid_set_mask_of_physid(boot_cpu_physical_apicid, &phys_cpu_present_map);
...@@ -967,6 +1005,13 @@ static __init void disable_smp(void) ...@@ -967,6 +1005,13 @@ static __init void disable_smp(void)
cpumask_set_cpu(0, cpu_core_mask(0)); cpumask_set_cpu(0, cpu_core_mask(0));
} }
enum {
SMP_OK,
SMP_NO_CONFIG,
SMP_NO_APIC,
SMP_FORCE_UP,
};
/* /*
* Various sanity checks. * Various sanity checks.
*/ */
...@@ -1014,10 +1059,7 @@ static int __init smp_sanity_check(unsigned max_cpus) ...@@ -1014,10 +1059,7 @@ static int __init smp_sanity_check(unsigned max_cpus)
if (!smp_found_config && !acpi_lapic) { if (!smp_found_config && !acpi_lapic) {
preempt_enable(); preempt_enable();
pr_notice("SMP motherboard not detected\n"); pr_notice("SMP motherboard not detected\n");
disable_smp(); return SMP_NO_CONFIG;
if (APIC_init_uniprocessor())
pr_notice("Local APIC not detected. Using dummy APIC emulation.\n");
return -1;
} }
/* /*
...@@ -1041,9 +1083,7 @@ static int __init smp_sanity_check(unsigned max_cpus) ...@@ -1041,9 +1083,7 @@ static int __init smp_sanity_check(unsigned max_cpus)
boot_cpu_physical_apicid); boot_cpu_physical_apicid);
pr_err("... forcing use of dummy APIC emulation (tell your hw vendor)\n"); pr_err("... forcing use of dummy APIC emulation (tell your hw vendor)\n");
} }
smpboot_clear_io_apic(); return SMP_NO_APIC;
disable_ioapic_support();
return -1;
} }
verify_local_APIC(); verify_local_APIC();
...@@ -1053,15 +1093,10 @@ static int __init smp_sanity_check(unsigned max_cpus) ...@@ -1053,15 +1093,10 @@ static int __init smp_sanity_check(unsigned max_cpus)
*/ */
if (!max_cpus) { if (!max_cpus) {
pr_info("SMP mode deactivated\n"); pr_info("SMP mode deactivated\n");
smpboot_clear_io_apic(); return SMP_FORCE_UP;
connect_bsp_APIC();
setup_local_APIC();
bsp_end_local_APIC_setup();
return -1;
} }
return 0; return SMP_OK;
} }
static void __init smp_cpu_index_default(void) static void __init smp_cpu_index_default(void)
...@@ -1101,10 +1136,21 @@ void __init native_smp_prepare_cpus(unsigned int max_cpus) ...@@ -1101,10 +1136,21 @@ void __init native_smp_prepare_cpus(unsigned int max_cpus)
} }
set_cpu_sibling_map(0); set_cpu_sibling_map(0);
if (smp_sanity_check(max_cpus) < 0) { switch (smp_sanity_check(max_cpus)) {
pr_info("SMP disabled\n"); case SMP_NO_CONFIG:
disable_smp(); disable_smp();
if (APIC_init_uniprocessor())
pr_notice("Local APIC not detected. Using dummy APIC emulation.\n");
return; return;
case SMP_NO_APIC:
disable_smp();
return;
case SMP_FORCE_UP:
disable_smp();
apic_bsp_setup(false);
return;
case SMP_OK:
break;
} }
default_setup_apic_routing(); default_setup_apic_routing();
...@@ -1115,33 +1161,10 @@ void __init native_smp_prepare_cpus(unsigned int max_cpus) ...@@ -1115,33 +1161,10 @@ void __init native_smp_prepare_cpus(unsigned int max_cpus)
/* Or can we switch back to PIC here? */ /* Or can we switch back to PIC here? */
} }
connect_bsp_APIC(); cpu0_logical_apicid = apic_bsp_setup(false);
/*
* 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
*/
if (!skip_ioapic_setup && nr_ioapics)
enable_IO_APIC();
bsp_end_local_APIC_setup();
smpboot_setup_io_apic();
/*
* Set up local APIC timer on boot CPU.
*/
pr_info("CPU%d: ", 0); pr_info("CPU%d: ", 0);
print_cpu_info(&cpu_data(0)); print_cpu_info(&cpu_data(0));
x86_init.timers.setup_percpu_clockev();
if (is_uv_system()) if (is_uv_system())
uv_system_init(); uv_system_init();
...@@ -1177,9 +1200,7 @@ void __init native_smp_cpus_done(unsigned int max_cpus) ...@@ -1177,9 +1200,7 @@ void __init native_smp_cpus_done(unsigned int max_cpus)
nmi_selftest(); nmi_selftest();
impress_friends(); impress_friends();
#ifdef CONFIG_X86_IO_APIC
setup_ioapic_dest(); setup_ioapic_dest();
#endif
mtrr_aps_init(); mtrr_aps_init();
} }
......
...@@ -4284,7 +4284,6 @@ static int alloc_hpet_msi(unsigned int irq, unsigned int id) ...@@ -4284,7 +4284,6 @@ static int alloc_hpet_msi(unsigned int irq, unsigned int id)
} }
struct irq_remap_ops amd_iommu_irq_ops = { struct irq_remap_ops amd_iommu_irq_ops = {
.supported = amd_iommu_supported,
.prepare = amd_iommu_prepare, .prepare = amd_iommu_prepare,
.enable = amd_iommu_enable, .enable = amd_iommu_enable,
.disable = amd_iommu_disable, .disable = amd_iommu_disable,
......
...@@ -2014,9 +2014,6 @@ static bool detect_ivrs(void) ...@@ -2014,9 +2014,6 @@ static bool detect_ivrs(void)
/* Make sure ACS will be enabled during PCI probe */ /* Make sure ACS will be enabled during PCI probe */
pci_request_acs(); pci_request_acs();
if (!disable_irq_remap)
amd_iommu_irq_remap = true;
return true; return true;
} }
...@@ -2123,12 +2120,14 @@ static int __init iommu_go_to_state(enum iommu_init_state state) ...@@ -2123,12 +2120,14 @@ static int __init iommu_go_to_state(enum iommu_init_state state)
#ifdef CONFIG_IRQ_REMAP #ifdef CONFIG_IRQ_REMAP
int __init amd_iommu_prepare(void) int __init amd_iommu_prepare(void)
{ {
return iommu_go_to_state(IOMMU_ACPI_FINISHED); int ret;
}
int __init amd_iommu_supported(void) amd_iommu_irq_remap = true;
{
return amd_iommu_irq_remap ? 1 : 0; 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) int __init amd_iommu_enable(void)
......
...@@ -33,7 +33,6 @@ extern void amd_iommu_init_notifier(void); ...@@ -33,7 +33,6 @@ extern void amd_iommu_init_notifier(void);
extern void amd_iommu_init_api(void); extern void amd_iommu_init_api(void);
/* Needed for interrupt remapping */ /* Needed for interrupt remapping */
extern int amd_iommu_supported(void);
extern int amd_iommu_prepare(void); extern int amd_iommu_prepare(void);
extern int amd_iommu_enable(void); extern int amd_iommu_enable(void);
extern void amd_iommu_disable(void); extern void amd_iommu_disable(void);
......
...@@ -32,8 +32,9 @@ struct hpet_scope { ...@@ -32,8 +32,9 @@ struct hpet_scope {
}; };
#define IR_X2APIC_MODE(mode) (mode ? (1 << 11) : 0) #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 ioapic_scope ir_ioapic[MAX_IO_APICS];
static struct hpet_scope ir_hpet[MAX_HPET_TBS]; static struct hpet_scope ir_hpet[MAX_HPET_TBS];
...@@ -481,11 +482,11 @@ static int intel_setup_irq_remapping(struct intel_iommu *iommu) ...@@ -481,11 +482,11 @@ static int intel_setup_irq_remapping(struct intel_iommu *iommu)
if (iommu->ir_table) if (iommu->ir_table)
return 0; return 0;
ir_table = kzalloc(sizeof(struct ir_table), GFP_ATOMIC); ir_table = kzalloc(sizeof(struct ir_table), GFP_KERNEL);
if (!ir_table) if (!ir_table)
return -ENOMEM; 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); INTR_REMAP_PAGE_ORDER);
if (!pages) { if (!pages) {
...@@ -566,13 +567,27 @@ static int __init dmar_x2apic_optout(void) ...@@ -566,13 +567,27 @@ static int __init dmar_x2apic_optout(void)
return dmar->flags & DMAR_X2APIC_OPT_OUT; return dmar->flags & DMAR_X2APIC_OPT_OUT;
} }
static int __init intel_irq_remapping_supported(void) 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 dmar_drhd_unit *drhd;
struct intel_iommu *iommu; struct intel_iommu *iommu;
if (disable_irq_remap)
return 0;
if (irq_remap_broken) { if (irq_remap_broken) {
printk(KERN_WARNING printk(KERN_WARNING
"This system BIOS has enabled interrupt remapping\n" "This system BIOS has enabled interrupt remapping\n"
...@@ -581,38 +596,45 @@ static int __init intel_irq_remapping_supported(void) ...@@ -581,38 +596,45 @@ static int __init intel_irq_remapping_supported(void)
"interrupt remapping is being disabled. Please\n" "interrupt remapping is being disabled. Please\n"
"contact your BIOS vendor for an update\n"); "contact your BIOS vendor for an update\n");
add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_STILL_OK); add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_STILL_OK);
disable_irq_remap = 1; return -ENODEV;
return 0;
} }
if (dmar_table_init() < 0)
return -ENODEV;
if (!dmar_ir_support()) if (!dmar_ir_support())
return 0; return -ENODEV;
if (parse_ioapics_under_ir() != 1) {
printk(KERN_INFO "Not enabling interrupt remapping\n");
goto error;
}
/* First make sure all IOMMUs support IRQ remapping */
for_each_iommu(iommu, drhd) for_each_iommu(iommu, drhd)
if (!ecap_ir_support(iommu->ecap)) if (!ecap_ir_support(iommu->ecap))
return 0; goto error;
return 1; /* Do the allocations early */
for_each_iommu(iommu, drhd)
if (intel_setup_irq_remapping(iommu))
goto error;
return 0;
error:
intel_cleanup_irq_remapping();
return -ENODEV;
} }
static int __init intel_enable_irq_remapping(void) static int __init intel_enable_irq_remapping(void)
{ {
struct dmar_drhd_unit *drhd; struct dmar_drhd_unit *drhd;
struct intel_iommu *iommu; struct intel_iommu *iommu;
bool x2apic_present;
int setup = 0; int setup = 0;
int eim = 0; int eim = 0;
x2apic_present = x2apic_supported(); if (x2apic_supported()) {
if (parse_ioapics_under_ir() != 1) {
printk(KERN_INFO "Not enable interrupt remapping\n");
goto error;
}
if (x2apic_present) {
pr_info("Queued invalidation will be enabled to support x2apic and Intr-remapping.\n");
eim = !dmar_x2apic_optout(); eim = !dmar_x2apic_optout();
if (!eim) if (!eim)
printk(KERN_WARNING printk(KERN_WARNING
...@@ -646,16 +668,15 @@ static int __init intel_enable_irq_remapping(void) ...@@ -646,16 +668,15 @@ static int __init intel_enable_irq_remapping(void)
/* /*
* check for the Interrupt-remapping support * check for the Interrupt-remapping support
*/ */
for_each_iommu(iommu, drhd) { for_each_iommu(iommu, drhd)
if (!ecap_ir_support(iommu->ecap))
continue;
if (eim && !ecap_eim_support(iommu->ecap)) { if (eim && !ecap_eim_support(iommu->ecap)) {
printk(KERN_INFO "DRHD %Lx: EIM not supported by DRHD, " printk(KERN_INFO "DRHD %Lx: EIM not supported by DRHD, "
" ecap %Lx\n", drhd->reg_base_addr, iommu->ecap); " 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. * Enable queued invalidation for all the DRHD's.
...@@ -675,12 +696,6 @@ static int __init intel_enable_irq_remapping(void) ...@@ -675,12 +696,6 @@ static int __init intel_enable_irq_remapping(void)
* Setup Interrupt-remapping for all the DRHD's now. * Setup Interrupt-remapping for all the DRHD's now.
*/ */
for_each_iommu(iommu, drhd) { for_each_iommu(iommu, drhd) {
if (!ecap_ir_support(iommu->ecap))
continue;
if (intel_setup_irq_remapping(iommu))
goto error;
iommu_set_irq_remapping(iommu, eim); iommu_set_irq_remapping(iommu, eim);
setup = 1; setup = 1;
} }
...@@ -702,15 +717,7 @@ static int __init intel_enable_irq_remapping(void) ...@@ -702,15 +717,7 @@ static int __init intel_enable_irq_remapping(void)
return eim ? IRQ_REMAP_X2APIC_MODE : IRQ_REMAP_XAPIC_MODE; return eim ? IRQ_REMAP_X2APIC_MODE : IRQ_REMAP_XAPIC_MODE;
error: error:
for_each_iommu(iommu, drhd) intel_cleanup_irq_remapping();
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");
return -1; return -1;
} }
...@@ -1199,8 +1206,7 @@ static int intel_alloc_hpet_msi(unsigned int irq, unsigned int id) ...@@ -1199,8 +1206,7 @@ static int intel_alloc_hpet_msi(unsigned int irq, unsigned int id)
} }
struct irq_remap_ops intel_irq_remap_ops = { struct irq_remap_ops intel_irq_remap_ops = {
.supported = intel_irq_remapping_supported, .prepare = intel_prepare_irq_remapping,
.prepare = dmar_table_init,
.enable = intel_enable_irq_remapping, .enable = intel_enable_irq_remapping,
.disable = disable_irq_remapping, .disable = disable_irq_remapping,
.reenable = reenable_irq_remapping, .reenable = reenable_irq_remapping,
......
...@@ -17,12 +17,11 @@ ...@@ -17,12 +17,11 @@
#include "irq_remapping.h" #include "irq_remapping.h"
int irq_remapping_enabled; int irq_remapping_enabled;
int disable_irq_remap;
int irq_remap_broken; int irq_remap_broken;
int disable_sourceid_checking; int disable_sourceid_checking;
int no_x2apic_optout; int no_x2apic_optout;
static int disable_irq_remap;
static struct irq_remap_ops *remap_ops; static struct irq_remap_ops *remap_ops;
static int msi_alloc_remapped_irq(struct pci_dev *pdev, int irq, int nvec); static int msi_alloc_remapped_irq(struct pci_dev *pdev, int irq, int nvec);
...@@ -194,45 +193,32 @@ static __init int setup_irqremap(char *str) ...@@ -194,45 +193,32 @@ static __init int setup_irqremap(char *str)
} }
early_param("intremap", setup_irqremap); 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) void set_irq_remapping_broken(void)
{ {
irq_remap_broken = 1; irq_remap_broken = 1;
} }
int irq_remapping_supported(void) int __init irq_remapping_prepare(void)
{ {
if (disable_irq_remap) if (disable_irq_remap)
return 0; return -ENOSYS;
if (!remap_ops || !remap_ops->supported)
return 0;
return remap_ops->supported();
}
int __init irq_remapping_prepare(void) if (intel_irq_remap_ops.prepare() == 0)
{ remap_ops = &intel_irq_remap_ops;
if (!remap_ops || !remap_ops->prepare) else if (IS_ENABLED(CONFIG_AMD_IOMMU) &&
return -ENODEV; amd_iommu_irq_ops.prepare() == 0)
remap_ops = &amd_iommu_irq_ops;
else
return -ENOSYS;
return remap_ops->prepare(); return 0;
} }
int __init irq_remapping_enable(void) int __init irq_remapping_enable(void)
{ {
int ret; int ret;
if (!remap_ops || !remap_ops->enable) if (!remap_ops->enable)
return -ENODEV; return -ENODEV;
ret = remap_ops->enable(); ret = remap_ops->enable();
...@@ -245,22 +231,16 @@ int __init irq_remapping_enable(void) ...@@ -245,22 +231,16 @@ int __init irq_remapping_enable(void)
void irq_remapping_disable(void) void irq_remapping_disable(void)
{ {
if (!irq_remapping_enabled || if (irq_remapping_enabled && remap_ops->disable)
!remap_ops || remap_ops->disable();
!remap_ops->disable)
return;
remap_ops->disable();
} }
int irq_remapping_reenable(int mode) int irq_remapping_reenable(int mode)
{ {
if (!irq_remapping_enabled || if (irq_remapping_enabled && remap_ops->reenable)
!remap_ops || return remap_ops->reenable(mode);
!remap_ops->reenable)
return 0;
return remap_ops->reenable(mode); return 0;
} }
int __init irq_remap_enable_fault_handling(void) int __init irq_remap_enable_fault_handling(void)
...@@ -268,7 +248,7 @@ int __init irq_remap_enable_fault_handling(void) ...@@ -268,7 +248,7 @@ int __init irq_remap_enable_fault_handling(void)
if (!irq_remapping_enabled) if (!irq_remapping_enabled)
return 0; return 0;
if (!remap_ops || !remap_ops->enable_faulting) if (!remap_ops->enable_faulting)
return -ENODEV; return -ENODEV;
return remap_ops->enable_faulting(); return remap_ops->enable_faulting();
...@@ -279,7 +259,7 @@ int setup_ioapic_remapped_entry(int irq, ...@@ -279,7 +259,7 @@ int setup_ioapic_remapped_entry(int irq,
unsigned int destination, int vector, unsigned int destination, int vector,
struct io_apic_irq_attr *attr) struct io_apic_irq_attr *attr)
{ {
if (!remap_ops || !remap_ops->setup_ioapic_entry) if (!remap_ops->setup_ioapic_entry)
return -ENODEV; return -ENODEV;
return remap_ops->setup_ioapic_entry(irq, entry, destination, return remap_ops->setup_ioapic_entry(irq, entry, destination,
...@@ -289,8 +269,7 @@ int setup_ioapic_remapped_entry(int irq, ...@@ -289,8 +269,7 @@ int setup_ioapic_remapped_entry(int irq,
static int set_remapped_irq_affinity(struct irq_data *data, static int set_remapped_irq_affinity(struct irq_data *data,
const struct cpumask *mask, bool force) const struct cpumask *mask, bool force)
{ {
if (!config_enabled(CONFIG_SMP) || !remap_ops || if (!config_enabled(CONFIG_SMP) || !remap_ops->set_affinity)
!remap_ops->set_affinity)
return 0; return 0;
return remap_ops->set_affinity(data, mask, force); return remap_ops->set_affinity(data, mask, force);
...@@ -300,10 +279,7 @@ void free_remapped_irq(int irq) ...@@ -300,10 +279,7 @@ void free_remapped_irq(int irq)
{ {
struct irq_cfg *cfg = irq_cfg(irq); struct irq_cfg *cfg = irq_cfg(irq);
if (!remap_ops || !remap_ops->free_irq) if (irq_remapped(cfg) && remap_ops->free_irq)
return;
if (irq_remapped(cfg))
remap_ops->free_irq(irq); remap_ops->free_irq(irq);
} }
...@@ -315,13 +291,13 @@ void compose_remapped_msi_msg(struct pci_dev *pdev, ...@@ -315,13 +291,13 @@ void compose_remapped_msi_msg(struct pci_dev *pdev,
if (!irq_remapped(cfg)) if (!irq_remapped(cfg))
native_compose_msi_msg(pdev, irq, dest, msg, hpet_id); 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); 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) 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 -ENODEV;
return remap_ops->msi_alloc_irq(pdev, irq, nvec); return remap_ops->msi_alloc_irq(pdev, irq, nvec);
...@@ -330,7 +306,7 @@ static int msi_alloc_remapped_irq(struct pci_dev *pdev, int irq, int nvec) ...@@ -330,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, static int msi_setup_remapped_irq(struct pci_dev *pdev, unsigned int irq,
int index, int sub_handle) int index, int sub_handle)
{ {
if (!remap_ops || !remap_ops->msi_setup_irq) if (!remap_ops->msi_setup_irq)
return -ENODEV; return -ENODEV;
return remap_ops->msi_setup_irq(pdev, irq, index, sub_handle); return remap_ops->msi_setup_irq(pdev, irq, index, sub_handle);
...@@ -340,7 +316,7 @@ int setup_hpet_msi_remapped(unsigned int irq, unsigned int id) ...@@ -340,7 +316,7 @@ int setup_hpet_msi_remapped(unsigned int irq, unsigned int id)
{ {
int ret; int ret;
if (!remap_ops || !remap_ops->alloc_hpet_msi) if (!remap_ops->alloc_hpet_msi)
return -ENODEV; return -ENODEV;
ret = remap_ops->alloc_hpet_msi(irq, id); ret = remap_ops->alloc_hpet_msi(irq, id);
......
...@@ -31,16 +31,12 @@ struct cpumask; ...@@ -31,16 +31,12 @@ struct cpumask;
struct pci_dev; struct pci_dev;
struct msi_msg; struct msi_msg;
extern int disable_irq_remap;
extern int irq_remap_broken; extern int irq_remap_broken;
extern int disable_sourceid_checking; extern int disable_sourceid_checking;
extern int no_x2apic_optout; extern int no_x2apic_optout;
extern int irq_remapping_enabled; extern int irq_remapping_enabled;
struct irq_remap_ops { struct irq_remap_ops {
/* Check whether Interrupt Remapping is supported */
int (*supported)(void);
/* Initializes hardware and makes it ready for remapping interrupts */ /* Initializes hardware and makes it ready for remapping interrupts */
int (*prepare)(void); int (*prepare)(void);
...@@ -89,7 +85,6 @@ extern struct irq_remap_ops amd_iommu_irq_ops; ...@@ -89,7 +85,6 @@ extern struct irq_remap_ops amd_iommu_irq_ops;
#else /* CONFIG_IRQ_REMAP */ #else /* CONFIG_IRQ_REMAP */
#define irq_remapping_enabled 0 #define irq_remapping_enabled 0
#define disable_irq_remap 1
#define irq_remap_broken 0 #define irq_remap_broken 0
#endif /* CONFIG_IRQ_REMAP */ #endif /* CONFIG_IRQ_REMAP */
......
...@@ -151,6 +151,13 @@ smp_call_function_any(const struct cpumask *mask, smp_call_func_t func, ...@@ -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 kick_all_cpus_sync(void) { }
static inline void wake_up_all_idle_cpus(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 */ #endif /* !SMP */
/* /*
......
...@@ -87,10 +87,6 @@ ...@@ -87,10 +87,6 @@
#include <asm/sections.h> #include <asm/sections.h>
#include <asm/cacheflush.h> #include <asm/cacheflush.h>
#ifdef CONFIG_X86_LOCAL_APIC
#include <asm/smp.h>
#endif
static int kernel_init(void *); static int kernel_init(void *);
extern void init_IRQ(void); extern void init_IRQ(void);
...@@ -351,15 +347,6 @@ __setup("rdinit=", rdinit_setup); ...@@ -351,15 +347,6 @@ __setup("rdinit=", rdinit_setup);
#ifndef CONFIG_SMP #ifndef CONFIG_SMP
static const unsigned int setup_max_cpus = NR_CPUS; 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 setup_nr_cpu_ids(void) { }
static inline void smp_prepare_cpus(unsigned int maxcpus) { } static inline void smp_prepare_cpus(unsigned int maxcpus) { }
#endif #endif
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment