aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBryan O'Donoghue <bryan.odonoghue@linux.intel.com>2012-04-18 12:37:39 -0400
committerLuis Henriques <luis.henriques@canonical.com>2012-05-25 12:24:33 -0400
commit3377ca31f07eff747b7bc0ca526c9225fff1473a (patch)
tree68851fda95c02be08f88c68e1aaecd0887ad3054
parenta61de180d861cc17a9ea1e90aeab290c42aca565 (diff)
x86, apic: APIC code touches invalid MSR on P5 class machines
BugLink: http://bugs.launchpad.net/bugs/996109 commit cbf2829b61c136edcba302a5e1b6b40e97d32c00 upstream. Current APIC code assumes MSR_IA32_APICBASE is present for all systems. Pentium Classic P5 and friends didn't have this MSR. MSR_IA32_APICBASE was introduced as an architectural MSR by Intel @ P6. Code paths that can touch this MSR invalidly are when vendor == Intel && cpu-family == 5 and APIC bit is set in CPUID - or when you simply pass lapic on the kernel command line, on a P5. The below patch stops Linux incorrectly interfering with the MSR_IA32_APICBASE for P5 class machines. Other code paths exist that touch the MSR - however those paths are not currently reachable for a conformant P5. Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linux.intel.com> Link: http://lkml.kernel.org/r/4F8EEDD3.1080404@linux.intel.com Signed-off-by: H. Peter Anvin <hpa@linux.intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--arch/x86/kernel/apic/apic.c34
1 files changed, 20 insertions, 14 deletions
diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c
index 9802bdf5298..4e8efd21671 100644
--- a/arch/x86/kernel/apic/apic.c
+++ b/arch/x86/kernel/apic/apic.c
@@ -1557,9 +1557,11 @@ static int __init apic_verify(void)
1557 mp_lapic_addr = APIC_DEFAULT_PHYS_BASE; 1557 mp_lapic_addr = APIC_DEFAULT_PHYS_BASE;
1558 1558
1559 /* The BIOS may have set up the APIC at some other address */ 1559 /* The BIOS may have set up the APIC at some other address */
1560 rdmsr(MSR_IA32_APICBASE, l, h); 1560 if (boot_cpu_data.x86 >= 6) {
1561 if (l & MSR_IA32_APICBASE_ENABLE) 1561 rdmsr(MSR_IA32_APICBASE, l, h);
1562 mp_lapic_addr = l & MSR_IA32_APICBASE_BASE; 1562 if (l & MSR_IA32_APICBASE_ENABLE)
1563 mp_lapic_addr = l & MSR_IA32_APICBASE_BASE;
1564 }
1563 1565
1564 pr_info("Found and enabled local APIC!\n"); 1566 pr_info("Found and enabled local APIC!\n");
1565 return 0; 1567 return 0;
@@ -1577,13 +1579,15 @@ int __init apic_force_enable(unsigned long addr)
1577 * MSR. This can only be done in software for Intel P6 or later 1579 * MSR. This can only be done in software for Intel P6 or later
1578 * and AMD K7 (Model > 1) or later. 1580 * and AMD K7 (Model > 1) or later.
1579 */ 1581 */
1580 rdmsr(MSR_IA32_APICBASE, l, h); 1582 if (boot_cpu_data.x86 >= 6) {
1581 if (!(l & MSR_IA32_APICBASE_ENABLE)) { 1583 rdmsr(MSR_IA32_APICBASE, l, h);
1582 pr_info("Local APIC disabled by BIOS -- reenabling.\n"); 1584 if (!(l & MSR_IA32_APICBASE_ENABLE)) {
1583 l &= ~MSR_IA32_APICBASE_BASE; 1585 pr_info("Local APIC disabled by BIOS -- reenabling.\n");
1584 l |= MSR_IA32_APICBASE_ENABLE | addr; 1586 l &= ~MSR_IA32_APICBASE_BASE;
1585 wrmsr(MSR_IA32_APICBASE, l, h); 1587 l |= MSR_IA32_APICBASE_ENABLE | addr;
1586 enabled_via_apicbase = 1; 1588 wrmsr(MSR_IA32_APICBASE, l, h);
1589 enabled_via_apicbase = 1;
1590 }
1587 } 1591 }
1588 return apic_verify(); 1592 return apic_verify();
1589} 1593}
@@ -2111,10 +2115,12 @@ static void lapic_resume(void)
2111 * FIXME! This will be wrong if we ever support suspend on 2115 * FIXME! This will be wrong if we ever support suspend on
2112 * SMP! We'll need to do this as part of the CPU restore! 2116 * SMP! We'll need to do this as part of the CPU restore!
2113 */ 2117 */
2114 rdmsr(MSR_IA32_APICBASE, l, h); 2118 if (boot_cpu_data.x86 >= 6) {
2115 l &= ~MSR_IA32_APICBASE_BASE; 2119 rdmsr(MSR_IA32_APICBASE, l, h);
2116 l |= MSR_IA32_APICBASE_ENABLE | mp_lapic_addr; 2120 l &= ~MSR_IA32_APICBASE_BASE;
2117 wrmsr(MSR_IA32_APICBASE, l, h); 2121 l |= MSR_IA32_APICBASE_ENABLE | mp_lapic_addr;
2122 wrmsr(MSR_IA32_APICBASE, l, h);
2123 }
2118 } 2124 }
2119 2125
2120 maxlvt = lapic_get_maxlvt(); 2126 maxlvt = lapic_get_maxlvt();