Merge branch 'fix/misc' into topic/misc
[pandora-kernel.git] / drivers / net / fec.c
index edfff92..768b840 100644 (file)
@@ -118,6 +118,8 @@ static unsigned char        fec_mac_default[] = {
 #define FEC_ENET_MII   ((uint)0x00800000)      /* MII interrupt */
 #define FEC_ENET_EBERR ((uint)0x00400000)      /* SDMA bus error */
 
+#define FEC_DEFAULT_IMASK (FEC_ENET_TXF | FEC_ENET_RXF | FEC_ENET_MII)
+
 /* The FEC stores dest/src/type, data, and checksum for receive packets.
  */
 #define PKT_MAXBUF_SIZE                1518
@@ -187,6 +189,7 @@ struct fec_enet_private {
        int     index;
        int     link;
        int     full_duplex;
+       struct  completion mdio_done;
 };
 
 static irqreturn_t fec_enet_interrupt(int irq, void * dev_id);
@@ -205,12 +208,12 @@ static void fec_stop(struct net_device *dev);
 #define FEC_MMFR_TA            (2 << 16)
 #define FEC_MMFR_DATA(v)       (v & 0xffff)
 
-#define FEC_MII_TIMEOUT                10000
+#define FEC_MII_TIMEOUT                1000 /* us */
 
 /* Transmitter timeout */
 #define TX_TIMEOUT (2 * HZ)
 
-static int
+static netdev_tx_t
 fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        struct fec_enet_private *fep = netdev_priv(dev);
@@ -334,6 +337,11 @@ fec_enet_interrupt(int irq, void * dev_id)
                        ret = IRQ_HANDLED;
                        fec_enet_tx(dev);
                }
+
+               if (int_events & FEC_ENET_MII) {
+                       ret = IRQ_HANDLED;
+                       complete(&fep->mdio_done);
+               }
        } while (int_events);
 
        return ret;
@@ -608,18 +616,13 @@ spin_unlock:
                phy_print_status(phy_dev);
 }
 
