if_i21143.c

来自「eCos操作系统源码」· C语言 代码 · 共 1,953 行 · 第 1/5 页

C
1,953
字号
        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 voidi21143_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_uint32eth_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 must be a *sc:    eth_drv_dsr( vector, count, (cyg_addrword_t)sc );}// ------------------------------------------------------------------------// Deliver routine:voidi21143_deliver(struct eth_drv_sc *sc){    struct i21143* p_i21143 = (struct i21143 *)(sc->driver_private);    cyg_uint32 status;    cyg_uint32 ioaddr;    IF_BAD_21143( p_i21143 ) {#ifdef DEBUG_TRAFFIC        diag_printf( "i21143_deliver: Bad device pointer %x\n", p_i21143 );#endif        return;    }    ioaddr = p_i21143->io_address;    status = INL( CSR_STATUS );#ifdef DEBUG_TRAFFIC    diag_printf( "i21143_deliver: status %08x\n", status );#endif        // Acknowledge all INT sources that were active    OUTL( status, CSR_STATUS );    // Search for link status changes    if ( i21143_status_changed( p_i21143 ) ) {#ifdef DEBUG_TRAFFIC        diag_printf( "i21143_can_send: status changed\n" );#endif        i21143_stop( sc );        i21143_start( sc, NULL, 0 );    }    if ( (CSR_STATUS_TBU | CSR_STATUS_TX_STOPPED | CSR_STATUS_TX_INTR)         & status ) {        TxDone( p_i21143 );    }    if ( (CSR_STATUS_RX_STOPPED | CSR_STATUS_RBU | CSR_STATUS_RX_INTR)         & status ) {        PacketRxReady( p_i21143 );    }    cyg_drv_interrupt_acknowledge(p_i21143->vector);    cyg_drv_interrupt_unmask( p_i21143->vector );}// ------------------------------------------------------------------------// Device table entry to operate the chip in a polled mode.// Only diddle the interface we were asked to!voidi21143_poll(struct eth_drv_sc *sc){    struct i21143 *p_i21143;    p_i21143 = (struct i21143 *)sc->driver_private;        IF_BAD_21143( p_i21143 ) {#ifdef DEBUG_TRAFFIC        diag_printf( "i21143_poll: Bad device pointer %x\n", p_i21143 );#endif        return;    }    // As it happens, this driver always requests the DSR to be cal

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?