From dfb787f7d157f97ba91344b584d33481f572530e Mon Sep 17 00:00:00 2001 From: Meghana Malladi Date: Fri, 12 Jun 2026 00:27:41 +0530 Subject: net: ti: icssg-prueth: Fix AF_XDP fill ring alloc and wakeup condition emac_rx_packet_zc() calls prueth_rx_alloc_zc() with count (frames received in the current NAPI poll) as the allocation budget. Two problems arise from this: 1. When the CPPI5 descriptor pool is exhausted (avail_desc == 0, FDQ already holds the maximum number of descriptors), count > 0 still triggers allocation attempts that all fail, spamming the kernel log with "rx push: failed to allocate descriptor" at high packet rates. 2. The XSK wakeup condition "ret < count" is wrong when avail_desc is zero: ret == 0 and count can be up to 64, so the condition is always true. This causes ~200 spurious ndo_xsk_wakeup() calls per second even when the FDQ is already full, wasting CPU cycles in repeated NAPI invocations that process zero frames. Fix both by introducing alloc_budget = min(budget, avail_desc): - When avail_desc == 0 no allocation is attempted, avoiding pool exhaustion errors. The wakeup condition "ret < alloc_budget" evaluates to 0 < 0 == false, correctly clearing the wakeup flag so the hardware IRQ re-arms NAPI without spurious kicks. - In steady state avail_desc == count <= budget, so alloc_budget == count and behaviour is unchanged. - After a dry-ring stall (count == 0, avail_desc > 0), alloc_budget > 0 causes new descriptors to be posted to the FDQ so the hardware can resume receiving immediately. Fixes: 7a64bb388df3 ("net: ti: icssg-prueth: Add AF_XDP zero copy for RX") Signed-off-by: Meghana Malladi Link: https://patch.msgid.link/20260611185744.2498070-2-m-malladi@ti.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/ti/icssg/icssg_common.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/ti/icssg/icssg_common.c b/drivers/net/ethernet/ti/icssg/icssg_common.c index a28a608f9bf4..55a696912811 100644 --- a/drivers/net/ethernet/ti/icssg/icssg_common.c +++ b/drivers/net/ethernet/ti/icssg/icssg_common.c @@ -927,6 +927,7 @@ static int emac_rx_packet_zc(struct prueth_emac *emac, u32 flow_id, struct cppi5_host_desc_t *desc_rx; struct prueth_swdata *swdata; dma_addr_t desc_dma, buf_dma; + int avail_desc, alloc_budget; struct xdp_buff *xdp; int xdp_status = 0; int count = 0; @@ -993,16 +994,13 @@ static int emac_rx_packet_zc(struct prueth_emac *emac, u32 flow_id, if (xdp_status & ICSSG_XDP_REDIR) xdp_do_flush(); - /* Allocate xsk buffers from the pool for the "count" number of - * packets processed in order to be able to receive more packets. - */ - ret = prueth_rx_alloc_zc(emac, count); + avail_desc = k3_cppi_desc_pool_avail(rx_chn->desc_pool); + alloc_budget = min_t(int, budget, avail_desc); + + ret = prueth_rx_alloc_zc(emac, alloc_budget); if (xsk_uses_need_wakeup(rx_chn->xsk_pool)) { - /* If the user space doesn't provide enough buffers then it must - * explicitly wake up the kernel when new buffers are available - */ - if (ret < count) + if (ret < alloc_budget) xsk_set_rx_need_wakeup(rx_chn->xsk_pool); else xsk_clear_rx_need_wakeup(rx_chn->xsk_pool); -- cgit v1.2.3 From bcbf73d98195577a89e788179843f6d0c66244a5 Mon Sep 17 00:00:00 2001 From: Meghana Malladi Date: Fri, 12 Jun 2026 00:27:42 +0530 Subject: net: ti: icssg: Use undirected TX tag for native XDP in HSR offload mode emac_xmit_xdp_frame() always sets the CPPI5 descriptor destination tag to emac->port_id, which directs the PRU firmware to transmit the frame on that specific slave port only. In HSR offload mode this bypasses the firmware's HSR duplication logic: the frame goes out on one ring leg and never appears on the other, breaking HSR redundancy for XDP_TX paths. icssg_ndo_start_xmit() already handles this correctly: when HSR offload mode is active and NETIF_F_HW_HSR_DUP is set it substitutes PRUETH_UNDIRECTED_PKT_DST_TAG (port 0) so the PRU duplicates the frame to both slave ports. It also sets PRUETH_UNDIRECTED_PKT_TAG_INS in epib[1] when NETIF_F_HW_HSR_TAG_INS is set so the PRU inserts the HSR sequence tag, which XDP_TX frames lack (the tag is stripped by the PRU on RX before the frame reaches the XDP program). Apply the same logic in emac_xmit_xdp_frame() so XDP_TX frames in HSR mode are treated identically to skb TX via hsr0. Fixes: 62aa3246f462 ("net: ti: icssg-prueth: Add XDP support") Signed-off-by: Meghana Malladi Link: https://patch.msgid.link/20260611185744.2498070-3-m-malladi@ti.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/ti/icssg/icssg_common.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/ti/icssg/icssg_common.c b/drivers/net/ethernet/ti/icssg/icssg_common.c index 55a696912811..ede32f266729 100644 --- a/drivers/net/ethernet/ti/icssg/icssg_common.c +++ b/drivers/net/ethernet/ti/icssg/icssg_common.c @@ -696,6 +696,7 @@ u32 emac_xmit_xdp_frame(struct prueth_emac *emac, dma_addr_t desc_dma, buf_dma; struct prueth_swdata *swdata; struct page *page; + u32 dst_tag_id; u32 *epib; int ret; @@ -737,9 +738,25 @@ u32 emac_xmit_xdp_frame(struct prueth_emac *emac, /* set dst tag to indicate internal qid at the firmware which is at * bit8..bit15. bit0..bit7 indicates port num for directed - * packets in case of switch mode operation + * packets in case of switch mode operation and port num 0 + * for undirected packets in case of HSR offload mode. + * + * XDP_TX frames arrive on a slave port with the HSR tag already + * stripped by the PRU firmware. Like skb TX via hsr0, they must + * be sent as undirected so the PRU duplicates them to both ports + * and re-inserts the HSR sequence tag. */ - cppi5_desc_set_tags_ids(&first_desc->hdr, 0, (emac->port_id | (q_idx << 8))); + dst_tag_id = emac->port_id | (q_idx << 8); + + if (emac->prueth->is_hsr_offload_mode && + (ndev->features & NETIF_F_HW_HSR_DUP)) + dst_tag_id = PRUETH_UNDIRECTED_PKT_DST_TAG; + + if (emac->prueth->is_hsr_offload_mode && + (ndev->features & NETIF_F_HW_HSR_TAG_INS)) + epib[1] |= PRUETH_UNDIRECTED_PKT_TAG_INS; + + cppi5_desc_set_tags_ids(&first_desc->hdr, 0, dst_tag_id); k3_udma_glue_tx_dma_to_cppi5_addr(tx_chn->tx_chn, &buf_dma); cppi5_hdesc_attach_buf(first_desc, buf_dma, xdpf->len, buf_dma, xdpf->len); swdata = cppi5_hdesc_get_swdata(first_desc); -- cgit v1.2.3 From f9691288413ceb4fc72f3ccc4d8e42adf66eb28d Mon Sep 17 00:00:00 2001 From: Meghana Malladi Date: Fri, 12 Jun 2026 00:27:43 +0530 Subject: net: ti: icssg: Use undirected TX tag for XDP zero copy in HSR offload mode emac_xsk_xmit_zc() has the same issue as the fixed emac_xmit_xdp_frame(): it always sets the CPPI5 descriptor destination tag to emac->port_id, which directs the PRU firmware to transmit on only one slave port in HSR mode, breaking redundancy. Apply the same fix: in HSR offload mode when NETIF_F_HW_HSR_DUP is set, use PRUETH_UNDIRECTED_PKT_DST_TAG (port 0) so the PRU duplicates frames to both ports. Also set PRUETH_UNDIRECTED_PKT_TAG_INS when NETIF_F_HW_HSR_TAG_INS is set so the PRU re-inserts the HSR sequence tag that was stripped by the PRU on RX before the XDP program saw the frame. This ensures XSK XDP_TX frames in HSR mode are treated identically to skb TX via hsr0. Fixes: 8756ef2eb078 ("net: ti: icssg-prueth: Add AF_XDP zero copy for TX") Signed-off-by: Meghana Malladi Link: https://patch.msgid.link/20260611185744.2498070-4-m-malladi@ti.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/ti/icssg/icssg_common.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/ti/icssg/icssg_common.c b/drivers/net/ethernet/ti/icssg/icssg_common.c index ede32f266729..82ddef9c17d5 100644 --- a/drivers/net/ethernet/ti/icssg/icssg_common.c +++ b/drivers/net/ethernet/ti/icssg/icssg_common.c @@ -105,6 +105,7 @@ static int emac_xsk_xmit_zc(struct prueth_emac *emac, struct xdp_desc xdp_desc; int num_tx = 0, pkt_len; int descs_avail, ret; + u32 dst_tag_id; u32 *epib; int i; @@ -137,9 +138,17 @@ static int emac_xsk_xmit_zc(struct prueth_emac *emac, epib[0] = 0; epib[1] = 0; cppi5_hdesc_set_pktlen(host_desc, pkt_len); - cppi5_desc_set_tags_ids(&host_desc->hdr, 0, - (emac->port_id | (q_idx << 8))); + dst_tag_id = emac->port_id | (q_idx << 8); + + if (emac->prueth->is_hsr_offload_mode && + (ndev->features & NETIF_F_HW_HSR_DUP)) + dst_tag_id = PRUETH_UNDIRECTED_PKT_DST_TAG; + + if (emac->prueth->is_hsr_offload_mode && + (ndev->features & NETIF_F_HW_HSR_TAG_INS)) + epib[1] |= PRUETH_UNDIRECTED_PKT_TAG_INS; + cppi5_desc_set_tags_ids(&host_desc->hdr, 0, dst_tag_id); k3_udma_glue_tx_dma_to_cppi5_addr(tx_chn->tx_chn, &dma_buf); cppi5_hdesc_attach_buf(host_desc, dma_buf, pkt_len, dma_buf, pkt_len); -- cgit v1.2.3