Add suspend and resume functionality.

Signed-off-by: Madalin Bucur <madalin.bu...@freescale.com>
---
 drivers/net/ethernet/freescale/dpaa/dpaa_eth.c | 109 +++++++++++++++++++++++++
 drivers/net/ethernet/freescale/dpaa/dpaa_eth.h |   9 ++
 2 files changed, 118 insertions(+)

diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c 
b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
index 96a7cee..76b05c1 100644
--- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
+++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
@@ -87,6 +87,110 @@ MODULE_PARM_DESC(tx_timeout, "The Tx timeout in ms");
 
 static u8 dpa_priv_common_bpid;
 
+#ifdef CONFIG_PM
+
+static int dpaa_suspend(struct device *dev)
+{
+       struct net_device       *net_dev;
+       struct dpa_priv_s       *priv;
+       struct mac_device       *mac_dev;
+       int                     err = 0;
+
+       net_dev = dev_get_drvdata(dev);
+
+       if (net_dev->flags & IFF_UP) {
+               priv = netdev_priv(net_dev);
+               mac_dev = priv->mac_dev;
+
+               if (priv->wol & DPAA_WOL_MAGIC) {
+                       err = priv->mac_dev->set_wol(
+                               priv->mac_dev->get_mac_handle(mac_dev), true);
+                       if (err) {
+                               netdev_err(net_dev, "set_wol() = %d\n", err);
+                               goto set_wol_failed;
+                       }
+               }
+
+               err = fm_port_suspend(mac_dev->port_dev[RX]);
+               if (err) {
+                       netdev_err(net_dev, "fm_port_suspend(RX) = %d\n", err);
+                       goto rx_port_suspend_failed;
+               }
+
+               err = fm_port_suspend(mac_dev->port_dev[TX]);
+               if (err) {
+                       netdev_err(net_dev, "fm_port_suspend(TX) = %d\n", err);
+                       goto tx_port_suspend_failed;
+               }
+       }
+
+       return 0;
+
+tx_port_suspend_failed:
+       fm_port_resume(mac_dev->port_dev[RX]);
+rx_port_suspend_failed:
+       if (priv->wol & DPAA_WOL_MAGIC) {
+               priv->mac_dev->set_wol(priv->mac_dev->get_mac_handle(mac_dev),
+                                      false);
+       }
+set_wol_failed:
+       return err;
+}
+
+static int dpaa_resume(struct device *dev)
+{
+       struct net_device       *net_dev;
+       struct dpa_priv_s       *priv;
+       struct mac_device       *mac_dev;
+       int                     err = 0;
+
+       net_dev = dev_get_drvdata(dev);
+
+       if (net_dev->flags & IFF_UP) {
+               priv = netdev_priv(net_dev);
+               mac_dev = priv->mac_dev;
+
+               err = fm_port_resume(mac_dev->port_dev[TX]);
+               if (err) {
+                       netdev_err(net_dev, "fm_port_resume(TX) = %d\n", err);
+                       goto resume_failed;
+               }
+
+               err = fm_port_resume(mac_dev->port_dev[RX]);
+               if (err) {
+                       netdev_err(net_dev, "fm_port_resume(RX) = %d\n", err);
+                       goto resume_failed;
+               }
+
+               if (priv->wol & DPAA_WOL_MAGIC) {
+                       err = priv->mac_dev->set_wol(
+                               priv->mac_dev->get_mac_handle(mac_dev), false);
+                       if (err) {
+                               netdev_err(net_dev, "set_wol() = %d\n", err);
+                               goto resume_failed;
+                       }
+               }
+       }
+
+       return 0;
+
+resume_failed:
+       return err;
+}
+
+static const struct dev_pm_ops dpaa_pm_ops = {
+       .suspend = dpaa_suspend,
+       .resume = dpaa_resume,
+};
+
+#define DPAA_PM_OPS (&dpaa_pm_ops)
+
+#else /* CONFIG_PM */
+
+#define DPAA_PM_OPS NULL
+
+#endif /* CONFIG_PM */
+
 static void _dpa_rx_error(struct net_device *net_dev,
                          const struct dpa_priv_s       *priv,
                          struct dpa_percpu_priv_s *percpu_priv,
@@ -744,6 +848,10 @@ dpaa_eth_priv_probe(struct platform_device *pdev)
        if (err < 0)
                goto netdev_init_failed;
 
+#ifdef CONFIG_PM
+       device_set_wakeup_capable(dev, true);
+#endif
+
        pr_info("Probed interface %s\n", net_dev->name);
 
        return 0;
@@ -789,6 +897,7 @@ static struct platform_driver dpa_driver = {
        .driver = {
                .name           = KBUILD_MODNAME,
                .owner          = THIS_MODULE,
+               .pm             = DPAA_PM_OPS,
        },
        .id_table       = dpa_devtype,
        .probe          = dpaa_eth_priv_probe,
diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.h 
b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.h
index 793491f..9b70c5a 100644
--- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.h
+++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.h
@@ -128,6 +128,11 @@ struct dpa_buffer_layout_s {
 #define FSL_DPAA_ETH_MAX_BUF_COUNT     128
 #define FSL_DPAA_ETH_REFILL_THRESHOLD  80
 
+#ifdef CONFIG_PM
+/* Magic Packet wakeup */
+#define DPAA_WOL_MAGIC         0x00000001
+#endif
+
 /* More detailed FQ types - used for fine-grained WQ assignments */
 enum dpa_fq_type {
        FQ_TYPE_RX_DEFAULT = 1, /* Rx Default FQs */
@@ -244,6 +249,10 @@ struct dpa_priv_s {
 
        struct dpa_buffer_layout_s *buf_layout;
        u16 rx_headroom;
+
+#ifdef CONFIG_PM
+       u32 wol;
+#endif
 };
 
 struct fm_port_fqs {
-- 
1.7.11.7

_______________________________________________
Linuxppc-dev mailing list
Linuxppc-dev@lists.ozlabs.org
https://lists.ozlabs.org/listinfo/linuxppc-dev

Reply via email to