Skip to content

Commit 1355e2a

Browse files
ctmarinasstevecapperlinaro
authored andcommitted
ARM: mm: HugeTLB support for LPAE systems.
This patch adds support for hugetlbfs based on the x86 implementation. It allows mapping of 2MB sections (see Documentation/vm/hugetlbpage.txt for usage). The 64K pages configuration is not supported (section size is 512MB in this case). Signed-off-by: Catalin Marinas <[email protected]> [[email protected]: symbolic constants replace numbers in places. Split up into multiple files, to simplify future non-LPAE support, removed huge_pmd_share code, as this is very rarely executed, Added PROT_NONE support]. Signed-off-by: Steve Capper <[email protected]> Reviewed-by: Will Deacon <[email protected]>
1 parent 0b19f93 commit 1355e2a

File tree

9 files changed

+276
-2
lines changed

9 files changed

+276
-2
lines changed

arch/arm/Kconfig

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1707,6 +1707,10 @@ config HW_PERF_EVENTS
17071707
Enable hardware performance counter support for perf events. If
17081708
disabled, perf events will use software events only.
17091709

1710+
config SYS_SUPPORTS_HUGETLBFS
1711+
def_bool y
1712+
depends on ARM_LPAE
1713+
17101714
source "mm/Kconfig"
17111715

17121716
config FORCE_MAX_ZONEORDER

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

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/*
2+
* arch/arm/include/asm/hugetlb-3level.h
3+
*
4+
* Copyright (C) 2012 ARM Ltd.
5+
*
6+
* Based on arch/x86/include/asm/hugetlb.h.
7+
*
8+
* This program is free software; you can redistribute it and/or modify
9+
* it under the terms of the GNU General Public License version 2 as
10+
* published by the Free Software Foundation.
11+
*
12+
* This program is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU General Public License
18+
* along with this program; if not, write to the Free Software
19+
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20+
*/
21+
22+
#ifndef _ASM_ARM_HUGETLB_3LEVEL_H
23+
#define _ASM_ARM_HUGETLB_3LEVEL_H
24+
25+
26+
/*
27+
* If our huge pte is non-zero then mark the valid bit.
28+
* This allows pte_present(huge_ptep_get(ptep)) to return true for non-zero
29+
* ptes.
30+
* (The valid bit is automatically cleared by set_pte_at for PROT_NONE ptes).
31+
*/
32+
static inline pte_t huge_ptep_get(pte_t *ptep)
33+
{
34+
pte_t retval = *ptep;
35+
if (pte_val(retval))
36+
pte_val(retval) |= L_PTE_VALID;
37+
return retval;
38+
}
39+
40+
static inline void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
41+
pte_t *ptep, pte_t pte)
42+
{
43+
set_pte_at(mm, addr, ptep, pte);
44+
}
45+
46+
static inline void huge_ptep_clear_flush(struct vm_area_struct *vma,
47+
unsigned long addr, pte_t *ptep)
48+
{
49+
ptep_clear_flush(vma, addr, ptep);
50+
}
51+
52+
static inline void huge_ptep_set_wrprotect(struct mm_struct *mm,
53+
unsigned long addr, pte_t *ptep)
54+
{
55+
ptep_set_wrprotect(mm, addr, ptep);
56+
}
57+
58+
static inline pte_t huge_ptep_get_and_clear(struct mm_struct *mm,
59+
unsigned long addr, pte_t *ptep)
60+
{
61+
return ptep_get_and_clear(mm, addr, ptep);
62+
}
63+
64+
static inline int huge_ptep_set_access_flags(struct vm_area_struct *vma,
65+
unsigned long addr, pte_t *ptep,
66+
pte_t pte, int dirty)
67+
{
68+
return ptep_set_access_flags(vma, addr, ptep, pte, dirty);
69+
}
70+
71+
#endif /* _ASM_ARM_HUGETLB_3LEVEL_H */

