Skip to content

Commit 8d96250

Browse files
ctmarinasstevecapperlinaro
authored andcommitted
ARM: mm: Transparent huge page support for LPAE systems.
The patch adds support for THP (transparent huge pages) to LPAE systems. When this feature is enabled, the kernel tries to map anonymous pages as 2MB sections where possible. Signed-off-by: Catalin Marinas <[email protected]> [[email protected]: symbolic constants used, value of PMD_SECT_SPLITTING adjusted, tlbflush.h included in pgtable.h, added PROT_NONE support.] Signed-off-by: Steve Capper <[email protected]> Reviewed-by: Will Deacon <[email protected]>
1 parent 1355e2a commit 8d96250

File tree

7 files changed

+78
-1
lines changed

7 files changed

+78
-1
lines changed

arch/arm/Kconfig

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1711,6 +1711,10 @@ config SYS_SUPPORTS_HUGETLBFS
17111711
def_bool y
17121712
depends on ARM_LPAE
17131713

1714+
config HAVE_ARCH_TRANSPARENT_HUGEPAGE
1715+
def_bool y
1716+
depends on ARM_LPAE
1717+
17141718
source "mm/Kconfig"
17151719

17161720
config FORCE_MAX_ZONEORDER

arch/arm/include/asm/pgtable-3level-hwdef.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@
4242
*/
4343
#define PMD_SECT_BUFFERABLE (_AT(pmdval_t, 1) << 2)
4444
#define PMD_SECT_CACHEABLE (_AT(pmdval_t, 1) << 3)
45+
#define PMD_SECT_USER (_AT(pmdval_t, 1) << 6) /* AP[1] */
46+
#define PMD_SECT_RDONLY (_AT(pmdval_t, 1) << 7) /* AP[2] */
4547
#define PMD_SECT_S (_AT(pmdval_t, 3) << 8)
4648
#define PMD_SECT_AF (_AT(pmdval_t, 1) << 10)
4749
#define PMD_SECT_nG (_AT(pmdval_t, 1) << 11)

arch/arm/include/asm/pgtable-3level.h

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,11 @@
8787
#define L_PTE_SPECIAL (_AT(pteval_t, 1) << 56) /* unused */
8888
#define L_PTE_NONE (_AT(pteval_t, 1) << 57) /* PROT_NONE */
8989

90+
#define PMD_SECT_VALID (_AT(pmdval_t, 1) << 0)
91+
#define PMD_SECT_DIRTY (_AT(pmdval_t, 1) << 55)
92+
#define PMD_SECT_SPLITTING (_AT(pmdval_t, 1) << 56)
93+
#define PMD_SECT_NONE (_AT(pmdval_t, 1) << 57)
94+
9095
/*
9196
* To be used in assembly code with the upper page attributes.
9297
*/
@@ -196,6 +201,61 @@ static inline pmd_t *pmd_offset(pud_t *pud, unsigned long addr)
196201
#define pte_huge(pte) (pte_val(pte) && !(pte_val(pte) & PTE_TABLE_BIT))
197202
#define pte_mkhuge(pte) (__pte(pte_val(pte) & ~PTE_TABLE_BIT))
198203

