diff options
Diffstat (limited to 'wilink_6_1/TWD/Data_Service')
-rw-r--r-- | wilink_6_1/TWD/Data_Service/Export_Inc/RxQueue_api.h | 59 | ||||
-rw-r--r-- | wilink_6_1/TWD/Data_Service/Export_Inc/txCtrlBlk_api.h | 61 | ||||
-rw-r--r-- | wilink_6_1/TWD/Data_Service/Export_Inc/txHwQueue_api.h | 71 | ||||
-rw-r--r-- | wilink_6_1/TWD/Data_Service/RxQueue.c | 823 | ||||
-rw-r--r-- | wilink_6_1/TWD/Data_Service/txCtrlBlk.c | 281 | ||||
-rw-r--r-- | wilink_6_1/TWD/Data_Service/txHwQueue.c | 712 |
6 files changed, 2007 insertions, 0 deletions
diff --git a/wilink_6_1/TWD/Data_Service/Export_Inc/RxQueue_api.h b/wilink_6_1/TWD/Data_Service/Export_Inc/RxQueue_api.h new file mode 100644 index 0000000..4695d41 --- /dev/null +++ b/wilink_6_1/TWD/Data_Service/Export_Inc/RxQueue_api.h @@ -0,0 +1,59 @@ +/* + * RxQueue_api.h + * + * Copyright(c) 1998 - 2009 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 RxQueue_api.h + * \brief RxQueue module header file. + * + * \see RxQueue_api.c + */ + +#ifndef _RX_QUEUE_H_ +#define _RX_QUEUE_H_ + +/* + * External Functions Prototypes + * ============================= + */ +TI_HANDLE RxQueue_Create (TI_HANDLE hOs); +TI_STATUS RxQueue_Destroy (TI_HANDLE hRxQueue); +TI_STATUS RxQueue_Init (TI_HANDLE hRxQueue, TI_HANDLE hReport); +void RxQueue_CloseBaSession(TI_HANDLE hRxQueue, TI_UINT8 uFrameTid); +void RxQueue_ReceivePacket (TI_HANDLE hRxQueue, const void *aFrame); +void RxQueue_Register_CB (TI_HANDLE hRxQueue, TI_UINT32 CallBackID, void *CBFunc, TI_HANDLE CBObj); + + +#endif /* _STA_CAP_H_ */ + + diff --git a/wilink_6_1/TWD/Data_Service/Export_Inc/txCtrlBlk_api.h b/wilink_6_1/TWD/Data_Service/Export_Inc/txCtrlBlk_api.h new file mode 100644 index 0000000..a324816 --- /dev/null +++ b/wilink_6_1/TWD/Data_Service/Export_Inc/txCtrlBlk_api.h @@ -0,0 +1,61 @@ +/* + * txCtrlBlk_api.h + * + * Copyright(c) 1998 - 2009 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. + */ + + +/***************************************************************************/ +/* */ +/* MODULE: txCtrlBlk_api.h */ +/* PURPOSE: Tx control block module API. */ +/* */ +/***************************************************************************/ +#ifndef _TX_CTRL_BLK_API_H_ +#define _TX_CTRL_BLK_API_H_ + + +#include "TWDriver.h" + +/* Public Function Definitions */ +TI_HANDLE txCtrlBlk_Create (TI_HANDLE hOs); +TI_STATUS txCtrlBlk_Destroy (TI_HANDLE hTxCtrlBlk); +TI_STATUS txCtrlBlk_Init (TI_HANDLE hTxCtrlBlk, TI_HANDLE hReport, TI_HANDLE hContext); +TTxCtrlBlk *txCtrlBlk_Alloc (TI_HANDLE hTxCtrlBlk); +void txCtrlBlk_Free (TI_HANDLE hTxCtrlBlk, TTxCtrlBlk *pCurrentEntry); +TTxCtrlBlk *txCtrlBlk_GetPointer(TI_HANDLE hTxCtrlBlk, TI_UINT8 descId); +#ifdef TI_DBG +void txCtrlBlk_PrintTable(TI_HANDLE hTxCtrlBlk); +#endif /* TI_DBG */ + + +#endif /* _TX_CTRL_BLK_API_H_ */ + + diff --git a/wilink_6_1/TWD/Data_Service/Export_Inc/txHwQueue_api.h b/wilink_6_1/TWD/Data_Service/Export_Inc/txHwQueue_api.h new file mode 100644 index 0000000..92e3bd2 --- /dev/null +++ b/wilink_6_1/TWD/Data_Service/Export_Inc/txHwQueue_api.h @@ -0,0 +1,71 @@ +/* + * txHwQueue_api.h + * + * Copyright(c) 1998 - 2009 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. + */ + + +/**************************************************************************** + * + * MODULE: txHwQueue_api.h + * + * PURPOSE: HW Tx Queue module API. + * + ****************************************************************************/ + +#ifndef _TX_HW_QUEUE_API_H +#define _TX_HW_QUEUE_API_H + + +#include "TWDriver.h" +#include "TWDriverInternal.h" + + +/* Public Function Definitions */ + +TI_HANDLE txHwQueue_Create (TI_HANDLE hOs); +TI_STATUS txHwQueue_Destroy (TI_HANDLE hTxHwQueue); +TI_STATUS txHwQueue_Init (TI_HANDLE hTxHwQueue, TI_HANDLE hReport); +TI_STATUS txHwQueue_Config (TI_HANDLE hTxHwQueue, TTwdInitParams *pInitParams); +TI_STATUS txHwQueue_SetHwInfo (TI_HANDLE hTxHwQueue, TDmaParams *pDmaParams); +TI_STATUS txHwQueue_Restart (TI_HANDLE hTxHwQueue); +ETxHwQueStatus txHwQueue_AllocResources (TI_HANDLE hTxHwQueue, TTxCtrlBlk *pTxCtrlBlk); +void txHwQueue_UpdateFreeResources (TI_HANDLE hTxHwQueue, FwStatus_t *pFwStatus); +void txHwQueue_RegisterCb (TI_HANDLE hTxHwQueue, TI_UINT32 uCallBackId, void *fCbFunc, TI_HANDLE hCbHndl); +#ifdef TI_DBG +void txHwQueue_PrintInfo (TI_HANDLE hTxHwQueue); +#endif /* TI_DBG */ + + +#endif /* _TX_HW_QUEUE_API_H */ + + + + diff --git a/wilink_6_1/TWD/Data_Service/RxQueue.c b/wilink_6_1/TWD/Data_Service/RxQueue.c new file mode 100644 index 0000000..7f627be --- /dev/null +++ b/wilink_6_1/TWD/Data_Service/RxQueue.c @@ -0,0 +1,823 @@ +/* + * RxQueue.c + * + * Copyright(c) 1998 - 2009 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 RxQueue.c + * \brief RX Queue module that responsible to support re-ordering of received packets to upper layers. + * + * \see RxQueue.h + */ +#define __FILE_ID__ FILE_ID_98 +#include "tidef.h" +#include "osApi.h" +#include "report.h" +#include "RxBuf.h" +#include "TWDriver.h" +#include "public_descriptors.h" + +/************************ static definition declaration *****************************/ +#define RX_QUEUE_ARRAY_SIZE 8 +#define RX_QUEUE_ARRAY_SIZE_BIT_MASK 0x7 /* RX_QUEUE_ARRAY_SIZE -1 */ +#define RX_QUEUE_WIN_SIZE RX_QUEUE_ARRAY_SIZE + +#define BA_SESSION_IS_A_BIGGER_THAN_B(A,B) (((((A)-(B)) & 0xFFF) < 0x7FF) && ((A)!=(B))) +#define BA_SESSION_IS_A_BIGGER_EQUAL_THAN_B(A,B) (((((A)-(B)) & 0xFFF) < 0x7FF)) +#define SEQ_NUM_WRAP 0x1000 +#define SEQ_NUM_MASK 0xFFF + + +/************************ static structures declaration *****************************/ +/* structure describe one entry of save packet information in the packet queue array */ +typedef struct +{ + void *pPacket; /* Packet address of the packet */ + TI_STATUS tStatus; /* RxXfer status. */ + TI_UINT16 uFrameSn; +} TRxQueuePacketEntry; + +/* structure describe set of data that one Tid, also including the arras himself */ +typedef struct +{ + /* array packets Entries */ + TRxQueuePacketEntry aPaketsQueue [RX_QUEUE_ARRAY_SIZE]; + /* TID BA state */ + TI_BOOL aTidBaEstablished; + /* index that winStar point on */ + TI_UINT32 aWinStartArrayInex; + /* windows size */ + TI_UINT32 aTidWinSize; + /* expected sequence number (ESN) */ + TI_UINT16 aTidExpectedSn; +} TRxQueueTidDataBase; + +/* structure describe set of data that assist of manage one SA RxQueue arrays */ +typedef struct +{ + TRxQueueTidDataBase tSa1ArrayMng [MAX_NUM_OF_802_1d_TAGS]; +} TRxQueueArraysMng; + +/* main RxQueue structure in order to management the packets disordered array. */ +typedef struct +{ + TI_HANDLE hOs; /* OS handler */ + TI_HANDLE hReport; /* Report handler */ + TRxQueueArraysMng tRxQueueArraysMng; /* manage each Source Address RxQueue arrays */ + TPacketReceiveCb tReceivePacketCB; /* Receive packets CB address */ + TI_HANDLE hReceivePacketCB_handle; /* Receive packets CB handler */ + +} TRxQueue; + +/************************ static function declaration *****************************/ +static TI_STATUS RxQueue_PassPacket (TI_HANDLE hRxQueue, TI_STATUS tStatus, const void *pBuffer); + +/** + * \fn RxQueue_Create() + * \brief Create the RxQueue module. + * + * Allocate and clear the RxQueue module object. + * + * \param hOs - Handle to Os Abstraction Layer + * \return Handle of the allocated object + * \sa RxQueue_Destroy + */ +TI_HANDLE RxQueue_Create (TI_HANDLE hOs) +{ + TRxQueue *pRxQueue; + + /* allocate module object */ + pRxQueue = os_memoryAlloc (hOs, sizeof(TRxQueue)); + + if (!pRxQueue) + { + WLAN_OS_REPORT (("RxQueue_Create(): Allocation failed!!\n")); + return NULL; + } + + os_memoryZero (hOs, pRxQueue, (sizeof(TRxQueue))); + + pRxQueue->hOs = hOs; + + return (pRxQueue); +} + + +/** + * \fn RxQueue_Destroy() + * \brief Destroy the module. + * + * Free the module's queues and object. + * + * \param hRxQueue - The module object + * \return TI_OK on success or TI_NOK on failure + * \sa RxQueue_Create + */ +TI_STATUS RxQueue_Destroy (TI_HANDLE hRxQueue) +{ + TRxQueue *pRxQueue = (TRxQueue *)hRxQueue; + + /* free module object */ + os_memoryFree (pRxQueue->hOs, pRxQueue, sizeof(TRxQueue)); + + return TI_OK; +} + + +/** + * \fn RxQueue_Init() + * \brief Init required handles + * + * Init required handles and module variables. + * + * \note + * \param hRxQueue - The module object + * \param hReport - Report module Handles + * \return TI_OK on success or TI_NOK on failure + * \sa + */ +TI_STATUS RxQueue_Init (TI_HANDLE hRxQueue, TI_HANDLE hReport) +{ + TRxQueue *pRxQueue = (TRxQueue *)hRxQueue; + + pRxQueue->hReport = hReport; + + return TI_OK; +} + + +/** + * \fn RxQueue_Register_CB() + * \brief Register the function to be called for received Rx. + * + * \note + * \param hRxQueue - The module object + * \param CallBackID - event ID + * \param CBFunc - function address. + * \param CBObj - function parameter. + * \return TI_OK on success or TI_NOK on failure + * \sa + */ +void RxQueue_Register_CB (TI_HANDLE hRxQueue, TI_UINT32 uCallBackID, void *CBFunc, TI_HANDLE CBObj) +{ + TRxQueue* pRxQueue = (TRxQueue *)hRxQueue; + + TRACE1(pRxQueue->hReport, REPORT_SEVERITY_INFORMATION , "RxQueue_Register_CB: CallBack ID = 0x%x\n", uCallBackID); + + switch(uCallBackID) + { + case TWD_INT_RECEIVE_PACKET: + pRxQueue->tReceivePacketCB = (TPacketReceiveCb)CBFunc; + pRxQueue->hReceivePacketCB_handle = CBObj; + break; + + default: + TRACE0(pRxQueue->hReport, REPORT_SEVERITY_ERROR , "RxQueue_Register_CB: Illegal value\n"); + break; + } +} + +/** + * \fn RxQueue_CloseBaSession () + * \brief Close BA session receiver and pass all packets in the TID queue to upper layer. + * + * \note + * \param hRxQueue - RxQueue handle. + * \param uFrameTid - TID session. + * \return None + * \sa + */ +void RxQueue_CloseBaSession(TI_HANDLE hRxQueue, TI_UINT8 uFrameTid) +{ + TRxQueue *pRxQueue = (TRxQueue *)hRxQueue; + TI_UINT32 i; + /*set the SA Tid pointer */ + TRxQueueTidDataBase *pTidDataBase = &(pRxQueue->tRxQueueArraysMng.tSa1ArrayMng[uFrameTid]); + + /* TID illegal value ? */ + if (uFrameTid >= MAX_NUM_OF_802_1d_TAGS) + { + TRACE1(pRxQueue->hReport, REPORT_SEVERITY_ERROR , "RxQueue_CloseBaSession: BA event - DELBA frame with TID value too big, TID = %d\n", uFrameTid); + + return; + } + + if(pTidDataBase->aTidBaEstablished == TI_TRUE) + { + /* clean BA session */ + pTidDataBase->aTidBaEstablished = TI_FALSE; + + /* pass all valid entries at the array */ + for (i = 0; (i < RX_QUEUE_ARRAY_SIZE) && (i < RX_QUEUE_WIN_SIZE); i++) + { + if (pTidDataBase->aPaketsQueue[pTidDataBase->aWinStartArrayInex].pPacket != NULL) + { + RxQueue_PassPacket (pRxQueue, + pTidDataBase->aPaketsQueue[pTidDataBase->aWinStartArrayInex].tStatus, + pTidDataBase->aPaketsQueue[pTidDataBase->aWinStartArrayInex].pPacket); + + pTidDataBase->aPaketsQueue[pTidDataBase->aWinStartArrayInex].pPacket = NULL; + } + + pTidDataBase->aWinStartArrayInex ++; + + /* aWinStartArrayInex % RX_QUEUE_ARRAY_SIZE */ + pTidDataBase->aWinStartArrayInex &= RX_QUEUE_ARRAY_SIZE_BIT_MASK; + } + } +} + + +/** + * \fn RxQueue_PassPacket() + * \brief Responsible on decode packet parameters and pass it to upper layer. + * + * \note + * \param hRxQueue - RxQueue handle. + * \param aStatus - RxXfer status that indicate if the upper layer should free the packet or use it. + * \param pFrame - paket address of the packet + * \param pRxParams - address to structure of the Rx Descriptor received by FW. + * \return TI_OK on success or TI_NOK on failure + * \sa + */ +static TI_STATUS RxQueue_PassPacket (TI_HANDLE hRxQueue, TI_STATUS tStatus, const void *pBuffer) +{ + + TRxQueue *pRxQueue = (TRxQueue *)hRxQueue; + + if (tStatus == TI_OK) + { + /* Get the mac header location in the packet Buffer */ + dot11_header_t *pMacHdr = (dot11_header_t *)(TI_UINT8*)RX_BUF_DATA(pBuffer); + + /* Handle endian for the frame control fields */ + pMacHdr->fc = ENDIAN_HANDLE_WORD(pMacHdr->fc); + pMacHdr->duration = ENDIAN_HANDLE_WORD(pMacHdr->duration); + pMacHdr->seqCtrl = ENDIAN_HANDLE_WORD(pMacHdr->seqCtrl); + } + else + { + RxIfDescriptor_t *pRxParams = (RxIfDescriptor_t*)pBuffer; + + pRxParams->status &= ~RX_DESC_STATUS_MASK; + pRxParams->status |= RX_DESC_STATUS_DRIVER_RX_Q_FAIL; + } + + TRACE0(pRxQueue->hReport, REPORT_SEVERITY_INFORMATION , "RxQueue_PassPacket: call TWD_OWNER_RX_QUEUE CB. In std rxData_ReceivePacket()\n"); + + /* Set the packet to upper layer */ + /* if the packet status not success it will be discarded */ + pRxQueue->tReceivePacketCB (pRxQueue->hReceivePacketCB_handle, pBuffer); + + return TI_OK; +} + + +/** + * \fn RxQueue_ReceivePacket() + * \brief Main function of the RxQueue module. + * Responsible on reorder of the packets from the RxXfer to the RX module. + * Call from RxXfer in order to pass packet to uppers layers. + * In order to save disordered packets the module use array of structures per TID + * that each entry describe a packet. The array elements is sorted in the way that + * the winStart array index represent always the winStar packet and the lowest SN. + * Each increment index represent index at the BA window. Array index winEnd always + * represent winEnd packet. The indexes of winStart and winEnd handled in cyclic manner. + * The function functionality devided to parts: + * Part 1: + * in case the modulo receive packet with SN equal to winStart: + * " pass it to upper layers + * " increases winStart and array index winStart + * " validate that all sequential queue packet are pass to the upper layers. + * Part 2: + * in case the modulo receive packet that SN between winStart to winEnd: + * " Save it sorted at the array at index: Save index = ((SN - winStart) + index array winStart) % arraySize. + * Part 3: + * in case the modulo receive packet that SN higher then winEnd: + * " Update winStart and WinEnd. + * " Save it sorted at the array in index winEnd index. + * " Pass to the upper layers all packets at the array indexes from old winStart index to the updated winStart index. + * Part 4 + 5: + * in case the modulo receive BA event packet: + * " Update winStart and WinEnd + * " Pass to the upper layers all packets at the array indexes from old winStart index to the updated winStart index. + * " Free BA event packet via pass it to upper layers with error status. + * + * \note + * \param hRxQueue - RxQueue handle. + * \param aStatus - RxXfer status that indicate if the upper layer should free the packet or use it. + * \param pBuffer - paket address of the packet + * \return None + * \sa + */ +void RxQueue_ReceivePacket (TI_HANDLE hRxQueue, const void * pBuffer) +{ + TRxQueue *pRxQueue = (TRxQueue *)hRxQueue; + RxIfDescriptor_t *pRxParams = (RxIfDescriptor_t*)pBuffer; + TI_UINT8 *pFrame = RX_BUF_DATA((TI_UINT8 *)pBuffer); + TI_STATUS tStatus = TI_OK; + dot11_header_t *pHdr = (dot11_header_t *)pFrame; + TI_UINT16 uQosControl; + + COPY_WLAN_WORD(&uQosControl, &pHdr->qosControl); /* copy with endianess handling. */ + + /* + * Retrieving the TAG from the packet itself and not from the Rx Descriptor since by now it is not correct + * Note: in the DR TAG_CLASS_EAPOL packet handled as TAG_CLASS_QOS_DATA + */ + if (IS_QOS_FRAME(*(TI_UINT16*)pFrame) && (pRxParams->packet_class_tag != TAG_CLASS_QOS_DATA) && (pRxParams->packet_class_tag != TAG_CLASS_AMSDU)) + { + TRACE1(pRxQueue->hReport, REPORT_SEVERITY_WARNING, "RxQueue_ReceivePacket: BAD CLASS TAG =0x%x from FW.\n", pRxParams->packet_class_tag); + + /* Get AMSDU bit from frame */ + if( uQosControl & DOT11_QOS_CONTROL_FIELD_A_MSDU_BITS) + { + pRxParams->packet_class_tag = TAG_CLASS_AMSDU; + } + else + { + pRxParams->packet_class_tag = TAG_CLASS_QOS_DATA; + } + } + + /* + * packet doesn't need reorder ? + */ + if ((pRxParams->packet_class_tag != TAG_CLASS_QOS_DATA) && (pRxParams->packet_class_tag != TAG_CLASS_BA_EVENT) && (pRxParams->packet_class_tag != TAG_CLASS_AMSDU)) + { + TRACE0(pRxQueue->hReport, REPORT_SEVERITY_INFORMATION, "RxQueue_ReceivePacket: pass packet without reorder.\n"); + + RxQueue_PassPacket (pRxQueue, tStatus, pBuffer); + + return; + } + + + /* + * pRxParams->type == TAG_CLASS_QOS_DATA ? + */ + if ((pRxParams->packet_class_tag == TAG_CLASS_QOS_DATA) || (pRxParams->packet_class_tag == TAG_CLASS_AMSDU)) + { + TI_UINT8 uFrameTid; + TI_UINT16 uFrameSn; + TI_UINT16 uSequenceControl; + TRxQueueTidDataBase *pTidDataBase; + + /* Get TID from frame */ + uFrameTid = uQosControl & DOT11_QOS_CONTROL_FIELD_TID_BITS; + + /* TID illegal value ? */ + if (uFrameTid >= MAX_NUM_OF_802_1d_TAGS) + { + TRACE1(pRxQueue->hReport, REPORT_SEVERITY_ERROR, "RxQueue_ReceivePacket: TID value too big, TID = %d. packet discarded!\n",uFrameTid); + + RxQueue_PassPacket (pRxQueue, TI_NOK, pBuffer); + + return; + } + + /*set the SA Tid pointer */ + pTidDataBase = &(pRxQueue->tRxQueueArraysMng.tSa1ArrayMng[uFrameTid]); + + /* TID legal value */ + /* packet TID BA not established ? */ + if (pTidDataBase->aTidBaEstablished != TI_TRUE) + { + TRACE0(pRxQueue->hReport, REPORT_SEVERITY_INFORMATION, "RxQueue_ReceivePacket: pass packet without reorder.\n"); + + RxQueue_PassPacket (pRxQueue, tStatus, pBuffer); + + return; + } + + /* packet TID BA established */ + /* Get Sequence Number from frame */ + COPY_WLAN_WORD(&uSequenceControl, &pHdr->seqCtrl); /* copy with endianess handling. */ + uFrameSn = (uSequenceControl & DOT11_SC_SEQ_NUM_MASK) >> 4; + + /* + * note: + * the FW never send paket, in establish TID BA, that the SN less then ESN !!! + */ + + /* frame Sequence Number is the expected one ? */ + if (uFrameSn == pTidDataBase->aTidExpectedSn) + { + TRACE0(pRxQueue->hReport, REPORT_SEVERITY_INFORMATION, "RxQueue_ReceivePacket: frame Sequence Number == expected one Sequence Number.\n"); + + /* pass the packet */ + RxQueue_PassPacket (pRxQueue, tStatus, pBuffer); + + pTidDataBase->aTidExpectedSn++; + pTidDataBase->aTidExpectedSn &= 0xfff; + + /* increase the ArrayInex to the next */ + pTidDataBase->aWinStartArrayInex++; + + /* aWinStartArrayInex % RX_QUEUE_ARRAY_SIZE */ + pTidDataBase->aWinStartArrayInex &= RX_QUEUE_ARRAY_SIZE_BIT_MASK; + + /* pass all saved queue packets with SN higher then the expected one */ + while (pTidDataBase->aPaketsQueue[pTidDataBase->aWinStartArrayInex].pPacket != NULL) + { + RxQueue_PassPacket (pRxQueue, + pTidDataBase->aPaketsQueue[pTidDataBase->aWinStartArrayInex].tStatus, + pTidDataBase->aPaketsQueue[pTidDataBase->aWinStartArrayInex].pPacket); + + pTidDataBase->aPaketsQueue[pTidDataBase->aWinStartArrayInex].pPacket = NULL; + + pTidDataBase->aWinStartArrayInex++; + + /* aWinStartArrayInex % RX_QUEUE_ARRAY_SIZE */ + pTidDataBase->aWinStartArrayInex &= RX_QUEUE_ARRAY_SIZE_BIT_MASK; + + pTidDataBase->aTidExpectedSn++; + pTidDataBase->aTidExpectedSn &= 0xfff; + } + + return; + } + + /* frame Sequence Number is lower then Expected sequence number (ISN) ? */ + if (! BA_SESSION_IS_A_BIGGER_THAN_B (uFrameSn, pTidDataBase->aTidExpectedSn)) + { + /* WLAN_OS_REPORT(("%s: ERROR - SN=%u is less than ESN=%u\n", __FUNCTION__, uFrameSn, pTidDataBase->aTidExpectedSn)); */ + + TRACE2(pRxQueue->hReport, REPORT_SEVERITY_ERROR, + "RxQueue_ReceivePacket: frame SN=%u is less than ESN=%u\n",uFrameSn,pTidDataBase->aTidExpectedSn); + + RxQueue_PassPacket (pRxQueue, TI_NOK, pBuffer); + + return; + } + + /* frame Sequence Number between winStart and winEnd ? */ + if ((BA_SESSION_IS_A_BIGGER_THAN_B (uFrameSn, pTidDataBase->aTidExpectedSn)) && + /* mean: uFrameSn <= pTidDataBase->aTidExpectedSn + pTidDataBase->aTidWinSize) */ + ( ! BA_SESSION_IS_A_BIGGER_THAN_B (uFrameSn,(pTidDataBase->aTidExpectedSn + pTidDataBase->aTidWinSize - 1)))) + { + TI_UINT16 uSaveInex = pTidDataBase->aWinStartArrayInex + (TI_UINT16)((uFrameSn + SEQ_NUM_WRAP - pTidDataBase->aTidExpectedSn) & SEQ_NUM_MASK); + /* uSaveInex % RX_QUEUE_ARRAY_SIZE */ + uSaveInex &= RX_QUEUE_ARRAY_SIZE_BIT_MASK; + + + if (pTidDataBase->aPaketsQueue[uSaveInex].pPacket == NULL) + { + /* save the packet in the queue */ + pTidDataBase->aPaketsQueue[uSaveInex].tStatus = tStatus; + pTidDataBase->aPaketsQueue[uSaveInex].pPacket = (void *)pBuffer; + pTidDataBase->aPaketsQueue[uSaveInex].uFrameSn = uFrameSn; + } + else + { + TRACE1(pRxQueue->hReport, REPORT_SEVERITY_ERROR, "RxQueue_ReceivePacket: frame Sequence has allready saved. uFrameSn = %d\n",uFrameSn); + RxQueue_PassPacket (pRxQueue, TI_NOK, pBuffer); + return; + } + return; + } + + + /* + frame Sequence Number higher then winEnd ? + */ + if ( BA_SESSION_IS_A_BIGGER_THAN_B (uFrameSn, (pTidDataBase->aTidExpectedSn + pTidDataBase->aTidWinSize - 1)) ) + { + TI_UINT32 i; + TI_UINT16 uNewWinStartSn = (uFrameSn + SEQ_NUM_WRAP - pTidDataBase->aTidWinSize + 1) & SEQ_NUM_MASK; + TI_UINT16 uSaveInex; + + TRACE0(pRxQueue->hReport, REPORT_SEVERITY_INFORMATION, "RxQueue_ReceivePacket: frame Sequence Number higher then winEnd.\n"); + + /* increase the ArrayInex to the next */ + pTidDataBase->aWinStartArrayInex++; + + /* aWinStartArrayInex % RX_QUEUE_ARRAY_SIZE */ + pTidDataBase->aWinStartArrayInex &= RX_QUEUE_ARRAY_SIZE_BIT_MASK; + + /* update the Expected SN since the current one is lost */ + pTidDataBase->aTidExpectedSn++; + pTidDataBase->aTidExpectedSn &= 0xFFF; + + /* pass all saved queue packets with SN lower then the new win start */ + for (i = 0; + BA_SESSION_IS_A_BIGGER_THAN_B(uNewWinStartSn,pTidDataBase->aTidExpectedSn) && + (i < RX_QUEUE_ARRAY_SIZE) && + (i < pTidDataBase->aTidWinSize); + i++) + { + if (pTidDataBase->aPaketsQueue[pTidDataBase->aWinStartArrayInex].pPacket != NULL) + { + RxQueue_PassPacket (pRxQueue, + pTidDataBase->aPaketsQueue[pTidDataBase->aWinStartArrayInex].tStatus, + pTidDataBase->aPaketsQueue[pTidDataBase->aWinStartArrayInex].pPacket); + + pTidDataBase->aPaketsQueue[pTidDataBase->aWinStartArrayInex].pPacket = NULL; + } + + pTidDataBase->aWinStartArrayInex++; + + /* aWinStartArrayInex % RX_QUEUE_ARRAY_SIZE */ + pTidDataBase->aWinStartArrayInex &= RX_QUEUE_ARRAY_SIZE_BIT_MASK; + + pTidDataBase->aTidExpectedSn++; + pTidDataBase->aTidExpectedSn &= 0xFFF; + + } + + /* Calculate the new Expected SN */ + if (i == pTidDataBase->aTidWinSize) + { + pTidDataBase->aTidExpectedSn = uNewWinStartSn; + } + else + { + /* Incase the uWinStartDelta lower than aTidWinSize check if ther are packets stored in Array */ + while (pTidDataBase->aPaketsQueue[pTidDataBase->aWinStartArrayInex].pPacket != NULL) { + RxQueue_PassPacket (pRxQueue, + pTidDataBase->aPaketsQueue[pTidDataBase->aWinStartArrayInex].tStatus, + pTidDataBase->aPaketsQueue[pTidDataBase->aWinStartArrayInex].pPacket); + + pTidDataBase->aPaketsQueue[pTidDataBase->aWinStartArrayInex].pPacket = NULL; + + pTidDataBase->aWinStartArrayInex++; + + /* aWinStartArrayInex % RX_QUEUE_ARRAY_SIZE */ + pTidDataBase->aWinStartArrayInex &= RX_QUEUE_ARRAY_SIZE_BIT_MASK; + + pTidDataBase->aTidExpectedSn++; + pTidDataBase->aTidExpectedSn &= 0xFFF; + } + } + + if(pTidDataBase->aTidExpectedSn == uFrameSn) + { + /* pass the packet */ + RxQueue_PassPacket (pRxQueue, tStatus, pBuffer); + pTidDataBase->aTidExpectedSn++; + pTidDataBase->aTidExpectedSn &= 0xfff; + } + else + { + uSaveInex = pTidDataBase->aWinStartArrayInex + (TI_UINT16)((uFrameSn + SEQ_NUM_WRAP - pTidDataBase->aTidExpectedSn) & SEQ_NUM_MASK); + + /* uSaveInex % RX_QUEUE_ARRAY_SIZE */ + uSaveInex &= RX_QUEUE_ARRAY_SIZE_BIT_MASK; + + /* save the packet in the last entry of the queue */ + pTidDataBase->aPaketsQueue[uSaveInex].tStatus = tStatus; + pTidDataBase->aPaketsQueue[uSaveInex].pPacket = (void *)pBuffer; + pTidDataBase->aPaketsQueue[uSaveInex].pPacket = (void *)pBuffer; + } + + return; + } + } + + + /* + * BA event ? + */ + if (pRxParams->packet_class_tag == TAG_CLASS_BA_EVENT) + { + TRxQueueTidDataBase *pTidDataBase; + TI_UINT8 *pDataFrameBody; + TI_UINT16 ufc; + TI_UINT8 uFrameTid; + TI_UINT16 uStartingSequenceNumber; + TI_UINT16 uWinStartDelta; + TI_UINT16 uBarControlField; + TI_UINT16 uBaStartingSequenceControlField; + TI_UINT16 uBAParameterField; + TI_UINT32 i; + + /* Get sub type from frame */ + COPY_WLAN_WORD(&ufc, &pHdr->fc); /* copy with endianess handling. */ + + /* get the type to BA event */ + switch ((dot11_Fc_Sub_Type_e)(ufc & DOT11_FC_SUB_MASK)) + { + case DOT11_FC_SUB_BAR: + TRACE0(pRxQueue->hReport, REPORT_SEVERITY_INFORMATION , "RxQueue_ReceivePacket: BA event - BAR frame.\n"); + + /* get pointer to the frame body */ + pDataFrameBody = pFrame + sizeof(dot11_BarFrameHeader_t); + + /* Get TID from BAR frame */ + COPY_WLAN_WORD (&uBarControlField, (TI_UINT16 *)pDataFrameBody); /* copy with endianess handling. */ + uFrameTid = (uBarControlField & DOT11_BAR_CONTROL_FIELD_TID_BITS) >> 12; + + /* TID illegal value ? */ + if (uFrameTid >= MAX_NUM_OF_802_1d_TAGS) + { + TRACE1(pRxQueue->hReport, REPORT_SEVERITY_ERROR , "RxQueue_ReceivePacket: BA event - BAR frame with TID value too big, TID = %d.\n",uFrameTid); + + RxQueue_PassPacket (pRxQueue, TI_NOK, pBuffer); + + return; + } + + /* set the SA Tid pointer */ + pTidDataBase = &(pRxQueue->tRxQueueArraysMng.tSa1ArrayMng[uFrameTid]); + + /* TID legal value */ + /* packet TID BA not established ? */ + if (pTidDataBase->aTidBaEstablished != TI_TRUE) + { + TRACE1(pRxQueue->hReport, REPORT_SEVERITY_ERROR , "RxQueue_ReceivePacket: BA event - BAR frame for TID not established, TID = %d.\n",uFrameTid); + + RxQueue_PassPacket (pRxQueue, TI_NOK, pBuffer); + + return; + } + + /* Get Starting Sequence number from BAR frame */ + pDataFrameBody = pDataFrameBody + 2; + COPY_WLAN_WORD (&uBaStartingSequenceControlField, (TI_UINT16 *)pDataFrameBody); /* copy with endianess handling. */ + uStartingSequenceNumber = (uBaStartingSequenceControlField & DOT11_SC_SEQ_NUM_MASK) >> 4; + + /* Starting Sequence Number is higher then winStart ? */ + if ( BA_SESSION_IS_A_BIGGER_THAN_B (uStartingSequenceNumber, pTidDataBase->aTidExpectedSn) ) + { + uWinStartDelta = (uStartingSequenceNumber + SEQ_NUM_WRAP - pTidDataBase->aTidExpectedSn) & SEQ_NUM_MASK; + + /* pass all saved queue packets with SN lower then the new win start */ + for (i = 0; + ((i < uWinStartDelta) || (pTidDataBase->aPaketsQueue[pTidDataBase->aWinStartArrayInex].pPacket != NULL)) && + (i < RX_QUEUE_ARRAY_SIZE) && + (i < RX_QUEUE_WIN_SIZE); + i++) + { + if (pTidDataBase->aPaketsQueue[pTidDataBase->aWinStartArrayInex].pPacket != NULL) + { + RxQueue_PassPacket (pRxQueue, + pTidDataBase->aPaketsQueue[pTidDataBase->aWinStartArrayInex].tStatus, + pTidDataBase->aPaketsQueue[pTidDataBase->aWinStartArrayInex].pPacket); + + pTidDataBase->aPaketsQueue[pTidDataBase->aWinStartArrayInex].pPacket = NULL; + } + + pTidDataBase->aWinStartArrayInex++; + + /* aWinStartArrayInex % RX_QUEUE_ARRAY_SIZE */ + pTidDataBase->aWinStartArrayInex &= RX_QUEUE_ARRAY_SIZE_BIT_MASK; + } + + pTidDataBase->aTidExpectedSn = uStartingSequenceNumber; + } + break; + + + case DOT11_FC_SUB_ACTION: + /* get pointer to the frame body */ + pDataFrameBody = pFrame + sizeof(dot11_mgmtHeader_t); + + /* get Action field from BA action frame */ + pDataFrameBody++; + switch(*pDataFrameBody) + { + case DOT11_BA_ACTION_ADDBA: + + TRACE0( pRxQueue->hReport, REPORT_SEVERITY_INFORMATION, "RxQueue_ReceivePacket: BA event - ADDBA frame.\n"); + + /* get TID field and winSize from ADDBA action frame */ + pDataFrameBody = pDataFrameBody + 2; + COPY_WLAN_WORD(&uBAParameterField, (TI_UINT16 *)pDataFrameBody); /* copy with endianess handling. */ + uFrameTid = (uBAParameterField & DOT11_BA_PARAMETER_SET_FIELD_TID_BITS) >> 2; + + /* TID illegal value ? */ + if (uFrameTid >= MAX_NUM_OF_802_1d_TAGS) + { + TRACE1(pRxQueue->hReport, REPORT_SEVERITY_ERROR , "RxQueue_ReceivePacket: BA event - ADDBA frame with TID value too big, TID = %d.\n",uFrameTid); + + RxQueue_PassPacket (pRxQueue, TI_NOK, pBuffer); + + return; + } + + /*set the SA Tid pointer */ + pTidDataBase = &(pRxQueue->tRxQueueArraysMng.tSa1ArrayMng[uFrameTid]); + + /* TID legal value */ + /* packet TID BA established ? */ + if (pTidDataBase->aTidBaEstablished == TI_TRUE) + { + TRACE1(pRxQueue->hReport, REPORT_SEVERITY_ERROR , "RxQueue_ReceivePacket: BA event - ADDBA frame for TID already established, TID = %d.\n",uFrameTid); + + RxQueue_PassPacket (pRxQueue, TI_NOK, pBuffer); + + return; + } + + /* get winSize from ADDBA action frame */ + pTidDataBase->aTidWinSize = (uBAParameterField & DOT11_BA_PARAMETER_SET_FIELD_WINSIZE_BITS) >> 6; + + /* winSize illegal value ? */ + if (pTidDataBase->aTidWinSize > RX_QUEUE_WIN_SIZE) + { + /* In case the win Size is higher then 8 the driver and the FW set it to 8 and inform the AP in ADDBA respond */ + pTidDataBase->aTidWinSize = RX_QUEUE_WIN_SIZE; + } + + /* packet TID BA not yet established and winSize legal */ + /* establishe BA TID */ + pTidDataBase->aTidBaEstablished = TI_TRUE; + + /* get initial sequence number (ISN) from ADDBA action frame */ + pDataFrameBody = pDataFrameBody + 4; + COPY_WLAN_WORD (&uStartingSequenceNumber, (TI_UINT16 *)pDataFrameBody); /* copy with endianess handling. */ + pTidDataBase->aTidExpectedSn = (uStartingSequenceNumber & DOT11_SC_SEQ_NUM_MASK) >> 4; + pTidDataBase->aWinStartArrayInex = 0; + os_memoryZero (pRxQueue->hOs, pTidDataBase->aPaketsQueue, sizeof (TRxQueuePacketEntry) * RX_QUEUE_ARRAY_SIZE); + break; + + case DOT11_BA_ACTION_DELBA: + + TRACE0( pRxQueue->hReport, REPORT_SEVERITY_INFORMATION, "RxQueue_ReceivePacket: BA event - DELBA frame.\n"); + + /* get TID field and winSize from ADDBA action frame */ + pDataFrameBody = pDataFrameBody + 2; + COPY_WLAN_WORD(&uBAParameterField, (TI_UINT16 *)pDataFrameBody); /* copy with endianess handling. */ + uFrameTid = (uBAParameterField & DOT11_DELBA_PARAMETER_FIELD_TID_BITS) >> 12; + + /* TID illegal value ? */ + if (uFrameTid >= MAX_NUM_OF_802_1d_TAGS) + { + TRACE1(pRxQueue->hReport, REPORT_SEVERITY_ERROR , "RxQueue_ReceivePacket: BA event - DELBA frame with TID value too big, TID = %d.\n",uFrameTid); + + RxQueue_PassPacket (pRxQueue, TI_NOK, pBuffer); + + return; + } + + /*set the SA Tid pointer */ + pTidDataBase = &(pRxQueue->tRxQueueArraysMng.tSa1ArrayMng[uFrameTid]); + + /* TID legal value */ + /* packet TID BA not established ? */ + if (pTidDataBase->aTidBaEstablished != TI_TRUE) + { + TRACE1(pRxQueue->hReport, REPORT_SEVERITY_ERROR , "RxQueue_ReceivePacket: BA event - DELBA frame for TID not established, TID = %d.\n",uFrameTid); + + RxQueue_PassPacket (pRxQueue, TI_NOK, pBuffer); + + return; + } + + RxQueue_CloseBaSession(hRxQueue, uFrameTid); + break; + + default: + TRACE1(pRxQueue->hReport, REPORT_SEVERITY_ERROR , "RxQueue_ReceivePacket: BA event Action field from BA action frame illegal. action = 0x%x\n",*pDataFrameBody); + + RxQueue_PassPacket (pRxQueue, TI_NOK, pBuffer); + + return; + } + break; + + default: + TRACE1(pRxQueue->hReport, REPORT_SEVERITY_ERROR , "RxQueue_ReceivePacket: BA event with Subtype illegal. Subtype = 0x%x\n",((ufc & DOT11_FC_SUB_MASK) >> 4)); + + RxQueue_PassPacket (pRxQueue, TI_NOK, pBuffer); + + return; + } + + } + + TRACE1(pRxQueue->hReport, REPORT_SEVERITY_ERROR, "RxQueue_ReceivePacket: unknow type tag. tag = %d\n", pRxParams->packet_class_tag); + + RxQueue_PassPacket (pRxQueue, tStatus, pBuffer); + + return; +} + diff --git a/wilink_6_1/TWD/Data_Service/txCtrlBlk.c b/wilink_6_1/TWD/Data_Service/txCtrlBlk.c new file mode 100644 index 0000000..1462e1b --- /dev/null +++ b/wilink_6_1/TWD/Data_Service/txCtrlBlk.c @@ -0,0 +1,281 @@ +/* + * txCtrlBlk.c + * + * Copyright(c) 1998 - 2009 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. + */ + + +/**************************************************************************** + * + * MODULE: txCtrlBlk.c + * + * PURPOSE: Maintains active packets Tx attributes table (including descriptor). + * + * DESCRIPTION: + * ============ + * This module allocates and frees table entry for each packet in the Tx + * process (from sendPkt by upper driver until Tx-complete). + * + ****************************************************************************/ +#define __FILE_ID__ FILE_ID_99 +#include "osApi.h" +#include "tidef.h" +#include "report.h" +#include "context.h" +#include "TWDriver.h" +#include "txCtrlBlk_api.h" + + +/* The TxCtrlBlk module object - contains the control-block table. */ +typedef struct +{ + TI_HANDLE hOs; + TI_HANDLE hReport; + TI_HANDLE hContext; + + TTxCtrlBlk aTxCtrlBlkTbl[CTRL_BLK_ENTRIES_NUM]; /* The table of control-block entries. */ + +#ifdef TI_DBG /* Just for debug. */ + TI_UINT32 uNumUsedEntries; +#endif + +} TTxCtrlBlkObj; + + +/**************************************************************************** + * txCtrlBlk_Create() + **************************************************************************** + * DESCRIPTION: Create the Tx control block table object + * + * INPUTS: hOs + * + * OUTPUT: None + * + * RETURNS: The Created object + ****************************************************************************/ +TI_HANDLE txCtrlBlk_Create (TI_HANDLE hOs) +{ + TTxCtrlBlkObj *pTxCtrlBlk; + + pTxCtrlBlk = os_memoryAlloc (hOs, sizeof(TTxCtrlBlkObj)); + if (pTxCtrlBlk == NULL) + return NULL; + + os_memoryZero (hOs, pTxCtrlBlk, sizeof(TTxCtrlBlkObj)); + + pTxCtrlBlk->hOs = hOs; + + return( (TI_HANDLE)pTxCtrlBlk ); +} + + +/**************************************************************************** + * txCtrlBlk_Destroy() + **************************************************************************** + * DESCRIPTION: Destroy the Tx control block table object + * + * INPUTS: hTxCtrlBlk - The object to free + * + * OUTPUT: None + * + * RETURNS: TI_OK or TI_NOK + ****************************************************************************/ +TI_STATUS txCtrlBlk_Destroy (TI_HANDLE hTxCtrlBlk) +{ + TTxCtrlBlkObj *pTxCtrlBlk = (TTxCtrlBlkObj *)hTxCtrlBlk; + + if (pTxCtrlBlk) + os_memoryFree(pTxCtrlBlk->hOs, pTxCtrlBlk, sizeof(TTxCtrlBlkObj)); + + return TI_OK; +} + + +/**************************************************************************** + * txCtrlBlk_Init() + **************************************************************************** + DESCRIPTION: Initialize the Tx control block module. + ****************************************************************************/ +TI_STATUS txCtrlBlk_Init (TI_HANDLE hTxCtrlBlk, TI_HANDLE hReport, TI_HANDLE hContext) +{ + TTxCtrlBlkObj *pTxCtrlBlk = (TTxCtrlBlkObj *)hTxCtrlBlk; + TI_UINT8 entry; + + pTxCtrlBlk->hReport = hReport; + pTxCtrlBlk->hContext = hContext; + + /* For all entries, write the entry index in the descriptor and the next entry address + in the next free entery pointer. Init also some other fields. */ + for(entry = 0; entry < CTRL_BLK_ENTRIES_NUM; entry++) + { + pTxCtrlBlk->aTxCtrlBlkTbl[entry].tTxDescriptor.descID = entry; + pTxCtrlBlk->aTxCtrlBlkTbl[entry].pNextFreeEntry = &(pTxCtrlBlk->aTxCtrlBlkTbl[entry + 1]); + pTxCtrlBlk->aTxCtrlBlkTbl[entry].tTxDescriptor.aid = 1; /* The value for infrastructure BSS */ + pTxCtrlBlk->aTxCtrlBlkTbl[entry].tTxDescriptor.reserved = 0; + } + + /* Write null in the next-free index of the last entry. */ + pTxCtrlBlk->aTxCtrlBlkTbl[CTRL_BLK_ENTRIES_NUM - 1].pNextFreeEntry = NULL; + + #ifdef TI_DBG + pTxCtrlBlk->uNumUsedEntries = 0; + #endif + + return TI_OK; +} + + +/**************************************************************************** + * txCtrlBlk_Alloc() + **************************************************************************** + * DESCRIPTION: + Allocate a free control-block entry for the current Tx packet's parameters + (including the descriptor structure). + Note that entry 0 in the list is never allocated and points to the + first free entry. + ****************************************************************************/ +TTxCtrlBlk *txCtrlBlk_Alloc (TI_HANDLE hTxCtrlBlk) +{ + TTxCtrlBlkObj *pTxCtrlBlk = (TTxCtrlBlkObj *)hTxCtrlBlk; + TTxCtrlBlk *pCurrentEntry; /* The pointer of the new entry allocated for the packet. */ + TTxCtrlBlk *pFirstFreeEntry; /* The first entry just points to the first free entry. */ + + pFirstFreeEntry = &(pTxCtrlBlk->aTxCtrlBlkTbl[0]); + + /* Protect block allocation from preemption (may be called from external context) */ + context_EnterCriticalSection (pTxCtrlBlk->hContext); + + pCurrentEntry = pFirstFreeEntry->pNextFreeEntry; /* Get free entry. */ + +#ifdef TI_DBG + /* If no free entries, print error (not expected to happen) and return NULL. */ + if (pCurrentEntry->pNextFreeEntry == NULL) + { +TRACE1(pTxCtrlBlk->hReport, REPORT_SEVERITY_ERROR, "txCtrlBlk_alloc(): No free entry, UsedEntries=%d\n", pTxCtrlBlk->uNumUsedEntries); + context_LeaveCriticalSection (pTxCtrlBlk->hContext); + return NULL; + } + pTxCtrlBlk->uNumUsedEntries++; +#endif + + /* Link the first entry to the next free entry. */ + pFirstFreeEntry->pNextFreeEntry = pCurrentEntry->pNextFreeEntry; + + context_LeaveCriticalSection (pTxCtrlBlk->hContext); + + /* Clear the next-free-entry index just as an indication that our entry is not free. */ + pCurrentEntry->pNextFreeEntry = 0; + + pCurrentEntry->tTxPktParams.uFlags = 0; + pCurrentEntry->tTxPktParams.uHeadroomSize = 0; + + return pCurrentEntry; +} + + +/**************************************************************************** + * txCtrlBlk_Free() + **************************************************************************** + * DESCRIPTION: + Link the freed entry after entry 0, so now it is the first free entry to + be allocated. + ****************************************************************************/ +void txCtrlBlk_Free (TI_HANDLE hTxCtrlBlk, TTxCtrlBlk *pCurrentEntry) +{ + TTxCtrlBlkObj *pTxCtrlBlk = (TTxCtrlBlkObj *)hTxCtrlBlk; + TTxCtrlBlk *pFirstFreeEntry = &(pTxCtrlBlk->aTxCtrlBlkTbl[0]); + +#ifdef TI_DBG + /* If the pointed entry is already free, print error and exit (not expected to happen). */ + if (pCurrentEntry->pNextFreeEntry != 0) + { +TRACE2(pTxCtrlBlk->hReport, REPORT_SEVERITY_ERROR, "txCtrlBlk_free(): Entry %d alredy free, UsedEntries=%d\n", pCurrentEntry->tTxDescriptor.descID, pTxCtrlBlk->uNumUsedEntries); + return; + } + pTxCtrlBlk->uNumUsedEntries--; +#endif + + /* Protect block freeing from preemption (may be called from external context) */ + context_EnterCriticalSection (pTxCtrlBlk->hContext); + + /* Link the freed entry between entry 0 and the next free entry. */ + pCurrentEntry->pNextFreeEntry = pFirstFreeEntry->pNextFreeEntry; + pFirstFreeEntry->pNextFreeEntry = pCurrentEntry; + + context_LeaveCriticalSection (pTxCtrlBlk->hContext); +} + + +/**************************************************************************** + * txCtrlBlk_GetPointer() + **************************************************************************** + * DESCRIPTION: + Return a pointer to the control block entry of the requested packet. + Used upon tx-complete to retrieve info after getting the descId from the FW. + ****************************************************************************/ +TTxCtrlBlk *txCtrlBlk_GetPointer (TI_HANDLE hTxCtrlBlk, TI_UINT8 descId) +{ + TTxCtrlBlkObj *pTxCtrlBlk = (TTxCtrlBlkObj *)hTxCtrlBlk; + return ( &(pTxCtrlBlk->aTxCtrlBlkTbl[descId]) ); +} + + +/**************************************************************************** + * txCtrlBlk_PrintTable() + **************************************************************************** + * DESCRIPTION: Print the txCtrlBlk table main fields. + ****************************************************************************/ +#ifdef TI_DBG +void txCtrlBlk_PrintTable (TI_HANDLE hTxCtrlBlk) +{ +#ifdef REPORT_LOG + TTxCtrlBlkObj *pTxCtrlBlk = (TTxCtrlBlkObj *)hTxCtrlBlk; + TI_UINT8 entry; + + WLAN_OS_REPORT((" Tx-Control-Block Information, UsedEntries=%d\n", pTxCtrlBlk->uNumUsedEntries)); + WLAN_OS_REPORT(("==============================================\n")); + + for(entry = 0; entry < CTRL_BLK_ENTRIES_NUM; entry++) + { + WLAN_OS_REPORT(("Entry %d: DescID=%d, Next=0x%x, Len=%d, StartTime=%d, TID=%d, ExtraBlks=%d, TotalBlks=%d, Flags=0x%x\n", + entry, + pTxCtrlBlk->aTxCtrlBlkTbl[entry].tTxDescriptor.descID, + pTxCtrlBlk->aTxCtrlBlkTbl[entry].pNextFreeEntry, + ENDIAN_HANDLE_WORD(pTxCtrlBlk->aTxCtrlBlkTbl[entry].tTxDescriptor.length), + ENDIAN_HANDLE_LONG(pTxCtrlBlk->aTxCtrlBlkTbl[entry].tTxDescriptor.startTime), + pTxCtrlBlk->aTxCtrlBlkTbl[entry].tTxDescriptor.tid, + pTxCtrlBlk->aTxCtrlBlkTbl[entry].tTxDescriptor.extraMemBlks, + pTxCtrlBlk->aTxCtrlBlkTbl[entry].tTxDescriptor.totalMemBlks, + pTxCtrlBlk->aTxCtrlBlkTbl[entry].tTxPktParams.uFlags)); + } +#endif +} +#endif /* TI_DBG */ + diff --git a/wilink_6_1/TWD/Data_Service/txHwQueue.c b/wilink_6_1/TWD/Data_Service/txHwQueue.c new file mode 100644 index 0000000..19a0098 --- /dev/null +++ b/wilink_6_1/TWD/Data_Service/txHwQueue.c @@ -0,0 +1,712 @@ +/* + * txHwQueue.c + * + * Copyright(c) 1998 - 2009 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. + */ + + +/**************************************************************************** + * + * MODULE: txHwQueue.c + * + * PURPOSE: manage the wlan hardware Tx memory blocks allocation per queue. + * + * DESCRIPTION: + * ============ + * This module is responsible for the HW Tx data-blocks and descriptors allocation. + * The HW Tx blocks are allocated in the driver by rough calculations without + * accessing the FW. + * They are freed according to FW counters that are provided by the FwEvent module + * on every FW interrupt. + ****************************************************************************/ +#define __FILE_ID__ FILE_ID_100 +#include "osApi.h" +#include "report.h" +#include "TWDriver.h" +#include "txCtrlBlk_api.h" +#include "txHwQueue_api.h" + + +/* Translate input TID to AC */ +/* Note: This structure is shared with other modules */ +const EAcTrfcType WMEQosTagToACTable[MAX_NUM_OF_802_1d_TAGS] = + {QOS_AC_BE, QOS_AC_BK, QOS_AC_BK, QOS_AC_BE, QOS_AC_VI, QOS_AC_VI, QOS_AC_VO, QOS_AC_VO}; + +/* + * Local definitions: + */ + +/* Spare blocks written in extraMemBlks field in TxDescriptor for HW use */ +#define BLKS_HW_ALLOC_SPARE 2 + +/* Set queue's backpressure bit (indicates queue state changed from ready to busy or inversely). */ +#define SET_QUEUE_BACKPRESSURE(pBackpressure, uQueueId) (*pBackpressure |= (1 << uQueueId)) + +/* Callback function definition for UpdateBusyMap */ +typedef void (* tUpdateBusyMapCb)(TI_HANDLE hCbHndl, TI_UINT32 uBackpressure); + +/* Per Queue HW blocks accounting data: */ +typedef struct +{ + TI_UINT32 uNumBlksThresh; /* Minimum HW blocks that must be reserved for this Queue. */ + TI_UINT32 uNumBlksUsed; /* Number of HW blocks that are currently allocated for this Queue. */ + TI_UINT32 uNumBlksReserved; /* Number of HW blocks currently reserved for this Queue (to guarentee the low threshold). */ + TI_UINT32 uAllocatedBlksCntr; /* Accumulates allocated blocks for FW freed-blocks counter coordination. */ + TI_UINT32 uFwFreedBlksCntr; /* Accumulated freed blocks in FW. */ + TI_UINT32 uNumBlksCausedBusy; /* Number of HW blocks that caused queue busy state. */ + TI_BOOL bQueueBusy; /* If TI_TRUE, this queue is currently stopped. */ + TI_UINT16 uPercentOfBlkLowThresh; /* Configured percentage of blocks to use as the queue's low allocation threshold */ + TI_UINT16 uPercentOfBlkHighThresh; /* Configured percentage of blocks to use as the queue's high allocation threshold */ + +} TTxHwQueueInfo; + +typedef struct +{ + TI_HANDLE hOs; + TI_HANDLE hReport; + + tUpdateBusyMapCb fUpdateBusyMapCb; /* The upper layers UpdateBusyMap callback */ + TI_HANDLE hUpdateBusyMapHndl;/* The handle for the fUpdateBusyMapCb */ + + TI_UINT32 uNumTotalBlks; /* The total number of Tx blocks */ + TI_UINT32 uNumTotalBlksFree; /* Total number of free HW blocks */ + TI_UINT32 uNumTotalBlksReserved; /* Total number of free but reserved HW blocks */ + TI_UINT32 uNumUsedDescriptors; /* Total number of packets in the FW. */ + TI_UINT8 uFwTxResultsCntr; /* Accumulated freed descriptors in FW. */ + TI_UINT8 uDrvTxPacketsCntr; /* Accumulated allocated descriptors in driver. */ + + TTxHwQueueInfo aTxHwQueueInfo[MAX_NUM_OF_AC]; /* The per queue variables */ + +} TTxHwQueue; + + +static void txHwQueue_UpdateFreeBlocks (TTxHwQueue *pTxHwQueue, TI_UINT32 uQueueId, TI_UINT32 uFreeBlocks); +static TI_UINT32 txHwQueue_CheckResources (TTxHwQueue *pTxHwQueue, TTxHwQueueInfo *pQueueInfo); + + + +/**************************************************************************** + * txHwQueue_Create() + **************************************************************************** + * DESCRIPTION: Create the Tx buffers pool object + * + * INPUTS: None + * + * OUTPUT: None + * + * RETURNS: The Created object + ****************************************************************************/ +TI_HANDLE txHwQueue_Create (TI_HANDLE hOs) +{ + TTxHwQueue *pTxHwQueue; + + pTxHwQueue = os_memoryAlloc(hOs, sizeof(TTxHwQueue)); + if (pTxHwQueue == NULL) + { + return NULL; + } + + os_memoryZero(hOs, pTxHwQueue, sizeof(TTxHwQueue)); + + pTxHwQueue->hOs = hOs; + + return (TI_HANDLE)pTxHwQueue; +} + +/**************************************************************************** + * txHwQueue_Destroy() + **************************************************************************** + * DESCRIPTION: Destroy the Tx buffers pool object + * + * INPUTS: hTxHwQueue - The object to free + * + * OUTPUT: None + * + * RETURNS: TI_OK or TI_NOK + ****************************************************************************/ +TI_STATUS txHwQueue_Destroy (TI_HANDLE hTxHwQueue) +{ + TTxHwQueue *pTxHwQueue = (TTxHwQueue *)hTxHwQueue; + + if (pTxHwQueue) + { + os_memoryFree(pTxHwQueue->hOs, pTxHwQueue, sizeof(TTxHwQueue)); + } + return TI_OK; +} + + + + +/**************************************************************************** + * txHwQueue_Init() + **************************************************************************** + + DESCRIPTION: Initialize module handles. + + ****************************************************************************/ +TI_STATUS txHwQueue_Init (TI_HANDLE hTxHwQueue, TI_HANDLE hReport) +{ + TTxHwQueue *pTxHwQueue = (TTxHwQueue *)hTxHwQueue; + + pTxHwQueue->hReport = hReport; + + return TI_OK; +} + + +/**************************************************************************** + * txHwQueue_Config() + **************************************************************************** + * DESCRIPTION: Configure the Tx buffers pool object + * + * INPUTS: None + * + * OUTPUT: None + * + * RETURNS: + ****************************************************************************/ +TI_STATUS txHwQueue_Config (TI_HANDLE hTxHwQueue, TTwdInitParams *pInitParams) +{ + TTxHwQueue *pTxHwQueue = (TTxHwQueue *)hTxHwQueue; + TI_UINT32 TxQid; + + /* Configure queue parameters to Tx-HW queue module */ + for (TxQid = 0; TxQid < MAX_NUM_OF_AC; TxQid++) + { + pTxHwQueue->aTxHwQueueInfo[TxQid].uNumBlksThresh = pInitParams->tGeneral.TxBlocksThresholdPerAc[TxQid]; + } + + return TI_OK; +} + + + +/**************************************************************************** + * txHwQueue_SetHwInfo() + **************************************************************************** + + DESCRIPTION: + + Called after the HW configuration in the driver init or recovery process. + Configure Tx HW information, including Tx-HW-blocks number, and per queue + Tx-descriptors number. Than, restart the module variables. + + Two thresholds are defined per queue: + a) TxBlocksLowPercentPerQueue[queue] - The lower threshold is the minimal number of + Tx blocks guaranteed for each queue. + The sum of all low thresholds should be less than 100%. + b) TxBlocksHighPercentPerQueue[queue] - The higher threshold is the maximal number of + Tx blocks that may be allocated to the queue. + The extra blocks above the low threshold can be allocated when needed only + if they are currently available and are not needed in order to guarantee + the other queues low threshold. + The sum of all high thresholds should be more than 100%. + ****************************************************************************/ +TI_STATUS txHwQueue_SetHwInfo (TI_HANDLE hTxHwQueue, TDmaParams *pDmaParams) +{ + TTxHwQueue *pTxHwQueue = (TTxHwQueue *)hTxHwQueue; + + pTxHwQueue->uNumTotalBlks = pDmaParams->NumTxBlocks - 1; /* One block must be always free for FW use. */ + + /* Restart the module variables. */ + txHwQueue_Restart (hTxHwQueue); + + return TI_OK; +} + + +/**************************************************************************** + * txHwQueue_Restart() + **************************************************************************** + DESCRIPTION: + ============ + Called after the HW configuration in the driver init or recovery process. + Restarts the Tx-HW-Queue module. + ****************************************************************************/ +TI_STATUS txHwQueue_Restart (TI_HANDLE hTxHwQueue) +{ + TTxHwQueue *pTxHwQueue = (TTxHwQueue *)hTxHwQueue; + TTxHwQueueInfo *pQueueInfo; + TI_UINT32 TxQid; + + + /* + * All blocks are free at restart. + * Note that free means all blocks that are currently not in use, while reserved are + * a part of the free blocks that are the summary of all queues reserved blocks. + * Each queue may take from the reserved part only up to its own reservation (according to + * its low threshold). + */ + pTxHwQueue->uNumTotalBlksFree = pTxHwQueue->uNumTotalBlks; + pTxHwQueue->uNumTotalBlksReserved = 0; + pTxHwQueue->uNumUsedDescriptors = 0; + pTxHwQueue->uFwTxResultsCntr = 0; + pTxHwQueue->uDrvTxPacketsCntr = 0; + + for (TxQid = 0; TxQid < MAX_NUM_OF_AC; TxQid++) + { + pQueueInfo = &pTxHwQueue->aTxHwQueueInfo[TxQid]; + + pQueueInfo->uNumBlksUsed = 0; + pQueueInfo->uAllocatedBlksCntr = 0; + pQueueInfo->uFwFreedBlksCntr = 0; + pQueueInfo->uNumBlksCausedBusy = 0; + pQueueInfo->bQueueBusy = TI_FALSE; + + /* Since no blocks are used yet, reserved blocks number equals to the low threshold. */ + pQueueInfo->uNumBlksReserved = pQueueInfo->uNumBlksThresh; + + /* Accumulate total reserved blocks. */ + pTxHwQueue->uNumTotalBlksReserved += pQueueInfo->uNumBlksReserved; + } + + return TI_OK; +} + + +/**************************************************************************** + * txHwQueue_AllocResources() + **************************************************************************** + * DESCRIPTION: + ============ + 1. Estimate required HW-blocks number. + 2. If the required blocks are not available or no free descriptor, + return STOP_CURRENT (to stop current queue and requeue the packet). + 3. Resources are available so update allocated blocks and descriptors counters. + 4. If no resources for another similar packet, return STOP_NEXT (to stop current queue). + Else, return SUCCESS + ****************************************************************************/ +ETxHwQueStatus txHwQueue_AllocResources (TI_HANDLE hTxHwQueue, TTxCtrlBlk *pTxCtrlBlk) +{ + TTxHwQueue *pTxHwQueue = (TTxHwQueue *)hTxHwQueue; + TI_UINT32 uNumBlksToAlloc; /* The number of blocks required for the current packet. */ + TI_UINT32 uExcludedLength; /* The data length not included in the rough blocks calculation */ + TI_UINT32 uAvailableBlks; /* Max blocks that are currently available for this queue. */ + TI_UINT32 uReservedBlks; /* How many blocks are reserved for this queue before this allocation. */ + TI_UINT32 uQueueId = WMEQosTagToACTable[pTxCtrlBlk->tTxDescriptor.tid]; + TTxHwQueueInfo *pQueueInfo = &(pTxHwQueue->aTxHwQueueInfo[uQueueId]); + + + /***********************************************************************/ + /* Calculate packet required HW blocks. */ + /***********************************************************************/ + + /* Divide length by 256 instead of 252 (block size) to save CPU */ + uNumBlksToAlloc = ( pTxCtrlBlk->tTxDescriptor.length + 20 ) >> 8; + + /* The length not yet included in the uNumBlksToAlloc is the sum of: + 1) 4 bytes per block as a result of using 256 instead of 252 block size. + 2) The remainder of the division by 256. + 3) Overhead due to header translation, security and LLC header (subtracting ethernet header). + */ + uExcludedLength = (uNumBlksToAlloc << 2) + ((pTxCtrlBlk->tTxDescriptor.length + 20) & 0xFF) + MAX_HEADER_SIZE - 14; + + /* Add 1 or 2 blocks for the excluded length, according to its size */ + uNumBlksToAlloc += (uExcludedLength > 252) ? 2 : 1; + + /* Add extra blocks needed in case of fragmentation */ + uNumBlksToAlloc += BLKS_HW_ALLOC_SPARE; + + /***********************************************************************/ + /* Check if the required resources are available */ + /***********************************************************************/ + + /* Find max available blocks for this queue (0 could indicate no descriptors). */ + uAvailableBlks = txHwQueue_CheckResources (pTxHwQueue, pQueueInfo); + + /* If we need more blocks than available, return STOP_CURRENT (stop current queue and requeue packet). */ + if (uNumBlksToAlloc > uAvailableBlks) + { + TRACE6(pTxHwQueue->hReport, REPORT_SEVERITY_INFORMATION, ": No resources, Queue=%d, ReqBlks=%d, FreeBlks=%d, UsedBlks=%d, AvailBlks=%d, UsedPkts=%d\n", uQueueId, uNumBlksToAlloc, pTxHwQueue->uNumTotalBlksFree, pQueueInfo->uNumBlksUsed, uAvailableBlks, pTxHwQueue->uNumUsedDescriptors); + pQueueInfo->uNumBlksCausedBusy = uNumBlksToAlloc; + pQueueInfo->bQueueBusy = TI_TRUE; + + return TX_HW_QUE_STATUS_STOP_CURRENT; /**** Exit! (we should stop queue and requeue packet) ****/ + } + + /***********************************************************************/ + /* Allocate required resources */ + /***********************************************************************/ + + /* Update blocks numbers in Tx descriptor */ + pTxCtrlBlk->tTxDescriptor.extraMemBlks = BLKS_HW_ALLOC_SPARE; + pTxCtrlBlk->tTxDescriptor.totalMemBlks = uNumBlksToAlloc; + + /* Update packet allocation info: */ + pTxHwQueue->uNumUsedDescriptors++; /* Update number of packets in FW (for descriptors allocation check). */ + pTxHwQueue->uDrvTxPacketsCntr++; + pQueueInfo->uAllocatedBlksCntr += uNumBlksToAlloc; /* For FW counter coordination. */ + uReservedBlks = pQueueInfo->uNumBlksReserved; + + /* If we are currently using less than the low threshold (i.e. we have some reserved blocks), + blocks allocation should reduce the reserved blocks number as follows: + */ + if (uReservedBlks) + { + + /* If adding the allocated blocks to the used blocks will pass the low-threshold, + only the part up to the low-threshold is subtracted from the reserved blocks. + This is because blocks are reserved for the Queue only up to its low-threshold. + + 0 old used low new used high + |######| | | | + |######| | | | + <------------ allocated -----------> + <----- old reserved ----> + new reserved = 0 (we passed the low threshold) + */ + if (uNumBlksToAlloc > uReservedBlks) + { + pQueueInfo->uNumBlksReserved = 0; + pTxHwQueue->uNumTotalBlksReserved -= uReservedBlks; /* reduce change from total reserved.*/ + } + + + /* Else, if allocating less than reserved, + the allocated blocks are subtracted from the reserved blocks: + + 0 old used new used low high + |######| | | | + |######| | | | + <- allocated -> + <--------- old reserved ----------> + <-- new reserved --> + */ + else + { + pQueueInfo->uNumBlksReserved -= uNumBlksToAlloc; + pTxHwQueue->uNumTotalBlksReserved -= uNumBlksToAlloc; /* reduce change from total reserved.*/ + } + } + + + /* Update total free blocks and Queue used blocks with the allocated blocks number. */ + pTxHwQueue->uNumTotalBlksFree -= uNumBlksToAlloc; + pQueueInfo->uNumBlksUsed += uNumBlksToAlloc; + + TRACE6(pTxHwQueue->hReport, REPORT_SEVERITY_INFORMATION, ": SUCCESS, Queue=%d, Req-blks=%d , Free=%d, Used=%d, Reserved=%d, Accumulated=%d\n", uQueueId, uNumBlksToAlloc, pTxHwQueue->uNumTotalBlksFree, pQueueInfo->uNumBlksUsed, pQueueInfo->uNumBlksReserved, pQueueInfo->uAllocatedBlksCntr); + + /* If no resources for another similar packet, return STOP_NEXT (to stop current queue). */ + /* Note: Current packet transmission is continued */ + if ( (uNumBlksToAlloc << 1) > uAvailableBlks ) + { + TRACE6(pTxHwQueue->hReport, REPORT_SEVERITY_INFORMATION, ": No resources for next pkt, Queue=%d, ReqBlks=%d, FreeBlks=%d, UsedBlks=%d, AvailBlks=%d, UsedPkts=%d\n", uQueueId, uNumBlksToAlloc, pTxHwQueue->uNumTotalBlksFree, pQueueInfo->uNumBlksUsed, uAvailableBlks, pTxHwQueue->uNumUsedDescriptors); + pQueueInfo->uNumBlksCausedBusy = uNumBlksToAlloc; + pQueueInfo->bQueueBusy = TI_TRUE; + return TX_HW_QUE_STATUS_STOP_NEXT; + } + + /* Return SUCCESS (resources are available). */ + return TX_HW_QUE_STATUS_SUCCESS; +} + + +/**************************************************************************** + * txHwQueue_UpdateFreeBlocks() + **************************************************************************** + * DESCRIPTION: + =========== + This function is called per queue after reading the freed blocks counters from the FwStatus. + It updates the queue's blocks status according to the freed blocks. + ****************************************************************************/ +static void txHwQueue_UpdateFreeBlocks (TTxHwQueue *pTxHwQueue, TI_UINT32 uQueueId, TI_UINT32 uFreeBlocks) +{ + TTxHwQueueInfo *pQueueInfo = &(pTxHwQueue->aTxHwQueueInfo[uQueueId]); + TI_UINT32 lowThreshold; /* Minimum blocks that are guaranteed for this Queue. */ + TI_UINT32 newUsedBlks; /* Blocks that are used by this Queue after updating free blocks. */ + TI_UINT32 newReserved; /* How many blocks are reserved to this Queue after freeing. */ + TI_UINT32 numBlksToFree; /* The number of blocks freed in the current queue. */ + + /* If the FW free blocks counter didn't change, exit */ + uFreeBlocks = ENDIAN_HANDLE_LONG(uFreeBlocks); + if (uFreeBlocks == pQueueInfo->uFwFreedBlksCntr) + { + return; + } + + pQueueInfo->uFwFreedBlksCntr = uFreeBlocks; + + /* The uFreeBlocks is the accumulated number of blocks freed by the FW for the uQueueId. + * Subtracting it from the accumulated number of blocks allocated by the driver should + * give the current number of used blocks in this queue. + * Since the difference is always a small positive number, a simple subtraction should work + * also for wrap around. + */ + newUsedBlks = pQueueInfo->uAllocatedBlksCntr - uFreeBlocks; + + numBlksToFree = pQueueInfo->uNumBlksUsed - newUsedBlks; + +#ifdef TI_DBG /* Sanity check: make sure we don't free more than is allocated. */ + if (numBlksToFree > pQueueInfo->uNumBlksUsed) + { + TRACE5(pTxHwQueue->hReport, REPORT_SEVERITY_ERROR, ": Try to free more blks than used: Queue %d, ToFree %d, Used %d, HostAlloc=0x%x, FwFree=0x%x\n", uQueueId, numBlksToFree, pQueueInfo->uNumBlksUsed, pQueueInfo->uAllocatedBlksCntr, uFreeBlocks); + } +#endif + + /* Update total free blocks and Queue used blocks with the freed blocks number. */ + pTxHwQueue->uNumTotalBlksFree += numBlksToFree; + pQueueInfo->uNumBlksUsed = newUsedBlks; + + lowThreshold = pQueueInfo->uNumBlksThresh; + + /* If after freeing the blocks we are using less than the low threshold, + update total reserved blocks number as follows: + (note: if we are above the low threshold after freeing the blocks we still have no reservation.) + */ + if (newUsedBlks < lowThreshold) + { + newReserved = lowThreshold - newUsedBlks; + pQueueInfo->uNumBlksReserved = newReserved; + + + /* If freeing the blocks reduces the used blocks from above to below the low-threshold, + only the part from the low-threshold to the new used number is added to the + reserved blocks (because blocks are reserved for the Queue only up to its low-threshold): + + 0 new used low old used high + |###########|####################|################| | + |###########|####################|################| | + <-------------- freed --------------> + <-- new reserved --> + old reserved = 0 + */ + if (numBlksToFree > newReserved) + pTxHwQueue->uNumTotalBlksReserved += newReserved; /* Add change to total reserved.*/ + + + /* Else, if we were under the low-threshold before freeing these blocks, + all freed blocks are added to the reserved blocks: + + 0 new used old used low high + |################|#################| | | + |################|#################| | | + <---- freed ----> + <- old reserved -> + <---------- new reserved ----------> + */ + else + pTxHwQueue->uNumTotalBlksReserved += numBlksToFree; /* Add change to total reserved.*/ + } + + TRACE5(pTxHwQueue->hReport, REPORT_SEVERITY_INFORMATION, ": Queue %d, ToFree %d, Used %d, HostAlloc=0x%x, FwFree=0x%x\n", uQueueId, numBlksToFree, pQueueInfo->uNumBlksUsed, pQueueInfo->uAllocatedBlksCntr, uFreeBlocks); +} + + +/**************************************************************************** + * txHwQueue_UpdateFreeResources() + **************************************************************************** + * DESCRIPTION: + =========== + Called by FwEvent upon Data interrupt to update freed HW-Queue resources as follows: + 1) For all queues, update blocks and descriptors numbers according to FwStatus information. + 2) For each busy queue, if now available indicate it in the backpressure bitmap. + ****************************************************************************/ +void txHwQueue_UpdateFreeResources (TI_HANDLE hTxHwQueue, FwStatus_t *pFwStatus) +{ + TTxHwQueue *pTxHwQueue = (TTxHwQueue *)hTxHwQueue; + TTxHwQueueInfo *pQueueInfo; + TI_UINT32 uQueueId; + TI_UINT32 uAvailableBlks; /* Max blocks available for current queue. */ + TI_UINT32 uNewNumUsedDescriptors; + TI_UINT32 uBackpressure = 0; + TI_UINT32 *pFreeBlocks = (TI_UINT32 *)pFwStatus->txReleasedBlks; + TI_UINT32 uTempFwCounters; + FwStatCntrs_t *pFwStatusCounters; + + /* + * If TxResults counter changed in FwStatus, update descriptors number according to information + */ + uTempFwCounters = (ENDIAN_HANDLE_LONG(pFwStatus->counters)); + pFwStatusCounters = (FwStatCntrs_t *)&uTempFwCounters; + if (pFwStatusCounters->txResultsCntr != pTxHwQueue->uFwTxResultsCntr) + { + pTxHwQueue->uFwTxResultsCntr = pFwStatusCounters->txResultsCntr; + + /* Calculate new number of used descriptors (the else is for wrap around case) */ + if (pTxHwQueue->uFwTxResultsCntr <= pTxHwQueue->uDrvTxPacketsCntr) + { + uNewNumUsedDescriptors = (TI_UINT32)(pTxHwQueue->uDrvTxPacketsCntr - pTxHwQueue->uFwTxResultsCntr); + } + else + { + uNewNumUsedDescriptors = 0x100 - (TI_UINT32)(pTxHwQueue->uFwTxResultsCntr - pTxHwQueue->uDrvTxPacketsCntr); + } + +#ifdef TI_DBG /* Sanity check: make sure we don't free more descriptors than allocated. */ + if (uNewNumUsedDescriptors >= pTxHwQueue->uNumUsedDescriptors) + { + TRACE2(pTxHwQueue->hReport, REPORT_SEVERITY_ERROR, ": Used descriptors number should decrease: UsedDesc %d, NewUsedDesc %d\n", pTxHwQueue->uNumUsedDescriptors, uNewNumUsedDescriptors); + } +#endif + + /* Update number of packets left in FW (for descriptors allocation check). */ + pTxHwQueue->uNumUsedDescriptors = uNewNumUsedDescriptors; + } + + /* + * For all queues, update blocks numbers according to FwStatus information + */ + for (uQueueId = 0; uQueueId < MAX_NUM_OF_AC; uQueueId++) + { + pQueueInfo = &(pTxHwQueue->aTxHwQueueInfo[uQueueId]); + + /* Update per queue number of used, free and reserved blocks. */ + txHwQueue_UpdateFreeBlocks (pTxHwQueue, uQueueId, pFreeBlocks[uQueueId]); + } + + /* + * For each busy queue, if now available indicate it in the backpressure bitmap + */ + for (uQueueId = 0; uQueueId < MAX_NUM_OF_AC; uQueueId++) + { + pQueueInfo = &(pTxHwQueue->aTxHwQueueInfo[uQueueId]); + + /* If the queue was stopped */ + if (pQueueInfo->bQueueBusy) + { + /* Find max available blocks for this queue (0 could indicate no descriptors). */ + uAvailableBlks = txHwQueue_CheckResources (pTxHwQueue, pQueueInfo); + + /* If the required blocks and a descriptor are available, + set the queue's backpressure bit to indicate NOT-busy! */ + if (pQueueInfo->uNumBlksCausedBusy <= uAvailableBlks) + { + TRACE6(pTxHwQueue->hReport, REPORT_SEVERITY_INFORMATION, ": Queue Available, Queue=%d, ReqBlks=%d, FreeBlks=%d, UsedBlks=%d, AvailBlks=%d, UsedPkts=%d\n", uQueueId, pQueueInfo->uNumBlksCausedBusy, pTxHwQueue->uNumTotalBlksFree, pQueueInfo->uNumBlksUsed, uAvailableBlks, pTxHwQueue->uNumUsedDescriptors); + SET_QUEUE_BACKPRESSURE(&uBackpressure, uQueueId); /* Start queue. */ + pQueueInfo->bQueueBusy = TI_FALSE; + } + } + } + + /* If released queues map is not 0, send it to the upper layers (if CB available) */ + if ((uBackpressure > 0) && (pTxHwQueue->fUpdateBusyMapCb != NULL)) + { + pTxHwQueue->fUpdateBusyMapCb (pTxHwQueue->hUpdateBusyMapHndl, uBackpressure); + } +} + + +/**************************************************************************** + * txHwQueue_CheckResources() + **************************************************************************** + * DESCRIPTION: + ============ + Return the given queue's available blocks. + If no descriptors available, return 0. + ****************************************************************************/ +static TI_UINT32 txHwQueue_CheckResources (TTxHwQueue *pTxHwQueue, TTxHwQueueInfo *pQueueInfo) +{ + /* If descriptors are available: */ + if (pTxHwQueue->uNumUsedDescriptors < NUM_TX_DESCRIPTORS) + { + /* Calculate how many buffers are available for this Queue: the total free buffers minus the buffers + that are reserved for other Queues (all reserved minus this Queue's reserved). */ + return (pTxHwQueue->uNumTotalBlksFree - (pTxHwQueue->uNumTotalBlksReserved - pQueueInfo->uNumBlksReserved)); + } + + /* If no descriptors are available, return 0 (can't transmit anything). */ + else + { + return 0; + } +} + + +/**************************************************************************** + * txHwQueue_RegisterCb() + **************************************************************************** + * DESCRIPTION: Register the upper driver TxHwQueue callback functions. + ****************************************************************************/ +void txHwQueue_RegisterCb (TI_HANDLE hTxHwQueue, TI_UINT32 uCallBackId, void *fCbFunc, TI_HANDLE hCbHndl) +{ + TTxHwQueue *pTxHwQueue = (TTxHwQueue *)hTxHwQueue; + + switch (uCallBackId) + { + case TWD_INT_UPDATE_BUSY_MAP: + pTxHwQueue->fUpdateBusyMapCb = (tUpdateBusyMapCb)fCbFunc; + pTxHwQueue->hUpdateBusyMapHndl = hCbHndl; + break; + + default: + TRACE1(pTxHwQueue->hReport, REPORT_SEVERITY_ERROR, " - Illegal parameter = %d\n", uCallBackId); + return; + } +} + + +/**************************************************************************** + * txHwQueue_PrintInfo() + **************************************************************************** + * DESCRIPTION: Print the Hw Queue module current information + ****************************************************************************/ +#ifdef TI_DBG +void txHwQueue_PrintInfo (TI_HANDLE hTxHwQueue) +{ +#ifdef REPORT_LOG + TTxHwQueue *pTxHwQueue = (TTxHwQueue *)hTxHwQueue; + TI_INT32 TxQid; + + /* Print the Tx-HW-Queue information: */ + WLAN_OS_REPORT(("Hw-Queues Information:\n")); + WLAN_OS_REPORT(("======================\n")); + WLAN_OS_REPORT(("Total Blocks: %d\n", pTxHwQueue->uNumTotalBlks)); + WLAN_OS_REPORT(("Total Free Blocks: %d\n", pTxHwQueue->uNumTotalBlksFree)); + WLAN_OS_REPORT(("Total Reserved Blocks: %d\n", pTxHwQueue->uNumTotalBlksReserved)); + WLAN_OS_REPORT(("Total Used Descriptors: %d\n", pTxHwQueue->uNumUsedDescriptors)); + WLAN_OS_REPORT(("FwTxResultsCntr: %d\n", pTxHwQueue->uFwTxResultsCntr)); + WLAN_OS_REPORT(("DrvTxPacketsCntr: %d\n", pTxHwQueue->uDrvTxPacketsCntr)); + + for(TxQid = 0; TxQid < MAX_NUM_OF_AC; TxQid++) + { + WLAN_OS_REPORT(("Q=%d: Used=%d, Reserve=%d, Threshold=%d\n", + TxQid, + pTxHwQueue->aTxHwQueueInfo[TxQid].uNumBlksUsed, + pTxHwQueue->aTxHwQueueInfo[TxQid].uNumBlksReserved, + pTxHwQueue->aTxHwQueueInfo[TxQid].uNumBlksThresh)); + } + + WLAN_OS_REPORT(("\n")); + + for(TxQid = 0; TxQid < MAX_NUM_OF_AC; TxQid++) + { + WLAN_OS_REPORT(("Queue=%d: HostAllocCount=0x%x, FwFreeCount=0x%x, BusyBlks=%d, Busy=%d\n", + TxQid, + pTxHwQueue->aTxHwQueueInfo[TxQid].uAllocatedBlksCntr, + pTxHwQueue->aTxHwQueueInfo[TxQid].uFwFreedBlksCntr, + pTxHwQueue->aTxHwQueueInfo[TxQid].uNumBlksCausedBusy, + pTxHwQueue->aTxHwQueueInfo[TxQid].bQueueBusy)); + } +#endif +} + +#endif /* TI_DBG */ + |