Commit 3d1e4db2 authored by Anton Vorontsov's avatar Anton Vorontsov Committed by David S. Miller

phylib: Rework suspend/resume code to check netdev wakeup capability

In most cases (e.g. PCI drivers) MDIO and MAC controllers are
represented by the same device. But for SOC ethernets we have
separate devices. So, in SOC case, checking whether MDIO
controller may wakeup is not only makes little sense, but also
prevents us from doing per-netdevice wakeup management.

This patch reworks suspend/resume code so that now it checks
for net device's wakeup flags, not MDIO controller's ones.

Each netdevice should manage its wakeup flags, and phylib will
decide whether suspend an attached PHY or not.
Signed-off-by: default avatarAnton Vorontsov <avorontsov@ru.mvista.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 2884e5cc
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/device.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
#include <linux/skbuff.h> #include <linux/skbuff.h>
...@@ -286,33 +287,58 @@ static int mdio_bus_match(struct device *dev, struct device_driver *drv) ...@@ -286,33 +287,58 @@ static int mdio_bus_match(struct device *dev, struct device_driver *drv)
(phydev->phy_id & phydrv->phy_id_mask)); (phydev->phy_id & phydrv->phy_id_mask));
} }
static bool mdio_bus_phy_may_suspend(struct phy_device *phydev)
{
struct device_driver *drv = phydev->dev.driver;
struct phy_driver *phydrv = to_phy_driver(drv);
struct net_device *netdev = phydev->attached_dev;
if (!drv || !phydrv->suspend)
return false;
/* PHY not attached? May suspend. */
if (!netdev)
return true;
/*
* Don't suspend PHY if the attched netdev parent may wakeup.
* The parent may point to a PCI device, as in tg3 driver.
*/
if (netdev->dev.parent && device_may_wakeup(netdev->dev.parent))
return false;
/*
* Also don't suspend PHY if the netdev itself may wakeup. This
* is the case for devices w/o underlaying pwr. mgmt. aware bus,
* e.g. SoC devices.
*/
if (device_may_wakeup(&netdev->dev))
return false;
return true;
}
/* Suspend and resume. Copied from platform_suspend and /* Suspend and resume. Copied from platform_suspend and
* platform_resume * platform_resume
*/ */
static int mdio_bus_suspend(struct device * dev, pm_message_t state) static int mdio_bus_suspend(struct device * dev, pm_message_t state)
{ {
int ret = 0; struct phy_driver *phydrv = to_phy_driver(dev->driver);
struct device_driver *drv = dev->driver;
struct phy_driver *phydrv = to_phy_driver(drv);
struct phy_device *phydev = to_phy_device(dev); struct phy_device *phydev = to_phy_device(dev);
if (drv && phydrv->suspend && !device_may_wakeup(phydev->dev.parent)) if (!mdio_bus_phy_may_suspend(phydev))
ret = phydrv->suspend(phydev); return 0;
return phydrv->suspend(phydev);
return ret;
} }
static int mdio_bus_resume(struct device * dev) static int mdio_bus_resume(struct device * dev)
{ {
int ret = 0; struct phy_driver *phydrv = to_phy_driver(dev->driver);
struct device_driver *drv = dev->driver;
struct phy_driver *phydrv = to_phy_driver(drv);
struct phy_device *phydev = to_phy_device(dev); struct phy_device *phydev = to_phy_device(dev);
if (drv && phydrv->resume && !device_may_wakeup(phydev->dev.parent)) if (!mdio_bus_phy_may_suspend(phydev))
ret = phydrv->resume(phydev); return 0;
return phydrv->resume(phydev);
return ret;
} }
struct bus_type mdio_bus_type = { struct bus_type mdio_bus_type = {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment