diff options
-rw-r--r-- | arch/x86/include/asm/pat.h | 1 | ||||
-rw-r--r-- | arch/x86/include/asm/pgtable_types.h | 4 | ||||
-rw-r--r-- | arch/x86/mm/init.c | 8 | ||||
-rw-r--r-- | arch/x86/mm/mm_internal.h | 2 | ||||
-rw-r--r-- | arch/x86/mm/pat.c | 50 |
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 | ||
13 | extern void pat_init(void); | 13 | extern void pat_init(void); |
14 | void pat_init_cache_modes(void); | ||
14 | 15 | ||
15 | extern int reserve_memtype(u64 start, u64 end, | 16 | extern 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 | ||
355 | static inline unsigned long cachemode2protval(enum page_cache_mode pcm) | 359 | static 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 | ||
719 | void 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 | ||
17 | extern int after_bootmem; | 17 | extern int after_bootmem; |
18 | 18 | ||
19 | void 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 |
36 | int __read_mostly pat_enabled = 1; | 37 | int __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 | |||
81 | static 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 | */ | ||
108 | void 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 | ||
80 | void pat_init(void) | 127 | void 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 |