aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/s390/include/asm/pgtable.h23
-rw-r--r--arch/s390/include/asm/sparsemem.h4
-rw-r--r--arch/s390/kernel/setup.c67
-rw-r--r--arch/s390/mm/init.c16
-rw-r--r--arch/s390/mm/pgtable.c11
5 files changed, 68 insertions, 53 deletions
diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h
index 4f289ff0b7fe..011358c1b18e 100644
--- a/arch/s390/include/asm/pgtable.h
+++ b/arch/s390/include/asm/pgtable.h
@@ -128,28 +128,11 @@ static inline int is_zero_pfn(unsigned long pfn)
128 * effect, this also makes sure that 64 bit module code cannot be used 128 * effect, this also makes sure that 64 bit module code cannot be used
129 * as system call address. 129 * as system call address.
130 */ 130 */
131
132extern unsigned long VMALLOC_START; 131extern unsigned long VMALLOC_START;
132extern unsigned long VMALLOC_END;
133extern struct page *vmemmap;
133 134
134#ifndef __s390x__ 135#define VMEM_MAX_PHYS ((unsigned long) vmemmap)
135#define VMALLOC_SIZE (96UL << 20)
136#define VMALLOC_END 0x7e000000UL
137#define VMEM_MAP_END 0x80000000UL
138#else /* __s390x__ */
139#define VMALLOC_SIZE (128UL << 30)
140#define VMALLOC_END 0x3e000000000UL
141#define VMEM_MAP_END 0x40000000000UL
142#endif /* __s390x__ */
143
144/*
145 * VMEM_MAX_PHYS is the highest physical address that can be added to the 1:1
146 * mapping. This needs to be calculated at compile time since the size of the
147 * VMEM_MAP is static but the size of struct page can change.
148 */
149#define VMEM_MAX_PAGES ((VMEM_MAP_END - VMALLOC_END) / sizeof(struct page))
150#define VMEM_MAX_PFN min(VMALLOC_START >> PAGE_SHIFT, VMEM_MAX_PAGES)
151#define VMEM_MAX_PHYS ((VMEM_MAX_PFN << PAGE_SHIFT) & ~((16 << 20) - 1))
152#define vmemmap ((struct page *) VMALLOC_END)
153 136
154/* 137/*
155 * A 31 bit pagetable entry of S390 has following format: 138 * A 31 bit pagetable entry of S390 has following format:
diff --git a/arch/s390/include/asm/sparsemem.h b/arch/s390/include/asm/sparsemem.h
index 545d219e6a2d..0fb34027d3f6 100644
--- a/arch/s390/include/asm/sparsemem.h
+++ b/arch/s390/include/asm/sparsemem.h
@@ -4,8 +4,8 @@
4#ifdef CONFIG_64BIT 4#ifdef CONFIG_64BIT
5 5
6#define SECTION_SIZE_BITS 28 6#define SECTION_SIZE_BITS 28
7#define MAX_PHYSADDR_BITS 42 7#define MAX_PHYSADDR_BITS 46
8#define MAX_PHYSMEM_BITS 42 8#define MAX_PHYSMEM_BITS 46
9 9
10#else 10#else
11 11
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c
index 26b601c2b137..66903eed36e6 100644
--- a/arch/s390/kernel/setup.c
+++ b/arch/s390/kernel/setup.c
@@ -94,6 +94,15 @@ struct mem_chunk __initdata memory_chunk[MEMORY_CHUNKS];
94int __initdata memory_end_set; 94int __initdata memory_end_set;
95unsigned long __initdata memory_end; 95unsigned long __initdata memory_end;
96 96
97unsigned long VMALLOC_START;
98EXPORT_SYMBOL(VMALLOC_START);
99
100unsigned long VMALLOC_END;
101EXPORT_SYMBOL(VMALLOC_END);
102
103struct page *vmemmap;
104EXPORT_SYMBOL(vmemmap);
105
97/* An array with a pointer to the lowcore of every CPU. */ 106/* An array with a pointer to the lowcore of every CPU. */
98struct _lowcore *lowcore_ptr[NR_CPUS]; 107struct _lowcore *lowcore_ptr[NR_CPUS];
99EXPORT_SYMBOL(lowcore_ptr); 108EXPORT_SYMBOL(lowcore_ptr);
@@ -277,6 +286,15 @@ static int __init early_parse_mem(char *p)
277} 286}
278early_param("mem", early_parse_mem); 287early_param("mem", early_parse_mem);
279 288
289static int __init parse_vmalloc(char *arg)
290{
291 if (!arg)
292 return -EINVAL;
293 VMALLOC_END = (memparse(arg, &arg) + PAGE_SIZE - 1) & PAGE_MASK;
294 return 0;
295}
296early_param("vmalloc", parse_vmalloc);
297
280unsigned int user_mode = HOME_SPACE_MODE; 298unsigned int user_mode = HOME_SPACE_MODE;
281EXPORT_SYMBOL_GPL(user_mode); 299EXPORT_SYMBOL_GPL(user_mode);
282 300
@@ -478,8 +496,7 @@ EXPORT_SYMBOL_GPL(real_memory_size);
478 496
479static void __init setup_memory_end(void) 497static void __init setup_memory_end(void)
480{ 498{
481 unsigned long memory_size; 499 unsigned long vmax, vmalloc_size, tmp;
482 unsigned long max_mem;
483 int i; 500 int i;
484 501
485 502
@@ -489,12 +506,9 @@ static void __init setup_memory_end(void)
489 memory_end_set = 1; 506 memory_end_set = 1;
490 } 507 }
491#endif 508#endif
492 memory_size = 0; 509 real_memory_size = 0;
493 memory_end &= PAGE_MASK; 510 memory_end &= PAGE_MASK;
494 511
495 max_mem = memory_end ? min(VMEM_MAX_PHYS, memory_end) : VMEM_MAX_PHYS;
496 memory_end = min(max_mem, memory_end);
497
498 /* 512 /*
499 * Make sure all chunks are MAX_ORDER aligned so we don't need the 513 * Make sure all chunks are MAX_ORDER aligned so we don't need the
500 * extra checks that HOLES_IN_ZONE would require. 514 * extra checks that HOLES_IN_ZONE would require.
@@ -514,23 +528,48 @@ static void __init setup_memory_end(void)
514 chunk->addr = start; 528 chunk->addr = start;
515 chunk->size = end - start; 529 chunk->size = end - start;
516 } 530 }
531 real_memory_size = max(real_memory_size,
532 chunk->addr + chunk->size);
517 } 533 }
518 534
535 /* Choose kernel address space layout: 2, 3, or 4 levels. */
536#ifdef CONFIG_64BIT
537 vmalloc_size = VMALLOC_END ?: 128UL << 30;
538 tmp = (memory_end ?: real_memory_size) / PAGE_SIZE;
539 tmp = tmp * (sizeof(struct page) + PAGE_SIZE) + vmalloc_size;
540 if (tmp <= (1UL << 42))
541 vmax = 1UL << 42; /* 3-level kernel page table */
542 else
543 vmax = 1UL << 53; /* 4-level kernel page table */
544#else
545 vmalloc_size = VMALLOC_END ?: 96UL << 20;
546 vmax = 1UL << 31; /* 2-level kernel page table */
547#endif
548 /* vmalloc area is at the end of the kernel address space. */
549 VMALLOC_END = vmax;
550 VMALLOC_START = vmax - vmalloc_size;
551
552 /* Split remaining virtual space between 1:1 mapping & vmemmap array */
553 tmp = VMALLOC_START / (PAGE_SIZE + sizeof(struct page));
554 tmp = VMALLOC_START - tmp * sizeof(struct page);
555 tmp &= ~((vmax >> 11) - 1); /* align to page table level */
556 tmp = min(tmp, 1UL << MAX_PHYSMEM_BITS);
557 vmemmap = (struct page *) tmp;
558
559 /* Take care that memory_end is set and <= vmemmap */
560 memory_end = min(memory_end ?: real_memory_size, tmp);
561
562 /* Fixup memory chunk array to fit into 0..memory_end */
519 for (i = 0; i < MEMORY_CHUNKS; i++) { 563 for (i = 0; i < MEMORY_CHUNKS; i++) {
520 struct mem_chunk *chunk = &memory_chunk[i]; 564 struct mem_chunk *chunk = &memory_chunk[i];
521 565
522 real_memory_size = max(real_memory_size, 566 if (chunk->addr >= memory_end) {
523 chunk->addr + chunk->size);
524 if (chunk->addr >= max_mem) {
525 memset(chunk, 0, sizeof(*chunk)); 567 memset(chunk, 0, sizeof(*chunk));
526 continue; 568 continue;
527 } 569 }
528 if (chunk->addr + chunk->size > max_mem) 570 if (chunk->addr + chunk->size > memory_end)
529 chunk->size = max_mem - chunk->addr; 571 chunk->size = memory_end - chunk->addr;
530 memory_size = max(memory_size, chunk->addr + chunk->size);
531 } 572 }
532 if (!memory_end)
533 memory_end = memory_size;
534} 573}
535 574
536void *restart_stack __attribute__((__section__(".data"))); 575void *restart_stack __attribute__((__section__(".data")));
diff --git a/arch/s390/mm/init.c b/arch/s390/mm/init.c
index d4b9fb4d0042..5d633019d8f3 100644
--- a/arch/s390/mm/init.c
+++ b/arch/s390/mm/init.c
@@ -93,18 +93,22 @@ static unsigned long setup_zero_pages(void)
93void __init paging_init(void) 93void __init paging_init(void)
94{ 94{
95 unsigned long max_zone_pfns[MAX_NR_ZONES]; 95 unsigned long max_zone_pfns[MAX_NR_ZONES];
96 unsigned long pgd_type; 96 unsigned long pgd_type, asce_bits;
97 97
98 init_mm.pgd = swapper_pg_dir; 98 init_mm.pgd = swapper_pg_dir;
99 S390_lowcore.kernel_asce = __pa(init_mm.pgd) & PAGE_MASK;
100#ifdef CONFIG_64BIT 99#ifdef CONFIG_64BIT
101 /* A three level page table (4TB) is enough for the kernel space. */ 100 if (VMALLOC_END > (1UL << 42)) {
102 S390_lowcore.kernel_asce |= _ASCE_TYPE_REGION3 | _ASCE_TABLE_LENGTH; 101 asce_bits = _ASCE_TYPE_REGION2 | _ASCE_TABLE_LENGTH;
103 pgd_type = _REGION3_ENTRY_EMPTY; 102 pgd_type = _REGION2_ENTRY_EMPTY;
103 } else {
104 asce_bits = _ASCE_TYPE_REGION3 | _ASCE_TABLE_LENGTH;
105 pgd_type = _REGION3_ENTRY_EMPTY;
106 }
104#else 107#else
105 S390_lowcore.kernel_asce |= _ASCE_TABLE_LENGTH; 108 asce_bits = _ASCE_TABLE_LENGTH;
106 pgd_type = _SEGMENT_ENTRY_EMPTY; 109 pgd_type = _SEGMENT_ENTRY_EMPTY;
107#endif 110#endif
111 S390_lowcore.kernel_asce = (__pa(init_mm.pgd) & PAGE_MASK) | asce_bits;
108 clear_table((unsigned long *) init_mm.pgd, pgd_type, 112 clear_table((unsigned long *) init_mm.pgd, pgd_type,
109 sizeof(unsigned long)*2048); 113 sizeof(unsigned long)*2048);
110 vmem_map_init(); 114 vmem_map_init();
diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c
index dc2269f1821c..9a4d02f64f16 100644
--- a/arch/s390/mm/pgtable.c
+++ b/arch/s390/mm/pgtable.c
@@ -33,17 +33,6 @@
33#define FRAG_MASK 0x03 33#define FRAG_MASK 0x03
34#endif 34#endif
35 35
36unsigned long VMALLOC_START = VMALLOC_END - VMALLOC_SIZE;
37EXPORT_SYMBOL(VMALLOC_START);
38
39static int __init parse_vmalloc(char *arg)
40{
41 if (!arg)
42 return -EINVAL;
43 VMALLOC_START = (VMALLOC_END - memparse(arg, &arg)) & PAGE_MASK;
44 return 0;
45}
46early_param("vmalloc", parse_vmalloc);
47 36
48unsigned long *crst_table_alloc(struct mm_struct *mm) 37unsigned long *crst_table_alloc(struct mm_struct *mm)
49{ 38{