diff options
author | Toshi Kani <toshi.kani@hp.com> | 2015-04-14 18:47:32 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-04-14 19:49:04 -0400 |
commit | 6b6378355b925050eb6fa966742d8c2d65ff0d83 (patch) | |
tree | 34fae2afb71d981d8ef8a2c640836c46781c00b8 /arch/x86 | |
parent | 5d72b4fba40ef4b3f7a1a11d6aacc85d9af81561 (diff) |
x86, mm: support huge KVA mappings on x86
Implement huge KVA mapping interfaces on x86.
On x86, MTRRs can override PAT memory types with a 4KB granularity. When
using a huge page, MTRRs can override the memory type of the huge page,
which may lead a performance penalty. The processor can also behave in an
undefined manner if a huge page is mapped to a memory range that MTRRs
have mapped with multiple different memory types. Therefore, the mapping
code falls back to use a smaller page size toward 4KB when a mapping range
is covered by non-WB type of MTRRs. The WB type of MTRRs has no affect on
the PAT memory types.
pud_set_huge() and pmd_set_huge() call mtrr_type_lookup() to see if a
given range is covered by MTRRs. MTRR_TYPE_WRBACK indicates that the
range is either covered by WB or not covered and the MTRR default value is
set to WB. 0xFF indicates that MTRRs are disabled.
HAVE_ARCH_HUGE_VMAP is selected when X86_64 or X86_32 with X86_PAE is set.
X86_32 without X86_PAE is not supported since such config can unlikey be
benefited from this feature, and there was an issue found in testing.
[fengguang.wu@intel.com: ioremap_pud_capable can be static]
Signed-off-by: Toshi Kani <toshi.kani@hp.com>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Dave Hansen <dave.hansen@intel.com>
Cc: Robert Elliott <Elliott@hp.com>
Signed-off-by: Fengguang Wu <fengguang.wu@intel.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'arch/x86')
-rw-r--r-- | arch/x86/Kconfig | 1 | ||||
-rw-r--r-- | arch/x86/mm/pgtable.c | 65 |
2 files changed, 66 insertions, 0 deletions
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 3e3aaad23414..0f948cefaeb1 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig | |||
@@ -99,6 +99,7 @@ config X86 | |||
99 | select IRQ_FORCED_THREADING | 99 | select IRQ_FORCED_THREADING |
100 | select HAVE_BPF_JIT if X86_64 | 100 | select HAVE_BPF_JIT if X86_64 |
101 | select HAVE_ARCH_TRANSPARENT_HUGEPAGE | 101 | select HAVE_ARCH_TRANSPARENT_HUGEPAGE |
102 | select HAVE_ARCH_HUGE_VMAP if X86_64 || (X86_32 && X86_PAE) | ||
102 | select ARCH_HAS_SG_CHAIN | 103 | select ARCH_HAS_SG_CHAIN |
103 | select CLKEVT_I8253 | 104 | select CLKEVT_I8253 |
104 | select ARCH_HAVE_NMI_SAFE_CMPXCHG | 105 | select ARCH_HAVE_NMI_SAFE_CMPXCHG |
diff --git a/arch/x86/mm/pgtable.c b/arch/x86/mm/pgtable.c index b28edfecbdfe..0b97d2c75df3 100644 --- a/arch/x86/mm/pgtable.c +++ b/arch/x86/mm/pgtable.c | |||
@@ -4,6 +4,7 @@ | |||
4 | #include <asm/pgtable.h> | 4 | #include <asm/pgtable.h> |
5 | #include <asm/tlb.h> | 5 | #include <asm/tlb.h> |
6 | #include <asm/fixmap.h> | 6 | #include <asm/fixmap.h> |
7 | #include <asm/mtrr.h> | ||
7 | 8 | ||
8 | #define PGALLOC_GFP GFP_KERNEL | __GFP_NOTRACK | __GFP_REPEAT | __GFP_ZERO | 9 | #define PGALLOC_GFP GFP_KERNEL | __GFP_NOTRACK | __GFP_REPEAT | __GFP_ZERO |
9 | 10 | ||
@@ -560,3 +561,67 @@ void native_set_fixmap(enum fixed_addresses idx, phys_addr_t phys, | |||
560 | { | 561 | { |
561 | __native_set_fixmap(idx, pfn_pte(phys >> PAGE_SHIFT, flags)); | 562 | __native_set_fixmap(idx, pfn_pte(phys >> PAGE_SHIFT, flags)); |
562 | } | 563 | } |
564 | |||
565 | #ifdef CONFIG_HAVE_ARCH_HUGE_VMAP | ||
566 | int pud_set_huge(pud_t *pud, phys_addr_t addr, pgprot_t prot) | ||
567 | { | ||
568 | u8 mtrr; | ||
569 | |||
570 | /* | ||
571 | * Do not use a huge page when the range is covered by non-WB type | ||
572 | * of MTRRs. | ||
573 | */ | ||
574 | mtrr = mtrr_type_lookup(addr, addr + PUD_SIZE); | ||
575 | if ((mtrr != MTRR_TYPE_WRBACK) && (mtrr != 0xFF)) | ||
576 | return 0; | ||
577 | |||
578 | prot = pgprot_4k_2_large(prot); | ||
579 | |||
580 | set_pte((pte_t *)pud, pfn_pte( | ||
581 | (u64)addr >> PAGE_SHIFT, | ||
582 | __pgprot(pgprot_val(prot) | _PAGE_PSE))); | ||
583 | |||
584 | return 1; | ||
585 | } | ||
586 | |||
587 | int pmd_set_huge(pmd_t *pmd, phys_addr_t addr, pgprot_t prot) | ||
588 | { | ||
589 | u8 mtrr; | ||
590 | |||
591 | /* | ||
592 | * Do not use a huge page when the range is covered by non-WB type | ||
593 | * of MTRRs. | ||
594 | */ | ||
595 | mtrr = mtrr_type_lookup(addr, addr + PMD_SIZE); | ||
596 | if ((mtrr != MTRR_TYPE_WRBACK) && (mtrr != 0xFF)) | ||
597 | return 0; | ||
598 | |||
599 | prot = pgprot_4k_2_large(prot); | ||
600 | |||
601 | set_pte((pte_t *)pmd, pfn_pte( | ||
602 | (u64)addr >> PAGE_SHIFT, | ||
603 | __pgprot(pgprot_val(prot) | _PAGE_PSE))); | ||
604 | |||
605 | return 1; | ||
606 | } | ||
607 | |||
608 | int pud_clear_huge(pud_t *pud) | ||
609 | { | ||
610 | if (pud_large(*pud)) { | ||
611 | pud_clear(pud); | ||
612 | return 1; | ||
613 | } | ||
614 | |||
615 | return 0; | ||
616 | } | ||
617 | |||
618 | int pmd_clear_huge(pmd_t *pmd) | ||
619 | { | ||
620 | if (pmd_large(*pmd)) { | ||
621 | pmd_clear(pmd); | ||
622 | return 1; | ||
623 | } | ||
624 | |||
625 | return 0; | ||
626 | } | ||
627 | #endif /* CONFIG_HAVE_ARCH_HUGE_VMAP */ | ||