2021-06-17 11:01:38

by Esben Haabendal

[permalink] [raw]
Subject: [PATCH 0/6] net: gianfar: 64-bit statistics and rx_missed_errors counter

This series replaces the legacy 32-bit statistics to proper 64-bit ditto,
and implements rx_missed_errors counter on top of that.

The device supports a 16-bit RDRP counter, and a related carry bit and
interrupt, which allows implementation of a robust 64-bit counter.

Esben Haabendal (6):
net: gianfar: Convert to ndo_get_stats64 interface
net: gianfar: Extend statistics counters to 64-bit
net: gianfar: Clear CAR registers
net: gianfar: Avoid 16 bytes of memset
net: gianfar: Add definitions for CAR1 and CAM1 register bits
net: gianfar: Implement rx_missed_errors counter

drivers/net/ethernet/freescale/gianfar.c | 76 +++++++++++++++++-------
drivers/net/ethernet/freescale/gianfar.h | 74 +++++++++++++++++++++--
2 files changed, 125 insertions(+), 25 deletions(-)

--
2.32.0


2021-06-17 11:04:11

by Esben Haabendal

[permalink] [raw]
Subject: [PATCH 6/6] net: gianfar: Implement rx_missed_errors counter

Devices with RMON support has a 16-bit RDRP counter. It provides: "Receive
dropped packets counter. Increments for frames received which are streamed
to system but are later dropped due to lack of system resources."

To handle more than 2^16 dropped packets, a carry bit in CAR1 register is
set on overflow, so we enable irq when this is set, extending the counter
to 2^64 for handling situations where lots of packets are missed (e.g.
during heavy network storms).

Signed-off-by: Esben Haabendal <[email protected]>
---
drivers/net/ethernet/freescale/gianfar.c | 50 ++++++++++++++++++++++--
drivers/net/ethernet/freescale/gianfar.h | 10 +++++
2 files changed, 57 insertions(+), 3 deletions(-)

diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c
index 4608c0c337bc..9646483137c4 100644
--- a/drivers/net/ethernet/freescale/gianfar.c
+++ b/drivers/net/ethernet/freescale/gianfar.c
@@ -289,6 +289,29 @@ static void gfar_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *s
stats->tx_bytes += priv->tx_queue[i]->stats.tx_bytes;
stats->tx_packets += priv->tx_queue[i]->stats.tx_packets;
}
+
+ if (priv->device_flags & FSL_GIANFAR_DEV_HAS_RMON) {
+ struct rmon_mib __iomem *rmon = &priv->gfargrp[0].regs->rmon;
+ unsigned long flags;
+ u32 rdrp, car, car_before;
+ u64 rdrp_offset;
+
+ spin_lock_irqsave(&priv->rmon_overflow.lock, flags);
+ car = gfar_read(&rmon->car1) & CAR1_C1RDR;
+ do {
+ car_before = car;
+ rdrp = gfar_read(&rmon->rdrp);
+ car = gfar_read(&rmon->car1) & CAR1_C1RDR;
+ } while (car != car_before);
+ if (car) {
+ priv->rmon_overflow.rdrp++;
+ gfar_write(&rmon->car1, car);
+ }
+ rdrp_offset = priv->rmon_overflow.rdrp;
+ spin_unlock_irqrestore(&priv->rmon_overflow.lock, flags);
+
+ stats->rx_missed_errors = rdrp + (rdrp_offset << 16);
+ }
}

/* Set the appropriate hash bit for the given addr */
@@ -379,7 +402,8 @@ static void gfar_ints_enable(struct gfar_private *priv)
for (i = 0; i < priv->num_grps; i++) {
struct gfar __iomem *regs = priv->gfargrp[i].regs;
/* Unmask the interrupts we look for */
- gfar_write(&regs->imask, IMASK_DEFAULT);
+ gfar_write(&regs->imask,
+ IMASK_DEFAULT | priv->rmon_overflow.imask);
}
}

