diff --git a/dp/inc/cdp_txrx_cmn_struct.h b/dp/inc/cdp_txrx_cmn_struct.h index 489e109315ee..39d9ec1be180 100644 --- a/dp/inc/cdp_txrx_cmn_struct.h +++ b/dp/inc/cdp_txrx_cmn_struct.h @@ -436,6 +436,14 @@ typedef qdf_nbuf_t (*ol_txrx_tx_exc_fp)(void *data_vdev, struct cdp_tx_exception_metadata *tx_exc_metadata); +/** + * ol_txrx_completion_fp - top-level transmit function + * for tx completion + * @skb: skb data + * @osif_dev: the virtual device's OS shim object + */ +typedef void (*ol_txrx_completion_fp)(qdf_nbuf_t skb, + void *osif_dev); /** * ol_txrx_tx_flow_control_fp - tx flow control notification * function from txrx to OS shim @@ -593,6 +601,7 @@ struct ol_txrx_ops { ol_txrx_tx_fp tx; ol_txrx_tx_exc_fp tx_exception; ol_txrx_tx_free_ext_fp tx_free_ext; + ol_txrx_completion_fp tx_comp; } tx; /* rx function pointers - specified by OS shim, stored by txrx */ diff --git a/dp/wifi3.0/dp_tx.c b/dp/wifi3.0/dp_tx.c index 21bcd3d3af3e..66e5a1da8d0e 100644 --- a/dp/wifi3.0/dp_tx.c +++ b/dp/wifi3.0/dp_tx.c @@ -1847,8 +1847,9 @@ qdf_nbuf_t dp_tx_send_mesh(void *vap_dev, qdf_nbuf_t nbuf) if (nbuf_clone) { if (!dp_tx_send(vap_dev, nbuf_clone)) { DP_STATS_INC(vdev, tx_i.mesh.exception_fw, 1); - } else + } else { qdf_nbuf_free(nbuf_clone); + } } if (no_enc_frame) @@ -2624,6 +2625,91 @@ static void dp_tx_update_peer_stats(struct dp_peer *peer, } } +#ifdef QCA_LL_TX_FLOW_CONTROL_V2 +/** + * dp_tx_flow_pool_lock() - take flow pool lock + * @soc: core txrx main context + * @tx_desc: tx desc + * + * Return: None + */ +static inline +void dp_tx_flow_pool_lock(struct dp_soc *soc, + struct dp_tx_desc_s *tx_desc) +{ + struct dp_tx_desc_pool_s *pool; + uint8_t desc_pool_id; + + desc_pool_id = tx_desc->pool_id; + pool = &soc->tx_desc[desc_pool_id]; + + qdf_spin_lock_bh(&pool->flow_pool_lock); +} + +/** + * dp_tx_flow_pool_unlock() - release flow pool lock + * @soc: core txrx main context + * @tx_desc: tx desc + * + * Return: None + */ +static inline +void dp_tx_flow_pool_unlock(struct dp_soc *soc, + struct dp_tx_desc_s *tx_desc) +{ + struct dp_tx_desc_pool_s *pool; + uint8_t desc_pool_id; + + desc_pool_id = tx_desc->pool_id; + pool = &soc->tx_desc[desc_pool_id]; + + qdf_spin_unlock_bh(&pool->flow_pool_lock); +} +#else +static inline +void dp_tx_flow_pool_lock(struct dp_soc *soc, struct dp_tx_desc_s *tx_desc) +{ +} + +static inline +void dp_tx_flow_pool_unlock(struct dp_soc *soc, struct dp_tx_desc_s *tx_desc) +{ +} +#endif + +/** + * dp_tx_notify_completion() - Notify tx completion for this desc + * @soc: core txrx main context + * @tx_desc: tx desc + * @netbuf: buffer + * + * Return: none + */ +static inline void dp_tx_notify_completion(struct dp_soc *soc, + struct dp_tx_desc_s *tx_desc, + qdf_nbuf_t netbuf) +{ + void *osif_dev; + ol_txrx_completion_fp tx_compl_cbk = NULL; + + qdf_assert(tx_desc); + + dp_tx_flow_pool_lock(soc, tx_desc); + + if (!tx_desc->vdev || + !tx_desc->vdev->osif_vdev) { + dp_tx_flow_pool_unlock(soc, tx_desc); + return; + } + + osif_dev = tx_desc->vdev->osif_vdev; + tx_compl_cbk = tx_desc->vdev->tx_comp; + dp_tx_flow_pool_unlock(soc, tx_desc); + + if (tx_compl_cbk) + tx_compl_cbk(netbuf, osif_dev); +} + /** * dp_tx_comp_process_tx_status() - Parse and Dump Tx completion status info * @tx_desc: software descriptor head pointer @@ -2737,6 +2823,10 @@ static void dp_tx_comp_process_desc(struct dp_soc *soc, peer = dp_peer_find_by_id(soc, ts.peer_id); length = qdf_nbuf_len(desc->nbuf); + /* check tx completion notification */ + if (QDF_NBUF_CB_TX_EXTRA_FRAG_FLAGS_NOTIFY_COMP(desc->nbuf)) + dp_tx_notify_completion(soc, desc, desc->nbuf); + dp_tx_comp_process_tx_status(desc, length); /*currently m_copy/tx_capture is not supported for scatter gather packets*/ diff --git a/dp/wifi3.0/dp_types.h b/dp/wifi3.0/dp_types.h index 12f94f5fefc6..dab4a69b6cca 100644 --- a/dp/wifi3.0/dp_types.h +++ b/dp/wifi3.0/dp_types.h @@ -1216,6 +1216,10 @@ struct dp_vdev { ol_txrx_rx_mon_fp osif_rx_mon; ol_txrx_mcast_me_fp me_convert; + + /* completion function used by this vdev*/ + ol_txrx_completion_fp tx_comp; + /* deferred vdev deletion state */ struct { /* VDEV delete pending */ diff --git a/qdf/linux/src/i_qdf_nbuf.h b/qdf/linux/src/i_qdf_nbuf.h index 221ca4fe189f..7e5ecb7727a7 100644 --- a/qdf/linux/src/i_qdf_nbuf.h +++ b/qdf/linux/src/i_qdf_nbuf.h @@ -245,7 +245,7 @@ struct qdf_nbuf_cb { flag_chfrag_cont:1, flag_chfrag_end:1, flag_ext_header:1, - reserved:1; + flag_notify_comp:1; } bits; uint8_t u8; } flags; @@ -348,6 +348,8 @@ QDF_COMPILE_TIME_ASSERT(qdf_nbuf_cb_size, ((skb)->cb))->u.tx.flags.bits.flag_nbuf) #define QDF_NBUF_CB_TX_NUM_EXTRA_FRAGS(skb) \ (((struct qdf_nbuf_cb *)((skb)->cb))->u.tx.flags.bits.num) +#define QDF_NBUF_CB_TX_EXTRA_FRAG_FLAGS_NOTIFY_COMP(skb) \ + (((struct qdf_nbuf_cb *)((skb)->cb))->u.tx.flags.bits.flag_notify_comp) #define QDF_NBUF_CB_TX_EXTRA_FRAG_FLAGS_CHFRAG_START(skb) \ (((struct qdf_nbuf_cb *) \ ((skb)->cb))->u.tx.flags.bits.flag_chfrag_start)