diff options
Diffstat (limited to 'drivers/net/phy/mdio_bus.c')
-rw-r--r-- | drivers/net/phy/mdio_bus.c | 54 |
1 files changed, 40 insertions, 14 deletions
diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c index 811a637695ca..bb29ae3ff17d 100644 --- a/drivers/net/phy/mdio_bus.c +++ b/drivers/net/phy/mdio_bus.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <linux/interrupt.h> | 21 | #include <linux/interrupt.h> |
22 | #include <linux/init.h> | 22 | #include <linux/init.h> |
23 | #include <linux/delay.h> | 23 | #include <linux/delay.h> |
24 | #include <linux/device.h> | ||
24 | #include <linux/netdevice.h> | 25 | #include <linux/netdevice.h> |
25 | #include <linux/etherdevice.h> | 26 | #include <linux/etherdevice.h> |
26 | #include <linux/skbuff.h> | 27 | #include <linux/skbuff.h> |
@@ -286,33 +287,58 @@ static int mdio_bus_match(struct device *dev, struct device_driver *drv) | |||
286 | (phydev->phy_id & phydrv->phy_id_mask)); | 287 | (phydev->phy_id & phydrv->phy_id_mask)); |
287 | } | 288 | } |
288 | 289 | ||
290 | static bool mdio_bus_phy_may_suspend(struct phy_device *phydev) | ||
291 | { | ||
292 | struct device_driver *drv = phydev->dev.driver; | ||
293 | struct phy_driver *phydrv = to_phy_driver(drv); | ||
294 | struct net_device *netdev = phydev->attached_dev; | ||
295 | |||
296 | if (!drv || !phydrv->suspend) | ||
297 | return false; | ||
298 | |||
299 | /* PHY not attached? May suspend. */ | ||
300 | if (!netdev) | ||
301 | return true; | ||
302 | |||
303 | /* | ||
304 | * Don't suspend PHY if the attched netdev parent may wakeup. | ||
305 | * The parent may point to a PCI device, as in tg3 driver. | ||
306 | */ | ||
307 | if (netdev->dev.parent && device_may_wakeup(netdev->dev.parent)) | ||
308 | return false; | ||
309 | |||
310 | /* | ||
311 | * Also don't suspend PHY if the netdev itself may wakeup. This | ||
312 | * is the case for devices w/o underlaying pwr. mgmt. aware bus, | ||
313 | * e.g. SoC devices. | ||
314 | */ | ||
315 | if (device_may_wakeup(&netdev->dev)) | ||
316 | return false; | ||
317 | |||
318 | return true; | ||
319 | } | ||
320 | |||
289 | /* Suspend and resume. Copied from platform_suspend and | 321 | /* Suspend and resume. Copied from platform_suspend and |
290 | * platform_resume | 322 | * platform_resume |
291 | */ | 323 | */ |
292 | static int mdio_bus_suspend(struct device * dev, pm_message_t state) | 324 | static int mdio_bus_suspend(struct device * dev, pm_message_t state) |
293 | { | 325 | { |
294 | int ret = 0; | 326 | struct phy_driver *phydrv = to_phy_driver(dev->driver); |
295 | struct device_driver *drv = dev->driver; | ||
296 | struct phy_driver *phydrv = to_phy_driver(drv); | ||
297 | struct phy_device *phydev = to_phy_device(dev); | 327 | struct phy_device *phydev = to_phy_device(dev); |
298 | 328 | ||
299 | if (drv && phydrv->suspend && !device_may_wakeup(phydev->dev.parent)) | 329 | if (!mdio_bus_phy_may_suspend(phydev)) |
300 | ret = phydrv->suspend(phydev); | 330 | return 0; |
301 | 331 | return phydrv->suspend(phydev); | |
302 | return ret; | ||
303 | } | 332 | } |
304 | 333 | ||
305 | static int mdio_bus_resume(struct device * dev) | 334 | static int mdio_bus_resume(struct device * dev) |
306 | { | 335 | { |
307 | int ret = 0; | 336 | struct phy_driver *phydrv = to_phy_driver(dev->driver); |
308 | struct device_driver *drv = dev->driver; | ||
309 | struct phy_driver *phydrv = to_phy_driver(drv); | ||
310 | struct phy_device *phydev = to_phy_device(dev); | 337 | struct phy_device *phydev = to_phy_device(dev); |
311 | 338 | ||
312 | if (drv && phydrv->resume && !device_may_wakeup(phydev->dev.parent)) | 339 | if (!mdio_bus_phy_may_suspend(phydev)) |
313 | ret = phydrv->resume(phydev); | 340 | return 0; |
314 | 341 | return phydrv->resume(phydev); | |
315 | return ret; | ||
316 | } | 342 | } |
317 | 343 | ||
318 | struct bus_type mdio_bus_type = { | 344 | struct bus_type mdio_bus_type = { |