📄 if_ebsa285.c
字号:
CYG_ASSERT( (cyg_uint8 *)p_rfd >= i82559_heap_base, "rfd under" );
CYG_ASSERT( (cyg_uint8 *)p_rfd < i82559_heap_free, "rfd over" );
CYG_ASSERT( p_i82559->rx_ring[
( i ? (i-1) : (MAX_RX_DESCRIPTORS-1) )
]->link == VIRT_TO_BUS(p_rfd), "rfd linked list broken" );
p_rfd->rxstatus = 0;
p_rfd->count = 0;
p_rfd->f = 0;
p_rfd->eof = 0;
p_rfd->rdb_address = 0xFFFFFFFF;
p_rfd->size = MAX_RX_PACKET_SIZE;
}
p_i82559->next_rx_descriptor = 0;
// And set an end-of-list marker in the previous one.
p_rfd->rxstatus = RFD_STATUS_EL;
}
// ------------------------------------------------------------------------
//
// Function : PacketRxReady (Called from delivery thread)
//
// ------------------------------------------------------------------------
static void PacketRxReady(struct i82559* p_i82559)
{
RFD *p_rfd;
int next_descriptor;
int length, ints;
struct cyg_netdevtab_entry *ndp;
struct eth_drv_sc *sc;
cyg_uint32 ioaddr;
cyg_uint16 status;
ndp = (struct cyg_netdevtab_entry *)(p_i82559->ndp);
sc = (struct eth_drv_sc *)(ndp->device_instance);
CHECK_NDP_SC_LINK();
ioaddr = p_i82559->io_address;
next_descriptor = p_i82559->next_rx_descriptor;
p_rfd = p_i82559->rx_ring[next_descriptor];
CYG_ASSERT( (cyg_uint8 *)p_rfd >= i82559_heap_base, "rfd under" );
CYG_ASSERT( (cyg_uint8 *)p_rfd < i82559_heap_free, "rfd over" );
while ( p_rfd->rxstatus & RFD_STATUS_C ) {
p_rfd->rxstatus_hi |= RFD_STATUS_HI_EL;
length = p_rfd->count;
#ifdef DEBUG_82559
os_printf( "Device %d (eth%d), rx descriptor %d:\n",
p_i82559->index, p_i82559->index, next_descriptor );
// dump_rfd( p_rfd, 1 );
#endif
p_i82559->next_rx_descriptor = next_descriptor;
// Check for bogusly short packets; can happen in promisc mode:
// Asserted against and checked by upper layer driver.
#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 );
p_rfd->count = 0;
p_rfd->f = 0;
p_rfd->eof = 0;
p_rfd->rxstatus_lo = 0;
// The just-emptied slot is now ready for re-use and already marked EL;
// we can now remove the EL marker from the previous one.
if ( 0 == next_descriptor )
p_rfd = p_i82559->rx_ring[ MAX_RX_DESCRIPTORS-1 ];
else
p_rfd = p_i82559->rx_ring[ next_descriptor-1 ];
// The previous one: check it *was* marked before clearing.
CYG_ASSERT( p_rfd->rxstatus_hi & RFD_STATUS_HI_EL, "No prev EL" );
p_rfd->rxstatus_hi = 0; // that word is not written by the device.
#ifdef KEEP_STATISTICS
statistics[p_i82559->index].rx_deliver++;
#endif
if (++next_descriptor >= MAX_RX_DESCRIPTORS)
next_descriptor = 0;
p_rfd = p_i82559->rx_ring[next_descriptor];
CYG_ASSERT( (cyg_uint8 *)p_rfd >= i82559_heap_base, "rfd under" );
CYG_ASSERT( (cyg_uint8 *)p_rfd < i82559_heap_free, "rfd over" );
}
// See if the RU has gone idle (usually because of out of resource
// condition) and restart it if needs be.
ints = Mask82559Interrupt(p_i82559);
status = INW(ioaddr + SCBStatus);
if ( RU_STATUS_READY != (status & RU_STATUS_MASK) ) {
// Acknowledge the RX INT sources
OUTW( SCB_INTACK_RX, ioaddr + SCBStatus);
// (see pages 6-10 & 6-90)
#ifdef KEEP_STATISTICS
statistics[p_i82559->index].rx_restart++;
#endif
// There's an end-of-list marker out there somewhere...
// So mop it up; it takes a little time but this is infrequent.
ResetRxRing( p_i82559 );
next_descriptor = 0; // re-initialize next desc.
// wait for SCB command complete
wait_for_cmd_done(ioaddr);
// load pointer to Rx Ring
OUTL(VIRT_TO_BUS(p_i82559->rx_ring[0]),
ioaddr + SCBPointer);
OUTW(RUC_START, ioaddr + SCBCmd);
Acknowledge82559Interrupt(p_i82559);
}
UnMask82559Interrupt(p_i82559, ints);
p_i82559->next_rx_descriptor = next_descriptor;
}
// and the callback function
static void i82559_recv( struct eth_drv_sc *sc,
struct eth_drv_sg *sg_list, int sg_len )
{
struct i82559 *p_i82559;
RFD *p_rfd;
int next_descriptor;
int total_len;
struct eth_drv_sg *last_sg;
volatile cyg_uint8 *from_p;
p_i82559 = (struct i82559 *)sc->driver_private;
IF_BAD_82559( p_i82559 ) {
#ifdef DEBUG
os_printf( "i82559_recv: Bad device pointer %x\n", p_i82559 );
#endif
return;
}
next_descriptor = p_i82559->next_rx_descriptor;
p_rfd = p_i82559->rx_ring[next_descriptor];
CYG_ASSERT( (cyg_uint8 *)p_rfd >= i82559_heap_base, "rfd under" );
CYG_ASSERT( (cyg_uint8 *)p_rfd < i82559_heap_free, "rfd over" );
CYG_ASSERT( p_rfd->rxstatus & RFD_STATUS_C, "No complete frame" );
CYG_ASSERT( p_rfd->rxstatus & RFD_STATUS_EL, "No marked frame" );
CYG_ASSERT( p_rfd->rxstatus_lo & RFD_STATUS_LO_C, "No complete frame 2" );
CYG_ASSERT( p_rfd->rxstatus_hi & RFD_STATUS_HI_EL, "No marked frame 2" );
if ( 0 == (p_rfd->rxstatus & RFD_STATUS_C) )
return;
total_len = p_rfd->count;
#ifdef DEBUG_82559
os_printf("Rx %d %x (status %x): %d sg's, %d bytes\n",
p_i82559->index, (int)p_i82559, p_rfd->rxstatus, sg_len, total_len);
#endif
// Copy the data to the network stack
from_p = &p_rfd->buffer[0];
// 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, (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( &p_rfd->buffer[0] < from_p, "from_p wild in rx" );
CYG_ASSERT( &p_rfd->buffer[0] + MAX_RX_PACKET_SIZE >= from_p,
"from_p overflow in rx" );
}
// ------------------------------------------------------------------------
//
// Function : InitTxRing
//
// ------------------------------------------------------------------------
static void InitTxRing(struct i82559* p_i82559)
{
int i;
cyg_uint32 ioaddr;
#ifdef DEBUG_82559
os_printf("InitTxRing %d\n", p_i82559->index);
#endif
ioaddr = p_i82559->io_address;
for ( i = 0; i < MAX_TX_DESCRIPTORS; i++) {
p_i82559->tx_ring[i] = (TxCB *)pciwindow_mem_alloc(
sizeof(TxCB) + MAX_TX_PACKET_SIZE);
}
ResetTxRing(p_i82559);
}
// ------------------------------------------------------------------------
//
// Function : ResetTxRing
//
// ------------------------------------------------------------------------
static void ResetTxRing(struct i82559* p_i82559)
{
int i;
cyg_uint32 ioaddr;
#ifdef DEBUG_82559
os_printf("ResetTxRing %d\n", p_i82559->index);
#endif
ioaddr = p_i82559->io_address;
p_i82559->tx_descriptor_add =
p_i82559->tx_descriptor_active =
p_i82559->tx_descriptor_remove = 0;
p_i82559->tx_in_progress =
p_i82559->tx_queue_full = 0;
for ( i = 0; i < MAX_TX_DESCRIPTORS; i++) {
TxCB *p_txcb = p_i82559->tx_ring[i];
CYG_ASSERT( (cyg_uint8 *)p_txcb >= i82559_heap_base, "txcb under" );
CYG_ASSERT( (cyg_uint8 *)p_txcb < i82559_heap_free, "txcb over" );
p_txcb->txstatus = 0;
p_txcb->command = 0;
p_txcb->link = VIRT_TO_BUS((cyg_uint32)p_txcb);
p_txcb->tbd_address = 0xFFFFFFFF;
p_txcb->tbd_number = 0;
p_txcb->tx_threshold = 16;
p_txcb->eof = 1;
p_txcb->count = 0;
p_i82559->tx_keys[i] = 0;
}
wait_for_cmd_done(ioaddr);
OUTL(0, ioaddr + SCBPointer);
OUTW(SCB_M | CU_ADDR_LOAD, ioaddr + SCBCmd);
}
// ------------------------------------------------------------------------
//
// Function : TxMachine (Called from FG & ISR)
//
// This steps the Tx Machine onto the next record if necessary - allowing
// for missed interrupts, and so on.
// ------------------------------------------------------------------------
static void TxMachine(struct i82559* p_i82559)
{
int tx_descriptor_active;
cyg_uint32 ioaddr;
tx_descriptor_active = p_i82559->tx_descriptor_active;
ioaddr = p_i82559->io_address;
// See if the CU is idle when we think it isn't; this is the only place
// tx_descriptor_active is advanced. (Also recovers from a dropped intr)
if ( p_i82559->tx_in_progress ) {
cyg_uint16 status;
status = INW(ioaddr + SCBStatus);
if ( 0 == (status & CU_STATUS_MASK) ) {
// It is idle. So ack the TX interrupts
OUTW( SCB_INTACK_TX, ioaddr + SCBStatus);
// (see pages 6-10 & 6-90)
// and step on to the next queued tx.
p_i82559->tx_in_progress = 0;
if ( ++tx_descriptor_active >= MAX_TX_DESCRIPTORS )
tx_descriptor_active = 0;
p_i82559->tx_descriptor_active = tx_descriptor_active;
}
}
// is the CU idle, and there a next tx to set going?
if ( ( ! p_i82559->tx_in_progress )
&& p_i82559->tx_descriptor_add != tx_descriptor_active ) {
TxCB *p_txcb;
p_txcb = p_i82559->tx_ring[tx_descriptor_active];
CYG_ASSERT( (cyg_uint8 *)p_txcb >= i82559_heap_base, "txcb under" );
CYG_ASSERT( (cyg_uint8 *)p_txcb < i82559_heap_free, "txcb over" );
#ifdef DEBUG_82559
os_printf("Tx %d %x: Starting Engines, KEY %x\n",
p_i82559->index, (int)p_i82559, key );
#endif
// make sure no command operating
wait_for_cmd_done(ioaddr);
// start Tx operation
OUTL(VIRT_TO_BUS(p_txcb), ioaddr + SCBPointer);
OUTW(CU_START, ioaddr + SCBCmd);
p_i82559->tx_in_progress = 1;
}
}
// ------------------------------------------------------------------------
//
// 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 i82559* p_i82559)
{
struct cyg_netdevtab_entry *ndp;
struct eth_drv_sc *sc;
int tx_descriptor_remove = p_i82559->tx_descriptor_remove;
ndp = (struct cyg_netdevtab_entry *)(p_i82559->ndp);
sc = (struct eth_drv_sc *)(ndp->device_instance);
CHECK_NDP_SC_LINK();
// "Done" txen are from here to active, OR
// the remove one if the queue is full AND its status is nonzero:
while ( (tx_descriptor_remove != p_i82559->tx_descriptor_active) ||
( p_i82559->tx_queue_full &&
(0 != p_i82559->tx_ring[ tx_descriptor_remove ]->txstatus) ) ) {
unsigned long key = p_i82559->tx_keys[ tx_descriptor_remove ];
#ifdef DEBUG_82559
os_printf("TxDone %d %x: KEY %x\n",
p_i82559->index, (int)p_i82559, key );
#endif
if (key) {
(sc->funs->eth_drv->tx_done)( sc, key, 1 /* status */ );
}
p_i82559->tx_keys[ tx_descriptor_remove ] = 0;
if ( ++tx_descriptor_remove >= MAX_TX_DESCRIPTORS )
tx_descriptor_remove = 0;
p_i82559->tx_descriptor_remove = tx_descriptor_remove;
p_i82559->tx_queue_full = 0;
}
}
// ------------------------------------------------------------------------
//
// Function : i82559_can_send
//
// ------------------------------------------------------------------------
static int
i82559_can_send(struct eth_drv_sc *sc)
{
struct i82559 *p_i82559;
int ints;
p_i82559 = (struct i82559 *)sc->driver_private;
IF_BAD_82559( p_i82559 ) {
#ifdef DEBUG
os_printf( "i82559_send: Bad device pointer %x\n", p_i82559 );
#endif
return 0;
}
// Advance TxMachine atomically
ints = Mask82559Interrupt(p_i82559);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -