FreeBSD/sys/dev/e1000/if_em.c
/**********************************************************************
 *
 *  Examine each tx_buffer in the used queue. If the hardware is done
 *  processing the packet then free associated resources. The
 *  tx_buffer is put back on the free queue.
 *
 **********************************************************************/
Examine each tx_buffer in the used queue. If the hardware is done
processing the packet then free associated resources. The
tx_buffer is put back on the free queue.
Examine each tx_buffer in the used queue . If the hardware is done processing the packet then free associated resources . The tx_buffer is put back on the free queue .
static void
em_txeof(struct tx_ring *txr)
{
	struct adapter	*adapter = txr->adapter;
        int first, last, done, processed;
        struct em_txbuffer *tx_buffer;
        struct e1000_tx_desc   *tx_desc, *eop_desc;
	if_t ifp = adapter->ifp;
	EM_TX_LOCK_ASSERT(txr);
#ifdef DEV_NETMAP
	if (netmap_tx_irq(ifp, txr->me))
		return;
#endif 
        if (txr->tx_avail == adapter->num_tx_desc) {
		txr->busy = EM_TX_IDLE;
                return;
	}
	processed = 0;
        first = txr->next_to_clean;
        tx_desc = &txr->tx_base[first];
        tx_buffer = &txr->tx_buffers[first];
	last = tx_buffer->next_eop;
        eop_desc = &txr->tx_base[last];
	if (++last == adapter->num_tx_desc)
 		last = 0;
	done = last;
        bus_dmamap_sync(txr->txdma.dma_tag, txr->txdma.dma_map,
            BUS_DMASYNC_POSTREAD);
        while (eop_desc->upper.fields.status & E1000_TXD_STAT_DD) {
		while (first != done) {
                	tx_desc->upper.data = 0;
                	tx_desc->lower.data = 0;
                	tx_desc->buffer_addr = 0;
                	++txr->tx_avail;
			++processed;
			if (tx_buffer->m_head) {
				bus_dmamap_sync(txr->txtag,
				    tx_buffer->map,
				    BUS_DMASYNC_POSTWRITE);
				bus_dmamap_unload(txr->txtag,
				    tx_buffer->map);
                        	m_freem(tx_buffer->m_head);
                        	tx_buffer->m_head = NULL;
                	}
			tx_buffer->next_eop = -1;
	                if (++first == adapter->num_tx_desc)
				first = 0;
	                tx_buffer = &txr->tx_buffers[first];
			tx_desc = &txr->tx_base[first];
		}
		if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
		last = tx_buffer->next_eop;
		if (last != -1) {
        		eop_desc = &txr->tx_base[last];
			if (++last == adapter->num_tx_desc) last = 0;
			done = last;
		} else
			break;
        }
        bus_dmamap_sync(txr->txdma.dma_tag, txr->txdma.dma_map,
            BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
        txr->next_to_clean = first;
	if (processed == 0) {
		if (txr->busy != EM_TX_HUNG)
			++txr->busy;
	} else 
		txr->busy = EM_TX_BUSY; 
        if (txr->tx_avail >= EM_MAX_SCATTER) {
		if_setdrvflagbits(ifp, 0, IFF_DRV_OACTIVE);
	}
	if (txr->tx_avail == adapter->num_tx_desc)
		txr->busy = EM_TX_IDLE;
}
static void em_txeof ( struct tx_ring * txr ) { struct adapter * adapter = txr -> adapter ; int first , last , done , processed ; struct em_txbuffer * tx_buffer ; struct e1000_tx_desc * tx_desc , * eop_desc ; if_t ifp = adapter -> ifp ; EM_TX_LOCK_ASSERT ( txr ) ; #ifdef DEV_NETMAP if ( netmap_tx_irq ( ifp , txr -> me ) ) return ; #endif if ( txr -> tx_avail == adapter -> num_tx_desc ) { txr -> busy = EM_TX_IDLE ; return ; } processed = 0 ; first = txr -> next_to_clean ; tx_desc = & txr -> tx_base [ first ] ; tx_buffer = & txr -> tx_buffers [ first ] ; last = tx_buffer -> next_eop ; eop_desc = & txr -> tx_base [ last ] ; if ( ++ last == adapter -> num_tx_desc ) last = 0 ; done = last ; bus_dmamap_sync ( txr -> txdma . dma_tag , txr -> txdma . dma_map , BUS_DMASYNC_POSTREAD ) ; while ( eop_desc -> upper . fields . status & E1000_TXD_STAT_DD ) { while ( first != done ) { tx_desc -> upper . data = 0 ; tx_desc -> lower . data = 0 ; tx_desc -> buffer_addr = 0 ; ++ txr -> tx_avail ; ++ processed ; if ( tx_buffer -> m_head ) { bus_dmamap_sync ( txr -> txtag , tx_buffer -> map , BUS_DMASYNC_POSTWRITE ) ; bus_dmamap_unload ( txr -> txtag , tx_buffer -> map ) ; m_freem ( tx_buffer -> m_head ) ; tx_buffer -> m_head = NULL ; } tx_buffer -> next_eop = -1 ; if ( ++ first == adapter -> num_tx_desc ) first = 0 ; tx_buffer = & txr -> tx_buffers [ first ] ; tx_desc = & txr -> tx_base [ first ] ; } if_inc_counter ( ifp , IFCOUNTER_OPACKETS , 1 ) ; last = tx_buffer -> next_eop ; if ( last != -1 ) { eop_desc = & txr -> tx_base [ last ] ; if ( ++ last == adapter -> num_tx_desc ) last = 0 ; done = last ; } else break ; } bus_dmamap_sync ( txr -> txdma . dma_tag , txr -> txdma . dma_map , BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE ) ; txr -> next_to_clean = first ; if ( processed == 0 ) { if ( txr -> busy != EM_TX_HUNG ) ++ txr -> busy ; } else txr -> busy = EM_TX_BUSY ; if ( txr -> tx_avail >= EM_MAX_SCATTER ) { if_setdrvflagbits ( ifp , 0 , IFF_DRV_OACTIVE ) ; } if ( txr -> tx_avail == adapter -> num_tx_desc ) txr -> busy = EM_TX_IDLE ; }
Examine each tx_buffer in the used queue.
Examine each tx_buffer in the used queue .
/* DEV_NETMAP */ /* No work, make sure hang detection is disabled */ /*
	 * What this does is get the index of the
	 * first descriptor AFTER the EOP of the 
	 * first packet, that way we can do the
	 * simple comparison on the inner while loop.
	 */ /* We clean the range of the packet */ /* See if we can continue to the next packet */ /* Get new done point */ /*
	** Hang detection: we know there's work outstanding
	** or the entry return would have been taken, so no
	** descriptor processed here indicates a potential hang.
	** The local timer will examine this and do a reset if needed.
	*/ /* At least one descriptor was cleaned */ /* note this clears HUNG */ /*
         * If we have a minimum free, clear IFF_DRV_OACTIVE
         * to tell the stack that it is OK to send packets.
	 * Notice that all writes of OACTIVE happen under the
	 * TX lock which, with a single queue, guarantees 
	 * sanity.
         */ /* Disable hang detection if all clean */