Skip to content

Commit

Permalink
phylib: Properly reinitialize PHYs after hibernation
Browse files Browse the repository at this point in the history
Since hibernation assumes power loss, we should fully reinitialize
PHYs (including platform fixups), as if PHYs were just attached.

This patch factors phy_init_hw() out of phy_attach_direct(), then
converts mdio_bus to dev_pm_ops and adds an appropriate restore()
callback.

Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Anton Vorontsov authored and David S. Miller committed Dec 31, 2009
1 parent 541cd3e commit 2f5cb43
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 22 deletions.
50 changes: 43 additions & 7 deletions drivers/net/phy/mdio_bus.c
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,8 @@ static int mdio_bus_match(struct device *dev, struct device_driver *drv)
(phydev->phy_id & phydrv->phy_id_mask));
}

#ifdef CONFIG_PM

static bool mdio_bus_phy_may_suspend(struct phy_device *phydev)
{
struct device_driver *drv = phydev->dev.driver;
Expand Down Expand Up @@ -295,10 +297,7 @@ static bool mdio_bus_phy_may_suspend(struct phy_device *phydev)
return true;
}

/* Suspend and resume. Copied from platform_suspend and
* platform_resume
*/
static int mdio_bus_suspend(struct device * dev, pm_message_t state)
static int mdio_bus_suspend(struct device *dev)
{
struct phy_driver *phydrv = to_phy_driver(dev->driver);
struct phy_device *phydev = to_phy_device(dev);
Expand All @@ -318,7 +317,7 @@ static int mdio_bus_suspend(struct device * dev, pm_message_t state)
return phydrv->suspend(phydev);
}

static int mdio_bus_resume(struct device * dev)
static int mdio_bus_resume(struct device *dev)
{
struct phy_driver *phydrv = to_phy_driver(dev->driver);
struct phy_device *phydev = to_phy_device(dev);
Expand All @@ -338,11 +337,48 @@ static int mdio_bus_resume(struct device * dev)
return 0;
}

static int mdio_bus_restore(struct device *dev)
{
struct phy_device *phydev = to_phy_device(dev);
struct net_device *netdev = phydev->attached_dev;
int ret;

if (!netdev)
return 0;

ret = phy_init_hw(phydev);
if (ret < 0)
return ret;

/* The PHY needs to renegotiate. */
phydev->link = 0;
phydev->state = PHY_UP;

phy_start_machine(phydev, NULL);

return 0;
}

static struct dev_pm_ops mdio_bus_pm_ops = {
.suspend = mdio_bus_suspend,
.resume = mdio_bus_resume,
.freeze = mdio_bus_suspend,
.thaw = mdio_bus_resume,
.restore = mdio_bus_restore,
};

#define MDIO_BUS_PM_OPS (&mdio_bus_pm_ops)

#else

#define MDIO_BUS_PM_OPS NULL

#endif /* CONFIG_PM */

struct bus_type mdio_bus_type = {
.name = "mdio_bus",
.match = mdio_bus_match,
.suspend = mdio_bus_suspend,
.resume = mdio_bus_resume,
.pm = MDIO_BUS_PM_OPS,
};
EXPORT_SYMBOL(mdio_bus_type);

Expand Down
30 changes: 15 additions & 15 deletions drivers/net/phy/phy_device.c
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,20 @@ void phy_disconnect(struct phy_device *phydev)
}
EXPORT_SYMBOL(phy_disconnect);

int phy_init_hw(struct phy_device *phydev)
{
int ret;

if (!phydev->drv || !phydev->drv->config_init)
return 0;

ret = phy_scan_fixups(phydev);
if (ret < 0)
return ret;

return phydev->drv->config_init(phydev);
}

/**
* phy_attach_direct - attach a network device to a given PHY device pointer
* @dev: network device to attach
Expand Down Expand Up @@ -425,21 +439,7 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
/* Do initial configuration here, now that
* we have certain key parameters
* (dev_flags and interface) */
if (phydev->drv->config_init) {
int err;

err = phy_scan_fixups(phydev);

if (err < 0)
return err;

err = phydev->drv->config_init(phydev);

if (err < 0)
return err;
}

return 0;
return phy_init_hw(phydev);
}
EXPORT_SYMBOL(phy_attach_direct);

Expand Down
1 change: 1 addition & 0 deletions include/linux/phy.h
Original file line number Diff line number Diff line change
Expand Up @@ -447,6 +447,7 @@ struct phy_device* get_phy_device(struct mii_bus *bus, int addr);
int phy_device_register(struct phy_device *phy);
int phy_clear_interrupt(struct phy_device *phydev);
int phy_config_interrupt(struct phy_device *phydev, u32 interrupts);
int phy_init_hw(struct phy_device *phydev);
int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
u32 flags, phy_interface_t interface);
struct phy_device * phy_attach(struct net_device *dev,
Expand Down

0 comments on commit 2f5cb43

Please sign in to comment.