diff options
author | Ingo Molnar <mingo@elte.hu> | 2010-05-03 11:17:01 +0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2010-05-03 11:17:01 +0400 |
commit | 53ba4f2fa73225113a488584df0d85d3cba52943 (patch) | |
tree | d85b984d9818abc3ccc0237eb53b710d9e96c39e /drivers/net/igb/igb_ethtool.c | |
parent | bd6d29c25bb1a24a4c160ec5de43e0004e01f72b (diff) | |
parent | 66f41d4c5c8a5deed66fdcc84509376c9a0bf9d8 (diff) | |
download | linux-53ba4f2fa73225113a488584df0d85d3cba52943.tar.xz |
Merge commit 'v2.6.34-rc6' into core/locking
Diffstat (limited to 'drivers/net/igb/igb_ethtool.c')
-rw-r--r-- | drivers/net/igb/igb_ethtool.c | 95 |
1 files changed, 65 insertions, 30 deletions
diff --git a/drivers/net/igb/igb_ethtool.c b/drivers/net/igb/igb_ethtool.c index f771a6c08777..743038490104 100644 --- a/drivers/net/igb/igb_ethtool.c +++ b/drivers/net/igb/igb_ethtool.c @@ -35,6 +35,7 @@ #include <linux/if_ether.h> #include <linux/ethtool.h> #include <linux/sched.h> +#include <linux/slab.h> #include "igb.h" @@ -234,6 +235,24 @@ static int igb_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) return 0; } +static u32 igb_get_link(struct net_device *netdev) +{ + struct igb_adapter *adapter = netdev_priv(netdev); + struct e1000_mac_info *mac = &adapter->hw.mac; + + /* + * If the link is not reported up to netdev, interrupts are disabled, + * and so the physical link state may have changed since we last + * looked. Set get_link_status to make sure that the true link + * state is interrogated, rather than pulling a cached and possibly + * stale link state from the driver. + */ + if (!netif_carrier_ok(netdev)) + mac->get_link_status = 1; + + return igb_has_link(adapter); +} + static void igb_get_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *pause) { @@ -296,7 +315,7 @@ static int igb_set_pauseparam(struct net_device *netdev, static u32 igb_get_rx_csum(struct net_device *netdev) { struct igb_adapter *adapter = netdev_priv(netdev); - return !!(adapter->rx_ring[0].flags & IGB_RING_FLAG_RX_CSUM); + return !!(adapter->rx_ring[0]->flags & IGB_RING_FLAG_RX_CSUM); } static int igb_set_rx_csum(struct net_device *netdev, u32 data) @@ -306,9 +325,9 @@ static int igb_set_rx_csum(struct net_device *netdev, u32 data) for (i = 0; i < adapter->num_rx_queues; i++) { if (data) - adapter->rx_ring[i].flags |= IGB_RING_FLAG_RX_CSUM; + adapter->rx_ring[i]->flags |= IGB_RING_FLAG_RX_CSUM; else - adapter->rx_ring[i].flags &= ~IGB_RING_FLAG_RX_CSUM; + adapter->rx_ring[i]->flags &= ~IGB_RING_FLAG_RX_CSUM; } return 0; @@ -771,9 +790,9 @@ static int igb_set_ringparam(struct net_device *netdev, if (!netif_running(adapter->netdev)) { for (i = 0; i < adapter->num_tx_queues; i++) - adapter->tx_ring[i].count = new_tx_count; + adapter->tx_ring[i]->count = new_tx_count; for (i = 0; i < adapter->num_rx_queues; i++) - adapter->rx_ring[i].count = new_rx_count; + adapter->rx_ring[i]->count = new_rx_count; adapter->tx_ring_count = new_tx_count; adapter->rx_ring_count = new_rx_count; goto clear_reset; @@ -797,10 +816,10 @@ static int igb_set_ringparam(struct net_device *netdev, * to the tx and rx ring structs. */ if (new_tx_count != adapter->tx_ring_count) { - memcpy(temp_ring, adapter->tx_ring, - adapter->num_tx_queues * sizeof(struct igb_ring)); - for (i = 0; i < adapter->num_tx_queues; i++) { + memcpy(&temp_ring[i], adapter->tx_ring[i], + sizeof(struct igb_ring)); + temp_ring[i].count = new_tx_count; err = igb_setup_tx_resources(&temp_ring[i]); if (err) { @@ -812,20 +831,21 @@ static int igb_set_ringparam(struct net_device *netdev, } } - for (i = 0; i < adapter->num_tx_queues; i++) - igb_free_tx_resources(&adapter->tx_ring[i]); + for (i = 0; i < adapter->num_tx_queues; i++) { + igb_free_tx_resources(adapter->tx_ring[i]); - memcpy(adapter->tx_ring, temp_ring, - adapter->num_tx_queues * sizeof(struct igb_ring)); + memcpy(adapter->tx_ring[i], &temp_ring[i], + sizeof(struct igb_ring)); + } adapter->tx_ring_count = new_tx_count; } - if (new_rx_count != adapter->rx_ring->count) { - memcpy(temp_ring, adapter->rx_ring, - adapter->num_rx_queues * sizeof(struct igb_ring)); - + if (new_rx_count != adapter->rx_ring_count) { for (i = 0; i < adapter->num_rx_queues; i++) { + memcpy(&temp_ring[i], adapter->rx_ring[i], + sizeof(struct igb_ring)); + temp_ring[i].count = new_rx_count; err = igb_setup_rx_resources(&temp_ring[i]); if (err) { @@ -838,11 +858,12 @@ static int igb_set_ringparam(struct net_device *netdev, } - for (i = 0; i < adapter->num_rx_queues; i++) - igb_free_rx_resources(&adapter->rx_ring[i]); + for (i = 0; i < adapter->num_rx_queues; i++) { + igb_free_rx_resources(adapter->rx_ring[i]); - memcpy(adapter->rx_ring, temp_ring, - adapter->num_rx_queues * sizeof(struct igb_ring)); + memcpy(adapter->rx_ring[i], &temp_ring[i], + sizeof(struct igb_ring)); + } adapter->rx_ring_count = new_rx_count; } @@ -1704,6 +1725,9 @@ static void igb_diag_test(struct net_device *netdev, dev_info(&adapter->pdev->dev, "offline testing starting\n"); + /* power up link for link test */ + igb_power_up_link(adapter); + /* Link test performed before hardware reset so autoneg doesn't * interfere with test result */ if (igb_link_test(adapter, &data[4])) @@ -1727,6 +1751,8 @@ static void igb_diag_test(struct net_device *netdev, eth_test->flags |= ETH_TEST_FL_FAILED; igb_reset(adapter); + /* power up link for loopback test */ + igb_power_up_link(adapter); if (igb_loopback_test(adapter, &data[3])) eth_test->flags |= ETH_TEST_FL_FAILED; @@ -1745,9 +1771,14 @@ static void igb_diag_test(struct net_device *netdev, dev_open(netdev); } else { dev_info(&adapter->pdev->dev, "online testing starting\n"); - /* Online tests */ - if (igb_link_test(adapter, &data[4])) - eth_test->flags |= ETH_TEST_FL_FAILED; + + /* PHY is powered down when interface is down */ + if (!netif_carrier_ok(netdev)) { + data[4] = 0; + } else { + if (igb_link_test(adapter, &data[4])) + eth_test->flags |= ETH_TEST_FL_FAILED; + } /* Online tests aren't run; pass by default */ data[0] = 0; @@ -1783,6 +1814,7 @@ static int igb_wol_exclusion(struct igb_adapter *adapter, retval = 0; break; case E1000_DEV_ID_82576_QUAD_COPPER: + case E1000_DEV_ID_82576_QUAD_COPPER_ET2: /* quad port adapters only support WoL on port A */ if (!(adapter->flags & IGB_FLAG_QUAD_PORT_A)) { wol->supported = 0; @@ -1812,7 +1844,8 @@ static void igb_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) struct igb_adapter *adapter = netdev_priv(netdev); wol->supported = WAKE_UCAST | WAKE_MCAST | - WAKE_BCAST | WAKE_MAGIC; + WAKE_BCAST | WAKE_MAGIC | + WAKE_PHY; wol->wolopts = 0; /* this function will set ->supported = 0 and return 1 if wol is not @@ -1835,15 +1868,15 @@ static void igb_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) wol->wolopts |= WAKE_BCAST; if (adapter->wol & E1000_WUFC_MAG) wol->wolopts |= WAKE_MAGIC; - - return; + if (adapter->wol & E1000_WUFC_LNKC) + wol->wolopts |= WAKE_PHY; } static int igb_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) { struct igb_adapter *adapter = netdev_priv(netdev); - if (wol->wolopts & (WAKE_PHY | WAKE_ARP | WAKE_MAGICSECURE)) + if (wol->wolopts & (WAKE_ARP | WAKE_MAGICSECURE)) return -EOPNOTSUPP; if (igb_wol_exclusion(adapter, wol) || @@ -1861,6 +1894,8 @@ static int igb_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) adapter->wol |= E1000_WUFC_BC; if (wol->wolopts & WAKE_MAGIC) adapter->wol |= E1000_WUFC_MAG; + if (wol->wolopts & WAKE_PHY) + adapter->wol |= E1000_WUFC_LNKC; device_set_wakeup_enable(&adapter->pdev->dev, adapter->wol); return 0; @@ -2005,12 +2040,12 @@ static void igb_get_ethtool_stats(struct net_device *netdev, sizeof(u64)) ? *(u64 *)p : *(u32 *)p; } for (j = 0; j < adapter->num_tx_queues; j++) { - queue_stat = (u64 *)&adapter->tx_ring[j].tx_stats; + queue_stat = (u64 *)&adapter->tx_ring[j]->tx_stats; for (k = 0; k < IGB_TX_QUEUE_STATS_LEN; k++, i++) data[i] = queue_stat[k]; } for (j = 0; j < adapter->num_rx_queues; j++) { - queue_stat = (u64 *)&adapter->rx_ring[j].rx_stats; + queue_stat = (u64 *)&adapter->rx_ring[j]->rx_stats; for (k = 0; k < IGB_RX_QUEUE_STATS_LEN; k++, i++) data[i] = queue_stat[k]; } @@ -2074,7 +2109,7 @@ static const struct ethtool_ops igb_ethtool_ops = { .get_msglevel = igb_get_msglevel, .set_msglevel = igb_set_msglevel, .nway_reset = igb_nway_reset, - .get_link = ethtool_op_get_link, + .get_link = igb_get_link, .get_eeprom_len = igb_get_eeprom_len, .get_eeprom = igb_get_eeprom, .set_eeprom = igb_set_eeprom, |