summaryrefslogtreecommitdiffstats
path: root/drivers/net/sh_eth.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/sh_eth.c')
-rw-r--r--drivers/net/sh_eth.c65
1 files changed, 53 insertions, 12 deletions
diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c
index 528b912a4b0..7402b858cab 100644
--- a/drivers/net/sh_eth.c
+++ b/drivers/net/sh_eth.c
@@ -30,6 +30,7 @@
#include <linux/phy.h>
#include <linux/cache.h>
#include <linux/io.h>
+#include <linux/pm_runtime.h>
#include <asm/cacheflush.h>
#include "sh_eth.h"
@@ -83,6 +84,8 @@ static struct sh_eth_cpu_data sh_eth_my_cpu_data = {
.mpr = 1,
.tpauser = 1,
.hw_swap = 1,
+ .rpadir = 1,
+ .rpadir_value = 0x00020000, /* NET_IP_ALIGN assumed to be 2 */
};
#elif defined(CONFIG_CPU_SUBTYPE_SH7763)
@@ -107,7 +110,7 @@ static void sh_eth_reset(struct net_device *ndev)
mdelay(1);
cnt--;
}
- if (cnt < 0)
+ if (cnt == 0)
printk(KERN_ERR "Device reset fail\n");
/* Table Init */
@@ -174,7 +177,6 @@ static struct sh_eth_cpu_data sh_eth_my_cpu_data = {
.tpauser = 1,
.bculr = 1,
.hw_swap = 1,
- .rpadir = 1,
.no_trimd = 1,
.no_ade = 1,
};
@@ -299,16 +301,20 @@ static void update_mac_address(struct net_device *ndev)
* When you want use this device, you must set MAC address in bootloader.
*
*/
-static void read_mac_address(struct net_device *ndev)
+static void read_mac_address(struct net_device *ndev, unsigned char *mac)
{
u32 ioaddr = ndev->base_addr;
- ndev->dev_addr[0] = (ctrl_inl(ioaddr + MAHR) >> 24);
- ndev->dev_addr[1] = (ctrl_inl(ioaddr + MAHR) >> 16) & 0xFF;
- ndev->dev_addr[2] = (ctrl_inl(ioaddr + MAHR) >> 8) & 0xFF;
- ndev->dev_addr[3] = (ctrl_inl(ioaddr + MAHR) & 0xFF);
- ndev->dev_addr[4] = (ctrl_inl(ioaddr + MALR) >> 8) & 0xFF;
- ndev->dev_addr[5] = (ctrl_inl(ioaddr + MALR) & 0xFF);
+ if (mac[0] || mac[1] || mac[2] || mac[3] || mac[4] || mac[5]) {
+ memcpy(ndev->dev_addr, mac, 6);
+ } else {
+ ndev->dev_addr[0] = (ctrl_inl(ioaddr + MAHR) >> 24);
+ ndev->dev_addr[1] = (ctrl_inl(ioaddr + MAHR) >> 16) & 0xFF;
+ ndev->dev_addr[2] = (ctrl_inl(ioaddr + MAHR) >> 8) & 0xFF;
+ ndev->dev_addr[3] = (ctrl_inl(ioaddr + MAHR) & 0xFF);
+ ndev->dev_addr[4] = (ctrl_inl(ioaddr + MALR) >> 8) & 0xFF;
+ ndev->dev_addr[5] = (ctrl_inl(ioaddr + MALR) & 0xFF);
+ }
}
struct bb_info {
@@ -496,6 +502,8 @@ static int sh_eth_ring_init(struct net_device *ndev)
*/
mdp->rx_buf_sz = (ndev->mtu <= 1492 ? PKT_BUF_SZ :
(((ndev->mtu + 26 + 7) & ~7) + 2 + 16));
+ if (mdp->cd->rpadir)
+ mdp->rx_buf_sz += NET_IP_ALIGN;
/* Allocate RX and TX skb rings */
mdp->rx_skbuff = kmalloc(sizeof(*mdp->rx_skbuff) * RX_RING_SIZE,
@@ -710,6 +718,8 @@ static int sh_eth_rx(struct net_device *ndev)
pkt_len + 2);
skb = mdp->rx_skbuff[entry];
mdp->rx_skbuff[entry] = NULL;
+ if (mdp->cd->rpadir)
+ skb_reserve(skb, NET_IP_ALIGN);
skb_put(skb, pkt_len);
skb->protocol = eth_type_trans(skb, ndev);
netif_rx(skb);
@@ -1009,7 +1019,9 @@ static int sh_eth_open(struct net_device *ndev)
int ret = 0;
struct sh_eth_private *mdp = netdev_priv(ndev);
- ret = request_irq(ndev->irq, &sh_eth_interrupt,
+ pm_runtime_get_sync(&mdp->pdev->dev);
+
+ ret = request_irq(ndev->irq, sh_eth_interrupt,
#if defined(CONFIG_CPU_SUBTYPE_SH7763) || defined(CONFIG_CPU_SUBTYPE_SH7764)
IRQF_SHARED,
#else
@@ -1045,6 +1057,7 @@ static int sh_eth_open(struct net_device *ndev)
out_free_irq:
free_irq(ndev->irq, ndev);
+ pm_runtime_put_sync(&mdp->pdev->dev);
return ret;
}
@@ -1176,6 +1189,8 @@ static int sh_eth_close(struct net_device *ndev)
ringsize = sizeof(struct sh_eth_txdesc) * TX_RING_SIZE;
dma_free_coherent(NULL, ringsize, mdp->tx_ring, mdp->tx_desc_dma);
+ pm_runtime_put_sync(&mdp->pdev->dev);
+
return 0;
}
@@ -1184,6 +1199,8 @@ static struct net_device_stats *sh_eth_get_stats(struct net_device *ndev)
struct sh_eth_private *mdp = netdev_priv(ndev);
u32 ioaddr = ndev->base_addr;
+ pm_runtime_get_sync(&mdp->pdev->dev);
+
mdp->stats.tx_dropped += ctrl_inl(ioaddr + TROCR);
ctrl_outl(0, ioaddr + TROCR); /* (write clear) */
mdp->stats.collisions += ctrl_inl(ioaddr + CDCR);
@@ -1199,6 +1216,8 @@ static struct net_device_stats *sh_eth_get_stats(struct net_device *ndev)
mdp->stats.tx_carrier_errors += ctrl_inl(ioaddr + CNDCR);
ctrl_outl(0, ioaddr + CNDCR); /* (write clear) */
#endif
+ pm_runtime_put_sync(&mdp->pdev->dev);
+
return &mdp->stats;
}
@@ -1407,6 +1426,9 @@ static int sh_eth_drv_probe(struct platform_device *pdev)
mdp = netdev_priv(ndev);
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);
/* get PHY ID */
@@ -1428,7 +1450,7 @@ static int sh_eth_drv_probe(struct platform_device *pdev)
mdp->post_fw = POST_FW >> (devno << 1);
/* read and set MAC address */
- read_mac_address(ndev);
+ read_mac_address(ndev, pd->mac_addr);
/* First device only init */
if (!devno) {
@@ -1482,18 +1504,37 @@ static int sh_eth_drv_remove(struct platform_device *pdev)
sh_mdio_release(ndev);
unregister_netdev(ndev);
flush_scheduled_work();
-
+ pm_runtime_disable(&pdev->dev);
free_netdev(ndev);
platform_set_drvdata(pdev, NULL);
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 = {
.probe = sh_eth_drv_probe,
.remove = sh_eth_drv_remove,
.driver = {
.name = CARDNAME,
+ .pm = &sh_eth_dev_pm_ops,
},
};