diff options
author | Toshi Kani <toshi.kani@hpe.com> | 2016-03-23 17:41:57 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2016-03-29 06:23:25 -0400 |
commit | 02f037d641dc6672be5cfe7875a48ab99b95b154 (patch) | |
tree | 606902997743c91bbb0886d3306ba7cc79f39d05 | |
parent | 1993b176a8224e371e0732ffada7ab9eb3b0912b (diff) |
x86/mm/pat: Add support of non-default PAT MSR setting
In preparation for fixing a regression caused by:
9cd25aac1f44 ("x86/mm/pat: Emulate PAT when it is disabled")'
... PAT needs to support a case that PAT MSR is initialized with a
non-default value.
When pat_init() is called and PAT is disabled, it initializes the
PAT table with the BIOS default value. Xen, however, sets PAT MSR
with a non-default value to enable WC. This causes inconsistency
between the PAT table and PAT MSR when PAT is set to disable on Xen.
Change pat_init() to handle the PAT disable cases properly. Add
init_cache_modes() to handle two cases when PAT is set to disable.
1. CPU supports PAT: Set PAT table to be consistent with PAT MSR.
2. CPU does not support PAT: Set PAT table to be consistent with
PWT and PCD bits in a PTE.
Note, __init_cache_modes(), renamed from pat_init_cache_modes(),
will be changed to a static function in a later patch.
Signed-off-by: Toshi Kani <toshi.kani@hpe.com>
Reviewed-by: Thomas Gleixner <tglx@linutronix.de>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Borislav Petkov <bp@suse.de>
Cc: Brian Gerst <brgerst@gmail.com>
Cc: Denys Vlasenko <dvlasenk@redhat.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Juergen Gross <jgross@suse.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Luis R. Rodriguez <mcgrof@suse.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Toshi Kani <toshi.kani@hp.com>
Cc: elliott@hpe.com
Cc: konrad.wilk@oracle.com
Cc: paul.gortmaker@windriver.com
Cc: xen-devel@lists.xenproject.org
Link: http://lkml.kernel.org/r/1458769323-24491-2-git-send-email-toshi.kani@hpe.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r-- | arch/x86/include/asm/pat.h | 2 | ||||
-rw-r--r-- | arch/x86/mm/pat.c | 73 | ||||
-rw-r--r-- | arch/x86/xen/enlighten.c | 2 |
3 files changed, 55 insertions, 22 deletions
diff --git a/arch/x86/include/asm/pat.h b/arch/x86/include/asm/pat.h index ca6c228d5e62..97ea55bc2b54 100644 --- a/arch/x86/include/asm/pat.h +++ b/arch/x86/include/asm/pat.h | |||
@@ -6,7 +6,7 @@ | |||
6 | 6 | ||
7 | bool pat_enabled(void); | 7 | bool pat_enabled(void); |
8 | extern void pat_init(void); | 8 | extern void pat_init(void); |
9 | void pat_init_cache_modes(u64); | 9 | void __init_cache_modes(u64); |
10 | 10 | ||
11 | extern int reserve_memtype(u64 start, u64 end, | 11 | extern int reserve_memtype(u64 start, u64 end, |
12 | enum page_cache_mode req_pcm, enum page_cache_mode *ret_pcm); | 12 | enum page_cache_mode req_pcm, enum page_cache_mode *ret_pcm); |
diff --git a/arch/x86/mm/pat.c b/arch/x86/mm/pat.c index faec01e7a17d..b4663885308f 100644 --- a/arch/x86/mm/pat.c +++ b/arch/x86/mm/pat.c | |||
@@ -181,7 +181,7 @@ static enum page_cache_mode pat_get_cache_mode(unsigned pat_val, char *msg) | |||
181 | * configuration. | 181 | * configuration. |
182 | * Using lower indices is preferred, so we start with highest index. | 182 | * Using lower indices is preferred, so we start with highest index. |
183 | */ | 183 | */ |
184 | void pat_init_cache_modes(u64 pat) | 184 | void __init_cache_modes(u64 pat) |
185 | { | 185 | { |
186 | enum page_cache_mode cache; | 186 | enum page_cache_mode cache; |
187 | char pat_msg[33]; | 187 | char pat_msg[33]; |
@@ -207,9 +207,6 @@ static void pat_bsp_init(u64 pat) | |||
207 | return; | 207 | return; |
208 | } | 208 | } |
209 | 209 | ||
210 | if (!pat_enabled()) | ||
211 | goto done; | ||
212 | |||
213 | rdmsrl(MSR_IA32_CR_PAT, tmp_pat); | 210 | rdmsrl(MSR_IA32_CR_PAT, tmp_pat); |
214 | if (!tmp_pat) { | 211 | if (!tmp_pat) { |
215 | pat_disable("PAT MSR is 0, disabled."); | 212 | pat_disable("PAT MSR is 0, disabled."); |
@@ -218,15 +215,11 @@ static void pat_bsp_init(u64 pat) | |||
218 | 215 | ||
219 | wrmsrl(MSR_IA32_CR_PAT, pat); | 216 | wrmsrl(MSR_IA32_CR_PAT, pat); |
220 | 217 | ||
221 | done: | 218 | __init_cache_modes(pat); |
222 | pat_init_cache_modes(pat); | ||
223 | } | 219 | } |
224 | 220 | ||
225 | static void pat_ap_init(u64 pat) | 221 | static void pat_ap_init(u64 pat) |
226 | { | 222 | { |
227 | if (!pat_enabled()) | ||
228 | return; | ||
229 | |||
230 | if (!cpu_has_pat) { | 223 | if (!cpu_has_pat) { |
231 | /* | 224 | /* |
232 | * If this happens we are on a secondary CPU, but switched to | 225 | * If this happens we are on a secondary CPU, but switched to |
@@ -238,18 +231,32 @@ static void pat_ap_init(u64 pat) | |||
238 | wrmsrl(MSR_IA32_CR_PAT, pat); | 231 | wrmsrl(MSR_IA32_CR_PAT, pat); |
239 | } | 232 | } |
240 | 233 | ||
241 | void pat_init(void) | 234 | static void init_cache_modes(void) |
242 | { | 235 | { |
243 | u64 pat; | 236 | u64 pat = 0; |
244 | struct cpuinfo_x86 *c = &boot_cpu_data; | 237 | static int init_cm_done; |
245 | 238 | ||
246 | if (!pat_enabled()) { | 239 | if (init_cm_done) |
240 | return; | ||
241 | |||
242 | if (boot_cpu_has(X86_FEATURE_PAT)) { | ||
243 | /* | ||
244 | * CPU supports PAT. Set PAT table to be consistent with | ||
245 | * PAT MSR. This case supports "nopat" boot option, and | ||
246 | * virtual machine environments which support PAT without | ||
247 | * MTRRs. In specific, Xen has unique setup to PAT MSR. | ||
248 | * | ||
249 | * If PAT MSR returns 0, it is considered invalid and emulates | ||
250 | * as No PAT. | ||
251 | */ | ||
252 | rdmsrl(MSR_IA32_CR_PAT, pat); | ||
253 | } | ||
254 | |||
255 | if (!pat) { | ||
247 | /* | 256 | /* |
248 | * No PAT. Emulate the PAT table that corresponds to the two | 257 | * No PAT. Emulate the PAT table that corresponds to the two |
249 | * cache bits, PWT (Write Through) and PCD (Cache Disable). This | 258 | * cache bits, PWT (Write Through) and PCD (Cache Disable). |
250 | * setup is the same as the BIOS default setup when the system | 259 | * This setup is also the same as the BIOS default setup. |
251 | * has PAT but the "nopat" boot option has been specified. This | ||
252 | * emulated PAT table is used when MSR_IA32_CR_PAT returns 0. | ||
253 | * | 260 | * |
254 | * PTE encoding: | 261 | * PTE encoding: |
255 | * | 262 | * |
@@ -266,10 +273,36 @@ void pat_init(void) | |||
266 | */ | 273 | */ |
267 | pat = PAT(0, WB) | PAT(1, WT) | PAT(2, UC_MINUS) | PAT(3, UC) | | 274 | pat = PAT(0, WB) | PAT(1, WT) | PAT(2, UC_MINUS) | PAT(3, UC) | |
268 | PAT(4, WB) | PAT(5, WT) | PAT(6, UC_MINUS) | PAT(7, UC); | 275 | PAT(4, WB) | PAT(5, WT) | PAT(6, UC_MINUS) | PAT(7, UC); |
276 | } | ||
277 | |||
278 | __init_cache_modes(pat); | ||
279 | |||
280 | init_cm_done = 1; | ||
281 | } | ||
282 | |||
283 | /** | ||
284 | * pat_init - Initialize PAT MSR and PAT table | ||
285 | * | ||
286 | * This function initializes PAT MSR and PAT table with an OS-defined value | ||
287 | * to enable additional cache attributes, WC and WT. | ||
288 | * | ||
289 | * This function must be called on all CPUs using the specific sequence of | ||
290 | * operations defined in Intel SDM. mtrr_rendezvous_handler() provides this | ||
291 | * procedure for PAT. | ||
292 | */ | ||
293 | void pat_init(void) | ||
294 | { | ||
295 | u64 pat; | ||
296 | struct cpuinfo_x86 *c = &boot_cpu_data; | ||
297 | |||
298 | if (!pat_enabled()) { | ||
299 | init_cache_modes(); | ||
300 | return; | ||
301 | } | ||
269 | 302 | ||
270 | } else if ((c->x86_vendor == X86_VENDOR_INTEL) && | 303 | if ((c->x86_vendor == X86_VENDOR_INTEL) && |
271 | (((c->x86 == 0x6) && (c->x86_model <= 0xd)) || | 304 | (((c->x86 == 0x6) && (c->x86_model <= 0xd)) || |
272 | ((c->x86 == 0xf) && (c->x86_model <= 0x6)))) { | 305 | ((c->x86 == 0xf) && (c->x86_model <= 0x6)))) { |
273 | /* | 306 | /* |
274 | * PAT support with the lower four entries. Intel Pentium 2, | 307 | * PAT support with the lower four entries. Intel Pentium 2, |
275 | * 3, M, and 4 are affected by PAT errata, which makes the | 308 | * 3, M, and 4 are affected by PAT errata, which makes the |
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index 880862c7d9dd..c469a7c7c309 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c | |||
@@ -1623,7 +1623,7 @@ asmlinkage __visible void __init xen_start_kernel(void) | |||
1623 | * configuration. | 1623 | * configuration. |
1624 | */ | 1624 | */ |
1625 | rdmsrl(MSR_IA32_CR_PAT, pat); | 1625 | rdmsrl(MSR_IA32_CR_PAT, pat); |
1626 | pat_init_cache_modes(pat); | 1626 | __init_cache_modes(pat); |
1627 | 1627 | ||
1628 | /* keep using Xen gdt for now; no urgent need to change it */ | 1628 | /* keep using Xen gdt for now; no urgent need to change it */ |
1629 | 1629 | ||