| |
| /******************************************************************************/ |
| /* */ |
| /* 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 */ |