mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [RFC net-next 0/5] r8169: RSS for the RTL8125B
@ 2026-11-11 22:01 Vlad Banea
  2026-11-11 22:01 ` [RFC net-next 1/5] r8169: recheck the TX descriptor after a vector-map interrupt Vlad Banea
                   ` (4 more replies)
  0 siblings, 5 replies; 6+ messages in thread
From: Vlad Banea @ 2026-11-11 22:01 UTC (permalink / raw)
  To: netdev
  Cc: hkallweit1, javen_xu, nic_swsd, andrew+netdev, davem, edumazet,
	kuba, pabeni, linux-kernel

Enable RSS on the RTL8125B (RTL_GIGA_MAC_VER_63) using the vector-map
interrupt model and multi-queue support added for the RTL8127A.

Patch 1 fixes a race in the vector-map TX path: the TX interrupt can
arrive before the descriptor write-back is visible, so the end of a
burst stays unreaped until BQL stops the queue and the watchdog fires.
The fix copies Realtek's driver: read a register and look at the
descriptor again. I don't know whether the register read is needed or a
short delay would do; I followed the vendor. The vendor driver does the
same on the RX path, but I could not reproduce a stranded RX descriptor,
so I left RX out.

I found the race on the RTL8125B with this series and have no RTL8127A
to test. Javen, is the RTL8127A affected? If so, I will send patch 1 to
net separately.

Patches 2-3 make the vector layout, the RSS hash types and the RX
descriptor type per chip, with no functional change. Patch 4 adds the
32-byte "type 3" RX descriptor that the RTL8125B needs for RSS. Patch 5
enables four RSS queues on the RTL8125B.

Thanks to Javen Xu for confirming the RTL8125B's vector layout and
descriptor requirements.

Tested with two RTL8125B on x86_64 (KVM, VFIO passthrough) and RISC-V
(SpacemiT K1): traffic spreads over four RX queues and link changes
arrive on vector 21; x86_64 runs at line rate both ways. Confirmed that
without patch 1, we get TX timeouts with bursty TCP traffic, and no
timeouts with the patch.

