Skip to content

Commit 0b6f65c

Browse files
Joakim Zhangdavem330
authored andcommitted
net: fec: fix system hang during suspend/resume
1. During normal suspend (WoL not enabled) process, system has posibility to hang. The root cause is TXF interrupt coming after clocks disabled, system hang when accessing registers from interrupt handler. To fix this issue, disable all interrupts when system suspend. 2. System also has posibility to hang with WoL enabled during suspend, after entering stop mode, then magic pattern coming after clocks disabled, system will be waked up, and interrupt handler will be called, system hang when access registers. To fix this issue, disable wakeup irq in .suspend(), and enable it in .resume(). Signed-off-by: Joakim Zhang <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 8438699 commit 0b6f65c

File tree

1 file changed

+34
-12
lines changed

1 file changed

+34
-12
lines changed

drivers/net/ethernet/freescale/fec_main.c

Lines changed: 34 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1185,6 +1185,21 @@ static void fec_enet_stop_mode(struct fec_enet_private *fep, bool enabled)
11851185
}
11861186
}
11871187

1188+
static void fec_irqs_disable(struct net_device *ndev)
1189+
{
1190+
struct fec_enet_private *fep = netdev_priv(ndev);
1191+
1192+
writel(0, fep->hwp + FEC_IMASK);
1193+
}
1194+
1195+
static void fec_irqs_disable_except_wakeup(struct net_device *ndev)
1196+
{
1197+
struct fec_enet_private *fep = netdev_priv(ndev);
1198+
1199+
writel(0, fep->hwp + FEC_IMASK);
1200+
writel(FEC_ENET_WAKEUP, fep->hwp + FEC_IMASK);
1201+
}
1202+
11881203
static void
11891204
fec_stop(struct net_device *ndev)
11901205
{
@@ -1211,15 +1226,13 @@ fec_stop(struct net_device *ndev)
12111226
writel(1, fep->hwp + FEC_ECNTRL);
12121227
udelay(10);
12131228
}
1214-
writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);
12151229
} else {
1216-
writel(FEC_DEFAULT_IMASK | FEC_ENET_WAKEUP, fep->hwp + FEC_IMASK);
12171230
val = readl(fep->hwp + FEC_ECNTRL);
12181231
val |= (FEC_ECR_MAGICEN | FEC_ECR_SLEEP);
12191232
writel(val, fep->hwp + FEC_ECNTRL);
1220-
fec_enet_stop_mode(fep, true);
12211233
}
12221234
writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED);
1235+
writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);
12231236

12241237
/* We have to keep ENET enabled to have MII interrupt stay working */
12251238
if (fep->quirks & FEC_QUIRK_ENET_MAC &&
@@ -2877,15 +2890,10 @@ fec_enet_set_wol(struct net_device *ndev, struct ethtool_wolinfo *wol)
28772890
return -EINVAL;
28782891

28792892
device_set_wakeup_enable(&ndev->dev, wol->wolopts & WAKE_MAGIC);
2880-
if (device_may_wakeup(&ndev->dev)) {
2893+
if (device_may_wakeup(&ndev->dev))
28812894
fep->wol_flag |= FEC_WOL_FLAG_ENABLE;
2882-
if (fep->wake_irq > 0)
2883-
enable_irq_wake(fep->wake_irq);
2884-
} else {
2895+
else
28852896
fep->wol_flag &= (~FEC_WOL_FLAG_ENABLE);
2886-
if (fep->wake_irq > 0)
2887-
disable_irq_wake(fep->wake_irq);
2888-
}
28892897

28902898
return 0;
28912899
}
@@ -4057,9 +4065,19 @@ static int __maybe_unused fec_suspend(struct device *dev)
40574065
netif_device_detach(ndev);
40584066
netif_tx_unlock_bh(ndev);
40594067
fec_stop(ndev);
4060-
fec_enet_clk_enable(ndev, false);
4061-
if (!(fep->wol_flag & FEC_WOL_FLAG_ENABLE))
4068+
if (!(fep->wol_flag & FEC_WOL_FLAG_ENABLE)) {
4069+
fec_irqs_disable(ndev);
40624070
pinctrl_pm_select_sleep_state(&fep->pdev->dev);
4071+
} else {
4072+
fec_irqs_disable_except_wakeup(ndev);
4073+
if (fep->wake_irq > 0) {
4074+
disable_irq(fep->wake_irq);
4075+
enable_irq_wake(fep->wake_irq);
4076+
}
4077+
fec_enet_stop_mode(fep, true);
4078+
}
4079+
/* It's safe to disable clocks since interrupts are masked */
4080+
fec_enet_clk_enable(ndev, false);
40634081
}
40644082
rtnl_unlock();
40654083

@@ -4097,6 +4115,10 @@ static int __maybe_unused fec_resume(struct device *dev)
40974115
}
40984116
if (fep->wol_flag & FEC_WOL_FLAG_ENABLE) {
40994117
fec_enet_stop_mode(fep, false);
4118+
if (fep->wake_irq) {
4119+
disable_irq_wake(fep->wake_irq);
4120+
enable_irq(fep->wake_irq);
4121+
}
41004122

41014123
val = readl(fep->hwp + FEC_ECNTRL);
41024124
val &= ~(FEC_ECR_MAGICEN | FEC_ECR_SLEEP);

0 commit comments

Comments
 (0)