public inbox for netdev@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH net-next v1 0/4] r8169: add ltr and c10 support for RTL8116af
@ 2026-03-02  6:32 javen
  2026-03-02  6:32 ` [PATCH net-next v1 1/4] r8169: add ltr " javen
                   ` (3 more replies)
  0 siblings, 4 replies; 17+ messages in thread
From: javen @ 2026-03-02  6:32 UTC (permalink / raw)
  To: hkallweit1, nic_swsd, andrew+netdev, davem, edumazet, kuba,
	pabeni, horms
  Cc: netdev, linux-kernel, Javen Xu

From: Javen Xu <javen_xu@realsil.com.cn>

This series patch add ltr support for RTL8116af, enable RTL8116af enter
l1.2 state. Next add sfp mode for RTL8116af, which helps build link for
RTL8116af. The last patch move other function to d3 state to enable the
whole system can enter c10 state.

Javen Xu (4):
  r8169: add ltr support for RTL8116af
  r8169: add sfp mode for RTL8116af
  r8169: move DECLARE_RTL_COND()
  r8169: enable system enter c10 with RTL8116af

 drivers/net/ethernet/realtek/r8169_main.c | 207 ++++++++++++++++++++--
 1 file changed, 188 insertions(+), 19 deletions(-)

-- 
2.43.0


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

* [PATCH net-next v1 1/4] r8169: add ltr support for RTL8116af
  2026-03-02  6:32 [PATCH net-next v1 0/4] r8169: add ltr and c10 support for RTL8116af javen
@ 2026-03-02  6:32 ` javen
  2026-03-02  6:32 ` [PATCH net-next v1 2/4] r8169: add sfp mode " javen
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 17+ messages in thread
From: javen @ 2026-03-02  6:32 UTC (permalink / raw)
  To: hkallweit1, nic_swsd, andrew+netdev, davem, edumazet, kuba,
	pabeni, horms
  Cc: netdev, linux-kernel, Javen Xu

From: Javen Xu <javen_xu@realsil.com.cn>

This patch adds ltr support for RTL8116af, enables RTL8116af enter l1.2
state. This makes sense for the system to enter c10 state.

Signed-off-by: Javen Xu <javen_xu@realsil.com.cn>
---
 drivers/net/ethernet/realtek/r8169_main.c | 31 +++++++++++++++++++----
 1 file changed, 26 insertions(+), 5 deletions(-)

diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c
index 58788d196c57..fb2247a20c36 100644
--- a/drivers/net/ethernet/realtek/r8169_main.c
+++ b/drivers/net/ethernet/realtek/r8169_main.c
@@ -330,11 +330,13 @@ enum rtl_registers {
 	ALDPS_LTR	= 0xe0a2,
 	LTR_OBFF_LOCK	= 0xe032,
 	LTR_SNOOP	= 0xe034,
+	SEND_LTR_MSG	= 0xe038,
 
 #define ALDPS_LTR_EN			BIT(0)
 #define LTR_OBFF_LOCK_EN		BIT(0)
 #define LINK_SPEED_CHANGE_EN		BIT(14)
 #define LTR_SNOOP_EN			GENMASK(15, 14)
+#define LTR_MSG_EN			BIT(0)
 };
 
 enum rtl8168_8101_registers {
@@ -3093,8 +3095,22 @@ static void rtl_enable_ltr(struct rtl8169_private *tp)
 		r8168_mac_ocp_write(tp, 0xcdf2, 0x9003);
 		r8168_mac_ocp_modify(tp, LTR_OBFF_LOCK, 0x0000, LINK_SPEED_CHANGE_EN);
 		break;
-	case RTL_GIGA_MAC_VER_46 ... RTL_GIGA_MAC_VER_48:
 	case RTL_GIGA_MAC_VER_52:
+		r8168_mac_ocp_write(tp, 0xcdd0, 0x9003);
+		r8168_mac_ocp_modify(tp, LTR_SNOOP, 0x0000, LTR_SNOOP_EN);
+		r8168_mac_ocp_write(tp, 0xe02c, 0x1880);
+		r8168_mac_ocp_write(tp, 0xe02e, 0x4880);
+		r8168_mac_ocp_modify(tp, ALDPS_LTR, 0x0000, ALDPS_LTR_EN);
+		r8168_mac_ocp_write(tp, 0xcdd8, 0x9003);
+		r8168_mac_ocp_write(tp, 0xcdda, 0x9003);
+		r8168_mac_ocp_write(tp, 0xcddc, 0x9003);
+		r8168_mac_ocp_write(tp, 0xcdd2, 0x883c);
+		r8168_mac_ocp_write(tp, 0xcdd4, 0x8c12);
+		r8168_mac_ocp_write(tp, 0xcdd6, 0x9003);
+		r8168_mac_ocp_write(tp, 0xe0a6, 0x9003);
+		r8168_mac_ocp_write(tp, 0xe0a8, 0x9003);
+		break;
+	case RTL_GIGA_MAC_VER_46 ... RTL_GIGA_MAC_VER_48:
 		r8168_mac_ocp_modify(tp, ALDPS_LTR, 0x0000, ALDPS_LTR_EN);
 		RTL_W8(tp, COMBO_LTR_EXTEND, RTL_R8(tp, COMBO_LTR_EXTEND) | COMBO_LTR_EXTEND_EN);
 		fallthrough;
@@ -3114,6 +3130,7 @@ static void rtl_enable_ltr(struct rtl8169_private *tp)
 	}
 	/* chip can trigger LTR */
 	r8168_mac_ocp_modify(tp, LTR_OBFF_LOCK, 0x0003, LTR_OBFF_LOCK_EN);
+	r8168_mac_ocp_modify(tp, SEND_LTR_MSG, 0x0000, LTR_MSG_EN);
 }
 
 static void rtl_hw_aspm_clkreq_enable(struct rtl8169_private *tp, bool enable)
