• Russell King's avatar
    net: fec: fix interrupt handling races · 7a16807c
    Russell King authored
    While running: while :; do iperf -c <HOST> -P 4; done, transmit timeouts
    are regularly reported.  With the tx ring dumping in place, we can see
    that all entries are in use, and the hardware has finished transmitting
    these packets.  However, the driver has not reclaimed these ring
    entries.
    
    This can occur if the interrupt handler is invoked at the wrong moment -
    eg:
    
    	CPU0				CPU1
    	fec_enet_tx()
    					interrupt, IEVENT = FEC_ENET_TXF
    					FEC_ENET_TXF cleared
    					napi_schedule_prep()
    	napi_complete()
    
    The result is that we clear the transmit interrupt, but we don't trigger
    any cleaning of the transmit ring.  Instead, use a different strategy:
    
    - When receiving a transmit or receive interrupt, disable both tx and rx
      interrupts, but do not acknowledge them.  Schedule a napi poll.  Don't
      loop.
    
    - When we are polled, read IEVENT, acknowledging the pending transmit
      and receive interrupts, before then going on to process the
      appropriate rings.
    
    This allows us to avoid the race, and has a number of other advantages:
    - we cut down on the number of transmit interrupts we have to process.
    - we only look at the rings which have pending events.
    - we gain additional throughput: the iperf total bandwidth increases
      from about 180Mbps to 240Mbps:
    
    [  3]  0.0-10.0 sec  68.1 MBytes  57.0 Mbits/sec
    [  5]  0.0-10.0 sec  72.4 MBytes  60.5 Mbits/sec
    [  4]  0.0-10.1 sec  76.1 MBytes  63.5 Mbits/sec
    [  6]  0.0-10.1 sec  71.9 MBytes  59.9 Mbits/sec
    [SUM]  0.0-10.1 sec   288 MBytes   241 Mbits/sec
    Acked-by: default avatarFugang Duan <B38611@freescale.com>
    Signed-off-by: default avatarRussell King <rmk+kernel@arm.linux.org.uk>
    Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
    7a16807c
fec_main.c 69.8 KB