]>
Commit | Line | Data |
---|---|---|
c609719b WD |
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) \ | |
8bde7f77 | 106 | \ |
c609719b | 107 | typedef struct { \ |
8bde7f77 WD |
108 | QQ_CONTAINER Container; \ |
109 | PQQ_ENTRY EntryBuffer[_QUEUE_SIZE]; \ | |
c609719b WD |
110 | } _QUEUE_TYPE, *P##_QUEUE_TYPE |
111 | ||
112 | ||
c609719b WD |
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 | ||
c609719b WD |
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 | ||
c609719b WD |
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 | ||
c609719b WD |
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 | ||
c609719b WD |
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 | ||
c609719b WD |
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) { | |
8bde7f77 | 215 | return 0; |
c609719b WD |
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 | ||
c609719b WD |
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) { | |
8bde7f77 | 243 | Tail = pQueue->Size; |
c609719b WD |
244 | } /* if */ |
245 | Tail--; | |
246 | ||
247 | #if !defined(QQ_NO_OVERFLOW_CHECK) | |
248 | if(Tail == pQueue->Head) { | |
8bde7f77 | 249 | return 0; |
c609719b WD |
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 | ||
c609719b WD |
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) { | |
8bde7f77 | 277 | return (PQQ_ENTRY) 0; |
c609719b WD |
278 | } /* if */ |
279 | #endif /* QQ_NO_UNDERFLOW_CHECK */ | |
280 | ||
281 | if(Head == 0) { | |
8bde7f77 | 282 | Head = pQueue->Size; |
c609719b WD |
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 | ||
c609719b WD |
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) { | |
8bde7f77 | 314 | return (PQQ_ENTRY) 0; |
c609719b WD |
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 | ||
c609719b WD |
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 | { | |
8bde7f77 | 343 | return (PQQ_ENTRY) 0; |
c609719b WD |
344 | } |
345 | ||
346 | if(pQueue->Head > Idx) | |
347 | { | |
8bde7f77 | 348 | Idx = pQueue->Head - Idx; |
c609719b WD |
349 | } |
350 | else | |
351 | { | |
8bde7f77 | 352 | Idx = pQueue->Size - (Idx - pQueue->Head); |
c609719b WD |
353 | } |
354 | Idx--; | |
355 | ||
356 | return pQueue->Array[Idx]; | |
357 | } | |
358 | ||
359 | ||
c609719b WD |
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 | { | |
8bde7f77 | 372 | return (PQQ_ENTRY) 0; |
c609719b WD |
373 | } |
374 | ||
375 | Idx += pQueue->Tail; | |
376 | if(Idx >= pQueue->Size) | |
377 | { | |
8bde7f77 | 378 | Idx = Idx - pQueue->Size; |
c609719b WD |
379 | } |
380 | ||
381 | return pQueue->Array[Idx]; | |
382 | } | |
383 | ||
384 | #endif /* QQ_USE_MACROS */ | |
385 | ||
386 | ||
c609719b | 387 | #endif /* QUEUE_H */ |