diff --git a/core/hdd/inc/wlan_hdd_main.h b/core/hdd/inc/wlan_hdd_main.h index 4063495fdc64..d2cda7cfe414 100644 --- a/core/hdd/inc/wlan_hdd_main.h +++ b/core/hdd/inc/wlan_hdd_main.h @@ -401,6 +401,7 @@ typedef struct hdd_stats_s { tCsrGlobalClassCStatsInfo ClassC_stat; tCsrGlobalClassDStatsInfo ClassD_stat; tCsrPerStaStatsInfo perStaStats; + struct csr_per_chain_rssi_stats_info per_chain_rssi_stats; hdd_tx_rx_stats_t hddTxRxStats; #ifdef WLAN_FEATURE_11W hdd_pmf_stats_t hddPmfStats; diff --git a/core/hdd/src/wlan_hdd_cfg80211.c b/core/hdd/src/wlan_hdd_cfg80211.c index 991b36cecef3..8f1c09fa6ae7 100644 --- a/core/hdd/src/wlan_hdd_cfg80211.c +++ b/core/hdd/src/wlan_hdd_cfg80211.c @@ -14031,6 +14031,7 @@ static struct cfg80211_ops wlan_hdd_cfg80211_ops = { .mgmt_tx_cancel_wait = wlan_hdd_cfg80211_mgmt_tx_cancel_wait, .set_default_mgmt_key = wlan_hdd_set_default_mgmt_key, .set_txq_params = wlan_hdd_set_txq_params, + .dump_station = wlan_hdd_cfg80211_dump_station, .get_station = wlan_hdd_cfg80211_get_station, .set_power_mgmt = wlan_hdd_cfg80211_set_power_mgmt, .del_station = wlan_hdd_cfg80211_del_station, diff --git a/core/hdd/src/wlan_hdd_stats.c b/core/hdd/src/wlan_hdd_stats.c index ff7a538e5c3c..600545f5acbd 100644 --- a/core/hdd/src/wlan_hdd_stats.c +++ b/core/hdd/src/wlan_hdd_stats.c @@ -1650,6 +1650,9 @@ static int __wlan_hdd_cfg80211_get_station(struct wiphy *wiphy, int status, mode = 0, maxHtIdx; struct index_vht_data_rate_type *supported_vht_mcs_rate; struct index_data_rate_type *supported_mcs_rate; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) + bool rssi_stats_valid = false; +#endif uint32_t vht_mcs_map; enum eDataRate11ACMaxMcs vhtMaxMcs; @@ -2128,6 +2131,35 @@ static int __wlan_hdd_cfg80211_get_station(struct wiphy *wiphy, sinfo->txrate.mcs, sinfo->txrate.flags, sinfo->tx_packets, sinfo->rx_packets); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) + sinfo->signal_avg = WLAN_HDD_TGT_NOISE_FLOOR_DBM; + for (i = 0; i < NUM_CHAINS_MAX; i++) { + sinfo->chain_signal_avg[i] = + pAdapter->hdd_stats.per_chain_rssi_stats.rssi[i]; + sinfo->chains |= 1 << i; + if (sinfo->chain_signal_avg[i] > sinfo->signal_avg && + sinfo->chain_signal_avg[i] != 0) + sinfo->signal_avg = sinfo->chain_signal_avg[i]; + + hdd_info("RSSI for chain %d, vdev_id %d is %d", + i, pAdapter->sessionId, sinfo->chain_signal_avg[i]); + + if (!rssi_stats_valid && sinfo->chain_signal_avg[i]) + rssi_stats_valid = true; + } + + if (rssi_stats_valid) { +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0)) && !defined(WITH_BACKPORTS) + sinfo->filled |= STATION_INFO_CHAIN_SIGNAL_AVG; + sinfo->filled |= STATION_INFO_SIGNAL_AVG; +#else + sinfo->filled |= BIT(NL80211_STA_INFO_CHAIN_SIGNAL_AVG); + sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL_AVG); +#endif + } +#endif + + MTRACE(qdf_trace(QDF_MODULE_ID_HDD, TRACE_CODE_HDD_CFG80211_GET_STA, pAdapter->sessionId, maxRate)); @@ -2163,6 +2195,54 @@ int wlan_hdd_cfg80211_get_station(struct wiphy *wiphy, return ret; } +/** + * __wlan_hdd_cfg80211_dump_station() - dump station statistics + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @idx: variable to determine whether to get stats or not + * @mac: Pointer to mac + * @sinfo: Pointer to station info + * + * Return: 0 for success, non-zero for failure + */ +static int __wlan_hdd_cfg80211_dump_station(struct wiphy *wiphy, + struct net_device *dev, + int idx, u8 *mac, + struct station_info *sinfo) +{ + hdd_context_t *hdd_ctx = (hdd_context_t *) wiphy_priv(wiphy); + + hdd_debug("%s: idx %d", __func__, idx); + if (idx != 0) + return -ENOENT; + qdf_mem_copy(mac, hdd_ctx->config->intfMacAddr[0].bytes, + QDF_MAC_ADDR_SIZE); + return __wlan_hdd_cfg80211_get_station(wiphy, dev, mac, sinfo); +} + +/** + * wlan_hdd_cfg80211_dump_station() - dump station statistics + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @idx: variable to determine whether to get stats or not + * @mac: Pointer to mac + * @sinfo: Pointer to station info + * + * Return: 0 for success, non-zero for failure + */ +int wlan_hdd_cfg80211_dump_station(struct wiphy *wiphy, + struct net_device *dev, + int idx, u8 *mac, + struct station_info *sinfo) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_dump_station(wiphy, dev, idx, mac, sinfo); + cds_ssr_unprotect(__func__); + return ret; +} + /** * hdd_get_stats() - Function to retrieve interface statistics * @dev: pointer to network device diff --git a/core/hdd/src/wlan_hdd_stats.h b/core/hdd/src/wlan_hdd_stats.h index c33031ff11e4..a7f4e126f9c1 100644 --- a/core/hdd/src/wlan_hdd_stats.h +++ b/core/hdd/src/wlan_hdd_stats.h @@ -40,6 +40,8 @@ /* LL stats get request time out value */ #define WLAN_WAIT_TIME_LL_STATS 800 +#define WLAN_HDD_TGT_NOISE_FLOOR_DBM (-96) + /** * struct index_vht_data_rate_type - vht data rate type * @beacon_rate_index: Beacon rate index @@ -190,6 +192,21 @@ int wlan_hdd_cfg80211_get_station(struct wiphy *wiphy, struct station_info *sinfo); #endif +/** + * wlan_hdd_cfg80211_dump_station() - dump station statistics + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @idx: variable to determine whether to get stats or not + * @mac: Pointer to mac + * @sinfo: Pointer to station info + * + * Return: 0 for success, non-zero for failure + */ +int wlan_hdd_cfg80211_dump_station(struct wiphy *wiphy, + struct net_device *dev, + int idx, u8 *mac, + struct station_info *sinfo); + struct net_device_stats *hdd_get_stats(struct net_device *dev); int wlan_hdd_cfg80211_dump_survey(struct wiphy *wiphy, diff --git a/core/hdd/src/wlan_hdd_wext.c b/core/hdd/src/wlan_hdd_wext.c index 8d176a9ddb3d..6f6051d31f2d 100644 --- a/core/hdd/src/wlan_hdd_wext.c +++ b/core/hdd/src/wlan_hdd_wext.c @@ -3717,6 +3717,7 @@ static void hdd_get_station_statistics_cb(void *pStats, void *pContext) struct statsContext *pStatsContext; tCsrSummaryStatsInfo *pSummaryStats; tCsrGlobalClassAStatsInfo *pClassAStats; + struct csr_per_chain_rssi_stats_info *per_chain_rssi_stats; hdd_adapter_t *pAdapter; if (ioctl_debug) { @@ -3739,6 +3740,8 @@ static void hdd_get_station_statistics_cb(void *pStats, void *pContext) pSummaryStats = (tCsrSummaryStatsInfo *) pStats; pClassAStats = (tCsrGlobalClassAStatsInfo *) (pSummaryStats + 1); + per_chain_rssi_stats = (struct csr_per_chain_rssi_stats_info *) + (pClassAStats + 1); pStatsContext = pContext; pAdapter = pStatsContext->pAdapter; if ((NULL == pAdapter) || @@ -3764,6 +3767,7 @@ static void hdd_get_station_statistics_cb(void *pStats, void *pContext) /* copy over the stats. do so as a struct copy */ pAdapter->hdd_stats.summary_stat = *pSummaryStats; pAdapter->hdd_stats.ClassA_stat = *pClassAStats; + pAdapter->hdd_stats.per_chain_rssi_stats = *per_chain_rssi_stats; /* notify the caller */ complete(&pStatsContext->completion); @@ -3799,7 +3803,8 @@ QDF_STATUS wlan_hdd_get_station_stats(hdd_adapter_t *pAdapter) hstatus = sme_get_statistics(WLAN_HDD_GET_HAL_CTX(pAdapter), eCSR_HDD, SME_SUMMARY_STATS | - SME_GLOBAL_CLASSA_STATS, + SME_GLOBAL_CLASSA_STATS | + SME_PER_CHAIN_RSSI_STATS, hdd_get_station_statistics_cb, 0, /* not periodic */ false, /* non-cached results */ diff --git a/core/mac/inc/sir_api.h b/core/mac/inc/sir_api.h index c1fc594f55e9..de874747c7bd 100644 --- a/core/mac/inc/sir_api.h +++ b/core/mac/inc/sir_api.h @@ -109,6 +109,8 @@ typedef uint8_t tSirVersionString[SIR_VERSION_STRING_LEN]; #define MAX_POWER_DBG_ARGS_SUPPORTED 8 +#define NUM_CHAINS_MAX 2 + /** * enum sir_conn_update_reason: Reason for conc connection update * @SIR_UPDATE_REASON_SET_OPER_CHAN: Set probable operating channel diff --git a/core/sme/inc/csr_api.h b/core/sme/inc/csr_api.h index d032de0bd5df..4fc656726b43 100644 --- a/core/sme/inc/csr_api.h +++ b/core/sme/inc/csr_api.h @@ -1522,6 +1522,16 @@ typedef struct tagCsrPerStaStatsInfo { uint32_t tx_mpdu_in_ampdu_cnt; } tCsrPerStaStatsInfo; +/** + * struct csr_per_chain_rssi_stats_info - stores chain rssi + * @rssi: array containing rssi for all chains + * @peer_mac_addr: peer mac address + */ +struct csr_per_chain_rssi_stats_info { + int8_t rssi[NUM_CHAINS_MAX]; + tSirMacAddr peer_mac_addr; +}; + typedef struct tagCsrRoamSetKey { eCsrEncryptionType encType; tAniKeyDirection keyDirection; /* Tx, Rx or Tx-and-Rx */ diff --git a/core/sme/inc/csr_internal.h b/core/sme/inc/csr_internal.h index 57df53f2c282..8fe191bcec97 100644 --- a/core/sme/inc/csr_internal.h +++ b/core/sme/inc/csr_internal.h @@ -240,6 +240,7 @@ typedef enum { eCsrGlobalClassCStats, eCsrGlobalClassDStats, eCsrPerStaStats, + csr_per_chain_rssi_stats, eCsrMaxStats } eCsrRoamStatsClassTypes; @@ -1023,6 +1024,7 @@ typedef struct tagCsrRoamStruct { tCsrGlobalClassCStatsInfo classCStatsInfo; tCsrGlobalClassDStatsInfo classDStatsInfo; tCsrPerStaStatsInfo perStaStatsInfo[CSR_MAX_STA]; + struct csr_per_chain_rssi_stats_info per_chain_rssi_stats; tDblLinkList statsClientReqList; tDblLinkList peStatsReqList; tCsrTlStatsReqInfo tlStatsReqInfo; diff --git a/core/sme/inc/sme_api.h b/core/sme/inc/sme_api.h index db91ca7841d6..2514084508d1 100644 --- a/core/sme/inc/sme_api.h +++ b/core/sme/inc/sme_api.h @@ -60,6 +60,7 @@ #define SME_GLOBAL_CLASSC_STATS 8 #define SME_GLOBAL_CLASSD_STATS 16 #define SME_PER_STA_STATS 32 +#define SME_PER_CHAIN_RSSI_STATS 64 #define SME_SESSION_ID_ANY 50 diff --git a/core/sme/src/csr/csr_api_roam.c b/core/sme/src/csr/csr_api_roam.c index c804e5a71700..0086e0d2dba9 100644 --- a/core/sme/src/csr/csr_api_roam.c +++ b/core/sme/src/csr/csr_api_roam.c @@ -15986,6 +15986,14 @@ csr_update_stats(tpAniSirGlobal mac, uint8_t stats_type, *stats += sizeof(tCsrPerStaStatsInfo); *length -= sizeof(tCsrPerStaStatsInfo); break; + case csr_per_chain_rssi_stats: + sms_log(mac, LOG2, + FL("csrRoamStatsRspProcessor:Per Chain RSSI stats")); + qdf_mem_copy((uint8_t *)&mac->roam.per_chain_rssi_stats, + *stats, sizeof(struct csr_per_chain_rssi_stats_info)); + *stats += sizeof(struct csr_per_chain_rssi_stats_info); + *length -= sizeof(struct csr_per_chain_rssi_stats_info); + break; default: sms_log(mac, LOGW, FL("unknown stats type")); break; @@ -17754,6 +17762,14 @@ void csr_roam_report_statistics(tpAniSirGlobal pMac, uint32_t statsMask, sizeof(tCsrPerStaStatsInfo)); pStats += sizeof(tCsrPerStaStatsInfo); break; + case csr_per_chain_rssi_stats: + sms_log(pMac, LOG2, FL("Per Chain RSSI stats")); + qdf_mem_copy(pStats, + (uint8_t *)&pMac->roam.per_chain_rssi_stats, + sizeof(struct csr_per_chain_rssi_stats_info)); + pStats += sizeof( + struct csr_per_chain_rssi_stats_info); + break; default: sms_log(pMac, LOGE, FL("Unknown stats type and counter %d"), diff --git a/core/wma/inc/wma_internal.h b/core/wma/inc/wma_internal.h index b5fc9f4eae48..dadac756d645 100644 --- a/core/wma/inc/wma_internal.h +++ b/core/wma/inc/wma_internal.h @@ -55,12 +55,14 @@ #define FW_PDEV_STATS_SET 0x1 #define FW_VDEV_STATS_SET 0x2 #define FW_PEER_STATS_SET 0x4 -#define FW_STATS_SET 0x7 +#define FW_RSSI_PER_CHAIN_STATS_SET 0x8 +#define FW_STATS_SET 0xf /*AR9888/AR6320 noise floor approx value * similar to the mentioned the WMA */ #define WMA_TGT_NOISE_FLOOR_DBM (-96) +#define WMA_TGT_RSSI_INVALID 96 /* * Make sure that link monitor and keep alive diff --git a/core/wma/src/wma_utils.c b/core/wma/src/wma_utils.c index b8f35702a0fe..aa18f515acb5 100644 --- a/core/wma/src/wma_utils.c +++ b/core/wma/src/wma_utils.c @@ -1298,11 +1298,6 @@ static void wma_update_peer_stats(tp_wma_handle wma, node->rate_flags, node->nss, classa_stats->max_pwr); } - - if (node->fw_stats_set & FW_STATS_SET) { - WMA_LOGD("<--STATS RSP VDEV_ID:%d", vdev_id); - wma_post_stats(wma, node); - } } } @@ -1331,6 +1326,107 @@ void wma_post_link_status(tAniGetLinkStatus *pGetLinkStatus, } } +/** + * wma_update_per_chain_rssi_stats() - to store per chain rssi stats + * @wma: wma handle + * @rssi_stats: rssi stats + * @rssi_per_chain_stats: buffer where rssi stats to be stored + * + * This function stores per chain rssi stats received from fw for all vdevs for + * which the stats were requested into a csr stats structure. + * + * Return: void + */ +static void wma_update_per_chain_rssi_stats(tp_wma_handle wma, + wmi_rssi_stats *rssi_stats, + struct csr_per_chain_rssi_stats_info *rssi_per_chain_stats) +{ + int i; + int8_t bcn_snr, dat_snr; + + for (i = 0; i < NUM_CHAINS_MAX; i++) { + bcn_snr = rssi_stats->rssi_avg_beacon[i]; + dat_snr = rssi_stats->rssi_avg_data[i]; + WMA_LOGD("chain %d beacon snr %d data snr %d", + i, bcn_snr, dat_snr); + if (dat_snr != WMA_TGT_INVALID_SNR) + rssi_per_chain_stats->rssi[i] = dat_snr; + else if (bcn_snr != WMA_TGT_INVALID_SNR) + rssi_per_chain_stats->rssi[i] = bcn_snr; + else + /* + * Firmware sends invalid snr till it sees + * Beacon/Data after connection since after + * vdev up fw resets the snr to invalid. + * In this duartion Host will return an invalid rssi + * value. + */ + rssi_per_chain_stats->rssi[i] = WMA_TGT_RSSI_INVALID; + + /* + * Get the absolute rssi value from the current rssi value the + * sinr value is hardcoded into 0 in the qcacld-new/CORE stack + */ + rssi_per_chain_stats->rssi[i] += WMA_TGT_NOISE_FLOOR_DBM; + WMI_MAC_ADDR_TO_CHAR_ARRAY(&(rssi_stats->peer_macaddr), + rssi_per_chain_stats->peer_mac_addr); + } +} + +/** + * wma_update_rssi_stats() - to update rssi stats for all vdevs + * for which the stats were requested. + * @wma: wma handle + * @rssi_stats: rssi stats + * + * This function updates the rssi stats for all vdevs for which + * the stats were requested. + * + * Return: void + */ +static void wma_update_rssi_stats(tp_wma_handle wma, + wmi_rssi_stats *rssi_stats) +{ + tAniGetPEStatsRsp *stats_rsp_params; + struct csr_per_chain_rssi_stats_info *rssi_per_chain_stats = NULL; + struct wma_txrx_node *node; + uint8_t *stats_buf; + uint32_t temp_mask; + uint8_t vdev_id; + + vdev_id = rssi_stats->vdev_id; + node = &wma->interfaces[vdev_id]; + if (node->stats_rsp) { + node->fw_stats_set |= FW_RSSI_PER_CHAIN_STATS_SET; + WMA_LOGD("<-- FW RSSI PER CHAIN STATS received for vdevId:%d", + vdev_id); + stats_rsp_params = (tAniGetPEStatsRsp *) node->stats_rsp; + stats_buf = (uint8_t *) (stats_rsp_params + 1); + temp_mask = stats_rsp_params->statsMask; + + if (temp_mask & (1 << eCsrSummaryStats)) + stats_buf += sizeof(tCsrSummaryStatsInfo); + if (temp_mask & (1 << eCsrGlobalClassAStats)) + stats_buf += sizeof(tCsrGlobalClassAStatsInfo); + if (temp_mask & (1 << eCsrGlobalClassBStats)) + stats_buf += sizeof(tCsrGlobalClassBStatsInfo); + if (temp_mask & (1 << eCsrGlobalClassCStats)) + stats_buf += sizeof(tCsrGlobalClassCStatsInfo); + if (temp_mask & (1 << eCsrGlobalClassDStats)) + stats_buf += sizeof(tCsrGlobalClassDStatsInfo); + if (temp_mask & (1 << eCsrPerStaStats)) + stats_buf += sizeof(tCsrPerStaStatsInfo); + + if (temp_mask & (1 << csr_per_chain_rssi_stats)) { + rssi_per_chain_stats = + (struct csr_per_chain_rssi_stats_info *)stats_buf; + wma_update_per_chain_rssi_stats(wma, rssi_stats, + rssi_per_chain_stats); + } + } +} + + /** * wma_link_status_event_handler() - link status event handler * @handle: wma handle @@ -1412,9 +1508,11 @@ int wma_stats_event_handler(void *handle, uint8_t *cmd_param_info, wmi_pdev_stats *pdev_stats; wmi_vdev_stats *vdev_stats; wmi_peer_stats *peer_stats; + wmi_rssi_stats *rssi_stats; + wmi_per_chain_rssi_stats *rssi_event; + struct wma_txrx_node *node; uint8_t i, *temp; - param_buf = (WMI_UPDATE_STATS_EVENTID_param_tlvs *) cmd_param_info; if (!param_buf) { WMA_LOGA("%s: Invalid stats event", __func__); @@ -1450,6 +1548,34 @@ int wma_stats_event_handler(void *handle, uint8_t *cmd_param_info, } } + rssi_event = (wmi_per_chain_rssi_stats *) param_buf->chain_stats; + if (rssi_event) { + if ((rssi_event->tlv_header & 0xFFFF0000) >> 16 == + WMITLV_TAG_STRUC_wmi_per_chain_rssi_stats) { + WMA_LOGD("%s: num_rssi_stats %u", __func__, + rssi_event->num_per_chain_rssi_stats); + if (rssi_event->num_per_chain_rssi_stats > 0) { + temp = (uint8_t *) rssi_event; + temp += sizeof(*rssi_event); + for (i = 0; + i < rssi_event->num_per_chain_rssi_stats; + i++) { + rssi_stats = (wmi_rssi_stats *)temp; + wma_update_rssi_stats(wma, rssi_stats); + temp += sizeof(wmi_rssi_stats); + } + } + } + } + + for (i = 0; i < wma->max_bssid; i++) { + node = &wma->interfaces[i]; + if (node->fw_stats_set & FW_PEER_STATS_SET) { + WMA_LOGD("<--STATS RSP VDEV_ID:%d", i); + wma_post_stats(wma, node); + } + } + WMA_LOGI("%s: Exit", __func__); return 0; } @@ -1880,6 +2006,10 @@ static tAniGetPEStatsRsp *wma_get_stats_rsp_buf case eCsrPerStaStats: len += sizeof(tCsrPerStaStatsInfo); break; + case csr_per_chain_rssi_stats: + len += + sizeof(struct csr_per_chain_rssi_stats_info); + break; } }