Home | History | Annotate | Line # | Download | only in pa
linux-atomic.c revision 1.3
      1  1.1  mrg /* Linux-specific atomic operations for PA Linux.
      2  1.3  mrg    Copyright (C) 2008-2015 Free Software Foundation, Inc.
      3  1.1  mrg    Based on code contributed by CodeSourcery for ARM EABI Linux.
      4  1.1  mrg    Modifications for PA Linux by Helge Deller <deller (at) gmx.de>
      5  1.1  mrg 
      6  1.1  mrg This file is part of GCC.
      7  1.1  mrg 
      8  1.1  mrg GCC is free software; you can redistribute it and/or modify it under
      9  1.1  mrg the terms of the GNU General Public License as published by the Free
     10  1.1  mrg Software Foundation; either version 3, or (at your option) any later
     11  1.1  mrg version.
     12  1.1  mrg 
     13  1.1  mrg GCC is distributed in the hope that it will be useful, but WITHOUT ANY
     14  1.1  mrg WARRANTY; without even the implied warranty of MERCHANTABILITY or
     15  1.1  mrg FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     16  1.1  mrg for more details.
     17  1.1  mrg 
     18  1.1  mrg Under Section 7 of GPL version 3, you are granted additional
     19  1.1  mrg permissions described in the GCC Runtime Library Exception, version
     20  1.1  mrg 3.1, as published by the Free Software Foundation.
     21  1.1  mrg 
     22  1.1  mrg You should have received a copy of the GNU General Public License and
     23  1.1  mrg a copy of the GCC Runtime Library Exception along with this program;
     24  1.1  mrg see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
     25  1.1  mrg <http://www.gnu.org/licenses/>.  */
     26  1.1  mrg 
     27  1.1  mrg #define EFAULT  14
     28  1.1  mrg #define EBUSY   16
     29  1.1  mrg #define ENOSYS 251
     30  1.1  mrg 
     31  1.1  mrg /* All PA-RISC implementations supported by linux have strongly
     32  1.1  mrg    ordered loads and stores.  Only cache flushes and purges can be
     33  1.1  mrg    delayed.  The data cache implementations are all globally
     34  1.1  mrg    coherent.  Thus, there is no need to synchonize memory accesses.
     35  1.1  mrg 
     36  1.1  mrg    GCC automatically issues a asm memory barrier when it encounters
     37  1.1  mrg    a __sync_synchronize builtin.  Thus, we do not need to define this
     38  1.1  mrg    builtin.
     39  1.1  mrg 
     40  1.1  mrg    We implement byte, short and int versions of each atomic operation
     41  1.1  mrg    using the kernel helper defined below.  There is no support for
     42  1.1  mrg    64-bit operations yet.  */
     43  1.1  mrg 
     44  1.1  mrg /* Determine kernel LWS function call (0=32-bit, 1=64-bit userspace).  */
     45  1.3  mrg #define LWS_CAS (sizeof(long) == 4 ? 0 : 1)
     46  1.1  mrg 
     47  1.1  mrg /* Kernel helper for compare-and-exchange a 32-bit value.  */
     48  1.1  mrg static inline long
     49  1.3  mrg __kernel_cmpxchg (int *mem, int oldval, int newval)
     50  1.1  mrg {
     51  1.1  mrg   register unsigned long lws_mem asm("r26") = (unsigned long) (mem);
     52  1.3  mrg   register int lws_old asm("r25") = oldval;
     53  1.3  mrg   register int lws_new asm("r24") = newval;
     54  1.1  mrg   register long lws_ret   asm("r28");
     55  1.1  mrg   register long lws_errno asm("r21");
     56  1.1  mrg   asm volatile (	"ble	0xb0(%%sr2, %%r0)	\n\t"
     57  1.3  mrg 			"ldi	%2, %%r20		\n\t"
     58  1.3  mrg 	: "=r" (lws_ret), "=r" (lws_errno)
     59  1.3  mrg 	: "i" (LWS_CAS), "r" (lws_mem), "r" (lws_old), "r" (lws_new)
     60  1.1  mrg 	: "r1", "r20", "r22", "r23", "r29", "r31", "memory"
     61  1.1  mrg   );
     62  1.1  mrg   if (__builtin_expect (lws_errno == -EFAULT || lws_errno == -ENOSYS, 0))
     63  1.3  mrg     __builtin_trap ();
     64  1.1  mrg 
     65  1.1  mrg   /* If the kernel LWS call succeeded (lws_errno == 0), lws_ret contains
     66  1.1  mrg      the old value from memory.  If this value is equal to OLDVAL, the
     67  1.1  mrg      new value was written to memory.  If not, return -EBUSY.  */
     68  1.1  mrg   if (!lws_errno && lws_ret != oldval)
     69  1.1  mrg     lws_errno = -EBUSY;
     70  1.1  mrg 
     71  1.1  mrg   return lws_errno;
     72  1.1  mrg }
     73  1.1  mrg 
     74  1.3  mrg static inline long
     75  1.3  mrg __kernel_cmpxchg2 (void *mem, const void *oldval, const void *newval,
     76  1.3  mrg 		   int val_size)
     77  1.3  mrg {
     78  1.3  mrg   register unsigned long lws_mem asm("r26") = (unsigned long) (mem);
     79  1.3  mrg   register unsigned long lws_old asm("r25") = (unsigned long) oldval;
     80  1.3  mrg   register unsigned long lws_new asm("r24") = (unsigned long) newval;
     81  1.3  mrg   register int lws_size asm("r23") = val_size;
     82  1.3  mrg   register long lws_ret   asm("r28");
     83  1.3  mrg   register long lws_errno asm("r21");
     84  1.3  mrg   asm volatile (	"ble	0xb0(%%sr2, %%r0)	\n\t"
     85  1.3  mrg 			"ldi	%6, %%r20		\n\t"
     86  1.3  mrg 	: "=r" (lws_ret), "=r" (lws_errno), "+r" (lws_mem),
     87  1.3  mrg 	  "+r" (lws_old), "+r" (lws_new), "+r" (lws_size)
     88  1.3  mrg 	: "i" (2)
     89  1.3  mrg 	: "r1", "r20", "r22", "r29", "r31", "fr4", "memory"
     90  1.3  mrg   );
     91  1.3  mrg 
     92  1.3  mrg   /* If the kernel LWS call is successful, lws_ret contains 0.  */
     93  1.3  mrg   if (__builtin_expect (lws_ret == 0, 1))
     94  1.3  mrg     return 0;
     95  1.3  mrg 
     96  1.3  mrg   if (__builtin_expect (lws_errno == -EFAULT || lws_errno == -ENOSYS, 0))
     97  1.3  mrg     __builtin_trap ();
     98  1.3  mrg 
     99  1.3  mrg   /* If the kernel LWS call fails with no error, return -EBUSY */
    100  1.3  mrg   if (__builtin_expect (!lws_errno, 0))
    101  1.3  mrg     return -EBUSY;
    102  1.3  mrg 
    103  1.3  mrg   return lws_errno;
    104  1.3  mrg }
    105  1.1  mrg #define HIDDEN __attribute__ ((visibility ("hidden")))
    106  1.1  mrg 
    107  1.1  mrg /* Big endian masks  */
    108  1.1  mrg #define INVERT_MASK_1 24
    109  1.1  mrg #define INVERT_MASK_2 16
    110  1.1  mrg 
    111  1.1  mrg #define MASK_1 0xffu
    112  1.1  mrg #define MASK_2 0xffffu
    113  1.1  mrg 
    114  1.3  mrg #define FETCH_AND_OP_2(OP, PFX_OP, INF_OP, TYPE, WIDTH, INDEX)		\
    115  1.3  mrg   TYPE HIDDEN								\
    116  1.3  mrg   __sync_fetch_and_##OP##_##WIDTH (TYPE *ptr, TYPE val)			\
    117  1.1  mrg   {									\
    118  1.3  mrg     TYPE tmp, newval;							\
    119  1.3  mrg     long failure;							\
    120  1.1  mrg 									\
    121  1.1  mrg     do {								\
    122  1.3  mrg       tmp = __atomic_load_n (ptr, __ATOMIC_SEQ_CST);			\
    123  1.3  mrg       newval = PFX_OP (tmp INF_OP val);					\
    124  1.3  mrg       failure = __kernel_cmpxchg2 (ptr, &tmp, &newval, INDEX);		\
    125  1.1  mrg     } while (failure != 0);						\
    126  1.1  mrg 									\
    127  1.1  mrg     return tmp;								\
    128  1.1  mrg   }
    129  1.1  mrg 
    130  1.3  mrg FETCH_AND_OP_2 (add,   , +, long long, 8, 3)
    131  1.3  mrg FETCH_AND_OP_2 (sub,   , -, long long, 8, 3)
    132  1.3  mrg FETCH_AND_OP_2 (or,    , |, long long, 8, 3)
    133  1.3  mrg FETCH_AND_OP_2 (and,   , &, long long, 8, 3)
    134  1.3  mrg FETCH_AND_OP_2 (xor,   , ^, long long, 8, 3)
    135  1.3  mrg FETCH_AND_OP_2 (nand, ~, &, long long, 8, 3)
    136  1.3  mrg 
    137  1.3  mrg FETCH_AND_OP_2 (add,   , +, short, 2, 1)
    138  1.3  mrg FETCH_AND_OP_2 (sub,   , -, short, 2, 1)
    139  1.3  mrg FETCH_AND_OP_2 (or,    , |, short, 2, 1)
    140  1.3  mrg FETCH_AND_OP_2 (and,   , &, short, 2, 1)
    141  1.3  mrg FETCH_AND_OP_2 (xor,   , ^, short, 2, 1)
    142  1.3  mrg FETCH_AND_OP_2 (nand, ~, &, short, 2, 1)
    143  1.3  mrg 
    144  1.3  mrg FETCH_AND_OP_2 (add,   , +, signed char, 1, 0)
    145  1.3  mrg FETCH_AND_OP_2 (sub,   , -, signed char, 1, 0)
    146  1.3  mrg FETCH_AND_OP_2 (or,    , |, signed char, 1, 0)
    147  1.3  mrg FETCH_AND_OP_2 (and,   , &, signed char, 1, 0)
    148  1.3  mrg FETCH_AND_OP_2 (xor,   , ^, signed char, 1, 0)
    149  1.3  mrg FETCH_AND_OP_2 (nand, ~, &, signed char, 1, 0)
    150  1.1  mrg 
    151  1.3  mrg #define OP_AND_FETCH_2(OP, PFX_OP, INF_OP, TYPE, WIDTH, INDEX)		\
    152  1.1  mrg   TYPE HIDDEN								\
    153  1.3  mrg   __sync_##OP##_and_fetch_##WIDTH (TYPE *ptr, TYPE val)			\
    154  1.1  mrg   {									\
    155  1.3  mrg     TYPE tmp, newval;							\
    156  1.3  mrg     long failure;							\
    157  1.1  mrg 									\
    158  1.3  mrg     do {								\
    159  1.3  mrg       tmp = __atomic_load_n (ptr, __ATOMIC_SEQ_CST);			\
    160  1.3  mrg       newval = PFX_OP (tmp INF_OP val);					\
    161  1.3  mrg       failure = __kernel_cmpxchg2 (ptr, &tmp, &newval, INDEX);		\
    162  1.3  mrg     } while (failure != 0);						\
    163  1.3  mrg 									\
    164  1.3  mrg     return PFX_OP (tmp INF_OP val);					\
    165  1.3  mrg   }
    166  1.3  mrg 
    167  1.3  mrg OP_AND_FETCH_2 (add,   , +, long long, 8, 3)
    168  1.3  mrg OP_AND_FETCH_2 (sub,   , -, long long, 8, 3)
    169  1.3  mrg OP_AND_FETCH_2 (or,    , |, long long, 8, 3)
    170  1.3  mrg OP_AND_FETCH_2 (and,   , &, long long, 8, 3)
    171  1.3  mrg OP_AND_FETCH_2 (xor,   , ^, long long, 8, 3)
    172  1.3  mrg OP_AND_FETCH_2 (nand, ~, &, long long, 8, 3)
    173  1.3  mrg 
    174  1.3  mrg OP_AND_FETCH_2 (add,   , +, short, 2, 1)
    175  1.3  mrg OP_AND_FETCH_2 (sub,   , -, short, 2, 1)
    176  1.3  mrg OP_AND_FETCH_2 (or,    , |, short, 2, 1)
    177  1.3  mrg OP_AND_FETCH_2 (and,   , &, short, 2, 1)
    178  1.3  mrg OP_AND_FETCH_2 (xor,   , ^, short, 2, 1)
    179  1.3  mrg OP_AND_FETCH_2 (nand, ~, &, short, 2, 1)
    180  1.3  mrg 
    181  1.3  mrg OP_AND_FETCH_2 (add,   , +, signed char, 1, 0)
    182  1.3  mrg OP_AND_FETCH_2 (sub,   , -, signed char, 1, 0)
    183  1.3  mrg OP_AND_FETCH_2 (or,    , |, signed char, 1, 0)
    184  1.3  mrg OP_AND_FETCH_2 (and,   , &, signed char, 1, 0)
    185  1.3  mrg OP_AND_FETCH_2 (xor,   , ^, signed char, 1, 0)
    186  1.3  mrg OP_AND_FETCH_2 (nand, ~, &, signed char, 1, 0)
    187  1.3  mrg 
    188  1.3  mrg #define FETCH_AND_OP_WORD(OP, PFX_OP, INF_OP)				\
    189  1.3  mrg   int HIDDEN								\
    190  1.3  mrg   __sync_fetch_and_##OP##_4 (int *ptr, int val)				\
    191  1.3  mrg   {									\
    192  1.3  mrg     int tmp;								\
    193  1.3  mrg     long failure;							\
    194  1.1  mrg 									\
    195  1.1  mrg     do {								\
    196  1.3  mrg       tmp = __atomic_load_n (ptr, __ATOMIC_SEQ_CST);			\
    197  1.3  mrg       failure = __kernel_cmpxchg (ptr, tmp, PFX_OP (tmp INF_OP val));	\
    198  1.1  mrg     } while (failure != 0);						\
    199  1.1  mrg 									\
    200  1.3  mrg     return tmp;								\
    201  1.1  mrg   }
    202  1.1  mrg 
    203  1.3  mrg FETCH_AND_OP_WORD (add,   , +)
    204  1.3  mrg FETCH_AND_OP_WORD (sub,   , -)
    205  1.3  mrg FETCH_AND_OP_WORD (or,    , |)
    206  1.3  mrg FETCH_AND_OP_WORD (and,   , &)
    207  1.3  mrg FETCH_AND_OP_WORD (xor,   , ^)
    208  1.3  mrg FETCH_AND_OP_WORD (nand, ~, &)
    209  1.1  mrg 
    210  1.1  mrg #define OP_AND_FETCH_WORD(OP, PFX_OP, INF_OP)				\
    211  1.1  mrg   int HIDDEN								\
    212  1.1  mrg   __sync_##OP##_and_fetch_4 (int *ptr, int val)				\
    213  1.1  mrg   {									\
    214  1.3  mrg     int tmp;								\
    215  1.3  mrg     long failure;							\
    216  1.1  mrg 									\
    217  1.1  mrg     do {								\
    218  1.3  mrg       tmp = __atomic_load_n (ptr, __ATOMIC_SEQ_CST);			\
    219  1.3  mrg       failure = __kernel_cmpxchg (ptr, tmp, PFX_OP (tmp INF_OP val));	\
    220  1.1  mrg     } while (failure != 0);						\
    221  1.1  mrg 									\
    222  1.1  mrg     return PFX_OP (tmp INF_OP val);					\
    223  1.1  mrg   }
    224  1.1  mrg 
    225  1.1  mrg OP_AND_FETCH_WORD (add,   , +)
    226  1.1  mrg OP_AND_FETCH_WORD (sub,   , -)
    227  1.1  mrg OP_AND_FETCH_WORD (or,    , |)
    228  1.1  mrg OP_AND_FETCH_WORD (and,   , &)
    229  1.1  mrg OP_AND_FETCH_WORD (xor,   , ^)
    230  1.1  mrg OP_AND_FETCH_WORD (nand, ~, &)
    231  1.1  mrg 
    232  1.3  mrg typedef unsigned char bool;
    233  1.3  mrg 
    234  1.3  mrg #define COMPARE_AND_SWAP_2(TYPE, WIDTH, INDEX)				\
    235  1.3  mrg   TYPE HIDDEN								\
    236  1.3  mrg   __sync_val_compare_and_swap_##WIDTH (TYPE *ptr, TYPE oldval,		\
    237  1.3  mrg 				       TYPE newval)			\
    238  1.3  mrg   {									\
    239  1.3  mrg     TYPE actual_oldval;							\
    240  1.3  mrg     long fail;								\
    241  1.3  mrg 									\
    242  1.3  mrg     while (1)								\
    243  1.3  mrg       {									\
    244  1.3  mrg 	actual_oldval = __atomic_load_n (ptr, __ATOMIC_SEQ_CST);	\
    245  1.3  mrg 									\
    246  1.3  mrg 	if (__builtin_expect (oldval != actual_oldval, 0))		\
    247  1.3  mrg 	  return actual_oldval;						\
    248  1.3  mrg 									\
    249  1.3  mrg 	fail = __kernel_cmpxchg2 (ptr, &actual_oldval, &newval, INDEX);	\
    250  1.3  mrg 									\
    251  1.3  mrg 	if (__builtin_expect (!fail, 1))				\
    252  1.3  mrg 	  return actual_oldval;						\
    253  1.3  mrg       }									\
    254  1.3  mrg   }									\
    255  1.3  mrg 									\
    256  1.3  mrg   bool HIDDEN								\
    257  1.3  mrg   __sync_bool_compare_and_swap_##WIDTH (TYPE *ptr, TYPE oldval,		\
    258  1.3  mrg 					TYPE newval)			\
    259  1.3  mrg   {									\
    260  1.3  mrg     long failure = __kernel_cmpxchg2 (ptr, &oldval, &newval, INDEX);	\
    261  1.3  mrg     return (failure == 0);						\
    262  1.3  mrg   }
    263  1.3  mrg 
    264  1.3  mrg COMPARE_AND_SWAP_2 (long long, 8, 3)
    265  1.3  mrg COMPARE_AND_SWAP_2 (short, 2, 1)
    266  1.3  mrg COMPARE_AND_SWAP_2 (char, 1, 0)
    267  1.1  mrg 
    268  1.1  mrg int HIDDEN
    269  1.1  mrg __sync_val_compare_and_swap_4 (int *ptr, int oldval, int newval)
    270  1.1  mrg {
    271  1.3  mrg   long fail;
    272  1.3  mrg   int actual_oldval;
    273  1.1  mrg 
    274  1.1  mrg   while (1)
    275  1.1  mrg     {
    276  1.3  mrg       actual_oldval = __atomic_load_n (ptr, __ATOMIC_SEQ_CST);
    277  1.1  mrg 
    278  1.1  mrg       if (__builtin_expect (oldval != actual_oldval, 0))
    279  1.1  mrg 	return actual_oldval;
    280  1.1  mrg 
    281  1.3  mrg       fail = __kernel_cmpxchg (ptr, actual_oldval, newval);
    282  1.1  mrg 
    283  1.1  mrg       if (__builtin_expect (!fail, 1))
    284  1.1  mrg 	return actual_oldval;
    285  1.1  mrg     }
    286  1.1  mrg }
    287  1.1  mrg 
    288  1.1  mrg bool HIDDEN
    289  1.1  mrg __sync_bool_compare_and_swap_4 (int *ptr, int oldval, int newval)
    290  1.1  mrg {
    291  1.3  mrg   long failure = __kernel_cmpxchg (ptr, oldval, newval);
    292  1.1  mrg   return (failure == 0);
    293  1.1  mrg }
    294  1.1  mrg 
    295  1.3  mrg #define SYNC_LOCK_TEST_AND_SET_2(TYPE, WIDTH, INDEX)			\
    296  1.3  mrg TYPE HIDDEN								\
    297  1.3  mrg   __sync_lock_test_and_set_##WIDTH (TYPE *ptr, TYPE val)		\
    298  1.1  mrg   {									\
    299  1.3  mrg     TYPE oldval;							\
    300  1.3  mrg     long failure;							\
    301  1.3  mrg 									\
    302  1.3  mrg     do {								\
    303  1.3  mrg       oldval = __atomic_load_n (ptr, __ATOMIC_SEQ_CST);			\
    304  1.3  mrg       failure = __kernel_cmpxchg2 (ptr, &oldval, &val, INDEX);		\
    305  1.3  mrg     } while (failure != 0);						\
    306  1.3  mrg 									\
    307  1.3  mrg     return oldval;							\
    308  1.1  mrg   }
    309  1.1  mrg 
    310  1.3  mrg SYNC_LOCK_TEST_AND_SET_2 (long long, 8, 3)
    311  1.3  mrg SYNC_LOCK_TEST_AND_SET_2 (short, 2, 1)
    312  1.3  mrg SYNC_LOCK_TEST_AND_SET_2 (signed char, 1, 0)
    313  1.1  mrg 
    314  1.1  mrg int HIDDEN
    315  1.1  mrg __sync_lock_test_and_set_4 (int *ptr, int val)
    316  1.1  mrg {
    317  1.3  mrg   long failure;
    318  1.3  mrg   int oldval;
    319  1.1  mrg 
    320  1.1  mrg   do {
    321  1.3  mrg     oldval = __atomic_load_n (ptr, __ATOMIC_SEQ_CST);
    322  1.3  mrg     failure = __kernel_cmpxchg (ptr, oldval, val);
    323  1.1  mrg   } while (failure != 0);
    324  1.1  mrg 
    325  1.1  mrg   return oldval;
    326  1.1  mrg }
    327  1.1  mrg 
    328  1.3  mrg #define SYNC_LOCK_RELEASE_2(TYPE, WIDTH, INDEX)			\
    329  1.3  mrg   void HIDDEN							\
    330  1.3  mrg   __sync_lock_release_##WIDTH (TYPE *ptr)			\
    331  1.3  mrg   {								\
    332  1.3  mrg     TYPE oldval, zero = 0;					\
    333  1.3  mrg     long failure;						\
    334  1.3  mrg 								\
    335  1.3  mrg     do {							\
    336  1.3  mrg       oldval = __atomic_load_n (ptr, __ATOMIC_SEQ_CST);		\
    337  1.3  mrg       failure = __kernel_cmpxchg2 (ptr, &oldval, &zero, INDEX);	\
    338  1.3  mrg     } while (failure != 0);					\
    339  1.1  mrg   }
    340  1.1  mrg 
    341  1.3  mrg SYNC_LOCK_RELEASE_2 (long long, 8, 3)
    342  1.3  mrg SYNC_LOCK_RELEASE_2 (short, 2, 1)
    343  1.3  mrg SYNC_LOCK_RELEASE_2 (signed char, 1, 0)
    344  1.1  mrg 
    345  1.3  mrg void HIDDEN
    346  1.3  mrg __sync_lock_release_4 (int *ptr)
    347  1.3  mrg {
    348  1.3  mrg   long failure;
    349  1.3  mrg   int oldval;
    350  1.1  mrg 
    351  1.3  mrg   do {
    352  1.3  mrg     oldval = __atomic_load_n (ptr, __ATOMIC_SEQ_CST);
    353  1.3  mrg     failure = __kernel_cmpxchg (ptr, oldval, 0);
    354  1.3  mrg   } while (failure != 0);
    355  1.3  mrg }
    356