diff options
| -rw-r--r-- | arch/s390/Kconfig.debug | 12 | ||||
| -rw-r--r-- | arch/s390/include/asm/chpid.h | 2 | ||||
| -rw-r--r-- | arch/s390/include/asm/css_chars.h | 3 | ||||
| -rw-r--r-- | arch/s390/include/asm/page.h | 14 | ||||
| -rw-r--r-- | arch/s390/include/asm/pgtable.h | 30 | ||||
| -rw-r--r-- | arch/s390/include/asm/setup.h | 14 | ||||
| -rw-r--r-- | arch/s390/include/uapi/asm/chsc.h | 10 | ||||
| -rw-r--r-- | arch/s390/kernel/early.c | 17 | ||||
| -rw-r--r-- | arch/s390/kernel/entry64.S | 2 | ||||
| -rw-r--r-- | arch/s390/kernel/head.S | 101 | ||||
| -rw-r--r-- | arch/s390/kernel/head31.S | 3 | ||||
| -rw-r--r-- | arch/s390/kernel/head64.S | 3 | ||||
| -rw-r--r-- | arch/s390/kernel/module.c | 11 | ||||
| -rw-r--r-- | arch/s390/kernel/setup.c | 51 | ||||
| -rw-r--r-- | arch/s390/mm/Makefile | 1 | ||||
| -rw-r--r-- | arch/s390/mm/dump_pagetables.c | 226 | ||||
| -rw-r--r-- | arch/s390/mm/pageattr.c | 40 | ||||
| -rw-r--r-- | arch/s390/mm/vmem.c | 45 | ||||
| -rw-r--r-- | drivers/s390/block/dcssblk.c | 52 | ||||
| -rw-r--r-- | drivers/s390/crypto/zcrypt_pcixcc.c | 1 |
20 files changed, 497 insertions, 141 deletions
diff --git a/arch/s390/Kconfig.debug b/arch/s390/Kconfig.debug index d76cef3fef37..fc32a2df4974 100644 --- a/arch/s390/Kconfig.debug +++ b/arch/s390/Kconfig.debug | |||
| @@ -31,6 +31,18 @@ config DEBUG_STRICT_USER_COPY_CHECKS | |||
| 31 | 31 | ||
| 32 | If unsure, or if you run an older (pre 4.4) gcc, say N. | 32 | If unsure, or if you run an older (pre 4.4) gcc, say N. |
| 33 | 33 | ||
| 34 | config S390_PTDUMP | ||
| 35 | bool "Export kernel pagetable layout to userspace via debugfs" | ||
| 36 | depends on DEBUG_KERNEL | ||
| 37 | select DEBUG_FS | ||
| 38 | ---help--- | ||
| 39 | Say Y here if you want to show the kernel pagetable layout in a | ||
| 40 | debugfs file. This information is only useful for kernel developers | ||
| 41 | who are working in architecture specific areas of the kernel. | ||
| 42 | It is probably not a good idea to enable this feature in a production | ||
| 43 | kernel. | ||
| 44 | If in doubt, say "N" | ||
| 45 | |||
| 34 | config DEBUG_SET_MODULE_RONX | 46 | config DEBUG_SET_MODULE_RONX |
| 35 | def_bool y | 47 | def_bool y |
| 36 | depends on MODULES | 48 | depends on MODULES |
diff --git a/arch/s390/include/asm/chpid.h b/arch/s390/include/asm/chpid.h index 64c76ddde3c1..38c405ef89ce 100644 --- a/arch/s390/include/asm/chpid.h +++ b/arch/s390/include/asm/chpid.h | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright IBM Corp. 2007 | 2 | * Copyright IBM Corp. 2007, 2012 |
| 3 | * Author(s): Peter Oberparleiter <peter.oberparleiter@de.ibm.com> | 3 | * Author(s): Peter Oberparleiter <peter.oberparleiter@de.ibm.com> |
| 4 | */ | 4 | */ |
| 5 | #ifndef _ASM_S390_CHPID_H | 5 | #ifndef _ASM_S390_CHPID_H |
diff --git a/arch/s390/include/asm/css_chars.h b/arch/s390/include/asm/css_chars.h index a06ebc2623fb..7e1c917bbba2 100644 --- a/arch/s390/include/asm/css_chars.h +++ b/arch/s390/include/asm/css_chars.h | |||
| @@ -3,8 +3,6 @@ | |||
| 3 | 3 | ||
| 4 | #include <linux/types.h> | 4 | #include <linux/types.h> |
| 5 | 5 | ||
| 6 | #ifdef __KERNEL__ | ||
| 7 | |||
| 8 | struct css_general_char { | 6 | struct css_general_char { |
| 9 | u64 : 12; | 7 | u64 : 12; |
| 10 | u32 dynio : 1; /* bit 12 */ | 8 | u32 dynio : 1; /* bit 12 */ |
| @@ -35,5 +33,4 @@ struct css_general_char { | |||
| 35 | 33 | ||
| 36 | extern struct css_general_char css_general_characteristics; | 34 | extern struct css_general_char css_general_characteristics; |
| 37 | 35 | ||
| 38 | #endif /* __KERNEL__ */ | ||
| 39 | #endif | 36 | #endif |
diff --git a/arch/s390/include/asm/page.h b/arch/s390/include/asm/page.h index 27ab3c7c1e8b..6d5367060a56 100644 --- a/arch/s390/include/asm/page.h +++ b/arch/s390/include/asm/page.h | |||
| @@ -30,12 +30,20 @@ | |||
| 30 | #include <asm/setup.h> | 30 | #include <asm/setup.h> |
| 31 | #ifndef __ASSEMBLY__ | 31 | #ifndef __ASSEMBLY__ |
| 32 | 32 | ||
| 33 | static unsigned long pfmf(unsigned long function, unsigned long address) | ||
| 34 | { | ||
| 35 | asm volatile( | ||
| 36 | " .insn rre,0xb9af0000,%[function],%[address]" | ||
| 37 | : [address] "+a" (address) | ||
| 38 | : [function] "d" (function) | ||
| 39 | : "memory"); | ||
| 40 | return address; | ||
| 41 | } | ||
| 42 | |||
| 33 | static inline void clear_page(void *page) | 43 | static inline void clear_page(void *page) |
| 34 | { | 44 | { |
| 35 | if (MACHINE_HAS_PFMF) { | 45 | if (MACHINE_HAS_PFMF) { |
| 36 | asm volatile( | 46 | pfmf(0x10000, (unsigned long)page); |
| 37 | " .insn rre,0xb9af0000,%0,%1" | ||
| 38 | : : "d" (0x10000), "a" (page) : "memory", "cc"); | ||
| 39 | } else { | 47 | } else { |
| 40 | register unsigned long reg1 asm ("1") = 0; | 48 | register unsigned long reg1 asm ("1") = 0; |
| 41 | register void *reg2 asm ("2") = page; | 49 | register void *reg2 asm ("2") = page; |
diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h index 979fe3dc0788..dd647c919a66 100644 --- a/arch/s390/include/asm/pgtable.h +++ b/arch/s390/include/asm/pgtable.h | |||
| @@ -119,13 +119,12 @@ static inline int is_zero_pfn(unsigned long pfn) | |||
| 119 | 119 | ||
| 120 | #ifndef __ASSEMBLY__ | 120 | #ifndef __ASSEMBLY__ |
| 121 | /* | 121 | /* |
| 122 | * The vmalloc area will always be on the topmost area of the kernel | 122 | * The vmalloc and module area will always be on the topmost area of the kernel |
| 123 | * mapping. We reserve 96MB (31bit) / 128GB (64bit) for vmalloc, | 123 | * mapping. We reserve 96MB (31bit) / 128GB (64bit) for vmalloc and modules. |
| 124 | * which should be enough for any sane case. | 124 | * On 64 bit kernels we have a 2GB area at the top of the vmalloc area where |
| 125 | * By putting vmalloc at the top, we maximise the gap between physical | 125 | * modules will reside. That makes sure that inter module branches always |
| 126 | * memory and vmalloc to catch misplaced memory accesses. As a side | 126 | * happen without trampolines and in addition the placement within a 2GB frame |
| 127 | * effect, this also makes sure that 64 bit module code cannot be used | 127 | * is branch prediction unit friendly. |
| 128 | * as system call address. | ||
| 129 | */ | 128 | */ |
| 130 | extern unsigned long VMALLOC_START; | 129 | extern unsigned long VMALLOC_START; |
| 131 | extern unsigned long VMALLOC_END; | 130 | extern unsigned long VMALLOC_END; |
| @@ -133,6 +132,14 @@ extern struct page *vmemmap; | |||
| 133 | 132 | ||
| 134 | #define VMEM_MAX_PHYS ((unsigned long) vmemmap) | 133 | #define VMEM_MAX_PHYS ((unsigned long) vmemmap) |
| 135 | 134 | ||
| 135 | #ifdef CONFIG_64BIT | ||
| 136 | extern unsigned long MODULES_VADDR; | ||
| 137 | extern unsigned long MODULES_END; | ||
| 138 | #define MODULES_VADDR MODULES_VADDR | ||
| 139 | #define MODULES_END MODULES_END | ||
| 140 | #define MODULES_LEN (1UL << 31) | ||
| 141 | #endif | ||
| 142 | |||
| 136 | /* | 143 | /* |
| 137 | * A 31 bit pagetable entry of S390 has following format: | 144 | * A 31 bit pagetable entry of S390 has following format: |
| 138 | * | PFRA | | OS | | 145 | * | PFRA | | OS | |
| @@ -507,6 +514,15 @@ static inline int pmd_none(pmd_t pmd) | |||
| 507 | return (pmd_val(pmd) & _SEGMENT_ENTRY_INV) != 0UL; | 514 | return (pmd_val(pmd) & _SEGMENT_ENTRY_INV) != 0UL; |
| 508 | } | 515 | } |
| 509 | 516 | ||
| 517 | static inline int pmd_large(pmd_t pmd) | ||
| 518 | { | ||
| 519 | #ifdef CONFIG_64BIT | ||
| 520 | return !!(pmd_val(pmd) & _SEGMENT_ENTRY_LARGE); | ||
| 521 | #else | ||
| 522 | return 0; | ||
| 523 | #endif | ||
| 524 | } | ||
| 525 | |||
| 510 | static inline int pmd_bad(pmd_t pmd) | 526 | static inline int pmd_bad(pmd_t pmd) |
| 511 | { | 527 | { |
| 512 | unsigned long mask = ~_SEGMENT_ENTRY_ORIGIN & ~_SEGMENT_ENTRY_INV; | 528 | unsigned long mask = ~_SEGMENT_ENTRY_ORIGIN & ~_SEGMENT_ENTRY_INV; |
diff --git a/arch/s390/include/asm/setup.h b/arch/s390/include/asm/setup.h index 55ad134bcedf..f69f76b3447a 100644 --- a/arch/s390/include/asm/setup.h +++ b/arch/s390/include/asm/setup.h | |||
| @@ -71,8 +71,8 @@ extern unsigned int s390_user_mode; | |||
| 71 | #define MACHINE_FLAG_DIAG9C (1UL << 7) | 71 | #define MACHINE_FLAG_DIAG9C (1UL << 7) |
| 72 | #define MACHINE_FLAG_MVCOS (1UL << 8) | 72 | #define MACHINE_FLAG_MVCOS (1UL << 8) |
| 73 | #define MACHINE_FLAG_KVM (1UL << 9) | 73 | #define MACHINE_FLAG_KVM (1UL << 9) |
| 74 | #define MACHINE_FLAG_HPAGE (1UL << 10) | 74 | #define MACHINE_FLAG_EDAT1 (1UL << 10) |
| 75 | #define MACHINE_FLAG_PFMF (1UL << 11) | 75 | #define MACHINE_FLAG_EDAT2 (1UL << 11) |
| 76 | #define MACHINE_FLAG_LPAR (1UL << 12) | 76 | #define MACHINE_FLAG_LPAR (1UL << 12) |
| 77 | #define MACHINE_FLAG_SPP (1UL << 13) | 77 | #define MACHINE_FLAG_SPP (1UL << 13) |
| 78 | #define MACHINE_FLAG_TOPOLOGY (1UL << 14) | 78 | #define MACHINE_FLAG_TOPOLOGY (1UL << 14) |
| @@ -84,6 +84,8 @@ extern unsigned int s390_user_mode; | |||
| 84 | #define MACHINE_IS_LPAR (S390_lowcore.machine_flags & MACHINE_FLAG_LPAR) | 84 | #define MACHINE_IS_LPAR (S390_lowcore.machine_flags & MACHINE_FLAG_LPAR) |
| 85 | 85 | ||
| 86 | #define MACHINE_HAS_DIAG9C (S390_lowcore.machine_flags & MACHINE_FLAG_DIAG9C) | 86 | #define MACHINE_HAS_DIAG9C (S390_lowcore.machine_flags & MACHINE_FLAG_DIAG9C) |
| 87 | #define MACHINE_HAS_PFMF MACHINE_HAS_EDAT1 | ||
| 88 | #define MACHINE_HAS_HPAGE MACHINE_HAS_EDAT1 | ||
| 87 | 89 | ||
| 88 | #ifndef CONFIG_64BIT | 90 | #ifndef CONFIG_64BIT |
| 89 | #define MACHINE_HAS_IEEE (S390_lowcore.machine_flags & MACHINE_FLAG_IEEE) | 91 | #define MACHINE_HAS_IEEE (S390_lowcore.machine_flags & MACHINE_FLAG_IEEE) |
| @@ -92,8 +94,8 @@ extern unsigned int s390_user_mode; | |||
| 92 | #define MACHINE_HAS_DIAG44 (1) | 94 | #define MACHINE_HAS_DIAG44 (1) |
| 93 | #define MACHINE_HAS_MVPG (S390_lowcore.machine_flags & MACHINE_FLAG_MVPG) | 95 | #define MACHINE_HAS_MVPG (S390_lowcore.machine_flags & MACHINE_FLAG_MVPG) |
| 94 | #define MACHINE_HAS_MVCOS (0) | 96 | #define MACHINE_HAS_MVCOS (0) |
| 95 | #define MACHINE_HAS_HPAGE (0) | 97 | #define MACHINE_HAS_EDAT1 (0) |
| 96 | #define MACHINE_HAS_PFMF (0) | 98 | #define MACHINE_HAS_EDAT2 (0) |
| 97 | #define MACHINE_HAS_SPP (0) | 99 | #define MACHINE_HAS_SPP (0) |
| 98 | #define MACHINE_HAS_TOPOLOGY (0) | 100 | #define MACHINE_HAS_TOPOLOGY (0) |
| 99 | #define MACHINE_HAS_TE (0) | 101 | #define MACHINE_HAS_TE (0) |
| @@ -105,8 +107,8 @@ extern unsigned int s390_user_mode; | |||
| 105 | #define MACHINE_HAS_DIAG44 (S390_lowcore.machine_flags & MACHINE_FLAG_DIAG44) | 107 | #define MACHINE_HAS_DIAG44 (S390_lowcore.machine_flags & MACHINE_FLAG_DIAG44) |
| 106 | #define MACHINE_HAS_MVPG (1) | 108 | #define MACHINE_HAS_MVPG (1) |
| 107 | #define MACHINE_HAS_MVCOS (S390_lowcore.machine_flags & MACHINE_FLAG_MVCOS) | 109 | #define MACHINE_HAS_MVCOS (S390_lowcore.machine_flags & MACHINE_FLAG_MVCOS) |
| 108 | #define MACHINE_HAS_HPAGE (S390_lowcore.machine_flags & MACHINE_FLAG_HPAGE) | 110 | #define MACHINE_HAS_EDAT1 (S390_lowcore.machine_flags & MACHINE_FLAG_EDAT1) |
| 109 | #define MACHINE_HAS_PFMF (S390_lowcore.machine_flags & MACHINE_FLAG_PFMF) | 111 | #define MACHINE_HAS_EDAT2 (S390_lowcore.machine_flags & MACHINE_FLAG_EDAT2) |
| 110 | #define MACHINE_HAS_SPP (S390_lowcore.machine_flags & MACHINE_FLAG_SPP) | 112 | #define MACHINE_HAS_SPP (S390_lowcore.machine_flags & MACHINE_FLAG_SPP) |
| 111 | #define MACHINE_HAS_TOPOLOGY (S390_lowcore.machine_flags & MACHINE_FLAG_TOPOLOGY) | 113 | #define MACHINE_HAS_TOPOLOGY (S390_lowcore.machine_flags & MACHINE_FLAG_TOPOLOGY) |
| 112 | #define MACHINE_HAS_TE (S390_lowcore.machine_flags & MACHINE_FLAG_TE) | 114 | #define MACHINE_HAS_TE (S390_lowcore.machine_flags & MACHINE_FLAG_TE) |
diff --git a/arch/s390/include/uapi/asm/chsc.h b/arch/s390/include/uapi/asm/chsc.h index aea451fd182e..1c6a7f85a581 100644 --- a/arch/s390/include/uapi/asm/chsc.h +++ b/arch/s390/include/uapi/asm/chsc.h | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * ioctl interface for /dev/chsc | 2 | * ioctl interface for /dev/chsc |
| 3 | * | 3 | * |
| 4 | * Copyright IBM Corp. 2008 | 4 | * Copyright IBM Corp. 2008, 2012 |
| 5 | * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com> | 5 | * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com> |
| 6 | */ | 6 | */ |
| 7 | 7 | ||
| @@ -9,9 +9,12 @@ | |||
| 9 | #define _ASM_CHSC_H | 9 | #define _ASM_CHSC_H |
| 10 | 10 | ||
| 11 | #include <linux/types.h> | 11 | #include <linux/types.h> |
| 12 | #include <linux/ioctl.h> | ||
| 12 | #include <asm/chpid.h> | 13 | #include <asm/chpid.h> |
| 13 | #include <asm/schid.h> | 14 | #include <asm/schid.h> |
| 14 | 15 | ||
| 16 | #define CHSC_SIZE 0x1000 | ||
| 17 | |||
| 15 | struct chsc_async_header { | 18 | struct chsc_async_header { |
| 16 | __u16 length; | 19 | __u16 length; |
| 17 | __u16 code; | 20 | __u16 code; |
| @@ -23,15 +26,14 @@ struct chsc_async_header { | |||
| 23 | 26 | ||
| 24 | struct chsc_async_area { | 27 | struct chsc_async_area { |
| 25 | struct chsc_async_header header; | 28 | struct chsc_async_header header; |
| 26 | __u8 data[PAGE_SIZE - 16 /* size of chsc_async_header */]; | 29 | __u8 data[CHSC_SIZE - sizeof(struct chsc_async_header)]; |
| 27 | } __attribute__ ((packed)); | 30 | } __attribute__ ((packed)); |
| 28 | 31 | ||
| 29 | |||
| 30 | struct chsc_response_struct { | 32 | struct chsc_response_struct { |
| 31 | __u16 length; | 33 | __u16 length; |
| 32 | __u16 code; | 34 | __u16 code; |
| 33 | __u32 parms; | 35 | __u32 parms; |
| 34 | __u8 data[PAGE_SIZE - 8]; | 36 | __u8 data[CHSC_SIZE - 2 * sizeof(__u16) - sizeof(__u32)]; |
| 35 | } __attribute__ ((packed)); | 37 | } __attribute__ ((packed)); |
| 36 | 38 | ||
| 37 | struct chsc_chp_cd { | 39 | struct chsc_chp_cd { |
diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c index 00d114445068..1f0eee9e7daa 100644 --- a/arch/s390/kernel/early.c +++ b/arch/s390/kernel/early.c | |||
| @@ -283,14 +283,6 @@ static noinline __init void setup_facility_list(void) | |||
| 283 | ARRAY_SIZE(S390_lowcore.stfle_fac_list)); | 283 | ARRAY_SIZE(S390_lowcore.stfle_fac_list)); |
| 284 | } | 284 | } |
| 285 | 285 | ||
| 286 | static noinline __init void setup_hpage(void) | ||
| 287 | { | ||
| 288 | if (!test_facility(2) || !test_facility(8)) | ||
| 289 | return; | ||
| 290 | S390_lowcore.machine_flags |= MACHINE_FLAG_HPAGE; | ||
| 291 | __ctl_set_bit(0, 23); | ||
| 292 | } | ||
| 293 | |||
| 294 | static __init void detect_mvpg(void) | 286 | static __init void detect_mvpg(void) |
| 295 | { | 287 | { |
| 296 | #ifndef CONFIG_64BIT | 288 | #ifndef CONFIG_64BIT |
| @@ -378,10 +370,14 @@ static __init void detect_diag44(void) | |||
| 378 | static __init void detect_machine_facilities(void) | 370 | static __init void detect_machine_facilities(void) |
| 379 | { | 371 | { |
| 380 | #ifdef CONFIG_64BIT | 372 | #ifdef CONFIG_64BIT |
| 373 | if (test_facility(8)) { | ||
| 374 | S390_lowcore.machine_flags |= MACHINE_FLAG_EDAT1; | ||
| 375 | __ctl_set_bit(0, 23); | ||
| 376 | } | ||
| 377 | if (test_facility(78)) | ||
| 378 | S390_lowcore.machine_flags |= MACHINE_FLAG_EDAT2; | ||
| 381 | if (test_facility(3)) | 379 | if (test_facility(3)) |
| 382 | S390_lowcore.machine_flags |= MACHINE_FLAG_IDTE; | 380 | S390_lowcore.machine_flags |= MACHINE_FLAG_IDTE; |
| 383 | if (test_facility(8)) | ||
| 384 | S390_lowcore.machine_flags |= MACHINE_FLAG_PFMF; | ||
| 385 | if (test_facility(27)) | 381 | if (test_facility(27)) |
| 386 | S390_lowcore.machine_flags |= MACHINE_FLAG_MVCOS; | 382 | S390_lowcore.machine_flags |= MACHINE_FLAG_MVCOS; |
| 387 | if (test_facility(40)) | 383 | if (test_facility(40)) |
| @@ -484,7 +480,6 @@ void __init startup_init(void) | |||
| 484 | detect_diag9c(); | 480 | detect_diag9c(); |
| 485 | detect_diag44(); | 481 | detect_diag44(); |
| 486 | detect_machine_facilities(); | 482 | detect_machine_facilities(); |
| 487 | setup_hpage(); | ||
| 488 | setup_topology(); | 483 | setup_topology(); |
| 489 | sclp_facilities_detect(); | 484 | sclp_facilities_detect(); |
| 490 | detect_memory_layout(memory_chunk); | 485 | detect_memory_layout(memory_chunk); |
diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S index 7549985402f7..8f211ad1c695 100644 --- a/arch/s390/kernel/entry64.S +++ b/arch/s390/kernel/entry64.S | |||
| @@ -295,7 +295,7 @@ sysc_sigpending: | |||
| 295 | jno sysc_return | 295 | jno sysc_return |
| 296 | lmg %r2,%r7,__PT_R2(%r11) # load svc arguments | 296 | lmg %r2,%r7,__PT_R2(%r11) # load svc arguments |
| 297 | lghi %r8,0 # svc 0 returns -ENOSYS | 297 | lghi %r8,0 # svc 0 returns -ENOSYS |
| 298 | lh %r1,__PT_INT_CODE+2(%r11) # load new svc number | 298 | llgh %r1,__PT_INT_CODE+2(%r11) # load new svc number |
| 299 | cghi %r1,NR_syscalls | 299 | cghi %r1,NR_syscalls |
| 300 | jnl sysc_nr_ok # invalid svc number -> do svc 0 | 300 | jnl sysc_nr_ok # invalid svc number -> do svc 0 |
| 301 | slag %r8,%r1,2 | 301 | slag %r8,%r1,2 |
diff --git a/arch/s390/kernel/head.S b/arch/s390/kernel/head.S index 805b6686b641..984726cbce16 100644 --- a/arch/s390/kernel/head.S +++ b/arch/s390/kernel/head.S | |||
| @@ -52,7 +52,7 @@ __HEAD | |||
| 52 | .long 0x02000370,0x60000050 # the channel program the PSW | 52 | .long 0x02000370,0x60000050 # the channel program the PSW |
| 53 | .long 0x020003c0,0x60000050 # at location 0 is loaded. | 53 | .long 0x020003c0,0x60000050 # at location 0 is loaded. |
| 54 | .long 0x02000410,0x60000050 # Initial processing starts | 54 | .long 0x02000410,0x60000050 # Initial processing starts |
| 55 | .long 0x02000460,0x60000050 # at 0xf0 = iplstart. | 55 | .long 0x02000460,0x60000050 # at 0x200 = iplstart. |
| 56 | .long 0x020004b0,0x60000050 | 56 | .long 0x020004b0,0x60000050 |
| 57 | .long 0x02000500,0x60000050 | 57 | .long 0x02000500,0x60000050 |
| 58 | .long 0x02000550,0x60000050 | 58 | .long 0x02000550,0x60000050 |
| @@ -62,11 +62,54 @@ __HEAD | |||
| 62 | .long 0x02000690,0x60000050 | 62 | .long 0x02000690,0x60000050 |
| 63 | .long 0x020006e0,0x20000050 | 63 | .long 0x020006e0,0x20000050 |
| 64 | 64 | ||
| 65 | .org 0xf0 | 65 | .org 0x200 |
| 66 | # | ||
| 67 | # subroutine to set architecture mode | ||
| 68 | # | ||
| 69 | .Lsetmode: | ||
| 70 | #ifdef CONFIG_64BIT | ||
| 71 | mvi __LC_AR_MODE_ID,1 # set esame flag | ||
| 72 | slr %r0,%r0 # set cpuid to zero | ||
| 73 | lhi %r1,2 # mode 2 = esame (dump) | ||
| 74 | sigp %r1,%r0,0x12 # switch to esame mode | ||
| 75 | bras %r13,0f | ||
| 76 | .fill 16,4,0x0 | ||
| 77 | 0: lmh %r0,%r15,0(%r13) # clear high-order half of gprs | ||
| 78 | sam31 # switch to 31 bit addressing mode | ||
| 79 | #else | ||
| 80 | mvi __LC_AR_MODE_ID,0 # set ESA flag (mode 0) | ||
| 81 | #endif | ||
| 82 | br %r14 | ||
| 83 | |||
| 84 | # | ||
| 85 | # subroutine to wait for end I/O | ||
| 86 | # | ||
| 87 | .Lirqwait: | ||
| 88 | #ifdef CONFIG_64BIT | ||
| 89 | mvc 0x1f0(16),.Lnewpsw # set up IO interrupt psw | ||
| 90 | lpsw .Lwaitpsw | ||
| 91 | .Lioint: | ||
| 92 | br %r14 | ||
| 93 | .align 8 | ||
| 94 | .Lnewpsw: | ||
| 95 | .quad 0x0000000080000000,.Lioint | ||
| 96 | #else | ||
| 97 | mvc 0x78(8),.Lnewpsw # set up IO interrupt psw | ||
| 98 | lpsw .Lwaitpsw | ||
| 99 | .Lioint: | ||
| 100 | br %r14 | ||
| 101 | .align 8 | ||
| 102 | .Lnewpsw: | ||
| 103 | .long 0x00080000,0x80000000+.Lioint | ||
| 104 | #endif | ||
| 105 | .Lwaitpsw: | ||
| 106 | .long 0x020a0000,0x80000000+.Lioint | ||
| 107 | |||
| 66 | # | 108 | # |
| 67 | # subroutine for loading cards from the reader | 109 | # subroutine for loading cards from the reader |
| 68 | # | 110 | # |
| 69 | .Lloader: | 111 | .Lloader: |
| 112 | la %r4,0(%r14) | ||
| 70 | la %r3,.Lorb # r2 = address of orb into r2 | 113 | la %r3,.Lorb # r2 = address of orb into r2 |
| 71 | la %r5,.Lirb # r4 = address of irb | 114 | la %r5,.Lirb # r4 = address of irb |
| 72 | la %r6,.Lccws | 115 | la %r6,.Lccws |
| @@ -83,9 +126,7 @@ __HEAD | |||
| 83 | ssch 0(%r3) # load chunk of 1600 bytes | 126 | ssch 0(%r3) # load chunk of 1600 bytes |
| 84 | bnz .Llderr | 127 | bnz .Llderr |
| 85 | .Lwait4irq: | 128 | .Lwait4irq: |
| 86 | mvc 0x78(8),.Lnewpsw # set up IO interrupt psw | 129 | bas %r14,.Lirqwait |
| 87 | lpsw .Lwaitpsw | ||
| 88 | .Lioint: | ||
| 89 | c %r1,0xb8 # compare subchannel number | 130 | c %r1,0xb8 # compare subchannel number |
| 90 | bne .Lwait4irq | 131 | bne .Lwait4irq |
| 91 | tsch 0(%r5) | 132 | tsch 0(%r5) |
| @@ -104,7 +145,7 @@ __HEAD | |||
| 104 | sr %r0,%r3 # #ccws*80-residual=#bytes read | 145 | sr %r0,%r3 # #ccws*80-residual=#bytes read |
| 105 | ar %r2,%r0 | 146 | ar %r2,%r0 |
| 106 | 147 | ||
| 107 | br %r14 # r2 contains the total size | 148 | br %r4 # r2 contains the total size |
| 108 | 149 | ||
| 109 | .Lcont: | 150 | .Lcont: |
| 110 | ahi %r2,0x640 # add 0x640 to total size | 151 | ahi %r2,0x640 # add 0x640 to total size |
| @@ -128,10 +169,6 @@ __HEAD | |||
| 128 | .Lloadp:.long 0,0 | 169 | .Lloadp:.long 0,0 |
| 129 | .align 8 | 170 | .align 8 |
| 130 | .Lcrash:.long 0x000a0000,0x00000000 | 171 | .Lcrash:.long 0x000a0000,0x00000000 |
| 131 | .Lnewpsw: | ||
| 132 | .long 0x00080000,0x80000000+.Lioint | ||
| 133 | .Lwaitpsw: | ||
| 134 | .long 0x020a0000,0x80000000+.Lioint | ||
| 135 | 172 | ||
| 136 | .align 8 | 173 | .align 8 |
| 137 | .Lccws: .rept 19 | 174 | .Lccws: .rept 19 |
| @@ -140,6 +177,7 @@ __HEAD | |||
| 140 | .long 0x02200050,0x00000000 | 177 | .long 0x02200050,0x00000000 |
| 141 | 178 | ||
| 142 | iplstart: | 179 | iplstart: |
| 180 | bas %r14,.Lsetmode # Immediately switch to 64 bit mode | ||
| 143 | lh %r1,0xb8 # test if subchannel number | 181 | lh %r1,0xb8 # test if subchannel number |
| 144 | bct %r1,.Lnoload # is valid | 182 | bct %r1,.Lnoload # is valid |
| 145 | l %r1,0xb8 # load ipl subchannel number | 183 | l %r1,0xb8 # load ipl subchannel number |
| @@ -209,8 +247,8 @@ iplstart: | |||
| 209 | # | 247 | # |
| 210 | # reset files in VM reader | 248 | # reset files in VM reader |
| 211 | # | 249 | # |
| 212 | stidp __LC_SAVE_AREA_SYNC # store cpuid | 250 | stidp .Lcpuid # store cpuid |
| 213 | tm __LC_SAVE_AREA_SYNC,0xff# running VM ? | 251 | tm .Lcpuid,0xff # running VM ? |
| 214 | bno .Lnoreset | 252 | bno .Lnoreset |
| 215 | la %r2,.Lreset | 253 | la %r2,.Lreset |
| 216 | lhi %r3,26 | 254 | lhi %r3,26 |
| @@ -222,23 +260,14 @@ iplstart: | |||
| 222 | tm 31(%r5),0xff # bits is set in the schib | 260 | tm 31(%r5),0xff # bits is set in the schib |
| 223 | bz .Lnoreset | 261 | bz .Lnoreset |
| 224 | .Lwaitforirq: | 262 | .Lwaitforirq: |
| 225 | mvc 0x78(8),.Lrdrnewpsw # set up IO interrupt psw | 263 | bas %r14,.Lirqwait # wait for IO interrupt |
| 226 | .Lwaitrdrirq: | ||
| 227 | lpsw .Lrdrwaitpsw | ||
| 228 | .Lrdrint: | ||
| 229 | c %r1,0xb8 # compare subchannel number | 264 | c %r1,0xb8 # compare subchannel number |
| 230 | bne .Lwaitrdrirq | 265 | bne .Lwaitforirq |
| 231 | la %r5,.Lirb | 266 | la %r5,.Lirb |
| 232 | tsch 0(%r5) | 267 | tsch 0(%r5) |
| 233 | .Lnoreset: | 268 | .Lnoreset: |
| 234 | b .Lnoload | 269 | b .Lnoload |
| 235 | 270 | ||
| 236 | .align 8 | ||
| 237 | .Lrdrnewpsw: | ||
| 238 | .long 0x00080000,0x80000000+.Lrdrint | ||
| 239 | .Lrdrwaitpsw: | ||
| 240 | .long 0x020a0000,0x80000000+.Lrdrint | ||
| 241 | |||
| 242 | # | 271 | # |
| 243 | # everything loaded, go for it | 272 | # everything loaded, go for it |
| 244 | # | 273 | # |
| @@ -254,6 +283,8 @@ iplstart: | |||
| 254 | .byte 0xc8,0xd6,0xd3,0xc4 # "change rdr all keep nohold" | 283 | .byte 0xc8,0xd6,0xd3,0xc4 # "change rdr all keep nohold" |
| 255 | .L_eof: .long 0xc5d6c600 /* C'EOF' */ | 284 | .L_eof: .long 0xc5d6c600 /* C'EOF' */ |
| 256 | .L_hdr: .long 0xc8c4d900 /* C'HDR' */ | 285 | .L_hdr: .long 0xc8c4d900 /* C'HDR' */ |
| 286 | .align 8 | ||
| 287 | .Lcpuid:.fill 8,1,0 | ||
| 257 | 288 | ||
| 258 | # | 289 | # |
| 259 | # SALIPL loader support. Based on a patch by Rob van der Heij. | 290 | # SALIPL loader support. Based on a patch by Rob van der Heij. |
| @@ -263,6 +294,7 @@ iplstart: | |||
| 263 | .org 0x800 | 294 | .org 0x800 |
| 264 | ENTRY(start) | 295 | ENTRY(start) |
| 265 | stm %r0,%r15,0x07b0 # store registers | 296 | stm %r0,%r15,0x07b0 # store registers |
| 297 | bas %r14,.Lsetmode # Immediately switch to 64 bit mode | ||
| 266 | basr %r12,%r0 | 298 | basr %r12,%r0 |
| 267 | .base: | 299 | .base: |
| 268 | l %r11,.parm | 300 | l %r11,.parm |
| @@ -343,6 +375,18 @@ ENTRY(startup) | |||
| 343 | ENTRY(startup_kdump) | 375 | ENTRY(startup_kdump) |
| 344 | j .Lep_startup_kdump | 376 | j .Lep_startup_kdump |
| 345 | .Lep_startup_normal: | 377 | .Lep_startup_normal: |
| 378 | #ifdef CONFIG_64BIT | ||
| 379 | mvi __LC_AR_MODE_ID,1 # set esame flag | ||
| 380 | slr %r0,%r0 # set cpuid to zero | ||
| 381 | lhi %r1,2 # mode 2 = esame (dump) | ||
| 382 | sigp %r1,%r0,0x12 # switch to esame mode | ||
| 383 | bras %r13,0f | ||
| 384 | .fill 16,4,0x0 | ||
| 385 | 0: lmh %r0,%r15,0(%r13) # clear high-order half of gprs | ||
| 386 | sam31 # switch to 31 bit addressing mode | ||
| 387 | #else | ||
| 388 | mvi __LC_AR_MODE_ID,0 # set ESA flag (mode 0) | ||
| 389 | #endif | ||
| 346 | basr %r13,0 # get base | 390 | basr %r13,0 # get base |
| 347 | .LPG0: | 391 | .LPG0: |
| 348 | xc 0x200(256),0x200 # partially clear lowcore | 392 | xc 0x200(256),0x200 # partially clear lowcore |
| @@ -410,22 +454,17 @@ ENTRY(startup_kdump) | |||
| 410 | #endif | 454 | #endif |
| 411 | 455 | ||
| 412 | #ifdef CONFIG_64BIT | 456 | #ifdef CONFIG_64BIT |
| 413 | mvi __LC_AR_MODE_ID,1 # set esame flag | 457 | /* Continue with 64bit startup code in head64.S */ |
| 414 | slr %r0,%r0 # set cpuid to zero | ||
| 415 | lhi %r1,2 # mode 2 = esame (dump) | ||
| 416 | sigp %r1,%r0,0x12 # switch to esame mode | ||
| 417 | sam64 # switch to 64 bit mode | 458 | sam64 # switch to 64 bit mode |
| 418 | larl %r13,4f | ||
| 419 | lmh %r0,%r15,0(%r13) # clear high-order half | ||
| 420 | jg startup_continue | 459 | jg startup_continue |
| 421 | 4: .fill 16,4,0x0 | ||
| 422 | #else | 460 | #else |
| 423 | mvi __LC_AR_MODE_ID,0 # set ESA flag (mode 0) | 461 | /* Continue with 31bit startup code in head31.S */ |
| 424 | l %r13,4f-.LPG0(%r13) | 462 | l %r13,4f-.LPG0(%r13) |
| 425 | b 0(%r13) | 463 | b 0(%r13) |
| 426 | .align 8 | 464 | .align 8 |
| 427 | 4: .long startup_continue | 465 | 4: .long startup_continue |
| 428 | #endif | 466 | #endif |
| 467 | |||
| 429 | .align 8 | 468 | .align 8 |
| 430 | 5: .long 0x7fffffff,0xffffffff | 469 | 5: .long 0x7fffffff,0xffffffff |
| 431 | 470 | ||
diff --git a/arch/s390/kernel/head31.S b/arch/s390/kernel/head31.S index a1372ae24ae1..9a99856df1c9 100644 --- a/arch/s390/kernel/head31.S +++ b/arch/s390/kernel/head31.S | |||
| @@ -78,10 +78,7 @@ ENTRY(startup_continue) | |||
| 78 | 78 | ||
| 79 | ENTRY(_ehead) | 79 | ENTRY(_ehead) |
| 80 | 80 | ||
| 81 | #ifdef CONFIG_SHARED_KERNEL | ||
| 82 | .org 0x100000 - 0x11000 # head.o ends at 0x11000 | 81 | .org 0x100000 - 0x11000 # head.o ends at 0x11000 |
| 83 | #endif | ||
| 84 | |||
| 85 | # | 82 | # |
| 86 | # startup-code, running in absolute addressing mode | 83 | # startup-code, running in absolute addressing mode |
| 87 | # | 84 | # |
diff --git a/arch/s390/kernel/head64.S b/arch/s390/kernel/head64.S index c108af28bbe8..b9e25ae2579c 100644 --- a/arch/s390/kernel/head64.S +++ b/arch/s390/kernel/head64.S | |||
| @@ -76,10 +76,7 @@ ENTRY(startup_continue) | |||
| 76 | 76 | ||
| 77 | ENTRY(_ehead) | 77 | ENTRY(_ehead) |
| 78 | 78 | ||
| 79 | #ifdef CONFIG_SHARED_KERNEL | ||
| 80 | .org 0x100000 - 0x11000 # head.o ends at 0x11000 | 79 | .org 0x100000 - 0x11000 # head.o ends at 0x11000 |
| 81 | #endif | ||
| 82 | |||
| 83 | # | 80 | # |
| 84 | # startup-code, running in absolute addressing mode | 81 | # startup-code, running in absolute addressing mode |
| 85 | # | 82 | # |
diff --git a/arch/s390/kernel/module.c b/arch/s390/kernel/module.c index 46412b1d7e1e..4610deafd953 100644 --- a/arch/s390/kernel/module.c +++ b/arch/s390/kernel/module.c | |||
| @@ -44,6 +44,17 @@ | |||
| 44 | #define PLT_ENTRY_SIZE 20 | 44 | #define PLT_ENTRY_SIZE 20 |
| 45 | #endif /* CONFIG_64BIT */ | 45 | #endif /* CONFIG_64BIT */ |
| 46 | 46 | ||
| 47 | #ifdef CONFIG_64BIT | ||
| 48 | void *module_alloc(unsigned long size) | ||
| 49 | { | ||
| 50 | if (PAGE_ALIGN(size) > MODULES_LEN) | ||
| 51 | return NULL; | ||
| 52 | return __vmalloc_node_range(size, 1, MODULES_VADDR, MODULES_END, | ||
| 53 | GFP_KERNEL, PAGE_KERNEL, -1, | ||
| 54 | __builtin_return_address(0)); | ||
| 55 | } | ||
| 56 | #endif | ||
| 57 | |||
| 47 | /* Free memory returned from module_alloc */ | 58 | /* Free memory returned from module_alloc */ |
| 48 | void module_free(struct module *mod, void *module_region) | 59 | void module_free(struct module *mod, void *module_region) |
| 49 | { | 60 | { |
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); | |||
| 105 | struct page *vmemmap; | 105 | struct page *vmemmap; |
| 106 | EXPORT_SYMBOL(vmemmap); | 106 | EXPORT_SYMBOL(vmemmap); |
| 107 | 107 | ||
| 108 | #ifdef CONFIG_64BIT | ||
| 109 | unsigned long MODULES_VADDR; | ||
| 110 | unsigned long MODULES_END; | ||
| 111 | #endif | ||
| 112 | |||
| 108 | /* An array with a pointer to the lowcore of every CPU. */ | 113 | /* An array with a pointer to the lowcore of every CPU. */ |
| 109 | struct _lowcore *lowcore_ptr[NR_CPUS]; | 114 | struct _lowcore *lowcore_ptr[NR_CPUS]; |
| 110 | EXPORT_SYMBOL(lowcore_ptr); | 115 | EXPORT_SYMBOL(lowcore_ptr); |
| @@ -544,19 +549,23 @@ static void __init setup_memory_end(void) | |||
| 544 | 549 | ||
| 545 | /* Choose kernel address space layout: 2, 3, or 4 levels. */ | 550 | /* Choose kernel address space layout: 2, 3, or 4 levels. */ |
| 546 | #ifdef CONFIG_64BIT | 551 | #ifdef CONFIG_64BIT |
| 547 | vmalloc_size = VMALLOC_END ?: 128UL << 30; | 552 | vmalloc_size = VMALLOC_END ?: (128UL << 30) - MODULES_LEN; |
| 548 | tmp = (memory_end ?: real_memory_size) / PAGE_SIZE; | 553 | tmp = (memory_end ?: real_memory_size) / PAGE_SIZE; |
| 549 | tmp = tmp * (sizeof(struct page) + PAGE_SIZE) + vmalloc_size; | 554 | tmp = tmp * (sizeof(struct page) + PAGE_SIZE) + vmalloc_size; |
| 550 | if (tmp <= (1UL << 42)) | 555 | if (tmp <= (1UL << 42)) |
| 551 | vmax = 1UL << 42; /* 3-level kernel page table */ | 556 | vmax = 1UL << 42; /* 3-level kernel page table */ |
| 552 | else | 557 | else |
| 553 | vmax = 1UL << 53; /* 4-level kernel page table */ | 558 | vmax = 1UL << 53; /* 4-level kernel page table */ |
| 559 | /* module area is at the end of the kernel address space. */ | ||
| 560 | MODULES_END = vmax; | ||
| 561 | MODULES_VADDR = MODULES_END - MODULES_LEN; | ||
| 562 | VMALLOC_END = MODULES_VADDR; | ||
| 554 | #else | 563 | #else |
| 555 | vmalloc_size = VMALLOC_END ?: 96UL << 20; | 564 | vmalloc_size = VMALLOC_END ?: 96UL << 20; |
| 556 | vmax = 1UL << 31; /* 2-level kernel page table */ | 565 | vmax = 1UL << 31; /* 2-level kernel page table */ |
| 557 | #endif | ||
| 558 | /* vmalloc area is at the end of the kernel address space. */ | 566 | /* vmalloc area is at the end of the kernel address space. */ |
| 559 | VMALLOC_END = vmax; | 567 | VMALLOC_END = vmax; |
| 568 | #endif | ||
| 560 | VMALLOC_START = vmax - vmalloc_size; | 569 | VMALLOC_START = vmax - vmalloc_size; |
| 561 | 570 | ||
| 562 | /* Split remaining virtual space between 1:1 mapping & vmemmap array */ | 571 | /* Split remaining virtual space between 1:1 mapping & vmemmap array */ |
| @@ -768,6 +777,40 @@ static void __init reserve_crashkernel(void) | |||
| 768 | #endif | 777 | #endif |
| 769 | } | 778 | } |
| 770 | 779 | ||
| 780 | static void __init init_storage_keys(unsigned long start, unsigned long end) | ||
| 781 | { | ||
| 782 | unsigned long boundary, function, size; | ||
| 783 | |||
| 784 | while (start < end) { | ||
| 785 | if (MACHINE_HAS_EDAT2) { | ||
| 786 | /* set storage keys for a 2GB frame */ | ||
| 787 | function = 0x22000 | PAGE_DEFAULT_KEY; | ||
| 788 | size = 1UL << 31; | ||
| 789 | boundary = (start + size) & ~(size - 1); | ||
| 790 | if (boundary <= end) { | ||
| 791 | do { | ||
| 792 | start = pfmf(function, start); | ||
| 793 | } while (start < boundary); | ||
| 794 | continue; | ||
| 795 | } | ||
| 796 | } | ||
| 797 | if (MACHINE_HAS_EDAT1) { | ||
| 798 | /* set storage keys for a 1MB frame */ | ||
| 799 | function = 0x21000 | PAGE_DEFAULT_KEY; | ||
| 800 | size = 1UL << 20; | ||
| 801 | boundary = (start + size) & ~(size - 1); | ||
| 802 | if (boundary <= end) { | ||
| 803 | do { | ||
| 804 | start = pfmf(function, start); | ||
| 805 | } while (start < boundary); | ||
| 806 | continue; | ||
| 807 | } | ||
| 808 | } | ||
| 809 | page_set_storage_key(start, PAGE_DEFAULT_KEY, 0); | ||
| 810 | start += PAGE_SIZE; | ||
| 811 | } | ||
| 812 | } | ||
| 813 | |||
| 771 | static void __init setup_memory(void) | 814 | static void __init setup_memory(void) |
| 772 | { | 815 | { |
| 773 | unsigned long bootmap_size; | 816 | unsigned long bootmap_size; |
| @@ -846,9 +889,7 @@ static void __init setup_memory(void) | |||
| 846 | memblock_add_node(PFN_PHYS(start_chunk), | 889 | memblock_add_node(PFN_PHYS(start_chunk), |
| 847 | PFN_PHYS(end_chunk - start_chunk), 0); | 890 | PFN_PHYS(end_chunk - start_chunk), 0); |
| 848 | pfn = max(start_chunk, start_pfn); | 891 | pfn = max(start_chunk, start_pfn); |
| 849 | for (; pfn < end_chunk; pfn++) | 892 | init_storage_keys(PFN_PHYS(pfn), PFN_PHYS(end_chunk)); |
| 850 | page_set_storage_key(PFN_PHYS(pfn), | ||
| 851 | PAGE_DEFAULT_KEY, 0); | ||
| 852 | } | 893 | } |
| 853 | 894 | ||
| 854 | psw_set_key(PAGE_DEFAULT_KEY); | 895 | psw_set_key(PAGE_DEFAULT_KEY); |
diff --git a/arch/s390/mm/Makefile b/arch/s390/mm/Makefile index 0f5536b0c1a1..1bea6d1f55ab 100644 --- a/arch/s390/mm/Makefile +++ b/arch/s390/mm/Makefile | |||
| @@ -7,3 +7,4 @@ obj-y := init.o fault.o extmem.o mmap.o vmem.o pgtable.o maccess.o \ | |||
| 7 | obj-$(CONFIG_CMM) += cmm.o | 7 | obj-$(CONFIG_CMM) += cmm.o |
| 8 | obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o | 8 | obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o |
| 9 | obj-$(CONFIG_DEBUG_SET_MODULE_RONX) += pageattr.o | 9 | obj-$(CONFIG_DEBUG_SET_MODULE_RONX) += pageattr.o |
| 10 | obj-$(CONFIG_S390_PTDUMP) += dump_pagetables.o | ||
diff --git a/arch/s390/mm/dump_pagetables.c b/arch/s390/mm/dump_pagetables.c new file mode 100644 index 000000000000..cbc6668acb85 --- /dev/null +++ b/arch/s390/mm/dump_pagetables.c | |||
| @@ -0,0 +1,226 @@ | |||
| 1 | #include <linux/seq_file.h> | ||
| 2 | #include <linux/debugfs.h> | ||
| 3 | #include <linux/module.h> | ||
| 4 | #include <linux/mm.h> | ||
| 5 | #include <asm/sections.h> | ||
| 6 | #include <asm/pgtable.h> | ||
| 7 | |||
| 8 | static unsigned long max_addr; | ||
| 9 | |||
| 10 | struct addr_marker { | ||
| 11 | unsigned long start_address; | ||
| 12 | const char *name; | ||
| 13 | }; | ||
| 14 | |||
| 15 | enum address_markers_idx { | ||
| 16 | IDENTITY_NR = 0, | ||
| 17 | KERNEL_START_NR, | ||
| 18 | KERNEL_END_NR, | ||
| 19 | VMEMMAP_NR, | ||
| 20 | VMALLOC_NR, | ||
| 21 | #ifdef CONFIG_64BIT | ||
| 22 | MODULES_NR, | ||
| 23 | #endif | ||
| 24 | }; | ||
| 25 | |||
| 26 | static struct addr_marker address_markers[] = { | ||
| 27 | [IDENTITY_NR] = {0, "Identity Mapping"}, | ||
| 28 | [KERNEL_START_NR] = {(unsigned long)&_stext, "Kernel Image Start"}, | ||
| 29 | [KERNEL_END_NR] = {(unsigned long)&_end, "Kernel Image End"}, | ||
| 30 | [VMEMMAP_NR] = {0, "vmemmap Area"}, | ||
| 31 | [VMALLOC_NR] = {0, "vmalloc Area"}, | ||
| 32 | #ifdef CONFIG_64BIT | ||
| 33 | [MODULES_NR] = {0, "Modules Area"}, | ||
| 34 | #endif | ||
| 35 | { -1, NULL } | ||
| 36 | }; | ||
| 37 | |||
| 38 | struct pg_state { | ||
| 39 | int level; | ||
| 40 | unsigned int current_prot; | ||
| 41 | unsigned long start_address; | ||
| 42 | unsigned long current_address; | ||
| 43 | const struct addr_marker *marker; | ||
| 44 | }; | ||
| 45 | |||
| 46 | static void print_prot(struct seq_file *m, unsigned int pr, int level) | ||
| 47 | { | ||
| 48 | static const char * const level_name[] = | ||
| 49 | { "ASCE", "PGD", "PUD", "PMD", "PTE" }; | ||
| 50 | |||
| 51 | seq_printf(m, "%s ", level_name[level]); | ||
| 52 | if (pr & _PAGE_INVALID) | ||
| 53 | seq_printf(m, "I\n"); | ||
| 54 | else | ||
| 55 | seq_printf(m, "%s\n", pr & _PAGE_RO ? "RO" : "RW"); | ||
| 56 | } | ||
| 57 | |||
| 58 | static void note_page(struct seq_file *m, struct pg_state *st, | ||
| 59 | unsigned int new_prot, int level) | ||
| 60 | { | ||
| 61 | static const char units[] = "KMGTPE"; | ||
| 62 | int width = sizeof(unsigned long) * 2; | ||
| 63 | const char *unit = units; | ||
| 64 | unsigned int prot, cur; | ||
| 65 | unsigned long delta; | ||
| 66 | |||
| 67 | /* | ||
| 68 | * If we have a "break" in the series, we need to flush the state | ||
| 69 | * that we have now. "break" is either changing perms, levels or | ||
| 70 | * address space marker. | ||
| 71 | */ | ||
| 72 | prot = new_prot; | ||
| 73 | cur = st->current_prot; | ||
| 74 | |||
| 75 | if (!st->level) { | ||
| 76 | /* First entry */ | ||
| 77 | st->current_prot = new_prot; | ||
| 78 | st->level = level; | ||
| 79 | st->marker = address_markers; | ||
| 80 | seq_printf(m, "---[ %s ]---\n", st->marker->name); | ||
| 81 | } else if (prot != cur || level != st->level || | ||
| 82 | st->current_address >= st->marker[1].start_address) { | ||
| 83 | /* Print the actual finished series */ | ||
| 84 | seq_printf(m, "0x%0*lx-0x%0*lx", | ||
| 85 | width, st->start_address, | ||
| 86 | width, st->current_address); | ||
| 87 | delta = (st->current_address - st->start_address) >> 10; | ||
| 88 | while (!(delta & 0x3ff) && unit[1]) { | ||
| 89 | delta >>= 10; | ||
| 90 | unit++; | ||
| 91 | } | ||
| 92 | seq_printf(m, "%9lu%c ", delta, *unit); | ||
| 93 | print_prot(m, st->current_prot, st->level); | ||
| 94 | if (st->current_address >= st->marker[1].start_address) { | ||
| 95 | st->marker++; | ||
| 96 | seq_printf(m, "---[ %s ]---\n", st->marker->name); | ||
| 97 | } | ||
| 98 | st->start_address = st->current_address; | ||
| 99 | st->current_prot = new_prot; | ||
| 100 | st->level = level; | ||
| 101 | } | ||
| 102 | } | ||
| 103 | |||
| 104 | /* | ||
| 105 | * The actual page table walker functions. In order to keep the implementation | ||
| 106 | * of print_prot() short, we only check and pass _PAGE_INVALID and _PAGE_RO | ||
| 107 | * flags to note_page() if a region, segment or page table entry is invalid or | ||
| 108 | * read-only. | ||
| 109 | * After all it's just a hint that the current level being walked contains an | ||
| 110 | * invalid or read-only entry. | ||
| 111 | */ | ||
| 112 | static void walk_pte_level(struct seq_file *m, struct pg_state *st, | ||
| 113 | pmd_t *pmd, unsigned long addr) | ||
| 114 | { | ||
| 115 | unsigned int prot; | ||
| 116 | pte_t *pte; | ||
| 117 | int i; | ||
| 118 | |||
| 119 | for (i = 0; i < PTRS_PER_PTE && addr < max_addr; i++) { | ||
| 120 | st->current_address = addr; | ||
| 121 | pte = pte_offset_kernel(pmd, addr); | ||
| 122 | prot = pte_val(*pte) & (_PAGE_RO | _PAGE_INVALID); | ||
| 123 | note_page(m, st, prot, 4); | ||
| 124 | addr += PAGE_SIZE; | ||
| 125 | } | ||
| 126 | } | ||
| 127 | |||
| 128 | static void walk_pmd_level(struct seq_file *m, struct pg_state *st, | ||
| 129 | pud_t *pud, unsigned long addr) | ||
| 130 | { | ||
| 131 | unsigned int prot; | ||
| 132 | pmd_t *pmd; | ||
| 133 | int i; | ||
| 134 | |||
| 135 | for (i = 0; i < PTRS_PER_PMD && addr < max_addr; i++) { | ||
| 136 | st->current_address = addr; | ||
| 137 | pmd = pmd_offset(pud, addr); | ||
| 138 | if (!pmd_none(*pmd)) { | ||
| 139 | if (pmd_large(*pmd)) { | ||
| 140 | prot = pmd_val(*pmd) & _SEGMENT_ENTRY_RO; | ||
| 141 | note_page(m, st, prot, 3); | ||
| 142 | } else | ||
| 143 | walk_pte_level(m, st, pmd, addr); | ||
| 144 | } else | ||
| 145 | note_page(m, st, _PAGE_INVALID, 3); | ||
| 146 | addr += PMD_SIZE; | ||
| 147 | } | ||
| 148 | } | ||
| 149 | |||
| 150 | static void walk_pud_level(struct seq_file *m, struct pg_state *st, | ||
| 151 | pgd_t *pgd, unsigned long addr) | ||
| 152 | { | ||
| 153 | pud_t *pud; | ||
| 154 | int i; | ||
| 155 | |||
| 156 | for (i = 0; i < PTRS_PER_PUD && addr < max_addr; i++) { | ||
| 157 | st->current_address = addr; | ||
| 158 | pud = pud_offset(pgd, addr); | ||
| 159 | if (!pud_none(*pud)) | ||
| 160 | walk_pmd_level(m, st, pud, addr); | ||
| 161 | else | ||
| 162 | note_page(m, st, _PAGE_INVALID, 2); | ||
| 163 | addr += PUD_SIZE; | ||
| 164 | } | ||
| 165 | } | ||
| 166 | |||
| 167 | static void walk_pgd_level(struct seq_file *m) | ||
| 168 | { | ||
| 169 | unsigned long addr = 0; | ||
| 170 | struct pg_state st; | ||
| 171 | pgd_t *pgd; | ||
| 172 | int i; | ||
| 173 | |||
| 174 | memset(&st, 0, sizeof(st)); | ||
| 175 | for (i = 0; i < PTRS_PER_PGD && addr < max_addr; i++) { | ||
| 176 | st.current_address = addr; | ||
| 177 | pgd = pgd_offset_k(addr); | ||
| 178 | if (!pgd_none(*pgd)) | ||
| 179 | walk_pud_level(m, &st, pgd, addr); | ||
| 180 | else | ||
| 181 | note_page(m, &st, _PAGE_INVALID, 1); | ||
| 182 | addr += PGDIR_SIZE; | ||
| 183 | } | ||
| 184 | /* Flush out the last page */ | ||
| 185 | st.current_address = max_addr; | ||
| 186 | note_page(m, &st, 0, 0); | ||
| 187 | } | ||
| 188 | |||
| 189 | static int ptdump_show(struct seq_file *m, void *v) | ||
| 190 | { | ||
| 191 | walk_pgd_level(m); | ||
| 192 | return 0; | ||
| 193 | } | ||
| 194 | |||
| 195 | static int ptdump_open(struct inode *inode, struct file *filp) | ||
| 196 | { | ||
| 197 | return single_open(filp, ptdump_show, NULL); | ||
| 198 | } | ||
| 199 | |||
| 200 | static const struct file_operations ptdump_fops = { | ||
| 201 | .open = ptdump_open, | ||
| 202 | .read = seq_read, | ||
| 203 | .llseek = seq_lseek, | ||
| 204 | .release = single_release, | ||
| 205 | }; | ||
| 206 | |||
| 207 | static int pt_dump_init(void) | ||
| 208 | { | ||
| 209 | /* | ||
| 210 | * Figure out the maximum virtual address being accessible with the | ||
| 211 | * kernel ASCE. We need this to keep the page table walker functions | ||
| 212 | * from accessing non-existent entries. | ||
| 213 | */ | ||
| 214 | #ifdef CONFIG_32BIT | ||
| 215 | max_addr = 1UL << 31; | ||
| 216 | #else | ||
| 217 | max_addr = (S390_lowcore.kernel_asce & _REGION_ENTRY_TYPE_MASK) >> 2; | ||
| 218 | max_addr = 1UL << (max_addr * 11 + 31); | ||
| 219 | address_markers[MODULES_NR].start_address = MODULES_VADDR; | ||
| 220 | #endif | ||
| 221 | address_markers[VMEMMAP_NR].start_address = (unsigned long) vmemmap; | ||
| 222 | address_markers[VMALLOC_NR].start_address = VMALLOC_START; | ||
| 223 | debugfs_create_file("kernel_page_tables", 0400, NULL, NULL, &ptdump_fops); | ||
| 224 | return 0; | ||
| 225 | } | ||
| 226 | device_initcall(pt_dump_init); | ||
diff --git a/arch/s390/mm/pageattr.c b/arch/s390/mm/pageattr.c index b36537a5f43e..00be01c4b4f3 100644 --- a/arch/s390/mm/pageattr.c +++ b/arch/s390/mm/pageattr.c | |||
| @@ -8,25 +8,38 @@ | |||
| 8 | #include <asm/cacheflush.h> | 8 | #include <asm/cacheflush.h> |
| 9 | #include <asm/pgtable.h> | 9 | #include <asm/pgtable.h> |
| 10 | 10 | ||
| 11 | static pte_t *walk_page_table(unsigned long addr) | ||
| 12 | { | ||
| 13 | pgd_t *pgdp; | ||
| 14 | pud_t *pudp; | ||
| 15 | pmd_t *pmdp; | ||
| 16 | pte_t *ptep; | ||
| 17 | |||
| 18 | pgdp = pgd_offset_k(addr); | ||
| 19 | if (pgd_none(*pgdp)) | ||
| 20 | return NULL; | ||
| 21 | pudp = pud_offset(pgdp, addr); | ||
| 22 | if (pud_none(*pudp)) | ||
| 23 | return NULL; | ||
| 24 | pmdp = pmd_offset(pudp, addr); | ||
| 25 | if (pmd_none(*pmdp) || pmd_large(*pmdp)) | ||
| 26 | return NULL; | ||
| 27 | ptep = pte_offset_kernel(pmdp, addr); | ||
| 28 | if (pte_none(*ptep)) | ||
| 29 | return NULL; | ||
| 30 | return ptep; | ||
| 31 | } | ||
| 32 | |||
| 11 | static void change_page_attr(unsigned long addr, int numpages, | 33 | static void change_page_attr(unsigned long addr, int numpages, |
| 12 | pte_t (*set) (pte_t)) | 34 | pte_t (*set) (pte_t)) |
| 13 | { | 35 | { |
| 14 | pte_t *ptep, pte; | 36 | pte_t *ptep, pte; |
| 15 | pmd_t *pmdp; | ||
| 16 | pud_t *pudp; | ||
| 17 | pgd_t *pgdp; | ||
| 18 | int i; | 37 | int i; |
| 19 | 38 | ||
| 20 | for (i = 0; i < numpages; i++) { | 39 | for (i = 0; i < numpages; i++) { |
| 21 | pgdp = pgd_offset(&init_mm, addr); | 40 | ptep = walk_page_table(addr); |
| 22 | pudp = pud_offset(pgdp, addr); | 41 | if (WARN_ON_ONCE(!ptep)) |
| 23 | pmdp = pmd_offset(pudp, addr); | 42 | break; |
| 24 | if (pmd_huge(*pmdp)) { | ||
| 25 | WARN_ON_ONCE(1); | ||
| 26 | continue; | ||
| 27 | } | ||
| 28 | ptep = pte_offset_kernel(pmdp, addr); | ||
| 29 | |||
| 30 | pte = *ptep; | 43 | pte = *ptep; |
| 31 | pte = set(pte); | 44 | pte = set(pte); |
| 32 | __ptep_ipte(addr, ptep); | 45 | __ptep_ipte(addr, ptep); |
| @@ -40,21 +53,18 @@ int set_memory_ro(unsigned long addr, int numpages) | |||
| 40 | change_page_attr(addr, numpages, pte_wrprotect); | 53 | change_page_attr(addr, numpages, pte_wrprotect); |
| 41 | return 0; | 54 | return 0; |
| 42 | } | 55 | } |
| 43 | EXPORT_SYMBOL_GPL(set_memory_ro); | ||
| 44 | 56 | ||
| 45 | int set_memory_rw(unsigned long addr, int numpages) | 57 | int set_memory_rw(unsigned long addr, int numpages) |
| 46 | { | 58 | { |
| 47 | change_page_attr(addr, numpages, pte_mkwrite); | 59 | change_page_attr(addr, numpages, pte_mkwrite); |
| 48 | return 0; | 60 | return 0; |
| 49 | } | 61 | } |
| 50 | EXPORT_SYMBOL_GPL(set_memory_rw); | ||
| 51 | 62 | ||
| 52 | /* not possible */ | 63 | /* not possible */ |
| 53 | int set_memory_nx(unsigned long addr, int numpages) | 64 | int set_memory_nx(unsigned long addr, int numpages) |
| 54 | { | 65 | { |
| 55 | return 0; | 66 | return 0; |
| 56 | } | 67 | } |
| 57 | EXPORT_SYMBOL_GPL(set_memory_nx); | ||
| 58 | 68 | ||
| 59 | int set_memory_x(unsigned long addr, int numpages) | 69 | int set_memory_x(unsigned long addr, int numpages) |
| 60 | { | 70 | { |
diff --git a/arch/s390/mm/vmem.c b/arch/s390/mm/vmem.c index c22abf900c9e..387c7c60b5b8 100644 --- a/arch/s390/mm/vmem.c +++ b/arch/s390/mm/vmem.c | |||
| @@ -79,7 +79,8 @@ static pte_t __ref *vmem_pte_alloc(unsigned long address) | |||
| 79 | */ | 79 | */ |
| 80 | static int vmem_add_mem(unsigned long start, unsigned long size, int ro) | 80 | static int vmem_add_mem(unsigned long start, unsigned long size, int ro) |
| 81 | { | 81 | { |
| 82 | unsigned long address; | 82 | unsigned long end = start + size; |
| 83 | unsigned long address = start; | ||
| 83 | pgd_t *pg_dir; | 84 | pgd_t *pg_dir; |
| 84 | pud_t *pu_dir; | 85 | pud_t *pu_dir; |
| 85 | pmd_t *pm_dir; | 86 | pmd_t *pm_dir; |
| @@ -87,7 +88,7 @@ static int vmem_add_mem(unsigned long start, unsigned long size, int ro) | |||
| 87 | pte_t pte; | 88 | pte_t pte; |
| 88 | int ret = -ENOMEM; | 89 | int ret = -ENOMEM; |
| 89 | 90 | ||
| 90 | for (address = start; address < start + size; address += PAGE_SIZE) { | 91 | while (address < end) { |
| 91 | pg_dir = pgd_offset_k(address); | 92 | pg_dir = pgd_offset_k(address); |
| 92 | if (pgd_none(*pg_dir)) { | 93 | if (pgd_none(*pg_dir)) { |
| 93 | pu_dir = vmem_pud_alloc(); | 94 | pu_dir = vmem_pud_alloc(); |
| @@ -108,12 +109,11 @@ static int vmem_add_mem(unsigned long start, unsigned long size, int ro) | |||
| 108 | pm_dir = pmd_offset(pu_dir, address); | 109 | pm_dir = pmd_offset(pu_dir, address); |
| 109 | 110 | ||
| 110 | #if defined(CONFIG_64BIT) && !defined(CONFIG_DEBUG_PAGEALLOC) | 111 | #if defined(CONFIG_64BIT) && !defined(CONFIG_DEBUG_PAGEALLOC) |
| 111 | if (MACHINE_HAS_HPAGE && !(address & ~HPAGE_MASK) && | 112 | if (MACHINE_HAS_EDAT1 && pmd_none(*pm_dir) && address && |
| 112 | (address + HPAGE_SIZE <= start + size) && | 113 | !(address & ~PMD_MASK) && (address + PMD_SIZE <= end)) { |
| 113 | (address >= HPAGE_SIZE)) { | ||
| 114 | pte_val(pte) |= _SEGMENT_ENTRY_LARGE; | 114 | pte_val(pte) |= _SEGMENT_ENTRY_LARGE; |
| 115 | pmd_val(*pm_dir) = pte_val(pte); | 115 | pmd_val(*pm_dir) = pte_val(pte); |
| 116 | address += HPAGE_SIZE - PAGE_SIZE; | 116 | address += PMD_SIZE; |
| 117 | continue; | 117 | continue; |
| 118 | } | 118 | } |
| 119 | #endif | 119 | #endif |
| @@ -126,10 +126,11 @@ static int vmem_add_mem(unsigned long start, unsigned long size, int ro) | |||
| 126 | 126 | ||
| 127 | pt_dir = pte_offset_kernel(pm_dir, address); | 127 | pt_dir = pte_offset_kernel(pm_dir, address); |
| 128 | *pt_dir = pte; | 128 | *pt_dir = pte; |
| 129 | address += PAGE_SIZE; | ||
| 129 | } | 130 | } |
| 130 | ret = 0; | 131 | ret = 0; |
| 131 | out: | 132 | out: |
| 132 | flush_tlb_kernel_range(start, start + size); | 133 | flush_tlb_kernel_range(start, end); |
| 133 | return ret; | 134 | return ret; |
| 134 | } | 135 | } |
| 135 | 136 | ||
| @@ -139,7 +140,8 @@ out: | |||
| 139 | */ | 140 | */ |
| 140 | static void vmem_remove_range(unsigned long start, unsigned long size) | 141 | static void vmem_remove_range(unsigned long start, unsigned long size) |
| 141 | { | 142 | { |
| 142 | unsigned long address; | 143 | unsigned long end = start + size; |
| 144 | unsigned long address = start; | ||
| 143 | pgd_t *pg_dir; | 145 | pgd_t *pg_dir; |
| 144 | pud_t *pu_dir; | 146 | pud_t *pu_dir; |
| 145 | pmd_t *pm_dir; | 147 | pmd_t *pm_dir; |
| @@ -147,25 +149,32 @@ static void vmem_remove_range(unsigned long start, unsigned long size) | |||
| 147 | pte_t pte; | 149 | pte_t pte; |
| 148 | 150 | ||
| 149 | pte_val(pte) = _PAGE_TYPE_EMPTY; | 151 | pte_val(pte) = _PAGE_TYPE_EMPTY; |
| 150 | for (address = start; address < start + size; address += PAGE_SIZE) { | 152 | while (address < end) { |
| 151 | pg_dir = pgd_offset_k(address); | 153 | pg_dir = pgd_offset_k(address); |
| 154 | if (pgd_none(*pg_dir)) { | ||
| 155 | address += PGDIR_SIZE; | ||
| 156 | continue; | ||
| 157 | } | ||
| 152 | pu_dir = pud_offset(pg_dir, address); | 158 | pu_dir = pud_offset(pg_dir, address); |
| 153 | if (pud_none(*pu_dir)) | 159 | if (pud_none(*pu_dir)) { |
| 160 | address += PUD_SIZE; | ||
| 154 | continue; | 161 | continue; |
| 162 | } | ||
| 155 | pm_dir = pmd_offset(pu_dir, address); | 163 | pm_dir = pmd_offset(pu_dir, address); |
| 156 | if (pmd_none(*pm_dir)) | 164 | if (pmd_none(*pm_dir)) { |
| 165 | address += PMD_SIZE; | ||
| 157 | continue; | 166 | continue; |
| 158 | 167 | } | |
| 159 | if (pmd_huge(*pm_dir)) { | 168 | if (pmd_large(*pm_dir)) { |
| 160 | pmd_clear(pm_dir); | 169 | pmd_clear(pm_dir); |
| 161 | address += HPAGE_SIZE - PAGE_SIZE; | 170 | address += PMD_SIZE; |
| 162 | continue; | 171 | continue; |
| 163 | } | 172 | } |
| 164 | |||
| 165 | pt_dir = pte_offset_kernel(pm_dir, address); | 173 | pt_dir = pte_offset_kernel(pm_dir, address); |
| 166 | *pt_dir = pte; | 174 | *pt_dir = pte; |
| 175 | address += PAGE_SIZE; | ||
| 167 | } | 176 | } |
| 168 | flush_tlb_kernel_range(start, start + size); | 177 | flush_tlb_kernel_range(start, end); |
| 169 | } | 178 | } |
| 170 | 179 | ||
| 171 | /* | 180 | /* |
| @@ -330,8 +339,8 @@ void __init vmem_map_init(void) | |||
| 330 | unsigned long start, end; | 339 | unsigned long start, end; |
| 331 | int i; | 340 | int i; |
| 332 | 341 | ||
| 333 | ro_start = ((unsigned long)&_stext) & PAGE_MASK; | 342 | ro_start = PFN_ALIGN((unsigned long)&_stext); |
| 334 | ro_end = PFN_ALIGN((unsigned long)&_eshared); | 343 | ro_end = (unsigned long)&_eshared & PAGE_MASK; |
| 335 | for (i = 0; i < MEMORY_CHUNKS && memory_chunk[i].size > 0; i++) { | 344 | for (i = 0; i < MEMORY_CHUNKS && memory_chunk[i].size > 0; i++) { |
| 336 | if (memory_chunk[i].type == CHUNK_CRASHK || | 345 | if (memory_chunk[i].type == CHUNK_CRASHK || |
| 337 | memory_chunk[i].type == CHUNK_OLDMEM) | 346 | memory_chunk[i].type == CHUNK_OLDMEM) |
diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c index a5a55da2a1ac..b6ad0de07930 100644 --- a/drivers/s390/block/dcssblk.c +++ b/drivers/s390/block/dcssblk.c | |||
| @@ -69,23 +69,9 @@ static ssize_t dcssblk_add_store(struct device * dev, struct device_attribute *a | |||
| 69 | size_t count); | 69 | size_t count); |
| 70 | static ssize_t dcssblk_remove_store(struct device * dev, struct device_attribute *attr, const char * buf, | 70 | static ssize_t dcssblk_remove_store(struct device * dev, struct device_attribute *attr, const char * buf, |
| 71 | size_t count); | 71 | size_t count); |
| 72 | static ssize_t dcssblk_save_store(struct device * dev, struct device_attribute *attr, const char * buf, | ||
| 73 | size_t count); | ||
| 74 | static ssize_t dcssblk_save_show(struct device *dev, struct device_attribute *attr, char *buf); | ||
| 75 | static ssize_t dcssblk_shared_store(struct device * dev, struct device_attribute *attr, const char * buf, | ||
| 76 | size_t count); | ||
| 77 | static ssize_t dcssblk_shared_show(struct device *dev, struct device_attribute *attr, char *buf); | ||
| 78 | static ssize_t dcssblk_seglist_show(struct device *dev, | ||
| 79 | struct device_attribute *attr, | ||
| 80 | char *buf); | ||
| 81 | 72 | ||
| 82 | static DEVICE_ATTR(add, S_IWUSR, NULL, dcssblk_add_store); | 73 | static DEVICE_ATTR(add, S_IWUSR, NULL, dcssblk_add_store); |
| 83 | static DEVICE_ATTR(remove, S_IWUSR, NULL, dcssblk_remove_store); | 74 | static DEVICE_ATTR(remove, S_IWUSR, NULL, dcssblk_remove_store); |
| 84 | static DEVICE_ATTR(save, S_IWUSR | S_IRUSR, dcssblk_save_show, | ||
| 85 | dcssblk_save_store); | ||
| 86 | static DEVICE_ATTR(shared, S_IWUSR | S_IRUSR, dcssblk_shared_show, | ||
| 87 | dcssblk_shared_store); | ||
| 88 | static DEVICE_ATTR(seglist, S_IRUSR, dcssblk_seglist_show, NULL); | ||
| 89 | 75 | ||
| 90 | static struct device *dcssblk_root_dev; | 76 | static struct device *dcssblk_root_dev; |
| 91 | 77 | ||
| @@ -416,6 +402,8 @@ out: | |||
| 416 | up_write(&dcssblk_devices_sem); | 402 | up_write(&dcssblk_devices_sem); |
| 417 | return rc; | 403 | return rc; |
| 418 | } | 404 | } |
| 405 | static DEVICE_ATTR(shared, S_IWUSR | S_IRUSR, dcssblk_shared_show, | ||
| 406 | dcssblk_shared_store); | ||
| 419 | 407 | ||
| 420 | /* | 408 | /* |
| 421 | * device attribute for save operation on current copy | 409 | * device attribute for save operation on current copy |
| @@ -476,6 +464,8 @@ dcssblk_save_store(struct device *dev, struct device_attribute *attr, const char | |||
| 476 | up_write(&dcssblk_devices_sem); | 464 | up_write(&dcssblk_devices_sem); |
| 477 | return count; | 465 | return count; |
| 478 | } | 466 | } |
| 467 | static DEVICE_ATTR(save, S_IWUSR | S_IRUSR, dcssblk_save_show, | ||
| 468 | dcssblk_save_store); | ||
| 479 | 469 | ||
| 480 | /* | 470 | /* |
| 481 | * device attribute for showing all segments in a device | 471 | * device attribute for showing all segments in a device |
| @@ -502,6 +492,21 @@ dcssblk_seglist_show(struct device *dev, struct device_attribute *attr, | |||
| 502 | up_read(&dcssblk_devices_sem); | 492 | up_read(&dcssblk_devices_sem); |
| 503 | return i; | 493 | return i; |
| 504 | } | 494 | } |
| 495 | static DEVICE_ATTR(seglist, S_IRUSR, dcssblk_seglist_show, NULL); | ||
| 496 | |||
| 497 | static struct attribute *dcssblk_dev_attrs[] = { | ||
| 498 | &dev_attr_shared.attr, | ||
| 499 | &dev_attr_save.attr, | ||
| 500 | &dev_attr_seglist.attr, | ||
| 501 | NULL, | ||
| 502 | }; | ||
| 503 | static struct attribute_group dcssblk_dev_attr_group = { | ||
| 504 | .attrs = dcssblk_dev_attrs, | ||
| 505 | }; | ||
| 506 | static const struct attribute_group *dcssblk_dev_attr_groups[] = { | ||
| 507 | &dcssblk_dev_attr_group, | ||
| 508 | NULL, | ||
| 509 | }; | ||
| 505 | 510 | ||
| 506 | /* | 511 | /* |
| 507 | * device attribute for adding devices | 512 | * device attribute for adding devices |
| @@ -590,6 +595,7 @@ dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char | |||
| 590 | 595 | ||
| 591 | dev_set_name(&dev_info->dev, dev_info->segment_name); | 596 | dev_set_name(&dev_info->dev, dev_info->segment_name); |
| 592 | dev_info->dev.release = dcssblk_release_segment; | 597 | dev_info->dev.release = dcssblk_release_segment; |
| 598 | dev_info->dev.groups = dcssblk_dev_attr_groups; | ||
| 593 | INIT_LIST_HEAD(&dev_info->lh); | 599 | INIT_LIST_HEAD(&dev_info->lh); |
| 594 | dev_info->gd = alloc_disk(DCSSBLK_MINORS_PER_DISK); | 600 | dev_info->gd = alloc_disk(DCSSBLK_MINORS_PER_DISK); |
| 595 | if (dev_info->gd == NULL) { | 601 | if (dev_info->gd == NULL) { |
| @@ -637,21 +643,10 @@ dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char | |||
| 637 | * register the device | 643 | * register the device |
| 638 | */ | 644 | */ |
| 639 | rc = device_register(&dev_info->dev); | 645 | rc = device_register(&dev_info->dev); |
| 640 | if (rc) { | ||
| 641 | module_put(THIS_MODULE); | ||
| 642 | goto dev_list_del; | ||
| 643 | } | ||
| 644 | get_device(&dev_info->dev); | ||
| 645 | rc = device_create_file(&dev_info->dev, &dev_attr_shared); | ||
| 646 | if (rc) | ||
| 647 | goto unregister_dev; | ||
| 648 | rc = device_create_file(&dev_info->dev, &dev_attr_save); | ||
| 649 | if (rc) | ||
| 650 | goto unregister_dev; | ||
| 651 | rc = device_create_file(&dev_info->dev, &dev_attr_seglist); | ||
| 652 | if (rc) | 646 | if (rc) |
| 653 | goto unregister_dev; | 647 | goto put_dev; |
| 654 | 648 | ||
| 649 | get_device(&dev_info->dev); | ||
| 655 | add_disk(dev_info->gd); | 650 | add_disk(dev_info->gd); |
| 656 | 651 | ||
| 657 | switch (dev_info->segment_type) { | 652 | switch (dev_info->segment_type) { |
| @@ -668,12 +663,11 @@ dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char | |||
| 668 | rc = count; | 663 | rc = count; |
| 669 | goto out; | 664 | goto out; |
| 670 | 665 | ||
| 671 | unregister_dev: | 666 | put_dev: |
| 672 | list_del(&dev_info->lh); | 667 | list_del(&dev_info->lh); |
| 673 | blk_cleanup_queue(dev_info->dcssblk_queue); | 668 | blk_cleanup_queue(dev_info->dcssblk_queue); |
| 674 | dev_info->gd->queue = NULL; | 669 | dev_info->gd->queue = NULL; |
| 675 | put_disk(dev_info->gd); | 670 | put_disk(dev_info->gd); |
| 676 | device_unregister(&dev_info->dev); | ||
| 677 | list_for_each_entry(seg_info, &dev_info->seg_list, lh) { | 671 | list_for_each_entry(seg_info, &dev_info->seg_list, lh) { |
| 678 | segment_unload(seg_info->segment_name); | 672 | segment_unload(seg_info->segment_name); |
| 679 | } | 673 | } |
diff --git a/drivers/s390/crypto/zcrypt_pcixcc.c b/drivers/s390/crypto/zcrypt_pcixcc.c index c7275e303a0d..899ffa19f5ec 100644 --- a/drivers/s390/crypto/zcrypt_pcixcc.c +++ b/drivers/s390/crypto/zcrypt_pcixcc.c | |||
| @@ -39,7 +39,6 @@ | |||
| 39 | #include "zcrypt_msgtype6.h" | 39 | #include "zcrypt_msgtype6.h" |
| 40 | #include "zcrypt_pcixcc.h" | 40 | #include "zcrypt_pcixcc.h" |
| 41 | #include "zcrypt_cca_key.h" | 41 | #include "zcrypt_cca_key.h" |
| 42 | #include "zcrypt_msgtype6.h" | ||
| 43 | 42 | ||
| 44 | #define PCIXCC_MIN_MOD_SIZE 16 /* 128 bits */ | 43 | #define PCIXCC_MIN_MOD_SIZE 16 /* 128 bits */ |
| 45 | #define PCIXCC_MIN_MOD_SIZE_OLD 64 /* 512 bits */ | 44 | #define PCIXCC_MIN_MOD_SIZE_OLD 64 /* 512 bits */ |
