[PATCH net-next v17 2/2] hinic3: Add ethtool statistic ops part2

From: Fan Gong

Date: Sun Oct 18 2026 - 23:50:14 EST


This commit adds five standard ethtool statistics callbacks to the hinic3
driver: get_eth_phy_stats, get_eth_mac_stats, get_eth_ctrl_stats,
get_rmon_stats and get_pause_stats. Each callback reads the physical port
counters from firmware via hinic3_get_phy_port_stats() and copies them
into the standard ethtool structures.

Co-developed-by: Wu Di <wudi234@xxxxxxxxxx>
Signed-off-by: Wu Di <wudi234@xxxxxxxxxx>
Co-developed-by: Teng Peisen <tengpeisen@xxxxxxxxxx>
Signed-off-by: Teng Peisen <tengpeisen@xxxxxxxxxx>
Signed-off-by: Fan Gong <gongfan1@xxxxxxxxxx>
---
.../ethernet/huawei/hinic3/hinic3_ethtool.c | 202 ++++++++++++++++++
1 file changed, 202 insertions(+)

diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_ethtool.c b/drivers/net/ethernet/huawei/hinic3/hinic3_ethtool.c
index 64c862052f1e..2ae4d5afe90d 100644
--- a/drivers/net/ethernet/huawei/hinic3/hinic3_ethtool.c
+++ b/drivers/net/ethernet/huawei/hinic3/hinic3_ethtool.c
@@ -696,6 +696,203 @@ static void hinic3_get_ethtool_stats(struct net_device *netdev,
hinic3_get_drv_queue_stats(netdev, data + i);
}