@@ -2287,7 +2311,7 @@ static irqreturn_t gfar_receive(int irq, void *grp_id)
if (likely(napi_schedule_prep(&grp->napi_rx))) {
spin_lock_irqsave(&grp->grplock, flags);
imask = gfar_read(&grp->regs->imask);
- imask &= IMASK_RX_DISABLED;
+ imask &= IMASK_RX_DISABLED | grp->priv->rmon_overflow.imask;
gfar_write(&grp->regs->imask, imask);
spin_unlock_irqrestore(&grp->grplock, flags);
__napi_schedule(&grp->napi_rx);
@@ -2311,7 +2335,7 @@ static irqreturn_t gfar_transmit(int irq, void *grp_id)
if (likely(napi_schedule_prep(&grp->napi_tx))) {
spin_lock_irqsave(&grp->grplock, flags);
imask = gfar_read(&grp->regs->imask);
- imask &= IMASK_TX_DISABLED;
+ imask &= IMASK_TX_DISABLED | grp->priv->rmon_overflow.imask;
gfar_write(&grp->regs->imask, imask);
spin_unlock_irqrestore(&grp->grplock, flags);
__napi_schedule(&grp->napi_tx);
@@ -2682,6 +2706,18 @@ static irqreturn_t gfar_error(int irq, void *grp_id)
}
netif_dbg(priv, tx_err, dev, "Transmit Error\n");
}
+ if (events & IEVENT_MSRO) {
+ struct rmon_mib __iomem *rmon = &regs->rmon;
+ u32 car;
+
+ spin_lock(&priv->rmon_overflow.lock);
+ car = gfar_read(&rmon->car1) & CAR1_C1RDR;
+ if (car) {
+ priv->rmon_overflow.rdrp++;
+ gfar_write(&rmon->car1, car);
+ }
+ spin_unlock(&priv->rmon_overflow.lock);
+ }
if (events & IEVENT_BSY) {
dev->stats.rx_over_errors++;
atomic64_inc(&priv->extra_stats.rx_bsy);
@@ -3259,6 +3295,14 @@ static int gfar_probe(struct platform_device *ofdev)

gfar_hw_init(priv);

+ if (priv->device_flags & FSL_GIANFAR_DEV_HAS_RMON) {
+ struct rmon_mib __iomem *rmon = &priv->gfargrp[0].regs->rmon;
+
+ spin_lock_init(&priv->rmon_overflow.lock);
+ priv->rmon_overflow.imask = IMASK_MSRO;
+ gfar_write(&rmon->cam1, gfar_read(&rmon->cam1) & ~CAM1_M1RDR);
+ }
+
/* Carrier starts down, phylib will bring it up */
netif_carrier_off(dev);

diff --git a/drivers/net/ethernet/freescale/gianfar.h b/drivers/net/ethernet/freescale/gianfar.h
index c8aa140a910f..ca5e14f908fe 100644
--- a/drivers/net/ethernet/freescale/gianfar.h
+++ b/drivers/net/ethernet/freescale/gianfar.h
@@ -663,6 +663,15 @@ struct rmon_mib
u32 cam2; /* 0x.73c - Carry Mask Register Two */
};

