Commit | Line | Data |
---|---|---|
1da177e4 | 1 | /* |
4baa9922 | 2 | * arch/arm/include/asm/pgalloc.h |
1da177e4 LT |
3 | * |
4 | * Copyright (C) 2000-2001 Russell King | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or modify | |
7 | * it under the terms of the GNU General Public License version 2 as | |
8 | * published by the Free Software Foundation. | |
9 | */ | |
10 | #ifndef _ASMARM_PGALLOC_H | |
11 | #define _ASMARM_PGALLOC_H | |
12 | ||
97594b0f UKK |
13 | #include <linux/pagemap.h> |
14 | ||
74945c86 RK |
15 | #include <asm/domain.h> |
16 | #include <asm/pgtable-hwdef.h> | |
1da177e4 LT |
17 | #include <asm/processor.h> |
18 | #include <asm/cacheflush.h> | |
19 | #include <asm/tlbflush.h> | |
20 | ||
002547b4 RK |
21 | #define check_pgt_cache() do { } while (0) |
22 | ||
23 | #ifdef CONFIG_MMU | |
24 | ||
74945c86 RK |
25 | #define _PAGE_USER_TABLE (PMD_TYPE_TABLE | PMD_BIT4 | PMD_DOMAIN(DOMAIN_USER)) |
26 | #define _PAGE_KERNEL_TABLE (PMD_TYPE_TABLE | PMD_BIT4 | PMD_DOMAIN(DOMAIN_KERNEL)) | |
27 | ||
da028779 CM |
28 | #ifdef CONFIG_ARM_LPAE |
29 | ||
30 | static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long addr) | |
31 | { | |
32 | return (pmd_t *)get_zeroed_page(GFP_KERNEL | __GFP_REPEAT); | |
33 | } | |
34 | ||
35 | static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd) | |
36 | { | |
37 | BUG_ON((unsigned long)pmd & (PAGE_SIZE-1)); | |
38 | free_page((unsigned long)pmd); | |
39 | } | |
40 | ||
41 | static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd) | |
42 | { | |
43 | set_pud(pud, __pud(__pa(pmd) | PMD_TYPE_TABLE)); | |
44 | } | |
45 | ||
46 | #else /* !CONFIG_ARM_LPAE */ | |
47 | ||
1da177e4 LT |
48 | /* |
49 | * Since we have only two-level page tables, these are trivial | |
50 | */ | |
51 | #define pmd_alloc_one(mm,addr) ({ BUG(); ((pmd_t *)2); }) | |
5e541973 | 52 | #define pmd_free(mm, pmd) do { } while (0) |
a32618d2 | 53 | #define pud_populate(mm,pmd,pte) BUG() |
1da177e4 | 54 | |
da028779 CM |
55 | #endif /* CONFIG_ARM_LPAE */ |
56 | ||
b0d03745 RK |
57 | extern pgd_t *pgd_alloc(struct mm_struct *mm); |
58 | extern void pgd_free(struct mm_struct *mm, pgd_t *pgd); | |
1da177e4 | 59 | |
65cec8e3 RK |
60 | #define PGALLOC_GFP (GFP_KERNEL | __GFP_NOTRACK | __GFP_REPEAT | __GFP_ZERO) |
61 | ||
d30e45ee RK |
62 | static inline void clean_pte_table(pte_t *pte) |
63 | { | |
64 | clean_dcache_area(pte + PTE_HWTABLE_PTRS, PTE_HWTABLE_SIZE); | |
65 | } | |
66 | ||
1da177e4 LT |
67 | /* |
68 | * Allocate one PTE table. | |
69 | * | |
70 | * This actually allocates two hardware PTE tables, but we wrap this up | |
71 | * into one table thus: | |
72 | * | |
73 | * +------------+ | |
1da177e4 LT |
74 | * | Linux pt 0 | |
75 | * +------------+ | |
76 | * | Linux pt 1 | | |
77 | * +------------+ | |
d30e45ee RK |
78 | * | h/w pt 0 | |
79 | * +------------+ | |
80 | * | h/w pt 1 | | |
81 | * +------------+ | |
1da177e4 LT |
82 | */ |
83 | static inline pte_t * | |
84 | pte_alloc_one_kernel(struct mm_struct *mm, unsigned long addr) | |
85 | { | |
86 | pte_t *pte; | |
87 | ||
65cec8e3 | 88 | pte = (pte_t *)__get_free_page(PGALLOC_GFP); |
d30e45ee RK |
89 | if (pte) |
90 | clean_pte_table(pte); | |
1da177e4 LT |
91 | |
92 | return pte; | |
93 | } | |
94 | ||
2f569afd | 95 | static inline pgtable_t |
1da177e4 LT |
96 | pte_alloc_one(struct mm_struct *mm, unsigned long addr) |
97 | { | |
98 | struct page *pte; | |
99 | ||
65cec8e3 RK |
100 | #ifdef CONFIG_HIGHPTE |
101 | pte = alloc_pages(PGALLOC_GFP | __GFP_HIGHMEM, 0); | |
102 | #else | |
103 | pte = alloc_pages(PGALLOC_GFP, 0); | |
104 | #endif | |
affce508 KS |
105 | if (!pte) |
106 | return NULL; | |
107 | if (!PageHighMem(pte)) | |
108 | clean_pte_table(page_address(pte)); | |
109 | if (!pgtable_page_ctor(pte)) { | |
110 | __free_page(pte); | |
111 | return NULL; | |
1da177e4 | 112 | } |
1da177e4 LT |
113 | return pte; |
114 | } | |
115 | ||
116 | /* | |
117 | * Free one PTE table. | |
118 | */ | |
5e541973 | 119 | static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte) |
1da177e4 | 120 | { |
d30e45ee | 121 | if (pte) |
1da177e4 | 122 | free_page((unsigned long)pte); |
1da177e4 LT |
123 | } |
124 | ||
2f569afd | 125 | static inline void pte_free(struct mm_struct *mm, pgtable_t pte) |
1da177e4 | 126 | { |
2f569afd | 127 | pgtable_page_dtor(pte); |
1da177e4 LT |
128 | __free_page(pte); |
129 | } | |
130 | ||
97092e0c | 131 | static inline void __pmd_populate(pmd_t *pmdp, phys_addr_t pte, |
442e70c0 | 132 | pmdval_t prot) |
bdf04248 | 133 | { |
442e70c0 | 134 | pmdval_t pmdval = (pte + PTE_HWTABLE_OFF) | prot; |
bdf04248 | 135 | pmdp[0] = __pmd(pmdval); |
da028779 | 136 | #ifndef CONFIG_ARM_LPAE |
bdf04248 | 137 | pmdp[1] = __pmd(pmdval + 256 * sizeof(pte_t)); |
da028779 | 138 | #endif |
bdf04248 RK |
139 | flush_pmd_entry(pmdp); |
140 | } | |
141 | ||
1da177e4 LT |
142 | /* |
143 | * Populate the pmdp entry with a pointer to the pte. This pmd is part | |
144 | * of the mm address space. | |
145 | * | |
146 | * Ensure that we always set both PMD entries. | |
147 | */ | |
148 | static inline void | |
149 | pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmdp, pte_t *ptep) | |
150 | { | |
1da177e4 | 151 | /* |
d30e45ee | 152 | * The pmd must be loaded with the physical address of the PTE table |
1da177e4 | 153 | */ |
d30e45ee | 154 | __pmd_populate(pmdp, __pa(ptep), _PAGE_KERNEL_TABLE); |
1da177e4 LT |
155 | } |
156 | ||
157 | static inline void | |
2f569afd | 158 | pmd_populate(struct mm_struct *mm, pmd_t *pmdp, pgtable_t ptep) |
1da177e4 | 159 | { |
97092e0c | 160 | __pmd_populate(pmdp, page_to_phys(ptep), _PAGE_USER_TABLE); |
1da177e4 | 161 | } |
2f569afd | 162 | #define pmd_pgtable(pmd) pmd_page(pmd) |
1da177e4 | 163 | |
002547b4 RK |
164 | #endif /* CONFIG_MMU */ |
165 | ||
1da177e4 | 166 | #endif |