if_i21143.c

来自「开放源码实时操作系统源码.」· C语言 代码 · 共 1,882 行 · 第 1/5 页

C
1,882
字号
        ndp = (struct cyg_netdevtab_entry *)(p_i21143->ndp);
        sc = (struct eth_drv_sc *)(ndp->device_instance);
        CHECK_NDP_SC_LINK();
    }

    CYG_ASSERT( 0 <= p_i21143->next_rx_descriptor, "rx descriptor underflow" );
    CYG_ASSERT( RX_DESCRIPTORS > p_i21143->next_rx_descriptor, "rx descriptor overflow" );

    index = p_i21143->next_rx_descriptor;

    // Scan receive buffers
    for ( count = 0; count < RX_DESCRIPTORS; count++ ) {
        cyg_uint32 ldes0;
        int length;

        bp = &p_i21143->rx_ring[ index ];

        CYG_ASSERT( 0 == bp->buf2, "Corrupt bp->buf2" );
        CYG_ASSERT( 0 != bp->buf1, "Null bp->buf1" );
        CYG_ASSERT( (MAX_RX_PACKET_SIZE << DES1_B1SIZE_SHIFT) == (bp->des1 &~ DES1_ENDRING),
                    "Corrupt bp->des1" );

        ldes0 = bp->des0;

#ifdef DEBUG_TRAFFIC
        diag_printf( "PacketRxReady: index %d des0 = %08x, %s, %s, %d bytes\n",
                     index, ldes0,
                     (ldes0 & DES0_STATUS_OWN) ? "open" : "done",
                     ((RDES0_STATUS_FIRST | RDES0_STATUS_LAST | DES0_STATUS_ERROR) & ldes0)
                     == (RDES0_STATUS_FIRST | RDES0_STATUS_LAST) ? "OK" : "--",
                     (RDES0_COUNT_MASK & ldes0) >> RDES0_COUNT_SHIFT );
#endif        

        if ( DES0_STATUS_OWN_OPEN == (ldes0 & DES0_STATUS_OWN) )
            // This buffer bilong the device
            break;

        INCR_STAT( rx_count );

        // Otherwise, this one is for us
        if ( ((RDES0_STATUS_FIRST | RDES0_STATUS_LAST | DES0_STATUS_ERROR) & ldes0)
             == (RDES0_STATUS_FIRST | RDES0_STATUS_LAST) ) {
            // A complete packet and no error bit
        
            length = (RDES0_COUNT_MASK & ldes0) >> RDES0_COUNT_SHIFT;

            CYG_ASSERT( MAX_RX_PACKET_SIZE >= length, "Oversize Rx" );

            // tell the callback the right packet
            p_i21143->next_rx_descriptor = index;

            INCR_STAT( rx_good );

#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!
        }
#ifdef KEEP_STATISTICS
        else {
            if ( RDES0_STATUS_LAST & ldes0 ) {
                // Then we have good error info; analyse and count the errors
                if ( ldes0 & ( RDES0_STATUS_CRC ) )
                    INCR_STAT( rx_crc_errors );
                if ( ldes0 & ( RDES0_STATUS_DB ) )
                    INCR_STAT( rx_align_errors );
                if ( ldes0 & ( RDES0_STATUS_LATECOLL ) )
                    INCR_STAT( rx_collisions );
                if ( ldes0 & ( RDES0_STATUS_TOOLONG ) )
                    INCR_STAT( rx_too_long_frames );
                if ( ldes0 & ( RDES0_STATUS_RF ) )
                    INCR_STAT( rx_short_frames );
                if ( ldes0 & ( RDES0_STATUS_RE ) )
                    INCR_STAT( rx_symbol_errors );
            }
            else
                // Dunno what went wrong really...
                INCR_STAT( rx_resource_errors );
        }
#endif // KEEP_STATISTICS

        // Open the buffer for the device to use
        bp->des0 = DES0_STATUS_OWN_OPEN; // NIC owns it, not the CPU

        // Step i around the ring buffer...
        index++;
        if ( index >= RX_DESCRIPTORS )
            index = 0;
    }

    // record the right packet for next time
    p_i21143->next_rx_descriptor = index;

    CYG_ASSERT( 0 <= p_i21143->next_rx_descriptor, "rx descriptor underflow" );
    CYG_ASSERT( RX_DESCRIPTORS > p_i21143->next_rx_descriptor, "rx descriptor overflow" );

    {   //  We should not have needed ioaddr before this point.
        cyg_uint32 ioaddr;
        cyg_uint32 l;

        // Now examine the state of the receive engine and prompt it accordingly.
        ioaddr = p_i21143->io_address; // get 21143's I/O address
        l = INL( CSR_STATUS );

#ifdef DEBUG_TRAFFIC
        diag_printf( "PacketRxReady: done scan, next %d, status %08x %s\n",
                     p_i21143->next_rx_descriptor, l,
                     (CSR_STATUS_RXSTATUS & l) != CSR_STATUS_RXSTATUS_STOPPED ?
                     "Running" : "Stopped" );
#endif

        if ( (CSR_STATUS_RXSTATUS & l) != CSR_STATUS_RXSTATUS_STOPPED ) {
            // Then ping it into life
            OUTL( 0, CSR_RXPOLL );
        }
        else {
            // Oh dear, it's stopped; we must initialize and start the rx machine
            InitRxRing( p_i21143 );
            OUTL( CYGHWR_PCI_VIRT_TO_BUS( (cyg_uint32)p_i21143->rx_ring ), CSR_RXBASE );
            l = INL( CSR_OPMODE );
            l |= CSR_OPMODE_RX_START;
            OUTL( l, CSR_OPMODE );
            INCR_STAT( rx_resource );
            INCR_STAT( rx_restart );
        }
    }
}


