| From fd19dce7ac07973f700b0f13fb7f94b951414a4c Mon Sep 17 00:00:00 2001 |
| From: Yinghai Lu <yinghai@kernel.org> |
| Date: Thu, 15 Jul 2010 00:00:59 -0700 |
| Subject: x86: Fix x2apic preenabled system with kexec |
| |
| From: Yinghai Lu <yinghai@kernel.org> |
| |
| commit fd19dce7ac07973f700b0f13fb7f94b951414a4c upstream. |
| |
| Found one x2apic system kexec loop test failed |
| when CONFIG_NMI_WATCHDOG=y (old) or CONFIG_LOCKUP_DETECTOR=y (current tip) |
| |
| first kernel can kexec second kernel, but second kernel can not kexec third one. |
| |
| it can be duplicated on another system with BIOS preenabled x2apic. |
| First kernel can not kexec second kernel. |
| |
| It turns out, when kernel boot with pre-enabled x2apic, it will not execute |
| disable_local_APIC on shutdown path. |
| |
| when init_apic_mappings() is called in setup_arch, it will skip setting of |
| apic_phys when x2apic_mode is set. ( x2apic_mode is much early check_x2apic()) |
| Then later, disable_local_APIC() will bail out early because !apic_phys. |
| |
| So check !x2apic_mode in x2apic_mode in disable_local_APIC with !apic_phys. |
| |
| another solution could be updating init_apic_mappings() to set apic_phys even |
| for preenabled x2apic system. Actually even for x2apic system, that lapic |
| address is mapped already in early stage. |
| |
| BTW: is there any x2apic preenabled system with apicid of boot cpu > 255? |
| |
| Signed-off-by: Yinghai Lu <yinghai@kernel.org> |
| LKML-Reference: <4C3EB22B.3000701@kernel.org> |
| Acked-by: Suresh Siddha <suresh.b.siddha@intel.com> |
| Signed-off-by: H. Peter Anvin <hpa@linux.intel.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> |
| |
| --- |
| arch/x86/kernel/apic/apic.c | 2 +- |
| 1 file changed, 1 insertion(+), 1 deletion(-) |
| |
| --- a/arch/x86/kernel/apic/apic.c |
| +++ b/arch/x86/kernel/apic/apic.c |
| @@ -920,7 +920,7 @@ void disable_local_APIC(void) |
| unsigned int value; |
| |
| /* APIC hasn't been mapped yet */ |
| - if (!apic_phys) |
| + if (!x2apic_mode && !apic_phys) |
| return; |
| |
| clear_local_APIC(); |