Open question: the RTL8125B can stop receiving when its RX ring runs
dry, until RxOverflow is cleared in IntrStatus ("r8169: enable the
RxOverflow interrupt again"). The vector-map handler never touches
IntrStatus. I could not run the ring dry in testing; does this mode need
the same handling?

Vlad Banea (5):
  r8169: recheck the TX descriptor after a vector-map interrupt
  r8169: describe the vector-map interrupt layout per chip
  r8169: make the RSS hash types and descriptor type per chip
  r8169: add the type 3 RX descriptor
  r8169: enable RSS on the RTL8125B

 drivers/net/ethernet/realtek/r8169_main.c | 309 +++++++++++++++++-----
 1 file changed, 241 insertions(+), 68 deletions(-)


base-commit: 368fbf5d82da9ebce309449c74fc0b128f7d0219
-- 
2.53.0


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [RFC net-next 1/5] r8169: recheck the TX descriptor after a vector-map interrupt
  2026-11-11 22:01 [RFC net-next 0/5] r8169: RSS for the RTL8125B Vlad Banea
@ 2026-11-11 22:01 ` Vlad Banea
  2026-11-11 22:01 ` [RFC net-next 2/5] r8169: describe the vector-map interrupt layout per chip Vlad Banea
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Vlad Banea @ 2026-11-11 22:01 UTC (permalink / raw)
  To: netdev
  Cc: hkallweit1, javen_xu, nic_swsd, andrew+netdev, davem, edumazet,
	kuba, pabeni, linux-kernel

With the vector-map interrupt model the TX interrupt can arrive before
the descriptor write-back is visible. rtl_tx() then stops at a
descriptor that still looks owned, and the end of a burst stays
unreaped. Once the BQL limit drops below the stranded bytes, the queue
stops and the watchdog resets the chip.

The legacy handler reads the interrupt status register before the poll
runs; the vector-map handler only writes registers. Do as Realtek's
driver does: if the first pending descriptor still looks owned, read a
register and look again.

Fixes: 677f8f8c4c5f ("r8169: add support for new interrupt mapping")
Signed-off-by: Vlad Banea <montrealtango@gmail.com>
---
 drivers/net/ethernet/realtek/r8169_main.c | 16 ++++++++++++++--
 1 file changed, 14 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c
index cd4ebc654dd0..6bd137358d1f 100644
--- a/drivers/net/ethernet/realtek/r8169_main.c
+++ b/drivers/net/ethernet/realtek/r8169_main.c
@@ -5228,6 +5228,7 @@ static void rtl_tx(struct net_device *dev, struct rtl8169_private *tp,
 		   int budget)
 {
 	unsigned int dirty_tx, bytes_compl = 0, pkts_compl = 0;
+	bool recheck = tp->irq_nvecs > 1;
 	struct sk_buff *skb;
 
 	dirty_tx = tp->dirty_tx;
@@ -5237,8 +5238,19 @@ static void rtl_tx(struct net_device *dev, struct rtl8169_private *tp,
 		u32 status;
 
 		status = le32_to_cpu(READ_ONCE(tp->TxDescArray[entry].opts1));
-		if (status & DescOwn)
-			break;
+		if (status & DescOwn) {
+			/* The vector-map TX interrupt can arrive before the
+			 * descriptor write-back is visible. Read a register and
+			 * look again, as Realtek's driver does.
+			 */
+			if (!recheck)
+				break;
+			recheck = false;
+			RTL_R8(tp, IMR_CLEAR_VEC_MAP_REG);
+			status = le32_to_cpu(READ_ONCE(tp->TxDescArray[entry].opts1));
+			if (status & DescOwn)
+				break;
+		}
 
 		skb = tp->tx_skb[entry].skb;
 		rtl8169_unmap_tx_skb(tp, entry);
-- 
2.53.0


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [RFC net-next 2/5] r8169: describe the vector-map interrupt layout per chip
  2026-11-11 22:01 [RFC net-next 0/5] r8169: RSS for the RTL8125B Vlad Banea
  2026-11-11 22:01 ` [RFC net-next 1/5] r8169: recheck the TX descriptor after a vector-map interrupt Vlad Banea
@ 2026-11-11 22:01 ` Vlad Banea
  2026-11-11 22:01 ` [RFC net-next 3/5] r8169: make the RSS hash types and descriptor type " Vlad Banea
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Vlad Banea @ 2026-11-11 22:01 UTC (permalink / raw)
  To: netdev
  Cc: hkallweit1, javen_xu, nic_swsd, andrew+netdev, davem, edumazet,
	kuba, pabeni, linux-kernel

The vector-map interrupt model hard-codes the RTL8127A's MSI-X layout.
Other chips put the TX and link change vectors elsewhere, so move the
layout into a per-chip struct rtl_vec_map.

No functional change.

Signed-off-by: Vlad Banea <montrealtango@gmail.com>
---
 drivers/net/ethernet/realtek/r8169_main.c | 79 ++++++++++++++---------
 1 file changed, 48 insertions(+), 31 deletions(-)

diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c
index 6bd137358d1f..a77bbedc8c02 100644
--- a/drivers/net/ethernet/realtek/r8169_main.c
+++ b/drivers/net/ethernet/realtek/r8169_main.c
@@ -81,8 +81,6 @@
 #define R8169_MAX_RX_QUEUES	8
 #define R8169_DEFAULT_RX_QUEUES	1
 #define R8169_MAX_TX_QUEUES	1
-#define R8127_MAX_NUM_IRQVEC	32
-#define R8127_MIN_NUM_IRQVEC	30
 #define R8169_IRQ_DEFAULT	1
 #define RTL_RSS_KEY_SIZE	40
 #define RSS_CPU_NUM_MASK	GENMASK(18, 16)
@@ -489,7 +487,6 @@ enum rtl8125_registers {
 	IMR_SET_VEC_MAP_REG	= 0x0d0c,
 };
 
-#define MSIX_ID_VEC_MAP_LINKCHG	29
 #define LEDSEL_MASK_8125	0x23f
 
 #define RX_VLAN_INNER_8125	BIT(22)
@@ -623,9 +620,6 @@ enum rtl_register_content {
 
 	/* magic enable v2 */
 	MagicPacket_v2	= (1 << 16),	/* Wake up when receives a Magic Packet */
-#define	ISRIMR_LINKCHG	BIT(29)
-#define	ISRIMR_TOK_Q0	BIT(8)
-#define	ISRIMR_ROK_Q0	BIT(0)
 #define RTL_DESC_TYPE_CTRL		0xd8
 #define RSS_KEY_REG			0x4600
 #define RSS_INDIRECTION_TBL_REG		0x4700
@@ -843,6 +837,23 @@ enum rtl_sfp_mode {
 	RTL_SFP_8127_ATF,
 };
 
+/* Vector-map MSI-X layout. RX queue N uses vector N; a source's bit in
+ * the vector-map IMR/ISR registers is its vector number.
+ */
+struct rtl_vec_map {
+	u8 tx;		/* TX completion */
+	u8 linkchg;	/* link change */
+	u8 min_nvecs;	/* vectors that must be allocated */
+	u8 max_nvecs;
+};
+
+static const struct rtl_vec_map rtl_vec_map_8127 = {
+	.tx		= 8,
+	.linkchg	= 29,
+	.min_nvecs	= 30,
+	.max_nvecs	= 32,
+};
+
 struct rtl8169_rss_data {
 	u8 rss_key[RTL_RSS_KEY_SIZE];
 	u8 rss_indir_tbl[RTL_MAX_INDIRECTION_TABLE_ENTRIES];
@@ -871,6 +882,7 @@ struct rtl8169_private {
 	unsigned int hw_supp_num_rx_queues;
 	struct rtl8169_rss_data *rss_data;
 	unsigned int irq_nvecs;
+	const struct rtl_vec_map *vec_map;	/* NULL: single vector only */
 	enum rx_desc_type init_rx_desc_type;
 	struct clk *clk;
 	int speed;
@@ -4755,7 +4767,7 @@ static void rtl8169_napi_disable(struct rtl8169_private *tp)
 	if (tp->irq_nvecs > 1) {
 		for (int i = 0; i < tp->num_rx_rings; i++)
 			napi_disable(&tp->rtl8169_napi[i]);
-		napi_disable(&tp->rtl8169_napi[R8169_MAX_RX_QUEUES]);
+		napi_disable(&tp->rtl8169_napi[tp->vec_map->tx]);
 	} else {
 		napi_disable(&tp->rtl8169_napi[0]);
 	}
@@ -4766,7 +4778,7 @@ static void rtl8169_napi_enable(struct rtl8169_private *tp)
 	if (tp->irq_nvecs > 1) {
 		for (int i = 0; i < tp->num_rx_rings; i++)
 			napi_enable(&tp->rtl8169_napi[i]);
-		napi_enable(&tp->rtl8169_napi[R8169_MAX_RX_QUEUES]);
+		napi_enable(&tp->rtl8169_napi[tp->vec_map->tx]);
 	} else {
 		napi_enable(&tp->rtl8169_napi[0]);
 	}
@@ -5535,9 +5547,9 @@ static void rtl8169_free_one_irq(struct rtl8169_private *tp, int i)
 	napi = &tp->rtl8169_napi[i];
 
 	if (tp->irq_nvecs > 1) {
-		if (i < tp->num_rx_rings || i == R8169_MAX_RX_QUEUES)
+		if (i < tp->num_rx_rings || i == tp->vec_map->tx)
 			free_irq(irq, napi);
-		else if (i == MSIX_ID_VEC_MAP_LINKCHG)
+		else if (i == tp->vec_map->linkchg)
 			free_irq(irq, tp);
 	} else {
 		free_irq(irq, napi);
@@ -5591,7 +5603,7 @@ static irqreturn_t rtl8169_interrupt_other(int irq, void *dev_instance)
 {
 	struct rtl8169_private *tp = dev_instance;
 
-	rtl8169_clear_hw_isr(tp, MSIX_ID_VEC_MAP_LINKCHG);
+	rtl8169_clear_hw_isr(tp, tp->vec_map->linkchg);
 	if (tp->phydev)
 		phy_mac_interrupt(tp->phydev);
 	else if (tp->sfp_mode)
@@ -5615,11 +5627,11 @@ static int rtl8169_request_irq(struct rtl8169_private *tp)
 		irq = pci_irq_vector(pdev, i);
 
 		if (tp->irq_nvecs > 1) {
-			/* RX: 0~7, TX: 8*/
-			if (i < tp->num_rx_rings || i == R8169_MAX_RX_QUEUES)
+			/* RX queue N on vector N, TX and link at vec_map */
+			if (i < tp->num_rx_rings || i == tp->vec_map->tx)
 				rc = request_irq(irq, rtl8169_interrupt_msix,
 						 irqflags, dev->name, napi);
-			else if (i == MSIX_ID_VEC_MAP_LINKCHG)
+			else if (i == tp->vec_map->linkchg)
 				rc = request_irq(irq, rtl8169_interrupt_other,
 						 irqflags, dev->name, tp);
 			else
@@ -5805,7 +5817,7 @@ static void rtl8169_netpoll(struct net_device *dev)
 	if (tp->irq_nvecs > 1) {
 		for (int i = 0; i < tp->num_rx_rings; i++)
 			rtl8169_interrupt_msix(0, &tp->rtl8169_napi[i]);
-		rtl8169_interrupt_msix(0, &tp->rtl8169_napi[R8169_MAX_RX_QUEUES]);
+		rtl8169_interrupt_msix(0, &tp->rtl8169_napi[tp->vec_map->tx]);
 	} else {
 		rtl8169_interrupt(0, &tp->rtl8169_napi[0]);
 	}
@@ -6034,7 +6046,7 @@ static void r8169_free_napi(struct rtl8169_private *tp)
 	if (tp->irq_nvecs > 1) {
 		for (int i = 0; i < tp->num_rx_rings; i++)
 			netif_napi_del(&tp->rtl8169_napi[i]);
-		netif_napi_del(&tp->rtl8169_napi[R8169_MAX_RX_QUEUES]);
+		netif_napi_del(&tp->rtl8169_napi[tp->vec_map->tx]);
 	} else {
 		netif_napi_del(&tp->rtl8169_napi[0]);
 	}
@@ -6091,9 +6103,9 @@ static const struct net_device_ops rtl_netdev_ops = {
 static void rtl_set_irq_mask(struct rtl8169_private *tp)
 {
 	if (tp->irq_nvecs > 1) {
-		tp->irq_mask = ISRIMR_LINKCHG | ISRIMR_TOK_Q0;
+		tp->irq_mask = BIT(tp->vec_map->linkchg) | BIT(tp->vec_map->tx);
 		for (int i = 0; i < tp->num_rx_rings; i++)
-			tp->irq_mask |= ISRIMR_ROK_Q0 << i;
+			tp->irq_mask |= BIT(i);
 	} else {
 		tp->irq_mask = RxOK | RxErr | TxOK | TxErr | LinkChg;
 
@@ -6102,18 +6114,24 @@ static void rtl_set_irq_mask(struct rtl8169_private *tp)
 	}
 }
 
+static const struct rtl_vec_map *rtl_get_vec_map(struct rtl8169_private *tp)
+{
+	switch (tp->mac_version) {
+	case RTL_GIGA_MAC_VER_80:
+		return &rtl_vec_map_8127;
+	default:
+		return NULL;
+	}
+}
+
 static int get_max_irq_nvecs(struct rtl8169_private *tp)
 {
-	if (tp->mac_version == RTL_GIGA_MAC_VER_80)
-		return R8127_MAX_NUM_IRQVEC;
-	return R8169_IRQ_DEFAULT;
+	return tp->vec_map ? tp->vec_map->max_nvecs : R8169_IRQ_DEFAULT;
 }
 
 static int get_min_irq_nvecs(struct rtl8169_private *tp)
 {
-	if (tp->mac_version == RTL_GIGA_MAC_VER_80)
-		return R8127_MIN_NUM_IRQVEC;
-	return R8169_IRQ_DEFAULT;
+	return tp->vec_map ? tp->vec_map->min_nvecs : R8169_IRQ_DEFAULT;
 }
 
 static void rtl8169_set_rx_ring_num(struct rtl8169_private *tp)
@@ -6727,10 +6745,8 @@ static int rtl8169_poll_msix_tx(struct napi_struct *napi, int budget)
 	return 0;
 }
 
-/* RTL8127 MSI-X vector layout:
- * Vectors 0 .. (MAX_RXQ - 1)			: Rx Queues
- * Vectors MAX_RXQ .. (MAX_RXQ + MAX_TXQ - 1)	: Tx Queues
- * NAPI is only allocated for data path
+/* Vector-map MSI-X: RX queue N on vector N, TX and link change on the
+ * chip's vec_map vectors. NAPI is only allocated for the data path.
  */
 static void r8169_init_napi(struct rtl8169_private *tp)
 {
@@ -6744,10 +6760,10 @@ static void r8169_init_napi(struct rtl8169_private *tp)
 					   pci_irq_vector(tp->pci_dev, i));
 		}
 		netif_napi_add_tx(tp->dev,
-				  &tp->rtl8169_napi[R8169_MAX_RX_QUEUES],
+				  &tp->rtl8169_napi[tp->vec_map->tx],
 				  rtl8169_poll_msix_tx);
-		netif_napi_set_irq(&tp->rtl8169_napi[R8169_MAX_RX_QUEUES],
-				   pci_irq_vector(tp->pci_dev, R8169_MAX_RX_QUEUES));
+		netif_napi_set_irq(&tp->rtl8169_napi[tp->vec_map->tx],
+				   pci_irq_vector(tp->pci_dev, tp->vec_map->tx));
 	} else {
 		netif_napi_add(tp->dev, &tp->rtl8169_napi[0], rtl8169_poll);
 		netif_napi_set_irq(&tp->rtl8169_napi[0],
@@ -6913,6 +6929,7 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 	rtl_hw_reset(tp);
 
 	rtl_setup_rx_params(tp);
+	tp->vec_map = rtl_get_vec_map(tp);
 
 	rc = rtl_alloc_irq(tp);
 	if (rc < 0)
-- 
2.53.0


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [RFC net-next 3/5] r8169: make the RSS hash types and descriptor type per chip
  2026-11-11 22:01 [RFC net-next 0/5] r8169: RSS for the RTL8125B Vlad Banea
  2026-11-11 22:01 ` [RFC net-next 1/5] r8169: recheck the TX descriptor after a vector-map interrupt Vlad Banea
  2026-11-11 22:01 ` [RFC net-next 2/5] r8169: describe the vector-map interrupt layout per chip Vlad Banea
@ 2026-11-11 22:01 ` Vlad Banea
  2026-11-11 22:01 ` [RFC net-next 4/5] r8169: add the type 3 RX descriptor Vlad Banea
  2026-11-11 22:01 ` [RFC net-next 5/5] r8169: enable RSS on the RTL8125B Vlad Banea
  4 siblings, 0 replies; 6+ messages in thread
From: Vlad Banea @ 2026-11-11 22:01 UTC (permalink / raw)
  To: netdev
  Cc: hkallweit1, javen_xu, nic_swsd, andrew+netdev, davem, edumazet,
	kuba, pabeni, linux-kernel

The RSS hash types and the RX descriptor type used with RSS are those of
the RTL8127A. Make both per chip, set in rtl_setup_rx_params().

No functional change.

Signed-off-by: Vlad Banea <montrealtango@gmail.com>
---
 drivers/net/ethernet/realtek/r8169_main.c | 29 +++++++++++++----------
 1 file changed, 17 insertions(+), 12 deletions(-)

diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c
index a77bbedc8c02..cc253728109c 100644
--- a/drivers/net/ethernet/realtek/r8169_main.c
+++ b/drivers/net/ethernet/realtek/r8169_main.c
@@ -858,6 +858,7 @@ struct rtl8169_rss_data {
 	u8 rss_key[RTL_RSS_KEY_SIZE];
 	u8 rss_indir_tbl[RTL_MAX_INDIRECTION_TABLE_ENTRIES];
 	unsigned int hw_supp_indir_tbl_entries;
+	u32 hash_types;		/* RSS_CTRL_*_SUPP bits to hash on */
 };
 
 struct rtl8169_private {
@@ -884,6 +885,7 @@ struct rtl8169_private {
 	unsigned int irq_nvecs;
 	const struct rtl_vec_map *vec_map;	/* NULL: single vector only */
 	enum rx_desc_type init_rx_desc_type;
+	enum rx_desc_type rss_desc_type;	/* layout used with RSS on */
 	struct clk *clk;
 	int speed;
 
@@ -2906,6 +2908,15 @@ static void rtl_setup_rx_params(struct rtl8169_private *tp)
 	case RTL_GIGA_MAC_VER_80:
 		tp->hw_supp_num_rx_queues = R8169_MAX_RX_QUEUES;
 		tp->rss_data->hw_supp_indir_tbl_entries = RTL_MAX_INDIRECTION_TABLE_ENTRIES;
+		tp->rss_data->hash_types = RSS_CTRL_TCP_IPV4_SUPP |
+					   RSS_CTRL_IPV4_SUPP |
+					   RSS_CTRL_IPV6_SUPP |
+					   RSS_CTRL_IPV6_EXT_SUPP |
+					   RSS_CTRL_TCP_IPV6_SUPP |
+					   RSS_CTRL_TCP_IPV6_EXT_SUPP |
+					   RSS_CTRL_UDP_IPV4_SUPP |
+					   RSS_CTRL_UDP_IPV6_SUPP;
+		tp->rss_desc_type = RX_DESC_TYPE_RSS;
 		break;
 	default:
 		tp->hw_supp_num_rx_queues = R8169_DEFAULT_RX_QUEUES;
@@ -3066,14 +3077,7 @@ static void rtl8169_set_rss_hash_opt(struct rtl8169_private *tp)
 	rss_ctrl = FIELD_PREP(RSS_CPU_NUM_MASK, ilog2(tp->num_rx_rings));
 
 	/* Perform hash on these packet types */
-	rss_ctrl |= RSS_CTRL_TCP_IPV4_SUPP |
-		    RSS_CTRL_IPV4_SUPP |
-		    RSS_CTRL_IPV6_SUPP |
-		    RSS_CTRL_IPV6_EXT_SUPP |
-		    RSS_CTRL_TCP_IPV6_SUPP |
-		    RSS_CTRL_TCP_IPV6_EXT_SUPP |
-		    RSS_CTRL_UDP_IPV4_SUPP |
-		    RSS_CTRL_UDP_IPV6_SUPP;
+	rss_ctrl |= tp->rss_data->hash_types;
 
 	rss_ctrl |= FIELD_PREP(RSS_HASH_MASK,
 			       ilog2(tp->rss_data->hw_supp_indir_tbl_entries));
@@ -4272,11 +4276,12 @@ static void rtl_hw_start_8125_common(struct rtl8169_private *tp)
 	    tp->mac_version == RTL_GIGA_MAC_VER_80)
 		RTL_W8(tp, 0xD8, RTL_R8(tp, 0xD8) & ~0x02);
 
-	/* enable rx descriptor type v4 and set queue num for rss */
+	/* set queue num for rss and enable its rx descriptor type */
 	if (tp->num_rx_rings > 1) {
 		rtl8125_set_rx_q_num(tp);
-		RTL_W8(tp, RTL_DESC_TYPE_CTRL,
-		       RTL_R8(tp, RTL_DESC_TYPE_CTRL) | RTL_DESC_TYPE_RSS);
+		if (tp->init_rx_desc_type == RX_DESC_TYPE_RSS)
+			RTL_W8(tp, RTL_DESC_TYPE_CTRL,
+			       RTL_R8(tp, RTL_DESC_TYPE_CTRL) | RTL_DESC_TYPE_RSS);
 	}
 
 	if (tp->mac_version == RTL_GIGA_MAC_VER_80)
@@ -6142,7 +6147,7 @@ static void rtl8169_set_rx_ring_num(struct rtl8169_private *tp)
 		tp->num_rx_rings = rounddown_pow_of_two(min(rss_queue_num,
 							    tp->hw_supp_num_rx_queues));
 		if (tp->num_rx_rings >= 2)
-			tp->init_rx_desc_type = RX_DESC_TYPE_RSS;
+			tp->init_rx_desc_type = tp->rss_desc_type;
 	}
 }
 
-- 
2.53.0


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [RFC net-next 4/5] r8169: add the type 3 RX descriptor
  2026-11-11 22:01 [RFC net-next 0/5] r8169: RSS for the RTL8125B Vlad Banea
                   ` (2 preceding siblings ...)
  2026-11-11 22:01 ` [RFC net-next 3/5] r8169: make the RSS hash types and descriptor type " Vlad Banea
@ 2026-11-11 22:01 ` Vlad Banea
  2026-11-11 22:01 ` [RFC net-next 5/5] r8169: enable RSS on the RTL8125B Vlad Banea
  4 siblings, 0 replies; 6+ messages in thread
From: Vlad Banea @ 2026-11-11 22:01 UTC (permalink / raw)
  To: netdev
  Cc: hkallweit1, javen_xu, nic_swsd, andrew+netdev, davem, edumazet,
	kuba, pabeni, linux-kernel

The RTL8125A/B family has a 32-byte RX descriptor ("type 3" in Realtek's
driver), which the RTL8125B requires with RSS. Its second half is laid
out like RX_DESC_TYPE_RSS, so add RX_DESC_TYPE_V3 as a 16-byte header
followed by a struct RxDesc and reuse the RSS accessors.

Differences from RX_DESC_TYPE_RSS:
 - FirstFrag/LastFrag at bits 25/24 and RES/RUNT/RWT/CRC at 20-17 of
   opts1;
 - one checksum flag per protocol in opts2, and only the matching
   protocol's failure flag is valid;
 - the RSS hash in rss_result, its type in hdr_info;
 - selected by RxConfig bit 24, set before the receiver is enabled.

No chip uses it yet.

Signed-off-by: Vlad Banea <montrealtango@gmail.com>
---
 drivers/net/ethernet/realtek/r8169_main.c | 158 +++++++++++++++++++---
 1 file changed, 136 insertions(+), 22 deletions(-)

diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c
index cc253728109c..85e2c03fa61d 100644
--- a/drivers/net/ethernet/realtek/r8169_main.c
+++ b/drivers/net/ethernet/realtek/r8169_main.c
@@ -75,7 +75,6 @@
 #define NUM_TX_DESC	256	/* Number of Tx descriptor registers */
 #define NUM_RX_DESC	256	/* Number of Rx descriptor registers */
 #define R8169_TX_RING_BYTES	(NUM_TX_DESC * sizeof(struct TxDesc))
-#define R8169_RX_RING_BYTES	(NUM_RX_DESC * sizeof(struct RxDesc))
 #define R8169_TX_STOP_THRS	(MAX_SKB_FRAGS + 1)
 #define R8169_TX_START_THRS	(2 * R8169_TX_STOP_THRS)
 #define R8169_MAX_RX_QUEUES	8
@@ -492,6 +491,26 @@ enum rtl8125_registers {
 #define RX_VLAN_INNER_8125	BIT(22)
 #define RX_VLAN_OUTER_8125	BIT(23)
 #define RX_VLAN_8125		(RX_VLAN_INNER_8125 | RX_VLAN_OUTER_8125)
+#define RX_DESC_V3_8125		BIT(24)	/* type 3 (32-byte) RX descriptors */
+
+/* RX_DESC_TYPE_V3 status bits, opts1 unless noted */
+#define RX_FIRST_FRAG_V3	BIT(25)
+#define RX_LAST_FRAG_V3		BIT(24)
+#define RX_RES_V3		BIT(20)
+#define RX_RUNT_V3		BIT(19)
+#define RX_RWT_V3		BIT(18)
+#define RX_CRC_V3		BIT(17)
+#define RX_UDPT_V3		BIT(29)	/* opts2: UDP packet */
+#define RX_TCPT_V3		BIT(28)	/* opts2: TCP packet */
+#define RX_IPF_V3		BIT(26)	/* opts2: IP checksum failed */
+#define RX_UDPF_V3		BIT(25)	/* opts2: UDP checksum failed */
+#define RX_TCPF_V3		BIT(24)	/* opts2: TCP checksum failed */
+#define RXS_RSS_UDP_V3		BIT(9)	/* hdr_info */
+#define RXS_RSS_IPV4_V3		BIT(10)
+#define RXS_RSS_IPV6_V3		BIT(12)
+#define RXS_RSS_TCP_V3		BIT(13)
+#define RXS_RSS_L3_V3		(RXS_RSS_IPV4_V3 | RXS_RSS_IPV6_V3)
+#define RXS_RSS_L4_V3		(RXS_RSS_TCP_V3 | RXS_RSS_UDP_V3)
 
 #define RX_FETCH_DFLT_8125	(8 << 27)
 
@@ -740,6 +759,19 @@ struct RxDesc {
 	};
 };
 
+/* 32-byte RX descriptor of the RTL8125A/B family ("type 3") */
+struct RxDescV3 {
+	__le32 rsv1;
+	__le32 rsv2;
+	__le32 rss_result;
+	__le16 hdr_buf_len;
+	__le16 hdr_info;
+	struct RxDesc desc;
+};
+
+static_assert(sizeof(struct RxDesc) == 16);
+static_assert(sizeof(struct RxDescV3) == 32);
+
 struct ring_info {
 	struct sk_buff	*skb;
 	u32		len;
@@ -812,6 +844,7 @@ enum rtl_dash_type {
 enum rx_desc_type {
 	RX_DESC_TYPE_DEFAULT,
 	RX_DESC_TYPE_RSS,
+	RX_DESC_TYPE_V3,	/* 32-byte struct RxDescV3 */
 };
 
 struct rtl8169_rx_ring {
@@ -2112,6 +2145,7 @@ static void rtl8169_rx_vlan_tag(struct rtl8169_private *tp,
 
 	switch (tp->init_rx_desc_type) {
 	case RX_DESC_TYPE_RSS:
+	case RX_DESC_TYPE_V3:
 		opts2 = le32_to_cpu(desc->rss_opts2);
 		break;
 	default:
@@ -2817,7 +2851,9 @@ static void rtl_init_rxcfg(struct rtl8169_private *tp)
 		break;
 	case RTL_GIGA_MAC_VER_63 ... RTL_GIGA_MAC_VER_LAST:
 		RTL_W32(tp, RxConfig, RX_FETCH_DFLT_8125 | RX_DMA_BURST |
-			RX_PAUSE_SLOT_ON);
+			RX_PAUSE_SLOT_ON |
+			(tp->init_rx_desc_type == RX_DESC_TYPE_V3 ?
+			 RX_DESC_V3_8125 : 0));
 		break;
 	default:
 		RTL_W32(tp, RxConfig, RX128_INT_EN | RX_DMA_BURST);
@@ -2825,12 +2861,36 @@ static void rtl_init_rxcfg(struct rtl8169_private *tp)
 	}
 }
 
+/* RX_DESC_TYPE_RSS and RX_DESC_TYPE_V3 share the address/opts2/opts1 order */
+static bool rtl8169_rx_desc_rss_layout(struct rtl8169_private *tp)
+{
+	return tp->init_rx_desc_type != RX_DESC_TYPE_DEFAULT;
+}
+
+static size_t rtl8169_rx_ring_bytes(struct rtl8169_private *tp)
+{
+	if (tp->init_rx_desc_type == RX_DESC_TYPE_V3)
+		return NUM_RX_DESC * sizeof(struct RxDescV3);
+
+	return NUM_RX_DESC * sizeof(struct RxDesc);
+}
+
+static struct RxDesc *rtl8169_rx_desc(struct rtl8169_private *tp,
+				      struct rtl8169_rx_ring *ring,
+				      unsigned int index)
+{
+	if (tp->init_rx_desc_type == RX_DESC_TYPE_V3)
+		return &((struct RxDescV3 *)ring->rx_desc_array)[index].desc;
+
+	return &ring->rx_desc_array[index];
+}
+
 static void rtl8169_rx_desc_init(struct rtl8169_private *tp)
 {
 	for (int i = 0; i < tp->num_rx_rings; i++) {
 		struct rtl8169_rx_ring *ring = &tp->rx_ring[i];
 
-		memset(ring->rx_desc_array, 0x0, R8169_RX_RING_BYTES);
+		memset(ring->rx_desc_array, 0x0, rtl8169_rx_ring_bytes(tp));
 	}
 }
 
@@ -4533,6 +4593,9 @@ static void rtl_hw_start(struct  rtl8169_private *tp)
 	/* Initially a 10 us delay. Turned it into a PCI commit. - FR */
 	rtl_pci_commit(tp);
 
+	/* Select the 32-byte descriptor before the receiver is enabled */
+	if (tp->init_rx_desc_type == RX_DESC_TYPE_V3)
+		rtl_init_rxcfg(tp);
 	RTL_W8(tp, ChipCmd, CmdTxEnb | CmdRxEnb);
 	rtl_init_rxcfg(tp);
 	rtl_set_tx_config_registers(tp);
@@ -4570,6 +4633,7 @@ static void rtl8169_mark_to_asic(struct rtl8169_private *tp, struct RxDesc *desc
 
 	switch (tp->init_rx_desc_type) {
 	case RX_DESC_TYPE_RSS:
+	case RX_DESC_TYPE_V3:
 		eor = le32_to_cpu(desc->rss_opts1) & RingEnd;
 		desc->rss_opts2 = cpu_to_le32(0);
 		/* Force memory writes to complete before releasing descriptor */
@@ -4589,7 +4653,7 @@ static void rtl8169_mark_to_asic(struct rtl8169_private *tp, struct RxDesc *desc
 static struct page *rtl8169_alloc_rx_data(struct rtl8169_private *tp,
 					  struct rtl8169_rx_ring *ring, unsigned int index)
 {
-	struct RxDesc *desc = ring->rx_desc_array + index;
+	struct RxDesc *desc = rtl8169_rx_desc(tp, ring, index);
 	struct device *d = tp_to_dev(tp);
 	int node = dev_to_node(d);
 	dma_addr_t mapping;
@@ -4607,7 +4671,7 @@ static struct page *rtl8169_alloc_rx_data(struct rtl8169_private *tp,
 	}
 
 	ring->rx_buf_dma_addr[index] = mapping;
-	if (tp->init_rx_desc_type == RX_DESC_TYPE_RSS)
+	if (rtl8169_rx_desc_rss_layout(tp))
 		desc->rss_addr = cpu_to_le64(mapping);
 	else
 		desc->addr = cpu_to_le64(mapping);
@@ -4619,6 +4683,7 @@ static struct page *rtl8169_alloc_rx_data(struct rtl8169_private *tp,
 static void rtl8169_rx_clear(struct rtl8169_private *tp,
 			     struct rtl8169_rx_ring *ring)
 {
+	struct RxDesc *desc;
 	int i;
 
 	for (i = 0; i < NUM_RX_DESC && ring->rx_databuff[i]; i++) {
@@ -4628,12 +4693,13 @@ static void rtl8169_rx_clear(struct rtl8169_private *tp,
 		__free_pages(ring->rx_databuff[i], get_order(R8169_RX_BUF_SIZE));
 		ring->rx_databuff[i] = NULL;
 		ring->rx_buf_dma_addr[i] = 0;
-		if (tp->init_rx_desc_type == RX_DESC_TYPE_RSS) {
-			ring->rx_desc_array[i].rss_addr = 0;
-			ring->rx_desc_array[i].rss_opts1 = 0;
+		desc = rtl8169_rx_desc(tp, ring, i);
+		if (rtl8169_rx_desc_rss_layout(tp)) {
+			desc->rss_addr = 0;
+			desc->rss_opts1 = 0;
 		} else {
-			ring->rx_desc_array[i].addr = 0;
-			ring->rx_desc_array[i].opts1 = 0;
+			desc->addr = 0;
+			desc->opts1 = 0;
 		}
 	}
 }
@@ -4642,6 +4708,7 @@ static void rtl8169_mark_as_last_descriptor(struct rtl8169_private *tp, struct R
 {
 	switch (tp->init_rx_desc_type) {
 	case RX_DESC_TYPE_RSS:
+	case RX_DESC_TYPE_V3:
 		desc->rss_opts1 |= cpu_to_le32(RingEnd);
 		break;
 	default:
@@ -4666,7 +4733,7 @@ static int rtl8169_rx_fill(struct rtl8169_private *tp, struct rtl8169_rx_ring *r
 	}
 
 	/* mark as last descriptor in the ring */
-	rtl8169_mark_as_last_descriptor(tp, &ring->rx_desc_array[NUM_RX_DESC - 1]);
+	rtl8169_mark_as_last_descriptor(tp, rtl8169_rx_desc(tp, ring, NUM_RX_DESC - 1));
 
 	return 0;
 }
@@ -4679,7 +4746,7 @@ static int rtl8169_alloc_rx_desc(struct rtl8169_private *tp)
 	for (int i = 0; i < tp->num_rx_rings; i++) {
 		ring = &tp->rx_ring[i];
 		ring->rx_desc_array = dma_alloc_coherent(&pdev->dev,
-							 R8169_RX_RING_BYTES,
+							 rtl8169_rx_ring_bytes(tp),
 							 &ring->rx_phy_addr,
 							 GFP_KERNEL);
 		if (!ring->rx_desc_array)
@@ -4697,7 +4764,7 @@ static void rtl8169_free_rx_desc(struct rtl8169_private *tp)
 		ring = &tp->rx_ring[i];
 		if (ring->rx_desc_array) {
 			dma_free_coherent(&pdev->dev,
-					  R8169_RX_RING_BYTES,
+					  rtl8169_rx_ring_bytes(tp),
 					  ring->rx_desc_array,
 					  ring->rx_phy_addr);
 			ring->rx_desc_array = NULL;
@@ -4832,11 +4899,12 @@ static void rtl8169_rx_desc_reset(struct rtl8169_private *tp)
 		struct rtl8169_rx_ring *ring = &tp->rx_ring[i];
 
 		for (int j = 0; j < NUM_RX_DESC; j++) {
+			struct RxDesc *desc = rtl8169_rx_desc(tp, ring, j);
 			dma_addr_t phy_addr = ring->rx_buf_dma_addr[j];
 
-			if (tp->init_rx_desc_type == RX_DESC_TYPE_RSS)
-				ring->rx_desc_array[j].rss_addr = cpu_to_le64(phy_addr);
-			rtl8169_mark_to_asic(tp, ring->rx_desc_array + j);
+			if (rtl8169_rx_desc_rss_layout(tp))
+				desc->rss_addr = cpu_to_le64(phy_addr);
+			rtl8169_mark_to_asic(tp, desc);
 		}
 	}
 }
@@ -5300,9 +5368,13 @@ static void rtl_tx(struct net_device *dev, struct rtl8169_private *tp,
 	}
 }
 
-static inline int rtl8169_fragmented_frame(u32 status)
+static inline int rtl8169_fragmented_frame(struct rtl8169_private *tp,
+					   u32 status)
 {
-	return (status & (FirstFrag | LastFrag)) != (FirstFrag | LastFrag);
+	u32 frags = tp->init_rx_desc_type == RX_DESC_TYPE_V3 ?
+		    RX_FIRST_FRAG_V3 | RX_LAST_FRAG_V3 : FirstFrag | LastFrag;
+
+	return (status & frags) != frags;
 }
 
 static void rtl8169_rx_hash(struct rtl8169_private *tp,
@@ -5315,6 +5387,20 @@ static void rtl8169_rx_hash(struct rtl8169_private *tp,
 	if (!(tp->dev->features & NETIF_F_RXHASH))
 		return;
 
+	if (tp->init_rx_desc_type == RX_DESC_TYPE_V3) {
+		const struct RxDescV3 *v3 = container_of(desc, struct RxDescV3,
+							 desc);
+
+		rss_header_info = le16_to_cpu(v3->hdr_info);
+		if (!(rss_header_info & RXS_RSS_L3_V3))
+			return;
+
+		skb_set_hash(skb, le32_to_cpu(v3->rss_result),
+			     (rss_header_info & RXS_RSS_L4_V3) ?
+			     PKT_HASH_TYPE_L4 : PKT_HASH_TYPE_L3);
+		return;
+	}
+
 	rss_header_info = le32_to_cpu(desc->rss_dword.rss_info);
 
 	if (!(rss_header_info & RXS_RSS_L3_TYPE_MASK))
@@ -5329,11 +5415,23 @@ static void rtl8169_rx_hash(struct rtl8169_private *tp,
 
 static void rtl8169_rx_csum(struct rtl8169_private *tp,
 			    struct sk_buff *skb,
+			    struct RxDesc *desc,
 			    u32 opts1)
 {
 	bool csum_ok = false;
+	u32 opts2;
 
 	switch (tp->init_rx_desc_type) {
+	case RX_DESC_TYPE_V3:
+		/* The chip also sets the failure flag of the other
+		 * protocol (a TCP frame carries UDPF); check only the
+		 * matching one.
+		 */
+		opts2 = le32_to_cpu(desc->rss_opts2);
+		if (((opts2 & RX_TCPT_V3) && !(opts2 & (RX_TCPF_V3 | RX_IPF_V3))) ||
+		    ((opts2 & RX_UDPT_V3) && !(opts2 & (RX_UDPF_V3 | RX_IPF_V3))))
+			csum_ok = true;
+		break;
 	case RX_DESC_TYPE_RSS:
 		if (((opts1 & RX_TCPT_DESC_RSS) && !(opts1 & RX_TCPF_DESC_RSS)) ||
 		    ((opts1 & RX_UDPT_DESC_RSS) && !(opts1 & RX_UDPF_DESC_RSS)))
@@ -5358,6 +5456,7 @@ static __le32 rtl8169_rx_desc_opts1(struct rtl8169_private *tp, struct RxDesc *d
 {
 	switch (tp->init_rx_desc_type) {
 	case RX_DESC_TYPE_RSS:
+	case RX_DESC_TYPE_V3:
 		return READ_ONCE(desc->rss_opts1);
 	default:
 		return READ_ONCE(desc->opts1);
@@ -5369,6 +5468,17 @@ static bool rtl8169_check_rx_desc_error(struct rtl8169_rx_ring *ring,
 					u32 status)
 {
 	switch (tp->init_rx_desc_type) {
+	case RX_DESC_TYPE_V3:
+		if (unlikely(status & RX_RES_V3)) {
+			u64_stats_update_begin(&ring->stats.syncp);
+			if (status & (RX_RWT_V3 | RX_RUNT_V3))
+				ring->stats.rx_length_errors++;
+			if (status & RX_CRC_V3)
+				ring->stats.rx_crc_errors++;
+			u64_stats_update_end(&ring->stats.syncp);
+			return true;
+		}
+		break;
 	case RX_DESC_TYPE_RSS:
 		if (unlikely(status & RX_RES_RSS)) {
 			u64_stats_update_begin(&ring->stats.syncp);
@@ -5407,7 +5517,7 @@ static int rtl_rx(struct net_device *dev, struct rtl8169_private *tp,
 
 	for (count = 0; count < budget; count++, ring->cur_rx++) {
 		unsigned int pkt_size, entry = ring->cur_rx % NUM_RX_DESC;
-		struct RxDesc *desc = ring->rx_desc_array + entry;
+		struct RxDesc *desc = rtl8169_rx_desc(tp, ring, entry);
 		struct sk_buff *skb;
 		const void *rx_buf;
 		dma_addr_t addr;
@@ -5437,6 +5547,10 @@ static int rtl_rx(struct net_device *dev, struct rtl8169_private *tp,
 			if (tp->init_rx_desc_type == RX_DESC_TYPE_DEFAULT) {
 				if (status & RxRWT || !(status & (RxRUNT | RxCRC)))
 					goto release_descriptor;
+			} else if (tp->init_rx_desc_type == RX_DESC_TYPE_V3) {
+				if (status & RX_RWT_V3 ||
+				    !(status & (RX_RUNT_V3 | RX_CRC_V3)))
+					goto release_descriptor;
 			} else {
 				if (!(status & (RXRUNT_RSS | RXCRC_RSS)))
 					goto release_descriptor;
@@ -5454,7 +5568,7 @@ static int rtl_rx(struct net_device *dev, struct rtl8169_private *tp,
 		/* The driver does not support incoming fragmented frames.
 		 * They are seen as a symptom of over-mtu sized frames.
 		 */
-		if (unlikely(rtl8169_fragmented_frame(status))) {
+		if (unlikely(rtl8169_fragmented_frame(tp, status))) {
 			u64_stats_update_begin(&ring->stats.syncp);
 			ring->stats.rx_dropped++;
 			ring->stats.rx_length_errors++;
@@ -5484,7 +5598,7 @@ static int rtl_rx(struct net_device *dev, struct rtl8169_private *tp,
 			rtl8169_rx_hash(tp, desc, skb);
 			skb_record_rx_queue(skb, ring - tp->rx_ring);
 		}
-		rtl8169_rx_csum(tp, skb, status);
+		rtl8169_rx_csum(tp, skb, desc, status);
 		skb->protocol = eth_type_trans(skb, dev);
 
 		rtl8169_rx_vlan_tag(tp, desc, skb);
@@ -5499,7 +5613,7 @@ static int rtl_rx(struct net_device *dev, struct rtl8169_private *tp,
 
 		dev_sw_netstats_rx_add(dev, pkt_size);
 release_descriptor:
-		if (tp->init_rx_desc_type == RX_DESC_TYPE_RSS)
+		if (rtl8169_rx_desc_rss_layout(tp))
 			desc->rss_addr = cpu_to_le64(ring->rx_buf_dma_addr[entry]);
 		rtl8169_mark_to_asic(tp, desc);
 	}
-- 
2.53.0


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [RFC net-next 5/5] r8169: enable RSS on the RTL8125B
  2026-11-11 22:01 [RFC net-next 0/5] r8169: RSS for the RTL8125B Vlad Banea
                   ` (3 preceding siblings ...)
  2026-11-11 22:01 ` [RFC net-next 4/5] r8169: add the type 3 RX descriptor Vlad Banea
@ 2026-11-11 22:01 ` Vlad Banea
  4 siblings, 0 replies; 6+ messages in thread
From: Vlad Banea @ 2026-11-11 22:01 UTC (permalink / raw)
  To: netdev
  Cc: hkallweit1, javen_xu, nic_swsd, andrew+netdev, davem, edumazet,
	kuba, pabeni, linux-kernel

The RTL8125B has four RSS queues with the vector-map interrupt model:
RX queue N on vector N, TX on 16, link change on 21, and at least 22
vectors. RSS requires the type 3 descriptor. The RTL8125A has neither,
so enable this for RTL_GIGA_MAC_VER_63 only.

Hash on TCP and IP only: the RTL8125B does not spread UDP flows by port.

Signed-off-by: Vlad Banea <montrealtango@gmail.com>
---
 drivers/net/ethernet/realtek/r8169_main.c | 27 ++++++++++++++++++++++-
 1 file changed, 26 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c
index 85e2c03fa61d..a313216998d2 100644
--- a/drivers/net/ethernet/realtek/r8169_main.c
+++ b/drivers/net/ethernet/realtek/r8169_main.c
@@ -78,6 +78,7 @@
 #define R8169_TX_STOP_THRS	(MAX_SKB_FRAGS + 1)
 #define R8169_TX_START_THRS	(2 * R8169_TX_STOP_THRS)
 #define R8169_MAX_RX_QUEUES	8
+#define R8125B_MAX_RX_QUEUES	4
 #define R8169_DEFAULT_RX_QUEUES	1
 #define R8169_MAX_TX_QUEUES	1
 #define R8169_IRQ_DEFAULT	1
@@ -880,6 +881,13 @@ struct rtl_vec_map {
 	u8 max_nvecs;
 };
 
+static const struct rtl_vec_map rtl_vec_map_8125b = {
+	.tx		= 16,
+	.linkchg	= 21,
+	.min_nvecs	= 22,
+	.max_nvecs	= 32,
+};
+
 static const struct rtl_vec_map rtl_vec_map_8127 = {
 	.tx		= 8,
 	.linkchg	= 29,
@@ -1835,7 +1843,8 @@ static enum rtl_sfp_mode rtl_get_sfp_mode(struct rtl8169_private *tp)
 
 static bool rtl_hw_support_rss(struct rtl8169_private *tp)
 {
-	return tp->mac_version == RTL_GIGA_MAC_VER_80;
+	return tp->mac_version == RTL_GIGA_MAC_VER_63 ||
+	       tp->mac_version == RTL_GIGA_MAC_VER_80;
 }
 
 static enum rtl_dash_type rtl_get_dash_type(struct rtl8169_private *tp)
@@ -2965,6 +2974,20 @@ static void rtl_setup_rx_params(struct rtl8169_private *tp)
 {
 	tp->num_rx_rings = 1;
 	switch (tp->mac_version) {
+	case RTL_GIGA_MAC_VER_63:
+		/* The UDP hash types do not spread UDP flows by port on the
+		 * RTL8125B, so hash TCP and IP only.
+		 */
+		tp->hw_supp_num_rx_queues = R8125B_MAX_RX_QUEUES;
+		tp->rss_data->hw_supp_indir_tbl_entries = RTL_MAX_INDIRECTION_TABLE_ENTRIES;
+		tp->rss_data->hash_types = RSS_CTRL_TCP_IPV4_SUPP |
+					   RSS_CTRL_IPV4_SUPP |
+					   RSS_CTRL_IPV6_SUPP |
+					   RSS_CTRL_IPV6_EXT_SUPP |
+					   RSS_CTRL_TCP_IPV6_SUPP |
+					   RSS_CTRL_TCP_IPV6_EXT_SUPP;
+		tp->rss_desc_type = RX_DESC_TYPE_V3;
+		break;
 	case RTL_GIGA_MAC_VER_80:
 		tp->hw_supp_num_rx_queues = R8169_MAX_RX_QUEUES;
 		tp->rss_data->hw_supp_indir_tbl_entries = RTL_MAX_INDIRECTION_TABLE_ENTRIES;
@@ -6236,6 +6259,8 @@ static void rtl_set_irq_mask(struct rtl8169_private *tp)
 static const struct rtl_vec_map *rtl_get_vec_map(struct rtl8169_private *tp)
 {
 	switch (tp->mac_version) {
+	case RTL_GIGA_MAC_VER_63:
+		return &rtl_vec_map_8125b;
 	case RTL_GIGA_MAC_VER_80:
 		return &rtl_vec_map_8127;
 	default:
-- 
2.53.0


^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2026-11-11 22:01 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-11-11 22:01 [RFC net-next 0/5] r8169: RSS for the RTL8125B Vlad Banea
2026-11-11 22:01 ` [RFC net-next 1/5] r8169: recheck the TX descriptor after a vector-map interrupt Vlad Banea
2026-11-11 22:01 ` [RFC net-next 2/5] r8169: describe the vector-map interrupt layout per chip Vlad Banea
2026-11-11 22:01 ` [RFC net-next 3/5] r8169: make the RSS hash types and descriptor type " Vlad Banea
2026-11-11 22:01 ` [RFC net-next 4/5] r8169: add the type 3 RX descriptor Vlad Banea
2026-11-11 22:01 ` [RFC net-next 5/5] r8169: enable RSS on the RTL8125B Vlad Banea

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®