blob: d382629a01728de29a1ceb396a637c26ed4f94c1 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Hans-Joachim Picht155af2f2009-06-16 10:30:52 +02002 * Copyright IBM Corp. 1999, 2009
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 *
Hans-Joachim Picht155af2f2009-06-16 10:30:52 +02004 * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 */
6
7#ifndef __ASM_SYSTEM_H
8#define __ASM_SYSTEM_H
9
Linus Torvalds1da177e2005-04-16 15:20:36 -070010#include <linux/kernel.h>
Heiko Carstens320c04c2008-12-25 13:38:40 +010011#include <linux/errno.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070012#include <asm/types.h>
13#include <asm/ptrace.h>
14#include <asm/setup.h>
Heiko Carstens77fa2242005-06-25 14:55:30 -070015#include <asm/processor.h>
Heiko Carstens484875b2008-04-30 13:38:43 +020016#include <asm/lowcore.h>
Heiko Carstensa2c9dbe2011-03-23 10:16:05 +010017#include <asm/cmpxchg.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070018
19#ifdef __KERNEL__
20
21struct task_struct;
22
23extern struct task_struct *__switch_to(void *, void *);
Martin Schwidefsky5e9a2692011-01-05 12:48:10 +010024extern void update_per_regs(struct task_struct *task);
Linus Torvalds1da177e2005-04-16 15:20:36 -070025
Linus Torvalds1da177e2005-04-16 15:20:36 -070026static inline void save_fp_regs(s390_fp_regs *fpregs)
27{
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +020028 asm volatile(
Martin Schwidefsky987bcda2010-02-26 22:37:31 +010029 " std 0,%O0+8(%R0)\n"
30 " std 2,%O0+24(%R0)\n"
31 " std 4,%O0+40(%R0)\n"
32 " std 6,%O0+56(%R0)"
33 : "=Q" (*fpregs) : "Q" (*fpregs));
Linus Torvalds1da177e2005-04-16 15:20:36 -070034 if (!MACHINE_HAS_IEEE)
35 return;
36 asm volatile(
Martin Schwidefsky987bcda2010-02-26 22:37:31 +010037 " stfpc %0\n"
38 " std 1,%O0+16(%R0)\n"
39 " std 3,%O0+32(%R0)\n"
40 " std 5,%O0+48(%R0)\n"
41 " std 7,%O0+64(%R0)\n"
42 " std 8,%O0+72(%R0)\n"
43 " std 9,%O0+80(%R0)\n"
44 " std 10,%O0+88(%R0)\n"
45 " std 11,%O0+96(%R0)\n"
46 " std 12,%O0+104(%R0)\n"
47 " std 13,%O0+112(%R0)\n"
48 " std 14,%O0+120(%R0)\n"
49 " std 15,%O0+128(%R0)\n"
50 : "=Q" (*fpregs) : "Q" (*fpregs));
Linus Torvalds1da177e2005-04-16 15:20:36 -070051}
52
53static inline void restore_fp_regs(s390_fp_regs *fpregs)
54{
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +020055 asm volatile(
Martin Schwidefsky987bcda2010-02-26 22:37:31 +010056 " ld 0,%O0+8(%R0)\n"
57 " ld 2,%O0+24(%R0)\n"
58 " ld 4,%O0+40(%R0)\n"
59 " ld 6,%O0+56(%R0)"
60 : : "Q" (*fpregs));
Linus Torvalds1da177e2005-04-16 15:20:36 -070061 if (!MACHINE_HAS_IEEE)
62 return;
63 asm volatile(
Martin Schwidefsky987bcda2010-02-26 22:37:31 +010064 " lfpc %0\n"
65 " ld 1,%O0+16(%R0)\n"
66 " ld 3,%O0+32(%R0)\n"
67 " ld 5,%O0+48(%R0)\n"
68 " ld 7,%O0+64(%R0)\n"
69 " ld 8,%O0+72(%R0)\n"
70 " ld 9,%O0+80(%R0)\n"
71 " ld 10,%O0+88(%R0)\n"
72 " ld 11,%O0+96(%R0)\n"
73 " ld 12,%O0+104(%R0)\n"
74 " ld 13,%O0+112(%R0)\n"
75 " ld 14,%O0+120(%R0)\n"
76 " ld 15,%O0+128(%R0)\n"
77 : : "Q" (*fpregs));
Linus Torvalds1da177e2005-04-16 15:20:36 -070078}
79
80static inline void save_access_regs(unsigned int *acrs)
81{
Martin Schwidefsky987bcda2010-02-26 22:37:31 +010082 asm volatile("stam 0,15,%0" : "=Q" (*acrs));
Linus Torvalds1da177e2005-04-16 15:20:36 -070083}
84
85static inline void restore_access_regs(unsigned int *acrs)
86{
Martin Schwidefsky987bcda2010-02-26 22:37:31 +010087 asm volatile("lam 0,15,%0" : : "Q" (*acrs));
Linus Torvalds1da177e2005-04-16 15:20:36 -070088}
89
Heiko Carstensfdb6d072010-10-25 16:10:18 +020090#define switch_to(prev,next,last) do { \
Heiko Carstensfdb6d072010-10-25 16:10:18 +020091 if (prev->mm) { \
92 save_fp_regs(&prev->thread.fp_regs); \
93 save_access_regs(&prev->thread.acrs[0]); \
94 } \
95 if (next->mm) { \
96 restore_fp_regs(&next->thread.fp_regs); \
97 restore_access_regs(&next->thread.acrs[0]); \
Martin Schwidefsky5e9a2692011-01-05 12:48:10 +010098 update_per_regs(next); \
Heiko Carstensfdb6d072010-10-25 16:10:18 +020099 } \
100 prev = __switch_to(prev,next); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101} while (0)
102
Martin Schwidefskyaa5e97c2008-12-31 15:11:39 +0100103extern void account_vtime(struct task_struct *, struct task_struct *);
Martin Schwidefsky1f1c12a2006-01-14 13:21:03 -0800104extern void account_tick_vtime(struct task_struct *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105
Heiko Carstens29b08d22006-12-04 15:40:40 +0100106#ifdef CONFIG_PFAULT
Heiko Carstens29b08d22006-12-04 15:40:40 +0100107extern int pfault_init(void);
108extern void pfault_fini(void);
109#else /* CONFIG_PFAULT */
Heiko Carstens29b08d22006-12-04 15:40:40 +0100110#define pfault_init() ({-1;})
111#define pfault_fini() do { } while (0)
112#endif /* CONFIG_PFAULT */
113
Martin Schwidefsky45e576b2008-05-07 09:22:59 +0200114extern void cmma_init(void);
Michael Holzheu92fe3132010-03-24 11:49:50 +0100115extern int memcpy_real(void *, void *, size_t);
Martin Schwidefsky45e576b2008-05-07 09:22:59 +0200116
Heiko Carstens5ee24d952005-06-30 02:58:48 -0700117#define finish_arch_switch(prev) do { \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118 set_fs(current->thread.mm_segment); \
Martin Schwidefskyaa5e97c2008-12-31 15:11:39 +0100119 account_vtime(prev, current); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120} while (0)
121
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200122#define nop() asm volatile("nop")
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124/*
125 * Force strict CPU ordering.
126 * And yes, this is required on UP too when we're talking
127 * to devices.
128 *
129 * This is very similar to the ppc eieio/sync instruction in that is
130 * does a checkpoint syncronisation & makes sure that
131 * all memory ops have completed wrt other CPU's ( see 7-15 POP DJB ).
132 */
133
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200134#define eieio() asm volatile("bcr 15,0" : : : "memory")
135#define SYNC_OTHER_CORES(x) eieio()
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136#define mb() eieio()
137#define rmb() eieio()
138#define wmb() eieio()
139#define read_barrier_depends() do { } while(0)
140#define smp_mb() mb()
141#define smp_rmb() rmb()
142#define smp_wmb() wmb()
143#define smp_read_barrier_depends() read_barrier_depends()
144#define smp_mb__before_clear_bit() smp_mb()
145#define smp_mb__after_clear_bit() smp_mb()
146
147
148#define set_mb(var, value) do { var = value; mb(); } while (0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150#ifdef __s390x__
151
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200152#define __ctl_load(array, low, high) ({ \
153 typedef struct { char _[sizeof(array)]; } addrtype; \
154 asm volatile( \
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100155 " lctlg %1,%2,%0\n" \
156 : : "Q" (*(addrtype *)(&array)), \
157 "i" (low), "i" (high)); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158 })
159
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200160#define __ctl_store(array, low, high) ({ \
161 typedef struct { char _[sizeof(array)]; } addrtype; \
162 asm volatile( \
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100163 " stctg %1,%2,%0\n" \
164 : "=Q" (*(addrtype *)(&array)) \
165 : "i" (low), "i" (high)); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166 })
167
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168#else /* __s390x__ */
169
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200170#define __ctl_load(array, low, high) ({ \
171 typedef struct { char _[sizeof(array)]; } addrtype; \
172 asm volatile( \
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100173 " lctl %1,%2,%0\n" \
174 : : "Q" (*(addrtype *)(&array)), \
175 "i" (low), "i" (high)); \
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200176})
177
178#define __ctl_store(array, low, high) ({ \
179 typedef struct { char _[sizeof(array)]; } addrtype; \
180 asm volatile( \
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100181 " stctl %1,%2,%0\n" \
182 : "=Q" (*(addrtype *)(&array)) \
183 : "i" (low), "i" (high)); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184 })
185
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186#endif /* __s390x__ */
187
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200188#define __ctl_set_bit(cr, bit) ({ \
189 unsigned long __dummy; \
190 __ctl_store(__dummy, cr, cr); \
191 __dummy |= 1UL << (bit); \
192 __ctl_load(__dummy, cr, cr); \
193})
194
195#define __ctl_clear_bit(cr, bit) ({ \
196 unsigned long __dummy; \
197 __ctl_store(__dummy, cr, cr); \
198 __dummy &= ~(1UL << (bit)); \
199 __ctl_load(__dummy, cr, cr); \
200})
201
Heiko Carstens77fa2242005-06-25 14:55:30 -0700202/*
203 * Use to set psw mask except for the first byte which
204 * won't be changed by this function.
205 */
206static inline void
207__set_psw_mask(unsigned long mask)
208{
David Howellsdf9ee292010-10-07 14:08:55 +0100209 __load_psw_mask(mask | (arch_local_save_flags() & ~(-1UL >> 8)));
Heiko Carstens77fa2242005-06-25 14:55:30 -0700210}
211
Gerald Schaeferc1821c22007-02-05 21:18:17 +0100212#define local_mcck_enable() __set_psw_mask(psw_kernel_bits)
213#define local_mcck_disable() __set_psw_mask(psw_kernel_bits & ~PSW_MASK_MCHECK)
Heiko Carstens77fa2242005-06-25 14:55:30 -0700214
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215#ifdef CONFIG_SMP
216
217extern void smp_ctl_set_bit(int cr, int bit);
218extern void smp_ctl_clear_bit(int cr, int bit);
219#define ctl_set_bit(cr, bit) smp_ctl_set_bit(cr, bit)
220#define ctl_clear_bit(cr, bit) smp_ctl_clear_bit(cr, bit)
221
222#else
223
224#define ctl_set_bit(cr, bit) __ctl_set_bit(cr, bit)
225#define ctl_clear_bit(cr, bit) __ctl_clear_bit(cr, bit)
226
227#endif /* CONFIG_SMP */
228
Martin Schwidefsky14375bc2010-10-25 16:10:51 +0200229#define MAX_FACILITY_BIT (256*8) /* stfle_fac_list has 256 bytes */
Heiko Carstens484875b2008-04-30 13:38:43 +0200230
Martin Schwidefsky14375bc2010-10-25 16:10:51 +0200231/*
232 * The test_facility function uses the bit odering where the MSB is bit 0.
233 * That makes it easier to query facility bits with the bit number as
234 * documented in the Principles of Operation.
235 */
236static inline int test_facility(unsigned long nr)
Heiko Carstens320c04c2008-12-25 13:38:40 +0100237{
Martin Schwidefsky14375bc2010-10-25 16:10:51 +0200238 unsigned char *ptr;
Heiko Carstens320c04c2008-12-25 13:38:40 +0100239
Martin Schwidefsky14375bc2010-10-25 16:10:51 +0200240 if (nr >= MAX_FACILITY_BIT)
241 return 0;
242 ptr = (unsigned char *) &S390_lowcore.stfle_fac_list + (nr >> 3);
243 return (*ptr & (0x80 >> (nr & 7))) != 0;
Heiko Carstens320c04c2008-12-25 13:38:40 +0100244}
245
Heiko Carstens2e5061e2008-04-30 13:38:45 +0200246static inline unsigned short stap(void)
247{
248 unsigned short cpu_address;
249
250 asm volatile("stap %0" : "=m" (cpu_address));
251 return cpu_address;
252}
253
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254extern void (*_machine_restart)(char *command);
255extern void (*_machine_halt)(void);
256extern void (*_machine_power_off)(void);
257
Heiko Carstens9887a1f2011-01-12 09:55:28 +0100258extern unsigned long arch_align_stack(unsigned long sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259
Hans-Joachim Picht155af2f2009-06-16 10:30:52 +0200260static inline int tprot(unsigned long addr)
261{
262 int rc = -EFAULT;
263
264 asm volatile(
265 " tprot 0(%1),0\n"
266 "0: ipm %0\n"
267 " srl %0,28\n"
268 "1:\n"
269 EX_TABLE(0b,1b)
270 : "+d" (rc) : "a" (addr) : "cc");
271 return rc;
272}
273
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274#endif /* __KERNEL__ */
275
276#endif