aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/include/asm/pgtable_types.h73
-rw-r--r--arch/x86/mm/init.c29
2 files changed, 101 insertions, 1 deletions
diff --git a/arch/x86/include/asm/pgtable_types.h b/arch/x86/include/asm/pgtable_types.h
index 07789647bf33..512464227c09 100644
--- a/arch/x86/include/asm/pgtable_types.h
+++ b/arch/x86/include/asm/pgtable_types.h
@@ -128,12 +128,34 @@
128 _PAGE_SOFT_DIRTY | _PAGE_NUMA) 128 _PAGE_SOFT_DIRTY | _PAGE_NUMA)
129#define _HPAGE_CHG_MASK (_PAGE_CHG_MASK | _PAGE_PSE | _PAGE_NUMA) 129#define _HPAGE_CHG_MASK (_PAGE_CHG_MASK | _PAGE_PSE | _PAGE_NUMA)
130 130
131#define _PAGE_CACHE_MASK (_PAGE_PCD | _PAGE_PWT)
132#define _PAGE_CACHE_WB (0) 131#define _PAGE_CACHE_WB (0)
133#define _PAGE_CACHE_WC (_PAGE_PWT) 132#define _PAGE_CACHE_WC (_PAGE_PWT)
134#define _PAGE_CACHE_UC_MINUS (_PAGE_PCD) 133#define _PAGE_CACHE_UC_MINUS (_PAGE_PCD)
135#define _PAGE_CACHE_UC (_PAGE_PCD | _PAGE_PWT) 134#define _PAGE_CACHE_UC (_PAGE_PCD | _PAGE_PWT)
136 135
136/*
137 * The cache modes defined here are used to translate between pure SW usage
138 * and the HW defined cache mode bits and/or PAT entries.
139 *
140 * The resulting bits for PWT, PCD and PAT should be chosen in a way
141 * to have the WB mode at index 0 (all bits clear). This is the default
142 * right now and likely would break too much if changed.
143 */
144#ifndef __ASSEMBLY__
145enum page_cache_mode {
146 _PAGE_CACHE_MODE_WB = 0,
147 _PAGE_CACHE_MODE_WC = 1,
148 _PAGE_CACHE_MODE_UC_MINUS = 2,
149 _PAGE_CACHE_MODE_UC = 3,
150 _PAGE_CACHE_MODE_WT = 4,
151 _PAGE_CACHE_MODE_WP = 5,
152 _PAGE_CACHE_MODE_NUM = 8
153};
154#endif
155
156#define _PAGE_CACHE_MASK (_PAGE_PAT | _PAGE_PCD | _PAGE_PWT)
157#define _PAGE_NOCACHE (cachemode2protval(_PAGE_CACHE_MODE_UC))
158
137#define PAGE_NONE __pgprot(_PAGE_PROTNONE | _PAGE_ACCESSED) 159#define PAGE_NONE __pgprot(_PAGE_PROTNONE | _PAGE_ACCESSED)
138#define PAGE_SHARED __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | \ 160#define PAGE_SHARED __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | \
139 _PAGE_ACCESSED | _PAGE_NX) 161 _PAGE_ACCESSED | _PAGE_NX)
@@ -341,6 +363,55 @@ static inline pmdval_t pmdnuma_flags(pmd_t pmd)
341#define pgprot_val(x) ((x).pgprot) 363#define pgprot_val(x) ((x).pgprot)
342#define __pgprot(x) ((pgprot_t) { (x) } ) 364#define __pgprot(x) ((pgprot_t) { (x) } )
343 365
366extern uint16_t __cachemode2pte_tbl[_PAGE_CACHE_MODE_NUM];
367extern uint8_t __pte2cachemode_tbl[8];
368
369#define __pte2cm_idx(cb) \
370 ((((cb) >> (_PAGE_BIT_PAT - 2)) & 4) | \
371 (((cb) >> (_PAGE_BIT_PCD - 1)) & 2) | \
372 (((cb) >> _PAGE_BIT_PWT) & 1))
373
374static inline unsigned long cachemode2protval(enum page_cache_mode pcm)
375{
376 if (likely(pcm == 0))
377 return 0;
378 return __cachemode2pte_tbl[pcm];
379}
380static inline pgprot_t cachemode2pgprot(enum page_cache_mode pcm)
381{
382 return __pgprot(cachemode2protval(pcm));
383}
384static inline enum page_cache_mode pgprot2cachemode(pgprot_t pgprot)
385{
386 unsigned long masked;
387
388 masked = pgprot_val(pgprot) & _PAGE_CACHE_MASK;
389 if (likely(masked == 0))
390 return 0;
391 return __pte2cachemode_tbl[__pte2cm_idx(masked)];
392}
393static inline pgprot_t pgprot_4k_2_large(pgprot_t pgprot)
394{
395 pgprot_t new;
396 unsigned long val;
397
398 val = pgprot_val(pgprot);
399 pgprot_val(new) = (val & ~(_PAGE_PAT | _PAGE_PAT_LARGE)) |
400 ((val & _PAGE_PAT) << (_PAGE_BIT_PAT_LARGE - _PAGE_BIT_PAT));
401 return new;
402}
403static inline pgprot_t pgprot_large_2_4k(pgprot_t pgprot)
404{
405 pgprot_t new;
406 unsigned long val;
407
408 val = pgprot_val(pgprot);
409 pgprot_val(new) = (val & ~(_PAGE_PAT | _PAGE_PAT_LARGE)) |
410 ((val & _PAGE_PAT_LARGE) >>
411 (_PAGE_BIT_PAT_LARGE - _PAGE_BIT_PAT));
412 return new;
413}
414
344 415
345typedef struct page *pgtable_t; 416typedef struct page *pgtable_t;
346 417
diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c
index 66dba36f2343..a9776ba475d4 100644
--- a/arch/x86/mm/init.c
+++ b/arch/x86/mm/init.c
@@ -27,6 +27,35 @@
27 27
28#include "mm_internal.h" 28#include "mm_internal.h"
29 29
30/*
31 * Tables translating between page_cache_type_t and pte encoding.
32 * Minimal supported modes are defined statically, modified if more supported
33 * cache modes are available.
34 * Index into __cachemode2pte_tbl is the cachemode.
35 * Index into __pte2cachemode_tbl are the caching attribute bits of the pte
36 * (_PAGE_PWT, _PAGE_PCD, _PAGE_PAT) at index bit positions 0, 1, 2.
37 */
38uint16_t __cachemode2pte_tbl[_PAGE_CACHE_MODE_NUM] = {
39 [_PAGE_CACHE_MODE_WB] = 0,
40 [_PAGE_CACHE_MODE_WC] = _PAGE_PWT,
41 [_PAGE_CACHE_MODE_UC_MINUS] = _PAGE_PCD,
42 [_PAGE_CACHE_MODE_UC] = _PAGE_PCD | _PAGE_PWT,
43 [_PAGE_CACHE_MODE_WT] = _PAGE_PCD,
44 [_PAGE_CACHE_MODE_WP] = _PAGE_PCD,
45};
46EXPORT_SYMBOL_GPL(__cachemode2pte_tbl);
47uint8_t __pte2cachemode_tbl[8] = {
48 [__pte2cm_idx(0)] = _PAGE_CACHE_MODE_WB,
49 [__pte2cm_idx(_PAGE_PWT)] = _PAGE_CACHE_MODE_WC,
50 [__pte2cm_idx(_PAGE_PCD)] = _PAGE_CACHE_MODE_UC_MINUS,
51 [__pte2cm_idx(_PAGE_PWT | _PAGE_PCD)] = _PAGE_CACHE_MODE_UC,
52 [__pte2cm_idx(_PAGE_PAT)] = _PAGE_CACHE_MODE_WB,
53 [__pte2cm_idx(_PAGE_PWT | _PAGE_PAT)] = _PAGE_CACHE_MODE_WC,
54 [__pte2cm_idx(_PAGE_PCD | _PAGE_PAT)] = _PAGE_CACHE_MODE_UC_MINUS,
55 [__pte2cm_idx(_PAGE_PWT | _PAGE_PCD | _PAGE_PAT)] = _PAGE_CACHE_MODE_UC,
56};
57EXPORT_SYMBOL_GPL(__pte2cachemode_tbl);
58
30static unsigned long __initdata pgt_buf_start; 59static unsigned long __initdata pgt_buf_start;
31static unsigned long __initdata pgt_buf_end; 60static unsigned long __initdata pgt_buf_end;
32static unsigned long __initdata pgt_buf_top; 61static unsigned long __initdata pgt_buf_top;