V4L/DVB: v4l2-dev: remove unnecessary lock around atomic clear_bit
[safe/jmp/linux-2.6] / drivers / net / sh_eth.c
index a2d82dd..6242b85 100644 (file)
@@ -30,6 +30,9 @@
 #include <linux/phy.h>
 #include <linux/cache.h>
 #include <linux/io.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+#include <asm/cacheflush.h>
 
 #include "sh_eth.h"
 
@@ -82,6 +85,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)
@@ -106,7 +111,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 */
@@ -173,7 +178,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,
 };
@@ -298,16 +302,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 {
@@ -495,6 +503,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,
@@ -709,6 +719,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);
@@ -772,13 +784,15 @@ static void sh_eth_error(struct net_device *ndev, int intr_status)
                        mdp->stats.tx_carrier_errors++;
                if (felic_stat & ECSR_LCHNG) {
                        /* Link Changed */
-                       if (mdp->cd->no_psr) {
+                       if (mdp->cd->no_psr || mdp->no_ether_link) {
                                if (mdp->link == PHY_DOWN)
                                        link_stat = 0;
                                else
                                        link_stat = PHY_ST_LINK;
                        } else {
                                link_stat = (ctrl_inl(ioaddr + PSR));
+                               if (mdp->ether_link_active_low)
+                                       link_stat = ~link_stat;
                        }
                        if (!(link_stat & PHY_ST_LINK)) {
                                /* Link Down : disable tx and rx */
@@ -1006,7 +1020,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
@@ -1042,6 +1058,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;
 }
 
@@ -1133,7 +1150,7 @@ static int sh_eth_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 
        ndev->trans_start = jiffies;
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /* device close function */
@@ -1173,6 +1190,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;
 }
 
@@ -1181,6 +1200,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);
@@ -1196,6 +1217,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;
 }
 
@@ -1404,12 +1427,17 @@ 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 */
        mdp->phy_id = pd->phy;
        /* EDMAC endian */
        mdp->edmac_endian = pd->edmac_endian;
+       mdp->no_ether_link = pd->no_ether_link;
+       mdp->ether_link_active_low = pd->ether_link_active_low;
 
        /* set cpu data */
        mdp->cd = &sh_eth_my_cpu_data;
@@ -1423,7 +1451,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) {
@@ -1446,13 +1474,9 @@ static int sh_eth_drv_probe(struct platform_device *pdev)
        if (ret)
                goto out_unregister;
 
-       /* pritnt device infomation */
-       pr_info("Base address at 0x%x, ",
-              (u32)ndev->base_addr);
-
-       for (i = 0; i < 5; i++)
-               printk("%02X:", ndev->dev_addr[i]);
-       printk("%02X, IRQ %d.\n", ndev->dev_addr[i], ndev->irq);
+       /* print device infomation */
+       pr_info("Base address at 0x%x, %pM, IRQ %d.\n",
+              (u32)ndev->base_addr, ndev->dev_addr, ndev->irq);
 
        platform_set_drvdata(pdev, ndev);
 
@@ -1477,18 +1501,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,
        },
 };