Merge branch 'for-rmk/samsung6' of git://git.fluff.org/bjdooks/linux into devel-stable
[linux-2.6.git] / drivers / net / e1000e / phy.c
index 5cd01c6..7f3ceb9 100644 (file)
@@ -44,6 +44,8 @@ static s32 e1000_access_phy_debug_regs_hv(struct e1000_hw *hw, u32 offset,
 /* Cable length tables */
 static const u16 e1000_m88_cable_length_table[] =
        { 0, 50, 80, 110, 140, 140, E1000_CABLE_LENGTH_UNDEFINED };
+#define M88E1000_CABLE_LENGTH_TABLE_SIZE \
+               ARRAY_SIZE(e1000_m88_cable_length_table)
 
 static const u16 e1000_igp_2_cable_length_table[] =
        { 0, 0, 0, 0, 0, 0, 0, 0, 3, 5, 8, 11, 13, 16, 18, 21, 0, 0, 0, 3,
@@ -150,32 +152,9 @@ s32 e1000e_get_phy_id(struct e1000_hw *hw)
                if (phy->id != 0 && phy->id != PHY_REVISION_MASK)
                        goto out;
 
-               /*
-                * If the PHY ID is still unknown, we may have an 82577i
-                * without link.  We will try again after setting Slow
-                * MDIC mode. No harm in trying again in this case since
-                * the PHY ID is unknown at this point anyway
-                */
-               ret_val = phy->ops.acquire(hw);
-               if (ret_val)
-                       goto out;
-               ret_val = e1000_set_mdio_slow_mode_hv(hw, true);
-               if (ret_val)
-                       goto out;
-               phy->ops.release(hw);
-
                retry_count++;
        }
 out:
-       /* Revert to MDIO fast mode, if applicable */
-       if (retry_count) {
-               ret_val = phy->ops.acquire(hw);
-               if (ret_val)
-                       return ret_val;
-               ret_val = e1000_set_mdio_slow_mode_hv(hw, false);
-               phy->ops.release(hw);
-       }
-
        return ret_val;
 }
 
@@ -1320,17 +1299,22 @@ s32 e1000e_phy_force_speed_duplex_m88(struct e1000_hw *hw)
                        return ret_val;
 
                if (!link) {
-                       /*
-                        * We didn't get link.
-                        * Reset the DSP and cross our fingers.
-                        */
-                       ret_val = e1e_wphy(hw, M88E1000_PHY_PAGE_SELECT,
-                                          0x001d);
-                       if (ret_val)
-                               return ret_val;
-                       ret_val = e1000e_phy_reset_dsp(hw);
-                       if (ret_val)
-                               return ret_val;
+                       if (hw->phy.type != e1000_phy_m88) {
+                               e_dbg("Link taking longer than expected.\n");
+                       } else {
+                               /*
+                                * We didn't get link.
+                                * Reset the DSP and cross our fingers.
+                                */
+                               ret_val = e1e_wphy(hw,
+                                               M88E1000_PHY_PAGE_SELECT,
+                                               0x001d);
+                               if (ret_val)
+                                       return ret_val;
+                               ret_val = e1000e_phy_reset_dsp(hw);
+                               if (ret_val)
+                                       return ret_val;
+                       }
                }
 
                /* Try once more */
@@ -1340,6 +1324,9 @@ s32 e1000e_phy_force_speed_duplex_m88(struct e1000_hw *hw)
                        return ret_val;
        }
 
+       if (hw->phy.type != e1000_phy_m88)
+               return 0;
+
        ret_val = e1e_rphy(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data);
        if (ret_val)
                return ret_val;
