Skip to content

Commit

Permalink
e1000e: Fix HW Error on es2lan, ARP capture issue by BMC
Browse files Browse the repository at this point in the history
Several components to this complex fix. The es2lan cards occasionally
gave a "HW Error" especially when forcing speed. Some users also
reported that the BMC stole ARP packets.

The fixes include setting the proper SW_FW bits to tell the BMC
that we're active and not do any un-initialization at all, so the
setup routine is largely changed.

Signed-off-by: David Graham <david.graham@intel.com>
Signed-off-by: Auke Kok <auke-jan.h.kok@intel.com>
Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
  • Loading branch information
David Graham authored and Jeff Garzik committed Apr 25, 2008
1 parent de5b307 commit 2d9498f
Show file tree
Hide file tree
Showing 4 changed files with 137 additions and 66 deletions.
1 change: 1 addition & 0 deletions drivers/net/e1000e/defines.h
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@
#define E1000_SWFW_EEP_SM 0x1
#define E1000_SWFW_PHY0_SM 0x2
#define E1000_SWFW_PHY1_SM 0x4
#define E1000_SWFW_CSR_SM 0x8

/* Device Control */
#define E1000_CTRL_FD 0x00000001 /* Full duplex.0=half; 1=full */
Expand Down
2 changes: 2 additions & 0 deletions drivers/net/e1000e/e1000.h
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,8 @@ extern s32 e1000e_read_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 *data);
extern s32 e1000e_phy_has_link_generic(struct e1000_hw *hw, u32 iterations,
u32 usec_interval, bool *success);
extern s32 e1000e_phy_reset_dsp(struct e1000_hw *hw);
extern s32 e1000e_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data);
extern s32 e1000e_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data);
extern s32 e1000e_check_downshift(struct e1000_hw *hw);

static inline s32 e1000_phy_hw_reset(struct e1000_hw *hw)
Expand Down
127 changes: 94 additions & 33 deletions drivers/net/e1000e/es2lan.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,15 @@
#define E1000_KMRNCTRLSTA_OFFSET_FIFO_CTRL 0x00
#define E1000_KMRNCTRLSTA_OFFSET_INB_CTRL 0x02
#define E1000_KMRNCTRLSTA_OFFSET_HD_CTRL 0x10
#define E1000_KMRNCTRLSTA_OFFSET_MAC2PHY_OPMODE 0x1F

#define E1000_KMRNCTRLSTA_FIFO_CTRL_RX_BYPASS 0x0008
#define E1000_KMRNCTRLSTA_FIFO_CTRL_TX_BYPASS 0x0800
#define E1000_KMRNCTRLSTA_INB_CTRL_DIS_PADDING 0x0010

#define E1000_KMRNCTRLSTA_HD_CTRL_10_100_DEFAULT 0x0004
#define E1000_KMRNCTRLSTA_HD_CTRL_1000_DEFAULT 0x0000
#define E1000_KMRNCTRLSTA_OPMODE_E_IDLE 0x2000

#define E1000_TCTL_EXT_GCEX_MASK 0x000FFC00 /* Gigabit Carry Extend Padding */
#define DEFAULT_TCTL_EXT_GCEX_80003ES2LAN 0x00010000
Expand Down Expand Up @@ -85,6 +87,9 @@
/* Kumeran Mode Control Register (Page 193, Register 16) */
#define GG82563_KMCR_PASS_FALSE_CARRIER 0x0800

/* Max number of times Kumeran read/write should be validated */
#define GG82563_MAX_KMRN_RETRY 0x5

/* Power Management Control Register (Page 193, Register 20) */
#define GG82563_PMCR_ENABLE_ELECTRICAL_IDLE 0x0001
/* 1=Enable SERDES Electrical Idle */
Expand Down Expand Up @@ -270,6 +275,7 @@ static s32 e1000_acquire_phy_80003es2lan(struct e1000_hw *hw)
u16 mask;

mask = hw->bus.func ? E1000_SWFW_PHY1_SM : E1000_SWFW_PHY0_SM;
mask |= E1000_SWFW_CSR_SM;

return e1000_acquire_swfw_sync_80003es2lan(hw, mask);
}
Expand All @@ -286,6 +292,8 @@ static void e1000_release_phy_80003es2lan(struct e1000_hw *hw)
u16 mask;

mask = hw->bus.func ? E1000_SWFW_PHY1_SM : E1000_SWFW_PHY0_SM;
mask |= E1000_SWFW_CSR_SM;

e1000_release_swfw_sync_80003es2lan(hw, mask);
}

