diff options
Diffstat (limited to 'arch/s390/mm/vmem.c')
-rw-r--r-- | arch/s390/mm/vmem.c | 53 |
1 files changed, 35 insertions, 18 deletions
diff --git a/arch/s390/mm/vmem.c b/arch/s390/mm/vmem.c index fd594d5fe142..fb9c5a85aa56 100644 --- a/arch/s390/mm/vmem.c +++ b/arch/s390/mm/vmem.c | |||
@@ -73,31 +73,28 @@ static void __init_refok *vmem_alloc_pages(unsigned int order) | |||
73 | return alloc_bootmem_pages((1 << order) * PAGE_SIZE); | 73 | return alloc_bootmem_pages((1 << order) * PAGE_SIZE); |
74 | } | 74 | } |
75 | 75 | ||
76 | #define vmem_pud_alloc() ({ BUG(); ((pud_t *) NULL); }) | ||
77 | |||
76 | static inline pmd_t *vmem_pmd_alloc(void) | 78 | static inline pmd_t *vmem_pmd_alloc(void) |
77 | { | 79 | { |
78 | pmd_t *pmd; | 80 | pmd_t *pmd = NULL; |
79 | int i; | ||
80 | 81 | ||
81 | pmd = vmem_alloc_pages(PMD_ALLOC_ORDER); | 82 | #ifdef CONFIG_64BIT |
83 | pmd = vmem_alloc_pages(2); | ||
82 | if (!pmd) | 84 | if (!pmd) |
83 | return NULL; | 85 | return NULL; |
84 | for (i = 0; i < PTRS_PER_PMD; i++) | 86 | clear_table((unsigned long *) pmd, _SEGMENT_ENTRY_EMPTY, PAGE_SIZE*4); |
85 | pmd_clear_kernel(pmd + i); | 87 | #endif |
86 | return pmd; | 88 | return pmd; |
87 | } | 89 | } |
88 | 90 | ||
89 | static inline pte_t *vmem_pte_alloc(void) | 91 | static inline pte_t *vmem_pte_alloc(void) |
90 | { | 92 | { |
91 | pte_t *pte; | 93 | pte_t *pte = vmem_alloc_pages(0); |
92 | pte_t empty_pte; | ||
93 | int i; | ||
94 | 94 | ||
95 | pte = vmem_alloc_pages(PTE_ALLOC_ORDER); | ||
96 | if (!pte) | 95 | if (!pte) |
97 | return NULL; | 96 | return NULL; |
98 | pte_val(empty_pte) = _PAGE_TYPE_EMPTY; | 97 | clear_table((unsigned long *) pte, _PAGE_TYPE_EMPTY, PAGE_SIZE); |
99 | for (i = 0; i < PTRS_PER_PTE; i++) | ||
100 | pte[i] = empty_pte; | ||
101 | return pte; | 98 | return pte; |
102 | } | 99 | } |
103 | 100 | ||
@@ -108,6 +105,7 @@ static int vmem_add_range(unsigned long start, unsigned long size) | |||
108 | { | 105 | { |
109 | unsigned long address; | 106 | unsigned long address; |
110 | pgd_t *pg_dir; | 107 | pgd_t *pg_dir; |
108 | pud_t *pu_dir; | ||
111 | pmd_t *pm_dir; | 109 | pmd_t *pm_dir; |
112 | pte_t *pt_dir; | 110 | pte_t *pt_dir; |
113 | pte_t pte; | 111 | pte_t pte; |
@@ -116,13 +114,21 @@ static int vmem_add_range(unsigned long start, unsigned long size) | |||
116 | for (address = start; address < start + size; address += PAGE_SIZE) { | 114 | for (address = start; address < start + size; address += PAGE_SIZE) { |
117 | pg_dir = pgd_offset_k(address); | 115 | pg_dir = pgd_offset_k(address); |
118 | if (pgd_none(*pg_dir)) { | 116 | if (pgd_none(*pg_dir)) { |
117 | pu_dir = vmem_pud_alloc(); | ||
118 | if (!pu_dir) | ||
119 | goto out; | ||
120 | pgd_populate_kernel(&init_mm, pg_dir, pu_dir); | ||
121 | } | ||
122 | |||
123 | pu_dir = pud_offset(pg_dir, address); | ||
124 | if (pud_none(*pu_dir)) { | ||
119 | pm_dir = vmem_pmd_alloc(); | 125 | pm_dir = vmem_pmd_alloc(); |
120 | if (!pm_dir) | 126 | if (!pm_dir) |
121 | goto out; | 127 | goto out; |
122 | pgd_populate_kernel(&init_mm, pg_dir, pm_dir); | 128 | pud_populate_kernel(&init_mm, pu_dir, pm_dir); |
123 | } | 129 | } |
124 | 130 | ||
125 | pm_dir = pmd_offset(pg_dir, address); | 131 | pm_dir = pmd_offset(pu_dir, address); |
126 | if (pmd_none(*pm_dir)) { | 132 | if (pmd_none(*pm_dir)) { |
127 | pt_dir = vmem_pte_alloc(); | 133 | pt_dir = vmem_pte_alloc(); |
128 | if (!pt_dir) | 134 | if (!pt_dir) |
@@ -148,6 +154,7 @@ static void vmem_remove_range(unsigned long start, unsigned long size) | |||
148 | { | 154 | { |
149 | unsigned long address; | 155 | unsigned long address; |
150 | pgd_t *pg_dir; | 156 | pgd_t *pg_dir; |
157 | pud_t *pu_dir; | ||
151 | pmd_t *pm_dir; | 158 | pmd_t *pm_dir; |
152 | pte_t *pt_dir; | 159 | pte_t *pt_dir; |
153 | pte_t pte; | 160 | pte_t pte; |
@@ -155,9 +162,10 @@ static void vmem_remove_range(unsigned long start, unsigned long size) | |||
155 | pte_val(pte) = _PAGE_TYPE_EMPTY; | 162 | pte_val(pte) = _PAGE_TYPE_EMPTY; |
156 | for (address = start; address < start + size; address += PAGE_SIZE) { | 163 | for (address = start; address < start + size; address += PAGE_SIZE) { |
157 | pg_dir = pgd_offset_k(address); | 164 | pg_dir = pgd_offset_k(address); |
158 | if (pgd_none(*pg_dir)) | 165 | pu_dir = pud_offset(pg_dir, address); |
166 | if (pud_none(*pu_dir)) | ||
159 | continue; | 167 | continue; |
160 | pm_dir = pmd_offset(pg_dir, address); | 168 | pm_dir = pmd_offset(pu_dir, address); |
161 | if (pmd_none(*pm_dir)) | 169 | if (pmd_none(*pm_dir)) |
162 | continue; | 170 | continue; |
163 | pt_dir = pte_offset_kernel(pm_dir, address); | 171 | pt_dir = pte_offset_kernel(pm_dir, address); |
@@ -174,6 +182,7 @@ static int vmem_add_mem_map(unsigned long start, unsigned long size) | |||
174 | unsigned long address, start_addr, end_addr; | 182 | unsigned long address, start_addr, end_addr; |
175 | struct page *map_start, *map_end; | 183 | struct page *map_start, *map_end; |
176 | pgd_t *pg_dir; | 184 | pgd_t *pg_dir; |
185 | pud_t *pu_dir; | ||
177 | pmd_t *pm_dir; | 186 | pmd_t *pm_dir; |
178 | pte_t *pt_dir; | 187 | pte_t *pt_dir; |
179 | pte_t pte; | 188 | pte_t pte; |
@@ -188,13 +197,21 @@ static int vmem_add_mem_map(unsigned long start, unsigned long size) | |||
188 | for (address = start_addr; address < end_addr; address += PAGE_SIZE) { | 197 | for (address = start_addr; address < end_addr; address += PAGE_SIZE) { |
189 | pg_dir = pgd_offset_k(address); | 198 | pg_dir = pgd_offset_k(address); |
190 | if (pgd_none(*pg_dir)) { | 199 | if (pgd_none(*pg_dir)) { |
200 | pu_dir = vmem_pud_alloc(); | ||
201 | if (!pu_dir) | ||
202 | goto out; | ||
203 | pgd_populate_kernel(&init_mm, pg_dir, pu_dir); | ||
204 | } | ||
205 | |||
206 | pu_dir = pud_offset(pg_dir, address); | ||
207 | if (pud_none(*pu_dir)) { | ||
191 | pm_dir = vmem_pmd_alloc(); | 208 | pm_dir = vmem_pmd_alloc(); |
192 | if (!pm_dir) | 209 | if (!pm_dir) |
193 | goto out; | 210 | goto out; |
194 | pgd_populate_kernel(&init_mm, pg_dir, pm_dir); | 211 | pud_populate_kernel(&init_mm, pu_dir, pm_dir); |
195 | } | 212 | } |
196 | 213 | ||
197 | pm_dir = pmd_offset(pg_dir, address); | 214 | pm_dir = pmd_offset(pu_dir, address); |
198 | if (pmd_none(*pm_dir)) { | 215 | if (pmd_none(*pm_dir)) { |
199 | pt_dir = vmem_pte_alloc(); | 216 | pt_dir = vmem_pte_alloc(); |
200 | if (!pt_dir) | 217 | if (!pt_dir) |