[PATCH net-next v3 7/7] r8169: add phylink support for RTL8127atf
From: javen
Date: Mon Jun 29 2026 - 02:19:47 EST
From: Javen Xu <javen_xu@xxxxxxxxxxxxxx>
RTL8127 ATF is a 10G SFP mode of RTL8127. Like RTL8116af, it has no
internal phy, so phylink uses a pcs to get the link status from the
serdes registers instead of standard phy registers.
The interface mode is PHY_INTERFACE_MODE_10GBASER. rtl_mac_select_pcs()
returns tp->pcs for it, and the serdes is configured for 10G in
pcs_config() via r8127_sfp_init_10g(). Speed and duplex are hardcoded
to 10Gbps Full-Duplex.
Per the datasheet, the 10G fiber does not support EEE/EEEP, RTD3, MAC
speed down, GPHY speed up, UPS or PFM mode, so EEE and runtime D3 are
disabled for RTL8127 ATF. UPS and PFM are already left disabled for this
chip, and the phy speed up/down paths are not reached because there is no
phydev.
Signed-off-by: Javen Xu <javen_xu@xxxxxxxxxxxxxx>
---
Changes in v3:
- No changes. New file.
---
drivers/net/ethernet/realtek/r8169_main.c | 84 ++++++++++-------------
1 file changed, 37 insertions(+), 47 deletions(-)
diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c
index 223501479d20..6f4221079e8f 100644
--- a/drivers/net/ethernet/realtek/r8169_main.c
+++ b/drivers/net/ethernet/realtek/r8169_main.c
@@ -104,6 +104,7 @@
#define OCP_SDS_DATA_REG 0xEB14
#define SDS_CMD_READ 0x0001
#define RTL_SDS_C22_BASE 0x40
+#define RTL_SDS_C45_BASE 0x0080
#define RTL_PKG_DETECT 0xdc00
#define RTL_PKG_DETECT_MASK 0x0078
#define RTL_PKG_DETECT_8116AF 0x0030
@@ -1161,10 +1162,6 @@ static int r8168_phy_ocp_read(struct rtl8169_private *tp, u32 reg)
if (rtl_ocp_reg_failure(reg))
return 0;
- /* Return dummy MII_PHYSID2 in SFP mode to match SFP PHY driver */
- 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);
return rtl_loop_wait_high(tp, &rtl_ocp_gphy_cond, 25, 10) ?
@@ -1250,12 +1247,6 @@ static void r8127_sfp_init_10g(struct rtl8169_private *tp)
r8168_phy_ocp_write(tp, 0xc804, (val & ~0x000f) | 0x000c);
}
-static void rtl_sfp_init(struct rtl8169_private *tp)
-{
- if (tp->mac_version == RTL_GIGA_MAC_VER_80)
- r8127_sfp_init_10g(tp);
-}
-
static void rtl_sfp_reset(struct rtl8169_private *tp)
{
if (tp->mac_version == RTL_GIGA_MAC_VER_80)
@@ -2445,31 +2436,8 @@ static int rtl8169_set_link_ksettings(struct net_device *ndev,
const struct ethtool_link_ksettings *cmd)
{
struct rtl8169_private *tp = netdev_priv(ndev);
- struct phy_device *phydev = tp->phydev;
- int duplex = cmd->base.duplex;
- int speed = cmd->base.speed;
-
- if (tp->sfp_mode != RTL_SFP_8127_ATF)
- return phylink_ethtool_ksettings_set(tp->phylink, cmd);
-
- if (cmd->base.autoneg != AUTONEG_DISABLE)
- return -EINVAL;
- if (!phy_check_valid(speed, duplex, phydev->supported))
- return -EINVAL;
-
- mutex_lock(&phydev->lock);
-
- phydev->autoneg = AUTONEG_DISABLE;
- phydev->speed = speed;
- phydev->duplex = duplex;
- tp->speed = speed;
-
- rtl_sfp_init(tp);
-
- mutex_unlock(&phydev->lock);
-
- return 0;
+ return phylink_ethtool_ksettings_set(tp->phylink, cmd);
}
static int rtl8169_nway_reset(struct net_device *dev)
@@ -2618,9 +2586,6 @@ static void rtl8169_init_phy(struct rtl8169_private *tp)
tp->pci_dev->subsystem_device == 0xe000)
phy_write_paged(tp->phydev, 0x0001, 0x10, 0xf01b);
- if (tp->sfp_mode == RTL_SFP_8127_ATF)
- rtl_sfp_init(tp);
-
/* We may have called phy_speed_down before */
phy_speed_up(tp->phydev);
@@ -5039,7 +5004,7 @@ static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance)
if (status & LinkChg) {
if (tp->phy_irq_domain)
generic_handle_domain_irq(tp->phy_irq_domain, 0);
- else if (tp->sfp_mode == RTL_SFP_8168_AF)
+ else if (tp->sfp_mode)
phylink_mac_change(tp->phylink,
!!(RTL_R8(tp, PHYstatus) & LinkStatus));
}
@@ -5809,7 +5774,9 @@ static struct phylink_pcs *rtl_mac_select_pcs(struct phylink_config *config,
{
struct rtl8169_private *tp = container_of(config, struct rtl8169_private, phylink_config);
- if (interface == PHY_INTERFACE_MODE_1000BASEX || interface == PHY_INTERFACE_MODE_SGMII)
+ if (interface == PHY_INTERFACE_MODE_1000BASEX ||
+ interface == PHY_INTERFACE_MODE_SGMII ||
+ interface == PHY_INTERFACE_MODE_10GBASER)
return &tp->pcs;
return NULL;
}
@@ -5838,12 +5805,28 @@ static void rtl8169_pcs_get_state(struct phylink_pcs *pcs,
struct phylink_link_state *state)
{
struct rtl8169_private *tp = container_of(pcs, struct rtl8169_private, pcs);
- u16 bmsr, lpa;
- bmsr = rtl8169_sds_read(tp, RTL_SDS_C22_BASE + MII_BMSR);
- lpa = rtl8169_sds_read(tp, RTL_SDS_C22_BASE + MII_LPA);
+ if (tp->sfp_mode == RTL_SFP_8127_ATF) {
+ u16 stat1;
+
+ stat1 = rtl8169_sds_read(tp, RTL_SDS_C45_BASE + MDIO_STAT1);
+
+ if (!(stat1 & MDIO_STAT1_LSTATUS))
+ stat1 = rtl8169_sds_read(tp, RTL_SDS_C45_BASE + MDIO_STAT1);
+
+ state->link = !!(stat1 & MDIO_STAT1_LSTATUS);
+ if (!state->link)
+ return;
- phylink_mii_c22_pcs_decode_state(state, neg_mode, bmsr, lpa);
+ state->duplex = DUPLEX_FULL;
+ state->speed = SPEED_10000;
+ } else {
+ u16 bmsr, lpa;
+
+ bmsr = rtl8169_sds_read(tp, RTL_SDS_C22_BASE + MII_BMSR);
+ lpa = rtl8169_sds_read(tp, RTL_SDS_C22_BASE + MII_LPA);
+ phylink_mii_c22_pcs_decode_state(state, neg_mode, bmsr, lpa);
+ }
}
static int rtl8169_pcs_config(struct phylink_pcs *pcs, unsigned int mode,
@@ -5851,6 +5834,11 @@ static int rtl8169_pcs_config(struct phylink_pcs *pcs, unsigned int mode,
const unsigned long *advertising,
bool permit_pause_to_mac)
{
+ struct rtl8169_private *tp = container_of(pcs, struct rtl8169_private, pcs);
+
+ if (tp->sfp_mode == RTL_SFP_8127_ATF)
+ r8127_sfp_init_10g(tp);
+
return 0;
}
@@ -5896,7 +5884,7 @@ static unsigned long rtl8169_get_lpi_caps(struct rtl8169_private *tp)
{
unsigned long caps = 0;
- if (!rtl_supports_eee(tp))
+ if (!rtl_supports_eee(tp) || tp->sfp_mode == RTL_SFP_8127_ATF)
return 0;
caps |= MAC_100FD | MAC_1000FD;
@@ -5940,7 +5928,9 @@ static int rtl_init_phylink(struct rtl8169_private *tp)
tp->phylink_config.mac_capabilities |= MAC_1000FD;
break;
case RTL_SFP_8127_ATF:
- phy_mode = PHY_INTERFACE_MODE_INTERNAL;
+ tp->pcs.ops = &r8169_pcs_ops;
+ phy_mode = PHY_INTERFACE_MODE_10GBASER;
+ tp->phylink_config.default_an_inband = true;
tp->phylink_config.mac_capabilities |= MAC_10000FD;
break;
default:
@@ -6167,7 +6157,7 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
if (rc)
return rc;
- if (tp->sfp_mode != RTL_SFP_8168_AF) {
+ if (tp->sfp_mode == RTL_SFP_NONE) {
rc = r8169_mdio_register(tp);
if (rc) {
phylink_destroy(tp->phylink);
@@ -6202,7 +6192,7 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
rtl8168_driver_start(tp);
}
- if (pci_dev_run_wake(pdev))
+ if (pci_dev_run_wake(pdev) && tp->sfp_mode != RTL_SFP_8127_ATF)
pm_runtime_put_sync(&pdev->dev);
return 0;
--
2.43.0