Commit 73636b1aacb1a07e6fbe0d25e560e69b024a8e25

Authored by Chris Metcalf
1 parent 51007004f4

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);