diff --git a/dp/wifi3.0/dp_tx.c b/dp/wifi3.0/dp_tx.c index 68d332c84379..972fa3949b00 100644 --- a/dp/wifi3.0/dp_tx.c +++ b/dp/wifi3.0/dp_tx.c @@ -1562,6 +1562,36 @@ dp_tx_hw_desc_update_evt(uint8_t *hal_tx_desc_cached, } #endif +#if defined(CLEAR_SW2TCL_CONSUMED_DESC) +/** + * dp_tx_clear_consumed_hw_descs - Reset all the consumed Tx ring descs to 0 + * + * @soc: DP soc handle + * @hal_ring_hdl: Source ring pointer + * + * Return: void + */ +static inline +void dp_tx_clear_consumed_hw_descs(struct dp_soc *soc, + hal_ring_handle_t hal_ring_hdl) +{ + void *desc = hal_srng_src_get_next_consumed(soc->hal_soc, hal_ring_hdl); + + while (desc) { + hal_tx_desc_clear(desc); + desc = hal_srng_src_get_next_consumed(soc->hal_soc, + hal_ring_hdl); + } +} + +#else +static inline +void dp_tx_clear_consumed_hw_descs(struct dp_soc *soc, + hal_ring_handle_t hal_ring_hdl) +{ +} +#endif /* CLEAR_SW2TCL_CONSUMED_DESC */ + /** * dp_tx_hw_enqueue() - Enqueue to TCL HW for transmit * @soc: DP Soc Handle @@ -1697,6 +1727,8 @@ dp_tx_hw_enqueue(struct dp_soc *soc, struct dp_vdev *vdev, return status; } + dp_tx_clear_consumed_hw_descs(soc, hal_ring_hdl); + /* Sync cached descriptor with HW */ hal_tx_desc = hal_srng_src_get_next(soc->hal_soc, hal_ring_hdl); diff --git a/hal/wifi3.0/hal_api.h b/hal/wifi3.0/hal_api.h index a510a2e26f2a..ba9dce42dbe1 100644 --- a/hal/wifi3.0/hal_api.h +++ b/hal/wifi3.0/hal_api.h @@ -1764,6 +1764,48 @@ void hal_get_sw_hptp(void *hal_soc, hal_ring_handle_t hal_ring_hdl, } } +#if defined(CLEAR_SW2TCL_CONSUMED_DESC) +/** + * hal_srng_src_get_next_consumed - Get the next desc if consumed by HW + * + * @hal_soc: Opaque HAL SOC handle + * @hal_ring_hdl: Source ring pointer + * + * Return: pointer to descriptor if consumed by HW, else NULL + */ +static inline +void *hal_srng_src_get_next_consumed(void *hal_soc, + hal_ring_handle_t hal_ring_hdl) +{ + struct hal_srng *srng = (struct hal_srng *)hal_ring_hdl; + uint32_t *desc = NULL; + /* TODO: Using % is expensive, but we have to do this since + * size of some SRNG rings is not power of 2 (due to descriptor + * sizes). Need to create separate API for rings used + * per-packet, with sizes power of 2 (TCL2SW, REO2SW, + * SW2RXDMA and CE rings) + */ + uint32_t next_entry = (srng->last_desc_cleared + srng->entry_size) % + srng->ring_size; + + if (next_entry != (srng->u.src_ring.cached_tp + srng->entry_size) % + srng->ring_size) { + desc = &srng->ring_base_vaddr[next_entry]; + srng->last_desc_cleared = next_entry; + } + + return desc; +} + +#else +static inline +void *hal_srng_src_get_next_consumed(void *hal_soc, + hal_ring_handle_t hal_ring_hdl) +{ + return NULL; +} +#endif /* CLEAR_SW2TCL_CONSUMED_DESC */ + /** * hal_srng_src_get_next - Get next entry from a source ring and move cached tail pointer * diff --git a/hal/wifi3.0/hal_internal.h b/hal/wifi3.0/hal_internal.h index 9be3976e6fe5..a8857c89c96e 100644 --- a/hal/wifi3.0/hal_internal.h +++ b/hal/wifi3.0/hal_internal.h @@ -472,6 +472,10 @@ struct hal_srng { unsigned long srng_event; /* last flushed time stamp */ uint64_t last_flush_ts; +#if defined(CLEAR_SW2TCL_CONSUMED_DESC) + /* last ring desc entry cleared */ + uint32_t last_desc_cleared; +#endif #if defined(FEATURE_HAL_DELAYED_REG_WRITE) || \ defined(FEATURE_HAL_DELAYED_REG_WRITE_V2) /* Previous hp/tp (based on ring dir) value written to the reg */ diff --git a/hal/wifi3.0/hal_tx.h b/hal/wifi3.0/hal_tx.h index 044fe2fa6350..7cc5e61033b0 100644 --- a/hal/wifi3.0/hal_tx.h +++ b/hal/wifi3.0/hal_tx.h @@ -463,6 +463,19 @@ static inline void hal_tx_desc_set_hlos_tid(void *desc, HAL_SET_FLD(desc, TCL_DATA_CMD_4, HLOS_TID_OVERWRITE) |= HAL_TX_SM(TCL_DATA_CMD_4, HLOS_TID_OVERWRITE, 1); } + +/** + * hal_tx_desc_clear - Clear the HW descriptor entry + * @hw_desc: Hardware descriptor to be cleared + * + * Return: void + */ +static inline void hal_tx_desc_clear(void *hw_desc) +{ + qdf_mem_set(hw_desc + sizeof(struct tlv_32_hdr), + HAL_TX_DESC_LEN_BYTES, 0); +} + /** * hal_tx_desc_sync - Commit the descriptor to Hardware * @hal_tx_des_cached: Cached descriptor that software maintains