aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/e1000e
diff options
context:
space:
mode:
authordave graham <david.graham@intel.com>2009-02-10 07:52:28 -0500
committerDavid S. Miller <davem@davemloft.net>2009-02-10 20:00:28 -0500
commitc9523379d6000f379a84b6b970efb8782c128071 (patch)
tree9674789cf9d452391bbafe9cd00bb9734e394554 /drivers/net/e1000e
parent573cca8c6fdbf6bd2dae8f9e9b66931990849c83 (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.c132
-rw-r--r--drivers/net/e1000e/hw.h8
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 @@
61static s32 e1000_get_phy_id_82571(struct e1000_hw *hw); 61static s32 e1000_get_phy_id_82571(struct e1000_hw *hw);
62static s32 e1000_setup_copper_link_82571(struct e1000_hw *hw); 62static s32 e1000_setup_copper_link_82571(struct e1000_hw *hw);
63static s32 e1000_setup_fiber_serdes_link_82571(struct e1000_hw *hw); 63static s32 e1000_setup_fiber_serdes_link_82571(struct e1000_hw *hw);
64static s32 e1000_check_for_serdes_link_82571(struct e1000_hw *hw);
64static s32 e1000_write_nvm_eewr_82571(struct e1000_hw *hw, u16 offset, 65static s32 e1000_write_nvm_eewr_82571(struct e1000_hw *hw, u16 offset,
65 u16 words, u16 *data); 66 u16 words, u16 *data);
66static s32 e1000_fix_nvm_checksum_82571(struct e1000_hw *hw); 67static 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 **/
1229s32 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
462enum 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 */
463struct e1000_rx_desc { 470struct 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
792struct e1000_phy_info { 800struct e1000_phy_info {