drivers/net/ethernet/realtek/r8169_main.c | 179 +++++++++++++++++++++- 1 file changed, 176 insertions(+), 3 deletions(-)
Add support for ATF variant of the RTL8127, this uses an SFP transceiver
instead of the twisted pair one and only runs at 1Gbps or 10Gbps.
The change is based on the r8127 driver package version 11.015.00
available on the Realtek website and also on
https://github.com/openwrt/rtl8127.
There's no public datasheet for the chip so this is just porting over
the original vendor code to the API and style of the upstream one.
Signed-off-by: Fabio Baltieri <fabio.baltieri@gmail.com>
---
Hi, this is a port of the fiber specific configuration code found in the
Realtek r8127 driver to the upstream one, basically just configuring the
serdes and making sure eee is disabled for good when the specific chip
variant is detected.
The code is full of magics and there's no public datasheet for the chip
so not much space to clarify what the individual registers/bits do, but
that seems to be the norm for this driver.
Tested this with a pair of RTL8127ATF based cards connected to each
other directly both with a 10G fiber transceivers and DAC cable and with
the other end running either the same r8169 upstream driver or the
Realtek r8127 one. Tested both 10G and 1G speed, connection seems to be
stable in all combinations.
That's all the 10G gear I have, though I also run this in a system with
other r8169 based cards just in case and things seems to work as
expected.
Cheers,
Fabio
---
drivers/net/ethernet/realtek/r8169_main.c | 179 +++++++++++++++++++++-
1 file changed, 176 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c
index d18734fe12e..7676c2af90e 100644
--- a/drivers/net/ethernet/realtek/r8169_main.c
+++ b/drivers/net/ethernet/realtek/r8169_main.c
@@ -729,6 +729,7 @@ struct rtl8169_private {
unsigned supports_gmii:1;
unsigned aspm_manageable:1;
unsigned dash_enabled:1;
+ unsigned fiber_mode:1;
dma_addr_t counters_phys_addr;
struct rtl8169_counters *counters;
struct rtl8169_tc_offsets tc_offset;
@@ -842,7 +843,8 @@ static bool rtl_supports_eee(struct rtl8169_private *tp)
{
return tp->mac_version >= RTL_GIGA_MAC_VER_34 &&
tp->mac_version != RTL_GIGA_MAC_VER_37 &&
- tp->mac_version != RTL_GIGA_MAC_VER_39;
+ tp->mac_version != RTL_GIGA_MAC_VER_39 &&
+ !tp->fiber_mode;
}
static void rtl_read_mac_from_reg(struct rtl8169_private *tp, u8 *mac, int reg)
@@ -1399,6 +1401,119 @@ DECLARE_RTL_COND(rtl_ocp_tx_cond)
return RTL_R8(tp, IBISR0) & 0x20;
}
+#define R8127_SDS_CMD 0x2348
+#define R8127_SDS_ADDR 0x234a
+#define R8127_SDS_DATA_IN 0x234c
+#define R8127_SDS_DATA_OUT 0x234e
+
+#define R8127_MAKE_SDS_ADDR(_index, _page, _reg) \
+ (((_index) << 11) | ((_page) << 5) | (_reg))
+
+#define R8127_SDS_CMD_IN BIT(0)
+#define R8127_SDS_WE_IN BIT(1)
+
+DECLARE_RTL_COND(rtl_sds_cmd_done)
+{
+ return RTL_R16(tp, R8127_SDS_CMD) & R8127_SDS_CMD_IN;
+}
+
+static u16 rtl8127_sds_phy_read(struct rtl8169_private *tp,
+ u16 index, u16 page, u16 reg)
+{
+ RTL_W16(tp, R8127_SDS_ADDR, R8127_MAKE_SDS_ADDR(index, page, reg));
+ RTL_W16(tp, R8127_SDS_CMD, R8127_SDS_CMD_IN);
+
+ if (rtl_loop_wait_low(tp, &rtl_sds_cmd_done, 1, 100))
+ return RTL_R16(tp, R8127_SDS_DATA_OUT);
+ else
+ return 0xffff;
+}
+
+static void rtl8127_sds_phy_write(struct rtl8169_private *tp,
+ u16 index, u16 page, u16 reg, u16 val)
+{
+ RTL_W16(tp, R8127_SDS_DATA_IN, val);
+ RTL_W16(tp, R8127_SDS_ADDR, R8127_MAKE_SDS_ADDR(index, page, reg));
+ RTL_W16(tp, R8127_SDS_CMD, R8127_SDS_CMD_IN | R8127_SDS_WE_IN);
+
+ rtl_loop_wait_low(tp, &rtl_sds_cmd_done, 1, 100);
+}
+
+static void rtl8127_sds_phy_modify(struct rtl8169_private *tp,
+ u16 index, u16 page, u16 addr,
+ u16 mask, u16 set)
+{
+ u16 val;
+
+ val = rtl8127_sds_phy_read(tp, index, page, addr);
+ val = (val & ~mask) | set;
+ rtl8127_sds_phy_write(tp, index, page, addr, val);
+}
+
+static void rtl8127_sds_phy_reset(struct rtl8169_private *tp)
+{
+ RTL_W8(tp, 0x2350, RTL_R8(tp, 0x2350) & ~BIT(0));
+ udelay(1);
+
+ RTL_W16(tp, 0x233a, 0x801f);
+ RTL_W8(tp, 0x2350, RTL_R8(tp, 0x2350) | BIT(0));
+ udelay(10);
+}
+
+static void rtl8127_sds_phy_exit_1g(struct rtl8169_private *tp)
+{
+ rtl8127_sds_phy_modify(tp, 0, 1, 31, BIT(3), 0);
+ rtl8127_sds_phy_modify(tp, 0, 2, 0,
+ BIT(13) | BIT(12) | BIT(6),
+ BIT(6));
+
+ rtl8127_sds_phy_reset(tp);
+}
+
+static void rtl8127_set_sds_phy_caps_1g(struct rtl8169_private *tp)
+{
+ u16 val;
+
+ rtl8127_sds_phy_modify(tp, 0, 1, 31, 0, BIT(3));
+ rtl8127_sds_phy_modify(tp, 0, 2, 0,
+ BIT(13) | BIT(12) | BIT(6),
+ BIT(12) | BIT(6));
+ RTL_W16(tp, 0x233a, 0x8004);
+
+ val = RTL_R16(tp, 0x233e);
+ val &= BIT(13) | BIT(12) | BIT(1) | BIT(0);
+ val |= BIT(1);
+ RTL_W16(tp, 0x233e, val);
+
+ r8169_mdio_write(tp, 0xc40a, 0x0);
+ r8169_mdio_write(tp, 0xc466, 0x0);
+ r8169_mdio_write(tp, 0xc808, 0x0);
+ r8169_mdio_write(tp, 0xc80a, 0x0);
+
+ val = r8168_phy_ocp_read(tp, 0xc804);
+ r8168_phy_ocp_write(tp, 0xc804, (val & ~0x000f) | 0x000c);
+}
+
+static void rtl8127_set_sds_phy_caps_10g(struct rtl8169_private *tp)
+{
+ u16 val;
+
+ RTL_W16(tp, 0x233a, 0x801a);
+
+ val = RTL_R16(tp, 0x233e);
+ val &= BIT(13) | BIT(12) | BIT(1) | BIT(0);
+ val |= BIT(12);
+ RTL_W16(tp, 0x233e, val);
+
+ r8169_mdio_write(tp, 0xc40a, 0x0);
+ r8169_mdio_write(tp, 0xc466, 0x3);
+ r8169_mdio_write(tp, 0xc808, 0x0);
+ r8169_mdio_write(tp, 0xc80a, 0x0);
+
+ val = r8168_phy_ocp_read(tp, 0xc804);
+ r8168_phy_ocp_write(tp, 0xc804, (val & ~0x000f) | 0x000c);
+}
+
static void rtl8168ep_stop_cmac(struct rtl8169_private *tp)
{
RTL_W8(tp, IBCR2, RTL_R8(tp, IBCR2) & ~0x01);
@@ -1512,6 +1627,15 @@ static enum rtl_dash_type rtl_get_dash_type(struct rtl8169_private *tp)
}
}
+static bool rtl_fiber_mode(struct rtl8169_private *tp)
+{
+ if (tp->mac_version == RTL_GIGA_MAC_VER_80 &&
+ (r8168_mac_ocp_read(tp, 0xd006) & 0xff) == 0x07)
+ return true;
+
+ return false;
+}
+
static void rtl_set_d3_pll_down(struct rtl8169_private *tp, bool enable)
{
if (tp->mac_version >= RTL_GIGA_MAC_VER_25 &&
@@ -2293,6 +2417,27 @@ static void rtl8169_get_eth_ctrl_stats(struct net_device *dev,
le32_to_cpu(tp->counters->rx_unknown_opcode);
}
+static int rtl8169_set_link_ksettings(struct net_device *ndev,
+ const struct ethtool_link_ksettings *cmd)
+{
+ struct rtl8169_private *tp = netdev_priv(ndev);
+
+ if (tp->fiber_mode) {
+ if (cmd->base.speed != SPEED_1000 &&
+ cmd->base.speed != SPEED_10000)
+ return -EINVAL;
+
+ rtl8127_sds_phy_exit_1g(tp);
+
+ if (cmd->base.speed == SPEED_1000)
+ rtl8127_set_sds_phy_caps_1g(tp);
+ else
+ rtl8127_set_sds_phy_caps_10g(tp);
+ }
+
+ return phy_ethtool_set_link_ksettings(ndev, cmd);
+}
+
static const struct ethtool_ops rtl8169_ethtool_ops = {
.supported_coalesce_params = ETHTOOL_COALESCE_USECS |
ETHTOOL_COALESCE_MAX_FRAMES,
@@ -2312,7 +2457,7 @@ static const struct ethtool_ops rtl8169_ethtool_ops = {
.get_eee = rtl8169_get_eee,
.set_eee = rtl8169_set_eee,
.get_link_ksettings = phy_ethtool_get_link_ksettings,
- .set_link_ksettings = phy_ethtool_set_link_ksettings,
+ .set_link_ksettings = rtl8169_set_link_ksettings,
.get_ringparam = rtl8169_get_ringparam,
.get_pause_stats = rtl8169_get_pause_stats,
.get_pauseparam = rtl8169_get_pauseparam,
@@ -2390,7 +2535,10 @@ static void rtl8125a_config_eee_mac(struct rtl8169_private *tp)
static void rtl8125b_config_eee_mac(struct rtl8169_private *tp)
{
- r8168_mac_ocp_modify(tp, 0xe040, 0, BIT(1) | BIT(0));
+ if (tp->fiber_mode)
+ r8168_mac_ocp_modify(tp, 0xe040, BIT(1) | BIT(0), 0);
+ else
+ r8168_mac_ocp_modify(tp, 0xe040, 0, BIT(1) | BIT(0));
}
static void rtl_rar_exgmac_set(struct rtl8169_private *tp, const u8 *addr)
@@ -2440,6 +2588,22 @@ 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->fiber_mode) {
+ phy_remove_link_mode(tp->phydev, ETHTOOL_LINK_MODE_10baseT_Half_BIT);
+ phy_remove_link_mode(tp->phydev, ETHTOOL_LINK_MODE_10baseT_Full_BIT);
+ phy_remove_link_mode(tp->phydev, ETHTOOL_LINK_MODE_100baseT_Half_BIT);
+ phy_remove_link_mode(tp->phydev, ETHTOOL_LINK_MODE_100baseT_Full_BIT);
+ phy_remove_link_mode(tp->phydev, ETHTOOL_LINK_MODE_2500baseT_Full_BIT);
+ phy_remove_link_mode(tp->phydev, ETHTOOL_LINK_MODE_5000baseT_Full_BIT);
+
+ phy_remove_link_mode(tp->phydev, ETHTOOL_LINK_MODE_Autoneg_BIT);
+ phy_remove_link_mode(tp->phydev, ETHTOOL_LINK_MODE_Pause_BIT);
+ phy_remove_link_mode(tp->phydev, ETHTOOL_LINK_MODE_Asym_Pause_BIT);
+
+ tp->phydev->autoneg = 0;
+ tp->phydev->port = PORT_FIBRE;
+ }
+
/* We may have called phy_speed_down before */
phy_speed_up(tp->phydev);
@@ -4893,6 +5057,13 @@ static int rtl_open(struct net_device *dev)
goto err_free_irq;
rtl8169_up(tp);
+
+ if (tp->fiber_mode) {
+ rtl8127_sds_phy_exit_1g(tp);
+
+ rtl8127_set_sds_phy_caps_10g(tp);
+ }
+
rtl8169_init_counter_offsets(tp);
netif_start_queue(dev);
out:
@@ -5453,6 +5624,8 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
tp->dash_type = rtl_get_dash_type(tp);
tp->dash_enabled = rtl_dash_is_enabled(tp);
+ tp->fiber_mode = rtl_fiber_mode(tp);
+
tp->cp_cmd = RTL_R16(tp, CPlusCmd) & CPCMD_MASK;
if (sizeof(dma_addr_t) > 4 && tp->mac_version >= RTL_GIGA_MAC_VER_18 &&
--
2.47.3
> + if (tp->fiber_mode) {
> + phy_remove_link_mode(tp->phydev, ETHTOOL_LINK_MODE_10baseT_Half_BIT);
> + phy_remove_link_mode(tp->phydev, ETHTOOL_LINK_MODE_10baseT_Full_BIT);
> + phy_remove_link_mode(tp->phydev, ETHTOOL_LINK_MODE_100baseT_Half_BIT);
> + phy_remove_link_mode(tp->phydev, ETHTOOL_LINK_MODE_100baseT_Full_BIT);
> + phy_remove_link_mode(tp->phydev, ETHTOOL_LINK_MODE_2500baseT_Full_BIT);
> + phy_remove_link_mode(tp->phydev, ETHTOOL_LINK_MODE_5000baseT_Full_BIT);
An SFP module can support baseT modes, if the SFP module has a PHY
inside it. But it could also be it is a fibre module with a laser and
so uses 100baseFX, 1000baseX, 2500BaseX, etc.
To do this properly, you need to be able to read the SFP EERPOMs
content, to know what sort of SFP module you have plugged in. Then you
can list the correct modes.
Andrew
On Mon, Nov 17, 2025 at 08:37:41PM +0100, Andrew Lunn wrote:
> > + if (tp->fiber_mode) {
> > + phy_remove_link_mode(tp->phydev, ETHTOOL_LINK_MODE_10baseT_Half_BIT);
> > + phy_remove_link_mode(tp->phydev, ETHTOOL_LINK_MODE_10baseT_Full_BIT);
> > + phy_remove_link_mode(tp->phydev, ETHTOOL_LINK_MODE_100baseT_Half_BIT);
> > + phy_remove_link_mode(tp->phydev, ETHTOOL_LINK_MODE_100baseT_Full_BIT);
> > + phy_remove_link_mode(tp->phydev, ETHTOOL_LINK_MODE_2500baseT_Full_BIT);
> > + phy_remove_link_mode(tp->phydev, ETHTOOL_LINK_MODE_5000baseT_Full_BIT);
>
> An SFP module can support baseT modes, if the SFP module has a PHY
> inside it. But it could also be it is a fibre module with a laser and
> so uses 100baseFX, 1000baseX, 2500BaseX, etc.
Right, so for an SFP NIC would you expect ethtool to report only the
modes supported by the module? It'd make sense, like right now I'm
testing with a 10GBASE-SR module but as it stands ethtool will always
only show 1000baseT and 10000baseT.
> To do this properly, you need to be able to read the SFP EERPOMs
> content, to know what sort of SFP module you have plugged in. Then you
> can list the correct modes.
I see, unfortunately all I have for this NIC is the out of tree Realtek
driver and it does not seem to implement the API for reading the module
EEPROM data, and there's no datasheet available, so I'm afraid that
either the Realtek folks pick this up or it's not going to happen.
In the current state the driver matches the behavior of the out of tree
one, which is to only report 1000baseT and 10000baseT as supported,
which I guess is a good hint that that's what the user can set the card
manually at. Are you suggesting that I should change this to do
something different?
--
Fabio
> I see, unfortunately all I have for this NIC is the out of tree Realtek > driver and it does not seem to implement the API for reading the module > EEPROM data, and there's no datasheet available, so I'm afraid that > either the Realtek folks pick this up or it's not going to happen. Heiner is of the opinion it is not going to happen. Andrew
On 11/18/2025 8:31 PM, Andrew Lunn wrote: >> I see, unfortunately all I have for this NIC is the out of tree Realtek >> driver and it does not seem to implement the API for reading the module >> EEPROM data, and there's no datasheet available, so I'm afraid that >> either the Realtek folks pick this up or it's not going to happen. > > Heiner is of the opinion it is not going to happen. > Realtek seems to do all SFP handling in firmware, w/o providing info about to which extent this firmware can be controlled via chip registers. A contact in Realtek confirmed that only 1G and 10G speeds are supported. He wasn't sure whether copper SFP modules are supported, and will check internally. I'll try to strip down the patch as far as possible, likely supporting 10G only in the beginning (as 1G requires some more vendor magic to configure). I assume the typical user won't spend money on a 10G card to use it with a 1G fiber module. Reducing complexity of the patch should make the decision easier to accept it. I don't have hw with RTL8127ATF, so I would give the patch to Fabio for testing. > Andrew Heiner
On Tue, Nov 18, 2025 at 09:02:22PM +0100, Heiner Kallweit wrote: > A contact in Realtek confirmed that only 1G and 10G speeds are supported. > He wasn't sure whether copper SFP modules are supported, and will check > internally. > > I'll try to strip down the patch as far as possible, likely supporting 10G > only in the beginning (as 1G requires some more vendor magic to configure). > I assume the typical user won't spend money on a 10G card to use it with a > 1G fiber module. > Reducing complexity of the patch should make the decision easier to accept it. > > I don't have hw with RTL8127ATF, so I would give the patch to Fabio for testing. Hey thanks for following up on this, cc'ing Michael as well, as it turns out he was also working on upstream support for this at the same time as me, maybe he can help testing in more scenarios. I did test 1G support between two RTL8127ATF cards and it works fine, have not tried between that a 1G fiber only card (don't own any), happy to drop it if you think it may not work but hopefully it can be tested and kept, it was in the out of tree driver after all, I'd hope the vendor did some interoperability test with that code. Cheers, Fabio
On Tue, Nov 18, 2025 at 9:20 PM Fabio Baltieri <fabio.baltieri@gmail.com> wrote:
>
> On Tue, Nov 18, 2025 at 09:02:22PM +0100, Heiner Kallweit wrote:
> > A contact in Realtek confirmed that only 1G and 10G speeds are supported.
> > He wasn't sure whether copper SFP modules are supported, and will check
> > internally.
> >
> > I'll try to strip down the patch as far as possible, likely supporting 10G
> > only in the beginning (as 1G requires some more vendor magic to configure).
> > I assume the typical user won't spend money on a 10G card to use it with a
> > 1G fiber module.
> > Reducing complexity of the patch should make the decision easier to accept it.
> >
> > I don't have hw with RTL8127ATF, so I would give the patch to Fabio for testing.
>
> Hey thanks for following up on this, cc'ing Michael as well, as it turns
> out he was also working on upstream support for this at the same time as
> me, maybe he can help testing in more scenarios.
>
> I did test 1G support between two RTL8127ATF cards and it works fine,
> have not tried between that a 1G fiber only card (don't own any), happy
> to drop it if you think it may not work but hopefully it can be tested
> and kept, it was in the out of tree driver after all, I'd hope the
> vendor did some interoperability test with that code.
>
> Cheers,
> Fabio
One thing the out-of-tree driver does, which your patch doesn't do, is
disabling eee when in fiber mode. I'd suggest something like this:
@@ -845,7 +860,8 @@ static bool rtl_supports_eee(struct rtl8169_private *tp)
{
return tp->mac_version >= RTL_GIGA_MAC_VER_34 &&
tp->mac_version != RTL_GIGA_MAC_VER_37 &&
- tp->mac_version != RTL_GIGA_MAC_VER_39;
+ tp->mac_version != RTL_GIGA_MAC_VER_39 &&
+ !tp->fiber_enabled;
}
Michael
On Tue, Nov 18, 2025 at 10:31:54PM +0100, Michael Zimmermann wrote:
> One thing the out-of-tree driver does, which your patch doesn't do, is
> disabling eee when in fiber mode. I'd suggest something like this:
> @@ -845,7 +860,8 @@ static bool rtl_supports_eee(struct rtl8169_private *tp)
> {
> return tp->mac_version >= RTL_GIGA_MAC_VER_34 &&
> tp->mac_version != RTL_GIGA_MAC_VER_37 &&
> - tp->mac_version != RTL_GIGA_MAC_VER_39;
> + tp->mac_version != RTL_GIGA_MAC_VER_39 &&
> + !tp->fiber_enabled;
> }
Heya, don't I have exactly that diff in the patch? The second chunk
@@ -842,7 +843,8 @@ static bool rtl_supports_eee(struct rtl8169_private *tp)
{
return tp->mac_version >= RTL_GIGA_MAC_VER_34 &&
tp->mac_version != RTL_GIGA_MAC_VER_37 &&
- tp->mac_version != RTL_GIGA_MAC_VER_39;
+ tp->mac_version != RTL_GIGA_MAC_VER_39 &&
+ !tp->fiber_mode;
}
On Tue, Nov 18, 2025 at 11:01 PM Fabio Baltieri
<fabio.baltieri@gmail.com> wrote:
>
> On Tue, Nov 18, 2025 at 10:31:54PM +0100, Michael Zimmermann wrote:
> > One thing the out-of-tree driver does, which your patch doesn't do, is
> > disabling eee when in fiber mode. I'd suggest something like this:
> > @@ -845,7 +860,8 @@ static bool rtl_supports_eee(struct rtl8169_private *tp)
> > {
> > return tp->mac_version >= RTL_GIGA_MAC_VER_34 &&
> > tp->mac_version != RTL_GIGA_MAC_VER_37 &&
> > - tp->mac_version != RTL_GIGA_MAC_VER_39;
> > + tp->mac_version != RTL_GIGA_MAC_VER_39 &&
> > + !tp->fiber_enabled;
> > }
>
> Heya, don't I have exactly that diff in the patch? The second chunk
>
> @@ -842,7 +843,8 @@ static bool rtl_supports_eee(struct rtl8169_private *tp)
> {
> return tp->mac_version >= RTL_GIGA_MAC_VER_34 &&
> tp->mac_version != RTL_GIGA_MAC_VER_37 &&
> - tp->mac_version != RTL_GIGA_MAC_VER_39;
> + tp->mac_version != RTL_GIGA_MAC_VER_39 &&
> + !tp->fiber_mode;
> }
You're right, no idea how I missed that, sorry.
I've also done some testing with the out-of-tree driver:
- (my normal setup) a DAC between the rt8127 and a 10G switch works just fine.
- RJ45 10G modules on both sides works fine, but HwFiberModeVer stays
at 1 even after reloading the driver.
- RJ45 1G modules on both sides works after "ethtool -s enp1s0 speed
1000 duplex full autoneg on", but you have to do that while connected
via 10G because that driver is buggy and returns EINVAL otherwise.
HwFiberModeVer was 1 as well after reloading the driver.
What this means is that the fiber mode is always enabled on these
cards, which makes sense given that the out-of-tree driver only reads
it once when loading the driver. I guess it's either a hardware
variant, configured in the factory or detected using a pin of the
chip.
It also means that it doesn't matter to the linux driver what's
actually connected beyond the speed you want to use since - as others
have said before - this seems to be fully handled on the NIC.
Michael
On Wed, Nov 19, 2025 at 08:00:01AM +0100, Michael Zimmermann wrote: > I've also done some testing with the out-of-tree driver: > - (my normal setup) a DAC between the rt8127 and a 10G switch works just fine. > - RJ45 10G modules on both sides works fine, but HwFiberModeVer stays > at 1 even after reloading the driver. > - RJ45 1G modules on both sides works after "ethtool -s enp1s0 speed > 1000 duplex full autoneg on", but you have to do that while connected > via 10G because that driver is buggy and returns EINVAL otherwise. > HwFiberModeVer was 1 as well after reloading the driver. You are right, did some more extensive testing and it seems like switching speed is somewhat unreliable. I've also bumped into https://lore.kernel.org/netdev/cc1c8d30-fda0-4d3d-ad61-3ff932ef0222@gmail.com/ and sure enough this is affected too, it also does not survive suspend without the wol flag, but more importantly I've found that the serdes has to be reconfigured on resume, so I need to send a v2 moving some code around. > What this means is that the fiber mode is always enabled on these > cards, which makes sense given that the out-of-tree driver only reads > it once when loading the driver. I guess it's either a hardware > variant, configured in the factory or detected using a pin of the > chip. > It also means that it doesn't matter to the linux driver what's > actually connected beyond the speed you want to use since - as others > have said before - this seems to be fully handled on the NIC. Yeah but that make sense, it does not really mean *fiber* mode, it controls the serdes configuration which is used both by fiber transceiver and DACs or anything else you plug in the SFP port. It's a good point though I think it may be a good idea to rename it to something like "sfp_mode" so it's not ambiguous. Heiner: if I'm reading the room right you are more keen to have a more minimal initial support patch: I'm sending a v2 anyway to fix up the standby support, would you like me to rip off the 1g code and keep it 10g only while at it? Then we can have at least that hopefully working reliably, as you pointed out that's probably what the vast majority of users of this nic needs anyway.
On 11/19/2025 11:26 AM, Fabio Baltieri wrote:
> On Wed, Nov 19, 2025 at 08:00:01AM +0100, Michael Zimmermann wrote:
>> I've also done some testing with the out-of-tree driver:
>> - (my normal setup) a DAC between the rt8127 and a 10G switch works just fine.
>> - RJ45 10G modules on both sides works fine, but HwFiberModeVer stays
>> at 1 even after reloading the driver.
>> - RJ45 1G modules on both sides works after "ethtool -s enp1s0 speed
>> 1000 duplex full autoneg on", but you have to do that while connected
>> via 10G because that driver is buggy and returns EINVAL otherwise.
>> HwFiberModeVer was 1 as well after reloading the driver.
>
> You are right, did some more extensive testing and it seems like
> switching speed is somewhat unreliable.
>
> I've also bumped into
> https://lore.kernel.org/netdev/cc1c8d30-fda0-4d3d-ad61-3ff932ef0222@gmail.com/
> and sure enough this is affected too, it also does not survive suspend
> without the wol flag, but more importantly I've found that the serdes
> has to be reconfigured on resume, so I need to send a v2 moving some
> code around.
>
Could you please test whether the following fixes the chip hang on suspend / shutdown?
diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c
index de304d1eb..97dbe8f89 100644
--- a/drivers/net/ethernet/realtek/r8169_main.c
+++ b/drivers/net/ethernet/realtek/r8169_main.c
@@ -1517,11 +1517,20 @@ static enum rtl_dash_type rtl_get_dash_type(struct rtl8169_private *tp)
static void rtl_set_d3_pll_down(struct rtl8169_private *tp, bool enable)
{
- if (tp->mac_version >= RTL_GIGA_MAC_VER_25 &&
- tp->mac_version != RTL_GIGA_MAC_VER_28 &&
- tp->mac_version != RTL_GIGA_MAC_VER_31 &&
- tp->mac_version != RTL_GIGA_MAC_VER_38)
- r8169_mod_reg8_cond(tp, PMCH, D3_NO_PLL_DOWN, !enable);
+ switch (tp->mac_version) {
+ case RTL_GIGA_MAC_VER_02 ... RTL_GIGA_MAC_VER_24:
+ case RTL_GIGA_MAC_VER_28:
+ case RTL_GIGA_MAC_VER_31:
+ case RTL_GIGA_MAC_VER_38:
+ break;
+ case RTL_GIGA_MAC_VER_80:
+ r8169_mod_reg8_cond(tp, PMCH, D3_NO_PLL_DOWN, true);
+ break;
+ default:
+ r8169_mod_reg8_cond(tp, PMCH, D3HOT_NO_PLL_DOWN, true);
+ r8169_mod_reg8_cond(tp, PMCH, D3COLD_NO_PLL_DOWN, !enable);
+ break;
+ }
}
static void rtl_reset_packet_filter(struct rtl8169_private *tp)
--
2.52.0
On Fri, Nov 21, 2025 at 12:17:33AM +0100, Heiner Kallweit wrote:
> Could you please test whether the following fixes the chip hang on suspend / shutdown?
>
> diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c
> index de304d1eb..97dbe8f89 100644
> --- a/drivers/net/ethernet/realtek/r8169_main.c
> +++ b/drivers/net/ethernet/realtek/r8169_main.c
> @@ -1517,11 +1517,20 @@ static enum rtl_dash_type rtl_get_dash_type(struct rtl8169_private *tp)
>
> static void rtl_set_d3_pll_down(struct rtl8169_private *tp, bool enable)
> {
> - if (tp->mac_version >= RTL_GIGA_MAC_VER_25 &&
> - tp->mac_version != RTL_GIGA_MAC_VER_28 &&
> - tp->mac_version != RTL_GIGA_MAC_VER_31 &&
> - tp->mac_version != RTL_GIGA_MAC_VER_38)
> - r8169_mod_reg8_cond(tp, PMCH, D3_NO_PLL_DOWN, !enable);
> + switch (tp->mac_version) {
> + case RTL_GIGA_MAC_VER_02 ... RTL_GIGA_MAC_VER_24:
> + case RTL_GIGA_MAC_VER_28:
> + case RTL_GIGA_MAC_VER_31:
> + case RTL_GIGA_MAC_VER_38:
> + break;
> + case RTL_GIGA_MAC_VER_80:
> + r8169_mod_reg8_cond(tp, PMCH, D3_NO_PLL_DOWN, true);
> + break;
> + default:
> + r8169_mod_reg8_cond(tp, PMCH, D3HOT_NO_PLL_DOWN, true);
> + r8169_mod_reg8_cond(tp, PMCH, D3COLD_NO_PLL_DOWN, !enable);
> + break;
> + }
> }
>
> static void rtl_reset_packet_filter(struct rtl8169_private *tp)
Yes, patched it in and tested on both suspend and reboot without
touching the wol flags, seems to be working correctly.
Thanks!
On 11/21/2025 1:09 PM, Fabio Baltieri wrote:
> On Fri, Nov 21, 2025 at 12:17:33AM +0100, Heiner Kallweit wrote:
>> Could you please test whether the following fixes the chip hang on suspend / shutdown?
>>
>> diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c
>> index de304d1eb..97dbe8f89 100644
>> --- a/drivers/net/ethernet/realtek/r8169_main.c
>> +++ b/drivers/net/ethernet/realtek/r8169_main.c
>> @@ -1517,11 +1517,20 @@ static enum rtl_dash_type rtl_get_dash_type(struct rtl8169_private *tp)
>>
>> static void rtl_set_d3_pll_down(struct rtl8169_private *tp, bool enable)
>> {
>> - if (tp->mac_version >= RTL_GIGA_MAC_VER_25 &&
>> - tp->mac_version != RTL_GIGA_MAC_VER_28 &&
>> - tp->mac_version != RTL_GIGA_MAC_VER_31 &&
>> - tp->mac_version != RTL_GIGA_MAC_VER_38)
>> - r8169_mod_reg8_cond(tp, PMCH, D3_NO_PLL_DOWN, !enable);
>> + switch (tp->mac_version) {
>> + case RTL_GIGA_MAC_VER_02 ... RTL_GIGA_MAC_VER_24:
>> + case RTL_GIGA_MAC_VER_28:
>> + case RTL_GIGA_MAC_VER_31:
>> + case RTL_GIGA_MAC_VER_38:
>> + break;
>> + case RTL_GIGA_MAC_VER_80:
>> + r8169_mod_reg8_cond(tp, PMCH, D3_NO_PLL_DOWN, true);
>> + break;
>> + default:
>> + r8169_mod_reg8_cond(tp, PMCH, D3HOT_NO_PLL_DOWN, true);
>> + r8169_mod_reg8_cond(tp, PMCH, D3COLD_NO_PLL_DOWN, !enable);
>> + break;
>> + }
>> }
>>
>> static void rtl_reset_packet_filter(struct rtl8169_private *tp)
>
> Yes, patched it in and tested on both suspend and reboot without
> touching the wol flags, seems to be working correctly.
>
Great, thanks for the feedback!
> Thanks!
© 2016 - 2025 Red Hat, Inc.