Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

net: stmmac: fix resume: calculate tso last_segment

Tao Wang reports that sometimes, after resume, stmmac can watchdog:
NETDEV WATCHDOG: CPU: x: transmit queue x timed out xx ms

When this occurs, the DMA transmit descriptors contain:
eth0: 221 [0x0000000876d10dd0]: 0x73660cbe 0x8 0x42 0xb04416a0
eth0: 222 [0x0000000876d10de0]: 0x77731d40 0x8 0x16a0 0x90000000

where descriptor 221 is the TSO header and 222 is the TSO payload.
tdes3 for descriptor 221 (0xb04416a0) has both bit 29 (first
descriptor) and bit 28 (last descriptor) set, which is incorrect.
The following packet also has bit 28 set, but isn't marked as a
first descriptor, and this causes the transmit DMA to stall.

This occurs because stmmac_tso_allocator() populates the first
descriptor, but does not set .last_segment correctly. There are two
places where this matters: one is later in stmmac_tso_xmit() where
we use it to update the TSO header descriptor. The other is in the
ring/chain mode clean_desc3() which is a performance optimisation.

Rather than using tx_q->tx_skbuff_dma[].last_segment to determine
whether the first descriptor entry is the only segment, calculate the
number of descriptor entries used. If there is only one descriptor,
then the first is also the last, so mark it as such.

Further work will be necessary to either eliminate .last_segment
entirely or set it correctly. Code analysis also indicates that a
similar issue exists with .is_jumbo. These will be the subject of
a future patch.

Reported-by: Tao Wang <tao03.wang@horizon.auto>
Fixes: c2837423cb54 ("net: stmmac: Rework TX Coalesce logic")
Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
Link: https://patch.msgid.link/E1vhq8O-00000005N5s-0Ke5@rmk-PC.armlinux.org.uk
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Russell King (Oracle) and committed by
Jakub Kicinski
5228e9fa 302e5b48

+9 -3
+9 -3
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
··· 4359 4359 unsigned int first_entry, tx_packets; 4360 4360 struct stmmac_txq_stats *txq_stats; 4361 4361 struct stmmac_tx_queue *tx_q; 4362 + bool set_ic, is_last_segment; 4362 4363 u32 pay_len, mss, queue; 4363 4364 int i, first_tx, nfrags; 4364 4365 u8 proto_hdr_len, hdr; 4365 4366 dma_addr_t des; 4366 - bool set_ic; 4367 4367 4368 4368 /* Always insert VLAN tag to SKB payload for TSO frames. 4369 4369 * ··· 4551 4551 stmmac_enable_tx_timestamp(priv, first); 4552 4552 } 4553 4553 4554 + /* If we only have one entry used, then the first entry is the last 4555 + * segment. 4556 + */ 4557 + is_last_segment = ((tx_q->cur_tx - first_entry) & 4558 + (priv->dma_conf.dma_tx_size - 1)) == 1; 4559 + 4554 4560 /* Complete the first descriptor before granting the DMA */ 4555 4561 stmmac_prepare_tso_tx_desc(priv, first, 1, proto_hdr_len, 0, 1, 4556 - tx_q->tx_skbuff_dma[first_entry].last_segment, 4557 - hdr / 4, (skb->len - proto_hdr_len)); 4562 + is_last_segment, hdr / 4, 4563 + skb->len - proto_hdr_len); 4558 4564 4559 4565 /* If context desc is used to change MSS */ 4560 4566 if (mss_desc) {