// and the callback function

static void 
i21143_recv( struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len )
{
    volatile BUFDES *bp;
    struct i21143 *p_i21143;
    cyg_uint32 from_p;
    int total_len;
    struct eth_drv_sg *last_sg;

    p_i21143 = (struct i21143 *)(sc->driver_private);

    CYG_ASSERT( 0 <= p_i21143->next_rx_descriptor, "rx descriptor underflow" );
    CYG_ASSERT( RX_DESCRIPTORS > p_i21143->next_rx_descriptor, "rx descriptor overflow" );

    bp = &p_i21143->rx_ring[ p_i21143->next_rx_descriptor ];

    CYG_ASSERT( 0 == bp->buf2, "Corrupt bp->buf2" );
    CYG_ASSERT( 0 != bp->buf1, "Null bp->buf1" );
    CYG_ASSERT( DES0_STATUS_OWN_DONE == (bp->des0 & DES0_STATUS_OWN), "bp not done" );

    // Copy the data to the network stack
    from_p = CYGHWR_BUS_TO_UNCACHED( bp->buf1 );
    total_len = (RDES0_COUNT_MASK & bp->des0) >> RDES0_COUNT_SHIFT;

#ifdef DEBUG_TRAFFIC
    diag_printf("Recv callback: index %d des0 = %08x: %d sg's, %d bytes\n",
                p_i21143->next_rx_descriptor, bp->des0, sg_len, 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

    INCR_STAT( rx_deliver );

    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( CYGHWR_BUS_TO_UNCACHED( bp->buf1 ) < from_p, "from_p wild in rx" );
    CYG_ASSERT( CYGHWR_BUS_TO_UNCACHED( bp->buf1 ) + MAX_RX_PACKET_SIZE >= from_p,
                "from_p overflow in rx" );
}


// ------------------------------------------------------------------------
//
//  Function : InitTxRing
//
// ------------------------------------------------------------------------
static void
InitTxRing(struct i21143* p_i21143)
{
    int i;
    volatile BUFDES *bp;

    p_i21143->tx_ring =
        (BUFDES *)CYGHWR_CACHED_TO_UNCACHED( &(p_i21143->_tx[0]) );

    bp = p_i21143->tx_ring;
    for ( i = 0 ; i < TX_DESCRIPTORS; i++ ) {
        bp->des0 = DES0_STATUS_OWN_DONE; // CPU owns it, not the NIC
        bp->des1 = 0;
        bp->buf1 = bp->buf2 = 0;
        bp++;
    }
    bp--; // last one
    bp->des1 |= DES1_ENDRING;
}

// ------------------------------------------------------------------------
//
//  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 i21143* p_i21143)
{
    struct eth_drv_sc *sc;
    unsigned long key = 0;
    cyg_uint32 ioaddr;

    {
        struct cyg_netdevtab_entry *ndp;
        ndp = (struct cyg_netdevtab_entry *)(p_i21143->ndp);
        sc = (struct eth_drv_sc *)(ndp->device_instance);
        CHECK_NDP_SC_LINK();
    }

    ioaddr = p_i21143->io_address; // get 21143's I/O address

#ifdef DEBUG_TRAFFIC_TXDETAILS
    dump_tx_details( p_i21143, "TxDone" );
#endif

    if ( NO_TX_IN_PROGRESS != p_i21143->tx_endbuf) {
        cyg_uint32 l;
        volatile BUFDES *bp;
        cyg_uint32 des;

        CYG_ASSERT( TX_DESCRIPTORS > p_i21143->tx_endbuf, "tx_endbuf range" );

        l = INL( CSR_STATUS ); // Important: read this first

        bp = p_i21143->tx_ring;
        bp += p_i21143->tx_endbuf; // The descriptor with the "end" marker

        // It's not clear where error status gets written if the error is
        // *before* the end-marked bufdesc.  We'll see.

        des = bp->des1;
        CYG_ASSERT( TDES1_CONTROL_LAST & des , "Last buf not marked" );
        CYG_ASSERT( TDES1_CONTROL_INTERRUPT & des , "No interrupt req" );
        CYG_ASSERT( 0 == (DES1_2ACHAIN & des), "Buffer chained" );
        CYG_ASSERT( 0 == ((TDES1_CONTROL_SETUP |
                           TDES1_CONTROL_SETUP_FT1 |
                           TDES1_CONTROL_SETUP_FT0 |
                           TDES1_CONTROL_NO_CRC |
                           TDES1_CONTROL_NO_PAD)
                          & des),   "Buffer wierd flags" );
        des = bp->des0;
        if ( DES0_STATUS_OWN_DONE == (des & DES0_STATUS_OWN) ) {
            // Then it finished; somehow...
            key = p_i21143->tx_keys[ 0 ];
#ifdef DEBUG_TRAFFIC
            diag_printf("TxDone: KEY %x, %d descs, status %08x\n",
                        key, p_i21143->tx_endbuf+1, des );
#endif
#ifdef KEEP_STATISTICS
            // Then look for an error code from the tx records...
            if ( ! ( DES0_STATUS_ERROR & des ) )
                INCR_STAT( tx_good );
            // Not all the following are errors, so check all
            if ( des & ( TDES0_STATUS_LO | TDES0_STATUS_NC ) )
                INCR_STAT( tx_carrier_loss );
            if ( des & ( TDES0_STATUS_LC ) )
                INCR_STAT( tx_late_collisions );
            if ( des & ( TDES0_STATUS_EC ) )
                INCR_STAT( tx_max_collisions );
            if ( des & ( TDES0_STATUS_LF ) )
                INCR_STAT( tx_sqetesterrors );
            if ( des & ( TDES0_STATUS_UFL ) )
                INCR_STAT( tx_underrun );
            if ( des & ( TDES0_STATUS_DE ) )
                INCR_STAT( tx_deferred );
            // Now count collisions per se:
            des = ((des & TDES0_STATUS_CC_MASK) >> TDES0_STATUS_CC_SHIFT);
            if ( 0 < des ) {
                INCR_STAT( tx_total_collisions );
                if ( 1 < des )
                    INCR_STAT( tx_mult_collisions );
                else 
                    INCR_STAT( tx_single_collisions );
            }
#endif // KEEP_STATISTICS
        }
        else {
            // a Tx is in progress, but it has not yet completed;
            // probably wise to check on the tx machine status.
            if ( ((CSR_STATUS_TXSTATUS & l) == CSR_STATUS_TXSTATUS_STOPPED) ||
                 ((CSR_STATUS_TXSTATUS & l) == CSR_STATUS_TXSTATUS_SUSPENDED) ) {
                // then it's not active right now!
                key = p_i21143->tx_keys[ 0 ];
#ifdef DEBUG_TRAFFIC
                diag_printf("TxDone STOPPED!  KEY %x, %d descs, status %08x, CSR_STATUS %08x\n",
                            key, p_i21143->tx_endbuf, des, l );
#endif
                INCR_STAT( tx_underrun ); // at a guess...
            }
        }

        // Common "done" code - key nonzero => report done
        if (key) {
            p_i21143->tx_keys[ 0 ] = 0;
            p_i21143->tx_endbuf = NO_TX_IN_PROGRESS;
            // Then tell the stack we are done:
            INCR_STAT( tx_complete );
            (sc->funs->eth_drv->tx_done)( sc, key, 0 );
        }
    }
}


// ------------------------------------------------------------------------
//
//  Function : i21143_can_send
//
// ------------------------------------------------------------------------

static int 
i21143_can_send(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_can_send: Bad device pointer %x\n", p_i21143 );
#endif
        return 0;
    }

    if ( p_i21143->active ) {
        if ( NO_TX_IN_PROGRESS != p_i21143->tx_endbuf )
            // Poll for Tx completion
            TxDone( p_i21143 );

        // Poll for receptions
        PacketRxReady( p_i21143 );
    }

#ifdef neverDEBUG_TRAFFIC
    diag_printf( "i21143_can_send: returning %d\n",
                 (NO_TX_IN_PROGRESS == p_i21143->tx_endbuf) && p_i21143->active );
#endif
    
    return (NO_TX_IN_PROGRESS == p_i21143->tx_endbuf) && p_i21143->active;

⌨️ 快捷键说明

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