| /******************************************************************************/ | |
| /* */ | |
| /* Broadcom BCM5700 Linux Network Driver, Copyright (c) 2000 Broadcom */ | |
| /* Corporation. */ | |
| /* All rights reserved. */ | |
| /* */ | |
| /* This program is free software; you can redistribute it and/or modify */ | |
| /* it under the terms of the GNU General Public License as published by */ | |
| /* the Free Software Foundation, located in the file LICENSE. */ | |
| /* */ | |
| /* Queue functions. */ | |
| /* void QQ_InitQueue(PQQ_CONTAINER pQueue) */ | |
| /* char QQ_Full(PQQ_CONTAINER pQueue) */ | |
| /* char QQ_Empty(PQQ_CONTAINER pQueue) */ | |
| /* unsigned int QQ_GetSize(PQQ_CONTAINER pQueue) */ | |
| /* unsigned int QQ_GetEntryCnt(PQQ_CONTAINER pQueue) */ | |
| /* char QQ_PushHead(PQQ_CONTAINER pQueue, PQQ_ENTRY pEntry) */ | |
| /* char QQ_PushTail(PQQ_CONTAINER pQueue, PQQ_ENTRY pEntry) */ | |
| /* PQQ_ENTRY QQ_PopHead(PQQ_CONTAINER pQueue) */ | |
| /* PQQ_ENTRY QQ_PopTail(PQQ_CONTAINER pQueue) */ | |
| /* PQQ_ENTRY QQ_GetHead(PQQ_CONTAINER pQueue, unsigned int Idx) */ | |
| /* PQQ_ENTRY QQ_GetTail(PQQ_CONTAINER pQueue, unsigned int Idx) */ | |
| /* */ | |
| /* */ | |
| /* History: */ | |
| /* 02/25/00 Hav Khauv Initial version. */ | |
| /******************************************************************************/ | |
| #ifndef BCM_QUEUE_H | |
| #define BCM_QUEUE_H | |
| #ifndef EMBEDDED | |
| #define EMBEDDED 1 | |
| #endif | |
| /******************************************************************************/ | |
| /* Queue definitions. */ | |
| /******************************************************************************/ | |
| /* Entry for queueing. */ | |
| typedef void *PQQ_ENTRY; | |
| /* Linux Atomic Ops support */ | |
| typedef struct { int counter; } atomic_t; | |
| /* | |
| * This combination of `inline' and `extern' has almost the effect of a | |
| * macro. The way to use it is to put a function definition in a header | |
| * file with these keywords, and put another copy of the definition | |
| * (lacking `inline' and `extern') in a library file. The definition in | |
| * the header file will cause most calls to the function to be inlined. | |
| * If any uses of the function remain, they will refer to the single copy | |
| * in the library. | |
| */ | |
| extern __inline void | |
| atomic_set(atomic_t* entry, int val) | |
| { | |
| entry->counter = val; | |
| } | |
| extern __inline int | |
| atomic_read(atomic_t* entry) | |
| { | |
| return entry->counter; | |
| } | |
| extern __inline void | |
| atomic_inc(atomic_t* entry) | |
| { | |
| if(entry) | |
| entry->counter++; | |
| } | |
| extern __inline void | |
| atomic_dec(atomic_t* entry) | |
| { | |
| if(entry) | |
| entry->counter--; | |
| } | |
| extern __inline void | |
| atomic_sub(int a, atomic_t* entry) | |
| { | |
| if(entry) | |
| entry->counter -= a; | |
| } | |
| extern __inline void | |
| atomic_add(int a, atomic_t* entry) | |
| { | |
| if(entry) | |
| entry->counter += a; | |
| } | |
| /* Queue header -- base type. */ | |
| typedef struct { | |
| unsigned int Head; | |
| unsigned int Tail; | |
| unsigned int Size; | |
| atomic_t EntryCnt; | |
| PQQ_ENTRY Array[1]; | |
| } QQ_CONTAINER, *PQQ_CONTAINER; | |
| /* Declare queue type macro. */ | |
| #define DECLARE_QUEUE_TYPE(_QUEUE_TYPE, _QUEUE_SIZE) \ | |
| \ | |
| typedef struct { \ | |
| QQ_CONTAINER Container; \ | |
| PQQ_ENTRY EntryBuffer[_QUEUE_SIZE]; \ | |
| } _QUEUE_TYPE, *P##_QUEUE_TYPE | |
| /******************************************************************************/ | |
| /* Compilation switches. */ | |
| /******************************************************************************/ | |
| #if DBG | |
| #undef QQ_NO_OVERFLOW_CHECK | |
| #undef QQ_NO_UNDERFLOW_CHECK | |
| #endif /* DBG */ | |
| #ifdef QQ_USE_MACROS | |
| /* notdone */ | |
| #else | |
| #ifdef QQ_NO_INLINE | |
| #define __inline | |
| #endif /* QQ_NO_INLINE */ | |
| /******************************************************************************/ | |
| /* Description: */ | |
| /* */ | |
| /* Return: */ | |
| /******************************************************************************/ | |
| extern __inline void | |
| QQ_InitQueue( | |
| PQQ_CONTAINER pQueue, | |
| unsigned int QueueSize) { | |
| pQueue->Head = 0; | |
| pQueue->Tail = 0; | |
| pQueue->Size = QueueSize+1; | |
| atomic_set(&pQueue->EntryCnt, 0); | |
| } /* QQ_InitQueue */ | |
| /******************************************************************************/ | |
| /* Description: */ | |
| /* */ | |
| /* Return: */ | |
| /******************************************************************************/ | |
| extern __inline char | |
| QQ_Full( | |
| PQQ_CONTAINER pQueue) { | |
| unsigned int NewHead; | |
| NewHead = (pQueue->Head + 1) % pQueue->Size; | |
| return(NewHead == pQueue->Tail); | |
| } /* QQ_Full */ | |
| /******************************************************************************/ | |
| /* Description: */ | |
| /* */ | |
| /* Return: */ | |
| /******************************************************************************/ | |
| extern __inline char | |
| QQ_Empty( | |
| PQQ_CONTAINER pQueue) { | |
| return(pQueue->Head == pQueue->Tail); | |
| } /* QQ_Empty */ | |
| /******************************************************************************/ | |
| /* Description: */ | |
| /* */ | |
| /* Return: */ | |
| /******************************************************************************/ | |
| extern __inline unsigned int | |
| QQ_GetSize( | |
| PQQ_CONTAINER pQueue) { | |
| return pQueue->Size; | |
| } /* QQ_GetSize */ | |
| /******************************************************************************/ | |
| /* Description: */ | |
| /* */ | |
| /* Return: */ | |
| /******************************************************************************/ | |
| extern __inline unsigned int | |
| QQ_GetEntryCnt( | |
| PQQ_CONTAINER pQueue) { | |
| return atomic_read(&pQueue->EntryCnt); | |
| } /* QQ_GetEntryCnt */ | |
| /******************************************************************************/ | |
| /* Description: */ | |
| /* */ | |
| /* Return: */ | |
| /* TRUE entry was added successfully. */ | |
| /* FALSE queue is full. */ | |
| /******************************************************************************/ | |
| extern __inline char | |
| QQ_PushHead( | |
| PQQ_CONTAINER pQueue, | |
| PQQ_ENTRY pEntry) { | |
| unsigned int Head; | |
| Head = (pQueue->Head + 1) % pQueue->Size; | |
| #if !defined(QQ_NO_OVERFLOW_CHECK) | |
| if(Head == pQueue->Tail) { | |
| return 0; | |
| } /* if */ | |
| #endif /* QQ_NO_OVERFLOW_CHECK */ | |
| pQueue->Array[pQueue->Head] = pEntry; | |
| wmb(); | |
| pQueue->Head = Head; | |
| atomic_inc(&pQueue->EntryCnt); | |
| return -1; | |
| } /* QQ_PushHead */ | |
| /******************************************************************************/ | |
| /* Description: */ | |
| /* */ | |
| /* Return: */ | |
| /* TRUE entry was added successfully. */ | |
| /* FALSE queue is full. */ | |
| /******************************************************************************/ | |
| extern __inline char | |
| QQ_PushTail( | |
| PQQ_CONTAINER pQueue, | |
| PQQ_ENTRY pEntry) { | |
| unsigned int Tail; | |
| Tail = pQueue->Tail; | |
| if(Tail == 0) { | |
| Tail = pQueue->Size; | |
| } /* if */ | |
| Tail--; | |
| #if !defined(QQ_NO_OVERFLOW_CHECK) | |
| if(Tail == pQueue->Head) { | |
| return 0; | |
| } /* if */ | |
| #endif /* QQ_NO_OVERFLOW_CHECK */ | |
| pQueue->Array[Tail] = pEntry; | |
| wmb(); | |
| pQueue->Tail = Tail; | |
| atomic_inc(&pQueue->EntryCnt); | |
| return -1; | |
| } /* QQ_PushTail */ | |
| /******************************************************************************/ | |
| /* Description: */ | |
| /* */ | |
| /* Return: */ | |
| /******************************************************************************/ | |
| extern __inline PQQ_ENTRY | |
| QQ_PopHead( | |
| PQQ_CONTAINER pQueue) { | |
| unsigned int Head; | |
| PQQ_ENTRY Entry; | |
| Head = pQueue->Head; | |
| #if !defined(QQ_NO_UNDERFLOW_CHECK) | |
| if(Head == pQueue->Tail) { | |
| return (PQQ_ENTRY) 0; | |
| } /* if */ | |
| #endif /* QQ_NO_UNDERFLOW_CHECK */ | |
| if(Head == 0) { | |
| Head = pQueue->Size; | |
| } /* if */ | |
| Head--; | |
| Entry = pQueue->Array[Head]; | |
| #ifdef EMBEDDED | |
| membar(); | |
| #else | |
| mb(); | |
| #endif | |
| pQueue->Head = Head; | |
| atomic_dec(&pQueue->EntryCnt); | |
| return Entry; | |
| } /* QQ_PopHead */ | |
| /******************************************************************************/ | |
| /* Description: */ | |
| /* */ | |
| /* Return: */ | |
| /******************************************************************************/ | |
| extern __inline PQQ_ENTRY | |
| QQ_PopTail( | |
| PQQ_CONTAINER pQueue) { | |
| unsigned int Tail; | |
| PQQ_ENTRY Entry; | |
| Tail = pQueue->Tail; | |
| #if !defined(QQ_NO_UNDERFLOW_CHECK) | |
| if(Tail == pQueue->Head) { | |
| return (PQQ_ENTRY) 0; | |
| } /* if */ | |
| #endif /* QQ_NO_UNDERFLOW_CHECK */ | |
| Entry = pQueue->Array[Tail]; | |
| #ifdef EMBEDDED | |
| membar(); | |
| #else | |
| mb(); | |
| #endif | |
| pQueue->Tail = (Tail + 1) % pQueue->Size; | |
| atomic_dec(&pQueue->EntryCnt); | |
| return Entry; | |
| } /* QQ_PopTail */ | |
| /******************************************************************************/ | |
| /* Description: */ | |
| /* */ | |
| /* Return: */ | |
| /******************************************************************************/ | |
| extern __inline PQQ_ENTRY | |
| QQ_GetHead( | |
| PQQ_CONTAINER pQueue, | |
| unsigned int Idx) | |
| { | |
| if(Idx >= atomic_read(&pQueue->EntryCnt)) | |
| { | |
| return (PQQ_ENTRY) 0; | |
| } | |
| if(pQueue->Head > Idx) | |
| { | |
| Idx = pQueue->Head - Idx; | |
| } | |
| else | |
| { | |
| Idx = pQueue->Size - (Idx - pQueue->Head); | |
| } | |
| Idx--; | |
| return pQueue->Array[Idx]; | |
| } | |
| /******************************************************************************/ | |
| /* Description: */ | |
| /* */ | |
| /* Return: */ | |
| /******************************************************************************/ | |
| extern __inline PQQ_ENTRY | |
| QQ_GetTail( | |
| PQQ_CONTAINER pQueue, | |
| unsigned int Idx) | |
| { | |
| if(Idx >= atomic_read(&pQueue->EntryCnt)) | |
| { | |
| return (PQQ_ENTRY) 0; | |
| } | |
| Idx += pQueue->Tail; | |
| if(Idx >= pQueue->Size) | |
| { | |
| Idx = Idx - pQueue->Size; | |
| } | |
| return pQueue->Array[Idx]; | |
| } | |
| #endif /* QQ_USE_MACROS */ | |
| #endif /* QUEUE_H */ |