From nobody Sat Feb 7 14:39:32 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 2EE58EB64D9 for ; Wed, 14 Jun 2023 16:30:33 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230264AbjFNQab (ORCPT ); Wed, 14 Jun 2023 12:30:31 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43712 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233720AbjFNQaY (ORCPT ); Wed, 14 Jun 2023 12:30:24 -0400 Received: from dfw.source.kernel.org (dfw.source.kernel.org [IPv6:2604:1380:4641:c500::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 5C0CC212C for ; Wed, 14 Jun 2023 09:30:19 -0700 (PDT) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by dfw.source.kernel.org (Postfix) with ESMTPS id D51BB63AB6 for ; Wed, 14 Jun 2023 16:30:18 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 91E1DC433C0; Wed, 14 Jun 2023 16:30:14 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1686760218; bh=38J+Lpe9beQ4yjmYo+d4WXoCGVHbzmLcJi7Bg/fXw0U=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=ObBOctGmKybhNkPc0leOFPBpDYA1Y7Ggl1Xl0RsCPDbftsFdUli1s1bLucO4RyV/u z2jJg8HBu9FpuuYUu6Ac6PC9vQPQPdcgKrSKA+5aqkZVLFgfr9cjE75r5i4qctfzZu KBwWzC60zD8FQtJcb10nZiq+2Wftk4VMtZgn/PQvAyBSdQWNQjJ8j3StY6OkA5QavD C3ORY6Mdvrv21yggGYEzfG4IHlfXvBvAJsbNMAfMI4RHEvPDIVjzEgvIys7Tq8zePp 6xQIjUNP6etu8s8kE1CxMSBcx3WGVsSbw//J10tlQx1UVGt0A59/WKSF/3ppKSIY2U JLZROH6DhndjQ== From: Jisheng Zhang To: Giuseppe Cavallaro , Alexandre Torgue , Jose Abreu , "David S . Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Maxime Coquelin , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland Cc: netdev@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, linux-sunxi@lists.linux.dev Subject: [PATCH 2/3] net: stmmac: fix overflow of some network statistics Date: Thu, 15 Jun 2023 00:18:46 +0800 Message-Id: <20230614161847.4071-3-jszhang@kernel.org> X-Mailer: git-send-email 2.40.0 In-Reply-To: <20230614161847.4071-1-jszhang@kernel.org> References: <20230614161847.4071-1-jszhang@kernel.org> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Currently, network statistics in stmmac_extra_stats, stmmac_rxq_stats and stmmac_txq_stats are 32 bit variables on 32 bit platforms. This can cause some stats to overflow after several minutes of high traffic, for example rx_pkt_n, tx_pkt_n and so on. To fix this issue, we convert those statistics to 64 bit, implement ndo_get_stats64 and update ethtool accordingly. Some statistics which are not possible to overflow are still kept as is. Signed-off-by: Jisheng Zhang --- drivers/net/ethernet/stmicro/stmmac/common.h | 43 +++-- .../net/ethernet/stmicro/stmmac/dwmac-sun8i.c | 12 +- .../ethernet/stmicro/stmmac/dwmac100_dma.c | 7 +- .../ethernet/stmicro/stmmac/dwmac4_descs.c | 13 +- .../net/ethernet/stmicro/stmmac/dwmac4_lib.c | 14 +- .../net/ethernet/stmicro/stmmac/dwmac_lib.c | 3 + .../ethernet/stmicro/stmmac/dwxgmac2_descs.c | 6 +- .../ethernet/stmicro/stmmac/dwxgmac2_dma.c | 2 + .../net/ethernet/stmicro/stmmac/enh_desc.c | 20 +-- drivers/net/ethernet/stmicro/stmmac/hwif.h | 12 +- .../net/ethernet/stmicro/stmmac/norm_desc.c | 15 +- .../ethernet/stmicro/stmmac/stmmac_ethtool.c | 69 +++++--- .../net/ethernet/stmicro/stmmac/stmmac_main.c | 152 ++++++++++++++---- 13 files changed, 236 insertions(+), 132 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/eth= ernet/stmicro/stmmac/common.h index 4ad692c4116c..1cb8be45330d 100644 --- a/drivers/net/ethernet/stmicro/stmmac/common.h +++ b/drivers/net/ethernet/stmicro/stmmac/common.h @@ -59,19 +59,22 @@ /* #define FRAME_FILTER_DEBUG */ =20 struct stmmac_txq_stats { - unsigned long tx_pkt_n; - unsigned long tx_normal_irq_n; + struct u64_stats_sync syncp; + u64 tx_pkt_n; + u64 tx_normal_irq_n; }; =20 struct stmmac_rxq_stats { - unsigned long rx_pkt_n; - unsigned long rx_normal_irq_n; + struct u64_stats_sync syncp; + u64 rx_pkt_n; + u64 rx_normal_irq_n; }; =20 /* Extra statistic and debug information exposed by ethtool */ struct stmmac_extra_stats { + struct u64_stats_sync syncp ____cacheline_aligned; /* Transmit errors */ - unsigned long tx_underflow ____cacheline_aligned; + unsigned long tx_underflow; unsigned long tx_carrier; unsigned long tx_losscarrier; unsigned long vlan_tag; @@ -81,6 +84,7 @@ struct stmmac_extra_stats { unsigned long tx_frame_flushed; unsigned long tx_payload_error; unsigned long tx_ip_header_error; + unsigned long tx_collision; /* Receive errors */ unsigned long rx_desc; unsigned long sa_filter_fail; @@ -113,14 +117,14 @@ struct stmmac_extra_stats { /* Tx/Rx IRQ Events */ unsigned long rx_early_irq; unsigned long threshold; - unsigned long tx_pkt_n; - unsigned long rx_pkt_n; - unsigned long normal_irq_n; - unsigned long rx_normal_irq_n; - unsigned long napi_poll; - unsigned long tx_normal_irq_n; - unsigned long tx_clean; - unsigned long tx_set_ic_bit; + u64 tx_pkt_n; + u64 rx_pkt_n; + u64 normal_irq_n; + u64 rx_normal_irq_n; + u64 napi_poll; + u64 tx_normal_irq_n; + u64 tx_clean; + u64 tx_set_ic_bit; unsigned long irq_receive_pmt_irq_n; /* MMC info */ unsigned long mmc_tx_irq_n; @@ -191,8 +195,8 @@ struct stmmac_extra_stats { unsigned long mac_rx_frame_ctrl_fifo; unsigned long mac_gmii_rx_proto_engine; /* TSO */ - unsigned long tx_tso_frames; - unsigned long tx_tso_nfrags; + u64 tx_tso_frames; + u64 tx_tso_nfrags; /* EST */ unsigned long mtl_est_cgce; unsigned long mtl_est_hlbs; @@ -202,6 +206,15 @@ struct stmmac_extra_stats { /* per queue statistics */ struct stmmac_txq_stats txq_stats[MTL_MAX_TX_QUEUES]; struct stmmac_rxq_stats rxq_stats[MTL_MAX_RX_QUEUES]; + /* device stats */ + u64 rx_packets; + u64 rx_bytes; + u64 tx_packets; + u64 tx_bytes; + unsigned long rx_dropped; + unsigned long rx_errors; + unsigned long tx_dropped; + unsigned long tx_errors; }; =20 /* Safety Feature statistics exposed by ethtool */ diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c b/drivers/ne= t/ethernet/stmicro/stmmac/dwmac-sun8i.c index c2c592ba0eb8..1571ca0c6616 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c @@ -450,11 +450,18 @@ static int sun8i_dwmac_dma_interrupt(struct stmmac_pr= iv *priv, else if (dir =3D=3D DMA_DIR_TX) v &=3D EMAC_INT_MSK_TX; =20 + u64_stats_update_begin(&priv->xstats.syncp); if (v & EMAC_TX_INT) { ret |=3D handle_tx; x->tx_normal_irq_n++; } =20 + if (v & EMAC_RX_INT) { + ret |=3D handle_rx; + x->rx_normal_irq_n++; + } + u64_stats_update_end(&priv->xstats.syncp); + if (v & EMAC_TX_DMA_STOP_INT) x->tx_process_stopped_irq++; =20 @@ -472,11 +479,6 @@ static int sun8i_dwmac_dma_interrupt(struct stmmac_pri= v *priv, if (v & EMAC_TX_EARLY_INT) x->tx_early_irq++; =20 - if (v & EMAC_RX_INT) { - ret |=3D handle_rx; - x->rx_normal_irq_n++; - } - if (v & EMAC_RX_BUF_UA_INT) x->rx_buf_unav_irq++; =20 diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c b/drivers/n= et/ethernet/stmicro/stmmac/dwmac100_dma.c index 1c32b1788f02..dea270f60cc3 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c @@ -82,29 +82,24 @@ static void dwmac100_dump_dma_regs(struct stmmac_priv *= priv, } =20 /* DMA controller has two counters to track the number of the missed frame= s. */ -static void dwmac100_dma_diagnostic_fr(struct net_device_stats *stats, - struct stmmac_extra_stats *x, +static void dwmac100_dma_diagnostic_fr(struct stmmac_extra_stats *x, void __iomem *ioaddr) { u32 csr8 =3D readl(ioaddr + DMA_MISSED_FRAME_CTR); =20 if (unlikely(csr8)) { if (csr8 & DMA_MISSED_FRAME_OVE) { - stats->rx_over_errors +=3D 0x800; x->rx_overflow_cntr +=3D 0x800; } else { unsigned int ove_cntr; ove_cntr =3D ((csr8 & DMA_MISSED_FRAME_OVE_CNTR) >> 17); - stats->rx_over_errors +=3D ove_cntr; x->rx_overflow_cntr +=3D ove_cntr; } =20 if (csr8 & DMA_MISSED_FRAME_OVE_M) { - stats->rx_missed_errors +=3D 0xffff; x->rx_missed_cntr +=3D 0xffff; } else { unsigned int miss_f =3D (csr8 & DMA_MISSED_FRAME_M_CNTR); - stats->rx_missed_errors +=3D miss_f; x->rx_missed_cntr +=3D miss_f; } } diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c b/drivers/n= et/ethernet/stmicro/stmmac/dwmac4_descs.c index 6a011d8633e8..f0c71c281fc1 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c @@ -13,8 +13,7 @@ #include "dwmac4.h" #include "dwmac4_descs.h" =20 -static int dwmac4_wrback_get_tx_status(struct net_device_stats *stats, - struct stmmac_extra_stats *x, +static int dwmac4_wrback_get_tx_status(struct stmmac_extra_stats *x, struct dma_desc *p, void __iomem *ioaddr) { @@ -40,15 +39,13 @@ static int dwmac4_wrback_get_tx_status(struct net_devic= e_stats *stats, x->tx_frame_flushed++; if (unlikely(tdes3 & TDES3_LOSS_CARRIER)) { x->tx_losscarrier++; - stats->tx_carrier_errors++; } if (unlikely(tdes3 & TDES3_NO_CARRIER)) { x->tx_carrier++; - stats->tx_carrier_errors++; } if (unlikely((tdes3 & TDES3_LATE_COLLISION) || (tdes3 & TDES3_EXCESSIVE_COLLISION))) - stats->collisions +=3D + x->tx_collision +=3D (tdes3 & TDES3_COLLISION_COUNT_MASK) >> TDES3_COLLISION_COUNT_SHIFT; =20 @@ -73,8 +70,7 @@ static int dwmac4_wrback_get_tx_status(struct net_device_= stats *stats, return ret; } =20 -static int dwmac4_wrback_get_rx_status(struct net_device_stats *stats, - struct stmmac_extra_stats *x, +static int dwmac4_wrback_get_rx_status(struct stmmac_extra_stats *x, struct dma_desc *p) { unsigned int rdes1 =3D le32_to_cpu(p->des1); @@ -93,7 +89,7 @@ static int dwmac4_wrback_get_rx_status(struct net_device_= stats *stats, =20 if (unlikely(rdes3 & RDES3_ERROR_SUMMARY)) { if (unlikely(rdes3 & RDES3_GIANT_PACKET)) - stats->rx_length_errors++; + x->rx_length++; if (unlikely(rdes3 & RDES3_OVERFLOW_ERROR)) x->rx_gmac_overflow++; =20 @@ -105,7 +101,6 @@ static int dwmac4_wrback_get_rx_status(struct net_devic= e_stats *stats, =20 if (unlikely(rdes3 & RDES3_CRC_ERROR)) { x->rx_crc_errors++; - stats->rx_crc_errors++; } =20 if (unlikely(rdes3 & RDES3_DRIBBLE_ERROR)) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c b/drivers/net= /ethernet/stmicro/stmmac/dwmac4_lib.c index df41eac54058..eda4859fa468 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c @@ -198,18 +198,28 @@ int dwmac4_dma_interrupt(struct stmmac_priv *priv, vo= id __iomem *ioaddr, } } /* TX/RX NORMAL interrupts */ + u64_stats_update_begin(&priv->xstats.syncp); if (likely(intr_status & DMA_CHAN_STATUS_NIS)) x->normal_irq_n++; - if (likely(intr_status & DMA_CHAN_STATUS_RI)) { + if (likely(intr_status & DMA_CHAN_STATUS_RI)) x->rx_normal_irq_n++; + if (likely(intr_status & DMA_CHAN_STATUS_TI)) + x->tx_normal_irq_n++; + u64_stats_update_end(&priv->xstats.syncp); + + if (likely(intr_status & DMA_CHAN_STATUS_RI)) { + u64_stats_update_begin(&priv->xstats.rxq_stats[chan].syncp); x->rxq_stats[chan].rx_normal_irq_n++; + u64_stats_update_end(&priv->xstats.rxq_stats[chan].syncp); ret |=3D handle_rx; } if (likely(intr_status & DMA_CHAN_STATUS_TI)) { - x->tx_normal_irq_n++; + u64_stats_update_begin(&priv->xstats.txq_stats[chan].syncp); x->txq_stats[chan].tx_normal_irq_n++; + u64_stats_update_end(&priv->xstats.txq_stats[chan].syncp); ret |=3D handle_tx; } + if (unlikely(intr_status & DMA_CHAN_STATUS_TBU)) ret |=3D handle_tx; if (unlikely(intr_status & DMA_CHAN_STATUS_ERI)) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c b/drivers/net/= ethernet/stmicro/stmmac/dwmac_lib.c index 0b6f999a8305..4cef67571d5a 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c @@ -10,6 +10,7 @@ #include #include "common.h" #include "dwmac_dma.h" +#include "stmmac.h" =20 #define GMAC_HI_REG_AE 0x80000000 =20 @@ -208,6 +209,7 @@ int dwmac_dma_interrupt(struct stmmac_priv *priv, void = __iomem *ioaddr, } /* TX/RX NORMAL interrupts */ if (likely(intr_status & DMA_STATUS_NIS)) { + u64_stats_update_begin(&priv->xstats.syncp); x->normal_irq_n++; if (likely(intr_status & DMA_STATUS_RI)) { u32 value =3D readl(ioaddr + DMA_INTR_ENA); @@ -221,6 +223,7 @@ int dwmac_dma_interrupt(struct stmmac_priv *priv, void = __iomem *ioaddr, x->tx_normal_irq_n++; ret |=3D handle_tx; } + u64_stats_update_end(&priv->xstats.syncp); if (unlikely(intr_status & DMA_STATUS_ERI)) x->rx_early_irq++; } diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_descs.c b/drivers= /net/ethernet/stmicro/stmmac/dwxgmac2_descs.c index 13c347ee8be9..fc82862a612c 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_descs.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_descs.c @@ -8,8 +8,7 @@ #include "common.h" #include "dwxgmac2.h" =20 -static int dwxgmac2_get_tx_status(struct net_device_stats *stats, - struct stmmac_extra_stats *x, +static int dwxgmac2_get_tx_status(struct stmmac_extra_stats *x, struct dma_desc *p, void __iomem *ioaddr) { unsigned int tdes3 =3D le32_to_cpu(p->des3); @@ -23,8 +22,7 @@ static int dwxgmac2_get_tx_status(struct net_device_stats= *stats, return ret; } =20 -static int dwxgmac2_get_rx_status(struct net_device_stats *stats, - struct stmmac_extra_stats *x, +static int dwxgmac2_get_rx_status(struct stmmac_extra_stats *x, struct dma_desc *p) { unsigned int rdes3 =3D le32_to_cpu(p->des3); diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c b/drivers/n= et/ethernet/stmicro/stmmac/dwxgmac2_dma.c index dfd53264e036..5997aa0c9b55 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c @@ -364,6 +364,7 @@ static int dwxgmac2_dma_interrupt(struct stmmac_priv *p= riv, =20 /* TX/RX NORMAL interrupts */ if (likely(intr_status & XGMAC_NIS)) { + u64_stats_update_begin(&priv->xstats.syncp); x->normal_irq_n++; =20 if (likely(intr_status & XGMAC_RI)) { @@ -374,6 +375,7 @@ static int dwxgmac2_dma_interrupt(struct stmmac_priv *p= riv, x->tx_normal_irq_n++; ret |=3D handle_tx; } + u64_stats_update_end(&priv->xstats.syncp); } =20 /* Clear interrupts */ diff --git a/drivers/net/ethernet/stmicro/stmmac/enh_desc.c b/drivers/net/e= thernet/stmicro/stmmac/enh_desc.c index a91d8f13a931..937b7a0466fc 100644 --- a/drivers/net/ethernet/stmicro/stmmac/enh_desc.c +++ b/drivers/net/ethernet/stmicro/stmmac/enh_desc.c @@ -12,8 +12,7 @@ #include "common.h" #include "descs_com.h" =20 -static int enh_desc_get_tx_status(struct net_device_stats *stats, - struct stmmac_extra_stats *x, +static int enh_desc_get_tx_status(struct stmmac_extra_stats *x, struct dma_desc *p, void __iomem *ioaddr) { unsigned int tdes0 =3D le32_to_cpu(p->des0); @@ -38,15 +37,13 @@ static int enh_desc_get_tx_status(struct net_device_sta= ts *stats, =20 if (unlikely(tdes0 & ETDES0_LOSS_CARRIER)) { x->tx_losscarrier++; - stats->tx_carrier_errors++; } if (unlikely(tdes0 & ETDES0_NO_CARRIER)) { x->tx_carrier++; - stats->tx_carrier_errors++; } if (unlikely((tdes0 & ETDES0_LATE_COLLISION) || (tdes0 & ETDES0_EXCESSIVE_COLLISIONS))) - stats->collisions +=3D + x->tx_collision +=3D (tdes0 & ETDES0_COLLISION_COUNT_MASK) >> 3; =20 if (unlikely(tdes0 & ETDES0_EXCESSIVE_DEFERRAL)) @@ -117,8 +114,7 @@ static int enh_desc_coe_rdes0(int ipc_err, int type, in= t payload_err) return ret; } =20 -static void enh_desc_get_ext_status(struct net_device_stats *stats, - struct stmmac_extra_stats *x, +static void enh_desc_get_ext_status(struct stmmac_extra_stats *x, struct dma_extended_desc *p) { unsigned int rdes0 =3D le32_to_cpu(p->basic.des0); @@ -182,8 +178,7 @@ static void enh_desc_get_ext_status(struct net_device_s= tats *stats, } } =20 -static int enh_desc_get_rx_status(struct net_device_stats *stats, - struct stmmac_extra_stats *x, +static int enh_desc_get_rx_status(struct stmmac_extra_stats *x, struct dma_desc *p) { unsigned int rdes0 =3D le32_to_cpu(p->des0); @@ -193,14 +188,14 @@ static int enh_desc_get_rx_status(struct net_device_s= tats *stats, return dma_own; =20 if (unlikely(!(rdes0 & RDES0_LAST_DESCRIPTOR))) { - stats->rx_length_errors++; + x->rx_length++; return discard_frame; } =20 if (unlikely(rdes0 & RDES0_ERROR_SUMMARY)) { if (unlikely(rdes0 & RDES0_DESCRIPTOR_ERROR)) { x->rx_desc++; - stats->rx_length_errors++; + x->rx_length++; } if (unlikely(rdes0 & RDES0_OVERFLOW_ERROR)) x->rx_gmac_overflow++; @@ -209,7 +204,7 @@ static int enh_desc_get_rx_status(struct net_device_sta= ts *stats, pr_err("\tIPC Csum Error/Giant frame\n"); =20 if (unlikely(rdes0 & RDES0_COLLISION)) - stats->collisions++; + x->rx_collision++; if (unlikely(rdes0 & RDES0_RECEIVE_WATCHDOG)) x->rx_watchdog++; =20 @@ -218,7 +213,6 @@ static int enh_desc_get_rx_status(struct net_device_sta= ts *stats, =20 if (unlikely(rdes0 & RDES0_CRC_ERROR)) { x->rx_crc_errors++; - stats->rx_crc_errors++; } ret =3D discard_frame; } diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.h b/drivers/net/ether= net/stmicro/stmmac/hwif.h index 6ee7cf07cfd7..652af8f6e75f 100644 --- a/drivers/net/ethernet/stmicro/stmmac/hwif.h +++ b/drivers/net/ethernet/stmicro/stmmac/hwif.h @@ -57,8 +57,7 @@ struct stmmac_desc_ops { /* Last tx segment reports the transmit status */ int (*get_tx_ls)(struct dma_desc *p); /* Return the transmit status looking at the TDES1 */ - int (*tx_status)(struct net_device_stats *stats, - struct stmmac_extra_stats *x, + int (*tx_status)(struct stmmac_extra_stats *x, struct dma_desc *p, void __iomem *ioaddr); /* Get the buffer size from the descriptor */ int (*get_tx_len)(struct dma_desc *p); @@ -67,11 +66,9 @@ struct stmmac_desc_ops { /* Get the receive frame size */ int (*get_rx_frame_len)(struct dma_desc *p, int rx_coe_type); /* Return the reception status looking at the RDES1 */ - int (*rx_status)(struct net_device_stats *stats, - struct stmmac_extra_stats *x, + int (*rx_status)(struct stmmac_extra_stats *x, struct dma_desc *p); - void (*rx_extended_status)(struct net_device_stats *stats, - struct stmmac_extra_stats *x, + void (*rx_extended_status)(struct stmmac_extra_stats *x, struct dma_extended_desc *p); /* Set tx timestamp enable bit */ void (*enable_tx_timestamp) (struct dma_desc *p); @@ -191,8 +188,7 @@ struct stmmac_dma_ops { void (*dma_tx_mode)(struct stmmac_priv *priv, void __iomem *ioaddr, int mode, u32 channel, int fifosz, u8 qmode); /* To track extra statistic (if supported) */ - void (*dma_diagnostic_fr)(struct net_device_stats *stats, - struct stmmac_extra_stats *x, + void (*dma_diagnostic_fr)(struct stmmac_extra_stats *x, void __iomem *ioaddr); void (*enable_dma_transmission) (void __iomem *ioaddr); void (*enable_dma_irq)(struct stmmac_priv *priv, void __iomem *ioaddr, diff --git a/drivers/net/ethernet/stmicro/stmmac/norm_desc.c b/drivers/net/= ethernet/stmicro/stmmac/norm_desc.c index 350e6670a576..68a7cfcb1d8f 100644 --- a/drivers/net/ethernet/stmicro/stmmac/norm_desc.c +++ b/drivers/net/ethernet/stmicro/stmmac/norm_desc.c @@ -12,8 +12,7 @@ #include "common.h" #include "descs_com.h" =20 -static int ndesc_get_tx_status(struct net_device_stats *stats, - struct stmmac_extra_stats *x, +static int ndesc_get_tx_status(struct stmmac_extra_stats *x, struct dma_desc *p, void __iomem *ioaddr) { unsigned int tdes0 =3D le32_to_cpu(p->des0); @@ -31,15 +30,12 @@ static int ndesc_get_tx_status(struct net_device_stats = *stats, if (unlikely(tdes0 & TDES0_ERROR_SUMMARY)) { if (unlikely(tdes0 & TDES0_UNDERFLOW_ERROR)) { x->tx_underflow++; - stats->tx_fifo_errors++; } if (unlikely(tdes0 & TDES0_NO_CARRIER)) { x->tx_carrier++; - stats->tx_carrier_errors++; } if (unlikely(tdes0 & TDES0_LOSS_CARRIER)) { x->tx_losscarrier++; - stats->tx_carrier_errors++; } if (unlikely((tdes0 & TDES0_EXCESSIVE_DEFERRAL) || (tdes0 & TDES0_EXCESSIVE_COLLISIONS) || @@ -47,7 +43,7 @@ static int ndesc_get_tx_status(struct net_device_stats *s= tats, unsigned int collisions; =20 collisions =3D (tdes0 & TDES0_COLLISION_COUNT_MASK) >> 3; - stats->collisions +=3D collisions; + x->tx_collision +=3D collisions; } ret =3D tx_err; } @@ -70,8 +66,7 @@ static int ndesc_get_tx_len(struct dma_desc *p) * and, if required, updates the multicast statistics. * In case of success, it returns good_frame because the GMAC device * is supposed to be able to compute the csum in HW. */ -static int ndesc_get_rx_status(struct net_device_stats *stats, - struct stmmac_extra_stats *x, +static int ndesc_get_rx_status(struct stmmac_extra_stats *x, struct dma_desc *p) { int ret =3D good_frame; @@ -81,7 +76,7 @@ static int ndesc_get_rx_status(struct net_device_stats *s= tats, return dma_own; =20 if (unlikely(!(rdes0 & RDES0_LAST_DESCRIPTOR))) { - stats->rx_length_errors++; + x->rx_length++; return discard_frame; } =20 @@ -96,11 +91,9 @@ static int ndesc_get_rx_status(struct net_device_stats *= stats, x->ipc_csum_error++; if (unlikely(rdes0 & RDES0_COLLISION)) { x->rx_collision++; - stats->collisions++; } if (unlikely(rdes0 & RDES0_CRC_ERROR)) { x->rx_crc_errors++; - stats->rx_crc_errors++; } ret =3D discard_frame; } diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers= /net/ethernet/stmicro/stmmac/stmmac_ethtool.c index 2ae73ab842d4..f9cca2562d60 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c @@ -89,14 +89,6 @@ static const struct stmmac_stats stmmac_gstrings_stats[]= =3D { /* Tx/Rx IRQ Events */ STMMAC_STAT(rx_early_irq), STMMAC_STAT(threshold), - STMMAC_STAT(tx_pkt_n), - STMMAC_STAT(rx_pkt_n), - STMMAC_STAT(normal_irq_n), - STMMAC_STAT(rx_normal_irq_n), - STMMAC_STAT(napi_poll), - STMMAC_STAT(tx_normal_irq_n), - STMMAC_STAT(tx_clean), - STMMAC_STAT(tx_set_ic_bit), STMMAC_STAT(irq_receive_pmt_irq_n), /* MMC info */ STMMAC_STAT(mmc_tx_irq_n), @@ -163,9 +155,6 @@ static const struct stmmac_stats stmmac_gstrings_stats[= ] =3D { STMMAC_STAT(mtl_rx_fifo_ctrl_active), STMMAC_STAT(mac_rx_frame_ctrl_fifo), STMMAC_STAT(mac_gmii_rx_proto_engine), - /* TSO */ - STMMAC_STAT(tx_tso_frames), - STMMAC_STAT(tx_tso_nfrags), /* EST */ STMMAC_STAT(mtl_est_cgce), STMMAC_STAT(mtl_est_hlbs), @@ -175,6 +164,22 @@ static const struct stmmac_stats stmmac_gstrings_stats= [] =3D { }; #define STMMAC_STATS_LEN ARRAY_SIZE(stmmac_gstrings_stats) =20 +static const struct stmmac_stats stmmac_gstrings_stats64[] =3D { + /* Tx/Rx IRQ Events */ + STMMAC_STAT(tx_pkt_n), + STMMAC_STAT(rx_pkt_n), + STMMAC_STAT(normal_irq_n), + STMMAC_STAT(rx_normal_irq_n), + STMMAC_STAT(napi_poll), + STMMAC_STAT(tx_normal_irq_n), + STMMAC_STAT(tx_clean), + STMMAC_STAT(tx_set_ic_bit), + /* TSO */ + STMMAC_STAT(tx_tso_frames), + STMMAC_STAT(tx_tso_nfrags), +}; +#define STMMAC_STATS64_LEN ARRAY_SIZE(stmmac_gstrings_stats64) + /* HW MAC Management counters (if supported) */ #define STMMAC_MMC_STAT(m) \ { #m, sizeof_field(struct stmmac_counters, m), \ @@ -535,24 +540,31 @@ static void stmmac_get_per_qstats(struct stmmac_priv = *priv, u64 *data) { u32 tx_cnt =3D priv->plat->tx_queues_to_use; u32 rx_cnt =3D priv->plat->rx_queues_to_use; + unsigned int start; int q, stat; char *p; =20 for (q =3D 0; q < tx_cnt; q++) { - p =3D (char *)priv + offsetof(struct stmmac_priv, - xstats.txq_stats[q].tx_pkt_n); - for (stat =3D 0; stat < STMMAC_TXQ_STATS; stat++) { - *data++ =3D (*(unsigned long *)p); - p +=3D sizeof(unsigned long); - } + do { + start =3D u64_stats_fetch_begin(&priv->xstats.txq_stats[q].syncp); + p =3D (char *)priv + offsetof(struct stmmac_priv, + xstats.txq_stats[q].tx_pkt_n); + for (stat =3D 0; stat < STMMAC_TXQ_STATS; stat++) { + *data++ =3D (*(u64 *)p); + p +=3D sizeof(u64); + } + } while (u64_stats_fetch_retry(&priv->xstats.txq_stats[q].syncp, start)); } for (q =3D 0; q < rx_cnt; q++) { - p =3D (char *)priv + offsetof(struct stmmac_priv, - xstats.rxq_stats[q].rx_pkt_n); - for (stat =3D 0; stat < STMMAC_RXQ_STATS; stat++) { - *data++ =3D (*(unsigned long *)p); - p +=3D sizeof(unsigned long); - } + do { + start =3D u64_stats_fetch_begin(&priv->xstats.rxq_stats[q].syncp); + p =3D (char *)priv + offsetof(struct stmmac_priv, + xstats.rxq_stats[q].rx_pkt_n); + for (stat =3D 0; stat < STMMAC_RXQ_STATS; stat++) { + *data++ =3D (*(u64 *)p); + p +=3D sizeof(u64); + } + } while (u64_stats_fetch_retry(&priv->xstats.rxq_stats[q].syncp, start)); } } =20 @@ -563,6 +575,7 @@ static void stmmac_get_ethtool_stats(struct net_device = *dev, u32 rx_queues_count =3D priv->plat->rx_queues_to_use; u32 tx_queues_count =3D priv->plat->tx_queues_to_use; unsigned long count; + unsigned int start; int i, j =3D 0, ret; =20 if (priv->dma_cap.asp) { @@ -574,8 +587,7 @@ static void stmmac_get_ethtool_stats(struct net_device = *dev, } =20 /* Update the DMA HW counters for dwmac10/100 */ - ret =3D stmmac_dma_diagnostic_fr(priv, &dev->stats, (void *) &priv->xstat= s, - priv->ioaddr); + ret =3D stmmac_dma_diagnostic_fr(priv, &priv->xstats, priv->ioaddr); if (ret) { /* If supported, for new GMAC chips expose the MMC counters */ if (priv->dma_cap.rmon) { @@ -606,6 +618,13 @@ static void stmmac_get_ethtool_stats(struct net_device= *dev, data[j++] =3D (stmmac_gstrings_stats[i].sizeof_stat =3D=3D sizeof(u64)) ? (*(u64 *)p) : (*(u32 *)p); } + do { + start =3D u64_stats_fetch_begin(&priv->xstats.syncp); + for (i =3D 0; i < STMMAC_STATS64_LEN; i++) { + char *p =3D (char *)priv + stmmac_gstrings_stats64[i].stat_offset; + data[j++] =3D *(u64 *)p; + } + } while (u64_stats_fetch_retry(&priv->xstats.syncp, start)); stmmac_get_per_qstats(priv, &data[j]); } =20 diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/ne= t/ethernet/stmicro/stmmac/stmmac_main.c index 951e037d0a80..69cb2835fa82 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -2429,6 +2429,7 @@ static bool stmmac_xdp_xmit_zc(struct stmmac_priv *pr= iv, u32 queue, u32 budget) struct dma_desc *tx_desc =3D NULL; struct xdp_desc xdp_desc; bool work_done =3D true; + u32 tx_set_ic_bit =3D 0; =20 /* Avoids TX time-out as we are sharing with slow path */ txq_trans_cond_update(nq); @@ -2489,7 +2490,7 @@ static bool stmmac_xdp_xmit_zc(struct stmmac_priv *pr= iv, u32 queue, u32 budget) if (set_ic) { tx_q->tx_count_frames =3D 0; stmmac_set_tx_ic(priv, tx_desc); - priv->xstats.tx_set_ic_bit++; + tx_set_ic_bit++; } =20 stmmac_prepare_tx_desc(priv, tx_desc, 1, xdp_desc.len, @@ -2501,6 +2502,9 @@ static bool stmmac_xdp_xmit_zc(struct stmmac_priv *pr= iv, u32 queue, u32 budget) tx_q->cur_tx =3D STMMAC_GET_ENTRY(tx_q->cur_tx, priv->dma_conf.dma_tx_si= ze); entry =3D tx_q->cur_tx; } + u64_stats_update_begin(&priv->xstats.syncp); + priv->xstats.tx_set_ic_bit +=3D tx_set_ic_bit; + u64_stats_update_end(&priv->xstats.syncp); =20 if (tx_desc) { stmmac_flush_tx_descriptors(priv, queue); @@ -2542,11 +2546,10 @@ static int stmmac_tx_clean(struct stmmac_priv *priv= , int budget, u32 queue) struct stmmac_tx_queue *tx_q =3D &priv->dma_conf.tx_queue[queue]; unsigned int bytes_compl =3D 0, pkts_compl =3D 0; unsigned int entry, xmits =3D 0, count =3D 0; + u32 tx_packets =3D 0, tx_errors =3D 0; =20 __netif_tx_lock_bh(netdev_get_tx_queue(priv->dev, queue)); =20 - priv->xstats.tx_clean++; - tx_q->xsk_frames_done =3D 0; =20 entry =3D tx_q->dirty_tx; @@ -2577,8 +2580,7 @@ static int stmmac_tx_clean(struct stmmac_priv *priv, = int budget, u32 queue) else p =3D tx_q->dma_tx + entry; =20 - status =3D stmmac_tx_status(priv, &priv->dev->stats, - &priv->xstats, p, priv->ioaddr); + status =3D stmmac_tx_status(priv, &priv->xstats, p, priv->ioaddr); /* Check if the descriptor is owned by the DMA */ if (unlikely(status & tx_dma_own)) break; @@ -2594,13 +2596,11 @@ static int stmmac_tx_clean(struct stmmac_priv *priv= , int budget, u32 queue) if (likely(!(status & tx_not_ls))) { /* ... verify the status error condition */ if (unlikely(status & tx_err)) { - priv->dev->stats.tx_errors++; + tx_errors++; if (unlikely(status & tx_err_bump_tc)) stmmac_bump_dma_threshold(priv, queue); } else { - priv->dev->stats.tx_packets++; - priv->xstats.tx_pkt_n++; - priv->xstats.txq_stats[queue].tx_pkt_n++; + tx_packets++; } if (skb) stmmac_get_tx_hwtstamp(priv, p, skb); @@ -2704,6 +2704,18 @@ static int stmmac_tx_clean(struct stmmac_priv *priv,= int budget, u32 queue) STMMAC_COAL_TIMER(priv->tx_coal_timer[queue]), HRTIMER_MODE_REL); =20 + u64_stats_update_begin(&priv->xstats.syncp); + priv->xstats.tx_packets +=3D tx_packets; + priv->xstats.tx_pkt_n +=3D tx_packets; + priv->xstats.tx_clean++; + u64_stats_update_end(&priv->xstats.syncp); + + u64_stats_update_begin(&priv->xstats.txq_stats[queue].syncp); + priv->xstats.txq_stats[queue].tx_pkt_n +=3D tx_packets; + u64_stats_update_end(&priv->xstats.txq_stats[queue].syncp); + + priv->xstats.tx_errors +=3D tx_errors; + __netif_tx_unlock_bh(netdev_get_tx_queue(priv->dev, queue)); =20 /* Combine decisions from TX clean and XSK TX */ @@ -2731,7 +2743,7 @@ static void stmmac_tx_err(struct stmmac_priv *priv, u= 32 chan) tx_q->dma_tx_phy, chan); stmmac_start_tx_dma(priv, chan); =20 - priv->dev->stats.tx_errors++; + priv->xstats.tx_errors++; netif_tx_wake_queue(netdev_get_tx_queue(priv->dev, chan)); } =20 @@ -4248,7 +4260,6 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *sk= b, struct net_device *dev) =20 tx_q->tx_count_frames =3D 0; stmmac_set_tx_ic(priv, desc); - priv->xstats.tx_set_ic_bit++; } =20 /* We've used all descriptors we need for this skb, however, @@ -4264,9 +4275,13 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *s= kb, struct net_device *dev) netif_tx_stop_queue(netdev_get_tx_queue(priv->dev, queue)); } =20 - dev->stats.tx_bytes +=3D skb->len; + u64_stats_update_begin(&priv->xstats.syncp); + priv->xstats.tx_bytes +=3D skb->len; priv->xstats.tx_tso_frames++; priv->xstats.tx_tso_nfrags +=3D nfrags; + if (set_ic) + priv->xstats.tx_set_ic_bit++; + u64_stats_update_end(&priv->xstats.syncp); =20 if (priv->sarc_type) stmmac_set_desc_sarc(priv, first, priv->sarc_type); @@ -4316,7 +4331,7 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *sk= b, struct net_device *dev) dma_map_err: dev_err(priv->device, "Tx dma map failed\n"); dev_kfree_skb(skb); - priv->dev->stats.tx_dropped++; + priv->xstats.tx_dropped++; return NETDEV_TX_OK; } =20 @@ -4470,7 +4485,6 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, s= truct net_device *dev) =20 tx_q->tx_count_frames =3D 0; stmmac_set_tx_ic(priv, desc); - priv->xstats.tx_set_ic_bit++; } =20 /* We've used all descriptors we need for this skb, however, @@ -4497,7 +4511,11 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, = struct net_device *dev) netif_tx_stop_queue(netdev_get_tx_queue(priv->dev, queue)); } =20 - dev->stats.tx_bytes +=3D skb->len; + u64_stats_update_begin(&priv->xstats.syncp); + priv->xstats.tx_bytes +=3D skb->len; + if (set_ic) + priv->xstats.tx_set_ic_bit++; + u64_stats_update_end(&priv->xstats.syncp); =20 if (priv->sarc_type) stmmac_set_desc_sarc(priv, first, priv->sarc_type); @@ -4559,7 +4577,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, s= truct net_device *dev) dma_map_err: netdev_err(priv->dev, "Tx DMA map failed\n"); dev_kfree_skb(skb); - priv->dev->stats.tx_dropped++; + priv->xstats.tx_dropped++; return NETDEV_TX_OK; } =20 @@ -4762,7 +4780,9 @@ static int stmmac_xdp_xmit_xdpf(struct stmmac_priv *p= riv, int queue, if (set_ic) { tx_q->tx_count_frames =3D 0; stmmac_set_tx_ic(priv, tx_desc); + u64_stats_update_begin(&priv->xstats.syncp); priv->xstats.tx_set_ic_bit++; + u64_stats_update_end(&priv->xstats.syncp); } =20 stmmac_enable_dma_transmission(priv, priv->ioaddr); @@ -4916,7 +4936,7 @@ static void stmmac_dispatch_skb_zc(struct stmmac_priv= *priv, u32 queue, =20 skb =3D stmmac_construct_skb_zc(ch, xdp); if (!skb) { - priv->dev->stats.rx_dropped++; + priv->xstats.rx_dropped++; return; } =20 @@ -4935,8 +4955,10 @@ static void stmmac_dispatch_skb_zc(struct stmmac_pri= v *priv, u32 queue, skb_record_rx_queue(skb, queue); napi_gro_receive(&ch->rxtx_napi, skb); =20 - priv->dev->stats.rx_packets++; - priv->dev->stats.rx_bytes +=3D len; + u64_stats_update_begin(&priv->xstats.syncp); + priv->xstats.rx_packets++; + priv->xstats.rx_bytes +=3D len; + u64_stats_update_end(&priv->xstats.syncp); } =20 static bool stmmac_rx_refill_zc(struct stmmac_priv *priv, u32 queue, u32 b= udget) @@ -5011,6 +5033,7 @@ static int stmmac_rx_zc(struct stmmac_priv *priv, int= limit, u32 queue) { struct stmmac_rx_queue *rx_q =3D &priv->dma_conf.rx_queue[queue]; unsigned int count =3D 0, error =3D 0, len =3D 0; + u32 rx_errors =3D 0, rx_dropped =3D 0; int dirty =3D stmmac_rx_dirty(priv, queue); unsigned int next_entry =3D rx_q->cur_rx; unsigned int desc_size; @@ -5071,8 +5094,7 @@ static int stmmac_rx_zc(struct stmmac_priv *priv, int= limit, u32 queue) p =3D rx_q->dma_rx + entry; =20 /* read the status of the incoming frame */ - status =3D stmmac_rx_status(priv, &priv->dev->stats, - &priv->xstats, p); + status =3D stmmac_rx_status(priv, &priv->xstats, p); /* check if managed by the DMA otherwise go ahead */ if (unlikely(status & dma_own)) break; @@ -5094,8 +5116,7 @@ static int stmmac_rx_zc(struct stmmac_priv *priv, int= limit, u32 queue) break; =20 if (priv->extend_desc) - stmmac_rx_extended_status(priv, &priv->dev->stats, - &priv->xstats, + stmmac_rx_extended_status(priv, &priv->xstats, rx_q->dma_erx + entry); if (unlikely(status =3D=3D discard_frame)) { xsk_buff_free(buf->xdp); @@ -5103,7 +5124,7 @@ static int stmmac_rx_zc(struct stmmac_priv *priv, int= limit, u32 queue) dirty++; error =3D 1; if (!priv->hwts_rx_en) - priv->dev->stats.rx_errors++; + rx_errors++; } =20 if (unlikely(error && (status & rx_not_ls))) @@ -5151,7 +5172,7 @@ static int stmmac_rx_zc(struct stmmac_priv *priv, int= limit, u32 queue) break; case STMMAC_XDP_CONSUMED: xsk_buff_free(buf->xdp); - priv->dev->stats.rx_dropped++; + rx_dropped++; break; case STMMAC_XDP_TX: case STMMAC_XDP_REDIRECT: @@ -5172,8 +5193,16 @@ static int stmmac_rx_zc(struct stmmac_priv *priv, in= t limit, u32 queue) =20 stmmac_finalize_xdp_rx(priv, xdp_status); =20 + u64_stats_update_begin(&priv->xstats.syncp); priv->xstats.rx_pkt_n +=3D count; + u64_stats_update_end(&priv->xstats.syncp); + + u64_stats_update_begin(&priv->xstats.rxq_stats[queue].syncp); priv->xstats.rxq_stats[queue].rx_pkt_n +=3D count; + u64_stats_update_end(&priv->xstats.rxq_stats[queue].syncp); + + priv->xstats.rx_dropped +=3D rx_dropped; + priv->xstats.rx_errors +=3D rx_errors; =20 if (xsk_uses_need_wakeup(rx_q->xsk_pool)) { if (failure || stmmac_rx_dirty(priv, queue) > 0) @@ -5197,6 +5226,7 @@ static int stmmac_rx_zc(struct stmmac_priv *priv, int= limit, u32 queue) */ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue) { + u32 rx_errors =3D 0, rx_dropped =3D 0, rx_bytes =3D 0, rx_packets =3D 0; struct stmmac_rx_queue *rx_q =3D &priv->dma_conf.rx_queue[queue]; struct stmmac_channel *ch =3D &priv->channel[queue]; unsigned int count =3D 0, error =3D 0, len =3D 0; @@ -5261,8 +5291,7 @@ static int stmmac_rx(struct stmmac_priv *priv, int li= mit, u32 queue) p =3D rx_q->dma_rx + entry; =20 /* read the status of the incoming frame */ - status =3D stmmac_rx_status(priv, &priv->dev->stats, - &priv->xstats, p); + status =3D stmmac_rx_status(priv, &priv->xstats, p); /* check if managed by the DMA otherwise go ahead */ if (unlikely(status & dma_own)) break; @@ -5279,14 +5308,13 @@ static int stmmac_rx(struct stmmac_priv *priv, int = limit, u32 queue) prefetch(np); =20 if (priv->extend_desc) - stmmac_rx_extended_status(priv, &priv->dev->stats, - &priv->xstats, rx_q->dma_erx + entry); + stmmac_rx_extended_status(priv, &priv->xstats, rx_q->dma_erx + entry); if (unlikely(status =3D=3D discard_frame)) { page_pool_recycle_direct(rx_q->page_pool, buf->page); buf->page =3D NULL; error =3D 1; if (!priv->hwts_rx_en) - priv->dev->stats.rx_errors++; + rx_errors++; } =20 if (unlikely(error && (status & rx_not_ls))) @@ -5354,7 +5382,7 @@ static int stmmac_rx(struct stmmac_priv *priv, int li= mit, u32 queue) virt_to_head_page(ctx.xdp.data), sync_len, true); buf->page =3D NULL; - priv->dev->stats.rx_dropped++; + rx_dropped++; =20 /* Clear skb as it was set as * status by XDP program. @@ -5383,7 +5411,7 @@ static int stmmac_rx(struct stmmac_priv *priv, int li= mit, u32 queue) =20 skb =3D napi_alloc_skb(&ch->rx_napi, buf1_len); if (!skb) { - priv->dev->stats.rx_dropped++; + rx_dropped++; count++; goto drain_data; } @@ -5443,8 +5471,8 @@ static int stmmac_rx(struct stmmac_priv *priv, int li= mit, u32 queue) napi_gro_receive(&ch->rx_napi, skb); skb =3D NULL; =20 - priv->dev->stats.rx_packets++; - priv->dev->stats.rx_bytes +=3D len; + rx_packets++; + rx_bytes +=3D len; count++; } =20 @@ -5459,8 +5487,18 @@ static int stmmac_rx(struct stmmac_priv *priv, int l= imit, u32 queue) =20 stmmac_rx_refill(priv, queue); =20 + u64_stats_update_begin(&priv->xstats.syncp); + priv->xstats.rx_packets +=3D rx_packets; + priv->xstats.rx_bytes +=3D rx_bytes; priv->xstats.rx_pkt_n +=3D count; + u64_stats_update_end(&priv->xstats.syncp); + + u64_stats_update_begin(&priv->xstats.rxq_stats[queue].syncp); priv->xstats.rxq_stats[queue].rx_pkt_n +=3D count; + u64_stats_update_end(&priv->xstats.rxq_stats[queue].syncp); + + priv->xstats.rx_dropped +=3D rx_dropped; + priv->xstats.rx_errors +=3D rx_errors; =20 return count; } @@ -5473,7 +5511,9 @@ static int stmmac_napi_poll_rx(struct napi_struct *na= pi, int budget) u32 chan =3D ch->index; int work_done; =20 + u64_stats_update_begin(&priv->xstats.syncp); priv->xstats.napi_poll++; + u64_stats_update_end(&priv->xstats.syncp); =20 work_done =3D stmmac_rx(priv, budget, chan); if (work_done < budget && napi_complete_done(napi, work_done)) { @@ -5495,7 +5535,9 @@ static int stmmac_napi_poll_tx(struct napi_struct *na= pi, int budget) u32 chan =3D ch->index; int work_done; =20 + u64_stats_update_begin(&priv->xstats.syncp); priv->xstats.napi_poll++; + u64_stats_update_end(&priv->xstats.syncp); =20 work_done =3D stmmac_tx_clean(priv, budget, chan); work_done =3D min(work_done, budget); @@ -5519,7 +5561,9 @@ static int stmmac_napi_poll_rxtx(struct napi_struct *= napi, int budget) int rx_done, tx_done, rxtx_done; u32 chan =3D ch->index; =20 + u64_stats_update_begin(&priv->xstats.syncp); priv->xstats.napi_poll++; + u64_stats_update_end(&priv->xstats.syncp); =20 tx_done =3D stmmac_tx_clean(priv, budget, chan); tx_done =3D min(tx_done, budget); @@ -6775,6 +6819,39 @@ int stmmac_xsk_wakeup(struct net_device *dev, u32 qu= eue, u32 flags) return 0; } =20 +static void stmmac_get_stats64(struct net_device *dev, struct rtnl_link_st= ats64 *stats) +{ + struct stmmac_priv *priv =3D netdev_priv(dev); + unsigned int start; + u64 rx_packets; + u64 rx_bytes; + u64 tx_packets; + u64 tx_bytes; + + do { + start =3D u64_stats_fetch_begin(&priv->xstats.syncp); + rx_packets =3D priv->xstats.rx_packets; + rx_bytes =3D priv->xstats.rx_bytes; + tx_packets =3D priv->xstats.tx_packets; + tx_bytes =3D priv->xstats.tx_bytes; + } while (u64_stats_fetch_retry(&priv->xstats.syncp, start)); + + stats->rx_packets =3D rx_packets; + stats->rx_bytes =3D rx_bytes; + stats->tx_packets =3D tx_packets; + stats->tx_bytes =3D tx_bytes; + stats->rx_dropped =3D priv->xstats.rx_dropped; + stats->rx_errors =3D priv->xstats.rx_errors; + stats->tx_dropped =3D priv->xstats.tx_dropped; + stats->tx_errors =3D priv->xstats.tx_errors; + stats->tx_carrier_errors =3D priv->xstats.tx_losscarrier + priv->xstats.t= x_carrier; + stats->collisions =3D priv->xstats.tx_collision + priv->xstats.rx_collisi= on; + stats->rx_length_errors =3D priv->xstats.rx_length; + stats->rx_crc_errors =3D priv->xstats.rx_crc_errors; + stats->rx_over_errors =3D priv->xstats.rx_overflow_cntr; + stats->rx_missed_errors =3D priv->xstats.rx_missed_cntr; +} + static const struct net_device_ops stmmac_netdev_ops =3D { .ndo_open =3D stmmac_open, .ndo_start_xmit =3D stmmac_xmit, @@ -6785,6 +6862,7 @@ static const struct net_device_ops stmmac_netdev_ops = =3D { .ndo_set_rx_mode =3D stmmac_set_rx_mode, .ndo_tx_timeout =3D stmmac_tx_timeout, .ndo_eth_ioctl =3D stmmac_ioctl, + .ndo_get_stats64 =3D stmmac_get_stats64, .ndo_setup_tc =3D stmmac_setup_tc, .ndo_select_queue =3D stmmac_select_queue, #ifdef CONFIG_NET_POLL_CONTROLLER @@ -7305,6 +7383,12 @@ int stmmac_dvr_probe(struct device *device, =20 priv->xstats.threshold =3D tc; =20 + u64_stats_init(&priv->xstats.syncp); + for (i =3D 0; i < priv->plat->rx_queues_to_use; i++) + u64_stats_init(&priv->xstats.rxq_stats[i].syncp); + for (i =3D 0; i < priv->plat->tx_queues_to_use; i++) + u64_stats_init(&priv->xstats.txq_stats[i].syncp); + /* Initialize RSS */ rxq =3D priv->plat->rx_queues_to_use; netdev_rss_key_fill(priv->rss.key, sizeof(priv->rss.key)); --=20 2.40.1