| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /******************************************************************************* |
|---|
| 2 | 3 | STMMAC Ethtool support |
|---|
| 3 | 4 | |
|---|
| 4 | 5 | Copyright (C) 2007-2009 STMicroelectronics Ltd |
|---|
| 5 | 6 | |
|---|
| 6 | | - This program is free software; you can redistribute it and/or modify it |
|---|
| 7 | | - under the terms and conditions of the GNU General Public License, |
|---|
| 8 | | - version 2, as published by the Free Software Foundation. |
|---|
| 9 | | - |
|---|
| 10 | | - This program is distributed in the hope it will be useful, but WITHOUT |
|---|
| 11 | | - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|---|
| 12 | | - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
|---|
| 13 | | - more details. |
|---|
| 14 | | - |
|---|
| 15 | | - The full GNU General Public License is included in this distribution in |
|---|
| 16 | | - the file called "COPYING". |
|---|
| 17 | 7 | |
|---|
| 18 | 8 | Author: Giuseppe Cavallaro <peppe.cavallaro@st.com> |
|---|
| 19 | 9 | *******************************************************************************/ |
|---|
| .. | .. |
|---|
| 22 | 12 | #include <linux/ethtool.h> |
|---|
| 23 | 13 | #include <linux/interrupt.h> |
|---|
| 24 | 14 | #include <linux/mii.h> |
|---|
| 25 | | -#include <linux/phy.h> |
|---|
| 15 | +#include <linux/phylink.h> |
|---|
| 26 | 16 | #include <linux/net_tstamp.h> |
|---|
| 27 | 17 | #include <asm/io.h> |
|---|
| 28 | 18 | |
|---|
| 29 | 19 | #include "stmmac.h" |
|---|
| 30 | 20 | #include "dwmac_dma.h" |
|---|
| 21 | +#include "dwxgmac2.h" |
|---|
| 31 | 22 | |
|---|
| 32 | 23 | #define REG_SPACE_SIZE 0x1060 |
|---|
| 24 | +#define GMAC4_REG_SPACE_SIZE 0x116C |
|---|
| 33 | 25 | #define MAC100_ETHTOOL_NAME "st_mac100" |
|---|
| 34 | 26 | #define GMAC_ETHTOOL_NAME "st_gmac" |
|---|
| 27 | +#define XGMAC_ETHTOOL_NAME "st_xgmac" |
|---|
| 28 | + |
|---|
| 29 | +/* Same as DMA_CHAN_BASE_ADDR defined in dwmac4_dma.h |
|---|
| 30 | + * |
|---|
| 31 | + * It is here because dwmac_dma.h and dwmac4_dam.h can not be included at the |
|---|
| 32 | + * same time due to the conflicting macro names. |
|---|
| 33 | + */ |
|---|
| 34 | +#define GMAC4_DMA_CHAN_BASE_ADDR 0x00001100 |
|---|
| 35 | 35 | |
|---|
| 36 | 36 | #define ETHTOOL_DMA_OFFSET 55 |
|---|
| 37 | 37 | |
|---|
| .. | .. |
|---|
| 42 | 42 | }; |
|---|
| 43 | 43 | |
|---|
| 44 | 44 | #define STMMAC_STAT(m) \ |
|---|
| 45 | | - { #m, FIELD_SIZEOF(struct stmmac_extra_stats, m), \ |
|---|
| 45 | + { #m, sizeof_field(struct stmmac_extra_stats, m), \ |
|---|
| 46 | 46 | offsetof(struct stmmac_priv, xstats.m)} |
|---|
| 47 | 47 | |
|---|
| 48 | 48 | static const struct stmmac_stats stmmac_gstrings_stats[] = { |
|---|
| .. | .. |
|---|
| 75 | 75 | STMMAC_STAT(rx_missed_cntr), |
|---|
| 76 | 76 | STMMAC_STAT(rx_overflow_cntr), |
|---|
| 77 | 77 | STMMAC_STAT(rx_vlan), |
|---|
| 78 | + STMMAC_STAT(rx_split_hdr_pkt_n), |
|---|
| 78 | 79 | /* Tx/Rx IRQ error info */ |
|---|
| 79 | 80 | STMMAC_STAT(tx_undeflow_irq), |
|---|
| 80 | 81 | STMMAC_STAT(tx_process_stopped_irq), |
|---|
| .. | .. |
|---|
| 170 | 171 | |
|---|
| 171 | 172 | /* HW MAC Management counters (if supported) */ |
|---|
| 172 | 173 | #define STMMAC_MMC_STAT(m) \ |
|---|
| 173 | | - { #m, FIELD_SIZEOF(struct stmmac_counters, m), \ |
|---|
| 174 | + { #m, sizeof_field(struct stmmac_counters, m), \ |
|---|
| 174 | 175 | offsetof(struct stmmac_priv, mmc.m)} |
|---|
| 175 | 176 | |
|---|
| 176 | 177 | static const struct stmmac_stats stmmac_mmc[] = { |
|---|
| .. | .. |
|---|
| 253 | 254 | STMMAC_MMC_STAT(mmc_rx_tcp_err_octets), |
|---|
| 254 | 255 | STMMAC_MMC_STAT(mmc_rx_icmp_gd_octets), |
|---|
| 255 | 256 | STMMAC_MMC_STAT(mmc_rx_icmp_err_octets), |
|---|
| 257 | + STMMAC_MMC_STAT(mmc_tx_fpe_fragment_cntr), |
|---|
| 258 | + STMMAC_MMC_STAT(mmc_tx_hold_req_cntr), |
|---|
| 259 | + STMMAC_MMC_STAT(mmc_rx_packet_assembly_err_cntr), |
|---|
| 260 | + STMMAC_MMC_STAT(mmc_rx_packet_smd_err_cntr), |
|---|
| 261 | + STMMAC_MMC_STAT(mmc_rx_packet_assembly_ok_cntr), |
|---|
| 262 | + STMMAC_MMC_STAT(mmc_rx_fpe_fragment_cntr), |
|---|
| 256 | 263 | }; |
|---|
| 257 | 264 | #define STMMAC_MMC_STATS_LEN ARRAY_SIZE(stmmac_mmc) |
|---|
| 258 | 265 | |
|---|
| .. | .. |
|---|
| 263 | 270 | |
|---|
| 264 | 271 | if (priv->plat->has_gmac || priv->plat->has_gmac4) |
|---|
| 265 | 272 | strlcpy(info->driver, GMAC_ETHTOOL_NAME, sizeof(info->driver)); |
|---|
| 273 | + else if (priv->plat->has_xgmac) |
|---|
| 274 | + strlcpy(info->driver, XGMAC_ETHTOOL_NAME, sizeof(info->driver)); |
|---|
| 266 | 275 | else |
|---|
| 267 | 276 | strlcpy(info->driver, MAC100_ETHTOOL_NAME, |
|---|
| 268 | 277 | sizeof(info->driver)); |
|---|
| .. | .. |
|---|
| 274 | 283 | struct ethtool_link_ksettings *cmd) |
|---|
| 275 | 284 | { |
|---|
| 276 | 285 | struct stmmac_priv *priv = netdev_priv(dev); |
|---|
| 277 | | - struct phy_device *phy = dev->phydev; |
|---|
| 278 | 286 | |
|---|
| 279 | 287 | if (priv->hw->pcs & STMMAC_PCS_RGMII || |
|---|
| 280 | 288 | priv->hw->pcs & STMMAC_PCS_SGMII) { |
|---|
| .. | .. |
|---|
| 353 | 361 | return 0; |
|---|
| 354 | 362 | } |
|---|
| 355 | 363 | |
|---|
| 356 | | - if (phy == NULL) { |
|---|
| 357 | | - pr_err("%s: %s: PHY is not registered\n", |
|---|
| 358 | | - __func__, dev->name); |
|---|
| 359 | | - return -ENODEV; |
|---|
| 360 | | - } |
|---|
| 361 | | - if (!netif_running(dev)) { |
|---|
| 362 | | - pr_err("%s: interface is disabled: we cannot track " |
|---|
| 363 | | - "link speed / duplex setting\n", dev->name); |
|---|
| 364 | | - return -EBUSY; |
|---|
| 365 | | - } |
|---|
| 366 | | - phy_ethtool_ksettings_get(phy, cmd); |
|---|
| 367 | | - return 0; |
|---|
| 364 | + return phylink_ethtool_ksettings_get(priv->phylink, cmd); |
|---|
| 368 | 365 | } |
|---|
| 369 | 366 | |
|---|
| 370 | 367 | static int |
|---|
| .. | .. |
|---|
| 372 | 369 | const struct ethtool_link_ksettings *cmd) |
|---|
| 373 | 370 | { |
|---|
| 374 | 371 | struct stmmac_priv *priv = netdev_priv(dev); |
|---|
| 375 | | - struct phy_device *phy = dev->phydev; |
|---|
| 376 | | - int rc; |
|---|
| 377 | 372 | |
|---|
| 378 | 373 | if (priv->hw->pcs & STMMAC_PCS_RGMII || |
|---|
| 379 | 374 | priv->hw->pcs & STMMAC_PCS_SGMII) { |
|---|
| .. | .. |
|---|
| 397 | 392 | return 0; |
|---|
| 398 | 393 | } |
|---|
| 399 | 394 | |
|---|
| 400 | | - rc = phy_ethtool_ksettings_set(phy, cmd); |
|---|
| 395 | + if (priv->plat->tx_queues_to_use > 1 && cmd->base.duplex == DUPLEX_HALF) { |
|---|
| 396 | + netdev_warn(priv->dev, "Half-Duplex can only work with single queue\n"); |
|---|
| 397 | + return -EINVAL; |
|---|
| 398 | + } |
|---|
| 401 | 399 | |
|---|
| 402 | | - return rc; |
|---|
| 400 | + return phylink_ethtool_ksettings_set(priv->phylink, cmd); |
|---|
| 403 | 401 | } |
|---|
| 404 | 402 | |
|---|
| 405 | 403 | static u32 stmmac_ethtool_getmsglevel(struct net_device *dev) |
|---|
| .. | .. |
|---|
| 424 | 422 | |
|---|
| 425 | 423 | static int stmmac_ethtool_get_regs_len(struct net_device *dev) |
|---|
| 426 | 424 | { |
|---|
| 425 | + struct stmmac_priv *priv = netdev_priv(dev); |
|---|
| 426 | + |
|---|
| 427 | + if (priv->plat->has_xgmac) |
|---|
| 428 | + return XGMAC_REGSIZE * 4; |
|---|
| 429 | + else if (priv->plat->has_gmac4) |
|---|
| 430 | + return GMAC4_REG_SPACE_SIZE; |
|---|
| 427 | 431 | return REG_SPACE_SIZE; |
|---|
| 428 | 432 | } |
|---|
| 429 | 433 | |
|---|
| 430 | 434 | static void stmmac_ethtool_gregs(struct net_device *dev, |
|---|
| 431 | 435 | struct ethtool_regs *regs, void *space) |
|---|
| 432 | 436 | { |
|---|
| 433 | | - u32 *reg_space = (u32 *) space; |
|---|
| 434 | | - |
|---|
| 435 | 437 | struct stmmac_priv *priv = netdev_priv(dev); |
|---|
| 436 | | - |
|---|
| 437 | | - memset(reg_space, 0x0, REG_SPACE_SIZE); |
|---|
| 438 | + u32 *reg_space = (u32 *) space; |
|---|
| 438 | 439 | |
|---|
| 439 | 440 | stmmac_dump_mac_regs(priv, priv->hw, reg_space); |
|---|
| 440 | 441 | stmmac_dump_dma_regs(priv, priv->ioaddr, reg_space); |
|---|
| 442 | + |
|---|
| 441 | 443 | /* Copy DMA registers to where ethtool expects them */ |
|---|
| 442 | | - memcpy(®_space[ETHTOOL_DMA_OFFSET], ®_space[DMA_BUS_MODE / 4], |
|---|
| 443 | | - NUM_DWMAC1000_DMA_REGS * 4); |
|---|
| 444 | + if (priv->plat->has_gmac4) { |
|---|
| 445 | + /* GMAC4 dumps its DMA registers at its DMA_CHAN_BASE_ADDR */ |
|---|
| 446 | + memcpy(®_space[ETHTOOL_DMA_OFFSET], |
|---|
| 447 | + ®_space[GMAC4_DMA_CHAN_BASE_ADDR / 4], |
|---|
| 448 | + NUM_DWMAC4_DMA_REGS * 4); |
|---|
| 449 | + } else if (!priv->plat->has_xgmac) { |
|---|
| 450 | + memcpy(®_space[ETHTOOL_DMA_OFFSET], |
|---|
| 451 | + ®_space[DMA_BUS_MODE / 4], |
|---|
| 452 | + NUM_DWMAC1000_DMA_REGS * 4); |
|---|
| 453 | + } |
|---|
| 454 | +} |
|---|
| 455 | + |
|---|
| 456 | +static int stmmac_nway_reset(struct net_device *dev) |
|---|
| 457 | +{ |
|---|
| 458 | + struct stmmac_priv *priv = netdev_priv(dev); |
|---|
| 459 | + |
|---|
| 460 | + return phylink_ethtool_nway_reset(priv->phylink); |
|---|
| 461 | +} |
|---|
| 462 | + |
|---|
| 463 | +static void stmmac_get_ringparam(struct net_device *netdev, |
|---|
| 464 | + struct ethtool_ringparam *ring) |
|---|
| 465 | +{ |
|---|
| 466 | + struct stmmac_priv *priv = netdev_priv(netdev); |
|---|
| 467 | + |
|---|
| 468 | + ring->rx_max_pending = DMA_MAX_RX_SIZE; |
|---|
| 469 | + ring->tx_max_pending = DMA_MAX_TX_SIZE; |
|---|
| 470 | + ring->rx_pending = priv->dma_rx_size; |
|---|
| 471 | + ring->tx_pending = priv->dma_tx_size; |
|---|
| 472 | +} |
|---|
| 473 | + |
|---|
| 474 | +static int stmmac_set_ringparam(struct net_device *netdev, |
|---|
| 475 | + struct ethtool_ringparam *ring) |
|---|
| 476 | +{ |
|---|
| 477 | + if (ring->rx_mini_pending || ring->rx_jumbo_pending || |
|---|
| 478 | + ring->rx_pending < DMA_MIN_RX_SIZE || |
|---|
| 479 | + ring->rx_pending > DMA_MAX_RX_SIZE || |
|---|
| 480 | + !is_power_of_2(ring->rx_pending) || |
|---|
| 481 | + ring->tx_pending < DMA_MIN_TX_SIZE || |
|---|
| 482 | + ring->tx_pending > DMA_MAX_TX_SIZE || |
|---|
| 483 | + !is_power_of_2(ring->tx_pending)) |
|---|
| 484 | + return -EINVAL; |
|---|
| 485 | + |
|---|
| 486 | + return stmmac_reinit_ringparam(netdev, ring->rx_pending, |
|---|
| 487 | + ring->tx_pending); |
|---|
| 444 | 488 | } |
|---|
| 445 | 489 | |
|---|
| 446 | 490 | static void |
|---|
| .. | .. |
|---|
| 450 | 494 | struct stmmac_priv *priv = netdev_priv(netdev); |
|---|
| 451 | 495 | struct rgmii_adv adv_lp; |
|---|
| 452 | 496 | |
|---|
| 453 | | - pause->rx_pause = 0; |
|---|
| 454 | | - pause->tx_pause = 0; |
|---|
| 455 | | - |
|---|
| 456 | 497 | if (priv->hw->pcs && !stmmac_pcs_get_adv_lp(priv, priv->ioaddr, &adv_lp)) { |
|---|
| 457 | 498 | pause->autoneg = 1; |
|---|
| 458 | 499 | if (!adv_lp.pause) |
|---|
| 459 | 500 | return; |
|---|
| 460 | 501 | } else { |
|---|
| 461 | | - if (!(netdev->phydev->supported & SUPPORTED_Pause) || |
|---|
| 462 | | - !(netdev->phydev->supported & SUPPORTED_Asym_Pause)) |
|---|
| 463 | | - return; |
|---|
| 502 | + phylink_ethtool_get_pauseparam(priv->phylink, pause); |
|---|
| 464 | 503 | } |
|---|
| 465 | | - |
|---|
| 466 | | - pause->autoneg = netdev->phydev->autoneg; |
|---|
| 467 | | - |
|---|
| 468 | | - if (priv->flow_ctrl & FLOW_RX) |
|---|
| 469 | | - pause->rx_pause = 1; |
|---|
| 470 | | - if (priv->flow_ctrl & FLOW_TX) |
|---|
| 471 | | - pause->tx_pause = 1; |
|---|
| 472 | | - |
|---|
| 473 | 504 | } |
|---|
| 474 | 505 | |
|---|
| 475 | 506 | static int |
|---|
| .. | .. |
|---|
| 477 | 508 | struct ethtool_pauseparam *pause) |
|---|
| 478 | 509 | { |
|---|
| 479 | 510 | struct stmmac_priv *priv = netdev_priv(netdev); |
|---|
| 480 | | - u32 tx_cnt = priv->plat->tx_queues_to_use; |
|---|
| 481 | | - struct phy_device *phy = netdev->phydev; |
|---|
| 482 | | - int new_pause = FLOW_OFF; |
|---|
| 483 | 511 | struct rgmii_adv adv_lp; |
|---|
| 484 | 512 | |
|---|
| 485 | 513 | if (priv->hw->pcs && !stmmac_pcs_get_adv_lp(priv, priv->ioaddr, &adv_lp)) { |
|---|
| 486 | 514 | pause->autoneg = 1; |
|---|
| 487 | 515 | if (!adv_lp.pause) |
|---|
| 488 | 516 | return -EOPNOTSUPP; |
|---|
| 517 | + return 0; |
|---|
| 489 | 518 | } else { |
|---|
| 490 | | - if (!(phy->supported & SUPPORTED_Pause) || |
|---|
| 491 | | - !(phy->supported & SUPPORTED_Asym_Pause)) |
|---|
| 492 | | - return -EOPNOTSUPP; |
|---|
| 519 | + return phylink_ethtool_set_pauseparam(priv->phylink, pause); |
|---|
| 493 | 520 | } |
|---|
| 494 | | - |
|---|
| 495 | | - if (pause->rx_pause) |
|---|
| 496 | | - new_pause |= FLOW_RX; |
|---|
| 497 | | - if (pause->tx_pause) |
|---|
| 498 | | - new_pause |= FLOW_TX; |
|---|
| 499 | | - |
|---|
| 500 | | - priv->flow_ctrl = new_pause; |
|---|
| 501 | | - phy->autoneg = pause->autoneg; |
|---|
| 502 | | - |
|---|
| 503 | | - if (phy->autoneg) { |
|---|
| 504 | | - if (netif_running(netdev)) |
|---|
| 505 | | - return phy_start_aneg(phy); |
|---|
| 506 | | - } |
|---|
| 507 | | - |
|---|
| 508 | | - stmmac_flow_ctrl(priv, priv->hw, phy->duplex, priv->flow_ctrl, |
|---|
| 509 | | - priv->pause, tx_cnt); |
|---|
| 510 | | - return 0; |
|---|
| 511 | 521 | } |
|---|
| 512 | 522 | |
|---|
| 513 | 523 | static void stmmac_get_ethtool_stats(struct net_device *dev, |
|---|
| .. | .. |
|---|
| 533 | 543 | if (ret) { |
|---|
| 534 | 544 | /* If supported, for new GMAC chips expose the MMC counters */ |
|---|
| 535 | 545 | if (priv->dma_cap.rmon) { |
|---|
| 536 | | - dwmac_mmc_read(priv->mmcaddr, &priv->mmc); |
|---|
| 546 | + stmmac_mmc_read(priv, priv->mmcaddr, &priv->mmc); |
|---|
| 537 | 547 | |
|---|
| 538 | 548 | for (i = 0; i < STMMAC_MMC_STATS_LEN; i++) { |
|---|
| 539 | 549 | char *p; |
|---|
| .. | .. |
|---|
| 545 | 555 | } |
|---|
| 546 | 556 | } |
|---|
| 547 | 557 | if (priv->eee_enabled) { |
|---|
| 548 | | - int val = phy_get_eee_err(dev->phydev); |
|---|
| 558 | + int val = phylink_get_eee_err(priv->phylink); |
|---|
| 549 | 559 | if (val) |
|---|
| 550 | 560 | priv->xstats.phy_eee_wakeup_error_n = val; |
|---|
| 551 | 561 | } |
|---|
| .. | .. |
|---|
| 585 | 595 | } |
|---|
| 586 | 596 | |
|---|
| 587 | 597 | return len; |
|---|
| 598 | + case ETH_SS_TEST: |
|---|
| 599 | + return stmmac_selftest_get_count(priv); |
|---|
| 588 | 600 | default: |
|---|
| 589 | 601 | return -EOPNOTSUPP; |
|---|
| 590 | 602 | } |
|---|
| .. | .. |
|---|
| 621 | 633 | p += ETH_GSTRING_LEN; |
|---|
| 622 | 634 | } |
|---|
| 623 | 635 | break; |
|---|
| 636 | + case ETH_SS_TEST: |
|---|
| 637 | + stmmac_selftest_get_strings(priv, p); |
|---|
| 638 | + break; |
|---|
| 624 | 639 | default: |
|---|
| 625 | 640 | WARN_ON(1); |
|---|
| 626 | 641 | break; |
|---|
| .. | .. |
|---|
| 632 | 647 | { |
|---|
| 633 | 648 | struct stmmac_priv *priv = netdev_priv(dev); |
|---|
| 634 | 649 | |
|---|
| 650 | + if (!priv->plat->pmt) |
|---|
| 651 | + return phylink_ethtool_get_wol(priv->phylink, wol); |
|---|
| 652 | + |
|---|
| 635 | 653 | mutex_lock(&priv->lock); |
|---|
| 636 | 654 | if (device_can_wakeup(priv->device)) { |
|---|
| 637 | 655 | wol->supported = WAKE_MAGIC | WAKE_UCAST; |
|---|
| 656 | + if (priv->hw_cap_support && !priv->dma_cap.pmt_magic_frame) |
|---|
| 657 | + wol->supported &= ~WAKE_MAGIC; |
|---|
| 638 | 658 | wol->wolopts = priv->wolopts; |
|---|
| 639 | 659 | } |
|---|
| 640 | 660 | mutex_unlock(&priv->lock); |
|---|
| .. | .. |
|---|
| 645 | 665 | struct stmmac_priv *priv = netdev_priv(dev); |
|---|
| 646 | 666 | u32 support = WAKE_MAGIC | WAKE_UCAST; |
|---|
| 647 | 667 | |
|---|
| 668 | + if (!device_can_wakeup(priv->device)) |
|---|
| 669 | + return -EOPNOTSUPP; |
|---|
| 670 | + |
|---|
| 671 | + if (!priv->plat->pmt) { |
|---|
| 672 | + int ret = phylink_ethtool_set_wol(priv->phylink, wol); |
|---|
| 673 | + |
|---|
| 674 | + if (!ret) |
|---|
| 675 | + device_set_wakeup_enable(priv->device, !!wol->wolopts); |
|---|
| 676 | + return ret; |
|---|
| 677 | + } |
|---|
| 678 | + |
|---|
| 648 | 679 | /* By default almost all GMAC devices support the WoL via |
|---|
| 649 | 680 | * magic frame but we can disable it if the HW capability |
|---|
| 650 | 681 | * register shows no support for pmt_magic_frame. */ |
|---|
| 651 | 682 | if ((priv->hw_cap_support) && (!priv->dma_cap.pmt_magic_frame)) |
|---|
| 652 | 683 | wol->wolopts &= ~WAKE_MAGIC; |
|---|
| 653 | | - |
|---|
| 654 | | - if (!device_can_wakeup(priv->device)) |
|---|
| 655 | | - return -EINVAL; |
|---|
| 656 | 684 | |
|---|
| 657 | 685 | if (wol->wolopts & ~support) |
|---|
| 658 | 686 | return -EINVAL; |
|---|
| .. | .. |
|---|
| 684 | 712 | edata->eee_enabled = priv->eee_enabled; |
|---|
| 685 | 713 | edata->eee_active = priv->eee_active; |
|---|
| 686 | 714 | edata->tx_lpi_timer = priv->tx_lpi_timer; |
|---|
| 715 | + edata->tx_lpi_enabled = priv->tx_lpi_enabled; |
|---|
| 687 | 716 | |
|---|
| 688 | | - return phy_ethtool_get_eee(dev->phydev, edata); |
|---|
| 717 | + return phylink_ethtool_get_eee(priv->phylink, edata); |
|---|
| 689 | 718 | } |
|---|
| 690 | 719 | |
|---|
| 691 | 720 | static int stmmac_ethtool_op_set_eee(struct net_device *dev, |
|---|
| .. | .. |
|---|
| 697 | 726 | if (!priv->dma_cap.eee) |
|---|
| 698 | 727 | return -EOPNOTSUPP; |
|---|
| 699 | 728 | |
|---|
| 729 | + if (priv->tx_lpi_enabled != edata->tx_lpi_enabled) |
|---|
| 730 | + netdev_warn(priv->dev, |
|---|
| 731 | + "Setting EEE tx-lpi is not supported\n"); |
|---|
| 732 | + |
|---|
| 700 | 733 | if (!edata->eee_enabled) |
|---|
| 701 | 734 | stmmac_disable_eee_mode(priv); |
|---|
| 702 | 735 | |
|---|
| 703 | | - ret = phy_ethtool_set_eee(dev->phydev, edata); |
|---|
| 736 | + ret = phylink_ethtool_set_eee(priv->phylink, edata); |
|---|
| 704 | 737 | if (ret) |
|---|
| 705 | 738 | return ret; |
|---|
| 706 | 739 | |
|---|
| 707 | | - priv->tx_lpi_timer = edata->tx_lpi_timer; |
|---|
| 740 | + if (edata->eee_enabled && |
|---|
| 741 | + priv->tx_lpi_timer != edata->tx_lpi_timer) { |
|---|
| 742 | + priv->tx_lpi_timer = edata->tx_lpi_timer; |
|---|
| 743 | + stmmac_eee_init(priv); |
|---|
| 744 | + } |
|---|
| 745 | + |
|---|
| 708 | 746 | return 0; |
|---|
| 709 | 747 | } |
|---|
| 710 | 748 | |
|---|
| .. | .. |
|---|
| 742 | 780 | ec->tx_coalesce_usecs = priv->tx_coal_timer; |
|---|
| 743 | 781 | ec->tx_max_coalesced_frames = priv->tx_coal_frames; |
|---|
| 744 | 782 | |
|---|
| 745 | | - if (priv->use_riwt) |
|---|
| 783 | + if (priv->use_riwt) { |
|---|
| 784 | + ec->rx_max_coalesced_frames = priv->rx_coal_frames; |
|---|
| 746 | 785 | ec->rx_coalesce_usecs = stmmac_riwt2usec(priv->rx_riwt, priv); |
|---|
| 786 | + } |
|---|
| 747 | 787 | |
|---|
| 748 | 788 | return 0; |
|---|
| 749 | 789 | } |
|---|
| .. | .. |
|---|
| 755 | 795 | u32 rx_cnt = priv->plat->rx_queues_to_use; |
|---|
| 756 | 796 | unsigned int rx_riwt; |
|---|
| 757 | 797 | |
|---|
| 758 | | - /* Check not supported parameters */ |
|---|
| 759 | | - if ((ec->rx_max_coalesced_frames) || (ec->rx_coalesce_usecs_irq) || |
|---|
| 760 | | - (ec->rx_max_coalesced_frames_irq) || (ec->tx_coalesce_usecs_irq) || |
|---|
| 761 | | - (ec->use_adaptive_rx_coalesce) || (ec->use_adaptive_tx_coalesce) || |
|---|
| 762 | | - (ec->pkt_rate_low) || (ec->rx_coalesce_usecs_low) || |
|---|
| 763 | | - (ec->rx_max_coalesced_frames_low) || (ec->tx_coalesce_usecs_high) || |
|---|
| 764 | | - (ec->tx_max_coalesced_frames_low) || (ec->pkt_rate_high) || |
|---|
| 765 | | - (ec->tx_coalesce_usecs_low) || (ec->rx_coalesce_usecs_high) || |
|---|
| 766 | | - (ec->rx_max_coalesced_frames_high) || |
|---|
| 767 | | - (ec->tx_max_coalesced_frames_irq) || |
|---|
| 768 | | - (ec->stats_block_coalesce_usecs) || |
|---|
| 769 | | - (ec->tx_max_coalesced_frames_high) || (ec->rate_sample_interval)) |
|---|
| 770 | | - return -EOPNOTSUPP; |
|---|
| 798 | + if (priv->use_riwt && (ec->rx_coalesce_usecs > 0)) { |
|---|
| 799 | + rx_riwt = stmmac_usec2riwt(ec->rx_coalesce_usecs, priv); |
|---|
| 771 | 800 | |
|---|
| 772 | | - if (ec->rx_coalesce_usecs == 0) |
|---|
| 773 | | - return -EINVAL; |
|---|
| 801 | + if ((rx_riwt > MAX_DMA_RIWT) || (rx_riwt < MIN_DMA_RIWT)) |
|---|
| 802 | + return -EINVAL; |
|---|
| 803 | + |
|---|
| 804 | + priv->rx_riwt = rx_riwt; |
|---|
| 805 | + stmmac_rx_watchdog(priv, priv->ioaddr, priv->rx_riwt, rx_cnt); |
|---|
| 806 | + } |
|---|
| 774 | 807 | |
|---|
| 775 | 808 | if ((ec->tx_coalesce_usecs == 0) && |
|---|
| 776 | 809 | (ec->tx_max_coalesced_frames == 0)) |
|---|
| .. | .. |
|---|
| 780 | 813 | (ec->tx_max_coalesced_frames > STMMAC_TX_MAX_FRAMES)) |
|---|
| 781 | 814 | return -EINVAL; |
|---|
| 782 | 815 | |
|---|
| 783 | | - rx_riwt = stmmac_usec2riwt(ec->rx_coalesce_usecs, priv); |
|---|
| 784 | | - |
|---|
| 785 | | - if ((rx_riwt > MAX_DMA_RIWT) || (rx_riwt < MIN_DMA_RIWT)) |
|---|
| 786 | | - return -EINVAL; |
|---|
| 787 | | - else if (!priv->use_riwt) |
|---|
| 788 | | - return -EOPNOTSUPP; |
|---|
| 789 | | - |
|---|
| 790 | 816 | /* Only copy relevant parameters, ignore all others. */ |
|---|
| 791 | 817 | priv->tx_coal_frames = ec->tx_max_coalesced_frames; |
|---|
| 792 | 818 | priv->tx_coal_timer = ec->tx_coalesce_usecs; |
|---|
| 793 | | - priv->rx_riwt = rx_riwt; |
|---|
| 794 | | - stmmac_rx_watchdog(priv, priv->ioaddr, priv->rx_riwt, rx_cnt); |
|---|
| 819 | + priv->rx_coal_frames = ec->rx_max_coalesced_frames; |
|---|
| 820 | + return 0; |
|---|
| 821 | +} |
|---|
| 822 | + |
|---|
| 823 | +static int stmmac_get_rxnfc(struct net_device *dev, |
|---|
| 824 | + struct ethtool_rxnfc *rxnfc, u32 *rule_locs) |
|---|
| 825 | +{ |
|---|
| 826 | + struct stmmac_priv *priv = netdev_priv(dev); |
|---|
| 827 | + |
|---|
| 828 | + switch (rxnfc->cmd) { |
|---|
| 829 | + case ETHTOOL_GRXRINGS: |
|---|
| 830 | + rxnfc->data = priv->plat->rx_queues_to_use; |
|---|
| 831 | + break; |
|---|
| 832 | + default: |
|---|
| 833 | + return -EOPNOTSUPP; |
|---|
| 834 | + } |
|---|
| 795 | 835 | |
|---|
| 796 | 836 | return 0; |
|---|
| 837 | +} |
|---|
| 838 | + |
|---|
| 839 | +static u32 stmmac_get_rxfh_key_size(struct net_device *dev) |
|---|
| 840 | +{ |
|---|
| 841 | + struct stmmac_priv *priv = netdev_priv(dev); |
|---|
| 842 | + |
|---|
| 843 | + return sizeof(priv->rss.key); |
|---|
| 844 | +} |
|---|
| 845 | + |
|---|
| 846 | +static u32 stmmac_get_rxfh_indir_size(struct net_device *dev) |
|---|
| 847 | +{ |
|---|
| 848 | + struct stmmac_priv *priv = netdev_priv(dev); |
|---|
| 849 | + |
|---|
| 850 | + return ARRAY_SIZE(priv->rss.table); |
|---|
| 851 | +} |
|---|
| 852 | + |
|---|
| 853 | +static int stmmac_get_rxfh(struct net_device *dev, u32 *indir, u8 *key, |
|---|
| 854 | + u8 *hfunc) |
|---|
| 855 | +{ |
|---|
| 856 | + struct stmmac_priv *priv = netdev_priv(dev); |
|---|
| 857 | + int i; |
|---|
| 858 | + |
|---|
| 859 | + if (indir) { |
|---|
| 860 | + for (i = 0; i < ARRAY_SIZE(priv->rss.table); i++) |
|---|
| 861 | + indir[i] = priv->rss.table[i]; |
|---|
| 862 | + } |
|---|
| 863 | + |
|---|
| 864 | + if (key) |
|---|
| 865 | + memcpy(key, priv->rss.key, sizeof(priv->rss.key)); |
|---|
| 866 | + if (hfunc) |
|---|
| 867 | + *hfunc = ETH_RSS_HASH_TOP; |
|---|
| 868 | + |
|---|
| 869 | + return 0; |
|---|
| 870 | +} |
|---|
| 871 | + |
|---|
| 872 | +static int stmmac_set_rxfh(struct net_device *dev, const u32 *indir, |
|---|
| 873 | + const u8 *key, const u8 hfunc) |
|---|
| 874 | +{ |
|---|
| 875 | + struct stmmac_priv *priv = netdev_priv(dev); |
|---|
| 876 | + int i; |
|---|
| 877 | + |
|---|
| 878 | + if ((hfunc != ETH_RSS_HASH_NO_CHANGE) && (hfunc != ETH_RSS_HASH_TOP)) |
|---|
| 879 | + return -EOPNOTSUPP; |
|---|
| 880 | + |
|---|
| 881 | + if (indir) { |
|---|
| 882 | + for (i = 0; i < ARRAY_SIZE(priv->rss.table); i++) |
|---|
| 883 | + priv->rss.table[i] = indir[i]; |
|---|
| 884 | + } |
|---|
| 885 | + |
|---|
| 886 | + if (key) |
|---|
| 887 | + memcpy(priv->rss.key, key, sizeof(priv->rss.key)); |
|---|
| 888 | + |
|---|
| 889 | + return stmmac_rss_configure(priv, priv->hw, &priv->rss, |
|---|
| 890 | + priv->plat->rx_queues_to_use); |
|---|
| 891 | +} |
|---|
| 892 | + |
|---|
| 893 | +static void stmmac_get_channels(struct net_device *dev, |
|---|
| 894 | + struct ethtool_channels *chan) |
|---|
| 895 | +{ |
|---|
| 896 | + struct stmmac_priv *priv = netdev_priv(dev); |
|---|
| 897 | + |
|---|
| 898 | + chan->rx_count = priv->plat->rx_queues_to_use; |
|---|
| 899 | + chan->tx_count = priv->plat->tx_queues_to_use; |
|---|
| 900 | + chan->max_rx = priv->dma_cap.number_rx_queues; |
|---|
| 901 | + chan->max_tx = priv->dma_cap.number_tx_queues; |
|---|
| 902 | +} |
|---|
| 903 | + |
|---|
| 904 | +static int stmmac_set_channels(struct net_device *dev, |
|---|
| 905 | + struct ethtool_channels *chan) |
|---|
| 906 | +{ |
|---|
| 907 | + struct stmmac_priv *priv = netdev_priv(dev); |
|---|
| 908 | + |
|---|
| 909 | + if (chan->rx_count > priv->dma_cap.number_rx_queues || |
|---|
| 910 | + chan->tx_count > priv->dma_cap.number_tx_queues || |
|---|
| 911 | + !chan->rx_count || !chan->tx_count) |
|---|
| 912 | + return -EINVAL; |
|---|
| 913 | + |
|---|
| 914 | + return stmmac_reinit_queues(dev, chan->rx_count, chan->tx_count); |
|---|
| 797 | 915 | } |
|---|
| 798 | 916 | |
|---|
| 799 | 917 | static int stmmac_get_ts_info(struct net_device *dev, |
|---|
| .. | .. |
|---|
| 869 | 987 | } |
|---|
| 870 | 988 | |
|---|
| 871 | 989 | static const struct ethtool_ops stmmac_ethtool_ops = { |
|---|
| 990 | + .supported_coalesce_params = ETHTOOL_COALESCE_USECS | |
|---|
| 991 | + ETHTOOL_COALESCE_MAX_FRAMES, |
|---|
| 872 | 992 | .begin = stmmac_check_if_running, |
|---|
| 873 | 993 | .get_drvinfo = stmmac_ethtool_getdrvinfo, |
|---|
| 874 | 994 | .get_msglevel = stmmac_ethtool_getmsglevel, |
|---|
| .. | .. |
|---|
| 876 | 996 | .get_regs = stmmac_ethtool_gregs, |
|---|
| 877 | 997 | .get_regs_len = stmmac_ethtool_get_regs_len, |
|---|
| 878 | 998 | .get_link = ethtool_op_get_link, |
|---|
| 879 | | - .nway_reset = phy_ethtool_nway_reset, |
|---|
| 999 | + .nway_reset = stmmac_nway_reset, |
|---|
| 1000 | + .get_ringparam = stmmac_get_ringparam, |
|---|
| 1001 | + .set_ringparam = stmmac_set_ringparam, |
|---|
| 880 | 1002 | .get_pauseparam = stmmac_get_pauseparam, |
|---|
| 881 | 1003 | .set_pauseparam = stmmac_set_pauseparam, |
|---|
| 1004 | + .self_test = stmmac_selftest_run, |
|---|
| 882 | 1005 | .get_ethtool_stats = stmmac_get_ethtool_stats, |
|---|
| 883 | 1006 | .get_strings = stmmac_get_strings, |
|---|
| 884 | 1007 | .get_wol = stmmac_get_wol, |
|---|
| .. | .. |
|---|
| 886 | 1009 | .get_eee = stmmac_ethtool_op_get_eee, |
|---|
| 887 | 1010 | .set_eee = stmmac_ethtool_op_set_eee, |
|---|
| 888 | 1011 | .get_sset_count = stmmac_get_sset_count, |
|---|
| 1012 | + .get_rxnfc = stmmac_get_rxnfc, |
|---|
| 1013 | + .get_rxfh_key_size = stmmac_get_rxfh_key_size, |
|---|
| 1014 | + .get_rxfh_indir_size = stmmac_get_rxfh_indir_size, |
|---|
| 1015 | + .get_rxfh = stmmac_get_rxfh, |
|---|
| 1016 | + .set_rxfh = stmmac_set_rxfh, |
|---|
| 889 | 1017 | .get_ts_info = stmmac_get_ts_info, |
|---|
| 890 | 1018 | .get_coalesce = stmmac_get_coalesce, |
|---|
| 891 | 1019 | .set_coalesce = stmmac_set_coalesce, |
|---|
| 1020 | + .get_channels = stmmac_get_channels, |
|---|
| 1021 | + .set_channels = stmmac_set_channels, |
|---|
| 892 | 1022 | .get_tunable = stmmac_get_tunable, |
|---|
| 893 | 1023 | .set_tunable = stmmac_set_tunable, |
|---|
| 894 | 1024 | .get_link_ksettings = stmmac_ethtool_get_link_ksettings, |
|---|