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