mirror of
				https://github.com/smaeul/u-boot.git
				synced 2025-11-04 14:00:19 +00: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 */
 |