diff --git a/dp/wifi3.0/dp_rx.c b/dp/wifi3.0/dp_rx.c index 9901cb25e5..8c0c917b27 100644 --- a/dp/wifi3.0/dp_rx.c +++ b/dp/wifi3.0/dp_rx.c @@ -1981,22 +1981,38 @@ void dp_rx_flush_rx_cached(struct dp_peer *peer, bool drop) /** * dp_rx_enqueue_rx() - cache rx frames * @peer: peer + * @txrx_peer: DP txrx_peer * @rx_buf_list: cache buffer list * * Return: None */ static QDF_STATUS -dp_rx_enqueue_rx(struct dp_txrx_peer *txrx_peer, qdf_nbuf_t rx_buf_list) +dp_rx_enqueue_rx(struct dp_peer *peer, + struct dp_txrx_peer *txrx_peer, + qdf_nbuf_t rx_buf_list) { struct dp_rx_cached_buf *cache_buf; struct dp_peer_cached_bufq *bufqi = &txrx_peer->bufq_info; int num_buff_elem; QDF_STATUS ret = QDF_STATUS_SUCCESS; struct dp_soc *soc = txrx_peer->vdev->pdev->soc; - struct dp_peer *peer = dp_peer_get_ref_by_id(soc, txrx_peer->peer_id, - DP_MOD_ID_RX); + struct dp_peer *ta_peer = NULL; - if (!peer) { + /* + * If peer id is invalid which likely peer map has not completed, + * then need caller provide dp_peer pointer, else it's ok to use + * txrx_peer->peer_id to get dp_peer. + */ + if (peer) { + if (QDF_STATUS_SUCCESS == + dp_peer_get_ref(soc, peer, DP_MOD_ID_RX)) + ta_peer = peer; + } else { + ta_peer = dp_peer_get_ref_by_id(soc, txrx_peer->peer_id, + DP_MOD_ID_RX); + } + + if (!ta_peer) { bufqi->dropped = dp_rx_drop_nbuf_list(txrx_peer->vdev->pdev, rx_buf_list); return QDF_STATUS_E_INVAL; @@ -2004,7 +2020,7 @@ dp_rx_enqueue_rx(struct dp_txrx_peer *txrx_peer, qdf_nbuf_t rx_buf_list) dp_debug_rl("bufq->curr %d bufq->drops %d", bufqi->entries, bufqi->dropped); - if (!peer->valid) { + if (!ta_peer->valid) { bufqi->dropped = dp_rx_drop_nbuf_list(txrx_peer->vdev->pdev, rx_buf_list); ret = QDF_STATUS_E_INVAL; @@ -2042,7 +2058,7 @@ dp_rx_enqueue_rx(struct dp_txrx_peer *txrx_peer, qdf_nbuf_t rx_buf_list) qdf_spin_unlock_bh(&bufqi->bufq_lock); fail: - dp_peer_unref_delete(peer, DP_MOD_ID_RX); + dp_peer_unref_delete(ta_peer, DP_MOD_ID_RX); return ret; } @@ -2059,7 +2075,9 @@ bool dp_rx_is_peer_cache_bufq_supported(void) } static inline QDF_STATUS -dp_rx_enqueue_rx(struct dp_txrx_peer *txrx_peer, qdf_nbuf_t rx_buf_list) +dp_rx_enqueue_rx(struct dp_peer *peer, + struct dp_txrx_peer *txrx_peer, + qdf_nbuf_t rx_buf_list) { return QDF_STATUS_SUCCESS; } @@ -2169,7 +2187,7 @@ dp_rx_validate_rx_callbacks(struct dp_soc *soc, */ if (qdf_unlikely(!vdev->osif_rx)) { if (txrx_peer && dp_rx_is_peer_cache_bufq_supported()) { - dp_rx_enqueue_rx(txrx_peer, nbuf_head); + dp_rx_enqueue_rx(NULL, txrx_peer, nbuf_head); } else { num_nbuf = dp_rx_drop_nbuf_list(vdev->pdev, nbuf_head); @@ -2605,6 +2623,8 @@ void dp_rx_deliver_to_stack_no_peer(struct dp_soc *soc, qdf_nbuf_t nbuf) uint8_t *rx_tlv_hdr; uint32_t frame_mask = FRAME_MASK_IPV4_ARP | FRAME_MASK_IPV4_DHCP | FRAME_MASK_IPV4_EAPOL | FRAME_MASK_IPV6_DHCP; + bool is_special_frame = false; + struct dp_peer *peer = NULL; peer_id = QDF_NBUF_CB_RX_PEER_ID(nbuf); if (peer_id > soc->max_peer_id) @@ -2612,7 +2632,7 @@ void dp_rx_deliver_to_stack_no_peer(struct dp_soc *soc, qdf_nbuf_t nbuf) vdev_id = QDF_NBUF_CB_RX_VDEV_ID(nbuf); vdev = dp_vdev_get_ref_by_id(soc, vdev_id, DP_MOD_ID_RX); - if (!vdev || vdev->delete.pending || !vdev->osif_rx) + if (!vdev || vdev->delete.pending) goto deliver_fail; if (qdf_unlikely(qdf_nbuf_is_frag(nbuf))) @@ -2629,15 +2649,54 @@ void dp_rx_deliver_to_stack_no_peer(struct dp_soc *soc, qdf_nbuf_t nbuf) qdf_nbuf_set_pktlen(nbuf, pkt_len); qdf_nbuf_pull_head(nbuf, soc->rx_pkt_tlv_size + l2_hdr_offset); - if (dp_rx_is_special_frame(nbuf, frame_mask) || - dp_rx_is_udp_allowed_over_roam_peer(vdev, rx_tlv_hdr, nbuf)) { - qdf_nbuf_set_exc_frame(nbuf, 1); - if (QDF_STATUS_SUCCESS != - vdev->osif_rx(vdev->osif_vdev, nbuf)) + is_special_frame = dp_rx_is_special_frame(nbuf, frame_mask); + if (qdf_likely(vdev->osif_rx)) { + if (is_special_frame || + dp_rx_is_udp_allowed_over_roam_peer(vdev, rx_tlv_hdr, + nbuf)) { + qdf_nbuf_set_exc_frame(nbuf, 1); + if (QDF_STATUS_SUCCESS != + vdev->osif_rx(vdev->osif_vdev, nbuf)) + goto deliver_fail; + + DP_STATS_INC(soc, rx.err.pkt_delivered_no_peer, 1); + dp_vdev_unref_delete(soc, vdev, DP_MOD_ID_RX); + return; + } + } else if (is_special_frame) { + /* + * If MLO connection, txrx_peer for link peer does not exist, + * try to store these RX packets to txrx_peer's bufq of MLD + * peer until vdev->osif_rx is registered from CP and flush + * them to stack. + */ + peer = dp_peer_get_tgt_peer_by_id(soc, peer_id, + DP_MOD_ID_RX); + if (!peer) goto deliver_fail; - DP_STATS_INC(soc, rx.err.pkt_delivered_no_peer, 1); - dp_vdev_unref_delete(soc, vdev, DP_MOD_ID_RX); - return; + + /* only check for MLO connection */ + if (IS_MLO_DP_MLD_PEER(peer) && peer->txrx_peer && + dp_rx_is_peer_cache_bufq_supported()) { + qdf_nbuf_set_exc_frame(nbuf, 1); + + if (QDF_STATUS_SUCCESS == + dp_rx_enqueue_rx(peer, peer->txrx_peer, nbuf)) { + DP_STATS_INC(soc, + rx.err.pkt_delivered_no_peer, + 1); + } else { + DP_STATS_INC(soc, + rx.err.rx_invalid_peer.num, + 1); + } + + dp_vdev_unref_delete(soc, vdev, DP_MOD_ID_RX); + dp_peer_unref_delete(peer, DP_MOD_ID_RX); + return; + } + + dp_peer_unref_delete(peer, DP_MOD_ID_RX); } deliver_fail: