diff options
author | Harini Katakam <harini.katakam@xilinx.com> | 2019-03-01 16:20:34 +0530 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2019-03-03 13:51:37 -0800 |
commit | d54f89af6cc4d6dd6a0bec2e21e1bafa8bd27c8e (patch) | |
tree | 1f2af9f7afbf9b8ad91526d2eeb1505eb776d301 /drivers/net/ethernet/cadence | |
parent | f5473d1d44e4b427b72824436b74a705f9eaf4b4 (diff) | |
download | linux-d54f89af6cc4d6dd6a0bec2e21e1bafa8bd27c8e.tar.gz |
net: macb: Add pm runtime support
Add runtime pm functions and move clock handling there.
Add runtime PM calls to mdio functions to allow for active mdio bus.
Signed-off-by: Shubhrajyoti Datta <shubhrajyoti.datta@xilinx.com>
Signed-off-by: Harini Katakam <harini.katakam@xilinx.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/cadence')
-rw-r--r-- | drivers/net/ethernet/cadence/macb_main.c | 148 |
1 files changed, 112 insertions, 36 deletions
diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c index be10ee4c791f..5173c02e292e 100644 --- a/drivers/net/ethernet/cadence/macb_main.c +++ b/drivers/net/ethernet/cadence/macb_main.c @@ -37,6 +37,7 @@ #include <linux/udp.h> #include <linux/tcp.h> #include <linux/iopoll.h> +#include <linux/pm_runtime.h> #include "macb.h" #define MACB_RX_BUFFER_SIZE 128 @@ -80,6 +81,8 @@ */ #define MACB_HALT_TIMEOUT 1230 +#define MACB_PM_TIMEOUT 100 /* ms */ + #define MACB_MDIO_TIMEOUT 1000000 /* in usecs */ /* DMA buffer descriptor might be different size @@ -332,12 +335,15 @@ static int macb_mdio_wait_for_idle(struct macb *bp) static int macb_mdio_read(struct mii_bus *bus, int mii_id, int regnum) { struct macb *bp = bus->priv; - int value; - int err; + int status; - err = macb_mdio_wait_for_idle(bp); - if (err < 0) - return err; + status = pm_runtime_get_sync(&bp->pdev->dev); + if (status < 0) + goto mdio_pm_exit; + + status = macb_mdio_wait_for_idle(bp); + if (status < 0) + goto mdio_read_exit; macb_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_SOF) | MACB_BF(RW, MACB_MAN_READ) @@ -345,24 +351,32 @@ static int macb_mdio_read(struct mii_bus *bus, int mii_id, int regnum) | MACB_BF(REGA, regnum) | MACB_BF(CODE, MACB_MAN_CODE))); - err = macb_mdio_wait_for_idle(bp); - if (err < 0) - return err; + status = macb_mdio_wait_for_idle(bp); + if (status < 0) + goto mdio_read_exit; - value = MACB_BFEXT(DATA, macb_readl(bp, MAN)); + status = MACB_BFEXT(DATA, macb_readl(bp, MAN)); - return value; +mdio_read_exit: + pm_runtime_mark_last_busy(&bp->pdev->dev); + pm_runtime_put_autosuspend(&bp->pdev->dev); +mdio_pm_exit: + return status; } static int macb_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 value) { struct macb *bp = bus->priv; - int err; + int status; - err = macb_mdio_wait_for_idle(bp); - if (err < 0) - return err; + status = pm_runtime_get_sync(&bp->pdev->dev); + if (status < 0) + goto mdio_pm_exit; + + status = macb_mdio_wait_for_idle(bp); + if (status < 0) + goto mdio_write_exit; macb_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_SOF) | MACB_BF(RW, MACB_MAN_WRITE) @@ -371,11 +385,15 @@ static int macb_mdio_write(struct mii_bus *bus, int mii_id, int regnum, | MACB_BF(CODE, MACB_MAN_CODE) | MACB_BF(DATA, value))); - err = macb_mdio_wait_for_idle(bp); - if (err < 0) - return err; + status = macb_mdio_wait_for_idle(bp); + if (status < 0) + goto mdio_write_exit; - return 0; +mdio_write_exit: + pm_runtime_mark_last_busy(&bp->pdev->dev); + pm_runtime_put_autosuspend(&bp->pdev->dev); +mdio_pm_exit: + return status; } /** @@ -2418,12 +2436,18 @@ static int macb_open(struct net_device *dev) netdev_dbg(bp->dev, "open\n"); + err = pm_runtime_get_sync(&bp->pdev->dev); + if (err < 0) + goto pm_exit; + /* carrier starts down */ netif_carrier_off(dev); /* if the phy is not yet register, retry later*/ - if (!dev->phydev) - return -EAGAIN; + if (!dev->phydev) { + err = -EAGAIN; + goto pm_exit; + } /* RX buffers initialization */ macb_init_rx_buffer_size(bp, bufsz); @@ -2432,7 +2456,7 @@ static int macb_open(struct net_device *dev) if (err) { netdev_err(dev, "Unable to allocate DMA memory (error %d)\n", err); - return err; + goto pm_exit; } bp->macbgem_ops.mog_init_rings(bp); @@ -2449,6 +2473,11 @@ static int macb_open(struct net_device *dev) if (bp->ptp_info) bp->ptp_info->ptp_init(dev); +pm_exit: + if (err) { + pm_runtime_put_sync(&bp->pdev->dev); + return err; + } return 0; } @@ -2477,6 +2506,8 @@ static int macb_close(struct net_device *dev) if (bp->ptp_info) bp->ptp_info->ptp_remove(dev); + pm_runtime_put(&bp->pdev->dev); + return 0; } @@ -4043,6 +4074,11 @@ static int macb_probe(struct platform_device *pdev) if (err) return err; + pm_runtime_set_autosuspend_delay(&pdev->dev, MACB_PM_TIMEOUT); + pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_get_noresume(&pdev->dev); + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); native_io = hw_is_native_io(mem); macb_probe_queues(mem, native_io, &queue_mask, &num_queues); @@ -4178,6 +4214,9 @@ static int macb_probe(struct platform_device *pdev) macb_is_gem(bp) ? "GEM" : "MACB", macb_readl(bp, MID), dev->base_addr, dev->irq, dev->dev_addr); + pm_runtime_mark_last_busy(&bp->pdev->dev); + pm_runtime_put_autosuspend(&bp->pdev->dev); + return 0; err_out_unregister_mdio: @@ -4197,6 +4236,9 @@ err_disable_clocks: clk_disable_unprepare(pclk); clk_disable_unprepare(rx_clk); clk_disable_unprepare(tsu_clk); + pm_runtime_disable(&pdev->dev); + pm_runtime_set_suspended(&pdev->dev); + pm_runtime_dont_use_autosuspend(&pdev->dev); return err; } @@ -4220,11 +4262,16 @@ static int macb_remove(struct platform_device *pdev) mdiobus_free(bp->mii_bus); unregister_netdev(dev); - clk_disable_unprepare(bp->tx_clk); - clk_disable_unprepare(bp->hclk); - clk_disable_unprepare(bp->pclk); - clk_disable_unprepare(bp->rx_clk); - clk_disable_unprepare(bp->tsu_clk); + pm_runtime_disable(&pdev->dev); + pm_runtime_dont_use_autosuspend(&pdev->dev); + if (!pm_runtime_suspended(&pdev->dev)) { + clk_disable_unprepare(bp->tx_clk); + clk_disable_unprepare(bp->hclk); + clk_disable_unprepare(bp->pclk); + clk_disable_unprepare(bp->rx_clk); + clk_disable_unprepare(bp->tsu_clk); + pm_runtime_set_suspended(&pdev->dev); + } of_node_put(bp->phy_node); free_netdev(dev); } @@ -4244,13 +4291,9 @@ static int __maybe_unused macb_suspend(struct device *dev) macb_writel(bp, IER, MACB_BIT(WOL)); macb_writel(bp, WOL, MACB_BIT(MAG)); enable_irq_wake(bp->queues[0].irq); - } else { - clk_disable_unprepare(bp->tx_clk); - clk_disable_unprepare(bp->hclk); - clk_disable_unprepare(bp->pclk); - clk_disable_unprepare(bp->rx_clk); } - clk_disable_unprepare(bp->tsu_clk); + + pm_runtime_force_suspend(dev); return 0; } @@ -4260,11 +4303,43 @@ static int __maybe_unused macb_resume(struct device *dev) struct net_device *netdev = dev_get_drvdata(dev); struct macb *bp = netdev_priv(netdev); + pm_runtime_force_resume(dev); + if (bp->wol & MACB_WOL_ENABLED) { macb_writel(bp, IDR, MACB_BIT(WOL)); macb_writel(bp, WOL, 0); disable_irq_wake(bp->queues[0].irq); - } else { + } + + netif_device_attach(netdev); + + return 0; +} + +static int __maybe_unused macb_runtime_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct net_device *netdev = platform_get_drvdata(pdev); + struct macb *bp = netdev_priv(netdev); + + if (!(device_may_wakeup(&bp->dev->dev))) { + clk_disable_unprepare(bp->tx_clk); + clk_disable_unprepare(bp->hclk); + clk_disable_unprepare(bp->pclk); + clk_disable_unprepare(bp->rx_clk); + } + clk_disable_unprepare(bp->tsu_clk); + + return 0; +} + +static int __maybe_unused macb_runtime_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct net_device *netdev = platform_get_drvdata(pdev); + struct macb *bp = netdev_priv(netdev); + + if (!(device_may_wakeup(&bp->dev->dev))) { clk_prepare_enable(bp->pclk); clk_prepare_enable(bp->hclk); clk_prepare_enable(bp->tx_clk); @@ -4272,12 +4347,13 @@ static int __maybe_unused macb_resume(struct device *dev) } clk_prepare_enable(bp->tsu_clk); - netif_device_attach(netdev); - return 0; } -static SIMPLE_DEV_PM_OPS(macb_pm_ops, macb_suspend, macb_resume); +static const struct dev_pm_ops macb_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(macb_suspend, macb_resume) + SET_RUNTIME_PM_OPS(macb_runtime_suspend, macb_runtime_resume, NULL) +}; static struct platform_driver macb_driver = { .probe = macb_probe, |