diff options
Diffstat (limited to 'arch/s390/kernel/setup.c')
-rw-r--r-- | arch/s390/kernel/setup.c | 51 |
1 files changed, 46 insertions, 5 deletions
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index afa9fdba200e..b1f2be9aaaad 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -105,6 +105,11 @@ EXPORT_SYMBOL(VMALLOC_END); struct page *vmemmap; EXPORT_SYMBOL(vmemmap); +#ifdef CONFIG_64BIT +unsigned long MODULES_VADDR; +unsigned long MODULES_END; +#endif + /* An array with a pointer to the lowcore of every CPU. */ struct _lowcore *lowcore_ptr[NR_CPUS]; EXPORT_SYMBOL(lowcore_ptr); @@ -544,19 +549,23 @@ static void __init setup_memory_end(void) /* Choose kernel address space layout: 2, 3, or 4 levels. */ #ifdef CONFIG_64BIT - vmalloc_size = VMALLOC_END ?: 128UL << 30; + vmalloc_size = VMALLOC_END ?: (128UL << 30) - MODULES_LEN; tmp = (memory_end ?: real_memory_size) / PAGE_SIZE; tmp = tmp * (sizeof(struct page) + PAGE_SIZE) + vmalloc_size; if (tmp <= (1UL << 42)) vmax = 1UL << 42; /* 3-level kernel page table */ else vmax = 1UL << 53; /* 4-level kernel page table */ + /* module area is at the end of the kernel address space. */ + MODULES_END = vmax; + MODULES_VADDR = MODULES_END - MODULES_LEN; + VMALLOC_END = MODULES_VADDR; #else vmalloc_size = VMALLOC_END ?: 96UL << 20; vmax = 1UL << 31; /* 2-level kernel page table */ -#endif /* vmalloc area is at the end of the kernel address space. */ VMALLOC_END = vmax; +#endif VMALLOC_START = vmax - vmalloc_size; /* Split remaining virtual space between 1:1 mapping & vmemmap array */ @@ -768,6 +777,40 @@ static void __init reserve_crashkernel(void) #endif } +static void __init init_storage_keys(unsigned long start, unsigned long end) +{ + unsigned long boundary, function, size; + + while (start < end) { + if (MACHINE_HAS_EDAT2) { + /* set storage keys for a 2GB frame */ + function = 0x22000 | PAGE_DEFAULT_KEY; + size = 1UL << 31; + boundary = (start + size) & ~(size - 1); + if (boundary <= end) { + do { + start = pfmf(function, start); + } while (start < boundary); + continue; + } + } + if (MACHINE_HAS_EDAT1) { + /* set storage keys for a 1MB frame */ + function = 0x21000 | PAGE_DEFAULT_KEY; + size = 1UL << 20; + boundary = (start + size) & ~(size - 1); + if (boundary <= end) { + do { + start = pfmf(function, start); + } while (start < boundary); + continue; + } + } + page_set_storage_key(start, PAGE_DEFAULT_KEY, 0); + start += PAGE_SIZE; + } +} + static void __init setup_memory(void) { unsigned long bootmap_size; @@ -846,9 +889,7 @@ static void __init setup_memory(void) memblock_add_node(PFN_PHYS(start_chunk), PFN_PHYS(end_chunk - start_chunk), 0); pfn = max(start_chunk, start_pfn); - for (; pfn < end_chunk; pfn++) - page_set_storage_key(PFN_PHYS(pfn), - PAGE_DEFAULT_KEY, 0); + init_storage_keys(PFN_PHYS(pfn), PFN_PHYS(end_chunk)); } psw_set_key(PAGE_DEFAULT_KEY); |