diff --git a/dp/wifi3.0/dp_rx_err.c b/dp/wifi3.0/dp_rx_err.c index dfd7f0b62e04..ddf45223cf7f 100644 --- a/dp/wifi3.0/dp_rx_err.c +++ b/dp/wifi3.0/dp_rx_err.c @@ -1,5 +1,6 @@ /* - * Copyright (c) 2016-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the @@ -1624,6 +1625,124 @@ fail: return; } +/** + * dp_rx_err_route_hdl() - Function to send EAPOL frames to stack + * Free any other packet which comes in + * this path. + * + * @soc: core DP main context + * @nbuf: buffer pointer + * @peer: peer handle + * @rx_tlv_hdr: start of rx tlv header + * @err_src: rxdma/reo + * + * This function indicates EAPOL frame received in wbm error ring to stack. + * Any other frame should be dropped. + * + * Return: SUCCESS if delivered to stack + */ +static void +dp_rx_err_route_hdl(struct dp_soc *soc, qdf_nbuf_t nbuf, + struct dp_peer *peer, uint8_t *rx_tlv_hdr, + enum hal_rx_wbm_error_source err_src) +{ + uint32_t pkt_len; + uint16_t msdu_len; + struct dp_vdev *vdev; + struct hal_rx_msdu_metadata msdu_metadata; + bool is_eapol; + + hal_rx_msdu_metadata_get(soc->hal_soc, rx_tlv_hdr, &msdu_metadata); + msdu_len = hal_rx_msdu_start_msdu_len_get(rx_tlv_hdr); + pkt_len = msdu_len + msdu_metadata.l3_hdr_pad + RX_PKT_TLVS_LEN; + + if (qdf_likely(!qdf_nbuf_is_frag(nbuf))) { + if (dp_rx_check_pkt_len(soc, pkt_len)) + goto drop_nbuf; + + /* Set length in nbuf */ + qdf_nbuf_set_pktlen( + nbuf, qdf_min(pkt_len, (uint32_t)RX_DATA_BUFFER_SIZE)); + qdf_assert_always(nbuf->data == rx_tlv_hdr); + } + + /* + * Check if DMA completed -- msdu_done is the last bit + * to be written + */ + if (!hal_rx_attn_msdu_done_get(rx_tlv_hdr)) { + dp_err_rl("MSDU DONE failure"); + hal_rx_dump_pkt_tlvs(soc->hal_soc, rx_tlv_hdr, + QDF_TRACE_LEVEL_INFO); + qdf_assert(0); + } + + if (!peer) + goto drop_nbuf; + + vdev = peer->vdev; + if (!vdev) { + dp_err_rl("Null vdev!"); + DP_STATS_INC(soc, rx.err.invalid_vdev, 1); + goto drop_nbuf; + } + + /* + * Advance the packet start pointer by total size of + * pre-header TLV's + */ + if (qdf_nbuf_is_frag(nbuf)) + qdf_nbuf_pull_head(nbuf, RX_PKT_TLVS_LEN); + else + qdf_nbuf_pull_head(nbuf, (msdu_metadata.l3_hdr_pad + + RX_PKT_TLVS_LEN)); + + dp_vdev_peer_stats_update_protocol_cnt(vdev, nbuf, NULL, 0, 1); + + /* + * Indicate EAPOL frame to stack only when vap mac address + * matches the destination address. + */ + is_eapol = qdf_nbuf_is_ipv4_eapol_pkt(nbuf); + if (is_eapol || qdf_nbuf_is_ipv4_wapi_pkt(nbuf)) { + qdf_ether_header_t *eh = + (qdf_ether_header_t *)qdf_nbuf_data(nbuf); + if (qdf_mem_cmp(eh->ether_dhost, &vdev->mac_addr.raw[0], + QDF_MAC_ADDR_SIZE) == 0) { + DP_STATS_INC_PKT(vdev, rx.to_stack, 1, + qdf_nbuf_len(nbuf)); + + /* + * Update the protocol tag in SKB based on + * CCE metadata. + */ + dp_rx_update_protocol_tag(soc, vdev, nbuf, rx_tlv_hdr, + EXCEPTION_DEST_RING_ID, + true, true); + /* Update the flow tag in SKB based on FSE metadata */ + dp_rx_update_flow_tag(soc, vdev, nbuf, rx_tlv_hdr, + true); + DP_STATS_INC_PKT(peer, rx.to_stack, 1, + qdf_nbuf_len(nbuf)); + qdf_nbuf_set_exc_frame(nbuf, 1); + qdf_nbuf_set_next(nbuf, NULL); + + dp_rx_deliver_to_stack(soc, vdev, peer, nbuf, NULL); + + return; + } + } + +drop_nbuf: + + DP_STATS_INCC(soc, rx.reo2rel_route_drop, 1, + err_src == HAL_RX_WBM_ERR_SRC_REO); + DP_STATS_INCC(soc, rx.rxdma2rel_route_drop, 1, + err_src == HAL_RX_WBM_ERR_SRC_RXDMA); + + qdf_nbuf_free(nbuf); +} + #ifdef DP_RX_DESC_COOKIE_INVALIDATE /** * dp_rx_link_cookie_check() - Validate link desc cookie @@ -2466,6 +2585,17 @@ done: wbm_err_info.reo_err_code); qdf_nbuf_free(nbuf); } + } else if (wbm_err_info.reo_psh_rsn + == HAL_RX_WBM_REO_PSH_RSN_ROUTE) { + dp_rx_err_route_hdl(soc, nbuf, peer, + rx_tlv_hdr, + HAL_RX_WBM_ERR_SRC_REO); + } else { + /* should not enter here */ + dp_alert("invalid reo push reason %u", + wbm_err_info.reo_psh_rsn); + qdf_nbuf_free(nbuf); + qdf_assert_always(0); } } else if (wbm_err_info.wbm_err_src == HAL_RX_WBM_ERR_SRC_RXDMA) { @@ -2530,6 +2660,17 @@ done: dp_err_rl("RXDMA error %d", wbm_err_info.rxdma_err_code); } + } else if (wbm_err_info.rxdma_psh_rsn + == HAL_RX_WBM_RXDMA_PSH_RSN_ROUTE) { + dp_rx_err_route_hdl(soc, nbuf, peer, + rx_tlv_hdr, + HAL_RX_WBM_ERR_SRC_RXDMA); + } else { + /* should not enter here */ + dp_alert("invalid rxdma push reason %u", + wbm_err_info.rxdma_psh_rsn); + qdf_nbuf_free(nbuf); + qdf_assert_always(0); } } else { /* Should not come here */ diff --git a/dp/wifi3.0/dp_stats.c b/dp/wifi3.0/dp_stats.c index 2d96e52c477c..979b23b7e6f9 100644 --- a/dp/wifi3.0/dp_stats.c +++ b/dp/wifi3.0/dp_stats.c @@ -6652,6 +6652,10 @@ dp_print_soc_rx_stats(struct dp_soc *soc) soc->stats.rx.err.reo_cmd_send_fail); DP_PRINT_STATS("Rx BAR frames:%d", soc->stats.rx.bar_frame); + DP_PRINT_STATS("Rxdma2rel route drop:%d", + soc->stats.rx.rxdma2rel_route_drop); + DP_PRINT_STATS("Reo2rel route drop:%d", + soc->stats.rx.reo2rel_route_drop); } #ifdef FEATURE_TSO_STATS diff --git a/dp/wifi3.0/dp_types.h b/dp/wifi3.0/dp_types.h index 248e22d4dcb7..51184b9f8e87 100644 --- a/dp/wifi3.0/dp_types.h +++ b/dp/wifi3.0/dp_types.h @@ -972,6 +972,10 @@ struct dp_soc_stats { uint32_t msdu_scatter_wait_break; /* Number of bar frames received */ uint32_t bar_frame; + /* Number of frames routed from rxdma */ + uint32_t rxdma2rel_route_drop; + /* Number of frames routed from reo*/ + uint32_t reo2rel_route_drop; struct { /* Invalid RBM error count */