This is the mail archive of the
ecos-patches@sources.redhat.com
mailing list for the eCos project.
DP83816 - improve error handling
- From: Gary Thomas <gary at mlbassoc dot com>
- To: eCos patches <ecos-patches at sources dot redhat dot com>
- Date: 30 Sep 2003 15:10:57 -0600
- Subject: DP83816 - improve error handling
- Organization: MLB Associates
Plus some other cleanups.
--
Gary Thomas <gary@mlbassoc.com>
MLB Associates
Index: devs/eth/ns/dp83816/current/src/if_dp83816.c
===================================================================
RCS file: /misc/cvsfiles/ecos/packages/devs/eth/ns/dp83816/current/src/if_dp83816.c,v
retrieving revision 1.1
diff -u -5 -p -r1.1 if_dp83816.c
--- devs/eth/ns/dp83816/current/src/if_dp83816.c 30 Sep 2003 15:25:31 -0000 1.1
+++ devs/eth/ns/dp83816/current/src/if_dp83816.c 30 Sep 2003 21:03:43 -0000
@@ -96,50 +96,22 @@ dp83816_deliver(struct eth_drv_sc *sc)
// Allow interrupts to happen again
cyg_drv_interrupt_unmask(dp->interrupt);
#endif
}
-static bool
-dp83816_init(struct cyg_netdevtab_entry *tab)
+static bool
+dp83816_reset(dp83816_priv_data_t *dp)
{
- 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;
+ dp83816_bd_t *bdp;
+ cyg_uint32 stat;
int i, timeout;
- bool esa_ok;
- unsigned char enaddr[6];
- // Get physical device address
-#ifdef CYGPKG_REDBOOT
-#ifdef CYGSEM_REDBOOT_FLASH_CONFIG
- esa_ok = flash_get_config(dp->esa_key, enaddr, CONFIG_ESA);
-#else
- esa_ok = false;
-#endif
-#else
- esa_ok = CYGACC_CALL_IF_FLASH_CFG_OP(CYGNUM_CALL_IF_FLASH_CFG_GET,
- dp->esa_key, enaddr, CONFIG_ESA);
-#endif
- if (!esa_ok) {
- // Can't figure out ESA
- diag_printf("DP83816 - Warning! ESA unknown\n");
- memcpy(&enaddr, dp->enaddr, sizeof(enaddr));
- }
-
- DEBUG_FUNCTION();
-
- CYGHWR_NS_DP83816_PLF_INIT(dp);
- base = dp->base;
- if (!base) return false; // No device found
-
- DP_OUT(base, DP_CR, _CR_RST); // Reset device
+ DP_OUT(dp->base, DP_CR, _CR_RST); // Reset device
timeout = 10000;
do {
- DP_IN(base, DP_CR, stat);
+ 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;
}
@@ -150,11 +122,11 @@ dp83816_init(struct cyg_netdevtab_entry
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;
+ 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;
@@ -162,27 +134,66 @@ dp83816_init(struct cyg_netdevtab_entry
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;
+ 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, enaddr[i] | (enaddr[i+1]<<8));
+ 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;
+ bool esa_ok;
+ unsigned char enaddr[6];
+
+ // Get physical device address
+#ifdef CYGPKG_REDBOOT
+#ifdef CYGSEM_REDBOOT_FLASH_CONFIG
+ esa_ok = flash_get_config(dp->esa_key, enaddr, CONFIG_ESA);
+#else
+ esa_ok = false;
+#endif
+#else
+ esa_ok = CYGACC_CALL_IF_FLASH_CFG_OP(CYGNUM_CALL_IF_FLASH_CFG_GET,
+ dp->esa_key, enaddr, CONFIG_ESA);
+#endif
+ if (esa_ok) {
+ memcpy(dp->enaddr, enaddr, sizeof(enaddr));
+ } else {
+ // Can't figure out ESA
+ diag_printf("DP83816 - Warning! ESA unknown\n");
+ }
+
+ DEBUG_FUNCTION();
+
+ CYGHWR_NS_DP83816_PLF_INIT(dp);
+ base = dp->base;
+ if (!base) return false; // No device found
+
+ 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] );
#ifdef CYGINT_IO_ETH_INT_SUPPORT_REQUIRED
@@ -195,15 +206,14 @@ dp83816_init(struct cyg_netdevtab_entry
&dp->interrupt_handle, // handle to intr obj
&dp->interrupt_object ); // space for int obj
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;
}
static void
@@ -279,17 +289,13 @@ dp83816_send(struct eth_drv_sc *sc, stru
for (i = 0; i < sg_len; i++) {
memcpy(data, (unsigned char *)sg_list[i].buf, sg_list[i].len);
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);
}
@@ -302,16 +308,13 @@ dp83816_TxEvent(struct eth_drv_sc *sc)
DEBUG_FUNCTION();
while ((_le2h(bdp->stat) & (BD_OWN|BD_INTR)) == BD_INTR) {
// 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;
}
//
@@ -324,10 +327,11 @@ dp83816_TxEvent(struct eth_drv_sc *sc)
static void
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();
while (true) {
@@ -335,14 +339,13 @@ dp83816_RxEvent(struct eth_drv_sc *sc)
len = _le2h(bdp->stat) & BD_LENGTH_MASK;
dp->rxnext = bdp;
(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++;
}
}
}
//
@@ -369,22 +372,50 @@ dp83816_recv(struct eth_drv_sc *sc, stru
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 {
if ((stat & (_ISR_TXDESC|_ISR_TXOK)) != 0) {
dp83816_TxEvent(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);
#ifdef CYGINT_IO_ETH_INT_SUPPORT_REQUIRED
CYGHWR_NS_DP83816_PLF_INT_CLEAR(dp);
Index: devs/eth/powerpc/moab/current/include/moab_eth_dp83816.inl
===================================================================
RCS file: /misc/cvsfiles/ecos/packages/devs/eth/powerpc/moab/current/include/moab_eth_dp83816.inl,v
retrieving revision 1.2
diff -u -5 -p -r1.2 moab_eth_dp83816.inl
--- devs/eth/powerpc/moab/current/include/moab_eth_dp83816.inl 30 Sep 2003 17:50:56 -0000 1.2
+++ devs/eth/powerpc/moab/current/include/moab_eth_dp83816.inl 30 Sep 2003 21:01:11 -0000
@@ -119,11 +119,11 @@ static dp83816_priv_data_t dp83816_eth1_
dp83816_eth_txbd, // Tx buffer headers
};
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,
dp83816_can_send,
dp83816_send,
@@ -131,11 +131,11 @@ ETH_DRV_SC(dp83816_sc,
dp83816_deliver, // "pseudoDSR" called from fast net thread
dp83816_poll, // poll function, encapsulates ISR and DSR
dp83816_int_vector);
NETDEVTAB_ENTRY(dp83816_netdev,
- CYGDAT_DEVS_ETH_MOAB_ETH1_NAME,
+ "eth1",
dp83816_init,
&dp83816_sc);
#if defined(CYGPKG_REDBOOT)
#include <pkgconf/redboot.h>