diff --git a/dp/inc/cdp_txrx_cmn_struct.h b/dp/inc/cdp_txrx_cmn_struct.h index 49630a60cd..1cf1a01241 100644 --- a/dp/inc/cdp_txrx_cmn_struct.h +++ b/dp/inc/cdp_txrx_cmn_struct.h @@ -541,6 +541,9 @@ struct cdp_tx_exception_metadata { enum cdp_sec_type sec_type; uint8_t is_tx_sniffer; uint16_t ppdu_cookie; +#ifdef QCA_SUPPORT_WDS_EXTENDED + uint8_t is_wds_extended; +#endif }; typedef struct cdp_soc_t *ol_txrx_soc_handle; diff --git a/dp/wifi3.0/dp_tx.c b/dp/wifi3.0/dp_tx.c index 3b3198bad9..c1bc6609c5 100644 --- a/dp/wifi3.0/dp_tx.c +++ b/dp/wifi3.0/dp_tx.c @@ -794,6 +794,82 @@ static void dp_tx_trace_pkt(qdf_nbuf_t skb, uint16_t msdu_id, } #endif +#ifdef QCA_SUPPORT_WDS_EXTENDED +/** + * dp_is_tx_extended() - Configure AST override from peer ast entry + * + * @vdev: DP vdev handle + * @tx_exc_metadata: Handle that holds exception path metadata + * + * Return: if this packet needs to exception to FW or not + * (false: exception to wlan FW, true: do not exception) + */ +static inline bool +dp_is_tx_extended(struct dp_vdev *vdev, struct cdp_tx_exception_metadata + *tx_exc_metadata) +{ + if (qdf_likely(!vdev->wds_ext_enabled)) + return false; + + if (tx_exc_metadata && !tx_exc_metadata->is_wds_extended) + return false; + + return true; +} + +/** + * dp_tx_wds_ext() - Configure AST override from peer ast entry + * + * @soc: DP soc handle + * @vdev: DP vdev handle + * @peer_id: peer_id of the peer for which packet is destined + * @msdu_info: MSDU info to be setup in MSDU descriptor and MSDU extension desc. + * + * Return: None + */ +static inline void +dp_tx_wds_ext(struct dp_soc *soc, struct dp_vdev *vdev, uint16_t peer_id, + struct dp_tx_msdu_info_s *msdu_info) +{ + struct dp_peer *peer = NULL; + + msdu_info->search_type = vdev->search_type; + msdu_info->ast_idx = vdev->bss_ast_idx; + msdu_info->ast_hash = vdev->bss_ast_hash; + + if (qdf_likely(!vdev->wds_ext_enabled)) + return; + + peer = dp_peer_get_ref_by_id(soc, peer_id, DP_MOD_ID_TX); + + if (qdf_unlikely(!peer)) + return; + + msdu_info->search_type = HAL_TX_ADDR_INDEX_SEARCH; + msdu_info->ast_idx = peer->self_ast_entry->ast_idx; + msdu_info->ast_hash = peer->self_ast_entry->ast_hash_value; + dp_peer_unref_delete(peer, DP_MOD_ID_TX); + msdu_info->exception_fw = 0; +} +#else + +static inline bool +dp_is_tx_extended(struct dp_vdev *vdev, struct cdp_tx_exception_metadata + *tx_exc_metadata) +{ + return false; +} + +static inline void +dp_tx_wds_ext(struct dp_soc *soc, struct dp_vdev *vdev, uint16_t peer_id, + struct dp_tx_msdu_info_s *msdu_info) +{ + msdu_info->search_type = vdev->search_type; + msdu_info->ast_idx = vdev->bss_ast_idx; + msdu_info->ast_hash = vdev->bss_ast_hash; +} +#endif + /** * dp_tx_desc_prepare_single - Allocate and prepare Tx descriptor * @vdev: DP vdev handle @@ -849,6 +925,9 @@ struct dp_tx_desc_s *dp_tx_prepare_desc_single(struct dp_vdev *vdev, goto failure; } + if (qdf_unlikely(dp_is_tx_extended(vdev, tx_exc_metadata))) + return tx_desc; + /* * For special modes (vdev_type == ocb or mesh), data frames should be * transmitted using varying transmit parameters (tx spec) which include @@ -1255,16 +1334,19 @@ dp_tx_ring_access_end(struct dp_soc *soc, hal_ring_handle_t hal_ring_hdl, * Return: QDF_STATUS_SUCCESS: success * QDF_STATUS_E_RESOURCES: Error return */ -static QDF_STATUS dp_tx_hw_enqueue(struct dp_soc *soc, struct dp_vdev *vdev, - struct dp_tx_desc_s *tx_desc, uint8_t tid, - uint16_t fw_metadata, uint8_t ring_id, - struct cdp_tx_exception_metadata - *tx_exc_metadata) +static QDF_STATUS +dp_tx_hw_enqueue(struct dp_soc *soc, struct dp_vdev *vdev, + struct dp_tx_desc_s *tx_desc, uint16_t fw_metadata, + struct cdp_tx_exception_metadata *tx_exc_metadata, + struct dp_tx_msdu_info_s *msdu_info) { uint8_t type; void *hal_tx_desc; uint32_t *hal_tx_desc_cached; int coalesce = 0; + struct dp_tx_queue *tx_q = &msdu_info->tx_queue; + uint8_t ring_id = tx_q->ring_id & DP_TX_QUEUE_MASK; + uint8_t tid = msdu_info->tid; /* * Setting it initialization statically here to avoid @@ -1314,16 +1396,16 @@ static QDF_STATUS dp_tx_hw_enqueue(struct dp_soc *soc, struct dp_vdev *vdev, hal_tx_desc_set_lmac_id(soc->hal_soc, hal_tx_desc_cached, vdev->lmac_id); hal_tx_desc_set_search_type(soc->hal_soc, hal_tx_desc_cached, - vdev->search_type); + msdu_info->search_type); hal_tx_desc_set_search_index(soc->hal_soc, hal_tx_desc_cached, - vdev->bss_ast_idx); + msdu_info->ast_idx); hal_tx_desc_set_dscp_tid_table_id(soc->hal_soc, hal_tx_desc_cached, vdev->dscp_tid_map_id); hal_tx_desc_set_encrypt_type(hal_tx_desc_cached, sec_type_map[sec_type]); hal_tx_desc_set_cache_set_num(soc->hal_soc, hal_tx_desc_cached, - (vdev->bss_ast_hash & 0xF)); + (msdu_info->ast_hash & 0xF)); hal_tx_desc_set_fw_metadata(hal_tx_desc_cached, fw_metadata); hal_tx_desc_set_buf_length(hal_tx_desc_cached, tx_desc->length); @@ -1955,8 +2037,8 @@ dp_tx_send_msdu_single(struct dp_vdev *vdev, qdf_nbuf_t nbuf, } /* Enqueue the Tx MSDU descriptor to HW for transmit */ - status = dp_tx_hw_enqueue(soc, vdev, tx_desc, tid, - htt_tcl_metadata, tx_q->ring_id, tx_exc_metadata); + status = dp_tx_hw_enqueue(soc, vdev, tx_desc, htt_tcl_metadata, + tx_exc_metadata, msdu_info); if (status != QDF_STATUS_SUCCESS) { QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR, @@ -2087,8 +2169,8 @@ qdf_nbuf_t dp_tx_send_msdu_multiple(struct dp_vdev *vdev, qdf_nbuf_t nbuf, /* * Enqueue the Tx MSDU descriptor to HW for transmit */ - status = dp_tx_hw_enqueue(soc, vdev, tx_desc, msdu_info->tid, - htt_tcl_metadata, tx_q->ring_id, NULL); + status = dp_tx_hw_enqueue(soc, vdev, tx_desc, htt_tcl_metadata, + NULL, msdu_info); if (status != QDF_STATUS_SUCCESS) { QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR, @@ -2420,6 +2502,52 @@ static bool dp_check_exc_metadata(struct cdp_tx_exception_metadata *tx_exc) return true; } +#ifdef ATH_SUPPORT_IQUE +/** + * dp_tx_mcast_enhance() - Multicast enhancement on TX + * @vdev: vdev handle + * @nbuf: skb + * + * Return: true on success, + * false on failure + */ +static inline bool dp_tx_mcast_enhance(struct dp_vdev *vdev, qdf_nbuf_t nbuf) +{ + qdf_ether_header_t *eh; + + /* Mcast to Ucast Conversion*/ + if (qdf_likely(!vdev->mcast_enhancement_en)) + return true; + + eh = (qdf_ether_header_t *)qdf_nbuf_data(nbuf); + if (DP_FRAME_IS_MULTICAST((eh)->ether_dhost) && + !DP_FRAME_IS_BROADCAST((eh)->ether_dhost)) { + dp_verbose_debug("Mcast frm for ME %pK", vdev); + + DP_STATS_INC_PKT(vdev, tx_i.mcast_en.mcast_pkt, 1, + qdf_nbuf_len(nbuf)); + if (dp_tx_prepare_send_me(vdev, nbuf) == + QDF_STATUS_SUCCESS) { + return false; + } + + if (qdf_unlikely(vdev->igmp_mcast_enhanc_en > 0)) { + if (dp_tx_prepare_send_igmp_me(vdev, nbuf) == + QDF_STATUS_SUCCESS) { + return false; + } + } + } + + return true; +} +#else +static inline bool dp_tx_mcast_enhance(struct dp_vdev *vdev, qdf_nbuf_t nbuf) +{ + return true; +} +#endif + /** * dp_tx_per_pkt_vdev_id_check() - vdev id check for frame * @nbuf: qdf_nbuf_t @@ -2489,6 +2617,7 @@ dp_tx_send_exception(struct cdp_soc_t *soc_hdl, uint8_t vdev_id, goto fail; msdu_info.tid = tx_exc_metadata->tid; + dp_tx_wds_ext(soc, vdev, tx_exc_metadata->peer_id, &msdu_info); eh = (qdf_ether_header_t *)qdf_nbuf_data(nbuf); dp_verbose_debug("skb "QDF_MAC_ADDR_FMT, @@ -2511,32 +2640,46 @@ dp_tx_send_exception(struct cdp_soc_t *soc_hdl, uint8_t vdev_id, goto fail; } - /* TSO or SG */ - if (qdf_unlikely(qdf_nbuf_is_tso(nbuf)) || - qdf_unlikely(qdf_nbuf_is_nonlinear(nbuf))) { - QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR, - "TSO and SG are not supported in exception path"); + /* + * Classify the frame and call corresponding + * "prepare" function which extracts the segment (TSO) + * and fragmentation information (for TSO , SG, ME, or Raw) + * into MSDU_INFO structure which is later used to fill + * SW and HW descriptors. + */ + if (qdf_nbuf_is_tso(nbuf)) { + dp_verbose_debug("TSO frame %pK", vdev); + DP_STATS_INC_PKT(vdev->pdev, tso_stats.num_tso_pkts, 1, + qdf_nbuf_len(nbuf)); - goto fail; - } - - /* RAW */ - if (qdf_unlikely(tx_exc_metadata->tx_encap_type == htt_cmn_pkt_type_raw)) { - QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR, - "Raw frame is not supported in exception path"); - goto fail; - } - - - /* Mcast enhancement*/ - if (qdf_unlikely(vdev->mcast_enhancement_en > 0)) { - if (DP_FRAME_IS_MULTICAST((eh)->ether_dhost) && - !DP_FRAME_IS_BROADCAST((eh)->ether_dhost)) { - QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR, - "Ignoring mcast_enhancement_en which is set and sending the mcast packet to the FW"); + if (dp_tx_prepare_tso(vdev, nbuf, &msdu_info)) { + DP_STATS_INC_PKT(vdev->pdev, tso_stats.dropped_host, 1, + qdf_nbuf_len(nbuf)); + return nbuf; } + + goto send_multiple; } + /* SG */ + if (qdf_unlikely(qdf_nbuf_is_nonlinear(nbuf))) { + struct dp_tx_seg_info_s seg_info = {0}; + + nbuf = dp_tx_prepare_sg(vdev, nbuf, &seg_info, &msdu_info); + if (!nbuf) + return NULL; + + dp_verbose_debug("non-TSO SG frame %pK", vdev); + + DP_STATS_INC_PKT(vdev, tx_i.sg.sg_pkt, 1, + qdf_nbuf_len(nbuf)); + + goto send_multiple; + } + + if (qdf_unlikely(!dp_tx_mcast_enhance(vdev, nbuf))) + return NULL; + if (qdf_likely(tx_exc_metadata->is_tx_sniffer)) { DP_STATS_INC_PKT(vdev, tx_i.sniffer_rcvd, 1, qdf_nbuf_len(nbuf)); @@ -2573,6 +2716,9 @@ dp_tx_send_exception(struct cdp_soc_t *soc_hdl, uint8_t vdev_id, dp_vdev_unref_delete(soc, vdev, DP_MOD_ID_TX_EXCEPTION); return nbuf; +send_multiple: + nbuf = dp_tx_send_msdu_multiple(vdev, nbuf, &msdu_info); + fail: if (vdev) dp_vdev_unref_delete(soc, vdev, DP_MOD_ID_TX_EXCEPTION); @@ -2844,6 +2990,7 @@ qdf_nbuf_t dp_tx_send(struct cdp_soc_t *soc_hdl, uint8_t vdev_id, * (TID override disabled) */ msdu_info.tid = HTT_TX_EXT_TID_INVALID; + dp_tx_wds_ext(soc, vdev, peer_id, &msdu_info); DP_STATS_INC_PKT(vdev, tx_i.rcvd, 1, qdf_nbuf_len(nbuf)); if (qdf_unlikely(vdev->mesh_vdev)) { @@ -2915,32 +3062,8 @@ qdf_nbuf_t dp_tx_send(struct cdp_soc_t *soc_hdl, uint8_t vdev_id, goto send_multiple; } -#ifdef ATH_SUPPORT_IQUE - /* Mcast to Ucast Conversion*/ - if (qdf_unlikely(vdev->mcast_enhancement_en > 0)) { - qdf_ether_header_t *eh = (qdf_ether_header_t *) - qdf_nbuf_data(nbuf); - if (DP_FRAME_IS_MULTICAST((eh)->ether_dhost) && - !DP_FRAME_IS_BROADCAST((eh)->ether_dhost)) { - dp_verbose_debug("Mcast frm for ME %pK", vdev); - - DP_STATS_INC_PKT(vdev, - tx_i.mcast_en.mcast_pkt, 1, - qdf_nbuf_len(nbuf)); - if (dp_tx_prepare_send_me(vdev, nbuf) == - QDF_STATUS_SUCCESS) { - return NULL; - } - - if (qdf_unlikely(vdev->igmp_mcast_enhanc_en > 0)) { - if (dp_tx_prepare_send_igmp_me(vdev, nbuf) == - QDF_STATUS_SUCCESS) { - return NULL; - } - } - } - } -#endif + if (qdf_unlikely(!dp_tx_mcast_enhance(vdev, nbuf))) + return NULL; /* RAW */ if (qdf_unlikely(vdev->tx_encap_type == htt_cmn_pkt_type_raw)) { diff --git a/dp/wifi3.0/dp_tx.h b/dp/wifi3.0/dp_tx.h index cce22e8e70..49f9b4db90 100644 --- a/dp/wifi3.0/dp_tx.h +++ b/dp/wifi3.0/dp_tx.h @@ -153,14 +153,17 @@ struct dp_tx_msdu_info_s { struct dp_tx_queue tx_queue; uint32_t num_seg; uint8_t tid; + uint8_t exception_fw; + uint8_t is_tx_sniffer; + uint8_t search_type; union { struct qdf_tso_info_t tso_info; struct dp_tx_sg_info_s sg_info; } u; uint32_t meta_data[DP_TX_MSDU_INFO_META_DATA_DWORDS]; - uint8_t exception_fw; uint16_t ppdu_cookie; - uint8_t is_tx_sniffer; + uint16_t ast_idx; + uint16_t ast_hash; }; /** diff --git a/dp/wifi3.0/dp_types.h b/dp/wifi3.0/dp_types.h index 062ca807b7..548915ebe7 100644 --- a/dp/wifi3.0/dp_types.h +++ b/dp/wifi3.0/dp_types.h @@ -199,7 +199,8 @@ enum dp_mod_id { DP_MOD_ID_TDLS = 19, DP_MOD_ID_MISC = 20, DP_MOD_ID_MSCS = 21, - DP_MOD_ID_MAX = 22, + DP_MOD_ID_TX = 22, + DP_MOD_ID_MAX = 23, }; #define DP_PDEV_ITERATE_VDEV_LIST(_pdev, _vdev) \ @@ -2300,6 +2301,10 @@ struct dp_vdev { /* MEC enabled */ bool mec_enabled; +#ifdef QCA_SUPPORT_WDS_EXTENDED + bool wds_ext_enabled; +#endif /* QCA_SUPPORT_WDS_EXTENDED */ + /* WDS Aging timer period */ uint32_t wds_aging_timer_val; @@ -2518,9 +2523,6 @@ struct dp_vdev { qdf_atomic_t ref_cnt; qdf_atomic_t mod_refs[DP_MOD_ID_MAX]; uint8_t num_latency_critical_conn; -#ifdef QCA_SUPPORT_WDS_EXTENDED - bool wds_ext_enabled; -#endif /* QCA_SUPPORT_WDS_EXTENDED */ };