From 5a717f4a8e00f563962b736961a12b6798c839a0 Mon Sep 17 00:00:00 2001 From: Somnath Kotur Date: Mon, 27 Dec 2021 03:00:26 -0500 Subject: [PATCH 1/7] bnxt_en: Add event handler for PAUSE Storm event FW has been modified to send a new async event when it detects a pause storm. Register for this new event and log it upon receipt. Reviewed-by: Andy Gospodarek Reviewed-by: Edwin Peer Signed-off-by: Somnath Kotur Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index c057b1df86a9..11255131abbc 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -2049,6 +2049,9 @@ static void bnxt_event_error_report(struct bnxt *bp, u32 data1, u32 data2) netdev_err(bp->dev, "1PPS: Received invalid signal on pin%lu from the external source. Please fix the signal and reconfigure the pin\n", BNXT_EVENT_INVALID_SIGNAL_DATA(data2)); break; + case ASYNC_EVENT_CMPL_ERROR_REPORT_BASE_EVENT_DATA1_ERROR_TYPE_PAUSE_STORM: + netdev_warn(bp->dev, "Pause Storm detected!\n"); + break; default: netdev_err(bp->dev, "FW reported unknown error type\n"); break; From 0fb8582ae5b9bf0dc5a4fededabe7db16a8b430a Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 27 Dec 2021 03:00:27 -0500 Subject: [PATCH 2/7] bnxt_en: Log error report for dropped doorbell Log the unrecognized error report type value as well. Reviewed-by: Andy Gospodarek Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 11255131abbc..53101d00768c 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -2044,7 +2044,9 @@ static u16 bnxt_agg_ring_id_to_grp_idx(struct bnxt *bp, u16 ring_id) static void bnxt_event_error_report(struct bnxt *bp, u32 data1, u32 data2) { - switch (BNXT_EVENT_ERROR_REPORT_TYPE(data1)) { + u32 err_type = BNXT_EVENT_ERROR_REPORT_TYPE(data1); + + switch (err_type) { case ASYNC_EVENT_CMPL_ERROR_REPORT_BASE_EVENT_DATA1_ERROR_TYPE_INVALID_SIGNAL: netdev_err(bp->dev, "1PPS: Received invalid signal on pin%lu from the external source. Please fix the signal and reconfigure the pin\n", BNXT_EVENT_INVALID_SIGNAL_DATA(data2)); @@ -2052,8 +2054,12 @@ static void bnxt_event_error_report(struct bnxt *bp, u32 data1, u32 data2) case ASYNC_EVENT_CMPL_ERROR_REPORT_BASE_EVENT_DATA1_ERROR_TYPE_PAUSE_STORM: netdev_warn(bp->dev, "Pause Storm detected!\n"); break; + case ASYNC_EVENT_CMPL_ERROR_REPORT_BASE_EVENT_DATA1_ERROR_TYPE_DOORBELL_DROP_THRESHOLD: + netdev_warn(bp->dev, "One or more MMIO doorbells dropped by the device!\n"); + break; default: - netdev_err(bp->dev, "FW reported unknown error type\n"); + netdev_err(bp->dev, "FW reported unknown error type %u\n", + err_type); break; } } From dc1f5d1ebc5c7f70cd352b2b71097f972b244c94 Mon Sep 17 00:00:00 2001 From: Andy Gospodarek Date: Mon, 27 Dec 2021 03:00:28 -0500 Subject: [PATCH 3/7] bnxt_en: enable interrupt sampling on 5750X for DIM 5750X (P5) chips handle receiving packets on the NQ rather than the main completion queue so we need to get and set stats from the correct spots for dynamic interrupt moderation. Signed-off-by: Andy Gospodarek Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 53101d00768c..11df2fc05f6a 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -2632,6 +2632,7 @@ static int bnxt_poll_p5(struct napi_struct *napi, int budget) { struct bnxt_napi *bnapi = container_of(napi, struct bnxt_napi, napi); struct bnxt_cp_ring_info *cpr = &bnapi->cp_ring; + struct bnxt_cp_ring_info *cpr_rx; u32 raw_cons = cpr->cp_raw_cons; struct bnxt *bp = bnapi->bp; struct nqe_cn *nqcmp; @@ -2659,7 +2660,7 @@ static int bnxt_poll_p5(struct napi_struct *napi, int budget) if (napi_complete_done(napi, work_done)) BNXT_DB_NQ_ARM_P5(&cpr->cp_db, cpr->cp_raw_cons); - return work_done; + goto poll_done; } /* The valid test of the entry must be done first before @@ -2685,6 +2686,17 @@ static int bnxt_poll_p5(struct napi_struct *napi, int budget) cpr->cp_raw_cons = raw_cons; BNXT_DB_NQ_P5(&cpr->cp_db, raw_cons); } +poll_done: + cpr_rx = cpr->cp_ring_arr[BNXT_RX_HDL]; + if (cpr_rx && (bp->flags & BNXT_FLAG_DIM)) { + struct dim_sample dim_sample = {}; + + dim_update_sample(cpr->event_ctr, + cpr_rx->rx_packets, + cpr_rx->rx_bytes, + &dim_sample); + net_dim(&cpr->dim, dim_sample); + } return work_done; } From df78ea22460b6c625bd2079686bec0d834e56946 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 27 Dec 2021 03:00:29 -0500 Subject: [PATCH 4/7] bnxt_en: Support configurable CQE coalescing mode CQE coalescing mode is the same as the timer reset coalescing mode on Broadcom devices. Currently this mode is always enabled if it is supported by the device. Restructure the code slightly to support dynamically changing this mode. Add a flags field to struct bnxt_coal. Initially, the CQE flag will be set for the RX and TX side if the device supports it. We need to move bnxt_init_dflt_coal() to set up default coalescing until the capability is determined. Reviewed-by: Andy Gospodarek Reviewed-by: Edwin Peer Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 16 +++++++++++----- drivers/net/ethernet/broadcom/bnxt/bnxt.h | 1 + 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 11df2fc05f6a..48e61355ca00 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -6496,8 +6496,8 @@ static void bnxt_hwrm_set_coal_params(struct bnxt *bp, struct hwrm_ring_cmpl_ring_cfg_aggint_params_input *req) { struct bnxt_coal_cap *coal_cap = &bp->coal_cap; + u16 val, tmr, max, flags = hw_coal->flags; u32 cmpl_params = coal_cap->cmpl_params; - u16 val, tmr, max, flags = 0; max = hw_coal->bufs_per_record * 128; if (hw_coal->budget) @@ -6540,8 +6540,6 @@ static void bnxt_hwrm_set_coal_params(struct bnxt *bp, cpu_to_le16(BNXT_COAL_CMPL_AGGR_TMR_DURING_INT_ENABLE); } - if (cmpl_params & RING_AGGINT_QCAPS_RESP_CMPL_PARAMS_TIMER_RESET) - flags |= RING_CMPL_RING_CFG_AGGINT_PARAMS_REQ_FLAGS_TIMER_RESET; if ((cmpl_params & RING_AGGINT_QCAPS_RESP_CMPL_PARAMS_RING_IDLE) && hw_coal->idle_thresh && hw_coal->coal_ticks < hw_coal->idle_thresh) flags |= RING_CMPL_RING_CFG_AGGINT_PARAMS_REQ_FLAGS_RING_IDLE; @@ -11897,7 +11895,13 @@ static void bnxt_cleanup_pci(struct bnxt *bp) static void bnxt_init_dflt_coal(struct bnxt *bp) { + struct bnxt_coal_cap *coal_cap = &bp->coal_cap; struct bnxt_coal *coal; + u16 flags = 0; + + if (coal_cap->cmpl_params & + RING_AGGINT_QCAPS_RESP_CMPL_PARAMS_TIMER_RESET) + flags |= RING_CMPL_RING_CFG_AGGINT_PARAMS_REQ_FLAGS_TIMER_RESET; /* Tick values in micro seconds. * 1 coal_buf x bufs_per_record = 1 completion record. @@ -11910,6 +11914,7 @@ static void bnxt_init_dflt_coal(struct bnxt *bp) coal->idle_thresh = 50; coal->bufs_per_record = 2; coal->budget = 64; /* NAPI budget */ + coal->flags = flags; coal = &bp->tx_coal; coal->coal_ticks = 28; @@ -11917,6 +11922,7 @@ static void bnxt_init_dflt_coal(struct bnxt *bp) coal->coal_ticks_irq = 2; coal->coal_bufs_irq = 2; coal->bufs_per_record = 1; + coal->flags = flags; bp->stats_coal_ticks = BNXT_DEF_STATS_COAL_TICKS; } @@ -12403,8 +12409,6 @@ static int bnxt_init_board(struct pci_dev *pdev, struct net_device *dev) bp->rx_ring_size = BNXT_DEFAULT_RX_RING_SIZE; bp->tx_ring_size = BNXT_DEFAULT_TX_RING_SIZE; - bnxt_init_dflt_coal(bp); - timer_setup(&bp->timer, bnxt_timer, 0); bp->current_interval = BNXT_TIMER_INTERVAL; @@ -13424,6 +13428,8 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) bnxt_fw_init_one_p3(bp); + bnxt_init_dflt_coal(bp); + if (dev->hw_features & BNXT_HW_FEATURE_VLAN_ALL_RX) bp->flags |= BNXT_FLAG_STRIP_VLAN; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index 4c9507d82fd0..7bd9c5d237d9 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -847,6 +847,7 @@ struct bnxt_coal { u16 idle_thresh; u8 bufs_per_record; u8 budget; + u16 flags; }; struct bnxt_tpa_info { From 3fcbdbd5d8d51d14ad5687a253990e89da9b7661 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 27 Dec 2021 03:00:30 -0500 Subject: [PATCH 5/7] bnxt_en: Support CQE coalescing mode in ethtool Support showing and setting the CQE mode in ethtool. Reviewed-by: Edwin Peer Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- .../net/ethernet/broadcom/bnxt/bnxt_ethtool.c | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c index 15253396096a..46859d9a01eb 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c @@ -68,6 +68,9 @@ static int bnxt_get_coalesce(struct net_device *dev, coal->rx_max_coalesced_frames = hw_coal->coal_bufs / mult; coal->rx_coalesce_usecs_irq = hw_coal->coal_ticks_irq; coal->rx_max_coalesced_frames_irq = hw_coal->coal_bufs_irq / mult; + if (hw_coal->flags & + RING_CMPL_RING_CFG_AGGINT_PARAMS_REQ_FLAGS_TIMER_RESET) + kernel_coal->use_cqe_mode_rx = true; hw_coal = &bp->tx_coal; mult = hw_coal->bufs_per_record; @@ -75,6 +78,9 @@ static int bnxt_get_coalesce(struct net_device *dev, coal->tx_max_coalesced_frames = hw_coal->coal_bufs / mult; coal->tx_coalesce_usecs_irq = hw_coal->coal_ticks_irq; coal->tx_max_coalesced_frames_irq = hw_coal->coal_bufs_irq / mult; + if (hw_coal->flags & + RING_CMPL_RING_CFG_AGGINT_PARAMS_REQ_FLAGS_TIMER_RESET) + kernel_coal->use_cqe_mode_tx = true; coal->stats_block_coalesce_usecs = bp->stats_coal_ticks; @@ -101,12 +107,22 @@ static int bnxt_set_coalesce(struct net_device *dev, } } + if ((kernel_coal->use_cqe_mode_rx || kernel_coal->use_cqe_mode_tx) && + !(bp->coal_cap.cmpl_params & + RING_AGGINT_QCAPS_RESP_CMPL_PARAMS_TIMER_RESET)) + return -EOPNOTSUPP; + hw_coal = &bp->rx_coal; mult = hw_coal->bufs_per_record; hw_coal->coal_ticks = coal->rx_coalesce_usecs; hw_coal->coal_bufs = coal->rx_max_coalesced_frames * mult; hw_coal->coal_ticks_irq = coal->rx_coalesce_usecs_irq; hw_coal->coal_bufs_irq = coal->rx_max_coalesced_frames_irq * mult; + hw_coal->flags &= + ~RING_CMPL_RING_CFG_AGGINT_PARAMS_REQ_FLAGS_TIMER_RESET; + if (kernel_coal->use_cqe_mode_rx) + hw_coal->flags |= + RING_CMPL_RING_CFG_AGGINT_PARAMS_REQ_FLAGS_TIMER_RESET; hw_coal = &bp->tx_coal; mult = hw_coal->bufs_per_record; @@ -114,6 +130,11 @@ static int bnxt_set_coalesce(struct net_device *dev, hw_coal->coal_bufs = coal->tx_max_coalesced_frames * mult; hw_coal->coal_ticks_irq = coal->tx_coalesce_usecs_irq; hw_coal->coal_bufs_irq = coal->tx_max_coalesced_frames_irq * mult; + hw_coal->flags &= + ~RING_CMPL_RING_CFG_AGGINT_PARAMS_REQ_FLAGS_TIMER_RESET; + if (kernel_coal->use_cqe_mode_tx) + hw_coal->flags |= + RING_CMPL_RING_CFG_AGGINT_PARAMS_REQ_FLAGS_TIMER_RESET; if (bp->stats_coal_ticks != coal->stats_block_coalesce_usecs) { u32 stats_ticks = coal->stats_block_coalesce_usecs; @@ -3921,7 +3942,8 @@ const struct ethtool_ops bnxt_ethtool_ops = { ETHTOOL_COALESCE_USECS_IRQ | ETHTOOL_COALESCE_MAX_FRAMES_IRQ | ETHTOOL_COALESCE_STATS_BLOCK_USECS | - ETHTOOL_COALESCE_USE_ADAPTIVE_RX, + ETHTOOL_COALESCE_USE_ADAPTIVE_RX | + ETHTOOL_COALESCE_USE_CQE, .get_link_ksettings = bnxt_get_link_ksettings, .set_link_ksettings = bnxt_set_link_ksettings, .get_fec_stats = bnxt_get_fec_stats, From b976969bed83e90fffb9e750e1d1562956500cd9 Mon Sep 17 00:00:00 2001 From: Edwin Peer Date: Mon, 27 Dec 2021 03:00:31 -0500 Subject: [PATCH 6/7] bnxt_en: convert to xdp_do_flush The xdp_do_flush_map function has been replaced with the more general xdp_do_flush(). Signed-off-by: Edwin Peer Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 48e61355ca00..ea5b072ba292 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -2429,7 +2429,7 @@ static int __bnxt_poll_work(struct bnxt *bp, struct bnxt_cp_ring_info *cpr, } if (event & BNXT_REDIRECT_EVENT) - xdp_do_flush_map(); + xdp_do_flush(); if (event & BNXT_TX_EVENT) { struct bnxt_tx_ring_info *txr = bnapi->tx_ring; From 720908e5f816d56579e098e32bd3b56bad2be8f0 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Mon, 27 Dec 2021 03:00:32 -0500 Subject: [PATCH 7/7] bnxt_en: Use page frag RX buffers for better software GRO performance If NETIF_F_GRO_HW is disabled, the existing driver code uses kmalloc'ed data for RX buffers. This causes inefficient SW GRO performance because the GRO data is merged using the less efficient frag_list. Use netdev_alloc_frag() and friends instead so that GRO data can be merged into skb_shinfo(skb)->frags for better performance. [Use skb_free_frag() - Vikas Gupta] Signed-off-by: Jakub Kicinski Reviewed-by: Pavan Chebbi Reviewed-by: Andy Gospodarek Signed-off-by: Vikas Gupta Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 27 +++++++++++++---------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index ea5b072ba292..4d7ea62e24fb 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -741,13 +741,16 @@ static struct page *__bnxt_alloc_rx_page(struct bnxt *bp, dma_addr_t *mapping, return page; } -static inline u8 *__bnxt_alloc_rx_data(struct bnxt *bp, dma_addr_t *mapping, +static inline u8 *__bnxt_alloc_rx_frag(struct bnxt *bp, dma_addr_t *mapping, gfp_t gfp) { u8 *data; struct pci_dev *pdev = bp->pdev; - data = kmalloc(bp->rx_buf_size, gfp); + if (gfp == GFP_ATOMIC) + data = napi_alloc_frag(bp->rx_buf_size); + else + data = netdev_alloc_frag(bp->rx_buf_size); if (!data) return NULL; @@ -756,7 +759,7 @@ static inline u8 *__bnxt_alloc_rx_data(struct bnxt *bp, dma_addr_t *mapping, DMA_ATTR_WEAK_ORDERING); if (dma_mapping_error(&pdev->dev, *mapping)) { - kfree(data); + skb_free_frag(data); data = NULL; } return data; @@ -779,7 +782,7 @@ int bnxt_alloc_rx_data(struct bnxt *bp, struct bnxt_rx_ring_info *rxr, rx_buf->data = page; rx_buf->data_ptr = page_address(page) + bp->rx_offset; } else { - u8 *data = __bnxt_alloc_rx_data(bp, &mapping, gfp); + u8 *data = __bnxt_alloc_rx_frag(bp, &mapping, gfp); if (!data) return -ENOMEM; @@ -1021,11 +1024,11 @@ static struct sk_buff *bnxt_rx_skb(struct bnxt *bp, return NULL; } - skb = build_skb(data, 0); + skb = build_skb(data, bp->rx_buf_size); dma_unmap_single_attrs(&bp->pdev->dev, dma_addr, bp->rx_buf_use_size, bp->rx_dir, DMA_ATTR_WEAK_ORDERING); if (!skb) { - kfree(data); + skb_free_frag(data); return NULL; } @@ -1613,7 +1616,7 @@ static inline struct sk_buff *bnxt_tpa_end(struct bnxt *bp, u8 *new_data; dma_addr_t new_mapping; - new_data = __bnxt_alloc_rx_data(bp, &new_mapping, GFP_ATOMIC); + new_data = __bnxt_alloc_rx_frag(bp, &new_mapping, GFP_ATOMIC); if (!new_data) { bnxt_abort_tpa(cpr, idx, agg_bufs); cpr->sw_stats.rx.rx_oom_discards += 1; @@ -1624,13 +1627,13 @@ static inline struct sk_buff *bnxt_tpa_end(struct bnxt *bp, tpa_info->data_ptr = new_data + bp->rx_offset; tpa_info->mapping = new_mapping; - skb = build_skb(data, 0); + skb = build_skb(data, bp->rx_buf_size); dma_unmap_single_attrs(&bp->pdev->dev, mapping, bp->rx_buf_use_size, bp->rx_dir, DMA_ATTR_WEAK_ORDERING); if (!skb) { - kfree(data); + skb_free_frag(data); bnxt_abort_tpa(cpr, idx, agg_bufs); cpr->sw_stats.rx.rx_oom_discards += 1; return NULL; @@ -2796,7 +2799,7 @@ static void bnxt_free_one_rx_ring_skbs(struct bnxt *bp, int ring_nr) tpa_info->data = NULL; - kfree(data); + skb_free_frag(data); } skip_rx_tpa_free: @@ -2822,7 +2825,7 @@ static void bnxt_free_one_rx_ring_skbs(struct bnxt *bp, int ring_nr) dma_unmap_single_attrs(&pdev->dev, mapping, bp->rx_buf_use_size, bp->rx_dir, DMA_ATTR_WEAK_ORDERING); - kfree(data); + skb_free_frag(data); } } @@ -3526,7 +3529,7 @@ static int bnxt_alloc_one_rx_ring(struct bnxt *bp, int ring_nr) u8 *data; for (i = 0; i < bp->max_tpa; i++) { - data = __bnxt_alloc_rx_data(bp, &mapping, GFP_KERNEL); + data = __bnxt_alloc_rx_frag(bp, &mapping, GFP_KERNEL); if (!data) return -ENOMEM;