gianfar: Add support for hibernation
authorAnton Vorontsov <avorontsov@ru.mvista.com>
Mon, 12 Oct 2009 06:00:42 +0000 (06:00 +0000)
committerDavid S. Miller <davem@davemloft.net>
Tue, 13 Oct 2009 06:54:05 +0000 (23:54 -0700)
Thanks to various cleanups and refactorings this is now straightforward:
convert the gianfar driver to dev_pm_ops, plus add ->restore() callback
that will fully reinitialize MAC internal registers and BDs.

Note that I kept legacy suspend/resume callbacks so that this patch
doesn't depend on PowerPC changes (i.e. dev_pm_ops support for OF
platform drivers).

Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/gianfar.c

index c2a508f..c6f6d3b 100644 (file)
@@ -700,23 +700,24 @@ static int gfar_remove(struct of_device *ofdev)
 }
 
 #ifdef CONFIG_PM
-static int gfar_suspend(struct of_device *ofdev, pm_message_t state)
+
+static int gfar_suspend(struct device *dev)
 {
-       struct gfar_private *priv = dev_get_drvdata(&ofdev->dev);
-       struct net_device *dev = priv->ndev;
+       struct gfar_private *priv = dev_get_drvdata(dev);
+       struct net_device *ndev = priv->ndev;
        unsigned long flags;
        u32 tempval;
 
        int magic_packet = priv->wol_en &&
                (priv->device_flags & FSL_GIANFAR_DEV_HAS_MAGIC_PACKET);
 
-       netif_device_detach(dev);
+       netif_device_detach(ndev);
 
-       if (netif_running(dev)) {
+       if (netif_running(ndev)) {
                spin_lock_irqsave(&priv->txlock, flags);
                spin_lock(&priv->rxlock);
 
-               gfar_halt_nodisable(dev);
+               gfar_halt_nodisable(ndev);
 
                /* Disable Tx, and Rx if wake-on-LAN is disabled. */
                tempval = gfar_read(&priv->regs->maccfg1);
@@ -749,17 +750,17 @@ static int gfar_suspend(struct of_device *ofdev, pm_message_t state)
        return 0;
 }
 
-static int gfar_resume(struct of_device *ofdev)
+static int gfar_resume(struct device *dev)
 {
-       struct gfar_private *priv = dev_get_drvdata(&ofdev->dev);
-       struct net_device *dev = priv->ndev;
+       struct gfar_private *priv = dev_get_drvdata(dev);
+       struct net_device *ndev = priv->ndev;
        unsigned long flags;
        u32 tempval;
        int magic_packet = priv->wol_en &&
                (priv->device_flags & FSL_GIANFAR_DEV_HAS_MAGIC_PACKET);
 
-       if (!netif_running(dev)) {
-               netif_device_attach(dev);
+       if (!netif_running(ndev)) {
+               netif_device_attach(ndev);
                return 0;
        }
 
@@ -777,20 +778,71 @@ static int gfar_resume(struct of_device *ofdev)
        tempval &= ~MACCFG2_MPEN;
        gfar_write(&priv->regs->maccfg2, tempval);
 
-       gfar_start(dev);
+       gfar_start(ndev);
 
        spin_unlock(&priv->rxlock);
        spin_unlock_irqrestore(&priv->txlock, flags);
 
-       netif_device_attach(dev);
+       netif_device_attach(ndev);
+
+       napi_enable(&priv->napi);
+
+       return 0;
+}
+
+static int gfar_restore(struct device *dev)
+{
+       struct gfar_private *priv = dev_get_drvdata(dev);
+       struct net_device *ndev = priv->ndev;
+
+       if (!netif_running(ndev))
+               return 0;
+
+       gfar_init_bds(ndev);
+       init_registers(ndev);
+       gfar_set_mac_address(ndev);
+       gfar_init_mac(ndev);
+       gfar_start(ndev);
+
+       priv->oldlink = 0;
+       priv->oldspeed = 0;
+       priv->oldduplex = -1;
+
+       if (priv->phydev)
+               phy_start(priv->phydev);
 
+       netif_device_attach(ndev);
        napi_enable(&priv->napi);
 
        return 0;
 }
+
+static struct dev_pm_ops gfar_pm_ops = {
+       .suspend = gfar_suspend,
+       .resume = gfar_resume,
+       .freeze = gfar_suspend,
+       .thaw = gfar_resume,
+       .restore = gfar_restore,
+};
+
+#define GFAR_PM_OPS (&gfar_pm_ops)
+
+static int gfar_legacy_suspend(struct of_device *ofdev, pm_message_t state)
+{
+       return gfar_suspend(&ofdev->dev);
+}
+
+static int gfar_legacy_resume(struct of_device *ofdev)
+{
+       return gfar_resume(&ofdev->dev);
+}
+
 #else
-#define gfar_suspend NULL
-#define gfar_resume NULL
+
+#define GFAR_PM_OPS NULL
+#define gfar_legacy_suspend NULL
+#define gfar_legacy_resume NULL
+
 #endif
 
 /* Reads the controller's registers to determine what interface
@@ -2364,8 +2416,9 @@ static struct of_platform_driver gfar_driver = {
 
        .probe = gfar_probe,
        .remove = gfar_remove,
-       .suspend = gfar_suspend,
-       .resume = gfar_resume,
+       .suspend = gfar_legacy_suspend,
+       .resume = gfar_legacy_resume,
+       .driver.pm = GFAR_PM_OPS,
 };
 
 static int __init gfar_init(void)