| 1 | /******************************************************************************/ |
| 2 | /* */ |
| 3 | /* Broadcom BCM5700 Linux Network Driver, Copyright (c) 2000 - 2004 Broadcom */ |
| 4 | /* Corporation. */ |
| 5 | /* All rights reserved. */ |
| 6 | /* */ |
| 7 | /* This program 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, located in the file LICENSE. */ |
| 10 | /* */ |
| 11 | /* Queue functions. */ |
| 12 | /* void QQ_InitQueue(PQQ_CONTAINER pQueue) */ |
| 13 | /* char QQ_Full(PQQ_CONTAINER pQueue) */ |
| 14 | /* char QQ_Empty(PQQ_CONTAINER pQueue) */ |
| 15 | /* unsigned int QQ_GetSize(PQQ_CONTAINER pQueue) */ |
| 16 | /* unsigned int QQ_GetEntryCnt(PQQ_CONTAINER pQueue) */ |
| 17 | /* char QQ_PushHead(PQQ_CONTAINER pQueue, PQQ_ENTRY pEntry) */ |
| 18 | /* char QQ_PushTail(PQQ_CONTAINER pQueue, PQQ_ENTRY pEntry) */ |
| 19 | /* PQQ_ENTRY QQ_PopHead(PQQ_CONTAINER pQueue) */ |
| 20 | /* PQQ_ENTRY QQ_PopTail(PQQ_CONTAINER pQueue) */ |
| 21 | /* PQQ_ENTRY QQ_GetHead(PQQ_CONTAINER pQueue, unsigned int Idx) */ |
| 22 | /* PQQ_ENTRY QQ_GetTail(PQQ_CONTAINER pQueue, unsigned int Idx) */ |
| 23 | /* */ |
| 24 | /* */ |
| 25 | /* History: */ |
| 26 | /* 02/25/00 Hav Khauv Initial version. */ |
| 27 | /******************************************************************************/ |
| 28 | |
| 29 | #ifndef BCM_QUEUE_H |
| 30 | #define BCM_QUEUE_H |
| 31 | |
| 32 | |
| 33 | |
| 34 | /******************************************************************************/ |
| 35 | /* Queue definitions. */ |
| 36 | /******************************************************************************/ |
| 37 | |
| 38 | /* Entry for queueing. */ |
| 39 | typedef void *PQQ_ENTRY; |
| 40 | |
| 41 | |
| 42 | /* Queue header -- base type. */ |
| 43 | typedef struct { |
| 44 | unsigned int Head; |
| 45 | unsigned int Tail; |
| 46 | unsigned int Size; |
| 47 | MM_ATOMIC_T EntryCnt; |
| 48 | PQQ_ENTRY Array[1]; |
| 49 | } QQ_CONTAINER, *PQQ_CONTAINER; |
| 50 | |
| 51 | |
| 52 | /* Declare queue type macro. */ |
| 53 | #define DECLARE_QUEUE_TYPE(_QUEUE_TYPE, _QUEUE_SIZE) \ |
| 54 | \ |
| 55 | typedef struct { \ |
| 56 | QQ_CONTAINER Container; \ |
| 57 | PQQ_ENTRY EntryBuffer[_QUEUE_SIZE]; \ |
| 58 | } _QUEUE_TYPE, *P##_QUEUE_TYPE |
| 59 | |
| 60 | |
| 61 | |
| 62 | /******************************************************************************/ |
| 63 | /* Compilation switches. */ |
| 64 | /******************************************************************************/ |
| 65 | |
| 66 | #if DBG |
| 67 | #undef QQ_NO_OVERFLOW_CHECK |
| 68 | #undef QQ_NO_UNDERFLOW_CHECK |
| 69 | #endif /* DBG */ |
| 70 | |
| 71 | #ifdef QQ_USE_MACROS |
| 72 | /* notdone */ |
| 73 | #else |
| 74 | |
| 75 | #ifdef QQ_NO_INLINE |
| 76 | #define __inline |
| 77 | #endif /* QQ_NO_INLINE */ |
| 78 | |
| 79 | |
| 80 | |
| 81 | /******************************************************************************/ |
| 82 | /* Description: */ |
| 83 | /* */ |
| 84 | /* Return: */ |
| 85 | /******************************************************************************/ |
| 86 | __inline static void |
| 87 | QQ_InitQueue( |
| 88 | PQQ_CONTAINER pQueue, |
| 89 | unsigned int QueueSize) { |
| 90 | pQueue->Head = 0; |
| 91 | pQueue->Tail = 0; |
| 92 | pQueue->Size = QueueSize+1; |
| 93 | MM_ATOMIC_SET(&pQueue->EntryCnt, 0); |
| 94 | } /* QQ_InitQueue */ |
| 95 | |
| 96 | |
| 97 | |
| 98 | /******************************************************************************/ |
| 99 | /* Description: */ |
| 100 | /* */ |
| 101 | /* Return: */ |
| 102 | /******************************************************************************/ |
| 103 | __inline static char |
| 104 | QQ_Full( |
| 105 | PQQ_CONTAINER pQueue) { |
| 106 | unsigned int NewHead; |
| 107 | |
| 108 | NewHead = (pQueue->Head + 1) % pQueue->Size; |
| 109 | |
| 110 | return(NewHead == pQueue->Tail); |
| 111 | } /* QQ_Full */ |
| 112 | |
| 113 | |
| 114 | |
| 115 | /******************************************************************************/ |
| 116 | /* Description: */ |
| 117 | /* */ |
| 118 | /* Return: */ |
| 119 | /******************************************************************************/ |
| 120 | __inline static char |
| 121 | QQ_Empty( |
| 122 | PQQ_CONTAINER pQueue) { |
| 123 | return(pQueue->Head == pQueue->Tail); |
| 124 | } /* QQ_Empty */ |
| 125 | |
| 126 | |
| 127 | |
| 128 | /******************************************************************************/ |
| 129 | /* Description: */ |
| 130 | /* */ |
| 131 | /* Return: */ |
| 132 | /******************************************************************************/ |
| 133 | __inline static unsigned int |
| 134 | QQ_GetSize( |
| 135 | PQQ_CONTAINER pQueue) { |
| 136 | return pQueue->Size; |
| 137 | } /* QQ_GetSize */ |
| 138 | |
| 139 | |
| 140 | |
| 141 | /******************************************************************************/ |
| 142 | /* Description: */ |
| 143 | /* */ |
| 144 | /* Return: */ |
| 145 | /******************************************************************************/ |
| 146 | __inline static unsigned int |
| 147 | QQ_GetEntryCnt( |
| 148 | PQQ_CONTAINER pQueue) { |
| 149 | return MM_ATOMIC_READ(&pQueue->EntryCnt); |
| 150 | } /* QQ_GetEntryCnt */ |
| 151 | |
| 152 | |
| 153 | |
| 154 | /******************************************************************************/ |
| 155 | /* Description: */ |
| 156 | /* */ |
| 157 | /* Return: */ |
| 158 | /* TRUE entry was added successfully. */ |
| 159 | /* FALSE queue is full. */ |
| 160 | /******************************************************************************/ |
| 161 | __inline static char |
| 162 | QQ_PushHead( |
| 163 | PQQ_CONTAINER pQueue, |
| 164 | PQQ_ENTRY pEntry) { |
| 165 | unsigned int Head; |
| 166 | |
| 167 | Head = (pQueue->Head + 1) % pQueue->Size; |
| 168 | |
| 169 | #if !defined(QQ_NO_OVERFLOW_CHECK) |
| 170 | if(Head == pQueue->Tail) { |
| 171 | return 0; |
| 172 | } /* if */ |
| 173 | #endif /* QQ_NO_OVERFLOW_CHECK */ |
| 174 | |
| 175 | pQueue->Array[pQueue->Head] = pEntry; |
| 176 | MM_WMB(); |
| 177 | pQueue->Head = Head; |
| 178 | MM_ATOMIC_INC(&pQueue->EntryCnt); |
| 179 | |
| 180 | return -1; |
| 181 | } /* QQ_PushHead */ |
| 182 | |
| 183 | |
| 184 | |
| 185 | /******************************************************************************/ |
| 186 | /* Description: */ |
| 187 | /* */ |
| 188 | /* Return: */ |
| 189 | /* TRUE entry was added successfully. */ |
| 190 | /* FALSE queue is full. */ |
| 191 | /******************************************************************************/ |
| 192 | __inline static char |
| 193 | QQ_PushTail( |
| 194 | PQQ_CONTAINER pQueue, |
| 195 | PQQ_ENTRY pEntry) { |
| 196 | unsigned int Tail; |
| 197 | |
| 198 | Tail = pQueue->Tail; |
| 199 | if(Tail == 0) { |
| 200 | Tail = pQueue->Size; |
| 201 | } /* if */ |
| 202 | Tail--; |
| 203 | |
| 204 | #if !defined(QQ_NO_OVERFLOW_CHECK) |
| 205 | if(Tail == pQueue->Head) { |
| 206 | return 0; |
| 207 | } /* if */ |
| 208 | #endif /* QQ_NO_OVERFLOW_CHECK */ |
| 209 | |
| 210 | pQueue->Array[Tail] = pEntry; |
| 211 | MM_WMB(); |
| 212 | pQueue->Tail = Tail; |
| 213 | MM_ATOMIC_INC(&pQueue->EntryCnt); |
| 214 | |
| 215 | return -1; |
| 216 | } /* QQ_PushTail */ |
| 217 | |
| 218 | |
| 219 | |
| 220 | /******************************************************************************/ |
| 221 | /* Description: */ |
| 222 | /* */ |
| 223 | /* Return: */ |
| 224 | /******************************************************************************/ |
| 225 | __inline static PQQ_ENTRY |
| 226 | QQ_PopHead( |
| 227 | PQQ_CONTAINER pQueue) { |
| 228 | unsigned int Head; |
| 229 | unsigned int Tail; |
| 230 | PQQ_ENTRY Entry; |
| 231 | |
| 232 | Head = pQueue->Head; |
| 233 | Tail = pQueue->Tail; |
| 234 | |
| 235 | MM_MB(); |
| 236 | #if !defined(QQ_NO_UNDERFLOW_CHECK) |
| 237 | if(Head == Tail) { |
| 238 | return (PQQ_ENTRY) 0; |
| 239 | } /* if */ |
| 240 | #endif /* QQ_NO_UNDERFLOW_CHECK */ |
| 241 | |
| 242 | if(Head == 0) { |
| 243 | Head = pQueue->Size; |
| 244 | } /* if */ |
| 245 | Head--; |
| 246 | |
| 247 | Entry = pQueue->Array[Head]; |
| 248 | MM_MB(); |
| 249 | pQueue->Head = Head; |
| 250 | MM_ATOMIC_DEC(&pQueue->EntryCnt); |
| 251 | |
| 252 | return Entry; |
| 253 | } /* QQ_PopHead */ |
| 254 | |
| 255 | |
| 256 | |
| 257 | /******************************************************************************/ |
| 258 | /* Description: */ |
| 259 | /* */ |
| 260 | /* Return: */ |
| 261 | /******************************************************************************/ |
| 262 | __inline static PQQ_ENTRY |
| 263 | QQ_PopTail( |
| 264 | PQQ_CONTAINER pQueue) { |
| 265 | unsigned int Head; |
| 266 | unsigned int Tail; |
| 267 | PQQ_ENTRY Entry; |
| 268 | |
| 269 | Head = pQueue->Head; |
| 270 | Tail = pQueue->Tail; |
| 271 | |
| 272 | MM_MB(); |
| 273 | #if !defined(QQ_NO_UNDERFLOW_CHECK) |
| 274 | if(Tail == Head) { |
| 275 | return (PQQ_ENTRY) 0; |
| 276 | } /* if */ |
| 277 | #endif /* QQ_NO_UNDERFLOW_CHECK */ |
| 278 | |
| 279 | Entry = pQueue->Array[Tail]; |
| 280 | MM_MB(); |
| 281 | pQueue->Tail = (Tail + 1) % pQueue->Size; |
| 282 | MM_ATOMIC_DEC(&pQueue->EntryCnt); |
| 283 | |
| 284 | return Entry; |
| 285 | } /* QQ_PopTail */ |
| 286 | |
| 287 | |
| 288 | |
| 289 | /******************************************************************************/ |
| 290 | /* Description: */ |
| 291 | /* */ |
| 292 | /* Return: */ |
| 293 | /******************************************************************************/ |
| 294 | __inline static PQQ_ENTRY |
| 295 | QQ_GetHead( |
| 296 | PQQ_CONTAINER pQueue, |
| 297 | unsigned int Idx) |
| 298 | { |
| 299 | if(Idx >= (unsigned int) MM_ATOMIC_READ(&pQueue->EntryCnt)) |
| 300 | { |
| 301 | return (PQQ_ENTRY) 0; |
| 302 | } |
| 303 | |
| 304 | if(pQueue->Head > Idx) |
| 305 | { |
| 306 | Idx = pQueue->Head - Idx; |
| 307 | } |
| 308 | else |
| 309 | { |
| 310 | Idx = pQueue->Size - (Idx - pQueue->Head); |
| 311 | } |
| 312 | Idx--; |
| 313 | |
| 314 | return pQueue->Array[Idx]; |
| 315 | } |
| 316 | |
| 317 | |
| 318 | |
| 319 | /******************************************************************************/ |
| 320 | /* Description: */ |
| 321 | /* */ |
| 322 | /* Return: */ |
| 323 | /******************************************************************************/ |
| 324 | __inline static PQQ_ENTRY |
| 325 | QQ_GetTail( |
| 326 | PQQ_CONTAINER pQueue, |
| 327 | unsigned int Idx) |
| 328 | { |
| 329 | if(Idx >= (unsigned int) MM_ATOMIC_READ(&pQueue->EntryCnt)) |
| 330 | { |
| 331 | return (PQQ_ENTRY) 0; |
| 332 | } |
| 333 | |
| 334 | Idx += pQueue->Tail; |
| 335 | if(Idx >= pQueue->Size) |
| 336 | { |
| 337 | Idx = Idx - pQueue->Size; |
| 338 | } |
| 339 | |
| 340 | return pQueue->Array[Idx]; |
| 341 | } |
| 342 | |
| 343 | #endif /* QQ_USE_MACROS */ |
| 344 | |
| 345 | |
| 346 | |
| 347 | #endif /* QUEUE_H */ |
| 348 | |