@@ -3147,6 +3164,7 @@ static void rtl_hw_aspm_clkreq_enable(struct rtl8169_private *tp, bool enable)
 		rtl_enable_ltr(tp);
 		switch (tp->mac_version) {
 		case RTL_GIGA_MAC_VER_46 ... RTL_GIGA_MAC_VER_48:
+		case RTL_GIGA_MAC_VER_52:
 		case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_LAST:
 			/* reset ephy tx/rx disable timer */
 			r8168_mac_ocp_modify(tp, 0xe094, 0xff00, 0);
@@ -3159,6 +3177,7 @@ static void rtl_hw_aspm_clkreq_enable(struct rtl8169_private *tp, bool enable)
 	} else {
 		switch (tp->mac_version) {
 		case RTL_GIGA_MAC_VER_46 ... RTL_GIGA_MAC_VER_48:
+		case RTL_GIGA_MAC_VER_52:
 		case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_LAST:
 			r8168_mac_ocp_modify(tp, 0xe092, 0x00ff, 0);
 			break;
@@ -3672,7 +3691,9 @@ static void rtl_hw_start_8117(struct rtl8169_private *tp)
 
 	rtl_eri_set_bits(tp, 0xd4, 0x0010);
 
-	rtl_eri_write(tp, 0x5f0, ERIAR_MASK_0011, 0x4f87);
+	rtl_eri_write(tp, 0x5f0, ERIAR_MASK_0011, 0x4000);
+
+	r8168_mac_ocp_write(tp, 0xe098, 0xc302);
 
 	rtl_disable_rxdvgate(tp);
 
@@ -3697,9 +3718,9 @@ static void rtl_hw_start_8117(struct rtl8169_private *tp)
 	}
 
 	r8168_mac_ocp_modify(tp, 0xe056, 0x00f0, 0x0000);
-	r8168_mac_ocp_write(tp, 0xea80, 0x0003);
-	r8168_mac_ocp_modify(tp, 0xe052, 0x0000, 0x0009);
-	r8168_mac_ocp_modify(tp, 0xd420, 0x0fff, 0x047f);
+	r8168_mac_ocp_write(tp, 0xea80, 0x0000);
+	r8168_mac_ocp_modify(tp, 0xe052, 0x0009, 0x0000);
+	r8168_mac_ocp_modify(tp, 0xd420, 0x0fff, 0x045f);
 
 	r8168_mac_ocp_write(tp, 0xe63e, 0x0001);
 	r8168_mac_ocp_write(tp, 0xe63e, 0x0000);
-- 
2.43.0


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

* [PATCH net-next v1 2/4] r8169: add sfp mode for RTL8116af
  2026-03-02  6:32 [PATCH net-next v1 0/4] r8169: add ltr and c10 support for RTL8116af javen
  2026-03-02  6:32 ` [PATCH net-next v1 1/4] r8169: add ltr " javen
@ 2026-03-02  6:32 ` javen
  2026-03-02 22:07   ` Heiner Kallweit
  2026-03-02  6:32 ` [PATCH net-next v1 3/4] r8169: move DECLARE_RTL_COND() javen
  2026-03-02  6:32 ` [PATCH net-next v1 4/4] r8169: enable system enter c10 with RTL8116af javen
  3 siblings, 1 reply; 17+ messages in thread
From: javen @ 2026-03-02  6:32 UTC (permalink / raw)
  To: hkallweit1, nic_swsd, andrew+netdev, davem, edumazet, kuba,
	pabeni, horms
  Cc: netdev, linux-kernel, Javen Xu

From: Javen Xu <javen_xu@realsil.com.cn>

RTL8116af is a variation of RTL8168fp. It uses SerDes instead of PHY.
But SerDes status will not relect to PHY. So it needs to add sfp mode
for quirk to help reflect SerDes status during PHY read.

Signed-off-by: Javen Xu <javen_xu@realsil.com.cn>
---
 drivers/net/ethernet/realtek/r8169_main.c | 71 ++++++++++++++++++++---
 1 file changed, 62 insertions(+), 9 deletions(-)

diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c
index fb2247a20c36..a5c0d3995328 100644
--- a/drivers/net/ethernet/realtek/r8169_main.c
+++ b/drivers/net/ethernet/realtek/r8169_main.c
@@ -726,6 +726,12 @@ enum rtl_dash_type {
 	RTL_DASH_25_BP,
 };
 
+enum rtl_sfp_mode {
+	RTL_SFP_NONE,
+	RTL_SFP_8168_AF,
+	RTL_SFP_8127_ATF,
+};
+
 struct rtl8169_private {
 	void __iomem *mmio_addr;	/* memory map physical address */
 	struct pci_dev *pci_dev;
@@ -734,6 +740,7 @@ struct rtl8169_private {
 	struct napi_struct napi;
 	enum mac_version mac_version;
 	enum rtl_dash_type dash_type;
+	enum rtl_sfp_mode sfp_mode;
 	u32 cur_rx; /* Index into the Rx descriptor buffer of next Rx pkt. */
 	u32 cur_tx; /* Index into the Tx descriptor buffer of next Rx pkt. */
 	u32 dirty_tx;
@@ -760,7 +767,6 @@ struct rtl8169_private {
 	unsigned supports_gmii:1;
 	unsigned aspm_manageable:1;
 	unsigned dash_enabled:1;
-	bool sfp_mode:1;
 	dma_addr_t counters_phys_addr;
 	struct rtl8169_counters *counters;
 	struct rtl8169_tc_offsets tc_offset;
@@ -1126,7 +1132,7 @@ static int r8168_phy_ocp_read(struct rtl8169_private *tp, u32 reg)
 		return 0;
 
 	/* Return dummy MII_PHYSID2 in SFP mode to match SFP PHY driver */
-	if (tp->sfp_mode && reg == (OCP_STD_PHY_BASE + 2 * MII_PHYSID2))
+	if (tp->sfp_mode == RTL_SFP_8127_ATF && reg == (OCP_STD_PHY_BASE + 2 * MII_PHYSID2))
 		return PHY_ID_RTL_DUMMY_SFP & 0xffff;
 
 	RTL_W32(tp, GPHY_OCP, reg << 15);
@@ -1270,6 +1276,34 @@ static int r8168g_mdio_read(struct rtl8169_private *tp, int reg)
 	return r8168_phy_ocp_read(tp, tp->ocp_base + reg * 2);
 }
 
+/* The quirk reflects RTL8116af SerDes status. */
+static int r8116af_mdio_read_quirk(struct rtl8169_private *tp, int reg)
+{
+	u8 phyStatus = RTL_R8(tp, PHYstatus);
+
+	if (!(phyStatus & LinkStatus))
+		return 0;
+
+	/* BMSR */
+	if (tp->ocp_base == OCP_STD_PHY_BASE && reg == MII_BMSR)
+		return BMSR_ANEGCOMPLETE | BMSR_LSTATUS;
+
+	/* PHYSR */
+	if (tp->ocp_base == 0xa430 && reg == 0x12) {
+		if (phyStatus & _1000bpsF)
+			return 0x0028;
+		else if (phyStatus & _100bps)
+			return 0x0018;
+	}
+
+	return 0;
+}
+
+static int r8116af_mdio_read(struct rtl8169_private *tp, int reg)
+{
+	return r8168g_mdio_read(tp, reg) | r8116af_mdio_read_quirk(tp, reg);
+}
+
 static void mac_mcu_write(struct rtl8169_private *tp, int reg, int value)
 {
 	if (reg == 0x1f) {
@@ -1280,6 +1314,13 @@ static void mac_mcu_write(struct rtl8169_private *tp, int reg, int value)
 	r8168_mac_ocp_write(tp, tp->ocp_base + reg, value);
 }
 
+static bool rtl_is_8116af(struct rtl8169_private *tp)
+{
+	return tp->mac_version == RTL_GIGA_MAC_VER_52 &&
+		(r8168_mac_ocp_read(tp, 0xdc00) & 0x0078) == 0x0030 &&
+		(r8168_mac_ocp_read(tp, 0xd006) & 0x00ff) == 0x0000;
+}
+
 static int mac_mcu_read(struct rtl8169_private *tp, int reg)
 {
 	return r8168_mac_ocp_read(tp, tp->ocp_base + reg);
@@ -1386,7 +1427,10 @@ static int rtl_readphy(struct rtl8169_private *tp, int location)
 	case RTL_GIGA_MAC_VER_31:
 		return r8168dp_2_mdio_read(tp, location);
 	case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_LAST:
-		return r8168g_mdio_read(tp, location);
+		if (tp->sfp_mode == RTL_SFP_8168_AF)
+			return r8116af_mdio_read(tp, location);
+		else
+			return r8168g_mdio_read(tp, location);
 	default:
 		return r8169_mdio_read(tp, location);
 	}
@@ -1575,6 +1619,20 @@ static bool rtl_dash_is_enabled(struct rtl8169_private *tp)
 	}
 }
 
+static enum rtl_sfp_mode rtl_get_sfp_mode(struct rtl8169_private *tp)
+{
+	if (rtl_is_8125(tp)) {
+		u16 data = r8168_mac_ocp_read(tp, 0xd006);
+
+		if ((data & 0xff) == 0x07)
+			return RTL_SFP_8127_ATF;
+	} else if (rtl_is_8116af(tp)) {
+		return RTL_SFP_8168_AF;
+	}
+
+	return RTL_SFP_NONE;
+}
+
 static enum rtl_dash_type rtl_get_dash_type(struct rtl8169_private *tp)
 {
 	switch (tp->mac_version) {
@@ -5693,12 +5751,7 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 	}
 	tp->aspm_manageable = !rc;
 
-	if (rtl_is_8125(tp)) {
-		u16 data = r8168_mac_ocp_read(tp, 0xd006);
-
-		if ((data & 0xff) == 0x07)
-			tp->sfp_mode = true;
-	}
+	tp->sfp_mode = rtl_get_sfp_mode(tp);
 
 	tp->dash_type = rtl_get_dash_type(tp);
 	tp->dash_enabled = rtl_dash_is_enabled(tp);
-- 
2.43.0


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

* [PATCH net-next v1 3/4] r8169: move DECLARE_RTL_COND()
  2026-03-02  6:32 [PATCH net-next v1 0/4] r8169: add ltr and c10 support for RTL8116af javen
  2026-03-02  6:32 ` [PATCH net-next v1 1/4] r8169: add ltr " javen
  2026-03-02  6:32 ` [PATCH net-next v1 2/4] r8169: add sfp mode " javen
@ 2026-03-02  6:32 ` javen
  2026-03-02  6:32 ` [PATCH net-next v1 4/4] r8169: enable system enter c10 with RTL8116af javen
  3 siblings, 0 replies; 17+ messages in thread
From: javen @ 2026-03-02  6:32 UTC (permalink / raw)
  To: hkallweit1, nic_swsd, andrew+netdev, davem, edumazet, kuba,
	pabeni, horms
  Cc: netdev, linux-kernel, Javen Xu

From: Javen Xu <javen_xu@realsil.com.cn>

There is no functional change. Moving DECLARE_RTL_COND() for the next
patch 4/4.

Signed-off-by: Javen Xu <javen_xu@realsil.com.cn>
---
 drivers/net/ethernet/realtek/r8169_main.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c
index a5c0d3995328..787859b0ab68 100644
--- a/drivers/net/ethernet/realtek/r8169_main.c
+++ b/drivers/net/ethernet/realtek/r8169_main.c
@@ -1052,6 +1052,11 @@ DECLARE_RTL_COND(rtl_eriar_cond)
 	return RTL_R32(tp, ERIAR) & ERIAR_FLAG;
 }
 
+DECLARE_RTL_COND(rtl_csiar_cond)
+{
+	return RTL_R32(tp, CSIAR) & CSIAR_FLAG;
+}
+
 static void _rtl_eri_write(struct rtl8169_private *tp, int addr, u32 mask,
 			   u32 val, int type)
 {
@@ -2927,11 +2932,6 @@ static void rtl_set_rx_mode(struct net_device *dev)
 	RTL_W32(tp, RxConfig, (tmp & ~RX_CONFIG_ACCEPT_OK_MASK) | rx_mode);
 }
 
-DECLARE_RTL_COND(rtl_csiar_cond)
-{
-	return RTL_R32(tp, CSIAR) & CSIAR_FLAG;
-}
-
 static void rtl_csi_write(struct rtl8169_private *tp, int addr, int value)
 {
 	u32 func = PCI_FUNC(tp->pci_dev->devfn);
-- 
2.43.0


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

* [PATCH net-next v1 4/4] r8169: enable system enter c10 with RTL8116af
  2026-03-02  6:32 [PATCH net-next v1 0/4] r8169: add ltr and c10 support for RTL8116af javen
                   ` (2 preceding siblings ...)
  2026-03-02  6:32 ` [PATCH net-next v1 3/4] r8169: move DECLARE_RTL_COND() javen
@ 2026-03-02  6:32 ` javen
  2026-03-02 21:53   ` Heiner Kallweit
  3 siblings, 1 reply; 17+ messages in thread
From: javen @ 2026-03-02  6:32 UTC (permalink / raw)
  To: hkallweit1, nic_swsd, andrew+netdev, davem, edumazet, kuba,
	pabeni, horms
  Cc: netdev, linux-kernel, Javen Xu

From: Javen Xu <javen_xu@realsil.com.cn>

RTL8116af is a multi function chip. Function 1 is load with r8169
driver. Function 0 is bmc virual driver which is used for power
management. This patch set Function 2 to 7 into d3 state when config
hw_config. This helps the whole system enter c10.

Signed-off-by: Javen Xu <javen_xu@realsil.com.cn>
---
 drivers/net/ethernet/realtek/r8169_main.c | 95 +++++++++++++++++++++++
 1 file changed, 95 insertions(+)

diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c
index 787859b0ab68..d8ffc76186b2 100644
--- a/drivers/net/ethernet/realtek/r8169_main.c
+++ b/drivers/net/ethernet/realtek/r8169_main.c
@@ -1121,6 +1121,100 @@ DECLARE_RTL_COND(rtl_ocp_gphy_cond)
 	return RTL_R32(tp, GPHY_OCP) & OCPAR_FLAG;
 }
 
+static u32 rtl_other_csi_read(struct rtl8169_private *tp, u8 multi_fun_sel_bit, int addr)
+{
+	RTL_W32(tp, CSIAR, (addr & CSIAR_ADDR_MASK) | multi_fun_sel_bit << 16 |
+		CSIAR_BYTE_ENABLE);
+
+	return rtl_loop_wait_high(tp, &rtl_csiar_cond, 10, 100) ?
+		RTL_R32(tp, CSIDR) : ~0;
+}
+
+static void rtl_other_csi_write(struct rtl8169_private *tp,
+				u8 multi_fun_sel_bit,
+				int addr,
+				int value)
+{
+	RTL_W32(tp, CSIDR, value);
+	RTL_W32(tp, CSIAR, CSIAR_WRITE_CMD | (addr & CSIAR_ADDR_MASK) |
+		CSIAR_BYTE_ENABLE | multi_fun_sel_bit << 16);
+
+	rtl_loop_wait_low(tp, &rtl_csiar_cond, 10, 100);
+}
+
+static void rtl8168_clear_and_set_other_fun_pci_bit(struct rtl8169_private *tp,
+						    u8 multi_fun_sel_bit,
+						    u32 addr,
+						    u32 clearmask,
+						    u32 setmask)
+{
+	u32 val;
+
+	val = rtl_other_csi_read(tp, multi_fun_sel_bit, addr);
+	val &= ~clearmask;
+	val |= setmask;
+	rtl_other_csi_write(tp, multi_fun_sel_bit, addr, val);
+}
+
+static void rtl8168_other_fun_dev_pci_setting(struct rtl8169_private *tp,
+					      u32 addr,
+					      u32 clearmask,
+					      u32 setmask,
+					      u8 multi_fun_sel_bit)
+{
+	u32 val;
+	u8 i;
+	u8 FunBit;
+	/* 0: BMC, 1: NIC, 2: TCR, 3: VGA/PCIE_TO_USB, 4: EHCI, 5: WIFI, 6: WIFI, 7: KCS */
+	for (i = 0; i < 8; i++) {
+		FunBit = (1 << i);
+		if (FunBit & multi_fun_sel_bit) {
+			u8 set_other_fun = true;
+
+			if (i == 0) {
+				set_other_fun = true;
+			} else if (i == 5 || i == 6) {
+				if (tp->dash_enabled) {
+					val = rtl_eri_read(tp, 0x184);
+					if (val & BIT(26))
+						set_other_fun = false;
+					else
+						set_other_fun = true;
+				}
+			} else {
+				val = rtl_other_csi_read(tp, i, 0x00);
+				if (val == 0xffffffff)
+					set_other_fun = true;
+				else
+					set_other_fun = false;
+			}
+			if (set_other_fun)
+				rtl8168_clear_and_set_other_fun_pci_bit(tp, i, addr,
+									clearmask, setmask);
+		}
+	}
+}
+
+static void rtl8168_set_dash_other_fun_dev_state_change(struct rtl8169_private *tp,
+							u8 dev_state,
+							u8 multi_fun_sel_bit)
+{
+	u32 clearmask;
+	u32 setmask;
+
+	if (dev_state == 0) {
+		clearmask = (BIT(0) | BIT(1));
+		setmask = 0;
+		rtl8168_other_fun_dev_pci_setting(tp, 0x44, clearmask,
+						  setmask, multi_fun_sel_bit);
+	} else {
+		clearmask = 0;
+		setmask = (BIT(0) | BIT(1));
+		rtl8168_other_fun_dev_pci_setting(tp, 0x44, clearmask,
+						  setmask, multi_fun_sel_bit);
+	}
+}
+
 static void r8168_phy_ocp_write(struct rtl8169_private *tp, u32 reg, u32 data)
 {
 	if (rtl_ocp_reg_failure(reg))
@@ -3785,6 +3879,7 @@ static void rtl_hw_start_8117(struct rtl8169_private *tp)
 	r8168_mac_ocp_write(tp, 0xc094, 0x0000);
 	r8168_mac_ocp_write(tp, 0xc09e, 0x0000);
 
+	rtl8168_set_dash_other_fun_dev_state_change(tp, 3, 0xfc);
 	/* firmware is for MAC only */
 	r8169_apply_firmware(tp);
 }
-- 
2.43.0


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

* Re: [PATCH net-next v1 4/4] r8169: enable system enter c10 with RTL8116af
  2026-03-02  6:32 ` [PATCH net-next v1 4/4] r8169: enable system enter c10 with RTL8116af javen
@ 2026-03-02 21:53   ` Heiner Kallweit
  2026-03-04  9:43     ` 许俊伟
  0 siblings, 1 reply; 17+ messages in thread
From: Heiner Kallweit @ 2026-03-02 21:53 UTC (permalink / raw)
  To: javen, nic_swsd, andrew+netdev, davem, edumazet, kuba, pabeni,
	horms
  Cc: netdev, linux-kernel

On 02.03.2026 07:32, javen wrote:
> From: Javen Xu <javen_xu@realsil.com.cn>
> 
> RTL8116af is a multi function chip. Function 1 is load with r8169
> driver. Function 0 is bmc virual driver which is used for power
> management. This patch set Function 2 to 7 into d3 state when config
> hw_config. This helps the whole system enter c10.
> 
> Signed-off-by: Javen Xu <javen_xu@realsil.com.cn>
> ---
>  drivers/net/ethernet/realtek/r8169_main.c | 95 +++++++++++++++++++++++
>  1 file changed, 95 insertions(+)
> 
> diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c
> index 787859b0ab68..d8ffc76186b2 100644
> --- a/drivers/net/ethernet/realtek/r8169_main.c
> +++ b/drivers/net/ethernet/realtek/r8169_main.c
> @@ -1121,6 +1121,100 @@ DECLARE_RTL_COND(rtl_ocp_gphy_cond)
>  	return RTL_R32(tp, GPHY_OCP) & OCPAR_FLAG;
>  }
>  
> +static u32 rtl_other_csi_read(struct rtl8169_private *tp, u8 multi_fun_sel_bit, int addr)
> +{
> +	RTL_W32(tp, CSIAR, (addr & CSIAR_ADDR_MASK) | multi_fun_sel_bit << 16 |
> +		CSIAR_BYTE_ENABLE);
> +
> +	return rtl_loop_wait_high(tp, &rtl_csiar_cond, 10, 100) ?
> +		RTL_R32(tp, CSIDR) : ~0;
> +}
> +
> +static void rtl_other_csi_write(struct rtl8169_private *tp,
> +				u8 multi_fun_sel_bit,
> +				int addr,
> +				int value)
> +{
> +	RTL_W32(tp, CSIDR, value);
> +	RTL_W32(tp, CSIAR, CSIAR_WRITE_CMD | (addr & CSIAR_ADDR_MASK) |
> +		CSIAR_BYTE_ENABLE | multi_fun_sel_bit << 16);
> +
> +	rtl_loop_wait_low(tp, &rtl_csiar_cond, 10, 100);
> +}
> +
> +static void rtl8168_clear_and_set_other_fun_pci_bit(struct rtl8169_private *tp,
> +						    u8 multi_fun_sel_bit,
> +						    u32 addr,
> +						    u32 clearmask,
> +						    u32 setmask)
> +{
> +	u32 val;
> +
> +	val = rtl_other_csi_read(tp, multi_fun_sel_bit, addr);
> +	val &= ~clearmask;
> +	val |= setmask;
> +	rtl_other_csi_write(tp, multi_fun_sel_bit, addr, val);
> +}
> +
> +static void rtl8168_other_fun_dev_pci_setting(struct rtl8169_private *tp,
> +					      u32 addr,
> +					      u32 clearmask,
> +					      u32 setmask,
> +					      u8 multi_fun_sel_bit)
> +{
> +	u32 val;
> +	u8 i;
> +	u8 FunBit;
> +	/* 0: BMC, 1: NIC, 2: TCR, 3: VGA/PCIE_TO_USB, 4: EHCI, 5: WIFI, 6: WIFI, 7: KCS */
> +	for (i = 0; i < 8; i++) {
> +		FunBit = (1 << i);
> +		if (FunBit & multi_fun_sel_bit) {
> +			u8 set_other_fun = true;
> +
> +			if (i == 0) {
> +				set_other_fun = true;
> +			} else if (i == 5 || i == 6) {
> +				if (tp->dash_enabled) {
> +					val = rtl_eri_read(tp, 0x184);
> +					if (val & BIT(26))
> +						set_other_fun = false;
> +					else
> +						set_other_fun = true;
> +				}
> +			} else {
> +				val = rtl_other_csi_read(tp, i, 0x00);
> +				if (val == 0xffffffff)
> +					set_other_fun = true;
> +				else
> +					set_other_fun = false;
> +			}
> +			if (set_other_fun)
> +				rtl8168_clear_and_set_other_fun_pci_bit(tp, i, addr,
> +									clearmask, setmask);
> +		}
> +	}
> +}
> +
> +static void rtl8168_set_dash_other_fun_dev_state_change(struct rtl8169_private *tp,
> +							u8 dev_state,
> +							u8 multi_fun_sel_bit)
> +{
> +	u32 clearmask;
> +	u32 setmask;
> +
> +	if (dev_state == 0) {
> +		clearmask = (BIT(0) | BIT(1));
> +		setmask = 0;
> +		rtl8168_other_fun_dev_pci_setting(tp, 0x44, clearmask,
> +						  setmask, multi_fun_sel_bit);
> +	} else {
> +		clearmask = 0;
> +		setmask = (BIT(0) | BIT(1));
> +		rtl8168_other_fun_dev_pci_setting(tp, 0x44, clearmask,
> +						  setmask, multi_fun_sel_bit);
> +	}
> +}
> +
>  static void r8168_phy_ocp_write(struct rtl8169_private *tp, u32 reg, u32 data)
>  {
>  	if (rtl_ocp_reg_failure(reg))
> @@ -3785,6 +3879,7 @@ static void rtl_hw_start_8117(struct rtl8169_private *tp)
>  	r8168_mac_ocp_write(tp, 0xc094, 0x0000);
>  	r8168_mac_ocp_write(tp, 0xc09e, 0x0000);
>  
> +	rtl8168_set_dash_other_fun_dev_state_change(tp, 3, 0xfc);
>  	/* firmware is for MAC only */
>  	r8169_apply_firmware(tp);
>  }

This is the type of code that would make r8169 become an unmaintainable mess like
the vendor drivers. Why not use standard means like pci_bus_read_config_word() et al?


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

* Re: [PATCH net-next v1 2/4] r8169: add sfp mode for RTL8116af
  2026-03-02  6:32 ` [PATCH net-next v1 2/4] r8169: add sfp mode " javen
@ 2026-03-02 22:07   ` Heiner Kallweit
  2026-03-04  8:16     ` 许俊伟
  2026-03-13  7:25     ` Javen
  0 siblings, 2 replies; 17+ messages in thread
From: Heiner Kallweit @ 2026-03-02 22:07 UTC (permalink / raw)
  To: javen, nic_swsd, andrew+netdev, davem, edumazet, kuba, pabeni,
	horms
  Cc: netdev, linux-kernel

On 02.03.2026 07:32, javen wrote:
> From: Javen Xu <javen_xu@realsil.com.cn>
> 
> RTL8116af is a variation of RTL8168fp. It uses SerDes instead of PHY.
> But SerDes status will not relect to PHY. So it needs to add sfp mode
> for quirk to help reflect SerDes status during PHY read.
> 

