blob: 059a3488175bddbd6c902ab16c4d1b3ad77a7d1a [file] [log] [blame]
/*
* queue.c
*
* Copyright(c) 1998 - 2010 Texas Instruments. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name Texas Instruments nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/** \file queue.c
* \brief This module provides generic queueing services, including enqueue, dequeue
* and requeue of any object that contains TQueNodeHdr in its structure.
*
* \see queue.h
*/
#define __FILE_ID__ FILE_ID_130
#include "report.h"
#include "queue.h"
/* Queue structure */
typedef struct
{
TQueNodeHdr tHead; /* The queue first node */
TI_UINT32 uCount; /* Current number of nodes in queue */
TI_UINT32 uLimit; /* Upper limit of nodes in queue */
TI_UINT32 uMaxCount; /* Maximum uCount value (for debug) */
TI_UINT32 uOverflow; /* Number of overflow occurences - couldn't insert node (for debug) */
TI_UINT32 uNodeHeaderOffset; /* Offset of NodeHeader field from the entry of the queued item */
TI_HANDLE hOs;
TI_HANDLE hReport;
} TQueue;
/*
* INTERNAL FUNCTIONS
* ===============================
*/
/*
* InsertNode(): Insert new node between pPrev and pNext
*/
static INLINE void InsertNode( TQueNodeHdr *pNode, TQueNodeHdr *pPrev, TQueNodeHdr *pNext)
{
pNext->pPrev = pNode;
pNode->pNext = pNext;
pNode->pPrev = pPrev;
pPrev->pNext = pNode;
}
/*
* RemoveNode(): Remove node from between pPrev and pNext
*/
static INLINE void RemoveNode( TQueNodeHdr *pPrev, TQueNodeHdr *pNext)
{
pNext->pPrev = pPrev;
pPrev->pNext = pNext;
}
/*
* AddToHead(): Add node to queue head (last in queue)
*/
static INLINE void AddToHead( TQueNodeHdr *pNode, TQueNodeHdr *pListHead)
{
InsertNode (pNode, pListHead, pListHead->pNext);
}
/*
* AddToTail(): Add node to queue tail (first in queue)
*/
static INLINE void AddToTail( TQueNodeHdr *pNode, TQueNodeHdr *pListHead)
{
InsertNode( pNode, pListHead->pPrev, pListHead );
}
/*
* DelFromTail(): Delete node from queue tail (first in queue)
*/
static INLINE void DelFromTail (TQueNodeHdr *pNode)
{
RemoveNode (pNode->pPrev, pNode->pNext);
}
/*
* EXTERNAL FUNCTIONS
* ===============================
*/
/**
* \fn que_Create
* \brief Create a queue.
*
* Allocate and init a queue object.
*
* \note
* \param hOs - Handle to Os Abstraction Layer
* \param hReport - Handle to report module
* \param uLimit - Maximum items to store in queue
* \param uNodeHeaderOffset - Offset of NodeHeader field from the entry of the queued item.
* \return Handle to the allocated queue
* \sa que_Destroy
*/
TI_HANDLE que_Create (TI_HANDLE hOs, TI_HANDLE hReport, TI_UINT32 uLimit, TI_UINT32 uNodeHeaderOffset)
{
TQueue *pQue;
/* allocate queue module */
pQue = os_memoryAlloc (hOs, sizeof(TQueue));
if (!pQue)
{
WLAN_OS_REPORT (("Error allocating the Queue Module\n"));
return NULL;
}
os_memoryZero (hOs, pQue, sizeof(TQueue));
/* Intialize the queue header */
pQue->tHead.pNext = pQue->tHead.pPrev = &pQue->tHead;
/* Set the Queue parameters */
pQue->hOs = hOs;
pQue->hReport = hReport;
pQue->uLimit = uLimit;
pQue->uNodeHeaderOffset = uNodeHeaderOffset;
return (TI_HANDLE)pQue;
}
/**
* \fn que_Destroy
* \brief Destroy the queue.
*
* Free the queue memory.
*
* \note The queue's owner should first free the queued items!
* \param hQue - The queue object
* \return TI_OK on success or TI_NOK on failure
* \sa que_Create
*/
TI_STATUS que_Destroy (TI_HANDLE hQue)
{
TQueue *pQue = (TQueue *)hQue;
if (pQue)
{
/* Alert if the queue is unloaded before it was cleared from items */
if (pQue->uCount)
{
TRACE0(pQue->hReport, REPORT_SEVERITY_WARNING, "que_Destroy() Queue Not Empty!!");
}
/* free Queue object */
os_memoryFree (pQue->hOs, pQue, sizeof(TQueue));
}
return TI_OK;
}
/**
* \fn que_Init
* \brief Init required handles
*
* Init required handles.
*
* \note
* \param hQue - The queue object
* \param hOs - Handle to Os Abstraction Layer
* \param hReport - Handle to report module
* \return TI_OK on success or TI_NOK on failure
* \sa
*/
TI_STATUS que_Init (TI_HANDLE hQue, TI_HANDLE hOs, TI_HANDLE hReport)
{
TQueue *pQue = (TQueue *)hQue;
pQue->hOs = hOs;
pQue->hReport = hReport;
return TI_OK;
}
/**
* \fn que_Enqueue
* \brief Enqueue an item
*
* Enqueue an item at the queue's head (last in queue).
*
* \note
* \param hQue - The queue object
* \param hItem - Handle to queued item
* \return TI_OK if item was queued, or TI_NOK if not queued due to overflow
* \sa que_Dequeue, que_Requeue
*/
TI_STATUS que_Enqueue (TI_HANDLE hQue, TI_HANDLE hItem)
{
TQueue *pQue = (TQueue *)hQue;
TQueNodeHdr *pQueNodeHdr; /* the Node-Header in the given item */
if (pQue)
{
/* Check queue limit */
if(pQue->uCount < pQue->uLimit)
{
/* Find NodeHeader in the given item */
pQueNodeHdr = (TQueNodeHdr *)((TI_UINT8*)hItem + pQue->uNodeHeaderOffset);
/* Verify that pNext is NULL --> Sanity check that this item is not already linked to a queue */
if (pQueNodeHdr->pNext)
{
/* Not an error since we have a case where a timer may expire twice in a row (in TxDataQueue) */
TRACE0(pQue->hReport, REPORT_SEVERITY_WARNING, "que_Enqueue(): Trying to enqueue an item that is already enqueued!!");
return TI_NOK;
}
/* Enqueue item and increment items counter */
AddToHead (pQueNodeHdr, &pQue->tHead);
pQue->uCount++;
#ifdef TI_DBG
if (pQue->uCount > pQue->uMaxCount)
{
pQue->uMaxCount = pQue->uCount;
}
TRACE0(pQue->hReport, REPORT_SEVERITY_INFORMATION , "que_Enqueue(): Enqueued Successfully\n");
#endif
return TI_OK;
}
/*
* Queue is overflowed, return TI_NOK.
*/
#ifdef TI_DBG
pQue->uOverflow++;
TRACE0(pQue->hReport, REPORT_SEVERITY_WARNING , "que_Enqueue(): Queue Overflow\n");
#endif
}
return TI_NOK;
}
/**
* \fn que_Dequeue
* \brief Dequeue an item
*
* Dequeue an item from the queue's tail (first in queue).
*
* \note
* \param hQue - The queue object
* \return pointer to dequeued item or NULL if queue is empty
* \sa que_Enqueue, que_Requeue
*/
TI_HANDLE que_Dequeue (TI_HANDLE hQue)
{
TQueue *pQue = (TQueue *)hQue;
TI_HANDLE hItem;
if (pQue)
{
if (pQue->uCount)
{
/* Queue is not empty, take packet from the queue tail */
/* find pointer to the node entry */
hItem = (TI_HANDLE)((TI_UINT8*)pQue->tHead.pPrev - pQue->uNodeHeaderOffset);
DelFromTail (pQue->tHead.pPrev); /* remove node from the queue */
pQue->uCount--;
#ifdef TI_DBG
/* Clear the pNext so we can do a sanity check when enqueuing this structre in the future */
((TQueNodeHdr *)((TI_UINT8*)hItem + pQue->uNodeHeaderOffset))->pNext = NULL;
#endif
return (hItem);
}
}
/* Queue is empty */
TRACE0(pQue->hReport, REPORT_SEVERITY_INFORMATION , "que_Dequeue(): Queue is empty\n");
return NULL;
}
/**
* \fn que_Requeue
* \brief Requeue an item
*
* Requeue an item at the queue's tail (first in queue).
*
* \note
* \param hQue - The queue object
* \param hItem - Handle to queued item
* \return TI_OK if item was queued, or TI_NOK if not queued due to overflow
* \sa que_Enqueue, que_Dequeue
*/
TI_STATUS que_Requeue (TI_HANDLE hQue, TI_HANDLE hItem)
{
TQueue *pQue = (TQueue *)hQue;
TQueNodeHdr *pQueNodeHdr; /* the NodeHeader in the given item */
/*
* If queue's limits not exceeded add the packet to queue's tail and return TI_OK
*/
if (pQue->uCount < pQue->uLimit)
{
/* Find NodeHeader in the given item */
pQueNodeHdr = (TQueNodeHdr *)((TI_UINT8*)hItem + pQue->uNodeHeaderOffset);
/* Verify that pNext is NULL --> Sanity check that this item is not already linked to a queue */
if (pQueNodeHdr->pNext)
{
TRACE0(pQue->hReport, REPORT_SEVERITY_ERROR, "que_Requeue(): Trying to Requeue an item that is already enqueued!!");
return TI_NOK;
}
/* Enqueue item and increment items counter */
AddToTail (pQueNodeHdr, &pQue->tHead);
pQue->uCount++;
#ifdef TI_DBG
if (pQue->uCount > pQue->uMaxCount)
pQue->uMaxCount = pQue->uCount;
TRACE0(pQue->hReport, REPORT_SEVERITY_INFORMATION , "que_Requeue(): Requeued successfully\n");
#endif
return TI_OK;
}
/*
* Queue is overflowed, return TI_NOK.
* Note: This is not expected in the current design, since Tx packet may be requeued
* only right after it was dequeued in the same context so the queue can't be full.
*/
#ifdef TI_DBG
pQue->uOverflow++;
TRACE0(pQue->hReport, REPORT_SEVERITY_ERROR , "que_Requeue(): Queue Overflow\n");
#endif
return TI_NOK;
}
/**
* \fn que_Size
* \brief Return queue size
*
* Return number of items in queue.
*
* \note
* \param hQue - The queue object
* \return TI_UINT32 - the items count
* \sa
*/
TI_UINT32 que_Size (TI_HANDLE hQue)
{
TQueue *pQue = (TQueue *)hQue;
return (pQue->uCount);
}
/**
* \fn que_Print
* \brief Print queue status
*
* Print the queue's parameters (not the content).
*
* \note
* \param hQue - The queue object
* \return void
* \sa
*/
#ifdef TI_DBG
void que_Print(TI_HANDLE hQue)
{
#ifdef REPORT_LOG
TQueue *pQue = (TQueue *)hQue;
WLAN_OS_REPORT(("que_Print: Count=%u MaxCount=%u Limit=%u Overflow=%u NodeHeaderOffset=%u Next=0x%x Prev=0x%x\n",
pQue->uCount, pQue->uMaxCount, pQue->uLimit, pQue->uOverflow,
pQue->uNodeHeaderOffset, pQue->tHead.pNext, pQue->tHead.pPrev));
#endif
}
#endif /* TI_DBG */