diff options
Diffstat (limited to 'drivers/net/e1000e/ethtool.c')
-rw-r--r-- | drivers/net/e1000e/ethtool.c | 93 |
1 files changed, 70 insertions, 23 deletions
diff --git a/drivers/net/e1000e/ethtool.c b/drivers/net/e1000e/ethtool.c index 1bf4d2a5d34f..0aa50c229c79 100644 --- a/drivers/net/e1000e/ethtool.c +++ b/drivers/net/e1000e/ethtool.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /******************************************************************************* | 1 | /******************************************************************************* |
2 | 2 | ||
3 | Intel PRO/1000 Linux driver | 3 | Intel PRO/1000 Linux driver |
4 | Copyright(c) 1999 - 2008 Intel Corporation. | 4 | Copyright(c) 1999 - 2009 Intel Corporation. |
5 | 5 | ||
6 | This program is free software; you can redistribute it and/or modify it | 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, | 7 | under the terms and conditions of the GNU General Public License, |
@@ -35,14 +35,22 @@ | |||
35 | 35 | ||
36 | #include "e1000.h" | 36 | #include "e1000.h" |
37 | 37 | ||
38 | enum {NETDEV_STATS, E1000_STATS}; | ||
39 | |||
38 | struct e1000_stats { | 40 | struct e1000_stats { |
39 | char stat_string[ETH_GSTRING_LEN]; | 41 | char stat_string[ETH_GSTRING_LEN]; |
42 | int type; | ||
40 | int sizeof_stat; | 43 | int sizeof_stat; |
41 | int stat_offset; | 44 | int stat_offset; |
42 | }; | 45 | }; |
43 | 46 | ||
44 | #define E1000_STAT(m) sizeof(((struct e1000_adapter *)0)->m), \ | 47 | #define E1000_STAT(m) E1000_STATS, \ |
45 | offsetof(struct e1000_adapter, m) | 48 | sizeof(((struct e1000_adapter *)0)->m), \ |
49 | offsetof(struct e1000_adapter, m) | ||
50 | #define E1000_NETDEV_STAT(m) NETDEV_STATS, \ | ||
51 | sizeof(((struct net_device *)0)->m), \ | ||
52 | offsetof(struct net_device, m) | ||
53 | |||
46 | static const struct e1000_stats e1000_gstrings_stats[] = { | 54 | static const struct e1000_stats e1000_gstrings_stats[] = { |
47 | { "rx_packets", E1000_STAT(stats.gprc) }, | 55 | { "rx_packets", E1000_STAT(stats.gprc) }, |
48 | { "tx_packets", E1000_STAT(stats.gptc) }, | 56 | { "tx_packets", E1000_STAT(stats.gptc) }, |
@@ -52,21 +60,21 @@ static const struct e1000_stats e1000_gstrings_stats[] = { | |||
52 | { "tx_broadcast", E1000_STAT(stats.bptc) }, | 60 | { "tx_broadcast", E1000_STAT(stats.bptc) }, |
53 | { "rx_multicast", E1000_STAT(stats.mprc) }, | 61 | { "rx_multicast", E1000_STAT(stats.mprc) }, |
54 | { "tx_multicast", E1000_STAT(stats.mptc) }, | 62 | { "tx_multicast", E1000_STAT(stats.mptc) }, |
55 | { "rx_errors", E1000_STAT(net_stats.rx_errors) }, | 63 | { "rx_errors", E1000_NETDEV_STAT(stats.rx_errors) }, |
56 | { "tx_errors", E1000_STAT(net_stats.tx_errors) }, | 64 | { "tx_errors", E1000_NETDEV_STAT(stats.tx_errors) }, |
57 | { "tx_dropped", E1000_STAT(net_stats.tx_dropped) }, | 65 | { "tx_dropped", E1000_NETDEV_STAT(stats.tx_dropped) }, |
58 | { "multicast", E1000_STAT(stats.mprc) }, | 66 | { "multicast", E1000_STAT(stats.mprc) }, |
59 | { "collisions", E1000_STAT(stats.colc) }, | 67 | { "collisions", E1000_STAT(stats.colc) }, |
60 | { "rx_length_errors", E1000_STAT(net_stats.rx_length_errors) }, | 68 | { "rx_length_errors", E1000_NETDEV_STAT(stats.rx_length_errors) }, |
61 | { "rx_over_errors", E1000_STAT(net_stats.rx_over_errors) }, | 69 | { "rx_over_errors", E1000_NETDEV_STAT(stats.rx_over_errors) }, |
62 | { "rx_crc_errors", E1000_STAT(stats.crcerrs) }, | 70 | { "rx_crc_errors", E1000_STAT(stats.crcerrs) }, |
63 | { "rx_frame_errors", E1000_STAT(net_stats.rx_frame_errors) }, | 71 | { "rx_frame_errors", E1000_NETDEV_STAT(stats.rx_frame_errors) }, |
64 | { "rx_no_buffer_count", E1000_STAT(stats.rnbc) }, | 72 | { "rx_no_buffer_count", E1000_STAT(stats.rnbc) }, |
65 | { "rx_missed_errors", E1000_STAT(stats.mpc) }, | 73 | { "rx_missed_errors", E1000_STAT(stats.mpc) }, |
66 | { "tx_aborted_errors", E1000_STAT(stats.ecol) }, | 74 | { "tx_aborted_errors", E1000_STAT(stats.ecol) }, |
67 | { "tx_carrier_errors", E1000_STAT(stats.tncrs) }, | 75 | { "tx_carrier_errors", E1000_STAT(stats.tncrs) }, |
68 | { "tx_fifo_errors", E1000_STAT(net_stats.tx_fifo_errors) }, | 76 | { "tx_fifo_errors", E1000_NETDEV_STAT(stats.tx_fifo_errors) }, |
69 | { "tx_heartbeat_errors", E1000_STAT(net_stats.tx_heartbeat_errors) }, | 77 | { "tx_heartbeat_errors", E1000_NETDEV_STAT(stats.tx_heartbeat_errors) }, |
70 | { "tx_window_errors", E1000_STAT(stats.latecol) }, | 78 | { "tx_window_errors", E1000_STAT(stats.latecol) }, |
71 | { "tx_abort_late_coll", E1000_STAT(stats.latecol) }, | 79 | { "tx_abort_late_coll", E1000_STAT(stats.latecol) }, |
72 | { "tx_deferred_ok", E1000_STAT(stats.dc) }, | 80 | { "tx_deferred_ok", E1000_STAT(stats.dc) }, |
@@ -182,6 +190,17 @@ static int e1000_get_settings(struct net_device *netdev, | |||
182 | static u32 e1000_get_link(struct net_device *netdev) | 190 | static u32 e1000_get_link(struct net_device *netdev) |
183 | { | 191 | { |
184 | struct e1000_adapter *adapter = netdev_priv(netdev); | 192 | struct e1000_adapter *adapter = netdev_priv(netdev); |
193 | struct e1000_mac_info *mac = &adapter->hw.mac; | ||
194 | |||
195 | /* | ||
196 | * If the link is not reported up to netdev, interrupts are disabled, | ||
197 | * and so the physical link state may have changed since we last | ||
198 | * looked. Set get_link_status to make sure that the true link | ||
199 | * state is interrogated, rather than pulling a cached and possibly | ||
200 | * stale link state from the driver. | ||
201 | */ | ||
202 | if (!netif_carrier_ok(netdev)) | ||
203 | mac->get_link_status = 1; | ||
185 | 204 | ||
186 | return e1000_has_link(adapter); | 205 | return e1000_has_link(adapter); |
187 | } | 206 | } |
@@ -327,10 +346,18 @@ static int e1000_set_pauseparam(struct net_device *netdev, | |||
327 | 346 | ||
328 | hw->fc.current_mode = hw->fc.requested_mode; | 347 | hw->fc.current_mode = hw->fc.requested_mode; |
329 | 348 | ||
330 | retval = ((hw->phy.media_type == e1000_media_type_fiber) ? | 349 | if (hw->phy.media_type == e1000_media_type_fiber) { |
331 | hw->mac.ops.setup_link(hw) : e1000e_force_mac_fc(hw)); | 350 | retval = hw->mac.ops.setup_link(hw); |
351 | /* implicit goto out */ | ||
352 | } else { | ||
353 | retval = e1000e_force_mac_fc(hw); | ||
354 | if (retval) | ||
355 | goto out; | ||
356 | e1000e_set_fc_watermarks(hw); | ||
357 | } | ||
332 | } | 358 | } |
333 | 359 | ||
360 | out: | ||
334 | clear_bit(__E1000_RESETTING, &adapter->state); | 361 | clear_bit(__E1000_RESETTING, &adapter->state); |
335 | return retval; | 362 | return retval; |
336 | } | 363 | } |
@@ -508,7 +535,8 @@ static int e1000_get_eeprom(struct net_device *netdev, | |||
508 | 535 | ||
509 | if (ret_val) { | 536 | if (ret_val) { |
510 | /* a read error occurred, throw away the result */ | 537 | /* a read error occurred, throw away the result */ |
511 | memset(eeprom_buff, 0xff, sizeof(eeprom_buff)); | 538 | memset(eeprom_buff, 0xff, sizeof(u16) * |
539 | (last_word - first_word + 1)); | ||
512 | } else { | 540 | } else { |
513 | /* Device's eeprom is always little-endian, word addressable */ | 541 | /* Device's eeprom is always little-endian, word addressable */ |
514 | for (i = 0; i < last_word - first_word + 1; i++) | 542 | for (i = 0; i < last_word - first_word + 1; i++) |
@@ -588,7 +616,9 @@ static int e1000_set_eeprom(struct net_device *netdev, | |||
588 | * and flush shadow RAM for applicable controllers | 616 | * and flush shadow RAM for applicable controllers |
589 | */ | 617 | */ |
590 | if ((first_word <= NVM_CHECKSUM_REG) || | 618 | if ((first_word <= NVM_CHECKSUM_REG) || |
591 | (hw->mac.type == e1000_82574) || (hw->mac.type == e1000_82573)) | 619 | (hw->mac.type == e1000_82583) || |
620 | (hw->mac.type == e1000_82574) || | ||
621 | (hw->mac.type == e1000_82573)) | ||
592 | ret_val = e1000e_update_nvm_checksum(hw); | 622 | ret_val = e1000e_update_nvm_checksum(hw); |
593 | 623 | ||
594 | out: | 624 | out: |
@@ -921,10 +951,10 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data) | |||
921 | e1000e_set_interrupt_capability(adapter); | 951 | e1000e_set_interrupt_capability(adapter); |
922 | } | 952 | } |
923 | /* Hook up test interrupt handler just for this test */ | 953 | /* Hook up test interrupt handler just for this test */ |
924 | if (!request_irq(irq, &e1000_test_intr, IRQF_PROBE_SHARED, netdev->name, | 954 | if (!request_irq(irq, e1000_test_intr, IRQF_PROBE_SHARED, netdev->name, |
925 | netdev)) { | 955 | netdev)) { |
926 | shared_int = 0; | 956 | shared_int = 0; |
927 | } else if (request_irq(irq, &e1000_test_intr, IRQF_SHARED, | 957 | } else if (request_irq(irq, e1000_test_intr, IRQF_SHARED, |
928 | netdev->name, netdev)) { | 958 | netdev->name, netdev)) { |
929 | *data = 1; | 959 | *data = 1; |
930 | ret_val = -1; | 960 | ret_val = -1; |
@@ -1231,6 +1261,10 @@ static int e1000_integrated_phy_loopback(struct e1000_adapter *adapter) | |||
1231 | 1261 | ||
1232 | hw->mac.autoneg = 0; | 1262 | hw->mac.autoneg = 0; |
1233 | 1263 | ||
1264 | /* Workaround: K1 must be disabled for stable 1Gbps operation */ | ||
1265 | if (hw->mac.type == e1000_pchlan) | ||
1266 | e1000_configure_k1_ich8lan(hw, false); | ||
1267 | |||
1234 | if (hw->phy.type == e1000_phy_m88) { | 1268 | if (hw->phy.type == e1000_phy_m88) { |
1235 | /* Auto-MDI/MDIX Off */ | 1269 | /* Auto-MDI/MDIX Off */ |
1236 | e1e_wphy(hw, M88E1000_PHY_SPEC_CTRL, 0x0808); | 1270 | e1e_wphy(hw, M88E1000_PHY_SPEC_CTRL, 0x0808); |
@@ -1761,12 +1795,11 @@ static int e1000_set_wol(struct net_device *netdev, | |||
1761 | { | 1795 | { |
1762 | struct e1000_adapter *adapter = netdev_priv(netdev); | 1796 | struct e1000_adapter *adapter = netdev_priv(netdev); |
1763 | 1797 | ||
1764 | if (wol->wolopts & WAKE_MAGICSECURE) | ||
1765 | return -EOPNOTSUPP; | ||
1766 | |||
1767 | if (!(adapter->flags & FLAG_HAS_WOL) || | 1798 | if (!(adapter->flags & FLAG_HAS_WOL) || |
1768 | !device_can_wakeup(&adapter->pdev->dev)) | 1799 | !device_can_wakeup(&adapter->pdev->dev) || |
1769 | return wol->wolopts ? -EOPNOTSUPP : 0; | 1800 | (wol->wolopts & ~(WAKE_UCAST | WAKE_MCAST | WAKE_BCAST | |
1801 | WAKE_MAGIC | WAKE_PHY | WAKE_ARP))) | ||
1802 | return -EOPNOTSUPP; | ||
1770 | 1803 | ||
1771 | /* these settings will always override what we currently have */ | 1804 | /* these settings will always override what we currently have */ |
1772 | adapter->wol = 0; | 1805 | adapter->wol = 0; |
@@ -1824,6 +1857,7 @@ static int e1000_phys_id(struct net_device *netdev, u32 data) | |||
1824 | 1857 | ||
1825 | if ((hw->phy.type == e1000_phy_ife) || | 1858 | if ((hw->phy.type == e1000_phy_ife) || |
1826 | (hw->mac.type == e1000_pchlan) || | 1859 | (hw->mac.type == e1000_pchlan) || |
1860 | (hw->mac.type == e1000_82583) || | ||
1827 | (hw->mac.type == e1000_82574)) { | 1861 | (hw->mac.type == e1000_82574)) { |
1828 | INIT_WORK(&adapter->led_blink_task, e1000e_led_blink_task); | 1862 | INIT_WORK(&adapter->led_blink_task, e1000e_led_blink_task); |
1829 | if (!adapter->blink_timer.function) { | 1863 | if (!adapter->blink_timer.function) { |
@@ -1904,10 +1938,21 @@ static void e1000_get_ethtool_stats(struct net_device *netdev, | |||
1904 | { | 1938 | { |
1905 | struct e1000_adapter *adapter = netdev_priv(netdev); | 1939 | struct e1000_adapter *adapter = netdev_priv(netdev); |
1906 | int i; | 1940 | int i; |
1941 | char *p = NULL; | ||
1907 | 1942 | ||
1908 | e1000e_update_stats(adapter); | 1943 | e1000e_update_stats(adapter); |
1909 | for (i = 0; i < E1000_GLOBAL_STATS_LEN; i++) { | 1944 | for (i = 0; i < E1000_GLOBAL_STATS_LEN; i++) { |
1910 | char *p = (char *)adapter+e1000_gstrings_stats[i].stat_offset; | 1945 | switch (e1000_gstrings_stats[i].type) { |
1946 | case NETDEV_STATS: | ||
1947 | p = (char *) netdev + | ||
1948 | e1000_gstrings_stats[i].stat_offset; | ||
1949 | break; | ||
1950 | case E1000_STATS: | ||
1951 | p = (char *) adapter + | ||
1952 | e1000_gstrings_stats[i].stat_offset; | ||
1953 | break; | ||
1954 | } | ||
1955 | |||
1911 | data[i] = (e1000_gstrings_stats[i].sizeof_stat == | 1956 | data[i] = (e1000_gstrings_stats[i].sizeof_stat == |
1912 | sizeof(u64)) ? *(u64 *)p : *(u32 *)p; | 1957 | sizeof(u64)) ? *(u64 *)p : *(u32 *)p; |
1913 | } | 1958 | } |
@@ -1967,6 +2012,8 @@ static const struct ethtool_ops e1000_ethtool_ops = { | |||
1967 | .get_sset_count = e1000e_get_sset_count, | 2012 | .get_sset_count = e1000e_get_sset_count, |
1968 | .get_coalesce = e1000_get_coalesce, | 2013 | .get_coalesce = e1000_get_coalesce, |
1969 | .set_coalesce = e1000_set_coalesce, | 2014 | .set_coalesce = e1000_set_coalesce, |
2015 | .get_flags = ethtool_op_get_flags, | ||
2016 | .set_flags = ethtool_op_set_flags, | ||
1970 | }; | 2017 | }; |
1971 | 2018 | ||
1972 | void e1000e_set_ethtool_ops(struct net_device *netdev) | 2019 | void e1000e_set_ethtool_ops(struct net_device *netdev) |