blob: 336b3caa4a96657bf4719b7e314cc4028fb3d02f [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) \
wdenk57b2d802003-06-27 21:31:46 +0000106 \
wdenkc6097192002-11-03 00:24:07 +0000107 typedef struct { \
wdenk57b2d802003-06-27 21:31:46 +0000108 QQ_CONTAINER Container; \
109 PQQ_ENTRY EntryBuffer[_QUEUE_SIZE]; \
wdenkc6097192002-11-03 00:24:07 +0000110 } _QUEUE_TYPE, *P##_QUEUE_TYPE
111
112
wdenkc6097192002-11-03 00:24:07 +0000113/******************************************************************************/
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/******************************************************************************/
135extern __inline void
136QQ_InitQueue(
137PQQ_CONTAINER pQueue,
138unsigned 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
wdenkc6097192002-11-03 00:24:07 +0000146/******************************************************************************/
147/* Description: */
148/* */
149/* Return: */
150/******************************************************************************/
151extern __inline char
152QQ_Full(
153PQQ_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
wdenkc6097192002-11-03 00:24:07 +0000162/******************************************************************************/
163/* Description: */
164/* */
165/* Return: */
166/******************************************************************************/
167extern __inline char
168QQ_Empty(
169PQQ_CONTAINER pQueue) {
170 return(pQueue->Head == pQueue->Tail);
171} /* QQ_Empty */
172
173
wdenkc6097192002-11-03 00:24:07 +0000174/******************************************************************************/
175/* Description: */
176/* */
177/* Return: */
178/******************************************************************************/
179extern __inline unsigned int
180QQ_GetSize(
181PQQ_CONTAINER pQueue) {
182 return pQueue->Size;
183} /* QQ_GetSize */
184
185
wdenkc6097192002-11-03 00:24:07 +0000186/******************************************************************************/
187/* Description: */
188/* */
189/* Return: */
190/******************************************************************************/
191extern __inline unsigned int
192QQ_GetEntryCnt(
193PQQ_CONTAINER pQueue) {
194 return atomic_read(&pQueue->EntryCnt);
195} /* QQ_GetEntryCnt */
196
197
wdenkc6097192002-11-03 00:24:07 +0000198/******************************************************************************/
199/* Description: */
200/* */
201/* Return: */
202/* TRUE entry was added successfully. */
203/* FALSE queue is full. */
204/******************************************************************************/
205extern __inline char
206QQ_PushHead(
207PQQ_CONTAINER pQueue,
208PQQ_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) {
wdenk57b2d802003-06-27 21:31:46 +0000215 return 0;
wdenkc6097192002-11-03 00:24:07 +0000216 } /* 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
wdenkc6097192002-11-03 00:24:07 +0000228/******************************************************************************/
229/* Description: */
230/* */
231/* Return: */
232/* TRUE entry was added successfully. */
233/* FALSE queue is full. */
234/******************************************************************************/
235extern __inline char
236QQ_PushTail(
237PQQ_CONTAINER pQueue,
238PQQ_ENTRY pEntry) {
239 unsigned int Tail;
240
241 Tail = pQueue->Tail;
242 if(Tail == 0) {
wdenk57b2d802003-06-27 21:31:46 +0000243 Tail = pQueue->Size;
wdenkc6097192002-11-03 00:24:07 +0000244 } /* if */
245 Tail--;
246
247#if !defined(QQ_NO_OVERFLOW_CHECK)
248 if(Tail == pQueue->Head) {
wdenk57b2d802003-06-27 21:31:46 +0000249 return 0;
wdenkc6097192002-11-03 00:24:07 +0000250 } /* 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
wdenkc6097192002-11-03 00:24:07 +0000262/******************************************************************************/
263/* Description: */
264/* */
265/* Return: */
266/******************************************************************************/
267extern __inline PQQ_ENTRY
268QQ_PopHead(
269PQQ_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) {
wdenk57b2d802003-06-27 21:31:46 +0000277 return (PQQ_ENTRY) 0;
wdenkc6097192002-11-03 00:24:07 +0000278 } /* if */
279#endif /* QQ_NO_UNDERFLOW_CHECK */
280
281 if(Head == 0) {
wdenk57b2d802003-06-27 21:31:46 +0000282 Head = pQueue->Size;
wdenkc6097192002-11-03 00:24:07 +0000283 } /* 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
wdenkc6097192002-11-03 00:24:07 +0000299/******************************************************************************/
300/* Description: */
301/* */
302/* Return: */
303/******************************************************************************/
304extern __inline PQQ_ENTRY
305QQ_PopTail(
306PQQ_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) {
wdenk57b2d802003-06-27 21:31:46 +0000314 return (PQQ_ENTRY) 0;
wdenkc6097192002-11-03 00:24:07 +0000315 } /* 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
wdenkc6097192002-11-03 00:24:07 +0000331/******************************************************************************/
332/* Description: */
333/* */
334/* Return: */
335/******************************************************************************/
336extern __inline PQQ_ENTRY
337QQ_GetHead(
338 PQQ_CONTAINER pQueue,
339 unsigned int Idx)
340{
341 if(Idx >= atomic_read(&pQueue->EntryCnt))
342 {
wdenk57b2d802003-06-27 21:31:46 +0000343 return (PQQ_ENTRY) 0;
wdenkc6097192002-11-03 00:24:07 +0000344 }
345
346 if(pQueue->Head > Idx)
347 {
wdenk57b2d802003-06-27 21:31:46 +0000348 Idx = pQueue->Head - Idx;
wdenkc6097192002-11-03 00:24:07 +0000349 }
350 else
351 {
wdenk57b2d802003-06-27 21:31:46 +0000352 Idx = pQueue->Size - (Idx - pQueue->Head);
wdenkc6097192002-11-03 00:24:07 +0000353 }
354 Idx--;
355
356 return pQueue->Array[Idx];
357}
358
359
wdenkc6097192002-11-03 00:24:07 +0000360/******************************************************************************/
361/* Description: */
362/* */
363/* Return: */
364/******************************************************************************/
365extern __inline PQQ_ENTRY
366QQ_GetTail(
367 PQQ_CONTAINER pQueue,
368 unsigned int Idx)
369{
370 if(Idx >= atomic_read(&pQueue->EntryCnt))
371 {
wdenk57b2d802003-06-27 21:31:46 +0000372 return (PQQ_ENTRY) 0;
wdenkc6097192002-11-03 00:24:07 +0000373 }
374
375 Idx += pQueue->Tail;
376 if(Idx >= pQueue->Size)
377 {
wdenk57b2d802003-06-27 21:31:46 +0000378 Idx = Idx - pQueue->Size;
wdenkc6097192002-11-03 00:24:07 +0000379 }
380
381 return pQueue->Array[Idx];
382}
383
384#endif /* QQ_USE_MACROS */
385
386
wdenkc6097192002-11-03 00:24:07 +0000387#endif /* QUEUE_H */