diff --git a/dp/inc/cdp_txrx_cmn_struct.h b/dp/inc/cdp_txrx_cmn_struct.h index 18b2c800f2..a74282fcd7 100644 --- a/dp/inc/cdp_txrx_cmn_struct.h +++ b/dp/inc/cdp_txrx_cmn_struct.h @@ -2415,6 +2415,8 @@ struct cdp_rx_stats_ppdu_user { * @sig_b_sym: Number of symbols of HE-SIG-B * @sig_b_comp: Compression mode of HE-SIG-B * @he_crc: CRC for HE-SIG contents + * @usr_nss_sum: Sum of user nss + * @usr_ru_tones_sum: Sum of user ru_tones */ struct cdp_rx_indication_ppdu { uint32_t ppdu_id; @@ -2510,6 +2512,8 @@ struct cdp_rx_indication_ppdu { sig_b_comp:1, he_crc:4; #endif + uint8_t usr_nss_sum; + uint32_t usr_ru_tones_sum; }; /** diff --git a/dp/inc/cdp_txrx_host_stats.h b/dp/inc/cdp_txrx_host_stats.h index c4f28c2efb..793f3b30d6 100644 --- a/dp/inc/cdp_txrx_host_stats.h +++ b/dp/inc/cdp_txrx_host_stats.h @@ -979,4 +979,60 @@ cdp_get_pdev_tid_stats(ol_txrx_soc_handle soc, uint8_t pdev_id, return soc->ops->host_stats_ops->txrx_get_pdev_tid_stats(soc, pdev_id, tid_stats); } + +#ifdef WLAN_TELEMETRY_STATS_SUPPORT +/** + * cdp_get_pdev_telemetry_stats(): function to get pdev telemetry stats + * @soc: soc handle + * @pdev_id: pdev id + * @stats: pointer to pdev telemetry stats + * + * return: status + */ +static inline QDF_STATUS cdp_get_pdev_telemetry_stats( + ol_txrx_soc_handle soc, + uint8_t pdev_id, + struct cdp_pdev_telemetry_stats *stats) +{ + if (!soc || !soc->ops) { + dp_cdp_debug("Invalid Instance"); + QDF_BUG(0); + return QDF_STATUS_E_FAILURE; + } + + if (!soc->ops->host_stats_ops || + !soc->ops->host_stats_ops->txrx_pdev_telemetry_stats) + return QDF_STATUS_E_FAILURE; + + return soc->ops->host_stats_ops->txrx_pdev_telemetry_stats( + soc, pdev_id, stats); +} + +/** + * cdp_get_peer_telemetry_stats(): function to get peer telemetry stats + * @soc: soc handle + * @addr: peer address + * @stats: pointer to peer telemetry stats + * + * return: status + */ +static inline QDF_STATUS cdp_get_peer_telemetry_stats( + ol_txrx_soc_handle soc, + uint8_t *addr, + struct cdp_peer_telemetry_stats *stats) +{ + if (!soc || !soc->ops) { + dp_cdp_debug("Invalid Instance"); + QDF_BUG(0); + return QDF_STATUS_E_FAILURE; + } + + if (!soc->ops->host_stats_ops || + !soc->ops->host_stats_ops->txrx_peer_telemetry_stats) + return QDF_STATUS_E_FAILURE; + + return soc->ops->host_stats_ops->txrx_peer_telemetry_stats( + soc, addr, stats); +} +#endif #endif /* _CDP_TXRX_HOST_STATS_H_ */ diff --git a/dp/inc/cdp_txrx_ops.h b/dp/inc/cdp_txrx_ops.h index 6cc8abfb52..04472f6035 100644 --- a/dp/inc/cdp_txrx_ops.h +++ b/dp/inc/cdp_txrx_ops.h @@ -1170,6 +1170,18 @@ struct cdp_host_stats_ops { QDF_STATUS (*txrx_get_pdev_tid_stats)(struct cdp_soc_t *soc, uint8_t pdev_id, struct cdp_tid_stats_intf *tid_stats); +#ifdef WLAN_TELEMETRY_STATS_SUPPORT + QDF_STATUS + (*txrx_pdev_telemetry_stats)( + struct cdp_soc_t *soc, + uint8_t pdev_id, + struct cdp_pdev_telemetry_stats *stats); + QDF_STATUS + (*txrx_peer_telemetry_stats)( + struct cdp_soc_t *soc, + uint8_t *addr, + struct cdp_peer_telemetry_stats *stats); +#endif }; struct cdp_wds_ops { diff --git a/dp/inc/cdp_txrx_stats_struct.h b/dp/inc/cdp_txrx_stats_struct.h index 92ed69ca76..d9e6099f8f 100644 --- a/dp/inc/cdp_txrx_stats_struct.h +++ b/dp/inc/cdp_txrx_stats_struct.h @@ -2628,6 +2628,36 @@ struct cdp_soc_stats { } mec; }; +#ifdef WLAN_TELEMETRY_STATS_SUPPORT +/** + * struct cdp_pdev_telemetry_stats- Structure to hold pdev telemetry stats + * @tx_mpdu_failed: Tx mpdu failed + * @tx_mpdu_total: Total tx mpdus + */ +struct cdp_pdev_telemetry_stats { + uint32_t tx_mpdu_failed; + uint32_t tx_mpdu_total; +}; + +/** + * struct cdp_peer_telemetry_stats- Structure to hold peer telemetry stats + * @tx_mpdu_retried: Tx mpdus retried + * @tx_mpdu_total: Total tx mpdus + * @rx_mpdu_retried: Rx mpdus retried + * @rx_mpdu_total: Total rx mpdus + * @airtime_consumption: airtime consumption of that peer + * @snr: peer average snr + */ +struct cdp_peer_telemetry_stats { + uint32_t tx_mpdu_retried; + uint32_t tx_mpdu_total; + uint32_t rx_mpdu_retried; + uint32_t rx_mpdu_total; + uint8_t airtime_consumption; + uint8_t snr; +}; +#endif + /* struct cdp_pdev_stats - pdev stats * @msdu_not_done: packets dropped because msdu done bit not set * @mec:Multicast Echo check @@ -2670,6 +2700,7 @@ struct cdp_soc_stats { * @ppdu_drop: stats counter for ppdu_desc drop once threshold reached * @ppdu_wrap_drop: stats counter for ppdu desc drop on wrap around * @peer_unauth_rx_pkt_drop: stats counter for drops due to unauthorized peer + * @telemetry_stats: pdev telemetry stats */ struct cdp_pdev_stats { struct { @@ -2753,6 +2784,9 @@ struct cdp_pdev_stats { } rx_refill_buff_pool; uint32_t peer_unauth_rx_pkt_drop; +#ifdef WLAN_TELEMETRY_STATS_SUPPORT + struct cdp_pdev_telemetry_stats telemetry_stats; +#endif }; /* struct cdp_peer_hmwds_ast_add_status - hmwds peer ast add status diff --git a/dp/wifi3.0/dp_internal.h b/dp/wifi3.0/dp_internal.h index 9d66e0ffce..280db027cd 100644 --- a/dp/wifi3.0/dp_internal.h +++ b/dp/wifi3.0/dp_internal.h @@ -3582,4 +3582,32 @@ dp_get_rx_hash_key_bytes(struct cdp_lro_hash_config *lro_hash) (sizeof(lro_hash->toeplitz_hash_ipv6[0]) * LRO_IPV6_SEED_ARR_SZ)); } + +#ifdef WLAN_TELEMETRY_STATS_SUPPORT +/* + * dp_get_pdev_telemetry_stats- API to get pdev telemetry stats + * @soc_hdl: soc handle + * @pdev_id: id of pdev handle + * @stats: pointer to pdev telemetry stats + * + * Return: QDF_STATUS_SUCCESS: Success + * QDF_STATUS_E_FAILURE: Error + */ +QDF_STATUS +dp_get_pdev_telemetry_stats(struct cdp_soc_t *soc_hdl, uint8_t pdev_id, + struct cdp_pdev_telemetry_stats *stats); + +/* + * dp_get_peer_telemetry_stats- API to get peer telemetry stats + * @soc_hdl: soc handle + * @addr: peer mac + * @stats: pointer to peer telemetry stats + * + * Return: QDF_STATUS_SUCCESS: Success + * QDF_STATUS_E_FAILURE: Error + */ +QDF_STATUS +dp_get_peer_telemetry_stats(struct cdp_soc_t *soc_hdl, uint8_t *addr, + struct cdp_peer_telemetry_stats *stats); +#endif /* WLAN_TELEMETRY_STATS_SUPPORT */ #endif /* #ifndef _DP_INTERNAL_H_ */ diff --git a/dp/wifi3.0/dp_main.c b/dp/wifi3.0/dp_main.c index 2e623f8a63..a5d235eb9e 100644 --- a/dp/wifi3.0/dp_main.c +++ b/dp/wifi3.0/dp_main.c @@ -12737,6 +12737,10 @@ static struct cdp_host_stats_ops dp_ops_host_stats = { .is_tx_delay_stats_enabled = dp_check_vdev_tx_delay_stats_enabled, #endif .txrx_get_pdev_tid_stats = dp_pdev_get_tid_stats, +#ifdef WLAN_TELEMETRY_STATS_SUPPORT + .txrx_pdev_telemetry_stats = dp_get_pdev_telemetry_stats, + .txrx_peer_telemetry_stats = dp_get_peer_telemetry_stats, +#endif /* TODO */ }; diff --git a/dp/wifi3.0/dp_stats.c b/dp/wifi3.0/dp_stats.c index 47d1992a70..5d01d42a38 100644 --- a/dp/wifi3.0/dp_stats.c +++ b/dp/wifi3.0/dp_stats.c @@ -8538,3 +8538,38 @@ dp_pdev_get_tx_capture_stats(struct cdp_soc_t *soc_hdl, uint8_t pdev_id, return QDF_STATUS_E_FAILURE; } #endif /* WLAN_TX_PKT_CAPTURE_ENH */ + +#ifdef WLAN_TELEMETRY_STATS_SUPPORT +QDF_STATUS +dp_get_pdev_telemetry_stats(struct cdp_soc_t *soc_hdl, uint8_t pdev_id, + struct cdp_pdev_telemetry_stats *stats) +{ + struct dp_soc *soc = (struct dp_soc *)soc_hdl; + struct dp_pdev *pdev = dp_get_pdev_from_soc_pdev_id_wifi3(soc, pdev_id); + + if (!pdev) + return QDF_STATUS_E_FAILURE; + + stats->tx_mpdu_failed = pdev->stats.telemetry_stats.tx_mpdu_failed; + stats->tx_mpdu_total = pdev->stats.telemetry_stats.tx_mpdu_total; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +dp_get_peer_telemetry_stats(struct cdp_soc_t *soc_hdl, uint8_t *addr, + struct cdp_peer_telemetry_stats *stats) +{ + struct dp_soc *soc = (struct dp_soc *)soc_hdl; + struct dp_peer *peer = dp_peer_find_hash_find(soc, addr, 0, DP_VDEV_ALL, + DP_MOD_ID_MISC); + + if (!peer) + return QDF_STATUS_E_FAILURE; + + dp_monitor_peer_telemetry_stats(peer, stats); + dp_peer_unref_delete(peer, DP_MOD_ID_MISC); + + return QDF_STATUS_SUCCESS; +} +#endif diff --git a/dp/wifi3.0/monitor/dp_mon.c b/dp/wifi3.0/monitor/dp_mon.c index a0dda474a9..a91579318e 100644 --- a/dp/wifi3.0/monitor/dp_mon.c +++ b/dp/wifi3.0/monitor/dp_mon.c @@ -2132,6 +2132,47 @@ QDF_STATUS dp_rx_populate_cbf_hdr(struct dp_soc *soc, } #ifdef ATH_SUPPORT_EXT_STAT +#ifdef WLAN_TELEMETRY_STATS_SUPPORT +/* dp_peer_update_telemetry_stats- update peer telemetry stats + * @peer : Datapath peer + */ +static inline +void dp_peer_update_telemetry_stats(struct dp_peer *peer) +{ + struct dp_pdev *pdev; + struct dp_vdev *vdev; + struct dp_mon_peer *mon_peer = NULL; + uint8_t idx; + + vdev = peer->vdev; + if (!vdev) + return; + + pdev = vdev->pdev; + if (!pdev) + return; + + mon_peer = peer->monitor_peer; + if (qdf_likely(mon_peer)) { + DP_STATS_INC(pdev, telemetry_stats.tx_mpdu_failed, + mon_peer->stats.tx.retries); + DP_STATS_INC(pdev, telemetry_stats.tx_mpdu_total, + mon_peer->stats.tx.tx_mpdus_tried); + idx = mon_peer->stats.airtime_consumption.avg_consumption.idx; + mon_peer->stats.airtime_consumption.avg_consumption.avg_consumption_per_sec[idx] = + mon_peer->stats.airtime_consumption.consumption; + mon_peer->stats.airtime_consumption.consumption = 0; + mon_peer->stats.airtime_consumption.avg_consumption.idx++; + if (idx == MAX_CONSUMPTION_TIME) + mon_peer->stats.airtime_consumption.avg_consumption.idx = 0; + } +} +#else +static inline +void dp_peer_update_telemetry_stats(struct dp_peer *peer) +{ } +#endif + /*dp_peer_cal_clients_stats_update - update peer stats on cal client timer * @soc : Datapath SOC * @peer : Datapath peer @@ -2153,6 +2194,8 @@ dp_peer_cal_clients_stats_update(struct dp_soc *soc, if (!tgt_peer || !(tgt_peer->txrx_peer)) return; + dp_peer_update_telemetry_stats(peer); + txrx_peer = tgt_peer->txrx_peer; peer_stats_intf.to_stack = txrx_peer->to_stack; peer_stats_intf.tx_success = @@ -4045,26 +4088,48 @@ static void dp_process_ppdu_tag(struct dp_pdev *pdev, } } -#ifdef WLAN_ATF_ENABLE +#ifdef WLAN_TELEMETRY_STATS_SUPPORT +static inline +void dp_ppdu_desc_user_airtime_consumption_update( + struct dp_peer *peer, + struct cdp_tx_completion_ppdu_user *user) +{ + struct dp_mon_peer *mon_peer = NULL; + + mon_peer = peer->monitor_peer; + if (qdf_unlikely(!mon_peer)) + return; + + DP_STATS_INC(mon_peer, airtime_consumption.consumption, + user->phy_tx_time_us); +} +#else +static inline +void dp_ppdu_desc_user_airtime_consumption_update( + struct dp_peer *peer, + struct cdp_tx_completion_ppdu_user *user) +{ } +#endif +#if defined(WLAN_ATF_ENABLE) || defined(WLAN_TELEMETRY_STATS_SUPPORT) static void dp_ppdu_desc_user_phy_tx_time_update(struct dp_pdev *pdev, + struct dp_peer *peer, struct cdp_tx_completion_ppdu *ppdu_desc, struct cdp_tx_completion_ppdu_user *user) { uint32_t nss_ru_width_sum = 0; - struct dp_mon_pdev *mon_pdev = NULL; + struct dp_mon_peer *mon_peer = NULL; - if (!pdev || !ppdu_desc || !user) - return; - - mon_pdev = pdev->monitor_pdev; - - if (!mon_pdev || !mon_pdev->dp_atf_stats_enable) + if (!pdev || !ppdu_desc || !user || !peer) return; if (ppdu_desc->frame_type != CDP_PPDU_FTYPE_DATA) return; + mon_peer = peer->monitor_peer; + if (qdf_unlikely(!mon_peer)) + return; + nss_ru_width_sum = ppdu_desc->usr_nss_sum * ppdu_desc->usr_ru_tones_sum; if (!nss_ru_width_sum) nss_ru_width_sum = 1; @@ -4084,10 +4149,13 @@ dp_ppdu_desc_user_phy_tx_time_update(struct dp_pdev *pdev, user->phy_tx_time_us = (ppdu_desc->phy_ppdu_tx_time_us * user->nss * user->ru_tones) / nss_ru_width_sum; } + + dp_ppdu_desc_user_airtime_consumption_update(peer, user); } #else static void dp_ppdu_desc_user_phy_tx_time_update(struct dp_pdev *pdev, + struct dp_peer *peer, struct cdp_tx_completion_ppdu *ppdu_desc, struct cdp_tx_completion_ppdu_user *user) { @@ -4191,7 +4259,7 @@ dp_ppdu_desc_user_stats_update(struct dp_pdev *pdev, ppdu_desc->ack_rssi); } - dp_ppdu_desc_user_phy_tx_time_update(pdev, ppdu_desc, + dp_ppdu_desc_user_phy_tx_time_update(pdev, peer, ppdu_desc, &ppdu_desc->user[i]); dp_peer_unref_delete(peer, DP_MOD_ID_TX_PPDU_STATS); diff --git a/dp/wifi3.0/monitor/dp_mon.h b/dp/wifi3.0/monitor/dp_mon.h index 66a3a2268b..9896be8ace 100644 --- a/dp/wifi3.0/monitor/dp_mon.h +++ b/dp/wifi3.0/monitor/dp_mon.h @@ -823,6 +823,17 @@ struct dp_mon_soc { #endif }; +#ifdef WLAN_TELEMETRY_STATS_SUPPORT +#define MAX_CONSUMPTION_TIME 5 /* in sec */ +struct dp_mon_peer_airtime_consumption { + uint32_t consumption; + struct { + uint32_t avg_consumption_per_sec[MAX_CONSUMPTION_TIME]; + uint8_t idx; + } avg_consumption; +}; +#endif + /** * struct dp_mon_peer_stats - Monitor peer stats */ @@ -830,6 +841,9 @@ struct dp_mon_peer_stats { #ifdef QCA_ENHANCED_STATS_SUPPORT dp_mon_peer_tx_stats tx; dp_mon_peer_rx_stats rx; +#ifdef WLAN_TELEMETRY_STATS_SUPPORT + struct dp_mon_peer_airtime_consumption airtime_consumption; +#endif #endif }; @@ -4089,4 +4103,32 @@ dp_lite_mon_rx_mpdu_process(struct dp_pdev *pdev, return QDF_STATUS_E_FAILURE; } #endif + +#ifdef WLAN_TELEMETRY_STATS_SUPPORT +static inline +void dp_monitor_peer_telemetry_stats(struct dp_peer *peer, + struct cdp_peer_telemetry_stats *stats) +{ + struct dp_mon_peer_stats *mon_peer_stats = NULL; + uint8_t idx = 0; + uint32_t consumption = 0; + + if (qdf_unlikely(!peer->monitor_peer)) + return; + + mon_peer_stats = &peer->monitor_peer->stats; + for (idx = 0; idx < MAX_CONSUMPTION_TIME; idx++) + consumption += + mon_peer_stats->airtime_consumption.avg_consumption.avg_consumption_per_sec[idx]; + /* consumption is in micro seconds, convert it to seconds and + * then calculate %age per 5 sec + */ + stats->airtime_consumption = ((consumption * 100) / (MAX_CONSUMPTION_TIME * 1000000)); + stats->tx_mpdu_retried = mon_peer_stats->tx.retries; + stats->tx_mpdu_total = mon_peer_stats->tx.tx_mpdus_tried; + stats->rx_mpdu_retried = mon_peer_stats->rx.mpdu_retry_cnt; + stats->rx_mpdu_total = mon_peer_stats->rx.rx_mpdus; + stats->snr = CDP_SNR_OUT(mon_peer_stats->rx.avg_snr); +} +#endif #endif /* _DP_MON_H_ */ diff --git a/dp/wifi3.0/monitor/dp_rx_mon.c b/dp/wifi3.0/monitor/dp_rx_mon.c index 39e7d4e3ed..2d504f9584 100644 --- a/dp/wifi3.0/monitor/dp_rx_mon.c +++ b/dp/wifi3.0/monitor/dp_rx_mon.c @@ -523,6 +523,7 @@ dp_rx_populate_cdp_indication_ppdu_user(struct dp_pdev *pdev, cdp_rx_ppdu->u.ppdu_type == HAL_RX_TYPE_MU_MIMO) { if (rx_user_status->mu_ul_info_valid) { rx_stats_peruser->nss = rx_user_status->nss; + cdp_rx_ppdu->usr_nss_sum += rx_stats_peruser->nss; rx_stats_peruser->mcs = rx_user_status->mcs; rx_stats_peruser->mu_ul_info_valid = rx_user_status->mu_ul_info_valid; @@ -530,6 +531,8 @@ dp_rx_populate_cdp_indication_ppdu_user(struct dp_pdev *pdev, rx_user_status->ofdma_ru_start_index; rx_stats_peruser->ofdma_ru_width = rx_user_status->ofdma_ru_width; + cdp_rx_ppdu->usr_ru_tones_sum += + rx_stats_peruser->ofdma_ru_width; rx_stats_peruser->user_index = i; ru_size = rx_user_status->ofdma_ru_size; /* @@ -820,6 +823,43 @@ static inline uint8_t dp_get_bw_offset_frm_bw(struct dp_soc *soc, } #endif +#ifdef WLAN_TELEMETRY_STATS_SUPPORT +static void +dp_ppdu_desc_user_rx_time_update(struct dp_pdev *pdev, + struct dp_peer *peer, + struct cdp_rx_indication_ppdu *ppdu_desc, + struct cdp_rx_stats_ppdu_user *user) +{ + uint32_t nss_ru_width_sum = 0; + struct dp_mon_peer *mon_peer = NULL; + uint16_t rx_time_us; + + if (!pdev || !ppdu_desc || !user || !peer) + return; + + mon_peer = peer->monitor_peer; + if (qdf_unlikely(!mon_peer)) + return; + + nss_ru_width_sum = ppdu_desc->usr_nss_sum * ppdu_desc->usr_ru_tones_sum; + if (!nss_ru_width_sum) + nss_ru_width_sum = 1; + + rx_time_us = (ppdu_desc->duration * + user->nss * user->ofdma_ru_width) / nss_ru_width_sum; + + DP_STATS_INC(mon_peer, airtime_consumption.consumption, + rx_time_us); +} +#else +static inline void +dp_ppdu_desc_user_rx_time_update(struct dp_pdev *pdev, + struct dp_peer *peer, + struct cdp_rx_indication_ppdu *ppdu_desc, + struct cdp_rx_stats_ppdu_user *user) +{ } +#endif + static void dp_rx_stats_update(struct dp_pdev *pdev, struct cdp_rx_indication_ppdu *ppdu) { @@ -1024,6 +1064,7 @@ static void dp_rx_stats_update(struct dp_pdev *pdev, dp_send_stats_event(pdev, peer, ppdu_user->peer_id); + dp_ppdu_desc_user_rx_time_update(pdev, peer, ppdu, ppdu_user); dp_peer_unref_delete(peer, DP_MOD_ID_RX_PPDU_STATS); } }