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

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 <catalin.marinas@arm.com>
[steve.capper@linaro.org: 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 <steve.capper@linaro.org>
Reviewed-by: Will Deacon <will.deacon@arm.com>

authored by

Catalin Marinas and committed by
Steve Capper
1355e2a6 0b19f933

+276 -2
+4
arch/arm/Kconfig
··· 1707 1707 Enable hardware performance counter support for perf events. If 1708 1708 disabled, perf events will use software events only. 1709 1709 1710 + config SYS_SUPPORTS_HUGETLBFS 1711 + def_bool y 1712 + depends on ARM_LPAE 1713 + 1710 1714 source "mm/Kconfig" 1711 1715 1712 1716 config FORCE_MAX_ZONEORDER
+71
arch/arm/include/asm/hugetlb-3level.h
··· 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 */
+84
arch/arm/include/asm/hugetlb.h
··· 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 */
+2
arch/arm/include/asm/pgtable-3level-hwdef.h
··· 30 30 #define PMD_TYPE_FAULT (_AT(pmdval_t, 0) << 0) 31 31 #define PMD_TYPE_TABLE (_AT(pmdval_t, 3) << 0) 32 32 #define PMD_TYPE_SECT (_AT(pmdval_t, 1) << 0) 33 + #define PMD_TABLE_BIT (_AT(pmdval_t, 1) << 1) 33 34 #define PMD_BIT4 (_AT(pmdval_t, 0)) 34 35 #define PMD_DOMAIN(x) (_AT(pmdval_t, 0)) 35 36 #define PMD_APTABLE_SHIFT (61) ··· 67 66 #define PTE_TYPE_MASK (_AT(pteval_t, 3) << 0) 68 67 #define PTE_TYPE_FAULT (_AT(pteval_t, 0) << 0) 69 68 #define PTE_TYPE_PAGE (_AT(pteval_t, 3) << 0) 69 + #define PTE_TABLE_BIT (_AT(pteval_t, 1) << 1) 70 70 #define PTE_BUFFERABLE (_AT(pteval_t, 1) << 2) /* AttrIndx[0] */ 71 71 #define PTE_CACHEABLE (_AT(pteval_t, 1) << 3) /* AttrIndx[1] */ 72 72 #define PTE_EXT_SHARED (_AT(pteval_t, 3) << 8) /* SH[1:0], inner shareable */
+11
arch/arm/include/asm/pgtable-3level.h
··· 62 62 #define USER_PTRS_PER_PGD (PAGE_OFFSET / PGDIR_SIZE) 63 63 64 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 + 72 + /* 65 73 * "Linux" PTE definitions for LPAE. 66 74 * 67 75 * These bits overlap with the hardware bits but the naming is preserved for ··· 192 184 : pte_val(pte_b))) 193 185 194 186 #define set_pte_ext(ptep,pte,ext) cpu_set_pte_ext(ptep,__pte(pte_val(pte)|(ext))) 187 + 188 + #define pte_huge(pte) (pte_val(pte) && !(pte_val(pte) & PTE_TABLE_BIT)) 189 + #define pte_mkhuge(pte) (__pte(pte_val(pte) & ~PTE_TABLE_BIT)) 195 190 196 191 #endif /* __ASSEMBLY__ */ 197 192
+1
arch/arm/mm/Makefile
··· 16 16 17 17 obj-$(CONFIG_ALIGNMENT_TRAP) += alignment.o 18 18 obj-$(CONFIG_HIGHMEM) += highmem.o 19 + obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o 19 20 20 21 obj-$(CONFIG_CPU_ABRT_NOMMU) += abort-nommu.o 21 22 obj-$(CONFIG_CPU_ABRT_EV4) += abort-ev4.o
+1 -1
arch/arm/mm/dma-mapping.c
··· 250 250 251 251 #ifdef CONFIG_MMU 252 252 #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 254 254 #endif 255 255 256 256 static void *__alloc_from_contiguous(struct device *dev, size_t size,
+1 -1
arch/arm/mm/fsr-3level.c
··· 13 13 { do_page_fault, SIGSEGV, SEGV_ACCERR, "level 3 access flag fault" }, 14 14 { do_bad, SIGBUS, 0, "reserved permission fault" }, 15 15 { 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" }, 17 17 { do_page_fault, SIGSEGV, SEGV_ACCERR, "level 3 permission fault" }, 18 18 { do_bad, SIGBUS, 0, "synchronous external abort" }, 19 19 { do_bad, SIGBUS, 0, "asynchronous external abort" },
+101
arch/arm/mm/hugetlbpage.c
··· 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 + }