Skip to content

Commit 084bd29

Browse files
ARM64: mm: HugeTLB support.
Add huge page support to ARM64, different huge page sizes are supported depending on the size of normal pages: PAGE_SIZE is 4KB: 2MB - (pmds) these can be allocated at any time. 1024MB - (puds) usually allocated on bootup with the command line with something like: hugepagesz=1G hugepages=6 PAGE_SIZE is 64KB: 512MB - (pmds) usually allocated on bootup via command line. Signed-off-by: Steve Capper <[email protected]> Acked-by: Catalin Marinas <[email protected]>
1 parent 59911ca commit 084bd29

File tree

7 files changed

+220
-17
lines changed

7 files changed

+220
-17
lines changed

arch/arm64/Kconfig

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,15 @@ config HW_PERF_EVENTS
180180
Enable hardware performance counter support for perf events. If
181181
disabled, perf events will use software events only.
182182

183+
config SYS_SUPPORTS_HUGETLBFS
184+
def_bool y
185+
186+
config ARCH_WANT_GENERAL_HUGETLB
187+
def_bool y
188+
189+
config ARCH_WANT_HUGE_PMD_SHARE
190+
def_bool y if !ARM64_64K_PAGES
191+
183192
source "mm/Kconfig"
184193

185194
endmenu

arch/arm64/include/asm/hugetlb.h

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
/*
2+
* arch/arm64/include/asm/hugetlb.h
3+
*
4+
* Copyright (C) 2013 Linaro 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_HUGETLB_H
23+
#define __ASM_HUGETLB_H
24+
25+
#include <asm-generic/hugetlb.h>
26+
#include <asm/page.h>
27+
28+
static inline pte_t huge_ptep_get(pte_t *ptep)
29+
{
30+
return *ptep;
31+
}
32+
33+
static inline void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
34+
pte_t *ptep, pte_t pte)
35+
{
36+
set_pte_at(mm, addr, ptep, pte);
37+
}
38+
39+
static inline void huge_ptep_clear_flush(struct vm_area_struct *vma,
40+
unsigned long addr, pte_t *ptep)
41+
{
42+
ptep_clear_flush(vma, addr, ptep);
43+
}
44+
45+
static inline void huge_ptep_set_wrprotect(struct mm_struct *mm,
46+
unsigned long addr, pte_t *ptep)
47+
{
48+
ptep_set_wrprotect(mm, addr, ptep);
49+
}
50+
51+
static inline pte_t huge_ptep_get_and_clear(struct mm_struct *mm,
52+
unsigned long addr, pte_t *ptep)
53+
{
54+
return ptep_get_and_clear(mm, addr, ptep);
55+
}
56+
57+
static inline int huge_ptep_set_access_flags(struct vm_area_struct *vma,
58+
unsigned long addr, pte_t *ptep,
59+
pte_t pte, int dirty)
60+
{
61+
return ptep_set_access_flags(vma, addr, ptep, pte, dirty);
62+
}
63+
64+
static inline void hugetlb_free_pgd_range(struct mmu_gather *tlb,
65+
unsigned long addr, unsigned long end,
66+
unsigned long floor,
67+
unsigned long ceiling)
68+
{
69+
free_pgd_range(tlb, addr, end, floor, ceiling);
70+
}
71+
72+
static inline int is_hugepage_only_range(struct mm_struct *mm,
73+
unsigned long addr, unsigned long len)
74+
{
75+
return 0;
76+
}
77+
78+
static inline int prepare_hugepage_range(struct file *file,
79+
unsigned long addr, unsigned long len)
80+
{
81+
struct hstate *h = hstate_file(file);
82+
if (len & ~huge_page_mask(h))
83+
return -EINVAL;
84+
if (addr & ~huge_page_mask(h))
85+
return -EINVAL;
86+
return 0;
87+
}
88+
89+
static inline void hugetlb_prefault_arch_hook(struct mm_struct *mm)
90+
{
91+
}
92+
93+
static inline int huge_pte_none(pte_t pte)
94+
{
95+
return pte_none(pte);
96+
}
97+
98+
static inline pte_t huge_pte_wrprotect(pte_t pte)
99+
{
100+
return pte_wrprotect(pte);
101+
}
102+
103+
static inline int arch_prepare_hugepage(struct page *page)
104+
{
105+
return 0;
106+
}
107+
108+
static inline void arch_release_hugepage(struct page *page)
109+
{
110+
}
111+
112+
static inline void arch_clear_hugepage_flags(struct page *page)
113+
{
114+
clear_bit(PG_dcache_clean, &page->flags);
115+
}
116+
117+
#endif /* __ASM_HUGETLB_H */

