aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeff Kirsher <jeffrey.t.kirsher@intel.com>2006-01-12 19:50:28 -0500
committerJeff Garzik <jgarzik@pobox.com>2006-01-17 07:40:10 -0500
commit571281972e2ca590ef160dcd6669b9f724b64283 (patch)
treecdb4f140fee6c924257ea52d40c56c031101d018
parent545c67c0a3550545fe50d28c874b0664bc5dc882 (diff)
[PATCH] e1000: Fix SoL/IDER link and loopback
Fix so that if a SoL/IDER session is active, do not allow operations which require a PHY reset and instead log a message. Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com> Signed-off-by: Jesse Brandeburg <jesse.brandeburg@intel.com> Signed-off-by: John Ronciak <john.ronciak@intel.com> Signed-off-by: Jeff Garzik <jgarzik@pobox.com>
-rw-r--r--drivers/net/e1000/e1000_ethtool.c128
-rw-r--r--drivers/net/e1000/e1000_main.c16
-rw-r--r--drivers/net/e1000/e1000_param.c6
3 files changed, 65 insertions, 85 deletions
diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c
index c88f1a3c1b1d..c929277dc276 100644
--- a/drivers/net/e1000/e1000_ethtool.c
+++ b/drivers/net/e1000/e1000_ethtool.c
@@ -183,7 +183,15 @@ e1000_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
183 struct e1000_adapter *adapter = netdev_priv(netdev); 183 struct e1000_adapter *adapter = netdev_priv(netdev);
184 struct e1000_hw *hw = &adapter->hw; 184 struct e1000_hw *hw = &adapter->hw;
185 185
186 if(ecmd->autoneg == AUTONEG_ENABLE) { 186 /* When SoL/IDER sessions are active, autoneg/speed/duplex
187 * cannot be changed */
188 if (e1000_check_phy_reset_block(hw)) {
189 DPRINTK(DRV, ERR, "Cannot change link characteristics "
190 "when SoL/IDER is active.\n");
191 return -EINVAL;
192 }
193
194 if (ecmd->autoneg == AUTONEG_ENABLE) {
187 hw->autoneg = 1; 195 hw->autoneg = 1;
188 if(hw->media_type == e1000_media_type_fiber) 196 if(hw->media_type == e1000_media_type_fiber)
189 hw->autoneg_advertised = ADVERTISED_1000baseT_Full | 197 hw->autoneg_advertised = ADVERTISED_1000baseT_Full |
@@ -562,29 +570,10 @@ e1000_get_drvinfo(struct net_device *netdev,
562 struct ethtool_drvinfo *drvinfo) 570 struct ethtool_drvinfo *drvinfo)
563{ 571{
564 struct e1000_adapter *adapter = netdev_priv(netdev); 572 struct e1000_adapter *adapter = netdev_priv(netdev);
565 char firmware_version[32];
566 uint16_t eeprom_data;
567 573
568 strncpy(drvinfo->driver, e1000_driver_name, 32); 574 strncpy(drvinfo->driver, e1000_driver_name, 32);
569 strncpy(drvinfo->version, e1000_driver_version, 32); 575 strncpy(drvinfo->version, e1000_driver_version, 32);
570 576 strncpy(drvinfo->fw_version, "N/A", 32);
571 /* EEPROM image version # is reported as firware version # for
572 * 8257{1|2|3} controllers */
573 e1000_read_eeprom(&adapter->hw, 5, 1, &eeprom_data);
574 switch (adapter->hw.mac_type) {
575 case e1000_82571:
576 case e1000_82572:
577 case e1000_82573:
578 sprintf(firmware_version, "%d.%d-%d",
579 (eeprom_data & 0xF000) >> 12,
580 (eeprom_data & 0x0FF0) >> 4,
581 eeprom_data & 0x000F);
582 break;
583 default:
584 sprintf(firmware_version, "n/a");
585 }
586
587 strncpy(drvinfo->fw_version, firmware_version, 32);
588 strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32); 577 strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32);
589 drvinfo->n_stats = E1000_STATS_LEN; 578 drvinfo->n_stats = E1000_STATS_LEN;
590 drvinfo->testinfo_len = E1000_TEST_LEN; 579 drvinfo->testinfo_len = E1000_TEST_LEN;
@@ -990,10 +979,8 @@ e1000_free_desc_rings(struct e1000_adapter *adapter)
990 979
991 kfree(txdr->buffer_info); 980 kfree(txdr->buffer_info);
992 txdr->buffer_info = NULL; 981 txdr->buffer_info = NULL;
993
994 kfree(rxdr->buffer_info); 982 kfree(rxdr->buffer_info);
995 rxdr->buffer_info = NULL; 983 rxdr->buffer_info = NULL;
996
997 return; 984 return;
998} 985}
999 986
@@ -1328,32 +1315,21 @@ static int
1328e1000_setup_loopback_test(struct e1000_adapter *adapter) 1315e1000_setup_loopback_test(struct e1000_adapter *adapter)
1329{ 1316{
1330 uint32_t rctl; 1317 uint32_t rctl;
1331 struct e1000_hw *hw = &adapter->hw;
1332 1318
1333 if (hw->media_type == e1000_media_type_fiber || 1319 if(adapter->hw.media_type == e1000_media_type_fiber ||
1334 hw->media_type == e1000_media_type_internal_serdes) { 1320 adapter->hw.media_type == e1000_media_type_internal_serdes) {
1335 switch (hw->mac_type) { 1321 if(adapter->hw.mac_type == e1000_82545 ||
1336 case e1000_82545: 1322 adapter->hw.mac_type == e1000_82546 ||
1337 case e1000_82546: 1323 adapter->hw.mac_type == e1000_82545_rev_3 ||
1338 case e1000_82545_rev_3: 1324 adapter->hw.mac_type == e1000_82546_rev_3)
1339 case e1000_82546_rev_3:
1340 return e1000_set_phy_loopback(adapter); 1325 return e1000_set_phy_loopback(adapter);
1341 break; 1326 else {
1342 case e1000_82571: 1327 rctl = E1000_READ_REG(&adapter->hw, RCTL);
1343 case e1000_82572:
1344#define E1000_SERDES_LB_ON 0x410
1345 e1000_set_phy_loopback(adapter);
1346 E1000_WRITE_REG(hw, SCTL, E1000_SERDES_LB_ON);
1347 msec_delay(10);
1348 return 0;
1349 break;
1350 default:
1351 rctl = E1000_READ_REG(hw, RCTL);
1352 rctl |= E1000_RCTL_LBM_TCVR; 1328 rctl |= E1000_RCTL_LBM_TCVR;
1353 E1000_WRITE_REG(hw, RCTL, rctl); 1329 E1000_WRITE_REG(&adapter->hw, RCTL, rctl);
1354 return 0; 1330 return 0;
1355 } 1331 }
1356 } else if (hw->media_type == e1000_media_type_copper) 1332 } else if(adapter->hw.media_type == e1000_media_type_copper)
1357 return e1000_set_phy_loopback(adapter); 1333 return e1000_set_phy_loopback(adapter);
1358 1334
1359 return 7; 1335 return 7;
@@ -1364,36 +1340,25 @@ e1000_loopback_cleanup(struct e1000_adapter *adapter)
1364{ 1340{
1365 uint32_t rctl; 1341 uint32_t rctl;
1366 uint16_t phy_reg; 1342 uint16_t phy_reg;
1367 struct e1000_hw *hw = &adapter->hw;
1368 1343
1369 rctl = E1000_READ_REG(&adapter->hw, RCTL); 1344 rctl = E1000_READ_REG(&adapter->hw, RCTL);
1370 rctl &= ~(E1000_RCTL_LBM_TCVR | E1000_RCTL_LBM_MAC); 1345 rctl &= ~(E1000_RCTL_LBM_TCVR | E1000_RCTL_LBM_MAC);
1371 E1000_WRITE_REG(&adapter->hw, RCTL, rctl); 1346 E1000_WRITE_REG(&adapter->hw, RCTL, rctl);
1372 1347
1373 switch (hw->mac_type) { 1348 if(adapter->hw.media_type == e1000_media_type_copper ||
1374 case e1000_82571: 1349 ((adapter->hw.media_type == e1000_media_type_fiber ||
1375 case e1000_82572: 1350 adapter->hw.media_type == e1000_media_type_internal_serdes) &&
1376 if (hw->media_type == e1000_media_type_fiber || 1351 (adapter->hw.mac_type == e1000_82545 ||
1377 hw->media_type == e1000_media_type_internal_serdes){ 1352 adapter->hw.mac_type == e1000_82546 ||
1378#define E1000_SERDES_LB_OFF 0x400 1353 adapter->hw.mac_type == e1000_82545_rev_3 ||
1379 E1000_WRITE_REG(hw, SCTL, E1000_SERDES_LB_OFF); 1354 adapter->hw.mac_type == e1000_82546_rev_3))) {
1380 msec_delay(10); 1355 adapter->hw.autoneg = TRUE;
1381 break; 1356 e1000_read_phy_reg(&adapter->hw, PHY_CTRL, &phy_reg);
1382 } 1357 if(phy_reg & MII_CR_LOOPBACK) {
1383 /* fall thru for Cu adapters */
1384 case e1000_82545:
1385 case e1000_82546:
1386 case e1000_82545_rev_3:
1387 case e1000_82546_rev_3:
1388 default:
1389 hw->autoneg = TRUE;
1390 e1000_read_phy_reg(hw, PHY_CTRL, &phy_reg);
1391 if (phy_reg & MII_CR_LOOPBACK) {
1392 phy_reg &= ~MII_CR_LOOPBACK; 1358 phy_reg &= ~MII_CR_LOOPBACK;
1393 e1000_write_phy_reg(hw, PHY_CTRL, phy_reg); 1359 e1000_write_phy_reg(&adapter->hw, PHY_CTRL, phy_reg);
1394 e1000_phy_reset(hw); 1360 e1000_phy_reset(&adapter->hw);
1395 } 1361 }
1396 break;
1397 } 1362 }
1398} 1363}
1399 1364
@@ -1488,14 +1453,25 @@ e1000_run_loopback_test(struct e1000_adapter *adapter)
1488static int 1453static int
1489e1000_loopback_test(struct e1000_adapter *adapter, uint64_t *data) 1454e1000_loopback_test(struct e1000_adapter *adapter, uint64_t *data)
1490{ 1455{
1491 if((*data = e1000_setup_desc_rings(adapter))) goto err_loopback; 1456 /* PHY loopback cannot be performed if SoL/IDER
1492 if((*data = e1000_setup_loopback_test(adapter))) 1457 * sessions are active */
1493 goto err_loopback_setup; 1458 if (e1000_check_phy_reset_block(&adapter->hw)) {
1459 DPRINTK(DRV, ERR, "Cannot do PHY loopback test "
1460 "when SoL/IDER is active.\n");
1461 *data = 0;
1462 goto out;
1463 }
1464
1465 if ((*data = e1000_setup_desc_rings(adapter)))
1466 goto out;
1467 if ((*data = e1000_setup_loopback_test(adapter)))
1468 goto err_loopback;
1494 *data = e1000_run_loopback_test(adapter); 1469 *data = e1000_run_loopback_test(adapter);
1495 e1000_loopback_cleanup(adapter); 1470 e1000_loopback_cleanup(adapter);
1496err_loopback_setup: 1471
1497 e1000_free_desc_rings(adapter);
1498err_loopback: 1472err_loopback:
1473 e1000_free_desc_rings(adapter);
1474out:
1499 return *data; 1475 return *data;
1500} 1476}
1501 1477
@@ -1722,14 +1698,6 @@ e1000_phys_id(struct net_device *netdev, uint32_t data)
1722 msleep_interruptible(data * 1000); 1698 msleep_interruptible(data * 1000);
1723 del_timer_sync(&adapter->blink_timer); 1699 del_timer_sync(&adapter->blink_timer);
1724 } 1700 }
1725 else if(adapter->hw.mac_type < e1000_82573) {
1726 E1000_WRITE_REG(&adapter->hw, LEDCTL, (E1000_LEDCTL_LED2_BLINK_RATE |
1727 E1000_LEDCTL_LED0_BLINK | E1000_LEDCTL_LED2_BLINK |
1728 (E1000_LEDCTL_MODE_LED_ON << E1000_LEDCTL_LED2_MODE_SHIFT) |
1729 (E1000_LEDCTL_MODE_LINK_ACTIVITY << E1000_LEDCTL_LED0_MODE_SHIFT) |
1730 (E1000_LEDCTL_MODE_LED_OFF << E1000_LEDCTL_LED1_MODE_SHIFT)));
1731 msleep_interruptible(data * 1000);
1732 }
1733 else { 1701 else {
1734 E1000_WRITE_REG(&adapter->hw, LEDCTL, (E1000_LEDCTL_LED2_BLINK_RATE | 1702 E1000_WRITE_REG(&adapter->hw, LEDCTL, (E1000_LEDCTL_LED2_BLINK_RATE |
1735 E1000_LEDCTL_LED1_BLINK | E1000_LEDCTL_LED2_BLINK | 1703 E1000_LEDCTL_LED1_BLINK | E1000_LEDCTL_LED2_BLINK |
diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
index 22c8286a4849..66cf1748ba9b 100644
--- a/drivers/net/e1000/e1000_main.c
+++ b/drivers/net/e1000/e1000_main.c
@@ -378,6 +378,8 @@ void
378e1000_down(struct e1000_adapter *adapter) 378e1000_down(struct e1000_adapter *adapter)
379{ 379{
380 struct net_device *netdev = adapter->netdev; 380 struct net_device *netdev = adapter->netdev;
381 boolean_t mng_mode_enabled = (adapter->hw.mac_type >= e1000_82571) &&
382 e1000_check_mng_mode(&adapter->hw);
381 383
382 e1000_irq_disable(adapter); 384 e1000_irq_disable(adapter);
383#ifdef CONFIG_E1000_MQ 385#ifdef CONFIG_E1000_MQ
@@ -405,12 +407,16 @@ e1000_down(struct e1000_adapter *adapter)
405 e1000_clean_all_tx_rings(adapter); 407 e1000_clean_all_tx_rings(adapter);
406 e1000_clean_all_rx_rings(adapter); 408 e1000_clean_all_rx_rings(adapter);
407 409
408 /* If WoL is not enabled and management mode is not IAMT 410 /* Power down the PHY so no link is implied when interface is down *
409 * Power down the PHY so no link is implied when interface is down */ 411 * The PHY cannot be powered down if any of the following is TRUE *
410 if(!adapter->wol && adapter->hw.mac_type >= e1000_82540 && 412 * (a) WoL is enabled
413 * (b) AMT is active
414 * (c) SoL/IDER session is active */
415 if (!adapter->wol && adapter->hw.mac_type >= e1000_82540 &&
411 adapter->hw.media_type == e1000_media_type_copper && 416 adapter->hw.media_type == e1000_media_type_copper &&
412 !e1000_check_mng_mode(&adapter->hw) && 417 !(E1000_READ_REG(&adapter->hw, MANC) & E1000_MANC_SMBUS_EN) &&
413 !(E1000_READ_REG(&adapter->hw, MANC) & E1000_MANC_SMBUS_EN)) { 418 !mng_mode_enabled &&
419 !e1000_check_phy_reset_block(&adapter->hw)) {
414 uint16_t mii_reg; 420 uint16_t mii_reg;
415 e1000_read_phy_reg(&adapter->hw, PHY_CTRL, &mii_reg); 421 e1000_read_phy_reg(&adapter->hw, PHY_CTRL, &mii_reg);
416 mii_reg |= MII_CR_POWER_DOWN; 422 mii_reg |= MII_CR_POWER_DOWN;
diff --git a/drivers/net/e1000/e1000_param.c b/drivers/net/e1000/e1000_param.c
index ccbbe5ad8e0f..852841f12fb9 100644
--- a/drivers/net/e1000/e1000_param.c
+++ b/drivers/net/e1000/e1000_param.c
@@ -584,6 +584,12 @@ e1000_check_copper_options(struct e1000_adapter *adapter)
584 .p = dplx_list }} 584 .p = dplx_list }}
585 }; 585 };
586 586
587 if (e1000_check_phy_reset_block(&adapter->hw)) {
588 DPRINTK(PROBE, INFO,
589 "Link active due to SoL/IDER Session. "
590 "Speed/Duplex/AutoNeg parameter ignored.\n");
591 return;
592 }
587 if (num_Duplex > bd) { 593 if (num_Duplex > bd) {
588 dplx = Duplex[bd]; 594 dplx = Duplex[bd];
589 e1000_validate_option(&dplx, &opt, adapter); 595 e1000_validate_option(&dplx, &opt, adapter);