blob: bc32ad70f2db77598a687b19027701b652c272b3 [file] [log] [blame]
wdenkc6097192002-11-03 00:24:07 +00001
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. */
41typedef void *PQQ_ENTRY;
42
43/* Linux Atomic Ops support */
44typedef 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 */
56extern __inline void
57atomic_set(atomic_t* entry, int val)
58{
59 entry->counter = val;
60}
61extern __inline int
62atomic_read(atomic_t* entry)
63{
64 return entry->counter;
65}
66extern __inline void
67atomic_inc(atomic_t* entry)
68{
69 if(entry)
70 entry->counter++;
71}
72
73extern __inline void
74atomic_dec(atomic_t* entry)
75{
76 if(entry)
77 entry->counter--;
78}
79
80extern __inline void
81atomic_sub(int a, atomic_t* entry)
82{
83 if(entry)
84 entry->counter -= a;
85}
86extern __inline void
87atomic_add(int a, atomic_t* entry)
88{
89 if(entry)
90 entry->counter += a;
91}
92
93
94/* Queue header -- base type. */
95typedef 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/******************************************************************************/
115/* Compilation switches. */
116/******************************************************************************/
117
118#if DBG
119#undef QQ_NO_OVERFLOW_CHECK
120#undef QQ_NO_UNDERFLOW_CHECK
121#endif /* DBG */
122
123#ifdef QQ_USE_MACROS
124/* notdone */
125#else
126
127#ifdef QQ_NO_INLINE
128#define __inline
129#endif /* QQ_NO_INLINE */
130
131/******************************************************************************/
132/* Description: */
133/* */
134/* Return: */
135/******************************************************************************/
136extern __inline void
137QQ_InitQueue(
138PQQ_CONTAINER pQueue,
139unsigned int QueueSize) {
140 pQueue->Head = 0;
141 pQueue->Tail = 0;
142 pQueue->Size = QueueSize+1;
143 atomic_set(&pQueue->EntryCnt, 0);
144} /* QQ_InitQueue */
145
146
147
148/******************************************************************************/
149/* Description: */
150/* */
151/* Return: */
152/******************************************************************************/
153extern __inline char
154QQ_Full(
155PQQ_CONTAINER pQueue) {
156 unsigned int NewHead;
157
158 NewHead = (pQueue->Head + 1) % pQueue->Size;
159
160 return(NewHead == pQueue->Tail);
161} /* QQ_Full */
162
163
164
165/******************************************************************************/
166/* Description: */
167/* */
168/* Return: */
169/******************************************************************************/
170extern __inline char
171QQ_Empty(
172PQQ_CONTAINER pQueue) {
173 return(pQueue->Head == pQueue->Tail);
174} /* QQ_Empty */
175
176
177
178/******************************************************************************/
179/* Description: */
180/* */
181/* Return: */
182/******************************************************************************/
183extern __inline unsigned int
184QQ_GetSize(
185PQQ_CONTAINER pQueue) {
186 return pQueue->Size;
187} /* QQ_GetSize */
188
189
190
191/******************************************************************************/
192/* Description: */
193/* */
194/* Return: */
195/******************************************************************************/
196extern __inline unsigned int
197QQ_GetEntryCnt(
198PQQ_CONTAINER pQueue) {
199 return atomic_read(&pQueue->EntryCnt);
200} /* QQ_GetEntryCnt */
201
202
203
204/******************************************************************************/
205/* Description: */
206/* */
207/* Return: */
208/* TRUE entry was added successfully. */
209/* FALSE queue is full. */
210/******************************************************************************/
211extern __inline char
212QQ_PushHead(
213PQQ_CONTAINER pQueue,
214PQQ_ENTRY pEntry) {
215 unsigned int Head;
216
217 Head = (pQueue->Head + 1) % pQueue->Size;
218
219#if !defined(QQ_NO_OVERFLOW_CHECK)
220 if(Head == pQueue->Tail) {
221 return 0;
222 } /* if */
223#endif /* QQ_NO_OVERFLOW_CHECK */
224
225 pQueue->Array[pQueue->Head] = pEntry;
226 wmb();
227 pQueue->Head = Head;
228 atomic_inc(&pQueue->EntryCnt);
229
230 return -1;
231} /* QQ_PushHead */
232
233
234
235/******************************************************************************/
236/* Description: */
237/* */
238/* Return: */
239/* TRUE entry was added successfully. */
240/* FALSE queue is full. */
241/******************************************************************************/
242extern __inline char
243QQ_PushTail(
244PQQ_CONTAINER pQueue,
245PQQ_ENTRY pEntry) {
246 unsigned int Tail;
247
248 Tail = pQueue->Tail;
249 if(Tail == 0) {
250 Tail = pQueue->Size;
251 } /* if */
252 Tail--;
253
254#if !defined(QQ_NO_OVERFLOW_CHECK)
255 if(Tail == pQueue->Head) {
256 return 0;
257 } /* if */
258#endif /* QQ_NO_OVERFLOW_CHECK */
259
260 pQueue->Array[Tail] = pEntry;
261 wmb();
262 pQueue->Tail = Tail;
263 atomic_inc(&pQueue->EntryCnt);
264
265 return -1;
266} /* QQ_PushTail */
267
268
269
270/******************************************************************************/
271/* Description: */
272/* */
273/* Return: */
274/******************************************************************************/
275extern __inline PQQ_ENTRY
276QQ_PopHead(
277PQQ_CONTAINER pQueue) {
278 unsigned int Head;
279 PQQ_ENTRY Entry;
280
281 Head = pQueue->Head;
282
283#if !defined(QQ_NO_UNDERFLOW_CHECK)
284 if(Head == pQueue->Tail) {
285 return (PQQ_ENTRY) 0;
286 } /* if */
287#endif /* QQ_NO_UNDERFLOW_CHECK */
288
289 if(Head == 0) {
290 Head = pQueue->Size;
291 } /* if */
292 Head--;
293
294 Entry = pQueue->Array[Head];
295#ifdef EMBEDDED
296 membar();
297#else
298 mb();
299#endif
300 pQueue->Head = Head;
301 atomic_dec(&pQueue->EntryCnt);
302
303 return Entry;
304} /* QQ_PopHead */
305
306
307
308/******************************************************************************/
309/* Description: */
310/* */
311/* Return: */
312/******************************************************************************/
313extern __inline PQQ_ENTRY
314QQ_PopTail(
315PQQ_CONTAINER pQueue) {
316 unsigned int Tail;
317 PQQ_ENTRY Entry;
318
319 Tail = pQueue->Tail;
320
321#if !defined(QQ_NO_UNDERFLOW_CHECK)
322 if(Tail == pQueue->Head) {
323 return (PQQ_ENTRY) 0;
324 } /* if */
325#endif /* QQ_NO_UNDERFLOW_CHECK */
326
327 Entry = pQueue->Array[Tail];
328#ifdef EMBEDDED
329 membar();
330#else
331 mb();
332#endif
333 pQueue->Tail = (Tail + 1) % pQueue->Size;
334 atomic_dec(&pQueue->EntryCnt);
335
336 return Entry;
337} /* QQ_PopTail */
338
339
340
341/******************************************************************************/
342/* Description: */
343/* */
344/* Return: */
345/******************************************************************************/
346extern __inline PQQ_ENTRY
347QQ_GetHead(
348 PQQ_CONTAINER pQueue,
349 unsigned int Idx)
350{
351 if(Idx >= atomic_read(&pQueue->EntryCnt))
352 {
353 return (PQQ_ENTRY) 0;
354 }
355
356 if(pQueue->Head > Idx)
357 {
358 Idx = pQueue->Head - Idx;
359 }
360 else
361 {
362 Idx = pQueue->Size - (Idx - pQueue->Head);
363 }
364 Idx--;
365
366 return pQueue->Array[Idx];
367}
368
369
370
371/******************************************************************************/
372/* Description: */
373/* */
374/* Return: */
375/******************************************************************************/
376extern __inline PQQ_ENTRY
377QQ_GetTail(
378 PQQ_CONTAINER pQueue,
379 unsigned int Idx)
380{
381 if(Idx >= atomic_read(&pQueue->EntryCnt))
382 {
383 return (PQQ_ENTRY) 0;
384 }
385
386 Idx += pQueue->Tail;
387 if(Idx >= pQueue->Size)
388 {
389 Idx = Idx - pQueue->Size;
390 }
391
392 return pQueue->Array[Idx];
393}
394
395#endif /* QQ_USE_MACROS */
396
397
398
399#endif /* QUEUE_H */