diff options
Diffstat (limited to 'drivers/net/sh_eth.c')
-rw-r--r-- | drivers/net/sh_eth.c | 56 |
1 files changed, 46 insertions, 10 deletions
diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c index 528b912a4b0d..c88bc1013047 100644 --- a/drivers/net/sh_eth.c +++ b/drivers/net/sh_eth.c | |||
@@ -30,6 +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 | #include <linux/pm_runtime.h> | ||
33 | #include <asm/cacheflush.h> | 34 | #include <asm/cacheflush.h> |
34 | 35 | ||
35 | #include "sh_eth.h" | 36 | #include "sh_eth.h" |
@@ -299,16 +300,20 @@ static void update_mac_address(struct net_device *ndev) | |||
299 | * When you want use this device, you must set MAC address in bootloader. | 300 | * When you want use this device, you must set MAC address in bootloader. |
300 | * | 301 | * |
301 | */ | 302 | */ |
302 | static void read_mac_address(struct net_device *ndev) | 303 | static void read_mac_address(struct net_device *ndev, unsigned char *mac) |
303 | { | 304 | { |
304 | u32 ioaddr = ndev->base_addr; | 305 | u32 ioaddr = ndev->base_addr; |
305 | 306 | ||
306 | ndev->dev_addr[0] = (ctrl_inl(ioaddr + MAHR) >> 24); | 307 | if (mac[0] || mac[1] || mac[2] || mac[3] || mac[4] || mac[5]) { |
307 | ndev->dev_addr[1] = (ctrl_inl(ioaddr + MAHR) >> 16) & 0xFF; | 308 | memcpy(ndev->dev_addr, mac, 6); |
308 | ndev->dev_addr[2] = (ctrl_inl(ioaddr + MAHR) >> 8) & 0xFF; | 309 | } else { |
309 | ndev->dev_addr[3] = (ctrl_inl(ioaddr + MAHR) & 0xFF); | 310 | ndev->dev_addr[0] = (ctrl_inl(ioaddr + MAHR) >> 24); |
310 | ndev->dev_addr[4] = (ctrl_inl(ioaddr + MALR) >> 8) & 0xFF; | 311 | ndev->dev_addr[1] = (ctrl_inl(ioaddr + MAHR) >> 16) & 0xFF; |
311 | ndev->dev_addr[5] = (ctrl_inl(ioaddr + MALR) & 0xFF); | 312 | ndev->dev_addr[2] = (ctrl_inl(ioaddr + MAHR) >> 8) & 0xFF; |
313 | ndev->dev_addr[3] = (ctrl_inl(ioaddr + MAHR) & 0xFF); | ||
314 | ndev->dev_addr[4] = (ctrl_inl(ioaddr + MALR) >> 8) & 0xFF; | ||
315 | ndev->dev_addr[5] = (ctrl_inl(ioaddr + MALR) & 0xFF); | ||
316 | } | ||
312 | } | 317 | } |
313 | 318 | ||
314 | struct bb_info { | 319 | struct bb_info { |
@@ -1009,7 +1014,9 @@ static int sh_eth_open(struct net_device *ndev) | |||
1009 | int ret = 0; | 1014 | int ret = 0; |
1010 | struct sh_eth_private *mdp = netdev_priv(ndev); | 1015 | struct sh_eth_private *mdp = netdev_priv(ndev); |
1011 | 1016 | ||
1012 | ret = request_irq(ndev->irq, &sh_eth_interrupt, | 1017 | pm_runtime_get_sync(&mdp->pdev->dev); |
1018 | |||
1019 | ret = request_irq(ndev->irq, sh_eth_interrupt, | ||
1013 | #if defined(CONFIG_CPU_SUBTYPE_SH7763) || defined(CONFIG_CPU_SUBTYPE_SH7764) | 1020 | #if defined(CONFIG_CPU_SUBTYPE_SH7763) || defined(CONFIG_CPU_SUBTYPE_SH7764) |
1014 | IRQF_SHARED, | 1021 | IRQF_SHARED, |
1015 | #else | 1022 | #else |
@@ -1045,6 +1052,7 @@ static int sh_eth_open(struct net_device *ndev) | |||
1045 | 1052 | ||
1046 | out_free_irq: | 1053 | out_free_irq: |
1047 | free_irq(ndev->irq, ndev); | 1054 | free_irq(ndev->irq, ndev); |
1055 | pm_runtime_put_sync(&mdp->pdev->dev); | ||
1048 | return ret; | 1056 | return ret; |
1049 | } | 1057 | } |
1050 | 1058 | ||
@@ -1176,6 +1184,8 @@ static int sh_eth_close(struct net_device *ndev) | |||
1176 | ringsize = sizeof(struct sh_eth_txdesc) * TX_RING_SIZE; | 1184 | ringsize = sizeof(struct sh_eth_txdesc) * TX_RING_SIZE; |
1177 | dma_free_coherent(NULL, ringsize, mdp->tx_ring, mdp->tx_desc_dma); | 1185 | dma_free_coherent(NULL, ringsize, mdp->tx_ring, mdp->tx_desc_dma); |
1178 | 1186 | ||
1187 | pm_runtime_put_sync(&mdp->pdev->dev); | ||
1188 | |||
1179 | return 0; | 1189 | return 0; |
1180 | } | 1190 | } |
1181 | 1191 | ||
@@ -1184,6 +1194,8 @@ static struct net_device_stats *sh_eth_get_stats(struct net_device *ndev) | |||
1184 | struct sh_eth_private *mdp = netdev_priv(ndev); | 1194 | struct sh_eth_private *mdp = netdev_priv(ndev); |
1185 | u32 ioaddr = ndev->base_addr; | 1195 | u32 ioaddr = ndev->base_addr; |
1186 | 1196 | ||
1197 | pm_runtime_get_sync(&mdp->pdev->dev); | ||
1198 | |||
1187 | mdp->stats.tx_dropped += ctrl_inl(ioaddr + TROCR); | 1199 | mdp->stats.tx_dropped += ctrl_inl(ioaddr + TROCR); |
1188 | ctrl_outl(0, ioaddr + TROCR); /* (write clear) */ | 1200 | ctrl_outl(0, ioaddr + TROCR); /* (write clear) */ |
1189 | mdp->stats.collisions += ctrl_inl(ioaddr + CDCR); | 1201 | mdp->stats.collisions += ctrl_inl(ioaddr + CDCR); |
@@ -1199,6 +1211,8 @@ static struct net_device_stats *sh_eth_get_stats(struct net_device *ndev) | |||
1199 | mdp->stats.tx_carrier_errors += ctrl_inl(ioaddr + CNDCR); | 1211 | mdp->stats.tx_carrier_errors += ctrl_inl(ioaddr + CNDCR); |
1200 | ctrl_outl(0, ioaddr + CNDCR); /* (write clear) */ | 1212 | ctrl_outl(0, ioaddr + CNDCR); /* (write clear) */ |
1201 | #endif | 1213 | #endif |
1214 | pm_runtime_put_sync(&mdp->pdev->dev); | ||
1215 | |||
1202 | return &mdp->stats; | 1216 | return &mdp->stats; |
1203 | } | 1217 | } |
1204 | 1218 | ||
@@ -1407,6 +1421,9 @@ static int sh_eth_drv_probe(struct platform_device *pdev) | |||
1407 | 1421 | ||
1408 | mdp = netdev_priv(ndev); | 1422 | mdp = netdev_priv(ndev); |
1409 | spin_lock_init(&mdp->lock); | 1423 | spin_lock_init(&mdp->lock); |
1424 | mdp->pdev = pdev; | ||
1425 | pm_runtime_enable(&pdev->dev); | ||
1426 | pm_runtime_resume(&pdev->dev); | ||
1410 | 1427 | ||
1411 | pd = (struct sh_eth_plat_data *)(pdev->dev.platform_data); | 1428 | pd = (struct sh_eth_plat_data *)(pdev->dev.platform_data); |
1412 | /* get PHY ID */ | 1429 | /* get PHY ID */ |
@@ -1428,7 +1445,7 @@ static int sh_eth_drv_probe(struct platform_device *pdev) | |||
1428 | mdp->post_fw = POST_FW >> (devno << 1); | 1445 | mdp->post_fw = POST_FW >> (devno << 1); |
1429 | 1446 | ||
1430 | /* read and set MAC address */ | 1447 | /* read and set MAC address */ |
1431 | read_mac_address(ndev); | 1448 | read_mac_address(ndev, pd->mac_addr); |
1432 | 1449 | ||
1433 | /* First device only init */ | 1450 | /* First device only init */ |
1434 | if (!devno) { | 1451 | if (!devno) { |
@@ -1482,18 +1499,37 @@ static int sh_eth_drv_remove(struct platform_device *pdev) | |||
1482 | sh_mdio_release(ndev); | 1499 | sh_mdio_release(ndev); |
1483 | unregister_netdev(ndev); | 1500 | unregister_netdev(ndev); |
1484 | flush_scheduled_work(); | 1501 | flush_scheduled_work(); |
1485 | 1502 | pm_runtime_disable(&pdev->dev); | |
1486 | free_netdev(ndev); | 1503 | free_netdev(ndev); |
1487 | platform_set_drvdata(pdev, NULL); | 1504 | platform_set_drvdata(pdev, NULL); |
1488 | 1505 | ||
1489 | return 0; | 1506 | return 0; |
1490 | } | 1507 | } |
1491 | 1508 | ||
1509 | static int sh_eth_runtime_nop(struct device *dev) | ||
1510 | { | ||
1511 | /* | ||
1512 | * Runtime PM callback shared between ->runtime_suspend() | ||
1513 | * and ->runtime_resume(). Simply returns success. | ||
1514 | * | ||
1515 | * This driver re-initializes all registers after | ||
1516 | * pm_runtime_get_sync() anyway so there is no need | ||
1517 | * to save and restore registers here. | ||
1518 | */ | ||
1519 | return 0; | ||
1520 | } | ||
1521 | |||
1522 | static struct dev_pm_ops sh_eth_dev_pm_ops = { | ||
1523 | .runtime_suspend = sh_eth_runtime_nop, | ||
1524 | .runtime_resume = sh_eth_runtime_nop, | ||
1525 | }; | ||
1526 | |||
1492 | static struct platform_driver sh_eth_driver = { | 1527 | static struct platform_driver sh_eth_driver = { |
1493 | .probe = sh_eth_drv_probe, | 1528 | .probe = sh_eth_drv_probe, |
1494 | .remove = sh_eth_drv_remove, | 1529 | .remove = sh_eth_drv_remove, |
1495 | .driver = { | 1530 | .driver = { |
1496 | .name = CARDNAME, | 1531 | .name = CARDNAME, |
1532 | .pm = &sh_eth_dev_pm_ops, | ||
1497 | }, | 1533 | }, |
1498 | }; | 1534 | }; |
1499 | 1535 | ||