@@ -1369,6 +1356,73 @@ s32 e1000e_phy_force_speed_duplex_m88(struct e1000_hw *hw)
 }
 
 /**
+ *  e1000_phy_force_speed_duplex_ife - Force PHY speed & duplex
+ *  @hw: pointer to the HW structure
+ *
+ *  Forces the speed and duplex settings of the PHY.
+ *  This is a function pointer entry point only called by
+ *  PHY setup routines.
+ **/
+s32 e1000_phy_force_speed_duplex_ife(struct e1000_hw *hw)
+{
+       struct e1000_phy_info *phy = &hw->phy;
+       s32 ret_val;
+       u16 data;
+       bool link;
+
+       ret_val = e1e_rphy(hw, PHY_CONTROL, &data);
+       if (ret_val)
+               goto out;
+
+       e1000e_phy_force_speed_duplex_setup(hw, &data);
+
+       ret_val = e1e_wphy(hw, PHY_CONTROL, data);
+       if (ret_val)
+               goto out;
+
+       /* Disable MDI-X support for 10/100 */
+       ret_val = e1e_rphy(hw, IFE_PHY_MDIX_CONTROL, &data);
+       if (ret_val)
+               goto out;
+
+       data &= ~IFE_PMC_AUTO_MDIX;
+       data &= ~IFE_PMC_FORCE_MDIX;
+
+       ret_val = e1e_wphy(hw, IFE_PHY_MDIX_CONTROL, data);
+       if (ret_val)
+               goto out;
+
+       e_dbg("IFE PMC: %X\n", data);
+
+       udelay(1);
+
+       if (phy->autoneg_wait_to_complete) {
+               e_dbg("Waiting for forced speed/duplex link on IFE phy.\n");
+
+               ret_val = e1000e_phy_has_link_generic(hw,
+                                                    PHY_FORCE_LIMIT,
+                                                    100000,
+                                                    &link);
+               if (ret_val)
+                       goto out;
+
+               if (!link)
+                       e_dbg("Link taking longer than expected.\n");
+
+               /* Try once more */
+               ret_val = e1000e_phy_has_link_generic(hw,
+                                                    PHY_FORCE_LIMIT,
+                                                    100000,
+                                                    &link);
+               if (ret_val)
+                       goto out;
+       }
+
+out:
+       return ret_val;
+}
+
+/**
  *  e1000e_phy_force_speed_duplex_setup - Configure forced PHY speed/duplex
  *  @hw: pointer to the HW structure
  *  @phy_ctrl: pointer to current value of PHY_CONTROL
@@ -1523,8 +1577,8 @@ s32 e1000e_check_downshift(struct e1000_hw *hw)
        switch (phy->type) {
        case e1000_phy_m88:
        case e1000_phy_gg82563:
+       case e1000_phy_bm:
        case e1000_phy_82578:
-       case e1000_phy_82577:
                offset  = M88E1000_PHY_SPEC_STATUS;
                mask    = M88E1000_PSSR_DOWNSHIFT;
                break;
@@ -1555,7 +1609,7 @@ s32 e1000e_check_downshift(struct e1000_hw *hw)
  *
  *  Polarity is determined based on the PHY specific status register.
  **/
