| /* |
| * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. |
| * |
| * Previously licensed under the ISC license by Qualcomm Atheros, Inc. |
| * |
| * |
| * Permission to use, copy, modify, and/or distribute this software for |
| * any purpose with or without fee is hereby granted, provided that the |
| * above copyright notice and this permission notice appear in all |
| * copies. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL |
| * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED |
| * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE |
| * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL |
| * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR |
| * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER |
| * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR |
| * PERFORMANCE OF THIS SOFTWARE. |
| */ |
| /* |
| * Copyright (c) 2012, The Linux Foundation. All rights reserved. |
| * |
| * Previously licensed under the ISC license by Qualcomm Atheros, Inc. |
| * |
| * |
| * Permission to use, copy, modify, and/or distribute this software for |
| * any purpose with or without fee is hereby granted, provided that the |
| * above copyright notice and this permission notice appear in all |
| * copies. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL |
| * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED |
| * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE |
| * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL |
| * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR |
| * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER |
| * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR |
| * PERFORMANCE OF THIS SOFTWARE. |
| */ |
| |
| /**========================================================================= |
| * |
| * \file wlan_qct_wdi_ds.c |
| * |
| * \brief define Dataservice API |
| * |
| * WLAN Device Abstraction layer External API for Dataservice |
| * DESCRIPTION |
| * This file contains the external API implemntation exposed by the |
| * wlan device abstarction layer module. |
| * |
| * Copyright (c) 2008 QUALCOMM Incorporated. All Rights Reserved. |
| * Qualcomm Confidential and Proprietary |
| */ |
| |
| |
| #include "wlan_qct_wdi.h" |
| #include "wlan_qct_wdi_i.h" |
| #include "wlan_qct_wdi_ds.h" |
| #include "wlan_qct_wdi_ds_i.h" |
| #include "wlan_qct_wdi_dts.h" |
| #include "wlan_qct_wdi_dp.h" |
| #include "wlan_qct_wdi_sta.h" |
| |
| |
| |
| |
| /* DAL registration function. |
| * Parameters: |
| * pContext:Cookie that should be passed back to the caller along |
| * with the callback. |
| * pfnTxCompleteCallback:Callback function that is to be invoked to return |
| * packets which have been transmitted. |
| * pfnRxPacketCallback:Callback function that is to be invoked to deliver |
| * packets which have been received |
| * pfnTxFlowControlCallback:Callback function that is to be invoked to |
| * indicate/clear congestion. |
| * |
| * Return Value: SUCCESS Completed successfully. |
| * FAILURE_XXX Request was rejected due XXX Reason. |
| * |
| */ |
| WDI_Status WDI_DS_Register( void *pContext, |
| WDI_DS_TxCompleteCallback pfnTxCompleteCallback, |
| WDI_DS_RxPacketCallback pfnRxPacketCallback, |
| WDI_DS_TxFlowControlCallback pfnTxFlowControlCallback, |
| void *pCallbackContext) |
| { |
| WDI_DS_ClientDataType *pClientData; |
| wpt_uint8 bssLoop; |
| |
| // Do Sanity checks |
| if (NULL == pContext || |
| NULL == pCallbackContext || |
| NULL == pfnTxCompleteCallback || |
| NULL == pfnRxPacketCallback || |
| NULL == pfnTxFlowControlCallback) { |
| return WDI_STATUS_E_FAILURE; |
| } |
| |
| pClientData = (WDI_DS_ClientDataType *)WDI_DS_GetDatapathContext(pContext); |
| if (NULL == pClientData) |
| { |
| return WDI_STATUS_MEM_FAILURE; |
| } |
| |
| // Store callbacks in client structure |
| pClientData->pcontext = pContext; |
| pClientData->receiveFrameCB = pfnRxPacketCallback; |
| pClientData->txCompleteCB = pfnTxCompleteCallback; |
| pClientData->txResourceCB = pfnTxFlowControlCallback; |
| pClientData->pCallbackContext = pCallbackContext; |
| |
| for(bssLoop = 0; bssLoop < WDI_DS_MAX_SUPPORTED_BSS; bssLoop++) |
| { |
| pClientData->staIdxPerBssIdxTable[bssLoop].isUsed = 0; |
| pClientData->staIdxPerBssIdxTable[bssLoop].bssIdx = WDI_DS_INDEX_INVALID; |
| pClientData->staIdxPerBssIdxTable[bssLoop].staIdx = WDI_DS_INDEX_INVALID; |
| } |
| return WDI_STATUS_SUCCESS; |
| } |
| |
| |
| |
| /* DAL Transmit function. |
| * Parameters: |
| * pContext:Cookie that should be passed back to the caller along with the callback. |
| * pFrame:Refernce to PAL frame. |
| * more: Does the invokee have more than one packet pending? |
| * Return Value: SUCCESS Completed successfully. |
| * FAILURE_XXX Request was rejected due XXX Reason. |
| * |
| */ |
| |
| |
| WDI_Status WDI_DS_TxPacket(void *pContext, |
| wpt_packet *pFrame, |
| wpt_boolean more) |
| { |
| WDI_DS_ClientDataType *pClientData; |
| wpt_uint8 ucSwFrameTXXlation; |
| wpt_uint8 ucUP; |
| wpt_uint8 ucTypeSubtype; |
| wpt_uint8 alignment; |
| wpt_uint8 ucTxFlag; |
| wpt_uint8* pSTAMACAddress; |
| wpt_uint8* pAddr2MACAddress; |
| WDI_DS_TxMetaInfoType *pTxMetadata; |
| void *physBDHeader, *pvBDHeader; |
| wpt_uint8 ucType; |
| WDI_DS_BdMemPoolType *pMemPool; |
| wpt_uint8 ucBdPoolType; |
| wpt_uint8 staId; |
| |
| // Do Sanity checks |
| if (NULL == pContext) |
| { |
| return WDI_STATUS_E_FAILURE; |
| } |
| |
| pClientData = (WDI_DS_ClientDataType *) WDI_DS_GetDatapathContext(pContext); |
| if (NULL == pClientData || pClientData->suspend) |
| { |
| return WDI_STATUS_E_FAILURE; |
| } |
| |
| // extract metadata from PAL packet |
| pTxMetadata = WDI_DS_ExtractTxMetaData(pFrame); |
| ucSwFrameTXXlation = pTxMetadata->fdisableFrmXlt; |
| ucTypeSubtype = pTxMetadata->typeSubtype; |
| ucUP = pTxMetadata->fUP; |
| ucTxFlag = pTxMetadata->txFlags; |
| pSTAMACAddress = &(pTxMetadata->fSTAMACAddress[0]); |
| pAddr2MACAddress = &(pTxMetadata->addr2MACAddress[0]); |
| |
| /*------------------------------------------------------------------------ |
| Get type and subtype of the frame first |
| ------------------------------------------------------------------------*/ |
| ucType = (ucTypeSubtype & WDI_FRAME_TYPE_MASK) >> WDI_FRAME_TYPE_OFFSET; |
| switch(ucType) |
| { |
| case WDI_MAC_DATA_FRAME: |
| if(!pTxMetadata->isEapol) |
| { |
| pMemPool = &(pClientData->dataMemPool); |
| ucBdPoolType = WDI_DATA_POOL_ID; |
| break; |
| } |
| // intentional fall-through to handle eapol packet as mgmt |
| case WDI_MAC_MGMT_FRAME: |
| pMemPool = &(pClientData->mgmtMemPool); |
| ucBdPoolType = WDI_MGMT_POOL_ID; |
| break; |
| default: |
| return WDI_STATUS_E_FAILURE; |
| } |
| |
| // Allocate BD header from pool |
| pvBDHeader = WDI_DS_MemPoolAlloc(pMemPool, &physBDHeader, ucBdPoolType); |
| if(NULL == pvBDHeader) |
| return WDI_STATUS_E_FAILURE; |
| |
| WDI_SetBDPointers(pFrame, pvBDHeader, physBDHeader); |
| |
| alignment = 0; |
| WDI_DS_PrepareBDHeader(pFrame, ucSwFrameTXXlation, alignment); |
| |
| if(WDI_STATUS_SUCCESS != |
| WDI_FillTxBd( pContext, ucTypeSubtype, pSTAMACAddress, pAddr2MACAddress, |
| &ucUP, 1, pvBDHeader, ucTxFlag /* No ACK */, 0, &staId)){ |
| WDI_DS_MemPoolFree(pMemPool, pvBDHeader, physBDHeader); |
| return WDI_STATUS_E_FAILURE; |
| } |
| // Send packet to transport layer. |
| if(eWLAN_PAL_STATUS_SUCCESS !=WDTS_TxPacket(pContext, pFrame)){ |
| WDI_DS_MemPoolFree(pMemPool, pvBDHeader, physBDHeader); |
| return WDI_STATUS_E_FAILURE; |
| } |
| |
| /* resource count only for data packet */ |
| // EAPOL packet doesn't use data mem pool if being treated as higher priority |
| if(WDI_MAC_DATA_FRAME == ucType && (!pTxMetadata->isEapol)) |
| { |
| WDI_DS_MemPoolIncreaseReserveCount(pMemPool, staId); |
| } |
| return WDI_STATUS_SUCCESS; |
| } |
| |
| |
| /* DAL Transmit Complete function. |
| * Parameters: |
| * pContext:Cookie that should be passed back to the caller along with the callback. |
| * ucTxResReq:TX resource number required by TL |
| * Return Value: SUCCESS Completed successfully. |
| * FAILURE_XXX Request was rejected due XXX Reason. |
| * |
| */ |
| |
| |
| WDI_Status WDI_DS_TxComplete(void *pContext, wpt_uint32 ucTxResReq) |
| { |
| // Do Sanity checks |
| if(NULL == pContext) |
| return WDI_STATUS_E_FAILURE; |
| |
| // Send notification to transport layer. |
| if(eWLAN_PAL_STATUS_SUCCESS !=WDTS_CompleteTx(pContext, ucTxResReq)) |
| { |
| return WDI_STATUS_E_FAILURE; |
| } |
| |
| return WDI_STATUS_SUCCESS; |
| } |
| |
| /* DAL Suspend Transmit function. |
| * Parameters: |
| * pContext:Cookie that should be passed back to the caller along with the callback. |
| * Return Value: SUCCESS Completed successfully. |
| * FAILURE_XXX Request was rejected due XXX Reason. |
| * |
| */ |
| |
| |
| WDI_Status WDI_DS_TxSuspend(void *pContext) |
| { |
| WDI_DS_ClientDataType *pClientData = |
| (WDI_DS_ClientDataType *) WDI_DS_GetDatapathContext(pContext); |
| pClientData->suspend = 1; |
| |
| return WDI_STATUS_SUCCESS; |
| |
| } |
| |
| |
| /* DAL Resume Transmit function. |
| * Parameters: |
| * pContext:Cookie that should be passed back to the caller along with the callback. |
| * Return Value: SUCCESS Completed successfully. |
| * FAILURE_XXX Request was rejected due XXX Reason. |
| * |
| */ |
| |
| |
| WDI_Status WDI_DS_TxResume(void *pContext) |
| { |
| WDI_DS_ClientDataType *pClientData = |
| (WDI_DS_ClientDataType *) WDI_DS_GetDatapathContext(pContext); |
| |
| pClientData->suspend = 0; |
| |
| return WDI_STATUS_SUCCESS; |
| } |
| |
| /* DAL Get Available Resource Count. |
| * This is the number of free descririptor in DXE |
| * Parameters: |
| * pContext:Cookie that should be passed back to the caller along with the callback. |
| * wdiResPool: - identifier of resource pool |
| * Return Value: number of resources available |
| * This is the number of free descririptor in DXE |
| * |
| */ |
| |
| wpt_uint32 WDI_GetAvailableResCount(void *pContext,WDI_ResPoolType wdiResPool) |
| { |
| WDI_DS_ClientDataType *pClientData = |
| (WDI_DS_ClientDataType *) WDI_DS_GetDatapathContext(pContext); |
| |
| switch(wdiResPool) |
| { |
| case WDI_MGMT_POOL_ID: |
| return (WDI_DS_HI_PRI_RES_NUM - 2*WDI_DS_GetAvailableResCount(&pClientData->mgmtMemPool)); |
| case WDI_DATA_POOL_ID: |
| return WDTS_GetFreeTxDataResNumber(pContext); |
| default: |
| return 0; |
| } |
| } |
| |
| /* DAL Get resrved Resource Count per STA. |
| * Parameters: |
| * pContext:Cookie that should be passed back to the caller along with the callback. |
| * wdiResPool: - identifier of resource pool |
| * staId: STA ID |
| * Return Value: number of resources reserved per STA |
| * |
| */ |
| wpt_uint32 WDI_DS_GetReservedResCountPerSTA(void *pContext,WDI_ResPoolType wdiResPool, wpt_uint8 staId) |
| { |
| WDI_DS_ClientDataType *pClientData = |
| (WDI_DS_ClientDataType *) WDI_DS_GetDatapathContext(pContext); |
| switch(wdiResPool) |
| { |
| case WDI_MGMT_POOL_ID: |
| return WDI_DS_MemPoolGetRsvdResCountPerSTA(&pClientData->mgmtMemPool, staId); |
| case WDI_DATA_POOL_ID: |
| return WDI_DS_MemPoolGetRsvdResCountPerSTA(&pClientData->dataMemPool, staId); |
| default: |
| return 0; |
| } |
| } |
| |
| /* DAL STA info add into memPool. |
| * Parameters: |
| * pContext:Cookie that should be passed back to the caller along with the callback. |
| * staId: STA ID |
| * Return Value: number of resources reserved per STA |
| * |
| */ |
| WDI_Status WDI_DS_AddSTAMemPool(void *pContext, wpt_uint8 staIndex) |
| { |
| WDI_Status status = WDI_STATUS_SUCCESS; |
| WDI_DS_ClientDataType *pClientData = |
| (WDI_DS_ClientDataType *) WDI_DS_GetDatapathContext(pContext); |
| |
| status = WDI_DS_MemPoolAddSTA(&pClientData->mgmtMemPool, staIndex); |
| if(WDI_STATUS_SUCCESS != status) |
| { |
| /* Add STA into MGMT memPool Fail */ |
| return status; |
| } |
| |
| status = WDI_DS_MemPoolAddSTA(&pClientData->dataMemPool, staIndex); |
| if(WDI_STATUS_SUCCESS != status) |
| { |
| /* Add STA into DATA memPool Fail */ |
| return status; |
| } |
| |
| return WDI_STATUS_SUCCESS; |
| } |
| |
| /* DAL STA info del from memPool. |
| * Parameters: |
| * pContext:Cookie that should be passed back to the caller along with the callback. |
| * staId: STA ID |
| * Return Value: number of resources reserved per STA |
| * |
| */ |
| WDI_Status WDI_DS_DelSTAMemPool(void *pContext, wpt_uint8 staIndex) |
| { |
| WDI_Status status = WDI_STATUS_SUCCESS; |
| WDI_DS_ClientDataType *pClientData = |
| (WDI_DS_ClientDataType *) WDI_DS_GetDatapathContext(pContext); |
| |
| status = WDI_DS_MemPoolDelSTA(&pClientData->mgmtMemPool, staIndex); |
| if(WDI_STATUS_SUCCESS != status) |
| { |
| /* Del STA from MGMT memPool Fail */ |
| return status; |
| } |
| status = WDI_DS_MemPoolDelSTA(&pClientData->dataMemPool, staIndex); |
| if(WDI_STATUS_SUCCESS != status) |
| { |
| /* Del STA from DATA memPool Fail */ |
| return status; |
| } |
| return WDI_STATUS_SUCCESS; |
| } |
| |
| /* DAL Set STA index associated with BSS index. |
| * Parameters: |
| * pContext:Cookie that should be passed back to the caller along with the callback. |
| * bssIdx: BSS index |
| * staId: STA index associated with BSS index |
| * Return Status: Found empty slot |
| * |
| */ |
| WDI_Status WDI_DS_SetStaIdxPerBssIdx(void *pContext, wpt_uint8 bssIdx, wpt_uint8 staIdx) |
| { |
| WDI_DS_ClientDataType *pClientData; |
| wpt_uint8 bssLoop; |
| |
| pClientData = (WDI_DS_ClientDataType *)WDI_DS_GetDatapathContext(pContext); |
| for (bssLoop = 0; bssLoop < WDI_DS_MAX_SUPPORTED_BSS; bssLoop++) |
| { |
| if ((pClientData->staIdxPerBssIdxTable[bssLoop].isUsed) && |
| (bssIdx == pClientData->staIdxPerBssIdxTable[bssLoop].bssIdx) && |
| (staIdx == pClientData->staIdxPerBssIdxTable[bssLoop].staIdx)) |
| { |
| return WDI_STATUS_SUCCESS; |
| } |
| |
| if (0 == pClientData->staIdxPerBssIdxTable[bssLoop].isUsed) |
| { |
| pClientData->staIdxPerBssIdxTable[bssLoop].bssIdx = bssIdx; |
| pClientData->staIdxPerBssIdxTable[bssLoop].staIdx = staIdx; |
| pClientData->staIdxPerBssIdxTable[bssLoop].isUsed = 1; |
| return WDI_STATUS_SUCCESS; |
| } |
| } |
| |
| /* Could not find empty slot */ |
| return WDI_STATUS_E_FAILURE; |
| } |
| |
| /* DAL Get STA index associated with BSS index. |
| * Parameters: |
| * pContext:Cookie that should be passed back to the caller along with the callback. |
| * bssIdx: BSS index |
| * staId: STA index associated with BSS index |
| * Return Status: Found empty slot |
| * |
| */ |
| WDI_Status WDI_DS_GetStaIdxFromBssIdx(void *pContext, wpt_uint8 bssIdx, wpt_uint8 *staIdx) |
| { |
| WDI_DS_ClientDataType *pClientData; |
| wpt_uint8 bssLoop; |
| |
| pClientData = (WDI_DS_ClientDataType *)WDI_DS_GetDatapathContext(pContext); |
| for(bssLoop = 0; bssLoop < WDI_DS_MAX_SUPPORTED_BSS; bssLoop++) |
| { |
| if(bssIdx == pClientData->staIdxPerBssIdxTable[bssLoop].bssIdx) |
| { |
| /* Found BSS index from slot */ |
| *staIdx = pClientData->staIdxPerBssIdxTable[bssLoop].staIdx; |
| return WDI_STATUS_SUCCESS; |
| } |
| } |
| |
| /* Could not find associated STA index with BSS index */ |
| return WDI_STATUS_E_FAILURE; |
| } |
| |
| /* DAL Clear STA index associated with BSS index. |
| * Parameters: |
| * pContext:Cookie that should be passed back to the caller along with the callback. |
| * bssIdx: BSS index |
| * staId: STA index associated with BSS index |
| * Return Status: Found empty slot |
| * |
| */ |
| WDI_Status WDI_DS_ClearStaIdxPerBssIdx(void *pContext, wpt_uint8 bssIdx, wpt_uint8 staIdx) |
| { |
| WDI_DS_ClientDataType *pClientData; |
| wpt_uint8 bssLoop; |
| |
| pClientData = (WDI_DS_ClientDataType *)WDI_DS_GetDatapathContext(pContext); |
| for(bssLoop = 0; bssLoop < WDI_DS_MAX_SUPPORTED_BSS; bssLoop++) |
| { |
| if((bssIdx == pClientData->staIdxPerBssIdxTable[bssLoop].bssIdx) && |
| (staIdx == pClientData->staIdxPerBssIdxTable[bssLoop].staIdx)) |
| { |
| pClientData->staIdxPerBssIdxTable[bssLoop].bssIdx = WDI_DS_INDEX_INVALID; |
| pClientData->staIdxPerBssIdxTable[bssLoop].staIdx = WDI_DS_INDEX_INVALID; |
| pClientData->staIdxPerBssIdxTable[bssLoop].isUsed = 0; |
| return WDI_STATUS_SUCCESS; |
| } |
| } |
| |
| /* Could not find associated STA index with BSS index */ |
| return WDI_STATUS_E_FAILURE; |
| } |