arch/arm64/include/asm/pgtable-hwdef.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,19 @@
2525
/*
2626
* Hardware page table definitions.
2727
*
28+
* Level 1 descriptor (PUD).
29+
*/
30+
31+
#define PUD_TABLE_BIT (_AT(pgdval_t, 1) << 1)
32+
33+
/*
2834
* Level 2 descriptor (PMD).
2935
*/
3036
#define PMD_TYPE_MASK (_AT(pmdval_t, 3) << 0)
3137
#define PMD_TYPE_FAULT (_AT(pmdval_t, 0) << 0)
3238
#define PMD_TYPE_TABLE (_AT(pmdval_t, 3) << 0)
3339
#define PMD_TYPE_SECT (_AT(pmdval_t, 1) << 0)
40+
#define PMD_TABLE_BIT (_AT(pmdval_t, 1) << 1)
3441

3542
/*
3643
* Section
@@ -53,6 +60,7 @@
5360
#define PTE_TYPE_MASK (_AT(pteval_t, 3) << 0)
5461
#define PTE_TYPE_FAULT (_AT(pteval_t, 0) << 0)
5562
#define PTE_TYPE_PAGE (_AT(pteval_t, 3) << 0)
63+
#define PTE_TABLE_BIT (_AT(pteval_t, 1) << 1)
5664
#define PTE_USER (_AT(pteval_t, 1) << 6) /* AP[1] */
5765
#define PTE_RDONLY (_AT(pteval_t, 1) << 7) /* AP[2] */
5866
#define PTE_SHARED (_AT(pteval_t, 3) << 8) /* SH[1:0], inner shareable */

arch/arm64/include/asm/pgtable.h

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -173,8 +173,17 @@ static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
173173
/*
174174
* Huge pte definitions.
175175
*/
176-
#define pte_huge(pte) ((pte_val(pte) & PTE_TYPE_MASK) == PTE_TYPE_HUGEPAGE)
177-
#define pte_mkhuge(pte) (__pte((pte_val(pte) & ~PTE_TYPE_MASK) | PTE_TYPE_HUGEPAGE))
176+
#define pte_huge(pte) (!(pte_val(pte) & PTE_TABLE_BIT))
177+
#define pte_mkhuge(pte) (__pte(pte_val(pte) & ~PTE_TABLE_BIT))
178+
179+
/*
180+
* Hugetlb definitions.
181+
*/
182+
#define HUGE_MAX_HSTATE 2
183+
#define HPAGE_SHIFT PMD_SHIFT
184+
#define HPAGE_SIZE (_AC(1, UL) << HPAGE_SHIFT)
185+
#define HPAGE_MASK (~(HPAGE_SIZE - 1))
186+
#define HUGETLB_PAGE_ORDER (HPAGE_SHIFT - PAGE_SHIFT)
178187

179188
#define __HAVE_ARCH_PTE_SPECIAL
180189

arch/arm64/mm/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ obj-y := dma-mapping.o extable.o fault.o init.o \
22
cache.o copypage.o flush.o \
33
ioremap.o mmap.o pgd.o mmu.o \
44
context.o tlb.o proc.o
5+
obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o

arch/arm64/mm/fault.c

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -364,17 +364,6 @@ static int __kprobes do_translation_fault(unsigned long addr,
364364
return 0;
365365
}
366366

