Skip to content

Commit f5e6403

Browse files
Russell Kingdavem330
authored andcommitted
net: phy: fix resume handling
When a PHY has the BMCR_PDOWN bit set, it may decide to ignore writes to other registers, or reset the registers to power-on defaults. Micrel PHYs do this for their interrupt registers. The current structure of phylib tries to enable interrupts before resuming (and releasing) the BMCR_PDOWN bit. This fails, causing Micrel PHYs to stop working after a suspend/resume sequence if they are using interrupts. Fix this by ensuring that the PHY driver resume methods do not take the phydev->lock mutex themselves, but the callers of phy_resume() take that lock. This then allows us to move the call to phy_resume() before we enable interrupts in phy_start(). Signed-off-by: Russell King <[email protected]> Reviewed-by: Andrew Lunn <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent cd8165c commit f5e6403

File tree

3 files changed

+9
-14
lines changed

3 files changed

+9
-14
lines changed

drivers/net/phy/at803x.c

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -239,14 +239,10 @@ static int at803x_resume(struct phy_device *phydev)
239239
{
240240
int value;
241241

242-
mutex_lock(&phydev->lock);
243-
244242
value = phy_read(phydev, MII_BMCR);
245243
value &= ~(BMCR_PDOWN | BMCR_ISOLATE);
246244
phy_write(phydev, MII_BMCR, value);
247245

248-
mutex_unlock(&phydev->lock);
249-
250246
return 0;
251247
}
252248

drivers/net/phy/phy.c

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -828,7 +828,6 @@ EXPORT_SYMBOL(phy_stop);
828828
*/
829829
void phy_start(struct phy_device *phydev)
830830
{
831-
bool do_resume = false;
832831
int err = 0;
833832

834833
mutex_lock(&phydev->lock);
@@ -841,6 +840,9 @@ void phy_start(struct phy_device *phydev)
841840
phydev->state = PHY_UP;
842841
break;
843842
case PHY_HALTED:
843+
/* if phy was suspended, bring the physical link up again */
844+
phy_resume(phydev);
845+
844846
/* make sure interrupts are re-enabled for the PHY */
845847
if (phydev->irq != PHY_POLL) {
846848
err = phy_enable_interrupts(phydev);
@@ -849,17 +851,12 @@ void phy_start(struct phy_device *phydev)
849851
}
850852

851853
phydev->state = PHY_RESUMING;
852-
do_resume = true;
853854
break;
854855
default:
855856
break;
856857
}
857858
mutex_unlock(&phydev->lock);
858859

859-
/* if phy was suspended, bring the physical link up again */
860-
if (do_resume)
861-
phy_resume(phydev);
862-
863860
phy_trigger_machine(phydev, true);
864861
}
865862
EXPORT_SYMBOL(phy_start);

drivers/net/phy/phy_device.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,9 @@ static int mdio_bus_phy_resume(struct device *dev)
135135
if (!mdio_bus_phy_may_suspend(phydev))
136136
goto no_resume;
137137

138+
mutex_lock(&phydev->lock);
138139
ret = phy_resume(phydev);
140+
mutex_unlock(&phydev->lock);
139141
if (ret < 0)
140142
return ret;
141143

@@ -1026,7 +1028,9 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
10261028
if (err)
10271029
goto error;
10281030

1031+
mutex_lock(&phydev->lock);
10291032
phy_resume(phydev);
1033+
mutex_unlock(&phydev->lock);
10301034
phy_led_triggers_register(phydev);
10311035

10321036
return err;
@@ -1157,6 +1161,8 @@ int phy_resume(struct phy_device *phydev)
11571161
struct phy_driver *phydrv = to_phy_driver(phydev->mdio.dev.driver);
11581162
int ret = 0;
11591163

1164+
WARN_ON(!mutex_is_locked(&phydev->lock));
1165+
11601166
if (phydev->drv && phydrv->resume)
11611167
ret = phydrv->resume(phydev);
11621168

@@ -1639,13 +1645,9 @@ int genphy_resume(struct phy_device *phydev)
16391645
{
16401646
int value;
16411647

1642-
mutex_lock(&phydev->lock);
1643-
16441648
value = phy_read(phydev, MII_BMCR);
16451649
phy_write(phydev, MII_BMCR, value & ~BMCR_PDOWN);
16461650

1647-
mutex_unlock(&phydev->lock);
1648-
16491651
return 0;
16501652
}
16511653
EXPORT_SYMBOL(genphy_resume);

0 commit comments

Comments
 (0)