net: add Runtime PM to the sh_eth driver
Add Runtime PM support to the sh_eth driver. The clock to the ethernet hardware block will be enabled as long as the network device is up. Signed-off-by: Magnus Damm <damm@opensource.se> Tested-by: Kuninori Morimoto <morimoto.kuninori@renesas.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
748031f9fd
commit
bcd5149ded
2 changed files with 34 additions and 2 deletions
|
@ -30,7 +30,7 @@
|
||||||
#include <linux/phy.h>
|
#include <linux/phy.h>
|
||||||
#include <linux/cache.h>
|
#include <linux/cache.h>
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
|
#include <linux/pm_runtime.h>
|
||||||
#include "sh_eth.h"
|
#include "sh_eth.h"
|
||||||
|
|
||||||
/* There is CPU dependent code */
|
/* There is CPU dependent code */
|
||||||
|
@ -1012,6 +1012,8 @@ static int sh_eth_open(struct net_device *ndev)
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
struct sh_eth_private *mdp = netdev_priv(ndev);
|
struct sh_eth_private *mdp = netdev_priv(ndev);
|
||||||
|
|
||||||
|
pm_runtime_get_sync(&mdp->pdev->dev);
|
||||||
|
|
||||||
ret = request_irq(ndev->irq, &sh_eth_interrupt,
|
ret = request_irq(ndev->irq, &sh_eth_interrupt,
|
||||||
#if defined(CONFIG_CPU_SUBTYPE_SH7763) || defined(CONFIG_CPU_SUBTYPE_SH7764)
|
#if defined(CONFIG_CPU_SUBTYPE_SH7763) || defined(CONFIG_CPU_SUBTYPE_SH7764)
|
||||||
IRQF_SHARED,
|
IRQF_SHARED,
|
||||||
|
@ -1048,6 +1050,7 @@ static int sh_eth_open(struct net_device *ndev)
|
||||||
|
|
||||||
out_free_irq:
|
out_free_irq:
|
||||||
free_irq(ndev->irq, ndev);
|
free_irq(ndev->irq, ndev);
|
||||||
|
pm_runtime_put_sync(&mdp->pdev->dev);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1179,6 +1182,8 @@ static int sh_eth_close(struct net_device *ndev)
|
||||||
ringsize = sizeof(struct sh_eth_txdesc) * TX_RING_SIZE;
|
ringsize = sizeof(struct sh_eth_txdesc) * TX_RING_SIZE;
|
||||||
dma_free_coherent(NULL, ringsize, mdp->tx_ring, mdp->tx_desc_dma);
|
dma_free_coherent(NULL, ringsize, mdp->tx_ring, mdp->tx_desc_dma);
|
||||||
|
|
||||||
|
pm_runtime_put_sync(&mdp->pdev->dev);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1187,6 +1192,8 @@ static struct net_device_stats *sh_eth_get_stats(struct net_device *ndev)
|
||||||
struct sh_eth_private *mdp = netdev_priv(ndev);
|
struct sh_eth_private *mdp = netdev_priv(ndev);
|
||||||
u32 ioaddr = ndev->base_addr;
|
u32 ioaddr = ndev->base_addr;
|
||||||
|
|
||||||
|
pm_runtime_get_sync(&mdp->pdev->dev);
|
||||||
|
|
||||||
mdp->stats.tx_dropped += ctrl_inl(ioaddr + TROCR);
|
mdp->stats.tx_dropped += ctrl_inl(ioaddr + TROCR);
|
||||||
ctrl_outl(0, ioaddr + TROCR); /* (write clear) */
|
ctrl_outl(0, ioaddr + TROCR); /* (write clear) */
|
||||||
mdp->stats.collisions += ctrl_inl(ioaddr + CDCR);
|
mdp->stats.collisions += ctrl_inl(ioaddr + CDCR);
|
||||||
|
@ -1202,6 +1209,8 @@ static struct net_device_stats *sh_eth_get_stats(struct net_device *ndev)
|
||||||
mdp->stats.tx_carrier_errors += ctrl_inl(ioaddr + CNDCR);
|
mdp->stats.tx_carrier_errors += ctrl_inl(ioaddr + CNDCR);
|
||||||
ctrl_outl(0, ioaddr + CNDCR); /* (write clear) */
|
ctrl_outl(0, ioaddr + CNDCR); /* (write clear) */
|
||||||
#endif
|
#endif
|
||||||
|
pm_runtime_put_sync(&mdp->pdev->dev);
|
||||||
|
|
||||||
return &mdp->stats;
|
return &mdp->stats;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1410,6 +1419,9 @@ static int sh_eth_drv_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
mdp = netdev_priv(ndev);
|
mdp = netdev_priv(ndev);
|
||||||
spin_lock_init(&mdp->lock);
|
spin_lock_init(&mdp->lock);
|
||||||
|
mdp->pdev = pdev;
|
||||||
|
pm_runtime_enable(&pdev->dev);
|
||||||
|
pm_runtime_resume(&pdev->dev);
|
||||||
|
|
||||||
pd = (struct sh_eth_plat_data *)(pdev->dev.platform_data);
|
pd = (struct sh_eth_plat_data *)(pdev->dev.platform_data);
|
||||||
/* get PHY ID */
|
/* get PHY ID */
|
||||||
|
@ -1485,18 +1497,37 @@ static int sh_eth_drv_remove(struct platform_device *pdev)
|
||||||
sh_mdio_release(ndev);
|
sh_mdio_release(ndev);
|
||||||
unregister_netdev(ndev);
|
unregister_netdev(ndev);
|
||||||
flush_scheduled_work();
|
flush_scheduled_work();
|
||||||
|
pm_runtime_disable(&pdev->dev);
|
||||||
free_netdev(ndev);
|
free_netdev(ndev);
|
||||||
platform_set_drvdata(pdev, NULL);
|
platform_set_drvdata(pdev, NULL);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int sh_eth_runtime_nop(struct device *dev)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Runtime PM callback shared between ->runtime_suspend()
|
||||||
|
* and ->runtime_resume(). Simply returns success.
|
||||||
|
*
|
||||||
|
* This driver re-initializes all registers after
|
||||||
|
* pm_runtime_get_sync() anyway so there is no need
|
||||||
|
* to save and restore registers here.
|
||||||
|
*/
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct dev_pm_ops sh_eth_dev_pm_ops = {
|
||||||
|
.runtime_suspend = sh_eth_runtime_nop,
|
||||||
|
.runtime_resume = sh_eth_runtime_nop,
|
||||||
|
};
|
||||||
|
|
||||||
static struct platform_driver sh_eth_driver = {
|
static struct platform_driver sh_eth_driver = {
|
||||||
.probe = sh_eth_drv_probe,
|
.probe = sh_eth_drv_probe,
|
||||||
.remove = sh_eth_drv_remove,
|
.remove = sh_eth_drv_remove,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = CARDNAME,
|
.name = CARDNAME,
|
||||||
|
.pm = &sh_eth_dev_pm_ops,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -703,6 +703,7 @@ struct sh_eth_cpu_data {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct sh_eth_private {
|
struct sh_eth_private {
|
||||||
|
struct platform_device *pdev;
|
||||||
struct sh_eth_cpu_data *cd;
|
struct sh_eth_cpu_data *cd;
|
||||||
dma_addr_t rx_desc_dma;
|
dma_addr_t rx_desc_dma;
|
||||||
dma_addr_t tx_desc_dma;
|
dma_addr_t tx_desc_dma;
|
||||||
|
|
Loading…
Add table
Reference in a new issue