aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/include/asm/pat.h1
-rw-r--r--arch/x86/include/asm/pgtable_types.h4
-rw-r--r--arch/x86/mm/init.c8
-rw-r--r--arch/x86/mm/mm_internal.h2
-rw-r--r--arch/x86/mm/pat.c50
5 files changed, 63 insertions, 2 deletions
diff --git a/arch/x86/include/asm/pat.h b/arch/x86/include/asm/pat.h
index 150407a7234d..91bc4ba95f91 100644
--- a/arch/x86/include/asm/pat.h
+++ b/arch/x86/include/asm/pat.h
@@ -11,6 +11,7 @@ static const int pat_enabled;
11#endif 11#endif
12 12
13extern void pat_init(void); 13extern void pat_init(void);
14void pat_init_cache_modes(void);
14 15
15extern int reserve_memtype(u64 start, u64 end, 16extern int reserve_memtype(u64 start, u64 end,
16 enum page_cache_mode req_pcm, enum page_cache_mode *ret_pcm); 17 enum page_cache_mode req_pcm, enum page_cache_mode *ret_pcm);
diff --git a/arch/x86/include/asm/pgtable_types.h b/arch/x86/include/asm/pgtable_types.h
index 6d5f6d154215..af447f95e3be 100644
--- a/arch/x86/include/asm/pgtable_types.h
+++ b/arch/x86/include/asm/pgtable_types.h
@@ -351,6 +351,10 @@ extern uint8_t __pte2cachemode_tbl[8];
351 ((((cb) >> (_PAGE_BIT_PAT - 2)) & 4) | \ 351 ((((cb) >> (_PAGE_BIT_PAT - 2)) & 4) | \
352 (((cb) >> (_PAGE_BIT_PCD - 1)) & 2) | \ 352 (((cb) >> (_PAGE_BIT_PCD - 1)) & 2) | \
353 (((cb) >> _PAGE_BIT_PWT) & 1)) 353 (((cb) >> _PAGE_BIT_PWT) & 1))
354#define __cm_idx2pte(i) \
355 ((((i) & 4) << (_PAGE_BIT_PAT - 2)) | \
356 (((i) & 2) << (_PAGE_BIT_PCD - 1)) | \
357 (((i) & 1) << _PAGE_BIT_PWT))
354 358
355static inline unsigned long cachemode2protval(enum page_cache_mode pcm) 359static inline unsigned long cachemode2protval(enum page_cache_mode pcm)
356{ 360{
diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c
index a9776ba475d4..82b41d56bb98 100644
--- a/arch/x86/mm/init.c
+++ b/arch/x86/mm/init.c
@@ -716,3 +716,11 @@ void __init zone_sizes_init(void)
716 free_area_init_nodes(max_zone_pfns); 716 free_area_init_nodes(max_zone_pfns);
717} 717}
718 718
719void update_cache_mode_entry(unsigned entry, enum page_cache_mode cache)
720{
721 /* entry 0 MUST be WB (hardwired to speed up translations) */
722 BUG_ON(!entry && cache != _PAGE_CACHE_MODE_WB);
723
724 __cachemode2pte_tbl[cache] = __cm_idx2pte(entry);
725 __pte2cachemode_tbl[entry] = cache;
726}
diff --git a/arch/x86/mm/mm_internal.h b/arch/x86/mm/mm_internal.h
index 6b563a118891..62474ba66c8e 100644
--- a/arch/x86/mm/mm_internal.h
+++ b/arch/x86/mm/mm_internal.h
@@ -16,4 +16,6 @@ void zone_sizes_init(void);
16 16
17extern int after_bootmem; 17extern int after_bootmem;
18 18
19void update_cache_mode_entry(unsigned entry, enum page_cache_mode cache);
20
19#endif /* __X86_MM_INTERNAL_H */ 21#endif /* __X86_MM_INTERNAL_H */
diff --git a/arch/x86/mm/pat.c b/arch/x86/mm/pat.c
index ef75f3f89810..4c601276a556 100644
--- a/arch/x86/mm/pat.c
+++ b/arch/x86/mm/pat.c
@@ -31,6 +31,7 @@
31#include <asm/io.h> 31#include <asm/io.h>
32 32
33#include "pat_internal.h" 33#include "pat_internal.h"
34#include "mm_internal.h"
34 35
35#ifdef CONFIG_X86_PAT 36#ifdef CONFIG_X86_PAT
36int __read_mostly pat_enabled = 1; 37int __read_mostly pat_enabled = 1;
@@ -75,6 +76,52 @@ enum {
75 PAT_UC_MINUS = 7, /* UC, but can be overriden by MTRR */ 76 PAT_UC_MINUS = 7, /* UC, but can be overriden by MTRR */
76}; 77};
77 78
79#define CM(c) (_PAGE_CACHE_MODE_ ## c)
80
81static enum page_cache_mode pat_get_cache_mode(unsigned pat_val, char *msg)
82{
83 enum page_cache_mode cache;
84 char *cache_mode;
85
86 switch (pat_val) {
87 case PAT_UC: cache = CM(UC); cache_mode = "UC "; break;
88 case PAT_WC: cache = CM(WC); cache_mode = "WC "; break;
89 case PAT_WT: cache = CM(WT); cache_mode = "WT "; break;
90 case PAT_WP: cache = CM(WP); cache_mode = "WP "; break;
91 case PAT_WB: cache = CM(WB); cache_mode = "WB "; break;
92 case PAT_UC_MINUS: cache = CM(UC_MINUS); cache_mode = "UC- "; break;
93 default: cache = CM(WB); cache_mode = "WB "; break;
94 }
95
96 memcpy(msg, cache_mode, 4);
97
98 return cache;
99}
100
101#undef CM
102
103/*
104 * Update the cache mode to pgprot translation tables according to PAT
105 * configuration.
106 * Using lower indices is preferred, so we start with highest index.
107 */
108void pat_init_cache_modes(void)
109{
110 int i;
111 enum page_cache_mode cache;
112 char pat_msg[33];
113 u64 pat;
114
115 rdmsrl(MSR_IA32_CR_PAT, pat);
116 pat_msg[32] = 0;
117 for (i = 7; i >= 0; i--) {
118 cache = pat_get_cache_mode((pat >> (i * 8)) & 7,
119 pat_msg + 4 * i);
120 update_cache_mode_entry(i, cache);
121 }
122 pr_info("PAT configuration [0-7]: %s\n", pat_msg);
123}
124
78#define PAT(x, y) ((u64)PAT_ ## y << ((x)*8)) 125#define PAT(x, y) ((u64)PAT_ ## y << ((x)*8))
79 126
80void pat_init(void) 127void pat_init(void)
@@ -124,8 +171,7 @@ void pat_init(void)
124 wrmsrl(MSR_IA32_CR_PAT, pat); 171 wrmsrl(MSR_IA32_CR_PAT, pat);
125 172
126 if (boot_cpu) 173 if (boot_cpu)
127 printk(KERN_INFO "x86 PAT enabled: cpu %d, old 0x%Lx, new 0x%Lx\n", 174 pat_init_cache_modes();
128 smp_processor_id(), boot_pat_state, pat);
129} 175}
130 176
131#undef PAT 177#undef PAT