net: stmmac: fix RX descriptors and XSK TX on resume
Subsystems (4)
v6 cover net: stmmac: fix RX descriptors and XSK TX on resume
From: Ding Hui <[email protected]>
This series restores RX descriptor addresses overwritten by hardware writeback between disabling NAPI and stopping RX DMA during suspend. It also fixes an AF_XDP TX-only resume stall found while testing the series.
Patch 1 honors RX allocation flags. Patch 2 keeps unfilled XSK slots CPU-owned and tracks pending refills explicitly, including an empty ring and short refills. Patch 3 restores RX addresses from retained buffers, rebuilds chain pointers and initializes descriptor control fields. It publishes a contiguous XSK prefix and recomputes the tail and pending region. Patch 4 restores the bound XSK TX pool after TX buffer cleanup; otherwise zero-copy transmission can stop after resume.
The earlier commit 9c63faaa931e ("net: stmmac: re-init rx buffers when mac resume back") was reverted by 00423969d806 after a Jetson TX2 suspend/resume regression. This series retains existing buffers and DMA mappings instead of recycling and reallocating every buffer. Jetson TX2 has not been tested.
Hardware validation used backports on our XGMAC platform with a vendor kernel based on Linux 6.12.41, not these upstream commits as-is:
- Receiving iperf traffic from a PC while suspending and resuming caused a fatal bus error after resume in almost every run without the RX fix. The same test no longer showed that failure with the fix.
- Native XDP/AF_XDP zero-copy RX continued after two suspend/resume cycles with the receive socket kept open.
- Zero-copy TX-only, with no RX fill buffers, is tested ok after one suspend/resume cycle, with no fatal bus error.
- Pausing the receive application with SIGSTOP and resuming it with SIGCONT recovered RX without recreating the socket.
- xdpsock is used for native XDP testing.
Additional testing would be welcome for RX sockets initially supplied with 0/1/8/15 fill buffers, replenishment in batches below 16, and those states across suspend/resume. These differ from TX-only with no RX fill buffers. Legacy descriptor cores, GMAC4, chain mode, timestamp-specific descriptor paths, multiple XSK queues and long suspend/resume runs remain untested.
Missing page_pool buffers are still allocated during resume. Allocation failure returns -ENOMEM without restarting DMA and leaves the device detached. This adds a trigger for existing resume error-recovery problems; full close/open recovery, including NAPI and platform power handling, is separate work. The Medium-severity AI review on failure recovery is not fully resolved by this revision.
Changes in v6:
- Add a separate fix to restore the bound XSK TX pool after resume cleanup, addressing TX-only stalls found during XGMAC validation.
- Factor resume descriptor work into one TX queue loop and one RX loop, following Thomas's review, and use common error cleanup.
- Restore addresses and chain pointers before initializing RX control fields, preserving legacy fields and RIWT/IOC policy without a separate OWN loop.
- Add format-specific RX ownership clearing for unfilled XSK descriptors.
- Track pending XSK refills independently of circular index equality; retry short refills and prevent consumption of unfilled descriptors.
- Restore a populated XSK prefix and retain later attached buffers for refill; recompute the allocation count, initial tail and pending region.
- Select XSK buffer size independently of the initial allocation count.
- Discard any partially assembled RX frame before resetting the RX ring after resume.
Link to v5:
https://lore.kernel.org/netdev/[email protected]/
Changes in v5:
- Target net and add Fixes tags to both patches.
- Split the allocation-flags fix into a separate patch, with a Fixes tag identifying the page_pool conversion that stopped honoring the flags.
- Share page_pool and XSK buffer preparation with the RX refill paths.
- Allocate missing secondary pages even when the primary page exists, using the current baseline's buffer2 capability check.
- Condense the reinitialization kernel-doc to two paragraphs.
- Restore descriptor addresses before the final dma_wmb()/OWN pass.
- Clarify that unavailable XSK slots remain CPU-owned and may stop DMA with RBU, rather than claiming that hardware skips them.
- Power down legacy SerDes if RX descriptor restoration fails.
Link to v4:
https://lore.kernel.org/netdev/[email protected]/
Changes in v4:
- Document the return value of stmmac_reinit_rx_descriptors().
Link to v3:
https://lore.kernel.org/netdev/[email protected]/
Changes in v3:
- Allocate missing page_pool buffers with GFP_KERNEL and abort resume on allocation failure.
- Try to allocate missing XSK buffers and clear descriptors when the fill ring cannot supply a buffer.
- Restore OWN after programming addresses and rebuilding chain pointers.
- Honor the flags argument of stmmac_init_rx_buffers().
- Restore RX descriptors after stmmac_clear_descriptors().
Link to v2:
https://lore.kernel.org/netdev/[email protected]/
Changes in v2:
- Introduce a helper to restore addresses from existing RX buffers.
- Update the commit message.
Link to v1:
https://lore.kernel.org/netdev/[email protected]/
Ding Hui (4):
net: stmmac: honor allocation flags when initializing RX buffers
net: stmmac: track unfilled XSK RX descriptors explicitly
net: stmmac: restore RX descriptor buffer addresses on resume
net: stmmac: restore the XSK TX pool on resume
.../ethernet/stmicro/stmmac/dwmac4_descs.c | 6 + .../ethernet/stmicro/stmmac/dwxgmac2_descs.c | 6 + .../net/ethernet/stmicro/stmmac/enh_desc.c | 6 + drivers/net/ethernet/stmicro/stmmac/hwif.h | 3 + .../net/ethernet/stmicro/stmmac/norm_desc.c | 6 + drivers/net/ethernet/stmicro/stmmac/stmmac.h | 2 + .../net/ethernet/stmicro/stmmac/stmmac_main.c | 277 +++++++++++++----- 7 files changed, 228 insertions(+), 78 deletions(-)
base-commit: 7076f684d5132e6a6145e1da2fa74771ecd052e5
Signature · 1 line
2.34.1
PATCH v6 1/4 net: stmmac: honor allocation flags when initializing RX buffers
From: Ding Hui <[email protected]>
stmmac_init_rx_buffers() accepts allocation flags but stopped using them when RX buffers were converted to page_pool. As a result, callers passing GFP_KERNEL still allocate with GFP_ATOMIC | __GFP_NOWARN and cannot use reclaim to satisfy an allocation.
Use the supplied flags while retaining GFP_DMA32 for hardware without 64-bit DMA addressing. This also allows the resume path to allocate missing RX pages with GFP_KERNEL.
--- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +1 -1
@@ -1688,7 +1688,7 @@ static int stmmac_init_rx_buffers(struct stmmac_priv *priv, {struct stmmac_rx_queue *rx_q = &dma_conf->rx_queue[queue];struct stmmac_rx_buffer *buf = &rx_q->buf_pool[i]; -gfp_t gfp = (GFP_ATOMIC | __GFP_NOWARN); +gfp_t gfp = flags;if (priv->dma_cap.host_dma_width <=32 ) gfp |=GFP_DMA32 ;
Signature · 1 line
2.34.1
PATCH v6 2/4 net: stmmac: track unfilled XSK RX descriptors explicitly
In reply to Ding HuiFrom: Ding Hui <[email protected]>
An XSK fill ring may supply fewer buffers than the RX ring needs. Those unfilled descriptors must remain CPU-owned, including on legacy cores whose clear callback only clears the buffer address. Add an ownership operation that preserves descriptor size and ring/chain control fields.
Track the number of descriptors awaiting refill independently of the ring indices, so an entirely empty ring can be distinguished from one with no pending refills. Initialize the pending region after the allocated prefix and stop consumption before entering it. Retry pending refills on each poll, including userspace wakeups with fewer than a batch of buffers, and retain batching during packet processing.
Update the tail after successful refills and kick legacy RX DMA. Use the end-of-ring tail address for a refill ending at index zero, including a completely empty ring populated before DMA has advanced from the base. Select the receive buffer size from the XSK pool even if no buffers were available at initialization.
--- .../ethernet/stmicro/stmmac/dwmac4_descs.c | 6 +++ .../ethernet/stmicro/stmmac/dwxgmac2_descs.c | 6 +++ .../net/ethernet/stmicro/stmmac/enh_desc.c | 6 +++ drivers/net/ethernet/stmicro/stmmac/hwif.h | 3 ++ .../net/ethernet/stmicro/stmmac/norm_desc.c | 6 +++ drivers/net/ethernet/stmicro/stmmac/stmmac.h | 2 + .../net/ethernet/stmicro/stmmac/stmmac_main.c | 49 +++++++++++++------ 7 files changed, 63 insertions(+), 15 deletions(-)
drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c +6 -0
@@ -176,6 +176,11 @@ static void dwmac4_set_tx_owner(struct dma_desc *p) p->des3 |=cpu_to_le32 (TDES3_OWN ); } +static void dwmac4_clear_rx_owner (struct dma_desc *p) +{ + p->des3 &=cpu_to_le32 (~RDES3_OWN ); +} +static void dwmac4_set_rx_owner (struct dma_desc *p,int disable_rx_ic) {u32 flags = (RDES3_OWN |RDES3_BUFFER1_VALID_ADDR );
@@ -539,6 +544,7 @@ const struct stmmac_desc_ops dwmac4_desc_ops = { .rx_status = dwmac4_wrback_get_rx_status, .set_tx_owner = dwmac4_set_tx_owner, .set_rx_owner = dwmac4_set_rx_owner, + .clear_rx_owner = dwmac4_clear_rx_owner, .get_rx_vlan_tci = dwmac4_wrback_get_rx_vlan_tci, .get_rx_vlan_valid = dwmac4_wrback_get_rx_vlan_valid, .get_rx_frame_len = dwmac4_wrback_get_rx_frame_len,
drivers/net/ethernet/stmicro/stmmac/dwxgmac2_descs.c +6 -0
@@ -51,6 +51,11 @@ static void dwxgmac2_set_tx_owner(struct dma_desc *p) p->des3 |=cpu_to_le32 (XGMAC_TDES3_OWN ); } +static void dwxgmac2_clear_rx_owner (struct dma_desc *p) +{ + p->des3 &=cpu_to_le32 (~XGMAC_RDES3_OWN ); +} +static void dwxgmac2_set_rx_owner (struct dma_desc *p,int disable_rx_ic) {u32 flags =XGMAC_RDES3_OWN ;
@@ -350,6 +355,7 @@ const struct stmmac_desc_ops dwxgmac210_desc_ops = { .rx_status = dwxgmac2_get_rx_status, .set_tx_owner = dwxgmac2_set_tx_owner, .set_rx_owner = dwxgmac2_set_rx_owner, + .clear_rx_owner = dwxgmac2_clear_rx_owner, .get_rx_vlan_tci = dwxgmac2_wrback_get_rx_vlan_tci, .get_rx_vlan_valid = dwxgmac2_wrback_get_rx_vlan_valid, .get_rx_frame_len = dwxgmac2_get_rx_frame_len,
drivers/net/ethernet/stmicro/stmmac/enh_desc.c +6 -0
@@ -278,6 +278,11 @@ static void enh_desc_set_tx_owner(struct dma_desc *p) p->des0 |=cpu_to_le32 (ETDES0_OWN ); } +static void enh_desc_clear_rx_owner (struct dma_desc *p) +{ + p->des0 &=cpu_to_le32 (~RDES0_OWN ); +} +static void enh_desc_set_rx_owner (struct dma_desc *p,int disable_rx_ic) { p->des0 |=cpu_to_le32 (RDES0_OWN );
@@ -439,6 +444,7 @@ const struct stmmac_desc_ops enh_desc_ops = { .set_tx_ic = enh_desc_set_tx_ic, .set_tx_owner = enh_desc_set_tx_owner, .set_rx_owner = enh_desc_set_rx_owner, + .clear_rx_owner = enh_desc_clear_rx_owner, .get_rx_frame_len = enh_desc_get_rx_frame_len, .rx_extended_status = enh_desc_get_ext_status, .enable_tx_timestamp = enh_desc_enable_tx_timestamp,
drivers/net/ethernet/stmicro/stmmac/hwif.h +3 -0
@@ -65,6 +65,7 @@ struct stmmac_desc_ops { struct dma_desc *p, void __iomem *ioaddr);/* Handle extra events on specific interrupts hw dependent */ void (*set_rx_owner)(struct dma_desc *p,int disable_rx_ic); +void (*clear_rx_owner)(struct dma_desc *p);/* Get the receive frame size */ int (*get_rx_frame_len)(struct dma_desc *p,int rx_coe_type);/* Return the reception status looking at the RDES1 */
@@ -121,6 +122,8 @@ struct stmmac_desc_ops { stmmac_do_callback(__priv, desc, get_rx_vlan_valid, __args) #define stmmac_tx_status(__priv, __args...) \ stmmac_do_callback(__priv, desc, tx_status, __args) +#define stmmac_clear_rx_owner(__priv, __args...) \ + stmmac_do_void_callback(__priv, desc, clear_rx_owner, __args) #define stmmac_set_rx_owner(__priv, __args...) \ stmmac_do_void_callback(__priv, desc, set_rx_owner, __args) #define stmmac_get_rx_frame_len(__priv, __args...) \
drivers/net/ethernet/stmicro/stmmac/norm_desc.c +6 -0
@@ -141,6 +141,11 @@ static void ndesc_set_tx_owner(struct dma_desc *p) p->des0 |=cpu_to_le32 (TDES0_OWN ); } +static void ndesc_clear_rx_owner (struct dma_desc *p) +{ + p->des0 &=cpu_to_le32 (~RDES0_OWN ); +} +static void ndesc_set_rx_owner (struct dma_desc *p,int disable_rx_ic) { p->des0 |=cpu_to_le32 (RDES0_OWN );
@@ -284,6 +289,7 @@ const struct stmmac_desc_ops ndesc_ops = { .set_tx_ic = ndesc_set_tx_ic, .set_tx_owner = ndesc_set_tx_owner, .set_rx_owner = ndesc_set_rx_owner, + .clear_rx_owner = ndesc_clear_rx_owner, .get_rx_frame_len = ndesc_get_rx_frame_len, .enable_tx_timestamp = ndesc_enable_tx_timestamp, .get_tx_timestamp_status = ndesc_get_tx_timestamp_status,
drivers/net/ethernet/stmicro/stmmac/stmmac.h +2 -0
@@ -128,6 +128,8 @@ struct stmmac_rx_queue {unsigned int cur_rx;unsigned int dirty_rx;unsigned int buf_alloc_num; +/* XSK descriptors waiting for refill, including a completely empty ring. */ +unsigned int xsk_rx_pending;unsigned int napi_skb_frag_size;dma_addr_t dma_rx_phy;unsigned int state_saved;
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +34 -15
139 lines not on this page · raw message
Signature · 1 line
2.34.1
PATCH v6 3/4 net: stmmac: restore RX descriptor buffer addresses on resume
In reply to Ding HuiFrom: Ding Hui <[email protected]>
Suspend disables NAPI before stopping RX DMA. Hardware can complete RX descriptors in between, overwriting GMAC4/XGMAC buffer addresses with writeback status. Resume currently rearms those descriptors without restoring their addresses, leading to a fatal bus error.
Share buffer preparation with the refill paths and restore addresses from attached buffers. Allocate missing primary and secondary pages independently with GFP_KERNEL. If allocation fails, return the error without restarting DMA and leave the device detached.
For XSK queues, restore a contiguous populated prefix and leave the rest CPU-owned in the pending refill region. Preserve attached buffers beyond the prefix for later refill. Recompute the initial tail and pending count rather than retaining the allocation count from open.
Rebuild chain pointers and discard partial receive state from before the DMA reset. Initialize RX descriptors after restoring their addresses, using the existing per-queue initializer to preserve the watchdog policy and legacy control fields. Keep the unpopulated XSK suffix CPU-owned when DMA restarts. This replaces the separate final ownership-setting loop.
Collect the resume work in stmmac_resume_descriptors(), with one loop over TX queues and one over RX queues. Free outstanding TX buffers before initializing each TX ring, and remove the now-unused all-queue TX wrapper. The RX rings no longer undergo initialization before address restoration.
Unlike the reverted commit 9c63faaa931e ("net: stmmac: re-init rx buffers when mac resume back"), retain attached buffers and their DMA mappings.
--- .../net/ethernet/stmicro/stmmac/stmmac_main.c | 225 +++++++++++++----- 1 file changed, 162 insertions(+), 63 deletions(-)
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +162 -63
@@ -1676,6 +1676,40 @@ static bool stmmac_rx_check_buf2_cap(struct stmmac_priv *priv)return priv->hw->desc && priv->hw->desc->set_sec_addr; } +static int stmmac_prepare_rx_buffer (struct stmmac_priv *priv, +struct stmmac_rx_queue *rx_q, +struct stmmac_rx_buffer *buf, +struct dma_desc *p,gfp_t flags) +{ +gfp_t gfp = flags; + +if (priv->dma_cap.host_dma_width <=32 ) + gfp |=GFP_DMA32 ; + +if (!buf->page) { + buf->page =page_pool_alloc_pages (rx_q->page_pool, gfp); +if (!buf->page) +return -ENOMEM ; + buf->page_offset =stmmac_rx_offset (priv); + } + +if (stmmac_rx_check_buf2_cap (priv) && !buf->sec_page) { + buf->sec_page =page_pool_alloc_pages (rx_q->page_pool, gfp); +if (!buf->sec_page) +return -ENOMEM ; + + buf->sec_addr =page_pool_get_dma_addr (buf->sec_page); + } + + buf->addr =page_pool_get_dma_addr (buf->page) + buf->page_offset; + +stmmac_set_desc_addr (priv, p, buf->addr); +stmmac_set_desc_sec_addr (priv, p, buf->sec_addr, +stmmac_rx_check_buf2_cap (priv)); + +return 0 ; +} +/** * stmmac_init_rx_buffers - init the RX descriptor buffer. * @priv: driver private structure
@@ -1694,32 +1728,104 @@ static int stmmac_init_rx_buffers(struct stmmac_priv *priv, {struct stmmac_rx_queue *rx_q = &dma_conf->rx_queue[queue];struct stmmac_rx_buffer *buf = &rx_q->buf_pool[i]; -gfp_t gfp = flags; +int ret; -if (priv->dma_cap.host_dma_width <=32 ) - gfp |=GFP_DMA32 ; + ret =stmmac_prepare_rx_buffer (priv, rx_q, buf, p, flags); +if (ret) +return ret; -if (!buf->page) { - buf->page =page_pool_alloc_pages (rx_q->page_pool, gfp); -if (!buf->page) +if (dma_conf->dma_buf_sz == BUF_SIZE_16KiB) +stmmac_init_desc3 (priv, p); + +return 0 ; +} + +static int stmmac_prepare_rx_buffer_zc (struct stmmac_priv *priv, +struct stmmac_rx_queue *rx_q, +struct stmmac_rx_buffer *buf, +struct dma_desc *p) +{ +if (!buf->xdp) { + buf->xdp =xsk_buff_alloc (rx_q->xsk_pool); +if (!buf->xdp)return -ENOMEM ; - buf->page_offset =stmmac_rx_offset (priv); } -if (stmmac_rx_check_buf2_cap (priv) && !buf->sec_page) { - buf->sec_page =page_pool_alloc_pages (rx_q->page_pool, gfp); -if (!buf->sec_page) -return -ENOMEM ; +stmmac_set_desc_addr (priv, p,xsk_buff_xdp_get_dma (buf->xdp)); +stmmac_set_desc_sec_addr (priv, p,0 , false); - buf->sec_addr =page_pool_get_dma_addr (buf->sec_page); -stmmac_set_desc_sec_addr (priv, p, buf->sec_addr, true); +return 0 ; +} + +/** +* stmmac_reinit_rx_descriptors - restore RX descriptors before restarting DMA +* @priv: driver private structure +* @dma_conf: DMA configuration +* @queue: RX queue index +* +* Restore addresses overwritten by hardware writeback, retaining attached +* buffers and allocating missing page_pool buffers with GFP_KERNEL. Keep +* descriptors CPU-owned until addresses and chain pointers are restored. +* +* For XSK, publish only the contiguous populated prefix. The remainder is +* left in the refill region, including any buffers already attached there, +* and can be populated by NAPI when userspace supplies more fill buffers. +* +* Return: 0 on success, or -ENOMEM if a required page cannot be allocated. +*/ +static int stmmac_reinit_rx_descriptors (struct stmmac_priv *priv, +struct stmmac_dma_conf *dma_conf, +u32 queue) +{ +struct stmmac_rx_queue *rx_q = &dma_conf->rx_queue[queue]; +struct dma_desc *p; +int i, ret; + +for (i =0 ; i < dma_conf->dma_rx_size; i++) { + p =stmmac_get_rx_desc (priv, rx_q, i); +stmmac_clear_rx_owner (priv, p); } - buf->addr =page_pool_get_dma_addr (buf->page) + buf->page_offset; + rx_q->buf_alloc_num =0 ; +for (i =0 ; i < dma_conf->dma_rx_size; i++) { +struct stmmac_rx_buffer *buf = &rx_q->buf_pool[i]; -stmmac_set_desc_addr (priv, p, buf->addr); -if (dma_conf->dma_buf_sz == BUF_SIZE_16KiB) -stmmac_init_desc3 (priv, p); + p =stmmac_get_rx_desc (priv, rx_q, i); +if (rx_q->xsk_pool) { + ret =stmmac_prepare_rx_buffer_zc (priv, rx_q, buf, p); +if (ret) +break ; + }else { + ret =stmmac_init_rx_buffers (priv, dma_conf, p, i, +GFP_KERNEL , queue); +if (ret) +return ret; + } + rx_q->buf_alloc_num++; + } + +/* Hardware timestamp writeback may have overwritten chain pointers. */ +if (priv->descriptor_mode ==STMMAC_CHAIN_MODE ) { +void *des = priv->extend_desc ? (void *)rx_q->dma_erx : + (void *)rx_q->dma_rx; + +stmmac_mode_init (priv, des, rx_q->dma_rx_phy, + dma_conf->dma_rx_size, priv->extend_desc); + } + +/* Discard a partially assembled frame from before the DMA reset. */ +if (rx_q->state_saved && !rx_q->xsk_pool) +dev_kfree_skb_any (rx_q->state.skb); + rx_q->state_saved = false; + rx_q->rx_count_frames =0 ; +stmmac_reset_rx_queue (priv, queue); + +/* Initialize control fields and publish ownership only after restoring +* addresses and chain pointers. DMA is stopped; initialization also +* clears OWN again for the unpopulated XSK suffix before DMA restarts. +*/ +dma_wmb (); +stmmac_clear_rx_descriptors (priv, dma_conf, queue);return 0 ; }
@@ -2156,16 +2262,37 @@ static void dma_free_tx_skbufs(struct stmmac_priv *priv, }/** -* stmmac_free_tx_skbufs - free TX skb buffers -* @priv: private structure +* stmmac_resume_descriptors - prepare TX and RX rings before restarting DMA +* @priv: driver private structure +* +* Release outstanding TX buffers before initializing each TX ring. Restore +* RX buffer addresses before initializing RX descriptors and their ownership. +* All DMA channels must be stopped throughout this operation. +* +* Return: 0 on success, or a negative errno if RX restoration fails. */ -static void stmmac_free_tx_skbufs (struct stmmac_priv *priv) +static int stmmac_resume_descriptors (struct stmmac_priv *priv) { -u8 tx_queue_cnt = priv->plat->tx_queues_to_use; -u8 queue; +struct stmmac_dma_conf *dma_conf = &priv->dma_conf; +u32 queue; +int ret; -for (queue =0 ; queue < tx_queue_cnt; queue++) -dma_free_tx_skbufs (priv, &priv->dma_conf, queue); +for (queue =0 ; queue < priv->plat->tx_queues_to_use; queue++) { +stmmac_reset_tx_queue (priv, queue); +dma_free_tx_skbufs (priv, dma_conf, queue); +stmmac_clear_tx_descriptors (priv, dma_conf, queue); + } + +for (queue =0 ; queue < priv->plat->rx_queues_to_use; queue++) { + ret =stmmac_reinit_rx_descriptors (priv, dma_conf, queue); +if (ret) { +netdev_err (priv->dev,"Failed to restore RX queue %u: %d\n" , + queue, ret); +return ret; + } + } + +return 0 ; }/**
@@ -5151,10 +5278,6 @@ static inline void stmmac_rx_refill(struct stmmac_priv *priv, u32 queue)struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[queue];int dirty =stmmac_rx_dirty (priv, queue);unsigned int entry = rx_q->dirty_rx; -gfp_t gfp = (GFP_ATOMIC | __GFP_NOWARN); - -if (priv->dma_cap.host_dma_width <=32 ) - gfp |=GFP_DMA32 ;while (dirty-- >0 ) {struct stmmac_rx_buffer *buf = &rx_q->buf_pool[entry];
@@ -5163,25 +5286,9 @@ static inline void stmmac_rx_refill(struct stmmac_priv *priv, u32 queue) p =stmmac_get_rx_desc (priv, rx_q, entry); -if (!buf->page) { - buf->page =page_pool_alloc_pages (rx_q->page_pool, gfp); -if (!buf->page) -break ; - } - -if (stmmac_rx_check_buf2_cap (priv) && !buf->sec_page) { - buf->sec_page =page_pool_alloc_pages (rx_q->page_pool, gfp); -if (!buf->sec_page) -break ; - - buf->sec_addr =page_pool_get_dma_addr (buf->sec_page); - } - - buf->addr =page_pool_get_dma_addr (buf->page) + buf->page_offset; - -stmmac_set_desc_addr (priv, p, buf->addr); -stmmac_set_desc_sec_addr (priv, p, buf->sec_addr, -stmmac_rx_check_buf2_cap (priv)); +if (stmmac_prepare_rx_buffer (priv, rx_q, buf, p, +GFP_ATOMIC | __GFP_NOWARN)) +break ;stmmac_refill_desc3 (priv, rx_q, p); use_rx_wd = !stmmac_rx_need_ic (priv, rx_q, queue);
@@ -5584,22 +5691,15 @@ static bool stmmac_rx_refill_zc(struct stmmac_priv *priv, u32 queue, u32 budget)while (budget-- >0 ) {struct stmmac_rx_buffer *buf = &rx_q->buf_pool[entry]; -dma_addr_t dma_addr; +struct dma_desc *p =stmmac_get_rx_desc (priv, rx_q, entry);bool use_rx_wd; -if (!buf->xdp) { - buf->xdp =xsk_buff_alloc (rx_q->xsk_pool); -if (!buf->xdp) { - ret = false; -break ; - } +if (stmmac_prepare_rx_buffer_zc (priv, rx_q, buf, p)) { + ret = false; +break ; } - rx_desc =stmmac_get_rx_desc (priv, rx_q, entry); - - dma_addr =xsk_buff_xdp_get_dma (buf->xdp); -stmmac_set_desc_addr (priv, rx_desc, dma_addr); -stmmac_set_desc_sec_addr (priv, rx_desc,0 , false); + rx_desc = p;stmmac_refill_desc3 (priv, rx_q, rx_desc); use_rx_wd = !stmmac_rx_need_ic (priv, rx_q, queue);
@@ -8517,10 +8617,9 @@ int stmmac_resume(struct device *dev)mutex_lock (&priv->lock); -stmmac_reset_queues_param (priv); - -stmmac_free_tx_skbufs (priv); -stmmac_clear_descriptors (priv, &priv->dma_conf); + ret =stmmac_resume_descriptors (priv); +if (ret) + goto error_unlock; ret =stmmac_hw_setup (ndev);if (ret <0 ) {
Signature · 1 line
2.34.1
PATCH v6 4/4 net: stmmac: restore the XSK TX pool on resume
In reply to Ding HuiFrom: Ding Hui <[email protected]>
When suspend interrupts AF_XDP zero-copy transmission, resume releases outstanding TX buffers through dma_free_tx_skbufs(). If it completes XSK frames, that helper also clears tx_q->xsk_pool even though the socket remains bound to the queue.
The resume path does not run the TX ring allocation routine that normally sets this pointer. Consequently, stmmac_tx_clean() skips XSK transmission and a running TX-only socket can stop sending after resume, despite the link coming back up.
Restore the TX pool from the queue's existing XSK binding after releasing TX buffers and before restarting DMA and NAPI. Keep the buffer cleanup helper's behavior for teardown unchanged.
--- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +3 -0
@@ -2280,6 +2280,9 @@ static int stmmac_resume_descriptors(struct stmmac_priv *priv)for (queue =0 ; queue < priv->plat->tx_queues_to_use; queue++) {stmmac_reset_tx_queue (priv, queue);dma_free_tx_skbufs (priv, dma_conf, queue); +/* Buffer cleanup may clear the pool; the socket remains bound. */ + dma_conf->tx_queue[queue].xsk_pool = +stmmac_get_xsk_pool (priv, queue);stmmac_clear_tx_descriptors (priv, dma_conf, queue); }
Signature · 1 line
2.34.1