PageRenderTime 35ms CodeModel.GetById 21ms app.highlight 11ms RepoModel.GetById 0ms app.codeStats 0ms

/arch/s390/include/asm/system.h

https://bitbucket.org/thekraven/iscream_thunderc-2.6.35
C++ Header | 478 lines | 389 code | 62 blank | 27 comment | 14 complexity | 9ea8912482a3c2bca896b8bd1c9bdb1c MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.0, AGPL-1.0
  1/*
  2 * Copyright IBM Corp. 1999, 2009
  3 *
  4 * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
  5 */
  6
  7#ifndef __ASM_SYSTEM_H
  8#define __ASM_SYSTEM_H
  9
 10#include <linux/kernel.h>
 11#include <linux/errno.h>
 12#include <asm/types.h>
 13#include <asm/ptrace.h>
 14#include <asm/setup.h>
 15#include <asm/processor.h>
 16#include <asm/lowcore.h>
 17
 18#ifdef __KERNEL__
 19
 20struct task_struct;
 21
 22extern struct task_struct *__switch_to(void *, void *);
 23
 24static inline void save_fp_regs(s390_fp_regs *fpregs)
 25{
 26	asm volatile(
 27		"	std	0,%O0+8(%R0)\n"
 28		"	std	2,%O0+24(%R0)\n"
 29		"	std	4,%O0+40(%R0)\n"
 30		"	std	6,%O0+56(%R0)"
 31		: "=Q" (*fpregs) : "Q" (*fpregs));
 32	if (!MACHINE_HAS_IEEE)
 33		return;
 34	asm volatile(
 35		"	stfpc	%0\n"
 36		"	std	1,%O0+16(%R0)\n"
 37		"	std	3,%O0+32(%R0)\n"
 38		"	std	5,%O0+48(%R0)\n"
 39		"	std	7,%O0+64(%R0)\n"
 40		"	std	8,%O0+72(%R0)\n"
 41		"	std	9,%O0+80(%R0)\n"
 42		"	std	10,%O0+88(%R0)\n"
 43		"	std	11,%O0+96(%R0)\n"
 44		"	std	12,%O0+104(%R0)\n"
 45		"	std	13,%O0+112(%R0)\n"
 46		"	std	14,%O0+120(%R0)\n"
 47		"	std	15,%O0+128(%R0)\n"
 48		: "=Q" (*fpregs) : "Q" (*fpregs));
 49}
 50
 51static inline void restore_fp_regs(s390_fp_regs *fpregs)
 52{
 53	asm volatile(
 54		"	ld	0,%O0+8(%R0)\n"
 55		"	ld	2,%O0+24(%R0)\n"
 56		"	ld	4,%O0+40(%R0)\n"
 57		"	ld	6,%O0+56(%R0)"
 58		: : "Q" (*fpregs));
 59	if (!MACHINE_HAS_IEEE)
 60		return;
 61	asm volatile(
 62		"	lfpc	%0\n"
 63		"	ld	1,%O0+16(%R0)\n"
 64		"	ld	3,%O0+32(%R0)\n"
 65		"	ld	5,%O0+48(%R0)\n"
 66		"	ld	7,%O0+64(%R0)\n"
 67		"	ld	8,%O0+72(%R0)\n"
 68		"	ld	9,%O0+80(%R0)\n"
 69		"	ld	10,%O0+88(%R0)\n"
 70		"	ld	11,%O0+96(%R0)\n"
 71		"	ld	12,%O0+104(%R0)\n"
 72		"	ld	13,%O0+112(%R0)\n"
 73		"	ld	14,%O0+120(%R0)\n"
 74		"	ld	15,%O0+128(%R0)\n"
 75		: : "Q" (*fpregs));
 76}
 77
 78static inline void save_access_regs(unsigned int *acrs)
 79{
 80	asm volatile("stam 0,15,%0" : "=Q" (*acrs));
 81}
 82
 83static inline void restore_access_regs(unsigned int *acrs)
 84{
 85	asm volatile("lam 0,15,%0" : : "Q" (*acrs));
 86}
 87
 88#define switch_to(prev,next,last) do {					     \
 89	if (prev == next)						     \
 90		break;							     \
 91	save_fp_regs(&prev->thread.fp_regs);				     \
 92	restore_fp_regs(&next->thread.fp_regs);				     \
 93	save_access_regs(&prev->thread.acrs[0]);			     \
 94	restore_access_regs(&next->thread.acrs[0]);			     \
 95	prev = __switch_to(prev,next);					     \
 96} while (0)
 97
 98extern void account_vtime(struct task_struct *, struct task_struct *);
 99extern void account_tick_vtime(struct task_struct *);
