📄 if_mahwah.c
字号:
struct eth_drv_sc *sc; cyg_uint32 ioaddr; cyg_uint16 status; ndp = (struct cyg_netdevtab_entry *)(p_i82559->ndp); sc = (struct eth_drv_sc *)(ndp->device_instance); CHECK_NDP_SC_LINK(); ioaddr = p_i82559->io_address; next_descriptor = p_i82559->next_rx_descriptor; p_rfd = p_i82559->rx_ring[next_descriptor]; CYG_ASSERT( (cyg_uint8 *)p_rfd >= i82559_heap_base, "rfd under" ); CYG_ASSERT( (cyg_uint8 *)p_rfd < i82559_heap_free, "rfd over" ); while ( p_rfd->rxstatus & RFD_STATUS_C ) { p_rfd->rxstatus_hi |= RFD_STATUS_HI_EL; length = p_rfd->count;#ifdef DEBUG_82559 os_printf( "Device %d (eth%d), rx descriptor %d:\n", p_i82559->index, p_i82559->index, next_descriptor );// dump_rfd( p_rfd, 1 );#endif p_i82559->next_rx_descriptor = next_descriptor; // Check for bogusly short packets; can happen in promisc mode: // Asserted against and checked by upper layer driver.#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 ); p_rfd->count = 0; p_rfd->f = 0; p_rfd->eof = 0; p_rfd->rxstatus_lo = 0; // The just-emptied slot is now ready for re-use and already marked EL; // we can now remove the EL marker from the previous one. if ( 0 == next_descriptor ) p_rfd = p_i82559->rx_ring[ MAX_RX_DESCRIPTORS-1 ]; else p_rfd = p_i82559->rx_ring[ next_descriptor-1 ]; // The previous one: check it *was* marked before clearing. CYG_ASSERT( p_rfd->rxstatus_hi & RFD_STATUS_HI_EL, "No prev EL" ); p_rfd->rxstatus_hi = 0; // that word is not written by the device.#ifdef KEEP_STATISTICS statistics[p_i82559->index].rx_deliver++;#endif if (++next_descriptor >= MAX_RX_DESCRIPTORS) next_descriptor = 0; p_rfd = p_i82559->rx_ring[next_descriptor]; CYG_ASSERT( (cyg_uint8 *)p_rfd >= i82559_heap_base, "rfd under" ); CYG_ASSERT( (cyg_uint8 *)p_rfd < i82559_heap_free, "rfd over" ); } // See if the RU has gone idle (usually because of out of resource // condition) and restart it if needs be. ints = Mask82559Interrupt(p_i82559); status = INW(ioaddr + SCBStatus); if ( RU_STATUS_READY != (status & RU_STATUS_MASK) ) { // Acknowledge the RX INT sources OUTW( SCB_INTACK_RX, ioaddr + SCBStatus); // (see pages 6-10 & 6-90)#ifdef KEEP_STATISTICS statistics[p_i82559->index].rx_restart++;#endif // There's an end-of-list marker out there somewhere... // So mop it up; it takes a little time but this is infrequent. ResetRxRing( p_i82559 ); next_descriptor = 0; // re-initialize next desc. // wait for SCB command complete wait_for_cmd_done(ioaddr); // load pointer to Rx Ring OUTL(VIRT_TO_BUS(p_i82559->rx_ring[0]), ioaddr + SCBPointer); OUTW(RUC_START, ioaddr + SCBCmd); Acknowledge82559Interrupt(p_i82559); } UnMask82559Interrupt(p_i82559, ints); p_i82559->next_rx_descriptor = next_descriptor;}// and the callback functionstatic void i82559_recv( struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len ){ struct i82559 *p_i82559; RFD *p_rfd; int next_descriptor; int total_len; struct eth_drv_sg *last_sg; volatile cyg_uint8 *from_p; p_i82559 = (struct i82559 *)sc->driver_private; IF_BAD_82559( p_i82559 ) {#ifdef DEBUG os_printf( "i82559_recv: Bad device pointer %x\n", p_i82559 );#endif return; } next_descriptor = p_i82559->next_rx_descriptor; p_rfd = p_i82559->rx_ring[next_descriptor]; CYG_ASSERT( (cyg_uint8 *)p_rfd >= i82559_heap_base, "rfd under" ); CYG_ASSERT( (cyg_uint8 *)p_rfd < i82559_heap_free, "rfd over" ); CYG_ASSERT( p_rfd->rxstatus & RFD_STATUS_C, "No complete frame" ); CYG_ASSERT( p_rfd->rxstatus & RFD_STATUS_EL, "No marked frame" ); CYG_ASSERT( p_rfd->rxstatus_lo & RFD_STATUS_LO_C, "No complete frame 2" ); CYG_ASSERT( p_rfd->rxstatus_hi & RFD_STATUS_HI_EL, "No marked frame 2" ); if ( 0 == (p_rfd->rxstatus & RFD_STATUS_C) ) return; total_len = p_rfd->count; #ifdef DEBUG_82559 os_printf("Rx %d %x (status %x): %d sg's, %d bytes\n", p_i82559->index, (int)p_i82559, p_rfd->rxstatus, sg_len, total_len);#endif // Copy the data to the network stack from_p = &p_rfd->buffer[0]; // 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, (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( &p_rfd->buffer[0] < from_p, "from_p wild in rx" ); CYG_ASSERT( &p_rfd->buffer[0] + MAX_RX_PACKET_SIZE >= from_p, "from_p overflow in rx" );} // ------------------------------------------------------------------------//// Function : InitTxRing//// ------------------------------------------------------------------------static void InitTxRing(struct i82559* p_i82559){ int i; cyg_uint32 ioaddr;#ifdef DEBUG_82559 os_printf("InitTxRing %d\n", p_i82559->index);#endif ioaddr = p_i82559->io_address; for ( i = 0; i < MAX_TX_DESCRIPTORS; i++) { p_i82559->tx_ring[i] = (TxCB *)pciwindow_mem_alloc( sizeof(TxCB) + MAX_TX_PACKET_SIZE); } ResetTxRing(p_i82559);}// ------------------------------------------------------------------------//// Function : ResetTxRing//// ------------------------------------------------------------------------static void ResetTxRing(struct i82559* p_i82559){ int i; cyg_uint32 ioaddr;#ifdef DEBUG_82559 os_printf("ResetTxRing %d\n", p_i82559->index);#endif ioaddr = p_i82559->io_address; p_i82559->tx_descriptor_add = p_i82559->tx_descriptor_active = p_i82559->tx_descriptor_remove = 0; p_i82559->tx_in_progress = p_i82559->tx_queue_full = 0; for ( i = 0; i < MAX_TX_DESCRIPTORS; i++) { TxCB *p_txcb = p_i82559->tx_ring[i]; CYG_ASSERT( (cyg_uint8 *)p_txcb >= i82559_heap_base, "txcb under" ); CYG_ASSERT( (cyg_uint8 *)p_txcb < i82559_heap_free, "txcb over" ); p_txcb->txstatus = 0; p_txcb->command = 0; p_txcb->link = VIRT_TO_BUS((cyg_uint32)p_txcb); p_txcb->tbd_address = 0xFFFFFFFF; p_txcb->tbd_number = 0; p_txcb->tx_threshold = 16; p_txcb->eof = 1; p_txcb->count = 0; p_i82559->tx_keys[i] = 0; } wait_for_cmd_done(ioaddr); OUTL(0, ioaddr + SCBPointer); OUTW(SCB_M | CU_ADDR_LOAD, ioaddr + SCBCmd);}// ------------------------------------------------------------------------//// Function : TxMachine (Called from FG & ISR)//// This steps the Tx Machine onto the next record if necessary - allowing// for missed interrupts, and so on.// ------------------------------------------------------------------------static void TxMachine(struct i82559* p_i82559){ int tx_descriptor_active; cyg_uint32 ioaddr; tx_descriptor_active = p_i82559->tx_descriptor_active; ioaddr = p_i82559->io_address; // See if the CU is idle when we think it isn't; this is the only place // tx_descriptor_active is advanced. (Also recovers from a dropped intr) if ( p_i82559->tx_in_progress ) { cyg_uint16 status; status = INW(ioaddr + SCBStatus); if ( 0 == (status & CU_STATUS_MASK) ) { // It is idle. So ack the TX interrupts OUTW( SCB_INTACK_TX, ioaddr + SCBStatus); // (see pages 6-10 & 6-90) // and step on to the next queued tx. p_i82559->tx_in_progress = 0; if ( ++tx_descriptor_active >= MAX_TX_DESCRIPTORS ) tx_descriptor_active = 0; p_i82559->tx_descriptor_active = tx_descriptor_active; } } // is the CU idle, and there a next tx to set going? if ( ( ! p_i82559->tx_in_progress ) && p_i82559->tx_descriptor_add != tx_descriptor_active ) { TxCB *p_txcb; p_txcb = p_i82559->tx_ring[tx_descriptor_active]; CYG_ASSERT( (cyg_uint8 *)p_txcb >= i82559_heap_base, "txcb under" ); CYG_ASSERT( (cyg_uint8 *)p_txcb < i82559_heap_free, "txcb over" );#ifdef DEBUG_82559 os_printf("Tx %d %x: Starting Engines, KEY %x\n", p_i82559->index, (int)p_i82559, key );#endif // make sure no command operating wait_for_cmd_done(ioaddr); // start Tx operation OUTL(VIRT_TO_BUS(p_txcb), ioaddr + SCBPointer); OUTW(CU_START, ioaddr + SCBCmd); p_i82559->tx_in_progress = 1; }}// ------------------------------------------------------------------------//// 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 i82559* p_i82559){ struct cyg_netdevtab_entry *ndp; struct eth_drv_sc *sc; int tx_descriptor_remove = p_i82559->tx_descriptor_remove; ndp = (struct cyg_netdevtab_entry *)(p_i82559->ndp); sc = (struct eth_drv_sc *)(ndp->device_instance); CHECK_NDP_SC_LINK(); // "Done" txen are from here to active, OR // the remove one if the queue is full AND its status is nonzero: while ( (tx_descriptor_remove != p_i82559->tx_descriptor_active) || ( p_i82559->tx_queue_full && (0 != p_i82559->tx_ring[ tx_descriptor_remove ]->txstatus) ) ) { unsigned long key = p_i82559->tx_keys[ tx_descriptor_remove ];#ifdef DEBUG_82559 os_printf("TxDone %d %x: KEY %x\n", p_i82559->index, (int)p_i82559, key );#endif (sc->funs->eth_drv->tx_done)( sc, key, 1 /* status */ ); if ( ++tx_descriptor_remove >= MAX_TX_DESCRIPTORS ) tx_descriptor_remove = 0; p_i82559->tx_descriptor_remove = tx_descriptor_remove; p_i82559->tx_queue_full = 0; }}// ------------------------------------------------------------------------//// Function : i82559_can_send//// ------------------------------------------------------------------------static int i82559_can_send(struct eth_drv_sc *sc){ struct i82559 *p_i82559; int ints; p_i82559 = (struct i82559 *)sc->driver_private; IF_BAD_82559( p_i82559 ) {#ifdef DEBUG os_printf( "i82559_send: Bad device pointer %x\n", p_i82559 );#endif return 0; } // Advance TxMachine atomically ints = Mask82559Interrupt(p_i82559); TxMachine(p_i82559); Acknowledge82559Interrupt(p_i82559); // This can eat an Rx interrupt, so PacketRxReady(p_i82559); UnMask82559Interrupt(p_i82559,ints); return ! p_i82559->tx_queue_full;}// ------------------------------------------------------------------------//// Function : i82559_send//// ------------------------------------------------------------------------static void i82559_send(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len, int total_len, unsigned long key){ struct i82559 *p_i82559; int tx_descriptor_add, ints; TxCB *p_txcb; cyg_uint32 ioaddr; p_i82559 = (struct i82559 *)sc->driver_private; IF_BAD_82559( p_i82559 ) {#ifdef DEBUG os_printf( "i82559_send: Bad device pointer %x\n", p_i82559 );#endif return; }#ifdef DEBUG_82559 os_printf("Tx %d %x: %d sg's, %d bytes, KEY %x\n", p_i82559->index, (int)p_i82559, sg_len, total_len, key );#endif if ( ! p_i82559->active ) return; // device inactive, no return#ifdef KEEP_STATISTICS statistics[p_i82559->index].tx_count++;#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -