net: mvmdio: make orion_mdio_wait_ready consistent
[cascardo/linux.git] / drivers / net / ethernet / marvell / mvmdio.c
index e2f6626..971a4c1 100644 (file)
 #define  MVMDIO_ERR_INT_SMI_DONE          0x00000010
 #define MVMDIO_ERR_INT_MASK               0x0080
 
+/*
+ * SMI Timeout measurements:
+ * - Kirkwood 88F6281 (Globalscale Dreamplug): 45us to 95us (Interrupt)
+ * - Armada 370       (Globalscale Mirabox):   41us to 43us (Polled)
+ */
+#define MVMDIO_SMI_TIMEOUT                1000 /* 1000us = 1ms */
+#define MVMDIO_SMI_POLL_INTERVAL_MIN      45
+#define MVMDIO_SMI_POLL_INTERVAL_MAX      55
+
 struct orion_mdio_dev {
        struct mutex lock;
        void __iomem *regs;
@@ -68,34 +77,33 @@ static int orion_mdio_smi_is_done(struct orion_mdio_dev *dev)
 static int orion_mdio_wait_ready(struct mii_bus *bus)
 {
        struct orion_mdio_dev *dev = bus->priv;
-       int count;
+       unsigned long timeout = usecs_to_jiffies(MVMDIO_SMI_TIMEOUT);
+       unsigned long end = jiffies + timeout;
+       int timedout = 0;
 
-       if (dev->err_interrupt <= 0) {
-               count = 0;
-               while (1) {
-                       if (orion_mdio_smi_is_done(dev))
-                               break;
+       while (1) {
+               if (orion_mdio_smi_is_done(dev))
+                       return 0;
+               else if (timedout)
+                       break;
 
-                       if (count > 100) {
-                               dev_err(bus->parent,
-                                       "Timeout: SMI busy for too long\n");
-                               return -ETIMEDOUT;
-                       }
+               if (dev->err_interrupt <= 0) {
+                       usleep_range(MVMDIO_SMI_POLL_INTERVAL_MIN,
+                                    MVMDIO_SMI_POLL_INTERVAL_MAX);
 
-                       udelay(10);
-                       count++;
-               }
-       } else {
-               if (!orion_mdio_smi_is_done(dev)) {
+                       if (time_is_before_jiffies(end))
+                               ++timedout;
+               } else {
                        wait_event_timeout(dev->smi_busy_wait,
-                               orion_mdio_smi_is_done(dev),
-                               msecs_to_jiffies(100));
-                       if (!orion_mdio_smi_is_done(dev))
-                               return -ETIMEDOUT;
-               }
+                                          orion_mdio_smi_is_done(dev),
+                                          timeout);
+
+                       ++timedout;
+               }
        }
 
-       return 0;
+       dev_err(bus->parent, "Timeout: SMI busy for too long\n");
+       return  -ETIMEDOUT;
 }
 
 static int orion_mdio_read(struct mii_bus *bus, int mii_id,