igc_clean_rx_irq() strips IGC_TS_HDR_LEN whenever a descriptor reports IGC_RXDADV_STAT_TSIP. For multi-buffer packets, continuation descriptors retain TSIP even though the inline timestamp is present only in the first RX buffer. Subtracting the header length from each continuation buffer truncates jumbo packets by 16 bytes per continuation and leaves the packet length larger than the received data. Only consume the timestamp header when skb is NULL, which identifies the first buffer of a new packet. An skb carried in rx_ring->skb remains non-NULL when packet assembly resumes in a later NAPI poll. Link: https://lore.kernel.org/all/20260625-igb-rx-ts-fix-v3-1-99b3efa08dca@aweta.nl/ Fixes: e1ed4f92a625 ("igc: Refactor Rx timestamp handling") Cc: stable@vger.kernel.org Signed-off-by: Paul Moses
Reviewed-by: Aleksandr Loktionov
---
drivers/net/ethernet/intel/igc/igc.h | 1 +
drivers/net/ethernet/intel/igc/igc_main.c | 33 +++++++++++++++++------
drivers/net/ethernet/intel/igc/igc_xdp.c | 11 +++++---
3 files changed, 33 insertions(+), 12 deletions(-)
diff --git a/drivers/net/ethernet/intel/igc/igc.h b/drivers/net/ethernet/intel/igc/igc.h
index 17f213cc9..ad1062f85 100644
--- a/drivers/net/ethernet/intel/igc/igc.h
+++ b/drivers/net/ethernet/intel/igc/igc.h
@@ -765,6 +765,7 @@ static inline s32 igc_read_phy_reg(struct igc_hw *hw, u32 offset, u16 *data)
return -EOPNOTSUPP;
}
+void igc_set_rlpml(struct igc_adapter *adapter);
void igc_reinit_locked(struct igc_adapter *);
struct igc_nfc_rule *igc_get_nfc_rule(struct igc_adapter *adapter,
u32 location);
diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c
index 41b293dc1..6b418dc71 100644
--- a/drivers/net/ethernet/intel/igc/igc_main.c
+++ b/drivers/net/ethernet/intel/igc/igc_main.c
@@ -674,8 +674,11 @@ static void igc_configure_rx_ring(struct igc_adapter *adapter,
ring->next_to_clean = 0;
ring->next_to_use = 0;
+ /* igc's XDP limits MTU to 1500; all XSK RX buffers can use 2kb;
+ * RLPML limits the receive length to fit after UMEM headroom.
+ */
if (ring->xsk_pool)
- buf_size = xsk_pool_get_rx_frame_size(ring->xsk_pool);
+ buf_size = IGC_RXBUFFER_2048;
else if (ring_uses_large_buffer(ring))
buf_size = IGC_RXBUFFER_3072;
else
@@ -830,6 +833,25 @@ static void igc_setup_mrqc(struct igc_adapter *adapter)
wr32(IGC_MRQC, mrqc);
}
+void igc_set_rlpml(struct igc_adapter *adapter)
+{
+ struct igc_hw *hw = &adapter->hw;
+ u32 rlpml = MAX_JUMBO_FRAME_SIZE;
+
+#if (PAGE_SIZE < 8192)
+ if (adapter->max_frame_size <= IGC_MAX_FRAME_BUILD_SKB)
+ rlpml = IGC_MAX_FRAME_BUILD_SKB;
+#endif
+ /* igc's XDP currently does not support jumbo frames. Limit the
+ * accepted packet size regardless of PAGE_SIZE so it fits in a 2kb
+ * XSK chunk.
+ */
+ if (igc_xdp_is_enabled(adapter))
+ rlpml = ETH_FRAME_LEN + VLAN_HLEN * 2 + ETH_FCS_LEN;
+
+ wr32(IGC_RLPML, rlpml);
+}
+
/**
* igc_setup_rctl - configure the receive control registers
* @adapter: Board private structure
@@ -874,6 +896,7 @@ static void igc_setup_rctl(struct igc_adapter *adapter)
IGC_RCTL_CFIEN); /* Disable VLAN CFIEN Filter */
}
+ igc_set_rlpml(adapter);
wr32(IGC_RCTL, rctl);
}
@@ -4117,7 +4140,7 @@ static void igc_set_rx_mode(struct net_device *netdev)
{
struct igc_adapter *adapter = netdev_priv(netdev);
struct igc_hw *hw = &adapter->hw;
- u32 rctl = 0, rlpml = MAX_JUMBO_FRAME_SIZE;
+ u32 rctl = 0;
int count;
/* Check for Promiscuous and All Multicast modes */
@@ -4147,12 +4170,6 @@ static void igc_set_rx_mode(struct net_device *netdev)
/* update state of unicast and multicast */
rctl |= rd32(IGC_RCTL) & ~(IGC_RCTL_UPE | IGC_RCTL_MPE);
wr32(IGC_RCTL, rctl);
-
-#if (PAGE_SIZE < 8192)
- if (adapter->max_frame_size <= IGC_MAX_FRAME_BUILD_SKB)
- rlpml = IGC_MAX_FRAME_BUILD_SKB;
-#endif
- wr32(IGC_RLPML, rlpml);
}
/**
diff --git a/drivers/net/ethernet/intel/igc/igc_xdp.c b/drivers/net/ethernet/intel/igc/igc_xdp.c
index 9eb47b4be..a0f1ecb2e 100644
--- a/drivers/net/ethernet/intel/igc/igc_xdp.c
+++ b/drivers/net/ethernet/intel/igc/igc_xdp.c
@@ -34,6 +34,8 @@ int igc_xdp_set_prog(struct igc_adapter *adapter, struct bpf_prog *prog,
}
old_prog = xchg(&adapter->xdp_prog, prog);
+ if (if_running && need_update)
+ igc_set_rlpml(adapter);
if (old_prog)
bpf_prog_put(old_prog);
@@ -69,11 +71,12 @@ static int igc_xdp_enable_pool(struct igc_adapter *adapter,
return -EINVAL;
frame_size = xsk_pool_get_rx_frame_size(pool);
- if (frame_size < ETH_FRAME_LEN + VLAN_HLEN * 2) {
+ if (frame_size < ETH_FRAME_LEN + VLAN_HLEN * 2 +
+ ETH_FCS_LEN + IGC_TS_HDR_LEN) {
/* When XDP is enabled, the driver doesn't support frames that
- * span over multiple buffers. To avoid that, we check if xsk
- * frame size is big enough to fit the max ethernet frame size
- * + vlan double tagging.
+ * span multiple buffers. Check the maximum supported MTU, not
+ * current MTU, as it may change while the pool is bound. Account
+ * for double VLAN tags, FCS and inline RX timestamping.
*/
return -EOPNOTSUPP;
}
--
2.56.GIT