.. | .. |
---|
| 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, |
---|