diff options
Diffstat (limited to 'drivers/net/sfc/ethtool.c')
-rw-r--r-- | drivers/net/sfc/ethtool.c | 57 |
1 files changed, 48 insertions, 9 deletions
diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c index 1b33f89df4d..0e81af6d834 100644 --- a/drivers/net/sfc/ethtool.c +++ b/drivers/net/sfc/ethtool.c | |||
@@ -12,11 +12,13 @@ | |||
12 | #include <linux/ethtool.h> | 12 | #include <linux/ethtool.h> |
13 | #include <linux/rtnetlink.h> | 13 | #include <linux/rtnetlink.h> |
14 | #include "net_driver.h" | 14 | #include "net_driver.h" |
15 | #include "workarounds.h" | ||
15 | #include "selftest.h" | 16 | #include "selftest.h" |
16 | #include "efx.h" | 17 | #include "efx.h" |
17 | #include "ethtool.h" | 18 | #include "ethtool.h" |
18 | #include "falcon.h" | 19 | #include "falcon.h" |
19 | #include "spi.h" | 20 | #include "spi.h" |
21 | #include "mdio_10g.h" | ||
20 | 22 | ||
21 | const char *efx_loopback_mode_names[] = { | 23 | const char *efx_loopback_mode_names[] = { |
22 | [LOOPBACK_NONE] = "NONE", | 24 | [LOOPBACK_NONE] = "NONE", |
@@ -674,14 +676,51 @@ static int efx_ethtool_set_pauseparam(struct net_device *net_dev, | |||
674 | struct ethtool_pauseparam *pause) | 676 | struct ethtool_pauseparam *pause) |
675 | { | 677 | { |
676 | struct efx_nic *efx = netdev_priv(net_dev); | 678 | struct efx_nic *efx = netdev_priv(net_dev); |
677 | enum efx_fc_type flow_control = efx->flow_control; | 679 | enum efx_fc_type wanted_fc; |
680 | bool reset; | ||
678 | 681 | ||
679 | flow_control &= ~(EFX_FC_RX | EFX_FC_TX | EFX_FC_AUTO); | 682 | wanted_fc = ((pause->rx_pause ? EFX_FC_RX : 0) | |
680 | flow_control |= pause->rx_pause ? EFX_FC_RX : 0; | 683 | (pause->tx_pause ? EFX_FC_TX : 0) | |
681 | flow_control |= pause->tx_pause ? EFX_FC_TX : 0; | 684 | (pause->autoneg ? EFX_FC_AUTO : 0)); |
682 | flow_control |= pause->autoneg ? EFX_FC_AUTO : 0; | 685 | |
686 | if ((wanted_fc & EFX_FC_TX) && !(wanted_fc & EFX_FC_RX)) { | ||
687 | EFX_LOG(efx, "Flow control unsupported: tx ON rx OFF\n"); | ||
688 | return -EINVAL; | ||
689 | } | ||
690 | |||
691 | if (!(efx->phy_op->mmds & DEV_PRESENT_BIT(MDIO_MMD_AN)) && | ||
692 | (wanted_fc & EFX_FC_AUTO)) { | ||
693 | EFX_LOG(efx, "PHY does not support flow control " | ||
694 | "autonegotiation\n"); | ||
695 | return -EINVAL; | ||
696 | } | ||
697 | |||
698 | /* TX flow control may automatically turn itself off if the | ||
699 | * link partner (intermittently) stops responding to pause | ||
700 | * frames. There isn't any indication that this has happened, | ||
701 | * so the best we do is leave it up to the user to spot this | ||
702 | * and fix it be cycling transmit flow control on this end. */ | ||
703 | reset = (wanted_fc & EFX_FC_TX) && !(efx->wanted_fc & EFX_FC_TX); | ||
704 | if (EFX_WORKAROUND_11482(efx) && reset) { | ||
705 | if (falcon_rev(efx) >= FALCON_REV_B0) { | ||
706 | /* Recover by resetting the EM block */ | ||
707 | if (efx->link_up) | ||
708 | falcon_drain_tx_fifo(efx); | ||
709 | } else { | ||
710 | /* Schedule a reset to recover */ | ||
711 | efx_schedule_reset(efx, RESET_TYPE_INVISIBLE); | ||
712 | } | ||
713 | } | ||
714 | |||
715 | /* Try to push the pause parameters */ | ||
716 | mutex_lock(&efx->mac_lock); | ||
717 | |||
718 | efx->wanted_fc = wanted_fc; | ||
719 | mdio_clause45_set_pause(efx); | ||
720 | __efx_reconfigure_port(efx); | ||
721 | |||
722 | mutex_unlock(&efx->mac_lock); | ||
683 | 723 | ||
684 | efx_reconfigure_port(efx); | ||
685 | return 0; | 724 | return 0; |
686 | } | 725 | } |
687 | 726 | ||
@@ -690,9 +729,9 @@ static void efx_ethtool_get_pauseparam(struct net_device *net_dev, | |||
690 | { | 729 | { |
691 | struct efx_nic *efx = netdev_priv(net_dev); | 730 | struct efx_nic *efx = netdev_priv(net_dev); |
692 | 731 | ||
693 | pause->rx_pause = !!(efx->flow_control & EFX_FC_RX); | 732 | pause->rx_pause = !!(efx->wanted_fc & EFX_FC_RX); |
694 | pause->tx_pause = !!(efx->flow_control & EFX_FC_TX); | 733 | pause->tx_pause = !!(efx->wanted_fc & EFX_FC_TX); |
695 | pause->autoneg = !!(efx->flow_control & EFX_FC_AUTO); | 734 | pause->autoneg = !!(efx->wanted_fc & EFX_FC_AUTO); |
696 | } | 735 | } |
697 | 736 | ||
698 | 737 | ||