FEC: Remove endless loop in the FEC driver
authorMarek Vasut <marex@denx.de>
Wed, 29 Aug 2012 03:49:49 +0000 (03:49 +0000)
committerJoe Hershberger <joe.hershberger@ni.com>
Thu, 27 Sep 2012 17:22:09 +0000 (12:22 -0500)
The FEC hardware sometimes errors out on data transfer and hangs in
the tightloop adjusted by this patch. So add timeout into the tightloop
to make such a hang recoverable.

Signed-off-by: Marek Vasut <marex@denx.de>
Cc: Joe Hershberger <joe.hershberger@ni.com>
Cc: Fabio Estevam <festevam@gmail.com>
Cc: Otavio Salvador <otavio@ossystems.com.br>
Cc: Stefano Babic <sbabic@denx.de>
drivers/net/fec_mxc.c

index bc44d38b4265e3e8e8add7f71b4dab87009d616c..6f071e9414c6b8532ff290b21646c299775be8e0 100644 (file)
 
 DECLARE_GLOBAL_DATA_PTR;
 
+/*
+ * Timeout the transfer after 5 mS. This is usually a bit more, since
+ * the code in the tightloops this timeout is used in adds some overhead.
+ */
+#define FEC_XFER_TIMEOUT       5000
+
 #ifndef CONFIG_MII
 #error "CONFIG_MII has to be defined!"
 #endif
@@ -697,6 +703,8 @@ static int fec_send(struct eth_device *dev, void *packet, int length)
        unsigned int status;
        uint32_t size, end;
        uint32_t addr;
+       int timeout = FEC_XFER_TIMEOUT;
+       int ret = 0;
 
        /*
         * This routine transmits one frame.  This routine only accepts
@@ -764,6 +772,10 @@ static int fec_send(struct eth_device *dev, void *packet, int length)
        while (readw(&fec->tbd_base[fec->tbd_index].status) & FEC_TBD_READY) {
                udelay(1);
                invalidate_dcache_range(addr, addr + size);
+               if (!timeout--) {
+                       ret = -EINVAL;
+                       break;
+               }
        }
 
        debug("fec_send: status 0x%x index %d\n",
@@ -775,7 +787,7 @@ static int fec_send(struct eth_device *dev, void *packet, int length)
        else
                fec->tbd_index = 1;
 
-       return 0;
+       return ret;
 }
 
 /**