Browse Source

[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 <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 7 years ago
parent
commit
97f0f56a34
1 changed files with 16 additions and 3 deletions
  1. 16
    3
      src/net/netdevice.c

+ 16
- 3
src/net/netdevice.c View File

402
 	list_del ( &iobuf->list );
402
 	list_del ( &iobuf->list );
403
 	netdev_tx_err ( netdev, iobuf, rc );
403
 	netdev_tx_err ( netdev, iobuf, rc );
404
 
404
 
405
-	/* Transmit first pending packet, if any */
406
-	if ( ( iobuf = list_first_entry ( &netdev->tx_deferred,
407
-					  struct io_buffer, list ) ) != NULL ) {
405
+	/* Handle pending transmit queue */
406
+	while ( ( iobuf = list_first_entry ( &netdev->tx_deferred,
407
+					     struct io_buffer, list ) ) ) {
408
+
409
+		/* Remove from pending transmit queue */
408
 		list_del ( &iobuf->list );
410
 		list_del ( &iobuf->list );
411
+
412
+		/* When any transmit completion fails, cancel all
413
+		 * pending transmissions.
414
+		 */
415
+		if ( rc != 0 ) {
416
+			netdev_tx_err ( netdev, iobuf, -ECANCELED );
417
+			continue;
418
+		}
419
+
420
+		/* Otherwise, attempt to transmit the first pending packet */
409
 		netdev_tx ( netdev, iobuf );
421
 		netdev_tx ( netdev, iobuf );
422
+		break;
410
 	}
423
 	}
411
 }
424
 }
412
 
425
 

Loading…
Cancel
Save