[PATCH] e1000: Fix SoL/IDER link and loopback
authorJeff Kirsher <jeffrey.t.kirsher@intel.com>
Fri, 13 Jan 2006 00:50:28 +0000 (16:50 -0800)
committerJeff Garzik <jgarzik@pobox.com>
Tue, 17 Jan 2006 12:40:10 +0000 (07:40 -0500)
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>
drivers/net/e1000/e1000_ethtool.c
drivers/net/e1000/e1000_main.c
drivers/net/e1000/e1000_param.c

index c88f1a3..c929277 100644 (file)
@@ -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 | 
index 22c8286..66cf174 100644 (file)
@@ -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;
index ccbbe5a..852841f 100644 (file)
@@ -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);