diff options
author | Magnus Damm <damm@opensource.se> | 2009-10-08 20:20:04 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-10-13 06:44:05 -0400 |
commit | bcd5149ded6b2edbf3732fa1483600a716b1cba6 (patch) | |
tree | ad517e9c9d196a76d7b7d50602f5c82c96fac996 | |
parent | 748031f9fd2c06b28817d80761a5de97190cfd03 (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.c | 35 | ||||
-rw-r--r-- | drivers/net/sh_eth.h | 1 |
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 | ||
1049 | out_free_irq: | 1051 | out_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 | ||
1507 | static 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 | |||
1520 | static 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 | |||
1495 | static struct platform_driver sh_eth_driver = { | 1525 | static 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 | ||
705 | struct sh_eth_private { | 705 | struct 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; |