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 + -
显示快捷键?