aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390/mm/vmem.c
diff options
context:
space:
mode:
authorGerald Schaefer <geraldsc@de.ibm.com>2008-04-30 07:38:46 -0400
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2008-04-30 07:38:47 -0400
commit53492b1de46a7576170e865062ffcfc93bb5650b (patch)
treebee94e5b2e8c19c1a094a25023cb82572707feb4 /arch/s390/mm/vmem.c
parent2e5061e40af88070984e3769eafb5a06022375fd (diff)
[S390] System z large page support.
This adds hugetlbfs support on System z, using both hardware large page support if available and software large page emulation on older hardware. Shared (large) page tables are implemented in software emulation mode, by using page->index of the first tail page from a compound large page to store page table information. Signed-off-by: Gerald Schaefer <geraldsc@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'arch/s390/mm/vmem.c')
-rw-r--r--arch/s390/mm/vmem.c55
1 files changed, 48 insertions, 7 deletions
diff --git a/arch/s390/mm/vmem.c b/arch/s390/mm/vmem.c
index 3ffc0211dc85..97bce6c97574 100644
--- a/arch/s390/mm/vmem.c
+++ b/arch/s390/mm/vmem.c
@@ -10,10 +10,12 @@
10#include <linux/mm.h> 10#include <linux/mm.h>
11#include <linux/module.h> 11#include <linux/module.h>
12#include <linux/list.h> 12#include <linux/list.h>
13#include <linux/hugetlb.h>
13#include <asm/pgalloc.h> 14#include <asm/pgalloc.h>
14#include <asm/pgtable.h> 15#include <asm/pgtable.h>
15#include <asm/setup.h> 16#include <asm/setup.h>
16#include <asm/tlbflush.h> 17#include <asm/tlbflush.h>
18#include <asm/sections.h>
17 19
18static DEFINE_MUTEX(vmem_mutex); 20static DEFINE_MUTEX(vmem_mutex);
19 21
@@ -113,7 +115,7 @@ static pte_t __init_refok *vmem_pte_alloc(void)
113/* 115/*
114 * Add a physical memory range to the 1:1 mapping. 116 * Add a physical memory range to the 1:1 mapping.
115 */ 117 */
116static int vmem_add_range(unsigned long start, unsigned long size) 118static int vmem_add_range(unsigned long start, unsigned long size, int ro)
117{ 119{
118 unsigned long address; 120 unsigned long address;
119 pgd_t *pg_dir; 121 pgd_t *pg_dir;
@@ -140,7 +142,19 @@ static int vmem_add_range(unsigned long start, unsigned long size)
140 pud_populate_kernel(&init_mm, pu_dir, pm_dir); 142 pud_populate_kernel(&init_mm, pu_dir, pm_dir);
141 } 143 }
142 144
145 pte = mk_pte_phys(address, __pgprot(ro ? _PAGE_RO : 0));
143 pm_dir = pmd_offset(pu_dir, address); 146 pm_dir = pmd_offset(pu_dir, address);
147
148#ifdef __s390x__
149 if (MACHINE_HAS_HPAGE && !(address & ~HPAGE_MASK) &&
150 (address + HPAGE_SIZE <= start + size) &&
151 (address >= HPAGE_SIZE)) {
152 pte_val(pte) |= _SEGMENT_ENTRY_LARGE;
153 pmd_val(*pm_dir) = pte_val(pte);
154 address += HPAGE_SIZE - PAGE_SIZE;
155 continue;
156 }
157#endif
144 if (pmd_none(*pm_dir)) { 158 if (pmd_none(*pm_dir)) {
145 pt_dir = vmem_pte_alloc(); 159 pt_dir = vmem_pte_alloc();
146 if (!pt_dir) 160 if (!pt_dir)
@@ -149,7 +163,6 @@ static int vmem_add_range(unsigned long start, unsigned long size)
149 } 163 }
150 164
151 pt_dir = pte_offset_kernel(pm_dir, address); 165 pt_dir = pte_offset_kernel(pm_dir, address);
152 pte = pfn_pte(address >> PAGE_SHIFT, PAGE_KERNEL);
153 *pt_dir = pte; 166 *pt_dir = pte;
154 } 167 }
155 ret = 0; 168 ret = 0;
@@ -180,6 +193,13 @@ static void vmem_remove_range(unsigned long start, unsigned long size)
180 pm_dir = pmd_offset(pu_dir, address); 193 pm_dir = pmd_offset(pu_dir, address);
181 if (pmd_none(*pm_dir)) 194 if (pmd_none(*pm_dir))
182 continue; 195 continue;
196
197 if (pmd_huge(*pm_dir)) {
198 pmd_clear_kernel(pm_dir);
199 address += HPAGE_SIZE - PAGE_SIZE;
200 continue;
201 }
202
183 pt_dir = pte_offset_kernel(pm_dir, address); 203 pt_dir = pte_offset_kernel(pm_dir, address);
184 *pt_dir = pte; 204 *pt_dir = pte;
185 } 205 }
@@ -248,14 +268,14 @@ out:
248 return ret; 268 return ret;
249} 269}
250 270
251static int vmem_add_mem(unsigned long start, unsigned long size) 271static int vmem_add_mem(unsigned long start, unsigned long size, int ro)
252{ 272{
253 int ret; 273 int ret;
254 274
255 ret = vmem_add_mem_map(start, size); 275 ret = vmem_add_mem_map(start, size);
256 if (ret) 276 if (ret)
257 return ret; 277 return ret;
258 return vmem_add_range(start, size); 278 return vmem_add_range(start, size, ro);
259} 279}
260 280
261/* 281/*
@@ -338,7 +358,7 @@ int add_shared_memory(unsigned long start, unsigned long size)
338 if (ret) 358 if (ret)
339 goto out_free; 359 goto out_free;
340 360
341 ret = vmem_add_mem(start, size); 361 ret = vmem_add_mem(start, size, 0);
342 if (ret) 362 if (ret)
343 goto out_remove; 363 goto out_remove;
344 364
@@ -374,14 +394,35 @@ out:
374 */ 394 */
375void __init vmem_map_init(void) 395void __init vmem_map_init(void)
376{ 396{
397 unsigned long ro_start, ro_end;
398 unsigned long start, end;
377 int i; 399 int i;
378 400
379 INIT_LIST_HEAD(&init_mm.context.crst_list); 401 INIT_LIST_HEAD(&init_mm.context.crst_list);
380 INIT_LIST_HEAD(&init_mm.context.pgtable_list); 402 INIT_LIST_HEAD(&init_mm.context.pgtable_list);
381 init_mm.context.noexec = 0; 403 init_mm.context.noexec = 0;
382 NODE_DATA(0)->node_mem_map = VMEM_MAP; 404 NODE_DATA(0)->node_mem_map = VMEM_MAP;
383 for (i = 0; i < MEMORY_CHUNKS && memory_chunk[i].size > 0; i++) 405 ro_start = ((unsigned long)&_stext) & PAGE_MASK;
384 vmem_add_mem(memory_chunk[i].addr, memory_chunk[i].size); 406 ro_end = PFN_ALIGN((unsigned long)&_eshared);
407 for (i = 0; i < MEMORY_CHUNKS && memory_chunk[i].size > 0; i++) {
408 start = memory_chunk[i].addr;
409 end = memory_chunk[i].addr + memory_chunk[i].size;
410 if (start >= ro_end || end <= ro_start)
411 vmem_add_mem(start, end - start, 0);
412 else if (start >= ro_start && end <= ro_end)
413 vmem_add_mem(start, end - start, 1);
414 else if (start >= ro_start) {
415 vmem_add_mem(start, ro_end - start, 1);
416 vmem_add_mem(ro_end, end - ro_end, 0);
417 } else if (end < ro_end) {
418 vmem_add_mem(start, ro_start - start, 0);
419 vmem_add_mem(ro_start, end - ro_start, 1);
420 } else {
421 vmem_add_mem(start, ro_start - start, 0);
422 vmem_add_mem(ro_start, ro_end - ro_start, 1);
423 vmem_add_mem(ro_end, end - ro_end, 0);
424 }
425 }
385} 426}
386 427
387/* 428/*