From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 7FD27A0C4A for ; Fri, 16 Jul 2021 08:32:45 +0200 (CEST) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 50BCC40143; Fri, 16 Jul 2021 08:32:45 +0200 (CEST) Received: from relay.smtp-ext.broadcom.com (lpdvacalvio01.broadcom.com [192.19.166.228]) by mails.dpdk.org (Postfix) with ESMTP id 5B9DA40143 for ; Fri, 16 Jul 2021 08:32:44 +0200 (CEST) Received: from dhcp-10-123-153-55.dhcp.broadcom.net (dhcp-10-123-153-55.dhcp.broadcom.net [10.123.153.55]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by relay.smtp-ext.broadcom.com (Postfix) with ESMTPS id 0065F7FFA; Fri, 16 Jul 2021 05:03:16 -0700 (PDT) DKIM-Filter: OpenDKIM Filter v2.11.0 relay.smtp-ext.broadcom.com 0065F7FFA DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=broadcom.com; s=dkimrelay; t=1626436998; bh=NgteSPtabl+Oj5I3LCmxIcpWhhqZ0X7Ga5RrfhJgHJ4=; h=From:To:Cc:Subject:Date:From; b=vNB+38Qwam3/9Z5dxUMZJ3MAHPozydLZosEBCruHz5/sGQ2Fp4aTEsq1+OiCuKTP3 fskHHYrVV/FEKiRyf9jbie9dI/IpGPa/iPM1X3/pDUnB5Fz3W0Y5vJ4Q4IJ293qSGn zTXZWuJz8kxdMIVi0DKmyvmtjettRgT5r9IXXLoI= From: Somnath Kotur To: stable@dpdk.org Cc: Somnath Kotur , Ajit Khaparde Date: Fri, 16 Jul 2021 11:59:11 +0530 Message-Id: <20210716062911.15394-1-somnath.kotur@broadcom.com> X-Mailer: git-send-email 2.28.0.450.g3a238e5 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Subject: [dpdk-stable] [PATCH 20.11] net/bnxt: detect bad opaque in Rx completion X-BeenThere: stable@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: patches for DPDK stable branches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: stable-bounces@dpdk.org Sender: "stable" [ upstream commit 03c8f2fe111c2b4c4fddc960dc82253ac7e6c5c5 ] There is a rare hardware bug that can cause a bad opaque value in the RX or TPA start completion. When this happens, the hardware may have used the same buffer twice for 2 Rx packets. In addition, the driver might also crash later using the bad opaque as an index into the ring. The Rx opaque value is predictable and is always monotonically increasing. The workaround is to keep track of the expected next opaque value and compare it with the one returned by hardware during RX and TPA start completions. If they miscompare, log it, discard the completion, schedule a ring reset and move on to the next one. Fixes: 0958d8b6435d ("net/bnxt: support LRO") Signed-off-by: Somnath Kotur Reviewed-by: Ajit Khaparde --- drivers/net/bnxt/bnxt_hwrm.c | 19 +++++++ drivers/net/bnxt/bnxt_hwrm.h | 1 + drivers/net/bnxt/bnxt_rxq.h | 1 + drivers/net/bnxt/bnxt_rxr.c | 99 +++++++++++++++++++++++++++++++++++- drivers/net/bnxt/bnxt_rxr.h | 1 + 5 files changed, 119 insertions(+), 2 deletions(-) diff --git a/drivers/net/bnxt/bnxt_hwrm.c b/drivers/net/bnxt/bnxt_hwrm.c index ea61fcf74b..ef402815cc 100644 --- a/drivers/net/bnxt/bnxt_hwrm.c +++ b/drivers/net/bnxt/bnxt_hwrm.c @@ -2585,6 +2585,25 @@ void bnxt_free_hwrm_rx_ring(struct bnxt *bp, int queue_index) bp->grp_info[queue_index].cp_fw_ring_id = INVALID_HW_RING_ID; } +int bnxt_hwrm_rx_ring_reset(struct bnxt *bp, int queue_index) +{ + int rc; + struct hwrm_ring_reset_input req = {.req_type = 0 }; + struct hwrm_ring_reset_output *resp = bp->hwrm_cmd_resp_addr; + + HWRM_PREP(&req, HWRM_RING_RESET, BNXT_USE_CHIMP_MB); + + req.ring_type = HWRM_RING_RESET_INPUT_RING_TYPE_RX_RING_GRP; + req.ring_id = rte_cpu_to_le_16(bp->grp_info[queue_index].fw_grp_id); + rc = bnxt_hwrm_send_message(bp, &req, sizeof(req), BNXT_USE_CHIMP_MB); + + HWRM_CHECK_RESULT(); + + HWRM_UNLOCK(); + + return rc; +} + static int bnxt_free_all_hwrm_rings(struct bnxt *bp) { diff --git a/drivers/net/bnxt/bnxt_hwrm.h b/drivers/net/bnxt/bnxt_hwrm.h index 6deae8faeb..82010e675b 100644 --- a/drivers/net/bnxt/bnxt_hwrm.h +++ b/drivers/net/bnxt/bnxt_hwrm.h @@ -296,4 +296,5 @@ int bnxt_hwrm_cfa_pair_free(struct bnxt *bp, struct bnxt_representor *rep); int bnxt_hwrm_poll_ver_get(struct bnxt *bp); int bnxt_hwrm_ring_stats(struct bnxt *bp, uint32_t cid, int idx, struct bnxt_ring_stats *stats, bool rx); +int bnxt_hwrm_rx_ring_reset(struct bnxt *bp, int queue_index); #endif diff --git a/drivers/net/bnxt/bnxt_rxq.h b/drivers/net/bnxt/bnxt_rxq.h index c72105cf06..980a16a566 100644 --- a/drivers/net/bnxt/bnxt_rxq.h +++ b/drivers/net/bnxt/bnxt_rxq.h @@ -30,6 +30,7 @@ struct bnxt_rx_queue { uint8_t rx_deferred_start; /* not in global dev start */ uint8_t rx_started; /* RX queue is started */ uint8_t drop_en; /* Drop when rx desc not available. */ + uint8_t in_reset; /* Rx ring is scheduled for reset */ struct bnxt *bp; int index; diff --git a/drivers/net/bnxt/bnxt_rxr.c b/drivers/net/bnxt/bnxt_rxr.c index d16340a34b..54c9df06e1 100644 --- a/drivers/net/bnxt/bnxt_rxr.c +++ b/drivers/net/bnxt/bnxt_rxr.c @@ -10,6 +10,7 @@ #include #include #include +#include #include "bnxt.h" #include "bnxt_reps.h" @@ -17,9 +18,7 @@ #include "bnxt_rxr.h" #include "bnxt_rxq.h" #include "hsi_struct_def_dpdk.h" -#ifdef RTE_LIBRTE_IEEE1588 #include "bnxt_hwrm.h" -#endif #include #include @@ -127,6 +126,50 @@ struct rte_mbuf *bnxt_consume_rx_buf(struct bnxt_rx_ring_info *rxr, return mbuf; } +static void bnxt_rx_ring_reset(void *arg) +{ + struct bnxt *bp = arg; + int i, rc = 0; + struct bnxt_rx_queue *rxq; + + + for (i = 0; i < (int)bp->rx_nr_rings; i++) { + struct bnxt_rx_ring_info *rxr; + + rxq = bp->rx_queues[i]; + if (!rxq || !rxq->in_reset) + continue; + + rxr = rxq->rx_ring; + /* Disable and flush TPA before resetting the RX ring */ + if (rxr->tpa_info) + bnxt_hwrm_vnic_tpa_cfg(bp, rxq->vnic, false); + rc = bnxt_hwrm_rx_ring_reset(bp, i); + if (rc) { + PMD_DRV_LOG(ERR, "Rx ring%d reset failed\n", i); + continue; + } + + bnxt_rx_queue_release_mbufs(rxq); + rxr->rx_prod = 0; + rxr->ag_prod = 0; + rxr->rx_next_cons = 0; + bnxt_init_one_rx_ring(rxq); + bnxt_db_write(&rxr->rx_db, rxr->rx_prod); + bnxt_db_write(&rxr->ag_db, rxr->ag_prod); + if (rxr->tpa_info) + bnxt_hwrm_vnic_tpa_cfg(bp, rxq->vnic, true); + + rxq->in_reset = 0; + } +} + +static void bnxt_sched_ring_reset(struct bnxt_rx_queue *rxq) +{ + rxq->in_reset = 1; + rte_eal_alarm_set(1, bnxt_rx_ring_reset, (void *)rxq->bp); +} + static void bnxt_tpa_start(struct bnxt_rx_queue *rxq, struct rx_tpa_start_cmpl *tpa_start, struct rx_tpa_start_cmpl_hi *tpa_start1) @@ -141,6 +184,12 @@ static void bnxt_tpa_start(struct bnxt_rx_queue *rxq, data_cons = tpa_start->opaque; tpa_info = &rxr->tpa_info[agg_id]; + if (unlikely(data_cons != rxr->rx_next_cons)) { + PMD_DRV_LOG(ERR, "TPA cons %x, expected cons %x\n", + data_cons, rxr->rx_next_cons); + bnxt_sched_ring_reset(rxq); + return; + } mbuf = bnxt_consume_rx_buf(rxr, data_cons); @@ -177,6 +226,8 @@ static void bnxt_tpa_start(struct bnxt_rx_queue *rxq, /* recycle next mbuf */ data_cons = RING_NEXT(rxr->rx_ring_struct, data_cons); bnxt_reuse_rx_mbuf(rxr, bnxt_consume_rx_buf(rxr, data_cons)); + + rxr->rx_next_cons = RING_NEXT(rxr->rx_ring_struct, data_cons); } static int bnxt_agg_bufs_valid(struct bnxt_cp_ring_info *cpr, @@ -272,6 +323,34 @@ static int bnxt_rx_pages(struct bnxt_rx_queue *rxq, return 0; } +static int bnxt_discard_rx(struct bnxt *bp, struct bnxt_cp_ring_info *cpr, + uint32_t *raw_cons, void *cmp) +{ + struct rx_pkt_cmpl *rxcmp = cmp; + uint32_t tmp_raw_cons = *raw_cons; + uint8_t cmp_type, agg_bufs = 0; + + cmp_type = CMP_TYPE(rxcmp); + + if (cmp_type == CMPL_BASE_TYPE_RX_L2) { + agg_bufs = BNXT_RX_L2_AGG_BUFS(rxcmp); + } else if (cmp_type == RX_TPA_END_CMPL_TYPE_RX_TPA_END) { + struct rx_tpa_end_cmpl *tpa_end = cmp; + + if (BNXT_CHIP_THOR(bp)) + return 0; + + agg_bufs = BNXT_TPA_END_AGG_BUFS(tpa_end); + } + + if (agg_bufs) { + if (!bnxt_agg_bufs_valid(cpr, agg_bufs, tmp_raw_cons)) + return -EBUSY; + } + *raw_cons = tmp_raw_cons; + return 0; +} + static inline struct rte_mbuf *bnxt_tpa_end( struct bnxt_rx_queue *rxq, uint32_t *raw_cp_cons, @@ -286,6 +365,13 @@ static inline struct rte_mbuf *bnxt_tpa_end( uint8_t payload_offset; struct bnxt_tpa_info *tpa_info; + if (unlikely(rxq->in_reset)) { + PMD_DRV_LOG(ERR, "rxq->in_reset: raw_cp_cons:%d\n", + *raw_cp_cons); + bnxt_discard_rx(rxq->bp, cpr, raw_cp_cons, tpa_end); + return NULL; + } + if (BNXT_CHIP_THOR(rxq->bp)) { struct rx_tpa_v2_end_cmpl *th_tpa_end; struct rx_tpa_v2_end_cmpl_hi *th_tpa_end1; @@ -773,6 +859,14 @@ static int bnxt_rx_pkt(struct rte_mbuf **rx_pkt, prod = rxr->rx_prod; cons = rxcmp->opaque; + if (unlikely(cons != rxr->rx_next_cons)) { + bnxt_discard_rx(bp, cpr, &tmp_raw_cons, rxcmp); + PMD_DRV_LOG(ERR, "RX cons %x != expected cons %x\n", + cons, rxr->rx_next_cons); + bnxt_sched_ring_reset(rxq); + rc = -EBUSY; + goto next_rx; + } mbuf = bnxt_consume_rx_buf(rxr, cons); if (mbuf == NULL) return -EBUSY; @@ -837,6 +931,7 @@ static int bnxt_rx_pkt(struct rte_mbuf **rx_pkt, goto rx; } rxr->rx_prod = prod; + rxr->rx_next_cons = RING_NEXT(rxr->rx_ring_struct, cons); if (BNXT_TRUFLOW_EN(bp) && (BNXT_VF_IS_TRUSTED(bp) || BNXT_PF(bp)) && vfr_flag) { diff --git a/drivers/net/bnxt/bnxt_rxr.h b/drivers/net/bnxt/bnxt_rxr.h index f8eb9b70b5..46b284024e 100644 --- a/drivers/net/bnxt/bnxt_rxr.h +++ b/drivers/net/bnxt/bnxt_rxr.h @@ -58,6 +58,7 @@ struct bnxt_rx_ring_info { uint16_t rx_prod; uint16_t ag_prod; uint16_t rx_cons; /* Needed for representor */ + uint16_t rx_next_cons; struct bnxt_db_info rx_db; struct bnxt_db_info ag_db; -- 2.28.0.497.g54e85e7