+static void hinic3_get_eth_phy_stats(struct net_device *netdev,
+ struct ethtool_eth_phy_stats *phy_stats)
+{
+ struct hinic3_nic_dev *nic_dev = netdev_priv(netdev);
+ struct mag_cmd_port_stats *ps;
+ int err;
+
+ if (HINIC3_IS_VF(nic_dev->hwdev))
+ return;
+
+ ps = kmalloc_obj(*ps);
+ if (!ps)
+ return;
+
+ err = hinic3_get_phy_port_stats(nic_dev->hwdev, ps);
+ if (err) {
+ kfree(ps);
+ netdev_err(netdev, "Failed to get eth phy stats from fw\n");
+ return;
+ }
+
+ phy_stats->SymbolErrorDuringCarrier =
+ le64_to_cpu(ps->mac_rx_sym_err_pkts);
+
+ kfree(ps);
+}
+
+static void hinic3_get_eth_mac_stats(struct net_device *netdev,
+ struct ethtool_eth_mac_stats *mac_stats)
+{
+ struct hinic3_nic_dev *nic_dev = netdev_priv(netdev);
+ struct mag_cmd_port_stats *ps;
+ int err;
+
+ if (HINIC3_IS_VF(nic_dev->hwdev))
+ return;
+
+ ps = kmalloc_obj(*ps);
+ if (!ps)
+ return;
+
+ err = hinic3_get_phy_port_stats(nic_dev->hwdev, ps);
+ if (err) {
+ kfree(ps);
+ netdev_err(netdev, "Failed to get eth mac stats from fw\n");
+ return;
+ }
+
+ mac_stats->FramesTransmittedOK =
+ le64_to_cpu(ps->mac_tx_good_pkts);
+ mac_stats->FramesReceivedOK =
+ le64_to_cpu(ps->mac_rx_good_pkts);
+ mac_stats->FrameCheckSequenceErrors =
+ le64_to_cpu(ps->mac_rx_fcs_err_pkts);
+ mac_stats->OctetsTransmittedOK =
+ le64_to_cpu(ps->mac_tx_good_octs);
+ mac_stats->OctetsReceivedOK =
+ le64_to_cpu(ps->mac_rx_good_octs);
+ mac_stats->MulticastFramesXmittedOK =
+ le64_to_cpu(ps->mac_tx_multi_pkts);
+ mac_stats->BroadcastFramesXmittedOK =
+ le64_to_cpu(ps->mac_tx_broad_pkts);
+ mac_stats->MulticastFramesReceivedOK =
+ le64_to_cpu(ps->mac_rx_multi_pkts);
+ mac_stats->BroadcastFramesReceivedOK =
+ le64_to_cpu(ps->mac_rx_broad_pkts);
+
+ kfree(ps);
+}
+
+static void hinic3_get_eth_ctrl_stats(struct net_device *netdev,
+ struct ethtool_eth_ctrl_stats *ctrl_stats)
+{
+ struct hinic3_nic_dev *nic_dev = netdev_priv(netdev);
+ struct mag_cmd_port_stats *ps;
+ int err;
+
+ if (HINIC3_IS_VF(nic_dev->hwdev))
+ return;
+
+ ps = kmalloc_obj(*ps);
+ if (!ps)
+ return;
+
+ err = hinic3_get_phy_port_stats(nic_dev->hwdev, ps);
+ if (err) {
+ kfree(ps);
+ netdev_err(netdev, "Failed to get eth ctrl stats from fw\n");
+ return;
+ }
+
+ ctrl_stats->MACControlFramesTransmitted =
+ le64_to_cpu(ps->mac_tx_control_pkts);
+ ctrl_stats->MACControlFramesReceived =
+ le64_to_cpu(ps->mac_rx_control_pkts);
+
+ kfree(ps);
+}
+
+static const struct ethtool_rmon_hist_range hinic3_rmon_ranges[] = {
+ { 0, 64 },
+ { 65, 127 },
+ { 128, 255 },
+ { 256, 511 },
+ { 512, 1023 },
+ { 1024, 1518 },
+ { 1519, 2047 },
+ { 2048, 4095 },
+ { 4096, 8191 },
+ { 8192, 9216 },
+ { 9217, 12287 },
+ {}
+};
+
+static void hinic3_get_rmon_stats(struct net_device *netdev,
+ struct ethtool_rmon_stats *rmon_stats,
+ const struct ethtool_rmon_hist_range **ranges)
+{
+ struct hinic3_nic_dev *nic_dev = netdev_priv(netdev);
+ struct mag_cmd_port_stats *ps;
+ int err;
+
+ if (HINIC3_IS_VF(nic_dev->hwdev))
+ return;
+
+ ps = kmalloc_obj(*ps);
+ if (!ps)
+ return;
+
+ err = hinic3_get_phy_port_stats(nic_dev->hwdev, ps);
+ if (err) {
+ kfree(ps);
+ netdev_err(netdev, "Failed to get eth rmon stats from fw\n");
+ return;
+ }
+
+ rmon_stats->undersize_pkts = le64_to_cpu(ps->mac_rx_undersize_pkts);
+ rmon_stats->oversize_pkts = le64_to_cpu(ps->mac_rx_oversize_pkts);
+ rmon_stats->fragments = le64_to_cpu(ps->mac_rx_fragment_pkts);
+ rmon_stats->jabbers = le64_to_cpu(ps->mac_rx_jabber_pkts);
+
+ rmon_stats->hist[0] = le64_to_cpu(ps->mac_rx_64_oct_pkts);
+ rmon_stats->hist[1] = le64_to_cpu(ps->mac_rx_65_127_oct_pkts);
+ rmon_stats->hist[2] = le64_to_cpu(ps->mac_rx_128_255_oct_pkts);
+ rmon_stats->hist[3] = le64_to_cpu(ps->mac_rx_256_511_oct_pkts);
+ rmon_stats->hist[4] = le64_to_cpu(ps->mac_rx_512_1023_oct_pkts);
+ rmon_stats->hist[5] = le64_to_cpu(ps->mac_rx_1024_1518_oct_pkts);
+ rmon_stats->hist[6] = le64_to_cpu(ps->mac_rx_1519_2047_oct_pkts);
+ rmon_stats->hist[7] = le64_to_cpu(ps->mac_rx_2048_4095_oct_pkts);
+ rmon_stats->hist[8] = le64_to_cpu(ps->mac_rx_4096_8191_oct_pkts);
+ rmon_stats->hist[9] = le64_to_cpu(ps->mac_rx_8192_9216_oct_pkts);
+ rmon_stats->hist[10] = le64_to_cpu(ps->mac_rx_9217_12287_oct_pkts);
+
+ rmon_stats->hist_tx[0] = le64_to_cpu(ps->mac_tx_64_oct_pkts);
+ rmon_stats->hist_tx[1] = le64_to_cpu(ps->mac_tx_65_127_oct_pkts);
+ rmon_stats->hist_tx[2] = le64_to_cpu(ps->mac_tx_128_255_oct_pkts);
+ rmon_stats->hist_tx[3] = le64_to_cpu(ps->mac_tx_256_511_oct_pkts);
+ rmon_stats->hist_tx[4] = le64_to_cpu(ps->mac_tx_512_1023_oct_pkts);
+ rmon_stats->hist_tx[5] = le64_to_cpu(ps->mac_tx_1024_1518_oct_pkts);
+ rmon_stats->hist_tx[6] = le64_to_cpu(ps->mac_tx_1519_2047_oct_pkts);
+ rmon_stats->hist_tx[7] = le64_to_cpu(ps->mac_tx_2048_4095_oct_pkts);
+ rmon_stats->hist_tx[8] = le64_to_cpu(ps->mac_tx_4096_8191_oct_pkts);
+ rmon_stats->hist_tx[9] = le64_to_cpu(ps->mac_tx_8192_9216_oct_pkts);
+ rmon_stats->hist_tx[10] = le64_to_cpu(ps->mac_tx_9217_12287_oct_pkts);
+
+ *ranges = hinic3_rmon_ranges;
+
+ kfree(ps);
+}
+
+static void hinic3_get_pause_stats(struct net_device *netdev,
+ struct ethtool_pause_stats *pause_stats)
+{
+ struct hinic3_nic_dev *nic_dev = netdev_priv(netdev);
+ struct mag_cmd_port_stats *ps;
+ int err;
+
+ if (HINIC3_IS_VF(nic_dev->hwdev))
+ return;
+
+ ps = kmalloc_obj(*ps);
+ if (!ps)
+ return;
+
+ err = hinic3_get_phy_port_stats(nic_dev->hwdev, ps);
+ if (err) {
+ kfree(ps);
+ netdev_err(netdev, "Failed to get eth pause stats from fw\n");
+ return;
+ }
+
+ pause_stats->tx_pause_frames = le64_to_cpu(ps->mac_tx_pause_pkts);
+ pause_stats->rx_pause_frames = le64_to_cpu(ps->mac_rx_pause_pkts);
+
+ kfree(ps);
+}
+
static const struct ethtool_ops hinic3_ethtool_ops = {
.supported_coalesce_params = ETHTOOL_COALESCE_USECS |
ETHTOOL_COALESCE_PKT_RATE_RX_USECS,
@@ -707,6 +904,11 @@ static const struct ethtool_ops hinic3_ethtool_ops = {
.get_strings = hinic3_get_strings,
.get_sset_count = hinic3_get_sset_count,
.get_ethtool_stats = hinic3_get_ethtool_stats,
+ .get_eth_phy_stats = hinic3_get_eth_phy_stats,
+ .get_eth_mac_stats = hinic3_get_eth_mac_stats,
+ .get_eth_ctrl_stats = hinic3_get_eth_ctrl_stats,
+ .get_rmon_stats = hinic3_get_rmon_stats,
+ .get_pause_stats = hinic3_get_pause_stats,
};

void hinic3_set_ethtool_ops(struct net_device *netdev)
--
2.43.0