if_upd985xx.c

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

C
1,622
字号
#ifdef DEBUG    os_printf("eth_upd985xx_stop %d flg %x\n", p_eth_upd985xx->index, *(int *)p_eth_upd985xx );#endif    p_eth_upd985xx->active = 0;         // stop people tormenting it    if ( p_eth_upd985xx->tx_busy ) {        // Then it is finshed now, by force:        cyg_uint32 key = p_eth_upd985xx->tx_keys[ 0 ];        // Turn off the transmitter (before the callback to the stack).        OUTL( ETH_TXCR, 0 );#ifdef DEBUG_TRAFFIC        os_printf("Stop: tidying up TX, KEY %x\n", key );#endif        // Leave tx_busy true so no recursion can occur here.        // Then tell the stack we are done:        if ( key ) {            (sc->funs->eth_drv->tx_done)( sc, key, 0 );        }    }    p_eth_upd985xx->tx_keys[ 0 ] = 0;    p_eth_upd985xx->tx_busy = p_eth_upd985xx->active = 0;    eth_upd985xx_reset(p_eth_upd985xx);    ResetTxRing( p_eth_upd985xx );}// ------------------------------------------------------------------------////  Function : InitRxRing//// ------------------------------------------------------------------------STATIC void InitRxRing(struct eth_upd985xx* p_eth_upd985xx){    int i;    struct bufdesc *bp;    // first just blat the various flags and addresses: the first N    // bufdescs point to data buffers, the last one is NULL.    bp = (struct bufdesc *)VIRT_TO_BUS( &p_eth_upd985xx->rx_bufdesc[0] );    // Record the initial active buffer:    p_eth_upd985xx->rxring_active = bp;    p_eth_upd985xx->rxring_active_index = 0;    for ( i = 0; i < NUM_RXBUFS - 1; i++, bp++ ) {        bp->ptr = VIRT_TO_BUS( &rx_databuf[i][0] );        bp->attr = ( ETH_BUF_D_L_DATA | ETH_BUF_OWN_CPU                     | (ETH_BUF_SIZE & sizeof( rx_databuf[0] )) );    }    CYG_ASSERT( i == NUM_RXBUFS-1, "Penultimate rx buffer index mismatch" );    CYG_ASSERT( (cyg_uint8 *)bp ==                 VIRT_TO_BUS( &p_eth_upd985xx->rx_bufdesc[NUM_RXBUFS-1] ),                "Penultimate rx buffer address mismatch" );    // NULL out the penultimate one    bp->ptr = NULL;    bp->attr = 0;    // And record it as next one to use    p_eth_upd985xx->rxring_next = bp;    p_eth_upd985xx->rxring_next_index = NUM_RXBUFS-1;    // Step on to the extra entry at the end which makes a ring:    bp++;    CYG_ASSERT( (cyg_uint8 *)bp ==                 VIRT_TO_BUS( &p_eth_upd985xx->rx_bufdesc[NUM_RXBUFS] ),                "Ultimate rx buffer address mismatch" );    // Link the Ultimate back to the start    bp->ptr = (cyg_uint8 *)p_eth_upd985xx->rxring_active; // Zeroth entry    bp->attr = ETH_BUF_D_L_LINK;    // All done.}// ------------------------------------------------------------------------////  Function : NextRxRing//// ------------------------------------------------------------------------STATIC void NextRxRing(struct eth_upd985xx* p_eth_upd985xx ){    volatile struct bufdesc *next, *dead;    int iactive;    int inext;    iactive = p_eth_upd985xx->rxring_active_index;    inext = p_eth_upd985xx->rxring_next_index;    // Preconditions:    CYG_ASSERT( 0 <=   inext && inext   < NUM_RXBUFS, "Bad inext" );    CYG_ASSERT( 0 <= iactive && iactive < NUM_RXBUFS, "Bad iactive" );    CYG_ASSERT( VIRT_TO_BUS( &p_eth_upd985xx->rx_bufdesc[ inext ] )                == (cyg_uint8 *)p_eth_upd985xx->rxring_next, "Next rx_bufdesc bad" );    CYG_ASSERT( VIRT_TO_BUS( &p_eth_upd985xx->rx_bufdesc[ iactive ] )                == (cyg_uint8 *)p_eth_upd985xx->rxring_active, "Active rx_bufdesc bad" );    CYG_ASSERT( ETH_BUF_D_L_LINK == p_eth_upd985xx->rxring_next->attr, "Next not a link" );    CYG_ASSERT( ETH_BUF_D_L_DATA & p_eth_upd985xx->rxring_active->attr, "Active not data" );    CYG_ASSERT( NULL == p_eth_upd985xx->rxring_next->ptr, "Next not NULL" );    CYG_ASSERT( VIRT_TO_BUS( &rx_databuf[iactive][0] ) ==                p_eth_upd985xx->rxring_active->ptr, "Active bad data pointer" );    CYG_ASSERT( (iactive - 1 == inext) || (0 == iactive && NUM_RXBUFS - 1 == inext),                "Chasing pointers mismatch" );    // Select the new bufdesc to be active - ie. next to scan for reception:    if ( ++iactive >= NUM_RXBUFS )        iactive = 0;    dead = p_eth_upd985xx->rxring_active; // the one that just died    // Step ahead the new active buffer:    p_eth_upd985xx->rxring_active = (volatile struct bufdesc *)        VIRT_TO_BUS( &p_eth_upd985xx->rx_bufdesc[ iactive ] );    p_eth_upd985xx->rxring_active_index = iactive;    // Blow away the currently active entry; we have dealt with it already    // and it is needed for an end stop to the ring:    dead->ptr = NULL;    dead->attr = 0;       // Select the next bufdesc to enliven    next = p_eth_upd985xx->rxring_next;    next->ptr = VIRT_TO_BUS( &rx_databuf[inext][0] );    next->attr = ( ETH_BUF_D_L_DATA | ETH_BUF_OWN_CPU                   | (ETH_BUF_SIZE & sizeof( rx_databuf[0] )) );    // And update the external info to reflect this:    if ( ++inext >= NUM_RXBUFS )        inext = 0;    next = (volatile struct bufdesc *)        VIRT_TO_BUS( &p_eth_upd985xx->rx_bufdesc[ inext ] );    p_eth_upd985xx->rxring_next = next;    p_eth_upd985xx->rxring_next_index = inext;    // Postconditions:    CYG_ASSERT( 0 <=   inext && inext   < NUM_RXBUFS, "Bad inext" );    CYG_ASSERT( 0 <= iactive && iactive < NUM_RXBUFS, "Bad iactive" );    CYG_ASSERT( VIRT_TO_BUS( &p_eth_upd985xx->rx_bufdesc[ inext ] )                == (cyg_uint8 *)p_eth_upd985xx->rxring_next, "Next rx_bufdesc bad" );    CYG_ASSERT( VIRT_TO_BUS( &p_eth_upd985xx->rx_bufdesc[ iactive ] )                == (cyg_uint8 *)p_eth_upd985xx->rxring_active, "Active rx_bufdesc bad" );    CYG_ASSERT( ETH_BUF_D_L_LINK == p_eth_upd985xx->rxring_next->attr, "Next not a link" );    CYG_ASSERT( ETH_BUF_D_L_DATA & p_eth_upd985xx->rxring_active->attr, "Active not data" );    CYG_ASSERT( NULL == p_eth_upd985xx->rxring_next->ptr, "Next not NULL" );    CYG_ASSERT( VIRT_TO_BUS( &rx_databuf[iactive][0] ) ==                p_eth_upd985xx->rxring_active->ptr, "Active bad data pointer" );    CYG_ASSERT( (iactive - 1 == inext) || (0 == iactive && NUM_RXBUFS - 1 == inext),                "Chasing pointers mismatch" );}// ------------------------------------------------------------------------////  Function : PacketRxReady        (Called from delivery thread)//// ------------------------------------------------------------------------STATIC void PacketRxReady(struct eth_upd985xx* p_eth_upd985xx){    struct cyg_netdevtab_entry *ndp;    struct eth_drv_sc *sc;    cyg_uint32 ss, length;    cyg_bool reset_required = 0;    ndp = (struct cyg_netdevtab_entry *)(p_eth_upd985xx->ndp);    sc = (struct eth_drv_sc *)(ndp->device_instance);    CHECK_NDP_SC_LINK();#ifdef DEBUG_TRAFFIC    ss = INL( ETH_RXSR );    os_printf("PacketRxReady: RXSR %x\n", ss );#endif    if ( ETH_ISR_RBDRU & p_eth_upd985xx->intrs )        reset_required = 1; // Out of buffers    if ( ! ETH_ISR_RCVDN & p_eth_upd985xx->intrs )        reset_required = 1; // or if no reception completed, reset anyway    // For all ready rx blocks...    do {        volatile struct bufdesc *bp;        bp = p_eth_upd985xx->rxring_active; // Current rx candidate        ss = bp->attr;#ifdef DEBUG_TRAFFIC        os_printf("PacketRxReady attr %x at %x\n", ss, bp );#endif        if ( ETH_BUF_OWN_CPU == (ETH_BUF_OWN & ss) ) {            // Then the packet is untouched...            break;        }#ifdef CYGOPT_DEVS_ETH_MIPS_UPD985XX_HARDWARE_BUGS_E1E2        // Perform address recognition by hand, hardware is in promisc mode        // (we have settable "software" promisc mode too of course)        if ( ETH_BUF_OK & ss ) {            cyg_uint8 *esa = (cyg_uint8 *)bp->ptr; // (this is a non-cachable address)            int ok = 0;            if ( p_eth_upd985xx->promisc )                ok = 1; // accept the packet            else            if ( p_eth_upd985xx->mac_address[0] == esa[0] &&                 p_eth_upd985xx->mac_address[1] == esa[1] &&                 p_eth_upd985xx->mac_address[2] == esa[2] &&                 p_eth_upd985xx->mac_address[3] == esa[3] &&                 p_eth_upd985xx->mac_address[4] == esa[4] &&                 p_eth_upd985xx->mac_address[5] == esa[5] )                ok = 1; // Then they are equal - accept            else            if ( 0xff == esa[0] &&                 0xff == esa[1] &&                 0xff == esa[2] &&                 0xff == esa[3] &&                 0xff == esa[4] &&                 0xff == esa[5] )                ok = 1; // Then they are equal - accept            if ( !ok )                ss = 0; // Easiest way...        }#endif        if ( ETH_BUF_OK & ss ) {            length = ETH_BUF_SIZE & ss;#ifdef DEBUG_TRAFFIC            os_printf("PacketRxReady found a packet size %d attr %x\n", length, ss );#endif            // Asserts for the length in-range can fire, with good status            // in the block, so be defensive here instead.  Belt and braces.            if ( 63 < length && length <= MAX_RX_PACKET_SIZE ) {                CYG_ASSERT( ETH_BUF_D_L_DATA == (ETH_BUF_D_L & ss), "Not data buffer" );                CYG_ASSERT( length > 63, "Tiny packet" );                CYG_ASSERT( length <= MAX_RX_PACKET_SIZE, "Too big packet" );                CYG_ASSERT( ETH_BUF_LAST & ss, "Not last buffer" );                (sc->funs->eth_drv->recv)( sc, length );            } // Else drop it on the floor.        }        // Step along to the next buffer descriptor...        NextRxRing( p_eth_upd985xx );        if ( ! reset_required ) {            // And tell the device it can have a biscuit:            OUTL( ETH_RXPDR, ETH_RXPDR_AL | 1 );            // Now, before moving on to the next packet, find out if receptions            // had caught up with us before adding that new buffer:            ss = INL( ETH_RXPDR );            ss &= ETH_RXPDR_RNOD;            ss >>= ETH_RXPDR_RNOD_SHIFT;            if ( 1 >= ss ) {                // Then it was zero before.  So the rx engine is stopped.#ifdef DEBUG_TRAFFIC                os_printf( "***ZERO rx buffers were left\n" );#endif                reset_required = 1;            }            // Otherwise we carry on as usual.        }    } while ( 1 );    if ( reset_required ) {        p_eth_upd985xx->count_rx_resource++;        // Disable the wet string end of the receiver        ss = INL( ETH_MACC1 );        ss &=~ETH_MACC1_SRXEN;        OUTL( ETH_MACC1, ss );        // Disable the DMA engine        OUTL( ETH_RXCR, 0 );        // Reset the RxRing from scratch        InitRxRing( p_eth_upd985xx );        // Point the hardware at the list of buffers        OUTL( ETH_RXDPR, (cyg_uint32)p_eth_upd985xx->rxring_active );        // Tell it about the buffers via the rx descriptor count:        ss = INL( ETH_RXPDR );        ss &= ETH_RXPDR_RNOD;        ss >>= ETH_RXPDR_RNOD_SHIFT;        // This awful register *increments* by what you write, even if the        // machinery is halted.  Vile filthy evil rubbish.        OUTL( ETH_RXPDR, ETH_RXPDR_AL | ((NUM_RXBUFS-1) - ss)  );        ss = INL( ETH_RXPDR );        CYG_ASSERT( (ETH_RXPDR_AL | (NUM_RXBUFS-1)) == ss, "RXPDR not right" );        // Start the rx.        OUTL( ETH_RXCR, ETH_RXCR_RXE | ETH_RXCR_DRBS_16 );        // Enable the wet string end of the receiver        ss = INL( ETH_MACC1 );        ss |= ETH_MACC1_SRXEN;        OUTL( ETH_MACC1, ss );        // All done.#ifdef DEBUG_TRAFFIC        os_printf( "***Rx Machine restarted\n" );#endif    }}// and the callback functionSTATIC voideth_upd985xx_recv( struct eth_drv_sc *sc,                   struct eth_drv_sg *sg_list, int sg_len ){    struct eth_upd985xx *p_eth_upd985xx;    int total_len;    struct eth_drv_sg *last_sg;    cyg_uint8 *from_p;    volatile struct bufdesc *bp;    p_eth_upd985xx = (struct eth_upd985xx *)sc->driver_private;        // Guard possible external entry points    if ( ! p_eth_upd985xx->active )        return;    bp = p_eth_upd985xx->rxring_active; // Current rx candidate#ifdef DEBUG_TRAFFIC    os_printf("Rx status %x\n", bp->attr );#endif    if ( 0 == (ETH_BUF_OK & bp->attr) )        return;            total_len = ETH_BUF_SIZE & bp->attr;    #ifdef DEBUG_TRAFFIC    os_printf("Rx %d %x (status %x): %d sg's, %d bytes\n",              p_eth_upd985xx->index, (int)p_eth_upd985xx,              bp->attr,              sg_len, total_len);#endif    // Copy the data to the network stack    from_p = bp->ptr; // (this is a non-cachable address)    // 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    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, 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( bp->ptr < from_p, "from_p wild in rx" );    CYG_ASSERT( bp->ptr + MAX_RX_PACKET_SIZE >= from_p,                "from_p overflow in rx" );}    // ------------------------------------------------------------------------////  Function : InitTxRing//// ------------------------------------------------------------------------STATIC void InitTxRing(struct eth_upd985xx* p_eth_upd985xx){    int i;    volatile struct bufdesc *bp;        p_eth_upd985xx->txring =        (struct bufdesc *)VIRT_TO_BUS( &p_eth_upd985xx->tx_bufdesc[0] );    bp = p_eth_upd985xx->txring;    for ( i = 0; i < NUM_ELEMENTS( p_eth_upd985xx->tx_bufdesc ); i++, bp++ ) {        bp->ptr = NULL;        bp->attr = 0;    }    // Last one is a NULL link    bp--;    bp->ptr = NULL;    bp->attr = ETH_BUF_D_L_LINK;    ResetTxRing(p_eth_upd985xx);}// ------------------------------------------------------------------------////  Function : ResetTxRing//// ------------------------------------------------------------------------STATIC void ResetTxRing(struct eth_upd985xx* p_eth_upd985xx){    int i;    volatile struct bufdesc *bp;    bp = p_eth_upd985xx->txring;    for ( i = 0; i < NUM_ELEMENTS( p_eth_upd985xx->tx_bufdesc ) - 1; i++, bp++ ) {

⌨️ 快捷键说明

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