mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-06-27 09:02:06 +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
4 changed files with 64 additions and 18 deletions
|
@ -176,6 +176,7 @@ static inline u64 native_x2apic_icr_read(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
extern int x2apic_phys;
|
extern int x2apic_phys;
|
||||||
|
extern int x2apic_preenabled;
|
||||||
extern void check_x2apic(void);
|
extern void check_x2apic(void);
|
||||||
extern void enable_x2apic(void);
|
extern void enable_x2apic(void);
|
||||||
extern void x2apic_icr_write(u32 low, u32 id);
|
extern void x2apic_icr_write(u32 low, u32 id);
|
||||||
|
@ -198,6 +199,9 @@ static inline void x2apic_force_phys(void)
|
||||||
x2apic_phys = 1;
|
x2apic_phys = 1;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
static inline void disable_x2apic(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
static inline void check_x2apic(void)
|
static inline void check_x2apic(void)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
@ -144,6 +144,7 @@
|
||||||
|
|
||||||
#define APIC_BASE (fix_to_virt(FIX_APIC_BASE))
|
#define APIC_BASE (fix_to_virt(FIX_APIC_BASE))
|
||||||
#define APIC_BASE_MSR 0x800
|
#define APIC_BASE_MSR 0x800
|
||||||
|
#define XAPIC_ENABLE (1UL << 11)
|
||||||
#define X2APIC_ENABLE (1UL << 10)
|
#define X2APIC_ENABLE (1UL << 10)
|
||||||
|
|
||||||
#ifdef CONFIG_X86_32
|
#ifdef CONFIG_X86_32
|
||||||
|
|
|
@ -146,7 +146,8 @@ __setup("apicpmtimer", setup_apicpmtimer);
|
||||||
int x2apic_mode;
|
int x2apic_mode;
|
||||||
#ifdef CONFIG_X86_X2APIC
|
#ifdef CONFIG_X86_X2APIC
|
||||||
/* x2apic enabled before OS handover */
|
/* x2apic enabled before OS handover */
|
||||||
static int x2apic_preenabled;
|
int x2apic_preenabled;
|
||||||
|
static int x2apic_disabled;
|
||||||
static __init int setup_nox2apic(char *str)
|
static __init int setup_nox2apic(char *str)
|
||||||
{
|
{
|
||||||
if (x2apic_enabled()) {
|
if (x2apic_enabled()) {
|
||||||
|
@ -1432,6 +1433,40 @@ void __init bsp_end_local_APIC_setup(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_X86_X2APIC
|
#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)
|
void check_x2apic(void)
|
||||||
{
|
{
|
||||||
if (x2apic_enabled()) {
|
if (x2apic_enabled()) {
|
||||||
|
@ -1442,15 +1477,20 @@ void check_x2apic(void)
|
||||||
|
|
||||||
void enable_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)
|
if (!x2apic_mode)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
rdmsr(MSR_IA32_APICBASE, msr, msr2);
|
|
||||||
if (!(msr & X2APIC_ENABLE)) {
|
if (!(msr & X2APIC_ENABLE)) {
|
||||||
printk_once(KERN_INFO "Enabling x2apic\n");
|
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 */
|
#endif /* CONFIG_X86_X2APIC */
|
||||||
|
@ -1487,7 +1527,7 @@ void __init enable_IR_x2apic(void)
|
||||||
ret = save_ioapic_entries();
|
ret = save_ioapic_entries();
|
||||||
if (ret) {
|
if (ret) {
|
||||||
pr_info("Saving IO-APIC state failed: %d\n", ret);
|
pr_info("Saving IO-APIC state failed: %d\n", ret);
|
||||||
goto out;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
local_irq_save(flags);
|
local_irq_save(flags);
|
||||||
|
@ -1499,13 +1539,19 @@ void __init enable_IR_x2apic(void)
|
||||||
else
|
else
|
||||||
ret = enable_IR();
|
ret = enable_IR();
|
||||||
|
|
||||||
|
if (!x2apic_supported())
|
||||||
|
goto nox2apic;
|
||||||
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
/* IR is required if there is APIC ID > 255 even when running
|
/* IR is required if there is APIC ID > 255 even when running
|
||||||
* under KVM
|
* under KVM
|
||||||
*/
|
*/
|
||||||
if (max_physical_apicid > 255 ||
|
if (max_physical_apicid > 255 ||
|
||||||
!hypervisor_x2apic_available())
|
!hypervisor_x2apic_available()) {
|
||||||
|
if (x2apic_preenabled)
|
||||||
|
disable_x2apic();
|
||||||
goto nox2apic;
|
goto nox2apic;
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
* without IR all CPUs can be addressed by IOAPIC/MSI
|
* without IR all CPUs can be addressed by IOAPIC/MSI
|
||||||
* only in physical mode
|
* only in physical mode
|
||||||
|
@ -1513,8 +1559,10 @@ void __init enable_IR_x2apic(void)
|
||||||
x2apic_force_phys();
|
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;
|
goto nox2apic;
|
||||||
|
}
|
||||||
|
|
||||||
x2apic_enabled = 1;
|
x2apic_enabled = 1;
|
||||||
|
|
||||||
|
@ -1529,17 +1577,6 @@ nox2apic:
|
||||||
restore_ioapic_entries();
|
restore_ioapic_entries();
|
||||||
legacy_pic->restore_mask();
|
legacy_pic->restore_mask();
|
||||||
local_irq_restore(flags);
|
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
|
#ifdef CONFIG_X86_64
|
||||||
|
|
|
@ -2948,6 +2948,10 @@ 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)
|
||||||
|
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 "
|
panic("IO-APIC + timer doesn't work! Boot with apic=debug and send a "
|
||||||
"report. Then try booting with the 'noapic' option.\n");
|
"report. Then try booting with the 'noapic' option.\n");
|
||||||
out:
|
out:
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue