blob: 2a2ad1f08fbbf7e220926ced3b032a89f476660d [file] [log] [blame]
/*
* 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.
*/
/*
* Airgo Networks, Inc proprietary. All rights reserved.
* This file pmmApi.cc contains functions related to the API exposed
* by power management module
*
* Author: Sandesh Goel
* Date: 02/25/02
* History:-
* Date Modified by Modification Information
* --------------------------------------------------------------------
*
*/
#include "palTypes.h"
#include "wniCfgSta.h"
#include "sirCommon.h"
#include "aniGlobal.h"
#include "schApi.h"
#include "limApi.h"
#include "limSendMessages.h"
#include "cfgApi.h"
#include "limSessionUtils.h"
#include "limFT.h"
#include "pmmApi.h"
#include "pmmDebug.h"
#include "sirApi.h"
#include "wmmApsd.h"
#include "limSendSmeRspMessages.h"
#include "limTimerUtils.h"
#include "limTrace.h"
#include "limUtils.h"
#include "VossWrapper.h"
#ifdef INTEGRATION_READY
#include "vos_status.h" //VOS_STATUS
#include "vos_mq.h" //vos_mq_post_message()
#endif
#include "wlan_qct_wda.h"
// --------------------------------------------------------------------
/**
* pmmInitialize
*
* FUNCTION:
* Initialize PMM module
*
* LOGIC:
*
* ASSUMPTIONS:
*
* NOTE:
*
* @param mode
* @param rate
* @return None
*/
tSirRetStatus
pmmInitialize(tpAniSirGlobal pMac)
{
#if (WNI_POLARIS_FW_PRODUCT == AP)
pMac->pmm.gPmmNextSta = 0;
pMac->pmm.gPmmNumSta = 0;
#endif
pmmResetStats(pMac);
pMac->pmm.gPmmBeaconInterval = WNI_CFG_BEACON_INTERVAL_STADEF;
pMac->pmm.gPmmState = ePMM_STATE_READY;
#ifdef ANI_PRODUCT_TYPE_AP
palZeroMemory(pMac->hHdd,
pMac->pmm.gPmmTim.pTim, sizeof(tANI_U8)*pMac->lim.maxStation);
palZeroMemory(pMac->hHdd,
pMac->pmm.gPmmTim.pStaInfo, sizeof(*pMac->pmm.gPmmTim.pStaInfo)*pMac->lim.maxStation);
palZeroMemory(pMac->hHdd,
pMac->pmm.gpPmmStaState, sizeof(tPmmStaState)*pMac->lim.maxStation);
palZeroMemory(pMac->hHdd,
pMac->pmm.gpPmmPSState, sizeof(tANI_U8)*pMac->lim.maxStation);
#endif
pMac->pmm.inMissedBeaconScenario = FALSE;
return eSIR_SUCCESS;
}
// --------------------------------------------------------------------
/**
* pmmResetStats
*
* FUNCTION:
* Resets the statistics
*
* LOGIC:
*
* ASSUMPTIONS:
*
* NOTE:
*
* @param pMac
*
* @return None
*/
void
pmmResetStats(void *pvMac)
{
tpAniSirGlobal pMac = (tpAniSirGlobal)pvMac;
pMac->pmm.BmpsmaxSleepTime = 0;
pMac->pmm.BmpsavgSleepTime = 0;
pMac->pmm.BmpsminSleepTime = 0;
pMac->pmm.BmpscntSleep = 0;
pMac->pmm.BmpsmaxTimeAwake = 0;
pMac->pmm.BmpsavgTimeAwake = 0;
pMac->pmm.BmpsminTimeAwake = 0;
pMac->pmm.BmpscntAwake = 0;
pMac->pmm.BmpsWakeupTimeStamp = 0;
pMac->pmm.BmpsSleepTimeStamp = 0;
pMac->pmm.BmpsHalReqFailCnt = 0;
pMac->pmm.BmpsInitFailCnt = 0;
pMac->pmm.BmpsInitFailCnt= 0;
pMac->pmm.BmpsInvStateCnt= 0;
pMac->pmm.BmpsPktDrpInSleepMode= 0;
pMac->pmm.BmpsReqInInvalidRoleCnt= 0;
pMac->pmm.BmpsSleeReqFailCnt= 0;
pMac->pmm.BmpsWakeupIndCnt= 0;
pMac->pmm.ImpsWakeupTimeStamp = 0;
pMac->pmm.ImpsSleepTimeStamp = 0;
pMac->pmm.ImpsMaxTimeAwake = 0;
pMac->pmm.ImpsMinTimeAwake = 0;
pMac->pmm.ImpsAvgTimeAwake = 0;
pMac->pmm.ImpsCntAwake = 0;
pMac->pmm.ImpsCntSleep = 0;
pMac->pmm.ImpsMaxSleepTime = 0;
pMac->pmm.ImpsMinSleepTime = 0;
pMac->pmm.ImpsAvgSleepTime = 0;
pMac->pmm.ImpsSleepErrCnt = 0;
pMac->pmm.ImpsWakeupErrCnt = 0;
pMac->pmm.ImpsLastErr = 0;
pMac->pmm.ImpsInvalidStateCnt = 0;
return;
}
// --------------------------------------------------------------------
/**
* pmmInitBmpsResponseHandler
*
* FUNCTION:
* This function processes the SIR_HAL_ENTER_BMPS_RSP from HAL.
* If the response is successful, it puts PMM in ePMM_STATE_BMP_SLEEP state
* and sends back success response to PMC.
*
* LOGIC:
*
* ASSUMPTIONS:
*
* NOTE:
*
* @param
* @return None
*/
void pmmInitBmpsResponseHandler(tpAniSirGlobal pMac, tpSirMsgQ limMsg )
{
tPmmState nextState = pMac->pmm.gPmmState;
tSirResultCodes retStatus = eSIR_SME_SUCCESS;
tpPESession psessionEntry;
tpEnterBmpsParams pEnterBmpsParams;
/* we need to process all the deferred messages enqueued since
* the initiating the SIR_HAL_ENTER_BMPS_REQ.
*/
SET_LIM_PROCESS_DEFD_MESGS(pMac, true);
if(pMac->pmm.gPmmState != ePMM_STATE_BMPS_WT_INIT_RSP)
{
PELOGE(pmmLog(pMac, LOGE,
FL("pmmBmps: Received 'InitPwrSaveRsp' while in incorrect state: %d\n"),
pMac->pmm.gPmmState);)
retStatus = eSIR_SME_INVALID_PMM_STATE;
pmmBmpsUpdateInvalidStateCnt(pMac);
goto failure;
}
if (NULL == limMsg->bodyptr)
{
PELOGE(pmmLog(pMac, LOGE, FL("pmmBmps: Received SIR_HAL_ENTER_BMPS_RSP with NULL "));)
goto failure;
}
pEnterBmpsParams = (tpEnterBmpsParams)(limMsg->bodyptr);
//if response is success, then set PMM to BMPS_SLEEP state and send response back to PMC.
//If response is failure, then send the response back to PMC and reset its state.
if(pEnterBmpsParams->status == eHAL_STATUS_SUCCESS)
{
PELOG2(pmmLog(pMac, LOG2,
FL("pmmBmps: Received successful response from HAL to enter BMPS_POWER_SAVE \n"));)
pMac->pmm.gPmmState = ePMM_STATE_BMPS_SLEEP;
// Update sleep statistics
pmmUpdatePwrSaveStats(pMac);
// Disable background scan mode
pMac->sys.gSysEnableScanMode = false;
if (pMac->lim.gLimTimersCreated)
{
/* Disable heartbeat timer as well */
if(pMac->lim.limTimers.gLimHeartBeatTimer.pMac)
{
MTRACE(macTrace(pMac, TRACE_CODE_TIMER_DEACTIVATE, NO_SESSION, eLIM_HEART_BEAT_TIMER));
tx_timer_deactivate(&pMac->lim.limTimers.gLimHeartBeatTimer);
}
}
limSendSmeRsp(pMac, eWNI_PMC_ENTER_BMPS_RSP, retStatus, 0, 0);
}
else
{
//if init req failed, then go back to WAKEUP state.
PELOGE(pmmLog(pMac, LOGE,
FL("pmmBmps: BMPS_INIT_PWR_SAVE_REQ failed, informing SME\n"));)
pmmBmpsUpdateInitFailureCnt(pMac);
nextState = ePMM_STATE_BMPS_WAKEUP;
retStatus = eSIR_SME_BMPS_REQ_FAILED;
goto failure;
}
return;
failure:
psessionEntry = peGetValidPowerSaveSession(pMac);
if(psessionEntry != NULL)
{
if (pMac->lim.gLimTimersCreated && pMac->lim.limTimers.gLimHeartBeatTimer.pMac)
{
if(VOS_TRUE != tx_timer_running(&pMac->lim.limTimers.gLimHeartBeatTimer))
{
PELOGE(pmmLog(pMac, LOGE, FL("Unexpected heartbeat timer not running"));)
limReactivateHeartBeatTimer(pMac, psessionEntry);
}
}
}
//Generate an error response back to PMC
pMac->pmm.gPmmState = nextState;
pmmBmpsUpdateSleepReqFailureCnt(pMac);
limSendSmeRsp(pMac, eWNI_PMC_ENTER_BMPS_RSP, retStatus, 0, 0);
return;
}
// --------------------------------------------------------------------
/**
* pmmExitBmpsRequestHandler
*
* FUNCTION:
* This function will send the wakeup message to HAL
*
* LOGIC:
*
* ASSUMPTIONS:
*
* NOTE:
*
* @param pMac pointer to Global Mac structure.
* @return None
*/
void pmmExitBmpsRequestHandler(tpAniSirGlobal pMac, tpExitBmpsInfo pExitBmpsInfo)
{
tSirResultCodes respStatus = eSIR_SME_SUCCESS;
tPmmState origState = pMac->pmm.gPmmState;
#ifdef FEATURE_WLAN_DIAG_SUPPORT
limDiagEventReport(pMac, WLAN_PE_DIAG_EXIT_BMPS_REQ_EVENT, peGetValidPowerSaveSession(pMac), 0, (tANI_U16)pExitBmpsInfo->exitBmpsReason);
#endif //FEATURE_WLAN_DIAG_SUPPORT
if (NULL == pExitBmpsInfo)
{
respStatus = eSIR_SME_BMPS_REQ_REJECT;
PELOGW(pmmLog(pMac, LOGW, FL("pmmBmps: Rcvd EXIT_BMPS with NULL body\n"));)
goto failure;
}
/* PMC is not aware of Background scan, which is done in
* BMPS mode while Nth Beacon is delivered. Essentially, PMC
* can request the device to get out of power-save while
* background scanning is happening. since, the device is already
* out of powersave, just inform that device is out of powersave
*/
if(limIsSystemInScanState(pMac))
{
PELOGW(pmmLog(pMac, LOGW,
FL("pmmBmps: Device is already awake and scanning, returning success to PMC \n"));)
limSendSmeRsp(pMac, eWNI_PMC_EXIT_BMPS_RSP, respStatus, 0, 0);
return;
}
/* send wakeup request, only when in sleep state */
PELOGW(pmmLog(pMac, LOGW, FL("pmmBmps: Sending eWNI_PMC_EXIT_BMPS_REQ to HAL\n"));)
if (pMac->pmm.gPmmState == ePMM_STATE_BMPS_SLEEP)
{
/* Store the reason code for exiting BMPS. This value will be
* checked when PMM receives SIR_HAL_EXIT_BMPS_RSP from HAL
*/
pMac->pmm.gPmmExitBmpsReasonCode = pExitBmpsInfo->exitBmpsReason;
palFreeMemory( pMac->hHdd, (tANI_U8 *) pExitBmpsInfo);
PELOGW(pmmLog(pMac, LOGW,
FL("pmmBmps: Rcvd EXIT_BMPS with reason code%d \n"), pMac->pmm.gPmmExitBmpsReasonCode);)
// Set PMM to BMPS_WT_WAKEUP_RSP state
pMac->pmm.gPmmState = ePMM_STATE_BMPS_WT_WAKEUP_RSP;
if(pmmSendChangePowerSaveMsg(pMac) != eSIR_SUCCESS)
{
/* Wakeup request failed */
respStatus = eSIR_SME_BMPS_REQ_REJECT;
pmmBmpsUpdateHalReqFailureCnt(pMac);
goto failure;
}
else
{
PELOG1(pmmLog(pMac, LOG1,
FL("pmmBmps: eWNI_PMC_EXIT_BMPS_REQ was successfully sent to HAL\n"));)
}
}
else
{
PELOGE(pmmLog(pMac, LOGE,
FL("pmmBmps: eWNI_PMC_EXIT_BMPS_REQ received in invalid state: %d\n"),
pMac->pmm.gPmmState );)
respStatus = eSIR_SME_INVALID_PMM_STATE;
pmmBmpsUpdateInvalidStateCnt(pMac);
palFreeMemory( pMac->hHdd, (tANI_U8 *) pExitBmpsInfo);
goto failure;
}
return;
failure:
pMac->pmm.gPmmState = origState;
pmmBmpsUpdateWakeupReqFailureCnt(pMac);
limSendSmeRsp(pMac, eWNI_PMC_EXIT_BMPS_RSP, respStatus, 0, 0);
}
// --------------------------------------------------------------------
/**
* pmmInitBmpsPwrSave
*
* FUNCTION:
* This function process the eWNI_PMC_ENTER_PMC_REQ from PMC.
* It checks for certain conditions before it puts PMM into
* BMPS power save state: ePMM_STATE_BMPS_WT_INIT_RSP
* It also invokes pmmSendInitPowerSaveMsg() to send ENTER_BMPS_REQ
* to HAL.
*
* LOGIC:
*
* ASSUMPTIONS:
*
* NOTE:
*
* @param mode can be either 0(sleep mode) or 1 (active mode)
* @param pMac pointer to Global Mac structure.
* @return None
*/
void pmmInitBmpsPwrSave(tpAniSirGlobal pMac)
{
tSirRetStatus retStatus = eSIR_SUCCESS;
tSirResultCodes respStatus = eSIR_SME_SUCCESS;
tpPESession psessionEntry;
tPmmState origState = pMac->pmm.gPmmState;
if((psessionEntry = peGetValidPowerSaveSession(pMac))== NULL)
{
respStatus = eSIR_SME_BMPS_REQ_REJECT;
goto failure;
}
#ifndef WLAN_ACTIVEMODE_OFFLOAD_FEATURE
// sending beacon filtering information down to HAL
if (limSendBeaconFilterInfo(pMac, psessionEntry) != eSIR_SUCCESS)
{
pmmLog(pMac, LOGE, FL("Fail to send Beacon Filter Info \n"));
}
#endif
#ifdef FEATURE_WLAN_DIAG_SUPPORT
limDiagEventReport(pMac, WLAN_PE_DIAG_ENTER_BMPS_REQ_EVENT, psessionEntry, 0, 0);
#endif //FEATURE_WLAN_DIAG_SUPPORT
if ( ((pMac->pmm.gPmmState != ePMM_STATE_READY) &&
(pMac->pmm.gPmmState != ePMM_STATE_BMPS_WAKEUP)) ||
limIsSystemInScanState(pMac) ||
limIsChanSwitchRunning(pMac) ||
limIsInQuietDuration(pMac) )
{
PELOGE(pmmLog(pMac, LOGE,
FL("pmmBmps: BMPS Request received in invalid state PMM=%d, SME=%d, rejecting the initpwrsave request\n"),
pMac->pmm.gPmmState, pMac->lim.gLimSmeState);)
respStatus = eSIR_SME_INVALID_PMM_STATE;
pmmBmpsUpdateInvalidStateCnt(pMac);
goto failure;
}
//If we are in a missed beacon scenario, we should not be attempting to enter BMPS as heartbeat probe is going on
if(pMac->pmm.inMissedBeaconScenario)
{
if (pMac->lim.gLimTimersCreated && pMac->lim.limTimers.gLimHeartBeatTimer.pMac)
{
if(VOS_TRUE != tx_timer_running(&pMac->lim.limTimers.gLimHeartBeatTimer))
{
PELOGE(pmmLog(pMac, LOGE, FL("Unexpected heartbeat timer not running"));)
limReactivateHeartBeatTimer(pMac, psessionEntry);
}
}
respStatus = eSIR_SME_BMPS_REQ_REJECT;
goto failure;
}
/* At this point, device is associated and PMM is not in BMPS_SLEEP state.
* Heartbeat timer not running is an indication that PE have detected a
* loss of link. In this case, reject BMPS request.
*/
/* TODO : We need to have a better check. This check is not valid */
#if 0
if ( (pMac->sys.gSysEnableLinkMonitorMode) && (pMac->lim.limTimers.gLimHeartBeatTimer.pMac) )
{
if(VOS_TRUE != tx_timer_running(&pMac->lim.limTimers.gLimHeartBeatTimer))
{
PELOGE(pmmLog(pMac, LOGE,
FL("Reject BMPS_REQ because HeartBeatTimer is not running. \n"));)
respStatus = eSIR_SME_BMPS_REQ_FAILED;
goto failure;
}
}
#endif
//If the following function returns SUCCESS, then PMM will wait for an explicit
//response message from softmac.
//changing PMM state before posting message to HAL, as this is a synchronous call to HAL
pMac->pmm.gPmmState = ePMM_STATE_BMPS_WT_INIT_RSP;
if((retStatus = pmmSendInitPowerSaveMsg(pMac,psessionEntry)) != eSIR_SUCCESS)
{
PELOGE(pmmLog(pMac, LOGE,
FL("pmmBmps: Init Power Save Request Failed: Sending Response: %d\n"),
retStatus);)
respStatus = eSIR_SME_BMPS_REQ_REJECT;
pmmBmpsUpdateHalReqFailureCnt(pMac);
goto failure;
}
//Update the powerSave sessionId
pMac->pmm.sessionId = psessionEntry->peSessionId;
return;
failure:
// Change the state back to original state
pMac->pmm.gPmmState =origState;
limSendSmeRsp(pMac, eWNI_PMC_ENTER_BMPS_RSP, respStatus, 0, 0);
return;
}
/**
* pmmSendChangePowerSaveMsg()
*
*FUNCTION:
* This function is called to send SIR_HAL_EXIT_BMPS_REQ to HAL.
* This message will trigger HAL to program HW to wake up.
*
*LOGIC:
*
*ASSUMPTIONS:
* NA
*
*NOTE:
* NA
*
* @param pMac pointer to Global Mac structure.
* @return success if message send is ok, else false.
*/
tSirRetStatus pmmSendChangePowerSaveMsg(tpAniSirGlobal pMac)
{
tSirRetStatus retStatus = eSIR_SUCCESS;
tpExitBmpsParams pExitBmpsParams;
tSirMsgQ msgQ;
tpPESession psessionEntry;
tANI_U8 currentOperatingChannel = limGetCurrentOperatingChannel(pMac);
if( eHAL_STATUS_SUCCESS != palAllocateMemory( pMac->hHdd, (void **)&pExitBmpsParams, sizeof(*pExitBmpsParams)) )
{
pmmLog(pMac, LOGW, FL("palAllocateMemory() failed\n"));
retStatus = eSIR_MEM_ALLOC_FAILED;
return retStatus;
}
if((psessionEntry = peGetValidPowerSaveSession(pMac)) == NULL )
{
retStatus = eSIR_FAILURE;
return retStatus;
}
palZeroMemory( pMac->hHdd, (tANI_U8 *)pExitBmpsParams, sizeof(*pExitBmpsParams));
msgQ.type = WDA_EXIT_BMPS_REQ;
msgQ.reserved = 0;
msgQ.bodyptr = pExitBmpsParams;
msgQ.bodyval = 0;
/* If reason for full power is disconnecting (ie. link is
* disconnected) or becasue of channel switch or full power requested
* because of beacon miss and connected on DFS channel
* then we should not send data null.
* For all other reason code, send data null.
*/
if ( !(SIR_IS_FULL_POWER_REASON_DISCONNECTED(pMac->pmm.gPmmExitBmpsReasonCode) ||
( (eSME_MISSED_BEACON_IND_RCVD == pMac->pmm.gPmmExitBmpsReasonCode) &&
limIsconnectedOnDFSChannel(currentOperatingChannel))))
pExitBmpsParams->sendDataNull = 1;
pExitBmpsParams->bssIdx = psessionEntry->bssIdx;
/* we need to defer any incoming messages until we
* get a WDA_EXIT_BMPS_RSP from HAL.
*/
SET_LIM_PROCESS_DEFD_MESGS(pMac, false);
MTRACE(macTraceMsgTx(pMac, NO_SESSION, msgQ.type));
retStatus = wdaPostCtrlMsg( pMac, &msgQ);
if( eSIR_SUCCESS != retStatus )
{
PELOGE(pmmLog( pMac, LOGE, FL("Sending WDA_EXIT_BMPS_REQ failed, reason=%X \n"), retStatus );)
palFreeMemory(pMac->hHdd, (tANI_U8*)pExitBmpsParams);
return retStatus;
}
PELOG1(pmmLog(pMac, LOG1, FL("WDA_EXIT_BMPS_REQ has been successfully sent to HAL\n"));)
return retStatus;
}
/**
* pmmSendInitPowerSaveMsg()
*
*FUNCTION:
* This function is called to send ENTER_BMPS_REQ message to HAL.
* This message is sent to intialize the process of bringing the
* station into power save state.
*
*LOGIC:
*
*ASSUMPTIONS:
* NA
*
*NOTE:
* NA
*
* @param pMac pointer to Global Mac structure.
* @param mode The Power Save or Active State
*
* @return success if message send is ok, else false.
*/
tSirRetStatus pmmSendInitPowerSaveMsg(tpAniSirGlobal pMac,tpPESession psessionEntry)
{
tSirRetStatus retCode = eSIR_SUCCESS;
tSirMsgQ msgQ;
tpEnterBmpsParams pBmpsParams = NULL;
int i=0;
tANI_U32 rssiFilterPeriod = 5;
tANI_U32 numBeaconPerRssiAverage = 5;
tANI_U32 bRssiFilterEnable = FALSE;
if((psessionEntry->currentBssBeaconCnt == 0 && (!IS_ACTIVEMODE_OFFLOAD_FEATURE_ENABLE)))
{
PELOGE(pmmLog( pMac, LOGE, FL("Beacon count is zero, can not retrieve the TSF, failing the Enter Bmps Request\n"));)
return eSIR_FAILURE;
}
if (palAllocateMemory(pMac->hHdd, (void **)&pBmpsParams, sizeof(tEnterBmpsParams)) != eHAL_STATUS_SUCCESS)
{
pmmLog(pMac, LOGP, "PMM: Not able to allocate memory for Enter Bmps\n");
return eSIR_FAILURE;
}
pMac->pmm.inMissedBeaconScenario = FALSE;
pBmpsParams->respReqd = TRUE;
pBmpsParams->tbtt = psessionEntry->lastBeaconTimeStamp;
pBmpsParams->dtimCount = psessionEntry->lastBeaconDtimCount;
pBmpsParams->dtimPeriod = psessionEntry->lastBeaconDtimPeriod;
pBmpsParams->bssIdx = psessionEntry->bssIdx;
if(wlan_cfgGetInt(pMac, WNI_CFG_RSSI_FILTER_PERIOD, &rssiFilterPeriod) != eSIR_SUCCESS)
pmmLog(pMac, LOGP, FL("pmmCfg: cfgGet failed for Rssi filter period"));
// This flag can be overridden when 11r/CCXEnabled=1 and FastTransition=1
if(wlan_cfgGetInt(pMac, WNI_CFG_PS_ENABLE_RSSI_MONITOR, &bRssiFilterEnable) != eSIR_SUCCESS)
pmmLog(pMac, LOGP, FL("pmmCfg: cfgGet failed for Rssi monitor enable flag"));
pBmpsParams->bRssiFilterEnable = bRssiFilterEnable;
#if defined (WLAN_FEATURE_VOWIFI_11R) || defined (FEATURE_WLAN_CCX) || defined(FEATURE_WLAN_LFR)
// If there is a CCX assoc or 11r assoc we need to pick up the rssiFilterPeriod from the
// FT config value.
for(i =0; i < pMac->lim.maxBssId; i++)
{
if (limisFastTransitionRequired(pMac, i))
{
if(wlan_cfgGetInt(pMac, WNI_CFG_FT_RSSI_FILTER_PERIOD, &rssiFilterPeriod) != eSIR_SUCCESS)
pmmLog(pMac, LOGP, FL("pmmCfg: cfgGet failed for Rssi filter period"));
// We need to override the ini value to enable
// FW RSSI Monitoring. Basically if CCX and FT are enabled
// then enable FW RSSI Monitoring
pBmpsParams->bRssiFilterEnable = TRUE;
break;
}
}
#endif
pBmpsParams->rssiFilterPeriod = (tANI_U8)rssiFilterPeriod;
/* The numBeaconPerRssiAverage should be less than the max allowed (default set to 20 in CFG)
*/
if(wlan_cfgGetInt(pMac, WNI_CFG_NUM_BEACON_PER_RSSI_AVERAGE, &numBeaconPerRssiAverage) != eSIR_SUCCESS)
pmmLog(pMac, LOGP, FL("pmmCfg: cfgGet failed for num beacon per rssi"));
pBmpsParams->numBeaconPerRssiAverage =
(tANI_U8)GET_MIN_VALUE((tANI_U8) numBeaconPerRssiAverage, WNI_CFG_NUM_BEACON_PER_RSSI_AVERAGE_STAMAX);
pmmLog (pMac, LOG1,
"%s: [INFOLOG]RssiFilterInfo..%d %x %x\n", __func__, (int)pBmpsParams->bRssiFilterEnable,
(unsigned int)pBmpsParams->rssiFilterPeriod, (unsigned int)pBmpsParams->numBeaconPerRssiAverage);
msgQ.type = WDA_ENTER_BMPS_REQ;
msgQ.reserved = 0;
msgQ.bodyptr = pBmpsParams;
msgQ.bodyval = 0;
PELOG2(pmmLog( pMac, LOG2,
FL( "pmmBmps: Sending WDA_ENTER_BMPS_REQ" ));)
/* we need to defer any incoming messages until we get a
* WDA_ENTER_BMPS_RSP from HAL.
*/
SET_LIM_PROCESS_DEFD_MESGS(pMac, false);
MTRACE(macTraceMsgTx(pMac, psessionEntry->peSessionId, msgQ.type));
if( eSIR_SUCCESS != (retCode = wdaPostCtrlMsg( pMac, &msgQ )))
{
palFreeMemory(pMac->hHdd, pBmpsParams);
PELOGE(pmmLog( pMac, LOGE,
FL("Posting WDA_ENTER_BMPS_REQ to HAL failed, reason=%X\n"),
retCode );)
}
return retCode;
}
/**
* pmmSendPowerSaveCfg()
*
*FUNCTION:
* This function is called to send power save configurtion.
*
*NOTE:
*
* @param pMac pointer to Global Mac structure.
* @param mode The Power Save or Active State
*
* @return success if message send is ok, else false.
*/
tSirRetStatus pmmSendPowerSaveCfg(tpAniSirGlobal pMac, tpSirPowerSaveCfg pUpdatedPwrSaveCfg)
{
tSirRetStatus retCode = eSIR_SUCCESS;
tSirMsgQ msgQ;
tANI_U32 listenInterval;
tANI_U32 HeartBeatCount = 1;
tANI_U32 maxPsPoll;
tANI_U32 numBeaconPerRssiAverage;
tANI_U32 minRssiThreshold;
tANI_U32 nthBeaconFilter;
tANI_U32 broadcastFrameFilter;
tANI_U32 rssiFilterPeriod;
tANI_U32 ignoreDtim;
if (NULL == pUpdatedPwrSaveCfg)
goto returnFailure;
if(pMac->lim.gLimSmeState != eLIM_SME_IDLE_STATE )
{
pmmLog(pMac, LOGE,
FL("pmmCfg: Power Save Configuration received in invalid global sme state %d"),
pMac->lim.gLimSmeState);
retCode = eSIR_SME_INVALID_STATE;
goto returnFailure;
}
// Get power save configuration CFG values
if(wlan_cfgGetInt(pMac, WNI_CFG_LISTEN_INTERVAL, &listenInterval) != eSIR_SUCCESS)
pmmLog(pMac, LOGP, FL("pmmCfg: cfgGet failed for listen interval"));
pUpdatedPwrSaveCfg->listenInterval = (tANI_U16)listenInterval;
if(wlan_cfgGetInt(pMac, WNI_CFG_HEART_BEAT_THRESHOLD, &HeartBeatCount) != eSIR_SUCCESS)
pmmLog(pMac, LOGP, FL("pmmCfg: cfgGet failed for heart beat thresh"));
pMac->lim.gLimHeartBeatCount = HeartBeatCount;
pUpdatedPwrSaveCfg->HeartBeatCount = HeartBeatCount;
if(wlan_cfgGetInt(pMac, WNI_CFG_NTH_BEACON_FILTER, &nthBeaconFilter) != eSIR_SUCCESS)
pmmLog(pMac, LOGP, FL("pmmCfg: cfgGet failed for Nth beacon filter"));
pUpdatedPwrSaveCfg->nthBeaconFilter = nthBeaconFilter;
if(wlan_cfgGetInt(pMac, WNI_CFG_MAX_PS_POLL, &maxPsPoll) != eSIR_SUCCESS)
pmmLog(pMac, LOGP, FL("pmmCfg: cfgGet failed for max poll"));
pUpdatedPwrSaveCfg->maxPsPoll = maxPsPoll;
if(wlan_cfgGetInt(pMac, WNI_CFG_MIN_RSSI_THRESHOLD, &minRssiThreshold) != eSIR_SUCCESS)
pmmLog(pMac, LOGP, FL("pmmCfg: cfgGet failed for min RSSI Threshold"));
pUpdatedPwrSaveCfg->minRssiThreshold = minRssiThreshold;
if(wlan_cfgGetInt(pMac, WNI_CFG_NUM_BEACON_PER_RSSI_AVERAGE, &numBeaconPerRssiAverage) != eSIR_SUCCESS)
pmmLog(pMac, LOGP, FL("pmmCfg: cfgGet failed for num beacon per rssi"));
pUpdatedPwrSaveCfg->numBeaconPerRssiAverage = (tANI_U8) numBeaconPerRssiAverage;
if(wlan_cfgGetInt(pMac, WNI_CFG_RSSI_FILTER_PERIOD, &rssiFilterPeriod) != eSIR_SUCCESS)
pmmLog(pMac, LOGP, FL("pmmCfg: cfgGet failed for Rssi filter period"));
pUpdatedPwrSaveCfg->rssiFilterPeriod = (tANI_U8) rssiFilterPeriod;
if(wlan_cfgGetInt(pMac, WNI_CFG_BROADCAST_FRAME_FILTER_ENABLE, &broadcastFrameFilter) != eSIR_SUCCESS)
pmmLog(pMac, LOGP, FL("pmmCfg: cfgGet failed for Nth beacon filter"));
pUpdatedPwrSaveCfg->broadcastFrameFilter = (tANI_U8) broadcastFrameFilter;
if(wlan_cfgGetInt(pMac, WNI_CFG_IGNORE_DTIM, &ignoreDtim) != eSIR_SUCCESS)
pmmLog(pMac, LOGP, FL("pmmCfg: cfgGet failed for ignoreDtim"));
pUpdatedPwrSaveCfg->ignoreDtim = (tANI_U8) ignoreDtim;
/* The numBeaconPerRssiAverage should be <= rssiFilter Period,
* and less than the max allowed (default set to 20 in CFG)
*/
if (numBeaconPerRssiAverage > rssiFilterPeriod)
pUpdatedPwrSaveCfg->numBeaconPerRssiAverage = (tANI_U8)GET_MIN_VALUE(rssiFilterPeriod, WNI_CFG_NUM_BEACON_PER_RSSI_AVERAGE_STAMAX);
//Save a copy of the CFG in global pmm context.
palCopyMemory( pMac->hHdd, (tANI_U8 *) &pMac->pmm.gPmmCfg, pUpdatedPwrSaveCfg, sizeof(tSirPowerSaveCfg));
msgQ.type = WDA_PWR_SAVE_CFG;
msgQ.reserved = 0;
msgQ.bodyptr = pUpdatedPwrSaveCfg;
msgQ.bodyval = 0;
PELOG1(pmmLog( pMac, LOG1, FL( "pmmBmps: Sending WDA_PWR_SAVE_CFG to HAL"));)
MTRACE(macTraceMsgTx(pMac, NO_SESSION, msgQ.type));
if( eSIR_SUCCESS != (retCode = wdaPostCtrlMsg( pMac, &msgQ )))
{
pmmLog( pMac, LOGP,
FL("Posting WDA_PWR_SAVE_CFG to HAL failed, reason=%X"),
retCode );
goto returnFailure;
}
return retCode;
returnFailure:
/* In case of failure, we need to free the memory */
if (NULL != pUpdatedPwrSaveCfg)
{
palFreeMemory( pMac->hHdd, (tANI_U8 *) pUpdatedPwrSaveCfg);
}
return retCode;
}
/**
* pmmExitBmpsResponseHandler
*
*FUNCTION:
* This function processes the Wakeup Rsp from HAL and if successfull,
* sends a respnose back to PMC layer.
*LOGIC:
*
*ASSUMPTIONS:
* NA
*
*NOTE:
* NA
*
* @param pMac pointer to Global Mac structure.
* @param rspStatus Status of the response, Success or an error code.
*
* @return none.
*/
void pmmExitBmpsResponseHandler(tpAniSirGlobal pMac, tpSirMsgQ limMsg)
{
tpExitBmpsParams pExitBmpsRsp;
eHalStatus rspStatus;
tANI_U8 PowersavesessionId;
tpPESession psessionEntry;
tSirResultCodes retStatus = eSIR_SME_SUCCESS;
/* Copy the power save sessionId to the local variable */
PowersavesessionId = pMac->pmm.sessionId;
/* we need to process all the deferred messages enqueued since
* the initiating the SIR_HAL_EXIT_BMPS_REQ.
*/
SET_LIM_PROCESS_DEFD_MESGS(pMac, true);
if((psessionEntry = peFindSessionBySessionId(pMac,PowersavesessionId))==NULL)
{
limLog(pMac, LOGP,FL("Session Does not exist for given sessionID\n"));
return;
}
/* Update wakeup statistics */
pmmUpdateWakeupStats(pMac);
if (NULL == limMsg->bodyptr)
{
pmmLog(pMac, LOGE, FL("Received SIR_HAL_EXIT_BMPS_RSP with NULL "));
return;
}
pExitBmpsRsp = (tpExitBmpsParams)(limMsg->bodyptr);
rspStatus = pExitBmpsRsp->status;
if(pMac->pmm.gPmmState != ePMM_STATE_BMPS_WT_WAKEUP_RSP)
{
PELOGE(pmmLog(pMac, LOGE,
FL("Received SIR_HAL_EXIT_BMPS_RSP while in incorrect state: %d\n"),
pMac->pmm.gPmmState);)
retStatus = eSIR_SME_INVALID_PMM_STATE;
pmmBmpsUpdateInvalidStateCnt(pMac);
}
else
{
PELOGW(pmmLog(pMac, LOGW, FL("Received SIR_HAL_EXIT_BMPS_RSP in correct state. \n"));)
}
/* PE is going to wakeup irrespective of whether
* SIR_HAL_EXIT_BMPS_REQ was successful or not
*/
switch (rspStatus)
{
case eHAL_STATUS_SUCCESS:
retStatus = eSIR_SME_SUCCESS;
break;
default:
{
/* PE is going to be awake irrespective of whether EXIT_BMPS_REQ
* failed or not. This is mainly to eliminate the dead-lock condition
* But, PMC will be informed about the error.
*/
retStatus = eSIR_SME_BMPS_REQ_FAILED;
}
break;
}
pMac->pmm.gPmmState = ePMM_STATE_BMPS_WAKEUP;
pmmUpdateWakeupStats(pMac);
// turn on background scan
pMac->sys.gSysEnableScanMode = true;
// send response to PMC
if(IS_FEATURE_SUPPORTED_BY_FW(SLM_SESSIONIZATION) )
{
limSendSmeRsp(pMac, eWNI_PMC_EXIT_BMPS_RSP, retStatus,
psessionEntry->smeSessionId, psessionEntry->transactionId);
}
else
{
limSendSmeRsp(pMac, eWNI_PMC_EXIT_BMPS_RSP, retStatus, 0, 0);
}
if ( pMac->pmm.gPmmExitBmpsReasonCode == eSME_MISSED_BEACON_IND_RCVD)
{
PELOGW(pmmLog(pMac, LOGW, FL("Rcvd SIR_HAL_EXIT_BMPS_RSP with MISSED_BEACON\n"));)
pmmMissedBeaconHandler(pMac);
}
else if(pMac->pmm.inMissedBeaconScenario)
{
PELOGW(pmmLog(pMac, LOGW, FL("Rcvd SIR_HAL_EXIT_BMPS_RSP in missed beacon scenario but reason code not correct"));)
pmmMissedBeaconHandler(pMac);
}
else
{
// Enable heartbeat timer
limReactivateHeartBeatTimer(pMac, psessionEntry);
}
return;
}
/**
* pmmMissedBeaconHandler()
*
*FUNCTION:
* This function is called when PMM receives an eWNI_PMC_EXIT_BMPS_REQ
* with reason code being eSME_MISSED_BEACON_IND_RCVD.
*
*NOTE:
* @param pMac pointer to Global Mac structure.
* @return none
*/
void pmmMissedBeaconHandler(tpAniSirGlobal pMac)
{
tANI_U8 pwrSaveSessionId;
tANI_U32 beaconInterval = 0;
tANI_U32 heartBeatInterval = pMac->lim.gLimHeartBeatCount;
tpPESession psessionEntry;
/* Copy the power save sessionId to the local variable */
pwrSaveSessionId = pMac->pmm.sessionId;
if((psessionEntry = peFindSessionBySessionId(pMac,pwrSaveSessionId))==NULL)
{
limLog(pMac, LOGE,FL("Session Does not exist for given sessionID\n"));
return;
}
PELOGE(pmmLog(pMac, LOG1, FL("The device woke up due to MISSED BEACON \n"));)
/* Proceed only if HeartBeat timer is created */
if((pMac->lim.limTimers.gLimHeartBeatTimer.pMac) &&
(pMac->lim.gLimTimersCreated))
{
if (wlan_cfgGetInt(pMac, WNI_CFG_BEACON_INTERVAL, &beaconInterval) != eSIR_SUCCESS)
PELOG1(pmmLog(pMac, LOG1, FL("Fail to get BEACON_INTERVAL value\n"));)
/* Change timer to reactivate it in future */
heartBeatInterval= SYS_MS_TO_TICKS(beaconInterval * heartBeatInterval);
if( tx_timer_change(&pMac->lim.limTimers.gLimHeartBeatTimer,
(tANI_U32)heartBeatInterval, 0) != TX_SUCCESS)
{
PELOG1(pmmLog(pMac, LOG1, FL("Fail to change HeartBeat timer\n"));)
}
/* update some statistics */
if(LIM_IS_CONNECTION_ACTIVE(psessionEntry))
{
if(psessionEntry->LimRxedBeaconCntDuringHB < MAX_NO_BEACONS_PER_HEART_BEAT_INTERVAL)
pMac->lim.gLimHeartBeatBeaconStats[psessionEntry->LimRxedBeaconCntDuringHB]++;
else
pMac->lim.gLimHeartBeatBeaconStats[0]++;
}
/* To handle the missed beacon failure, message is being posted to self as if the
* actual timer has expired. This is done to make sure that there exists one
* common entry and exit points
*/
//limResetHBPktCount(pMac); // 090805: Where did this come from?
limResetHBPktCount(psessionEntry); // 090805: This is what it SHOULD be. If we even need it.
pmmSendMessageToLim(pMac, SIR_LIM_HEART_BEAT_TIMEOUT);
}
else
{
PELOGE(pmmLog(pMac, LOGE, FL("HeartBeat Timer is not created, cannot re-activate\n"));)
}
return;
}
/**
* pmmExitBmpsIndicationHandler
*
*FUNCTION:
* This function sends a Power Save Indication. back to PMC layer.
* This indication is originated from softmac and will occur in the following two
* scenarios:
* 1) When softmac is in sleep state and wakes up to parse TIM and finds that
* AP has the data pending for this STA, then it sends this indication to let PMC know
* that it is going to be awake and pass the control over to PMC
* 2) When softmac is in sleep state and wakes up to parse TIM and determines that
* current TIM is DTIM and AP has buffered broadcast/multicast frames.
* In this scenario, softmac needs to remain awake for broadcast/multicast frames and it
* sends an indication to PMC that it is awake and passes the control over to PMC.
* 3) If station is awake and 'fEnablePwrSaveImmediately' flag is set, then softmac will transmit all
* frames in its queues and go to sleep. Before going to sleep it sends the notification to PMC that
* it is going to sleep.
*LOGIC:
*
*ASSUMPTIONS:
* NA
*
*NOTE:
* NA
*
* @param pMac pointer to Global Mac structure.
* @param rspStatus Status of the response, Success or an error code.
*
* @return none.
*/
void pmmExitBmpsIndicationHandler(tpAniSirGlobal pMac, tANI_U8 mode, eHalStatus rspStatus)
{
tANI_U32 beaconInterval = 0;
tANI_U32 heartBeatInterval = pMac->lim.gLimHeartBeatCount;
tANI_U8 powersavesessionId;
tpPESession psessionEntry;
/* Copy the power save sessionId to the local variable */
powersavesessionId = pMac->pmm.sessionId;
psessionEntry = peFindSessionBySessionId(pMac,powersavesessionId);
if(psessionEntry == NULL)
{
PELOGE(limLog(pMac, LOGE,FL("Session does Not exist with given sessionId :%d \n"),powersavesessionId);)
return;
}
/* Since, the hardware is already wokenup, PE also wakesup and informs
* the upper layers that the system is waking up. Hence always Success is
* sent in the reason code for the message sent to PMC
*/
PELOGW(pmmLog(pMac, LOGW,
FL("pmmBmps: Received SIR_HAL_EXIT_BMPS_IND from HAL, Exiting BMPS sleep mode\n")); )
pMac->pmm.gPmmState = ePMM_STATE_BMPS_WAKEUP;
pmmUpdateWakeupStats(pMac);
/* turn on background scan */
pMac->sys.gSysEnableScanMode = true;
pmmBmpsUpdateWakeupIndCnt(pMac);
/* Inform SME about the system awake state */
limSendSmeRsp(pMac,
eWNI_PMC_EXIT_BMPS_IND,
eSIR_SME_SUCCESS, 0, 0);
switch(rspStatus)
{
/* The SoftMAC sends wakeup indication even when Heart-Beat timer expired
* The PE should start taking action against this as soon as it identifies
* that the SoftMAC has identified heart-beat miss
*/
case eHAL_STATUS_HEARTBEAT_TMOUT:
{
PELOG1(pmmLog(pMac, LOG1,
FL("pmmBmps: The device woke up due to HeartBeat Timeout\n"));)
/* Proceed only if HeartBeat timer is created */
if((pMac->lim.limTimers.gLimHeartBeatTimer.pMac) &&
(pMac->lim.gLimTimersCreated))
{
/* Read the beacon interval from sessionTable */
beaconInterval = psessionEntry->beaconParams.beaconInterval;
/* Change timer to reactivate it in future */
heartBeatInterval= SYS_MS_TO_TICKS(beaconInterval * heartBeatInterval);
if(tx_timer_change(&pMac->lim.limTimers.gLimHeartBeatTimer,
(tANI_U32)heartBeatInterval, 0) != TX_SUCCESS)
{
PELOG1(pmmLog(pMac, LOG1,
FL("pmmBmps: Unable to change HeartBeat timer\n"));)
}
/* update some statistics */
if(LIM_IS_CONNECTION_ACTIVE(psessionEntry))
{
if(psessionEntry->LimRxedBeaconCntDuringHB < MAX_NO_BEACONS_PER_HEART_BEAT_INTERVAL)
pMac->lim.gLimHeartBeatBeaconStats[psessionEntry->LimRxedBeaconCntDuringHB]++;
else
pMac->lim.gLimHeartBeatBeaconStats[0]++;
}
/* To handle the heartbeat failure, message is being posted to self as if the
* actual timer has expired. This is done to make sure that there exists one
* common entry and exit points
*/
pmmSendMessageToLim(pMac, SIR_LIM_HEART_BEAT_TIMEOUT);
}
else
{
PELOGE(pmmLog(pMac, LOGE,
FL("pmmBmps: HeartBeat Timer is not created, cannot re-activate\n"));)
}
}
break;
case eHAL_STATUS_NTH_BEACON_DELIVERY:
break;
default:
break;
}
return;
}
// --------------------------------------------------------------------
/**
* pmmProcessMessageQueue
*
* FUNCTION:
*
* LOGIC:
*
* ASSUMPTIONS:
*
* NOTE:
*
* @param None
* @return None
*/
void pmmProcessMessageQueue(tpAniSirGlobal pMac)
{
#if 0
tSirMsgQ msg;
while (1)
{
if (tx_queue_receive(&pMac->sys.gSirPmmMsgQ, (void *) &msg, TX_WAIT_FOREVER)
!= TX_SUCCESS)
break;
pmmProcessMessage(pMac, &msg);
}
#endif
}
// --------------------------------------------------------------------
/**
* pmmProcessMessage
*
* FUNCTION: Processes the next received Power Management message
*
* LOGIC:
*
* ASSUMPTIONS:
*
* NOTE:
*
* @param None
* @return None
*/
void pmmProcessMessage(tpAniSirGlobal pMac, tpSirMsgQ pMsg)
{
switch (pMsg->type)
{
case eWNI_PMC_PWR_SAVE_CFG:
{
tpSirPowerSaveCfg pPSCfg;
tSirMbMsg *pMbMsg = (tSirMbMsg *)pMsg->bodyptr;
if (palAllocateMemory(pMac->hHdd, (void **)&pPSCfg, sizeof(tSirPowerSaveCfg)) != eHAL_STATUS_SUCCESS)
{
pmmLog(pMac, LOGP, "PMM: Not able to allocate memory for PMC Config\n");
}
(void) palCopyMemory(pMac->hHdd, pPSCfg, pMbMsg->data, sizeof(tSirPowerSaveCfg));
(void) pmmSendPowerSaveCfg(pMac, pPSCfg);
}
break;
case eWNI_PMC_ENTER_BMPS_REQ:
pmmInitBmpsPwrSave(pMac);
break;
case WDA_ENTER_BMPS_RSP:
pmmInitBmpsResponseHandler(pMac, pMsg);
break;
case eWNI_PMC_EXIT_BMPS_REQ:
{
tpExitBmpsInfo pExitBmpsInfo;
tSirMbMsg *pMbMsg = (tSirMbMsg *)pMsg->bodyptr;
if (palAllocateMemory(pMac->hHdd, (void **)&pExitBmpsInfo, sizeof(tExitBmpsInfo)) != eHAL_STATUS_SUCCESS)
{
pmmLog(pMac, LOGP, "PMM: Failed to allocate memory for Exit BMPS Info \n");
}
(void) palCopyMemory(pMac->hHdd, pExitBmpsInfo, pMbMsg->data, sizeof(tExitBmpsInfo));
(void) pmmExitBmpsRequestHandler(pMac, pExitBmpsInfo);
}
break;
case WDA_EXIT_BMPS_RSP:
pmmExitBmpsResponseHandler(pMac, pMsg);
break;
case WDA_EXIT_BMPS_IND:
pmmExitBmpsIndicationHandler(pMac, SIR_PM_ACTIVE_MODE, (eHalStatus)pMsg->bodyval);
break;
case eWNI_PMC_ENTER_IMPS_REQ:
pmmEnterImpsRequestHandler(pMac);
break;
case WDA_ENTER_IMPS_RSP:
pmmEnterImpsResponseHandler(pMac, (eHalStatus)pMsg->bodyval);
break;
case eWNI_PMC_EXIT_IMPS_REQ:
pmmExitImpsRequestHandler(pMac);
break;
case WDA_EXIT_IMPS_RSP:
pmmExitImpsResponseHandler(pMac, (eHalStatus)pMsg->bodyval);
break;
case eWNI_PMC_ENTER_UAPSD_REQ:
pmmEnterUapsdRequestHandler(pMac);
break;
case WDA_ENTER_UAPSD_RSP:
pmmEnterUapsdResponseHandler(pMac, pMsg);
break;
case eWNI_PMC_EXIT_UAPSD_REQ:
pmmExitUapsdRequestHandler(pMac);
break;
case WDA_EXIT_UAPSD_RSP:
pmmExitUapsdResponseHandler(pMac, pMsg);
break;
case eWNI_PMC_WOWL_ADD_BCAST_PTRN:
pmmSendWowlAddBcastPtrn(pMac, pMsg);
break;
case eWNI_PMC_WOWL_DEL_BCAST_PTRN:
pmmSendWowlDelBcastPtrn(pMac, pMsg);
break;
case eWNI_PMC_ENTER_WOWL_REQ:
pmmEnterWowlRequestHandler(pMac, pMsg);
break;
case WDA_WOWL_ENTER_RSP:
pmmEnterWowlanResponseHandler(pMac, pMsg);
break;
case eWNI_PMC_EXIT_WOWL_REQ:
pmmExitWowlanRequestHandler(pMac);
break;
case WDA_WOWL_EXIT_RSP:
pmmExitWowlanResponseHandler(pMac, pMsg);
break;
#ifdef WLAN_FEATURE_PACKET_FILTERING
case WDA_PACKET_COALESCING_FILTER_MATCH_COUNT_RSP:
pmmFilterMatchCountResponseHandler(pMac, pMsg);
break;
#endif // WLAN_FEATURE_PACKET_FILTERING
#ifdef WLAN_FEATURE_GTK_OFFLOAD
case WDA_GTK_OFFLOAD_GETINFO_RSP:
pmmGTKOffloadGetInfoResponseHandler(pMac, pMsg);
break;
#endif // WLAN_FEATURE_GTK_OFFLOAD
default:
PELOGW(pmmLog(pMac, LOGW,
FL("PMM: Unknown message in pmmMsgQ type %d, potential memory leak!!\n"),
pMsg->type);)
}
if (NULL != pMsg->bodyptr)
{
palFreeMemory(pMac->hHdd, (tANI_U8 *)pMsg->bodyptr);
pMsg->bodyptr = NULL;
}
}
// --------------------------------------------------------------------
/**
* pmmPostMessage
*
* FUNCTION:
* Post a message to the pmm message queue
*
* LOGIC:
*
* ASSUMPTIONS:
*
* NOTE:
*
* @param pMsg pointer to message
* @return None
*/
tSirRetStatus
pmmPostMessage(tpAniSirGlobal pMac, tpSirMsgQ pMsg)
{
#if defined(VOSS_ENABLED)
VOS_STATUS vosStatus;
vosStatus = vos_mq_post_message(VOS_MQ_ID_PE, (vos_msg_t *) pMsg);
if(!VOS_IS_STATUS_SUCCESS(vosStatus))
{
pmmLog(pMac, LOGP, FL("vos_mq_post_message failed with status code %d\n"), vosStatus);
return eSIR_FAILURE;
}
#elif defined(ANI_OS_TYPE_WINDOWS)
pmmProcessMessage(pMac, pMsg);
#else
if (tx_queue_send(&pMac->sys.gSirPmmMsgQ, pMsg, TX_NO_WAIT) != TX_SUCCESS)
return eSIR_FAILURE;
#endif // VOSS_ENABLED
return eSIR_SUCCESS;
}
/**
* pmmUpdatePwrSaveStats
*
* FUNCTION: updated BMPS stats, when Station is going into power save state.
*
* LOGIC:
*
* ASSUMPTIONS:
*
* NOTE:
*
* @param pMac pointer to Global MAC Structure.
* @return None
*/
void pmmUpdatePwrSaveStats(tpAniSirGlobal pMac)
{
/*
tANI_U64 TimeAwake = 0;
pMac->pmm.BmpsSleepTimeStamp = vos_timer_get_system_ticks();
if (pMac->pmm.BmpsWakeupTimeStamp)
TimeAwake = (pMac->pmm.BmpsSleepTimeStamp - pMac->pmm.BmpsWakeupTimeStamp) /10;
else
TimeAwake = 0; // very first time
if (TimeAwake > pMac->pmm.BmpsmaxTimeAwake)
{
pMac->pmm.BmpsmaxTimeAwake = TimeAwake;
}
if ((!pMac->pmm.BmpsminTimeAwake) || (TimeAwake < pMac->pmm.BmpsminTimeAwake))
{
pMac->pmm.BmpsminTimeAwake = TimeAwake;
}
pMac->pmm.BmpsavgTimeAwake = ( ( (pMac->pmm.BmpsavgTimeAwake * pMac->pmm.BmpscntSleep) + TimeAwake ) / (pMac->pmm.BmpscntSleep + 1) );
pMac->pmm.BmpscntSleep++;
return;
*/
}
/**
* pmmUpdatePwrSaveStats
*
* FUNCTION: updated BMPS stats, when Station is waking up.
*
* LOGIC:
*
* ASSUMPTIONS:
*
* NOTE:
*
* @param pMac pointer to Global MAC Structure.
* @return None
*/
void pmmUpdateWakeupStats(tpAniSirGlobal pMac)
{
/*
tANI_U64 SleepTime = 0;
pMac->pmm.BmpsWakeupTimeStamp = vos_timer_get_system_ticks();
SleepTime = (pMac->pmm.BmpsWakeupTimeStamp - pMac->pmm.BmpsSleepTimeStamp) / 10;
if (SleepTime > pMac->pmm.BmpsmaxSleepTime)
{
pMac->pmm.BmpsmaxSleepTime = SleepTime;
}
if ((!pMac->pmm.BmpsminSleepTime) || (SleepTime < pMac->pmm.BmpsminSleepTime))
{
pMac->pmm.BmpsminSleepTime = SleepTime;
}
pMac->pmm.BmpsavgSleepTime = ( ( (pMac->pmm.BmpsavgSleepTime * pMac->pmm.BmpscntAwake) + SleepTime ) / (pMac->pmm.BmpscntAwake + 1) );
pMac->pmm.BmpscntAwake++;
return;
*/
}
// --------------------------------------------------------------------
/**
* pmmEnterImpsRequestHandler
*
* FUNCTION:
* This function sends the idle mode power save request from host device
* drive to HAL. This function is called from pmmProcessMsg()
*
* LOGIC:
*
* ASSUMPTIONS:
* None
*
* NOTE:
*
* @param Global handle to MAC
* @return None
*/
void pmmEnterImpsRequestHandler (tpAniSirGlobal pMac)
{
tSirResultCodes resultCode = eSIR_SME_SUCCESS;
tSirRetStatus retStatus = eSIR_SUCCESS;
tPmmState origState = pMac->pmm.gPmmState;
#ifdef FEATURE_WLAN_DIAG_SUPPORT
limDiagEventReport(pMac, WLAN_PE_DIAG_ENTER_IMPS_REQ_EVENT, peGetValidPowerSaveSession(pMac), 0, 0);
#endif //FEATURE_WLAN_DIAG_SUPPORT
/*Returns True even single active session present */
if(peIsAnySessionActive(pMac))
{
resultCode = eSIR_SME_INVALID_STATE;
goto failure;
}
if ( ((pMac->pmm.gPmmState != ePMM_STATE_READY) &&
(pMac->pmm.gPmmState != ePMM_STATE_IMPS_WAKEUP)) ||
((pMac->lim.gLimSmeState != eLIM_SME_IDLE_STATE) &&
(pMac->lim.gLimSmeState != eLIM_SME_JOIN_FAILURE_STATE)) ||
(pMac->lim.gLimMlmState != eLIM_MLM_IDLE_STATE) ||
limIsChanSwitchRunning (pMac) ||
limIsInQuietDuration (pMac) )
{
PELOGE(pmmLog(pMac, LOGE,
FL("pmmImps: PMM State = %d, Global MLM State = %d, Global SME State = %d, rejecting the sleep mode request\n"),
pMac->pmm.gPmmState, pMac->lim.gLimMlmState, pMac->lim.gLimSmeState);)
resultCode = eSIR_SME_INVALID_PMM_STATE;
pmmImpsUpdateErrStateStats(pMac);
goto failure;
}
// change PE state and send the request to HAL
pMac->pmm.gPmmState = ePMM_STATE_IMPS_WT_SLEEP_RSP;
if( (retStatus = pmmImpsSendChangePwrSaveMsg(pMac, SIR_PM_SLEEP_MODE)) != eSIR_SUCCESS)
{
PELOGE(pmmLog(pMac, LOGE,
FL("pmmImps: IMPS Sleep Request failed: sending response: %x\n"), retStatus);)
resultCode = eSIR_SME_IMPS_REQ_FAILED;
goto failure;
}
else
{
PELOG1(pmmLog(pMac, LOG1,
FL("pmmImps: Waiting for SoftMac response for IMPS request\n"));)
}
return;
failure:
pMac->pmm.gPmmState = origState;
pmmImpsUpdateSleepErrStats(pMac, retStatus);
limSendSmeRsp(pMac,
eWNI_PMC_ENTER_IMPS_RSP,
resultCode, 0, 0);
}
// --------------------------------------------------------------------
/**
* pmmEnterImpsResponseHandler
*
* FUNCTION:
* This function receives the response from HAL layer for the idle mode
* power save request sent. The function is also responsible for checking
* the correctness of the system state before configuring the new state
* on success. This function is called by pmmProcessMsg()
*
* LOGIC:
*
* ASSUMPTIONS:
* None
*
* NOTE:
*
* @param Global handle to MAC, Status code
* @return None
*/
void pmmEnterImpsResponseHandler (tpAniSirGlobal pMac, eHalStatus rspStatus)
{
tPmmState nextState = pMac->pmm.gPmmState;
tSirResultCodes resultCode = eSIR_SME_SUCCESS;
/* we need to process all the deferred messages enqueued since
* the initiating the WDA_ENTER_IMPS_REQ.
*/
SET_LIM_PROCESS_DEFD_MESGS(pMac, true);
if(pMac->pmm.gPmmState != ePMM_STATE_IMPS_WT_SLEEP_RSP)
{
PELOGE(pmmLog(pMac, LOGE,
FL("pmmImps: Receives IMPS sleep rsp in invalid state: %d\n"),
pMac->pmm.gPmmState);)
resultCode = eSIR_SME_INVALID_PMM_STATE;
pmmImpsUpdateErrStateStats(pMac);
goto failure;
}
if(eHAL_STATUS_SUCCESS == rspStatus)
{
//if success, change the state to IMPS sleep mode
pMac->pmm.gPmmState = ePMM_STATE_IMPS_SLEEP;
PELOG2(pmmLog(pMac, LOG2,
FL("pmmImps: Received successful WDA_ENTER_IMPS_RSP from HAL\n"));)
//update power save statistics
pmmImpsUpdatePwrSaveStats(pMac);
limSendSmeRsp(pMac,
eWNI_PMC_ENTER_IMPS_RSP,
resultCode, 0, 0);
}
else
{
// go back to previous state if request failed
nextState = ePMM_STATE_IMPS_WAKEUP;
resultCode = eSIR_SME_CANNOT_ENTER_IMPS;
goto failure;
}
return;
failure:
PELOGE(pmmLog(pMac, LOGE,
FL("pmmImpsSleepRsp failed, Ret Code: %d, next state will be: %d\n"),
rspStatus,
pMac->pmm.gPmmState);)
pMac->pmm.gPmmState = nextState;
limSendSmeRsp(pMac,
eWNI_PMC_ENTER_IMPS_RSP,
resultCode, 0, 0);
}
// --------------------------------------------------------------------
/**
* pmmExitImpsRequestHandler
*
* FUNCTION:
* This function is called by pmmProcessMsg(). The function sends a request
* to HAL to wakeup the device from idle mode power save mode.
*
* LOGIC:
*
* ASSUMPTIONS:
* None
*
* NOTE:
*
* @param Global handle to MAC
* @return None
*/
void pmmExitImpsRequestHandler (tpAniSirGlobal pMac)
{
tSirRetStatus retStatus = eSIR_SUCCESS;
tSirResultCodes resultCode = eSIR_SME_SUCCESS;
tPmmState origState = pMac->pmm.gPmmState;
#ifdef FEATURE_WLAN_DIAG_SUPPORT
limDiagEventReport(pMac, WLAN_PE_DIAG_EXIT_IMPS_REQ_EVENT, peGetValidPowerSaveSession(pMac), 0, 0);
#endif //FEATURE_WLAN_DIAG_SUPPORT
if (ePMM_STATE_IMPS_SLEEP == pMac->pmm.gPmmState)
{
pMac->pmm.gPmmState = ePMM_STATE_IMPS_WT_WAKEUP_RSP;
if( (retStatus = pmmImpsSendChangePwrSaveMsg(pMac, SIR_PM_ACTIVE_MODE)) !=
eSIR_SUCCESS)
{
PELOGE(pmmLog(pMac, LOGE,
FL("pmmImps: Wakeup request message sent to SoftMac failed\n"));)
resultCode = eSIR_SME_IMPS_REQ_FAILED;
goto failure;
}
}
else
{
// PE in invalid state
PELOGE(pmmLog(pMac, LOGE,
FL("pmmImps: Wakeup Req received in invalid state: %x\n"),
pMac->pmm.gPmmState);)
resultCode = eSIR_SME_INVALID_PMM_STATE;
pmmImpsUpdateErrStateStats(pMac);
goto failure;
}
return;
failure:
PELOGE(pmmLog (pMac, LOGE,
FL("pmmImps: Changing to IMPS wakeup mode failed, Ret Code: %d, Next State: %d\n"),
retStatus, pMac->pmm.gPmmState);)
pMac->pmm.gPmmState = origState;
pmmImpsUpdateWakeupErrStats(pMac, retStatus);
limSendSmeRsp(pMac,
eWNI_PMC_EXIT_IMPS_RSP,
resultCode, 0, 0);
}
// --------------------------------------------------------------------
/**
* pmmExitImpsResponseHandler
*
* FUNCTION:
* This function receives the response from HAL layer for the idle mode
* power save request sent. The function is also responsible for checking
* the correctness of the system state before configuring the new state
* on success. This function is called by pmmProcessMsg()
*
* LOGIC:
*
* ASSUMPTIONS:
* None
*
* NOTE:
*
* @param Global handle to MAC
* @return None
*/
void pmmExitImpsResponseHandler(tpAniSirGlobal pMac, eHalStatus rspStatus)
{
tSirResultCodes resultCode = eSIR_SME_SUCCESS;
/* we need to process all the deferred messages enqueued since
* the initiating the WDA_EXIT_IMPS_REQ.
*/
SET_LIM_PROCESS_DEFD_MESGS(pMac, true);
if (pMac->pmm.gPmmState != ePMM_STATE_IMPS_WT_WAKEUP_RSP)
{
PELOGE(pmmLog(pMac, LOGE,
FL("pmmImps: Received 'Wakeup' response in invalid state: %d\n"),
pMac->pmm.gPmmState);)
resultCode = eSIR_SME_INVALID_PMM_STATE;
pmmImpsUpdateErrStateStats(pMac);
}
switch(rspStatus)
{
case eHAL_STATUS_SUCCESS:
{
resultCode = eSIR_SME_SUCCESS;
PELOG2(pmmLog(pMac, LOG2,
FL("pmmImps: Received WDA_EXIT_IMPS_RSP with Successful response from HAL\n"));)
}
break;
default:
{
resultCode = eSIR_SME_IMPS_REQ_FAILED;
PELOGW(pmmLog(pMac, LOGW,
FL("pmmImps: Received WDA_EXIT_IMPS_RSP with Failure Status from HAL\n"));)
}
break;
}
pMac->pmm.gPmmState = ePMM_STATE_IMPS_WAKEUP;
//update power save statistics
pmmImpsUpdateWakeupStats(pMac);
limSendSmeRsp(pMac,
eWNI_PMC_EXIT_IMPS_RSP,
resultCode, 0, 0);
return;
}
// --------------------------------------------------------------------
/**
* pmmEnterUapsdRequestHandler
*
* FUNCTION:
* This function process the eWNI_PMC_ENTER_UAPSD_REQ from PMC,
* checks the correctness of the system state before configuring
* PMM to the new ePMM_STATE_UAPSD_WT_SLEEP_RSP state, and invokes
* invokes pmmUapsdSendChangePwrSaveMsg() to send
* WDA_ENTER_UAPSD_REQ to HAL.
*
* NOTE:
*
* @param Global handle to MAC
* @return None
*/
void pmmEnterUapsdRequestHandler (tpAniSirGlobal pMac)
{
tSirResultCodes resultCode = eSIR_SME_SUCCESS;
tSirRetStatus retStatus = eSIR_SUCCESS;
tPmmState origState = pMac->pmm.gPmmState;
#ifdef FEATURE_WLAN_DIAG_SUPPORT
limDiagEventReport(pMac, WLAN_PE_DIAG_ENTER_UAPSD_REQ_EVENT, peGetValidPowerSaveSession(pMac), 0, 0);
#endif //FEATURE_WLAN_DIAG_SUPPORT
if ( (pMac->pmm.gPmmState != ePMM_STATE_BMPS_SLEEP) ||
limIsSystemInScanState(pMac) )
{
PELOGE(pmmLog(pMac, LOGE,
FL("pmmUapsd: PMM State = %d, Global MLM State = %d, Global SME State = %d, rejecting the sleep mode request\n"),
pMac->pmm.gPmmState, pMac->lim.gLimMlmState, pMac->lim.gLimSmeState);)
resultCode = eSIR_SME_INVALID_PMM_STATE;
goto failure;
}
pMac->pmm.gPmmState = ePMM_STATE_UAPSD_WT_SLEEP_RSP;
if( (retStatus = pmmUapsdSendChangePwrSaveMsg(pMac, SIR_PM_SLEEP_MODE)) != eSIR_SUCCESS)
{
PELOGE(pmmLog(pMac, LOGE,
FL("pmmUapsd: HAL_ENTER_UAPSD_REQ failed with response: %x\n"), retStatus);)
resultCode = eSIR_SME_UAPSD_REQ_FAILED;
goto failure;
}
PELOG1(pmmLog(pMac, LOG1, FL("pmmUapsd: Waiting for WDA_ENTER_UAPSD_RSP \n"));)
return;
failure:
pMac->pmm.gPmmState = origState;
limSendSmeRsp(pMac, eWNI_PMC_ENTER_UAPSD_RSP, resultCode, 0, 0);
return;
}
// --------------------------------------------------------------------
/**
* pmmEnterUapsdResponseHandler
*
* FUNCTION:
* This function processes the SIR_HAL_ENTER_UAPSD_RSP from HAL.
* If the response is successful, it puts PMM into ePMM_STATE_UAPSD_SLEEP
* state and sends back success response to PMC.
*
* NOTE:
*
* @param limMsg
* @return None
*/
void pmmEnterUapsdResponseHandler(tpAniSirGlobal pMac, tpSirMsgQ limMsg)
{
tpUapsdParams pUapsdRspMsg;
tSirResultCodes retStatus = eSIR_SME_SUCCESS;
tANI_U8 PowersavesessionId;
tpPESession psessionEntry;
/* we need to process all the deferred messages enqueued since
* the initiating the SIR_HAL_ENTER_UAPSD_REQ.
*/
SET_LIM_PROCESS_DEFD_MESGS(pMac, true);
/* Copy the power save sessionId to the local variable */
PowersavesessionId = pMac->pmm.sessionId;
if (NULL == limMsg->bodyptr)
{
PELOGE(pmmLog(pMac, LOGE, FL("pmmUapsd: Received SIR_HAL_ENTER_UAPSD_RSP with NULL "));)
return;
}
pUapsdRspMsg = (tpUapsdParams)(limMsg->bodyptr);
if((psessionEntry = peFindSessionBySessionId(pMac,PowersavesessionId))==NULL)
{
limLog(pMac, LOGP,FL("Session Does not exist for given sessionID\n"));
return;
}
if(pMac->pmm.gPmmState != ePMM_STATE_UAPSD_WT_SLEEP_RSP)
{
PELOGE(pmmLog(pMac, LOGE,
FL("pmmUapsd: Received SIR_HAL_ENTER_UAPSD_RSP while in incorrect state: %d\n"),
pMac->pmm.gPmmState);)
limSendSmeRsp(pMac, eWNI_PMC_ENTER_UAPSD_RSP, eSIR_SME_INVALID_PMM_STATE, 0, 0);
return;
}
if(pUapsdRspMsg->status == eHAL_STATUS_SUCCESS)
{
PELOGW(pmmLog(pMac, LOGW,
FL("pmmUapsd: Received successful response from HAL to enter UAPSD mode \n"));)
pMac->pmm.gPmmState = ePMM_STATE_UAPSD_SLEEP;
}
else
{
PELOGE(pmmLog(pMac, LOGE,
FL("pmmUapsd: SIR_HAL_ENTER_UAPSD_RSP failed, informing SME\n"));)
pMac->pmm.gPmmState = ePMM_STATE_BMPS_SLEEP;
retStatus = eSIR_SME_UAPSD_REQ_FAILED;
}
if(IS_FEATURE_SUPPORTED_BY_FW(SLM_SESSIONIZATION))
{
limSendSmeRsp(pMac, eWNI_PMC_ENTER_UAPSD_RSP, retStatus,
psessionEntry->smeSessionId, psessionEntry->transactionId);
}
else
{
limSendSmeRsp(pMac, eWNI_PMC_ENTER_UAPSD_RSP, retStatus, 0, 0);
}
return;
}
// --------------------------------------------------------------------
/**
* pmmExitUapsdRequestHandler
*
* FUNCTION:
* This function process the eWNI_PMC_EXIT_UAPSD_REQ from PMC,
* checks the correctness of the system state before configuring
* PMM to the new ePMM_STATE_UAPSD_WT_WAKEUP_RSP state, and
* invokes pmmUapsdSendChangePwrSaveMsg() to send
* SIR_HAL_EXIT_UAPSD_REQ to HAL.
*
* NOTE:
*
* @param Global handle to MAC
* @return None
*/
void pmmExitUapsdRequestHandler(tpAniSirGlobal pMac)
{
tSirRetStatus retStatus = eSIR_SUCCESS;
tSirResultCodes resultCode = eSIR_SME_SUCCESS;
tPmmState origState = pMac->pmm.gPmmState;
#ifdef FEATURE_WLAN_DIAG_SUPPORT
limDiagEventReport(pMac, WLAN_PE_DIAG_EXIT_UAPSD_REQ_EVENT, peGetValidPowerSaveSession(pMac), 0, 0);
#endif //FEATURE_WLAN_DIAG_SUPPORT
if (ePMM_STATE_UAPSD_SLEEP == pMac->pmm.gPmmState)
{
pMac->pmm.gPmmState = ePMM_STATE_UAPSD_WT_WAKEUP_RSP;
if( (retStatus = pmmUapsdSendChangePwrSaveMsg(pMac, SIR_PM_ACTIVE_MODE)) !=
eSIR_SUCCESS)
{
PELOGE(pmmLog(pMac, LOGE,
FL("pmmUapsd: sending EXIT_UAPSD to HAL failed \n"));)
resultCode = eSIR_SME_UAPSD_REQ_FAILED;
goto failure;
}
}
else
{
PELOGE(pmmLog(pMac, LOGE,
FL("pmmUapsd: Rcv EXIT_UAPSD from PMC in invalid state: %x\n"),
pMac->pmm.gPmmState);)
resultCode = eSIR_SME_INVALID_PMM_STATE;
goto failure;
}
return;
failure:
pMac->pmm.gPmmState = origState;
PELOGE(pmmLog(pMac, LOGE,
FL("pmmUapsd: Waking up from UAPSD mode failed, Ret Code: %d, Next State: %d\n"),
retStatus, pMac->pmm.gPmmState);)
limSendSmeRsp(pMac, eWNI_PMC_EXIT_UAPSD_RSP, resultCode, 0, 0);
}
// --------------------------------------------------------------------
/**
* pmmExitUapsdResponseHandler
*
* FUNCTION:
* This function receives the SIR_HAL_EXIT_UAPSD_RSP from HAL and is
* responsible for checking the correctness of the system state
* before configuring PMM to the new ePMM_STATE_BMPS_SLEEP state
* and send eWNI_PMC_EXIT_UAPSD_RSP to PMC.
*
* NOTE:
*
* @param Global handle to MAC
* @return None
*/
void pmmExitUapsdResponseHandler(tpAniSirGlobal pMac, tpSirMsgQ limMsg)
{
tSirResultCodes resultCode = eSIR_SME_SUCCESS;
tANI_U8 PowersavesessionId;
tpPESession psessionEntry;
tUapsdParams *pUapsdExitRspParams;
/* we need to process all the deferred messages enqueued since
* the initiating the SIR_HAL_EXIT_UAPSD_REQ.
*/
SET_LIM_PROCESS_DEFD_MESGS(pMac, true);
if (pMac->pmm.gPmmState != ePMM_STATE_UAPSD_WT_WAKEUP_RSP)
{
PELOGE(pmmLog(pMac, LOGE,
FL("Received HAL_EXIT_UAPSD_RSP in invalid state: %d\n"),
pMac->pmm.gPmmState);)
limSendSmeRsp(pMac, eWNI_PMC_EXIT_UAPSD_RSP, eSIR_SME_INVALID_PMM_STATE, 0, 0);
return;
}
pUapsdExitRspParams = (tUapsdParams *)(limMsg->bodyptr);
PowersavesessionId = pMac->pmm.sessionId;
if((psessionEntry = peFindSessionBySessionId(pMac,PowersavesessionId))==NULL)
{
limLog(pMac, LOGP,FL("Session Does not exist for given sessionID\n"));
return;
}
if(NULL == pUapsdExitRspParams )
{
PELOGE(pmmLog(pMac, LOGE,
FL("Received HAL_EXIT_UAPSD_RSP message with zero parameters:\n"));)
limSendSmeRsp(pMac, eWNI_PMC_EXIT_UAPSD_RSP, eSIR_SME_UAPSD_REQ_FAILED, 0, 0);
return;
}
switch(pUapsdExitRspParams->status)
{
case eHAL_STATUS_SUCCESS:
resultCode = eSIR_SME_SUCCESS;
PELOGW(pmmLog(pMac, LOGW,
FL("Received SIR_HAL_EXIT_UAPSD_RSP with Successful response \n"));)
break;
default:
resultCode = eSIR_SME_UAPSD_REQ_FAILED;
PELOGE(pmmLog(pMac, LOGW,
FL("Received SIR_HAL_EXIT_UAPSD_RSP with Failure Status\n"));)
break;
}
pMac->pmm.gPmmState = ePMM_STATE_BMPS_SLEEP;
if(IS_FEATURE_SUPPORTED_BY_FW(SLM_SESSIONIZATION))
{
limSendSmeRsp(pMac, eWNI_PMC_EXIT_UAPSD_RSP, resultCode, psessionEntry->smeSessionId,
psessionEntry->transactionId);
}
else
{
limSendSmeRsp(pMac, eWNI_PMC_EXIT_UAPSD_RSP, resultCode, 0, 0);
}
return;
}
/** ------------------------------------------------------------
\fn pmmSendWowlAddBcastPtrn
\brief This function sends a SIR_HAL_WOWL_ADD_BCAST_PTRN
\ message to HAL.
\param tpAniSirGlobal pMac
\param tpSirMsgQ pMsg
\return None
--------------------------------------------------------------*/
void pmmSendWowlAddBcastPtrn(tpAniSirGlobal pMac, tpSirMsgQ pMsg)
{
tpSirWowlAddBcastPtrn pBcastPtrn;
tSirMbMsg *pMbMsg = (tSirMbMsg *)pMsg->bodyptr;
tSirRetStatus retCode = eSIR_SUCCESS;
tSirMsgQ msgQ;
if (palAllocateMemory(pMac->hHdd, (void **)&pBcastPtrn, sizeof(*pBcastPtrn)) != eHAL_STATUS_SUCCESS)
{
pmmLog(pMac, LOGP, FL("Fail to allocate memory for WoWLAN Add Bcast Pattern \n"));
return;
}
(void) palCopyMemory(pMac->hHdd, pBcastPtrn, pMbMsg->data, sizeof(*pBcastPtrn));
if (NULL == pBcastPtrn)
{
pmmLog(pMac, LOGE, FL("Add broadcast pattern message is NULL \n"));
return;
}
msgQ.type = WDA_WOWL_ADD_BCAST_PTRN;
msgQ.reserved = 0;
msgQ.bodyptr = pBcastPtrn;
msgQ.bodyval = 0;
pmmLog(pMac, LOG1, FL( "Sending WDA_WOWL_ADD_BCAST_PTRN to HAL"));
#ifdef FEATURE_WLAN_DIAG_SUPPORT
limDiagEventReport(pMac, WLAN_PE_DIAG_WOWL_ADD_BCAST_PTRN_EVENT, NULL, 0, 0);
#endif //FEATURE_WLAN_DIAG_SUPPORT
if( eSIR_SUCCESS != (retCode = wdaPostCtrlMsg( pMac, &msgQ )))
{
if (pBcastPtrn != NULL)
palFreeMemory( pMac->hHdd, (tANI_U8 *) pBcastPtrn);
pmmLog( pMac, LOGP, FL("Posting WDA_WOWL_ADD_BCAST_PTRN failed, reason=%X"), retCode );
}
return;
}
/** ------------------------------------------------------------
\fn pmmSendWowlDelBcastPtrn
\brief This function sends a SIR_HAL_WOWL_DEL_BCAST_PTRN
\ message to HAL.
\param tpAniSirGlobal pMac
\param tpSirMsgQ pMsg
\return None
--------------------------------------------------------------*/
void pmmSendWowlDelBcastPtrn(tpAniSirGlobal pMac, tpSirMsgQ pMsg)
{
tpSirWowlDelBcastPtrn pDeletePtrn;
tSirMbMsg *pMbMsg = (tSirMbMsg *)pMsg->bodyptr;
tSirRetStatus retCode = eSIR_SUCCESS;
tSirMsgQ msgQ;
if (palAllocateMemory(pMac->hHdd, (void **)&pDeletePtrn, sizeof(*pDeletePtrn)) != eHAL_STATUS_SUCCESS)
{
pmmLog(pMac, LOGP, FL("Fail to allocate memory for WoWLAN Delete Bcast Pattern \n"));
return;
}
(void) palCopyMemory(pMac->hHdd, pDeletePtrn, pMbMsg->data, sizeof(*pDeletePtrn));
if (NULL == pDeletePtrn)
{
pmmLog(pMac, LOGE, FL("Delete broadcast pattern message is NULL \n"));
return;
}
msgQ.type = WDA_WOWL_DEL_BCAST_PTRN;
msgQ.reserved = 0;
msgQ.bodyptr = pDeletePtrn;
msgQ.bodyval = 0;
pmmLog(pMac, LOG1, FL( "Sending WDA_WOWL_DEL_BCAST_PTRN"));
#ifdef FEATURE_WLAN_DIAG_SUPPORT
limDiagEventReport(pMac, WLAN_PE_DIAG_WOWL_DEL_BCAST_PTRN_EVENT, NULL, 0, 0);
#endif //FEATURE_WLAN_DIAG_SUPPORT
if( eSIR_SUCCESS != (retCode = wdaPostCtrlMsg( pMac, &msgQ )))
{
if (NULL != pDeletePtrn)
palFreeMemory( pMac->hHdd, (tANI_U8 *) pDeletePtrn);
pmmLog( pMac, LOGP, FL("Posting WDA_WOWL_DEL_BCAST_PTRN failed, reason=%X"), retCode );
}
return;
}
/** ---------------------------------------------------------
\fn pmmEnterWowlRequestHandler
\brief LIM process the eWNI_PMC_ENTER_WOWL_REQ message, and
\ invokes pmmSendWowlEnterRequest() to send
\ WDA_WOWL_ENTER_REQ message to HAL.
\param tpAniSirGlobal pMac
\param tpSirMsgQ pMsg
\return None
------------------------------------------------------------*/
void pmmEnterWowlRequestHandler(tpAniSirGlobal pMac, tpSirMsgQ pMsg)
{
tpSirSmeWowlEnterParams pSmeWowlParams = NULL;
tpSirHalWowlEnterParams pHalWowlParams = NULL;
tSirRetStatus retCode = eSIR_SUCCESS;
tANI_U32 cfgValue = 0;
tSirMbMsg *pMbMsg = (tSirMbMsg *)pMsg->bodyptr;
tpPESession pSessionEntry = NULL;
tANI_U8 peSessionId = 0;
#ifdef FEATURE_WLAN_DIAG_SUPPORT
limDiagEventReport(pMac, WLAN_PE_DIAG_ENTER_WOWL_REQ_EVENT, NULL, 0, 0);
#endif //FEATURE_WLAN_DIAG_SUPPORT
pSmeWowlParams = (tpSirSmeWowlEnterParams)(pMbMsg->data);
if((pSessionEntry = peFindSessionByBssid(pMac,pSmeWowlParams->bssId,&peSessionId))== NULL)
{
limLog(pMac, LOGE,
FL("session does not exist for given BSSId\n"));
goto end;
}
pMac->pmm.sessionId = peSessionId;
if (NULL == pSmeWowlParams)
return;
// Need to fix it ASAP - TBH
#if 0
if (pMac->lim.gLimSmeState != eLIM_SME_LINK_EST_STATE)
{
pmmLog(pMac, LOGE, FL("Rcvd PMC_ENTER_WOWL_REQ when station is not associated \n"));
limSendSmeRsp(pMac, eWNI_PMC_ENTER_WOWL_RSP, eSIR_SME_STA_NOT_ASSOCIATED, 0, 0);
goto end;
}
#endif
if ((pMac->pmm.gPmmState != ePMM_STATE_BMPS_SLEEP) && (pMac->pmm.gPmmState != ePMM_STATE_WOWLAN))
{
pmmLog(pMac, LOGE, FL("Rcvd PMC_ENTER_WOWL_REQ in invalid Power Save state \n"));
limSendSmeRsp(pMac, eWNI_PMC_ENTER_WOWL_RSP, eSIR_SME_INVALID_PMM_STATE, 0, 0);
goto end;
}
if (palAllocateMemory(pMac->hHdd, (void **)&pHalWowlParams, sizeof(*pHalWowlParams)) != eHAL_STATUS_SUCCESS)
{
pmmLog(pMac, LOGP, FL("Fail to allocate memory for Enter Wowl Request \n"));
goto end;
}
(void) palZeroMemory(pMac->hHdd, (tANI_U8 *)pHalWowlParams, sizeof(*pHalWowlParams) );
// fill in the message field
pHalWowlParams->ucMagicPktEnable = pSmeWowlParams->ucMagicPktEnable;
pHalWowlParams->ucPatternFilteringEnable = pSmeWowlParams->ucPatternFilteringEnable;
(void)palCopyMemory( pMac->hHdd, (tANI_U8 *)pHalWowlParams->magicPtrn, (tANI_U8 *)pSmeWowlParams->magicPtrn, sizeof(tSirMacAddr) );
#ifdef WLAN_WAKEUP_EVENTS
pHalWowlParams->ucWoWEAPIDRequestEnable = pSmeWowlParams->ucWoWEAPIDRequestEnable;
pHalWowlParams->ucWoWEAPOL4WayEnable = pSmeWowlParams->ucWoWEAPOL4WayEnable;
pHalWowlParams->ucWowNetScanOffloadMatch = pSmeWowlParams->ucWowNetScanOffloadMatch;
pHalWowlParams->ucWowGTKRekeyError = pSmeWowlParams->ucWowGTKRekeyError;
pHalWowlParams->ucWoWBSSConnLoss = pSmeWowlParams->ucWoWBSSConnLoss;
#endif // WLAN_WAKEUP_EVENTS
pHalWowlParams->bssIdx = pSessionEntry->bssIdx;
if(wlan_cfgGetInt(pMac, WNI_CFG_WOWLAN_UCAST_PATTERN_FILTER_ENABLE, &cfgValue) != eSIR_SUCCESS)
{
limLog(pMac, LOGP, FL("cfgGet failed for WNI_CFG_WOWLAN_UCAST_PATTERN_FILTER_ENABLE"));
goto end;
}
pHalWowlParams->ucUcastPatternFilteringEnable = (tANI_U8)cfgValue;
if(wlan_cfgGetInt(pMac, WNI_CFG_WOWLAN_CHANNEL_SWITCH_ENABLE, &cfgValue) != eSIR_SUCCESS)
{
limLog(pMac, LOGP, FL("cfgGet failed for WNI_CFG_WOWLAN_CHANNEL_SWITCH_ENABLE"));
goto end;
}
pHalWowlParams->ucWowChnlSwitchRcv = (tANI_U8)cfgValue;
if(wlan_cfgGetInt(pMac, WNI_CFG_WOWLAN_DEAUTH_ENABLE, &cfgValue) != eSIR_SUCCESS)
{
limLog(pMac, LOGP, FL("cfgGet failed for WNI_CFG_WOWLAN_DEAUTH_ENABLE \n"));
goto end;
}
pHalWowlParams->ucWowDeauthRcv = (tANI_U8)cfgValue;
if(wlan_cfgGetInt(pMac, WNI_CFG_WOWLAN_DISASSOC_ENABLE, &cfgValue) != eSIR_SUCCESS)
{
limLog(pMac, LOGP, FL("cfgGet failed for WNI_CFG_WOWLAN_DEAUTH_ENABLE \n"));
goto end;
}
pHalWowlParams->ucWowDisassocRcv = (tANI_U8)cfgValue;
if(wlan_cfgGetInt(pMac, WNI_CFG_WOWLAN_MAX_MISSED_BEACON, &cfgValue) != eSIR_SUCCESS)
{
limLog(pMac, LOGP, FL("cfgGet failed for WNI_CFG_WOWLAN_MAX_MISSED_BEACON \n"));
goto end;
}
pHalWowlParams->ucWowMaxMissedBeacons = (tANI_U8)cfgValue;
if(wlan_cfgGetInt(pMac, WNI_CFG_WOWLAN_MAX_SLEEP_PERIOD, &cfgValue) != eSIR_SUCCESS)
{
limLog(pMac, LOGP, FL("cfgGet failed for WNI_CFG_WOWLAN_MAX_SLEEP_PERIOD \n"));
goto end;
}
pHalWowlParams->ucWowMaxSleepUsec = (tANI_U8)cfgValue;
//Send message to HAL
if( eSIR_SUCCESS != (retCode = pmmSendWowlEnterRequest( pMac, pHalWowlParams)))
{
pmmLog(pMac, LOGE, FL("Send ENTER_WOWL_REQ to HAL failed, reasonCode %d \n"), retCode);
limSendSmeRsp(pMac, eWNI_PMC_ENTER_WOWL_RSP, eSIR_SME_WOWL_ENTER_REQ_FAILED, 0, 0);
goto end;
}
return;
end:
if (pHalWowlParams != NULL)
palFreeMemory( pMac->hHdd, (tANI_U8 *) pHalWowlParams);
return;
}
/** ------------------------------------------------------------
\fn pmmSendWowlEnterRequest
\brief LIM sends a WDA_WOWL_ENTER_REQ message to HAL with
\ the message structure pHalWowlParams. HAL shall later
\ send a WDA_WOWL_ENTER_RSP with the same pointer
\ to the message structure back to PMM.
\param tpAniSirGlobal pMac
\param tpSirHalWowlEnterParams pHalWowlParams
\return tSirRetStatus
--------------------------------------------------------------*/
tSirRetStatus pmmSendWowlEnterRequest(tpAniSirGlobal pMac, tpSirHalWowlEnterParams pHalWowlParams)
{
tSirRetStatus retCode = eSIR_SUCCESS;
tSirMsgQ msgQ;
if (NULL == pHalWowlParams)
return eSIR_FAILURE;
msgQ.type = WDA_WOWL_ENTER_REQ;
msgQ.reserved = 0;
msgQ.bodyptr = pHalWowlParams;
msgQ.bodyval = 0;
/* Defer any incoming message until we get
* a WDA_WOWL_ENTER_RSP from HAL
*/
SET_LIM_PROCESS_DEFD_MESGS(pMac, false);
retCode = wdaPostCtrlMsg(pMac, &msgQ);
if( eSIR_SUCCESS != retCode )
{
pmmLog( pMac, LOGE, FL("Posting WDA_WOWL_ENTER_REQ failed, reason=%X"), retCode );
return retCode;
}
return retCode;
}
/** ---------------------------------------------------------
\fn pmmEnterWowlanResponseHandler
\brief LIM process the WDA_WOWL_ENTER_RSP message.
\ and sends eWNI_PMC_ENTER_WOWL_RSP to SME.
\param tpAniSirGlobal pMac
\param tpSirMsgQ limMsg
\return None
------------------------------------------------------------*/
void pmmEnterWowlanResponseHandler(tpAniSirGlobal pMac, tpSirMsgQ limMsg)
{
tpSirHalWowlEnterParams pWowlEnterParams;
eHalStatus rspStatus;
tSirResultCodes smeRspCode = eSIR_SME_SUCCESS;
/* we need to process all the deferred messages enqueued
* since the initiating the WDA_WOWL_ENTER_REQ.
*/
SET_LIM_PROCESS_DEFD_MESGS(pMac, true);
pWowlEnterParams = (tpSirHalWowlEnterParams)(limMsg->bodyptr);
if (NULL == pWowlEnterParams)
{
pmmLog(pMac, LOGE, FL("Recvd WDA_WOWL_ENTER_RSP with NULL msg "));
smeRspCode = eSIR_SME_WOWL_ENTER_REQ_FAILED;
}
else
{
rspStatus = pWowlEnterParams->status;
if(rspStatus == eHAL_STATUS_SUCCESS)
{
pmmLog(pMac, LOGW, FL("Rcv successful response from HAL to enter WOWLAN \n"));
pMac->pmm.gPmmState = ePMM_STATE_WOWLAN;
}
else
{
pmmLog(pMac, LOGE, FL("HAL enter WOWLAN failed, informing SME\n"));
smeRspCode = eSIR_SME_WOWL_ENTER_REQ_FAILED;
}
}
limSendSmeRsp(pMac, eWNI_PMC_ENTER_WOWL_RSP, smeRspCode, 0, 0);
return;
}
/** ---------------------------------------------------------
\fn pmmExitWowlanRequestHandler
\brief PE process the eWNI_PMC_EXIT_WOWL_REQ message.
\ and sends WDA_WOWL_EXIT_REQ to HAL.
\param tpAniSirGlobal pMac
\return None
------------------------------------------------------------*/
void pmmExitWowlanRequestHandler(tpAniSirGlobal pMac)
{
tSirRetStatus retStatus = eSIR_SUCCESS;
tSirResultCodes smeRspCode = eSIR_SME_SUCCESS;
tpPESession pSessionEntry;
tpSirHalWowlExitParams pHalWowlMsg;
tANI_U8 PowersavesessionId = 0;
PowersavesessionId = pMac->pmm.sessionId;
if((pSessionEntry = peFindSessionBySessionId(pMac,PowersavesessionId)) == NULL )
{
PELOGW(pmmLog(pMac, LOGE, FL("pmmWowl :palAllocateMemory() failed\n"));)
smeRspCode = eSIR_SME_WOWL_EXIT_REQ_FAILED;
goto failure;
}
if (palAllocateMemory(pMac->hHdd, (void **)&pHalWowlMsg, sizeof(*pHalWowlMsg)) != eHAL_STATUS_SUCCESS)
{
pmmLog(pMac, LOGP, FL("Fail to allocate memory for WoWLAN Add Bcast Pattern \n"));
smeRspCode = eSIR_SME_WOWL_EXIT_REQ_FAILED;
goto failure;
}
#ifdef FEATURE_WLAN_DIAG_SUPPORT
limDiagEventReport(pMac, WLAN_PE_DIAG_EXIT_WOWL_REQ_EVENT, NULL, 0, 0);
#endif //FEATURE_WLAN_DIAG_SUPPORT
if ( pMac->pmm.gPmmState != ePMM_STATE_WOWLAN )
{
pmmLog(pMac, LOGE,
FL("Exit WOWLAN Request received in invalid state PMM=%d \n"),
pMac->pmm.gPmmState);
smeRspCode = eSIR_SME_INVALID_PMM_STATE;
goto failure;
}
(void) palZeroMemory(pMac->hHdd, (tANI_U8 *)pHalWowlMsg, sizeof(*pHalWowlMsg) );
pHalWowlMsg->bssIdx = pSessionEntry->bssIdx;
if((retStatus = pmmSendExitWowlReq(pMac, pHalWowlMsg)) != eSIR_SUCCESS)
{
pmmLog(pMac, LOGE,
FL("Fail to send WDA_WOWL_EXIT_REQ, reason code %d\n"),
retStatus);
smeRspCode = eSIR_SME_WOWL_EXIT_REQ_FAILED;
goto failure;
}
return;
failure:
if (pHalWowlMsg != NULL)
palFreeMemory( pMac->hHdd, (tANI_U8 *) pHalWowlMsg);
limSendSmeRsp(pMac, eWNI_PMC_EXIT_WOWL_RSP, smeRspCode, 0, 0);
return;
}
/** ---------------------------------------------------------
\fn pmmSendExitWowlReq
\brief This function sends the WDA_WOWL_EXIT_REQ
\ message to HAL.
\param tpAniSirGlobal pMac
\return None
------------------------------------------------------------*/
tSirRetStatus pmmSendExitWowlReq(tpAniSirGlobal pMac, tpSirHalWowlExitParams pHalWowlParams)
{
tSirRetStatus retCode = eSIR_SUCCESS;
tSirMsgQ msgQ;
if (NULL == pHalWowlParams)
return eSIR_FAILURE;
msgQ.type = WDA_WOWL_EXIT_REQ;
msgQ.reserved = 0;
msgQ.bodyptr = pHalWowlParams;
msgQ.bodyval = 0;
pmmLog(pMac, LOGW, FL("Sending WDA_WOWL_EXIT_REQ"));
/* we need to defer any incoming messages until
* we get a WDA_WOWL_EXIT_RSP from HAL.
*/
SET_LIM_PROCESS_DEFD_MESGS(pMac, false);
if( eSIR_SUCCESS != (retCode = wdaPostCtrlMsg( pMac, &msgQ )))
pmmLog( pMac, LOGE,
FL("Posting WDA_WOWL_EXIT_REQ failed, reason=%X\n"),
retCode );
return retCode;
}
/** ---------------------------------------------------------
\fn pmmExitWowlanResponseHandler
\brief This function process the WDA_WOWL_EXIT_RSP message.
\ and sends back eWNI_PMC_EXIT_WOWL_RSP to SME.
\param tpAniSirGlobal pMac
\return None
------------------------------------------------------------*/
void pmmExitWowlanResponseHandler(tpAniSirGlobal pMac, tpSirMsgQ limMsg)
{
tpSirHalWowlExitParams pHalWowlRspMsg;
eHalStatus rspStatus = eHAL_STATUS_FAILURE;
/* we need to process all the deferred messages enqueued
* since the initiating the WDA_WOWL_EXIT_REQ.
*/
SET_LIM_PROCESS_DEFD_MESGS(pMac, true);
pHalWowlRspMsg = (tpSirHalWowlExitParams)(limMsg->bodyptr);
if (NULL == pHalWowlRspMsg)
{
pmmLog(pMac, LOGE, FL("Recvd WDA_WOWL_ENTER_RSP with NULL msg "));
}
else
{
// restore PMM state to BMPS mode
pMac->pmm.gPmmState = ePMM_STATE_BMPS_SLEEP;
rspStatus = pHalWowlRspMsg->status;
}
if( rspStatus == eHAL_STATUS_SUCCESS)
{
pmmLog(pMac, LOGW, FL("Rcvd successful rsp from HAL to exit WOWLAN \n"));
limSendSmeRsp(pMac, eWNI_PMC_EXIT_WOWL_RSP, eSIR_SME_SUCCESS, 0, 0);
}
else
{
pmmLog(pMac, LOGE, FL("Rcvd failure rsp from HAL to exit WOWLAN \n"));
limSendSmeRsp(pMac, eWNI_PMC_EXIT_WOWL_RSP, eSIR_SME_WOWL_EXIT_REQ_FAILED, 0, 0);
}
return;
}
// --------------------------------------------------------------------
/**
* pmmImpsSendChangePwrSaveMsg
*
* FUNCTION:
* This function is called to toggle the Idle mode power save mode
*
* LOGIC:
*
* ASSUMPTIONS:
* None
*
* NOTE:
*
* @param Global handle to MAC
* @param mode to be configured
* @return None
*/
tSirRetStatus pmmImpsSendChangePwrSaveMsg(tpAniSirGlobal pMac, tANI_U8 mode)
{
tSirRetStatus retStatus = eSIR_SUCCESS;
tSirMsgQ msgQ;
if (SIR_PM_SLEEP_MODE == mode)
{
msgQ.type = WDA_ENTER_IMPS_REQ;
PELOG2(pmmLog (pMac, LOG2, FL("Sending WDA_ENTER_IMPS_REQ to HAL\n"));)
}
else
{
msgQ.type = WDA_EXIT_IMPS_REQ;
PELOG2(pmmLog (pMac, LOG2, FL("Sending WDA_EXIT_IMPS_REQ to HAL\n"));)
}
msgQ.reserved = 0;
msgQ.bodyptr = NULL;
msgQ.bodyval = 0;
/* we need to defer any incoming messages until we get a
* WDA_ENTER_IMPS_REQ or WDA_EXIT_IMPS_RSP from HAL.
*/
SET_LIM_PROCESS_DEFD_MESGS(pMac, false);
MTRACE(macTraceMsgTx(pMac, NO_SESSION, msgQ.type));
retStatus = wdaPostCtrlMsg(pMac, &msgQ);
if ( eSIR_SUCCESS != retStatus )
{
PELOGE(pmmLog(pMac, LOGE,
FL("WDA_ENTER/EXIT_IMPS_REQ to HAL failed, reason=%X\n"), retStatus);)
}
return retStatus;
}
// --------------------------------------------------------------------
/**
* pmmUapsdSendChangePwrSaveMsg
*
* FUNCTION:
* This function is called to send either WDA_ENTER_UAPSD_REQ
* or WDA_EXIT_UAPSD_REQ to HAL.
*
* NOTE:
*
* @param pMac Global handle to MAC
* @param mode mode to be configured
* @return tSirRetStatus
*/
tSirRetStatus pmmUapsdSendChangePwrSaveMsg (tpAniSirGlobal pMac, tANI_U8 mode)
{
tSirRetStatus retStatus = eSIR_SUCCESS;
tpUapsdParams pUapsdParams = NULL;
tANI_U8 uapsdDeliveryMask = 0;
tANI_U8 uapsdTriggerMask = 0;
tSirMsgQ msgQ;
tpPESession pSessionEntry;
tpExitUapsdParams pExitUapsdParams = NULL;
if((pSessionEntry = peGetValidPowerSaveSession(pMac)) == NULL )
{
PELOGW(pmmLog(pMac, LOGW, FL("pmmUapsd :palAllocateMemory() failed\n"));)
retStatus = eSIR_FAILURE;
return retStatus;
}
if (SIR_PM_SLEEP_MODE == mode)
{
if( eHAL_STATUS_SUCCESS != palAllocateMemory( pMac->hHdd, (void **)&pUapsdParams, sizeof(tUapsdParams)) )
{
PELOGW(pmmLog(pMac, LOGW, FL("pmmUapsd :palAllocateMemory() failed\n"));)
retStatus = eSIR_MEM_ALLOC_FAILED;
return retStatus;
}
palZeroMemory( pMac->hHdd, (tANI_U8 *)pUapsdParams, sizeof(tUapsdParams));
msgQ.type = WDA_ENTER_UAPSD_REQ;
msgQ.bodyptr = pUapsdParams;
uapsdDeliveryMask = (pMac->lim.gUapsdPerAcBitmask | pMac->lim.gUapsdPerAcDeliveryEnableMask);
uapsdTriggerMask = (pMac->lim.gUapsdPerAcBitmask | pMac->lim.gUapsdPerAcTriggerEnableMask);
pUapsdParams->bkDeliveryEnabled = LIM_UAPSD_GET(ACBK, uapsdDeliveryMask);
pUapsdParams->beDeliveryEnabled = LIM_UAPSD_GET(ACBE, uapsdDeliveryMask);
pUapsdParams->viDeliveryEnabled = LIM_UAPSD_GET(ACVI, uapsdDeliveryMask);
pUapsdParams->voDeliveryEnabled = LIM_UAPSD_GET(ACVO, uapsdDeliveryMask);
pUapsdParams->bkTriggerEnabled = LIM_UAPSD_GET(ACBK, uapsdTriggerMask);
pUapsdParams->beTriggerEnabled = LIM_UAPSD_GET(ACBE, uapsdTriggerMask);
pUapsdParams->viTriggerEnabled = LIM_UAPSD_GET(ACVI, uapsdTriggerMask);
pUapsdParams->voTriggerEnabled = LIM_UAPSD_GET(ACVO, uapsdTriggerMask);
pUapsdParams->bssIdx = pSessionEntry->bssIdx;
PELOGE(pmmLog(pMac, LOGE,
FL("UAPSD Mask: static = 0x%x, DeliveryEnabled = 0x%x, TriggerEnabled = 0x%x \n"),
pMac->lim.gUapsdPerAcBitmask,
pMac->lim.gUapsdPerAcDeliveryEnableMask,
pMac->lim.gUapsdPerAcTriggerEnableMask);)
PELOG1(pmmLog(pMac, LOG1, FL("Delivery Enabled: BK=%d, BE=%d, Vi=%d, Vo=%d \n"),
pUapsdParams->bkDeliveryEnabled,
pUapsdParams->beDeliveryEnabled,
pUapsdParams->viDeliveryEnabled,
pUapsdParams->voDeliveryEnabled);)
PELOG1(pmmLog(pMac, LOG1, FL("Trigger Enabled: BK=%d, BE=%d, Vi=%d, Vo=%d \n"),
pUapsdParams->bkTriggerEnabled,
pUapsdParams->beTriggerEnabled,
pUapsdParams->viTriggerEnabled,
pUapsdParams->voTriggerEnabled);)
PELOGW(pmmLog (pMac, LOGW, FL("pmmUapsd: Sending WDA_ENTER_UAPSD_REQ to HAL\n"));)
}
else
{
if( eHAL_STATUS_SUCCESS != palAllocateMemory( pMac->hHdd, (void **)&pExitUapsdParams, sizeof(tExitUapsdParams)) )
{
PELOGW(pmmLog(pMac, LOGW, FL("pmmUapsd :palAllocateMemory() failed\n"));)
retStatus = eSIR_MEM_ALLOC_FAILED;
return retStatus;
}
palZeroMemory( pMac->hHdd, (tANI_U8 *)pExitUapsdParams, sizeof(tExitUapsdParams));
msgQ.type = WDA_EXIT_UAPSD_REQ;
msgQ.bodyptr = pExitUapsdParams;
pExitUapsdParams->bssIdx = pSessionEntry->bssIdx;
PELOGW(pmmLog (pMac, LOGW, FL("pmmUapsd: Sending WDA_EXIT_UAPSD_REQ to HAL\n"));)
}
/* we need to defer any incoming messages until we get a
* WDA_ENTER/EXIT_UAPSD_RSP from HAL.
*/
SET_LIM_PROCESS_DEFD_MESGS(pMac, false);
msgQ.reserved = 0;
msgQ.bodyval = 0;
MTRACE(macTraceMsgTx(pMac, NO_SESSION, msgQ.type));
retStatus = wdaPostCtrlMsg(pMac, &msgQ);
if ( eSIR_SUCCESS != retStatus )
{
PELOGE(pmmLog(pMac, LOGE,
FL("pmmUapsd: WDA_ENTER/EXIT_UAPSD_REQ to HAL failed, reason=%X\n"),
retStatus);)
if (SIR_PM_SLEEP_MODE == mode)
palFreeMemory(pMac->hHdd, (tANI_U8*)pUapsdParams);
else
palFreeMemory(pMac->hHdd, (tANI_U8*)pExitUapsdParams);
}
return retStatus;
}
// --------------------------------------------------------------------
/**
* pmmUpdateImpsPwrSaveStats
*
* FUNCTION:
* This function is called to update the power save statistics in MAC
* for Idle mode power save
*
* LOGIC:
*
* ASSUMPTIONS:
* None
*
* NOTE:
*
* @param Global handle to MAC
* @return None
*/
void pmmImpsUpdatePwrSaveStats(tpAniSirGlobal pMac)
{
/*
tANI_U64 TimeAwake = 0;
pMac->pmm.ImpsSleepTimeStamp = vos_timer_get_system_ticks();
if (pMac->pmm.ImpsWakeupTimeStamp)
{
TimeAwake = (pMac->pmm.ImpsSleepTimeStamp - pMac->pmm.ImpsWakeupTimeStamp) / 10 ;
}
else
{
TimeAwake = 0;
}
if (TimeAwake > pMac->pmm.ImpsMaxTimeAwake)
{
pMac->pmm.ImpsMaxTimeAwake = TimeAwake;
}
if ((!pMac->pmm.ImpsMinTimeAwake) || (TimeAwake < pMac->pmm.ImpsMinTimeAwake))
{
pMac->pmm.ImpsMinTimeAwake = TimeAwake;
}
pMac->pmm.ImpsAvgTimeAwake = ((pMac->pmm.ImpsAvgTimeAwake * pMac->pmm.ImpsCntSleep) + TimeAwake) / (pMac->pmm.ImpsCntSleep + 1);
(pMac->pmm.ImpsCntSleep)++;
return;
*/
}
// --------------------------------------------------------------------
/**
* pmmImpsUpdateWakeupStats
*
* FUNCTION:
* This function is called to update the Wake up statistics in MAC
* for Idle mode power save
*
* LOGIC:
*
* ASSUMPTIONS:
* None
*
* NOTE:
*
* @param Global handle to MAC
* @return None
*/
void pmmImpsUpdateWakeupStats (tpAniSirGlobal pMac)
{
/*
tANI_U64 SleepTime = 0;
pMac->pmm.ImpsWakeupTimeStamp = vos_timer_get_system_ticks();
SleepTime = (pMac->pmm.ImpsWakeupTimeStamp - pMac->pmm.ImpsSleepTimeStamp) / 10;
if (SleepTime > pMac->pmm.ImpsMaxSleepTime)
{
pMac->pmm.ImpsMaxSleepTime = SleepTime;
}
if ((!pMac->pmm.ImpsMinSleepTime) || (SleepTime < pMac->pmm.ImpsMinSleepTime))
{
pMac->pmm.ImpsMinSleepTime = SleepTime;
}
pMac->pmm.ImpsAvgSleepTime = ( ( (pMac->pmm.ImpsAvgSleepTime * pMac->pmm.ImpsCntAwake) + SleepTime) / (pMac->pmm.ImpsCntAwake + 1));
(pMac->pmm.ImpsCntAwake)++;
return;
*/
}
// Collects number of times error occurred while going to sleep mode
void pmmImpsUpdateSleepErrStats(tpAniSirGlobal pMac,
tSirRetStatus retStatus)
{
pMac->pmm.ImpsSleepErrCnt++;
pMac->pmm.ImpsLastErr = retStatus;
return;
}
// Collects number of times error occurred while waking up from sleep mode
void pmmImpsUpdateWakeupErrStats(tpAniSirGlobal pMac,
tSirRetStatus retStatus)
{
pMac->pmm.ImpsWakeupErrCnt++;
pMac->pmm.ImpsLastErr = retStatus;
return;
}
// Collects number of times the system has received request or
// response in an invalid state
void pmmImpsUpdateErrStateStats(tpAniSirGlobal pMac)
{
pMac->pmm.ImpsInvalidStateCnt++;
return;
}
// Collects number of packets dropped while in IMPS mode
void pmmImpsUpdatePktDropStats(tpAniSirGlobal pMac)
{
pMac->pmm.ImpsPktDrpInSleepMode++;
return;
}
// Collects number of packets dropped while in BMPS mode
void pmmBmpsUpdatePktDropStats(tpAniSirGlobal pMac)
{
pMac->pmm.BmpsPktDrpInSleepMode++;
return;
}
// Collects statistics for number of times BMPS init failed
void pmmBmpsUpdateInitFailureCnt(tpAniSirGlobal pMac)
{
pMac->pmm.BmpsInitFailCnt++;
return;
}
// Collects statistics for number of times sleep request failed
void pmmBmpsUpdateSleepReqFailureCnt(tpAniSirGlobal pMac)
{
pMac->pmm.BmpsSleeReqFailCnt++;
return;
}
// Collects statistics for number of times Wakeup request failed
void pmmBmpsUpdateWakeupReqFailureCnt(tpAniSirGlobal pMac)
{
pMac->pmm.BmpsWakeupReqFailCnt++;
return;
}
// Collects statistics for number of times request / response received in invalid state
void pmmBmpsUpdateInvalidStateCnt(tpAniSirGlobal pMac)
{
pMac->pmm.BmpsInvStateCnt++;
return;
}
// Collects statistics for number of times wakeup indications received
void pmmBmpsUpdateWakeupIndCnt(tpAniSirGlobal pMac)
{
pMac->pmm.BmpsWakeupIndCnt++;
return;
}
// Collects statistics for number of times wakeup indications received
void pmmBmpsUpdateHalReqFailureCnt(tpAniSirGlobal pMac)
{
pMac->pmm.BmpsHalReqFailCnt++;
return;
}
// Collects statistics for number of times requests received from HDD in
// invalid device role
void pmmBmpsUpdateReqInInvalidRoleCnt(tpAniSirGlobal pMac)
{
pMac->pmm.BmpsReqInInvalidRoleCnt++;
return;
}
#if 0
// Update the sleep statistics
void pmmUpdateDroppedPktStats(tpAniSirGlobal pMac)
{
switch (pMac->pmm.gPmmState)
{
case ePMM_STATE_BMPS_SLEEP:
pmmBmpsUpdatePktDropStats(pMac);
break;
case ePMM_STATE_IMPS_SLEEP:
pmmImpsUpdatePktDropStats(pMac);
break;
default:
break;
}
return;
}
#endif
// Resets PMM state ePMM_STATE_READY
void pmmResetPmmState(tpAniSirGlobal pMac)
{
pMac->pmm.gPmmState = ePMM_STATE_READY;
pMac->pmm.inMissedBeaconScenario = FALSE;
return;
}
/* Sends Background scan message back to Lim */
void pmmSendMessageToLim(tpAniSirGlobal pMac,
tANI_U32 msgId)
{
tSirMsgQ limMsg;
tANI_U32 statusCode;
limMsg.type = (tANI_U16) msgId;
limMsg.bodyptr = NULL;
limMsg.bodyval = 0;
if ((statusCode = limPostMsgApi(pMac, &limMsg)) != eSIR_SUCCESS)
{
PELOGW(pmmLog(pMac, LOGW,
FL("posting message %X to LIM failed, reason=%d\n"),
limMsg.type, statusCode);)
}
}
#ifdef WLAN_FEATURE_PACKET_FILTERING
void pmmFilterMatchCountResponseHandler(tpAniSirGlobal pMac, tpSirMsgQ limMsg)
{
tpSirRcvFltPktMatchRsp pRcvFltPktMatchCntRsp;
eHalStatus rspStatus;
tSirResultCodes smeRspCode = eSIR_SME_SUCCESS;
/* we need to process all the deferred messages enqueued
* since the initiating the WDA_PACKET_COALESCING_FILTER_MATCH_COUNT_REQ.
*/
SET_LIM_PROCESS_DEFD_MESGS(pMac, true);
pRcvFltPktMatchCntRsp = (tpSirRcvFltPktMatchRsp)(limMsg->bodyptr);
if (NULL == pRcvFltPktMatchCntRsp)
{
pmmLog(pMac, LOGE, FL("Received "
"WDA_PACKET_COALESCING_FILTER_MATCH_COUNT_RSP with NULL msg "));
smeRspCode = eSIR_SME_PC_FILTER_MATCH_COUNT_REQ_FAILED;
}
else
{
rspStatus = pRcvFltPktMatchCntRsp->status;
if (eHAL_STATUS_SUCCESS == rspStatus)
{
pmmLog(pMac, LOGE, FL("Rcv successful response from HAL to get "
"Packet Coalescing Filter Match Count\n"));
}
else
{
pmmLog(pMac, LOGE, FL("HAL failed to get Packet Coalescing "
"Filter Match Count, informing SME\n"));
smeRspCode = eSIR_SME_PC_FILTER_MATCH_COUNT_REQ_FAILED;
}
}
limSendSmeRsp(pMac, eWNI_PMC_PACKET_COALESCING_FILTER_MATCH_COUNT_RSP,
smeRspCode, 0, 0);
return;
}
#endif // WLAN_FEATURE_PACKET_FILTERING
#ifdef WLAN_FEATURE_GTK_OFFLOAD
void pmmGTKOffloadGetInfoResponseHandler(tpAniSirGlobal pMac, tpSirMsgQ limMsg)
{
tpSirGtkOffloadGetInfoRspParams pGtkOffloadGetInfoRspParams;
eHalStatus rspStatus;
tSirResultCodes smeRspCode = eSIR_SME_SUCCESS;
/* we need to process all the deferred messages enqueued
* since the initiating the WDA_GTK_OFFLOAD_GETINFO_REQ.
*/
SET_LIM_PROCESS_DEFD_MESGS(pMac, true);
pGtkOffloadGetInfoRspParams = (tpSirGtkOffloadGetInfoRspParams)(limMsg->bodyptr);
if (NULL == pGtkOffloadGetInfoRspParams)
{
pmmLog(pMac, LOGE, FL("Received WDA_GTK_OFFLOAD_GETINFO_RSP with NULL msg "));
smeRspCode = eSIR_SME_GTK_OFFLOAD_GETINFO_REQ_FAILED;
}
else
{
rspStatus = pGtkOffloadGetInfoRspParams->ulStatus;
if(rspStatus == eHAL_STATUS_SUCCESS)
{
pmmLog(pMac, LOGW, FL("Rcv successful response from HAL to get GTK Offload Information\n"));
}
else
{
pmmLog(pMac, LOGE, FL("HAL failed to get GTK Offload Information, informing SME\n"));
smeRspCode = eSIR_SME_GTK_OFFLOAD_GETINFO_REQ_FAILED;
}
}
limSendSmeRsp(pMac, eWNI_PMC_GTK_OFFLOAD_GETINFO_RSP, smeRspCode, 0, 0);
return;
}
#endif // WLAN_FEATURE_GTK_OFFLOAD