1 // SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause 2 3 /* Ethtool support for Mellanox Gigabit Ethernet driver 4 * 5 * Copyright (C) 2020-2021 NVIDIA CORPORATION & AFFILIATES 6 */ 7 8 #include <linux/phy.h> 9 10 #include "mlxbf_gige.h" 11 #include "mlxbf_gige_regs.h" 12 13 /* Start of struct ethtool_ops functions */ 14 static int mlxbf_gige_get_regs_len(struct net_device *netdev) 15 { 16 return MLXBF_GIGE_MMIO_REG_SZ; 17 } 18 19 static void mlxbf_gige_get_regs(struct net_device *netdev, 20 struct ethtool_regs *regs, void *p) 21 { 22 struct mlxbf_gige *priv = netdev_priv(netdev); 23 24 regs->version = MLXBF_GIGE_REGS_VERSION; 25 26 /* Read entire MMIO register space and store results 27 * into the provided buffer. Each 64-bit word is converted 28 * to big-endian to make the output more readable. 29 * 30 * NOTE: by design, a read to an offset without an existing 31 * register will be acknowledged and return zero. 32 */ 33 memcpy_fromio(p, priv->base, MLXBF_GIGE_MMIO_REG_SZ); 34 } 35 36 static void mlxbf_gige_get_ringparam(struct net_device *netdev, 37 struct ethtool_ringparam *ering) 38 { 39 struct mlxbf_gige *priv = netdev_priv(netdev); 40 41 ering->rx_max_pending = MLXBF_GIGE_MAX_RXQ_SZ; 42 ering->tx_max_pending = MLXBF_GIGE_MAX_TXQ_SZ; 43 ering->rx_pending = priv->rx_q_entries; 44 ering->tx_pending = priv->tx_q_entries; 45 } 46 47 static const struct { 48 const char string[ETH_GSTRING_LEN]; 49 } mlxbf_gige_ethtool_stats_keys[] = { 50 { "hw_access_errors" }, 51 { "tx_invalid_checksums" }, 52 { "tx_small_frames" }, 53 { "tx_index_errors" }, 54 { "sw_config_errors" }, 55 { "sw_access_errors" }, 56 { "rx_truncate_errors" }, 57 { "rx_mac_errors" }, 58 { "rx_din_dropped_pkts" }, 59 { "tx_fifo_full" }, 60 { "rx_filter_passed_pkts" }, 61 { "rx_filter_discard_pkts" }, 62 }; 63 64 static int mlxbf_gige_get_sset_count(struct net_device *netdev, int stringset) 65 { 66 if (stringset != ETH_SS_STATS) 67 return -EOPNOTSUPP; 68 return ARRAY_SIZE(mlxbf_gige_ethtool_stats_keys); 69 } 70 71 static void mlxbf_gige_get_strings(struct net_device *netdev, u32 stringset, 72 u8 *buf) 73 { 74 if (stringset != ETH_SS_STATS) 75 return; 76 memcpy(buf, &mlxbf_gige_ethtool_stats_keys, 77 sizeof(mlxbf_gige_ethtool_stats_keys)); 78 } 79 80 static void mlxbf_gige_get_ethtool_stats(struct net_device *netdev, 81 struct ethtool_stats *estats, 82 u64 *data) 83 { 84 struct mlxbf_gige *priv = netdev_priv(netdev); 85 86 /* Fill data array with interface statistics 87 * 88 * NOTE: the data writes must be in 89 * sync with the strings shown in 90 * the mlxbf_gige_ethtool_stats_keys[] array 91 * 92 * NOTE2: certain statistics below are zeroed upon 93 * port disable, so the calculation below 94 * must include the "cached" value of the stat 95 * plus the value read directly from hardware. 96 * Cached statistics are currently: 97 * rx_din_dropped_pkts 98 * rx_filter_passed_pkts 99 * rx_filter_discard_pkts 100 */ 101 *data++ = priv->stats.hw_access_errors; 102 *data++ = priv->stats.tx_invalid_checksums; 103 *data++ = priv->stats.tx_small_frames; 104 *data++ = priv->stats.tx_index_errors; 105 *data++ = priv->stats.sw_config_errors; 106 *data++ = priv->stats.sw_access_errors; 107 *data++ = priv->stats.rx_truncate_errors; 108 *data++ = priv->stats.rx_mac_errors; 109 *data++ = (priv->stats.rx_din_dropped_pkts + 110 readq(priv->base + MLXBF_GIGE_RX_DIN_DROP_COUNTER)); 111 *data++ = priv->stats.tx_fifo_full; 112 *data++ = (priv->stats.rx_filter_passed_pkts + 113 readq(priv->base + MLXBF_GIGE_RX_PASS_COUNTER_ALL)); 114 *data++ = (priv->stats.rx_filter_discard_pkts + 115 readq(priv->base + MLXBF_GIGE_RX_DISC_COUNTER_ALL)); 116 } 117 118 static void mlxbf_gige_get_pauseparam(struct net_device *netdev, 119 struct ethtool_pauseparam *pause) 120 { 121 pause->autoneg = AUTONEG_DISABLE; 122 pause->rx_pause = 1; 123 pause->tx_pause = 1; 124 } 125 126 const struct ethtool_ops mlxbf_gige_ethtool_ops = { 127 .get_link = ethtool_op_get_link, 128 .get_ringparam = mlxbf_gige_get_ringparam, 129 .get_regs_len = mlxbf_gige_get_regs_len, 130 .get_regs = mlxbf_gige_get_regs, 131 .get_strings = mlxbf_gige_get_strings, 132 .get_sset_count = mlxbf_gige_get_sset_count, 133 .get_ethtool_stats = mlxbf_gige_get_ethtool_stats, 134 .nway_reset = phy_ethtool_nway_reset, 135 .get_pauseparam = mlxbf_gige_get_pauseparam, 136 .get_link_ksettings = phy_ethtool_get_link_ksettings, 137 }; 138