Is there any mass market device using this chip version? As far as possible
I'd like to avoid adding support for chip versions that never make it
to the mass market. This just makes driver maintenance harder.

The patch includes support for 100Mbps fiber mode. Is there any use case
for such legacy modes?


> Signed-off-by: Javen Xu <javen_xu@realsil.com.cn>
> ---
>  drivers/net/ethernet/realtek/r8169_main.c | 71 ++++++++++++++++++++---
>  1 file changed, 62 insertions(+), 9 deletions(-)
> 
> diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c
> index fb2247a20c36..a5c0d3995328 100644
> --- a/drivers/net/ethernet/realtek/r8169_main.c
> +++ b/drivers/net/ethernet/realtek/r8169_main.c
> @@ -726,6 +726,12 @@ enum rtl_dash_type {
>  	RTL_DASH_25_BP,
>  };
>  
> +enum rtl_sfp_mode {
> +	RTL_SFP_NONE,
> +	RTL_SFP_8168_AF,
> +	RTL_SFP_8127_ATF,
> +};
> +
>  struct rtl8169_private {
>  	void __iomem *mmio_addr;	/* memory map physical address */
>  	struct pci_dev *pci_dev;
> @@ -734,6 +740,7 @@ struct rtl8169_private {
>  	struct napi_struct napi;
>  	enum mac_version mac_version;
>  	enum rtl_dash_type dash_type;
> +	enum rtl_sfp_mode sfp_mode;
>  	u32 cur_rx; /* Index into the Rx descriptor buffer of next Rx pkt. */
>  	u32 cur_tx; /* Index into the Tx descriptor buffer of next Rx pkt. */
>  	u32 dirty_tx;
> @@ -760,7 +767,6 @@ struct rtl8169_private {
>  	unsigned supports_gmii:1;
>  	unsigned aspm_manageable:1;
>  	unsigned dash_enabled:1;
> -	bool sfp_mode:1;
>  	dma_addr_t counters_phys_addr;
>  	struct rtl8169_counters *counters;
>  	struct rtl8169_tc_offsets tc_offset;
> @@ -1126,7 +1132,7 @@ static int r8168_phy_ocp_read(struct rtl8169_private *tp, u32 reg)
>  		return 0;
>  
>  	/* Return dummy MII_PHYSID2 in SFP mode to match SFP PHY driver */
> -	if (tp->sfp_mode && reg == (OCP_STD_PHY_BASE + 2 * MII_PHYSID2))
> +	if (tp->sfp_mode == RTL_SFP_8127_ATF && reg == (OCP_STD_PHY_BASE + 2 * MII_PHYSID2))
>  		return PHY_ID_RTL_DUMMY_SFP & 0xffff;
>  
>  	RTL_W32(tp, GPHY_OCP, reg << 15);
> @@ -1270,6 +1276,34 @@ static int r8168g_mdio_read(struct rtl8169_private *tp, int reg)
>  	return r8168_phy_ocp_read(tp, tp->ocp_base + reg * 2);
>  }
>  
> +/* The quirk reflects RTL8116af SerDes status. */
> +static int r8116af_mdio_read_quirk(struct rtl8169_private *tp, int reg)
> +{
> +	u8 phyStatus = RTL_R8(tp, PHYstatus);
> +
> +	if (!(phyStatus & LinkStatus))
> +		return 0;
> +
> +	/* BMSR */
> +	if (tp->ocp_base == OCP_STD_PHY_BASE && reg == MII_BMSR)
> +		return BMSR_ANEGCOMPLETE | BMSR_LSTATUS;
> +
> +	/* PHYSR */
> +	if (tp->ocp_base == 0xa430 && reg == 0x12) {
> +		if (phyStatus & _1000bpsF)
> +			return 0x0028;
> +		else if (phyStatus & _100bps)
> +			return 0x0018;

This is a complete hack. Any means to access the SerDes directly?

> +	}
> +
> +	return 0;
> +}
> +
> +static int r8116af_mdio_read(struct rtl8169_private *tp, int reg)
> +{
> +	return r8168g_mdio_read(tp, reg) | r8116af_mdio_read_quirk(tp, reg);
> +}
> +
>  static void mac_mcu_write(struct rtl8169_private *tp, int reg, int value)
>  {
>  	if (reg == 0x1f) {
> @@ -1280,6 +1314,13 @@ static void mac_mcu_write(struct rtl8169_private *tp, int reg, int value)
>  	r8168_mac_ocp_write(tp, tp->ocp_base + reg, value);
>  }
>  
> +static bool rtl_is_8116af(struct rtl8169_private *tp)
> +{
> +	return tp->mac_version == RTL_GIGA_MAC_VER_52 &&
> +		(r8168_mac_ocp_read(tp, 0xdc00) & 0x0078) == 0x0030 &&
> +		(r8168_mac_ocp_read(tp, 0xd006) & 0x00ff) == 0x0000;
> +}
> +
>  static int mac_mcu_read(struct rtl8169_private *tp, int reg)
>  {
>  	return r8168_mac_ocp_read(tp, tp->ocp_base + reg);
> @@ -1386,7 +1427,10 @@ static int rtl_readphy(struct rtl8169_private *tp, int location)
>  	case RTL_GIGA_MAC_VER_31:
>  		return r8168dp_2_mdio_read(tp, location);
>  	case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_LAST:
> -		return r8168g_mdio_read(tp, location);
> +		if (tp->sfp_mode == RTL_SFP_8168_AF)
> +			return r8116af_mdio_read(tp, location);
> +		else
> +			return r8168g_mdio_read(tp, location);
>  	default:
>  		return r8169_mdio_read(tp, location);
>  	}
> @@ -1575,6 +1619,20 @@ static bool rtl_dash_is_enabled(struct rtl8169_private *tp)
>  	}
>  }
>  
> +static enum rtl_sfp_mode rtl_get_sfp_mode(struct rtl8169_private *tp)
> +{
> +	if (rtl_is_8125(tp)) {
> +		u16 data = r8168_mac_ocp_read(tp, 0xd006);
> +
> +		if ((data & 0xff) == 0x07)
> +			return RTL_SFP_8127_ATF;
> +	} else if (rtl_is_8116af(tp)) {
> +		return RTL_SFP_8168_AF;
> +	}
> +
> +	return RTL_SFP_NONE;
> +}
> +
>  static enum rtl_dash_type rtl_get_dash_type(struct rtl8169_private *tp)
>  {
>  	switch (tp->mac_version) {
> @@ -5693,12 +5751,7 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
>  	}
>  	tp->aspm_manageable = !rc;
>  
> -	if (rtl_is_8125(tp)) {
> -		u16 data = r8168_mac_ocp_read(tp, 0xd006);
> -
> -		if ((data & 0xff) == 0x07)
> -			tp->sfp_mode = true;
> -	}
> +	tp->sfp_mode = rtl_get_sfp_mode(tp);
>  
>  	tp->dash_type = rtl_get_dash_type(tp);
>  	tp->dash_enabled = rtl_dash_is_enabled(tp);


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

* RE: [PATCH net-next v1 2/4] r8169: add sfp mode for RTL8116af
  2026-03-02 22:07   ` Heiner Kallweit
@ 2026-03-04  8:16     ` 许俊伟
  2026-03-04 21:42       ` Heiner Kallweit
  2026-03-13  7:25     ` Javen
  1 sibling, 1 reply; 17+ messages in thread
From: 许俊伟 @ 2026-03-04  8:16 UTC (permalink / raw)
  To: Heiner Kallweit, nic_swsd@realtek.com, andrew+netdev@lunn.ch,
	davem@davemloft.net, edumazet@google.com, kuba@kernel.org,
	pabeni@redhat.com, horms@kernel.org
  Cc: netdev@vger.kernel.org, linux-kernel@vger.kernel.org

>On 02.03.2026 07:32, javen wrote:
>> From: Javen Xu <javen_xu@realsil.com.cn>
>>
>> RTL8116af is a variation of RTL8168fp. It uses SerDes instead of PHY.
>> But SerDes status will not relect to PHY. So it needs to add sfp mode
>> for quirk to help reflect SerDes status during PHY read.
>>
>
>Is there any mass market device using this chip version? As far as possible I'd
>like to avoid adding support for chip versions that never make it to the mass
>market. This just makes driver maintenance harder.
>
>The patch includes support for 100Mbps fiber mode. Is there any use case for
>such legacy modes?
>

Our customer platform (using RTL8116af) requires support for entering c10
power-saving state, so we need to add support for this chip.

>
>> Signed-off-by: Javen Xu <javen_xu@realsil.com.cn>
>> ---
>>  drivers/net/ethernet/realtek/r8169_main.c | 71
>> ++++++++++++++++++++---
>>  1 file changed, 62 insertions(+), 9 deletions(-)
>>
>> diff --git a/drivers/net/ethernet/realtek/r8169_main.c
>> b/drivers/net/ethernet/realtek/r8169_main.c
>> index fb2247a20c36..a5c0d3995328 100644
>> --- a/drivers/net/ethernet/realtek/r8169_main.c
>> +++ b/drivers/net/ethernet/realtek/r8169_main.c
>> @@ -726,6 +726,12 @@ enum rtl_dash_type {
>>       RTL_DASH_25_BP,
>>  };
>>
>> +enum rtl_sfp_mode {
>> +     RTL_SFP_NONE,
>> +     RTL_SFP_8168_AF,
>> +     RTL_SFP_8127_ATF,
>> +};
>> +
>>  struct rtl8169_private {
>>       void __iomem *mmio_addr;        /* memory map physical address */
>>       struct pci_dev *pci_dev;
>> @@ -734,6 +740,7 @@ struct rtl8169_private {
>>       struct napi_struct napi;
>>       enum mac_version mac_version;
>>       enum rtl_dash_type dash_type;
>> +     enum rtl_sfp_mode sfp_mode;
>>       u32 cur_rx; /* Index into the Rx descriptor buffer of next Rx pkt. */
>>       u32 cur_tx; /* Index into the Tx descriptor buffer of next Rx pkt. */
>>       u32 dirty_tx;
>> @@ -760,7 +767,6 @@ struct rtl8169_private {
>>       unsigned supports_gmii:1;
>>       unsigned aspm_manageable:1;
>>       unsigned dash_enabled:1;
>> -     bool sfp_mode:1;
>>       dma_addr_t counters_phys_addr;
>>       struct rtl8169_counters *counters;
>>       struct rtl8169_tc_offsets tc_offset; @@ -1126,7 +1132,7 @@
>> static int r8168_phy_ocp_read(struct rtl8169_private *tp, u32 reg)
>>               return 0;
>>
>>       /* Return dummy MII_PHYSID2 in SFP mode to match SFP PHY driver */
>> -     if (tp->sfp_mode && reg == (OCP_STD_PHY_BASE + 2 * MII_PHYSID2))
>> +     if (tp->sfp_mode == RTL_SFP_8127_ATF && reg ==
>(OCP_STD_PHY_BASE
>> + + 2 * MII_PHYSID2))
>>               return PHY_ID_RTL_DUMMY_SFP & 0xffff;
>>
>>       RTL_W32(tp, GPHY_OCP, reg << 15); @@ -1270,6 +1276,34 @@ static
>> int r8168g_mdio_read(struct rtl8169_private *tp, int reg)
>>       return r8168_phy_ocp_read(tp, tp->ocp_base + reg * 2);  }
>>
>> +/* The quirk reflects RTL8116af SerDes status. */ static int
>> +r8116af_mdio_read_quirk(struct rtl8169_private *tp, int reg) {
>> +     u8 phyStatus = RTL_R8(tp, PHYstatus);
>> +
>> +     if (!(phyStatus & LinkStatus))
>> +             return 0;
>> +
>> +     /* BMSR */
>> +     if (tp->ocp_base == OCP_STD_PHY_BASE && reg == MII_BMSR)
>> +             return BMSR_ANEGCOMPLETE | BMSR_LSTATUS;
>> +
>> +     /* PHYSR */
>> +     if (tp->ocp_base == 0xa430 && reg == 0x12) {
>> +             if (phyStatus & _1000bpsF)
>> +                     return 0x0028;
>> +             else if (phyStatus & _100bps)
>> +                     return 0x0018;
>
>This is a complete hack. Any means to access the SerDes directly?

Unlike RTL8127atf where the SerDes status is automatically reflected in the
Standard PHY register, RTL8116af does not sync this status to the PHY register.
Maybe this hardware design is to save power. So we have no choice but to
upstream such hack code to get link status and speed. 
Given this hardware behavior, do you have any suggestions for a cleaner approach,
or would this workaround be acceptable with some explaining comments?

Thanks,
Javen Xu

>
>> +     }
>> +
>> +     return 0;
>> +}
>> +
>> +static int r8116af_mdio_read(struct rtl8169_private *tp, int reg) {
>> +     return r8168g_mdio_read(tp, reg) | r8116af_mdio_read_quirk(tp,
>> +reg); }
>> +
>>  static void mac_mcu_write(struct rtl8169_private *tp, int reg, int
>> value)  {
>>       if (reg == 0x1f) {
>> @@ -1280,6 +1314,13 @@ static void mac_mcu_write(struct rtl8169_private
>*tp, int reg, int value)
>>       r8168_mac_ocp_write(tp, tp->ocp_base + reg, value);  }
>>
>> +static bool rtl_is_8116af(struct rtl8169_private *tp) {
>> +     return tp->mac_version == RTL_GIGA_MAC_VER_52 &&
>> +             (r8168_mac_ocp_read(tp, 0xdc00) & 0x0078) == 0x0030 &&
>> +             (r8168_mac_ocp_read(tp, 0xd006) & 0x00ff) == 0x0000; }
>> +
>>  static int mac_mcu_read(struct rtl8169_private *tp, int reg)  {
>>       return r8168_mac_ocp_read(tp, tp->ocp_base + reg); @@ -1386,7
>> +1427,10 @@ static int rtl_readphy(struct rtl8169_private *tp, int location)
>>       case RTL_GIGA_MAC_VER_31:
>>               return r8168dp_2_mdio_read(tp, location);
>>       case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_LAST:
>> -             return r8168g_mdio_read(tp, location);
>> +             if (tp->sfp_mode == RTL_SFP_8168_AF)
>> +                     return r8116af_mdio_read(tp, location);
>> +             else
>> +                     return r8168g_mdio_read(tp, location);
>>       default:
>>               return r8169_mdio_read(tp, location);
>>       }
>> @@ -1575,6 +1619,20 @@ static bool rtl_dash_is_enabled(struct
>rtl8169_private *tp)
>>       }
>>  }
>>
>> +static enum rtl_sfp_mode rtl_get_sfp_mode(struct rtl8169_private *tp)
>> +{
>> +     if (rtl_is_8125(tp)) {
>> +             u16 data = r8168_mac_ocp_read(tp, 0xd006);
>> +
>> +             if ((data & 0xff) == 0x07)
>> +                     return RTL_SFP_8127_ATF;
>> +     } else if (rtl_is_8116af(tp)) {
>> +             return RTL_SFP_8168_AF;
>> +     }
>> +
>> +     return RTL_SFP_NONE;
>> +}
>> +
>>  static enum rtl_dash_type rtl_get_dash_type(struct rtl8169_private
>> *tp)  {
>>       switch (tp->mac_version) {
>> @@ -5693,12 +5751,7 @@ static int rtl_init_one(struct pci_dev *pdev, const
>struct pci_device_id *ent)
>>       }
>>       tp->aspm_manageable = !rc;
>>
>> -     if (rtl_is_8125(tp)) {
>> -             u16 data = r8168_mac_ocp_read(tp, 0xd006);
>> -
>> -             if ((data & 0xff) == 0x07)
>> -                     tp->sfp_mode = true;
>> -     }
>> +     tp->sfp_mode = rtl_get_sfp_mode(tp);
>>
>>       tp->dash_type = rtl_get_dash_type(tp);
>>       tp->dash_enabled = rtl_dash_is_enabled(tp);


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

* RE: [PATCH net-next v1 4/4] r8169: enable system enter c10 with RTL8116af
  2026-03-02 21:53   ` Heiner Kallweit
@ 2026-03-04  9:43     ` 许俊伟
  2026-03-04 21:51       ` Heiner Kallweit
  0 siblings, 1 reply; 17+ messages in thread
From: 许俊伟 @ 2026-03-04  9:43 UTC (permalink / raw)
  To: Heiner Kallweit, nic_swsd@realtek.com, andrew+netdev@lunn.ch,
	davem@davemloft.net, edumazet@google.com, kuba@kernel.org,
	pabeni@redhat.com, horms@kernel.org
  Cc: netdev@vger.kernel.org, linux-kernel@vger.kernel.org

>On 02.03.2026 07:32, javen wrote:
>> From: Javen Xu <javen_xu@realsil.com.cn>
>>
>> RTL8116af is a multi function chip. Function 1 is load with r8169
>> driver. Function 0 is bmc virual driver which is used for power
>> management. This patch set Function 2 to 7 into d3 state when config
>> hw_config. This helps the whole system enter c10.
>>
>> Signed-off-by: Javen Xu <javen_xu@realsil.com.cn>
>> ---
>>  drivers/net/ethernet/realtek/r8169_main.c | 95
>> +++++++++++++++++++++++
>>  1 file changed, 95 insertions(+)
>>
>> diff --git a/drivers/net/ethernet/realtek/r8169_main.c
>> b/drivers/net/ethernet/realtek/r8169_main.c
>> index 787859b0ab68..d8ffc76186b2 100644
>> --- a/drivers/net/ethernet/realtek/r8169_main.c
>> +++ b/drivers/net/ethernet/realtek/r8169_main.c
>> @@ -1121,6 +1121,100 @@ DECLARE_RTL_COND(rtl_ocp_gphy_cond)
>>       return RTL_R32(tp, GPHY_OCP) & OCPAR_FLAG;  }
>>
>> +static u32 rtl_other_csi_read(struct rtl8169_private *tp, u8
>> +multi_fun_sel_bit, int addr) {
>> +     RTL_W32(tp, CSIAR, (addr & CSIAR_ADDR_MASK) | multi_fun_sel_bit
><< 16 |
>> +             CSIAR_BYTE_ENABLE);
>> +
>> +     return rtl_loop_wait_high(tp, &rtl_csiar_cond, 10, 100) ?
>> +             RTL_R32(tp, CSIDR) : ~0; }
>> +
>> +static void rtl_other_csi_write(struct rtl8169_private *tp,
>> +                             u8 multi_fun_sel_bit,
>> +                             int addr,
>> +                             int value) {
>> +     RTL_W32(tp, CSIDR, value);
>> +     RTL_W32(tp, CSIAR, CSIAR_WRITE_CMD | (addr & CSIAR_ADDR_MASK)
>|
>> +             CSIAR_BYTE_ENABLE | multi_fun_sel_bit << 16);
>> +
>> +     rtl_loop_wait_low(tp, &rtl_csiar_cond, 10, 100); }
>> +
>> +static void rtl8168_clear_and_set_other_fun_pci_bit(struct rtl8169_private
>*tp,
>> +                                                 u8 multi_fun_sel_bit,
>> +                                                 u32 addr,
>> +                                                 u32 clearmask,
>> +                                                 u32 setmask) {
>> +     u32 val;
>> +
>> +     val = rtl_other_csi_read(tp, multi_fun_sel_bit, addr);
>> +     val &= ~clearmask;
>> +     val |= setmask;
>> +     rtl_other_csi_write(tp, multi_fun_sel_bit, addr, val); }
>> +
>> +static void rtl8168_other_fun_dev_pci_setting(struct rtl8169_private *tp,
>> +                                           u32 addr,
>> +                                           u32 clearmask,
>> +                                           u32 setmask,
>> +                                           u8 multi_fun_sel_bit) {
>> +     u32 val;
>> +     u8 i;
>> +     u8 FunBit;
>> +     /* 0: BMC, 1: NIC, 2: TCR, 3: VGA/PCIE_TO_USB, 4: EHCI, 5: WIFI, 6: WIFI,
>7: KCS */
>> +     for (i = 0; i < 8; i++) {
>> +             FunBit = (1 << i);
>> +             if (FunBit & multi_fun_sel_bit) {
>> +                     u8 set_other_fun = true;
>> +
>> +                     if (i == 0) {
>> +                             set_other_fun = true;
>> +                     } else if (i == 5 || i == 6) {
>> +                             if (tp->dash_enabled) {
>> +                                     val = rtl_eri_read(tp, 0x184);
>> +                                     if (val & BIT(26))
>> +                                             set_other_fun = false;
>> +                                     else
>> +                                             set_other_fun = true;
>> +                             }
>> +                     } else {
>> +                             val = rtl_other_csi_read(tp, i, 0x00);
>> +                             if (val == 0xffffffff)
>> +                                     set_other_fun = true;
>> +                             else
>> +                                     set_other_fun = false;
>> +                     }
>> +                     if (set_other_fun)
>> +                             rtl8168_clear_and_set_other_fun_pci_bit(tp, i, addr,
>> +                                                                     clearmask, setmask);
>> +             }
>> +     }
>> +}
>> +
>> +static void rtl8168_set_dash_other_fun_dev_state_change(struct
>rtl8169_private *tp,
>> +                                                     u8 dev_state,
>> +                                                     u8
>> +multi_fun_sel_bit) {
>> +     u32 clearmask;
>> +     u32 setmask;
>> +
>> +     if (dev_state == 0) {
>> +             clearmask = (BIT(0) | BIT(1));
>> +             setmask = 0;
>> +             rtl8168_other_fun_dev_pci_setting(tp, 0x44, clearmask,
>> +                                               setmask, multi_fun_sel_bit);
>> +     } else {
>> +             clearmask = 0;
>> +             setmask = (BIT(0) | BIT(1));
>> +             rtl8168_other_fun_dev_pci_setting(tp, 0x44, clearmask,
>> +                                               setmask, multi_fun_sel_bit);
>> +     }
>> +}
>> +
>>  static void r8168_phy_ocp_write(struct rtl8169_private *tp, u32 reg,
>> u32 data)  {
>>       if (rtl_ocp_reg_failure(reg))
>> @@ -3785,6 +3879,7 @@ static void rtl_hw_start_8117(struct
>rtl8169_private *tp)
>>       r8168_mac_ocp_write(tp, 0xc094, 0x0000);
>>       r8168_mac_ocp_write(tp, 0xc09e, 0x0000);
>>
>> +     rtl8168_set_dash_other_fun_dev_state_change(tp, 3, 0xfc);
>>       /* firmware is for MAC only */
>>       r8169_apply_firmware(tp);
>>  }
>
>This is the type of code that would make r8169 become an unmaintainable
>mess like the vendor drivers. Why not use standard means like
>pci_bus_read_config_word() et al?

Thanks for the suggestion.
I first tried to use lspci, but I can't find function 2-7 in pci system. Then I tried to
use pci_bus_read_config_word() to access Function 2-7 and get result as below.

[21254.984983] RTL8168_DEBUG: Slot 0, Function 2, Read Vendor ID: 0xffffffff

This confirms that these funcitons are physically hidden from the PCI bus. They do
not respond to standard PCI configuration cycles, this maybe the reason why standard
PCI APIs cannot be used here.
These functions are important for power state issue. When system suspends, linux PCI
core automatically handles the power transition for the visible functions. But since
function 2-7 is invisible, the kernel cannot manage it. As a result, we have no choice but
to use the vendor-specific indirect access mechanism(via CSIAR register).

Thanks,
Javen Xu


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

* Re: [PATCH net-next v1 2/4] r8169: add sfp mode for RTL8116af
  2026-03-04  8:16     ` 许俊伟
@ 2026-03-04 21:42       ` Heiner Kallweit
  0 siblings, 0 replies; 17+ messages in thread
From: Heiner Kallweit @ 2026-03-04 21:42 UTC (permalink / raw)
  To: 许俊伟, nic_swsd@realtek.com,
	andrew+netdev@lunn.ch, davem@davemloft.net, edumazet@google.com,
	kuba@kernel.org, pabeni@redhat.com, horms@kernel.org
  Cc: netdev@vger.kernel.org, linux-kernel@vger.kernel.org

On 04.03.2026 09:16, 许俊伟 wrote:
>> On 02.03.2026 07:32, javen wrote:
>>> From: Javen Xu <javen_xu@realsil.com.cn>
>>>
>>> RTL8116af is a variation of RTL8168fp. It uses SerDes instead of PHY.
>>> But SerDes status will not relect to PHY. So it needs to add sfp mode
>>> for quirk to help reflect SerDes status during PHY read.
>>>
>>
>> Is there any mass market device using this chip version? As far as possible I'd
>> like to avoid adding support for chip versions that never make it to the mass
>> market. This just makes driver maintenance harder.
>>
>> The patch includes support for 100Mbps fiber mode. Is there any use case for
>> such legacy modes?
>>
> 
> Our customer platform (using RTL8116af) requires support for entering c10
> power-saving state, so we need to add support for this chip.
> 
What do you mean with "customer platform"? That what other manufacturers
would call a board support package (BSP)?

>>
>>> Signed-off-by: Javen Xu <javen_xu@realsil.com.cn>
>>> ---
>>>  drivers/net/ethernet/realtek/r8169_main.c | 71
>>> ++++++++++++++++++++---
>>>  1 file changed, 62 insertions(+), 9 deletions(-)
>>>
>>> diff --git a/drivers/net/ethernet/realtek/r8169_main.c
>>> b/drivers/net/ethernet/realtek/r8169_main.c
>>> index fb2247a20c36..a5c0d3995328 100644
>>> --- a/drivers/net/ethernet/realtek/r8169_main.c
>>> +++ b/drivers/net/ethernet/realtek/r8169_main.c
>>> @@ -726,6 +726,12 @@ enum rtl_dash_type {
>>>       RTL_DASH_25_BP,
>>>  };
>>>
>>> +enum rtl_sfp_mode {
>>> +     RTL_SFP_NONE,
>>> +     RTL_SFP_8168_AF,
>>> +     RTL_SFP_8127_ATF,
>>> +};
>>> +
>>>  struct rtl8169_private {
>>>       void __iomem *mmio_addr;        /* memory map physical address */
>>>       struct pci_dev *pci_dev;
>>> @@ -734,6 +740,7 @@ struct rtl8169_private {
>>>       struct napi_struct napi;
>>>       enum mac_version mac_version;
>>>       enum rtl_dash_type dash_type;
>>> +     enum rtl_sfp_mode sfp_mode;
>>>       u32 cur_rx; /* Index into the Rx descriptor buffer of next Rx pkt. */
>>>       u32 cur_tx; /* Index into the Tx descriptor buffer of next Rx pkt. */
>>>       u32 dirty_tx;
>>> @@ -760,7 +767,6 @@ struct rtl8169_private {
>>>       unsigned supports_gmii:1;
>>>       unsigned aspm_manageable:1;
>>>       unsigned dash_enabled:1;
>>> -     bool sfp_mode:1;
>>>       dma_addr_t counters_phys_addr;
>>>       struct rtl8169_counters *counters;
>>>       struct rtl8169_tc_offsets tc_offset; @@ -1126,7 +1132,7 @@
>>> static int r8168_phy_ocp_read(struct rtl8169_private *tp, u32 reg)
>>>               return 0;
>>>
>>>       /* Return dummy MII_PHYSID2 in SFP mode to match SFP PHY driver */
>>> -     if (tp->sfp_mode && reg == (OCP_STD_PHY_BASE + 2 * MII_PHYSID2))
>>> +     if (tp->sfp_mode == RTL_SFP_8127_ATF && reg ==
>> (OCP_STD_PHY_BASE
>>> + + 2 * MII_PHYSID2))
>>>               return PHY_ID_RTL_DUMMY_SFP & 0xffff;
>>>
>>>       RTL_W32(tp, GPHY_OCP, reg << 15); @@ -1270,6 +1276,34 @@ static
>>> int r8168g_mdio_read(struct rtl8169_private *tp, int reg)
>>>       return r8168_phy_ocp_read(tp, tp->ocp_base + reg * 2);  }
>>>
>>> +/* The quirk reflects RTL8116af SerDes status. */ static int
>>> +r8116af_mdio_read_quirk(struct rtl8169_private *tp, int reg) {
>>> +     u8 phyStatus = RTL_R8(tp, PHYstatus);
>>> +
>>> +     if (!(phyStatus & LinkStatus))
>>> +             return 0;
>>> +
>>> +     /* BMSR */
>>> +     if (tp->ocp_base == OCP_STD_PHY_BASE && reg == MII_BMSR)
>>> +             return BMSR_ANEGCOMPLETE | BMSR_LSTATUS;
>>> +
>>> +     /* PHYSR */
>>> +     if (tp->ocp_base == 0xa430 && reg == 0x12) {
>>> +             if (phyStatus & _1000bpsF)
>>> +                     return 0x0028;
>>> +             else if (phyStatus & _100bps)
>>> +                     return 0x0018;
>>
>> This is a complete hack. Any means to access the SerDes directly?
> 
> Unlike RTL8127atf where the SerDes status is automatically reflected in the
> Standard PHY register, RTL8116af does not sync this status to the PHY register.
> Maybe this hardware design is to save power. So we have no choice but to
> upstream such hack code to get link status and speed. 
> Given this hardware behavior, do you have any suggestions for a cleaner approach,
> or would this workaround be acceptable with some explaining comments?
> 
Even RTL8127atf requires ugly workarounds because there's no direct access to
the SerDes and the SFP I2C bus.
Realtek's wish to upstream support for their chips collides with their decision
to hide several essential components behind firmware. For proper mainline support
Realtek should expose components like SerDes and SFP I2C, so that the kernel
can access them, and phylink, sfp, and friends can do their job.

If use case is just Realtek's customer platform, then RTL8116af support could
be implemented downstream, avoiding hacks in mainline.


> Thanks,
> Javen Xu
> 
>>
>>> +     }
>>> +
>>> +     return 0;
>>> +}
>>> +
>>> +static int r8116af_mdio_read(struct rtl8169_private *tp, int reg) {
>>> +     return r8168g_mdio_read(tp, reg) | r8116af_mdio_read_quirk(tp,
>>> +reg); }
>>> +
>>>  static void mac_mcu_write(struct rtl8169_private *tp, int reg, int
>>> value)  {
>>>       if (reg == 0x1f) {
>>> @@ -1280,6 +1314,13 @@ static void mac_mcu_write(struct rtl8169_private
>> *tp, int reg, int value)
>>>       r8168_mac_ocp_write(tp, tp->ocp_base + reg, value);  }
>>>
>>> +static bool rtl_is_8116af(struct rtl8169_private *tp) {
>>> +     return tp->mac_version == RTL_GIGA_MAC_VER_52 &&
>>> +             (r8168_mac_ocp_read(tp, 0xdc00) & 0x0078) == 0x0030 &&
>>> +             (r8168_mac_ocp_read(tp, 0xd006) & 0x00ff) == 0x0000; }
>>> +
>>>  static int mac_mcu_read(struct rtl8169_private *tp, int reg)  {
>>>       return r8168_mac_ocp_read(tp, tp->ocp_base + reg); @@ -1386,7
>>> +1427,10 @@ static int rtl_readphy(struct rtl8169_private *tp, int location)
>>>       case RTL_GIGA_MAC_VER_31:
>>>               return r8168dp_2_mdio_read(tp, location);
>>>       case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_LAST:
>>> -             return r8168g_mdio_read(tp, location);
>>> +             if (tp->sfp_mode == RTL_SFP_8168_AF)
>>> +                     return r8116af_mdio_read(tp, location);
>>> +             else
>>> +                     return r8168g_mdio_read(tp, location);
>>>       default:
>>>               return r8169_mdio_read(tp, location);
>>>       }
>>> @@ -1575,6 +1619,20 @@ static bool rtl_dash_is_enabled(struct
>> rtl8169_private *tp)
>>>       }
>>>  }
>>>
>>> +static enum rtl_sfp_mode rtl_get_sfp_mode(struct rtl8169_private *tp)
>>> +{
>>> +     if (rtl_is_8125(tp)) {
>>> +             u16 data = r8168_mac_ocp_read(tp, 0xd006);
>>> +
>>> +             if ((data & 0xff) == 0x07)
>>> +                     return RTL_SFP_8127_ATF;
>>> +     } else if (rtl_is_8116af(tp)) {
>>> +             return RTL_SFP_8168_AF;
>>> +     }
>>> +
>>> +     return RTL_SFP_NONE;
>>> +}
>>> +
>>>  static enum rtl_dash_type rtl_get_dash_type(struct rtl8169_private
>>> *tp)  {
>>>       switch (tp->mac_version) {
>>> @@ -5693,12 +5751,7 @@ static int rtl_init_one(struct pci_dev *pdev, const
>> struct pci_device_id *ent)
>>>       }
>>>       tp->aspm_manageable = !rc;
>>>
>>> -     if (rtl_is_8125(tp)) {
>>> -             u16 data = r8168_mac_ocp_read(tp, 0xd006);
>>> -
>>> -             if ((data & 0xff) == 0x07)
>>> -                     tp->sfp_mode = true;
>>> -     }
>>> +     tp->sfp_mode = rtl_get_sfp_mode(tp);
>>>
>>>       tp->dash_type = rtl_get_dash_type(tp);
>>>       tp->dash_enabled = rtl_dash_is_enabled(tp);
> 


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

* Re: [PATCH net-next v1 4/4] r8169: enable system enter c10 with RTL8116af
  2026-03-04  9:43     ` 许俊伟
@ 2026-03-04 21:51       ` Heiner Kallweit
  2026-03-05 10:58         ` Javen
  0 siblings, 1 reply; 17+ messages in thread
From: Heiner Kallweit @ 2026-03-04 21:51 UTC (permalink / raw)
  To: 许俊伟, nic_swsd@realtek.com,
	andrew+netdev@lunn.ch, davem@davemloft.net, edumazet@google.com,
	kuba@kernel.org, pabeni@redhat.com, horms@kernel.org
  Cc: netdev@vger.kernel.org, linux-kernel@vger.kernel.org

On 04.03.2026 10:43, 许俊伟 wrote:
>> On 02.03.2026 07:32, javen wrote:
>>> From: Javen Xu <javen_xu@realsil.com.cn>
>>>
>>> RTL8116af is a multi function chip. Function 1 is load with r8169
>>> driver. Function 0 is bmc virual driver which is used for power
>>> management. This patch set Function 2 to 7 into d3 state when config
>>> hw_config. This helps the whole system enter c10.
>>>
>>> Signed-off-by: Javen Xu <javen_xu@realsil.com.cn>
>>> ---
>>>  drivers/net/ethernet/realtek/r8169_main.c | 95
>>> +++++++++++++++++++++++
>>>  1 file changed, 95 insertions(+)
>>>
>>> diff --git a/drivers/net/ethernet/realtek/r8169_main.c
>>> b/drivers/net/ethernet/realtek/r8169_main.c
>>> index 787859b0ab68..d8ffc76186b2 100644
>>> --- a/drivers/net/ethernet/realtek/r8169_main.c
>>> +++ b/drivers/net/ethernet/realtek/r8169_main.c
>>> @@ -1121,6 +1121,100 @@ DECLARE_RTL_COND(rtl_ocp_gphy_cond)
>>>       return RTL_R32(tp, GPHY_OCP) & OCPAR_FLAG;  }
>>>
>>> +static u32 rtl_other_csi_read(struct rtl8169_private *tp, u8
>>> +multi_fun_sel_bit, int addr) {
>>> +     RTL_W32(tp, CSIAR, (addr & CSIAR_ADDR_MASK) | multi_fun_sel_bit
>> << 16 |
>>> +             CSIAR_BYTE_ENABLE);
>>> +
>>> +     return rtl_loop_wait_high(tp, &rtl_csiar_cond, 10, 100) ?
>>> +             RTL_R32(tp, CSIDR) : ~0; }
>>> +
>>> +static void rtl_other_csi_write(struct rtl8169_private *tp,
>>> +                             u8 multi_fun_sel_bit,
>>> +                             int addr,
>>> +                             int value) {
>>> +     RTL_W32(tp, CSIDR, value);
>>> +     RTL_W32(tp, CSIAR, CSIAR_WRITE_CMD | (addr & CSIAR_ADDR_MASK)
>> |
>>> +             CSIAR_BYTE_ENABLE | multi_fun_sel_bit << 16);
>>> +
>>> +     rtl_loop_wait_low(tp, &rtl_csiar_cond, 10, 100); }
>>> +
>>> +static void rtl8168_clear_and_set_other_fun_pci_bit(struct rtl8169_private
>> *tp,
>>> +                                                 u8 multi_fun_sel_bit,
>>> +                                                 u32 addr,
>>> +                                                 u32 clearmask,
>>> +                                                 u32 setmask) {
>>> +     u32 val;
>>> +
>>> +     val = rtl_other_csi_read(tp, multi_fun_sel_bit, addr);
>>> +     val &= ~clearmask;
>>> +     val |= setmask;
>>> +     rtl_other_csi_write(tp, multi_fun_sel_bit, addr, val); }
>>> +
>>> +static void rtl8168_other_fun_dev_pci_setting(struct rtl8169_private *tp,
>>> +                                           u32 addr,
>>> +                                           u32 clearmask,
>>> +                                           u32 setmask,
>>> +                                           u8 multi_fun_sel_bit) {
>>> +     u32 val;
>>> +     u8 i;
>>> +     u8 FunBit;
>>> +     /* 0: BMC, 1: NIC, 2: TCR, 3: VGA/PCIE_TO_USB, 4: EHCI, 5: WIFI, 6: WIFI,
>> 7: KCS */
>>> +     for (i = 0; i < 8; i++) {
>>> +             FunBit = (1 << i);
>>> +             if (FunBit & multi_fun_sel_bit) {
>>> +                     u8 set_other_fun = true;
>>> +
>>> +                     if (i == 0) {
>>> +                             set_other_fun = true;
>>> +                     } else if (i == 5 || i == 6) {
>>> +                             if (tp->dash_enabled) {
>>> +                                     val = rtl_eri_read(tp, 0x184);
>>> +                                     if (val & BIT(26))
>>> +                                             set_other_fun = false;
>>> +                                     else
>>> +                                             set_other_fun = true;
>>> +                             }
>>> +                     } else {
>>> +                             val = rtl_other_csi_read(tp, i, 0x00);
>>> +                             if (val == 0xffffffff)
>>> +                                     set_other_fun = true;
>>> +                             else
>>> +                                     set_other_fun = false;
>>> +                     }
>>> +                     if (set_other_fun)
>>> +                             rtl8168_clear_and_set_other_fun_pci_bit(tp, i, addr,
>>> +                                                                     clearmask, setmask);
>>> +             }
>>> +     }
>>> +}
>>> +
>>> +static void rtl8168_set_dash_other_fun_dev_state_change(struct
>> rtl8169_private *tp,
>>> +                                                     u8 dev_state,
>>> +                                                     u8
>>> +multi_fun_sel_bit) {
>>> +     u32 clearmask;
>>> +     u32 setmask;
>>> +
>>> +     if (dev_state == 0) {
>>> +             clearmask = (BIT(0) | BIT(1));
>>> +             setmask = 0;
>>> +             rtl8168_other_fun_dev_pci_setting(tp, 0x44, clearmask,
>>> +                                               setmask, multi_fun_sel_bit);
>>> +     } else {
>>> +             clearmask = 0;
>>> +             setmask = (BIT(0) | BIT(1));
>>> +             rtl8168_other_fun_dev_pci_setting(tp, 0x44, clearmask,
>>> +                                               setmask, multi_fun_sel_bit);
>>> +     }
>>> +}
>>> +
>>>  static void r8168_phy_ocp_write(struct rtl8169_private *tp, u32 reg,
>>> u32 data)  {
>>>       if (rtl_ocp_reg_failure(reg))
>>> @@ -3785,6 +3879,7 @@ static void rtl_hw_start_8117(struct
>> rtl8169_private *tp)
>>>       r8168_mac_ocp_write(tp, 0xc094, 0x0000);
>>>       r8168_mac_ocp_write(tp, 0xc09e, 0x0000);
>>>
>>> +     rtl8168_set_dash_other_fun_dev_state_change(tp, 3, 0xfc);
>>>       /* firmware is for MAC only */
>>>       r8169_apply_firmware(tp);
>>>  }
>>
>> This is the type of code that would make r8169 become an unmaintainable
>> mess like the vendor drivers. Why not use standard means like
>> pci_bus_read_config_word() et al?
> 
> Thanks for the suggestion.
> I first tried to use lspci, but I can't find function 2-7 in pci system. Then I tried to
> use pci_bus_read_config_word() to access Function 2-7 and get result as below.
> 
> [21254.984983] RTL8168_DEBUG: Slot 0, Function 2, Read Vendor ID: 0xffffffff
> 
> This confirms that these funcitons are physically hidden from the PCI bus. They do
> not respond to standard PCI configuration cycles, this maybe the reason why standard
> PCI APIs cannot be used here.
> These functions are important for power state issue. When system suspends, linux PCI
> core automatically handles the power transition for the visible functions. But since
> function 2-7 is invisible, the kernel cannot manage it. As a result, we have no choice but
> to use the vendor-specific indirect access mechanism(via CSIAR register).
> 
I understand your pain adding mainline support for broken hw designs. I consider the chip
design fundamentally broken as PCI functions 2-7 are hidden and the ethernet driver is
expected to set power management states for e.g. the EHCI and WiFi functions.
As stated in another comment, the best option seems to me to add support for this chip
downstream only.

> Thanks,
> Javen Xu
> 


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

* RE: [PATCH net-next v1 4/4] r8169: enable system enter c10 with RTL8116af
  2026-03-04 21:51       ` Heiner Kallweit
@ 2026-03-05 10:58         ` Javen
  0 siblings, 0 replies; 17+ messages in thread
From: Javen @ 2026-03-05 10:58 UTC (permalink / raw)
  To: Heiner Kallweit, nic_swsd@realtek.com, andrew+netdev@lunn.ch,
	davem@davemloft.net, edumazet@google.com, kuba@kernel.org,
	pabeni@redhat.com, horms@kernel.org
  Cc: netdev@vger.kernel.org, linux-kernel@vger.kernel.org

>On 04.03.2026 10:43, 许俊伟 wrote:
>>> On 02.03.2026 07:32, javen wrote:
>>>> From: Javen Xu <javen_xu@realsil.com.cn>
>>>>
>>>> RTL8116af is a multi function chip. Function 1 is load with r8169
>>>> driver. Function 0 is bmc virual driver which is used for power
>>>> management. This patch set Function 2 to 7 into d3 state when config
>>>> hw_config. This helps the whole system enter c10.
>>>>
>>>> Signed-off-by: Javen Xu <javen_xu@realsil.com.cn>
>>>> ---
>>>>  drivers/net/ethernet/realtek/r8169_main.c | 95
>>>> +++++++++++++++++++++++
>>>>  1 file changed, 95 insertions(+)
>>>>
>>>> diff --git a/drivers/net/ethernet/realtek/r8169_main.c
>>>> b/drivers/net/ethernet/realtek/r8169_main.c
>>>> index 787859b0ab68..d8ffc76186b2 100644
>>>> --- a/drivers/net/ethernet/realtek/r8169_main.c
>>>> +++ b/drivers/net/ethernet/realtek/r8169_main.c
>>>> @@ -1121,6 +1121,100 @@ DECLARE_RTL_COND(rtl_ocp_gphy_cond)
>>>>       return RTL_R32(tp, GPHY_OCP) & OCPAR_FLAG;  }
>>>>
>>>> +static u32 rtl_other_csi_read(struct rtl8169_private *tp, u8
>>>> +multi_fun_sel_bit, int addr) {
>>>> +     RTL_W32(tp, CSIAR, (addr & CSIAR_ADDR_MASK) |
>>>> +multi_fun_sel_bit
>>> << 16 |
>>>> +             CSIAR_BYTE_ENABLE);
>>>> +
>>>> +     return rtl_loop_wait_high(tp, &rtl_csiar_cond, 10, 100) ?
>>>> +             RTL_R32(tp, CSIDR) : ~0; }
>>>> +
>>>> +static void rtl_other_csi_write(struct rtl8169_private *tp,
>>>> +                             u8 multi_fun_sel_bit,
>>>> +                             int addr,
>>>> +                             int value) {
>>>> +     RTL_W32(tp, CSIDR, value);
>>>> +     RTL_W32(tp, CSIAR, CSIAR_WRITE_CMD | (addr &
>CSIAR_ADDR_MASK)
>>> |
>>>> +             CSIAR_BYTE_ENABLE | multi_fun_sel_bit << 16);
>>>> +
>>>> +     rtl_loop_wait_low(tp, &rtl_csiar_cond, 10, 100); }
>>>> +
>>>> +static void rtl8168_clear_and_set_other_fun_pci_bit(struct
>>>> +rtl8169_private
>>> *tp,
>>>> +                                                 u8 multi_fun_sel_bit,
>>>> +                                                 u32 addr,
>>>> +                                                 u32 clearmask,
>>>> +                                                 u32 setmask) {
>>>> +     u32 val;
>>>> +
>>>> +     val = rtl_other_csi_read(tp, multi_fun_sel_bit, addr);
>>>> +     val &= ~clearmask;
>>>> +     val |= setmask;
>>>> +     rtl_other_csi_write(tp, multi_fun_sel_bit, addr, val); }
>>>> +
>>>> +static void rtl8168_other_fun_dev_pci_setting(struct rtl8169_private *tp,
>>>> +                                           u32 addr,
>>>> +                                           u32 clearmask,
>>>> +                                           u32 setmask,
>>>> +                                           u8 multi_fun_sel_bit) {
>>>> +     u32 val;
>>>> +     u8 i;
>>>> +     u8 FunBit;
>>>> +     /* 0: BMC, 1: NIC, 2: TCR, 3: VGA/PCIE_TO_USB, 4: EHCI, 5:
>>>> +WIFI, 6: WIFI,
>>> 7: KCS */
>>>> +     for (i = 0; i < 8; i++) {
>>>> +             FunBit = (1 << i);
>>>> +             if (FunBit & multi_fun_sel_bit) {
>>>> +                     u8 set_other_fun = true;
>>>> +
>>>> +                     if (i == 0) {
>>>> +                             set_other_fun = true;
>>>> +                     } else if (i == 5 || i == 6) {
>>>> +                             if (tp->dash_enabled) {
>>>> +                                     val = rtl_eri_read(tp, 0x184);
>>>> +                                     if (val & BIT(26))
>>>> +                                             set_other_fun = false;
>>>> +                                     else
>>>> +                                             set_other_fun = true;
>>>> +                             }
>>>> +                     } else {
>>>> +                             val = rtl_other_csi_read(tp, i, 0x00);
>>>> +                             if (val == 0xffffffff)
>>>> +                                     set_other_fun = true;
>>>> +                             else
>>>> +                                     set_other_fun = false;
>>>> +                     }
>>>> +                     if (set_other_fun)
>>>> +                             rtl8168_clear_and_set_other_fun_pci_bit(tp, i, addr,
>>>> +                                                                     clearmask, setmask);
>>>> +             }
>>>> +     }
>>>> +}
>>>> +
>>>> +static void rtl8168_set_dash_other_fun_dev_state_change(struct
>>> rtl8169_private *tp,
>>>> +                                                     u8 dev_state,
>>>> +                                                     u8
>>>> +multi_fun_sel_bit) {
>>>> +     u32 clearmask;
>>>> +     u32 setmask;
>>>> +
>>>> +     if (dev_state == 0) {
>>>> +             clearmask = (BIT(0) | BIT(1));
>>>> +             setmask = 0;
>>>> +             rtl8168_other_fun_dev_pci_setting(tp, 0x44, clearmask,
>>>> +                                               setmask, multi_fun_sel_bit);
>>>> +     } else {
>>>> +             clearmask = 0;
>>>> +             setmask = (BIT(0) | BIT(1));
>>>> +             rtl8168_other_fun_dev_pci_setting(tp, 0x44, clearmask,
>>>> +                                               setmask, multi_fun_sel_bit);
>>>> +     }
>>>> +}
>>>> +
>>>>  static void r8168_phy_ocp_write(struct rtl8169_private *tp, u32
>>>> reg,
>>>> u32 data)  {
>>>>       if (rtl_ocp_reg_failure(reg))
>>>> @@ -3785,6 +3879,7 @@ static void rtl_hw_start_8117(struct
>>> rtl8169_private *tp)
>>>>       r8168_mac_ocp_write(tp, 0xc094, 0x0000);
>>>>       r8168_mac_ocp_write(tp, 0xc09e, 0x0000);
>>>>
>>>> +     rtl8168_set_dash_other_fun_dev_state_change(tp, 3, 0xfc);
>>>>       /* firmware is for MAC only */
>>>>       r8169_apply_firmware(tp);
>>>>  }
>>>
>>> This is the type of code that would make r8169 become an
>>> unmaintainable mess like the vendor drivers. Why not use standard
>>> means like
>>> pci_bus_read_config_word() et al?
>>
>> Thanks for the suggestion.
>> I first tried to use lspci, but I can't find function 2-7 in pci
>> system. Then I tried to use pci_bus_read_config_word() to access Function
>2-7 and get result as below.
>>
>> [21254.984983] RTL8168_DEBUG: Slot 0, Function 2, Read Vendor ID:
>> 0xffffffff
>>
>> This confirms that these funcitons are physically hidden from the PCI
>> bus. They do not respond to standard PCI configuration cycles, this
>> maybe the reason why standard PCI APIs cannot be used here.
>> These functions are important for power state issue. When system
>> suspends, linux PCI core automatically handles the power transition
>> for the visible functions. But since function 2-7 is invisible, the
>> kernel cannot manage it. As a result, we have no choice but to use the
>vendor-specific indirect access mechanism(via CSIAR register).
>>
>I understand your pain adding mainline support for broken hw designs. I
>consider the chip design fundamentally broken as PCI functions 2-7 are hidden
>and the ethernet driver is expected to set power management states for e.g.
>the EHCI and WiFi functions.
>As stated in another comment, the best option seems to me to add support
>for this chip downstream only.

Thanks for your suggestion, I will take it into consideration.

Thanks,
Javen Xu


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

* RE: [PATCH net-next v1 2/4] r8169: add sfp mode for RTL8116af
  2026-03-02 22:07   ` Heiner Kallweit
  2026-03-04  8:16     ` 许俊伟
@ 2026-03-13  7:25     ` Javen
  2026-03-13 21:21       ` Heiner Kallweit
  1 sibling, 1 reply; 17+ messages in thread
From: Javen @ 2026-03-13  7:25 UTC (permalink / raw)
  To: Heiner Kallweit, nic_swsd@realtek.com, andrew+netdev@lunn.ch,
	davem@davemloft.net, edumazet@google.com, kuba@kernel.org,
	pabeni@redhat.com, horms@kernel.org
  Cc: netdev@vger.kernel.org, linux-kernel@vger.kernel.org

>On 02.03.2026 07:32, javen wrote:
>> From: Javen Xu <javen_xu@realsil.com.cn>
>>
>> RTL8116af is a variation of RTL8168fp. It uses SerDes instead of PHY.
>> But SerDes status will not relect to PHY. So it needs to add sfp mode
>> for quirk to help reflect SerDes status during PHY read.
>>
>
>Is there any mass market device using this chip version? As far as possible I'd
>like to avoid adding support for chip versions that never make it to the mass
>market. This just makes driver maintenance harder.
>
>The patch includes support for 100Mbps fiber mode. Is there any use case for
>such legacy modes?
>
>
>> Signed-off-by: Javen Xu <javen_xu@realsil.com.cn>
>> ---
>>  drivers/net/ethernet/realtek/r8169_main.c | 71
>> ++++++++++++++++++++---
>>  1 file changed, 62 insertions(+), 9 deletions(-)
>>
>> diff --git a/drivers/net/ethernet/realtek/r8169_main.c
>> b/drivers/net/ethernet/realtek/r8169_main.c
>> index fb2247a20c36..a5c0d3995328 100644
>> --- a/drivers/net/ethernet/realtek/r8169_main.c
>> +++ b/drivers/net/ethernet/realtek/r8169_main.c
>> @@ -726,6 +726,12 @@ enum rtl_dash_type {
>>       RTL_DASH_25_BP,
>>  };
>>
>> +enum rtl_sfp_mode {
>> +     RTL_SFP_NONE,
>> +     RTL_SFP_8168_AF,
>> +     RTL_SFP_8127_ATF,
>> +};
>> +
>>  struct rtl8169_private {
>>       void __iomem *mmio_addr;        /* memory map physical address */
>>       struct pci_dev *pci_dev;
>> @@ -734,6 +740,7 @@ struct rtl8169_private {
>>       struct napi_struct napi;
>>       enum mac_version mac_version;
>>       enum rtl_dash_type dash_type;
>> +     enum rtl_sfp_mode sfp_mode;
>>       u32 cur_rx; /* Index into the Rx descriptor buffer of next Rx pkt. */
>>       u32 cur_tx; /* Index into the Tx descriptor buffer of next Rx pkt. */
>>       u32 dirty_tx;
>> @@ -760,7 +767,6 @@ struct rtl8169_private {
>>       unsigned supports_gmii:1;
>>       unsigned aspm_manageable:1;
>>       unsigned dash_enabled:1;
>> -     bool sfp_mode:1;
>>       dma_addr_t counters_phys_addr;
>>       struct rtl8169_counters *counters;
>>       struct rtl8169_tc_offsets tc_offset; @@ -1126,7 +1132,7 @@
>> static int r8168_phy_ocp_read(struct rtl8169_private *tp, u32 reg)
>>               return 0;
>>
>>       /* Return dummy MII_PHYSID2 in SFP mode to match SFP PHY driver */
>> -     if (tp->sfp_mode && reg == (OCP_STD_PHY_BASE + 2 * MII_PHYSID2))
>> +     if (tp->sfp_mode == RTL_SFP_8127_ATF && reg ==
>(OCP_STD_PHY_BASE
>> + + 2 * MII_PHYSID2))
>>               return PHY_ID_RTL_DUMMY_SFP & 0xffff;
>>
>>       RTL_W32(tp, GPHY_OCP, reg << 15); @@ -1270,6 +1276,34 @@ static
>> int r8168g_mdio_read(struct rtl8169_private *tp, int reg)
>>       return r8168_phy_ocp_read(tp, tp->ocp_base + reg * 2);  }
>>
>> +/* The quirk reflects RTL8116af SerDes status. */ static int
>> +r8116af_mdio_read_quirk(struct rtl8169_private *tp, int reg) {
>> +     u8 phyStatus = RTL_R8(tp, PHYstatus);
>> +
>> +     if (!(phyStatus & LinkStatus))
>> +             return 0;
>> +
>> +     /* BMSR */
>> +     if (tp->ocp_base == OCP_STD_PHY_BASE && reg == MII_BMSR)
>> +             return BMSR_ANEGCOMPLETE | BMSR_LSTATUS;
>> +
>> +     /* PHYSR */
>> +     if (tp->ocp_base == 0xa430 && reg == 0x12) {
>> +             if (phyStatus & _1000bpsF)
>> +                     return 0x0028;
>> +             else if (phyStatus & _100bps)
>> +                     return 0x0018;
>
>This is a complete hack. Any means to access the SerDes directly?

Hi, Heiner
Now we find a indirect access to serdes reg. The serdes reg is designed according to IEEE 802.3.
BIT 2 means Link Status and BIT 5 means ANEGCOMPLETE. We can access it through read mac ocp
0xeb14, I wonder whether this indirect access can be accepted?

Thanks,
Javen Xu

>
>> +     }
>> +
>> +     return 0;
>> +}
>> +
>> +static int r8116af_mdio_read(struct rtl8169_private *tp, int reg) {
>> +     return r8168g_mdio_read(tp, reg) | r8116af_mdio_read_quirk(tp,
>> +reg); }
>> +
>>  static void mac_mcu_write(struct rtl8169_private *tp, int reg, int
>> value)  {
>>       if (reg == 0x1f) {
>> @@ -1280,6 +1314,13 @@ static void mac_mcu_write(struct rtl8169_private
>*tp, int reg, int value)
>>       r8168_mac_ocp_write(tp, tp->ocp_base + reg, value);  }
>>
>> +static bool rtl_is_8116af(struct rtl8169_private *tp) {
>> +     return tp->mac_version == RTL_GIGA_MAC_VER_52 &&
>> +             (r8168_mac_ocp_read(tp, 0xdc00) & 0x0078) == 0x0030 &&
>> +             (r8168_mac_ocp_read(tp, 0xd006) & 0x00ff) == 0x0000; }
>> +
>>  static int mac_mcu_read(struct rtl8169_private *tp, int reg)  {
>>       return r8168_mac_ocp_read(tp, tp->ocp_base + reg); @@ -1386,7
>> +1427,10 @@ static int rtl_readphy(struct rtl8169_private *tp, int location)
>>       case RTL_GIGA_MAC_VER_31:
>>               return r8168dp_2_mdio_read(tp, location);
>>       case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_LAST:
>> -             return r8168g_mdio_read(tp, location);
>> +             if (tp->sfp_mode == RTL_SFP_8168_AF)
>> +                     return r8116af_mdio_read(tp, location);
>> +             else
>> +                     return r8168g_mdio_read(tp, location);
>>       default:
>>               return r8169_mdio_read(tp, location);
>>       }
>> @@ -1575,6 +1619,20 @@ static bool rtl_dash_is_enabled(struct
>rtl8169_private *tp)
>>       }
>>  }
>>
>> +static enum rtl_sfp_mode rtl_get_sfp_mode(struct rtl8169_private *tp)
>> +{
>> +     if (rtl_is_8125(tp)) {
>> +             u16 data = r8168_mac_ocp_read(tp, 0xd006);
>> +
>> +             if ((data & 0xff) == 0x07)
>> +                     return RTL_SFP_8127_ATF;
>> +     } else if (rtl_is_8116af(tp)) {
>> +             return RTL_SFP_8168_AF;
>> +     }
>> +
>> +     return RTL_SFP_NONE;
>> +}
>> +
>>  static enum rtl_dash_type rtl_get_dash_type(struct rtl8169_private
>> *tp)  {
>>       switch (tp->mac_version) {
>> @@ -5693,12 +5751,7 @@ static int rtl_init_one(struct pci_dev *pdev, const
>struct pci_device_id *ent)
>>       }
>>       tp->aspm_manageable = !rc;
>>
>> -     if (rtl_is_8125(tp)) {
>> -             u16 data = r8168_mac_ocp_read(tp, 0xd006);
>> -
>> -             if ((data & 0xff) == 0x07)
>> -                     tp->sfp_mode = true;
>> -     }
>> +     tp->sfp_mode = rtl_get_sfp_mode(tp);
>>
>>       tp->dash_type = rtl_get_dash_type(tp);
>>       tp->dash_enabled = rtl_dash_is_enabled(tp);


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

* Re: [PATCH net-next v1 2/4] r8169: add sfp mode for RTL8116af
  2026-03-13  7:25     ` Javen
@ 2026-03-13 21:21       ` Heiner Kallweit
  2026-03-17  3:14         ` Javen
  0 siblings, 1 reply; 17+ messages in thread
From: Heiner Kallweit @ 2026-03-13 21:21 UTC (permalink / raw)
  To: Javen, nic_swsd@realtek.com, andrew+netdev@lunn.ch,
	davem@davemloft.net, edumazet@google.com, kuba@kernel.org,
	pabeni@redhat.com, horms@kernel.org
  Cc: netdev@vger.kernel.org, linux-kernel@vger.kernel.org

On 13.03.2026 08:25, Javen wrote:
>> On 02.03.2026 07:32, javen wrote:
>>> From: Javen Xu <javen_xu@realsil.com.cn>
>>>
>>> RTL8116af is a variation of RTL8168fp. It uses SerDes instead of PHY.
>>> But SerDes status will not relect to PHY. So it needs to add sfp mode
>>> for quirk to help reflect SerDes status during PHY read.
>>>
>>
>> Is there any mass market device using this chip version? As far as possible I'd
>> like to avoid adding support for chip versions that never make it to the mass
>> market. This just makes driver maintenance harder.
>>
>> The patch includes support for 100Mbps fiber mode. Is there any use case for
>> such legacy modes?
>>
>>
>>> Signed-off-by: Javen Xu <javen_xu@realsil.com.cn>
>>> ---
>>>  drivers/net/ethernet/realtek/r8169_main.c | 71
>>> ++++++++++++++++++++---
>>>  1 file changed, 62 insertions(+), 9 deletions(-)
>>>
>>> diff --git a/drivers/net/ethernet/realtek/r8169_main.c
>>> b/drivers/net/ethernet/realtek/r8169_main.c
>>> index fb2247a20c36..a5c0d3995328 100644
>>> --- a/drivers/net/ethernet/realtek/r8169_main.c
>>> +++ b/drivers/net/ethernet/realtek/r8169_main.c
>>> @@ -726,6 +726,12 @@ enum rtl_dash_type {
>>>       RTL_DASH_25_BP,
>>>  };
>>>
>>> +enum rtl_sfp_mode {
>>> +     RTL_SFP_NONE,
>>> +     RTL_SFP_8168_AF,
>>> +     RTL_SFP_8127_ATF,
>>> +};
>>> +
>>>  struct rtl8169_private {
>>>       void __iomem *mmio_addr;        /* memory map physical address */
>>>       struct pci_dev *pci_dev;
>>> @@ -734,6 +740,7 @@ struct rtl8169_private {
>>>       struct napi_struct napi;
>>>       enum mac_version mac_version;
>>>       enum rtl_dash_type dash_type;
>>> +     enum rtl_sfp_mode sfp_mode;
>>>       u32 cur_rx; /* Index into the Rx descriptor buffer of next Rx pkt. */
>>>       u32 cur_tx; /* Index into the Tx descriptor buffer of next Rx pkt. */
>>>       u32 dirty_tx;
>>> @@ -760,7 +767,6 @@ struct rtl8169_private {
>>>       unsigned supports_gmii:1;
>>>       unsigned aspm_manageable:1;
>>>       unsigned dash_enabled:1;
>>> -     bool sfp_mode:1;
>>>       dma_addr_t counters_phys_addr;
>>>       struct rtl8169_counters *counters;
>>>       struct rtl8169_tc_offsets tc_offset; @@ -1126,7 +1132,7 @@
>>> static int r8168_phy_ocp_read(struct rtl8169_private *tp, u32 reg)
>>>               return 0;
>>>
>>>       /* Return dummy MII_PHYSID2 in SFP mode to match SFP PHY driver */
>>> -     if (tp->sfp_mode && reg == (OCP_STD_PHY_BASE + 2 * MII_PHYSID2))
>>> +     if (tp->sfp_mode == RTL_SFP_8127_ATF && reg ==
>> (OCP_STD_PHY_BASE
>>> + + 2 * MII_PHYSID2))
>>>               return PHY_ID_RTL_DUMMY_SFP & 0xffff;
>>>
>>>       RTL_W32(tp, GPHY_OCP, reg << 15); @@ -1270,6 +1276,34 @@ static
>>> int r8168g_mdio_read(struct rtl8169_private *tp, int reg)
>>>       return r8168_phy_ocp_read(tp, tp->ocp_base + reg * 2);  }
>>>
>>> +/* The quirk reflects RTL8116af SerDes status. */ static int
>>> +r8116af_mdio_read_quirk(struct rtl8169_private *tp, int reg) {
>>> +     u8 phyStatus = RTL_R8(tp, PHYstatus);
>>> +
>>> +     if (!(phyStatus & LinkStatus))
>>> +             return 0;
>>> +
>>> +     /* BMSR */
>>> +     if (tp->ocp_base == OCP_STD_PHY_BASE && reg == MII_BMSR)
>>> +             return BMSR_ANEGCOMPLETE | BMSR_LSTATUS;
>>> +
>>> +     /* PHYSR */
>>> +     if (tp->ocp_base == 0xa430 && reg == 0x12) {
>>> +             if (phyStatus & _1000bpsF)
>>> +                     return 0x0028;
>>> +             else if (phyStatus & _100bps)
>>> +                     return 0x0018;
>>
>> This is a complete hack. Any means to access the SerDes directly?
> 
> Hi, Heiner
> Now we find a indirect access to serdes reg. The serdes reg is designed according to IEEE 802.3.
> BIT 2 means Link Status and BIT 5 means ANEGCOMPLETE. We can access it through read mac ocp
> 0xeb14, I wonder whether this indirect access can be accepted?
> 
Based on the bit numbers this seems to be the BMSR register. Can all clause 22 registers be
accessed in a similar way so that a MII bus can be implemented for accessing the SerDes?
In general it's hard to provide a statement w/o knowing the internal layout of the IP blocks.
Can you provide any chip documentation / datasheet?
For proper support of such a component chain between MAC and SFP port the driver would have
to be converted to use phylink, what requires access to the involved components, incl. the
SFP I2C bus.


> Thanks,
> Javen Xu
> 
>>
>>> +     }
>>> +
>>> +     return 0;
>>> +}
>>> +
>>> +static int r8116af_mdio_read(struct rtl8169_private *tp, int reg) {
>>> +     return r8168g_mdio_read(tp, reg) | r8116af_mdio_read_quirk(tp,
>>> +reg); }
>>> +
>>>  static void mac_mcu_write(struct rtl8169_private *tp, int reg, int
>>> value)  {
>>>       if (reg == 0x1f) {
>>> @@ -1280,6 +1314,13 @@ static void mac_mcu_write(struct rtl8169_private
>> *tp, int reg, int value)
>>>       r8168_mac_ocp_write(tp, tp->ocp_base + reg, value);  }
>>>
>>> +static bool rtl_is_8116af(struct rtl8169_private *tp) {
>>> +     return tp->mac_version == RTL_GIGA_MAC_VER_52 &&
>>> +             (r8168_mac_ocp_read(tp, 0xdc00) & 0x0078) == 0x0030 &&
>>> +             (r8168_mac_ocp_read(tp, 0xd006) & 0x00ff) == 0x0000; }
>>> +
>>>  static int mac_mcu_read(struct rtl8169_private *tp, int reg)  {
>>>       return r8168_mac_ocp_read(tp, tp->ocp_base + reg); @@ -1386,7
>>> +1427,10 @@ static int rtl_readphy(struct rtl8169_private *tp, int location)
>>>       case RTL_GIGA_MAC_VER_31:
>>>               return r8168dp_2_mdio_read(tp, location);
>>>       case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_LAST:
>>> -             return r8168g_mdio_read(tp, location);
>>> +             if (tp->sfp_mode == RTL_SFP_8168_AF)
>>> +                     return r8116af_mdio_read(tp, location);
>>> +             else
>>> +                     return r8168g_mdio_read(tp, location);
>>>       default:
>>>               return r8169_mdio_read(tp, location);
>>>       }
>>> @@ -1575,6 +1619,20 @@ static bool rtl_dash_is_enabled(struct
>> rtl8169_private *tp)
>>>       }
>>>  }
>>>
>>> +static enum rtl_sfp_mode rtl_get_sfp_mode(struct rtl8169_private *tp)
>>> +{
>>> +     if (rtl_is_8125(tp)) {
>>> +             u16 data = r8168_mac_ocp_read(tp, 0xd006);
>>> +
>>> +             if ((data & 0xff) == 0x07)
>>> +                     return RTL_SFP_8127_ATF;
>>> +     } else if (rtl_is_8116af(tp)) {
>>> +             return RTL_SFP_8168_AF;
>>> +     }
>>> +
>>> +     return RTL_SFP_NONE;
>>> +}
>>> +
>>>  static enum rtl_dash_type rtl_get_dash_type(struct rtl8169_private
>>> *tp)  {
>>>       switch (tp->mac_version) {
>>> @@ -5693,12 +5751,7 @@ static int rtl_init_one(struct pci_dev *pdev, const
>> struct pci_device_id *ent)
>>>       }
>>>       tp->aspm_manageable = !rc;
>>>
>>> -     if (rtl_is_8125(tp)) {
>>> -             u16 data = r8168_mac_ocp_read(tp, 0xd006);
>>> -
>>> -             if ((data & 0xff) == 0x07)
>>> -                     tp->sfp_mode = true;
>>> -     }
>>> +     tp->sfp_mode = rtl_get_sfp_mode(tp);
>>>
>>>       tp->dash_type = rtl_get_dash_type(tp);
>>>       tp->dash_enabled = rtl_dash_is_enabled(tp);
> 


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

* RE: [PATCH net-next v1 2/4] r8169: add sfp mode for RTL8116af
  2026-03-13 21:21       ` Heiner Kallweit
@ 2026-03-17  3:14         ` Javen
  2026-03-18 21:45           ` Heiner Kallweit
  0 siblings, 1 reply; 17+ messages in thread
From: Javen @ 2026-03-17  3:14 UTC (permalink / raw)
  To: Heiner Kallweit, nic_swsd@realtek.com, andrew+netdev@lunn.ch,
	davem@davemloft.net, edumazet@google.com, kuba@kernel.org,
	pabeni@redhat.com, horms@kernel.org
  Cc: netdev@vger.kernel.org, linux-kernel@vger.kernel.org

>On 13.03.2026 08:25, Javen wrote:
>>> On 02.03.2026 07:32, javen wrote:
>>>> From: Javen Xu <javen_xu@realsil.com.cn>
>>>>
>>>> RTL8116af is a variation of RTL8168fp. It uses SerDes instead of PHY.
>>>> But SerDes status will not relect to PHY. So it needs to add sfp
>>>> mode for quirk to help reflect SerDes status during PHY read.
>>>>
>>>
>>> Is there any mass market device using this chip version? As far as
>>> possible I'd like to avoid adding support for chip versions that
>>> never make it to the mass market. This just makes driver maintenance
>harder.
>>>
>>> The patch includes support for 100Mbps fiber mode. Is there any use
>>> case for such legacy modes?
>>>
>>>
>>>> Signed-off-by: Javen Xu <javen_xu@realsil.com.cn>
>>>> ---
>>>>  drivers/net/ethernet/realtek/r8169_main.c | 71
>>>> ++++++++++++++++++++---
>>>>  1 file changed, 62 insertions(+), 9 deletions(-)
>>>>
>>>> diff --git a/drivers/net/ethernet/realtek/r8169_main.c
>>>> b/drivers/net/ethernet/realtek/r8169_main.c
>>>> index fb2247a20c36..a5c0d3995328 100644
>>>> --- a/drivers/net/ethernet/realtek/r8169_main.c
>>>> +++ b/drivers/net/ethernet/realtek/r8169_main.c
>>>> @@ -726,6 +726,12 @@ enum rtl_dash_type {
>>>>       RTL_DASH_25_BP,
>>>>  };
>>>>
>>>> +enum rtl_sfp_mode {
>>>> +     RTL_SFP_NONE,
>>>> +     RTL_SFP_8168_AF,
>>>> +     RTL_SFP_8127_ATF,
>>>> +};
>>>> +
>>>>  struct rtl8169_private {
>>>>       void __iomem *mmio_addr;        /* memory map physical address */
>>>>       struct pci_dev *pci_dev;
>>>> @@ -734,6 +740,7 @@ struct rtl8169_private {
>>>>       struct napi_struct napi;
>>>>       enum mac_version mac_version;
>>>>       enum rtl_dash_type dash_type;
>>>> +     enum rtl_sfp_mode sfp_mode;
>>>>       u32 cur_rx; /* Index into the Rx descriptor buffer of next Rx pkt. */
>>>>       u32 cur_tx; /* Index into the Tx descriptor buffer of next Rx pkt. */
>>>>       u32 dirty_tx;
>>>> @@ -760,7 +767,6 @@ struct rtl8169_private {
>>>>       unsigned supports_gmii:1;
>>>>       unsigned aspm_manageable:1;
>>>>       unsigned dash_enabled:1;
>>>> -     bool sfp_mode:1;
>>>>       dma_addr_t counters_phys_addr;
>>>>       struct rtl8169_counters *counters;
>>>>       struct rtl8169_tc_offsets tc_offset; @@ -1126,7 +1132,7 @@
>>>> static int r8168_phy_ocp_read(struct rtl8169_private *tp, u32 reg)
>>>>               return 0;
>>>>
>>>>       /* Return dummy MII_PHYSID2 in SFP mode to match SFP PHY driver
>*/
>>>> -     if (tp->sfp_mode && reg == (OCP_STD_PHY_BASE + 2 * MII_PHYSID2))
>>>> +     if (tp->sfp_mode == RTL_SFP_8127_ATF && reg ==
>>> (OCP_STD_PHY_BASE
>>>> + + 2 * MII_PHYSID2))
>>>>               return PHY_ID_RTL_DUMMY_SFP & 0xffff;
>>>>
>>>>       RTL_W32(tp, GPHY_OCP, reg << 15); @@ -1270,6 +1276,34 @@
>>>> static int r8168g_mdio_read(struct rtl8169_private *tp, int reg)
>>>>       return r8168_phy_ocp_read(tp, tp->ocp_base + reg * 2);  }
>>>>
>>>> +/* The quirk reflects RTL8116af SerDes status. */ static int
>>>> +r8116af_mdio_read_quirk(struct rtl8169_private *tp, int reg) {
>>>> +     u8 phyStatus = RTL_R8(tp, PHYstatus);
>>>> +
>>>> +     if (!(phyStatus & LinkStatus))
>>>> +             return 0;
>>>> +
>>>> +     /* BMSR */
>>>> +     if (tp->ocp_base == OCP_STD_PHY_BASE && reg == MII_BMSR)
>>>> +             return BMSR_ANEGCOMPLETE | BMSR_LSTATUS;
>>>> +
>>>> +     /* PHYSR */
>>>> +     if (tp->ocp_base == 0xa430 && reg == 0x12) {
>>>> +             if (phyStatus & _1000bpsF)
>>>> +                     return 0x0028;
>>>> +             else if (phyStatus & _100bps)
>>>> +                     return 0x0018;
>>>
>>> This is a complete hack. Any means to access the SerDes directly?
>>
>> Hi, Heiner
>> Now we find a indirect access to serdes reg. The serdes reg is designed
>according to IEEE 802.3.
>> BIT 2 means Link Status and BIT 5 means ANEGCOMPLETE. We can access it
>> through read mac ocp 0xeb14, I wonder whether this indirect access can be
>accepted?
>>
>Based on the bit numbers this seems to be the BMSR register. Can all clause
>22 registers be accessed in a similar way so that a MII bus can be implemented
>for accessing the SerDes?

We checked our chip documentation and confirmed that the SerDes register file maps
all clause 22 registers(e.g. WR 0xeb10<reg_addr>, RD 0xeb14. reg_addr 0x40 is for BMCR,
0x41 for BMSR, 0x42 for PHYSID1, 0x43 for PHYSID2, etc.)
As you suggested, I wonder whether the proper approach is to implement a virtual mii_bus
and map the standard serdes reg in the new map.

Thanks,
Javen Xu

>In general it's hard to provide a statement w/o knowing the internal layout of
>the IP blocks.
>Can you provide any chip documentation / datasheet?
>For proper support of such a component chain between MAC and SFP port
>the driver would have to be converted to use phylink, what requires access to
>the involved components, incl. the SFP I2C bus.
>
>
>> Thanks,
>> Javen Xu
>>
>>>
>>>> +     }
>>>> +
>>>> +     return 0;
>>>> +}
>>>> +
>>>> +static int r8116af_mdio_read(struct rtl8169_private *tp, int reg) {
>>>> +     return r8168g_mdio_read(tp, reg) | r8116af_mdio_read_quirk(tp,
>>>> +reg); }
>>>> +
>>>>  static void mac_mcu_write(struct rtl8169_private *tp, int reg, int
>>>> value)  {
>>>>       if (reg == 0x1f) {
>>>> @@ -1280,6 +1314,13 @@ static void mac_mcu_write(struct
>>>> rtl8169_private
>>> *tp, int reg, int value)
>>>>       r8168_mac_ocp_write(tp, tp->ocp_base + reg, value);  }
>>>>
>>>> +static bool rtl_is_8116af(struct rtl8169_private *tp) {
>>>> +     return tp->mac_version == RTL_GIGA_MAC_VER_52 &&
>>>> +             (r8168_mac_ocp_read(tp, 0xdc00) & 0x0078) == 0x0030 &&
>>>> +             (r8168_mac_ocp_read(tp, 0xd006) & 0x00ff) == 0x0000; }
>>>> +
>>>>  static int mac_mcu_read(struct rtl8169_private *tp, int reg)  {
>>>>       return r8168_mac_ocp_read(tp, tp->ocp_base + reg); @@ -1386,7
>>>> +1427,10 @@ static int rtl_readphy(struct rtl8169_private *tp, int
>>>> +location)
>>>>       case RTL_GIGA_MAC_VER_31:
>>>>               return r8168dp_2_mdio_read(tp, location);
>>>>       case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_LAST:
>>>> -             return r8168g_mdio_read(tp, location);
>>>> +             if (tp->sfp_mode == RTL_SFP_8168_AF)
>>>> +                     return r8116af_mdio_read(tp, location);
>>>> +             else
>>>> +                     return r8168g_mdio_read(tp, location);
>>>>       default:
>>>>               return r8169_mdio_read(tp, location);
>>>>       }
>>>> @@ -1575,6 +1619,20 @@ static bool rtl_dash_is_enabled(struct
>>> rtl8169_private *tp)
>>>>       }
>>>>  }
>>>>
>>>> +static enum rtl_sfp_mode rtl_get_sfp_mode(struct rtl8169_private
>>>> +*tp) {
>>>> +     if (rtl_is_8125(tp)) {
>>>> +             u16 data = r8168_mac_ocp_read(tp, 0xd006);
>>>> +
>>>> +             if ((data & 0xff) == 0x07)
>>>> +                     return RTL_SFP_8127_ATF;
>>>> +     } else if (rtl_is_8116af(tp)) {
>>>> +             return RTL_SFP_8168_AF;
>>>> +     }
>>>> +
>>>> +     return RTL_SFP_NONE;
>>>> +}
>>>> +
>>>>  static enum rtl_dash_type rtl_get_dash_type(struct rtl8169_private
>>>> *tp)  {
>>>>       switch (tp->mac_version) {
>>>> @@ -5693,12 +5751,7 @@ static int rtl_init_one(struct pci_dev *pdev,
>>>> const
>>> struct pci_device_id *ent)
>>>>       }
>>>>       tp->aspm_manageable = !rc;
>>>>
>>>> -     if (rtl_is_8125(tp)) {
>>>> -             u16 data = r8168_mac_ocp_read(tp, 0xd006);
>>>> -
>>>> -             if ((data & 0xff) == 0x07)
>>>> -                     tp->sfp_mode = true;
>>>> -     }
>>>> +     tp->sfp_mode = rtl_get_sfp_mode(tp);
>>>>
>>>>       tp->dash_type = rtl_get_dash_type(tp);
>>>>       tp->dash_enabled = rtl_dash_is_enabled(tp);
>>


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

* Re: [PATCH net-next v1 2/4] r8169: add sfp mode for RTL8116af
  2026-03-17  3:14         ` Javen
@ 2026-03-18 21:45           ` Heiner Kallweit
  2026-03-19 17:09             ` Andrew Lunn
  0 siblings, 1 reply; 17+ messages in thread
From: Heiner Kallweit @ 2026-03-18 21:45 UTC (permalink / raw)
  To: Javen, nic_swsd@realtek.com, andrew+netdev@lunn.ch,
	davem@davemloft.net, edumazet@google.com, kuba@kernel.org,
	pabeni@redhat.com, horms@kernel.org
  Cc: netdev@vger.kernel.org, linux-kernel@vger.kernel.org

On 17.03.2026 04:14, Javen wrote:
>> On 13.03.2026 08:25, Javen wrote:
>>>> On 02.03.2026 07:32, javen wrote:
>>>>> From: Javen Xu <javen_xu@realsil.com.cn>
>>>>>
>>>>> RTL8116af is a variation of RTL8168fp. It uses SerDes instead of PHY.
>>>>> But SerDes status will not relect to PHY. So it needs to add sfp
>>>>> mode for quirk to help reflect SerDes status during PHY read.
>>>>>
>>>>
>>>> Is there any mass market device using this chip version? As far as
>>>> possible I'd like to avoid adding support for chip versions that
>>>> never make it to the mass market. This just makes driver maintenance
>> harder.
>>>>
>>>> The patch includes support for 100Mbps fiber mode. Is there any use
>>>> case for such legacy modes?
>>>>
>>>>
>>>>> Signed-off-by: Javen Xu <javen_xu@realsil.com.cn>
>>>>> ---
>>>>>  drivers/net/ethernet/realtek/r8169_main.c | 71
>>>>> ++++++++++++++++++++---
>>>>>  1 file changed, 62 insertions(+), 9 deletions(-)
>>>>>
>>>>> diff --git a/drivers/net/ethernet/realtek/r8169_main.c
>>>>> b/drivers/net/ethernet/realtek/r8169_main.c
>>>>> index fb2247a20c36..a5c0d3995328 100644
>>>>> --- a/drivers/net/ethernet/realtek/r8169_main.c
>>>>> +++ b/drivers/net/ethernet/realtek/r8169_main.c
>>>>> @@ -726,6 +726,12 @@ enum rtl_dash_type {
>>>>>       RTL_DASH_25_BP,
>>>>>  };
>>>>>
>>>>> +enum rtl_sfp_mode {
>>>>> +     RTL_SFP_NONE,
>>>>> +     RTL_SFP_8168_AF,
>>>>> +     RTL_SFP_8127_ATF,
>>>>> +};
>>>>> +
>>>>>  struct rtl8169_private {
>>>>>       void __iomem *mmio_addr;        /* memory map physical address */
>>>>>       struct pci_dev *pci_dev;
>>>>> @@ -734,6 +740,7 @@ struct rtl8169_private {
>>>>>       struct napi_struct napi;
>>>>>       enum mac_version mac_version;
>>>>>       enum rtl_dash_type dash_type;
>>>>> +     enum rtl_sfp_mode sfp_mode;
>>>>>       u32 cur_rx; /* Index into the Rx descriptor buffer of next Rx pkt. */
>>>>>       u32 cur_tx; /* Index into the Tx descriptor buffer of next Rx pkt. */
>>>>>       u32 dirty_tx;
>>>>> @@ -760,7 +767,6 @@ struct rtl8169_private {
>>>>>       unsigned supports_gmii:1;
>>>>>       unsigned aspm_manageable:1;
>>>>>       unsigned dash_enabled:1;
>>>>> -     bool sfp_mode:1;
>>>>>       dma_addr_t counters_phys_addr;
>>>>>       struct rtl8169_counters *counters;
>>>>>       struct rtl8169_tc_offsets tc_offset; @@ -1126,7 +1132,7 @@
>>>>> static int r8168_phy_ocp_read(struct rtl8169_private *tp, u32 reg)
>>>>>               return 0;
>>>>>
>>>>>       /* Return dummy MII_PHYSID2 in SFP mode to match SFP PHY driver
>> */
>>>>> -     if (tp->sfp_mode && reg == (OCP_STD_PHY_BASE + 2 * MII_PHYSID2))
>>>>> +     if (tp->sfp_mode == RTL_SFP_8127_ATF && reg ==
>>>> (OCP_STD_PHY_BASE
>>>>> + + 2 * MII_PHYSID2))
>>>>>               return PHY_ID_RTL_DUMMY_SFP & 0xffff;
>>>>>
>>>>>       RTL_W32(tp, GPHY_OCP, reg << 15); @@ -1270,6 +1276,34 @@
>>>>> static int r8168g_mdio_read(struct rtl8169_private *tp, int reg)
>>>>>       return r8168_phy_ocp_read(tp, tp->ocp_base + reg * 2);  }
>>>>>
>>>>> +/* The quirk reflects RTL8116af SerDes status. */ static int
>>>>> +r8116af_mdio_read_quirk(struct rtl8169_private *tp, int reg) {
>>>>> +     u8 phyStatus = RTL_R8(tp, PHYstatus);
>>>>> +
>>>>> +     if (!(phyStatus & LinkStatus))
>>>>> +             return 0;
>>>>> +
>>>>> +     /* BMSR */
>>>>> +     if (tp->ocp_base == OCP_STD_PHY_BASE && reg == MII_BMSR)
>>>>> +             return BMSR_ANEGCOMPLETE | BMSR_LSTATUS;
>>>>> +
>>>>> +     /* PHYSR */
>>>>> +     if (tp->ocp_base == 0xa430 && reg == 0x12) {
>>>>> +             if (phyStatus & _1000bpsF)
>>>>> +                     return 0x0028;
>>>>> +             else if (phyStatus & _100bps)
>>>>> +                     return 0x0018;
>>>>
>>>> This is a complete hack. Any means to access the SerDes directly?
>>>
>>> Hi, Heiner
>>> Now we find a indirect access to serdes reg. The serdes reg is designed
>> according to IEEE 802.3.
>>> BIT 2 means Link Status and BIT 5 means ANEGCOMPLETE. We can access it
>>> through read mac ocp 0xeb14, I wonder whether this indirect access can be
>> accepted?
>>>
>> Based on the bit numbers this seems to be the BMSR register. Can all clause
>> 22 registers be accessed in a similar way so that a MII bus can be implemented
>> for accessing the SerDes?
> 
> We checked our chip documentation and confirmed that the SerDes register file maps
> all clause 22 registers(e.g. WR 0xeb10<reg_addr>, RD 0xeb14. reg_addr 0x40 is for BMCR,
> 0x41 for BMSR, 0x42 for PHYSID1, 0x43 for PHYSID2, etc.)
> As you suggested, I wonder whether the proper approach is to implement a virtual mii_bus
> and map the standard serdes reg in the new map.
> 
We'd need to know how the internal PHY and the SerDes play together.
Whether the usual internal PHY plays any role in communication between MAC and SerDes.
How interface modes are controlled on MAC and SerDes side, etc.
If Realtek doesn't implement proper layering in hw, and doesn't have enough knowledge
about mainline network driver structures, and on the other hand doesn't want to provide
chip documentation, then the situation somewhat deadlocks.

> Thanks,
> Javen Xu
> 
>> In general it's hard to provide a statement w/o knowing the internal layout of
>> the IP blocks.
>> Can you provide any chip documentation / datasheet?
>> For proper support of such a component chain between MAC and SFP port
>> the driver would have to be converted to use phylink, what requires access to
>> the involved components, incl. the SFP I2C bus.
>>
>>
>>> Thanks,
>>> Javen Xu
>>>
>>>>
>>>>> +     }
>>>>> +
>>>>> +     return 0;
>>>>> +}
>>>>> +
>>>>> +static int r8116af_mdio_read(struct rtl8169_private *tp, int reg) {
>>>>> +     return r8168g_mdio_read(tp, reg) | r8116af_mdio_read_quirk(tp,
>>>>> +reg); }
>>>>> +
>>>>>  static void mac_mcu_write(struct rtl8169_private *tp, int reg, int
>>>>> value)  {
>>>>>       if (reg == 0x1f) {
>>>>> @@ -1280,6 +1314,13 @@ static void mac_mcu_write(struct
>>>>> rtl8169_private
>>>> *tp, int reg, int value)
>>>>>       r8168_mac_ocp_write(tp, tp->ocp_base + reg, value);  }
>>>>>
>>>>> +static bool rtl_is_8116af(struct rtl8169_private *tp) {
>>>>> +     return tp->mac_version == RTL_GIGA_MAC_VER_52 &&
>>>>> +             (r8168_mac_ocp_read(tp, 0xdc00) & 0x0078) == 0x0030 &&
>>>>> +             (r8168_mac_ocp_read(tp, 0xd006) & 0x00ff) == 0x0000; }
>>>>> +
>>>>>  static int mac_mcu_read(struct rtl8169_private *tp, int reg)  {
>>>>>       return r8168_mac_ocp_read(tp, tp->ocp_base + reg); @@ -1386,7
>>>>> +1427,10 @@ static int rtl_readphy(struct rtl8169_private *tp, int
>>>>> +location)
>>>>>       case RTL_GIGA_MAC_VER_31:
>>>>>               return r8168dp_2_mdio_read(tp, location);
>>>>>       case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_LAST:
>>>>> -             return r8168g_mdio_read(tp, location);
>>>>> +             if (tp->sfp_mode == RTL_SFP_8168_AF)
>>>>> +                     return r8116af_mdio_read(tp, location);
>>>>> +             else
>>>>> +                     return r8168g_mdio_read(tp, location);
>>>>>       default:
>>>>>               return r8169_mdio_read(tp, location);
>>>>>       }
>>>>> @@ -1575,6 +1619,20 @@ static bool rtl_dash_is_enabled(struct
>>>> rtl8169_private *tp)
>>>>>       }
>>>>>  }
>>>>>
>>>>> +static enum rtl_sfp_mode rtl_get_sfp_mode(struct rtl8169_private
>>>>> +*tp) {
>>>>> +     if (rtl_is_8125(tp)) {
>>>>> +             u16 data = r8168_mac_ocp_read(tp, 0xd006);
>>>>> +
>>>>> +             if ((data & 0xff) == 0x07)
>>>>> +                     return RTL_SFP_8127_ATF;
>>>>> +     } else if (rtl_is_8116af(tp)) {
>>>>> +             return RTL_SFP_8168_AF;
>>>>> +     }
>>>>> +
>>>>> +     return RTL_SFP_NONE;
>>>>> +}
>>>>> +
>>>>>  static enum rtl_dash_type rtl_get_dash_type(struct rtl8169_private
>>>>> *tp)  {
>>>>>       switch (tp->mac_version) {
>>>>> @@ -5693,12 +5751,7 @@ static int rtl_init_one(struct pci_dev *pdev,
>>>>> const
>>>> struct pci_device_id *ent)
>>>>>       }
>>>>>       tp->aspm_manageable = !rc;
>>>>>
>>>>> -     if (rtl_is_8125(tp)) {
>>>>> -             u16 data = r8168_mac_ocp_read(tp, 0xd006);
>>>>> -
>>>>> -             if ((data & 0xff) == 0x07)
>>>>> -                     tp->sfp_mode = true;
>>>>> -     }
>>>>> +     tp->sfp_mode = rtl_get_sfp_mode(tp);
>>>>>
>>>>>       tp->dash_type = rtl_get_dash_type(tp);
>>>>>       tp->dash_enabled = rtl_dash_is_enabled(tp);
>>>
> 


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

* Re: [PATCH net-next v1 2/4] r8169: add sfp mode for RTL8116af
  2026-03-18 21:45           ` Heiner Kallweit
@ 2026-03-19 17:09             ` Andrew Lunn
  0 siblings, 0 replies; 17+ messages in thread
From: Andrew Lunn @ 2026-03-19 17:09 UTC (permalink / raw)
  To: Heiner Kallweit
  Cc: Javen, nic_swsd@realtek.com, andrew+netdev@lunn.ch,
	davem@davemloft.net, edumazet@google.com, kuba@kernel.org,
	pabeni@redhat.com, horms@kernel.org, netdev@vger.kernel.org,
	linux-kernel@vger.kernel.org

> > We checked our chip documentation and confirmed that the SerDes register file maps
> > all clause 22 registers(e.g. WR 0xeb10<reg_addr>, RD 0xeb14. reg_addr 0x40 is for BMCR,
> > 0x41 for BMSR, 0x42 for PHYSID1, 0x43 for PHYSID2, etc.)
> > As you suggested, I wonder whether the proper approach is to implement a virtual mii_bus
> > and map the standard serdes reg in the new map.
> > 
> We'd need to know how the internal PHY and the SerDes play together.
> Whether the usual internal PHY plays any role in communication between MAC and SerDes.
> How interface modes are controlled on MAC and SerDes side, etc.
> If Realtek doesn't implement proper layering in hw, and doesn't have enough knowledge
> about mainline network driver structures, and on the other hand doesn't want to provide
> chip documentation, then the situation somewhat deadlocks.

The PHYSID1 and PHYSID2 might give us some clues. Is it a PCS licensed
from Synopsys?

https://elixir.bootlin.com/linux/v6.19.8/source/include/linux/pcs/pcs-xpcs.h#L24

	Andrew

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

end of thread, other threads:[~2026-03-19 17:09 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-02  6:32 [PATCH net-next v1 0/4] r8169: add ltr and c10 support for RTL8116af javen
2026-03-02  6:32 ` [PATCH net-next v1 1/4] r8169: add ltr " javen
2026-03-02  6:32 ` [PATCH net-next v1 2/4] r8169: add sfp mode " javen
2026-03-02 22:07   ` Heiner Kallweit
2026-03-04  8:16     ` 许俊伟
2026-03-04 21:42       ` Heiner Kallweit
2026-03-13  7:25     ` Javen
2026-03-13 21:21       ` Heiner Kallweit
2026-03-17  3:14         ` Javen
2026-03-18 21:45           ` Heiner Kallweit
2026-03-19 17:09             ` Andrew Lunn
2026-03-02  6:32 ` [PATCH net-next v1 3/4] r8169: move DECLARE_RTL_COND() javen
2026-03-02  6:32 ` [PATCH net-next v1 4/4] r8169: enable system enter c10 with RTL8116af javen
2026-03-02 21:53   ` Heiner Kallweit
2026-03-04  9:43     ` 许俊伟
2026-03-04 21:51       ` Heiner Kallweit
2026-03-05 10:58         ` Javen

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