arch/arm/include/asm/hugetlb.h

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
/*
2+
* arch/arm/include/asm/hugetlb.h
3+
*
4+
* Copyright (C) 2012 ARM Ltd.
5+
*
6+
* Based on arch/x86/include/asm/hugetlb.h
7+
*
8+
* This program is free software; you can redistribute it and/or modify
9+
* it under the terms of the GNU General Public License version 2 as
10+
* published by the Free Software Foundation.
11+
*
12+
* This program is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU General Public License
18+
* along with this program; if not, write to the Free Software
19+
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20+
*/
21+
22+
#ifndef _ASM_ARM_HUGETLB_H
23+
#define _ASM_ARM_HUGETLB_H
24+
25+
#include <asm/page.h>
26+
#include <asm-generic/hugetlb.h>
27+
28+
#include <asm/hugetlb-3level.h>
29+
30+
static inline void hugetlb_free_pgd_range(struct mmu_gather *tlb,
31+
unsigned long addr, unsigned long end,
32+
unsigned long floor,
33+
unsigned long ceiling)
34+
{
35+
free_pgd_range(tlb, addr, end, floor, ceiling);
36+
}
37+
38+
39+
static inline int is_hugepage_only_range(struct mm_struct *mm,
40+
unsigned long addr, unsigned long len)
41+
{
42+
return 0;
43+
}
44+
45+
static inline int prepare_hugepage_range(struct file *file,
46+
unsigned long addr, unsigned long len)
47+
{
48+
struct hstate *h = hstate_file(file);
49+
if (len & ~huge_page_mask(h))
50+
return -EINVAL;
51+
if (addr & ~huge_page_mask(h))
52+
return -EINVAL;
53+
return 0;
54+
}
55+
56+
static inline void hugetlb_prefault_arch_hook(struct mm_struct *mm)
57+
{
58+
}
59+
60+
static inline int huge_pte_none(pte_t pte)
61+
{
62+
return pte_none(pte);
63+
}
64+
65+
static inline pte_t huge_pte_wrprotect(pte_t pte)
66+
{
67+
return pte_wrprotect(pte);
68+
}
69+
70+
static inline int arch_prepare_hugepage(struct page *page)
71+
{
72+
return 0;
73+
}
74+
75+
static inline void arch_release_hugepage(struct page *page)
76+
{
77+
}
78+
79+
static inline void arch_clear_hugepage_flags(struct page *page)
80+
{
81+
clear_bit(PG_dcache_clean, &page->flags);
82+
}
83+
84+
#endif /* _ASM_ARM_HUGETLB_H */

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#define PMD_TYPE_FAULT (_AT(pmdval_t, 0) << 0)
3131
#define PMD_TYPE_TABLE (_AT(pmdval_t, 3) << 0)
3232
#define PMD_TYPE_SECT (_AT(pmdval_t, 1) << 0)
33+
#define PMD_TABLE_BIT (_AT(pmdval_t, 1) << 1)
3334
#define PMD_BIT4 (_AT(pmdval_t, 0))
3435
#define PMD_DOMAIN(x) (_AT(pmdval_t, 0))
3536
#define PMD_APTABLE_SHIFT (61)
@@ -66,6 +67,7 @@
6667
#define PTE_TYPE_MASK (_AT(pteval_t, 3) << 0)
6768
#define PTE_TYPE_FAULT (_AT(pteval_t, 0) << 0)
6869
#define PTE_TYPE_PAGE (_AT(pteval_t, 3) << 0)
70+
#define PTE_TABLE_BIT (_AT(pteval_t, 1) << 1)
6971
#define PTE_BUFFERABLE (_AT(pteval_t, 1) << 2) /* AttrIndx[0] */
7072
#define PTE_CACHEABLE (_AT(pteval_t, 1) << 3) /* AttrIndx[1] */
7173
#define PTE_EXT_SHARED (_AT(pteval_t, 3) << 8) /* SH[1:0], inner shareable */

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,14 @@
6161

6262
#define USER_PTRS_PER_PGD (PAGE_OFFSET / PGDIR_SIZE)
6363

64+
/*
65+
* Hugetlb definitions.
66+
*/
67+
#define HPAGE_SHIFT PMD_SHIFT
68+
#define HPAGE_SIZE (_AC(1, UL) << HPAGE_SHIFT)
69+
#define HPAGE_MASK (~(HPAGE_SIZE - 1))
70+
#define HUGETLB_PAGE_ORDER (HPAGE_SHIFT - PAGE_SHIFT)
71+
6472
/*
6573
* "Linux" PTE definitions for LPAE.
6674
*
@@ -185,6 +193,9 @@ static inline pmd_t *pmd_offset(pud_t *pud, unsigned long addr)
185193

186194
#define set_pte_ext(ptep,pte,ext) cpu_set_pte_ext(ptep,__pte(pte_val(pte)|(ext)))
187195

196+
#define pte_huge(pte) (pte_val(pte) && !(pte_val(pte) & PTE_TABLE_BIT))
197+
#define pte_mkhuge(pte) (__pte(pte_val(pte) & ~PTE_TABLE_BIT))
198+
188199
#endif /* __ASSEMBLY__ */
189200

190201
#endif /* _ASM_PGTABLE_3LEVEL_H */

arch/arm/mm/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ obj-$(CONFIG_MODULES) += proc-syms.o
1616

