if_i21143.c
来自「开放源码实时操作系统源码.」· C语言 代码 · 共 1,882 行 · 第 1/5 页
C
1,882 行
ndp = (struct cyg_netdevtab_entry *)(p_i21143->ndp);
sc = (struct eth_drv_sc *)(ndp->device_instance);
CHECK_NDP_SC_LINK();
}
CYG_ASSERT( 0 <= p_i21143->next_rx_descriptor, "rx descriptor underflow" );
CYG_ASSERT( RX_DESCRIPTORS > p_i21143->next_rx_descriptor, "rx descriptor overflow" );
index = p_i21143->next_rx_descriptor;
// Scan receive buffers
for ( count = 0; count < RX_DESCRIPTORS; count++ ) {
cyg_uint32 ldes0;
int length;
bp = &p_i21143->rx_ring[ index ];
CYG_ASSERT( 0 == bp->buf2, "Corrupt bp->buf2" );
CYG_ASSERT( 0 != bp->buf1, "Null bp->buf1" );
CYG_ASSERT( (MAX_RX_PACKET_SIZE << DES1_B1SIZE_SHIFT) == (bp->des1 &~ DES1_ENDRING),
"Corrupt bp->des1" );
ldes0 = bp->des0;
#ifdef DEBUG_TRAFFIC
diag_printf( "PacketRxReady: index %d des0 = %08x, %s, %s, %d bytes\n",
index, ldes0,
(ldes0 & DES0_STATUS_OWN) ? "open" : "done",
((RDES0_STATUS_FIRST | RDES0_STATUS_LAST | DES0_STATUS_ERROR) & ldes0)
== (RDES0_STATUS_FIRST | RDES0_STATUS_LAST) ? "OK" : "--",
(RDES0_COUNT_MASK & ldes0) >> RDES0_COUNT_SHIFT );
#endif
if ( DES0_STATUS_OWN_OPEN == (ldes0 & DES0_STATUS_OWN) )
// This buffer bilong the device
break;
INCR_STAT( rx_count );
// Otherwise, this one is for us
if ( ((RDES0_STATUS_FIRST | RDES0_STATUS_LAST | DES0_STATUS_ERROR) & ldes0)
== (RDES0_STATUS_FIRST | RDES0_STATUS_LAST) ) {
// 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 function
static 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 void
InitTxRing(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 void
TxDone(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;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?