mirror of
https://github.com/torvalds/linux.git
synced 2024-11-23 04:31:50 +00:00
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 ...
This commit is contained in:
commit
9d43bade34
@ -856,6 +856,10 @@ config SCHED_MC
|
||||
|
||||
source "kernel/Kconfig.preempt"
|
||||
|
||||
config UP_LATE_INIT
|
||||
def_bool y
|
||||
depends on !SMP && X86_LOCAL_APIC
|
||||
|
||||
config X86_UP_APIC
|
||||
bool "Local APIC support on uniprocessors"
|
||||
depends on X86_32 && !SMP && !X86_32_NON_STANDARD
|
||||
|
@ -106,7 +106,14 @@ 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;
|
||||
|
||||
if (rdmsrl_safe(MSR_IA32_APICBASE, &msr))
|
||||
return false;
|
||||
return msr & X2APIC_ENABLE;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_X86_X2APIC
|
||||
/*
|
||||
@ -169,48 +176,23 @@ 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);
|
||||
extern void enable_x2apic(void);
|
||||
extern void __init check_x2apic(void);
|
||||
extern void x2apic_setup(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)
|
||||
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 check_x2apic(void) { }
|
||||
static inline void x2apic_setup(void) { }
|
||||
static inline int x2apic_enabled(void) { return 0; }
|
||||
|
||||
#define x2apic_preenabled 0
|
||||
#define x2apic_supported() 0
|
||||
#define x2apic_mode (0)
|
||||
#define x2apic_supported() (0)
|
||||
#endif
|
||||
|
||||
extern void enable_IR_x2apic(void);
|
||||
@ -219,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);
|
||||
@ -227,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);
|
||||
@ -236,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(bool upmode);
|
||||
extern void apic_ap_setup(void);
|
||||
|
||||
/*
|
||||
* On 32bit this is mach-xxx local
|
||||
*/
|
||||
|
@ -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 */
|
||||
|
@ -33,8 +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);
|
||||
extern int irq_remapping_enable(void);
|
||||
@ -60,8 +58,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; }
|
||||
static inline int irq_remapping_enable(void) { return -ENODEV; }
|
||||
|
@ -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
|
||||
}
|
@ -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;
|
||||
|
@ -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
|
||||
|
||||
int x2apic_mode;
|
||||
#ifdef CONFIG_X86_X2APIC
|
||||
/* 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 */
|
||||
@ -1475,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();
|
||||
|
||||
@ -1492,116 +1462,184 @@ 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
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
int x2apic_mode;
|
||||
|
||||
static __init void disable_x2apic(void)
|
||||
enum {
|
||||
X2APIC_OFF,
|
||||
X2APIC_ON,
|
||||
X2APIC_DISABLED,
|
||||
};
|
||||
static int x2apic_state;
|
||||
|
||||
static inline void __x2apic_disable(void)
|
||||
{
|
||||
u64 msr;
|
||||
|
||||
if (!cpu_has_x2apic)
|
||||
if (cpu_has_apic)
|
||||
return;
|
||||
|
||||
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);
|
||||
|
||||
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_disabled = 1;
|
||||
x2apic_mode = 0;
|
||||
|
||||
register_lapic_address(mp_lapic_addr);
|
||||
}
|
||||
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");
|
||||
}
|
||||
|
||||
void check_x2apic(void)
|
||||
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()) {
|
||||
pr_info("x2apic enabled by BIOS, switching to x2apic ops\n");
|
||||
x2apic_preenabled = x2apic_mode = 1;
|
||||
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.\n");
|
||||
__x2apic_disable();
|
||||
}
|
||||
setup_clear_cpu_cap(X86_FEATURE_X2APIC);
|
||||
x2apic_state = X2APIC_DISABLED;
|
||||
x2apic_mode = 0;
|
||||
return 0;
|
||||
}
|
||||
early_param("nox2apic", setup_nox2apic);
|
||||
|
||||
void enable_x2apic(void)
|
||||
/* Called from cpu_init() to enable x2apic on (secondary) cpus */
|
||||
void x2apic_setup(void)
|
||||
{
|
||||
u64 msr;
|
||||
|
||||
rdmsrl(MSR_IA32_APICBASE, msr);
|
||||
if (x2apic_disabled) {
|
||||
__disable_x2apic(msr);
|
||||
/*
|
||||
* If x2apic is not in ON state, disable it if already enabled
|
||||
* from BIOS.
|
||||
*/
|
||||
if (x2apic_state != X2APIC_ON) {
|
||||
__x2apic_disable();
|
||||
return;
|
||||
}
|
||||
__x2apic_enable();
|
||||
}
|
||||
|
||||
if (!x2apic_mode)
|
||||
static __init void x2apic_disable(void)
|
||||
{
|
||||
u32 x2apic_id;
|
||||
|
||||
if (x2apic_state != X2APIC_ON)
|
||||
goto out;
|
||||
|
||||
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)
|
||||
{
|
||||
if (x2apic_state != X2APIC_OFF)
|
||||
return;
|
||||
|
||||
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_state == X2APIC_DISABLED)
|
||||
return;
|
||||
|
||||
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("x2apic: IRQ remapping doesn't support X2APIC mode\n");
|
||||
x2apic_disable();
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* without IR all CPUs can be addressed by IOAPIC/MSI
|
||||
* only in physical mode
|
||||
*/
|
||||
x2apic_phys = 1;
|
||||
}
|
||||
x2apic_enable();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_X86_X2APIC */
|
||||
|
||||
int __init enable_IR(void)
|
||||
#else /* CONFIG_X86_X2APIC */
|
||||
static int __init validate_x2apic(void)
|
||||
{
|
||||
#ifdef CONFIG_IRQ_REMAP
|
||||
if (!irq_remapping_supported()) {
|
||||
pr_debug("intr-remapping not supported\n");
|
||||
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 remap_mode) { }
|
||||
static inline void __x2apic_enable(void) { }
|
||||
#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;
|
||||
}
|
||||
|
||||
if (!x2apic_preenabled && skip_ioapic_setup) {
|
||||
pr_info("Skipped enabling intr-remap because of skipping "
|
||||
"io-apic setup\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return irq_remapping_enable();
|
||||
#endif
|
||||
return -1;
|
||||
return irq_remapping_enable();
|
||||
}
|
||||
|
||||
void __init enable_IR_x2apic(void)
|
||||
{
|
||||
unsigned long flags;
|
||||
int ret, x2apic_enabled = 0;
|
||||
int hardware_init_ret;
|
||||
int ret, ir_stat;
|
||||
|
||||
/* Make sure irq_remap_ops are initialized */
|
||||
setup_irq_remapping_ops();
|
||||
|
||||
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();
|
||||
@ -1614,49 +1652,13 @@ void __init enable_IR_x2apic(void)
|
||||
legacy_pic->mask_all();
|
||||
mask_ioapic_entries();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
x2apic_enabled = 1;
|
||||
|
||||
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);
|
||||
@ -1847,82 +1849,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();
|
||||
|
||||
#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
|
||||
|
||||
bsp_end_local_APIC_setup();
|
||||
|
||||
#ifdef CONFIG_X86_IO_APIC
|
||||
if (smp_found_config && !skip_ioapic_setup && nr_ioapics)
|
||||
setup_IO_APIC();
|
||||
else {
|
||||
nr_ioapics = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
x86_init.timers.setup_percpu_clockev();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Local APIC interrupts
|
||||
*/
|
||||
@ -2027,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) {
|
||||
@ -2274,6 +2202,100 @@ void __init apic_set_eoi_write(void (*eoi_write)(u32 reg, u32 v))
|
||||
}
|
||||
}
|
||||
|
||||
static void __init apic_bsp_up_setup(void)
|
||||
{
|
||||
#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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(bool upmode)
|
||||
{
|
||||
int id;
|
||||
|
||||
connect_bsp_APIC();
|
||||
if (upmode)
|
||||
apic_bsp_up_setup();
|
||||
setup_local_APIC();
|
||||
|
||||
if (x2apic_mode)
|
||||
id = apic_read(APIC_LDR);
|
||||
else
|
||||
id = GET_APIC_LOGICAL_ID(apic_read(APIC_LDR));
|
||||
|
||||
enable_IO_APIC();
|
||||
end_local_APIC_setup();
|
||||
irq_remap_enable_fault_handling();
|
||||
setup_IO_APIC();
|
||||
/* Setup local timer */
|
||||
x86_init.timers.setup_percpu_clockev();
|
||||
return id;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
|
||||
if (!smp_found_config)
|
||||
disable_ioapic_support();
|
||||
|
||||
default_setup_apic_routing();
|
||||
verify_local_APIC();
|
||||
apic_bsp_setup(true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_UP_LATE_INIT
|
||||
void __init up_late_init(void)
|
||||
{
|
||||
APIC_init_uniprocessor();
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Power management
|
||||
*/
|
||||
@ -2359,9 +2381,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
|
||||
*
|
||||
|
@ -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) {
|
||||
@ -2295,7 +2298,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");
|
||||
@ -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");
|
||||
|
@ -1332,7 +1332,7 @@ void cpu_init(void)
|
||||
barrier();
|
||||
|
||||
x86_configure_nx();
|
||||
enable_x2apic();
|
||||
x2apic_setup();
|
||||
|
||||
/*
|
||||
* set up and load the per-CPU TSS
|
||||
|
@ -73,7 +73,6 @@
|
||||
#include <asm/setup.h>
|
||||
#include <asm/uv/uv.h>
|
||||
#include <linux/mc146818rtc.h>
|
||||
#include <asm/smpboot_hooks.h>
|
||||
#include <asm/i8259.h>
|
||||
#include <asm/realmode.h>
|
||||
#include <asm/misc.h>
|
||||
@ -104,6 +103,43 @@ EXPORT_PER_CPU_SYMBOL(cpu_info);
|
||||
|
||||
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
|
||||
* during CPU online.
|
||||
@ -136,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.
|
||||
@ -955,9 +990,12 @@ 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));
|
||||
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);
|
||||
@ -967,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.
|
||||
*/
|
||||
@ -1014,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;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1041,9 +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");
|
||||
}
|
||||
smpboot_clear_io_apic();
|
||||
disable_ioapic_support();
|
||||
return -1;
|
||||
return SMP_NO_APIC;
|
||||
}
|
||||
|
||||
verify_local_APIC();
|
||||
@ -1053,15 +1093,10 @@ static int __init smp_sanity_check(unsigned max_cpus)
|
||||
*/
|
||||
if (!max_cpus) {
|
||||
pr_info("SMP mode deactivated\n");
|
||||
smpboot_clear_io_apic();
|
||||
|
||||
connect_bsp_APIC();
|
||||
setup_local_APIC();
|
||||
bsp_end_local_APIC_setup();
|
||||
return -1;
|
||||
return SMP_FORCE_UP;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return SMP_OK;
|
||||
}
|
||||
|
||||
static void __init smp_cpu_index_default(void)
|
||||
@ -1101,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(false);
|
||||
return;
|
||||
case SMP_OK:
|
||||
break;
|
||||
}
|
||||
|
||||
default_setup_apic_routing();
|
||||
@ -1115,33 +1161,10 @@ 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
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
cpu0_logical_apicid = apic_bsp_setup(false);
|
||||
|
||||
pr_info("CPU%d: ", 0);
|
||||
print_cpu_info(&cpu_data(0));
|
||||
x86_init.timers.setup_percpu_clockev();
|
||||
|
||||
if (is_uv_system())
|
||||
uv_system_init();
|
||||
@ -1177,9 +1200,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();
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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,12 +2120,14 @@ static int __init iommu_go_to_state(enum iommu_init_state state)
|
||||
#ifdef CONFIG_IRQ_REMAP
|
||||
int __init amd_iommu_prepare(void)
|
||||
{
|
||||
return iommu_go_to_state(IOMMU_ACPI_FINISHED);
|
||||
}
|
||||
int ret;
|
||||
|
||||
int __init amd_iommu_supported(void)
|
||||
{
|
||||
return amd_iommu_irq_remap ? 1 : 0;
|
||||
amd_iommu_irq_remap = true;
|
||||
|
||||
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)
|
||||
|
@ -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);
|
||||
|
@ -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];
|
||||
|
||||
@ -481,11 +482,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) {
|
||||
@ -566,13 +567,27 @@ static int __init dmar_x2apic_optout(void)
|
||||
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 intel_iommu *iommu;
|
||||
|
||||
if (disable_irq_remap)
|
||||
return 0;
|
||||
if (irq_remap_broken) {
|
||||
printk(KERN_WARNING
|
||||
"This system BIOS has enabled interrupt remapping\n"
|
||||
@ -581,38 +596,45 @@ static int __init intel_irq_remapping_supported(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 0;
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (!dmar_ir_support())
|
||||
return 0;
|
||||
if (dmar_table_init() < 0)
|
||||
return -ENODEV;
|
||||
|
||||
if (!dmar_ir_support())
|
||||
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)
|
||||
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)
|
||||
{
|
||||
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) {
|
||||
pr_info("Queued invalidation will be enabled to support x2apic and Intr-remapping.\n");
|
||||
|
||||
if (x2apic_supported()) {
|
||||
eim = !dmar_x2apic_optout();
|
||||
if (!eim)
|
||||
printk(KERN_WARNING
|
||||
@ -646,16 +668,15 @@ 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;
|
||||
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.
|
||||
@ -675,12 +696,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;
|
||||
|
||||
if (intel_setup_irq_remapping(iommu))
|
||||
goto error;
|
||||
|
||||
iommu_set_irq_remapping(iommu, eim);
|
||||
setup = 1;
|
||||
}
|
||||
@ -702,15 +717,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;
|
||||
}
|
||||
|
||||
@ -1199,8 +1206,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,
|
||||
|
@ -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);
|
||||
@ -194,45 +193,32 @@ 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;
|
||||
}
|
||||
|
||||
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 (!remap_ops || !remap_ops->prepare)
|
||||
return -ENODEV;
|
||||
if (disable_irq_remap)
|
||||
return -ENOSYS;
|
||||
|
||||
return remap_ops->prepare();
|
||||
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;
|
||||
else
|
||||
return -ENOSYS;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __init irq_remapping_enable(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!remap_ops || !remap_ops->enable)
|
||||
if (!remap_ops->enable)
|
||||
return -ENODEV;
|
||||
|
||||
ret = remap_ops->enable();
|
||||
@ -245,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)
|
||||
@ -268,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();
|
||||
@ -279,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,
|
||||
@ -289,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);
|
||||
@ -300,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);
|
||||
}
|
||||
|
||||
@ -315,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);
|
||||
@ -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,
|
||||
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);
|
||||
@ -340,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);
|
||||
|
@ -31,16 +31,12 @@ 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;
|
||||
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);
|
||||
|
||||
@ -89,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 */
|
||||
|
@ -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 */
|
||||
|
||||
/*
|
||||
|
13
init/main.c
13
init/main.c
@ -87,10 +87,6 @@
|
||||
#include <asm/sections.h>
|
||||
#include <asm/cacheflush.h>
|
||||
|
||||
#ifdef CONFIG_X86_LOCAL_APIC
|
||||
#include <asm/smp.h>
|
||||
#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
|
||||
|
Loading…
Reference in New Issue
Block a user