-/*
- * NOTE: a MII transaction is during around 25 us, so polling it...
- */
 static int fec_enet_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
 {
        struct fec_enet_private *fep = bus->priv;
-       int timeout = FEC_MII_TIMEOUT;
+       unsigned long time_left;
 
        fep->mii_timeout = 0;
-
-       /* clear MII end of transfer bit*/
-       writel(FEC_ENET_MII, fep->hwp + FEC_IEVENT);
+       init_completion(&fep->mdio_done);
 
        /* start a read op */
        writel(FEC_MMFR_ST | FEC_MMFR_OP_READ |
@@ -627,13 +630,12 @@ static int fec_enet_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
                FEC_MMFR_TA, fep->hwp + FEC_MII_DATA);
 
        /* wait for end of transfer */
-       while (!(readl(fep->hwp + FEC_IEVENT) & FEC_ENET_MII)) {
-               cpu_relax();
-               if (timeout-- < 0) {
-                       fep->mii_timeout = 1;
-                       printk(KERN_ERR "FEC: MDIO read timeout\n");
-                       return -ETIMEDOUT;
-               }
+       time_left = wait_for_completion_timeout(&fep->mdio_done,
+                       usecs_to_jiffies(FEC_MII_TIMEOUT));
+       if (time_left == 0) {
+               fep->mii_timeout = 1;
+               printk(KERN_ERR "FEC: MDIO read timeout\n");
+               return -ETIMEDOUT;
        }
 
        /* return value */
@@ -644,12 +646,10 @@ static int fec_enet_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
                           u16 value)
 {
        struct fec_enet_private *fep = bus->priv;
-       int timeout = FEC_MII_TIMEOUT;
+       unsigned long time_left;
 
        fep->mii_timeout = 0;
-
-       /* clear MII end of transfer bit*/
-       writel(FEC_ENET_MII, fep->hwp + FEC_IEVENT);
+       init_completion(&fep->mdio_done);
 
        /* start a read op */
        writel(FEC_MMFR_ST | FEC_MMFR_OP_READ |
@@ -658,13 +658,12 @@ static int fec_enet_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
                fep->hwp + FEC_MII_DATA);
 
        /* wait for end of transfer */
-       while (!(readl(fep->hwp + FEC_IEVENT) & FEC_ENET_MII)) {
-               cpu_relax();
-               if (timeout-- < 0) {
-                       fep->mii_timeout = 1;
-                       printk(KERN_ERR "FEC: MDIO write timeout\n");
-                       return -ETIMEDOUT;
-               }
+       time_left = wait_for_completion_timeout(&fep->mdio_done,
+                       usecs_to_jiffies(FEC_MII_TIMEOUT));
+       if (time_left == 0) {
+               fep->mii_timeout = 1;
+               printk(KERN_ERR "FEC: MDIO write timeout\n");
+               return -ETIMEDOUT;
        }
 
        return 0;
@@ -679,30 +678,24 @@ static int fec_enet_mii_probe(struct net_device *dev)
 {
        struct fec_enet_private *fep = netdev_priv(dev);
        struct phy_device *phy_dev = NULL;
-       int phy_addr;
+       int ret;
 
        fep->phy_dev = NULL;
 
        /* find the first phy */
-       for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) {
-               if (fep->mii_bus->phy_map[phy_addr]) {
-                       phy_dev = fep->mii_bus->phy_map[phy_addr];
-                       break;
-               }
-       }
-
+       phy_dev = phy_find_first(fep->mii_bus);
        if (!phy_dev) {
                printk(KERN_ERR "%s: no PHY found\n", dev->name);
                return -ENODEV;
        }
 
        /* attach the mac to the phy */
-       phy_dev = phy_connect(dev, dev_name(&phy_dev->dev),
+       ret = phy_connect_direct(dev, phy_dev,
                             &fec_enet_adjust_link, 0,
                             PHY_INTERFACE_MODE_MII);
-       if (IS_ERR(phy_dev)) {
+       if (ret) {
                printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name);
-               return PTR_ERR(phy_dev);
+               return ret;
        }
 
        /* mask with MAC supported features */
@@ -834,7 +827,7 @@ static int fec_enet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
        if (!phydev)
                return -ENODEV;
 
-       return phy_mii_ioctl(phydev, if_mii(rq), cmd);
+       return phy_mii_ioctl(phydev, rq, cmd);
 }
 
 static void fec_enet_free_buffers(struct net_device *dev)
@@ -1222,7 +1215,7 @@ fec_restart(struct net_device *dev, int duplex)
        writel(0, fep->hwp + FEC_R_DES_ACTIVE);
 
        /* Enable interrupts we wish to service */
-       writel(FEC_ENET_TXF | FEC_ENET_RXF, fep->hwp + FEC_IMASK);
+       writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);
 }
 
 static void
@@ -1241,11 +1234,8 @@ fec_stop(struct net_device *dev)
        /* Whack a reset.  We should wait for this. */
        writel(1, fep->hwp + FEC_ECNTRL);
        udelay(10);
-
-       /* Clear outstanding MII command interrupts. */
-       writel(FEC_ENET_MII, fep->hwp + FEC_IEVENT);
-
        writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED);
+       writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);
 }
 
 static int __devinit
@@ -1365,10 +1355,11 @@ fec_drv_remove(struct platform_device *pdev)
        return 0;
 }
 
+#ifdef CONFIG_PM
 static int
-fec_suspend(struct platform_device *dev, pm_message_t state)
+fec_suspend(struct device *dev)
 {
-       struct net_device *ndev = platform_get_drvdata(dev);
+       struct net_device *ndev = dev_get_drvdata(dev);
        struct fec_enet_private *fep;
 
        if (ndev) {
@@ -1381,9 +1372,9 @@ fec_suspend(struct platform_device *dev, pm_message_t state)
 }
 
 static int
-fec_resume(struct platform_device *dev)
+fec_resume(struct device *dev)
 {
-       struct net_device *ndev = platform_get_drvdata(dev);
+       struct net_device *ndev = dev_get_drvdata(dev);
        struct fec_enet_private *fep;
 
        if (ndev) {
@@ -1395,15 +1386,26 @@ fec_resume(struct platform_device *dev)
        return 0;
 }
 
+static const struct dev_pm_ops fec_pm_ops = {
+       .suspend        = fec_suspend,
+       .resume         = fec_resume,
+       .freeze         = fec_suspend,
+       .thaw           = fec_resume,
+       .poweroff       = fec_suspend,
+       .restore        = fec_resume,
+};
+#endif
+
 static struct platform_driver fec_driver = {
        .driver = {
-               .name    = "fec",
-               .owner   = THIS_MODULE,
+               .name   = "fec",
+               .owner  = THIS_MODULE,
+#ifdef CONFIG_PM
+               .pm     = &fec_pm_ops,
+#endif
        },
-       .probe   = fec_probe,
-       .remove  = __devexit_p(fec_drv_remove),
-       .suspend = fec_suspend,
-       .resume  = fec_resume,
+       .probe  = fec_probe,
+       .remove = __devexit_p(fec_drv_remove),
 };
 
 static int __init