]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
net: fman_memac: report structured ethtool counters
authorVladimir Oltean <vladimir.oltean@nxp.com>
Sat, 22 Nov 2025 11:59:31 +0000 (13:59 +0200)
committerJakub Kicinski <kuba@kernel.org>
Thu, 27 Nov 2025 02:10:41 +0000 (18:10 -0800)
The FMan driver has support for 2 MACs: mEMAC (newer, present on
Layerscape and PowerPC T series) and dTSEC/TGEC (older, present on
PowerPC P series). I only have handy access to the mEMAC, and this adds
support for MAC counters for those platforms.

MAC counters are necessary for any kind of low-level debugging, and
currently there is no mechanism to dump them.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Link: https://patch.msgid.link/20251122115931.151719-1-vladimir.oltean@nxp.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c
drivers/net/ethernet/freescale/fman/fman_memac.c
drivers/net/ethernet/freescale/fman/mac.h

index d09e456f14c02bcc2eae6acab4907a957416a53e..ed3fa80af8c3f921a927711ed782a4a4dfd1f638 100644 (file)
@@ -467,6 +467,47 @@ revert_values:
        return res;
 }
 
+static void dpaa_get_pause_stats(struct net_device *net_dev,
+                                struct ethtool_pause_stats *s)
+{
+       struct dpaa_priv *priv = netdev_priv(net_dev);
+       struct mac_device *mac_dev = priv->mac_dev;
+
+       if (mac_dev->get_pause_stats)
+               mac_dev->get_pause_stats(mac_dev->fman_mac, s);
+}
+
+static void dpaa_get_rmon_stats(struct net_device *net_dev,
+                               struct ethtool_rmon_stats *s,
+                               const struct ethtool_rmon_hist_range **ranges)
+{
+       struct dpaa_priv *priv = netdev_priv(net_dev);
+       struct mac_device *mac_dev = priv->mac_dev;
+
+       if (mac_dev->get_rmon_stats)
+               mac_dev->get_rmon_stats(mac_dev->fman_mac, s, ranges);
+}
+
+static void dpaa_get_eth_ctrl_stats(struct net_device *net_dev,
+                                   struct ethtool_eth_ctrl_stats *s)
+{
+       struct dpaa_priv *priv = netdev_priv(net_dev);
+       struct mac_device *mac_dev = priv->mac_dev;
+
+       if (mac_dev->get_eth_ctrl_stats)
+               mac_dev->get_eth_ctrl_stats(mac_dev->fman_mac, s);
+}
+
+static void dpaa_get_eth_mac_stats(struct net_device *net_dev,
+                                  struct ethtool_eth_mac_stats *s)
+{
+       struct dpaa_priv *priv = netdev_priv(net_dev);
+       struct mac_device *mac_dev = priv->mac_dev;
+
+       if (mac_dev->get_eth_mac_stats)
+               mac_dev->get_eth_mac_stats(mac_dev->fman_mac, s);
+}
+
 const struct ethtool_ops dpaa_ethtool_ops = {
        .supported_coalesce_params = ETHTOOL_COALESCE_RX_USECS |
                                     ETHTOOL_COALESCE_RX_MAX_FRAMES,
@@ -487,4 +528,8 @@ const struct ethtool_ops dpaa_ethtool_ops = {
        .get_ts_info = dpaa_get_ts_info,
        .get_coalesce = dpaa_get_coalesce,
        .set_coalesce = dpaa_set_coalesce,
+       .get_pause_stats = dpaa_get_pause_stats,
+       .get_rmon_stats = dpaa_get_rmon_stats,
+       .get_eth_ctrl_stats = dpaa_get_eth_ctrl_stats,
+       .get_eth_mac_stats = dpaa_get_eth_mac_stats,
 };
index d32ffd6be7b1e0552f6608f1eb92b0c6d7b727ac..c84f0336c94c9c8a967da42d74f2a80743648761 100644 (file)
@@ -900,6 +900,89 @@ static int memac_set_exception(struct fman_mac *memac,
        return 0;
 }
 
+static u64 memac_read64(void __iomem *reg)
+{
+       u32 low, high, tmp;
+
+       do {
+               high = ioread32be(reg + 4);
+               low = ioread32be(reg);
+               tmp = ioread32be(reg + 4);
+       } while (high != tmp);
+
+       return ((u64)high << 32) | low;
+}
+
+static void memac_get_pause_stats(struct fman_mac *memac,
+                                 struct ethtool_pause_stats *s)
+{
+       s->tx_pause_frames = memac_read64(&memac->regs->txpf_l);
+       s->rx_pause_frames = memac_read64(&memac->regs->rxpf_l);
+}
+
+static const struct ethtool_rmon_hist_range memac_rmon_ranges[] = {
+       {   64,   64 },
+       {   65,  127 },
+       {  128,  255 },
+       {  256,  511 },
+       {  512, 1023 },
+       { 1024, 1518 },
+       { 1519, 9600 },
+       {},
+};
+
+static void memac_get_rmon_stats(struct fman_mac *memac,
+                                struct ethtool_rmon_stats *s,
+                                const struct ethtool_rmon_hist_range **ranges)
+{
+       s->undersize_pkts = memac_read64(&memac->regs->rund_l);
+       s->oversize_pkts = memac_read64(&memac->regs->rovr_l);
+       s->fragments = memac_read64(&memac->regs->rfrg_l);
+       s->jabbers = memac_read64(&memac->regs->rjbr_l);
+
+       s->hist[0] = memac_read64(&memac->regs->r64_l);
+       s->hist[1] = memac_read64(&memac->regs->r127_l);
+       s->hist[2] = memac_read64(&memac->regs->r255_l);
+       s->hist[3] = memac_read64(&memac->regs->r511_l);
+       s->hist[4] = memac_read64(&memac->regs->r1023_l);
+       s->hist[5] = memac_read64(&memac->regs->r1518_l);
+       s->hist[6] = memac_read64(&memac->regs->r1519x_l);
+
+       s->hist_tx[0] = memac_read64(&memac->regs->t64_l);
+       s->hist_tx[1] = memac_read64(&memac->regs->t127_l);
+       s->hist_tx[2] = memac_read64(&memac->regs->t255_l);
+       s->hist_tx[3] = memac_read64(&memac->regs->t511_l);
+       s->hist_tx[4] = memac_read64(&memac->regs->t1023_l);
+       s->hist_tx[5] = memac_read64(&memac->regs->t1518_l);
+       s->hist_tx[6] = memac_read64(&memac->regs->t1519x_l);
+
+       *ranges = memac_rmon_ranges;
+}
+
+static void memac_get_eth_ctrl_stats(struct fman_mac *memac,
+                                    struct ethtool_eth_ctrl_stats *s)
+{
+       s->MACControlFramesTransmitted = memac_read64(&memac->regs->tcnp_l);
+       s->MACControlFramesReceived = memac_read64(&memac->regs->rcnp_l);
+}
+
+static void memac_get_eth_mac_stats(struct fman_mac *memac,
+                                   struct ethtool_eth_mac_stats *s)
+{
+       s->FramesTransmittedOK = memac_read64(&memac->regs->tfrm_l);
+       s->FramesReceivedOK = memac_read64(&memac->regs->rfrm_l);
+       s->FrameCheckSequenceErrors = memac_read64(&memac->regs->rfcs_l);
+       s->AlignmentErrors = memac_read64(&memac->regs->raln_l);
+       s->OctetsTransmittedOK = memac_read64(&memac->regs->teoct_l);
+       s->FramesLostDueToIntMACXmitError = memac_read64(&memac->regs->terr_l);
+       s->OctetsReceivedOK = memac_read64(&memac->regs->reoct_l);
+       s->FramesLostDueToIntMACRcvError = memac_read64(&memac->regs->rdrntp_l);
+       s->MulticastFramesXmittedOK = memac_read64(&memac->regs->tmca_l);
+       s->BroadcastFramesXmittedOK = memac_read64(&memac->regs->tbca_l);
+       s->MulticastFramesReceivedOK = memac_read64(&memac->regs->rmca_l);
+       s->BroadcastFramesReceivedOK = memac_read64(&memac->regs->rbca_l);
+}
+
 static int memac_init(struct fman_mac *memac)
 {
        struct memac_cfg *memac_drv_param;
@@ -1092,6 +1175,10 @@ int memac_initialization(struct mac_device *mac_dev,
        mac_dev->set_tstamp             = memac_set_tstamp;
        mac_dev->enable                 = memac_enable;
        mac_dev->disable                = memac_disable;
+       mac_dev->get_pause_stats        = memac_get_pause_stats;
+       mac_dev->get_rmon_stats         = memac_get_rmon_stats;
+       mac_dev->get_eth_ctrl_stats     = memac_get_eth_ctrl_stats;
+       mac_dev->get_eth_mac_stats      = memac_get_eth_mac_stats;
 
        mac_dev->fman_mac = memac_config(mac_dev, params);
        if (!mac_dev->fman_mac)
index 955ace338965a77efb17baf3bfbf4b0781512c82..63c2c5b4f99ea2766bd6f87add8d3f28df43ca53 100644 (file)
 #include "fman.h"
 #include "fman_mac.h"
 
+struct ethtool_eth_ctrl_stats;
+struct ethtool_eth_mac_stats;
+struct ethtool_pause_stats;
+struct ethtool_rmon_stats;
+struct ethtool_rmon_hist_range;
 struct fman_mac;
 struct mac_priv_s;
 
@@ -46,6 +51,15 @@ struct mac_device {
                                 enet_addr_t *eth_addr);
        int (*remove_hash_mac_addr)(struct fman_mac *mac_dev,
                                    enet_addr_t *eth_addr);
+       void (*get_pause_stats)(struct fman_mac *memac,
+                               struct ethtool_pause_stats *s);
+       void (*get_rmon_stats)(struct fman_mac *memac,
+                              struct ethtool_rmon_stats *s,
+                              const struct ethtool_rmon_hist_range **ranges);
+       void (*get_eth_ctrl_stats)(struct fman_mac *memac,
+                                  struct ethtool_eth_ctrl_stats *s);
+       void (*get_eth_mac_stats)(struct fman_mac *memac,
+                                 struct ethtool_eth_mac_stats *s);
 
        void (*update_speed)(struct mac_device *mac_dev, int speed);