diff --git a/dp/wifi3.0/be/dp_be.c b/dp/wifi3.0/be/dp_be.c index 7f47362cda..1d2f2fabcb 100644 --- a/dp/wifi3.0/be/dp_be.c +++ b/dp/wifi3.0/be/dp_be.c @@ -1779,6 +1779,7 @@ void dp_initialize_arch_ops_be(struct dp_arch_ops *arch_ops) dp_peer_rx_reorder_queue_setup_be; arch_ops->txrx_print_peer_stats = dp_print_peer_txrx_stats_be; arch_ops->dp_find_peer_by_destmac = dp_find_peer_by_destmac_be; + arch_ops->dp_tx_compute_hw_delay = dp_tx_compute_tx_delay_be; dp_init_near_full_arch_ops_be(arch_ops); arch_ops->get_rx_hash_key = dp_get_rx_hash_key_be; } diff --git a/dp/wifi3.0/be/dp_be_tx.c b/dp/wifi3.0/be/dp_be_tx.c index 803226cb3d..16e842793c 100644 --- a/dp/wifi3.0/be/dp_be_tx.c +++ b/dp/wifi3.0/be/dp_be_tx.c @@ -549,6 +549,20 @@ void dp_sawf_config_be(struct dp_soc *soc, uint32_t *hal_tx_desc_cached, uint16_t *fw_metadata, qdf_nbuf_t nbuf) { } + +static inline +QDF_STATUS dp_sawf_tx_enqueue_peer_stats(struct dp_soc *soc, + struct dp_tx_desc_s *tx_desc) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +QDF_STATUS dp_sawf_tx_enqueue_fail_peer_stats(struct dp_soc *soc, + struct dp_tx_desc_s *tx_desc) +{ + return QDF_STATUS_SUCCESS; +} #endif QDF_STATUS @@ -594,6 +608,7 @@ dp_tx_hw_enqueue_be(struct dp_soc *soc, struct dp_vdev *vdev, if (dp_sawf_tag_valid_get(tx_desc->nbuf)) { dp_sawf_config_be(soc, hal_tx_desc_cached, &fw_metadata, tx_desc->nbuf); + dp_sawf_tx_enqueue_peer_stats(soc, tx_desc); } hal_tx_desc_set_buf_addr_be(soc->hal_soc, hal_tx_desc_cached, @@ -644,6 +659,7 @@ dp_tx_hw_enqueue_be(struct dp_soc *soc, struct dp_vdev *vdev, dp_err("HAL RING Access Failed -- %pK", hal_ring_hdl); DP_STATS_INC(soc, tx.tcl_ring_full[ring_id], 1); DP_STATS_INC(vdev, tx_i.dropped.enqueue_fail, 1); + dp_sawf_tx_enqueue_fail_peer_stats(soc, tx_desc); return status; } @@ -652,6 +668,7 @@ dp_tx_hw_enqueue_be(struct dp_soc *soc, struct dp_vdev *vdev, dp_verbose_debug("TCL ring full ring_id:%d", ring_id); DP_STATS_INC(soc, tx.tcl_ring_full[ring_id], 1); DP_STATS_INC(vdev, tx_i.dropped.enqueue_fail, 1); + dp_sawf_tx_enqueue_fail_peer_stats(soc, tx_desc); goto ring_access_fail; } @@ -942,3 +959,81 @@ uint32_t dp_tx_comp_nf_handler(struct dp_intr *int_ctx, struct dp_soc *soc, return work_done; } #endif + +#if defined(WLAN_FEATURE_11BE_MLO) && defined(WLAN_MLO_MULTI_CHIP) && \ + defined(CONFIG_SAWF) +#define PPDUID_GET_HW_LINK_ID(PPDU_ID, LINK_ID_OFFSET, LINK_ID_BITS) \ + (((PPDU_ID) >> (LINK_ID_OFFSET)) & ((1 << (LINK_ID_BITS)) - 1)) + +#define HW_TX_DELAY_MAX 0x1000000 +#define TX_COMPL_SHIFT_BUFFER_TIMESTAMP_US 10 +#define HW_TX_DELAY_MASK 0x1FFFFFFF +#define TX_COMPL_BUFFER_TSTAMP_US(TSTAMP) \ + (((TSTAMP) << TX_COMPL_SHIFT_BUFFER_TIMESTAMP_US) & \ + HW_TX_DELAY_MASK) + +static inline +QDF_STATUS dp_mlo_compute_hw_delay_us(struct dp_soc *soc, + struct dp_vdev *vdev, + struct hal_tx_completion_status *ts, + uint32_t *delay_us) +{ + uint32_t ppdu_id; + uint8_t link_id_offset, link_id_bits; + uint8_t hw_link_id; + uint32_t msdu_tqm_enqueue_tstamp_us, final_msdu_tqm_enqueue_tstamp_us; + uint32_t msdu_compl_tsf_tstamp_us, final_msdu_compl_tsf_tstamp_us; + uint32_t delay; + int32_t delta_tsf2, delta_tqm; + + if (!ts->valid) + return QDF_STATUS_E_INVAL; + + link_id_offset = soc->link_id_offset; + link_id_bits = soc->link_id_bits; + ppdu_id = ts->ppdu_id; + hw_link_id = PPDUID_GET_HW_LINK_ID(ppdu_id, link_id_offset, + link_id_bits); + + msdu_tqm_enqueue_tstamp_us = + TX_COMPL_BUFFER_TSTAMP_US(ts->buffer_timestamp); + msdu_compl_tsf_tstamp_us = ts->tsf; + + delta_tsf2 = dp_mlo_get_delta_tsf2_wrt_mlo_offset(soc, hw_link_id); + delta_tqm = dp_mlo_get_delta_tqm_wrt_mlo_offset(soc); + + final_msdu_tqm_enqueue_tstamp_us = (msdu_tqm_enqueue_tstamp_us + + delta_tqm) & HW_TX_DELAY_MASK; + + final_msdu_compl_tsf_tstamp_us = (msdu_compl_tsf_tstamp_us + + delta_tsf2) & HW_TX_DELAY_MASK; + + delay = (final_msdu_compl_tsf_tstamp_us - + final_msdu_tqm_enqueue_tstamp_us) & HW_TX_DELAY_MASK; + + if (delay > HW_TX_DELAY_MAX) + return QDF_STATUS_E_FAILURE; + + if (delay_us) + *delay_us = delay; + + return QDF_STATUS_SUCCESS; +} +#else +static inline +QDF_STATUS dp_mlo_compute_hw_delay_us(struct dp_soc *soc, + struct dp_vdev *vdev, + struct hal_tx_completion_status *ts, + uint32_t *delay_us) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +QDF_STATUS dp_tx_compute_tx_delay_be(struct dp_soc *soc, + struct dp_vdev *vdev, + struct hal_tx_completion_status *ts, + uint32_t *delay_us) +{ + return dp_mlo_compute_hw_delay_us(soc, vdev, ts, delay_us); +} diff --git a/dp/wifi3.0/be/dp_be_tx.h b/dp/wifi3.0/be/dp_be_tx.h index 100b0b9ae3..60934f9852 100644 --- a/dp/wifi3.0/be/dp_be_tx.h +++ b/dp/wifi3.0/be/dp_be_tx.h @@ -226,4 +226,18 @@ uint32_t dp_tx_comp_nf_handler(struct dp_intr *int_ctx, struct dp_soc *soc, return 0; } #endif /* WLAN_FEATURE_NEAR_FULL_IRQ */ + +/** + * dp_tx_compute_tx_delay_be() - Compute HW Tx completion delay + * @soc: Handle to DP Soc structure + * @vdev: vdev + * @ts: Tx completion status + * @delay_us: Delay to be calculated in microseconds + * + * Return: QDF_STATUS + */ +QDF_STATUS dp_tx_compute_tx_delay_be(struct dp_soc *soc, + struct dp_vdev *vdev, + struct hal_tx_completion_status *ts, + uint32_t *delay_us); #endif diff --git a/dp/wifi3.0/dp_types.h b/dp/wifi3.0/dp_types.h index 3e51d78f6e..a6ac3d122a 100644 --- a/dp/wifi3.0/dp_types.h +++ b/dp/wifi3.0/dp_types.h @@ -1863,6 +1863,11 @@ struct dp_arch_ops { struct dp_peer *(*dp_find_peer_by_destmac)(struct dp_soc *soc, uint8_t *dest_mac_addr, uint8_t vdev_id); + QDF_STATUS + (*dp_tx_compute_hw_delay)(struct dp_soc *soc, + struct dp_vdev *vdev, + struct hal_tx_completion_status *ts, + uint32_t *delay_us); }; /** diff --git a/dp/wifi3.0/li/dp_li.c b/dp/wifi3.0/li/dp_li.c index bca978a29d..b01ff48e62 100644 --- a/dp/wifi3.0/li/dp_li.c +++ b/dp/wifi3.0/li/dp_li.c @@ -607,6 +607,7 @@ void dp_initialize_arch_ops_li(struct dp_arch_ops *arch_ops) arch_ops->dp_peer_rx_reorder_queue_setup = dp_peer_rx_reorder_queue_setup_li; arch_ops->dp_find_peer_by_destmac = dp_find_peer_by_destmac_li; + arch_ops->dp_tx_compute_hw_delay = dp_tx_compute_tx_delay_li; } #ifdef QCA_DP_TX_HW_SW_NBUF_DESC_PREFETCH diff --git a/dp/wifi3.0/li/dp_li_tx.c b/dp/wifi3.0/li/dp_li_tx.c index d579f78679..d1a8a7576a 100644 --- a/dp/wifi3.0/li/dp_li_tx.c +++ b/dp/wifi3.0/li/dp_li_tx.c @@ -368,6 +368,15 @@ void dp_sawf_config_li(struct dp_soc *soc, uint32_t *hal_tx_desc_cached, hal_tx_desc_set_search_index_li(soc->hal_soc, hal_tx_desc_cached, search_index); } + +static inline +QDF_STATUS dp_tx_compute_hw_delay_li(struct dp_soc *soc, + struct dp_vdev *vdev, + struct hal_tx_completion_status *ts, + uint32_t *delay_us) +{ + return dp_tx_compute_hw_delay_us(ts, vdev->delta_tsf, delay_us); +} #else static inline void dp_sawf_config_li(struct dp_soc *soc, uint32_t *hal_tx_desc_cached, @@ -376,6 +385,15 @@ void dp_sawf_config_li(struct dp_soc *soc, uint32_t *hal_tx_desc_cached, { } +static inline +QDF_STATUS dp_tx_compute_hw_delay_li(struct dp_soc *soc, + struct dp_vdev *vdev, + struct hal_tx_completion_status *ts, + uint32_t *delay_us) +{ + return QDF_STATUS_SUCCESS; +} + #define dp_sawf_tx_enqueue_peer_stats(soc, tx_desc) #define dp_sawf_tx_enqueue_fail_peer_stats(soc, tx_desc) #endif @@ -554,3 +572,11 @@ void dp_tx_desc_pool_deinit_li(struct dp_soc *soc, uint8_t pool_id) { } + +QDF_STATUS dp_tx_compute_tx_delay_li(struct dp_soc *soc, + struct dp_vdev *vdev, + struct hal_tx_completion_status *ts, + uint32_t *delay_us) +{ + return dp_tx_compute_hw_delay_li(soc, vdev, ts, delay_us); +} diff --git a/dp/wifi3.0/li/dp_li_tx.h b/dp/wifi3.0/li/dp_li_tx.h index c282b05e96..26f64c4533 100644 --- a/dp/wifi3.0/li/dp_li_tx.h +++ b/dp/wifi3.0/li/dp_li_tx.h @@ -93,4 +93,18 @@ QDF_STATUS dp_tx_desc_pool_init_li(struct dp_soc *soc, void dp_tx_desc_pool_deinit_li(struct dp_soc *soc, struct dp_tx_desc_pool_s *tx_desc_pool, uint8_t pool_id); + +/** + * dp_tx_compute_tx_delay_li() - Compute HW Tx completion delay + * @soc: Handle to DP Soc structure + * @vdev: vdev + * @ts: Tx completion status + * @delay_us: Delay to be calculated in microseconds + * + * Return: QDF_STATUS + */ +QDF_STATUS dp_tx_compute_tx_delay_li(struct dp_soc *soc, + struct dp_vdev *vdev, + struct hal_tx_completion_status *ts, + uint32_t *delay_us); #endif