100extern void account_system_vtime(struct task_struct *);
101
102#ifdef CONFIG_PFAULT
103extern void pfault_irq_init(void);
104extern int pfault_init(void);
105extern void pfault_fini(void);
106#else /* CONFIG_PFAULT */
107#define pfault_irq_init()	do { } while (0)
108#define pfault_init()		({-1;})
109#define pfault_fini()		do { } while (0)
110#endif /* CONFIG_PFAULT */
111
112extern void cmma_init(void);
113extern int memcpy_real(void *, void *, size_t);
114
115#define finish_arch_switch(prev) do {					     \
116	set_fs(current->thread.mm_segment);				     \
117	account_vtime(prev, current);					     \
118} while (0)
119
120#define nop() asm volatile("nop")
121
122#define xchg(ptr,x)							  \
123({									  \
124	__typeof__(*(ptr)) __ret;					  \
125	__ret = (__typeof__(*(ptr)))					  \
126		__xchg((unsigned long)(x), (void *)(ptr),sizeof(*(ptr))); \
127	__ret;								  \
128})
129
130extern void __xchg_called_with_bad_pointer(void);
131
132static inline unsigned long __xchg(unsigned long x, void * ptr, int size)
133{
134	unsigned long addr, old;
135	int shift;
136
137        switch (size) {
138	case 1:
139		addr = (unsigned long) ptr;
140		shift = (3 ^ (addr & 3)) << 3;
141		addr ^= addr & 3;
142		asm volatile(
143			"	l	%0,%4\n"
144			"0:	lr	0,%0\n"
145			"	nr	0,%3\n"
146			"	or	0,%2\n"
147			"	cs	%0,0,%4\n"
148			"	jl	0b\n"
149			: "=&d" (old), "=Q" (*(int *) addr)
150			: "d" (x << shift), "d" (~(255 << shift)),
151			  "Q" (*(int *) addr) : "memory", "cc", "0");
152		return old >> shift;
153	case 2:
154		addr = (unsigned long) ptr;
155		shift = (2 ^ (addr & 2)) << 3;
156		addr ^= addr & 2;
157		asm volatile(
158			"	l	%0,%4\n"
159			"0:	lr	0,%0\n"
160			"	nr	0,%3\n"
161			"	or	0,%2\n"
162			"	cs	%0,0,%4\n"
163			"	jl	0b\n"
164			: "=&d" (old), "=Q" (*(int *) addr)
165			: "d" (x << shift), "d" (~(65535 << shift)),
166			  "Q" (*(int *) addr) : "memory", "cc", "0");
167		return old >> shift;
168	case 4:
169		asm volatile(
170			"	l	%0,%3\n"
171			"0:	cs	%0,%2,%3\n"
172			"	jl	0b\n"
173			: "=&d" (old), "=Q" (*(int *) ptr)
174			: "d" (x), "Q" (*(int *) ptr)
175			: "memory", "cc");
176		return old;
177#ifdef __s390x__
178	case 8:
179		asm volatile(
180			"	lg	%0,%3\n"
181			"0:	csg	%0,%2,%3\n"
182			"	jl	0b\n"
183			: "=&d" (old), "=m" (*(long *) ptr)
184			: "d" (x), "Q" (*(long *) ptr)
185			: "memory", "cc");
186		return old;
187#endif /* __s390x__ */
188	}
189	__xchg_called_with_bad_pointer();
190	return x;
191}
192
193/*
194 * Atomic compare and exchange.  Compare OLD with MEM, if identical,
195 * store NEW in MEM.  Return the initial value in MEM.  Success is
196 * indicated by comparing RETURN with OLD.
197 */
198
199#define __HAVE_ARCH_CMPXCHG 1
200
201#define cmpxchg(ptr, o, n)						\
202	((__typeof__(*(ptr)))__cmpxchg((ptr), (unsigned long)(o),	\
203					(unsigned long)(n), sizeof(*(ptr))))
204
205extern void __cmpxchg_called_with_bad_pointer(void);
206
207static inline unsigned long
208__cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size)
209{
210	unsigned long addr, prev, tmp;
211	int shift;
212
213        switch (size) {
214	case 1:
215		addr = (unsigned long) ptr;
216		shift = (3 ^ (addr & 3)) << 3;
217		addr ^= addr & 3;
218		asm volatile(
219			"	l	%0,%2\n"
220			"0:	nr	%0,%5\n"
221			"	lr	%1,%0\n"
222			"	or	%0,%3\n"
223			"	or	%1,%4\n"
224			"	cs	%0,%1,%2\n"
225			"	jnl	1f\n"
226			"	xr	%1,%0\n"
227			"	nr	%1,%5\n"
228			"	jnz	0b\n"
229			"1:"
230			: "=&d" (prev), "=&d" (tmp), "=Q" (*(int *) ptr)
231			: "d" (old << shift), "d" (new << shift),
232			  "d" (~(255 << shift)), "Q" (*(int *) ptr)
233			: "memory", "cc");
234		return prev >> shift;
235	case 2:
236		addr = (unsigned long) ptr;
237		shift = (2 ^ (addr & 2)) << 3;
238		addr ^= addr & 2;
239		asm volatile(
240			"	l	%0,%2\n"
241			"0:	nr	%0,%5\n"
242			"	lr	%1,%0\n"
243			"	or	%0,%3\n"
244			"	or	%1,%4\n"
245			"	cs	%0,%1,%2\n"
246			"	jnl	1f\n"
247			"	xr	%1,%0\n"
248			"	nr	%1,%5\n"
249			"	jnz	0b\n"
250			"1:"
251			: "=&d" (prev), "=&d" (tmp), "=Q" (*(int *) ptr)
252			: "d" (old << shift), "d" (new << shift),
253			  "d" (~(65535 << shift)), "Q" (*(int *) ptr)
254			: "memory", "cc");
255		return prev >> shift;
256	case 4:
257		asm volatile(
258			"	cs	%0,%3,%1\n"
259			: "=&d" (prev), "=Q" (*(int *) ptr)
260			: "0" (old), "d" (new), "Q" (*(int *) ptr)
261			: "memory", "cc");
262		return prev;
263#ifdef __s390x__
264	case 8:
265		asm volatile(
266			"	csg	%0,%3,%1\n"
267			: "=&d" (prev), "=Q" (*(long *) ptr)
268			: "0" (old), "d" (new), "Q" (*(long *) ptr)
269			: "memory", "cc");
270		return prev;
271#endif /* __s390x__ */
272        }
273	__cmpxchg_called_with_bad_pointer();
274	return old;
275}
276
277/*
278 * Force strict CPU ordering.
279 * And yes, this is required on UP too when we're talking
280 * to devices.
281 *
282 * This is very similar to the ppc eieio/sync instruction in that is
283 * does a checkpoint syncronisation & makes sure that 
284 * all memory ops have completed wrt other CPU's ( see 7-15 POP  DJB ).
285 */
286
287#define eieio()	asm volatile("bcr 15,0" : : : "memory")
288#define SYNC_OTHER_CORES(x)   eieio()
289#define mb()    eieio()
290#define rmb()   eieio()
291#define wmb()   eieio()
292#define read_barrier_depends() do { } while(0)
293#define smp_mb()       mb()
294#define smp_rmb()      rmb()
295#define smp_wmb()      wmb()
296#define smp_read_barrier_depends()    read_barrier_depends()
297#define smp_mb__before_clear_bit()     smp_mb()
298#define smp_mb__after_clear_bit()      smp_mb()
299
300
301#define set_mb(var, value)      do { var = value; mb(); } while (0)
302
303#ifdef __s390x__
304
305#define __ctl_load(array, low, high) ({				\
306	typedef struct { char _[sizeof(array)]; } addrtype;	\
307	asm volatile(						\
308		"	lctlg	%1,%2,%0\n"			\
309		: : "Q" (*(addrtype *)(&array)),		\
310		    "i" (low), "i" (high));			\
311	})
312
313#define __ctl_store(array, low, high) ({			\
314	typedef struct { char _[sizeof(array)]; } addrtype;	\
315	asm volatile(						\
316		"	stctg	%1,%2,%0\n"			\
317		: "=Q" (*(addrtype *)(&array))			\
318		: "i" (low), "i" (high));			\
319	})
320
321#else /* __s390x__ */
322
323#define __ctl_load(array, low, high) ({				\
324	typedef struct { char _[sizeof(array)]; } addrtype;	\
325	asm volatile(						\
326		"	lctl	%1,%2,%0\n"			\
327		: : "Q" (*(addrtype *)(&array)),		\
328		    "i" (low), "i" (high));			\
329})
330
331#define __ctl_store(array, low, high) ({			\
332	typedef struct { char _[sizeof(array)]; } addrtype;	\
333	asm volatile(						\
334		"	stctl	%1,%2,%0\n"			\
335		: "=Q" (*(addrtype *)(&array))			\
336		: "i" (low), "i" (high));			\
337	})
338
339#endif /* __s390x__ */
340
341#define __ctl_set_bit(cr, bit) ({	\
342	unsigned long __dummy;		\
343	__ctl_store(__dummy, cr, cr);	\
344	__dummy |= 1UL << (bit);	\
345	__ctl_load(__dummy, cr, cr);	\
346})
347
348#define __ctl_clear_bit(cr, bit) ({	\
349	unsigned long __dummy;		\
350	__ctl_store(__dummy, cr, cr);	\
351	__dummy &= ~(1UL << (bit));	\
352	__ctl_load(__dummy, cr, cr);	\
353})
354
355#include <linux/irqflags.h>
356
357#include <asm-generic/cmpxchg-local.h>
358
359static inline unsigned long __cmpxchg_local(volatile void *ptr,
360				      unsigned long old,
361				      unsigned long new, int size)
362{
363	switch (size) {
364	case 1:
365	case 2:
366	case 4:
367#ifdef __s390x__
368	case 8:
369#endif
370		return __cmpxchg(ptr, old, new, size);
371	default:
372		return __cmpxchg_local_generic(ptr, old, new, size);
373	}
374
375	return old;
376}
377
378/*
379 * cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make
380 * them available.
381 */
382#define cmpxchg_local(ptr, o, n)					\
383	((__typeof__(*(ptr)))__cmpxchg_local((ptr), (unsigned long)(o),	\
384			(unsigned long)(n), sizeof(*(ptr))))
385#ifdef __s390x__
386#define cmpxchg64_local(ptr, o, n)					\
387  ({									\
388	BUILD_BUG_ON(sizeof(*(ptr)) != 8);				\
389	cmpxchg_local((ptr), (o), (n));					\
390  })
391#else
392#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
393#endif
394
395/*
396 * Use to set psw mask except for the first byte which
397 * won't be changed by this function.
398 */
399static inline void
400__set_psw_mask(unsigned long mask)
401{
402	__load_psw_mask(mask | (__raw_local_irq_stosm(0x00) & ~(-1UL >> 8)));
403}
404
405#define local_mcck_enable()  __set_psw_mask(psw_kernel_bits)
406#define local_mcck_disable() __set_psw_mask(psw_kernel_bits & ~PSW_MASK_MCHECK)
407
408#ifdef CONFIG_SMP
409
410extern void smp_ctl_set_bit(int cr, int bit);
411extern void smp_ctl_clear_bit(int cr, int bit);
412#define ctl_set_bit(cr, bit) smp_ctl_set_bit(cr, bit)
413#define ctl_clear_bit(cr, bit) smp_ctl_clear_bit(cr, bit)
414
415#else
416
417#define ctl_set_bit(cr, bit) __ctl_set_bit(cr, bit)
418#define ctl_clear_bit(cr, bit) __ctl_clear_bit(cr, bit)
419
420#endif /* CONFIG_SMP */
421
422static inline unsigned int stfl(void)
423{
424	asm volatile(
425		"	.insn	s,0xb2b10000,0(0)\n" /* stfl */
426		"0:\n"
427		EX_TABLE(0b,0b));
428	return S390_lowcore.stfl_fac_list;
429}
430
431static inline int __stfle(unsigned long long *list, int doublewords)
432{
433	typedef struct { unsigned long long _[doublewords]; } addrtype;
434	register unsigned long __nr asm("0") = doublewords - 1;
435
436	asm volatile(".insn s,0xb2b00000,%0" /* stfle */
437		     : "=m" (*(addrtype *) list), "+d" (__nr) : : "cc");
438	return __nr + 1;
439}
440
441static inline int stfle(unsigned long long *list, int doublewords)
442{
443	if (!(stfl() & (1UL << 24)))
444		return -EOPNOTSUPP;
445	return __stfle(list, doublewords);
446}
447
448static inline unsigned short stap(void)
449{
450	unsigned short cpu_address;
451
452	asm volatile("stap %0" : "=m" (cpu_address));
453	return cpu_address;
454}
455
456extern void (*_machine_restart)(char *command);
457extern void (*_machine_halt)(void);
458extern void (*_machine_power_off)(void);
459
460#define arch_align_stack(x) (x)
461
462static inline int tprot(unsigned long addr)
463{
464	int rc = -EFAULT;
465
466	asm volatile(
467		"	tprot	0(%1),0\n"
468		"0:	ipm	%0\n"
469		"	srl	%0,28\n"
470		"1:\n"
471		EX_TABLE(0b,1b)
472		: "+d" (rc) : "a" (addr) : "cc");
473	return rc;
474}
475
476#endif /* __KERNEL__ */
477
478#endif