wlan: Add SNR monitoring support
Add support to retrieve SNR from the received frame
and return it to the user space.
CRs-Fixed: 529156
Change-Id: Ic63c41e6bc2d9402dc42554e96637dd829a59a53
diff --git a/CORE/HDD/inc/wlan_hdd_cfg.h b/CORE/HDD/inc/wlan_hdd_cfg.h
index ebe4dd5..bb2449b 100644
--- a/CORE/HDD/inc/wlan_hdd_cfg.h
+++ b/CORE/HDD/inc/wlan_hdd_cfg.h
@@ -1808,6 +1808,10 @@
#define CFG_ANTENNA_DIVERSITY_PARAM_MAX ( 3 )
#define CFG_ANTENNA_DIVERSITY_PARAM_DEFAULT ( 0 )
+#define CFG_ENABLE_SNR_MONITORING_NAME "gEnableSNRMonitoring"
+#define CFG_ENABLE_SNR_MONITORING_MIN ( 0 )
+#define CFG_ENABLE_SNR_MONITORING_MAX ( 1 )
+#define CFG_ENABLE_SNR_MONITORING_DEFAULT ( 0 )
/*---------------------------------------------------------------------------
Type declarations
-------------------------------------------------------------------------*/
@@ -2189,6 +2193,7 @@
v_U8_t flexConnectPowerFactor;
v_BOOL_t enableIbssHeartBeatOffload;
v_U32_t antennaDiversity;
+ v_BOOL_t fEnableSNRMonitoring;
} hdd_config_t;
/*---------------------------------------------------------------------------
Function declarations and documenation
diff --git a/CORE/HDD/inc/wlan_hdd_main.h b/CORE/HDD/inc/wlan_hdd_main.h
index 88a7e41..a533b29 100644
--- a/CORE/HDD/inc/wlan_hdd_main.h
+++ b/CORE/HDD/inc/wlan_hdd_main.h
@@ -800,6 +800,9 @@
#endif
v_S7_t rssi;
+
+ tANI_U8 snr;
+
struct work_struct monTxWorkQueue;
struct sk_buff *skb_to_tx;
@@ -818,6 +821,7 @@
//Magic cookie for adapter sanity verification
v_U32_t magic;
v_BOOL_t higherDtimTransition;
+ v_BOOL_t survey_idx;
};
#define WLAN_HDD_GET_STATION_CTX_PTR(pAdapter) (&(pAdapter)->sessionCtx.station)
diff --git a/CORE/HDD/inc/wlan_hdd_wext.h b/CORE/HDD/inc/wlan_hdd_wext.h
index 07135f8..6d2e266 100644
--- a/CORE/HDD/inc/wlan_hdd_wext.h
+++ b/CORE/HDD/inc/wlan_hdd_wext.h
@@ -413,6 +413,8 @@
VOS_STATUS wlan_hdd_get_rssi(hdd_adapter_t *pAdapter, v_S7_t *rssi_value);
+VOS_STATUS wlan_hdd_get_snr(hdd_adapter_t *pAdapter, v_S7_t *snr);
+
void hdd_wmm_tx_snapshot(hdd_adapter_t *pAdapter);
#ifdef FEATURE_WLAN_TDLS
diff --git a/CORE/HDD/src/wlan_hdd_cfg.c b/CORE/HDD/src/wlan_hdd_cfg.c
index 26de48d..5212cd3 100644
--- a/CORE/HDD/src/wlan_hdd_cfg.c
+++ b/CORE/HDD/src/wlan_hdd_cfg.c
@@ -2362,6 +2362,14 @@
CFG_ANTENNA_DIVERSITY_PARAM_DEFAULT,
CFG_ANTENNA_DIVERSITY_PARAM_MIN,
CFG_ANTENNA_DIVERSITY_PARAM_MAX),
+
+ REG_VARIABLE( CFG_ENABLE_SNR_MONITORING_NAME, WLAN_PARAM_Integer,
+ hdd_config_t, fEnableSNRMonitoring,
+ VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK ,
+ CFG_ENABLE_SNR_MONITORING_DEFAULT,
+ CFG_ENABLE_SNR_MONITORING_MIN,
+ CFG_ENABLE_SNR_MONITORING_MAX),
+
};
/*
diff --git a/CORE/HDD/src/wlan_hdd_cfg80211.c b/CORE/HDD/src/wlan_hdd_cfg80211.c
index 9c05427..45a5875 100644
--- a/CORE/HDD/src/wlan_hdd_cfg80211.c
+++ b/CORE/HDD/src/wlan_hdd_cfg80211.c
@@ -8236,6 +8236,107 @@
}
#endif /* CONFIG_NL80211_TESTMODE */
+static int wlan_hdd_cfg80211_dump_survey(struct wiphy *wiphy,
+ struct net_device *dev,
+ int idx, struct survey_info *survey)
+{
+ hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
+ hdd_context_t *pHddCtx;
+ tHalHandle halHandle;
+ v_U32_t channel, freq;
+ v_S7_t snr,rssi;
+ int status, i, j, filled = 0;
+
+ ENTER();
+
+
+ if (NULL == pAdapter)
+ {
+ VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
+ "%s: HDD adapter is Null", __func__);
+ return -ENODEV;
+ }
+
+ if (NULL == wiphy)
+ {
+ VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
+ "%s: wiphy is Null", __func__);
+ return -ENODEV;
+ }
+
+ pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
+ status = wlan_hdd_validate_context(pHddCtx);
+
+ if (0 != status)
+ {
+ VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+ "%s: HDD context is not valid", __func__);
+ return status;
+ }
+
+ if (0 == pHddCtx->cfg_ini->fEnableSNRMonitoring ||
+ 0 != pAdapter->survey_idx)
+ {
+ /* The survey dump ops when implemented completely is expected to
+ * return a survey of all channels and the ops is called by the
+ * kernel with incremental values of the argument 'idx' till it
+ * returns -ENONET. But we can only support the survey for the
+ * operating channel for now. survey_idx is used to track
+ * that the ops is called only once and then return -ENONET for
+ * the next iteration
+ */
+ pAdapter->survey_idx = 0;
+ return -ENONET;
+ }
+
+ halHandle = WLAN_HDD_GET_HAL_CTX(pAdapter);
+
+ wlan_hdd_get_snr(pAdapter, &snr);
+ wlan_hdd_get_rssi(pAdapter, &rssi);
+
+ sme_GetOperationChannel(halHandle, &channel, pAdapter->sessionId);
+ hdd_wlan_get_freq(channel, &freq);
+
+
+ for (i = 0; i < IEEE80211_NUM_BANDS; i++)
+ {
+ if (NULL == wiphy->bands[i])
+ {
+ VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_INFO,
+ "%s: wiphy->bands[i] is NULL, i = %d", __func__, i);
+ continue;
+ }
+
+ for (j = 0; j < wiphy->bands[i]->n_channels; j++)
+ {
+ struct ieee80211_supported_band *band = wiphy->bands[i];
+
+ if (band->channels[j].center_freq == (v_U16_t)freq)
+ {
+ survey->channel = &band->channels[j];
+ /* The Rx BDs contain SNR values in dB for the received frames
+ * while the supplicant expects noise. So we calculate and
+ * return the value of noise (dBm)
+ * SNR (dB) = RSSI (dBm) - NOISE (dBm)
+ */
+ survey->noise = rssi - snr;
+ survey->filled = SURVEY_INFO_NOISE_DBM;
+ filled = 1;
+ }
+ }
+ }
+
+ if (filled)
+ pAdapter->survey_idx = 1;
+ else
+ {
+ pAdapter->survey_idx = 0;
+ return -ENONET;
+ }
+
+ return 0;
+}
+
/* cfg80211_ops */
static struct cfg80211_ops wlan_hdd_cfg80211_ops =
{
@@ -8303,5 +8404,6 @@
#ifdef WLAN_NL80211_TESTMODE
.testmode_cmd = wlan_hdd_cfg80211_testmode,
#endif
+ .dump_survey = wlan_hdd_cfg80211_dump_survey,
};
diff --git a/CORE/HDD/src/wlan_hdd_main.c b/CORE/HDD/src/wlan_hdd_main.c
index b868e32..fd7e923 100644
--- a/CORE/HDD/src/wlan_hdd_main.c
+++ b/CORE/HDD/src/wlan_hdd_main.c
@@ -5577,6 +5577,21 @@
pHddCtx->cfg_ini->nBandCapability = 1;
}
}
+
+ /* If SNR Monitoring is enabled, FW has to parse all beacons
+ * for calcaluting and storing the average SNR, so set Nth beacon
+ * filter to 1 to enable FW to parse all the beaocons
+ */
+ if (1 == pHddCtx->cfg_ini->fEnableSNRMonitoring)
+ {
+ /* The log level is deliberately set to WARN as overriding
+ * nthBeaconFilter to 1 will increase power cosumption and this
+ * might just prove helpful to detect the power issue.
+ */
+ hddLog(VOS_TRACE_LEVEL_WARN,
+ "%s: Setting pHddCtx->cfg_ini->nthBeaconFilter = 1", __func__);
+ pHddCtx->cfg_ini->nthBeaconFilter = 1;
+ }
/*
* cfg80211: Initialization and registration ...
*/
diff --git a/CORE/HDD/src/wlan_hdd_wext.c b/CORE/HDD/src/wlan_hdd_wext.c
index b50c0d3..55b2c35 100644
--- a/CORE/HDD/src/wlan_hdd_wext.c
+++ b/CORE/HDD/src/wlan_hdd_wext.c
@@ -140,7 +140,8 @@
#define STATS_CONTEXT_MAGIC 0x53544154 //STAT
#define RSSI_CONTEXT_MAGIC 0x52535349 //RSSI
-#define POWER_CONTEXT_MAGIC 0x504F5752 // POWR
+#define POWER_CONTEXT_MAGIC 0x504F5752 //POWR
+#define SNR_CONTEXT_MAGIC 0x534E5200 //SNR
/* To Validate Channel against the Frequency and Vice-Versa */
static const hdd_freq_chan_map_t freq_chan_map[] = { {2412, 1}, {2417, 2},
@@ -613,6 +614,57 @@
complete(&pStatsContext->completion);
}
+static void hdd_GetSnrCB(tANI_S8 snr, tANI_U32 staId, void *pContext)
+{
+ struct statsContext *pStatsContext;
+ hdd_adapter_t *pAdapter;
+
+ if (ioctl_debug)
+ {
+ pr_info("%s: snr [%d] STA [%d] pContext [%p]\n",
+ __func__, (int)snr, (int)staId, pContext);
+ }
+
+ if (NULL == pContext)
+ {
+ hddLog(VOS_TRACE_LEVEL_ERROR,
+ "%s: Bad param, pContext [%p]",
+ __func__, pContext);
+ return;
+ }
+
+ /* there is a race condition that exists between this callback function
+ * and the caller since the caller could time out either before or
+ * while this code is executing. we'll assume the timeout hasn't
+ * occurred, but we'll verify that right before we save our work
+ */
+
+ pStatsContext = pContext;
+ pAdapter = pStatsContext->pAdapter;
+ if ((NULL == pAdapter) || (SNR_CONTEXT_MAGIC != pStatsContext->magic))
+ {
+ /* the caller presumably timed out so there is nothing we can do */
+ hddLog(VOS_TRACE_LEVEL_WARN,
+ "%s: Invalid context, pAdapter [%p] magic [%08x]",
+ __func__, pAdapter, pStatsContext->magic);
+ if (ioctl_debug)
+ {
+ pr_info("%s: Invalid context, pAdapter [%p] magic [%08x]\n",
+ __func__, pAdapter, pStatsContext->magic);
+ }
+ return;
+ }
+
+ /* the race is on. caller could have timed out immediately after
+ * we verified the magic, but if so, caller will wait a short time
+ * for us to copy over the snr
+ */
+ pAdapter->snr = snr;
+
+ /* and notify the caller */
+ complete(&pStatsContext->completion);
+}
+
VOS_STATUS wlan_hdd_get_rssi(hdd_adapter_t *pAdapter, v_S7_t *rssi_value)
{
struct statsContext context;
@@ -680,6 +732,81 @@
return VOS_STATUS_SUCCESS;
}
+VOS_STATUS wlan_hdd_get_snr(hdd_adapter_t *pAdapter, v_S7_t *snr)
+{
+ struct statsContext context;
+ hdd_context_t *pHddCtx;
+ hdd_station_ctx_t *pHddStaCtx;
+ eHalStatus hstatus;
+ long lrc;
+ int valid;
+
+ if (NULL == pAdapter)
+ {
+ hddLog(VOS_TRACE_LEVEL_ERROR,
+ "%s: Invalid context, pAdapter", __func__);
+ return VOS_STATUS_E_FAULT;
+ }
+
+ pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
+
+ valid = wlan_hdd_validate_context(pHddCtx);
+ if (0 != valid)
+ {
+ hddLog(VOS_TRACE_LEVEL_ERROR, FL("HDD context is not valid"));
+ return VOS_STATUS_E_FAULT;
+ }
+
+ pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
+ if (NULL == pHddStaCtx)
+ {
+ hddLog(VOS_TRACE_LEVEL_ERROR, FL("HDD STA context is not valid"));
+ return VOS_STATUS_E_FAULT;
+ }
+
+ init_completion(&context.completion);
+ context.pAdapter = pAdapter;
+ context.magic = SNR_CONTEXT_MAGIC;
+
+ hstatus = sme_GetSnr(pHddCtx->hHal, hdd_GetSnrCB,
+ pHddStaCtx->conn_info.staId[ 0 ],
+ pHddStaCtx->conn_info.bssId,
+ &context);
+ if (eHAL_STATUS_SUCCESS != hstatus)
+ {
+ hddLog(VOS_TRACE_LEVEL_ERROR,"%s: Unable to retrieve RSSI",
+ __func__);
+ /* we'll returned a cached value below */
+ }
+ else
+ {
+ /* request was sent -- wait for the response */
+ lrc = wait_for_completion_interruptible_timeout(&context.completion,
+ msecs_to_jiffies(WLAN_WAIT_TIME_STATS));
+ /* either we have a response or we timed out
+ * either way, first invalidate our magic
+ */
+ context.magic = 0;
+ if (lrc <= 0)
+ {
+ hddLog(VOS_TRACE_LEVEL_ERROR,"%s: SME %s while retrieving SNR ",
+ __func__, (0 == lrc) ? "timeout" : "interrupt");
+ /* there is a race condition such that the callback
+ * function could be executing at the same time we are. Of
+ * primary concern is if the callback function had already
+ * verified the "magic" but hasn't yet set the completion
+ * variable. Since the completion variable is on our
+ * stack, we'll delay just a bit to make sure the data is
+ * still valid if that is the case
+ */
+ msleep(50);
+ /* we'll now returned a cached value below */
+ }
+ }
+ *snr = pAdapter->snr;
+
+ return VOS_STATUS_SUCCESS;
+}
#if defined WLAN_FEATURE_VOWIFI_11R || defined FEATURE_WLAN_CCX || defined(FEATURE_WLAN_LFR)
static void hdd_GetRoamRssiCB( v_S7_t rssi, tANI_U32 staId, void *pContext )
diff --git a/CORE/MAC/inc/sirApi.h b/CORE/MAC/inc/sirApi.h
index d144631..967ba30 100644
--- a/CORE/MAC/inc/sirApi.h
+++ b/CORE/MAC/inc/sirApi.h
@@ -2104,6 +2104,17 @@
} tAniGetRssiReq, *tpAniGetRssiReq;
+typedef struct sAniGetSnrReq
+{
+ // Common for all types are requests
+ tANI_U16 msgType; // message type is same as the request type
+ tANI_U16 msgLen; // length of the entire request
+ tANI_U8 sessionId;
+ tANI_U8 staId;
+ void *snrCallback;
+ void *pDevContext; //device context
+} tAniGetSnrReq, *tpAniGetSnrReq;
+
#if defined WLAN_FEATURE_VOWIFI_11R || defined FEATURE_WLAN_CCX || defined(FEATURE_WLAN_LFR)
typedef struct sAniGetRoamRssiRsp
{
diff --git a/CORE/MAC/inc/wniApi.h b/CORE/MAC/inc/wniApi.h
index 65aa11d..4c4a709 100644
--- a/CORE/MAC/inc/wniApi.h
+++ b/CORE/MAC/inc/wniApi.h
@@ -246,6 +246,7 @@
eWNI_SME_UPDATE_NOA,
eWNI_SME_CLEAR_DFS_CHANNEL_LIST,
eWNI_SME_PRE_CHANNEL_SWITCH_FULL_POWER,
+ eWNI_SME_GET_SNR_REQ,
//General Power Save Messages
eWNI_PMC_MSG_TYPES_BEGIN,
eWNI_PMC_PWR_SAVE_CFG,
diff --git a/CORE/SME/inc/csrApi.h b/CORE/SME/inc/csrApi.h
index b9d7614..89851c2 100644
--- a/CORE/SME/inc/csrApi.h
+++ b/CORE/SME/inc/csrApi.h
@@ -1533,6 +1533,17 @@
typedef void ( *tCsrRssiCallback) (v_S7_t rssi, tANI_U32 staId, void *pContext);
+/*---------------------------------------------------------------------------
+ This is the type for a snr callback to be registered with SME
+ for getting snr
+
+ \param snr
+ \param pContext - any user data given at callback registration.
+ \return None
+
+---------------------------------------------------------------------------*/
+typedef void (*tCsrSnrCallback) (v_S7_t snr, tANI_U32 staId, void *pContext);
+
#ifdef WLAN_FEATURE_VOWIFI_11R
eHalStatus csrRoamIssueFTPreauthReq(tHalHandle hHal, tANI_U32 sessionId, tpSirBssDescription pBssDescription);
#endif
diff --git a/CORE/SME/inc/csrInternal.h b/CORE/SME/inc/csrInternal.h
index 1eb601f..1d3f7c0 100644
--- a/CORE/SME/inc/csrInternal.h
+++ b/CORE/SME/inc/csrInternal.h
@@ -1223,6 +1223,22 @@
tANI_U16 csrGetTLSTAState(tpAniSirGlobal pMac, tANI_U8 staId);
eHalStatus csrGetRssi(tpAniSirGlobal pMac,tCsrRssiCallback callback,tANI_U8 staId,tCsrBssid bssId,void * pContext,void * pVosContext);
+
+/* ---------------------------------------------------------------------------
+ \fn csrGetSnr
+ \brief csr function that client calls to register a callback to get
+ SNR stored in TL
+
+ \param callback - SME sends back the requested stats using the callback
+ \param staId - The station ID for which the stats is requested for
+ \param bssid - The bssid for the connected session
+ \param pContext - user context to be passed back along with the callback
+
+ \return eHalStatus
+ ---------------------------------------------------------------------------*/
+eHalStatus csrGetSnr(tpAniSirGlobal pMac, tCsrSnrCallback callback,
+ tANI_U8 staId, tCsrBssid bssId, void *pContext);
+
#if defined WLAN_FEATURE_VOWIFI_11R || defined FEATURE_WLAN_CCX || defined(FEATURE_WLAN_LFR)
eHalStatus csrGetRoamRssi(tpAniSirGlobal pMac,
tCsrRssiCallback callback,
diff --git a/CORE/SME/inc/sme_Api.h b/CORE/SME/inc/sme_Api.h
index 778dcc5..3ee6608 100644
--- a/CORE/SME/inc/sme_Api.h
+++ b/CORE/SME/inc/sme_Api.h
@@ -791,6 +791,21 @@
eHalStatus sme_GetRssi(tHalHandle hHal,
tCsrRssiCallback callback,
tANI_U8 staId, tCsrBssid bssId, void *pContext, void* pVosContext);
+
+/* ---------------------------------------------------------------------------
+ \fn sme_GetSnr
+ \brief a wrapper function that client calls to register a callback to get
+ SNR from FW
+
+ \param callback - SME sends back the requested stats using the callback
+ \param staId - The station ID for which the stats is requested for
+ \param bssid - The bssid of the connected session
+ \param pContext - user context to be passed back along with the callback
+ ---------------------------------------------------------------------------*/
+eHalStatus sme_GetSnr(tHalHandle hHal,
+ tCsrSnrCallback callback,
+ tANI_U8 staId, tCsrBssid bssId,
+ void *pContext);
#if defined WLAN_FEATURE_VOWIFI_11R || defined FEATURE_WLAN_CCX || defined(FEATURE_WLAN_LFR)
eHalStatus sme_GetRoamRssi(tHalHandle hHal,
tCsrRssiCallback callback,
diff --git a/CORE/SME/src/csr/csrApiRoam.c b/CORE/SME/src/csr/csrApiRoam.c
index d63d910..680d409 100644
--- a/CORE/SME/src/csr/csrApiRoam.c
+++ b/CORE/SME/src/csr/csrApiRoam.c
@@ -8673,6 +8673,38 @@
}
return;
}
+
+static void csrUpdateSnr(tpAniSirGlobal pMac, void* pMsg)
+{
+ tANI_S8 snr = 0;
+ tAniGetSnrReq *pGetSnrReq = (tAniGetSnrReq*)pMsg;
+
+ if (pGetSnrReq)
+ {
+ if (VOS_STATUS_SUCCESS !=
+ WDA_GetSnr(pGetSnrReq->staId, &snr))
+ {
+ smsLog(pMac, LOGE, FL("Error in WLANTL_GetSnr"));
+ return;
+ }
+
+ if (pGetSnrReq->snrCallback)
+ {
+ ((tCsrSnrCallback)(pGetSnrReq->snrCallback))(snr, pGetSnrReq->staId,
+ pGetSnrReq->pDevContext);
+ }
+ else
+ {
+ smsLog(pMac, LOGE, FL("pGetSnrReq->snrCallback is NULL"));
+ return;
+ }
+ }
+ else
+ {
+ smsLog(pMac, LOGE, FL("pGetSnrReq is NULL"));
+ }
+ return;
+}
#if defined WLAN_FEATURE_VOWIFI_11R || defined FEATURE_WLAN_CCX || defined(FEATURE_WLAN_LFR)
void csrRoamRssiRspProcessor(tpAniSirGlobal pMac, void* pMsg)
{
@@ -9632,6 +9664,11 @@
csrUpdateRssi( pMac, pSirMsg );
break;
+ case eWNI_SME_GET_SNR_REQ:
+ smsLog( pMac, LOG2, FL("GetSnrReq from self"));
+ csrUpdateSnr(pMac, pSirMsg);
+ break;
+
#ifdef WLAN_FEATURE_VOWIFI_11R
case eWNI_SME_FT_PRE_AUTH_RSP:
csrRoamFTPreAuthRspProcessor( pMac, (tpSirFTPreAuthRsp)pSirMsg );
@@ -13992,8 +14029,8 @@
tANI_U8 *pStats = NULL;
tANI_U32 length = 0;
v_PVOID_t pvosGCtx;
- v_S7_t rssi = 0;
- tANI_U32 *pRssi = NULL;
+ v_S7_t rssi = 0, snr = 0;
+ tANI_U32 *pRssi = NULL, *pSnr = NULL;
tANI_U32 linkCapacity;
pSmeStatsRsp = (tAniGetPEStatsRsp *)pSirMsg;
if(pSmeStatsRsp->rc)
@@ -14106,6 +14143,8 @@
if (length != 0)
{
linkCapacity = *(tANI_U32*)pStats;
+ pStats += sizeof(tANI_U32);
+ length -= sizeof(tANI_U32);
}
else
{
@@ -14113,6 +14152,18 @@
}
WDA_UpdateLinkCapacity(pvosGCtx, pSmeStatsRsp->staId, linkCapacity);
+
+ if (length != 0)
+ {
+ pSnr = (tANI_U32*)pStats;
+ snr = (v_S7_t)*pSnr;
+ }
+ else
+ {
+ snr = SNR_HACK_BMPS;
+ }
+
+ WDA_UpdateSnrBmps(pvosGCtx, pSmeStatsRsp->staId, snr);
post_update:
//make sure to update the pe stats req list
pEntry = csrRoamFindInPeStatsReqList(pMac, pSmeStatsRsp->statsMask);
@@ -14431,6 +14482,49 @@
return status;
}
+eHalStatus csrGetSnr(tpAniSirGlobal pMac,
+ tCsrSnrCallback callback,
+ tANI_U8 staId, tCsrBssid bssId,
+ void *pContext)
+{
+ eHalStatus status = eHAL_STATUS_SUCCESS;
+ vos_msg_t msg;
+ tANI_U32 sessionId;
+
+ tAniGetSnrReq *pMsg;
+
+ smsLog(pMac, LOG2, FL("called"));
+
+ pMsg =(tAniGetSnrReq *)vos_mem_malloc(sizeof(tAniGetSnrReq));
+ if (NULL == pMsg )
+ {
+ smsLog(pMac, LOGE, "%s: failed to allocate mem for req",__func__);
+ return status;
+ }
+
+ csrRoamGetSessionIdFromBSSID(pMac, (tCsrBssid *)bssId, &sessionId);
+
+ pMsg->msgType = pal_cpu_to_be16((tANI_U16)eWNI_SME_GET_SNR_REQ);
+ pMsg->msgLen = (tANI_U16)sizeof(tAniGetSnrReq);
+ pMsg->sessionId = sessionId;
+ pMsg->staId = staId;
+ pMsg->snrCallback = callback;
+ pMsg->pDevContext = pContext;
+ msg.type = eWNI_SME_GET_SNR_REQ;
+ msg.bodyptr = pMsg;
+ msg.reserved = 0;
+
+ if (VOS_STATUS_SUCCESS != vos_mq_post_message(VOS_MQ_ID_SME, &msg))
+ {
+ smsLog(pMac, LOGE, "%s failed to post msg to self", __func__);
+ vos_mem_free((v_VOID_t *)pMsg);
+ status = eHAL_STATUS_FAILURE;
+ }
+
+ smsLog(pMac, LOG2, FL("returned"));
+ return status;
+}
+
#if defined WLAN_FEATURE_VOWIFI_11R || defined FEATURE_WLAN_CCX || defined(FEATURE_WLAN_LFR)
eHalStatus csrGetRoamRssi(tpAniSirGlobal pMac,
tCsrRssiCallback callback,
diff --git a/CORE/SME/src/sme_common/sme_Api.c b/CORE/SME/src/sme_common/sme_Api.c
index f09f7f6..eddbc74 100644
--- a/CORE/SME/src/sme_common/sme_Api.c
+++ b/CORE/SME/src/sme_common/sme_Api.c
@@ -3989,6 +3989,35 @@
}
return (status);
}
+
+/* ---------------------------------------------------------------------------
+ \fn sme_GetSnr
+ \brief a wrapper function that client calls to register a callback to
+ get SNR
+
+ \param callback - SME sends back the requested stats using the callback
+ \param staId - The station ID for which the stats is requested for
+ \param pContext - user context to be passed back along with the callback
+ \param pVosContext - vos context
+ \return eHalStatus
+ ---------------------------------------------------------------------------*/
+eHalStatus sme_GetSnr(tHalHandle hHal,
+ tCsrSnrCallback callback,
+ tANI_U8 staId, tCsrBssid bssId,
+ void *pContext)
+{
+ eHalStatus status = eHAL_STATUS_FAILURE;
+ tpAniSirGlobal pMac = PMAC_STRUCT( hHal );
+
+ status = sme_AcquireGlobalLock( &pMac->sme );
+ if ( HAL_STATUS_SUCCESS( status ) )
+ {
+ status = csrGetSnr(pMac, callback,
+ staId, bssId, pContext);
+ sme_ReleaseGlobalLock( &pMac->sme );
+ }
+ return status;
+}
#if defined WLAN_FEATURE_VOWIFI_11R || defined FEATURE_WLAN_CCX || defined(FEATURE_WLAN_LFR)
/* ---------------------------------------------------------------------------
\fn sme_GetRoamRssi
diff --git a/CORE/SYS/legacy/src/utils/src/macTrace.c b/CORE/SYS/legacy/src/utils/src/macTrace.c
index 4e4679a..394ebe1 100644
--- a/CORE/SYS/legacy/src/utils/src/macTrace.c
+++ b/CORE/SYS/legacy/src/utils/src/macTrace.c
@@ -462,6 +462,7 @@
CASE_RETURN_STRING(eWNI_SME_UPDATE_NOA);
CASE_RETURN_STRING(eWNI_SME_CLEAR_DFS_CHANNEL_LIST);
CASE_RETURN_STRING(eWNI_SME_PRE_CHANNEL_SWITCH_FULL_POWER);
+ CASE_RETURN_STRING(eWNI_SME_GET_SNR_REQ);
CASE_RETURN_STRING(eWNI_PMC_MSG_TYPES_BEGIN);
//General Power Save Messages
diff --git a/CORE/TL/inc/wlan_qct_tl.h b/CORE/TL/inc/wlan_qct_tl.h
index 8d4197c..98b009f 100644
--- a/CORE/TL/inc/wlan_qct_tl.h
+++ b/CORE/TL/inc/wlan_qct_tl.h
@@ -156,6 +156,9 @@
#define WLANTL_HO_DEFAULT_ALPHA 5
#define WLANTL_HO_TDLS_ALPHA 7
+// Choose the largest possible value that can be accomodates in 8 bit signed
+// variable.
+#define SNR_HACK_BMPS (127)
/*--------------------------------------------------------------------------
Access category enum used by TL
- order must be kept as these values are used to setup the AC mask
@@ -1431,6 +1434,51 @@
/*==========================================================================
+ FUNCTION WLANTL_GetSnr
+
+ DESCRIPTION
+ TL will extract the SNR information from every data packet from the
+ ongoing traffic and will store it. It will provide the result to SME
+ upon request.
+
+ DEPENDENCIES
+
+ WARNING: the read and write of this value will not be protected
+ by locks, therefore the information obtained after a read
+ might not always be consistent.
+
+ PARAMETERS
+
+ IN
+ pvosGCtx: pointer to the global vos context; a handle to TL's
+ or SME's control block can be extracted from its context
+ ucSTAId: station identifier for the requested value
+
+ OUT
+ puSnr: the average value of the SNR
+
+
+ RETURN VALUE
+ The result code associated with performing the operation
+
+ VOS_STATUS_E_INVAL: Input parameters are invalid
+ VOS_STATUS_E_FAULT: Station ID is outside array boundaries or pointer
+ to TL cb is NULL ; access would cause a page fault
+ VOS_STATUS_E_EXISTS: STA was not yet registered
+ VOS_STATUS_SUCCESS: Everything is good :)
+
+ SIDE EFFECTS
+
+============================================================================*/
+VOS_STATUS
+WLANTL_GetSnr
+(
+ tANI_U8 ucSTAId,
+ tANI_S8* pSnr
+);
+
+/*==========================================================================
+
FUNCTION WLANTL_GetLinkQuality
DESCRIPTION
@@ -2536,6 +2584,26 @@
void WLANTL_UpdateRssiBmps(v_PVOID_t pvosGCtx, v_U8_t staId, v_S7_t rssi);
+/*===============================================================================
+ FUNCTION WLANTL_UpdateSnrBmps
+
+ DESCRIPTION This function updates the TL's SNR (in BMPS mode)
+
+ DEPENDENCIES None
+
+ PARAMETERS
+
+ pvosGCtx VOS context VOS Global context
+ staId Station ID Station ID
+ snr SNR (BMPS mode) SNR in BMPS mode
+
+ RETURN None
+
+ SIDE EFFECTS none
+ ===============================================================================*/
+
+void WLANTL_UpdateSnrBmps(v_PVOID_t pvosGCtx, v_U8_t staId, v_S7_t snr);
+
/*==========================================================================
FUNCTION WLANTL_SetTxXmitPending
diff --git a/CORE/TL/src/wlan_qct_tl.c b/CORE/TL/src/wlan_qct_tl.c
index d695bfa..53930e7 100644
--- a/CORE/TL/src/wlan_qct_tl.c
+++ b/CORE/TL/src/wlan_qct_tl.c
@@ -178,6 +178,7 @@
/*BT-AMP packet LLC OUI value*/
const v_U8_t WLANTL_BT_AMP_OUI[] = {0x00, 0x19, 0x58 };
+#define WLANTL_MAX_SNR_DATA_SAMPLES 20
#ifdef VOLANS_PERF
#define WLANTL_BD_PDU_INTERRUPT_ENABLE_THRESHOLD 120
@@ -2591,6 +2592,142 @@
/*==========================================================================
+ FUNCTION WLANTL_GetSnr
+
+ DESCRIPTION
+ TL will extract the SNR information from every data packet from the
+ ongoing traffic and will store it. It will provide the result to SME
+ upon request.
+
+ DEPENDENCIES
+
+ WARNING: the read and write of this value will not be protected
+ by locks, therefore the information obtained after a read
+ might not always be consistent.
+
+ PARAMETERS
+
+ IN
+ pvosGCtx: pointer to the global vos context; a handle to TL's
+ or SME's control block can be extracted from its context
+ ucSTAId: station identifier for the requested value
+
+ OUT
+ pSnr: the average value of the SNR
+
+
+ RETURN VALUE
+ The result code associated with performing the operation
+
+ VOS_STATUS_E_INVAL: Input parameters are invalid
+ VOS_STATUS_E_FAULT: Station ID is outside array boundaries or pointer
+ to TL cb is NULL ; access would cause a page fault
+ VOS_STATUS_E_EXISTS: STA was not yet registered
+ VOS_STATUS_SUCCESS: Everything is good :)
+
+ SIDE EFFECTS
+
+============================================================================*/
+VOS_STATUS
+WLANTL_GetSnr
+(
+ tANI_U8 ucSTAId,
+ tANI_S8* pSnr
+)
+{
+ WLANTL_CbType* pTLCb = NULL;
+ WLANTL_STAClientType* pClientSTA = NULL;
+ /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
+
+ /*------------------------------------------------------------------------
+ Sanity check
+ ------------------------------------------------------------------------*/
+ if (NULL == pSnr)
+ {
+ TLLOGE(VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
+ "WLAN TL:Invalid parameter sent on %s", __func__));
+ return VOS_STATUS_E_INVAL;
+ }
+
+ if (WLANTL_STA_ID_INVALID(ucSTAId))
+ {
+ TLLOGE(VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
+ "WLAN TL:Invalid station id requested on %s", __func__));
+ return VOS_STATUS_E_FAULT;
+ }
+
+ /*------------------------------------------------------------------------
+ Extract TL control block and check existance
+ ------------------------------------------------------------------------*/
+ pTLCb = VOS_GET_TL_CB(vos_get_global_context(VOS_MODULE_ID_TL, NULL));
+ if (NULL == pTLCb)
+ {
+ TLLOGE(VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
+ "WLAN TL:Invalid TL pointer from pvosGCtx on %s", __func__));
+ return VOS_STATUS_E_FAULT;
+ }
+
+ pClientSTA = pTLCb->atlSTAClients[ucSTAId];
+
+ if (NULL == pClientSTA)
+ {
+ TLLOGE(VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
+ "WLAN TL:Client Memory was not allocated on %s", __func__));
+ return VOS_STATUS_E_FAILURE;
+ }
+
+ if (0 == pClientSTA->ucExists)
+ {
+ TLLOGE(VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
+ "WLAN TL:Station was not previously registered on %s", __func__));
+ return VOS_STATUS_E_EXISTS;
+ }
+
+ /*------------------------------------------------------------------------
+ Copy will not be locked; please read restriction
+ ------------------------------------------------------------------------*/
+ if (pTLCb->isBMPS)
+ {
+ *pSnr = pClientSTA->snrAvgBmps;
+ }
+ else
+ {
+ /* SNR is averaged over WLANTL_MAX_SNR_DATA_SAMPLES, if there are not enough
+ * data samples (snridx) to calculate the average then return the
+ * average for the window of prevoius 20 packets. And if there aren't
+ * enough samples and the average for previous window of 20 packets is
+ * not available then return a predefined value
+ *
+ * NOTE: the SNR_HACK_BMPS value is defined to 127, documents from HW
+ * team reveal that the SNR value has a ceiling well below 127 dBm,
+ * so if SNR has value of 127 the userspace applications can know that
+ * the SNR has not been computed yet because enough data was not
+ * available for SNR calculation
+ */
+ if (pClientSTA->snrIdx > (WLANTL_MAX_SNR_DATA_SAMPLES/2)
+ || !(pClientSTA->prevSnrAvg))
+ {
+ *pSnr = pClientSTA->snrSum / pClientSTA->snrIdx;
+ }
+ else if (pClientSTA->prevSnrAvg)
+ {
+ *pSnr = pClientSTA->prevSnrAvg;
+ }
+ else
+ {
+ *pSnr = SNR_HACK_BMPS;
+ }
+ }
+
+ VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO_HIGH,
+ "WLAN TL:WLANTL_GetSnr for STA: %d SNR: %d%s",
+ ucSTAId, *pSnr,
+ pTLCb->isBMPS ? " in BMPS" : "");
+
+ return VOS_STATUS_SUCCESS;
+}/* WLANTL_GetSnr */
+/*==========================================================================
+
FUNCTION WLANTL_GetLinkQuality
DESCRIPTION
@@ -5471,19 +5608,27 @@
#else
vosStatus = WLANTL_ReadRSSI(pvosGCtx, pvBDHeader, ucSTAId);
#endif
+ if (!VOS_IS_STATUS_SUCCESS(vosStatus))
+ {
+ TLLOGW(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_WARN,
+ "Handle RX Management Frame fail within Handoff "
+ "support module"));
+ /* Do Not Drop packet at here
+ * Revisit why HO module return fail
+ * vos_pkt_return_packet(vosTempBuff);
+ * vosTempBuff = vosDataBuff;
+ * continue;
+ */
+ }
+ vosStatus = WLANTL_ReadSNR(pvosGCtx, pvBDHeader, ucSTAId);
+
+ if (!VOS_IS_STATUS_SUCCESS(vosStatus))
+ {
+ TLLOGW(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_WARN,
+ FL("Failed to Read SNR")));
+ }
}
- if(!VOS_IS_STATUS_SUCCESS(vosStatus))
- {
- TLLOGW(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_WARN,
- "Handle RX Management Frame fail within Handoff support module"));
- /* Do Not Drop packet at here
- * Revisit why HO module return fail
- vos_pkt_return_packet(vosTempBuff);
- vosTempBuff = vosDataBuff;
- continue;
- */
- }
pTLCb->tlMgmtFrmClient.pfnTlMgmtFrmRx( pvosGCtx, vosTempBuff);
}
else /* Data Frame */
@@ -5692,17 +5837,25 @@
#else
vosStatus = WLANTL_ReadRSSI(pvosGCtx, pvBDHeader, ucSTAId);
#endif /*FEATURE_WLAN_GEN6_ROAMING*/
- if(!VOS_IS_STATUS_SUCCESS(vosStatus))
+ if (!VOS_IS_STATUS_SUCCESS(vosStatus))
{
TLLOGW(VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_WARN,
"Handle RX Data Frame fail within Handoff support module"));
/* Do Not Drop packet at here
* Revisit why HO module return fail
- vos_pkt_return_packet(vosTempBuff);
- vosTempBuff = vosDataBuff;
- continue;
+ * vos_pkt_return_packet(vosTempBuff);
+ * vosTempBuff = vosDataBuff;
+ * continue;
*/
}
+ vosStatus = WLANTL_ReadSNR(pvosGCtx, pvBDHeader, ucSTAId);
+
+ if (!VOS_IS_STATUS_SUCCESS(vosStatus))
+ {
+ TLLOGW(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_WARN,
+ FL("Failed to Read SNR")));
+ }
+
pfnSTAFsm( pvosGCtx, ucSTAId, &vosTempBuff);
}
else
@@ -11503,6 +11656,74 @@
return VOS_STATUS_SUCCESS;
}
+/*==========================================================================
+
+ FUNCTION
+
+ DESCRIPTION Read SNR value out of a RX BD
+
+ PARAMETERS: Caller must validate all parameters
+
+ RETURN VALUE
+
+============================================================================*/
+VOS_STATUS WLANTL_ReadSNR
+(
+ v_PVOID_t pAdapter,
+ v_PVOID_t pBDHeader,
+ v_U8_t STAid
+)
+{
+ WLANTL_CbType *tlCtxt = VOS_GET_TL_CB(pAdapter);
+ v_S7_t currentSNR;
+
+
+ if (NULL == tlCtxt)
+ {
+ TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
+ "%s Invalid TL handle", __func__));
+ return VOS_STATUS_E_INVAL;
+ }
+
+ if (NULL == tlCtxt->atlSTAClients[STAid])
+ {
+ TLLOGE(VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
+ "WLAN TL:Client Memory was not allocated on %s", __func__));
+ return VOS_STATUS_E_FAILURE;
+ }
+
+ currentSNR = WLANTL_GETSNR(pBDHeader);
+
+ TLLOG2(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO_HIGH,
+ "%s: snrsum: %d snridx: %d prevsnravg: %d",
+ __func__,
+ tlCtxt->atlSTAClients[STAid]->snrSum,
+ tlCtxt->atlSTAClients[STAid]->snrIdx,
+ tlCtxt->atlSTAClients[STAid]->prevSnrAvg));
+
+ /* The SNR returned for all purposes is the average SNR over
+ * WLANTL_MAX_SNR_DATA_SMAPLES.When data samples
+ * > WLANTL_MAX_SNR_DATA_SAMPLES are obtained,
+ * store the average of the samples in prevSnrAvg
+ * and start a new averaging window. The prevSnrAvg is used when
+ * enough data samples are not available when applications
+ * actually query for SNR.
+ *
+ * SEE: WLANTL_GetSnr()
+ */
+ if (tlCtxt->atlSTAClients[STAid]->snrIdx >= WLANTL_MAX_SNR_DATA_SAMPLES)
+ {
+ tlCtxt->atlSTAClients[STAid]->prevSnrAvg =
+ tlCtxt->atlSTAClients[STAid]->snrSum /
+ tlCtxt->atlSTAClients[STAid]->snrIdx;
+ tlCtxt->atlSTAClients[STAid]->snrSum = 0;
+ tlCtxt->atlSTAClients[STAid]->snrIdx = 0;
+ }
+ tlCtxt->atlSTAClients[STAid]->snrSum += currentSNR;
+ tlCtxt->atlSTAClients[STAid]->snrIdx += 1;
+
+ return VOS_STATUS_SUCCESS;
+}
/*
DESCRIPTION
@@ -12048,6 +12269,34 @@
}
/*===============================================================================
+ FUNCTION WLANTL_UpdateSnrBmps
+
+ DESCRIPTION This function updates the TL's SNR (in BMPS mode)
+
+ DEPENDENCIES None
+
+ PARAMETERS
+
+ pvosGCtx VOS context VOS Global context
+ staId Station ID Station ID
+ snr SNR (BMPS mode) SNR in BMPS mode
+
+ RETURN None
+
+ SIDE EFFECTS none
+ ===============================================================================*/
+
+void WLANTL_UpdateSnrBmps(v_PVOID_t pvosGCtx, v_U8_t staId, v_S7_t snr)
+{
+ WLANTL_CbType* pTLCb = VOS_GET_TL_CB(pvosGCtx);
+
+ if (NULL != pTLCb && NULL != pTLCb->atlSTAClients[staId])
+ {
+ pTLCb->atlSTAClients[staId]->snrAvgBmps = snr;
+ }
+}
+
+/*===============================================================================
FUNCTION WLANTL_UpdateLinkCapacity
DESCRIPTION This function updates the STA's Link Capacity in TL
diff --git a/CORE/TL/src/wlan_qct_tli.h b/CORE/TL/src/wlan_qct_tli.h
index adf841a..fb4630c 100644
--- a/CORE/TL/src/wlan_qct_tli.h
+++ b/CORE/TL/src/wlan_qct_tli.h
@@ -247,6 +247,8 @@
/*get RSSI1 from a RX BD*/
#define WLANTL_GETRSSI1(pBD) (WDA_GETRSSI1(pBD) - WLAN_TL_RSSI_CORRECTION)
+#define WLANTL_GETSNR(pBD) WDA_GET_RX_SNR(pBD)
+
/* Check whether Rx frame is LS or EAPOL packet (other than data) */
#define WLANTL_BAP_IS_NON_DATA_PKT_TYPE(usType) \
((WLANTL_BT_AMP_TYPE_AR == usType) || (WLANTL_BT_AMP_TYPE_SEC == usType) || \
@@ -515,6 +517,18 @@
/* Value of the averaged RSSI for this station */
v_U32_t uLinkQualityAvg;
+ /* Sum of SNR for snrIdx number of consecutive frames */
+ v_U32_t snrSum;
+
+ /* Number of consecutive frames over which snrSum is calculated */
+ v_S7_t snrIdx;
+
+ /* Average SNR of previous 20 frames */
+ v_S7_t prevSnrAvg;
+
+ /* Average SNR returned by fw */
+ v_S7_t snrAvgBmps;
+
/* Tx packet count per station per TID */
v_U32_t auTxCount[WLAN_MAX_TID];
@@ -1619,6 +1633,23 @@
v_U8_t STAid
);
+/*==========================================================================
+
+ FUNCTION
+
+ DESCRIPTION Read SNR value out of a RX BD
+
+ PARAMETERS: Caller must validate all parameters
+
+ RETURN VALUE
+
+============================================================================*/
+VOS_STATUS WLANTL_ReadSNR
+(
+ v_PVOID_t pAdapter,
+ v_PVOID_t pBDHeader,
+ v_U8_t STAid
+);
void WLANTL_PowerStateChangedCB
diff --git a/CORE/WDA/inc/wlan_qct_wda.h b/CORE/WDA/inc/wlan_qct_wda.h
index 72d458a..6c15759 100644
--- a/CORE/WDA/inc/wlan_qct_wda.h
+++ b/CORE/WDA/inc/wlan_qct_wda.h
@@ -1148,6 +1148,12 @@
#define WDA_UpdateRssiBmps(pvosGCtx, staId, rssi) \
WLANTL_UpdateRssiBmps(pvosGCtx, staId, rssi)
+#define WDA_UpdateSnrBmps(pvosGCtx, staId, rssi) \
+ WLANTL_UpdateSnrBmps(pvosGCtx, staId, snr)
+
+#define WDA_GetSnr(staId, snr) \
+ WLANTL_GetSnr(staId, snr)
+
#define WDA_UpdateLinkCapacity(pvosGCtx, staId, linkCapacity) \
WLANTL_UpdateLinkCapacity(pvosGCtx, staId, linkCapacity)