Expand Down Expand Up @@ -410,20 +418,27 @@ static s32 e1000_read_phy_reg_gg82563_80003es2lan(struct e1000_hw *hw,
u32 page_select;
u16 temp;

ret_val = e1000_acquire_phy_80003es2lan(hw);
if (ret_val)
return ret_val;

/* Select Configuration Page */
if ((offset & MAX_PHY_REG_ADDRESS) < GG82563_MIN_ALT_REG)
if ((offset & MAX_PHY_REG_ADDRESS) < GG82563_MIN_ALT_REG) {
page_select = GG82563_PHY_PAGE_SELECT;
else
} else {
/*
* Use Alternative Page Select register to access
* registers 30 and 31
*/
page_select = GG82563_PHY_PAGE_SELECT_ALT;
}

temp = (u16)((u16)offset >> GG82563_PAGE_SHIFT);
ret_val = e1000e_write_phy_reg_m88(hw, page_select, temp);
if (ret_val)
ret_val = e1000e_write_phy_reg_mdic(hw, page_select, temp);
if (ret_val) {
e1000_release_phy_80003es2lan(hw);
return ret_val;
}

/*
* The "ready" bit in the MDIC register may be incorrectly set
Expand All @@ -433,20 +448,21 @@ static s32 e1000_read_phy_reg_gg82563_80003es2lan(struct e1000_hw *hw,
udelay(200);

/* ...and verify the command was successful. */
ret_val = e1000e_read_phy_reg_m88(hw, page_select, &temp);
ret_val = e1000e_read_phy_reg_mdic(hw, page_select, &temp);

if (((u16)offset >> GG82563_PAGE_SHIFT) != temp) {
ret_val = -E1000_ERR_PHY;
e1000_release_phy_80003es2lan(hw);
return ret_val;
}

udelay(200);

ret_val = e1000e_read_phy_reg_m88(hw,
MAX_PHY_REG_ADDRESS & offset,
data);
ret_val = e1000e_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
data);

udelay(200);
e1000_release_phy_80003es2lan(hw);

return ret_val;
}
Expand All @@ -467,20 +483,27 @@ static s32 e1000_write_phy_reg_gg82563_80003es2lan(struct e1000_hw *hw,
u32 page_select;
u16 temp;

ret_val = e1000_acquire_phy_80003es2lan(hw);
if (ret_val)
return ret_val;

/* Select Configuration Page */
if ((offset & MAX_PHY_REG_ADDRESS) < GG82563_MIN_ALT_REG)
if ((offset & MAX_PHY_REG_ADDRESS) < GG82563_MIN_ALT_REG) {
page_select = GG82563_PHY_PAGE_SELECT;
else
} else {
/*
* Use Alternative Page Select register to access
* registers 30 and 31
*/
page_select = GG82563_PHY_PAGE_SELECT_ALT;
}

temp = (u16)((u16)offset >> GG82563_PAGE_SHIFT);
ret_val = e1000e_write_phy_reg_m88(hw, page_select, temp);
if (ret_val)
ret_val = e1000e_write_phy_reg_mdic(hw, page_select, temp);
if (ret_val) {
e1000_release_phy_80003es2lan(hw);
return ret_val;
}


/*
Expand All @@ -491,18 +514,20 @@ static s32 e1000_write_phy_reg_gg82563_80003es2lan(struct e1000_hw *hw,
udelay(200);

/* ...and verify the command was successful. */
ret_val = e1000e_read_phy_reg_m88(hw, page_select, &temp);
ret_val = e1000e_read_phy_reg_mdic(hw, page_select, &temp);

if (((u16)offset >> GG82563_PAGE_SHIFT) != temp)
if (((u16)offset >> GG82563_PAGE_SHIFT) != temp) {
e1000_release_phy_80003es2lan(hw);
return -E1000_ERR_PHY;
}

udelay(200);

ret_val = e1000e_write_phy_reg_m88(hw,
MAX_PHY_REG_ADDRESS & offset,
data);
ret_val = e1000e_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
data);

udelay(200);
e1000_release_phy_80003es2lan(hw);

return ret_val;
}
Expand Down Expand Up @@ -882,19 +907,18 @@ static s32 e1000_copper_link_setup_gg82563_80003es2lan(struct e1000_hw *hw)
struct e1000_phy_info *phy = &hw->phy;
s32 ret_val;
u32 ctrl_ext;
u16 data;
u32 i = 0;
u16 data, data2;

ret_val = e1e_rphy(hw, GG82563_PHY_MAC_SPEC_CTRL,
&data);
ret_val = e1e_rphy(hw, GG82563_PHY_MAC_SPEC_CTRL, &data);
if (ret_val)
return ret_val;

data |= GG82563_MSCR_ASSERT_CRS_ON_TX;
/* Use 25MHz for both link down and 1000Base-T for Tx clock. */
data |= GG82563_MSCR_TX_CLK_1000MBPS_25;

ret_val = e1e_wphy(hw, GG82563_PHY_MAC_SPEC_CTRL,
data);
ret_val = e1e_wphy(hw, GG82563_PHY_MAC_SPEC_CTRL, data);
if (ret_val)
return ret_val;

Expand Down Expand Up @@ -954,6 +978,18 @@ static s32 e1000_copper_link_setup_gg82563_80003es2lan(struct e1000_hw *hw)
if (ret_val)
return ret_val;

