aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMagnus Damm <damm@opensource.se>2009-10-08 20:20:04 -0400
committerDavid S. Miller <davem@davemloft.net>2009-10-13 06:44:05 -0400
commitbcd5149ded6b2edbf3732fa1483600a716b1cba6 (patch)
treead517e9c9d196a76d7b7d50602f5c82c96fac996
parent748031f9fd2c06b28817d80761a5de97190cfd03 (diff)
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>
-rw-r--r--drivers/net/sh_eth.c35
-rw-r--r--drivers/net/sh_eth.h1
2 files changed, 34 insertions, 2 deletions
diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c
index a4da7e7574eb..161181a4b3d6 100644
--- a/drivers/net/sh_eth.c
+++ b/drivers/net/sh_eth.c
@@ -30,7 +30,7 @@
30#include <linux/phy.h> 30#include <linux/phy.h>
31#include <linux/cache.h> 31#include <linux/cache.h>
32#include <linux/io.h> 32#include <linux/io.h>
33 33#include <linux/pm_runtime.h>
34#include "sh_eth.h" 34#include "sh_eth.h"
35 35
36/* There is CPU dependent code */ 36/* There is CPU dependent code */
@@ -1012,6 +1012,8 @@ static int sh_eth_open(struct net_device *ndev)
1012 int ret = 0; 1012 int ret = 0;
1013 struct sh_eth_private *mdp = netdev_priv(ndev); 1013 struct sh_eth_private *mdp = netdev_priv(ndev);
1014 1014
1015 pm_runtime_get_sync(&mdp->pdev->dev);
1016
1015 ret = request_irq(ndev->irq, &sh_eth_interrupt, 1017 ret = request_irq(ndev->irq, &sh_eth_interrupt,
1016#if defined(CONFIG_CPU_SUBTYPE_SH7763) || defined(CONFIG_CPU_SUBTYPE_SH7764) 1018#if defined(CONFIG_CPU_SUBTYPE_SH7763) || defined(CONFIG_CPU_SUBTYPE_SH7764)
1017 IRQF_SHARED, 1019 IRQF_SHARED,
@@ -1048,6 +1050,7 @@ static int sh_eth_open(struct net_device *ndev)
1048 1050
1049out_free_irq: 1051out_free_irq:
1050 free_irq(ndev->irq, ndev); 1052 free_irq(ndev->irq, ndev);
1053 pm_runtime_put_sync(&mdp->pdev->dev);
1051 return ret; 1054 return ret;
1052} 1055}
1053 1056
@@ -1179,6 +1182,8 @@ static int sh_eth_close(struct net_device *ndev)
1179 ringsize = sizeof(struct sh_eth_txdesc) * TX_RING_SIZE; 1182 ringsize = sizeof(struct sh_eth_txdesc) * TX_RING_SIZE;
1180 dma_free_coherent(NULL, ringsize, mdp->tx_ring, mdp->tx_desc_dma); 1183 dma_free_coherent(NULL, ringsize, mdp->tx_ring, mdp->tx_desc_dma);
1181 1184
1185 pm_runtime_put_sync(&mdp->pdev->dev);
1186
1182 return 0; 1187 return 0;
1183} 1188}
1184 1189
@@ -1187,6 +1192,8 @@ static struct net_device_stats *sh_eth_get_stats(struct net_device *ndev)
1187 struct sh_eth_private *mdp = netdev_priv(ndev); 1192 struct sh_eth_private *mdp = netdev_priv(ndev);
1188 u32 ioaddr = ndev->base_addr; 1193 u32 ioaddr = ndev->base_addr;
1189 1194
1195 pm_runtime_get_sync(&mdp->pdev->dev);
1196
1190 mdp->stats.tx_dropped += ctrl_inl(ioaddr + TROCR); 1197 mdp->stats.tx_dropped += ctrl_inl(ioaddr + TROCR);
1191 ctrl_outl(0, ioaddr + TROCR); /* (write clear) */ 1198 ctrl_outl(0, ioaddr + TROCR); /* (write clear) */
1192 mdp->stats.collisions += ctrl_inl(ioaddr + CDCR); 1199 mdp->stats.collisions += ctrl_inl(ioaddr + CDCR);
@@ -1202,6 +1209,8 @@ static struct net_device_stats *sh_eth_get_stats(struct net_device *ndev)
1202 mdp->stats.tx_carrier_errors += ctrl_inl(ioaddr + CNDCR); 1209 mdp->stats.tx_carrier_errors += ctrl_inl(ioaddr + CNDCR);
1203 ctrl_outl(0, ioaddr + CNDCR); /* (write clear) */ 1210 ctrl_outl(0, ioaddr + CNDCR); /* (write clear) */
1204#endif 1211#endif
1212 pm_runtime_put_sync(&mdp->pdev->dev);
1213
1205 return &mdp->stats; 1214 return &mdp->stats;
1206} 1215}
1207 1216
@@ -1410,6 +1419,9 @@ static int sh_eth_drv_probe(struct platform_device *pdev)
1410 1419
1411 mdp = netdev_priv(ndev); 1420 mdp = netdev_priv(ndev);
1412 spin_lock_init(&mdp->lock); 1421 spin_lock_init(&mdp->lock);
1422 mdp->pdev = pdev;
1423 pm_runtime_enable(&pdev->dev);
1424 pm_runtime_resume(&pdev->dev);
1413 1425
1414 pd = (struct sh_eth_plat_data *)(pdev->dev.platform_data); 1426 pd = (struct sh_eth_plat_data *)(pdev->dev.platform_data);
1415 /* get PHY ID */ 1427 /* get PHY ID */
@@ -1485,18 +1497,37 @@ static int sh_eth_drv_remove(struct platform_device *pdev)
1485 sh_mdio_release(ndev); 1497 sh_mdio_release(ndev);
1486 unregister_netdev(ndev); 1498 unregister_netdev(ndev);
1487 flush_scheduled_work(); 1499 flush_scheduled_work();
1488 1500 pm_runtime_disable(&pdev->dev);
1489 free_netdev(ndev); 1501 free_netdev(ndev);
1490 platform_set_drvdata(pdev, NULL); 1502 platform_set_drvdata(pdev, NULL);
1491 1503
1492 return 0; 1504 return 0;
1493} 1505}
1494 1506
1507static int sh_eth_runtime_nop(struct device *dev)
1508{
1509 /*
1510 * Runtime PM callback shared between ->runtime_suspend()
1511 * and ->runtime_resume(). Simply returns success.
1512 *
1513 * This driver re-initializes all registers after
1514 * pm_runtime_get_sync() anyway so there is no need
1515 * to save and restore registers here.
1516 */
1517 return 0;
1518}
1519
1520static struct dev_pm_ops sh_eth_dev_pm_ops = {
1521 .runtime_suspend = sh_eth_runtime_nop,
1522 .runtime_resume = sh_eth_runtime_nop,
1523};
1524
1495static struct platform_driver sh_eth_driver = { 1525static struct platform_driver sh_eth_driver = {
1496 .probe = sh_eth_drv_probe, 1526 .probe = sh_eth_drv_probe,
1497 .remove = sh_eth_drv_remove, 1527 .remove = sh_eth_drv_remove,
1498 .driver = { 1528 .driver = {
1499 .name = CARDNAME, 1529 .name = CARDNAME,
1530 .pm = &sh_eth_dev_pm_ops,
1500 }, 1531 },
1501}; 1532};
1502 1533
diff --git a/drivers/net/sh_eth.h b/drivers/net/sh_eth.h
index ba151f86ae7b..8b47763958f2 100644
--- a/drivers/net/sh_eth.h
+++ b/drivers/net/sh_eth.h
@@ -703,6 +703,7 @@ struct sh_eth_cpu_data {
703}; 703};
704 704
705struct sh_eth_private { 705struct sh_eth_private {
706 struct platform_device *pdev;
706 struct sh_eth_cpu_data *cd; 707 struct sh_eth_cpu_data *cd;
707 dma_addr_t rx_desc_dma; 708 dma_addr_t rx_desc_dma;
708 dma_addr_t tx_desc_dma; 709 dma_addr_t tx_desc_dma;