blob: 336b3caa4a96657bf4719b7e314cc4028fb3d02f [file] [log] [blame]
/******************************************************************************/
/* */
/* 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 */