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 37 mlxbf_gige_get_ringparam(struct net_device *netdev, 38 struct ethtool_ringparam *ering, 39 struct kernel_ethtool_ringparam *kernel_ering, 40 struct netlink_ext_ack *extack) 41 { 42 struct mlxbf_gige *priv = netdev_priv(netdev); 43 44 ering->rx_max_pending = MLXBF_GIGE_MAX_RXQ_SZ; 45 ering->tx_max_pending = MLXBF_GIGE_MAX_TXQ_SZ; 46 ering->rx_pending = priv->rx_q_entries; 47 ering->tx_pending = priv->tx_q_entries; 48 } 49 50 static const struct { 51 const char string[ETH_GSTRING_LEN]; 52 } mlxbf_gige_ethtool_stats_keys[] = { 53 { "hw_access_errors" }, 54 { "tx_invalid_checksums" }, 55 { "tx_small_frames" }, 56 { "tx_index_errors" }, 57 { "sw_config_errors" }, 58 { "sw_access_errors" }, 59 { "rx_truncate_errors" }, 60 { "rx_mac_errors" }, 61 { "rx_din_dropped_pkts" }, 62 { "tx_fifo_full" }, 63 { "rx_filter_passed_pkts" }, 64 { "rx_filter_discard_pkts" }, 65 }; 66 67 static int mlxbf_gige_get_sset_count(struct net_device *netdev, int stringset) 68 { 69 if (stringset != ETH_SS_STATS) 70 return -EOPNOTSUPP; 71 return ARRAY_SIZE(mlxbf_gige_ethtool_stats_keys); 72 } 73 74 static void mlxbf_gige_get_strings(struct net_device *netdev, u32 stringset, 75 u8 *buf) 76 { 77 if (stringset != ETH_SS_STATS) 78 return; 79 memcpy(buf, &mlxbf_gige_ethtool_stats_keys, 80 sizeof(mlxbf_gige_ethtool_stats_keys)); 81 } 82 83 static void mlxbf_gige_get_ethtool_stats(struct net_device *netdev, 84 struct ethtool_stats *estats, 85 u64 *data) 86 { 87 struct mlxbf_gige *priv = netdev_priv(netdev); 88 89 /* Fill data array with interface statistics 90 * 91 * NOTE: the data writes must be in 92 * sync with the strings shown in 93 * the mlxbf_gige_ethtool_stats_keys[] array 94 * 95 * NOTE2: certain statistics below are zeroed upon 96 * port disable, so the calculation below 97 * must include the "cached" value of the stat 98 * plus the value read directly from hardware. 99 * Cached statistics are currently: 100 * rx_din_dropped_pkts 101 * rx_filter_passed_pkts 102 * rx_filter_discard_pkts 103 */ 104 *data++ = priv->stats.hw_access_errors; 105 *data++ = priv->stats.tx_invalid_checksums; 106 *data++ = priv->stats.tx_small_frames; 107 *data++ = priv->stats.tx_index_errors; 108 *data++ = priv->stats.sw_config_errors; 109 *data++ = priv->stats.sw_access_errors; 110 *data++ = priv->stats.rx_truncate_errors; 111 *data++ = priv->stats.rx_mac_errors; 112 *data++ = (priv->stats.rx_din_dropped_pkts + 113 readq(priv->base + MLXBF_GIGE_RX_DIN_DROP_COUNTER)); 114 *data++ = priv->stats.tx_fifo_full; 115 *data++ = (priv->stats.rx_filter_passed_pkts + 116 readq(priv->base + MLXBF_GIGE_RX_PASS_COUNTER_ALL)); 117 *data++ = (priv->stats.rx_filter_discard_pkts + 118 readq(priv->base + MLXBF_GIGE_RX_DISC_COUNTER_ALL)); 119 } 120 121 static void mlxbf_gige_get_pauseparam(struct net_device *netdev, 122 struct ethtool_pauseparam *pause) 123 { 124 pause->autoneg = AUTONEG_DISABLE; 125 pause->rx_pause = 1; 126 pause->tx_pause = 1; 127 } 128 129 const struct ethtool_ops mlxbf_gige_ethtool_ops = { 130 .get_link = ethtool_op_get_link, 131 .get_ringparam = mlxbf_gige_get_ringparam, 132 .get_regs_len = mlxbf_gige_get_regs_len, 133 .get_regs = mlxbf_gige_get_regs, 134 .get_strings = mlxbf_gige_get_strings, 135 .get_sset_count = mlxbf_gige_get_sset_count, 136 .get_ethtool_stats = mlxbf_gige_get_ethtool_stats, 137 .nway_reset = phy_ethtool_nway_reset, 138 .get_pauseparam = mlxbf_gige_get_pauseparam, 139 .get_link_ksettings = phy_ethtool_get_link_ksettings, 140 }; 141