diff options
| -rw-r--r-- | arch/x86/mm/pat.c | 59 |
1 files changed, 29 insertions, 30 deletions
diff --git a/arch/x86/mm/pat.c b/arch/x86/mm/pat.c index 076187c76d7a..188e3e07eeeb 100644 --- a/arch/x86/mm/pat.c +++ b/arch/x86/mm/pat.c | |||
| @@ -70,18 +70,22 @@ __setup("debugpat", pat_debug_setup); | |||
| 70 | 70 | ||
| 71 | #ifdef CONFIG_X86_PAT | 71 | #ifdef CONFIG_X86_PAT |
| 72 | /* | 72 | /* |
| 73 | * X86 PAT uses page flags WC and Uncached together to keep track of | 73 | * X86 PAT uses page flags arch_1 and uncached together to keep track of |
| 74 | * memory type of pages that have backing page struct. X86 PAT supports 3 | 74 | * memory type of pages that have backing page struct. |
| 75 | * different memory types, _PAGE_CACHE_MODE_WB, _PAGE_CACHE_MODE_WC and | 75 | * |
| 76 | * _PAGE_CACHE_MODE_UC_MINUS and fourth state where page's memory type has not | 76 | * X86 PAT supports 4 different memory types: |
| 77 | * been changed from its default (value of -1 used to denote this). | 77 | * - _PAGE_CACHE_MODE_WB |
| 78 | * Note we do not support _PAGE_CACHE_MODE_UC here. | 78 | * - _PAGE_CACHE_MODE_WC |
| 79 | * - _PAGE_CACHE_MODE_UC_MINUS | ||
| 80 | * - _PAGE_CACHE_MODE_WT | ||
| 81 | * | ||
| 82 | * _PAGE_CACHE_MODE_WB is the default type. | ||
| 79 | */ | 83 | */ |
| 80 | 84 | ||
| 81 | #define _PGMT_DEFAULT 0 | 85 | #define _PGMT_WB 0 |
| 82 | #define _PGMT_WC (1UL << PG_arch_1) | 86 | #define _PGMT_WC (1UL << PG_arch_1) |
| 83 | #define _PGMT_UC_MINUS (1UL << PG_uncached) | 87 | #define _PGMT_UC_MINUS (1UL << PG_uncached) |
| 84 | #define _PGMT_WB (1UL << PG_uncached | 1UL << PG_arch_1) | 88 | #define _PGMT_WT (1UL << PG_uncached | 1UL << PG_arch_1) |
| 85 | #define _PGMT_MASK (1UL << PG_uncached | 1UL << PG_arch_1) | 89 | #define _PGMT_MASK (1UL << PG_uncached | 1UL << PG_arch_1) |
| 86 | #define _PGMT_CLEAR_MASK (~_PGMT_MASK) | 90 | #define _PGMT_CLEAR_MASK (~_PGMT_MASK) |
| 87 | 91 | ||
| @@ -89,14 +93,14 @@ static inline enum page_cache_mode get_page_memtype(struct page *pg) | |||
| 89 | { | 93 | { |
| 90 | unsigned long pg_flags = pg->flags & _PGMT_MASK; | 94 | unsigned long pg_flags = pg->flags & _PGMT_MASK; |
| 91 | 95 | ||
| 92 | if (pg_flags == _PGMT_DEFAULT) | 96 | if (pg_flags == _PGMT_WB) |
| 93 | return -1; | 97 | return _PAGE_CACHE_MODE_WB; |
| 94 | else if (pg_flags == _PGMT_WC) | 98 | else if (pg_flags == _PGMT_WC) |
| 95 | return _PAGE_CACHE_MODE_WC; | 99 | return _PAGE_CACHE_MODE_WC; |
| 96 | else if (pg_flags == _PGMT_UC_MINUS) | 100 | else if (pg_flags == _PGMT_UC_MINUS) |
| 97 | return _PAGE_CACHE_MODE_UC_MINUS; | 101 | return _PAGE_CACHE_MODE_UC_MINUS; |
| 98 | else | 102 | else |
| 99 | return _PAGE_CACHE_MODE_WB; | 103 | return _PAGE_CACHE_MODE_WT; |
| 100 | } | 104 | } |
| 101 | 105 | ||
| 102 | static inline void set_page_memtype(struct page *pg, | 106 | static inline void set_page_memtype(struct page *pg, |
| @@ -113,11 +117,12 @@ static inline void set_page_memtype(struct page *pg, | |||
| 113 | case _PAGE_CACHE_MODE_UC_MINUS: | 117 | case _PAGE_CACHE_MODE_UC_MINUS: |
| 114 | memtype_flags = _PGMT_UC_MINUS; | 118 | memtype_flags = _PGMT_UC_MINUS; |
| 115 | break; | 119 | break; |
| 116 | case _PAGE_CACHE_MODE_WB: | 120 | case _PAGE_CACHE_MODE_WT: |
| 117 | memtype_flags = _PGMT_WB; | 121 | memtype_flags = _PGMT_WT; |
| 118 | break; | 122 | break; |
| 123 | case _PAGE_CACHE_MODE_WB: | ||
| 119 | default: | 124 | default: |
| 120 | memtype_flags = _PGMT_DEFAULT; | 125 | memtype_flags = _PGMT_WB; |
| 121 | break; | 126 | break; |
| 122 | } | 127 | } |
| 123 | 128 | ||
| @@ -401,8 +406,10 @@ static int pat_pagerange_is_ram(resource_size_t start, resource_size_t end) | |||
| 401 | 406 | ||
| 402 | /* | 407 | /* |
| 403 | * For RAM pages, we use page flags to mark the pages with appropriate type. | 408 | * For RAM pages, we use page flags to mark the pages with appropriate type. |
| 404 | * The page flags are limited to three types, WB, WC and UC-. WT and WP requests | 409 | * The page flags are limited to four types, WB (default), WC, WT and UC-. |
| 405 | * fail with -EINVAL, and UC gets redirected to UC-. | 410 | * WP request fails with -EINVAL, and UC gets redirected to UC-. Setting |
| 411 | * a new memory type is only allowed for a page mapped with the default WB | ||
| 412 | * type. | ||
| 406 | * | 413 | * |
| 407 | * Here we do two passes: | 414 | * Here we do two passes: |
| 408 | * - Find the memtype of all the pages in the range, look for any conflicts. | 415 | * - Find the memtype of all the pages in the range, look for any conflicts. |
| @@ -415,8 +422,7 @@ static int reserve_ram_pages_type(u64 start, u64 end, | |||
| 415 | struct page *page; | 422 | struct page *page; |
| 416 | u64 pfn; | 423 | u64 pfn; |
| 417 | 424 | ||
| 418 | if ((req_type == _PAGE_CACHE_MODE_WT) || | 425 | if (req_type == _PAGE_CACHE_MODE_WP) { |
| 419 | (req_type == _PAGE_CACHE_MODE_WP)) { | ||
| 420 | if (new_type) | 426 | if (new_type) |
| 421 | *new_type = _PAGE_CACHE_MODE_UC_MINUS; | 427 | *new_type = _PAGE_CACHE_MODE_UC_MINUS; |
| 422 | return -EINVAL; | 428 | return -EINVAL; |
| @@ -433,7 +439,7 @@ static int reserve_ram_pages_type(u64 start, u64 end, | |||
| 433 | 439 | ||
| 434 | page = pfn_to_page(pfn); | 440 | page = pfn_to_page(pfn); |
| 435 | type = get_page_memtype(page); | 441 | type = get_page_memtype(page); |
| 436 | if (type != -1) { | 442 | if (type != _PAGE_CACHE_MODE_WB) { |
| 437 | pr_info("x86/PAT: reserve_ram_pages_type failed [mem %#010Lx-%#010Lx], track 0x%x, req 0x%x\n", | 443 | pr_info("x86/PAT: reserve_ram_pages_type failed [mem %#010Lx-%#010Lx], track 0x%x, req 0x%x\n", |
| 438 | start, end - 1, type, req_type); | 444 | start, end - 1, type, req_type); |
| 439 | if (new_type) | 445 | if (new_type) |
| @@ -460,7 +466,7 @@ static int free_ram_pages_type(u64 start, u64 end) | |||
| 460 | 466 | ||
| 461 | for (pfn = (start >> PAGE_SHIFT); pfn < (end >> PAGE_SHIFT); ++pfn) { | 467 | for (pfn = (start >> PAGE_SHIFT); pfn < (end >> PAGE_SHIFT); ++pfn) { |
| 462 | page = pfn_to_page(pfn); | 468 | page = pfn_to_page(pfn); |
| 463 | set_page_memtype(page, -1); | 469 | set_page_memtype(page, _PAGE_CACHE_MODE_WB); |
| 464 | } | 470 | } |
| 465 | return 0; | 471 | return 0; |
| 466 | } | 472 | } |
| @@ -601,7 +607,7 @@ int free_memtype(u64 start, u64 end) | |||
| 601 | * Only to be called when PAT is enabled | 607 | * Only to be called when PAT is enabled |
| 602 | * | 608 | * |
| 603 | * Returns _PAGE_CACHE_MODE_WB, _PAGE_CACHE_MODE_WC, _PAGE_CACHE_MODE_UC_MINUS | 609 | * Returns _PAGE_CACHE_MODE_WB, _PAGE_CACHE_MODE_WC, _PAGE_CACHE_MODE_UC_MINUS |
| 604 | * or _PAGE_CACHE_MODE_UC | 610 | * or _PAGE_CACHE_MODE_WT. |
| 605 | */ | 611 | */ |
| 606 | static enum page_cache_mode lookup_memtype(u64 paddr) | 612 | static enum page_cache_mode lookup_memtype(u64 paddr) |
| 607 | { | 613 | { |
| @@ -613,16 +619,9 @@ static enum page_cache_mode lookup_memtype(u64 paddr) | |||
| 613 | 619 | ||
| 614 | if (pat_pagerange_is_ram(paddr, paddr + PAGE_SIZE)) { | 620 | if (pat_pagerange_is_ram(paddr, paddr + PAGE_SIZE)) { |
| 615 | struct page *page; | 621 | struct page *page; |
| 616 | page = pfn_to_page(paddr >> PAGE_SHIFT); | ||
| 617 | rettype = get_page_memtype(page); | ||
| 618 | /* | ||
| 619 | * -1 from get_page_memtype() implies RAM page is in its | ||
| 620 | * default state and not reserved, and hence of type WB | ||
| 621 | */ | ||
| 622 | if (rettype == -1) | ||
| 623 | rettype = _PAGE_CACHE_MODE_WB; | ||
| 624 | 622 | ||
| 625 | return rettype; | 623 | page = pfn_to_page(paddr >> PAGE_SHIFT); |
| 624 | return get_page_memtype(page); | ||
| 626 | } | 625 | } |
| 627 | 626 | ||
| 628 | spin_lock(&memtype_lock); | 627 | spin_lock(&memtype_lock); |