-static s32 e1000_check_polarity_m88(struct e1000_hw *hw)
+s32 e1000_check_polarity_m88(struct e1000_hw *hw)
 {
        struct e1000_phy_info *phy = &hw->phy;
        s32 ret_val;
@@ -1580,7 +1634,7 @@ static s32 e1000_check_polarity_m88(struct e1000_hw *hw)
  *  Polarity is determined based on the PHY port status register, and the
  *  current speed (since there is no polarity at 100Mbps).
  **/
-static s32 e1000_check_polarity_igp(struct e1000_hw *hw)
+s32 e1000_check_polarity_igp(struct e1000_hw *hw)
 {
        struct e1000_phy_info *phy = &hw->phy;
        s32 ret_val;
@@ -1618,6 +1672,39 @@ static s32 e1000_check_polarity_igp(struct e1000_hw *hw)
 }
 
 /**
+ *  e1000_check_polarity_ife - Check cable polarity for IFE PHY
+ *  @hw: pointer to the HW structure
+ *
+ *  Polarity is determined on the polarity reversal feature being enabled.
+ **/
+s32 e1000_check_polarity_ife(struct e1000_hw *hw)
+{
+       struct e1000_phy_info *phy = &hw->phy;
+       s32 ret_val;
+       u16 phy_data, offset, mask;
+
+       /*
+        * Polarity is determined based on the reversal feature being enabled.
+        */
+       if (phy->polarity_correction) {
+               offset = IFE_PHY_EXTENDED_STATUS_CONTROL;
+               mask = IFE_PESC_POLARITY_REVERSED;
+       } else {
+               offset = IFE_PHY_SPECIAL_CONTROL;
+               mask = IFE_PSC_FORCE_POLARITY;
+       }
+
+       ret_val = e1e_rphy(hw, offset, &phy_data);
+
+       if (!ret_val)
+               phy->cable_polarity = (phy_data & mask)
+                                      ? e1000_rev_polarity_reversed
+                                      : e1000_rev_polarity_normal;
+
+       return ret_val;
+}
+
+/**
  *  e1000_wait_autoneg - Wait for auto-neg completion
  *  @hw: pointer to the HW structure
  *
@@ -1717,15 +1804,21 @@ s32 e1000e_get_cable_length_m88(struct e1000_hw *hw)
 
        ret_val = e1e_rphy(hw, M88E1000_PHY_SPEC_STATUS, &phy_data);
        if (ret_val)
-               return ret_val;
+               goto out;
 
        index = (phy_data & M88E1000_PSSR_CABLE_LENGTH) >>
-               M88E1000_PSSR_CABLE_LENGTH_SHIFT;
+               M88E1000_PSSR_CABLE_LENGTH_SHIFT;
+       if (index >= M88E1000_CABLE_LENGTH_TABLE_SIZE - 1) {
+               ret_val = -E1000_ERR_PHY;
+               goto out;
+       }
+
        phy->min_cable_length = e1000_m88_cable_length_table[index];
-       phy->max_cable_length = e1000_m88_cable_length_table[index+1];
+       phy->max_cable_length = e1000_m88_cable_length_table[index + 1];
 
        phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2;
 
+out:
        return ret_val;
 }
 
@@ -1736,7 +1829,7 @@ s32 e1000e_get_cable_length_m88(struct e1000_hw *hw)
  *  The automatic gain control (agc) normalizes the amplitude of the
  *  received signal, adjusting for the attenuation produced by the
  *  cable.  By reading the AGC registers, which represent the
- *  combination of course and fine gain value, the value can be put
+ *  combination of coarse and fine gain value, the value can be put
  *  into a lookup table to obtain the approximate cable length
  *  for each channel.
  **/
@@ -1761,7 +1854,7 @@ s32 e1000e_get_cable_length_igp_2(struct e1000_hw *hw)
 
                /*
                 * Getting bits 15:9, which represent the combination of
-                * course and fine gain values.  The result is a number
+                * coarse and fine gain values.  The result is a number
                 * that can be put into the lookup table to obtain the
                 * approximate cable length.
                 */
@@ -1815,7 +1908,7 @@ s32 e1000e_get_phy_info_m88(struct e1000_hw *hw)
        u16 phy_data;
        bool link;
 
-       if (hw->phy.media_type != e1000_media_type_copper) {
+       if (phy->media_type != e1000_media_type_copper) {
                e_dbg("Phy info is only valid for copper media\n");
                return -E1000_ERR_CONFIG;
        }
@@ -1936,6 +2029,61 @@ s32 e1000e_get_phy_info_igp(struct e1000_hw *hw)
 }
 
 /**
+ *  e1000_get_phy_info_ife - Retrieves various IFE PHY states
+ *  @hw: pointer to the HW structure
+ *
+ *  Populates "phy" structure with various feature states.
+ **/
+s32 e1000_get_phy_info_ife(struct e1000_hw *hw)
+{
+       struct e1000_phy_info *phy = &hw->phy;
+       s32 ret_val;
+       u16 data;
+       bool link;
+
+       ret_val = e1000e_phy_has_link_generic(hw, 1, 0, &link);
+       if (ret_val)
+               goto out;
+
+       if (!link) {
+               e_dbg("Phy info is only valid if link is up\n");
+               ret_val = -E1000_ERR_CONFIG;
+               goto out;
+       }
+
+       ret_val = e1e_rphy(hw, IFE_PHY_SPECIAL_CONTROL, &data);
+       if (ret_val)
+               goto out;
+       phy->polarity_correction = (data & IFE_PSC_AUTO_POLARITY_DISABLE)
+                                  ? false : true;
+
+       if (phy->polarity_correction) {
+               ret_val = e1000_check_polarity_ife(hw);
+               if (ret_val)
+                       goto out;
+       } else {
+               /* Polarity is forced */
+               phy->cable_polarity = (data & IFE_PSC_FORCE_POLARITY)
+                                     ? e1000_rev_polarity_reversed
+                                     : e1000_rev_polarity_normal;
+       }
+
+       ret_val = e1e_rphy(hw, IFE_PHY_MDIX_CONTROL, &data);
+       if (ret_val)
+               goto out;
+
+       phy->is_mdix = (data & IFE_PMC_MDIX_STATUS) ? true : false;
+
+       /* The following parameters are undefined for 10/100 operation. */
+       phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED;
+       phy->local_rx = e1000_1000t_rx_status_undefined;
+       phy->remote_rx = e1000_1000t_rx_status_undefined;
+
+out:
+       return ret_val;
+}
+
+/**
  *  e1000e_phy_sw_reset - PHY software reset
  *  @hw: pointer to the HW structure
  *
@@ -2189,28 +2337,34 @@ enum e1000_phy_type e1000e_get_phy_type_from_id(u32 phy_id)
 s32 e1000e_determine_phy_address(struct e1000_hw *hw)
 {
        s32 ret_val = -E1000_ERR_PHY_TYPE;
-       u32 phy_addr= 0;
-       u32 i = 0;
+       u32 phy_addr = 0;
+       u32 i;
        enum e1000_phy_type phy_type = e1000_phy_unknown;
 
-       do {
-               for (phy_addr = 0; phy_addr < 4; phy_addr++) {
-                       hw->phy.addr = phy_addr;
+       hw->phy.id = phy_type;
+
+       for (phy_addr = 0; phy_addr < E1000_MAX_PHY_ADDR; phy_addr++) {
+               hw->phy.addr = phy_addr;
+               i = 0;
+
+               do {
                        e1000e_get_phy_id(hw);
                        phy_type = e1000e_get_phy_type_from_id(hw->phy.id);
 
-                       /* 
+                       /*
                         * If phy_type is valid, break - we found our
                         * PHY address
                         */
                        if (phy_type  != e1000_phy_unknown) {
                                ret_val = 0;
-                               break;
+                               goto out;
                        }
-               }
-               i++;
-       } while ((ret_val != 0) && (i < 100));
+                       msleep(1);
+                       i++;
+               } while (i < 10);
+       }
 
