ethernet:lpc32xx:Ethernet PHY timeout fix
authorMattRedfearn <matt.redfearn@xxx.com>
Mon, 9 Apr 2012 22:16:50 +0000 (22:16 +0000)
committerBangaragiri G <bangaragiri.g@nxp.com>
Mon, 9 Apr 2012 22:16:50 +0000 (22:16 +0000)
The lpc_mdio_read() function returns an EIO before the final
lpc_net_hard_start_xmit() is called. It turns out that this is because
jiffies rolls over 5 minutes after boot. On a build with my gcc-4.6.1
toolchain, the phy just happens to get polled at a point when jiffies is
0xFFFFFFF8. Timeout therefore becomes +2 and the timeout comparison
fails immediately. The function returns an error and does not set
LPC_ENET_MCMD back to 0. I guess this means that the phy can no longer
receive packets, hence the crc errors. The atached patch fixes the
issue.

Signed-off-by: Bangaragiri G <bangaragiri.g@nxp.com>

drivers/net/lpc_eth.c

index d99a22b..eaa58f8 100644 (file)
@@ -392,7 +392,7 @@ static void __lpc_net_shutdown(struct netdata_local *pldat)
 static int lpc_mdio_read(struct mii_bus *bus, int phy_id, int phyreg)
 {
        struct netdata_local *pldat = bus->priv;
-       unsigned long timeout = jiffies + ((HZ * 100) / 1000); /* 100mS */
+       unsigned long timeout = jiffies + msecs_to_jiffies(100);
        int lps;
 
        writel(((phy_id << 8) | phyreg), LPC_ENET_MADR(pldat->net_base));
@@ -400,7 +400,7 @@ static int lpc_mdio_read(struct mii_bus *bus, int phy_id, int phyreg)
 
        /* Wait for unbusy status */
        while (readl(LPC_ENET_MIND(pldat->net_base)) & LPC_MIND_BUSY) {
-               if (jiffies > timeout)
+               if (time_after(jiffies,timeout))
                        return -EIO;
                cpu_relax();
        }
@@ -415,14 +415,14 @@ static int lpc_mdio_write(struct mii_bus *bus, int phy_id, int phyreg,
                        u16 phydata)
 {
        struct netdata_local *pldat = bus->priv;
-       unsigned long timeout = jiffies + ((HZ * 100) / 1000); /* 100mS */
+       unsigned long timeout = jiffies + msecs_to_jiffies(100);
 
        writel(((phy_id << 8) | phyreg), LPC_ENET_MADR(pldat->net_base));
        writel(phydata, LPC_ENET_MWTD(pldat->net_base));
 
        /* Wait for completion */
        while (readl(LPC_ENET_MIND(pldat->net_base)) & LPC_MIND_BUSY) {
-               if (jiffies > timeout)
+               if (time_after(jiffies,timeout))
                        return -EIO;
                cpu_relax();
        }
@@ -637,7 +637,7 @@ static void __lpc_handle_xmit(struct net_device *ndev)
                        /* Free buffer */
                        dev_kfree_skb_irq(skb);
                }
-               
+
                txcidx = readl(LPC_ENET_TXCONSUMEINDEX(pldat->net_base));
        }
 
@@ -840,19 +840,19 @@ static int lpc_set_mac_address(struct net_device *ndev, void *p)
         struct sockaddr *addr = p;
        struct netdata_local *pldat = netdev_priv(ndev);
        unsigned long flags;
-        
+
        if (!is_valid_ether_addr(addr->sa_data))
                 return -EADDRNOTAVAIL;
         memcpy(ndev->dev_addr, addr->sa_data, ETH_ALEN);
 
        spin_lock_irqsave(&pldat->lock, flags);
-       
+
        /* Set station address */
        __lpc_set_mac(pldat, ndev->dev_addr);
 
        spin_unlock_irqrestore(&pldat->lock, flags);
 
-       return 0;       
+       return 0;
 }
 
 static void lpc_net_set_multicast_list(struct net_device *ndev)