aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/e1000e/phy.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/e1000e/phy.c')
-rw-r--r--drivers/net/e1000e/phy.c374
1 files changed, 295 insertions, 79 deletions
diff --git a/drivers/net/e1000e/phy.c b/drivers/net/e1000e/phy.c
index 99d53fa..55a2c0a 100644
--- a/drivers/net/e1000e/phy.c
+++ b/drivers/net/e1000e/phy.c
@@ -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,
@@ -71,7 +73,6 @@ static const u16 e1000_igp_2_cable_length_table[] =
#define I82577_CFG_ASSERT_CRS_ON_TX (1 << 15)
#define I82577_CFG_ENABLE_DOWNSHIFT (3 << 10) /* auto downshift 100/10 */
#define I82577_CTRL_REG 23
-#define I82577_CTRL_DOWNSHIFT_MASK (7 << 10)
/* 82577 specific PHY registers */
#define I82577_PHY_CTRL_2 18
@@ -152,10 +153,10 @@ s32 e1000e_get_phy_id(struct e1000_hw *hw)
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
+ * If the PHY ID is still unknown, we may have an 82577
+ * 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)
@@ -660,15 +661,6 @@ s32 e1000_copper_link_setup_82577(struct e1000_hw *hw)
phy_data |= I82577_CFG_ENABLE_DOWNSHIFT;
ret_val = phy->ops.write_reg(hw, I82577_CFG_REG, phy_data);
- if (ret_val)
- goto out;
-
- /* Set number of link attempts before downshift */
- ret_val = phy->ops.read_reg(hw, I82577_CTRL_REG, &phy_data);
- if (ret_val)
- goto out;
- phy_data &= ~I82577_CTRL_DOWNSHIFT_MASK;
- ret_val = phy->ops.write_reg(hw, I82577_CTRL_REG, phy_data);
out:
return ret_val;
@@ -1330,17 +1322,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 */
@@ -1350,6 +1347,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;
@@ -1379,6 +1379,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
@@ -1533,8 +1600,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;
@@ -1565,7 +1632,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;
@@ -1590,7 +1657,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;
@@ -1628,6 +1695,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
*
@@ -1727,15 +1827,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;
}
@@ -1746,7 +1852,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.
**/
@@ -1771,7 +1877,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.
*/
@@ -1825,7 +1931,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;
}
@@ -1946,6 +2052,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
*
@@ -2199,28 +2360,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;
}
@@ -2474,7 +2641,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;
@@ -2484,20 +2651,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,
@@ -2505,21 +2678,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
@@ -2530,12 +2707,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
*
@@ -2658,19 +2876,18 @@ static s32 __e1000_read_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 *data,
page = 0;
if (reg > MAX_PHY_MULTI_PAGE_REG) {
- if ((hw->phy.type != e1000_phy_82578) ||
- ((reg != I82578_ADDR_REG) &&
- (reg != I82578_ADDR_REG + 1))) {
- u32 phy_addr = hw->phy.addr;
-
- hw->phy.addr = 1;
-
- /* Page is shifted left, PHY expects (page x 32) */
- ret_val = e1000e_write_phy_reg_mdic(hw,
- IGP01E1000_PHY_PAGE_SELECT,
- (page << IGP_PAGE_SHIFT));
- hw->phy.addr = phy_addr;
- }
+ u32 phy_addr = hw->phy.addr;
+
+ hw->phy.addr = 1;
+
+ /* Page is shifted left, PHY expects (page x 32) */
+ ret_val = e1000e_write_phy_reg_mdic(hw,
+ IGP01E1000_PHY_PAGE_SELECT,
+ (page << IGP_PAGE_SHIFT));
+ hw->phy.addr = phy_addr;
+
+ if (ret_val)
+ goto out;
}
ret_val = e1000e_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & reg,
@@ -2678,7 +2895,7 @@ static s32 __e1000_read_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 *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);
+ ret_val |= e1000_set_mdio_slow_mode_hv(hw, false);
if (!locked)
hw->phy.ops.release(hw);
@@ -2784,19 +3001,18 @@ static s32 __e1000_write_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 data,
}
if (reg > MAX_PHY_MULTI_PAGE_REG) {
- if ((hw->phy.type != e1000_phy_82578) ||
- ((reg != I82578_ADDR_REG) &&
- (reg != I82578_ADDR_REG + 1))) {
- u32 phy_addr = hw->phy.addr;
-
- hw->phy.addr = 1;
-
- /* Page is shifted left, PHY expects (page x 32) */
- ret_val = e1000e_write_phy_reg_mdic(hw,
- IGP01E1000_PHY_PAGE_SELECT,
- (page << IGP_PAGE_SHIFT));
- hw->phy.addr = phy_addr;
- }
+ u32 phy_addr = hw->phy.addr;
+
+ hw->phy.addr = 1;
+
+ /* Page is shifted left, PHY expects (page x 32) */
+ ret_val = e1000e_write_phy_reg_mdic(hw,
+ IGP01E1000_PHY_PAGE_SELECT,
+ (page << IGP_PAGE_SHIFT));
+ hw->phy.addr = phy_addr;
+
+ if (ret_val)
+ goto out;
}
ret_val = e1000e_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & reg,
@@ -2805,7 +3021,7 @@ static s32 __e1000_write_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 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);
+ ret_val |= e1000_set_mdio_slow_mode_hv(hw, false);
if (!locked)
hw->phy.ops.release(hw);