aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/phy/phy_device.c12
-rw-r--r--include/linux/netdevice.h3
-rw-r--r--net/core/ethtool.c9
3 files changed, 20 insertions, 4 deletions
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index db1172db1e7c..19ab8a7d1e48 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -93,7 +93,12 @@ static bool mdio_bus_phy_may_suspend(struct phy_device *phydev)
93 if (!netdev) 93 if (!netdev)
94 return !phydev->suspended; 94 return !phydev->suspended;
95 95
96 /* Don't suspend PHY if the attached netdev parent may wakeup. 96 if (netdev->wol_enabled)
97 return false;
98
99 /* As long as not all affected network drivers support the
100 * wol_enabled flag, let's check for hints that WoL is enabled.
101 * Don't suspend PHY if the attached netdev parent may wake up.
97 * The parent may point to a PCI device, as in tg3 driver. 102 * The parent may point to a PCI device, as in tg3 driver.
98 */ 103 */
99 if (netdev->dev.parent && device_may_wakeup(netdev->dev.parent)) 104 if (netdev->dev.parent && device_may_wakeup(netdev->dev.parent))
@@ -1132,9 +1137,9 @@ void phy_detach(struct phy_device *phydev)
1132 sysfs_remove_link(&dev->dev.kobj, "phydev"); 1137 sysfs_remove_link(&dev->dev.kobj, "phydev");
1133 sysfs_remove_link(&phydev->mdio.dev.kobj, "attached_dev"); 1138 sysfs_remove_link(&phydev->mdio.dev.kobj, "attached_dev");
1134 } 1139 }
1140 phy_suspend(phydev);
1135 phydev->attached_dev->phydev = NULL; 1141 phydev->attached_dev->phydev = NULL;
1136 phydev->attached_dev = NULL; 1142 phydev->attached_dev = NULL;
1137 phy_suspend(phydev);
1138 phydev->phylink = NULL; 1143 phydev->phylink = NULL;
1139 1144
1140 phy_led_triggers_unregister(phydev); 1145 phy_led_triggers_unregister(phydev);
@@ -1168,12 +1173,13 @@ EXPORT_SYMBOL(phy_detach);
1168int phy_suspend(struct phy_device *phydev) 1173int phy_suspend(struct phy_device *phydev)
1169{ 1174{
1170 struct phy_driver *phydrv = to_phy_driver(phydev->mdio.dev.driver); 1175 struct phy_driver *phydrv = to_phy_driver(phydev->mdio.dev.driver);
1176 struct net_device *netdev = phydev->attached_dev;
1171 struct ethtool_wolinfo wol = { .cmd = ETHTOOL_GWOL }; 1177 struct ethtool_wolinfo wol = { .cmd = ETHTOOL_GWOL };
1172 int ret = 0; 1178 int ret = 0;
1173 1179
1174 /* If the device has WOL enabled, we cannot suspend the PHY */ 1180 /* If the device has WOL enabled, we cannot suspend the PHY */
1175 phy_ethtool_get_wol(phydev, &wol); 1181 phy_ethtool_get_wol(phydev, &wol);
1176 if (wol.wolopts) 1182 if (wol.wolopts || (netdev && netdev->wol_enabled))
1177 return -EBUSY; 1183 return -EBUSY;
1178 1184
1179 if (phydev->drv && phydrv->suspend) 1185 if (phydev->drv && phydrv->suspend)
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index ca5ab98053c8..c7861e4b402c 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1730,6 +1730,8 @@ enum netdev_priv_flags {
1730 * switch driver and used to set the phys state of the 1730 * switch driver and used to set the phys state of the
1731 * switch port. 1731 * switch port.
1732 * 1732 *
1733 * @wol_enabled: Wake-on-LAN is enabled
1734 *
1733 * FIXME: cleanup struct net_device such that network protocol info 1735 * FIXME: cleanup struct net_device such that network protocol info
1734 * moves out. 1736 * moves out.
1735 */ 1737 */
@@ -2014,6 +2016,7 @@ struct net_device {
2014 struct lock_class_key *qdisc_tx_busylock; 2016 struct lock_class_key *qdisc_tx_busylock;
2015 struct lock_class_key *qdisc_running_key; 2017 struct lock_class_key *qdisc_running_key;
2016 bool proto_down; 2018 bool proto_down;
2019 unsigned wol_enabled:1;
2017}; 2020};
2018#define to_net_dev(d) container_of(d, struct net_device, dev) 2021#define to_net_dev(d) container_of(d, struct net_device, dev)
2019 2022
diff --git a/net/core/ethtool.c b/net/core/ethtool.c
index 234a0ec2e932..0762aaf8e964 100644
--- a/net/core/ethtool.c
+++ b/net/core/ethtool.c
@@ -1483,6 +1483,7 @@ static int ethtool_get_wol(struct net_device *dev, char __user *useraddr)
1483static int ethtool_set_wol(struct net_device *dev, char __user *useraddr) 1483static int ethtool_set_wol(struct net_device *dev, char __user *useraddr)
1484{ 1484{
1485 struct ethtool_wolinfo wol; 1485 struct ethtool_wolinfo wol;
1486 int ret;
1486 1487
1487 if (!dev->ethtool_ops->set_wol) 1488 if (!dev->ethtool_ops->set_wol)
1488 return -EOPNOTSUPP; 1489 return -EOPNOTSUPP;
@@ -1490,7 +1491,13 @@ static int ethtool_set_wol(struct net_device *dev, char __user *useraddr)
1490 if (copy_from_user(&wol, useraddr, sizeof(wol))) 1491 if (copy_from_user(&wol, useraddr, sizeof(wol)))
1491 return -EFAULT; 1492 return -EFAULT;
1492 1493
1493 return dev->ethtool_ops->set_wol(dev, &wol); 1494 ret = dev->ethtool_ops->set_wol(dev, &wol);
1495 if (ret)
1496 return ret;
1497
1498 dev->wol_enabled = !!wol.wolopts;
1499
1500 return 0;
1494} 1501}
1495 1502
1496static int ethtool_get_eee(struct net_device *dev, char __user *useraddr) 1503static int ethtool_get_eee(struct net_device *dev, char __user *useraddr)