From nobody Sun Jun 14 18:58:01 2026 Received: from mail-wm1-f42.google.com (mail-wm1-f42.google.com [209.85.128.42]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 46BE93264E5 for ; Sat, 4 Apr 2026 20:13:37 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.42 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775333619; cv=none; b=AQDbjIwAf65oZ0If5bQnE1BnkzyYRh0vuu0/7EcTp3OnCiawlGr9AXx0lL35sbKJvS8sXT7RsJqpd0MnfjM2gGHW8HN87BU5MSIxvlFa23JOpBetHIdGDYUENkxla73o/UGEcW3bTKtqM54exJm3dXDu/iJgbYu0T+/l3TRMuSc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775333619; c=relaxed/simple; bh=6IVkTjQ2D8zBMbDV+vErJ9JRCgC6abbJric/W+zRtIo=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version; b=bOQ473FEwVclJoQ/0sKTVzoiSOqRS6J9+b5iz7HmHy3YLWAr2Z9HqyiR0ZhDC2XFx5g3nA1eMXpHAK47gnOkxHSw7FLGNzj6MMeg4plgE5sHAJwCP1GX8SYA/mBp1+UP+rTmoKO0H2nQAM3Dqax/51DbGl7rp1kRJLUluGNCiiE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=V8eAGki5; arc=none smtp.client-ip=209.85.128.42 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="V8eAGki5" Received: by mail-wm1-f42.google.com with SMTP id 5b1f17b1804b1-4852a9c6309so25327965e9.0 for ; Sat, 04 Apr 2026 13:13:37 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1775333615; x=1775938415; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to; bh=SEYuEqxQ+TO3/jPNzXLnvJ7/Z/KsUW75My4aiFyt8Vc=; b=V8eAGki55jpJHVr0mIIPYqUGYm6zhlDT4r+2m8yoLovhhUGkQT+WfTGrexZ64WKHzB L70mpYrv/MUMepaTij90G8rArRS86VMO0w4eZ/Q92tDPrIV+S62MdLCJlHK/7IN0Tes+ u900xyMYBZQInX+Jq+c0T7+8BHNbWXT9ZJbJrsd8Kj0CmAnfwriq0S9gmNH/6CEKJEvZ FqJZP++IE9rWxn+3nCr09mtOE0FTa4w1w046y7drnrg87wzAP+UDADOpkheWovPxKy3c FInmtCHr0LBK5rJCX6elBd1q/fc0jiHLLayZ8j9FL5O34yg1XU8ErqeJteUr4RJkGEwe hTnw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1775333615; x=1775938415; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=SEYuEqxQ+TO3/jPNzXLnvJ7/Z/KsUW75My4aiFyt8Vc=; b=EKvcSeEKDofHnrTYU/QsvEtsdpfvtFjr+NMmd5XuiOEydIjjYCDhxY7LJdhzzAffny s2AhxS6CgTjgA2UJFqJ3Uo5U+UvUOjssg6G6qLH9KGeYDcirI+/HK0bZ5vgz5S0su1wv ORoUuX6nnxpoStH2vyCXnFgZjbc4H08C61vC/j1+XUPbPANQjmmVc7dCuWVxaDnZwIeL /PX2MzHNzGWBBTZWSB53N70oxLexRvDjIT+MsRfhRyWLl3+Pct3WE2FnJZny/8AhN/xu EyW0S0b2xuhWCyePLQHPVBHLLhwS38RmtCHLnX4HZgev7ThMpO25PX295fFi0BPSxJl8 0Z4w== X-Forwarded-Encrypted: i=1; AJvYcCXj0bAydE47dzLSHid79TBy8DzCGBIBUuuP7FYTXArhk7GhTUTPGV7Jw2UGM0pOrtcWWa45AY6P+zt1YTA=@vger.kernel.org X-Gm-Message-State: AOJu0YwXGDZNn7sVNxt+qwWKjuFu2A1KZq3Ce0nAfqHRrSkC4KBDFMA7 ndU43bPONzPoL2wRjoX9JDH0h4nJye5Q/mQuoXaZ+LipZn4Hnzsd3VFw X-Gm-Gg: AeBDies3oTQBMX/mc5BBSWzke8u+ZRDweGYptI1YhtRpus6T/pnHoN9mg0LViEpj+i9 ThOEZ2NGoUzFovvnVoVzgqm6qP776Fw/b2gJjMU/LtivIYfd1+CyU7PPHYSnJJcf7UJKScL4hTM VnHftFlqX1r61Ecf1wkL8pMfYLSYxR+DVaiE4qRk6lCsDOm6neIPE8zQYKKiUtwsSa8b6D9YA7c 5xQb0nmukE14X3lHSMtaZGMPb85IqoYm0AxFTD5CMnHnGoWwd05RVKzayy/kjpNWRQNs9dGF192 +8zJhm1Njg/1qr0J96jzNOQ07RWAcFj5q6hImTFOTLrsuZgsiA6Y/x8wBwD7kYBiNbyDQuQkezk 9GLSO1kMsnMEATw2W8JD4Jni9KMfYKGo4ddrL5TJZvLR7nyUfY46aMSci6yFjPD+4HIzR3Pu9QR zEePt6KDK5ds0IPyi89n0v5/99DfO06ZVEESQ= X-Received: by 2002:a05:600c:1d1c:b0:488:79a3:f04c with SMTP id 5b1f17b1804b1-488997d1387mr109585605e9.27.1775333615312; Sat, 04 Apr 2026 13:13:35 -0700 (PDT) Received: from rpi5.lan ([37.228.206.31]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-43d1e4d58e5sm28179680f8f.23.2026.04.04.13.13.34 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 04 Apr 2026 13:13:34 -0700 (PDT) From: Fabio Baltieri To: Heiner Kallweit , nic_swsd@realtek.com, Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni Cc: netdev@vger.kernel.org, linux-kernel@vger.kernel.org, Fabio Baltieri Subject: [PATCH net-next v1] r8169: implement get_module functions for rtl8127atf Date: Sat, 4 Apr 2026 21:13:32 +0100 Message-ID: <20260404201333.2849-1-fabio.baltieri@gmail.com> X-Mailer: git-send-email 2.47.3 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" 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 --- 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 0x0= 0 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 :=20 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 0x0= 0 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/ethern= et/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_de= vice *ndev, return 0; } =20 +#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 =3D 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 =3D 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 =3D 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 =3D -EIO; + goto out; + } + + intr_stat =3D r8168_mac_ocp_read(tp, R8127_SDS_I2C_INTR_STAT); + if (intr_stat & R8127_SDS_I2C_STAT_TX_ABRT) { + /* NACK */ + ret =3D -EIO; + goto out; + } + + for (int i =3D 0; i < len; i++) { + u16 data =3D R8127_SDS_I2C_CMD_READ; + + if (i =3D=3D len - 1) + data |=3D R8127_SDS_I2C_CMD_STOP; + if (i =3D=3D 0) + data |=3D 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 =3D -ETIMEDOUT; + goto out; + } + + buf[i] =3D 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 =3D netdev_priv(ndev); + u8 compliance_val, dom_type; + int ret; + + if (!tp->sfp_mode) + return -EOPNOTSUPP; + + ret =3D r8127_sfp_sds_i2c_read(tp, SFF_8472_ID_ADDR, + SFF_8472_COMP_ADDR, &compliance_val, 1); + if (ret) + return ret; + + ret =3D 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 =3D=3D = 0x00) { + modinfo->type =3D ETH_MODULE_SFF_8079; + modinfo->eeprom_len =3D ETH_MODULE_SFF_8079_LEN; + } else { + modinfo->type =3D ETH_MODULE_SFF_8472; + modinfo->eeprom_len =3D 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 =3D netdev_priv(ndev); + unsigned int first, last, len; + int ret; + + if (!tp->sfp_mode) + return -EOPNOTSUPP; + + first =3D ee->offset; + last =3D ee->offset + ee->len; + + if (first < ETH_MODULE_SFF_8079_LEN) { + len =3D min(last, ETH_MODULE_SFF_8079_LEN); + len -=3D first; + + ret =3D r8127_sfp_sds_i2c_read(tp, SFF_8472_ID_ADDR, + first, data, len); + if (ret) + return ret; + + first +=3D len; + data +=3D len; + } + if (first < ETH_MODULE_SFF_8472_LEN && last > ETH_MODULE_SFF_8079_LEN) { + len =3D min(last, ETH_MODULE_SFF_8472_LEN); + len -=3D first; + first -=3D ETH_MODULE_SFF_8079_LEN; + + ret =3D 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 =3D { .supported_coalesce_params =3D ETHTOOL_COALESCE_USECS | ETHTOOL_COALESCE_MAX_FRAMES, @@ -2437,6 +2612,8 @@ static const struct ethtool_ops rtl8169_ethtool_ops = =3D { .set_pauseparam =3D rtl8169_set_pauseparam, .get_eth_mac_stats =3D rtl8169_get_eth_mac_stats, .get_eth_ctrl_stats =3D rtl8169_get_eth_ctrl_stats, + .get_module_info =3D rtl8169_get_module_info, + .get_module_eeprom =3D rtl8169_get_module_eeprom, }; =20 static const struct rtl_chip_info *rtl8169_get_chip_version(u32 xid, bool = gmii) --=20 2.47.3