Skip to content

Commit 5228e9f

Browse files
Russell King (Oracle)kuba-moo
authored andcommitted
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: c283742 ("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>
1 parent 302e5b4 commit 5228e9f

1 file changed

Lines changed: 9 additions & 3 deletions

File tree

drivers/net/ethernet/stmicro/stmmac/stmmac_main.c

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4359,11 +4359,11 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev)
43594359
unsigned int first_entry, tx_packets;
43604360
struct stmmac_txq_stats *txq_stats;
43614361
struct stmmac_tx_queue *tx_q;
4362+
bool set_ic, is_last_segment;
43624363
u32 pay_len, mss, queue;
43634364
int i, first_tx, nfrags;
43644365
u8 proto_hdr_len, hdr;
43654366
dma_addr_t des;
4366-
bool set_ic;
43674367

43684368
/* Always insert VLAN tag to SKB payload for TSO frames.
43694369
*
@@ -4551,10 +4551,16 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev)
45514551
stmmac_enable_tx_timestamp(priv, first);
45524552
}
45534553

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+
45544560
/* Complete the first descriptor before granting the DMA */
45554561
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);
45584564

45594565
/* If context desc is used to change MSS */
45604566
if (mss_desc) {

0 commit comments

Comments
 (0)