Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+111 -53
+83 -6
arch/tile/include/asm/pgtable.h
··· 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 ··· 313 312 */ 314 313 static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) 315 314 { 316 - return pfn_pte(hv_pte_get_pfn(pte), newprot); 315 + return pfn_pte(pte_pfn(pte), newprot); 317 316 } 318 317 319 318 /* ··· 411 410 return (address >> PMD_SHIFT) & (PTRS_PER_PMD - 1); 412 411 } 413 412 413 + #define __HAVE_ARCH_PMDP_TEST_AND_CLEAR_YOUNG 414 + static inline int pmdp_test_and_clear_young(struct vm_area_struct *vma, 415 + unsigned long address, 416 + pmd_t *pmdp) 417 + { 418 + return ptep_test_and_clear_young(vma, address, pmdp_ptep(pmdp)); 419 + } 420 + 421 + #define __HAVE_ARCH_PMDP_SET_WRPROTECT 422 + static inline void pmdp_set_wrprotect(struct mm_struct *mm, 423 + unsigned long address, pmd_t *pmdp) 424 + { 425 + ptep_set_wrprotect(mm, address, pmdp_ptep(pmdp)); 426 + } 427 + 428 + 429 + #define __HAVE_ARCH_PMDP_GET_AND_CLEAR 430 + static inline pmd_t pmdp_get_and_clear(struct mm_struct *mm, 431 + unsigned long address, 432 + pmd_t *pmdp) 433 + { 434 + return pte_pmd(ptep_get_and_clear(mm, address, pmdp_ptep(pmdp))); 435 + } 436 + 437 + static inline void __set_pmd(pmd_t *pmdp, pmd_t pmdval) 438 + { 439 + set_pte(pmdp_ptep(pmdp), pmd_pte(pmdval)); 440 + } 441 + 442 + #define set_pmd_at(mm, addr, pmdp, pmdval) __set_pmd(pmdp, pmdval) 443 + 444 + /* Create a pmd from a PTFN. */ 445 + static inline pmd_t ptfn_pmd(unsigned long ptfn, pgprot_t prot) 446 + { 447 + return pte_pmd(hv_pte_set_ptfn(prot, ptfn)); 448 + } 449 + 450 + /* Return the page-table frame number (ptfn) that a pmd_t points at. */ 451 + #define pmd_ptfn(pmd) hv_pte_get_ptfn(pmd_pte(pmd)) 452 + 414 453 /* 415 454 * A given kernel pmd_t maps to a specific virtual address (either a 416 455 * kernel huge page or a kernel pte_t table). Since kernel pte_t ··· 473 432 */ 474 433 #define pmd_page(pmd) pfn_to_page(HV_PTFN_TO_PFN(pmd_ptfn(pmd))) 475 434 435 + static inline void pmd_clear(pmd_t *pmdp) 436 + { 437 + __pte_clear(pmdp_ptep(pmdp)); 438 + } 439 + 440 + #define pmd_mknotpresent(pmd) pte_pmd(pte_mknotpresent(pmd_pte(pmd))) 441 + #define pmd_young(pmd) pte_young(pmd_pte(pmd)) 442 + #define pmd_mkyoung(pmd) pte_pmd(pte_mkyoung(pmd_pte(pmd))) 443 + #define pmd_mkold(pmd) pte_pmd(pte_mkold(pmd_pte(pmd))) 444 + #define pmd_mkwrite(pmd) pte_pmd(pte_mkwrite(pmd_pte(pmd))) 445 + #define pmd_write(pmd) pte_write(pmd_pte(pmd)) 446 + #define pmd_wrprotect(pmd) pte_pmd(pte_wrprotect(pmd_pte(pmd))) 447 + #define pmd_mkdirty(pmd) pte_pmd(pte_mkdirty(pmd_pte(pmd))) 448 + #define pmd_huge_page(pmd) pte_huge(pmd_pte(pmd)) 449 + #define pmd_mkhuge(pmd) pte_pmd(pte_mkhuge(pmd_pte(pmd))) 450 + #define __HAVE_ARCH_PMD_WRITE 451 + 452 + #define pfn_pmd(pfn, pgprot) pte_pmd(pfn_pte((pfn), (pgprot))) 453 + #define pmd_pfn(pmd) pte_pfn(pmd_pte(pmd)) 454 + #define mk_pmd(page, pgprot) pfn_pmd(page_to_pfn(page), (pgprot)) 455 + 456 + static inline pmd_t pmd_modify(pmd_t pmd, pgprot_t newprot) 457 + { 458 + return pfn_pmd(pmd_pfn(pmd), newprot); 459 + } 460 + 461 + #ifdef CONFIG_TRANSPARENT_HUGEPAGE 462 + #define has_transparent_hugepage() 1 463 + #define pmd_trans_huge pmd_huge_page 464 + 465 + static inline pmd_t pmd_mksplitting(pmd_t pmd) 466 + { 467 + return pte_pmd(hv_pte_set_client2(pmd_pte(pmd))); 468 + } 469 + 470 + static inline int pmd_trans_splitting(pmd_t pmd) 471 + { 472 + return hv_pte_get_client2(pmd_pte(pmd)); 473 + } 474 + #endif /* CONFIG_TRANSPARENT_HUGEPAGE */ 475 + 476 476 /* 477 477 * The pte page can be thought of an array like this: pte_t[PTRS_PER_PTE] 478 478 * ··· 528 446 static inline pte_t *pte_offset_kernel(pmd_t *pmd, unsigned long address) 529 447 { 530 448 return (pte_t *)pmd_page_vaddr(*pmd) + pte_index(address); 531 - } 532 - 533 - static inline int pmd_huge_page(pmd_t pmd) 534 - { 535 - return pmd_val(pmd) & _PAGE_HUGE_PAGE; 536 449 } 537 450 538 451 #include <asm-generic/pgtable.h>
+8 -18
arch/tile/include/asm/pgtable_32.h
··· 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
+7 -22
arch/tile/include/asm/pgtable_64.h
··· 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) ··· 147 169 { 148 170 return hv_pte(__insn_exch(&ptep->val, 0UL)); 149 171 } 172 + 173 + /* 174 + * pmds are the same as pgds and ptes, so converting is a no-op. 175 + */ 176 + #define pmd_pte(pmd) (pmd) 177 + #define pmdp_ptep(pmdp) (pmdp) 178 + #define pte_pmd(pte) (pte) 150 179 151 180 #endif /* __ASSEMBLY__ */ 152 181
+9 -2
arch/tile/include/hv/hypervisor.h
··· 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 */ ··· 2045 2046 */ 2046 2047 #define HV_PTE_CLIENT1 (__HV_PTE_ONE << HV_PTE_INDEX_CLIENT1) 2047 2048 2049 + /** Client-private bit in PTE. 2050 + * 2051 + * This bit is guaranteed not to be inspected or modified by the 2052 + * hypervisor. 2053 + */ 2054 + #define HV_PTE_CLIENT2 (__HV_PTE_ONE << HV_PTE_INDEX_CLIENT2) 2055 + 2048 2056 /** Non-coherent (NC) bit in PTE. 2049 2057 * 2050 2058 * If this bit is set, the mapping that is set up will be non-coherent ··· 2186 2180 _HV_BIT(page, PAGE) 2187 2181 _HV_BIT(client0, CLIENT0) 2188 2182 _HV_BIT(client1, CLIENT1) 2183 + _HV_BIT(client2, CLIENT2) 2189 2184 _HV_BIT(migrating, MIGRATING) 2190 2185 _HV_BIT(nc, NC) 2191 2186 _HV_BIT(readable, READABLE)
+2 -3
include/asm-generic/pgtable.h
··· 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
+2 -2
mm/pgtable-generic.c
··· 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);