diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-05-24 15:06:02 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-05-24 15:06:02 -0400 |
commit | 0d66cba1ac3ad38614077443d604d6a09cec99de (patch) | |
tree | 383981fd93c7e6d467fb239edd51f935f1a481dd | |
parent | 4637f40f200063973553ce3c4c1ac6c247e4535c (diff) | |
parent | 5bd418784a2764a8d9de177a5462bfc008fd334a (diff) |
Merge branch 'for-linus' of git://git390.marist.edu/pub/scm/linux-2.6
* 'for-linus' of git://git390.marist.edu/pub/scm/linux-2.6: (29 commits)
[S390] cpu hotplug: fix external interrupt subclass mask handling
[S390] oprofile: dont access lowcore
[S390] oprofile: add missing irq stats counter
[S390] Ignore sendmmsg system call note wired up warning
[S390] s390,oprofile: fix compile error for !CONFIG_SMP
[S390] s390,oprofile: fix alert counter increment
[S390] Remove unused includes in process.c
[S390] get CPC image name
[S390] sclp: event buffer dissection
[S390] chsc: process channel-path-availability information
[S390] refactor page table functions for better pgste support
[S390] merge page_test_dirty and page_clear_dirty
[S390] qdio: prevent compile warning
[S390] sclp: remove unnecessary sendmask check
[S390] convert old cpumask API into new one
[S390] pfault: cleanup code
[S390] pfault: cpu hotplug vs missing completion interrupts
[S390] smp: add __noreturn attribute to cpu_die()
[S390] percpu: implement arch specific irqsafe_cpu_ops
[S390] vdso: disable gcov profiling
...
58 files changed, 895 insertions, 1284 deletions
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 4a7f14079e03..ff2d2371b2e9 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig | |||
@@ -230,17 +230,6 @@ config SYSVIPC_COMPAT | |||
230 | config AUDIT_ARCH | 230 | config AUDIT_ARCH |
231 | def_bool y | 231 | def_bool y |
232 | 232 | ||
233 | config S390_EXEC_PROTECT | ||
234 | def_bool y | ||
235 | prompt "Data execute protection" | ||
236 | help | ||
237 | This option allows to enable a buffer overflow protection for user | ||
238 | space programs and it also selects the addressing mode option above. | ||
239 | The kernel parameter noexec=on will enable this feature and also | ||
240 | switch the addressing modes, default is disabled. Enabling this (via | ||
241 | kernel parameter) on machines earlier than IBM System z9 this will | ||
242 | reduce system performance. | ||
243 | |||
244 | comment "Code generation options" | 233 | comment "Code generation options" |
245 | 234 | ||
246 | choice | 235 | choice |
diff --git a/arch/s390/appldata/appldata_base.c b/arch/s390/appldata/appldata_base.c index 5c91995b74e4..24bff4f1cc52 100644 --- a/arch/s390/appldata/appldata_base.c +++ b/arch/s390/appldata/appldata_base.c | |||
@@ -130,9 +130,7 @@ static void appldata_work_fn(struct work_struct *work) | |||
130 | { | 130 | { |
131 | struct list_head *lh; | 131 | struct list_head *lh; |
132 | struct appldata_ops *ops; | 132 | struct appldata_ops *ops; |
133 | int i; | ||
134 | 133 | ||
135 | i = 0; | ||
136 | get_online_cpus(); | 134 | get_online_cpus(); |
137 | mutex_lock(&appldata_ops_mutex); | 135 | mutex_lock(&appldata_ops_mutex); |
138 | list_for_each(lh, &appldata_ops_list) { | 136 | list_for_each(lh, &appldata_ops_list) { |
diff --git a/arch/s390/include/asm/cmpxchg.h b/arch/s390/include/asm/cmpxchg.h index 7488e52efa97..81d7908416cf 100644 --- a/arch/s390/include/asm/cmpxchg.h +++ b/arch/s390/include/asm/cmpxchg.h | |||
@@ -167,7 +167,6 @@ static inline unsigned long __cmpxchg(void *ptr, unsigned long old, | |||
167 | #ifdef CONFIG_64BIT | 167 | #ifdef CONFIG_64BIT |
168 | #define cmpxchg64(ptr, o, n) \ | 168 | #define cmpxchg64(ptr, o, n) \ |
169 | ({ \ | 169 | ({ \ |
170 | BUILD_BUG_ON(sizeof(*(ptr)) != 8); \ | ||
171 | cmpxchg((ptr), (o), (n)); \ | 170 | cmpxchg((ptr), (o), (n)); \ |
172 | }) | 171 | }) |
173 | #else /* CONFIG_64BIT */ | 172 | #else /* CONFIG_64BIT */ |
diff --git a/arch/s390/include/asm/elf.h b/arch/s390/include/asm/elf.h index 10c029cfcc7d..64b61bf72e93 100644 --- a/arch/s390/include/asm/elf.h +++ b/arch/s390/include/asm/elf.h | |||
@@ -196,18 +196,6 @@ do { \ | |||
196 | } while (0) | 196 | } while (0) |
197 | #endif /* __s390x__ */ | 197 | #endif /* __s390x__ */ |
198 | 198 | ||
199 | /* | ||
200 | * An executable for which elf_read_implies_exec() returns TRUE will | ||
201 | * have the READ_IMPLIES_EXEC personality flag set automatically. | ||
202 | */ | ||
203 | #define elf_read_implies_exec(ex, executable_stack) \ | ||
204 | ({ \ | ||
205 | if (current->mm->context.noexec && \ | ||
206 | executable_stack != EXSTACK_DISABLE_X) \ | ||
207 | disable_noexec(current->mm, current); \ | ||
208 | current->mm->context.noexec == 0; \ | ||
209 | }) | ||
210 | |||
211 | #define STACK_RND_MASK 0x7ffUL | 199 | #define STACK_RND_MASK 0x7ffUL |
212 | 200 | ||
213 | #define ARCH_DLINFO \ | 201 | #define ARCH_DLINFO \ |
diff --git a/arch/s390/include/asm/hugetlb.h b/arch/s390/include/asm/hugetlb.h index b56403c2df28..799ed0f1643d 100644 --- a/arch/s390/include/asm/hugetlb.h +++ b/arch/s390/include/asm/hugetlb.h | |||
@@ -111,21 +111,10 @@ static inline void huge_ptep_invalidate(struct mm_struct *mm, | |||
111 | { | 111 | { |
112 | pmd_t *pmdp = (pmd_t *) ptep; | 112 | pmd_t *pmdp = (pmd_t *) ptep; |
113 | 113 | ||
114 | if (!MACHINE_HAS_IDTE) { | 114 | if (MACHINE_HAS_IDTE) |
115 | __pmd_csp(pmdp); | ||
116 | if (mm->context.noexec) { | ||
117 | pmdp = get_shadow_table(pmdp); | ||
118 | __pmd_csp(pmdp); | ||
119 | } | ||
120 | return; | ||
121 | } | ||
122 | |||
123 | __pmd_idte(address, pmdp); | ||
124 | if (mm->context.noexec) { | ||
125 | pmdp = get_shadow_table(pmdp); | ||
126 | __pmd_idte(address, pmdp); | 115 | __pmd_idte(address, pmdp); |
127 | } | 116 | else |
128 | return; | 117 | __pmd_csp(pmdp); |
129 | } | 118 | } |
130 | 119 | ||
131 | #define huge_ptep_set_access_flags(__vma, __addr, __ptep, __entry, __dirty) \ | 120 | #define huge_ptep_set_access_flags(__vma, __addr, __ptep, __entry, __dirty) \ |
diff --git a/arch/s390/include/asm/irq.h b/arch/s390/include/asm/irq.h index db14a311f1d2..1544b90bd6d6 100644 --- a/arch/s390/include/asm/irq.h +++ b/arch/s390/include/asm/irq.h | |||
@@ -15,6 +15,7 @@ enum interruption_class { | |||
15 | EXTINT_VRT, | 15 | EXTINT_VRT, |
16 | EXTINT_SCP, | 16 | EXTINT_SCP, |
17 | EXTINT_IUC, | 17 | EXTINT_IUC, |
18 | EXTINT_CPM, | ||
18 | IOINT_QAI, | 19 | IOINT_QAI, |
19 | IOINT_QDI, | 20 | IOINT_QDI, |
20 | IOINT_DAS, | 21 | IOINT_DAS, |
diff --git a/arch/s390/include/asm/lowcore.h b/arch/s390/include/asm/lowcore.h index 65e172f8209d..228cf0b295db 100644 --- a/arch/s390/include/asm/lowcore.h +++ b/arch/s390/include/asm/lowcore.h | |||
@@ -124,7 +124,7 @@ struct _lowcore { | |||
124 | /* Address space pointer. */ | 124 | /* Address space pointer. */ |
125 | __u32 kernel_asce; /* 0x02ac */ | 125 | __u32 kernel_asce; /* 0x02ac */ |
126 | __u32 user_asce; /* 0x02b0 */ | 126 | __u32 user_asce; /* 0x02b0 */ |
127 | __u32 user_exec_asce; /* 0x02b4 */ | 127 | __u32 current_pid; /* 0x02b4 */ |
128 | 128 | ||
129 | /* SMP info area */ | 129 | /* SMP info area */ |
130 | __u32 cpu_nr; /* 0x02b8 */ | 130 | __u32 cpu_nr; /* 0x02b8 */ |
@@ -255,7 +255,7 @@ struct _lowcore { | |||
255 | /* Address space pointer. */ | 255 | /* Address space pointer. */ |
256 | __u64 kernel_asce; /* 0x0310 */ | 256 | __u64 kernel_asce; /* 0x0310 */ |
257 | __u64 user_asce; /* 0x0318 */ | 257 | __u64 user_asce; /* 0x0318 */ |
258 | __u64 user_exec_asce; /* 0x0320 */ | 258 | __u64 current_pid; /* 0x0320 */ |
259 | 259 | ||
260 | /* SMP info area */ | 260 | /* SMP info area */ |
261 | __u32 cpu_nr; /* 0x0328 */ | 261 | __u32 cpu_nr; /* 0x0328 */ |
diff --git a/arch/s390/include/asm/mmu.h b/arch/s390/include/asm/mmu.h index 78522cdefdd4..82d0847896a0 100644 --- a/arch/s390/include/asm/mmu.h +++ b/arch/s390/include/asm/mmu.h | |||
@@ -5,19 +5,18 @@ typedef struct { | |||
5 | atomic_t attach_count; | 5 | atomic_t attach_count; |
6 | unsigned int flush_mm; | 6 | unsigned int flush_mm; |
7 | spinlock_t list_lock; | 7 | spinlock_t list_lock; |
8 | struct list_head crst_list; | ||
9 | struct list_head pgtable_list; | 8 | struct list_head pgtable_list; |
10 | unsigned long asce_bits; | 9 | unsigned long asce_bits; |
11 | unsigned long asce_limit; | 10 | unsigned long asce_limit; |
12 | unsigned long vdso_base; | 11 | unsigned long vdso_base; |
13 | int noexec; | 12 | /* Cloned contexts will be created with extended page tables. */ |
14 | int has_pgste; /* The mmu context has extended page tables */ | 13 | unsigned int alloc_pgste:1; |
15 | int alloc_pgste; /* cloned contexts will have extended page tables */ | 14 | /* The mmu context has extended page tables. */ |
15 | unsigned int has_pgste:1; | ||
16 | } mm_context_t; | 16 | } mm_context_t; |
17 | 17 | ||
18 | #define INIT_MM_CONTEXT(name) \ | 18 | #define INIT_MM_CONTEXT(name) \ |
19 | .context.list_lock = __SPIN_LOCK_UNLOCKED(name.context.list_lock), \ | 19 | .context.list_lock = __SPIN_LOCK_UNLOCKED(name.context.list_lock), \ |
20 | .context.crst_list = LIST_HEAD_INIT(name.context.crst_list), \ | ||
21 | .context.pgtable_list = LIST_HEAD_INIT(name.context.pgtable_list), | 20 | .context.pgtable_list = LIST_HEAD_INIT(name.context.pgtable_list), |
22 | 21 | ||
23 | #endif | 22 | #endif |
diff --git a/arch/s390/include/asm/mmu_context.h b/arch/s390/include/asm/mmu_context.h index 8c277caa8d3a..5682f160ff82 100644 --- a/arch/s390/include/asm/mmu_context.h +++ b/arch/s390/include/asm/mmu_context.h | |||
@@ -35,11 +35,9 @@ static inline int init_new_context(struct task_struct *tsk, | |||
35 | * and if has_pgste is set, it will create extended page | 35 | * and if has_pgste is set, it will create extended page |
36 | * tables. | 36 | * tables. |
37 | */ | 37 | */ |
38 | mm->context.noexec = 0; | ||
39 | mm->context.has_pgste = 1; | 38 | mm->context.has_pgste = 1; |
40 | mm->context.alloc_pgste = 1; | 39 | mm->context.alloc_pgste = 1; |
41 | } else { | 40 | } else { |
42 | mm->context.noexec = (user_mode == SECONDARY_SPACE_MODE); | ||
43 | mm->context.has_pgste = 0; | 41 | mm->context.has_pgste = 0; |
44 | mm->context.alloc_pgste = 0; | 42 | mm->context.alloc_pgste = 0; |
45 | } | 43 | } |
@@ -63,10 +61,8 @@ static inline void update_mm(struct mm_struct *mm, struct task_struct *tsk) | |||
63 | S390_lowcore.user_asce = mm->context.asce_bits | __pa(pgd); | 61 | S390_lowcore.user_asce = mm->context.asce_bits | __pa(pgd); |
64 | if (user_mode != HOME_SPACE_MODE) { | 62 | if (user_mode != HOME_SPACE_MODE) { |
65 | /* Load primary space page table origin. */ | 63 | /* Load primary space page table origin. */ |
66 | pgd = mm->context.noexec ? get_shadow_table(pgd) : pgd; | ||
67 | S390_lowcore.user_exec_asce = mm->context.asce_bits | __pa(pgd); | ||
68 | asm volatile(LCTL_OPCODE" 1,1,%0\n" | 64 | asm volatile(LCTL_OPCODE" 1,1,%0\n" |
69 | : : "m" (S390_lowcore.user_exec_asce) ); | 65 | : : "m" (S390_lowcore.user_asce) ); |
70 | } else | 66 | } else |
71 | /* Load home space page table origin. */ | 67 | /* Load home space page table origin. */ |
72 | asm volatile(LCTL_OPCODE" 13,13,%0" | 68 | asm volatile(LCTL_OPCODE" 13,13,%0" |
diff --git a/arch/s390/include/asm/page.h b/arch/s390/include/asm/page.h index 3c987e9ec8d6..accb372ddc7e 100644 --- a/arch/s390/include/asm/page.h +++ b/arch/s390/include/asm/page.h | |||
@@ -90,6 +90,7 @@ static inline void copy_page(void *to, void *from) | |||
90 | */ | 90 | */ |
91 | 91 | ||
92 | typedef struct { unsigned long pgprot; } pgprot_t; | 92 | typedef struct { unsigned long pgprot; } pgprot_t; |
93 | typedef struct { unsigned long pgste; } pgste_t; | ||
93 | typedef struct { unsigned long pte; } pte_t; | 94 | typedef struct { unsigned long pte; } pte_t; |
94 | typedef struct { unsigned long pmd; } pmd_t; | 95 | typedef struct { unsigned long pmd; } pmd_t; |
95 | typedef struct { unsigned long pud; } pud_t; | 96 | typedef struct { unsigned long pud; } pud_t; |
@@ -97,18 +98,21 @@ typedef struct { unsigned long pgd; } pgd_t; | |||
97 | typedef pte_t *pgtable_t; | 98 | typedef pte_t *pgtable_t; |
98 | 99 | ||
99 | #define pgprot_val(x) ((x).pgprot) | 100 | #define pgprot_val(x) ((x).pgprot) |
101 | #define pgste_val(x) ((x).pgste) | ||
100 | #define pte_val(x) ((x).pte) | 102 | #define pte_val(x) ((x).pte) |
101 | #define pmd_val(x) ((x).pmd) | 103 | #define pmd_val(x) ((x).pmd) |
102 | #define pud_val(x) ((x).pud) | 104 | #define pud_val(x) ((x).pud) |
103 | #define pgd_val(x) ((x).pgd) | 105 | #define pgd_val(x) ((x).pgd) |
104 | 106 | ||
107 | #define __pgste(x) ((pgste_t) { (x) } ) | ||
105 | #define __pte(x) ((pte_t) { (x) } ) | 108 | #define __pte(x) ((pte_t) { (x) } ) |
106 | #define __pmd(x) ((pmd_t) { (x) } ) | 109 | #define __pmd(x) ((pmd_t) { (x) } ) |
110 | #define __pud(x) ((pud_t) { (x) } ) | ||
107 | #define __pgd(x) ((pgd_t) { (x) } ) | 111 | #define __pgd(x) ((pgd_t) { (x) } ) |
108 | #define __pgprot(x) ((pgprot_t) { (x) } ) | 112 | #define __pgprot(x) ((pgprot_t) { (x) } ) |
109 | 113 | ||
110 | static inline void | 114 | static inline void page_set_storage_key(unsigned long addr, |
111 | page_set_storage_key(unsigned long addr, unsigned int skey, int mapped) | 115 | unsigned char skey, int mapped) |
112 | { | 116 | { |
113 | if (!mapped) | 117 | if (!mapped) |
114 | asm volatile(".insn rrf,0xb22b0000,%0,%1,8,0" | 118 | asm volatile(".insn rrf,0xb22b0000,%0,%1,8,0" |
@@ -117,15 +121,59 @@ page_set_storage_key(unsigned long addr, unsigned int skey, int mapped) | |||
117 | asm volatile("sske %0,%1" : : "d" (skey), "a" (addr)); | 121 | asm volatile("sske %0,%1" : : "d" (skey), "a" (addr)); |
118 | } | 122 | } |
119 | 123 | ||
120 | static inline unsigned int | 124 | static inline unsigned char page_get_storage_key(unsigned long addr) |
121 | page_get_storage_key(unsigned long addr) | ||
122 | { | 125 | { |
123 | unsigned int skey; | 126 | unsigned char skey; |
124 | 127 | ||
125 | asm volatile("iske %0,%1" : "=d" (skey) : "a" (addr), "0" (0)); | 128 | asm volatile("iske %0,%1" : "=d" (skey) : "a" (addr)); |
126 | return skey; | 129 | return skey; |
127 | } | 130 | } |
128 | 131 | ||
132 | static inline int page_reset_referenced(unsigned long addr) | ||
133 | { | ||
134 | unsigned int ipm; | ||
135 | |||
136 | asm volatile( | ||
137 | " rrbe 0,%1\n" | ||
138 | " ipm %0\n" | ||
139 | : "=d" (ipm) : "a" (addr) : "cc"); | ||
140 | return !!(ipm & 0x20000000); | ||
141 | } | ||
142 | |||
143 | /* Bits int the storage key */ | ||
144 | #define _PAGE_CHANGED 0x02 /* HW changed bit */ | ||
145 | #define _PAGE_REFERENCED 0x04 /* HW referenced bit */ | ||
146 | #define _PAGE_FP_BIT 0x08 /* HW fetch protection bit */ | ||
147 | #define _PAGE_ACC_BITS 0xf0 /* HW access control bits */ | ||
148 | |||
149 | /* | ||
150 | * Test and clear dirty bit in storage key. | ||
151 | * We can't clear the changed bit atomically. This is a potential | ||
152 | * race against modification of the referenced bit. This function | ||
153 | * should therefore only be called if it is not mapped in any | ||
154 | * address space. | ||
155 | */ | ||
156 | #define __HAVE_ARCH_PAGE_TEST_AND_CLEAR_DIRTY | ||
157 | static inline int page_test_and_clear_dirty(unsigned long pfn, int mapped) | ||
158 | { | ||
159 | unsigned char skey; | ||
160 | |||
161 | skey = page_get_storage_key(pfn << PAGE_SHIFT); | ||
162 | if (!(skey & _PAGE_CHANGED)) | ||
163 | return 0; | ||
164 | page_set_storage_key(pfn << PAGE_SHIFT, skey & ~_PAGE_CHANGED, mapped); | ||
165 | return 1; | ||
166 | } | ||
167 | |||
168 | /* | ||
169 | * Test and clear referenced bit in storage key. | ||
170 | */ | ||
171 | #define __HAVE_ARCH_PAGE_TEST_AND_CLEAR_YOUNG | ||
172 | static inline int page_test_and_clear_young(unsigned long pfn) | ||
173 | { | ||
174 | return page_reset_referenced(pfn << PAGE_SHIFT); | ||
175 | } | ||
176 | |||
129 | struct page; | 177 | struct page; |
130 | void arch_free_page(struct page *page, int order); | 178 | void arch_free_page(struct page *page, int order); |
131 | void arch_alloc_page(struct page *page, int order); | 179 | void arch_alloc_page(struct page *page, int order); |
diff --git a/arch/s390/include/asm/percpu.h b/arch/s390/include/asm/percpu.h index f7ad8719d02d..5325c89a5843 100644 --- a/arch/s390/include/asm/percpu.h +++ b/arch/s390/include/asm/percpu.h | |||
@@ -1,6 +1,9 @@ | |||
1 | #ifndef __ARCH_S390_PERCPU__ | 1 | #ifndef __ARCH_S390_PERCPU__ |
2 | #define __ARCH_S390_PERCPU__ | 2 | #define __ARCH_S390_PERCPU__ |
3 | 3 | ||
4 | #include <linux/preempt.h> | ||
5 | #include <asm/cmpxchg.h> | ||
6 | |||
4 | /* | 7 | /* |
5 | * s390 uses its own implementation for per cpu data, the offset of | 8 | * s390 uses its own implementation for per cpu data, the offset of |
6 | * the cpu local data area is cached in the cpu's lowcore memory. | 9 | * the cpu local data area is cached in the cpu's lowcore memory. |
@@ -16,6 +19,71 @@ | |||
16 | #define ARCH_NEEDS_WEAK_PER_CPU | 19 | #define ARCH_NEEDS_WEAK_PER_CPU |
17 | #endif | 20 | #endif |
18 | 21 | ||
22 | #define arch_irqsafe_cpu_to_op(pcp, val, op) \ | ||
23 | do { \ | ||
24 | typedef typeof(pcp) pcp_op_T__; \ | ||
25 | pcp_op_T__ old__, new__, prev__; \ | ||
26 | pcp_op_T__ *ptr__; \ | ||
27 | preempt_disable(); \ | ||
28 | ptr__ = __this_cpu_ptr(&(pcp)); \ | ||
29 | prev__ = *ptr__; \ | ||
30 | do { \ | ||
31 | old__ = prev__; \ | ||
32 | new__ = old__ op (val); \ | ||
33 | switch (sizeof(*ptr__)) { \ | ||
34 | case 8: \ | ||
35 | prev__ = cmpxchg64(ptr__, old__, new__); \ | ||
36 | break; \ | ||
37 | default: \ | ||
38 | prev__ = cmpxchg(ptr__, old__, new__); \ | ||
39 | } \ | ||
40 | } while (prev__ != old__); \ | ||
41 | preempt_enable(); \ | ||
42 | } while (0) | ||
43 | |||
44 | #define irqsafe_cpu_add_1(pcp, val) arch_irqsafe_cpu_to_op(pcp, val, +) | ||
45 | #define irqsafe_cpu_add_2(pcp, val) arch_irqsafe_cpu_to_op(pcp, val, +) | ||
46 | #define irqsafe_cpu_add_4(pcp, val) arch_irqsafe_cpu_to_op(pcp, val, +) | ||
47 | #define irqsafe_cpu_add_8(pcp, val) arch_irqsafe_cpu_to_op(pcp, val, +) | ||
48 | |||
49 | #define irqsafe_cpu_and_1(pcp, val) arch_irqsafe_cpu_to_op(pcp, val, &) | ||
50 | #define irqsafe_cpu_and_2(pcp, val) arch_irqsafe_cpu_to_op(pcp, val, &) | ||
51 | #define irqsafe_cpu_and_4(pcp, val) arch_irqsafe_cpu_to_op(pcp, val, &) | ||
52 | #define irqsafe_cpu_and_8(pcp, val) arch_irqsafe_cpu_to_op(pcp, val, &) | ||
53 | |||
54 | #define irqsafe_cpu_or_1(pcp, val) arch_irqsafe_cpu_to_op(pcp, val, |) | ||
55 | #define irqsafe_cpu_or_2(pcp, val) arch_irqsafe_cpu_to_op(pcp, val, |) | ||
56 | #define irqsafe_cpu_or_4(pcp, val) arch_irqsafe_cpu_to_op(pcp, val, |) | ||
57 | #define irqsafe_cpu_or_8(pcp, val) arch_irqsafe_cpu_to_op(pcp, val, |) | ||
58 | |||
59 | #define irqsafe_cpu_xor_1(pcp, val) arch_irqsafe_cpu_to_op(pcp, val, ^) | ||
60 | #define irqsafe_cpu_xor_2(pcp, val) arch_irqsafe_cpu_to_op(pcp, val, ^) | ||
61 | #define irqsafe_cpu_xor_4(pcp, val) arch_irqsafe_cpu_to_op(pcp, val, ^) | ||
62 | #define irqsafe_cpu_xor_8(pcp, val) arch_irqsafe_cpu_to_op(pcp, val, ^) | ||
63 | |||
64 | #define arch_irqsafe_cpu_cmpxchg(pcp, oval, nval) \ | ||
65 | ({ \ | ||
66 | typedef typeof(pcp) pcp_op_T__; \ | ||
67 | pcp_op_T__ ret__; \ | ||
68 | pcp_op_T__ *ptr__; \ | ||
69 | preempt_disable(); \ | ||
70 | ptr__ = __this_cpu_ptr(&(pcp)); \ | ||
71 | switch (sizeof(*ptr__)) { \ | ||
72 | case 8: \ | ||
73 | ret__ = cmpxchg64(ptr__, oval, nval); \ | ||
74 | break; \ | ||
75 | default: \ | ||
76 | ret__ = cmpxchg(ptr__, oval, nval); \ | ||
77 | } \ | ||
78 | preempt_enable(); \ | ||
79 | ret__; \ | ||
80 | }) | ||
81 | |||
82 | #define irqsafe_cpu_cmpxchg_1(pcp, oval, nval) arch_irqsafe_cpu_cmpxchg(pcp, oval, nval) | ||
83 | #define irqsafe_cpu_cmpxchg_2(pcp, oval, nval) arch_irqsafe_cpu_cmpxchg(pcp, oval, nval) | ||
84 | #define irqsafe_cpu_cmpxchg_4(pcp, oval, nval) arch_irqsafe_cpu_cmpxchg(pcp, oval, nval) | ||
85 | #define irqsafe_cpu_cmpxchg_8(pcp, oval, nval) arch_irqsafe_cpu_cmpxchg(pcp, oval, nval) | ||
86 | |||
19 | #include <asm-generic/percpu.h> | 87 | #include <asm-generic/percpu.h> |
20 | 88 | ||
21 | #endif /* __ARCH_S390_PERCPU__ */ | 89 | #endif /* __ARCH_S390_PERCPU__ */ |
diff --git a/arch/s390/include/asm/pgalloc.h b/arch/s390/include/asm/pgalloc.h index 082eb4e50e8b..f6314af3b354 100644 --- a/arch/s390/include/asm/pgalloc.h +++ b/arch/s390/include/asm/pgalloc.h | |||
@@ -19,14 +19,13 @@ | |||
19 | 19 | ||
20 | #define check_pgt_cache() do {} while (0) | 20 | #define check_pgt_cache() do {} while (0) |
21 | 21 | ||
22 | unsigned long *crst_table_alloc(struct mm_struct *, int); | 22 | unsigned long *crst_table_alloc(struct mm_struct *); |
23 | void crst_table_free(struct mm_struct *, unsigned long *); | 23 | void crst_table_free(struct mm_struct *, unsigned long *); |
24 | void crst_table_free_rcu(struct mm_struct *, unsigned long *); | 24 | void crst_table_free_rcu(struct mm_struct *, unsigned long *); |
25 | 25 | ||
26 | unsigned long *page_table_alloc(struct mm_struct *); | 26 | unsigned long *page_table_alloc(struct mm_struct *); |
27 | void page_table_free(struct mm_struct *, unsigned long *); | 27 | void page_table_free(struct mm_struct *, unsigned long *); |
28 | void page_table_free_rcu(struct mm_struct *, unsigned long *); | 28 | void page_table_free_rcu(struct mm_struct *, unsigned long *); |
29 | void disable_noexec(struct mm_struct *, struct task_struct *); | ||
30 | 29 | ||
31 | static inline void clear_table(unsigned long *s, unsigned long val, size_t n) | 30 | static inline void clear_table(unsigned long *s, unsigned long val, size_t n) |
32 | { | 31 | { |
@@ -50,9 +49,6 @@ static inline void clear_table(unsigned long *s, unsigned long val, size_t n) | |||
50 | static inline void crst_table_init(unsigned long *crst, unsigned long entry) | 49 | static inline void crst_table_init(unsigned long *crst, unsigned long entry) |
51 | { | 50 | { |
52 | clear_table(crst, entry, sizeof(unsigned long)*2048); | 51 | clear_table(crst, entry, sizeof(unsigned long)*2048); |
53 | crst = get_shadow_table(crst); | ||
54 | if (crst) | ||
55 | clear_table(crst, entry, sizeof(unsigned long)*2048); | ||
56 | } | 52 | } |
57 | 53 | ||
58 | #ifndef __s390x__ | 54 | #ifndef __s390x__ |
@@ -69,10 +65,7 @@ static inline unsigned long pgd_entry_type(struct mm_struct *mm) | |||
69 | #define pmd_free(mm, x) do { } while (0) | 65 | #define pmd_free(mm, x) do { } while (0) |
70 | 66 | ||
71 | #define pgd_populate(mm, pgd, pud) BUG() | 67 | #define pgd_populate(mm, pgd, pud) BUG() |
72 | #define pgd_populate_kernel(mm, pgd, pud) BUG() | ||
73 | |||
74 | #define pud_populate(mm, pud, pmd) BUG() | 68 | #define pud_populate(mm, pud, pmd) BUG() |
75 | #define pud_populate_kernel(mm, pud, pmd) BUG() | ||
76 | 69 | ||
77 | #else /* __s390x__ */ | 70 | #else /* __s390x__ */ |
78 | 71 | ||
@@ -90,7 +83,7 @@ void crst_table_downgrade(struct mm_struct *, unsigned long limit); | |||
90 | 83 | ||
91 | static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long address) | 84 | static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long address) |
92 | { | 85 | { |
93 | unsigned long *table = crst_table_alloc(mm, mm->context.noexec); | 86 | unsigned long *table = crst_table_alloc(mm); |
94 | if (table) | 87 | if (table) |
95 | crst_table_init(table, _REGION3_ENTRY_EMPTY); | 88 | crst_table_init(table, _REGION3_ENTRY_EMPTY); |
96 | return (pud_t *) table; | 89 | return (pud_t *) table; |
@@ -99,43 +92,21 @@ static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long address) | |||
99 | 92 | ||
100 | static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long vmaddr) | 93 | static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long vmaddr) |
101 | { | 94 | { |
102 | unsigned long *table = crst_table_alloc(mm, mm->context.noexec); | 95 | unsigned long *table = crst_table_alloc(mm); |
103 | if (table) | 96 | if (table) |
104 | crst_table_init(table, _SEGMENT_ENTRY_EMPTY); | 97 | crst_table_init(table, _SEGMENT_ENTRY_EMPTY); |
105 | return (pmd_t *) table; | 98 | return (pmd_t *) table; |
106 | } | 99 | } |
107 | #define pmd_free(mm, pmd) crst_table_free(mm, (unsigned long *) pmd) | 100 | #define pmd_free(mm, pmd) crst_table_free(mm, (unsigned long *) pmd) |
108 | 101 | ||
109 | static inline void pgd_populate_kernel(struct mm_struct *mm, | ||
110 | pgd_t *pgd, pud_t *pud) | ||
111 | { | ||
112 | pgd_val(*pgd) = _REGION2_ENTRY | __pa(pud); | ||
113 | } | ||
114 | |||
115 | static inline void pgd_populate(struct mm_struct *mm, pgd_t *pgd, pud_t *pud) | 102 | static inline void pgd_populate(struct mm_struct *mm, pgd_t *pgd, pud_t *pud) |
116 | { | 103 | { |
117 | pgd_populate_kernel(mm, pgd, pud); | 104 | pgd_val(*pgd) = _REGION2_ENTRY | __pa(pud); |
118 | if (mm->context.noexec) { | ||
119 | pgd = get_shadow_table(pgd); | ||
120 | pud = get_shadow_table(pud); | ||
121 | pgd_populate_kernel(mm, pgd, pud); | ||
122 | } | ||
123 | } | ||
124 | |||
125 | static inline void pud_populate_kernel(struct mm_struct *mm, | ||
126 | pud_t *pud, pmd_t *pmd) | ||
127 | { | ||
128 | pud_val(*pud) = _REGION3_ENTRY | __pa(pmd); | ||
129 | } | 105 | } |
130 | 106 | ||
131 | static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd) | 107 | static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd) |
132 | { | 108 | { |
133 | pud_populate_kernel(mm, pud, pmd); | 109 | pud_val(*pud) = _REGION3_ENTRY | __pa(pmd); |
134 | if (mm->context.noexec) { | ||
135 | pud = get_shadow_table(pud); | ||
136 | pmd = get_shadow_table(pmd); | ||
137 | pud_populate_kernel(mm, pud, pmd); | ||
138 | } | ||
139 | } | 110 | } |
140 | 111 | ||
141 | #endif /* __s390x__ */ | 112 | #endif /* __s390x__ */ |
@@ -143,29 +114,19 @@ static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd) | |||
143 | static inline pgd_t *pgd_alloc(struct mm_struct *mm) | 114 | static inline pgd_t *pgd_alloc(struct mm_struct *mm) |
144 | { | 115 | { |
145 | spin_lock_init(&mm->context.list_lock); | 116 | spin_lock_init(&mm->context.list_lock); |
146 | INIT_LIST_HEAD(&mm->context.crst_list); | ||
147 | INIT_LIST_HEAD(&mm->context.pgtable_list); | 117 | INIT_LIST_HEAD(&mm->context.pgtable_list); |
148 | return (pgd_t *) | 118 | return (pgd_t *) crst_table_alloc(mm); |
149 | crst_table_alloc(mm, user_mode == SECONDARY_SPACE_MODE); | ||
150 | } | 119 | } |
151 | #define pgd_free(mm, pgd) crst_table_free(mm, (unsigned long *) pgd) | 120 | #define pgd_free(mm, pgd) crst_table_free(mm, (unsigned long *) pgd) |
152 | 121 | ||
153 | static inline void pmd_populate_kernel(struct mm_struct *mm, | ||
154 | pmd_t *pmd, pte_t *pte) | ||
155 | { | ||
156 | pmd_val(*pmd) = _SEGMENT_ENTRY + __pa(pte); | ||
157 | } | ||
158 | |||
159 | static inline void pmd_populate(struct mm_struct *mm, | 122 | static inline void pmd_populate(struct mm_struct *mm, |
160 | pmd_t *pmd, pgtable_t pte) | 123 | pmd_t *pmd, pgtable_t pte) |
161 | { | 124 | { |
162 | pmd_populate_kernel(mm, pmd, pte); | 125 | pmd_val(*pmd) = _SEGMENT_ENTRY + __pa(pte); |
163 | if (mm->context.noexec) { | ||
164 | pmd = get_shadow_table(pmd); | ||
165 | pmd_populate_kernel(mm, pmd, pte + PTRS_PER_PTE); | ||
166 | } | ||
167 | } | 126 | } |
168 | 127 | ||
128 | #define pmd_populate_kernel(mm, pmd, pte) pmd_populate(mm, pmd, pte) | ||
129 | |||
169 | #define pmd_pgtable(pmd) \ | 130 | #define pmd_pgtable(pmd) \ |
170 | (pgtable_t)(pmd_val(pmd) & -sizeof(pte_t)*PTRS_PER_PTE) | 131 | (pgtable_t)(pmd_val(pmd) & -sizeof(pte_t)*PTRS_PER_PTE) |
171 | 132 | ||
diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h index 02ace3491c51..c4773a2ef3d3 100644 --- a/arch/s390/include/asm/pgtable.h +++ b/arch/s390/include/asm/pgtable.h | |||
@@ -31,9 +31,8 @@ | |||
31 | #ifndef __ASSEMBLY__ | 31 | #ifndef __ASSEMBLY__ |
32 | #include <linux/sched.h> | 32 | #include <linux/sched.h> |
33 | #include <linux/mm_types.h> | 33 | #include <linux/mm_types.h> |
34 | #include <asm/bitops.h> | ||
35 | #include <asm/bug.h> | 34 | #include <asm/bug.h> |
36 | #include <asm/processor.h> | 35 | #include <asm/page.h> |
37 | 36 | ||
38 | extern pgd_t swapper_pg_dir[] __attribute__ ((aligned (4096))); | 37 | extern pgd_t swapper_pg_dir[] __attribute__ ((aligned (4096))); |
39 | extern void paging_init(void); | 38 | extern void paging_init(void); |
@@ -243,11 +242,13 @@ extern unsigned long VMALLOC_START; | |||
243 | /* Software bits in the page table entry */ | 242 | /* Software bits in the page table entry */ |
244 | #define _PAGE_SWT 0x001 /* SW pte type bit t */ | 243 | #define _PAGE_SWT 0x001 /* SW pte type bit t */ |
245 | #define _PAGE_SWX 0x002 /* SW pte type bit x */ | 244 | #define _PAGE_SWX 0x002 /* SW pte type bit x */ |
246 | #define _PAGE_SPECIAL 0x004 /* SW associated with special page */ | 245 | #define _PAGE_SWC 0x004 /* SW pte changed bit (for KVM) */ |
246 | #define _PAGE_SWR 0x008 /* SW pte referenced bit (for KVM) */ | ||
247 | #define _PAGE_SPECIAL 0x010 /* SW associated with special page */ | ||
247 | #define __HAVE_ARCH_PTE_SPECIAL | 248 | #define __HAVE_ARCH_PTE_SPECIAL |
248 | 249 | ||
249 | /* Set of bits not changed in pte_modify */ | 250 | /* Set of bits not changed in pte_modify */ |
250 | #define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_SPECIAL) | 251 | #define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_SPECIAL | _PAGE_SWC | _PAGE_SWR) |
251 | 252 | ||
252 | /* Six different types of pages. */ | 253 | /* Six different types of pages. */ |
253 | #define _PAGE_TYPE_EMPTY 0x400 | 254 | #define _PAGE_TYPE_EMPTY 0x400 |
@@ -256,8 +257,6 @@ extern unsigned long VMALLOC_START; | |||
256 | #define _PAGE_TYPE_FILE 0x601 /* bit 0x002 is used for offset !! */ | 257 | #define _PAGE_TYPE_FILE 0x601 /* bit 0x002 is used for offset !! */ |
257 | #define _PAGE_TYPE_RO 0x200 | 258 | #define _PAGE_TYPE_RO 0x200 |
258 | #define _PAGE_TYPE_RW 0x000 | 259 | #define _PAGE_TYPE_RW 0x000 |
259 | #define _PAGE_TYPE_EX_RO 0x202 | ||
260 | #define _PAGE_TYPE_EX_RW 0x002 | ||
261 | 260 | ||
262 | /* | 261 | /* |
263 | * Only four types for huge pages, using the invalid bit and protection bit | 262 | * Only four types for huge pages, using the invalid bit and protection bit |
@@ -287,8 +286,6 @@ extern unsigned long VMALLOC_START; | |||
287 | * _PAGE_TYPE_FILE 11?1 -> 11?1 | 286 | * _PAGE_TYPE_FILE 11?1 -> 11?1 |
288 | * _PAGE_TYPE_RO 0100 -> 1100 | 287 | * _PAGE_TYPE_RO 0100 -> 1100 |
289 | * _PAGE_TYPE_RW 0000 -> 1000 | 288 | * _PAGE_TYPE_RW 0000 -> 1000 |
290 | * _PAGE_TYPE_EX_RO 0110 -> 1110 | ||
291 | * _PAGE_TYPE_EX_RW 0010 -> 1010 | ||
292 | * | 289 | * |
293 | * pte_none is true for bits combinations 1000, 1010, 1100, 1110 | 290 | * pte_none is true for bits combinations 1000, 1010, 1100, 1110 |
294 | * pte_present is true for bits combinations 0000, 0010, 0100, 0110, 1001 | 291 | * pte_present is true for bits combinations 0000, 0010, 0100, 0110, 1001 |
@@ -297,14 +294,17 @@ extern unsigned long VMALLOC_START; | |||
297 | */ | 294 | */ |
298 | 295 | ||
299 | /* Page status table bits for virtualization */ | 296 | /* Page status table bits for virtualization */ |
300 | #define RCP_PCL_BIT 55 | 297 | #define RCP_ACC_BITS 0xf000000000000000UL |
301 | #define RCP_HR_BIT 54 | 298 | #define RCP_FP_BIT 0x0800000000000000UL |
302 | #define RCP_HC_BIT 53 | 299 | #define RCP_PCL_BIT 0x0080000000000000UL |
303 | #define RCP_GR_BIT 50 | 300 | #define RCP_HR_BIT 0x0040000000000000UL |
304 | #define RCP_GC_BIT 49 | 301 | #define RCP_HC_BIT 0x0020000000000000UL |
305 | 302 | #define RCP_GR_BIT 0x0004000000000000UL | |
306 | /* User dirty bit for KVM's migration feature */ | 303 | #define RCP_GC_BIT 0x0002000000000000UL |
307 | #define KVM_UD_BIT 47 | 304 | |
305 | /* User dirty / referenced bit for KVM's migration feature */ | ||
306 | #define KVM_UR_BIT 0x0000800000000000UL | ||
307 | #define KVM_UC_BIT 0x0000400000000000UL | ||
308 | 308 | ||
309 | #ifndef __s390x__ | 309 | #ifndef __s390x__ |
310 | 310 | ||
@@ -377,85 +377,54 @@ extern unsigned long VMALLOC_START; | |||
377 | #define _ASCE_USER_BITS (_ASCE_SPACE_SWITCH | _ASCE_PRIVATE_SPACE | \ | 377 | #define _ASCE_USER_BITS (_ASCE_SPACE_SWITCH | _ASCE_PRIVATE_SPACE | \ |
378 | _ASCE_ALT_EVENT) | 378 | _ASCE_ALT_EVENT) |
379 | 379 | ||
380 | /* Bits int the storage key */ | ||
381 | #define _PAGE_CHANGED 0x02 /* HW changed bit */ | ||
382 | #define _PAGE_REFERENCED 0x04 /* HW referenced bit */ | ||
383 | |||
384 | /* | 380 | /* |
385 | * Page protection definitions. | 381 | * Page protection definitions. |
386 | */ | 382 | */ |
387 | #define PAGE_NONE __pgprot(_PAGE_TYPE_NONE) | 383 | #define PAGE_NONE __pgprot(_PAGE_TYPE_NONE) |
388 | #define PAGE_RO __pgprot(_PAGE_TYPE_RO) | 384 | #define PAGE_RO __pgprot(_PAGE_TYPE_RO) |
389 | #define PAGE_RW __pgprot(_PAGE_TYPE_RW) | 385 | #define PAGE_RW __pgprot(_PAGE_TYPE_RW) |
390 | #define PAGE_EX_RO __pgprot(_PAGE_TYPE_EX_RO) | ||
391 | #define PAGE_EX_RW __pgprot(_PAGE_TYPE_EX_RW) | ||
392 | 386 | ||
393 | #define PAGE_KERNEL PAGE_RW | 387 | #define PAGE_KERNEL PAGE_RW |
394 | #define PAGE_COPY PAGE_RO | 388 | #define PAGE_COPY PAGE_RO |
395 | 389 | ||
396 | /* | 390 | /* |
397 | * Dependent on the EXEC_PROTECT option s390 can do execute protection. | 391 | * On s390 the page table entry has an invalid bit and a read-only bit. |
398 | * Write permission always implies read permission. In theory with a | 392 | * Read permission implies execute permission and write permission |
399 | * primary/secondary page table execute only can be implemented but | 393 | * implies read permission. |
400 | * it would cost an additional bit in the pte to distinguish all the | ||
401 | * different pte types. To avoid that execute permission currently | ||
402 | * implies read permission as well. | ||
403 | */ | 394 | */ |
404 | /*xwr*/ | 395 | /*xwr*/ |
405 | #define __P000 PAGE_NONE | 396 | #define __P000 PAGE_NONE |
406 | #define __P001 PAGE_RO | 397 | #define __P001 PAGE_RO |
407 | #define __P010 PAGE_RO | 398 | #define __P010 PAGE_RO |
408 | #define __P011 PAGE_RO | 399 | #define __P011 PAGE_RO |
409 | #define __P100 PAGE_EX_RO | 400 | #define __P100 PAGE_RO |
410 | #define __P101 PAGE_EX_RO | 401 | #define __P101 PAGE_RO |
411 | #define __P110 PAGE_EX_RO | 402 | #define __P110 PAGE_RO |
412 | #define __P111 PAGE_EX_RO | 403 | #define __P111 PAGE_RO |
413 | 404 | ||
414 | #define __S000 PAGE_NONE | 405 | #define __S000 PAGE_NONE |
415 | #define __S001 PAGE_RO | 406 | #define __S001 PAGE_RO |
416 | #define __S010 PAGE_RW | 407 | #define __S010 PAGE_RW |
417 | #define __S011 PAGE_RW | 408 | #define __S011 PAGE_RW |
418 | #define __S100 PAGE_EX_RO | 409 | #define __S100 PAGE_RO |
419 | #define __S101 PAGE_EX_RO | 410 | #define __S101 PAGE_RO |
420 | #define __S110 PAGE_EX_RW | 411 | #define __S110 PAGE_RW |
421 | #define __S111 PAGE_EX_RW | 412 | #define __S111 PAGE_RW |
422 | |||
423 | #ifndef __s390x__ | ||
424 | # define PxD_SHADOW_SHIFT 1 | ||
425 | #else /* __s390x__ */ | ||
426 | # define PxD_SHADOW_SHIFT 2 | ||
427 | #endif /* __s390x__ */ | ||
428 | 413 | ||
429 | static inline void *get_shadow_table(void *table) | 414 | static inline int mm_exclusive(struct mm_struct *mm) |
430 | { | 415 | { |
431 | unsigned long addr, offset; | 416 | return likely(mm == current->active_mm && |
432 | struct page *page; | 417 | atomic_read(&mm->context.attach_count) <= 1); |
433 | |||
434 | addr = (unsigned long) table; | ||
435 | offset = addr & ((PAGE_SIZE << PxD_SHADOW_SHIFT) - 1); | ||
436 | page = virt_to_page((void *)(addr ^ offset)); | ||
437 | return (void *)(addr_t)(page->index ? (page->index | offset) : 0UL); | ||
438 | } | 418 | } |
439 | 419 | ||
440 | /* | 420 | static inline int mm_has_pgste(struct mm_struct *mm) |
441 | * Certain architectures need to do special things when PTEs | ||
442 | * within a page table are directly modified. Thus, the following | ||
443 | * hook is made available. | ||
444 | */ | ||
445 | static inline void set_pte_at(struct mm_struct *mm, unsigned long addr, | ||
446 | pte_t *ptep, pte_t entry) | ||
447 | { | 421 | { |
448 | *ptep = entry; | 422 | #ifdef CONFIG_PGSTE |
449 | if (mm->context.noexec) { | 423 | if (unlikely(mm->context.has_pgste)) |
450 | if (!(pte_val(entry) & _PAGE_INVALID) && | 424 | return 1; |
451 | (pte_val(entry) & _PAGE_SWX)) | 425 | #endif |
452 | pte_val(entry) |= _PAGE_RO; | 426 | return 0; |
453 | else | ||
454 | pte_val(entry) = _PAGE_TYPE_EMPTY; | ||
455 | ptep[PTRS_PER_PTE] = entry; | ||
456 | } | ||
457 | } | 427 | } |
458 | |||
459 | /* | 428 | /* |
460 | * pgd/pmd/pte query functions | 429 | * pgd/pmd/pte query functions |
461 | */ | 430 | */ |
@@ -568,52 +537,127 @@ static inline int pte_special(pte_t pte) | |||
568 | } | 537 | } |
569 | 538 | ||
570 | #define __HAVE_ARCH_PTE_SAME | 539 | #define __HAVE_ARCH_PTE_SAME |
571 | #define pte_same(a,b) (pte_val(a) == pte_val(b)) | 540 | static inline int pte_same(pte_t a, pte_t b) |
541 | { | ||
542 | return pte_val(a) == pte_val(b); | ||
543 | } | ||
572 | 544 | ||
573 | static inline void rcp_lock(pte_t *ptep) | 545 | static inline pgste_t pgste_get_lock(pte_t *ptep) |
574 | { | 546 | { |
547 | unsigned long new = 0; | ||
575 | #ifdef CONFIG_PGSTE | 548 | #ifdef CONFIG_PGSTE |
576 | unsigned long *pgste = (unsigned long *) (ptep + PTRS_PER_PTE); | 549 | unsigned long old; |
550 | |||
577 | preempt_disable(); | 551 | preempt_disable(); |
578 | while (test_and_set_bit(RCP_PCL_BIT, pgste)) | 552 | asm( |
579 | ; | 553 | " lg %0,%2\n" |
554 | "0: lgr %1,%0\n" | ||
555 | " nihh %0,0xff7f\n" /* clear RCP_PCL_BIT in old */ | ||
556 | " oihh %1,0x0080\n" /* set RCP_PCL_BIT in new */ | ||
557 | " csg %0,%1,%2\n" | ||
558 | " jl 0b\n" | ||
559 | : "=&d" (old), "=&d" (new), "=Q" (ptep[PTRS_PER_PTE]) | ||
560 | : "Q" (ptep[PTRS_PER_PTE]) : "cc"); | ||
580 | #endif | 561 | #endif |
562 | return __pgste(new); | ||
581 | } | 563 | } |
582 | 564 | ||
583 | static inline void rcp_unlock(pte_t *ptep) | 565 | static inline void pgste_set_unlock(pte_t *ptep, pgste_t pgste) |
584 | { | 566 | { |
585 | #ifdef CONFIG_PGSTE | 567 | #ifdef CONFIG_PGSTE |
586 | unsigned long *pgste = (unsigned long *) (ptep + PTRS_PER_PTE); | 568 | asm( |
587 | clear_bit(RCP_PCL_BIT, pgste); | 569 | " nihh %1,0xff7f\n" /* clear RCP_PCL_BIT */ |
570 | " stg %1,%0\n" | ||
571 | : "=Q" (ptep[PTRS_PER_PTE]) | ||
572 | : "d" (pgste_val(pgste)), "Q" (ptep[PTRS_PER_PTE]) : "cc"); | ||
588 | preempt_enable(); | 573 | preempt_enable(); |
589 | #endif | 574 | #endif |
590 | } | 575 | } |
591 | 576 | ||
592 | /* forward declaration for SetPageUptodate in page-flags.h*/ | 577 | static inline pgste_t pgste_update_all(pte_t *ptep, pgste_t pgste) |
593 | static inline void page_clear_dirty(struct page *page, int mapped); | ||
594 | #include <linux/page-flags.h> | ||
595 | |||
596 | static inline void ptep_rcp_copy(pte_t *ptep) | ||
597 | { | 578 | { |
598 | #ifdef CONFIG_PGSTE | 579 | #ifdef CONFIG_PGSTE |
599 | struct page *page = virt_to_page(pte_val(*ptep)); | 580 | unsigned long pfn, bits; |
600 | unsigned int skey; | 581 | unsigned char skey; |
601 | unsigned long *pgste = (unsigned long *) (ptep + PTRS_PER_PTE); | 582 | |
602 | 583 | pfn = pte_val(*ptep) >> PAGE_SHIFT; | |
603 | skey = page_get_storage_key(page_to_phys(page)); | 584 | skey = page_get_storage_key(pfn); |
604 | if (skey & _PAGE_CHANGED) { | 585 | bits = skey & (_PAGE_CHANGED | _PAGE_REFERENCED); |
605 | set_bit_simple(RCP_GC_BIT, pgste); | 586 | /* Clear page changed & referenced bit in the storage key */ |
606 | set_bit_simple(KVM_UD_BIT, pgste); | 587 | if (bits) { |
588 | skey ^= bits; | ||
589 | page_set_storage_key(pfn, skey, 1); | ||
607 | } | 590 | } |
608 | if (skey & _PAGE_REFERENCED) | 591 | /* Transfer page changed & referenced bit to guest bits in pgste */ |
609 | set_bit_simple(RCP_GR_BIT, pgste); | 592 | pgste_val(pgste) |= bits << 48; /* RCP_GR_BIT & RCP_GC_BIT */ |
610 | if (test_and_clear_bit_simple(RCP_HC_BIT, pgste)) { | 593 | /* Get host changed & referenced bits from pgste */ |
611 | SetPageDirty(page); | 594 | bits |= (pgste_val(pgste) & (RCP_HR_BIT | RCP_HC_BIT)) >> 52; |
612 | set_bit_simple(KVM_UD_BIT, pgste); | 595 | /* Clear host bits in pgste. */ |
613 | } | 596 | pgste_val(pgste) &= ~(RCP_HR_BIT | RCP_HC_BIT); |
614 | if (test_and_clear_bit_simple(RCP_HR_BIT, pgste)) | 597 | pgste_val(pgste) &= ~(RCP_ACC_BITS | RCP_FP_BIT); |
615 | SetPageReferenced(page); | 598 | /* Copy page access key and fetch protection bit to pgste */ |
599 | pgste_val(pgste) |= | ||
600 | (unsigned long) (skey & (_PAGE_ACC_BITS | _PAGE_FP_BIT)) << 56; | ||
601 | /* Transfer changed and referenced to kvm user bits */ | ||
602 | pgste_val(pgste) |= bits << 45; /* KVM_UR_BIT & KVM_UC_BIT */ | ||
603 | /* Transfer changed & referenced to pte sofware bits */ | ||
604 | pte_val(*ptep) |= bits << 1; /* _PAGE_SWR & _PAGE_SWC */ | ||
616 | #endif | 605 | #endif |
606 | return pgste; | ||
607 | |||
608 | } | ||
609 | |||
610 | static inline pgste_t pgste_update_young(pte_t *ptep, pgste_t pgste) | ||
611 | { | ||
612 | #ifdef CONFIG_PGSTE | ||
613 | int young; | ||
614 | |||
615 | young = page_reset_referenced(pte_val(*ptep) & PAGE_MASK); | ||
616 | /* Transfer page referenced bit to pte software bit (host view) */ | ||
617 | if (young || (pgste_val(pgste) & RCP_HR_BIT)) | ||
618 | pte_val(*ptep) |= _PAGE_SWR; | ||
619 | /* Clear host referenced bit in pgste. */ | ||
620 | pgste_val(pgste) &= ~RCP_HR_BIT; | ||
621 | /* Transfer page referenced bit to guest bit in pgste */ | ||
622 | pgste_val(pgste) |= (unsigned long) young << 50; /* set RCP_GR_BIT */ | ||
623 | #endif | ||
624 | return pgste; | ||
625 | |||
626 | } | ||
627 | |||
628 | static inline void pgste_set_pte(pte_t *ptep, pgste_t pgste) | ||
629 | { | ||
630 | #ifdef CONFIG_PGSTE | ||
631 | unsigned long pfn; | ||
632 | unsigned long okey, nkey; | ||
633 | |||
634 | pfn = pte_val(*ptep) >> PAGE_SHIFT; | ||
635 | okey = nkey = page_get_storage_key(pfn); | ||
636 | nkey &= ~(_PAGE_ACC_BITS | _PAGE_FP_BIT); | ||
637 | /* Set page access key and fetch protection bit from pgste */ | ||
638 | nkey |= (pgste_val(pgste) & (RCP_ACC_BITS | RCP_FP_BIT)) >> 56; | ||
639 | if (okey != nkey) | ||
640 | page_set_storage_key(pfn, nkey, 1); | ||
641 | #endif | ||
642 | } | ||
643 | |||
644 | /* | ||
645 | * Certain architectures need to do special things when PTEs | ||
646 | * within a page table are directly modified. Thus, the following | ||
647 | * hook is made available. | ||
648 | */ | ||
649 | static inline void set_pte_at(struct mm_struct *mm, unsigned long addr, | ||
650 | pte_t *ptep, pte_t entry) | ||
651 | { | ||
652 | pgste_t pgste; | ||
653 | |||
654 | if (mm_has_pgste(mm)) { | ||
655 | pgste = pgste_get_lock(ptep); | ||
656 | pgste_set_pte(ptep, pgste); | ||
657 | *ptep = entry; | ||
658 | pgste_set_unlock(ptep, pgste); | ||
659 | } else | ||
660 | *ptep = entry; | ||
617 | } | 661 | } |
618 | 662 | ||
619 | /* | 663 | /* |
@@ -627,19 +671,19 @@ static inline int pte_write(pte_t pte) | |||
627 | 671 | ||
628 | static inline int pte_dirty(pte_t pte) | 672 | static inline int pte_dirty(pte_t pte) |
629 | { | 673 | { |
630 | /* A pte is neither clean nor dirty on s/390. The dirty bit | 674 | #ifdef CONFIG_PGSTE |
631 | * is in the storage key. See page_test_and_clear_dirty for | 675 | if (pte_val(pte) & _PAGE_SWC) |
632 | * details. | 676 | return 1; |
633 | */ | 677 | #endif |
634 | return 0; | 678 | return 0; |
635 | } | 679 | } |
636 | 680 | ||
637 | static inline int pte_young(pte_t pte) | 681 | static inline int pte_young(pte_t pte) |
638 | { | 682 | { |
639 | /* A pte is neither young nor old on s/390. The young bit | 683 | #ifdef CONFIG_PGSTE |
640 | * is in the storage key. See page_test_and_clear_young for | 684 | if (pte_val(pte) & _PAGE_SWR) |
641 | * details. | 685 | return 1; |
642 | */ | 686 | #endif |
643 | return 0; | 687 | return 0; |
644 | } | 688 | } |
645 | 689 | ||
@@ -647,64 +691,30 @@ static inline int pte_young(pte_t pte) | |||
647 | * pgd/pmd/pte modification functions | 691 | * pgd/pmd/pte modification functions |
648 | */ | 692 | */ |
649 | 693 | ||
650 | #ifndef __s390x__ | 694 | static inline void pgd_clear(pgd_t *pgd) |
651 | |||
652 | #define pgd_clear(pgd) do { } while (0) | ||
653 | #define pud_clear(pud) do { } while (0) | ||
654 | |||
655 | #else /* __s390x__ */ | ||
656 | |||
657 | static inline void pgd_clear_kernel(pgd_t * pgd) | ||
658 | { | 695 | { |
696 | #ifdef __s390x__ | ||
659 | if ((pgd_val(*pgd) & _REGION_ENTRY_TYPE_MASK) == _REGION_ENTRY_TYPE_R2) | 697 | if ((pgd_val(*pgd) & _REGION_ENTRY_TYPE_MASK) == _REGION_ENTRY_TYPE_R2) |
660 | pgd_val(*pgd) = _REGION2_ENTRY_EMPTY; | 698 | pgd_val(*pgd) = _REGION2_ENTRY_EMPTY; |
699 | #endif | ||
661 | } | 700 | } |
662 | 701 | ||
663 | static inline void pgd_clear(pgd_t * pgd) | 702 | static inline void pud_clear(pud_t *pud) |
664 | { | ||
665 | pgd_t *shadow = get_shadow_table(pgd); | ||
666 | |||
667 | pgd_clear_kernel(pgd); | ||
668 | if (shadow) | ||
669 | pgd_clear_kernel(shadow); | ||
670 | } | ||
671 | |||
672 | static inline void pud_clear_kernel(pud_t *pud) | ||
673 | { | 703 | { |
704 | #ifdef __s390x__ | ||
674 | if ((pud_val(*pud) & _REGION_ENTRY_TYPE_MASK) == _REGION_ENTRY_TYPE_R3) | 705 | if ((pud_val(*pud) & _REGION_ENTRY_TYPE_MASK) == _REGION_ENTRY_TYPE_R3) |
675 | pud_val(*pud) = _REGION3_ENTRY_EMPTY; | 706 | pud_val(*pud) = _REGION3_ENTRY_EMPTY; |
707 | #endif | ||
676 | } | 708 | } |
677 | 709 | ||
678 | static inline void pud_clear(pud_t *pud) | 710 | static inline void pmd_clear(pmd_t *pmdp) |
679 | { | ||
680 | pud_t *shadow = get_shadow_table(pud); | ||
681 | |||
682 | pud_clear_kernel(pud); | ||
683 | if (shadow) | ||
684 | pud_clear_kernel(shadow); | ||
685 | } | ||
686 | |||
687 | #endif /* __s390x__ */ | ||
688 | |||
689 | static inline void pmd_clear_kernel(pmd_t * pmdp) | ||
690 | { | 711 | { |
691 | pmd_val(*pmdp) = _SEGMENT_ENTRY_EMPTY; | 712 | pmd_val(*pmdp) = _SEGMENT_ENTRY_EMPTY; |
692 | } | 713 | } |
693 | 714 | ||
694 | static inline void pmd_clear(pmd_t *pmd) | ||
695 | { | ||
696 | pmd_t *shadow = get_shadow_table(pmd); | ||
697 | |||
698 | pmd_clear_kernel(pmd); | ||
699 | if (shadow) | ||
700 | pmd_clear_kernel(shadow); | ||
701 | } | ||
702 | |||
703 | static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) | 715 | static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) |
704 | { | 716 | { |
705 | pte_val(*ptep) = _PAGE_TYPE_EMPTY; | 717 | pte_val(*ptep) = _PAGE_TYPE_EMPTY; |
706 | if (mm->context.noexec) | ||
707 | pte_val(ptep[PTRS_PER_PTE]) = _PAGE_TYPE_EMPTY; | ||
708 | } | 718 | } |
709 | 719 | ||
710 | /* | 720 | /* |
@@ -734,35 +744,27 @@ static inline pte_t pte_mkwrite(pte_t pte) | |||
734 | 744 | ||
735 | static inline pte_t pte_mkclean(pte_t pte) | 745 | static inline pte_t pte_mkclean(pte_t pte) |
736 | { | 746 | { |
737 | /* The only user of pte_mkclean is the fork() code. | 747 | #ifdef CONFIG_PGSTE |
738 | We must *not* clear the *physical* page dirty bit | 748 | pte_val(pte) &= ~_PAGE_SWC; |
739 | just because fork() wants to clear the dirty bit in | 749 | #endif |
740 | *one* of the page's mappings. So we just do nothing. */ | ||
741 | return pte; | 750 | return pte; |
742 | } | 751 | } |
743 | 752 | ||
744 | static inline pte_t pte_mkdirty(pte_t pte) | 753 | static inline pte_t pte_mkdirty(pte_t pte) |
745 | { | 754 | { |
746 | /* We do not explicitly set the dirty bit because the | ||
747 | * sske instruction is slow. It is faster to let the | ||
748 | * next instruction set the dirty bit. | ||
749 | */ | ||
750 | return pte; | 755 | return pte; |
751 | } | 756 | } |
752 | 757 | ||
753 | static inline pte_t pte_mkold(pte_t pte) | 758 | static inline pte_t pte_mkold(pte_t pte) |
754 | { | 759 | { |
755 | /* S/390 doesn't keep its dirty/referenced bit in the pte. | 760 | #ifdef CONFIG_PGSTE |
756 | * There is no point in clearing the real referenced bit. | 761 | pte_val(pte) &= ~_PAGE_SWR; |
757 | */ | 762 | #endif |
758 | return pte; | 763 | return pte; |
759 | } | 764 | } |
760 | 765 | ||
761 | static inline pte_t pte_mkyoung(pte_t pte) | 766 | static inline pte_t pte_mkyoung(pte_t pte) |
762 | { | 767 | { |
763 | /* S/390 doesn't keep its dirty/referenced bit in the pte. | ||
764 | * There is no point in setting the real referenced bit. | ||
765 | */ | ||
766 | return pte; | 768 | return pte; |
767 | } | 769 | } |
768 | 770 | ||
@@ -800,62 +802,60 @@ static inline pte_t pte_mkhuge(pte_t pte) | |||
800 | } | 802 | } |
801 | #endif | 803 | #endif |
802 | 804 | ||
803 | #ifdef CONFIG_PGSTE | ||
804 | /* | 805 | /* |
805 | * Get (and clear) the user dirty bit for a PTE. | 806 | * Get (and clear) the user dirty bit for a pte. |
806 | */ | 807 | */ |
807 | static inline int kvm_s390_test_and_clear_page_dirty(struct mm_struct *mm, | 808 | static inline int ptep_test_and_clear_user_dirty(struct mm_struct *mm, |
808 | pte_t *ptep) | 809 | pte_t *ptep) |
809 | { | 810 | { |
810 | int dirty; | 811 | pgste_t pgste; |
811 | unsigned long *pgste; | 812 | int dirty = 0; |
812 | struct page *page; | 813 | |
813 | unsigned int skey; | 814 | if (mm_has_pgste(mm)) { |
814 | 815 | pgste = pgste_get_lock(ptep); | |
815 | if (!mm->context.has_pgste) | 816 | pgste = pgste_update_all(ptep, pgste); |
816 | return -EINVAL; | 817 | dirty = !!(pgste_val(pgste) & KVM_UC_BIT); |
817 | rcp_lock(ptep); | 818 | pgste_val(pgste) &= ~KVM_UC_BIT; |
818 | pgste = (unsigned long *) (ptep + PTRS_PER_PTE); | 819 | pgste_set_unlock(ptep, pgste); |
819 | page = virt_to_page(pte_val(*ptep)); | 820 | return dirty; |
820 | skey = page_get_storage_key(page_to_phys(page)); | ||
821 | if (skey & _PAGE_CHANGED) { | ||
822 | set_bit_simple(RCP_GC_BIT, pgste); | ||
823 | set_bit_simple(KVM_UD_BIT, pgste); | ||
824 | } | 821 | } |
825 | if (test_and_clear_bit_simple(RCP_HC_BIT, pgste)) { | ||
826 | SetPageDirty(page); | ||
827 | set_bit_simple(KVM_UD_BIT, pgste); | ||
828 | } | ||
829 | dirty = test_and_clear_bit_simple(KVM_UD_BIT, pgste); | ||
830 | if (skey & _PAGE_CHANGED) | ||
831 | page_clear_dirty(page, 1); | ||
832 | rcp_unlock(ptep); | ||
833 | return dirty; | 822 | return dirty; |
834 | } | 823 | } |
835 | #endif | 824 | |
825 | /* | ||
826 | * Get (and clear) the user referenced bit for a pte. | ||
827 | */ | ||
828 | static inline int ptep_test_and_clear_user_young(struct mm_struct *mm, | ||
829 | pte_t *ptep) | ||
830 | { | ||
831 | pgste_t pgste; | ||
832 | int young = 0; | ||
833 | |||
834 | if (mm_has_pgste(mm)) { | ||
835 | pgste = pgste_get_lock(ptep); | ||
836 | pgste = pgste_update_young(ptep, pgste); | ||
837 | young = !!(pgste_val(pgste) & KVM_UR_BIT); | ||
838 | pgste_val(pgste) &= ~KVM_UR_BIT; | ||
839 | pgste_set_unlock(ptep, pgste); | ||
840 | } | ||
841 | return young; | ||
842 | } | ||
836 | 843 | ||
837 | #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG | 844 | #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG |
838 | static inline int ptep_test_and_clear_young(struct vm_area_struct *vma, | 845 | static inline int ptep_test_and_clear_young(struct vm_area_struct *vma, |
839 | unsigned long addr, pte_t *ptep) | 846 | unsigned long addr, pte_t *ptep) |
840 | { | 847 | { |
841 | #ifdef CONFIG_PGSTE | 848 | pgste_t pgste; |
842 | unsigned long physpage; | 849 | pte_t pte; |
843 | int young; | ||
844 | unsigned long *pgste; | ||
845 | 850 | ||
846 | if (!vma->vm_mm->context.has_pgste) | 851 | if (mm_has_pgste(vma->vm_mm)) { |
847 | return 0; | 852 | pgste = pgste_get_lock(ptep); |
848 | physpage = pte_val(*ptep) & PAGE_MASK; | 853 | pgste = pgste_update_young(ptep, pgste); |
849 | pgste = (unsigned long *) (ptep + PTRS_PER_PTE); | 854 | pte = *ptep; |
850 | 855 | *ptep = pte_mkold(pte); | |
851 | young = ((page_get_storage_key(physpage) & _PAGE_REFERENCED) != 0); | 856 | pgste_set_unlock(ptep, pgste); |
852 | rcp_lock(ptep); | 857 | return pte_young(pte); |
853 | if (young) | 858 | } |
854 | set_bit_simple(RCP_GR_BIT, pgste); | ||
855 | young |= test_and_clear_bit_simple(RCP_HR_BIT, pgste); | ||
856 | rcp_unlock(ptep); | ||
857 | return young; | ||
858 | #endif | ||
859 | return 0; | 859 | return 0; |
860 | } | 860 | } |
861 | 861 | ||
@@ -867,10 +867,7 @@ static inline int ptep_clear_flush_young(struct vm_area_struct *vma, | |||
867 | * On s390 reference bits are in storage key and never in TLB | 867 | * On s390 reference bits are in storage key and never in TLB |
868 | * With virtualization we handle the reference bit, without we | 868 | * With virtualization we handle the reference bit, without we |
869 | * we can simply return */ | 869 | * we can simply return */ |
870 | #ifdef CONFIG_PGSTE | ||
871 | return ptep_test_and_clear_young(vma, address, ptep); | 870 | return ptep_test_and_clear_young(vma, address, ptep); |
872 | #endif | ||
873 | return 0; | ||
874 | } | 871 | } |
875 | 872 | ||
876 | static inline void __ptep_ipte(unsigned long address, pte_t *ptep) | 873 | static inline void __ptep_ipte(unsigned long address, pte_t *ptep) |
@@ -890,25 +887,6 @@ static inline void __ptep_ipte(unsigned long address, pte_t *ptep) | |||
890 | } | 887 | } |
891 | } | 888 | } |
892 | 889 | ||
893 | static inline void ptep_invalidate(struct mm_struct *mm, | ||
894 | unsigned long address, pte_t *ptep) | ||
895 | { | ||
896 | if (mm->context.has_pgste) { | ||
897 | rcp_lock(ptep); | ||
898 | __ptep_ipte(address, ptep); | ||
899 | ptep_rcp_copy(ptep); | ||
900 | pte_val(*ptep) = _PAGE_TYPE_EMPTY; | ||
901 | rcp_unlock(ptep); | ||
902 | return; | ||
903 | } | ||
904 | __ptep_ipte(address, ptep); | ||
905 | pte_val(*ptep) = _PAGE_TYPE_EMPTY; | ||
906 | if (mm->context.noexec) { | ||
907 | __ptep_ipte(address, ptep + PTRS_PER_PTE); | ||
908 | pte_val(*(ptep + PTRS_PER_PTE)) = _PAGE_TYPE_EMPTY; | ||
909 | } | ||
910 | } | ||
911 | |||
912 | /* | 890 | /* |
913 | * This is hard to understand. ptep_get_and_clear and ptep_clear_flush | 891 | * This is hard to understand. ptep_get_and_clear and ptep_clear_flush |
914 | * both clear the TLB for the unmapped pte. The reason is that | 892 | * both clear the TLB for the unmapped pte. The reason is that |
@@ -923,24 +901,72 @@ static inline void ptep_invalidate(struct mm_struct *mm, | |||
923 | * is a nop. | 901 | * is a nop. |
924 | */ | 902 | */ |
925 | #define __HAVE_ARCH_PTEP_GET_AND_CLEAR | 903 | #define __HAVE_ARCH_PTEP_GET_AND_CLEAR |
926 | #define ptep_get_and_clear(__mm, __address, __ptep) \ | 904 | static inline pte_t ptep_get_and_clear(struct mm_struct *mm, |
927 | ({ \ | 905 | unsigned long address, pte_t *ptep) |
928 | pte_t __pte = *(__ptep); \ | 906 | { |
929 | (__mm)->context.flush_mm = 1; \ | 907 | pgste_t pgste; |
930 | if (atomic_read(&(__mm)->context.attach_count) > 1 || \ | 908 | pte_t pte; |
931 | (__mm) != current->active_mm) \ | 909 | |
932 | ptep_invalidate(__mm, __address, __ptep); \ | 910 | mm->context.flush_mm = 1; |
933 | else \ | 911 | if (mm_has_pgste(mm)) |
934 | pte_clear((__mm), (__address), (__ptep)); \ | 912 | pgste = pgste_get_lock(ptep); |
935 | __pte; \ | 913 | |
936 | }) | 914 | pte = *ptep; |
915 | if (!mm_exclusive(mm)) | ||
916 | __ptep_ipte(address, ptep); | ||
917 | pte_val(*ptep) = _PAGE_TYPE_EMPTY; | ||
918 | |||
919 | if (mm_has_pgste(mm)) { | ||
920 | pgste = pgste_update_all(&pte, pgste); | ||
921 | pgste_set_unlock(ptep, pgste); | ||
922 | } | ||
923 | return pte; | ||
924 | } | ||
925 | |||
926 | #define __HAVE_ARCH_PTEP_MODIFY_PROT_TRANSACTION | ||
927 | static inline pte_t ptep_modify_prot_start(struct mm_struct *mm, | ||
928 | unsigned long address, | ||
929 | pte_t *ptep) | ||
930 | { | ||
931 | pte_t pte; | ||
932 | |||
933 | mm->context.flush_mm = 1; | ||
934 | if (mm_has_pgste(mm)) | ||
935 | pgste_get_lock(ptep); | ||
936 | |||
937 | pte = *ptep; | ||
938 | if (!mm_exclusive(mm)) | ||
939 | __ptep_ipte(address, ptep); | ||
940 | return pte; | ||
941 | } | ||
942 | |||
943 | static inline void ptep_modify_prot_commit(struct mm_struct *mm, | ||
944 | unsigned long address, | ||
945 | pte_t *ptep, pte_t pte) | ||
946 | { | ||
947 | *ptep = pte; | ||
948 | if (mm_has_pgste(mm)) | ||
949 | pgste_set_unlock(ptep, *(pgste_t *)(ptep + PTRS_PER_PTE)); | ||
950 | } | ||
937 | 951 | ||
938 | #define __HAVE_ARCH_PTEP_CLEAR_FLUSH | 952 | #define __HAVE_ARCH_PTEP_CLEAR_FLUSH |
939 | static inline pte_t ptep_clear_flush(struct vm_area_struct *vma, | 953 | static inline pte_t ptep_clear_flush(struct vm_area_struct *vma, |
940 | unsigned long address, pte_t *ptep) | 954 | unsigned long address, pte_t *ptep) |
941 | { | 955 | { |
942 | pte_t pte = *ptep; | 956 | pgste_t pgste; |
943 | ptep_invalidate(vma->vm_mm, address, ptep); | 957 | pte_t pte; |
958 | |||
959 | if (mm_has_pgste(vma->vm_mm)) | ||
960 | pgste = pgste_get_lock(ptep); | ||
961 | |||
962 | pte = *ptep; | ||
963 | __ptep_ipte(address, ptep); | ||
964 | pte_val(*ptep) = _PAGE_TYPE_EMPTY; | ||
965 | |||
966 | if (mm_has_pgste(vma->vm_mm)) { | ||
967 | pgste = pgste_update_all(&pte, pgste); | ||
968 | pgste_set_unlock(ptep, pgste); | ||
969 | } | ||
944 | return pte; | 970 | return pte; |
945 | } | 971 | } |
946 | 972 | ||
@@ -953,76 +979,67 @@ static inline pte_t ptep_clear_flush(struct vm_area_struct *vma, | |||
953 | */ | 979 | */ |
954 | #define __HAVE_ARCH_PTEP_GET_AND_CLEAR_FULL | 980 | #define __HAVE_ARCH_PTEP_GET_AND_CLEAR_FULL |
955 | static inline pte_t ptep_get_and_clear_full(struct mm_struct *mm, | 981 | static inline pte_t ptep_get_and_clear_full(struct mm_struct *mm, |
956 | unsigned long addr, | 982 | unsigned long address, |
957 | pte_t *ptep, int full) | 983 | pte_t *ptep, int full) |
958 | { | 984 | { |
959 | pte_t pte = *ptep; | 985 | pgste_t pgste; |
986 | pte_t pte; | ||
987 | |||
988 | if (mm_has_pgste(mm)) | ||
989 | pgste = pgste_get_lock(ptep); | ||
990 | |||
991 | pte = *ptep; | ||
992 | if (!full) | ||
993 | __ptep_ipte(address, ptep); | ||
994 | pte_val(*ptep) = _PAGE_TYPE_EMPTY; | ||
960 | 995 | ||
961 | if (full) | 996 | if (mm_has_pgste(mm)) { |
962 | pte_clear(mm, addr, ptep); | 997 | pgste = pgste_update_all(&pte, pgste); |
963 | else | 998 | pgste_set_unlock(ptep, pgste); |
964 | ptep_invalidate(mm, addr, ptep); | 999 | } |
965 | return pte; | 1000 | return pte; |
966 | } | 1001 | } |
967 | 1002 | ||
968 | #define __HAVE_ARCH_PTEP_SET_WRPROTECT | 1003 | #define __HAVE_ARCH_PTEP_SET_WRPROTECT |
969 | #define ptep_set_wrprotect(__mm, __addr, __ptep) \ | 1004 | static inline pte_t ptep_set_wrprotect(struct mm_struct *mm, |
970 | ({ \ | 1005 | unsigned long address, pte_t *ptep) |
971 | pte_t __pte = *(__ptep); \ | 1006 | { |
972 | if (pte_write(__pte)) { \ | 1007 | pgste_t pgste; |
973 | (__mm)->context.flush_mm = 1; \ | 1008 | pte_t pte = *ptep; |
974 | if (atomic_read(&(__mm)->context.attach_count) > 1 || \ | ||
975 | (__mm) != current->active_mm) \ | ||
976 | ptep_invalidate(__mm, __addr, __ptep); \ | ||
977 | set_pte_at(__mm, __addr, __ptep, pte_wrprotect(__pte)); \ | ||
978 | } \ | ||
979 | }) | ||
980 | 1009 | ||
981 | #define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS | 1010 | if (pte_write(pte)) { |
982 | #define ptep_set_access_flags(__vma, __addr, __ptep, __entry, __dirty) \ | 1011 | mm->context.flush_mm = 1; |
983 | ({ \ | 1012 | if (mm_has_pgste(mm)) |
984 | int __changed = !pte_same(*(__ptep), __entry); \ | 1013 | pgste = pgste_get_lock(ptep); |
985 | if (__changed) { \ | ||
986 | ptep_invalidate((__vma)->vm_mm, __addr, __ptep); \ | ||
987 | set_pte_at((__vma)->vm_mm, __addr, __ptep, __entry); \ | ||
988 | } \ | ||
989 | __changed; \ | ||
990 | }) | ||
991 | 1014 | ||
992 | /* | 1015 | if (!mm_exclusive(mm)) |
993 | * Test and clear dirty bit in storage key. | 1016 | __ptep_ipte(address, ptep); |
994 | * We can't clear the changed bit atomically. This is a potential | 1017 | *ptep = pte_wrprotect(pte); |
995 | * race against modification of the referenced bit. This function | ||
996 | * should therefore only be called if it is not mapped in any | ||
997 | * address space. | ||
998 | */ | ||
999 | #define __HAVE_ARCH_PAGE_TEST_DIRTY | ||
1000 | static inline int page_test_dirty(struct page *page) | ||
1001 | { | ||
1002 | return (page_get_storage_key(page_to_phys(page)) & _PAGE_CHANGED) != 0; | ||
1003 | } | ||
1004 | 1018 | ||
1005 | #define __HAVE_ARCH_PAGE_CLEAR_DIRTY | 1019 | if (mm_has_pgste(mm)) |
1006 | static inline void page_clear_dirty(struct page *page, int mapped) | 1020 | pgste_set_unlock(ptep, pgste); |
1007 | { | 1021 | } |
1008 | page_set_storage_key(page_to_phys(page), PAGE_DEFAULT_KEY, mapped); | 1022 | return pte; |
1009 | } | 1023 | } |
1010 | 1024 | ||
1011 | /* | 1025 | #define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS |
1012 | * Test and clear referenced bit in storage key. | 1026 | static inline int ptep_set_access_flags(struct vm_area_struct *vma, |
1013 | */ | 1027 | unsigned long address, pte_t *ptep, |
1014 | #define __HAVE_ARCH_PAGE_TEST_AND_CLEAR_YOUNG | 1028 | pte_t entry, int dirty) |
1015 | static inline int page_test_and_clear_young(struct page *page) | ||
1016 | { | 1029 | { |
1017 | unsigned long physpage = page_to_phys(page); | 1030 | pgste_t pgste; |
1018 | int ccode; | 1031 | |
1019 | 1032 | if (pte_same(*ptep, entry)) | |
1020 | asm volatile( | 1033 | return 0; |
1021 | " rrbe 0,%1\n" | 1034 | if (mm_has_pgste(vma->vm_mm)) |
1022 | " ipm %0\n" | 1035 | pgste = pgste_get_lock(ptep); |
1023 | " srl %0,28\n" | 1036 | |
1024 | : "=d" (ccode) : "a" (physpage) : "cc" ); | 1037 | __ptep_ipte(address, ptep); |
1025 | return ccode & 2; | 1038 | *ptep = entry; |
1039 | |||
1040 | if (mm_has_pgste(vma->vm_mm)) | ||
1041 | pgste_set_unlock(ptep, pgste); | ||
1042 | return 1; | ||
1026 | } | 1043 | } |
1027 | 1044 | ||
1028 | /* | 1045 | /* |
diff --git a/arch/s390/include/asm/processor.h b/arch/s390/include/asm/processor.h index 2c79b6416271..1300c3025334 100644 --- a/arch/s390/include/asm/processor.h +++ b/arch/s390/include/asm/processor.h | |||
@@ -84,6 +84,7 @@ struct thread_struct { | |||
84 | struct per_event per_event; /* Cause of the last PER trap */ | 84 | struct per_event per_event; /* Cause of the last PER trap */ |
85 | /* pfault_wait is used to block the process on a pfault event */ | 85 | /* pfault_wait is used to block the process on a pfault event */ |
86 | unsigned long pfault_wait; | 86 | unsigned long pfault_wait; |
87 | struct list_head list; | ||
87 | }; | 88 | }; |
88 | 89 | ||
89 | typedef struct thread_struct thread_struct; | 90 | typedef struct thread_struct thread_struct; |
diff --git a/arch/s390/include/asm/tlbflush.h b/arch/s390/include/asm/tlbflush.h index 29d5d6d4becc..b7a4f2eb0057 100644 --- a/arch/s390/include/asm/tlbflush.h +++ b/arch/s390/include/asm/tlbflush.h | |||
@@ -50,7 +50,7 @@ static inline void __tlb_flush_full(struct mm_struct *mm) | |||
50 | /* | 50 | /* |
51 | * If the process only ran on the local cpu, do a local flush. | 51 | * If the process only ran on the local cpu, do a local flush. |
52 | */ | 52 | */ |
53 | local_cpumask = cpumask_of_cpu(smp_processor_id()); | 53 | cpumask_copy(&local_cpumask, cpumask_of(smp_processor_id())); |
54 | if (cpumask_equal(mm_cpumask(mm), &local_cpumask)) | 54 | if (cpumask_equal(mm_cpumask(mm), &local_cpumask)) |
55 | __tlb_flush_local(); | 55 | __tlb_flush_local(); |
56 | else | 56 | else |
@@ -80,16 +80,11 @@ static inline void __tlb_flush_mm(struct mm_struct * mm) | |||
80 | * on all cpus instead of doing a local flush if the mm | 80 | * on all cpus instead of doing a local flush if the mm |
81 | * only ran on the local cpu. | 81 | * only ran on the local cpu. |
82 | */ | 82 | */ |
83 | if (MACHINE_HAS_IDTE) { | 83 | if (MACHINE_HAS_IDTE) |
84 | if (mm->context.noexec) | ||
85 | __tlb_flush_idte((unsigned long) | ||
86 | get_shadow_table(mm->pgd) | | ||
87 | mm->context.asce_bits); | ||
88 | __tlb_flush_idte((unsigned long) mm->pgd | | 84 | __tlb_flush_idte((unsigned long) mm->pgd | |
89 | mm->context.asce_bits); | 85 | mm->context.asce_bits); |
90 | return; | 86 | else |
91 | } | 87 | __tlb_flush_full(mm); |
92 | __tlb_flush_full(mm); | ||
93 | } | 88 | } |
94 | 89 | ||
95 | static inline void __tlb_flush_mm_cond(struct mm_struct * mm) | 90 | static inline void __tlb_flush_mm_cond(struct mm_struct * mm) |
diff --git a/arch/s390/include/asm/unistd.h b/arch/s390/include/asm/unistd.h index e82152572377..9208e69245a0 100644 --- a/arch/s390/include/asm/unistd.h +++ b/arch/s390/include/asm/unistd.h | |||
@@ -385,6 +385,7 @@ | |||
385 | 385 | ||
386 | /* Ignore system calls that are also reachable via sys_socket */ | 386 | /* Ignore system calls that are also reachable via sys_socket */ |
387 | #define __IGNORE_recvmmsg | 387 | #define __IGNORE_recvmmsg |
388 | #define __IGNORE_sendmmsg | ||
388 | 389 | ||
389 | #define __ARCH_WANT_IPC_PARSE_VERSION | 390 | #define __ARCH_WANT_IPC_PARSE_VERSION |
390 | #define __ARCH_WANT_OLD_READDIR | 391 | #define __ARCH_WANT_OLD_READDIR |
diff --git a/arch/s390/kernel/asm-offsets.c b/arch/s390/kernel/asm-offsets.c index fe03c140002a..edfbd17d7082 100644 --- a/arch/s390/kernel/asm-offsets.c +++ b/arch/s390/kernel/asm-offsets.c | |||
@@ -124,13 +124,11 @@ int main(void) | |||
124 | DEFINE(__LC_LAST_UPDATE_TIMER, offsetof(struct _lowcore, last_update_timer)); | 124 | DEFINE(__LC_LAST_UPDATE_TIMER, offsetof(struct _lowcore, last_update_timer)); |
125 | DEFINE(__LC_LAST_UPDATE_CLOCK, offsetof(struct _lowcore, last_update_clock)); | 125 | DEFINE(__LC_LAST_UPDATE_CLOCK, offsetof(struct _lowcore, last_update_clock)); |
126 | DEFINE(__LC_CURRENT, offsetof(struct _lowcore, current_task)); | 126 | DEFINE(__LC_CURRENT, offsetof(struct _lowcore, current_task)); |
127 | DEFINE(__LC_CURRENT_PID, offsetof(struct _lowcore, current_pid)); | ||
127 | DEFINE(__LC_THREAD_INFO, offsetof(struct _lowcore, thread_info)); | 128 | DEFINE(__LC_THREAD_INFO, offsetof(struct _lowcore, thread_info)); |
128 | DEFINE(__LC_KERNEL_STACK, offsetof(struct _lowcore, kernel_stack)); | 129 | DEFINE(__LC_KERNEL_STACK, offsetof(struct _lowcore, kernel_stack)); |
129 | DEFINE(__LC_ASYNC_STACK, offsetof(struct _lowcore, async_stack)); | 130 | DEFINE(__LC_ASYNC_STACK, offsetof(struct _lowcore, async_stack)); |
130 | DEFINE(__LC_PANIC_STACK, offsetof(struct _lowcore, panic_stack)); | 131 | DEFINE(__LC_PANIC_STACK, offsetof(struct _lowcore, panic_stack)); |
131 | DEFINE(__LC_KERNEL_ASCE, offsetof(struct _lowcore, kernel_asce)); | ||
132 | DEFINE(__LC_USER_ASCE, offsetof(struct _lowcore, user_asce)); | ||
133 | DEFINE(__LC_USER_EXEC_ASCE, offsetof(struct _lowcore, user_exec_asce)); | ||
134 | DEFINE(__LC_INT_CLOCK, offsetof(struct _lowcore, int_clock)); | 132 | DEFINE(__LC_INT_CLOCK, offsetof(struct _lowcore, int_clock)); |
135 | DEFINE(__LC_MCCK_CLOCK, offsetof(struct _lowcore, mcck_clock)); | 133 | DEFINE(__LC_MCCK_CLOCK, offsetof(struct _lowcore, mcck_clock)); |
136 | DEFINE(__LC_MACHINE_FLAGS, offsetof(struct _lowcore, machine_flags)); | 134 | DEFINE(__LC_MACHINE_FLAGS, offsetof(struct _lowcore, machine_flags)); |
diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S index 1b67fc6ebdc2..0476174dfff5 100644 --- a/arch/s390/kernel/entry.S +++ b/arch/s390/kernel/entry.S | |||
@@ -212,6 +212,7 @@ __switch_to: | |||
212 | lctl %c4,%c4,__TASK_pid(%r3) # load pid to control reg. 4 | 212 | lctl %c4,%c4,__TASK_pid(%r3) # load pid to control reg. 4 |
213 | lm %r6,%r15,__SF_GPRS(%r15) # load gprs of next task | 213 | lm %r6,%r15,__SF_GPRS(%r15) # load gprs of next task |
214 | st %r3,__LC_CURRENT # store task struct of next | 214 | st %r3,__LC_CURRENT # store task struct of next |
215 | mvc __LC_CURRENT_PID(4,%r0),__TASK_pid(%r3) # store pid of next | ||
215 | st %r5,__LC_THREAD_INFO # store thread info of next | 216 | st %r5,__LC_THREAD_INFO # store thread info of next |
216 | ahi %r5,STACK_SIZE # end of kernel stack of next | 217 | ahi %r5,STACK_SIZE # end of kernel stack of next |
217 | st %r5,__LC_KERNEL_STACK # store end of kernel stack | 218 | st %r5,__LC_KERNEL_STACK # store end of kernel stack |
diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S index 9fd864563499..d61967e2eab0 100644 --- a/arch/s390/kernel/entry64.S +++ b/arch/s390/kernel/entry64.S | |||
@@ -220,6 +220,7 @@ __switch_to: | |||
220 | lctl %c4,%c4,__TASK_pid(%r3) # load pid to control reg. 4 | 220 | lctl %c4,%c4,__TASK_pid(%r3) # load pid to control reg. 4 |
221 | lmg %r6,%r15,__SF_GPRS(%r15) # load gprs of next task | 221 | lmg %r6,%r15,__SF_GPRS(%r15) # load gprs of next task |
222 | stg %r3,__LC_CURRENT # store task struct of next | 222 | stg %r3,__LC_CURRENT # store task struct of next |
223 | mvc __LC_CURRENT_PID+4(4,%r0),__TASK_pid(%r3) # store pid of next | ||
223 | stg %r5,__LC_THREAD_INFO # store thread info of next | 224 | stg %r5,__LC_THREAD_INFO # store thread info of next |
224 | aghi %r5,STACK_SIZE # end of kernel stack of next | 225 | aghi %r5,STACK_SIZE # end of kernel stack of next |
225 | stg %r5,__LC_KERNEL_STACK # store end of kernel stack | 226 | stg %r5,__LC_KERNEL_STACK # store end of kernel stack |
diff --git a/arch/s390/kernel/irq.c b/arch/s390/kernel/irq.c index ea5099c9709c..e204f9597aaf 100644 --- a/arch/s390/kernel/irq.c +++ b/arch/s390/kernel/irq.c | |||
@@ -32,6 +32,7 @@ static const struct irq_class intrclass_names[] = { | |||
32 | {.name = "VRT", .desc = "[EXT] Virtio" }, | 32 | {.name = "VRT", .desc = "[EXT] Virtio" }, |
33 | {.name = "SCP", .desc = "[EXT] Service Call" }, | 33 | {.name = "SCP", .desc = "[EXT] Service Call" }, |
34 | {.name = "IUC", .desc = "[EXT] IUCV" }, | 34 | {.name = "IUC", .desc = "[EXT] IUCV" }, |
35 | {.name = "CPM", .desc = "[EXT] CPU Measurement" }, | ||
35 | {.name = "QAI", .desc = "[I/O] QDIO Adapter Interrupt" }, | 36 | {.name = "QAI", .desc = "[I/O] QDIO Adapter Interrupt" }, |
36 | {.name = "QDI", .desc = "[I/O] QDIO Interrupt" }, | 37 | {.name = "QDI", .desc = "[I/O] QDIO Interrupt" }, |
37 | {.name = "DAS", .desc = "[I/O] DASD" }, | 38 | {.name = "DAS", .desc = "[I/O] DASD" }, |
diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c index a895e69379f7..541a7509faeb 100644 --- a/arch/s390/kernel/process.c +++ b/arch/s390/kernel/process.c | |||
@@ -9,41 +9,26 @@ | |||
9 | 9 | ||
10 | #include <linux/compiler.h> | 10 | #include <linux/compiler.h> |
11 | #include <linux/cpu.h> | 11 | #include <linux/cpu.h> |
12 | #include <linux/errno.h> | ||
13 | #include <linux/sched.h> | 12 | #include <linux/sched.h> |
14 | #include <linux/kernel.h> | 13 | #include <linux/kernel.h> |
15 | #include <linux/mm.h> | 14 | #include <linux/mm.h> |
16 | #include <linux/fs.h> | ||
17 | #include <linux/smp.h> | 15 | #include <linux/smp.h> |
18 | #include <linux/stddef.h> | ||
19 | #include <linux/slab.h> | 16 | #include <linux/slab.h> |
20 | #include <linux/unistd.h> | ||
21 | #include <linux/ptrace.h> | ||
22 | #include <linux/vmalloc.h> | ||
23 | #include <linux/user.h> | ||
24 | #include <linux/interrupt.h> | 17 | #include <linux/interrupt.h> |
25 | #include <linux/delay.h> | ||
26 | #include <linux/reboot.h> | ||
27 | #include <linux/init.h> | ||
28 | #include <linux/module.h> | ||
29 | #include <linux/notifier.h> | ||
30 | #include <linux/tick.h> | 18 | #include <linux/tick.h> |
31 | #include <linux/elfcore.h> | ||
32 | #include <linux/kernel_stat.h> | ||
33 | #include <linux/personality.h> | 19 | #include <linux/personality.h> |
34 | #include <linux/syscalls.h> | 20 | #include <linux/syscalls.h> |
35 | #include <linux/compat.h> | 21 | #include <linux/compat.h> |
36 | #include <linux/kprobes.h> | 22 | #include <linux/kprobes.h> |
37 | #include <linux/random.h> | 23 | #include <linux/random.h> |
38 | #include <asm/compat.h> | 24 | #include <linux/module.h> |
39 | #include <asm/uaccess.h> | ||
40 | #include <asm/pgtable.h> | ||
41 | #include <asm/system.h> | 25 | #include <asm/system.h> |
42 | #include <asm/io.h> | 26 | #include <asm/io.h> |
43 | #include <asm/processor.h> | 27 | #include <asm/processor.h> |
44 | #include <asm/irq.h> | 28 | #include <asm/irq.h> |
45 | #include <asm/timer.h> | 29 | #include <asm/timer.h> |
46 | #include <asm/nmi.h> | 30 | #include <asm/nmi.h> |
31 | #include <asm/compat.h> | ||
47 | #include <asm/smp.h> | 32 | #include <asm/smp.h> |
48 | #include "entry.h" | 33 | #include "entry.h" |
49 | 34 | ||
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index f5434d1ecb31..0c35dee10b00 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c | |||
@@ -305,8 +305,7 @@ static int set_amode_and_uaccess(unsigned long user_amode, | |||
305 | */ | 305 | */ |
306 | static int __init early_parse_switch_amode(char *p) | 306 | static int __init early_parse_switch_amode(char *p) |
307 | { | 307 | { |
308 | if (user_mode != SECONDARY_SPACE_MODE) | 308 | user_mode = PRIMARY_SPACE_MODE; |
309 | user_mode = PRIMARY_SPACE_MODE; | ||
310 | return 0; | 309 | return 0; |
311 | } | 310 | } |
312 | early_param("switch_amode", early_parse_switch_amode); | 311 | early_param("switch_amode", early_parse_switch_amode); |
@@ -315,10 +314,6 @@ static int __init early_parse_user_mode(char *p) | |||
315 | { | 314 | { |
316 | if (p && strcmp(p, "primary") == 0) | 315 | if (p && strcmp(p, "primary") == 0) |
317 | user_mode = PRIMARY_SPACE_MODE; | 316 | user_mode = PRIMARY_SPACE_MODE; |
318 | #ifdef CONFIG_S390_EXEC_PROTECT | ||
319 | else if (p && strcmp(p, "secondary") == 0) | ||
320 | user_mode = SECONDARY_SPACE_MODE; | ||
321 | #endif | ||
322 | else if (!p || strcmp(p, "home") == 0) | 317 | else if (!p || strcmp(p, "home") == 0) |
323 | user_mode = HOME_SPACE_MODE; | 318 | user_mode = HOME_SPACE_MODE; |
324 | else | 319 | else |
@@ -327,31 +322,9 @@ static int __init early_parse_user_mode(char *p) | |||
327 | } | 322 | } |
328 | early_param("user_mode", early_parse_user_mode); | 323 | early_param("user_mode", early_parse_user_mode); |
329 | 324 | ||
330 | #ifdef CONFIG_S390_EXEC_PROTECT | ||
331 | /* | ||
332 | * Enable execute protection? | ||
333 | */ | ||
334 | static int __init early_parse_noexec(char *p) | ||
335 | { | ||
336 | if (!strncmp(p, "off", 3)) | ||
337 | return 0; | ||
338 | user_mode = SECONDARY_SPACE_MODE; | ||
339 | return 0; | ||
340 | } | ||
341 | early_param("noexec", early_parse_noexec); | ||
342 | #endif /* CONFIG_S390_EXEC_PROTECT */ | ||
343 | |||
344 | static void setup_addressing_mode(void) | 325 | static void setup_addressing_mode(void) |
345 | { | 326 | { |
346 | if (user_mode == SECONDARY_SPACE_MODE) { | 327 | if (user_mode == PRIMARY_SPACE_MODE) { |
347 | if (set_amode_and_uaccess(PSW_ASC_SECONDARY, | ||
348 | PSW32_ASC_SECONDARY)) | ||
349 | pr_info("Execute protection active, " | ||
350 | "mvcos available\n"); | ||
351 | else | ||
352 | pr_info("Execute protection active, " | ||
353 | "mvcos not available\n"); | ||
354 | } else if (user_mode == PRIMARY_SPACE_MODE) { | ||
355 | if (set_amode_and_uaccess(PSW_ASC_PRIMARY, PSW32_ASC_PRIMARY)) | 328 | if (set_amode_and_uaccess(PSW_ASC_PRIMARY, PSW32_ASC_PRIMARY)) |
356 | pr_info("Address spaces switched, " | 329 | pr_info("Address spaces switched, " |
357 | "mvcos available\n"); | 330 | "mvcos available\n"); |
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index 63c7d9ff220d..f8e85ecbc459 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c | |||
@@ -335,7 +335,7 @@ static int smp_rescan_cpus_sigp(cpumask_t avail) | |||
335 | smp_cpu_polarization[logical_cpu] = POLARIZATION_UNKNWN; | 335 | smp_cpu_polarization[logical_cpu] = POLARIZATION_UNKNWN; |
336 | if (!cpu_stopped(logical_cpu)) | 336 | if (!cpu_stopped(logical_cpu)) |
337 | continue; | 337 | continue; |
338 | cpu_set(logical_cpu, cpu_present_map); | 338 | set_cpu_present(logical_cpu, true); |
339 | smp_cpu_state[logical_cpu] = CPU_STATE_CONFIGURED; | 339 | smp_cpu_state[logical_cpu] = CPU_STATE_CONFIGURED; |
340 | logical_cpu = cpumask_next(logical_cpu, &avail); | 340 | logical_cpu = cpumask_next(logical_cpu, &avail); |
341 | if (logical_cpu >= nr_cpu_ids) | 341 | if (logical_cpu >= nr_cpu_ids) |
@@ -367,7 +367,7 @@ static int smp_rescan_cpus_sclp(cpumask_t avail) | |||
367 | continue; | 367 | continue; |
368 | __cpu_logical_map[logical_cpu] = cpu_id; | 368 | __cpu_logical_map[logical_cpu] = cpu_id; |
369 | smp_cpu_polarization[logical_cpu] = POLARIZATION_UNKNWN; | 369 | smp_cpu_polarization[logical_cpu] = POLARIZATION_UNKNWN; |
370 | cpu_set(logical_cpu, cpu_present_map); | 370 | set_cpu_present(logical_cpu, true); |
371 | if (cpu >= info->configured) | 371 | if (cpu >= info->configured) |
372 | smp_cpu_state[logical_cpu] = CPU_STATE_STANDBY; | 372 | smp_cpu_state[logical_cpu] = CPU_STATE_STANDBY; |
373 | else | 373 | else |
@@ -385,7 +385,7 @@ static int __smp_rescan_cpus(void) | |||
385 | { | 385 | { |
386 | cpumask_t avail; | 386 | cpumask_t avail; |
387 | 387 | ||
388 | cpus_xor(avail, cpu_possible_map, cpu_present_map); | 388 | cpumask_xor(&avail, cpu_possible_mask, cpu_present_mask); |
389 | if (smp_use_sigp_detection) | 389 | if (smp_use_sigp_detection) |
390 | return smp_rescan_cpus_sigp(avail); | 390 | return smp_rescan_cpus_sigp(avail); |
391 | else | 391 | else |
@@ -467,7 +467,7 @@ int __cpuinit start_secondary(void *cpuvoid) | |||
467 | notify_cpu_starting(smp_processor_id()); | 467 | notify_cpu_starting(smp_processor_id()); |
468 | /* Mark this cpu as online */ | 468 | /* Mark this cpu as online */ |
469 | ipi_call_lock(); | 469 | ipi_call_lock(); |
470 | cpu_set(smp_processor_id(), cpu_online_map); | 470 | set_cpu_online(smp_processor_id(), true); |
471 | ipi_call_unlock(); | 471 | ipi_call_unlock(); |
472 | /* Switch on interrupts */ | 472 | /* Switch on interrupts */ |
473 | local_irq_enable(); | 473 | local_irq_enable(); |
@@ -644,7 +644,7 @@ int __cpu_disable(void) | |||
644 | struct ec_creg_mask_parms cr_parms; | 644 | struct ec_creg_mask_parms cr_parms; |
645 | int cpu = smp_processor_id(); | 645 | int cpu = smp_processor_id(); |
646 | 646 | ||
647 | cpu_clear(cpu, cpu_online_map); | 647 | set_cpu_online(cpu, false); |
648 | 648 | ||
649 | /* Disable pfault pseudo page faults on this cpu. */ | 649 | /* Disable pfault pseudo page faults on this cpu. */ |
650 | pfault_fini(); | 650 | pfault_fini(); |
@@ -654,8 +654,8 @@ int __cpu_disable(void) | |||
654 | 654 | ||
655 | /* disable all external interrupts */ | 655 | /* disable all external interrupts */ |
656 | cr_parms.orvals[0] = 0; | 656 | cr_parms.orvals[0] = 0; |
657 | cr_parms.andvals[0] = ~(1 << 15 | 1 << 14 | 1 << 13 | 1 << 12 | | 657 | cr_parms.andvals[0] = ~(1 << 15 | 1 << 14 | 1 << 13 | 1 << 11 | |
658 | 1 << 11 | 1 << 10 | 1 << 6 | 1 << 4); | 658 | 1 << 10 | 1 << 9 | 1 << 6 | 1 << 4); |
659 | /* disable all I/O interrupts */ | 659 | /* disable all I/O interrupts */ |
660 | cr_parms.orvals[6] = 0; | 660 | cr_parms.orvals[6] = 0; |
661 | cr_parms.andvals[6] = ~(1 << 31 | 1 << 30 | 1 << 29 | 1 << 28 | | 661 | cr_parms.andvals[6] = ~(1 << 31 | 1 << 30 | 1 << 29 | 1 << 28 | |
@@ -681,7 +681,7 @@ void __cpu_die(unsigned int cpu) | |||
681 | atomic_dec(&init_mm.context.attach_count); | 681 | atomic_dec(&init_mm.context.attach_count); |
682 | } | 682 | } |
683 | 683 | ||
684 | void cpu_die(void) | 684 | void __noreturn cpu_die(void) |
685 | { | 685 | { |
686 | idle_task_exit(); | 686 | idle_task_exit(); |
687 | while (sigp(smp_processor_id(), sigp_stop) == sigp_busy) | 687 | while (sigp(smp_processor_id(), sigp_stop) == sigp_busy) |
@@ -738,8 +738,8 @@ void __init smp_prepare_boot_cpu(void) | |||
738 | BUG_ON(smp_processor_id() != 0); | 738 | BUG_ON(smp_processor_id() != 0); |
739 | 739 | ||
740 | current_thread_info()->cpu = 0; | 740 | current_thread_info()->cpu = 0; |
741 | cpu_set(0, cpu_present_map); | 741 | set_cpu_present(0, true); |
742 | cpu_set(0, cpu_online_map); | 742 | set_cpu_online(0, true); |
743 | S390_lowcore.percpu_offset = __per_cpu_offset[0]; | 743 | S390_lowcore.percpu_offset = __per_cpu_offset[0]; |
744 | current_set[0] = current; | 744 | current_set[0] = current; |
745 | smp_cpu_state[0] = CPU_STATE_CONFIGURED; | 745 | smp_cpu_state[0] = CPU_STATE_CONFIGURED; |
@@ -1016,21 +1016,21 @@ int __ref smp_rescan_cpus(void) | |||
1016 | 1016 | ||
1017 | get_online_cpus(); | 1017 | get_online_cpus(); |
1018 | mutex_lock(&smp_cpu_state_mutex); | 1018 | mutex_lock(&smp_cpu_state_mutex); |
1019 | newcpus = cpu_present_map; | 1019 | cpumask_copy(&newcpus, cpu_present_mask); |
1020 | rc = __smp_rescan_cpus(); | 1020 | rc = __smp_rescan_cpus(); |
1021 | if (rc) | 1021 | if (rc) |
1022 | goto out; | 1022 | goto out; |
1023 | cpus_andnot(newcpus, cpu_present_map, newcpus); | 1023 | cpumask_andnot(&newcpus, cpu_present_mask, &newcpus); |
1024 | for_each_cpu_mask(cpu, newcpus) { | 1024 | for_each_cpu(cpu, &newcpus) { |
1025 | rc = smp_add_present_cpu(cpu); | 1025 | rc = smp_add_present_cpu(cpu); |
1026 | if (rc) | 1026 | if (rc) |
1027 | cpu_clear(cpu, cpu_present_map); | 1027 | set_cpu_present(cpu, false); |
1028 | } | 1028 | } |
1029 | rc = 0; | 1029 | rc = 0; |
1030 | out: | 1030 | out: |
1031 | mutex_unlock(&smp_cpu_state_mutex); | 1031 | mutex_unlock(&smp_cpu_state_mutex); |
1032 | put_online_cpus(); | 1032 | put_online_cpus(); |
1033 | if (!cpus_empty(newcpus)) | 1033 | if (!cpumask_empty(&newcpus)) |
1034 | topology_schedule_update(); | 1034 | topology_schedule_update(); |
1035 | return rc; | 1035 | return rc; |
1036 | } | 1036 | } |
diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c index 87be655557aa..a59557f1fb5f 100644 --- a/arch/s390/kernel/time.c +++ b/arch/s390/kernel/time.c | |||
@@ -810,7 +810,7 @@ static int etr_sync_clock_stop(struct etr_aib *aib, int port) | |||
810 | etr_sync.etr_port = port; | 810 | etr_sync.etr_port = port; |
811 | get_online_cpus(); | 811 | get_online_cpus(); |
812 | atomic_set(&etr_sync.cpus, num_online_cpus() - 1); | 812 | atomic_set(&etr_sync.cpus, num_online_cpus() - 1); |
813 | rc = stop_machine(etr_sync_clock, &etr_sync, &cpu_online_map); | 813 | rc = stop_machine(etr_sync_clock, &etr_sync, cpu_online_mask); |
814 | put_online_cpus(); | 814 | put_online_cpus(); |
815 | return rc; | 815 | return rc; |
816 | } | 816 | } |
@@ -1579,7 +1579,7 @@ static void stp_work_fn(struct work_struct *work) | |||
1579 | memset(&stp_sync, 0, sizeof(stp_sync)); | 1579 | memset(&stp_sync, 0, sizeof(stp_sync)); |
1580 | get_online_cpus(); | 1580 | get_online_cpus(); |
1581 | atomic_set(&stp_sync.cpus, num_online_cpus() - 1); | 1581 | atomic_set(&stp_sync.cpus, num_online_cpus() - 1); |
1582 | stop_machine(stp_sync_clock, &stp_sync, &cpu_online_map); | 1582 | stop_machine(stp_sync_clock, &stp_sync, cpu_online_mask); |
1583 | put_online_cpus(); | 1583 | put_online_cpus(); |
1584 | 1584 | ||
1585 | if (!check_sync_clock()) | 1585 | if (!check_sync_clock()) |
diff --git a/arch/s390/kernel/topology.c b/arch/s390/kernel/topology.c index 94b06c31fc8a..2eafb8c7a746 100644 --- a/arch/s390/kernel/topology.c +++ b/arch/s390/kernel/topology.c | |||
@@ -52,20 +52,20 @@ static cpumask_t cpu_group_map(struct mask_info *info, unsigned int cpu) | |||
52 | { | 52 | { |
53 | cpumask_t mask; | 53 | cpumask_t mask; |
54 | 54 | ||
55 | cpus_clear(mask); | 55 | cpumask_clear(&mask); |
56 | if (!topology_enabled || !MACHINE_HAS_TOPOLOGY) { | 56 | if (!topology_enabled || !MACHINE_HAS_TOPOLOGY) { |
57 | cpumask_copy(&mask, cpumask_of(cpu)); | 57 | cpumask_copy(&mask, cpumask_of(cpu)); |
58 | return mask; | 58 | return mask; |
59 | } | 59 | } |
60 | while (info) { | 60 | while (info) { |
61 | if (cpu_isset(cpu, info->mask)) { | 61 | if (cpumask_test_cpu(cpu, &info->mask)) { |
62 | mask = info->mask; | 62 | mask = info->mask; |
63 | break; | 63 | break; |
64 | } | 64 | } |
65 | info = info->next; | 65 | info = info->next; |
66 | } | 66 | } |
67 | if (cpus_empty(mask)) | 67 | if (cpumask_empty(&mask)) |
68 | mask = cpumask_of_cpu(cpu); | 68 | cpumask_copy(&mask, cpumask_of(cpu)); |
69 | return mask; | 69 | return mask; |
70 | } | 70 | } |
71 | 71 | ||
@@ -85,10 +85,10 @@ static void add_cpus_to_mask(struct topology_cpu *tl_cpu, | |||
85 | if (cpu_logical_map(lcpu) != rcpu) | 85 | if (cpu_logical_map(lcpu) != rcpu) |
86 | continue; | 86 | continue; |
87 | #ifdef CONFIG_SCHED_BOOK | 87 | #ifdef CONFIG_SCHED_BOOK |
88 | cpu_set(lcpu, book->mask); | 88 | cpumask_set_cpu(lcpu, &book->mask); |
89 | cpu_book_id[lcpu] = book->id; | 89 | cpu_book_id[lcpu] = book->id; |
90 | #endif | 90 | #endif |
91 | cpu_set(lcpu, core->mask); | 91 | cpumask_set_cpu(lcpu, &core->mask); |
92 | cpu_core_id[lcpu] = core->id; | 92 | cpu_core_id[lcpu] = core->id; |
93 | smp_cpu_polarization[lcpu] = tl_cpu->pp; | 93 | smp_cpu_polarization[lcpu] = tl_cpu->pp; |
94 | } | 94 | } |
@@ -101,13 +101,13 @@ static void clear_masks(void) | |||
101 | 101 | ||
102 | info = &core_info; | 102 | info = &core_info; |
103 | while (info) { | 103 | while (info) { |
104 | cpus_clear(info->mask); | 104 | cpumask_clear(&info->mask); |
105 | info = info->next; | 105 | info = info->next; |
106 | } | 106 | } |
107 | #ifdef CONFIG_SCHED_BOOK | 107 | #ifdef CONFIG_SCHED_BOOK |
108 | info = &book_info; | 108 | info = &book_info; |
109 | while (info) { | 109 | while (info) { |
110 | cpus_clear(info->mask); | 110 | cpumask_clear(&info->mask); |
111 | info = info->next; | 111 | info = info->next; |
112 | } | 112 | } |
113 | #endif | 113 | #endif |
diff --git a/arch/s390/kernel/vdso32/Makefile b/arch/s390/kernel/vdso32/Makefile index d13e8755a8cc..8ad2b34ad151 100644 --- a/arch/s390/kernel/vdso32/Makefile +++ b/arch/s390/kernel/vdso32/Makefile | |||
@@ -22,6 +22,9 @@ obj-y += vdso32_wrapper.o | |||
22 | extra-y += vdso32.lds | 22 | extra-y += vdso32.lds |
23 | CPPFLAGS_vdso32.lds += -P -C -U$(ARCH) | 23 | CPPFLAGS_vdso32.lds += -P -C -U$(ARCH) |
24 | 24 | ||
25 | # Disable gcov profiling for VDSO code | ||
26 | GCOV_PROFILE := n | ||
27 | |||
25 | # Force dependency (incbin is bad) | 28 | # Force dependency (incbin is bad) |
26 | $(obj)/vdso32_wrapper.o : $(obj)/vdso32.so | 29 | $(obj)/vdso32_wrapper.o : $(obj)/vdso32.so |
27 | 30 | ||
diff --git a/arch/s390/kernel/vdso64/Makefile b/arch/s390/kernel/vdso64/Makefile index 449352dda9cd..2a8ddfd12a5b 100644 --- a/arch/s390/kernel/vdso64/Makefile +++ b/arch/s390/kernel/vdso64/Makefile | |||
@@ -22,6 +22,9 @@ obj-y += vdso64_wrapper.o | |||
22 | extra-y += vdso64.lds | 22 | extra-y += vdso64.lds |
23 | CPPFLAGS_vdso64.lds += -P -C -U$(ARCH) | 23 | CPPFLAGS_vdso64.lds += -P -C -U$(ARCH) |
24 | 24 | ||
25 | # Disable gcov profiling for VDSO code | ||
26 | GCOV_PROFILE := n | ||
27 | |||
25 | # Force dependency (incbin is bad) | 28 | # Force dependency (incbin is bad) |
26 | $(obj)/vdso64_wrapper.o : $(obj)/vdso64.so | 29 | $(obj)/vdso64_wrapper.o : $(obj)/vdso64.so |
27 | 30 | ||
diff --git a/arch/s390/mm/extmem.c b/arch/s390/mm/extmem.c index 3cc95dd0a3a6..075ddada4911 100644 --- a/arch/s390/mm/extmem.c +++ b/arch/s390/mm/extmem.c | |||
@@ -412,6 +412,7 @@ __segment_load (char *name, int do_nonshared, unsigned long *addr, unsigned long | |||
412 | struct dcss_segment *seg; | 412 | struct dcss_segment *seg; |
413 | int rc, diag_cc; | 413 | int rc, diag_cc; |
414 | 414 | ||
415 | start_addr = end_addr = 0; | ||
415 | seg = kmalloc(sizeof(*seg), GFP_KERNEL | GFP_DMA); | 416 | seg = kmalloc(sizeof(*seg), GFP_KERNEL | GFP_DMA); |
416 | if (seg == NULL) { | 417 | if (seg == NULL) { |
417 | rc = -ENOMEM; | 418 | rc = -ENOMEM; |
@@ -573,6 +574,7 @@ segment_modify_shared (char *name, int do_nonshared) | |||
573 | unsigned long start_addr, end_addr, dummy; | 574 | unsigned long start_addr, end_addr, dummy; |
574 | int rc, diag_cc; | 575 | int rc, diag_cc; |
575 | 576 | ||
577 | start_addr = end_addr = 0; | ||
576 | mutex_lock(&dcss_lock); | 578 | mutex_lock(&dcss_lock); |
577 | seg = segment_by_name (name); | 579 | seg = segment_by_name (name); |
578 | if (seg == NULL) { | 580 | if (seg == NULL) { |
@@ -681,8 +683,6 @@ void | |||
681 | segment_save(char *name) | 683 | segment_save(char *name) |
682 | { | 684 | { |
683 | struct dcss_segment *seg; | 685 | struct dcss_segment *seg; |
684 | int startpfn = 0; | ||
685 | int endpfn = 0; | ||
686 | char cmd1[160]; | 686 | char cmd1[160]; |
687 | char cmd2[80]; | 687 | char cmd2[80]; |
688 | int i, response; | 688 | int i, response; |
@@ -698,8 +698,6 @@ segment_save(char *name) | |||
698 | goto out; | 698 | goto out; |
699 | } | 699 | } |
700 | 700 | ||
701 | startpfn = seg->start_addr >> PAGE_SHIFT; | ||
702 | endpfn = (seg->end) >> PAGE_SHIFT; | ||
703 | sprintf(cmd1, "DEFSEG %s", name); | 701 | sprintf(cmd1, "DEFSEG %s", name); |
704 | for (i=0; i<seg->segcnt; i++) { | 702 | for (i=0; i<seg->segcnt; i++) { |
705 | sprintf(cmd1+strlen(cmd1), " %lX-%lX %s", | 703 | sprintf(cmd1+strlen(cmd1), " %lX-%lX %s", |
diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c index ab988135e5c6..a0f9e730f26a 100644 --- a/arch/s390/mm/fault.c +++ b/arch/s390/mm/fault.c | |||
@@ -225,33 +225,6 @@ static noinline void do_sigbus(struct pt_regs *regs, long int_code, | |||
225 | force_sig_info(SIGBUS, &si, tsk); | 225 | force_sig_info(SIGBUS, &si, tsk); |
226 | } | 226 | } |
227 | 227 | ||
228 | #ifdef CONFIG_S390_EXEC_PROTECT | ||
229 | static noinline int signal_return(struct pt_regs *regs, long int_code, | ||
230 | unsigned long trans_exc_code) | ||
231 | { | ||
232 | u16 instruction; | ||
233 | int rc; | ||
234 | |||
235 | rc = __get_user(instruction, (u16 __user *) regs->psw.addr); | ||
236 | |||
237 | if (!rc && instruction == 0x0a77) { | ||
238 | clear_tsk_thread_flag(current, TIF_PER_TRAP); | ||
239 | if (is_compat_task()) | ||
240 | sys32_sigreturn(); | ||
241 | else | ||
242 | sys_sigreturn(); | ||
243 | } else if (!rc && instruction == 0x0aad) { | ||
244 | clear_tsk_thread_flag(current, TIF_PER_TRAP); | ||
245 | if (is_compat_task()) | ||
246 | sys32_rt_sigreturn(); | ||
247 | else | ||
248 | sys_rt_sigreturn(); | ||
249 | } else | ||
250 | do_sigsegv(regs, int_code, SEGV_MAPERR, trans_exc_code); | ||
251 | return 0; | ||
252 | } | ||
253 | #endif /* CONFIG_S390_EXEC_PROTECT */ | ||
254 | |||
255 | static noinline void do_fault_error(struct pt_regs *regs, long int_code, | 228 | static noinline void do_fault_error(struct pt_regs *regs, long int_code, |
256 | unsigned long trans_exc_code, int fault) | 229 | unsigned long trans_exc_code, int fault) |
257 | { | 230 | { |
@@ -259,13 +232,6 @@ static noinline void do_fault_error(struct pt_regs *regs, long int_code, | |||
259 | 232 | ||
260 | switch (fault) { | 233 | switch (fault) { |
261 | case VM_FAULT_BADACCESS: | 234 | case VM_FAULT_BADACCESS: |
262 | #ifdef CONFIG_S390_EXEC_PROTECT | ||
263 | if ((regs->psw.mask & PSW_MASK_ASC) == PSW_ASC_SECONDARY && | ||
264 | (trans_exc_code & 3) == 0) { | ||
265 | signal_return(regs, int_code, trans_exc_code); | ||
266 | break; | ||
267 | } | ||
268 | #endif /* CONFIG_S390_EXEC_PROTECT */ | ||
269 | case VM_FAULT_BADMAP: | 235 | case VM_FAULT_BADMAP: |
270 | /* Bad memory access. Check if it is kernel or user space. */ | 236 | /* Bad memory access. Check if it is kernel or user space. */ |
271 | if (regs->psw.mask & PSW_MASK_PSTATE) { | 237 | if (regs->psw.mask & PSW_MASK_PSTATE) { |
@@ -414,11 +380,6 @@ void __kprobes do_dat_exception(struct pt_regs *regs, long pgm_int_code, | |||
414 | int access, fault; | 380 | int access, fault; |
415 | 381 | ||
416 | access = VM_READ | VM_EXEC | VM_WRITE; | 382 | access = VM_READ | VM_EXEC | VM_WRITE; |
417 | #ifdef CONFIG_S390_EXEC_PROTECT | ||
418 | if ((regs->psw.mask & PSW_MASK_ASC) == PSW_ASC_SECONDARY && | ||
419 | (trans_exc_code & 3) == 0) | ||
420 | access = VM_EXEC; | ||
421 | #endif | ||
422 | fault = do_exception(regs, access, trans_exc_code); | 383 | fault = do_exception(regs, access, trans_exc_code); |
423 | if (unlikely(fault)) | 384 | if (unlikely(fault)) |
424 | do_fault_error(regs, pgm_int_code & 255, trans_exc_code, fault); | 385 | do_fault_error(regs, pgm_int_code & 255, trans_exc_code, fault); |
@@ -491,22 +452,28 @@ static int __init nopfault(char *str) | |||
491 | 452 | ||
492 | __setup("nopfault", nopfault); | 453 | __setup("nopfault", nopfault); |
493 | 454 | ||
494 | typedef struct { | 455 | struct pfault_refbk { |
495 | __u16 refdiagc; | 456 | u16 refdiagc; |
496 | __u16 reffcode; | 457 | u16 reffcode; |
497 | __u16 refdwlen; | 458 | u16 refdwlen; |
498 | __u16 refversn; | 459 | u16 refversn; |
499 | __u64 refgaddr; | 460 | u64 refgaddr; |
500 | __u64 refselmk; | 461 | u64 refselmk; |
501 | __u64 refcmpmk; | 462 | u64 refcmpmk; |
502 | __u64 reserved; | 463 | u64 reserved; |
503 | } __attribute__ ((packed, aligned(8))) pfault_refbk_t; | 464 | } __attribute__ ((packed, aligned(8))); |
504 | 465 | ||
505 | int pfault_init(void) | 466 | int pfault_init(void) |
506 | { | 467 | { |
507 | pfault_refbk_t refbk = | 468 | struct pfault_refbk refbk = { |
508 | { 0x258, 0, 5, 2, __LC_CURRENT, 1ULL << 48, 1ULL << 48, | 469 | .refdiagc = 0x258, |
509 | __PF_RES_FIELD }; | 470 | .reffcode = 0, |
471 | .refdwlen = 5, | ||
472 | .refversn = 2, | ||
473 | .refgaddr = __LC_CURRENT_PID, | ||
474 | .refselmk = 1ULL << 48, | ||
475 | .refcmpmk = 1ULL << 48, | ||
476 | .reserved = __PF_RES_FIELD }; | ||
510 | int rc; | 477 | int rc; |
511 | 478 | ||
512 | if (!MACHINE_IS_VM || pfault_disable) | 479 | if (!MACHINE_IS_VM || pfault_disable) |
@@ -524,8 +491,12 @@ int pfault_init(void) | |||
524 | 491 | ||
525 | void pfault_fini(void) | 492 | void pfault_fini(void) |
526 | { | 493 | { |
527 | pfault_refbk_t refbk = | 494 | struct pfault_refbk refbk = { |
528 | { 0x258, 1, 5, 2, 0ULL, 0ULL, 0ULL, 0ULL }; | 495 | .refdiagc = 0x258, |
496 | .reffcode = 1, | ||
497 | .refdwlen = 5, | ||
498 | .refversn = 2, | ||
499 | }; | ||
529 | 500 | ||
530 | if (!MACHINE_IS_VM || pfault_disable) | 501 | if (!MACHINE_IS_VM || pfault_disable) |
531 | return; | 502 | return; |
@@ -537,11 +508,15 @@ void pfault_fini(void) | |||
537 | : : "a" (&refbk), "m" (refbk) : "cc"); | 508 | : : "a" (&refbk), "m" (refbk) : "cc"); |
538 | } | 509 | } |
539 | 510 | ||
511 | static DEFINE_SPINLOCK(pfault_lock); | ||
512 | static LIST_HEAD(pfault_list); | ||
513 | |||
540 | static void pfault_interrupt(unsigned int ext_int_code, | 514 | static void pfault_interrupt(unsigned int ext_int_code, |
541 | unsigned int param32, unsigned long param64) | 515 | unsigned int param32, unsigned long param64) |
542 | { | 516 | { |
543 | struct task_struct *tsk; | 517 | struct task_struct *tsk; |
544 | __u16 subcode; | 518 | __u16 subcode; |
519 | pid_t pid; | ||
545 | 520 | ||
546 | /* | 521 | /* |
547 | * Get the external interruption subcode & pfault | 522 | * Get the external interruption subcode & pfault |
@@ -553,44 +528,79 @@ static void pfault_interrupt(unsigned int ext_int_code, | |||
553 | if ((subcode & 0xff00) != __SUBCODE_MASK) | 528 | if ((subcode & 0xff00) != __SUBCODE_MASK) |
554 | return; | 529 | return; |
555 | kstat_cpu(smp_processor_id()).irqs[EXTINT_PFL]++; | 530 | kstat_cpu(smp_processor_id()).irqs[EXTINT_PFL]++; |
556 | 531 | if (subcode & 0x0080) { | |
557 | /* | 532 | /* Get the token (= pid of the affected task). */ |
558 | * Get the token (= address of the task structure of the affected task). | 533 | pid = sizeof(void *) == 4 ? param32 : param64; |
559 | */ | 534 | rcu_read_lock(); |
560 | #ifdef CONFIG_64BIT | 535 | tsk = find_task_by_pid_ns(pid, &init_pid_ns); |
561 | tsk = (struct task_struct *) param64; | 536 | if (tsk) |
562 | #else | 537 | get_task_struct(tsk); |
563 | tsk = (struct task_struct *) param32; | 538 | rcu_read_unlock(); |
564 | #endif | 539 | if (!tsk) |
565 | 540 | return; | |
541 | } else { | ||
542 | tsk = current; | ||
543 | } | ||
544 | spin_lock(&pfault_lock); | ||
566 | if (subcode & 0x0080) { | 545 | if (subcode & 0x0080) { |
567 | /* signal bit is set -> a page has been swapped in by VM */ | 546 | /* signal bit is set -> a page has been swapped in by VM */ |
568 | if (xchg(&tsk->thread.pfault_wait, -1) != 0) { | 547 | if (tsk->thread.pfault_wait == 1) { |
569 | /* Initial interrupt was faster than the completion | 548 | /* Initial interrupt was faster than the completion |
570 | * interrupt. pfault_wait is valid. Set pfault_wait | 549 | * interrupt. pfault_wait is valid. Set pfault_wait |
571 | * back to zero and wake up the process. This can | 550 | * back to zero and wake up the process. This can |
572 | * safely be done because the task is still sleeping | 551 | * safely be done because the task is still sleeping |
573 | * and can't produce new pfaults. */ | 552 | * and can't produce new pfaults. */ |
574 | tsk->thread.pfault_wait = 0; | 553 | tsk->thread.pfault_wait = 0; |
554 | list_del(&tsk->thread.list); | ||
575 | wake_up_process(tsk); | 555 | wake_up_process(tsk); |
576 | put_task_struct(tsk); | 556 | } else { |
557 | /* Completion interrupt was faster than initial | ||
558 | * interrupt. Set pfault_wait to -1 so the initial | ||
559 | * interrupt doesn't put the task to sleep. */ | ||
560 | tsk->thread.pfault_wait = -1; | ||
577 | } | 561 | } |
562 | put_task_struct(tsk); | ||
578 | } else { | 563 | } else { |
579 | /* signal bit not set -> a real page is missing. */ | 564 | /* signal bit not set -> a real page is missing. */ |
580 | get_task_struct(tsk); | 565 | if (tsk->thread.pfault_wait == -1) { |
581 | set_task_state(tsk, TASK_UNINTERRUPTIBLE); | ||
582 | if (xchg(&tsk->thread.pfault_wait, 1) != 0) { | ||
583 | /* Completion interrupt was faster than the initial | 566 | /* Completion interrupt was faster than the initial |
584 | * interrupt (swapped in a -1 for pfault_wait). Set | 567 | * interrupt (pfault_wait == -1). Set pfault_wait |
585 | * pfault_wait back to zero and exit. This can be | 568 | * back to zero and exit. */ |
586 | * done safely because tsk is running in kernel | ||
587 | * mode and can't produce new pfaults. */ | ||
588 | tsk->thread.pfault_wait = 0; | 569 | tsk->thread.pfault_wait = 0; |
589 | set_task_state(tsk, TASK_RUNNING); | 570 | } else { |
590 | put_task_struct(tsk); | 571 | /* Initial interrupt arrived before completion |
591 | } else | 572 | * interrupt. Let the task sleep. */ |
573 | tsk->thread.pfault_wait = 1; | ||
574 | list_add(&tsk->thread.list, &pfault_list); | ||
575 | set_task_state(tsk, TASK_UNINTERRUPTIBLE); | ||
592 | set_tsk_need_resched(tsk); | 576 | set_tsk_need_resched(tsk); |
577 | } | ||
578 | } | ||
579 | spin_unlock(&pfault_lock); | ||
580 | } | ||
581 | |||
582 | static int __cpuinit pfault_cpu_notify(struct notifier_block *self, | ||
583 | unsigned long action, void *hcpu) | ||
584 | { | ||
585 | struct thread_struct *thread, *next; | ||
586 | struct task_struct *tsk; | ||
587 | |||
588 | switch (action) { | ||
589 | case CPU_DEAD: | ||
590 | case CPU_DEAD_FROZEN: | ||
591 | spin_lock_irq(&pfault_lock); | ||
592 | list_for_each_entry_safe(thread, next, &pfault_list, list) { | ||
593 | thread->pfault_wait = 0; | ||
594 | list_del(&thread->list); | ||
595 | tsk = container_of(thread, struct task_struct, thread); | ||
596 | wake_up_process(tsk); | ||
597 | } | ||
598 | spin_unlock_irq(&pfault_lock); | ||
599 | break; | ||
600 | default: | ||
601 | break; | ||
593 | } | 602 | } |
603 | return NOTIFY_OK; | ||
594 | } | 604 | } |
595 | 605 | ||
596 | static int __init pfault_irq_init(void) | 606 | static int __init pfault_irq_init(void) |
@@ -599,22 +609,21 @@ static int __init pfault_irq_init(void) | |||
599 | 609 | ||
600 | if (!MACHINE_IS_VM) | 610 | if (!MACHINE_IS_VM) |
601 | return 0; | 611 | return 0; |
602 | /* | ||
603 | * Try to get pfault pseudo page faults going. | ||
604 | */ | ||
605 | rc = register_external_interrupt(0x2603, pfault_interrupt); | 612 | rc = register_external_interrupt(0x2603, pfault_interrupt); |
606 | if (rc) { | 613 | if (rc) |
607 | pfault_disable = 1; | 614 | goto out_extint; |
608 | return rc; | 615 | rc = pfault_init() == 0 ? 0 : -EOPNOTSUPP; |
609 | } | 616 | if (rc) |
610 | if (pfault_init() == 0) | 617 | goto out_pfault; |
611 | return 0; | 618 | hotcpu_notifier(pfault_cpu_notify, 0); |
619 | return 0; | ||
612 | 620 | ||
613 | /* Tough luck, no pfault. */ | 621 | out_pfault: |
614 | pfault_disable = 1; | ||
615 | unregister_external_interrupt(0x2603, pfault_interrupt); | 622 | unregister_external_interrupt(0x2603, pfault_interrupt); |
616 | return 0; | 623 | out_extint: |
624 | pfault_disable = 1; | ||
625 | return rc; | ||
617 | } | 626 | } |
618 | early_initcall(pfault_irq_init); | 627 | early_initcall(pfault_irq_init); |
619 | 628 | ||
620 | #endif | 629 | #endif /* CONFIG_PFAULT */ |
diff --git a/arch/s390/mm/hugetlbpage.c b/arch/s390/mm/hugetlbpage.c index 639cd21f2218..a4d856db9154 100644 --- a/arch/s390/mm/hugetlbpage.c +++ b/arch/s390/mm/hugetlbpage.c | |||
@@ -13,7 +13,6 @@ void set_huge_pte_at(struct mm_struct *mm, unsigned long addr, | |||
13 | pte_t *pteptr, pte_t pteval) | 13 | pte_t *pteptr, pte_t pteval) |
14 | { | 14 | { |
15 | pmd_t *pmdp = (pmd_t *) pteptr; | 15 | pmd_t *pmdp = (pmd_t *) pteptr; |
16 | pte_t shadow_pteval = pteval; | ||
17 | unsigned long mask; | 16 | unsigned long mask; |
18 | 17 | ||
19 | if (!MACHINE_HAS_HPAGE) { | 18 | if (!MACHINE_HAS_HPAGE) { |
@@ -21,18 +20,9 @@ void set_huge_pte_at(struct mm_struct *mm, unsigned long addr, | |||
21 | mask = pte_val(pteval) & | 20 | mask = pte_val(pteval) & |
22 | (_SEGMENT_ENTRY_INV | _SEGMENT_ENTRY_RO); | 21 | (_SEGMENT_ENTRY_INV | _SEGMENT_ENTRY_RO); |
23 | pte_val(pteval) = (_SEGMENT_ENTRY + __pa(pteptr)) | mask; | 22 | pte_val(pteval) = (_SEGMENT_ENTRY + __pa(pteptr)) | mask; |
24 | if (mm->context.noexec) { | ||
25 | pteptr += PTRS_PER_PTE; | ||
26 | pte_val(shadow_pteval) = | ||
27 | (_SEGMENT_ENTRY + __pa(pteptr)) | mask; | ||
28 | } | ||
29 | } | 23 | } |
30 | 24 | ||
31 | pmd_val(*pmdp) = pte_val(pteval); | 25 | pmd_val(*pmdp) = pte_val(pteval); |
32 | if (mm->context.noexec) { | ||
33 | pmdp = get_shadow_table(pmdp); | ||
34 | pmd_val(*pmdp) = pte_val(shadow_pteval); | ||
35 | } | ||
36 | } | 26 | } |
37 | 27 | ||
38 | int arch_prepare_hugepage(struct page *page) | 28 | int arch_prepare_hugepage(struct page *page) |
diff --git a/arch/s390/mm/init.c b/arch/s390/mm/init.c index bb409332a484..dfefc2171691 100644 --- a/arch/s390/mm/init.c +++ b/arch/s390/mm/init.c | |||
@@ -175,7 +175,8 @@ void kernel_map_pages(struct page *page, int numpages, int enable) | |||
175 | pmd = pmd_offset(pud, address); | 175 | pmd = pmd_offset(pud, address); |
176 | pte = pte_offset_kernel(pmd, address); | 176 | pte = pte_offset_kernel(pmd, address); |
177 | if (!enable) { | 177 | if (!enable) { |
178 | ptep_invalidate(&init_mm, address, pte); | 178 | __ptep_ipte(address, pte); |
179 | pte_val(*pte) = _PAGE_TYPE_EMPTY; | ||
179 | continue; | 180 | continue; |
180 | } | 181 | } |
181 | *pte = mk_pte_phys(address, __pgprot(_PAGE_TYPE_RW)); | 182 | *pte = mk_pte_phys(address, __pgprot(_PAGE_TYPE_RW)); |
diff --git a/arch/s390/mm/pageattr.c b/arch/s390/mm/pageattr.c index f05edcc3beff..d013ed39743b 100644 --- a/arch/s390/mm/pageattr.c +++ b/arch/s390/mm/pageattr.c | |||
@@ -28,7 +28,7 @@ static void change_page_attr(unsigned long addr, int numpages, | |||
28 | 28 | ||
29 | pte = *ptep; | 29 | pte = *ptep; |
30 | pte = set(pte); | 30 | pte = set(pte); |
31 | ptep_invalidate(&init_mm, addr, ptep); | 31 | __ptep_ipte(addr, ptep); |
32 | *ptep = pte; | 32 | *ptep = pte; |
33 | addr += PAGE_SIZE; | 33 | addr += PAGE_SIZE; |
34 | } | 34 | } |
diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c index e1850c28cd68..8d4330642512 100644 --- a/arch/s390/mm/pgtable.c +++ b/arch/s390/mm/pgtable.c | |||
@@ -40,7 +40,6 @@ DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); | |||
40 | static DEFINE_PER_CPU(struct rcu_table_freelist *, rcu_table_freelist); | 40 | static DEFINE_PER_CPU(struct rcu_table_freelist *, rcu_table_freelist); |
41 | 41 | ||
42 | static void __page_table_free(struct mm_struct *mm, unsigned long *table); | 42 | static void __page_table_free(struct mm_struct *mm, unsigned long *table); |
43 | static void __crst_table_free(struct mm_struct *mm, unsigned long *table); | ||
44 | 43 | ||
45 | static struct rcu_table_freelist *rcu_table_freelist_get(struct mm_struct *mm) | 44 | static struct rcu_table_freelist *rcu_table_freelist_get(struct mm_struct *mm) |
46 | { | 45 | { |
@@ -67,7 +66,7 @@ static void rcu_table_freelist_callback(struct rcu_head *head) | |||
67 | while (batch->pgt_index > 0) | 66 | while (batch->pgt_index > 0) |
68 | __page_table_free(batch->mm, batch->table[--batch->pgt_index]); | 67 | __page_table_free(batch->mm, batch->table[--batch->pgt_index]); |
69 | while (batch->crst_index < RCU_FREELIST_SIZE) | 68 | while (batch->crst_index < RCU_FREELIST_SIZE) |
70 | __crst_table_free(batch->mm, batch->table[batch->crst_index++]); | 69 | crst_table_free(batch->mm, batch->table[batch->crst_index++]); |
71 | free_page((unsigned long) batch); | 70 | free_page((unsigned long) batch); |
72 | } | 71 | } |
73 | 72 | ||
@@ -125,63 +124,33 @@ static int __init parse_vmalloc(char *arg) | |||
125 | } | 124 | } |
126 | early_param("vmalloc", parse_vmalloc); | 125 | early_param("vmalloc", parse_vmalloc); |
127 | 126 | ||
128 | unsigned long *crst_table_alloc(struct mm_struct *mm, int noexec) | 127 | unsigned long *crst_table_alloc(struct mm_struct *mm) |
129 | { | 128 | { |
130 | struct page *page = alloc_pages(GFP_KERNEL, ALLOC_ORDER); | 129 | struct page *page = alloc_pages(GFP_KERNEL, ALLOC_ORDER); |
131 | 130 | ||
132 | if (!page) | 131 | if (!page) |
133 | return NULL; | 132 | return NULL; |
134 | page->index = 0; | ||
135 | if (noexec) { | ||
136 | struct page *shadow = alloc_pages(GFP_KERNEL, ALLOC_ORDER); | ||
137 | if (!shadow) { | ||
138 | __free_pages(page, ALLOC_ORDER); | ||
139 | return NULL; | ||
140 | } | ||
141 | page->index = page_to_phys(shadow); | ||
142 | } | ||
143 | spin_lock_bh(&mm->context.list_lock); | ||
144 | list_add(&page->lru, &mm->context.crst_list); | ||
145 | spin_unlock_bh(&mm->context.list_lock); | ||
146 | return (unsigned long *) page_to_phys(page); | 133 | return (unsigned long *) page_to_phys(page); |
147 | } | 134 | } |
148 | 135 | ||
149 | static void __crst_table_free(struct mm_struct *mm, unsigned long *table) | ||
150 | { | ||
151 | unsigned long *shadow = get_shadow_table(table); | ||
152 | |||
153 | if (shadow) | ||
154 | free_pages((unsigned long) shadow, ALLOC_ORDER); | ||
155 | free_pages((unsigned long) table, ALLOC_ORDER); | ||
156 | } | ||
157 | |||
158 | void crst_table_free(struct mm_struct *mm, unsigned long *table) | 136 | void crst_table_free(struct mm_struct *mm, unsigned long *table) |
159 | { | 137 | { |
160 | struct page *page = virt_to_page(table); | 138 | free_pages((unsigned long) table, ALLOC_ORDER); |
161 | |||
162 | spin_lock_bh(&mm->context.list_lock); | ||
163 | list_del(&page->lru); | ||
164 | spin_unlock_bh(&mm->context.list_lock); | ||
165 | __crst_table_free(mm, table); | ||
166 | } | 139 | } |
167 | 140 | ||
168 | void crst_table_free_rcu(struct mm_struct *mm, unsigned long *table) | 141 | void crst_table_free_rcu(struct mm_struct *mm, unsigned long *table) |
169 | { | 142 | { |
170 | struct rcu_table_freelist *batch; | 143 | struct rcu_table_freelist *batch; |
171 | struct page *page = virt_to_page(table); | ||
172 | 144 | ||
173 | spin_lock_bh(&mm->context.list_lock); | ||
174 | list_del(&page->lru); | ||
175 | spin_unlock_bh(&mm->context.list_lock); | ||
176 | if (atomic_read(&mm->mm_users) < 2 && | 145 | if (atomic_read(&mm->mm_users) < 2 && |
177 | cpumask_equal(mm_cpumask(mm), cpumask_of(smp_processor_id()))) { | 146 | cpumask_equal(mm_cpumask(mm), cpumask_of(smp_processor_id()))) { |
178 | __crst_table_free(mm, table); | 147 | crst_table_free(mm, table); |
179 | return; | 148 | return; |
180 | } | 149 | } |
181 | batch = rcu_table_freelist_get(mm); | 150 | batch = rcu_table_freelist_get(mm); |
182 | if (!batch) { | 151 | if (!batch) { |
183 | smp_call_function(smp_sync, NULL, 1); | 152 | smp_call_function(smp_sync, NULL, 1); |
184 | __crst_table_free(mm, table); | 153 | crst_table_free(mm, table); |
185 | return; | 154 | return; |
186 | } | 155 | } |
187 | batch->table[--batch->crst_index] = table; | 156 | batch->table[--batch->crst_index] = table; |
@@ -197,7 +166,7 @@ int crst_table_upgrade(struct mm_struct *mm, unsigned long limit) | |||
197 | 166 | ||
198 | BUG_ON(limit > (1UL << 53)); | 167 | BUG_ON(limit > (1UL << 53)); |
199 | repeat: | 168 | repeat: |
200 | table = crst_table_alloc(mm, mm->context.noexec); | 169 | table = crst_table_alloc(mm); |
201 | if (!table) | 170 | if (!table) |
202 | return -ENOMEM; | 171 | return -ENOMEM; |
203 | spin_lock_bh(&mm->page_table_lock); | 172 | spin_lock_bh(&mm->page_table_lock); |
@@ -273,7 +242,7 @@ unsigned long *page_table_alloc(struct mm_struct *mm) | |||
273 | unsigned long *table; | 242 | unsigned long *table; |
274 | unsigned long bits; | 243 | unsigned long bits; |
275 | 244 | ||
276 | bits = (mm->context.noexec || mm->context.has_pgste) ? 3UL : 1UL; | 245 | bits = (mm->context.has_pgste) ? 3UL : 1UL; |
277 | spin_lock_bh(&mm->context.list_lock); | 246 | spin_lock_bh(&mm->context.list_lock); |
278 | page = NULL; | 247 | page = NULL; |
279 | if (!list_empty(&mm->context.pgtable_list)) { | 248 | if (!list_empty(&mm->context.pgtable_list)) { |
@@ -329,7 +298,7 @@ void page_table_free(struct mm_struct *mm, unsigned long *table) | |||
329 | struct page *page; | 298 | struct page *page; |
330 | unsigned long bits; | 299 | unsigned long bits; |
331 | 300 | ||
332 | bits = (mm->context.noexec || mm->context.has_pgste) ? 3UL : 1UL; | 301 | bits = (mm->context.has_pgste) ? 3UL : 1UL; |
333 | bits <<= (__pa(table) & (PAGE_SIZE - 1)) / 256 / sizeof(unsigned long); | 302 | bits <<= (__pa(table) & (PAGE_SIZE - 1)) / 256 / sizeof(unsigned long); |
334 | page = pfn_to_page(__pa(table) >> PAGE_SHIFT); | 303 | page = pfn_to_page(__pa(table) >> PAGE_SHIFT); |
335 | spin_lock_bh(&mm->context.list_lock); | 304 | spin_lock_bh(&mm->context.list_lock); |
@@ -366,7 +335,7 @@ void page_table_free_rcu(struct mm_struct *mm, unsigned long *table) | |||
366 | page_table_free(mm, table); | 335 | page_table_free(mm, table); |
367 | return; | 336 | return; |
368 | } | 337 | } |
369 | bits = (mm->context.noexec || mm->context.has_pgste) ? 3UL : 1UL; | 338 | bits = (mm->context.has_pgste) ? 3UL : 1UL; |
370 | bits <<= (__pa(table) & (PAGE_SIZE - 1)) / 256 / sizeof(unsigned long); | 339 | bits <<= (__pa(table) & (PAGE_SIZE - 1)) / 256 / sizeof(unsigned long); |
371 | page = pfn_to_page(__pa(table) >> PAGE_SHIFT); | 340 | page = pfn_to_page(__pa(table) >> PAGE_SHIFT); |
372 | spin_lock_bh(&mm->context.list_lock); | 341 | spin_lock_bh(&mm->context.list_lock); |
@@ -379,25 +348,6 @@ void page_table_free_rcu(struct mm_struct *mm, unsigned long *table) | |||
379 | rcu_table_freelist_finish(); | 348 | rcu_table_freelist_finish(); |
380 | } | 349 | } |
381 | 350 | ||
382 | void disable_noexec(struct mm_struct *mm, struct task_struct *tsk) | ||
383 | { | ||
384 | struct page *page; | ||
385 | |||
386 | spin_lock_bh(&mm->context.list_lock); | ||
387 | /* Free shadow region and segment tables. */ | ||
388 | list_for_each_entry(page, &mm->context.crst_list, lru) | ||
389 | if (page->index) { | ||
390 | free_pages((unsigned long) page->index, ALLOC_ORDER); | ||
391 | page->index = 0; | ||
392 | } | ||
393 | /* "Free" second halves of page tables. */ | ||
394 | list_for_each_entry(page, &mm->context.pgtable_list, lru) | ||
395 | page->flags &= ~SECOND_HALVES; | ||
396 | spin_unlock_bh(&mm->context.list_lock); | ||
397 | mm->context.noexec = 0; | ||
398 | update_mm(mm, tsk); | ||
399 | } | ||
400 | |||
401 | /* | 351 | /* |
402 | * switch on pgstes for its userspace process (for kvm) | 352 | * switch on pgstes for its userspace process (for kvm) |
403 | */ | 353 | */ |
diff --git a/arch/s390/mm/vmem.c b/arch/s390/mm/vmem.c index 34c43f23b28c..8c1970d1dd91 100644 --- a/arch/s390/mm/vmem.c +++ b/arch/s390/mm/vmem.c | |||
@@ -95,7 +95,7 @@ static int vmem_add_mem(unsigned long start, unsigned long size, int ro) | |||
95 | pu_dir = vmem_pud_alloc(); | 95 | pu_dir = vmem_pud_alloc(); |
96 | if (!pu_dir) | 96 | if (!pu_dir) |
97 | goto out; | 97 | goto out; |
98 | pgd_populate_kernel(&init_mm, pg_dir, pu_dir); | 98 | pgd_populate(&init_mm, pg_dir, pu_dir); |
99 | } | 99 | } |
100 | 100 | ||
101 | pu_dir = pud_offset(pg_dir, address); | 101 | pu_dir = pud_offset(pg_dir, address); |
@@ -103,7 +103,7 @@ static int vmem_add_mem(unsigned long start, unsigned long size, int ro) | |||
103 | pm_dir = vmem_pmd_alloc(); | 103 | pm_dir = vmem_pmd_alloc(); |
104 | if (!pm_dir) | 104 | if (!pm_dir) |
105 | goto out; | 105 | goto out; |
106 | pud_populate_kernel(&init_mm, pu_dir, pm_dir); | 106 | pud_populate(&init_mm, pu_dir, pm_dir); |
107 | } | 107 | } |
108 | 108 | ||
109 | pte = mk_pte_phys(address, __pgprot(ro ? _PAGE_RO : 0)); | 109 | pte = mk_pte_phys(address, __pgprot(ro ? _PAGE_RO : 0)); |
@@ -123,7 +123,7 @@ static int vmem_add_mem(unsigned long start, unsigned long size, int ro) | |||
123 | pt_dir = vmem_pte_alloc(); | 123 | pt_dir = vmem_pte_alloc(); |
124 | if (!pt_dir) | 124 | if (!pt_dir) |
125 | goto out; | 125 | goto out; |
126 | pmd_populate_kernel(&init_mm, pm_dir, pt_dir); | 126 | pmd_populate(&init_mm, pm_dir, pt_dir); |
127 | } | 127 | } |
128 | 128 | ||
129 | pt_dir = pte_offset_kernel(pm_dir, address); | 129 | pt_dir = pte_offset_kernel(pm_dir, address); |
@@ -159,7 +159,7 @@ static void vmem_remove_range(unsigned long start, unsigned long size) | |||
159 | continue; | 159 | continue; |
160 | 160 | ||
161 | if (pmd_huge(*pm_dir)) { | 161 | if (pmd_huge(*pm_dir)) { |
162 | pmd_clear_kernel(pm_dir); | 162 | pmd_clear(pm_dir); |
163 | address += HPAGE_SIZE - PAGE_SIZE; | 163 | address += HPAGE_SIZE - PAGE_SIZE; |
164 | continue; | 164 | continue; |
165 | } | 165 | } |
@@ -192,7 +192,7 @@ int __meminit vmemmap_populate(struct page *start, unsigned long nr, int node) | |||
192 | pu_dir = vmem_pud_alloc(); | 192 | pu_dir = vmem_pud_alloc(); |
193 | if (!pu_dir) | 193 | if (!pu_dir) |
194 | goto out; | 194 | goto out; |
195 | pgd_populate_kernel(&init_mm, pg_dir, pu_dir); | 195 | pgd_populate(&init_mm, pg_dir, pu_dir); |
196 | } | 196 | } |
197 | 197 | ||
198 | pu_dir = pud_offset(pg_dir, address); | 198 | pu_dir = pud_offset(pg_dir, address); |
@@ -200,7 +200,7 @@ int __meminit vmemmap_populate(struct page *start, unsigned long nr, int node) | |||
200 | pm_dir = vmem_pmd_alloc(); | 200 | pm_dir = vmem_pmd_alloc(); |
201 | if (!pm_dir) | 201 | if (!pm_dir) |
202 | goto out; | 202 | goto out; |
203 | pud_populate_kernel(&init_mm, pu_dir, pm_dir); | 203 | pud_populate(&init_mm, pu_dir, pm_dir); |
204 | } | 204 | } |
205 | 205 | ||
206 | pm_dir = pmd_offset(pu_dir, address); | 206 | pm_dir = pmd_offset(pu_dir, address); |
@@ -208,7 +208,7 @@ int __meminit vmemmap_populate(struct page *start, unsigned long nr, int node) | |||
208 | pt_dir = vmem_pte_alloc(); | 208 | pt_dir = vmem_pte_alloc(); |
209 | if (!pt_dir) | 209 | if (!pt_dir) |
210 | goto out; | 210 | goto out; |
211 | pmd_populate_kernel(&init_mm, pm_dir, pt_dir); | 211 | pmd_populate(&init_mm, pm_dir, pt_dir); |
212 | } | 212 | } |
213 | 213 | ||
214 | pt_dir = pte_offset_kernel(pm_dir, address); | 214 | pt_dir = pte_offset_kernel(pm_dir, address); |
diff --git a/arch/s390/oprofile/hwsampler.c b/arch/s390/oprofile/hwsampler.c index 33cbd373cce4..053caa0fd276 100644 --- a/arch/s390/oprofile/hwsampler.c +++ b/arch/s390/oprofile/hwsampler.c | |||
@@ -5,6 +5,7 @@ | |||
5 | * Author: Heinz Graalfs <graalfs@de.ibm.com> | 5 | * Author: Heinz Graalfs <graalfs@de.ibm.com> |
6 | */ | 6 | */ |
7 | 7 | ||
8 | #include <linux/kernel_stat.h> | ||
8 | #include <linux/kernel.h> | 9 | #include <linux/kernel.h> |
9 | #include <linux/module.h> | 10 | #include <linux/module.h> |
10 | #include <linux/smp.h> | 11 | #include <linux/smp.h> |
@@ -674,17 +675,11 @@ int hwsampler_activate(unsigned int cpu) | |||
674 | static void hws_ext_handler(unsigned int ext_int_code, | 675 | static void hws_ext_handler(unsigned int ext_int_code, |
675 | unsigned int param32, unsigned long param64) | 676 | unsigned int param32, unsigned long param64) |
676 | { | 677 | { |
677 | int cpu; | ||
678 | struct hws_cpu_buffer *cb; | 678 | struct hws_cpu_buffer *cb; |
679 | 679 | ||
680 | cpu = smp_processor_id(); | 680 | kstat_cpu(smp_processor_id()).irqs[EXTINT_CPM]++; |
681 | cb = &per_cpu(sampler_cpu_buffer, cpu); | 681 | cb = &__get_cpu_var(sampler_cpu_buffer); |
682 | 682 | atomic_xchg(&cb->ext_params, atomic_read(&cb->ext_params) | param32); | |
683 | atomic_xchg( | ||
684 | &cb->ext_params, | ||
685 | atomic_read(&cb->ext_params) | ||
686 | | S390_lowcore.ext_params); | ||
687 | |||
688 | if (hws_wq) | 683 | if (hws_wq) |
689 | queue_work(hws_wq, &cb->worker); | 684 | queue_work(hws_wq, &cb->worker); |
690 | } | 685 | } |
@@ -764,7 +759,7 @@ static int worker_check_error(unsigned int cpu, int ext_params) | |||
764 | if (!sdbt || !*sdbt) | 759 | if (!sdbt || !*sdbt) |
765 | return -EINVAL; | 760 | return -EINVAL; |
766 | 761 | ||
767 | if (ext_params & EI_IEA) | 762 | if (ext_params & EI_PRA) |
768 | cb->req_alert++; | 763 | cb->req_alert++; |
769 | 764 | ||
770 | if (ext_params & EI_LSDA) | 765 | if (ext_params & EI_LSDA) |
@@ -1009,7 +1004,7 @@ int hwsampler_deallocate() | |||
1009 | if (hws_state != HWS_STOPPED) | 1004 | if (hws_state != HWS_STOPPED) |
1010 | goto deallocate_exit; | 1005 | goto deallocate_exit; |
1011 | 1006 | ||
1012 | smp_ctl_clear_bit(0, 5); /* set bit 58 CR0 off */ | 1007 | ctl_clear_bit(0, 5); /* set bit 58 CR0 off */ |
1013 | deallocate_sdbt(); | 1008 | deallocate_sdbt(); |
1014 | 1009 | ||
1015 | hws_state = HWS_DEALLOCATED; | 1010 | hws_state = HWS_DEALLOCATED; |
@@ -1123,7 +1118,7 @@ int hwsampler_shutdown() | |||
1123 | mutex_lock(&hws_sem); | 1118 | mutex_lock(&hws_sem); |
1124 | 1119 | ||
1125 | if (hws_state == HWS_STOPPED) { | 1120 | if (hws_state == HWS_STOPPED) { |
1126 | smp_ctl_clear_bit(0, 5); /* set bit 58 CR0 off */ | 1121 | ctl_clear_bit(0, 5); /* set bit 58 CR0 off */ |
1127 | deallocate_sdbt(); | 1122 | deallocate_sdbt(); |
1128 | } | 1123 | } |
1129 | if (hws_wq) { | 1124 | if (hws_wq) { |
@@ -1198,7 +1193,7 @@ start_all_exit: | |||
1198 | hws_oom = 1; | 1193 | hws_oom = 1; |
1199 | hws_flush_all = 0; | 1194 | hws_flush_all = 0; |
1200 | /* now let them in, 1407 CPUMF external interrupts */ | 1195 | /* now let them in, 1407 CPUMF external interrupts */ |
1201 | smp_ctl_set_bit(0, 5); /* set CR0 bit 58 */ | 1196 | ctl_set_bit(0, 5); /* set CR0 bit 58 */ |
1202 | 1197 | ||
1203 | return 0; | 1198 | return 0; |
1204 | } | 1199 | } |
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index c64c3807f516..e0b25de1e339 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig | |||
@@ -74,6 +74,8 @@ config ZCRYPT | |||
74 | + PCI-X Cryptographic Coprocessor (PCIXCC) | 74 | + PCI-X Cryptographic Coprocessor (PCIXCC) |
75 | + Crypto Express2 Coprocessor (CEX2C) | 75 | + Crypto Express2 Coprocessor (CEX2C) |
76 | + Crypto Express2 Accelerator (CEX2A) | 76 | + Crypto Express2 Accelerator (CEX2A) |
77 | + Crypto Express3 Coprocessor (CEX3C) | ||
78 | + Crypto Express3 Accelerator (CEX3A) | ||
77 | 79 | ||
78 | config ZCRYPT_MONOLITHIC | 80 | config ZCRYPT_MONOLITHIC |
79 | bool "Monolithic zcrypt module" | 81 | bool "Monolithic zcrypt module" |
diff --git a/drivers/s390/block/dasd_alias.c b/drivers/s390/block/dasd_alias.c index 2b771f18d1ad..c388eda1e2b1 100644 --- a/drivers/s390/block/dasd_alias.c +++ b/drivers/s390/block/dasd_alias.c | |||
@@ -253,13 +253,11 @@ int dasd_alias_make_device_known_to_lcu(struct dasd_device *device) | |||
253 | */ | 253 | */ |
254 | void dasd_alias_lcu_setup_complete(struct dasd_device *device) | 254 | void dasd_alias_lcu_setup_complete(struct dasd_device *device) |
255 | { | 255 | { |
256 | struct dasd_eckd_private *private; | ||
257 | unsigned long flags; | 256 | unsigned long flags; |
258 | struct alias_server *server; | 257 | struct alias_server *server; |
259 | struct alias_lcu *lcu; | 258 | struct alias_lcu *lcu; |
260 | struct dasd_uid uid; | 259 | struct dasd_uid uid; |
261 | 260 | ||
262 | private = (struct dasd_eckd_private *) device->private; | ||
263 | device->discipline->get_uid(device, &uid); | 261 | device->discipline->get_uid(device, &uid); |
264 | lcu = NULL; | 262 | lcu = NULL; |
265 | spin_lock_irqsave(&aliastree.lock, flags); | 263 | spin_lock_irqsave(&aliastree.lock, flags); |
@@ -279,13 +277,11 @@ void dasd_alias_lcu_setup_complete(struct dasd_device *device) | |||
279 | 277 | ||
280 | void dasd_alias_wait_for_lcu_setup(struct dasd_device *device) | 278 | void dasd_alias_wait_for_lcu_setup(struct dasd_device *device) |
281 | { | 279 | { |
282 | struct dasd_eckd_private *private; | ||
283 | unsigned long flags; | 280 | unsigned long flags; |
284 | struct alias_server *server; | 281 | struct alias_server *server; |
285 | struct alias_lcu *lcu; | 282 | struct alias_lcu *lcu; |
286 | struct dasd_uid uid; | 283 | struct dasd_uid uid; |
287 | 284 | ||
288 | private = (struct dasd_eckd_private *) device->private; | ||
289 | device->discipline->get_uid(device, &uid); | 285 | device->discipline->get_uid(device, &uid); |
290 | lcu = NULL; | 286 | lcu = NULL; |
291 | spin_lock_irqsave(&aliastree.lock, flags); | 287 | spin_lock_irqsave(&aliastree.lock, flags); |
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 3ebdf5f92f8f..30fb979d684d 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c | |||
@@ -1611,10 +1611,8 @@ static void dasd_eckd_analysis_callback(struct dasd_ccw_req *init_cqr, | |||
1611 | 1611 | ||
1612 | static int dasd_eckd_start_analysis(struct dasd_block *block) | 1612 | static int dasd_eckd_start_analysis(struct dasd_block *block) |
1613 | { | 1613 | { |
1614 | struct dasd_eckd_private *private; | ||
1615 | struct dasd_ccw_req *init_cqr; | 1614 | struct dasd_ccw_req *init_cqr; |
1616 | 1615 | ||
1617 | private = (struct dasd_eckd_private *) block->base->private; | ||
1618 | init_cqr = dasd_eckd_analysis_ccw(block->base); | 1616 | init_cqr = dasd_eckd_analysis_ccw(block->base); |
1619 | if (IS_ERR(init_cqr)) | 1617 | if (IS_ERR(init_cqr)) |
1620 | return PTR_ERR(init_cqr); | 1618 | return PTR_ERR(init_cqr); |
@@ -2264,7 +2262,6 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_track( | |||
2264 | unsigned int blk_per_trk, | 2262 | unsigned int blk_per_trk, |
2265 | unsigned int blksize) | 2263 | unsigned int blksize) |
2266 | { | 2264 | { |
2267 | struct dasd_eckd_private *private; | ||
2268 | unsigned long *idaws; | 2265 | unsigned long *idaws; |
2269 | struct dasd_ccw_req *cqr; | 2266 | struct dasd_ccw_req *cqr; |
2270 | struct ccw1 *ccw; | 2267 | struct ccw1 *ccw; |
@@ -2283,7 +2280,6 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_track( | |||
2283 | unsigned int recoffs; | 2280 | unsigned int recoffs; |
2284 | 2281 | ||
2285 | basedev = block->base; | 2282 | basedev = block->base; |
2286 | private = (struct dasd_eckd_private *) basedev->private; | ||
2287 | if (rq_data_dir(req) == READ) | 2283 | if (rq_data_dir(req) == READ) |
2288 | cmd = DASD_ECKD_CCW_READ_TRACK_DATA; | 2284 | cmd = DASD_ECKD_CCW_READ_TRACK_DATA; |
2289 | else if (rq_data_dir(req) == WRITE) | 2285 | else if (rq_data_dir(req) == WRITE) |
@@ -2556,8 +2552,7 @@ static int prepare_itcw(struct itcw *itcw, | |||
2556 | 2552 | ||
2557 | dcw = itcw_add_dcw(itcw, pfx_cmd, 0, | 2553 | dcw = itcw_add_dcw(itcw, pfx_cmd, 0, |
2558 | &pfxdata, sizeof(pfxdata), total_data_size); | 2554 | &pfxdata, sizeof(pfxdata), total_data_size); |
2559 | 2555 | return IS_ERR(dcw) ? PTR_ERR(dcw) : 0; | |
2560 | return rc; | ||
2561 | } | 2556 | } |
2562 | 2557 | ||
2563 | static struct dasd_ccw_req *dasd_eckd_build_cp_tpm_track( | 2558 | static struct dasd_ccw_req *dasd_eckd_build_cp_tpm_track( |
@@ -2573,7 +2568,6 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_tpm_track( | |||
2573 | unsigned int blk_per_trk, | 2568 | unsigned int blk_per_trk, |
2574 | unsigned int blksize) | 2569 | unsigned int blksize) |
2575 | { | 2570 | { |
2576 | struct dasd_eckd_private *private; | ||
2577 | struct dasd_ccw_req *cqr; | 2571 | struct dasd_ccw_req *cqr; |
2578 | struct req_iterator iter; | 2572 | struct req_iterator iter; |
2579 | struct bio_vec *bv; | 2573 | struct bio_vec *bv; |
@@ -2594,7 +2588,6 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_tpm_track( | |||
2594 | unsigned int count, count_to_trk_end; | 2588 | unsigned int count, count_to_trk_end; |
2595 | 2589 | ||
2596 | basedev = block->base; | 2590 | basedev = block->base; |
2597 | private = (struct dasd_eckd_private *) basedev->private; | ||
2598 | if (rq_data_dir(req) == READ) { | 2591 | if (rq_data_dir(req) == READ) { |
2599 | cmd = DASD_ECKD_CCW_READ_TRACK_DATA; | 2592 | cmd = DASD_ECKD_CCW_READ_TRACK_DATA; |
2600 | itcw_op = ITCW_OP_READ; | 2593 | itcw_op = ITCW_OP_READ; |
@@ -2801,7 +2794,6 @@ static struct dasd_ccw_req *dasd_raw_build_cp(struct dasd_device *startdev, | |||
2801 | struct dasd_block *block, | 2794 | struct dasd_block *block, |
2802 | struct request *req) | 2795 | struct request *req) |
2803 | { | 2796 | { |
2804 | struct dasd_eckd_private *private; | ||
2805 | unsigned long *idaws; | 2797 | unsigned long *idaws; |
2806 | struct dasd_device *basedev; | 2798 | struct dasd_device *basedev; |
2807 | struct dasd_ccw_req *cqr; | 2799 | struct dasd_ccw_req *cqr; |
@@ -2836,7 +2828,6 @@ static struct dasd_ccw_req *dasd_raw_build_cp(struct dasd_device *startdev, | |||
2836 | trkcount = last_trk - first_trk + 1; | 2828 | trkcount = last_trk - first_trk + 1; |
2837 | first_offs = 0; | 2829 | first_offs = 0; |
2838 | basedev = block->base; | 2830 | basedev = block->base; |
2839 | private = (struct dasd_eckd_private *) basedev->private; | ||
2840 | 2831 | ||
2841 | if (rq_data_dir(req) == READ) | 2832 | if (rq_data_dir(req) == READ) |
2842 | cmd = DASD_ECKD_CCW_READ_TRACK; | 2833 | cmd = DASD_ECKD_CCW_READ_TRACK; |
diff --git a/drivers/s390/char/Kconfig b/drivers/s390/char/Kconfig index dcee3c5c8954..a4f117d9fdc6 100644 --- a/drivers/s390/char/Kconfig +++ b/drivers/s390/char/Kconfig | |||
@@ -119,18 +119,6 @@ config S390_TAPE | |||
119 | comment "S/390 tape interface support" | 119 | comment "S/390 tape interface support" |
120 | depends on S390_TAPE | 120 | depends on S390_TAPE |
121 | 121 | ||
122 | config S390_TAPE_BLOCK | ||
123 | def_bool y | ||
124 | prompt "Support for tape block devices" | ||
125 | depends on S390_TAPE && BLOCK | ||
126 | help | ||
127 | Select this option if you want to access your channel-attached tape | ||
128 | devices using the block device interface. This interface is similar | ||
129 | to CD-ROM devices on other platforms. The tapes can only be | ||
130 | accessed read-only when using this interface. Have a look at | ||
131 | <file:Documentation/s390/TAPE> for further information about creating | ||
132 | volumes for and using this interface. It is safe to say "Y" here. | ||
133 | |||
134 | comment "S/390 tape hardware support" | 122 | comment "S/390 tape hardware support" |
135 | depends on S390_TAPE | 123 | depends on S390_TAPE |
136 | 124 | ||
diff --git a/drivers/s390/char/Makefile b/drivers/s390/char/Makefile index efb500ab66c0..f3c325207445 100644 --- a/drivers/s390/char/Makefile +++ b/drivers/s390/char/Makefile | |||
@@ -3,7 +3,7 @@ | |||
3 | # | 3 | # |
4 | 4 | ||
5 | obj-y += ctrlchar.o keyboard.o defkeymap.o sclp.o sclp_rw.o sclp_quiesce.o \ | 5 | obj-y += ctrlchar.o keyboard.o defkeymap.o sclp.o sclp_rw.o sclp_quiesce.o \ |
6 | sclp_cmd.o sclp_config.o sclp_cpi_sys.o | 6 | sclp_cmd.o sclp_config.o sclp_cpi_sys.o sclp_ocf.o |
7 | 7 | ||
8 | obj-$(CONFIG_TN3270) += raw3270.o | 8 | obj-$(CONFIG_TN3270) += raw3270.o |
9 | obj-$(CONFIG_TN3270_CONSOLE) += con3270.o | 9 | obj-$(CONFIG_TN3270_CONSOLE) += con3270.o |
@@ -22,7 +22,6 @@ obj-$(CONFIG_ZVM_WATCHDOG) += vmwatchdog.o | |||
22 | obj-$(CONFIG_VMLOGRDR) += vmlogrdr.o | 22 | obj-$(CONFIG_VMLOGRDR) += vmlogrdr.o |
23 | obj-$(CONFIG_VMCP) += vmcp.o | 23 | obj-$(CONFIG_VMCP) += vmcp.o |
24 | 24 | ||
25 | tape-$(CONFIG_S390_TAPE_BLOCK) += tape_block.o | ||
26 | tape-$(CONFIG_PROC_FS) += tape_proc.o | 25 | tape-$(CONFIG_PROC_FS) += tape_proc.o |
27 | tape-objs := tape_core.o tape_std.o tape_char.o $(tape-y) | 26 | tape-objs := tape_core.o tape_std.o tape_char.o $(tape-y) |
28 | obj-$(CONFIG_S390_TAPE) += tape.o tape_class.o | 27 | obj-$(CONFIG_S390_TAPE) += tape.o tape_class.o |
diff --git a/drivers/s390/char/monwriter.c b/drivers/s390/char/monwriter.c index e0702d3ea33b..4600aa10a1c6 100644 --- a/drivers/s390/char/monwriter.c +++ b/drivers/s390/char/monwriter.c | |||
@@ -97,7 +97,7 @@ static int monwrite_new_hdr(struct mon_private *monpriv) | |||
97 | { | 97 | { |
98 | struct monwrite_hdr *monhdr = &monpriv->hdr; | 98 | struct monwrite_hdr *monhdr = &monpriv->hdr; |
99 | struct mon_buf *monbuf; | 99 | struct mon_buf *monbuf; |
100 | int rc; | 100 | int rc = 0; |
101 | 101 | ||
102 | if (monhdr->datalen > MONWRITE_MAX_DATALEN || | 102 | if (monhdr->datalen > MONWRITE_MAX_DATALEN || |
103 | monhdr->mon_function > MONWRITE_START_CONFIG || | 103 | monhdr->mon_function > MONWRITE_START_CONFIG || |
@@ -135,7 +135,7 @@ static int monwrite_new_hdr(struct mon_private *monpriv) | |||
135 | mon_buf_count++; | 135 | mon_buf_count++; |
136 | } | 136 | } |
137 | monpriv->current_buf = monbuf; | 137 | monpriv->current_buf = monbuf; |
138 | return 0; | 138 | return rc; |
139 | } | 139 | } |
140 | 140 | ||
141 | static int monwrite_new_data(struct mon_private *monpriv) | 141 | static int monwrite_new_data(struct mon_private *monpriv) |
diff --git a/drivers/s390/char/raw3270.c b/drivers/s390/char/raw3270.c index e21a5c39ef20..810ac38631c3 100644 --- a/drivers/s390/char/raw3270.c +++ b/drivers/s390/char/raw3270.c | |||
@@ -598,7 +598,6 @@ __raw3270_size_device(struct raw3270 *rp) | |||
598 | static const unsigned char wbuf[] = | 598 | static const unsigned char wbuf[] = |
599 | { 0x00, 0x07, 0x01, 0xff, 0x03, 0x00, 0x81 }; | 599 | { 0x00, 0x07, 0x01, 0xff, 0x03, 0x00, 0x81 }; |
600 | struct raw3270_ua *uap; | 600 | struct raw3270_ua *uap; |
601 | unsigned short count; | ||
602 | int rc; | 601 | int rc; |
603 | 602 | ||
604 | /* | 603 | /* |
@@ -653,7 +652,6 @@ __raw3270_size_device(struct raw3270 *rp) | |||
653 | if (rc) | 652 | if (rc) |
654 | return rc; | 653 | return rc; |
655 | /* Got a Query Reply */ | 654 | /* Got a Query Reply */ |
656 | count = sizeof(rp->init_data) - rp->init_request.rescnt; | ||
657 | uap = (struct raw3270_ua *) (rp->init_data + 1); | 655 | uap = (struct raw3270_ua *) (rp->init_data + 1); |
658 | /* Paranoia check. */ | 656 | /* Paranoia check. */ |
659 | if (rp->init_data[0] != 0x88 || uap->uab.qcode != 0x81) | 657 | if (rp->init_data[0] != 0x88 || uap->uab.qcode != 0x81) |
diff --git a/drivers/s390/char/sclp.h b/drivers/s390/char/sclp.h index 6bb5a6bdfab5..49a1bb52bc87 100644 --- a/drivers/s390/char/sclp.h +++ b/drivers/s390/char/sclp.h | |||
@@ -28,6 +28,7 @@ | |||
28 | #define EVTYP_CONFMGMDATA 0x04 | 28 | #define EVTYP_CONFMGMDATA 0x04 |
29 | #define EVTYP_SDIAS 0x1C | 29 | #define EVTYP_SDIAS 0x1C |
30 | #define EVTYP_ASYNC 0x0A | 30 | #define EVTYP_ASYNC 0x0A |
31 | #define EVTYP_OCF 0x1E | ||
31 | 32 | ||
32 | #define EVTYP_OPCMD_MASK 0x80000000 | 33 | #define EVTYP_OPCMD_MASK 0x80000000 |
33 | #define EVTYP_MSG_MASK 0x40000000 | 34 | #define EVTYP_MSG_MASK 0x40000000 |
@@ -40,6 +41,7 @@ | |||
40 | #define EVTYP_CONFMGMDATA_MASK 0x10000000 | 41 | #define EVTYP_CONFMGMDATA_MASK 0x10000000 |
41 | #define EVTYP_SDIAS_MASK 0x00000010 | 42 | #define EVTYP_SDIAS_MASK 0x00000010 |
42 | #define EVTYP_ASYNC_MASK 0x00400000 | 43 | #define EVTYP_ASYNC_MASK 0x00400000 |
44 | #define EVTYP_OCF_MASK 0x00000004 | ||
43 | 45 | ||
44 | #define GNRLMSGFLGS_DOM 0x8000 | 46 | #define GNRLMSGFLGS_DOM 0x8000 |
45 | #define GNRLMSGFLGS_SNDALRM 0x4000 | 47 | #define GNRLMSGFLGS_SNDALRM 0x4000 |
@@ -186,4 +188,26 @@ sclp_ascebc_str(unsigned char *str, int nr) | |||
186 | (MACHINE_IS_VM) ? ASCEBC(str, nr) : ASCEBC_500(str, nr); | 188 | (MACHINE_IS_VM) ? ASCEBC(str, nr) : ASCEBC_500(str, nr); |
187 | } | 189 | } |
188 | 190 | ||
191 | static inline struct gds_vector * | ||
192 | sclp_find_gds_vector(void *start, void *end, u16 id) | ||
193 | { | ||
194 | struct gds_vector *v; | ||
195 | |||
196 | for (v = start; (void *) v < end; v = (void *) v + v->length) | ||
197 | if (v->gds_id == id) | ||
198 | return v; | ||
199 | return NULL; | ||
200 | } | ||
201 | |||
202 | static inline struct gds_subvector * | ||
203 | sclp_find_gds_subvector(void *start, void *end, u8 key) | ||
204 | { | ||
205 | struct gds_subvector *sv; | ||
206 | |||
207 | for (sv = start; (void *) sv < end; sv = (void *) sv + sv->length) | ||
208 | if (sv->key == key) | ||
209 | return sv; | ||
210 | return NULL; | ||
211 | } | ||
212 | |||
189 | #endif /* __SCLP_H__ */ | 213 | #endif /* __SCLP_H__ */ |
diff --git a/drivers/s390/char/sclp_config.c b/drivers/s390/char/sclp_config.c index 16e232a99fb7..95b909ac2b73 100644 --- a/drivers/s390/char/sclp_config.c +++ b/drivers/s390/char/sclp_config.c | |||
@@ -71,21 +71,9 @@ static struct sclp_register sclp_conf_register = | |||
71 | 71 | ||
72 | static int __init sclp_conf_init(void) | 72 | static int __init sclp_conf_init(void) |
73 | { | 73 | { |
74 | int rc; | ||
75 | |||
76 | INIT_WORK(&sclp_cpu_capability_work, sclp_cpu_capability_notify); | 74 | INIT_WORK(&sclp_cpu_capability_work, sclp_cpu_capability_notify); |
77 | INIT_WORK(&sclp_cpu_change_work, sclp_cpu_change_notify); | 75 | INIT_WORK(&sclp_cpu_change_work, sclp_cpu_change_notify); |
78 | 76 | return sclp_register(&sclp_conf_register); | |
79 | rc = sclp_register(&sclp_conf_register); | ||
80 | if (rc) | ||
81 | return rc; | ||
82 | |||
83 | if (!(sclp_conf_register.sclp_send_mask & EVTYP_CONFMGMDATA_MASK)) { | ||
84 | pr_warning("no configuration management.\n"); | ||
85 | sclp_unregister(&sclp_conf_register); | ||
86 | rc = -ENOSYS; | ||
87 | } | ||
88 | return rc; | ||
89 | } | 77 | } |
90 | 78 | ||
91 | __initcall(sclp_conf_init); | 79 | __initcall(sclp_conf_init); |
diff --git a/drivers/s390/char/sclp_ocf.c b/drivers/s390/char/sclp_ocf.c new file mode 100644 index 000000000000..ab294d5a534e --- /dev/null +++ b/drivers/s390/char/sclp_ocf.c | |||
@@ -0,0 +1,145 @@ | |||
1 | /* | ||
2 | * drivers/s390/char/sclp_ocf.c | ||
3 | * SCLP OCF communication parameters sysfs interface | ||
4 | * | ||
5 | * Copyright IBM Corp. 2011 | ||
6 | * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com> | ||
7 | */ | ||
8 | |||
9 | #define KMSG_COMPONENT "sclp_ocf" | ||
10 | #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt | ||
11 | |||
12 | #include <linux/kernel.h> | ||
13 | #include <linux/init.h> | ||
14 | #include <linux/stat.h> | ||
15 | #include <linux/device.h> | ||
16 | #include <linux/string.h> | ||
17 | #include <linux/ctype.h> | ||
18 | #include <linux/kmod.h> | ||
19 | #include <linux/timer.h> | ||
20 | #include <linux/err.h> | ||
21 | #include <asm/ebcdic.h> | ||
22 | #include <asm/sclp.h> | ||
23 | |||
24 | #include "sclp.h" | ||
25 | |||
26 | #define OCF_LENGTH_HMC_NETWORK 8UL | ||
27 | #define OCF_LENGTH_CPC_NAME 8UL | ||
28 | |||
29 | static char hmc_network[OCF_LENGTH_HMC_NETWORK + 1]; | ||
30 | static char cpc_name[OCF_LENGTH_CPC_NAME + 1]; | ||
31 | |||
32 | static DEFINE_SPINLOCK(sclp_ocf_lock); | ||
33 | static struct work_struct sclp_ocf_change_work; | ||
34 | |||
35 | static struct kset *ocf_kset; | ||
36 | |||
37 | static void sclp_ocf_change_notify(struct work_struct *work) | ||
38 | { | ||
39 | kobject_uevent(&ocf_kset->kobj, KOBJ_CHANGE); | ||
40 | } | ||
41 | |||
42 | /* Handler for OCF event. Look for the CPC image name. */ | ||
43 | static void sclp_ocf_handler(struct evbuf_header *evbuf) | ||
44 | { | ||
45 | struct gds_vector *v; | ||
46 | struct gds_subvector *sv, *netid, *cpc; | ||
47 | size_t size; | ||
48 | |||
49 | /* Find the 0x9f00 block. */ | ||
50 | v = sclp_find_gds_vector(evbuf + 1, (void *) evbuf + evbuf->length, | ||
51 | 0x9f00); | ||
52 | if (!v) | ||
53 | return; | ||
54 | /* Find the 0x9f22 block inside the 0x9f00 block. */ | ||
55 | v = sclp_find_gds_vector(v + 1, (void *) v + v->length, 0x9f22); | ||
56 | if (!v) | ||
57 | return; | ||
58 | /* Find the 0x81 block inside the 0x9f22 block. */ | ||
59 | sv = sclp_find_gds_subvector(v + 1, (void *) v + v->length, 0x81); | ||
60 | if (!sv) | ||
61 | return; | ||
62 | /* Find the 0x01 block inside the 0x81 block. */ | ||
63 | netid = sclp_find_gds_subvector(sv + 1, (void *) sv + sv->length, 1); | ||
64 | /* Find the 0x02 block inside the 0x81 block. */ | ||
65 | cpc = sclp_find_gds_subvector(sv + 1, (void *) sv + sv->length, 2); | ||
66 | /* Copy network name and cpc name. */ | ||
67 | spin_lock(&sclp_ocf_lock); | ||
68 | if (netid) { | ||
69 | size = min(OCF_LENGTH_HMC_NETWORK, (size_t) netid->length); | ||
70 | memcpy(hmc_network, netid + 1, size); | ||
71 | EBCASC(hmc_network, size); | ||
72 | hmc_network[size] = 0; | ||
73 | } | ||
74 | if (cpc) { | ||
75 | size = min(OCF_LENGTH_CPC_NAME, (size_t) cpc->length); | ||
76 | memcpy(cpc_name, cpc + 1, size); | ||
77 | EBCASC(cpc_name, size); | ||
78 | cpc_name[size] = 0; | ||
79 | } | ||
80 | spin_unlock(&sclp_ocf_lock); | ||
81 | schedule_work(&sclp_ocf_change_work); | ||
82 | } | ||
83 | |||
84 | static struct sclp_register sclp_ocf_event = { | ||
85 | .receive_mask = EVTYP_OCF_MASK, | ||
86 | .receiver_fn = sclp_ocf_handler, | ||
87 | }; | ||
88 | |||
89 | static ssize_t cpc_name_show(struct kobject *kobj, | ||
90 | struct kobj_attribute *attr, char *page) | ||
91 | { | ||
92 | int rc; | ||
93 | |||
94 | spin_lock_irq(&sclp_ocf_lock); | ||
95 | rc = snprintf(page, PAGE_SIZE, "%s\n", cpc_name); | ||
96 | spin_unlock_irq(&sclp_ocf_lock); | ||
97 | return rc; | ||
98 | } | ||
99 | |||
100 | static struct kobj_attribute cpc_name_attr = | ||
101 | __ATTR(cpc_name, 0444, cpc_name_show, NULL); | ||
102 | |||
103 | static ssize_t hmc_network_show(struct kobject *kobj, | ||
104 | struct kobj_attribute *attr, char *page) | ||
105 | { | ||
106 | int rc; | ||
107 | |||
108 | spin_lock_irq(&sclp_ocf_lock); | ||
109 | rc = snprintf(page, PAGE_SIZE, "%s\n", hmc_network); | ||
110 | spin_unlock_irq(&sclp_ocf_lock); | ||
111 | return rc; | ||
112 | } | ||
113 | |||
114 | static struct kobj_attribute hmc_network_attr = | ||
115 | __ATTR(hmc_network, 0444, hmc_network_show, NULL); | ||
116 | |||
117 | static struct attribute *ocf_attrs[] = { | ||
118 | &cpc_name_attr.attr, | ||
119 | &hmc_network_attr.attr, | ||
120 | NULL, | ||
121 | }; | ||
122 | |||
123 | static struct attribute_group ocf_attr_group = { | ||
124 | .attrs = ocf_attrs, | ||
125 | }; | ||
126 | |||
127 | static int __init ocf_init(void) | ||
128 | { | ||
129 | int rc; | ||
130 | |||
131 | INIT_WORK(&sclp_ocf_change_work, sclp_ocf_change_notify); | ||
132 | ocf_kset = kset_create_and_add("ocf", NULL, firmware_kobj); | ||
133 | if (!ocf_kset) | ||
134 | return -ENOMEM; | ||
135 | |||
136 | rc = sysfs_create_group(&ocf_kset->kobj, &ocf_attr_group); | ||
137 | if (rc) { | ||
138 | kset_unregister(ocf_kset); | ||
139 | return rc; | ||
140 | } | ||
141 | |||
142 | return sclp_register(&sclp_ocf_event); | ||
143 | } | ||
144 | |||
145 | device_initcall(ocf_init); | ||
diff --git a/drivers/s390/char/sclp_sdias.c b/drivers/s390/char/sclp_sdias.c index 6a1c58dc61a7..fa733ecd3d70 100644 --- a/drivers/s390/char/sclp_sdias.c +++ b/drivers/s390/char/sclp_sdias.c | |||
@@ -69,9 +69,6 @@ static DEFINE_MUTEX(sdias_mutex); | |||
69 | 69 | ||
70 | static void sdias_callback(struct sclp_req *request, void *data) | 70 | static void sdias_callback(struct sclp_req *request, void *data) |
71 | { | 71 | { |
72 | struct sdias_sccb *cbsccb; | ||
73 | |||
74 | cbsccb = (struct sdias_sccb *) request->sccb; | ||
75 | sclp_req_done = 1; | 72 | sclp_req_done = 1; |
76 | wake_up(&sdias_wq); /* Inform caller, that request is complete */ | 73 | wake_up(&sdias_wq); /* Inform caller, that request is complete */ |
77 | TRACE("callback done\n"); | 74 | TRACE("callback done\n"); |
diff --git a/drivers/s390/char/sclp_tty.c b/drivers/s390/char/sclp_tty.c index 8258d590505f..a879c139926a 100644 --- a/drivers/s390/char/sclp_tty.c +++ b/drivers/s390/char/sclp_tty.c | |||
@@ -408,118 +408,72 @@ static int sclp_switch_cases(unsigned char *buf, int count) | |||
408 | return op - buf; | 408 | return op - buf; |
409 | } | 409 | } |
410 | 410 | ||
411 | static void | 411 | static void sclp_get_input(struct gds_subvector *sv) |
412 | sclp_get_input(unsigned char *start, unsigned char *end) | ||
413 | { | 412 | { |
413 | unsigned char *str; | ||
414 | int count; | 414 | int count; |
415 | 415 | ||
416 | count = end - start; | 416 | str = (unsigned char *) (sv + 1); |
417 | count = sv->length - sizeof(*sv); | ||
417 | if (sclp_tty_tolower) | 418 | if (sclp_tty_tolower) |
418 | EBC_TOLOWER(start, count); | 419 | EBC_TOLOWER(str, count); |
419 | count = sclp_switch_cases(start, count); | 420 | count = sclp_switch_cases(str, count); |
420 | /* convert EBCDIC to ASCII (modify original input in SCCB) */ | 421 | /* convert EBCDIC to ASCII (modify original input in SCCB) */ |
421 | sclp_ebcasc_str(start, count); | 422 | sclp_ebcasc_str(str, count); |
422 | 423 | ||
423 | /* transfer input to high level driver */ | 424 | /* transfer input to high level driver */ |
424 | sclp_tty_input(start, count); | 425 | sclp_tty_input(str, count); |
425 | } | ||
426 | |||
427 | static inline struct gds_vector * | ||
428 | find_gds_vector(struct gds_vector *start, struct gds_vector *end, u16 id) | ||
429 | { | ||
430 | struct gds_vector *vec; | ||
431 | |||
432 | for (vec = start; vec < end; vec = (void *) vec + vec->length) | ||
433 | if (vec->gds_id == id) | ||
434 | return vec; | ||
435 | return NULL; | ||
436 | } | 426 | } |
437 | 427 | ||
438 | static inline struct gds_subvector * | 428 | static inline void sclp_eval_selfdeftextmsg(struct gds_subvector *sv) |
439 | find_gds_subvector(struct gds_subvector *start, | ||
440 | struct gds_subvector *end, u8 key) | ||
441 | { | 429 | { |
442 | struct gds_subvector *subvec; | 430 | void *end; |
443 | 431 | ||
444 | for (subvec = start; subvec < end; | 432 | end = (void *) sv + sv->length; |
445 | subvec = (void *) subvec + subvec->length) | 433 | for (sv = sv + 1; (void *) sv < end; sv = (void *) sv + sv->length) |
446 | if (subvec->key == key) | 434 | if (sv->key == 0x30) |
447 | return subvec; | 435 | sclp_get_input(sv); |
448 | return NULL; | ||
449 | } | 436 | } |
450 | 437 | ||
451 | static inline void | 438 | static inline void sclp_eval_textcmd(struct gds_vector *v) |
452 | sclp_eval_selfdeftextmsg(struct gds_subvector *start, | ||
453 | struct gds_subvector *end) | ||
454 | { | 439 | { |
455 | struct gds_subvector *subvec; | 440 | struct gds_subvector *sv; |
456 | 441 | void *end; | |
457 | subvec = start; | ||
458 | while (subvec < end) { | ||
459 | subvec = find_gds_subvector(subvec, end, 0x30); | ||
460 | if (!subvec) | ||
461 | break; | ||
462 | sclp_get_input((unsigned char *)(subvec + 1), | ||
463 | (unsigned char *) subvec + subvec->length); | ||
464 | subvec = (void *) subvec + subvec->length; | ||
465 | } | ||
466 | } | ||
467 | 442 | ||
468 | static inline void | 443 | end = (void *) v + v->length; |
469 | sclp_eval_textcmd(struct gds_subvector *start, | 444 | for (sv = (struct gds_subvector *) (v + 1); |
470 | struct gds_subvector *end) | 445 | (void *) sv < end; sv = (void *) sv + sv->length) |
471 | { | 446 | if (sv->key == GDS_KEY_SELFDEFTEXTMSG) |
472 | struct gds_subvector *subvec; | 447 | sclp_eval_selfdeftextmsg(sv); |
473 | 448 | ||
474 | subvec = start; | ||
475 | while (subvec < end) { | ||
476 | subvec = find_gds_subvector(subvec, end, | ||
477 | GDS_KEY_SELFDEFTEXTMSG); | ||
478 | if (!subvec) | ||
479 | break; | ||
480 | sclp_eval_selfdeftextmsg((struct gds_subvector *)(subvec + 1), | ||
481 | (void *)subvec + subvec->length); | ||
482 | subvec = (void *) subvec + subvec->length; | ||
483 | } | ||
484 | } | 449 | } |
485 | 450 | ||
486 | static inline void | 451 | static inline void sclp_eval_cpmsu(struct gds_vector *v) |
487 | sclp_eval_cpmsu(struct gds_vector *start, struct gds_vector *end) | ||
488 | { | 452 | { |
489 | struct gds_vector *vec; | 453 | void *end; |
490 | 454 | ||
491 | vec = start; | 455 | end = (void *) v + v->length; |
492 | while (vec < end) { | 456 | for (v = v + 1; (void *) v < end; v = (void *) v + v->length) |
493 | vec = find_gds_vector(vec, end, GDS_ID_TEXTCMD); | 457 | if (v->gds_id == GDS_ID_TEXTCMD) |
494 | if (!vec) | 458 | sclp_eval_textcmd(v); |
495 | break; | ||
496 | sclp_eval_textcmd((struct gds_subvector *)(vec + 1), | ||
497 | (void *) vec + vec->length); | ||
498 | vec = (void *) vec + vec->length; | ||
499 | } | ||
500 | } | 459 | } |
501 | 460 | ||
502 | 461 | ||
503 | static inline void | 462 | static inline void sclp_eval_mdsmu(struct gds_vector *v) |
504 | sclp_eval_mdsmu(struct gds_vector *start, void *end) | ||
505 | { | 463 | { |
506 | struct gds_vector *vec; | 464 | v = sclp_find_gds_vector(v + 1, (void *) v + v->length, GDS_ID_CPMSU); |
507 | 465 | if (v) | |
508 | vec = find_gds_vector(start, end, GDS_ID_CPMSU); | 466 | sclp_eval_cpmsu(v); |
509 | if (vec) | ||
510 | sclp_eval_cpmsu(vec + 1, (void *) vec + vec->length); | ||
511 | } | 467 | } |
512 | 468 | ||
513 | static void | 469 | static void sclp_tty_receiver(struct evbuf_header *evbuf) |
514 | sclp_tty_receiver(struct evbuf_header *evbuf) | ||
515 | { | 470 | { |
516 | struct gds_vector *start, *end, *vec; | 471 | struct gds_vector *v; |
517 | 472 | ||
518 | start = (struct gds_vector *)(evbuf + 1); | 473 | v = sclp_find_gds_vector(evbuf + 1, (void *) evbuf + evbuf->length, |
519 | end = (void *) evbuf + evbuf->length; | 474 | GDS_ID_MDSMU); |
520 | vec = find_gds_vector(start, end, GDS_ID_MDSMU); | 475 | if (v) |
521 | if (vec) | 476 | sclp_eval_mdsmu(v); |
522 | sclp_eval_mdsmu(vec + 1, (void *) vec + vec->length); | ||
523 | } | 477 | } |
524 | 478 | ||
525 | static void | 479 | static void |
diff --git a/drivers/s390/char/tape_3590.c b/drivers/s390/char/tape_3590.c index b98dcbd16711..a7d570728882 100644 --- a/drivers/s390/char/tape_3590.c +++ b/drivers/s390/char/tape_3590.c | |||
@@ -796,10 +796,8 @@ static void tape_3590_med_state_set(struct tape_device *device, | |||
796 | static int | 796 | static int |
797 | tape_3590_done(struct tape_device *device, struct tape_request *request) | 797 | tape_3590_done(struct tape_device *device, struct tape_request *request) |
798 | { | 798 | { |
799 | struct tape_3590_disc_data *disc_data; | ||
800 | 799 | ||
801 | DBF_EVENT(6, "%s done\n", tape_op_verbose[request->op]); | 800 | DBF_EVENT(6, "%s done\n", tape_op_verbose[request->op]); |
802 | disc_data = device->discdata; | ||
803 | 801 | ||
804 | switch (request->op) { | 802 | switch (request->op) { |
805 | case TO_BSB: | 803 | case TO_BSB: |
@@ -1394,17 +1392,12 @@ tape_3590_print_era_msg(struct tape_device *device, struct irb *irb) | |||
1394 | static int tape_3590_crypt_error(struct tape_device *device, | 1392 | static int tape_3590_crypt_error(struct tape_device *device, |
1395 | struct tape_request *request, struct irb *irb) | 1393 | struct tape_request *request, struct irb *irb) |
1396 | { | 1394 | { |
1397 | u8 cu_rc, ekm_rc1; | 1395 | u8 cu_rc; |
1398 | u16 ekm_rc2; | 1396 | u16 ekm_rc2; |
1399 | u32 drv_rc; | ||
1400 | const char *bus_id; | ||
1401 | char *sense; | 1397 | char *sense; |
1402 | 1398 | ||
1403 | sense = ((struct tape_3590_sense *) irb->ecw)->fmt.data; | 1399 | sense = ((struct tape_3590_sense *) irb->ecw)->fmt.data; |
1404 | bus_id = dev_name(&device->cdev->dev); | ||
1405 | cu_rc = sense[0]; | 1400 | cu_rc = sense[0]; |
1406 | drv_rc = *((u32*) &sense[5]) & 0xffffff; | ||
1407 | ekm_rc1 = sense[9]; | ||
1408 | ekm_rc2 = *((u16*) &sense[10]); | 1401 | ekm_rc2 = *((u16*) &sense[10]); |
1409 | if ((cu_rc == 0) && (ekm_rc2 == 0xee31)) | 1402 | if ((cu_rc == 0) && (ekm_rc2 == 0xee31)) |
1410 | /* key not defined on EKM */ | 1403 | /* key not defined on EKM */ |
@@ -1429,7 +1422,6 @@ tape_3590_unit_check(struct tape_device *device, struct tape_request *request, | |||
1429 | struct irb *irb) | 1422 | struct irb *irb) |
1430 | { | 1423 | { |
1431 | struct tape_3590_sense *sense; | 1424 | struct tape_3590_sense *sense; |
1432 | int rc; | ||
1433 | 1425 | ||
1434 | #ifdef CONFIG_S390_TAPE_BLOCK | 1426 | #ifdef CONFIG_S390_TAPE_BLOCK |
1435 | if (request->op == TO_BLOCK) { | 1427 | if (request->op == TO_BLOCK) { |
@@ -1454,7 +1446,6 @@ tape_3590_unit_check(struct tape_device *device, struct tape_request *request, | |||
1454 | * - "break": basic error recovery is done | 1446 | * - "break": basic error recovery is done |
1455 | * - "goto out:": just print error message if available | 1447 | * - "goto out:": just print error message if available |
1456 | */ | 1448 | */ |
1457 | rc = -EIO; | ||
1458 | switch (sense->rc_rqc) { | 1449 | switch (sense->rc_rqc) { |
1459 | 1450 | ||
1460 | case 0x1110: | 1451 | case 0x1110: |
diff --git a/drivers/s390/char/tape_block.c b/drivers/s390/char/tape_block.c deleted file mode 100644 index 1b3924c2fffd..000000000000 --- a/drivers/s390/char/tape_block.c +++ /dev/null | |||
@@ -1,444 +0,0 @@ | |||
1 | /* | ||
2 | * drivers/s390/char/tape_block.c | ||
3 | * block device frontend for tape device driver | ||
4 | * | ||
5 | * S390 and zSeries version | ||
6 | * Copyright (C) 2001,2003 IBM Deutschland Entwicklung GmbH, IBM Corporation | ||
7 | * Author(s): Carsten Otte <cotte@de.ibm.com> | ||
8 | * Tuan Ngo-Anh <ngoanh@de.ibm.com> | ||
9 | * Martin Schwidefsky <schwidefsky@de.ibm.com> | ||
10 | * Stefan Bader <shbader@de.ibm.com> | ||
11 | */ | ||
12 | |||
13 | #define KMSG_COMPONENT "tape" | ||
14 | #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt | ||
15 | |||
16 | #include <linux/fs.h> | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/blkdev.h> | ||
19 | #include <linux/mutex.h> | ||
20 | #include <linux/interrupt.h> | ||
21 | #include <linux/buffer_head.h> | ||
22 | #include <linux/kernel.h> | ||
23 | |||
24 | #include <asm/debug.h> | ||
25 | |||
26 | #define TAPE_DBF_AREA tape_core_dbf | ||
27 | |||
28 | #include "tape.h" | ||
29 | |||
30 | #define TAPEBLOCK_MAX_SEC 100 | ||
31 | #define TAPEBLOCK_MIN_REQUEUE 3 | ||
32 | |||
33 | /* | ||
34 | * 2003/11/25 Stefan Bader <shbader@de.ibm.com> | ||
35 | * | ||
36 | * In 2.5/2.6 the block device request function is very likely to be called | ||
37 | * with disabled interrupts (e.g. generic_unplug_device). So the driver can't | ||
38 | * just call any function that tries to allocate CCW requests from that con- | ||
39 | * text since it might sleep. There are two choices to work around this: | ||
40 | * a) do not allocate with kmalloc but use its own memory pool | ||
41 | * b) take requests from the queue outside that context, knowing that | ||
42 | * allocation might sleep | ||
43 | */ | ||
44 | |||
45 | /* | ||
46 | * file operation structure for tape block frontend | ||
47 | */ | ||
48 | static DEFINE_MUTEX(tape_block_mutex); | ||
49 | static int tapeblock_open(struct block_device *, fmode_t); | ||
50 | static int tapeblock_release(struct gendisk *, fmode_t); | ||
51 | static unsigned int tapeblock_check_events(struct gendisk *, unsigned int); | ||
52 | static int tapeblock_revalidate_disk(struct gendisk *); | ||
53 | |||
54 | static const struct block_device_operations tapeblock_fops = { | ||
55 | .owner = THIS_MODULE, | ||
56 | .open = tapeblock_open, | ||
57 | .release = tapeblock_release, | ||
58 | .check_events = tapeblock_check_events, | ||
59 | .revalidate_disk = tapeblock_revalidate_disk, | ||
60 | }; | ||
61 | |||
62 | static int tapeblock_major = 0; | ||
63 | |||
64 | static void | ||
65 | tapeblock_trigger_requeue(struct tape_device *device) | ||
66 | { | ||
67 | /* Protect against rescheduling. */ | ||
68 | if (atomic_cmpxchg(&device->blk_data.requeue_scheduled, 0, 1) != 0) | ||
69 | return; | ||
70 | schedule_work(&device->blk_data.requeue_task); | ||
71 | } | ||
72 | |||
73 | /* | ||
74 | * Post finished request. | ||
75 | */ | ||
76 | static void | ||
77 | __tapeblock_end_request(struct tape_request *ccw_req, void *data) | ||
78 | { | ||
79 | struct tape_device *device; | ||
80 | struct request *req; | ||
81 | |||
82 | DBF_LH(6, "__tapeblock_end_request()\n"); | ||
83 | |||
84 | device = ccw_req->device; | ||
85 | req = (struct request *) data; | ||
86 | blk_end_request_all(req, (ccw_req->rc == 0) ? 0 : -EIO); | ||
87 | if (ccw_req->rc == 0) | ||
88 | /* Update position. */ | ||
89 | device->blk_data.block_position = | ||
90 | (blk_rq_pos(req) + blk_rq_sectors(req)) >> TAPEBLOCK_HSEC_S2B; | ||
91 | else | ||
92 | /* We lost the position information due to an error. */ | ||
93 | device->blk_data.block_position = -1; | ||
94 | device->discipline->free_bread(ccw_req); | ||
95 | if (!list_empty(&device->req_queue) || | ||
96 | blk_peek_request(device->blk_data.request_queue)) | ||
97 | tapeblock_trigger_requeue(device); | ||
98 | } | ||
99 | |||
100 | /* | ||
101 | * Feed the tape device CCW queue with requests supplied in a list. | ||
102 | */ | ||
103 | static int | ||
104 | tapeblock_start_request(struct tape_device *device, struct request *req) | ||
105 | { | ||
106 | struct tape_request * ccw_req; | ||
107 | int rc; | ||
108 | |||
109 | DBF_LH(6, "tapeblock_start_request(%p, %p)\n", device, req); | ||
110 | |||
111 | ccw_req = device->discipline->bread(device, req); | ||
112 | if (IS_ERR(ccw_req)) { | ||
113 | DBF_EVENT(1, "TBLOCK: bread failed\n"); | ||
114 | blk_end_request_all(req, -EIO); | ||
115 | return PTR_ERR(ccw_req); | ||
116 | } | ||
117 | ccw_req->callback = __tapeblock_end_request; | ||
118 | ccw_req->callback_data = (void *) req; | ||
119 | ccw_req->retries = TAPEBLOCK_RETRIES; | ||
120 | |||
121 | rc = tape_do_io_async(device, ccw_req); | ||
122 | if (rc) { | ||
123 | /* | ||
124 | * Start/enqueueing failed. No retries in | ||
125 | * this case. | ||
126 | */ | ||
127 | blk_end_request_all(req, -EIO); | ||
128 | device->discipline->free_bread(ccw_req); | ||
129 | } | ||
130 | |||
131 | return rc; | ||
132 | } | ||
133 | |||
134 | /* | ||
135 | * Move requests from the block device request queue to the tape device ccw | ||
136 | * queue. | ||
137 | */ | ||
138 | static void | ||
139 | tapeblock_requeue(struct work_struct *work) { | ||
140 | struct tape_blk_data * blkdat; | ||
141 | struct tape_device * device; | ||
142 | struct request_queue * queue; | ||
143 | int nr_queued; | ||
144 | struct request * req; | ||
145 | struct list_head * l; | ||
146 | int rc; | ||
147 | |||
148 | blkdat = container_of(work, struct tape_blk_data, requeue_task); | ||
149 | device = blkdat->device; | ||
150 | if (!device) | ||
151 | return; | ||
152 | |||
153 | spin_lock_irq(get_ccwdev_lock(device->cdev)); | ||
154 | queue = device->blk_data.request_queue; | ||
155 | |||
156 | /* Count number of requests on ccw queue. */ | ||
157 | nr_queued = 0; | ||
158 | list_for_each(l, &device->req_queue) | ||
159 | nr_queued++; | ||
160 | spin_unlock(get_ccwdev_lock(device->cdev)); | ||
161 | |||
162 | spin_lock_irq(&device->blk_data.request_queue_lock); | ||
163 | while ( | ||
164 | blk_peek_request(queue) && | ||
165 | nr_queued < TAPEBLOCK_MIN_REQUEUE | ||
166 | ) { | ||
167 | req = blk_fetch_request(queue); | ||
168 | if (rq_data_dir(req) == WRITE) { | ||
169 | DBF_EVENT(1, "TBLOCK: Rejecting write request\n"); | ||
170 | spin_unlock_irq(&device->blk_data.request_queue_lock); | ||
171 | blk_end_request_all(req, -EIO); | ||
172 | spin_lock_irq(&device->blk_data.request_queue_lock); | ||
173 | continue; | ||
174 | } | ||
175 | nr_queued++; | ||
176 | spin_unlock_irq(&device->blk_data.request_queue_lock); | ||
177 | rc = tapeblock_start_request(device, req); | ||
178 | spin_lock_irq(&device->blk_data.request_queue_lock); | ||
179 | } | ||
180 | spin_unlock_irq(&device->blk_data.request_queue_lock); | ||
181 | atomic_set(&device->blk_data.requeue_scheduled, 0); | ||
182 | } | ||
183 | |||
184 | /* | ||
185 | * Tape request queue function. Called from ll_rw_blk.c | ||
186 | */ | ||
187 | static void | ||
188 | tapeblock_request_fn(struct request_queue *queue) | ||
189 | { | ||
190 | struct tape_device *device; | ||
191 | |||
192 | device = (struct tape_device *) queue->queuedata; | ||
193 | DBF_LH(6, "tapeblock_request_fn(device=%p)\n", device); | ||
194 | BUG_ON(device == NULL); | ||
195 | tapeblock_trigger_requeue(device); | ||
196 | } | ||
197 | |||
198 | /* | ||
199 | * This function is called for every new tapedevice | ||
200 | */ | ||
201 | int | ||
202 | tapeblock_setup_device(struct tape_device * device) | ||
203 | { | ||
204 | struct tape_blk_data * blkdat; | ||
205 | struct gendisk * disk; | ||
206 | int rc; | ||
207 | |||
208 | blkdat = &device->blk_data; | ||
209 | blkdat->device = device; | ||
210 | spin_lock_init(&blkdat->request_queue_lock); | ||
211 | atomic_set(&blkdat->requeue_scheduled, 0); | ||
212 | |||
213 | blkdat->request_queue = blk_init_queue( | ||
214 | tapeblock_request_fn, | ||
215 | &blkdat->request_queue_lock | ||
216 | ); | ||
217 | if (!blkdat->request_queue) | ||
218 | return -ENOMEM; | ||
219 | |||
220 | rc = elevator_change(blkdat->request_queue, "noop"); | ||
221 | if (rc) | ||
222 | goto cleanup_queue; | ||
223 | |||
224 | blk_queue_logical_block_size(blkdat->request_queue, TAPEBLOCK_HSEC_SIZE); | ||
225 | blk_queue_max_hw_sectors(blkdat->request_queue, TAPEBLOCK_MAX_SEC); | ||
226 | blk_queue_max_segments(blkdat->request_queue, -1L); | ||
227 | blk_queue_max_segment_size(blkdat->request_queue, -1L); | ||
228 | blk_queue_segment_boundary(blkdat->request_queue, -1L); | ||
229 | |||
230 | disk = alloc_disk(1); | ||
231 | if (!disk) { | ||
232 | rc = -ENOMEM; | ||
233 | goto cleanup_queue; | ||
234 | } | ||
235 | |||
236 | disk->major = tapeblock_major; | ||
237 | disk->first_minor = device->first_minor; | ||
238 | disk->fops = &tapeblock_fops; | ||
239 | disk->private_data = tape_get_device(device); | ||
240 | disk->queue = blkdat->request_queue; | ||
241 | set_capacity(disk, 0); | ||
242 | sprintf(disk->disk_name, "btibm%d", | ||
243 | device->first_minor / TAPE_MINORS_PER_DEV); | ||
244 | |||
245 | blkdat->disk = disk; | ||
246 | blkdat->medium_changed = 1; | ||
247 | blkdat->request_queue->queuedata = tape_get_device(device); | ||
248 | |||
249 | add_disk(disk); | ||
250 | |||
251 | tape_get_device(device); | ||
252 | INIT_WORK(&blkdat->requeue_task, tapeblock_requeue); | ||
253 | |||
254 | return 0; | ||
255 | |||
256 | cleanup_queue: | ||
257 | blk_cleanup_queue(blkdat->request_queue); | ||
258 | blkdat->request_queue = NULL; | ||
259 | |||
260 | return rc; | ||
261 | } | ||
262 | |||
263 | void | ||
264 | tapeblock_cleanup_device(struct tape_device *device) | ||
265 | { | ||
266 | flush_work_sync(&device->blk_data.requeue_task); | ||
267 | tape_put_device(device); | ||
268 | |||
269 | if (!device->blk_data.disk) { | ||
270 | goto cleanup_queue; | ||
271 | } | ||
272 | |||
273 | del_gendisk(device->blk_data.disk); | ||
274 | device->blk_data.disk->private_data = NULL; | ||
275 | tape_put_device(device); | ||
276 | put_disk(device->blk_data.disk); | ||
277 | |||
278 | device->blk_data.disk = NULL; | ||
279 | cleanup_queue: | ||
280 | device->blk_data.request_queue->queuedata = NULL; | ||
281 | tape_put_device(device); | ||
282 | |||
283 | blk_cleanup_queue(device->blk_data.request_queue); | ||
284 | device->blk_data.request_queue = NULL; | ||
285 | } | ||
286 | |||
287 | /* | ||
288 | * Detect number of blocks of the tape. | ||
289 | * FIXME: can we extent this to detect the blocks size as well ? | ||
290 | */ | ||
291 | static int | ||
292 | tapeblock_revalidate_disk(struct gendisk *disk) | ||
293 | { | ||
294 | struct tape_device * device; | ||
295 | unsigned int nr_of_blks; | ||
296 | int rc; | ||
297 | |||
298 | device = (struct tape_device *) disk->private_data; | ||
299 | BUG_ON(!device); | ||
300 | |||
301 | if (!device->blk_data.medium_changed) | ||
302 | return 0; | ||
303 | |||
304 | rc = tape_mtop(device, MTFSFM, 1); | ||
305 | if (rc) | ||
306 | return rc; | ||
307 | |||
308 | rc = tape_mtop(device, MTTELL, 1); | ||
309 | if (rc < 0) | ||
310 | return rc; | ||
311 | |||
312 | pr_info("%s: Determining the size of the recorded area...\n", | ||
313 | dev_name(&device->cdev->dev)); | ||
314 | DBF_LH(3, "Image file ends at %d\n", rc); | ||
315 | nr_of_blks = rc; | ||
316 | |||
317 | /* This will fail for the first file. Catch the error by checking the | ||
318 | * position. */ | ||
319 | tape_mtop(device, MTBSF, 1); | ||
320 | |||
321 | rc = tape_mtop(device, MTTELL, 1); | ||
322 | if (rc < 0) | ||
323 | return rc; | ||
324 | |||
325 | if (rc > nr_of_blks) | ||
326 | return -EINVAL; | ||
327 | |||
328 | DBF_LH(3, "Image file starts at %d\n", rc); | ||
329 | device->bof = rc; | ||
330 | nr_of_blks -= rc; | ||
331 | |||
332 | pr_info("%s: The size of the recorded area is %i blocks\n", | ||
333 | dev_name(&device->cdev->dev), nr_of_blks); | ||
334 | set_capacity(device->blk_data.disk, | ||
335 | nr_of_blks*(TAPEBLOCK_HSEC_SIZE/512)); | ||
336 | |||
337 | device->blk_data.block_position = 0; | ||
338 | device->blk_data.medium_changed = 0; | ||
339 | return 0; | ||
340 | } | ||
341 | |||
342 | static unsigned int | ||
343 | tapeblock_check_events(struct gendisk *disk, unsigned int clearing) | ||
344 | { | ||
345 | struct tape_device *device; | ||
346 | |||
347 | device = (struct tape_device *) disk->private_data; | ||
348 | DBF_LH(6, "tapeblock_medium_changed(%p) = %d\n", | ||
349 | device, device->blk_data.medium_changed); | ||
350 | |||
351 | return device->blk_data.medium_changed ? DISK_EVENT_MEDIA_CHANGE : 0; | ||
352 | } | ||
353 | |||
354 | /* | ||
355 | * Block frontend tape device open function. | ||
356 | */ | ||
357 | static int | ||
358 | tapeblock_open(struct block_device *bdev, fmode_t mode) | ||
359 | { | ||
360 | struct gendisk * disk = bdev->bd_disk; | ||
361 | struct tape_device * device; | ||
362 | int rc; | ||
363 | |||
364 | mutex_lock(&tape_block_mutex); | ||
365 | device = tape_get_device(disk->private_data); | ||
366 | |||
367 | if (device->required_tapemarks) { | ||
368 | DBF_EVENT(2, "TBLOCK: missing tapemarks\n"); | ||
369 | pr_warning("%s: Opening the tape failed because of missing " | ||
370 | "end-of-file marks\n", dev_name(&device->cdev->dev)); | ||
371 | rc = -EPERM; | ||
372 | goto put_device; | ||
373 | } | ||
374 | |||
375 | rc = tape_open(device); | ||
376 | if (rc) | ||
377 | goto put_device; | ||
378 | |||
379 | rc = tapeblock_revalidate_disk(disk); | ||
380 | if (rc) | ||
381 | goto release; | ||
382 | |||
383 | /* | ||
384 | * Note: The reference to <device> is hold until the release function | ||
385 | * is called. | ||
386 | */ | ||
387 | tape_state_set(device, TS_BLKUSE); | ||
388 | mutex_unlock(&tape_block_mutex); | ||
389 | return 0; | ||
390 | |||
391 | release: | ||
392 | tape_release(device); | ||
393 | put_device: | ||
394 | tape_put_device(device); | ||
395 | mutex_unlock(&tape_block_mutex); | ||
396 | return rc; | ||
397 | } | ||
398 | |||
399 | /* | ||
400 | * Block frontend tape device release function. | ||
401 | * | ||
402 | * Note: One reference to the tape device was made by the open function. So | ||
403 | * we just get the pointer here and release the reference. | ||
404 | */ | ||
405 | static int | ||
406 | tapeblock_release(struct gendisk *disk, fmode_t mode) | ||
407 | { | ||
408 | struct tape_device *device = disk->private_data; | ||
409 | |||
410 | mutex_lock(&tape_block_mutex); | ||
411 | tape_state_set(device, TS_IN_USE); | ||
412 | tape_release(device); | ||
413 | tape_put_device(device); | ||
414 | mutex_unlock(&tape_block_mutex); | ||
415 | |||
416 | return 0; | ||
417 | } | ||
418 | |||
419 | /* | ||
420 | * Initialize block device frontend. | ||
421 | */ | ||
422 | int | ||
423 | tapeblock_init(void) | ||
424 | { | ||
425 | int rc; | ||
426 | |||
427 | /* Register the tape major number to the kernel */ | ||
428 | rc = register_blkdev(tapeblock_major, "tBLK"); | ||
429 | if (rc < 0) | ||
430 | return rc; | ||
431 | |||
432 | if (tapeblock_major == 0) | ||
433 | tapeblock_major = rc; | ||
434 | return 0; | ||
435 | } | ||
436 | |||
437 | /* | ||
438 | * Deregister major for block device frontend | ||
439 | */ | ||
440 | void | ||
441 | tapeblock_exit(void) | ||
442 | { | ||
443 | unregister_blkdev(tapeblock_major, "tBLK"); | ||
444 | } | ||
diff --git a/drivers/s390/char/tape_std.c b/drivers/s390/char/tape_std.c index 3c3f342149ec..e7650170274a 100644 --- a/drivers/s390/char/tape_std.c +++ b/drivers/s390/char/tape_std.c | |||
@@ -564,7 +564,6 @@ int | |||
564 | tape_std_mtreten(struct tape_device *device, int mt_count) | 564 | tape_std_mtreten(struct tape_device *device, int mt_count) |
565 | { | 565 | { |
566 | struct tape_request *request; | 566 | struct tape_request *request; |
567 | int rc; | ||
568 | 567 | ||
569 | request = tape_alloc_request(4, 0); | 568 | request = tape_alloc_request(4, 0); |
570 | if (IS_ERR(request)) | 569 | if (IS_ERR(request)) |
@@ -576,7 +575,7 @@ tape_std_mtreten(struct tape_device *device, int mt_count) | |||
576 | tape_ccw_cc(request->cpaddr + 2, NOP, 0, NULL); | 575 | tape_ccw_cc(request->cpaddr + 2, NOP, 0, NULL); |
577 | tape_ccw_end(request->cpaddr + 3, CCW_CMD_TIC, 0, request->cpaddr); | 576 | tape_ccw_end(request->cpaddr + 3, CCW_CMD_TIC, 0, request->cpaddr); |
578 | /* execute it, MTRETEN rc gets ignored */ | 577 | /* execute it, MTRETEN rc gets ignored */ |
579 | rc = tape_do_io_interruptible(device, request); | 578 | tape_do_io_interruptible(device, request); |
580 | tape_free_request(request); | 579 | tape_free_request(request); |
581 | return tape_mtop(device, MTREW, 1); | 580 | return tape_mtop(device, MTREW, 1); |
582 | } | 581 | } |
diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index 0689fcf23a11..75c3f1f8fd43 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c | |||
@@ -326,6 +326,36 @@ static void chsc_process_sei_res_acc(struct chsc_sei_area *sei_area) | |||
326 | s390_process_res_acc(&link); | 326 | s390_process_res_acc(&link); |
327 | } | 327 | } |
328 | 328 | ||
329 | static void chsc_process_sei_chp_avail(struct chsc_sei_area *sei_area) | ||
330 | { | ||
331 | struct channel_path *chp; | ||
332 | struct chp_id chpid; | ||
333 | u8 *data; | ||
334 | int num; | ||
335 | |||
336 | CIO_CRW_EVENT(4, "chsc: channel path availability information\n"); | ||
337 | if (sei_area->rs != 0) | ||
338 | return; | ||
339 | data = sei_area->ccdf; | ||
340 | chp_id_init(&chpid); | ||
341 | for (num = 0; num <= __MAX_CHPID; num++) { | ||
342 | if (!chp_test_bit(data, num)) | ||
343 | continue; | ||
344 | chpid.id = num; | ||
345 | |||
346 | CIO_CRW_EVENT(4, "Update information for channel path " | ||
347 | "%x.%02x\n", chpid.cssid, chpid.id); | ||
348 | chp = chpid_to_chp(chpid); | ||
349 | if (!chp) { | ||
350 | chp_new(chpid); | ||
351 | continue; | ||
352 | } | ||
353 | mutex_lock(&chp->lock); | ||
354 | chsc_determine_base_channel_path_desc(chpid, &chp->desc); | ||
355 | mutex_unlock(&chp->lock); | ||
356 | } | ||
357 | } | ||
358 | |||
329 | struct chp_config_data { | 359 | struct chp_config_data { |
330 | u8 map[32]; | 360 | u8 map[32]; |
331 | u8 op; | 361 | u8 op; |
@@ -376,9 +406,12 @@ static void chsc_process_sei(struct chsc_sei_area *sei_area) | |||
376 | case 1: /* link incident*/ | 406 | case 1: /* link incident*/ |
377 | chsc_process_sei_link_incident(sei_area); | 407 | chsc_process_sei_link_incident(sei_area); |
378 | break; | 408 | break; |
379 | case 2: /* i/o resource accessibiliy */ | 409 | case 2: /* i/o resource accessibility */ |
380 | chsc_process_sei_res_acc(sei_area); | 410 | chsc_process_sei_res_acc(sei_area); |
381 | break; | 411 | break; |
412 | case 7: /* channel-path-availability information */ | ||
413 | chsc_process_sei_chp_avail(sei_area); | ||
414 | break; | ||
382 | case 8: /* channel-path-configuration notification */ | 415 | case 8: /* channel-path-configuration notification */ |
383 | chsc_process_sei_chp_config(sei_area); | 416 | chsc_process_sei_chp_config(sei_area); |
384 | break; | 417 | break; |
diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c index 6084103672b5..52c233fa2b12 100644 --- a/drivers/s390/cio/device_fsm.c +++ b/drivers/s390/cio/device_fsm.c | |||
@@ -408,9 +408,10 @@ ccw_device_done(struct ccw_device *cdev, int state) | |||
408 | CIO_MSG_EVENT(0, "Disconnected device %04x on subchannel " | 408 | CIO_MSG_EVENT(0, "Disconnected device %04x on subchannel " |
409 | "%04x\n", cdev->private->dev_id.devno, | 409 | "%04x\n", cdev->private->dev_id.devno, |
410 | sch->schid.sch_no); | 410 | sch->schid.sch_no); |
411 | if (ccw_device_notify(cdev, CIO_NO_PATH) != NOTIFY_OK) | 411 | if (ccw_device_notify(cdev, CIO_NO_PATH) != NOTIFY_OK) { |
412 | cdev->private->state = DEV_STATE_NOT_OPER; | ||
412 | ccw_device_sched_todo(cdev, CDEV_TODO_UNREG); | 413 | ccw_device_sched_todo(cdev, CDEV_TODO_UNREG); |
413 | else | 414 | } else |
414 | ccw_device_set_disconnected(cdev); | 415 | ccw_device_set_disconnected(cdev); |
415 | cdev->private->flags.donotify = 0; | 416 | cdev->private->flags.donotify = 0; |
416 | break; | 417 | break; |
@@ -840,9 +841,6 @@ call_handler: | |||
840 | static void | 841 | static void |
841 | ccw_device_killing_irq(struct ccw_device *cdev, enum dev_event dev_event) | 842 | ccw_device_killing_irq(struct ccw_device *cdev, enum dev_event dev_event) |
842 | { | 843 | { |
843 | struct subchannel *sch; | ||
844 | |||
845 | sch = to_subchannel(cdev->dev.parent); | ||
846 | ccw_device_set_timeout(cdev, 0); | 844 | ccw_device_set_timeout(cdev, 0); |
847 | /* Start delayed path verification. */ | 845 | /* Start delayed path verification. */ |
848 | ccw_device_online_verify(cdev, 0); | 846 | ccw_device_online_verify(cdev, 0); |
diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c index 651976b54af8..f98698d5735e 100644 --- a/drivers/s390/cio/device_ops.c +++ b/drivers/s390/cio/device_ops.c | |||
@@ -418,12 +418,9 @@ int ccw_device_resume(struct ccw_device *cdev) | |||
418 | int | 418 | int |
419 | ccw_device_call_handler(struct ccw_device *cdev) | 419 | ccw_device_call_handler(struct ccw_device *cdev) |
420 | { | 420 | { |
421 | struct subchannel *sch; | ||
422 | unsigned int stctl; | 421 | unsigned int stctl; |
423 | int ending_status; | 422 | int ending_status; |
424 | 423 | ||
425 | sch = to_subchannel(cdev->dev.parent); | ||
426 | |||
427 | /* | 424 | /* |
428 | * we allow for the device action handler if . | 425 | * we allow for the device action handler if . |
429 | * - we received ending status | 426 | * - we received ending status |
diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index e8f267eb8887..55e8f721e38a 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c | |||
@@ -1446,7 +1446,7 @@ set: | |||
1446 | static int handle_outbound(struct qdio_q *q, unsigned int callflags, | 1446 | static int handle_outbound(struct qdio_q *q, unsigned int callflags, |
1447 | int bufnr, int count) | 1447 | int bufnr, int count) |
1448 | { | 1448 | { |
1449 | unsigned char state; | 1449 | unsigned char state = 0; |
1450 | int used, rc = 0; | 1450 | int used, rc = 0; |
1451 | 1451 | ||
1452 | qperf_inc(q, outbound_call); | 1452 | qperf_inc(q, outbound_call); |
diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index 67302b944ab3..16e4a25596e7 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c | |||
@@ -1183,8 +1183,12 @@ static void ap_scan_bus(struct work_struct *unused) | |||
1183 | INIT_LIST_HEAD(&ap_dev->list); | 1183 | INIT_LIST_HEAD(&ap_dev->list); |
1184 | setup_timer(&ap_dev->timeout, ap_request_timeout, | 1184 | setup_timer(&ap_dev->timeout, ap_request_timeout, |
1185 | (unsigned long) ap_dev); | 1185 | (unsigned long) ap_dev); |
1186 | if (device_type == 0) | 1186 | if (device_type == 0) { |
1187 | ap_probe_device_type(ap_dev); | 1187 | if (ap_probe_device_type(ap_dev)) { |
1188 | kfree(ap_dev); | ||
1189 | continue; | ||
1190 | } | ||
1191 | } | ||
1188 | else | 1192 | else |
1189 | ap_dev->device_type = device_type; | 1193 | ap_dev->device_type = device_type; |
1190 | 1194 | ||
diff --git a/include/asm-generic/pgtable.h b/include/asm-generic/pgtable.h index b4bfe338ea0e..e9b8e5926bef 100644 --- a/include/asm-generic/pgtable.h +++ b/include/asm-generic/pgtable.h | |||
@@ -184,22 +184,18 @@ static inline int pmd_same(pmd_t pmd_a, pmd_t pmd_b) | |||
184 | #endif /* CONFIG_TRANSPARENT_HUGEPAGE */ | 184 | #endif /* CONFIG_TRANSPARENT_HUGEPAGE */ |
185 | #endif | 185 | #endif |
186 | 186 | ||
187 | #ifndef __HAVE_ARCH_PAGE_TEST_DIRTY | 187 | #ifndef __HAVE_ARCH_PAGE_TEST_AND_CLEAR_DIRTY |
188 | #define page_test_dirty(page) (0) | 188 | #define page_test_and_clear_dirty(pfn, mapped) (0) |
189 | #endif | 189 | #endif |
190 | 190 | ||
191 | #ifndef __HAVE_ARCH_PAGE_CLEAR_DIRTY | 191 | #ifndef __HAVE_ARCH_PAGE_TEST_AND_CLEAR_DIRTY |
192 | #define page_clear_dirty(page, mapped) do { } while (0) | ||
193 | #endif | ||
194 | |||
195 | #ifndef __HAVE_ARCH_PAGE_TEST_DIRTY | ||
196 | #define pte_maybe_dirty(pte) pte_dirty(pte) | 192 | #define pte_maybe_dirty(pte) pte_dirty(pte) |
197 | #else | 193 | #else |
198 | #define pte_maybe_dirty(pte) (1) | 194 | #define pte_maybe_dirty(pte) (1) |
199 | #endif | 195 | #endif |
200 | 196 | ||
201 | #ifndef __HAVE_ARCH_PAGE_TEST_AND_CLEAR_YOUNG | 197 | #ifndef __HAVE_ARCH_PAGE_TEST_AND_CLEAR_YOUNG |
202 | #define page_test_and_clear_young(page) (0) | 198 | #define page_test_and_clear_young(pfn) (0) |
203 | #endif | 199 | #endif |
204 | 200 | ||
205 | #ifndef __HAVE_ARCH_PGD_OFFSET_GATE | 201 | #ifndef __HAVE_ARCH_PGD_OFFSET_GATE |
diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h index 811183de1ef5..79a6700b7162 100644 --- a/include/linux/page-flags.h +++ b/include/linux/page-flags.h | |||
@@ -308,7 +308,7 @@ static inline void SetPageUptodate(struct page *page) | |||
308 | { | 308 | { |
309 | #ifdef CONFIG_S390 | 309 | #ifdef CONFIG_S390 |
310 | if (!test_and_set_bit(PG_uptodate, &page->flags)) | 310 | if (!test_and_set_bit(PG_uptodate, &page->flags)) |
311 | page_clear_dirty(page, 0); | 311 | page_set_storage_key(page_to_pfn(page), PAGE_DEFAULT_KEY, 0); |
312 | #else | 312 | #else |
313 | /* | 313 | /* |
314 | * Memory barrier must be issued before setting the PG_uptodate bit, | 314 | * Memory barrier must be issued before setting the PG_uptodate bit, |
@@ -719,7 +719,7 @@ int page_referenced(struct page *page, | |||
719 | unlock_page(page); | 719 | unlock_page(page); |
720 | } | 720 | } |
721 | out: | 721 | out: |
722 | if (page_test_and_clear_young(page)) | 722 | if (page_test_and_clear_young(page_to_pfn(page))) |
723 | referenced++; | 723 | referenced++; |
724 | 724 | ||
725 | return referenced; | 725 | return referenced; |
@@ -785,10 +785,8 @@ int page_mkclean(struct page *page) | |||
785 | struct address_space *mapping = page_mapping(page); | 785 | struct address_space *mapping = page_mapping(page); |
786 | if (mapping) { | 786 | if (mapping) { |
787 | ret = page_mkclean_file(mapping, page); | 787 | ret = page_mkclean_file(mapping, page); |
788 | if (page_test_dirty(page)) { | 788 | if (page_test_and_clear_dirty(page_to_pfn(page), 1)) |
789 | page_clear_dirty(page, 1); | ||
790 | ret = 1; | 789 | ret = 1; |
791 | } | ||
792 | } | 790 | } |
793 | } | 791 | } |
794 | 792 | ||
@@ -981,10 +979,9 @@ void page_remove_rmap(struct page *page) | |||
981 | * not if it's in swapcache - there might be another pte slot | 979 | * not if it's in swapcache - there might be another pte slot |
982 | * containing the swap entry, but page not yet written to swap. | 980 | * containing the swap entry, but page not yet written to swap. |
983 | */ | 981 | */ |
984 | if ((!PageAnon(page) || PageSwapCache(page)) && page_test_dirty(page)) { | 982 | if ((!PageAnon(page) || PageSwapCache(page)) && |
985 | page_clear_dirty(page, 1); | 983 | page_test_and_clear_dirty(page_to_pfn(page), 1)) |
986 | set_page_dirty(page); | 984 | set_page_dirty(page); |
987 | } | ||
988 | /* | 985 | /* |
989 | * Hugepages are not counted in NR_ANON_PAGES nor NR_FILE_MAPPED | 986 | * Hugepages are not counted in NR_ANON_PAGES nor NR_FILE_MAPPED |
990 | * and not charged by memcg for now. | 987 | * and not charged by memcg for now. |