diff --git a/target_if/cp_stats/src/target_if_mc_cp_stats.c b/target_if/cp_stats/src/target_if_mc_cp_stats.c index 7911bb058b..84d478d0b9 100644 --- a/target_if/cp_stats/src/target_if_mc_cp_stats.c +++ b/target_if/cp_stats/src/target_if_mc_cp_stats.c @@ -56,6 +56,10 @@ static void target_if_cp_stats_free_stats_event(struct stats_event *ev) ev->peer_stats = NULL; qdf_mem_free(ev->cca_stats); ev->cca_stats = NULL; + qdf_mem_free(ev->vdev_summary_stats); + ev->vdev_summary_stats = NULL; + qdf_mem_free(ev->vdev_chain_rssi); + ev->vdev_chain_rssi = NULL; } static QDF_STATUS target_if_cp_stats_extract_pdev_stats( @@ -159,6 +163,136 @@ static QDF_STATUS target_if_cp_stats_extract_cca_stats( return QDF_STATUS_SUCCESS; } +static QDF_STATUS target_if_cp_stats_extract_vdev_summary_stats( + struct wmi_unified *wmi_hdl, + wmi_host_stats_event *stats_param, + struct stats_event *ev, uint8_t *data) +{ + uint32_t i, j; + QDF_STATUS status; + int32_t bcn_snr, dat_snr; + wmi_host_vdev_stats vdev_stats; + + ev->num_summary_stats = stats_param->num_vdev_stats; + if (!ev->num_summary_stats) + return QDF_STATUS_SUCCESS; + + ev->vdev_summary_stats = qdf_mem_malloc(sizeof(*ev->vdev_summary_stats) + * ev->num_summary_stats); + + if (!ev->vdev_summary_stats) { + cp_stats_err("malloc failed"); + return QDF_STATUS_E_NOMEM; + } + + for (i = 0; i < ev->num_summary_stats; i++) { + status = wmi_extract_vdev_stats(wmi_hdl, data, i, &vdev_stats); + if (QDF_IS_STATUS_ERROR(status)) + continue; + + bcn_snr = vdev_stats.vdev_snr.bcn_snr; + dat_snr = vdev_stats.vdev_snr.dat_snr; + ev->vdev_summary_stats[i].vdev_id = vdev_stats.vdev_id; + + for (j = 0; j < 4; j++) { + ev->vdev_summary_stats[i].stats.tx_frm_cnt[j] + = vdev_stats.tx_frm_cnt[j]; + ev->vdev_summary_stats[i].stats.fail_cnt[j] + = vdev_stats.fail_cnt[j]; + ev->vdev_summary_stats[i].stats.multiple_retry_cnt[j] + = vdev_stats.multiple_retry_cnt[j]; + } + + ev->vdev_summary_stats[i].stats.rx_frm_cnt = + vdev_stats.rx_frm_cnt; + ev->vdev_summary_stats[i].stats.rx_error_cnt = + vdev_stats.rx_err_cnt; + ev->vdev_summary_stats[i].stats.rx_discard_cnt = + vdev_stats.rx_discard_cnt; + ev->vdev_summary_stats[i].stats.ack_fail_cnt = + vdev_stats.ack_fail_cnt; + ev->vdev_summary_stats[i].stats.rts_succ_cnt = + vdev_stats.rts_succ_cnt; + ev->vdev_summary_stats[i].stats.rts_fail_cnt = + vdev_stats.rts_fail_cnt; + /* Update SNR and RSSI in SummaryStats */ + if (TGT_IS_VALID_SNR(bcn_snr)) { + ev->vdev_summary_stats[i].stats.snr = bcn_snr; + ev->vdev_summary_stats[i].stats.rssi = + bcn_snr + TGT_NOISE_FLOOR_DBM; + } else if (TGT_IS_VALID_SNR(dat_snr)) { + ev->vdev_summary_stats[i].stats.snr = dat_snr; + ev->vdev_summary_stats[i].stats.rssi = + dat_snr + TGT_NOISE_FLOOR_DBM; + } else { + ev->vdev_summary_stats[i].stats.snr = TGT_INVALID_SNR; + ev->vdev_summary_stats[i].stats.rssi = 0; + } + } + + return QDF_STATUS_SUCCESS; +} + + +static QDF_STATUS target_if_cp_stats_extract_vdev_chain_rssi_stats( + struct wmi_unified *wmi_hdl, + wmi_host_stats_event *stats_param, + struct stats_event *ev, uint8_t *data) +{ + uint32_t i; + QDF_STATUS status; + int32_t bcn_snr, dat_snr; + struct wmi_host_per_chain_rssi_stats rssi_stats; + + ev->num_chain_rssi_stats = stats_param->num_rssi_stats; + if (!ev->num_chain_rssi_stats) + return QDF_STATUS_SUCCESS; + + ev->vdev_chain_rssi = qdf_mem_malloc(sizeof(*ev->vdev_chain_rssi) * + ev->num_chain_rssi_stats); + if (!ev->vdev_chain_rssi) { + cp_stats_err("malloc failed"); + return QDF_STATUS_E_NOMEM; + } + + for (i = 0; i < ev->num_chain_rssi_stats; i++) { + status = wmi_extract_per_chain_rssi_stats(wmi_hdl, data, i, + &rssi_stats); + if (QDF_IS_STATUS_ERROR(status)) + continue; + + for (i = 0; i < MAX_NUM_CHAINS; i++) { + dat_snr = rssi_stats.rssi_avg_data[i]; + bcn_snr = rssi_stats.rssi_avg_beacon[i]; + cp_stats_err("Chain %d SNR bcn: %d data: %d", i, + bcn_snr, dat_snr); + if (TGT_IS_VALID_SNR(bcn_snr)) + ev->vdev_chain_rssi[i].chain_rssi[i] = bcn_snr; + else if (TGT_IS_VALID_SNR(dat_snr)) + ev->vdev_chain_rssi[i].chain_rssi[i] = dat_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. + */ + ev->vdev_chain_rssi[i].chain_rssi[i] = + TGT_INVALID_SNR; + /* + * Get the absolute rssi value from the current rssi + * value the snr value is hardcoded into 0 in the + * qcacld-new/CORE stack + */ + ev->vdev_chain_rssi[i].chain_rssi[i] += + TGT_NOISE_FLOOR_DBM; + } + } + + return QDF_STATUS_SUCCESS; +} + static QDF_STATUS target_if_cp_stats_extract_event(struct wmi_unified *wmi_hdl, struct stats_event *ev, uint8_t *data) @@ -168,7 +302,7 @@ static QDF_STATUS target_if_cp_stats_extract_event(struct wmi_unified *wmi_hdl, status = wmi_extract_stats_param(wmi_hdl, data, &stats_param); if (QDF_IS_STATUS_ERROR(status)) { - cp_stats_debug("stats param extract failed: %d", status); + cp_stats_err("stats param extract failed: %d", status); return status; } cp_stats_debug("num: pdev: %d, vdev: %d, peer: %d, rssi: %d", @@ -190,6 +324,18 @@ static QDF_STATUS target_if_cp_stats_extract_event(struct wmi_unified *wmi_hdl, if (QDF_IS_STATUS_ERROR(status)) return status; + status = target_if_cp_stats_extract_vdev_summary_stats(wmi_hdl, + &stats_param, + ev, data); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + status = target_if_cp_stats_extract_vdev_chain_rssi_stats(wmi_hdl, + &stats_param, + ev, data); + if (QDF_IS_STATUS_ERROR(status)) + return status; + return QDF_STATUS_SUCCESS; } @@ -373,6 +519,12 @@ static uint32_t get_stats_id(enum stats_req_type type) return WMI_REQUEST_PDEV_STAT; case TYPE_PEER_STATS: return WMI_REQUEST_PEER_STAT; + case TYPE_STATION_STATS: + return (WMI_REQUEST_AP_STAT | + WMI_REQUEST_PEER_STAT | + WMI_REQUEST_VDEV_STAT | + WMI_REQUEST_PDEV_STAT | + WMI_REQUEST_RSSI_PER_CHAIN_STAT); } return 0; } diff --git a/wmi/inc/wmi_unified_api.h b/wmi/inc/wmi_unified_api.h index 59808cdf60..5bb294c643 100644 --- a/wmi/inc/wmi_unified_api.h +++ b/wmi/inc/wmi_unified_api.h @@ -1705,6 +1705,9 @@ QDF_STATUS wmi_extract_atf_token_info_ev(void *wmi_hdl, void *evt_buf, QDF_STATUS wmi_extract_vdev_stats(void *wmi_hdl, void *evt_buf, uint32_t index, wmi_host_vdev_stats *vdev_stats); +QDF_STATUS wmi_extract_per_chain_rssi_stats(void *wmi_hdl, void *evt_buf, + uint32_t index, struct wmi_host_per_chain_rssi_stats *rssi_stats); + QDF_STATUS wmi_extract_vdev_extd_stats(void *wmi_hdl, void *evt_buf, uint32_t index, wmi_host_vdev_extd_stats *vdev_extd_stats); diff --git a/wmi/inc/wmi_unified_param.h b/wmi/inc/wmi_unified_param.h index 6dc74be636..e77e5284bf 100644 --- a/wmi/inc/wmi_unified_param.h +++ b/wmi/inc/wmi_unified_param.h @@ -5162,6 +5162,12 @@ typedef struct { * */ #define WMI_HOST_WLAN_MAX_AC 4 +/* The WMI_HOST_MAX_CHAINS macro cannot be changed without breaking WMI + * compatibility. + * The maximum value of number of chains + */ +#define WMI_HOST_MAX_CHAINS 8 + /** * struct wmi_host_vdev_stats - vdev stats structure * @vdev_id: unique id identifying the VDEV, generated by the caller @@ -5263,6 +5269,21 @@ struct wmi_host_vdev_nac_rssi_event { uint32_t rssi_seq_num; }; + +/** + * struct wmi_host_per_chain_rssi_stats - VDEV nac rssi stats + * @vdev_id: unique id identifying the VDEV, generated by the caller + * @rssi_avg_beacon: per chain avg rssi for beacon + * @rssi_avg_data: per chain avg rssi for data + * @peer_macaddr: peer macaddr + */ +struct wmi_host_per_chain_rssi_stats { + uint32_t vdev_id; + int32_t rssi_avg_beacon[WMI_HOST_MAX_CHAINS]; + int32_t rssi_avg_data[WMI_HOST_MAX_CHAINS]; + wmi_host_mac_addr peer_macaddr; +}; + /** * struct wmi_host_peer_stats - peer stats * @peer_macaddr: peer MAC address diff --git a/wmi/inc/wmi_unified_priv.h b/wmi/inc/wmi_unified_priv.h index 56b9ae6dba..49fc4002ef 100644 --- a/wmi/inc/wmi_unified_priv.h +++ b/wmi/inc/wmi_unified_priv.h @@ -1290,6 +1290,10 @@ QDF_STATUS (*extract_pdev_ext_stats)(wmi_unified_t wmi_handle, void *evt_buf, QDF_STATUS (*extract_vdev_stats)(wmi_unified_t wmi_handle, void *evt_buf, uint32_t index, wmi_host_vdev_stats *vdev_stats); +QDF_STATUS (*extract_per_chain_rssi_stats)(wmi_unified_t wmi_handle, + void *evt_buf, uint32_t index, + struct wmi_host_per_chain_rssi_stats *rssi_stats); + QDF_STATUS (*extract_peer_stats)(wmi_unified_t wmi_handle, void *evt_buf, uint32_t index, wmi_host_peer_stats *peer_stats); diff --git a/wmi/src/wmi_unified_api.c b/wmi/src/wmi_unified_api.c index 484c55c0a9..9ca88029f2 100644 --- a/wmi/src/wmi_unified_api.c +++ b/wmi/src/wmi_unified_api.c @@ -6210,6 +6210,27 @@ QDF_STATUS wmi_extract_vdev_stats(void *wmi_hdl, void *evt_buf, return QDF_STATUS_E_FAILURE; } +/** + * wmi_extract_per_chain_rssi_stats() - extract rssi stats from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param index: Index into rssi stats + * @param rssi_stats: Pointer to hold rssi stats + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_extract_per_chain_rssi_stats(void *wmi_hdl, void *evt_buf, + uint32_t index, struct wmi_host_per_chain_rssi_stats *rssi_stats) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->extract_per_chain_rssi_stats) + return wmi_handle->ops->extract_per_chain_rssi_stats(wmi_handle, + evt_buf, index, rssi_stats); + + return QDF_STATUS_E_FAILURE; +} + /** * wmi_extract_rtt_hdr() - extract rtt header from event * @wmi_handle: wmi handle diff --git a/wmi/src/wmi_unified_tlv.c b/wmi/src/wmi_unified_tlv.c index 562dd35d38..8ab1cf1f5f 100644 --- a/wmi/src/wmi_unified_tlv.c +++ b/wmi/src/wmi_unified_tlv.c @@ -19516,6 +19516,57 @@ static QDF_STATUS extract_vdev_stats_tlv(wmi_unified_t wmi_handle, return QDF_STATUS_SUCCESS; } +/** + * extract_per_chain_rssi_stats_tlv() - api to extract rssi stats from event + * buffer + * @wmi_handle: wmi handle + * @evt_buf: pointer to event buffer + * @index: Index into vdev stats + * @rssi_stats: Pointer to hold rssi stats + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +static QDF_STATUS extract_per_chain_rssi_stats_tlv(wmi_unified_t wmi_handle, + void *evt_buf, uint32_t index, + struct wmi_host_per_chain_rssi_stats *rssi_stats) +{ + uint8_t *data; + wmi_rssi_stats *fw_rssi_stats; + wmi_per_chain_rssi_stats *rssi_event; + WMI_UPDATE_STATS_EVENTID_param_tlvs *param_buf; + + if (!evt_buf) { + WMI_LOGE("evt_buf is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + param_buf = (WMI_UPDATE_STATS_EVENTID_param_tlvs *) evt_buf; + rssi_event = param_buf->chain_stats; + + if (index >= rssi_event->num_per_chain_rssi_stats) { + WMI_LOGE("invalid index"); + return QDF_STATUS_E_INVAL; + } + + data = ((uint8_t *)(&rssi_event[1])) + WMI_TLV_HDR_SIZE; + fw_rssi_stats = &((wmi_rssi_stats *)data)[index]; + + rssi_stats->vdev_id = fw_rssi_stats->vdev_id; + qdf_mem_copy(rssi_stats->rssi_avg_beacon, + fw_rssi_stats->rssi_avg_beacon, + sizeof(fw_rssi_stats->rssi_avg_beacon)); + qdf_mem_copy(rssi_stats->rssi_avg_data, + fw_rssi_stats->rssi_avg_data, + sizeof(fw_rssi_stats->rssi_avg_data)); + qdf_mem_copy(&rssi_stats->peer_macaddr, + &fw_rssi_stats->peer_macaddr, + sizeof(fw_rssi_stats->peer_macaddr)); + + return QDF_STATUS_SUCCESS; +} + + + /** * extract_bcn_stats_tlv() - extract bcn stats from event * @wmi_handle: wmi handle @@ -22805,6 +22856,7 @@ struct wmi_ops tlv_ops = { .extract_unit_test = extract_unit_test_tlv, .extract_pdev_ext_stats = extract_pdev_ext_stats_tlv, .extract_vdev_stats = extract_vdev_stats_tlv, + .extract_per_chain_rssi_stats = extract_per_chain_rssi_stats_tlv, .extract_peer_stats = extract_peer_stats_tlv, .extract_bcn_stats = extract_bcn_stats_tlv, .extract_bcnflt_stats = extract_bcnflt_stats_tlv,