if_i21143.c
来自「eCos操作系统源码」· C语言 代码 · 共 1,953 行 · 第 1/5 页
C
1,953 行
// A complete packet and no error bit length = (RDES0_COUNT_MASK & ldes0) >> RDES0_COUNT_SHIFT; CYG_ASSERT( MAX_RX_PACKET_SIZE >= length, "Oversize Rx" ); // tell the callback the right packet p_i21143->next_rx_descriptor = index; INCR_STAT( rx_good );#ifdef CYGPKG_NET if ( length > sizeof( struct ether_header ) ) // then it is acceptable; offer the data to the network stack#endif (sc->funs->eth_drv->recv)( sc, length ); // All done! }#ifdef KEEP_STATISTICS else { if ( RDES0_STATUS_LAST & ldes0 ) { // Then we have good error info; analyse and count the errors if ( ldes0 & ( RDES0_STATUS_CRC ) ) INCR_STAT( rx_crc_errors ); if ( ldes0 & ( RDES0_STATUS_DB ) ) INCR_STAT( rx_align_errors ); if ( ldes0 & ( RDES0_STATUS_LATECOLL ) ) INCR_STAT( rx_collisions ); if ( ldes0 & ( RDES0_STATUS_TOOLONG ) ) INCR_STAT( rx_too_long_frames ); if ( ldes0 & ( RDES0_STATUS_RF ) ) INCR_STAT( rx_short_frames ); if ( ldes0 & ( RDES0_STATUS_RE ) ) INCR_STAT( rx_symbol_errors ); } else // Dunno what went wrong really... INCR_STAT( rx_resource_errors ); }#endif // KEEP_STATISTICS // Open the buffer for the device to use bp->des0 = DES0_STATUS_OWN_OPEN; // NIC owns it, not the CPU // Step i around the ring buffer... index++; if ( index >= RX_DESCRIPTORS ) index = 0; } // record the right packet for next time p_i21143->next_rx_descriptor = index; CYG_ASSERT( 0 <= p_i21143->next_rx_descriptor, "rx descriptor underflow" ); CYG_ASSERT( RX_DESCRIPTORS > p_i21143->next_rx_descriptor, "rx descriptor overflow" ); { // We should not have needed ioaddr before this point. cyg_uint32 ioaddr; cyg_uint32 l; // Now examine the state of the receive engine and prompt it accordingly. ioaddr = p_i21143->io_address; // get 21143's I/O address l = INL( CSR_STATUS );#ifdef DEBUG_TRAFFIC diag_printf( "PacketRxReady: done scan, next %d, status %08x %s\n", p_i21143->next_rx_descriptor, l, (CSR_STATUS_RXSTATUS & l) != CSR_STATUS_RXSTATUS_STOPPED ? "Running" : "Stopped" );#endif if ( (CSR_STATUS_RXSTATUS & l) != CSR_STATUS_RXSTATUS_STOPPED ) { // Then ping it into life OUTL( 0, CSR_RXPOLL ); } else { // Oh dear, it's stopped; we must initialize and start the rx machine InitRxRing( p_i21143 ); OUTL( CYGHWR_PCI_VIRT_TO_BUS( (cyg_uint32)p_i21143->rx_ring ), CSR_RXBASE ); l = INL( CSR_OPMODE ); l |= CSR_OPMODE_RX_START; OUTL( l, CSR_OPMODE ); INCR_STAT( rx_resource ); INCR_STAT( rx_restart ); } }}// and the callback functionstatic void i21143_recv( struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len ){ volatile BUFDES *bp; struct i21143 *p_i21143; cyg_uint32 from_p; int total_len; struct eth_drv_sg *last_sg; p_i21143 = (struct i21143 *)(sc->driver_private); CYG_ASSERT( 0 <= p_i21143->next_rx_descriptor, "rx descriptor underflow" ); CYG_ASSERT( RX_DESCRIPTORS > p_i21143->next_rx_descriptor, "rx descriptor overflow" ); bp = &p_i21143->rx_ring[ p_i21143->next_rx_descriptor ]; CYG_ASSERT( 0 == bp->buf2, "Corrupt bp->buf2" ); CYG_ASSERT( 0 != bp->buf1, "Null bp->buf1" ); CYG_ASSERT( DES0_STATUS_OWN_DONE == (bp->des0 & DES0_STATUS_OWN), "bp not done" ); // Copy the data to the network stack from_p = CYGHWR_BUS_TO_UNCACHED( bp->buf1 ); total_len = (RDES0_COUNT_MASK & bp->des0) >> RDES0_COUNT_SHIFT;#ifdef DEBUG_TRAFFIC diag_printf("Recv callback: index %d des0 = %08x: %d sg's, %d bytes\n", p_i21143->next_rx_descriptor, bp->des0, sg_len, total_len);#endif // check we have memory to copy into; we would be called even if // caller was out of memory in order to maintain our state. if ( 0 == sg_len || 0 == sg_list ) return; // caller was out of mbufs INCR_STAT( rx_deliver ); CYG_ASSERT( 0 < sg_len, "sg_len underflow" ); CYG_ASSERT( MAX_ETH_DRV_SG >= sg_len, "sg_len overflow" ); for ( last_sg = &sg_list[sg_len]; sg_list < last_sg; sg_list++ ) { cyg_uint8 *to_p; int l; to_p = (cyg_uint8 *)(sg_list->buf); l = sg_list->len; CYG_ASSERT( 0 <= l, "sg length -ve" ); if ( 0 >= l || 0 == to_p ) return; // caller was out of mbufs if ( l > total_len ) l = total_len; memcpy( to_p, (unsigned char *)from_p, l ); from_p += l; total_len -= l; } CYG_ASSERT( 0 == total_len, "total_len mismatch in rx" ); CYG_ASSERT( last_sg == sg_list, "sg count mismatch in rx" ); CYG_ASSERT( CYGHWR_BUS_TO_UNCACHED( bp->buf1 ) < from_p, "from_p wild in rx" ); CYG_ASSERT( CYGHWR_BUS_TO_UNCACHED( bp->buf1 ) + MAX_RX_PACKET_SIZE >= from_p, "from_p overflow in rx" );}// ------------------------------------------------------------------------//// Function : InitTxRing//// ------------------------------------------------------------------------static voidInitTxRing(struct i21143* p_i21143){ int i; volatile BUFDES *bp; p_i21143->tx_ring = (BUFDES *)CYGHWR_CACHED_TO_UNCACHED( &(p_i21143->_tx[0]) ); bp = p_i21143->tx_ring; for ( i = 0 ; i < TX_DESCRIPTORS; i++ ) { bp->des0 = DES0_STATUS_OWN_DONE; // CPU owns it, not the NIC bp->des1 = 0; bp->buf1 = bp->buf2 = 0; bp++; } bp--; // last one bp->des1 |= DES1_ENDRING;}// ------------------------------------------------------------------------//// Function : TxDone (Called from delivery thread)//// This returns Tx's from the Tx Machine to the stack (ie. reports// completion) - allowing for missed interrupts, and so on.// ------------------------------------------------------------------------static voidTxDone(struct i21143* p_i21143){ struct eth_drv_sc *sc; unsigned long key = 0; cyg_uint32 ioaddr; { struct cyg_netdevtab_entry *ndp; ndp = (struct cyg_netdevtab_entry *)(p_i21143->ndp); sc = (struct eth_drv_sc *)(ndp->device_instance); CHECK_NDP_SC_LINK(); } ioaddr = p_i21143->io_address; // get 21143's I/O address#ifdef DEBUG_TRAFFIC_TXDETAILS dump_tx_details( p_i21143, "TxDone" );#endif if ( NO_TX_IN_PROGRESS != p_i21143->tx_endbuf) { cyg_uint32 l; volatile BUFDES *bp; cyg_uint32 des; CYG_ASSERT( TX_DESCRIPTORS > p_i21143->tx_endbuf, "tx_endbuf range" ); l = INL( CSR_STATUS ); // Important: read this first bp = p_i21143->tx_ring; bp += p_i21143->tx_endbuf; // The descriptor with the "end" marker // It's not clear where error status gets written if the error is // *before* the end-marked bufdesc. We'll see. des = bp->des1; CYG_ASSERT( TDES1_CONTROL_LAST & des , "Last buf not marked" ); CYG_ASSERT( TDES1_CONTROL_INTERRUPT & des , "No interrupt req" ); CYG_ASSERT( 0 == (DES1_2ACHAIN & des), "Buffer chained" ); CYG_ASSERT( 0 == ((TDES1_CONTROL_SETUP | TDES1_CONTROL_SETUP_FT1 | TDES1_CONTROL_SETUP_FT0 | TDES1_CONTROL_NO_CRC | TDES1_CONTROL_NO_PAD) & des), "Buffer wierd flags" ); des = bp->des0; if ( DES0_STATUS_OWN_DONE == (des & DES0_STATUS_OWN) ) { // Then it finished; somehow... key = p_i21143->tx_keys[ 0 ];#ifdef DEBUG_TRAFFIC diag_printf("TxDone: KEY %x, %d descs, status %08x\n", key, p_i21143->tx_endbuf+1, des );#endif#ifdef KEEP_STATISTICS // Then look for an error code from the tx records... if ( ! ( DES0_STATUS_ERROR & des ) ) INCR_STAT( tx_good ); // Not all the following are errors, so check all if ( des & ( TDES0_STATUS_LO | TDES0_STATUS_NC ) ) INCR_STAT( tx_carrier_loss ); if ( des & ( TDES0_STATUS_LC ) ) INCR_STAT( tx_late_collisions ); if ( des & ( TDES0_STATUS_EC ) ) INCR_STAT( tx_max_collisions ); if ( des & ( TDES0_STATUS_LF ) ) INCR_STAT( tx_sqetesterrors ); if ( des & ( TDES0_STATUS_UFL ) ) INCR_STAT( tx_underrun ); if ( des & ( TDES0_STATUS_DE ) ) INCR_STAT( tx_deferred ); // Now count collisions per se: des = ((des & TDES0_STATUS_CC_MASK) >> TDES0_STATUS_CC_SHIFT); if ( 0 < des ) { INCR_STAT( tx_total_collisions ); if ( 1 < des ) INCR_STAT( tx_mult_collisions ); else INCR_STAT( tx_single_collisions ); }#endif // KEEP_STATISTICS } else { // a Tx is in progress, but it has not yet completed; // probably wise to check on the tx machine status. if ( ((CSR_STATUS_TXSTATUS & l) == CSR_STATUS_TXSTATUS_STOPPED) || ((CSR_STATUS_TXSTATUS & l) == CSR_STATUS_TXSTATUS_SUSPENDED) ) { // then it's not active right now! key = p_i21143->tx_keys[ 0 ];#ifdef DEBUG_TRAFFIC diag_printf("TxDone STOPPED! KEY %x, %d descs, status %08x, CSR_STATUS %08x\n", key, p_i21143->tx_endbuf, des, l );#endif INCR_STAT( tx_underrun ); // at a guess... } } // Common "done" code - key nonzero => report done if (key) { p_i21143->tx_keys[ 0 ] = 0; p_i21143->tx_endbuf = NO_TX_IN_PROGRESS; // Then tell the stack we are done: INCR_STAT( tx_complete ); (sc->funs->eth_drv->tx_done)( sc, key, 0 ); } }}// ------------------------------------------------------------------------//// Function : i21143_can_send//// ------------------------------------------------------------------------static int i21143_can_send(struct eth_drv_sc *sc){ struct i21143 *p_i21143; p_i21143 = (struct i21143 *)sc->driver_private; IF_BAD_21143( p_i21143 ) {#ifdef DEBUG_TRAFFIC diag_printf( "i21143_can_send: Bad device pointer %x\n", p_i21143 );#endif return 0; } if ( p_i21143->active ) { if ( NO_TX_IN_PROGRESS != p_i21143->tx_endbuf ) // Poll for Tx completion TxDone( p_i21143 ); // Poll for receptions PacketRxReady( p_i21143 ); }#ifdef neverDEBUG_TRAFFIC diag_printf( "i21143_can_send: returning %d\n", (NO_TX_IN_PROGRESS == p_i21143->tx_endbuf) && p_i21143->active );#endif return (NO_TX_IN_PROGRESS == p_i21143->tx_endbuf) && p_i21143->active;}// ------------------------------------------------------------------------//// Function : i21143_send//// ------------------------------------------------------------------------static void i21143_send(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len, int total_len, unsigned long key){ struct i21143 *p_i21143; cyg_uint32 ioaddr; struct eth_drv_sg *last_sg; volatile BUFDES *bp; int bufcount; cyg_uint32 x; p_i21143 = (struct i21143 *)sc->driver_private; IF_BAD_21143( p_i21143 ) {#ifdef DEBUG_TRAFFIC diag_printf( "i21143_send: Bad device pointer %x\n", p_i21143 );#endif return; } if ( NO_TX_IN_PROGRESS != p_i21143->tx_endbuf) { // Then we cannot do this#ifdef DEBUG_TRAFFIC diag_printf( "i21143_send: tx busy %x, %d bufs key %x\n", p_i21143, p_i21143->tx_endbuf, p_i21143->tx_keys[0] );#endif CYG_FAIL( "Send call when already busy" ); INCR_STAT( tx_dropped ); return; } ioaddr = p_i21143->io_address; bp = p_i21143->tx_ring; bufcount = 0;#ifdef DEBUG_TRAFFIC diag_printf( "i21143_send() key %x\n", key );#endif INCR_STAT( tx_count ); for ( last_sg = &sg_list[sg_len]; sg_list < last_sg; sg_list++ ) { cyg_uint8 *from_p; int l; from_p = (cyg_uint8 *)(sg_list->buf); // normal cached address
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?