diff options
-rw-r--r-- | drivers/net/phy/phy_device.c | 12 | ||||
-rw-r--r-- | include/linux/netdevice.h | 3 | ||||
-rw-r--r-- | net/core/ethtool.c | 9 |
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); | |||
1168 | int phy_suspend(struct phy_device *phydev) | 1173 | int 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) | |||
1483 | static int ethtool_set_wol(struct net_device *dev, char __user *useraddr) | 1483 | static 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 | ||
1496 | static int ethtool_get_eee(struct net_device *dev, char __user *useraddr) | 1503 | static int ethtool_get_eee(struct net_device *dev, char __user *useraddr) |