changeset 1258:a77bd30a9395

More cleanup, handle errors and buffer wrap better
author gthomas
date Tue, 30 Sep 2003 21:10:11 +0000
parents bfc43ab51fb2
children 13ba50dd5a8e
files packages/devs/eth/ns/dp83816/current/src/if_dp83816.c packages/devs/eth/powerpc/moab/current/include/moab_eth_dp83816.inl
diffstat 2 files changed, 105 insertions(+), 74 deletions(-) [+]
line wrap: on
line diff
--- a/packages/devs/eth/ns/dp83816/current/src/if_dp83816.c
+++ b/packages/devs/eth/ns/dp83816/current/src/if_dp83816.c
@@ -98,16 +98,71 @@ dp83816_deliver(struct eth_drv_sc *sc)
 #endif
 }
 
+static bool
+dp83816_reset(dp83816_priv_data_t *dp)
+{
+    unsigned char *bp;
+    dp83816_bd_t *bdp;
+    cyg_uint32 stat;
+    int i, timeout;
+
+    DP_OUT(dp->base, DP_CR, _CR_RST);  // Reset device
+    timeout = 10000;
+    do {
+        DP_IN(dp->base, DP_CR, stat);
+    } while (((stat & _CR_RST) != 0) && (--timeout > 0));
+    if (timeout == 0) {
+        diag_printf("DP83816 - reset timed out! - stat: %x\n", stat);
+        return false;
+    }
+    // Rx ring
+    bdp = dp->rxnext = CYGARC_UNCACHED_ADDRESS(dp->rxd);
+    bp = dp->rxbuf;
+    for (i = 0; i < dp->rxnum; i++, bdp++) {
+        bdp->next = (dp83816_bd_t *)_h2le(CYGARC_PHYSICAL_ADDRESS(bdp+1));
+        bdp->stat = _h2le(BD_INTR | _DP83816_BUFSIZE);  // Max buffer
+        bdp->buf = (unsigned char *)_h2le(CYGARC_PHYSICAL_ADDRESS(bp));
+        bp += _DP83816_BUFSIZE;
+    }
+    bdp--;  bdp->next = (dp83816_bd_t *)_h2le(CYGARC_PHYSICAL_ADDRESS(dp->rxd));
+    DP_OUT(dp->base, DP_RXCFG, _RXCFG_MXDMA_128 | ((64/32)<<_RXCFG_DRTH_SHIFT));
+    DP_OUT(dp->base, DP_RXDP, CYGARC_PHYSICAL_ADDRESS(dp->rxd));
+    // Tx ring
+    bdp = dp->txfill = dp->txint = CYGARC_UNCACHED_ADDRESS(dp->txd);
+    bp = dp->txbuf;
+    for (i = 0; i < dp->txnum; i++, bdp++) {
+        bdp->next = (dp83816_bd_t *)_h2le(CYGARC_PHYSICAL_ADDRESS(bdp+1));
+        bdp->stat = 0;  // Driver owns buffer for now
+        bdp->buf = (unsigned char *)_h2le(CYGARC_PHYSICAL_ADDRESS(bp));
+        bp += _DP83816_BUFSIZE;
+    }
+    bdp--;  bdp->next = (dp83816_bd_t *)_h2le(CYGARC_PHYSICAL_ADDRESS(dp->txd));
+    DP_OUT(dp->base, DP_TXCFG, _TXCFG_ATP |
+                               _TXCFG_MXDMA_128 |
+                               ((256/32)<<_TXCFG_FLTH_SHIFT) |
+                               ((512/32)<<_TXCFG_DRTH_SHIFT));
+    DP_OUT(dp->base, DP_TXDP, CYGARC_PHYSICAL_ADDRESS(dp->txd));
+    dp->txbusy = 0;
+    // Fill in ESA
+    for (i = 0;  i < 6;  i+=2) {
+        DP_OUT(dp->base, DP_RFCR, i);
+        DP_OUT(dp->base, DP_RFDR, dp->enaddr[i] | (dp->enaddr[i+1]<<8));
+    }
+    // Setup up acceptance criteria
+    DP_OUT(dp->base, DP_RFCR, _RFCR_RFEN | _RFCR_AAB | _RFCR_APM);
+    // Set up interrupts
+    DP_IN(dp->base, DP_ISR, stat);  // Clear any current interrupts
+    DP_OUT(dp->base, DP_IMR, 0xFFFFFFFF);  // Enable them all!
+    DP_OUT(dp->base, DP_IER, 1);
+    return true;
+}
+
 static bool 
 dp83816_init(struct cyg_netdevtab_entry *tab)
 {
     struct eth_drv_sc *sc = (struct eth_drv_sc *)tab->device_instance;
     dp83816_priv_data_t *dp = (dp83816_priv_data_t *)sc->driver_private;
     cyg_uint8 *base;
-    cyg_uint32 stat;
-    dp83816_bd_t *bdp;
-    unsigned char *bp;
-    int i, timeout;
     bool esa_ok;
     unsigned char enaddr[6];
 
@@ -122,10 +177,11 @@ dp83816_init(struct cyg_netdevtab_entry 
     esa_ok = CYGACC_CALL_IF_FLASH_CFG_OP(CYGNUM_CALL_IF_FLASH_CFG_GET,         
                                          dp->esa_key, enaddr, CONFIG_ESA);
 #endif
-    if (!esa_ok) {
+    if (esa_ok) {
+        memcpy(dp->enaddr, enaddr, sizeof(enaddr));
+    } else {
         // Can't figure out ESA
         diag_printf("DP83816 - Warning! ESA unknown\n");
-        memcpy(&enaddr, dp->enaddr, sizeof(enaddr));
     }
 
     DEBUG_FUNCTION();
@@ -134,53 +190,8 @@ dp83816_init(struct cyg_netdevtab_entry 
     base = dp->base;
     if (!base) return false;  // No device found
 
-    DP_OUT(base, DP_CR, _CR_RST);  // Reset device
-    timeout = 10000;
-    do {
-        DP_IN(base, DP_CR, stat);
-    } while (((stat & _CR_RST) != 0) && (--timeout > 0));
-    if (timeout == 0) {
-        diag_printf("DP83816 - reset timed out! - stat: %x\n", stat);
-        return false;
-    }
-    // Rx ring
-    bdp = dp->rxnext = CYGARC_UNCACHED_ADDRESS(dp->rxd);
-    bp = dp->rxbuf;
-    for (i = 0; i < dp->rxnum; i++, bdp++) {
-        bdp->next = (dp83816_bd_t *)_h2le(CYGARC_PHYSICAL_ADDRESS(bdp+1));
-        bdp->stat = _h2le(BD_INTR | _DP83816_BUFSIZE);  // Max buffer
-        bdp->buf = (unsigned char *)_h2le(CYGARC_PHYSICAL_ADDRESS(bp));
-        bp += _DP83816_BUFSIZE;
-    }
-    bdp--;  bdp->next = (dp83816_bd_t *)0;
-    DP_OUT(dp->base, DP_RXCFG, _RXCFG_MXDMA_128 | ((64/32)<<_RXCFG_DRTH_SHIFT));
-    DP_OUT(dp->base, DP_RXDP, CYGARC_PHYSICAL_ADDRESS(dp->rxd));
-    // Tx ring
-    bdp = dp->txfill = dp->txint = CYGARC_UNCACHED_ADDRESS(dp->txd);
-    bp = dp->txbuf;
-    for (i = 0; i < dp->txnum; i++, bdp++) {
-        bdp->next = (dp83816_bd_t *)_h2le(CYGARC_PHYSICAL_ADDRESS(bdp+1));
-        bdp->stat = 0;  // Driver owns buffer for now
-        bdp->buf = (unsigned char *)_h2le(CYGARC_PHYSICAL_ADDRESS(bp));
-        bp += _DP83816_BUFSIZE;
-    }
-    bdp--;  bdp->next = (dp83816_bd_t *)0;
-    DP_OUT(dp->base, DP_TXCFG, _TXCFG_ATP |
-                               _TXCFG_MXDMA_128 |
-                               ((256/32)<<_TXCFG_FLTH_SHIFT) |
-                               ((512/32)<<_TXCFG_DRTH_SHIFT));
-    DP_OUT(dp->base, DP_TXDP, CYGARC_PHYSICAL_ADDRESS(dp->txd));
-    dp->txbusy = 0;
-    // Fill in ESA
-    for (i = 0;  i < 6;  i+=2) {
-        DP_OUT(dp->base, DP_RFCR, i);
-        DP_OUT(dp->base, DP_RFDR, enaddr[i] | (enaddr[i+1]<<8));
-    }
-    // Setup up acceptance criteria
-    DP_OUT(dp->base, DP_RFCR, _RFCR_RFEN | _RFCR_AAB | _RFCR_APM);
-    // Set up interrupts
-    DP_IN(dp->base, DP_ISR, stat);  // Clear any current interrupts
-    DP_OUT(dp->base, DP_IMR, 0xFFFFFFFF);  // Enable them all!
+    if (!dp83816_reset(dp)) return false;
+
     diag_printf("DP83816 - ESA: %02x:%02x:%02x:%02x:%02x:%02x\n",
                 dp->enaddr[0], dp->enaddr[1], dp->enaddr[2],
                 dp->enaddr[3], dp->enaddr[4], dp->enaddr[5] );
@@ -197,11 +208,10 @@ dp83816_init(struct cyg_netdevtab_entry 
 
     cyg_drv_interrupt_attach(dp->interrupt_handle);
     cyg_drv_interrupt_unmask(dp->interrupt);
-    DP_OUT(dp->base, DP_IER, 1);
 #endif
 
     // Initialize upper level driver
-    (sc->funs->eth_drv->init)(sc, enaddr);
+    (sc->funs->eth_drv->init)(sc, dp->enaddr);
 
     return true;
 }
@@ -281,13 +291,9 @@ dp83816_send(struct eth_drv_sc *sc, stru
         data += sg_list[i].len;
     }
     bdp->key = key;
-    bdp->stat = _h2le(total_len | BD_OWN | BD_INTR);
+    bdp->stat = _h2le(len | BD_OWN | BD_INTR);
     dp->txbusy++;
-    if (bdp->next == (dp83816_bd_t *)0) {
-        bdp = CYGARC_UNCACHED_ADDRESS(dp->txd);
-    } else {
-        bdp++;
-    }
+    bdp = (dp83816_bd_t *)CYGARC_UNCACHED_ADDRESS(CYGARC_VIRTUAL_ADDRESS(_le2h((unsigned long)bdp->next)));
     dp->txfill = bdp;
     // Kick the device, in case it went idle
     DP_OUT(dp->base, DP_CR, _CR_TXE);
@@ -304,12 +310,9 @@ dp83816_TxEvent(struct eth_drv_sc *sc)
         // Tell higher level we sent this packet
         (sc->funs->eth_drv->tx_done)(sc, bdp->key, 0);
         bdp->stat = 0;  // retake buffer
+        bdp->key = 0;
         dp->txbusy--;
-        if (bdp->next == (dp83816_bd_t *)0) {
-            bdp = CYGARC_UNCACHED_ADDRESS(dp->txd);
-        } else {
-            bdp++;
-        }
+        bdp = (dp83816_bd_t *)CYGARC_UNCACHED_ADDRESS(CYGARC_VIRTUAL_ADDRESS(_le2h((unsigned long)bdp->next)));
     }
     dp->txint = bdp;
 }
@@ -326,6 +329,7 @@ dp83816_RxEvent(struct eth_drv_sc *sc)
 {
     struct dp83816_priv_data *dp = (struct dp83816_priv_data *)sc->driver_private;
     dp83816_bd_t *bdp = CYGARC_UNCACHED_ADDRESS(dp->rxd);
+    dp83816_bd_t *bdfirst = CYGARC_UNCACHED_ADDRESS(dp->rxd);
     int len;
 
     DEBUG_FUNCTION();
@@ -337,10 +341,9 @@ dp83816_RxEvent(struct eth_drv_sc *sc)
             (sc->funs->eth_drv->recv)(sc, len);
             bdp->stat = _h2le(BD_INTR | _DP83816_BUFSIZE);  // Give back buffer
         }
-        if (bdp->next == (dp83816_bd_t *)0) {
+        bdp = (dp83816_bd_t *)CYGARC_UNCACHED_ADDRESS(CYGARC_VIRTUAL_ADDRESS(_le2h((unsigned long)bdp->next)));
+        if (bdp == bdfirst) {
             break;
-        } else {
-            bdp++;
         }
     }
 }
@@ -371,7 +374,9 @@ static void
 dp83816_poll(struct eth_drv_sc *sc)
 {
     struct dp83816_priv_data *dp = (struct dp83816_priv_data *)sc->driver_private;
-    unsigned long stat;
+    unsigned long stat, cr_stat;
+    dp83816_bd_t *bdp;
+    int i;
 
     DP_IN(dp->base, DP_ISR, stat);
     do {
@@ -381,8 +386,34 @@ dp83816_poll(struct eth_drv_sc *sc)
         if ((stat & (_ISR_RXDESC|_ISR_RXOK)) != 0) {
             dp83816_RxEvent(sc);
         }
-        if ((stat & (_ISR_HIBERR|_ISR_TXURN|_ISR_RXORN)) != 0) {
-            diag_printf("DP83816 - major error: %x\n", stat);
+        if ((stat & (_ISR_HIBERR|_ISR_TXURN|_ISR_RXORN)) != 0) {            
+            diag_printf("DP83816 - major error: %x", stat);
+            DP_IN(dp->base, DP_CR, stat);
+            diag_printf(", cmd: %x\n", stat);
+            // Try to reset the device
+            bdp = CYGARC_UNCACHED_ADDRESS(dp->txd);
+            for (i = 0; i < dp->txnum; i++, bdp++) {
+                if (bdp->key) {
+                    (sc->funs->eth_drv->tx_done)(sc, bdp->key, 0);
+                }
+            }
+            dp83816_reset(dp);
+            DP_OUT(dp->base, DP_CR, _CR_RXE | _CR_TXE);
+        }
+        DP_IN(dp->base, DP_CR, cr_stat);
+        if (((cr_stat & _CR_RXE) == 0) ||
+            ((dp->txbusy > 1) && ((cr_stat & _CR_TXE) == 0))) {
+            // What happened?
+            diag_printf("DP83816 went to lunch? - stat: %x, txbusy: %x\n", cr_stat, dp->txbusy);
+            // Try to reset the device
+            bdp = CYGARC_UNCACHED_ADDRESS(dp->txd);
+            for (i = 0; i < dp->txnum; i++, bdp++) {
+                if (bdp->key) {
+                    (sc->funs->eth_drv->tx_done)(sc, bdp->key, 0);
+                }
+            }
+            dp83816_reset(dp);
+            DP_OUT(dp->base, DP_CR, _CR_RXE | _CR_TXE);
         }
         DP_IN(dp->base, DP_ISR, stat);
     } while (stat != 0);
--- a/packages/devs/eth/powerpc/moab/current/include/moab_eth_dp83816.inl
+++ b/packages/devs/eth/powerpc/moab/current/include/moab_eth_dp83816.inl
@@ -121,7 +121,7 @@ static dp83816_priv_data_t dp83816_eth1_
 
 ETH_DRV_SC(dp83816_sc,
            &dp83816_eth1_priv_data, // Driver specific data
-           CYGDAT_DEVS_ETH_MOAB_ETH1_NAME,
+           "eth1",
            dp83816_start,
            dp83816_stop,
            dp83816_control,
@@ -133,7 +133,7 @@ ETH_DRV_SC(dp83816_sc,
            dp83816_int_vector);
 
 NETDEVTAB_ENTRY(dp83816_netdev, 
-                CYGDAT_DEVS_ETH_MOAB_ETH1_NAME,
+                "eth1",
                 dp83816_init, 
                 &dp83816_sc);