From fcbf106189aaf69a2a2f6116672d442d473ecbcd Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Fri, 20 Mar 2026 16:47:12 +0000 Subject: [PATCH 1/6] net: stmmac: move stmmac_xmit() skb head handling The skb head buffer handling is delayed in stmmac_xmit() until after the skb fragments have been populated into the descriptors. The reason is this code used to set the OWN bit on the first descriptor, which then allows the TX DMA to process the first and subsequent descriptors. However, as of commit 579a25a854d4 ("net: stmmac: Initial support for TBS") this is now separated, but the comments weren't updated. Move the code populating the first descriptor along side the jumbo code which also populates the first descriptor. This gives a consistent location where we populate the descriptor(s) for the SKB head. Signed-off-by: Russell King (Oracle) Link: https://patch.msgid.link/E1w3d0C-0000000DfLj-0BLb@rmk-PC.armlinux.org.uk Tested-by: Maxime Chevallier Signed-off-by: Paolo Abeni --- .../net/ethernet/stmicro/stmmac/stmmac_main.c | 63 +++++++++---------- 1 file changed, 30 insertions(+), 33 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index ecb6d9a27567..fb9719820b93 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -4763,6 +4763,33 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) entry = stmmac_jumbo_frm(priv, tx_q, skb, csum_insertion); if (unlikely(entry < 0) && (entry != -EINVAL)) goto dma_map_err; + } else { + bool last_segment = (nfrags == 0); + + dma_addr = dma_map_single(priv->device, skb->data, + nopaged_len, DMA_TO_DEVICE); + if (dma_mapping_error(priv->device, dma_addr)) + goto dma_map_err; + + stmmac_set_tx_skb_dma_entry(tx_q, first_entry, dma_addr, + nopaged_len, false); + + stmmac_set_desc_addr(priv, first_desc, dma_addr); + + if (last_segment) + stmmac_set_tx_dma_last_segment(tx_q, first_entry); + + if (unlikely((skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) && + priv->hwts_tx_en)) { + /* declare that device is doing timestamping */ + skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; + stmmac_enable_tx_timestamp(priv, first_desc); + } + + /* Prepare the first descriptor without setting the OWN bit */ + stmmac_prepare_tx_desc(priv, first_desc, 1, nopaged_len, + csum_insertion, priv->descriptor_mode, + 0, last_segment, skb->len); } for (i = 0; i < nfrags; i++) { @@ -4854,39 +4881,6 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) if (priv->sarc_type) stmmac_set_desc_sarc(priv, first_desc, priv->sarc_type); - /* Ready to fill the first descriptor and set the OWN bit w/o any - * problems because all the descriptors are actually ready to be - * passed to the DMA engine. - */ - if (likely(!is_jumbo)) { - bool last_segment = (nfrags == 0); - - dma_addr = dma_map_single(priv->device, skb->data, - nopaged_len, DMA_TO_DEVICE); - if (dma_mapping_error(priv->device, dma_addr)) - goto dma_map_err; - - stmmac_set_tx_skb_dma_entry(tx_q, first_entry, dma_addr, - nopaged_len, false); - - stmmac_set_desc_addr(priv, first_desc, dma_addr); - - if (last_segment) - stmmac_set_tx_dma_last_segment(tx_q, first_entry); - - if (unlikely((skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) && - priv->hwts_tx_en)) { - /* declare that device is doing timestamping */ - skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; - stmmac_enable_tx_timestamp(priv, first_desc); - } - - /* Prepare the first descriptor setting the OWN bit too */ - stmmac_prepare_tx_desc(priv, first_desc, 1, nopaged_len, - csum_insertion, priv->descriptor_mode, - 0, last_segment, skb->len); - } - if (tx_q->tbs & STMMAC_TBS_EN) { struct timespec64 ts = ns_to_timespec64(skb->tstamp); @@ -4894,6 +4888,9 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) stmmac_set_desc_tbs(priv, tbs_desc, ts.tv_sec, ts.tv_nsec); } + /* Set the OWN bit on the first descriptor now that all descriptors + * for this skb are populated. + */ stmmac_set_tx_owner(priv, first_desc); netdev_tx_sent_queue(netdev_get_tx_queue(dev, queue), skb->len); From cafacdc48a74e16b2ad727b3f31a06c08d96e0b1 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Fri, 20 Mar 2026 16:47:17 +0000 Subject: [PATCH 2/6] net: stmmac: move first xmit descriptor SARC and TBS config Move the first transmit descriptor's SARC and TBS configuration alongside the code which populates the first descriptor, which helps to keep all the code specific to that descriptor together. Signed-off-by: Russell King (Oracle) Link: https://patch.msgid.link/E1w3d0H-0000000DfLp-0gIx@rmk-PC.armlinux.org.uk Tested-by: Maxime Chevallier Signed-off-by: Paolo Abeni --- .../net/ethernet/stmicro/stmmac/stmmac_main.c | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index fb9719820b93..8741513b152d 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -4792,6 +4792,16 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) 0, last_segment, skb->len); } + if (priv->sarc_type) + stmmac_set_desc_sarc(priv, first_desc, priv->sarc_type); + + if (tx_q->tbs & STMMAC_TBS_EN) { + struct timespec64 ts = ns_to_timespec64(skb->tstamp); + + tbs_desc = &tx_q->dma_entx[first_entry]; + stmmac_set_desc_tbs(priv, tbs_desc, ts.tv_sec, ts.tv_nsec); + } + for (i = 0; i < nfrags; i++) { const skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; unsigned int frag_size = skb_frag_size(frag); @@ -4878,16 +4888,6 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) u64_stats_inc(&txq_stats->q.tx_set_ic_bit); u64_stats_update_end(&txq_stats->q_syncp); - if (priv->sarc_type) - stmmac_set_desc_sarc(priv, first_desc, priv->sarc_type); - - if (tx_q->tbs & STMMAC_TBS_EN) { - struct timespec64 ts = ns_to_timespec64(skb->tstamp); - - tbs_desc = &tx_q->dma_entx[first_entry]; - stmmac_set_desc_tbs(priv, tbs_desc, ts.tv_sec, ts.tv_nsec); - } - /* Set the OWN bit on the first descriptor now that all descriptors * for this skb are populated. */ From 7b8683115034360a2f7f7e5b0dac958249fa810a Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Fri, 20 Mar 2026 16:47:22 +0000 Subject: [PATCH 3/6] net: stmmac: move stmmac_xmit() first entry index code The handling of the first descriptor index/pointer is split around the checksum handling which makes no sense. Group this code together. Signed-off-by: Russell King (Oracle) Link: https://patch.msgid.link/E1w3d0M-0000000DfLv-1C6S@rmk-PC.armlinux.org.uk Tested-by: Maxime Chevallier Signed-off-by: Paolo Abeni --- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 8741513b152d..84de1134d581 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -4728,10 +4728,6 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) /* Check if VLAN can be inserted by HW */ has_vlan = stmmac_vlan_insert(priv, skb, tx_q); - entry = tx_q->cur_tx; - first_entry = entry; - WARN_ON(tx_q->tx_skbuff[first_entry]); - csum_insertion = (skb->ip_summed == CHECKSUM_PARTIAL); /* DWMAC IPs can be synthesized to support tx coe only for a few tx * queues. In that case, checksum offloading for those queues that don't @@ -4748,6 +4744,10 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) csum_insertion = !csum_insertion; } + entry = tx_q->cur_tx; + first_entry = entry; + WARN_ON(tx_q->tx_skbuff[first_entry]); + desc = stmmac_get_tx_desc(priv, tx_q, entry); first_desc = desc; From 2e3bfeb1bc0c0a7cd51212ecc6533aca73cf8e2d Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Fri, 20 Mar 2026 16:47:27 +0000 Subject: [PATCH 4/6] net: stmmac: move stmmac_xmit() initial variable init Move tx_q, first_tx and txq_stats just before their first use. Signed-off-by: Russell King (Oracle) Link: https://patch.msgid.link/E1w3d0R-0000000DfM1-1itN@rmk-PC.armlinux.org.uk Tested-by: Maxime Chevallier Signed-off-by: Paolo Abeni --- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 84de1134d581..58a84570821c 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -4685,10 +4685,6 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) dma_addr_t dma_addr; u32 sdu_len; - tx_q = &priv->dma_conf.tx_queue[queue]; - txq_stats = &priv->xstats.txq_stats[queue]; - first_tx = tx_q->cur_tx; - if (priv->tx_path_in_lpi_mode && priv->eee_sw_timer_en) stmmac_stop_sw_lpi(priv); @@ -4725,6 +4721,9 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_BUSY; } + tx_q = &priv->dma_conf.tx_queue[queue]; + first_tx = tx_q->cur_tx; + /* Check if VLAN can be inserted by HW */ has_vlan = stmmac_vlan_insert(priv, skb, tx_q); @@ -4882,6 +4881,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) netif_tx_stop_queue(netdev_get_tx_queue(priv->dev, queue)); } + txq_stats = &priv->xstats.txq_stats[queue]; u64_stats_update_begin(&txq_stats->q_syncp); u64_stats_add(&txq_stats->q.tx_bytes, skb->len); if (set_ic) From 557ccd54ba141650cfd6962296c062089f3c6cd3 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Fri, 20 Mar 2026 16:47:32 +0000 Subject: [PATCH 5/6] net: stmmac: use first_desc for TBS Rather than freshly getting a pointer for the TBS descriptor (because we want to access its enhanced fields) convert the existing first_desc basic descriptor to a pointer to the enhanced descriptor. Add a comment explaining why it is safe to convert from the basic descriptor pointer to the enhanced descriptor pointer. Signed-off-by: Russell King (Oracle) Link: https://patch.msgid.link/E1w3d0W-0000000DfM7-2BMA@rmk-PC.armlinux.org.uk Tested-by: Maxime Chevallier [pabeni@redhat.com: fixed comment typo] Signed-off-by: Paolo Abeni --- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 58a84570821c..a8a18d79b6a8 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -4794,10 +4794,15 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) if (priv->sarc_type) stmmac_set_desc_sarc(priv, first_desc, priv->sarc_type); + /* STMMAC_TBS_EN can only be set if STMMAC_TBS_AVAIL has already + * been set, which means the underlying type of the descriptors + * will be struct stmmac_edesc. Therefore, it is safe to convert + * the basic descriptor to the enhanced descriptor here. + */ if (tx_q->tbs & STMMAC_TBS_EN) { struct timespec64 ts = ns_to_timespec64(skb->tstamp); - tbs_desc = &tx_q->dma_entx[first_entry]; + tbs_desc = dma_desc_to_edesc(first_desc); stmmac_set_desc_tbs(priv, tbs_desc, ts.tv_sec, ts.tv_nsec); } From cd1f306e28157bd0900cae52207839d210e61f61 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Fri, 20 Mar 2026 16:47:37 +0000 Subject: [PATCH 6/6] net: stmmac: elminate tbs_desc in stmmac_xmit() There is no need to have a local variable for tbs_desc, we can do the conversion when calling stmmac_set_desc_tbs(). Signed-off-by: Russell King (Oracle) Link: https://patch.msgid.link/E1w3d0b-0000000DfMD-2hrD@rmk-PC.armlinux.org.uk Tested-by: Maxime Chevallier Signed-off-by: Paolo Abeni --- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index a8a18d79b6a8..9b6b49331639 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -4678,7 +4678,6 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) int gso = skb_shinfo(skb)->gso_type; struct stmmac_txq_stats *txq_stats; struct dma_desc *desc, *first_desc; - struct dma_edesc *tbs_desc = NULL; struct stmmac_tx_queue *tx_q; int i, csum_insertion = 0; int entry, first_tx; @@ -4802,8 +4801,8 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) if (tx_q->tbs & STMMAC_TBS_EN) { struct timespec64 ts = ns_to_timespec64(skb->tstamp); - tbs_desc = dma_desc_to_edesc(first_desc); - stmmac_set_desc_tbs(priv, tbs_desc, ts.tv_sec, ts.tv_nsec); + stmmac_set_desc_tbs(priv, dma_desc_to_edesc(first_desc), + ts.tv_sec, ts.tv_nsec); } for (i = 0; i < nfrags; i++) {