diff options
Diffstat (limited to 'drivers/net/ucc_geth.c')
-rw-r--r-- | drivers/net/ucc_geth.c | 85 |
1 files changed, 85 insertions, 0 deletions
diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c index d2ca61d3dffc..7fb96f33bade 100644 --- a/drivers/net/ucc_geth.c +++ b/drivers/net/ucc_geth.c @@ -3497,6 +3497,10 @@ static int ucc_geth_open(struct net_device *dev) napi_enable(&ugeth->napi); netif_start_queue(dev); + device_set_wakeup_capable(&dev->dev, + qe_alive_during_sleep() || ugeth->phydev->irq); + device_set_wakeup_enable(&dev->dev, ugeth->wol_en); + return err; err: @@ -3561,6 +3565,85 @@ static void ucc_geth_timeout(struct net_device *dev) schedule_work(&ugeth->timeout_work); } + +#ifdef CONFIG_PM + +static int ucc_geth_suspend(struct of_device *ofdev, pm_message_t state) +{ + struct net_device *ndev = dev_get_drvdata(&ofdev->dev); + struct ucc_geth_private *ugeth = netdev_priv(ndev); + + if (!netif_running(ndev)) + return 0; + + napi_disable(&ugeth->napi); + + /* + * Disable the controller, otherwise we'll wakeup on any network + * activity. + */ + ugeth_disable(ugeth, COMM_DIR_RX_AND_TX); + + if (ugeth->wol_en & WAKE_MAGIC) { + setbits32(ugeth->uccf->p_uccm, UCC_GETH_UCCE_MPD); + setbits32(&ugeth->ug_regs->maccfg2, MACCFG2_MPE); + ucc_fast_enable(ugeth->uccf, COMM_DIR_RX_AND_TX); + } else if (!(ugeth->wol_en & WAKE_PHY)) { + phy_stop(ugeth->phydev); + } + + return 0; +} + +static int ucc_geth_resume(struct of_device *ofdev) +{ + struct net_device *ndev = dev_get_drvdata(&ofdev->dev); + struct ucc_geth_private *ugeth = netdev_priv(ndev); + int err; + + if (!netif_running(ndev)) + return 0; + + if (qe_alive_during_sleep()) { + if (ugeth->wol_en & WAKE_MAGIC) { + ucc_fast_disable(ugeth->uccf, COMM_DIR_RX_AND_TX); + clrbits32(&ugeth->ug_regs->maccfg2, MACCFG2_MPE); + clrbits32(ugeth->uccf->p_uccm, UCC_GETH_UCCE_MPD); + } + ugeth_enable(ugeth, COMM_DIR_RX_AND_TX); + } else { + /* + * Full reinitialization is required if QE shuts down + * during sleep. + */ + ucc_geth_memclean(ugeth); + + err = ucc_geth_init_mac(ugeth); + if (err) { + ugeth_err("%s: Cannot initialize MAC, aborting.", + ndev->name); + return err; + } + } + + ugeth->oldlink = 0; + ugeth->oldspeed = 0; + ugeth->oldduplex = -1; + + phy_stop(ugeth->phydev); + phy_start(ugeth->phydev); + + napi_enable(&ugeth->napi); + netif_start_queue(ndev); + + return 0; +} + +#else +#define ucc_geth_suspend NULL +#define ucc_geth_resume NULL +#endif + static phy_interface_t to_phy_interface(const char *phy_connection_type) { if (strcasecmp(phy_connection_type, "mii") == 0) @@ -3852,6 +3935,8 @@ static struct of_platform_driver ucc_geth_driver = { .match_table = ucc_geth_match, .probe = ucc_geth_probe, .remove = ucc_geth_remove, + .suspend = ucc_geth_suspend, + .resume = ucc_geth_resume, }; static int __init ucc_geth_init(void) |