summaryrefslogtreecommitdiffstats
path: root/src/drivers/net/efi/nii.c
diff options
context:
space:
mode:
authorMichael Brown2023-06-21 12:49:53 +0200
committerMichael Brown2023-06-21 12:49:53 +0200
commit2689a6e77668bc7bd0cf486fa7e4d733c5069bd9 (patch)
treecb98505a1642c47c8b52ee555a9486420955f26e /src/drivers/net/efi/nii.c
parent[efi] Provide read-only access to EFI variables via settings mechanism (diff)
downloadipxe-2689a6e77668bc7bd0cf486fa7e4d733c5069bd9.tar.gz
ipxe-2689a6e77668bc7bd0cf486fa7e4d733c5069bd9.tar.xz
ipxe-2689a6e77668bc7bd0cf486fa7e4d733c5069bd9.zip
[efi] Always poll for TX completions
Polling for TX completions is arguably redundant when there are no transmissions currently in progress. Commit c6c7e78 ("[efi] Poll for TX completions only when there is an outstanding TX buffer") switched to setting the PXE_OPFLAGS_GET_TRANSMITTED_BUFFERS flag only when there is an in-progress transmission awaiting completion, in order to reduce reported TX errors and debug message noise from buggy NII implementations that report spurious TX completions whenever the transmit queue is empty. Some other NII implementations (observed with the Realtek driver in a Dell Latitude 3440) seem to have a bug in the transmit datapath handling which results in the transmit ring freezing after sending a few hundred packets under heavy load. The symptoms are that the TPPoll register's NPQ bit remains set and the 256-entry transmit ring contains a large number of uncompleted descriptors (with the OWN bit set), the first two of which have identical data buffer addresses. Though iPXE will submit at most one in-progress transmission via NII, the Dell/Realtek driver seems to make a page-aligned copy of each transmit data buffer and to report TX completions immediately without waiting for the packet to actually be transmitted. These synthetic TX completions continue even after the hardware transmit ring freezes. Setting PXE_OPFLAGS_GET_TRANSMITTED_BUFFERS on every poll reduces the probability of this Dell/Realtek driver bug being triggered by a factor of around 500, which brings the failure rate down to the point that it can sensibly be managed by external logic such as the "--timeout" option for image downloads. Closing and reopening the interface (via "ifclose"/"ifopen") will clear the error condition and allow transmissions to resume. Revert to setting PXE_OPFLAGS_GET_TRANSMITTED_BUFFERS on every poll, and silently ignore situations in which the hardware reports a completion when no transmission is in progress. This approximately matches the behaviour of the SnpDxe driver, which will also generally set PXE_OPFLAGS_GET_TRANSMITTED_BUFFERS on every poll. Signed-off-by: Michael Brown <mcb30@ipxe.org>
Diffstat (limited to 'src/drivers/net/efi/nii.c')
-rw-r--r--src/drivers/net/efi/nii.c10
1 files changed, 5 insertions, 5 deletions
diff --git a/src/drivers/net/efi/nii.c b/src/drivers/net/efi/nii.c
index be5bce4b..8dd17e4b 100644
--- a/src/drivers/net/efi/nii.c
+++ b/src/drivers/net/efi/nii.c
@@ -1032,8 +1032,9 @@ static void nii_poll_tx ( struct net_device *netdev, unsigned int stat ) {
if ( stat & PXE_STATFLAGS_GET_STATUS_NO_TXBUFS_WRITTEN )
return;
- /* Sanity check */
- assert ( nii->txbuf != NULL );
+ /* Ignore spurious completions reported by some devices */
+ if ( ! nii->txbuf )
+ return;
/* Complete transmission */
iobuf = nii->txbuf;
@@ -1131,7 +1132,7 @@ static void nii_poll ( struct net_device *netdev ) {
/* Get status */
op = NII_OP ( PXE_OPCODE_GET_STATUS,
( PXE_OPFLAGS_GET_INTERRUPT_STATUS |
- ( nii->txbuf ? PXE_OPFLAGS_GET_TRANSMITTED_BUFFERS : 0)|
+ PXE_OPFLAGS_GET_TRANSMITTED_BUFFERS |
( nii->media ? PXE_OPFLAGS_GET_MEDIA_STATUS : 0 ) ) );
if ( ( stat = nii_issue_db ( nii, op, &db, sizeof ( db ) ) ) < 0 ) {
rc = -EIO_STAT ( stat );
@@ -1141,8 +1142,7 @@ static void nii_poll ( struct net_device *netdev ) {
}
/* Process any TX completions */
- if ( nii->txbuf )
- nii_poll_tx ( netdev, stat );
+ nii_poll_tx ( netdev, stat );
/* Process any RX completions */
nii_poll_rx ( netdev );