From 85e9d0e5ffabfede5facbac5b0d9b90768bc6e90 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Thu, 27 Sep 2012 10:45:06 +0200 Subject: s390/mm: use pfmf instruction to initialize storage keys Make use of the pfmf instruction, if available, to initialize storage keys of whole 1MB or 2GB frames instead of initializing every single page with the sske instruction. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/early.c | 2 ++ arch/s390/kernel/setup.c | 38 +++++++++++++++++++++++++++++++++++--- 2 files changed, 37 insertions(+), 3 deletions(-) (limited to 'arch/s390/kernel') diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c index 4c91d07..1f0eee9 100644 --- a/arch/s390/kernel/early.c +++ b/arch/s390/kernel/early.c @@ -374,6 +374,8 @@ static __init void detect_machine_facilities(void) S390_lowcore.machine_flags |= MACHINE_FLAG_EDAT1; __ctl_set_bit(0, 23); } + if (test_facility(78)) + S390_lowcore.machine_flags |= MACHINE_FLAG_EDAT2; if (test_facility(3)) S390_lowcore.machine_flags |= MACHINE_FLAG_IDTE; if (test_facility(27)) diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index afa9fdb..bfb48f1 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -768,6 +768,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 +880,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); -- cgit v1.1