diff --git a/dp/wifi3.0/be/dp_be_tx.c b/dp/wifi3.0/be/dp_be_tx.c index 9948cdb2e9..7d9263eb1b 100644 --- a/dp/wifi3.0/be/dp_be_tx.c +++ b/dp/wifi3.0/be/dp_be_tx.c @@ -1514,6 +1514,9 @@ qdf_nbuf_t dp_tx_fast_send_be(struct cdp_soc_t *soc_hdl, uint8_t vdev_id, tx_desc->flags |= DP_TX_DESC_FLAG_SIMPLE; tx_desc->nbuf->fast_recycled = 1; + if (nbuf->is_from_recycler && nbuf->fast_xmit) + tx_desc->flags |= DP_TX_DESC_FLAG_FAST; + paddr = dp_tx_nbuf_map_be(vdev, tx_desc, nbuf); if (!paddr) { /* Handle failure */ diff --git a/dp/wifi3.0/dp_tx.c b/dp/wifi3.0/dp_tx.c index a4e7396519..6d7f090dfc 100644 --- a/dp/wifi3.0/dp_tx.c +++ b/dp/wifi3.0/dp_tx.c @@ -5400,14 +5400,8 @@ void dp_tx_prefetch_next_nbuf_data(struct dp_tx_desc_s *next) if (next) nbuf = next->nbuf; - if (nbuf) { - /* prefetch skb->next and first few bytes of skb->cb */ - qdf_prefetch(next->shinfo_addr); + if (nbuf) qdf_prefetch(nbuf); - /* prefetch skb fields present in different cachelines */ - qdf_prefetch(&nbuf->len); - qdf_prefetch(&nbuf->users); - } } #else static inline @@ -5460,6 +5454,50 @@ dp_tx_mcast_reinject_handler(struct dp_soc *soc, struct dp_tx_desc_s *desc) } #endif +#ifdef QCA_DP_TX_NBUF_LIST_FREE +static inline void +dp_tx_nbuf_queue_head_init(qdf_nbuf_queue_head_t *nbuf_queue_head) +{ + qdf_nbuf_queue_head_init(nbuf_queue_head); +} + +static inline void +dp_tx_nbuf_dev_queue_free(qdf_nbuf_queue_head_t *nbuf_queue_head, + struct dp_tx_desc_s *desc) +{ + qdf_nbuf_t nbuf = NULL; + + nbuf = desc->nbuf; + if (qdf_likely(desc->flags & DP_TX_DESC_FLAG_FAST)) + qdf_nbuf_dev_queue_head(nbuf_queue_head, nbuf); + else + qdf_nbuf_free(nbuf); +} + +static inline void +dp_tx_nbuf_dev_kfree_list(qdf_nbuf_queue_head_t *nbuf_queue_head) +{ + qdf_nbuf_dev_kfree_list(nbuf_queue_head); +} +#else +static inline void +dp_tx_nbuf_queue_head_init(qdf_nbuf_queue_head_t *nbuf_queue_head) +{ +} + +static inline void +dp_tx_nbuf_dev_queue_free(qdf_nbuf_queue_head_t *nbuf_queue_head, + struct dp_tx_desc_s *desc) +{ + qdf_nbuf_free(desc->nbuf); +} + +static inline void +dp_tx_nbuf_dev_kfree_list(qdf_nbuf_queue_head_t *nbuf_queue_head) +{ +} +#endif + /** * dp_tx_comp_process_desc_list() - Tx complete software descriptor handler * @soc: core txrx main context @@ -5481,9 +5519,12 @@ dp_tx_comp_process_desc_list(struct dp_soc *soc, struct dp_txrx_peer *txrx_peer = NULL; uint16_t peer_id = DP_INVALID_PEER; dp_txrx_ref_handle txrx_ref_handle = NULL; + qdf_nbuf_queue_head_t h; desc = comp_head; + dp_tx_nbuf_queue_head_init(&h); + while (desc) { next = desc->next; dp_tx_prefetch_next_nbuf_data(next); @@ -5534,7 +5575,7 @@ dp_tx_comp_process_desc_list(struct dp_soc *soc, dp_tx_desc_history_add(soc, desc->dma_addr, desc->nbuf, desc->id, DP_TX_COMP_UNMAP); dp_tx_nbuf_unmap(soc, desc); - qdf_nbuf_free_simple(desc->nbuf); + dp_tx_nbuf_dev_queue_free(&h, desc); dp_tx_desc_free(soc, desc, desc->pool_id); desc = next; continue; @@ -5550,6 +5591,7 @@ dp_tx_comp_process_desc_list(struct dp_soc *soc, dp_tx_desc_release(desc, desc->pool_id); desc = next; } + dp_tx_nbuf_dev_kfree_list(&h); if (txrx_peer) dp_txrx_peer_unref_delete(txrx_ref_handle, DP_MOD_ID_TX_COMP); } diff --git a/dp/wifi3.0/dp_tx.h b/dp/wifi3.0/dp_tx.h index 6a8fb90bc7..04f7353135 100644 --- a/dp/wifi3.0/dp_tx.h +++ b/dp/wifi3.0/dp_tx.h @@ -64,9 +64,10 @@ /* * Since the Tx descriptor flag is of only 16-bit and no more bit is free for * any new flag, therefore for time being overloading PPEDS flag with that of - * FLUSH flag. + * FLUSH flag and FLAG_FAST with TDLS which is not enabled for WIN. */ #define DP_TX_DESC_FLAG_PPEDS 0x2000 +#define DP_TX_DESC_FLAG_FAST 0x100 #define DP_TX_EXT_DESC_FLAG_METADATA_VALID 0x1 diff --git a/qdf/inc/qdf_nbuf.h b/qdf/inc/qdf_nbuf.h index 18abc3766d..0961a1ad34 100644 --- a/qdf/inc/qdf_nbuf.h +++ b/qdf/inc/qdf_nbuf.h @@ -1375,6 +1375,18 @@ void qdf_nbuf_queue_head_purge(qdf_nbuf_queue_head_t *nbuf_queue_head) return __qdf_nbuf_queue_head_purge(nbuf_queue_head); } +/** + * qdf_nbuf_queue_empty() - dequeue nbuf from the head of queue + * @nbuf_queue_head: pointer to nbuf queue head + * + * Return: true if queue is empty else false + */ +static inline +int qdf_nbuf_queue_empty(qdf_nbuf_queue_head_t *nbuf_queue_head) +{ + return __qdf_nbuf_queue_empty(nbuf_queue_head); +} + /** * qdf_nbuf_queue_head_lock() - Acquire the nbuf_queue_head lock * @head: nbuf_queue_head of the nbuf_list for which lock is to be acquired @@ -2233,6 +2245,21 @@ qdf_nbuf_t qdf_nbuf_unshare_debug(qdf_nbuf_t buf, const char *func_name, uint32_t line_num); +/** + * qdf_nbuf_kfree_list() - Free nbuf list using kfree + * @buf: Pointer to network buffer head + * + * This function is called to free the nbuf list on failure cases + * + * Return: None + */ +#define qdf_nbuf_dev_kfree_list(d) \ + qdf_nbuf_dev_kfree_list_debug(d, __func__, __LINE__) + +void +qdf_nbuf_dev_kfree_list_debug(qdf_nbuf_queue_head_t *nbuf_queue_head, + const char *func_name, + uint32_t line_num); #else /* NBUF_MEMORY_DEBUG */ static inline void qdf_net_buf_debug_init(void) {} @@ -2362,8 +2389,38 @@ static inline qdf_nbuf_t qdf_nbuf_unshare(qdf_nbuf_t buf) { return __qdf_nbuf_unshare(buf); } + +/** + * qdf_nbuf_kfree_list() - Free nbuf list using kfree + * @buf: Pointer to network buffer head + * + * This function is called to free the nbuf list on failure cases + * + * Return: None + */ +static inline void +qdf_nbuf_dev_kfree_list(qdf_nbuf_queue_head_t *nbuf_queue_head) +{ + __qdf_nbuf_dev_kfree_list(nbuf_queue_head); +} #endif /* NBUF_MEMORY_DEBUG */ +/** + * qdf_nbuf_dev_queue_head() - Queue a buffer at the list head + * @nbuf_queue_head: Pointer to buffer list head + * @buff: Pointer to network buffer head + * + * This function is called to queue a buffer at the list head + * + * Return: None + */ +static inline void +qdf_nbuf_dev_queue_head(qdf_nbuf_queue_head_t *nbuf_queue_head, + qdf_nbuf_t buf) +{ + __qdf_nbuf_dev_queue_head(nbuf_queue_head, buf); +} + /** * qdf_nbuf_kfree() - Free nbuf using kfree * @buf: Pointer to network buffer diff --git a/qdf/linux/src/i_qdf_nbuf.h b/qdf/linux/src/i_qdf_nbuf.h index 4a652faa5c..6568547595 100644 --- a/qdf/linux/src/i_qdf_nbuf.h +++ b/qdf/linux/src/i_qdf_nbuf.h @@ -2595,6 +2595,12 @@ void __qdf_nbuf_queue_head_purge(struct sk_buff_head *skb_queue_head) return skb_queue_purge(skb_queue_head); } +static inline +int __qdf_nbuf_queue_empty(__qdf_nbuf_queue_head_t *nbuf_queue_head) +{ + return skb_queue_empty(nbuf_queue_head); +} + /** * __qdf_nbuf_queue_head_lock() - Acquire the skb list lock * @head: skb list for which lock is to be acquired @@ -2905,6 +2911,33 @@ static inline void __qdf_nbuf_kfree(struct sk_buff *skb) kfree_skb(skb); } +/** + * __qdf_nbuf_dev_kfree_list() - Free nbuf list using dev based os call + * @skb_queue_head: Pointer to nbuf queue head + * + * This function is called to free the nbuf list on failure cases + * + * Return: None + */ +void +__qdf_nbuf_dev_kfree_list(__qdf_nbuf_queue_head_t *nbuf_queue_head); + +/** + * __qdf_nbuf_dev_queue_head() - queue a buffer using dev at the list head + * @skb_queue_head: Pointer to skb list head + * @buff: Pointer to nbuf + * + * This function is called to queue buffer at the skb list head + * + * Return: None + */ +static inline void +__qdf_nbuf_dev_queue_head(__qdf_nbuf_queue_head_t *nbuf_queue_head, + __qdf_nbuf_t buff) +{ + __skb_queue_head(nbuf_queue_head, buff); +} + /** * __qdf_nbuf_dev_kfree() - Free nbuf using dev based os call * @buf: Pointer to network buffer diff --git a/qdf/linux/src/qdf_nbuf.c b/qdf/linux/src/qdf_nbuf.c index 536d6354a6..e3424ef1ed 100644 --- a/qdf/linux/src/qdf_nbuf.c +++ b/qdf/linux/src/qdf_nbuf.c @@ -746,6 +746,21 @@ __qdf_nbuf_t __qdf_nbuf_clone(__qdf_nbuf_t skb) qdf_export_symbol(__qdf_nbuf_clone); +#ifdef QCA_DP_TX_NBUF_LIST_FREE +void +__qdf_nbuf_dev_kfree_list(__qdf_nbuf_queue_head_t *nbuf_queue_head) +{ + dev_kfree_skb_list_fast(nbuf_queue_head); +} +#else +void +__qdf_nbuf_dev_kfree_list(__qdf_nbuf_queue_head_t *nbuf_queue_head) +{ +} +#endif + +qdf_export_symbol(__qdf_nbuf_dev_kfree_list); + #ifdef NBUF_MEMORY_DEBUG struct qdf_nbuf_event { qdf_nbuf_t nbuf; @@ -3892,6 +3907,23 @@ unshare_buf: qdf_export_symbol(qdf_nbuf_unshare_debug); +void +qdf_nbuf_dev_kfree_list_debug(__qdf_nbuf_queue_head_t *nbuf_queue_head, + const char *func, uint32_t line) +{ + qdf_nbuf_t buf; + + if (qdf_nbuf_queue_empty(nbuf_queue_head)) + return; + + if (is_initial_mem_debug_disabled) + return __qdf_nbuf_dev_kfree_list(nbuf_queue_head); + + while ((buf = qdf_nbuf_queue_head_dequeue(nbuf_queue_head)) != NULL) + qdf_nbuf_free_debug(buf, func, line); +} + +qdf_export_symbol(qdf_nbuf_dev_kfree_list_debug); #endif /* NBUF_MEMORY_DEBUG */ #if defined(FEATURE_TSO)