diff options
Diffstat (limited to 'drivers/net/e1000e/ethtool.c')
-rw-r--r-- | drivers/net/e1000e/ethtool.c | 154 |
1 files changed, 81 insertions, 73 deletions
diff --git a/drivers/net/e1000e/ethtool.c b/drivers/net/e1000e/ethtool.c index 07f09e96e453..859d0d3af6c9 100644 --- a/drivers/net/e1000e/ethtool.c +++ b/drivers/net/e1000e/ethtool.c @@ -122,6 +122,7 @@ static int e1000_get_settings(struct net_device *netdev, { struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; + u32 speed; if (hw->phy.media_type == e1000_media_type_copper) { @@ -159,23 +160,23 @@ static int e1000_get_settings(struct net_device *netdev, ecmd->transceiver = XCVR_EXTERNAL; } - ecmd->speed = -1; + speed = -1; ecmd->duplex = -1; if (netif_running(netdev)) { if (netif_carrier_ok(netdev)) { - ecmd->speed = adapter->link_speed; + speed = adapter->link_speed; ecmd->duplex = adapter->link_duplex - 1; } } else { u32 status = er32(STATUS); if (status & E1000_STATUS_LU) { if (status & E1000_STATUS_SPEED_1000) - ecmd->speed = 1000; + speed = SPEED_1000; else if (status & E1000_STATUS_SPEED_100) - ecmd->speed = 100; + speed = SPEED_100; else - ecmd->speed = 10; + speed = SPEED_10; if (status & E1000_STATUS_FD) ecmd->duplex = DUPLEX_FULL; @@ -184,6 +185,7 @@ static int e1000_get_settings(struct net_device *netdev, } } + ethtool_cmd_speed_set(ecmd, speed); ecmd->autoneg = ((hw->phy.media_type == e1000_media_type_fiber) || hw->mac.autoneg) ? AUTONEG_ENABLE : AUTONEG_DISABLE; @@ -198,20 +200,25 @@ static int e1000_get_settings(struct net_device *netdev, return 0; } -static int e1000_set_spd_dplx(struct e1000_adapter *adapter, u16 spddplx) +static int e1000_set_spd_dplx(struct e1000_adapter *adapter, u32 spd, u8 dplx) { struct e1000_mac_info *mac = &adapter->hw.mac; mac->autoneg = 0; + /* Make sure dplx is at most 1 bit and lsb of speed is not set + * for the switch() below to work */ + if ((spd & 1) || (dplx & ~1)) + goto err_inval; + /* Fiber NICs only allow 1000 gbps Full duplex */ if ((adapter->hw.phy.media_type == e1000_media_type_fiber) && - spddplx != (SPEED_1000 + DUPLEX_FULL)) { - e_err("Unsupported Speed/Duplex configuration\n"); - return -EINVAL; + spd != SPEED_1000 && + dplx != DUPLEX_FULL) { + goto err_inval; } - switch (spddplx) { + switch (spd + dplx) { case SPEED_10 + DUPLEX_HALF: mac->forced_speed_duplex = ADVERTISE_10_HALF; break; @@ -230,10 +237,13 @@ static int e1000_set_spd_dplx(struct e1000_adapter *adapter, u16 spddplx) break; case SPEED_1000 + DUPLEX_HALF: /* not supported */ default: - e_err("Unsupported Speed/Duplex configuration\n"); - return -EINVAL; + goto err_inval; } return 0; + +err_inval: + e_err("Unsupported Speed/Duplex configuration\n"); + return -EINVAL; } static int e1000_set_settings(struct net_device *netdev, @@ -253,7 +263,7 @@ static int e1000_set_settings(struct net_device *netdev, } while (test_and_set_bit(__E1000_RESETTING, &adapter->state)) - msleep(1); + usleep_range(1000, 2000); if (ecmd->autoneg == AUTONEG_ENABLE) { hw->mac.autoneg = 1; @@ -269,7 +279,8 @@ static int e1000_set_settings(struct net_device *netdev, if (adapter->fc_autoneg) hw->fc.requested_mode = e1000_fc_default; } else { - if (e1000_set_spd_dplx(adapter, ecmd->speed + ecmd->duplex)) { + u32 speed = ethtool_cmd_speed(ecmd); + if (e1000_set_spd_dplx(adapter, speed, ecmd->duplex)) { clear_bit(__E1000_RESETTING, &adapter->state); return -EINVAL; } @@ -317,7 +328,7 @@ static int e1000_set_pauseparam(struct net_device *netdev, adapter->fc_autoneg = pause->autoneg; while (test_and_set_bit(__E1000_RESETTING, &adapter->state)) - msleep(1); + usleep_range(1000, 2000); if (adapter->fc_autoneg == AUTONEG_ENABLE) { hw->fc.requested_mode = e1000_fc_default; @@ -673,7 +684,7 @@ static int e1000_set_ringparam(struct net_device *netdev, return -EINVAL; while (test_and_set_bit(__E1000_RESETTING, &adapter->state)) - msleep(1); + usleep_range(1000, 2000); if (netif_running(adapter->netdev)) e1000e_down(adapter); @@ -952,7 +963,7 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data) /* Disable all the interrupts */ ew32(IMC, 0xFFFFFFFF); - msleep(10); + usleep_range(10000, 20000); /* Test each interrupt */ for (i = 0; i < 10; i++) { @@ -984,7 +995,7 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data) adapter->test_icr = 0; ew32(IMC, mask); ew32(ICS, mask); - msleep(10); + usleep_range(10000, 20000); if (adapter->test_icr & mask) { *data = 3; @@ -1002,7 +1013,7 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data) adapter->test_icr = 0; ew32(IMS, mask); ew32(ICS, mask); - msleep(10); + usleep_range(10000, 20000); if (!(adapter->test_icr & mask)) { *data = 4; @@ -1020,7 +1031,7 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data) adapter->test_icr = 0; ew32(IMC, ~mask & 0x00007FFF); ew32(ICS, ~mask & 0x00007FFF); - msleep(10); + usleep_range(10000, 20000); if (adapter->test_icr) { *data = 5; @@ -1031,7 +1042,7 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data) /* Disable all the interrupts */ ew32(IMC, 0xFFFFFFFF); - msleep(10); + usleep_range(10000, 20000); /* Unhook test interrupt handler */ free_irq(irq, netdev); @@ -1406,7 +1417,7 @@ static int e1000_set_82571_fiber_loopback(struct e1000_adapter *adapter) */ #define E1000_SERDES_LB_ON 0x410 ew32(SCTL, E1000_SERDES_LB_ON); - msleep(10); + usleep_range(10000, 20000); return 0; } @@ -1501,7 +1512,7 @@ static void e1000_loopback_cleanup(struct e1000_adapter *adapter) hw->phy.media_type == e1000_media_type_internal_serdes) { #define E1000_SERDES_LB_OFF 0x400 ew32(SCTL, E1000_SERDES_LB_OFF); - msleep(10); + usleep_range(10000, 20000); break; } /* Fall Through */ @@ -1851,64 +1862,35 @@ static int e1000_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) return 0; } -/* toggle LED 4 times per second = 2 "blinks" per second */ -#define E1000_ID_INTERVAL (HZ/4) - -/* bit defines for adapter->led_status */ -#define E1000_LED_ON 0 - -void e1000e_led_blink_task(struct work_struct *work) -{ - struct e1000_adapter *adapter = container_of(work, - struct e1000_adapter, led_blink_task); - - if (test_and_change_bit(E1000_LED_ON, &adapter->led_status)) - adapter->hw.mac.ops.led_off(&adapter->hw); - else - adapter->hw.mac.ops.led_on(&adapter->hw); -} - -static void e1000_led_blink_callback(unsigned long data) -{ - struct e1000_adapter *adapter = (struct e1000_adapter *) data; - - schedule_work(&adapter->led_blink_task); - mod_timer(&adapter->blink_timer, jiffies + E1000_ID_INTERVAL); -} - -static int e1000_phys_id(struct net_device *netdev, u32 data) +static int e1000_set_phys_id(struct net_device *netdev, + enum ethtool_phys_id_state state) { struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; - if (!data) - data = INT_MAX; + switch (state) { + case ETHTOOL_ID_ACTIVE: + if (!hw->mac.ops.blink_led) + return 2; /* cycle on/off twice per second */ - if ((hw->phy.type == e1000_phy_ife) || - (hw->mac.type == e1000_pchlan) || - (hw->mac.type == e1000_pch2lan) || - (hw->mac.type == e1000_82583) || - (hw->mac.type == e1000_82574)) { - if (!adapter->blink_timer.function) { - init_timer(&adapter->blink_timer); - adapter->blink_timer.function = - e1000_led_blink_callback; - adapter->blink_timer.data = (unsigned long) adapter; - } - mod_timer(&adapter->blink_timer, jiffies); - msleep_interruptible(data * 1000); - del_timer_sync(&adapter->blink_timer); + hw->mac.ops.blink_led(hw); + break; + + case ETHTOOL_ID_INACTIVE: if (hw->phy.type == e1000_phy_ife) e1e_wphy(hw, IFE_PHY_SPECIAL_CONTROL_LED, 0); - } else { - e1000e_blink_led(hw); - msleep_interruptible(data * 1000); - } + hw->mac.ops.led_off(hw); + hw->mac.ops.cleanup_led(hw); + break; - hw->mac.ops.led_off(hw); - clear_bit(E1000_LED_ON, &adapter->led_status); - hw->mac.ops.cleanup_led(hw); + case ETHTOOL_ID_ON: + adapter->hw.mac.ops.led_on(&adapter->hw); + break; + case ETHTOOL_ID_OFF: + adapter->hw.mac.ops.led_off(&adapter->hw); + break; + } return 0; } @@ -2020,6 +2002,31 @@ static void e1000_get_strings(struct net_device *netdev, u32 stringset, } } +static int e1000e_set_flags(struct net_device *netdev, u32 data) +{ + struct e1000_adapter *adapter = netdev_priv(netdev); + bool need_reset = false; + int rc; + + need_reset = (data & ETH_FLAG_RXVLAN) != + (netdev->features & NETIF_F_HW_VLAN_RX); + + rc = ethtool_op_set_flags(netdev, data, ETH_FLAG_RXVLAN | + ETH_FLAG_TXVLAN); + + if (rc) + return rc; + + if (need_reset) { + if (netif_running(netdev)) + e1000e_reinit_locked(adapter); + else + e1000e_reset(adapter); + } + + return 0; +} + static const struct ethtool_ops e1000_ethtool_ops = { .get_settings = e1000_get_settings, .set_settings = e1000_set_settings, @@ -2049,12 +2056,13 @@ static const struct ethtool_ops e1000_ethtool_ops = { .set_tso = e1000_set_tso, .self_test = e1000_diag_test, .get_strings = e1000_get_strings, - .phys_id = e1000_phys_id, + .set_phys_id = e1000_set_phys_id, .get_ethtool_stats = e1000_get_ethtool_stats, .get_sset_count = e1000e_get_sset_count, .get_coalesce = e1000_get_coalesce, .set_coalesce = e1000_set_coalesce, .get_flags = ethtool_op_get_flags, + .set_flags = e1000e_set_flags, }; void e1000e_set_ethtool_ops(struct net_device *netdev) |