diff options
author | Gerald Schaefer <gerald.schaefer@de.ibm.com> | 2016-07-04 08:47:01 -0400 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2016-07-06 02:46:43 -0400 |
commit | d08de8e2d86744f91d9d5d57c56ca2b6e33bf6ec (patch) | |
tree | 2bcf0bcb5ec30e48eb82fbc7e3a216cab8671f04 | |
parent | 46210c440c7b2d32a8ee4e1f0248d0a0b4ad9fa5 (diff) |
s390/mm: add support for 2GB hugepages
This adds support for 2GB hugetlbfs pages on s390.
Reviewed-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: Gerald Schaefer <gerald.schaefer@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
-rw-r--r-- | arch/s390/include/asm/hugetlb.h | 5 | ||||
-rw-r--r-- | arch/s390/include/asm/page.h | 1 | ||||
-rw-r--r-- | arch/s390/include/asm/pgtable.h | 71 | ||||
-rw-r--r-- | arch/s390/mm/gmap.c | 3 | ||||
-rw-r--r-- | arch/s390/mm/gup.c | 45 | ||||
-rw-r--r-- | arch/s390/mm/hugetlbpage.c | 129 | ||||
-rw-r--r-- | arch/s390/mm/pgtable.c | 39 | ||||
-rw-r--r-- | mm/hugetlb.c | 4 |
8 files changed, 233 insertions, 64 deletions
diff --git a/arch/s390/include/asm/hugetlb.h b/arch/s390/include/asm/hugetlb.h index d9be7c0c1291..4c7fac75090e 100644 --- a/arch/s390/include/asm/hugetlb.h +++ b/arch/s390/include/asm/hugetlb.h | |||
@@ -41,7 +41,10 @@ static inline int prepare_hugepage_range(struct file *file, | |||
41 | static inline void huge_pte_clear(struct mm_struct *mm, unsigned long addr, | 41 | static inline void huge_pte_clear(struct mm_struct *mm, unsigned long addr, |
42 | pte_t *ptep) | 42 | pte_t *ptep) |
43 | { | 43 | { |
44 | pte_val(*ptep) = _SEGMENT_ENTRY_EMPTY; | 44 | if ((pte_val(*ptep) & _REGION_ENTRY_TYPE_MASK) == _REGION_ENTRY_TYPE_R3) |
45 | pte_val(*ptep) = _REGION3_ENTRY_EMPTY; | ||
46 | else | ||
47 | pte_val(*ptep) = _SEGMENT_ENTRY_EMPTY; | ||
45 | } | 48 | } |
46 | 49 | ||
47 | static inline void huge_ptep_clear_flush(struct vm_area_struct *vma, | 50 | static inline void huge_ptep_clear_flush(struct vm_area_struct *vma, |
diff --git a/arch/s390/include/asm/page.h b/arch/s390/include/asm/page.h index 42fd5fea42ee..b2146c4119b2 100644 --- a/arch/s390/include/asm/page.h +++ b/arch/s390/include/asm/page.h | |||
@@ -21,6 +21,7 @@ | |||
21 | #define HPAGE_SIZE (1UL << HPAGE_SHIFT) | 21 | #define HPAGE_SIZE (1UL << HPAGE_SHIFT) |
22 | #define HPAGE_MASK (~(HPAGE_SIZE - 1)) | 22 | #define HPAGE_MASK (~(HPAGE_SIZE - 1)) |
23 | #define HUGETLB_PAGE_ORDER (HPAGE_SHIFT - PAGE_SHIFT) | 23 | #define HUGETLB_PAGE_ORDER (HPAGE_SHIFT - PAGE_SHIFT) |
24 | #define HUGE_MAX_HSTATE 2 | ||
24 | 25 | ||
25 | #define ARCH_HAS_SETCLEAR_HUGE_PTE | 26 | #define ARCH_HAS_SETCLEAR_HUGE_PTE |
26 | #define ARCH_HAS_HUGE_PTE_TYPE | 27 | #define ARCH_HAS_HUGE_PTE_TYPE |
diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h index 37e1aa9bf84c..ea1533e07271 100644 --- a/arch/s390/include/asm/pgtable.h +++ b/arch/s390/include/asm/pgtable.h | |||
@@ -306,6 +306,9 @@ static inline int is_module_addr(void *addr) | |||
306 | #define _REGION3_ENTRY_SOFT_DIRTY 0x0000 /* SW region soft dirty bit */ | 306 | #define _REGION3_ENTRY_SOFT_DIRTY 0x0000 /* SW region soft dirty bit */ |
307 | #endif | 307 | #endif |
308 | 308 | ||
309 | #define _REGION_ENTRY_BITS 0xfffffffffffff227UL | ||
310 | #define _REGION_ENTRY_BITS_LARGE 0xffffffff8000fe27UL | ||
311 | |||
309 | /* Bits in the segment table entry */ | 312 | /* Bits in the segment table entry */ |
310 | #define _SEGMENT_ENTRY_BITS 0xfffffffffffffe33UL | 313 | #define _SEGMENT_ENTRY_BITS 0xfffffffffffffe33UL |
311 | #define _SEGMENT_ENTRY_BITS_LARGE 0xfffffffffff0ff33UL | 314 | #define _SEGMENT_ENTRY_BITS_LARGE 0xfffffffffff0ff33UL |
@@ -573,7 +576,7 @@ static inline int pud_none(pud_t pud) | |||
573 | { | 576 | { |
574 | if ((pud_val(pud) & _REGION_ENTRY_TYPE_MASK) < _REGION_ENTRY_TYPE_R3) | 577 | if ((pud_val(pud) & _REGION_ENTRY_TYPE_MASK) < _REGION_ENTRY_TYPE_R3) |
575 | return 0; | 578 | return 0; |
576 | return (pud_val(pud) & _REGION_ENTRY_INVALID) != 0UL; | 579 | return pud_val(pud) == _REGION3_ENTRY_EMPTY; |
577 | } | 580 | } |
578 | 581 | ||
579 | static inline int pud_large(pud_t pud) | 582 | static inline int pud_large(pud_t pud) |
@@ -593,17 +596,25 @@ static inline unsigned long pud_pfn(pud_t pud) | |||
593 | return (pud_val(pud) & origin_mask) >> PAGE_SHIFT; | 596 | return (pud_val(pud) & origin_mask) >> PAGE_SHIFT; |
594 | } | 597 | } |
595 | 598 | ||
599 | static inline int pmd_large(pmd_t pmd) | ||
600 | { | ||
601 | return (pmd_val(pmd) & _SEGMENT_ENTRY_LARGE) != 0; | ||
602 | } | ||
603 | |||
604 | static inline int pmd_bad(pmd_t pmd) | ||
605 | { | ||
606 | if (pmd_large(pmd)) | ||
607 | return (pmd_val(pmd) & ~_SEGMENT_ENTRY_BITS_LARGE) != 0; | ||
608 | return (pmd_val(pmd) & ~_SEGMENT_ENTRY_BITS) != 0; | ||
609 | } | ||
610 | |||
596 | static inline int pud_bad(pud_t pud) | 611 | static inline int pud_bad(pud_t pud) |
597 | { | 612 | { |
598 | /* | 613 | if ((pud_val(pud) & _REGION_ENTRY_TYPE_MASK) < _REGION_ENTRY_TYPE_R3) |
599 | * With dynamic page table levels the pud can be a region table | 614 | return pmd_bad(__pmd(pud_val(pud))); |
600 | * entry or a segment table entry. Check for the bit that are | 615 | if (pud_large(pud)) |
601 | * invalid for either table entry. | 616 | return (pud_val(pud) & ~_REGION_ENTRY_BITS_LARGE) != 0; |
602 | */ | 617 | return (pud_val(pud) & ~_REGION_ENTRY_BITS) != 0; |
603 | unsigned long mask = | ||
604 | ~_SEGMENT_ENTRY_ORIGIN & ~_REGION_ENTRY_INVALID & | ||
605 | ~_REGION_ENTRY_TYPE_MASK & ~_REGION_ENTRY_LENGTH; | ||
606 | return (pud_val(pud) & mask) != 0; | ||
607 | } | 618 | } |
608 | 619 | ||
609 | static inline int pmd_present(pmd_t pmd) | 620 | static inline int pmd_present(pmd_t pmd) |
@@ -616,11 +627,6 @@ static inline int pmd_none(pmd_t pmd) | |||
616 | return pmd_val(pmd) == _SEGMENT_ENTRY_INVALID; | 627 | return pmd_val(pmd) == _SEGMENT_ENTRY_INVALID; |
617 | } | 628 | } |
618 | 629 | ||
619 | static inline int pmd_large(pmd_t pmd) | ||
620 | { | ||
621 | return (pmd_val(pmd) & _SEGMENT_ENTRY_LARGE) != 0; | ||
622 | } | ||
623 | |||
624 | static inline unsigned long pmd_pfn(pmd_t pmd) | 630 | static inline unsigned long pmd_pfn(pmd_t pmd) |
625 | { | 631 | { |
626 | unsigned long origin_mask; | 632 | unsigned long origin_mask; |
@@ -631,13 +637,6 @@ static inline unsigned long pmd_pfn(pmd_t pmd) | |||
631 | return (pmd_val(pmd) & origin_mask) >> PAGE_SHIFT; | 637 | return (pmd_val(pmd) & origin_mask) >> PAGE_SHIFT; |
632 | } | 638 | } |
633 | 639 | ||
634 | static inline int pmd_bad(pmd_t pmd) | ||
635 | { | ||
636 | if (pmd_large(pmd)) | ||
637 | return (pmd_val(pmd) & ~_SEGMENT_ENTRY_BITS_LARGE) != 0; | ||
638 | return (pmd_val(pmd) & ~_SEGMENT_ENTRY_BITS) != 0; | ||
639 | } | ||
640 | |||
641 | #define __HAVE_ARCH_PMD_WRITE | 640 | #define __HAVE_ARCH_PMD_WRITE |
642 | static inline int pmd_write(pmd_t pmd) | 641 | static inline int pmd_write(pmd_t pmd) |
643 | { | 642 | { |
@@ -1081,6 +1080,7 @@ static inline pmd_t *pmd_offset(pud_t *pud, unsigned long address) | |||
1081 | #define pte_page(x) pfn_to_page(pte_pfn(x)) | 1080 | #define pte_page(x) pfn_to_page(pte_pfn(x)) |
1082 | 1081 | ||
1083 | #define pmd_page(pmd) pfn_to_page(pmd_pfn(pmd)) | 1082 | #define pmd_page(pmd) pfn_to_page(pmd_pfn(pmd)) |
1083 | #define pud_page(pud) pfn_to_page(pud_pfn(pud)) | ||
1084 | 1084 | ||
1085 | /* Find an entry in the lowest level page table.. */ | 1085 | /* Find an entry in the lowest level page table.. */ |
1086 | #define pte_offset(pmd, addr) ((pte_t *) pmd_deref(*(pmd)) + pte_index(addr)) | 1086 | #define pte_offset(pmd, addr) ((pte_t *) pmd_deref(*(pmd)) + pte_index(addr)) |
@@ -1238,6 +1238,19 @@ static inline void __pmdp_idte(unsigned long address, pmd_t *pmdp) | |||
1238 | : "cc" ); | 1238 | : "cc" ); |
1239 | } | 1239 | } |
1240 | 1240 | ||
1241 | static inline void __pudp_idte(unsigned long address, pud_t *pudp) | ||
1242 | { | ||
1243 | unsigned long r3o; | ||
1244 | |||
1245 | r3o = (unsigned long) pudp - pud_index(address) * sizeof(pud_t); | ||
1246 | r3o |= _ASCE_TYPE_REGION3; | ||
1247 | asm volatile( | ||
1248 | " .insn rrf,0xb98e0000,%2,%3,0,0" | ||
1249 | : "=m" (*pudp) | ||
1250 | : "m" (*pudp), "a" (r3o), "a" ((address & PUD_MASK)) | ||
1251 | : "cc"); | ||
1252 | } | ||
1253 | |||
1241 | static inline void __pmdp_idte_local(unsigned long address, pmd_t *pmdp) | 1254 | static inline void __pmdp_idte_local(unsigned long address, pmd_t *pmdp) |
1242 | { | 1255 | { |
1243 | unsigned long sto; | 1256 | unsigned long sto; |
@@ -1250,8 +1263,22 @@ static inline void __pmdp_idte_local(unsigned long address, pmd_t *pmdp) | |||
1250 | : "cc" ); | 1263 | : "cc" ); |
1251 | } | 1264 | } |
1252 | 1265 | ||
1266 | static inline void __pudp_idte_local(unsigned long address, pud_t *pudp) | ||
1267 | { | ||
1268 | unsigned long r3o; | ||
1269 | |||
1270 | r3o = (unsigned long) pudp - pud_index(address) * sizeof(pud_t); | ||
1271 | r3o |= _ASCE_TYPE_REGION3; | ||
1272 | asm volatile( | ||
1273 | " .insn rrf,0xb98e0000,%2,%3,0,1" | ||
1274 | : "=m" (*pudp) | ||
1275 | : "m" (*pudp), "a" (r3o), "a" ((address & PUD_MASK)) | ||
1276 | : "cc"); | ||
1277 | } | ||
1278 | |||
1253 | pmd_t pmdp_xchg_direct(struct mm_struct *, unsigned long, pmd_t *, pmd_t); | 1279 | pmd_t pmdp_xchg_direct(struct mm_struct *, unsigned long, pmd_t *, pmd_t); |
1254 | pmd_t pmdp_xchg_lazy(struct mm_struct *, unsigned long, pmd_t *, pmd_t); | 1280 | pmd_t pmdp_xchg_lazy(struct mm_struct *, unsigned long, pmd_t *, pmd_t); |
1281 | pud_t pudp_xchg_direct(struct mm_struct *, unsigned long, pud_t *, pud_t); | ||
1255 | 1282 | ||
1256 | #ifdef CONFIG_TRANSPARENT_HUGEPAGE | 1283 | #ifdef CONFIG_TRANSPARENT_HUGEPAGE |
1257 | 1284 | ||
diff --git a/arch/s390/mm/gmap.c b/arch/s390/mm/gmap.c index cace818d86eb..69466f6055c2 100644 --- a/arch/s390/mm/gmap.c +++ b/arch/s390/mm/gmap.c | |||
@@ -430,6 +430,9 @@ int __gmap_link(struct gmap *gmap, unsigned long gaddr, unsigned long vmaddr) | |||
430 | VM_BUG_ON(pgd_none(*pgd)); | 430 | VM_BUG_ON(pgd_none(*pgd)); |
431 | pud = pud_offset(pgd, vmaddr); | 431 | pud = pud_offset(pgd, vmaddr); |
432 | VM_BUG_ON(pud_none(*pud)); | 432 | VM_BUG_ON(pud_none(*pud)); |
433 | /* large puds cannot yet be handled */ | ||
434 | if (pud_large(*pud)) | ||
435 | return -EFAULT; | ||
433 | pmd = pmd_offset(pud, vmaddr); | 436 | pmd = pmd_offset(pud, vmaddr); |
434 | VM_BUG_ON(pmd_none(*pmd)); | 437 | VM_BUG_ON(pmd_none(*pmd)); |
435 | /* large pmds cannot yet be handled */ | 438 | /* large pmds cannot yet be handled */ |
diff --git a/arch/s390/mm/gup.c b/arch/s390/mm/gup.c index a8a6765f1a51..adb0c34bf431 100644 --- a/arch/s390/mm/gup.c +++ b/arch/s390/mm/gup.c | |||
@@ -128,6 +128,44 @@ static inline int gup_pmd_range(pud_t *pudp, pud_t pud, unsigned long addr, | |||
128 | return 1; | 128 | return 1; |
129 | } | 129 | } |
130 | 130 | ||
131 | static int gup_huge_pud(pud_t *pudp, pud_t pud, unsigned long addr, | ||
132 | unsigned long end, int write, struct page **pages, int *nr) | ||
133 | { | ||
134 | struct page *head, *page; | ||
135 | unsigned long mask; | ||
136 | int refs; | ||
137 | |||
138 | mask = (write ? _REGION_ENTRY_PROTECT : 0) | _REGION_ENTRY_INVALID; | ||
139 | if ((pud_val(pud) & mask) != 0) | ||
140 | return 0; | ||
141 | VM_BUG_ON(!pfn_valid(pud_pfn(pud))); | ||
142 | |||
143 | refs = 0; | ||
144 | head = pud_page(pud); | ||
145 | page = head + ((addr & ~PUD_MASK) >> PAGE_SHIFT); | ||
146 | do { | ||
147 | VM_BUG_ON_PAGE(compound_head(page) != head, page); | ||
148 | pages[*nr] = page; | ||
149 | (*nr)++; | ||
150 | page++; | ||
151 | refs++; | ||
152 | } while (addr += PAGE_SIZE, addr != end); | ||
153 | |||
154 | if (!page_cache_add_speculative(head, refs)) { | ||
155 | *nr -= refs; | ||
156 | return 0; | ||
157 | } | ||
158 | |||
159 | if (unlikely(pud_val(pud) != pud_val(*pudp))) { | ||
160 | *nr -= refs; | ||
161 | while (refs--) | ||
162 | put_page(head); | ||
163 | return 0; | ||
164 | } | ||
165 | |||
166 | return 1; | ||
167 | } | ||
168 | |||
131 | static inline int gup_pud_range(pgd_t *pgdp, pgd_t pgd, unsigned long addr, | 169 | static inline int gup_pud_range(pgd_t *pgdp, pgd_t pgd, unsigned long addr, |
132 | unsigned long end, int write, struct page **pages, int *nr) | 170 | unsigned long end, int write, struct page **pages, int *nr) |
133 | { | 171 | { |
@@ -144,7 +182,12 @@ static inline int gup_pud_range(pgd_t *pgdp, pgd_t pgd, unsigned long addr, | |||
144 | next = pud_addr_end(addr, end); | 182 | next = pud_addr_end(addr, end); |
145 | if (pud_none(pud)) | 183 | if (pud_none(pud)) |
146 | return 0; | 184 | return 0; |
147 | if (!gup_pmd_range(pudp, pud, addr, next, write, pages, nr)) | 185 | if (unlikely(pud_large(pud))) { |
186 | if (!gup_huge_pud(pudp, pud, addr, next, write, pages, | ||
187 | nr)) | ||
188 | return 0; | ||
189 | } else if (!gup_pmd_range(pudp, pud, addr, next, write, pages, | ||
190 | nr)) | ||
148 | return 0; | 191 | return 0; |
149 | } while (pudp++, addr = next, addr != end); | 192 | } while (pudp++, addr = next, addr != end); |
150 | 193 | ||
diff --git a/arch/s390/mm/hugetlbpage.c b/arch/s390/mm/hugetlbpage.c index 1b5e8983f4f3..e19d853883be 100644 --- a/arch/s390/mm/hugetlbpage.c +++ b/arch/s390/mm/hugetlbpage.c | |||
@@ -1,19 +1,22 @@ | |||
1 | /* | 1 | /* |
2 | * IBM System z Huge TLB Page Support for Kernel. | 2 | * IBM System z Huge TLB Page Support for Kernel. |
3 | * | 3 | * |
4 | * Copyright IBM Corp. 2007 | 4 | * Copyright IBM Corp. 2007,2016 |
5 | * Author(s): Gerald Schaefer <gerald.schaefer@de.ibm.com> | 5 | * Author(s): Gerald Schaefer <gerald.schaefer@de.ibm.com> |
6 | */ | 6 | */ |
7 | 7 | ||
8 | #define KMSG_COMPONENT "hugetlb" | ||
9 | #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt | ||
10 | |||
8 | #include <linux/mm.h> | 11 | #include <linux/mm.h> |
9 | #include <linux/hugetlb.h> | 12 | #include <linux/hugetlb.h> |
10 | 13 | ||
11 | static inline pmd_t __pte_to_pmd(pte_t pte) | 14 | static inline unsigned long __pte_to_rste(pte_t pte) |
12 | { | 15 | { |
13 | pmd_t pmd; | 16 | unsigned long rste; |
14 | 17 | ||
15 | /* | 18 | /* |
16 | * Convert encoding pte bits pmd bits | 19 | * Convert encoding pte bits pmd / pud bits |
17 | * lIR.uswrdy.p dy..R...I...wr | 20 | * lIR.uswrdy.p dy..R...I...wr |
18 | * empty 010.000000.0 -> 00..0...1...00 | 21 | * empty 010.000000.0 -> 00..0...1...00 |
19 | * prot-none, clean, old 111.000000.1 -> 00..1...1...00 | 22 | * prot-none, clean, old 111.000000.1 -> 00..1...1...00 |
@@ -33,25 +36,31 @@ static inline pmd_t __pte_to_pmd(pte_t pte) | |||
33 | * u unused, l large | 36 | * u unused, l large |
34 | */ | 37 | */ |
35 | if (pte_present(pte)) { | 38 | if (pte_present(pte)) { |
36 | pmd_val(pmd) = pte_val(pte) & PAGE_MASK; | 39 | rste = pte_val(pte) & PAGE_MASK; |
37 | pmd_val(pmd) |= (pte_val(pte) & _PAGE_READ) >> 4; | 40 | rste |= (pte_val(pte) & _PAGE_READ) >> 4; |
38 | pmd_val(pmd) |= (pte_val(pte) & _PAGE_WRITE) >> 4; | 41 | rste |= (pte_val(pte) & _PAGE_WRITE) >> 4; |
39 | pmd_val(pmd) |= (pte_val(pte) & _PAGE_INVALID) >> 5; | 42 | rste |= (pte_val(pte) & _PAGE_INVALID) >> 5; |
40 | pmd_val(pmd) |= (pte_val(pte) & _PAGE_PROTECT); | 43 | rste |= (pte_val(pte) & _PAGE_PROTECT); |
41 | pmd_val(pmd) |= (pte_val(pte) & _PAGE_DIRTY) << 10; | 44 | rste |= (pte_val(pte) & _PAGE_DIRTY) << 10; |
42 | pmd_val(pmd) |= (pte_val(pte) & _PAGE_YOUNG) << 10; | 45 | rste |= (pte_val(pte) & _PAGE_YOUNG) << 10; |
43 | pmd_val(pmd) |= (pte_val(pte) & _PAGE_SOFT_DIRTY) << 13; | 46 | rste |= (pte_val(pte) & _PAGE_SOFT_DIRTY) << 13; |
44 | } else | 47 | } else |
45 | pmd_val(pmd) = _SEGMENT_ENTRY_INVALID; | 48 | rste = _SEGMENT_ENTRY_INVALID; |
46 | return pmd; | 49 | return rste; |
47 | } | 50 | } |
48 | 51 | ||
49 | static inline pte_t __pmd_to_pte(pmd_t pmd) | 52 | static inline pte_t __rste_to_pte(unsigned long rste) |
50 | { | 53 | { |
54 | int present; | ||
51 | pte_t pte; | 55 | pte_t pte; |
52 | 56 | ||
57 | if ((rste & _REGION_ENTRY_TYPE_MASK) == _REGION_ENTRY_TYPE_R3) | ||
58 | present = pud_present(__pud(rste)); | ||
59 | else | ||
60 | present = pmd_present(__pmd(rste)); | ||
61 | |||
53 | /* | 62 | /* |
54 | * Convert encoding pmd bits pte bits | 63 | * Convert encoding pmd / pud bits pte bits |
55 | * dy..R...I...wr lIR.uswrdy.p | 64 | * dy..R...I...wr lIR.uswrdy.p |
56 | * empty 00..0...1...00 -> 010.000000.0 | 65 | * empty 00..0...1...00 -> 010.000000.0 |
57 | * prot-none, clean, old 00..1...1...00 -> 111.000000.1 | 66 | * prot-none, clean, old 00..1...1...00 -> 111.000000.1 |
@@ -70,16 +79,16 @@ static inline pte_t __pmd_to_pte(pmd_t pmd) | |||
70 | * SW-bits: p present, y young, d dirty, r read, w write, s special, | 79 | * SW-bits: p present, y young, d dirty, r read, w write, s special, |
71 | * u unused, l large | 80 | * u unused, l large |
72 | */ | 81 | */ |
73 | if (pmd_present(pmd)) { | 82 | if (present) { |
74 | pte_val(pte) = pmd_val(pmd) & _SEGMENT_ENTRY_ORIGIN_LARGE; | 83 | pte_val(pte) = rste & _SEGMENT_ENTRY_ORIGIN_LARGE; |
75 | pte_val(pte) |= _PAGE_LARGE | _PAGE_PRESENT; | 84 | pte_val(pte) |= _PAGE_LARGE | _PAGE_PRESENT; |
76 | pte_val(pte) |= (pmd_val(pmd) & _SEGMENT_ENTRY_READ) << 4; | 85 | pte_val(pte) |= (rste & _SEGMENT_ENTRY_READ) << 4; |
77 | pte_val(pte) |= (pmd_val(pmd) & _SEGMENT_ENTRY_WRITE) << 4; | 86 | pte_val(pte) |= (rste & _SEGMENT_ENTRY_WRITE) << 4; |
78 | pte_val(pte) |= (pmd_val(pmd) & _SEGMENT_ENTRY_INVALID) << 5; | 87 | pte_val(pte) |= (rste & _SEGMENT_ENTRY_INVALID) << 5; |
79 | pte_val(pte) |= (pmd_val(pmd) & _SEGMENT_ENTRY_PROTECT); | 88 | pte_val(pte) |= (rste & _SEGMENT_ENTRY_PROTECT); |
80 | pte_val(pte) |= (pmd_val(pmd) & _SEGMENT_ENTRY_DIRTY) >> 10; | 89 | pte_val(pte) |= (rste & _SEGMENT_ENTRY_DIRTY) >> 10; |
81 | pte_val(pte) |= (pmd_val(pmd) & _SEGMENT_ENTRY_YOUNG) >> 10; | 90 | pte_val(pte) |= (rste & _SEGMENT_ENTRY_YOUNG) >> 10; |
82 | pte_val(pte) |= (pmd_val(pmd) & _SEGMENT_ENTRY_SOFT_DIRTY) >> 13; | 91 | pte_val(pte) |= (rste & _SEGMENT_ENTRY_SOFT_DIRTY) >> 13; |
83 | } else | 92 | } else |
84 | pte_val(pte) = _PAGE_INVALID; | 93 | pte_val(pte) = _PAGE_INVALID; |
85 | return pte; | 94 | return pte; |
@@ -88,27 +97,33 @@ static inline pte_t __pmd_to_pte(pmd_t pmd) | |||
88 | void set_huge_pte_at(struct mm_struct *mm, unsigned long addr, | 97 | void set_huge_pte_at(struct mm_struct *mm, unsigned long addr, |
89 | pte_t *ptep, pte_t pte) | 98 | pte_t *ptep, pte_t pte) |
90 | { | 99 | { |
91 | pmd_t pmd = __pte_to_pmd(pte); | 100 | unsigned long rste = __pte_to_rste(pte); |
92 | 101 | ||
93 | pmd_val(pmd) |= _SEGMENT_ENTRY_LARGE; | 102 | /* Set correct table type for 2G hugepages */ |
94 | *(pmd_t *) ptep = pmd; | 103 | if ((pte_val(*ptep) & _REGION_ENTRY_TYPE_MASK) == _REGION_ENTRY_TYPE_R3) |
104 | rste |= _REGION_ENTRY_TYPE_R3 | _REGION3_ENTRY_LARGE; | ||
105 | else | ||
106 | rste |= _SEGMENT_ENTRY_LARGE; | ||
107 | pte_val(*ptep) = rste; | ||
95 | } | 108 | } |
96 | 109 | ||
97 | pte_t huge_ptep_get(pte_t *ptep) | 110 | pte_t huge_ptep_get(pte_t *ptep) |
98 | { | 111 | { |
99 | pmd_t pmd = *(pmd_t *) ptep; | 112 | return __rste_to_pte(pte_val(*ptep)); |
100 | |||
101 | return __pmd_to_pte(pmd); | ||
102 | } | 113 | } |
103 | 114 | ||
104 | pte_t huge_ptep_get_and_clear(struct mm_struct *mm, | 115 | pte_t huge_ptep_get_and_clear(struct mm_struct *mm, |
105 | unsigned long addr, pte_t *ptep) | 116 | unsigned long addr, pte_t *ptep) |
106 | { | 117 | { |
118 | pte_t pte = huge_ptep_get(ptep); | ||
107 | pmd_t *pmdp = (pmd_t *) ptep; | 119 | pmd_t *pmdp = (pmd_t *) ptep; |
108 | pmd_t old; | 120 | pud_t *pudp = (pud_t *) ptep; |
109 | 121 | ||
110 | old = pmdp_xchg_direct(mm, addr, pmdp, __pmd(_SEGMENT_ENTRY_EMPTY)); | 122 | if ((pte_val(*ptep) & _REGION_ENTRY_TYPE_MASK) == _REGION_ENTRY_TYPE_R3) |
111 | return __pmd_to_pte(old); | 123 | pudp_xchg_direct(mm, addr, pudp, __pud(_REGION3_ENTRY_EMPTY)); |
124 | else | ||
125 | pmdp_xchg_direct(mm, addr, pmdp, __pmd(_SEGMENT_ENTRY_EMPTY)); | ||
126 | return pte; | ||
112 | } | 127 | } |
113 | 128 | ||
114 | pte_t *huge_pte_alloc(struct mm_struct *mm, | 129 | pte_t *huge_pte_alloc(struct mm_struct *mm, |
@@ -120,8 +135,12 @@ pte_t *huge_pte_alloc(struct mm_struct *mm, | |||
120 | 135 | ||
121 | pgdp = pgd_offset(mm, addr); | 136 | pgdp = pgd_offset(mm, addr); |
122 | pudp = pud_alloc(mm, pgdp, addr); | 137 | pudp = pud_alloc(mm, pgdp, addr); |
123 | if (pudp) | 138 | if (pudp) { |
124 | pmdp = pmd_alloc(mm, pudp, addr); | 139 | if (sz == PUD_SIZE) |
140 | return (pte_t *) pudp; | ||
141 | else if (sz == PMD_SIZE) | ||
142 | pmdp = pmd_alloc(mm, pudp, addr); | ||
143 | } | ||
125 | return (pte_t *) pmdp; | 144 | return (pte_t *) pmdp; |
126 | } | 145 | } |
127 | 146 | ||
@@ -134,8 +153,11 @@ pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr) | |||
134 | pgdp = pgd_offset(mm, addr); | 153 | pgdp = pgd_offset(mm, addr); |
135 | if (pgd_present(*pgdp)) { | 154 | if (pgd_present(*pgdp)) { |
136 | pudp = pud_offset(pgdp, addr); | 155 | pudp = pud_offset(pgdp, addr); |
137 | if (pud_present(*pudp)) | 156 | if (pud_present(*pudp)) { |
157 | if (pud_large(*pudp)) | ||
158 | return (pte_t *) pudp; | ||
138 | pmdp = pmd_offset(pudp, addr); | 159 | pmdp = pmd_offset(pudp, addr); |
160 | } | ||
139 | } | 161 | } |
140 | return (pte_t *) pmdp; | 162 | return (pte_t *) pmdp; |
141 | } | 163 | } |
@@ -147,5 +169,34 @@ int pmd_huge(pmd_t pmd) | |||
147 | 169 | ||
148 | int pud_huge(pud_t pud) | 170 | int pud_huge(pud_t pud) |
149 | { | 171 | { |
150 | return 0; | 172 | return pud_large(pud); |
173 | } | ||
174 | |||
175 | struct page * | ||
176 | follow_huge_pud(struct mm_struct *mm, unsigned long address, | ||
177 | pud_t *pud, int flags) | ||
178 | { | ||
179 | if (flags & FOLL_GET) | ||
180 | return NULL; | ||
181 | |||
182 | return pud_page(*pud) + ((address & ~PUD_MASK) >> PAGE_SHIFT); | ||
183 | } | ||
184 | |||
185 | static __init int setup_hugepagesz(char *opt) | ||
186 | { | ||
187 | unsigned long size; | ||
188 | char *string = opt; | ||
189 | |||
190 | size = memparse(opt, &opt); | ||
191 | if (MACHINE_HAS_EDAT1 && size == PMD_SIZE) { | ||
192 | hugetlb_add_hstate(PMD_SHIFT - PAGE_SHIFT); | ||
193 | } else if (MACHINE_HAS_EDAT2 && size == PUD_SIZE) { | ||
194 | hugetlb_add_hstate(PUD_SHIFT - PAGE_SHIFT); | ||
195 | } else { | ||
196 | pr_err("hugepagesz= specifies an unsupported page size %s\n", | ||
197 | string); | ||
198 | return 0; | ||
199 | } | ||
200 | return 1; | ||
151 | } | 201 | } |
202 | __setup("hugepagesz=", setup_hugepagesz); | ||
diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c index 74f8f2a8a4e8..b98d1a152d46 100644 --- a/arch/s390/mm/pgtable.c +++ b/arch/s390/mm/pgtable.c | |||
@@ -352,6 +352,45 @@ pmd_t pmdp_xchg_lazy(struct mm_struct *mm, unsigned long addr, | |||
352 | } | 352 | } |
353 | EXPORT_SYMBOL(pmdp_xchg_lazy); | 353 | EXPORT_SYMBOL(pmdp_xchg_lazy); |
354 | 354 | ||
355 | static inline pud_t pudp_flush_direct(struct mm_struct *mm, | ||
356 | unsigned long addr, pud_t *pudp) | ||
357 | { | ||
358 | pud_t old; | ||
359 | |||
360 | old = *pudp; | ||
361 | if (pud_val(old) & _REGION_ENTRY_INVALID) | ||
362 | return old; | ||
363 | if (!MACHINE_HAS_IDTE) { | ||
364 | /* | ||
365 | * Invalid bit position is the same for pmd and pud, so we can | ||
366 | * re-use _pmd_csp() here | ||
367 | */ | ||
368 | __pmdp_csp((pmd_t *) pudp); | ||
369 | return old; | ||
370 | } | ||
371 | atomic_inc(&mm->context.flush_count); | ||
372 | if (MACHINE_HAS_TLB_LC && | ||
373 | cpumask_equal(mm_cpumask(mm), cpumask_of(smp_processor_id()))) | ||
374 | __pudp_idte_local(addr, pudp); | ||
375 | else | ||
376 | __pudp_idte(addr, pudp); | ||
377 | atomic_dec(&mm->context.flush_count); | ||
378 | return old; | ||
379 | } | ||
380 | |||
381 | pud_t pudp_xchg_direct(struct mm_struct *mm, unsigned long addr, | ||
382 | pud_t *pudp, pud_t new) | ||
383 | { | ||
384 | pud_t old; | ||
385 | |||
386 | preempt_disable(); | ||
387 | old = pudp_flush_direct(mm, addr, pudp); | ||
388 | *pudp = new; | ||
389 | preempt_enable(); | ||
390 | return old; | ||
391 | } | ||
392 | EXPORT_SYMBOL(pudp_xchg_direct); | ||
393 | |||
355 | #ifdef CONFIG_TRANSPARENT_HUGEPAGE | 394 | #ifdef CONFIG_TRANSPARENT_HUGEPAGE |
356 | void pgtable_trans_huge_deposit(struct mm_struct *mm, pmd_t *pmdp, | 395 | void pgtable_trans_huge_deposit(struct mm_struct *mm, pmd_t *pmdp, |
357 | pgtable_t pgtable) | 396 | pgtable_t pgtable) |
diff --git a/mm/hugetlb.c b/mm/hugetlb.c index 388c2bb9b55c..7f0fa87cc66d 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c | |||
@@ -1022,7 +1022,9 @@ static int hstate_next_node_to_free(struct hstate *h, nodemask_t *nodes_allowed) | |||
1022 | ((node = hstate_next_node_to_free(hs, mask)) || 1); \ | 1022 | ((node = hstate_next_node_to_free(hs, mask)) || 1); \ |
1023 | nr_nodes--) | 1023 | nr_nodes--) |
1024 | 1024 | ||
1025 | #if defined(CONFIG_X86_64) && ((defined(CONFIG_MEMORY_ISOLATION) && defined(CONFIG_COMPACTION)) || defined(CONFIG_CMA)) | 1025 | #if (defined(CONFIG_X86_64) || defined(CONFIG_S390)) && \ |
1026 | ((defined(CONFIG_MEMORY_ISOLATION) && defined(CONFIG_COMPACTION)) || \ | ||
1027 | defined(CONFIG_CMA)) | ||
1026 | static void destroy_compound_gigantic_page(struct page *page, | 1028 | static void destroy_compound_gigantic_page(struct page *page, |
1027 | unsigned int order) | 1029 | unsigned int order) |
1028 | { | 1030 | { |