mirror of
				https://source.denx.de/u-boot/u-boot.git
				synced 2025-10-31 08:21:36 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			388 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			388 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| 
 | |
| /******************************************************************************/
 | |
| /*                                                                            */
 | |
| /* 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 */
 |