Home | History | Annotate | Line # | Download | only in uatomic
s390.h revision 1.1
      1  1.1  christos // SPDX-FileCopyrightText: 2009 Novell, Inc.
      2  1.1  christos // SPDX-FileCopyrightText: 2009 Mathieu Desnoyers <mathieu.desnoyers (at) efficios.com>
      3  1.1  christos //
      4  1.1  christos // SPDX-License-Identifier: MIT
      5  1.1  christos 
      6  1.1  christos #ifndef _URCU_UATOMIC_ARCH_S390_H
      7  1.1  christos #define _URCU_UATOMIC_ARCH_S390_H
      8  1.1  christos 
      9  1.1  christos /*
     10  1.1  christos  * Atomic exchange operations for the S390 architecture. Based on information
     11  1.1  christos  * taken from the Principles of Operation Appendix A "Conditional Swapping
     12  1.1  christos  * Instructions (CS, CDS)".
     13  1.1  christos  *
     14  1.1  christos  * Author: Jan Blunck <jblunck (at) suse.de>
     15  1.1  christos  */
     16  1.1  christos 
     17  1.1  christos #include <urcu/compiler.h>
     18  1.1  christos #include <urcu/system.h>
     19  1.1  christos 
     20  1.1  christos #ifdef __cplusplus
     21  1.1  christos extern "C" {
     22  1.1  christos #endif
     23  1.1  christos 
     24  1.1  christos #if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 2)
     25  1.1  christos #define COMPILER_HAVE_SHORT_MEM_OPERAND
     26  1.1  christos #endif
     27  1.1  christos 
     28  1.1  christos /*
     29  1.1  christos  * MEMOP assembler operand rules:
     30  1.1  christos  * - op refer to MEMOP_IN operand
     31  1.1  christos  * - MEMOP_IN can expand to more than a single operand. Use it at the end of
     32  1.1  christos  *   operand list only.
     33  1.1  christos  */
     34  1.1  christos 
     35  1.1  christos #ifdef COMPILER_HAVE_SHORT_MEM_OPERAND
     36  1.1  christos 
     37  1.1  christos #define MEMOP_OUT(addr)	"=Q" (*(addr))
     38  1.1  christos #define MEMOP_IN(addr)	"Q" (*(addr))
     39  1.1  christos #define MEMOP_REF(op)	#op		/* op refer to MEMOP_IN operand */
     40  1.1  christos 
     41  1.1  christos #else /* !COMPILER_HAVE_SHORT_MEM_OPERAND */
     42  1.1  christos 
     43  1.1  christos #define MEMOP_OUT(addr)	"=m" (*(addr))
     44  1.1  christos #define MEMOP_IN(addr)	"a" (addr), "m" (*(addr))
     45  1.1  christos #define MEMOP_REF(op)	"0(" #op ")"	/* op refer to MEMOP_IN operand */
     46  1.1  christos 
     47  1.1  christos #endif /* !COMPILER_HAVE_SHORT_MEM_OPERAND */
     48  1.1  christos 
     49  1.1  christos /*
     50  1.1  christos  * The __hp() macro casts the void pointer @x to a pointer to a structure
     51  1.1  christos  * containing an array of char of the specified size. This allows passing the
     52  1.1  christos  * @addr arguments of the following inline functions as "m" and "+m" operands
     53  1.1  christos  * to the assembly. The @size parameter should be a constant to support
     54  1.1  christos  * compilers such as clang which do not support VLA. Create typedefs because
     55  1.1  christos  * C++ does not allow types be defined in casts.
     56  1.1  christos  */
     57  1.1  christos 
     58  1.1  christos typedef struct { char v[4]; } __hp_4;
     59  1.1  christos typedef struct { char v[8]; } __hp_8;
     60  1.1  christos 
     61  1.1  christos #define __hp(size, x)	((__hp_##size *)(x))
     62  1.1  christos 
     63  1.1  christos /* xchg */
     64  1.1  christos 
     65  1.1  christos static inline __attribute__((always_inline))
     66  1.1  christos unsigned long _uatomic_exchange(volatile void *addr, unsigned long val, int len)
     67  1.1  christos {
     68  1.1  christos 	switch (len) {
     69  1.1  christos 	case 4:
     70  1.1  christos 	{
     71  1.1  christos 		unsigned int old_val;
     72  1.1  christos 
     73  1.1  christos 		__asm__ __volatile__(
     74  1.1  christos 			"0:	cs %0,%2," MEMOP_REF(%3) "\n"
     75  1.1  christos 			"	brc 4,0b\n"
     76  1.1  christos 			: "=&r" (old_val), MEMOP_OUT (__hp(4, addr))
     77  1.1  christos 			: "r" (val), MEMOP_IN (__hp(4, addr))
     78  1.1  christos 			: "memory", "cc");
     79  1.1  christos 		return old_val;
     80  1.1  christos 	}
     81  1.1  christos #if (CAA_BITS_PER_LONG == 64)
     82  1.1  christos 	case 8:
     83  1.1  christos 	{
     84  1.1  christos 		unsigned long old_val;
     85  1.1  christos 
     86  1.1  christos 		__asm__ __volatile__(
     87  1.1  christos 			"0:	csg %0,%2," MEMOP_REF(%3) "\n"
     88  1.1  christos 			"	brc 4,0b\n"
     89  1.1  christos 			: "=&r" (old_val), MEMOP_OUT (__hp(8, addr))
     90  1.1  christos 			: "r" (val), MEMOP_IN (__hp(8, addr))
     91  1.1  christos 			: "memory", "cc");
     92  1.1  christos 		return old_val;
     93  1.1  christos 	}
     94  1.1  christos #endif
     95  1.1  christos 	default:
     96  1.1  christos 		__asm__ __volatile__(".long	0xd00d00");
     97  1.1  christos 	}
     98  1.1  christos 
     99  1.1  christos 	return 0;
    100  1.1  christos }
    101  1.1  christos 
    102  1.1  christos #define uatomic_xchg_mo(addr, v, mo)					\
    103  1.1  christos 	(__typeof__(*(addr))) _uatomic_exchange((addr),			    \
    104  1.1  christos 						caa_cast_long_keep_sign(v), \
    105  1.1  christos 						sizeof(*(addr)))
    106  1.1  christos 
    107  1.1  christos /* cmpxchg */
    108  1.1  christos 
    109  1.1  christos static inline __attribute__((always_inline))
    110  1.1  christos unsigned long _uatomic_cmpxchg(void *addr, unsigned long old,
    111  1.1  christos 			       unsigned long _new, int len)
    112  1.1  christos {
    113  1.1  christos 	switch (len) {
    114  1.1  christos 	case 4:
    115  1.1  christos 	{
    116  1.1  christos 		unsigned int old_val = (unsigned int)old;
    117  1.1  christos 
    118  1.1  christos 		__asm__ __volatile__(
    119  1.1  christos 			"	cs %0,%2," MEMOP_REF(%3) "\n"
    120  1.1  christos 			: "+r" (old_val), MEMOP_OUT (__hp(4, addr))
    121  1.1  christos 			: "r" (_new), MEMOP_IN (__hp(4, addr))
    122  1.1  christos 			: "memory", "cc");
    123  1.1  christos 		return old_val;
    124  1.1  christos 	}
    125  1.1  christos #if (CAA_BITS_PER_LONG == 64)
    126  1.1  christos 	case 8:
    127  1.1  christos 	{
    128  1.1  christos 		__asm__ __volatile__(
    129  1.1  christos 			"	csg %0,%2," MEMOP_REF(%3) "\n"
    130  1.1  christos 			: "+r" (old), MEMOP_OUT (__hp(8, addr))
    131  1.1  christos 			: "r" (_new), MEMOP_IN (__hp(8, addr))
    132  1.1  christos 			: "memory", "cc");
    133  1.1  christos 		return old;
    134  1.1  christos 	}
    135  1.1  christos #endif
    136  1.1  christos 	default:
    137  1.1  christos 		__asm__ __volatile__(".long	0xd00d00");
    138  1.1  christos 	}
    139  1.1  christos 
    140  1.1  christos 	return 0;
    141  1.1  christos }
    142  1.1  christos 
    143  1.1  christos #define uatomic_cmpxchg_mo(addr, old, _new, mos, mof)			\
    144  1.1  christos 	(__typeof__(*(addr))) _uatomic_cmpxchg((addr),			     \
    145  1.1  christos 					       caa_cast_long_keep_sign(old), \
    146  1.1  christos 					       caa_cast_long_keep_sign(_new),\
    147  1.1  christos 					       sizeof(*(addr)))
    148  1.1  christos 
    149  1.1  christos #ifdef __cplusplus
    150  1.1  christos }
    151  1.1  christos #endif
    152  1.1  christos 
    153  1.1  christos #include <urcu/uatomic/generic.h>
    154  1.1  christos 
    155  1.1  christos #endif /* _URCU_UATOMIC_ARCH_S390_H */
    156