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_alloc_failed", 12 "rx_phy_errors", 13 "rx_forwarded_phy_errors", 14 "rx_invalid_frame_errors", 15 "tx_packets", 16 "tx_bytes", 17 "tx_dropped", 18 }; 19 20 struct tsnep_stats { 21 u64 rx_packets; 22 u64 rx_bytes; 23 u64 rx_dropped; 24 u64 rx_multicast; 25 u64 rx_alloc_failed; 26 u64 rx_phy_errors; 27 u64 rx_forwarded_phy_errors; 28 u64 rx_invalid_frame_errors; 29 u64 tx_packets; 30 u64 tx_bytes; 31 u64 tx_dropped; 32 }; 33 34 #define TSNEP_STATS_COUNT (sizeof(struct tsnep_stats) / sizeof(u64)) 35 36 static const char tsnep_rx_queue_stats_strings[][ETH_GSTRING_LEN] = { 37 "rx_%d_packets", 38 "rx_%d_bytes", 39 "rx_%d_dropped", 40 "rx_%d_multicast", 41 "rx_%d_alloc_failed", 42 "rx_%d_no_descriptor_errors", 43 "rx_%d_buffer_too_small_errors", 44 "rx_%d_fifo_overflow_errors", 45 "rx_%d_invalid_frame_errors", 46 }; 47 48 struct tsnep_rx_queue_stats { 49 u64 rx_packets; 50 u64 rx_bytes; 51 u64 rx_dropped; 52 u64 rx_multicast; 53 u64 rx_alloc_failed; 54 u64 rx_no_descriptor_errors; 55 u64 rx_buffer_too_small_errors; 56 u64 rx_fifo_overflow_errors; 57 u64 rx_invalid_frame_errors; 58 }; 59 60 #define TSNEP_RX_QUEUE_STATS_COUNT (sizeof(struct tsnep_rx_queue_stats) / \ 61 sizeof(u64)) 62 63 static const char tsnep_tx_queue_stats_strings[][ETH_GSTRING_LEN] = { 64 "tx_%d_packets", 65 "tx_%d_bytes", 66 "tx_%d_dropped", 67 }; 68 69 struct tsnep_tx_queue_stats { 70 u64 tx_packets; 71 u64 tx_bytes; 72 u64 tx_dropped; 73 }; 74 75 #define TSNEP_TX_QUEUE_STATS_COUNT (sizeof(struct tsnep_tx_queue_stats) / \ 76 sizeof(u64)) 77 78 static void tsnep_ethtool_get_drvinfo(struct net_device *netdev, 79 struct ethtool_drvinfo *drvinfo) 80 { 81 struct tsnep_adapter *adapter = netdev_priv(netdev); 82 83 strscpy(drvinfo->driver, TSNEP, sizeof(drvinfo->driver)); 84 strscpy(drvinfo->bus_info, dev_name(&adapter->pdev->dev), 85 sizeof(drvinfo->bus_info)); 86 } 87 88 static int tsnep_ethtool_get_regs_len(struct net_device *netdev) 89 { 90 struct tsnep_adapter *adapter = netdev_priv(netdev); 91 int len; 92 int num_additional_queues; 93 94 len = TSNEP_MAC_SIZE; 95 96 /* first queue pair is within TSNEP_MAC_SIZE, only queues additional to 97 * the first queue pair extend the register length by TSNEP_QUEUE_SIZE 98 */ 99 num_additional_queues = 100 max(adapter->num_tx_queues, adapter->num_rx_queues) - 1; 101 len += TSNEP_QUEUE_SIZE * num_additional_queues; 102 103 return len; 104 } 105 106 static void tsnep_ethtool_get_regs(struct net_device *netdev, 107 struct ethtool_regs *regs, 108 void *p) 109 { 110 struct tsnep_adapter *adapter = netdev_priv(netdev); 111 112 regs->version = 1; 113 114 memcpy_fromio(p, adapter->addr, regs->len); 115 } 116 117 static u32 tsnep_ethtool_get_msglevel(struct net_device *netdev) 118 { 119 struct tsnep_adapter *adapter = netdev_priv(netdev); 120 121 return adapter->msg_enable; 122 } 123 124 static void tsnep_ethtool_set_msglevel(struct net_device *netdev, u32 data) 125 { 126 struct tsnep_adapter *adapter = netdev_priv(netdev); 127 128 adapter->msg_enable = data; 129 } 130 131 static void tsnep_ethtool_get_strings(struct net_device *netdev, u32 stringset, 132 u8 *data) 133 { 134 struct tsnep_adapter *adapter = netdev_priv(netdev); 135 int rx_count = adapter->num_rx_queues; 136 int tx_count = adapter->num_tx_queues; 137 int i, j; 138 139 switch (stringset) { 140 case ETH_SS_STATS: 141 memcpy(data, tsnep_stats_strings, sizeof(tsnep_stats_strings)); 142 data += sizeof(tsnep_stats_strings); 143 144 for (i = 0; i < rx_count; i++) { 145 for (j = 0; j < TSNEP_RX_QUEUE_STATS_COUNT; j++) { 146 snprintf(data, ETH_GSTRING_LEN, 147 tsnep_rx_queue_stats_strings[j], i); 148 data += ETH_GSTRING_LEN; 149 } 150 } 151 152 for (i = 0; i < tx_count; i++) { 153 for (j = 0; j < TSNEP_TX_QUEUE_STATS_COUNT; j++) { 154 snprintf(data, ETH_GSTRING_LEN, 155 tsnep_tx_queue_stats_strings[j], i); 156 data += ETH_GSTRING_LEN; 157 } 158 } 159 break; 160 case ETH_SS_TEST: 161 tsnep_ethtool_get_test_strings(data); 162 break; 163 } 164 } 165 166 static void tsnep_ethtool_get_ethtool_stats(struct net_device *netdev, 167 struct ethtool_stats *stats, 168 u64 *data) 169 { 170 struct tsnep_adapter *adapter = netdev_priv(netdev); 171 int rx_count = adapter->num_rx_queues; 172 int tx_count = adapter->num_tx_queues; 173 struct tsnep_stats tsnep_stats; 174 struct tsnep_rx_queue_stats tsnep_rx_queue_stats; 175 struct tsnep_tx_queue_stats tsnep_tx_queue_stats; 176 u32 reg; 177 int i; 178 179 memset(&tsnep_stats, 0, sizeof(tsnep_stats)); 180 for (i = 0; i < adapter->num_rx_queues; i++) { 181 tsnep_stats.rx_packets += adapter->rx[i].packets; 182 tsnep_stats.rx_bytes += adapter->rx[i].bytes; 183 tsnep_stats.rx_dropped += adapter->rx[i].dropped; 184 tsnep_stats.rx_multicast += adapter->rx[i].multicast; 185 tsnep_stats.rx_alloc_failed += adapter->rx[i].alloc_failed; 186 } 187 reg = ioread32(adapter->addr + ECM_STAT); 188 tsnep_stats.rx_phy_errors = 189 (reg & ECM_STAT_RX_ERR_MASK) >> ECM_STAT_RX_ERR_SHIFT; 190 tsnep_stats.rx_forwarded_phy_errors = 191 (reg & ECM_STAT_FWD_RX_ERR_MASK) >> ECM_STAT_FWD_RX_ERR_SHIFT; 192 tsnep_stats.rx_invalid_frame_errors = 193 (reg & ECM_STAT_INV_FRM_MASK) >> ECM_STAT_INV_FRM_SHIFT; 194 for (i = 0; i < adapter->num_tx_queues; i++) { 195 tsnep_stats.tx_packets += adapter->tx[i].packets; 196 tsnep_stats.tx_bytes += adapter->tx[i].bytes; 197 tsnep_stats.tx_dropped += adapter->tx[i].dropped; 198 } 199 memcpy(data, &tsnep_stats, sizeof(tsnep_stats)); 200 data += TSNEP_STATS_COUNT; 201 202 for (i = 0; i < rx_count; i++) { 203 memset(&tsnep_rx_queue_stats, 0, sizeof(tsnep_rx_queue_stats)); 204 tsnep_rx_queue_stats.rx_packets = adapter->rx[i].packets; 205 tsnep_rx_queue_stats.rx_bytes = adapter->rx[i].bytes; 206 tsnep_rx_queue_stats.rx_dropped = adapter->rx[i].dropped; 207 tsnep_rx_queue_stats.rx_multicast = adapter->rx[i].multicast; 208 tsnep_rx_queue_stats.rx_alloc_failed = 209 adapter->rx[i].alloc_failed; 210 reg = ioread32(adapter->addr + TSNEP_QUEUE(i) + 211 TSNEP_RX_STATISTIC); 212 tsnep_rx_queue_stats.rx_no_descriptor_errors = 213 (reg & TSNEP_RX_STATISTIC_NO_DESC_MASK) >> 214 TSNEP_RX_STATISTIC_NO_DESC_SHIFT; 215 tsnep_rx_queue_stats.rx_buffer_too_small_errors = 216 (reg & TSNEP_RX_STATISTIC_BUFFER_TOO_SMALL_MASK) >> 217 TSNEP_RX_STATISTIC_BUFFER_TOO_SMALL_SHIFT; 218 tsnep_rx_queue_stats.rx_fifo_overflow_errors = 219 (reg & TSNEP_RX_STATISTIC_FIFO_OVERFLOW_MASK) >> 220 TSNEP_RX_STATISTIC_FIFO_OVERFLOW_SHIFT; 221 tsnep_rx_queue_stats.rx_invalid_frame_errors = 222 (reg & TSNEP_RX_STATISTIC_INVALID_FRAME_MASK) >> 223 TSNEP_RX_STATISTIC_INVALID_FRAME_SHIFT; 224 memcpy(data, &tsnep_rx_queue_stats, 225 sizeof(tsnep_rx_queue_stats)); 226 data += TSNEP_RX_QUEUE_STATS_COUNT; 227 } 228 229 for (i = 0; i < tx_count; i++) { 230 memset(&tsnep_tx_queue_stats, 0, sizeof(tsnep_tx_queue_stats)); 231 tsnep_tx_queue_stats.tx_packets += adapter->tx[i].packets; 232 tsnep_tx_queue_stats.tx_bytes += adapter->tx[i].bytes; 233 tsnep_tx_queue_stats.tx_dropped += adapter->tx[i].dropped; 234 memcpy(data, &tsnep_tx_queue_stats, 235 sizeof(tsnep_tx_queue_stats)); 236 data += TSNEP_TX_QUEUE_STATS_COUNT; 237 } 238 } 239 240 static int tsnep_ethtool_get_sset_count(struct net_device *netdev, int sset) 241 { 242 struct tsnep_adapter *adapter = netdev_priv(netdev); 243 int rx_count; 244 int tx_count; 245 246 switch (sset) { 247 case ETH_SS_STATS: 248 rx_count = adapter->num_rx_queues; 249 tx_count = adapter->num_tx_queues; 250 return TSNEP_STATS_COUNT + 251 TSNEP_RX_QUEUE_STATS_COUNT * rx_count + 252 TSNEP_TX_QUEUE_STATS_COUNT * tx_count; 253 case ETH_SS_TEST: 254 return tsnep_ethtool_get_test_count(); 255 default: 256 return -EOPNOTSUPP; 257 } 258 } 259 260 static int tsnep_ethtool_get_rxnfc(struct net_device *netdev, 261 struct ethtool_rxnfc *cmd, u32 *rule_locs) 262 { 263 struct tsnep_adapter *adapter = netdev_priv(netdev); 264 265 switch (cmd->cmd) { 266 case ETHTOOL_GRXRINGS: 267 cmd->data = adapter->num_rx_queues; 268 return 0; 269 case ETHTOOL_GRXCLSRLCNT: 270 cmd->rule_cnt = adapter->rxnfc_count; 271 cmd->data = adapter->rxnfc_max; 272 cmd->data |= RX_CLS_LOC_SPECIAL; 273 return 0; 274 case ETHTOOL_GRXCLSRULE: 275 return tsnep_rxnfc_get_rule(adapter, cmd); 276 case ETHTOOL_GRXCLSRLALL: 277 return tsnep_rxnfc_get_all(adapter, cmd, rule_locs); 278 default: 279 return -EOPNOTSUPP; 280 } 281 } 282 283 static int tsnep_ethtool_set_rxnfc(struct net_device *netdev, 284 struct ethtool_rxnfc *cmd) 285 { 286 struct tsnep_adapter *adapter = netdev_priv(netdev); 287 288 switch (cmd->cmd) { 289 case ETHTOOL_SRXCLSRLINS: 290 return tsnep_rxnfc_add_rule(adapter, cmd); 291 case ETHTOOL_SRXCLSRLDEL: 292 return tsnep_rxnfc_del_rule(adapter, cmd); 293 default: 294 return -EOPNOTSUPP; 295 } 296 } 297 298 static void tsnep_ethtool_get_channels(struct net_device *netdev, 299 struct ethtool_channels *ch) 300 { 301 struct tsnep_adapter *adapter = netdev_priv(netdev); 302 303 ch->max_combined = adapter->num_queues; 304 ch->combined_count = adapter->num_queues; 305 } 306 307 static int tsnep_ethtool_get_ts_info(struct net_device *netdev, 308 struct kernel_ethtool_ts_info *info) 309 { 310 struct tsnep_adapter *adapter = netdev_priv(netdev); 311 312 info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE | 313 SOF_TIMESTAMPING_TX_HARDWARE | 314 SOF_TIMESTAMPING_RX_HARDWARE | 315 SOF_TIMESTAMPING_RAW_HARDWARE; 316 317 if (adapter->ptp_clock) 318 info->phc_index = ptp_clock_index(adapter->ptp_clock); 319 320 info->tx_types = BIT(HWTSTAMP_TX_OFF) | 321 BIT(HWTSTAMP_TX_ON); 322 info->rx_filters = BIT(HWTSTAMP_FILTER_NONE) | 323 BIT(HWTSTAMP_FILTER_ALL); 324 325 return 0; 326 } 327 328 static struct tsnep_queue *tsnep_get_queue_with_tx(struct tsnep_adapter *adapter, 329 int index) 330 { 331 int i; 332 333 for (i = 0; i < adapter->num_queues; i++) { 334 if (adapter->queue[i].tx) { 335 if (index == 0) 336 return &adapter->queue[i]; 337 338 index--; 339 } 340 } 341 342 return NULL; 343 } 344 345 static struct tsnep_queue *tsnep_get_queue_with_rx(struct tsnep_adapter *adapter, 346 int index) 347 { 348 int i; 349 350 for (i = 0; i < adapter->num_queues; i++) { 351 if (adapter->queue[i].rx) { 352 if (index == 0) 353 return &adapter->queue[i]; 354 355 index--; 356 } 357 } 358 359 return NULL; 360 } 361 362 static int tsnep_ethtool_get_coalesce(struct net_device *netdev, 363 struct ethtool_coalesce *ec, 364 struct kernel_ethtool_coalesce *kernel_coal, 365 struct netlink_ext_ack *extack) 366 { 367 struct tsnep_adapter *adapter = netdev_priv(netdev); 368 struct tsnep_queue *queue; 369 370 queue = tsnep_get_queue_with_rx(adapter, 0); 371 if (queue) 372 ec->rx_coalesce_usecs = tsnep_get_irq_coalesce(queue); 373 374 queue = tsnep_get_queue_with_tx(adapter, 0); 375 if (queue) 376 ec->tx_coalesce_usecs = tsnep_get_irq_coalesce(queue); 377 378 return 0; 379 } 380 381 static int tsnep_ethtool_set_coalesce(struct net_device *netdev, 382 struct ethtool_coalesce *ec, 383 struct kernel_ethtool_coalesce *kernel_coal, 384 struct netlink_ext_ack *extack) 385 { 386 struct tsnep_adapter *adapter = netdev_priv(netdev); 387 int i; 388 int retval; 389 390 for (i = 0; i < adapter->num_queues; i++) { 391 /* RX coalesce has priority for queues with TX and RX */ 392 if (adapter->queue[i].rx) 393 retval = tsnep_set_irq_coalesce(&adapter->queue[i], 394 ec->rx_coalesce_usecs); 395 else 396 retval = tsnep_set_irq_coalesce(&adapter->queue[i], 397 ec->tx_coalesce_usecs); 398 if (retval != 0) 399 return retval; 400 } 401 402 return 0; 403 } 404 405 static int tsnep_ethtool_get_per_queue_coalesce(struct net_device *netdev, 406 u32 queue, 407 struct ethtool_coalesce *ec) 408 { 409 struct tsnep_adapter *adapter = netdev_priv(netdev); 410 struct tsnep_queue *queue_with_rx; 411 struct tsnep_queue *queue_with_tx; 412 413 if (queue >= max(adapter->num_tx_queues, adapter->num_rx_queues)) 414 return -EINVAL; 415 416 queue_with_rx = tsnep_get_queue_with_rx(adapter, queue); 417 if (queue_with_rx) 418 ec->rx_coalesce_usecs = tsnep_get_irq_coalesce(queue_with_rx); 419 420 queue_with_tx = tsnep_get_queue_with_tx(adapter, queue); 421 if (queue_with_tx) 422 ec->tx_coalesce_usecs = tsnep_get_irq_coalesce(queue_with_tx); 423 424 return 0; 425 } 426 427 static int tsnep_ethtool_set_per_queue_coalesce(struct net_device *netdev, 428 u32 queue, 429 struct ethtool_coalesce *ec) 430 { 431 struct tsnep_adapter *adapter = netdev_priv(netdev); 432 struct tsnep_queue *queue_with_rx; 433 struct tsnep_queue *queue_with_tx; 434 int retval; 435 436 if (queue >= max(adapter->num_tx_queues, adapter->num_rx_queues)) 437 return -EINVAL; 438 439 queue_with_rx = tsnep_get_queue_with_rx(adapter, queue); 440 if (queue_with_rx) { 441 retval = tsnep_set_irq_coalesce(queue_with_rx, ec->rx_coalesce_usecs); 442 if (retval != 0) 443 return retval; 444 } 445 446 /* RX coalesce has priority for queues with TX and RX */ 447 queue_with_tx = tsnep_get_queue_with_tx(adapter, queue); 448 if (queue_with_tx && !queue_with_tx->rx) { 449 retval = tsnep_set_irq_coalesce(queue_with_tx, ec->tx_coalesce_usecs); 450 if (retval != 0) 451 return retval; 452 } 453 454 return 0; 455 } 456 457 const struct ethtool_ops tsnep_ethtool_ops = { 458 .supported_coalesce_params = ETHTOOL_COALESCE_USECS, 459 .get_drvinfo = tsnep_ethtool_get_drvinfo, 460 .get_regs_len = tsnep_ethtool_get_regs_len, 461 .get_regs = tsnep_ethtool_get_regs, 462 .get_msglevel = tsnep_ethtool_get_msglevel, 463 .set_msglevel = tsnep_ethtool_set_msglevel, 464 .nway_reset = phy_ethtool_nway_reset, 465 .get_link = ethtool_op_get_link, 466 .self_test = tsnep_ethtool_self_test, 467 .get_strings = tsnep_ethtool_get_strings, 468 .get_ethtool_stats = tsnep_ethtool_get_ethtool_stats, 469 .get_sset_count = tsnep_ethtool_get_sset_count, 470 .get_rxnfc = tsnep_ethtool_get_rxnfc, 471 .set_rxnfc = tsnep_ethtool_set_rxnfc, 472 .get_channels = tsnep_ethtool_get_channels, 473 .get_ts_info = tsnep_ethtool_get_ts_info, 474 .get_coalesce = tsnep_ethtool_get_coalesce, 475 .set_coalesce = tsnep_ethtool_set_coalesce, 476 .get_per_queue_coalesce = tsnep_ethtool_get_per_queue_coalesce, 477 .set_per_queue_coalesce = tsnep_ethtool_set_per_queue_coalesce, 478 .get_link_ksettings = phy_ethtool_get_link_ksettings, 479 .set_link_ksettings = phy_ethtool_set_link_ksettings, 480 }; 481