* [PATCH iwl-net v2] e1000e: work around TSO erratum that corrupts data and hangs Tx
@ 2026-10-20 23:02 Andre Brait
0 siblings, 0 replies; only message in thread
From: Andre Brait @ 2026-10-20 23:02 UTC (permalink / raw)
To: intel-wired-lan
Cc: netdev, anthony.l.nguyen, przemyslaw.kitszel, g.goller,
Andre Brait
On I219, a TSO packet whose first buffer is long and has a 4 KB
boundary just after the TCP checksum field makes the NIC send corrupted
data and then hang the Tx DMA. Forwarded VM traffic (tun/vhost-net)
produces such packets, so hosts bridging guests onto an I219 hit it
within minutes:
e1000e 0000:00:1f.6 eno1: Detected Hardware Unit Hang
Right before the hang the receiver gets TCP segments carrying data from
128 bytes earlier in the stream, with a valid checksum.
This is the erratum Intel documents for the 82571/82572 (#76), 82574
(#17) and 82583V (#7): if the first buffer is larger than
3 * (max_read_request - 4) bytes and a 4 KB boundary falls just after
the headers, a read is repeated, wrong data goes out with a correct
checksum, and the Tx DMA hangs. e1000e never implemented the documented
workaround.
Apply it to all e1000e parts: limit the first data descriptor of a TSO
packet to 3 * (max_read_request - 4) bytes (372 on the I219, where
pcie_get_readrq() returns 128). The rest of the linear part goes into
the next descriptor, which e1000_xmit_frame() already reserves; the NIC
still segments the packet.
Tested on I219-LM (8086:15bb), v7.0.14, byte-verified traffic:
unpatched patched
packets placed inside the window [1] hang in seconds no hang
guest traffic, TCP timestamps on hang at 387 s 60 min ok
guest traffic, TCP timestamps off hang at 402 s 40 min ok
guest traffic, VLAN tag from stack hang at 1176 s 40 min ok
[1] 785-1013 packets at each of 10 offsets, 54- to 70-byte headers
Unpatched, data was corrupted at every hang. Patched, no corruption, no
Tx timeouts or drops, and hardware TSO stayed in use (26.5M segments).
Developed with an AI coding assistant (Claude); details below the cut.
Fixes: bc7f75fa9788 ("[E1000E]: New pci-express e1000 driver (currently for ICH9 devices only)")
Assisted-by: LLM
Signed-off-by: Andre Brait <andrebrait@gmail.com>
---
Notes:
This is a follow-up to a first attempt at fixing this issue
(https://lore.kernel.org/netdev/20261018203215.77371-1-andrebrait@gmail.com/).
Gabriel replied that the stack can still move the headers after
ndo_features_check, which made me look further. The condition that
patch relied on, TSO headers crossing a 4 KB boundary, turned out to be
only part of the problem.
The NIC hangs, after sending TCP segments with the wrong data and a
valid checksum, when the first buffer of a TSO packet is long and a
4 KB boundary falls 1 to 16 bytes after the start of the TCP checksum
field. The headers do not have to cross the boundary: with TCP
timestamps off (54-byte headers), a packet whose headers end 10 bytes
before it hangs the NIC too, and the first patch did not catch that.
Forwarded VM traffic hits this because tun/vhost-net builds linear TSO
buffers at arbitrary offsets.
Intel documents the same failure as a TSO erratum for the
82571/82572, 82574 and 82583V: a first buffer longer than
3 * (max_read_request - 4) bytes with a 4 KB boundary just after the
headers. Its workaround is to keep the headers in a first buffer no
longer than that, which removes the long-buffer condition no matter
where the boundary falls. This patch applies it to all e1000e parts; on
the I219 it prevented the hang at every offset in the window.
The full investigation, tools, captures and raw results are at
https://github.com/andrebrait/e1000e-i219-tso-hang/tree/08c29e379bac
Summary of the runs. "ts on/off" is TCP timestamps in the guest (66-
or 54-byte headers); "VLAN" has the stack insert a VLAN tag (rx/txvlan
off, timestamps on). "hang <Xm": every run hung, the slowest within
X minutes; "ok Xm": ran X minutes without a hang.
ts on ts off VLAN placed [1]
unpatched hang <27m hang <7m hang <20m hang <12m
first patch ok 252m hang <6m ok 72m -
check in xmit [2] ok 60m hang <2m ok 47m -
SPT/KBL regs [3] - - - hang <1m
split at 4 KB [4] - - - hang <1m
this patch ok 60m ok 40m ok 40m ok
[1] buffer placed so the 4 KB boundary falls inside the window;
"ok" means about 1000 packets per offset without a hang
[2] an attempt to redo the first patch in e1000_xmit_frame(), on the
final layout, segmenting in the driver; it could also stall the
queue when it returned NETDEV_TX_BUSY
[3] the existing SPT/KBL IOSFPC/TARC0 workaround, extended to CNP
[4] first descriptor ending at the 4 KB boundary
Every hang came with corrupted data, except the two with the 4 KB
split.
Limits:
- Tested only on I219-LM (CNP); an I219-V hung the same way in
production. The 8257x parts are covered by the erratum but untested
here. Runtime-tested on 7.0.14; builds with W=1 on dev-queue.
- The I219 window (1-16 bytes after tucso) differs from the documented
8257x one (64 bytes after the headers). Intel may know whether the
engine differs, and the I219's actual max_read_request.
- Not addressed here: since 95ecba62e2fd the netdev watchdog may never
reset a hung e1000e (bugzilla.kernel.org 118721, comments 29-30).
The AI ran as an agent with SSH access to my two test hosts. I set the
test requirements (byte-checked traffic, controls that must fail first,
identical setups) and reviewed the results and the code.
drivers/net/ethernet/intel/e1000e/e1000.h | 1 +
drivers/net/ethernet/intel/e1000e/netdev.c | 11 +++++++++++
2 files changed, 12 insertions(+)
diff --git a/drivers/net/ethernet/intel/e1000e/e1000.h b/drivers/net/ethernet/intel/e1000e/e1000.h
index 63ebe0037..704284188 100644
--- a/drivers/net/ethernet/intel/e1000e/e1000.h
+++ b/drivers/net/ethernet/intel/e1000e/e1000.h
@@ -219,6 +219,7 @@ struct e1000_adapter {
/* Tx - one ring per active queue */
struct e1000_ring *tx_ring ____cacheline_aligned_in_smp;
u32 tx_fifo_limit;
+ u32 tx_hdr_buf_max;
struct napi_struct napi;
diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c
index 834a5b888..f5f5d2230 100644
--- a/drivers/net/ethernet/intel/e1000e/netdev.c
+++ b/drivers/net/ethernet/intel/e1000e/netdev.c
@@ -4143,6 +4143,15 @@ void e1000e_reset(struct e1000_adapter *adapter)
adapter->tx_fifo_limit = min_t(u32, ((er32(PBA) >> 16) << 10) - 96,
24 << 10);
+ /* TSO erratum (82571/82572 #76, 82574 #17, 82583V #7, also seen on
+ * I219): when the first buffer of a TSO packet is larger than
+ * 3 * (max_read_request - 4) bytes and a 4 KB boundary lies just
+ * after its headers, the NIC repeats a read, sends wrong data with a
+ * correct checksum and then hangs. Keep the headers in a first buffer
+ * no larger than that.
+ */
+ adapter->tx_hdr_buf_max = 3 * (pcie_get_readrq(adapter->pdev) - 4);
+
/* Disable Adaptive Interrupt Moderation if 2 full packets cannot
* fit in receive buffer.
*/
@@ -5632,6 +5641,8 @@ static int e1000_tx_map(struct e1000_ring *tx_ring, struct sk_buff *skb,
while (len) {
buffer_info = &tx_ring->buffer_info[i];
size = min(len, max_per_txd);
+ if (!offset && skb_is_gso(skb))
+ size = min(size, adapter->tx_hdr_buf_max);
buffer_info->length = size;
buffer_info->time_stamp = jiffies;
--
2.56.0
^ permalink raw reply related [flat|nested] only message in thread
only message in thread, other threads:[~2026-10-20 23:03 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-20 23:02 [PATCH iwl-net v2] e1000e: work around TSO erratum that corrupts data and hangs Tx Andre Brait
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox