OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libgcc/] [config/] [pa/] [linux-atomic.c] - Blame information for rev 866

Go to most recent revision | Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.