+out:
        return ret_val;
 }
 
@@ -2464,7 +2618,7 @@ static s32 e1000_access_phy_wakeup_reg_bm(struct e1000_hw *hw, u32 offset,
        /* Gig must be disabled for MDIO accesses to page 800 */
        if ((hw->mac.type == e1000_pchlan) &&
           (!(er32(PHY_CTRL) & E1000_PHY_CTRL_GBE_DISABLE)))
-               e_dbg("Attempting to access page 800 while gig enabled\n");
+               e_dbg("Attempting to access page 800 while gig enabled.\n");
 
        /* All operations in this function are phy address 1 */
        hw->phy.addr = 1;
@@ -2474,20 +2628,26 @@ static s32 e1000_access_phy_wakeup_reg_bm(struct e1000_hw *hw, u32 offset,
                                  (BM_WUC_ENABLE_PAGE << IGP_PAGE_SHIFT));
 
        ret_val = e1000e_read_phy_reg_mdic(hw, BM_WUC_ENABLE_REG, &phy_reg);
-       if (ret_val)
+       if (ret_val) {
+               e_dbg("Could not read PHY page 769\n");
                goto out;
+       }
 
        /* First clear bit 4 to avoid a power state change */
        phy_reg &= ~(BM_WUC_HOST_WU_BIT);
        ret_val = e1000e_write_phy_reg_mdic(hw, BM_WUC_ENABLE_REG, phy_reg);
-       if (ret_val)
+       if (ret_val) {
+               e_dbg("Could not clear PHY page 769 bit 4\n");
                goto out;
+       }
 
        /* Write bit 2 = 1, and clear bit 4 to 769_17 */
        ret_val = e1000e_write_phy_reg_mdic(hw, BM_WUC_ENABLE_REG,
                                            phy_reg | BM_WUC_ENABLE_BIT);
-       if (ret_val)
+       if (ret_val) {
+               e_dbg("Could not write PHY page 769 bit 2\n");
                goto out;
+       }
 
        /* Select page 800 */
        ret_val = e1000e_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT,
@@ -2495,21 +2655,25 @@ static s32 e1000_access_phy_wakeup_reg_bm(struct e1000_hw *hw, u32 offset,
 
        /* Write the page 800 offset value using opcode 0x11 */
        ret_val = e1000e_write_phy_reg_mdic(hw, BM_WUC_ADDRESS_OPCODE, reg);
-       if (ret_val)
+       if (ret_val) {
+               e_dbg("Could not write address opcode to page 800\n");
                goto out;
+       }
 
        if (read) {
                /* Read the page 800 value using opcode 0x12 */
                ret_val = e1000e_read_phy_reg_mdic(hw, BM_WUC_DATA_OPCODE,
                                                   data);
        } else {
-               /* Read the page 800 value using opcode 0x12 */
+               /* Write the page 800 value using opcode 0x12 */
                ret_val = e1000e_write_phy_reg_mdic(hw, BM_WUC_DATA_OPCODE,
                                                    *data);
        }
 
-       if (ret_val)
+       if (ret_val) {
+               e_dbg("Could not access data value from page 800\n");
                goto out;
+       }
 
        /*
         * Restore 769_17.2 to its original value
@@ -2520,12 +2684,53 @@ static s32 e1000_access_phy_wakeup_reg_bm(struct e1000_hw *hw, u32 offset,
 
        /* Clear 769_17.2 */
        ret_val = e1000e_write_phy_reg_mdic(hw, BM_WUC_ENABLE_REG, phy_reg);
+       if (ret_val) {
+               e_dbg("Could not clear PHY page 769 bit 2\n");
+               goto out;
+       }
 
 out:
        return ret_val;
 }
 
 /**
+ * e1000_power_up_phy_copper - Restore copper link in case of PHY power down
+ * @hw: pointer to the HW structure
+ *
+ * In the case of a PHY power down to save power, or to turn off link during a
+ * driver unload, or wake on lan is not enabled, restore the link to previous
+ * settings.
+ **/
+void e1000_power_up_phy_copper(struct e1000_hw *hw)
+{
+       u16 mii_reg = 0;
+
+       /* The PHY will retain its settings across a power down/up cycle */
+       e1e_rphy(hw, PHY_CONTROL, &mii_reg);
+       mii_reg &= ~MII_CR_POWER_DOWN;
+       e1e_wphy(hw, PHY_CONTROL, mii_reg);
+}
+
+/**
+ * e1000_power_down_phy_copper - Restore copper link in case of PHY power down
+ * @hw: pointer to the HW structure
+ *
+ * In the case of a PHY power down to save power, or to turn off link during a
+ * driver unload, or wake on lan is not enabled, restore the link to previous
+ * settings.
+ **/
+void e1000_power_down_phy_copper(struct e1000_hw *hw)
+{
+       u16 mii_reg = 0;
+
+       /* The PHY will retain its settings across a power down/up cycle */
+       e1e_rphy(hw, PHY_CONTROL, &mii_reg);
+       mii_reg |= MII_CR_POWER_DOWN;
+       e1e_wphy(hw, PHY_CONTROL, mii_reg);
+       msleep(1);
+}
+
+/**
  *  e1000e_commit_phy - Soft PHY reset
  *  @hw: pointer to the HW structure
  *
@@ -2563,38 +2768,6 @@ static s32 e1000_set_d0_lplu_state(struct e1000_hw *hw, bool active)
 }
 
 /**
- *  e1000_set_mdio_slow_mode_hv - Set slow MDIO access mode
- *  @hw:   pointer to the HW structure
- *  @slow: true for slow mode, false for normal mode
- *
- *  Assumes semaphore already acquired.
- **/
-s32 e1000_set_mdio_slow_mode_hv(struct e1000_hw *hw, bool slow)
-{
-       s32 ret_val = 0;
-       u16 data = 0;
-
-       /* Set MDIO mode - page 769, register 16: 0x2580==slow, 0x2180==fast */
-       hw->phy.addr = 1;
-       ret_val = e1000e_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT,
-                                        (BM_PORT_CTRL_PAGE << IGP_PAGE_SHIFT));
-       if (ret_val)
-               goto out;
-
-       ret_val = e1000e_write_phy_reg_mdic(hw, BM_CS_CTRL1,
-                                          (0x2180 | (slow << 10)));
-       if (ret_val)
-               goto out;
-
-       /* dummy read when reverting to fast mode - throw away result */
-       if (!slow)
-               ret_val = e1000e_read_phy_reg_mdic(hw, BM_CS_CTRL1, &data);
-
-out:
-       return ret_val;
-}
-
-/**
  *  __e1000_read_phy_reg_hv -  Read HV PHY register
  *  @hw: pointer to the HW structure
  *  @offset: register offset to be read
@@ -2611,7 +2784,6 @@ static s32 __e1000_read_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 *data,
        s32 ret_val;
        u16 page = BM_PHY_REG_PAGE(offset);
        u16 reg = BM_PHY_REG_NUM(offset);
-       bool in_slow_mode = false;
 
        if (!locked) {
                ret_val = hw->phy.ops.acquire(hw);
@@ -2619,16 +2791,6 @@ static s32 __e1000_read_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 *data,
                        return ret_val;
        }
 
-       /* Workaround failure in MDIO access while cable is disconnected */
-       if ((hw->phy.type == e1000_phy_82577) &&
-           !(er32(STATUS) & E1000_STATUS_LU)) {
-               ret_val = e1000_set_mdio_slow_mode_hv(hw, true);
-               if (ret_val)
-                       goto out;
-
-               in_slow_mode = true;
-       }
-
        /* Page 800 works differently than the rest so it has its own func */
        if (page == BM_WUC_PAGE) {
                ret_val = e1000_access_phy_wakeup_reg_bm(hw, offset,
@@ -2665,10 +2827,6 @@ static s32 __e1000_read_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 *data,
        ret_val = e1000e_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & reg,
                                          data);
 out:
-       /* Revert to MDIO fast mode, if applicable */
-       if ((hw->phy.type == e1000_phy_82577) && in_slow_mode)
-               ret_val |= e1000_set_mdio_slow_mode_hv(hw, false);
-
        if (!locked)
                hw->phy.ops.release(hw);
 
@@ -2720,7 +2878,6 @@ static s32 __e1000_write_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 data,
        s32 ret_val;
        u16 page = BM_PHY_REG_PAGE(offset);
        u16 reg = BM_PHY_REG_NUM(offset);
-       bool in_slow_mode = false;
 
        if (!locked) {
                ret_val = hw->phy.ops.acquire(hw);
@@ -2728,16 +2885,6 @@ static s32 __e1000_write_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 data,
                        return ret_val;
        }
 
-       /* Workaround failure in MDIO access while cable is disconnected */
-       if ((hw->phy.type == e1000_phy_82577) &&
-           !(er32(STATUS) & E1000_STATUS_LU)) {
-               ret_val = e1000_set_mdio_slow_mode_hv(hw, true);
-               if (ret_val)
-                       goto out;
-
-               in_slow_mode = true;
-       }
-
        /* Page 800 works differently than the rest so it has its own func */
        if (page == BM_WUC_PAGE) {
                ret_val = e1000_access_phy_wakeup_reg_bm(hw, offset,
@@ -2791,10 +2938,6 @@ static s32 __e1000_write_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 data,
                                          data);
 
 out:
-       /* Revert to MDIO fast mode, if applicable */
-       if ((hw->phy.type == e1000_phy_82577) && in_slow_mode)
-               ret_val |= e1000_set_mdio_slow_mode_hv(hw, false);
-
        if (!locked)
                hw->phy.ops.release(hw);