Commit 73636b1aacb1a07e6fbe0d25e560e69b024a8e25
1 parent
51007004f4
Exists in
master
and in
20 other branches
arch/tile: allow building Linux with transparent huge pages enabled
The change adds some infrastructure for managing tile pmd's more generally, using pte_pmd() and pmd_pte() methods to translate pmd values to and from ptes, since on TILEPro a pmd is really just a nested structure holding a pgd (aka pte). Several existing pmd methods are moved into this framework, and a whole raft of additional pmd accessors are defined that are used by the transparent hugepage framework. The tile PTE now has a "client2" bit. The bit is used to indicate a transparent huge page is in the process of being split into subpages. This change also fixes a generic bug where the return value of the generic pmdp_splitting_flush() was incorrect. Signed-off-by: Chris Metcalf <cmetcalf@tilera.com>
Showing 6 changed files with 111 additions and 53 deletions Side-by-side Diff
arch/tile/include/asm/pgtable.h
... | ... | @@ -187,6 +187,7 @@ |
187 | 187 | * Undefined behaviour if not.. |
188 | 188 | */ |
189 | 189 | #define pte_present hv_pte_get_present |
190 | +#define pte_mknotpresent hv_pte_clear_present | |
190 | 191 | #define pte_user hv_pte_get_user |
191 | 192 | #define pte_read hv_pte_get_readable |
192 | 193 | #define pte_dirty hv_pte_get_dirty |
... | ... | @@ -312,7 +313,7 @@ |
312 | 313 | */ |
313 | 314 | static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) |
314 | 315 | { |
315 | - return pfn_pte(hv_pte_get_pfn(pte), newprot); | |
316 | + return pfn_pte(pte_pfn(pte), newprot); | |
316 | 317 | } |
317 | 318 | |
318 | 319 | /* |
... | ... | @@ -410,6 +411,46 @@ |
410 | 411 | return (address >> PMD_SHIFT) & (PTRS_PER_PMD - 1); |
411 | 412 | } |
412 | 413 | |
414 | +#define __HAVE_ARCH_PMDP_TEST_AND_CLEAR_YOUNG | |
415 | +static inline int pmdp_test_and_clear_young(struct vm_area_struct *vma, | |
416 | + unsigned long address, | |
417 | + pmd_t *pmdp) | |
418 | +{ | |
419 | + return ptep_test_and_clear_young(vma, address, pmdp_ptep(pmdp)); | |
420 | +} | |
421 | + | |
422 | +#define __HAVE_ARCH_PMDP_SET_WRPROTECT | |
423 | +static inline void pmdp_set_wrprotect(struct mm_struct *mm, | |
424 | + unsigned long address, pmd_t *pmdp) | |
425 | +{ | |
426 | + ptep_set_wrprotect(mm, address, pmdp_ptep(pmdp)); | |
427 | +} | |
428 | + | |
429 | + | |
430 | +#define __HAVE_ARCH_PMDP_GET_AND_CLEAR | |
431 | +static inline pmd_t pmdp_get_and_clear(struct mm_struct *mm, | |
432 | + unsigned long address, | |
433 | + pmd_t *pmdp) | |
434 | +{ | |
435 | + return pte_pmd(ptep_get_and_clear(mm, address, pmdp_ptep(pmdp))); | |
436 | +} | |
437 | + | |
438 | +static inline void __set_pmd(pmd_t *pmdp, pmd_t pmdval) | |
439 | +{ | |
440 | + set_pte(pmdp_ptep(pmdp), pmd_pte(pmdval)); | |
441 | +} | |
442 | + | |
443 | +#define set_pmd_at(mm, addr, pmdp, pmdval) __set_pmd(pmdp, pmdval) | |
444 | + | |
445 | +/* Create a pmd from a PTFN. */ | |
446 | +static inline pmd_t ptfn_pmd(unsigned long ptfn, pgprot_t prot) | |
447 | +{ | |
448 | + return pte_pmd(hv_pte_set_ptfn(prot, ptfn)); | |
449 | +} | |
450 | + | |
451 | +/* Return the page-table frame number (ptfn) that a pmd_t points at. */ | |
452 | +#define pmd_ptfn(pmd) hv_pte_get_ptfn(pmd_pte(pmd)) | |
453 | + | |
413 | 454 | /* |
414 | 455 | * A given kernel pmd_t maps to a specific virtual address (either a |
415 | 456 | * kernel huge page or a kernel pte_t table). Since kernel pte_t |
... | ... | @@ -432,6 +473,47 @@ |
432 | 473 | */ |
433 | 474 | #define pmd_page(pmd) pfn_to_page(HV_PTFN_TO_PFN(pmd_ptfn(pmd))) |
434 | 475 | |
476 | +static inline void pmd_clear(pmd_t *pmdp) | |
477 | +{ | |
478 | + __pte_clear(pmdp_ptep(pmdp)); | |
479 | +} | |
480 | + | |
481 | +#define pmd_mknotpresent(pmd) pte_pmd(pte_mknotpresent(pmd_pte(pmd))) | |
482 | +#define pmd_young(pmd) pte_young(pmd_pte(pmd)) | |
483 | +#define pmd_mkyoung(pmd) pte_pmd(pte_mkyoung(pmd_pte(pmd))) | |
484 | +#define pmd_mkold(pmd) pte_pmd(pte_mkold(pmd_pte(pmd))) | |
485 | +#define pmd_mkwrite(pmd) pte_pmd(pte_mkwrite(pmd_pte(pmd))) | |
486 | +#define pmd_write(pmd) pte_write(pmd_pte(pmd)) | |
487 | +#define pmd_wrprotect(pmd) pte_pmd(pte_wrprotect(pmd_pte(pmd))) | |
488 | +#define pmd_mkdirty(pmd) pte_pmd(pte_mkdirty(pmd_pte(pmd))) | |
489 | +#define pmd_huge_page(pmd) pte_huge(pmd_pte(pmd)) | |
490 | +#define pmd_mkhuge(pmd) pte_pmd(pte_mkhuge(pmd_pte(pmd))) | |
491 | +#define __HAVE_ARCH_PMD_WRITE | |
492 | + | |
493 | +#define pfn_pmd(pfn, pgprot) pte_pmd(pfn_pte((pfn), (pgprot))) | |
494 | +#define pmd_pfn(pmd) pte_pfn(pmd_pte(pmd)) | |
495 | +#define mk_pmd(page, pgprot) pfn_pmd(page_to_pfn(page), (pgprot)) | |
496 | + | |
497 | +static inline pmd_t pmd_modify(pmd_t pmd, pgprot_t newprot) | |
498 | +{ | |
499 | + return pfn_pmd(pmd_pfn(pmd), newprot); | |
500 | +} | |
501 | + | |
502 | +#ifdef CONFIG_TRANSPARENT_HUGEPAGE | |
503 | +#define has_transparent_hugepage() 1 | |
504 | +#define pmd_trans_huge pmd_huge_page | |
505 | + | |
506 | +static inline pmd_t pmd_mksplitting(pmd_t pmd) | |
507 | +{ | |
508 | + return pte_pmd(hv_pte_set_client2(pmd_pte(pmd))); | |
509 | +} | |
510 | + | |
511 | +static inline int pmd_trans_splitting(pmd_t pmd) | |
512 | +{ | |
513 | + return hv_pte_get_client2(pmd_pte(pmd)); | |
514 | +} | |
515 | +#endif /* CONFIG_TRANSPARENT_HUGEPAGE */ | |
516 | + | |
435 | 517 | /* |
436 | 518 | * The pte page can be thought of an array like this: pte_t[PTRS_PER_PTE] |
437 | 519 | * |
... | ... | @@ -446,11 +528,6 @@ |
446 | 528 | static inline pte_t *pte_offset_kernel(pmd_t *pmd, unsigned long address) |
447 | 529 | { |
448 | 530 | return (pte_t *)pmd_page_vaddr(*pmd) + pte_index(address); |
449 | -} | |
450 | - | |
451 | -static inline int pmd_huge_page(pmd_t pmd) | |
452 | -{ | |
453 | - return pmd_val(pmd) & _PAGE_HUGE_PAGE; | |
454 | 531 | } |
455 | 532 | |
456 | 533 | #include <asm-generic/pgtable.h> |
arch/tile/include/asm/pgtable_32.h
... | ... | @@ -111,24 +111,14 @@ |
111 | 111 | return pte; |
112 | 112 | } |
113 | 113 | |
114 | -static inline void __set_pmd(pmd_t *pmdp, pmd_t pmdval) | |
115 | -{ | |
116 | - set_pte(&pmdp->pud.pgd, pmdval.pud.pgd); | |
117 | -} | |
118 | - | |
119 | -/* Create a pmd from a PTFN. */ | |
120 | -static inline pmd_t ptfn_pmd(unsigned long ptfn, pgprot_t prot) | |
121 | -{ | |
122 | - return (pmd_t){ { hv_pte_set_ptfn(prot, ptfn) } }; | |
123 | -} | |
124 | - | |
125 | -/* Return the page-table frame number (ptfn) that a pmd_t points at. */ | |
126 | -#define pmd_ptfn(pmd) hv_pte_get_ptfn((pmd).pud.pgd) | |
127 | - | |
128 | -static inline void pmd_clear(pmd_t *pmdp) | |
129 | -{ | |
130 | - __pte_clear(&pmdp->pud.pgd); | |
131 | -} | |
114 | +/* | |
115 | + * pmds are wrappers around pgds, which are the same as ptes. | |
116 | + * It's often convenient to "cast" back and forth and use the pte methods, | |
117 | + * which are the methods supplied by the hypervisor. | |
118 | + */ | |
119 | +#define pmd_pte(pmd) ((pmd).pud.pgd) | |
120 | +#define pmdp_ptep(pmdp) (&(pmdp)->pud.pgd) | |
121 | +#define pte_pmd(pte) ((pmd_t){ { (pte) } }) | |
132 | 122 | |
133 | 123 | #endif /* __ASSEMBLY__ */ |
134 | 124 |
arch/tile/include/asm/pgtable_64.h
... | ... | @@ -108,28 +108,6 @@ |
108 | 108 | #define pmd_offset(pud, address) \ |
109 | 109 | ((pmd_t *)pud_page_vaddr(*(pud)) + pmd_index(address)) |
110 | 110 | |
111 | -static inline void __set_pmd(pmd_t *pmdp, pmd_t pmdval) | |
112 | -{ | |
113 | - set_pte(pmdp, pmdval); | |
114 | -} | |
115 | - | |
116 | -/* Create a pmd from a PTFN and pgprot. */ | |
117 | -static inline pmd_t ptfn_pmd(unsigned long ptfn, pgprot_t prot) | |
118 | -{ | |
119 | - return hv_pte_set_ptfn(prot, ptfn); | |
120 | -} | |
121 | - | |
122 | -/* Return the page-table frame number (ptfn) that a pmd_t points at. */ | |
123 | -static inline unsigned long pmd_ptfn(pmd_t pmd) | |
124 | -{ | |
125 | - return hv_pte_get_ptfn(pmd); | |
126 | -} | |
127 | - | |
128 | -static inline void pmd_clear(pmd_t *pmdp) | |
129 | -{ | |
130 | - __pte_clear(pmdp); | |
131 | -} | |
132 | - | |
133 | 111 | /* Normalize an address to having the correct high bits set. */ |
134 | 112 | #define pgd_addr_normalize pgd_addr_normalize |
135 | 113 | static inline unsigned long pgd_addr_normalize(unsigned long addr) |
... | ... | @@ -169,6 +147,13 @@ |
169 | 147 | { |
170 | 148 | return hv_pte(__insn_exch(&ptep->val, 0UL)); |
171 | 149 | } |
150 | + | |
151 | +/* | |
152 | + * pmds are the same as pgds and ptes, so converting is a no-op. | |
153 | + */ | |
154 | +#define pmd_pte(pmd) (pmd) | |
155 | +#define pmdp_ptep(pmdp) (pmdp) | |
156 | +#define pte_pmd(pte) (pte) | |
172 | 157 | |
173 | 158 | #endif /* __ASSEMBLY__ */ |
174 | 159 |
arch/tile/include/hv/hypervisor.h
... | ... | @@ -1855,8 +1855,7 @@ |
1855 | 1855 | future use. */ |
1856 | 1856 | #define HV_PTE_INDEX_MODE 16 /**< Page mode; see HV_PTE_MODE_xxx */ |
1857 | 1857 | #define HV_PTE_MODE_BITS 3 /**< Number of bits in mode */ |
1858 | - /* Bit 19 is reserved for | |
1859 | - future use. */ | |
1858 | +#define HV_PTE_INDEX_CLIENT2 19 /**< Page client state 2 */ | |
1860 | 1859 | #define HV_PTE_INDEX_LOTAR 20 /**< Page's LOTAR; must be high bits |
1861 | 1860 | of word */ |
1862 | 1861 | #define HV_PTE_LOTAR_BITS 12 /**< Number of bits in a LOTAR */ |
... | ... | @@ -2046,6 +2045,13 @@ |
2046 | 2045 | */ |
2047 | 2046 | #define HV_PTE_CLIENT1 (__HV_PTE_ONE << HV_PTE_INDEX_CLIENT1) |
2048 | 2047 | |
2048 | +/** Client-private bit in PTE. | |
2049 | + * | |
2050 | + * This bit is guaranteed not to be inspected or modified by the | |
2051 | + * hypervisor. | |
2052 | + */ | |
2053 | +#define HV_PTE_CLIENT2 (__HV_PTE_ONE << HV_PTE_INDEX_CLIENT2) | |
2054 | + | |
2049 | 2055 | /** Non-coherent (NC) bit in PTE. |
2050 | 2056 | * |
2051 | 2057 | * If this bit is set, the mapping that is set up will be non-coherent |
... | ... | @@ -2180,6 +2186,7 @@ |
2180 | 2186 | _HV_BIT(page, PAGE) |
2181 | 2187 | _HV_BIT(client0, CLIENT0) |
2182 | 2188 | _HV_BIT(client1, CLIENT1) |
2189 | +_HV_BIT(client2, CLIENT2) | |
2183 | 2190 | _HV_BIT(migrating, MIGRATING) |
2184 | 2191 | _HV_BIT(nc, NC) |
2185 | 2192 | _HV_BIT(readable, READABLE) |
include/asm-generic/pgtable.h
... | ... | @@ -158,9 +158,8 @@ |
158 | 158 | #endif |
159 | 159 | |
160 | 160 | #ifndef __HAVE_ARCH_PMDP_SPLITTING_FLUSH |
161 | -extern pmd_t pmdp_splitting_flush(struct vm_area_struct *vma, | |
162 | - unsigned long address, | |
163 | - pmd_t *pmdp); | |
161 | +extern void pmdp_splitting_flush(struct vm_area_struct *vma, | |
162 | + unsigned long address, pmd_t *pmdp); | |
164 | 163 | #endif |
165 | 164 | |
166 | 165 | #ifndef __HAVE_ARCH_PTE_SAME |
mm/pgtable-generic.c
... | ... | @@ -109,8 +109,8 @@ |
109 | 109 | |
110 | 110 | #ifndef __HAVE_ARCH_PMDP_SPLITTING_FLUSH |
111 | 111 | #ifdef CONFIG_TRANSPARENT_HUGEPAGE |
112 | -pmd_t pmdp_splitting_flush(struct vm_area_struct *vma, unsigned long address, | |
113 | - pmd_t *pmdp) | |
112 | +void pmdp_splitting_flush(struct vm_area_struct *vma, unsigned long address, | |
113 | + pmd_t *pmdp) | |
114 | 114 | { |
115 | 115 | pmd_t pmd = pmd_mksplitting(*pmdp); |
116 | 116 | VM_BUG_ON(address & ~HPAGE_PMD_MASK); |