mirror of
https://github.com/torvalds/linux.git
synced 2024-11-01 09:41:44 +00:00
x86, x2apic: Fallback to xapic when BIOS doesn't setup interrupt-remapping
On some of the recent Intel SNB platforms, by default bios is pre-enabling x2apic mode in the cpu with out setting up interrupt-remapping. This case was resulting in the kernel to panic as the cpu is already in x2apic mode but the OS was not able to enable interrupt-remapping (which is a pre-req for using x2apic capability). On these platforms all the apic-ids are < 255 and the kernel can fallback to xapic mode if the bios has not enabled interrupt-remapping (which is mostly the case if the bios has not exported interrupt-remapping tables to the OS). Reported-by: Berck E. Nash <flyboy@gmail.com> Signed-off-by: Yinghai Lu <yinghai@kernel.org> Link: http://lkml.kernel.org/r/20111222014632.600418637@sbsiddha-desk.sc.intel.com Signed-off-by: Suresh Siddha <suresh.b.siddha@intel.com> Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
This commit is contained in:
parent
a35fd28256
commit
fb209bd891
@ -176,6 +176,7 @@ static inline u64 native_x2apic_icr_read(void)
|
||||
}
|
||||
|
||||
extern int x2apic_phys;
|
||||
extern int x2apic_preenabled;
|
||||
extern void check_x2apic(void);
|
||||
extern void enable_x2apic(void);
|
||||
extern void x2apic_icr_write(u32 low, u32 id);
|
||||
@ -198,6 +199,9 @@ static inline void x2apic_force_phys(void)
|
||||
x2apic_phys = 1;
|
||||
}
|
||||
#else
|
||||
static inline void disable_x2apic(void)
|
||||
{
|
||||
}
|
||||
static inline void check_x2apic(void)
|
||||
{
|
||||
}
|
||||
|
@ -144,6 +144,7 @@
|
||||
|
||||
#define APIC_BASE (fix_to_virt(FIX_APIC_BASE))
|
||||
#define APIC_BASE_MSR 0x800
|
||||
#define XAPIC_ENABLE (1UL << 11)
|
||||
#define X2APIC_ENABLE (1UL << 10)
|
||||
|
||||
#ifdef CONFIG_X86_32
|
||||
|
@ -146,7 +146,8 @@ __setup("apicpmtimer", setup_apicpmtimer);
|
||||
int x2apic_mode;
|
||||
#ifdef CONFIG_X86_X2APIC
|
||||
/* x2apic enabled before OS handover */
|
||||
static int x2apic_preenabled;
|
||||
int x2apic_preenabled;
|
||||
static int x2apic_disabled;
|
||||
static __init int setup_nox2apic(char *str)
|
||||
{
|
||||
if (x2apic_enabled()) {
|
||||
@ -1432,6 +1433,40 @@ void __init bsp_end_local_APIC_setup(void)
|
||||
}
|
||||
|
||||
#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);
|
||||
}
|
||||
|
||||
static void disable_x2apic(void)
|
||||
{
|
||||
u64 msr;
|
||||
|
||||
if (!cpu_has_x2apic)
|
||||
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);
|
||||
|
||||
x2apic_disabled = 1;
|
||||
x2apic_mode = 0;
|
||||
|
||||
register_lapic_address(mp_lapic_addr);
|
||||
}
|
||||
}
|
||||
|
||||
void check_x2apic(void)
|
||||
{
|
||||
if (x2apic_enabled()) {
|
||||
@ -1442,15 +1477,20 @@ void check_x2apic(void)
|
||||
|
||||
void enable_x2apic(void)
|
||||
{
|
||||
int msr, msr2;
|
||||
u64 msr;
|
||||
|
||||
rdmsrl(MSR_IA32_APICBASE, msr);
|
||||
if (x2apic_disabled) {
|
||||
__disable_x2apic(msr);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!x2apic_mode)
|
||||
return;
|
||||
|
||||
rdmsr(MSR_IA32_APICBASE, msr, msr2);
|
||||
if (!(msr & X2APIC_ENABLE)) {
|
||||
printk_once(KERN_INFO "Enabling x2apic\n");
|
||||
wrmsr(MSR_IA32_APICBASE, msr | X2APIC_ENABLE, msr2);
|
||||
wrmsrl(MSR_IA32_APICBASE, msr | X2APIC_ENABLE);
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_X86_X2APIC */
|
||||
@ -1487,7 +1527,7 @@ void __init enable_IR_x2apic(void)
|
||||
ret = save_ioapic_entries();
|
||||
if (ret) {
|
||||
pr_info("Saving IO-APIC state failed: %d\n", ret);
|
||||
goto out;
|
||||
return;
|
||||
}
|
||||
|
||||
local_irq_save(flags);
|
||||
@ -1499,13 +1539,19 @@ void __init enable_IR_x2apic(void)
|
||||
else
|
||||
ret = enable_IR();
|
||||
|
||||
if (!x2apic_supported())
|
||||
goto nox2apic;
|
||||
|
||||
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())
|
||||
!hypervisor_x2apic_available()) {
|
||||
if (x2apic_preenabled)
|
||||
disable_x2apic();
|
||||
goto nox2apic;
|
||||
}
|
||||
/*
|
||||
* without IR all CPUs can be addressed by IOAPIC/MSI
|
||||
* only in physical mode
|
||||
@ -1513,8 +1559,10 @@ void __init enable_IR_x2apic(void)
|
||||
x2apic_force_phys();
|
||||
}
|
||||
|
||||
if (ret == IRQ_REMAP_XAPIC_MODE)
|
||||
if (ret == IRQ_REMAP_XAPIC_MODE) {
|
||||
pr_info("x2apic not enabled, IRQ remapping is in xapic mode\n");
|
||||
goto nox2apic;
|
||||
}
|
||||
|
||||
x2apic_enabled = 1;
|
||||
|
||||
@ -1529,17 +1577,6 @@ nox2apic:
|
||||
restore_ioapic_entries();
|
||||
legacy_pic->restore_mask();
|
||||
local_irq_restore(flags);
|
||||
|
||||
out:
|
||||
if (x2apic_enabled || !x2apic_supported())
|
||||
return;
|
||||
|
||||
if (x2apic_preenabled)
|
||||
panic("x2apic: enabled by BIOS but kernel init failed.");
|
||||
else if (ret == IRQ_REMAP_XAPIC_MODE)
|
||||
pr_info("x2apic not enabled, IRQ remapping is in xapic mode\n");
|
||||
else if (ret < 0)
|
||||
pr_info("x2apic not enabled, IRQ remapping init failed\n");
|
||||
}
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
|
@ -2948,6 +2948,10 @@ static inline void __init check_timer(void)
|
||||
}
|
||||
local_irq_disable();
|
||||
apic_printk(APIC_QUIET, KERN_INFO "..... failed :(.\n");
|
||||
if (x2apic_preenabled)
|
||||
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");
|
||||
panic("IO-APIC + timer doesn't work! Boot with apic=debug and send a "
|
||||
"report. Then try booting with the 'noapic' option.\n");
|
||||
out:
|
||||
|
Loading…
Reference in New Issue
Block a user