blob: 64be51893e3715606dac4505dbd37fafbbf3a952 [file] [log] [blame]
/*
* Copyright (c) 2012-2017 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.
*/
/*
* This file was originally distributed by Qualcomm Atheros, Inc.
* under proprietary terms before Copyright ownership was assigned
* to the Linux Foundation.
*/
/**=========================================================================
EDIT HISTORY FOR FILE
This section contains comments describing changes made to the module.
Notice that changes are listed in reverse chronological order.
$Header:$ $DateTime: $ $Author: $
when who what, where, why
-------- --- --------------------------------------------------------
03/29/11 tbh Created module.
==========================================================================*/
/*----------------------------------------------------------------------------
* Include Files
* -------------------------------------------------------------------------*/
#include <wlan_hdd_dev_pwr.h>
#include <wcnss_api.h>
/*----------------------------------------------------------------------------
* Preprocessor Definitions and Constants
* -------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------
* Type Declarations
* -------------------------------------------------------------------------*/
/*-------------------------------------------------------------------------
* Global variables.
*-------------------------------------------------------------------------*/
/*-------------------------------------------------------------------------
* Local variables.
*-------------------------------------------------------------------------*/
/* Reference VoIP, 100msec delay make disconnect.
* So TX sleep must be less than 100msec
* Every 20msec TX frame will goes out.
* 10 frame means 2seconds TX operation */
static const hdd_tmLevelAction_t thermalMigrationAction[WLAN_HDD_TM_LEVEL_MAX] =
{
/* TM Level 0, Do nothing, just normal operation */
{1, 0, 0, 0, 0xFFFFF},
/* Tm Level 1, disable TX AMPDU */
{0, 0, 0, 0, 0xFFFFF},
/* TM Level 2, disable AMDPU,
* TX sleep 100msec if TX frame count is larger than 16 during 300msec */
{0, 0, 100, 300, 16},
/* TM Level 3, disable AMDPU,
* TX sleep 500msec if TX frame count is larger than 11 during 500msec */
{0, 0, 500, 500, 11},
/* TM Level 4, MAX TM level, enter IMPS */
{0, 1, 1000, 500, 10}
};
#ifdef HAVE_WCNSS_SUSPEND_RESUME_NOTIFY
static bool suspend_notify_sent;
#endif
#ifdef FEATURE_WLAN_DIAG_SUPPORT
/**
* hdd_wlan_suspend_resume_event()- send suspend/resume state
* @state: suspend/resume state
*
* This Function send send suspend resume state diag event
*
* Return: void.
*/
void hdd_wlan_suspend_resume_event(uint8_t state)
{
WLAN_VOS_DIAG_EVENT_DEF(suspend_state, struct vos_event_suspend);
vos_mem_zero(&suspend_state, sizeof(suspend_state));
suspend_state.state = state;
WLAN_VOS_DIAG_EVENT_REPORT(&suspend_state, EVENT_WLAN_SUSPEND_RESUME);
}
#endif
/*----------------------------------------------------------------------------
@brief TX frame block timeout handler
Resume TX, and reset TX frame count
@param hdd_context_t pHddCtx
Global hdd context
@return NONE
----------------------------------------------------------------------------*/
void hddDevTmTxBlockTimeoutHandler(void *usrData)
{
hdd_context_t *pHddCtx = (hdd_context_t *)usrData;
hdd_adapter_t *staAdapater;
/* Sanity, This should not happen */
if(NULL == pHddCtx)
{
VOS_TRACE(VOS_MODULE_ID_HDD,VOS_TRACE_LEVEL_ERROR,
"%s: NULL Context", __func__);
VOS_ASSERT(0);
return;
}
staAdapater = hdd_get_adapter(pHddCtx, WLAN_HDD_INFRA_STATION);
if ((NULL == staAdapater) ||
(WLAN_HDD_ADAPTER_MAGIC != staAdapater->magic)) {
VOS_TRACE(VOS_MODULE_ID_HDD,VOS_TRACE_LEVEL_ERROR,
FL("invalid Adapter %pK"), staAdapater);
VOS_ASSERT(0);
return;
}
if(mutex_lock_interruptible(&pHddCtx->tmInfo.tmOperationLock))
{
VOS_TRACE(VOS_MODULE_ID_HDD,VOS_TRACE_LEVEL_ERROR,
"%s: Acquire lock fail", __func__);
return;
}
pHddCtx->tmInfo.txFrameCount = 0;
/* Resume TX flow */
hddLog(LOG1, FL("Enabling queues"));
wlan_hdd_netif_queue_control(staAdapater,
WLAN_WAKE_ALL_NETIF_QUEUE,
WLAN_CONTROL_PATH);
pHddCtx->tmInfo.qBlocked = VOS_FALSE;
mutex_unlock(&pHddCtx->tmInfo.tmOperationLock);
return;
}
/*----------------------------------------------------------------------------
@brief Register function
Register Thermal Mitigation Level Changed handle callback function
@param hdd_context_t pHddCtx
Global hdd context
@return General status code
VOS_STATUS_SUCCESS Registration Success
VOS_STATUS_E_FAILURE Registration Fail
----------------------------------------------------------------------------*/
VOS_STATUS hddDevTmRegisterNotifyCallback(hdd_context_t *pHddCtx)
{
VOS_TRACE(VOS_MODULE_ID_HDD,VOS_TRACE_LEVEL_INFO,
"%s: Register TM Handler", __func__);
wcnss_register_thermal_mitigation(pHddCtx->parent_dev ,hddDevTmLevelChangedHandler);
/* Set Default TM Level as Lowest, do nothing */
pHddCtx->tmInfo.currentTmLevel = WLAN_HDD_TM_LEVEL_0;
vos_mem_zero(&pHddCtx->tmInfo.tmAction, sizeof(hdd_tmLevelAction_t));
vos_timer_init(&pHddCtx->tmInfo.txSleepTimer,
VOS_TIMER_TYPE_SW,
hddDevTmTxBlockTimeoutHandler,
(void *)pHddCtx);
mutex_init(&pHddCtx->tmInfo.tmOperationLock);
pHddCtx->tmInfo.txFrameCount = 0;
pHddCtx->tmInfo.blockedQueue = NULL;
pHddCtx->tmInfo.qBlocked = VOS_FALSE;
return VOS_STATUS_SUCCESS;
}
/*----------------------------------------------------------------------------
@brief Un-Register function
Un-Register Thermal Mitigation Level Changed handle callback function
@param hdd_context_t pHddCtx
Global hdd context
@return General status code
VOS_STATUS_SUCCESS Un-Registration Success
VOS_STATUS_E_FAILURE Un-Registration Fail
----------------------------------------------------------------------------*/
VOS_STATUS hddDevTmUnregisterNotifyCallback(hdd_context_t *pHddCtx)
{
VOS_STATUS vosStatus = VOS_STATUS_SUCCESS;
wcnss_unregister_thermal_mitigation(hddDevTmLevelChangedHandler);
if(VOS_TIMER_STATE_RUNNING ==
vos_timer_getCurrentState(&pHddCtx->tmInfo.txSleepTimer))
{
vosStatus = vos_timer_stop(&pHddCtx->tmInfo.txSleepTimer);
if(!VOS_IS_STATUS_SUCCESS(vosStatus))
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"%s: Timer stop fail", __func__);
}
}
// Destroy the vos timer...
vosStatus = vos_timer_destroy(&pHddCtx->tmInfo.txSleepTimer);
if (!VOS_IS_STATUS_SUCCESS(vosStatus))
{
VOS_TRACE(VOS_MODULE_ID_HDD,VOS_TRACE_LEVEL_ERROR,
"%s: Fail to destroy timer", __func__);
}
return VOS_STATUS_SUCCESS;
}