📄 if_iq80310.c
字号:
if (temp1 & MDI_STAT_LINK) // speed only valid with good LNK
link_speed = (phy_addr_reg & I82555_100_MBPS) ? SPEED_100M : SPEED_10M;
#ifdef DEBUG
else
os_printf ("Connect Speed is NOT VALID\n");
#endif
}
if ((phy_id & 0xfffffff0) == ICS1890_PHY_ID) {
#ifdef DEBUG
os_printf ("Integrated Circuit Systems ICS1890 PHY detected...\n");
os_printf ("Revision = %c\n", 'A' + (phy_id & REVISION_MASK));
#endif
// dummy read for reliable status
(void)readMDI (ioaddr, MDI_DEFAULT_PHY_ADDR, ICS1890_QUICKPOLL_REG);
temp1 = readMDI (ioaddr, MDI_DEFAULT_PHY_ADDR, ICS1890_QUICKPOLL_REG);
if (temp1 & QUICK_LINK_VALID) // speed only valid with good LNK
link_speed = (temp1 & QUICK_100_MBPS) ? SPEED_100M : SPEED_10M;
#ifdef DEBUG
else
os_printf ("Connect Speed is NOT VALID\n");
#endif
}
if ((phy_id & 0xfffffff0) == DP83840_PHY_ID) {
#ifdef DEBUG
os_printf ("National DP83840 PHY detected...\n");
os_printf ("Revision = %c\n", 'A' + (phy_id & REVISION_MASK));
#endif
// dummy read for reliable status
(void)readMDI (ioaddr, MDI_DEFAULT_PHY_ADDR, MDI_PHY_STAT);
temp1 = readMDI (ioaddr, MDI_DEFAULT_PHY_ADDR, MDI_PHY_STAT);
phy_addr_reg = readMDI (ioaddr ,MDI_DEFAULT_PHY_ADDR, DP83840_PHY_ADDR_REG);
if (temp1 & MDI_STAT_LINK) // speed only valid with good LNK
link_speed = (phy_addr_reg & PHY_ADDR_SPEED_10_MBPS) ? SPEED_10M : SPEED_100M;
#ifdef DEBUG
else
os_printf ("Connect Speed is NOT VALID\n");
#endif
}
if ((phy_id & 0xfffffff0) == I82553_PHY_ID) {
#ifdef DEBUG
os_printf ("Intel 82553 PHY detected...\n");
os_printf ("Revision = %c\n", 'A' + (phy_id & REVISION_MASK));
#endif
broadcom_flag = true;
}
if (phy_id == I82553_REVAB_PHY_ID) {
#ifdef DEBUG
os_printf ("Intel 82553 PHY detected...\n");
os_printf ("Revision = B\n");
#endif
broadcom_flag = true;
}
if (broadcom_flag == true) {
temp2 = readMDI (ioaddr, MDI_DEFAULT_PHY_ADDR, I82553_PHY_EXT_REG0);
// dummy read for reliable status
(void)readMDI (ioaddr ,MDI_DEFAULT_PHY_ADDR, MDI_PHY_STAT);
temp1 = readMDI (ioaddr ,MDI_DEFAULT_PHY_ADDR, MDI_PHY_STAT);
if (temp1 & MDI_STAT_LINK) { // speed only valid with good LNK
link_speed = (temp2 & EXT_REG0_100_MBPS) ? SPEED_100M : SPEED_10M;
#ifdef DEBUG
} else {
os_printf ("Connect Speed is NOT VALID\n");
#endif
}
}
#ifdef KEEP_STATISTICS
#ifdef CYGDBG_DEVS_ETH_ARM_IQ80310_KEEP_82559_STATISTICS
p_i82559->p_statistics =
p_statistics = pciwindow_mem_alloc(sizeof(I82559_COUNTERS));
memset(p_statistics, 0xFFFFFFFF, sizeof(I82559_COUNTERS));
wait_for_cmd_done(ioaddr); // make sure no command operating
// set statistics dump address
OUTL(VIRT_TO_BUS(p_statistics), ioaddr + SCBPointer);
OUTW(SCB_M | CU_STATSADDR, ioaddr + SCBCmd);
wait_for_cmd_done(ioaddr); // make sure no command operating
OUTW(SCB_M | CU_DUMPSTATS, ioaddr + SCBCmd); // start register dump
#endif
#endif
// Set the base address
wait_for_cmd_done(ioaddr);
OUTL(0, ioaddr + SCBPointer); // load ru base address = 0
OUTW(SCB_M | RUC_ADDR_LOAD, ioaddr + SCBCmd);
udelay( 1000 ); // load pointer to Rx Ring
OUTL(VIRT_TO_BUS(p_i82559->rx_ring[0]), ioaddr + SCBPointer);
OUTW(RUC_START, ioaddr + SCBCmd);
p_i82559->active = 1;
initPHY(ioaddr, phy_id);
#ifdef CYGPKG_NET
if (( 0
#ifdef ETH_DRV_FLAGS_PROMISC_MODE
!= (flags & ETH_DRV_FLAGS_PROMISC_MODE)
#endif
) || (ifp->if_flags & IFF_PROMISC)
) {
eth_set_promiscuous_mode(p_i82559);
}
#endif
#ifdef DEBUG
{
int status = i82559_status( sc );
os_printf("i82559_start %d flg %x Link = %s, %s Mbps, %s Duplex\n",
p_i82559->index,
*(int *)p_i82559,
status & GEN_STATUS_LINK ? "Up" : "Down",
status & GEN_STATUS_100MBPS ? "100" : "10",
status & GEN_STATUS_FDX ? "Full" : "Half");
}
#endif
}
// ------------------------------------------------------------------------
//
// Function : i82559_status
//
// ------------------------------------------------------------------------
int i82559_status( struct eth_drv_sc *sc )
{
int status;
struct i82559 *p_i82559;
cyg_uint32 ioaddr;
p_i82559 = (struct i82559 *)sc->driver_private;
IF_BAD_82559( p_i82559 ) {
#ifdef DEBUG
os_printf( "i82559_status: Bad device pointer %x\n", p_i82559 );
#endif
return 0;
}
ioaddr = p_i82559->io_address; // get 82559's I/O address
status = INB(ioaddr + SCBGenStatus);
return status;
}
// ------------------------------------------------------------------------
//
// Function : BringDown82559
//
// ------------------------------------------------------------------------
static void i82559_stop( struct eth_drv_sc *sc )
{
struct i82559 *p_i82559;
p_i82559 = (struct i82559 *)sc->driver_private;
IF_BAD_82559( p_i82559 ) {
#ifdef DEBUG
os_printf( "i82559_stop: Bad device pointer %x\n", p_i82559 );
#endif
return;
}
#ifdef DEBUG
os_printf("i82559_stop %d flg %x\n", p_i82559->index, *(int *)p_i82559 );
#endif
p_i82559->active = 0; // stop people tormenting it
i82559_reset(p_i82559); // that should stop it
ResetRxRing( p_i82559 );
ResetTxRing( p_i82559 );
}
// ------------------------------------------------------------------------
//
// Function : InitRxRing
//
// ------------------------------------------------------------------------
static void InitRxRing(struct i82559* p_i82559)
{
int i;
RFD *rfd;
RFD *p_rfd = 0;
#ifdef DEBUG_82559
os_printf("InitRxRing %d\n", p_i82559->index);
#endif
for ( i = 0; i < MAX_RX_DESCRIPTORS; i++ ) {
rfd = (RFD *)pciwindow_mem_alloc(sizeof(RFD) + MAX_RX_PACKET_SIZE);
p_i82559->rx_ring[i] = rfd;
if ( i )
p_rfd->link = VIRT_TO_BUS(rfd);
p_rfd = (RFD *)rfd;
}
// link last RFD to first:
p_rfd->link = VIRT_TO_BUS(p_i82559->rx_ring[0]);
ResetRxRing( p_i82559 );
}
// ------------------------------------------------------------------------
//
// Function : ResetRxRing
//
// ------------------------------------------------------------------------
static void ResetRxRing(struct i82559* p_i82559)
{
RFD *p_rfd;
int i;
#ifdef DEBUG_82559
os_printf("ResetRxRing %d\n", p_i82559->index);
#endif
for ( i = 0; i < MAX_RX_DESCRIPTORS; i++ ) {
p_rfd = p_i82559->rx_ring[i];
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" );
#ifdef CYGPKG_REDBOOT
// FIXME. Temporary hack for expediency.
// Need to make this decision at runtime.
break;
#endif
}
// 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -