diff options
author | Jeff Kirsher <jeffrey.t.kirsher@intel.com> | 2006-01-12 19:50:28 -0500 |
---|---|---|
committer | Jeff Garzik <jgarzik@pobox.com> | 2006-01-17 07:40:10 -0500 |
commit | 571281972e2ca590ef160dcd6669b9f724b64283 (patch) | |
tree | cdb4f140fee6c924257ea52d40c56c031101d018 | |
parent | 545c67c0a3550545fe50d28c874b0664bc5dc882 (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.c | 128 | ||||
-rw-r--r-- | drivers/net/e1000/e1000_main.c | 16 | ||||
-rw-r--r-- | drivers/net/e1000/e1000_param.c | 6 |
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 | |||
1328 | e1000_setup_loopback_test(struct e1000_adapter *adapter) | 1315 | e1000_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) | |||
1488 | static int | 1453 | static int |
1489 | e1000_loopback_test(struct e1000_adapter *adapter, uint64_t *data) | 1454 | e1000_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); |
1496 | err_loopback_setup: | 1471 | |
1497 | e1000_free_desc_rings(adapter); | ||
1498 | err_loopback: | 1472 | err_loopback: |
1473 | e1000_free_desc_rings(adapter); | ||
1474 | out: | ||
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 | |||
378 | e1000_down(struct e1000_adapter *adapter) | 378 | e1000_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); |