ixgbe: add polling test to end of PHY reset
authorEmil Tantilov <emil.s.tantilov@intel.com>
Wed, 16 Feb 2011 01:38:13 +0000 (01:38 +0000)
committerJeff Kirsher <jeffrey.t.kirsher@intel.com>
Thu, 3 Mar 2011 11:05:34 +0000 (03:05 -0800)
Some PHYs require that we poll the reset bit and wait for it to clear
before continuing initialization.  As such we should add this check to the
end of the ixgbe_reset_phy_generic routine.

Signed-off-by: Emil Tantilov <emil.s.tantilov@intel.com>
Tested-by: Stephen Ko <stephen.s.ko@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
drivers/net/ixgbe/ixgbe_phy.c

index f8a60ca8750053bdf1f9d90fa0f8400e6716229e..ebd6e4492a3f04102a75baefe73ced725077171c 100644 (file)
@@ -138,17 +138,51 @@ static enum ixgbe_phy_type ixgbe_get_phy_type_from_id(u32 phy_id)
  **/
 s32 ixgbe_reset_phy_generic(struct ixgbe_hw *hw)
 {
+       u32 i;
+       u16 ctrl = 0;
+       s32 status = 0;
+
+       if (hw->phy.type == ixgbe_phy_unknown)
+               status = ixgbe_identify_phy_generic(hw);
+
+       if (status != 0 || hw->phy.type == ixgbe_phy_none)
+               goto out;
+
        /* Don't reset PHY if it's shut down due to overtemp. */
        if (!hw->phy.reset_if_overtemp &&
            (IXGBE_ERR_OVERTEMP == hw->phy.ops.check_overtemp(hw)))
-               return 0;
+               goto out;
 
        /*
         * Perform soft PHY reset to the PHY_XS.
         * This will cause a soft reset to the PHY
         */
-       return hw->phy.ops.write_reg(hw, MDIO_CTRL1, MDIO_MMD_PHYXS,
-                                    MDIO_CTRL1_RESET);
+       hw->phy.ops.write_reg(hw, MDIO_CTRL1,
+                             MDIO_MMD_PHYXS,
+                             MDIO_CTRL1_RESET);
+
+       /*
+        * Poll for reset bit to self-clear indicating reset is complete.
+        * Some PHYs could take up to 3 seconds to complete and need about
+        * 1.7 usec delay after the reset is complete.
+        */
+       for (i = 0; i < 30; i++) {
+               msleep(100);
+               hw->phy.ops.read_reg(hw, MDIO_CTRL1,
+                                    MDIO_MMD_PHYXS, &ctrl);
+               if (!(ctrl & MDIO_CTRL1_RESET)) {
+                       udelay(2);
+                       break;
+               }
+       }
+
+       if (ctrl & MDIO_CTRL1_RESET) {
+               status = IXGBE_ERR_RESET_FAILED;
+               hw_dbg(hw, "PHY reset polling failed to complete.\n");
+       }
+
+out:
+       return status;
 }
 
 /**