FreeBSD/sys/dev/e1000/if_lem.c
/*********************************************************************
 *
 * 82547 workaround to avoid controller hang in half-duplex environment.
 * The workaround is to avoid queuing a large packet that would span
 * the internal Tx FIFO ring boundary. We need to reset the FIFO pointers
 * in this case. We do that only when FIFO is quiescent.
 *
 **********************************************************************/
82547 workaround to avoid controller hang in half-duplex environment.
The workaround is to avoid queuing a large packet that would span
the internal Tx FIFO ring boundary. We need to reset the FIFO pointers
in this case. We do that only when FIFO is quiescent.
82547 workaround to avoid controller hang in half - duplex environment . The workaround is to avoid queuing a large packet that would span the internal Tx FIFO ring boundary . We need to reset the FIFO pointers in this case . We do that only when FIFO is quiescent .
static void
lem_82547_move_tail(void *arg)
{
	struct adapter *adapter = arg;
	struct e1000_tx_desc *tx_desc;
	u16	hw_tdt, sw_tdt, length = 0;
	bool	eop = 0;
	EM_TX_LOCK_ASSERT(adapter);
	hw_tdt = E1000_READ_REG(&adapter->hw, E1000_TDT(0));
	sw_tdt = adapter->next_avail_tx_desc;
	while (hw_tdt != sw_tdt) {
		tx_desc = &adapter->tx_desc_base[hw_tdt];
		length += tx_desc->lower.flags.length;
		eop = tx_desc->lower.data & E1000_TXD_CMD_EOP;
		if (++hw_tdt == adapter->num_tx_desc)
			hw_tdt = 0;
		if (eop) {
			if (lem_82547_fifo_workaround(adapter, length)) {
				adapter->tx_fifo_wrk_cnt++;
				callout_reset(&adapter->tx_fifo_timer, 1,
					lem_82547_move_tail, adapter);
				break;
			}
			E1000_WRITE_REG(&adapter->hw, E1000_TDT(0), hw_tdt);
			lem_82547_update_fifo_head(adapter, length);
			length = 0;
		}
	}	
}
static void lem_82547_move_tail ( void * arg ) { struct adapter * adapter = arg ; struct e1000_tx_desc * tx_desc ; u16 hw_tdt , sw_tdt , length = 0 ; bool eop = 0 ; EM_TX_LOCK_ASSERT ( adapter ) ; hw_tdt = E1000_READ_REG ( & adapter -> hw , E1000_TDT ( 0 ) ) ; sw_tdt = adapter -> next_avail_tx_desc ; while ( hw_tdt != sw_tdt ) { tx_desc = & adapter -> tx_desc_base [ hw_tdt ] ; length += tx_desc -> lower . flags . length ; eop = tx_desc -> lower . data & E1000_TXD_CMD_EOP ; if ( ++ hw_tdt == adapter -> num_tx_desc ) hw_tdt = 0 ; if ( eop ) { if ( lem_82547_fifo_workaround ( adapter , length ) ) { adapter -> tx_fifo_wrk_cnt ++ ; callout_reset ( & adapter -> tx_fifo_timer , 1 , lem_82547_move_tail , adapter ) ; break ; } E1000_WRITE_REG ( & adapter -> hw , E1000_TDT ( 0 ) , hw_tdt ) ; lem_82547_update_fifo_head ( adapter , length ) ; length = 0 ; } } }
82547 workaround to avoid controller hang in half-duplex environment.
82547 workaround to avoid controller hang in half - duplex environment .