Messages in this thread |  | | Date | Wed, 1 Apr 2026 09:20:18 +0200 | | Subject | Re: [PATCH net-next v1 2/4] r8169: add sfp mode for RTL8116af | | From | Heiner Kallweit <> |
| |
On 01.04.2026 03:43, Javen wrote: >> 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? >
The described scenario MAC->PCS->SerDes is a standard scenario supported by phylink, see e.g. phylink_pcs_ops and the drivers under drivers/net/pcs. So you best get familiar with phylink, and start thinking about what it would take to drive your IP blocks using phylink.
And still: Proper advice needs documentation as input. So if Realtek asks for advice, they should also be willing to share datasheets etc.
> 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); >>>>> >>> >
|  |