* [PATCH net-next v1] r8169: implement get_module functions for rtl8127atf
@ 2026-04-04 20:13 Fabio Baltieri
2026-04-04 21:55 ` Heiner Kallweit
0 siblings, 1 reply; 6+ messages in thread
From: Fabio Baltieri @ 2026-04-04 20:13 UTC (permalink / raw)
To: Heiner Kallweit, nic_swsd, Andrew Lunn, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni
Cc: netdev, linux-kernel, Fabio Baltieri
Implement get_module_info and get_module_eeprom for supported devices,
right now that's the rtl8127atf.
This enables using ethtool to retrieve the transceiver identification
and diagnostic data.
Signed-off-by: Fabio Baltieri <fabio.baltieri@gmail.com>
---
Hi,
Realtek released a new out of tree driver for the rtl8127 and it
includes some code that exposes the I2C controller connected to the SFP
port.
This patch implements get_module_info and get_module_eeprom based on the
information found on that driver, it allows ethtool to fetch the SFP
module information, which is useful both to identify the module and to
track the health of fiber optic transceivers.
The logic for the SFF standard and i2c address selection is borrowed
directly from the aquantia/atlantic driver, I don't have a lot of stuff
to test it but I was able to trigger all code paths from a fiber optic
transceiver and an SFP cable I have available.
Demo:
# Fiber transceiver
$ sudo ethtool -m eth1
Identifier : 0x03 (SFP)
Extended identifier : 0x04 (GBIC/SFP defined by 2-wire interface ID)
Connector : 0x07 (LC)
Transceiver codes : 0x10 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
Transceiver type : 10G Ethernet: 10G Base-SR
Encoding : 0x06 (64B/66B)
BR Nominal : 10300MBd
Rate identifier : 0x00 (unspecified)
Length (SMF) : 0km
Length (OM2) : 80m
Length (OM1) : 30m
Length (Copper or Active cable) : 0m
Length (OM3) : 300m
Laser wavelength : 850nm
Vendor name : QSFPTEK
Vendor OUI : 00:0a:0d
Vendor PN : QT-SFP+-SR
Vendor rev :
Option values : 0x00 0x1a
Option : TX_DISABLE implemented
BR margin max : 10%
BR margin min : 88%
Vendor SN : QT8250805131
Date code : 250806
Optical diagnostics support : Yes
Laser bias current : 5.880 mA
Laser output power : 0.5431 mW / -2.65 dBm
Receiver signal average optical power : 0.6912 mW / -1.60 dBm
Module temperature : 20.70 degrees C / 69.25 degrees F
Module voltage : 3.3000 V
...
# DAC
$ sudo ethtool -m eth1
Identifier : 0x03 (SFP)
Extended identifier : 0x04 (GBIC/SFP defined by 2-wire interface ID)
Connector : 0x21 (Copper pigtail)
Transceiver codes : 0x00 0x00 0x00 0x00 0x00 0x04 0x00 0x00 0x00
Transceiver type : Passive Cable
Encoding : 0x00 (unspecified)
BR Nominal : 10300MBd
Rate identifier : 0x00 (unspecified)
Length (SMF) : 0km
Length (OM2) : 0m
Length (OM1) : 0m
Length (Copper or Active cable) : 1m
Length (OM3) : 0m
Passive Cu cmplnce. : 0x01 (SFF-8431 appendix E [SFF-8472 rev10.4 only])
Vendor name : OEM
Vendor OUI : 00:40:20
Vendor PN : SFP-H10GB-CU1M
Vendor rev : R
Option values : 0x00 0x00
BR margin max : 0%
BR margin min : 0%
Vendor SN : CSC240415030053
Date code : 240508
...
# No module
$ sudo ethtool -m eth1
netlink error: Input/output error
Cheers,
Fabio
drivers/net/ethernet/realtek/r8169_main.c | 177 ++++++++++++++++++++++
1 file changed, 177 insertions(+)
diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c
index 58788d196c57..45ec0b5c1c21 100644
--- a/drivers/net/ethernet/realtek/r8169_main.c
+++ b/drivers/net/ethernet/realtek/r8169_main.c
@@ -2411,6 +2411,181 @@ static int rtl8169_set_link_ksettings(struct net_device *ndev,
return 0;
}
+#define R8127_SDS_I2C_CON 0xe200
+#define R8127_SDS_I2C_TAR 0xe204
+#define R8127_SDS_I2C_DATA_CMD 0xe210
+#define R8127_SDS_I2C_FS_SCL_HCNT 0xe21c
+#define R8127_SDS_I2C_FS_SCL_LCNT 0xe220
+#define R8127_SDS_I2C_INTR_STAT 0xe22c
+#define R8127_SDS_I2C_EN 0xe26c
+#define R8127_SDS_I2C_STATUS 0xe270
+
+#define R8127_SDS_I2C_STATUS_ACTIVITY BIT(0)
+#define R8127_SDS_I2C_RX_FIFO_NOT_EMPTY BIT(3)
+#define R8127_SDS_I2C_STAT_TX_ABRT BIT(6)
+
+#define R8127_SDS_I2C_CMD_READ BIT(8)
+#define R8127_SDS_I2C_CMD_STOP BIT(9)
+#define R8127_SDS_I2C_CMD_RESTART BIT(10)
+
+#define SFF_8472_ID_ADDR 0x50
+#define SFF_8472_DIAGNOSTICS_ADDR 0x51
+
+#define SFF_8472_COMP_ADDR 0x5e
+#define SFF_8472_DOM_TYPE_ADDR 0x5c
+
+#define SFF_8472_ADDRESS_CHANGE_REQ_MASK 0x4
+
+static void r8127_sfp_sds_i2c_init(struct rtl8169_private *tp, u8 addr)
+{
+ r8168_mac_ocp_write(tp, R8127_SDS_I2C_EN, 0);
+ r8168_mac_ocp_write(tp, R8127_SDS_I2C_CON, 0x65);
+ r8168_mac_ocp_write(tp, R8127_SDS_I2C_TAR, addr);
+ r8168_mac_ocp_write(tp, R8127_SDS_I2C_FS_SCL_HCNT, 0x23a);
+ r8168_mac_ocp_write(tp, R8127_SDS_I2C_FS_SCL_LCNT, 0x23a);
+ r8168_mac_ocp_write(tp, R8127_SDS_I2C_EN, 1);
+}
+
+static void r8127_sfp_sds_i2c_disable(struct rtl8169_private *tp)
+{
+ r8168_mac_ocp_write(tp, R8127_SDS_I2C_EN, 0);
+}
+
+DECLARE_RTL_COND(r8127_sfp_sds_i2c_idle_cond)
+{
+ u16 val;
+
+ val = r8168_mac_ocp_read(tp, R8127_SDS_I2C_STATUS);
+
+ return val & R8127_SDS_I2C_STATUS_ACTIVITY;
+}
+
+DECLARE_RTL_COND(r8127_sfp_sds_i2c_rx_fifo_cond)
+{
+ u16 val;
+
+ val = r8168_mac_ocp_read(tp, R8127_SDS_I2C_STATUS);
+
+ return val & R8127_SDS_I2C_RX_FIFO_NOT_EMPTY;
+}
+
+static int r8127_sfp_sds_i2c_read(struct rtl8169_private *tp,
+ u8 addr, u8 off, u8 *buf, u16 len)
+{
+ u16 intr_stat;
+ int ret = 0;
+
+ r8127_sfp_sds_i2c_init(tp, addr);
+
+ r8168_mac_ocp_write(tp, R8127_SDS_I2C_DATA_CMD, off);
+
+ if (!rtl_loop_wait_low(tp, &r8127_sfp_sds_i2c_idle_cond, 10, 100)) {
+ ret = -EIO;
+ goto out;
+ }
+
+ intr_stat = r8168_mac_ocp_read(tp, R8127_SDS_I2C_INTR_STAT);
+ if (intr_stat & R8127_SDS_I2C_STAT_TX_ABRT) {
+ /* NACK */
+ ret = -EIO;
+ goto out;
+ }
+
+ for (int i = 0; i < len; i++) {
+ u16 data = R8127_SDS_I2C_CMD_READ;
+
+ if (i == len - 1)
+ data |= R8127_SDS_I2C_CMD_STOP;
+ if (i == 0)
+ data |= R8127_SDS_I2C_CMD_RESTART;
+
+ r8168_mac_ocp_write(tp, R8127_SDS_I2C_DATA_CMD, data);
+
+ if (!rtl_loop_wait_high(tp, &r8127_sfp_sds_i2c_rx_fifo_cond,
+ 10, 1000)) {
+ ret = -ETIMEDOUT;
+ goto out;
+ }
+
+ buf[i] = r8168_mac_ocp_read(tp, R8127_SDS_I2C_DATA_CMD);
+ }
+
+out:
+ r8127_sfp_sds_i2c_disable(tp);
+
+ return ret;
+}
+
+static int rtl8169_get_module_info(struct net_device *ndev,
+ struct ethtool_modinfo *modinfo)
+{
+ struct rtl8169_private *tp = netdev_priv(ndev);
+ u8 compliance_val, dom_type;
+ int ret;
+
+ if (!tp->sfp_mode)
+ return -EOPNOTSUPP;
+
+ ret = r8127_sfp_sds_i2c_read(tp, SFF_8472_ID_ADDR,
+ SFF_8472_COMP_ADDR, &compliance_val, 1);
+ if (ret)
+ return ret;
+
+ ret = r8127_sfp_sds_i2c_read(tp, SFF_8472_ID_ADDR,
+ SFF_8472_DOM_TYPE_ADDR, &dom_type, 1);
+ if (ret)
+ return ret;
+
+ if (dom_type & SFF_8472_ADDRESS_CHANGE_REQ_MASK || compliance_val == 0x00) {
+ modinfo->type = ETH_MODULE_SFF_8079;
+ modinfo->eeprom_len = ETH_MODULE_SFF_8079_LEN;
+ } else {
+ modinfo->type = ETH_MODULE_SFF_8472;
+ modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN;
+ }
+
+ return 0;
+}
+
+static int rtl8169_get_module_eeprom(struct net_device *ndev,
+ struct ethtool_eeprom *ee, unsigned char *data)
+{
+ struct rtl8169_private *tp = netdev_priv(ndev);
+ unsigned int first, last, len;
+ int ret;
+
+ if (!tp->sfp_mode)
+ return -EOPNOTSUPP;
+
+ first = ee->offset;
+ last = ee->offset + ee->len;
+
+ if (first < ETH_MODULE_SFF_8079_LEN) {
+ len = min(last, ETH_MODULE_SFF_8079_LEN);
+ len -= first;
+
+ ret = r8127_sfp_sds_i2c_read(tp, SFF_8472_ID_ADDR,
+ first, data, len);
+ if (ret)
+ return ret;
+
+ first += len;
+ data += len;
+ }
+ if (first < ETH_MODULE_SFF_8472_LEN && last > ETH_MODULE_SFF_8079_LEN) {
+ len = min(last, ETH_MODULE_SFF_8472_LEN);
+ len -= first;
+ first -= ETH_MODULE_SFF_8079_LEN;
+
+ ret = r8127_sfp_sds_i2c_read(tp, SFF_8472_DIAGNOSTICS_ADDR,
+ first, data, len);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
static const struct ethtool_ops rtl8169_ethtool_ops = {
.supported_coalesce_params = ETHTOOL_COALESCE_USECS |
ETHTOOL_COALESCE_MAX_FRAMES,
@@ -2437,6 +2612,8 @@ static const struct ethtool_ops rtl8169_ethtool_ops = {
.set_pauseparam = rtl8169_set_pauseparam,
.get_eth_mac_stats = rtl8169_get_eth_mac_stats,
.get_eth_ctrl_stats = rtl8169_get_eth_ctrl_stats,
+ .get_module_info = rtl8169_get_module_info,
+ .get_module_eeprom = rtl8169_get_module_eeprom,
};
static const struct rtl_chip_info *rtl8169_get_chip_version(u32 xid, bool gmii)
--
2.47.3
^ permalink raw reply related [flat|nested] 6+ messages in thread* Re: [PATCH net-next v1] r8169: implement get_module functions for rtl8127atf
2026-04-04 20:13 [PATCH net-next v1] r8169: implement get_module functions for rtl8127atf Fabio Baltieri
@ 2026-04-04 21:55 ` Heiner Kallweit
2026-04-04 22:37 ` Fabio Baltieri
2026-04-04 22:46 ` Andrew Lunn
0 siblings, 2 replies; 6+ messages in thread
From: Heiner Kallweit @ 2026-04-04 21:55 UTC (permalink / raw)
To: Fabio Baltieri, nic_swsd, Andrew Lunn, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Russell King - ARM Linux, Andrew Lunn
Cc: netdev, linux-kernel
On 04.04.2026 22:13, Fabio Baltieri wrote:
> Implement get_module_info and get_module_eeprom for supported devices,
> right now that's the rtl8127atf.
>
> This enables using ethtool to retrieve the transceiver identification
> and diagnostic data.
>
> Signed-off-by: Fabio Baltieri <fabio.baltieri@gmail.com>
> ---
>
> Hi,
>
> Realtek released a new out of tree driver for the rtl8127 and it
> includes some code that exposes the I2C controller connected to the SFP
> port.
>
> This patch implements get_module_info and get_module_eeprom based on the
> information found on that driver, it allows ethtool to fetch the SFP
> module information, which is useful both to identify the module and to
> track the health of fiber optic transceivers.
>
> The logic for the SFF standard and i2c address selection is borrowed
> directly from the aquantia/atlantic driver, I don't have a lot of stuff
> to test it but I was able to trigger all code paths from a fiber optic
> transceiver and an SFP cable I have available.
>
Hi Fabio, thanks for the patch. Being able to access the SFP I2C bus is an
important step towards future phylink/SFP support.
@Russell/@Andrew
I'm not really familiar with the phylink and sfp code. And I would like to have
the functionality being implemented here reusable once we do further steps
towards phylink support in r8169. So how shall the code be modeled, which
components are needed?
- Shall the SFP I2C bus be modeled as a struct i2c_adapter?
- Shall we (partially?) implement a struct sfp, so that functions like
sfp_module_eeprom() can be used (implicitly)?
I assume this patch includes logic which duplicates what is available in
phylink/sfp already. I'd a appreciate any hints you can provide.
Thanks, Heiner
> Demo:
>
> # Fiber transceiver
> $ sudo ethtool -m eth1
> Identifier : 0x03 (SFP)
> Extended identifier : 0x04 (GBIC/SFP defined by 2-wire interface ID)
> Connector : 0x07 (LC)
> Transceiver codes : 0x10 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
> Transceiver type : 10G Ethernet: 10G Base-SR
> Encoding : 0x06 (64B/66B)
> BR Nominal : 10300MBd
> Rate identifier : 0x00 (unspecified)
> Length (SMF) : 0km
> Length (OM2) : 80m
> Length (OM1) : 30m
> Length (Copper or Active cable) : 0m
> Length (OM3) : 300m
> Laser wavelength : 850nm
> Vendor name : QSFPTEK
> Vendor OUI : 00:0a:0d
> Vendor PN : QT-SFP+-SR
> Vendor rev :
> Option values : 0x00 0x1a
> Option : TX_DISABLE implemented
> BR margin max : 10%
> BR margin min : 88%
> Vendor SN : QT8250805131
> Date code : 250806
> Optical diagnostics support : Yes
> Laser bias current : 5.880 mA
> Laser output power : 0.5431 mW / -2.65 dBm
> Receiver signal average optical power : 0.6912 mW / -1.60 dBm
> Module temperature : 20.70 degrees C / 69.25 degrees F
> Module voltage : 3.3000 V
> ...
>
> # DAC
> $ sudo ethtool -m eth1
> Identifier : 0x03 (SFP)
> Extended identifier : 0x04 (GBIC/SFP defined by 2-wire interface ID)
> Connector : 0x21 (Copper pigtail)
> Transceiver codes : 0x00 0x00 0x00 0x00 0x00 0x04 0x00 0x00 0x00
> Transceiver type : Passive Cable
> Encoding : 0x00 (unspecified)
> BR Nominal : 10300MBd
> Rate identifier : 0x00 (unspecified)
> Length (SMF) : 0km
> Length (OM2) : 0m
> Length (OM1) : 0m
> Length (Copper or Active cable) : 1m
> Length (OM3) : 0m
> Passive Cu cmplnce. : 0x01 (SFF-8431 appendix E [SFF-8472 rev10.4 only])
> Vendor name : OEM
> Vendor OUI : 00:40:20
> Vendor PN : SFP-H10GB-CU1M
> Vendor rev : R
> Option values : 0x00 0x00
> BR margin max : 0%
> BR margin min : 0%
> Vendor SN : CSC240415030053
> Date code : 240508
> ...
>
> # No module
> $ sudo ethtool -m eth1
> netlink error: Input/output error
>
> Cheers,
> Fabio
>
>
> drivers/net/ethernet/realtek/r8169_main.c | 177 ++++++++++++++++++++++
> 1 file changed, 177 insertions(+)
>
> diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c
> index 58788d196c57..45ec0b5c1c21 100644
> --- a/drivers/net/ethernet/realtek/r8169_main.c
> +++ b/drivers/net/ethernet/realtek/r8169_main.c
> @@ -2411,6 +2411,181 @@ static int rtl8169_set_link_ksettings(struct net_device *ndev,
> return 0;
> }
>
> +#define R8127_SDS_I2C_CON 0xe200
> +#define R8127_SDS_I2C_TAR 0xe204
> +#define R8127_SDS_I2C_DATA_CMD 0xe210
> +#define R8127_SDS_I2C_FS_SCL_HCNT 0xe21c
> +#define R8127_SDS_I2C_FS_SCL_LCNT 0xe220
> +#define R8127_SDS_I2C_INTR_STAT 0xe22c
> +#define R8127_SDS_I2C_EN 0xe26c
> +#define R8127_SDS_I2C_STATUS 0xe270
> +
> +#define R8127_SDS_I2C_STATUS_ACTIVITY BIT(0)
> +#define R8127_SDS_I2C_RX_FIFO_NOT_EMPTY BIT(3)
> +#define R8127_SDS_I2C_STAT_TX_ABRT BIT(6)
> +
> +#define R8127_SDS_I2C_CMD_READ BIT(8)
> +#define R8127_SDS_I2C_CMD_STOP BIT(9)
> +#define R8127_SDS_I2C_CMD_RESTART BIT(10)
> +
> +#define SFF_8472_ID_ADDR 0x50
> +#define SFF_8472_DIAGNOSTICS_ADDR 0x51
> +
> +#define SFF_8472_COMP_ADDR 0x5e
> +#define SFF_8472_DOM_TYPE_ADDR 0x5c
> +
> +#define SFF_8472_ADDRESS_CHANGE_REQ_MASK 0x4
> +
> +static void r8127_sfp_sds_i2c_init(struct rtl8169_private *tp, u8 addr)
> +{
> + r8168_mac_ocp_write(tp, R8127_SDS_I2C_EN, 0);
> + r8168_mac_ocp_write(tp, R8127_SDS_I2C_CON, 0x65);
> + r8168_mac_ocp_write(tp, R8127_SDS_I2C_TAR, addr);
> + r8168_mac_ocp_write(tp, R8127_SDS_I2C_FS_SCL_HCNT, 0x23a);
> + r8168_mac_ocp_write(tp, R8127_SDS_I2C_FS_SCL_LCNT, 0x23a);
> + r8168_mac_ocp_write(tp, R8127_SDS_I2C_EN, 1);
> +}
> +
> +static void r8127_sfp_sds_i2c_disable(struct rtl8169_private *tp)
> +{
> + r8168_mac_ocp_write(tp, R8127_SDS_I2C_EN, 0);
> +}
> +
> +DECLARE_RTL_COND(r8127_sfp_sds_i2c_idle_cond)
> +{
> + u16 val;
> +
> + val = r8168_mac_ocp_read(tp, R8127_SDS_I2C_STATUS);
> +
> + return val & R8127_SDS_I2C_STATUS_ACTIVITY;
> +}
> +
> +DECLARE_RTL_COND(r8127_sfp_sds_i2c_rx_fifo_cond)
> +{
> + u16 val;
> +
> + val = r8168_mac_ocp_read(tp, R8127_SDS_I2C_STATUS);
> +
> + return val & R8127_SDS_I2C_RX_FIFO_NOT_EMPTY;
> +}
> +
> +static int r8127_sfp_sds_i2c_read(struct rtl8169_private *tp,
> + u8 addr, u8 off, u8 *buf, u16 len)
> +{
> + u16 intr_stat;
> + int ret = 0;
> +
> + r8127_sfp_sds_i2c_init(tp, addr);
> +
> + r8168_mac_ocp_write(tp, R8127_SDS_I2C_DATA_CMD, off);
> +
> + if (!rtl_loop_wait_low(tp, &r8127_sfp_sds_i2c_idle_cond, 10, 100)) {
> + ret = -EIO;
> + goto out;
> + }
> +
> + intr_stat = r8168_mac_ocp_read(tp, R8127_SDS_I2C_INTR_STAT);
> + if (intr_stat & R8127_SDS_I2C_STAT_TX_ABRT) {
> + /* NACK */
> + ret = -EIO;
> + goto out;
> + }
> +
> + for (int i = 0; i < len; i++) {
> + u16 data = R8127_SDS_I2C_CMD_READ;
> +
> + if (i == len - 1)
> + data |= R8127_SDS_I2C_CMD_STOP;
> + if (i == 0)
> + data |= R8127_SDS_I2C_CMD_RESTART;
> +
> + r8168_mac_ocp_write(tp, R8127_SDS_I2C_DATA_CMD, data);
> +
> + if (!rtl_loop_wait_high(tp, &r8127_sfp_sds_i2c_rx_fifo_cond,
> + 10, 1000)) {
> + ret = -ETIMEDOUT;
> + goto out;
> + }
> +
> + buf[i] = r8168_mac_ocp_read(tp, R8127_SDS_I2C_DATA_CMD);
> + }
> +
> +out:
> + r8127_sfp_sds_i2c_disable(tp);
> +
> + return ret;
> +}
> +
> +static int rtl8169_get_module_info(struct net_device *ndev,
> + struct ethtool_modinfo *modinfo)
> +{
> + struct rtl8169_private *tp = netdev_priv(ndev);
> + u8 compliance_val, dom_type;
> + int ret;
> +
> + if (!tp->sfp_mode)
> + return -EOPNOTSUPP;
> +
> + ret = r8127_sfp_sds_i2c_read(tp, SFF_8472_ID_ADDR,
> + SFF_8472_COMP_ADDR, &compliance_val, 1);
> + if (ret)
> + return ret;
> +
> + ret = r8127_sfp_sds_i2c_read(tp, SFF_8472_ID_ADDR,
> + SFF_8472_DOM_TYPE_ADDR, &dom_type, 1);
> + if (ret)
> + return ret;
> +
> + if (dom_type & SFF_8472_ADDRESS_CHANGE_REQ_MASK || compliance_val == 0x00) {
> + modinfo->type = ETH_MODULE_SFF_8079;
> + modinfo->eeprom_len = ETH_MODULE_SFF_8079_LEN;
> + } else {
> + modinfo->type = ETH_MODULE_SFF_8472;
> + modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN;
> + }
> +
> + return 0;
> +}
> +
> +static int rtl8169_get_module_eeprom(struct net_device *ndev,
> + struct ethtool_eeprom *ee, unsigned char *data)
> +{
> + struct rtl8169_private *tp = netdev_priv(ndev);
> + unsigned int first, last, len;
> + int ret;
> +
> + if (!tp->sfp_mode)
> + return -EOPNOTSUPP;
> +
> + first = ee->offset;
> + last = ee->offset + ee->len;
> +
> + if (first < ETH_MODULE_SFF_8079_LEN) {
> + len = min(last, ETH_MODULE_SFF_8079_LEN);
> + len -= first;
> +
> + ret = r8127_sfp_sds_i2c_read(tp, SFF_8472_ID_ADDR,
> + first, data, len);
> + if (ret)
> + return ret;
> +
> + first += len;
> + data += len;
> + }
> + if (first < ETH_MODULE_SFF_8472_LEN && last > ETH_MODULE_SFF_8079_LEN) {
> + len = min(last, ETH_MODULE_SFF_8472_LEN);
> + len -= first;
> + first -= ETH_MODULE_SFF_8079_LEN;
> +
> + ret = r8127_sfp_sds_i2c_read(tp, SFF_8472_DIAGNOSTICS_ADDR,
> + first, data, len);
> + if (ret)
> + return ret;
> + }
> +
> + return 0;
> +}
> +
> static const struct ethtool_ops rtl8169_ethtool_ops = {
> .supported_coalesce_params = ETHTOOL_COALESCE_USECS |
> ETHTOOL_COALESCE_MAX_FRAMES,
> @@ -2437,6 +2612,8 @@ static const struct ethtool_ops rtl8169_ethtool_ops = {
> .set_pauseparam = rtl8169_set_pauseparam,
> .get_eth_mac_stats = rtl8169_get_eth_mac_stats,
> .get_eth_ctrl_stats = rtl8169_get_eth_ctrl_stats,
> + .get_module_info = rtl8169_get_module_info,
> + .get_module_eeprom = rtl8169_get_module_eeprom,
> };
>
> static const struct rtl_chip_info *rtl8169_get_chip_version(u32 xid, bool gmii)
^ permalink raw reply [flat|nested] 6+ messages in thread* Re: [PATCH net-next v1] r8169: implement get_module functions for rtl8127atf
2026-04-04 21:55 ` Heiner Kallweit
@ 2026-04-04 22:37 ` Fabio Baltieri
2026-04-04 22:57 ` Andrew Lunn
2026-04-04 22:46 ` Andrew Lunn
1 sibling, 1 reply; 6+ messages in thread
From: Fabio Baltieri @ 2026-04-04 22:37 UTC (permalink / raw)
To: Heiner Kallweit
Cc: nic_swsd, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Russell King - ARM Linux,
Andrew Lunn, netdev, linux-kernel
On Sat, Apr 04, 2026 at 11:55:25PM +0200, Heiner Kallweit wrote:
> On 04.04.2026 22:13, Fabio Baltieri wrote:
> > Implement get_module_info and get_module_eeprom for supported devices,
> > right now that's the rtl8127atf.
> >
> > This enables using ethtool to retrieve the transceiver identification
> > and diagnostic data.
> >
> > Signed-off-by: Fabio Baltieri <fabio.baltieri@gmail.com>
> > ---
> >
> > Hi,
> >
> > Realtek released a new out of tree driver for the rtl8127 and it
> > includes some code that exposes the I2C controller connected to the SFP
> > port.
> >
> > This patch implements get_module_info and get_module_eeprom based on the
> > information found on that driver, it allows ethtool to fetch the SFP
> > module information, which is useful both to identify the module and to
> > track the health of fiber optic transceivers.
> >
> > The logic for the SFF standard and i2c address selection is borrowed
> > directly from the aquantia/atlantic driver, I don't have a lot of stuff
> > to test it but I was able to trigger all code paths from a fiber optic
> > transceiver and an SFP cable I have available.
> >
>
> Hi Fabio, thanks for the patch. Being able to access the SFP I2C bus is an
> important step towards future phylink/SFP support.
>
> @Russell/@Andrew
> I'm not really familiar with the phylink and sfp code. And I would like to have
> the functionality being implemented here reusable once we do further steps
> towards phylink support in r8169. So how shall the code be modeled, which
> components are needed?
> - Shall the SFP I2C bus be modeled as a struct i2c_adapter?
> - Shall we (partially?) implement a struct sfp, so that functions like
> sfp_module_eeprom() can be used (implicitly)?
Yeah happy to hear any input on it, the controller actually seems to be
a designware IP and there is some reusable code for it but what I've
seen done for other drivers for this functionality is to implement a
minimum i2c "read bulk" functionality in the driver itself, so that's
what I proposed here too, the code is fairly simple after all. However I
did borrow some logic much verbatim from the atlantis driver as I
mentioned, happy to hear if there's a path to reuse.
>
> I assume this patch includes logic which duplicates what is available in
> phylink/sfp already. I'd a appreciate any hints you can provide.
>
> Thanks, Heiner
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH net-next v1] r8169: implement get_module functions for rtl8127atf
2026-04-04 22:37 ` Fabio Baltieri
@ 2026-04-04 22:57 ` Andrew Lunn
0 siblings, 0 replies; 6+ messages in thread
From: Andrew Lunn @ 2026-04-04 22:57 UTC (permalink / raw)
To: Fabio Baltieri
Cc: Heiner Kallweit, nic_swsd, Andrew Lunn, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Russell King - ARM Linux, netdev, linux-kernel
> Yeah happy to hear any input on it, the controller actually seems to be
> a designware IP
Ah, interesting. Ideally you want to use the existing designware
driver. Take a look at txgbe_i2c_register().
Andrew
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH net-next v1] r8169: implement get_module functions for rtl8127atf
2026-04-04 21:55 ` Heiner Kallweit
2026-04-04 22:37 ` Fabio Baltieri
@ 2026-04-04 22:46 ` Andrew Lunn
2026-04-04 23:05 ` Fabio Baltieri
1 sibling, 1 reply; 6+ messages in thread
From: Andrew Lunn @ 2026-04-04 22:46 UTC (permalink / raw)
To: Heiner Kallweit
Cc: Fabio Baltieri, nic_swsd, Andrew Lunn, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Russell King - ARM Linux, netdev, linux-kernel
On Sat, Apr 04, 2026 at 11:55:25PM +0200, Heiner Kallweit wrote:
> On 04.04.2026 22:13, Fabio Baltieri wrote:
> > Implement get_module_info and get_module_eeprom for supported devices,
> > right now that's the rtl8127atf.
> >
> > This enables using ethtool to retrieve the transceiver identification
> > and diagnostic data.
> >
> > Signed-off-by: Fabio Baltieri <fabio.baltieri@gmail.com>
> > ---
> >
> > Hi,
> >
> > Realtek released a new out of tree driver for the rtl8127 and it
> > includes some code that exposes the I2C controller connected to the SFP
> > port.
> >
> > This patch implements get_module_info and get_module_eeprom based on the
> > information found on that driver, it allows ethtool to fetch the SFP
> > module information, which is useful both to identify the module and to
> > track the health of fiber optic transceivers.
> >
> > The logic for the SFF standard and i2c address selection is borrowed
> > directly from the aquantia/atlantic driver, I don't have a lot of stuff
> > to test it but I was able to trigger all code paths from a fiber optic
> > transceiver and an SFP cable I have available.
> >
>
> Hi Fabio, thanks for the patch. Being able to access the SFP I2C bus is an
> important step towards future phylink/SFP support.
>
> @Russell/@Andrew
> I'm not really familiar with the phylink and sfp code. And I would like to have
> the functionality being implemented here reusable once we do further steps
> towards phylink support in r8169. So how shall the code be modeled, which
> components are needed?
> - Shall the SFP I2C bus be modeled as a struct i2c_adapter?
Yes, that would be best. Call i2c_add_adapter() to add it to the I2C
core. The SFP code in drivers/net/phy can then make use of it.
> - Shall we (partially?) implement a struct sfp, so that functions like
> sfp_module_eeprom() can be used (implicitly)?
>
> I assume this patch includes logic which duplicates what is available in
> phylink/sfp already. I'd a appreciate any hints you can provide.
No. phylink etc will end up populating netdev->sfp_bus, and then
get_module_eeprom_by_page() should then just make the module work in
ethtool.
The interesting bit if gluing it all together, without DT. But
txgbe_phy.c should be something you can copy from.
Does the out of tree driver give access to GPIOs connected to the SFP
cage pins? Ideally you want those as well, for loss of signal,
transmitter disable, knowing when a module has been inserted into the
cage, etc.
And you will need a PCS driver.
But first step is probably to work with the existing Base-T devices
and convert the driver to phylink.
Andrew
---
pw-bot: cr
^ permalink raw reply [flat|nested] 6+ messages in thread* Re: [PATCH net-next v1] r8169: implement get_module functions for rtl8127atf
2026-04-04 22:46 ` Andrew Lunn
@ 2026-04-04 23:05 ` Fabio Baltieri
0 siblings, 0 replies; 6+ messages in thread
From: Fabio Baltieri @ 2026-04-04 23:05 UTC (permalink / raw)
To: Andrew Lunn
Cc: Heiner Kallweit, nic_swsd, Andrew Lunn, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Russell King - ARM Linux, netdev, linux-kernel
On Sun, Apr 05, 2026 at 12:46:41AM +0200, Andrew Lunn wrote:
> On Sat, Apr 04, 2026 at 11:55:25PM +0200, Heiner Kallweit wrote:
> > On 04.04.2026 22:13, Fabio Baltieri wrote:
> > > Implement get_module_info and get_module_eeprom for supported devices,
> > > right now that's the rtl8127atf.
> > >
> > > This enables using ethtool to retrieve the transceiver identification
> > > and diagnostic data.
> > >
> > > Signed-off-by: Fabio Baltieri <fabio.baltieri@gmail.com>
> > > ---
> > >
> > > Hi,
> > >
> > > Realtek released a new out of tree driver for the rtl8127 and it
> > > includes some code that exposes the I2C controller connected to the SFP
> > > port.
> > >
> > > This patch implements get_module_info and get_module_eeprom based on the
> > > information found on that driver, it allows ethtool to fetch the SFP
> > > module information, which is useful both to identify the module and to
> > > track the health of fiber optic transceivers.
> > >
> > > The logic for the SFF standard and i2c address selection is borrowed
> > > directly from the aquantia/atlantic driver, I don't have a lot of stuff
> > > to test it but I was able to trigger all code paths from a fiber optic
> > > transceiver and an SFP cable I have available.
> > >
> >
> > Hi Fabio, thanks for the patch. Being able to access the SFP I2C bus is an
> > important step towards future phylink/SFP support.
> >
> > @Russell/@Andrew
> > I'm not really familiar with the phylink and sfp code. And I would like to have
> > the functionality being implemented here reusable once we do further steps
> > towards phylink support in r8169. So how shall the code be modeled, which
> > components are needed?
> > - Shall the SFP I2C bus be modeled as a struct i2c_adapter?
>
> Yes, that would be best. Call i2c_add_adapter() to add it to the I2C
> core. The SFP code in drivers/net/phy can then make use of it.
>
> > - Shall we (partially?) implement a struct sfp, so that functions like
> > sfp_module_eeprom() can be used (implicitly)?
> >
> > I assume this patch includes logic which duplicates what is available in
> > phylink/sfp already. I'd a appreciate any hints you can provide.
>
> No. phylink etc will end up populating netdev->sfp_bus, and then
> get_module_eeprom_by_page() should then just make the module work in
> ethtool.
>
> The interesting bit if gluing it all together, without DT. But
> txgbe_phy.c should be something you can copy from.
>
> Does the out of tree driver give access to GPIOs connected to the SFP
> cage pins? Ideally you want those as well, for loss of signal,
> transmitter disable, knowing when a module has been inserted into the
> cage, etc.
The current version does not seem to do that, maybe the Realtek folks
can chime in about it.
I'll look into the dw driver, thanks for the pointer.
> And you will need a PCS driver.
>
> But first step is probably to work with the existing Base-T devices
> and convert the driver to phylink.
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2026-04-04 23:05 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-04 20:13 [PATCH net-next v1] r8169: implement get_module functions for rtl8127atf Fabio Baltieri
2026-04-04 21:55 ` Heiner Kallweit
2026-04-04 22:37 ` Fabio Baltieri
2026-04-04 22:57 ` Andrew Lunn
2026-04-04 22:46 ` Andrew Lunn
2026-04-04 23:05 ` Fabio Baltieri
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox