diff options
author | Jeff Kirsher <jeffrey.t.kirsher@intel.com> | 2006-01-12 16:50:28 -0800 |
---|---|---|
committer | Jeff Garzik <jgarzik@pobox.com> | 2006-01-17 07:40:10 -0500 |
commit | 571281972e2ca590ef160dcd6669b9f724b64283 (patch) | |
tree | cdb4f140fee6c924257ea52d40c56c031101d018 | |
parent | 545c67c0a3550545fe50d28c874b0664bc5dc882 (diff) | |
download | op-kernel-dev-571281972e2ca590ef160dcd6669b9f724b64283.zip op-kernel-dev-571281972e2ca590ef160dcd6669b9f724b64283.tar.gz |
[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 c88f1a3..c929277 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) struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; - if(ecmd->autoneg == AUTONEG_ENABLE) { + /* When SoL/IDER sessions are active, autoneg/speed/duplex + * cannot be changed */ + if (e1000_check_phy_reset_block(hw)) { + DPRINTK(DRV, ERR, "Cannot change link characteristics " + "when SoL/IDER is active.\n"); + return -EINVAL; + } + + if (ecmd->autoneg == AUTONEG_ENABLE) { hw->autoneg = 1; if(hw->media_type == e1000_media_type_fiber) hw->autoneg_advertised = ADVERTISED_1000baseT_Full | @@ -562,29 +570,10 @@ e1000_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo) { struct e1000_adapter *adapter = netdev_priv(netdev); - char firmware_version[32]; - uint16_t eeprom_data; strncpy(drvinfo->driver, e1000_driver_name, 32); strncpy(drvinfo->version, e1000_driver_version, 32); - - /* EEPROM image version # is reported as firware version # for - * 8257{1|2|3} controllers */ - e1000_read_eeprom(&adapter->hw, 5, 1, &eeprom_data); - switch (adapter->hw.mac_type) { - case e1000_82571: - case e1000_82572: - case e1000_82573: - sprintf(firmware_version, "%d.%d-%d", - (eeprom_data & 0xF000) >> 12, - (eeprom_data & 0x0FF0) >> 4, - eeprom_data & 0x000F); - break; - default: - sprintf(firmware_version, "n/a"); - } - - strncpy(drvinfo->fw_version, firmware_version, 32); + strncpy(drvinfo->fw_version, "N/A", 32); strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32); drvinfo->n_stats = E1000_STATS_LEN; drvinfo->testinfo_len = E1000_TEST_LEN; @@ -990,10 +979,8 @@ e1000_free_desc_rings(struct e1000_adapter *adapter) kfree(txdr->buffer_info); txdr->buffer_info = NULL; - kfree(rxdr->buffer_info); rxdr->buffer_info = NULL; - return; } @@ -1328,32 +1315,21 @@ static int e1000_setup_loopback_test(struct e1000_adapter *adapter) { uint32_t rctl; - struct e1000_hw *hw = &adapter->hw; - if (hw->media_type == e1000_media_type_fiber || - hw->media_type == e1000_media_type_internal_serdes) { - switch (hw->mac_type) { - case e1000_82545: - case e1000_82546: - case e1000_82545_rev_3: - case e1000_82546_rev_3: + if(adapter->hw.media_type == e1000_media_type_fiber || + adapter->hw.media_type == e1000_media_type_internal_serdes) { + if(adapter->hw.mac_type == e1000_82545 || + adapter->hw.mac_type == e1000_82546 || + adapter->hw.mac_type == e1000_82545_rev_3 || + adapter->hw.mac_type == e1000_82546_rev_3) return e1000_set_phy_loopback(adapter); - break; - case e1000_82571: - case e1000_82572: -#define E1000_SERDES_LB_ON 0x410 - e1000_set_phy_loopback(adapter); - E1000_WRITE_REG(hw, SCTL, E1000_SERDES_LB_ON); - msec_delay(10); - return 0; - break; - default: - rctl = E1000_READ_REG(hw, RCTL); + else { + rctl = E1000_READ_REG(&adapter->hw, RCTL); rctl |= E1000_RCTL_LBM_TCVR; - E1000_WRITE_REG(hw, RCTL, rctl); + E1000_WRITE_REG(&adapter->hw, RCTL, rctl); return 0; } - } else if (hw->media_type == e1000_media_type_copper) + } else if(adapter->hw.media_type == e1000_media_type_copper) return e1000_set_phy_loopback(adapter); return 7; @@ -1364,36 +1340,25 @@ e1000_loopback_cleanup(struct e1000_adapter *adapter) { uint32_t rctl; uint16_t phy_reg; - struct e1000_hw *hw = &adapter->hw; rctl = E1000_READ_REG(&adapter->hw, RCTL); rctl &= ~(E1000_RCTL_LBM_TCVR | E1000_RCTL_LBM_MAC); E1000_WRITE_REG(&adapter->hw, RCTL, rctl); - switch (hw->mac_type) { - case e1000_82571: - case e1000_82572: - if (hw->media_type == e1000_media_type_fiber || - hw->media_type == e1000_media_type_internal_serdes){ -#define E1000_SERDES_LB_OFF 0x400 - E1000_WRITE_REG(hw, SCTL, E1000_SERDES_LB_OFF); - msec_delay(10); - break; - } - /* fall thru for Cu adapters */ - case e1000_82545: - case e1000_82546: - case e1000_82545_rev_3: - case e1000_82546_rev_3: - default: - hw->autoneg = TRUE; - e1000_read_phy_reg(hw, PHY_CTRL, &phy_reg); - if (phy_reg & MII_CR_LOOPBACK) { + if(adapter->hw.media_type == e1000_media_type_copper || + ((adapter->hw.media_type == e1000_media_type_fiber || + adapter->hw.media_type == e1000_media_type_internal_serdes) && + (adapter->hw.mac_type == e1000_82545 || + adapter->hw.mac_type == e1000_82546 || + adapter->hw.mac_type == e1000_82545_rev_3 || + adapter->hw.mac_type == e1000_82546_rev_3))) { + adapter->hw.autoneg = TRUE; + e1000_read_phy_reg(&adapter->hw, PHY_CTRL, &phy_reg); + if(phy_reg & MII_CR_LOOPBACK) { phy_reg &= ~MII_CR_LOOPBACK; - e1000_write_phy_reg(hw, PHY_CTRL, phy_reg); - e1000_phy_reset(hw); + e1000_write_phy_reg(&adapter->hw, PHY_CTRL, phy_reg); + e1000_phy_reset(&adapter->hw); } - break; } } @@ -1488,14 +1453,25 @@ e1000_run_loopback_test(struct e1000_adapter *adapter) static int e1000_loopback_test(struct e1000_adapter *adapter, uint64_t *data) { - if((*data = e1000_setup_desc_rings(adapter))) goto err_loopback; - if((*data = e1000_setup_loopback_test(adapter))) - goto err_loopback_setup; + /* PHY loopback cannot be performed if SoL/IDER + * sessions are active */ + if (e1000_check_phy_reset_block(&adapter->hw)) { + DPRINTK(DRV, ERR, "Cannot do PHY loopback test " + "when SoL/IDER is active.\n"); + *data = 0; + goto out; + } + + if ((*data = e1000_setup_desc_rings(adapter))) + goto out; + if ((*data = e1000_setup_loopback_test(adapter))) + goto err_loopback; *data = e1000_run_loopback_test(adapter); e1000_loopback_cleanup(adapter); -err_loopback_setup: - e1000_free_desc_rings(adapter); + err_loopback: + e1000_free_desc_rings(adapter); +out: return *data; } @@ -1722,14 +1698,6 @@ e1000_phys_id(struct net_device *netdev, uint32_t data) msleep_interruptible(data * 1000); del_timer_sync(&adapter->blink_timer); } - else if(adapter->hw.mac_type < e1000_82573) { - E1000_WRITE_REG(&adapter->hw, LEDCTL, (E1000_LEDCTL_LED2_BLINK_RATE | - E1000_LEDCTL_LED0_BLINK | E1000_LEDCTL_LED2_BLINK | - (E1000_LEDCTL_MODE_LED_ON << E1000_LEDCTL_LED2_MODE_SHIFT) | - (E1000_LEDCTL_MODE_LINK_ACTIVITY << E1000_LEDCTL_LED0_MODE_SHIFT) | - (E1000_LEDCTL_MODE_LED_OFF << E1000_LEDCTL_LED1_MODE_SHIFT))); - msleep_interruptible(data * 1000); - } else { E1000_WRITE_REG(&adapter->hw, LEDCTL, (E1000_LEDCTL_LED2_BLINK_RATE | 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 22c8286..66cf174 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -378,6 +378,8 @@ void e1000_down(struct e1000_adapter *adapter) { struct net_device *netdev = adapter->netdev; + boolean_t mng_mode_enabled = (adapter->hw.mac_type >= e1000_82571) && + e1000_check_mng_mode(&adapter->hw); e1000_irq_disable(adapter); #ifdef CONFIG_E1000_MQ @@ -405,12 +407,16 @@ e1000_down(struct e1000_adapter *adapter) e1000_clean_all_tx_rings(adapter); e1000_clean_all_rx_rings(adapter); - /* If WoL is not enabled and management mode is not IAMT - * Power down the PHY so no link is implied when interface is down */ - if(!adapter->wol && adapter->hw.mac_type >= e1000_82540 && + /* Power down the PHY so no link is implied when interface is down * + * The PHY cannot be powered down if any of the following is TRUE * + * (a) WoL is enabled + * (b) AMT is active + * (c) SoL/IDER session is active */ + if (!adapter->wol && adapter->hw.mac_type >= e1000_82540 && adapter->hw.media_type == e1000_media_type_copper && - !e1000_check_mng_mode(&adapter->hw) && - !(E1000_READ_REG(&adapter->hw, MANC) & E1000_MANC_SMBUS_EN)) { + !(E1000_READ_REG(&adapter->hw, MANC) & E1000_MANC_SMBUS_EN) && + !mng_mode_enabled && + !e1000_check_phy_reset_block(&adapter->hw)) { uint16_t mii_reg; e1000_read_phy_reg(&adapter->hw, PHY_CTRL, &mii_reg); mii_reg |= MII_CR_POWER_DOWN; diff --git a/drivers/net/e1000/e1000_param.c b/drivers/net/e1000/e1000_param.c index ccbbe5a..852841f 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) .p = dplx_list }} }; + if (e1000_check_phy_reset_block(&adapter->hw)) { + DPRINTK(PROBE, INFO, + "Link active due to SoL/IDER Session. " + "Speed/Duplex/AutoNeg parameter ignored.\n"); + return; + } if (num_Duplex > bd) { dplx = Duplex[bd]; e1000_validate_option(&dplx, &opt, adapter); |