aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexander Duyck <alexander.h.duyck@intel.com>2009-10-05 02:35:42 -0400
committerDavid S. Miller <davem@davemloft.net>2009-10-06 17:59:24 -0400
commit2553bb2681645bf932db2845121b8f33954f6f39 (patch)
tree3aa34b3b94bb1fab528870a7dc72caa182e3587f
parentab576389b733b458495529f81839f499b3fece78 (diff)
igb: add additional error handling to the phy code
This update adds additional exception handling to the phy code to handle situations where it may be called incorrectly. In addition it adds some bounds checking to the cable length checks to prevent an array overrun in the event that the hardware returned a different value than expected. Signed-off-by: Alexander Duyck <alexander.h.duyck@intel.com> Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/igb/e1000_phy.c39
1 files changed, 25 insertions, 14 deletions
diff --git a/drivers/net/igb/e1000_phy.c b/drivers/net/igb/e1000_phy.c
index 5fe03e114b83..83b706c460b3 100644
--- a/drivers/net/igb/e1000_phy.c
+++ b/drivers/net/igb/e1000_phy.c
@@ -39,6 +39,9 @@ static s32 igb_wait_autoneg(struct e1000_hw *hw);
39/* Cable length tables */ 39/* Cable length tables */
40static const u16 e1000_m88_cable_length_table[] = 40static const u16 e1000_m88_cable_length_table[] =
41 { 0, 50, 80, 110, 140, 140, E1000_CABLE_LENGTH_UNDEFINED }; 41 { 0, 50, 80, 110, 140, 140, E1000_CABLE_LENGTH_UNDEFINED };
42#define M88E1000_CABLE_LENGTH_TABLE_SIZE \
43 (sizeof(e1000_m88_cable_length_table) / \
44 sizeof(e1000_m88_cable_length_table[0]))
42 45
43static const u16 e1000_igp_2_cable_length_table[] = 46static const u16 e1000_igp_2_cable_length_table[] =
44 { 0, 0, 0, 0, 0, 0, 0, 0, 3, 5, 8, 11, 13, 16, 18, 21, 47 { 0, 0, 0, 0, 0, 0, 0, 0, 3, 5, 8, 11, 13, 16, 18, 21,
@@ -109,7 +112,10 @@ out:
109 **/ 112 **/
110static s32 igb_phy_reset_dsp(struct e1000_hw *hw) 113static s32 igb_phy_reset_dsp(struct e1000_hw *hw)
111{ 114{
112 s32 ret_val; 115 s32 ret_val = 0;
116
117 if (!(hw->phy.ops.write_reg))
118 goto out;
113 119
114 ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_GEN_CONTROL, 0xC1); 120 ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_GEN_CONTROL, 0xC1);
115 if (ret_val) 121 if (ret_val)
@@ -1059,22 +1065,19 @@ s32 igb_phy_force_speed_duplex_m88(struct e1000_hw *hw)
1059 1065
1060 igb_phy_force_speed_duplex_setup(hw, &phy_data); 1066 igb_phy_force_speed_duplex_setup(hw, &phy_data);
1061 1067
1062 /* Reset the phy to commit changes. */
1063 phy_data |= MII_CR_RESET;
1064
1065 ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_data); 1068 ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_data);
1066 if (ret_val) 1069 if (ret_val)
1067 goto out; 1070 goto out;
1068 1071
1069 udelay(1); 1072 /* Reset the phy to commit changes. */
1073 ret_val = igb_phy_sw_reset(hw);
1074 if (ret_val)
1075 goto out;
1070 1076
1071 if (phy->autoneg_wait_to_complete) { 1077 if (phy->autoneg_wait_to_complete) {
1072 hw_dbg("Waiting for forced speed/duplex link on M88 phy.\n"); 1078 hw_dbg("Waiting for forced speed/duplex link on M88 phy.\n");
1073 1079
1074 ret_val = igb_phy_has_link(hw, 1080 ret_val = igb_phy_has_link(hw, PHY_FORCE_LIMIT, 100000, &link);
1075 PHY_FORCE_LIMIT,
1076 100000,
1077 &link);
1078 if (ret_val) 1081 if (ret_val)
1079 goto out; 1082 goto out;
1080 1083
@@ -1084,8 +1087,8 @@ s32 igb_phy_force_speed_duplex_m88(struct e1000_hw *hw)
1084 * Reset the DSP and cross our fingers. 1087 * Reset the DSP and cross our fingers.
1085 */ 1088 */
1086 ret_val = phy->ops.write_reg(hw, 1089 ret_val = phy->ops.write_reg(hw,
1087 M88E1000_PHY_PAGE_SELECT, 1090 M88E1000_PHY_PAGE_SELECT,
1088 0x001d); 1091 0x001d);
1089 if (ret_val) 1092 if (ret_val)
1090 goto out; 1093 goto out;
1091 ret_val = igb_phy_reset_dsp(hw); 1094 ret_val = igb_phy_reset_dsp(hw);
@@ -1095,7 +1098,7 @@ s32 igb_phy_force_speed_duplex_m88(struct e1000_hw *hw)
1095 1098
1096 /* Try once more */ 1099 /* Try once more */
1097 ret_val = igb_phy_has_link(hw, PHY_FORCE_LIMIT, 1100 ret_val = igb_phy_has_link(hw, PHY_FORCE_LIMIT,
1098 100000, &link); 1101 100000, &link);
1099 if (ret_val) 1102 if (ret_val)
1100 goto out; 1103 goto out;
1101 } 1104 }
@@ -1207,9 +1210,12 @@ static void igb_phy_force_speed_duplex_setup(struct e1000_hw *hw,
1207s32 igb_set_d3_lplu_state(struct e1000_hw *hw, bool active) 1210s32 igb_set_d3_lplu_state(struct e1000_hw *hw, bool active)
1208{ 1211{
1209 struct e1000_phy_info *phy = &hw->phy; 1212 struct e1000_phy_info *phy = &hw->phy;
1210 s32 ret_val; 1213 s32 ret_val = 0;
1211 u16 data; 1214 u16 data;
1212 1215
1216 if (!(hw->phy.ops.read_reg))
1217 goto out;
1218
1213 ret_val = phy->ops.read_reg(hw, IGP02E1000_PHY_POWER_MGMT, &data); 1219 ret_val = phy->ops.read_reg(hw, IGP02E1000_PHY_POWER_MGMT, &data);
1214 if (ret_val) 1220 if (ret_val)
1215 goto out; 1221 goto out;
@@ -1495,8 +1501,13 @@ s32 igb_get_cable_length_m88(struct e1000_hw *hw)
1495 1501
1496 index = (phy_data & M88E1000_PSSR_CABLE_LENGTH) >> 1502 index = (phy_data & M88E1000_PSSR_CABLE_LENGTH) >>
1497 M88E1000_PSSR_CABLE_LENGTH_SHIFT; 1503 M88E1000_PSSR_CABLE_LENGTH_SHIFT;
1504 if (index >= M88E1000_CABLE_LENGTH_TABLE_SIZE - 1) {
1505 ret_val = -E1000_ERR_PHY;
1506 goto out;
1507 }
1508
1498 phy->min_cable_length = e1000_m88_cable_length_table[index]; 1509 phy->min_cable_length = e1000_m88_cable_length_table[index];
1499 phy->max_cable_length = e1000_m88_cable_length_table[index+1]; 1510 phy->max_cable_length = e1000_m88_cable_length_table[index + 1];
1500 1511
1501 phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2; 1512 phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2;
1502 1513