Mercurial > ecos-v2_0-branch
changeset 771:ee025918fc58
* src/if_quicc.c: Fixed several bugs, mostly dealing with getting
the device restarted after certain failures such as collisions.
* src/quicc_eth.h: Added some statistics gathering.
| author | nickg |
|---|---|
| date | Thu, 20 Mar 2003 21:31:53 +0000 |
| parents | 65a9cab241ce |
| children | f5585bc94013 |
| files | packages/devs/eth/powerpc/quicc/current/ChangeLog packages/devs/eth/powerpc/quicc/current/src/if_quicc.c packages/devs/eth/powerpc/quicc/current/src/quicc_eth.h |
| diffstat | 3 files changed, 252 insertions(+), 27 deletions(-) [+] |
line wrap: on
line diff
--- a/packages/devs/eth/powerpc/quicc/current/ChangeLog +++ b/packages/devs/eth/powerpc/quicc/current/ChangeLog @@ -1,3 +1,10 @@ +2003-03-14 Nick Garnett <nickg@balti.calivar.com> + + * src/if_quicc.c: Fixed several bugs, mostly dealing with getting + the device restarted after certain failures such as collisions. + + * src/quicc_eth.h: Added some statistics gathering. + 2003-03-06 Gary Thomas <gary@mlbassoc.com> * src/if_quicc.c (quicc_eth_init): New name for CPM/DPRAM allocator.
--- a/packages/devs/eth/powerpc/quicc/current/src/if_quicc.c +++ b/packages/devs/eth/powerpc/quicc/current/src/if_quicc.c @@ -370,7 +370,7 @@ quicc_eth_init(struct cyg_netdevtab_entr scc->scc_scce = 0xFFFF; // Enable interrupts - scc->scc_sccm = QUICC_SCCE_INTS; + scc->scc_sccm = QUICC_SCCE_INTS | QUICC_SCCE_GRC | QUICC_SCCE_BSY; // Set up SCCx to run in ethernet mode scc->scc_gsmr_h = 0; @@ -454,6 +454,65 @@ quicc_eth_control(struct eth_drv_sc *sc, case ETH_DRV_SET_MAC_ADDRESS: return 0; break; + +#ifdef ETH_DRV_GET_IF_STATS + case ETH_DRV_GET_IF_STATS: + { + struct ether_drv_stats *p = (struct ether_drv_stats *)data; + struct quicc_eth_info *qi = (struct quicc_eth_info *)sc->driver_private; + + strcpy( p->description, "QUICC (MPC8xx) SCC Ethernet" ); + CYG_ASSERT( 48 > strlen(p->description), "Description too long" ); + + // Really need to determine the following values properly, for + // now just assume the link is up, full duplex, unknown speed. + + p->operational = 3; // LINK UP + p->duplex = 1; + p->speed = 0; + + { + p->supports_dot3 = false; + + // Those commented out are not available on this chip. + + p->tx_good = qi->tx_good ; + //p->tx_max_collisions = qi->tx_max_collisions ; + p->tx_late_collisions = qi->tx_late_collisions ; + p->tx_underrun = qi->tx_underrun ; + p->tx_carrier_loss = qi->tx_carrier_loss ; + p->tx_deferred = qi->tx_deferred ; + //p->tx_sqetesterrors = qi->tx_sqetesterrors ; + //p->tx_single_collisions = qi->tx_single_collisions; + //p->tx_mult_collisions = qi->tx_mult_collisions ; + //p->tx_total_collisions = qi->tx_total_collisions ; + p->rx_good = qi->rx_good ; + p->rx_crc_errors = qi->rx_crc_errors ; + p->rx_align_errors = qi->rx_align_errors ; + p->rx_resource_errors = qi->rx_resource_errors ; + p->rx_overrun_errors = qi->rx_overrun_errors ; + p->rx_collisions = qi->rx_collisions ; + p->rx_short_frames = qi->rx_short_frames ; + p->rx_too_long_frames = qi->rx_long_frames ; + //p->rx_symbol_errors = qi->rx_symbol_errors ; + + p->interrupts = qi->interrupts ; + p->rx_count = qi->rx_count ; + p->rx_deliver = qi->rx_deliver ; + p->rx_resource = qi->rx_resource ; + p->rx_restart = qi->rx_restart ; + p->tx_count = qi->tx_count ; + p->tx_complete = qi->tx_complete ; + p->tx_dropped = qi->tx_dropped ; + } + + p->tx_queue_len = CYGNUM_DEVS_ETH_POWERPC_QUICC_TxNUM; + + return 0; // OK + } +#endif + + default: return 1; break; @@ -485,23 +544,17 @@ quicc_eth_send(struct eth_drv_sc *sc, st int i, txindex, cache_state; unsigned int ctrl; + qi->tx_count++; + // Find a free buffer txbd = txfirst = qi->txbd; - while (txbd->ctrl & QUICC_BD_CTL_Ready) { - // This buffer is busy, move to next one - if (txbd->ctrl & QUICC_BD_CTL_Wrap) { - txbd = qi->tbase; - } else { - txbd++; - } - if (txbd == txfirst) { + if ((txbd->ctrl & (QUICC_BD_CTL_Ready | QUICC_BD_CTL_Int ))) #ifdef CYGPKG_NET panic ("No free xmit buffers"); #else diag_printf("QUICC Ethernet: No free xmit buffers\n"); #endif - } - } + // Remember the next buffer to try if (txbd->ctrl & QUICC_BD_CTL_Wrap) { qi->txbd = qi->tbase; @@ -545,19 +598,69 @@ quicc_eth_RxEvent(struct eth_drv_sc *sc) { struct quicc_eth_info *qi = (struct quicc_eth_info *)sc->driver_private; volatile struct cp_bufdesc *rxbd; + rxbd = qi->rnext; while ((rxbd->ctrl & (QUICC_BD_CTL_Ready | QUICC_BD_CTL_Int)) == QUICC_BD_CTL_Int) { - qi->rxbd = rxbd; // Save for callback - set_led(LED_RxACTIVE); - (sc->funs->eth_drv->recv)(sc, rxbd->length); - clear_led(LED_RxACTIVE); - rxbd->ctrl |= QUICC_BD_CTL_Ready; - if (rxbd->ctrl & QUICC_BD_CTL_Wrap) { + + qi->rx_count++; + + if( rxbd->ctrl & QUICC_BD_RX_MISS ) + { + qi->rx_miss++; + } + if( rxbd->ctrl & QUICC_BD_RX_LG ) + { + qi->rx_long_frames++; + } + if( rxbd->ctrl & QUICC_BD_RX_NO ) + { + qi->rx_align_errors++; + } + if( rxbd->ctrl & QUICC_BD_RX_SH ) + { + qi->rx_short_frames++; + } + if( rxbd->ctrl & QUICC_BD_RX_CR ) + { + qi->rx_crc_errors++; + } + if( rxbd->ctrl & QUICC_BD_RX_OV ) + { + qi->rx_overrun_errors++; + } + + if( rxbd->ctrl & QUICC_BD_RX_CL ) + { + qi->rx_collisions++; + } + + if( (rxbd->ctrl & QUICC_BD_RX_ERRORS) == 0 ) + { + qi->rx_good++; + + // OK frame - Prepare for callback + qi->rxbd = rxbd; // Save for callback + set_led(LED_RxACTIVE); + + (sc->funs->eth_drv->recv)(sc, rxbd->length); + + clear_led(LED_RxACTIVE); + } + + + // Clear flags and wrap if needed else step up BD pointer + if (rxbd->ctrl & QUICC_BD_CTL_Wrap) + { + rxbd->ctrl = QUICC_BD_CTL_Ready | QUICC_BD_CTL_Int | QUICC_BD_CTL_Wrap; rxbd = qi->rbase; - } else { + } + else + { + rxbd->ctrl = QUICC_BD_CTL_Ready | QUICC_BD_CTL_Int; rxbd++; } + } // Remember where we left off qi->rnext = (struct cp_bufdesc *)rxbd; @@ -576,7 +679,8 @@ quicc_eth_recv(struct eth_drv_sc *sc, st struct quicc_eth_info *qi = (struct quicc_eth_info *)sc->driver_private; unsigned char *bp; int i, cache_state; - + int sg_list_null_buffer = 0; + bp = (unsigned char *)qi->rxbd->buffer; // Note: the MPC8xx does not seem to snoop/invalidate the data cache properly! HAL_DCACHE_IS_ENABLED(cache_state); @@ -588,7 +692,30 @@ quicc_eth_recv(struct eth_drv_sc *sc, st memcpy((void *)sg_list[i].buf, bp, sg_list[i].len); bp += sg_list[i].len; } + else + sg_list_null_buffer = 1; } + + // A NULL sg_list buffer usually means no mbufs, so we don't count + // it as a delivery, instead we count it as a resource error. + + if (!sg_list_null_buffer) + qi->rx_deliver++; + else + qi->rx_resource++; + +} + + +static void +quicc_eth_command( struct eth_drv_sc *sc, unsigned long cmd) +{ + volatile EPPC *eppc = (volatile EPPC *)eppc_base(); + + eppc->cp_cr = QUICC_CPM_SCCx | cmd | QUICC_CPM_CR_BUSY; + + while (eppc->cp_cr & QUICC_CPM_CR_BUSY ) + continue; } static void @@ -597,23 +724,59 @@ quicc_eth_TxEvent(struct eth_drv_sc *sc, struct quicc_eth_info *qi = (struct quicc_eth_info *)sc->driver_private; volatile struct cp_bufdesc *txbd; int txindex; + bool restart = false; txbd = qi->tnext; + while ((txbd->ctrl & (QUICC_BD_CTL_Ready | QUICC_BD_CTL_Int)) == QUICC_BD_CTL_Int) { + txindex = ((unsigned long)txbd - (unsigned long)qi->tbase) / sizeof(*txbd); + + qi->tx_complete++; + + (sc->funs->eth_drv->tx_done)(sc, qi->txkey[txindex], 0); txbd->ctrl &= ~QUICC_BD_CTL_Int; // Reset int pending bit - (sc->funs->eth_drv->tx_done)(sc, qi->txkey[txindex], 0); + + if (txbd->ctrl & QUICC_BD_TX_LC ) + qi->tx_late_collisions++, restart = true; + if (txbd->ctrl & QUICC_BD_TX_RL ) + qi->tx_retransmit_error++, restart = true; + if (txbd->ctrl & QUICC_BD_TX_UN ) + qi->tx_underrun++, restart = true; + if (txbd->ctrl & QUICC_BD_TX_CSL ) + qi->tx_carrier_loss++; + if (txbd->ctrl & QUICC_BD_TX_HB ) + qi->tx_heartbeat_loss++; + if (txbd->ctrl & QUICC_BD_TX_DEF ) + qi->tx_deferred++; + + if( (txbd->ctrl & QUICC_BD_TX_ERRORS) == 0 ) + qi->tx_good++; + + if (txbd->ctrl & QUICC_BD_CTL_Wrap) { + txbd->ctrl = QUICC_BD_CTL_Wrap; txbd = qi->tbase; } else { + txbd->ctrl = 0; txbd++; } - if (--qi->txactive == 0) { - clear_led(LED_TxACTIVE); - } + qi->txactive--; } + + if (qi->txactive == 0) { + clear_led(LED_TxACTIVE); + } + // Remember where we left off qi->tnext = (struct cp_bufdesc *)txbd; + + if (restart) + { + quicc_eth_command(sc,QUICC_CPM_CR_RESTART_TX); + qi->tx_restart++; + } + } // @@ -626,14 +789,31 @@ quicc_eth_int(struct eth_drv_sc *sc) volatile struct scc_regs *scc = qi->ctl; unsigned short scce; - while ((scce = (scc->scc_scce & QUICC_SCCE_INTS)) != 0) { - if ((scce & (QUICC_SCCE_TXE | QUICC_SCCE_TX)) != 0) { + qi->interrupts++; + + while ( (scce = scc->scc_scce) != 0 ) + { + scc->scc_scce = scce; + + if ( (scce & (QUICC_SCCE_TXE | QUICC_SCCE_TX)) != 0) + { quicc_eth_TxEvent(sc, scce); } - if ((scce & QUICC_SCCE_RXF) != 0) { + if ( (scce & ( QUICC_SCCE_RXF | QUICC_SCCE_RX )) != 0) + { quicc_eth_RxEvent(sc); } - scc->scc_scce = scce; // Reset the bits we handled + if ( (scce & QUICC_SCCE_BSY) != 0) + { + qi->rx_resource_errors++; + } + if ( (scce & QUICC_SCCE_GRC) != 0 ) + { + quicc_eth_command(sc, QUICC_CPM_CR_RESTART_TX); + qi->tx_restart++; + quicc_eth_command(sc, QUICC_CPM_CR_HUNT_MODE); + qi->rx_restart++; + } } }
--- a/packages/devs/eth/powerpc/quicc/current/src/quicc_eth.h +++ b/packages/devs/eth/powerpc/quicc/current/src/quicc_eth.h @@ -75,6 +75,35 @@ struct quicc_eth_info { int txsize, rxsize; // Length of individual buffers int txactive; // Count of active Tx buffers unsigned long txkey[CYGNUM_DEVS_ETH_POWERPC_QUICC_TxNUM]; + + // Keep some statistics + cyg_uint32 interrupts; + + cyg_uint32 rx_count; + cyg_uint32 rx_deliver; + cyg_uint32 rx_resource; + cyg_uint32 rx_restart; + cyg_uint32 rx_good; + cyg_uint32 rx_crc_errors; + cyg_uint32 rx_align_errors; + cyg_uint32 rx_resource_errors; + cyg_uint32 rx_overrun_errors; + cyg_uint32 rx_collisions; + cyg_uint32 rx_short_frames; + cyg_uint32 rx_long_frames; + cyg_uint32 rx_miss; + + cyg_uint32 tx_count; + cyg_uint32 tx_complete; + cyg_uint32 tx_restart; + cyg_uint32 tx_good; + cyg_uint32 tx_dropped; + cyg_uint32 tx_underrun; + cyg_uint32 tx_late_collisions; + cyg_uint32 tx_carrier_loss; + cyg_uint32 tx_retransmit_error; + cyg_uint32 tx_heartbeat_loss; + cyg_uint32 tx_deferred; }; // SCC registers - ethernet mode @@ -145,6 +174,11 @@ struct quicc_eth_info { #define QUICC_BD_RX_OV 0x0002 // Rx overrun #define QUICC_BD_RX_CL 0x0001 // Collision during frame +#define QUICC_BD_RX_ERRORS ( QUICC_BD_RX_CL | QUICC_BD_RX_OV | \ + QUICC_BD_RX_CR | QUICC_BD_RX_SH | \ + QUICC_BD_RX_NO | QUICC_BD_RX_LG | \ + QUICC_BD_RX_MISS ) + // Transmit buffer status #define QUICC_BD_TX_PAD 0x4000 // Pad short packets #define QUICC_BD_TX_LAST 0x0800 // Last buffer in chain @@ -157,6 +191,10 @@ struct quicc_eth_info { #define QUICC_BD_TX_UN 0x0002 // Tx underrun #define QUICC_BD_TX_CSL 0x0001 // Carrier lost +#define QUICC_BD_TX_ERRORS (QUICC_BD_TX_CSL | QUICC_BD_TX_UN | \ + QUICC_BD_TX_RL | QUICC_BD_TX_LC | \ + QUICC_BD_TX_HB | QUICC_BD_TX_DEF ) + #include CYGDAT_DEVS_QUICC_ETH_INL // Platform specifics #define IEEE_8023_MAX_FRAME 1518 // Largest possible ethernet frame