204+
#define pmd_young(pmd) (pmd_val(pmd) & PMD_SECT_AF)
205+
206+
#define __HAVE_ARCH_PMD_WRITE
207+
#define pmd_write(pmd) (!(pmd_val(pmd) & PMD_SECT_RDONLY))
208+
209+
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
210+
#define pmd_trans_huge(pmd) (pmd_val(pmd) && !(pmd_val(pmd) & PMD_TABLE_BIT))
211+
#define pmd_trans_splitting(pmd) (pmd_val(pmd) & PMD_SECT_SPLITTING)
212+
#endif
213+
214+
#define PMD_BIT_FUNC(fn,op) \
215+
static inline pmd_t pmd_##fn(pmd_t pmd) { pmd_val(pmd) op; return pmd; }
216+
217+
PMD_BIT_FUNC(wrprotect, |= PMD_SECT_RDONLY);
218+
PMD_BIT_FUNC(mkold, &= ~PMD_SECT_AF);
219+
PMD_BIT_FUNC(mksplitting, |= PMD_SECT_SPLITTING);
220+
PMD_BIT_FUNC(mkwrite, &= ~PMD_SECT_RDONLY);
221+
PMD_BIT_FUNC(mkdirty, |= PMD_SECT_DIRTY);
222+
PMD_BIT_FUNC(mkyoung, |= PMD_SECT_AF);
223+
224+
#define pmd_mkhuge(pmd) (__pmd(pmd_val(pmd) & ~PMD_TABLE_BIT))
225+
226+
#define pmd_pfn(pmd) (((pmd_val(pmd) & PMD_MASK) & PHYS_MASK) >> PAGE_SHIFT)
227+
#define pfn_pmd(pfn,prot) (__pmd(((phys_addr_t)(pfn) << PAGE_SHIFT) | pgprot_val(prot)))
228+
#define mk_pmd(page,prot) pfn_pmd(page_to_pfn(page),prot)
229+
230+
/* represent a notpresent pmd by zero, this is used by pmdp_invalidate */
231+
#define pmd_mknotpresent(pmd) (__pmd(0))
232+
233+
static inline pmd_t pmd_modify(pmd_t pmd, pgprot_t newprot)
234+
{
235+
const pmdval_t mask = PMD_SECT_USER | PMD_SECT_XN | PMD_SECT_RDONLY |
236+
PMD_SECT_VALID | PMD_SECT_NONE;
237+
pmd_val(pmd) = (pmd_val(pmd) & ~mask) | (pgprot_val(newprot) & mask);
238+
return pmd;
239+
}
240+
241+
static inline void set_pmd_at(struct mm_struct *mm, unsigned long addr,
242+
pmd_t *pmdp, pmd_t pmd)
243+
{
244+
BUG_ON(addr >= TASK_SIZE);
245+
246+
/* create a faulting entry if PROT_NONE protected */
247+
if (pmd_val(pmd) & PMD_SECT_NONE)
248+
pmd_val(pmd) &= ~PMD_SECT_VALID;
249+
250+
*pmdp = __pmd(pmd_val(pmd) | PMD_SECT_nG);
251+
flush_pmd_entry(pmdp);
252+
}
253+
254+
static inline int has_transparent_hugepage(void)
255+
{
256+
return 1;
257+
}
258+
199259
#endif /* __ASSEMBLY__ */
200260

201261
#endif /* _ASM_PGTABLE_3LEVEL_H */

arch/arm/include/asm/pgtable.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@
2424
#include <asm/memory.h>
2525
#include <asm/pgtable-hwdef.h>
2626

27+
28+
#include <asm/tlbflush.h>
29+
2730
#ifdef CONFIG_ARM_LPAE
2831
#include <asm/pgtable-3level.h>
2932
#else

arch/arm/include/asm/tlb.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,12 @@ static inline void __pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmdp,
223223
#endif
224224
}
225225

226+
static inline void
227+
tlb_remove_pmd_tlb_entry(struct mmu_gather *tlb, pmd_t *pmdp, unsigned long addr)
228+
{
229+
tlb_add_flush(tlb, addr);
230+
}
231+
226232
#define pte_free_tlb(tlb, ptep, addr) __pte_free_tlb(tlb, ptep, addr)
227233
#define pmd_free_tlb(tlb, pmdp, addr) __pmd_free_tlb(tlb, pmdp, addr)
228234
#define pud_free_tlb(tlb, pudp, addr) pud_free((tlb)->mm, pudp)

arch/arm/include/asm/tlbflush.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -535,6 +535,8 @@ static inline void update_mmu_cache(struct vm_area_struct *vma,
535535
}
536536
#endif
537537

538+
#define update_mmu_cache_pmd(vma, address, pmd) do { } while (0)
539+
538540
#endif
539541

540542
#endif /* CONFIG_MMU */

arch/arm/mm/fsr-3level.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ static struct fsr_info fsr_info[] = {
99
{ do_page_fault, SIGSEGV, SEGV_MAPERR, "level 3 translation fault" },
1010
{ do_bad, SIGBUS, 0, "reserved access flag fault" },
1111
{ do_bad, SIGSEGV, SEGV_ACCERR, "level 1 access flag fault" },
12-
{ do_bad, SIGSEGV, SEGV_ACCERR, "level 2 access flag fault" },
12+
{ do_page_fault, SIGSEGV, SEGV_ACCERR, "level 2 access flag fault" },
1313
{ do_page_fault, SIGSEGV, SEGV_ACCERR, "level 3 access flag fault" },
1414
{ do_bad, SIGBUS, 0, "reserved permission fault" },
1515
{ do_bad, SIGSEGV, SEGV_ACCERR, "level 1 permission fault" },

0 commit comments

Comments
 (0)