367-
/*
368-
* Some section permission faults need to be handled gracefully. They can
369-
* happen due to a __{get,put}_user during an oops.
370-
*/
371-
static int do_sect_fault(unsigned long addr, unsigned int esr,
372-
struct pt_regs *regs)
373-
{
374-
do_bad_area(addr, esr, regs);
375-
return 0;
376-
}
377-
378367
/*
379368
* This abort handler always returns "fault".
380369
*/
@@ -398,12 +387,12 @@ static struct fault_info {
398387
{ do_translation_fault, SIGSEGV, SEGV_MAPERR, "level 2 translation fault" },
399388
{ do_page_fault, SIGSEGV, SEGV_MAPERR, "level 3 translation fault" },
400389
{ do_bad, SIGBUS, 0, "reserved access flag fault" },
401-
{ do_bad, SIGSEGV, SEGV_ACCERR, "level 1 access flag fault" },
402-
{ do_bad, SIGSEGV, SEGV_ACCERR, "level 2 access flag fault" },
390+
{ do_page_fault, SIGSEGV, SEGV_ACCERR, "level 1 access flag fault" },
391+
{ do_page_fault, SIGSEGV, SEGV_ACCERR, "level 2 access flag fault" },
403392
{ do_page_fault, SIGSEGV, SEGV_ACCERR, "level 3 access flag fault" },
404393
{ do_bad, SIGBUS, 0, "reserved permission fault" },
405-
{ do_bad, SIGSEGV, SEGV_ACCERR, "level 1 permission fault" },
406-
{ do_sect_fault, SIGSEGV, SEGV_ACCERR, "level 2 permission fault" },
394+
{ do_page_fault, SIGSEGV, SEGV_ACCERR, "level 1 permission fault" },
395+
{ do_page_fault, SIGSEGV, SEGV_ACCERR, "level 2 permission fault" },
407396
{ do_page_fault, SIGSEGV, SEGV_ACCERR, "level 3 permission fault" },
408397
{ do_bad, SIGBUS, 0, "synchronous external abort" },
409398
{ do_bad, SIGBUS, 0, "asynchronous external abort" },

arch/arm64/mm/hugetlbpage.c

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/*
2+
* arch/arm64/mm/hugetlbpage.c
3+
*
4+
* Copyright (C) 2013 Linaro Ltd.
5+
*
6+
* Based on arch/x86/mm/hugetlbpage.c.
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+
#ifndef CONFIG_ARCH_WANT_HUGE_PMD_SHARE
35+
int huge_pmd_unshare(struct mm_struct *mm, unsigned long *addr, pte_t *ptep)
36+
{
37+
return 0;
38+
}
39+
#endif
40+
41+
struct page *follow_huge_addr(struct mm_struct *mm, unsigned long address,
42+
int write)
43+
{
44+
return ERR_PTR(-EINVAL);
45+
}
46+
47+
int pmd_huge(pmd_t pmd)
48+
{
49+
return !(pmd_val(pmd) & PMD_TABLE_BIT);
50+
}
51+
52+
int pud_huge(pud_t pud)
53+
{
54+
return !(pud_val(pud) & PUD_TABLE_BIT);
55+
}
56+
57+
static __init int setup_hugepagesz(char *opt)
58+
{
59+
unsigned long ps = memparse(opt, &opt);
60+
if (ps == PMD_SIZE) {
61+
hugetlb_add_hstate(PMD_SHIFT - PAGE_SHIFT);
62+
} else if (ps == PUD_SIZE) {
63+
hugetlb_add_hstate(PUD_SHIFT - PAGE_SHIFT);
64+
} else {
65+
pr_err("hugepagesz: Unsupported page size %lu M\n", ps >> 20);
66+
return 0;
67+
}
68+
return 1;
69+
}
70+
__setup("hugepagesz=", setup_hugepagesz);

0 commit comments

Comments
 (0)