aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/e1000/e1000_main.c
diff options
context:
space:
mode:
authorJesse Brandeburg <jesse.brandeburg@intel.com>2009-09-25 12:17:44 +0000
committerDavid S. Miller <davem@davemloft.net>2009-09-26 20:15:36 -0700
commitbe0f071956e2142e2e88e9d6d5655ba1c75d07c8 (patch)
treee0b1be3f259841aaabcfbb02c4495dd2580d0130 /drivers/net/e1000/e1000_main.c
parentbaa34745fe6263c733f43feddb0b8100d6538f37 (diff)
downloadlinux-be0f071956e2142e2e88e9d6d5655ba1c75d07c8.tar.gz
e1000: test link state conclusively
e1000 was using one particular way to detect link, but with the advent of some of the newer hardware designs using SERDES connections, tests for link must completely cover all cases. Signed-off-by: Jesse Brandeburg <jesse.brandeburg@intel.com> Signed-off-by: Don Skidmore <donald.c.skidmore@intel.com> Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/e1000/e1000_main.c')
-rw-r--r--drivers/net/e1000/e1000_main.c49
1 files changed, 41 insertions, 8 deletions
diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
index 7af3255a8e9c1c..11508afdfdb9c2 100644
--- a/drivers/net/e1000/e1000_main.c
+++ b/drivers/net/e1000/e1000_main.c
@@ -2251,6 +2251,41 @@ static void e1000_82547_tx_fifo_stall(unsigned long data)
}
}
+static bool e1000_has_link(struct e1000_adapter *adapter)
+{
+ struct e1000_hw *hw = &adapter->hw;
+ bool link_active = false;
+ s32 ret_val = 0;
+
+ /* get_link_status is set on LSC (link status) interrupt or
+ * rx sequence error interrupt. get_link_status will stay
+ * false until the e1000_check_for_link establishes link
+ * for copper adapters ONLY
+ */
+ switch (hw->media_type) {
+ case e1000_media_type_copper:
+ if (hw->get_link_status) {
+ ret_val = e1000_check_for_link(hw);
+ link_active = !hw->get_link_status;
+ } else {
+ link_active = true;
+ }
+ break;
+ case e1000_media_type_fiber:
+ ret_val = e1000_check_for_link(hw);
+ link_active = !!(er32(STATUS) & E1000_STATUS_LU);
+ break;
+ case e1000_media_type_internal_serdes:
+ ret_val = e1000_check_for_link(hw);
+ link_active = hw->serdes_has_link;
+ break;
+ default:
+ break;
+ }
+
+ return link_active;
+}
+
/**
* e1000_watchdog - Timer Call-back
* @data: pointer to adapter cast into an unsigned long
@@ -2263,18 +2298,15 @@ static void e1000_watchdog(unsigned long data)
struct e1000_tx_ring *txdr = adapter->tx_ring;
u32 link, tctl;
- e1000_check_for_link(hw);
-
- if ((hw->media_type == e1000_media_type_internal_serdes) &&
- !(er32(TXCW) & E1000_TXCW_ANE))
- link = !hw->serdes_link_down;
- else
- link = er32(STATUS) & E1000_STATUS_LU;
+ link = e1000_has_link(adapter);
+ if ((netif_carrier_ok(netdev)) && link)
+ goto link_up;
if (link) {
if (!netif_carrier_ok(netdev)) {
u32 ctrl;
bool txb2b = true;
+ /* update snapshot of PHY registers on LSC */
e1000_get_speed_and_duplex(hw,
&adapter->link_speed,
&adapter->link_duplex);
@@ -2299,7 +2331,7 @@ static void e1000_watchdog(unsigned long data)
case SPEED_10:
txb2b = false;
netdev->tx_queue_len = 10;
- adapter->tx_timeout_factor = 8;
+ adapter->tx_timeout_factor = 16;
break;
case SPEED_100:
txb2b = false;
@@ -2335,6 +2367,7 @@ static void e1000_watchdog(unsigned long data)
e1000_smartspeed(adapter);
}
+link_up:
e1000_update_stats(adapter);
hw->tx_packet_delta = adapter->stats.tpt - adapter->tpt_old;