diff options
-rw-r--r-- | arch/s390/include/asm/pgtable.h | 23 | ||||
-rw-r--r-- | arch/s390/include/asm/sparsemem.h | 4 | ||||
-rw-r--r-- | arch/s390/kernel/setup.c | 67 | ||||
-rw-r--r-- | arch/s390/mm/init.c | 16 | ||||
-rw-r--r-- | arch/s390/mm/pgtable.c | 11 |
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 | |||
132 | extern unsigned long VMALLOC_START; | 131 | extern unsigned long VMALLOC_START; |
132 | extern unsigned long VMALLOC_END; | ||
133 | extern 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]; | |||
94 | int __initdata memory_end_set; | 94 | int __initdata memory_end_set; |
95 | unsigned long __initdata memory_end; | 95 | unsigned long __initdata memory_end; |
96 | 96 | ||
97 | unsigned long VMALLOC_START; | ||
98 | EXPORT_SYMBOL(VMALLOC_START); | ||
99 | |||
100 | unsigned long VMALLOC_END; | ||
101 | EXPORT_SYMBOL(VMALLOC_END); | ||
102 | |||
103 | struct page *vmemmap; | ||
104 | EXPORT_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. */ |
98 | struct _lowcore *lowcore_ptr[NR_CPUS]; | 107 | struct _lowcore *lowcore_ptr[NR_CPUS]; |
99 | EXPORT_SYMBOL(lowcore_ptr); | 108 | EXPORT_SYMBOL(lowcore_ptr); |
@@ -277,6 +286,15 @@ static int __init early_parse_mem(char *p) | |||
277 | } | 286 | } |
278 | early_param("mem", early_parse_mem); | 287 | early_param("mem", early_parse_mem); |
279 | 288 | ||
289 | static 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 | } | ||
296 | early_param("vmalloc", parse_vmalloc); | ||
297 | |||
280 | unsigned int user_mode = HOME_SPACE_MODE; | 298 | unsigned int user_mode = HOME_SPACE_MODE; |
281 | EXPORT_SYMBOL_GPL(user_mode); | 299 | EXPORT_SYMBOL_GPL(user_mode); |
282 | 300 | ||
@@ -478,8 +496,7 @@ EXPORT_SYMBOL_GPL(real_memory_size); | |||
478 | 496 | ||
479 | static void __init setup_memory_end(void) | 497 | static 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 | ||
536 | void *restart_stack __attribute__((__section__(".data"))); | 575 | void *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) | |||
93 | void __init paging_init(void) | 93 | void __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 | ||
36 | unsigned long VMALLOC_START = VMALLOC_END - VMALLOC_SIZE; | ||
37 | EXPORT_SYMBOL(VMALLOC_START); | ||
38 | |||
39 | static 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 | } | ||
46 | early_param("vmalloc", parse_vmalloc); | ||
47 | 36 | ||
48 | unsigned long *crst_table_alloc(struct mm_struct *mm) | 37 | unsigned long *crst_table_alloc(struct mm_struct *mm) |
49 | { | 38 | { |