1251875Speter/* Licensed to the Apache Software Foundation (ASF) under one or more
2251875Speter * contributor license agreements.  See the NOTICE file distributed with
3251875Speter * this work for additional information regarding copyright ownership.
4251875Speter * The ASF licenses this file to You under the Apache License, Version 2.0
5251875Speter * (the "License"); you may not use this file except in compliance with
6251875Speter * the License.  You may obtain a copy of the License at
7251875Speter *
8251875Speter *     http://www.apache.org/licenses/LICENSE-2.0
9251875Speter *
10251875Speter * Unless required by applicable law or agreed to in writing, software
11251875Speter * distributed under the License is distributed on an "AS IS" BASIS,
12251875Speter * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13251875Speter * See the License for the specific language governing permissions and
14251875Speter * limitations under the License.
15251875Speter */
16251875Speter
17251875Speter#include "apr_arch_atomic.h"
18251875Speter
19251875Speter#ifdef USE_ATOMICS_PPC
20251875Speter
21251875Speter#ifdef PPC405_ERRATA
22253734Speter#   define PPC405_ERR77_SYNC   "    sync\n"
23251875Speter#else
24251875Speter#   define PPC405_ERR77_SYNC
25251875Speter#endif
26251875Speter
27251875SpeterAPR_DECLARE(apr_status_t) apr_atomic_init(apr_pool_t *p)
28251875Speter{
29251875Speter    return APR_SUCCESS;
30251875Speter}
31251875Speter
32251875SpeterAPR_DECLARE(apr_uint32_t) apr_atomic_read32(volatile apr_uint32_t *mem)
33251875Speter{
34251875Speter    return *mem;
35251875Speter}
36251875Speter
37251875SpeterAPR_DECLARE(void) apr_atomic_set32(volatile apr_uint32_t *mem, apr_uint32_t val)
38251875Speter{
39251875Speter    *mem = val;
40251875Speter}
41251875Speter
42251875SpeterAPR_DECLARE(apr_uint32_t) apr_atomic_add32(volatile apr_uint32_t *mem, apr_uint32_t val)
43251875Speter{
44251875Speter    apr_uint32_t prev, temp;
45251875Speter
46253734Speter    asm volatile ("1:\n"                       /* lost reservation     */
47253734Speter                  "    lwarx   %0,0,%3\n"      /* load and reserve     */
48253734Speter                  "    add     %1,%0,%4\n"     /* add val and prev     */
49253734Speter                  PPC405_ERR77_SYNC            /* ppc405 Erratum 77    */
50253734Speter                  "    stwcx.  %1,0,%3\n"      /* store new value      */
51253734Speter                  "    bne-    1b\n"           /* loop if lost         */
52251875Speter                  : "=&r" (prev), "=&r" (temp), "=m" (*mem)
53251875Speter                  : "b" (mem), "r" (val)
54251875Speter                  : "cc", "memory");
55251875Speter
56251875Speter    return prev;
57251875Speter}
58251875Speter
59251875SpeterAPR_DECLARE(void) apr_atomic_sub32(volatile apr_uint32_t *mem, apr_uint32_t val)
60251875Speter{
61251875Speter    apr_uint32_t temp;
62251875Speter
63253734Speter    asm volatile ("1:\n"                       /* lost reservation     */
64253734Speter                  "    lwarx   %0,0,%2\n"      /* load and reserve     */
65253734Speter                  "    subf    %0,%3,%0\n"     /* subtract val         */
66253734Speter                  PPC405_ERR77_SYNC            /* ppc405 Erratum 77    */
67253734Speter                  "    stwcx.  %0,0,%2\n"      /* store new value      */
68253734Speter                  "    bne-    1b\n"           /* loop if lost         */
69251875Speter                  : "=&r" (temp), "=m" (*mem)
70251875Speter                  : "b" (mem), "r" (val)
71251875Speter                  : "cc", "memory");
72251875Speter}
73251875Speter
74251875SpeterAPR_DECLARE(apr_uint32_t) apr_atomic_inc32(volatile apr_uint32_t *mem)
75251875Speter{
76251875Speter    apr_uint32_t prev;
77251875Speter
78253734Speter    asm volatile ("1:\n"                       /* lost reservation     */
79253734Speter                  "    lwarx   %0,0,%2\n"      /* load and reserve     */
80253734Speter                  "    addi    %0,%0,1\n"      /* add immediate        */
81253734Speter                  PPC405_ERR77_SYNC            /* ppc405 Erratum 77    */
82253734Speter                  "    stwcx.  %0,0,%2\n"      /* store new value      */
83253734Speter                  "    bne-    1b\n"           /* loop if lost         */
84253734Speter                  "    subi    %0,%0,1\n"      /* return old value     */
85251875Speter                  : "=&b" (prev), "=m" (*mem)
86251875Speter                  : "b" (mem), "m" (*mem)
87251875Speter                  : "cc", "memory");
88251875Speter
89251875Speter    return prev;
90251875Speter}
91251875Speter
92251875SpeterAPR_DECLARE(int) apr_atomic_dec32(volatile apr_uint32_t *mem)
93251875Speter{
94251875Speter    apr_uint32_t prev;
95251875Speter
96253734Speter    asm volatile ("1:\n"                       /* lost reservation     */
97253734Speter                  "    lwarx   %0,0,%2\n"      /* load and reserve     */
98253734Speter                  "    subi    %0,%0,1\n"      /* subtract immediate   */
99253734Speter                  PPC405_ERR77_SYNC            /* ppc405 Erratum 77    */
100253734Speter                  "    stwcx.  %0,0,%2\n"      /* store new value      */
101253734Speter                  "    bne-    1b\n"           /* loop if lost         */
102251875Speter                  : "=&b" (prev), "=m" (*mem)
103251875Speter                  : "b" (mem), "m" (*mem)
104251875Speter                  : "cc", "memory");
105251875Speter
106251875Speter    return prev;
107251875Speter}
108251875Speter
109251875SpeterAPR_DECLARE(apr_uint32_t) apr_atomic_cas32(volatile apr_uint32_t *mem, apr_uint32_t with,
110251875Speter                                           apr_uint32_t cmp)
111251875Speter{
112251875Speter    apr_uint32_t prev;
113251875Speter
114253734Speter    asm volatile ("1:\n"                       /* lost reservation     */
115253734Speter                  "    lwarx   %0,0,%1\n"      /* load and reserve     */
116253734Speter                  "    cmpw    %0,%3\n"        /* compare operands     */
117253734Speter                  "    bne-    exit_%=\n"      /* skip if not equal    */
118253734Speter                  PPC405_ERR77_SYNC            /* ppc405 Erratum 77    */
119253734Speter                  "    stwcx.  %2,0,%1\n"      /* store new value      */
120253734Speter                  "    bne-    1b\n"           /* loop if lost         */
121253734Speter                  "exit_%=:\n"                 /* not equal            */
122251875Speter                  : "=&r" (prev)
123251875Speter                  : "b" (mem), "r" (with), "r" (cmp)
124251875Speter                  : "cc", "memory");
125251875Speter
126251875Speter    return prev;
127251875Speter}
128251875Speter
129251875SpeterAPR_DECLARE(apr_uint32_t) apr_atomic_xchg32(volatile apr_uint32_t *mem, apr_uint32_t val)
130251875Speter{
131251875Speter    apr_uint32_t prev;
132251875Speter
133253734Speter    asm volatile ("1:\n"                       /* lost reservation     */
134253734Speter                  "    lwarx   %0,0,%1\n"      /* load and reserve     */
135253734Speter                  PPC405_ERR77_SYNC            /* ppc405 Erratum 77    */
136253734Speter                  "    stwcx.  %2,0,%1\n"      /* store new value      */
137253734Speter                  "    bne-    1b"             /* loop if lost         */
138251875Speter                  : "=&r" (prev)
139251875Speter                  : "b" (mem), "r" (val)
140251875Speter                  : "cc", "memory");
141251875Speter
142251875Speter    return prev;
143251875Speter}
144251875Speter
145251875SpeterAPR_DECLARE(void*) apr_atomic_casptr(volatile void **mem, void *with, const void *cmp)
146251875Speter{
147251875Speter    void *prev;
148251875Speter#if APR_SIZEOF_VOIDP == 4
149253734Speter    asm volatile ("1:\n"                       /* lost reservation     */
150253734Speter                  "    lwarx   %0,0,%1\n"      /* load and reserve     */
151253734Speter                  "    cmpw    %0,%3\n"        /* compare operands     */
152253734Speter                  "    bne-    2f\n"           /* skip if not equal    */
153253734Speter                  PPC405_ERR77_SYNC            /* ppc405 Erratum 77    */
154253734Speter                  "    stwcx.  %2,0,%1\n"      /* store new value      */
155253734Speter                  "    bne-    1b\n"           /* loop if lost         */
156253734Speter                  "2:\n"                       /* not equal            */
157251875Speter                  : "=&r" (prev)
158251875Speter                  : "b" (mem), "r" (with), "r" (cmp)
159251875Speter                  : "cc", "memory");
160251875Speter#elif APR_SIZEOF_VOIDP == 8
161253734Speter    asm volatile ("1:\n"                       /* lost reservation     */
162253734Speter                  "    ldarx   %0,0,%1\n"      /* load and reserve     */
163253734Speter                  "    cmpd    %0,%3\n"        /* compare operands     */
164253734Speter                  "    bne-    2f\n"           /* skip if not equal    */
165253734Speter                  PPC405_ERR77_SYNC            /* ppc405 Erratum 77    */
166253734Speter                  "    stdcx.  %2,0,%1\n"      /* store new value      */
167253734Speter                  "    bne-    1b\n"           /* loop if lost         */
168253734Speter                  "2:\n"                       /* not equal            */
169251875Speter                  : "=&r" (prev)
170251875Speter                  : "b" (mem), "r" (with), "r" (cmp)
171251875Speter                  : "cc", "memory");
172251875Speter#else
173251875Speter#error APR_SIZEOF_VOIDP value not supported
174251875Speter#endif
175251875Speter    return prev;
176251875Speter}
177251875Speter
178251875SpeterAPR_DECLARE(void*) apr_atomic_xchgptr(volatile void **mem, void *with)
179251875Speter{
180251875Speter    void *prev;
181251875Speter#if APR_SIZEOF_VOIDP == 4
182253734Speter    asm volatile ("1:\n"                       /* lost reservation     */
183253734Speter                  "    lwarx   %0,0,%1\n"      /* load and reserve     */
184253734Speter                  PPC405_ERR77_SYNC            /* ppc405 Erratum 77    */
185253734Speter                  "    stwcx.  %2,0,%1\n"      /* store new value      */
186253734Speter                  "    bne-    1b\n"           /* loop if lost         */
187253734Speter                  "    isync\n"                /* memory barrier       */
188251875Speter                  : "=&r" (prev)
189251875Speter                  : "b" (mem), "r" (with)
190251875Speter                  : "cc", "memory");
191251875Speter#elif APR_SIZEOF_VOIDP == 8
192253734Speter    asm volatile ("1:\n"                       /* lost reservation     */
193253734Speter                  "    ldarx   %0,0,%1\n"      /* load and reserve     */
194253734Speter                  PPC405_ERR77_SYNC            /* ppc405 Erratum 77    */
195253734Speter                  "    stdcx.  %2,0,%1\n"      /* store new value      */
196253734Speter                  "    bne-    1b\n"           /* loop if lost         */
197253734Speter                  "    isync\n"                /* memory barrier       */
198251875Speter                  : "=&r" (prev)
199251875Speter                  : "b" (mem), "r" (with)
200251875Speter                  : "cc", "memory");
201251875Speter#else
202251875Speter#error APR_SIZEOF_VOIDP value not supported
203251875Speter#endif
204251875Speter    return prev;
205251875Speter}
206251875Speter
207251875Speter#endif /* USE_ATOMICS_PPC */
208