if_upd985xx.c

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

C
1,622
字号
        bp->attr =            ETH_BUF_LAST |            ETH_BUF_D_L_DATA |            ETH_BUF_OWN_CPU |            (ETH_BUF_SIZE & 0);    }}// ------------------------------------------------------------------------////  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 eth_upd985xx* p_eth_upd985xx){    struct cyg_netdevtab_entry *ndp;    struct eth_drv_sc *sc;    ndp = (struct cyg_netdevtab_entry *)(p_eth_upd985xx->ndp);    sc = (struct eth_drv_sc *)(ndp->device_instance);    CHECK_NDP_SC_LINK();    if ( p_eth_upd985xx->tx_busy ) {        cyg_uint32 ss;        ss = INL( ETH_TXSR ); // Get tx status        if ( ss & (ETH_TXSR_CSE |                   ETH_TXSR_TUDR |                   ETH_TXSR_TGNT |                   ETH_TXSR_LCOL |                   ETH_TXSR_ECOL |                   ETH_TXSR_TEDFR |                   ETH_TXSR_TDFR |                   ETH_TXSR_TBRO |                   ETH_TXSR_TMUL |                   ETH_TXSR_TDONE ) ) {            // Then it finished; somehow...            cyg_uint32 key = p_eth_upd985xx->tx_keys[ 0 ];                        // Turn off the transmitter (before the callback to the stack).            OUTL( ETH_TXCR, 0 );#ifdef CYGOPT_DEVS_ETH_MIPS_UPD985XX_HARDWARE_BUGS_E8            // Must take action after certain types of tx failure:            if ( ss & (ETH_TXSR_TUDR |                       ETH_TXSR_LCOL |                       ETH_TXSR_ECOL) ) {                p_eth_upd985xx->count_bad_tx_completion++;                CYG_ASSERT ( p_eth_upd985xx->active, "Device not active!" );                eth_upd985xx_stop( sc );                eth_upd985xx_start( sc, NULL, 0 );                key = 0; // Important!  Stop above already fed it back.            }#endif#ifdef DEBUG_TRAFFIC            os_printf("TxDone %d %x: KEY %x\n",                      p_eth_upd985xx->index, (int)p_eth_upd985xx, key );#endif            // Finished, ready for the next one            p_eth_upd985xx->tx_keys[ 0 ] = 0;            p_eth_upd985xx->tx_busy = 0;            // Then tell the stack we are done:            if (key) {                (sc->funs->eth_drv->tx_done)( sc, key,                       0 == (p_eth_upd985xx->intrs & ETH_ISR_TABR) );            }        }    }}// ------------------------------------------------------------------------////  Function : eth_upd985xx_can_send//// ------------------------------------------------------------------------STATIC int eth_upd985xx_can_send(struct eth_drv_sc *sc){    struct eth_upd985xx *p_eth_upd985xx;    p_eth_upd985xx = (struct eth_upd985xx *)sc->driver_private;    // Guard possible external entry points    if ( ! p_eth_upd985xx->active )        return 0;    return ! p_eth_upd985xx->tx_busy;}// ------------------------------------------------------------------------////  Function : eth_upd985xx_send//// ------------------------------------------------------------------------STATIC void eth_upd985xx_send(struct eth_drv_sc *sc,            struct eth_drv_sg *sg_list, int sg_len, int total_len,            unsigned long key){    struct eth_upd985xx *p_eth_upd985xx;    struct eth_drv_sg *last_sg;    volatile struct bufdesc *bp;#ifdef CYGOPT_DEVS_ETH_MIPS_UPD985XX_HARDWARE_BUGS_E3    struct eth_drv_sg local_sg[2];#endif    p_eth_upd985xx = (struct eth_upd985xx *)sc->driver_private;#ifdef DEBUG_TRAFFIC    os_printf("Tx %d %x: %d sg's, %d bytes, KEY %x\n",              p_eth_upd985xx->index, (int)p_eth_upd985xx, sg_len, total_len, key );#endif    if ( ! p_eth_upd985xx->active )        return;                         // device inactive, no return        CYG_ASSERT( ! p_eth_upd985xx->tx_busy, "Can't send when busy!" );    p_eth_upd985xx->tx_busy++;    p_eth_upd985xx->tx_keys[0] = key;    bp = &p_eth_upd985xx->txring[0]; // Current free tx    CYG_ASSERT( 0 < sg_len, "sg_len underflow" );    CYG_ASSERT( MAX_ETH_DRV_SG >= sg_len, "sg_len overflow" );#ifdef CYGOPT_DEVS_ETH_MIPS_UPD985XX_HARDWARE_BUGS_E3    // We must copy any Tx that is more than two SGs into just one buffer.    if ( sg_len > 2 ) {        cyg_uint8 *from_p, *to_p;        to_p = &tx_databuf[0]; // normal cached address        if ( sizeof( tx_databuf ) < total_len )            total_len = sizeof( tx_databuf );        for ( last_sg = &sg_list[sg_len]; sg_list < last_sg; sg_list++ ) {            int l;            from_p = (cyg_uint8 *)(sg_list->buf); // normal cached address            l = sg_list->len;                       if ( l > total_len )                l = total_len;            memcpy( to_p, from_p, l ); // All in cached memory            to_p += l;            total_len -= l;            if ( 0 > total_len )                 break; // Should exit via sg_last normally        }        // Set up SGs describing the single tx buffer        total_len = to_p - &tx_databuf[0];        local_sg[0].buf = (CYG_ADDRESS)&tx_databuf[0];        local_sg[0].len = (CYG_ADDRWORD)total_len;        local_sg[1].buf = (CYG_ADDRESS)0;        local_sg[1].len = (CYG_ADDRWORD)0;        // And make the subsequent code use it.        sg_len = 1;        sg_list = &local_sg[0];    }#endif    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 4120)        HAL_DCACHE_STORE( ((CYG_ADDRESS)from_p) &~(HAL_DCACHE_LINE_SIZE-1),                          l + HAL_DCACHE_LINE_SIZE );                bp->ptr = VIRT_TO_BUS( from_p ); // uncached real RAM address        bp->attr &=~(ETH_BUF_LAST | ETH_BUF_SIZE);        bp->attr |= ETH_BUF_SIZE & l;        bp->attr |= ETH_BUF_D_L_DATA;        total_len -= l;        bp++;        if ( 0 > total_len )             break; // Should exit via sg_last normally    }    CYG_ASSERT( bp > &p_eth_upd985xx->txring[0], "bp underflow" );    CYG_ASSERT( bp < &p_eth_upd985xx->txring[        NUM_ELEMENTS(p_eth_upd985xx->tx_bufdesc)        ], "bp underflow" );    bp--;    bp->attr |= ETH_BUF_LAST;    // Make the rest be null links    for ( bp++; bp <              &p_eth_upd985xx->txring[NUM_ELEMENTS(p_eth_upd985xx->tx_bufdesc)];          bp++ ) {        bp->attr = ETH_BUF_D_L_LINK;        bp->ptr = NULL;    }    CYG_ASSERT( 0 == total_len, "length mismatch in tx" );    CYG_ASSERT( last_sg == sg_list, "sg count mismatch in tx" );    // And start off the tx system    // Point the hardware at the list of buffers    OUTL( ETH_TXDPR, (cyg_uint32)p_eth_upd985xx->txring );    // and start the tx.    // Fault E4 - use only 8 for DTBS, not the previously recommended 16.    // Tag: CYGOPT_DEVS_ETH_MIPS_UPD985XX_HARDWARE_BUGS_E4    // but no config opt is provided.    // Fault E7: ETH_TXCR_AFCE must not be used.    // Tag: CYGOPT_DEVS_ETH_MIPS_UPD985XX_HARDWARE_BUGS_E7    // but no config opt is provided.    OUTL( ETH_TXCR, ETH_TXCR_TXE | ETH_TXCR_DTBS_8 /* | ETH_TXCR_AFCE */ );}#ifdef CYGPKG_NET// ------------------------------------------------------------------------////  Function : eth_upd985xx_configure////  Return : 0 = It worked.//           non0 = It failed.// ------------------------------------------------------------------------STATIC inteth_upd985xx_configure(struct eth_upd985xx* p_eth_upd985xx, int promisc, int oversized){    int ss;    // We implement permission of oversize packets by changing LMAX (rather    // than enabling HUGEN in ETH_MACC1) because we rely on only one    // reception per rx descriptor.  General oversize packets could eat    // many rx descriptors and we would become ...confused.    // Sanity check the numbers we're about to use.    CYG_ASSERT( sizeof( rx_databuf[0] ) >= MAX_OVERSIZE_PACKET_SIZE,                "Oversize packet would overflow rx buffer" );    CYG_ASSERT( sizeof( rx_databuf[0] ) >= MAX_ETHERNET_PACKET_SIZE,                "Ethernet packet would overflow rx buffer" );    if ( oversized )        OUTL( ETH_LMAX, MAX_OVERSIZE_PACKET_SIZE );    else        OUTL( ETH_LMAX, MAX_ETHERNET_PACKET_SIZE );#ifdef CYGOPT_DEVS_ETH_MIPS_UPD985XX_HARDWARE_BUGS_E1E2    ss = promisc ? 1 : 0; // avoid unused var warning    p_eth_upd985xx->promisc = ss;#ifdef CYGOPT_DEVS_ETH_MIPS_UPD985XX_HARDWARE_BUGS_E1E2_E2ONLY    // Then we must also set the mode in the chip    ss = INL( ETH_AFR );    if ( promisc )        ss |= ETH_AFR_PRO;    else        ss &=~ETH_AFR_PRO;    OUTL( ETH_AFR, ss );#endif // CYGOPT_DEVS_ETH_MIPS_UPD985XX_HARDWARE_BUGS_E1E2_E2ONLY#else    ss = INL( ETH_AFR );    if ( promisc )        ss |= ETH_AFR_PRO;    else        ss &=~ETH_AFR_PRO;    OUTL( ETH_AFR, ss );#endif    return 0; // OK}#endif// ------------------------------------------------------------------------////  Function : eth_upd985xx_ioctl//// ------------------------------------------------------------------------STATIC int eth_upd985xx_ioctl(struct eth_drv_sc *sc, unsigned long key,                   void *data, int data_length){    struct eth_upd985xx *p_eth_upd985xx;    p_eth_upd985xx = (struct eth_upd985xx *)sc->driver_private;#ifdef DEBUG_IOCTL    db_printf( "eth_upd985xx_ioctl: device eth%d at %x; key is 0x%x, data at %x[%d]\n",               p_eth_upd985xx->index, p_eth_upd985xx, key, data, data_length );#endif    // DO NOT guard possible external entry points - want to be able eg. to    // set a mac address of a down interface before bringing it up!    switch ( key ) {#ifdef ETH_DRV_SET_MAC_ADDRESS    case ETH_DRV_SET_MAC_ADDRESS:        if ( 6 != data_length )            return -2;        return eth_set_mac_address( p_eth_upd985xx, data );#endif#ifdef ETH_DRV_GET_IF_STATS_UD    case ETH_DRV_GET_IF_STATS_UD: // UD == UPDATE#endif        // drop through#ifdef ETH_DRV_GET_IF_STATS    case ETH_DRV_GET_IF_STATS:#endif#if defined(ETH_DRV_GET_IF_STATS) || defined (ETH_DRV_GET_IF_STATS_UD)    {        struct ether_drv_stats *p = (struct ether_drv_stats *)data;        int i;        // Chipset entry is no longer supported; RFC1573.        for ( i = 0; i < SNMP_CHIPSET_LEN; i++ )            p->snmp_chipset[i] = 0;        // This perhaps should be a config opt, so you can make up your own        // description, or supply it from the instantiation.        strcpy( p->description, "NEC uPD985xx on-chip ethernet (CANDY)" );        // CYG_ASSERT( 48 > strlen(p->description), "Description too long" );        i = eth_upd985xx_status( p_eth_upd985xx );        if ( !( i & PHY_STATUS_LINK) ) {            p->operational = 2;         // LINK DOWN            p->duplex = 1;              // UNKNOWN            p->speed = 0;        }        else {            p->operational = 3;            // LINK UP            p->duplex = (i & PHY_STATUS_FDX) ? 3 : 2; // 2 = SIMPLEX, 3 = DUPLEX            p->speed = ((i & PHY_STATUS_100MBPS) ? 100 : 10) * 1000000;        }        // Admit to it...        p->supports_dot3        = true;        // Those commented out are not available on this chip.        p->tx_good              = INL( ETH_TPCT   )   ;        p->tx_max_collisions    = INL( ETH_TXCL   )   ;        p->tx_late_collisions   = INL( ETH_TLCL   )   ;        //p->tx_underrun          = INL(    )   ;        p->tx_carrier_loss      = INL( ETH_TCSE   )   ;        p->tx_deferred          = INL( ETH_TDFR   ) +                                  INL( ETH_TXDF   )    ;        //p->tx_sqetesterrors     = INL(    )   ;        p->tx_single_collisions = INL( ETH_TSCL   )   ;        p->tx_mult_collisions   = INL( ETH_TMCL   )   ;        p->tx_total_collisions  = INL( ETH_TSCL   ) +                                  INL( ETH_TMCL   ) +                                  INL( ETH_TLCL   ) +                                  INL( ETH_TXCL   )   ;        p->rx_good              = INL( ETH_RPKT   )   ;        p->rx_crc_errors        = INL( ETH_RFCS   )   ;        p->rx_align_errors      = INL( ETH_RALN   )   ;        p->rx_resource_errors   = p_eth_upd985xx->count_rx_resource;        //p->rx_overrun_errors    = INL(    )   ;        //p->rx_collisions        = INL(    )   ;        p->rx_short_frames      = INL( ETH_RUND   )   ;        p->rx_too_long_frames   = INL( ETH_ROVR   )   ;        p->rx_symbol_errors     = INL( ETH_RXUO   )   ;        p->interrupts           = p_eth_upd985xx->count_interrupts;        p->rx_count             = INL( ETH_RBYT   )   ;        p->rx_deliver           = INL( ETH_RPKT   )   ;        p->rx_resource          = p_eth_upd985xx->count_rx_resource;        p->rx_restart           = p_eth_upd985xx->count_rx_resource +                                  p_eth_upd985xx->count_rx_restart;        p->tx_count             = INL( ETH_TBYT   )   ;        p->tx_complete          = INL( ETH_TPCT   )   ;        p->tx_dropped           = INL( ETH_TNCL   )   ;                p->tx_queue_len = 1;                return 0; // OK    }#endif    default:        break;    }    return -1;}// ------------------------------------------------------------------------// EOF if_upd985xx.c

⌨️ 快捷键说明

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