diff options
author | Steve Capper <steve.capper@linaro.org> | 2013-04-10 08:48:00 -0400 |
---|---|---|
committer | Steve Capper <steve.capper@linaro.org> | 2013-06-14 04:52:40 -0400 |
commit | 084bd29810a5689e423d2f085255a3200a03a06e (patch) | |
tree | 2c26ab58c8b95fb5c6f925044c3873979217da4a /arch/arm64/mm | |
parent | 59911ca4325dc7bd95e05c988fef3593b694e62c (diff) |
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 <steve.capper@linaro.org>
Acked-by: Catalin Marinas <catalin.marinas@arm.com>
Diffstat (limited to 'arch/arm64/mm')
-rw-r--r-- | arch/arm64/mm/Makefile | 1 | ||||
-rw-r--r-- | arch/arm64/mm/fault.c | 19 | ||||
-rw-r--r-- | arch/arm64/mm/hugetlbpage.c | 70 |
3 files changed, 75 insertions, 15 deletions
diff --git a/arch/arm64/mm/Makefile b/arch/arm64/mm/Makefile index 3140a2abcdc2..b51d36401d83 100644 --- a/arch/arm64/mm/Makefile +++ b/arch/arm64/mm/Makefile | |||
@@ -2,3 +2,4 @@ obj-y := dma-mapping.o extable.o fault.o init.o \ | |||
2 | cache.o copypage.o flush.o \ | 2 | cache.o copypage.o flush.o \ |
3 | ioremap.o mmap.o pgd.o mmu.o \ | 3 | ioremap.o mmap.o pgd.o mmu.o \ |
4 | context.o tlb.o proc.o | 4 | context.o tlb.o proc.o |
5 | obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o | ||
diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c index 1426468b77f3..0ecac8980aae 100644 --- a/arch/arm64/mm/fault.c +++ b/arch/arm64/mm/fault.c | |||
@@ -365,17 +365,6 @@ static int __kprobes do_translation_fault(unsigned long addr, | |||
365 | } | 365 | } |
366 | 366 | ||
367 | /* | 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 | |||
378 | /* | ||
379 | * This abort handler always returns "fault". | 368 | * This abort handler always returns "fault". |
380 | */ | 369 | */ |
381 | static int do_bad(unsigned long addr, unsigned int esr, struct pt_regs *regs) | 370 | static int do_bad(unsigned long addr, unsigned int esr, struct pt_regs *regs) |
@@ -398,12 +387,12 @@ static struct fault_info { | |||
398 | { do_translation_fault, SIGSEGV, SEGV_MAPERR, "level 2 translation fault" }, | 387 | { do_translation_fault, SIGSEGV, SEGV_MAPERR, "level 2 translation fault" }, |
399 | { do_page_fault, SIGSEGV, SEGV_MAPERR, "level 3 translation fault" }, | 388 | { do_page_fault, SIGSEGV, SEGV_MAPERR, "level 3 translation fault" }, |
400 | { do_bad, SIGBUS, 0, "reserved access flag fault" }, | 389 | { do_bad, SIGBUS, 0, "reserved access flag fault" }, |
401 | { do_bad, SIGSEGV, SEGV_ACCERR, "level 1 access flag fault" }, | 390 | { do_page_fault, SIGSEGV, SEGV_ACCERR, "level 1 access flag fault" }, |
402 | { do_bad, SIGSEGV, SEGV_ACCERR, "level 2 access flag fault" }, | 391 | { do_page_fault, SIGSEGV, SEGV_ACCERR, "level 2 access flag fault" }, |
403 | { do_page_fault, SIGSEGV, SEGV_ACCERR, "level 3 access flag fault" }, | 392 | { do_page_fault, SIGSEGV, SEGV_ACCERR, "level 3 access flag fault" }, |
404 | { do_bad, SIGBUS, 0, "reserved permission fault" }, | 393 | { do_bad, SIGBUS, 0, "reserved permission fault" }, |
405 | { do_bad, SIGSEGV, SEGV_ACCERR, "level 1 permission fault" }, | 394 | { do_page_fault, SIGSEGV, SEGV_ACCERR, "level 1 permission fault" }, |
406 | { do_sect_fault, SIGSEGV, SEGV_ACCERR, "level 2 permission fault" }, | 395 | { do_page_fault, SIGSEGV, SEGV_ACCERR, "level 2 permission fault" }, |
407 | { do_page_fault, SIGSEGV, SEGV_ACCERR, "level 3 permission fault" }, | 396 | { do_page_fault, SIGSEGV, SEGV_ACCERR, "level 3 permission fault" }, |
408 | { do_bad, SIGBUS, 0, "synchronous external abort" }, | 397 | { do_bad, SIGBUS, 0, "synchronous external abort" }, |
409 | { do_bad, SIGBUS, 0, "asynchronous external abort" }, | 398 | { do_bad, SIGBUS, 0, "asynchronous external abort" }, |
diff --git a/arch/arm64/mm/hugetlbpage.c b/arch/arm64/mm/hugetlbpage.c new file mode 100644 index 000000000000..2fc8258bab2d --- /dev/null +++ b/arch/arm64/mm/hugetlbpage.c | |||
@@ -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); | ||