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