+struct rmon_overflow {
+ /* lock for synchronization of the rdrp field of this struct, and
+ * CAR1/CAR2 registers
+ */
+ spinlock_t lock;
+ u32 imask;
+ u64 rdrp;
+};
+
struct gfar_extra_stats {
atomic64_t rx_alloc_err;
atomic64_t rx_large;
@@ -1150,6 +1159,7 @@ struct gfar_private {

/* Network Statistics */
struct gfar_extra_stats extra_stats;
+ struct rmon_overflow rmon_overflow;

/* PHY stuff */
phy_interface_t interface;
--
2.32.0

2021-06-17 12:04:31

by Esben Haabendal

[permalink] [raw]
Subject: [PATCH 5/6] net: gianfar: Add definitions for CAR1 and CAM1 register bits

These are for carry status and interrupt mask bits of statistics registers.

Signed-off-by: Esben Haabendal <[email protected]>
---
drivers/net/ethernet/freescale/gianfar.h | 54 ++++++++++++++++++++++++
1 file changed, 54 insertions(+)

diff --git a/drivers/net/ethernet/freescale/gianfar.h b/drivers/net/ethernet/freescale/gianfar.h
index d8ae5353e881..c8aa140a910f 100644
--- a/drivers/net/ethernet/freescale/gianfar.h
+++ b/drivers/net/ethernet/freescale/gianfar.h
@@ -445,6 +445,60 @@ struct ethtool_rx_list {
#define RQFPR_PER 0x00000002
#define RQFPR_EER 0x00000001

+/* CAR1 bits */
+#define CAR1_C164 0x80000000
+#define CAR1_C1127 0x40000000
+#define CAR1_C1255 0x20000000
+#define CAR1_C1511 0x10000000
+#define CAR1_C11K 0x08000000
+#define CAR1_C1MAX 0x04000000
+#define CAR1_C1MGV 0x02000000
+#define CAR1_C1REJ 0x00020000
+#define CAR1_C1RBY 0x00010000
+#define CAR1_C1RPK 0x00008000
+#define CAR1_C1RFC 0x00004000
+#define CAR1_C1RMC 0x00002000
+#define CAR1_C1RBC 0x00001000
+#define CAR1_C1RXC 0x00000800
+#define CAR1_C1RXP 0x00000400
+#define CAR1_C1RXU 0x00000200
+#define CAR1_C1RAL 0x00000100
+#define CAR1_C1RFL 0x00000080
+#define CAR1_C1RCD 0x00000040
+#define CAR1_C1RCS 0x00000020
+#define CAR1_C1RUN 0x00000010
+#define CAR1_C1ROV 0x00000008
+#define CAR1_C1RFR 0x00000004
+#define CAR1_C1RJB 0x00000002
+#define CAR1_C1RDR 0x00000001
+
+/* CAM1 bits */
+#define CAM1_M164 0x80000000
+#define CAM1_M1127 0x40000000
+#define CAM1_M1255 0x20000000
+#define CAM1_M1511 0x10000000
+#define CAM1_M11K 0x08000000
+#define CAM1_M1MAX 0x04000000
+#define CAM1_M1MGV 0x02000000
+#define CAM1_M1REJ 0x00020000
+#define CAM1_M1RBY 0x00010000
+#define CAM1_M1RPK 0x00008000
+#define CAM1_M1RFC 0x00004000
+#define CAM1_M1RMC 0x00002000
+#define CAM1_M1RBC 0x00001000
+#define CAM1_M1RXC 0x00000800
+#define CAM1_M1RXP 0x00000400
+#define CAM1_M1RXU 0x00000200
+#define CAM1_M1RAL 0x00000100
+#define CAM1_M1RFL 0x00000080
+#define CAM1_M1RCD 0x00000040
+#define CAM1_M1RCS 0x00000020
+#define CAM1_M1RUN 0x00000010
+#define CAM1_M1ROV 0x00000008
+#define CAM1_M1RFR 0x00000004
+#define CAM1_M1RJB 0x00000002
+#define CAM1_M1RDR 0x00000001
+
/* TxBD status field bits */
#define TXBD_READY 0x8000
#define TXBD_PADCRC 0x4000
--
2.32.0

2021-06-17 12:04:52

by Esben Haabendal

[permalink] [raw]
Subject: [PATCH 2/6] net: gianfar: Extend statistics counters to 64-bit

No reason to wrap counter values at 2^32. Especially the bytes counters
can wrap pretty fast on Gbit networks.

Signed-off-by: Esben Haabendal <[email protected]>
---
drivers/net/ethernet/freescale/gianfar.h | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/drivers/net/ethernet/freescale/gianfar.h b/drivers/net/ethernet/freescale/gianfar.h
index 5ea47df93e5e..d8ae5353e881 100644
--- a/drivers/net/ethernet/freescale/gianfar.h
+++ b/drivers/net/ethernet/freescale/gianfar.h
@@ -913,8 +913,8 @@ enum {
* Per TX queue stats
*/
struct tx_q_stats {
- unsigned long tx_packets;
- unsigned long tx_bytes;
+ u64 tx_packets;
+ u64 tx_bytes;
};

/**
@@ -963,9 +963,9 @@ struct gfar_priv_tx_q {
* Per RX queue stats
*/
struct rx_q_stats {
- unsigned long rx_packets;
- unsigned long rx_bytes;
- unsigned long rx_dropped;
+ u64 rx_packets;
+ u64 rx_bytes;
+ u64 rx_dropped;
};

struct gfar_rx_buff {
--
2.32.0

2021-06-17 20:58:44

by patchwork-bot+netdevbpf

[permalink] [raw]
Subject: Re: [PATCH 0/6] net: gianfar: 64-bit statistics and rx_missed_errors counter

Hello:

This series was applied to netdev/net-next.git (refs/heads/master):

On Thu, 17 Jun 2021 11:49:12 +0200 you wrote:
> This series replaces the legacy 32-bit statistics to proper 64-bit ditto,
> and implements rx_missed_errors counter on top of that.
>
> The device supports a 16-bit RDRP counter, and a related carry bit and
> interrupt, which allows implementation of a robust 64-bit counter.
>
> Esben Haabendal (6):
> net: gianfar: Convert to ndo_get_stats64 interface
> net: gianfar: Extend statistics counters to 64-bit
> net: gianfar: Clear CAR registers
> net: gianfar: Avoid 16 bytes of memset
> net: gianfar: Add definitions for CAR1 and CAM1 register bits
> net: gianfar: Implement rx_missed_errors counter
>
> [...]

Here is the summary with links:
- [1/6] net: gianfar: Convert to ndo_get_stats64 interface
https://git.kernel.org/netdev/net-next/c/d59a24fd1bdb
- [2/6] net: gianfar: Extend statistics counters to 64-bit
https://git.kernel.org/netdev/net-next/c/2658530d797f
- [3/6] net: gianfar: Clear CAR registers
https://git.kernel.org/netdev/net-next/c/ef09487431a9
- [4/6] net: gianfar: Avoid 16 bytes of memset
https://git.kernel.org/netdev/net-next/c/e2dbbbe52c4a
- [5/6] net: gianfar: Add definitions for CAR1 and CAM1 register bits
https://git.kernel.org/netdev/net-next/c/8da32a1071af
- [6/6] net: gianfar: Implement rx_missed_errors counter
https://git.kernel.org/netdev/net-next/c/14870b75fe0b

You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html