1717
obj-$(CONFIG_ALIGNMENT_TRAP) += alignment.o
1818
obj-$(CONFIG_HIGHMEM) += highmem.o
19+
obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o
1920

2021
obj-$(CONFIG_CPU_ABRT_NOMMU) += abort-nommu.o
2122
obj-$(CONFIG_CPU_ABRT_EV4) += abort-ev4.o

arch/arm/mm/dma-mapping.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,7 @@ static void __dma_free_buffer(struct page *page, size_t size)
250250

251251
#ifdef CONFIG_MMU
252252
#ifdef CONFIG_HUGETLB_PAGE
253-
#error ARM Coherent DMA allocator does not (yet) support huge TLB
253+
#warning ARM Coherent DMA allocator does not (yet) support huge TLB
254254
#endif
255255

256256
static void *__alloc_from_contiguous(struct device *dev, size_t size,

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ static struct fsr_info fsr_info[] = {
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" },
16-
{ do_sect_fault, SIGSEGV, SEGV_ACCERR, "level 2 permission fault" },
16+
{ do_page_fault, SIGSEGV, SEGV_ACCERR, "level 2 permission fault" },
1717
{ do_page_fault, SIGSEGV, SEGV_ACCERR, "level 3 permission fault" },
1818
{ do_bad, SIGBUS, 0, "synchronous external abort" },
1919
{ do_bad, SIGBUS, 0, "asynchronous external abort" },

arch/arm/mm/hugetlbpage.c

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
/*
2+
* arch/arm/mm/hugetlbpage.c
3+
*
4+
* Copyright (C) 2012 ARM Ltd.
5+
*
6+
* Based on arch/x86/include/asm/hugetlb.h and Bill Carson's patches
7+
*
8+
* This program is free software; you can redistribute it and/or modify
9+
* it under the terms of the GNU General Public License version 2 as
10+
* published by the Free Software Foundation.
11+
*
12+
* This program is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU General Public License
18+
* along with this program; if not, write to the Free Software
19+
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20+
*/
21+
22+
#include <linux/init.h>
23+
#include <linux/fs.h>
24+
#include <linux/mm.h>
25+
#include <linux/hugetlb.h>
26+
#include <linux/pagemap.h>
27+
#include <linux/err.h>
28+
#include <linux/sysctl.h>
29+
#include <asm/mman.h>
30+
#include <asm/tlb.h>
31+
#include <asm/tlbflush.h>
32+
#include <asm/pgalloc.h>
33+
34+
/*
35+
* On ARM, huge pages are backed by pmd's rather than pte's, so we do a lot
36+
* of type casting from pmd_t * to pte_t *.
37+
*/
38+
39+
pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr)
40+
{
41+
pgd_t *pgd;
42+
pud_t *pud;
43+
pmd_t *pmd = NULL;
44+
45+
pgd = pgd_offset(mm, addr);
46+
if (pgd_present(*pgd)) {
47+
pud = pud_offset(pgd, addr);
48+
if (pud_present(*pud))
49+
pmd = pmd_offset(pud, addr);
50+
}
51+
52+
return (pte_t *)pmd;
53+
}
54+
55+
struct page *follow_huge_addr(struct mm_struct *mm, unsigned long address,
56+
int write)
57+
{
58+
return ERR_PTR(-EINVAL);
59+
}
60+
61+
int pud_huge(pud_t pud)
62+
{
63+
return 0;
64+
}
65+
66+
int huge_pmd_unshare(struct mm_struct *mm, unsigned long *addr, pte_t *ptep)
67+
{
68+
return 0;
69+
}
70+
71+
pte_t *huge_pte_alloc(struct mm_struct *mm,
72+
unsigned long addr, unsigned long sz)
73+
{
74+
pgd_t *pgd;
75+
pud_t *pud;
76+
pte_t *pte = NULL;
77+
78+
pgd = pgd_offset(mm, addr);
79+
pud = pud_alloc(mm, pgd, addr);
80+
if (pud)
81+
pte = (pte_t *)pmd_alloc(mm, pud, addr);
82+
83+
return pte;
84+
}
85+
86+
struct page *
87+
follow_huge_pmd(struct mm_struct *mm, unsigned long address,
88+
pmd_t *pmd, int write)
89+
{
90+
struct page *page;
91+
92+
page = pte_page(*(pte_t *)pmd);
93+
if (page)
94+
page += ((address & ~PMD_MASK) >> PAGE_SHIFT);
95+
return page;
96+
}
97+
98+
int pmd_huge(pmd_t pmd)
99+
{
100+
return pmd_val(pmd) && !(pmd_val(pmd) & PMD_TABLE_BIT);
101+
}

0 commit comments

Comments
 (0)