Imported Upstream version 3.2.2
[debian/gnuradio] / gcell / lib / runtime / gc_jd_stack.c
1 /* -*- c -*- */
2 /*
3  * Copyright 2007 Free Software Foundation, Inc.
4  * 
5  * This file is part of GNU Radio
6  * 
7  * GNU Radio is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3, or (at your option)
10  * any later version.
11  * 
12  * GNU Radio is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License along
18  * with this program; if not, write to the Free Software Foundation, Inc.,
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20  */
21
22 #include <gcell/gc_jd_stack.h>
23 #include <gcell/memory_barrier.h>
24
25 /*
26  * begin extract from ppu_intrinics.h
27  * FIXME handle this a different way
28  */
29
30 #if !defined(__PPU__) && !defined(__ppc__) && !defined(__ppc64__)
31     && !defined(__GNUC__)
32   #error ppu_intrinsics.h included on wrong platform/compiler
33 #endif
34
35 #define __lwarx(base) __extension__             \
36   ({unsigned int result;                        \
37     typedef  struct {char a[4];} wordsize;      \
38     wordsize *ptrp = (wordsize*)(base);         \
39   __asm__ volatile ("lwarx %0,%y1"              \
40            : "=r" (result)                      \
41            : "Z" (*ptrp));                      \
42   result; })
43
44 #ifdef __powerpc64__
45 #define __ldarx(base) __extension__                     \
46   ({unsigned long long result;                          \
47     typedef  struct {char a[8];} doublewordsize;        \
48     doublewordsize *ptrp = (doublewordsize*)(base);     \
49   __asm__ volatile ("ldarx %0,%y1"                      \
50            : "=r" (result)                              \
51            : "Z" (*ptrp));                              \
52   result; })
53 #endif /* __powerpc64__ */
54
55 #define __stwcx(base, value) __extension__      \
56   ({unsigned int result;                        \
57     typedef  struct {char a[4];} wordsize;      \
58     wordsize *ptrp = (wordsize*)(base);         \
59   __asm__ volatile ("stwcx. %2,%y1\n"           \
60            "\tmfocrf %0,0x80"                   \
61            : "=r" (result),                     \
62              "=Z" (*ptrp)                       \
63            : "r" (value));                      \
64   ((result & 0x20000000) >> 29); })
65
66
67 #ifdef __powerpc64__
68 #define __stdcx(base, value) __extension__              \
69   ({unsigned long long result;                          \
70     typedef  struct {char a[8];} doublewordsize;        \
71     doublewordsize *ptrp = (doublewordsize*)(base);     \
72   __asm__ volatile ("stdcx. %2,%y1\n"                   \
73            "\tmfocrf %0,0x80"                           \
74            : "=r" (result),                             \
75              "=Z" (*ptrp)                               \
76            : "r" (value));                              \
77   ((result & 0x20000000) >> 29); })
78 #endif /* __powerpc64__ */
79
80
81 /*
82  * --- end extract from ppu_intrinics.h --
83  */
84
85
86 void 
87 gc_jd_stack_init(gc_jd_stack_t *stack)
88 {
89   stack->top = 0;
90 }
91   
92
93 #ifdef __powerpc64__  // 64-bit mode
94
95 void 
96 gc_jd_stack_push(gc_jd_stack_t *stack, gc_job_desc_t *item)
97 {
98   gc_eaddr_t    top;
99   gc_eaddr_t    item_ea = ptr_to_ea(item);
100   unsigned int  done;
101
102   do {
103     top = __ldarx(&stack->top);
104     item->sys.next = top;
105     smp_wmb();        // order store of item->next before store of stack->top
106     done = __stdcx(&stack->top, item_ea);
107   } while (unlikely(done == 0));
108 }
109
110 gc_job_desc_t *
111 gc_jd_stack_pop(gc_jd_stack_t *stack)
112 {
113   gc_eaddr_t    s;
114   gc_eaddr_t    t;
115   unsigned int  done;
116
117   do {
118     s  = __ldarx(&stack->top);
119     if (s == 0)                 /* stack's empty */
120       return 0;
121     t = ((gc_job_desc_t *) ea_to_ptr(s))->sys.next;
122     done = __stdcx(&stack->top, t);
123   } while (unlikely(done == 0));
124
125   return ea_to_ptr(s);
126 }
127
128 #else  // 32-bit mode
129
130 /*
131  * In 32-bit mode, gc_eaddr's will have the top 32-bits zero.
132  * The ldarx/stdcx instructions aren't available in 32-bit mode,
133  * thus we use lwarx/stwcx on the low 32-bits of the 64-bit addresses.
134  * Since we're big-endian, the low 32-bits are at word offset 1.
135  */
136 void 
137 gc_jd_stack_push(gc_jd_stack_t *stack, gc_job_desc_t *item)
138 {
139   gc_eaddr_t    top;
140   unsigned int  done;
141
142   do {
143     top = __lwarx((int32_t *)(&stack->top) + 1);
144     item->sys.next = top;
145     smp_wmb();        // order store of item->sys.next before store of stack->top
146     done = __stwcx((int32_t *)(&stack->top) + 1, item);
147   } while (unlikely(done == 0));
148 }
149
150 gc_job_desc_t *
151 gc_jd_stack_pop(gc_jd_stack_t *stack)
152 {
153   gc_eaddr_t    s;
154   gc_eaddr_t    t;
155   unsigned int  done;
156
157   do {
158     s  = __lwarx((int32_t *)(&stack->top) + 1);
159     if (s == 0)                 /* stack's empty */
160       return 0;
161     t = ((gc_job_desc_t *) ea_to_ptr(s))->sys.next;
162     done = __stwcx((int32_t *)(&stack->top) + 1, (uint32_t) t);
163   } while (unlikely(done == 0));
164
165   return ea_to_ptr(s);
166 }
167
168 #endif