1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifndef ANDROID_CUTILS_ATOMIC_MIPS_H
18#define ANDROID_CUTILS_ATOMIC_MIPS_H
19
20#include <stdint.h>
21
22#ifndef ANDROID_ATOMIC_INLINE
23#define ANDROID_ATOMIC_INLINE inline __attribute__((always_inline))
24#endif
25
26extern ANDROID_ATOMIC_INLINE void android_compiler_barrier(void)
27{
28    __asm__ __volatile__ ("" : : : "memory");
29}
30
31#if ANDROID_SMP == 0
32extern ANDROID_ATOMIC_INLINE void android_memory_barrier(void)
33{
34    android_compiler_barrier();
35}
36extern ANDROID_ATOMIC_INLINE void android_memory_store_barrier(void)
37{
38    android_compiler_barrier();
39}
40#else
41extern ANDROID_ATOMIC_INLINE void android_memory_barrier(void)
42{
43    __asm__ __volatile__ ("sync" : : : "memory");
44}
45extern ANDROID_ATOMIC_INLINE void android_memory_store_barrier(void)
46{
47    __asm__ __volatile__ ("sync" : : : "memory");
48}
49#endif
50
51extern ANDROID_ATOMIC_INLINE int32_t
52android_atomic_acquire_load(volatile const int32_t *ptr)
53{
54    int32_t value = *ptr;
55    android_memory_barrier();
56    return value;
57}
58
59extern ANDROID_ATOMIC_INLINE int32_t
60android_atomic_release_load(volatile const int32_t *ptr)
61{
62    android_memory_barrier();
63    return *ptr;
64}
65
66extern ANDROID_ATOMIC_INLINE void
67android_atomic_acquire_store(int32_t value, volatile int32_t *ptr)
68{
69    *ptr = value;
70    android_memory_barrier();
71}
72
73extern ANDROID_ATOMIC_INLINE void
74android_atomic_release_store(int32_t value, volatile int32_t *ptr)
75{
76    android_memory_barrier();
77    *ptr = value;
78}
79
80extern ANDROID_ATOMIC_INLINE int
81android_atomic_cas(int32_t old_value, int32_t new_value, volatile int32_t *ptr)
82{
83    int32_t prev, status;
84    do {
85        __asm__ __volatile__ (
86            "    ll     %[prev], (%[ptr])\n"
87            "    li     %[status], 1\n"
88            "    bne    %[prev], %[old], 9f\n"
89            "    move   %[status], %[new_value]\n"
90            "    sc     %[status], (%[ptr])\n"
91            "9:\n"
92            : [prev] "=&r" (prev), [status] "=&r" (status)
93            : [ptr] "r" (ptr), [old] "r" (old_value), [new_value] "r" (new_value)
94            );
95    } while (__builtin_expect(status == 0, 0));
96    return prev != old_value;
97}
98
99extern ANDROID_ATOMIC_INLINE int
100android_atomic_acquire_cas(int32_t old_value,
101                           int32_t new_value,
102                           volatile int32_t *ptr)
103{
104    int status = android_atomic_cas(old_value, new_value, ptr);
105    android_memory_barrier();
106    return status;
107}
108
109extern ANDROID_ATOMIC_INLINE int
110android_atomic_release_cas(int32_t old_value,
111                           int32_t new_value,
112                           volatile int32_t *ptr)
113{
114    android_memory_barrier();
115    return android_atomic_cas(old_value, new_value, ptr);
116}
117
118
119extern ANDROID_ATOMIC_INLINE int32_t
120android_atomic_swap(int32_t new_value, volatile int32_t *ptr)
121{
122    int32_t prev, status;
123    do {
124    __asm__ __volatile__ (
125        "    move %[status], %[new_value]\n"
126        "    ll %[prev], (%[ptr])\n"
127        "    sc %[status], (%[ptr])\n"
128        : [prev] "=&r" (prev), [status] "=&r" (status)
129        : [ptr] "r" (ptr), [new_value] "r" (new_value)
130        );
131    } while (__builtin_expect(status == 0, 0));
132    android_memory_barrier();
133    return prev;
134}
135
136extern ANDROID_ATOMIC_INLINE int32_t
137android_atomic_add(int32_t increment, volatile int32_t *ptr)
138{
139    int32_t prev, status;
140    android_memory_barrier();
141    do {
142        __asm__ __volatile__ (
143        "    ll    %[prev], (%[ptr])\n"
144        "    addu  %[status], %[prev], %[inc]\n"
145        "    sc    %[status], (%[ptr])\n"
146        :  [status] "=&r" (status), [prev] "=&r" (prev)
147        :  [ptr] "r" (ptr), [inc] "Ir" (increment)
148        );
149    } while (__builtin_expect(status == 0, 0));
150    return prev;
151}
152
153extern ANDROID_ATOMIC_INLINE int32_t
154android_atomic_inc(volatile int32_t *addr)
155{
156    return android_atomic_add(1, addr);
157}
158
159extern ANDROID_ATOMIC_INLINE int32_t
160android_atomic_dec(volatile int32_t *addr)
161{
162    return android_atomic_add(-1, addr);
163}
164
165extern ANDROID_ATOMIC_INLINE int32_t
166android_atomic_and(int32_t value, volatile int32_t *ptr)
167{
168    int32_t prev, status;
169    android_memory_barrier();
170    do {
171        __asm__ __volatile__ (
172        "    ll    %[prev], (%[ptr])\n"
173        "    and   %[status], %[prev], %[value]\n"
174        "    sc    %[status], (%[ptr])\n"
175        : [prev] "=&r" (prev), [status] "=&r" (status)
176        : [ptr] "r" (ptr), [value] "Ir" (value)
177            );
178    } while (__builtin_expect(status == 0, 0));
179    return prev;
180}
181
182extern ANDROID_ATOMIC_INLINE int32_t
183android_atomic_or(int32_t value, volatile int32_t *ptr)
184{
185    int32_t prev, status;
186    android_memory_barrier();
187    do {
188        __asm__ __volatile__ (
189        "    ll    %[prev], (%[ptr])\n"
190        "    or    %[status], %[prev], %[value]\n"
191        "    sc    %[status], (%[ptr])\n"
192        : [prev] "=&r" (prev), [status] "=&r" (status)
193        : [ptr] "r" (ptr), [value] "Ir" (value)
194            );
195    } while (__builtin_expect(status == 0, 0));
196    return prev;
197}
198
199#endif /* ANDROID_CUTILS_ATOMIC_MIPS_H */
200