]> err.no Git - linux-2.6/commitdiff
DM9000: Fix delays used by EEPROM read and write
authorBen Dooks <ben-linux@fluff.org>
Tue, 5 Feb 2008 00:02:17 +0000 (00:02 +0000)
committerJeff Garzik <jeff@garzik.org>
Mon, 11 Feb 2008 16:06:33 +0000 (11:06 -0500)
The code was using a delay of 8ms, when it should have been
using the EEPROM status flag from the device to indicate the
EEPROM transaction had finished.

Signed-off-by: Ben Dooks <ben-linux@fluff.org>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
drivers/net/dm9000.c

index 851618338b2e0499efe24ec9acfa5e2f51fcce9e..1d790a8e3a98456fe7cbd97064f1685356830e6e 100644 (file)
@@ -1048,6 +1048,50 @@ dm9000_rx(struct net_device *dev)
        } while (rxbyte == DM9000_PKT_RDY);
 }
 
+static unsigned int
+dm9000_read_locked(board_info_t *db, int reg)
+{
+       unsigned long flags;
+       unsigned int ret;
+
+       spin_lock_irqsave(&db->lock, flags);
+       ret = ior(db, reg);
+       spin_unlock_irqrestore(&db->lock, flags);
+
+       return ret;
+}
+
+static int dm9000_wait_eeprom(board_info_t *db)
+{
+       unsigned int status;
+       int timeout = 8;        /* wait max 8msec */
+
+       /* The DM9000 data sheets say we should be able to
+        * poll the ERRE bit in EPCR to wait for the EEPROM
+        * operation. From testing several chips, this bit
+        * does not seem to work. 
+        *
+        * We attempt to use the bit, but fall back to the
+        * timeout (which is why we do not return an error
+        * on expiry) to say that the EEPROM operation has
+        * completed.
+        */
+
+       while (1) {
+               status = dm9000_read_locked(db, DM9000_EPCR);
+
+               if ((status & EPCR_ERRE) == 0)
+                       break;
+
+               if (timeout-- < 0) {
+                       dev_dbg(db->dev, "timeout waiting EEPROM\n");
+                       break;
+               }
+       }
+
+       return 0;
+}
+
 /*
  *  Read a word data from EEPROM
  */
@@ -1065,8 +1109,10 @@ dm9000_read_eeprom(board_info_t *db, int offset, u8 *to)
 
        spin_unlock_irqrestore(&db->lock, flags);
 
-       mdelay(8);              /* according to the datasheet 200us should be enough,
-                                  but it doesn't work */
+       dm9000_wait_eeprom(db);
+
+       /* delay for at-least 150uS */
+       msleep(1);
 
        spin_lock_irqsave(&db->lock, flags);
 
@@ -1097,7 +1143,9 @@ dm9000_write_eeprom(board_info_t *db, int offset, u8 *data)
        iow(db, DM9000_EPCR, EPCR_WEP | EPCR_ERPRW);
        spin_unlock_irqrestore(&db->lock, flags);
 
-       mdelay(8);              /* same shit */
+       dm9000_wait_eeprom(db);
+
+       mdelay(1);      /* wait at least 150uS to clear */
 
        spin_lock_irqsave(&db->lock, flags);
        iow(db, DM9000_EPCR, 0);