Merge with /home/git/u-boot
[platform/kernel/u-boot.git] / drivers / bcm570x_queue.h
1
2 /******************************************************************************/
3 /*                                                                            */
4 /* Broadcom BCM5700 Linux Network Driver, Copyright (c) 2000 Broadcom         */
5 /* Corporation.                                                               */
6 /* All rights reserved.                                                       */
7 /*                                                                            */
8 /* This program is free software; you can redistribute it and/or modify       */
9 /* it under the terms of the GNU General Public License as published by       */
10 /* the Free Software Foundation, located in the file LICENSE.                 */
11 /*                                                                            */
12 /* Queue functions.                                                           */
13 /*    void          QQ_InitQueue(PQQ_CONTAINER pQueue)                        */
14 /*    char          QQ_Full(PQQ_CONTAINER pQueue)                             */
15 /*    char          QQ_Empty(PQQ_CONTAINER pQueue)                            */
16 /*    unsigned int QQ_GetSize(PQQ_CONTAINER pQueue)                          */
17 /*    unsigned int QQ_GetEntryCnt(PQQ_CONTAINER pQueue)                      */
18 /*    char          QQ_PushHead(PQQ_CONTAINER pQueue, PQQ_ENTRY pEntry)       */
19 /*    char          QQ_PushTail(PQQ_CONTAINER pQueue, PQQ_ENTRY pEntry)       */
20 /*    PQQ_ENTRY     QQ_PopHead(PQQ_CONTAINER pQueue)                          */
21 /*    PQQ_ENTRY     QQ_PopTail(PQQ_CONTAINER pQueue)                          */
22 /*    PQQ_ENTRY     QQ_GetHead(PQQ_CONTAINER pQueue, unsigned int Idx)       */
23 /*    PQQ_ENTRY     QQ_GetTail(PQQ_CONTAINER pQueue, unsigned int Idx)       */
24 /*                                                                            */
25 /*                                                                            */
26 /* History:                                                                   */
27 /*    02/25/00 Hav Khauv        Initial version.                              */
28 /******************************************************************************/
29
30 #ifndef BCM_QUEUE_H
31 #define BCM_QUEUE_H
32 #ifndef EMBEDDED
33 #define EMBEDDED 1
34 #endif
35
36 /******************************************************************************/
37 /* Queue definitions. */
38 /******************************************************************************/
39
40 /* Entry for queueing. */
41 typedef void *PQQ_ENTRY;
42
43 /* Linux Atomic Ops support */
44 typedef struct { int counter; } atomic_t;
45
46
47 /*
48  * This combination of `inline' and `extern' has almost the effect of a
49  * macro.  The way to use it is to put a function definition in a header
50  * file with these keywords, and put another copy of the definition
51  * (lacking `inline' and `extern') in a library file.  The definition in
52  * the header file will cause most calls to the function to be inlined.
53  * If any uses of the function remain, they will refer to the single copy
54  * in the library.
55  */
56 extern __inline void
57 atomic_set(atomic_t* entry, int val)
58 {
59     entry->counter = val;
60 }
61 extern __inline int
62 atomic_read(atomic_t* entry)
63 {
64     return entry->counter;
65 }
66 extern __inline void
67 atomic_inc(atomic_t* entry)
68 {
69     if(entry)
70         entry->counter++;
71 }
72
73 extern __inline void
74 atomic_dec(atomic_t* entry)
75 {
76     if(entry)
77         entry->counter--;
78 }
79
80 extern __inline void
81 atomic_sub(int a, atomic_t* entry)
82 {
83     if(entry)
84         entry->counter -= a;
85 }
86 extern __inline void
87 atomic_add(int a, atomic_t* entry)
88 {
89     if(entry)
90         entry->counter += a;
91 }
92
93
94 /* Queue header -- base type. */
95 typedef struct {
96     unsigned int Head;
97     unsigned int Tail;
98     unsigned int Size;
99     atomic_t EntryCnt;
100     PQQ_ENTRY Array[1];
101 } QQ_CONTAINER, *PQQ_CONTAINER;
102
103
104 /* Declare queue type macro. */
105 #define DECLARE_QUEUE_TYPE(_QUEUE_TYPE, _QUEUE_SIZE)            \
106                                                                 \
107     typedef struct {                                            \
108         QQ_CONTAINER Container;                                 \
109         PQQ_ENTRY EntryBuffer[_QUEUE_SIZE];                     \
110     } _QUEUE_TYPE, *P##_QUEUE_TYPE
111
112
113 /******************************************************************************/
114 /* Compilation switches. */
115 /******************************************************************************/
116
117 #if DBG
118 #undef QQ_NO_OVERFLOW_CHECK
119 #undef QQ_NO_UNDERFLOW_CHECK
120 #endif /* DBG */
121
122 #ifdef QQ_USE_MACROS
123 /* notdone */
124 #else
125
126 #ifdef QQ_NO_INLINE
127 #define __inline
128 #endif /* QQ_NO_INLINE */
129
130 /******************************************************************************/
131 /* Description:                                                               */
132 /*                                                                            */
133 /* Return:                                                                    */
134 /******************************************************************************/
135 extern __inline void
136 QQ_InitQueue(
137 PQQ_CONTAINER pQueue,
138 unsigned int QueueSize) {
139     pQueue->Head = 0;
140     pQueue->Tail = 0;
141     pQueue->Size = QueueSize+1;
142     atomic_set(&pQueue->EntryCnt, 0);
143 } /* QQ_InitQueue */
144
145
146 /******************************************************************************/
147 /* Description:                                                               */
148 /*                                                                            */
149 /* Return:                                                                    */
150 /******************************************************************************/
151 extern __inline char
152 QQ_Full(
153 PQQ_CONTAINER pQueue) {
154     unsigned int NewHead;
155
156     NewHead = (pQueue->Head + 1) % pQueue->Size;
157
158     return(NewHead == pQueue->Tail);
159 } /* QQ_Full */
160
161
162 /******************************************************************************/
163 /* Description:                                                               */
164 /*                                                                            */
165 /* Return:                                                                    */
166 /******************************************************************************/
167 extern __inline char
168 QQ_Empty(
169 PQQ_CONTAINER pQueue) {
170     return(pQueue->Head == pQueue->Tail);
171 } /* QQ_Empty */
172
173
174 /******************************************************************************/
175 /* Description:                                                               */
176 /*                                                                            */
177 /* Return:                                                                    */
178 /******************************************************************************/
179 extern __inline unsigned int
180 QQ_GetSize(
181 PQQ_CONTAINER pQueue) {
182     return pQueue->Size;
183 } /* QQ_GetSize */
184
185
186 /******************************************************************************/
187 /* Description:                                                               */
188 /*                                                                            */
189 /* Return:                                                                    */
190 /******************************************************************************/
191 extern __inline unsigned int
192 QQ_GetEntryCnt(
193 PQQ_CONTAINER pQueue) {
194     return atomic_read(&pQueue->EntryCnt);
195 } /* QQ_GetEntryCnt */
196
197
198 /******************************************************************************/
199 /* Description:                                                               */
200 /*                                                                            */
201 /* Return:                                                                    */
202 /*    TRUE entry was added successfully.                                      */
203 /*    FALSE queue is full.                                                    */
204 /******************************************************************************/
205 extern __inline char
206 QQ_PushHead(
207 PQQ_CONTAINER pQueue,
208 PQQ_ENTRY pEntry) {
209     unsigned int Head;
210
211     Head = (pQueue->Head + 1) % pQueue->Size;
212
213 #if !defined(QQ_NO_OVERFLOW_CHECK)
214     if(Head == pQueue->Tail) {
215         return 0;
216     } /* if */
217 #endif /* QQ_NO_OVERFLOW_CHECK */
218
219     pQueue->Array[pQueue->Head] = pEntry;
220     wmb();
221     pQueue->Head = Head;
222     atomic_inc(&pQueue->EntryCnt);
223
224     return -1;
225 } /* QQ_PushHead */
226
227
228 /******************************************************************************/
229 /* Description:                                                               */
230 /*                                                                            */
231 /* Return:                                                                    */
232 /*    TRUE entry was added successfully.                                      */
233 /*    FALSE queue is full.                                                    */
234 /******************************************************************************/
235 extern __inline char
236 QQ_PushTail(
237 PQQ_CONTAINER pQueue,
238 PQQ_ENTRY pEntry) {
239     unsigned int Tail;
240
241     Tail = pQueue->Tail;
242     if(Tail == 0) {
243         Tail = pQueue->Size;
244     } /* if */
245     Tail--;
246
247 #if !defined(QQ_NO_OVERFLOW_CHECK)
248     if(Tail == pQueue->Head) {
249         return 0;
250     } /* if */
251 #endif /* QQ_NO_OVERFLOW_CHECK */
252
253     pQueue->Array[Tail] = pEntry;
254     wmb();
255     pQueue->Tail = Tail;
256     atomic_inc(&pQueue->EntryCnt);
257
258     return -1;
259 } /* QQ_PushTail */
260
261
262 /******************************************************************************/
263 /* Description:                                                               */
264 /*                                                                            */
265 /* Return:                                                                    */
266 /******************************************************************************/
267 extern __inline PQQ_ENTRY
268 QQ_PopHead(
269 PQQ_CONTAINER pQueue) {
270     unsigned int Head;
271     PQQ_ENTRY Entry;
272
273     Head = pQueue->Head;
274
275 #if !defined(QQ_NO_UNDERFLOW_CHECK)
276     if(Head == pQueue->Tail) {
277         return (PQQ_ENTRY) 0;
278     } /* if */
279 #endif /* QQ_NO_UNDERFLOW_CHECK */
280
281     if(Head == 0) {
282         Head = pQueue->Size;
283     } /* if */
284     Head--;
285
286     Entry = pQueue->Array[Head];
287 #ifdef EMBEDDED
288     membar();
289 #else
290     mb();
291 #endif
292     pQueue->Head = Head;
293     atomic_dec(&pQueue->EntryCnt);
294
295     return Entry;
296 } /* QQ_PopHead */
297
298
299 /******************************************************************************/
300 /* Description:                                                               */
301 /*                                                                            */
302 /* Return:                                                                    */
303 /******************************************************************************/
304 extern __inline PQQ_ENTRY
305 QQ_PopTail(
306 PQQ_CONTAINER pQueue) {
307     unsigned int Tail;
308     PQQ_ENTRY Entry;
309
310     Tail = pQueue->Tail;
311
312 #if !defined(QQ_NO_UNDERFLOW_CHECK)
313     if(Tail == pQueue->Head) {
314         return (PQQ_ENTRY) 0;
315     } /* if */
316 #endif /* QQ_NO_UNDERFLOW_CHECK */
317
318     Entry = pQueue->Array[Tail];
319 #ifdef EMBEDDED
320     membar();
321 #else
322     mb();
323 #endif
324     pQueue->Tail = (Tail + 1) % pQueue->Size;
325     atomic_dec(&pQueue->EntryCnt);
326
327     return Entry;
328 } /* QQ_PopTail */
329
330
331 /******************************************************************************/
332 /* Description:                                                               */
333 /*                                                                            */
334 /* Return:                                                                    */
335 /******************************************************************************/
336 extern __inline PQQ_ENTRY
337 QQ_GetHead(
338     PQQ_CONTAINER pQueue,
339     unsigned int Idx)
340 {
341     if(Idx >= atomic_read(&pQueue->EntryCnt))
342     {
343         return (PQQ_ENTRY) 0;
344     }
345
346     if(pQueue->Head > Idx)
347     {
348         Idx = pQueue->Head - Idx;
349     }
350     else
351     {
352         Idx = pQueue->Size - (Idx - pQueue->Head);
353     }
354     Idx--;
355
356     return pQueue->Array[Idx];
357 }
358
359
360 /******************************************************************************/
361 /* Description:                                                               */
362 /*                                                                            */
363 /* Return:                                                                    */
364 /******************************************************************************/
365 extern __inline PQQ_ENTRY
366 QQ_GetTail(
367     PQQ_CONTAINER pQueue,
368     unsigned int Idx)
369 {
370     if(Idx >= atomic_read(&pQueue->EntryCnt))
371     {
372         return (PQQ_ENTRY) 0;
373     }
374
375     Idx += pQueue->Tail;
376     if(Idx >= pQueue->Size)
377     {
378         Idx = Idx - pQueue->Size;
379     }
380
381     return pQueue->Array[Idx];
382 }
383
384 #endif /* QQ_USE_MACROS */
385
386
387 #endif /* QUEUE_H */