From 97f0f56a34e32e705d3eee18526222f43fc88e6e Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 5 Sep 2017 12:21:11 +0100 Subject: [netdevice] Cancel all pending transmissions on any transmit error Some external code (such as the UEFI UNDI driver for the Realtek USB NIC on a Microsoft Surface Book) will block during transmission attempts and can take several seconds to report a transmit error. If there is a large queue of pending transmissions, then the accumulated time from a series of such failures can easily exceed the EFI watchdog timeout, resulting in what appears to be a system lockup followed by a reboot. Work around this problem by immediately cancelling any pending transmissions as soon as any transmit error occurs. The only expected transmit error under normal operation is ENOBUFS arising when the hardware transmit queue is full. By definition, this can happen only for drivers that do not utilise deferred transmissions, and so this new behaviour will not affect these drivers. Signed-off-by: Michael Brown --- src/net/netdevice.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) (limited to 'src/net') diff --git a/src/net/netdevice.c b/src/net/netdevice.c index 41ece77f..4c211d70 100644 --- a/src/net/netdevice.c +++ b/src/net/netdevice.c @@ -402,11 +402,24 @@ void netdev_tx_complete_err ( struct net_device *netdev, list_del ( &iobuf->list ); netdev_tx_err ( netdev, iobuf, rc ); - /* Transmit first pending packet, if any */ - if ( ( iobuf = list_first_entry ( &netdev->tx_deferred, - struct io_buffer, list ) ) != NULL ) { + /* Handle pending transmit queue */ + while ( ( iobuf = list_first_entry ( &netdev->tx_deferred, + struct io_buffer, list ) ) ) { + + /* Remove from pending transmit queue */ list_del ( &iobuf->list ); + + /* When any transmit completion fails, cancel all + * pending transmissions. + */ + if ( rc != 0 ) { + netdev_tx_err ( netdev, iobuf, -ECANCELED ); + continue; + } + + /* Otherwise, attempt to transmit the first pending packet */ netdev_tx ( netdev, iobuf ); + break; } } -- cgit v1.2.3-55-g7522