diff options
| author | Geert Uytterhoeven <geert+renesas@glider.be> | 2017-09-13 13:42:05 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2017-09-15 17:24:49 -0400 |
| commit | 2aa70f864955bf02362e3fb3008e4208d7a17a98 (patch) | |
| tree | 90818b285680aac8d9bddebf89f6d3ea74ebd5b4 | |
| parent | 7095c973453e56efa0903e863b59cd89c75e62dc (diff) | |
net: smsc911x: Quieten netif during suspend
If the network interface is kept running during suspend, the net core
may call net_device_ops.ndo_start_xmit() while the Ethernet device is
still suspended, which may lead to a system crash.
E.g. on sh73a0/kzm9g and r8a73a4/ape6evm, the external Ethernet chip is
driven by a PM controlled clock. If the Ethernet registers are accessed
while the clock is not running, the system will crash with an imprecise
external abort.
As this is a race condition with a small time window, it is not so easy
to trigger at will. Using pm_test may increase your chances:
# echo 0 > /sys/module/printk/parameters/console_suspend
# echo platform > /sys/power/pm_test
# echo mem > /sys/power/state
To fix this, make sure the network interface is quietened during
suspend.
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
| -rw-r--r-- | drivers/net/ethernet/smsc/smsc911x.c | 15 |
1 files changed, 14 insertions, 1 deletions
diff --git a/drivers/net/ethernet/smsc/smsc911x.c b/drivers/net/ethernet/smsc/smsc911x.c index 0b6a39b003a4..012fb66eed8d 100644 --- a/drivers/net/ethernet/smsc/smsc911x.c +++ b/drivers/net/ethernet/smsc/smsc911x.c | |||
| @@ -2595,6 +2595,11 @@ static int smsc911x_suspend(struct device *dev) | |||
| 2595 | struct net_device *ndev = dev_get_drvdata(dev); | 2595 | struct net_device *ndev = dev_get_drvdata(dev); |
| 2596 | struct smsc911x_data *pdata = netdev_priv(ndev); | 2596 | struct smsc911x_data *pdata = netdev_priv(ndev); |
| 2597 | 2597 | ||
| 2598 | if (netif_running(ndev)) { | ||
| 2599 | netif_stop_queue(ndev); | ||
| 2600 | netif_device_detach(ndev); | ||
| 2601 | } | ||
| 2602 | |||
| 2598 | /* enable wake on LAN, energy detection and the external PME | 2603 | /* enable wake on LAN, energy detection and the external PME |
| 2599 | * signal. */ | 2604 | * signal. */ |
| 2600 | smsc911x_reg_write(pdata, PMT_CTRL, | 2605 | smsc911x_reg_write(pdata, PMT_CTRL, |
| @@ -2628,7 +2633,15 @@ static int smsc911x_resume(struct device *dev) | |||
| 2628 | while (!(smsc911x_reg_read(pdata, PMT_CTRL) & PMT_CTRL_READY_) && --to) | 2633 | while (!(smsc911x_reg_read(pdata, PMT_CTRL) & PMT_CTRL_READY_) && --to) |
| 2629 | udelay(1000); | 2634 | udelay(1000); |
| 2630 | 2635 | ||
| 2631 | return (to == 0) ? -EIO : 0; | 2636 | if (to == 0) |
| 2637 | return -EIO; | ||
| 2638 | |||
| 2639 | if (netif_running(ndev)) { | ||
| 2640 | netif_device_attach(ndev); | ||
| 2641 | netif_start_queue(ndev); | ||
| 2642 | } | ||
| 2643 | |||
| 2644 | return 0; | ||
| 2632 | } | 2645 | } |
| 2633 | 2646 | ||
| 2634 | static const struct dev_pm_ops smsc911x_pm_ops = { | 2647 | static const struct dev_pm_ops smsc911x_pm_ops = { |