ret_val = e1000e_read_kmrn_reg(hw,
E1000_KMRNCTRLSTA_OFFSET_MAC2PHY_OPMODE,
&data);
if (ret_val)
return ret_val;
data |= E1000_KMRNCTRLSTA_OPMODE_E_IDLE;
ret_val = e1000e_write_kmrn_reg(hw,
E1000_KMRNCTRLSTA_OFFSET_MAC2PHY_OPMODE,
data);
if (ret_val)
return ret_val;

ret_val = e1e_rphy(hw, GG82563_PHY_SPEC_CTRL_2, &data);
if (ret_val)
return ret_val;
Expand Down Expand Up @@ -983,9 +1019,18 @@ static s32 e1000_copper_link_setup_gg82563_80003es2lan(struct e1000_hw *hw)
if (ret_val)
return ret_val;

ret_val = e1e_rphy(hw, GG82563_PHY_KMRN_MODE_CTRL, &data);
if (ret_val)
return ret_val;
do {
ret_val = e1e_rphy(hw, GG82563_PHY_KMRN_MODE_CTRL,
&data);
if (ret_val)
return ret_val;

ret_val = e1e_rphy(hw, GG82563_PHY_KMRN_MODE_CTRL,
&data2);
if (ret_val)
return ret_val;
i++;
} while ((data != data2) && (i < GG82563_MAX_KMRN_RETRY));

data &= ~GG82563_KMCR_PASS_FALSE_CARRIER;
ret_val = e1e_wphy(hw, GG82563_PHY_KMRN_MODE_CTRL, data);
Expand Down Expand Up @@ -1074,7 +1119,8 @@ static s32 e1000_cfg_kmrn_10_100_80003es2lan(struct e1000_hw *hw, u16 duplex)
{
s32 ret_val;
u32 tipg;
u16 reg_data;
u32 i = 0;
u16 reg_data, reg_data2;

reg_data = E1000_KMRNCTRLSTA_HD_CTRL_10_100_DEFAULT;
ret_val = e1000e_write_kmrn_reg(hw, E1000_KMRNCTRLSTA_OFFSET_HD_CTRL,
Expand All @@ -1088,9 +1134,16 @@ static s32 e1000_cfg_kmrn_10_100_80003es2lan(struct e1000_hw *hw, u16 duplex)
tipg |= DEFAULT_TIPG_IPGT_10_100_80003ES2LAN;
ew32(TIPG, tipg);

ret_val = e1e_rphy(hw, GG82563_PHY_KMRN_MODE_CTRL, &reg_data);
if (ret_val)
return ret_val;
do {
ret_val = e1e_rphy(hw, GG82563_PHY_KMRN_MODE_CTRL, &reg_data);
if (ret_val)
return ret_val;

ret_val = e1e_rphy(hw, GG82563_PHY_KMRN_MODE_CTRL, &reg_data2);
if (ret_val)
return ret_val;
i++;
} while ((reg_data != reg_data2) && (i < GG82563_MAX_KMRN_RETRY));

if (duplex == HALF_DUPLEX)
reg_data |= GG82563_KMCR_PASS_FALSE_CARRIER;
Expand All @@ -1112,8 +1165,9 @@ static s32 e1000_cfg_kmrn_10_100_80003es2lan(struct e1000_hw *hw, u16 duplex)
static s32 e1000_cfg_kmrn_1000_80003es2lan(struct e1000_hw *hw)
{
s32 ret_val;
u16 reg_data;
u16 reg_data, reg_data2;
u32 tipg;
u32 i = 0;

reg_data = E1000_KMRNCTRLSTA_HD_CTRL_1000_DEFAULT;
ret_val = e1000e_write_kmrn_reg(hw, E1000_KMRNCTRLSTA_OFFSET_HD_CTRL,
Expand All @@ -1127,9 +1181,16 @@ static s32 e1000_cfg_kmrn_1000_80003es2lan(struct e1000_hw *hw)
tipg |= DEFAULT_TIPG_IPGT_1000_80003ES2LAN;
ew32(TIPG, tipg);

ret_val = e1e_rphy(hw, GG82563_PHY_KMRN_MODE_CTRL, &reg_data);
if (ret_val)
return ret_val;
do {
ret_val = e1e_rphy(hw, GG82563_PHY_KMRN_MODE_CTRL, &reg_data);
if (ret_val)
return ret_val;

ret_val = e1e_rphy(hw, GG82563_PHY_KMRN_MODE_CTRL, &reg_data2);
if (ret_val)
return ret_val;
i++;
} while ((reg_data != reg_data2) && (i < GG82563_MAX_KMRN_RETRY));

reg_data &= ~GG82563_KMCR_PASS_FALSE_CARRIER;
ret_val = e1e_wphy(hw, GG82563_PHY_KMRN_MODE_CTRL, reg_data);
Expand Down
Loading

0 comments on commit 2d9498f

Please sign in to comment.