Skip to content

Commit 6dbdd4d

Browse files
vlifshtsanguy11
authored andcommitted
e1000e: Workaround for sporadic MDI error on Meteor Lake systems
On some Meteor Lake systems accessing the PHY via the MDIO interface may result in an MDI error. This issue happens sporadically and in most cases a second access to the PHY via the MDIO interface results in success. As a workaround, introduce a retry counter which is set to 3 on Meteor Lake systems. The driver will only return an error if 3 consecutive PHY access attempts fail. The retry mechanism is disabled in specific flows, where MDI errors are expected. Fixes: cc23f4f ("e1000e: Add support for Meteor Lake") Suggested-by: Nikolay Mushayev <[email protected]> Co-developed-by: Nir Efrati <[email protected]> Signed-off-by: Nir Efrati <[email protected]> Signed-off-by: Vitaly Lifshits <[email protected]> Tested-by: Naama Meir <[email protected]> Signed-off-by: Tony Nguyen <[email protected]>
1 parent afbf75e commit 6dbdd4d

File tree

4 files changed

+150
-69
lines changed

4 files changed

+150
-69
lines changed

drivers/net/ethernet/intel/e1000e/hw.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -628,6 +628,7 @@ struct e1000_phy_info {
628628
u32 id;
629629
u32 reset_delay_us; /* in usec */
630630
u32 revision;
631+
u32 retry_count;
631632

632633
enum e1000_media_type media_type;
633634

@@ -644,6 +645,7 @@ struct e1000_phy_info {
644645
bool polarity_correction;
645646
bool speed_downgraded;
646647
bool autoneg_wait_to_complete;
648+
bool retry_enabled;
647649
};
648650

649651
struct e1000_nvm_info {

drivers/net/ethernet/intel/e1000e/ich8lan.c

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,11 +222,18 @@ static bool e1000_phy_is_accessible_pchlan(struct e1000_hw *hw)
222222
if (hw->mac.type >= e1000_pch_lpt) {
223223
/* Only unforce SMBus if ME is not active */
224224
if (!(er32(FWSM) & E1000_ICH_FWSM_FW_VALID)) {
225+
/* Switching PHY interface always returns MDI error
226+
* so disable retry mechanism to avoid wasting time
227+
*/
228+
e1000e_disable_phy_retry(hw);
229+
225230
/* Unforce SMBus mode in PHY */
226231
e1e_rphy_locked(hw, CV_SMB_CTRL, &phy_reg);
227232
phy_reg &= ~CV_SMB_CTRL_FORCE_SMBUS;
228233
e1e_wphy_locked(hw, CV_SMB_CTRL, phy_reg);
229234

235+
e1000e_enable_phy_retry(hw);
236+
230237
/* Unforce SMBus mode in MAC */
231238
mac_reg = er32(CTRL_EXT);
232239
mac_reg &= ~E1000_CTRL_EXT_FORCE_SMBUS;
@@ -310,6 +317,11 @@ static s32 e1000_init_phy_workarounds_pchlan(struct e1000_hw *hw)
310317
goto out;
311318
}
312319

320+
/* There is no guarantee that the PHY is accessible at this time
321+
* so disable retry mechanism to avoid wasting time
322+
*/
323+
e1000e_disable_phy_retry(hw);
324+
313325
/* The MAC-PHY interconnect may be in SMBus mode. If the PHY is
314326
* inaccessible and resetting the PHY is not blocked, toggle the
315327
* LANPHYPC Value bit to force the interconnect to PCIe mode.
@@ -380,6 +392,8 @@ static s32 e1000_init_phy_workarounds_pchlan(struct e1000_hw *hw)
380392
break;
381393
}
382394

395+
e1000e_enable_phy_retry(hw);
396+
383397
hw->phy.ops.release(hw);
384398
if (!ret_val) {
385399

@@ -449,6 +463,11 @@ static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw)
449463

450464
phy->id = e1000_phy_unknown;
451465

466+
if (hw->mac.type == e1000_pch_mtp) {
467+
phy->retry_count = 2;
468+
e1000e_enable_phy_retry(hw);
469+
}
470+
452471
ret_val = e1000_init_phy_workarounds_pchlan(hw);
453472
if (ret_val)
454473
return ret_val;
@@ -1146,13 +1165,20 @@ s32 e1000_enable_ulp_lpt_lp(struct e1000_hw *hw, bool to_sx)
11461165
if (ret_val)
11471166
goto out;
11481167

1168+
/* Switching PHY interface always returns MDI error
1169+
* so disable retry mechanism to avoid wasting time
1170+
*/
1171+
e1000e_disable_phy_retry(hw);
1172+
11491173
/* Force SMBus mode in PHY */
11501174
ret_val = e1000_read_phy_reg_hv_locked(hw, CV_SMB_CTRL, &phy_reg);
11511175
if (ret_val)
11521176
goto release;
11531177
phy_reg |= CV_SMB_CTRL_FORCE_SMBUS;
11541178
e1000_write_phy_reg_hv_locked(hw, CV_SMB_CTRL, phy_reg);
11551179

1180+
e1000e_enable_phy_retry(hw);
1181+
11561182
/* Force SMBus mode in MAC */
11571183
mac_reg = er32(CTRL_EXT);
11581184
mac_reg |= E1000_CTRL_EXT_FORCE_SMBUS;
@@ -1313,6 +1339,11 @@ static s32 e1000_disable_ulp_lpt_lp(struct e1000_hw *hw, bool force)
13131339
/* Toggle LANPHYPC Value bit */
13141340
e1000_toggle_lanphypc_pch_lpt(hw);
13151341

1342+
/* Switching PHY interface always returns MDI error
1343+
* so disable retry mechanism to avoid wasting time
1344+
*/
1345+
e1000e_disable_phy_retry(hw);
1346+
13161347
/* Unforce SMBus mode in PHY */
13171348
ret_val = e1000_read_phy_reg_hv_locked(hw, CV_SMB_CTRL, &phy_reg);
13181349
if (ret_val) {
@@ -1333,6 +1364,8 @@ static s32 e1000_disable_ulp_lpt_lp(struct e1000_hw *hw, bool force)
13331364
phy_reg &= ~CV_SMB_CTRL_FORCE_SMBUS;
13341365
e1000_write_phy_reg_hv_locked(hw, CV_SMB_CTRL, phy_reg);
13351366

1367+
e1000e_enable_phy_retry(hw);
1368+
13361369
/* Unforce SMBus mode in MAC */
13371370
mac_reg = er32(CTRL_EXT);
13381371
mac_reg &= ~E1000_CTRL_EXT_FORCE_SMBUS;

drivers/net/ethernet/intel/e1000e/phy.c

Lines changed: 113 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,16 @@ s32 e1000e_phy_reset_dsp(struct e1000_hw *hw)
107107
return e1e_wphy(hw, M88E1000_PHY_GEN_CONTROL, 0);
108108
}
109109

110+
void e1000e_disable_phy_retry(struct e1000_hw *hw)
111+
{
112+
hw->phy.retry_enabled = false;
113+
}
114+
115+
void e1000e_enable_phy_retry(struct e1000_hw *hw)
116+
{
117+
hw->phy.retry_enabled = true;
118+
}
119+
110120
/**
111121
* e1000e_read_phy_reg_mdic - Read MDI control register
112122
* @hw: pointer to the HW structure
@@ -118,55 +128,73 @@ s32 e1000e_phy_reset_dsp(struct e1000_hw *hw)
118128
**/
119129
s32 e1000e_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data)
120130
{
131+
u32 i, mdic = 0, retry_counter, retry_max;
121132
struct e1000_phy_info *phy = &hw->phy;
122-
u32 i, mdic = 0;
133+
bool success;
123134

124135
if (offset > MAX_PHY_REG_ADDRESS) {
125136
e_dbg("PHY Address %d is out of range\n", offset);
126137
return -E1000_ERR_PARAM;
127138
}
128139

140+
retry_max = phy->retry_enabled ? phy->retry_count : 0;
141+
129142
/* Set up Op-code, Phy Address, and register offset in the MDI
130143
* Control register. The MAC will take care of interfacing with the
131144
* PHY to retrieve the desired data.
132145
*/
133-
mdic = ((offset << E1000_MDIC_REG_SHIFT) |
134-
(phy->addr << E1000_MDIC_PHY_SHIFT) |
135-
(E1000_MDIC_OP_READ));
146+
for (retry_counter = 0; retry_counter <= retry_max; retry_counter++) {
147+
success = true;
136148

137-
ew32(MDIC, mdic);
149+
mdic = ((offset << E1000_MDIC_REG_SHIFT) |
150+
(phy->addr << E1000_MDIC_PHY_SHIFT) |
151+
(E1000_MDIC_OP_READ));
138152

139-
/* Poll the ready bit to see if the MDI read completed
140-
* Increasing the time out as testing showed failures with
141-
* the lower time out
142-
*/
143-
for (i = 0; i < (E1000_GEN_POLL_TIMEOUT * 3); i++) {
144-
udelay(50);
145-
mdic = er32(MDIC);
146-
if (mdic & E1000_MDIC_READY)
147-
break;
148-
}
149-
if (!(mdic & E1000_MDIC_READY)) {
150-
e_dbg("MDI Read PHY Reg Address %d did not complete\n", offset);
151-
return -E1000_ERR_PHY;
152-
}
153-
if (mdic & E1000_MDIC_ERROR) {
154-
e_dbg("MDI Read PHY Reg Address %d Error\n", offset);
155-
return -E1000_ERR_PHY;
156-
}
157-
if (FIELD_GET(E1000_MDIC_REG_MASK, mdic) != offset) {
158-
e_dbg("MDI Read offset error - requested %d, returned %d\n",
159-
offset, FIELD_GET(E1000_MDIC_REG_MASK, mdic));
160-
return -E1000_ERR_PHY;
153+
ew32(MDIC, mdic);
154+
155+
/* Poll the ready bit to see if the MDI read completed
156+
* Increasing the time out as testing showed failures with
157+
* the lower time out
158+
*/
159+
for (i = 0; i < (E1000_GEN_POLL_TIMEOUT * 3); i++) {
160+
usleep_range(50, 60);
161+
mdic = er32(MDIC);
162+
if (mdic & E1000_MDIC_READY)
163+
break;
164+
}
165+
if (!(mdic & E1000_MDIC_READY)) {
166+
e_dbg("MDI Read PHY Reg Address %d did not complete\n",
167+
offset);
168+
success = false;
169+
}
170+
if (mdic & E1000_MDIC_ERROR) {
171+
e_dbg("MDI Read PHY Reg Address %d Error\n", offset);
172+
success = false;
173+
}
174+
if (FIELD_GET(E1000_MDIC_REG_MASK, mdic) != offset) {
175+
e_dbg("MDI Read offset error - requested %d, returned %d\n",
176+
offset, FIELD_GET(E1000_MDIC_REG_MASK, mdic));
177+
success = false;
178+
}
179+
180+
/* Allow some time after each MDIC transaction to avoid
181+
* reading duplicate data in the next MDIC transaction.
182+
*/
183+
if (hw->mac.type == e1000_pch2lan)
184+
usleep_range(100, 150);
185+
186+
if (success) {
187+
*data = (u16)mdic;
188+
return 0;
189+
}
190+
191+
if (retry_counter != retry_max) {
192+
e_dbg("Perform retry on PHY transaction...\n");
193+
mdelay(10);
194+
}
161195
}
162-
*data = (u16)mdic;
163196

164-
/* Allow some time after each MDIC transaction to avoid
165-
* reading duplicate data in the next MDIC transaction.
166-
*/
167-
if (hw->mac.type == e1000_pch2lan)
168-
udelay(100);
169-
return 0;
197+
return -E1000_ERR_PHY;
170198
}
171199

172200
/**
@@ -179,56 +207,72 @@ s32 e1000e_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data)
179207
**/
180208
s32 e1000e_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data)
181209
{
210+
u32 i, mdic = 0, retry_counter, retry_max;
182211
struct e1000_phy_info *phy = &hw->phy;
183-
u32 i, mdic = 0;
212+
bool success;
184213

185214
if (offset > MAX_PHY_REG_ADDRESS) {
186215
e_dbg("PHY Address %d is out of range\n", offset);
187216
return -E1000_ERR_PARAM;
188217
}
189218

219+
retry_max = phy->retry_enabled ? phy->retry_count : 0;
220+
190221
/* Set up Op-code, Phy Address, and register offset in the MDI
191222
* Control register. The MAC will take care of interfacing with the
192223
* PHY to retrieve the desired data.
193224
*/
194-
mdic = (((u32)data) |
195-
(offset << E1000_MDIC_REG_SHIFT) |
196-
(phy->addr << E1000_MDIC_PHY_SHIFT) |
197-
(E1000_MDIC_OP_WRITE));
225+
for (retry_counter = 0; retry_counter <= retry_max; retry_counter++) {
226+
success = true;
198227

199-
ew32(MDIC, mdic);
228+
mdic = (((u32)data) |
229+
(offset << E1000_MDIC_REG_SHIFT) |
230+
(phy->addr << E1000_MDIC_PHY_SHIFT) |
231+
(E1000_MDIC_OP_WRITE));
200232

201-
/* Poll the ready bit to see if the MDI read completed
202-
* Increasing the time out as testing showed failures with
203-
* the lower time out
204-
*/
205-
for (i = 0; i < (E1000_GEN_POLL_TIMEOUT * 3); i++) {
206-
udelay(50);
207-
mdic = er32(MDIC);
208-
if (mdic & E1000_MDIC_READY)
209-
break;
210-
}
211-
if (!(mdic & E1000_MDIC_READY)) {
212-
e_dbg("MDI Write PHY Reg Address %d did not complete\n", offset);
213-
return -E1000_ERR_PHY;
214-
}
215-
if (mdic & E1000_MDIC_ERROR) {
216-
e_dbg("MDI Write PHY Red Address %d Error\n", offset);
217-
return -E1000_ERR_PHY;
218-
}
219-
if (FIELD_GET(E1000_MDIC_REG_MASK, mdic) != offset) {
220-
e_dbg("MDI Write offset error - requested %d, returned %d\n",
221-
offset, FIELD_GET(E1000_MDIC_REG_MASK, mdic));
222-
return -E1000_ERR_PHY;
223-
}
233+
ew32(MDIC, mdic);
224234

225-
/* Allow some time after each MDIC transaction to avoid
226-
* reading duplicate data in the next MDIC transaction.
227-
*/
228-
if (hw->mac.type == e1000_pch2lan)
229-
udelay(100);
235+
/* Poll the ready bit to see if the MDI read completed
236+
* Increasing the time out as testing showed failures with
237+
* the lower time out
238+
*/
239+
for (i = 0; i < (E1000_GEN_POLL_TIMEOUT * 3); i++) {
240+
usleep_range(50, 60);
241+
mdic = er32(MDIC);
242+
if (mdic & E1000_MDIC_READY)
243+
break;
244+
}
245+
if (!(mdic & E1000_MDIC_READY)) {
246+
e_dbg("MDI Write PHY Reg Address %d did not complete\n",
247+
offset);
248+
success = false;
249+
}
250+
if (mdic & E1000_MDIC_ERROR) {
251+
e_dbg("MDI Write PHY Reg Address %d Error\n", offset);
252+
success = false;
253+
}
254+
if (FIELD_GET(E1000_MDIC_REG_MASK, mdic) != offset) {
255+
e_dbg("MDI Write offset error - requested %d, returned %d\n",
256+
offset, FIELD_GET(E1000_MDIC_REG_MASK, mdic));
257+
success = false;
258+
}
230259

231-
return 0;
260+
/* Allow some time after each MDIC transaction to avoid
261+
* reading duplicate data in the next MDIC transaction.
262+
*/
263+
if (hw->mac.type == e1000_pch2lan)
264+
usleep_range(100, 150);
265+
266+
if (success)
267+
return 0;
268+
269+
if (retry_counter != retry_max) {
270+
e_dbg("Perform retry on PHY transaction...\n");
271+
mdelay(10);
272+
}
273+
}
274+
275+
return -E1000_ERR_PHY;
232276
}
233277

234278
/**

drivers/net/ethernet/intel/e1000e/phy.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ s32 e1000e_read_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 *data);
5151
s32 e1000e_write_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 data);
5252
void e1000_power_up_phy_copper(struct e1000_hw *hw);
5353
void e1000_power_down_phy_copper(struct e1000_hw *hw);
54+
void e1000e_disable_phy_retry(struct e1000_hw *hw);
55+
void e1000e_enable_phy_retry(struct e1000_hw *hw);
5456
s32 e1000e_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data);
5557
s32 e1000e_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data);
5658
s32 e1000_read_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 *data);

0 commit comments

Comments
 (0)