aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBernhard Kaindl <bk@suse.de>2007-05-02 13:27:17 -0400
committerAndi Kleen <andi@basil.nowhere.org>2007-05-02 13:27:17 -0400
commit2b1f6278d77c1f2f669346fc2bb48012b5e9495a (patch)
tree52a30a649b4786869a51bceefb2c7ca696e0fe32
parent2b3b4835c94226681c496de9446d456dcf42ed08 (diff)
[PATCH] x86: Save the MTRRs of the BSP before booting an AP
Applied fix by Andew Morton: http://lkml.org/lkml/2007/4/8/88 - Fix `make headers_check'. AMD and Intel x86 CPU manuals state that it is the responsibility of system software to initialize and maintain MTRR consistency across all processors in Multi-Processing Environments. Quote from page 188 of the AMD64 System Programming manual (Volume 2): 7.6.5 MTRRs in Multi-Processing Environments "In multi-processing environments, the MTRRs located in all processors must characterize memory in the same way. Generally, this means that identical values are written to the MTRRs used by the processors." (short omission here) "Failure to do so may result in coherency violations or loss of atomicity. Processor implementations do not check the MTRR settings in other processors to ensure consistency. It is the responsibility of system software to initialize and maintain MTRR consistency across all processors." Current Linux MTRR code already implements the above in the case that the BIOS does not properly initialize MTRRs on the secondary processors, but the case where the fixed-range MTRRs of the boot processor are changed after Linux started to boot, before the initialsation of a secondary processor, is not handled yet. In this case, secondary processors are currently initialized by Linux with MTRRs which the boot processor had very early, when mtrr_bp_init() did run, but not with the MTRRs which the boot processor uses at the time when that secondary processors is actually booted, causing differing MTRR contents on the secondary processors. Such situation happens on Acer Ferrari 1000 and 5000 notebooks where the BIOS enables and sets AMD-specific IORR bits in the fixed-range MTRRs of the boot processor when it transitions the system into ACPI mode. The SMI handler of the BIOS does this in SMM, entered while Linux ACPI code runs acpi_enable(). Other occasions where the SMI handler of the BIOS may change bits in the MTRRs could occur as well. To initialize newly booted secodary processors with the fixed-range MTRRs which the boot processor uses at that time, this patch saves the fixed-range MTRRs of the boot processor before new secondary processors are started. When the secondary processors run their Linux initialisation code, their fixed-range MTRRs will be updated with the saved fixed-range MTRRs. If CONFIG_MTRR is not set, we define mtrr_save_state as an empty statement because there is nothing to do. Possible TODOs: *) CPU-hotplugging outside of SMP suspend/resume is not yet tested with this patch. *) If, even in this case, an AP never runs i386/do_boot_cpu or x86_64/cpu_up, then the calls to mtrr_save_state() could be replaced by calls to mtrr_save_fixed_ranges(NULL) and mtrr_save_state() would not be needed. That would need either verification of the CPU-hotplug code or at least a test on a >2 CPU machine. *) The MTRRs of other running processors are not yet checked at this time but it might be interesting to syncronize the MTTRs of all processors before booting. That would be an incremental patch, but of rather low priority since there is no machine known so far which would require this. AK: moved prototypes on x86-64 around to fix warnings Signed-off-by: Bernhard Kaindl <bk@suse.de> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Andi Kleen <ak@suse.de> Cc: Andi Kleen <ak@suse.de> Cc: Dave Jones <davej@codemonkey.org.uk>
-rw-r--r--arch/i386/kernel/cpu/mtrr/main.c11
-rw-r--r--arch/i386/kernel/smpboot.c7
-rw-r--r--arch/x86_64/kernel/smpboot.c6
-rw-r--r--include/asm-i386/mtrr.h2
-rw-r--r--include/asm-x86_64/mtrr.h2
5 files changed, 28 insertions, 0 deletions
diff --git a/arch/i386/kernel/cpu/mtrr/main.c b/arch/i386/kernel/cpu/mtrr/main.c
index 0acfb6a5a220..02a2f39e5e0a 100644
--- a/arch/i386/kernel/cpu/mtrr/main.c
+++ b/arch/i386/kernel/cpu/mtrr/main.c
@@ -729,6 +729,17 @@ void mtrr_ap_init(void)
729 local_irq_restore(flags); 729 local_irq_restore(flags);
730} 730}
731 731
732/**
733 * Save current fixed-range MTRR state of the BSP
734 */
735void mtrr_save_state(void)
736{
737 if (smp_processor_id() == 0)
738 mtrr_save_fixed_ranges(NULL);
739 else
740 smp_call_function_single(0, mtrr_save_fixed_ranges, NULL, 1, 1);
741}
742
732static int __init mtrr_init_finialize(void) 743static int __init mtrr_init_finialize(void)
733{ 744{
734 if (!mtrr_if) 745 if (!mtrr_if)
diff --git a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c
index 7c1dbef399cd..f14d93351a82 100644
--- a/arch/i386/kernel/smpboot.c
+++ b/arch/i386/kernel/smpboot.c
@@ -58,6 +58,7 @@
58#include <mach_wakecpu.h> 58#include <mach_wakecpu.h>
59#include <smpboot_hooks.h> 59#include <smpboot_hooks.h>
60#include <asm/vmi.h> 60#include <asm/vmi.h>
61#include <asm/mtrr.h>
61 62
62/* Set if we find a B stepping CPU */ 63/* Set if we find a B stepping CPU */
63static int __devinitdata smp_b_stepping; 64static int __devinitdata smp_b_stepping;
@@ -815,6 +816,12 @@ static int __cpuinit do_boot_cpu(int apicid, int cpu)
815 unsigned short nmi_high = 0, nmi_low = 0; 816 unsigned short nmi_high = 0, nmi_low = 0;
816 817
817 /* 818 /*
819 * Save current MTRR state in case it was changed since early boot
820 * (e.g. by the ACPI SMI) to initialize new CPUs with MTRRs in sync:
821 */
822 mtrr_save_state();
823
824 /*
818 * We can't use kernel_thread since we must avoid to 825 * We can't use kernel_thread since we must avoid to
819 * reschedule the child. 826 * reschedule the child.
820 */ 827 */
diff --git a/arch/x86_64/kernel/smpboot.c b/arch/x86_64/kernel/smpboot.c
index 14724be48bec..ddc392bee243 100644
--- a/arch/x86_64/kernel/smpboot.c
+++ b/arch/x86_64/kernel/smpboot.c
@@ -944,6 +944,12 @@ int __cpuinit __cpu_up(unsigned int cpu)
944 return -ENOSYS; 944 return -ENOSYS;
945 } 945 }
946 946
947 /*
948 * Save current MTRR state in case it was changed since early boot
949 * (e.g. by the ACPI SMI) to initialize new CPUs with MTRRs in sync:
950 */
951 mtrr_save_state();
952
947 per_cpu(cpu_state, cpu) = CPU_UP_PREPARE; 953 per_cpu(cpu_state, cpu) = CPU_UP_PREPARE;
948 /* Boot it! */ 954 /* Boot it! */
949 err = do_boot_cpu(cpu, apicid); 955 err = do_boot_cpu(cpu, apicid);
diff --git a/include/asm-i386/mtrr.h b/include/asm-i386/mtrr.h
index 02a41b99bd7e..7e9c7ccbdcfe 100644
--- a/include/asm-i386/mtrr.h
+++ b/include/asm-i386/mtrr.h
@@ -70,6 +70,7 @@ struct mtrr_gentry
70/* The following functions are for use by other drivers */ 70/* The following functions are for use by other drivers */
71# ifdef CONFIG_MTRR 71# ifdef CONFIG_MTRR
72extern void mtrr_save_fixed_ranges(void *); 72extern void mtrr_save_fixed_ranges(void *);
73extern void mtrr_save_state(void);
73extern int mtrr_add (unsigned long base, unsigned long size, 74extern int mtrr_add (unsigned long base, unsigned long size,
74 unsigned int type, char increment); 75 unsigned int type, char increment);
75extern int mtrr_add_page (unsigned long base, unsigned long size, 76extern int mtrr_add_page (unsigned long base, unsigned long size,
@@ -81,6 +82,7 @@ extern void mtrr_ap_init(void);
81extern void mtrr_bp_init(void); 82extern void mtrr_bp_init(void);
82# else 83# else
83#define mtrr_save_fixed_ranges(arg) do {} while (0) 84#define mtrr_save_fixed_ranges(arg) do {} while (0)
85#define mtrr_save_state() do {} while (0)
84static __inline__ int mtrr_add (unsigned long base, unsigned long size, 86static __inline__ int mtrr_add (unsigned long base, unsigned long size,
85 unsigned int type, char increment) 87 unsigned int type, char increment)
86{ 88{
diff --git a/include/asm-x86_64/mtrr.h b/include/asm-x86_64/mtrr.h
index 1b326cbb9305..b557c486bef8 100644
--- a/include/asm-x86_64/mtrr.h
+++ b/include/asm-x86_64/mtrr.h
@@ -139,10 +139,12 @@ struct mtrr_gentry32
139extern void mtrr_ap_init(void); 139extern void mtrr_ap_init(void);
140extern void mtrr_bp_init(void); 140extern void mtrr_bp_init(void);
141extern void mtrr_save_fixed_ranges(void *); 141extern void mtrr_save_fixed_ranges(void *);
142extern void mtrr_save_state(void);
142#else 143#else
143#define mtrr_ap_init() do {} while (0) 144#define mtrr_ap_init() do {} while (0)
144#define mtrr_bp_init() do {} while (0) 145#define mtrr_bp_init() do {} while (0)
145#define mtrr_save_fixed_ranges(arg) do {} while (0) 146#define mtrr_save_fixed_ranges(arg) do {} while (0)
147#define mtrr_save_state() do {} while (0)
146#endif 148#endif
147 149
148#endif /* __KERNEL__ */ 150#endif /* __KERNEL__ */