if_i82544.c
来自「开放源码实时操作系统源码.」· C语言 代码 · 共 2,053 行 · 第 1/5 页
C
2,053 行
p_i82544->index );
#endif
return;
}
if ( p_i82544->active )
i82544_stop( sc );
// Enable device
p_i82544->active = 1;
/* Enable promiscuous mode if requested, reception of oversized frames always.
* The latter is needed for VLAN support and shouldn't hurt even if we're not
* using VLANs.
*/
i82544_configure(p_i82544, 0
#ifdef CYGPKG_NET
|| !!(ifp->if_flags & IFF_PROMISC)
#endif
#ifdef ETH_DRV_FLAGS_PROMISC_MODE
|| !!(flags & ETH_DRV_FLAGS_PROMISC_MODE)
#endif
, 1);
// enable receiver
rxctl = INL( ioaddr + I82544_RCTL );
rxctl |= I82544_RCTL_EN;
OUTL( rxctl, ioaddr + I82544_RCTL );
// Enable transmitter
txctl = INL( ioaddr + I82544_TCTL );
txctl |= I82544_TCTL_EN;
OUTL( txctl, ioaddr + I82544_TCTL );
}
// ------------------------------------------------------------------------
//
// Function : i82544_status
//
// ------------------------------------------------------------------------
int
i82544_status( struct eth_drv_sc *sc )
{
int status;
struct i82544 *p_i82544;
cyg_uint32 ioaddr;
#ifdef DEBUG
db_printf("i82544_status\n");
#endif
p_i82544 = (struct i82544 *)sc->driver_private;
IF_BAD_82544( p_i82544 ) {
#ifdef DEBUG
os_printf( "i82544_status: Bad device pointer %x\n", p_i82544 );
#endif
return 0;
}
ioaddr = p_i82544->io_address; // get 82544's I/O address
status = INL(ioaddr + I82544_STATUS);
return status;
}
// ------------------------------------------------------------------------
//
// Function : BringDown82544
//
// ------------------------------------------------------------------------
static void
i82544_stop( struct eth_drv_sc *sc )
{
struct i82544 *p_i82544;
cyg_uint32 ioaddr;
cyg_uint32 txctl, rxctl;
#ifdef DEBUG
db_printf("i82544_stop\n");
#endif
p_i82544 = (struct i82544 *)sc->driver_private;
IF_BAD_82544( p_i82544 ) {
#ifdef DEBUG
os_printf( "i82544_stop: Bad device pointer %x\n", p_i82544 );
#endif
return;
}
#ifdef DEBUG
os_printf("i82544_stop %d flg %x\n", p_i82544->index, *(int *)p_i82544 );
#endif
p_i82544->active = 0; // stop people tormenting it
ioaddr = p_i82544->io_address;
// disable receiver
rxctl = INL( ioaddr + I82544_RCTL );
rxctl &= ~I82544_RCTL_EN;
OUTL( rxctl, ioaddr + I82544_RCTL );
// Enable transmitter
txctl = INL( ioaddr + I82544_TCTL );
txctl &= ~I82544_TCTL_EN;
OUTL( txctl, ioaddr + I82544_TCTL );
}
// ------------------------------------------------------------------------
//
// Function : InitRxRing
//
// ------------------------------------------------------------------------
static void
InitRxRing(struct i82544* p_i82544)
{
int i;
CYG_ADDRESS rxring;
cyg_uint32 ioaddr = p_i82544->io_address;
cyg_uint32 rxctl;
#ifdef DEBUG_82544
os_printf("InitRxRing %d\n", p_i82544->index);
#endif
// Allocate array of Rx desriptors
rxring = pciwindow_mem_alloc(
MAX_RX_DESCRIPTORS * I82544_RD_SIZE + 32 );
// assign ring structure, aligning it on a 16 byte boudary.
p_i82544->rx_ring = (rxring + 15) & ~15;
// Allocate and fill in buffer pointers
for ( i = 0; i < MAX_RX_DESCRIPTORS; i++) {
CYG_ADDRESS rd = p_i82544->rx_ring + (i*I82544_RD_SIZE);
CYG_ADDRESS buf = pciwindow_mem_alloc(MAX_RX_PACKET_SIZE);
WRITEMEM64( rd + I82544_RD_BUFFER, VIRT_TO_BUS(buf) );
}
// Set the receiver queue registers
OUTL( VIRT_TO_BUS(p_i82544->rx_ring), ioaddr + I82544_RDBAL );
OUTL( 0, ioaddr + I82544_RDBAH );
OUTL( MAX_RX_DESCRIPTORS * I82544_RD_SIZE, ioaddr + I82544_RDLEN );
OUTL( 0, ioaddr + I82544_RDH );
OUTL( MAX_RX_DESCRIPTORS - 5, ioaddr + I82544_RDT );
// zero out RAT
for( i = 0; i < 32; i++ )
OUTL( 0, ioaddr + I82544_RAT +(i*4) );
// Zero out MTA
for( i = 0; i < 128; i++ )
OUTL( 0, ioaddr + I82544_MTA +(i*4) );
// Set up receiver to accept broadcasts
rxctl = INL( ioaddr + I82544_RCTL );
rxctl |= I82544_RCTL_BAM;
OUTL( rxctl, ioaddr + I82544_RCTL );
#ifdef DEBUG_82544
os_printf("RCTL %08x\n",rxctl);
#endif
p_i82544->next_rx_descriptor = 0;
p_i82544->rx_pointer = 0;
}
// ------------------------------------------------------------------------
//
// Function : PacketRxReady (Called from delivery thread & foreground)
//
// ------------------------------------------------------------------------
static void
PacketRxReady(struct i82544* p_i82544)
{
struct cyg_netdevtab_entry *ndp;
struct eth_drv_sc *sc;
cyg_int32 rxp;
cyg_uint32 ioaddr;
#ifdef DEBUG_82544
// db_printf("PacketRxReady\n");
#endif
ndp = (struct cyg_netdevtab_entry *)(p_i82544->ndp);
sc = (struct eth_drv_sc *)(ndp->device_instance);
CHECK_NDP_SC_LINK();
ioaddr = p_i82544->io_address;
rxp = p_i82544->rx_pointer;
for(;;)
{
cyg_int32 rxh, rxt;
CYG_ADDRESS dp;
cyg_uint8 status;
rxh = INL( ioaddr + I82544_RDH );
#if 0 //def DEBUG_82544
os_printf("rxp %04d rxh %04x\n",rxp,rxh);
#endif
// If the head pointer has not advanced, there have been no
// packets received.
if( rxh == rxp )
break;
// Form packet address
dp = p_i82544->rx_ring + (rxp * I82544_RD_SIZE);
// Get status
READMEM8( dp + I82544_RD_STATUS, status );
#if 0 //def DEBUG_82544
{
cyg_uint16 length;
READMEM16( dp + I82544_RD_LENGTH, length );
os_printf("rxp %04d status %02x length %d\n",rxp,status,length);
}
#endif
if( status & I82544_RD_STATUS_EOP )
{
cyg_uint16 length;
READMEM16( dp + I82544_RD_LENGTH, length );
#ifdef DEBUG_82544
os_printf("rxp %04d length %d\n",rxp,length);
#endif
CYG_ASSERT( MAX_RX_PACKET_SIZE >= length, "Oversize Rx" );
// tell the callback the right packet
p_i82544->next_rx_descriptor = rxp;
#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!
}
// Advance rxp pointer
rxp = ( rxp + 1 ) % MAX_RX_DESCRIPTORS;
// We can now also advance the tail pointer by 1
rxt = INL( ioaddr + I82544_RDT );
dp = p_i82544->rx_ring + (rxt * I82544_RD_SIZE);
WRITEMEM8( dp + I82544_RD_STATUS, status );
rxt = ( rxt + 1 ) % MAX_RX_DESCRIPTORS;
OUTL( rxt, ioaddr + I82544_RDT );
#ifdef CYGPKG_IO_ETH_DRIVERS_STAND_ALONE
// Can't deliver more than one packet in polled standalone mode
break;
#endif
}
// Save next rx pointer for next time.
p_i82544->rx_pointer = rxp;
}
// and the callback function
static void
i82544_recv( struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len )
{
struct i82544 *p_i82544;
cyg_int32 rxp;
CYG_ADDRESS dp;
CYG_ADDRESS from_p;
cyg_uint16 total_len;
struct eth_drv_sg *last_sg;
#ifdef DEBUG_82544
db_printf("i82544_recv\n");
#endif
p_i82544 = (struct i82544 *)sc->driver_private;
IF_BAD_82544( p_i82544 ) {
#ifdef DEBUG_82544
os_printf( "i82544_recv: Bad device pointer %x\n", p_i82544 );
#endif
return;
}
rxp = p_i82544->next_rx_descriptor;
// Form packet address
dp = p_i82544->rx_ring + (rxp * I82544_RD_SIZE);
#if 0 //def DEBUG_82544
{
int i;
os_printf("RxD %08x",dp);
for( i = 0; i < 16; i++ )
{
cyg_uint8 b;
if( (i%8) == 0 ) os_printf("\n");
READMEM8( dp + i, b );
os_printf("%02x ",b);
}
os_printf("\n");
}
#endif
// Copy the data to the network stack
READMEM64( dp + I82544_RD_BUFFER, from_p );
from_p = BUS_TO_VIRT(from_p);
READMEM16( dp + I82544_RD_LENGTH, total_len );
#ifdef DEBUG_82544
db_printf("RXP: %04x len %d\n",rxp,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
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;
#if 0 //def DEBUG_82544
{
int i,ll = l;
os_printf("Pkt len %d",l);
if( ll > 32 ) ll = 32;
for( i = 0; i < ll; i++ )
{
cyg_uint8 b;
if( (i%8) == 0 ) os_printf("\n %04x: ",i);
b = ((cyg_uint8 *)from_p)[i];
os_printf("%02x ",b);
}
os_printf("\n");
}
#endif
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" );
}
// ------------------------------------------------------------------------
//
// Function : InitTxRing
//
// ------------------------------------------------------------------------
static void
InitTxRing(struct i82544* p_i82544)
{
int i;
cyg_uint32 ioaddr = p_i82544->io_address;
CYG_ADDRESS txring;
cyg_uint32 txctl;
#ifdef DEBUG_82544
os_printf("InitTxRing %d\n", p_i82544->index);
#endif
// Allocate array of Tx desriptors
txring = pciwindow_mem_alloc(
MAX_TX_DESCRIPTORS * I82544_TD_SIZE + 32 );
// assign ring structure, aligning it on a 16 byte boudary.
p_i82544->tx_ring = (txring + 15) & ~15;
// Allocate and fill in buffer pointers
for ( i = 0; i < MAX_TX_DESCRIPTORS; i++) {
CYG_ADDRESS
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?