Netdev List
 help / color / mirror / Atom feed
* [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