1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright (C) 2021 Gerhard Engleder <gerhard@engleder-embedded.com> */ 3 4 #include "tsnep.h" 5 6 static const char tsnep_stats_strings[][ETH_GSTRING_LEN] = { 7 "rx_packets", 8 "rx_bytes", 9 "rx_dropped", 10 "rx_multicast", 11 "rx_phy_errors", 12 "rx_forwarded_phy_errors", 13 "rx_invalid_frame_errors", 14 "tx_packets", 15 "tx_bytes", 16 "tx_dropped", 17 }; 18 19 struct tsnep_stats { 20 u64 rx_packets; 21 u64 rx_bytes; 22 u64 rx_dropped; 23 u64 rx_multicast; 24 u64 rx_phy_errors; 25 u64 rx_forwarded_phy_errors; 26 u64 rx_invalid_frame_errors; 27 u64 tx_packets; 28 u64 tx_bytes; 29 u64 tx_dropped; 30 }; 31 32 #define TSNEP_STATS_COUNT (sizeof(struct tsnep_stats) / sizeof(u64)) 33 34 static const char tsnep_rx_queue_stats_strings[][ETH_GSTRING_LEN] = { 35 "rx_%d_packets", 36 "rx_%d_bytes", 37 "rx_%d_dropped", 38 "rx_%d_multicast", 39 "rx_%d_no_descriptor_errors", 40 "rx_%d_buffer_too_small_errors", 41 "rx_%d_fifo_overflow_errors", 42 "rx_%d_invalid_frame_errors", 43 }; 44 45 struct tsnep_rx_queue_stats { 46 u64 rx_packets; 47 u64 rx_bytes; 48 u64 rx_dropped; 49 u64 rx_multicast; 50 u64 rx_no_descriptor_errors; 51 u64 rx_buffer_too_small_errors; 52 u64 rx_fifo_overflow_errors; 53 u64 rx_invalid_frame_errors; 54 }; 55 56 #define TSNEP_RX_QUEUE_STATS_COUNT (sizeof(struct tsnep_rx_queue_stats) / \ 57 sizeof(u64)) 58 59 static const char tsnep_tx_queue_stats_strings[][ETH_GSTRING_LEN] = { 60 "tx_%d_packets", 61 "tx_%d_bytes", 62 "tx_%d_dropped", 63 }; 64 65 struct tsnep_tx_queue_stats { 66 u64 tx_packets; 67 u64 tx_bytes; 68 u64 tx_dropped; 69 }; 70 71 #define TSNEP_TX_QUEUE_STATS_COUNT (sizeof(struct tsnep_tx_queue_stats) / \ 72 sizeof(u64)) 73 74 static void tsnep_ethtool_get_drvinfo(struct net_device *netdev, 75 struct ethtool_drvinfo *drvinfo) 76 { 77 struct tsnep_adapter *adapter = netdev_priv(netdev); 78 79 strscpy(drvinfo->driver, TSNEP, sizeof(drvinfo->driver)); 80 strscpy(drvinfo->bus_info, dev_name(&adapter->pdev->dev), 81 sizeof(drvinfo->bus_info)); 82 } 83 84 static int tsnep_ethtool_get_regs_len(struct net_device *netdev) 85 { 86 struct tsnep_adapter *adapter = netdev_priv(netdev); 87 int len; 88 int num_additional_queues; 89 90 len = TSNEP_MAC_SIZE; 91 92 /* first queue pair is within TSNEP_MAC_SIZE, only queues additional to 93 * the first queue pair extend the register length by TSNEP_QUEUE_SIZE 94 */ 95 num_additional_queues = 96 max(adapter->num_tx_queues, adapter->num_rx_queues) - 1; 97 len += TSNEP_QUEUE_SIZE * num_additional_queues; 98 99 return len; 100 } 101 102 static void tsnep_ethtool_get_regs(struct net_device *netdev, 103 struct ethtool_regs *regs, 104 void *p) 105 { 106 struct tsnep_adapter *adapter = netdev_priv(netdev); 107 108 regs->version = 1; 109 110 memcpy_fromio(p, adapter->addr, regs->len); 111 } 112 113 static u32 tsnep_ethtool_get_msglevel(struct net_device *netdev) 114 { 115 struct tsnep_adapter *adapter = netdev_priv(netdev); 116 117 return adapter->msg_enable; 118 } 119 120 static void tsnep_ethtool_set_msglevel(struct net_device *netdev, u32 data) 121 { 122 struct tsnep_adapter *adapter = netdev_priv(netdev); 123 124 adapter->msg_enable = data; 125 } 126 127 static void tsnep_ethtool_get_strings(struct net_device *netdev, u32 stringset, 128 u8 *data) 129 { 130 struct tsnep_adapter *adapter = netdev_priv(netdev); 131 int rx_count = adapter->num_rx_queues; 132 int tx_count = adapter->num_tx_queues; 133 int i, j; 134 135 switch (stringset) { 136 case ETH_SS_STATS: 137 memcpy(data, tsnep_stats_strings, sizeof(tsnep_stats_strings)); 138 data += sizeof(tsnep_stats_strings); 139 140 for (i = 0; i < rx_count; i++) { 141 for (j = 0; j < TSNEP_RX_QUEUE_STATS_COUNT; j++) { 142 snprintf(data, ETH_GSTRING_LEN, 143 tsnep_rx_queue_stats_strings[j], i); 144 data += ETH_GSTRING_LEN; 145 } 146 } 147 148 for (i = 0; i < tx_count; i++) { 149 for (j = 0; j < TSNEP_TX_QUEUE_STATS_COUNT; j++) { 150 snprintf(data, ETH_GSTRING_LEN, 151 tsnep_tx_queue_stats_strings[j], i); 152 data += ETH_GSTRING_LEN; 153 } 154 } 155 break; 156 case ETH_SS_TEST: 157 tsnep_ethtool_get_test_strings(data); 158 break; 159 } 160 } 161 162 static void tsnep_ethtool_get_ethtool_stats(struct net_device *netdev, 163 struct ethtool_stats *stats, 164 u64 *data) 165 { 166 struct tsnep_adapter *adapter = netdev_priv(netdev); 167 int rx_count = adapter->num_rx_queues; 168 int tx_count = adapter->num_tx_queues; 169 struct tsnep_stats tsnep_stats; 170 struct tsnep_rx_queue_stats tsnep_rx_queue_stats; 171 struct tsnep_tx_queue_stats tsnep_tx_queue_stats; 172 u32 reg; 173 int i; 174 175 memset(&tsnep_stats, 0, sizeof(tsnep_stats)); 176 for (i = 0; i < adapter->num_rx_queues; i++) { 177 tsnep_stats.rx_packets += adapter->rx[i].packets; 178 tsnep_stats.rx_bytes += adapter->rx[i].bytes; 179 tsnep_stats.rx_dropped += adapter->rx[i].dropped; 180 tsnep_stats.rx_multicast += adapter->rx[i].multicast; 181 } 182 reg = ioread32(adapter->addr + ECM_STAT); 183 tsnep_stats.rx_phy_errors = 184 (reg & ECM_STAT_RX_ERR_MASK) >> ECM_STAT_RX_ERR_SHIFT; 185 tsnep_stats.rx_forwarded_phy_errors = 186 (reg & ECM_STAT_FWD_RX_ERR_MASK) >> ECM_STAT_FWD_RX_ERR_SHIFT; 187 tsnep_stats.rx_invalid_frame_errors = 188 (reg & ECM_STAT_INV_FRM_MASK) >> ECM_STAT_INV_FRM_SHIFT; 189 for (i = 0; i < adapter->num_tx_queues; i++) { 190 tsnep_stats.tx_packets += adapter->tx[i].packets; 191 tsnep_stats.tx_bytes += adapter->tx[i].bytes; 192 tsnep_stats.tx_dropped += adapter->tx[i].dropped; 193 } 194 memcpy(data, &tsnep_stats, sizeof(tsnep_stats)); 195 data += TSNEP_STATS_COUNT; 196 197 for (i = 0; i < rx_count; i++) { 198 memset(&tsnep_rx_queue_stats, 0, sizeof(tsnep_rx_queue_stats)); 199 tsnep_rx_queue_stats.rx_packets = adapter->rx[i].packets; 200 tsnep_rx_queue_stats.rx_bytes = adapter->rx[i].bytes; 201 tsnep_rx_queue_stats.rx_dropped = adapter->rx[i].dropped; 202 tsnep_rx_queue_stats.rx_multicast = adapter->rx[i].multicast; 203 reg = ioread32(adapter->addr + TSNEP_QUEUE(i) + 204 TSNEP_RX_STATISTIC); 205 tsnep_rx_queue_stats.rx_no_descriptor_errors = 206 (reg & TSNEP_RX_STATISTIC_NO_DESC_MASK) >> 207 TSNEP_RX_STATISTIC_NO_DESC_SHIFT; 208 tsnep_rx_queue_stats.rx_buffer_too_small_errors = 209 (reg & TSNEP_RX_STATISTIC_BUFFER_TOO_SMALL_MASK) >> 210 TSNEP_RX_STATISTIC_BUFFER_TOO_SMALL_SHIFT; 211 tsnep_rx_queue_stats.rx_fifo_overflow_errors = 212 (reg & TSNEP_RX_STATISTIC_FIFO_OVERFLOW_MASK) >> 213 TSNEP_RX_STATISTIC_FIFO_OVERFLOW_SHIFT; 214 tsnep_rx_queue_stats.rx_invalid_frame_errors = 215 (reg & TSNEP_RX_STATISTIC_INVALID_FRAME_MASK) >> 216 TSNEP_RX_STATISTIC_INVALID_FRAME_SHIFT; 217 memcpy(data, &tsnep_rx_queue_stats, 218 sizeof(tsnep_rx_queue_stats)); 219 data += TSNEP_RX_QUEUE_STATS_COUNT; 220 } 221 222 for (i = 0; i < tx_count; i++) { 223 memset(&tsnep_tx_queue_stats, 0, sizeof(tsnep_tx_queue_stats)); 224 tsnep_tx_queue_stats.tx_packets += adapter->tx[i].packets; 225 tsnep_tx_queue_stats.tx_bytes += adapter->tx[i].bytes; 226 tsnep_tx_queue_stats.tx_dropped += adapter->tx[i].dropped; 227 memcpy(data, &tsnep_tx_queue_stats, 228 sizeof(tsnep_tx_queue_stats)); 229 data += TSNEP_TX_QUEUE_STATS_COUNT; 230 } 231 } 232 233 static int tsnep_ethtool_get_sset_count(struct net_device *netdev, int sset) 234 { 235 struct tsnep_adapter *adapter = netdev_priv(netdev); 236 int rx_count; 237 int tx_count; 238 239 switch (sset) { 240 case ETH_SS_STATS: 241 rx_count = adapter->num_rx_queues; 242 tx_count = adapter->num_tx_queues; 243 return TSNEP_STATS_COUNT + 244 TSNEP_RX_QUEUE_STATS_COUNT * rx_count + 245 TSNEP_TX_QUEUE_STATS_COUNT * tx_count; 246 case ETH_SS_TEST: 247 return tsnep_ethtool_get_test_count(); 248 default: 249 return -EOPNOTSUPP; 250 } 251 } 252 253 static int tsnep_ethtool_get_ts_info(struct net_device *dev, 254 struct ethtool_ts_info *info) 255 { 256 struct tsnep_adapter *adapter = netdev_priv(dev); 257 258 info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE | 259 SOF_TIMESTAMPING_RX_SOFTWARE | 260 SOF_TIMESTAMPING_SOFTWARE | 261 SOF_TIMESTAMPING_TX_HARDWARE | 262 SOF_TIMESTAMPING_RX_HARDWARE | 263 SOF_TIMESTAMPING_RAW_HARDWARE; 264 265 if (adapter->ptp_clock) 266 info->phc_index = ptp_clock_index(adapter->ptp_clock); 267 else 268 info->phc_index = -1; 269 270 info->tx_types = BIT(HWTSTAMP_TX_OFF) | 271 BIT(HWTSTAMP_TX_ON); 272 info->rx_filters = BIT(HWTSTAMP_FILTER_NONE) | 273 BIT(HWTSTAMP_FILTER_ALL); 274 275 return 0; 276 } 277 278 const struct ethtool_ops tsnep_ethtool_ops = { 279 .get_drvinfo = tsnep_ethtool_get_drvinfo, 280 .get_regs_len = tsnep_ethtool_get_regs_len, 281 .get_regs = tsnep_ethtool_get_regs, 282 .get_msglevel = tsnep_ethtool_get_msglevel, 283 .set_msglevel = tsnep_ethtool_set_msglevel, 284 .nway_reset = phy_ethtool_nway_reset, 285 .get_link = ethtool_op_get_link, 286 .self_test = tsnep_ethtool_self_test, 287 .get_strings = tsnep_ethtool_get_strings, 288 .get_ethtool_stats = tsnep_ethtool_get_ethtool_stats, 289 .get_sset_count = tsnep_ethtool_get_sset_count, 290 .get_ts_info = tsnep_ethtool_get_ts_info, 291 .get_link_ksettings = phy_ethtool_get_link_ksettings, 292 .set_link_ksettings = phy_ethtool_set_link_ksettings, 293 }; 294