Skip to content

Commit

Permalink
net: macb: Add pm runtime support
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
harini-katakam authored and davem330 committed Mar 3, 2019
1 parent f5473d1 commit d54f89a
Showing 1 changed file with 112 additions and 36 deletions.
148 changes: 112 additions & 36 deletions drivers/net/ethernet/cadence/macb_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -332,37 +335,48 @@ 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)
| MACB_BF(PHYA, mii_id)
| 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)
Expand All @@ -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;
}

/**
Expand Down Expand Up @@ -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);
Expand All @@ -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);
Expand All @@ -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;
}

Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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:
Expand All @@ -4197,6 +4236,9 @@ static int macb_probe(struct platform_device *pdev)
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;
}
Expand All @@ -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);
}
Expand All @@ -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;
}
Expand All @@ -4260,24 +4303,57 @@ 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);
clk_prepare_enable(bp->rx_clk);
}
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,
Expand Down

0 comments on commit d54f89a

Please sign in to comment.