blob: 6582f69f23899b4989c05b9aacf0fb6de4bed4c2 [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);
Michael Holzheu7dd6b332011-08-03 16:44:19 +0200116extern void copy_to_absolute_zero(void *dest, void *src, size_t count);
Martin Schwidefsky45e576b2008-05-07 09:22:59 +0200117
Heiko Carstens5ee24d952005-06-30 02:58:48 -0700118#define finish_arch_switch(prev) do { \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119 set_fs(current->thread.mm_segment); \
Martin Schwidefskyaa5e97c2008-12-31 15:11:39 +0100120 account_vtime(prev, current); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121} while (0)
122
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200123#define nop() asm volatile("nop")
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125/*
126 * Force strict CPU ordering.
127 * And yes, this is required on UP too when we're talking
128 * to devices.
129 *
130 * This is very similar to the ppc eieio/sync instruction in that is
131 * does a checkpoint syncronisation & makes sure that
132 * all memory ops have completed wrt other CPU's ( see 7-15 POP DJB ).
133 */
134
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200135#define eieio() asm volatile("bcr 15,0" : : : "memory")
136#define SYNC_OTHER_CORES(x) eieio()
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137#define mb() eieio()
138#define rmb() eieio()
139#define wmb() eieio()
140#define read_barrier_depends() do { } while(0)
141#define smp_mb() mb()
142#define smp_rmb() rmb()
143#define smp_wmb() wmb()
144#define smp_read_barrier_depends() read_barrier_depends()
145#define smp_mb__before_clear_bit() smp_mb()
146#define smp_mb__after_clear_bit() smp_mb()
147
148
149#define set_mb(var, value) do { var = value; mb(); } while (0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151#ifdef __s390x__
152
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200153#define __ctl_load(array, low, high) ({ \
154 typedef struct { char _[sizeof(array)]; } addrtype; \
155 asm volatile( \
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100156 " lctlg %1,%2,%0\n" \
157 : : "Q" (*(addrtype *)(&array)), \
158 "i" (low), "i" (high)); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159 })
160
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200161#define __ctl_store(array, low, high) ({ \
162 typedef struct { char _[sizeof(array)]; } addrtype; \
163 asm volatile( \
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100164 " stctg %1,%2,%0\n" \
165 : "=Q" (*(addrtype *)(&array)) \
166 : "i" (low), "i" (high)); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167 })
168
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169#else /* __s390x__ */
170
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200171#define __ctl_load(array, low, high) ({ \
172 typedef struct { char _[sizeof(array)]; } addrtype; \
173 asm volatile( \
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100174 " lctl %1,%2,%0\n" \
175 : : "Q" (*(addrtype *)(&array)), \
176 "i" (low), "i" (high)); \
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200177})
178
179#define __ctl_store(array, low, high) ({ \
180 typedef struct { char _[sizeof(array)]; } addrtype; \
181 asm volatile( \
Martin Schwidefsky987bcda2010-02-26 22:37:31 +0100182 " stctl %1,%2,%0\n" \
183 : "=Q" (*(addrtype *)(&array)) \
184 : "i" (low), "i" (high)); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185 })
186
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187#endif /* __s390x__ */
188
Martin Schwidefsky94c12cc2006-09-28 16:56:43 +0200189#define __ctl_set_bit(cr, bit) ({ \
190 unsigned long __dummy; \
191 __ctl_store(__dummy, cr, cr); \
192 __dummy |= 1UL << (bit); \
193 __ctl_load(__dummy, cr, cr); \
194})
195
196#define __ctl_clear_bit(cr, bit) ({ \
197 unsigned long __dummy; \
198 __ctl_store(__dummy, cr, cr); \
199 __dummy &= ~(1UL << (bit)); \
200 __ctl_load(__dummy, cr, cr); \
201})
202
Heiko Carstens77fa2242005-06-25 14:55:30 -0700203/*
204 * Use to set psw mask except for the first byte which
205 * won't be changed by this function.
206 */
207static inline void
208__set_psw_mask(unsigned long mask)
209{
David Howellsdf9ee292010-10-07 14:08:55 +0100210 __load_psw_mask(mask | (arch_local_save_flags() & ~(-1UL >> 8)));
Heiko Carstens77fa2242005-06-25 14:55:30 -0700211}
212
Gerald Schaeferc1821c22007-02-05 21:18:17 +0100213#define local_mcck_enable() __set_psw_mask(psw_kernel_bits)
214#define local_mcck_disable() __set_psw_mask(psw_kernel_bits & ~PSW_MASK_MCHECK)
Heiko Carstens77fa2242005-06-25 14:55:30 -0700215
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216#ifdef CONFIG_SMP
217
218extern void smp_ctl_set_bit(int cr, int bit);
219extern void smp_ctl_clear_bit(int cr, int bit);
220#define ctl_set_bit(cr, bit) smp_ctl_set_bit(cr, bit)
221#define ctl_clear_bit(cr, bit) smp_ctl_clear_bit(cr, bit)
222
223#else
224
225#define ctl_set_bit(cr, bit) __ctl_set_bit(cr, bit)
226#define ctl_clear_bit(cr, bit) __ctl_clear_bit(cr, bit)
227
228#endif /* CONFIG_SMP */
229
Martin Schwidefsky14375bc2010-10-25 16:10:51 +0200230#define MAX_FACILITY_BIT (256*8) /* stfle_fac_list has 256 bytes */
Heiko Carstens484875b2008-04-30 13:38:43 +0200231
Martin Schwidefsky14375bc2010-10-25 16:10:51 +0200232/*
233 * The test_facility function uses the bit odering where the MSB is bit 0.
234 * That makes it easier to query facility bits with the bit number as
235 * documented in the Principles of Operation.
236 */
237static inline int test_facility(unsigned long nr)
Heiko Carstens320c04c2008-12-25 13:38:40 +0100238{
Martin Schwidefsky14375bc2010-10-25 16:10:51 +0200239 unsigned char *ptr;
Heiko Carstens320c04c2008-12-25 13:38:40 +0100240
Martin Schwidefsky14375bc2010-10-25 16:10:51 +0200241 if (nr >= MAX_FACILITY_BIT)
242 return 0;
243 ptr = (unsigned char *) &S390_lowcore.stfle_fac_list + (nr >> 3);
244 return (*ptr & (0x80 >> (nr & 7))) != 0;
Heiko Carstens320c04c2008-12-25 13:38:40 +0100245}
246
Heiko Carstens2e5061e2008-04-30 13:38:45 +0200247static inline unsigned short stap(void)
248{
249 unsigned short cpu_address;
250
251 asm volatile("stap %0" : "=m" (cpu_address));
252 return cpu_address;
253}
254
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255extern void (*_machine_restart)(char *command);
256extern void (*_machine_halt)(void);
257extern void (*_machine_power_off)(void);
258
Heiko Carstens9887a1f2011-01-12 09:55:28 +0100259extern unsigned long arch_align_stack(unsigned long sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260
Hans-Joachim Picht155af2f2009-06-16 10:30:52 +0200261static inline int tprot(unsigned long addr)
262{
263 int rc = -EFAULT;
264
265 asm volatile(
266 " tprot 0(%1),0\n"
267 "0: ipm %0\n"
268 " srl %0,28\n"
269 "1:\n"
270 EX_TABLE(0b,1b)
271 : "+d" (rc) : "a" (addr) : "cc");
272 return rc;
273}
274
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275#endif /* __KERNEL__ */
276
277#endif