if_i21143.c

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

C
1,953
字号
            // 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 functionstatic 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 voidInitTxRing(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 voidTxDone(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;}// ------------------------------------------------------------------------////  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

⌨️ 快捷键说明

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