diff options
author | dave graham <david.graham@intel.com> | 2009-02-10 07:52:28 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-02-10 20:00:28 -0500 |
commit | c9523379d6000f379a84b6b970efb8782c128071 (patch) | |
tree | 9674789cf9d452391bbafe9cd00bb9734e394554 /drivers/net/e1000e | |
parent | 573cca8c6fdbf6bd2dae8f9e9b66931990849c83 (diff) |
e1000e: Serdes - attempt autoneg when link restored.
This patch addresses an issue where we did not restart auto-negotiation on
serdes links when the link partner was disabled and re-enabled. It includes
reworking the serdes link detect mechanism to be a state machine for
82571 and 82572 parts only.
Signed-off-by: dave graham <david.graham@intel.com>
Acked-by: Bruce Allan <bruce.w.allan@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/e1000e')
-rw-r--r-- | drivers/net/e1000e/82571.c | 132 | ||||
-rw-r--r-- | drivers/net/e1000e/hw.h | 8 |
2 files changed, 139 insertions, 1 deletions
diff --git a/drivers/net/e1000e/82571.c b/drivers/net/e1000e/82571.c index 25f6bc94e69b..565fd4e8f951 100644 --- a/drivers/net/e1000e/82571.c +++ b/drivers/net/e1000e/82571.c | |||
@@ -61,6 +61,7 @@ | |||
61 | static s32 e1000_get_phy_id_82571(struct e1000_hw *hw); | 61 | static s32 e1000_get_phy_id_82571(struct e1000_hw *hw); |
62 | static s32 e1000_setup_copper_link_82571(struct e1000_hw *hw); | 62 | static s32 e1000_setup_copper_link_82571(struct e1000_hw *hw); |
63 | static s32 e1000_setup_fiber_serdes_link_82571(struct e1000_hw *hw); | 63 | static s32 e1000_setup_fiber_serdes_link_82571(struct e1000_hw *hw); |
64 | static s32 e1000_check_for_serdes_link_82571(struct e1000_hw *hw); | ||
64 | static s32 e1000_write_nvm_eewr_82571(struct e1000_hw *hw, u16 offset, | 65 | static s32 e1000_write_nvm_eewr_82571(struct e1000_hw *hw, u16 offset, |
65 | u16 words, u16 *data); | 66 | u16 words, u16 *data); |
66 | static s32 e1000_fix_nvm_checksum_82571(struct e1000_hw *hw); | 67 | static s32 e1000_fix_nvm_checksum_82571(struct e1000_hw *hw); |
@@ -250,7 +251,7 @@ static s32 e1000_init_mac_params_82571(struct e1000_adapter *adapter) | |||
250 | case e1000_media_type_internal_serdes: | 251 | case e1000_media_type_internal_serdes: |
251 | func->setup_physical_interface = | 252 | func->setup_physical_interface = |
252 | e1000_setup_fiber_serdes_link_82571; | 253 | e1000_setup_fiber_serdes_link_82571; |
253 | func->check_for_link = e1000e_check_for_serdes_link; | 254 | func->check_for_link = e1000_check_for_serdes_link_82571; |
254 | func->get_link_up_info = | 255 | func->get_link_up_info = |
255 | e1000e_get_speed_and_duplex_fiber_serdes; | 256 | e1000e_get_speed_and_duplex_fiber_serdes; |
256 | break; | 257 | break; |
@@ -830,6 +831,10 @@ static s32 e1000_reset_hw_82571(struct e1000_hw *hw) | |||
830 | hw->dev_spec.e82571.alt_mac_addr_is_present) | 831 | hw->dev_spec.e82571.alt_mac_addr_is_present) |
831 | e1000e_set_laa_state_82571(hw, true); | 832 | e1000e_set_laa_state_82571(hw, true); |
832 | 833 | ||
834 | /* Reinitialize the 82571 serdes link state machine */ | ||
835 | if (hw->phy.media_type == e1000_media_type_internal_serdes) | ||
836 | hw->mac.serdes_link_state = e1000_serdes_link_down; | ||
837 | |||
833 | return 0; | 838 | return 0; |
834 | } | 839 | } |
835 | 840 | ||
@@ -1215,6 +1220,131 @@ static s32 e1000_setup_fiber_serdes_link_82571(struct e1000_hw *hw) | |||
1215 | } | 1220 | } |
1216 | 1221 | ||
1217 | /** | 1222 | /** |
1223 | * e1000_check_for_serdes_link_82571 - Check for link (Serdes) | ||
1224 | * @hw: pointer to the HW structure | ||
1225 | * | ||
1226 | * Checks for link up on the hardware. If link is not up and we have | ||
1227 | * a signal, then we need to force link up. | ||
1228 | **/ | ||
1229 | s32 e1000_check_for_serdes_link_82571(struct e1000_hw *hw) | ||
1230 | { | ||
1231 | struct e1000_mac_info *mac = &hw->mac; | ||
1232 | u32 rxcw; | ||
1233 | u32 ctrl; | ||
1234 | u32 status; | ||
1235 | s32 ret_val = 0; | ||
1236 | |||
1237 | ctrl = er32(CTRL); | ||
1238 | status = er32(STATUS); | ||
1239 | rxcw = er32(RXCW); | ||
1240 | |||
1241 | if ((rxcw & E1000_RXCW_SYNCH) && !(rxcw & E1000_RXCW_IV)) { | ||
1242 | |||
1243 | /* Receiver is synchronized with no invalid bits. */ | ||
1244 | switch (mac->serdes_link_state) { | ||
1245 | case e1000_serdes_link_autoneg_complete: | ||
1246 | if (!(status & E1000_STATUS_LU)) { | ||
1247 | /* | ||
1248 | * We have lost link, retry autoneg before | ||
1249 | * reporting link failure | ||
1250 | */ | ||
1251 | mac->serdes_link_state = | ||
1252 | e1000_serdes_link_autoneg_progress; | ||
1253 | hw_dbg(hw, "AN_UP -> AN_PROG\n"); | ||
1254 | } | ||
1255 | break; | ||
1256 | |||
1257 | case e1000_serdes_link_forced_up: | ||
1258 | /* | ||
1259 | * If we are receiving /C/ ordered sets, re-enable | ||
1260 | * auto-negotiation in the TXCW register and disable | ||
1261 | * forced link in the Device Control register in an | ||
1262 | * attempt to auto-negotiate with our link partner. | ||
1263 | */ | ||
1264 | if (rxcw & E1000_RXCW_C) { | ||
1265 | /* Enable autoneg, and unforce link up */ | ||
1266 | ew32(TXCW, mac->txcw); | ||
1267 | ew32(CTRL, | ||
1268 | (ctrl & ~E1000_CTRL_SLU)); | ||
1269 | mac->serdes_link_state = | ||
1270 | e1000_serdes_link_autoneg_progress; | ||
1271 | hw_dbg(hw, "FORCED_UP -> AN_PROG\n"); | ||
1272 | } | ||
1273 | break; | ||
1274 | |||
1275 | case e1000_serdes_link_autoneg_progress: | ||
1276 | /* | ||
1277 | * If the LU bit is set in the STATUS register, | ||
1278 | * autoneg has completed sucessfully. If not, | ||
1279 | * try foring the link because the far end may be | ||
1280 | * available but not capable of autonegotiation. | ||
1281 | */ | ||
1282 | if (status & E1000_STATUS_LU) { | ||
1283 | mac->serdes_link_state = | ||
1284 | e1000_serdes_link_autoneg_complete; | ||
1285 | hw_dbg(hw, "AN_PROG -> AN_UP\n"); | ||
1286 | } else { | ||
1287 | /* | ||
1288 | * Disable autoneg, force link up and | ||
1289 | * full duplex, and change state to forced | ||
1290 | */ | ||
1291 | ew32(TXCW, | ||
1292 | (mac->txcw & ~E1000_TXCW_ANE)); | ||
1293 | ctrl |= (E1000_CTRL_SLU | E1000_CTRL_FD); | ||
1294 | ew32(CTRL, ctrl); | ||
1295 | |||
1296 | /* Configure Flow Control after link up. */ | ||
1297 | ret_val = | ||
1298 | e1000e_config_fc_after_link_up(hw); | ||
1299 | if (ret_val) { | ||
1300 | hw_dbg(hw, "Error config flow control\n"); | ||
1301 | break; | ||
1302 | } | ||
1303 | mac->serdes_link_state = | ||
1304 | e1000_serdes_link_forced_up; | ||
1305 | hw_dbg(hw, "AN_PROG -> FORCED_UP\n"); | ||
1306 | } | ||
1307 | mac->serdes_has_link = true; | ||
1308 | break; | ||
1309 | |||
1310 | case e1000_serdes_link_down: | ||
1311 | default: | ||
1312 | /* The link was down but the receiver has now gained | ||
1313 | * valid sync, so lets see if we can bring the link | ||
1314 | * up. */ | ||
1315 | ew32(TXCW, mac->txcw); | ||
1316 | ew32(CTRL, | ||
1317 | (ctrl & ~E1000_CTRL_SLU)); | ||
1318 | mac->serdes_link_state = | ||
1319 | e1000_serdes_link_autoneg_progress; | ||
1320 | hw_dbg(hw, "DOWN -> AN_PROG\n"); | ||
1321 | break; | ||
1322 | } | ||
1323 | } else { | ||
1324 | if (!(rxcw & E1000_RXCW_SYNCH)) { | ||
1325 | mac->serdes_has_link = false; | ||
1326 | mac->serdes_link_state = e1000_serdes_link_down; | ||
1327 | hw_dbg(hw, "ANYSTATE -> DOWN\n"); | ||
1328 | } else { | ||
1329 | /* | ||
1330 | * We have sync, and can tolerate one | ||
1331 | * invalid (IV) codeword before declaring | ||
1332 | * link down, so reread to look again | ||
1333 | */ | ||
1334 | udelay(10); | ||
1335 | rxcw = er32(RXCW); | ||
1336 | if (rxcw & E1000_RXCW_IV) { | ||
1337 | mac->serdes_link_state = e1000_serdes_link_down; | ||
1338 | mac->serdes_has_link = false; | ||
1339 | hw_dbg(hw, "ANYSTATE -> DOWN\n"); | ||
1340 | } | ||
1341 | } | ||
1342 | } | ||
1343 | |||
1344 | return ret_val; | ||
1345 | } | ||
1346 | |||
1347 | /** | ||
1218 | * e1000_valid_led_default_82571 - Verify a valid default LED config | 1348 | * e1000_valid_led_default_82571 - Verify a valid default LED config |
1219 | * @hw: pointer to the HW structure | 1349 | * @hw: pointer to the HW structure |
1220 | * @data: pointer to the NVM (EEPROM) | 1350 | * @data: pointer to the NVM (EEPROM) |
diff --git a/drivers/net/e1000e/hw.h b/drivers/net/e1000e/hw.h index 2d4ce0492df0..5cb428c2811d 100644 --- a/drivers/net/e1000e/hw.h +++ b/drivers/net/e1000e/hw.h | |||
@@ -459,6 +459,13 @@ enum e1000_smart_speed { | |||
459 | e1000_smart_speed_off | 459 | e1000_smart_speed_off |
460 | }; | 460 | }; |
461 | 461 | ||
462 | enum e1000_serdes_link_state { | ||
463 | e1000_serdes_link_down = 0, | ||
464 | e1000_serdes_link_autoneg_progress, | ||
465 | e1000_serdes_link_autoneg_complete, | ||
466 | e1000_serdes_link_forced_up | ||
467 | }; | ||
468 | |||
462 | /* Receive Descriptor */ | 469 | /* Receive Descriptor */ |
463 | struct e1000_rx_desc { | 470 | struct e1000_rx_desc { |
464 | __le64 buffer_addr; /* Address of the descriptor's data buffer */ | 471 | __le64 buffer_addr; /* Address of the descriptor's data buffer */ |
@@ -787,6 +794,7 @@ struct e1000_mac_info { | |||
787 | bool in_ifs_mode; | 794 | bool in_ifs_mode; |
788 | bool serdes_has_link; | 795 | bool serdes_has_link; |
789 | bool tx_pkt_filtering; | 796 | bool tx_pkt_filtering; |
797 | enum e1000_serdes_link_state serdes_link_state; | ||
790 | }; | 798 | }; |
791 | 799 | ||
792 | struct e1000_phy_info { | 800 | struct e1000_phy_info { |