if_upd985xx.c
来自「开放源码实时操作系统源码.」· C语言 代码 · 共 1,622 行 · 第 1/4 页
C
1,622 行
#ifdef DEBUG
os_printf("eth_upd985xx_stop %d flg %x\n", p_eth_upd985xx->index, *(int *)p_eth_upd985xx );
#endif
p_eth_upd985xx->active = 0; // stop people tormenting it
if ( p_eth_upd985xx->tx_busy ) {
// Then it is finshed now, by force:
cyg_uint32 key = p_eth_upd985xx->tx_keys[ 0 ];
// Turn off the transmitter (before the callback to the stack).
OUTL( ETH_TXCR, 0 );
#ifdef DEBUG_TRAFFIC
os_printf("Stop: tidying up TX, KEY %x\n", key );
#endif
// Leave tx_busy true so no recursion can occur here.
// Then tell the stack we are done:
if ( key ) {
(sc->funs->eth_drv->tx_done)( sc, key, 0 );
}
}
p_eth_upd985xx->tx_keys[ 0 ] = 0;
p_eth_upd985xx->tx_busy = p_eth_upd985xx->active = 0;
eth_upd985xx_reset(p_eth_upd985xx);
ResetTxRing( p_eth_upd985xx );
}
// ------------------------------------------------------------------------
//
// Function : InitRxRing
//
// ------------------------------------------------------------------------
STATIC void InitRxRing(struct eth_upd985xx* p_eth_upd985xx)
{
int i;
struct bufdesc *bp;
// first just blat the various flags and addresses: the first N
// bufdescs point to data buffers, the last one is NULL.
bp = (struct bufdesc *)VIRT_TO_BUS( &p_eth_upd985xx->rx_bufdesc[0] );
// Record the initial active buffer:
p_eth_upd985xx->rxring_active = bp;
p_eth_upd985xx->rxring_active_index = 0;
for ( i = 0; i < NUM_RXBUFS - 1; i++, bp++ ) {
bp->ptr = VIRT_TO_BUS( &rx_databuf[i][0] );
bp->attr = ( ETH_BUF_D_L_DATA | ETH_BUF_OWN_CPU
| (ETH_BUF_SIZE & sizeof( rx_databuf[0] )) );
}
CYG_ASSERT( i == NUM_RXBUFS-1, "Penultimate rx buffer index mismatch" );
CYG_ASSERT( (cyg_uint8 *)bp ==
VIRT_TO_BUS( &p_eth_upd985xx->rx_bufdesc[NUM_RXBUFS-1] ),
"Penultimate rx buffer address mismatch" );
// NULL out the penultimate one
bp->ptr = NULL;
bp->attr = 0;
// And record it as next one to use
p_eth_upd985xx->rxring_next = bp;
p_eth_upd985xx->rxring_next_index = NUM_RXBUFS-1;
// Step on to the extra entry at the end which makes a ring:
bp++;
CYG_ASSERT( (cyg_uint8 *)bp ==
VIRT_TO_BUS( &p_eth_upd985xx->rx_bufdesc[NUM_RXBUFS] ),
"Ultimate rx buffer address mismatch" );
// Link the Ultimate back to the start
bp->ptr = (cyg_uint8 *)p_eth_upd985xx->rxring_active; // Zeroth entry
bp->attr = ETH_BUF_D_L_LINK;
// All done.
}
// ------------------------------------------------------------------------
//
// Function : NextRxRing
//
// ------------------------------------------------------------------------
STATIC void NextRxRing(struct eth_upd985xx* p_eth_upd985xx )
{
volatile struct bufdesc *next, *dead;
int iactive;
int inext;
iactive = p_eth_upd985xx->rxring_active_index;
inext = p_eth_upd985xx->rxring_next_index;
// Preconditions:
CYG_ASSERT( 0 <= inext && inext < NUM_RXBUFS, "Bad inext" );
CYG_ASSERT( 0 <= iactive && iactive < NUM_RXBUFS, "Bad iactive" );
CYG_ASSERT( VIRT_TO_BUS( &p_eth_upd985xx->rx_bufdesc[ inext ] )
== (cyg_uint8 *)p_eth_upd985xx->rxring_next, "Next rx_bufdesc bad" );
CYG_ASSERT( VIRT_TO_BUS( &p_eth_upd985xx->rx_bufdesc[ iactive ] )
== (cyg_uint8 *)p_eth_upd985xx->rxring_active, "Active rx_bufdesc bad" );
CYG_ASSERT( ETH_BUF_D_L_LINK == p_eth_upd985xx->rxring_next->attr, "Next not a link" );
CYG_ASSERT( ETH_BUF_D_L_DATA & p_eth_upd985xx->rxring_active->attr, "Active not data" );
CYG_ASSERT( NULL == p_eth_upd985xx->rxring_next->ptr, "Next not NULL" );
CYG_ASSERT( VIRT_TO_BUS( &rx_databuf[iactive][0] ) ==
p_eth_upd985xx->rxring_active->ptr, "Active bad data pointer" );
CYG_ASSERT( (iactive - 1 == inext) || (0 == iactive && NUM_RXBUFS - 1 == inext),
"Chasing pointers mismatch" );
// Select the new bufdesc to be active - ie. next to scan for reception:
if ( ++iactive >= NUM_RXBUFS )
iactive = 0;
dead = p_eth_upd985xx->rxring_active; // the one that just died
// Step ahead the new active buffer:
p_eth_upd985xx->rxring_active = (volatile struct bufdesc *)
VIRT_TO_BUS( &p_eth_upd985xx->rx_bufdesc[ iactive ] );
p_eth_upd985xx->rxring_active_index = iactive;
// Blow away the currently active entry; we have dealt with it already
// and it is needed for an end stop to the ring:
dead->ptr = NULL;
dead->attr = 0;
// Select the next bufdesc to enliven
next = p_eth_upd985xx->rxring_next;
next->ptr = VIRT_TO_BUS( &rx_databuf[inext][0] );
next->attr = ( ETH_BUF_D_L_DATA | ETH_BUF_OWN_CPU
| (ETH_BUF_SIZE & sizeof( rx_databuf[0] )) );
// And update the external info to reflect this:
if ( ++inext >= NUM_RXBUFS )
inext = 0;
next = (volatile struct bufdesc *)
VIRT_TO_BUS( &p_eth_upd985xx->rx_bufdesc[ inext ] );
p_eth_upd985xx->rxring_next = next;
p_eth_upd985xx->rxring_next_index = inext;
// Postconditions:
CYG_ASSERT( 0 <= inext && inext < NUM_RXBUFS, "Bad inext" );
CYG_ASSERT( 0 <= iactive && iactive < NUM_RXBUFS, "Bad iactive" );
CYG_ASSERT( VIRT_TO_BUS( &p_eth_upd985xx->rx_bufdesc[ inext ] )
== (cyg_uint8 *)p_eth_upd985xx->rxring_next, "Next rx_bufdesc bad" );
CYG_ASSERT( VIRT_TO_BUS( &p_eth_upd985xx->rx_bufdesc[ iactive ] )
== (cyg_uint8 *)p_eth_upd985xx->rxring_active, "Active rx_bufdesc bad" );
CYG_ASSERT( ETH_BUF_D_L_LINK == p_eth_upd985xx->rxring_next->attr, "Next not a link" );
CYG_ASSERT( ETH_BUF_D_L_DATA & p_eth_upd985xx->rxring_active->attr, "Active not data" );
CYG_ASSERT( NULL == p_eth_upd985xx->rxring_next->ptr, "Next not NULL" );
CYG_ASSERT( VIRT_TO_BUS( &rx_databuf[iactive][0] ) ==
p_eth_upd985xx->rxring_active->ptr, "Active bad data pointer" );
CYG_ASSERT( (iactive - 1 == inext) || (0 == iactive && NUM_RXBUFS - 1 == inext),
"Chasing pointers mismatch" );
}
// ------------------------------------------------------------------------
//
// Function : PacketRxReady (Called from delivery thread)
//
// ------------------------------------------------------------------------
STATIC void PacketRxReady(struct eth_upd985xx* p_eth_upd985xx)
{
struct cyg_netdevtab_entry *ndp;
struct eth_drv_sc *sc;
cyg_uint32 ss, length;
cyg_bool reset_required = 0;
ndp = (struct cyg_netdevtab_entry *)(p_eth_upd985xx->ndp);
sc = (struct eth_drv_sc *)(ndp->device_instance);
CHECK_NDP_SC_LINK();
#ifdef DEBUG_TRAFFIC
ss = INL( ETH_RXSR );
os_printf("PacketRxReady: RXSR %x\n", ss );
#endif
if ( ETH_ISR_RBDRU & p_eth_upd985xx->intrs )
reset_required = 1; // Out of buffers
if ( ! ETH_ISR_RCVDN & p_eth_upd985xx->intrs )
reset_required = 1; // or if no reception completed, reset anyway
// For all ready rx blocks...
do {
volatile struct bufdesc *bp;
bp = p_eth_upd985xx->rxring_active; // Current rx candidate
ss = bp->attr;
#ifdef DEBUG_TRAFFIC
os_printf("PacketRxReady attr %x at %x\n", ss, bp );
#endif
if ( ETH_BUF_OWN_CPU == (ETH_BUF_OWN & ss) ) {
// Then the packet is untouched...
break;
}
#ifdef CYGOPT_DEVS_ETH_MIPS_UPD985XX_HARDWARE_BUGS_E1E2
// Perform address recognition by hand, hardware is in promisc mode
// (we have settable "software" promisc mode too of course)
if ( ETH_BUF_OK & ss ) {
cyg_uint8 *esa = (cyg_uint8 *)bp->ptr; // (this is a non-cachable address)
int ok = 0;
if ( p_eth_upd985xx->promisc )
ok = 1; // accept the packet
else
if ( p_eth_upd985xx->mac_address[0] == esa[0] &&
p_eth_upd985xx->mac_address[1] == esa[1] &&
p_eth_upd985xx->mac_address[2] == esa[2] &&
p_eth_upd985xx->mac_address[3] == esa[3] &&
p_eth_upd985xx->mac_address[4] == esa[4] &&
p_eth_upd985xx->mac_address[5] == esa[5] )
ok = 1; // Then they are equal - accept
else
if ( 0xff == esa[0] &&
0xff == esa[1] &&
0xff == esa[2] &&
0xff == esa[3] &&
0xff == esa[4] &&
0xff == esa[5] )
ok = 1; // Then they are equal - accept
if ( !ok )
ss = 0; // Easiest way...
}
#endif
if ( ETH_BUF_OK & ss ) {
length = ETH_BUF_SIZE & ss;
#ifdef DEBUG_TRAFFIC
os_printf("PacketRxReady found a packet size %d attr %x\n", length, ss );
#endif
// Asserts for the length in-range can fire, with good status
// in the block, so be defensive here instead. Belt and braces.
if ( 63 < length && length <= MAX_RX_PACKET_SIZE ) {
CYG_ASSERT( ETH_BUF_D_L_DATA == (ETH_BUF_D_L & ss), "Not data buffer" );
CYG_ASSERT( length > 63, "Tiny packet" );
CYG_ASSERT( length <= MAX_RX_PACKET_SIZE, "Too big packet" );
CYG_ASSERT( ETH_BUF_LAST & ss, "Not last buffer" );
(sc->funs->eth_drv->recv)( sc, length );
} // Else drop it on the floor.
}
// Step along to the next buffer descriptor...
NextRxRing( p_eth_upd985xx );
if ( ! reset_required ) {
// And tell the device it can have a biscuit:
OUTL( ETH_RXPDR, ETH_RXPDR_AL | 1 );
// Now, before moving on to the next packet, find out if receptions
// had caught up with us before adding that new buffer:
ss = INL( ETH_RXPDR );
ss &= ETH_RXPDR_RNOD;
ss >>= ETH_RXPDR_RNOD_SHIFT;
if ( 1 >= ss ) {
// Then it was zero before. So the rx engine is stopped.
#ifdef DEBUG_TRAFFIC
os_printf( "***ZERO rx buffers were left\n" );
#endif
reset_required = 1;
}
// Otherwise we carry on as usual.
}
} while ( 1 );
if ( reset_required ) {
p_eth_upd985xx->count_rx_resource++;
// Disable the wet string end of the receiver
ss = INL( ETH_MACC1 );
ss &=~ETH_MACC1_SRXEN;
OUTL( ETH_MACC1, ss );
// Disable the DMA engine
OUTL( ETH_RXCR, 0 );
// Reset the RxRing from scratch
InitRxRing( p_eth_upd985xx );
// Point the hardware at the list of buffers
OUTL( ETH_RXDPR, (cyg_uint32)p_eth_upd985xx->rxring_active );
// Tell it about the buffers via the rx descriptor count:
ss = INL( ETH_RXPDR );
ss &= ETH_RXPDR_RNOD;
ss >>= ETH_RXPDR_RNOD_SHIFT;
// This awful register *increments* by what you write, even if the
// machinery is halted. Vile filthy evil rubbish.
OUTL( ETH_RXPDR, ETH_RXPDR_AL | ((NUM_RXBUFS-1) - ss) );
ss = INL( ETH_RXPDR );
CYG_ASSERT( (ETH_RXPDR_AL | (NUM_RXBUFS-1)) == ss, "RXPDR not right" );
// Start the rx.
OUTL( ETH_RXCR, ETH_RXCR_RXE | ETH_RXCR_DRBS_16 );
// Enable the wet string end of the receiver
ss = INL( ETH_MACC1 );
ss |= ETH_MACC1_SRXEN;
OUTL( ETH_MACC1, ss );
// All done.
#ifdef DEBUG_TRAFFIC
os_printf( "***Rx Machine restarted\n" );
#endif
}
}
// and the callback function
STATIC void
eth_upd985xx_recv( struct eth_drv_sc *sc,
struct eth_drv_sg *sg_list, int sg_len )
{
struct eth_upd985xx *p_eth_upd985xx;
int total_len;
struct eth_drv_sg *last_sg;
cyg_uint8 *from_p;
volatile struct bufdesc *bp;
p_eth_upd985xx = (struct eth_upd985xx *)sc->driver_private;
// Guard possible external entry points
if ( ! p_eth_upd985xx->active )
return;
bp = p_eth_upd985xx->rxring_active; // Current rx candidate
#ifdef DEBUG_TRAFFIC
os_printf("Rx status %x\n", bp->attr );
#endif
if ( 0 == (ETH_BUF_OK & bp->attr) )
return;
total_len = ETH_BUF_SIZE & bp->attr;
#ifdef DEBUG_TRAFFIC
os_printf("Rx %d %x (status %x): %d sg's, %d bytes\n",
p_eth_upd985xx->index, (int)p_eth_upd985xx,
bp->attr,
sg_len, total_len);
#endif
// Copy the data to the network stack
from_p = bp->ptr; // (this is a non-cachable address)
// 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
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, 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( bp->ptr < from_p, "from_p wild in rx" );
CYG_ASSERT( bp->ptr + MAX_RX_PACKET_SIZE >= from_p,
"from_p overflow in rx" );
}
// ------------------------------------------------------------------------
//
// Function : InitTxRing
//
// ------------------------------------------------------------------------
STATIC void InitTxRing(struct eth_upd985xx* p_eth_upd985xx)
{
int i;
volatile struct bufdesc *bp;
p_eth_upd985xx->txring =
(struct bufdesc *)VIRT_TO_BUS( &p_eth_upd985xx->tx_bufdesc[0] );
bp = p_eth_upd985xx->txring;
for ( i = 0; i < NUM_ELEMENTS( p_eth_upd985xx->tx_bufdesc ); i++, bp++ ) {
bp->ptr = NULL;
bp->attr = 0;
}
// Last one is a NULL link
bp--;
bp->ptr = NULL;
bp->attr = ETH_BUF_D_L_LINK;
ResetTxRing(p_eth_upd985xx);
}
// ------------------------------------------------------------------------
//
// Function : ResetTxRing
//
// ------------------------------------------------------------------------
STATIC void ResetTxRing(struct eth_upd985xx* p_eth_upd985xx)
{
int i;
volatile struct bufdesc *bp;
bp = p_eth_upd985xx->txring;
for ( i = 0; i < NUM_ELEMENTS( p_eth_upd985xx->tx_bufdesc ) - 1; i++, bp++ ) {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?