if_i21143.c
来自「开放源码实时操作系统源码.」· C语言 代码 · 共 1,882 行 · 第 1/5 页
C
1,882 行
}
// ------------------------------------------------------------------------
//
// Function : i21143_send
//
// ------------------------------------------------------------------------
static void
i21143_send(struct eth_drv_sc *sc,
struct eth_drv_sg *sg_list, int sg_len, int total_len,
unsigned long key)
{
struct i21143 *p_i21143;
cyg_uint32 ioaddr;
struct eth_drv_sg *last_sg;
volatile BUFDES *bp;
int bufcount;
cyg_uint32 x;
p_i21143 = (struct i21143 *)sc->driver_private;
IF_BAD_21143( p_i21143 ) {
#ifdef DEBUG_TRAFFIC
diag_printf( "i21143_send: Bad device pointer %x\n", p_i21143 );
#endif
return;
}
if ( NO_TX_IN_PROGRESS != p_i21143->tx_endbuf) {
// Then we cannot do this
#ifdef DEBUG_TRAFFIC
diag_printf( "i21143_send: tx busy %x, %d bufs key %x\n",
p_i21143, p_i21143->tx_endbuf, p_i21143->tx_keys[0] );
#endif
CYG_FAIL( "Send call when already busy" );
INCR_STAT( tx_dropped );
return;
}
ioaddr = p_i21143->io_address;
bp = p_i21143->tx_ring;
bufcount = 0;
#ifdef DEBUG_TRAFFIC
diag_printf( "i21143_send() key %x\n", key );
#endif
INCR_STAT( tx_count );
for ( last_sg = &sg_list[sg_len]; sg_list < last_sg; sg_list++ ) {
cyg_uint8 *from_p;
int l;
from_p = (cyg_uint8 *)(sg_list->buf); // normal cached address
l = sg_list->len;
if ( l > total_len )
l = total_len;
// Ensure the mbuf contents really is in RAM where DMA can see it.
// (Must round to cache lines apparantly for some MIPS)
HAL_DCACHE_STORE( ((CYG_ADDRESS)from_p) &~(HAL_DCACHE_LINE_SIZE-1),
l + HAL_DCACHE_LINE_SIZE );
// There are two pointer, length pairs in each descriptor. We only
// bother using the first one - the code saved is small but so is
// the overhead of memory.
bp->buf1 = CYGHWR_PCI_VIRT_TO_BUS( from_p ); // uncached real RAM address
bp->buf2 = 0;
// Record length and add endring flag iff end of ring - never leave
// it blank in memory!
x = (l << DES1_B1SIZE_SHIFT) & DES1_B1SIZE_MASK; // plus zero buf2 size.
if ( (TX_DESCRIPTORS-1) == bufcount )
x |= DES1_ENDRING;
bp->des1 = x;
// Leave writing the zeroth bufdesc DES0 until all are complete:
// the tx engine will be stopped looking there.
if ( 0 < bufcount ) // then we can write DES0 also.
bp->des0 = DES0_STATUS_OWN_OPEN;
total_len -= l;
bp++;
bufcount++;
if ( 0 > total_len )
break; // Should exit via sg_last normally
}
CYG_ASSERT( 0 == total_len, "length mismatch in tx" );
CYG_ASSERT( last_sg == sg_list, "sg count mismatch in tx" );
CYG_ASSERT( bp > &p_i21143->tx_ring[0], "bp underflow" );
bp--; // back to the last-used bp.
bufcount--;
p_i21143->tx_endbuf = bufcount; // record that we are busy
p_i21143->tx_keys[0] = key; // and the key to return
CYG_ASSERT( bp < &p_i21143->tx_ring[ TX_DESCRIPTORS ], "bp underflow" );
// Mark this the last valid buffer.
bp->des1 |= TDES1_CONTROL_LAST | TDES1_CONTROL_INTERRUPT;
CYG_ASSERT( &(p_i21143->tx_ring[bufcount]) == bp, "Bp/bufcount misstep" );
bp++;
bufcount++;
// Make the rest be null links
for ( /* bp */ ; bp < &p_i21143->tx_ring[ TX_DESCRIPTORS ]; bp++ ) {
bp->buf1 = 0;
bp->buf2 = 0;
x = 0; // zero size for both buffers
if ( (TX_DESCRIPTORS-1) == bufcount )
x |= DES1_ENDRING;
bp->des1 = x;
bp->des0 = DES0_STATUS_OWN_OPEN;
bufcount++;
}
// Now it's safe to write the zeroth descriptor:
p_i21143->tx_ring->des1 |= TDES1_CONTROL_FIRST;
p_i21143->tx_ring->des0 = DES0_STATUS_OWN_OPEN;
#ifdef DEBUG_TRAFFIC_TXDETAILS
dump_tx_details( p_i21143, "i21143_send" );
#endif
// And start off the tx system
x = INL( CSR_STATUS );
#ifdef DEBUG_TRAFFIC
diag_printf( "i21143_send: ready, status %08x %s\n",
x,
(CSR_STATUS_TXSTATUS & x) != CSR_STATUS_TXSTATUS_STOPPED ?
"Running" : "Stopped" );
#endif
if ( CSR_STATUS_TXSTATUS_STOPPED == (CSR_STATUS_TXSTATUS & x) ) {
cyg_uint32 l;
// Then we must initialize and start the tx machine
OUTL( CYGHWR_PCI_VIRT_TO_BUS( (cyg_uint32)p_i21143->tx_ring ), CSR_TXBASE );
l = INL( CSR_OPMODE );
l |= CSR_OPMODE_TX_START;
OUTL( l, CSR_OPMODE );
}
else if ( CSR_STATUS_TXSTATUS_SUSPENDED == (CSR_STATUS_TXSTATUS & x) ) {
// Then we just have to ping it
OUTL( 0, CSR_TXPOLL );
}
else {
#ifdef DEBUG_TRAFFIC
diag_printf( "i21143_send: tx not ready %x CSR_STATUS %08x\n", p_i21143, x );
#endif
CYG_FAIL( "Tx is not ready to tx" );
// Try to recover by brutal means...
i21143_stop( sc ); // will return the key
i21143_start( sc, NULL, 0 );
}
}
// ------------------------------------------------------------------------
//
// Function : i21143_reset
//
// ------------------------------------------------------------------------
static void
i21143_reset(struct i21143* p_i21143)
{
cyg_uint32 ioaddr = p_i21143->io_address;
cyg_uint32 l;
int i, status;
// First stop the tx and rx engines - doc suggests that's necessary
// before writing the reset reg, but it seems a little paranoid.
l = INL( CSR_OPMODE );
l &=~ (CSR_OPMODE_RX_START | CSR_OPMODE_TX_START);
OUTL( l, CSR_OPMODE );
for ( i = 0; i < 10000; i++) {
l = INL( CSR_STATUS );
if ( ((CSR_STATUS_TXSTATUS & l) == CSR_STATUS_TXSTATUS_STOPPED) &&
((CSR_STATUS_RXSTATUS & l) == CSR_STATUS_RXSTATUS_STOPPED) )
break;
}
#ifdef DEBUG_STARTSTOPRESET
diag_printf( "i21143_reset: rx and tx idle after %d iters, status %x\n",
i, l );
#endif
// Acknowledge all the interrupts from these activities
// within the device:
OUTL( 0xffffffff, CSR_STATUS ); // clear all bits
// Now reset the device. We are going to re-init all params anyway, so
// ignore other settings:
OUTL( CSR_BUSMODE_RESET, CSR_BUSMODE );
udelay( 100 ); // let reset take effect. "50 PCI clock cycles"
for ( i = 0; i < 10000; i++) {
l = INL( CSR_BUSMODE );
if ( (CSR_BUSMODE_RESET & l) == 0 )
break;
}
#ifdef DEBUG_STARTSTOPRESET
diag_printf( "i21143_reset: reset zero after %d iters, busmode %x\n",
i, l );
#endif
// Gross initialization
OUTL( 0 // No other options
// CSR_BUSMODE_PM
// CSR_BUSMODE_WIE
// CSR_BUSMODE_RLE
// CSR_BUSMODE_RME
// CSR_BUSMODE_DBO_BE
// CSR_BUSMODE_DBO_LE
// CSR_BUSMODE_TAP_SHIFT
| (1 << CSR_BUSMODE_CAL_SHIFT)
| (4 << CSR_BUSMODE_PBL_SHIFT)
// CSR_BUSMODE_ENDIAN_BE
// CSR_BUSMODE_ENDIAN_LE
// CSR_BUSMODE_DSL_SHIFT
// CSR_BUSMODE_BAR
// CSR_BUSMODE_RESET
, CSR_BUSMODE );
// No interrupt sources enabled yet
OUTL( 0, CSR_INTR_ENABLE );
OUTL( 0
// CSR_ROM_MII_MGT_MDI
| CSR_ROM_MII_MGT_MOM_READ
// CSR_ROM_MII_MGT_MDO
// CSR_ROM_MII_MGT_MDC
// CSR_ROM_MII_MGT_RD
// CSR_ROM_MII_MGT_WR
// CSR_ROM_MII_MGT_BR
// CSR_ROM_MII_MGT_SR
// CSR_ROM_MII_MGT_REG
// CSR_ROM_MII_MGT_SR_DO
// CSR_ROM_MII_MGT_SR_DI
// CSR_ROM_MII_MGT_SR_CK
// CSR_ROM_MII_MGT_SR_CS
| 0xff,
CSR_ROM_MII_MGT );
// -----------------------------------
// Now find out about the status of the PHY via MII
#if 0
// Try resetting the PHY and power-cycling it:
mii_write_register( ioaddr, PHY_CONTROL_REG, PHY_CONTROL_RESET | PHY_CONTROL_AUTONEG_EN);
while (1) {
int v;
v = mii_read_register( ioaddr, PHY_CONTROL_REG );
if ( 0 == (v & PHY_CONTROL_RESET) )
break;
}
mii_write_register( ioaddr, PHY_CONTROL_REG,
PHY_CONTROL_POWERDOWN | PHY_CONTROL_MII_DIS | PHY_CONTROL_AUTONEG_EN );
udelay( 1000 );
mii_write_register( ioaddr, PHY_CONTROL_REG, PHY_CONTROL_AUTONEG_EN | PHY_CONTROL_AUTONEG_RST );
udelay( 1000 );
while (1) {
int v;
v = mii_read_register( ioaddr, PHY_STATUS_REG );
if ( PHY_STATUS_AUTONEG_ACK & v )
break;
}
#endif
#ifdef DEBUG_DUMP_REGS
debug_dump_regs( ioaddr, MII );
#endif
status = i21143_status( p_i21143 );
p_i21143->line_status = status; // record it for SNMP info
#ifdef DEBUG_STARTSTOPRESET
diag_printf("i21143_reset %d flg %x Link = %s, %s Mbps, %s Duplex\n",
p_i21143->index,
*(int *)p_i21143,
(GEN_STATUS_LINK & status) ? "Up" : "Down",
(GEN_STATUS_100MBPS & status) ? "100" : "10",
(GEN_STATUS_FDX & status) ? "Full" : "Half");
#endif
OUTL( -1, CSR_ROM_PGM_ADDR );
OUTL( 0, CSR_INTR_MITIGATION );
// CSR13, 14 = 0; select SIA mode temporarily.
// OUTL( CSR_OPMODE_MUST_BE_ONE, CSR_OPMODE);
OUTL( CSR_SIA_CONN_DEFAULT, CSR_SIA_CONN );
OUTL( CSR_SIA_TXRX_DEFAULT, CSR_SIA_TXRX );
OUTL( CSR_SIA_GPPORT_DEFAULT, CSR_SIA_GPPORT );
// Last one, CSR6
l = 0
| CSR_OPMODE_SC
// CSR_OPMODE_RA
// CSR_OPMODE_IGNOREMSB
| CSR_OPMODE_MUST_BE_ONE
// CSR_OPMODE_SCR do not set for MII mode
// CSR_OPMODE_PCS do not set for MII mode
// CSR_OPMODE_TTM set for 10Mb, not set for 100Mb
| CSR_OPMODE_SF // Set the store&forward bit so we can keep-
| CSR_OPMODE_HBD // -up at 100Mbit
| CSR_OPMODE_PS_MIISYM
| CSR_OPMODE_CA
// CSR_OPMODE_TX_THRES_SHIFT
// CSR_OPMODE_TX_START
// CSR_OPMODE_FC
// (0 << CSR_OPMODE_LOOPBACK_SHIFT)
// CSR_OPMODE_FD
// CSR_OPMODE_MULTICAST // Pass all multicast
// CSR_OPMODE_PROMISC // Promisc mode
// CSR_OPMODE_SB
// CSR_OPMODE_IF // Inverse filtering (!)
// CSR_OPMODE_PB
// CSR_OPMODE_HO // 0: Perfect filter
// CSR_OPMODE_RX_START // 1: hashing for /all/ addresses
// CSR_OPMODE_HP // 0: Perfect filter of N address
; // 1: imperfect hash filter + 1 fixed addr
if ( GEN_STATUS_FDX & status )
l |= CSR_OPMODE_FD;
if ( ! (GEN_STATUS_100MBPS & status) )
l |= CSR_OPMODE_TTM;
OUTL( l, CSR_OPMODE );
}
// ------------------------------------------------------------------------
//
// INTERRUPT HANDLERS
//
// ------------------------------------------------------------------------
static cyg_uint32
eth_isr(cyg_vector_t vector, cyg_addrword_t data)
{
cyg_drv_interrupt_mask( vector );
#ifdef DEBUG_TRAFFIC
diag_printf( "i21143_isr, vector %d\n", vector );
#endif
return CYG_ISR_CALL_DSR; // schedule DSR
}
// An indirection is used because (if we have multiple devices) we don't
// know all the "sc" values at the time the interrupts are created.
static
void eth_dsr(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
{
struct i21143* p_i21143 = (struct i21143 *)data;
struct cyg_netdevtab_entry *ndp =
(struct cyg_netdevtab_entry *)(p_i21143->ndp);
struct eth_drv_sc *sc = (struct eth_drv_sc *)(ndp->device_instance);
INCR_STAT( interrupts );
// but here, it
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?