diff --git a/dp/inc/cdp_txrx_ctrl.h b/dp/inc/cdp_txrx_ctrl.h index 8a94c3f03f..187cfc5cb0 100644 --- a/dp/inc/cdp_txrx_ctrl.h +++ b/dp/inc/cdp_txrx_ctrl.h @@ -1284,4 +1284,86 @@ void cdp_txrx_peer_flush_frags(ol_txrx_soc_handle soc, uint8_t vdev_id, return soc->ops->ctrl_ops->txrx_peer_flush_frags(soc, vdev_id, peer_mac); } + +#ifdef WLAN_FEATURE_TSF_UPLINK_DELAY +/** + * cdp_set_delta_tsf() - wrapper function to set delta_tsf + * @soc: SOC TXRX handle + * @vdev_id: vdev id + * @delta_tsf: difference between TSF clock and qtimer + * + * Return: None + */ +static inline void cdp_set_delta_tsf(ol_txrx_soc_handle soc, uint8_t vdev_id, + uint32_t delta_tsf) +{ + if (!soc || !soc->ops) { + dp_cdp_err("Invalid instance"); + QDF_BUG(0); + return; + } + + if (!soc->ops->ctrl_ops || + !soc->ops->ctrl_ops->txrx_set_delta_tsf) + return; + + soc->ops->ctrl_ops->txrx_set_delta_tsf(soc, vdev_id, delta_tsf); +} + +/** + * cdp_set_tsf_ul_delay_report() - Enable or disable reporting uplink delay + * @soc: SOC TXRX handle + * @vdev_id: vdev id + * @enable: true to enable and false to disable + * + * Return: QDF_STATUS + */ +static inline QDF_STATUS cdp_set_tsf_ul_delay_report(ol_txrx_soc_handle soc, + uint8_t vdev_id, + bool enable) +{ + if (!soc || !soc->ops) { + dp_cdp_err("Invalid SOC instance"); + QDF_BUG(0); + return QDF_STATUS_E_FAILURE; + } + + if (!soc->ops->ctrl_ops || + !soc->ops->ctrl_ops->txrx_set_tsf_ul_delay_report) + return QDF_STATUS_E_FAILURE; + + return soc->ops->ctrl_ops->txrx_set_tsf_ul_delay_report(soc, vdev_id, + enable); +} + +/** + * cdp_get_uplink_delay() - Get uplink delay value + * @soc: SOC TXRX handle + * @vdev_id: vdev id + * @val: pointer to save uplink delay value + * + * Return: QDF_STATUS + */ +static inline QDF_STATUS cdp_get_uplink_delay(ol_txrx_soc_handle soc, + uint32_t vdev_id, uint32_t *val) +{ + if (!soc || !soc->ops) { + dp_cdp_err("Invalid SOC instance"); + QDF_BUG(0); + return QDF_STATUS_E_FAILURE; + } + + if (!val) { + dp_cdp_err("Invalid params val"); + return QDF_STATUS_E_FAILURE; + } + + if (!soc->ops->ctrl_ops || + !soc->ops->ctrl_ops->txrx_get_uplink_delay) + return QDF_STATUS_E_FAILURE; + + return soc->ops->ctrl_ops->txrx_get_uplink_delay(soc, vdev_id, val); +} +#endif /* WLAN_FEATURE_TSF_UPLINK_DELAY */ + #endif /* _CDP_TXRX_CTRL_H_ */ diff --git a/dp/inc/cdp_txrx_ops.h b/dp/inc/cdp_txrx_ops.h index b8c8c511ba..806f2c060c 100644 --- a/dp/inc/cdp_txrx_ops.h +++ b/dp/inc/cdp_txrx_ops.h @@ -813,6 +813,17 @@ struct cdp_ctrl_ops { int8_t vdev_id); #endif + +#ifdef WLAN_FEATURE_TSF_UPLINK_DELAY + void (*txrx_set_delta_tsf)(struct cdp_soc_t *soc, uint8_t vdev_id, + uint32_t delta_tsf); + QDF_STATUS (*txrx_set_tsf_ul_delay_report)(struct cdp_soc_t *soc, + uint8_t vdev_id, + bool enable); + QDF_STATUS (*txrx_get_uplink_delay)(struct cdp_soc_t *soc, + uint8_t vdev_id, + uint32_t *val); +#endif }; struct cdp_me_ops { diff --git a/dp/wifi3.0/dp_main.c b/dp/wifi3.0/dp_main.c index d0db4536d6..b18acb074e 100644 --- a/dp/wifi3.0/dp_main.c +++ b/dp/wifi3.0/dp_main.c @@ -12471,6 +12471,11 @@ static struct cdp_ctrl_ops dp_ops_ctrl = { .txrx_update_peer_pkt_capture_params = dp_peer_update_pkt_capture_params, #endif /* WLAN_TX_PKT_CAPTURE_ENH || WLAN_RX_PKT_CAPTURE_ENH */ +#ifdef WLAN_FEATURE_TSF_UPLINK_DELAY + .txrx_set_delta_tsf = dp_set_delta_tsf, + .txrx_set_tsf_ul_delay_report = dp_set_tsf_ul_delay_report, + .txrx_get_uplink_delay = dp_get_uplink_delay, +#endif }; static struct cdp_me_ops dp_ops_me = { diff --git a/dp/wifi3.0/dp_tx.c b/dp/wifi3.0/dp_tx.c index f2b9eaf3d7..5315511945 100644 --- a/dp/wifi3.0/dp_tx.c +++ b/dp/wifi3.0/dp_tx.c @@ -3991,6 +3991,138 @@ void dp_tx_update_connectivity_stats(struct dp_soc *soc, } #endif +#ifdef WLAN_FEATURE_TSF_UPLINK_DELAY +void dp_set_delta_tsf(struct cdp_soc_t *soc_hdl, uint8_t vdev_id, + uint32_t delta_tsf) +{ + struct dp_soc *soc = cdp_soc_t_to_dp_soc(soc_hdl); + struct dp_vdev *vdev = dp_vdev_get_ref_by_id(soc, vdev_id, + DP_MOD_ID_CDP); + + if (!vdev) { + dp_err_rl("vdev %d does not exist", vdev_id); + return; + } + + vdev->delta_tsf = delta_tsf; + dp_debug("vdev id %u delta_tsf %u", vdev_id, delta_tsf); + + dp_vdev_unref_delete(soc, vdev, DP_MOD_ID_CDP); +} + +QDF_STATUS dp_set_tsf_ul_delay_report(struct cdp_soc_t *soc_hdl, + uint8_t vdev_id, bool enable) +{ + struct dp_soc *soc = cdp_soc_t_to_dp_soc(soc_hdl); + struct dp_vdev *vdev = dp_vdev_get_ref_by_id(soc, vdev_id, + DP_MOD_ID_CDP); + + if (!vdev) { + dp_err_rl("vdev %d does not exist", vdev_id); + return QDF_STATUS_E_FAILURE; + } + + qdf_atomic_set(&vdev->ul_delay_report, enable); + + dp_vdev_unref_delete(soc, vdev, DP_MOD_ID_CDP); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS dp_get_uplink_delay(struct cdp_soc_t *soc_hdl, uint8_t vdev_id, + uint32_t *val) +{ + struct dp_soc *soc = cdp_soc_t_to_dp_soc(soc_hdl); + struct dp_vdev *vdev; + uint32_t delay_accum; + uint32_t pkts_accum; + + vdev = dp_vdev_get_ref_by_id(soc, vdev_id, DP_MOD_ID_CDP); + if (!vdev) { + dp_err_rl("vdev %d does not exist", vdev_id); + return QDF_STATUS_E_FAILURE; + } + + if (!qdf_atomic_read(&vdev->ul_delay_report)) { + dp_vdev_unref_delete(soc, vdev, DP_MOD_ID_CDP); + return QDF_STATUS_E_FAILURE; + } + + /* Average uplink delay based on current accumulated values */ + delay_accum = qdf_atomic_read(&vdev->ul_delay_accum); + pkts_accum = qdf_atomic_read(&vdev->ul_pkts_accum); + + *val = delay_accum / pkts_accum; + dp_debug("uplink_delay %u delay_accum %u pkts_accum %u", *val, + delay_accum, pkts_accum); + + /* Reset accumulated values to 0 */ + qdf_atomic_set(&vdev->ul_delay_accum, 0); + qdf_atomic_set(&vdev->ul_pkts_accum, 0); + + dp_vdev_unref_delete(soc, vdev, DP_MOD_ID_CDP); + + return QDF_STATUS_SUCCESS; +} + +static void dp_tx_update_uplink_delay(struct dp_soc *soc, struct dp_vdev *vdev, + struct hal_tx_completion_status *ts) +{ + uint32_t buffer_ts; + uint32_t delta_tsf; + uint32_t ul_delay; + + /* Tx_rate_stats_info_valid is 0 and tsf is invalid then */ + if (!ts->valid) + return; + + if (qdf_unlikely(!vdev)) { + dp_info_rl("vdev is null or delete in progrss"); + return; + } + + if (!qdf_atomic_read(&vdev->ul_delay_report)) + return; + + delta_tsf = vdev->delta_tsf; + + /* buffer_timestamp is in units of 1024 us and is [31:13] of + * WBM_RELEASE_RING_4. After left shift 10 bits, it's + * valid up to 29 bits. + */ + buffer_ts = ts->buffer_timestamp << 10; + + ul_delay = ts->tsf - buffer_ts - delta_tsf; + ul_delay &= 0x1FFFFFFF; /* mask 29 BITS */ + if (ul_delay > 0x1000000) { + dp_info_rl("----------------------\n" + "Tx completion status:\n" + "----------------------\n" + "release_src = %d\n" + "ppdu_id = 0x%x\n" + "release_reason = %d\n" + "tsf = %u (0x%x)\n" + "buffer_timestamp = %u (0x%x)\n" + "delta_tsf = %u (0x%x)\n", + ts->release_src, ts->ppdu_id, ts->status, + ts->tsf, ts->tsf, ts->buffer_timestamp, + ts->buffer_timestamp, delta_tsf, delta_tsf); + return; + } + + ul_delay /= 1000; /* in unit of ms */ + + qdf_atomic_add(ul_delay, &vdev->ul_delay_accum); + qdf_atomic_inc(&vdev->ul_pkts_accum); +} +#else /* !WLAN_FEATURE_TSF_UPLINK_DELAY */ +static inline +void dp_tx_update_uplink_delay(struct dp_soc *soc, struct dp_vdev *vdev, + struct hal_tx_completion_status *ts) +{ +} +#endif /* WLAN_FEATURE_TSF_UPLINK_DELAY */ + /** * dp_tx_comp_process_tx_status() - Parse and Dump Tx completion status info * @soc: DP soc handle @@ -4069,6 +4201,7 @@ void dp_tx_comp_process_tx_status(struct dp_soc *soc, vdev = peer->vdev; dp_tx_update_connectivity_stats(soc, vdev, tx_desc, ts->status); + dp_tx_update_uplink_delay(soc, vdev, ts); /* Update per-packet stats for mesh mode */ if (qdf_unlikely(vdev->mesh_vdev) && diff --git a/dp/wifi3.0/dp_tx.h b/dp/wifi3.0/dp_tx.h index c404d3c93b..b524e31399 100644 --- a/dp/wifi3.0/dp_tx.h +++ b/dp/wifi3.0/dp_tx.h @@ -771,4 +771,39 @@ dp_tx_hw_desc_update_evt(uint8_t *hal_tx_desc_cached, } #endif +#ifdef WLAN_FEATURE_TSF_UPLINK_DELAY +/** + * dp_set_delta_tsf() - Set delta_tsf to dp_soc structure + * @soc_hdl: cdp soc pointer + * @vdev_id: vdev id + * @delta_tsf: difference between TSF clock and qtimer + * + * Return: None + */ +void dp_set_delta_tsf(struct cdp_soc_t *soc_hdl, uint8_t vdev_id, + uint32_t delta_tsf); + +/** + * dp_set_tsf_report_ul_delay() - Enable or disable reporting uplink delay + * @soc_hdl: cdp soc pointer + * @vdev_id: vdev id + * @enable: true to enable and false to disable + * + * Return: QDF_STATUS + */ +QDF_STATUS dp_set_tsf_ul_delay_report(struct cdp_soc_t *soc_hdl, + uint8_t vdev_id, bool enable); + +/** + * dp_get_uplink_delay() - Get uplink delay value + * @soc_hdl: cdp soc pointer + * @vdev_id: vdev id + * @val: pointer to save uplink delay value + * + * Return: QDF_STATUS + */ +QDF_STATUS dp_get_uplink_delay(struct cdp_soc_t *soc_hdl, uint8_t vdev_id, + uint32_t *val); +#endif /* WLAN_FEATURE_TSF_UPLINK_TSF */ + #endif diff --git a/dp/wifi3.0/dp_types.h b/dp/wifi3.0/dp_types.h index 5aa4628f41..7667eadd02 100644 --- a/dp/wifi3.0/dp_types.h +++ b/dp/wifi3.0/dp_types.h @@ -3032,8 +3032,18 @@ struct dp_vdev { uint8_t latency_tid; } mesh_tid_latency_config; #endif -}; +#ifdef WLAN_FEATURE_TSF_UPLINK_DELAY + /* Indicate if uplink delay report is enabled or not */ + qdf_atomic_t ul_delay_report; + /* Delta between TQM clock and TSF clock */ + uint32_t delta_tsf; + /* accumulative delay for every TX completion */ + qdf_atomic_t ul_delay_accum; + /* accumulative number of packets delay has accumulated */ + qdf_atomic_t ul_pkts_accum; +#endif /* WLAN_FEATURE_TSF_UPLINK_DELAY */ +}; enum { dp_sec_mcast = 0,