Messages in this thread |  | | From | Javen <> | | Subject | RE: [PATCH net-next v1 2/4] r8169: add sfp mode for RTL8116af | | Date | Wed, 1 Apr 2026 01:43:44 +0000 |
| |
>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. >
Hi, Heiner For RTL8116af, the datapath is structured as MAC->PCS->SerDes. However, PCS block does not have a standard MDIO interface. Instead, we have to access the standard reg via MAC OCP.These standard registers are exactly the standard IEEE 802.3 Clause 22 PHY registers. Given hardware information above, I would like to ask for your advice on the recommended approach to support RTL8116af. Or any other information do I need to provide?
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); >>>> >>
|  |